/* * Copyright 2010 Proofpoint, Inc. * * 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 io.airlift.jaxrs; import com.google.inject.Binder; import com.google.inject.Guice; import com.google.inject.Module; import io.airlift.http.client.HttpClient; import io.airlift.http.client.Request; import io.airlift.http.client.StatusResponseHandler.StatusResponse; import io.airlift.http.client.jetty.JettyHttpClient; import io.airlift.http.server.testing.TestingHttpServer; import io.airlift.http.server.testing.TestingHttpServerModule; import io.airlift.json.JsonModule; import io.airlift.node.testing.TestingNodeModule; import io.airlift.testing.Closeables; import org.testng.annotations.AfterClass; import org.testng.annotations.BeforeClass; import org.testng.annotations.BeforeMethod; import org.testng.annotations.Test; import javax.ws.rs.DELETE; import javax.ws.rs.GET; import javax.ws.rs.POST; import javax.ws.rs.PUT; import javax.ws.rs.Path; import javax.ws.rs.core.Response.Status; import java.io.IOException; import java.util.concurrent.ExecutionException; import static io.airlift.http.client.StatusResponseHandler.createStatusResponseHandler; import static io.airlift.jaxrs.JaxrsBinder.jaxrsBinder; import static java.lang.String.format; import static org.testng.Assert.assertEquals; import static org.testng.Assert.assertFalse; import static org.testng.Assert.assertTrue; @Test(singleThreaded = true) public class TestOverrideMethodFilterInHttpServer { private static final String GET = "GET"; private static final String POST = "POST"; private static final String PUT = "PUT"; private static final String DELETE = "DELETE"; private TestingHttpServer server; private TestResource resource; private HttpClient client; @BeforeClass public void setup() throws Exception { resource = new TestResource(); server = createServer(resource); client = new JettyHttpClient(); server.start(); } @AfterClass(alwaysRun = true) public void teardown() { try { if (server != null) { server.stop(); } } catch (Throwable ignored) { } Closeables.closeQuietly(client); } @BeforeMethod public void resetResource() { resource.reset(); } @Test public void testDeleteViaQueryParam() throws Exception { client.execute(buildRequestWithQueryParam(POST, DELETE), createStatusResponseHandler()); assertFalse(resource.postCalled(), "POST"); assertTrue(resource.deleteCalled(), "DELETE"); assertFalse(resource.putCalled(), "PUT"); assertFalse(resource.getCalled(), "GET"); } @Test public void testPutViaQueryParam() throws Exception { client.execute(buildRequestWithQueryParam(POST, PUT), createStatusResponseHandler()); assertFalse(resource.postCalled(), "POST"); assertFalse(resource.deleteCalled(), "DELETE"); assertTrue(resource.putCalled(), "PUT"); assertFalse(resource.getCalled(), "GET"); } @Test public void testPostViaQueryParam() throws Exception { client.execute(buildRequestWithQueryParam(POST, POST), createStatusResponseHandler()); assertTrue(resource.postCalled(), "POST"); assertFalse(resource.deleteCalled(), "DELETE"); assertFalse(resource.putCalled(), "PUT"); assertFalse(resource.getCalled(), "GET"); } @Test public void testDeleteViaHeader() throws Exception { client.execute(buildRequestWithHeader(POST, DELETE), createStatusResponseHandler()); assertFalse(resource.postCalled(), "POST"); assertTrue(resource.deleteCalled(), "DELETE"); assertFalse(resource.putCalled(), "PUT"); assertFalse(resource.getCalled(), "GET"); } @Test public void testPutViaHeader() throws Exception { client.execute(buildRequestWithHeader(POST, PUT), createStatusResponseHandler()); assertFalse(resource.postCalled(), "POST"); assertFalse(resource.deleteCalled(), "DELETE"); assertTrue(resource.putCalled(), "PUT"); assertFalse(resource.getCalled(), "GET"); } @Test public void testPostViaHeader() throws Exception { client.execute(buildRequestWithHeader(POST, POST), createStatusResponseHandler()); assertTrue(resource.postCalled(), "POST"); assertFalse(resource.deleteCalled(), "DELETE"); assertFalse(resource.putCalled(), "PUT"); assertFalse(resource.getCalled(), "GET"); } private void assertNonOverridableMethod(Request request) throws IOException, ExecutionException, InterruptedException { StatusResponse response = client.execute(request, createStatusResponseHandler()); assertEquals(response.getStatusCode(), Status.BAD_REQUEST.getStatusCode()); assertFalse(resource.postCalled(), "POST"); assertFalse(resource.deleteCalled(), "DELETE"); assertFalse(resource.putCalled(), "PUT"); assertFalse(resource.getCalled(), "GET"); } private Request buildRequestWithHeader(String type, String override) { return Request.builder().setUri(server.getBaseUrl()).setMethod(type).addHeader("X-HTTP-Method-Override", override).build(); } private Request buildRequestWithQueryParam(String type, String override) { return Request.builder().setUri(server.getBaseUrl().resolve(format("/?_method=%s", override))).setMethod(type).build(); } @Test public void testNonOverridableMethodsWithHeader() throws IOException, ExecutionException, InterruptedException { assertNonOverridableMethod(buildRequestWithHeader(GET, POST)); assertNonOverridableMethod(buildRequestWithHeader(GET, DELETE)); assertNonOverridableMethod(buildRequestWithHeader(GET, PUT)); assertNonOverridableMethod(buildRequestWithHeader(DELETE, POST)); assertNonOverridableMethod(buildRequestWithHeader(DELETE, GET)); assertNonOverridableMethod(buildRequestWithHeader(DELETE, PUT)); assertNonOverridableMethod(buildRequestWithHeader(PUT, POST)); assertNonOverridableMethod(buildRequestWithHeader(PUT, DELETE)); assertNonOverridableMethod(buildRequestWithHeader(PUT, GET)); } @Test public void testNonOverridableMethodsWithQueryParam() throws IOException, ExecutionException, InterruptedException { assertNonOverridableMethod(buildRequestWithQueryParam(GET, POST)); assertNonOverridableMethod(buildRequestWithQueryParam(GET, DELETE)); assertNonOverridableMethod(buildRequestWithQueryParam(GET, PUT)); assertNonOverridableMethod(buildRequestWithQueryParam(DELETE, POST)); assertNonOverridableMethod(buildRequestWithQueryParam(DELETE, GET)); assertNonOverridableMethod(buildRequestWithQueryParam(DELETE, PUT)); assertNonOverridableMethod(buildRequestWithQueryParam(PUT, POST)); assertNonOverridableMethod(buildRequestWithQueryParam(PUT, DELETE)); assertNonOverridableMethod(buildRequestWithQueryParam(PUT, GET)); } @Path("/") public static class TestResource { private volatile boolean post; private volatile boolean put; private volatile boolean get; private volatile boolean delete; public void reset() { post = false; put = false; get = false; delete = false; } @POST public void post() { post = true; } @GET public boolean get() { get = true; return true; } @DELETE public void delete() { delete = true; } @PUT public void put() { put = true; } public boolean postCalled() { return post; } public boolean putCalled() { return put; } public boolean getCalled() { return get; } public boolean deleteCalled() { return delete; } } private static TestingHttpServer createServer(final TestResource resource) { return Guice.createInjector( new TestingNodeModule(), new JaxrsModule(true), new JsonModule(), new TestingHttpServerModule(), new Module() { @Override public void configure(Binder binder) { jaxrsBinder(binder).bindInstance(resource); } }).getInstance(TestingHttpServer.class); } }