Statistics
| Branch: | Tag: | Revision:

root / lib / http / __init__.py @ 39cfc25b

History | View | Annotate | Download (22.7 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) = range(3)
71

    
72
# send/receive quantum
73
SOCK_BUF_SIZE = 32768
74

    
75

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

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

81
  """
82

    
83

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

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

90
  """
91

    
92

    
93
class HttpSocketTimeout(Exception):
94
  """Internal exception for socket timeouts.
95

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

98
  """
99

    
100

    
101
class HttpException(Exception):
102
  code = None
103
  message = None
104

    
105
  def __init__(self, message=None):
106
    Exception.__init__(self)
107
    if message is not None:
108
      self.message = message
109

    
110

    
111
class HttpBadRequest(HttpException):
112
  code = 400
113

    
114

    
115
class HttpForbidden(HttpException):
116
  code = 403
117

    
118

    
119
class HttpNotFound(HttpException):
120
  code = 404
121

    
122

    
123
class HttpGone(HttpException):
124
  code = 410
125

    
126

    
127
class HttpLengthRequired(HttpException):
128
  code = 411
129

    
130

    
131
class HttpInternalError(HttpException):
132
  code = 500
133

    
134

    
135
class HttpNotImplemented(HttpException):
136
  code = 501
137

    
138

    
139
class HttpServiceUnavailable(HttpException):
140
  code = 503
141

    
142

    
143
class HttpVersionNotSupported(HttpException):
144
  code = 505
145

    
146

    
147
class HttpJsonConverter:
148
  CONTENT_TYPE = "application/json"
149

    
150
  def Encode(self, data):
151
    return serializer.DumpJson(data)
152

    
153
  def Decode(self, data):
154
    return serializer.LoadJson(data)
155

    
156

    
157
def WaitForSocketCondition(poller, sock, event, timeout):
158
  """Waits for a condition to occur on the socket.
159

160
  @type poller: select.Poller
161
  @param poller: Poller object as created by select.poll()
162
  @type sock: socket
163
  @param sock: Wait for events on this socket
164
  @type event: int
165
  @param event: ORed condition (see select module)
166
  @type timeout: float or None
167
  @param timeout: Timeout in seconds
168
  @rtype: int or None
169
  @return: None for timeout, otherwise occured conditions
170

171
  """
172
  check = (event | select.POLLPRI |
173
           select.POLLNVAL | select.POLLHUP | select.POLLERR)
174

    
175
  if timeout is not None:
176
    # Poller object expects milliseconds
177
    timeout *= 1000
178

    
179
  poller.register(sock, event)
180
  try:
181
    while True:
182
      # TODO: If the main thread receives a signal and we have no timeout, we
183
      # could wait forever. This should check a global "quit" flag or
184
      # something every so often.
185
      io_events = poller.poll(timeout)
186
      if not io_events:
187
        # Timeout
188
        return None
189
      for (evfd, evcond) in io_events:
190
        if evcond & check:
191
          return evcond
192
  finally:
193
    poller.unregister(sock)
194

    
195

    
196
def SocketOperation(poller, sock, op, arg1, timeout):
197
  """Wrapper around socket functions.
198

199
  This function abstracts error handling for socket operations, especially
200
  for the complicated interaction with OpenSSL.
201

202
  @type poller: select.Poller
203
  @param poller: Poller object as created by select.poll()
204
  @type sock: socket
205
  @param sock: Socket for the operation
206
  @type op: int
207
  @param op: Operation to execute (SOCKOP_* constants)
208
  @type arg1: any
209
  @param arg1: Parameter for function (if needed)
210
  @type timeout: None or float
211
  @param timeout: Timeout in seconds or None
212
  @return: Return value of socket function
213

214
  """
215
  # TODO: event_poll/event_check/override
216
  if op == SOCKOP_SEND:
217
    event_poll = select.POLLOUT
218
    event_check = select.POLLOUT
219

    
220
  elif op == SOCKOP_RECV:
221
    event_poll = select.POLLIN
222
    event_check = select.POLLIN | select.POLLPRI
223

    
224
  elif op == SOCKOP_SHUTDOWN:
225
    event_poll = None
226
    event_check = None
227

    
228
    # The timeout is only used when OpenSSL requests polling for a condition.
229
    # It is not advisable to have no timeout for shutdown.
230
    assert timeout
231

    
232
  else:
233
    raise AssertionError("Invalid socket operation")
234

    
235
  # No override by default
236
  event_override = 0
237

    
238
  while True:
239
    # Poll only for certain operations and when asked for by an override
240
    if event_override or op in (SOCKOP_SEND, SOCKOP_RECV):
241
      if event_override:
242
        wait_for_event = event_override
243
      else:
244
        wait_for_event = event_poll
245

    
246
      event = WaitForSocketCondition(poller, sock, wait_for_event, timeout)
247
      if event is None:
248
        raise HttpSocketTimeout()
249

    
250
      if (op == SOCKOP_RECV and
251
          event & (select.POLLNVAL | select.POLLHUP | select.POLLERR)):
252
        return ""
253

    
254
      if not event & wait_for_event:
255
        continue
256

    
257
    # Reset override
258
    event_override = 0
259

    
260
    try:
261
      try:
262
        if op == SOCKOP_SEND:
263
          return sock.send(arg1)
264

    
265
        elif op == SOCKOP_RECV:
266
          return sock.recv(arg1)
267

    
268
        elif op == SOCKOP_SHUTDOWN:
269
          if isinstance(sock, OpenSSL.SSL.ConnectionType):
270
            # PyOpenSSL's shutdown() doesn't take arguments
271
            return sock.shutdown()
272
          else:
273
            return sock.shutdown(arg1)
274

    
275
      except OpenSSL.SSL.WantWriteError:
276
        # OpenSSL wants to write, poll for POLLOUT
277
        event_override = select.POLLOUT
278
        continue
279

    
280
      except OpenSSL.SSL.WantReadError:
281
        # OpenSSL wants to read, poll for POLLIN
282
        event_override = select.POLLIN | select.POLLPRI
283
        continue
284

    
285
      except OpenSSL.SSL.WantX509LookupError:
286
        continue
287

    
288
      except OpenSSL.SSL.ZeroReturnError, err:
289
        # SSL Connection has been closed. In SSL 3.0 and TLS 1.0, this only
290
        # occurs if a closure alert has occurred in the protocol, i.e. the
291
        # connection has been closed cleanly. Note that this does not
292
        # necessarily mean that the transport layer (e.g. a socket) has been
293
        # closed.
294
        if op == SOCKOP_SEND:
295
          # Can happen during a renegotiation
296
          raise HttpConnectionClosed(err.args)
297
        elif op == SOCKOP_RECV:
298
          return ""
299

    
300
        # SSL_shutdown shouldn't return SSL_ERROR_ZERO_RETURN
301
        raise socket.error(err.args)
302

    
303
      except OpenSSL.SSL.SysCallError, err:
304
        if op == SOCKOP_SEND:
305
          # arg1 is the data when writing
306
          if err.args and err.args[0] == -1 and arg1 == "":
307
            # errors when writing empty strings are expected
308
            # and can be ignored
309
            return 0
310

    
311
        elif op == SOCKOP_RECV:
312
          if err.args == (-1, _SSL_UNEXPECTED_EOF):
313
            return ""
314

    
315
        raise socket.error(err.args)
316

    
317
      except OpenSSL.SSL.Error, err:
318
        raise socket.error(err.args)
319

    
320
    except socket.error, err:
321
      if err.args and err.args[0] == errno.EAGAIN:
322
        # Ignore EAGAIN
323
        continue
324

    
325
      raise
326

    
327

    
328
def ShutdownConnection(poller, sock, close_timeout, write_timeout, msgreader,
329
                       force):
330
  """Closes the connection.
331

332
  @type poller: select.Poller
333
  @param poller: Poller object as created by select.poll()
334
  @type sock: socket
335
  @param sock: Socket to be shut down
336
  @type close_timeout: float
337
  @param close_timeout: How long to wait for the peer to close the connection
338
  @type write_timeout: float
339
  @param write_timeout: Write timeout for shutdown
340
  @type msgreader: http.HttpMessageReader
341
  @param msgreader: Request message reader, used to determine whether peer
342
                    should close connection
343
  @type force: bool
344
  @param force: Whether to forcibly close the connection without waiting
345
                for peer
346

347
  """
348
  poller = select.poll()
349

    
350
  #print msgreader.peer_will_close, force
351
  if msgreader and msgreader.peer_will_close and not force:
352
    # Wait for peer to close
353
    try:
354
      # Check whether it's actually closed
355
      if not SocketOperation(poller, sock, SOCKOP_RECV, 1, close_timeout):
356
        return
357
    except (socket.error, HttpError, HttpSocketTimeout):
358
      # Ignore errors at this stage
359
      pass
360

    
361
  # Close the connection from our side
362
  try:
363
    # We don't care about the return value, see NOTES in SSL_shutdown(3).
364
    SocketOperation(poller, sock, SOCKOP_SHUTDOWN, socket.SHUT_RDWR,
365
                    write_timeout)
366
  except HttpSocketTimeout:
367
    raise HttpError("Timeout while shutting down connection")
368
  except socket.error, err:
369
    raise HttpError("Error while shutting down connection: %s" % err)
370

    
371

    
372
class HttpSslParams(object):
373
  """Data class for SSL key and certificate.
374

375
  """
376
  def __init__(self, ssl_key_path, ssl_cert_path):
377
    """Initializes this class.
378

379
    @type ssl_key_path: string
380
    @param ssl_key_path: Path to file containing SSL key in PEM format
381
    @type ssl_cert_path: string
382
    @param ssl_cert_path: Path to file containing SSL certificate in PEM format
383

384
    """
385
    self.ssl_key_pem = utils.ReadFile(ssl_key_path)
386
    self.ssl_cert_pem = utils.ReadFile(ssl_cert_path)
387

    
388
  def GetKey(self):
389
    return OpenSSL.crypto.load_privatekey(OpenSSL.crypto.FILETYPE_PEM,
390
                                          self.ssl_key_pem)
391

    
392
  def GetCertificate(self):
393
    return OpenSSL.crypto.load_certificate(OpenSSL.crypto.FILETYPE_PEM,
394
                                           self.ssl_cert_pem)
395

    
396

    
397
class HttpBase(object):
398
  """Base class for HTTP server and client.
399

400
  """
401
  def __init__(self):
402
    self.using_ssl = None
403
    self._ssl_params = None
404
    self._ssl_key = None
405
    self._ssl_cert = None
406

    
407
  def _CreateSocket(self, ssl_params, ssl_verify_peer):
408
    """Creates a TCP socket and initializes SSL if needed.
409

410
    @type ssl_params: HttpSslParams
411
    @param ssl_params: SSL key and certificate
412
    @type ssl_verify_peer: bool
413
    @param ssl_verify_peer: Whether to require client certificate and compare
414
                            it with our certificate
415

416
    """
417
    self._ssl_params = ssl_params
418

    
419
    sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
420

    
421
    # Should we enable SSL?
422
    self.using_ssl = ssl_params is not None
423

    
424
    if not self.using_ssl:
425
      return sock
426

    
427
    self._ssl_key = ssl_params.GetKey()
428
    self._ssl_cert = ssl_params.GetCertificate()
429

    
430
    ctx = OpenSSL.SSL.Context(OpenSSL.SSL.SSLv23_METHOD)
431
    ctx.set_options(OpenSSL.SSL.OP_NO_SSLv2)
432

    
433
    ctx.use_privatekey(self._ssl_key)
434
    ctx.use_certificate(self._ssl_cert)
435
    ctx.check_privatekey()
436

    
437
    if ssl_verify_peer:
438
      ctx.set_verify(OpenSSL.SSL.VERIFY_PEER |
439
                     OpenSSL.SSL.VERIFY_FAIL_IF_NO_PEER_CERT,
440
                     self._SSLVerifyCallback)
441

    
442
    return OpenSSL.SSL.Connection(ctx, sock)
443

    
444
  def _SSLVerifyCallback(self, conn, cert, errnum, errdepth, ok):
445
    """Verify the certificate provided by the peer
446

447
    We only compare fingerprints. The client must use the same certificate as
448
    we do on our side.
449

450
    """
451
    assert self._ssl_params, "SSL not initialized"
452

    
453
    return (self._ssl_cert.digest("sha1") == cert.digest("sha1") and
454
            self._ssl_cert.digest("md5") == cert.digest("md5"))
455

    
456

    
457
class HttpMessage(object):
458
  """Data structure for HTTP message.
459

460
  """
461
  def __init__(self):
462
    self.start_line = None
463
    self.headers = None
464
    self.body = None
465
    self.decoded_body = None
466

    
467

    
468
class HttpClientToServerStartLine(object):
469
  """Data structure for HTTP request start line.
470

471
  """
472
  def __init__(self, method, path, version):
473
    self.method = method
474
    self.path = path
475
    self.version = version
476

    
477
  def __str__(self):
478
    return "%s %s %s" % (self.method, self.path, self.version)
479

    
480

    
481
class HttpServerToClientStartLine(object):
482
  """Data structure for HTTP response start line.
483

484
  """
485
  def __init__(self, version, code, reason):
486
    self.version = version
487
    self.code = code
488
    self.reason = reason
489

    
490
  def __str__(self):
491
    return "%s %s %s" % (self.version, self.code, self.reason)
492

    
493

    
494
class HttpMessageWriter(object):
495
  """Writes an HTTP message to a socket.
496

497
  """
498
  def __init__(self, sock, msg, write_timeout):
499
    """Initializes this class and writes an HTTP message to a socket.
500

501
    @type sock: socket
502
    @param sock: Socket to be written to
503
    @type msg: http.HttpMessage
504
    @param msg: HTTP message to be written
505
    @type write_timeout: float
506
    @param write_timeout: Write timeout for socket
507

508
    """
509
    self._msg = msg
510

    
511
    self._PrepareMessage()
512

    
513
    buf = self._FormatMessage()
514

    
515
    poller = select.poll()
516

    
517
    pos = 0
518
    end = len(buf)
519
    while pos < end:
520
      # Send only SOCK_BUF_SIZE bytes at a time
521
      data = buf[pos:(pos + SOCK_BUF_SIZE)]
522

    
523
      sent = SocketOperation(poller, sock, SOCKOP_SEND, data,
524
                             write_timeout)
525

    
526
      # Remove sent bytes
527
      pos += sent
528

    
529
    assert pos == end, "Message wasn't sent completely"
530

    
531
  def _PrepareMessage(self):
532
    """Prepares the HTTP message by setting mandatory headers.
533

534
    """
535
    # RFC2616, section 4.3: "The presence of a message-body in a request is
536
    # signaled by the inclusion of a Content-Length or Transfer-Encoding header
537
    # field in the request's message-headers."
538
    if self._msg.body:
539
      self._msg.headers[HTTP_CONTENT_LENGTH] = len(self._msg.body)
540

    
541
  def _FormatMessage(self):
542
    """Serializes the HTTP message into a string.
543

544
    """
545
    buf = StringIO()
546

    
547
    # Add start line
548
    buf.write(str(self._msg.start_line))
549
    buf.write("\r\n")
550

    
551
    # Add headers
552
    if self._msg.start_line.version != HTTP_0_9:
553
      for name, value in self._msg.headers.iteritems():
554
        buf.write("%s: %s\r\n" % (name, value))
555

    
556
    buf.write("\r\n")
557

    
558
    # Add message body if needed
559
    if self.HasMessageBody():
560
      buf.write(self._msg.body)
561

    
562
    elif self._msg.body:
563
      logging.warning("Ignoring message body")
564

    
565
    return buf.getvalue()
566

    
567
  def HasMessageBody(self):
568
    """Checks whether the HTTP message contains a body.
569

570
    Can be overriden by subclasses.
571

572
    """
573
    return bool(self._msg.body)
574

    
575

    
576
class HttpMessageReader(object):
577
  """Reads HTTP message from socket.
578

579
  """
580
  # Length limits
581
  START_LINE_LENGTH_MAX = None
582
  HEADER_LENGTH_MAX = None
583

    
584
  # Parser state machine
585
  PS_START_LINE = "start-line"
586
  PS_HEADERS = "headers"
587
  PS_BODY = "entity-body"
588
  PS_COMPLETE = "complete"
589

    
590
  def __init__(self, sock, msg, read_timeout):
591
    """Reads an HTTP message from a socket.
592

593
    @type sock: socket
594
    @param sock: Socket to be read from
595
    @type msg: http.HttpMessage
596
    @param msg: Object for the read message
597
    @type read_timeout: float
598
    @param read_timeout: Read timeout for socket
599

600
    """
601
    self.sock = sock
602
    self.msg = msg
603

    
604
    self.poller = select.poll()
605
    self.start_line_buffer = None
606
    self.header_buffer = StringIO()
607
    self.body_buffer = StringIO()
608
    self.parser_status = self.PS_START_LINE
609
    self.content_length = None
610
    self.peer_will_close = None
611

    
612
    buf = ""
613
    eof = False
614
    while self.parser_status != self.PS_COMPLETE:
615
      data = SocketOperation(self.poller, sock, SOCKOP_RECV, SOCK_BUF_SIZE,
616
                             read_timeout)
617

    
618
      if data:
619
        buf += data
620
      else:
621
        eof = True
622

    
623
      # Do some parsing and error checking while more data arrives
624
      buf = self._ContinueParsing(buf, eof)
625

    
626
      # Must be done only after the buffer has been evaluated
627
      # TODO: Connection-length < len(data read) and connection closed
628
      if (eof and
629
          self.parser_status in (self.PS_START_LINE,
630
                                 self.PS_HEADERS)):
631
        raise HttpError("Connection closed prematurely")
632

    
633
    # Parse rest
634
    buf = self._ContinueParsing(buf, True)
635

    
636
    assert self.parser_status == self.PS_COMPLETE
637
    assert not buf, "Parser didn't read full response"
638

    
639
    msg.body = self.body_buffer.getvalue()
640

    
641
    # TODO: Content-type, error handling
642
    if msg.body:
643
      msg.decoded_body = HttpJsonConverter().Decode(msg.body)
644
    else:
645
      msg.decoded_body = None
646

    
647
    if msg.decoded_body:
648
      logging.debug("Message body: %s", msg.decoded_body)
649

    
650
  def _ContinueParsing(self, buf, eof):
651
    """Main function for HTTP message state machine.
652

653
    @type buf: string
654
    @param buf: Receive buffer
655
    @type eof: bool
656
    @param eof: Whether we've reached EOF on the socket
657
    @rtype: string
658
    @return: Updated receive buffer
659

660
    """
661
    if self.parser_status == self.PS_START_LINE:
662
      # Expect start line
663
      while True:
664
        idx = buf.find("\r\n")
665

    
666
        # RFC2616, section 4.1: "In the interest of robustness, servers SHOULD
667
        # ignore any empty line(s) received where a Request-Line is expected.
668
        # In other words, if the server is reading the protocol stream at the
669
        # beginning of a message and receives a CRLF first, it should ignore
670
        # the CRLF."
671
        if idx == 0:
672
          # TODO: Limit number of CRLFs/empty lines for safety?
673
          buf = buf[:2]
674
          continue
675

    
676
        if idx > 0:
677
          self.start_line_buffer = buf[:idx]
678

    
679
          self._CheckStartLineLength(len(self.start_line_buffer))
680

    
681
          # Remove status line, including CRLF
682
          buf = buf[idx + 2:]
683

    
684
          self.msg.start_line = self.ParseStartLine(self.start_line_buffer)
685

    
686
          self.parser_status = self.PS_HEADERS
687
        else:
688
          # Check whether incoming data is getting too large, otherwise we just
689
          # fill our read buffer.
690
          self._CheckStartLineLength(len(buf))
691

    
692
        break
693

    
694
    # TODO: Handle messages without headers
695
    if self.parser_status == self.PS_HEADERS:
696
      # Wait for header end
697
      idx = buf.find("\r\n\r\n")
698
      if idx >= 0:
699
        self.header_buffer.write(buf[:idx + 2])
700

    
701
        self._CheckHeaderLength(self.header_buffer.tell())
702

    
703
        # Remove headers, including CRLF
704
        buf = buf[idx + 4:]
705

    
706
        self._ParseHeaders()
707

    
708
        self.parser_status = self.PS_BODY
709
      else:
710
        # Check whether incoming data is getting too large, otherwise we just
711
        # fill our read buffer.
712
        self._CheckHeaderLength(len(buf))
713

    
714
    if self.parser_status == self.PS_BODY:
715
      # TODO: Implement max size for body_buffer
716
      self.body_buffer.write(buf)
717
      buf = ""
718

    
719
      # Check whether we've read everything
720
      #
721
      # RFC2616, section 4.4: "When a message-body is included with a message,
722
      # the transfer-length of that body is determined by one of the following
723
      # [...] 5. By the server closing the connection. (Closing the connection
724
      # cannot be used to indicate the end of a request body, since that would
725
      # leave no possibility for the server to send back a response.)"
726
      if (eof or
727
          self.content_length is None or
728
          (self.content_length is not None and
729
           self.body_buffer.tell() >= self.content_length)):
730
        self.parser_status = self.PS_COMPLETE
731

    
732
    return buf
733

    
734
  def _CheckStartLineLength(self, length):
735
    """Limits the start line buffer size.
736

737
    @type length: int
738
    @param length: Buffer size
739

740
    """
741
    if (self.START_LINE_LENGTH_MAX is not None and
742
        length > self.START_LINE_LENGTH_MAX):
743
      raise HttpError("Start line longer than %d chars" %
744
                       self.START_LINE_LENGTH_MAX)
745

    
746
  def _CheckHeaderLength(self, length):
747
    """Limits the header buffer size.
748

749
    @type length: int
750
    @param length: Buffer size
751

752
    """
753
    if (self.HEADER_LENGTH_MAX is not None and
754
        length > self.HEADER_LENGTH_MAX):
755
      raise HttpError("Headers longer than %d chars" % self.HEADER_LENGTH_MAX)
756

    
757
  def ParseStartLine(self, start_line):
758
    """Parses the start line of a message.
759

760
    Must be overriden by subclass.
761

762
    @type start_line: string
763
    @param start_line: Start line string
764

765
    """
766
    raise NotImplementedError()
767

    
768
  def _WillPeerCloseConnection(self):
769
    """Evaluate whether peer will close the connection.
770

771
    @rtype: bool
772
    @return: Whether peer will close the connection
773

774
    """
775
    # RFC2616, section 14.10: "HTTP/1.1 defines the "close" connection option
776
    # for the sender to signal that the connection will be closed after
777
    # completion of the response. For example,
778
    #
779
    #        Connection: close
780
    #
781
    # in either the request or the response header fields indicates that the
782
    # connection SHOULD NOT be considered `persistent' (section 8.1) after the
783
    # current request/response is complete."
784

    
785
    hdr_connection = self.msg.headers.get(HTTP_CONNECTION, None)
786
    if hdr_connection:
787
      hdr_connection = hdr_connection.lower()
788

    
789
    # An HTTP/1.1 server is assumed to stay open unless explicitly closed.
790
    if self.msg.start_line.version == HTTP_1_1:
791
      return (hdr_connection and "close" in hdr_connection)
792

    
793
    # Some HTTP/1.0 implementations have support for persistent connections,
794
    # using rules different than HTTP/1.1.
795

    
796
    # For older HTTP, Keep-Alive indicates persistent connection.
797
    if self.msg.headers.get(HTTP_KEEP_ALIVE):
798
      return False
799

    
800
    # At least Akamai returns a "Connection: Keep-Alive" header, which was
801
    # supposed to be sent by the client.
802
    if hdr_connection and "keep-alive" in hdr_connection:
803
      return False
804

    
805
    return True
806

    
807
  def _ParseHeaders(self):
808
    """Parses the headers.
809

810
    This function also adjusts internal variables based on header values.
811

812
    RFC2616, section 4.3: "The presence of a message-body in a request is
813
    signaled by the inclusion of a Content-Length or Transfer-Encoding header
814
    field in the request's message-headers."
815

816
    """
817
    # Parse headers
818
    self.header_buffer.seek(0, 0)
819
    self.msg.headers = mimetools.Message(self.header_buffer, 0)
820

    
821
    self.peer_will_close = self._WillPeerCloseConnection()
822

    
823
    # Do we have a Content-Length header?
824
    hdr_content_length = self.msg.headers.get(HTTP_CONTENT_LENGTH, None)
825
    if hdr_content_length:
826
      try:
827
        self.content_length = int(hdr_content_length)
828
      except ValueError:
829
        self.content_length = None
830
      if self.content_length is not None and self.content_length < 0:
831
        self.content_length = None
832

    
833
    # if the connection remains open and a content-length was not provided,
834
    # then assume that the connection WILL close.
835
    if self.content_length is None:
836
      self.peer_will_close = True