/*
* 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.shindig.gadgets.servlet;
import org.apache.commons.codec.binary.Base64;
import org.apache.shindig.common.servlet.HttpServletResponseRecorder;
import org.apache.shindig.common.servlet.HttpUtil;
import org.apache.shindig.common.uri.Uri;
import org.apache.shindig.common.util.FakeTimeSource;
import org.apache.shindig.gadgets.GadgetException;
import org.apache.shindig.gadgets.http.HttpRequest;
import org.apache.shindig.gadgets.http.HttpResponse;
import org.apache.shindig.gadgets.http.HttpResponseBuilder;
import org.easymock.EasyMock;
import org.json.JSONObject;
import org.junit.Test;
import javax.servlet.ServletInputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.util.Arrays;
import java.util.Enumeration;
import java.util.Vector;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNull;
public class ServletUtilTest {
@Test
public void testValidateUrlNoPath() throws Exception {
Uri url = ServletUtil.validateUrl(Uri.parse("http://www.example.com"));
assertEquals("http", url.getScheme());
assertEquals("www.example.com", url.getAuthority());
assertEquals("/", url.getPath());
assertNull(url.getQuery());
assertNull(url.getFragment());
}
@Test
public void testValidateUrlHttps() throws Exception {
Uri url = ServletUtil.validateUrl(Uri.parse("https://www.example.com"));
assertEquals("https", url.getScheme());
assertEquals("www.example.com", url.getAuthority());
assertEquals("/", url.getPath());
assertNull(url.getQuery());
assertNull(url.getFragment());
}
@Test
public void testValidateUrlWithPath() throws Exception {
Uri url = ServletUtil.validateUrl(Uri.parse("http://www.example.com/foo"));
assertEquals("http", url.getScheme());
assertEquals("www.example.com", url.getAuthority());
assertEquals("/foo", url.getPath());
assertNull(url.getQuery());
assertNull(url.getFragment());
}
@Test
public void testValidateUrlWithPort() throws Exception {
Uri url = ServletUtil.validateUrl(Uri.parse("http://www.example.com:8080/foo"));
assertEquals("http", url.getScheme());
assertEquals("www.example.com:8080", url.getAuthority());
assertEquals("/foo", url.getPath());
assertNull(url.getQuery());
assertNull(url.getFragment());
}
@Test
public void testValidateUrlWithEncodedPath() throws Exception {
Uri url = ServletUtil.validateUrl(Uri.parse("http://www.example.com/foo%20bar"));
assertEquals("http", url.getScheme());
assertEquals("www.example.com", url.getAuthority());
assertEquals("/foo%20bar", url.getPath());
assertNull(url.getQuery());
assertNull(url.getFragment());
}
@Test
public void testValidateUrlWithEncodedQuery() throws Exception {
Uri url = ServletUtil.validateUrl(Uri.parse("http://www.example.com/foo?q=with%20space"));
assertEquals("http", url.getScheme());
assertEquals("www.example.com", url.getAuthority());
assertEquals("/foo", url.getPath());
assertEquals("q=with%20space", url.getQuery());
assertEquals("with space", url.getQueryParameter("q"));
assertNull(url.getFragment());
}
@Test
public void testValidateUrlWithNoPathAndEncodedQuery() throws Exception {
Uri url = ServletUtil.validateUrl(Uri.parse("http://www.example.com?q=with%20space"));
assertEquals("http", url.getScheme());
assertEquals("www.example.com", url.getAuthority());
assertEquals("/", url.getPath());
assertEquals("q=with%20space", url.getQuery());
assertNull(url.getFragment());
}
@Test(expected = GadgetException.class)
public void testValidateUrlNullInput() throws Exception {
ServletUtil.validateUrl(null);
}
@Test
public void testOutputDataUri() throws Exception {
checkOutputDataUri("text/foo", "text/foo", "UTF-8");
}
@Test
public void testOutputDataUriWithCharset() throws Exception {
checkOutputDataUri("text/bar; charset=ISO-8859-1", "text/bar", "ISO-8859-1");
}
@Test
public void testOutputDataUriWithEmptyCharset() throws Exception {
checkOutputDataUri("text/bar; charset=", "text/bar", "UTF-8");
}
private void checkOutputDataUri(String contentType, String expectedType,
String expectedEncoding) throws Exception {
String theData = "this is the data";
String mk1 = "meta1", mv1 = "val1";
String mk2 = "'\"}key", mv2 = "val{\"'";
HttpResponse response = new HttpResponseBuilder()
.setResponseString(theData)
.addHeader("Content-Type", contentType)
.setMetadata(mk1, mv1)
.setMetadata(mk2, mv2)
.setMetadata(ServletUtil.DATA_URI_KEY, "foo") // Should be ignored.
.create();
HttpResponse jsonified = ServletUtil.convertToJsonResponse(response);
assertEquals("application/json; charset=UTF-8", jsonified.getHeader("Content-Type"));
String emitted = jsonified.getResponseAsString();
JSONObject js = new JSONObject(emitted);
assertEquals(mv1, js.getString(mk1));
assertEquals(mv2, js.getString(mk2));
String content64 = getBase64(theData);
assertEquals("data:" + expectedType + ";base64;charset=" + expectedEncoding + "," + content64,
js.getString(ServletUtil.DATA_URI_KEY));
}
private String getBase64(String input) throws Exception {
return new String(Base64.encodeBase64(input.getBytes("UTF8")), "UTF8");
}
@Test
public void testFromHttpServletRequest() throws Exception {
HttpServletRequest original = EasyMock.createMock(HttpServletRequest.class);
EasyMock.expect(original.getScheme()).andReturn("https");
EasyMock.expect(original.getServerName()).andReturn("www.example.org");
EasyMock.expect(original.getServerPort()).andReturn(444);
EasyMock.expect(original.getRequestURI()).andReturn("/path/foo");
EasyMock.expect(original.getQueryString()).andReturn("one=two&three=four");
Vector<String> headerNames = new Vector<String>();
headerNames.add("Header1");
headerNames.add("Header2");
EasyMock.expect(original.getHeaderNames()).andReturn(headerNames.elements());
EasyMock.expect(original.getHeaders("Header1"))
.andReturn(makeEnumeration("HVal1", "HVal3"));
EasyMock.expect(original.getHeaders("Header2"))
.andReturn(makeEnumeration("HVal2", "HVal4"));
EasyMock.expect(original.getMethod()).andReturn("post");
final ByteArrayInputStream bais = new ByteArrayInputStream("post body".getBytes());
ServletInputStream sis = new ServletInputStream() {
@Override
public int read() throws IOException {
return bais.read();
}
};
EasyMock.expect(original.getInputStream()).andReturn(sis);
EasyMock.expect(original.getRemoteAddr()).andReturn("1.2.3.4");
EasyMock.replay(original);
HttpRequest request = ServletUtil.fromHttpServletRequest(original);
EasyMock.verify(original);
assertEquals(Uri.parse("https://www.example.org:444/path/foo?one=two&three=four"),
request.getUri());
assertEquals(3, request.getHeaders().size());
assertEquals("HVal1", request.getHeaders("Header1").get(0));
assertEquals("HVal3", request.getHeaders("Header1").get(1));
assertEquals("HVal2", request.getHeaders("Header2").get(0));
assertEquals("HVal4", request.getHeaders("Header2").get(1));
assertEquals("post", request.getMethod());
assertEquals("post body", request.getPostBodyAsString());
assertEquals("1.2.3.4", request.getParam(ServletUtil.REMOTE_ADDR_KEY));
}
@Test
public void testCopyResponseToServlet() throws Exception {
FakeTimeSource fakeTime = new FakeTimeSource();
HttpUtil.setTimeSource(fakeTime);
HttpResponse response = new HttpResponseBuilder()
.setResponseString("response string").setHttpStatusCode(200).addHeader("h1", "v1")
.addHeader("h2", "v2").setCacheTtl(1000).create();
HttpServletResponse servletResponse = EasyMock.createMock(HttpServletResponse.class);
HttpServletResponseRecorder recorder = new HttpServletResponseRecorder(servletResponse);
ServletUtil.copyResponseToServlet(response, recorder);
assertEquals(200, recorder.getHttpStatusCode());
assertEquals("response string", recorder.getResponseAsString());
assertEquals("v1", recorder.getHeader("h1"));
assertEquals("v2", recorder.getHeader("h2"));
assertEquals("public,max-age=1000", recorder.getHeader("Cache-Control"));
}
@Test
public void testCopyResponseToServletNoCache() throws Exception {
HttpResponse response = new HttpResponseBuilder()
.setResponseString("response string").setHttpStatusCode(200).addHeader("h1", "v1")
.addHeader("h2", "v2").setStrictNoCache().create();
HttpServletResponse servletResponse = EasyMock.createMock(HttpServletResponse.class);
HttpServletResponseRecorder recorder = new HttpServletResponseRecorder(servletResponse);
FakeTimeSource fakeTime = new FakeTimeSource();
HttpUtil.setTimeSource(fakeTime);
ServletUtil.copyResponseToServlet(response, recorder);
assertEquals(200, recorder.getHttpStatusCode());
assertEquals("response string", recorder.getResponseAsString());
assertEquals("v1", recorder.getHeader("h1"));
assertEquals("v2", recorder.getHeader("h2"));
assertEquals("no-cache", recorder.getHeader("Pragma"));
assertEquals("no-cache", recorder.getHeader("Cache-Control"));
}
Enumeration<String> makeEnumeration(String... args) {
Vector<String> vector = new Vector<String>();
vector.addAll(Arrays.asList(args));
return vector.elements();
}
}