I don't even know why I try to understand things sometimes. Toying with adding
pipelining support, I added some echo("OUT ", headersString) and echo("IN",
line) to httpclient.nim to see what was actually being sent when. Then I ran
this script:
import asyncdispatch, asyncfutures, httpclient
from strformat import `&`
proc runclients() {.async.} =
var futures: seq[Future[AsyncResponse]]
let client = newAsyncHttpClient()
for i in 0..5:
let tag = &"{i}"
echo("requesting to server ", tag)
let f = (
client.request(&"http://127.0.0.1/tag/{tag}", "GET"))
futures.add(f)
try:
let resps = await futures.all()
for resp in resps:
echo("response from server ", resp.headers)
echo("getting bodies now")
for resp in resps:
discard await resp.body
echo("done")
except ProtocolError:
echo("protocol error whee")
waitFor runclients()
Run
And it... hung until the socket timed out then died with a protocol error.
But! Looking at the IN and OUT stuff, I saw:
OUT GET /tag/0 HTTP/1.1
Host: 127.0.0.1
Connection: Keep-Alive
user-agent: Nim httpclient/0.20.99
OUT GET /tag/1 HTTP/1.1
Host: 127.0.0.1
Connection: Keep-Alive
user-agent: Nim httpclient/0.20.99
OUT GET /tag/2 HTTP/1.1
Host: 127.0.0.1
Connection: Keep-Alive
user-agent: Nim httpclient/0.20.99
Run
and so on, and then ONLY after that, I saw
IN HTTP/1.1 404 Not Found
IN Server: nginx/1.17.0
IN Date: Sun, 09 Jun 2019 05:32:56 GMT
etc
Run
And that's uh... pipelining. So apparently when you wait for the entire
response body, Nim just uses its psychic powers to determine that what you
really want to do is send more requests while you're waiting. **httpclient.nim
is doing HTTP pipelining just fine.**
As for why my script then hangs... it probably has to do with the fact that
there hasn't been some joker yet, firing off a bunch of requests on one
AsyncHttpClient before waiting for any of them to complete. All the data is
successfully sent and received over the async socket, but httpclient.nim stalls
out turning the response data into various AsyncHttpResponse objects. Probably
naively overwriting a future or something, where a queue should be used instead.