HttpClient超时机制(安全问题处理:访问超大文件控制)
背景
?? ? 最近一直在做项目,其中的一个功能点,主要是访问外部网站并获取页面的字符串,具体的网站url完全是由用户输入,所以存在一定的安全隐患。
?? ?从测试来看,如果给定的一部电影的url地址,链接会一直不能被关闭,直到数据流被读完,如果来个几十次这样的请求,应用估计也差不多崩溃了
?
说明: ? 项目中使用的HttpClient版本是3.0.1
测试一般的HttpClient使用例子:?
?
??
分析
目前httpClient3.1只支持3种timeout的设置:
?
connectionTimeout ?: ?socket建立链接的超时时间,Httpclient包中通过一个异步线程去创建socket链接,对应的超时控制。timeoutInMilliseconds : ?socket read数据的超时时间,?socket.setSoTimeout(timeout);httpConnectionTimeout : ?如果那个的是MultiThreadedHttpConnectionManager,对应的是从连接池获取链接的超时时间。
分析一下问题,我们需要的是一个HttpClient整个链接读取的一个超时时间,包括请求发起,Http Head解析,response流读取的一系列时间的总和。?
目标很明确,对应的修正后的测试代码:?static void exhaustInputStream(InputStream inStream) throws IOException { // read and discard the remainder of the message byte buffer[] = new byte[1024]; while (inStream.read(buffer) >= 0) { ; } }?说明:?因为非sleep和park的方法,不会响应InterruptedException事件,所以普通future超时发起的Thread.interrpt()并没有效果。默认的SimpleHttpConnectionManager不支持这样的操作,所以选择MultiThreadedHttpConnectionManager.shutdown()方法,强制关闭底层HttpConnection的sock的输入输出流。总结?
理解一下HttpClient这样设计的理由: socket重用,keepAlive协议的支持等,保证上一次数据不会对新的请求有影响。Thread.interrpt()处理,只会在Thread处于sleep或者wait状态才会被唤醒(api的描述)。而且该方法的调用并不自动产生InterruptedException异常,一般是需要自己判断Thread.isInterrupted(),然后throw异常。 我们目前使用的一些jdk cocurrent类比如future.cancel也是类似处理。
1 楼 zywang 2011-02-23 也许你可以先发个HEAD请求,获取一下请求头信息,判断返回内容的类型,如果时流类型的,那就没必要再发送GET请求获取资源了 2 楼 agapple 2011-02-23 zywang 写道也许你可以先发个HEAD请求,获取一下请求头信息,判断返回内容的类型,如果时流类型的,那就没必要再发送GET请求获取资源了
如果你遇到个合格一点的码工,很容易伪造Head信息,包括隐藏具体的content-length,然后读取/dev/null信息给你,很容易就搞死应用 3 楼 stone2083 2011-04-09 今天发现,在3.1版本中。SimpleHttpConnectionManager也有shutdown方法了。不需要使用MultiThreadedHttpConnectionManager.
3.0.1中,还没有此方法。呜呼。 4 楼 agapple 2011-04-09 stone2083 写道今天发现,在3.1版本中。SimpleHttpConnectionManager也有shutdown方法了。不需要使用MultiThreadedHttpConnectionManager.
3.0.1中,还没有此方法。呜呼。
不是吧,我们不就是用3.1版本? 现在HttpClient出到4.1.1版本,貌似在新版本里api使用变化比较大。 5 楼 pindai 2011-07-31 hi,我想问下,你把整个manager都shut down了。那你下次调用会发生什么或者说怎么处理吧? 6 楼 agapple 2011-08-01 pindai 写道hi,我想问下,你把整个manager都shut down了。那你下次调用会发生什么或者说怎么处理吧?
因为我这里的需求是请求不固定的外部网站,所以没必要使用connection pool,所以会在timeout下关闭整个manager。 每次调用时都是new一个manager进行链接请求,代价并不高。
如果你对connection pool有需求,可以使用新版本看下,或者使用反射强制关闭下http链接即可 7 楼 student007 2012-07-16 你好,我现在遇到问题和你说的 一样,能否请教你几个问题? 我 qq: 490836924,等候你的佳音。 谢谢