"""
winky_proxy.py inspired by SUZUKI Hisao
changed to use urllib2 instead of a raw socket
copyrighted by winky released under GPL or LGPL
"""

import BaseHTTPServer,SocketServer
import urllib,urllib2
import urlparse
import cgi
import re
encrypt_start_tag = "<winky>"
encrypt_end_tag = "</winky>"
encrypt_start_tag_q = cgi.escape(encrypt_start_tag)
encrypt_end_tag_q = cgi.escape(encrypt_end_tag)

def encrypt(buffer):
	result = []
	for ch in buffer :
		enc = "%2X" % (ord(ch))
		result.append(enc.replace(" ","0"))
	return "".join(result)
		
def decrypt(buffer):
	result = []
	for i in range(0,len(buffer),2):
		enc = buffer[i:i+2]
		ch = chr(int(enc,16))
		result.append(ch)
	return "".join(result)

re_encrypt = re.compile(encrypt_start_tag+"(.*?)"+encrypt_end_tag,re.DOTALL)
def encode_buffer(buffer):
	enc_buffer = ""
	end_pos = 0
	for m in re_encrypt.finditer(buffer) :
		enc_buffer += buffer[end_pos:m.start(1)]
		enc_buffer += encrypt(buffer[m.start(1):m.end(1)])
		end_pos = m.end(1)
	return enc_buffer + buffer[end_pos:]

reg_decrypt = "(%s|%s)(.*?)(%s|%s)"
re_decrypt = re.compile(reg_decrypt % (
					encrypt_start_tag,
					encrypt_start_tag_q,
					encrypt_end_tag,
					encrypt_end_tag_q,
					),re.DOTALL)
def decode_buffer(buffer):
	dec_buffer = ""
	end_pos = 0
	for m in re_decrypt.finditer(buffer):
		dec_buffer += buffer[end_pos:m.start(2)]
		dec_buffer += decrypt(buffer[m.start(2):m.end(2)])
		end_pos = m.end(2)
	return dec_buffer + buffer[end_pos:]

class ProxyHandler (BaseHTTPServer.BaseHTTPRequestHandler):
	__base = BaseHTTPServer.BaseHTTPRequestHandler
	__base_handle = __base.handle
	
	def handle(self):
		(ip, port) =  self.client_address
		if hasattr(self, 'allowed_clients') and ip not in self.allowed_clients:
			self.raw_requestline = self.rfile.readline()
			if self.parse_request(): self.send_error(403)
		else:
			self.__base_handle()
			
	def _GET_POST(self,pageUrl,data=None):
		if data :
			request = urllib2.Request(url=pageUrl,data=data)
		else :
			request = urllib2.Request(url=pageUrl)
		request.add_header('User-agent', 'Mozilla/5.0')
		
		try :
			page = urllib2.urlopen(request)
		except urllib2.HTTPError, Error :
			self.send_error(400, "http error")
			return
		except urllib2.URLError, Error :
			self.send_error(400, "address not found")
			return
			
		page_body = page.read()
		page_body = decode_buffer(page_body)
		page.headers.dict['Content-Length'] = str(len(page_body))
			
		self.send_response(page.code,page.msg)
		try :
			del page.headers.dict['transfer-encoding']
		except KeyError :
			pass
		for key,value in page.headers.dict.items() :
			self.send_header(key,value)
		self.end_headers()
		self.wfile.write(page_body)
			
	def do_GET(self):
		(scm, netloc, path, query, fragment) = urlparse.urlsplit(self.path, 'http')
		if scm != 'http' or fragment or not netloc:
			self.send_error(400, "bad url %s" % self.path)
			return
		pageUrl = urlparse.urlunsplit((scm, netloc, path, query, fragment))
		self._GET_POST(pageUrl)
	
	def do_POST(self):
		query_str = self.rfile.read(int(self.headers['Content-Length']))
		query_dict = cgi.parse_qs(query_str)
	
		(scm, netloc, path, query, fragment) = urlparse.urlsplit(self.path, 'http')
		if scm != 'http' or fragment or not netloc:
			self.send_error(400, "bad url %s" % self.path)
			return
		
		pageUrl = urlparse.urlunsplit((scm, netloc, path, query, fragment))
		
		if query_dict.has_key("content") :
			query_dict["content"] = [encode_buffer(query_dict["content"][0])]
		
		query_post = urllib.urlencode(query_dict,True)
		self._GET_POST(pageUrl,query_post)
		
	do_HEAD = do_GET
	do_PUT  = do_GET
	do_DELETE=do_GET
			
	
	
class ThreadingHTTPServer(SocketServer.ThreadingMixIn, BaseHTTPServer.HTTPServer): 
	pass

def main() :
	from sys import argv
	if argv[1:] and argv[1] in ('-h', '--help'):
		print argv[0], "[port [allowed_client_name ...]]"
	else:
		if argv[2:]:
			allowed = []
			for name in argv[2:]:
				client = socket.gethostbyname(name)
				allowed.append(client)
				print "Accept: %s (%s)" % (client, name)
			ProxyHandler.allowed_clients = allowed
			del argv[2:]
		else:
			print "Any clients will be served..."
		proxy = ThreadingHTTPServer(("127.0.0.1",8000), ProxyHandler)
		proxy.serve_forever()
		
if __name__ == '__main__':
	import sys
	try:
		main()
	except KeyboardInterrupt :
		sys.exit(0)
	

