diff --git a/core/src/main/java/jenkins/model/Jenkins.java b/core/src/main/java/jenkins/model/Jenkins.java index 5a0bd29e4ee9a28877ebf50c1d3d1e8f719751f9..e57ced74c200337982b528396070f0bd881bfdc4 100755 --- a/core/src/main/java/jenkins/model/Jenkins.java +++ b/core/src/main/java/jenkins/model/Jenkins.java @@ -1861,17 +1861,20 @@ public class Jenkins extends AbstractCIBase implements ModifiableTopLevelItemGro * @see #getRootUrlFromRequest() */ public String getRootUrl() { - // for compatibility. the actual data is stored in Mailer + String url = JenkinsLocationConfiguration.get().getUrl(); - if(url!=null) { - if (!url.endsWith("/")) url += '/'; - return url; + if(url!=null && !url.endsWith("/")) { + url += '/'; } StaplerRequest req = Stapler.getCurrentRequest(); - if(req!=null) - return getRootUrlFromRequest(); - return null; + + if(req == null) return url; + + if(url == null) return getRootUrlFromRequest(); + + // replace current protocol, if any, with request protocol + return url.replaceFirst("^\\w+(?=://)", req.getScheme()); } /** diff --git a/core/src/test/java/jenkins/model/JenkinsGetRootUrlTest.java b/core/src/test/java/jenkins/model/JenkinsGetRootUrlTest.java new file mode 100644 index 0000000000000000000000000000000000000000..6aa171a74204942e28d916aa59f004a45bde0404 --- /dev/null +++ b/core/src/test/java/jenkins/model/JenkinsGetRootUrlTest.java @@ -0,0 +1,129 @@ +/* + * The MIT License + * + * Copyright (c) 2013 RedHat Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package jenkins.model; + +import static org.hamcrest.CoreMatchers.equalTo; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.powermock.api.mockito.PowerMockito.mock; +import static org.powermock.api.mockito.PowerMockito.mockStatic; +import static org.powermock.api.mockito.PowerMockito.when; + +import java.net.URL; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.kohsuke.stapler.Stapler; +import org.kohsuke.stapler.StaplerRequest; +import org.mockito.Mockito; +import org.powermock.core.classloader.annotations.PrepareForTest; +import org.powermock.modules.junit4.PowerMockRunner; + +@RunWith(PowerMockRunner.class) +@PrepareForTest({JenkinsLocationConfiguration.class, Stapler.class}) +public class JenkinsGetRootUrlTest { + + private Jenkins jenkins; + private JenkinsLocationConfiguration config; + + @Before + public void setUp() { + + jenkins = mock(Jenkins.class, Mockito.CALLS_REAL_METHODS); + config = mock(JenkinsLocationConfiguration.class); + + mockStatic(JenkinsLocationConfiguration.class); + when(JenkinsLocationConfiguration.get()).thenReturn(config); + + mockStatic(Stapler.class); + } + + @Test + public void getConfiguredRootUrl() { + + configured("http://configured.host"); + + rootUrlIs("http://configured.host/"); + } + + @Test + public void getAccessedRootUrl() { + + accessing("https://real.host/jenkins/"); + + rootUrlIs("https://real.host/jenkins/"); + } + + @Test + public void preferConfiguredOverAccessed() { + + configured("http://configured.host/"); + accessing("http://real.host/"); + + rootUrlIs("http://configured.host/"); + } + + @Test + public void inheritProtocolWhenDispatchingRequest() { + + configured("http://configured.host/"); + accessing("https://real.host/"); + + rootUrlIs("https://configured.host/"); + } + + private void rootUrlIs(final String expectedRootUrl) { + + assertThat(jenkins.getRootUrl(), equalTo(expectedRootUrl)); + } + + private void configured(final String configuredHost) { + + when(config.getUrl()).thenReturn(configuredHost); + } + + private void accessing(final String realUrl) { + + final URL url = getUrl(realUrl); + + final StaplerRequest req = mock(StaplerRequest.class); + when(req.getScheme()).thenReturn(url.getProtocol()); + when(req.getServerName()).thenReturn(url.getHost()); + when(req.getServerPort()).thenReturn(url.getPort() == -1 ? 80 : url.getPort()); + when(req.getContextPath()).thenReturn(url.getPath().replaceAll("/$", "")); + + when(Stapler.getCurrentRequest()).thenReturn(req); + } + + private URL getUrl(final String realUrl) { + + try { + + return new URL(realUrl); + } catch(Exception ex) { + + throw new RuntimeException(ex); + } + } +}