(cls, data, metadata, _)
| 650 | # tcp_reassemble is used by TCPSession in session.py |
| 651 | @classmethod |
| 652 | def tcp_reassemble(cls, data, metadata, _): |
| 653 | detect_end = metadata.get("detect_end", None) |
| 654 | is_unknown = metadata.get("detect_unknown", True) |
| 655 | # General idea of the following is explained at |
| 656 | # https://datatracker.ietf.org/doc/html/rfc2616#section-4.4 |
| 657 | if not detect_end or is_unknown: |
| 658 | metadata["detect_unknown"] = False |
| 659 | http_packet = cls(data) |
| 660 | # Detect packing method |
| 661 | if not isinstance(http_packet.payload, _HTTPContent): |
| 662 | return http_packet |
| 663 | is_response = isinstance(http_packet.payload, cls.clsresp) |
| 664 | # Packets may have a Content-Length we must honnor |
| 665 | length = http_packet.Content_Length |
| 666 | if length: |
| 667 | # Parse the length as an integer |
| 668 | try: |
| 669 | length = int(length) |
| 670 | except ValueError: |
| 671 | length = None |
| 672 | if length is not None: |
| 673 | # The packet provides a Content-Length attribute: let's |
| 674 | # use it. When the total size of the frags is high enough, |
| 675 | # we have the packet |
| 676 | |
| 677 | # Subtract the length of the "HTTP*" layer |
| 678 | if http_packet.payload.payload or length == 0: |
| 679 | http_length = len(data) - http_packet.payload._original_len |
| 680 | detect_end = lambda dat: len(dat) - http_length >= length |
| 681 | else: |
| 682 | # The HTTP layer isn't fully received. |
| 683 | if metadata.get("tcp_end", False): |
| 684 | # This was likely a HEAD response. Ugh |
| 685 | detect_end = lambda dat: True |
| 686 | else: |
| 687 | detect_end = lambda dat: False |
| 688 | metadata["detect_unknown"] = True |
| 689 | else: |
| 690 | # It's not Content-Length based. It could be chunked |
| 691 | encodings = http_packet[cls].payload._get_encodings() |
| 692 | chunked = "chunked" in encodings |
| 693 | if chunked: |
| 694 | detect_end = lambda dat: dat.endswith(b"0\r\n\r\n") |
| 695 | # HTTP Requests that do not have any content, |
| 696 | # end with a double CRLF. Same for HEAD responses |
| 697 | elif isinstance(http_packet.payload, cls.clsreq): |
| 698 | detect_end = lambda dat: dat.endswith(b"\r\n\r\n") |
| 699 | # In case we are handling a HTTP Request, |
| 700 | # we want to continue assessing the data, |
| 701 | # to handle requests with a body (POST) |
| 702 | metadata["detect_unknown"] = True |
| 703 | elif is_response and http_packet.Status_Code == b"101": |
| 704 | # If it's an upgrade response, it may also hold a |
| 705 | # different protocol data. |
| 706 | # make sure all headers are present |
| 707 | detect_end = lambda dat: dat.find(b"\r\n\r\n") |
| 708 | else: |
| 709 | # If neither Content-Length nor chunked is specified, |
nothing calls this directly
no test coverage detected