Package ganeti :: Package http
[hide private]
[frames] | no frames]

Source Code for Package ganeti.http

  1  # 
  2  # 
  3   
  4  # Copyright (C) 2007, 2008 Google Inc. 
  5  # 
  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. 
 10  # 
 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. 
 15  # 
 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 
 19  # 02110-1301, USA. 
 20   
 21  """HTTP module. 
 22   
 23  """ 
 24   
 25  import logging 
 26  import mimetools 
 27  import OpenSSL 
 28  import select 
 29  import socket 
 30  import errno 
 31   
 32  from cStringIO import StringIO 
 33   
 34  from ganeti import constants 
 35  from ganeti import serializer 
 36  from ganeti import utils 
 37   
 38   
 39  HTTP_GANETI_VERSION = "Ganeti %s" % constants.RELEASE_VERSION 
 40   
 41  HTTP_OK = 200 
 42  HTTP_NO_CONTENT = 204 
 43  HTTP_NOT_MODIFIED = 304 
 44   
 45  HTTP_0_9 = "HTTP/0.9" 
 46  HTTP_1_0 = "HTTP/1.0" 
 47  HTTP_1_1 = "HTTP/1.1" 
 48   
 49  HTTP_GET = "GET" 
 50  HTTP_HEAD = "HEAD" 
 51  HTTP_POST = "POST" 
 52  HTTP_PUT = "PUT" 
 53  HTTP_DELETE = "DELETE" 
 54   
 55  HTTP_ETAG = "ETag" 
 56  HTTP_HOST = "Host" 
 57  HTTP_SERVER = "Server" 
 58  HTTP_DATE = "Date" 
 59  HTTP_USER_AGENT = "User-Agent" 
 60  HTTP_CONTENT_TYPE = "Content-Type" 
 61  HTTP_CONTENT_LENGTH = "Content-Length" 
 62  HTTP_CONNECTION = "Connection" 
 63  HTTP_KEEP_ALIVE = "Keep-Alive" 
 64  HTTP_WWW_AUTHENTICATE = "WWW-Authenticate" 
 65  HTTP_AUTHORIZATION = "Authorization" 
 66  HTTP_AUTHENTICATION_INFO = "Authentication-Info" 
 67  HTTP_ALLOW = "Allow" 
 68   
 69  _SSL_UNEXPECTED_EOF = "Unexpected EOF" 
 70   
 71  # Socket operations 
 72  (SOCKOP_SEND, 
 73   SOCKOP_RECV, 
 74   SOCKOP_SHUTDOWN, 
 75   SOCKOP_HANDSHAKE) = range(4) 
 76   
 77  # send/receive quantum 
 78  SOCK_BUF_SIZE = 32768 
79 80 81 -class HttpError(Exception):
82 """Internal exception for HTTP errors. 83 84 This should only be used for internal error reporting. 85 86 """
87
88 89 -class HttpConnectionClosed(Exception):
90 """Internal exception for a closed connection. 91 92 This should only be used for internal error reporting. Only use 93 it if there's no other way to report this condition. 94 95 """
96
97 98 -class HttpSessionHandshakeUnexpectedEOF(HttpError):
99 """Internal exception for errors during SSL handshake. 100 101 This should only be used for internal error reporting. 102 103 """
104
105 106 -class HttpSocketTimeout(Exception):
107 """Internal exception for socket timeouts. 108 109 This should only be used for internal error reporting. 110 111 """
112
113 114 -class HttpException(Exception):
115 code = None 116 message = None 117
118 - def __init__(self, message=None, headers=None):
119 Exception.__init__(self) 120 self.message = message 121 self.headers = headers
122
123 124 -class HttpBadRequest(HttpException):
125 """400 Bad Request 126 127 RFC2616, 10.4.1: The request could not be understood by the server 128 due to malformed syntax. The client SHOULD NOT repeat the request 129 without modifications. 130 131 """ 132 code = 400
133
134 135 -class HttpUnauthorized(HttpException):
136 """401 Unauthorized 137 138 RFC2616, section 10.4.2: The request requires user 139 authentication. The response MUST include a WWW-Authenticate header 140 field (section 14.47) containing a challenge applicable to the 141 requested resource. 142 143 """ 144 code = 401
145
146 147 -class HttpForbidden(HttpException):
148 """403 Forbidden 149 150 RFC2616, 10.4.4: The server understood the request, but is refusing 151 to fulfill it. Authorization will not help and the request SHOULD 152 NOT be repeated. 153 154 """ 155 code = 403
156
157 158 -class HttpNotFound(HttpException):
159 """404 Not Found 160 161 RFC2616, 10.4.5: The server has not found anything matching the 162 Request-URI. No indication is given of whether the condition is 163 temporary or permanent. 164 165 """ 166 code = 404
167
168 169 -class HttpMethodNotAllowed(HttpException):
170 """405 Method Not Allowed 171 172 RFC2616, 10.4.6: The method specified in the Request-Line is not 173 allowed for the resource identified by the Request-URI. The response 174 MUST include an Allow header containing a list of valid methods for 175 the requested resource. 176 177 """ 178 code = 405
179
180 181 -class HttpRequestTimeout(HttpException):
182 """408 Request Timeout 183 184 RFC2616, 10.4.9: The client did not produce a request within the 185 time that the server was prepared to wait. The client MAY repeat the 186 request without modifications at any later time. 187 188 """ 189 code = 408
190
191 192 -class HttpConflict(HttpException):
193 """409 Conflict 194 195 RFC2616, 10.4.10: The request could not be completed due to a 196 conflict with the current state of the resource. This code is only 197 allowed in situations where it is expected that the user might be 198 able to resolve the conflict and resubmit the request. 199 200 """ 201 code = 409
202
203 204 -class HttpGone(HttpException):
205 """410 Gone 206 207 RFC2616, 10.4.11: The requested resource is no longer available at 208 the server and no forwarding address is known. This condition is 209 expected to be considered permanent. 210 211 """ 212 code = 410
213
214 215 -class HttpLengthRequired(HttpException):
216 """411 Length Required 217 218 RFC2616, 10.4.12: The server refuses to accept the request without a 219 defined Content-Length. The client MAY repeat the request if it adds 220 a valid Content-Length header field containing the length of the 221 message-body in the request message. 222 223 """ 224 code = 411
225
226 227 -class HttpPreconditionFailed(HttpException):
228 """412 Precondition Failed 229 230 RFC2616, 10.4.13: The precondition given in one or more of the 231 request-header fields evaluated to false when it was tested on the 232 server. 233 234 """ 235 code = 412
236
237 238 -class HttpInternalServerError(HttpException):
239 """500 Internal Server Error 240 241 RFC2616, 10.5.1: The server encountered an unexpected condition 242 which prevented it from fulfilling the request. 243 244 """ 245 code = 500
246
247 248 -class HttpNotImplemented(HttpException):
249 """501 Not Implemented 250 251 RFC2616, 10.5.2: The server does not support the functionality 252 required to fulfill the request. 253 254 """ 255 code = 501
256
257 258 -class HttpBadGateway(HttpException):
259 """502 Bad Gateway 260 261 RFC2616, 10.5.3: The server, while acting as a gateway or proxy, 262 received an invalid response from the upstream server it accessed in 263 attempting to fulfill the request. 264 265 """ 266 code = 502
267
268 269 -class HttpServiceUnavailable(HttpException):
270 """503 Service Unavailable 271 272 RFC2616, 10.5.4: The server is currently unable to handle the 273 request due to a temporary overloading or maintenance of the server. 274 275 """ 276 code = 503
277
278 279 -class HttpGatewayTimeout(HttpException):
280 """504 Gateway Timeout 281 282 RFC2616, 10.5.5: The server, while acting as a gateway or proxy, did 283 not receive a timely response from the upstream server specified by 284 the URI (e.g. HTTP, FTP, LDAP) or some other auxiliary server 285 (e.g. DNS) it needed to access in attempting to complete the 286 request. 287 288 """ 289 code = 504
290
291 292 -class HttpVersionNotSupported(HttpException):
293 """505 HTTP Version Not Supported 294 295 RFC2616, 10.5.6: The server does not support, or refuses to support, 296 the HTTP protocol version that was used in the request message. 297 298 """ 299 code = 505
300
301 302 -class HttpJsonConverter: # pylint: disable-msg=W0232
303 CONTENT_TYPE = "application/json" 304 305 @staticmethod
306 - def Encode(data):
307 return serializer.DumpJson(data)
308 309 @staticmethod
310 - def Decode(data):
311 return serializer.LoadJson(data)
312
313 314 -def SocketOperation(sock, op, arg1, timeout):
315 """Wrapper around socket functions. 316 317 This function abstracts error handling for socket operations, especially 318 for the complicated interaction with OpenSSL. 319 320 @type sock: socket 321 @param sock: Socket for the operation 322 @type op: int 323 @param op: Operation to execute (SOCKOP_* constants) 324 @type arg1: any 325 @param arg1: Parameter for function (if needed) 326 @type timeout: None or float 327 @param timeout: Timeout in seconds or None 328 @return: Return value of socket function 329 330 """ 331 # TODO: event_poll/event_check/override 332 if op in (SOCKOP_SEND, SOCKOP_HANDSHAKE): 333 event_poll = select.POLLOUT 334 335 elif op == SOCKOP_RECV: 336 event_poll = select.POLLIN 337 338 elif op == SOCKOP_SHUTDOWN: 339 event_poll = None 340 341 # The timeout is only used when OpenSSL requests polling for a condition. 342 # It is not advisable to have no timeout for shutdown. 343 assert timeout 344 345 else: 346 raise AssertionError("Invalid socket operation") 347 348 # Handshake is only supported by SSL sockets 349 if (op == SOCKOP_HANDSHAKE and 350 not isinstance(sock, OpenSSL.SSL.ConnectionType)): 351 return 352 353 # No override by default 354 event_override = 0 355 356 while True: 357 # Poll only for certain operations and when asked for by an override 358 if event_override or op in (SOCKOP_SEND, SOCKOP_RECV, SOCKOP_HANDSHAKE): 359 if event_override: 360 wait_for_event = event_override 361 else: 362 wait_for_event = event_poll 363 364 event = utils.WaitForFdCondition(sock, wait_for_event, timeout) 365 if event is None: 366 raise HttpSocketTimeout() 367 368 if event & (select.POLLNVAL | select.POLLHUP | select.POLLERR): 369 # Let the socket functions handle these 370 break 371 372 if not event & wait_for_event: 373 continue 374 375 # Reset override 376 event_override = 0 377 378 try: 379 try: 380 if op == SOCKOP_SEND: 381 return sock.send(arg1) 382 383 elif op == SOCKOP_RECV: 384 return sock.recv(arg1) 385 386 elif op == SOCKOP_SHUTDOWN: 387 if isinstance(sock, OpenSSL.SSL.ConnectionType): 388 # PyOpenSSL's shutdown() doesn't take arguments 389 return sock.shutdown() 390 else: 391 return sock.shutdown(arg1) 392 393 elif op == SOCKOP_HANDSHAKE: 394 return sock.do_handshake() 395 396 except OpenSSL.SSL.WantWriteError: 397 # OpenSSL wants to write, poll for POLLOUT 398 event_override = select.POLLOUT 399 continue 400 401 except OpenSSL.SSL.WantReadError: 402 # OpenSSL wants to read, poll for POLLIN 403 event_override = select.POLLIN | select.POLLPRI 404 continue 405 406 except OpenSSL.SSL.WantX509LookupError: 407 continue 408 409 except OpenSSL.SSL.ZeroReturnError, err: 410 # SSL Connection has been closed. In SSL 3.0 and TLS 1.0, this only 411 # occurs if a closure alert has occurred in the protocol, i.e. the 412 # connection has been closed cleanly. Note that this does not 413 # necessarily mean that the transport layer (e.g. a socket) has been 414 # closed. 415 if op == SOCKOP_SEND: 416 # Can happen during a renegotiation 417 raise HttpConnectionClosed(err.args) 418 elif op == SOCKOP_RECV: 419 return "" 420 421 # SSL_shutdown shouldn't return SSL_ERROR_ZERO_RETURN 422 raise socket.error(err.args) 423 424 except OpenSSL.SSL.SysCallError, err: 425 if op == SOCKOP_SEND: 426 # arg1 is the data when writing 427 if err.args and err.args[0] == -1 and arg1 == "": 428 # errors when writing empty strings are expected 429 # and can be ignored 430 return 0 431 432 if err.args == (-1, _SSL_UNEXPECTED_EOF): 433 if op == SOCKOP_RECV: 434 return "" 435 elif op == SOCKOP_HANDSHAKE: 436 # Can happen if peer disconnects directly after the connection is 437 # opened. 438 raise HttpSessionHandshakeUnexpectedEOF(err.args) 439 440 raise socket.error(err.args) 441 442 except OpenSSL.SSL.Error, err: 443 raise socket.error(err.args) 444 445 except socket.error, err: 446 if err.args and err.args[0] == errno.EAGAIN: 447 # Ignore EAGAIN 448 continue 449 450 raise
451
452 453 -def ShutdownConnection(sock, close_timeout, write_timeout, msgreader, force):
454 """Closes the connection. 455 456 @type sock: socket 457 @param sock: Socket to be shut down 458 @type close_timeout: float 459 @param close_timeout: How long to wait for the peer to close 460 the connection 461 @type write_timeout: float 462 @param write_timeout: Write timeout for shutdown 463 @type msgreader: http.HttpMessageReader 464 @param msgreader: Request message reader, used to determine whether 465 peer should close connection 466 @type force: bool 467 @param force: Whether to forcibly close the connection without 468 waiting for peer 469 470 """ 471 #print msgreader.peer_will_close, force 472 if msgreader and msgreader.peer_will_close and not force: 473 # Wait for peer to close 474 try: 475 # Check whether it's actually closed 476 if not SocketOperation(sock, SOCKOP_RECV, 1, close_timeout): 477 return 478 except (socket.error, HttpError, HttpSocketTimeout): 479 # Ignore errors at this stage 480 pass 481 482 # Close the connection from our side 483 try: 484 # We don't care about the return value, see NOTES in SSL_shutdown(3). 485 SocketOperation(sock, SOCKOP_SHUTDOWN, socket.SHUT_RDWR, 486 write_timeout) 487 except HttpSocketTimeout: 488 raise HttpError("Timeout while shutting down connection") 489 except socket.error, err: 490 # Ignore ENOTCONN 491 if not (err.args and err.args[0] == errno.ENOTCONN): 492 raise HttpError("Error while shutting down connection: %s" % err)
493
494 495 -def Handshake(sock, write_timeout):
496 """Shakes peer's hands. 497 498 @type sock: socket 499 @param sock: Socket to be shut down 500 @type write_timeout: float 501 @param write_timeout: Write timeout for handshake 502 503 """ 504 try: 505 return SocketOperation(sock, SOCKOP_HANDSHAKE, None, write_timeout) 506 except HttpSocketTimeout: 507 raise HttpError("Timeout during SSL handshake") 508 except socket.error, err: 509 raise HttpError("Error in SSL handshake: %s" % err)
510
511 512 -def InitSsl():
513 """Initializes the SSL infrastructure. 514 515 This function is idempotent. 516 517 """ 518 if not OpenSSL.rand.status(): 519 raise EnvironmentError("OpenSSL could not collect enough entropy" 520 " for the PRNG")
521
522 # TODO: Maybe add some additional seeding for OpenSSL's PRNG 523 524 525 -class HttpSslParams(object):
526 """Data class for SSL key and certificate. 527 528 """
529 - def __init__(self, ssl_key_path, ssl_cert_path):
530 """Initializes this class. 531 532 @type ssl_key_path: string 533 @param ssl_key_path: Path to file containing SSL key in PEM format 534 @type ssl_cert_path: string 535 @param ssl_cert_path: Path to file containing SSL certificate 536 in PEM format 537 538 """ 539 self.ssl_key_pem = utils.ReadFile(ssl_key_path) 540 self.ssl_cert_pem = utils.ReadFile(ssl_cert_path)
541
542 - def GetKey(self):
543 return OpenSSL.crypto.load_privatekey(OpenSSL.crypto.FILETYPE_PEM, 544 self.ssl_key_pem)
545
546 - def GetCertificate(self):
547 return OpenSSL.crypto.load_certificate(OpenSSL.crypto.FILETYPE_PEM, 548 self.ssl_cert_pem)
549
550 551 -class HttpBase(object):
552 """Base class for HTTP server and client. 553 554 """
555 - def __init__(self):
556 self.using_ssl = None 557 self._ssl_params = None 558 self._ssl_key = None 559 self._ssl_cert = None
560
561 - def _CreateSocket(self, ssl_params, ssl_verify_peer):
562 """Creates a TCP socket and initializes SSL if needed. 563 564 @type ssl_params: HttpSslParams 565 @param ssl_params: SSL key and certificate 566 @type ssl_verify_peer: bool 567 @param ssl_verify_peer: Whether to require client certificate 568 and compare it with our certificate 569 570 """ 571 self._ssl_params = ssl_params 572 573 sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 574 575 # Should we enable SSL? 576 self.using_ssl = ssl_params is not None 577 578 if not self.using_ssl: 579 return sock 580 581 self._ssl_key = ssl_params.GetKey() 582 self._ssl_cert = ssl_params.GetCertificate() 583 584 ctx = OpenSSL.SSL.Context(OpenSSL.SSL.SSLv23_METHOD) 585 ctx.set_options(OpenSSL.SSL.OP_NO_SSLv2) 586 587 ctx.use_privatekey(self._ssl_key) 588 ctx.use_certificate(self._ssl_cert) 589 ctx.check_privatekey() 590 591 if ssl_verify_peer: 592 ctx.set_verify(OpenSSL.SSL.VERIFY_PEER | 593 OpenSSL.SSL.VERIFY_FAIL_IF_NO_PEER_CERT, 594 self._SSLVerifyCallback) 595 596 return OpenSSL.SSL.Connection(ctx, sock)
597
598 - def _SSLVerifyCallback(self, conn, cert, errnum, errdepth, ok):
599 """Verify the certificate provided by the peer 600 601 We only compare fingerprints. The client must use the same certificate as 602 we do on our side. 603 604 """ 605 # some parameters are unused, but this is the API 606 # pylint: disable-msg=W0613 607 assert self._ssl_params, "SSL not initialized" 608 609 return (self._ssl_cert.digest("sha1") == cert.digest("sha1") and 610 self._ssl_cert.digest("md5") == cert.digest("md5"))
611
612 613 -class HttpMessage(object):
614 """Data structure for HTTP message. 615 616 """
617 - def __init__(self):
618 self.start_line = None 619 self.headers = None 620 self.body = None 621 self.decoded_body = None
622
623 624 -class HttpClientToServerStartLine(object):
625 """Data structure for HTTP request start line. 626 627 """
628 - def __init__(self, method, path, version):
629 self.method = method 630 self.path = path 631 self.version = version
632
633 - def __str__(self):
634 return "%s %s %s" % (self.method, self.path, self.version)
635
636 637 -class HttpServerToClientStartLine(object):
638 """Data structure for HTTP response start line. 639 640 """
641 - def __init__(self, version, code, reason):
642 self.version = version 643 self.code = code 644 self.reason = reason
645
646 - def __str__(self):
647 return "%s %s %s" % (self.version, self.code, self.reason)
648
649 650 -class HttpMessageWriter(object):
651 """Writes an HTTP message to a socket. 652 653 """
654 - def __init__(self, sock, msg, write_timeout):
655 """Initializes this class and writes an HTTP message to a socket. 656 657 @type sock: socket 658 @param sock: Socket to be written to 659 @type msg: http.HttpMessage 660 @param msg: HTTP message to be written 661 @type write_timeout: float 662 @param write_timeout: Write timeout for socket 663 664 """ 665 self._msg = msg 666 667 self._PrepareMessage() 668 669 buf = self._FormatMessage() 670 671 pos = 0 672 end = len(buf) 673 while pos < end: 674 # Send only SOCK_BUF_SIZE bytes at a time 675 data = buf[pos:(pos + SOCK_BUF_SIZE)] 676 677 sent = SocketOperation(sock, SOCKOP_SEND, data, write_timeout) 678 679 # Remove sent bytes 680 pos += sent 681 682 assert pos == end, "Message wasn't sent completely"
683
684 - def _PrepareMessage(self):
685 """Prepares the HTTP message by setting mandatory headers. 686 687 """ 688 # RFC2616, section 4.3: "The presence of a message-body in a request is 689 # signaled by the inclusion of a Content-Length or Transfer-Encoding header 690 # field in the request's message-headers." 691 if self._msg.body: 692 self._msg.headers[HTTP_CONTENT_LENGTH] = len(self._msg.body)
693
694 - def _FormatMessage(self):
695 """Serializes the HTTP message into a string. 696 697 """ 698 buf = StringIO() 699 700 # Add start line 701 buf.write(str(self._msg.start_line)) 702 buf.write("\r\n") 703 704 # Add headers 705 if self._msg.start_line.version != HTTP_0_9: 706 for name, value in self._msg.headers.iteritems(): 707 buf.write("%s: %s\r\n" % (name, value)) 708 709 buf.write("\r\n") 710 711 # Add message body if needed 712 if self.HasMessageBody(): 713 buf.write(self._msg.body) 714 715 elif self._msg.body: 716 logging.warning("Ignoring message body") 717 718 return buf.getvalue()
719
720 - def HasMessageBody(self):
721 """Checks whether the HTTP message contains a body. 722 723 Can be overridden by subclasses. 724 725 """ 726 return bool(self._msg.body)
727
728 729 -class HttpMessageReader(object):
730 """Reads HTTP message from socket. 731 732 """ 733 # Length limits 734 START_LINE_LENGTH_MAX = None 735 HEADER_LENGTH_MAX = None 736 737 # Parser state machine 738 PS_START_LINE = "start-line" 739 PS_HEADERS = "headers" 740 PS_BODY = "entity-body" 741 PS_COMPLETE = "complete" 742
743 - def __init__(self, sock, msg, read_timeout):
744 """Reads an HTTP message from a socket. 745 746 @type sock: socket 747 @param sock: Socket to be read from 748 @type msg: http.HttpMessage 749 @param msg: Object for the read message 750 @type read_timeout: float 751 @param read_timeout: Read timeout for socket 752 753 """ 754 self.sock = sock 755 self.msg = msg 756 757 self.start_line_buffer = None 758 self.header_buffer = StringIO() 759 self.body_buffer = StringIO() 760 self.parser_status = self.PS_START_LINE 761 self.content_length = None 762 self.peer_will_close = None 763 764 buf = "" 765 eof = False 766 while self.parser_status != self.PS_COMPLETE: 767 # TODO: Don't read more than necessary (Content-Length), otherwise 768 # data might be lost and/or an error could occur 769 data = SocketOperation(sock, SOCKOP_RECV, SOCK_BUF_SIZE, read_timeout) 770 771 if data: 772 buf += data 773 else: 774 eof = True 775 776 # Do some parsing and error checking while more data arrives 777 buf = self._ContinueParsing(buf, eof) 778 779 # Must be done only after the buffer has been evaluated 780 # TODO: Connection-length < len(data read) and connection closed 781 if (eof and 782 self.parser_status in (self.PS_START_LINE, 783 self.PS_HEADERS)): 784 raise HttpError("Connection closed prematurely") 785 786 # Parse rest 787 buf = self._ContinueParsing(buf, True) 788 789 assert self.parser_status == self.PS_COMPLETE 790 assert not buf, "Parser didn't read full response" 791 792 msg.body = self.body_buffer.getvalue() 793 794 # TODO: Content-type, error handling 795 if msg.body: 796 msg.decoded_body = HttpJsonConverter().Decode(msg.body) 797 else: 798 msg.decoded_body = None 799 800 if msg.decoded_body: 801 logging.debug("Message body: %s", msg.decoded_body)
802
803 - def _ContinueParsing(self, buf, eof):
804 """Main function for HTTP message state machine. 805 806 @type buf: string 807 @param buf: Receive buffer 808 @type eof: bool 809 @param eof: Whether we've reached EOF on the socket 810 @rtype: string 811 @return: Updated receive buffer 812 813 """ 814 # TODO: Use offset instead of slicing when possible 815 if self.parser_status == self.PS_START_LINE: 816 # Expect start line 817 while True: 818 idx = buf.find("\r\n") 819 820 # RFC2616, section 4.1: "In the interest of robustness, servers SHOULD 821 # ignore any empty line(s) received where a Request-Line is expected. 822 # In other words, if the server is reading the protocol stream at the 823 # beginning of a message and receives a CRLF first, it should ignore 824 # the CRLF." 825 if idx == 0: 826 # TODO: Limit number of CRLFs/empty lines for safety? 827 buf = buf[2:] 828 continue 829 830 if idx > 0: 831 self.start_line_buffer = buf[:idx] 832 833 self._CheckStartLineLength(len(self.start_line_buffer)) 834 835 # Remove status line, including CRLF 836 buf = buf[idx + 2:] 837 838 self.msg.start_line = self.ParseStartLine(self.start_line_buffer) 839 840 self.parser_status = self.PS_HEADERS 841 else: 842 # Check whether incoming data is getting too large, otherwise we just 843 # fill our read buffer. 844 self._CheckStartLineLength(len(buf)) 845 846 break 847 848 # TODO: Handle messages without headers 849 if self.parser_status == self.PS_HEADERS: 850 # Wait for header end 851 idx = buf.find("\r\n\r\n") 852 if idx >= 0: 853 self.header_buffer.write(buf[:idx + 2]) 854 855 self._CheckHeaderLength(self.header_buffer.tell()) 856 857 # Remove headers, including CRLF 858 buf = buf[idx + 4:] 859 860 self._ParseHeaders() 861 862 self.parser_status = self.PS_BODY 863 else: 864 # Check whether incoming data is getting too large, otherwise we just 865 # fill our read buffer. 866 self._CheckHeaderLength(len(buf)) 867 868 if self.parser_status == self.PS_BODY: 869 # TODO: Implement max size for body_buffer 870 self.body_buffer.write(buf) 871 buf = "" 872 873 # Check whether we've read everything 874 # 875 # RFC2616, section 4.4: "When a message-body is included with a message, 876 # the transfer-length of that body is determined by one of the following 877 # [...] 5. By the server closing the connection. (Closing the connection 878 # cannot be used to indicate the end of a request body, since that would 879 # leave no possibility for the server to send back a response.)" 880 # 881 # TODO: Error when buffer length > Content-Length header 882 if (eof or 883 self.content_length is None or 884 (self.content_length is not None and 885 self.body_buffer.tell() >= self.content_length)): 886 self.parser_status = self.PS_COMPLETE 887 888 return buf
889
890 - def _CheckStartLineLength(self, length):
891 """Limits the start line buffer size. 892 893 @type length: int 894 @param length: Buffer size 895 896 """ 897 if (self.START_LINE_LENGTH_MAX is not None and 898 length > self.START_LINE_LENGTH_MAX): 899 raise HttpError("Start line longer than %d chars" % 900 self.START_LINE_LENGTH_MAX)
901
902 - def _CheckHeaderLength(self, length):
903 """Limits the header buffer size. 904 905 @type length: int 906 @param length: Buffer size 907 908 """ 909 if (self.HEADER_LENGTH_MAX is not None and 910 length > self.HEADER_LENGTH_MAX): 911 raise HttpError("Headers longer than %d chars" % self.HEADER_LENGTH_MAX)
912
913 - def ParseStartLine(self, start_line):
914 """Parses the start line of a message. 915 916 Must be overridden by subclass. 917 918 @type start_line: string 919 @param start_line: Start line string 920 921 """ 922 raise NotImplementedError()
923
924 - def _WillPeerCloseConnection(self):
925 """Evaluate whether peer will close the connection. 926 927 @rtype: bool 928 @return: Whether peer will close the connection 929 930 """ 931 # RFC2616, section 14.10: "HTTP/1.1 defines the "close" connection option 932 # for the sender to signal that the connection will be closed after 933 # completion of the response. For example, 934 # 935 # Connection: close 936 # 937 # in either the request or the response header fields indicates that the 938 # connection SHOULD NOT be considered `persistent' (section 8.1) after the 939 # current request/response is complete." 940 941 hdr_connection = self.msg.headers.get(HTTP_CONNECTION, None) 942 if hdr_connection: 943 hdr_connection = hdr_connection.lower() 944 945 # An HTTP/1.1 server is assumed to stay open unless explicitly closed. 946 if self.msg.start_line.version == HTTP_1_1: 947 return (hdr_connection and "close" in hdr_connection) 948 949 # Some HTTP/1.0 implementations have support for persistent connections, 950 # using rules different than HTTP/1.1. 951 952 # For older HTTP, Keep-Alive indicates persistent connection. 953 if self.msg.headers.get(HTTP_KEEP_ALIVE): 954 return False 955 956 # At least Akamai returns a "Connection: Keep-Alive" header, which was 957 # supposed to be sent by the client. 958 if hdr_connection and "keep-alive" in hdr_connection: 959 return False 960 961 return True
962
963 - def _ParseHeaders(self):
964 """Parses the headers. 965 966 This function also adjusts internal variables based on header values. 967 968 RFC2616, section 4.3: The presence of a message-body in a request is 969 signaled by the inclusion of a Content-Length or Transfer-Encoding header 970 field in the request's message-headers. 971 972 """ 973 # Parse headers 974 self.header_buffer.seek(0, 0) 975 self.msg.headers = mimetools.Message(self.header_buffer, 0) 976 977 self.peer_will_close = self._WillPeerCloseConnection() 978 979 # Do we have a Content-Length header? 980 hdr_content_length = self.msg.headers.get(HTTP_CONTENT_LENGTH, None) 981 if hdr_content_length: 982 try: 983 self.content_length = int(hdr_content_length) 984 except (TypeError, ValueError): 985 self.content_length = None 986 if self.content_length is not None and self.content_length < 0: 987 self.content_length = None 988 989 # if the connection remains open and a content-length was not provided, 990 # then assume that the connection WILL close. 991 if self.content_length is None: 992 self.peer_will_close = True
993