Permalink
Browse files

Be smarter about message body presence/absence

Be sure not to process bodies for 204 and 304 responses,
and don't bother handling pipelining for HTTP/1.0 without
a content-length. (Strictly, 1.0 should never pipeline, but
IIS at least does this, but it gives a content-length so
we handle it just fine). This fix results in more accurate
processing of out-of-order.pcap, so the test har was updated.
There's also a couple useful debugging classes in pcaputil.
  • Loading branch information...
1 parent 5f52a6b commit 41b99128626d843d6863b9cd961cc33983e590e0 Andrew Fleenor committed Jul 11, 2012
Showing with 51 additions and 10 deletions.
  1. +24 −6 dpkt_http_replacement.py
  2. +21 −0 pcaputil.py
  3. +6 −4 tests/out-of-order.pcap.har
View
@@ -13,8 +13,8 @@ def parse_headers(f):
d = {}
while 1:
line = f.readline()
- if not line:
- raise dpkt.NeedData('premature end of headers')
+ # regular dpkt checks for premature end of headers
+ # but that's too picky
line = line.strip()
if not line:
break
@@ -29,7 +29,7 @@ def parse_headers(f):
d[k] = v
return d
-def parse_body(f, headers):
+def parse_body(f, version, headers):
"""Return HTTP body parsed from a file object, given HTTP header dict."""
if headers.get('transfer-encoding', '').lower() == 'chunked':
l = []
@@ -59,7 +59,22 @@ def parse_body(f, headers):
raise dpkt.NeedData('short body (missing %d bytes)' % (n - len(body)))
else:
# XXX - need to handle HTTP/0.9
- body = ''
+ # BTW, this function is not called if status code is 204 or 304
+ if version == '1.0':
+ # we can assume that there are no further
+ # responses on this stream, since 1.0 doesn't
+ # support keepalive
+ body = f.read()
+ elif (version == '1.1' and
+ headers.get('connection', None) == 'close'):
+ # sender has said they won't send anything else.
+ body = f.read()
+ # there's also the case where other end sends connection: close,
+ # but we don't have the architecture to handle that.
+ else:
+ # we don't really know what to do
+ #print 'returning body as empty string:', version, headers
+ body = ''
return body
class Message(dpkt.Packet):
@@ -84,8 +99,11 @@ def unpack(self, buf):
f = cStringIO.StringIO(buf)
# Parse headers
self.headers = parse_headers(f)
- # Parse body
- self.body = parse_body(f, self.headers)
+ # Parse body, unless we know there isn't one
+ if not (getattr(self, 'status', None) in ('204', '304')):
+ self.body = parse_body(f, self.version, self.headers)
+ else:
+ self.body = ''
# Save the rest
self.data = f.read()
View
@@ -108,3 +108,24 @@ def __iter__(self):
hdr = self.__ph(buf)
buf = self.__f.read(hdr.caplen)
yield (hdr.tv_sec + (hdr.tv_usec / 1000000.0), buf, hdr)
+
+class FakeStream(object):
+ '''
+ Emulates a tcp.Direction with a predetermined data stream.
+
+ Useful for debugging http message classes.
+ '''
+ def __init__(self, data):
+ self.data = data
+ def byte_to_seq(self, n):
+ return n
+ def seq_final_arrival(self, n):
+ return None
+
+class FakeFlow(object):
+ '''
+ Emulates a tcp.Flow, with two FakeStream's.
+ '''
+ def __init__(self, fwd, rev):
+ self.fwd = fwd
+ self.rev = rev
Oops, something went wrong.

0 comments on commit 41b9912

Please sign in to comment.