编写了一个HTTP高匿代理
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
1. 编写了一个HTTP高匿代理
本以为编写http代理和上一篇的端口转发差不多的,结果实际一编写起来发现要复杂的多。怎么回事呢,就在于要手动解析http协议。
说简单点吧,如果直接用ie上一个网站,用sniffe一看http请求头是这样的。
GET / HTTP/1.1
Accept: application/x-ms-application, image/jpeg, application/xaml+xml, image/gif, image/pjpeg, application/x-ms-xbap, application/x-shockwave-flash, application/QVOD, application/QVOD, */* Accept-Language: zh-CN
User-Agent: Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 6.1; WOW64; Trident/4.0; SLCC2; .NET CLR 2.0.50727; .NET CLR 3.5.30729; .NET CLR 3.0.30729; Media Center PC 6.0; .NET4.0C; .NET4.0E)
Accept-Encoding: gzip, deflate
Host:
Connection: Keep-Alive
Cookie: xxxxxxxxx
但是如果用代理就变成了这样
GET / HTTP/1.1
Accept: application/x-ms-application, image/jpeg, application/xaml+xml, image/gif, image/pjpeg, application/x-ms-xbap, application/x-shockwave-flash, application/QVOD, application/QVOD, */* Accept-Language: zh-CN
User-Agent: Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 6.1; WOW64; Trident/4.0; SLCC2; .NET CLR 2.0.50727; .NET CLR 3.5.30729; .NET CLR 3.0.30729; Media Center PC 6.0; .NET4.0C; .NET4.0E)
Accept-Encoding: gzip, deflate
Host:
Proxy-Connection: Keep-Alive
Cookie: xxxxxxxxx
区别就在这里,用代理get那地方会把完整url写上,而且Connection加上了proxy标志,其他一样。所以用TcpListener和TcpClient每接受一个连接,就要首先把提交的http请求的头部分改写,就是把下面的改成上面的。
这是GET方法,只有请求的头部分没有实体部分。
还有一种POST方法,是包含实体部分的,比如上传图片了什么的,都是用的POST方法。post方法紧跟在头部分后面。
怎么判断哪是头那是实体呢?
http协议规定头必然有2个连续的"/r/n",就像上面Cookie后面就跟了2个/r/n,所以读取请求头的时候只要读到/r/n/r/n,那么前面就是头,后面就是实体。实体大小在上面有一个Content-Length标记。所以从/r/n/r/n后面读Content-Length大小后就结束了
还有一种是CONNECT方法,凡是用connect的就是ssl加密通信,当收到 CONNECT
:443 HTTP /1.0之类的请求后,代理服务器要给客户(如IE)返回一个"HTTP/1.1 200 Connection established/r/n/r/n",然后就tcpclinet一个服务器的443,后只负责客户和服务器的转发就可以了,就像上一篇的转发一样,什么都不用管了。这种反而最简单。
就以上3种最常用。
其他的请求方法还有put option什么的,因为实在是没见过,也不知道去哪里试所以都按照get post的方法处理了。
服务器返回更麻烦,麻烦就在于http协议过于宽松,如果每个回应或者请求都包括Content-Length或者chunked之类表明实体大小的东西那么就好判断了,http协议规定判断实体大小的方法有好几种
,当然最准确的就是有Content-Length和chunked,还有以服务器断开连接来判断的,有的回应中没有Content-Length或者chunked,以什么时候断开来判断,疑似那些网络上下坏文件的就是这么造成的,客户根本不知道有多大,如果读取完了服务器断开那么没问题,如果读着读着网络中断了了
,客户还以为是服务器断开了是吧。
所以读取服务器回应的时候就要判断好几个值
1、判断状态码,http协议规定1xx 204 304肯定不包括实体,所以读到/r/n/r/n就不用再读了
2、判断没有Content-Length
3、判断有没有chunked
如果有Content-Length,那么读取和上面请求头一样,/r/n/r/n后面读Content-Length个返回给客户。
还有一种是chunked编码,这种编码一般是gzip压缩的,微软论坛就是用的这种,当你请求页面的时候,服务器一边把页面gzip压缩一点传给你再压缩一点传给你,所以开始没法得到Content-Length,但是每chunked却有标记的大小
HTTP/1.1 200 OK
Cache-Control: private
Content-Type: text/html; charset=utf-8
Server: Microsoft-IIS/7.5
X-AspNetMvc-Version: 2.0
X-AspNet-Version: 4.0.30319
Set-Cookie: Set-Cookie: X-Powered-By:
P3P: CP=ALL IND DSP COR ADM CONo CUR CUSo IVAo IVDo PSA PSD TAI TELo OUR SAMo CNT COM INT NAV ONL PHY PRE PUR UNI
Server: CO1VB06
Date: Fri, 24 Sep 2010 09:33:28 GMT
ntCoent-Length: 166137
Content-Encoding: gzip
Transfer-Encoding: chunked
2D23
...........}.s.G.......j....*u......y....%...;QO.M.[....3..,...
.!..O....H-."v..>.............=YY