mercurial/url.py
changeset 49279 127d33e63d1a
parent 48946 642e31cb55f0
parent 49277 51b07ac1991c
child 49390 9f3edb305261
equal deleted inserted replaced
49275:c6a3243567b6 49279:127d33e63d1a
    10 
    10 
    11 import base64
    11 import base64
    12 import socket
    12 import socket
    13 
    13 
    14 from .i18n import _
    14 from .i18n import _
    15 from .pycompat import getattr
       
    16 from . import (
    15 from . import (
    17     encoding,
    16     encoding,
    18     error,
    17     error,
    19     httpconnection as httpconnectionmod,
    18     httpconnection as httpconnectionmod,
    20     keepalive,
    19     keepalive,
   196 
   195 
   197 class httpconnection(keepalive.HTTPConnection):
   196 class httpconnection(keepalive.HTTPConnection):
   198     # must be able to send big bundle as stream.
   197     # must be able to send big bundle as stream.
   199     send = _gen_sendfile(keepalive.HTTPConnection.send)
   198     send = _gen_sendfile(keepalive.HTTPConnection.send)
   200 
   199 
   201     def getresponse(self):
       
   202         proxyres = getattr(self, 'proxyres', None)
       
   203         if proxyres:
       
   204             if proxyres.will_close:
       
   205                 self.close()
       
   206             self.proxyres = None
       
   207             return proxyres
       
   208         return keepalive.HTTPConnection.getresponse(self)
       
   209 
       
   210 
   200 
   211 # Large parts of this function have their origin from before Python 2.6
   201 # Large parts of this function have their origin from before Python 2.6
   212 # and could potentially be removed.
   202 # and could potentially be removed.
   213 def _generic_start_transaction(handler, h, req):
   203 def _generic_start_transaction(handler, h, req):
   214     tunnel_host = req._tunnel_host
   204     tunnel_host = req._tunnel_host
   253         version, status, reason = res._read_status()
   243         version, status, reason = res._read_status()
   254         if status != httplib.CONTINUE:
   244         if status != httplib.CONTINUE:
   255             break
   245             break
   256         # skip lines that are all whitespace
   246         # skip lines that are all whitespace
   257         list(iter(lambda: res.fp.readline().strip(), b''))
   247         list(iter(lambda: res.fp.readline().strip(), b''))
   258     res.status = status
   248 
   259     res.reason = reason.strip()
   249     if status == 200:
   260 
       
   261     if res.status == 200:
       
   262         # skip lines until we find a blank line
   250         # skip lines until we find a blank line
   263         list(iter(res.fp.readline, b'\r\n'))
   251         list(iter(res.fp.readline, b'\r\n'))
   264         return True
       
   265 
       
   266     if version == b'HTTP/1.0':
       
   267         res.version = 10
       
   268     elif version.startswith(b'HTTP/1.'):
       
   269         res.version = 11
       
   270     elif version == b'HTTP/0.9':
       
   271         res.version = 9
       
   272     else:
   252     else:
   273         raise httplib.UnknownProtocol(version)
   253         self.close()
   274 
   254         raise socket.error(
   275     if res.version == 9:
   255             "Tunnel connection failed: %d %s" % (status, reason.strip())
   276         res.length = None
   256         )
   277         res.chunked = 0
       
   278         res.will_close = 1
       
   279         res.msg = httplib.HTTPMessage(stringio())
       
   280         return False
       
   281 
       
   282     res.msg = httplib.HTTPMessage(res.fp)
       
   283     res.msg.fp = None
       
   284 
       
   285     # are we using the chunked-style of transfer encoding?
       
   286     trenc = res.msg.getheader(b'transfer-encoding')
       
   287     if trenc and trenc.lower() == b"chunked":
       
   288         res.chunked = 1
       
   289         res.chunk_left = None
       
   290     else:
       
   291         res.chunked = 0
       
   292 
       
   293     # will the connection close at the end of the response?
       
   294     res.will_close = res._check_close()
       
   295 
       
   296     # do we have a Content-Length?
       
   297     # NOTE: RFC 2616, section 4.4, #3 says we ignore this if
       
   298     # transfer-encoding is "chunked"
       
   299     length = res.msg.getheader(b'content-length')
       
   300     if length and not res.chunked:
       
   301         try:
       
   302             res.length = int(length)
       
   303         except ValueError:
       
   304             res.length = None
       
   305         else:
       
   306             if res.length < 0:  # ignore nonsensical negative lengths
       
   307                 res.length = None
       
   308     else:
       
   309         res.length = None
       
   310 
       
   311     # does the body have a fixed length? (of zero)
       
   312     if (
       
   313         status == httplib.NO_CONTENT
       
   314         or status == httplib.NOT_MODIFIED
       
   315         or 100 <= status < 200
       
   316         or res._method == b'HEAD'  # 1xx codes
       
   317     ):
       
   318         res.length = 0
       
   319 
       
   320     # if the connection remains open, and we aren't using chunked, and
       
   321     # a content-length was not provided, then assume that the connection
       
   322     # WILL close.
       
   323     if not res.will_close and not res.chunked and res.length is None:
       
   324         res.will_close = 1
       
   325 
       
   326     self.proxyres = res
       
   327 
       
   328     return False
       
   329 
   257 
   330 
   258 
   331 class httphandler(keepalive.HTTPHandler):
   259 class httphandler(keepalive.HTTPHandler):
   332     def http_open(self, req):
   260     def http_open(self, req):
   333         return self.do_open(httpconnection, req)
   261         return self.do_open(httpconnection, req)