/local/proxy.py
Python | 3095 lines | 3008 code | 41 blank | 46 comment | 106 complexity | c1af3c78cac0f97438b1b25490f10db5 MD5 | raw file
Large files files are truncated, but you can click here to view the full file
- #!/usr/bin/env python
- # coding:utf-8
- # Based on GAppProxy 2.0.0 by Du XiaoGang <dugang.2008@gmail.com>
- # Based on WallProxy 0.4.0 by Hust Moon <www.ehust@gmail.com>
- # Contributor:
- # Phus Lu <phus.lu@gmail.com>
- # Hewig Xu <hewigovens@gmail.com>
- # Ayanamist Yang <ayanamist@gmail.com>
- # V.E.O <V.E.O@tom.com>
- # Max Lv <max.c.lv@gmail.com>
- # AlsoTang <alsotang@gmail.com>
- # Christopher Meng <i@cicku.me>
- # Yonsm Guo <YonsmGuo@gmail.com>
- # Parkman <cseparkman@gmail.com>
- # Ming Bai <mbbill@gmail.com>
- # Bin Yu <yubinlove1991@gmail.com>
- # lileixuan <lileixuan@gmail.com>
- # Cong Ding <cong@cding.org>
- # Zhang Youfu <zhangyoufu@gmail.com>
- # Lu Wei <luwei@barfoo>
- # Harmony Meow <harmony.meow@gmail.com>
- # logostream <logostream@gmail.com>
- # Rui Wang <isnowfy@gmail.com>
- # Wang Wei Qiang <wwqgtxx@gmail.com>
- # Felix Yan <felixonmars@gmail.com>
- # Sui Feng <suifeng.me@qq.com>
- # QXO <qxodream@gmail.com>
- # Geek An <geekan@foxmail.com>
- # Poly Rabbit <mcx_221@foxmail.com>
- # oxnz <yunxinyi@gmail.com>
- # Shusen Liu <liushusen.smart@gmail.com>
- # Yad Smood <y.s.inside@gmail.com>
- # Chen Shuang <cs0x7f@gmail.com>
- # cnfuyu <cnfuyu@gmail.com>
- # cuixin <steven.cuixin@gmail.com>
- # s2marine0 <s2marine0@gmail.com>
- # Toshio Xiang <snachx@gmail.com>
- # Bo Tian <dxmtb@163.com>
- # Virgil <variousvirgil@gmail.com>
- # hub01 <miaojiabumiao@yeah.net>
- # v3aqb <sgzz.cj@gmail.com>
- # Oling Cat <olingcat@gmail.com>
- __version__ = '3.1.11'
- import sys
- import os
- import glob
- reload(sys).setdefaultencoding('UTF-8')
- sys.dont_write_bytecode = True
- sys.path += glob.glob('%s/*.egg' % os.path.dirname(os.path.abspath(__file__)))
- try:
- import gevent
- import gevent.socket
- import gevent.server
- import gevent.queue
- import gevent.monkey
- gevent.monkey.patch_all(subprocess=True)
- except ImportError:
- gevent = None
- except TypeError:
- gevent.monkey.patch_all()
- sys.stderr.write('\033[31m Warning: Please update gevent to the latest 1.0 version!\033[0m\n')
- import errno
- import time
- import struct
- import collections
- import binascii
- import zlib
- import itertools
- import re
- import io
- import fnmatch
- import traceback
- import random
- import base64
- import string
- import hashlib
- import threading
- import thread
- import socket
- import ssl
- import select
- import Queue
- import SocketServer
- import ConfigParser
- import BaseHTTPServer
- import httplib
- import urllib2
- import urlparse
- try:
- import dnslib
- except ImportError:
- dnslib = None
- try:
- import OpenSSL
- except ImportError:
- OpenSSL = None
- try:
- import pygeoip
- except ImportError:
- pygeoip = None
- HAS_PYPY = hasattr(sys, 'pypy_version_info')
- NetWorkIOError = (socket.error, ssl.SSLError, OSError) if not OpenSSL else (socket.error, ssl.SSLError, OpenSSL.SSL.Error, OSError)
- class Logging(type(sys)):
- CRITICAL = 50
- FATAL = CRITICAL
- ERROR = 40
- WARNING = 30
- WARN = WARNING
- INFO = 20
- DEBUG = 10
- NOTSET = 0
- def __init__(self, *args, **kwargs):
- self.level = self.__class__.INFO
- self.__set_error_color = lambda: None
- self.__set_warning_color = lambda: None
- self.__set_debug_color = lambda: None
- self.__reset_color = lambda: None
- if hasattr(sys.stderr, 'isatty') and sys.stderr.isatty():
- if os.name == 'nt':
- import ctypes
- SetConsoleTextAttribute = ctypes.windll.kernel32.SetConsoleTextAttribute
- GetStdHandle = ctypes.windll.kernel32.GetStdHandle
- self.__set_error_color = lambda: SetConsoleTextAttribute(GetStdHandle(-11), 0x04)
- self.__set_warning_color = lambda: SetConsoleTextAttribute(GetStdHandle(-11), 0x06)
- self.__set_debug_color = lambda: SetConsoleTextAttribute(GetStdHandle(-11), 0x002)
- self.__reset_color = lambda: SetConsoleTextAttribute(GetStdHandle(-11), 0x07)
- elif os.name == 'posix':
- self.__set_error_color = lambda: sys.stderr.write('\033[31m')
- self.__set_warning_color = lambda: sys.stderr.write('\033[33m')
- self.__set_debug_color = lambda: sys.stderr.write('\033[32m')
- self.__reset_color = lambda: sys.stderr.write('\033[0m')
- @classmethod
- def getLogger(cls, *args, **kwargs):
- return cls(*args, **kwargs)
- def basicConfig(self, *args, **kwargs):
- self.level = int(kwargs.get('level', self.__class__.INFO))
- if self.level > self.__class__.DEBUG:
- self.debug = self.dummy
- def log(self, level, fmt, *args, **kwargs):
- sys.stderr.write('%s - [%s] %s\n' % (level, time.ctime()[4:-5], fmt % args))
- def dummy(self, *args, **kwargs):
- pass
- def debug(self, fmt, *args, **kwargs):
- self.__set_debug_color()
- self.log('DEBUG', fmt, *args, **kwargs)
- self.__reset_color()
- def info(self, fmt, *args, **kwargs):
- self.log('INFO', fmt, *args)
- def warning(self, fmt, *args, **kwargs):
- self.__set_warning_color()
- self.log('WARNING', fmt, *args, **kwargs)
- self.__reset_color()
- def warn(self, fmt, *args, **kwargs):
- self.warning(fmt, *args, **kwargs)
- def error(self, fmt, *args, **kwargs):
- self.__set_error_color()
- self.log('ERROR', fmt, *args, **kwargs)
- self.__reset_color()
- def exception(self, fmt, *args, **kwargs):
- self.error(fmt, *args, **kwargs)
- sys.stderr.write(traceback.format_exc() + '\n')
- def critical(self, fmt, *args, **kwargs):
- self.__set_error_color()
- self.log('CRITICAL', fmt, *args, **kwargs)
- self.__reset_color()
- logging = sys.modules['logging'] = Logging('logging')
- class LRUCache(object):
- """http://pypi.python.org/pypi/lru/"""
- def __init__(self, max_items=100):
- self.cache = {}
- self.key_order = []
- self.max_items = max_items
- def __setitem__(self, key, value):
- self.cache[key] = value
- self._mark(key)
- def __getitem__(self, key):
- value = self.cache[key]
- self._mark(key)
- return value
- def __contains__(self, key):
- return key in self.cache
- def _mark(self, key):
- if key in self.key_order:
- self.key_order.remove(key)
- self.key_order.insert(0, key)
- if len(self.key_order) > self.max_items:
- index = self.max_items // 2
- delitem = self.cache.__delitem__
- key_order = self.key_order
- any(delitem(key_order[x]) for x in xrange(index, len(key_order)))
- self.key_order = self.key_order[:index]
- def clear(self):
- self.cache = {}
- self.key_order = []
- class CertUtil(object):
- """CertUtil module, based on mitmproxy"""
- ca_vendor = 'GoAgent'
- ca_keyfile = 'CA.crt'
- ca_certdir = 'certs'
- ca_lock = threading.Lock()
- @staticmethod
- def create_ca():
- key = OpenSSL.crypto.PKey()
- key.generate_key(OpenSSL.crypto.TYPE_RSA, 2048)
- ca = OpenSSL.crypto.X509()
- ca.set_serial_number(0)
- ca.set_version(2)
- subj = ca.get_subject()
- subj.countryName = 'CN'
- subj.stateOrProvinceName = 'Internet'
- subj.localityName = 'Cernet'
- subj.organizationName = CertUtil.ca_vendor
- subj.organizationalUnitName = '%s Root' % CertUtil.ca_vendor
- subj.commonName = '%s CA' % CertUtil.ca_vendor
- ca.gmtime_adj_notBefore(0)
- ca.gmtime_adj_notAfter(24 * 60 * 60 * 3652)
- ca.set_issuer(ca.get_subject())
- ca.set_pubkey(key)
- ca.add_extensions([
- OpenSSL.crypto.X509Extension(b'basicConstraints', True, b'CA:TRUE'),
- OpenSSL.crypto.X509Extension(b'nsCertType', True, b'sslCA'),
- OpenSSL.crypto.X509Extension(b'extendedKeyUsage', True, b'serverAuth,clientAuth,emailProtection,timeStamping,msCodeInd,msCodeCom,msCTLSign,msSGC,msEFS,nsSGC'),
- OpenSSL.crypto.X509Extension(b'keyUsage', False, b'keyCertSign, cRLSign'),
- OpenSSL.crypto.X509Extension(b'subjectKeyIdentifier', False, b'hash', subject=ca), ])
- ca.sign(key, 'sha1')
- return key, ca
- @staticmethod
- def dump_ca():
- key, ca = CertUtil.create_ca()
- with open(CertUtil.ca_keyfile, 'wb') as fp:
- fp.write(OpenSSL.crypto.dump_certificate(OpenSSL.crypto.FILETYPE_PEM, ca))
- fp.write(OpenSSL.crypto.dump_privatekey(OpenSSL.crypto.FILETYPE_PEM, key))
- @staticmethod
- def _get_cert(commonname, sans=()):
- with open(CertUtil.ca_keyfile, 'rb') as fp:
- content = fp.read()
- key = OpenSSL.crypto.load_privatekey(OpenSSL.crypto.FILETYPE_PEM, content)
- ca = OpenSSL.crypto.load_certificate(OpenSSL.crypto.FILETYPE_PEM, content)
- pkey = OpenSSL.crypto.PKey()
- pkey.generate_key(OpenSSL.crypto.TYPE_RSA, 2048)
- req = OpenSSL.crypto.X509Req()
- subj = req.get_subject()
- subj.countryName = 'CN'
- subj.stateOrProvinceName = 'Internet'
- subj.localityName = 'Cernet'
- subj.organizationalUnitName = '%s Branch' % CertUtil.ca_vendor
- if commonname[0] == '.':
- subj.commonName = '*' + commonname
- subj.organizationName = '*' + commonname
- sans = ['*'+commonname] + [x for x in sans if x != '*'+commonname]
- else:
- subj.commonName = commonname
- subj.organizationName = commonname
- sans = [commonname] + [x for x in sans if x != commonname]
- #req.add_extensions([OpenSSL.crypto.X509Extension(b'subjectAltName', True, ', '.join('DNS: %s' % x for x in sans)).encode()])
- req.set_pubkey(pkey)
- req.sign(pkey, 'sha1')
- cert = OpenSSL.crypto.X509()
- cert.set_version(2)
- try:
- cert.set_serial_number(int(hashlib.md5(commonname.encode('utf-8')).hexdigest(), 16))
- except OpenSSL.SSL.Error:
- cert.set_serial_number(int(time.time()*1000))
- cert.gmtime_adj_notBefore(0)
- cert.gmtime_adj_notAfter(60 * 60 * 24 * 3652)
- cert.set_issuer(ca.get_subject())
- cert.set_subject(req.get_subject())
- cert.set_pubkey(req.get_pubkey())
- if commonname[0] == '.':
- sans = ['*'+commonname] + [s for s in sans if s != '*'+commonname]
- else:
- sans = [commonname] + [s for s in sans if s != commonname]
- #cert.add_extensions([OpenSSL.crypto.X509Extension(b'subjectAltName', True, ', '.join('DNS: %s' % x for x in sans))])
- cert.sign(key, 'sha1')
- certfile = os.path.join(CertUtil.ca_certdir, commonname + '.crt')
- with open(certfile, 'wb') as fp:
- fp.write(OpenSSL.crypto.dump_certificate(OpenSSL.crypto.FILETYPE_PEM, cert))
- fp.write(OpenSSL.crypto.dump_privatekey(OpenSSL.crypto.FILETYPE_PEM, pkey))
- return certfile
- @staticmethod
- def get_cert(commonname, sans=()):
- if commonname.count('.') >= 2 and [len(x) for x in reversed(commonname.split('.'))] > [2, 4]:
- commonname = '.'+commonname.partition('.')[-1]
- certfile = os.path.join(CertUtil.ca_certdir, commonname + '.crt')
- if os.path.exists(certfile):
- return certfile
- elif OpenSSL is None:
- return CertUtil.ca_keyfile
- else:
- with CertUtil.ca_lock:
- if os.path.exists(certfile):
- return certfile
- return CertUtil._get_cert(commonname, sans)
- @staticmethod
- def import_ca(certfile):
- commonname = os.path.splitext(os.path.basename(certfile))[0]
- sha1digest = 'AB:70:2C:DF:18:EB:E8:B4:38:C5:28:69:CD:4A:5D:EF:48:B4:0E:33'
- if OpenSSL:
- try:
- with open(certfile, 'rb') as fp:
- x509 = OpenSSL.crypto.load_certificate(OpenSSL.crypto.FILETYPE_PEM, fp.read())
- commonname = next(v.decode() for k, v in x509.get_subject().get_components() if k == b'O')
- sha1digest = x509.digest('sha1')
- except StandardError as e:
- logging.error('load_certificate(certfile=%r) failed:%s', certfile, e)
- if sys.platform.startswith('win'):
- import ctypes
- with open(certfile, 'rb') as fp:
- certdata = fp.read()
- if certdata.startswith(b'-----'):
- begin = b'-----BEGIN CERTIFICATE-----'
- end = b'-----END CERTIFICATE-----'
- certdata = base64.b64decode(b''.join(certdata[certdata.find(begin)+len(begin):certdata.find(end)].strip().splitlines()))
- crypt32 = ctypes.WinDLL(b'crypt32.dll'.decode())
- store_handle = crypt32.CertOpenStore(10, 0, 0, 0x4000 | 0x20000, b'ROOT'.decode())
- if not store_handle:
- return -1
- X509_ASN_ENCODING = 0x00000001
- CERT_FIND_HASH = 0x10000
- class CRYPT_HASH_BLOB(ctypes.Structure):
- _fields_ = [('cbData', ctypes.c_ulong), ('pbData', ctypes.c_char_p)]
- crypt_hash = CRYPT_HASH_BLOB(20, binascii.a2b_hex(sha1digest.replace(':', '')))
- crypt_handle = crypt32.CertFindCertificateInStore(store_handle, X509_ASN_ENCODING, 0, CERT_FIND_HASH, ctypes.byref(crypt_hash), None)
- if crypt_handle:
- crypt32.CertFreeCertificateContext(crypt_handle)
- return 0
- ret = crypt32.CertAddEncodedCertificateToStore(store_handle, 0x1, certdata, len(certdata), 4, None)
- crypt32.CertCloseStore(store_handle, 0)
- del crypt32
- return 0 if ret else -1
- elif sys.platform == 'darwin':
- return os.system(('security find-certificate -a -c "%s" | grep "%s" >/dev/null || security add-trusted-cert -d -r trustRoot -k "/Library/Keychains/System.keychain" "%s"' % (commonname, commonname, certfile.decode('utf-8'))).encode('utf-8'))
- elif sys.platform.startswith('linux'):
- import platform
- platform_distname = platform.dist()[0]
- if platform_distname == 'Ubuntu':
- pemfile = "/etc/ssl/certs/%s.pem" % commonname
- new_certfile = "/usr/local/share/ca-certificates/%s.crt" % commonname
- if not os.path.exists(pemfile):
- return os.system('cp "%s" "%s" && update-ca-certificates' % (certfile, new_certfile))
- elif any(os.path.isfile('%s/certutil' % x) for x in os.environ['PATH'].split(os.pathsep)):
- return os.system('certutil -L -d sql:$HOME/.pki/nssdb | grep "%s" || certutil -d sql:$HOME/.pki/nssdb -A -t "C,," -n "%s" -i "%s"' % (commonname, commonname, certfile))
- else:
- logging.warning('please install *libnss3-tools* package to import GoAgent root ca')
- return 0
- @staticmethod
- def check_ca():
- #Check CA exists
- capath = os.path.join(os.path.dirname(os.path.abspath(__file__)), CertUtil.ca_keyfile)
- certdir = os.path.join(os.path.dirname(os.path.abspath(__file__)), CertUtil.ca_certdir)
- if not os.path.exists(capath):
- if not OpenSSL:
- logging.critical('CA.key is not exist and OpenSSL is disabled, ABORT!')
- sys.exit(-1)
- if os.path.exists(certdir):
- if os.path.isdir(certdir):
- any(os.remove(x) for x in glob.glob(certdir+'/*.crt')+glob.glob(certdir+'/.*.crt'))
- else:
- os.remove(certdir)
- os.mkdir(certdir)
- CertUtil.dump_ca()
- if glob.glob('%s/*.key' % CertUtil.ca_certdir):
- for filename in glob.glob('%s/*.key' % CertUtil.ca_certdir):
- try:
- os.remove(filename)
- os.remove(os.path.splitext(filename)[0]+'.crt')
- except EnvironmentError:
- pass
- #Check CA imported
- if CertUtil.import_ca(capath) != 0:
- logging.warning('install root certificate failed, Please run as administrator/root/sudo')
- #Check Certs Dir
- if not os.path.exists(certdir):
- os.makedirs(certdir)
- class DetectMobileBrowser:
- """detect mobile function from http://detectmobilebrowsers.com"""
- regex_match_a = re.compile(r"(android|bb\\d+|meego).+mobile|avantgo|bada\\/|blackberry|blazer|compal|elaine|fennec|hiptop|iemobile|ip(hone|od)|iris|kindle|lge |maemo|midp|mmp|mobile.+firefox|netfront|opera m(ob|in)i|palm( os)?|phone|p(ixi|re)\\/|plucker|pocket|psp|series(4|6)0|symbian|treo|up\\.(browser|link)|vodafone|wap|windows (ce|phone)|xda|xiino", re.I|re.M).search
- regex_match_b = re.compile(r"1207|6310|6590|3gso|4thp|50[1-6]i|770s|802s|a wa|abac|ac(er|oo|s\\-)|ai(ko|rn)|al(av|ca|co)|amoi|an(ex|ny|yw)|aptu|ar(ch|go)|as(te|us)|attw|au(di|\\-m|r |s )|avan|be(ck|ll|nq)|bi(lb|rd)|bl(ac|az)|br(e|v)w|bumb|bw\\-(n|u)|c55\\/|capi|ccwa|cdm\\-|cell|chtm|cldc|cmd\\-|co(mp|nd)|craw|da(it|ll|ng)|dbte|dc\\-s|devi|dica|dmob|do(c|p)o|ds(12|\\-d)|el(49|ai)|em(l2|ul)|er(ic|k0)|esl8|ez([4-7]0|os|wa|ze)|fetc|fly(\\-|_)|g1 u|g560|gene|gf\\-5|g\\-mo|go(\\.w|od)|gr(ad|un)|haie|hcit|hd\\-(m|p|t)|hei\\-|hi(pt|ta)|hp( i|ip)|hs\\-c|ht(c(\\-| |_|a|g|p|s|t)|tp)|hu(aw|tc)|i\\-(20|go|ma)|i230|iac( |\\-|\\/)|ibro|idea|ig01|ikom|im1k|inno|ipaq|iris|ja(t|v)a|jbro|jemu|jigs|kddi|keji|kgt( |\\/)|klon|kpt |kwc\\-|kyo(c|k)|le(no|xi)|lg( g|\\/(k|l|u)|50|54|\\-[a-w])|libw|lynx|m1\\-w|m3ga|m50\\/|ma(te|ui|xo)|mc(01|21|ca)|m\\-cr|me(rc|ri)|mi(o8|oa|ts)|mmef|mo(01|02|bi|de|do|t(\\-| |o|v)|zz)|mt(50|p1|v )|mwbp|mywa|n10[0-2]|n20[2-3]|n30(0|2)|n50(0|2|5)|n7(0(0|1)|10)|ne((c|m)\\-|on|tf|wf|wg|wt)|nok(6|i)|nzph|o2im|op(ti|wv)|oran|owg1|p800|pan(a|d|t)|pdxg|pg(13|\\-([1-8]|c))|phil|pire|pl(ay|uc)|pn\\-2|po(ck|rt|se)|prox|psio|pt\\-g|qa\\-a|qc(07|12|21|32|60|\\-[2-7]|i\\-)|qtek|r380|r600|raks|rim9|ro(ve|zo)|s55\\/|sa(ge|ma|mm|ms|ny|va)|sc(01|h\\-|oo|p\\-)|sdk\\/|se(c(\\-|0|1)|47|mc|nd|ri)|sgh\\-|shar|sie(\\-|m)|sk\\-0|sl(45|id)|sm(al|ar|b3|it|t5)|so(ft|ny)|sp(01|h\\-|v\\-|v )|sy(01|mb)|t2(18|50)|t6(00|10|18)|ta(gt|lk)|tcl\\-|tdg\\-|tel(i|m)|tim\\-|t\\-mo|to(pl|sh)|ts(70|m\\-|m3|m5)|tx\\-9|up(\\.b|g1|si)|utst|v400|v750|veri|vi(rg|te)|vk(40|5[0-3]|\\-v)|vm40|voda|vulc|vx(52|53|60|61|70|80|81|83|85|98)|w3c(\\-| )|webc|whit|wi(g |nc|nw)|wmlb|wonu|x700|yas\\-|your|zeto|zte\\-", re.I|re.M).search
-
- @staticmethod
- def detect(user_agent):
- return DetectMobileBrowser.regex_match_a(user_agent) or DetectMobileBrowser.regex_match_b(user_agent)
- class SSLConnection(object):
- has_gevent = socket.socket is getattr(sys.modules.get('gevent.socket'), 'socket', None)
- def __init__(self, context, sock):
- self._context = context
- self._sock = sock
- self._connection = OpenSSL.SSL.Connection(context, sock)
- self._makefile_refs = 0
- if self.has_gevent:
- self._wait_read = gevent.socket.wait_read
- self._wait_write = gevent.socket.wait_write
- self._wait_readwrite = gevent.socket.wait_readwrite
- else:
- self._wait_read = lambda fd,t: select.select([fd], [], [fd], t)
- self._wait_write = lambda fd,t: select.select([], [fd], [fd], t)
- self._wait_readwrite = lambda fd,t: select.select([fd], [fd], [fd], t)
- def __getattr__(self, attr):
- if attr not in ('_context', '_sock', '_connection', '_makefile_refs'):
- return getattr(self._connection, attr)
- def accept(self):
- sock, addr = self._sock.accept()
- client = OpenSSL.SSL.Connection(sock._context, sock)
- return client, addr
- def do_handshake(self):
- timeout = self._sock.gettimeout()
- while True:
- try:
- self._connection.do_handshake()
- break
- except (OpenSSL.SSL.WantReadError, OpenSSL.SSL.WantX509LookupError, OpenSSL.SSL.WantWriteError):
- sys.exc_clear()
- self._wait_readwrite(self._sock.fileno(), timeout)
- def connect(self, *args, **kwargs):
- timeout = self._sock.gettimeout()
- while True:
- try:
- self._connection.connect(*args, **kwargs)
- break
- except (OpenSSL.SSL.WantReadError, OpenSSL.SSL.WantX509LookupError):
- sys.exc_clear()
- self._wait_read(self._sock.fileno(), timeout)
- except OpenSSL.SSL.WantWriteError:
- sys.exc_clear()
- self._wait_write(self._sock.fileno(), timeout)
- def send(self, data, flags=0):
- timeout = self._sock.gettimeout()
- while True:
- try:
- self._connection.send(data, flags)
- break
- except (OpenSSL.SSL.WantReadError, OpenSSL.SSL.WantX509LookupError):
- sys.exc_clear()
- self._wait_read(self._sock.fileno(), timeout)
- except OpenSSL.SSL.WantWriteError:
- sys.exc_clear()
- self._wait_write(self._sock.fileno(), timeout)
- except OpenSSL.SSL.SysCallError as e:
- if e[0] == -1 and not data:
- # errors when writing empty strings are expected and can be ignored
- return 0
- raise
- def recv(self, bufsiz, flags=0):
- timeout = self._sock.gettimeout()
- pending = self._connection.pending()
- if pending:
- return self._connection.recv(min(pending, bufsiz))
- while True:
- try:
- return self._connection.recv(bufsiz, flags)
- except (OpenSSL.SSL.WantReadError, OpenSSL.SSL.WantX509LookupError):
- sys.exc_clear()
- self._wait_read(self._sock.fileno(), timeout)
- except OpenSSL.SSL.WantWriteError:
- sys.exc_clear()
- self._wait_write(self._sock.fileno(), timeout)
- except OpenSSL.SSL.ZeroReturnError:
- return ''
- def read(self, bufsiz, flags=0):
- return self.recv(bufsiz, flags)
- def write(self, buf, flags=0):
- return self.sendall(buf, flags)
- def close(self):
- if self._makefile_refs < 1:
- self._connection = None
- if self._sock:
- socket.socket.close(self._sock)
- else:
- self._makefile_refs -= 1
- def makefile(self, mode='r', bufsize=-1):
- self._makefile_refs += 1
- return socket._fileobject(self, mode, bufsize, close=True)
- class ProxyUtil(object):
- """ProxyUtil module, based on urllib2"""
- @staticmethod
- def parse_proxy(proxy):
- return urllib2._parse_proxy(proxy)
- @staticmethod
- def get_system_proxy():
- proxies = urllib2.getproxies()
- return proxies.get('https') or proxies.get('http') or {}
- @staticmethod
- def get_listen_ip():
- listen_ip = '127.0.0.1'
- sock = None
- try:
- sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
- sock.connect(('8.8.8.8', 53))
- listen_ip = sock.getsockname()[0]
- except socket.error:
- pass
- finally:
- if sock:
- sock.close()
- return listen_ip
- def dnslib_resolve_over_udp(qname, dnsservers, timeout, **kwargs):
- """
- http://gfwrev.blogspot.com/2009/11/gfwdns.html
- http://zh.wikipedia.org/wiki/%E5%9F%9F%E5%90%8D%E6%9C%8D%E5%8A%A1%E5%99%A8%E7%BC%93%E5%AD%98%E6%B1%A1%E6%9F%93
- http://support.microsoft.com/kb/241352
- """
- blacklist = kwargs.get('blacklist', ())
- turstservers = kwargs.get('turstservers', ())
- query = dnslib.DNSRecord(q=dnslib.DNSQuestion(qname))
- query_data = query.pack()
- dns_v4_servers = [x for x in dnsservers if ':' not in x]
- dns_v6_servers = [x for x in dnsservers if ':' in x]
- sock_v4 = sock_v6 = None
- socks = []
- if dns_v4_servers:
- sock_v4 = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
- socks.append(sock_v4)
- if dns_v6_servers:
- sock_v6 = socket.socket(socket.AF_INET6, socket.SOCK_DGRAM)
- socks.append(sock_v6)
- timeout_at = time.time() + timeout
- try:
- for _ in xrange(4):
- try:
- for dnsserver in dns_v4_servers:
- sock_v4.sendto(query_data, (dnsserver, 53))
- for dnsserver in dns_v6_servers:
- sock_v6.sendto(query_data, (dnsserver, 53))
- while time.time() < timeout_at:
- ins, _, _ = select.select(socks, [], [], 0.1)
- for sock in ins:
- reply_data, (reply_server, _) = sock.recvfrom(512)
- record = dnslib.DNSRecord.parse(reply_data)
- rtypes = (1, 28) if sock is sock_v6 else (1,)
- iplist = [str(x.rdata) for x in record.rr if x.rtype in rtypes]
- if any(x in blacklist for x in iplist):
- logging.warning('query qname=%r dnsservers=%r record bad iplist=%r', qname, dnsservers, iplist)
- elif record.header.rcode and not iplist and reply_server in turstservers:
- logging.info('query qname=%r trust reply_server=%r record rcode=%s', qname, reply_server, record.header.rcode)
- return record
- elif iplist:
- logging.debug('query qname=%r reply_server=%r record iplist=%s', qname, reply_server, iplist)
- return record
- else:
- logging.debug('query qname=%r reply_server=%r record null iplist=%s', qname, reply_server, iplist)
- continue
- except socket.error as e:
- logging.warning('handle dns query=%s socket: %r', query, e)
- raise socket.gaierror(11004, 'getaddrinfo %r from %r failed' % (qname, dnsservers))
- finally:
- for sock in socks:
- sock.close()
- def dnslib_resolve_over_tcp(qname, dnsservers, timeout, **kwargs):
- """dns query over tcp"""
- blacklist = kwargs.get('blacklist', ())
- def do_resolve(qname, dnsserver, timeout, queobj):
- query = dnslib.DNSRecord(q=dnslib.DNSQuestion(qname))
- query_data = query.pack()
- sock_family = socket.AF_INET6 if ':' in dnsserver else socket.AF_INET
- sock = socket.socket(sock_family)
- rfile = None
- try:
- sock.settimeout(timeout or None)
- sock.connect((dnsserver, 53))
- sock.send(struct.pack('>h', len(query_data)) + query_data)
- rfile = sock.makefile('r', 1024)
- reply_data_length = rfile.read(2)
- if len(reply_data_length) < 2:
- raise socket.gaierror(11004, 'getaddrinfo %r from %r failed' % (qname, dnsserver))
- reply_data = rfile.read(struct.unpack('>h', reply_data_length)[0])
- record = dnslib.DNSRecord.parse(reply_data)
- rtypes = (1, 28) if sock_family is socket.AF_INET6 else (1,)
- iplist = [str(x.rdata) for x in record.rr if x.rtype in rtypes]
- if any(x in blacklist for x in iplist):
- logging.debug('query qname=%r dnsserver=%r record bad iplist=%r', qname, dnsserver, iplist)
- raise socket.gaierror(11004, 'getaddrinfo %r from %r failed' % (qname, dnsserver))
- else:
- logging.debug('query qname=%r dnsserver=%r record iplist=%s', qname, dnsserver, iplist)
- queobj.put(record)
- except socket.error as e:
- logging.debug('query qname=%r dnsserver=%r failed %r', qname, dnsserver, e)
- queobj.put(e)
- finally:
- if rfile:
- rfile.close()
- sock.close()
- queobj = Queue.Queue()
- for dnsserver in dnsservers:
- thread.start_new_thread(do_resolve, (qname, dnsserver, timeout, queobj))
- for i in range(len(dnsservers)):
- try:
- result = queobj.get(timeout)
- except Queue.Empty:
- raise socket.gaierror(11004, 'getaddrinfo %r from %r failed' % (qname, dnsservers))
- if result and not isinstance(result, Exception):
- return result
- elif i == len(dnsservers) - 1:
- logging.warning('dnslib_resolve_over_tcp %r with %s return %r', qname, dnsservers, result)
- raise socket.gaierror(11004, 'getaddrinfo %r from %r failed' % (qname, dnsservers))
- def dnslib_record2iplist(record):
- """convert dnslib.DNSRecord to iplist"""
- assert isinstance(record, dnslib.DNSRecord)
- return [str(x.rdata) for x in record.rr if x.rtype in (1, 28)]
- def get_dnsserver_list():
- if os.name == 'nt':
- import ctypes, ctypes.wintypes, struct, socket
- DNS_CONFIG_DNS_SERVER_LIST = 6
- buf = ctypes.create_string_buffer(2048)
- ctypes.windll.dnsapi.DnsQueryConfig(DNS_CONFIG_DNS_SERVER_LIST, 0, None, None, ctypes.byref(buf), ctypes.byref(ctypes.wintypes.DWORD(len(buf))))
- ips = struct.unpack('I', buf[0:4])[0]
- out = []
- for i in xrange(ips):
- start = (i+1) * 4
- out.append(socket.inet_ntoa(buf[start:start+4]))
- return out
- elif os.path.isfile('/etc/resolv.conf'):
- with open('/etc/resolv.conf', 'rb') as fp:
- return re.findall(r'(?m)^nameserver\s+(\S+)', fp.read())
- else:
- logging.warning("get_dnsserver_list failed: unsupport platform '%s-%s'", sys.platform, os.name)
- return []
- def spawn_later(seconds, target, *args, **kwargs):
- def wrap(*args, **kwargs):
- __import__('time').sleep(seconds)
- return target(*args, **kwargs)
- return __import__('thread').start_new_thread(wrap, args, kwargs)
- def is_clienthello(data):
- if len(data) < 20:
- return False
- if data.startswith('\x16\x03'):
- # TLSv12/TLSv11/TLSv1/SSLv3
- length, = struct.unpack('>h', data[3:5])
- return len(data) == 5 + length
- elif data[0] == '\x80' and data[2:4] == '\x01\x03':
- # SSLv23
- return len(data) == 2 + ord(data[1])
- else:
- return False
- def extract_sni_name(packet):
- if packet.startswith('\x16\x03'):
- stream = io.BytesIO(packet)
- stream.read(0x2b)
- session_id_length = ord(stream.read(1))
- stream.read(session_id_length)
- cipher_suites_length, = struct.unpack('>h', stream.read(2))
- stream.read(cipher_suites_length+2)
- extensions_length, = struct.unpack('>h', stream.read(2))
- extensions = {}
- while True:
- data = stream.read(2)
- if not data:
- break
- etype, = struct.unpack('>h', data)
- elen, = struct.unpack('>h', stream.read(2))
- edata = stream.read(elen)
- if etype == 0:
- server_name = edata[5:]
- return server_name
- class URLFetch(object):
- """URLFetch for gae/php fetchservers"""
- skip_headers = frozenset(['Vary', 'Via', 'X-Forwarded-For', 'Proxy-Authorization', 'Proxy-Connection', 'Upgrade', 'X-Chrome-Variations', 'Connection', 'Cache-Control'])
- def __init__(self, fetchserver, create_http_request):
- assert isinstance(fetchserver, basestring) and callable(create_http_request)
- self.fetchserver = fetchserver
- self.create_http_request = create_http_request
- def fetch(self, method, url, headers, body, timeout, **kwargs):
- if '.appspot.com/' in self.fetchserver:
- response = self.__gae_fetch(method, url, headers, body, timeout, **kwargs)
- response.app_header_parsed = True
- else:
- response = self.__php_fetch(method, url, headers, body, timeout, **kwargs)
- response.app_header_parsed = False
- return response
- def __gae_fetch(self, method, url, headers, body, timeout, **kwargs):
- # deflate = lambda x:zlib.compress(x)[2:-4]
- rc4crypt = lambda s, k: RC4Cipher(k).encrypt(s) if k else s
- if body:
- if len(body) < 10 * 1024 * 1024 and 'Content-Encoding' not in headers:
- zbody = zlib.compress(body)[2:-4]
- if len(zbody) < len(body):
- body = zbody
- headers['Content-Encoding'] = 'deflate'
- headers['Content-Length'] = str(len(body))
- # GAE donot allow set `Host` header
- if 'Host' in headers:
- del headers['Host']
- metadata = 'G-Method:%s\nG-Url:%s\n%s' % (method, url, ''.join('G-%s:%s\n' % (k, v) for k, v in kwargs.items() if v))
- skip_headers = self.skip_headers
- metadata += ''.join('%s:%s\n' % (k.title(), v) for k, v in headers.items() if k not in skip_headers)
- # prepare GAE request
- request_method = 'POST'
- request_headers = {}
- if common.GAE_OBFUSCATE:
- if 'rc4' in common.GAE_OPTIONS:
- request_headers['X-GOA-Options'] = 'rc4'
- cookie = base64.b64encode(rc4crypt(zlib.compress(metadata)[2:-4], kwargs.get('password'))).strip()
- body = rc4crypt(body, kwargs.get('password'))
- else:
- cookie = base64.b64encode(zlib.compress(metadata)[2:-4]).strip()
- request_headers['Cookie'] = cookie
- if body:
- request_headers['Content-Length'] = str(len(body))
- else:
- request_method = 'GET'
- else:
- metadata = zlib.compress(metadata)[2:-4]
- body = '%s%s%s' % (struct.pack('!h', len(metadata)), metadata, body)
- if 'rc4' in common.GAE_OPTIONS:
- request_headers['X-GOA-Options'] = 'rc4'
- body = rc4crypt(body, kwargs.get('password'))
- request_headers['Content-Length'] = str(len(body))
- # post data
- need_crlf = 0 if common.GAE_MODE == 'https' else 1
- need_validate = common.GAE_VALIDATE
- cache_key = '%s:%d' % (common.HOST_POSTFIX_MAP['.appspot.com'], 443 if common.GAE_MODE == 'https' else 80)
- response = self.create_http_request(request_method, self.fetchserver, request_headers, body, timeout, crlf=need_crlf, validate=need_validate, cache_key=cache_key)
- response.app_status = response.status
- response.app_options = response.getheader('X-GOA-Options', '')
- if response.status != 200:
- return response
- data = response.read(4)
- if len(data) < 4:
- response.status = 502
- response.fp = io.BytesIO(b'connection aborted. too short leadbyte data=' + data)
- response.read = response.fp.read
- return response
- response.status, headers_length = struct.unpack('!hh', data)
- data = response.read(headers_length)
- if len(data) < headers_length:
- response.status = 502
- response.fp = io.BytesIO(b'connection aborted. too short headers data=' + data)
- response.read = response.fp.read
- return response
- if 'rc4' not in response.app_options:
- response.msg = httplib.HTTPMessage(io.BytesIO(zlib.decompress(data, -zlib.MAX_WBITS)))
- else:
- response.msg = httplib.HTTPMessage(io.BytesIO(zlib.decompress(rc4crypt(data, kwargs.get('password')), -zlib.MAX_WBITS)))
- if kwargs.get('password') and response.fp:
- response.fp = CipherFileObject(response.fp, RC4Cipher(kwargs['password']))
- return response
- def __php_fetch(self, method, url, headers, body, timeout, **kwargs):
- if body:
- if len(body) < 10 * 1024 * 1024 and 'Content-Encoding' not in headers:
- zbody = zlib.compress(body)[2:-4]
- if len(zbody) < len(body):
- body = zbody
- headers['Content-Encoding'] = 'deflate'
- headers['Content-Length'] = str(len(body))
- skip_headers = self.skip_headers
- metadata = 'G-Method:%s\nG-Url:%s\n%s%s' % (method, url, ''.join('G-%s:%s\n' % (k, v) for k, v in kwargs.items() if v), ''.join('%s:%s\n' % (k, v) for k, v in headers.items() if k not in skip_headers))
- metadata = zlib.compress(metadata)[2:-4]
- app_body = b''.join((struct.pack('!h', len(metadata)), metadata, body))
- app_headers = {'Content-Length': len(app_body), 'Content-Type': 'application/octet-stream'}
- fetchserver = '%s?%s' % (self.fetchserver, random.random())
- crlf = 0
- cache_key = '%s//:%s' % urlparse.urlsplit(fetchserver)[:2]
- response = self.create_http_request('POST', fetchserver, app_headers, app_body, timeout, crlf=crlf, cache_key=cache_key)
- if not response:
- raise socket.error(errno.ECONNRESET, 'urlfetch %r return None' % url)
- if response.status >= 400:
- return response
- response.app_status = response.status
- need_decrypt = kwargs.get('password') and response.app_status == 200 and response.getheader('Content-Type', '') == 'image/gif' and response.fp
- if need_decrypt:
- response.fp = CipherFileObject(response.fp, XORCipher(kwargs['password'][0]))
- return response
- class BaseProxyHandlerFilter(object):
- """base proxy handler filter"""
- def filter(self, handler):
- raise NotImplementedError
- class SimpleProxyHandlerFilter(BaseProxyHandlerFilter):
- """simple proxy handler filter"""
- def filter(self, handler):
- if handler.command == 'CONNECT':
- return [handler.FORWARD, handler.host, handler.port, handler.connect_timeout]
- else:
- return [handler.DIRECT, {}]
- class AuthFilter(BaseProxyHandlerFilter):
- """authorization filter"""
- auth_info = "Proxy authentication required"""
- white_list = set(['127.0.0.1'])
- def __init__(self, username, password):
- self.username = username
- self.password = password
- def check_auth_header(self, auth_header):
- method, _, auth_data = auth_header.partition(' ')
- if method == 'Basic':
- username, _, password = base64.b64decode(auth_data).partition(':')
- if username == self.username and password == self.password:
- return True
- return False
- def filter(self, handler):
- if self.white_list and handler.client_address[0] in self.white_list:
- return None
- auth_header = handler.headers.get('Proxy-Authorization') or getattr(handler, 'auth_header', None)
- if auth_header and self.check_auth_header(auth_header):
- handler.auth_header = auth_header
- else:
- headers = {'Access-Control-Allow-Origin': '*',
- 'Proxy-Authenticate': 'Basic realm="%s"' % self.auth_info,
- 'Content-Length': '0',
- 'Connection': 'keep-alive'}
- return [handler.MOCK, 407, headers, '']
- class SimpleProxyHandler(BaseHTTPServer.BaseHTTPRequestHandler):
- """SimpleProxyHandler for GoAgent 3.x"""
- protocol_version = 'HTTP/1.1'
- ssl_version = ssl.PROTOCOL_SSLv23
- disable_transport_ssl = True
- scheme = 'http'
- skip_headers = frozenset(['Vary', 'Via', 'X-Forwarded-For', 'Proxy-Authorization', 'Proxy-Connection', 'Upgrade', 'X-Chrome-Variations', 'Connection', 'Cache-Control'])
- bufsize = 256 * 1024
- max_timeout = 16
- connect_timeout = 8
- first_run_lock = threading.Lock()
- handler_filters = [SimpleProxyHandlerFilter()]
- sticky_filter = None
- def finish(self):
- """make python2 BaseHTTPRequestHandler happy"""
- try:
- BaseHTTPServer.BaseHTTPRequestHandler.finish(self)
- except NetWorkIOError as e:
- if e[0] not in (errno.ECONNABORTED, errno.ECONNRESET, errno.EPIPE):
- raise
- def address_string(self):
- return '%s:%s' % self.client_address[:2]
- def send_response(self, code, message=None):
- if message is None:
- if code in self.responses:
- message = self.responses[code][0]
- else:
- message = ''
- if self.request_version != 'HTTP/0.9':
- self.wfile.write('%s %d %s\r\n' % (self.protocol_version, code, message))
- def send_header(self, keyword, value):
- """Send a MIME header."""
- base_send_header = BaseHTTPServer.BaseHTTPRequestHandler.send_header
- keyword = keyword.title()
- if keyword == 'Set-Cookie':
- for cookie in re.split(r', (?=[^ =]+(?:=|$))', value):
- base_send_header(self, keyword, cookie)
- elif keyword == 'Content-Disposition' and '"' not in value:
- value = re.sub(r'filename=([^"\']+)', 'filename="\\1"', value)
- base_send_header(self, keyword, value)
- else:
- base_send_header(self, keyword, value)
- def setup(self):
- if isinstance(self.__class__.first_run, collections.Callable):
- try:
- with self.__class__.first_run_lock:
- if isinstance(self.__class__.first_run, collections.Callable):
- self.first_run()
- self.__class__.first_run = None
- except StandardError as e:
- logging.exception('%s.first_run() return %r', self.__class__, e)
- self.__class__.setup = BaseHTTPServer.BaseHTTPRequestHandler.setup
- self.__class__.do_CONNECT = self.__class__.do_METHOD
- self.__class__.do_GET = self.__class__.do_METHOD
- self.__class__.do_PUT = self.__class__.do_METHOD
- self.__class__.do_POST = self.__class__.do_METHOD
- self.__class__.do_HEAD = self.__class__.do_METHOD
- self.__class__.do_DELETE = self.__class__.do_METHOD
- self.__class__.do_OPTIONS = self.__class__.do_METHOD
- self.setup()
- def handle_one_request(self):
- if not self.disable_transport_ssl and self.scheme == 'http':
- leadbyte = self.connection.recv(1, socket.MSG_PEEK)
- if leadbyte in ('\x80', '\x16'):
- server_name = ''
- if leadbyte == '\x16':
- for _ in xrange(2):
- leaddata = self.connection.recv(1024, socket.MSG_PEEK)
- if is_clienthello(leaddata):
- try:
- server_name = extract_sni_name(leaddata)
- finally:
- break
- try:
- certfile = CertUtil.get_cert(server_name or 'www.google.com')
- ssl_sock = ssl.wrap_socket(self.connection, ssl_version=self.ssl_version, keyfile=certfile, certfile=certfile, server_side=True)
- except StandardError as e:
- if e.args[0] not in (errno.ECONNABORTED, errno.ECONNRESET):
- logging.exception('ssl.wrap_socket(self.connection=%r) failed: %s', self.connection, e)
- return
- self.connection = ssl_sock
- self.rfile = self.connection.makefile('rb', self.bufsize)
- self.wfile = self.connection.makefile('wb', 0)
- self.scheme = 'https'
- return BaseHTTPServer.BaseHTTPRequestHandler.handle_one_request(self)
- def first_run(self):
- pass
- def gethostbyname2(self, hostname):
- return socket.gethostbyname_ex(hostname)[-1]
- def create_tcp_connection(self, hostname, port, timeout, **kwargs):
- return socket.create_connection((hostname, port), timeout)
- def create_ssl_connection(self, hostname, port, timeout, **kwargs):
- sock = self.create_tcp_connection(hostname, port, timeout, **kwargs)
- ssl_sock = ssl.wrap_socket(sock, ssl_version=self.ssl_version)
- return ssl_sock
- def create_http_request(self, method, url, headers, body, timeout, **kwargs):
- scheme, netloc, path, query, _ = urlparse.urlsplit(url)
- if netloc.rfind(':') <= netloc.rfind(']'):
- # no port number
- host = netloc
- port = 443 if scheme == 'https' else 80
- else:
- host, _, port = netloc.rpartition(':')
- port = int(port)
- if query:
- path += '?' + query
- if 'Host' not in headers:
- headers['Host'] = host
- if body and 'Content-Length' not in headers:
- headers['Content-Length'] = str(len(body))
- ConnectionType = httplib.HTTPSConnection if scheme == 'https' else httplib.HTTPConnection
- connection = ConnectionType(netloc, timeout=timeout)
- connection.request(method, path, body=body, headers=headers)
- response = connection.getresponse(buffering=True)
- return response
- def create_http_request_withserver(self, fetchserver, method, url, headers, body, timeout, **kwargs):
- return URLFetch(fetchserver, self.create_http_request).fetch(method, url, headers, body, timeout, **kwargs)
- def handle_urlfetch_error(self, fetchserver, response):
- pass
- def handle_urlfetch_response_close(self, fetchserver, response):
- pass
- def parse_header(self):
- if self.command == 'CONNECT':
- netloc = self.path
- elif self.path[0] == '/':
- netloc = self.headers.get('Host', 'localhost')
- self.path = '%s://%s%s' % (self.scheme, netloc, self.path)
- else:
- netloc = urlparse.urlsplit(self.path).netloc
- m = re.match(r'^(.+):(\d+)$', netloc)
- if m:
- self.host = m.group(1).strip('[]')
- self.port = int(m.group(2))
- else:
- self.host = netloc
- self.port = 443 if self.scheme == 'https' else 80
- def forward_socket(self, local, remote, timeout):
- try:
- tick = 1
- bufsize = self.bufsize
- timecount = timeout
- while 1:
- timecount -= tick
- if timecount <= 0:
- break
- (ins, _, errors) = select.select([local, remote], [], [local, remote], tick)
- if errors:
- break
- for sock in ins:
- data = sock.recv(bufsize)
- if not data:
- break
- if sock is remote:
- local.sendall(data)
- timecount = timeout
- else:
- remote.sendall(data)
- timecount = timeout
- except socket.timeout:
- pass
- except NetWorkIOError as e:
- if e.args[0] not in (errno.ECONNABORTED, errno.ECONNRESET, errno.ENOTCONN, errno.EPIPE):
- raise
- if e.args[0] in (errno.EBADF,):
- return
- finally:
- for sock in (remote, local):
- try:
- sock.close()
- except StandardError:
- pass
- def MOCK(self, status, headers, content):
- """mock response"""
- logging.info('%s "MOCK %s %s %s" %d %d', self.address_string(), self.command, self.path, self.protocol_version, status, len(content))
- headers = {k.title(): v for k, v in headers.items()}
- if 'Transfer-Encoding' in headers:
- del headers['Transfer-Encoding']
- if 'Content-Length' not in headers:
- headers['Content-Length'] = len(content)
- if 'Connection' not in headers:
- headers['Connection'] = 'close'
- self.send_response(status)
- for key, value in headers.items():
- self.send_header(key, value)
- self.end_headers()
- self.wfile.write(content)
- def STRIP(self, do_ssl_handshake=True, sticky_filter=None):
- """strip connect"""
- certfile = CertUtil.get_cert(self.host)
- logging.info('%s "STRIP %s %s:%d %s" - -', self.address_string(), self.command, self.host, self.port, self.protocol_version)
- self.send_response(200)
- self.end_headers()
- if do_ssl_handshake:
- try:
- ssl_sock = ssl.wrap_socket(self.connection, ssl_version=self.ssl_version, keyfile=certfile, certfile=certfile, server_side=True)
- except StandardError as e:
- if e.args[0] not in (errno.ECONNABORTED, errno.ECONNRESET):
- logging.exception('ssl.wrap_socket(self.connection=%r) failed: %s', self.connection, e)
- return
- self.connection = ssl_sock
- self.rfile = self.connection.makefile('rb', self.bufsize)
- self.wfile = self.connection.makefile('wb', 0)
- self.scheme = 'https'
- try:
- self.raw_requestline = self.rfile.readline(65537)
- if len(self.raw_requestline) > 65536:
- self.requestline = ''
- self.request_version = ''
- self.command = ''
- self.send_error(414)
- return
- if not self.raw_requestline:
- self.close_connection = 1
- return
- if not self.parse_request():
- return
- except NetWorkIOError as e:
- if e.args[0] not in (errno.ECONNABORTED, errno.ECONNRESET, errno.EPIPE):
- raise
- self.sticky_filter = sticky_filter
- try:
- self.do_METHOD()
- except NetWorkIOError as e:
- if e.args[0] not in (errno.ECONNABORTED, errno.ETIMEDOUT, errno.EPIPE):
- raise
- def FORWARD(self, hostname, port, timeout, kwargs={}):
- """forward socket"""
- do_ssl_handshake = kwargs.pop('do_ssl_handshake', False)
- …
Large files files are truncated, but you can click here to view the full file