Author: ivaynberg
Date: Tue Dec 6 01:06:38 2011
New Revision: 1210730
URL: http://svn.apache.org/viewvc?rev=1210730&view=rev
Log:
made https mapper more customizable, and the code simpler and easier to follow
Added:
wicket/trunk/wicket-core/src/main/java/org/apache/wicket/protocol/https/Scheme.java
wicket/trunk/wicket-core/src/test/java/org/apache/wicket/protocol/https/HttpsMapperTest.java
Removed:
wicket/trunk/wicket-core/src/main/java/org/apache/wicket/protocol/https/HttpsRequestChecker.java
wicket/trunk/wicket-core/src/main/java/org/apache/wicket/protocol/https/Protocol.java
wicket/trunk/wicket-core/src/main/java/org/apache/wicket/protocol/https/SwitchProtocolRequestHandler.java
wicket/trunk/wicket-core/src/test/java/org/apache/wicket/protocol/https/HttpsRequestCheckerTest.java
wicket/trunk/wicket-core/src/test/java/org/apache/wicket/protocol/https/SwitchProtocolRequestHandlerTest.java
Modified:
wicket/trunk/wicket-core/src/main/java/org/apache/wicket/protocol/https/HttpsConfig.java
wicket/trunk/wicket-core/src/main/java/org/apache/wicket/protocol/https/HttpsMapper.java
wicket/trunk/wicket-core/src/test/java/org/apache/wicket/protocol/https/HttpsMapperApplicationTest.java
Modified:
wicket/trunk/wicket-core/src/main/java/org/apache/wicket/protocol/https/HttpsConfig.java
URL:
http://svn.apache.org/viewvc/wicket/trunk/wicket-core/src/main/java/org/apache/wicket/protocol/https/HttpsConfig.java?rev=1210730&r1=1210729&r2=1210730&view=diff
==============================================================================
---
wicket/trunk/wicket-core/src/main/java/org/apache/wicket/protocol/https/HttpsConfig.java
(original)
+++
wicket/trunk/wicket-core/src/main/java/org/apache/wicket/protocol/https/HttpsConfig.java
Tue Dec 6 01:06:38 2011
@@ -101,8 +101,8 @@ public class HttpsConfig
}
/**
- * Sets whether or not a new session is created before redirecting from
{@code http} to {@code
- * https}
+ * Sets whether or not a new session is created before redirecting from
{@code http} to
+ * {@code https}
* <p>
* BE VERY CAREFUL WHEN SETTING THIS VALUE TO {@code false}.
*
Modified:
wicket/trunk/wicket-core/src/main/java/org/apache/wicket/protocol/https/HttpsMapper.java
URL:
http://svn.apache.org/viewvc/wicket/trunk/wicket-core/src/main/java/org/apache/wicket/protocol/https/HttpsMapper.java?rev=1210730&r1=1210729&r2=1210730&view=diff
==============================================================================
---
wicket/trunk/wicket-core/src/main/java/org/apache/wicket/protocol/https/HttpsMapper.java
(original)
+++
wicket/trunk/wicket-core/src/main/java/org/apache/wicket/protocol/https/HttpsMapper.java
Tue Dec 6 01:06:38 2011
@@ -1,27 +1,19 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
package org.apache.wicket.protocol.https;
+import javax.servlet.http.HttpServletRequest;
+
import org.apache.wicket.Session;
+import org.apache.wicket.request.IRequestCycle;
import org.apache.wicket.request.IRequestHandler;
import org.apache.wicket.request.IRequestMapper;
import org.apache.wicket.request.Request;
import org.apache.wicket.request.Url;
-import org.apache.wicket.util.lang.Args;
+import org.apache.wicket.request.component.IRequestablePage;
+import org.apache.wicket.request.cycle.RequestCycle;
+import org.apache.wicket.request.handler.IPageClassRequestHandler;
+import org.apache.wicket.request.http.WebRequest;
+import org.apache.wicket.request.http.WebResponse;
+import org.apache.wicket.util.collections.ClassMetaCache;
/**
* A {@link IRequestMapper} that will issue a redirect to secured
communication (over https) if the
@@ -49,94 +41,290 @@ import org.apache.wicket.util.lang.Args;
*
* any request to <em>http://hostname:httpPort/secured</em> will be redirected
to
* <em>https://hostname:httpsPort/secured</em>
+ *
+ * @author igor
*/
public class HttpsMapper implements IRequestMapper
{
+ private final HttpsConfig config;
+ private final IRequestMapper delegate;
+ private final ClassMetaCache<Scheme> cache = new
ClassMetaCache<Scheme>();
+
/**
- * The original request mapper that will actually resolve the page
+ * Constructor
+ *
+ * @param delegate
+ * @param config
*/
- private final IRequestMapper delegate;
+ public HttpsMapper(IRequestMapper delegate, HttpsConfig config)
+ {
+ this.delegate = delegate;
+ this.config = config;
+ }
+
+ @Override
+ public final int getCompatibilityScore(Request request)
+ {
+ return delegate.getCompatibilityScore(request);
+ }
+
+
+ @Override
+ public final IRequestHandler mapRequest(Request request)
+ {
+ IRequestHandler handler = delegate.mapRequest(request);
+
+ Scheme desired = getDesiredSchemeFor(handler);
+ Scheme current = getSchemeOf(request);
+ if (!desired.isCompatibleWith(current))
+ {
+ // we are currently on the wrong scheme for this handler
+
+ // construct a url for the handler on the correct scheme
+ String url = createRedirectUrl(handler, request,
desired);
+
+ // replace handler with one that will redirect to the
created url
+ handler = createRedirectHandler(url);
+ }
+ return handler;
+ }
+
+ @Override
+ public final Url mapHandler(IRequestHandler handler)
+ {
+ return mapHandler(handler, RequestCycle.get().getRequest());
+ }
/**
- * The object that brings the settings for communication over https
+ * Creates the {@link IRequestHandler} that will be responsible for the
redirect
+ *
+ * @param url
+ * @return request handler
*/
- private final HttpsConfig httpsConfig;
+ protected IRequestHandler createRedirectHandler(String url)
+ {
+ return new RedirectHandler(url, config);
+ }
/**
- * A helper that will check the resolved page for @{@link RequireHttps}
annotation
+ * Construts a redirect url that should switch the user to the
specified {@code scheme}
+ *
+ * @param handler
+ * request handler being accessed
+ * @param request
+ * current request
+ * @param scheme
+ * desired scheme for the redirect url
+ * @return url
*/
- private final HttpsRequestChecker checker;
+ protected String createRedirectUrl(IRequestHandler handler, Request
request, Scheme scheme)
+ {
+ HttpServletRequest req =
(HttpServletRequest)((WebRequest)request).getContainerRequest();
+ String url = scheme.urlName() + "://";
+ url += req.getServerName();
+ if (!scheme.usesStandardPort(config))
+ {
+ url += ":" + scheme.getPort(config);
+ }
+ url += req.getRequestURI();
+ if (req.getQueryString() != null)
+ {
+ url += "?" + req.getQueryString();
+ }
+ return url;
+ }
+
/**
- * Construct.
+ * Creates a url for the handler. Modifies it with the correct {@link
Scheme} if necessary.
*
- * @param delegate
- * @param httpsConfig
+ * @param handler
+ * @param request
+ * @return url
*/
- public HttpsMapper(final IRequestMapper delegate, final HttpsConfig
httpsConfig)
+ final Url mapHandler(IRequestHandler handler, Request request)
{
- Args.notNull(delegate, "delegate");
- Args.notNull(httpsConfig, "httpsConfig");
+ Url url = delegate.mapHandler(handler);
- this.delegate = delegate;
- this.httpsConfig = httpsConfig;
- checker = new HttpsRequestChecker();
+ Scheme desired = getDesiredSchemeFor(handler);
+ Scheme current = getSchemeOf(request);
+ if (!desired.isCompatibleWith(current))
+ {
+ // the generated url does not have the correct scheme,
set it (which in turn will cause
+ // the url to be rendered in its full representation)
+ url.setProtocol(desired.urlName());
+ if (url.getPort() != null ||
!desired.usesStandardPort(config))
+ {
+ url.setPort(desired.getPort(config));
+ }
+ }
+ return url;
}
+
/**
- * {@inheritDoc}
+ * Figures out which {@link Scheme} should be used to access the
request handler
+ *
+ * @param handler
+ * request handler
+ * @return {@link Scheme}
*/
- @Override
- public IRequestHandler mapRequest(final Request request)
+ protected Scheme getDesiredSchemeFor(IRequestHandler handler)
+ {
+ if (handler instanceof IPageClassRequestHandler)
+ {
+ return
getDesiredSchemeFor(((IPageClassRequestHandler)handler).getPageClass());
+ }
+ return Scheme.ANY;
+ }
+
+ /**
+ * Determines the {@link Scheme} of the request
+ *
+ * @param url
+ * @param request
+ * @throws IlelgalStateException
+ * if protocol cannot be determined
+ * @return {@link Scheme#HTTPS} or {@link Scheme#HTTP}
+ */
+ protected Scheme getSchemeOf(Request request)
{
- IRequestHandler requestHandler = delegate.mapRequest(request);
+ HttpServletRequest req =
(HttpServletRequest)((WebRequest)request).getContainerRequest();
- if (requestHandler != null)
+ if ("https".equalsIgnoreCase(req.getScheme()))
{
- final IRequestHandler httpsHandler =
checker.checkSecureIncoming(requestHandler,
- httpsConfig);
+ return Scheme.HTTPS;
+ }
+ else if ("http".equalsIgnoreCase(req.getScheme()))
+ {
+ return Scheme.HTTP;
+ }
+ else
+ {
+ throw new IllegalStateException("Could not resolve
protocol for request: " + req);
+ }
+ }
- // XXX do we need to check if httpsHandler is instance
of SwitchProtocolRequestHandler
- if (httpsConfig.isPreferStateful())
+ /**
+ * Determines which {@link Scheme} should be used to access the page
+ *
+ * @param pageClass
+ * type of page
+ * @return {@link Scheme}
+ */
+ protected Scheme getDesiredSchemeFor(Class<? extends IRequestablePage>
pageClass)
+ {
+ Scheme SCHEME = cache.get(pageClass);
+ if (SCHEME == null)
+ {
+ if (hasSecureAnnotation(pageClass))
{
- // we need to persist the session before a
redirect to https so the session lasts
- // across both http and https calls.
- Session.get().bind();
+ SCHEME = Scheme.HTTPS;
}
-
- requestHandler = httpsHandler;
+ else
+ {
+ SCHEME = Scheme.HTTP;
+ }
+ cache.put(pageClass, SCHEME);
}
+ return SCHEME;
+ }
- return requestHandler;
+ /**
+ * @return config with which this mapper was created
+ */
+ public final HttpsConfig getConfig()
+ {
+ return config;
}
/**
- * {@inheritDoc}
+ * Checks if the specified {@code type} has the {@link RequireHttps}
annotation
+ *
+ * @param type
+ * @return {@code true} iff {@code type} has the {@link RequireHttps}
annotation
*/
- @Override
- public int getCompatibilityScore(final Request request)
+ private boolean hasSecureAnnotation(Class<?> type)
{
- return delegate.getCompatibilityScore(request);
+ if (type.getAnnotation(RequireHttps.class) != null)
+ {
+ return true;
+ }
+
+ for (Class<?> iface : type.getInterfaces())
+ {
+ if (hasSecureAnnotation(iface))
+ {
+ return true;
+ }
+ }
+
+ if (type.getSuperclass() != null)
+ {
+ return hasSecureAnnotation(type.getSuperclass());
+ }
+ return false;
}
+
/**
- * {@inheritDoc}
+ * Handler that takes care of redirecting
+ *
+ * @author igor
*/
- @Override
- public Url mapHandler(IRequestHandler requestHandler)
+ public static class RedirectHandler implements IRequestHandler
{
- Url url = delegate.mapHandler(requestHandler);
- switch (checker.getProtocol(requestHandler))
+ private final String url;
+ private final HttpsConfig config;
+
+ /**
+ * Constructor
+ *
+ * @param config
+ * https config
+ * @param url
+ * redirect location
+ */
+ public RedirectHandler(String url, HttpsConfig config)
{
- case HTTP :
- url.setProtocol("http");
- url.setPort(httpsConfig.getHttpPort());
- break;
- case HTTPS :
- url.setProtocol("https");
- url.setPort(httpsConfig.getHttpsPort());
- break;
+ this.url = url;
+ this.config = config;
}
- return url;
+
+ /**
+ * @return redirect location
+ */
+ public String getUrl()
+ {
+ return url;
+ }
+
+ @Override
+ public void respond(IRequestCycle requestCycle)
+ {
+ String location = url.toString();
+
+ if (location.startsWith("/"))
+ {
+ // context-absolute url
+ location =
requestCycle.getUrlRenderer().renderContextRelativeUrl(location);
+ }
+
+ if (config.isPreferStateful())
+ {
+ // we need to persist the session before a
redirect to https so the session lasts
+ // across both http and https calls.
+ Session.get().bind();
+ }
+
+ WebResponse response =
(WebResponse)requestCycle.getResponse();
+ response.sendRedirect(location);
+ }
+
+ @Override
+ public void detach(IRequestCycle requestCycle)
+ {
+ }
+
}
}
Added:
wicket/trunk/wicket-core/src/main/java/org/apache/wicket/protocol/https/Scheme.java
URL:
http://svn.apache.org/viewvc/wicket/trunk/wicket-core/src/main/java/org/apache/wicket/protocol/https/Scheme.java?rev=1210730&view=auto
==============================================================================
---
wicket/trunk/wicket-core/src/main/java/org/apache/wicket/protocol/https/Scheme.java
(added)
+++
wicket/trunk/wicket-core/src/main/java/org/apache/wicket/protocol/https/Scheme.java
Tue Dec 6 01:06:38 2011
@@ -0,0 +1,88 @@
+package org.apache.wicket.protocol.https;
+
+/**
+ * Url scheme
+ *
+ * @author igor
+ */
+enum Scheme {
+ /** https */
+ HTTPS {
+ @Override
+ public boolean usesStandardPort(HttpsConfig config)
+ {
+ return getPort(config) == 443;
+ }
+
+ @Override
+ public int getPort(HttpsConfig config)
+ {
+ return config.getHttpsPort();
+ }
+ },
+ /** http */
+ HTTP {
+ @Override
+ public boolean usesStandardPort(HttpsConfig config)
+ {
+ return getPort(config) == 80;
+ }
+
+ @Override
+ public int getPort(HttpsConfig config)
+ {
+ return config.getHttpPort();
+ }
+ },
+ /** any, aka preserve current */
+ ANY {
+ @Override
+ public String urlName()
+ {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public boolean isCompatibleWith(Scheme other)
+ {
+ return true;
+ }
+
+ @Override
+ public boolean usesStandardPort(HttpsConfig config)
+ {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public int getPort(HttpsConfig config)
+ {
+ throw new UnsupportedOperationException();
+ }
+ };
+
+
+ /**
+ * @return scheme's url name
+ */
+ public String urlName()
+ {
+ return name().toLowerCase();
+ }
+
+ /**
+ * Checks if two schemes are compatible. Compatible schemes do not
require a redirect from the
+ * current scheme to the {@code other}.
+ *
+ * @param other
+ * @return {@code true} iff the schemes are compatible.
+ */
+ public boolean isCompatibleWith(Scheme other)
+ {
+ return this == other;
+ }
+
+ public abstract boolean usesStandardPort(HttpsConfig config);
+
+ public abstract int getPort(HttpsConfig config);
+}
Modified:
wicket/trunk/wicket-core/src/test/java/org/apache/wicket/protocol/https/HttpsMapperApplicationTest.java
URL:
http://svn.apache.org/viewvc/wicket/trunk/wicket-core/src/test/java/org/apache/wicket/protocol/https/HttpsMapperApplicationTest.java?rev=1210730&r1=1210729&r2=1210730&view=diff
==============================================================================
---
wicket/trunk/wicket-core/src/test/java/org/apache/wicket/protocol/https/HttpsMapperApplicationTest.java
(original)
+++
wicket/trunk/wicket-core/src/test/java/org/apache/wicket/protocol/https/HttpsMapperApplicationTest.java
Tue Dec 6 01:06:38 2011
@@ -28,7 +28,7 @@ import org.junit.Test;
*/
public class HttpsMapperApplicationTest
{
- @SuppressWarnings({"unchecked"})
+ @SuppressWarnings({ "unchecked" })
private <T extends Page> T requestPage(WicketTester tester, Class<T>
pageClass)
{
Page page = tester.startPage(pageClass);
@@ -43,11 +43,10 @@ public class HttpsMapperApplicationTest
public void switchDefaultToHttpsWithDefaultPorts()
{
WicketTester tester = new WicketTester(new
HttpsMapperApplication());
-
+
requestPage(tester, HttpsPage.class);
-
+
assertEquals("https", tester.getLastRequest().getScheme());
- assertEquals(443, tester.getLastRequest().getServerPort());
}
@Test
@@ -68,11 +67,10 @@ public class HttpsMapperApplicationTest
tester.getRequest().setScheme("https");
tester.getRequest().setServerPort(443);
-
+
requestPage(tester, HttpPage.class);
-
+
assertEquals("http", tester.getLastRequest().getScheme());
- assertEquals(80, tester.getLastRequest().getServerPort());
}
@Test
@@ -126,7 +124,7 @@ public class HttpsMapperApplicationTest
assertEquals("https", tester.getLastRequest().getScheme());
assertEquals(443, tester.getLastRequest().getServerPort());
-
+
assertEquals("https", tester.getRequest().getScheme());
assertEquals(443, tester.getRequest().getServerPort());
}
Added:
wicket/trunk/wicket-core/src/test/java/org/apache/wicket/protocol/https/HttpsMapperTest.java
URL:
http://svn.apache.org/viewvc/wicket/trunk/wicket-core/src/test/java/org/apache/wicket/protocol/https/HttpsMapperTest.java?rev=1210730&view=auto
==============================================================================
---
wicket/trunk/wicket-core/src/test/java/org/apache/wicket/protocol/https/HttpsMapperTest.java
(added)
+++
wicket/trunk/wicket-core/src/test/java/org/apache/wicket/protocol/https/HttpsMapperTest.java
Tue Dec 6 01:06:38 2011
@@ -0,0 +1,219 @@
+package org.apache.wicket.protocol.https;
+
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.hamcrest.Matchers.instanceOf;
+import static org.hamcrest.Matchers.is;
+import static org.hamcrest.Matchers.nullValue;
+import static org.hamcrest.Matchers.sameInstance;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.reset;
+import static org.mockito.Mockito.when;
+
+import javax.servlet.http.HttpServletRequest;
+
+import org.apache.wicket.Page;
+import org.apache.wicket.protocol.http.servlet.ServletWebRequest;
+import org.apache.wicket.protocol.https.HttpsMapper.RedirectHandler;
+import org.apache.wicket.request.IRequestHandler;
+import org.apache.wicket.request.IRequestMapper;
+import org.apache.wicket.request.Url;
+import org.apache.wicket.request.handler.PageProvider;
+import org.apache.wicket.request.handler.RenderPageRequestHandler;
+import org.junit.Test;
+
+public class HttpsMapperTest
+{
+ @Test
+ public void getDesiredSchemeOfPageClass()
+ {
+ IRequestMapper delegate = mock(IRequestMapper.class);
+ HttpsMapper mapper = new HttpsMapper(delegate, new
HttpsConfig());
+
+ assertThat(mapper.getDesiredSchemeFor(SecurePage.class),
is(Scheme.HTTPS));
+
assertThat(mapper.getDesiredSchemeFor(SecureDecendantPage.class),
is(Scheme.HTTPS));
+ assertThat(mapper.getDesiredSchemeFor(SecureMixinPage.class),
is(Scheme.HTTPS));
+ assertThat(mapper.getDesiredSchemeFor(InsecurePage.class),
is(Scheme.HTTP));
+ }
+
+ @Test
+ public void getDesiredSchemeOfHandler()
+ {
+ IRequestMapper delegate = mock(IRequestMapper.class);
+ HttpsMapper mapper = new HttpsMapper(delegate, new
HttpsConfig());
+
+ IRequestHandler handler = new RenderPageRequestHandler(new
PageProvider(SecurePage.class));
+ assertThat(mapper.getDesiredSchemeFor(handler),
is(Scheme.HTTPS));
+
+ handler = new RenderPageRequestHandler(new
PageProvider(InsecurePage.class));
+ assertThat(mapper.getDesiredSchemeFor(handler),
is(Scheme.HTTP));
+
+ handler = mock(IRequestHandler.class);
+ assertThat(mapper.getDesiredSchemeFor(handler), is(Scheme.ANY));
+ }
+
+ @Test
+ public void getSchemeOfRequest()
+ {
+ IRequestMapper delegate = mock(IRequestMapper.class);
+ HttpsMapper mapper = new HttpsMapper(delegate, new
HttpsConfig());
+
+ ServletWebRequest request = mock(ServletWebRequest.class);
+ HttpServletRequest req = mock(HttpServletRequest.class);
+ when(request.getContainerRequest()).thenReturn(req);
+
+ when(req.getScheme()).thenReturn("https");
+ assertThat(mapper.getSchemeOf(request), is(Scheme.HTTPS));
+
+ reset(req);
+ when(req.getScheme()).thenReturn("hTTps");
+ assertThat(mapper.getSchemeOf(request), is(Scheme.HTTPS));
+
+ reset(req);
+ when(req.getScheme()).thenReturn("http");
+ assertThat(mapper.getSchemeOf(request), is(Scheme.HTTP));
+
+ try
+ {
+ reset(req);
+ when(req.getScheme()).thenReturn("ftp");
+ mapper.getSchemeOf(request);
+ assertThat("expected error", false);
+ }
+ catch (IllegalStateException e)
+ { // expected
+
+ }
+ }
+
+ @Test
+ public void mapHandler()
+ {
+ IRequestMapper delegate = mock(IRequestMapper.class);
+ HttpsMapper mapper = new HttpsMapper(delegate, new
HttpsConfig());
+
+ ServletWebRequest request = mock(ServletWebRequest.class);
+ HttpServletRequest req = mock(HttpServletRequest.class);
+ when(request.getContainerRequest()).thenReturn(req);
+
+ // rendering url to https page on http, set protocol
+ IRequestHandler handler = new RenderPageRequestHandler(new
PageProvider(SecurePage.class));
+ Url url = new Url();
+ when(delegate.mapHandler(handler)).thenReturn(url);
+ when(req.getScheme()).thenReturn("http");
+ mapper.mapHandler(handler, request);
+ assertThat(url.getProtocol(), is("https"));
+
+ // render url to http page on http, ignore protocol
+ handler = new RenderPageRequestHandler(new
PageProvider(InsecurePage.class));
+ url = new Url();
+ reset(delegate);
+ when(delegate.mapHandler(handler)).thenReturn(url);
+ when(req.getScheme()).thenReturn("http");
+ mapper.mapHandler(handler, request);
+ assertThat(url.getProtocol(), is(nullValue()));
+
+ // render url to http page on https, set protocol
+ handler = new RenderPageRequestHandler(new
PageProvider(InsecurePage.class));
+ url = new Url();
+ reset(delegate);
+ when(delegate.mapHandler(handler)).thenReturn(url);
+ when(req.getScheme()).thenReturn("https");
+ mapper.mapHandler(handler, request);
+ assertThat(url.getProtocol(), is("http"));
+ }
+
+
+ @Test
+ public void mapRequest()
+ {
+ IRequestMapper delegate = mock(IRequestMapper.class);
+ HttpsMapper mapper = new HttpsMapper(delegate, new
HttpsConfig());
+
+ ServletWebRequest request = mock(ServletWebRequest.class);
+ HttpServletRequest req = mock(HttpServletRequest.class);
+ when(request.getContainerRequest()).thenReturn(req);
+
+ // https handler on http request, redirect to https
+ setupRequest(req, "http", "localhost", 80, "/ctx", "foo=bar");
+ IRequestHandler handler = new RenderPageRequestHandler(new
PageProvider(SecurePage.class));
+ when(delegate.mapRequest(request)).thenReturn(handler);
+ IRequestHandler resolved = mapper.mapRequest(request);
+ assertThat(resolved, is(instanceOf(RedirectHandler.class)));
+ assertThat(((RedirectHandler)resolved).getUrl(),
is("https://localhost/ctx?foo=bar"));
+
+ // http handler on http request, return the original handler
+ handler = new RenderPageRequestHandler(new
PageProvider(InsecurePage.class));
+ reset(delegate);
+ when(delegate.mapRequest(request)).thenReturn(handler);
+ setupRequest(req, "http", "localhost", 80, "/ctx", "foo=bar");
+ resolved = mapper.mapRequest(request);
+ assertThat(resolved, is(sameInstance(handler)));
+ }
+
+ @Test
+ public void mapRequestWithCustomPorts()
+ {
+ IRequestMapper delegate = mock(IRequestMapper.class);
+ HttpsMapper mapper = new HttpsMapper(delegate, new
HttpsConfig(10, 20));
+
+ ServletWebRequest request = mock(ServletWebRequest.class);
+ HttpServletRequest req = mock(HttpServletRequest.class);
+ when(request.getContainerRequest()).thenReturn(req);
+
+ // https handler on http request, redirect to https
+ setupRequest(req, "http", "localhost", 10, "/ctx", "foo=bar");
+ IRequestHandler handler = new RenderPageRequestHandler(new
PageProvider(SecurePage.class));
+ when(delegate.mapRequest(request)).thenReturn(handler);
+ IRequestHandler resolved = mapper.mapRequest(request);
+ assertThat(resolved, is(instanceOf(RedirectHandler.class)));
+ assertThat(((RedirectHandler)resolved).getUrl(),
is("https://localhost:20/ctx?foo=bar"));
+
+ // http handler on http request, return the original handler
+ handler = new RenderPageRequestHandler(new
PageProvider(InsecurePage.class));
+ reset(delegate);
+ when(delegate.mapRequest(request)).thenReturn(handler);
+ setupRequest(req, "https", "localhost", 20, "/ctx", "foo=bar");
+ resolved = mapper.mapRequest(request);
+ assertThat(resolved, is(instanceOf(RedirectHandler.class)));
+ assertThat(((RedirectHandler)resolved).getUrl(),
is("http://localhost:10/ctx?foo=bar"));
+ }
+
+ private static void setupRequest(HttpServletRequest mock, String
scheme, String host, int port,
+ String uri, String query)
+ {
+ reset(mock);
+ when(mock.getScheme()).thenReturn(scheme);
+ when(mock.getServerName()).thenReturn(host);
+ when(mock.getServerPort()).thenReturn(port);
+ when(mock.getRequestURI()).thenReturn(uri);
+ when(mock.getQueryString()).thenReturn(query);
+ }
+
+
+ @RequireHttps
+ private static class SecurePage extends Page
+ {
+
+ }
+
+ private static class InsecurePage extends Page
+ {
+
+ }
+
+ @RequireHttps
+ private static interface Secured
+ {
+
+ }
+
+ private static class SecureDecendantPage extends SecurePage
+ {
+
+ }
+
+ private static class SecureMixinPage extends Page implements Secured
+ {
+
+ }
+}
\ No newline at end of file