Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

https://issues.jboss.org/browse/RAILO-3208 #431

Open
wants to merge 3 commits into
base: 4.2
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Binary file modified railo-java/libs/apache-commons-httpclient.jar
Binary file not shown.
Binary file modified railo-java/libs/apache-commons-httpcore.jar
Binary file not shown.
Binary file modified railo-java/libs/apache-commons-httpmime.jar
Binary file not shown.
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,12 @@
import java.io.InputStream;
import java.net.URL;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.concurrent.TimeUnit;

import org.apache.http.Header;
import org.apache.http.HttpEntity;
Expand All @@ -29,11 +31,13 @@
import org.apache.http.client.params.ClientPNames;
import org.apache.http.client.protocol.ClientContext;
import org.apache.http.conn.params.ConnRoutePNames;
import org.apache.http.conn.scheme.SchemeRegistry;
import org.apache.http.entity.ByteArrayEntity;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.auth.BasicScheme;
import org.apache.http.impl.client.BasicAuthCache;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.impl.conn.PoolingClientConnectionManager;
import org.apache.http.impl.cookie.BasicClientCookie;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.params.BasicHttpParams;
Expand Down Expand Up @@ -65,6 +69,23 @@

public class HTTPEngine4Impl {


private static PoolingClientConnectionManager cm;
private static final int CONNECTION_TTL = 30;
private static Map<String, DefaultHttpClient> clients;
public static final boolean CONNECTION_POOLING_ENABLED = true;
private static ConnectionCleaner cc;
static {
clients = new HashMap<String, DefaultHttpClient>();
SchemeRegistry sr = new PoolingClientConnectionManager( ).getSchemeRegistry();
cm = new PoolingClientConnectionManager(
sr, CONNECTION_TTL,
TimeUnit.SECONDS );
cm.setDefaultMaxPerRoute(400);
cm.setMaxTotal(1000);
cc = new ConnectionCleaner( cm, CONNECTION_TTL );
}

/**
* does a http get request
* @param url
Expand Down Expand Up @@ -214,18 +235,17 @@ private static HTTPResponse _invoke(URL url,HttpUriRequest request,String userna
ProxyData proxy, railo.commons.net.http.Header[] headers, Map<String,String> formfields) throws IOException {

// TODO HttpConnectionManager manager=new SimpleHttpConnectionManager();//MultiThreadedHttpConnectionManager();
BasicHttpParams params = new BasicHttpParams();
DefaultHttpClient client = createClient(params,maxRedirect);
DefaultHttpClient client = createClient( maxRedirect, timeout );
HttpHost hh=new HttpHost(url.getHost(),url.getPort());
setHeader(request,headers);
if(CollectionUtil.isEmpty(formfields))setContentType(request,charset);
setFormFields(request,formfields,charset);
setUserAgent(request,useragent);
setTimeout(params,timeout);
HttpContext context=setCredentials(client,hh, username, password,false);
setProxy(client,request,proxy);
if(context==null)context = new BasicHttpContext();
return new HTTPResponse4Impl(url,context,request,client.execute(request,context));
HTTPResponse result = new HTTPResponse4Impl(url,context,request,client.execute(request,context));
return result;
}

private static void setFormFields(HttpUriRequest request, Map<String, String> formfields, String charset) throws IOException {
Expand All @@ -245,11 +265,32 @@ private static void setFormFields(HttpUriRequest request, Map<String, String> fo
}
}

public static DefaultHttpClient createClient(BasicHttpParams params, int maxRedirect) {
params.setParameter(ClientPNames.HANDLE_REDIRECTS, maxRedirect==0?Boolean.FALSE:Boolean.TRUE);
public static DefaultHttpClient createClient( int maxRedirect, long timeout ) {
String key = Integer.toString( maxRedirect ) + ":" + Long.toString( timeout );
if( !clients.containsKey( key ))
clients.put( key, _createClient( maxRedirect, timeout ) );
return clients.get( key );

}

private static DefaultHttpClient _createClient( int maxRedirect, long timeout ) {
BasicHttpParams params = new BasicHttpParams();
if( timeout > 0L ) setTimeout(params, timeout);
params.setParameter(ClientPNames.HANDLE_REDIRECTS, maxRedirect==0?Boolean.FALSE:Boolean.TRUE);
if(maxRedirect>0)params.setParameter(ClientPNames.MAX_REDIRECTS, new Integer(maxRedirect));
params.setParameter(ClientPNames.REJECT_RELATIVE_REDIRECT, Boolean.FALSE);
return new DefaultHttpClient(params);

if ( CONNECTION_POOLING_ENABLED ) {
_startConnectionCleanerIfNeeded();
return new DefaultHttpClient( cm, params );
}
return new DefaultHttpClient( params );
}

private synchronized static void _startConnectionCleanerIfNeeded() {
if ( !cc.isAlive() ) {
cc.start();
}
}

private static void setUserAgent(HttpMessage hm, String useragent) {
Expand Down Expand Up @@ -382,6 +423,30 @@ public static Entity getTemporaryStreamEntity(TemporaryStream ts,String contentT
public static Entity getResourceEntity(Resource res, String contentType) {
return new ResourceHttpEntity(res,contentType);
}


private static class ConnectionCleaner extends Thread {

PoolingClientConnectionManager cm;
int timeout;
ConnectionCleaner ( PoolingClientConnectionManager cm, int timeout ) {
this.cm = cm;
this.timeout = timeout;
setDaemon(true);
}

public synchronized void run () {

while(true) {
cm.closeExpiredConnections();
cm.closeIdleConnections( timeout, TimeUnit.SECONDS);
try {
Thread.sleep( 5000 );
}
catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@

import java.io.IOException;
import java.io.InputStream;
import java.io.PipedInputStream;
import java.io.PipedOutputStream;
import java.net.MalformedURLException;
import java.net.URI;
import java.net.URL;
Expand All @@ -23,13 +25,30 @@ public class HTTPResponse4Impl extends HTTPResponseSupport implements HTTPRespon
HttpResponse rsp;
HttpUriRequest req;
private URL url;
private HttpContext context;
private HttpContext context;
private PipedInputStream is = null;

public HTTPResponse4Impl(URL url,HttpContext context, HttpUriRequest req,HttpResponse rsp) {
this.url=url;
this.context=context;
this.req=req;
this.rsp=rsp;
if( HTTPEngine4Impl.CONNECTION_POOLING_ENABLED ) {
// create thread to push content to a surrogate input stream, so that this class can appropriately close the underlying content inputstream and
// release connections back to the connection pool
HttpEntity e = rsp.getEntity();
if(e != null) {
is = new PipedInputStream();
PipedOutputStream os = null;
try {
os = new PipedOutputStream( is );
new Thread( new HTTPContentPiper( e.getContent(), os ) ).start();
}
catch (IOException e1) {
// is will be null
}
}
}
}

@Override
Expand All @@ -40,11 +59,10 @@ public String getContentAsString() throws IOException {

@Override
public String getContentAsString(String charset) throws IOException {
HttpEntity entity = rsp.getEntity();
InputStream is=null;
if(StringUtil.isEmpty(charset,true))charset=getCharset();
try{
return IOUtil.toString(is=entity.getContent(), charset);
return IOUtil.toString(is=getContentAsStream(), charset);
}
finally {
IOUtil.closeEL(is);
Expand All @@ -55,7 +73,11 @@ public String getContentAsString(String charset) throws IOException {
public InputStream getContentAsStream() throws IOException {
HttpEntity e = rsp.getEntity();
if(e==null) return null;
if( HTTPEngine4Impl.CONNECTION_POOLING_ENABLED ) {
return is;
}
return e.getContent();

}

@Override
Expand All @@ -64,7 +86,7 @@ public byte[] getContentAsByteArray() throws IOException {
InputStream is=null;
if(entity==null) return new byte[0];
try{
return IOUtil.toBytes(is=entity.getContent());
return IOUtil.toBytes(is=getContentAsStream());
}
finally {
IOUtil.closeEL(is);
Expand Down Expand Up @@ -157,4 +179,31 @@ public Header[] getAllHeaders() {
}
return trg;
}

/**
* consumes an http inputstream and closes it
*/
private class HTTPContentPiper implements Runnable {

private InputStream is;
private PipedOutputStream os;

public HTTPContentPiper( InputStream is, PipedOutputStream os ) {
this.os = os;
this.is = is;
}
@Override
public void run() {
try {
IOUtil.copy( is, os,false,false );
}
catch (IOException e) {
e.printStackTrace();
}

IOUtil.closeEL( is );
IOUtil.closeEL( os );
}

}
}
6 changes: 1 addition & 5 deletions railo-java/railo-core/src/railo/runtime/tag/Http4.java
Original file line number Diff line number Diff line change
Expand Up @@ -603,8 +603,7 @@ public int doEndTag() throws PageException {


private void _doEndTag(Struct cfhttp) throws PageException, IOException {
BasicHttpParams params = new BasicHttpParams();
DefaultHttpClient client = HTTPEngine4Impl.createClient(params,redirect?HTTPEngine.MAX_REDIRECT:0);
DefaultHttpClient client = HTTPEngine4Impl.createClient( redirect?HTTPEngine.MAX_REDIRECT:0, (int)this.timeout );


ConfigWeb cw = pageContext.getConfig();
Expand Down Expand Up @@ -902,9 +901,6 @@ else if(type.equals("body")) {
if(!hasHeaderIgnoreCase(req,"User-Agent"))
req.setHeader("User-Agent",this.useragent);

// set timeout
if(this.timeout>0L)HTTPEngine4Impl.setTimeout(params, (int)this.timeout);

// set Username and Password
if(this.username!=null) {
if(this.password==null)this.password="";
Expand Down