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(); } } }