Skip to content

Commit 3d9285a

Browse files
committed
Auth challenge parsing code improvement
1 parent 51ce3eb commit 3d9285a

File tree

3 files changed

+83
-51
lines changed

3 files changed

+83
-51
lines changed

httpclient5/src/main/java/org/apache/hc/client5/http/impl/auth/AuthChallengeParser.java

Lines changed: 44 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@
3434
import org.apache.hc.client5.http.auth.ChallengeType;
3535
import org.apache.hc.core5.http.NameValuePair;
3636
import org.apache.hc.core5.http.ParseException;
37+
import org.apache.hc.core5.http.message.BasicHeaderValueParser;
3738
import org.apache.hc.core5.http.message.BasicNameValuePair;
3839
import org.apache.hc.core5.http.message.ParserCursor;
3940
import org.apache.hc.core5.util.TextUtils;
@@ -107,19 +108,52 @@ public List<AuthChallenge> parse(
107108
}
108109
final List<AuthChallenge> challenges = new ArrayList<>(internalChallenges.size());
109110
for (final ChallengeInt internal : internalChallenges) {
110-
final List<NameValuePair> params = internal.params;
111-
String token68 = null;
112-
if (params.size() == 1) {
113-
final NameValuePair param = params.get(0);
114-
if (param.getValue() == null) {
115-
token68 = param.getName();
116-
params.clear();
111+
challenges.add(parseInt(challengeType, internal));
112+
}
113+
return challenges;
114+
}
115+
116+
/**
117+
* Parses the given sequence of characters into a single {@link AuthChallenge}.
118+
*
119+
* @param challengeType the type of challenge (target or proxy).
120+
* @param schemeName the scheme name
121+
* @param buffer the sequence of characters to be parsed.
122+
* @param cursor the parser cursor.
123+
* @return auth challenge.
124+
*
125+
* @since 5.7
126+
*/
127+
public AuthChallenge parse(
128+
final ChallengeType challengeType,
129+
final String schemeName,
130+
final CharSequence buffer,
131+
final ParserCursor cursor) {
132+
final List<NameValuePair> params = new ArrayList<>();
133+
while (!cursor.atEnd()) {
134+
final NameValuePair param = BasicHeaderValueParser.INSTANCE.parseNameValuePair(buffer, cursor);
135+
params.add(param);
136+
if (!cursor.atEnd()) {
137+
final char ch = buffer.charAt(cursor.getPos());
138+
if (ch == ',') {
139+
cursor.updatePos(cursor.getPos() + 1);
117140
}
118141
}
119-
challenges.add(
120-
new AuthChallenge(challengeType, internal.schemeName, token68, !params.isEmpty() ? params : null));
121142
}
122-
return challenges;
143+
return new AuthChallenge(challengeType, schemeName, null, params);
144+
}
145+
146+
AuthChallenge parseInt(final ChallengeType challengeType, final ChallengeInt internal) {
147+
final List<NameValuePair> params = internal.params;
148+
String token68 = null;
149+
if (params.size() == 1) {
150+
final NameValuePair param = params.get(0);
151+
if (param.getValue() == null) {
152+
token68 = param.getName();
153+
params.clear();
154+
}
155+
}
156+
return new AuthChallenge(challengeType, internal.schemeName, token68, !params.isEmpty() ? params : null);
123157
}
124158

125159
ChallengeInt parseChallenge(

httpclient5/src/main/java/org/apache/hc/client5/http/impl/auth/AuthenticationHandler.java

Lines changed: 22 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,6 @@
2828
package org.apache.hc.client5.http.impl.auth;
2929

3030
import java.util.HashMap;
31-
import java.util.Iterator;
3231
import java.util.LinkedList;
3332
import java.util.List;
3433
import java.util.Locale;
@@ -47,7 +46,6 @@
4746
import org.apache.hc.core5.annotation.Contract;
4847
import org.apache.hc.core5.annotation.Internal;
4948
import org.apache.hc.core5.annotation.ThreadingBehavior;
50-
import org.apache.hc.core5.http.FormattedHeader;
5149
import org.apache.hc.core5.http.Header;
5250
import org.apache.hc.core5.http.HttpHeaders;
5351
import org.apache.hc.core5.http.HttpHost;
@@ -56,10 +54,9 @@
5654
import org.apache.hc.core5.http.HttpStatus;
5755
import org.apache.hc.core5.http.ParseException;
5856
import org.apache.hc.core5.http.message.BasicHeader;
59-
import org.apache.hc.core5.http.message.ParserCursor;
57+
import org.apache.hc.core5.http.message.MessageSupport;
6058
import org.apache.hc.core5.http.protocol.HttpContext;
6159
import org.apache.hc.core5.util.Asserts;
62-
import org.apache.hc.core5.util.CharArrayBuffer;
6360
import org.slf4j.Logger;
6461
import org.slf4j.LoggerFactory;
6562

@@ -169,43 +166,27 @@ public Map<String, AuthChallenge> extractChallengeMap(
169166
final HttpResponse response,
170167
final HttpClientContext context) {
171168
final Map<String, AuthChallenge> challengeMap = new HashMap<>();
172-
final Iterator<Header> headerIterator = response.headerIterator(
173-
challengeType == ChallengeType.PROXY ? HttpHeaders.PROXY_AUTHENTICATE : HttpHeaders.WWW_AUTHENTICATE);
174-
while (headerIterator.hasNext()) {
175-
final Header header = headerIterator.next();
176-
final CharArrayBuffer buffer;
177-
final int pos;
178-
if (header instanceof FormattedHeader) {
179-
buffer = ((FormattedHeader) header).getBuffer();
180-
pos = ((FormattedHeader) header).getValuePos();
181-
} else {
182-
final String s = header.getValue();
183-
if (s == null) {
184-
continue;
185-
}
186-
buffer = new CharArrayBuffer(s.length());
187-
buffer.append(s);
188-
pos = 0;
189-
}
190-
final ParserCursor cursor = new ParserCursor(pos, buffer.length());
191-
final List<AuthChallenge> authChallenges;
192-
try {
193-
authChallenges = parser.parse(challengeType, buffer, cursor);
194-
} catch (final ParseException ex) {
195-
if (LOG.isWarnEnabled()) {
196-
final HttpClientContext clientContext = HttpClientContext.cast(context);
197-
final String exchangeId = clientContext.getExchangeId();
198-
LOG.warn("{} Malformed challenge: {}", exchangeId, header.getValue());
199-
}
200-
continue;
201-
}
202-
for (final AuthChallenge authChallenge : authChallenges) {
203-
final String schemeName = authChallenge.getSchemeName().toLowerCase(Locale.ROOT);
204-
if (!challengeMap.containsKey(schemeName)) {
205-
challengeMap.put(schemeName, authChallenge);
206-
}
207-
}
208-
}
169+
MessageSupport.parseHeaders(
170+
response,
171+
challengeType == ChallengeType.PROXY ? HttpHeaders.PROXY_AUTHENTICATE : HttpHeaders.WWW_AUTHENTICATE,
172+
(buffer, cursor) -> {
173+
try {
174+
final List<AuthChallenge> authChallenges = parser.parse(challengeType, buffer, cursor);
175+
for (final AuthChallenge authChallenge : authChallenges) {
176+
final String schemeName = authChallenge.getSchemeName().toLowerCase(Locale.ROOT);
177+
if (!challengeMap.containsKey(schemeName)) {
178+
challengeMap.put(schemeName, authChallenge);
179+
}
180+
}
181+
} catch (final ParseException ex) {
182+
if (LOG.isWarnEnabled()) {
183+
final HttpClientContext clientContext = HttpClientContext.cast(context);
184+
final String exchangeId = clientContext.getExchangeId();
185+
LOG.warn("{} Malformed challenge", exchangeId);
186+
}
187+
}
188+
189+
});
209190
return challengeMap;
210191
}
211192

httpclient5/src/test/java/org/apache/hc/client5/http/impl/auth/TestAuthChallengeParser.java

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -345,4 +345,21 @@ private static void assertNameValuePair(final NameValuePair pair, final String n
345345
Assertions.assertEquals(value, pair.getValue());
346346
}
347347

348+
@Test
349+
void testParseAuthInfo() throws Exception {
350+
final CharArrayBuffer buffer = new CharArrayBuffer(64);
351+
buffer.append(" realm = blah, this, that , name = value ");
352+
final ParserCursor cursor = new ParserCursor(0, buffer.length());
353+
final AuthChallenge challenge = parser.parse(ChallengeType.TARGET, StandardAuthScheme.BASIC, buffer, cursor);
354+
Assertions.assertEquals(StandardAuthScheme.BASIC, challenge.getSchemeName());
355+
Assertions.assertNull(challenge.getValue());
356+
final List<NameValuePair> params = challenge.getParams();
357+
Assertions.assertNotNull(params);
358+
Assertions.assertEquals(4, params.size());
359+
assertNameValuePair(params.get(0), "realm", "blah");
360+
assertNameValuePair(params.get(1), "this", null);
361+
assertNameValuePair(params.get(2), "that", null);
362+
assertNameValuePair(params.get(3), "name", "value");
363+
}
364+
348365
}

0 commit comments

Comments
 (0)