Statistics
| Branch: | Tag: | Revision:

root / lib / http / __init__.py @ 79589f25

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 due to
128
  malformed syntax. The client SHOULD NOT repeat the request without
129
  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 authentication. The
139
  response MUST include a WWW-Authenticate header field (section 14.47)
140
  containing a challenge applicable to the requested resource.
141

142
  """
143
  code = 401
144

    
145

    
146
class HttpForbidden(HttpException):
147
  """403 Forbidden
148

149
  RFC2616, 10.4.4: The server understood the request, but is refusing to
150
  fulfill it.  Authorization will not help and the request SHOULD NOT be
151
  repeated.
152

153
  """
154
  code = 403
155

    
156

    
157
class HttpNotFound(HttpException):
158
  """404 Not Found
159

160
  RFC2616, 10.4.5: The server has not found anything matching the Request-URI.
161
  No indication is given of whether the condition is temporary or permanent.
162

163
  """
164
  code = 404
165

    
166

    
167
class HttpMethodNotAllowed(HttpException):
168
  """405 Method Not Allowed
169

170
  RFC2616, 10.4.6: The method specified in the Request-Line is not allowed for
171
  the resource identified by the Request-URI. The response MUST include an
172
  Allow header containing a list of valid methods for the requested resource.
173

174
  """
175
  code = 405
176

    
177

    
178
class HttpRequestTimeout(HttpException):
179
  """408 Request Timeout
180

181
  RFC2616, 10.4.9: The client did not produce a request within the time that
182
  the server was prepared to wait. The client MAY repeat the request without
183
  modifications at any later time.
184

185
  """
186
  code = 408
187

    
188

    
189
class HttpConflict(HttpException):
190
  """409 Conflict
191

192
  RFC2616, 10.4.10: The request could not be completed due to a conflict with
193
  the current state of the resource. This code is only allowed in situations
194
  where it is expected that the user might be able to resolve the conflict and
195
  resubmit the request.
196

197
  """
198
  code = 409
199

    
200

    
201
class HttpGone(HttpException):
202
  """410 Gone
203

204
  RFC2616, 10.4.11: The requested resource is no longer available at the server
205
  and no forwarding address is known. This condition is expected to be
206
  considered permanent.
207

208
  """
209
  code = 410
210

    
211

    
212
class HttpLengthRequired(HttpException):
213
  """411 Length Required
214

215
  RFC2616, 10.4.12: The server refuses to accept the request without a defined
216
  Content-Length. The client MAY repeat the request if it adds a valid
217
  Content-Length header field containing the length of the message-body in the
218
  request message.
219

220
  """
221
  code = 411
222

    
223

    
224
class HttpPreconditionFailed(HttpException):
225
  """412 Precondition Failed
226

227
  RFC2616, 10.4.13: The precondition given in one or more of the request-header
228
  fields evaluated to false when it was tested on the server.
229

230
  """
231
  code = 412
232

    
233

    
234
class HttpInternalServerError(HttpException):
235
  """500 Internal Server Error
236

237
  RFC2616, 10.5.1: The server encountered an unexpected condition which
238
  prevented it from fulfilling the request.
239

240
  """
241
  code = 500
242

    
243

    
244
class HttpNotImplemented(HttpException):
245
  """501 Not Implemented
246

247
  RFC2616, 10.5.2: The server does not support the functionality required to
248
  fulfill the request.
249

250
  """
251
  code = 501
252

    
253

    
254
class HttpServiceUnavailable(HttpException):
255
  """503 Service Unavailable
256

257
  RFC2616, 10.5.4: The server is currently unable to handle the request due to
258
  a temporary overloading or maintenance of the server.
259

260
  """
261
  code = 503
262

    
263

    
264
class HttpVersionNotSupported(HttpException):
265
  """505 HTTP Version Not Supported
266

267
  RFC2616, 10.5.6: The server does not support, or refuses to support, the HTTP
268
  protocol version that was used in the request message.
269

270
  """
271
  code = 505
272

    
273

    
274
class HttpJsonConverter:
275
  CONTENT_TYPE = "application/json"
276

    
277
  def Encode(self, data):
278
    return serializer.DumpJson(data)
279

    
280
  def Decode(self, data):
281
    return serializer.LoadJson(data)
282

    
283

    
284
def WaitForSocketCondition(poller, sock, event, timeout):
285
  """Waits for a condition to occur on the socket.
286

287
  @type poller: select.Poller
288
  @param poller: Poller object as created by select.poll()
289
  @type sock: socket
290
  @param sock: Wait for events on this socket
291
  @type event: int
292
  @param event: ORed condition (see select module)
293
  @type timeout: float or None
294
  @param timeout: Timeout in seconds
295
  @rtype: int or None
296
  @return: None for timeout, otherwise occured conditions
297

298
  """
299
  check = (event | select.POLLPRI |
300
           select.POLLNVAL | select.POLLHUP | select.POLLERR)
301

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

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

    
322

    
323
def SocketOperation(poller, sock, op, arg1, timeout):
324
  """Wrapper around socket functions.
325

326
  This function abstracts error handling for socket operations, especially
327
  for the complicated interaction with OpenSSL.
328

329
  @type poller: select.Poller
330
  @param poller: Poller object as created by select.poll()
331
  @type sock: socket
332
  @param sock: Socket for the operation
333
  @type op: int
334
  @param op: Operation to execute (SOCKOP_* constants)
335
  @type arg1: any
336
  @param arg1: Parameter for function (if needed)
337
  @type timeout: None or float
338
  @param timeout: Timeout in seconds or None
339
  @return: Return value of socket function
340

341
  """
342
  # TODO: event_poll/event_check/override
343
  if op in (SOCKOP_SEND, SOCKOP_HANDSHAKE):
344
    event_poll = select.POLLOUT
345
    event_check = select.POLLOUT
346

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

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

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

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

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

    
367
  # No override by default
368
  event_override = 0
369

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

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

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

    
386
      if not event & wait_for_event:
387
        continue
388

    
389
    # Reset override
390
    event_override = 0
391

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

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

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

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

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

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

    
420
      except OpenSSL.SSL.WantX509LookupError:
421
        continue
422

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

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

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

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

    
454
        raise socket.error(err.args)
455

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

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

    
464
      raise
465

    
466

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

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

486
  """
487
  poller = select.poll()
488

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

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

    
512

    
513
def Handshake(poller, sock, write_timeout):
514
  """Shakes peer's hands.
515

516
  @type poller: select.Poller
517
  @param poller: Poller object as created by select.poll()
518
  @type sock: socket
519
  @param sock: Socket to be shut down
520
  @type write_timeout: float
521
  @param write_timeout: Write timeout for handshake
522

523
  """
524
  try:
525
    return SocketOperation(poller, sock, SOCKOP_HANDSHAKE, None, write_timeout)
526
  except HttpSocketTimeout:
527
    raise HttpError("Timeout during SSL handshake")
528
  except socket.error, err:
529
    raise HttpError("Error in SSL handshake: %s" % err)
530

    
531

    
532
class HttpSslParams(object):
533
  """Data class for SSL key and certificate.
534

535
  """
536
  def __init__(self, ssl_key_path, ssl_cert_path):
537
    """Initializes this class.
538

539
    @type ssl_key_path: string
540
    @param ssl_key_path: Path to file containing SSL key in PEM format
541
    @type ssl_cert_path: string
542
    @param ssl_cert_path: Path to file containing SSL certificate in PEM format
543

544
    """
545
    self.ssl_key_pem = utils.ReadFile(ssl_key_path)
546
    self.ssl_cert_pem = utils.ReadFile(ssl_cert_path)
547

    
548
  def GetKey(self):
549
    return OpenSSL.crypto.load_privatekey(OpenSSL.crypto.FILETYPE_PEM,
550
                                          self.ssl_key_pem)
551

    
552
  def GetCertificate(self):
553
    return OpenSSL.crypto.load_certificate(OpenSSL.crypto.FILETYPE_PEM,
554
                                           self.ssl_cert_pem)
555

    
556

    
557
class HttpBase(object):
558
  """Base class for HTTP server and client.
559

560
  """
561
  def __init__(self):
562
    self.using_ssl = None
563
    self._ssl_params = None
564
    self._ssl_key = None
565
    self._ssl_cert = None
566

    
567
  def _CreateSocket(self, ssl_params, ssl_verify_peer):
568
    """Creates a TCP socket and initializes SSL if needed.
569

570
    @type ssl_params: HttpSslParams
571
    @param ssl_params: SSL key and certificate
572
    @type ssl_verify_peer: bool
573
    @param ssl_verify_peer: Whether to require client certificate and compare
574
                            it with our certificate
575

576
    """
577
    self._ssl_params = ssl_params
578

    
579
    sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
580

    
581
    # Should we enable SSL?
582
    self.using_ssl = ssl_params is not None
583

    
584
    if not self.using_ssl:
585
      return sock
586

    
587
    self._ssl_key = ssl_params.GetKey()
588
    self._ssl_cert = ssl_params.GetCertificate()
589

    
590
    ctx = OpenSSL.SSL.Context(OpenSSL.SSL.SSLv23_METHOD)
591
    ctx.set_options(OpenSSL.SSL.OP_NO_SSLv2)
592

    
593
    ctx.use_privatekey(self._ssl_key)
594
    ctx.use_certificate(self._ssl_cert)
595
    ctx.check_privatekey()
596

    
597
    if ssl_verify_peer:
598
      ctx.set_verify(OpenSSL.SSL.VERIFY_PEER |
599
                     OpenSSL.SSL.VERIFY_FAIL_IF_NO_PEER_CERT,
600
                     self._SSLVerifyCallback)
601

    
602
    return OpenSSL.SSL.Connection(ctx, sock)
603

    
604
  def _SSLVerifyCallback(self, conn, cert, errnum, errdepth, ok):
605
    """Verify the certificate provided by the peer
606

607
    We only compare fingerprints. The client must use the same certificate as
608
    we do on our side.
609

610
    """
611
    assert self._ssl_params, "SSL not initialized"
612

    
613
    return (self._ssl_cert.digest("sha1") == cert.digest("sha1") and
614
            self._ssl_cert.digest("md5") == cert.digest("md5"))
615

    
616

    
617
class HttpMessage(object):
618
  """Data structure for HTTP message.
619

620
  """
621
  def __init__(self):
622
    self.start_line = None
623
    self.headers = None
624
    self.body = None
625
    self.decoded_body = None
626

    
627

    
628
class HttpClientToServerStartLine(object):
629
  """Data structure for HTTP request start line.
630

631
  """
632
  def __init__(self, method, path, version):
633
    self.method = method
634
    self.path = path
635
    self.version = version
636

    
637
  def __str__(self):
638
    return "%s %s %s" % (self.method, self.path, self.version)
639

    
640

    
641
class HttpServerToClientStartLine(object):
642
  """Data structure for HTTP response start line.
643

644
  """
645
  def __init__(self, version, code, reason):
646
    self.version = version
647
    self.code = code
648
    self.reason = reason
649

    
650
  def __str__(self):
651
    return "%s %s %s" % (self.version, self.code, self.reason)
652

    
653

    
654
class HttpMessageWriter(object):
655
  """Writes an HTTP message to a socket.
656

657
  """
658
  def __init__(self, sock, msg, write_timeout):
659
    """Initializes this class and writes an HTTP message to a socket.
660

661
    @type sock: socket
662
    @param sock: Socket to be written to
663
    @type msg: http.HttpMessage
664
    @param msg: HTTP message to be written
665
    @type write_timeout: float
666
    @param write_timeout: Write timeout for socket
667

668
    """
669
    self._msg = msg
670

    
671
    self._PrepareMessage()
672

    
673
    buf = self._FormatMessage()
674

    
675
    poller = select.poll()
676

    
677
    pos = 0
678
    end = len(buf)
679
    while pos < end:
680
      # Send only SOCK_BUF_SIZE bytes at a time
681
      data = buf[pos:(pos + SOCK_BUF_SIZE)]
682

    
683
      sent = SocketOperation(poller, sock, SOCKOP_SEND, data,
684
                             write_timeout)
685

    
686
      # Remove sent bytes
687
      pos += sent
688

    
689
    assert pos == end, "Message wasn't sent completely"
690

    
691
  def _PrepareMessage(self):
692
    """Prepares the HTTP message by setting mandatory headers.
693

694
    """
695
    # RFC2616, section 4.3: "The presence of a message-body in a request is
696
    # signaled by the inclusion of a Content-Length or Transfer-Encoding header
697
    # field in the request's message-headers."
698
    if self._msg.body:
699
      self._msg.headers[HTTP_CONTENT_LENGTH] = len(self._msg.body)
700

    
701
  def _FormatMessage(self):
702
    """Serializes the HTTP message into a string.
703

704
    """
705
    buf = StringIO()
706

    
707
    # Add start line
708
    buf.write(str(self._msg.start_line))
709
    buf.write("\r\n")
710

    
711
    # Add headers
712
    if self._msg.start_line.version != HTTP_0_9:
713
      for name, value in self._msg.headers.iteritems():
714
        buf.write("%s: %s\r\n" % (name, value))
715

    
716
    buf.write("\r\n")
717

    
718
    # Add message body if needed
719
    if self.HasMessageBody():
720
      buf.write(self._msg.body)
721

    
722
    elif self._msg.body:
723
      logging.warning("Ignoring message body")
724

    
725
    return buf.getvalue()
726

    
727
  def HasMessageBody(self):
728
    """Checks whether the HTTP message contains a body.
729

730
    Can be overriden by subclasses.
731

732
    """
733
    return bool(self._msg.body)
734

    
735

    
736
class HttpMessageReader(object):
737
  """Reads HTTP message from socket.
738

739
  """
740
  # Length limits
741
  START_LINE_LENGTH_MAX = None
742
  HEADER_LENGTH_MAX = None
743

    
744
  # Parser state machine
745
  PS_START_LINE = "start-line"
746
  PS_HEADERS = "headers"
747
  PS_BODY = "entity-body"
748
  PS_COMPLETE = "complete"
749

    
750
  def __init__(self, sock, msg, read_timeout):
751
    """Reads an HTTP message from a socket.
752

753
    @type sock: socket
754
    @param sock: Socket to be read from
755
    @type msg: http.HttpMessage
756
    @param msg: Object for the read message
757
    @type read_timeout: float
758
    @param read_timeout: Read timeout for socket
759

760
    """
761
    self.sock = sock
762
    self.msg = msg
763

    
764
    self.poller = select.poll()
765
    self.start_line_buffer = None
766
    self.header_buffer = StringIO()
767
    self.body_buffer = StringIO()
768
    self.parser_status = self.PS_START_LINE
769
    self.content_length = None
770
    self.peer_will_close = None
771

    
772
    buf = ""
773
    eof = False
774
    while self.parser_status != self.PS_COMPLETE:
775
      # TODO: Don't read more than necessary (Content-Length), otherwise
776
      # data might be lost and/or an error could occur
777
      data = SocketOperation(self.poller, sock, SOCKOP_RECV, SOCK_BUF_SIZE,
778
                             read_timeout)
779

    
780
      if data:
781
        buf += data
782
      else:
783
        eof = True
784

    
785
      # Do some parsing and error checking while more data arrives
786
      buf = self._ContinueParsing(buf, eof)
787

    
788
      # Must be done only after the buffer has been evaluated
789
      # TODO: Connection-length < len(data read) and connection closed
790
      if (eof and
791
          self.parser_status in (self.PS_START_LINE,
792
                                 self.PS_HEADERS)):
793
        raise HttpError("Connection closed prematurely")
794

    
795
    # Parse rest
796
    buf = self._ContinueParsing(buf, True)
797

    
798
    assert self.parser_status == self.PS_COMPLETE
799
    assert not buf, "Parser didn't read full response"
800

    
801
    msg.body = self.body_buffer.getvalue()
802

    
803
    # TODO: Content-type, error handling
804
    if msg.body:
805
      msg.decoded_body = HttpJsonConverter().Decode(msg.body)
806
    else:
807
      msg.decoded_body = None
808

    
809
    if msg.decoded_body:
810
      logging.debug("Message body: %s", msg.decoded_body)
811

    
812
  def _ContinueParsing(self, buf, eof):
813
    """Main function for HTTP message state machine.
814

815
    @type buf: string
816
    @param buf: Receive buffer
817
    @type eof: bool
818
    @param eof: Whether we've reached EOF on the socket
819
    @rtype: string
820
    @return: Updated receive buffer
821

822
    """
823
    # TODO: Use offset instead of slicing when possible
824
    if self.parser_status == self.PS_START_LINE:
825
      # Expect start line
826
      while True:
827
        idx = buf.find("\r\n")
828

    
829
        # RFC2616, section 4.1: "In the interest of robustness, servers SHOULD
830
        # ignore any empty line(s) received where a Request-Line is expected.
831
        # In other words, if the server is reading the protocol stream at the
832
        # beginning of a message and receives a CRLF first, it should ignore
833
        # the CRLF."
834
        if idx == 0:
835
          # TODO: Limit number of CRLFs/empty lines for safety?
836
          buf = buf[:2]
837
          continue
838

    
839
        if idx > 0:
840
          self.start_line_buffer = buf[:idx]
841

    
842
          self._CheckStartLineLength(len(self.start_line_buffer))
843

    
844
          # Remove status line, including CRLF
845
          buf = buf[idx + 2:]
846

    
847
          self.msg.start_line = self.ParseStartLine(self.start_line_buffer)
848

    
849
          self.parser_status = self.PS_HEADERS
850
        else:
851
          # Check whether incoming data is getting too large, otherwise we just
852
          # fill our read buffer.
853
          self._CheckStartLineLength(len(buf))
854

    
855
        break
856

    
857
    # TODO: Handle messages without headers
858
    if self.parser_status == self.PS_HEADERS:
859
      # Wait for header end
860
      idx = buf.find("\r\n\r\n")
861
      if idx >= 0:
862
        self.header_buffer.write(buf[:idx + 2])
863

    
864
        self._CheckHeaderLength(self.header_buffer.tell())
865

    
866
        # Remove headers, including CRLF
867
        buf = buf[idx + 4:]
868

    
869
        self._ParseHeaders()
870

    
871
        self.parser_status = self.PS_BODY
872
      else:
873
        # Check whether incoming data is getting too large, otherwise we just
874
        # fill our read buffer.
875
        self._CheckHeaderLength(len(buf))
876

    
877
    if self.parser_status == self.PS_BODY:
878
      # TODO: Implement max size for body_buffer
879
      self.body_buffer.write(buf)
880
      buf = ""
881

    
882
      # Check whether we've read everything
883
      #
884
      # RFC2616, section 4.4: "When a message-body is included with a message,
885
      # the transfer-length of that body is determined by one of the following
886
      # [...] 5. By the server closing the connection. (Closing the connection
887
      # cannot be used to indicate the end of a request body, since that would
888
      # leave no possibility for the server to send back a response.)"
889
      #
890
      # TODO: Error when buffer length > Content-Length header
891
      if (eof or
892
          self.content_length is None or
893
          (self.content_length is not None and
894
           self.body_buffer.tell() >= self.content_length)):
895
        self.parser_status = self.PS_COMPLETE
896

    
897
    return buf
898

    
899
  def _CheckStartLineLength(self, length):
900
    """Limits the start line buffer size.
901

902
    @type length: int
903
    @param length: Buffer size
904

905
    """
906
    if (self.START_LINE_LENGTH_MAX is not None and
907
        length > self.START_LINE_LENGTH_MAX):
908
      raise HttpError("Start line longer than %d chars" %
909
                       self.START_LINE_LENGTH_MAX)
910

    
911
  def _CheckHeaderLength(self, length):
912
    """Limits the header buffer size.
913

914
    @type length: int
915
    @param length: Buffer size
916

917
    """
918
    if (self.HEADER_LENGTH_MAX is not None and
919
        length > self.HEADER_LENGTH_MAX):
920
      raise HttpError("Headers longer than %d chars" % self.HEADER_LENGTH_MAX)
921

    
922
  def ParseStartLine(self, start_line):
923
    """Parses the start line of a message.
924

925
    Must be overriden by subclass.
926

927
    @type start_line: string
928
    @param start_line: Start line string
929

930
    """
931
    raise NotImplementedError()
932

    
933
  def _WillPeerCloseConnection(self):
934
    """Evaluate whether peer will close the connection.
935

936
    @rtype: bool
937
    @return: Whether peer will close the connection
938

939
    """
940
    # RFC2616, section 14.10: "HTTP/1.1 defines the "close" connection option
941
    # for the sender to signal that the connection will be closed after
942
    # completion of the response. For example,
943
    #
944
    #        Connection: close
945
    #
946
    # in either the request or the response header fields indicates that the
947
    # connection SHOULD NOT be considered `persistent' (section 8.1) after the
948
    # current request/response is complete."
949

    
950
    hdr_connection = self.msg.headers.get(HTTP_CONNECTION, None)
951
    if hdr_connection:
952
      hdr_connection = hdr_connection.lower()
953

    
954
    # An HTTP/1.1 server is assumed to stay open unless explicitly closed.
955
    if self.msg.start_line.version == HTTP_1_1:
956
      return (hdr_connection and "close" in hdr_connection)
957

    
958
    # Some HTTP/1.0 implementations have support for persistent connections,
959
    # using rules different than HTTP/1.1.
960

    
961
    # For older HTTP, Keep-Alive indicates persistent connection.
962
    if self.msg.headers.get(HTTP_KEEP_ALIVE):
963
      return False
964

    
965
    # At least Akamai returns a "Connection: Keep-Alive" header, which was
966
    # supposed to be sent by the client.
967
    if hdr_connection and "keep-alive" in hdr_connection:
968
      return False
969

    
970
    return True
971

    
972
  def _ParseHeaders(self):
973
    """Parses the headers.
974

975
    This function also adjusts internal variables based on header values.
976

977
    RFC2616, section 4.3: "The presence of a message-body in a request is
978
    signaled by the inclusion of a Content-Length or Transfer-Encoding header
979
    field in the request's message-headers."
980

981
    """
982
    # Parse headers
983
    self.header_buffer.seek(0, 0)
984
    self.msg.headers = mimetools.Message(self.header_buffer, 0)
985

    
986
    self.peer_will_close = self._WillPeerCloseConnection()
987

    
988
    # Do we have a Content-Length header?
989
    hdr_content_length = self.msg.headers.get(HTTP_CONTENT_LENGTH, None)
990
    if hdr_content_length:
991
      try:
992
        self.content_length = int(hdr_content_length)
993
      except ValueError:
994
        self.content_length = None
995
      if self.content_length is not None and self.content_length < 0:
996
        self.content_length = None
997

    
998
    # if the connection remains open and a content-length was not provided,
999
    # then assume that the connection WILL close.
1000
    if self.content_length is None:
1001
      self.peer_will_close = True