#!/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 = 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, 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

