4 # Copyright (C) 2007, 2008 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 serializer
36 from ganeti import utils
39 HTTP_GANETI_VERSION = "Ganeti %s" % constants.RELEASE_VERSION
43 HTTP_NOT_MODIFIED = 304
53 HTTP_DELETE = "DELETE"
57 HTTP_SERVER = "Server"
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"
65 _SSL_UNEXPECTED_EOF = "Unexpected EOF"
71 SOCKOP_HANDSHAKE) = range(4)
73 # send/receive quantum
77 class HttpError(Exception):
78 """Internal exception for HTTP errors.
80 This should only be used for internal error reporting.
85 class HttpConnectionClosed(Exception):
86 """Internal exception for a closed connection.
88 This should only be used for internal error reporting. Only use
89 it if there's no other way to report this condition.
94 class HttpSessionHandshakeUnexpectedEOF(HttpError):
95 """Internal exception for errors during SSL handshake.
97 This should only be used for internal error reporting.
102 class HttpSocketTimeout(Exception):
103 """Internal exception for socket timeouts.
105 This should only be used for internal error reporting.
110 class HttpException(Exception):
114 def __init__(self, message=None):
115 Exception.__init__(self)
116 if message is not None:
117 self.message = message
120 class HttpBadRequest(HttpException):
124 class HttpForbidden(HttpException):
128 class HttpNotFound(HttpException):
132 class HttpGone(HttpException):
136 class HttpLengthRequired(HttpException):
140 class HttpInternalError(HttpException):
144 class HttpNotImplemented(HttpException):
148 class HttpServiceUnavailable(HttpException):
152 class HttpVersionNotSupported(HttpException):
156 class HttpJsonConverter:
157 CONTENT_TYPE = "application/json"
159 def Encode(self, data):
160 return serializer.DumpJson(data)
162 def Decode(self, data):
163 return serializer.LoadJson(data)
166 def WaitForSocketCondition(poller, sock, event, timeout):
167 """Waits for a condition to occur on the socket.
169 @type poller: select.Poller
170 @param poller: Poller object as created by select.poll()
172 @param sock: Wait for events on this socket
174 @param event: ORed condition (see select module)
175 @type timeout: float or None
176 @param timeout: Timeout in seconds
178 @return: None for timeout, otherwise occured conditions
181 check = (event | select.POLLPRI |
182 select.POLLNVAL | select.POLLHUP | select.POLLERR)
184 if timeout is not None:
185 # Poller object expects milliseconds
188 poller.register(sock, event)
191 # TODO: If the main thread receives a signal and we have no timeout, we
192 # could wait forever. This should check a global "quit" flag or
193 # something every so often.
194 io_events = poller.poll(timeout)
198 for (evfd, evcond) in io_events:
202 poller.unregister(sock)
205 def SocketOperation(poller, sock, op, arg1, timeout):
206 """Wrapper around socket functions.
208 This function abstracts error handling for socket operations, especially
209 for the complicated interaction with OpenSSL.
211 @type poller: select.Poller
212 @param poller: Poller object as created by select.poll()
214 @param sock: Socket for the operation
216 @param op: Operation to execute (SOCKOP_* constants)
218 @param arg1: Parameter for function (if needed)
219 @type timeout: None or float
220 @param timeout: Timeout in seconds or None
221 @return: Return value of socket function
224 # TODO: event_poll/event_check/override
225 if op in (SOCKOP_SEND, SOCKOP_HANDSHAKE):
226 event_poll = select.POLLOUT
227 event_check = select.POLLOUT
229 elif op == SOCKOP_RECV:
230 event_poll = select.POLLIN
231 event_check = select.POLLIN | select.POLLPRI
233 elif op == SOCKOP_SHUTDOWN:
237 # The timeout is only used when OpenSSL requests polling for a condition.
238 # It is not advisable to have no timeout for shutdown.
242 raise AssertionError("Invalid socket operation")
244 # Handshake is only supported by SSL sockets
245 if (op == SOCKOP_HANDSHAKE and
246 not isinstance(sock, OpenSSL.SSL.ConnectionType)):
249 # No override by default
253 # Poll only for certain operations and when asked for by an override
254 if event_override or op in (SOCKOP_SEND, SOCKOP_RECV, SOCKOP_HANDSHAKE):
256 wait_for_event = event_override
258 wait_for_event = event_poll
260 event = WaitForSocketCondition(poller, sock, wait_for_event, timeout)
262 raise HttpSocketTimeout()
264 if (op == SOCKOP_RECV and
265 event & (select.POLLNVAL | select.POLLHUP | select.POLLERR)):
268 if not event & wait_for_event:
276 if op == SOCKOP_SEND:
277 return sock.send(arg1)
279 elif op == SOCKOP_RECV:
280 return sock.recv(arg1)
282 elif op == SOCKOP_SHUTDOWN:
283 if isinstance(sock, OpenSSL.SSL.ConnectionType):
284 # PyOpenSSL's shutdown() doesn't take arguments
285 return sock.shutdown()
287 return sock.shutdown(arg1)
289 elif op == SOCKOP_HANDSHAKE:
290 return sock.do_handshake()
292 except OpenSSL.SSL.WantWriteError:
293 # OpenSSL wants to write, poll for POLLOUT
294 event_override = select.POLLOUT
297 except OpenSSL.SSL.WantReadError:
298 # OpenSSL wants to read, poll for POLLIN
299 event_override = select.POLLIN | select.POLLPRI
302 except OpenSSL.SSL.WantX509LookupError:
305 except OpenSSL.SSL.ZeroReturnError, err:
306 # SSL Connection has been closed. In SSL 3.0 and TLS 1.0, this only
307 # occurs if a closure alert has occurred in the protocol, i.e. the
308 # connection has been closed cleanly. Note that this does not
309 # necessarily mean that the transport layer (e.g. a socket) has been
311 if op == SOCKOP_SEND:
312 # Can happen during a renegotiation
313 raise HttpConnectionClosed(err.args)
314 elif op == SOCKOP_RECV:
317 # SSL_shutdown shouldn't return SSL_ERROR_ZERO_RETURN
318 raise socket.error(err.args)
320 except OpenSSL.SSL.SysCallError, err:
321 if op == SOCKOP_SEND:
322 # arg1 is the data when writing
323 if err.args and err.args[0] == -1 and arg1 == "":
324 # errors when writing empty strings are expected
328 if err.args == (-1, _SSL_UNEXPECTED_EOF):
329 if op == SOCKOP_RECV:
331 elif op == SOCKOP_HANDSHAKE:
332 # Can happen if peer disconnects directly after the connection is
334 raise HttpSessionHandshakeUnexpectedEOF(err.args)
336 raise socket.error(err.args)
338 except OpenSSL.SSL.Error, err:
339 raise socket.error(err.args)
341 except socket.error, err:
342 if err.args and err.args[0] == errno.EAGAIN:
349 def ShutdownConnection(poller, sock, close_timeout, write_timeout, msgreader,
351 """Closes the connection.
353 @type poller: select.Poller
354 @param poller: Poller object as created by select.poll()
356 @param sock: Socket to be shut down
357 @type close_timeout: float
358 @param close_timeout: How long to wait for the peer to close the connection
359 @type write_timeout: float
360 @param write_timeout: Write timeout for shutdown
361 @type msgreader: http.HttpMessageReader
362 @param msgreader: Request message reader, used to determine whether peer
363 should close connection
365 @param force: Whether to forcibly close the connection without waiting
369 poller = select.poll()
371 #print msgreader.peer_will_close, force
372 if msgreader and msgreader.peer_will_close and not force:
373 # Wait for peer to close
375 # Check whether it's actually closed
376 if not SocketOperation(poller, sock, SOCKOP_RECV, 1, close_timeout):
378 except (socket.error, HttpError, HttpSocketTimeout):
379 # Ignore errors at this stage
382 # Close the connection from our side
384 # We don't care about the return value, see NOTES in SSL_shutdown(3).
385 SocketOperation(poller, sock, SOCKOP_SHUTDOWN, socket.SHUT_RDWR,
387 except HttpSocketTimeout:
388 raise HttpError("Timeout while shutting down connection")
389 except socket.error, err:
390 raise HttpError("Error while shutting down connection: %s" % err)
393 def Handshake(poller, sock, write_timeout):
394 """Shakes peer's hands.
396 @type poller: select.Poller
397 @param poller: Poller object as created by select.poll()
399 @param sock: Socket to be shut down
400 @type write_timeout: float
401 @param write_timeout: Write timeout for handshake
405 return SocketOperation(poller, sock, SOCKOP_HANDSHAKE, None, write_timeout)
406 except HttpSocketTimeout:
407 raise HttpError("Timeout during SSL handshake")
408 except socket.error, err:
409 raise HttpError("Error in SSL handshake: %s" % err)
412 class HttpSslParams(object):
413 """Data class for SSL key and certificate.
416 def __init__(self, ssl_key_path, ssl_cert_path):
417 """Initializes this class.
419 @type ssl_key_path: string
420 @param ssl_key_path: Path to file containing SSL key in PEM format
421 @type ssl_cert_path: string
422 @param ssl_cert_path: Path to file containing SSL certificate in PEM format
425 self.ssl_key_pem = utils.ReadFile(ssl_key_path)
426 self.ssl_cert_pem = utils.ReadFile(ssl_cert_path)
429 return OpenSSL.crypto.load_privatekey(OpenSSL.crypto.FILETYPE_PEM,
432 def GetCertificate(self):
433 return OpenSSL.crypto.load_certificate(OpenSSL.crypto.FILETYPE_PEM,
437 class HttpBase(object):
438 """Base class for HTTP server and client.
442 self.using_ssl = None
443 self._ssl_params = None
445 self._ssl_cert = None
447 def _CreateSocket(self, ssl_params, ssl_verify_peer):
448 """Creates a TCP socket and initializes SSL if needed.
450 @type ssl_params: HttpSslParams
451 @param ssl_params: SSL key and certificate
452 @type ssl_verify_peer: bool
453 @param ssl_verify_peer: Whether to require client certificate and compare
454 it with our certificate
457 self._ssl_params = ssl_params
459 sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
461 # Should we enable SSL?
462 self.using_ssl = ssl_params is not None
464 if not self.using_ssl:
467 self._ssl_key = ssl_params.GetKey()
468 self._ssl_cert = ssl_params.GetCertificate()
470 ctx = OpenSSL.SSL.Context(OpenSSL.SSL.SSLv23_METHOD)
471 ctx.set_options(OpenSSL.SSL.OP_NO_SSLv2)
473 ctx.use_privatekey(self._ssl_key)
474 ctx.use_certificate(self._ssl_cert)
475 ctx.check_privatekey()
478 ctx.set_verify(OpenSSL.SSL.VERIFY_PEER |
479 OpenSSL.SSL.VERIFY_FAIL_IF_NO_PEER_CERT,
480 self._SSLVerifyCallback)
482 return OpenSSL.SSL.Connection(ctx, sock)
484 def _SSLVerifyCallback(self, conn, cert, errnum, errdepth, ok):
485 """Verify the certificate provided by the peer
487 We only compare fingerprints. The client must use the same certificate as
491 assert self._ssl_params, "SSL not initialized"
493 return (self._ssl_cert.digest("sha1") == cert.digest("sha1") and
494 self._ssl_cert.digest("md5") == cert.digest("md5"))
497 class HttpMessage(object):
498 """Data structure for HTTP message.
502 self.start_line = None
505 self.decoded_body = None
508 class HttpClientToServerStartLine(object):
509 """Data structure for HTTP request start line.
512 def __init__(self, method, path, version):
515 self.version = version
518 return "%s %s %s" % (self.method, self.path, self.version)
521 class HttpServerToClientStartLine(object):
522 """Data structure for HTTP response start line.
525 def __init__(self, version, code, reason):
526 self.version = version
531 return "%s %s %s" % (self.version, self.code, self.reason)
534 class HttpMessageWriter(object):
535 """Writes an HTTP message to a socket.
538 def __init__(self, sock, msg, write_timeout):
539 """Initializes this class and writes an HTTP message to a socket.
542 @param sock: Socket to be written to
543 @type msg: http.HttpMessage
544 @param msg: HTTP message to be written
545 @type write_timeout: float
546 @param write_timeout: Write timeout for socket
551 self._PrepareMessage()
553 buf = self._FormatMessage()
555 poller = select.poll()
560 # Send only SOCK_BUF_SIZE bytes at a time
561 data = buf[pos:(pos + SOCK_BUF_SIZE)]
563 sent = SocketOperation(poller, sock, SOCKOP_SEND, data,
569 assert pos == end, "Message wasn't sent completely"
571 def _PrepareMessage(self):
572 """Prepares the HTTP message by setting mandatory headers.
575 # RFC2616, section 4.3: "The presence of a message-body in a request is
576 # signaled by the inclusion of a Content-Length or Transfer-Encoding header
577 # field in the request's message-headers."
579 self._msg.headers[HTTP_CONTENT_LENGTH] = len(self._msg.body)
581 def _FormatMessage(self):
582 """Serializes the HTTP message into a string.
588 buf.write(str(self._msg.start_line))
592 if self._msg.start_line.version != HTTP_0_9:
593 for name, value in self._msg.headers.iteritems():
594 buf.write("%s: %s\r\n" % (name, value))
598 # Add message body if needed
599 if self.HasMessageBody():
600 buf.write(self._msg.body)
603 logging.warning("Ignoring message body")
605 return buf.getvalue()
607 def HasMessageBody(self):
608 """Checks whether the HTTP message contains a body.
610 Can be overriden by subclasses.
613 return bool(self._msg.body)
616 class HttpMessageReader(object):
617 """Reads HTTP message from socket.
621 START_LINE_LENGTH_MAX = None
622 HEADER_LENGTH_MAX = None
624 # Parser state machine
625 PS_START_LINE = "start-line"
626 PS_HEADERS = "headers"
627 PS_BODY = "entity-body"
628 PS_COMPLETE = "complete"
630 def __init__(self, sock, msg, read_timeout):
631 """Reads an HTTP message from a socket.
634 @param sock: Socket to be read from
635 @type msg: http.HttpMessage
636 @param msg: Object for the read message
637 @type read_timeout: float
638 @param read_timeout: Read timeout for socket
644 self.poller = select.poll()
645 self.start_line_buffer = None
646 self.header_buffer = StringIO()
647 self.body_buffer = StringIO()
648 self.parser_status = self.PS_START_LINE
649 self.content_length = None
650 self.peer_will_close = None
654 while self.parser_status != self.PS_COMPLETE:
655 # TODO: Don't read more than necessary (Content-Length), otherwise
656 # data might be lost and/or an error could occur
657 data = SocketOperation(self.poller, sock, SOCKOP_RECV, SOCK_BUF_SIZE,
665 # Do some parsing and error checking while more data arrives
666 buf = self._ContinueParsing(buf, eof)
668 # Must be done only after the buffer has been evaluated
669 # TODO: Connection-length < len(data read) and connection closed
671 self.parser_status in (self.PS_START_LINE,
673 raise HttpError("Connection closed prematurely")
676 buf = self._ContinueParsing(buf, True)
678 assert self.parser_status == self.PS_COMPLETE
679 assert not buf, "Parser didn't read full response"
681 msg.body = self.body_buffer.getvalue()
683 # TODO: Content-type, error handling
685 msg.decoded_body = HttpJsonConverter().Decode(msg.body)
687 msg.decoded_body = None
690 logging.debug("Message body: %s", msg.decoded_body)
692 def _ContinueParsing(self, buf, eof):
693 """Main function for HTTP message state machine.
696 @param buf: Receive buffer
698 @param eof: Whether we've reached EOF on the socket
700 @return: Updated receive buffer
703 # TODO: Use offset instead of slicing when possible
704 if self.parser_status == self.PS_START_LINE:
707 idx = buf.find("\r\n")
709 # RFC2616, section 4.1: "In the interest of robustness, servers SHOULD
710 # ignore any empty line(s) received where a Request-Line is expected.
711 # In other words, if the server is reading the protocol stream at the
712 # beginning of a message and receives a CRLF first, it should ignore
715 # TODO: Limit number of CRLFs/empty lines for safety?
720 self.start_line_buffer = buf[:idx]
722 self._CheckStartLineLength(len(self.start_line_buffer))
724 # Remove status line, including CRLF
727 self.msg.start_line = self.ParseStartLine(self.start_line_buffer)
729 self.parser_status = self.PS_HEADERS
731 # Check whether incoming data is getting too large, otherwise we just
732 # fill our read buffer.
733 self._CheckStartLineLength(len(buf))
737 # TODO: Handle messages without headers
738 if self.parser_status == self.PS_HEADERS:
739 # Wait for header end
740 idx = buf.find("\r\n\r\n")
742 self.header_buffer.write(buf[:idx + 2])
744 self._CheckHeaderLength(self.header_buffer.tell())
746 # Remove headers, including CRLF
751 self.parser_status = self.PS_BODY
753 # Check whether incoming data is getting too large, otherwise we just
754 # fill our read buffer.
755 self._CheckHeaderLength(len(buf))
757 if self.parser_status == self.PS_BODY:
758 # TODO: Implement max size for body_buffer
759 self.body_buffer.write(buf)
762 # Check whether we've read everything
764 # RFC2616, section 4.4: "When a message-body is included with a message,
765 # the transfer-length of that body is determined by one of the following
766 # [...] 5. By the server closing the connection. (Closing the connection
767 # cannot be used to indicate the end of a request body, since that would
768 # leave no possibility for the server to send back a response.)"
770 # TODO: Error when buffer length > Content-Length header
772 self.content_length is None or
773 (self.content_length is not None and
774 self.body_buffer.tell() >= self.content_length)):
775 self.parser_status = self.PS_COMPLETE
779 def _CheckStartLineLength(self, length):
780 """Limits the start line buffer size.
783 @param length: Buffer size
786 if (self.START_LINE_LENGTH_MAX is not None and
787 length > self.START_LINE_LENGTH_MAX):
788 raise HttpError("Start line longer than %d chars" %
789 self.START_LINE_LENGTH_MAX)
791 def _CheckHeaderLength(self, length):
792 """Limits the header buffer size.
795 @param length: Buffer size
798 if (self.HEADER_LENGTH_MAX is not None and
799 length > self.HEADER_LENGTH_MAX):
800 raise HttpError("Headers longer than %d chars" % self.HEADER_LENGTH_MAX)
802 def ParseStartLine(self, start_line):
803 """Parses the start line of a message.
805 Must be overriden by subclass.
807 @type start_line: string
808 @param start_line: Start line string
811 raise NotImplementedError()
813 def _WillPeerCloseConnection(self):
814 """Evaluate whether peer will close the connection.
817 @return: Whether peer will close the connection
820 # RFC2616, section 14.10: "HTTP/1.1 defines the "close" connection option
821 # for the sender to signal that the connection will be closed after
822 # completion of the response. For example,
826 # in either the request or the response header fields indicates that the
827 # connection SHOULD NOT be considered `persistent' (section 8.1) after the
828 # current request/response is complete."
830 hdr_connection = self.msg.headers.get(HTTP_CONNECTION, None)
832 hdr_connection = hdr_connection.lower()
834 # An HTTP/1.1 server is assumed to stay open unless explicitly closed.
835 if self.msg.start_line.version == HTTP_1_1:
836 return (hdr_connection and "close" in hdr_connection)
838 # Some HTTP/1.0 implementations have support for persistent connections,
839 # using rules different than HTTP/1.1.
841 # For older HTTP, Keep-Alive indicates persistent connection.
842 if self.msg.headers.get(HTTP_KEEP_ALIVE):
845 # At least Akamai returns a "Connection: Keep-Alive" header, which was
846 # supposed to be sent by the client.
847 if hdr_connection and "keep-alive" in hdr_connection:
852 def _ParseHeaders(self):
853 """Parses the headers.
855 This function also adjusts internal variables based on header values.
857 RFC2616, section 4.3: "The presence of a message-body in a request is
858 signaled by the inclusion of a Content-Length or Transfer-Encoding header
859 field in the request's message-headers."
863 self.header_buffer.seek(0, 0)
864 self.msg.headers = mimetools.Message(self.header_buffer, 0)
866 self.peer_will_close = self._WillPeerCloseConnection()
868 # Do we have a Content-Length header?
869 hdr_content_length = self.msg.headers.get(HTTP_CONTENT_LENGTH, None)
870 if hdr_content_length:
872 self.content_length = int(hdr_content_length)
874 self.content_length = None
875 if self.content_length is not None and self.content_length < 0:
876 self.content_length = None
878 # if the connection remains open and a content-length was not provided,
879 # then assume that the connection WILL close.
880 if self.content_length is None:
881 self.peer_will_close = True