/** * Copyright (c) 2009-2011 VMware, Inc. All Rights Reserved. * * 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 com.springsource.insight.plugin.socket; import java.io.IOException; import java.io.Writer; import java.net.HttpURLConnection; import java.net.URL; import java.util.List; import java.util.Map; import java.util.concurrent.TimeUnit; import javax.servlet.ServletException; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.junit.AfterClass; import org.junit.BeforeClass; import org.junit.Test; import org.mortbay.jetty.Handler; import org.mortbay.jetty.HttpConnection; import org.mortbay.jetty.Request; import org.mortbay.jetty.Server; import com.springsource.insight.collection.ObscuredValueSetMarker; import com.springsource.insight.collection.http.HttpObfuscator; import com.springsource.insight.intercept.operation.Operation; import com.springsource.insight.intercept.operation.OperationFields; import com.springsource.insight.intercept.topology.ExternalResourceType; import com.springsource.insight.util.ListUtil; import com.springsource.insight.util.MapUtil; import com.springsource.insight.util.io.Base64; /** * */ public class HttpURLConnectionOperationCollectionAspectTest extends SocketOperationCollectionAspectTestSupport { private static final String TEST_URI = "http://" + TEST_HOST + ":" + TEST_PORT + "/"; private static Server SERVER; public HttpURLConnectionOperationCollectionAspectTest() { super(); } @BeforeClass public static void startEmbeddedServer() throws Exception { SERVER = new Server(TEST_PORT); SERVER.setHandler(new TestHandler()); System.out.println("Starting embedded server on port " + TEST_PORT); SERVER.start(); System.out.println("Started embedded server on port " + TEST_PORT); } @AfterClass public static void stopEmbeddedServer() throws Exception { if (SERVER != null) { System.out.println("Stopping embedded server"); SERVER.stop(); System.out.println("Server stopped"); } } @Test public void testConnect() throws IOException { final String METHOD = "GET"; HttpURLConnection conn = createConnection(METHOD, "testConnect"); try { conn.connect(); int responseCode = conn.getResponseCode(); assertEquals("Bad response code", HttpServletResponse.SC_OK, responseCode); } finally { conn.disconnect(); } Operation op = assertSocketOperation(SocketDefinitions.CONNECT_ACTION, TEST_HOST, TEST_PORT); assertEquals("Mismatched method", METHOD, op.get("method", String.class)); URL url = conn.getURL(); assertEquals("Mismatched URL", url.toExternalForm(), op.get(OperationFields.URI, String.class)); runExternalResourceAnalyzer(op, ExternalResourceType.WEB_SERVER, TEST_HOST, TEST_PORT); } @Test public void testDefaultObscuredHeaders() throws IOException { ObscuredValueSetMarker marker = setupObscuredTest(HttpObfuscator.OBFUSCATED_HEADERS_SETTING, HttpObfuscator.DEFAULT_OBFUSCATED_HEADERS_VALUES); HttpURLConnection conn = createConnection("POST", "testDefaultObscuredHeaders"); Map<String, List<String>> propsMap; try { propsMap = conn.getRequestProperties(); assertTrue("No request properties map", MapUtil.size(propsMap) > 0); conn.connect(); int responseCode = conn.getResponseCode(); assertEquals("Bad response code", HttpServletResponse.SC_OK, responseCode); } finally { conn.disconnect(); } for (String hdrName : HttpObfuscator.DEFAULT_OBFUSCATED_HEADERS_LIST) { if ("WWW-Authenticate".equals(hdrName)) { continue; // this is a response header and we do not intercept them } // see http://stackoverflow.com/questions/2864062/getrequestpropertyauthorization-always-returns-null List<String> values = propsMap.get(hdrName); if (ListUtil.size(values) <= 0) { continue; } assertEquals("Mismatched num. of values for " + hdrName, 1, values.size()); assertObscureTestResults(marker, hdrName, values.get(0), true); } } @Test public void testObscuredHeaders() throws IOException { final String hdrName = "TestObscuredHeaders", hdrValue = String.valueOf(System.nanoTime()); ObscuredValueSetMarker marker = setupObscuredTest(HttpObfuscator.OBFUSCATED_HEADERS_SETTING, hdrName); HttpURLConnection conn = createConnection("POST", hdrName); Map<String, List<String>> propsMap; try { conn.setRequestProperty(hdrName, hdrValue); propsMap = conn.getRequestProperties(); assertTrue("No request properties map", MapUtil.size(propsMap) > 0); conn.connect(); int responseCode = conn.getResponseCode(); assertEquals("Bad response code", HttpServletResponse.SC_OK, responseCode); } finally { conn.disconnect(); } assertObscureTestResults(marker, hdrName, hdrValue, true); assertObscureTestResults(marker, hdrName, "X-Dummy-Value", false); for (String defName : HttpObfuscator.DEFAULT_OBFUSCATED_HEADERS_LIST) { // see http://stackoverflow.com/questions/2864062/getrequestpropertyauthorization-always-returns-null List<String> values = propsMap.get(defName); if (ListUtil.size(values) <= 0) { continue; } assertEquals("Mismatched num. of values for " + defName, 1, values.size()); assertObscureTestResults(marker, defName, values.get(0), false); } } @Override public HttpURLConnectionOperationCollectionAspect getAspect() { return HttpURLConnectionOperationCollectionAspect.aspectOf(); } protected HttpURLConnection createConnection(final String method, final String testName) throws IOException { URL testURL = new URL(createTestUri(testName)); HttpURLConnection conn = (HttpURLConnection) testURL.openConnection(); conn.setConnectTimeout((int) TimeUnit.SECONDS.toMillis(15L)); conn.setReadTimeout((int) TimeUnit.SECONDS.toMillis(15L)); if ("POST".equalsIgnoreCase(method)) { conn.setDoOutput(true); } conn.setRequestMethod(method); final String authToken = Base64.encode(getClass().getSimpleName() + ":" + testName); conn.setRequestProperty("Authentication-Info", "Blah"); conn.setRequestProperty("Authorization", "Basic " + authToken); conn.setRequestProperty("Proxy-Authenticate", "Base64 " + authToken); conn.setRequestProperty("Proxy-Authorization", "Basic " + authToken); return conn; } static String createResponseContent(String testName) { return "<test name=\"" + testName + "\" />"; } static String createTestUri(String testName) { return TEST_URI + testName; } private static final class TestHandler implements Handler { private Server server; private boolean started; protected TestHandler() { super(); } public void stop() throws Exception { if (!started) { throw new IllegalStateException("Not started"); } started = false; } public void addLifeCycleListener(Listener listener) { // ignored } public void removeLifeCycleListener(Listener listener) { // ignored } public void start() throws Exception { if (started) { throw new IllegalStateException("Double start"); } started = true; } public boolean isStopping() { return true; } public boolean isStopped() { return !started; } public boolean isStarting() { return true; } public boolean isStarted() { return started; } public boolean isRunning() { return started; } public boolean isFailed() { return false; } public Server getServer() { return this.server; } public void setServer(Server serverInstance) { this.server = serverInstance; } public void handle(String target, HttpServletRequest request, HttpServletResponse response, int dispatch) throws IOException, ServletException { int namePos = target.lastIndexOf('/'); String testName = target.substring(namePos + 1); response.setStatus(HttpServletResponse.SC_OK); response.setContentType("text/xml;charset=utf-8"); response.addHeader("X-Test-Name", testName); response.addHeader("WWW-Authenticate", "allowed"); Writer writer = response.getWriter(); try { writer.append(createResponseContent(testName)); } finally { writer.close(); } Request baseRequest = (request instanceof Request) ? (Request) request : HttpConnection.getCurrentConnection().getRequest(); baseRequest.setHandled(true); } public void destroy() { if (this.server != null) this.server = null; } } }