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 utils
36
37
38 HTTP_GANETI_VERSION = "Ganeti %s" % constants.RELEASE_VERSION
39
40 HTTP_OK = 200
41 HTTP_NO_CONTENT = 204
42 HTTP_NOT_MODIFIED = 304
43
44 HTTP_0_9 = "HTTP/0.9"
45 HTTP_1_0 = "HTTP/1.0"
46 HTTP_1_1 = "HTTP/1.1"
47
48 HTTP_GET = "GET"
49 HTTP_HEAD = "HEAD"
50 HTTP_POST = "POST"
51 HTTP_PUT = "PUT"
52 HTTP_DELETE = "DELETE"
53
54 HTTP_ETAG = "ETag"
55 HTTP_HOST = "Host"
56 HTTP_SERVER = "Server"
57 HTTP_DATE = "Date"
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"
66 HTTP_ALLOW = "Allow"
67
68 HTTP_APP_OCTET_STREAM = "application/octet-stream"
69 HTTP_APP_JSON = "application/json"
70
71 _SSL_UNEXPECTED_EOF = "Unexpected EOF"
72
73
74 (SOCKOP_SEND,
75 SOCKOP_RECV,
76 SOCKOP_SHUTDOWN,
77 SOCKOP_HANDSHAKE) = range(4)
78
79
80 SOCK_BUF_SIZE = 32768
81
82
84 """Internal exception for HTTP errors.
85
86 This should only be used for internal error reporting.
87
88 """
89
90
92 """Internal exception for a closed connection.
93
94 This should only be used for internal error reporting. Only use
95 it if there's no other way to report this condition.
96
97 """
98
99
101 """Internal exception for errors during SSL handshake.
102
103 This should only be used for internal error reporting.
104
105 """
106
107
109 """Internal exception for socket timeouts.
110
111 This should only be used for internal error reporting.
112
113 """
114
115
124
125
127 """400 Bad Request
128
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.
132
133 """
134 code = 400
135
136
138 """401 Unauthorized
139
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
143 requested resource.
144
145 """
146 code = 401
147
148
150 """403 Forbidden
151
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
154 NOT be repeated.
155
156 """
157 code = 403
158
159
161 """404 Not Found
162
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.
166
167 """
168 code = 404
169
170
172 """405 Method Not Allowed
173
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.
178
179 """
180 code = 405
181
182
184 """406 Not Acceptable
185
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.
189
190 """
191 code = 406
192
193
195 """408 Request Timeout
196
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.
200
201 """
202 code = 408
203
204
206 """409 Conflict
207
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.
212
213 """
214 code = 409
215
216
218 """410 Gone
219
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.
223
224 """
225 code = 410
226
227
229 """411 Length Required
230
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.
235
236 """
237 code = 411
238
239
241 """412 Precondition Failed
242
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
245 server.
246
247 """
248 code = 412
249
250
260
261
263 """500 Internal Server Error
264
265 RFC2616, 10.5.1: The server encountered an unexpected condition
266 which prevented it from fulfilling the request.
267
268 """
269 code = 500
270
271
273 """501 Not Implemented
274
275 RFC2616, 10.5.2: The server does not support the functionality
276 required to fulfill the request.
277
278 """
279 code = 501
280
281
283 """502 Bad Gateway
284
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.
288
289 """
290 code = 502
291
292
294 """503 Service Unavailable
295
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.
298
299 """
300 code = 503
301
302
304 """504 Gateway Timeout
305
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
310 request.
311
312 """
313 code = 504
314
315
317 """505 HTTP Version Not Supported
318
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.
321
322 """
323 code = 505
324
325
327 """Wrapper around socket functions.
328
329 This function abstracts error handling for socket operations, especially
330 for the complicated interaction with OpenSSL.
331
332 @type sock: socket
333 @param sock: Socket for the operation
334 @type op: int
335 @param op: Operation to execute (SOCKOP_* constants)
336 @type arg1: any
337 @param arg1: Parameter for function (if needed)
338 @type timeout: None or float
339 @param timeout: Timeout in seconds or None
340 @return: Return value of socket function
341
342 """
343
344 if op in (SOCKOP_SEND, SOCKOP_HANDSHAKE):
345 event_poll = select.POLLOUT
346
347 elif op == SOCKOP_RECV:
348 event_poll = select.POLLIN
349
350 elif op == SOCKOP_SHUTDOWN:
351 event_poll = None
352
353
354
355 assert timeout
356
357 else:
358 raise AssertionError("Invalid socket operation")
359
360
361 if (op == SOCKOP_HANDSHAKE and
362 not isinstance(sock, OpenSSL.SSL.ConnectionType)):
363 return
364
365
366 event_override = 0
367
368 while True:
369
370 if event_override or op in (SOCKOP_SEND, SOCKOP_RECV, SOCKOP_HANDSHAKE):
371 if event_override:
372 wait_for_event = event_override
373 else:
374 wait_for_event = event_poll
375
376 event = utils.WaitForFdCondition(sock, wait_for_event, timeout)
377 if event is None:
378 raise HttpSocketTimeout()
379
380 if event & (select.POLLNVAL | select.POLLHUP | select.POLLERR):
381
382 break
383
384 if not event & wait_for_event:
385 continue
386
387
388 event_override = 0
389
390 try:
391 try:
392 if op == SOCKOP_SEND:
393 return sock.send(arg1)
394
395 elif op == SOCKOP_RECV:
396 return sock.recv(arg1)
397
398 elif op == SOCKOP_SHUTDOWN:
399 if isinstance(sock, OpenSSL.SSL.ConnectionType):
400
401 return sock.shutdown()
402 else:
403 return sock.shutdown(arg1)
404
405 elif op == SOCKOP_HANDSHAKE:
406 return sock.do_handshake()
407
408 except OpenSSL.SSL.WantWriteError:
409
410 event_override = select.POLLOUT
411 continue
412
413 except OpenSSL.SSL.WantReadError:
414
415 event_override = select.POLLIN | select.POLLPRI
416 continue
417
418 except OpenSSL.SSL.WantX509LookupError:
419 continue
420
421 except OpenSSL.SSL.ZeroReturnError, err:
422
423
424
425
426
427 if op == SOCKOP_SEND:
428
429 raise HttpConnectionClosed(err.args)
430 elif op == SOCKOP_RECV:
431 return ""
432
433
434 raise socket.error(err.args)
435
436 except OpenSSL.SSL.SysCallError, err:
437 if op == SOCKOP_SEND:
438
439 if err.args and err.args[0] == -1 and arg1 == "":
440
441
442 return 0
443
444 if err.args == (-1, _SSL_UNEXPECTED_EOF):
445 if op == SOCKOP_RECV:
446 return ""
447 elif op == SOCKOP_HANDSHAKE:
448
449
450 raise HttpSessionHandshakeUnexpectedEOF(err.args)
451
452 raise socket.error(err.args)
453
454 except OpenSSL.SSL.Error, err:
455 raise socket.error(err.args)
456
457 except socket.error, err:
458 if err.args and err.args[0] == errno.EAGAIN:
459
460 continue
461
462 raise
463
464
466 """Closes the connection.
467
468 @type sock: socket
469 @param sock: Socket to be shut down
470 @type close_timeout: float
471 @param close_timeout: How long to wait for the peer to close
472 the connection
473 @type write_timeout: float
474 @param write_timeout: Write timeout for shutdown
475 @type msgreader: http.HttpMessageReader
476 @param msgreader: Request message reader, used to determine whether
477 peer should close connection
478 @type force: bool
479 @param force: Whether to forcibly close the connection without
480 waiting for peer
481
482 """
483
484 if msgreader and msgreader.peer_will_close and not force:
485
486 try:
487
488 if not SocketOperation(sock, SOCKOP_RECV, 1, close_timeout):
489 return
490 except (socket.error, HttpError, HttpSocketTimeout):
491
492 pass
493
494
495 try:
496
497 SocketOperation(sock, SOCKOP_SHUTDOWN, socket.SHUT_RDWR,
498 write_timeout)
499 except HttpSocketTimeout:
500 raise HttpError("Timeout while shutting down connection")
501 except socket.error, err:
502
503 if not (err.args and err.args[0] == errno.ENOTCONN):
504 raise HttpError("Error while shutting down connection: %s" % err)
505
506
508 """Shakes peer's hands.
509
510 @type sock: socket
511 @param sock: Socket to be shut down
512 @type write_timeout: float
513 @param write_timeout: Write timeout for handshake
514
515 """
516 try:
517 return SocketOperation(sock, SOCKOP_HANDSHAKE, None, write_timeout)
518 except HttpSocketTimeout:
519 raise HttpError("Timeout during SSL handshake")
520 except socket.error, err:
521 raise HttpError("Error in SSL handshake: %s" % err)
522
523
525 """Initializes the SSL infrastructure.
526
527 This function is idempotent.
528
529 """
530 if not OpenSSL.rand.status():
531 raise EnvironmentError("OpenSSL could not collect enough entropy"
532 " for the PRNG")
533
534
535
536
538 """Data class for SSL key and certificate.
539
540 """
541 - def __init__(self, ssl_key_path, ssl_cert_path):
542 """Initializes this class.
543
544 @type ssl_key_path: string
545 @param ssl_key_path: Path to file containing SSL key in PEM format
546 @type ssl_cert_path: string
547 @param ssl_cert_path: Path to file containing SSL certificate
548 in PEM format
549
550 """
551 self.ssl_key_pem = utils.ReadFile(ssl_key_path)
552 self.ssl_cert_pem = utils.ReadFile(ssl_cert_path)
553 self.ssl_cert_path = ssl_cert_path
554
556 return OpenSSL.crypto.load_privatekey(OpenSSL.crypto.FILETYPE_PEM,
557 self.ssl_key_pem)
558
560 return OpenSSL.crypto.load_certificate(OpenSSL.crypto.FILETYPE_PEM,
561 self.ssl_cert_pem)
562
563
565 """Base class for HTTP server and client.
566
567 """
569 self.using_ssl = None
570 self._ssl_params = None
571 self._ssl_key = None
572 self._ssl_cert = None
573
575 """Creates a TCP socket and initializes SSL if needed.
576
577 @type ssl_params: HttpSslParams
578 @param ssl_params: SSL key and certificate
579 @type ssl_verify_peer: bool
580 @param ssl_verify_peer: Whether to require client certificate
581 and compare it with our certificate
582 @type family: int
583 @param family: socket.AF_INET | socket.AF_INET6
584
585 """
586 assert family in (socket.AF_INET, socket.AF_INET6)
587
588 self._ssl_params = ssl_params
589 sock = socket.socket(family, socket.SOCK_STREAM)
590
591
592 self.using_ssl = ssl_params is not None
593
594 if not self.using_ssl:
595 return sock
596
597 self._ssl_key = ssl_params.GetKey()
598 self._ssl_cert = ssl_params.GetCertificate()
599
600 ctx = OpenSSL.SSL.Context(OpenSSL.SSL.SSLv23_METHOD)
601 ctx.set_options(OpenSSL.SSL.OP_NO_SSLv2)
602
603 ciphers = self.GetSslCiphers()
604 logging.debug("Setting SSL cipher string %s", ciphers)
605 ctx.set_cipher_list(ciphers)
606
607 ctx.use_privatekey(self._ssl_key)
608 ctx.use_certificate(self._ssl_cert)
609 ctx.check_privatekey()
610
611 if ssl_verify_peer:
612 ctx.set_verify(OpenSSL.SSL.VERIFY_PEER |
613 OpenSSL.SSL.VERIFY_FAIL_IF_NO_PEER_CERT,
614 self._SSLVerifyCallback)
615
616
617
618 try:
619
620 ctx.add_client_ca(self._ssl_cert)
621 except AttributeError:
622
623 ctx.load_client_ca(ssl_params.ssl_cert_path)
624
625 return OpenSSL.SSL.Connection(ctx, sock)
626
628 """Returns the ciphers string for SSL.
629
630 """
631 return constants.OPENSSL_CIPHERS
632
634 """Verify the certificate provided by the peer
635
636 We only compare fingerprints. The client must use the same certificate as
637 we do on our side.
638
639 """
640
641
642 assert self._ssl_params, "SSL not initialized"
643
644 return (self._ssl_cert.digest("sha1") == cert.digest("sha1") and
645 self._ssl_cert.digest("md5") == cert.digest("md5"))
646
647
649 """Data structure for HTTP message.
650
651 """
653 self.start_line = None
654 self.headers = None
655 self.body = None
656
657
659 """Data structure for HTTP request start line.
660
661 """
662 - def __init__(self, method, path, version):
663 self.method = method
664 self.path = path
665 self.version = version
666
668 return "%s %s %s" % (self.method, self.path, self.version)
669
670
672 """Data structure for HTTP response start line.
673
674 """
675 - def __init__(self, version, code, reason):
676 self.version = version
677 self.code = code
678 self.reason = reason
679
681 return "%s %s %s" % (self.version, self.code, self.reason)
682
683
685 """Writes an HTTP message to a socket.
686
687 """
688 - def __init__(self, sock, msg, write_timeout):
689 """Initializes this class and writes an HTTP message to a socket.
690
691 @type sock: socket
692 @param sock: Socket to be written to
693 @type msg: http.HttpMessage
694 @param msg: HTTP message to be written
695 @type write_timeout: float
696 @param write_timeout: Write timeout for socket
697
698 """
699 self._msg = msg
700
701 self._PrepareMessage()
702
703 buf = self._FormatMessage()
704
705 pos = 0
706 end = len(buf)
707 while pos < end:
708
709 data = buf[pos:(pos + SOCK_BUF_SIZE)]
710
711 sent = SocketOperation(sock, SOCKOP_SEND, data, write_timeout)
712
713
714 pos += sent
715
716 assert pos == end, "Message wasn't sent completely"
717
719 """Prepares the HTTP message by setting mandatory headers.
720
721 """
722
723
724
725 if self._msg.body:
726 self._msg.headers[HTTP_CONTENT_LENGTH] = len(self._msg.body)
727
753
754 - def HasMessageBody(self):
755 """Checks whether the HTTP message contains a body.
756
757 Can be overridden by subclasses.
758
759 """
760 return bool(self._msg.body)
761
762
764 """Reads HTTP message from socket.
765
766 """
767
768 START_LINE_LENGTH_MAX = None
769 HEADER_LENGTH_MAX = None
770
771
772 PS_START_LINE = "start-line"
773 PS_HEADERS = "headers"
774 PS_BODY = "entity-body"
775 PS_COMPLETE = "complete"
776
777 - def __init__(self, sock, msg, read_timeout):
778 """Reads an HTTP message from a socket.
779
780 @type sock: socket
781 @param sock: Socket to be read from
782 @type msg: http.HttpMessage
783 @param msg: Object for the read message
784 @type read_timeout: float
785 @param read_timeout: Read timeout for socket
786
787 """
788 self.sock = sock
789 self.msg = msg
790
791 self.start_line_buffer = None
792 self.header_buffer = StringIO()
793 self.body_buffer = StringIO()
794 self.parser_status = self.PS_START_LINE
795 self.content_length = None
796 self.peer_will_close = None
797
798 buf = ""
799 eof = False
800 while self.parser_status != self.PS_COMPLETE:
801
802
803 data = SocketOperation(sock, SOCKOP_RECV, SOCK_BUF_SIZE, read_timeout)
804
805 if data:
806 buf += data
807 else:
808 eof = True
809
810
811 buf = self._ContinueParsing(buf, eof)
812
813
814
815 if (eof and
816 self.parser_status in (self.PS_START_LINE,
817 self.PS_HEADERS)):
818 raise HttpError("Connection closed prematurely")
819
820
821 buf = self._ContinueParsing(buf, True)
822
823 assert self.parser_status == self.PS_COMPLETE
824 assert not buf, "Parser didn't read full response"
825
826
827 msg.body = self.body_buffer.getvalue()
828
830 """Main function for HTTP message state machine.
831
832 @type buf: string
833 @param buf: Receive buffer
834 @type eof: bool
835 @param eof: Whether we've reached EOF on the socket
836 @rtype: string
837 @return: Updated receive buffer
838
839 """
840
841 if self.parser_status == self.PS_START_LINE:
842
843 while True:
844 idx = buf.find("\r\n")
845
846
847
848
849
850
851 if idx == 0:
852
853 buf = buf[2:]
854 continue
855
856 if idx > 0:
857 self.start_line_buffer = buf[:idx]
858
859 self._CheckStartLineLength(len(self.start_line_buffer))
860
861
862 buf = buf[idx + 2:]
863
864 self.msg.start_line = self.ParseStartLine(self.start_line_buffer)
865
866 self.parser_status = self.PS_HEADERS
867 else:
868
869
870 self._CheckStartLineLength(len(buf))
871
872 break
873
874
875 if self.parser_status == self.PS_HEADERS:
876
877 idx = buf.find("\r\n\r\n")
878 if idx >= 0:
879 self.header_buffer.write(buf[:idx + 2])
880
881 self._CheckHeaderLength(self.header_buffer.tell())
882
883
884 buf = buf[idx + 4:]
885
886 self._ParseHeaders()
887
888 self.parser_status = self.PS_BODY
889 else:
890
891
892 self._CheckHeaderLength(len(buf))
893
894 if self.parser_status == self.PS_BODY:
895
896 self.body_buffer.write(buf)
897 buf = ""
898
899
900
901
902
903
904
905
906
907
908 if (eof or
909 self.content_length is None or
910 (self.content_length is not None and
911 self.body_buffer.tell() >= self.content_length)):
912 self.parser_status = self.PS_COMPLETE
913
914 return buf
915
927
938
940 """Parses the start line of a message.
941
942 Must be overridden by subclass.
943
944 @type start_line: string
945 @param start_line: Start line string
946
947 """
948 raise NotImplementedError()
949
951 """Evaluate whether peer will close the connection.
952
953 @rtype: bool
954 @return: Whether peer will close the connection
955
956 """
957
958
959
960
961
962
963
964
965
966
967 hdr_connection = self.msg.headers.get(HTTP_CONNECTION, None)
968 if hdr_connection:
969 hdr_connection = hdr_connection.lower()
970
971
972 if self.msg.start_line.version == HTTP_1_1:
973 return (hdr_connection and "close" in hdr_connection)
974
975
976
977
978
979 if self.msg.headers.get(HTTP_KEEP_ALIVE):
980 return False
981
982
983
984 if hdr_connection and "keep-alive" in hdr_connection:
985 return False
986
987 return True
988
990 """Parses the headers.
991
992 This function also adjusts internal variables based on header values.
993
994 RFC2616, section 4.3: The presence of a message-body in a request is
995 signaled by the inclusion of a Content-Length or Transfer-Encoding header
996 field in the request's message-headers.
997
998 """
999
1000 self.header_buffer.seek(0, 0)
1001 self.msg.headers = mimetools.Message(self.header_buffer, 0)
1002
1003 self.peer_will_close = self._WillPeerCloseConnection()
1004
1005
1006 hdr_content_length = self.msg.headers.get(HTTP_CONTENT_LENGTH, None)
1007 if hdr_content_length:
1008 try:
1009 self.content_length = int(hdr_content_length)
1010 except (TypeError, ValueError):
1011 self.content_length = None
1012 if self.content_length is not None and self.content_length < 0:
1013 self.content_length = None
1014
1015
1016
1017 if self.content_length is None:
1018 self.peer_will_close = True
1019