HttpClient使用过程中的安全隐患
HttpClient使用过程中的安全隐患,这个有些标题党。因为这本身不是HttpClient的问题,而是使用者的问题。
安全隐患场景说明:
一旦请求大数据资源,则HttpClient线程会被长时间占有。即便调用了org.apache.commons.httpclient.HttpMethod#releaseConnection()方法,也无济于事。
如果请求的资源是应用可控的,那么不存在任何问题。可是恰恰我们应用的使用场景是,请求资源由用户自行输入,于是乎,我们不得不重视这个问题。我们跟踪releaseConnection代码发现:
org.apache.commons.httpclient.HttpMethodBase#releaseConnection()
1 public void releaseConnection() {
2 try {
3 if (this.responseStream != null) {
4 try {
5 // FYI - this may indirectly invoke responseBodyConsumed.
6 this.responseStream.close();
7 } catch (IOException ignore) {
8 }
9 }
10 } finally {
11 ensureConnectionRelease();
12 }
13 }org.apache.commons.httpclient.ChunkedInputStream#close()
1 public void close() throws IOException {
2 if (!closed) {
3 try {
4 if (!eof) {
5 exhaustInputStream(this);
6 }
7 } finally {
8 eof = true;
9 closed = true;
10 }
11 }
12 }org.apache.commons.httpclient.ChunkedInputStream#exhaustInputStream(InputStream inStream)
1 static void exhaustInputStream(InputStream inStream) throws IOException {
2 // read and discard the remainder of the message
3 byte buffer[] = new byte[1024];
4 while (inStream.read(buffer) >= 0) {
5 ;
6 }
7 }看到了吧,所谓的丢弃response,其实是读完了一次请求的response,只是不做任何处理罢了。想想也是,HttpClient的设计理念是重复使用HttpConnection,岂能轻易被强制close呢。
怎么办?有朋友说,不是有time out设置嘛,设置下就可以下。
我先来解释下Httpclient中两个time out的概念:
1.public static final String CONNECTION_TIMEOUT = "http.connection.timeout";
即创建socket连接的超时时间:java.net.Socket#connect(SocketAddress endpoint, int timeout)中的timeout2.public static final String SO_TIMEOUT = "http.socket.timeout";
即read data过程中,等待数据的timeout:java.net.Socket#setSoTimeout(int timeout)中的timeout而在我上面场景中,这两个timeout都不满足,确实是由于资源过大,而占用了大量的请求时间。
问题总是要解决的,解决思路如下:
1.利用DelayQueue,管理所有请求
2.利用一个异步线程监控,关闭超长时间的请求演示代码如下:
1 public class Misc2 {
2
3 private static final DelayQueue<Timeout> TIMEOUT_QUEUE = new DelayQueue<Timeout>();
4
5 public static void main(String[] args) throws Exception {
6 new Monitor().start(); // 超时监控线程
7
8 new Request(4).start();// 模拟第一个下载
9 new Request(3).start();// 模拟第二个下载
10 new Request(2).start();// 模拟第三个下载
11 }
12
13 /**
14 * 模拟一次HttpClient请求
15 *
16 * @author <a href="Stone.Jmailto:li.jinl@alibaba-inc.com">Stone.J</a> 2011-4-9
17 */
18 public static class Request extends Thread {
19
20 private long delay;
21
22 public Request(long delay){
23 this.delay = delay;
24 }
25
26 public void run() {
27 HttpClient hc = new HttpClient();
28 GetMethod req = new GetMethod("http://www.python.org/ftp/python/2.7.1/Python-2.7.1.tgz");
29 try {
30 TIMEOUT_QUEUE.offer(new Timeout(delay * 1000, hc.getHttpConnectionManager()));
31 hc.executeMethod(req);
32 } catch (Exception e) {
33 System.out.println(e);
34 }
35 req.releaseConnection();
36 }
37
38 }
39
40 /**
41 * 监工:监控线程,通过DelayQueue,阻塞得到最近超时的对象,强制关闭
42 *
43 * @author <a href="Stone.Jmailto:li.jinl@alibaba-inc.com">Stone.J</a> 2011-4-9
44 */
45 public static class Monitor extends Thread {
46
47 @Override
48 public void run() {
49 while (true) {
50 try {
51 Timeout timeout = TIMEOUT_QUEUE.take();
52 timeout.forceClose();
53
补充:综合编程 , 安全编程 ,