1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
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
72 (SOCKOP_SEND,
73 SOCKOP_RECV,
74 SOCKOP_SHUTDOWN,
75 SOCKOP_HANDSHAKE) = range(4)
76
77
78 SOCK_BUF_SIZE = 32768
82 """Internal exception for HTTP errors.
83
84 This should only be used for internal error reporting.
85
86 """
87
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
99 """Internal exception for errors during SSL handshake.
100
101 This should only be used for internal error reporting.
102
103 """
104
107 """Internal exception for socket timeouts.
108
109 This should only be used for internal error reporting.
110
111 """
112
122
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
303 CONTENT_TYPE = "application/json"
304
305 @staticmethod
308
309 @staticmethod
312
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
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
342
343 assert timeout
344
345 else:
346 raise AssertionError("Invalid socket operation")
347
348
349 if (op == SOCKOP_HANDSHAKE and
350 not isinstance(sock, OpenSSL.SSL.ConnectionType)):
351 return
352
353
354 event_override = 0
355
356 while True:
357
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
370 break
371
372 if not event & wait_for_event:
373 continue
374
375
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
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
398 event_override = select.POLLOUT
399 continue
400
401 except OpenSSL.SSL.WantReadError:
402
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
411
412
413
414
415 if op == SOCKOP_SEND:
416
417 raise HttpConnectionClosed(err.args)
418 elif op == SOCKOP_RECV:
419 return ""
420
421
422 raise socket.error(err.args)
423
424 except OpenSSL.SSL.SysCallError, err:
425 if op == SOCKOP_SEND:
426
427 if err.args and err.args[0] == -1 and arg1 == "":
428
429
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
437
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
448 continue
449
450 raise
451
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
472 if msgreader and msgreader.peer_will_close and not force:
473
474 try:
475
476 if not SocketOperation(sock, SOCKOP_RECV, 1, close_timeout):
477 return
478 except (socket.error, HttpError, HttpSocketTimeout):
479
480 pass
481
482
483 try:
484
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
491 if not (err.args and err.args[0] == errno.ENOTCONN):
492 raise HttpError("Error while shutting down connection: %s" % err)
493
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
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
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
543 return OpenSSL.crypto.load_privatekey(OpenSSL.crypto.FILETYPE_PEM,
544 self.ssl_key_pem)
545
547 return OpenSSL.crypto.load_certificate(OpenSSL.crypto.FILETYPE_PEM,
548 self.ssl_cert_pem)
549
552 """Base class for HTTP server and client.
553
554 """
556 self.using_ssl = None
557 self._ssl_params = None
558 self._ssl_key = None
559 self._ssl_cert = None
560
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
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
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
606
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
614 """Data structure for HTTP message.
615
616 """
618 self.start_line = None
619 self.headers = None
620 self.body = None
621 self.decoded_body = None
622
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
634 return "%s %s %s" % (self.method, self.path, self.version)
635
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
647 return "%s %s %s" % (self.version, self.code, self.reason)
648
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
675 data = buf[pos:(pos + SOCK_BUF_SIZE)]
676
677 sent = SocketOperation(sock, SOCKOP_SEND, data, write_timeout)
678
679
680 pos += sent
681
682 assert pos == end, "Message wasn't sent completely"
683
685 """Prepares the HTTP message by setting mandatory headers.
686
687 """
688
689
690
691 if self._msg.body:
692 self._msg.headers[HTTP_CONTENT_LENGTH] = len(self._msg.body)
693
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
730 """Reads HTTP message from socket.
731
732 """
733
734 START_LINE_LENGTH_MAX = None
735 HEADER_LENGTH_MAX = None
736
737
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
768
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
777 buf = self._ContinueParsing(buf, eof)
778
779
780
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
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
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
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
815 if self.parser_status == self.PS_START_LINE:
816
817 while True:
818 idx = buf.find("\r\n")
819
820
821
822
823
824
825 if idx == 0:
826
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
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
843
844 self._CheckStartLineLength(len(buf))
845
846 break
847
848
849 if self.parser_status == self.PS_HEADERS:
850
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
858 buf = buf[idx + 4:]
859
860 self._ParseHeaders()
861
862 self.parser_status = self.PS_BODY
863 else:
864
865
866 self._CheckHeaderLength(len(buf))
867
868 if self.parser_status == self.PS_BODY:
869
870 self.body_buffer.write(buf)
871 buf = ""
872
873
874
875
876
877
878
879
880
881
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
901
912
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
925 """Evaluate whether peer will close the connection.
926
927 @rtype: bool
928 @return: Whether peer will close the connection
929
930 """
931
932
933
934
935
936
937
938
939
940
941 hdr_connection = self.msg.headers.get(HTTP_CONNECTION, None)
942 if hdr_connection:
943 hdr_connection = hdr_connection.lower()
944
945
946 if self.msg.start_line.version == HTTP_1_1:
947 return (hdr_connection and "close" in hdr_connection)
948
949
950
951
952
953 if self.msg.headers.get(HTTP_KEEP_ALIVE):
954 return False
955
956
957
958 if hdr_connection and "keep-alive" in hdr_connection:
959 return False
960
961 return True
962
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
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
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
990
991 if self.content_length is None:
992 self.peer_will_close = True
993