PageRenderTime 61ms CodeModel.GetById 24ms RepoModel.GetById 0ms app.codeStats 0ms

/assets/goagent.py

https://github.com/yourmoonlight/gaeproxy
Python | 2417 lines | 2293 code | 65 blank | 59 comment | 108 complexity | 2ee13670943693f3914cc4607be18fb3 MD5 | raw file
Possible License(s): GPL-3.0

Large files files are truncated, but you can click here to view the full file

  1. #!/usr/bin/env python
  2. # coding:utf-8
  3. # Based on GAppProxy 2.0.0 by Du XiaoGang <dugang.2008@gmail.com>
  4. # Based on WallProxy 0.4.0 by Hust Moon <www.ehust@gmail.com>
  5. # Contributor:
  6. # Phus Lu <phus.lu@gmail.com>
  7. # Hewig Xu <hewigovens@gmail.com>
  8. # Ayanamist Yang <ayanamist@gmail.com>
  9. # V.E.O <V.E.O@tom.com>
  10. # Max Lv <max.c.lv@gmail.com>
  11. # AlsoTang <alsotang@gmail.com>
  12. # Christopher Meng <i@cicku.me>
  13. # Yonsm Guo <YonsmGuo@gmail.com>
  14. # Parkman <cseparkman@gmail.com>
  15. # Ming Bai <mbbill@gmail.com>
  16. # Bin Yu <yubinlove1991@gmail.com>
  17. # lileixuan <lileixuan@gmail.com>
  18. # Cong Ding <cong@cding.org>
  19. # Zhang Youfu <zhangyoufu@gmail.com>
  20. # Lu Wei <luwei@barfoo>
  21. # Harmony Meow <harmony.meow@gmail.com>
  22. # logostream <logostream@gmail.com>
  23. # Rui Wang <isnowfy@gmail.com>
  24. # Wang Wei Qiang <wwqgtxx@gmail.com>
  25. # Felix Yan <felixonmars@gmail.com>
  26. # Sui Feng <suifeng.me@qq.com>
  27. # QXO <qxodream@gmail.com>
  28. # Geek An <geekan@foxmail.com>
  29. # Poly Rabbit <mcx_221@foxmail.com>
  30. # oxnz <yunxinyi@gmail.com>
  31. # Shusen Liu <liushusen.smart@gmail.com>
  32. # Yad Smood <y.s.inside@gmail.com>
  33. # Chen Shuang <cs0x7f@gmail.com>
  34. # cnfuyu <cnfuyu@gmail.com>
  35. # cuixin <steven.cuixin@gmail.com>
  36. # s2marine0 <s2marine0@gmail.com>
  37. # Toshio Xiang <snachx@gmail.com>
  38. __version__ = '3.1.5'
  39. import sys
  40. import os
  41. import glob
  42. # GAEProxy Patch
  43. # The sys path in Android is set up outside.
  44. try:
  45. import gevent
  46. import gevent.socket
  47. import gevent.server
  48. import gevent.queue
  49. import gevent.monkey
  50. gevent.monkey.patch_all(subprocess=True)
  51. except ImportError:
  52. gevent = None
  53. except TypeError:
  54. gevent.monkey.patch_all()
  55. sys.stderr.write('\033[31m Warning: Please update gevent to the latest 1.0 version!\033[0m\n')
  56. import errno
  57. import binascii
  58. import time
  59. import struct
  60. import collections
  61. import zlib
  62. import functools
  63. import itertools
  64. import re
  65. import io
  66. import fnmatch
  67. import traceback
  68. import random
  69. import subprocess
  70. import base64
  71. import string
  72. import hashlib
  73. import threading
  74. import thread
  75. import socket
  76. import ssl
  77. import select
  78. import Queue
  79. import SocketServer
  80. import ConfigParser
  81. import BaseHTTPServer
  82. import httplib
  83. import urllib2
  84. import urlparse
  85. try:
  86. import dnslib
  87. except ImportError:
  88. dnslib = None
  89. try:
  90. import OpenSSL
  91. except ImportError:
  92. OpenSSL = None
  93. try:
  94. import pacparser
  95. except ImportError:
  96. pacparser = None
  97. # GAEProxy Patch
  98. class NullDevice():
  99. def write(self, s):
  100. pass
  101. sys.stdout = NullDevice()
  102. sys.stderr = sys.stdout
  103. class DNSCacheUtil(object):
  104. '''DNSCache module, integrated with GAEProxy'''
  105. cache = {"127.0.0.1": 'localhost'}
  106. @staticmethod
  107. def getHost(address):
  108. p = "(?:\d{1,3}\.){3}\d{1,3}"
  109. if re.match(p, address) is None:
  110. return
  111. if address in DNSCacheUtil.cache:
  112. return DNSCacheUtil.cache[address]
  113. host = None
  114. sock = None
  115. address_family = socket.AF_INET
  116. retry = 0
  117. while address not in DNSCacheUtil.cache:
  118. try:
  119. sock = socket.socket(family=address_family, type=socket.SOCK_STREAM)
  120. sock.settimeout(2)
  121. sock.connect(("127.0.0.1", 9090))
  122. sock.sendall(address + "\r\n")
  123. host = sock.recv(512)
  124. if host is not None and not host.startswith("null"):
  125. host = host.strip()
  126. DNSCacheUtil.cache[address] = host
  127. break
  128. else:
  129. if retry > 3:
  130. host = None
  131. break
  132. else:
  133. retry = retry + 1
  134. continue
  135. except socket.error as e:
  136. if e[0] in (10060, 'timed out'):
  137. continue
  138. except Exception, e:
  139. logging.error('reverse dns query exception: %s', e)
  140. break
  141. finally:
  142. if sock:
  143. sock.close()
  144. return host
  145. HAS_PYPY = hasattr(sys, 'pypy_version_info')
  146. NetWorkIOError = (socket.error, ssl.SSLError, OSError) if not OpenSSL else (socket.error, ssl.SSLError, OpenSSL.SSL.Error, OSError)
  147. class Logging(type(sys)):
  148. CRITICAL = 50
  149. FATAL = CRITICAL
  150. ERROR = 40
  151. WARNING = 30
  152. WARN = WARNING
  153. INFO = 20
  154. DEBUG = 10
  155. NOTSET = 0
  156. def __init__(self, *args, **kwargs):
  157. self.level = self.__class__.INFO
  158. #GAEProxy Patch
  159. @classmethod
  160. def getLogger(cls, *args, **kwargs):
  161. return cls(*args, **kwargs)
  162. def basicConfig(self, *args, **kwargs):
  163. self.level = int(kwargs.get('level', self.__class__.INFO))
  164. if self.level > self.__class__.DEBUG:
  165. self.debug = self.dummy
  166. def log(self, level, fmt, *args, **kwargs):
  167. sys.stderr.write('%s - [%s] %s\n' % (level, time.ctime()[4:-5], fmt % args))
  168. def dummy(self, *args, **kwargs):
  169. pass
  170. def debug(self, fmt, *args, **kwargs):
  171. self.log('DEBUG', fmt, *args, **kwargs)
  172. def info(self, fmt, *args, **kwargs):
  173. self.log('INFO', fmt, *args)
  174. def warning(self, fmt, *args, **kwargs):
  175. self.log('WARNING', fmt, *args, **kwargs)
  176. def warn(self, fmt, *args, **kwargs):
  177. self.warning(fmt, *args, **kwargs)
  178. def error(self, fmt, *args, **kwargs):
  179. self.log('ERROR', fmt, *args, **kwargs)
  180. def exception(self, fmt, *args, **kwargs):
  181. self.error(fmt, *args, **kwargs)
  182. sys.stderr.write(traceback.format_exc() + '\n')
  183. def critical(self, fmt, *args, **kwargs):
  184. self.log('CRITICAL', fmt, *args, **kwargs)
  185. logging = sys.modules['logging'] = Logging('logging')
  186. class LRUCache(object):
  187. """http://pypi.python.org/pypi/lru/"""
  188. def __init__(self, max_items=100):
  189. self.cache = {}
  190. self.key_order = []
  191. self.max_items = max_items
  192. def __setitem__(self, key, value):
  193. self.cache[key] = value
  194. self._mark(key)
  195. def __getitem__(self, key):
  196. value = self.cache[key]
  197. self._mark(key)
  198. return value
  199. def _mark(self, key):
  200. if key in self.key_order:
  201. self.key_order.remove(key)
  202. self.key_order.insert(0, key)
  203. if len(self.key_order) > self.max_items:
  204. remove = self.key_order[self.max_items]
  205. del self.cache[remove]
  206. self.key_order.pop(self.max_items)
  207. def clear(self):
  208. self.cache = {}
  209. self.key_order = []
  210. class CertUtil(object):
  211. """CertUtil module, based on mitmproxy"""
  212. ca_vendor = 'GoAgent'
  213. ca_keyfile = 'CA.crt'
  214. ca_certdir = 'certs'
  215. ca_lock = threading.Lock()
  216. @staticmethod
  217. def create_ca():
  218. key = OpenSSL.crypto.PKey()
  219. key.generate_key(OpenSSL.crypto.TYPE_RSA, 2048)
  220. ca = OpenSSL.crypto.X509()
  221. ca.set_serial_number(0)
  222. ca.set_version(2)
  223. subj = ca.get_subject()
  224. subj.countryName = 'CN'
  225. subj.stateOrProvinceName = 'Internet'
  226. subj.localityName = 'Cernet'
  227. subj.organizationName = CertUtil.ca_vendor
  228. subj.organizationalUnitName = '%s Root' % CertUtil.ca_vendor
  229. subj.commonName = '%s CA' % CertUtil.ca_vendor
  230. ca.gmtime_adj_notBefore(0)
  231. ca.gmtime_adj_notAfter(24 * 60 * 60 * 3652)
  232. ca.set_issuer(ca.get_subject())
  233. ca.set_pubkey(key)
  234. ca.add_extensions([
  235. OpenSSL.crypto.X509Extension(b'basicConstraints', True, b'CA:TRUE'),
  236. OpenSSL.crypto.X509Extension(b'nsCertType', True, b'sslCA'),
  237. OpenSSL.crypto.X509Extension(b'extendedKeyUsage', True, b'serverAuth,clientAuth,emailProtection,timeStamping,msCodeInd,msCodeCom,msCTLSign,msSGC,msEFS,nsSGC'),
  238. OpenSSL.crypto.X509Extension(b'keyUsage', False, b'keyCertSign, cRLSign'),
  239. OpenSSL.crypto.X509Extension(b'subjectKeyIdentifier', False, b'hash', subject=ca), ])
  240. ca.sign(key, 'sha1')
  241. return key, ca
  242. @staticmethod
  243. def dump_ca():
  244. key, ca = CertUtil.create_ca()
  245. with open(CertUtil.ca_keyfile, 'wb') as fp:
  246. fp.write(OpenSSL.crypto.dump_certificate(OpenSSL.crypto.FILETYPE_PEM, ca))
  247. fp.write(OpenSSL.crypto.dump_privatekey(OpenSSL.crypto.FILETYPE_PEM, key))
  248. @staticmethod
  249. def _get_cert(commonname, sans=()):
  250. with open(CertUtil.ca_keyfile, 'rb') as fp:
  251. content = fp.read()
  252. key = OpenSSL.crypto.load_privatekey(OpenSSL.crypto.FILETYPE_PEM, content)
  253. ca = OpenSSL.crypto.load_certificate(OpenSSL.crypto.FILETYPE_PEM, content)
  254. pkey = OpenSSL.crypto.PKey()
  255. pkey.generate_key(OpenSSL.crypto.TYPE_RSA, 2048)
  256. req = OpenSSL.crypto.X509Req()
  257. subj = req.get_subject()
  258. subj.countryName = 'CN'
  259. subj.stateOrProvinceName = 'Internet'
  260. subj.localityName = 'Cernet'
  261. subj.organizationalUnitName = '%s Branch' % CertUtil.ca_vendor
  262. if commonname[0] == '.':
  263. subj.commonName = '*' + commonname
  264. subj.organizationName = '*' + commonname
  265. sans = ['*'+commonname] + [x for x in sans if x != '*'+commonname]
  266. else:
  267. subj.commonName = commonname
  268. subj.organizationName = commonname
  269. sans = [commonname] + [x for x in sans if x != commonname]
  270. # GAEProxy Patch
  271. req.add_extensions([OpenSSL.crypto.X509Extension(b'subjectAltName', True, ', '.join('DNS: %s' % x for x in sans))])
  272. req.set_pubkey(pkey)
  273. req.sign(pkey, 'sha1')
  274. cert = OpenSSL.crypto.X509()
  275. # GAEProxy Patch
  276. cert.set_version(3)
  277. try:
  278. cert.set_serial_number(int(hashlib.md5(commonname.encode('utf-8')).hexdigest(), 16))
  279. except OpenSSL.SSL.Error:
  280. cert.set_serial_number(int(time.time()*1000))
  281. cert.gmtime_adj_notBefore(0)
  282. cert.gmtime_adj_notAfter(60 * 60 * 24 * 3652)
  283. cert.set_issuer(ca.get_subject())
  284. cert.set_subject(req.get_subject())
  285. cert.set_pubkey(req.get_pubkey())
  286. if commonname[0] == '.':
  287. sans = ['*'+commonname] + [s for s in sans if s != '*'+commonname]
  288. else:
  289. sans = [commonname] + [s for s in sans if s != commonname]
  290. # GAEProxy Patch
  291. cert.add_extensions([OpenSSL.crypto.X509Extension(b'subjectAltName', True, ', '.join('DNS: %s' % x for x in sans))])
  292. cert.sign(key, 'sha1')
  293. certfile = os.path.join(CertUtil.ca_certdir, commonname + '.crt')
  294. with open(certfile, 'wb') as fp:
  295. fp.write(OpenSSL.crypto.dump_certificate(OpenSSL.crypto.FILETYPE_PEM, cert))
  296. fp.write(OpenSSL.crypto.dump_privatekey(OpenSSL.crypto.FILETYPE_PEM, pkey))
  297. return certfile
  298. @staticmethod
  299. def get_cert(commonname, sans=()):
  300. # GAEProxy Patch
  301. sans = ["*.akamaihd.net","*.fbcdn.net","*.google.com","*.appspot.com","*.googleapis.com","*.googlevideo.com","*.twitter.com","*.facebook.com","*.whatsapp.net"]
  302. if commonname.count('.') >= 2 and [len(x) for x in reversed(commonname.split('.'))] > [2, 4]:
  303. commonname = '.'+commonname.partition('.')[-1]
  304. certfile = os.path.join(CertUtil.ca_certdir, commonname + '.crt')
  305. if os.path.exists(certfile):
  306. return certfile
  307. elif OpenSSL is None:
  308. return CertUtil.ca_keyfile
  309. else:
  310. with CertUtil.ca_lock:
  311. if os.path.exists(certfile):
  312. return certfile
  313. return CertUtil._get_cert(commonname, sans)
  314. @staticmethod
  315. def import_ca(certfile):
  316. commonname = os.path.splitext(os.path.basename(certfile))[0]
  317. if OpenSSL:
  318. try:
  319. with open(certfile, 'rb') as fp:
  320. x509 = OpenSSL.crypto.load_certificate(OpenSSL.crypto.FILETYPE_PEM, fp.read())
  321. commonname = next(v.decode() for k, v in x509.get_subject().get_components() if k == b'O')
  322. except Exception as e:
  323. logging.error('load_certificate(certfile=%r) failed:%s', certfile, e)
  324. # GAEProxy Patch
  325. return 0
  326. @staticmethod
  327. def check_ca():
  328. #Check CA exists
  329. capath = os.path.join(os.path.dirname(os.path.abspath(__file__)), CertUtil.ca_keyfile)
  330. certdir = os.path.join(os.path.dirname(os.path.abspath(__file__)), CertUtil.ca_certdir)
  331. if not os.path.exists(capath):
  332. if not OpenSSL:
  333. logging.critical('CA.key is not exist and OpenSSL is disabled, ABORT!')
  334. sys.exit(-1)
  335. if os.path.exists(certdir):
  336. if os.path.isdir(certdir):
  337. any(os.remove(x) for x in glob.glob(certdir+'/*.crt')+glob.glob(certdir+'/.*.crt'))
  338. else:
  339. os.remove(certdir)
  340. os.mkdir(certdir)
  341. CertUtil.dump_ca()
  342. if glob.glob('%s/*.key' % CertUtil.ca_certdir):
  343. for filename in glob.glob('%s/*.key' % CertUtil.ca_certdir):
  344. try:
  345. os.remove(filename)
  346. os.remove(os.path.splitext(filename)[0]+'.crt')
  347. except EnvironmentError:
  348. pass
  349. #Check CA imported
  350. if CertUtil.import_ca(capath) != 0:
  351. logging.warning('install root certificate failed, Please run as administrator/root/sudo')
  352. #Check Certs Dir
  353. if not os.path.exists(certdir):
  354. os.makedirs(certdir)
  355. class SSLConnection(object):
  356. has_gevent = socket.socket is getattr(sys.modules.get('gevent.socket'), 'socket', None)
  357. def __init__(self, context, sock):
  358. self._context = context
  359. self._sock = sock
  360. self._connection = OpenSSL.SSL.Connection(context, sock)
  361. self._makefile_refs = 0
  362. if self.has_gevent:
  363. self._wait_read = gevent.socket.wait_read
  364. self._wait_write = gevent.socket.wait_write
  365. self._wait_readwrite = gevent.socket.wait_readwrite
  366. else:
  367. self._wait_read = lambda fd,t: select.select([fd], [], [fd], t)
  368. self._wait_write = lambda fd,t: select.select([], [fd], [fd], t)
  369. self._wait_readwrite = lambda fd,t: select.select([fd], [fd], [fd], t)
  370. def __getattr__(self, attr):
  371. if attr not in ('_context', '_sock', '_connection', '_makefile_refs'):
  372. return getattr(self._connection, attr)
  373. def accept(self):
  374. sock, addr = self._sock.accept()
  375. client = OpenSSL.SSL.Connection(sock._context, sock)
  376. return client, addr
  377. def do_handshake(self):
  378. timeout = self._sock.gettimeout()
  379. while True:
  380. try:
  381. self._connection.do_handshake()
  382. break
  383. except (OpenSSL.SSL.WantReadError, OpenSSL.SSL.WantX509LookupError, OpenSSL.SSL.WantWriteError):
  384. sys.exc_clear()
  385. self._wait_readwrite(self._sock.fileno(), timeout)
  386. def connect(self, *args, **kwargs):
  387. timeout = self._sock.gettimeout()
  388. while True:
  389. try:
  390. self._connection.connect(*args, **kwargs)
  391. break
  392. except (OpenSSL.SSL.WantReadError, OpenSSL.SSL.WantX509LookupError):
  393. sys.exc_clear()
  394. self._wait_read(self._sock.fileno(), timeout)
  395. except OpenSSL.SSL.WantWriteError:
  396. sys.exc_clear()
  397. self._wait_write(self._sock.fileno(), timeout)
  398. def send(self, data, flags=0):
  399. timeout = self._sock.gettimeout()
  400. while True:
  401. try:
  402. self._connection.send(data, flags)
  403. break
  404. except (OpenSSL.SSL.WantReadError, OpenSSL.SSL.WantX509LookupError):
  405. sys.exc_clear()
  406. self._wait_read(self._sock.fileno(), timeout)
  407. except OpenSSL.SSL.WantWriteError:
  408. sys.exc_clear()
  409. self._wait_write(self._sock.fileno(), timeout)
  410. except OpenSSL.SSL.SysCallError as e:
  411. if e[0] == -1 and not data:
  412. # errors when writing empty strings are expected and can be ignored
  413. return 0
  414. raise
  415. def recv(self, bufsiz, flags=0):
  416. timeout = self._sock.gettimeout()
  417. pending = self._connection.pending()
  418. if pending:
  419. return self._connection.recv(min(pending, bufsiz))
  420. while True:
  421. try:
  422. return self._connection.recv(bufsiz, flags)
  423. except (OpenSSL.SSL.WantReadError, OpenSSL.SSL.WantX509LookupError):
  424. sys.exc_clear()
  425. self._wait_read(self._sock.fileno(), timeout)
  426. except OpenSSL.SSL.WantWriteError:
  427. sys.exc_clear()
  428. self._wait_write(self._sock.fileno(), timeout)
  429. except OpenSSL.SSL.ZeroReturnError:
  430. return ''
  431. def read(self, bufsiz, flags=0):
  432. return self.recv(bufsiz, flags)
  433. def write(self, buf, flags=0):
  434. return self.sendall(buf, flags)
  435. def close(self):
  436. if self._makefile_refs < 1:
  437. self._connection = None
  438. if self._sock:
  439. socket.socket.close(self._sock)
  440. else:
  441. self._makefile_refs -= 1
  442. def makefile(self, mode='r', bufsize=-1):
  443. self._makefile_refs += 1
  444. return socket._fileobject(self, mode, bufsize, close=True)
  445. class ProxyUtil(object):
  446. """ProxyUtil module, based on urllib2"""
  447. @staticmethod
  448. def parse_proxy(proxy):
  449. return urllib2._parse_proxy(proxy)
  450. @staticmethod
  451. def get_system_proxy():
  452. proxies = urllib2.getproxies()
  453. return proxies.get('https') or proxies.get('http') or {}
  454. @staticmethod
  455. def get_listen_ip():
  456. sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
  457. sock.connect(('8.8.8.8', 53))
  458. listen_ip = sock.getsockname()[0]
  459. sock.close()
  460. return listen_ip
  461. # GAEProxy Patch
  462. # No PAC
  463. def dns_remote_resolve(qname, dnsservers, blacklist, timeout):
  464. """
  465. http://gfwrev.blogspot.com/2009/11/gfwdns.html
  466. http://zh.wikipedia.org/wiki/域名服务器缓存污染
  467. http://support.microsoft.com/kb/241352
  468. """
  469. query = dnslib.DNSRecord(q=dnslib.DNSQuestion(qname))
  470. query_data = query.pack()
  471. dns_v4_servers = [x for x in dnsservers if ':' not in x]
  472. dns_v6_servers = [x for x in dnsservers if ':' in x]
  473. sock_v4 = sock_v6 = None
  474. socks = []
  475. if dns_v4_servers:
  476. sock_v4 = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
  477. socks.append(sock_v4)
  478. if dns_v6_servers:
  479. sock_v6 = socket.socket(socket.AF_INET6, socket.SOCK_DGRAM)
  480. socks.append(sock_v6)
  481. timeout_at = time.time() + timeout
  482. try:
  483. for _ in xrange(2):
  484. try:
  485. for dnsserver in dns_v4_servers:
  486. sock_v4.sendto(query_data, (dnsserver, 53))
  487. for dnsserver in dns_v6_servers:
  488. sock_v6.sendto(query_data, (dnsserver, 53))
  489. while time.time() < timeout_at:
  490. ins, _, _ = select.select(socks, [], [], 0.1)
  491. for sock in ins:
  492. reply_data, _ = sock.recvfrom(512)
  493. reply = dnslib.DNSRecord.parse(reply_data)
  494. rtypes = (1, 28) if sock is sock_v6 else (1,)
  495. iplist = [str(x.rdata) for x in reply.rr if x.rtype in rtypes]
  496. if any(x in blacklist for x in iplist):
  497. logging.warning('query qname=%r reply bad iplist=%r', qname, iplist)
  498. else:
  499. logging.debug('query qname=%r reply iplist=%s', qname, iplist)
  500. return iplist
  501. except socket.error as e:
  502. logging.warning('handle dns query=%s socket: %r', query, e)
  503. finally:
  504. for sock in socks:
  505. sock.close()
  506. def get_dnsserver_list():
  507. if os.name == 'nt':
  508. import ctypes, ctypes.wintypes, struct, socket
  509. DNS_CONFIG_DNS_SERVER_LIST = 6
  510. buf = ctypes.create_string_buffer(2048)
  511. ctypes.windll.dnsapi.DnsQueryConfig(DNS_CONFIG_DNS_SERVER_LIST, 0, None, None, ctypes.byref(buf), ctypes.byref(ctypes.wintypes.DWORD(len(buf))))
  512. ips = struct.unpack('I', buf[0:4])[0]
  513. out = []
  514. for i in xrange(ips):
  515. start = (i+1) * 4
  516. out.append(socket.inet_ntoa(buf[start:start+4]))
  517. return out
  518. elif os.path.isfile('/etc/resolv.conf'):
  519. with open('/etc/resolv.conf', 'rb') as fp:
  520. return re.findall(r'(?m)^nameserver\s+(\S+)', fp.read())
  521. else:
  522. logging.warning("get_dnsserver_list failed: unsupport platform '%s-%s'", sys.platform, os.name)
  523. return []
  524. def spawn_later(seconds, target, *args, **kwargs):
  525. def wrap(*args, **kwargs):
  526. __import__('time').sleep(seconds)
  527. return target(*args, **kwargs)
  528. return __import__('thread').start_new_thread(wrap, args, kwargs)
  529. class HTTPUtil(object):
  530. """HTTP Request Class"""
  531. MessageClass = dict
  532. protocol_version = 'HTTP/1.1'
  533. skip_headers = frozenset(['Vary', 'Via', 'X-Forwarded-For', 'Proxy-Authorization', 'Proxy-Connection', 'Upgrade', 'X-Chrome-Variations', 'Connection', 'Cache-Control'])
  534. ssl_validate = False
  535. ssl_obfuscate = False
  536. ssl_ciphers = ':'.join(['ECDHE-ECDSA-AES256-SHA',
  537. 'ECDHE-RSA-AES256-SHA',
  538. 'DHE-RSA-CAMELLIA256-SHA',
  539. 'DHE-DSS-CAMELLIA256-SHA',
  540. 'DHE-RSA-AES256-SHA',
  541. 'DHE-DSS-AES256-SHA',
  542. 'ECDH-RSA-AES256-SHA',
  543. 'ECDH-ECDSA-AES256-SHA',
  544. 'CAMELLIA256-SHA',
  545. 'AES256-SHA',
  546. 'ECDHE-ECDSA-RC4-SHA',
  547. 'ECDHE-ECDSA-AES128-SHA',
  548. 'ECDHE-RSA-RC4-SHA',
  549. 'ECDHE-RSA-AES128-SHA',
  550. 'DHE-RSA-CAMELLIA128-SHA',
  551. 'DHE-DSS-CAMELLIA128-SHA',
  552. 'DHE-RSA-AES128-SHA',
  553. 'DHE-DSS-AES128-SHA',
  554. 'ECDH-RSA-RC4-SHA',
  555. 'ECDH-RSA-AES128-SHA',
  556. 'ECDH-ECDSA-RC4-SHA',
  557. 'ECDH-ECDSA-AES128-SHA',
  558. 'SEED-SHA',
  559. 'CAMELLIA128-SHA',
  560. 'RC4-SHA',
  561. 'RC4-MD5',
  562. 'AES128-SHA',
  563. 'ECDHE-ECDSA-DES-CBC3-SHA',
  564. 'ECDHE-RSA-DES-CBC3-SHA',
  565. 'EDH-RSA-DES-CBC3-SHA',
  566. 'EDH-DSS-DES-CBC3-SHA',
  567. 'ECDH-RSA-DES-CBC3-SHA',
  568. 'ECDH-ECDSA-DES-CBC3-SHA',
  569. 'DES-CBC3-SHA',
  570. 'TLS_EMPTY_RENEGOTIATION_INFO_SCSV'])
  571. def __init__(self, max_window=4, max_timeout=8, max_retry=4, proxy='', dns_servers=[], dns_blacklist=set()):
  572. # http://docs.python.org/dev/library/ssl.html
  573. # http://blog.ivanristic.com/2009/07/examples-of-the-information-collected-from-ssl-handshakes.html
  574. # http://src.chromium.org/svn/trunk/src/net/third_party/nss/ssl/sslenum.c
  575. # http://www.openssl.org/docs/apps/ciphers.html
  576. # openssl s_server -accept 443 -key CA.crt -cert CA.crt
  577. # set_ciphers as Modern Browsers
  578. self.max_window = max_window
  579. self.max_retry = max_retry
  580. self.max_timeout = max_timeout
  581. self.tcp_connection_time = collections.defaultdict(float)
  582. self.tcp_connection_cache = collections.defaultdict(Queue.PriorityQueue)
  583. self.ssl_connection_time = collections.defaultdict(float)
  584. self.ssl_connection_cache = collections.defaultdict(Queue.PriorityQueue)
  585. self.dns = {}
  586. self.proxy = proxy
  587. self.openssl_context = None
  588. if self.proxy:
  589. self.dns_resolve = self.__dns_resolve_withproxy
  590. self.create_connection = self.__create_connection_withproxy
  591. self.create_ssl_connection = self.__create_ssl_connection_withproxy
  592. self.dns_servers = dns_servers
  593. self.dns_blacklist = dns_blacklist
  594. def set_openssl_option(self, validate=True, obfuscate=True):
  595. if self.openssl_context is None:
  596. self.openssl_context = OpenSSL.SSL.Context(OpenSSL.SSL.TLSv1_METHOD)
  597. self.openssl_context.set_session_id(binascii.b2a_hex(os.urandom(10)))
  598. if hasattr(OpenSSL.SSL, 'SESS_CACHE_BOTH'):
  599. self.openssl_context.set_session_cache_mode(OpenSSL.SSL.SESS_CACHE_BOTH)
  600. if validate:
  601. self.openssl_context.load_verify_locations(os.path.join(os.path.dirname(os.path.abspath(__file__)), 'cacert.pem'))
  602. self.openssl_context.set_verify(OpenSSL.SSL.VERIFY_PEER, lambda c, x, e, d, ok: ok)
  603. if obfuscate:
  604. ssl_ciphers = ':'.join(x for x in self.ssl_ciphers.split(':') if random.random() > 0.5)
  605. self.openssl_context.set_cipher_list(ssl_ciphers)
  606. def dns_resolve(self, host, dnsservers=[], ipv4_only=True):
  607. iplist = self.dns.get(host)
  608. if not iplist:
  609. if not dnsservers:
  610. iplist = list(set(socket.gethostbyname_ex(host)[-1]) - self.dns_blacklist)
  611. else:
  612. iplist = dns_remote_resolve(host, dnsservers, self.dns_blacklist, timeout=2)
  613. if not iplist:
  614. iplist = dns_remote_resolve(host, self.dns_servers, self.dns_blacklist, timeout=2)
  615. if ipv4_only:
  616. iplist = [ip for ip in iplist if re.match(r'\d+\.\d+\.\d+\.\d+', ip)]
  617. self.dns[host] = iplist = list(set(iplist))
  618. return iplist
  619. def __dns_resolve_withproxy(self, host, dnsservers=[], ipv4_only=True):
  620. return [host]
  621. def create_connection(self, address, timeout=None, source_address=None, **kwargs):
  622. connection_cache_key = kwargs.get('cache_key')
  623. def _create_connection(ipaddr, timeout, queobj):
  624. sock = None
  625. try:
  626. # create a ipv4/ipv6 socket object
  627. sock = socket.socket(socket.AF_INET if ':' not in ipaddr[0] else socket.AF_INET6)
  628. # set reuseaddr option to avoid 10048 socket error
  629. sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
  630. # resize socket recv buffer 8K->32K to improve browser releated application performance
  631. sock.setsockopt(socket.SOL_SOCKET, socket.SO_RCVBUF, 32*1024)
  632. # disable nagle algorithm to send http request quickly.
  633. sock.setsockopt(socket.SOL_TCP, socket.TCP_NODELAY, True)
  634. # set a short timeout to trigger timeout retry more quickly.
  635. sock.settimeout(timeout or self.max_timeout)
  636. # start connection time record
  637. start_time = time.time()
  638. # TCP connect
  639. sock.connect(ipaddr)
  640. # record TCP connection time
  641. self.tcp_connection_time[ipaddr] = time.time() - start_time
  642. # put ssl socket object to output queobj
  643. queobj.put(sock)
  644. except (socket.error, OSError) as e:
  645. # any socket.error, put Excpetions to output queobj.
  646. queobj.put(e)
  647. # reset a large and random timeout to the ipaddr
  648. self.tcp_connection_time[ipaddr] = self.max_timeout+random.random()
  649. # close tcp socket
  650. if sock:
  651. sock.close()
  652. def _close_connection(count, queobj):
  653. for i in range(count):
  654. sock = queobj.get()
  655. if sock and not isinstance(sock, Exception):
  656. if connection_cache_key and i == 0:
  657. self.tcp_connection_cache[connection_cache_key].put((time.time(), sock))
  658. else:
  659. sock.close()
  660. try:
  661. while connection_cache_key:
  662. ctime, sock = self.tcp_connection_cache[connection_cache_key].get_nowait()
  663. if time.time() - ctime < 30:
  664. return sock
  665. except Queue.Empty:
  666. pass
  667. host, port = address
  668. result = None
  669. addresses = [(x, port) for x in self.dns_resolve(host)]
  670. if port == 443:
  671. get_connection_time = lambda addr: self.ssl_connection_time.__getitem__(addr) or self.tcp_connection_time.__getitem__(addr)
  672. else:
  673. get_connection_time = self.tcp_connection_time.__getitem__
  674. for i in range(self.max_retry):
  675. window = min((self.max_window+1)//2 + min(i, 1), len(addresses))
  676. addresses.sort(key=get_connection_time)
  677. addrs = addresses[:window] + random.sample(addresses, min(len(addresses), window, self.max_window-window))
  678. queobj = Queue.Queue()
  679. for addr in addrs:
  680. thread.start_new_thread(_create_connection, (addr, timeout, queobj))
  681. for i in range(len(addrs)):
  682. result = queobj.get()
  683. if not isinstance(result, (socket.error, OSError)):
  684. thread.start_new_thread(_close_connection, (len(addrs)-i-1, queobj))
  685. return result
  686. else:
  687. if i == 0:
  688. # only output first error
  689. logging.warning('create_connection to %s return %r, try again.', addrs, result)
  690. def create_ssl_connection(self, address, timeout=None, source_address=None, **kwargs):
  691. connection_cache_key = kwargs.get('cache_key')
  692. validate = kwargs.get('validate')
  693. def _create_ssl_connection(ipaddr, timeout, queobj):
  694. sock = None
  695. ssl_sock = None
  696. try:
  697. # create a ipv4/ipv6 socket object
  698. sock = socket.socket(socket.AF_INET if ':' not in ipaddr[0] else socket.AF_INET6)
  699. # set reuseaddr option to avoid 10048 socket error
  700. sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
  701. # resize socket recv buffer 8K->32K to improve browser releated application performance
  702. sock.setsockopt(socket.SOL_SOCKET, socket.SO_RCVBUF, 32*1024)
  703. # disable negal algorithm to send http request quickly.
  704. sock.setsockopt(socket.SOL_TCP, socket.TCP_NODELAY, True)
  705. # set a short timeout to trigger timeout retry more quickly.
  706. sock.settimeout(timeout or self.max_timeout)
  707. # pick up the certificate
  708. if not validate:
  709. ssl_sock = ssl.wrap_socket(sock, do_handshake_on_connect=False)
  710. else:
  711. ssl_sock = ssl.wrap_socket(sock, cert_reqs=ssl.CERT_REQUIRED, ca_certs=os.path.join(os.path.dirname(os.path.abspath(__file__)),'cacert.pem'), do_handshake_on_connect=False)
  712. ssl_sock.settimeout(timeout or self.max_timeout)
  713. # start connection time record
  714. start_time = time.time()
  715. # TCP connect
  716. ssl_sock.connect(ipaddr)
  717. connected_time = time.time()
  718. # SSL handshake
  719. ssl_sock.do_handshake()
  720. handshaked_time = time.time()
  721. # record TCP connection time
  722. self.tcp_connection_time[ipaddr] = ssl_sock.tcp_time = connected_time - start_time
  723. # record SSL connection time
  724. self.ssl_connection_time[ipaddr] = ssl_sock.ssl_time = handshaked_time - start_time
  725. ssl_sock.ssl_time = connected_time - start_time
  726. # sometimes, we want to use raw tcp socket directly(select/epoll), so setattr it to ssl socket.
  727. ssl_sock.sock = sock
  728. # verify SSL certificate.
  729. if validate and address[0].endswith('.appspot.com'):
  730. cert = ssl_sock.getpeercert()
  731. orgname = next((v for ((k, v),) in cert['subject'] if k == 'organizationName'))
  732. if not orgname.lower().startswith('google '):
  733. raise ssl.SSLError("%r certificate organizationName(%r) not startswith 'Google'" % (address[0], orgname))
  734. # put ssl socket object to output queobj
  735. queobj.put(ssl_sock)
  736. except (socket.error, ssl.SSLError, OSError) as e:
  737. # any socket.error, put Excpetions to output queobj.
  738. queobj.put(e)
  739. # reset a large and random timeout to the ipaddr
  740. self.ssl_connection_time[ipaddr] = self.max_timeout + random.random()
  741. # close ssl socket
  742. if ssl_sock:
  743. ssl_sock.close()
  744. # close tcp socket
  745. if sock:
  746. sock.close()
  747. def _create_openssl_connection(ipaddr, timeout, queobj):
  748. sock = None
  749. ssl_sock = None
  750. try:
  751. # create a ipv4/ipv6 socket object
  752. sock = socket.socket(socket.AF_INET if ':' not in ipaddr[0] else socket.AF_INET6)
  753. # set reuseaddr option to avoid 10048 socket error
  754. sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
  755. # resize socket recv buffer 8K->32K to improve browser releated application performance
  756. sock.setsockopt(socket.SOL_SOCKET, socket.SO_RCVBUF, 32*1024)
  757. # disable negal algorithm to send http request quickly.
  758. sock.setsockopt(socket.SOL_TCP, socket.TCP_NODELAY, True)
  759. # set a short timeout to trigger timeout retry more quickly.
  760. sock.settimeout(timeout or self.max_timeout)
  761. # pick up the certificate
  762. server_hostname = b'www.google.com' if address[0].endswith('.appspot.com') else None
  763. ssl_sock = SSLConnection(self.openssl_context, sock)
  764. ssl_sock.set_connect_state()
  765. if server_hostname:
  766. ssl_sock.set_tlsext_host_name(server_hostname)
  767. # start connection time record
  768. start_time = time.time()
  769. # TCP connect
  770. ssl_sock.connect(ipaddr)
  771. connected_time = time.time()
  772. # SSL handshake
  773. ssl_sock.do_handshake()
  774. handshaked_time = time.time()
  775. # record TCP connection time
  776. self.tcp_connection_time[ipaddr] = ssl_sock.tcp_time = connected_time - start_time
  777. # record SSL connection time
  778. self.ssl_connection_time[ipaddr] = ssl_sock.ssl_time = handshaked_time - start_time
  779. # sometimes, we want to use raw tcp socket directly(select/epoll), so setattr it to ssl socket.
  780. ssl_sock.sock = sock
  781. # verify SSL certificate.
  782. if validate and address[0].endswith('.appspot.com'):
  783. cert = ssl_sock.get_peer_certificate()
  784. commonname = next((v for k, v in cert.get_subject().get_components() if k == 'CN'))
  785. if '.google' not in commonname and not commonname.endswith('.appspot.com'):
  786. raise socket.error("Host name '%s' doesn't match certificate host '%s'" % (address[0], commonname))
  787. # put ssl socket object to output queobj
  788. queobj.put(ssl_sock)
  789. except (socket.error, OpenSSL.SSL.Error, OSError) as e:
  790. # any socket.error, put Excpetions to output queobj.
  791. queobj.put(e)
  792. # reset a large and random timeout to the ipaddr
  793. self.ssl_connection_time[ipaddr] = self.max_timeout + random.random()
  794. # close ssl socket
  795. if ssl_sock:
  796. ssl_sock.close()
  797. # close tcp socket
  798. if sock:
  799. sock.close()
  800. def _close_ssl_connection(count, queobj, first_tcp_time, first_ssl_time):
  801. for i in range(count):
  802. sock = queobj.get()
  803. ssl_time_threshold = min(1, 1.5 * first_ssl_time)
  804. if sock and not isinstance(sock, Exception):
  805. if connection_cache_key and sock.ssl_time < ssl_time_threshold:
  806. self.ssl_connection_cache[connection_cache_key].put((time.time(), sock))
  807. else:
  808. sock.close()
  809. try:
  810. while connection_cache_key:
  811. ctime, sock = self.ssl_connection_cache[connection_cache_key].get_nowait()
  812. if time.time() - ctime < 30:
  813. return sock
  814. except Queue.Empty:
  815. pass
  816. host, port = address
  817. result = None
  818. # create_connection = _create_ssl_connection if not validate else _create_openssl_connection
  819. create_connection = _create_ssl_connection
  820. addresses = [(x, port) for x in self.dns_resolve(host)]
  821. for i in range(self.max_retry):
  822. window = min((self.max_window+1)//2 + min(i, 1), len(addresses))
  823. addresses.sort(key=self.ssl_connection_time.__getitem__)
  824. addrs = addresses[:window] + random.sample(addresses, min(len(addresses), window, self.max_window-window))
  825. queobj = Queue.Queue()
  826. for addr in addrs:
  827. thread.start_new_thread(create_connection, (addr, timeout, queobj))
  828. for i in range(len(addrs)):
  829. result = queobj.get()
  830. if not isinstance(result, Exception):
  831. thread.start_new_thread(_close_ssl_connection, (len(addrs)-i-1, queobj, result.tcp_time, result.ssl_time))
  832. return result
  833. else:
  834. if i == 0:
  835. # only output first error
  836. logging.warning('create_ssl_connection to %s return %r, try again.', addrs, result)
  837. def __create_connection_withproxy(self, address, timeout=None, source_address=None, **kwargs):
  838. host, port = address
  839. logging.debug('__create_connection_withproxy connect (%r, %r)', host, port)
  840. _, proxyuser, proxypass, proxyaddress = ProxyUtil.parse_proxy(self.proxy)
  841. try:
  842. try:
  843. self.dns_resolve(host)
  844. except (socket.error, OSError):
  845. pass
  846. proxyhost, _, proxyport = proxyaddress.rpartition(':')
  847. sock = socket.create_connection((proxyhost, int(proxyport)))
  848. if host in self.dns:
  849. hostname = random.choice(self.dns[host])
  850. elif host.endswith('.appspot.com'):
  851. hostname = 'www.google.com'
  852. else:
  853. hostname = host
  854. request_data = 'CONNECT %s:%s HTTP/1.1\r\n' % (hostname, port)
  855. if proxyuser and proxypass:
  856. request_data += 'Proxy-authorization: Basic %s\r\n' % base64.b64encode(('%s:%s' % (proxyuser, proxypass)).encode()).decode().strip()
  857. request_data += '\r\n'
  858. sock.sendall(request_data)
  859. response = httplib.HTTPResponse(sock)
  860. response.begin()
  861. if response.status >= 400:
  862. logging.error('__create_connection_withproxy return http error code %s', response.status)
  863. sock = None
  864. return sock
  865. except Exception as e:
  866. logging.error('__create_connection_withproxy error %s', e)
  867. raise
  868. def __create_ssl_connection_withproxy(self, address, timeout=None, source_address=None, **kwargs):
  869. host, port = address
  870. logging.debug('__create_ssl_connection_withproxy connect (%r, %r)', host, port)
  871. try:
  872. sock = self.__create_connection_withproxy(address, timeout, source_address)
  873. ssl_sock = ssl.wrap_socket(sock)
  874. ssl_sock.sock = sock
  875. return ssl_sock
  876. except Exception as e:
  877. logging.error('__create_ssl_connection_withproxy error %s', e)
  878. raise
  879. def forward_socket(self, local, remote, timeout=60, tick=2, bufsize=8192, maxping=None, maxpong=None):
  880. try:
  881. timecount = timeout
  882. while 1:
  883. timecount -= tick
  884. if timecount <= 0:
  885. break
  886. (ins, _, errors) = select.select([local, remote], [], [local, remote], tick)
  887. if errors:
  888. break
  889. if ins:
  890. for sock in ins:
  891. data = sock.recv(bufsize)
  892. if data:
  893. if sock is remote:
  894. local.sendall(data)
  895. timecount = maxpong or timeout
  896. else:
  897. remote.sendall(data)
  898. timecount = maxping or timeout
  899. else:
  900. return
  901. except NetWorkIOError as e:
  902. if e.args[0] not in (errno.ECONNABORTED, errno.ECONNRESET, errno.ENOTCONN, errno.EPIPE):
  903. raise
  904. finally:
  905. if local:
  906. local.close()
  907. if remote:
  908. remote.close()
  909. def green_forward_socket(self, local, remote, timeout=60, tick=2, bufsize=8192, maxping=None, maxpong=None, pongcallback=None, bitmask=None):
  910. def io_copy(dest, source):
  911. try:
  912. dest.settimeout(timeout)
  913. source.settimeout(timeout)
  914. while 1:
  915. data = source.recv(bufsize)
  916. if not data:
  917. break
  918. if bitmask:
  919. data = ''.join(chr(ord(x) ^ bitmask) for x in data)
  920. dest.sendall(data)
  921. except NetWorkIOError as e:
  922. if e.args[0] not in ('timed out', errno.ECONNABORTED, errno.ECONNRESET, errno.EBADF, errno.EPIPE, errno.ENOTCONN, errno.ETIMEDOUT):
  923. raise
  924. finally:
  925. if local:
  926. local.close()
  927. if remote:
  928. remote.close()
  929. thread.start_new_thread(io_copy, (remote.dup(), local.dup()))
  930. io_copy(local, remote)
  931. def _request(self, sock, method, path, protocol_version, headers, payload, bufsize=8192, crlf=None, return_sock=None):
  932. skip_headers = self.skip_headers
  933. need_crlf = bool(crlf)
  934. if need_crlf:
  935. fakehost = 'www.' + ''.join(random.choice(('bcdfghjklmnpqrstvwxyz','aeiou')[x&1]) for x in xrange(random.randint(5,20))) + random.choice(['.net', '.com', '.org'])
  936. request_data = 'GET / HTTP/1.1\r\nHost: %s\r\n\r\n\r\n\r\r' % fakehost
  937. else:
  938. request_data = ''
  939. request_data += '%s %s %s\r\n' % (method, path, protocol_version)
  940. request_data += ''.join('%s: %s\r\n' % (k.title(), v) for k, v in headers.items() if k.title() not in skip_headers)
  941. if self.proxy:
  942. _, username, password, _ = ProxyUtil.parse_proxy(self.proxy)
  943. if username and password:
  944. request_data += 'Proxy-Authorization: Basic %s\r\n' % base64.b64encode(('%s:%s' % (username, password)).encode()).decode().strip()
  945. request_data += '\r\n'
  946. if isinstance(payload, bytes):
  947. sock.sendall(request_data.encode() + payload)
  948. elif hasattr(payload, 'read'):
  949. sock.sendall(request_data)
  950. while 1:
  951. data = payload.read(bufsize)
  952. if not data:
  953. break
  954. sock.sendall(data)
  955. else:
  956. raise TypeError('http_util.request(payload) must be a string or buffer, not %r' % type(payload))
  957. if need_crlf:
  958. try:
  959. response = httplib.HTTPResponse(sock)
  960. response.begin()
  961. response.read()
  962. except Exception:
  963. logging.exception('crlf skip read')
  964. return None
  965. if return_sock:
  966. return sock
  967. response = httplib.HTTPResponse(sock, buffering=True)
  968. try:
  969. response.begin()
  970. except httplib.BadStatusLine:
  971. response = None
  972. return response
  973. def request(self, method, url, payload=None, headers={}, realhost='', bufsize=8192, crlf=None, validate=None, return_sock=None, connection_cache_key=None):
  974. scheme, netloc, path, _, query, _ = urlparse.urlparse(url)
  975. if netloc.rfind(':') <= netloc.rfind(']'):
  976. # no port number
  977. host = netloc
  978. port = 443 if scheme == 'https' else 80
  979. else:
  980. host, _, port = netloc.rpartition(':')
  981. port = int(port)
  982. if query:
  983. path += '?' + query
  984. if 'Host' not in headers:
  985. headers['Host'] = host
  986. if payload and 'Content-Length' not in headers:
  987. headers['Content-Length'] = str(len(payload))
  988. for i in range(self.max_retry):
  989. sock = None
  990. ssl_sock = None
  991. try:
  992. if scheme == 'https':
  993. ssl_sock = self.create_ssl_connection((realhost or host, port), self.max_timeout, validate=validate, cache_key=connection_cache_key)
  994. if ssl_sock:
  995. sock = ssl_sock.sock
  996. del ssl_sock.sock
  997. else:
  998. raise socket.error('timed out', 'create_ssl_connection(%r,%r)' % (realhost or host, port))
  999. else:
  1000. sock = self.create_connection((realhost or host, port), self.max_timeout, cache_key=connection_cache_key)
  1001. if sock:
  1002. if scheme == 'https':
  1003. crlf = 0
  1004. return self._request(ssl_sock or sock, method, path, self.protocol_version, headers, payload, bufsize=bufsize, crlf=crlf, return_sock=return_sock)
  1005. except Exception as e:
  1006. logging.debug('request "%s %s" failed:%s', method, url, e)
  1007. if ssl_sock:
  1008. ssl_sock.close()
  1009. if sock:
  1010. sock.close()
  1011. if i == self.max_retry - 1:
  1012. raise
  1013. else:
  1014. continue
  1015. class Common(object):
  1016. """Global Config Object"""
  1017. ENV_CONFIG_PREFIX = 'GOAGENT_'
  1018. def __init__(self):
  1019. """load config from proxy.ini"""
  1020. ConfigParser.RawConfigParser.OPTCRE = re.compile(r'(?P<option>[^=\s][^=]*)\s*(?P<vi>[=])\s*(?P<value>.*)$')
  1021. self.CONFIG = ConfigParser.ConfigParser()
  1022. # GAEProxy Patch
  1023. self.CONFIG_FILENAME = '/data/data/org.gaeproxy/proxy.ini'
  1024. self.CONFIG.read(self.CONFIG_FILENAME)
  1025. self.LISTEN_IP = self.CONFIG.get('listen', 'ip')
  1026. self.LISTEN_PORT = self.CONFIG.getint('listen', 'port')
  1027. self.LISTEN_VISIBLE = self.CONFIG.getint('listen', 'visible')
  1028. self.LISTEN_DEBUGINFO = self.CONFIG.getint('listen', 'debuginfo')
  1029. self.GAE_APPIDS = re.findall(r'[\w\-\.]+', self.CONFIG.get('gae', 'appid').replace('.appspot.com', ''))
  1030. self.GAE_PASSWORD = self.CONFIG.get('gae', 'password').strip()
  1031. self.GAE_PATH = self.CONFIG.get('gae', 'path')
  1032. self.GAE_MODE = self.CONFIG.get('gae', 'mode')
  1033. self.GAE_PROFILE = self.CONFIG.get('gae', 'profile').strip()
  1034. self.GAE_WINDOW = self.CONFIG.getint('gae', 'window')
  1035. self.GAE_VALIDATE = self.CONFIG.getint('gae', 'validate')
  1036. self.GAE_OBFUSCATE = self.CONFIG.getint('gae', 'obfuscate')
  1037. self.GAE_OPTIONS = self.CONFIG.get('gae', 'options')
  1038. hosts_section, http_section = '%s/hosts' % self.GAE_PROFILE, '%s/http' % self.GAE_PROFILE
  1039. self.HOSTS_MAP = collections.OrderedDict((k, v or k) for k, v in self.CONFIG.items(hosts_section) if '\\' not in k and ':' not in k and not k.startswith('.'))
  1040. self.HOSTS_POSTFIX_MAP = collections.OrderedDict((k, v) for k, v in self.CONFIG.items(hosts_section) if '\\' not in k and ':' not in k and k.startswith('.'))
  1041. self.HOSTS_POSTFIX_ENDSWITH = tuple(self.HOSTS_POSTFIX_MAP)
  1042. self.CONNECT_HOSTS_MAP = collections.OrderedDict((k, v) for k, v in self.CONFIG.items(hosts_section) if ':' in k and not k.startswith('.'))
  1043. self.CONNECT_POSTFIX_MAP = collections.OrderedDict((k, v) for k, v in self.CONFIG.items(hosts_section) if ':' in k and k.startswith('.'))
  1044. self.CONNECT_POSTFIX_ENDSWITH = tuple(self.CONNECT_POSTFIX_MAP)
  1045. self.METHOD_REMATCH_MAP = collections.OrderedDict((re.compile(k).match, v) for k, v in self.CONFIG.items(hosts_section) if '\\' in k)
  1046. self.METHOD_REMATCH_HAS_LOCALFILE = any(x.startswith('file://') for x in self.METHOD_REMATCH_MAP.values())
  1047. self.HTTP_WITHGAE = tuple(self.CONFIG.get(http_section, 'withgae').split('|'))
  1048. self.HTTP_CRLFSITES = tuple(self.CONFIG.get(http_section, 'crlfsites').split('|'))
  1049. self.HTTP_FORCEHTTPS = set(self.CONFIG.get(http_section, 'forcehttps').split('|'))
  1050. self.HTTP_FAKEHTTPS = set(self.CONFIG.get(http_section, 'fakehttps').split('|'))
  1051. self.HTTP_DNS = self.CONFIG.get(http_section, 'dns').split('|') if self.CONFIG.has_o

Large files files are truncated, but you can click here to view the full file