Python开发Http代理服务器 - socketref,呆在autonavi.com - C++博客

Python开发Http代理服务器 - socketref,呆在autonavi.com - C++博客

之前开发酒店广告投放系统编写的Http代理服务程序,功能实现广告插播进Html DOM结构内。一般都是DIV被插入,当然包括script都是可以从数据库中动态获得。
简单修改之后当做Http代理服务器程序,在浏览器中设置Http转发程序的Ip即可,只要代理程序的机器能上网,客户机便能上网(其中涉及Page gzip的工作有点麻烦)

  1  #  -*- coding:utf-8 -*-
  2  #  http代理服务器
  3  #  1.ip限制,mac限制
  4  #
  5  #  socketref@hotmail.com 
  6  #  www.sw2us.com
  7 
  8  " exec "   " python "   " -O "   " $0 "   " $@ "
  9 
 10  __doc__   =   """ sw2us HTTP Proxy.
 11 
 12  """
 13 
 14  __version__   =   " 0.2.1 "
 15 
 16  import  BaseHTTPServer, select, socket, SocketServer, urlparse
 17  import  httplib,traceback,re
 18  import  os,sys,re,mimetools,zlib,StringIO,gzip,time,StringIO
 19 
 20 
 21  class  ConfigProperty:
 22       def   __init__ (self,owner):
 23          self.key = ''
 24          self.value = ''
 25      
 26       def  create(self,text):
 27           # text -  key=value
 28           # @return: boolean
 29          pos  =  text.find( ' # ' )
 30           if (pos  !=- 1 ):
 31              text  =  text[:pos]
 32          pair  =  text.split( ' = ' )
 33           if  len(pair)  != 2 :
 34               # print "Property Line Invalid:%s"%(text)
 35               return  False
 36          k  =  pair[0].strip()
 37          v  =  pair[ 1 ].strip()
 38          self.key  =  k
 39          self.value  =  v
 40 
 41           return  True
 42      
 43       def  toString(self):
 44          s  = ''
 45           try :            
 46              s  =   " %s=%s " % (self.key,self.value)            
 47           except :
 48               return   ''
 49           return  s
 50      
 51       def  toInt(self):
 52          r = 0
 53           try :
 54              r  =  int(self.value)
 55           except :
 56              r  = 0
 57           return  r
 58      
 59       def  toFloat(self):
 60          r = 0.0
 61           try :
 62              r  =  float(self.value)
 63           except :
 64              r = 0.0
 65           return  r
 66      
 67      
 68  # @def SimpleConfig
 69  #  简单配置信息文件,基本格式 : key=value
 70  class  SimpleConfig:
 71       def   __init__ (self):
 72          self._file = ''
 73          self._props = []
 74          self._strip  =  True
 75          
 76       def  open(self,file,strip = True):
 77           # 打开配置文件
 78           # @param strip - 是否裁剪不可见首尾两端的字符
 79           try :
 80              self._strip  =  strip 
 81              self._props = []
 82              fh  =  open(file, ' r ' )
 83              lines  =  fh.readlines()            
 84               for  text  in  lines:                
 85                  prop  =  ConfigProperty(self)
 86                   if  prop.create(text)  ==  False:                    
 87                      prop  =  None
 88                   else :                    
 89                      self._props.append(prop)                    
 90              fh.close()
 91           except :            
 92               return  False
 93           return  True
 94 
 95       def  toString(self):
 96          s = ''
 97           for  p  in  self._props:
 98              s  =  s  +  p.toString()  + " \n "
 99           return  s
100      
101       def  saveAs(self,file):
102           # 保存配置信息到文件
103           try :
104              fh  =  open(file, ' w ' )
105              fh.write(toString())
106              fh.close()
107           except :
108               print   " write File Failed! "
109               return  False
110           return  True
111      
112       def  getProperty(self,name):
113           # 取属性值
114          prop = None
115           try :
116               for  p  in  self._props:
117                   if  p.key  ==  name:
118                      prop  =  p
119                       break
120           except :
121               pass
122          
123           return  prop
124      
125       def  getPropertyValue(self,key,default = '' ):
126          prop  =  self.getProperty(key)
127           if   not  prop:
128               return  default
129           return  prop.value
130      
131       def  getPropertyValueAsInt(self,name,default = 0):
132          prop  =  self.getPropertyValue(name)
133          
134           if   not  prop:
135               return  default
136          r = default
137           try :
138              r  =  int(prop)
139           except : pass
140           return  r
141      
142       def  getPropertyValueAsFloat(self,name,default = 0.0 ):
143          prop  =  self.getPropertyValue(name)
144           if   not  prop:
145               return  default
146          r  =  default
147           try :
148              r  =  float(r)
149           except : pass
150           return  r
151      
152 
153  # ===========================================#
154 
155      
156  # ===========================================#
157 
158  def  getMacList():
159      maclist = []
160      f  =  os.popen( ' arp -a ' , ' r ' )
161       while  True:
162          line   =  f.readline()
163           if   not  line:
164               break
165          line  =  line.strip()
166          rst  =  re.match( ' ^(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})\s+([0-9a-fA-F]{1,2}\-[0-9a-fA-F]{1,2}\-[0-9a-fA-F]{1,2}\-[0-9a-fA-F]{1,2}\-[0-9a-fA-F]{1,2}\-[0-9a-fA-F]{1,2}).* ' ,line)
167           # rst = re.match('^(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})',line)
168           if  rst:
169               # print rst.groups()
170              maclist.append(rst.groups())
171       # print maclist
172       return  maclist
173 
174 
175          
176  # #########################################
177  confile  =  SimpleConfig()
178  confile.open( ' proxy.conf ' )
179  dbconn  =  None
180 
181  # #########################################
182  # 初始化系统配置
183  def  initConfiguration():
184      r  =  True
185      
186       return  r
187 
188  # #########################################
189 
190  class  ProxyHandler (BaseHTTPServer.BaseHTTPRequestHandler):
191       __base   =  BaseHTTPServer.BaseHTTPRequestHandler
192       __base_handle   =   __base .handle
193      server_version  =   " TinyHTTPProxy/ "   +   __version__
194      rbufsize  =  0                         #  self.rfile Be unbuffered
195 
196 
197  # ######################################################33
198 
199       # handle()是在单独线程中执行
200       def  handle(self):  #  调用入口,线程刚进入,携带socket进入
201           print   ' client incoming '
202           # self.__base_handle()
203           # return 
204          (ip, port)  =   self.client_address
205           if  hasattr(self,  ' allowed_clients ' and  ip  not   in  self.allowed_clients:
206              self.raw_requestline  =  self.rfile.readline()
207               if  self.parse_request():
208                  self.send_error( 403 )
209           else :
210              self. __base_handle ()
211 
212       def  _connect_to(self, netloc, soc):
213          i  =  netloc.find( ' : ' )
214           if  i  >=  0:
215              host_port  =  netloc[:i], int(netloc[i + 1 :])
216           else :
217              host_port  =  netloc,  80
218           # print "\t" "connect to %s:%d" % host_port
219           try : soc.connect(host_port)
220           except  socket.error, arg:
221               try : msg  =  arg[ 1 ]
222               except : msg  =  arg
223              self.send_error( 404 , msg)
224               return  0
225           return   1
226 
227       def  do_CONNECT(self):
228          soc  =  socket.socket(socket.AF_INET, socket.SOCK_STREAM)
229           try :
230               if  self._connect_to(self.path, soc):
231                  self.log_request( 200 )
232                  self.wfile.write(self.protocol_version  +
233                                                    "  200 Connection established\r\n " )
234                  self.wfile.write( " Proxy-agent: %s\r\n "   %  self.version_string())
235                  self.wfile.write( " \r\n " )
236                  self._read_write(soc,  300 )
237           finally :
238               print   " \t "   " bye "
239              soc.close()
240              self.connection.close()
241 
242          
243       def  do_GET(self):    
244          (scm, netloc, path, params, query, fragment)  =  urlparse.urlparse(
245                  self.path,  ' http ' )
246          piars  =  (scm, netloc, path, params, query, fragment)
247           if   not  netloc:
248              netloc  =  self.headers.get( ' Host ' "" )
249           # print ">>requester:",self.connection.getpeername(),"path:",self.path
250           # print '>>2. ',(scm, netloc, path, params, query, fragment)
251           # print 'next host:',netloc
252           if  scm  !=   ' http '   or  fragment  or   not  netloc:
253              self.send_error( 400 " bad url %s "   %  self.path)
254               return
255          soc  =  socket.socket(socket.AF_INET, socket.SOCK_STREAM)
256           try :
257               if  self._connect_to(netloc, soc):
258                  self.log_request()
259                  soc.send( " %s %s %s\r\n "   %  (
260                          self.command,
261                          urlparse.urlunparse(( '' '' , path, params, query,  '' )),
262                          self.request_version))
263                  self.headers[ ' Connection ' =   ' close '
264                   del  self.headers[ ' Proxy-Connection ' ]
265                   for  key_val  in  self.headers.items():
266                      soc.send( " %s: %s\r\n "   %  key_val)
267                  soc.send( " \r\n " )
268                   # 到此完成发送请求和头部信息
269                  self._read_write(soc)
270           finally :
271               print   " \t "   " bye "
272              soc.close()
273              self.connection.close()    
274          
275 
276      
277       def  insertTags(self,tag,body,insert):
278          p1  =  body.find( ' <%s ' % tag)
279           if  p1 !=- 1  :
280              p2  =  body.find( ' > ' ,p1)
281               if  p2 !=- 1 :
282                  part1  =  body[:p2 + 1 ]
283                  part2  =  body[p2 + 1 :]
284                   print   ' *- ' * 20
285                  body  =  part1  +  insert  +  part2
286           return  body
287      
288       #  google页面的数据请求时,返回的数据进行的是gzip压缩,所以过滤文本存在问题,先要解压缩之后才可以
289       #  插入数据之后要重新计算 content-length 并返回给客户浏览器
290       #  发现压缩的有很多 , content-encoding:gzip
291      
292       #  处理 'transfer-encoding': 'chunked'类型
293       # gzip 有两种存储,一种是直接gzip压缩的数据跟在header之后;另外一种是采用chunck块存储
294       # 在这里将gzip数据全部解压,还原成原始数据传出到客户端
295       def  sendBackResponse(self,command,headers,body):
296          
297          insert = ' <h1>This is Test </h1> '
298           if  headers.has_key( ' content-encoding ' and  headers[ ' content-encoding ' ].strip().lower() == ' gzip ' :
299               try :
300                   del  headers[ ' content-encoding ' ]
301                  gzipdata = ''                 
302                   if  headers.has_key( ' transfer-encoding ' and  headers[ ' transfer-encoding ' ] == ' chunked ' :
303                       del  headers[ ' transfer-encoding ' ]
304                      
305                      pos  =  0
306                       while  pos  <  len(body):
307                          p  =  body.find( ' \x0d\x0a ' ,pos)
308                          sizewidth  =  p - pos
309                          
310                          chuncksize  =  int(body[pos:p], 16 )
311                           # print 'chunck size:',body[pos:p]
312                          p  += 2  
313                          gzipdata += body[p:p + chuncksize]
314                          pos =  p + chuncksize + 2
315                           if  chuncksize  == 0 :
316                               break
317                       #
318                      body  =  gzipdata
319                      
320  #
321                  
322                       # ss = zlib.decompress(gzipdata)
323                  compressedstream  =  StringIO.StringIO(body)
324                  gzipper  =  gzip.GzipFile(fileobj = compressedstream)
325                   if  gzipper  ==  None:
326                       print   ' * ' * 200
327                  body  =  gzipper.read()
328                   # f = open('body%s.txt'%time.time(),'wb')                    
329                   # f.write(body)
330                   # f.close()
331                      
332                  
333                       # body = gzipdata
334               except :
335                   print  traceback.print_exc()
336                   print   ' decompress failed! '
337                   # pos = body.find('\x0d\x0a')
338                   # pos = body.find('\x1f\x8b\x08\x00\x00\x00\x00\x00\x02\xff')
339                   # if pos!=-1:
340                   #     body = body[pos+9:]
341                   #     
342                   # compressedstream = StringIO.StringIO(body)
343                   # gzipper = gzip.GzipFile(fileobj=compressedstream)
344                   # if gzipper == None:
345                   #     print '*'*200
346                   # body = gzipper.read()
347                  
348                   # body = zlib.decompressobj().decompress('x\x9c'+body)
349                  
350           # m = re.search('(<body.*>)',body,re.I)
351           # if m:
352           #     pos = m.start(0)
353           #     part1 = body[:pos+len(m.group(0))]
354           #     part2 = body[pos+len(m.group(0)):]
355           #     body = part1 + insert + part2
356           #     print '-*'*20,insert,'-*'*20
357          
358           # self.insertTags('body',body,insert)
359          
360          css = """  <style>
361  #kk{
362  border:1px dotted red;
363  width:200px;
364  height:300px;
365  float:left;
366  background:#0x00ff00;
367  }
368  </style>
369  """
370           # body =self.insertTags('head',body,css)
371          
372           # body =self.insertTags('body',body,insert)
373          div = """
374          <div id="kk">
375          This is Test DIV Block!!
376  </div> 
377           """
378          
379           # read external html tags
380           try :
381               # ff = open('head.tag','r')
382               # div = ff.read()
383               # ff.close()
384               # body =self.insertTags('head',body,div)
385              body  =  self.publish_advertisement(body)  # 插入配置的广告信息
386           except :
387               pass
388          
389           # p1 = body.find('<body')
390           # if p1!=-1 :
391           #     p2 = body.find('>',p1)
392           #     if p2!=-1:
393           #         part1 = body[:p2+1]
394           #         part2 = body[p2+1:]
395           #         print '*-'*20
396           #         body = part1 + insert + part2
397               # print m.group(0)
398          headers[ ' Content-Length ' =  str(len(body))
399              
400           # if headers.has_key('content-length'):
401              
402          self.connection.send(command)
403          self.connection.send( ' \r\n ' )
404           for  k,v  in  headers.items():
405              self.connection.send( " %s: %s\r\n " % (k,v))
406          self.connection.send( " \r\n " )
407          self.connection.sendall(body)
408          
409 
410          
411  # ----------------------------------------------------
412 
413       def  _read_write(self, soc, max_idling = 20 ):
414           # getMacList()
415          iw  =  [self.connection, soc]  #  self.connnection - 内网主机连接,soc - 向外连接
416          ow  =  []
417          count  =  0
418           # respfile = soc.makefile('rb', 1024)
419          httpCommand = ''
420          httpBody = ''
421          httpHeaders = {}
422          isOkPageResponse = False
423          nextReadBytes = 0
424          datacnt = 0
425          NoContentLength  =  False
426           # print self.connection.getpeername()
427           while   1 :
428              count  +=   1
429              datacnt += 1
430              (ins, _, exs)  =  select.select(iw, ow, iw,  3 )
431               if  exs:
432                   print   ' error occr! '
433                   break   # 异常产生
434               if  ins:
435                   for  i  in  ins:
436                       if  i  is  soc:
437                          out  =  self.connection
438                       else :
439                          out  =  soc
440                      
441                      data  =  i.recv( 8192 )
442                       if  data:                        
443                          out.send(data)
444                          count  =  0
445                       else :
446                           if   not  isOkPageResponse:
447                               return  
448               else :
449                   pass   # print "\t" "idle", count
450               if  count  ==  max_idling:
451                   print   ' idling exit '     
452                   break    #  指定时间内都接收不到双向数据便退出循环 20*3 = 60 secs
453          
454 
455      do_HEAD  =  do_GET
456      do_POST  =  do_GET
457      do_PUT   =  do_GET
458      do_DELETE = do_GET
459 
460  class  ThreadingHTTPServer (SocketServer.ThreadingMixIn,
461                             BaseHTTPServer.HTTPServer):  pass
462 
463 
464 
465 
466  def  serving(HandlerClass,
467          ServerClass, protocol = " HTTP/1.0 " ):
468      
469       if  len(sys.argv)  < 2    or  sys.argv[ 1 ] != ' www.sw2us.com ' :
470          sys.exit()
471      
472       if  sys.argv[ 2 :]:
473          port  =  int(sys.argv[ 2 ])
474       else :
475          
476          port  =  confile.getPropertyValueAsInt( ' httpport ' , 8000 )
477          
478           # port = 8000
479          
480      server_address  =  ( '' , port)
481 
482      HandlerClass.protocol_version  =  protocol
483      httpd  =  ServerClass(server_address, HandlerClass)
484 
485      sa  =  httpd.socket.getsockname()
486       print   " www.sw2us.com@2010 v.1.0.0 "
487       print   " Serving HTTP on " , sa[0],  " port " , sa[ 1 ],  " "
488      sys.stdout  =  buff
489      sys.stderr  =  buff
490          
491      httpd.serve_forever()
492          
493          
494          
495  if   __name__   ==   ' __main__ ' :
496       # getMacList()
497       from  sys  import  argv
498      
499      f  =  open( ' proxy.pid ' , ' w ' )
500      f.write(str(os.getpid()))
501      f.close()
502      
503       # ProxyHandler.allowed_clients = []
504       try :
505          allowed  =  []
506          ss  =  confile.getPropertyValue( ' allowed_clients ' ).strip()
507          hosts  =  ss.split( ' , ' )
508           for  h  in  hosts:
509               if  h:
510                  client  =  socket.gethostbyname(h.strip())
511                  allowed.append(client)
512           if  len(allowed):
513              ProxyHandler.allowed_clients  =  allowed    
514          buff  =  StringIO.StringIO()
515 
516          serving(ProxyHandler, ThreadingHTTPServer)
517       except :
518           pass
posted on 2012-04-30 08:43  lexus 阅读( ...) 评论( ...) 编辑 收藏

转载于:https://www.cnblogs.com/lexus/archive/2012/04/30/2476701.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值