Ejemplo n.º 1
0
def handle_response(url, code, msg, data):
    """Interpret the code & headers and wrap the provided data in a RangeFile.

    This is a factory method which returns an appropriate RangeFile based on
    the code & headers it's given.

    :param url: The url being processed. Mostly for error reporting
    :param code: The integer HTTP response code
    :param msg: An HTTPMessage containing the headers for the response
    :param data: A file-like object that can be read() to get the
                 requested data
    :return: A file-like object that can seek()+read() the 
             ranges indicated by the headers.
    """
    rfile = RangeFile(url, data)
    if code == 200:
        # A whole file
        size = msg.getheader('content-length', None)
        if size is None:
            size = -1
        else:
            size = int(size)
        rfile.set_range(0, size)
    elif code == 206:
        content_type = msg.getheader('content-type', None)
        if content_type is None:
            # When there is no content-type header we treat the response as
            # being of type 'application/octet-stream' as per RFC2616 section
            # 7.2.1.
            # Therefore it is obviously not multipart
            content_type = 'application/octet-stream'
            is_multipart = False
        else:
            is_multipart = (msg.getmaintype() == 'multipart'
                            and msg.getsubtype() == 'byteranges')

        if is_multipart:
            # Full fledged multipart response
            rfile.set_boundary(msg.getparam('boundary'))
        else:
            # A response to a range request, but not multipart
            content_range = msg.getheader('content-range', None)
            if content_range is None:
                raise errors.InvalidHttpResponse(
                    url,
                    'Missing the Content-Range header in a 206 range response')
            rfile.set_range_from_header(content_range)
    else:
        raise errors.InvalidHttpResponse(url,
                                         'Unknown response code %s' % code)

    return rfile
Ejemplo n.º 2
0
    def _raise_curl_http_error(self, curl, info=None, body=None):
        """Common curl->bzrlib error translation.

        Some methods may choose to override this for particular cases.

        The URL and code are automatically included as appropriate.

        :param info: Extra information to include in the message.

        :param body: File-like object from which the body of the page can be
            read.
        """
        code = curl.getinfo(pycurl.HTTP_CODE)
        url = curl.getinfo(pycurl.EFFECTIVE_URL)
        if body is not None:
            response_body = body.read()
            plaintext_body = unhtml_roughly(response_body)
        else:
            response_body = None
            plaintext_body = ''
        if code == 403:
            raise errors.TransportError(
                'Server refuses to fulfill the request (403 Forbidden)'
                ' for %s: %s' % (url, plaintext_body))
        else:
            if info is None:
                msg = ''
            else:
                msg = ': ' + info
            raise errors.InvalidHttpResponse(
                url, 'Unable to handle http code %d%s: %s'
                % (code, msg, plaintext_body))
Ejemplo n.º 3
0
 def send_http_smart_request(self, bytes):
     try:
         # Get back the http_transport hold by the weak reference
         t = self._http_transport_ref()
         code, body_filelike = t._post(bytes)
         if code != 200:
             raise errors.InvalidHttpResponse(
                 t._remote_path('.bzr/smart'),
                 'Expected 200 response code, got %r' % (code, ))
     except (errors.InvalidHttpResponse, errors.ConnectionReset), e:
         raise errors.SmartProtocolError(str(e))
Ejemplo n.º 4
0
    def read_range_definition(self):
        """Read a new range definition in a multi parts message.

        Parse the headers including the empty line following them so that we
        are ready to read the data itself.
        """
        self._headers = httplib.HTTPMessage(self._file, seekable=0)
        # Extract the range definition
        content_range = self._headers.getheader('content-range', None)
        if content_range is None:
            raise errors.InvalidHttpResponse(
                self._path,
                'Content-Range header missing in a multi-part response')
        self.set_range_from_header(content_range)
Ejemplo n.º 5
0
 def _raise_curl_http_error(self, curl, info=None):
     code = curl.getinfo(pycurl.HTTP_CODE)
     url = curl.getinfo(pycurl.EFFECTIVE_URL)
     # Some error codes can be handled the same way for all
     # requests
     if code == 403:
         raise errors.TransportError(
             'Server refuses to fulfill the request (403 Forbidden)'
             ' for %s' % url)
     else:
         if info is None:
             msg = ''
         else:
             msg = ': ' + info
         raise errors.InvalidHttpResponse(
             url, 'Unable to handle http code %d%s' % (code, msg))
Ejemplo n.º 6
0
    def read_boundary(self):
        """Read the boundary headers defining a new range"""
        boundary_line = '\r\n'
        while boundary_line == '\r\n':
            # RFC2616 19.2 Additional CRLFs may precede the first boundary
            # string entity.
            # To be on the safe side we allow it before any boundary line
            boundary_line = self._file.readline()

        if boundary_line != '--' + self._boundary + '\r\n':
            # rfc822.unquote() incorrectly unquotes strings enclosed in <>
            # IIS 6 and 7 incorrectly wrap boundary strings in <>
            # together they make a beautiful bug, which we will be gracious
            # about here
            if (self._unquote_boundary(boundary_line) !=
                    '--' + self._boundary + '\r\n'):
                raise errors.InvalidHttpResponse(
                    self._path, "Expected a boundary (%s) line, got '%s'" %
                    (self._boundary, boundary_line))