Skip to content

Commit 3198a10

Browse files
author
Stephane Landelle
committed
Pool StringBuilders, close AsyncHttpClient#777
1 parent 07a2d75 commit 3198a10

File tree

10 files changed

+87
-44
lines changed

10 files changed

+87
-44
lines changed

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

Lines changed: 28 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
import static java.nio.charset.StandardCharsets.UTF_8;
2222

2323
import com.ning.http.client.uri.Uri;
24+
import com.ning.http.util.StringUtils;
2425

2526
import java.io.UnsupportedEncodingException;
2627
import java.nio.charset.Charset;
@@ -560,7 +561,9 @@ private void newResponse() throws UnsupportedEncodingException {
560561
} catch (NoSuchAlgorithmException e) {
561562
throw new SecurityException(e);
562563
}
563-
md.update(new StringBuilder(principal)
564+
565+
StringBuilder sb = StringUtils.stringBuilder();
566+
md.update(sb.append(principal)
564567
.append(":")
565568
.append(realmName)
566569
.append(":")
@@ -571,50 +574,49 @@ private void newResponse() throws UnsupportedEncodingException {
571574
md.reset();
572575

573576
//HA2 if qop is auth-int is methodName:url:md5(entityBody)
574-
md.update(new StringBuilder(methodName)
577+
578+
// BEWARE: compute first as it used the cached StringBuilder
579+
String url = uri.toUrl();
580+
581+
sb.setLength(0);
582+
md.update(sb.append(methodName)
575583
.append(':')
576-
.append(uri).toString().getBytes(ISO_8859_1));
584+
.append(url).toString().getBytes(ISO_8859_1));
577585
byte[] ha2 = md.digest();
578586

579-
if(qop==null || qop.equals("")) {
580-
md.update(new StringBuilder(toBase16(ha1))
581-
.append(':')
582-
.append(nonce)
583-
.append(':')
584-
.append(toBase16(ha2)).toString().getBytes(ISO_8859_1));
585-
586-
} else {
587-
//qop ="auth" or "auth-int"
588-
md.update(new StringBuilder(toBase16(ha1))
589-
.append(':')
590-
.append(nonce)
591-
.append(':')
592-
.append(NC)
593-
.append(':')
594-
.append(cnonce)
595-
.append(':')
596-
.append(qop)
597-
.append(':')
598-
.append(toBase16(ha2)).toString().getBytes(ISO_8859_1));
587+
sb.setLength(0);
588+
appendBase16(sb, ha1);
589+
sb.append(':').append(nonce).append(':');
590+
591+
if (isNonEmpty(qop)) {
592+
//qop ="auth" or "auth-int"
593+
sb.append(NC)//
594+
.append(':')//
595+
.append(cnonce)//
596+
.append(':')//
597+
.append(qop)//
598+
.append(':');
599599
}
600600

601+
appendBase16(sb, ha2);
602+
md.update(sb.toString().getBytes(ISO_8859_1));
603+
601604
byte[] digest = md.digest();
602605

603606
response = toHexString(digest);
604607
}
605608

606609
private static String toHexString(byte[] data) {
607-
StringBuilder buffer = new StringBuilder();
610+
StringBuilder buffer = StringUtils.stringBuilder();
608611
for (int i = 0; i < data.length; i++) {
609612
buffer.append(Integer.toHexString((data[i] & 0xf0) >>> 4));
610613
buffer.append(Integer.toHexString(data[i] & 0x0f));
611614
}
612615
return buffer.toString();
613616
}
614617

615-
private static String toBase16(byte[] bytes) {
618+
private static void appendBase16(StringBuilder buf, byte[] bytes) {
616619
int base = 16;
617-
StringBuilder buf = new StringBuilder();
618620
for (byte b : bytes) {
619621
int bi = 0xff & b;
620622
int c = '0' + (bi / base) % base;
@@ -626,7 +628,6 @@ private static String toBase16(byte[] bytes) {
626628
c = 'a' + (c - '0' - 10);
627629
buf.append((char) c);
628630
}
629-
return buf.toString();
630631
}
631632

632633
/**
@@ -668,5 +669,4 @@ public Realm build() {
668669
targetProxy);
669670
}
670671
}
671-
672672
}

src/main/java/com/ning/http/client/cookie/CookieDecoder.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414

1515
import com.ning.http.client.date.CalendarTimeConverter;
1616
import com.ning.http.client.date.TimeConverter;
17+
import com.ning.http.util.StringUtils;
1718

1819
public class CookieDecoder {
1920

@@ -92,7 +93,7 @@ public static Cookie decode(String header, TimeConverter timeConverter) {
9293
char c = header.charAt(i);
9394
if (c == '"' || c == '\'') {
9495
// NAME="VALUE" or NAME='VALUE'
95-
StringBuilder newValueBuf = new StringBuilder(header.length() - i);
96+
StringBuilder newValueBuf = StringUtils.stringBuilder();
9697

9798
int rawValueStart = i;
9899
int rawValueEnd = i;

src/main/java/com/ning/http/client/cookie/CookieEncoder.java

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,8 @@
1212
*/
1313
package com.ning.http.client.cookie;
1414

15+
import com.ning.http.util.StringUtils;
16+
1517
import java.util.Collection;
1618

1719
public final class CookieEncoder {
@@ -20,7 +22,7 @@ private CookieEncoder() {
2022
}
2123

2224
public static String encode(Collection<Cookie> cookies) {
23-
StringBuilder sb = new StringBuilder();
25+
StringBuilder sb = StringUtils.stringBuilder();
2426

2527
for (Cookie cookie : cookies) {
2628
add(sb, cookie.getName(), cookie.getRawValue());

src/main/java/com/ning/http/client/multipart/MultipartUtils.java

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,12 +16,13 @@
1616
package com.ning.http.client.multipart;
1717

1818
import static java.nio.charset.StandardCharsets.*;
19-
2019
import static com.ning.http.client.multipart.Part.CRLF_BYTES;
2120
import static com.ning.http.client.multipart.Part.EXTRA_BYTES;
2221
import static com.ning.http.util.MiscUtils.isNonEmpty;
2322

2423
import com.ning.http.client.FluentCaseInsensitiveStringsMap;
24+
import com.ning.http.util.StringUtils;
25+
2526
import org.slf4j.Logger;
2627
import org.slf4j.LoggerFactory;
2728

@@ -101,9 +102,9 @@ private static byte[] generateMultipartBoundary() {
101102
}
102103

103104
private static String computeContentType(String base, byte[] multipartBoundary) {
104-
StringBuilder buffer = new StringBuilder(base);
105+
StringBuilder buffer = StringUtils.stringBuilder().append(base);
105106
if (!base.endsWith(";"))
106-
buffer.append(";");
107+
buffer.append(';');
107108
return buffer.append(" boundary=").append(new String(multipartBoundary, US_ASCII)).toString();
108109
}
109110

src/main/java/com/ning/http/client/oauth/OAuthSignatureCalculator.java

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
import com.ning.http.client.SignatureCalculator;
2626
import com.ning.http.client.uri.Uri;
2727
import com.ning.http.util.Base64;
28+
import com.ning.http.util.StringUtils;
2829
import com.ning.http.util.UTF8UrlEncoder;
2930

3031
import java.util.ArrayList;
@@ -95,7 +96,7 @@ public void calculateAndAddSignature(Request request, RequestBuilderBase<?> requ
9596
*/
9697
public String calculateSignature(String method, Uri uri, long oauthTimestamp, String nonce,
9798
List<Param> formParams, List<Param> queryParams) {
98-
StringBuilder signedText = new StringBuilder(100);
99+
StringBuilder signedText = StringUtils.stringBuilder();
99100
signedText.append(method); // POST / GET etc (nothing to URL encode)
100101
signedText.append('&');
101102

@@ -162,7 +163,7 @@ else if (scheme.equals("https"))
162163
* Method used for constructing
163164
*/
164165
public String constructAuthHeader(String signature, String nonce, long oauthTimestamp) {
165-
StringBuilder sb = new StringBuilder(200);
166+
StringBuilder sb = StringUtils.stringBuilder();
166167
sb.append("OAuth ");
167168
sb.append(KEY_OAUTH_CONSUMER_KEY).append("=\"").append(consumerAuth.getKey()).append("\", ");
168169
if (userAuth.getKey() != null) {

src/main/java/com/ning/http/client/providers/netty/request/NettyRequestFactory.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@
5353
import com.ning.http.client.providers.netty.request.body.NettyMultipartBody;
5454
import com.ning.http.client.providers.netty.spnego.SpnegoEngine;
5555
import com.ning.http.client.uri.Uri;
56+
import com.ning.http.util.StringUtils;
5657
import com.ning.http.util.UTF8UrlEncoder;
5758

5859
import java.io.IOException;
@@ -188,7 +189,7 @@ private String systematicProxyAuthorizationHeader(Request request, ProxyServer p
188189

189190
private byte[] computeBodyFromParams(List<Param> params, Charset bodyCharset) {
190191

191-
StringBuilder sb = new StringBuilder();
192+
StringBuilder sb = StringUtils.stringBuilder();
192193
for (Param param : params) {
193194
UTF8UrlEncoder.appendEncoded(sb, param.getName());
194195
sb.append('=');

src/main/java/com/ning/http/client/uri/Uri.java

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
package com.ning.http.client.uri;
1515

1616
import com.ning.http.util.MiscUtils;
17+
import com.ning.http.util.StringUtils;
1718

1819
import java.net.URI;
1920
import java.net.URISyntaxException;
@@ -94,7 +95,7 @@ public URI toJavaNetURI() throws URISyntaxException {
9495

9596
public String toUrl() {
9697
if (url == null) {
97-
StringBuilder sb = new StringBuilder();
98+
StringBuilder sb = StringUtils.stringBuilder();
9899
sb.append(scheme).append("://");
99100
if (userInfo != null)
100101
sb.append(userInfo).append('@');
@@ -112,7 +113,7 @@ public String toUrl() {
112113
}
113114

114115
public String toRelativeUrl() {
115-
StringBuilder sb = new StringBuilder();
116+
StringBuilder sb = StringUtils.stringBuilder();
116117
if (MiscUtils.isNonEmpty(path))
117118
sb.append(path);
118119
else

src/main/java/com/ning/http/util/AsyncHttpProviderUtils.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -169,7 +169,7 @@ public static boolean followRedirect(AsyncHttpClientConfig config, Request reque
169169
}
170170

171171
public static String formParams2UTF8String(List<Param> params) {
172-
StringBuilder sb = new StringBuilder(params.size() * 15);
172+
StringBuilder sb = StringUtils.stringBuilder();
173173
for (Param param : params) {
174174
UTF8UrlEncoder.appendEncoded(sb, param.getName());
175175
sb.append("=");

src/main/java/com/ning/http/util/QueryComputer.java

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ private final void encodeAndAppendQuery(final StringBuilder sb, final String que
5555

5656
protected final String withQueryWithParams(final String query, final List<Param> queryParams) {
5757
// concatenate encoded query + encoded query params
58-
StringBuilder sb = new StringBuilder(query.length() + queryParams.size() * 16);
58+
StringBuilder sb = StringUtils.stringBuilder();
5959
encodeAndAppendQuery(sb, query);
6060
encodeAndAppendQueryParams(sb, queryParams);
6161
sb.setLength(sb.length() - 1);
@@ -64,15 +64,15 @@ protected final String withQueryWithParams(final String query, final List<Param>
6464

6565
protected final String withQueryWithoutParams(final String query) {
6666
// encode query
67-
StringBuilder sb = new StringBuilder(query.length() + 6);
67+
StringBuilder sb = StringUtils.stringBuilder();
6868
encodeAndAppendQuery(sb, query);
6969
sb.setLength(sb.length() - 1);
7070
return sb.toString();
7171
}
7272

7373
protected final String withoutQueryWithParams(final List<Param> queryParams) {
7474
// concatenate encoded query params
75-
StringBuilder sb = new StringBuilder(queryParams.size() * 16);
75+
StringBuilder sb = StringUtils.stringBuilder();
7676
encodeAndAppendQueryParams(sb, queryParams);
7777
sb.setLength(sb.length() - 1);
7878
return sb.toString();
@@ -95,7 +95,7 @@ private final void appendRawQueryParams(final StringBuilder sb, final List<Param
9595

9696
protected final String withQueryWithParams(final String query, final List<Param> queryParams) {
9797
// concatenate raw query + raw query params
98-
StringBuilder sb = new StringBuilder(query.length() + queryParams.size() * 16);
98+
StringBuilder sb = StringUtils.stringBuilder();
9999
sb.append(query);
100100
appendRawQueryParams(sb, queryParams);
101101
sb.setLength(sb.length() - 1);
@@ -109,7 +109,7 @@ protected final String withQueryWithoutParams(final String query) {
109109

110110
protected final String withoutQueryWithParams(final List<Param> queryParams) {
111111
// concatenate raw queryParams
112-
StringBuilder sb = new StringBuilder(queryParams.size() * 16);
112+
StringBuilder sb = StringUtils.stringBuilder();
113113
appendRawQueryParams(sb, queryParams);
114114
sb.setLength(sb.length() - 1);
115115
return sb.toString();
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
/*
2+
* Copyright (c) 2014 AsyncHttpClient Project. All rights reserved.
3+
*
4+
* This program is licensed to you under the Apache License Version 2.0,
5+
* and you may not use this file except in compliance with the Apache License Version 2.0.
6+
* You may obtain a copy of the Apache License Version 2.0 at http://www.apache.org/licenses/LICENSE-2.0.
7+
*
8+
* Unless required by applicable law or agreed to in writing,
9+
* software distributed under the Apache License Version 2.0 is distributed on an
10+
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11+
* See the Apache License Version 2.0 for the specific language governing permissions and limitations there under.
12+
*/
13+
package com.ning.http.util;
14+
15+
public final class StringUtils {
16+
17+
private static final ThreadLocal<StringBuilder> STRING_BUILDERS = new ThreadLocal<StringBuilder>() {
18+
protected StringBuilder initialValue() {
19+
return new StringBuilder(512);
20+
};
21+
};
22+
23+
/**
24+
* BEWARE: MUSN'T APPEND TO ITSELF!
25+
* @return a pooled StringBuilder
26+
*/
27+
public static StringBuilder stringBuilder() {
28+
StringBuilder sb = STRING_BUILDERS.get();
29+
sb.setLength(0);
30+
return sb;
31+
}
32+
33+
private StringUtils() {
34+
// unused
35+
}
36+
}

0 commit comments

Comments
 (0)