python的httplib

最近公司网络改造,限制所有对公网的直接tcp连接,打开一个网页只能通过代理,于是,我以前写的一些网络程序,统统不能用鸟~~

直接的socket连接不能用,也没有办法了,但是有些走http协议的,倒是还可以利用下代理访问,便想改造一番。

python的urllib支持代理的方式访问,只要设置一个http_proxy的环境变量就行了。但是,httplib不知道基于什么古怪的原因,居然不支持。

决定手工改了,打开httplib的源代码,仔细读了一番,在HTTPConnection类的connect方法中,直接连到代理服务器。试了试,还是不行,抓了下包,原来浏览器访问的时候在http协议的GET和POST之类的请求中,将地址设成绝对路径,而不仅仅是设置Host的header。又在putrequest函数里改了。

还是不行,抓包,仔细看,很诡异的问题,直到后来无意中发现,http请求里的header里面,Host被加入了两次~~~改掉之后就行了。

真烦啊,耽误我们大量时间的,往往不是那些看起来很困难的东西,而是无足轻重的不起眼的小细节。

直接改httplib的代码有些暴力,其他使用这个库的应用程序,可能会产生一些不可预知的错误,后来改了改,实现了一个单独的代理类。

下面把主要的代码贴出来

[python]
class ProxyHttpConnection(httplib.HTTPConnection):
def __init__(self, host, port=None, strict=None):
httplib.HTTPConnection.__init__(self, host, port, strict)

def connect(self):
"""Connect to the host and port specified in __init__."""
msg = "getaddrinfo returns an empty list"
for res in socket.getaddrinfo(self.host, self.port, 0,
socket.SOCK_STREAM):
af, socktype, proto, canonname, sa = res
if self._http_vsn == 11 and os.environ.has_key("http_proxy"):
proaddr = os.environ["http_proxy"];
if proaddr.startswith("http:"): proaddr = proaddr[7:];
prhost,prport = proaddr.split(":");
sa = prhost,int(prport);
try:
self.sock = socket.socket(af, socktype, proto)
if self.debuglevel > 0:
print "connect: (%s, %s)" % (self.host, self.port)
self.sock.connect(sa)
except socket.error, msg:
if self.debuglevel > 0:
print ‘connect fail:’, (self.host, self.port)
if self.sock:
self.sock.close()
self.sock = None
continue
break
if not self.sock:
raise socket.error, msg

def putrequest(self, method, url, skip_host=0, skip_accept_encoding=0):
if self._HTTPConnection__response and self._HTTPConnection__response.isclosed():
self._HTTPConnection__response = None

if self._HTTPConnection__state == httplib._CS_IDLE:
self._HTTPConnection__state = httplib._CS_REQ_STARTED
else:
raise CannotSendRequest()

self._method = method
if not url:
url = ‘/’
if self._http_vsn == 11 and os.environ.has_key("http_proxy"):
if not url.startswith("http"):
tmport = "";
if self.port!=80: tmport = ":%d"%port;
url = "http://%s%s%s" % (self.host,tmport,url);
str = ‘%s %s %s’ % (method, url, self._http_vsn_str)

self._output(str)

if self._http_vsn == 11:
if not skip_accept_encoding:
self.putheader(‘Accept-Encoding’, ‘identity’)
self.putheader(‘Proxy-Connection’, ‘Close’);
else:
pass
[/python]

在自己的应用中,直接使用这个ProxyHttpConnection代替HttpConnection类就行了。

Proxy-Connection这个header在标准的http协议里是没有定义的,但是大部分浏览器实现了它,来告诉缓存服务器应该将连接直接关掉还是保持,主要是因为缓存服务器两边的连接有http 1.0和http 1.1两种可能,这样做反而导致了误解和歧义,因为http协议头本身就有一个connection来控制。现在的大部分浏览器会加入一个判断,如果连接的是一个代理服务器,就会使用Proxy-Connection,如果是真正的服务器,就采用标准的头。与之相关的一些讨论可以google到。

登山

下了几天雨,今天终于放晴,心情也为之一变。

周六下的很大,上午有些感冒,下午很郁闷,爬了一把南山,中途雨下的很大,浑身淋的湿透。

上周末我尝试骑自行车到山顶,当时感觉没有多高,奋力往上骑,有些地方坡度甚至已经超过了45度,在快到山顶的时候虚脱了,实在走不动,我喘气都上不来了,汗水已经把我全身浸没,脸色铁青,几乎倒在地上。休息一会决定放弃,我连走路的力气都没有了。回去的路上,一个小孩子看到我吓得往他妈妈怀里钻,唉,真的想自己看看当时的形象。

周六我步行爬了上去,一路走来,到了山顶,没有感觉丝毫的劳累。看着道路的坡度,实在是感叹我居然能够一直骑上去,再看看我放弃的地方,距离山顶只差那么一点点,真是可惜啊,回想一下,就是这么一点点距离当时也实在没有力气上去了。为山九仞,功亏一篑,就是最后的一点点,将之前所有的努力都一笔抹煞,实在令人扼腕痛惜。

可能换一辆性能更好一些的单车会好一些,其实主要还是刚开始我骑的太快了,如果一开始慢慢的走,也许不会那么累,但是谁又知道呢,走的慢了,可能需要更多的功才能维持。第二次步行给我的感叹最多的就是,这座山实在是太陡峭了。

这次登山的经历,跟最近这段时间发生的一件事情倒是有些相似,也许昭示着我应该放弃吧。

ssh

这个空间的提供商说提供ssh访问,但是需要额外申请,那就申请吧,提交之后一直没有反应,可能是我填写的理由不够充分。

不过既然有权限执行perl脚本,那想必我的账户已经具有执行一些shell命令的权限了,只不过他们没有给我提供远程进行ssh的方式罢了。

但如果使用perl写一段cgi脚本,提供一个输入框,输入需要执行的命令,直接通过perl调用系统命令,是不是就能够实现一个简单的shell了?

下面是这段perl脚本

[perl]
#!/usr/bin/perl

use CGI qw(:all);

print header(),start_html("a simple shell");

print "<pre>n";
if (param("cmd")){
$c = param("cmd");
print `$c`;
}
print "</pre>n";
print start_form(-name=>"fm"),
textfield("cmd","",120),
end_form;

print "<script>document.fm.cmd.value=”;document.fm.cmd.focus();</script>";

print end_html();
[/perl]

放上去,随便敲下,cat /etc/passwd,果然很爽,除了不支持类似vi之类的交互模式,对于大部分场合已经足够了。

还有些不足,比如到stderr的输出无法重定向出来,仔细想想,应该有解决方案吧,不过也没必要了,倒是想到一个方案,先把标准错误流重定向到一个临时文件,再cat出来。

用了几下之后便把这个脚本删掉了,直接放到外面太危险了

无语

从5月23号开始,megabyet的免费空间就一直访问不了,连接的时候服务器timeout,一开始我以为是down掉了,过了一天还是不能访问,心想维护人员也不可能这么不专业吧。于是我怀疑是否被墙掉了,但是如果被墙掉一般会是reset by peer的错误,timeout还是服务器挂掉的可能行比较大一些。

后来翻出去看了一下,果然能够正常访问,仔细想想原因,也许是ip被直接干掉了,在bing.com里输入ip:64.79.79.227有上万条结果,如此多站点都指向在这个地址,总有几个站点的内容敏感,被干掉也属正常,唉,好东西都被我朝糟蹋了。

一开始用blogger,遭墙,然后是appengine,也是断续的被封,后来用免费的megabyet以后以为高枕无忧,怎知到最后还是挂掉。

于是痛下决心,决定花钱租空间,对比后选择了一个叫cyberultra的新加坡服务提供商,一年$23.4,大致折合人民币160块,还算便宜,将就着用吧。

将域名的A记录改到了这个ip地址。花钱果然不同,支持perl和python等cgi脚本,ping了下,大致有300ms的延迟,配置上了wordpress后感觉速度和稳定性上都还可以。

我没什么大的需求,就是一个能写点东西的地方,连这点微小的权利,都不能保障,政~#府(连这两个字都要拆开写)啊,让我如何不愤怒呢~

新家,第一篇,发泄一下这几天的不爽。