/* * Copyright (C) 2014 Stefan Niederhauser (nidin@gmx.ch) * * Licensed 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 guru.nidi.ramltester; import guru.nidi.ramltester.model.RamlRequest; import guru.nidi.ramltester.model.RamlResponse; import guru.nidi.ramltester.model.Values; import guru.nidi.ramltester.servlet.ServletRamlRequest; import guru.nidi.ramltester.servlet.ServletRamlResponse; import guru.nidi.ramltester.util.FileValue; import guru.nidi.ramltester.util.ServerTest; import org.apache.catalina.Context; import org.apache.catalina.deploy.FilterDef; import org.apache.catalina.deploy.FilterMap; import org.apache.catalina.startup.Tomcat; import org.apache.http.HttpEntity; import org.apache.http.client.entity.UrlEncodedFormEntity; import org.apache.http.client.methods.HttpGet; import org.apache.http.client.methods.HttpPost; import org.apache.http.client.methods.HttpUriRequest; import org.apache.http.entity.ByteArrayEntity; import org.apache.http.entity.ContentType; import org.apache.http.entity.mime.MultipartEntityBuilder; import org.apache.http.impl.client.CloseableHttpClient; import org.apache.http.impl.client.HttpClientBuilder; import org.apache.http.message.BasicNameValuePair; import org.junit.Before; import org.junit.BeforeClass; import org.junit.Test; import javax.servlet.*; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException; import java.io.UnsupportedEncodingException; import java.net.URLEncoder; import java.util.Arrays; import java.util.concurrent.ArrayBlockingQueue; import java.util.concurrent.BlockingQueue; import java.util.concurrent.TimeUnit; import java.util.zip.GZIPOutputStream; import static org.junit.Assert.assertEquals; import static org.junit.Assert.fail; /** * */ public class ServletRamlMessageTest extends ServerTest { private CloseableHttpClient client; private static TestFilter testFilter; private static HttpServlet testServlet, gzipTestServlet; private static MessageTester tester; private static final BlockingQueue<Error> error = new ArrayBlockingQueue<>(1); private static final Error OK = new Error() { }; @BeforeClass public static void setupClass() { testFilter = new TestFilter(); testServlet = new TestServlet(); gzipTestServlet = new GzipTestServlet(); } @Before public void setup() { client = HttpClientBuilder.create().build(); } interface MessageTester { void test(HttpServletRequest servletRequest, HttpServletResponse servletResponse, RamlRequest ramlRequest, RamlResponse ramlResponse) throws IOException; } @Test public void base() throws Exception { final HttpGet get = new HttpGet(url("test/more?param=value¶m=v2")); get.addHeader("header", "pedro"); execute(get, new MessageTester() { @Override public void test(HttpServletRequest servletRequest, HttpServletResponse servletResponse, RamlRequest ramlRequest, RamlResponse ramlResponse) { assertEquals(0, ramlRequest.getContent().length); assertEquals(null, ramlRequest.getContentType()); assertEquals(Arrays.asList("pedro"), ramlRequest.getHeaderValues().get("header")); assertEquals("GET", ramlRequest.getMethod()); assertEquals(new Values().addValue("param", "value").addValue("param", "v2"), ramlRequest.getQueryValues()); assertEquals(url("test/more"), ramlRequest.getRequestUrl(null, false)); assertEquals("https://base/more", ramlRequest.getRequestUrl("https://base", false)); assertEquals(0, ramlResponse.getContent().length); assertEquals(null, ramlResponse.getContentType()); assertEquals(new Values().addValue("resHeader", "hula"), ramlResponse.getHeaderValues()); assertEquals(222, ramlResponse.getStatus()); } }); } @Test public void content() throws Exception { final HttpPost post = new HttpPost(url("test/more")); final HttpEntity entity = new ByteArrayEntity(new byte[]{65, 66, 67}); post.setEntity(entity); execute(post, new MessageTester() { @Override public void test(HttpServletRequest servletRequest, HttpServletResponse servletResponse, RamlRequest ramlRequest, RamlResponse ramlResponse) throws IOException { assertEquals("ABC", stringOf(ramlRequest.getContent())); assertEquals("ABC", stringOf(ramlResponse.getContent())); } }); } @Test public void urlEncodedForm() throws Exception { final HttpPost post = new HttpPost(url("test/more")); final HttpEntity entity = new UrlEncodedFormEntity(Arrays.asList( new BasicNameValuePair("param", "value"), new BasicNameValuePair("param", "v2"), new BasicNameValuePair("p2", "äöü+$% "))); post.setEntity(entity); execute(post, new MessageTester() { @Override public void test(HttpServletRequest servletRequest, HttpServletResponse servletResponse, RamlRequest ramlRequest, RamlResponse ramlResponse) throws IOException { final Values values = new Values() .addValue("param", "value") .addValue("param", "v2") .addValue("p2", "äöü+$% "); assertEquals(values, ramlRequest.getFormValues()); assertEquals("param=value¶m=v2&p2=" + URLEncoder.encode("äöü+$% ", "iso-8859-1"), stringOf(ramlResponse.getContent())); } }); } @Test public void multipartForm() throws Exception { final HttpPost post = new HttpPost(url("test/more")); final HttpEntity entity = MultipartEntityBuilder.create() .addBinaryBody("binary", new byte[]{65, 66, 67}, ContentType.APPLICATION_OCTET_STREAM, "filename") .addTextBody("param", "value") .addTextBody("param", "v2") .addTextBody("p2", "äöü+$% ") .build(); post.setEntity(entity); execute(post, new MessageTester() { @Override public void test(HttpServletRequest servletRequest, HttpServletResponse servletResponse, RamlRequest ramlRequest, RamlResponse ramlResponse) throws IOException { final Values values = new Values() .addValue("binary", new FileValue()) .addValue("param", "value") .addValue("param", "v2") .addValue("p2", "äöü+$% "); assertEquals(values, ramlRequest.getFormValues()); } }); } @Test public void includeServletPathNoPathInfo() throws Exception { final HttpPost post = new HttpPost(url("test")); execute(post, new MessageTester() { @Override public void test(HttpServletRequest servletRequest, HttpServletResponse servletResponse, RamlRequest ramlRequest, RamlResponse ramlResponse) throws IOException { assertEquals(baseUrlWithPort() + "/test", ramlRequest.getRequestUrl(null, true)); assertEquals("http://server/servlet/path/test", ramlRequest.getRequestUrl("http://server/servlet/path", true)); } }); } @Test public void includeServletPathWithPathInfo() throws Exception { final HttpPost post = new HttpPost(url("test/info")); execute(post, new MessageTester() { @Override public void test(HttpServletRequest servletRequest, HttpServletResponse servletResponse, RamlRequest ramlRequest, RamlResponse ramlResponse) throws IOException { assertEquals(baseUrlWithPort() + "/test/info", ramlRequest.getRequestUrl(null, true)); assertEquals("http://server/servlet/path/test/info", ramlRequest.getRequestUrl("http://server/servlet/path", true)); } }); } @Test public void gzip() throws Exception { final HttpGet get = new HttpGet(url("gzip/path")); execute(get, new MessageTester() { @Override public void test(HttpServletRequest servletRequest, HttpServletResponse servletResponse, RamlRequest ramlRequest, RamlResponse ramlResponse) throws IOException { assertEquals("Gzip works!", new String(ramlResponse.getContent())); } }); } private String stringOf(byte[] bytes) throws UnsupportedEncodingException { return new String(bytes, "iso-8859-1"); } private void execute(HttpUriRequest request, MessageTester messageTester) throws IOException, InterruptedException { tester = messageTester; error.clear(); client.execute(request); final Error e = error.poll(100, TimeUnit.MILLISECONDS); if (e == null) { fail("Got no response"); } if (e != OK) { throw e; } } private static class TestFilter implements Filter { @Override public void init(FilterConfig filterConfig) throws ServletException { } @Override public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { final ServletRamlRequest req = new ServletRamlRequest((HttpServletRequest) request); final ServletRamlResponse res = new ServletRamlResponse((HttpServletResponse) response); chain.doFilter(req, res); try { tester.test((HttpServletRequest) request, (HttpServletResponse) response, req, res); error.add(OK); } catch (Error e) { error.add(e); } } @Override public void destroy() { } } private static class TestServlet extends HttpServlet { @Override protected void service(HttpServletRequest req, HttpServletResponse res) throws ServletException, IOException { res.addHeader("resHeader", "hula"); res.setStatus(222); final byte[] buf = new byte[1000]; try (final ServletInputStream in = req.getInputStream(); final ServletOutputStream out = res.getOutputStream()) { int read; while ((read = in.read(buf)) > 0) { out.write(buf, 0, read); } out.flush(); } } } private static class GzipTestServlet extends HttpServlet { @Override protected void service(HttpServletRequest req, HttpServletResponse res) throws ServletException, IOException { res.addHeader("Content-Encoding", "gzip"); res.setStatus(200); final GZIPOutputStream gzipOut = new GZIPOutputStream(res.getOutputStream()); gzipOut.write("Gzip works!".getBytes()); gzipOut.finish(); res.getOutputStream().flush(); } } @Override protected void init(Context ctx) { final FilterDef filterDef = new FilterDef(); filterDef.setFilter(testFilter); filterDef.setFilterName("filter"); ctx.addFilterDef(filterDef); final FilterMap filterMap = new FilterMap(); filterMap.addURLPattern("/*"); filterMap.setFilterName("filter"); ctx.addFilterMap(filterMap); Tomcat.addServlet(ctx, "test", testServlet); Tomcat.addServlet(ctx, "gzip", gzipTestServlet); ctx.addServletMapping("/test/*", "test"); ctx.addServletMapping("/gzip/*", "gzip"); } }