[Date Prev][Date Next] [Thread Prev][Thread Next] [Date Index] [Thread Index]

Bug#64530: apt: The http method does not work correctly for HTTP/1.0 proxies



Package: apt
Version: 0.3.18
Severity: normal

The current version of the apt http method has some support for HTTP/1.0 servers
and proxies, but is not consistent.

-------------------- HttpMethod::SendReq() --------------------

   /* Build the request. We include a keep-alive header only for non-proxy
      requests. This is to tweak old http/1.0 servers that do support keep-alive
      but not HTTP/1.1 automatic keep-alive. Doing this with a proxy server 
      will glitch HTTP/1.0 proxies because they do not filter it out and 
      pass it on, HTTP/1.1 says the connection should default to keep alive
      and we expect the proxy to do this */

-------------------- HttpMethod::SendReq() --------------------

This is good, it shows that the workings of HTTP/1.0 and HTTP/1.1 are recognised
and that HTTP/1.0 will close the connection.


-------------------- ServerState::HeaderLine() --------------------

   if (stringcasecmp(Tag.begin(),Tag.begin()+4,"HTTP") == 0)
   {
      // Evil servers return no version
      if (Line[4] == '/')
      {
	 if (sscanf(Line.c_str(),"HTTP/%u.%u %u %[^\n]",&Major,&Minor,
		    &Result,Code) != 4)
	    return _error->Error("The http server sent an invalid reply header");
      }
      else
      {
	 Major = 0;
	 Minor = 9;
	 if (sscanf(Line.c_str(),"HTTP %u %[^\n]",&Result,Code) != 2)
	    return _error->Error("The http server sent an invalid reply header");
      }
      
      return true;
   }      

-------------------- ServerState::HeaderLine() --------------------

This is the code that checks for the returned header from the server.  There is
no checking here if the server is HTTP/1.0 or HTTP/1.1.  I think that you need
the following two lines before the return statement.

      if(Major==0 || (Major==1 && Minor==0))
         Encoding = Closes;


-------------------- ServerState::HeaderLine() --------------------

   if (stringcasecmp(Tag,"Content-Length:") == 0)
   {
      if (Encoding == Closes)
	 Encoding = Stream;

-------------------- ServerState::HeaderLine() --------------------

Here the if statement says that if there is a "Content-Length:" header then the
connection will not close.  This is different to what is said in the comment in
HttpMethod::SendReq(), there is no reason for an HTTP/1.0 server to not send
this header.  You need to remove those two lines.


-------------------- ServerState::HeaderLine() --------------------
-------------------- ServerState::HeaderLine() --------------------

There is no code in this function to test for "Connection:" headers like
HTTP/1.1 says there might be.  A "Connection: close" from an HTTP/1.1 server
means that the connection will be closed.

I think that you need code like this:

   if (stringcasecmp(Tag,"Connection:") == 0)
   {
    if (stringcasecmp(Val,"Close") == 0)
       Encoding = Closes;
   }


Having tried these modifications on an HTTP/1.0 proxy I have noticed a much
better performance.  Previously about half of the requests to the server were
never made (checking the server logs).  I think this is because they were made
to the same connection as the previous request.  With these changes all except
one requests work.  I am still trying to debug that one since the correct amount
of data seems to have been sent, but apt reports that gzip cannot unzip it.


-- System Information
Debian Release: 2.2
Kernel Version: Linux g2 2.2.14 #1 Sun Apr 16 09:42:29 BST 2000 i586 unknown

Versions of the packages apt depends on:
ii  libc6          2.1.3-10       GNU C Library: Shared libraries and Timezone
ii  libstdc++2.10  2.95.2-10      The GNU stdc++ library



Reply to: