这篇文章主要介绍HttpClient使用过程中的安全隐患有哪些,文中介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们一定要看完!
HttpClient使用过程中的安全隐患,这个有些标题党。因为这本身不是HttpClient的问题,而是使用者的问题。
安全隐患场景说明:
一旦请求大数据资源,则HttpClient线程会被长时间占有。即便调用了org.apache.commons.httpclient.HttpMethod#releaseConnection()方法,也无济于事。
如果请求的资源是应用可控的,那么不存在任何问题。可是恰恰我们应用的使用场景是,请求资源由用户自行输入,于是乎,我们不得不重视这个问题。
我们跟踪releaseConnection代码发现:
org.apache.commons.httpclient.HttpMethodBase#releaseConnection()
public void releaseConnection() { try { if ( this .responseStream != null ) { try { // FYI - this may indirectly invoke responseBodyConsumed. this .responseStream.close(); } catch (IOException ignore) { } } } finally { ensureConnectionRelease(); } }
org.apache.commons.httpclient.ChunkedInputStream#close()
public void close() throws IOException { if ( ! closed) { try { if ( ! eof) { exhaustInputStream( this ); } } finally { eof = true ; closed = true ; } } }
org.apache.commons.httpclient.ChunkedInputStream#exhaustInputStream(InputStream inStream)
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 ) { ; } }
看到了吧,所谓的丢弃response,其实是读完了一次请求的response,只是不做任何处理罢了。
想想也是,HttpClient的设计理念是重复使用HttpConnection,岂能轻易被强制close呢。
怎么办?有朋友说,不是有time out设置嘛,设置下就可以下。
我先来解释下Httpclient中两个time out的概念:
public static final String CONNECTION_TIMEOUT = "http.connection.timeout";
即创建socket连接的超时时间:java.net.Socket#connect(SocketAddress endpoint, int timeout)中的timeout
public static final String SO_TIMEOUT = "http.socket.timeout";
即read data过程中,等待数据的timeout:java.net.Socket#setSoTimeout(int timeout)中的timeout
而在我上面场景中,这两个timeout都不满足,确实是由于资源过大,而占用了大量的请求时间。
问题总是要解决的,解决思路如下:
利用DelayQueue,管理所有请求
利用一个异步线程监控,关闭超长时间的请求
演示代码如下:
public class Misc2 { private static final DelayQueue < Timeout > TIMEOUT_QUEUE = new DelayQueue < Timeout > (); public static void main(String[] args) throws Exception { new Monitor().start(); // 超时监控线程 new Request( 4 ).start(); // 模拟***个下载 new Request( 3 ).start(); // 模拟第二个下载 new Request( 2 ).start(); // 模拟第三个下载 } public static class Request extends Thread { private long delay; public Request( long delay){ this .delay = delay; } public void run() { HttpClient hc = new HttpClient(); GetMethod req = new GetMethod( " http://www.python.org/ftp/python/2.7.1/Python-2.7.1.tgz " ); try { TIMEOUT_QUEUE.offer( new Timeout(delay * 1000 , hc.getHttpConnectionManager())); hc.executeMethod(req); } catch (Exception e) { System.out.println(e); } req.releaseConnection(); } } public static class Monitor extends Thread { @Override public void run() { while ( true ) { try { Timeout timeout = TIMEOUT_QUEUE.take(); timeout.forceClose(); } catch (InterruptedException e) { System.out.println(e); } } } } public static class Timeout implements Delayed { private long debut; private long delay; private HttpConnectionManager manager; public Timeout( long delay, HttpConnectionManager manager){ this .debut = System.currentTimeMillis(); this .delay = delay; this .manager = manager; } public void forceClose() { System.out.println( this .debut + " : " + this .delay); if (manager instanceof SimpleHttpConnectionManager) { ((SimpleHttpConnectionManager) manager).shutdown(); } if (manager instanceof MultiThreadedHttpConnectionManager) { ((MultiThreadedHttpConnectionManager) manager).shutdown(); } } @Override public int compareTo(Delayed o) { if (o instanceof Timeout) { Timeout timeout = (Timeout) o; if ( this .debut + this .delay == timeout.debut + timeout.delay) { return 0 ; } else if ( this .debut + this .delay > timeout.debut + timeout.delay) { return 1 ; } else { return - 1 ; } } return 0 ; } @Override public long getDelay(TimeUnit unit) { return debut + delay - System.currentTimeMillis(); } } }
以上是“HttpClient使用过程中的安全隐患有哪些”这篇文章的所有内容,感谢各位的阅读!希望分享的内容对大家有帮助,更多相关知识,欢迎关注编程网行业资讯频道!