Skip to content

Commit 6f1fb81

Browse files
authored
Enabled NullAway for util package (AsyncHttpClient#1885)
* Added new failing test when there are 2 duplicating form parameters but one if them has null as a value * Fixed potentian NPE when form params include two params with the same name and one of the param has null as a value * Enabled NullAway for util package
1 parent e504fa5 commit 6f1fb81

File tree

9 files changed

+51
-31
lines changed

9 files changed

+51
-31
lines changed

client/src/main/java/org/asynchttpclient/proxy/ProxyServer.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -147,7 +147,7 @@ public Builder setSecuredPort(int securedPort) {
147147
return this;
148148
}
149149

150-
public Builder setRealm(Realm realm) {
150+
public Builder setRealm(@Nullable Realm realm) {
151151
this.realm = realm;
152152
return this;
153153
}

client/src/main/java/org/asynchttpclient/util/Assertions.java

+7-2
Original file line numberDiff line numberDiff line change
@@ -15,20 +15,25 @@
1515
*/
1616
package org.asynchttpclient.util;
1717

18+
import org.jetbrains.annotations.Contract;
19+
import org.jetbrains.annotations.Nullable;
20+
1821
public final class Assertions {
1922

2023
private Assertions() {
2124
}
2225

23-
public static <T> T assertNotNull(T value, String name) {
26+
@Contract(value = "null, _ -> fail", pure = true)
27+
public static <T> T assertNotNull(@Nullable T value, String name) {
2428
if (value == null) {
2529
throw new NullPointerException(name);
2630
}
2731
return value;
2832

2933
}
3034

31-
public static String assertNotEmpty(String value, String name) {
35+
@Contract(value = "null, _ -> fail", pure = true)
36+
public static String assertNotEmpty(@Nullable String value, String name) {
3237
assertNotNull(value, name);
3338
if (value.length() == 0) {
3439
throw new IllegalArgumentException("empty " + name);

client/src/main/java/org/asynchttpclient/util/AuthenticatorUtils.java

+18-14
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
import org.asynchttpclient.spnego.SpnegoEngine;
2020
import org.asynchttpclient.spnego.SpnegoEngineException;
2121
import org.asynchttpclient.uri.Uri;
22+
import org.jetbrains.annotations.Nullable;
2223

2324
import java.nio.charset.Charset;
2425
import java.nio.charset.StandardCharsets;
@@ -38,7 +39,7 @@ private AuthenticatorUtils() {
3839
// Prevent outside initialization
3940
}
4041

41-
public static String getHeaderWithPrefix(List<String> authenticateHeaders, String prefix) {
42+
public static @Nullable String getHeaderWithPrefix(@Nullable List<String> authenticateHeaders, String prefix) {
4243
if (authenticateHeaders != null) {
4344
for (String authenticateHeader : authenticateHeaders) {
4445
if (authenticateHeader.regionMatches(true, 0, prefix, 0, prefix.length())) {
@@ -50,11 +51,11 @@ public static String getHeaderWithPrefix(List<String> authenticateHeaders, Strin
5051
return null;
5152
}
5253

53-
private static String computeBasicAuthentication(Realm realm) {
54+
private static @Nullable String computeBasicAuthentication(@Nullable Realm realm) {
5455
return realm != null ? computeBasicAuthentication(realm.getPrincipal(), realm.getPassword(), realm.getCharset()) : null;
5556
}
5657

57-
private static String computeBasicAuthentication(String principal, String password, Charset charset) {
58+
private static String computeBasicAuthentication(@Nullable String principal, @Nullable String password, Charset charset) {
5859
String s = principal + ':' + password;
5960
return "Basic " + Base64.getEncoder().encodeToString(s.getBytes(charset));
6061
}
@@ -68,9 +69,9 @@ public static String computeRealmURI(Uri uri, boolean useAbsoluteURI, boolean om
6869
}
6970
}
7071

71-
private static String computeDigestAuthentication(Realm realm) {
72+
private static String computeDigestAuthentication(Realm realm, Uri uri) {
7273

73-
String realmUri = computeRealmURI(realm.getUri(), realm.isUseAbsoluteURI(), realm.isOmitQuery());
74+
String realmUri = computeRealmURI(uri, realm.isUseAbsoluteURI(), realm.isOmitQuery());
7475

7576
StringBuilder builder = new StringBuilder().append("Digest ");
7677
append(builder, "username", realm.getPrincipal(), true);
@@ -99,7 +100,7 @@ private static String computeDigestAuthentication(Realm realm) {
99100
return new String(StringUtils.charSequence2Bytes(builder, ISO_8859_1), StandardCharsets.UTF_8);
100101
}
101102

102-
private static void append(StringBuilder builder, String name, String value, boolean quoted) {
103+
private static void append(StringBuilder builder, String name, @Nullable String value, boolean quoted) {
103104
builder.append(name).append('=');
104105
if (quoted) {
105106
builder.append('"').append(value).append('"');
@@ -109,7 +110,7 @@ private static void append(StringBuilder builder, String name, String value, boo
109110
builder.append(", ");
110111
}
111112

112-
public static String perConnectionProxyAuthorizationHeader(Request request, Realm proxyRealm) {
113+
public static @Nullable String perConnectionProxyAuthorizationHeader(Request request, @Nullable Realm proxyRealm) {
113114
String proxyAuthorization = null;
114115
if (proxyRealm != null && proxyRealm.isUsePreemptiveAuth()) {
115116
switch (proxyRealm.getScheme()) {
@@ -130,7 +131,7 @@ public static String perConnectionProxyAuthorizationHeader(Request request, Real
130131
return proxyAuthorization;
131132
}
132133

133-
public static String perRequestProxyAuthorizationHeader(Request request, Realm proxyRealm) {
134+
public static @Nullable String perRequestProxyAuthorizationHeader(Request request, @Nullable Realm proxyRealm) {
134135
String proxyAuthorization = null;
135136
if (proxyRealm != null && proxyRealm.isUsePreemptiveAuth()) {
136137

@@ -141,11 +142,12 @@ public static String perRequestProxyAuthorizationHeader(Request request, Realm p
141142
case DIGEST:
142143
if (isNonEmpty(proxyRealm.getNonce())) {
143144
// update realm with request information
145+
final Uri uri = request.getUri();
144146
proxyRealm = realm(proxyRealm)
145-
.setUri(request.getUri())
147+
.setUri(uri)
146148
.setMethodName(request.getMethod())
147149
.build();
148-
proxyAuthorization = computeDigestAuthentication(proxyRealm);
150+
proxyAuthorization = computeDigestAuthentication(proxyRealm, uri);
149151
}
150152
break;
151153
case NTLM:
@@ -162,7 +164,8 @@ public static String perRequestProxyAuthorizationHeader(Request request, Realm p
162164
return proxyAuthorization;
163165
}
164166

165-
public static String perConnectionAuthorizationHeader(Request request, ProxyServer proxyServer, Realm realm) {
167+
public static @Nullable String perConnectionAuthorizationHeader(Request request, @Nullable ProxyServer proxyServer,
168+
@Nullable Realm realm) {
166169
String authorizationHeader = null;
167170

168171
if (realm != null && realm.isUsePreemptiveAuth()) {
@@ -203,7 +206,7 @@ public static String perConnectionAuthorizationHeader(Request request, ProxyServ
203206
return authorizationHeader;
204207
}
205208

206-
public static String perRequestAuthorizationHeader(Request request, Realm realm) {
209+
public static @Nullable String perRequestAuthorizationHeader(Request request, @Nullable Realm realm) {
207210
String authorizationHeader = null;
208211
if (realm != null && realm.isUsePreemptiveAuth()) {
209212

@@ -214,11 +217,12 @@ public static String perRequestAuthorizationHeader(Request request, Realm realm)
214217
case DIGEST:
215218
if (isNonEmpty(realm.getNonce())) {
216219
// update realm with request information
220+
final Uri uri = request.getUri();
217221
realm = realm(realm)
218-
.setUri(request.getUri())
222+
.setUri(uri)
219223
.setMethodName(request.getMethod())
220224
.build();
221-
authorizationHeader = computeDigestAuthentication(realm);
225+
authorizationHeader = computeDigestAuthentication(realm, uri);
222226
}
223227
break;
224228
case NTLM:

client/src/main/java/org/asynchttpclient/util/HttpUtils.java

+5-4
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
import org.asynchttpclient.Param;
2020
import org.asynchttpclient.Request;
2121
import org.asynchttpclient.uri.Uri;
22+
import org.jetbrains.annotations.Nullable;
2223

2324
import java.net.URLEncoder;
2425
import java.nio.ByteBuffer;
@@ -59,16 +60,16 @@ public static String originHeader(Uri uri) {
5960
return sb.toString();
6061
}
6162

62-
public static Charset extractContentTypeCharsetAttribute(String contentType) {
63+
public static @Nullable Charset extractContentTypeCharsetAttribute(String contentType) {
6364
String charsetName = extractContentTypeAttribute(contentType, CONTENT_TYPE_CHARSET_ATTRIBUTE);
6465
return charsetName != null ? Charset.forName(charsetName) : null;
6566
}
6667

67-
public static String extractContentTypeBoundaryAttribute(String contentType) {
68+
public static @Nullable String extractContentTypeBoundaryAttribute(String contentType) {
6869
return extractContentTypeAttribute(contentType, CONTENT_TYPE_BOUNDARY_ATTRIBUTE);
6970
}
7071

71-
private static String extractContentTypeAttribute(String contentType, String attribute) {
72+
private static @Nullable String extractContentTypeAttribute(@Nullable String contentType, String attribute) {
7273
if (contentType == null) {
7374
return null;
7475
}
@@ -147,7 +148,7 @@ private static StringBuilder urlEncodeFormParams0(List<Param> params, Charset ch
147148
return sb;
148149
}
149150

150-
private static void encodeAndAppendFormParam(StringBuilder sb, String name, String value, Charset charset) {
151+
private static void encodeAndAppendFormParam(StringBuilder sb, String name, @Nullable String value, Charset charset) {
151152
encodeAndAppendFormField(sb, name, charset);
152153
if (value != null) {
153154
sb.append('=');

client/src/main/java/org/asynchttpclient/util/MiscUtils.java

+4
Original file line numberDiff line numberDiff line change
@@ -37,18 +37,22 @@ public static boolean isEmpty(@Nullable String string) {
3737
return string == null || string.isEmpty();
3838
}
3939

40+
@Contract(value = "null -> false", pure = true)
4041
public static boolean isNonEmpty(@Nullable Object[] array) {
4142
return array != null && array.length != 0;
4243
}
4344

45+
@Contract(value = "null -> false", pure = true)
4446
public static boolean isNonEmpty(byte @Nullable [] array) {
4547
return array != null && array.length != 0;
4648
}
4749

50+
@Contract(value = "null -> false")
4851
public static boolean isNonEmpty(@Nullable Collection<?> collection) {
4952
return collection != null && !collection.isEmpty();
5053
}
5154

55+
@Contract(value = "null -> false")
5256
public static boolean isNonEmpty(@Nullable Map<?, ?> map) {
5357
return map != null && !map.isEmpty();
5458
}

client/src/main/java/org/asynchttpclient/util/ProxyUtils.java

+2-1
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
import org.asynchttpclient.Request;
1818
import org.asynchttpclient.proxy.ProxyServer;
1919
import org.asynchttpclient.proxy.ProxyServerSelector;
20+
import org.jetbrains.annotations.Nullable;
2021
import org.slf4j.Logger;
2122
import org.slf4j.LoggerFactory;
2223

@@ -80,7 +81,7 @@ private ProxyUtils() {
8081
* @param request the request
8182
* @return the proxy server to be used for this request (can be null)
8283
*/
83-
public static ProxyServer getProxyServer(AsyncHttpClientConfig config, Request request) {
84+
public static @Nullable ProxyServer getProxyServer(AsyncHttpClientConfig config, Request request) {
8485
ProxyServer proxyServer = request.getProxyServer();
8586
if (proxyServer == null) {
8687
ProxyServerSelector selector = config.getProxyServerSelector();

client/src/main/java/org/asynchttpclient/util/UriEncoder.java

+7-6
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717

1818
import org.asynchttpclient.Param;
1919
import org.asynchttpclient.uri.Uri;
20+
import org.jetbrains.annotations.Nullable;
2021

2122
import java.util.List;
2223

@@ -31,7 +32,7 @@ public String encodePath(String path) {
3132
return Utf8UrlEncoder.encodePath(path);
3233
}
3334

34-
private void encodeAndAppendQueryParam(final StringBuilder sb, final CharSequence name, final CharSequence value) {
35+
private void encodeAndAppendQueryParam(final StringBuilder sb, final CharSequence name, final @Nullable CharSequence value) {
3536
Utf8UrlEncoder.encodeAndAppendQueryElement(sb, name);
3637
if (value != null) {
3738
sb.append('=');
@@ -81,7 +82,7 @@ public String encodePath(String path) {
8182
return path;
8283
}
8384

84-
private void appendRawQueryParam(StringBuilder sb, String name, String value) {
85+
private void appendRawQueryParam(StringBuilder sb, String name, @Nullable String value) {
8586
sb.append(name);
8687
if (value != null) {
8788
sb.append('=').append(value);
@@ -131,15 +132,15 @@ public static UriEncoder uriEncoder(boolean disableUrlEncoding) {
131132

132133
protected abstract String withoutQueryWithParams(List<Param> queryParams);
133134

134-
private String withQuery(final String query, final List<Param> queryParams) {
135+
private String withQuery(final String query, final @Nullable List<Param> queryParams) {
135136
return isNonEmpty(queryParams) ? withQueryWithParams(query, queryParams) : withQueryWithoutParams(query);
136137
}
137138

138-
private String withoutQuery(final List<Param> queryParams) {
139+
private @Nullable String withoutQuery(final @Nullable List<Param> queryParams) {
139140
return isNonEmpty(queryParams) ? withoutQueryWithParams(queryParams) : null;
140141
}
141142

142-
public Uri encode(Uri uri, List<Param> queryParams) {
143+
public Uri encode(Uri uri, @Nullable List<Param> queryParams) {
143144
String newPath = encodePath(uri.getPath());
144145
String newQuery = encodeQuery(uri.getQuery(), queryParams);
145146
return new Uri(uri.getScheme(),
@@ -153,7 +154,7 @@ public Uri encode(Uri uri, List<Param> queryParams) {
153154

154155
protected abstract String encodePath(String path);
155156

156-
private String encodeQuery(final String query, final List<Param> queryParams) {
157+
private @Nullable String encodeQuery(final @Nullable String query, final @Nullable List<Param> queryParams) {
157158
return isNonEmpty(query) ? withQuery(query, queryParams) : withoutQuery(queryParams);
158159
}
159160
}

client/src/main/java/org/asynchttpclient/util/Utf8UrlEncoder.java

+6-2
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,9 @@
1515
*/
1616
package org.asynchttpclient.util;
1717

18+
import org.jetbrains.annotations.Contract;
19+
import org.jetbrains.annotations.Nullable;
20+
1821
import java.util.BitSet;
1922

2023
public final class Utf8UrlEncoder {
@@ -144,7 +147,8 @@ public static StringBuilder encodeAndAppendFormElement(StringBuilder sb, CharSeq
144147
return appendEncoded(sb, input, FORM_URL_ENCODED_SAFE_CHARS, true);
145148
}
146149

147-
public static String percentEncodeQueryElement(String input) {
150+
@Contract(value = "!null -> !null")
151+
public static @Nullable String percentEncodeQueryElement(@Nullable String input) {
148152
if (input == null) {
149153
return null;
150154
}
@@ -165,7 +169,7 @@ private static StringBuilder lazyInitStringBuilder(CharSequence input, int first
165169
return sb;
166170
}
167171

168-
private static StringBuilder lazyAppendEncoded(StringBuilder sb, CharSequence input, BitSet dontNeedEncoding, boolean encodeSpaceAsPlus) {
172+
private static @Nullable StringBuilder lazyAppendEncoded(@Nullable StringBuilder sb, CharSequence input, BitSet dontNeedEncoding, boolean encodeSpaceAsPlus) {
169173
int c;
170174
for (int i = 0; i < input.length(); i += Character.charCount(c)) {
171175
c = Character.codePointAt(input, i);

pom.xml

+1-1
Original file line numberDiff line numberDiff line change
@@ -233,7 +233,7 @@
233233
-Xep:NullOptional:ERROR
234234
-XepExcludedPaths:.*/src/test/java/.*
235235
-XepOpt:NullAway:AnnotatedPackages=org.asynchttpclient
236-
-XepOpt:NullAway:UnannotatedSubPackages=org.asynchttpclient.netty,org.asynchttpclient.ntlm,org.asynchttpclient.request,org.asynchttpclient.spnego,org.asynchttpclient.util,org.asynchttpclient.webdav,org.asynchttpclient.ws
236+
-XepOpt:NullAway:UnannotatedSubPackages=org.asynchttpclient.netty,org.asynchttpclient.ntlm,org.asynchttpclient.request,org.asynchttpclient.spnego,org.asynchttpclient.webdav,org.asynchttpclient.ws
237237
-XepOpt:NullAway:AcknowledgeRestrictiveAnnotations=true
238238
-Xep:NullAway:ERROR
239239
</arg>

0 commit comments

Comments
 (0)