PageRenderTime 39ms CodeModel.GetById 15ms RepoModel.GetById 1ms app.codeStats 0ms

/tests/tinyproxy.py

https://bitbucket.org/mirror/mercurial/
Python | 150 lines | 148 code | 1 blank | 1 comment | 0 complexity | 6b39efe89f86a4df623f8a95c6a2f224 MD5 | raw file
Possible License(s): GPL-2.0
  1. #!/usr/bin/env python
  2. __doc__ = """Tiny HTTP Proxy.
  3. This module implements GET, HEAD, POST, PUT and DELETE methods
  4. on BaseHTTPServer, and behaves as an HTTP proxy. The CONNECT
  5. method is also implemented experimentally, but has not been
  6. tested yet.
  7. Any help will be greatly appreciated. SUZUKI Hisao
  8. """
  9. __version__ = "0.2.1"
  10. import BaseHTTPServer, select, socket, SocketServer, urlparse, os
  11. class ProxyHandler (BaseHTTPServer.BaseHTTPRequestHandler):
  12. __base = BaseHTTPServer.BaseHTTPRequestHandler
  13. __base_handle = __base.handle
  14. server_version = "TinyHTTPProxy/" + __version__
  15. rbufsize = 0 # self.rfile Be unbuffered
  16. def handle(self):
  17. (ip, port) = self.client_address
  18. allowed = getattr(self, 'allowed_clients', None)
  19. if allowed is not None and ip not in allowed:
  20. self.raw_requestline = self.rfile.readline()
  21. if self.parse_request():
  22. self.send_error(403)
  23. else:
  24. self.__base_handle()
  25. def log_request(self, code='-', size='-'):
  26. xheaders = [h for h in self.headers.items() if h[0].startswith('x-')]
  27. self.log_message('"%s" %s %s%s',
  28. self.requestline, str(code), str(size),
  29. ''.join([' %s:%s' % h for h in sorted(xheaders)]))
  30. def _connect_to(self, netloc, soc):
  31. i = netloc.find(':')
  32. if i >= 0:
  33. host_port = netloc[:i], int(netloc[i + 1:])
  34. else:
  35. host_port = netloc, 80
  36. print "\t" "connect to %s:%d" % host_port
  37. try: soc.connect(host_port)
  38. except socket.error, arg:
  39. try: msg = arg[1]
  40. except (IndexError, TypeError): msg = arg
  41. self.send_error(404, msg)
  42. return 0
  43. return 1
  44. def do_CONNECT(self):
  45. soc = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
  46. try:
  47. if self._connect_to(self.path, soc):
  48. self.log_request(200)
  49. self.wfile.write(self.protocol_version +
  50. " 200 Connection established\r\n")
  51. self.wfile.write("Proxy-agent: %s\r\n" % self.version_string())
  52. self.wfile.write("\r\n")
  53. self._read_write(soc, 300)
  54. finally:
  55. print "\t" "bye"
  56. soc.close()
  57. self.connection.close()
  58. def do_GET(self):
  59. (scm, netloc, path, params, query, fragment) = urlparse.urlparse(
  60. self.path, 'http')
  61. if scm != 'http' or fragment or not netloc:
  62. self.send_error(400, "bad url %s" % self.path)
  63. return
  64. soc = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
  65. try:
  66. if self._connect_to(netloc, soc):
  67. self.log_request()
  68. soc.send("%s %s %s\r\n" % (
  69. self.command,
  70. urlparse.urlunparse(('', '', path, params, query, '')),
  71. self.request_version))
  72. self.headers['Connection'] = 'close'
  73. del self.headers['Proxy-Connection']
  74. for key_val in self.headers.items():
  75. soc.send("%s: %s\r\n" % key_val)
  76. soc.send("\r\n")
  77. self._read_write(soc)
  78. finally:
  79. print "\t" "bye"
  80. soc.close()
  81. self.connection.close()
  82. def _read_write(self, soc, max_idling=20):
  83. iw = [self.connection, soc]
  84. ow = []
  85. count = 0
  86. while True:
  87. count += 1
  88. (ins, _, exs) = select.select(iw, ow, iw, 3)
  89. if exs:
  90. break
  91. if ins:
  92. for i in ins:
  93. if i is soc:
  94. out = self.connection
  95. else:
  96. out = soc
  97. try:
  98. data = i.recv(8192)
  99. except socket.error:
  100. break
  101. if data:
  102. out.send(data)
  103. count = 0
  104. else:
  105. print "\t" "idle", count
  106. if count == max_idling:
  107. break
  108. do_HEAD = do_GET
  109. do_POST = do_GET
  110. do_PUT = do_GET
  111. do_DELETE = do_GET
  112. class ThreadingHTTPServer (SocketServer.ThreadingMixIn,
  113. BaseHTTPServer.HTTPServer):
  114. def __init__(self, *args, **kwargs):
  115. BaseHTTPServer.HTTPServer.__init__(self, *args, **kwargs)
  116. a = open("proxy.pid", "w")
  117. a.write(str(os.getpid()) + "\n")
  118. a.close()
  119. if __name__ == '__main__':
  120. from sys import argv
  121. if argv[1:] and argv[1] in ('-h', '--help'):
  122. print argv[0], "[port [allowed_client_name ...]]"
  123. else:
  124. if argv[2:]:
  125. allowed = []
  126. for name in argv[2:]:
  127. client = socket.gethostbyname(name)
  128. allowed.append(client)
  129. print "Accept: %s (%s)" % (client, name)
  130. ProxyHandler.allowed_clients = allowed
  131. del argv[2:]
  132. else:
  133. print "Any clients will be served..."
  134. BaseHTTPServer.test(ProxyHandler, ThreadingHTTPServer)