package org.eclipse.jetty.server.handler;
import java.io.BufferedReader;
import java.io.EOFException;
import java.io.IOException;
import java.net.Socket;
import java.net.SocketTimeoutException;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.eclipse.jetty.server.Connector;
import org.eclipse.jetty.server.Handler;
import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.server.nio.SelectChannelConnector;
import org.junit.AfterClass;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
/**
* @version $Revision$ $Date$
*/
public abstract class AbstractConnectHandlerTest
{
protected static Server server;
protected static Connector serverConnector;
protected static Server proxy;
protected static Connector proxyConnector;
protected static void startServer(Connector connector, Handler handler) throws Exception
{
server = new Server();
serverConnector = connector;
server.addConnector(serverConnector);
server.setHandler(handler);
server.start();
}
protected static void startProxy() throws Exception
{
proxy = new Server();
proxyConnector = new SelectChannelConnector();
proxy.addConnector(proxyConnector);
proxy.setHandler(new ConnectHandler());
proxy.start();
}
@AfterClass
public static void stop() throws Exception
{
stopProxy();
stopServer();
}
protected static void stopServer() throws Exception
{
server.stop();
server.join();
}
protected static void stopProxy() throws Exception
{
proxy.stop();
proxy.join();
}
protected Response readResponse(BufferedReader reader) throws IOException
{
// Simplified parser for HTTP responses
String line = reader.readLine();
if (line == null)
throw new EOFException();
Matcher responseLine = Pattern.compile("HTTP/1\\.1\\s+(\\d+)").matcher(line);
assertTrue(responseLine.lookingAt());
String code = responseLine.group(1);
Map<String, String> headers = new LinkedHashMap<String, String>();
while ((line = reader.readLine()) != null)
{
if (line.trim().length() == 0)
break;
Matcher header = Pattern.compile("([^:]+):\\s*(.*)").matcher(line);
assertTrue(header.lookingAt());
String headerName = header.group(1);
String headerValue = header.group(2);
headers.put(headerName.toLowerCase(), headerValue.toLowerCase());
}
StringBuilder body = new StringBuilder();
if (headers.containsKey("content-length"))
{
int readLen = 0;
int length = Integer.parseInt(headers.get("content-length"));
try
{
for (int i = 0; i < length; ++i)
{
char c = (char)reader.read();
body.append(c);
readLen++;
}
}
catch (SocketTimeoutException e)
{
System.err.printf("Read %,d bytes (out of an expected %,d bytes)%n",readLen,length);
throw e;
}
}
else if ("chunked".equals(headers.get("transfer-encoding")))
{
while ((line = reader.readLine()) != null)
{
if ("0".equals(line))
{
line = reader.readLine();
assertEquals("", line);
break;
}
int length = Integer.parseInt(line, 16);
for (int i = 0; i < length; ++i)
{
char c = (char)reader.read();
body.append(c);
}
line = reader.readLine();
assertEquals("", line);
}
}
return new Response(code, headers, body.toString().trim());
}
protected Socket newSocket() throws IOException
{
Socket socket = new Socket("localhost", proxyConnector.getLocalPort());
socket.setSoTimeout(10000);
return socket;
}
protected class Response
{
private final String code;
private final Map<String, String> headers;
private final String body;
private Response(String code, Map<String, String> headers, String body)
{
this.code = code;
this.headers = headers;
this.body = body;
}
public String getCode()
{
return code;
}
public Map<String, String> getHeaders()
{
return headers;
}
public String getBody()
{
return body;
}
@Override
public String toString()
{
StringBuilder builder = new StringBuilder();
builder.append(code).append("\r\n");
for (Map.Entry<String, String> entry : headers.entrySet())
builder.append(entry.getKey()).append(": ").append(entry.getValue()).append("\r\n");
builder.append("\r\n");
builder.append(body);
return builder.toString();
}
}
}