FileBasedConfig userConfig = SystemReader.getInstance()
.openUserConfig(null, FS.DETECTED);
- userConfig.setBoolean("http", null, "sslVerify", false);
+ userConfig.setBoolean("http",
+ "https://" + secureURI.getHost() + ':' + server.getSecurePort(),
+ "sslVerify", false);
+ userConfig.setBoolean("http",
+ "http://" + remoteURI.getHost() + ':' + server.getPort(),
+ "sslVerify", false);
userConfig.save();
}
--- /dev/null
+/*
+ * Copyright (C) 2017, Thomas Wolf <thomas.wolf@paranor.ch>
+ * and other copyright owners as documented in the project's IP log.
+ *
+ * This program and the accompanying materials are made available
+ * under the terms of the Eclipse Distribution License v1.0 which
+ * accompanies this distribution, is reproduced below, and is
+ * available at http://www.eclipse.org/org/documents/edl-v10.php
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ *
+ * - Neither the name of the Eclipse Foundation, Inc. nor the
+ * names of its contributors may be used to endorse or promote
+ * products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
+ * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package org.eclipse.jgit.transport;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+import org.eclipse.jgit.lib.Config;
+import org.junit.Before;
+import org.junit.Test;
+
+/**
+ * Tests for correctly resolving URIs when reading http.* values from a
+ * {@link Config}.
+ */
+public class HttpConfigTest {
+
+ private static final String DEFAULT = "[http]\n" + "\tpostBuffer = 1\n"
+ + "\tsslVerify= true\n" + "\tfollowRedirects = true\n"
+ + "\tmaxRedirects = 5\n\n";
+
+ private Config config;
+
+ @Before
+ public void setUp() {
+ config = new Config();
+ }
+
+ @Test
+ public void testDefault() throws Exception {
+ HttpConfig http = new HttpConfig(config,
+ new URIish("http://example.com/path/repo.git"));
+ assertEquals(1024 * 1024, http.getPostBuffer());
+ assertTrue(http.isSslVerify());
+ assertEquals(HttpConfig.HttpRedirectMode.INITIAL,
+ http.getFollowRedirects());
+ }
+
+ @Test
+ public void testMatchSuccess() throws Exception {
+ config.fromText(DEFAULT + "[http \"http://example.com\"]\n"
+ + "\tpostBuffer = 1024\n");
+ HttpConfig http = new HttpConfig(config,
+ new URIish("http://example.com/path/repo.git"));
+ assertEquals(1024, http.getPostBuffer());
+ http = new HttpConfig(config,
+ new URIish("https://example.com/path/repo.git"));
+ assertEquals(1, http.getPostBuffer());
+ http = new HttpConfig(config,
+ new URIish("http://example.org/path/repo.git"));
+ assertEquals(1, http.getPostBuffer());
+ http = new HttpConfig(config,
+ new URIish("http://example.com:80/path/repo.git"));
+ assertEquals(1024, http.getPostBuffer());
+ http = new HttpConfig(config,
+ new URIish("http://example.com:8080/path/repo.git"));
+ assertEquals(1, http.getPostBuffer());
+ }
+
+ @Test
+ public void testMatchWithOnlySchemeInConfig() throws Exception {
+ config.fromText(
+ DEFAULT + "[http \"http://\"]\n" + "\tpostBuffer = 1024\n");
+ HttpConfig http = new HttpConfig(config,
+ new URIish("http://example.com/path/repo.git"));
+ assertEquals(1, http.getPostBuffer());
+ }
+
+ @Test
+ public void testMatchWithPrefixUriInConfig() throws Exception {
+ config.fromText(DEFAULT + "[http \"http://example\"]\n"
+ + "\tpostBuffer = 1024\n");
+ HttpConfig http = new HttpConfig(config,
+ new URIish("http://example.com/path/repo.git"));
+ assertEquals(1, http.getPostBuffer());
+ }
+
+ @Test
+ public void testMatchCaseSensitivity() throws Exception {
+ config.fromText(DEFAULT + "[http \"http://exAMPle.com\"]\n"
+ + "\tpostBuffer = 1024\n");
+ HttpConfig http = new HttpConfig(config,
+ new URIish("http://example.com/path/repo.git"));
+ assertEquals(1024, http.getPostBuffer());
+ }
+
+ @Test
+ public void testMatchWithInvalidUriInConfig() throws Exception {
+ config.fromText(
+ DEFAULT + "[http \"///\"]\n" + "\tpostBuffer = 1024\n");
+ HttpConfig http = new HttpConfig(config,
+ new URIish("http://example.com/path/repo.git"));
+ assertEquals(1, http.getPostBuffer());
+ }
+
+ @Test
+ public void testMatchWithInvalidAndValidUriInConfig() throws Exception {
+ config.fromText(DEFAULT + "[http \"///\"]\n" + "\tpostBuffer = 1024\n"
+ + "[http \"http://example.com\"]\n" + "\tpostBuffer = 2048\n");
+ HttpConfig http = new HttpConfig(config,
+ new URIish("http://example.com/path/repo.git"));
+ assertEquals(2048, http.getPostBuffer());
+ }
+
+ @Test
+ public void testMatchWithHostEndingInSlash() throws Exception {
+ config.fromText(DEFAULT + "[http \"http://example.com/\"]\n"
+ + "\tpostBuffer = 1024\n");
+ HttpConfig http = new HttpConfig(config,
+ new URIish("http://example.com/path/repo.git"));
+ assertEquals(1024, http.getPostBuffer());
+ }
+
+ @Test
+ public void testMatchWithUser() throws Exception {
+ config.fromText(DEFAULT + "[http \"http://example.com/path\"]\n"
+ + "\tpostBuffer = 1024\n"
+ + "[http \"http://example.com/path/repo\"]\n"
+ + "\tpostBuffer = 2048\n"
+ + "[http \"http://user@example.com/path\"]\n"
+ + "\tpostBuffer = 4096\n");
+ HttpConfig http = new HttpConfig(config,
+ new URIish("http://example.com/path/repo.git"));
+ assertEquals(1024, http.getPostBuffer());
+ http = new HttpConfig(config,
+ new URIish("http://user@example.com/path/repo.git"));
+ assertEquals(4096, http.getPostBuffer());
+ http = new HttpConfig(config,
+ new URIish("http://user@example.com/path/repo/foo.git"));
+ assertEquals(2048, http.getPostBuffer());
+ http = new HttpConfig(config,
+ new URIish("http://user@example.com/path/foo.git"));
+ assertEquals(4096, http.getPostBuffer());
+ http = new HttpConfig(config,
+ new URIish("http://example.com/path/foo.git"));
+ assertEquals(1024, http.getPostBuffer());
+ http = new HttpConfig(config,
+ new URIish("http://User@example.com/path/repo/foo.git"));
+ assertEquals(2048, http.getPostBuffer());
+ http = new HttpConfig(config,
+ new URIish("http://User@example.com/path/foo.git"));
+ assertEquals(1024, http.getPostBuffer());
+ }
+
+ @Test
+ public void testMatchLonger() throws Exception {
+ config.fromText(DEFAULT + "[http \"http://example.com/path\"]\n"
+ + "\tpostBuffer = 1024\n"
+ + "[http \"http://example.com/path/repo\"]\n"
+ + "\tpostBuffer = 2048\n");
+ HttpConfig http = new HttpConfig(config,
+ new URIish("http://example.com/path/repo.git"));
+ assertEquals(1024, http.getPostBuffer());
+ http = new HttpConfig(config,
+ new URIish("http://example.com/foo/repo.git"));
+ assertEquals(1, http.getPostBuffer());
+ http = new HttpConfig(config,
+ new URIish("https://example.com/path/repo.git"));
+ assertEquals(1, http.getPostBuffer());
+ http = new HttpConfig(config,
+ new URIish("http://example.com/path/repo/.git"));
+ assertEquals(2048, http.getPostBuffer());
+ http = new HttpConfig(config, new URIish("http://example.com/path"));
+ assertEquals(1024, http.getPostBuffer());
+ http = new HttpConfig(config,
+ new URIish("http://user@example.com/path"));
+ assertEquals(1024, http.getPostBuffer());
+ }
+}
--- /dev/null
+/*
+ * Copyright (C) 2017, Thomas Wolf <thomas.wolf@paranor.ch>
+ * and other copyright owners as documented in the project's IP log.
+ *
+ * This program and the accompanying materials are made available
+ * under the terms of the Eclipse Distribution License v1.0 which
+ * accompanies this distribution, is reproduced below, and is
+ * available at http://www.eclipse.org/org/documents/edl-v10.php
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ *
+ * - Neither the name of the Eclipse Foundation, Inc. nor the
+ * names of its contributors may be used to endorse or promote
+ * products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
+ * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package org.eclipse.jgit.transport;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNull;
+
+import org.junit.Test;
+
+/**
+ * Basic URI path prefix match tests for {@link HttpConfig}.
+ */
+public class HttpConfigUriPathTest {
+
+ @Test
+ public void testNormalizationEmptyPaths() {
+ assertEquals("/", HttpConfig.normalize(""));
+ assertEquals("/", HttpConfig.normalize("/"));
+ }
+
+ @Test
+ public void testNormalization() {
+ assertEquals("/f", HttpConfig.normalize("f"));
+ assertEquals("/f", HttpConfig.normalize("/f"));
+ assertEquals("/f/", HttpConfig.normalize("/f/"));
+ assertEquals("/foo", HttpConfig.normalize("foo"));
+ assertEquals("/foo", HttpConfig.normalize("/foo"));
+ assertEquals("/foo/", HttpConfig.normalize("/foo/"));
+ assertEquals("/foo/bar", HttpConfig.normalize("foo/bar"));
+ assertEquals("/foo/bar", HttpConfig.normalize("/foo/bar"));
+ assertEquals("/foo/bar/", HttpConfig.normalize("/foo/bar/"));
+ }
+
+ @Test
+ public void testNormalizationWithDot() {
+ assertEquals("/", HttpConfig.normalize("."));
+ assertEquals("/", HttpConfig.normalize("/."));
+ assertEquals("/", HttpConfig.normalize("/./"));
+ assertEquals("/foo", HttpConfig.normalize("foo/."));
+ assertEquals("/foo/bar", HttpConfig.normalize("/foo/./bar"));
+ assertEquals("/foo/bar", HttpConfig.normalize("/foo/bar/."));
+ assertEquals("/foo/bar/", HttpConfig.normalize("/foo/bar/./"));
+ assertEquals("/foo/bar", HttpConfig.normalize("/foo/./././bar"));
+ assertEquals("/foo/bar/", HttpConfig.normalize("/foo/./././bar/"));
+ assertEquals("/foo/bar", HttpConfig.normalize("/foo/bar/././."));
+ assertEquals("/foo/bar/", HttpConfig.normalize("/foo/bar/./././"));
+ assertEquals("/foo/bar/.baz/bam",
+ HttpConfig.normalize("/foo/bar/.baz/bam"));
+ assertEquals("/foo/bar/.baz/bam/",
+ HttpConfig.normalize("/foo/bar/.baz/bam/"));
+ }
+
+ @Test
+ public void testNormalizationWithDotDot() {
+ assertEquals("/", HttpConfig.normalize("foo/.."));
+ assertEquals("/", HttpConfig.normalize("/foo/.."));
+ assertEquals("/", HttpConfig.normalize("/foo/../bar/.."));
+ assertEquals("/", HttpConfig.normalize("/foo/.././bar/.."));
+ assertEquals("/bar", HttpConfig.normalize("foo/../bar"));
+ assertEquals("/bar", HttpConfig.normalize("/foo/../bar"));
+ assertEquals("/bar", HttpConfig.normalize("/foo/./.././bar"));
+ assertEquals("/bar/", HttpConfig.normalize("/foo/../bar/"));
+ assertEquals("/bar/", HttpConfig.normalize("/foo/./.././bar/"));
+ assertEquals("/foo/bar", HttpConfig.normalize("/foo/bar/baz/.."));
+ assertEquals("/foo/bar/", HttpConfig.normalize("/foo/bar/baz/../"));
+ assertEquals("/foo", HttpConfig.normalize("/foo/bar/baz/../.."));
+ assertEquals("/foo", HttpConfig.normalize("/foo/bar/baz/../.."));
+ assertEquals("/foo", HttpConfig.normalize("/foo/bar/baz/.././.."));
+ assertEquals("/foo", HttpConfig.normalize("/foo/bar/baz/../././.."));
+ assertEquals("/foo/baz", HttpConfig.normalize("/foo/bar/../baz"));
+ assertEquals("/foo/baz/", HttpConfig.normalize("/foo/bar/../baz/"));
+ assertEquals("/foo/baz", HttpConfig.normalize("/foo/bar/../baz/."));
+ assertEquals("/foo/baz/", HttpConfig.normalize("/foo/bar/../baz/./"));
+ assertEquals("/foo", HttpConfig.normalize("/foo/bar/../baz/.."));
+ assertEquals("/foo/", HttpConfig.normalize("/foo/bar/../baz/../"));
+ assertEquals("/baz", HttpConfig.normalize("/foo/bar/../../baz"));
+ assertEquals("/baz/", HttpConfig.normalize("/foo/bar/../../baz/"));
+ assertEquals("/foo/.b/bar", HttpConfig.normalize("/foo/.b/bar"));
+ assertEquals("/.f/foo/.b/bar/", HttpConfig.normalize(".f/foo/.b/bar/"));
+ assertEquals("/foo/bar/..baz/bam",
+ HttpConfig.normalize("/foo/bar/..baz/bam"));
+ assertEquals("/foo/bar/..baz/bam/",
+ HttpConfig.normalize("/foo/bar/..baz/bam/"));
+ assertEquals("/foo/bar/.../baz/bam",
+ HttpConfig.normalize("/foo/bar/.../baz/bam"));
+ assertEquals("/foo/bar/.../baz/bam/",
+ HttpConfig.normalize("/foo/bar/.../baz/bam/"));
+ }
+
+ @Test
+ public void testNormalizationWithDoubleSlash() {
+ assertEquals("/", HttpConfig.normalize("//"));
+ assertEquals("/foo/", HttpConfig.normalize("///foo//"));
+ assertEquals("/foo", HttpConfig.normalize("///foo//."));
+ assertEquals("/foo/", HttpConfig.normalize("///foo//.////"));
+ assertEquals("/foo/bar", HttpConfig.normalize("/foo//bar"));
+ assertEquals("/foo/bar", HttpConfig.normalize("/foo//bar//."));
+ assertEquals("/foo/bar/", HttpConfig.normalize("/foo//bar//./"));
+ }
+
+ @Test
+ public void testNormalizationWithDotDotFailing() {
+ assertNull(HttpConfig.normalize(".."));
+ assertNull(HttpConfig.normalize("/.."));
+ assertNull(HttpConfig.normalize("/../"));
+ assertNull(HttpConfig.normalize("/../foo"));
+ assertNull(HttpConfig.normalize("./../foo"));
+ assertNull(HttpConfig.normalize("/./../foo"));
+ assertNull(HttpConfig.normalize("/foo/./.././.."));
+ assertNull(HttpConfig.normalize("/foo/../bar/../.."));
+ assertNull(HttpConfig.normalize("/foo/../bar/../../baz"));
+ }
+
+ @Test
+ public void testSegmentCompare() {
+ // 2nd parameter is the match, will be normalized
+ assertSuccess("/foo", "");
+ assertSuccess("/foo", "/");
+ assertSuccess("/foo", "//");
+ assertSuccess("/foo", "foo");
+ assertSuccess("/foo", "/foo");
+ assertSuccess("/foo/", "foo");
+ assertSuccess("/foo/", "/foo");
+ assertSuccess("/foo/", "foo/");
+ assertSuccess("/foo/", "/foo/");
+ assertSuccess("/foo/bar", "foo");
+ assertSuccess("/foo/bar", "foo/");
+ assertSuccess("/foo/bar", "foo/bar");
+ assertSuccess("/foo/bar/", "foo/bar");
+ assertSuccess("/foo/bar/", "foo/bar/");
+ assertSuccess("/foo/bar", "/foo/bar");
+ assertSuccess("/foo/bar/", "/foo/bar");
+ assertSuccess("/foo/bar/", "/foo/bar/");
+ assertSuccess("/foo/bar", "/foo/bar/..");
+ assertSuccess("/foo/bar/", "/foo/bar/..");
+ assertSuccess("/foo/bar/", "/foo/bar/../");
+ assertSuccess("/foo/bar", "/foo/./bar");
+ assertSuccess("/foo/bar/", "/foo/./bar/");
+ assertSuccess("/some/repo/.git", "/some/repo");
+ assertSuccess("/some/repo/bare.git", "/some/repo");
+ assertSuccess("/some/repo/.git", "/some/repo/.git");
+ assertSuccess("/some/repo/bare.git", "/some/repo/bare.git");
+ }
+
+ @Test
+ public void testSegmentCompareFailing() {
+ // 2nd parameter is the match, will be normalized
+ assertEquals(-1, HttpConfig.segmentCompare("/foo", "foo/"));
+ assertEquals(-1, HttpConfig.segmentCompare("/foo", "/foo/"));
+ assertEquals(-1, HttpConfig.segmentCompare("/foobar", "foo"));
+ assertEquals(-1, HttpConfig.segmentCompare("/foobar", "/foo"));
+ assertEquals(-1,
+ HttpConfig.segmentCompare("/foo/barbar/baz", "foo/bar"));
+ assertEquals(-1, HttpConfig.segmentCompare("/foo/barbar", "/foo/bar"));
+ assertEquals(-1,
+ HttpConfig.segmentCompare("/some/repo.git", "/some/repo"));
+ assertEquals(-1,
+ HttpConfig.segmentCompare("/some/repo.git", "/some/repo.g"));
+ assertEquals(-1, HttpConfig.segmentCompare("/some/repo/bare.git",
+ "/some/repo/bar"));
+ assertSuccess("/some/repo/bare.git", "/some/repo");
+ // Just to make sure we don't use the PathMatchers...
+ assertEquals(-1, HttpConfig.segmentCompare("/foo/barbar/baz", "**"));
+ assertEquals(-1,
+ HttpConfig.segmentCompare("/foo/barbar/baz", "**/foo"));
+ assertEquals(-1,
+ HttpConfig.segmentCompare("/foo/barbar/baz", "/*/barbar/**"));
+ assertEquals(-1, HttpConfig.segmentCompare("/foo", "/*"));
+ assertEquals(-1, HttpConfig.segmentCompare("/foo", "/???"));
+ assertEquals(-1, HttpConfig.segmentCompare("/foo/bar/baz", "bar"));
+ // Failing to normalize
+ assertEquals(-1,
+ HttpConfig.segmentCompare("/foo/bar/baz", "bar/../.."));
+ }
+
+ private void assertSuccess(String uri, String match) {
+ String normalized = HttpConfig.normalize(match);
+ assertEquals(normalized.length(),
+ HttpConfig.segmentCompare(uri, match));
+ }
+}
gitmodulesNotFound=.gitmodules not found in tree.
headRequiredToStash=HEAD required to stash local changes
hoursAgo={0} hours ago
+httpConfigCannotNormalizeURL=Cannot normalize URL path {0}: too many .. segments
+httpConfigInvalidURL=Cannot parse URL from subsection http.{0} in git config; ignored.
hugeIndexesAreNotSupportedByJgitYet=Huge indexes are not supported by jgit, yet
hunkBelongsToAnotherFile=Hunk belongs to another file
hunkDisconnectedFromFile=Hunk disconnected from file
/***/ public String gitmodulesNotFound;
/***/ public String headRequiredToStash;
/***/ public String hoursAgo;
+ /***/ public String httpConfigCannotNormalizeURL;
+ /***/ public String httpConfigInvalidURL;
/***/ public String hugeIndexesAreNotSupportedByJgitYet;
/***/ public String hunkBelongsToAnotherFile;
/***/ public String hunkDisconnectedFromFile;
--- /dev/null
+/*
+ * Copyright (C) 2008, 2010, Google Inc.
+ * Copyright (C) 2017, Thomas Wolf <thomas.wolf@paranor.ch>
+ * and other copyright owners as documented in the project's IP log.
+ *
+ * This program and the accompanying materials are made available
+ * under the terms of the Eclipse Distribution License v1.0 which
+ * accompanies this distribution, is reproduced below, and is
+ * available at http://www.eclipse.org/org/documents/edl-v10.php
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ *
+ * - Neither the name of the Eclipse Foundation, Inc. nor the
+ * names of its contributors may be used to endorse or promote
+ * products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
+ * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package org.eclipse.jgit.transport;
+
+import java.net.URISyntaxException;
+import java.text.MessageFormat;
+import java.util.Set;
+import java.util.function.Supplier;
+
+import org.eclipse.jgit.internal.JGitText;
+import org.eclipse.jgit.lib.Config;
+import org.eclipse.jgit.util.FS;
+import org.eclipse.jgit.util.StringUtils;
+import org.eclipse.jgit.util.SystemReader;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * A representation of the "http.*" config values in a git {@link Config}. git
+ * provides for setting values for specific URLs through "http.<url>.*
+ * subsections. git always considers only the initial original URL for such
+ * settings, not any redirected URL.
+ *
+ * @since 4.9
+ */
+public class HttpConfig {
+
+ private static final Logger LOG = LoggerFactory.getLogger(HttpConfig.class);
+
+ private static final String FTP = "ftp"; //$NON-NLS-1$
+
+ private static final String HTTP = "http"; //$NON-NLS-1$
+
+ private static final String FOLLOW_REDIRECTS_KEY = "followRedirects"; //$NON-NLS-1$
+
+ private static final String MAX_REDIRECTS_KEY = "maxRedirects"; //$NON-NLS-1$
+
+ private static final String POST_BUFFER_KEY = "postBuffer"; //$NON-NLS-1$
+
+ private static final String SSL_VERIFY_KEY = "sslVerify"; //$NON-NLS-1$
+
+ private static final String MAX_REDIRECT_SYSTEM_PROPERTY = "http.maxRedirects"; //$NON-NLS-1$
+
+ private static final int DEFAULT_MAX_REDIRECTS = 5;
+
+ private static final int MAX_REDIRECTS = (new Supplier<Integer>() {
+
+ @Override
+ public Integer get() {
+ String rawValue = SystemReader.getInstance()
+ .getProperty(MAX_REDIRECT_SYSTEM_PROPERTY);
+ Integer value = Integer.valueOf(DEFAULT_MAX_REDIRECTS);
+ if (rawValue != null) {
+ try {
+ value = Integer.valueOf(Integer.parseUnsignedInt(rawValue));
+ } catch (NumberFormatException e) {
+ LOG.warn(MessageFormat.format(
+ JGitText.get().invalidSystemProperty,
+ MAX_REDIRECT_SYSTEM_PROPERTY, rawValue, value));
+ }
+ }
+ return value;
+ }
+ }).get().intValue();
+
+ /**
+ * Config values for http.followRedirect.
+ */
+ public enum HttpRedirectMode implements Config.ConfigEnum {
+
+ /** Always follow redirects (up to the http.maxRedirects limit). */
+ TRUE("true"), //$NON-NLS-1$
+ /**
+ * Only follow redirects on the initial GET request. This is the
+ * default.
+ */
+ INITIAL("initial"), //$NON-NLS-1$
+ /** Never follow redirects. */
+ FALSE("false"); //$NON-NLS-1$
+
+ private final String configValue;
+
+ private HttpRedirectMode(String configValue) {
+ this.configValue = configValue;
+ }
+
+ @Override
+ public String toConfigValue() {
+ return configValue;
+ }
+
+ @Override
+ public boolean matchConfigValue(String s) {
+ return configValue.equals(s);
+ }
+ }
+
+ private final int postBuffer;
+
+ private final boolean sslVerify;
+
+ private final HttpRedirectMode followRedirects;
+
+ private final int maxRedirects;
+
+ /**
+ * @return the value of the "http.postBuffer" setting
+ */
+ public int getPostBuffer() {
+ return postBuffer;
+ }
+
+ /**
+ * @return the value of the "http.sslVerify" setting
+ */
+ public boolean isSslVerify() {
+ return sslVerify;
+ }
+
+ /**
+ * @return the value of the "http.followRedirects" setting
+ */
+ public HttpRedirectMode getFollowRedirects() {
+ return followRedirects;
+ }
+
+ /**
+ * @return the value of the "http.maxRedirects" setting
+ */
+ public int getMaxRedirects() {
+ return maxRedirects;
+ }
+
+ /**
+ * Creates a new {@link HttpConfig} tailored to the given {@link URIish}.
+ *
+ * @param config
+ * to read the {@link HttpConfig} from
+ * @param uri
+ * to get the configuration values for
+ */
+ public HttpConfig(Config config, URIish uri) {
+ // Set defaults from the section first
+ int postBufferSize = config.getInt(HTTP, POST_BUFFER_KEY,
+ 1 * 1024 * 1024);
+ boolean sslVerifyFlag = config.getBoolean(HTTP, SSL_VERIFY_KEY, true);
+ HttpRedirectMode followRedirectsMode = config.getEnum(
+ HttpRedirectMode.values(), HTTP, null,
+ FOLLOW_REDIRECTS_KEY, HttpRedirectMode.INITIAL);
+ int redirectLimit = config.getInt(HTTP, MAX_REDIRECTS_KEY,
+ MAX_REDIRECTS);
+ if (redirectLimit < 0) {
+ redirectLimit = MAX_REDIRECTS;
+ }
+ String match = findMatch(config.getSubsections(HTTP), uri);
+ if (match != null) {
+ // Override with more specific items
+ postBufferSize = config.getInt(HTTP, match, POST_BUFFER_KEY,
+ postBufferSize);
+ sslVerifyFlag = config.getBoolean(HTTP, match, SSL_VERIFY_KEY,
+ sslVerifyFlag);
+ followRedirectsMode = config.getEnum(HttpRedirectMode.values(),
+ HTTP, match, FOLLOW_REDIRECTS_KEY, followRedirectsMode);
+ int newMaxRedirects = config.getInt(HTTP, match, MAX_REDIRECTS_KEY,
+ redirectLimit);
+ if (newMaxRedirects >= 0) {
+ redirectLimit = newMaxRedirects;
+ }
+ }
+ postBuffer = postBufferSize;
+ sslVerify = sslVerifyFlag;
+ followRedirects = followRedirectsMode;
+ maxRedirects = redirectLimit;
+ }
+
+ /**
+ * Creates a {@link HttpConfig} that reads values solely from the user
+ * config.
+ *
+ * @param uri
+ * to get the configuration values for
+ */
+ public HttpConfig(URIish uri) {
+ this(SystemReader.getInstance().openUserConfig(null, FS.DETECTED), uri);
+ }
+
+ /**
+ * Determines the best match from a set of subsection names (representing
+ * prefix URLs) for the given {@link URIish}.
+ *
+ * @param names
+ * to match against the {@code uri}
+ * @param uri
+ * to find a match for
+ * @return the best matching subsection name, or {@code null} if no
+ * subsection matches
+ */
+ private String findMatch(Set<String> names, URIish uri) {
+ String bestMatch = null;
+ int bestMatchLength = -1;
+ boolean withUser = false;
+ String uPath = uri.getPath();
+ boolean hasPath = !StringUtils.isEmptyOrNull(uPath);
+ if (hasPath) {
+ uPath = normalize(uPath);
+ if (uPath == null) {
+ // Normalization failed; warning was logged.
+ return null;
+ }
+ }
+ for (String s : names) {
+ try {
+ URIish candidate = new URIish(s);
+ // Scheme and host must match case-insensitively
+ if (!compare(uri.getScheme(), candidate.getScheme())
+ || !compare(uri.getHost(), candidate.getHost())) {
+ continue;
+ }
+ // Ports must match after default ports have been substituted
+ if (defaultedPort(uri.getPort(),
+ uri.getScheme()) != defaultedPort(candidate.getPort(),
+ candidate.getScheme())) {
+ continue;
+ }
+ // User: if present in candidate, must match
+ boolean hasUser = false;
+ if (candidate.getUser() != null) {
+ if (!candidate.getUser().equals(uri.getUser())) {
+ continue;
+ }
+ hasUser = true;
+ }
+ // Path: prefix match, longer is better
+ String cPath = candidate.getPath();
+ int matchLength = -1;
+ if (StringUtils.isEmptyOrNull(cPath)) {
+ matchLength = 0;
+ } else {
+ if (!hasPath) {
+ continue;
+ }
+ // Paths can match only on segments
+ matchLength = segmentCompare(uPath, cPath);
+ if (matchLength < 0) {
+ continue;
+ }
+ }
+ // A longer path match is always preferred even over a user
+ // match. If the path matches are equal, a match with user wins
+ // over a match without user.
+ if (matchLength > bestMatchLength || !withUser && hasUser
+ && matchLength >= 0 && matchLength == bestMatchLength) {
+ bestMatch = s;
+ bestMatchLength = matchLength;
+ withUser = hasUser;
+ }
+ } catch (URISyntaxException e) {
+ LOG.warn(MessageFormat
+ .format(JGitText.get().httpConfigInvalidURL, s));
+ }
+ }
+ return bestMatch;
+ }
+
+ private boolean compare(String a, String b) {
+ if (a == null) {
+ return b == null;
+ }
+ return a.equalsIgnoreCase(b);
+ }
+
+ private int defaultedPort(int port, String scheme) {
+ if (port >= 0) {
+ return port;
+ }
+ if (FTP.equalsIgnoreCase(scheme)) {
+ return 21;
+ } else if (HTTP.equalsIgnoreCase(scheme)) {
+ return 80;
+ } else {
+ return 443; // https
+ }
+ }
+
+ static int segmentCompare(String uriPath, String m) {
+ // Precondition: !uriPath.isEmpty() && !m.isEmpty(),and u must already
+ // be normalized
+ String matchPath = normalize(m);
+ if (matchPath == null || !uriPath.startsWith(matchPath)) {
+ return -1;
+ }
+ // We can match only on a segment boundary: either both paths are equal,
+ // or if matchPath does not end in '/', there is a '/' in uriPath right
+ // after the match.
+ int uLength = uriPath.length();
+ int mLength = matchPath.length();
+ if (mLength == uLength || matchPath.charAt(mLength - 1) == '/'
+ || mLength < uLength && uriPath.charAt(mLength) == '/') {
+ return mLength;
+ }
+ return -1;
+ }
+
+ static String normalize(String path) {
+ // C-git resolves . and .. segments
+ int i = 0;
+ int length = path.length();
+ StringBuilder builder = new StringBuilder(length);
+ builder.append('/');
+ if (length > 0 && path.charAt(0) == '/') {
+ i = 1;
+ }
+ while (i < length) {
+ int slash = path.indexOf('/', i);
+ if (slash < 0) {
+ slash = length;
+ }
+ if (slash == i || slash == i + 1 && path.charAt(i) == '.') {
+ // Skip /. or also double slashes
+ } else if (slash == i + 2 && path.charAt(i) == '.'
+ && path.charAt(i + 1) == '.') {
+ // Remove previous segment if we have "/.."
+ int l = builder.length() - 2; // Skip terminating slash.
+ while (l >= 0 && builder.charAt(l) != '/') {
+ l--;
+ }
+ if (l < 0) {
+ LOG.warn(MessageFormat.format(
+ JGitText.get().httpConfigCannotNormalizeURL, path));
+ return null;
+ }
+ builder.setLength(l + 1);
+ } else {
+ // Include the slash, if any
+ builder.append(path, i, Math.min(length, slash + 1));
+ }
+ i = slash + 1;
+ }
+ if (builder.length() > 1 && builder.charAt(builder.length() - 1) == '/'
+ && length > 0 && path.charAt(length - 1) != '/') {
+ // . or .. normalization left a trailing slash when the original
+ // path had none at the end
+ builder.setLength(builder.length() - 1);
+ }
+ return builder.toString();
+ }
+}
import java.util.Map;
import java.util.Set;
import java.util.TreeMap;
-import java.util.function.Supplier;
import java.util.zip.GZIPInputStream;
import java.util.zip.GZIPOutputStream;
import org.eclipse.jgit.errors.TransportException;
import org.eclipse.jgit.internal.JGitText;
import org.eclipse.jgit.internal.storage.file.RefDirectory;
-import org.eclipse.jgit.lib.Config;
import org.eclipse.jgit.lib.Constants;
import org.eclipse.jgit.lib.ObjectId;
import org.eclipse.jgit.lib.ObjectIdRef;
import org.eclipse.jgit.lib.Repository;
import org.eclipse.jgit.lib.SymbolicRef;
import org.eclipse.jgit.transport.HttpAuthMethod.Type;
+import org.eclipse.jgit.transport.HttpConfig.HttpRedirectMode;
import org.eclipse.jgit.transport.http.HttpConnection;
import org.eclipse.jgit.util.HttpSupport;
import org.eclipse.jgit.util.IO;
import org.eclipse.jgit.util.RawParseUtils;
-import org.eclipse.jgit.util.SystemReader;
import org.eclipse.jgit.util.TemporaryBuffer;
import org.eclipse.jgit.util.io.DisabledOutputStream;
import org.eclipse.jgit.util.io.UnionInputStream;
private static final String SVC_RECEIVE_PACK = "git-receive-pack"; //$NON-NLS-1$
- private static final String MAX_REDIRECT_SYSTEM_PROPERTY = "http.maxRedirects"; //$NON-NLS-1$
-
- private static final int DEFAULT_MAX_REDIRECTS = 5;
-
- private static final int MAX_REDIRECTS = (new Supplier<Integer>() {
-
- @Override
- public Integer get() {
- String rawValue = SystemReader.getInstance()
- .getProperty(MAX_REDIRECT_SYSTEM_PROPERTY);
- Integer value = Integer.valueOf(DEFAULT_MAX_REDIRECTS);
- if (rawValue != null) {
- try {
- value = Integer.valueOf(Integer.parseUnsignedInt(rawValue));
- } catch (NumberFormatException e) {
- LOG.warn(MessageFormat.format(
- JGitText.get().invalidSystemProperty,
- MAX_REDIRECT_SYSTEM_PROPERTY, rawValue, value));
- }
- }
- return value;
- }
- }).get().intValue();
-
/**
* Accept-Encoding header in the HTTP request
* (https://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html).
}
};
- /**
- * Config values for http.followRedirect
- */
- private static enum HttpRedirectMode implements Config.ConfigEnum {
-
- /** Always follow redirects (up to the http.maxRedirects limit). */
- TRUE("true"), //$NON-NLS-1$
- /**
- * Only follow redirects on the initial GET request. This is the
- * default.
- */
- INITIAL("initial"), //$NON-NLS-1$
- /** Never follow redirects. */
- FALSE("false"); //$NON-NLS-1$
-
- private final String configValue;
-
- private HttpRedirectMode(String configValue) {
- this.configValue = configValue;
- }
-
- @Override
- public String toConfigValue() {
- return configValue;
- }
-
- @Override
- public boolean matchConfigValue(String s) {
- return configValue.equals(s);
- }
- }
-
- private static class HttpConfig {
- final int postBuffer;
-
- final boolean sslVerify;
-
- final HttpRedirectMode followRedirects;
-
- final int maxRedirects;
-
- HttpConfig(final Config rc) {
- postBuffer = rc.getInt("http", "postbuffer", 1 * 1024 * 1024); //$NON-NLS-1$ //$NON-NLS-2$
- sslVerify = rc.getBoolean("http", "sslVerify", true); //$NON-NLS-1$ //$NON-NLS-2$
- followRedirects = rc.getEnum(HttpRedirectMode.values(), "http", //$NON-NLS-1$
- null, "followRedirects", HttpRedirectMode.INITIAL); //$NON-NLS-1$
- int redirectLimit = rc.getInt("http", "maxRedirects", //$NON-NLS-1$ //$NON-NLS-2$
- MAX_REDIRECTS);
- if (redirectLimit < 0) {
- redirectLimit = MAX_REDIRECTS;
- }
- maxRedirects = redirectLimit;
- }
-
- HttpConfig() {
- this(new Config());
- }
- }
-
/**
* The current URI we're talking to. The inherited (final) field
* {@link #uri} stores the original URI; {@code currentUri} may be different
throws NotSupportedException {
super(local, uri);
setURI(uri);
- http = local.getConfig().get(HttpConfig::new);
+ http = new HttpConfig(local.getConfig(), uri);
proxySelector = ProxySelector.getDefault();
}
TransportHttp(final URIish uri) throws NotSupportedException {
super(uri);
setURI(uri);
- http = new HttpConfig();
+ http = new HttpConfig(uri);
proxySelector = ProxySelector.getDefault();
}
// SEE_OTHER should actually never be sent by a git server,
// and in general should occur only on POST requests. But it
// doesn't hurt to accept it here as a redirect.
- if (http.followRedirects == HttpRedirectMode.FALSE) {
+ if (http.getFollowRedirects() == HttpRedirectMode.FALSE) {
throw new TransportException(uri,
MessageFormat.format(
JGitText.get().redirectsOff,
MessageFormat.format(JGitText.get().redirectLocationMissing,
baseUrl));
}
- if (redirects >= http.maxRedirects) {
+ if (redirects >= http.getMaxRedirects()) {
throw new TransportException(uri,
MessageFormat.format(JGitText.get().redirectLimitExceeded,
- Integer.valueOf(http.maxRedirects), baseUrl, location));
+ Integer.valueOf(http.getMaxRedirects()), baseUrl,
+ location));
}
try {
if (!isValidRedirect(baseUrl, location, checkFor)) {
final Proxy proxy = HttpSupport.proxyFor(proxySelector, u);
HttpConnection conn = connectionFactory.create(u, proxy);
- if (!http.sslVerify && "https".equals(u.getProtocol())) { //$NON-NLS-1$
+ if (!http.isSslVerify() && "https".equals(u.getProtocol())) { //$NON-NLS-1$
HttpSupport.disableSslVerify(conn);
}
void sendRequest() throws IOException {
// Try to compress the content, but only if that is smaller.
- TemporaryBuffer buf = new TemporaryBuffer.Heap(http.postBuffer);
+ TemporaryBuffer buf = new TemporaryBuffer.Heap(
+ http.getPostBuffer());
try {
GZIPOutputStream gzip = new GZIPOutputStream(buf);
out.writeTo(gzip, null);
// SEE_OTHER after a POST doesn't make sense for a git
// server, so we don't handle it here and thus we'll
// report an error in openResponse() later on.
- if (http.followRedirects != HttpRedirectMode.TRUE) {
+ if (http.getFollowRedirects() != HttpRedirectMode.TRUE) {
// Let openResponse() issue an error
return;
}
class HttpOutputStream extends TemporaryBuffer {
HttpOutputStream() {
- super(http.postBuffer);
+ super(http.getPostBuffer());
}
@Override