Statistics
| Branch: | Tag: | Revision:

root / lib / http / __init__.py @ d7fa9982

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

    
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
      data = SocketOperation(self.poller, sock, SOCKOP_RECV, SOCK_BUF_SIZE,
656
                             read_timeout)
657

    
658
      if data:
659
        buf += data
660
      else:
661
        eof = True
662

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

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

    
673
    # Parse rest
674
    buf = self._ContinueParsing(buf, True)
675

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

    
679
    msg.body = self.body_buffer.getvalue()
680

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

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

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

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

700
    """
701
    if self.parser_status == self.PS_START_LINE:
702
      # Expect start line
703
      while True:
704
        idx = buf.find("\r\n")
705

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

    
716
        if idx > 0:
717
          self.start_line_buffer = buf[:idx]
718

    
719
          self._CheckStartLineLength(len(self.start_line_buffer))
720

    
721
          # Remove status line, including CRLF
722
          buf = buf[idx + 2:]
723

    
724
          self.msg.start_line = self.ParseStartLine(self.start_line_buffer)
725

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

    
732
        break
733

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

    
741
        self._CheckHeaderLength(self.header_buffer.tell())
742

    
743
        # Remove headers, including CRLF
744
        buf = buf[idx + 4:]
745

    
746
        self._ParseHeaders()
747

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

    
754
    if self.parser_status == self.PS_BODY:
755
      # TODO: Implement max size for body_buffer
756
      self.body_buffer.write(buf)
757
      buf = ""
758

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

    
772
    return buf
773

    
774
  def _CheckStartLineLength(self, length):
775
    """Limits the start line buffer size.
776

777
    @type length: int
778
    @param length: Buffer size
779

780
    """
781
    if (self.START_LINE_LENGTH_MAX is not None and
782
        length > self.START_LINE_LENGTH_MAX):
783
      raise HttpError("Start line longer than %d chars" %
784
                       self.START_LINE_LENGTH_MAX)
785

    
786
  def _CheckHeaderLength(self, length):
787
    """Limits the header buffer size.
788

789
    @type length: int
790
    @param length: Buffer size
791

792
    """
793
    if (self.HEADER_LENGTH_MAX is not None and
794
        length > self.HEADER_LENGTH_MAX):
795
      raise HttpError("Headers longer than %d chars" % self.HEADER_LENGTH_MAX)
796

    
797
  def ParseStartLine(self, start_line):
798
    """Parses the start line of a message.
799

800
    Must be overriden by subclass.
801

802
    @type start_line: string
803
    @param start_line: Start line string
804

805
    """
806
    raise NotImplementedError()
807

    
808
  def _WillPeerCloseConnection(self):
809
    """Evaluate whether peer will close the connection.
810

811
    @rtype: bool
812
    @return: Whether peer will close the connection
813

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

    
825
    hdr_connection = self.msg.headers.get(HTTP_CONNECTION, None)
826
    if hdr_connection:
827
      hdr_connection = hdr_connection.lower()
828

    
829
    # An HTTP/1.1 server is assumed to stay open unless explicitly closed.
830
    if self.msg.start_line.version == HTTP_1_1:
831
      return (hdr_connection and "close" in hdr_connection)
832

    
833
    # Some HTTP/1.0 implementations have support for persistent connections,
834
    # using rules different than HTTP/1.1.
835

    
836
    # For older HTTP, Keep-Alive indicates persistent connection.
837
    if self.msg.headers.get(HTTP_KEEP_ALIVE):
838
      return False
839

    
840
    # At least Akamai returns a "Connection: Keep-Alive" header, which was
841
    # supposed to be sent by the client.
842
    if hdr_connection and "keep-alive" in hdr_connection:
843
      return False
844

    
845
    return True
846

    
847
  def _ParseHeaders(self):
848
    """Parses the headers.
849

850
    This function also adjusts internal variables based on header values.
851

852
    RFC2616, section 4.3: "The presence of a message-body in a request is
853
    signaled by the inclusion of a Content-Length or Transfer-Encoding header
854
    field in the request's message-headers."
855

856
    """
857
    # Parse headers
858
    self.header_buffer.seek(0, 0)
859
    self.msg.headers = mimetools.Message(self.header_buffer, 0)
860

    
861
    self.peer_will_close = self._WillPeerCloseConnection()
862

    
863
    # Do we have a Content-Length header?
864
    hdr_content_length = self.msg.headers.get(HTTP_CONTENT_LENGTH, None)
865
    if hdr_content_length:
866
      try:
867
        self.content_length = int(hdr_content_length)
868
      except ValueError:
869
        self.content_length = None
870
      if self.content_length is not None and self.content_length < 0:
871
        self.content_length = None
872

    
873
    # if the connection remains open and a content-length was not provided,
874
    # then assume that the connection WILL close.
875
    if self.content_length is None:
876
      self.peer_will_close = True