| // |
| // ======================================================================== |
| // Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd. |
| // ------------------------------------------------------------------------ |
| // 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.opensource.org/licenses/apache2.0.php |
| // |
| // You may elect to redistribute this code under either of these licenses. |
| // ======================================================================== |
| // |
| |
| package org.eclipse.jetty.test.support.rawhttp; |
| |
| import java.io.BufferedReader; |
| import java.io.ByteArrayInputStream; |
| import java.io.IOException; |
| import java.io.InputStream; |
| import java.io.InputStreamReader; |
| import java.io.StringReader; |
| import java.io.StringWriter; |
| import java.net.InetAddress; |
| import java.net.Socket; |
| import java.net.SocketTimeoutException; |
| import java.net.UnknownHostException; |
| import java.nio.ByteBuffer; |
| import java.util.ArrayList; |
| import java.util.List; |
| |
| import org.eclipse.jetty.http.HttpTester; |
| import org.eclipse.jetty.util.BufferUtil; |
| import org.eclipse.jetty.util.IO; |
| import org.eclipse.jetty.util.StringUtil; |
| |
| /** |
| * 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 static List<HttpTester.Response> getParts (String boundary, HttpTester.Response response) throws IOException |
| { |
| // TODO This method appears to be broken in how it uses the HttpParser |
| // Should use MultiPartInputStreamParser ?? |
| |
| List<HttpTester.Response> parts = new ArrayList<HttpTester.Response>(); |
| |
| BufferedReader buf = new BufferedReader(new StringReader(response.getContent())); |
| String line; |
| String startBoundary = "--" + boundary; |
| String endBoundary = "--" + boundary + "--"; |
| |
| StringBuffer partBuff = null; |
| boolean parsingHeader = true; |
| boolean previousBodyLine = false; |
| |
| while ((line = buf.readLine()) != null) |
| { |
| if (line.equals(startBoundary)) |
| { |
| // end of multipart, start a new one. |
| if (partBuff != null) |
| { |
| HttpTester.Response part = HttpTester.parseResponse(partBuff.toString()); |
| parts.add(part); |
| } |
| partBuff = new StringBuffer(); |
| parsingHeader = true; |
| previousBodyLine = false; |
| continue; |
| } |
| |
| if (line.equals(endBoundary)) |
| { |
| if (partBuff != null) |
| { |
| HttpTester.Response part = HttpTester.parseResponse(partBuff.toString()); |
| parts.add(part); |
| } |
| break; |
| } |
| |
| if (parsingHeader) |
| { |
| if (line.equals("")) |
| { |
| parsingHeader = false; |
| continue; |
| } |
| |
| partBuff.append(line); |
| } |
| else |
| { |
| if (previousBodyLine) |
| { |
| partBuff.append("\n"); |
| } |
| partBuff.append(line); |
| previousBodyLine = true; |
| } |
| } |
| |
| return parts; |
| |
| } |
| |
| public static List<HttpTester.Response> readResponses(String string) throws IOException |
| { |
| List<HttpTester.Response> list = new ArrayList<>(); |
| |
| ByteBuffer buffer = BufferUtil.toBuffer(string); |
| while(BufferUtil.hasContent(buffer)) |
| { |
| HttpTester.Response response = HttpTester.parseResponse(buffer); |
| if (response == null) |
| break; |
| list.add(response); |
| } |
| return list; |
| } |
| |
| 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 HttpTester.Response read(Socket sock) throws IOException |
| { |
| return HttpTester.parseResponse(readRaw(sock)); |
| } |
| |
| |
| public List<HttpTester.Response> readResponses(Socket sock) throws IOException |
| { |
| List<HttpTester.Response> list = new ArrayList<>(); |
| String r = readRaw(sock); |
| ByteBuffer buffer = BufferUtil.toBuffer(r); |
| while(BufferUtil.hasContent(buffer)) |
| { |
| HttpTester.Response response = HttpTester.parseResponse(buffer); |
| if (response == null) |
| break; |
| list.add(response); |
| } |
| return list; |
| } |
| |
| /** |
| * Read any available response from a socket. |
| * |
| * @param sock |
| * the socket to read from. |
| * @return the response object |
| * @throws IOException |
| */ |
| public HttpTester.Response readAvailable(Socket sock) throws IOException |
| { |
| |
| String rawResponse = readRawAvailable(sock); |
| if (StringUtil.isBlank(rawResponse)) |
| { |
| return null; |
| } |
| return HttpTester.parseResponse(rawResponse); |
| } |
| |
| /** |
| * 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 HttpTester.Response 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 HttpTester.Response request(HttpTester.Request request) throws IOException |
| { |
| ByteBuffer byteBuff = request.generate(); |
| return request(BufferUtil.toString(byteBuff)); |
| } |
| |
| /** |
| * Initiate multiple raw HTTP requests, parse the responses. |
| * |
| * @param rawRequests |
| * the raw HTTP requests. |
| * @return the responses. |
| * @throws IOException |
| */ |
| public List<HttpTester.Response> 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 readResponses(rawResponses); |
| } |
| finally |
| { |
| close(sock); |
| } |
| } |
| |
| |
| /** |
| * 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; |
| } |
| } |