This is a fork of:
https://github.com/roglew/puppy
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
197 lines
5.3 KiB
197 lines
5.3 KiB
import re |
|
import itertools |
|
|
|
from pygments import highlight |
|
from pygments.lexers.data import JsonLexer |
|
from pygments.lexers.html import XmlLexer |
|
from pygments.lexers import get_lexer_for_mimetype, HttpLexer |
|
from pygments.formatters import TerminalFormatter |
|
|
|
def clen(s): |
|
ansi_escape = re.compile(r'\x1b[^m]*m') |
|
return len(ansi_escape.sub('', s)) |
|
|
|
class Colors: |
|
HEADER = '\033[95m' |
|
OKBLUE = '\033[94m' |
|
OKGREEN = '\033[92m' |
|
WARNING = '\033[93m' |
|
FAIL = '\033[91m' |
|
# Effects |
|
ENDC = '\033[0m' |
|
BOLD = '\033[1m' |
|
UNDERLINE = '\033[4m' |
|
|
|
# Colors |
|
BLACK = '\033[30m' |
|
RED = '\033[31m' |
|
GREEN = '\033[32m' |
|
YELLOW = '\033[33m' |
|
BLUE = '\033[34m' |
|
MAGENTA = '\033[35m' |
|
CYAN = '\033[36m' |
|
WHITE = '\033[37m' |
|
|
|
# BG Colors |
|
BGBLACK = '\033[40m' |
|
BGRED = '\033[41m' |
|
BGGREEN = '\033[42m' |
|
BGYELLOW = '\033[43m' |
|
BGBLUE = '\033[44m' |
|
BGMAGENTA = '\033[45m' |
|
BGCYAN = '\033[46m' |
|
BGWHITE = '\033[47m' |
|
|
|
# Light Colors |
|
LBLACK = '\033[90m' |
|
LRED = '\033[91m' |
|
LGREEN = '\033[92m' |
|
LYELLOW = '\033[93m' |
|
LBLUE = '\033[94m' |
|
LMAGENTA = '\033[95m' |
|
LCYAN = '\033[96m' |
|
LWHITE = '\033[97m' |
|
|
|
class Styles: |
|
|
|
################ |
|
# Request tables |
|
TABLE_HEADER = Colors.BOLD+Colors.UNDERLINE |
|
VERB_GET = Colors.CYAN |
|
VERB_POST = Colors.YELLOW |
|
VERB_OTHER = Colors.BLUE |
|
STATUS_200 = Colors.CYAN |
|
STATUS_300 = Colors.MAGENTA |
|
STATUS_400 = Colors.YELLOW |
|
STATUS_500 = Colors.RED |
|
PATH_COLORS = [Colors.CYAN, Colors.BLUE] |
|
|
|
KV_KEY = Colors.GREEN |
|
KV_VAL = Colors.ENDC |
|
|
|
UNPRINTABLE_DATA = Colors.CYAN |
|
|
|
|
|
def verb_color(verb): |
|
if verb and verb == 'GET': |
|
return Styles.VERB_GET |
|
elif verb and verb == 'POST': |
|
return Styles.VERB_POST |
|
else: |
|
return Styles.VERB_OTHER |
|
|
|
def scode_color(scode): |
|
if scode and scode[0] == '2': |
|
return Styles.STATUS_200 |
|
elif scode and scode[0] == '3': |
|
return Styles.STATUS_300 |
|
elif scode and scode[0] == '4': |
|
return Styles.STATUS_400 |
|
elif scode and scode[0] == '5': |
|
return Styles.STATUS_500 |
|
else: |
|
return Colors.ENDC |
|
|
|
def path_formatter(path, width=-1): |
|
if len(path) > width and width != -1: |
|
path = path[:width] |
|
path = path[:-3]+'...' |
|
parts = path.split('/') |
|
colparts = [] |
|
for p, c in zip(parts, itertools.cycle(Styles.PATH_COLORS)): |
|
colparts.append(c+p+Colors.ENDC) |
|
return '/'.join(colparts) |
|
|
|
def color_string(s, color_only=False): |
|
""" |
|
Return the string with a a color/ENDC. The same string will always be the same color. |
|
""" |
|
from .util import str_hash_code |
|
# Give each unique host a different color (ish) |
|
if not s: |
|
return "" |
|
strcols = [Colors.RED, |
|
Colors.GREEN, |
|
Colors.YELLOW, |
|
Colors.BLUE, |
|
Colors.MAGENTA, |
|
Colors.CYAN, |
|
Colors.LRED, |
|
Colors.LGREEN, |
|
Colors.LYELLOW, |
|
Colors.LBLUE, |
|
Colors.LMAGENTA, |
|
Colors.LCYAN] |
|
col = strcols[str_hash_code(s)%(len(strcols)-1)] |
|
if color_only: |
|
return col |
|
else: |
|
return col + s + Colors.ENDC |
|
|
|
def pretty_msg(msg): |
|
to_ret = pretty_headers(msg) + '\r\n' + pretty_body(msg) |
|
return to_ret |
|
|
|
def pretty_headers(msg): |
|
to_ret = msg.headers_section() |
|
to_ret = highlight(to_ret, HttpLexer(), TerminalFormatter()) |
|
return to_ret |
|
|
|
def pretty_body(msg): |
|
from .util import printable_data |
|
to_ret = printable_data(msg.body, colors=False) |
|
if 'content-type' in msg.headers: |
|
try: |
|
lexer = get_lexer_for_mimetype(msg.headers.get('content-type').split(';')[0]) |
|
to_ret = highlight(to_ret, lexer, TerminalFormatter()) |
|
except: |
|
pass |
|
return to_ret |
|
|
|
def url_formatter(req, colored=False, always_have_path=False, explicit_path=False, explicit_port=False): |
|
retstr = '' |
|
|
|
if not req.use_tls: |
|
if colored: |
|
retstr += Colors.RED |
|
retstr += 'http' |
|
if colored: |
|
retstr += Colors.ENDC |
|
retstr += '://' |
|
else: |
|
retstr += 'https://' |
|
|
|
if colored: |
|
retstr += color_string(req.dest_host) |
|
else: |
|
retstr += req.dest_host |
|
if not ((req.use_tls and req.dest_port == 443) or \ |
|
(not req.use_tls and req.dest_port == 80) or \ |
|
explicit_port): |
|
if colored: |
|
retstr += ':' |
|
retstr += Colors.MAGENTA |
|
retstr += str(req.dest_port) |
|
retstr += Colors.ENDC |
|
else: |
|
retstr += ':{}'.format(req.dest_port) |
|
if (req.url.path and req.url.path != '/') or always_have_path: |
|
if colored: |
|
retstr += path_formatter(req.url.path) |
|
else: |
|
retstr += req.url.path |
|
if req.url.params: |
|
retstr += '?' |
|
params = req.url.params.split("&") |
|
pairs = [tuple(param.split("=")) for param in params] |
|
paramstrs = [] |
|
for k, v in pairs: |
|
if colored: |
|
paramstrs += (Colors.GREEN + '{}' + Colors.ENDC + '=' + Colors.LGREEN + '{}' + Colors.ENDC).format(k, v) |
|
else: |
|
paramstrs += '{}={}'.format(k, v) |
|
retstr += '&'.join(paramstrs) |
|
if req.url.fragment: |
|
retstr += '#%s' % req.url.fragment |
|
return retstr |
|
|
|
|