Advertisement
cuentas-vps

proxy.py

Jan 22nd, 2018
1,943
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1.  #!/usr/bin/env python
  2.  
  3. import sys
  4. import httplib
  5. from SocketServer import ThreadingMixIn
  6. from BaseHTTPServer import HTTPServer, BaseHTTPRequestHandler
  7. from threading import Lock, Timer
  8. from cStringIO import StringIO
  9. from urlparse import urlsplit
  10. import socket
  11. import select
  12. import gzip
  13. import zlib
  14. import re
  15. import traceback
  16.  
  17.  
  18. class ThreadingHTTPServer(ThreadingMixIn, HTTPServer):
  19.  
  20.     address_family = socket.AF_INET
  21.  
  22.     def handle_error(self, request, client_address):
  23.  
  24.         print >>sys.stderr, '-'*40
  25.         print >>sys.stderr, 'Exception happened during processing of request from', client_address
  26.         traceback.print_exc()
  27.         print >>sys.stderr, '-'*40
  28.  
  29.  
  30. class ThreadingHTTPServer6(ThreadingHTTPServer):
  31.  
  32.     address_family = socket.AF_INET6
  33.  
  34.  
  35. class SimpleHTTPProxyHandler(BaseHTTPRequestHandler):
  36.     global_lock = Lock()
  37.     conn_table = {}
  38.     timeout = 20
  39.     upstream_timeout = 300
  40.     proxy_via = None
  41.  
  42.     def log_error(self, format, *args):
  43.         if format == "Request timed out: %r":
  44.             return
  45.         self.log_message(format, *args)
  46.  
  47.     def do_CONNECT(self):
  48.  
  49.  
  50.         req = self
  51.         reqbody = None
  52.         req.path = "http://%s/" % req.path.replace(':443', '')
  53.  
  54. replaced_reqbody = self.request_handler(req, reqbody)
  55.         if replaced_reqbody is True:
  56.             return
  57.  
  58.         u = urlsplit(req.path)
  59.         address = (u.hostname, u.port or 443)
  60.         try:
  61.             conn = socket.create_connection(address)
  62.         except socket.error:
  63.             return
  64.         self.send_response(200, '<font color="red">PROXY SOCKS</font> <font color="blue">#Byprez</font>')
  65.         self.send_header('Connection', 'close')
  66.         self.end_headers()
  67.  
  68.         conns = [self.connection, conn]
  69.         keep_connection = True
  70.         while keep_connection:
  71.             keep_connection = False
  72.             rlist, wlist, xlist = select.select(conns, [], conns, self.timeout)
  73.             if xlist:
  74.                 break
  75.             for r in rlist:
  76.                 other = conns[1] if r is conns[0] else conns[0]
  77.                 data = r.recv(8192)
  78.                 if data:
  79.                     other.sendall(data)
  80.                     keep_connection = True
  81.         conn.close()
  82.  
  83.     def do_HEAD(self):
  84.         self.do_SPAM()
  85.  
  86.     def do_GET(self):
  87.         self.do_SPAM()
  88.  
  89.     def do_POST(self):
  90.         self.do_SPAM()
  91.  
  92.     def do_SPAM(self):
  93.         req = self
  94.         content_length = int(req.headers.get('Content-Length', 0))
  95.         if content_length > 0:
  96.             reqbody = self.rfile.read(content_length)
  97.         else:
  98.             reqbody = None
  99.  
  100.         replaced_reqbody = self.request_handler(req, reqbody)
  101.         if replaced_reqbody is True:
  102.             return
  103.         elif replaced_reqbody is not None:
  104.             reqbody = replaced_reqbody
  105.             if 'Content-Length' in req.headers:
  106.                 req.headers['Content-Length'] = str(len(reqbody))
  107.  
  108.  
  109.         self.remove_hop_by_hop_headers(req.headers)
  110.         if self.upstream_timeout:
  111.             req.headers['Connection'] = 'Keep-Alive'
  112.  else:
  113.             req.headers['Connection'] = 'close'
  114.         if self.proxy_via:
  115.             self.modify_via_header(req.headers)
  116.  
  117.         try:
  118.             res, resdata = self.request_to_upstream_server(req, reqbody)
  119.         except socket.error:
  120.             return
  121.  
  122.         content_encoding = res.headers.get('Content-Encoding', 'identity')
  123.         resbody = self.decode_content_body(resdata, content_encoding)
  124.  
  125.         replaced_resbody = self.response_handler(req, reqbody, res, resbody)
  126.         if replaced_resbody is True:
  127.             return
  128.         elif replaced_resbody is not None:
  129.             resdata = self.encode_content_body(replaced_resbody, content_encoding)
  130.             if 'Content-Length' in res.headers:
  131.                 res.headers['Content-Length'] = str(len(resdata))
  132.             resbody = replaced_resbody
  133.  
  134.         self.remove_hop_by_hop_headers(res.headers)
  135.         if self.timeout:
  136.             res.headers['Connection'] = 'Keep-Alive'
  137.         else:
  138.             res.headers['Connection'] = 'close'
  139.         if self.proxy_via:
  140.   self.modify_via_header(res.headers)
  141.  
  142.         self.send_response(res.status, res.reason)
  143.         for k, v in res.headers.items():
  144.             if k == 'set-cookie':
  145.  
  146.                 for value in self.split_set_cookie_header(v):
  147.                     self.send_header(k, value)
  148.             else:
  149.                 self.send_header(k, v)
  150.         self.end_headers()
  151.  
  152.         if self.command != 'HEAD':
  153.             self.wfile.write(resdata)
  154.             with self.global_lock:
  155.                 self.save_handler(req, reqbody, res, resbody)
  156.  
  157.     def request_to_upstream_server(self, req, reqbody):
  158.         u = urlsplit(req.path)
  159.         origin = (u.scheme, u.netloc)
  160.  
  161.  
  162.         req.headers['Host'] = u.netloc
  163.         selector = "%s?%s" % (u.path, u.query) if u.query else u.path
  164.  
  165.         while True:
  166.             with self.lock_origin(origin):
  167.                 conn = self.open_origin(origin)
  168.  try:
  169.                     conn.request(req.command, selector, reqbody, headers=dict(req.headers))
  170.                 except socket.error:
  171.  
  172.                     self.close_origin(origin)
  173.                     raise
  174.                 try:
  175.                     res = conn.getresponse(buffering=True)
  176.                 except httplib.BadStatusLine as e:
  177.                     if e.line == "''":
  178.  
  179.                         self.close_origin(origin)
  180.                         continue
  181.                     else:
  182.                         raise
  183.                 resdata = res.read()
  184.                 res.headers = res.msg
  185.                 if not self.upstream_timeout or 'close' in res.headers.get('Connection', ''):
  186.                     self.close_origin(origin)
  187.                 else:
  188.                     self.reset_timer(origin)
  189.             return res, resdata
  190.  
  191.     def lock_origin(self, origin):
  192.         d = self.conn_table.setdefault(origin, {})
  193.         if not 'lock' in d:
  194.             d['lock'] = Lock()
  195.         return d['lock']
  196.  
  197.  def open_origin(self, origin):
  198.         conn = self.conn_table[origin].get('connection')
  199.         if not conn:
  200.             scheme, netloc = origin
  201.             if scheme == 'https':
  202.                 conn = httplib.HTTPSConnection(netloc)
  203.             else:
  204.                 conn = httplib.HTTPConnection(netloc)
  205.             self.reset_timer(origin)
  206.             self.conn_table[origin]['connection'] = conn
  207.         return conn
  208.  
  209.     def reset_timer(self, origin):
  210.         timer = self.conn_table[origin].get('timer')
  211.         if timer:
  212.             timer.cancel()
  213.         if self.upstream_timeout:
  214.             timer = Timer(self.upstream_timeout, self.close_origin, args=[origin])
  215.             timer.daemon = True
  216.             timer.start()
  217.         else:
  218.             timer = None
  219.         self.conn_table[origin]['timer'] = timer
  220.  
  221.     def close_origin(self, origin):
  222.         timer = self.conn_table[origin]['timer']
  223.         if timer:
  224.  timer.cancel()
  225.         conn = self.conn_table[origin]['connection']
  226.         conn.close()
  227.         del self.conn_table[origin]['connection']
  228.  
  229.     def remove_hop_by_hop_headers(self, headers):
  230.         hop_by_hop_headers = ['Connection', 'Keep-Alive', 'Proxy-Authenticate', 'Proxy-Authorization', 'TE', 'Trailers', 'Trailer', 'Transfer-Encoding', 'Up$
  231.        connection = headers.get('Connection')
  232.        if connection:
  233.            keys = re.split(r',\s*', connection)
  234.            hop_by_hop_headers.extend(keys)
  235.  
  236.        for k in hop_by_hop_headers:
  237.            if k in headers:
  238.                del headers[k]
  239.  
  240.    def modify_via_header(self, headers):
  241.        via_string = "%s %s" % (self.protocol_version, self.proxy_via)
  242.        via_string = re.sub(r'^HTTP/', '', via_string)
  243.  
  244.        original = headers.get('Via')
  245.        if original:
  246.            headers['Via'] = original + ', ' + via_string
  247.        else:
  248.            headers['Via'] = via_string
  249.  
  250.    def decode_content_body(self, data, content_encoding):
  251.        if content_encoding in ('gzip', 'x-gzip'):
  252. io = StringIO(data)
  253.            with gzip.GzipFile(fileobj=io) as f:
  254.                body = f.read()
  255.        elif content_encoding == 'deflate':
  256.            body = zlib.decompress(data)
  257.        elif content_encoding == 'identity':
  258.            body = data
  259.        else:
  260.            raise Exception("Unknown Content-Encoding: %s" % content_encoding)
  261.        return body
  262.  
  263.    def encode_content_body(self, body, content_encoding):
  264.        if content_encoding in ('gzip', 'x-gzip'):
  265.            io = StringIO()
  266.            with gzip.GzipFile(fileobj=io, mode='wb') as f:
  267.                f.write(body)
  268.            data = io.getvalue()
  269.        elif content_encoding == 'deflate':
  270.            data = zlib.compress(body)
  271.        elif content_encoding == 'identity':
  272.            data = body
  273.        else:
  274.            raise Exception("Unknown Content-Encoding: %s" % content_encoding)
  275.        return data
  276.  
  277.    def split_set_cookie_header(self, value):
  278.        re_cookies = r'([^=]+=[^,;]+(?:;\s*Expires=[^,]+,[^,;]+|;[^,;]+)*)(?:,\s*)?'
  279.        return re.findall(re_cookies, value, flags=re.IGNORECASE)
  280. def request_handler(self, req, reqbody):
  281.  
  282.        pass
  283.  
  284.    def response_handler(self, req, reqbody, res, resbody):
  285.  
  286.        pass
  287.  
  288.    def save_handler(self, req, reqbody, res, resbody):
  289.  
  290.        pass
  291.  
  292.  
  293.  
  294.  
  295. def test(HandlerClass=SimpleHTTPProxyHandler, ServerClass=ThreadingHTTPServer, protocol="HTTP/1.1"):
  296.    if sys.argv[1:]:
  297.        port = int(sys.argv[1])
  298.    else:
  299.        port = 9202
  300.    server_address = ('', port)
  301.  
  302.    HandlerClass.protocol_version = protocol
  303.    httpd = ServerClass(server_address, HandlerClass)
  304.  
  305.    sa = httpd.socket.getsockname()
  306.    print "Serving HTTP on", sa[0], "port", sa[1], "..."
  307. httpd.serve_forever()
  308.  
  309.  
  310. if __name__ == '__main__':
  311.    test()
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement