]> git.mxchange.org Git - simgear.git/commitdiff
Fix a nasty bug in non-libCurl HTTP pipelining.
authorJames Turner <zakalawe@mac.com>
Thu, 25 Feb 2016 22:10:34 +0000 (00:10 +0200)
committerJames Turner <zakalawe@mac.com>
Thu, 25 Feb 2016 22:10:34 +0000 (00:10 +0200)
- when requests were closely overlapped, but not submitted at the
  same time, connection state could get corrupted.

simgear/io/HTTPClient.cxx
simgear/io/test_HTTP.cxx

index 93ad361217325cc71fe62b520cb9c3aedd617161..6ec17c49b8338c29c1230d8d3fd578defc3ed77f 100644 (file)
@@ -68,7 +68,7 @@ namespace HTTP
 
 extern const int DEFAULT_HTTP_PORT = 80;
 const char* CONTENT_TYPE_URL_ENCODED = "application/x-www-form-urlencoded";
-const unsigned int MAX_INFLIGHT_REQUESTS = 32;
+const unsigned int MAX_INFLIGHT_REQUESTS = 4;
 
 class Connection;
 typedef std::multimap<std::string, Connection*> ConnectionDict;
@@ -377,7 +377,9 @@ public:
       // successfully sent, remove from queue, and maybe send the next
       queuedRequests.pop_front();
       sentRequests.push_back(r);
-      state = STATE_WAITING_FOR_RESPONSE;
+      if (state == STATE_IDLE) {
+          state = STATE_WAITING_FOR_RESPONSE;
+      }
 
       // pipelining, let's maybe send the next request right away
       tryStartNextRequest();
index 39a1d27a228ebeed4922c8d31c5002459159d79e..2f90b4427d5930026f3701d08813ae233d5479af 100644 (file)
@@ -86,7 +86,7 @@ protected:
 
     virtual void gotBodyData(const char* s, int n)
     {
-      //std::cout << "got body data:'" << string(s, n) << "'" <<std::endl;
+        //std::cout << "got body data:'" << string(s, n) << "'" <<std::endl;
         bodyData += string(s, n);
     }
 
@@ -256,6 +256,36 @@ public:
               requestContentLength = strutils::to_int(requestHeaders["Content-Length"]);
               setByteCount(requestContentLength);
               state = STATE_REQUEST_BODY;
+        } else if (path == "/test_get_during_send") {
+            // indicate we will send some number of bytes, but only send
+            // some of them now.
+            waitingOnNextRequestToContinue = true;
+
+            string contentStr(BODY3, 100); // only send first 100 chars
+            stringstream d;
+            d << "HTTP/1.1 " << 200 << " " << reasonForCode(200) << "\r\n";
+            d << "Content-Length:" << strlen(BODY3) << "\r\n";
+            d << "\r\n"; // final CRLF to terminate the headers
+            d << contentStr;
+            push(d.str().c_str());
+        } else if (path == "/test_get_during_send_2") {
+            stringstream d;
+
+            if (waitingOnNextRequestToContinue) {
+                waitingOnNextRequestToContinue = false;
+                // push the rest of the first request
+                d << string(BODY3).substr(100);
+            }
+
+
+            // push the response to this request
+            string contentStr(BODY1);
+            d << "HTTP/1.1 " << 200 << " " << reasonForCode(200) << "\r\n";
+            d << "Content-Length:" << contentStr.size() << "\r\n";
+            d << "\r\n"; // final CRLF to terminate the headers
+            d << contentStr;
+            push(d.str().c_str());
+
         } else {
           TestServerChannel::processRequestHeaders();
         }
@@ -309,6 +339,8 @@ public:
         push(d.str().c_str());
         bufferSend(body2, body2Size);
     }
+
+    bool waitingOnNextRequestToContinue;
 };
 
 TestServer<HTTPTestChannel> testServer;
@@ -666,6 +698,34 @@ cout << "testing proxy close" << endl;
         COMPARE(tr->responseBytesReceived(), 0);
     }
 
+    {
+        cout << "get-during-response-send" << endl;
+        //test_get_during_send
+
+        TestRequest* tr = new TestRequest("http://localhost:2000/test_get_during_send");
+        HTTP::Request_ptr own(tr);
+        cl.makeRequest(tr);
+
+        // kick things along
+        for (int i=0; i<10; ++i) {
+            SGTimeStamp::sleepForMSec(1);
+            cl.update();
+            testServer.poll();
+
+        }
+
+        TestRequest* tr2 = new TestRequest("http://localhost:2000/test_get_during_send_2");
+        HTTP::Request_ptr own2(tr2);
+        cl.makeRequest(tr2);
+
+        waitForComplete(&cl, tr2);
+        COMPARE(tr->responseCode(), 200);
+        COMPARE(tr->bodyData, string(BODY3));
+        COMPARE(tr->responseBytesReceived(), strlen(BODY3));
+        COMPARE(tr2->responseCode(), 200);
+        COMPARE(tr2->bodyData, string(BODY1));
+        COMPARE(tr2->responseBytesReceived(), strlen(BODY1));
+    }
 
     cout << "all tests passed ok" << endl;
     return EXIT_SUCCESS;