Skip to content

Commit 9f59ac6

Browse files
author
Stephane Landelle
committed
Optimize URI.create/String round trips, fix proposal for AsyncHttpClient#139
1 parent d2eed46 commit 9f59ac6

File tree

7 files changed

+108
-97
lines changed

7 files changed

+108
-97
lines changed

src/main/java/com/ning/http/client/Request.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
import java.io.InputStream;
2222
import java.io.OutputStream;
2323
import java.net.InetAddress;
24+
import java.net.URI;
2425
import java.util.Collection;
2526
import java.util.List;
2627

@@ -66,6 +67,10 @@ public static interface EntityWriter {
6667
*/
6768
public String getUrl();
6869

70+
public URI getOriginalURI();
71+
public URI getURI();
72+
public URI getRawURI();
73+
6974
/**
7075
* Return the InetAddress to override
7176
*

src/main/java/com/ning/http/client/RequestBuilderBase.java

Lines changed: 69 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
import static com.ning.http.util.MiscUtil.isNonEmpty;
1919

2020
import com.ning.http.client.Request.EntityWriter;
21+
import com.ning.http.util.AsyncHttpProviderUtils;
2122
import com.ning.http.util.UTF8UrlEncoder;
2223
import org.slf4j.Logger;
2324
import org.slf4j.LoggerFactory;
@@ -38,15 +39,19 @@
3839

3940
/**
4041
* Builder for {@link Request}
41-
*
42+
*
4243
* @param <T>
4344
*/
4445
public abstract class RequestBuilderBase<T extends RequestBuilderBase<T>> {
4546
private final static Logger logger = LoggerFactory.getLogger(RequestBuilderBase.class);
4647

48+
private static final URI DEFAULT_REQUEST_URL = URI.create("http://localhost");
49+
4750
private static final class RequestImpl implements Request {
4851
private String method;
49-
private String url = null;
52+
private URI originalUri = null;
53+
private URI uri = null;
54+
private URI rawUri = null;
5055
private InetAddress address = null;
5156
private InetAddress localAddress = null;
5257
private FluentCaseInsensitiveStringsMap headers = new FluentCaseInsensitiveStringsMap();
@@ -78,9 +83,7 @@ public RequestImpl(boolean useRawUrl) {
7883
public RequestImpl(Request prototype) {
7984
if (prototype != null) {
8085
this.method = prototype.getMethod();
81-
String prototypeUrl = prototype.getUrl();
82-
int pos = prototypeUrl.indexOf("?");
83-
this.url = pos > 0 ? prototypeUrl.substring(0, pos) : prototypeUrl;
86+
this.originalUri = prototype.getOriginalURI();
8487
this.address = prototype.getInetAddress();
8588
this.localAddress = prototype.getLocalAddress();
8689
this.headers = new FluentCaseInsensitiveStringsMap(prototype.getHeaders());
@@ -117,12 +120,6 @@ public String getMethod() {
117120
return method;
118121
}
119122

120-
/* @Override */
121-
122-
public String getUrl() {
123-
return toUrl(true);
124-
}
125-
126123
public InetAddress getInetAddress() {
127124
return address;
128125
}
@@ -131,34 +128,66 @@ public InetAddress getLocalAddress() {
131128
return localAddress;
132129
}
133130

134-
private String toUrl(boolean encode) {
131+
private String removeTrailingSlash(URI uri) {
132+
String uriString = uri.toString();
133+
if (uriString.endsWith("/")) {
134+
return uriString.substring(0, uriString.length() - 1);
135+
} else {
136+
return uriString;
137+
}
138+
}
135139

136-
if (url == null) {
140+
/* @Override */
141+
public String getUrl() {
142+
return removeTrailingSlash(getURI());
143+
}
144+
145+
/* @Override */
146+
public String getRawUrl() {
147+
return removeTrailingSlash(getRawURI());
148+
}
149+
150+
public URI getOriginalURI() {
151+
return originalUri;
152+
}
153+
154+
public URI getURI() {
155+
if (uri == null)
156+
uri = toURI(true);
157+
return uri;
158+
}
159+
160+
public URI getRawURI() {
161+
if (rawUri == null)
162+
rawUri = toURI(false);
163+
return rawUri;
164+
}
165+
166+
private URI toURI(boolean encode) {
167+
168+
if (originalUri == null) {
137169
logger.debug("setUrl hasn't been invoked. Using http://localhost");
138-
url = "http://localhost/";
170+
originalUri = DEFAULT_REQUEST_URL;
139171
}
140172

141-
String uri = url;
142-
if (!uri.startsWith("ws")) {
143-
try {
144-
uri = URI.create(url).toURL().toString();
145-
} catch (Throwable e) {
146-
throw new IllegalArgumentException("Illegal URL: " + url, e);
147-
}
173+
AsyncHttpProviderUtils.validateSupportedScheme(originalUri);
174+
175+
StringBuilder builder = new StringBuilder();
176+
builder.append(originalUri.getScheme()).append("://").append(originalUri.getAuthority());
177+
if (isNonEmpty(originalUri.getRawPath())) {
178+
builder.append(originalUri.getRawPath());
179+
} else {
180+
builder.append("/");
148181
}
149182

150183
if (isNonEmpty(queryParams)) {
151184

152-
StringBuilder builder = new StringBuilder();
153-
if (!url.substring(8).contains("/")) { // no other "/" than http[s]:// -> http://localhost:1234
154-
builder.append("/");
155-
}
156185
builder.append("?");
157186

158-
for (Iterator<Entry<String, List<String>>> i = queryParams.iterator(); i.hasNext(); ) {
187+
for (Iterator<Entry<String, List<String>>> i = queryParams.iterator(); i.hasNext();) {
159188
Map.Entry<String, List<String>> param = i.next();
160189
String name = param.getKey();
161-
for (Iterator<String> j = param.getValue().iterator(); j.hasNext(); ) {
190+
for (Iterator<String> j = param.getValue().iterator(); j.hasNext();) {
162191
String value = j.next();
163192
if (encode) {
164193
UTF8UrlEncoder.appendEncoded(builder, name);
@@ -181,14 +210,9 @@ private String toUrl(boolean encode) {
181210
builder.append('&');
182211
}
183212
}
184-
uri += builder.toString();
185213
}
186-
return uri;
187-
}
188214

189-
/* @Override */
190-
public String getRawUrl() {
191-
return toUrl(false);
215+
return URI.create(builder.toString());
192216
}
193217

194218
/* @Override */
@@ -292,12 +316,12 @@ public String getBodyEncoding() {
292316
}
293317

294318
public ConnectionPoolKeyStrategy getConnectionPoolKeyStrategy() {
295-
return connectionPoolKeyStrategy;
296-
}
297-
319+
return connectionPoolKeyStrategy;
320+
}
321+
298322
@Override
299323
public String toString() {
300-
StringBuilder sb = new StringBuilder(url);
324+
StringBuilder sb = new StringBuilder(getURI().toString());
301325

302326
sb.append("\t");
303327
sb.append(method);
@@ -346,7 +370,7 @@ protected RequestBuilderBase(Class<T> derived, Request prototype) {
346370
}
347371

348372
public T setUrl(String url) {
349-
request.url = buildUrl(url);
373+
request.originalUri = buildURI(url);
350374
return derived.cast(this);
351375
}
352376

@@ -360,7 +384,7 @@ public T setLocalInetAddress(InetAddress address) {
360384
return derived.cast(this);
361385
}
362386

363-
private String buildUrl(String url) {
387+
private URI buildURI(String url) {
364388
URI uri = URI.create(url);
365389
StringBuilder buildedUrl = new StringBuilder();
366390

@@ -380,7 +404,7 @@ private String buildUrl(String url) {
380404
if (url.indexOf("://") == -1) {
381405
String s = buildedUrl.toString();
382406
url = s + url.substring(uri.getScheme().length() + 1);
383-
return buildUrl(url);
407+
return buildURI(url);
384408
} else {
385409
throw new IllegalArgumentException("Invalid url " + uri.toString());
386410
}
@@ -395,7 +419,7 @@ private String buildUrl(String url) {
395419
addQueryParameter(query, null);
396420
} else {
397421
try {
398-
if (this.useRawUrl) {
422+
if (useRawUrl) {
399423
addQueryParameter(query.substring(0, pos), query.substring(pos + 1));
400424
} else {
401425
addQueryParameter(URLDecoder.decode(query.substring(0, pos), "UTF-8"), URLDecoder.decode(query.substring(pos + 1), "UTF-8"));
@@ -406,10 +430,9 @@ private String buildUrl(String url) {
406430
}
407431
}
408432
}
409-
return buildedUrl.toString();
433+
return uri;
410434
}
411435

412-
413436
public T setVirtualHost(String virtualHost) {
414437
request.virtualHost = virtualHost;
415438
return derived.cast(this);
@@ -612,8 +635,8 @@ public T setBodyEncoding(String charset) {
612635
}
613636

614637
public T setConnectionPoolKeyStrategy(ConnectionPoolKeyStrategy connectionPoolKeyStrategy) {
615-
request.connectionPoolKeyStrategy = connectionPoolKeyStrategy;
616-
return derived.cast(this);
638+
request.connectionPoolKeyStrategy = connectionPoolKeyStrategy;
639+
return derived.cast(this);
617640
}
618641

619642
public Request build() {
@@ -633,13 +656,7 @@ public Request build() {
633656
}
634657

635658
private boolean allowBody(String method) {
636-
if (method.equalsIgnoreCase("GET") || method.equalsIgnoreCase("OPTIONS")
637-
&& method.equalsIgnoreCase("TRACE")
638-
&& method.equalsIgnoreCase("HEAD")) {
639-
return false;
640-
} else {
641-
return true;
642-
}
659+
return !(method.equalsIgnoreCase("GET") || method.equalsIgnoreCase("OPTIONS") || method.equalsIgnoreCase("TRACE") || method.equalsIgnoreCase("HEAD"));
643660
}
644661

645662
public T addOrReplaceCookie(Cookie cookie) {

src/main/java/com/ning/http/client/providers/grizzly/GrizzlyAsyncHttpProvider.java

Lines changed: 12 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -846,7 +846,7 @@ private boolean sendAsGrizzlyRequest(final Request request,
846846
httpCtx.isWSRequest = true;
847847
convertToUpgradeRequest(httpCtx);
848848
}
849-
final URI uri = AsyncHttpProviderUtils.createUri(httpCtx.requestUrl);
849+
final URI uri = httpCtx.request.getURI();
850850
final HttpRequestPacket.Builder builder = HttpRequestPacket.builder();
851851
boolean secure = "https".equals(uri.getScheme());
852852
builder.method(request.getMethod());
@@ -1209,7 +1209,7 @@ protected void onInitialLineParsed(HttpHeader httpHeader,
12091209
}
12101210
final GrizzlyResponseStatus responseStatus =
12111211
new GrizzlyResponseStatus((HttpResponsePacket) httpHeader,
1212-
getURI(context.requestUrl),
1212+
context.request.getURI(),
12131213
provider);
12141214
context.responseStatus = responseStatus;
12151215
if (context.statusHandler != null) {
@@ -1457,14 +1457,6 @@ private static HttpTransactionContext cleanup(final FilterChainContext ctx,
14571457

14581458
}
14591459

1460-
1461-
private static URI getURI(String url) {
1462-
1463-
return AsyncHttpProviderUtils.createUri(url);
1464-
1465-
}
1466-
1467-
14681460
private static boolean redirectCountExceeded(final HttpTransactionContext context) {
14691461

14701462
return (context.redirectCount.get() > context.maxRedirectCount);
@@ -1521,7 +1513,7 @@ public boolean handleStatus(final HttpResponsePacket responsePacket,
15211513
final Request req = httpTransactionContext.request;
15221514
realm = new Realm.RealmBuilder().clone(realm)
15231515
.setScheme(realm.getAuthScheme())
1524-
.setUri(URI.create(httpTransactionContext.requestUrl).getPath())
1516+
.setUri(httpTransactionContext.request.getURI().getPath())
15251517
.setMethodName(req.getMethod())
15261518
.setUsePreemptiveAuth(true)
15271519
.parseWWWAuthenticateHeader(auth)
@@ -1600,9 +1592,9 @@ public boolean handleStatus(final HttpResponsePacket responsePacket,
16001592

16011593
URI orig;
16021594
if (httpTransactionContext.lastRedirectURI == null) {
1603-
orig = AsyncHttpProviderUtils.createUri(httpTransactionContext.requestUrl);
1595+
orig = httpTransactionContext.request.getURI();
16041596
} else {
1605-
orig = AsyncHttpProviderUtils.getRedirectUri(AsyncHttpProviderUtils.createUri(httpTransactionContext.requestUrl),
1597+
orig = AsyncHttpProviderUtils.getRedirectUri(httpTransactionContext.request.getURI(),
16061598
httpTransactionContext.lastRedirectURI);
16071599
}
16081600
httpTransactionContext.lastRedirectURI = redirectURL;
@@ -2320,13 +2312,12 @@ void doAsyncTrackedConnection(final Request request,
23202312
final GrizzlyResponseFuture requestFuture,
23212313
final CompletionHandler<Connection> connectHandler)
23222314
throws IOException, ExecutionException, InterruptedException {
2323-
final String url = request.getUrl();
23242315
Connection c = pool.poll(getPoolKey(request));
23252316
if (c == null) {
23262317
if (!connectionMonitor.acquire()) {
23272318
throw new IOException("Max connections exceeded");
23282319
}
2329-
doAsyncConnect(url, request, requestFuture, connectHandler);
2320+
doAsyncConnect(request, requestFuture, connectHandler);
23302321
} else {
23312322
provider.touchConnection(c, request);
23322323
connectHandler.completed(c);
@@ -2338,25 +2329,23 @@ Connection obtainConnection(final Request request,
23382329
final GrizzlyResponseFuture requestFuture)
23392330
throws IOException, ExecutionException, InterruptedException, TimeoutException {
23402331

2341-
final Connection c = (obtainConnection0(request.getUrl(),
2342-
request,
2332+
final Connection c = (obtainConnection0(request,
23432333
requestFuture));
23442334
DO_NOT_CACHE.set(c, Boolean.TRUE);
23452335
return c;
23462336

23472337
}
23482338

2349-
void doAsyncConnect(final String url,
2350-
final Request request,
2339+
void doAsyncConnect(final Request request,
23512340
final GrizzlyResponseFuture requestFuture,
23522341
final CompletionHandler<Connection> connectHandler)
23532342
throws IOException, ExecutionException, InterruptedException {
23542343

2355-
final URI uri = AsyncHttpProviderUtils.createUri(url);
23562344
ProxyServer proxy = getProxyServer(request);
23572345
if (ProxyUtils.avoidProxy(proxy, request)) {
23582346
proxy = null;
23592347
}
2348+
final URI uri = request.getURI();
23602349
String host = ((proxy != null) ? proxy.getHost() : uri.getHost());
23612350
int port = ((proxy != null) ? proxy.getPort() : uri.getPort());
23622351
if(request.getLocalAddress()!=null) {
@@ -2369,12 +2358,11 @@ void doAsyncConnect(final String url,
23692358

23702359
}
23712360

2372-
private Connection obtainConnection0(final String url,
2373-
final Request request,
2361+
private Connection obtainConnection0(final Request request,
23742362
final GrizzlyResponseFuture requestFuture)
23752363
throws IOException, ExecutionException, InterruptedException, TimeoutException {
23762364

2377-
final URI uri = AsyncHttpProviderUtils.createUri(url);
2365+
final URI uri = request.getURI();
23782366
ProxyServer proxy = getProxyServer(request);
23792367
if (ProxyUtils.avoidProxy(proxy, request)) {
23802368
proxy = null;
@@ -2471,7 +2459,7 @@ public void updated(Connection result) {
24712459

24722460
private static String getPoolKey(final Request request) {
24732461
final ConnectionPoolKeyStrategy keyStrategy = request.getConnectionPoolKeyStrategy();
2474-
return keyStrategy.getKey(AsyncHttpProviderUtils.createUri(AsyncHttpProviderUtils.getBaseUrl(request.getUrl())));
2462+
return keyStrategy.getKey(request.getURI());
24752463
}
24762464

24772465
// ------------------------------------------------------ Nested Classes

0 commit comments

Comments
 (0)