#!/usr/bin/env python import argparse, sys from libpathod import pathoc, version, language from netlib import tcp, http_uastrings if __name__ == "__main__": preparser = argparse.ArgumentParser(add_help=False) preparser.add_argument( "--show-uas", dest="showua", action="store_true", default=False, help="Print user agent shortcuts and exit." ) pa = preparser.parse_known_args()[0] if pa.showua: print "User agent strings:" for i in http_uastrings.UASTRINGS: print " ", i[1], i[0] sys.exit(0) parser = argparse.ArgumentParser(description='A perverse HTTP client.', parents=[preparser]) parser.add_argument('--version', action='version', version="pathoc " + version.VERSION) parser.add_argument( "-c", dest="connect_to", type=str, default=False, metavar = "HOST:PORT", help="Issue an HTTP CONNECT to connect to the specified host." ) parser.add_argument( "-n", dest='repeat', default=1, type=int, metavar="N", help='Repeat requests N times' ) parser.add_argument( "-p", dest="port", type=int, default=None, help="Port. Defaults to 80, or 443 if SSL is active" ) parser.add_argument( "-t", dest="timeout", type=int, default=None, help="Connection timeout" ) parser.add_argument( 'host', type=str, help='Host to connect to' ) parser.add_argument( 'request', type=str, nargs="+", help='Request specification' ) group = parser.add_argument_group( 'SSL', ) group.add_argument( "-s", dest="ssl", action="store_true", default=False, help="Connect with SSL" ) group.add_argument( "-C", dest="clientcert", type=str, default=False, help="Path to a file containing client certificate and private key" ) group.add_argument( "-i", dest="sni", type=str, default=False, help="SSL Server Name Indication" ) group.add_argument( "--sslversion", dest="sslversion", type=int, default=1, choices=[1, 2, 3], help="Use a specified protocol - TLSv1, SSLv2, SSLv3. Default to TLSv1." ) group = parser.add_argument_group( 'Controlling Output', """ Some of these options expand generated values for logging - if you're generating large data, use them with caution. """ ) group.add_argument( "-I", dest="ignorecodes", type=str, default="", help="Comma-separated list of response codes to ignore" ) group.add_argument( "-e", dest="explain", action="store_true", default=False, help="Explain requests" ) group.add_argument( "-o", dest="oneshot", action="store_true", default=False, help="Oneshot - exit after first non-ignored response" ) group.add_argument( "-q", dest="showreq", action="store_true", default=False, help="Print full request" ) group.add_argument( "-r", dest="showresp", action="store_true", default=False, help="Print full response" ) group.add_argument( "-T", dest="ignoretimeout", action="store_true", default=False, help="Ignore timeouts" ) group.add_argument( "-x", dest="hexdump", action="store_true", default=False, help="Output in hexdump format" ) args = parser.parse_args() if args.port is None: port = 443 if args.ssl else 80 else: port = args.port try: codes = [int(i) for i in args.ignorecodes.split(",") if i] except ValueError: parser.error("Invalid return code specification: %s"%args.ignorecodes) if args.connect_to: parts = args.connect_to.split(":") if len(parts) != 2: parser.error("Invalid CONNECT specification: %s"%args.connect_to) try: parts[1] = int(parts[1]) except ValueError: parser.error("Invalid CONNECT specification: %s"%args.connect_to) connect_to = parts else: connect_to = None try: for i in range(args.repeat): p = pathoc.Pathoc( (args.host, port), ssl=args.ssl, sni=args.sni, sslversion=args.sslversion, clientcert=args.clientcert ) try: p.connect(connect_to) except (tcp.NetLibError, pathoc.PathocError), v: print >> sys.stderr, str(v) sys.exit(1) if args.timeout: p.settimeout(args.timeout) for spec in args.request: ret = p.print_request( spec, showreq=args.showreq, showresp=args.showresp, explain=args.explain, hexdump=args.hexdump, ignorecodes=codes, ignoretimeout=args.ignoretimeout ) sys.stdout.flush() if ret and args.oneshot: sys.exit(0) except KeyboardInterrupt: pass