// ======================================================================== // Copyright (c) Webtide LLC // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 // and Apache License v2.0 which accompanies this distribution. // // The Eclipse Public License is available at // http://www.eclipse.org/legal/epl-v10.html // // The Apache License v2.0 is available at // http://www.apache.org/licenses/LICENSE-2.0.txt // // You may elect to redistribute this code under either of these licenses. // ======================================================================== package org.eclipse.jetty.test.support.rawhttp; import java.io.ByteArrayInputStream; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.io.StringWriter; import java.net.InetAddress; import java.net.Socket; import java.net.SocketTimeoutException; import java.net.UnknownHostException; import java.util.List; import org.eclipse.jetty.test.support.StringUtil; import org.eclipse.jetty.util.IO; /** * Testing utility for performing RAW HTTP request/response. */ public class HttpTesting { private boolean debug = false; private HttpSocket httpSocket; private InetAddress serverHost; private int serverPort; private int timeoutMillis = 5000; public HttpTesting(HttpSocket httpSocket, InetAddress host, int port) { this.httpSocket = httpSocket; this.serverHost = host; this.serverPort = port; } public HttpTesting(HttpSocket socket, int port) throws UnknownHostException { this(socket,InetAddress.getLocalHost(),port); } public HttpTesting(HttpSocket socket, String host, int port) throws UnknownHostException { this(socket,InetAddress.getByName(host),port); } public void close(Socket sock) { if (sock != null) { try { sock.close(); } catch (IOException e) { System.err.println("Unable to close socket: " + sock); e.printStackTrace(System.err); } } } private void DEBUG(String msg) { if (debug) { System.out.println(msg); } } public void enableDebug() { this.debug = true; } public int getTimeoutMillis() { return timeoutMillis; } /** * Open a socket. * * @return the open socket. * @throws IOException */ public Socket open() throws IOException { Socket sock = httpSocket.connect(serverHost,serverPort); sock.setSoTimeout(timeoutMillis); return sock; } /** * Read a response from a socket. * * @param sock * the socket to read from. * @return the response object * @throws IOException */ public HttpResponseTester read(Socket sock) throws IOException { HttpResponseTester response = new HttpResponseTester(); response.parse(readRaw(sock)); return response; } /** * Read any available response from a socket. * * @param sock * the socket to read from. * @return the response object * @throws IOException */ public HttpResponseTester readAvailable(Socket sock) throws IOException { HttpResponseTester response = new HttpResponseTester(); String rawResponse = readRawAvailable(sock); if (StringUtil.isBlank(rawResponse)) { return null; } response.parse(rawResponse); return response; } /** * Read the raw response from the socket. * * @param sock * @return all of the the data from the socket as a String * @throws IOException */ public String readRaw(Socket sock) throws IOException { sock.setSoTimeout(timeoutMillis); // Collect response String rawResponse = IO.toString(sock.getInputStream()); DEBUG("--raw-response--\n" + rawResponse); return rawResponse; } /** * Read the raw response from the socket, reading whatever is available. * Any {@link SocketTimeoutException} is consumed and just stops the reading. * * @param sock * @return the raw data from the socket in string form, reading whatever is available. * a {@link SocketTimeoutException} will result in the read stopping. * @throws IOException */ public String readRawAvailable(Socket sock) throws IOException { sock.setSoTimeout(timeoutMillis); // Collect response StringWriter writer = new StringWriter(); InputStreamReader reader = new InputStreamReader(sock.getInputStream()); try { IO.copy(reader,writer); } catch (SocketTimeoutException e) { /* ignore */ } String rawResponse = writer.toString(); DEBUG("--raw-response--\n" + rawResponse); return rawResponse; } /** * Initiate a standard HTTP request, parse the response. * * Note: not for HTTPS requests. * * @param rawRequest * the request * @return the response * @throws IOException */ public HttpResponseTester request(CharSequence rawRequest) throws IOException { Socket sock = open(); try { send(sock,rawRequest); return read(sock); } finally { close(sock); } } /** * Initiate a standard HTTP request, parse the response. * * Note: not for HTTPS requests. * * @param request * the request * @return the response * @throws IOException */ public HttpResponseTester request(HttpRequestTester request) throws IOException { String rawRequest = request.generate(); return request(rawRequest); } /** * Initiate multiple raw HTTP requests, parse the responses. * * @param rawRequests * the raw HTTP requests. * @return the responses. * @throws IOException */ public List<HttpResponseTester> requests(CharSequence rawRequests) throws IOException { Socket sock = open(); try { send(sock,rawRequests); // Collect response String rawResponses = IO.toString(sock.getInputStream()); DEBUG("--raw-response--\n" + rawResponses); return HttpResponseTester.parseMulti(rawResponses); } finally { close(sock); } } /** * Initiate a multiple HTTP requests, parse the responses * * @param requests * the request objects. * @return the response objects. * @throws IOException */ public List<HttpResponseTester> requests(List<HttpRequestTester> requests) throws IOException { StringBuffer rawRequest = new StringBuffer(); for (HttpRequestTester request : requests) { rawRequest.append(request.generate()); } return requests(rawRequest); } /** * Send a data (as request) to open socket. * * @param sock * the socket to send the request to * @param rawData * the raw data to send. * @throws IOException */ public void send(Socket sock, CharSequence rawData) throws IOException { sock.setSoTimeout(timeoutMillis); DEBUG("--raw-request--\n" + rawData.toString()); InputStream in = new ByteArrayInputStream(rawData.toString().getBytes()); // Send request IO.copy(in,sock.getOutputStream()); } public void setTimeoutMillis(int timeoutMillis) { this.timeoutMillis = timeoutMillis; } }