/*
* This file is part of the OWASP Proxy, a free intercepting proxy library.
* Copyright (C) 2008-2010 Rogan Dawes <rogan@dawes.za.net>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to:
* The Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*
*/
package org.owasp.proxy.tcp;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import java.io.IOException;
import java.net.InetSocketAddress;
import java.util.HashSet;
import java.util.logging.Logger;
import org.junit.AfterClass;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;
import org.owasp.proxy.daemon.Proxy;
import org.owasp.proxy.daemon.TargetedConnectionHandler;
import org.owasp.proxy.http.MessageFormatException;
import org.owasp.proxy.http.MessageUtils;
import org.owasp.proxy.http.MutableBufferedResponse;
import org.owasp.proxy.http.StreamingRequest;
import org.owasp.proxy.http.StreamingResponse;
import org.owasp.proxy.http.client.HttpClient;
import org.owasp.proxy.test.TraceServer;
public class TcpInterceptorTest {
private static Logger logger = Logger.getAnonymousLogger();
private static TraceServer ts;
private InetSocketAddress listen;
private TargetedConnectionHandler ch;
private HashSet<StreamHandle> handlers = new HashSet<StreamHandle>();
@BeforeClass
public static void setUpBeforeClass() throws Exception {
try {
ts = new TraceServer(9999);
ts.setChunked(true);
ts.start();
} catch (Exception e) {
e.printStackTrace();
}
}
@Before
public void setup() throws Exception {
listen = new InetSocketAddress("localhost", 9998);
StreamInterceptor<InetSocketAddress, InetSocketAddress> si = new StreamInterceptor<InetSocketAddress, InetSocketAddress>() {
public void connected(StreamHandle cs, StreamHandle sc,
InetSocketAddress cl, InetSocketAddress sl) {
logger.info("Connected " + cl + " to " + sl);
if (!handlers.contains(cs)) {
handlers.add(cs);
} else {
fail("Connect called twice for the same handler");
}
if (!handlers.contains(sc)) {
handlers.add(sc);
} else {
fail("Connect called twice for the same handler");
}
}
public void inputClosed(StreamHandle handle) {
logger.info(handle + " : input closed, closing output");
handle.close();
if (handlers.contains(handle)) {
handlers.remove(handle);
} else {
fail("Closed called twice for the same handler");
}
}
public void readException(StreamHandle handle, IOException ioe) {
logger.info(handle + ": error reading: " + ioe);
if (!handlers.contains(handle))
fail("readException called for nonexistent handler");
}
public void received(StreamHandle handle, byte[] b, int off, int len) {
// logger.info(handle + ": received '" + new String(b, off, len)
// + "'");
if (!handlers.contains(handle))
fail("receive called for nonexistent handler");
try {
handle.write(b, off, len);
} catch (IOException ioe) {
logger.info(handle + ": error writing to the output: "
+ ioe);
}
}
};
ch = new InterceptingConnectionHandler(si);
}
@AfterClass
public static void tearDownAfterClass() throws Exception {
ts.stop();
Thread.sleep(1000);
assertTrue("TraceServer shutdown failed!", ts.isStopped());
}
@Test
public void testServerClose() throws Exception {
InetSocketAddress target = new InetSocketAddress("127.0.0.1", 9999);
Proxy proxy = new Proxy(listen, ch, target);
proxy.start();
HttpClient client = new HttpClient();
client.setSoTimeout(0);
client.connect(listen, false);
assertEquals("Expected '200' response", 200, sendRequest(client, true));
assertEquals("Expected '200' response", 200, sendRequest(client, false));
client.disconnect();
Thread.sleep(2000);
assertEquals("Both handlers did not terminate", 0, handlers.size());
proxy.stop();
assertTrue("Listener didn't exit", proxy.isStopped());
}
@Test
public void testClientClose() throws Exception {
InetSocketAddress target = new InetSocketAddress("127.0.0.1", 9999);
Proxy proxy = new Proxy(listen, ch, target);
proxy.start();
HttpClient client = new HttpClient();
client.setSoTimeout(0);
client.connect(listen, false);
assertEquals("Expected '200' response", 200, sendRequest(client, true));
assertEquals("Expected '200' response", 200, sendRequest(client, true));
client.disconnect();
Thread.sleep(2000);
assertEquals("Both handlers did not terminate", 0, handlers.size());
proxy.stop();
assertTrue("Listener didn't exit", proxy.isStopped());
}
private int sendRequest(HttpClient client, boolean keepAlive)
throws IOException, MessageFormatException {
StreamingRequest req = new StreamingRequest.Impl();
req.setTarget(listen);
req.setSsl(false);
req.setHeader(("GET / HTTP/1.1\r\n\r\n").getBytes());
if (keepAlive)
req.setHeader("Connection", "Keep-alive");
StreamingResponse sr = client.fetchResponse(req);
MutableBufferedResponse br = new MutableBufferedResponse.Impl();
MessageUtils.buffer(sr, br, Integer.MAX_VALUE);
System.out.println(br.getStartLine());
return Integer.parseInt(br.getStatus());
}
}