PageRenderTime 689ms CodeModel.GetById 22ms RepoModel.GetById 0ms app.codeStats 0ms

/http-server/src/test/java/io/airlift/http/server/TestHttpServerModule.java

https://gitlab.com/github-cloud-corp/airlift
Java | 379 lines | 313 code | 47 blank | 19 comment | 3 complexity | 803180c58aa809426ab471c0d8fce7c2 MD5 | raw file
  1. /*
  2. * Copyright 2010 Proofpoint, Inc.
  3. *
  4. * Licensed under the Apache License, Version 2.0 (the "License");
  5. * you may not use this file except in compliance with the License.
  6. * You may obtain a copy of the License at
  7. *
  8. * http://www.apache.org/licenses/LICENSE-2.0
  9. *
  10. * Unless required by applicable law or agreed to in writing, software
  11. * distributed under the License is distributed on an "AS IS" BASIS,
  12. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. * See the License for the specific language governing permissions and
  14. * limitations under the License.
  15. */
  16. package io.airlift.http.server;
  17. import com.google.common.base.Charsets;
  18. import com.google.common.base.Joiner;
  19. import com.google.common.collect.ArrayListMultimap;
  20. import com.google.common.collect.ImmutableMap;
  21. import com.google.common.collect.ListMultimap;
  22. import com.google.common.io.ByteStreams;
  23. import com.google.common.io.Files;
  24. import com.google.common.net.HttpHeaders;
  25. import com.google.common.net.MediaType;
  26. import com.google.inject.Binder;
  27. import com.google.inject.Guice;
  28. import com.google.inject.Injector;
  29. import com.google.inject.Key;
  30. import com.google.inject.Module;
  31. import com.google.inject.Scopes;
  32. import com.google.inject.multibindings.Multibinder;
  33. import io.airlift.configuration.ConfigurationFactory;
  34. import io.airlift.configuration.ConfigurationModule;
  35. import io.airlift.event.client.EventModule;
  36. import io.airlift.event.client.InMemoryEventClient;
  37. import io.airlift.event.client.InMemoryEventModule;
  38. import io.airlift.http.client.HttpClient;
  39. import io.airlift.http.client.HttpStatus;
  40. import io.airlift.http.client.HttpUriBuilder;
  41. import io.airlift.http.client.StatusResponseHandler.StatusResponse;
  42. import io.airlift.http.client.StringResponseHandler.StringResponse;
  43. import io.airlift.http.client.jetty.JettyHttpClient;
  44. import io.airlift.log.Logging;
  45. import io.airlift.node.NodeInfo;
  46. import io.airlift.node.NodeModule;
  47. import io.airlift.testing.FileUtils;
  48. import io.airlift.tracetoken.TraceTokenModule;
  49. import org.testng.Assert;
  50. import org.testng.annotations.AfterMethod;
  51. import org.testng.annotations.BeforeMethod;
  52. import org.testng.annotations.BeforeSuite;
  53. import org.testng.annotations.Test;
  54. import javax.servlet.Filter;
  55. import javax.servlet.Servlet;
  56. import javax.servlet.ServletException;
  57. import javax.servlet.http.HttpServlet;
  58. import javax.servlet.http.HttpServletRequest;
  59. import javax.servlet.http.HttpServletResponse;
  60. import java.io.File;
  61. import java.io.IOException;
  62. import java.net.URI;
  63. import java.util.List;
  64. import java.util.Map;
  65. import java.util.Map.Entry;
  66. import static com.google.common.net.HttpHeaders.CONTENT_TYPE;
  67. import static com.google.common.net.HttpHeaders.REFERER;
  68. import static com.google.common.net.HttpHeaders.USER_AGENT;
  69. import static com.google.common.net.MediaType.PLAIN_TEXT_UTF_8;
  70. import static io.airlift.http.client.HttpUriBuilder.uriBuilderFrom;
  71. import static io.airlift.http.client.Request.Builder.prepareGet;
  72. import static io.airlift.http.client.Request.Builder.preparePost;
  73. import static io.airlift.http.client.StaticBodyGenerator.createStaticBodyGenerator;
  74. import static io.airlift.http.client.StatusResponseHandler.createStatusResponseHandler;
  75. import static io.airlift.http.client.StringResponseHandler.createStringResponseHandler;
  76. import static io.airlift.http.server.HttpServerBinder.httpServerBinder;
  77. import static java.util.Collections.nCopies;
  78. import static org.testng.Assert.assertEquals;
  79. import static org.testng.Assert.assertNotNull;
  80. import static org.testng.Assert.assertNull;
  81. import static org.testng.Assert.assertTrue;
  82. public class TestHttpServerModule
  83. {
  84. private File tempDir;
  85. @BeforeSuite
  86. public void setupSuite()
  87. {
  88. Logging.initialize();
  89. }
  90. @BeforeMethod
  91. public void setup()
  92. throws IOException
  93. {
  94. tempDir = Files.createTempDir().getCanonicalFile(); // getCanonicalFile needed to get around Issue 365 (http://code.google.com/p/guava-libraries/issues/detail?id=365)
  95. }
  96. @AfterMethod
  97. public void tearDown()
  98. throws IOException
  99. {
  100. FileUtils.deleteRecursively(tempDir);
  101. }
  102. @Test
  103. public void testCanConstructServer()
  104. throws Exception
  105. {
  106. Map<String, String> properties = new ImmutableMap.Builder<String, String>()
  107. .put("node.environment", "test")
  108. .put("http-server.http.port", "0")
  109. .put("http-server.log.path", new File(tempDir, "http-request.log").getAbsolutePath())
  110. .build();
  111. ConfigurationFactory configFactory = new ConfigurationFactory(properties);
  112. Injector injector = Guice.createInjector(new HttpServerModule(),
  113. new NodeModule(),
  114. new ConfigurationModule(configFactory),
  115. new EventModule(),
  116. new Module()
  117. {
  118. @Override
  119. public void configure(Binder binder)
  120. {
  121. binder.bind(Servlet.class).annotatedWith(TheServlet.class).to(DummyServlet.class);
  122. }
  123. });
  124. HttpServer server = injector.getInstance(HttpServer.class);
  125. assertNotNull(server);
  126. }
  127. @Test
  128. public void testHttpServerUri()
  129. throws Exception
  130. {
  131. Map<String, String> properties = new ImmutableMap.Builder<String, String>()
  132. .put("node.environment", "test")
  133. .put("http-server.http.port", "0")
  134. .put("http-server.log.path", new File(tempDir, "http-request.log").getAbsolutePath())
  135. .build();
  136. ConfigurationFactory configFactory = new ConfigurationFactory(properties);
  137. Injector injector = Guice.createInjector(new HttpServerModule(),
  138. new NodeModule(),
  139. new ConfigurationModule(configFactory),
  140. new EventModule(),
  141. new Module()
  142. {
  143. @Override
  144. public void configure(Binder binder)
  145. {
  146. binder.bind(Servlet.class).annotatedWith(TheServlet.class).to(DummyServlet.class);
  147. }
  148. });
  149. NodeInfo nodeInfo = injector.getInstance(NodeInfo.class);
  150. HttpServer server = injector.getInstance(HttpServer.class);
  151. assertNotNull(server);
  152. server.start();
  153. try {
  154. HttpServerInfo httpServerInfo = injector.getInstance(HttpServerInfo.class);
  155. assertNotNull(httpServerInfo);
  156. assertNotNull(httpServerInfo.getHttpUri());
  157. assertEquals(httpServerInfo.getHttpUri().getScheme(), "http");
  158. assertEquals(httpServerInfo.getHttpUri().getHost(), nodeInfo.getInternalIp().getHostAddress());
  159. assertNull(httpServerInfo.getHttpsUri());
  160. }
  161. catch (Exception e) {
  162. server.stop();
  163. }
  164. }
  165. @Test
  166. public void testServer()
  167. throws Exception
  168. {
  169. Map<String, String> properties = new ImmutableMap.Builder<String, String>()
  170. .put("node.environment", "test")
  171. .put("http-server.http.port", "0")
  172. .put("http-server.log.path", new File(tempDir, "http-request.log").getAbsolutePath())
  173. .build();
  174. ConfigurationFactory configFactory = new ConfigurationFactory(properties);
  175. Injector injector = Guice.createInjector(new HttpServerModule(),
  176. new NodeModule(),
  177. new ConfigurationModule(configFactory),
  178. new EventModule(),
  179. new Module()
  180. {
  181. @Override
  182. public void configure(Binder binder)
  183. {
  184. binder.bind(Servlet.class).annotatedWith(TheServlet.class).to(DummyServlet.class);
  185. Multibinder.newSetBinder(binder, Filter.class, TheServlet.class).addBinding().to(DummyFilter.class).in(Scopes.SINGLETON);
  186. httpServerBinder(binder).bindResource("/", "webapp/user").withWelcomeFile("user-welcome.txt");
  187. httpServerBinder(binder).bindResource("/", "webapp/user2");
  188. httpServerBinder(binder).bindResource("path", "webapp/user").withWelcomeFile("user-welcome.txt");
  189. httpServerBinder(binder).bindResource("path", "webapp/user2");
  190. }
  191. });
  192. HttpServerInfo httpServerInfo = injector.getInstance(HttpServerInfo.class);
  193. HttpServer server = injector.getInstance(HttpServer.class);
  194. server.start();
  195. try (HttpClient client = new JettyHttpClient()) {
  196. // test servlet bound correctly
  197. URI httpUri = httpServerInfo.getHttpUri();
  198. StatusResponse response = client.execute(prepareGet().setUri(httpUri).build(), createStatusResponseHandler());
  199. assertEquals(response.getStatusCode(), HttpServletResponse.SC_OK);
  200. // test filter bound correctly
  201. response = client.execute(prepareGet().setUri(httpUri.resolve("/filter")).build(), createStatusResponseHandler());
  202. assertEquals(response.getStatusCode(), HttpServletResponse.SC_PAYMENT_REQUIRED);
  203. assertEquals(response.getStatusMessage(), "filtered");
  204. // test http resources
  205. assertResource(httpUri, client, "", "welcome user!");
  206. assertResource(httpUri, client, "user-welcome.txt", "welcome user!");
  207. assertResource(httpUri, client, "user.txt", "user");
  208. assertResource(httpUri, client, "user2.txt", "user2");
  209. assertResource(httpUri, client, "path", "welcome user!");
  210. assertResource(httpUri, client, "path/", "welcome user!");
  211. assertResource(httpUri, client, "path/user-welcome.txt", "welcome user!");
  212. assertResource(httpUri, client, "path/user.txt", "user");
  213. assertResource(httpUri, client, "path/user2.txt", "user2");
  214. }
  215. finally {
  216. server.stop();
  217. }
  218. }
  219. private void assertResource(URI baseUri, HttpClient client, String path, String contents)
  220. {
  221. HttpUriBuilder uriBuilder = uriBuilderFrom(baseUri);
  222. StringResponse data = client.execute(prepareGet().setUri(uriBuilder.appendPath(path).build()).build(), createStringResponseHandler());
  223. assertEquals(data.getStatusCode(), HttpStatus.OK.code());
  224. MediaType contentType = MediaType.parse(data.getHeader(HttpHeaders.CONTENT_TYPE));
  225. assertTrue(PLAIN_TEXT_UTF_8.is(contentType), "Expected text/plain but got " + contentType);
  226. assertEquals(data.getBody().trim(), contents);
  227. }
  228. @Test
  229. public void testHttpRequestEvent()
  230. throws Exception
  231. {
  232. Map<String, String> properties = new ImmutableMap.Builder<String, String>()
  233. .put("node.environment", "test")
  234. .put("http-server.http.port", "0")
  235. .put("http-server.log.path", new File(tempDir, "http-request.log").getAbsolutePath())
  236. .build();
  237. ConfigurationFactory configFactory = new ConfigurationFactory(properties);
  238. Injector injector = Guice.createInjector(new HttpServerModule(),
  239. new NodeModule(),
  240. new ConfigurationModule(configFactory),
  241. new InMemoryEventModule(),
  242. new TraceTokenModule(),
  243. new Module()
  244. {
  245. @Override
  246. public void configure(Binder binder)
  247. {
  248. binder.bind(Servlet.class).annotatedWith(TheServlet.class).to(EchoServlet.class).in(Scopes.SINGLETON);
  249. }
  250. });
  251. HttpServerInfo httpServerInfo = injector.getInstance(HttpServerInfo.class);
  252. InMemoryEventClient eventClient = injector.getInstance(InMemoryEventClient.class);
  253. EchoServlet echoServlet = (EchoServlet) injector.getInstance(Key.get(Servlet.class, TheServlet.class));
  254. HttpServer server = injector.getInstance(HttpServer.class);
  255. server.start();
  256. URI requestUri = httpServerInfo.getHttpUri().resolve("/my/path");
  257. String userAgent = "my-user-agent";
  258. String referrer = "http://www.google.com";
  259. String token = "this is a trace token";
  260. String requestBody = Joiner.on(" ").join(nCopies(50, "request"));
  261. String requestContentType = "request/type";
  262. int responseCode = 555;
  263. String responseBody = Joiner.on(" ").join(nCopies(100, "response"));
  264. String responseContentType = "response/type";
  265. echoServlet.responseBody = responseBody;
  266. echoServlet.responseStatusCode = responseCode;
  267. echoServlet.responseHeaders.put("Content-Type", responseContentType);
  268. long beforeRequest = System.currentTimeMillis();
  269. long afterRequest;
  270. try (JettyHttpClient client = new JettyHttpClient()) {
  271. // test servlet bound correctly
  272. StringResponse response = client.execute(
  273. preparePost().setUri(requestUri)
  274. .addHeader(USER_AGENT, userAgent)
  275. .addHeader(CONTENT_TYPE, requestContentType)
  276. .addHeader(REFERER, referrer)
  277. .addHeader("X-Airlift-TraceToken", token)
  278. .setBodyGenerator(createStaticBodyGenerator(requestBody, Charsets.UTF_8))
  279. .build(),
  280. createStringResponseHandler());
  281. afterRequest = System.currentTimeMillis();
  282. assertEquals(response.getStatusCode(), responseCode);
  283. assertEquals(response.getBody(), responseBody);
  284. assertEquals(response.getHeader("Content-Type"), responseContentType);
  285. }
  286. finally {
  287. server.stop();
  288. }
  289. List<Object> events = eventClient.getEvents();
  290. Assert.assertEquals(events.size(), 1);
  291. HttpRequestEvent event = (HttpRequestEvent) events.get(0);
  292. Assert.assertEquals(event.getClientAddress(), echoServlet.remoteAddress);
  293. Assert.assertEquals(event.getProtocol(), "http");
  294. Assert.assertEquals(event.getMethod(), "POST");
  295. Assert.assertEquals(event.getRequestUri(), requestUri.getPath());
  296. Assert.assertNull(event.getUser());
  297. Assert.assertEquals(event.getAgent(), userAgent);
  298. Assert.assertEquals(event.getReferrer(), referrer);
  299. Assert.assertEquals(event.getTraceToken(), token);
  300. Assert.assertEquals(event.getRequestSize(), requestBody.length());
  301. Assert.assertEquals(event.getRequestContentType(), requestContentType);
  302. Assert.assertEquals(event.getResponseSize(), responseBody.length());
  303. Assert.assertEquals(event.getResponseCode(), responseCode);
  304. Assert.assertEquals(event.getResponseContentType(), responseContentType);
  305. Assert.assertTrue(event.getTimeStamp().getMillis() >= beforeRequest);
  306. Assert.assertTrue(event.getTimeToLastByte() <= afterRequest - beforeRequest);
  307. Assert.assertNotNull(event.getTimeToFirstByte());
  308. Assert.assertTrue(event.getTimeToDispatch() <= event.getTimeToFirstByte());
  309. Assert.assertTrue(event.getTimeToFirstByte() <= event.getTimeToLastByte());
  310. }
  311. private static final class EchoServlet extends HttpServlet
  312. {
  313. private int responseStatusCode = 300;
  314. private final ListMultimap<String, String> responseHeaders = ArrayListMultimap.create();
  315. public String responseBody;
  316. private String remoteAddress;
  317. @Override
  318. protected void service(HttpServletRequest request, HttpServletResponse response)
  319. throws ServletException, IOException
  320. {
  321. ByteStreams.copy(request.getInputStream(), ByteStreams.nullOutputStream());
  322. remoteAddress = request.getRemoteAddr();
  323. for (Entry<String, String> entry : responseHeaders.entries()) {
  324. response.addHeader(entry.getKey(), entry.getValue());
  325. }
  326. response.setStatus(responseStatusCode);
  327. if (responseBody != null) {
  328. response.getOutputStream().write(responseBody.getBytes(Charsets.UTF_8));
  329. }
  330. }
  331. }
  332. }