关于WEBrick

前前后后用了很多年ruby,最熟悉的标准库恐怕就是WEBrick了,本文记录了这期间个人遇到的关于它的各种问题,随着版本更新,有的可能已经不存在了。

 

WEBrick是完全支持并发请求(select→accept→thread)的http server。我们在开发rails应用的时候,其实是rails人为的加锁,才导致使用WEBrick服务器时同一时间只能相应一个request;而且使用WEBrick原有的并发也是有rails的配置项可以启用的。

WEBrick的主要问题就是它是用ruby写的,因此性能不佳,内存管理不佳。

现在最主流的ruby界的服务器大概是Passenger了。

此外走libev(EventMachine)这种路线的是Thin,只可惜Rails这种框架发挥不出来EventMachine的优势。注:EventMachine的地位大概就像是node.js本身。

 

❶ 一个没有注明response的字符编码导致浏览器渲染成乱码的bug

环境:大学在读期间,WinXP+JRuby 1.4.0(Ruby 1.8.6的标准库)。

我处于学校内网的某个宿舍子网,所以网上邻居之类涉及广播报文的协议无法彼此穿透;所以我经常使用WEBrick写个小Web服务器来共享文件。

问题是大家使用的各种浏览器(最便利的客户端)的默认编码一般是gbk,而WEBrick的FileHandler类生成的http response中是使用UTF-8的编码却没有注明这一点,导致上述浏览器使用默认的gbk解码,使得文件名中ASCII之外的字符显示为乱码。

自己的脚本很简单,如下:

在创建s的时候,会有代码把:DocumentRoot用FileHandler作为HTTPServlet并以:DocumentRootOptions为参数mount到'/',成为Web根目录。

:DocumentRootOptions里的:FancyIndexing的意思是,如果是个目录(一般会mount一个html甚至erb而不是目录),并且这个开关开启了的话,会显示文件列表。这正是我所希望的,显示一个文件列表来共享文件。如果设为false,客户端访问一个目录时会提示没有权限而不是显示一个文件列表。

问题出在FileHandler构造文件列表(一个Response报文)的时候,在这个时间点之前,FileHandler的三个Callback函数和:RequestCallback都已经执行过了(如果你实现了的话),如果你没有实现任何一个Callback,那么到了这个时间点,Response报文的Content-Type应该是nil,所以FileHandler的作者就只得把Content-Type指定成"text/html",这个字符串里不带任何字符编码信息,然后到了默认gbk的浏览器客户端那里,汉字就都成乱码了。

之所以说是个Bug,是因为回调函数里指定Content-Type会在后来被覆盖掉,而且没有指定Content-Type的参数。

最后在filehandler.rb文件中,把"text/html"改成"text/html; charset=utf-8",问题解决。

 

❷webrick/httpproxy没有正确使用URI库的bug

实习公司上网要用http代理,需要认证的那种;而且2009年刚刚被该公司忽悠到大连培训的时候,五六个人一个账号,且帐号绑定IP,也就是说同时只能有一台机器上网,于是写个脚本做了个二级代理,七八行的样子,就是用webrick/httpproxy。

因为要做二级代理,所以需要把一级代理作为:ProxyURI参数传给构造函数,当时除了脚本慢点(一是JRuby,二是WEBrick不支持流),别的还凑合。话说现在来到沈阳,分配的账号需要设置强度很高的密码,于是乎不小心密码中包含了“@”,这时才发现,我的脚本无法支持"http://user:pa%[email protected]:1234"这样的:ProxyURI。我不知道URI的RFC怎么规定的,不过曾经用mplayer看ftp里电影的时候,mplayer支持这种转义的方式(这里就是用%40替代@)。

URI这个库只保存转义后的序列,也就是你交给他parse的字符串的片段,它本来就不打算decode之后存起来交给其他人使用。所以这个bug 的问题出在WEBrick::HTTPProxyServer,它在将URI的user_info编码为Base64之前没考虑user_info中可能含有%23%24之类需要解码后才能使用的字符序列。

解决方法也很简单,利用ruby无敌的动态性,在脚本中重新定义 WEBrick::HTTPProxyServer的相应方法就是了,把upstream.user_info改成 URI.decode_www_form_component(upstream.userinfo)即可。此外URI.encode_www_form_component方法可以方便地将特殊字符转义。

至少在ruby192-p0中还存在这个bug,不过后来我使用了效率更高的软件Privoxy:

forward / 192.168.1.95:8080


{ +add-header{Proxy-Connection: keep-alive} }
/
{ +add-header{Proxy-Authorization: Basic eXVfcTohQDM0UVdlcg==} }
/

 第一行是在Main Configuration里,其余几行在UserActions里。UserActions里的配置其实算个hack,Privoxy没有什么专门的方法支持认证——把那串“乱码”用base64解码就能看到我的用户名和密码了。

 

你可能感兴趣的:(Web,浏览器,脚本,Ruby,jruby)