浙江省高等学校教师教育理论培训

微信搜索“教师资格证岗前培训”小程序

  博客园  :: 首页  :: 新随笔  :: 联系 :: 订阅 订阅  :: 管理

用CONNECT方法突破HTTP代理服务器的扩展名封锁(python) [转] - MyNewID - 博客园

公司里的电脑是通过一台内部代理服务器上网的,为了节省带宽,对下载进行了限制。方法是过滤URL中的扩展名,如'exe','rar','tar.gz'等,并且限制了连接时间,当连接时间超过2分钟就主动断开。这样平常就只能看看网页了,要下载就要申请,非常麻烦。虽说可以通过“问号大法”来解决URL过滤,wget来解决断点续传,但这样还是不好,下大一点的文件或网速慢一点时,要断线好几十次。一次偶然的机会发现公司的代理服务器没有限制CONNECT命令,哈哈,终于可以解决下载问题了。

通过向代理服务器发送CONNECT命令,可以让代理服务器和目标主机的目标端口建立一个连接,这样本机和目标主机就有了一个通道。从此以后向代理服务器发送命令就等于向目标主机发送命令。这和一般的GET方式不同,完全不受过滤机制的影响。先来看看两种方式的不同之处,

GET方式:

socket.connect('HTTP代理服务器IP',HTTP代理服务器端口)

socket.send('GET http://XXX.XXX.XXX/XXX.EXE HTTP/1.1\r\n

                  HOST: XXX.XXX.XXX\r\n\r\n')


CONNECT方式:

socket.connect('HTTP代理服务器IP',HTTP代理服务器端口)

socket.send('CONNECT XXX.XXX.XXX:80 HTTP/1.1\r\n\r\n')

socket.recv(1024)

socket.send('GET /XXX.EXE HTTP/1.1\r\n

                  HOST: XXX.XXX.XXX\r\n\r\n')


就是这么简单,下面就用python来完成编码。python有很多对http协议的封装库,如urllib2,httplib等。但我不知urllib2如何设置connect方式的代理,懒得去研究了。所以直接用socket来实现。相对于C++,用python来操作socket是如此的简单优雅。
pget.py:

import socket

import sys



#如果参数<1则显示信息

if len(sys.argv)<2:

    print 'proxyGet v0.3 \n\

Written by Wangfan\n\

Powered by Python 2.5\n\n\

Usage:\n\

    pget [URL]'

    sys.exit()



#URL处理函数,得到文件名、HOST、GET请求

def parseURL(url):

    url=url.split('/')

    file_name=url[-1].strip()

    host=url[2]

    del url[0]

    del url[0]

    del url[0]        

    header_get='/'+'/'.join(url)

    return (file_name,host,header_get)

    

urlInfo=parseURL(sys.argv[1])

print '***pget v0.3***\n\n\

File Name:  %s\n\

     From:  %s\n\

      GET:  %s\n\

' %(urlInfo[0],urlInfo[1],urlInfo[2])



#确认可以开始下载

input_char=raw_input('ok?(press "y" to start,press other to exit):')

if input_char!='y':

    sys.exit()



#初始化socket

s=socket.socket()



#连接代理服务器

s.connect(('10.100.1.206',3128))



#发送CONNECT命令,连接目标主机

s.send('CONNECT '+urlInfo[1]+':80 HTTP/1.1\n\n')



#得到回应

print 'Proxy:',s.recv(1024).strip()



#发送下载请求和头信息

s.send('GET '+urlInfo[2]+' HTTP/1.1\r\n\

Host: '+urlInfo[1]+'\r\n\

User-Agent: Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9.0.3) Gecko/2008092417 Firefox/3.0.3\r\n\

Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8\r\n\

Accept-Language: en-us,en;q=0.5\r\n\

Accept-Encoding: gzip,deflate\r\n\

Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7\r\n\

Keep-Alive: 300\r\n\

Proxy-Connection: keep-alive\r\n\r\n')

r=''

headers=''

content_length=0

header_end=False



#循环读取,处理回应的头信息和内容

while True:

    r+=s.recv(1)

    downloaded=len(r)

    if header_end==False:

        if r.find('\r\n\r\n')!=-1:

            headers=r.split('\r\n\r\n')[0]

            print headers

            for header in headers.split('\r\n'):

                if header.split(':')[0]=='Content-Length':

                    content_length=int(header.split(':')[-1])

                if header.split(':')[0]=='Location':

                    sys.exit()

            r=''

            header_end=True

            if content_length==0:

                sys.exit()

    if downloaded%1024==0:

        #输出下载进度

        print '\r[',int((downloaded/1024)/float(content_length/1024)*100),'%]',downloaded/1024,'KB /',content_length/1024,'KB',



    #如果已下载的内容长度等于头信息中长度则跳出

    if downloaded==content_length:

        break



#保存文件

fp=open(urlInfo[0],'wb')

fp.write(r)

fp.close() 

s.close()

sys.exit()



由于不想占用过多的带宽,所以没有加入多线程。但是,可以扩展的地方还有很多,比如断点续传等,以后有空再完善吧,先做个可以用的原型:)

posted on 2012-04-30 09:10  lexus  阅读(439)  评论(0编辑  收藏  举报