Statistics
| Branch: | Tag: | Revision:

root / lib / http / __init__.py @ 81b59aaf

History | View | Annotate | Download (27.5 kB)

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:
303
  CONTENT_TYPE = "application/json"
304

    
305
  def Encode(self, data):
306
    return serializer.DumpJson(data)
307

    
308
  def Decode(self, data):
309
    return serializer.LoadJson(data)
310

    
311

    
312
def WaitForSocketCondition(sock, event, timeout):
313
  """Waits for a condition to occur on the socket.
314

315
  @type sock: socket
316
  @param sock: Wait for events on this socket
317
  @type event: int
318
  @param event: ORed condition (see select module)
319
  @type timeout: float or None
320
  @param timeout: Timeout in seconds
321
  @rtype: int or None
322
  @return: None for timeout, otherwise occured conditions
323

324
  """
325
  check = (event | select.POLLPRI |
326
           select.POLLNVAL | select.POLLHUP | select.POLLERR)
327

    
328
  if timeout is not None:
329
    # Poller object expects milliseconds
330
    timeout *= 1000
331

    
332
  poller = select.poll()
333
  poller.register(sock, event)
334
  try:
335
    while True:
336
      # TODO: If the main thread receives a signal and we have no timeout, we
337
      # could wait forever. This should check a global "quit" flag or
338
      # something every so often.
339
      io_events = poller.poll(timeout)
340
      if not io_events:
341
        # Timeout
342
        return None
343
      for (evfd, evcond) in io_events:
344
        if evcond & check:
345
          return evcond
346
  finally:
347
    poller.unregister(sock)
348

    
349

    
350
def SocketOperation(sock, op, arg1, timeout):
351
  """Wrapper around socket functions.
352

353
  This function abstracts error handling for socket operations, especially
354
  for the complicated interaction with OpenSSL.
355

356
  @type sock: socket
357
  @param sock: Socket for the operation
358
  @type op: int
359
  @param op: Operation to execute (SOCKOP_* constants)
360
  @type arg1: any
361
  @param arg1: Parameter for function (if needed)
362
  @type timeout: None or float
363
  @param timeout: Timeout in seconds or None
364
  @return: Return value of socket function
365

366
  """
367
  # TODO: event_poll/event_check/override
368
  if op in (SOCKOP_SEND, SOCKOP_HANDSHAKE):
369
    event_poll = select.POLLOUT
370
    event_check = select.POLLOUT
371

    
372
  elif op == SOCKOP_RECV:
373
    event_poll = select.POLLIN
374
    event_check = select.POLLIN | select.POLLPRI
375

    
376
  elif op == SOCKOP_SHUTDOWN:
377
    event_poll = None
378
    event_check = None
379

    
380
    # The timeout is only used when OpenSSL requests polling for a condition.
381
    # It is not advisable to have no timeout for shutdown.
382
    assert timeout
383

    
384
  else:
385
    raise AssertionError("Invalid socket operation")
386

    
387
  # Handshake is only supported by SSL sockets
388
  if (op == SOCKOP_HANDSHAKE and
389
      not isinstance(sock, OpenSSL.SSL.ConnectionType)):
390
    return
391

    
392
  # No override by default
393
  event_override = 0
394

    
395
  while True:
396
    # Poll only for certain operations and when asked for by an override
397
    if event_override or op in (SOCKOP_SEND, SOCKOP_RECV, SOCKOP_HANDSHAKE):
398
      if event_override:
399
        wait_for_event = event_override
400
      else:
401
        wait_for_event = event_poll
402

    
403
      event = WaitForSocketCondition(sock, wait_for_event, timeout)
404
      if event is None:
405
        raise HttpSocketTimeout()
406

    
407
      if (op == SOCKOP_RECV and
408
          event & (select.POLLNVAL | select.POLLHUP | select.POLLERR)):
409
        return ""
410

    
411
      if not event & wait_for_event:
412
        continue
413

    
414
    # Reset override
415
    event_override = 0
416

    
417
    try:
418
      try:
419
        if op == SOCKOP_SEND:
420
          return sock.send(arg1)
421

    
422
        elif op == SOCKOP_RECV:
423
          return sock.recv(arg1)
424

    
425
        elif op == SOCKOP_SHUTDOWN:
426
          if isinstance(sock, OpenSSL.SSL.ConnectionType):
427
            # PyOpenSSL's shutdown() doesn't take arguments
428
            return sock.shutdown()
429
          else:
430
            return sock.shutdown(arg1)
431

    
432
        elif op == SOCKOP_HANDSHAKE:
433
          return sock.do_handshake()
434

    
435
      except OpenSSL.SSL.WantWriteError:
436
        # OpenSSL wants to write, poll for POLLOUT
437
        event_override = select.POLLOUT
438
        continue
439

    
440
      except OpenSSL.SSL.WantReadError:
441
        # OpenSSL wants to read, poll for POLLIN
442
        event_override = select.POLLIN | select.POLLPRI
443
        continue
444

    
445
      except OpenSSL.SSL.WantX509LookupError:
446
        continue
447

    
448
      except OpenSSL.SSL.ZeroReturnError, err:
449
        # SSL Connection has been closed. In SSL 3.0 and TLS 1.0, this only
450
        # occurs if a closure alert has occurred in the protocol, i.e. the
451
        # connection has been closed cleanly. Note that this does not
452
        # necessarily mean that the transport layer (e.g. a socket) has been
453
        # closed.
454
        if op == SOCKOP_SEND:
455
          # Can happen during a renegotiation
456
          raise HttpConnectionClosed(err.args)
457
        elif op == SOCKOP_RECV:
458
          return ""
459

    
460
        # SSL_shutdown shouldn't return SSL_ERROR_ZERO_RETURN
461
        raise socket.error(err.args)
462

    
463
      except OpenSSL.SSL.SysCallError, err:
464
        if op == SOCKOP_SEND:
465
          # arg1 is the data when writing
466
          if err.args and err.args[0] == -1 and arg1 == "":
467
            # errors when writing empty strings are expected
468
            # and can be ignored
469
            return 0
470

    
471
        if err.args == (-1, _SSL_UNEXPECTED_EOF):
472
          if op == SOCKOP_RECV:
473
            return ""
474
          elif op == SOCKOP_HANDSHAKE:
475
            # Can happen if peer disconnects directly after the connection is
476
            # opened.
477
            raise HttpSessionHandshakeUnexpectedEOF(err.args)
478

    
479
        raise socket.error(err.args)
480

    
481
      except OpenSSL.SSL.Error, err:
482
        raise socket.error(err.args)
483

    
484
    except socket.error, err:
485
      if err.args and err.args[0] == errno.EAGAIN:
486
        # Ignore EAGAIN
487
        continue
488

    
489
      raise
490

    
491

    
492
def ShutdownConnection(sock, close_timeout, write_timeout, msgreader, force):
493
  """Closes the connection.
494

495
  @type sock: socket
496
  @param sock: Socket to be shut down
497
  @type close_timeout: float
498
  @param close_timeout: How long to wait for the peer to close
499
      the connection
500
  @type write_timeout: float
501
  @param write_timeout: Write timeout for shutdown
502
  @type msgreader: http.HttpMessageReader
503
  @param msgreader: Request message reader, used to determine whether
504
      peer should close connection
505
  @type force: bool
506
  @param force: Whether to forcibly close the connection without
507
      waiting for peer
508

509
  """
510
  #print msgreader.peer_will_close, force
511
  if msgreader and msgreader.peer_will_close and not force:
512
    # Wait for peer to close
513
    try:
514
      # Check whether it's actually closed
515
      if not SocketOperation(sock, SOCKOP_RECV, 1, close_timeout):
516
        return
517
    except (socket.error, HttpError, HttpSocketTimeout):
518
      # Ignore errors at this stage
519
      pass
520

    
521
  # Close the connection from our side
522
  try:
523
    # We don't care about the return value, see NOTES in SSL_shutdown(3).
524
    SocketOperation(sock, SOCKOP_SHUTDOWN, socket.SHUT_RDWR,
525
                    write_timeout)
526
  except HttpSocketTimeout:
527
    raise HttpError("Timeout while shutting down connection")
528
  except socket.error, err:
529
    # Ignore ENOTCONN
530
    if not (err.args and err.args[0] == errno.ENOTCONN):
531
      raise HttpError("Error while shutting down connection: %s" % err)
532

    
533

    
534
def Handshake(sock, write_timeout):
535
  """Shakes peer's hands.
536

537
  @type sock: socket
538
  @param sock: Socket to be shut down
539
  @type write_timeout: float
540
  @param write_timeout: Write timeout for handshake
541

542
  """
543
  try:
544
    return SocketOperation(sock, SOCKOP_HANDSHAKE, None, write_timeout)
545
  except HttpSocketTimeout:
546
    raise HttpError("Timeout during SSL handshake")
547
  except socket.error, err:
548
    raise HttpError("Error in SSL handshake: %s" % err)
549

    
550

    
551
class HttpSslParams(object):
552
  """Data class for SSL key and certificate.
553

554
  """
555
  def __init__(self, ssl_key_path, ssl_cert_path):
556
    """Initializes this class.
557

558
    @type ssl_key_path: string
559
    @param ssl_key_path: Path to file containing SSL key in PEM format
560
    @type ssl_cert_path: string
561
    @param ssl_cert_path: Path to file containing SSL certificate
562
        in PEM format
563

564
    """
565
    self.ssl_key_pem = utils.ReadFile(ssl_key_path)
566
    self.ssl_cert_pem = utils.ReadFile(ssl_cert_path)
567

    
568
  def GetKey(self):
569
    return OpenSSL.crypto.load_privatekey(OpenSSL.crypto.FILETYPE_PEM,
570
                                          self.ssl_key_pem)
571

    
572
  def GetCertificate(self):
573
    return OpenSSL.crypto.load_certificate(OpenSSL.crypto.FILETYPE_PEM,
574
                                           self.ssl_cert_pem)
575

    
576

    
577
class HttpBase(object):
578
  """Base class for HTTP server and client.
579

580
  """
581
  def __init__(self):
582
    self.using_ssl = None
583
    self._ssl_params = None
584
    self._ssl_key = None
585
    self._ssl_cert = None
586

    
587
  def _CreateSocket(self, ssl_params, ssl_verify_peer):
588
    """Creates a TCP socket and initializes SSL if needed.
589

590
    @type ssl_params: HttpSslParams
591
    @param ssl_params: SSL key and certificate
592
    @type ssl_verify_peer: bool
593
    @param ssl_verify_peer: Whether to require client certificate
594
        and compare it with our certificate
595

596
    """
597
    self._ssl_params = ssl_params
598

    
599
    sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
600

    
601
    # Should we enable SSL?
602
    self.using_ssl = ssl_params is not None
603

    
604
    if not self.using_ssl:
605
      return sock
606

    
607
    self._ssl_key = ssl_params.GetKey()
608
    self._ssl_cert = ssl_params.GetCertificate()
609

    
610
    ctx = OpenSSL.SSL.Context(OpenSSL.SSL.SSLv23_METHOD)
611
    ctx.set_options(OpenSSL.SSL.OP_NO_SSLv2)
612

    
613
    ctx.use_privatekey(self._ssl_key)
614
    ctx.use_certificate(self._ssl_cert)
615
    ctx.check_privatekey()
616

    
617
    if ssl_verify_peer:
618
      ctx.set_verify(OpenSSL.SSL.VERIFY_PEER |
619
                     OpenSSL.SSL.VERIFY_FAIL_IF_NO_PEER_CERT,
620
                     self._SSLVerifyCallback)
621

    
622
    return OpenSSL.SSL.Connection(ctx, sock)
623

    
624
  def _SSLVerifyCallback(self, conn, cert, errnum, errdepth, ok):
625
    """Verify the certificate provided by the peer
626

627
    We only compare fingerprints. The client must use the same certificate as
628
    we do on our side.
629

630
    """
631
    assert self._ssl_params, "SSL not initialized"
632

    
633
    return (self._ssl_cert.digest("sha1") == cert.digest("sha1") and
634
            self._ssl_cert.digest("md5") == cert.digest("md5"))
635

    
636

    
637
class HttpMessage(object):
638
  """Data structure for HTTP message.
639

640
  """
641
  def __init__(self):
642
    self.start_line = None
643
    self.headers = None
644
    self.body = None
645
    self.decoded_body = None
646

    
647

    
648
class HttpClientToServerStartLine(object):
649
  """Data structure for HTTP request start line.
650

651
  """
652
  def __init__(self, method, path, version):
653
    self.method = method
654
    self.path = path
655
    self.version = version
656

    
657
  def __str__(self):
658
    return "%s %s %s" % (self.method, self.path, self.version)
659

    
660

    
661
class HttpServerToClientStartLine(object):
662
  """Data structure for HTTP response start line.
663

664
  """
665
  def __init__(self, version, code, reason):
666
    self.version = version
667
    self.code = code
668
    self.reason = reason
669

    
670
  def __str__(self):
671
    return "%s %s %s" % (self.version, self.code, self.reason)
672

    
673

    
674
class HttpMessageWriter(object):
675
  """Writes an HTTP message to a socket.
676

677
  """
678
  def __init__(self, sock, msg, write_timeout):
679
    """Initializes this class and writes an HTTP message to a socket.
680

681
    @type sock: socket
682
    @param sock: Socket to be written to
683
    @type msg: http.HttpMessage
684
    @param msg: HTTP message to be written
685
    @type write_timeout: float
686
    @param write_timeout: Write timeout for socket
687

688
    """
689
    self._msg = msg
690

    
691
    self._PrepareMessage()
692

    
693
    buf = self._FormatMessage()
694

    
695
    pos = 0
696
    end = len(buf)
697
    while pos < end:
698
      # Send only SOCK_BUF_SIZE bytes at a time
699
      data = buf[pos:(pos + SOCK_BUF_SIZE)]
700

    
701
      sent = SocketOperation(sock, SOCKOP_SEND, data, write_timeout)
702

    
703
      # Remove sent bytes
704
      pos += sent
705

    
706
    assert pos == end, "Message wasn't sent completely"
707

    
708
  def _PrepareMessage(self):
709
    """Prepares the HTTP message by setting mandatory headers.
710

711
    """
712
    # RFC2616, section 4.3: "The presence of a message-body in a request is
713
    # signaled by the inclusion of a Content-Length or Transfer-Encoding header
714
    # field in the request's message-headers."
715
    if self._msg.body:
716
      self._msg.headers[HTTP_CONTENT_LENGTH] = len(self._msg.body)
717

    
718
  def _FormatMessage(self):
719
    """Serializes the HTTP message into a string.
720

721
    """
722
    buf = StringIO()
723

    
724
    # Add start line
725
    buf.write(str(self._msg.start_line))
726
    buf.write("\r\n")
727

    
728
    # Add headers
729
    if self._msg.start_line.version != HTTP_0_9:
730
      for name, value in self._msg.headers.iteritems():
731
        buf.write("%s: %s\r\n" % (name, value))
732

    
733
    buf.write("\r\n")
734

    
735
    # Add message body if needed
736
    if self.HasMessageBody():
737
      buf.write(self._msg.body)
738

    
739
    elif self._msg.body:
740
      logging.warning("Ignoring message body")
741

    
742
    return buf.getvalue()
743

    
744
  def HasMessageBody(self):
745
    """Checks whether the HTTP message contains a body.
746

747
    Can be overriden by subclasses.
748

749
    """
750
    return bool(self._msg.body)
751

    
752

    
753
class HttpMessageReader(object):
754
  """Reads HTTP message from socket.
755

756
  """
757
  # Length limits
758
  START_LINE_LENGTH_MAX = None
759
  HEADER_LENGTH_MAX = None
760

    
761
  # Parser state machine
762
  PS_START_LINE = "start-line"
763
  PS_HEADERS = "headers"
764
  PS_BODY = "entity-body"
765
  PS_COMPLETE = "complete"
766

    
767
  def __init__(self, sock, msg, read_timeout):
768
    """Reads an HTTP message from a socket.
769

770
    @type sock: socket
771
    @param sock: Socket to be read from
772
    @type msg: http.HttpMessage
773
    @param msg: Object for the read message
774
    @type read_timeout: float
775
    @param read_timeout: Read timeout for socket
776

777
    """
778
    self.sock = sock
779
    self.msg = msg
780

    
781
    self.start_line_buffer = None
782
    self.header_buffer = StringIO()
783
    self.body_buffer = StringIO()
784
    self.parser_status = self.PS_START_LINE
785
    self.content_length = None
786
    self.peer_will_close = None
787

    
788
    buf = ""
789
    eof = False
790
    while self.parser_status != self.PS_COMPLETE:
791
      # TODO: Don't read more than necessary (Content-Length), otherwise
792
      # data might be lost and/or an error could occur
793
      data = SocketOperation(sock, SOCKOP_RECV, SOCK_BUF_SIZE, read_timeout)
794

    
795
      if data:
796
        buf += data
797
      else:
798
        eof = True
799

    
800
      # Do some parsing and error checking while more data arrives
801
      buf = self._ContinueParsing(buf, eof)
802

    
803
      # Must be done only after the buffer has been evaluated
804
      # TODO: Connection-length < len(data read) and connection closed
805
      if (eof and
806
          self.parser_status in (self.PS_START_LINE,
807
                                 self.PS_HEADERS)):
808
        raise HttpError("Connection closed prematurely")
809

    
810
    # Parse rest
811
    buf = self._ContinueParsing(buf, True)
812

    
813
    assert self.parser_status == self.PS_COMPLETE
814
    assert not buf, "Parser didn't read full response"
815

    
816
    msg.body = self.body_buffer.getvalue()
817

    
818
    # TODO: Content-type, error handling
819
    if msg.body:
820
      msg.decoded_body = HttpJsonConverter().Decode(msg.body)
821
    else:
822
      msg.decoded_body = None
823

    
824
    if msg.decoded_body:
825
      logging.debug("Message body: %s", msg.decoded_body)
826

    
827
  def _ContinueParsing(self, buf, eof):
828
    """Main function for HTTP message state machine.
829

830
    @type buf: string
831
    @param buf: Receive buffer
832
    @type eof: bool
833
    @param eof: Whether we've reached EOF on the socket
834
    @rtype: string
835
    @return: Updated receive buffer
836

837
    """
838
    # TODO: Use offset instead of slicing when possible
839
    if self.parser_status == self.PS_START_LINE:
840
      # Expect start line
841
      while True:
842
        idx = buf.find("\r\n")
843

    
844
        # RFC2616, section 4.1: "In the interest of robustness, servers SHOULD
845
        # ignore any empty line(s) received where a Request-Line is expected.
846
        # In other words, if the server is reading the protocol stream at the
847
        # beginning of a message and receives a CRLF first, it should ignore
848
        # the CRLF."
849
        if idx == 0:
850
          # TODO: Limit number of CRLFs/empty lines for safety?
851
          buf = buf[:2]
852
          continue
853

    
854
        if idx > 0:
855
          self.start_line_buffer = buf[:idx]
856

    
857
          self._CheckStartLineLength(len(self.start_line_buffer))
858

    
859
          # Remove status line, including CRLF
860
          buf = buf[idx + 2:]
861

    
862
          self.msg.start_line = self.ParseStartLine(self.start_line_buffer)
863

    
864
          self.parser_status = self.PS_HEADERS
865
        else:
866
          # Check whether incoming data is getting too large, otherwise we just
867
          # fill our read buffer.
868
          self._CheckStartLineLength(len(buf))
869

    
870
        break
871

    
872
    # TODO: Handle messages without headers
873
    if self.parser_status == self.PS_HEADERS:
874
      # Wait for header end
875
      idx = buf.find("\r\n\r\n")
876
      if idx >= 0:
877
        self.header_buffer.write(buf[:idx + 2])
878

    
879
        self._CheckHeaderLength(self.header_buffer.tell())
880

    
881
        # Remove headers, including CRLF
882
        buf = buf[idx + 4:]
883

    
884
        self._ParseHeaders()
885

    
886
        self.parser_status = self.PS_BODY
887
      else:
888
        # Check whether incoming data is getting too large, otherwise we just
889
        # fill our read buffer.
890
        self._CheckHeaderLength(len(buf))
891

    
892
    if self.parser_status == self.PS_BODY:
893
      # TODO: Implement max size for body_buffer
894
      self.body_buffer.write(buf)
895
      buf = ""
896

    
897
      # Check whether we've read everything
898
      #
899
      # RFC2616, section 4.4: "When a message-body is included with a message,
900
      # the transfer-length of that body is determined by one of the following
901
      # [...] 5. By the server closing the connection. (Closing the connection
902
      # cannot be used to indicate the end of a request body, since that would
903
      # leave no possibility for the server to send back a response.)"
904
      #
905
      # TODO: Error when buffer length > Content-Length header
906
      if (eof or
907
          self.content_length is None or
908
          (self.content_length is not None and
909
           self.body_buffer.tell() >= self.content_length)):
910
        self.parser_status = self.PS_COMPLETE
911

    
912
    return buf
913

    
914
  def _CheckStartLineLength(self, length):
915
    """Limits the start line buffer size.
916

917
    @type length: int
918
    @param length: Buffer size
919

920
    """
921
    if (self.START_LINE_LENGTH_MAX is not None and
922
        length > self.START_LINE_LENGTH_MAX):
923
      raise HttpError("Start line longer than %d chars" %
924
                       self.START_LINE_LENGTH_MAX)
925

    
926
  def _CheckHeaderLength(self, length):
927
    """Limits the header buffer size.
928

929
    @type length: int
930
    @param length: Buffer size
931

932
    """
933
    if (self.HEADER_LENGTH_MAX is not None and
934
        length > self.HEADER_LENGTH_MAX):
935
      raise HttpError("Headers longer than %d chars" % self.HEADER_LENGTH_MAX)
936

    
937
  def ParseStartLine(self, start_line):
938
    """Parses the start line of a message.
939

940
    Must be overriden by subclass.
941

942
    @type start_line: string
943
    @param start_line: Start line string
944

945
    """
946
    raise NotImplementedError()
947

    
948
  def _WillPeerCloseConnection(self):
949
    """Evaluate whether peer will close the connection.
950

951
    @rtype: bool
952
    @return: Whether peer will close the connection
953

954
    """
955
    # RFC2616, section 14.10: "HTTP/1.1 defines the "close" connection option
956
    # for the sender to signal that the connection will be closed after
957
    # completion of the response. For example,
958
    #
959
    #        Connection: close
960
    #
961
    # in either the request or the response header fields indicates that the
962
    # connection SHOULD NOT be considered `persistent' (section 8.1) after the
963
    # current request/response is complete."
964

    
965
    hdr_connection = self.msg.headers.get(HTTP_CONNECTION, None)
966
    if hdr_connection:
967
      hdr_connection = hdr_connection.lower()
968

    
969
    # An HTTP/1.1 server is assumed to stay open unless explicitly closed.
970
    if self.msg.start_line.version == HTTP_1_1:
971
      return (hdr_connection and "close" in hdr_connection)
972

    
973
    # Some HTTP/1.0 implementations have support for persistent connections,
974
    # using rules different than HTTP/1.1.
975

    
976
    # For older HTTP, Keep-Alive indicates persistent connection.
977
    if self.msg.headers.get(HTTP_KEEP_ALIVE):
978
      return False
979

    
980
    # At least Akamai returns a "Connection: Keep-Alive" header, which was
981
    # supposed to be sent by the client.
982
    if hdr_connection and "keep-alive" in hdr_connection:
983
      return False
984

    
985
    return True
986

    
987
  def _ParseHeaders(self):
988
    """Parses the headers.
989

990
    This function also adjusts internal variables based on header values.
991

992
    RFC2616, section 4.3: The presence of a message-body in a request is
993
    signaled by the inclusion of a Content-Length or Transfer-Encoding header
994
    field in the request's message-headers.
995

996
    """
997
    # Parse headers
998
    self.header_buffer.seek(0, 0)
999
    self.msg.headers = mimetools.Message(self.header_buffer, 0)
1000

    
1001
    self.peer_will_close = self._WillPeerCloseConnection()
1002

    
1003
    # Do we have a Content-Length header?
1004
    hdr_content_length = self.msg.headers.get(HTTP_CONTENT_LENGTH, None)
1005
    if hdr_content_length:
1006
      try:
1007
        self.content_length = int(hdr_content_length)
1008
      except ValueError:
1009
        self.content_length = None
1010
      if self.content_length is not None and self.content_length < 0:
1011
        self.content_length = None
1012

    
1013
    # if the connection remains open and a content-length was not provided,
1014
    # then assume that the connection WILL close.
1015
    if self.content_length is None:
1016
      self.peer_will_close = True