CONFIGURATION and COMPILING --------------------------- When just checked out from git, run: ./autogen.sh Next run: ./configure --enable-maintainer-mode make You need to have a C++ compiler and boost installed (and libcurl of course). PKG_CONFIG_PATH can be used to find and use a specific installation of libcurl, but don't forget to also set LD_LIBRARY_PATH correctly if you installed it in a non-standard place. RUNNING ------- To run the test, first start the server: ./http_server and in a different terminal (the server doesn't go to the background) run the client: ./http_client [-p port] [hostname] The default hostname is 'localhost' and the default port is 9001. An alternative way to run the client is using strace, for example: strace -tt -s256 -e trace=network,select,poll -e write=4,5,6 -e read=4,5,6 -o outfile ./http_client and then inspect outfile. EXPLANATION ----------- The http_server listens on port 9001 and accepts any number of connections. Each connection is full HTTP pipeline capable (version 1.1), that is - it deals correctly with whatever http_client is feeding it ;). The client sends (multiple) requests (without waiting for replies) of the form: GET / HTTP/1.1\r\n Host: localhost:9001\r\n Accept: */*\r\n X-Sleep: 500\r\n X-Request: 3\r\n \r\n Where the number after X-Requests starts at 0 and is incremented with 1 for every next request (32 in total). The server waits 'X-Sleep' milliseconds after receiving the request and then replies with: HTTP/1.1 200 OK\r\n Keep-Alive: timeout=10 max=400\r\n Content-Length: 32\r\n Content-Type: text/html\r\n X-Connection: 1\r\n X-Request: 3\r\n X-Reply: 3\r\n \r\n <html><body>hello</body></html>\n Where X-Connection enumerates the socket connections (and therefore should remain the same for the full duration of the test: we want this to be a pipeline only using a single connection). The returned X-Request header is the same as the one that was received (that this is a reply for), and the X-Reply header enumerates the replies that the server sent over this connection in the order they are generated. It should be the case therefore that X-Request and X-Reply are always the same number (and they are). LIBCURL BUGS ------------ In order of importance, - At the end of this application while a request is timing out, libcurl starts to return from curl_multi_perform() immediately, while curl_multi_fdset() keeps returning a bit set on the fdread set. At this point there is activity on this socket, but libcurl doesn't read that. The result is select() immediately returns, and get into a tight loop of the main loop, calling curl_multi_perform() / curl_multi_fdset() / select() 10,000 times per second (until finally the 4 seconds of CURLOPT_TIMEOUT did pass). - The http_client application first sends a single request and waits for a reply. This is necessary because if we start immediately with sending six requests we end up with six connections. I think that it would be better if: 1) libcurl had an option to pass to an easy handle that pipelining is guaranteed to be supported - and libcurl would then ALWAYS do pipelining on a single connection (until CURLMOPT_MAX_PIPELINE_LENGTH is reached). 2) If libcurl would simply queue extra request until it got back headers for the first request and thus knows if pipelining is supported in exactly the same way as this happens now (where the application has to add extra code in order to make sure that it doesn't add more than one connection the first time). This seems especially important after an error occurs on the socket: the new connection is AGAIN 'unknown' to libcurl (or so is my experience), while the applicaiton is oblivious of this and now no longer CAN be the one who limits the number of requests to one until (again) headers are received. PS Both these problems have now been addressed through the addition of CURLMOPT_PIPELINE_POLICY_FUNCTION.
CarloWood/curl_http_pipeline_tester
A test server and client to test http pipelining with libcurl.
C++