blob: e0c1f8192ad0bdc17265de05bdde8f6f8882fd3f [file] [log] [blame]
//
// ========================================================================
// Copyright (c) 1995-2015 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;
}
}