Python代码实现http/https代理服务器的脚本
一个几百行代码做出http/https代理服务器的脚本,启动即可做httphttps透明代理使用
pythonproxy.py8992
使用非阻塞io模式,性能还可以。
可以和浏览器一样保持长连接,代码有点乱,不管那么多了能跑就行
几百行代码做出http/https代理服务器代码片段
*1.* [代码][Python]代码
#!/usr/bin/python
#-*-coding:utf-8-*-
importsocket,logging
importselect,errno
importos
importsys
importtraceback
importgzip
fromStringIOimportStringIO
importQueue
importthreading
importtime
importthread
importcgi
fromcgiimportparse_qs
importjson
importimp
fromos.pathimportjoin,getsize
importre
importssl
##################userconfig##################
logger=logging.getLogger("network-server")
#############################################
defgetTraceStackMsg():
tb=sys.exc_info()[2]
msg=''
foriintraceback.format_tb(tb):
msg+=i
returnmsg
defInitLog():
logger.setLevel(logging.DEBUG)
fh=logging.FileHandler("network-server.log")
fh.setLevel(logging.DEBUG)
ch=logging.StreamHandler()
ch.setLevel(logging.ERROR)
formatter=logging.Formatter("%(asctime)s-%(name)s-%(levelname)s-%(message)s")
ch.setFormatter(formatter)
fh.setFormatter(formatter)
logger.addHandler(fh)
logger.addHandler(ch)
defclearfdpro(epoll_fd,params,fd):
try:
fd_check=int(fd)
exceptException,e:
print"fderror"
sys.exit(1)
try:
#print"pid:%s,closefd:%s"%(os.getpid(),fd)
epoll_fd.unregister(fd)
exceptException,e:
#printstr(e)+getTraceStackMsg()
pass
try:
param=params[fd]
try:
addr=param["addr"]
if"next"inparam:
print"closesock,%s:%s"%(addr[0],addr[1])
exceptException,e:
pass
param["connections"].shutdown(socket.SHUT_RDWR)
param["connections"].close()
f=param.get("f",None)
iff!=None:
f.close()
rc=param.get("rc",None)
ifrc!=None:
rc.close()
if"read_cache_name"inparam:
os.remove(param["read_cache_name"])
exceptException,e:
#printstr(e)+getTraceStackMsg()
pass
try:
delparams[fd]
#logger.error(getTraceStackMsg())
#logger.error("clearfd:%s"%fd)
exceptException,e:
#printstr(e)+getTraceStackMsg()
pass
defclearfd(epoll_fd,params,fd):
try:
param=params[fd]
if"nextfd"inparam:
nextfd=param["nextfd"]
next_param=params[nextfd]
delparam["nextfd"]
delnext_param["nextfd"]
ifnot"next"inparam:#masterfd
clearfdpro(epoll_fd,params,nextfd)
else:#nextfd
ifnot"writedata"innext_paramorlen(next_param["writedata"])==0:
clearfdpro(epoll_fd,params,nextfd)
else:
next_param["sendandclose"]="true"
clearfdpro(epoll_fd,params,fd)
exceptException,e:
#printstr(e)+getTraceStackMsg()
pass
defFindHostPort(datas):
host_s=-1
host_e=-1
host_str=None
host=""
port=""
ifnotdatas.startswith("CONNECT"):
host_s=datas.find("Host:")
ifhost_s<0:
host_s=datas.find("host:")
ifhost_s>0:
host_e=datas.find("\r\n",host_s)
ifhost_s>0andhost_e>0:
host_str=datas[host_s+5:host_e].strip()
add_list=host_str.split(":")
iflen(add_list)==2:
host=add_list[0]
port=add_list[1]
else:
host=add_list[0]
port=80
first_seg=datas.find("\r\n")
first_line=datas[0:first_seg]
first_line=first_line.replace("http://%s"%host_str,"")
datas=first_line+datas[first_seg:]
else:
first_seg=datas.find("\r\n")
head_e=datas.find("\r\n\r\n")
iffirst_seg>0andhead_e>0:
first_line=datas[0:first_seg]
36a0
com,host_str,http_version=re.split('\s+',first_line)
add_list=host_str.split(":")
iflen(add_list)==2:
host=add_list[0]
port=add_list[1]
else:
host=add_list[0]
port=443
host_s=1
host_e=1
returnhost_str,host_s,host_e,host,port,datas
defconnect_pro(params,param,epoll_fd,datas,fd,cur_time,host,port):
try:
nextfd=socket.socket(socket.AF_INET,socket.SOCK_STREAM,0)
nextfd.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR,1)
nextfd.settimeout(5)
try:
nextfd.connect((host,int(port)))
exceptException,e:
print"########%s,%sconnectfail"%(host,port)
nextfd.setblocking(0)
next_fileno=nextfd.fileno()
print"pid:%s,connect%s:%sfd:%s"%(os.getpid(),host,port,next_fileno)
ifnext_filenoinparams:
print"filenoexist"
sys.exit(1)
ifnotdatas.startswith("CONNECT"):
next_param={"addr":[host,port],"writelen":0,"connections":nextfd,"time":cur_time,"nextfd":fd}
param["nextfd"]=next_fileno
next_param["writedata"]=datas
next_param["writelen"]=0
next_param["next"]="true"
param["read_len"]=0
param["readdata"]=""
params[next_fileno]=next_param
epoll_fd.register(next_fileno,select.EPOLLIN|select.EPOLLOUT|select.EPOLLERR|select.EPOLLHUP)
epoll_fd.modify(fd,select.EPOLLIN|select.EPOLLERR|select.EPOLLHUP)
else:
next_param={"addr":[host,port],"writelen":0,"connections":nextfd,"time":cur_time,"nextfd":fd}
param["nextfd"]=next_fileno
next_param["next"]="true"
params[next_fileno]=next_param
epoll_fd.register(next_fileno,select.EPOLLIN|select.EPOLLERR|select.EPOLLHUP)
param["read_len"]=0
param["readdata"]=""
param["writedata"]="HTTP/1.1200ConnectionEstablished\r\nConnection:close\r\n\r\n"
param["writelen"]=0
param["reuse"]="true"
epoll_fd.modify(fd,select.EPOLLIN|select.EPOLLOUT|select.EPOLLERR|select.EPOLLHUP)
exceptsocket.error,msg:
clearfd(epoll_fd,params,fd)
defprocess_datas(process_status,params,param,epoll_fd,datas,read_len,fd,cur_time):
ifprocess_status=="close":
clearfd(epoll_fd,params,fd)
else:
need_connect=False
host_str=None
host_s=-1
host_e=-1
if"reuse"inparamand"next"notinparam:
ifnotdatas.startswith("CONNECT")and\
notdatas.startswith("GET")and\
notdatas.startswith("POST")and\
notdatas.startswith("PUT"):
delparam["reuse"]
else:
host_str,host_s,host_e,host,port,datas=FindHostPort(datas)
host_s=int(host_s)
host_e=int(host_e)
next_fileno=param["nextfd"]
next_param=params[next_fileno]
addr=next_param["addr"]
ifhost_s>0andhost_e>0:
ifhost!=addr[0]orstr(port)!=str(addr[1]):
print"%s,%sneq%s,%s"%(host,port,addr[0],addr[1])
need_connect=True
delparam["nextfd"]
delnext_param["nextfd"]
clearfd(epoll_fd,params,next_fileno)
delparam["reuse"]
else:
param["read_len"]=read_len
param["readdata"]=datas
returnNone
ifneed_connectornot"nextfd"inparam:
ifhost_str==Noneornothost_s>0ornothost_e>0:
host_str,host_s,host_e,host,port,datas=FindHostPort(datas)
host_s=int(host_s)
host_e=int(host_e)
ifhost_s>0andhost_e>0:
ifnotdatas.startswith("CONNECT"):
epoll_fd.modify(fd,select.EPOLLERR|select.EPOLLHUP)#简单处理,http连接时把读去掉,避免内存攻击
thread.start_new_thread(connect_pro,(params,param,epoll_fd,datas,fd,cur_time,host,port))
else:
param["read_len"]=read_len
param["readdata"]=datas
else:
next_fileno=param["nextfd"]
next_param=params[next_fileno]
if"next"inparam:
next_param["reuse"]="true"
write_data=next_param.get("writedata","")
write_data+=datas
next_param["writedata"]=write_data
param["read_len"]=0
param["readdata"]=""
epoll_fd.modify(next_fileno,select.EPOLLIN|select.EPOLLOUT|select.EPOLLERR|select.EPOLLHUP)
ifprocess_status=="close_after_process":
print"closeafterprocess"
clearfd(epoll_fd,params,fd)
defrun_main(listen_fd):
try:
epoll_fd=select.epoll()
epoll_fd.register(listen_fd.fileno(),select.EPOLLIN|select.EPOLLERR|select.EPOLLHUP)
print"listen_fd:%s"%listen_fd.fileno()
exceptselect.error,msg:
logger.error(msg)
params={}
last_min_time=-1
whileTrue:
epoll_list=epoll_fd.poll()
cur_time=time.time()
forfd,eventsinepoll_list:
iffd==listen_fd.fileno():
whileTrue:
try:
conn,addr=listen_fd.accept()
conn.setblocking(0)
epoll_fd.register(conn.fileno(),select.EPOLLIN|select.EPOLLERR|select.EPOLLHUP)
conn.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR,1)
#conn.setsockopt(socket.IPPROTO_TCP,socket.TCP_NODELAY,True)
params[conn.fileno()]={"addr":addr,"writelen":0,"connections":conn,"time":cur_time}
exceptsocket.error,msg:
break
elifselect.EPOLLIN&events:
param=params.get(fd,None)
ifparam==None:
continue
param["time"]=cur_time
datas=param.get("readdata","")
cur_sock=params[fd]["connections"]
read_len=param.get("read_len",0)
process_status="close"
whileTrue:
try:
data=cur_sock.recv(102400)
ifnotdata:
ifdatas=="":
break
else:
raiseException("closeafterprocess")
else:
datas+=data
read_len+=len(data)
exceptsocket.error,msg:
ifmsg.errno==errno.EAGAIN:
process_status="process"
break
else:
break
exceptException,e:
process_status="close_after_process"
break
process_datas(process_status,params,param,epoll_fd,datas,read_len,fd,cur_time)
elifselect.EPOLLHUP&eventsorselect.EPOLLERR&events:
clearfd(epoll_fd,params,fd)
logger.error("sock:%serror"%fd)
elifselect.EPOLLOUT&events:
param=params.get(fd,None)
ifparam==None:
continue
param["time"]=cur_time
sendLen=param.get("writelen",0)
writedata=param.get("writedata","")
total_write_len=len(writedata)
cur_sock=param["connections"]
f=param.get("f",None)
totalsenlen=param.get("totalsenlen",None)
ifwritedata=="":
clearfd(epoll_fd,params,fd)
continue
whileTrue:
try:
sendLen+=cur_sock.send(writedata[sendLen:])
ifsendLen==total_write_len:
iff!=Noneandtotalsenlen!=None:
readmorelen=102400
ifreadmorelen>totalsenlen:
readmorelen=totalsenlen
morefiledata=""
ifreadmorelen>0:
morefiledata=f.read(readmorelen)
ifmorefiledata!="":
writedata=morefiledata
sendLen=0
total_write_len=len(writedata)
totalsenlen-=total_write_len
param["writedata"]=writedata
param["totalsenlen"]=totalsenlen
continue
else:
f.close()
delparam["f"]
delparam["totalsenlen"]
ifnot"sendandclose"inparam:
param["writedata"]=""
param["writelen"]=0
epoll_fd.modify(fd,select.EPOLLIN|select.EPOLLERR|select.EPOLLHUP)
else:
clearfd(epoll_fd,params,fd)
break
exceptsocket.error,msg:
ifmsg.errno==errno.EAGAIN:
param["writelen"]=sendLen
break
clearfd(epoll_fd,params,fd)
break
else:
continue
#checktimeout
ifcur_time-last_min_time>20:
last_min_time=cur_time
objs=params.items()
for(key_fd,value)inobjs:
fd_time=value.get("time",0)
del_time=cur_time-fd_time
ifdel_time>20:
clearfd(epoll_fd,params,key_fd)
eliffd_time
总结
以上所述是小编给大家介绍的Python代码实现http/https代理服务器,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对毛票票网站的支持!
如果你觉得本文对你有帮助,欢迎转载,烦请注明出处,谢谢!