Statistics
| Branch: | Tag: | Revision:

root / lib / http / __init__.py @ f088165d

History | View | Annotate | Download (24.2 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

    
65
_SSL_UNEXPECTED_EOF = "Unexpected EOF"
66

    
67
# Socket operations
68
(SOCKOP_SEND,
69
 SOCKOP_RECV,
70
 SOCKOP_SHUTDOWN,
71
 SOCKOP_HANDSHAKE) = range(4)
72

    
73
# send/receive quantum
74
SOCK_BUF_SIZE = 32768
75

    
76

    
77
class HttpError(Exception):
78
  """Internal exception for HTTP errors.
79

80
  This should only be used for internal error reporting.
81

82
  """
83

    
84

    
85
class HttpConnectionClosed(Exception):
86
  """Internal exception for a closed connection.
87

88
  This should only be used for internal error reporting. Only use
89
  it if there's no other way to report this condition.
90

91
  """
92

    
93

    
94
class HttpSessionHandshakeUnexpectedEOF(HttpError):
95
  """Internal exception for errors during SSL handshake.
96

97
  This should only be used for internal error reporting.
98

99
  """
100

    
101

    
102
class HttpSocketTimeout(Exception):
103
  """Internal exception for socket timeouts.
104

105
  This should only be used for internal error reporting.
106

107
  """
108

    
109

    
110
class HttpException(Exception):
111
  code = None
112
  message = None
113

    
114
  def __init__(self, message=None):
115
    Exception.__init__(self)
116
    if message is not None:
117
      self.message = message
118

    
119

    
120
class HttpBadRequest(HttpException):
121
  code = 400
122

    
123

    
124
class HttpForbidden(HttpException):
125
  code = 403
126

    
127

    
128
class HttpNotFound(HttpException):
129
  code = 404
130

    
131

    
132
class HttpGone(HttpException):
133
  code = 410
134

    
135

    
136
class HttpLengthRequired(HttpException):
137
  code = 411
138

    
139

    
140
class HttpInternalError(HttpException):
141
  code = 500
142

    
143

    
144
class HttpNotImplemented(HttpException):
145
  code = 501
146

    
147

    
148
class HttpServiceUnavailable(HttpException):
149
  code = 503
150

    
151

    
152
class HttpVersionNotSupported(HttpException):
153
  code = 505
154

    
155

    
156
class HttpJsonConverter:
157
  CONTENT_TYPE = "application/json"
158

    
159
  def Encode(self, data):
160
    return serializer.DumpJson(data)
161

    
162
  def Decode(self, data):
163
    return serializer.LoadJson(data)
164

    
165

    
166
def WaitForSocketCondition(poller, sock, event, timeout):
167
  """Waits for a condition to occur on the socket.
168

169
  @type poller: select.Poller
170
  @param poller: Poller object as created by select.poll()
171
  @type sock: socket
172
  @param sock: Wait for events on this socket
173
  @type event: int
174
  @param event: ORed condition (see select module)
175
  @type timeout: float or None
176
  @param timeout: Timeout in seconds
177
  @rtype: int or None
178
  @return: None for timeout, otherwise occured conditions
179

180
  """
181
  check = (event | select.POLLPRI |
182
           select.POLLNVAL | select.POLLHUP | select.POLLERR)
183

    
184
  if timeout is not None:
185
    # Poller object expects milliseconds
186
    timeout *= 1000
187

    
188
  poller.register(sock, event)
189
  try:
190
    while True:
191
      # TODO: If the main thread receives a signal and we have no timeout, we
192
      # could wait forever. This should check a global "quit" flag or
193
      # something every so often.
194
      io_events = poller.poll(timeout)
195
      if not io_events:
196
        # Timeout
197
        return None
198
      for (evfd, evcond) in io_events:
199
        if evcond & check:
200
          return evcond
201
  finally:
202
    poller.unregister(sock)
203

    
204

    
205
def SocketOperation(poller, sock, op, arg1, timeout):
206
  """Wrapper around socket functions.
207

208
  This function abstracts error handling for socket operations, especially
209
  for the complicated interaction with OpenSSL.
210

211
  @type poller: select.Poller
212
  @param poller: Poller object as created by select.poll()
213
  @type sock: socket
214
  @param sock: Socket for the operation
215
  @type op: int
216
  @param op: Operation to execute (SOCKOP_* constants)
217
  @type arg1: any
218
  @param arg1: Parameter for function (if needed)
219
  @type timeout: None or float
220
  @param timeout: Timeout in seconds or None
221
  @return: Return value of socket function
222

223
  """
224
  # TODO: event_poll/event_check/override
225
  if op in (SOCKOP_SEND, SOCKOP_HANDSHAKE):
226
    event_poll = select.POLLOUT
227
    event_check = select.POLLOUT
228

    
229
  elif op == SOCKOP_RECV:
230
    event_poll = select.POLLIN
231
    event_check = select.POLLIN | select.POLLPRI
232

    
233
  elif op == SOCKOP_SHUTDOWN:
234
    event_poll = None
235
    event_check = None
236

    
237
    # The timeout is only used when OpenSSL requests polling for a condition.
238
    # It is not advisable to have no timeout for shutdown.
239
    assert timeout
240

    
241
  else:
242
    raise AssertionError("Invalid socket operation")
243

    
244
  # Handshake is only supported by SSL sockets
245
  if (op == SOCKOP_HANDSHAKE and
246
      not isinstance(sock, OpenSSL.SSL.ConnectionType)):
247
    return
248

    
249
  # No override by default
250
  event_override = 0
251

    
252
  while True:
253
    # Poll only for certain operations and when asked for by an override
254
    if event_override or op in (SOCKOP_SEND, SOCKOP_RECV, SOCKOP_HANDSHAKE):
255
      if event_override:
256
        wait_for_event = event_override
257
      else:
258
        wait_for_event = event_poll
259

    
260
      event = WaitForSocketCondition(poller, sock, wait_for_event, timeout)
261
      if event is None:
262
        raise HttpSocketTimeout()
263

    
264
      if (op == SOCKOP_RECV and
265
          event & (select.POLLNVAL | select.POLLHUP | select.POLLERR)):
266
        return ""
267

    
268
      if not event & wait_for_event:
269
        continue
270

    
271
    # Reset override
272
    event_override = 0
273

    
274
    try:
275
      try:
276
        if op == SOCKOP_SEND:
277
          return sock.send(arg1)
278

    
279
        elif op == SOCKOP_RECV:
280
          return sock.recv(arg1)
281

    
282
        elif op == SOCKOP_SHUTDOWN:
283
          if isinstance(sock, OpenSSL.SSL.ConnectionType):
284
            # PyOpenSSL's shutdown() doesn't take arguments
285
            return sock.shutdown()
286
          else:
287
            return sock.shutdown(arg1)
288

    
289
        elif op == SOCKOP_HANDSHAKE:
290
          return sock.do_handshake()
291

    
292
      except OpenSSL.SSL.WantWriteError:
293
        # OpenSSL wants to write, poll for POLLOUT
294
        event_override = select.POLLOUT
295
        continue
296

    
297
      except OpenSSL.SSL.WantReadError:
298
        # OpenSSL wants to read, poll for POLLIN
299
        event_override = select.POLLIN | select.POLLPRI
300
        continue
301

    
302
      except OpenSSL.SSL.WantX509LookupError:
303
        continue
304

    
305
      except OpenSSL.SSL.ZeroReturnError, err:
306
        # SSL Connection has been closed. In SSL 3.0 and TLS 1.0, this only
307
        # occurs if a closure alert has occurred in the protocol, i.e. the
308
        # connection has been closed cleanly. Note that this does not
309
        # necessarily mean that the transport layer (e.g. a socket) has been
310
        # closed.
311
        if op == SOCKOP_SEND:
312
          # Can happen during a renegotiation
313
          raise HttpConnectionClosed(err.args)
314
        elif op == SOCKOP_RECV:
315
          return ""
316

    
317
        # SSL_shutdown shouldn't return SSL_ERROR_ZERO_RETURN
318
        raise socket.error(err.args)
319

    
320
      except OpenSSL.SSL.SysCallError, err:
321
        if op == SOCKOP_SEND:
322
          # arg1 is the data when writing
323
          if err.args and err.args[0] == -1 and arg1 == "":
324
            # errors when writing empty strings are expected
325
            # and can be ignored
326
            return 0
327

    
328
        if err.args == (-1, _SSL_UNEXPECTED_EOF):
329
          if op == SOCKOP_RECV:
330
            return ""
331
          elif op == SOCKOP_HANDSHAKE:
332
            # Can happen if peer disconnects directly after the connection is
333
            # opened.
334
            raise HttpSessionHandshakeUnexpectedEOF(err.args)
335

    
336
        raise socket.error(err.args)
337

    
338
      except OpenSSL.SSL.Error, err:
339
        raise socket.error(err.args)
340

    
341
    except socket.error, err:
342
      if err.args and err.args[0] == errno.EAGAIN:
343
        # Ignore EAGAIN
344
        continue
345

    
346
      raise
347

    
348

    
349
def ShutdownConnection(poller, sock, close_timeout, write_timeout, msgreader,
350
                       force):
351
  """Closes the connection.
352

353
  @type poller: select.Poller
354
  @param poller: Poller object as created by select.poll()
355
  @type sock: socket
356
  @param sock: Socket to be shut down
357
  @type close_timeout: float
358
  @param close_timeout: How long to wait for the peer to close the connection
359
  @type write_timeout: float
360
  @param write_timeout: Write timeout for shutdown
361
  @type msgreader: http.HttpMessageReader
362
  @param msgreader: Request message reader, used to determine whether peer
363
                    should close connection
364
  @type force: bool
365
  @param force: Whether to forcibly close the connection without waiting
366
                for peer
367

368
  """
369
  poller = select.poll()
370

    
371
  #print msgreader.peer_will_close, force
372
  if msgreader and msgreader.peer_will_close and not force:
373
    # Wait for peer to close
374
    try:
375
      # Check whether it's actually closed
376
      if not SocketOperation(poller, sock, SOCKOP_RECV, 1, close_timeout):
377
        return
378
    except (socket.error, HttpError, HttpSocketTimeout):
379
      # Ignore errors at this stage
380
      pass
381

    
382
  # Close the connection from our side
383
  try:
384
    # We don't care about the return value, see NOTES in SSL_shutdown(3).
385
    SocketOperation(poller, sock, SOCKOP_SHUTDOWN, socket.SHUT_RDWR,
386
                    write_timeout)
387
  except HttpSocketTimeout:
388
    raise HttpError("Timeout while shutting down connection")
389
  except socket.error, err:
390
    raise HttpError("Error while shutting down connection: %s" % err)
391

    
392

    
393
def Handshake(poller, sock, write_timeout):
394
  """Shakes peer's hands.
395

396
  @type poller: select.Poller
397
  @param poller: Poller object as created by select.poll()
398
  @type sock: socket
399
  @param sock: Socket to be shut down
400
  @type write_timeout: float
401
  @param write_timeout: Write timeout for handshake
402

403
  """
404
  try:
405
    return SocketOperation(poller, sock, SOCKOP_HANDSHAKE, None, write_timeout)
406
  except HttpSocketTimeout:
407
    raise HttpError("Timeout during SSL handshake")
408
  except socket.error, err:
409
    raise HttpError("Error in SSL handshake: %s" % err)
410

    
411

    
412
class HttpSslParams(object):
413
  """Data class for SSL key and certificate.
414

415
  """
416
  def __init__(self, ssl_key_path, ssl_cert_path):
417
    """Initializes this class.
418

419
    @type ssl_key_path: string
420
    @param ssl_key_path: Path to file containing SSL key in PEM format
421
    @type ssl_cert_path: string
422
    @param ssl_cert_path: Path to file containing SSL certificate in PEM format
423

424
    """
425
    self.ssl_key_pem = utils.ReadFile(ssl_key_path)
426
    self.ssl_cert_pem = utils.ReadFile(ssl_cert_path)
427

    
428
  def GetKey(self):
429
    return OpenSSL.crypto.load_privatekey(OpenSSL.crypto.FILETYPE_PEM,
430
                                          self.ssl_key_pem)
431

    
432
  def GetCertificate(self):
433
    return OpenSSL.crypto.load_certificate(OpenSSL.crypto.FILETYPE_PEM,
434
                                           self.ssl_cert_pem)
435

    
436

    
437
class HttpBase(object):
438
  """Base class for HTTP server and client.
439

440
  """
441
  def __init__(self):
442
    self.using_ssl = None
443
    self._ssl_params = None
444
    self._ssl_key = None
445
    self._ssl_cert = None
446

    
447
  def _CreateSocket(self, ssl_params, ssl_verify_peer):
448
    """Creates a TCP socket and initializes SSL if needed.
449

450
    @type ssl_params: HttpSslParams
451
    @param ssl_params: SSL key and certificate
452
    @type ssl_verify_peer: bool
453
    @param ssl_verify_peer: Whether to require client certificate and compare
454
                            it with our certificate
455

456
    """
457
    self._ssl_params = ssl_params
458

    
459
    sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
460

    
461
    # Should we enable SSL?
462
    self.using_ssl = ssl_params is not None
463

    
464
    if not self.using_ssl:
465
      return sock
466

    
467
    self._ssl_key = ssl_params.GetKey()
468
    self._ssl_cert = ssl_params.GetCertificate()
469

    
470
    ctx = OpenSSL.SSL.Context(OpenSSL.SSL.SSLv23_METHOD)
471
    ctx.set_options(OpenSSL.SSL.OP_NO_SSLv2)
472

    
473
    ctx.use_privatekey(self._ssl_key)
474
    ctx.use_certificate(self._ssl_cert)
475
    ctx.check_privatekey()
476

    
477
    if ssl_verify_peer:
478
      ctx.set_verify(OpenSSL.SSL.VERIFY_PEER |
479
                     OpenSSL.SSL.VERIFY_FAIL_IF_NO_PEER_CERT,
480
                     self._SSLVerifyCallback)
481

    
482
    return OpenSSL.SSL.Connection(ctx, sock)
483

    
484
  def _SSLVerifyCallback(self, conn, cert, errnum, errdepth, ok):
485
    """Verify the certificate provided by the peer
486

487
    We only compare fingerprints. The client must use the same certificate as
488
    we do on our side.
489

490
    """
491
    assert self._ssl_params, "SSL not initialized"
492

    
493
    return (self._ssl_cert.digest("sha1") == cert.digest("sha1") and
494
            self._ssl_cert.digest("md5") == cert.digest("md5"))
495

    
496

    
497
class HttpMessage(object):
498
  """Data structure for HTTP message.
499

500
  """
501
  def __init__(self):
502
    self.start_line = None
503
    self.headers = None
504
    self.body = None
505
    self.decoded_body = None
506

    
507

    
508
class HttpClientToServerStartLine(object):
509
  """Data structure for HTTP request start line.
510

511
  """
512
  def __init__(self, method, path, version):
513
    self.method = method
514
    self.path = path
515
    self.version = version
516

    
517
  def __str__(self):
518
    return "%s %s %s" % (self.method, self.path, self.version)
519

    
520

    
521
class HttpServerToClientStartLine(object):
522
  """Data structure for HTTP response start line.
523

524
  """
525
  def __init__(self, version, code, reason):
526
    self.version = version
527
    self.code = code
528
    self.reason = reason
529

    
530
  def __str__(self):
531
    return "%s %s %s" % (self.version, self.code, self.reason)
532

    
533

    
534
class HttpMessageWriter(object):
535
  """Writes an HTTP message to a socket.
536

537
  """
538
  def __init__(self, sock, msg, write_timeout):
539
    """Initializes this class and writes an HTTP message to a socket.
540

541
    @type sock: socket
542
    @param sock: Socket to be written to
543
    @type msg: http.HttpMessage
544
    @param msg: HTTP message to be written
545
    @type write_timeout: float
546
    @param write_timeout: Write timeout for socket
547

548
    """
549
    self._msg = msg
550

    
551
    self._PrepareMessage()
552

    
553
    buf = self._FormatMessage()
554

    
555
    poller = select.poll()
556

    
557
    pos = 0
558
    end = len(buf)
559
    while pos < end:
560
      # Send only SOCK_BUF_SIZE bytes at a time
561
      data = buf[pos:(pos + SOCK_BUF_SIZE)]
562

    
563
      sent = SocketOperation(poller, sock, SOCKOP_SEND, data,
564
                             write_timeout)
565

    
566
      # Remove sent bytes
567
      pos += sent
568

    
569
    assert pos == end, "Message wasn't sent completely"
570

    
571
  def _PrepareMessage(self):
572
    """Prepares the HTTP message by setting mandatory headers.
573

574
    """
575
    # RFC2616, section 4.3: "The presence of a message-body in a request is
576
    # signaled by the inclusion of a Content-Length or Transfer-Encoding header
577
    # field in the request's message-headers."
578
    if self._msg.body:
579
      self._msg.headers[HTTP_CONTENT_LENGTH] = len(self._msg.body)
580

    
581
  def _FormatMessage(self):
582
    """Serializes the HTTP message into a string.
583

584
    """
585
    buf = StringIO()
586

    
587
    # Add start line
588
    buf.write(str(self._msg.start_line))
589
    buf.write("\r\n")
590

    
591
    # Add headers
592
    if self._msg.start_line.version != HTTP_0_9:
593
      for name, value in self._msg.headers.iteritems():
594
        buf.write("%s: %s\r\n" % (name, value))
595

    
596
    buf.write("\r\n")
597

    
598
    # Add message body if needed
599
    if self.HasMessageBody():
600
      buf.write(self._msg.body)
601

    
602
    elif self._msg.body:
603
      logging.warning("Ignoring message body")
604

    
605
    return buf.getvalue()
606

    
607
  def HasMessageBody(self):
608
    """Checks whether the HTTP message contains a body.
609

610
    Can be overriden by subclasses.
611

612
    """
613
    return bool(self._msg.body)
614

    
615

    
616
class HttpMessageReader(object):
617
  """Reads HTTP message from socket.
618

619
  """
620
  # Length limits
621
  START_LINE_LENGTH_MAX = None
622
  HEADER_LENGTH_MAX = None
623

    
624
  # Parser state machine
625
  PS_START_LINE = "start-line"
626
  PS_HEADERS = "headers"
627
  PS_BODY = "entity-body"
628
  PS_COMPLETE = "complete"
629

    
630
  def __init__(self, sock, msg, read_timeout):
631
    """Reads an HTTP message from a socket.
632

633
    @type sock: socket
634
    @param sock: Socket to be read from
635
    @type msg: http.HttpMessage
636
    @param msg: Object for the read message
637
    @type read_timeout: float
638
    @param read_timeout: Read timeout for socket
639

640
    """
641
    self.sock = sock
642
    self.msg = msg
643

    
644
    self.poller = select.poll()
645
    self.start_line_buffer = None
646
    self.header_buffer = StringIO()
647
    self.body_buffer = StringIO()
648
    self.parser_status = self.PS_START_LINE
649
    self.content_length = None
650
    self.peer_will_close = None
651

    
652
    buf = ""
653
    eof = False
654
    while self.parser_status != self.PS_COMPLETE:
655
      # TODO: Don't read more than necessary (Content-Length), otherwise
656
      # data might be lost and/or an error could occur
657
      data = SocketOperation(self.poller, sock, SOCKOP_RECV, SOCK_BUF_SIZE,
658
                             read_timeout)
659

    
660
      if data:
661
        buf += data
662
      else:
663
        eof = True
664

    
665
      # Do some parsing and error checking while more data arrives
666
      buf = self._ContinueParsing(buf, eof)
667

    
668
      # Must be done only after the buffer has been evaluated
669
      # TODO: Connection-length < len(data read) and connection closed
670
      if (eof and
671
          self.parser_status in (self.PS_START_LINE,
672
                                 self.PS_HEADERS)):
673
        raise HttpError("Connection closed prematurely")
674

    
675
    # Parse rest
676
    buf = self._ContinueParsing(buf, True)
677

    
678
    assert self.parser_status == self.PS_COMPLETE
679
    assert not buf, "Parser didn't read full response"
680

    
681
    msg.body = self.body_buffer.getvalue()
682

    
683
    # TODO: Content-type, error handling
684
    if msg.body:
685
      msg.decoded_body = HttpJsonConverter().Decode(msg.body)
686
    else:
687
      msg.decoded_body = None
688

    
689
    if msg.decoded_body:
690
      logging.debug("Message body: %s", msg.decoded_body)
691

    
692
  def _ContinueParsing(self, buf, eof):
693
    """Main function for HTTP message state machine.
694

695
    @type buf: string
696
    @param buf: Receive buffer
697
    @type eof: bool
698
    @param eof: Whether we've reached EOF on the socket
699
    @rtype: string
700
    @return: Updated receive buffer
701

702
    """
703
    # TODO: Use offset instead of slicing when possible
704
    if self.parser_status == self.PS_START_LINE:
705
      # Expect start line
706
      while True:
707
        idx = buf.find("\r\n")
708

    
709
        # RFC2616, section 4.1: "In the interest of robustness, servers SHOULD
710
        # ignore any empty line(s) received where a Request-Line is expected.
711
        # In other words, if the server is reading the protocol stream at the
712
        # beginning of a message and receives a CRLF first, it should ignore
713
        # the CRLF."
714
        if idx == 0:
715
          # TODO: Limit number of CRLFs/empty lines for safety?
716
          buf = buf[:2]
717
          continue
718

    
719
        if idx > 0:
720
          self.start_line_buffer = buf[:idx]
721

    
722
          self._CheckStartLineLength(len(self.start_line_buffer))
723

    
724
          # Remove status line, including CRLF
725
          buf = buf[idx + 2:]
726

    
727
          self.msg.start_line = self.ParseStartLine(self.start_line_buffer)
728

    
729
          self.parser_status = self.PS_HEADERS
730
        else:
731
          # Check whether incoming data is getting too large, otherwise we just
732
          # fill our read buffer.
733
          self._CheckStartLineLength(len(buf))
734

    
735
        break
736

    
737
    # TODO: Handle messages without headers
738
    if self.parser_status == self.PS_HEADERS:
739
      # Wait for header end
740
      idx = buf.find("\r\n\r\n")
741
      if idx >= 0:
742
        self.header_buffer.write(buf[:idx + 2])
743

    
744
        self._CheckHeaderLength(self.header_buffer.tell())
745

    
746
        # Remove headers, including CRLF
747
        buf = buf[idx + 4:]
748

    
749
        self._ParseHeaders()
750

    
751
        self.parser_status = self.PS_BODY
752
      else:
753
        # Check whether incoming data is getting too large, otherwise we just
754
        # fill our read buffer.
755
        self._CheckHeaderLength(len(buf))
756

    
757
    if self.parser_status == self.PS_BODY:
758
      # TODO: Implement max size for body_buffer
759
      self.body_buffer.write(buf)
760
      buf = ""
761

    
762
      # Check whether we've read everything
763
      #
764
      # RFC2616, section 4.4: "When a message-body is included with a message,
765
      # the transfer-length of that body is determined by one of the following
766
      # [...] 5. By the server closing the connection. (Closing the connection
767
      # cannot be used to indicate the end of a request body, since that would
768
      # leave no possibility for the server to send back a response.)"
769
      #
770
      # TODO: Error when buffer length > Content-Length header
771
      if (eof or
772
          self.content_length is None or
773
          (self.content_length is not None and
774
           self.body_buffer.tell() >= self.content_length)):
775
        self.parser_status = self.PS_COMPLETE
776

    
777
    return buf
778

    
779
  def _CheckStartLineLength(self, length):
780
    """Limits the start line buffer size.
781

782
    @type length: int
783
    @param length: Buffer size
784

785
    """
786
    if (self.START_LINE_LENGTH_MAX is not None and
787
        length > self.START_LINE_LENGTH_MAX):
788
      raise HttpError("Start line longer than %d chars" %
789
                       self.START_LINE_LENGTH_MAX)
790

    
791
  def _CheckHeaderLength(self, length):
792
    """Limits the header buffer size.
793

794
    @type length: int
795
    @param length: Buffer size
796

797
    """
798
    if (self.HEADER_LENGTH_MAX is not None and
799
        length > self.HEADER_LENGTH_MAX):
800
      raise HttpError("Headers longer than %d chars" % self.HEADER_LENGTH_MAX)
801

    
802
  def ParseStartLine(self, start_line):
803
    """Parses the start line of a message.
804

805
    Must be overriden by subclass.
806

807
    @type start_line: string
808
    @param start_line: Start line string
809

810
    """
811
    raise NotImplementedError()
812

    
813
  def _WillPeerCloseConnection(self):
814
    """Evaluate whether peer will close the connection.
815

816
    @rtype: bool
817
    @return: Whether peer will close the connection
818

819
    """
820
    # RFC2616, section 14.10: "HTTP/1.1 defines the "close" connection option
821
    # for the sender to signal that the connection will be closed after
822
    # completion of the response. For example,
823
    #
824
    #        Connection: close
825
    #
826
    # in either the request or the response header fields indicates that the
827
    # connection SHOULD NOT be considered `persistent' (section 8.1) after the
828
    # current request/response is complete."
829

    
830
    hdr_connection = self.msg.headers.get(HTTP_CONNECTION, None)
831
    if hdr_connection:
832
      hdr_connection = hdr_connection.lower()
833

    
834
    # An HTTP/1.1 server is assumed to stay open unless explicitly closed.
835
    if self.msg.start_line.version == HTTP_1_1:
836
      return (hdr_connection and "close" in hdr_connection)
837

    
838
    # Some HTTP/1.0 implementations have support for persistent connections,
839
    # using rules different than HTTP/1.1.
840

    
841
    # For older HTTP, Keep-Alive indicates persistent connection.
842
    if self.msg.headers.get(HTTP_KEEP_ALIVE):
843
      return False
844

    
845
    # At least Akamai returns a "Connection: Keep-Alive" header, which was
846
    # supposed to be sent by the client.
847
    if hdr_connection and "keep-alive" in hdr_connection:
848
      return False
849

    
850
    return True
851

    
852
  def _ParseHeaders(self):
853
    """Parses the headers.
854

855
    This function also adjusts internal variables based on header values.
856

857
    RFC2616, section 4.3: "The presence of a message-body in a request is
858
    signaled by the inclusion of a Content-Length or Transfer-Encoding header
859
    field in the request's message-headers."
860

861
    """
862
    # Parse headers
863
    self.header_buffer.seek(0, 0)
864
    self.msg.headers = mimetools.Message(self.header_buffer, 0)
865

    
866
    self.peer_will_close = self._WillPeerCloseConnection()
867

    
868
    # Do we have a Content-Length header?
869
    hdr_content_length = self.msg.headers.get(HTTP_CONTENT_LENGTH, None)
870
    if hdr_content_length:
871
      try:
872
        self.content_length = int(hdr_content_length)
873
      except ValueError:
874
        self.content_length = None
875
      if self.content_length is not None and self.content_length < 0:
876
        self.content_length = None
877

    
878
    # if the connection remains open and a content-length was not provided,
879
    # then assume that the connection WILL close.
880
    if self.content_length is None:
881
      self.peer_will_close = True