Statistics
| Branch: | Tag: | Revision:

root / lib / http / __init__.py @ 25e7b43f

History | View | Annotate | Download (26.9 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 HttpServiceUnavailable(HttpException):
259
  """503 Service Unavailable
260

261
  RFC2616, 10.5.4: The server is currently unable to handle the
262
  request due to a temporary overloading or maintenance of the server.
263

264
  """
265
  code = 503
266

    
267

    
268
class HttpVersionNotSupported(HttpException):
269
  """505 HTTP Version Not Supported
270

271
  RFC2616, 10.5.6: The server does not support, or refuses to support,
272
  the HTTP protocol version that was used in the request message.
273

274
  """
275
  code = 505
276

    
277

    
278
class HttpJsonConverter:
279
  CONTENT_TYPE = "application/json"
280

    
281
  def Encode(self, data):
282
    return serializer.DumpJson(data)
283

    
284
  def Decode(self, data):
285
    return serializer.LoadJson(data)
286

    
287

    
288
def WaitForSocketCondition(sock, event, timeout):
289
  """Waits for a condition to occur on the socket.
290

291
  @type sock: socket
292
  @param sock: Wait for events on this socket
293
  @type event: int
294
  @param event: ORed condition (see select module)
295
  @type timeout: float or None
296
  @param timeout: Timeout in seconds
297
  @rtype: int or None
298
  @return: None for timeout, otherwise occured conditions
299

300
  """
301
  check = (event | select.POLLPRI |
302
           select.POLLNVAL | select.POLLHUP | select.POLLERR)
303

    
304
  if timeout is not None:
305
    # Poller object expects milliseconds
306
    timeout *= 1000
307

    
308
  poller = select.poll()
309
  poller.register(sock, event)
310
  try:
311
    while True:
312
      # TODO: If the main thread receives a signal and we have no timeout, we
313
      # could wait forever. This should check a global "quit" flag or
314
      # something every so often.
315
      io_events = poller.poll(timeout)
316
      if not io_events:
317
        # Timeout
318
        return None
319
      for (evfd, evcond) in io_events:
320
        if evcond & check:
321
          return evcond
322
  finally:
323
    poller.unregister(sock)
324

    
325

    
326
def SocketOperation(sock, op, arg1, timeout):
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
  # TODO: event_poll/event_check/override
344
  if op in (SOCKOP_SEND, SOCKOP_HANDSHAKE):
345
    event_poll = select.POLLOUT
346
    event_check = select.POLLOUT
347

    
348
  elif op == SOCKOP_RECV:
349
    event_poll = select.POLLIN
350
    event_check = select.POLLIN | select.POLLPRI
351

    
352
  elif op == SOCKOP_SHUTDOWN:
353
    event_poll = None
354
    event_check = None
355

    
356
    # The timeout is only used when OpenSSL requests polling for a condition.
357
    # It is not advisable to have no timeout for shutdown.
358
    assert timeout
359

    
360
  else:
361
    raise AssertionError("Invalid socket operation")
362

    
363
  # Handshake is only supported by SSL sockets
364
  if (op == SOCKOP_HANDSHAKE and
365
      not isinstance(sock, OpenSSL.SSL.ConnectionType)):
366
    return
367

    
368
  # No override by default
369
  event_override = 0
370

    
371
  while True:
372
    # Poll only for certain operations and when asked for by an override
373
    if event_override or op in (SOCKOP_SEND, SOCKOP_RECV, SOCKOP_HANDSHAKE):
374
      if event_override:
375
        wait_for_event = event_override
376
      else:
377
        wait_for_event = event_poll
378

    
379
      event = WaitForSocketCondition(sock, wait_for_event, timeout)
380
      if event is None:
381
        raise HttpSocketTimeout()
382

    
383
      if (op == SOCKOP_RECV and
384
          event & (select.POLLNVAL | select.POLLHUP | select.POLLERR)):
385
        return ""
386

    
387
      if not event & wait_for_event:
388
        continue
389

    
390
    # Reset override
391
    event_override = 0
392

    
393
    try:
394
      try:
395
        if op == SOCKOP_SEND:
396
          return sock.send(arg1)
397

    
398
        elif op == SOCKOP_RECV:
399
          return sock.recv(arg1)
400

    
401
        elif op == SOCKOP_SHUTDOWN:
402
          if isinstance(sock, OpenSSL.SSL.ConnectionType):
403
            # PyOpenSSL's shutdown() doesn't take arguments
404
            return sock.shutdown()
405
          else:
406
            return sock.shutdown(arg1)
407

    
408
        elif op == SOCKOP_HANDSHAKE:
409
          return sock.do_handshake()
410

    
411
      except OpenSSL.SSL.WantWriteError:
412
        # OpenSSL wants to write, poll for POLLOUT
413
        event_override = select.POLLOUT
414
        continue
415

    
416
      except OpenSSL.SSL.WantReadError:
417
        # OpenSSL wants to read, poll for POLLIN
418
        event_override = select.POLLIN | select.POLLPRI
419
        continue
420

    
421
      except OpenSSL.SSL.WantX509LookupError:
422
        continue
423

    
424
      except OpenSSL.SSL.ZeroReturnError, err:
425
        # SSL Connection has been closed. In SSL 3.0 and TLS 1.0, this only
426
        # occurs if a closure alert has occurred in the protocol, i.e. the
427
        # connection has been closed cleanly. Note that this does not
428
        # necessarily mean that the transport layer (e.g. a socket) has been
429
        # closed.
430
        if op == SOCKOP_SEND:
431
          # Can happen during a renegotiation
432
          raise HttpConnectionClosed(err.args)
433
        elif op == SOCKOP_RECV:
434
          return ""
435

    
436
        # SSL_shutdown shouldn't return SSL_ERROR_ZERO_RETURN
437
        raise socket.error(err.args)
438

    
439
      except OpenSSL.SSL.SysCallError, err:
440
        if op == SOCKOP_SEND:
441
          # arg1 is the data when writing
442
          if err.args and err.args[0] == -1 and arg1 == "":
443
            # errors when writing empty strings are expected
444
            # and can be ignored
445
            return 0
446

    
447
        if err.args == (-1, _SSL_UNEXPECTED_EOF):
448
          if op == SOCKOP_RECV:
449
            return ""
450
          elif op == SOCKOP_HANDSHAKE:
451
            # Can happen if peer disconnects directly after the connection is
452
            # opened.
453
            raise HttpSessionHandshakeUnexpectedEOF(err.args)
454

    
455
        raise socket.error(err.args)
456

    
457
      except OpenSSL.SSL.Error, err:
458
        raise socket.error(err.args)
459

    
460
    except socket.error, err:
461
      if err.args and err.args[0] == errno.EAGAIN:
462
        # Ignore EAGAIN
463
        continue
464

    
465
      raise
466

    
467

    
468
def ShutdownConnection(sock, close_timeout, write_timeout, msgreader, force):
469
  """Closes the connection.
470

471
  @type sock: socket
472
  @param sock: Socket to be shut down
473
  @type close_timeout: float
474
  @param close_timeout: How long to wait for the peer to close
475
      the connection
476
  @type write_timeout: float
477
  @param write_timeout: Write timeout for shutdown
478
  @type msgreader: http.HttpMessageReader
479
  @param msgreader: Request message reader, used to determine whether
480
      peer should close connection
481
  @type force: bool
482
  @param force: Whether to forcibly close the connection without
483
      waiting for peer
484

485
  """
486
  #print msgreader.peer_will_close, force
487
  if msgreader and msgreader.peer_will_close and not force:
488
    # Wait for peer to close
489
    try:
490
      # Check whether it's actually closed
491
      if not SocketOperation(sock, SOCKOP_RECV, 1, close_timeout):
492
        return
493
    except (socket.error, HttpError, HttpSocketTimeout):
494
      # Ignore errors at this stage
495
      pass
496

    
497
  # Close the connection from our side
498
  try:
499
    # We don't care about the return value, see NOTES in SSL_shutdown(3).
500
    SocketOperation(sock, SOCKOP_SHUTDOWN, socket.SHUT_RDWR,
501
                    write_timeout)
502
  except HttpSocketTimeout:
503
    raise HttpError("Timeout while shutting down connection")
504
  except socket.error, err:
505
    # Ignore ENOTCONN
506
    if not (err.args and err.args[0] == errno.ENOTCONN):
507
      raise HttpError("Error while shutting down connection: %s" % err)
508

    
509

    
510
def Handshake(sock, write_timeout):
511
  """Shakes peer's hands.
512

513
  @type sock: socket
514
  @param sock: Socket to be shut down
515
  @type write_timeout: float
516
  @param write_timeout: Write timeout for handshake
517

518
  """
519
  try:
520
    return SocketOperation(sock, SOCKOP_HANDSHAKE, None, write_timeout)
521
  except HttpSocketTimeout:
522
    raise HttpError("Timeout during SSL handshake")
523
  except socket.error, err:
524
    raise HttpError("Error in SSL handshake: %s" % err)
525

    
526

    
527
class HttpSslParams(object):
528
  """Data class for SSL key and certificate.
529

530
  """
531
  def __init__(self, ssl_key_path, ssl_cert_path):
532
    """Initializes this class.
533

534
    @type ssl_key_path: string
535
    @param ssl_key_path: Path to file containing SSL key in PEM format
536
    @type ssl_cert_path: string
537
    @param ssl_cert_path: Path to file containing SSL certificate
538
        in PEM format
539

540
    """
541
    self.ssl_key_pem = utils.ReadFile(ssl_key_path)
542
    self.ssl_cert_pem = utils.ReadFile(ssl_cert_path)
543

    
544
  def GetKey(self):
545
    return OpenSSL.crypto.load_privatekey(OpenSSL.crypto.FILETYPE_PEM,
546
                                          self.ssl_key_pem)
547

    
548
  def GetCertificate(self):
549
    return OpenSSL.crypto.load_certificate(OpenSSL.crypto.FILETYPE_PEM,
550
                                           self.ssl_cert_pem)
551

    
552

    
553
class HttpBase(object):
554
  """Base class for HTTP server and client.
555

556
  """
557
  def __init__(self):
558
    self.using_ssl = None
559
    self._ssl_params = None
560
    self._ssl_key = None
561
    self._ssl_cert = None
562

    
563
  def _CreateSocket(self, ssl_params, ssl_verify_peer):
564
    """Creates a TCP socket and initializes SSL if needed.
565

566
    @type ssl_params: HttpSslParams
567
    @param ssl_params: SSL key and certificate
568
    @type ssl_verify_peer: bool
569
    @param ssl_verify_peer: Whether to require client certificate
570
        and compare it with our certificate
571

572
    """
573
    self._ssl_params = ssl_params
574

    
575
    sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
576

    
577
    # Should we enable SSL?
578
    self.using_ssl = ssl_params is not None
579

    
580
    if not self.using_ssl:
581
      return sock
582

    
583
    self._ssl_key = ssl_params.GetKey()
584
    self._ssl_cert = ssl_params.GetCertificate()
585

    
586
    ctx = OpenSSL.SSL.Context(OpenSSL.SSL.SSLv23_METHOD)
587
    ctx.set_options(OpenSSL.SSL.OP_NO_SSLv2)
588

    
589
    ctx.use_privatekey(self._ssl_key)
590
    ctx.use_certificate(self._ssl_cert)
591
    ctx.check_privatekey()
592

    
593
    if ssl_verify_peer:
594
      ctx.set_verify(OpenSSL.SSL.VERIFY_PEER |
595
                     OpenSSL.SSL.VERIFY_FAIL_IF_NO_PEER_CERT,
596
                     self._SSLVerifyCallback)
597

    
598
    return OpenSSL.SSL.Connection(ctx, sock)
599

    
600
  def _SSLVerifyCallback(self, conn, cert, errnum, errdepth, ok):
601
    """Verify the certificate provided by the peer
602

603
    We only compare fingerprints. The client must use the same certificate as
604
    we do on our side.
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

    
612

    
613
class HttpMessage(object):
614
  """Data structure for HTTP message.
615

616
  """
617
  def __init__(self):
618
    self.start_line = None
619
    self.headers = None
620
    self.body = None
621
    self.decoded_body = None
622

    
623

    
624
class HttpClientToServerStartLine(object):
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

    
633
  def __str__(self):
634
    return "%s %s %s" % (self.method, self.path, self.version)
635

    
636

    
637
class HttpServerToClientStartLine(object):
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

    
646
  def __str__(self):
647
    return "%s %s %s" % (self.version, self.code, self.reason)
648

    
649

    
650
class HttpMessageWriter(object):
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
      # Send only SOCK_BUF_SIZE bytes at a time
675
      data = buf[pos:(pos + SOCK_BUF_SIZE)]
676

    
677
      sent = SocketOperation(sock, SOCKOP_SEND, data, write_timeout)
678

    
679
      # Remove sent bytes
680
      pos += sent
681

    
682
    assert pos == end, "Message wasn't sent completely"
683

    
684
  def _PrepareMessage(self):
685
    """Prepares the HTTP message by setting mandatory headers.
686

687
    """
688
    # RFC2616, section 4.3: "The presence of a message-body in a request is
689
    # signaled by the inclusion of a Content-Length or Transfer-Encoding header
690
    # field in the request's message-headers."
691
    if self._msg.body:
692
      self._msg.headers[HTTP_CONTENT_LENGTH] = len(self._msg.body)
693

    
694
  def _FormatMessage(self):
695
    """Serializes the HTTP message into a string.
696

697
    """
698
    buf = StringIO()
699

    
700
    # Add start line
701
    buf.write(str(self._msg.start_line))
702
    buf.write("\r\n")
703

    
704
    # Add headers
705
    if self._msg.start_line.version != HTTP_0_9:
706
      for name, value in self._msg.headers.iteritems():
707
        buf.write("%s: %s\r\n" % (name, value))
708

    
709
    buf.write("\r\n")
710

    
711
    # Add message body if needed
712
    if self.HasMessageBody():
713
      buf.write(self._msg.body)
714

    
715
    elif self._msg.body:
716
      logging.warning("Ignoring message body")
717

    
718
    return buf.getvalue()
719

    
720
  def HasMessageBody(self):
721
    """Checks whether the HTTP message contains a body.
722

723
    Can be overriden by subclasses.
724

725
    """
726
    return bool(self._msg.body)
727

    
728

    
729
class HttpMessageReader(object):
730
  """Reads HTTP message from socket.
731

732
  """
733
  # Length limits
734
  START_LINE_LENGTH_MAX = None
735
  HEADER_LENGTH_MAX = None
736

    
737
  # Parser state machine
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
      # TODO: Don't read more than necessary (Content-Length), otherwise
768
      # data might be lost and/or an error could occur
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
      # Do some parsing and error checking while more data arrives
777
      buf = self._ContinueParsing(buf, eof)
778

    
779
      # Must be done only after the buffer has been evaluated
780
      # TODO: Connection-length < len(data read) and connection closed
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
    # Parse rest
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
    # TODO: Content-type, error handling
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

    
803
  def _ContinueParsing(self, buf, eof):
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
    # TODO: Use offset instead of slicing when possible
815
    if self.parser_status == self.PS_START_LINE:
816
      # Expect start line
817
      while True:
818
        idx = buf.find("\r\n")
819

    
820
        # RFC2616, section 4.1: "In the interest of robustness, servers SHOULD
821
        # ignore any empty line(s) received where a Request-Line is expected.
822
        # In other words, if the server is reading the protocol stream at the
823
        # beginning of a message and receives a CRLF first, it should ignore
824
        # the CRLF."
825
        if idx == 0:
826
          # TODO: Limit number of CRLFs/empty lines for safety?
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
          # Remove status line, including CRLF
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
          # Check whether incoming data is getting too large, otherwise we just
843
          # fill our read buffer.
844
          self._CheckStartLineLength(len(buf))
845

    
846
        break
847

    
848
    # TODO: Handle messages without headers
849
    if self.parser_status == self.PS_HEADERS:
850
      # Wait for header end
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
        # Remove headers, including CRLF
858
        buf = buf[idx + 4:]
859

    
860
        self._ParseHeaders()
861

    
862
        self.parser_status = self.PS_BODY
863
      else:
864
        # Check whether incoming data is getting too large, otherwise we just
865
        # fill our read buffer.
866
        self._CheckHeaderLength(len(buf))
867

    
868
    if self.parser_status == self.PS_BODY:
869
      # TODO: Implement max size for body_buffer
870
      self.body_buffer.write(buf)
871
      buf = ""
872

    
873
      # Check whether we've read everything
874
      #
875
      # RFC2616, section 4.4: "When a message-body is included with a message,
876
      # the transfer-length of that body is determined by one of the following
877
      # [...] 5. By the server closing the connection. (Closing the connection
878
      # cannot be used to indicate the end of a request body, since that would
879
      # leave no possibility for the server to send back a response.)"
880
      #
881
      # TODO: Error when buffer length > Content-Length header
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

    
890
  def _CheckStartLineLength(self, length):
891
    """Limits the start line buffer size.
892

893
    @type length: int
894
    @param length: Buffer size
895

896
    """
897
    if (self.START_LINE_LENGTH_MAX is not None and
898
        length > self.START_LINE_LENGTH_MAX):
899
      raise HttpError("Start line longer than %d chars" %
900
                       self.START_LINE_LENGTH_MAX)
901

    
902
  def _CheckHeaderLength(self, length):
903
    """Limits the header buffer size.
904

905
    @type length: int
906
    @param length: Buffer size
907

908
    """
909
    if (self.HEADER_LENGTH_MAX is not None and
910
        length > self.HEADER_LENGTH_MAX):
911
      raise HttpError("Headers longer than %d chars" % self.HEADER_LENGTH_MAX)
912

    
913
  def ParseStartLine(self, start_line):
914
    """Parses the start line of a message.
915

916
    Must be overriden by subclass.
917

918
    @type start_line: string
919
    @param start_line: Start line string
920

921
    """
922
    raise NotImplementedError()
923

    
924
  def _WillPeerCloseConnection(self):
925
    """Evaluate whether peer will close the connection.
926

927
    @rtype: bool
928
    @return: Whether peer will close the connection
929

930
    """
931
    # RFC2616, section 14.10: "HTTP/1.1 defines the "close" connection option
932
    # for the sender to signal that the connection will be closed after
933
    # completion of the response. For example,
934
    #
935
    #        Connection: close
936
    #
937
    # in either the request or the response header fields indicates that the
938
    # connection SHOULD NOT be considered `persistent' (section 8.1) after the
939
    # current request/response is complete."
940

    
941
    hdr_connection = self.msg.headers.get(HTTP_CONNECTION, None)
942
    if hdr_connection:
943
      hdr_connection = hdr_connection.lower()
944

    
945
    # An HTTP/1.1 server is assumed to stay open unless explicitly closed.
946
    if self.msg.start_line.version == HTTP_1_1:
947
      return (hdr_connection and "close" in hdr_connection)
948

    
949
    # Some HTTP/1.0 implementations have support for persistent connections,
950
    # using rules different than HTTP/1.1.
951

    
952
    # For older HTTP, Keep-Alive indicates persistent connection.
953
    if self.msg.headers.get(HTTP_KEEP_ALIVE):
954
      return False
955

    
956
    # At least Akamai returns a "Connection: Keep-Alive" header, which was
957
    # supposed to be sent by the client.
958
    if hdr_connection and "keep-alive" in hdr_connection:
959
      return False
960

    
961
    return True
962

    
963
  def _ParseHeaders(self):
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
    # Parse headers
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
    # Do we have a Content-Length header?
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 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
    # if the connection remains open and a content-length was not provided,
990
    # then assume that the connection WILL close.
991
    if self.content_length is None:
992
      self.peer_will_close = True