Пример #1
0
 def received(self, data):
     """
     Receives the HTTP stream for one request.  Returns the number of
     bytes consumed.  Sets the completed flag once both the header and the
     body have been received.
     """
     if self.completed:
         return 0  # Can't consume any more.
     datalen = len(data)
     br = self.body_rcv
     if br is None:
         # In header.
         s = self.header_plus + data
         index = find_double_newline(s)
         if index >= 0:
             # Header finished.
             header_plus = s[:index]
             consumed = len(data) - (len(s) - index)
             # Remove preceeding blank lines.
             header_plus = header_plus.lstrip()
             if not header_plus:
                 self.empty = True
                 self.completed = True
             else:
                 try:
                     self.parse_header(header_plus)
                 except ParsingError as e:
                     self.error = BadRequest(e.args[0])
                     self.completed = True
                 else:
                     if self.body_rcv is None:
                         # no content-length header and not a t-e: chunked
                         # request
                         self.completed = True
                     if self.content_length > 0:
                         max_body = self.adj.max_request_body_size
                         # we won't accept this request if the content-length
                         # is too large
                         if self.content_length >= max_body:
                             self.error = RequestEntityTooLarge(
                                 'exceeds max_body of %s' % max_body)
                             self.completed = True
             self.headers_finished = True
             return consumed
         else:
             # Header not finished yet.
             self.header_bytes_received += datalen
             max_header = self.adj.max_request_header_size
             if self.header_bytes_received >= max_header:
                 # malformed header, we need to construct some request
                 # on our own. we disregard the incoming(?) requests HTTP
                 # version and just use 1.0. IOW someone just sent garbage
                 # over the wire
                 self.parse_header(b'GET / HTTP/1.0\n')
                 self.error = RequestHeaderFieldsTooLarge(
                     'exceeds max_header of %s' % max_header)
                 self.completed = True
             self.header_plus = s
             return datalen
     else:
         # In body.
         consumed = br.received(data)
         self.body_bytes_received += consumed
         max_body = self.adj.max_request_body_size
         if self.body_bytes_received >= max_body:
             # this will only be raised during t-e: chunked requests
             self.error = RequestEntityTooLarge('exceeds max_body of %s' %
                                                max_body)
             self.completed = True
         elif br.error:
             # garbage in chunked encoding input probably
             self.error = br.error
             self.completed = True
         elif br.completed:
             # The request (with the body) is ready to use.
             self.completed = True
             if self.chunked:
                 # We've converted the chunked transfer encoding request
                 # body into a normal request body, so we know its content
                 # length; set the header here.  We already popped the
                 # TRANSFER_ENCODING header in parse_header, so this will
                 # appear to the client to be an entirely non-chunked HTTP
                 # request with a valid content-length.
                 self.headers['CONTENT_LENGTH'] = str(br.__len__())
         return consumed
Пример #2
0
    def received(self, data):
        """
        Receives the HTTP stream for one request.  Returns the number of
        bytes consumed.  Sets the completed flag once both the header and the
        body have been received.
        """
        if self.completed:
            return 0  # Can't consume any more.

        datalen = len(data)
        br = self.body_rcv
        if br is None:
            # In header.
            max_header = self.adj.max_request_header_size

            s = self.header_plus + data
            index = find_double_newline(s)
            consumed = 0

            if index >= 0:
                # If the headers have ended, and we also have part of the body
                # message in data we still want to validate we aren't going
                # over our limit for received headers.
                self.header_bytes_received += index
                consumed = datalen - (len(s) - index)
            else:
                self.header_bytes_received += datalen
                consumed = datalen

            # If the first line + headers is over the max length, we return a
            # RequestHeaderFieldsTooLarge error rather than continuing to
            # attempt to parse the headers.
            if self.header_bytes_received >= max_header:
                self.parse_header(b"GET / HTTP/1.0\r\n")
                self.error = RequestHeaderFieldsTooLarge(
                    "exceeds max_header of %s" % max_header)
                self.completed = True
                return consumed

            if index >= 0:
                # Header finished.
                header_plus = s[:index]

                # Remove preceeding blank lines. This is suggested by
                # https://tools.ietf.org/html/rfc7230#section-3.5 to support
                # clients sending an extra CR LF after another request when
                # using HTTP pipelining
                header_plus = header_plus.lstrip()

                if not header_plus:
                    self.empty = True
                    self.completed = True
                else:
                    try:
                        self.parse_header(header_plus)
                    except ParsingError as e:
                        self.error = BadRequest(e.args[0])
                        self.completed = True
                    except TransferEncodingNotImplemented as e:
                        self.error = ServerNotImplemented(e.args[0])
                        self.completed = True
                    else:
                        if self.body_rcv is None:
                            # no content-length header and not a t-e: chunked
                            # request
                            self.completed = True

                        if self.content_length > 0:
                            max_body = self.adj.max_request_body_size
                            # we won't accept this request if the content-length
                            # is too large

                            if self.content_length >= max_body:
                                self.error = RequestEntityTooLarge(
                                    "exceeds max_body of %s" % max_body)
                                self.completed = True
                self.headers_finished = True

                return consumed

            # Header not finished yet.
            self.header_plus = s

            return datalen
        else:
            # In body.
            consumed = br.received(data)
            self.body_bytes_received += consumed
            max_body = self.adj.max_request_body_size

            if self.body_bytes_received >= max_body:
                # this will only be raised during t-e: chunked requests
                self.error = RequestEntityTooLarge("exceeds max_body of %s" %
                                                   max_body)
                self.completed = True
            elif br.error:
                # garbage in chunked encoding input probably
                self.error = br.error
                self.completed = True
            elif br.completed:
                # The request (with the body) is ready to use.
                self.completed = True

                if self.chunked:
                    # We've converted the chunked transfer encoding request
                    # body into a normal request body, so we know its content
                    # length; set the header here.  We already popped the
                    # TRANSFER_ENCODING header in parse_header, so this will
                    # appear to the client to be an entirely non-chunked HTTP
                    # request with a valid content-length.
                    self.headers["CONTENT_LENGTH"] = str(br.__len__())

            return consumed
Пример #3
0
 def received(self, data):
     """
     Receives the HTTP stream for one request.  Returns the number of
     bytes consumed.  Sets the completed flag once both the header and the
     body have been received.
     """
     if self.completed:
         return 0  # Can't consume any more.
     datalen = len(data)
     br = self.body_rcv
     if br is None:
         # In header.
         s = self.header_plus + data
         index = find_double_newline(s)
         if index >= 0:
             # Header finished.
             header_plus = s[:index]
             consumed = len(data) - (len(s) - index)
             # Remove preceeding blank lines.
             header_plus = header_plus.lstrip()
             if not header_plus:
                 self.empty = True
                 self.completed = True
             else:
                 self.parse_header(header_plus)
                 if self.body_rcv is None:
                     # no content-length header and not a t-e: chunked
                     # request
                     self.completed = True
                 if self.content_length > 0:
                     max_body = self.adj.max_request_body_size
                     # we won't accept this request if the content-length
                     # is too large
                     if self.content_length >= max_body:
                         self.error = RequestEntityTooLarge(
                             'exceeds max_body of %s' % max_body)
                         self.completed = True
             self.headers_finished = True
             return consumed
         else:
             # Header not finished yet.
             self.header_bytes_received += datalen
             max_header = self.adj.max_request_header_size
             if self.header_bytes_received >= max_header:
                 self.parse_header(b'GET / HTTP/1.0\n')
                 self.error = RequestHeaderFieldsTooLarge(
                     'exceeds max_header of %s' % max_header)
                 self.completed = True
             self.header_plus = s
             return datalen
     else:
         # In body.
         consumed = br.received(data)
         self.body_bytes_received += consumed
         max_body = self.adj.max_request_body_size
         if self.body_bytes_received >= max_body:
             # this will only be raised during t-e: chunked requests
             self.error = RequestEntityTooLarge(
                 'exceeds max_body of %s' % max_body)
             self.completed = True
         elif br.error:
             # garbage in chunked encoding input probably
             self.error = br.error
             self.completed = True
         elif br.completed:
             self.completed = True
         return consumed