""" Hypertext Transfer Protocol. """ from pypacker import pypacker, triggerlist import re import logging logger = logging.getLogger("pypacker") class HTTPStartLine(triggerlist.TriggerList): def _pack(self): # logger.debug("packing HTTP-header") # no header = no CRNL if len(self) == 0: # logger.debug("empty buf 2") return b"" return b"".join(self) + b"\r\n" class HTTPHeader(triggerlist.TriggerList): def _pack(self): # logger.debug("packing HTTP-header") # no header = no CRNL if len(self) == 0: # logger.debug("empty buf 2") return b"" return b"\r\n".join([b": ".join(keyval) for keyval in self]) + b"\r\n\r\n" # REQ_METHODS_BASIC = set([b"GET", b"POST", b"HEAD", b"PUT", b"OPTIONS", b"CONNECT", b"UPDATE", b"TRACE"]) PROG_SPLIT_HEADBODY = re.compile(b"\r\n\r\n") PROG_SPLIT_HEADER = re.compile(b"\r\n") PROG_SPLIT_KEYVAL = re.compile(b": ") class HTTP(pypacker.Packet): __hdr__ = ( # content: ["startline"] ("startline", None, HTTPStartLine), # content: [("name", "value"), ...] ("hdr", None, HTTPHeader), ) def _dissect(self, buf): # requestline: [method] [uri] [version] eg GET / HTTP/1.1 # responseline: [version] [status] [reason] eg HTTP/1.1 200 OK # TODO: raises exception on reader try: bts_header, bts_body = PROG_SPLIT_HEADBODY.split(buf, 1) except ValueError: # assume this is part of a bigger (splittet) HTTP-message (no header) return len(buf) # logger.debug("head: %s" % bts_header) # logger.debug("body: %s" % bts_body) startline, bts_header = PROG_SPLIT_HEADER.split(bts_header, 1) # logger.debug("startline: %s" % startline) # logger.debug("bts_header: %s" % bts_header) self._init_triggerlist("startline", startline + b"\r\n", lambda bts: bts.strip()) self._init_triggerlist("hdr", bts_header + b"\r\n\r\n", self.__parse_header) # logger.debug(self.startline.bin()) # logger.debug(self.header.bin()) # logger.debug(len(startline+b"\r\n") + len(bts_header+b"\r\n\r\n")) # logger.debug("lengths head/body: %d %d" % (len(buf), len(bts_body))) # logger.debug(buf[:len(buf) - len(bts_body)]) # HEADER + "\r\n\r\n" + BODY -> newline is part of the header return len(buf) - len(bts_body) @staticmethod def __parse_header(buf): # logger.debug("parsing: %s" % buf) header = [] lines = PROG_SPLIT_HEADER.split(buf) for line in lines: # logger.debug("checking HTTP-header: %s" % line) if len(line) == 0: break key, val = PROG_SPLIT_KEYVAL.split(line, 1) header.append((key, val)) return header