def format_flow(f, focus, extended=False, hostheader=False, cols=False, layout='default'): acked = False if f.reply and f.reply.state == "committed": acked = True d = dict( focus=focus, extended=extended, two_line=extended or cols < 100, cols=cols, intercepted=f.intercepted, acked=acked, req_timestamp=f.request.timestamp_start, req_is_replay=f.request.is_replay, req_method=f.request.method, req_promise='h2-pushed-stream' in f.metadata, req_url=f.request.pretty_url if hostheader else f.request.url, req_scheme=f.request.scheme, req_host=f.request.pretty_host if hostheader else f.request.host, req_path=f.request.path, req_http_version=f.request.http_version, err_msg=f.error.msg if f.error else None, marked=f.marked, ) if f.response: if f.response.raw_content: content_len = len(f.response.raw_content) contentdesc = human.pretty_size(len(f.response.raw_content)) elif f.response.raw_content is None: content_len = -1 contentdesc = "[content missing]" else: content_len = -2 contentdesc = "[no content]" duration = None if f.response.timestamp_end and f.request.timestamp_start: duration = max( [f.response.timestamp_end - f.request.timestamp_start, 0]) d.update( dict( resp_code=f.response.status_code, resp_reason=f.response.reason, resp_is_replay=f.response.is_replay, resp_len=content_len, resp_ctype=f.response.headers.get("content-type"), resp_clen=contentdesc, duration=duration, )) if ((layout == 'default' and cols < 100) or layout == "list"): return raw_format_list(tuple(sorted(d.items()))) else: return raw_format_table(tuple(sorted(d.items())))
def __repr__(self) -> str: if self.raw_content: ct = self.headers.get("content-type", "unknown content type") size = human.pretty_size(len(self.raw_content)) details = f"{ct}, {size}" else: details = "no content" return f"Response({self.status_code}, {details})"
def _echo_response_line(self, flow: http.HTTPFlow) -> None: if flow.is_replay == "response": replay_str = "[replay]" replay = self.style(replay_str, fg="yellow", bold=True) else: replay_str = "" replay = "" assert flow.response code_int = flow.response.status_code code_color = None if 200 <= code_int < 300: code_color = "green" elif 300 <= code_int < 400: code_color = "magenta" elif 400 <= code_int < 600: code_color = "red" code = self.style( str(code_int), fg=code_color, bold=True, blink=(code_int == 418), ) if not flow.response.is_http2: reason = flow.response.reason else: reason = http.status_codes.RESPONSES.get(flow.response.status_code, "") reason = self.style( strutils.escape_control_characters(reason), fg=code_color, bold=True ) if flow.response.raw_content is None: size = "(content missing)" else: size = human.pretty_size(len(flow.response.raw_content)) size = self.style(size, bold=True) http_version = "" if ( not (flow.response.is_http10 or flow.response.is_http11) or flow.request.http_version != flow.response.http_version ): # Hide version for h1 <-> h1 connections. http_version = f"{flow.response.http_version} " arrows = self.style(" <<", bold=True) if ctx.options.flow_detail == 1: # This aligns the HTTP response code with the HTTP request method: # 127.0.0.1:59519: GET http://example.com/ # << 304 Not Modified 0b pad = max(0, len(human.format_address(flow.client_conn.peername)) - (2 + len(http_version) + len(replay_str))) arrows = " " * pad + arrows self.echo(f"{replay}{arrows} {http_version}{code} {reason} {size}")
def __repr__(self): if self.raw_content: details = "{}, {}".format( self.headers.get("content-type", "unknown content type"), human.pretty_size(len(self.raw_content))) else: details = "no content" return "Response({status_code} {reason}, {details})".format( status_code=self.status_code, reason=self.reason, details=details)
def test_pretty_size(): assert human.pretty_size(0) == "0b" assert human.pretty_size(100) == "100b" assert human.pretty_size(1024) == "1.0k" assert human.pretty_size(1024 + 512) == "1.5k" assert human.pretty_size(1024 * 1024) == "1.0m" assert human.pretty_size(10 * 1024 * 1024) == "10.0m" assert human.pretty_size(100 * 1024 * 1024) == "100m"
def detail(self, flow): if flow.response.raw_content: details = "{}, {}".format( flow.response.headers.get("content-type", "unknown content type"), human.pretty_size(len(flow.response.raw_content))) else: details = "no content" return "Response({status_code} {reason}, {details})".format( status_code=flow.response.status_code, reason=flow.response.reason, details=details)
def test_pretty_size(): assert human.pretty_size(0) == "0b" assert human.pretty_size(100) == "100b" assert human.pretty_size(1024) == "1k" assert human.pretty_size(1024 + (1024 / 2.0)) == "1.5k" assert human.pretty_size(1024 * 1024) == "1m" assert human.pretty_size(10 * 1024 * 1024) == "10m"
def __repr__(self): if self.raw_content: details = "{}, {}".format( self.headers.get("content-type", "unknown content type"), human.pretty_size(len(self.raw_content)) ) else: details = "no content" return "Response({status_code} {reason}, {details})".format( status_code=self.status_code, reason=self.reason, details=details )
def format_flow(f, focus, extended=False, hostheader=False, max_url_len=False): acked = False if f.reply and f.reply.state == "committed": acked = True d = dict( focus=focus, extended=extended, max_url_len=max_url_len, intercepted = f.intercepted, acked = acked, req_timestamp = f.request.timestamp_start, req_is_replay = f.request.is_replay, req_method = f.request.method, req_url = f.request.pretty_url if hostheader else f.request.url, req_http_version = f.request.http_version, err_msg = f.error.msg if f.error else None, marked = f.marked, ) if f.response: if f.response.raw_content: contentdesc = human.pretty_size(len(f.response.raw_content)) elif f.response.raw_content is None: contentdesc = "[content missing]" else: contentdesc = "[no content]" duration = 0 if f.response.timestamp_end and f.request.timestamp_start: duration = f.response.timestamp_end - f.request.timestamp_start roundtrip = human.pretty_duration(duration) d.update(dict( resp_code = f.response.status_code, resp_reason = f.response.reason, resp_is_replay = f.response.is_replay, resp_clen = contentdesc, roundtrip = roundtrip, )) t = f.response.headers.get("content-type") if t: d["resp_ctype"] = t.split(";")[0] else: d["resp_ctype"] = "" return raw_format_flow(tuple(sorted(d.items())), f)
def __repr__(self): vals = [ "ws frame:", OPCODE.get_name(self.opcode, hex(self.opcode)).lower() ] flags = [] for i in ["fin", "rsv1", "rsv2", "rsv3", "mask"]: if getattr(self, i): flags.append(i) if flags: vals.extend([":", "|".join(flags)]) if self.masking_key: vals.append(":key=%s" % repr(self.masking_key)) if self.payload_length: vals.append(" %s" % human.pretty_size(self.payload_length)) return "".join(vals)
def _echo_response_line(self, flow): if flow.response.is_replay: replay = click.style("[replay] ", fg="yellow", bold=True) else: replay = "" code = flow.response.status_code code_color = None if 200 <= code < 300: code_color = "green" elif 300 <= code < 400: code_color = "magenta" elif 400 <= code < 600: code_color = "red" code = click.style( str(code), fg=code_color, bold=True, blink=(code == 418) ) reason = click.style( strutils.escape_control_characters(flow.response.reason), fg=code_color, bold=True ) if flow.response.raw_content is None: size = "(content missing)" else: size = human.pretty_size(len(flow.response.raw_content)) size = click.style(size, bold=True) arrows = click.style(" <<", bold=True) if self.flow_detail == 1: # This aligns the HTTP response code with the HTTP request method: # 127.0.0.1:59519: GET http://example.com/ # << 304 Not Modified 0b arrows = " " * (len(repr(flow.client_conn.address)) - 2) + arrows line = "{replay}{arrows} {code} {reason} {size}".format( replay=replay, arrows=arrows, code=code, reason=reason, size=size ) self.echo(line)
def get_status(self): r = [] sreplay = self.master.addons.get("serverplayback") creplay = self.master.addons.get("clientplayback") if len(self.master.options.setheaders): r.append("[") r.append(("heading_key", "H")) r.append("eaders]") if len(self.master.options.replacements): r.append("[") r.append(("heading_key", "R")) r.append("eplacing]") if creplay.count(): r.append("[") r.append(("heading_key", "cplayback")) r.append(":%s]" % creplay.count()) if sreplay.count(): r.append("[") r.append(("heading_key", "splayback")) r.append(":%s]" % sreplay.count()) if self.master.options.ignore_hosts: r.append("[") r.append(("heading_key", "I")) r.append("gnore:%d]" % len(self.master.options.ignore_hosts)) if self.master.options.tcp_hosts: r.append("[") r.append(("heading_key", "T")) r.append("CP:%d]" % len(self.master.options.tcp_hosts)) if self.master.options.intercept: r.append("[") r.append(("heading_key", "i")) r.append(":%s]" % self.master.options.intercept) if self.master.options.filter: r.append("[") r.append(("heading_key", "f")) r.append(":%s]" % self.master.options.filter) if self.master.options.stickycookie: r.append("[") r.append(("heading_key", "t")) r.append(":%s]" % self.master.options.stickycookie) if self.master.options.stickyauth: r.append("[") r.append(("heading_key", "u")) r.append(":%s]" % self.master.options.stickyauth) if self.master.options.default_contentview != "auto": r.append("[") r.append(("heading_key", "M")) r.append(":%s]" % self.master.options.default_contentview) if self.master.options.console_order: r.append("[") r.append(("heading_key", "o")) r.append(":%s]" % self.master.options.console_order) opts = [] if self.master.options.anticache: opts.append("anticache") if self.master.options.anticomp: opts.append("anticomp") if self.master.options.showhost: opts.append("showhost") if not self.master.options.refresh_server_playback: opts.append("norefresh") if self.master.options.replay_kill_extra: opts.append("killextra") if self.master.options.no_upstream_cert: opts.append("no-upstream-cert") if self.master.options.console_focus_follow: opts.append("following") if self.master.options.stream_large_bodies: opts.append( "stream:%s" % human.pretty_size(self.master.options.stream_large_bodies)) if opts: r.append("[%s]" % (":".join(opts))) if self.master.options.mode in ["reverse", "upstream"]: dst = self.master.server.config.upstream_server r.append("[dest:%s]" % mitmproxy.net.http.url.unparse( dst.scheme, dst.address.host, dst.address.port)) if self.master.options.scripts: r.append("[") r.append(("heading_key", "s")) r.append("cripts:%s]" % len(self.master.options.scripts)) if self.master.options.streamfile: r.append("[W:%s]" % self.master.options.streamfile) return r
def get_status(self): r = [] sreplay = self.master.addons.get("serverplayback") creplay = self.master.addons.get("clientplayback") if len(self.master.options.setheaders): r.append("[") r.append(("heading_key", "H")) r.append("eaders]") if len(self.master.options.replacements): r.append("[") r.append(("heading_key", "R")) r.append("eplacing]") if creplay.count(): r.append("[") r.append(("heading_key", "cplayback")) r.append(":%s]" % creplay.count()) if sreplay.count(): r.append("[") r.append(("heading_key", "splayback")) r.append(":%s]" % sreplay.count()) if self.master.options.ignore_hosts: r.append("[") r.append(("heading_key", "I")) r.append("gnore:%d]" % len(self.master.options.ignore_hosts)) if self.master.options.tcp_hosts: r.append("[") r.append(("heading_key", "T")) r.append("CP:%d]" % len(self.master.options.tcp_hosts)) if self.master.options.intercept: r.append("[") r.append(("heading_key", "i")) r.append(":%s]" % self.master.options.intercept) if self.master.options.filter: r.append("[") r.append(("heading_key", "f")) r.append(":%s]" % self.master.options.filter) if self.master.options.stickycookie: r.append("[") r.append(("heading_key", "t")) r.append(":%s]" % self.master.options.stickycookie) if self.master.options.stickyauth: r.append("[") r.append(("heading_key", "u")) r.append(":%s]" % self.master.options.stickyauth) if self.master.options.default_contentview != "auto": r.append("[") r.append(("heading_key", "M")) r.append(":%s]" % self.master.options.default_contentview) if self.master.options.order: r.append("[") r.append(("heading_key", "o")) r.append(":%s]" % self.master.options.order) opts = [] if self.master.options.anticache: opts.append("anticache") if self.master.options.anticomp: opts.append("anticomp") if self.master.options.showhost: opts.append("showhost") if not self.master.options.refresh_server_playback: opts.append("norefresh") if self.master.options.replay_kill_extra: opts.append("killextra") if self.master.options.no_upstream_cert: opts.append("no-upstream-cert") if self.master.options.focus_follow: opts.append("following") if self.master.options.stream_large_bodies: opts.append( "stream:%s" % human.pretty_size( self.master.options.stream_large_bodies ) ) if opts: r.append("[%s]" % (":".join(opts))) if self.master.options.mode in ["reverse", "upstream"]: dst = self.master.server.config.upstream_server r.append("[dest:%s]" % mitmproxy.net.http.url.unparse( dst.scheme, dst.address.host, dst.address.port )) if self.master.options.scripts: r.append("[") r.append(("heading_key", "s")) r.append("cripts:%s]" % len(self.master.options.scripts)) if self.master.options.streamfile: r.append("[W:%s]" % self.master.options.streamfile) return r
def format_size(num_bytes: int) -> typing.Tuple[str, str]: pretty_size = human.pretty_size(num_bytes) style = 'gradient_%02d' % int(99 - 100 * min(math.log2(1 + num_bytes) / 20, 0.99)) return pretty_size, style
def raw_format_table(f): f = dict(f) pile = [] req = [] cursor = [' ', 'focus'] if f['focus']: cursor[0] = '>' req.append(fcol(*cursor)) if f.get('resp_is_replay', False) or f.get('req_is_replay', False): req.append(fcol(SYMBOL_REPLAY, 'replay')) if f['marked']: req.append(fcol(SYMBOL_MARK, 'mark')) if f["two_line"]: req.append( TruncatedText(f["req_url"], colorize_url(f["req_url"]), 'left')) pile.append(urwid.Columns(req, dividechars=1)) req = [] req.append(fcol(' ', 'text')) if f["intercepted"] and not f["acked"]: uc = "intercept" elif "resp_code" in f or f["err_msg"] is not None: uc = "highlight" else: uc = "title" if f["extended"]: s = human.format_timestamp(f["req_timestamp"]) else: s = datetime.datetime.fromtimestamp( time.mktime(time.localtime( f["req_timestamp"]))).strftime("%H:%M:%S") req.append(fcol(s, uc)) methods = { 'GET': 'method_get', 'POST': 'method_post', 'DELETE': 'method_delete', 'HEAD': 'method_head', 'PUT': 'method_put' } uc = methods.get(f["req_method"], "method_other") if f['extended']: req.append(fcol(f["req_method"], uc)) if f["req_promise"]: req.append(fcol('PUSH_PROMISE', 'method_http2_push')) else: if f["req_promise"]: uc = 'method_http2_push' req.append(("fixed", 4, truncated_plain(f["req_method"], uc))) if f["two_line"]: req.append(fcol(f["req_http_version"], 'text')) else: schemes = { 'http': 'scheme_http', 'https': 'scheme_https', } req.append( fcol(fixlen(f["req_scheme"].upper(), 5), schemes.get(f["req_scheme"], "scheme_other"))) req.append(('weight', 0.25, TruncatedText(f["req_host"], colorize_host(f["req_host"]), 'right'))) req.append(('weight', 1.0, TruncatedText(f["req_path"], colorize_req(f["req_path"]), 'left'))) ret = (' ' * len(SYMBOL_RETURN), 'text') status = ('', 'text') content = ('', 'text') size = ('', 'text') duration = ('', 'text') if "resp_code" in f: codes = { 2: "code_200", 3: "code_300", 4: "code_400", 5: "code_500", } ccol = codes.get(f["resp_code"] // 100, "code_other") ret = (SYMBOL_RETURN, ccol) status = (str(f["resp_code"]), ccol) if f["resp_len"] < 0: if f["intercepted"] and f["resp_code"] and not f["acked"]: rc = "intercept" else: rc = "content_none" if f["resp_len"] == -1: contentdesc = "[content missing]" else: contentdesc = "[no content]" content = (contentdesc, rc) else: if f["resp_ctype"]: ctype = f["resp_ctype"].split(";")[0] if ctype.endswith('/javascript'): rc = 'content_script' elif ctype.startswith('text/'): rc = 'content_text' elif (ctype.startswith('image/') or ctype.startswith('video/') or ctype.startswith('font/') or "/x-font-" in ctype): rc = 'content_media' elif ctype.endswith('/json') or ctype.endswith('/xml'): rc = 'content_data' elif ctype.startswith('application/'): rc = 'content_raw' else: rc = 'content_other' content = (ctype, rc) rc = 'gradient_%02d' % int( 99 - 100 * min(math.log2(1 + f["resp_len"]) / 20, 0.99)) size_str = human.pretty_size(f["resp_len"]) if not f['extended']: # shorten to 5 chars max if len(size_str) > 5: size_str = size_str[0:4].rstrip('.') + size_str[-1:] size = (size_str, rc) if f['duration'] is not None: rc = 'gradient_%02d' % int( 99 - 100 * min(math.log2(1 + 1000 * f['duration']) / 12, 0.99)) duration = (human.pretty_duration(f['duration']), rc) elif f["err_msg"]: status = ('Err', 'error') content = f["err_msg"], 'error' if f["two_line"]: req.append(fcol(*ret)) req.append(fcol(fixlen(status[0], 3), status[1])) req.append(('weight', 0.15, truncated_plain(content[0], content[1], 'right'))) if f['extended']: req.append(fcol(*size)) else: req.append(fcol(fixlen_r(size[0], 5), size[1])) req.append(fcol(fixlen_r(duration[0], 5), duration[1])) pile.append(urwid.Columns(req, dividechars=1, min_width=15)) return urwid.Pile(pile)