Statistics
| Branch: | Tag: | Revision:

root / lib / http / __init__.py @ b18dd019

History | View | Annotate | Download (20.8 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
class HttpError(Exception):
76
  """Internal exception for HTTP errors.
77

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

80
  """
81

    
82

    
83
class _HttpClientError(Exception):
84
  """Internal exception for HTTP client errors.
85

86
  This should only be used for internal error reporting.
87

88
  """
89

    
90

    
91
class HttpSocketTimeout(Exception):
92
  """Internal exception for socket timeouts.
93

94
  This should only be used for internal error reporting.
95

96
  """
97

    
98

    
99
class HttpException(Exception):
100
  code = None
101
  message = None
102

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

    
108

    
109
class HttpBadRequest(HttpException):
110
  code = 400
111

    
112

    
113
class HttpForbidden(HttpException):
114
  code = 403
115

    
116

    
117
class HttpNotFound(HttpException):
118
  code = 404
119

    
120

    
121
class HttpGone(HttpException):
122
  code = 410
123

    
124

    
125
class HttpLengthRequired(HttpException):
126
  code = 411
127

    
128

    
129
class HttpInternalError(HttpException):
130
  code = 500
131

    
132

    
133
class HttpNotImplemented(HttpException):
134
  code = 501
135

    
136

    
137
class HttpServiceUnavailable(HttpException):
138
  code = 503
139

    
140

    
141
class HttpVersionNotSupported(HttpException):
142
  code = 505
143

    
144

    
145
class HttpJsonConverter:
146
  CONTENT_TYPE = "application/json"
147

    
148
  def Encode(self, data):
149
    return serializer.DumpJson(data)
150

    
151
  def Decode(self, data):
152
    return serializer.LoadJson(data)
153

    
154

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

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

169
  """
170
  check = (event | select.POLLPRI |
171
           select.POLLNVAL | select.POLLHUP | select.POLLERR)
172

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

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

    
193

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

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

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

211
  """
212
  # TODO: event_poll/event_check/override
213
  if op == SOCKOP_SEND:
214
    event_poll = select.POLLOUT
215
    event_check = select.POLLOUT
216

    
217
  elif op == SOCKOP_RECV:
218
    event_poll = select.POLLIN
219
    event_check = select.POLLIN | select.POLLPRI
220

    
221
  elif op == SOCKOP_SHUTDOWN:
222
    event_poll = None
223
    event_check = None
224

    
225
    # The timeout is only used when OpenSSL requests polling for a condition.
226
    # It is not advisable to have no timeout for shutdown.
227
    assert timeout
228

    
229
  else:
230
    raise AssertionError("Invalid socket operation")
231

    
232
  # No override by default
233
  event_override = 0
234

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

    
243
      event = WaitForSocketCondition(poller, sock, wait_for_event, timeout)
244
      if event is None:
245
        raise HttpSocketTimeout()
246

    
247
      if (op == SOCKOP_RECV and
248
          event & (select.POLLNVAL | select.POLLHUP | select.POLLERR)):
249
        return ""
250

    
251
      if not event & wait_for_event:
252
        continue
253

    
254
    # Reset override
255
    event_override = 0
256

    
257
    try:
258
      try:
259
        if op == SOCKOP_SEND:
260
          return sock.send(arg1)
261

    
262
        elif op == SOCKOP_RECV:
263
          return sock.recv(arg1)
264

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

    
272
      except OpenSSL.SSL.WantWriteError:
273
        # OpenSSL wants to write, poll for POLLOUT
274
        event_override = select.POLLOUT
275
        continue
276

    
277
      except OpenSSL.SSL.WantReadError:
278
        # OpenSSL wants to read, poll for POLLIN
279
        event_override = select.POLLIN | select.POLLPRI
280
        continue
281

    
282
      except OpenSSL.SSL.WantX509LookupError:
283
        continue
284

    
285
      except OpenSSL.SSL.SysCallError, err:
286
        if op == SOCKOP_SEND:
287
          # arg1 is the data when writing
288
          if err.args and err.args[0] == -1 and arg1 == "":
289
            # errors when writing empty strings are expected
290
            # and can be ignored
291
            return 0
292

    
293
        elif op == SOCKOP_RECV:
294
          if err.args == (-1, _SSL_UNEXPECTED_EOF):
295
            return ""
296

    
297
        raise socket.error(err.args)
298

    
299
      except OpenSSL.SSL.Error, err:
300
        raise socket.error(err.args)
301

    
302
    except socket.error, err:
303
      if err.args and err.args[0] == errno.EAGAIN:
304
        # Ignore EAGAIN
305
        continue
306

    
307
      raise
308

    
309

    
310
def ShutdownConnection(poller, sock, close_timeout, write_timeout, msgreader,
311
                       force):
312
  """Closes the connection.
313

314
  """
315
  poller = select.poll()
316

    
317
  #print msgreader.peer_will_close, force
318
  if msgreader and msgreader.peer_will_close and not force:
319
    # Wait for peer to close
320
    try:
321
      # Check whether it's actually closed
322
      if not SocketOperation(poller, sock, SOCKOP_RECV, 1, close_timeout):
323
        return
324
    except (socket.error, HttpError, HttpSocketTimeout):
325
      # Ignore errors at this stage
326
      pass
327

    
328
  # Close the connection from our side
329
  try:
330
    SocketOperation(poller, sock, SOCKOP_SHUTDOWN, socket.SHUT_RDWR,
331
                    write_timeout)
332
  except HttpSocketTimeout:
333
    raise HttpError("Timeout while shutting down connection")
334
  except socket.error, err:
335
    raise HttpError("Error while shutting down connection: %s" % err)
336

    
337

    
338
class HttpSslParams(object):
339
  """Data class for SSL key and certificate.
340

341
  """
342
  def __init__(self, ssl_key_path, ssl_cert_path):
343
    """Initializes this class.
344

345
    @type ssl_key_path: string
346
    @param ssl_key_path: Path to file containing SSL key in PEM format
347
    @type ssl_cert_path: string
348
    @param ssl_cert_path: Path to file containing SSL certificate in PEM format
349

350
    """
351
    self.ssl_key_pem = utils.ReadFile(ssl_key_path)
352
    self.ssl_cert_pem = utils.ReadFile(ssl_cert_path)
353

    
354
  def GetKey(self):
355
    return OpenSSL.crypto.load_privatekey(OpenSSL.crypto.FILETYPE_PEM,
356
                                          self.ssl_key_pem)
357

    
358
  def GetCertificate(self):
359
    return OpenSSL.crypto.load_certificate(OpenSSL.crypto.FILETYPE_PEM,
360
                                           self.ssl_cert_pem)
361

    
362

    
363
class HttpSocketBase(object):
364
  """Base class for HTTP server and client.
365

366
  """
367
  def __init__(self):
368
    self._using_ssl = None
369
    self._ssl_params = None
370
    self._ssl_key = None
371
    self._ssl_cert = None
372

    
373
  def _CreateSocket(self, ssl_params, ssl_verify_peer):
374
    """Creates a TCP socket and initializes SSL if needed.
375

376
    @type ssl_params: HttpSslParams
377
    @param ssl_params: SSL key and certificate
378
    @type ssl_verify_peer: bool
379
    @param ssl_verify_peer: Whether to require client certificate and compare
380
                            it with our certificate
381

382
    """
383
    self._ssl_params = ssl_params
384

    
385
    sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
386

    
387
    # Should we enable SSL?
388
    self._using_ssl = ssl_params is not None
389

    
390
    if not self._using_ssl:
391
      return sock
392

    
393
    self._ssl_key = ssl_params.GetKey()
394
    self._ssl_cert = ssl_params.GetCertificate()
395

    
396
    ctx = OpenSSL.SSL.Context(OpenSSL.SSL.SSLv23_METHOD)
397
    ctx.set_options(OpenSSL.SSL.OP_NO_SSLv2)
398

    
399
    ctx.use_privatekey(self._ssl_key)
400
    ctx.use_certificate(self._ssl_cert)
401
    ctx.check_privatekey()
402

    
403
    if ssl_verify_peer:
404
      ctx.set_verify(OpenSSL.SSL.VERIFY_PEER |
405
                     OpenSSL.SSL.VERIFY_FAIL_IF_NO_PEER_CERT,
406
                     self._SSLVerifyCallback)
407

    
408
    return OpenSSL.SSL.Connection(ctx, sock)
409

    
410
  def _SSLVerifyCallback(self, conn, cert, errnum, errdepth, ok):
411
    """Verify the certificate provided by the peer
412

413
    We only compare fingerprints. The client must use the same certificate as
414
    we do on our side.
415

416
    """
417
    assert self._ssl_params, "SSL not initialized"
418

    
419
    return (self._ssl_cert.digest("sha1") == cert.digest("sha1") and
420
            self._ssl_cert.digest("md5") == cert.digest("md5"))
421

    
422

    
423
class HttpMessage(object):
424
  """Data structure for HTTP message.
425

426
  """
427
  def __init__(self):
428
    self.start_line = None
429
    self.headers = None
430
    self.body = None
431
    self.decoded_body = None
432

    
433

    
434
class HttpClientToServerStartLine(object):
435
  """Data structure for HTTP request start line.
436

437
  """
438
  def __init__(self, method, path, version):
439
    self.method = method
440
    self.path = path
441
    self.version = version
442

    
443
  def __str__(self):
444
    return "%s %s %s" % (self.method, self.path, self.version)
445

    
446

    
447
class HttpServerToClientStartLine(object):
448
  """Data structure for HTTP response start line.
449

450
  """
451
  def __init__(self, version, code, reason):
452
    self.version = version
453
    self.code = code
454
    self.reason = reason
455

    
456
  def __str__(self):
457
    return "%s %s %s" % (self.version, self.code, self.reason)
458

    
459

    
460
class HttpMessageWriter(object):
461
  """Writes an HTTP message to a socket.
462

463
  """
464
  def __init__(self, sock, msg, write_timeout):
465
    self._msg = msg
466

    
467
    self._PrepareMessage()
468

    
469
    buf = self._FormatMessage()
470

    
471
    poller = select.poll()
472

    
473
    pos = 0
474
    end = len(buf)
475
    while pos < end:
476
      # Send only SOCK_BUF_SIZE bytes at a time
477
      data = buf[pos:pos+SOCK_BUF_SIZE]
478

    
479
      sent = SocketOperation(poller, sock, SOCKOP_SEND, data,
480
                             write_timeout)
481

    
482
      # Remove sent bytes
483
      pos += sent
484

    
485
    assert pos == end, "Message wasn't sent completely"
486

    
487
  def _PrepareMessage(self):
488
    """Prepares the HTTP message by setting mandatory headers.
489

490
    """
491
    # RFC2616, section 4.3: "The presence of a message-body in a request is
492
    # signaled by the inclusion of a Content-Length or Transfer-Encoding header
493
    # field in the request's message-headers."
494
    if self._msg.body:
495
      self._msg.headers[HTTP_CONTENT_LENGTH] = len(self._msg.body)
496

    
497
  def _FormatMessage(self):
498
    """Serializes the HTTP message into a string.
499

500
    """
501
    buf = StringIO()
502

    
503
    # Add start line
504
    buf.write(str(self._msg.start_line))
505
    buf.write("\r\n")
506

    
507
    # Add headers
508
    if self._msg.start_line.version != HTTP_0_9:
509
      for name, value in self._msg.headers.iteritems():
510
        buf.write("%s: %s\r\n" % (name, value))
511

    
512
    buf.write("\r\n")
513

    
514
    # Add message body if needed
515
    if self.HasMessageBody():
516
      buf.write(self._msg.body)
517

    
518
    elif self._msg.body:
519
      logging.warning("Ignoring message body")
520

    
521
    return buf.getvalue()
522

    
523
  def HasMessageBody(self):
524
    """Checks whether the HTTP message contains a body.
525

526
    Can be overriden by subclasses.
527

528
    """
529
    return bool(self._msg.body)
530

    
531

    
532
class HttpMessageReader(object):
533
  """Reads HTTP message from socket.
534

535
  """
536
  # Length limits
537
  START_LINE_LENGTH_MAX = None
538
  HEADER_LENGTH_MAX = None
539

    
540
  # Parser state machine
541
  PS_START_LINE = "start-line"
542
  PS_HEADERS = "headers"
543
  PS_BODY = "entity-body"
544
  PS_COMPLETE = "complete"
545

    
546
  def __init__(self, sock, msg, read_timeout):
547
    self.sock = sock
548
    self.msg = msg
549

    
550
    self.poller = select.poll()
551
    self.start_line_buffer = None
552
    self.header_buffer = StringIO()
553
    self.body_buffer = StringIO()
554
    self.parser_status = self.PS_START_LINE
555
    self.content_length = None
556
    self.peer_will_close = None
557

    
558
    buf = ""
559
    eof = False
560
    while self.parser_status != self.PS_COMPLETE:
561
      data = SocketOperation(self.poller, sock, SOCKOP_RECV, SOCK_BUF_SIZE,
562
                             read_timeout)
563

    
564
      if data:
565
        buf += data
566
      else:
567
        eof = True
568

    
569
      # Do some parsing and error checking while more data arrives
570
      buf = self._ContinueParsing(buf, eof)
571

    
572
      # Must be done only after the buffer has been evaluated
573
      # TODO: Connection-length < len(data read) and connection closed
574
      if (eof and
575
          self.parser_status in (self.PS_START_LINE,
576
                                 self.PS_HEADERS)):
577
        raise HttpError("Connection closed prematurely")
578

    
579
    # Parse rest
580
    buf = self._ContinueParsing(buf, True)
581

    
582
    assert self.parser_status == self.PS_COMPLETE
583
    assert not buf, "Parser didn't read full response"
584

    
585
    msg.body = self.body_buffer.getvalue()
586

    
587
    # TODO: Content-type, error handling
588
    if msg.body:
589
      msg.decoded_body = HttpJsonConverter().Decode(msg.body)
590
    else:
591
      msg.decoded_body = None
592

    
593
    if msg.decoded_body:
594
      logging.debug("Message body: %s", msg.decoded_body)
595

    
596
  def _ContinueParsing(self, buf, eof):
597
    """Main function for HTTP message state machine.
598

599
    @type buf: string
600
    @param buf: Receive buffer
601
    @type eof: bool
602
    @param eof: Whether we've reached EOF on the socket
603
    @rtype: string
604
    @return: Updated receive buffer
605

606
    """
607
    if self.parser_status == self.PS_START_LINE:
608
      # Expect start line
609
      while True:
610
        idx = buf.find("\r\n")
611

    
612
        # RFC2616, section 4.1: "In the interest of robustness, servers SHOULD
613
        # ignore any empty line(s) received where a Request-Line is expected.
614
        # In other words, if the server is reading the protocol stream at the
615
        # beginning of a message and receives a CRLF first, it should ignore
616
        # the CRLF."
617
        if idx == 0:
618
          # TODO: Limit number of CRLFs for safety?
619
          buf = buf[:2]
620
          continue
621

    
622
        if idx > 0:
623
          self.start_line_buffer = buf[:idx]
624

    
625
          self._CheckStartLineLength(len(self.start_line_buffer))
626

    
627
          # Remove status line, including CRLF
628
          buf = buf[idx + 2:]
629

    
630
          self.msg.start_line = self.ParseStartLine(self.start_line_buffer)
631

    
632
          self.parser_status = self.PS_HEADERS
633
        else:
634
          # Check whether incoming data is getting too large, otherwise we just
635
          # fill our read buffer.
636
          self._CheckStartLineLength(len(buf))
637

    
638
        break
639

    
640
    # TODO: Handle messages without headers
641
    if self.parser_status == self.PS_HEADERS:
642
      # Wait for header end
643
      idx = buf.find("\r\n\r\n")
644
      if idx >= 0:
645
        self.header_buffer.write(buf[:idx + 2])
646

    
647
        self._CheckHeaderLength(self.header_buffer.tell())
648

    
649
        # Remove headers, including CRLF
650
        buf = buf[idx + 4:]
651

    
652
        self._ParseHeaders()
653

    
654
        self.parser_status = self.PS_BODY
655
      else:
656
        # Check whether incoming data is getting too large, otherwise we just
657
        # fill our read buffer.
658
        self._CheckHeaderLength(len(buf))
659

    
660
    if self.parser_status == self.PS_BODY:
661
      # TODO: Implement max size for body_buffer
662
      self.body_buffer.write(buf)
663
      buf = ""
664

    
665
      # Check whether we've read everything
666
      #
667
      # RFC2616, section 4.4: "When a message-body is included with a message,
668
      # the transfer-length of that body is determined by one of the following
669
      # [...] 5. By the server closing the connection. (Closing the connection
670
      # cannot be used to indicate the end of a request body, since that would
671
      # leave no possibility for the server to send back a response.)"
672
      if (eof or
673
          self.content_length is None or
674
          (self.content_length is not None and
675
           self.body_buffer.tell() >= self.content_length)):
676
        self.parser_status = self.PS_COMPLETE
677

    
678
    return buf
679

    
680
  def _CheckStartLineLength(self, length):
681
    """Limits the start line buffer size.
682

683
    @type length: int
684
    @param length: Buffer size
685

686
    """
687
    if (self.START_LINE_LENGTH_MAX is not None and
688
        length > self.START_LINE_LENGTH_MAX):
689
      raise HttpError("Start line longer than %d chars" %
690
                       self.START_LINE_LENGTH_MAX)
691

    
692
  def _CheckHeaderLength(self, length):
693
    """Limits the header buffer size.
694

695
    @type length: int
696
    @param length: Buffer size
697

698
    """
699
    if (self.HEADER_LENGTH_MAX is not None and
700
        length > self.HEADER_LENGTH_MAX):
701
      raise HttpError("Headers longer than %d chars" % self.HEADER_LENGTH_MAX)
702

    
703
  def ParseStartLine(self, start_line):
704
    """Parses the start line of a message.
705

706
    Must be overriden by subclass.
707

708
    @type start_line: string
709
    @param start_line: Start line string
710

711
    """
712
    raise NotImplementedError()
713

    
714
  def _WillPeerCloseConnection(self):
715
    """Evaluate whether peer will close the connection.
716

717
    @rtype: bool
718
    @return: Whether peer will close the connection
719

720
    """
721
    # RFC2616, section 14.10: "HTTP/1.1 defines the "close" connection option
722
    # for the sender to signal that the connection will be closed after
723
    # completion of the response. For example,
724
    #
725
    #        Connection: close
726
    #
727
    # in either the request or the response header fields indicates that the
728
    # connection SHOULD NOT be considered `persistent' (section 8.1) after the
729
    # current request/response is complete."
730

    
731
    hdr_connection = self.msg.headers.get(HTTP_CONNECTION, None)
732
    if hdr_connection:
733
      hdr_connection = hdr_connection.lower()
734

    
735
    # An HTTP/1.1 server is assumed to stay open unless explicitly closed.
736
    if self.msg.start_line.version == HTTP_1_1:
737
      return (hdr_connection and "close" in hdr_connection)
738

    
739
    # Some HTTP/1.0 implementations have support for persistent connections,
740
    # using rules different than HTTP/1.1.
741

    
742
    # For older HTTP, Keep-Alive indicates persistent connection.
743
    if self.msg.headers.get(HTTP_KEEP_ALIVE):
744
      return False
745

    
746
    # At least Akamai returns a "Connection: Keep-Alive" header, which was
747
    # supposed to be sent by the client.
748
    if hdr_connection and "keep-alive" in hdr_connection:
749
      return False
750

    
751
    return True
752

    
753
  def _ParseHeaders(self):
754
    """Parses the headers.
755

756
    This function also adjusts internal variables based on header values.
757

758
    RFC2616, section 4.3: "The presence of a message-body in a request is
759
    signaled by the inclusion of a Content-Length or Transfer-Encoding header
760
    field in the request's message-headers."
761

762
    """
763
    # Parse headers
764
    self.header_buffer.seek(0, 0)
765
    self.msg.headers = mimetools.Message(self.header_buffer, 0)
766

    
767
    self.peer_will_close = self._WillPeerCloseConnection()
768

    
769
    # Do we have a Content-Length header?
770
    hdr_content_length = self.msg.headers.get(HTTP_CONTENT_LENGTH, None)
771
    if hdr_content_length:
772
      try:
773
        self.content_length = int(hdr_content_length)
774
      except ValueError:
775
        self.content_length = None
776
      if self.content_length is not None and self.content_length < 0:
777
        self.content_length = None
778

    
779
    # if the connection remains open and a content-length was not provided,
780
    # then assume that the connection WILL close.
781
    if self.content_length is None:
782
      self.peer_will_close = True