pax_global_header00006660000000000000000000000064122600533130014505gustar00rootroot0000000000000052 comment=3e77a978ffb7bfb06022ae56f69f1048c8e45db9 python-netlib-0.9.2/000077500000000000000000000000001226005331300143115ustar00rootroot00000000000000python-netlib-0.9.2/.coveragerc000066400000000000000000000000641226005331300164320ustar00rootroot00000000000000[report] omit = *contrib* include = *netlib/netlib* python-netlib-0.9.2/.gitignore000066400000000000000000000001001226005331300162700ustar00rootroot00000000000000MANIFEST /build /dist /tmp /doc *.py[cdo] *.swp *.swo .coverage python-netlib-0.9.2/MANIFEST.in000066400000000000000000000001541226005331300160470ustar00rootroot00000000000000include README recursive-include test * recursive-include netlib * recursive-exclude test *.swo *.swp *.pyc python-netlib-0.9.2/README000066400000000000000000000005571226005331300152000ustar00rootroot00000000000000 Netlib is a collection of network utility classes, used by the pathod and mitmproxy projects. It differs from other projects in some fundamental respects, because both pathod and mitmproxy often need to violate standards. This means that protocols are implemented as small, well-contained and flexible functions, and are designed to allow misbehaviour when needed. python-netlib-0.9.2/netlib/000077500000000000000000000000001226005331300155665ustar00rootroot00000000000000python-netlib-0.9.2/netlib/__init__.py000066400000000000000000000000001226005331300176650ustar00rootroot00000000000000python-netlib-0.9.2/netlib/certutils.py000066400000000000000000000173551226005331300201710ustar00rootroot00000000000000import os, ssl, time, datetime, tempfile, shutil from pyasn1.type import univ, constraint, char, namedtype, tag from pyasn1.codec.der.decoder import decode from pyasn1.error import PyAsn1Error import OpenSSL import tcp def create_ca(): key = OpenSSL.crypto.PKey() key.generate_key(OpenSSL.crypto.TYPE_RSA, 1024) ca = OpenSSL.crypto.X509() ca.set_serial_number(int(time.time()*10000)) ca.set_version(2) ca.get_subject().CN = "mitmproxy" ca.get_subject().O = "mitmproxy" ca.gmtime_adj_notBefore(0) ca.gmtime_adj_notAfter(24 * 60 * 60 * 720) ca.set_issuer(ca.get_subject()) ca.set_pubkey(key) ca.add_extensions([ OpenSSL.crypto.X509Extension("basicConstraints", True, "CA:TRUE"), OpenSSL.crypto.X509Extension("nsCertType", True, "sslCA"), OpenSSL.crypto.X509Extension("extendedKeyUsage", True, "serverAuth,clientAuth,emailProtection,timeStamping,msCodeInd,msCodeCom,msCTLSign,msSGC,msEFS,nsSGC" ), OpenSSL.crypto.X509Extension("keyUsage", False, "keyCertSign, cRLSign"), OpenSSL.crypto.X509Extension("subjectKeyIdentifier", False, "hash", subject=ca), ]) ca.sign(key, "sha1") return key, ca def dummy_ca(path): dirname = os.path.dirname(path) if not os.path.exists(dirname): os.makedirs(dirname) if path.endswith(".pem"): basename, _ = os.path.splitext(path) basename = os.path.basename(basename) else: basename = os.path.basename(path) key, ca = create_ca() # Dump the CA plus private key f = open(path, "wb") f.write(OpenSSL.crypto.dump_privatekey(OpenSSL.crypto.FILETYPE_PEM, key)) f.write(OpenSSL.crypto.dump_certificate(OpenSSL.crypto.FILETYPE_PEM, ca)) f.close() # Dump the certificate in PEM format f = open(os.path.join(dirname, basename + "-cert.pem"), "wb") f.write(OpenSSL.crypto.dump_certificate(OpenSSL.crypto.FILETYPE_PEM, ca)) f.close() # Create a .cer file with the same contents for Android f = open(os.path.join(dirname, basename + "-cert.cer"), "wb") f.write(OpenSSL.crypto.dump_certificate(OpenSSL.crypto.FILETYPE_PEM, ca)) f.close() # Dump the certificate in PKCS12 format for Windows devices f = open(os.path.join(dirname, basename + "-cert.p12"), "wb") p12 = OpenSSL.crypto.PKCS12() p12.set_certificate(ca) p12.set_privatekey(key) f.write(p12.export()) f.close() return True def dummy_cert(ca, commonname, sans): """ Generates and writes a certificate to fp. ca: Path to the certificate authority file, or None. commonname: Common name for the generated certificate. sans: A list of Subject Alternate Names. Returns cert path if operation succeeded, None if not. """ ss = [] for i in sans: ss.append("DNS: %s"%i) ss = ", ".join(ss) raw = file(ca, "rb").read() ca = OpenSSL.crypto.load_certificate(OpenSSL.crypto.FILETYPE_PEM, raw) key = OpenSSL.crypto.load_privatekey(OpenSSL.crypto.FILETYPE_PEM, raw) req = OpenSSL.crypto.X509Req() subj = req.get_subject() subj.CN = commonname req.set_pubkey(ca.get_pubkey()) req.sign(key, "sha1") if ss: req.add_extensions([OpenSSL.crypto.X509Extension("subjectAltName", True, ss)]) cert = OpenSSL.crypto.X509() cert.gmtime_adj_notBefore(-3600) cert.gmtime_adj_notAfter(60 * 60 * 24 * 30) cert.set_issuer(ca.get_subject()) cert.set_subject(req.get_subject()) cert.set_serial_number(int(time.time()*10000)) if ss: cert.set_version(2) cert.add_extensions([OpenSSL.crypto.X509Extension("subjectAltName", True, ss)]) cert.set_pubkey(req.get_pubkey()) cert.sign(key, "sha1") return SSLCert(cert) class CertStore: """ Implements an in-memory certificate store. """ def __init__(self): self.certs = {} def check_domain(self, commonname): try: commonname.decode("idna") commonname.decode("ascii") except: return False if ".." in commonname: return False if "/" in commonname: return False return True def get_cert(self, commonname, sans, cacert): """ Returns an SSLCert object. commonname: Common name for the generated certificate. Must be a valid, plain-ASCII, IDNA-encoded domain name. sans: A list of Subject Alternate Names. cacert: The path to a CA certificate. Return None if the certificate could not be found or generated. """ if not self.check_domain(commonname): return None if commonname in self.certs: return self.certs[commonname] c = dummy_cert(cacert, commonname, sans) self.certs[commonname] = c return c class _GeneralName(univ.Choice): # We are only interested in dNSNames. We use a default handler to ignore # other types. componentType = namedtype.NamedTypes( namedtype.NamedType('dNSName', char.IA5String().subtype( implicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatSimple, 2) ) ), ) class _GeneralNames(univ.SequenceOf): componentType = _GeneralName() sizeSpec = univ.SequenceOf.sizeSpec + constraint.ValueSizeConstraint(1, 1024) class SSLCert: def __init__(self, cert): """ Returns a (common name, [subject alternative names]) tuple. """ self.x509 = cert @classmethod def from_pem(klass, txt): x509 = OpenSSL.crypto.load_certificate(OpenSSL.crypto.FILETYPE_PEM, txt) return klass(x509) @classmethod def from_der(klass, der): pem = ssl.DER_cert_to_PEM_cert(der) return klass.from_pem(pem) def to_pem(self): return OpenSSL.crypto.dump_certificate(OpenSSL.crypto.FILETYPE_PEM, self.x509) def digest(self, name): return self.x509.digest(name) @property def issuer(self): return self.x509.get_issuer().get_components() @property def notbefore(self): t = self.x509.get_notBefore() return datetime.datetime.strptime(t, "%Y%m%d%H%M%SZ") @property def notafter(self): t = self.x509.get_notAfter() return datetime.datetime.strptime(t, "%Y%m%d%H%M%SZ") @property def has_expired(self): return self.x509.has_expired() @property def subject(self): return self.x509.get_subject().get_components() @property def serial(self): return self.x509.get_serial_number() @property def keyinfo(self): pk = self.x509.get_pubkey() types = { OpenSSL.crypto.TYPE_RSA: "RSA", OpenSSL.crypto.TYPE_DSA: "DSA", } return ( types.get(pk.type(), "UNKNOWN"), pk.bits() ) @property def cn(self): c = None for i in self.subject: if i[0] == "CN": c = i[1] return c @property def altnames(self): altnames = [] for i in range(self.x509.get_extension_count()): ext = self.x509.get_extension(i) if ext.get_short_name() == "subjectAltName": try: dec = decode(ext.get_data(), asn1Spec=_GeneralNames()) except PyAsn1Error: continue for i in dec[0]: altnames.append(i[0].asOctets()) return altnames def get_remote_cert(host, port, sni): c = tcp.TCPClient(host, port) c.connect() c.convert_to_ssl(sni=sni) return c.cert python-netlib-0.9.2/netlib/contrib/000077500000000000000000000000001226005331300172265ustar00rootroot00000000000000python-netlib-0.9.2/netlib/contrib/__init__.py000066400000000000000000000000001226005331300213250ustar00rootroot00000000000000python-netlib-0.9.2/netlib/contrib/md5crypt.py000066400000000000000000000057631226005331300213620ustar00rootroot00000000000000# Based on FreeBSD src/lib/libcrypt/crypt.c 1.2 # http://www.freebsd.org/cgi/cvsweb.cgi/~checkout~/src/lib/libcrypt/crypt.c?rev=1.2&content-type=text/plain # Original license: # * "THE BEER-WARE LICENSE" (Revision 42): # * wrote this file. As long as you retain this notice you # * can do whatever you want with this stuff. If we meet some day, and you think # * this stuff is worth it, you can buy me a beer in return. Poul-Henning Kamp # This port adds no further stipulations. I forfeit any copyright interest. import md5 def md5crypt(password, salt, magic='$1$'): # /* The password first, since that is what is most unknown */ /* Then our magic string */ /* Then the raw salt */ m = md5.new() m.update(password + magic + salt) # /* Then just as many characters of the MD5(pw,salt,pw) */ mixin = md5.md5(password + salt + password).digest() for i in range(0, len(password)): m.update(mixin[i % 16]) # /* Then something really weird... */ # Also really broken, as far as I can tell. -m i = len(password) while i: if i & 1: m.update('\x00') else: m.update(password[0]) i >>= 1 final = m.digest() # /* and now, just to make sure things don't run too fast */ for i in range(1000): m2 = md5.md5() if i & 1: m2.update(password) else: m2.update(final) if i % 3: m2.update(salt) if i % 7: m2.update(password) if i & 1: m2.update(final) else: m2.update(password) final = m2.digest() # This is the bit that uses to64() in the original code. itoa64 = './0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz' rearranged = '' for a, b, c in ((0, 6, 12), (1, 7, 13), (2, 8, 14), (3, 9, 15), (4, 10, 5)): v = ord(final[a]) << 16 | ord(final[b]) << 8 | ord(final[c]) for i in range(4): rearranged += itoa64[v & 0x3f]; v >>= 6 v = ord(final[11]) for i in range(2): rearranged += itoa64[v & 0x3f]; v >>= 6 return magic + salt + '$' + rearranged if __name__ == '__main__': def test(clear_password, the_hash): magic, salt = the_hash[1:].split('$')[:2] magic = '$' + magic + '$' return md5crypt(clear_password, salt, magic) == the_hash test_cases = ( (' ', '$1$yiiZbNIH$YiCsHZjcTkYd31wkgW8JF.'), ('pass', '$1$YeNsbWdH$wvOF8JdqsoiLix754LTW90'), ('____fifteen____', '$1$s9lUWACI$Kk1jtIVVdmT01p0z3b/hw1'), ('____sixteen_____', '$1$dL3xbVZI$kkgqhCanLdxODGq14g/tW1'), ('____seventeen____', '$1$NaH5na7J$j7y8Iss0hcRbu3kzoJs5V.'), ('__________thirty-three___________', '$1$HO7Q6vzJ$yGwp2wbL5D7eOVzOmxpsy.'), ('apache', '$apr1$J.w5a/..$IW9y6DR0oO/ADuhlMF5/X1') ) for clearpw, hashpw in test_cases: if test(clearpw, hashpw): print '%s: pass' % clearpw else: print '%s: FAIL' % clearpw python-netlib-0.9.2/netlib/http.py000066400000000000000000000246201226005331300171230ustar00rootroot00000000000000import string, urlparse, binascii import odict, utils class HttpError(Exception): def __init__(self, code, msg): self.code, self.msg = code, msg def __str__(self): return "HttpError(%s, %s)"%(self.code, self.msg) class HttpErrorConnClosed(HttpError): pass def _is_valid_port(port): if not 0 <= port <= 65535: return False return True def _is_valid_host(host): try: host.decode("idna") except ValueError: return False if "\0" in host: return None return True def parse_url(url): """ Returns a (scheme, host, port, path) tuple, or None on error. Checks that: port is an integer 0-65535 host is a valid IDNA-encoded hostname with no null-bytes path is valid ASCII """ try: scheme, netloc, path, params, query, fragment = urlparse.urlparse(url) except ValueError: return None if not scheme: return None if ':' in netloc: host, port = string.rsplit(netloc, ':', maxsplit=1) try: port = int(port) except ValueError: return None else: host = netloc if scheme == "https": port = 443 else: port = 80 path = urlparse.urlunparse(('', '', path, params, query, fragment)) if not path.startswith("/"): path = "/" + path if not _is_valid_host(host): return None if not utils.isascii(path): return None if not _is_valid_port(port): return None return scheme, host, port, path def read_headers(fp): """ Read a set of headers from a file pointer. Stop once a blank line is reached. Return a ODictCaseless object, or None if headers are invalid. """ ret = [] name = '' while 1: line = fp.readline() if not line or line == '\r\n' or line == '\n': break if line[0] in ' \t': if not ret: return None # continued header ret[-1][1] = ret[-1][1] + '\r\n ' + line.strip() else: i = line.find(':') # We're being liberal in what we accept, here. if i > 0: name = line[:i] value = line[i+1:].strip() ret.append([name, value]) else: return None return odict.ODictCaseless(ret) def read_chunked(code, fp, limit): """ Read a chunked HTTP body. May raise HttpError. """ content = "" total = 0 while 1: line = fp.readline(128) if line == "": raise HttpErrorConnClosed(code, "Connection closed prematurely") if line != '\r\n' and line != '\n': try: length = int(line, 16) except ValueError: # FIXME: Not strictly correct - this could be from the server, in which # case we should send a 502. raise HttpError(code, "Invalid chunked encoding length: %s"%line) if not length: break total += length if limit is not None and total > limit: msg = "HTTP Body too large."\ " Limit is %s, chunked content length was at least %s"%(limit, total) raise HttpError(code, msg) content += fp.read(length) line = fp.readline(5) if line != '\r\n': raise HttpError(code, "Malformed chunked body") while 1: line = fp.readline() if line == "": raise HttpErrorConnClosed(code, "Connection closed prematurely") if line == '\r\n' or line == '\n': break return content def get_header_tokens(headers, key): """ Retrieve all tokens for a header key. A number of different headers follow a pattern where each header line can containe comma-separated tokens, and headers can be set multiple times. """ toks = [] for i in headers[key]: for j in i.split(","): toks.append(j.strip()) return toks def has_chunked_encoding(headers): return "chunked" in [i.lower() for i in get_header_tokens(headers, "transfer-encoding")] def read_http_body(code, rfile, headers, all, limit): """ Read an HTTP body: code: The HTTP error code to be used when raising HttpError rfile: A file descriptor to read from headers: An ODictCaseless object all: Should we read all data? limit: Size limit. """ if has_chunked_encoding(headers): content = read_chunked(code, rfile, limit) elif "content-length" in headers: try: l = int(headers["content-length"][0]) except ValueError: # FIXME: Not strictly correct - this could be from the server, in which # case we should send a 502. raise HttpError(code, "Invalid content-length header: %s"%headers["content-length"]) if limit is not None and l > limit: raise HttpError(code, "HTTP Body too large. Limit is %s, content-length was %s"%(limit, l)) content = rfile.read(l) elif all: content = rfile.read(limit if limit else -1) else: content = "" return content def parse_http_protocol(s): """ Parse an HTTP protocol declaration. Returns a (major, minor) tuple, or None. """ if not s.startswith("HTTP/"): return None _, version = s.split('/', 1) if "." not in version: return None major, minor = version.split('.', 1) try: major = int(major) minor = int(minor) except ValueError: return None return major, minor def parse_http_basic_auth(s): words = s.split() if len(words) != 2: return None scheme = words[0] try: user = binascii.a2b_base64(words[1]) except binascii.Error: return None parts = user.split(':') if len(parts) != 2: return None return scheme, parts[0], parts[1] def assemble_http_basic_auth(scheme, username, password): v = binascii.b2a_base64(username + ":" + password) return scheme + " " + v def parse_init(line): try: method, url, protocol = string.split(line) except ValueError: return None httpversion = parse_http_protocol(protocol) if not httpversion: return None if not utils.isascii(method): return None return method, url, httpversion def parse_init_connect(line): v = parse_init(line) if not v: return None method, url, httpversion = v if method.upper() != 'CONNECT': return None try: host, port = url.split(":") except ValueError: return None try: port = int(port) except ValueError: return None if not _is_valid_port(port): return None if not _is_valid_host(host): return None return host, port, httpversion def parse_init_proxy(line): v = parse_init(line) if not v: return None method, url, httpversion = v parts = parse_url(url) if not parts: return None scheme, host, port, path = parts return method, scheme, host, port, path, httpversion def parse_init_http(line): """ Returns (method, url, httpversion) """ v = parse_init(line) if not v: return None method, url, httpversion = v if not utils.isascii(url): return None if not (url.startswith("/") or url == "*"): return None return method, url, httpversion def request_connection_close(httpversion, headers): """ Checks the request to see if the client connection should be closed. """ if "connection" in headers: toks = get_header_tokens(headers, "connection") if "close" in toks: return True elif "keep-alive" in toks: return False # HTTP 1.1 connections are assumed to be persistent if httpversion == (1, 1): return False return True def response_connection_close(httpversion, headers): """ Checks the response to see if the client connection should be closed. """ if request_connection_close(httpversion, headers): return True elif (not has_chunked_encoding(headers)) and "content-length" in headers: return False return True def read_http_body_request(rfile, wfile, headers, httpversion, limit): """ Read the HTTP body from a client request. """ if "expect" in headers: # FIXME: Should be forwarded upstream if "100-continue" in headers['expect'] and httpversion >= (1, 1): wfile.write('HTTP/1.1 100 Continue\r\n') wfile.write('\r\n') del headers['expect'] return read_http_body(400, rfile, headers, False, limit) def read_http_body_response(rfile, headers, limit): """ Read the HTTP body from a server response. """ all = "close" in get_header_tokens(headers, "connection") return read_http_body(500, rfile, headers, all, limit) def parse_response_line(line): parts = line.strip().split(" ", 2) if len(parts) == 2: # handle missing message gracefully parts.append("") if len(parts) != 3: return None proto, code, msg = parts try: code = int(code) except ValueError: return None return (proto, code, msg) def read_response(rfile, method, body_size_limit): """ Return an (httpversion, code, msg, headers, content) tuple. """ line = rfile.readline() if line == "\r\n" or line == "\n": # Possible leftover from previous message line = rfile.readline() if not line: raise HttpErrorConnClosed(502, "Server disconnect.") parts = parse_response_line(line) if not parts: raise HttpError(502, "Invalid server response: %s"%repr(line)) proto, code, msg = parts httpversion = parse_http_protocol(proto) if httpversion is None: raise HttpError(502, "Invalid HTTP version in line: %s"%repr(proto)) headers = read_headers(rfile) if headers is None: raise HttpError(502, "Invalid headers.") if code >= 100 and code <= 199: return read_response(rfile, method, body_size_limit) if method == "HEAD" or code == 204 or code == 304: content = "" else: content = read_http_body_response(rfile, headers, body_size_limit) return httpversion, code, msg, headers, content python-netlib-0.9.2/netlib/http_auth.py000066400000000000000000000061651226005331300201500ustar00rootroot00000000000000import binascii import contrib.md5crypt as md5crypt import http class NullProxyAuth(): """ No proxy auth at all (returns empty challange headers) """ def __init__(self, password_manager): self.password_manager = password_manager def clean(self, headers): """ Clean up authentication headers, so they're not passed upstream. """ pass def authenticate(self, headers): """ Tests that the user is allowed to use the proxy """ return True def auth_challenge_headers(self): """ Returns a dictionary containing the headers require to challenge the user """ return {} class BasicProxyAuth(NullProxyAuth): CHALLENGE_HEADER = 'Proxy-Authenticate' AUTH_HEADER = 'Proxy-Authorization' def __init__(self, password_manager, realm): NullProxyAuth.__init__(self, password_manager) self.realm = realm def clean(self, headers): del headers[self.AUTH_HEADER] def authenticate(self, headers): auth_value = headers.get(self.AUTH_HEADER, []) if not auth_value: return False parts = http.parse_http_basic_auth(auth_value[0]) if not parts: return False scheme, username, password = parts if scheme.lower()!='basic': return False if not self.password_manager.test(username, password): return False self.username = username return True def auth_challenge_headers(self): return {self.CHALLENGE_HEADER:'Basic realm="%s"'%self.realm} class PassMan(): def test(self, username, password_token): return False class PassManNonAnon: """ Ensure the user specifies a username, accept any password. """ def test(self, username, password_token): if username: return True return False class PassManHtpasswd: """ Read usernames and passwords from an htpasswd file """ def __init__(self, fp): """ Raises ValueError if htpasswd file is invalid. """ self.usernames = {} for l in fp: l = l.strip().split(':') if len(l) != 2: raise ValueError("Invalid htpasswd file.") parts = l[1].split('$') if len(parts) != 4: raise ValueError("Invalid htpasswd file.") self.usernames[l[0]] = dict( token = l[1], dummy = parts[0], magic = parts[1], salt = parts[2], hashed_password = parts[3] ) def test(self, username, password_token): ui = self.usernames.get(username) if not ui: return False expected = md5crypt.md5crypt(password_token, ui["salt"], '$'+ui["magic"]+'$') return expected==ui["token"] class PassManSingleUser: def __init__(self, username, password): self.username, self.password = username, password def test(self, username, password_token): return self.username==username and self.password==password_token python-netlib-0.9.2/netlib/http_status.py000066400000000000000000000065511226005331300205310ustar00rootroot00000000000000 CONTINUE = 100 SWITCHING = 101 OK = 200 CREATED = 201 ACCEPTED = 202 NON_AUTHORITATIVE_INFORMATION = 203 NO_CONTENT = 204 RESET_CONTENT = 205 PARTIAL_CONTENT = 206 MULTI_STATUS = 207 MULTIPLE_CHOICE = 300 MOVED_PERMANENTLY = 301 FOUND = 302 SEE_OTHER = 303 NOT_MODIFIED = 304 USE_PROXY = 305 TEMPORARY_REDIRECT = 307 BAD_REQUEST = 400 UNAUTHORIZED = 401 PAYMENT_REQUIRED = 402 FORBIDDEN = 403 NOT_FOUND = 404 NOT_ALLOWED = 405 NOT_ACCEPTABLE = 406 PROXY_AUTH_REQUIRED = 407 REQUEST_TIMEOUT = 408 CONFLICT = 409 GONE = 410 LENGTH_REQUIRED = 411 PRECONDITION_FAILED = 412 REQUEST_ENTITY_TOO_LARGE = 413 REQUEST_URI_TOO_LONG = 414 UNSUPPORTED_MEDIA_TYPE = 415 REQUESTED_RANGE_NOT_SATISFIABLE = 416 EXPECTATION_FAILED = 417 INTERNAL_SERVER_ERROR = 500 NOT_IMPLEMENTED = 501 BAD_GATEWAY = 502 SERVICE_UNAVAILABLE = 503 GATEWAY_TIMEOUT = 504 HTTP_VERSION_NOT_SUPPORTED = 505 INSUFFICIENT_STORAGE_SPACE = 507 NOT_EXTENDED = 510 RESPONSES = { # 100 CONTINUE: "Continue", SWITCHING: "Switching Protocols", # 200 OK: "OK", CREATED: "Created", ACCEPTED: "Accepted", NON_AUTHORITATIVE_INFORMATION: "Non-Authoritative Information", NO_CONTENT: "No Content", RESET_CONTENT: "Reset Content.", PARTIAL_CONTENT: "Partial Content", MULTI_STATUS: "Multi-Status", # 300 MULTIPLE_CHOICE: "Multiple Choices", MOVED_PERMANENTLY: "Moved Permanently", FOUND: "Found", SEE_OTHER: "See Other", NOT_MODIFIED: "Not Modified", USE_PROXY: "Use Proxy", # 306 not defined?? TEMPORARY_REDIRECT: "Temporary Redirect", # 400 BAD_REQUEST: "Bad Request", UNAUTHORIZED: "Unauthorized", PAYMENT_REQUIRED: "Payment Required", FORBIDDEN: "Forbidden", NOT_FOUND: "Not Found", NOT_ALLOWED: "Method Not Allowed", NOT_ACCEPTABLE: "Not Acceptable", PROXY_AUTH_REQUIRED: "Proxy Authentication Required", REQUEST_TIMEOUT: "Request Time-out", CONFLICT: "Conflict", GONE: "Gone", LENGTH_REQUIRED: "Length Required", PRECONDITION_FAILED: "Precondition Failed", REQUEST_ENTITY_TOO_LARGE: "Request Entity Too Large", REQUEST_URI_TOO_LONG: "Request-URI Too Long", UNSUPPORTED_MEDIA_TYPE: "Unsupported Media Type", REQUESTED_RANGE_NOT_SATISFIABLE: "Requested Range not satisfiable", EXPECTATION_FAILED: "Expectation Failed", # 500 INTERNAL_SERVER_ERROR: "Internal Server Error", NOT_IMPLEMENTED: "Not Implemented", BAD_GATEWAY: "Bad Gateway", SERVICE_UNAVAILABLE: "Service Unavailable", GATEWAY_TIMEOUT: "Gateway Time-out", HTTP_VERSION_NOT_SUPPORTED: "HTTP Version not supported", INSUFFICIENT_STORAGE_SPACE: "Insufficient Storage Space", NOT_EXTENDED: "Not Extended" } python-netlib-0.9.2/netlib/http_uastrings.py000066400000000000000000000035331226005331300212220ustar00rootroot00000000000000""" A small collection of useful user-agent header strings. These should be kept reasonably current to reflect common usage. """ # A collection of (name, shortcut, string) tuples. UASTRINGS = [ ( "android", "a", "Mozilla/5.0 (Linux; U; Android 4.1.1; en-gb; Nexus 7 Build/JRO03D) AFL/01.04.02" ), ( "blackberry", "l", "Mozilla/5.0 (BlackBerry; U; BlackBerry 9900; en) AppleWebKit/534.11+ (KHTML, like Gecko) Version/7.1.0.346 Mobile Safari/534.11+" ), ( "bingbot", "b", "Mozilla/5.0 (compatible; bingbot/2.0; +http://www.bing.com/bingbot.htm)" ), ( "chrome", "c", "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.1 (KHTML, like Gecko) Chrome/22.0.1207.1 Safari/537.1" ), ( "firefox", "f", "Mozilla/5.0 (Windows NT 6.1; Win64; x64; rv:14.0) Gecko/20120405 Firefox/14.0a1" ), ( "googlebot", "g", "Googlebot/2.1 (+http://www.googlebot.com/bot.html)" ), ( "ie9", "i", "Mozilla/5.0 (Windows; U; MSIE 9.0; WIndows NT 9.0; en-US))" ), ( "ipad", "p", "Mozilla/5.0 (iPad; CPU OS 5_1 like Mac OS X) AppleWebKit/534.46 (KHTML, like Gecko ) Version/5.1 Mobile/9B176 Safari/7534.48.3" ), ( "iphone", "h", "Mozilla/5.0 (iPhone; CPU iPhone OS 4_2_1 like Mac OS X) AppleWebKit/533.17.9 (KHTML, like Gecko) Version/5.0.2 Mobile/8C148a Safari/6533.18.5", ), ( "safari", "s", "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_7_3) AppleWebKit/534.55.3 (KHTML, like Gecko) Version/5.1.3 Safari/534.53.10" ) ] def get_by_shortcut(s): """ Retrieve a user agent entry by shortcut. """ for i in UASTRINGS: if s == i[1]: return i python-netlib-0.9.2/netlib/odict.py000066400000000000000000000111131226005331300172370ustar00rootroot00000000000000import re, copy def safe_subn(pattern, repl, target, *args, **kwargs): """ There are Unicode conversion problems with re.subn. We try to smooth that over by casting the pattern and replacement to strings. We really need a better solution that is aware of the actual content ecoding. """ return re.subn(str(pattern), str(repl), target, *args, **kwargs) class ODict: """ A dictionary-like object for managing ordered (key, value) data. """ def __init__(self, lst=None): self.lst = lst or [] def _kconv(self, s): return s def __eq__(self, other): return self.lst == other.lst def __iter__(self): return self.lst.__iter__() def __getitem__(self, k): """ Returns a list of values matching key. """ ret = [] k = self._kconv(k) for i in self.lst: if self._kconv(i[0]) == k: ret.append(i[1]) return ret def keys(self): return list(set([self._kconv(i[0]) for i in self.lst])) def _filter_lst(self, k, lst): k = self._kconv(k) new = [] for i in lst: if self._kconv(i[0]) != k: new.append(i) return new def __len__(self): """ Total number of (key, value) pairs. """ return len(self.lst) def __setitem__(self, k, valuelist): """ Sets the values for key k. If there are existing values for this key, they are cleared. """ if isinstance(valuelist, basestring): raise ValueError("ODict valuelist should be lists.") new = self._filter_lst(k, self.lst) for i in valuelist: new.append([k, i]) self.lst = new def __delitem__(self, k): """ Delete all items matching k. """ self.lst = self._filter_lst(k, self.lst) def __contains__(self, k): for i in self.lst: if self._kconv(i[0]) == self._kconv(k): return True return False def add(self, key, value): self.lst.append([key, str(value)]) def get(self, k, d=None): if k in self: return self[k] else: return d def get_first(self, k, d=None): if k in self: return self[k][0] else: return d def items(self): return self.lst[:] def _get_state(self): return [tuple(i) for i in self.lst] @classmethod def _from_state(klass, state): return klass([list(i) for i in state]) def copy(self): """ Returns a copy of this object. """ lst = copy.deepcopy(self.lst) return self.__class__(lst) def __repr__(self): elements = [] for itm in self.lst: elements.append(itm[0] + ": " + itm[1]) elements.append("") return "\r\n".join(elements) def in_any(self, key, value, caseless=False): """ Do any of the values matching key contain value? If caseless is true, value comparison is case-insensitive. """ if caseless: value = value.lower() for i in self[key]: if caseless: i = i.lower() if value in i: return True return False def match_re(self, expr): """ Match the regular expression against each (key, value) pair. For each pair a string of the following format is matched against: "key: value" """ for k, v in self.lst: s = "%s: %s"%(k, v) if re.search(expr, s): return True return False def replace(self, pattern, repl, *args, **kwargs): """ Replaces a regular expression pattern with repl in both keys and values. Encoded content will be decoded before replacement, and re-encoded afterwards. Returns the number of replacements made. """ nlst, count = [], 0 for i in self.lst: k, c = safe_subn(pattern, repl, i[0], *args, **kwargs) count += c v, c = safe_subn(pattern, repl, i[1], *args, **kwargs) count += c nlst.append([k, v]) self.lst = nlst return count class ODictCaseless(ODict): """ A variant of ODict with "caseless" keys. This version _preserves_ key case, but does not consider case when setting or getting items. """ def _kconv(self, s): return s.lower() python-netlib-0.9.2/netlib/tcp.py000066400000000000000000000350611226005331300167330ustar00rootroot00000000000000import select, socket, threading, sys, time, traceback from OpenSSL import SSL import certutils SSLv2_METHOD = SSL.SSLv2_METHOD SSLv3_METHOD = SSL.SSLv3_METHOD SSLv23_METHOD = SSL.SSLv23_METHOD TLSv1_METHOD = SSL.TLSv1_METHOD OP_ALL = SSL.OP_ALL OP_CIPHER_SERVER_PREFERENCE = SSL.OP_CIPHER_SERVER_PREFERENCE OP_COOKIE_EXCHANGE = SSL.OP_COOKIE_EXCHANGE OP_DONT_INSERT_EMPTY_FRAGMENTS = SSL.OP_DONT_INSERT_EMPTY_FRAGMENTS OP_EPHEMERAL_RSA = SSL.OP_EPHEMERAL_RSA OP_MICROSOFT_BIG_SSLV3_BUFFER = SSL.OP_MICROSOFT_BIG_SSLV3_BUFFER OP_MICROSOFT_SESS_ID_BUG = SSL.OP_MICROSOFT_SESS_ID_BUG OP_MSIE_SSLV2_RSA_PADDING = SSL.OP_MSIE_SSLV2_RSA_PADDING OP_NETSCAPE_CA_DN_BUG = SSL.OP_NETSCAPE_CA_DN_BUG OP_NETSCAPE_CHALLENGE_BUG = SSL.OP_NETSCAPE_CHALLENGE_BUG OP_NETSCAPE_DEMO_CIPHER_CHANGE_BUG = SSL.OP_NETSCAPE_DEMO_CIPHER_CHANGE_BUG OP_NETSCAPE_REUSE_CIPHER_CHANGE_BUG = SSL.OP_NETSCAPE_REUSE_CIPHER_CHANGE_BUG OP_NO_QUERY_MTU = SSL.OP_NO_QUERY_MTU OP_NO_SSLv2 = SSL.OP_NO_SSLv2 OP_NO_SSLv3 = SSL.OP_NO_SSLv3 OP_NO_TICKET = SSL.OP_NO_TICKET OP_NO_TLSv1 = SSL.OP_NO_TLSv1 OP_PKCS1_CHECK_1 = SSL.OP_PKCS1_CHECK_1 OP_PKCS1_CHECK_2 = SSL.OP_PKCS1_CHECK_2 OP_SINGLE_DH_USE = SSL.OP_SINGLE_DH_USE OP_SSLEAY_080_CLIENT_DH_BUG = SSL.OP_SSLEAY_080_CLIENT_DH_BUG OP_SSLREF2_REUSE_CERT_TYPE_BUG = SSL.OP_SSLREF2_REUSE_CERT_TYPE_BUG OP_TLS_BLOCK_PADDING_BUG = SSL.OP_TLS_BLOCK_PADDING_BUG OP_TLS_D5_BUG = SSL.OP_TLS_D5_BUG OP_TLS_ROLLBACK_BUG = SSL.OP_TLS_ROLLBACK_BUG class NetLibError(Exception): pass class NetLibDisconnect(NetLibError): pass class NetLibTimeout(NetLibError): pass class NetLibSSLError(NetLibError): pass class _FileLike: BLOCKSIZE = 1024 * 32 def __init__(self, o): self.o = o self._log = None self.first_byte_timestamp = None def set_descriptor(self, o): self.o = o def __getattr__(self, attr): return getattr(self.o, attr) def start_log(self): """ Starts or resets the log. This will store all bytes read or written. """ self._log = [] def stop_log(self): """ Stops the log. """ self._log = None def is_logging(self): return self._log is not None def get_log(self): """ Returns the log as a string. """ if not self.is_logging(): raise ValueError("Not logging!") return "".join(self._log) def add_log(self, v): if self.is_logging(): self._log.append(v) def reset_timestamps(self): self.first_byte_timestamp = None class Writer(_FileLike): def flush(self): """ May raise NetLibDisconnect """ if hasattr(self.o, "flush"): try: self.o.flush() except (socket.error, IOError), v: raise NetLibDisconnect(str(v)) def write(self, v): """ May raise NetLibDisconnect """ if v: try: if hasattr(self.o, "sendall"): self.add_log(v) return self.o.sendall(v) else: r = self.o.write(v) self.add_log(v[:r]) return r except (SSL.Error, socket.error), v: raise NetLibDisconnect(str(v)) class Reader(_FileLike): def read(self, length): """ If length is -1, we read until connection closes. """ result = '' start = time.time() while length == -1 or length > 0: if length == -1 or length > self.BLOCKSIZE: rlen = self.BLOCKSIZE else: rlen = length try: data = self.o.read(rlen) except SSL.ZeroReturnError: break except SSL.WantReadError: if (time.time() - start) < self.o.gettimeout(): time.sleep(0.1) continue else: raise NetLibTimeout except socket.timeout: raise NetLibTimeout except socket.error: raise NetLibDisconnect except SSL.SysCallError: raise NetLibDisconnect except SSL.Error, v: raise NetLibSSLError(v.message) self.first_byte_timestamp = self.first_byte_timestamp or time.time() if not data: break result += data if length != -1: length -= len(data) self.add_log(result) return result def readline(self, size = None): result = '' bytes_read = 0 while True: if size is not None and bytes_read >= size: break try: ch = self.read(1) except NetLibDisconnect: break bytes_read += 1 if not ch: break else: result += ch if ch == '\n': break return result class TCPClient: rbufsize = -1 wbufsize = -1 def __init__(self, host, port, source_address=None): self.host, self.port = host, port self.connection, self.rfile, self.wfile = None, None, None self.cert = None self.ssl_established = False self.source_address = source_address def convert_to_ssl(self, cert=None, sni=None, method=TLSv1_METHOD, options=None): """ cert: Path to a file containing both client cert and private key. """ context = SSL.Context(method) if options is not None: context.set_options(options) if cert: try: context.use_privatekey_file(cert) context.use_certificate_file(cert) except SSL.Error, v: raise NetLibError("SSL client certificate error: %s"%str(v)) self.connection = SSL.Connection(context, self.connection) self.ssl_established = True if sni: self.connection.set_tlsext_host_name(sni) self.connection.set_connect_state() try: self.connection.do_handshake() except SSL.Error, v: raise NetLibError("SSL handshake error: %s"%str(v)) self.cert = certutils.SSLCert(self.connection.get_peer_certificate()) self.rfile.set_descriptor(self.connection) self.wfile.set_descriptor(self.connection) def connect(self): try: addr = socket.gethostbyname(self.host) connection = socket.socket(socket.AF_INET, socket.SOCK_STREAM) if self.source_address: connection.bind(self.source_address) connection.connect((addr, self.port)) self.rfile = Reader(connection.makefile('rb', self.rbufsize)) self.wfile = Writer(connection.makefile('wb', self.wbufsize)) except (socket.error, IOError), err: raise NetLibError('Error connecting to "%s": %s' % (self.host, err)) self.connection = connection def settimeout(self, n): self.connection.settimeout(n) def gettimeout(self): return self.connection.gettimeout() def close(self): """ Does a hard close of the socket, i.e. a shutdown, followed by a close. """ try: if self.ssl_established: self.connection.shutdown() else: self.connection.shutdown(socket.SHUT_WR) #Section 4.2.2.13 of RFC 1122 tells us that a close() with any pending readable data could lead to an immediate RST being sent. #http://ia600609.us.archive.org/22/items/TheUltimateSo_lingerPageOrWhyIsMyTcpNotReliable/the-ultimate-so_linger-page-or-why-is-my-tcp-not-reliable.html while self.connection.recv(4096): pass self.connection.close() except (socket.error, SSL.Error, IOError): # Socket probably already closed pass class BaseHandler: """ The instantiator is expected to call the handle() and finish() methods. """ rbufsize = -1 wbufsize = -1 def __init__(self, connection, client_address, server): self.connection = connection self.rfile = Reader(self.connection.makefile('rb', self.rbufsize)) self.wfile = Writer(self.connection.makefile('wb', self.wbufsize)) self.client_address = client_address self.server = server self.finished = False self.ssl_established = False self.clientcert = None def convert_to_ssl(self, cert, key, method=SSLv23_METHOD, options=None, handle_sni=None, request_client_cert=False): """ cert: A certutils.SSLCert object. method: One of SSLv2_METHOD, SSLv3_METHOD, SSLv23_METHOD, or TLSv1_METHOD handle_sni: SNI handler, should take a connection object. Server name can be retrieved like this: connection.get_servername() And you can specify the connection keys as follows: new_context = Context(TLSv1_METHOD) new_context.use_privatekey(key) new_context.use_certificate(cert) connection.set_context(new_context) The request_client_cert argument requires some explanation. We're supposed to be able to do this with no negative effects - if the client has no cert to present, we're notified and proceed as usual. Unfortunately, Android seems to have a bug (tested on 4.2.2) - when an Android client is asked to present a certificate it does not have, it hangs up, which is frankly bogus. Some time down the track we may be able to make the proper behaviour the default again, but until then we're conservative. """ ctx = SSL.Context(method) if not options is None: ctx.set_options(options) if handle_sni: # SNI callback happens during do_handshake() ctx.set_tlsext_servername_callback(handle_sni) ctx.use_privatekey_file(key) ctx.use_certificate(cert.x509) if request_client_cert: def ver(*args): self.clientcert = certutils.SSLCert(args[1]) ctx.set_verify(SSL.VERIFY_PEER, ver) self.connection = SSL.Connection(ctx, self.connection) self.ssl_established = True self.connection.set_accept_state() try: self.connection.do_handshake() except SSL.Error, v: raise NetLibError("SSL handshake error: %s"%str(v)) self.rfile.set_descriptor(self.connection) self.wfile.set_descriptor(self.connection) def finish(self): self.finished = True try: if not getattr(self.wfile, "closed", False): self.wfile.flush() self.close() self.wfile.close() self.rfile.close() except (socket.error, NetLibDisconnect): # Remote has disconnected pass def handle(self): # pragma: no cover raise NotImplementedError def settimeout(self, n): self.connection.settimeout(n) def close(self): """ Does a hard close of the socket, i.e. a shutdown, followed by a close. """ try: if self.ssl_established: self.connection.shutdown() else: self.connection.shutdown(socket.SHUT_WR) #Section 4.2.2.13 of RFC 1122 tells us that a close() with any pending readable data could lead to an immediate RST being sent. #http://ia600609.us.archive.org/22/items/TheUltimateSo_lingerPageOrWhyIsMyTcpNotReliable/the-ultimate-so_linger-page-or-why-is-my-tcp-not-reliable.html while self.connection.recv(4096): pass except (socket.error, SSL.Error): # Socket probably already closed pass self.connection.close() class TCPServer: request_queue_size = 20 def __init__(self, server_address): self.server_address = server_address self.__is_shut_down = threading.Event() self.__shutdown_request = False self.socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) self.socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) self.socket.bind(self.server_address) self.server_address = self.socket.getsockname() self.port = self.server_address[1] self.socket.listen(self.request_queue_size) def request_thread(self, request, client_address): try: self.handle_connection(request, client_address) request.close() except: self.handle_error(request, client_address) request.close() def serve_forever(self, poll_interval=0.1): self.__is_shut_down.clear() try: while not self.__shutdown_request: try: r, w, e = select.select([self.socket], [], [], poll_interval) except select.error, ex: if ex[0] == 4: continue else: raise if self.socket in r: request, client_address = self.socket.accept() t = threading.Thread( target = self.request_thread, args = (request, client_address) ) t.setDaemon(1) t.start() finally: self.__shutdown_request = False self.__is_shut_down.set() def shutdown(self): self.__shutdown_request = True self.__is_shut_down.wait() self.socket.close() self.handle_shutdown() def handle_error(self, request, client_address, fp=sys.stderr): """ Called when handle_connection raises an exception. """ # If a thread has persisted after interpreter exit, the module might be # none. if traceback: exc = traceback.format_exc() print >> fp, '-'*40 print >> fp, "Error in processing of request from %s:%s"%client_address print >> fp, exc print >> fp, '-'*40 def handle_connection(self, request, client_address): # pragma: no cover """ Called after client connection. """ raise NotImplementedError def handle_shutdown(self): """ Called after server shutdown. """ pass python-netlib-0.9.2/netlib/test.py000066400000000000000000000042011226005331300171140ustar00rootroot00000000000000import threading, Queue, cStringIO import tcp, certutils class ServerThread(threading.Thread): def __init__(self, server): self.server = server threading.Thread.__init__(self) def run(self): self.server.serve_forever() def shutdown(self): self.server.shutdown() class ServerTestBase: ssl = None handler = None @classmethod def setupAll(cls): cls.q = Queue.Queue() s = cls.makeserver() cls.port = s.port cls.server = ServerThread(s) cls.server.start() @classmethod def makeserver(cls): return TServer(cls.ssl, cls.q, cls.handler) @classmethod def teardownAll(cls): cls.server.shutdown() @property def last_handler(self): return self.server.server.last_handler class TServer(tcp.TCPServer): def __init__(self, ssl, q, handler_klass, addr=("127.0.0.1", 0)): """ ssl: A {cert, key, v3_only} dict. """ tcp.TCPServer.__init__(self, addr) self.ssl, self.q = ssl, q self.handler_klass = handler_klass self.last_handler = None def handle_connection(self, request, client_address): h = self.handler_klass(request, client_address, self) self.last_handler = h if self.ssl: cert = certutils.SSLCert.from_pem( file(self.ssl["cert"], "r").read() ) if self.ssl["v3_only"]: method = tcp.SSLv3_METHOD options = tcp.OP_NO_SSLv2|tcp.OP_NO_TLSv1 else: method = tcp.SSLv23_METHOD options = None h.convert_to_ssl( cert, self.ssl["key"], method = method, options = options, handle_sni = getattr(h, "handle_sni", None), request_client_cert = self.ssl["request_client_cert"] ) h.handle() h.finish() def handle_error(self, request, client_address): s = cStringIO.StringIO() tcp.TCPServer.handle_error(self, request, client_address, s) self.q.put(s.getvalue()) python-netlib-0.9.2/netlib/utils.py000066400000000000000000000020411226005331300172750ustar00rootroot00000000000000 def isascii(s): try: s.decode("ascii") except ValueError: return False return True def cleanBin(s, fixspacing=False): """ Cleans binary data to make it safe to display. If fixspacing is True, tabs, newlines and so forth will be maintained, if not, they will be replaced with a placeholder. """ parts = [] for i in s: o = ord(i) if (o > 31 and o < 127): parts.append(i) elif i in "\n\t" and not fixspacing: parts.append(i) else: parts.append(".") return "".join(parts) def hexdump(s): """ Returns a set of tuples: (offset, hex, str) """ parts = [] for i in range(0, len(s), 16): o = "%.10x"%i part = s[i:i+16] x = " ".join("%.2x"%ord(i) for i in part) if len(part) < 16: x += " " x += " ".join(" " for i in range(16 - len(part))) parts.append( (o, x, cleanBin(part, True)) ) return parts python-netlib-0.9.2/netlib/version.py000066400000000000000000000001651226005331300176270ustar00rootroot00000000000000IVERSION = (0, 9, 2) VERSION = ".".join(str(i) for i in IVERSION) NAME = "netlib" NAMEVERSION = NAME + " " + VERSION python-netlib-0.9.2/netlib/wsgi.py000066400000000000000000000117061226005331300171160ustar00rootroot00000000000000import cStringIO, urllib, time, traceback import odict class ClientConn: def __init__(self, address): self.address = address class Request: def __init__(self, client_conn, scheme, method, path, headers, content): self.scheme, self.method, self.path = scheme, method, path self.headers, self.content = headers, content self.client_conn = client_conn def date_time_string(): """Return the current date and time formatted for a message header.""" WEEKS = ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'] MONTHS = [None, 'Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'] now = time.time() year, month, day, hh, mm, ss, wd, y, z = time.gmtime(now) s = "%s, %02d %3s %4d %02d:%02d:%02d GMT" % ( WEEKS[wd], day, MONTHS[month], year, hh, mm, ss) return s class WSGIAdaptor: def __init__(self, app, domain, port, sversion): self.app, self.domain, self.port, self.sversion = app, domain, port, sversion def make_environ(self, request, errsoc): if '?' in request.path: path_info, query = request.path.split('?', 1) else: path_info = request.path query = '' environ = { 'wsgi.version': (1, 0), 'wsgi.url_scheme': request.scheme, 'wsgi.input': cStringIO.StringIO(request.content), 'wsgi.errors': errsoc, 'wsgi.multithread': True, 'wsgi.multiprocess': False, 'wsgi.run_once': False, 'SERVER_SOFTWARE': self.sversion, 'REQUEST_METHOD': request.method, 'SCRIPT_NAME': '', 'PATH_INFO': urllib.unquote(path_info), 'QUERY_STRING': query, 'CONTENT_TYPE': request.headers.get('Content-Type', [''])[0], 'CONTENT_LENGTH': request.headers.get('Content-Length', [''])[0], 'SERVER_NAME': self.domain, 'SERVER_PORT': str(self.port), # FIXME: We need to pick up the protocol read from the request. 'SERVER_PROTOCOL': "HTTP/1.1", } if request.client_conn.address: environ["REMOTE_ADDR"], environ["REMOTE_PORT"] = request.client_conn.address for key, value in request.headers.items(): key = 'HTTP_' + key.upper().replace('-', '_') if key not in ('HTTP_CONTENT_TYPE', 'HTTP_CONTENT_LENGTH'): environ[key] = value return environ def error_page(self, soc, headers_sent, s): """ Make a best-effort attempt to write an error page. If headers are already sent, we just bung the error into the page. """ c = """

Internal Server Error

%s"
"""%s if not headers_sent: soc.write("HTTP/1.1 500 Internal Server Error\r\n") soc.write("Content-Type: text/html\r\n") soc.write("Content-Length: %s\r\n"%len(c)) soc.write("\r\n") soc.write(c) def serve(self, request, soc): state = dict( response_started = False, headers_sent = False, status = None, headers = None ) def write(data): if not state["headers_sent"]: soc.write("HTTP/1.1 %s\r\n"%state["status"]) h = state["headers"] if 'server' not in h: h["Server"] = [self.sversion] if 'date' not in h: h["Date"] = [date_time_string()] soc.write(str(h)) soc.write("\r\n") state["headers_sent"] = True if data: soc.write(data) soc.flush() def start_response(status, headers, exc_info=None): if exc_info: try: if state["headers_sent"]: raise exc_info[0], exc_info[1], exc_info[2] finally: exc_info = None elif state["status"]: raise AssertionError('Response already started') state["status"] = status state["headers"] = odict.ODictCaseless(headers) return write errs = cStringIO.StringIO() try: dataiter = self.app(self.make_environ(request, errs), start_response) for i in dataiter: write(i) if not state["headers_sent"]: write("") except Exception: try: s = traceback.format_exc() errs.write(s) self.error_page(soc, state["headers_sent"], s) except Exception: # pragma: no cover pass return errs.getvalue() python-netlib-0.9.2/setup.py000066400000000000000000000060231226005331300160240ustar00rootroot00000000000000from distutils.core import setup import fnmatch, os.path from netlib import version def _fnmatch(name, patternList): for i in patternList: if fnmatch.fnmatch(name, i): return True return False def _splitAll(path): parts = [] h = path while 1: if not h: break h, t = os.path.split(h) parts.append(t) parts.reverse() return parts def findPackages(path, dataExclude=[]): """ Recursively find all packages and data directories rooted at path. Note that only data _directories_ and their contents are returned - non-Python files at module scope are not, and should be manually included. dataExclude is a list of fnmatch-compatible expressions for files and directories that should not be included in pakcage_data. Returns a (packages, package_data) tuple, ready to be passed to the corresponding distutils.core.setup arguments. """ packages = [] datadirs = [] for root, dirs, files in os.walk(path, topdown=True): if "__init__.py" in files: p = _splitAll(root) packages.append(".".join(p)) else: dirs[:] = [] if packages: datadirs.append(root) # Now we recurse into the data directories package_data = {} for i in datadirs: if not _fnmatch(i, dataExclude): parts = _splitAll(i) module = ".".join(parts[:-1]) acc = package_data.get(module, []) for root, dirs, files in os.walk(i, topdown=True): sub = os.path.join(*_splitAll(root)[1:]) if not _fnmatch(sub, dataExclude): for fname in files: path = os.path.join(sub, fname) if not _fnmatch(path, dataExclude): acc.append(path) else: dirs[:] = [] package_data[module] = acc return packages, package_data long_description = file("README").read() packages, package_data = findPackages("netlib") setup( name = "netlib", version = version.VERSION, description = "A collection of network utilities used by pathod and mitmproxy.", long_description = long_description, author = "Aldo Cortesi", author_email = "aldo@corte.si", url = "http://cortesi.github.com/netlib", packages = packages, package_data = package_data, classifiers = [ "License :: OSI Approved :: MIT License", "Development Status :: 3 - Alpha", "Operating System :: POSIX", "Programming Language :: Python", "Topic :: Internet", "Topic :: Internet :: WWW/HTTP :: HTTP Servers", "Topic :: Software Development :: Testing", "Topic :: Software Development :: Testing :: Traffic Generation", "Topic :: Internet :: WWW/HTTP", ], install_requires=["pyasn1>0.1.2", "pyopenssl>=0.12"], ) python-netlib-0.9.2/test/000077500000000000000000000000001226005331300152705ustar00rootroot00000000000000python-netlib-0.9.2/test/data/000077500000000000000000000000001226005331300162015ustar00rootroot00000000000000python-netlib-0.9.2/test/data/clientcert/000077500000000000000000000000001226005331300203355ustar00rootroot00000000000000python-netlib-0.9.2/test/data/clientcert/.gitignore000066400000000000000000000000411226005331300223200ustar00rootroot00000000000000client.crt client.key client.req python-netlib-0.9.2/test/data/clientcert/client.cnf000066400000000000000000000002121226005331300222760ustar00rootroot00000000000000[ ssl_client ] basicConstraints = CA:FALSE nsCertType = client keyUsage = digitalSignature, keyEncipherment extendedKeyUsage = clientAuth python-netlib-0.9.2/test/data/clientcert/client.pem000066400000000000000000000050021226005331300223130ustar00rootroot00000000000000-----BEGIN RSA PRIVATE KEY----- MIIEpAIBAAKCAQEAzCpoRjSTfIN24kkNap/GYmP9zVWj0Gk8R5BB/PvvN0OB1Zk0 EEYPsWCcuhEdK0ehiDZX030doF0DOncKKa6mop/d0x2o+ts42peDhZM6JNUrm6d+ ZWQVtio33mpp77UMhR093vaA+ExDnmE26kBTVijJ1+fRAVDXG/cmQINEri91Kk/G 3YJ5e45UrohGI5seBZ4vV0xbHtmczFRhYFlGOvYsoIe4Lvz/eFS2pIrTIpYQ2VM/ SQQl+JFy+NlQRsWG2NrxtKOzMnnDE7YN4I3z5D5eZFo1EtwZ48LNCeSwrEOdfuzP G5q5qbs5KpE/x85H9umuRwSCIArbMwBYV8a8JwIDAQABAoIBAFE3FV/IDltbmHEP iky93hbJm+6QgKepFReKpRVTyqb7LaygUvueQyPWQMIriKTsy675nxo8DQr7tQsO y3YlSZgra/xNMikIB6e82c7K8DgyrDQw/rCqjZB3Xt4VCqsWJDLXnQMSn98lx0g7 d7Lbf8soUpKWXqfdVpSDTi4fibSX6kshXyfSTpcz4AdoncEpViUfU1xkEEmZrjT8 1GcCsDC41xdNmzCpqRuZX7DKSFRoB+0hUzsC1oiqM7FD5kixonRd4F5PbRXImIzt 6YCsT2okxTA04jX7yByis7LlOLTlkmLtKQYuc3erOFvwx89s4vW+AeFei+GGNitn tHfSwbECgYEA7SzV+nN62hAERHlg8cEQT4TxnsWvbronYWcc/ev44eHSPDWL5tPi GHfSbW6YAq5Wa0I9jMWfXyhOYEC3MZTC5EEeLOB71qVrTwcy/sY66rOrcgjFI76Q 5JFHQ4wy3SWU50KxE0oWJO9LIowprG+pW1vzqC3VF0T7q0FqESrY4LUCgYEA3F7Z 80ndnCUlooJAb+Hfotv7peFf1o6+m1PTRcz1lLnVt5R5lXj86kn+tXEpYZo1RiGR 2rE2N0seeznWCooakHcsBN7/qmFIhhooJNF7yW+JP2I4P2UV5+tJ+8bcs/voUkQD 1x+rGOuMn8nvHBd2+Vharft8eGL2mgooPVI2XusCgYEAlMZpO3+w8pTVeHaDP2MR 7i/AuQ3cbCLNjSX3Y7jgGCFllWspZRRIYXzYPNkA9b2SbBnTLjjRLgnEkFBIGgvs 7O2EFjaCuDRvydUEQhjq4ErwIsopj7B8h0QyZcbOKTbn3uFQ3n68wVJx2Sv/ADHT FIHrp/WIE96r19Niy34LKXkCgYB2W59VsuOKnMz01l5DeR5C+0HSWxS9SReIl2IO yEFSKullWyJeLIgyUaGy0990430feKI8whcrZXYumuah7IDN/KOwzhCk8vEfzWao N7bzfqtJVrh9HA7C7DVlO+6H4JFrtcoWPZUIomJ549w/yz6EN3ckoMC+a/Ck1TW9 ka1QFwKBgQCywG6TrZz0UmOjyLQZ+8Q4uvZklSW5NAKBkNnyuQ2kd5rzyYgMPE8C Er8T88fdVIKvkhDyHhwcI7n58xE5Gr7wkwsrk/Hbd9/ZB2GgAPY3cATskK1v1McU YeX38CU0fUS4aoy26hWQXkViB47IGQ3jWo3ZCtzIJl8DI9/RsBWTnw== -----END RSA PRIVATE KEY----- -----BEGIN CERTIFICATE----- MIICYDCCAckCAQEwDQYJKoZIhvcNAQEFBQAwKDESMBAGA1UEAxMJbWl0bXByb3h5 MRIwEAYDVQQKEwltaXRtcHJveHkwHhcNMTMwMTIwMDEwODEzWhcNMTUxMDE3MDEw ODEzWjBFMQswCQYDVQQGEwJBVTETMBEGA1UECBMKU29tZS1TdGF0ZTEhMB8GA1UE ChMYSW50ZXJuZXQgV2lkZ2l0cyBQdHkgTHRkMIIBIjANBgkqhkiG9w0BAQEFAAOC AQ8AMIIBCgKCAQEAzCpoRjSTfIN24kkNap/GYmP9zVWj0Gk8R5BB/PvvN0OB1Zk0 EEYPsWCcuhEdK0ehiDZX030doF0DOncKKa6mop/d0x2o+ts42peDhZM6JNUrm6d+ ZWQVtio33mpp77UMhR093vaA+ExDnmE26kBTVijJ1+fRAVDXG/cmQINEri91Kk/G 3YJ5e45UrohGI5seBZ4vV0xbHtmczFRhYFlGOvYsoIe4Lvz/eFS2pIrTIpYQ2VM/ SQQl+JFy+NlQRsWG2NrxtKOzMnnDE7YN4I3z5D5eZFo1EtwZ48LNCeSwrEOdfuzP G5q5qbs5KpE/x85H9umuRwSCIArbMwBYV8a8JwIDAQABMA0GCSqGSIb3DQEBBQUA A4GBAFvI+cd47B85PQ970n2dU/PlA2/Hb1ldrrXh2guR4hX6vYx/uuk5yRI/n0Rd KOXJ3czO0bd2Fpe3ZoNpkW0pOSDej/Q+58ScuJd0gWCT/Sh1eRk6ZdC0kusOuWoY bPOPMkG45LPgUMFOnZEsfJP6P5mZIxlbCvSMFC25nPHWlct7 -----END CERTIFICATE----- python-netlib-0.9.2/test/data/clientcert/make000077500000000000000000000007261226005331300212050ustar00rootroot00000000000000#!/bin/sh openssl genrsa -out client.key 2048 openssl req -key client.key -new -out client.req openssl x509 -req -days 365 -in client.req -signkey client.key -out client.crt -extfile client.cnf -extensions ssl_client openssl x509 -req -days 1000 -in client.req -CA ~/.mitmproxy/mitmproxy-ca.pem -CAkey ~/.mitmproxy/mitmproxy-ca.pem -set_serial 00001 -out client.crt -extensions ssl_client cat client.key client.crt > client.pem openssl x509 -text -noout -in client.pem python-netlib-0.9.2/test/data/dercert000066400000000000000000000034561226005331300175640ustar00rootroot000000000000000‚*0‚ wvŠ]ðåyYÊ*P‚µ0  *†H†÷ 0i1 0 UUS10U  DigiCert Inc10U www.digicert.com1(0&UDigiCert High Assurance EV CA-10 110527000000Z 130729120000Z0Ê10U Private Organization10 +‚7<US10 +‚7< California10UC32681021 0 UUS10U California10U San Francisco10U  GitHub, Inc.10U github.com0‚"0  *†H†÷ ‚0‚ ‚íÓ‰Ã]pr ó3OrtÙ¶Z•P»haŸ÷ûáÚ1¯|ùs¯åC+V EiJèÄ[ßÂwRQ[Ñ+Ù9e6 2Asû2²=Ÿ˜ì‚[ 7d9,·ƒrÍðê$KúÙ”.Ã…9©:öˆÚô'‰¦•O„¢7N|%x:Ƀm•x}G¨Uƒîȳ<ñ_þ;á…ûf« ]ŸLCðÇ$^)r(ÎÔuhO$r)®9(üßOMƒst o›§ÝbÞÿâëæÿ ¿À-1;ÖY¢ò݇JH{m3M4Ÿ28öÈñ¶=ÅFïQ ŠÆ3íHaĽ|¶gé9Ï¥R€ ôêÍ£‚j0‚f0U#0€LXË%ðAORô(ÈC›¦¨ æ’å0U‡Ñnä‡oSŒw‘Pߣ¿UG 0%U0‚ github.com‚www.github.com0+u0s0$+0†http://ocsp.digicert.com0K+0†?http://www.digicert.com/CACerts/DigiCertHighAssuranceEVCA-1.crt0 Uÿ00aUZ0X0* ( &†$http://crl3.digicert.com/ev2009a.crl0* ( &†$http://crl4.digicert.com/ev2009a.crl0‚ÄU ‚»0‚·0‚³ `†H†ýl0‚¤0:+.http://www.digicert.com/ssl-cps-repository.htm0‚d+0‚V‚RAny use of this Certificate constitutes acceptance of the DigiCert CP/CPS and the Relying Party Agreement which limit liability and are incorporated herein by reference.0U%0++0 `†H†øBÀ0Uÿ 0  *†H†÷ ‚Rq†m5>†»f‹…˜¹LËBµFüçD9ÈèRØ#³r–锞/(÷ÕE@ÆôWBBÞ ‰— \k½ ÷£_gó 8c¿Á0ºŽ¥TtYSg¡P[&Úý~Y¿Iï”~E¤ý:I2ðjÿ‰©a©ª›–FÈàæû‚ô «R¦ÊèT"ÙÛ*=Z"{€êÔùÇðSY_»w~Þ“pAN#ËxyyÄ.ê×f*÷ÑÅ|âx‚삞¢å¾x¡¹YXÅLoO¥1´I[^˜.8öÄ9¢Jûy¸òYå&p­Àèu#Ñ àŸeäÃ×I‡[rl±/¬opython-netlib-0.9.2/test/data/htpasswd000066400000000000000000000000531226005331300177570ustar00rootroot00000000000000test:$apr1$/LkYxy3x$WI4.YbiJlu537jLGEW2eu1 python-netlib-0.9.2/test/data/server.crt000066400000000000000000000015021226005331300202170ustar00rootroot00000000000000-----BEGIN CERTIFICATE----- MIICOzCCAaQCCQDC7f5GsEpo9jANBgkqhkiG9w0BAQUFADBiMQswCQYDVQQGEwJO WjEOMAwGA1UECBMFT3RhZ28xEDAOBgNVBAcTB0R1bmVkaW4xDzANBgNVBAoTBm5l dGxpYjEPMA0GA1UECxMGbmV0bGliMQ8wDQYDVQQDEwZuZXRsaWIwHhcNMTIwNjI0 MjI0MTU0WhcNMjIwNjIyMjI0MTU0WjBiMQswCQYDVQQGEwJOWjEOMAwGA1UECBMF T3RhZ28xEDAOBgNVBAcTB0R1bmVkaW4xDzANBgNVBAoTBm5ldGxpYjEPMA0GA1UE CxMGbmV0bGliMQ8wDQYDVQQDEwZuZXRsaWIwgZ8wDQYJKoZIhvcNAQEBBQADgY0A MIGJAoGBALJSVEl9y3QUSYuXTH0UjBOPQgS0nHmNWej9hjqnA0KWvEnGY+c6yQeP /rmwswlKw1iVV5o8kRK9Wej88YWQl/hl/xruyeJgGic0+yqY/FcueZxRudwBcWu2 7+46aEftwLLRF0GwHZxX/HwWME+TcCXGpXGSG2qs921M4iVeBn5hAgMBAAEwDQYJ KoZIhvcNAQEFBQADgYEAODZCihEv2yr8zmmQZDrfqg2ChxAoOXWF5+W2F/0LAUBf 2bHP+K4XE6BJWmadX1xKngj7SWrhmmTDp1gBAvXURoDaScOkB1iOCOHoIyalscTR 0FvSHKqFF8fgSlfqS6eYaSbXU3zQolvwP+URzIVnGDqgQCWPtjMqLD3Kd5tuwos= -----END CERTIFICATE----- python-netlib-0.9.2/test/data/server.key000066400000000000000000000015671226005331300202320ustar00rootroot00000000000000-----BEGIN RSA PRIVATE KEY----- MIICXAIBAAKBgQCyUlRJfct0FEmLl0x9FIwTj0IEtJx5jVno/YY6pwNClrxJxmPn OskHj/65sLMJSsNYlVeaPJESvVno/PGFkJf4Zf8a7sniYBonNPsqmPxXLnmcUbnc AXFrtu/uOmhH7cCy0RdBsB2cV/x8FjBPk3AlxqVxkhtqrPdtTOIlXgZ+YQIDAQAB AoGAQEpGcSiVTYhy64zk2sOprPOdTa0ALSK1I7cjycmk90D5KXAJXLho+f0ETVZT dioqO6m8J7NmamcyHznyqcDzyNRqD2hEBDGVRJWmpOjIER/JwWLNNbpeVjsMHV8I 40P5rZMOhBPYlwECSC5NtMwaN472fyGNNze8u37IZKiER/ECQQDe1iY5AG3CgkP3 tEZB3Vtzcn4PoOr3Utyn1YER34lPqAmeAsWUhmAVEfR3N1HDe1VFD9s2BidhBn1a /Bgqxz4DAkEAzNw0m+uO0WkD7aEYRBW7SbXCX+3xsbVToIWC1jXFG+XDzSWn++c1 DMXEElzEJxPDA+FzQUvRTml4P92bTAbGywJAS9H7wWtm7Ubbj33UZfbGdhqfz/uF 109naufXedhgZS0c0JnK1oV+Tc0FLEczV9swIUaK5O/lGDtYDcw3AN84NwJBAIw5 /1jrOOtm8uVp6+5O4dBmthJsEZEPCZtLSG/Qhoe+EvUN3Zq0fL+tb7USAsKs6ERz wizj9PWzhDhTPMYhrVkCQGIponZHx6VqiFyLgYUH9+gDTjBhYyI+6yMTYzcRweyL 9Suc2NkS3X2Lp+wCjvVZdwGtStp6Vo8z02b3giIsAIY= -----END RSA PRIVATE KEY----- python-netlib-0.9.2/test/data/text_cert000066400000000000000000000220211226005331300201220ustar00rootroot00000000000000-----BEGIN CERTIFICATE----- MIIadTCCGd6gAwIBAgIGR09PUAFtMA0GCSqGSIb3DQEBBQUAMEYxCzAJBgNVBAYT AlVTMRMwEQYDVQQKEwpHb29nbGUgSW5jMSIwIAYDVQQDExlHb29nbGUgSW50ZXJu ZXQgQXV0aG9yaXR5MB4XDTEyMDExNzEyNTUwNFoXDTEzMDExNzEyNTUwNFowTDEL MAkGA1UEBhMCVVMxEzARBgNVBAgTCkNhbGlmb3JuaWExEzARBgNVBAoTCkdvb2ds ZSBJbmMxEzARBgNVBAMTCmdvb2dsZS5jb20wgZ8wDQYJKoZIhvcNAQEBBQADgY0A MIGJAoGBALofcxR2fud5cyFIeld9pj2vGB5GH0y9tmAYa5t33xbJguKKX/el3tXA KMNiT1SZzu8ELJ1Ey0GcBAgHA9jVPQd0LGdbEtNIxjblAsWAD/FZlSt8X87h7C5w 2JSefOani0qgQqU6sTdsaCUGZ+Eu7D0lBfT5/Vnl2vV+zI3YmDlpAgMBAAGjghhm MIIYYjAdBgNVHQ4EFgQUL3+JeC/oL9jZhTp3F550LautzV8wHwYDVR0jBBgwFoAU v8Aw6/VDET5nup6R+/xq2uNrEiQwWwYDVR0fBFQwUjBQoE6gTIZKaHR0cDovL3d3 dy5nc3RhdGljLmNvbS9Hb29nbGVJbnRlcm5ldEF1dGhvcml0eS9Hb29nbGVJbnRl cm5ldEF1dGhvcml0eS5jcmwwZgYIKwYBBQUHAQEEWjBYMFYGCCsGAQUFBzAChkpo dHRwOi8vd3d3LmdzdGF0aWMuY29tL0dvb2dsZUludGVybmV0QXV0aG9yaXR5L0dv b2dsZUludGVybmV0QXV0aG9yaXR5LmNydDCCF1kGA1UdEQSCF1AwghdMggpnb29n bGUuY29tggwqLmdvb2dsZS5jb22CCyouZ29vZ2xlLmFjggsqLmdvb2dsZS5hZIIL Ki5nb29nbGUuYWWCCyouZ29vZ2xlLmFmggsqLmdvb2dsZS5hZ4ILKi5nb29nbGUu YW2CCyouZ29vZ2xlLmFzggsqLmdvb2dsZS5hdIILKi5nb29nbGUuYXqCCyouZ29v Z2xlLmJhggsqLmdvb2dsZS5iZYILKi5nb29nbGUuYmaCCyouZ29vZ2xlLmJnggsq Lmdvb2dsZS5iaYILKi5nb29nbGUuYmqCCyouZ29vZ2xlLmJzggsqLmdvb2dsZS5i eYILKi5nb29nbGUuY2GCDCouZ29vZ2xlLmNhdIILKi5nb29nbGUuY2OCCyouZ29v Z2xlLmNkggsqLmdvb2dsZS5jZoILKi5nb29nbGUuY2eCCyouZ29vZ2xlLmNoggsq Lmdvb2dsZS5jaYILKi5nb29nbGUuY2yCCyouZ29vZ2xlLmNtggsqLmdvb2dsZS5j boIOKi5nb29nbGUuY28uYW+CDiouZ29vZ2xlLmNvLmJ3gg4qLmdvb2dsZS5jby5j a4IOKi5nb29nbGUuY28uY3KCDiouZ29vZ2xlLmNvLmh1gg4qLmdvb2dsZS5jby5p ZIIOKi5nb29nbGUuY28uaWyCDiouZ29vZ2xlLmNvLmltgg4qLmdvb2dsZS5jby5p boIOKi5nb29nbGUuY28uamWCDiouZ29vZ2xlLmNvLmpwgg4qLmdvb2dsZS5jby5r ZYIOKi5nb29nbGUuY28ua3KCDiouZ29vZ2xlLmNvLmxzgg4qLmdvb2dsZS5jby5t YYIOKi5nb29nbGUuY28ubXqCDiouZ29vZ2xlLmNvLm56gg4qLmdvb2dsZS5jby50 aIIOKi5nb29nbGUuY28udHqCDiouZ29vZ2xlLmNvLnVngg4qLmdvb2dsZS5jby51 a4IOKi5nb29nbGUuY28udXqCDiouZ29vZ2xlLmNvLnZlgg4qLmdvb2dsZS5jby52 aYIOKi5nb29nbGUuY28uemGCDiouZ29vZ2xlLmNvLnptgg4qLmdvb2dsZS5jby56 d4IPKi5nb29nbGUuY29tLmFmgg8qLmdvb2dsZS5jb20uYWeCDyouZ29vZ2xlLmNv bS5haYIPKi5nb29nbGUuY29tLmFygg8qLmdvb2dsZS5jb20uYXWCDyouZ29vZ2xl LmNvbS5iZIIPKi5nb29nbGUuY29tLmJogg8qLmdvb2dsZS5jb20uYm6CDyouZ29v Z2xlLmNvbS5ib4IPKi5nb29nbGUuY29tLmJygg8qLmdvb2dsZS5jb20uYnmCDyou Z29vZ2xlLmNvbS5ieoIPKi5nb29nbGUuY29tLmNugg8qLmdvb2dsZS5jb20uY2+C DyouZ29vZ2xlLmNvbS5jdYIPKi5nb29nbGUuY29tLmN5gg8qLmdvb2dsZS5jb20u ZG+CDyouZ29vZ2xlLmNvbS5lY4IPKi5nb29nbGUuY29tLmVngg8qLmdvb2dsZS5j b20uZXSCDyouZ29vZ2xlLmNvbS5maoIPKi5nb29nbGUuY29tLmdlgg8qLmdvb2ds ZS5jb20uZ2iCDyouZ29vZ2xlLmNvbS5naYIPKi5nb29nbGUuY29tLmdygg8qLmdv b2dsZS5jb20uZ3SCDyouZ29vZ2xlLmNvbS5oa4IPKi5nb29nbGUuY29tLmlxgg8q Lmdvb2dsZS5jb20uam2CDyouZ29vZ2xlLmNvbS5qb4IPKi5nb29nbGUuY29tLmto gg8qLmdvb2dsZS5jb20ua3eCDyouZ29vZ2xlLmNvbS5sYoIPKi5nb29nbGUuY29t Lmx5gg8qLmdvb2dsZS5jb20ubXSCDyouZ29vZ2xlLmNvbS5teIIPKi5nb29nbGUu Y29tLm15gg8qLmdvb2dsZS5jb20ubmGCDyouZ29vZ2xlLmNvbS5uZoIPKi5nb29n bGUuY29tLm5ngg8qLmdvb2dsZS5jb20ubmmCDyouZ29vZ2xlLmNvbS5ucIIPKi5n b29nbGUuY29tLm5ygg8qLmdvb2dsZS5jb20ub22CDyouZ29vZ2xlLmNvbS5wYYIP Ki5nb29nbGUuY29tLnBlgg8qLmdvb2dsZS5jb20ucGiCDyouZ29vZ2xlLmNvbS5w a4IPKi5nb29nbGUuY29tLnBsgg8qLmdvb2dsZS5jb20ucHKCDyouZ29vZ2xlLmNv bS5weYIPKi5nb29nbGUuY29tLnFhgg8qLmdvb2dsZS5jb20ucnWCDyouZ29vZ2xl LmNvbS5zYYIPKi5nb29nbGUuY29tLnNigg8qLmdvb2dsZS5jb20uc2eCDyouZ29v Z2xlLmNvbS5zbIIPKi5nb29nbGUuY29tLnN2gg8qLmdvb2dsZS5jb20udGqCDyou Z29vZ2xlLmNvbS50boIPKi5nb29nbGUuY29tLnRygg8qLmdvb2dsZS5jb20udHeC DyouZ29vZ2xlLmNvbS51YYIPKi5nb29nbGUuY29tLnV5gg8qLmdvb2dsZS5jb20u dmOCDyouZ29vZ2xlLmNvbS52ZYIPKi5nb29nbGUuY29tLnZuggsqLmdvb2dsZS5j doILKi5nb29nbGUuY3qCCyouZ29vZ2xlLmRlggsqLmdvb2dsZS5kaoILKi5nb29n bGUuZGuCCyouZ29vZ2xlLmRtggsqLmdvb2dsZS5keoILKi5nb29nbGUuZWWCCyou Z29vZ2xlLmVzggsqLmdvb2dsZS5maYILKi5nb29nbGUuZm2CCyouZ29vZ2xlLmZy ggsqLmdvb2dsZS5nYYILKi5nb29nbGUuZ2WCCyouZ29vZ2xlLmdnggsqLmdvb2ds ZS5nbIILKi5nb29nbGUuZ22CCyouZ29vZ2xlLmdwggsqLmdvb2dsZS5ncoILKi5n b29nbGUuZ3mCCyouZ29vZ2xlLmhrggsqLmdvb2dsZS5oboILKi5nb29nbGUuaHKC CyouZ29vZ2xlLmh0ggsqLmdvb2dsZS5odYILKi5nb29nbGUuaWWCCyouZ29vZ2xl Lmltgg0qLmdvb2dsZS5pbmZvggsqLmdvb2dsZS5pcYILKi5nb29nbGUuaXOCCyou Z29vZ2xlLml0gg4qLmdvb2dsZS5pdC5hb4ILKi5nb29nbGUuamWCCyouZ29vZ2xl Lmpvgg0qLmdvb2dsZS5qb2JzggsqLmdvb2dsZS5qcIILKi5nb29nbGUua2eCCyou Z29vZ2xlLmtpggsqLmdvb2dsZS5reoILKi5nb29nbGUubGGCCyouZ29vZ2xlLmxp ggsqLmdvb2dsZS5sa4ILKi5nb29nbGUubHSCCyouZ29vZ2xlLmx1ggsqLmdvb2ds ZS5sdoILKi5nb29nbGUubWSCCyouZ29vZ2xlLm1lggsqLmdvb2dsZS5tZ4ILKi5n b29nbGUubWuCCyouZ29vZ2xlLm1sggsqLmdvb2dsZS5tboILKi5nb29nbGUubXOC CyouZ29vZ2xlLm11ggsqLmdvb2dsZS5tdoILKi5nb29nbGUubXeCCyouZ29vZ2xl Lm5lgg4qLmdvb2dsZS5uZS5qcIIMKi5nb29nbGUubmV0ggsqLmdvb2dsZS5ubIIL Ki5nb29nbGUubm+CCyouZ29vZ2xlLm5yggsqLmdvb2dsZS5udYIPKi5nb29nbGUu b2ZmLmFpggsqLmdvb2dsZS5wa4ILKi5nb29nbGUucGyCCyouZ29vZ2xlLnBuggsq Lmdvb2dsZS5wc4ILKi5nb29nbGUucHSCCyouZ29vZ2xlLnJvggsqLmdvb2dsZS5y c4ILKi5nb29nbGUucnWCCyouZ29vZ2xlLnJ3ggsqLmdvb2dsZS5zY4ILKi5nb29n bGUuc2WCCyouZ29vZ2xlLnNoggsqLmdvb2dsZS5zaYILKi5nb29nbGUuc2uCCyou Z29vZ2xlLnNtggsqLmdvb2dsZS5zboILKi5nb29nbGUuc2+CCyouZ29vZ2xlLnN0 ggsqLmdvb2dsZS50ZIILKi5nb29nbGUudGeCCyouZ29vZ2xlLnRrggsqLmdvb2ds ZS50bIILKi5nb29nbGUudG2CCyouZ29vZ2xlLnRuggsqLmdvb2dsZS50b4ILKi5n b29nbGUudHCCCyouZ29vZ2xlLnR0ggsqLmdvb2dsZS51c4ILKi5nb29nbGUudXqC CyouZ29vZ2xlLnZnggsqLmdvb2dsZS52dYILKi5nb29nbGUud3OCCWdvb2dsZS5h Y4IJZ29vZ2xlLmFkgglnb29nbGUuYWWCCWdvb2dsZS5hZoIJZ29vZ2xlLmFnggln b29nbGUuYW2CCWdvb2dsZS5hc4IJZ29vZ2xlLmF0gglnb29nbGUuYXqCCWdvb2ds ZS5iYYIJZ29vZ2xlLmJlgglnb29nbGUuYmaCCWdvb2dsZS5iZ4IJZ29vZ2xlLmJp gglnb29nbGUuYmqCCWdvb2dsZS5ic4IJZ29vZ2xlLmJ5gglnb29nbGUuY2GCCmdv b2dsZS5jYXSCCWdvb2dsZS5jY4IJZ29vZ2xlLmNkgglnb29nbGUuY2aCCWdvb2ds ZS5jZ4IJZ29vZ2xlLmNogglnb29nbGUuY2mCCWdvb2dsZS5jbIIJZ29vZ2xlLmNt gglnb29nbGUuY26CDGdvb2dsZS5jby5hb4IMZ29vZ2xlLmNvLmJ3ggxnb29nbGUu Y28uY2uCDGdvb2dsZS5jby5jcoIMZ29vZ2xlLmNvLmh1ggxnb29nbGUuY28uaWSC DGdvb2dsZS5jby5pbIIMZ29vZ2xlLmNvLmltggxnb29nbGUuY28uaW6CDGdvb2ds ZS5jby5qZYIMZ29vZ2xlLmNvLmpwggxnb29nbGUuY28ua2WCDGdvb2dsZS5jby5r coIMZ29vZ2xlLmNvLmxzggxnb29nbGUuY28ubWGCDGdvb2dsZS5jby5teoIMZ29v Z2xlLmNvLm56ggxnb29nbGUuY28udGiCDGdvb2dsZS5jby50eoIMZ29vZ2xlLmNv LnVnggxnb29nbGUuY28udWuCDGdvb2dsZS5jby51eoIMZ29vZ2xlLmNvLnZlggxn b29nbGUuY28udmmCDGdvb2dsZS5jby56YYIMZ29vZ2xlLmNvLnptggxnb29nbGUu Y28ueneCDWdvb2dsZS5jb20uYWaCDWdvb2dsZS5jb20uYWeCDWdvb2dsZS5jb20u YWmCDWdvb2dsZS5jb20uYXKCDWdvb2dsZS5jb20uYXWCDWdvb2dsZS5jb20uYmSC DWdvb2dsZS5jb20uYmiCDWdvb2dsZS5jb20uYm6CDWdvb2dsZS5jb20uYm+CDWdv b2dsZS5jb20uYnKCDWdvb2dsZS5jb20uYnmCDWdvb2dsZS5jb20uYnqCDWdvb2ds ZS5jb20uY26CDWdvb2dsZS5jb20uY2+CDWdvb2dsZS5jb20uY3WCDWdvb2dsZS5j b20uY3mCDWdvb2dsZS5jb20uZG+CDWdvb2dsZS5jb20uZWOCDWdvb2dsZS5jb20u ZWeCDWdvb2dsZS5jb20uZXSCDWdvb2dsZS5jb20uZmqCDWdvb2dsZS5jb20uZ2WC DWdvb2dsZS5jb20uZ2iCDWdvb2dsZS5jb20uZ2mCDWdvb2dsZS5jb20uZ3KCDWdv b2dsZS5jb20uZ3SCDWdvb2dsZS5jb20uaGuCDWdvb2dsZS5jb20uaXGCDWdvb2ds ZS5jb20uam2CDWdvb2dsZS5jb20uam+CDWdvb2dsZS5jb20ua2iCDWdvb2dsZS5j b20ua3eCDWdvb2dsZS5jb20ubGKCDWdvb2dsZS5jb20ubHmCDWdvb2dsZS5jb20u bXSCDWdvb2dsZS5jb20ubXiCDWdvb2dsZS5jb20ubXmCDWdvb2dsZS5jb20ubmGC DWdvb2dsZS5jb20ubmaCDWdvb2dsZS5jb20ubmeCDWdvb2dsZS5jb20ubmmCDWdv b2dsZS5jb20ubnCCDWdvb2dsZS5jb20ubnKCDWdvb2dsZS5jb20ub22CDWdvb2ds ZS5jb20ucGGCDWdvb2dsZS5jb20ucGWCDWdvb2dsZS5jb20ucGiCDWdvb2dsZS5j b20ucGuCDWdvb2dsZS5jb20ucGyCDWdvb2dsZS5jb20ucHKCDWdvb2dsZS5jb20u cHmCDWdvb2dsZS5jb20ucWGCDWdvb2dsZS5jb20ucnWCDWdvb2dsZS5jb20uc2GC DWdvb2dsZS5jb20uc2KCDWdvb2dsZS5jb20uc2eCDWdvb2dsZS5jb20uc2yCDWdv b2dsZS5jb20uc3aCDWdvb2dsZS5jb20udGqCDWdvb2dsZS5jb20udG6CDWdvb2ds ZS5jb20udHKCDWdvb2dsZS5jb20udHeCDWdvb2dsZS5jb20udWGCDWdvb2dsZS5j b20udXmCDWdvb2dsZS5jb20udmOCDWdvb2dsZS5jb20udmWCDWdvb2dsZS5jb20u dm6CCWdvb2dsZS5jdoIJZ29vZ2xlLmN6gglnb29nbGUuZGWCCWdvb2dsZS5kaoIJ Z29vZ2xlLmRrgglnb29nbGUuZG2CCWdvb2dsZS5keoIJZ29vZ2xlLmVlgglnb29n bGUuZXOCCWdvb2dsZS5maYIJZ29vZ2xlLmZtgglnb29nbGUuZnKCCWdvb2dsZS5n YYIJZ29vZ2xlLmdlgglnb29nbGUuZ2eCCWdvb2dsZS5nbIIJZ29vZ2xlLmdtggln b29nbGUuZ3CCCWdvb2dsZS5ncoIJZ29vZ2xlLmd5gglnb29nbGUuaGuCCWdvb2ds ZS5oboIJZ29vZ2xlLmhygglnb29nbGUuaHSCCWdvb2dsZS5odYIJZ29vZ2xlLmll gglnb29nbGUuaW2CC2dvb2dsZS5pbmZvgglnb29nbGUuaXGCCWdvb2dsZS5pc4IJ Z29vZ2xlLml0ggxnb29nbGUuaXQuYW+CCWdvb2dsZS5qZYIJZ29vZ2xlLmpvggtn b29nbGUuam9ic4IJZ29vZ2xlLmpwgglnb29nbGUua2eCCWdvb2dsZS5raYIJZ29v Z2xlLmt6gglnb29nbGUubGGCCWdvb2dsZS5saYIJZ29vZ2xlLmxrgglnb29nbGUu bHSCCWdvb2dsZS5sdYIJZ29vZ2xlLmx2gglnb29nbGUubWSCCWdvb2dsZS5tZYIJ Z29vZ2xlLm1ngglnb29nbGUubWuCCWdvb2dsZS5tbIIJZ29vZ2xlLm1ugglnb29n bGUubXOCCWdvb2dsZS5tdYIJZ29vZ2xlLm12gglnb29nbGUubXeCCWdvb2dsZS5u ZYIMZ29vZ2xlLm5lLmpwggpnb29nbGUubmV0gglnb29nbGUubmyCCWdvb2dsZS5u b4IJZ29vZ2xlLm5ygglnb29nbGUubnWCDWdvb2dsZS5vZmYuYWmCCWdvb2dsZS5w a4IJZ29vZ2xlLnBsgglnb29nbGUucG6CCWdvb2dsZS5wc4IJZ29vZ2xlLnB0ggln b29nbGUucm+CCWdvb2dsZS5yc4IJZ29vZ2xlLnJ1gglnb29nbGUucneCCWdvb2ds ZS5zY4IJZ29vZ2xlLnNlgglnb29nbGUuc2iCCWdvb2dsZS5zaYIJZ29vZ2xlLnNr gglnb29nbGUuc22CCWdvb2dsZS5zboIJZ29vZ2xlLnNvgglnb29nbGUuc3SCCWdv b2dsZS50ZIIJZ29vZ2xlLnRngglnb29nbGUudGuCCWdvb2dsZS50bIIJZ29vZ2xl LnRtgglnb29nbGUudG6CCWdvb2dsZS50b4IJZ29vZ2xlLnRwgglnb29nbGUudHSC CWdvb2dsZS51c4IJZ29vZ2xlLnV6gglnb29nbGUudmeCCWdvb2dsZS52dYIJZ29v Z2xlLndzMA0GCSqGSIb3DQEBBQUAA4GBAJmZ9RyqpUzrP0UcJnHXoLu/AjIEsIvZ Y9hq/9bLry8InfmvERYHr4hNetkOYlW0FeDZtCpWxdPUgJjmWgKAK6j0goOFavTV GptkL8gha4p1QUsdLkd36/cvBXeBYSle787veo46N1k4V6Uv2gaDVkre786CNsHv Q6MYZ5ClQ+kS -----END CERTIFICATE----- python-netlib-0.9.2/test/data/text_cert_2000066400000000000000000000045331226005331300203530ustar00rootroot00000000000000-----BEGIN CERTIFICATE----- MIIGujCCBaKgAwIBAgIDAQlEMA0GCSqGSIb3DQEBBQUAMIGMMQswCQYDVQQGEwJJ TDEWMBQGA1UEChMNU3RhcnRDb20gTHRkLjErMCkGA1UECxMiU2VjdXJlIERpZ2l0 YWwgQ2VydGlmaWNhdGUgU2lnbmluZzE4MDYGA1UEAxMvU3RhcnRDb20gQ2xhc3Mg MSBQcmltYXJ5IEludGVybWVkaWF0ZSBTZXJ2ZXIgQ0EwHhcNMTAwMTExMTkyNzM2 WhcNMTEwMTEyMDkxNDU1WjCBtDEgMB4GA1UEDRMXMTI2ODMyLU1DeExzWTZUbjFn bTdvOTAxCzAJBgNVBAYTAk5aMR4wHAYDVQQKExVQZXJzb25hIE5vdCBWYWxpZGF0 ZWQxKTAnBgNVBAsTIFN0YXJ0Q29tIEZyZWUgQ2VydGlmaWNhdGUgTWVtYmVyMRgw FgYDVQQDEw93d3cuaW5vZGUuY28ubnoxHjAcBgkqhkiG9w0BCQEWD2ppbUBpbm9k ZS5jby5uejCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAL6ghWlGhqg+ V0P58R3SvLRiO9OrdekDxzmQbKwQcc05frnF5Z9vT6ga7YOuXVeXxhYCAo0nr6KI +y/Lx+QHvP5W0nKbs+svzUQErq2ZZFwhh1e1LbVccrNwkHUzKOq0TTaVdU4k8kDQ zzYF9tTZb+G5Hv1BJjpwYwe8P4cAiPJPrFFOKTySzHqiYsXlx+vR1l1e3zKavhd+ LVSoLWWXb13yKODq6vnuiHjUJXl8CfVlBhoGotXU4JR5cbuGoW/8+rkwEdX+YoCv VCqgdx9IkRFB6uWfN6ocUiFvhA0eknO+ewuVfRLiIaSDB8pNyUWVqu4ngFWtWO1O YZg0I/32BkcCAwEAAaOCAvkwggL1MAkGA1UdEwQCMAAwCwYDVR0PBAQDAgOoMBMG A1UdJQQMMAoGCCsGAQUFBwMBMB0GA1UdDgQWBBQfaL2Rj6r8iRlBTgppgE7ZZ5WT UzAfBgNVHSMEGDAWgBTrQjTQmLCrn/Qbawj3zGQu7w4sRTAnBgNVHREEIDAegg93 d3cuaW5vZGUuY28ubnqCC2lub2RlLmNvLm56MIIBQgYDVR0gBIIBOTCCATUwggEx BgsrBgEEAYG1NwECATCCASAwLgYIKwYBBQUHAgEWImh0dHA6Ly93d3cuc3RhcnRz c2wuY29tL3BvbGljeS5wZGYwNAYIKwYBBQUHAgEWKGh0dHA6Ly93d3cuc3RhcnRz c2wuY29tL2ludGVybWVkaWF0ZS5wZGYwgbcGCCsGAQUFBwICMIGqMBQWDVN0YXJ0 Q29tIEx0ZC4wAwIBARqBkUxpbWl0ZWQgTGlhYmlsaXR5LCBzZWUgc2VjdGlvbiAq TGVnYWwgTGltaXRhdGlvbnMqIG9mIHRoZSBTdGFydENvbSBDZXJ0aWZpY2F0aW9u IEF1dGhvcml0eSBQb2xpY3kgYXZhaWxhYmxlIGF0IGh0dHA6Ly93d3cuc3RhcnRz c2wuY29tL3BvbGljeS5wZGYwYQYDVR0fBFowWDAqoCigJoYkaHR0cDovL3d3dy5z dGFydHNzbC5jb20vY3J0MS1jcmwuY3JsMCqgKKAmhiRodHRwOi8vY3JsLnN0YXJ0 c3NsLmNvbS9jcnQxLWNybC5jcmwwgY4GCCsGAQUFBwEBBIGBMH8wOQYIKwYBBQUH MAGGLWh0dHA6Ly9vY3NwLnN0YXJ0c3NsLmNvbS9zdWIvY2xhc3MxL3NlcnZlci9j YTBCBggrBgEFBQcwAoY2aHR0cDovL3d3dy5zdGFydHNzbC5jb20vY2VydHMvc3Vi LmNsYXNzMS5zZXJ2ZXIuY2EuY3J0MCMGA1UdEgQcMBqGGGh0dHA6Ly93d3cuc3Rh cnRzc2wuY29tLzANBgkqhkiG9w0BAQUFAAOCAQEAivWID0KT8q1EzWzy+BecsFry hQhuLFfAsPkHqpNd9OfkRStGBuJlLX+9DQ9TzjqutdY2buNBuDn71buZK+Y5fmjr 28rAT6+WMd+KnCl5WLT5IOS6Z9s3cec5TFQbmOGlepSS9Q6Ts9KsXOHHQvDkQeDq OV2UqdgXIAyFm5efSL9JXPXntRausNu2s8F2B2rRJe4jPfnUy2LvY8OW1YvjUA++ vpdWRdfUbJQp55mRfaYMPRnyUm30lAI27QaxgQPFOqDeZUm5llb5eFG/B3f87uhg +Y1oEykbEvZrIFN4hithioQ0tb+57FKkkG2sW3uemNiQw2qrEo/GAMb1cI50Rg== -----END CERTIFICATE----- python-netlib-0.9.2/test/data/text_cert_weird1000066400000000000000000000035131226005331300214020ustar00rootroot00000000000000-----BEGIN CERTIFICATE----- MIIFNDCCBBygAwIBAgIEDFJFNzANBgkqhkiG9w0BAQUFADCBjDELMAkGA1UEBhMC REUxHjAcBgNVBAoTFVVuaXZlcnNpdGFldCBNdWVuc3RlcjE6MDgGA1UEAxMxWmVy dGlmaXppZXJ1bmdzc3RlbGxlIFVuaXZlcnNpdGFldCBNdWVuc3RlciAtIEcwMjEh MB8GCSqGSIb3DQEJARYSY2FAdW5pLW11ZW5zdGVyLmRlMB4XDTA4MDUyMDEyNDQy NFoXDTEzMDUxOTEyNDQyNFowezELMAkGA1UEBhMCREUxHjAcBgNVBAoTFVVuaXZl cnNpdGFldCBNdWVuc3RlcjEuMCwGA1UECxMlWmVudHJ1bSBmdWVyIEluZm9ybWF0 aW9uc3ZlcmFyYmVpdHVuZzEcMBoGA1UEAxMTd3d3LnVuaS1tdWVuc3Rlci5kZTCC ASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMM0WlCj0ew+tyZ1GurBOqFn AlChKk4S1F9oDzvp3FwOON4H8YFET7p9ZnoWtkfXSlGNMjekqy67dFlLt1sLusSo tjNdaOrDLYmnGEgnYAT0RFBvErzIybJoD/Vu3NXyhes+L94R9mEMCwYXmSvG51H9 c5CvguXBofMchDLCM/U6AYpwu3sST5orV3S1Rsa9sndj8sKJAcw195PYwl6EiEBb M36ltDBlTYEUAg3Z+VSzB09J3U4vSvguVkDCz+szZh5RG3xlN9mlNfzhf4lHrNgV 0BRbKypa5Uuf81wbMcMMqTxKq+A9ysObpn9J3pNUym+Tn2oqHzGgvwZYB4tzXqUC AwEAAaOCAawwggGoMAkGA1UdEwQCMAAwCwYDVR0PBAQDAgTwMBMGA1UdJQQMMAoG CCsGAQUFBwMBMB0GA1UdDgQWBBQ3RFo8awewUTq5TpOFf3jOCEKihzAfBgNVHSME GDAWgBS+nlGiyZJ8u2CL5rBoZHdaUhmhADAjBgNVHREEHDAagRh3d3dhZG1pbkB1 bmktbXVlbnN0ZXIuZGUwewYDVR0fBHQwcjA3oDWgM4YxaHR0cDovL2NkcDEucGNh LmRmbi5kZS93d3UtY2EvcHViL2NybC9nX2NhY3JsLmNybDA3oDWgM4YxaHR0cDov L2NkcDIucGNhLmRmbi5kZS93d3UtY2EvcHViL2NybC9nX2NhY3JsLmNybDCBlgYI KwYBBQUHAQEEgYkwgYYwQQYIKwYBBQUHMAKGNWh0dHA6Ly9jZHAxLnBjYS5kZm4u ZGUvd3d1LWNhL3B1Yi9jYWNlcnQvZ19jYWNlcnQuY3J0MEEGCCsGAQUFBzAChjVo dHRwOi8vY2RwMi5wY2EuZGZuLmRlL3d3dS1jYS9wdWIvY2FjZXJ0L2dfY2FjZXJ0 LmNydDANBgkqhkiG9w0BAQUFAAOCAQEAFfNpagtcKUSDKss7TcqjYn99FQ4FtWjE pGmzYL2zX2wsdCGoVQlGkieL9slbQVEUAnBuqM1LPzUNNe9kZpOPV3Rdhq4y8vyS xkx3G1v5aGxfPUe8KM8yKIOHRqYefNronHJM0fw7KyjQ73xgbIEgkW+kNXaMLcrb EPC36O2Zna8GP9FQxJRLgcfQCcYdRKGVn0EtRSkz2ym5Rbh/hrmJBbbC2yJGGMI0 Vu5A9piK0EZPekZIUmhMQynD9QcMfWhTEFr7YZfx9ktxKDW4spnu7YrgICfZNcCm tfxmnEAFt6a47u9P0w9lpY8+Sx9MNFfTePym+HP4TYha9bIBes+XnA== -----END CERTIFICATE----- python-netlib-0.9.2/test/test_certutils.py000066400000000000000000000053121226005331300207200ustar00rootroot00000000000000import os from netlib import certutils import tutils def test_dummy_ca(): with tutils.tmpdir() as d: path = os.path.join(d, "foo/cert.cnf") assert certutils.dummy_ca(path) assert os.path.exists(path) path = os.path.join(d, "foo/cert2.pem") assert certutils.dummy_ca(path) assert os.path.exists(path) assert os.path.exists(os.path.join(d, "foo/cert2-cert.pem")) assert os.path.exists(os.path.join(d, "foo/cert2-cert.p12")) class TestCertStore: def test_create_explicit(self): with tutils.tmpdir() as d: ca = os.path.join(d, "ca") assert certutils.dummy_ca(ca) c = certutils.CertStore() def test_create_tmp(self): with tutils.tmpdir() as d: ca = os.path.join(d, "ca") assert certutils.dummy_ca(ca) c = certutils.CertStore() assert c.get_cert("foo.com", [], ca) assert c.get_cert("foo.com", [], ca) assert c.get_cert("*.foo.com", [], ca) def test_check_domain(self): c = certutils.CertStore() assert c.check_domain("foo") assert c.check_domain("\x01foo") assert not c.check_domain("\xfefoo") assert not c.check_domain("xn--\0") assert not c.check_domain("foo..foo") assert not c.check_domain("foo/foo") class TestDummyCert: def test_with_ca(self): with tutils.tmpdir() as d: cacert = os.path.join(d, "cacert") assert certutils.dummy_ca(cacert) r = certutils.dummy_cert( cacert, "foo.com", ["one.com", "two.com", "*.three.com"] ) assert r.cn == "foo.com" class TestSSLCert: def test_simple(self): c = certutils.SSLCert.from_pem(file(tutils.test_data.path("data/text_cert"), "rb").read()) assert c.cn == "google.com" assert len(c.altnames) == 436 c = certutils.SSLCert.from_pem(file(tutils.test_data.path("data/text_cert_2"), "rb").read()) assert c.cn == "www.inode.co.nz" assert len(c.altnames) == 2 assert c.digest("sha1") assert c.notbefore assert c.notafter assert c.subject assert c.keyinfo == ("RSA", 2048) assert c.serial assert c.issuer assert c.to_pem() c.has_expired def test_err_broken_sans(self): c = certutils.SSLCert.from_pem(file(tutils.test_data.path("data/text_cert_weird1"), "rb").read()) # This breaks unless we ignore a decoding error. c.altnames def test_der(self): d = file(tutils.test_data.path("data/dercert"),"rb").read() s = certutils.SSLCert.from_der(d) assert s.cn python-netlib-0.9.2/test/test_http.py000066400000000000000000000231751226005331300176700ustar00rootroot00000000000000import cStringIO, textwrap, binascii from netlib import http, odict import tutils def test_httperror(): e = http.HttpError(404, "Not found") assert str(e) def test_has_chunked_encoding(): h = odict.ODictCaseless() assert not http.has_chunked_encoding(h) h["transfer-encoding"] = ["chunked"] assert http.has_chunked_encoding(h) def test_read_chunked(): s = cStringIO.StringIO("1\r\na\r\n0\r\n") tutils.raises("closed prematurely", http.read_chunked, 500, s, None) s = cStringIO.StringIO("1\r\na\r\n0\r\n\r\n") assert http.read_chunked(500, s, None) == "a" s = cStringIO.StringIO("\r\n\r\n1\r\na\r\n0\r\n\r\n") assert http.read_chunked(500, s, None) == "a" s = cStringIO.StringIO("\r\n") tutils.raises("closed prematurely", http.read_chunked, 500, s, None) s = cStringIO.StringIO("1\r\nfoo") tutils.raises("malformed chunked body", http.read_chunked, 500, s, None) s = cStringIO.StringIO("foo\r\nfoo") tutils.raises(http.HttpError, http.read_chunked, 500, s, None) s = cStringIO.StringIO("5\r\naaaaa\r\n0\r\n\r\n") tutils.raises("too large", http.read_chunked, 500, s, 2) def test_request_connection_close(): h = odict.ODictCaseless() assert http.request_connection_close((1, 0), h) assert not http.request_connection_close((1, 1), h) h["connection"] = ["keep-alive"] assert not http.request_connection_close((1, 1), h) h["connection"] = ["close"] assert http.request_connection_close((1, 1), h) def test_response_connection_close(): h = odict.ODictCaseless() assert http.response_connection_close((1, 1), h) h["content-length"] = [10] assert not http.response_connection_close((1, 1), h) h["connection"] = ["close"] assert http.response_connection_close((1, 1), h) def test_read_http_body_response(): h = odict.ODictCaseless() h["content-length"] = [7] s = cStringIO.StringIO("testing") assert http.read_http_body_response(s, h, None) == "testing" h = odict.ODictCaseless() s = cStringIO.StringIO("testing") assert not http.read_http_body_response(s, h, None) h = odict.ODictCaseless() h["connection"] = ["close"] s = cStringIO.StringIO("testing") assert http.read_http_body_response(s, h, None) == "testing" def test_get_header_tokens(): h = odict.ODictCaseless() assert http.get_header_tokens(h, "foo") == [] h["foo"] = ["bar"] assert http.get_header_tokens(h, "foo") == ["bar"] h["foo"] = ["bar, voing"] assert http.get_header_tokens(h, "foo") == ["bar", "voing"] h["foo"] = ["bar, voing", "oink"] assert http.get_header_tokens(h, "foo") == ["bar", "voing", "oink"] def test_read_http_body_request(): h = odict.ODictCaseless() h["expect"] = ["100-continue"] r = cStringIO.StringIO("testing") w = cStringIO.StringIO() assert http.read_http_body_request(r, w, h, (1, 1), None) == "" assert "100 Continue" in w.getvalue() def test_read_http_body(): h = odict.ODictCaseless() s = cStringIO.StringIO("testing") assert http.read_http_body(500, s, h, False, None) == "" h["content-length"] = ["foo"] s = cStringIO.StringIO("testing") tutils.raises(http.HttpError, http.read_http_body, 500, s, h, False, None) h["content-length"] = [5] s = cStringIO.StringIO("testing") assert len(http.read_http_body(500, s, h, False, None)) == 5 s = cStringIO.StringIO("testing") tutils.raises(http.HttpError, http.read_http_body, 500, s, h, False, 4) h = odict.ODictCaseless() s = cStringIO.StringIO("testing") assert len(http.read_http_body(500, s, h, True, 4)) == 4 s = cStringIO.StringIO("testing") assert len(http.read_http_body(500, s, h, True, 100)) == 7 h = odict.ODictCaseless() h["transfer-encoding"] = ["chunked"] s = cStringIO.StringIO("5\r\naaaaa\r\n0\r\n\r\n") assert http.read_http_body(500, s, h, True, 100) == "aaaaa" def test_parse_http_protocol(): assert http.parse_http_protocol("HTTP/1.1") == (1, 1) assert http.parse_http_protocol("HTTP/0.0") == (0, 0) assert not http.parse_http_protocol("HTTP/a.1") assert not http.parse_http_protocol("HTTP/1.a") assert not http.parse_http_protocol("foo/0.0") assert not http.parse_http_protocol("HTTP/x") def test_parse_init_connect(): assert http.parse_init_connect("CONNECT host.com:443 HTTP/1.0") assert not http.parse_init_connect("C\xfeONNECT host.com:443 HTTP/1.0") assert not http.parse_init_connect("CONNECT \0host.com:443 HTTP/1.0") assert not http.parse_init_connect("CONNECT host.com:444444 HTTP/1.0") assert not http.parse_init_connect("bogus") assert not http.parse_init_connect("GET host.com:443 HTTP/1.0") assert not http.parse_init_connect("CONNECT host.com443 HTTP/1.0") assert not http.parse_init_connect("CONNECT host.com:443 foo/1.0") assert not http.parse_init_connect("CONNECT host.com:foo HTTP/1.0") def test_parse_init_proxy(): u = "GET http://foo.com:8888/test HTTP/1.1" m, s, h, po, pa, httpversion = http.parse_init_proxy(u) assert m == "GET" assert s == "http" assert h == "foo.com" assert po == 8888 assert pa == "/test" assert httpversion == (1, 1) u = "G\xfeET http://foo.com:8888/test HTTP/1.1" assert not http.parse_init_proxy(u) assert not http.parse_init_proxy("invalid") assert not http.parse_init_proxy("GET invalid HTTP/1.1") assert not http.parse_init_proxy("GET http://foo.com:8888/test foo/1.1") def test_parse_init_http(): u = "GET /test HTTP/1.1" m, u, httpversion = http.parse_init_http(u) assert m == "GET" assert u == "/test" assert httpversion == (1, 1) u = "G\xfeET /test HTTP/1.1" assert not http.parse_init_http(u) assert not http.parse_init_http("invalid") assert not http.parse_init_http("GET invalid HTTP/1.1") assert not http.parse_init_http("GET /test foo/1.1") assert not http.parse_init_http("GET /test\xc0 HTTP/1.1") class TestReadHeaders: def _read(self, data, verbatim=False): if not verbatim: data = textwrap.dedent(data) data = data.strip() s = cStringIO.StringIO(data) return http.read_headers(s) def test_read_simple(self): data = """ Header: one Header2: two \r\n """ h = self._read(data) assert h.lst == [["Header", "one"], ["Header2", "two"]] def test_read_multi(self): data = """ Header: one Header: two \r\n """ h = self._read(data) assert h.lst == [["Header", "one"], ["Header", "two"]] def test_read_continued(self): data = """ Header: one \ttwo Header2: three \r\n """ h = self._read(data) assert h.lst == [["Header", "one\r\n two"], ["Header2", "three"]] def test_read_continued_err(self): data = "\tfoo: bar\r\n" assert self._read(data, True) is None def test_read_err(self): data = """ foo """ assert self._read(data) is None def test_read_response(): def tst(data, method, limit): data = textwrap.dedent(data) r = cStringIO.StringIO(data) return http.read_response(r, method, limit) tutils.raises("server disconnect", tst, "", "GET", None) tutils.raises("invalid server response", tst, "foo", "GET", None) data = """ HTTP/1.1 200 OK """ assert tst(data, "GET", None) == ((1, 1), 200, 'OK', odict.ODictCaseless(), '') data = """ HTTP/1.1 200 """ assert tst(data, "GET", None) == ((1, 1), 200, '', odict.ODictCaseless(), '') data = """ HTTP/x 200 OK """ tutils.raises("invalid http version", tst, data, "GET", None) data = """ HTTP/1.1 xx OK """ tutils.raises("invalid server response", tst, data, "GET", None) data = """ HTTP/1.1 100 CONTINUE HTTP/1.1 200 OK """ assert tst(data, "GET", None) == ((1, 1), 200, 'OK', odict.ODictCaseless(), '') data = """ HTTP/1.1 200 OK Content-Length: 3 foo """ assert tst(data, "GET", None)[4] == 'foo' assert tst(data, "HEAD", None)[4] == '' data = """ HTTP/1.1 200 OK \tContent-Length: 3 foo """ tutils.raises("invalid headers", tst, data, "GET", None) def test_parse_url(): assert not http.parse_url("") u = "http://foo.com:8888/test" s, h, po, pa = http.parse_url(u) assert s == "http" assert h == "foo.com" assert po == 8888 assert pa == "/test" s, h, po, pa = http.parse_url("http://foo/bar") assert s == "http" assert h == "foo" assert po == 80 assert pa == "/bar" s, h, po, pa = http.parse_url("http://foo") assert pa == "/" s, h, po, pa = http.parse_url("https://foo") assert po == 443 assert not http.parse_url("https://foo:bar") assert not http.parse_url("https://foo:") # Invalid IDNA assert not http.parse_url("http://\xfafoo") # Invalid PATH assert not http.parse_url("http:/\xc6/localhost:56121") # Null byte in host assert not http.parse_url("http://foo\0") # Port out of range assert not http.parse_url("http://foo:999999") # Invalid IPv6 URL - see http://www.ietf.org/rfc/rfc2732.txt assert not http.parse_url('http://lo[calhost') def test_parse_http_basic_auth(): vals = ("basic", "foo", "bar") assert http.parse_http_basic_auth(http.assemble_http_basic_auth(*vals)) == vals assert not http.parse_http_basic_auth("") assert not http.parse_http_basic_auth("foo bar") v = "basic " + binascii.b2a_base64("foo") assert not http.parse_http_basic_auth(v) python-netlib-0.9.2/test/test_http_auth.py000066400000000000000000000047631226005331300207130ustar00rootroot00000000000000import binascii, cStringIO from netlib import odict, http_auth, http import tutils class TestPassManNonAnon: def test_simple(self): p = http_auth.PassManNonAnon() assert not p.test("", "") assert p.test("user", "") class TestPassManHtpasswd: def test_file_errors(self): s = cStringIO.StringIO("foo") tutils.raises("invalid htpasswd", http_auth.PassManHtpasswd, s) s = cStringIO.StringIO("foo:bar$foo") tutils.raises("invalid htpasswd", http_auth.PassManHtpasswd, s) def test_simple(self): f = open(tutils.test_data.path("data/htpasswd")) pm = http_auth.PassManHtpasswd(f) vals = ("basic", "test", "test") p = http.assemble_http_basic_auth(*vals) assert pm.test("test", "test") assert not pm.test("test", "foo") assert not pm.test("foo", "test") assert not pm.test("test", "") assert not pm.test("", "") class TestPassManSingleUser: def test_simple(self): pm = http_auth.PassManSingleUser("test", "test") assert pm.test("test", "test") assert not pm.test("test", "foo") assert not pm.test("foo", "test") class TestNullProxyAuth: def test_simple(self): na = http_auth.NullProxyAuth(http_auth.PassManNonAnon()) assert not na.auth_challenge_headers() assert na.authenticate("foo") na.clean({}) class TestBasicProxyAuth: def test_simple(self): ba = http_auth.BasicProxyAuth(http_auth.PassManNonAnon(), "test") h = odict.ODictCaseless() assert ba.auth_challenge_headers() assert not ba.authenticate(h) def test_authenticate_clean(self): ba = http_auth.BasicProxyAuth(http_auth.PassManNonAnon(), "test") hdrs = odict.ODictCaseless() vals = ("basic", "foo", "bar") hdrs[ba.AUTH_HEADER] = [http.assemble_http_basic_auth(*vals)] assert ba.authenticate(hdrs) ba.clean(hdrs) assert not ba.AUTH_HEADER in hdrs hdrs[ba.AUTH_HEADER] = [""] assert not ba.authenticate(hdrs) hdrs[ba.AUTH_HEADER] = ["foo"] assert not ba.authenticate(hdrs) vals = ("foo", "foo", "bar") hdrs[ba.AUTH_HEADER] = [http.assemble_http_basic_auth(*vals)] assert not ba.authenticate(hdrs) ba = http_auth.BasicProxyAuth(http_auth.PassMan(), "test") vals = ("basic", "foo", "bar") hdrs[ba.AUTH_HEADER] = [http.assemble_http_basic_auth(*vals)] assert not ba.authenticate(hdrs) python-netlib-0.9.2/test/test_http_uastrings.py000066400000000000000000000002571226005331300217630ustar00rootroot00000000000000from netlib import http_uastrings def test_get_shortcut(): assert http_uastrings.get_by_shortcut("c")[0] == "chrome" assert not http_uastrings.get_by_shortcut("_") python-netlib-0.9.2/test/test_imports.py000066400000000000000000000001141226005331300203720ustar00rootroot00000000000000# These are actually tests! import netlib.http_status import netlib.version python-netlib-0.9.2/test/test_odict.py000066400000000000000000000077531226005331300200170ustar00rootroot00000000000000from netlib import odict import tutils class TestODict: def setUp(self): self.od = odict.ODict() def test_str_err(self): h = odict.ODict() tutils.raises(ValueError, h.__setitem__, "key", "foo") def test_dictToHeader1(self): self.od.add("one", "uno") self.od.add("two", "due") self.od.add("two", "tre") expected = [ "one: uno\r\n", "two: due\r\n", "two: tre\r\n", "\r\n" ] out = repr(self.od) for i in expected: assert out.find(i) >= 0 def test_dictToHeader2(self): self.od["one"] = ["uno"] expected1 = "one: uno\r\n" expected2 = "\r\n" out = repr(self.od) assert out.find(expected1) >= 0 assert out.find(expected2) >= 0 def test_match_re(self): h = odict.ODict() h.add("one", "uno") h.add("two", "due") h.add("two", "tre") assert h.match_re("uno") assert h.match_re("two: due") assert not h.match_re("nonono") def test_getset_state(self): self.od.add("foo", 1) self.od.add("foo", 2) self.od.add("bar", 3) state = self.od._get_state() nd = odict.ODict._from_state(state) assert nd == self.od def test_in_any(self): self.od["one"] = ["atwoa", "athreea"] assert self.od.in_any("one", "two") assert self.od.in_any("one", "three") assert not self.od.in_any("one", "four") assert not self.od.in_any("nonexistent", "foo") assert not self.od.in_any("one", "TWO") assert self.od.in_any("one", "TWO", True) def test_iter(self): assert not [i for i in self.od] self.od.add("foo", 1) assert [i for i in self.od] def test_keys(self): assert not self.od.keys() self.od.add("foo", 1) assert self.od.keys() == ["foo"] self.od.add("foo", 2) assert self.od.keys() == ["foo"] self.od.add("bar", 2) assert len(self.od.keys()) == 2 def test_copy(self): self.od.add("foo", 1) self.od.add("foo", 2) self.od.add("bar", 3) assert self.od == self.od.copy() def test_del(self): self.od.add("foo", 1) self.od.add("Foo", 2) self.od.add("bar", 3) del self.od["foo"] assert len(self.od.lst) == 2 def test_replace(self): self.od.add("one", "two") self.od.add("two", "one") assert self.od.replace("one", "vun") == 2 assert self.od.lst == [ ["vun", "two"], ["two", "vun"], ] def test_get(self): self.od.add("one", "two") assert self.od.get("one") == ["two"] assert self.od.get("two") == None def test_get_first(self): self.od.add("one", "two") self.od.add("one", "three") assert self.od.get_first("one") == "two" assert self.od.get_first("two") == None class TestODictCaseless: def setUp(self): self.od = odict.ODictCaseless() def test_override(self): o = odict.ODictCaseless() o.add('T', 'application/x-www-form-urlencoded; charset=UTF-8') o["T"] = ["foo"] assert o["T"] == ["foo"] def test_case_preservation(self): self.od["Foo"] = ["1"] assert "foo" in self.od assert self.od.items()[0][0] == "Foo" assert self.od.get("foo") == ["1"] assert self.od.get("foo", [""]) == ["1"] assert self.od.get("Foo", [""]) == ["1"] assert self.od.get("xx", "yy") == "yy" def test_del(self): self.od.add("foo", 1) self.od.add("Foo", 2) self.od.add("bar", 3) del self.od["foo"] assert len(self.od) == 1 def test_keys(self): assert not self.od.keys() self.od.add("foo", 1) assert self.od.keys() == ["foo"] self.od.add("Foo", 2) assert self.od.keys() == ["foo"] self.od.add("bar", 2) assert len(self.od.keys()) == 2 python-netlib-0.9.2/test/test_tcp.py000066400000000000000000000234141226005331300174730ustar00rootroot00000000000000import cStringIO, Queue, time, socket from netlib import tcp, certutils, test import mock import tutils class SNIHandler(tcp.BaseHandler): sni = None def handle_sni(self, connection): self.sni = connection.get_servername() def handle(self): self.wfile.write(self.sni) self.wfile.flush() class EchoHandler(tcp.BaseHandler): sni = None def handle_sni(self, connection): self.sni = connection.get_servername() def handle(self): v = self.rfile.readline() self.wfile.write(v) self.wfile.flush() class CertHandler(tcp.BaseHandler): sni = None def handle_sni(self, connection): self.sni = connection.get_servername() def handle(self): self.wfile.write("%s\n"%self.clientcert.serial) self.wfile.flush() class DisconnectHandler(tcp.BaseHandler): def handle(self): self.close() class HangHandler(tcp.BaseHandler): def handle(self): while 1: time.sleep(1) class TimeoutHandler(tcp.BaseHandler): def handle(self): self.timeout = False self.settimeout(0.01) try: self.rfile.read(10) except tcp.NetLibTimeout: self.timeout = True class TestServer(test.ServerTestBase): handler = EchoHandler def test_echo(self): testval = "echo!\n" c = tcp.TCPClient("127.0.0.1", self.port) c.connect() c.wfile.write(testval) c.wfile.flush() assert c.rfile.readline() == testval class FinishFailHandler(tcp.BaseHandler): def handle(self): v = self.rfile.readline() self.wfile.write(v) self.wfile.flush() o = mock.MagicMock() self.wfile.close() self.rfile.close() self.close = mock.MagicMock(side_effect=socket.error) class TestFinishFail(test.ServerTestBase): """ This tests a difficult-to-trigger exception in the .finish() method of the handler. """ handler = FinishFailHandler def test_disconnect_in_finish(self): testval = "echo!\n" c = tcp.TCPClient("127.0.0.1", self.port) c.connect() c.wfile.write("foo\n") c.wfile.flush() c.rfile.read(4) h = self.last_handler h.finish() class TestDisconnect(test.ServerTestBase): handler = EchoHandler def test_echo(self): testval = "echo!\n" c = tcp.TCPClient("127.0.0.1", self.port) c.connect() c.wfile.write(testval) c.wfile.flush() assert c.rfile.readline() == testval class TestServerSSL(test.ServerTestBase): handler = EchoHandler ssl = dict( cert = tutils.test_data.path("data/server.crt"), key = tutils.test_data.path("data/server.key"), request_client_cert = False, v3_only = False ) def test_echo(self): c = tcp.TCPClient("127.0.0.1", self.port) c.connect() c.convert_to_ssl(sni="foo.com", options=tcp.OP_ALL) testval = "echo!\n" c.wfile.write(testval) c.wfile.flush() assert c.rfile.readline() == testval def test_get_remote_cert(self): assert certutils.get_remote_cert("127.0.0.1", self.port, None).digest("sha1") class TestSSLv3Only(test.ServerTestBase): handler = EchoHandler ssl = dict( cert = tutils.test_data.path("data/server.crt"), key = tutils.test_data.path("data/server.key"), request_client_cert = False, v3_only = True ) def test_failure(self): c = tcp.TCPClient("127.0.0.1", self.port) c.connect() tutils.raises(tcp.NetLibError, c.convert_to_ssl, sni="foo.com", method=tcp.TLSv1_METHOD) class TestSSLClientCert(test.ServerTestBase): handler = CertHandler ssl = dict( cert = tutils.test_data.path("data/server.crt"), key = tutils.test_data.path("data/server.key"), request_client_cert = True, v3_only = False ) def test_clientcert(self): c = tcp.TCPClient("127.0.0.1", self.port) c.connect() c.convert_to_ssl(cert=tutils.test_data.path("data/clientcert/client.pem")) assert c.rfile.readline().strip() == "1" def test_clientcert_err(self): c = tcp.TCPClient("127.0.0.1", self.port) c.connect() tutils.raises( tcp.NetLibError, c.convert_to_ssl, cert=tutils.test_data.path("data/clientcert/make") ) class TestSNI(test.ServerTestBase): handler = SNIHandler ssl = dict( cert = tutils.test_data.path("data/server.crt"), key = tutils.test_data.path("data/server.key"), request_client_cert = False, v3_only = False ) def test_echo(self): c = tcp.TCPClient("127.0.0.1", self.port) c.connect() c.convert_to_ssl(sni="foo.com") assert c.rfile.readline() == "foo.com" class TestSSLDisconnect(test.ServerTestBase): handler = DisconnectHandler ssl = dict( cert = tutils.test_data.path("data/server.crt"), key = tutils.test_data.path("data/server.key"), request_client_cert = False, v3_only = False ) def test_echo(self): c = tcp.TCPClient("127.0.0.1", self.port) c.connect() c.convert_to_ssl() # Excercise SSL.ZeroReturnError c.rfile.read(10) c.close() tutils.raises(tcp.NetLibDisconnect, c.wfile.write, "foo") tutils.raises(Queue.Empty, self.q.get_nowait) class TestDisconnect(test.ServerTestBase): def test_echo(self): c = tcp.TCPClient("127.0.0.1", self.port) c.connect() c.rfile.read(10) c.wfile.write("foo") c.close() c.close() class TestServerTimeOut(test.ServerTestBase): handler = TimeoutHandler def test_timeout(self): c = tcp.TCPClient("127.0.0.1", self.port) c.connect() time.sleep(0.3) assert self.last_handler.timeout class TestTimeOut(test.ServerTestBase): handler = HangHandler def test_timeout(self): c = tcp.TCPClient("127.0.0.1", self.port) c.connect() c.settimeout(0.1) assert c.gettimeout() == 0.1 tutils.raises(tcp.NetLibTimeout, c.rfile.read, 10) class TestSSLTimeOut(test.ServerTestBase): handler = HangHandler ssl = dict( cert = tutils.test_data.path("data/server.crt"), key = tutils.test_data.path("data/server.key"), request_client_cert = False, v3_only = False ) def test_timeout_client(self): c = tcp.TCPClient("127.0.0.1", self.port) c.connect() c.convert_to_ssl() c.settimeout(0.1) tutils.raises(tcp.NetLibTimeout, c.rfile.read, 10) class TestTCPClient: def test_conerr(self): c = tcp.TCPClient("127.0.0.1", 0) tutils.raises(tcp.NetLibError, c.connect) class TestFileLike: def test_blocksize(self): s = cStringIO.StringIO("1234567890abcdefghijklmnopqrstuvwxyz") s = tcp.Reader(s) s.BLOCKSIZE = 2 assert s.read(1) == "1" assert s.read(2) == "23" assert s.read(3) == "456" assert s.read(4) == "7890" d = s.read(-1) assert d.startswith("abc") and d.endswith("xyz") def test_wrap(self): s = cStringIO.StringIO("foobar\nfoobar") s.flush() s = tcp.Reader(s) assert s.readline() == "foobar\n" assert s.readline() == "foobar" # Test __getattr__ assert s.isatty def test_limit(self): s = cStringIO.StringIO("foobar\nfoobar") s = tcp.Reader(s) assert s.readline(3) == "foo" def test_limitless(self): s = cStringIO.StringIO("f"*(50*1024)) s = tcp.Reader(s) ret = s.read(-1) assert len(ret) == 50 * 1024 def test_readlog(self): s = cStringIO.StringIO("foobar\nfoobar") s = tcp.Reader(s) assert not s.is_logging() s.start_log() assert s.is_logging() s.readline() assert s.get_log() == "foobar\n" s.read(1) assert s.get_log() == "foobar\nf" s.start_log() assert s.get_log() == "" s.read(1) assert s.get_log() == "o" s.stop_log() tutils.raises(ValueError, s.get_log) def test_writelog(self): s = cStringIO.StringIO() s = tcp.Writer(s) s.start_log() assert s.is_logging() s.write("x") assert s.get_log() == "x" s.write("x") assert s.get_log() == "xx" def test_writer_flush_error(self): s = cStringIO.StringIO() s = tcp.Writer(s) o = mock.MagicMock() o.flush = mock.MagicMock(side_effect=socket.error) s.o = o tutils.raises(tcp.NetLibDisconnect, s.flush) def test_reader_read_error(self): s = cStringIO.StringIO("foobar\nfoobar") s = tcp.Reader(s) o = mock.MagicMock() o.read = mock.MagicMock(side_effect=socket.error) s.o = o tutils.raises(tcp.NetLibDisconnect, s.read, 10) def test_reset_timestamps(self): s = cStringIO.StringIO("foobar\nfoobar") s = tcp.Reader(s) s.first_byte_timestamp = 500 s.reset_timestamps() assert not s.first_byte_timestamp def test_first_byte_timestamp_updated_on_read(self): s = cStringIO.StringIO("foobar\nfoobar") s = tcp.Reader(s) s.read(1) assert s.first_byte_timestamp expected = s.first_byte_timestamp s.read(5) assert s.first_byte_timestamp == expected def test_first_byte_timestamp_updated_on_readline(self): s = cStringIO.StringIO("foobar\nfoobar\nfoobar") s = tcp.Reader(s) s.readline() assert s.first_byte_timestamp expected = s.first_byte_timestamp s.readline() assert s.first_byte_timestamp == expected python-netlib-0.9.2/test/test_utils.py000066400000000000000000000004371226005331300200450ustar00rootroot00000000000000from netlib import utils def test_hexdump(): assert utils.hexdump("one\0"*10) def test_cleanBin(): assert utils.cleanBin("one") == "one" assert utils.cleanBin("\00ne") == ".ne" assert utils.cleanBin("\nne") == "\nne" assert utils.cleanBin("\nne", True) == ".ne" python-netlib-0.9.2/test/test_wsgi.py000066400000000000000000000060231226005331300176530ustar00rootroot00000000000000import cStringIO, sys from netlib import wsgi, odict def treq(): cc = wsgi.ClientConn(("127.0.0.1", 8888)) h = odict.ODictCaseless() h["test"] = ["value"] return wsgi.Request(cc, "http", "GET", "/", h, "") class TestApp: def __init__(self): self.called = False def __call__(self, environ, start_response): self.called = True status = '200 OK' response_headers = [('Content-type', 'text/plain')] start_response(status, response_headers) return ['Hello', ' world!\n'] class TestWSGI: def test_make_environ(self): w = wsgi.WSGIAdaptor(None, "foo", 80, "version") tr = treq() assert w.make_environ(tr, None) tr.path = "/foo?bar=voing" r = w.make_environ(tr, None) assert r["QUERY_STRING"] == "bar=voing" def test_serve(self): ta = TestApp() w = wsgi.WSGIAdaptor(ta, "foo", 80, "version") r = treq() r.host = "foo" r.port = 80 wfile = cStringIO.StringIO() err = w.serve(r, wfile) assert ta.called assert not err val = wfile.getvalue() assert "Hello world" in val assert "Server:" in val def _serve(self, app): w = wsgi.WSGIAdaptor(app, "foo", 80, "version") r = treq() r.host = "foo" r.port = 80 wfile = cStringIO.StringIO() err = w.serve(r, wfile) return wfile.getvalue() def test_serve_empty_body(self): def app(environ, start_response): status = '200 OK' response_headers = [('Foo', 'bar')] start_response(status, response_headers) return [] assert self._serve(app) def test_serve_double_start(self): def app(environ, start_response): try: raise ValueError("foo") except: ei = sys.exc_info() status = '200 OK' response_headers = [('Content-type', 'text/plain')] start_response(status, response_headers) start_response(status, response_headers) assert "Internal Server Error" in self._serve(app) def test_serve_single_err(self): def app(environ, start_response): try: raise ValueError("foo") except: ei = sys.exc_info() status = '200 OK' response_headers = [('Content-type', 'text/plain')] start_response(status, response_headers, ei) assert "Internal Server Error" in self._serve(app) def test_serve_double_err(self): def app(environ, start_response): try: raise ValueError("foo") except: ei = sys.exc_info() status = '200 OK' response_headers = [('Content-type', 'text/plain')] start_response(status, response_headers) yield "aaa" start_response(status, response_headers, ei) yield "bbb" assert "Internal Server Error" in self._serve(app) python-netlib-0.9.2/test/tutils.py000066400000000000000000000030711226005331300171670ustar00rootroot00000000000000import tempfile, os, shutil from contextlib import contextmanager from libpathod import utils @contextmanager def tmpdir(*args, **kwargs): orig_workdir = os.getcwd() temp_workdir = tempfile.mkdtemp(*args, **kwargs) os.chdir(temp_workdir) yield temp_workdir os.chdir(orig_workdir) shutil.rmtree(temp_workdir) def raises(exc, obj, *args, **kwargs): """ Assert that a callable raises a specified exception. :exc An exception class or a string. If a class, assert that an exception of this type is raised. If a string, assert that the string occurs in the string representation of the exception, based on a case-insenstivie match. :obj A callable object. :args Arguments to be passsed to the callable. :kwargs Arguments to be passed to the callable. """ try: apply(obj, args, kwargs) except Exception, v: if isinstance(exc, basestring): if exc.lower() in str(v).lower(): return else: raise AssertionError( "Expected %s, but caught %s"%( repr(str(exc)), v ) ) else: if isinstance(v, exc): return else: raise AssertionError( "Expected %s, but caught %s %s"%( exc.__name__, v.__class__.__name__, str(v) ) ) raise AssertionError("No exception raised.") test_data = utils.Data(__name__) python-netlib-0.9.2/tools/000077500000000000000000000000001226005331300154515ustar00rootroot00000000000000python-netlib-0.9.2/tools/getcertnames000077500000000000000000000005141226005331300200600ustar00rootroot00000000000000#!/usr/bin/env python import sys sys.path.insert(0, "../../") from netlib import certutils if len(sys.argv) > 2: port = int(sys.argv[2]) else: port = 443 cert = certutils.get_remote_cert(sys.argv[1], port, None) print "CN:", cert.cn if cert.altnames: print "SANs:", for i in cert.altnames: print "\t", i