/*
* 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.request.cycle;
import static org.mockito.Matchers.argThat;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
import org.apache.wicket.core.request.handler.BookmarkablePageRequestHandler;
import org.apache.wicket.mock.MockHomePage;
import org.apache.wicket.request.IExceptionMapper;
import org.apache.wicket.request.IRequestMapper;
import org.apache.wicket.request.Request;
import org.apache.wicket.request.Response;
import org.apache.wicket.request.Url;
import org.apache.wicket.request.handler.resource.ResourceReferenceRequestHandler;
import org.apache.wicket.request.handler.resource.ResourceRequestHandler;
import org.apache.wicket.request.mapper.parameter.PageParameters;
import org.apache.wicket.request.resource.ByteArrayResource;
import org.apache.wicket.request.resource.IResource;
import org.apache.wicket.request.resource.ResourceReference;
import org.apache.wicket.request.resource.caching.IStaticCacheableResource;
import org.apache.wicket.response.StringResponse;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
import org.mockito.ArgumentMatcher;
/**
* Tests that RequestCycle#urlFor() does not encode the jsessionid for static resources.
*
* https://issues.apache.org/jira/browse/WICKET-4334
*/
public class RequestCycleUrlForTest extends Assert
{
private static final String JSESSIONID = ";jsessionid=1234567890";
private static final String BOOKMARKABLE_PAGE_URL = "bookmarkablePage";
private static final String RES_REF_URL = "resRef";
private static final String RESOURCE_URL = "res";
RequestCycle requestCycle;
@Before
public void before()
{
Request request = mock(Request.class);
Url baseUrl = Url.parse("");
when(request.getClientUrl()).thenReturn(baseUrl);
Response response = new StringResponse() {
@Override
public String encodeURL(CharSequence url)
{
return url + JSESSIONID;
}
};
IRequestMapper mapper = mock(IRequestMapper.class);
Url bookmarkablePageUrl = Url.parse(BOOKMARKABLE_PAGE_URL);
when(mapper.mapHandler(argThat(new ExactClassMatcher<BookmarkablePageRequestHandler>(BookmarkablePageRequestHandler.class)))).thenReturn(bookmarkablePageUrl);
Url resourceUrl = Url.parse(RESOURCE_URL);
when(mapper.mapHandler(argThat(new ExactClassMatcher<ResourceRequestHandler>(ResourceRequestHandler.class)))).thenReturn(resourceUrl);
Url resourceReferenceUrl = Url.parse(RES_REF_URL);
when(mapper.mapHandler(argThat(new ExactClassMatcher<ResourceReferenceRequestHandler>(ResourceReferenceRequestHandler.class)))).thenReturn(resourceReferenceUrl);
IExceptionMapper exceptionMapper = mock(IExceptionMapper.class);
RequestCycleContext context = new RequestCycleContext(request, response, mapper, exceptionMapper);
requestCycle = new RequestCycle(context);
requestCycle.getUrlRenderer().setBaseUrl(baseUrl);
}
/**
* Pages should have the jsessionid encoded in the url
*
* @throws Exception
*/
@Test
public void urlForClass() throws Exception
{
CharSequence url = requestCycle.urlFor(MockHomePage.class, new PageParameters());
assertEquals("./bookmarkablePage"+JSESSIONID, url);
}
/**
* ResourceReference with IStaticCacheableResource should not have the jsessionid encoded in the url
*
* @throws Exception
*/
@Test
public void urlForResourceReference() throws Exception
{
final IStaticCacheableResource resource = mock(IStaticCacheableResource.class);
ResourceReference reference = new ResourceReference("dummy")
{
@Override
public IResource getResource()
{
return resource;
}
};
ResourceReferenceRequestHandler handler = new ResourceReferenceRequestHandler(reference);
CharSequence url = requestCycle.urlFor(handler);
assertEquals("./"+RES_REF_URL, url);
}
/**
* ResourceReference with non-IStaticCacheableResource should not have the jsessionid encoded in the url
*
* @throws Exception
*/
@Test
public void urlForResourceReferenceWithNonStaticResource() throws Exception
{
final IResource resource = mock(IResource.class);
ResourceReference reference = new ResourceReference("dummy")
{
@Override
public IResource getResource()
{
return resource;
}
};
ResourceReferenceRequestHandler handler = new ResourceReferenceRequestHandler(reference);
CharSequence url = requestCycle.urlFor(handler);
assertEquals("./"+RES_REF_URL+JSESSIONID, url);
}
/**
* IStaticCacheableResource should not have the jsessionid encoded in the url
*
* @throws Exception
*/
@Test
public void urlForStaticResource() throws Exception
{
IStaticCacheableResource resource = mock(IStaticCacheableResource.class);
ResourceRequestHandler handler = new ResourceRequestHandler(resource, new PageParameters());
CharSequence url = requestCycle.urlFor(handler);
assertEquals("./"+RESOURCE_URL, url);
}
/**
* Non-IStaticCacheableResource should have the jsessionid encoded in the url
*
* @throws Exception
*/
@Test
public void urlForDynamicResource() throws Exception
{
ByteArrayResource resource = new ByteArrayResource(null, new byte[] {1, 2}, "test.bin");
ResourceRequestHandler handler = new ResourceRequestHandler(resource, new PageParameters());
CharSequence url = requestCycle.urlFor(handler);
assertEquals("./"+RESOURCE_URL + JSESSIONID, url);
}
/**
* A matcher that matches only when the object class is exactly the same as the expected one.
*
* @param <T>
* the type of the expected class
*/
private static class ExactClassMatcher<T> implements ArgumentMatcher<T>
{
private final Class<T> targetClass;
public ExactClassMatcher(Class<T> targetClass)
{
this.targetClass = targetClass;
}
@SuppressWarnings("unchecked")
@Override
public boolean matches(Object obj)
{
if (obj != null)
{
return targetClass.equals(obj.getClass());
}
return false;
}
@Override
public String toString()
{
return "Matches a class or subclass";
}
}
}