1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30 """HTTP module.
31
32 """
33
34 import logging
35 import mimetools
36 import OpenSSL
37 import select
38 import socket
39 import errno
40
41 from cStringIO import StringIO
42
43 from ganeti import constants
44 from ganeti import utils
45
46
47 HTTP_GANETI_VERSION = "Ganeti %s" % constants.RELEASE_VERSION
48
49 HTTP_OK = 200
50 HTTP_NO_CONTENT = 204
51 HTTP_NOT_MODIFIED = 304
52
53 HTTP_0_9 = "HTTP/0.9"
54 HTTP_1_0 = "HTTP/1.0"
55 HTTP_1_1 = "HTTP/1.1"
56
57 HTTP_GET = "GET"
58 HTTP_HEAD = "HEAD"
59 HTTP_POST = "POST"
60 HTTP_PUT = "PUT"
61 HTTP_DELETE = "DELETE"
62
63 HTTP_ETAG = "ETag"
64 HTTP_HOST = "Host"
65 HTTP_SERVER = "Server"
66 HTTP_DATE = "Date"
67 HTTP_USER_AGENT = "User-Agent"
68 HTTP_CONTENT_TYPE = "Content-Type"
69 HTTP_CONTENT_LENGTH = "Content-Length"
70 HTTP_CONNECTION = "Connection"
71 HTTP_KEEP_ALIVE = "Keep-Alive"
72 HTTP_WWW_AUTHENTICATE = "WWW-Authenticate"
73 HTTP_AUTHORIZATION = "Authorization"
74 HTTP_AUTHENTICATION_INFO = "Authentication-Info"
75 HTTP_ALLOW = "Allow"
76
77 HTTP_APP_OCTET_STREAM = "application/octet-stream"
78 HTTP_APP_JSON = "application/json"
79
80 _SSL_UNEXPECTED_EOF = "Unexpected EOF"
81
82
83 (SOCKOP_SEND,
84 SOCKOP_RECV,
85 SOCKOP_SHUTDOWN,
86 SOCKOP_HANDSHAKE) = range(4)
87
88
89 SOCK_BUF_SIZE = 32768
90
91
93 """Internal exception for HTTP errors.
94
95 This should only be used for internal error reporting.
96
97 """
98
99
101 """Internal exception for a closed connection.
102
103 This should only be used for internal error reporting. Only use
104 it if there's no other way to report this condition.
105
106 """
107
108
110 """Internal exception for errors during SSL handshake.
111
112 This should only be used for internal error reporting.
113
114 """
115
116
118 """Internal exception for socket timeouts.
119
120 This should only be used for internal error reporting.
121
122 """
123
124
133
134
136 """400 Bad Request
137
138 RFC2616, 10.4.1: The request could not be understood by the server
139 due to malformed syntax. The client SHOULD NOT repeat the request
140 without modifications.
141
142 """
143 code = 400
144
145
147 """401 Unauthorized
148
149 RFC2616, section 10.4.2: The request requires user
150 authentication. The response MUST include a WWW-Authenticate header
151 field (section 14.47) containing a challenge applicable to the
152 requested resource.
153
154 """
155 code = 401
156
157
159 """403 Forbidden
160
161 RFC2616, 10.4.4: The server understood the request, but is refusing
162 to fulfill it. Authorization will not help and the request SHOULD
163 NOT be repeated.
164
165 """
166 code = 403
167
168
170 """404 Not Found
171
172 RFC2616, 10.4.5: The server has not found anything matching the
173 Request-URI. No indication is given of whether the condition is
174 temporary or permanent.
175
176 """
177 code = 404
178
179
181 """405 Method Not Allowed
182
183 RFC2616, 10.4.6: The method specified in the Request-Line is not
184 allowed for the resource identified by the Request-URI. The response
185 MUST include an Allow header containing a list of valid methods for
186 the requested resource.
187
188 """
189 code = 405
190
191
193 """406 Not Acceptable
194
195 RFC2616, 10.4.7: The resource identified by the request is only capable of
196 generating response entities which have content characteristics not
197 acceptable according to the accept headers sent in the request.
198
199 """
200 code = 406
201
202
204 """408 Request Timeout
205
206 RFC2616, 10.4.9: The client did not produce a request within the
207 time that the server was prepared to wait. The client MAY repeat the
208 request without modifications at any later time.
209
210 """
211 code = 408
212
213
215 """409 Conflict
216
217 RFC2616, 10.4.10: The request could not be completed due to a
218 conflict with the current state of the resource. This code is only
219 allowed in situations where it is expected that the user might be
220 able to resolve the conflict and resubmit the request.
221
222 """
223 code = 409
224
225
227 """410 Gone
228
229 RFC2616, 10.4.11: The requested resource is no longer available at
230 the server and no forwarding address is known. This condition is
231 expected to be considered permanent.
232
233 """
234 code = 410
235
236
238 """411 Length Required
239
240 RFC2616, 10.4.12: The server refuses to accept the request without a
241 defined Content-Length. The client MAY repeat the request if it adds
242 a valid Content-Length header field containing the length of the
243 message-body in the request message.
244
245 """
246 code = 411
247
248
250 """412 Precondition Failed
251
252 RFC2616, 10.4.13: The precondition given in one or more of the
253 request-header fields evaluated to false when it was tested on the
254 server.
255
256 """
257 code = 412
258
259
269
270
272 """500 Internal Server Error
273
274 RFC2616, 10.5.1: The server encountered an unexpected condition
275 which prevented it from fulfilling the request.
276
277 """
278 code = 500
279
280
282 """501 Not Implemented
283
284 RFC2616, 10.5.2: The server does not support the functionality
285 required to fulfill the request.
286
287 """
288 code = 501
289
290
292 """502 Bad Gateway
293
294 RFC2616, 10.5.3: The server, while acting as a gateway or proxy,
295 received an invalid response from the upstream server it accessed in
296 attempting to fulfill the request.
297
298 """
299 code = 502
300
301
303 """503 Service Unavailable
304
305 RFC2616, 10.5.4: The server is currently unable to handle the
306 request due to a temporary overloading or maintenance of the server.
307
308 """
309 code = 503
310
311
313 """504 Gateway Timeout
314
315 RFC2616, 10.5.5: The server, while acting as a gateway or proxy, did
316 not receive a timely response from the upstream server specified by
317 the URI (e.g. HTTP, FTP, LDAP) or some other auxiliary server
318 (e.g. DNS) it needed to access in attempting to complete the
319 request.
320
321 """
322 code = 504
323
324
326 """505 HTTP Version Not Supported
327
328 RFC2616, 10.5.6: The server does not support, or refuses to support,
329 the HTTP protocol version that was used in the request message.
330
331 """
332 code = 505
333
334
336 """Parses HTTP headers.
337
338 @note: This is just a trivial wrapper around C{mimetools.Message}
339
340 """
341 return mimetools.Message(buf, 0)
342
343
345 """Wrapper around socket functions.
346
347 This function abstracts error handling for socket operations, especially
348 for the complicated interaction with OpenSSL.
349
350 @type sock: socket
351 @param sock: Socket for the operation
352 @type op: int
353 @param op: Operation to execute (SOCKOP_* constants)
354 @type arg1: any
355 @param arg1: Parameter for function (if needed)
356 @type timeout: None or float
357 @param timeout: Timeout in seconds or None
358 @return: Return value of socket function
359
360 """
361
362 if op in (SOCKOP_SEND, SOCKOP_HANDSHAKE):
363 event_poll = select.POLLOUT
364
365 elif op == SOCKOP_RECV:
366 event_poll = select.POLLIN
367
368 elif op == SOCKOP_SHUTDOWN:
369 event_poll = None
370
371
372
373 assert timeout
374
375 else:
376 raise AssertionError("Invalid socket operation")
377
378
379 if (op == SOCKOP_HANDSHAKE and
380 not isinstance(sock, OpenSSL.SSL.ConnectionType)):
381 return
382
383
384 event_override = 0
385
386 while True:
387
388 if event_override or op in (SOCKOP_SEND, SOCKOP_RECV, SOCKOP_HANDSHAKE):
389 if event_override:
390 wait_for_event = event_override
391 else:
392 wait_for_event = event_poll
393
394 event = utils.WaitForFdCondition(sock, wait_for_event, timeout)
395 if event is None:
396 raise HttpSocketTimeout()
397
398 if event & (select.POLLNVAL | select.POLLHUP | select.POLLERR):
399
400 break
401
402 if not event & wait_for_event:
403 continue
404
405
406 event_override = 0
407
408 try:
409 try:
410 if op == SOCKOP_SEND:
411 return sock.send(arg1)
412
413 elif op == SOCKOP_RECV:
414 return sock.recv(arg1)
415
416 elif op == SOCKOP_SHUTDOWN:
417 if isinstance(sock, OpenSSL.SSL.ConnectionType):
418
419 return sock.shutdown()
420 else:
421 return sock.shutdown(arg1)
422
423 elif op == SOCKOP_HANDSHAKE:
424 return sock.do_handshake()
425
426 except OpenSSL.SSL.WantWriteError:
427
428 event_override = select.POLLOUT
429 continue
430
431 except OpenSSL.SSL.WantReadError:
432
433 event_override = select.POLLIN | select.POLLPRI
434 continue
435
436 except OpenSSL.SSL.WantX509LookupError:
437 continue
438
439 except OpenSSL.SSL.ZeroReturnError, err:
440
441
442
443
444
445 if op == SOCKOP_SEND:
446
447 raise HttpConnectionClosed(err.args)
448 elif op == SOCKOP_RECV:
449 return ""
450
451
452 raise socket.error(err.args)
453
454 except OpenSSL.SSL.SysCallError, err:
455 if op == SOCKOP_SEND:
456
457 if err.args and err.args[0] == -1 and arg1 == "":
458
459
460 return 0
461
462 if err.args == (-1, _SSL_UNEXPECTED_EOF):
463 if op == SOCKOP_RECV:
464 return ""
465 elif op == SOCKOP_HANDSHAKE:
466
467
468 raise HttpSessionHandshakeUnexpectedEOF(err.args)
469
470 raise socket.error(err.args)
471
472 except OpenSSL.SSL.Error, err:
473 raise socket.error(err.args)
474
475 except socket.error, err:
476 if err.args and err.args[0] == errno.EAGAIN:
477
478 continue
479
480 raise
481
482
484 """Closes the connection.
485
486 @type sock: socket
487 @param sock: Socket to be shut down
488 @type close_timeout: float
489 @param close_timeout: How long to wait for the peer to close
490 the connection
491 @type write_timeout: float
492 @param write_timeout: Write timeout for shutdown
493 @type msgreader: http.HttpMessageReader
494 @param msgreader: Request message reader, used to determine whether
495 peer should close connection
496 @type force: bool
497 @param force: Whether to forcibly close the connection without
498 waiting for peer
499
500 """
501
502 if msgreader and msgreader.peer_will_close and not force:
503
504 try:
505
506 if not SocketOperation(sock, SOCKOP_RECV, 1, close_timeout):
507 return
508 except (socket.error, HttpError, HttpSocketTimeout):
509
510 pass
511
512
513 try:
514
515 SocketOperation(sock, SOCKOP_SHUTDOWN, socket.SHUT_RDWR,
516 write_timeout)
517 except HttpSocketTimeout:
518 raise HttpError("Timeout while shutting down connection")
519 except socket.error, err:
520
521 if not (err.args and err.args[0] == errno.ENOTCONN):
522 raise HttpError("Error while shutting down connection: %s" % err)
523
524
526 """Shakes peer's hands.
527
528 @type sock: socket
529 @param sock: Socket to be shut down
530 @type write_timeout: float
531 @param write_timeout: Write timeout for handshake
532
533 """
534 try:
535 return SocketOperation(sock, SOCKOP_HANDSHAKE, None, write_timeout)
536 except HttpSocketTimeout:
537 raise HttpError("Timeout during SSL handshake")
538 except socket.error, err:
539 raise HttpError("Error in SSL handshake: %s" % err)
540
541
543 """Data class for SSL key and certificate.
544
545 """
546 - def __init__(self, ssl_key_path, ssl_cert_path):
547 """Initializes this class.
548
549 @type ssl_key_path: string
550 @param ssl_key_path: Path to file containing SSL key in PEM format
551 @type ssl_cert_path: string
552 @param ssl_cert_path: Path to file containing SSL certificate
553 in PEM format
554
555 """
556 self.ssl_key_pem = utils.ReadFile(ssl_key_path)
557 self.ssl_cert_pem = utils.ReadFile(ssl_cert_path)
558 self.ssl_cert_path = ssl_cert_path
559
561 return OpenSSL.crypto.load_privatekey(OpenSSL.crypto.FILETYPE_PEM,
562 self.ssl_key_pem)
563
565 return OpenSSL.crypto.load_certificate(OpenSSL.crypto.FILETYPE_PEM,
566 self.ssl_cert_pem)
567
568
570 """Base class for HTTP server and client.
571
572 """
574 self.using_ssl = None
575 self._ssl_params = None
576 self._ssl_key = None
577 self._ssl_cert = None
578
580 """Creates a TCP socket and initializes SSL if needed.
581
582 @type ssl_params: HttpSslParams
583 @param ssl_params: SSL key and certificate
584 @type ssl_verify_peer: bool
585 @param ssl_verify_peer: Whether to require client certificate
586 and compare it with our certificate
587 @type family: int
588 @param family: socket.AF_INET | socket.AF_INET6
589
590 """
591 assert family in (socket.AF_INET, socket.AF_INET6)
592
593 self._ssl_params = ssl_params
594 sock = socket.socket(family, socket.SOCK_STREAM)
595
596
597 self.using_ssl = ssl_params is not None
598
599 if not self.using_ssl:
600 return sock
601
602 self._ssl_key = ssl_params.GetKey()
603 self._ssl_cert = ssl_params.GetCertificate()
604
605 ctx = OpenSSL.SSL.Context(OpenSSL.SSL.SSLv23_METHOD)
606 ctx.set_options(OpenSSL.SSL.OP_NO_SSLv2)
607
608 ciphers = self.GetSslCiphers()
609 logging.debug("Setting SSL cipher string %s", ciphers)
610 ctx.set_cipher_list(ciphers)
611
612 ctx.use_privatekey(self._ssl_key)
613 ctx.use_certificate(self._ssl_cert)
614 ctx.check_privatekey()
615
616 if ssl_verify_peer:
617 ctx.set_verify(OpenSSL.SSL.VERIFY_PEER |
618 OpenSSL.SSL.VERIFY_FAIL_IF_NO_PEER_CERT,
619 self._SSLVerifyCallback)
620
621
622
623 try:
624
625 ctx.add_client_ca(self._ssl_cert)
626 except AttributeError:
627
628 ctx.load_client_ca(ssl_params.ssl_cert_path)
629
630 return OpenSSL.SSL.Connection(ctx, sock)
631
633 """Returns the ciphers string for SSL.
634
635 """
636 return constants.OPENSSL_CIPHERS
637
639 """Verify the certificate provided by the peer
640
641 We only compare fingerprints. The client must use the same certificate as
642 we do on our side.
643
644 """
645
646
647 assert self._ssl_params, "SSL not initialized"
648
649 return (self._ssl_cert.digest("sha1") == cert.digest("sha1") and
650 self._ssl_cert.digest("md5") == cert.digest("md5"))
651
652
654 """Data structure for HTTP message.
655
656 """
658 self.start_line = None
659 self.headers = None
660 self.body = None
661
662
664 """Data structure for HTTP request start line.
665
666 """
667 - def __init__(self, method, path, version):
668 self.method = method
669 self.path = path
670 self.version = version
671
673 return "%s %s %s" % (self.method, self.path, self.version)
674
675
677 """Data structure for HTTP response start line.
678
679 """
680 - def __init__(self, version, code, reason):
684
686 return "%s %s %s" % (self.version, self.code, self.reason)
687
688
690 """Writes an HTTP message to a socket.
691
692 """
693 - def __init__(self, sock, msg, write_timeout):
694 """Initializes this class and writes an HTTP message to a socket.
695
696 @type sock: socket
697 @param sock: Socket to be written to
698 @type msg: http.HttpMessage
699 @param msg: HTTP message to be written
700 @type write_timeout: float
701 @param write_timeout: Write timeout for socket
702
703 """
704 self._msg = msg
705
706 self._PrepareMessage()
707
708 buf = self._FormatMessage()
709
710 pos = 0
711 end = len(buf)
712 while pos < end:
713
714 data = buf[pos:(pos + SOCK_BUF_SIZE)]
715
716 sent = SocketOperation(sock, SOCKOP_SEND, data, write_timeout)
717
718
719 pos += sent
720
721 assert pos == end, "Message wasn't sent completely"
722
724 """Prepares the HTTP message by setting mandatory headers.
725
726 """
727
728
729
730 if self._msg.body:
731 self._msg.headers[HTTP_CONTENT_LENGTH] = len(self._msg.body)
732
758
759 - def HasMessageBody(self):
760 """Checks whether the HTTP message contains a body.
761
762 Can be overridden by subclasses.
763
764 """
765 return bool(self._msg.body)
766
767
769 """Reads HTTP message from socket.
770
771 """
772
773 START_LINE_LENGTH_MAX = None
774 HEADER_LENGTH_MAX = None
775
776
777 PS_START_LINE = "start-line"
778 PS_HEADERS = "headers"
779 PS_BODY = "entity-body"
780 PS_COMPLETE = "complete"
781
782 - def __init__(self, sock, msg, read_timeout):
783 """Reads an HTTP message from a socket.
784
785 @type sock: socket
786 @param sock: Socket to be read from
787 @type msg: http.HttpMessage
788 @param msg: Object for the read message
789 @type read_timeout: float
790 @param read_timeout: Read timeout for socket
791
792 """
793 self.sock = sock
794 self.msg = msg
795
796 self.start_line_buffer = None
797 self.header_buffer = StringIO()
798 self.body_buffer = StringIO()
799 self.parser_status = self.PS_START_LINE
800 self.content_length = None
801 self.peer_will_close = None
802
803 buf = ""
804 eof = False
805 while self.parser_status != self.PS_COMPLETE:
806
807
808 data = SocketOperation(sock, SOCKOP_RECV, SOCK_BUF_SIZE, read_timeout)
809
810 if data:
811 buf += data
812 else:
813 eof = True
814
815
816 buf = self._ContinueParsing(buf, eof)
817
818
819
820 if (eof and
821 self.parser_status in (self.PS_START_LINE,
822 self.PS_HEADERS)):
823 raise HttpError("Connection closed prematurely")
824
825
826 buf = self._ContinueParsing(buf, True)
827
828 assert self.parser_status == self.PS_COMPLETE
829 assert not buf, "Parser didn't read full response"
830
831
832 msg.body = self.body_buffer.getvalue()
833
835 """Main function for HTTP message state machine.
836
837 @type buf: string
838 @param buf: Receive buffer
839 @type eof: bool
840 @param eof: Whether we've reached EOF on the socket
841 @rtype: string
842 @return: Updated receive buffer
843
844 """
845
846 if self.parser_status == self.PS_START_LINE:
847
848 while True:
849 idx = buf.find("\r\n")
850
851
852
853
854
855
856 if idx == 0:
857
858 buf = buf[2:]
859 continue
860
861 if idx > 0:
862 self.start_line_buffer = buf[:idx]
863
864 self._CheckStartLineLength(len(self.start_line_buffer))
865
866
867 buf = buf[idx + 2:]
868
869 self.msg.start_line = self.ParseStartLine(self.start_line_buffer)
870
871 self.parser_status = self.PS_HEADERS
872 else:
873
874
875 self._CheckStartLineLength(len(buf))
876
877 break
878
879
880 if self.parser_status == self.PS_HEADERS:
881
882 idx = buf.find("\r\n\r\n")
883 if idx >= 0:
884 self.header_buffer.write(buf[:idx + 2])
885
886 self._CheckHeaderLength(self.header_buffer.tell())
887
888
889 buf = buf[idx + 4:]
890
891 self._ParseHeaders()
892
893 self.parser_status = self.PS_BODY
894 else:
895
896
897 self._CheckHeaderLength(len(buf))
898
899 if self.parser_status == self.PS_BODY:
900
901 self.body_buffer.write(buf)
902 buf = ""
903
904
905
906
907
908
909
910
911
912
913 if (eof or
914 self.content_length is None or
915 (self.content_length is not None and
916 self.body_buffer.tell() >= self.content_length)):
917 self.parser_status = self.PS_COMPLETE
918
919 return buf
920
932
943
945 """Parses the start line of a message.
946
947 Must be overridden by subclass.
948
949 @type start_line: string
950 @param start_line: Start line string
951
952 """
953 raise NotImplementedError()
954
956 """Evaluate whether peer will close the connection.
957
958 @rtype: bool
959 @return: Whether peer will close the connection
960
961 """
962
963
964
965
966
967
968
969
970
971
972 hdr_connection = self.msg.headers.get(HTTP_CONNECTION, None)
973 if hdr_connection:
974 hdr_connection = hdr_connection.lower()
975
976
977 if self.msg.start_line.version == HTTP_1_1:
978 return (hdr_connection and "close" in hdr_connection)
979
980
981
982
983
984 if self.msg.headers.get(HTTP_KEEP_ALIVE):
985 return False
986
987
988
989 if hdr_connection and "keep-alive" in hdr_connection:
990 return False
991
992 return True
993
995 """Parses the headers.
996
997 This function also adjusts internal variables based on header values.
998
999 RFC2616, section 4.3: The presence of a message-body in a request is
1000 signaled by the inclusion of a Content-Length or Transfer-Encoding header
1001 field in the request's message-headers.
1002
1003 """
1004
1005 self.header_buffer.seek(0, 0)
1006 self.msg.headers = ParseHeaders(self.header_buffer)
1007
1008 self.peer_will_close = self._WillPeerCloseConnection()
1009
1010
1011 hdr_content_length = self.msg.headers.get(HTTP_CONTENT_LENGTH, None)
1012 if hdr_content_length:
1013 try:
1014 self.content_length = int(hdr_content_length)
1015 except (TypeError, ValueError):
1016 self.content_length = None
1017 if self.content_length is not None and self.content_length < 0:
1018 self.content_length = None
1019
1020
1021
1022 if self.content_length is None:
1023 self.peer_will_close = True
1024