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
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45 package org.eclipse.jgit.transport;
46
47 import java.io.IOException;
48 import java.net.URISyntaxException;
49 import java.text.MessageFormat;
50 import java.util.Set;
51 import java.util.function.Supplier;
52
53 import org.eclipse.jgit.errors.ConfigInvalidException;
54 import org.eclipse.jgit.internal.JGitText;
55 import org.eclipse.jgit.lib.Config;
56 import org.eclipse.jgit.storage.file.FileBasedConfig;
57 import org.eclipse.jgit.util.FS;
58 import org.eclipse.jgit.util.StringUtils;
59 import org.eclipse.jgit.util.SystemReader;
60 import org.slf4j.Logger;
61 import org.slf4j.LoggerFactory;
62
63
64
65
66
67
68
69
70
71 public class HttpConfig {
72
73 private static final Logger LOG = LoggerFactory.getLogger(HttpConfig.class);
74
75 private static final String FTP = "ftp";
76
77
78 public static final String HTTP = "http";
79
80
81 public static final String FOLLOW_REDIRECTS_KEY = "followRedirects";
82
83
84 public static final String MAX_REDIRECTS_KEY = "maxRedirects";
85
86
87 public static final String POST_BUFFER_KEY = "postBuffer";
88
89
90 public static final String SSL_VERIFY_KEY = "sslVerify";
91
92 private static final String MAX_REDIRECT_SYSTEM_PROPERTY = "http.maxRedirects";
93
94 private static final int DEFAULT_MAX_REDIRECTS = 5;
95
96 private static final int MAX_REDIRECTS = (new Supplier<Integer>() {
97
98 @Override
99 public Integer get() {
100 String rawValue = SystemReader.getInstance()
101 .getProperty(MAX_REDIRECT_SYSTEM_PROPERTY);
102 Integer value = Integer.valueOf(DEFAULT_MAX_REDIRECTS);
103 if (rawValue != null) {
104 try {
105 value = Integer.valueOf(Integer.parseUnsignedInt(rawValue));
106 } catch (NumberFormatException e) {
107 LOG.warn(MessageFormat.format(
108 JGitText.get().invalidSystemProperty,
109 MAX_REDIRECT_SYSTEM_PROPERTY, rawValue, value));
110 }
111 }
112 return value;
113 }
114 }).get().intValue();
115
116
117
118
119 public enum HttpRedirectMode implements Config.ConfigEnum {
120
121
122 TRUE("true"),
123
124
125
126
127 INITIAL("initial"),
128
129 FALSE("false");
130
131 private final String configValue;
132
133 private HttpRedirectMode(String configValue) {
134 this.configValue = configValue;
135 }
136
137 @Override
138 public String toConfigValue() {
139 return configValue;
140 }
141
142 @Override
143 public boolean matchConfigValue(String s) {
144 return configValue.equals(s);
145 }
146 }
147
148 private int postBuffer;
149
150 private boolean sslVerify;
151
152 private HttpRedirectMode followRedirects;
153
154 private int maxRedirects;
155
156
157
158
159
160
161 public int getPostBuffer() {
162 return postBuffer;
163 }
164
165
166
167
168
169
170 public boolean isSslVerify() {
171 return sslVerify;
172 }
173
174
175
176
177
178
179 public HttpRedirectMode getFollowRedirects() {
180 return followRedirects;
181 }
182
183
184
185
186
187
188 public int getMaxRedirects() {
189 return maxRedirects;
190 }
191
192
193
194
195
196
197
198
199
200
201 public HttpConfig(Config config, URIish uri) {
202 init(config, uri);
203 }
204
205
206
207
208
209
210
211
212 public HttpConfig(URIish uri) {
213 FileBasedConfig userConfig = SystemReader.getInstance()
214 .openUserConfig(null, FS.DETECTED);
215 try {
216 userConfig.load();
217 } catch (IOException | ConfigInvalidException e) {
218
219 LOG.error(MessageFormat.format(JGitText.get().userConfigFileInvalid,
220 userConfig.getFile().getAbsolutePath(), e));
221 init(new Config(), uri);
222 return;
223 }
224 init(userConfig, uri);
225 }
226
227 private void init(Config config, URIish uri) {
228
229 int postBufferSize = config.getInt(HTTP, POST_BUFFER_KEY,
230 1 * 1024 * 1024);
231 boolean sslVerifyFlag = config.getBoolean(HTTP, SSL_VERIFY_KEY, true);
232 HttpRedirectMode followRedirectsMode = config.getEnum(
233 HttpRedirectMode.values(), HTTP, null,
234 FOLLOW_REDIRECTS_KEY, HttpRedirectMode.INITIAL);
235 int redirectLimit = config.getInt(HTTP, MAX_REDIRECTS_KEY,
236 MAX_REDIRECTS);
237 if (redirectLimit < 0) {
238 redirectLimit = MAX_REDIRECTS;
239 }
240 String match = findMatch(config.getSubsections(HTTP), uri);
241 if (match != null) {
242
243 postBufferSize = config.getInt(HTTP, match, POST_BUFFER_KEY,
244 postBufferSize);
245 sslVerifyFlag = config.getBoolean(HTTP, match, SSL_VERIFY_KEY,
246 sslVerifyFlag);
247 followRedirectsMode = config.getEnum(HttpRedirectMode.values(),
248 HTTP, match, FOLLOW_REDIRECTS_KEY, followRedirectsMode);
249 int newMaxRedirects = config.getInt(HTTP, match, MAX_REDIRECTS_KEY,
250 redirectLimit);
251 if (newMaxRedirects >= 0) {
252 redirectLimit = newMaxRedirects;
253 }
254 }
255 postBuffer = postBufferSize;
256 sslVerify = sslVerifyFlag;
257 followRedirects = followRedirectsMode;
258 maxRedirects = redirectLimit;
259 }
260
261
262
263
264
265
266
267
268
269
270
271
272 private String findMatch(Set<String> names, URIish uri) {
273 String bestMatch = null;
274 int bestMatchLength = -1;
275 boolean withUser = false;
276 String uPath = uri.getPath();
277 boolean hasPath = !StringUtils.isEmptyOrNull(uPath);
278 if (hasPath) {
279 uPath = normalize(uPath);
280 if (uPath == null) {
281
282 return null;
283 }
284 }
285 for (String s : names) {
286 try {
287 URIish candidate = new URIish(s);
288
289 if (!compare(uri.getScheme(), candidate.getScheme())
290 || !compare(uri.getHost(), candidate.getHost())) {
291 continue;
292 }
293
294 if (defaultedPort(uri.getPort(),
295 uri.getScheme()) != defaultedPort(candidate.getPort(),
296 candidate.getScheme())) {
297 continue;
298 }
299
300 boolean hasUser = false;
301 if (candidate.getUser() != null) {
302 if (!candidate.getUser().equals(uri.getUser())) {
303 continue;
304 }
305 hasUser = true;
306 }
307
308 String cPath = candidate.getPath();
309 int matchLength = -1;
310 if (StringUtils.isEmptyOrNull(cPath)) {
311 matchLength = 0;
312 } else {
313 if (!hasPath) {
314 continue;
315 }
316
317 matchLength = segmentCompare(uPath, cPath);
318 if (matchLength < 0) {
319 continue;
320 }
321 }
322
323
324
325 if (matchLength > bestMatchLength || !withUser && hasUser
326 && matchLength >= 0 && matchLength == bestMatchLength) {
327 bestMatch = s;
328 bestMatchLength = matchLength;
329 withUser = hasUser;
330 }
331 } catch (URISyntaxException e) {
332 LOG.warn(MessageFormat
333 .format(JGitText.get().httpConfigInvalidURL, s));
334 }
335 }
336 return bestMatch;
337 }
338
339 private boolean compare(String a, String b) {
340 if (a == null) {
341 return b == null;
342 }
343 return a.equalsIgnoreCase(b);
344 }
345
346 private int defaultedPort(int port, String scheme) {
347 if (port >= 0) {
348 return port;
349 }
350 if (FTP.equalsIgnoreCase(scheme)) {
351 return 21;
352 } else if (HTTP.equalsIgnoreCase(scheme)) {
353 return 80;
354 } else {
355 return 443;
356 }
357 }
358
359 static int segmentCompare(String uriPath, String m) {
360
361
362 String matchPath = normalize(m);
363 if (matchPath == null || !uriPath.startsWith(matchPath)) {
364 return -1;
365 }
366
367
368
369 int uLength = uriPath.length();
370 int mLength = matchPath.length();
371 if (mLength == uLength || matchPath.charAt(mLength - 1) == '/'
372 || mLength < uLength && uriPath.charAt(mLength) == '/') {
373 return mLength;
374 }
375 return -1;
376 }
377
378 static String normalize(String path) {
379
380 int i = 0;
381 int length = path.length();
382 StringBuilder builder = new StringBuilder(length);
383 builder.append('/');
384 if (length > 0 && path.charAt(0) == '/') {
385 i = 1;
386 }
387 while (i < length) {
388 int slash = path.indexOf('/', i);
389 if (slash < 0) {
390 slash = length;
391 }
392 if (slash == i || slash == i + 1 && path.charAt(i) == '.') {
393
394 } else if (slash == i + 2 && path.charAt(i) == '.'
395 && path.charAt(i + 1) == '.') {
396
397 int l = builder.length() - 2;
398 while (l >= 0 && builder.charAt(l) != '/') {
399 l--;
400 }
401 if (l < 0) {
402 LOG.warn(MessageFormat.format(
403 JGitText.get().httpConfigCannotNormalizeURL, path));
404 return null;
405 }
406 builder.setLength(l + 1);
407 } else {
408
409 builder.append(path, i, Math.min(length, slash + 1));
410 }
411 i = slash + 1;
412 }
413 if (builder.length() > 1 && builder.charAt(builder.length() - 1) == '/'
414 && length > 0 && path.charAt(length - 1) != '/') {
415
416
417 builder.setLength(builder.length() - 1);
418 }
419 return builder.toString();
420 }
421 }