Permalink
Browse files

Better spec compliance for handling of response content length, esp. …

…for non-keepalive HTTP/1.0 responses with no content-length. And, don't enforce that hosts in HTTP requests match the IP or host used to make the connect, since e.g. proxies don't care.
  • Loading branch information...
1 parent fd540e0 commit e3687656c3cfd4b887cf9670609875dceccc0629 @sah sah committed Apr 11, 2012
Showing with 24 additions and 5 deletions.
  1. +24 −5 monocle/stack/network/http.py
@@ -1,6 +1,8 @@
import collections
from monocle import _o, Return
+from monocle.stack.network import ConnectionLost
+
class HttpHeaders(collections.MutableMapping):
def __init__(self, headers=None):
@@ -126,11 +128,15 @@ def read_response(conn):
data = yield conn.read_until("\r\n\r\n")
proto, code, msg, headers = parse_response(data)
+ proto = proto.lower()
content_length = int(headers.get('Content-Length', 0))
body = ""
- if content_length:
- body = yield conn.read(content_length)
- elif headers.get('Transfer-Encoding') == 'chunked':
+
+ # Messages MUST NOT include both a Content-Length header field and
+ # a non-identity transfer-coding. If the message does include a
+ # non- identity transfer-coding, the Content-Length MUST be
+ # ignored.
+ if headers.get('Transfer-Encoding', '').lower() == 'chunked':
while True:
line = yield conn.read_until("\r\n")
line = line[:-2]
@@ -140,6 +146,18 @@ def read_response(conn):
yield conn.read_until("\r\n")
if not chunk_len:
break
+ elif content_length:
+ body = yield conn.read(content_length)
+ elif ((proto == 'http/1.0' and
+ not headers.get('Connection', '').lower() == 'keep-alive')
+ or
+ (proto == 'http/1.1' and
+ headers.get('Connection', '').lower() == 'close')):
+ while True:
+ try:
+ body += yield conn.read_some()
+ except ConnectionLost:
+ break
yield Return(HttpResponse(code, msg, headers, body, proto))
@@ -182,8 +200,9 @@ def request(self, url, headers=None, method='GET', body=None):
if parts.query:
path += '?' + parts.query
- if not (scheme, host, port) == (self.scheme, self.host, self.port):
- raise HttpException("URL doesn't match connected server")
+ if scheme != self.scheme:
+ raise HttpException("URL is %s but connection is %s" %
+ (scheme, self.scheme))
if not headers:
headers = HttpHeaders()

0 comments on commit e368765

Please sign in to comment.