import time from mitmproxy.utils import strutils from mitmproxy.utils import human def write_raw(fp, lines, timestamp=True): if fp: if timestamp: fp.write(human.format_timestamp(time.time())) for i in lines: fp.write(i) fp.write("\n") fp.flush() class LogCtx: def __init__(self, fp, hex, timestamp, rfile, wfile): self.lines = [] self.fp = fp self.suppressed = False self.hex = hex self.timestamp = timestamp self.rfile, self.wfile = rfile, wfile def __enter__(self): if self.wfile: self.wfile.start_log() if self.rfile: self.rfile.start_log() return self def __exit__(self, exc_type, exc_value, traceback): wlog = self.wfile.get_log() if self.wfile else None rlog = self.rfile.get_log() if self.rfile else None if self.suppressed or not self.fp: return if wlog: self("Bytes written:") self.dump(wlog, self.hex) if rlog: self("Bytes read:") self.dump(rlog, self.hex) if self.lines: write_raw( self.fp, [ "\n".join(self.lines), ], timestamp = self.timestamp ) if exc_value: raise exc_value def suppress(self): self.suppressed = True def dump(self, data, hexdump): if hexdump: for line in strutils.hexdump(data): self("\t%s %s %s" % line) else: data = strutils.always_str( strutils.escape_control_characters( data .decode("ascii", "replace") .replace("\ufffd", ".") ) ) for i in data.split("\n"): self("\t%s" % i) def __call__(self, line): self.lines.append(line) class ConnectionLogger: def __init__(self, fp, hex, timestamp, rfile, wfile): self.fp = fp self.hex = hex self.rfile, self.wfile = rfile, wfile self.timestamp = timestamp def ctx(self): return LogCtx(self.fp, self.hex, self.timestamp, self.rfile, self.wfile) def write(self, lines): write_raw(self.fp, lines, timestamp=self.timestamp)