1919Note that this layer ISN'T loaded by default, as quite experimental for now.
2020
2121To follow HTTP packets streams = group packets together to get the
22- whole request/answer, use ``TCPSession`` as:
22+ whole request/answer, use ``TCPSession`` as::
2323
2424 >>> sniff(session=TCPSession) # Live on-the-flow session
2525 >>> sniff(offline="./http_chunk.pcap", session=TCPSession) # pcap
2828and will also decompress the packets when needed.
2929Note: on failure, decompression will be ignored.
3030
31- You can turn auto-decompression/auto-compression off with:
31+ You can turn auto-decompression/auto-compression off with::
3232
3333 >>> conf.contribs["http"]["auto_compression"] = False
3434
3535(Defaults to True)
3636"""
3737
38- # This file is a modified version of the former scapy_http plugin.
38+ # This file is a rewritten version of the former scapy_http plugin.
3939# It was reimplemented for scapy 2.4.3+ using sessions, stream handling.
4040# Original Authors : Steeve Barbeau, Luca Invernizzi
4141
6666except ImportError :
6767 _is_brotli_available = False
6868
69+ try :
70+ import lzw
71+ _is_lzw_available = True
72+ except ImportError :
73+ _is_lzw_available = False
74+
6975try :
7076 import zstandard
7177 _is_zstd_available = True
@@ -312,8 +318,13 @@ def post_dissect(self, s):
312318 elif "gzip" in encodings :
313319 s = gzip .decompress (s )
314320 elif "compress" in encodings :
315- import lzw
316- s = lzw .decompress (s )
321+ if _is_lzw_available :
322+ s = lzw .decompress (s )
323+ else :
324+ log_loading .info (
325+ "Can't import lzw. compress decompression "
326+ "will be ignored !"
327+ )
317328 elif "br" in encodings :
318329 if _is_brotli_available :
319330 s = brotli .decompress (s )
@@ -351,8 +362,13 @@ def post_build(self, pkt, pay):
351362 elif "gzip" in encodings :
352363 pay = gzip .compress (pay )
353364 elif "compress" in encodings :
354- import lzw
355- pay = lzw .compress (pay )
365+ if _is_lzw_available :
366+ pay = lzw .compress (pay )
367+ else :
368+ log_loading .info (
369+ "Can't import lzw. compress compression "
370+ "will be ignored !"
371+ )
356372 elif "br" in encodings :
357373 if _is_brotli_available :
358374 pay = brotli .compress (pay )
@@ -589,14 +605,22 @@ def dispatch_hook(cls, _pkt=None, *args, **kargs):
589605 def tcp_reassemble (cls , data , metadata , _ ):
590606 detect_end = metadata .get ("detect_end" , None )
591607 is_unknown = metadata .get ("detect_unknown" , True )
608+ # General idea of the following is explained at
609+ # https://datatracker.ietf.org/doc/html/rfc2616#section-4.4
592610 if not detect_end or is_unknown :
593611 metadata ["detect_unknown" ] = False
594612 http_packet = cls (data )
595613 # Detect packing method
596614 if not isinstance (http_packet .payload , _HTTPContent ):
597615 return http_packet
616+ is_response = isinstance (http_packet .payload , cls .clsresp )
617+ # Packets may have a Content-Length we must honnor
598618 length = http_packet .Content_Length
599- if length is not None :
619+ # Heuristic to try and detect instant HEAD responses, as those include a
620+ # Content-Length that must not be honored.
621+ if is_response and data .endswith (b"\r \n \r \n " ):
622+ detect_end = lambda _ : True
623+ elif length is not None :
600624 # The packet provides a Content-Length attribute: let's
601625 # use it. When the total size of the frags is high enough,
602626 # we have the packet
@@ -613,11 +637,10 @@ def tcp_reassemble(cls, data, metadata, _):
613637 # It's not Content-Length based. It could be chunked
614638 encodings = http_packet [cls ].payload ._get_encodings ()
615639 chunked = ("chunked" in encodings )
616- is_response = isinstance (http_packet .payload , cls .clsresp )
617640 if chunked :
618641 detect_end = lambda dat : dat .endswith (b"0\r \n \r \n " )
619642 # HTTP Requests that do not have any content,
620- # end with a double CRLF
643+ # end with a double CRLF. Same for HEAD responses
621644 elif isinstance (http_packet .payload , cls .clsreq ):
622645 detect_end = lambda dat : dat .endswith (b"\r \n \r \n " )
623646 # In case we are handling a HTTP Request,
0 commit comments