ソースを参照

handle servers closing encoded connections correctly

Servers who advertise that they close the connection get the 'Closes'
encoding flag, but this conflicts with servers who response with a
transfer-encoding (e.g. encoding) as it is saved in the same flag.

We have a better flag for the keep-alive (or not) of the connection
anyway, so we check this instead of the encoding.

This is in practice not much of a problem as real servers we talk to are
HTTP1.1 servers (with keep-alive) and there isn't much point in doing
chunked encoding if you are going to close anyway, but our simple
testserver stumbles over this if pressed and its a bit cleaner, too.

Git-Dch: Ignore
David Kalnischkies 11 年 前
コミット
117038bac9
共有2 個のファイルを変更した24 個の追加10 個の削除を含む
  1. 3 3
      methods/http.cc
  2. 21 7
      test/interactive-helper/aptwebserver.cc

+ 3 - 3
methods/http.cc

@@ -442,7 +442,7 @@ bool HttpServerState::RunData(FileFd * const File)
    {
    {
       /* Closes encoding is used when the server did not specify a size, the
       /* Closes encoding is used when the server did not specify a size, the
          loss of the connection means we are done */
          loss of the connection means we are done */
-      if (Encoding == Closes)
+      if (Persistent == false)
 	 In.Limit(-1);
 	 In.Limit(-1);
       else if (JunkSize != 0)
       else if (JunkSize != 0)
 	 In.Limit(JunkSize);
 	 In.Limit(JunkSize);
@@ -524,7 +524,7 @@ bool HttpServerState::Die(FileFd &File)
 
 
    // See if this is because the server finished the data stream
    // See if this is because the server finished the data stream
    if (In.IsLimit() == false && State != HttpServerState::Header &&
    if (In.IsLimit() == false && State != HttpServerState::Header &&
-       Encoding != HttpServerState::Closes)
+       Persistent == true)
    {
    {
       Close();
       Close();
       if (LErrno == 0)
       if (LErrno == 0)
@@ -571,7 +571,7 @@ bool HttpServerState::Flush(FileFd * const File)
 	    return true;
 	    return true;
       }
       }
 
 
-      if (In.IsLimit() == true || Encoding == ServerState::Closes)
+      if (In.IsLimit() == true || Persistent == false)
 	 return true;
 	 return true;
    }
    }
    return false;
    return false;

+ 21 - 7
test/interactive-helper/aptwebserver.cc

@@ -598,17 +598,24 @@ static void * handleClient(void * voidclient)				/*{{{*/
 {
 {
    int client = *((int*)(voidclient));
    int client = *((int*)(voidclient));
    std::clog << "ACCEPT client " << client << std::endl;
    std::clog << "ACCEPT client " << client << std::endl;
-   std::vector<std::string> messages;
    bool closeConnection = false;
    bool closeConnection = false;
-   std::list<std::string> headers;
-   while (closeConnection == false && ReadMessages(client, messages))
+   while (closeConnection == false)
    {
    {
-      // if we announced a closing, do the close
-      if (std::find(headers.begin(), headers.end(), std::string("Connection: close")) != headers.end())
+      std::vector<std::string> messages;
+      if (ReadMessages(client, messages) == false)
 	 break;
 	 break;
-      headers.clear();
+
+      std::list<std::string> headers;
       for (std::vector<std::string>::const_iterator m = messages.begin();
       for (std::vector<std::string>::const_iterator m = messages.begin();
 	    m != messages.end() && closeConnection == false; ++m) {
 	    m != messages.end() && closeConnection == false; ++m) {
+	 // if we announced a closing in previous response, do the close now
+	 if (std::find(headers.begin(), headers.end(), std::string("Connection: close")) != headers.end())
+	 {
+	    closeConnection = true;
+	    break;
+	 }
+	 headers.clear();
+
 	 std::clog << ">>> REQUEST from " << client << " >>>" << std::endl << *m
 	 std::clog << ">>> REQUEST from " << client << " >>>" << std::endl << *m
 	    << std::endl << "<<<<<<<<<<<<<<<<" << std::endl;
 	    << std::endl << "<<<<<<<<<<<<<<<<" << std::endl;
 	 std::string filename;
 	 std::string filename;
@@ -760,9 +767,16 @@ static void * handleClient(void * voidclient)				/*{{{*/
 	 else
 	 else
 	    sendError(client, 404, *m, sendContent, "", headers);
 	    sendError(client, 404, *m, sendContent, "", headers);
       }
       }
+
+      // if we announced a closing in the last response, do the close now
+      if (std::find(headers.begin(), headers.end(), std::string("Connection: close")) != headers.end())
+	 closeConnection = true;
+
+      if (_error->PendingError() == true)
+	 break;
       _error->DumpErrors(std::cerr);
       _error->DumpErrors(std::cerr);
-      messages.clear();
    }
    }
+   _error->DumpErrors(std::cerr);
    close(client);
    close(client);
    std::clog << "CLOSE client " << client << std::endl;
    std::clog << "CLOSE client " << client << std::endl;
    return NULL;
    return NULL;