4 # Copyright (C) 2007, 2008, 2010 Google Inc.
6 # This program is free software; you can redistribute it and/or modify
7 # it under the terms of the GNU General Public License as published by
8 # the Free Software Foundation; either version 2 of the License, or
9 # (at your option) any later version.
11 # This program is distributed in the hope that it will be useful, but
12 # WITHOUT ANY WARRANTY; without even the implied warranty of
13 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 # General Public License for more details.
16 # You should have received a copy of the GNU General Public License
17 # along with this program; if not, write to the Free Software
18 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
32 from cStringIO import StringIO
34 from ganeti import constants
35 from ganeti import utils
38 HTTP_GANETI_VERSION = "Ganeti %s" % constants.RELEASE_VERSION
42 HTTP_NOT_MODIFIED = 304
52 HTTP_DELETE = "DELETE"
56 HTTP_SERVER = "Server"
58 HTTP_USER_AGENT = "User-Agent"
59 HTTP_CONTENT_TYPE = "Content-Type"
60 HTTP_CONTENT_LENGTH = "Content-Length"
61 HTTP_CONNECTION = "Connection"
62 HTTP_KEEP_ALIVE = "Keep-Alive"
63 HTTP_WWW_AUTHENTICATE = "WWW-Authenticate"
64 HTTP_AUTHORIZATION = "Authorization"
65 HTTP_AUTHENTICATION_INFO = "Authentication-Info"
68 HTTP_APP_OCTET_STREAM = "application/octet-stream"
69 HTTP_APP_JSON = "application/json"
71 _SSL_UNEXPECTED_EOF = "Unexpected EOF"
77 SOCKOP_HANDSHAKE) = range(4)
79 # send/receive quantum
83 class HttpError(Exception):
84 """Internal exception for HTTP errors.
86 This should only be used for internal error reporting.
91 class HttpConnectionClosed(Exception):
92 """Internal exception for a closed connection.
94 This should only be used for internal error reporting. Only use
95 it if there's no other way to report this condition.
100 class HttpSessionHandshakeUnexpectedEOF(HttpError):
101 """Internal exception for errors during SSL handshake.
103 This should only be used for internal error reporting.
108 class HttpSocketTimeout(Exception):
109 """Internal exception for socket timeouts.
111 This should only be used for internal error reporting.
116 class HttpException(Exception):
120 def __init__(self, message=None, headers=None):
121 Exception.__init__(self)
122 self.message = message
123 self.headers = headers
126 class HttpBadRequest(HttpException):
129 RFC2616, 10.4.1: The request could not be understood by the server
130 due to malformed syntax. The client SHOULD NOT repeat the request
131 without modifications.
137 class HttpUnauthorized(HttpException):
140 RFC2616, section 10.4.2: The request requires user
141 authentication. The response MUST include a WWW-Authenticate header
142 field (section 14.47) containing a challenge applicable to the
149 class HttpForbidden(HttpException):
152 RFC2616, 10.4.4: The server understood the request, but is refusing
153 to fulfill it. Authorization will not help and the request SHOULD
160 class HttpNotFound(HttpException):
163 RFC2616, 10.4.5: The server has not found anything matching the
164 Request-URI. No indication is given of whether the condition is
165 temporary or permanent.
171 class HttpMethodNotAllowed(HttpException):
172 """405 Method Not Allowed
174 RFC2616, 10.4.6: The method specified in the Request-Line is not
175 allowed for the resource identified by the Request-URI. The response
176 MUST include an Allow header containing a list of valid methods for
177 the requested resource.
183 class HttpNotAcceptable(HttpException):
184 """406 Not Acceptable
186 RFC2616, 10.4.7: The resource identified by the request is only capable of
187 generating response entities which have content characteristics not
188 acceptable according to the accept headers sent in the request.
194 class HttpRequestTimeout(HttpException):
195 """408 Request Timeout
197 RFC2616, 10.4.9: The client did not produce a request within the
198 time that the server was prepared to wait. The client MAY repeat the
199 request without modifications at any later time.
205 class HttpConflict(HttpException):
208 RFC2616, 10.4.10: The request could not be completed due to a
209 conflict with the current state of the resource. This code is only
210 allowed in situations where it is expected that the user might be
211 able to resolve the conflict and resubmit the request.
217 class HttpGone(HttpException):
220 RFC2616, 10.4.11: The requested resource is no longer available at
221 the server and no forwarding address is known. This condition is
222 expected to be considered permanent.
228 class HttpLengthRequired(HttpException):
229 """411 Length Required
231 RFC2616, 10.4.12: The server refuses to accept the request without a
232 defined Content-Length. The client MAY repeat the request if it adds
233 a valid Content-Length header field containing the length of the
234 message-body in the request message.
240 class HttpPreconditionFailed(HttpException):
241 """412 Precondition Failed
243 RFC2616, 10.4.13: The precondition given in one or more of the
244 request-header fields evaluated to false when it was tested on the
251 class HttpUnsupportedMediaType(HttpException):
252 """415 Unsupported Media Type
254 RFC2616, 10.4.16: The server is refusing to service the request because the
255 entity of the request is in a format not supported by the requested resource
256 for the requested method.
262 class HttpInternalServerError(HttpException):
263 """500 Internal Server Error
265 RFC2616, 10.5.1: The server encountered an unexpected condition
266 which prevented it from fulfilling the request.
272 class HttpNotImplemented(HttpException):
273 """501 Not Implemented
275 RFC2616, 10.5.2: The server does not support the functionality
276 required to fulfill the request.
282 class HttpBadGateway(HttpException):
285 RFC2616, 10.5.3: The server, while acting as a gateway or proxy,
286 received an invalid response from the upstream server it accessed in
287 attempting to fulfill the request.
293 class HttpServiceUnavailable(HttpException):
294 """503 Service Unavailable
296 RFC2616, 10.5.4: The server is currently unable to handle the
297 request due to a temporary overloading or maintenance of the server.
303 class HttpGatewayTimeout(HttpException):
304 """504 Gateway Timeout
306 RFC2616, 10.5.5: The server, while acting as a gateway or proxy, did
307 not receive a timely response from the upstream server specified by
308 the URI (e.g. HTTP, FTP, LDAP) or some other auxiliary server
309 (e.g. DNS) it needed to access in attempting to complete the
316 class HttpVersionNotSupported(HttpException):
317 """505 HTTP Version Not Supported
319 RFC2616, 10.5.6: The server does not support, or refuses to support,
320 the HTTP protocol version that was used in the request message.
326 def ParseHeaders(buf):
327 """Parses HTTP headers.
329 @note: This is just a trivial wrapper around C{mimetools.Message}
332 return mimetools.Message(buf, 0)
335 def SocketOperation(sock, op, arg1, timeout):
336 """Wrapper around socket functions.
338 This function abstracts error handling for socket operations, especially
339 for the complicated interaction with OpenSSL.
342 @param sock: Socket for the operation
344 @param op: Operation to execute (SOCKOP_* constants)
346 @param arg1: Parameter for function (if needed)
347 @type timeout: None or float
348 @param timeout: Timeout in seconds or None
349 @return: Return value of socket function
352 # TODO: event_poll/event_check/override
353 if op in (SOCKOP_SEND, SOCKOP_HANDSHAKE):
354 event_poll = select.POLLOUT
356 elif op == SOCKOP_RECV:
357 event_poll = select.POLLIN
359 elif op == SOCKOP_SHUTDOWN:
362 # The timeout is only used when OpenSSL requests polling for a condition.
363 # It is not advisable to have no timeout for shutdown.
367 raise AssertionError("Invalid socket operation")
369 # Handshake is only supported by SSL sockets
370 if (op == SOCKOP_HANDSHAKE and
371 not isinstance(sock, OpenSSL.SSL.ConnectionType)):
374 # No override by default
378 # Poll only for certain operations and when asked for by an override
379 if event_override or op in (SOCKOP_SEND, SOCKOP_RECV, SOCKOP_HANDSHAKE):
381 wait_for_event = event_override
383 wait_for_event = event_poll
385 event = utils.WaitForFdCondition(sock, wait_for_event, timeout)
387 raise HttpSocketTimeout()
389 if event & (select.POLLNVAL | select.POLLHUP | select.POLLERR):
390 # Let the socket functions handle these
393 if not event & wait_for_event:
401 if op == SOCKOP_SEND:
402 return sock.send(arg1)
404 elif op == SOCKOP_RECV:
405 return sock.recv(arg1)
407 elif op == SOCKOP_SHUTDOWN:
408 if isinstance(sock, OpenSSL.SSL.ConnectionType):
409 # PyOpenSSL's shutdown() doesn't take arguments
410 return sock.shutdown()
412 return sock.shutdown(arg1)
414 elif op == SOCKOP_HANDSHAKE:
415 return sock.do_handshake()
417 except OpenSSL.SSL.WantWriteError:
418 # OpenSSL wants to write, poll for POLLOUT
419 event_override = select.POLLOUT
422 except OpenSSL.SSL.WantReadError:
423 # OpenSSL wants to read, poll for POLLIN
424 event_override = select.POLLIN | select.POLLPRI
427 except OpenSSL.SSL.WantX509LookupError:
430 except OpenSSL.SSL.ZeroReturnError, err:
431 # SSL Connection has been closed. In SSL 3.0 and TLS 1.0, this only
432 # occurs if a closure alert has occurred in the protocol, i.e. the
433 # connection has been closed cleanly. Note that this does not
434 # necessarily mean that the transport layer (e.g. a socket) has been
436 if op == SOCKOP_SEND:
437 # Can happen during a renegotiation
438 raise HttpConnectionClosed(err.args)
439 elif op == SOCKOP_RECV:
442 # SSL_shutdown shouldn't return SSL_ERROR_ZERO_RETURN
443 raise socket.error(err.args)
445 except OpenSSL.SSL.SysCallError, err:
446 if op == SOCKOP_SEND:
447 # arg1 is the data when writing
448 if err.args and err.args[0] == -1 and arg1 == "":
449 # errors when writing empty strings are expected
453 if err.args == (-1, _SSL_UNEXPECTED_EOF):
454 if op == SOCKOP_RECV:
456 elif op == SOCKOP_HANDSHAKE:
457 # Can happen if peer disconnects directly after the connection is
459 raise HttpSessionHandshakeUnexpectedEOF(err.args)
461 raise socket.error(err.args)
463 except OpenSSL.SSL.Error, err:
464 raise socket.error(err.args)
466 except socket.error, err:
467 if err.args and err.args[0] == errno.EAGAIN:
474 def ShutdownConnection(sock, close_timeout, write_timeout, msgreader, force):
475 """Closes the connection.
478 @param sock: Socket to be shut down
479 @type close_timeout: float
480 @param close_timeout: How long to wait for the peer to close
482 @type write_timeout: float
483 @param write_timeout: Write timeout for shutdown
484 @type msgreader: http.HttpMessageReader
485 @param msgreader: Request message reader, used to determine whether
486 peer should close connection
488 @param force: Whether to forcibly close the connection without
492 #print msgreader.peer_will_close, force
493 if msgreader and msgreader.peer_will_close and not force:
494 # Wait for peer to close
496 # Check whether it's actually closed
497 if not SocketOperation(sock, SOCKOP_RECV, 1, close_timeout):
499 except (socket.error, HttpError, HttpSocketTimeout):
500 # Ignore errors at this stage
503 # Close the connection from our side
505 # We don't care about the return value, see NOTES in SSL_shutdown(3).
506 SocketOperation(sock, SOCKOP_SHUTDOWN, socket.SHUT_RDWR,
508 except HttpSocketTimeout:
509 raise HttpError("Timeout while shutting down connection")
510 except socket.error, err:
512 if not (err.args and err.args[0] == errno.ENOTCONN):
513 raise HttpError("Error while shutting down connection: %s" % err)
516 def Handshake(sock, write_timeout):
517 """Shakes peer's hands.
520 @param sock: Socket to be shut down
521 @type write_timeout: float
522 @param write_timeout: Write timeout for handshake
526 return SocketOperation(sock, SOCKOP_HANDSHAKE, None, write_timeout)
527 except HttpSocketTimeout:
528 raise HttpError("Timeout during SSL handshake")
529 except socket.error, err:
530 raise HttpError("Error in SSL handshake: %s" % err)
534 """Initializes the SSL infrastructure.
536 This function is idempotent.
539 if not OpenSSL.rand.status():
540 raise EnvironmentError("OpenSSL could not collect enough entropy"
543 # TODO: Maybe add some additional seeding for OpenSSL's PRNG
546 class HttpSslParams(object):
547 """Data class for SSL key and certificate.
550 def __init__(self, ssl_key_path, ssl_cert_path):
551 """Initializes this class.
553 @type ssl_key_path: string
554 @param ssl_key_path: Path to file containing SSL key in PEM format
555 @type ssl_cert_path: string
556 @param ssl_cert_path: Path to file containing SSL certificate
560 self.ssl_key_pem = utils.ReadFile(ssl_key_path)
561 self.ssl_cert_pem = utils.ReadFile(ssl_cert_path)
562 self.ssl_cert_path = ssl_cert_path
565 return OpenSSL.crypto.load_privatekey(OpenSSL.crypto.FILETYPE_PEM,
568 def GetCertificate(self):
569 return OpenSSL.crypto.load_certificate(OpenSSL.crypto.FILETYPE_PEM,
573 class HttpBase(object):
574 """Base class for HTTP server and client.
578 self.using_ssl = None
579 self._ssl_params = None
581 self._ssl_cert = None
583 def _CreateSocket(self, ssl_params, ssl_verify_peer, family):
584 """Creates a TCP socket and initializes SSL if needed.
586 @type ssl_params: HttpSslParams
587 @param ssl_params: SSL key and certificate
588 @type ssl_verify_peer: bool
589 @param ssl_verify_peer: Whether to require client certificate
590 and compare it with our certificate
592 @param family: socket.AF_INET | socket.AF_INET6
595 assert family in (socket.AF_INET, socket.AF_INET6)
597 self._ssl_params = ssl_params
598 sock = socket.socket(family, socket.SOCK_STREAM)
600 # Should we enable SSL?
601 self.using_ssl = ssl_params is not None
603 if not self.using_ssl:
606 self._ssl_key = ssl_params.GetKey()
607 self._ssl_cert = ssl_params.GetCertificate()
609 ctx = OpenSSL.SSL.Context(OpenSSL.SSL.SSLv23_METHOD)
610 ctx.set_options(OpenSSL.SSL.OP_NO_SSLv2)
612 ciphers = self.GetSslCiphers()
613 logging.debug("Setting SSL cipher string %s", ciphers)
614 ctx.set_cipher_list(ciphers)
616 ctx.use_privatekey(self._ssl_key)
617 ctx.use_certificate(self._ssl_cert)
618 ctx.check_privatekey()
621 ctx.set_verify(OpenSSL.SSL.VERIFY_PEER |
622 OpenSSL.SSL.VERIFY_FAIL_IF_NO_PEER_CERT,
623 self._SSLVerifyCallback)
625 # Also add our certificate as a trusted CA to be sent to the client.
626 # This is required at least for GnuTLS clients to work.
628 # This will fail for PyOpenssl versions before 0.10
629 ctx.add_client_ca(self._ssl_cert)
630 except AttributeError:
631 # Fall back to letting OpenSSL read the certificate file directly.
632 ctx.load_client_ca(ssl_params.ssl_cert_path)
634 return OpenSSL.SSL.Connection(ctx, sock)
636 def GetSslCiphers(self): # pylint: disable=R0201
637 """Returns the ciphers string for SSL.
640 return constants.OPENSSL_CIPHERS
642 def _SSLVerifyCallback(self, conn, cert, errnum, errdepth, ok):
643 """Verify the certificate provided by the peer
645 We only compare fingerprints. The client must use the same certificate as
649 # some parameters are unused, but this is the API
650 # pylint: disable=W0613
651 assert self._ssl_params, "SSL not initialized"
653 return (self._ssl_cert.digest("sha1") == cert.digest("sha1") and
654 self._ssl_cert.digest("md5") == cert.digest("md5"))
657 class HttpMessage(object):
658 """Data structure for HTTP message.
662 self.start_line = None
667 class HttpClientToServerStartLine(object):
668 """Data structure for HTTP request start line.
671 def __init__(self, method, path, version):
674 self.version = version
677 return "%s %s %s" % (self.method, self.path, self.version)
680 class HttpServerToClientStartLine(object):
681 """Data structure for HTTP response start line.
684 def __init__(self, version, code, reason):
685 self.version = version
690 return "%s %s %s" % (self.version, self.code, self.reason)
693 class HttpMessageWriter(object):
694 """Writes an HTTP message to a socket.
697 def __init__(self, sock, msg, write_timeout):
698 """Initializes this class and writes an HTTP message to a socket.
701 @param sock: Socket to be written to
702 @type msg: http.HttpMessage
703 @param msg: HTTP message to be written
704 @type write_timeout: float
705 @param write_timeout: Write timeout for socket
710 self._PrepareMessage()
712 buf = self._FormatMessage()
717 # Send only SOCK_BUF_SIZE bytes at a time
718 data = buf[pos:(pos + SOCK_BUF_SIZE)]
720 sent = SocketOperation(sock, SOCKOP_SEND, data, write_timeout)
725 assert pos == end, "Message wasn't sent completely"
727 def _PrepareMessage(self):
728 """Prepares the HTTP message by setting mandatory headers.
731 # RFC2616, section 4.3: "The presence of a message-body in a request is
732 # signaled by the inclusion of a Content-Length or Transfer-Encoding header
733 # field in the request's message-headers."
735 self._msg.headers[HTTP_CONTENT_LENGTH] = len(self._msg.body)
737 def _FormatMessage(self):
738 """Serializes the HTTP message into a string.
744 buf.write(str(self._msg.start_line))
748 if self._msg.start_line.version != HTTP_0_9:
749 for name, value in self._msg.headers.iteritems():
750 buf.write("%s: %s\r\n" % (name, value))
754 # Add message body if needed
755 if self.HasMessageBody():
756 buf.write(self._msg.body)
759 logging.warning("Ignoring message body")
761 return buf.getvalue()
763 def HasMessageBody(self):
764 """Checks whether the HTTP message contains a body.
766 Can be overridden by subclasses.
769 return bool(self._msg.body)
772 class HttpMessageReader(object):
773 """Reads HTTP message from socket.
777 START_LINE_LENGTH_MAX = None
778 HEADER_LENGTH_MAX = None
780 # Parser state machine
781 PS_START_LINE = "start-line"
782 PS_HEADERS = "headers"
783 PS_BODY = "entity-body"
784 PS_COMPLETE = "complete"
786 def __init__(self, sock, msg, read_timeout):
787 """Reads an HTTP message from a socket.
790 @param sock: Socket to be read from
791 @type msg: http.HttpMessage
792 @param msg: Object for the read message
793 @type read_timeout: float
794 @param read_timeout: Read timeout for socket
800 self.start_line_buffer = None
801 self.header_buffer = StringIO()
802 self.body_buffer = StringIO()
803 self.parser_status = self.PS_START_LINE
804 self.content_length = None
805 self.peer_will_close = None
809 while self.parser_status != self.PS_COMPLETE:
810 # TODO: Don't read more than necessary (Content-Length), otherwise
811 # data might be lost and/or an error could occur
812 data = SocketOperation(sock, SOCKOP_RECV, SOCK_BUF_SIZE, read_timeout)
819 # Do some parsing and error checking while more data arrives
820 buf = self._ContinueParsing(buf, eof)
822 # Must be done only after the buffer has been evaluated
823 # TODO: Content-Length < len(data read) and connection closed
825 self.parser_status in (self.PS_START_LINE,
827 raise HttpError("Connection closed prematurely")
830 buf = self._ContinueParsing(buf, True)
832 assert self.parser_status == self.PS_COMPLETE
833 assert not buf, "Parser didn't read full response"
836 msg.body = self.body_buffer.getvalue()
838 def _ContinueParsing(self, buf, eof):
839 """Main function for HTTP message state machine.
842 @param buf: Receive buffer
844 @param eof: Whether we've reached EOF on the socket
846 @return: Updated receive buffer
849 # TODO: Use offset instead of slicing when possible
850 if self.parser_status == self.PS_START_LINE:
853 idx = buf.find("\r\n")
855 # RFC2616, section 4.1: "In the interest of robustness, servers SHOULD
856 # ignore any empty line(s) received where a Request-Line is expected.
857 # In other words, if the server is reading the protocol stream at the
858 # beginning of a message and receives a CRLF first, it should ignore
861 # TODO: Limit number of CRLFs/empty lines for safety?
866 self.start_line_buffer = buf[:idx]
868 self._CheckStartLineLength(len(self.start_line_buffer))
870 # Remove status line, including CRLF
873 self.msg.start_line = self.ParseStartLine(self.start_line_buffer)
875 self.parser_status = self.PS_HEADERS
877 # Check whether incoming data is getting too large, otherwise we just
878 # fill our read buffer.
879 self._CheckStartLineLength(len(buf))
883 # TODO: Handle messages without headers
884 if self.parser_status == self.PS_HEADERS:
885 # Wait for header end
886 idx = buf.find("\r\n\r\n")
888 self.header_buffer.write(buf[:idx + 2])
890 self._CheckHeaderLength(self.header_buffer.tell())
892 # Remove headers, including CRLF
897 self.parser_status = self.PS_BODY
899 # Check whether incoming data is getting too large, otherwise we just
900 # fill our read buffer.
901 self._CheckHeaderLength(len(buf))
903 if self.parser_status == self.PS_BODY:
904 # TODO: Implement max size for body_buffer
905 self.body_buffer.write(buf)
908 # Check whether we've read everything
910 # RFC2616, section 4.4: "When a message-body is included with a message,
911 # the transfer-length of that body is determined by one of the following
912 # [...] 5. By the server closing the connection. (Closing the connection
913 # cannot be used to indicate the end of a request body, since that would
914 # leave no possibility for the server to send back a response.)"
916 # TODO: Error when buffer length > Content-Length header
918 self.content_length is None or
919 (self.content_length is not None and
920 self.body_buffer.tell() >= self.content_length)):
921 self.parser_status = self.PS_COMPLETE
925 def _CheckStartLineLength(self, length):
926 """Limits the start line buffer size.
929 @param length: Buffer size
932 if (self.START_LINE_LENGTH_MAX is not None and
933 length > self.START_LINE_LENGTH_MAX):
934 raise HttpError("Start line longer than %d chars" %
935 self.START_LINE_LENGTH_MAX)
937 def _CheckHeaderLength(self, length):
938 """Limits the header buffer size.
941 @param length: Buffer size
944 if (self.HEADER_LENGTH_MAX is not None and
945 length > self.HEADER_LENGTH_MAX):
946 raise HttpError("Headers longer than %d chars" % self.HEADER_LENGTH_MAX)
948 def ParseStartLine(self, start_line):
949 """Parses the start line of a message.
951 Must be overridden by subclass.
953 @type start_line: string
954 @param start_line: Start line string
957 raise NotImplementedError()
959 def _WillPeerCloseConnection(self):
960 """Evaluate whether peer will close the connection.
963 @return: Whether peer will close the connection
966 # RFC2616, section 14.10: "HTTP/1.1 defines the "close" connection option
967 # for the sender to signal that the connection will be closed after
968 # completion of the response. For example,
972 # in either the request or the response header fields indicates that the
973 # connection SHOULD NOT be considered `persistent' (section 8.1) after the
974 # current request/response is complete."
976 hdr_connection = self.msg.headers.get(HTTP_CONNECTION, None)
978 hdr_connection = hdr_connection.lower()
980 # An HTTP/1.1 server is assumed to stay open unless explicitly closed.
981 if self.msg.start_line.version == HTTP_1_1:
982 return (hdr_connection and "close" in hdr_connection)
984 # Some HTTP/1.0 implementations have support for persistent connections,
985 # using rules different than HTTP/1.1.
987 # For older HTTP, Keep-Alive indicates persistent connection.
988 if self.msg.headers.get(HTTP_KEEP_ALIVE):
991 # At least Akamai returns a "Connection: Keep-Alive" header, which was
992 # supposed to be sent by the client.
993 if hdr_connection and "keep-alive" in hdr_connection:
998 def _ParseHeaders(self):
999 """Parses the headers.
1001 This function also adjusts internal variables based on header values.
1003 RFC2616, section 4.3: The presence of a message-body in a request is
1004 signaled by the inclusion of a Content-Length or Transfer-Encoding header
1005 field in the request's message-headers.
1009 self.header_buffer.seek(0, 0)
1010 self.msg.headers = ParseHeaders(self.header_buffer)
1012 self.peer_will_close = self._WillPeerCloseConnection()
1014 # Do we have a Content-Length header?
1015 hdr_content_length = self.msg.headers.get(HTTP_CONTENT_LENGTH, None)
1016 if hdr_content_length:
1018 self.content_length = int(hdr_content_length)
1019 except (TypeError, ValueError):
1020 self.content_length = None
1021 if self.content_length is not None and self.content_length < 0:
1022 self.content_length = None
1024 # if the connection remains open and a content-length was not provided,
1025 # then assume that the connection WILL close.
1026 if self.content_length is None:
1027 self.peer_will_close = True