1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28 package org.apache.hc.client5.http.impl.auth;
29
30 import java.util.ArrayList;
31 import java.util.List;
32
33 import org.apache.hc.client5.http.auth.AuthChallenge;
34 import org.apache.hc.client5.http.auth.ChallengeType;
35 import org.apache.hc.core5.http.NameValuePair;
36 import org.apache.hc.core5.http.ParseException;
37 import org.apache.hc.core5.http.message.BasicNameValuePair;
38 import org.apache.hc.core5.http.message.ParserCursor;
39 import org.apache.hc.core5.util.TextUtils;
40 import org.apache.hc.core5.util.Tokenizer;
41
42
43
44
45
46
47 public class AuthChallengeParser {
48
49 public static final AuthChallengeParser INSTANCE = new AuthChallengeParser();
50
51 private final Tokenizer tokenParser = Tokenizer.INSTANCE;
52
53 private final static char BLANK = ' ';
54 private final static char COMMA_CHAR = ',';
55 private final static char EQUAL_CHAR = '=';
56
57 private static final Tokenizer.Delimiter TERMINATORS = Tokenizer.delimiters(BLANK, EQUAL_CHAR, COMMA_CHAR);
58 private static final Tokenizer.Delimiter DELIMITER = Tokenizer.delimiters(COMMA_CHAR);
59 private static final Tokenizer.Delimiter SPACE = Tokenizer.delimiters(BLANK);
60
61 static class ChallengeInt {
62
63 final String schemeName;
64 final List<NameValuePair> params;
65
66 ChallengeInt(final String schemeName) {
67 this.schemeName = schemeName;
68 this.params = new ArrayList<>();
69 }
70
71 @Override
72 public String toString() {
73 return "ChallengeInternal{" +
74 "schemeName='" + schemeName + '\'' +
75 ", params=" + params +
76 '}';
77 }
78
79 }
80
81
82
83
84
85
86
87
88
89 public List<AuthChallenge> parse(
90 final ChallengeType challengeType, final CharSequence buffer, final ParserCursor cursor) throws ParseException {
91 tokenParser.skipWhiteSpace(buffer, cursor);
92 if (cursor.atEnd()) {
93 throw new ParseException("Malformed auth challenge");
94 }
95 final List<ChallengeInt> internalChallenges = new ArrayList<>();
96 final String schemeName = tokenParser.parseToken(buffer, cursor, SPACE);
97 if (TextUtils.isBlank(schemeName)) {
98 throw new ParseException("Malformed auth challenge");
99 }
100 ChallengeInt current = new ChallengeInt(schemeName);
101 while (current != null) {
102 internalChallenges.add(current);
103 current = parseChallenge(buffer, cursor, current);
104 }
105 final List<AuthChallenge> challenges = new ArrayList<>(internalChallenges.size());
106 for (final ChallengeInt internal : internalChallenges) {
107 final List<NameValuePair> params = internal.params;
108 String token68 = null;
109 if (params.size() == 1) {
110 final NameValuePair param = params.get(0);
111 if (param.getValue() == null) {
112 token68 = param.getName();
113 params.clear();
114 }
115 }
116 challenges.add(
117 new AuthChallenge(challengeType, internal.schemeName, token68, !params.isEmpty() ? params : null));
118 }
119 return challenges;
120 }
121
122 ChallengeInt parseChallenge(
123 final CharSequence buffer,
124 final ParserCursor cursor,
125 final ChallengeInt currentChallenge) throws ParseException {
126 for (;;) {
127 tokenParser.skipWhiteSpace(buffer, cursor);
128 if (cursor.atEnd()) {
129 return null;
130 }
131 final String token = parseToken(buffer, cursor);
132 if (TextUtils.isBlank(token)) {
133 throw new ParseException("Malformed auth challenge");
134 }
135 tokenParser.skipWhiteSpace(buffer, cursor);
136
137
138 if (cursor.atEnd()) {
139
140 currentChallenge.params.add(new BasicNameValuePair(token, null));
141 } else {
142 char ch = buffer.charAt(cursor.getPos());
143 if (ch == EQUAL_CHAR) {
144 cursor.updatePos(cursor.getPos() + 1);
145 final String value = tokenParser.parseValue(buffer, cursor, DELIMITER);
146 tokenParser.skipWhiteSpace(buffer, cursor);
147 if (!cursor.atEnd()) {
148 ch = buffer.charAt(cursor.getPos());
149 if (ch == COMMA_CHAR) {
150 cursor.updatePos(cursor.getPos() + 1);
151 }
152 }
153 currentChallenge.params.add(new BasicNameValuePair(token, value));
154 } else if (ch == COMMA_CHAR) {
155 cursor.updatePos(cursor.getPos() + 1);
156 currentChallenge.params.add(new BasicNameValuePair(token, null));
157 } else {
158
159 if (currentChallenge.params.isEmpty()) {
160 throw new ParseException("Malformed auth challenge");
161 }
162 return new ChallengeInt(token);
163 }
164 }
165 }
166 }
167
168 String parseToken(final CharSequence buf, final ParserCursor cursor) {
169 final StringBuilder dst = new StringBuilder();
170 while (!cursor.atEnd()) {
171 int pos = cursor.getPos();
172 char current = buf.charAt(pos);
173 if (TERMINATORS.test(current)) {
174
175 if (current == EQUAL_CHAR) {
176
177
178 if (pos + 1 < cursor.getUpperBound() && buf.charAt(pos + 1) != EQUAL_CHAR) {
179 break;
180 }
181 do {
182 dst.append(current);
183 pos++;
184 cursor.updatePos(pos);
185 if (cursor.atEnd()) {
186 break;
187 }
188 current = buf.charAt(pos);
189 } while (current == EQUAL_CHAR);
190 } else {
191 break;
192 }
193 } else {
194 dst.append(current);
195 cursor.updatePos(pos + 1);
196 }
197 }
198 return dst.toString();
199 }
200
201 }