init
This commit is contained in:
493
test/org/apache/catalina/startup/SimpleHttpClient.java
Normal file
493
test/org/apache/catalina/startup/SimpleHttpClient.java
Normal file
@@ -0,0 +1,493 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.apache.catalina.startup;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.InputStreamReader;
|
||||
import java.io.OutputStream;
|
||||
import java.io.OutputStreamWriter;
|
||||
import java.io.Reader;
|
||||
import java.io.Writer;
|
||||
import java.net.InetSocketAddress;
|
||||
import java.net.Socket;
|
||||
import java.net.SocketAddress;
|
||||
import java.net.SocketException;
|
||||
import java.net.UnknownHostException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
|
||||
import org.junit.Assert;
|
||||
|
||||
/**
|
||||
* Simple client for unit testing. It isn't robust, it isn't secure and
|
||||
* should not be used as the basis for production code. Its only purpose
|
||||
* is to do the bare minimum for the unit tests.
|
||||
*/
|
||||
public abstract class SimpleHttpClient {
|
||||
public static final String TEMP_DIR =
|
||||
System.getProperty("java.io.tmpdir");
|
||||
|
||||
public static final String CR = "\r";
|
||||
public static final String LF = "\n";
|
||||
public static final String CRLF = CR + LF;
|
||||
|
||||
public static final String INFO_100 = "HTTP/1.1 100 ";
|
||||
public static final String OK_200 = "HTTP/1.1 200 ";
|
||||
public static final String CREATED_201 = "HTTP/1.1 201 ";
|
||||
public static final String NOCONTENT_204 = "HTTP/1.1 204 ";
|
||||
public static final String REDIRECT_302 = "HTTP/1.1 302 ";
|
||||
public static final String REDIRECT_303 = "HTTP/1.1 303 ";
|
||||
public static final String FAIL_400 = "HTTP/1.1 400 ";
|
||||
public static final String FORBIDDEN_403 = "HTTP/1.1 403 ";
|
||||
public static final String FAIL_404 = "HTTP/1.1 404 ";
|
||||
public static final String FAIL_405 = "HTTP/1.1 405 ";
|
||||
public static final String TIMEOUT_408 = "HTTP/1.1 408 ";
|
||||
public static final String FAIL_413 = "HTTP/1.1 413 ";
|
||||
public static final String FAIL_417 = "HTTP/1.1 417 ";
|
||||
public static final String FAIL_50X = "HTTP/1.1 50";
|
||||
public static final String FAIL_500 = "HTTP/1.1 500 ";
|
||||
public static final String FAIL_501 = "HTTP/1.1 501 ";
|
||||
|
||||
private static final String CONTENT_LENGTH_HEADER_PREFIX =
|
||||
"Content-Length: ";
|
||||
|
||||
protected static final String SESSION_COOKIE_NAME = "JSESSIONID";
|
||||
protected static final String SESSION_PARAMETER_NAME =
|
||||
SESSION_COOKIE_NAME.toLowerCase(Locale.ENGLISH);
|
||||
|
||||
private static final String COOKIE_HEADER_PREFIX = "Set-Cookie: ";
|
||||
private static final String SESSION_COOKIE_HEADER_PREFIX =
|
||||
COOKIE_HEADER_PREFIX + SESSION_COOKIE_NAME + "=";
|
||||
|
||||
private static final String REDIRECT_HEADER_PREFIX = "Location: ";
|
||||
protected static final String SESSION_PATH_PARAMETER_PREFIX =
|
||||
SESSION_PARAMETER_NAME + "=";
|
||||
protected static final String SESSION_PATH_PARAMETER_TAILS = CRLF + ";?";
|
||||
|
||||
private static final String ELEMENT_HEAD = "<";
|
||||
private static final String ELEMENT_TAIL = ">";
|
||||
private static final String RESOURCE_TAG = "a";
|
||||
private static final String LOGIN_TAG = "form";
|
||||
|
||||
private Socket socket;
|
||||
private Writer writer;
|
||||
private BufferedReader reader;
|
||||
private int port = 8080;
|
||||
|
||||
private String[] request;
|
||||
private boolean useContinue = false;
|
||||
private boolean useCookies = true;
|
||||
private int requestPause = 1000;
|
||||
|
||||
private String responseLine;
|
||||
private List<String> responseHeaders = new ArrayList<>();
|
||||
private String sessionId;
|
||||
private boolean useContentLength;
|
||||
private int contentLength;
|
||||
private String redirectUri;
|
||||
|
||||
private String responseBody;
|
||||
private List<String> bodyUriElements = null;
|
||||
|
||||
public void setPort(int thePort) {
|
||||
port = thePort;
|
||||
}
|
||||
|
||||
public void setRequest(String[] theRequest) {
|
||||
request = theRequest;
|
||||
}
|
||||
|
||||
/*
|
||||
* Expect the server to reply with 100 Continue interim response
|
||||
*/
|
||||
public void setUseContinue(boolean theUseContinueFlag) {
|
||||
useContinue = theUseContinueFlag;
|
||||
}
|
||||
|
||||
public boolean getUseContinue() {
|
||||
return useContinue;
|
||||
}
|
||||
|
||||
public void setUseCookies(boolean theUseCookiesFlag) {
|
||||
useCookies = theUseCookiesFlag;
|
||||
}
|
||||
|
||||
public boolean getUseCookies() {
|
||||
return useCookies;
|
||||
}
|
||||
|
||||
public void setRequestPause(int theRequestPause) {
|
||||
requestPause = theRequestPause;
|
||||
}
|
||||
|
||||
public String getResponseLine() {
|
||||
return responseLine;
|
||||
}
|
||||
|
||||
public List<String> getResponseHeaders() {
|
||||
return responseHeaders;
|
||||
}
|
||||
|
||||
public String getResponseBody() {
|
||||
return responseBody;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return opening tags of HTML elements that were extracted by the
|
||||
* {@link #extractUriElements()} method.
|
||||
*
|
||||
* <p>
|
||||
* Note, that {@link #extractUriElements()} method has to be called
|
||||
* explicitly.
|
||||
*
|
||||
* @return List of HTML tags, accumulated by {@link #extractUriElements()}
|
||||
* method, or {@code null} if the method has not been called yet.
|
||||
*/
|
||||
public List<String> getResponseBodyUriElements() {
|
||||
return bodyUriElements;
|
||||
}
|
||||
|
||||
public void setUseContentLength(boolean b) {
|
||||
useContentLength = b;
|
||||
}
|
||||
|
||||
public void setSessionId(String theSessionId) {
|
||||
sessionId = theSessionId;
|
||||
}
|
||||
|
||||
public String getSessionId() {
|
||||
return sessionId;
|
||||
}
|
||||
|
||||
public String getRedirectUri() {
|
||||
return redirectUri;
|
||||
}
|
||||
|
||||
public void connect(int connectTimeout, int soTimeout)
|
||||
throws UnknownHostException, IOException {
|
||||
final String encoding = "ISO-8859-1";
|
||||
SocketAddress addr = new InetSocketAddress("localhost", port);
|
||||
socket = new Socket();
|
||||
socket.setSoTimeout(soTimeout);
|
||||
socket.connect(addr,connectTimeout);
|
||||
OutputStream os = createOutputStream(socket);
|
||||
writer = new OutputStreamWriter(os, encoding);
|
||||
InputStream is = socket.getInputStream();
|
||||
Reader r = new InputStreamReader(is, encoding);
|
||||
reader = new BufferedReader(r);
|
||||
}
|
||||
public void connect() throws UnknownHostException, IOException {
|
||||
connect(0,0);
|
||||
}
|
||||
|
||||
protected OutputStream createOutputStream(Socket socket) throws IOException {
|
||||
return socket.getOutputStream();
|
||||
}
|
||||
|
||||
public void processRequest() throws IOException, InterruptedException {
|
||||
processRequest(true);
|
||||
}
|
||||
|
||||
public void processRequest(boolean wantBody)
|
||||
throws IOException, InterruptedException {
|
||||
sendRequest();
|
||||
|
||||
readResponse(wantBody);
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
* Send the component parts of the request
|
||||
* (be tolerant and simply skip null entries)
|
||||
*/
|
||||
public void sendRequest() throws InterruptedException, IOException {
|
||||
boolean first = true;
|
||||
for (String requestPart : request) {
|
||||
if (requestPart != null) {
|
||||
if (first) {
|
||||
first = false;
|
||||
}
|
||||
else {
|
||||
Thread.sleep(requestPause);
|
||||
}
|
||||
writer.write(requestPart);
|
||||
writer.flush();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void readResponse(boolean wantBody) throws IOException {
|
||||
// clear any residual data before starting on this response
|
||||
responseHeaders.clear();
|
||||
responseBody = null;
|
||||
if (bodyUriElements != null) {
|
||||
bodyUriElements.clear();
|
||||
}
|
||||
|
||||
// Read the response status line
|
||||
responseLine = readLine();
|
||||
|
||||
// Is a 100 continue response expected?
|
||||
if (useContinue) {
|
||||
if (isResponse100()) {
|
||||
// Skip the blank after the 100 Continue response
|
||||
readLine();
|
||||
// Now get the final response
|
||||
responseLine = readLine();
|
||||
} else {
|
||||
throw new IOException("No 100 Continue response");
|
||||
}
|
||||
}
|
||||
|
||||
// Put the headers into a map, and process interesting ones
|
||||
processHeaders();
|
||||
|
||||
// Read the body, if requested and if one exists
|
||||
processBody(wantBody);
|
||||
|
||||
if (isResponse408()) {
|
||||
// the session has timed out
|
||||
sessionId = null;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Accumulate the response headers into a map, and extract
|
||||
* interesting details at the same time
|
||||
*/
|
||||
private void processHeaders() throws IOException {
|
||||
// Reset response fields
|
||||
redirectUri = null;
|
||||
contentLength = -1;
|
||||
|
||||
String line = readLine();
|
||||
while ((line != null) && (line.length() > 0)) {
|
||||
responseHeaders.add(line);
|
||||
if (line.startsWith(CONTENT_LENGTH_HEADER_PREFIX)) {
|
||||
contentLength = Integer.parseInt(line.substring(16));
|
||||
}
|
||||
else if (line.startsWith(COOKIE_HEADER_PREFIX)) {
|
||||
if (useCookies) {
|
||||
String temp = line.substring(
|
||||
SESSION_COOKIE_HEADER_PREFIX.length());
|
||||
temp = temp.substring(0, temp.indexOf(';'));
|
||||
setSessionId(temp);
|
||||
}
|
||||
}
|
||||
else if (line.startsWith(REDIRECT_HEADER_PREFIX)) {
|
||||
redirectUri = line.substring(REDIRECT_HEADER_PREFIX.length());
|
||||
}
|
||||
line = readLine();
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Read the body of the server response. Save its contents and
|
||||
* search it for uri-elements only if requested
|
||||
*/
|
||||
private void processBody(boolean wantBody) throws IOException {
|
||||
// Read the body, if one exists
|
||||
StringBuilder builder = new StringBuilder();
|
||||
if (wantBody) {
|
||||
if (useContentLength && (contentLength > -1)) {
|
||||
char[] body = new char[contentLength];
|
||||
int read = reader.read(body);
|
||||
Assert.assertEquals(contentLength, read);
|
||||
builder.append(body);
|
||||
}
|
||||
else {
|
||||
// not using content length, so just read it line by line
|
||||
String line = null;
|
||||
try {
|
||||
while ((line = readLine()) != null) {
|
||||
builder.append(line);
|
||||
}
|
||||
} catch (SocketException e) {
|
||||
// Ignore
|
||||
// May see a SocketException if the request hasn't been
|
||||
// fully read when the connection is closed as that may
|
||||
// trigger a TCP reset.
|
||||
}
|
||||
}
|
||||
}
|
||||
responseBody = builder.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Scan the response body for opening tags of certain HTML elements
|
||||
* (<a>, <form>). If any are found, then accumulate them.
|
||||
*
|
||||
* <p>
|
||||
* Note: This method has the following limitations: a) It assumes that the
|
||||
* response is HTML. b) It searches for lowercase tags only.
|
||||
*
|
||||
* @see #getResponseBodyUriElements()
|
||||
*/
|
||||
public void extractUriElements() {
|
||||
bodyUriElements = new ArrayList<>();
|
||||
if (responseBody.length() > 0) {
|
||||
int ix = 0;
|
||||
while ((ix = extractUriElement(responseBody, ix, RESOURCE_TAG)) > 0){
|
||||
// loop
|
||||
}
|
||||
ix = 0;
|
||||
while ((ix = extractUriElement(responseBody, ix, LOGIN_TAG)) > 0){
|
||||
// loop
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Scan an html body for a given html uri element, starting from the
|
||||
* given index into the source string. If any are found, simply
|
||||
* accumulate them as literal strings, including angle brackets.
|
||||
* note: nested elements will not be collected.
|
||||
*
|
||||
* @param body HTTP body of the response
|
||||
* @param startIx offset into the body to resume the scan (for iteration)
|
||||
* @param elementName to scan for (only one at a time)
|
||||
* @returns the index into the body to continue the scan (for iteration)
|
||||
*/
|
||||
private int extractUriElement(String body, int startIx, String elementName) {
|
||||
String detector = ELEMENT_HEAD + elementName + " ";
|
||||
int iStart = body.indexOf(detector, startIx);
|
||||
if (iStart > -1) {
|
||||
int iEnd = body.indexOf(ELEMENT_TAIL, iStart);
|
||||
if (iEnd < 0) {
|
||||
throw new IllegalArgumentException(
|
||||
"Response body check failure.\n"
|
||||
+ "element [" + detector + "] is not terminated with ["
|
||||
+ ELEMENT_TAIL + "]\nActual: [" + body + "]");
|
||||
}
|
||||
String element = body.substring(iStart, iEnd);
|
||||
bodyUriElements.add(element);
|
||||
iStart += element.length();
|
||||
}
|
||||
return iStart;
|
||||
}
|
||||
|
||||
public String readLine() throws IOException {
|
||||
return reader.readLine();
|
||||
}
|
||||
|
||||
public void disconnect() throws IOException {
|
||||
writer.close();
|
||||
reader.close();
|
||||
socket.close();
|
||||
}
|
||||
|
||||
public void reset() {
|
||||
socket = null;
|
||||
writer = null;
|
||||
reader = null;
|
||||
|
||||
request = null;
|
||||
requestPause = 1000;
|
||||
|
||||
useContinue = false;
|
||||
|
||||
resetResponse();
|
||||
}
|
||||
|
||||
public void resetResponse() {
|
||||
responseLine = null;
|
||||
responseHeaders = new ArrayList<>();
|
||||
responseBody = null;
|
||||
}
|
||||
|
||||
public boolean responseLineStartsWith(String expected) {
|
||||
String line = getResponseLine();
|
||||
if (line == null) {
|
||||
return false;
|
||||
}
|
||||
return line.startsWith(expected);
|
||||
}
|
||||
|
||||
public boolean isResponse100() {
|
||||
return responseLineStartsWith(INFO_100);
|
||||
}
|
||||
|
||||
public boolean isResponse200() {
|
||||
return responseLineStartsWith(OK_200);
|
||||
}
|
||||
|
||||
public boolean isResponse201() {
|
||||
return responseLineStartsWith(CREATED_201);
|
||||
}
|
||||
|
||||
public boolean isResponse204() {
|
||||
return responseLineStartsWith(NOCONTENT_204);
|
||||
}
|
||||
|
||||
public boolean isResponse302() {
|
||||
return responseLineStartsWith(REDIRECT_302);
|
||||
}
|
||||
|
||||
public boolean isResponse303() {
|
||||
return responseLineStartsWith(REDIRECT_303);
|
||||
}
|
||||
|
||||
public boolean isResponse400() {
|
||||
return responseLineStartsWith(FAIL_400);
|
||||
}
|
||||
|
||||
public boolean isResponse403() {
|
||||
return responseLineStartsWith(FORBIDDEN_403);
|
||||
}
|
||||
|
||||
public boolean isResponse404() {
|
||||
return responseLineStartsWith(FAIL_404);
|
||||
}
|
||||
|
||||
public boolean isResponse405() {
|
||||
return responseLineStartsWith(FAIL_405);
|
||||
}
|
||||
|
||||
public boolean isResponse408() {
|
||||
return responseLineStartsWith(TIMEOUT_408);
|
||||
}
|
||||
|
||||
public boolean isResponse413() {
|
||||
return responseLineStartsWith(FAIL_413);
|
||||
}
|
||||
|
||||
public boolean isResponse417() {
|
||||
return responseLineStartsWith(FAIL_417);
|
||||
}
|
||||
|
||||
public boolean isResponse50x() {
|
||||
return responseLineStartsWith(FAIL_50X);
|
||||
}
|
||||
|
||||
public boolean isResponse500() {
|
||||
return responseLineStartsWith(FAIL_500);
|
||||
}
|
||||
|
||||
public boolean isResponse501() {
|
||||
return responseLineStartsWith(FAIL_501);
|
||||
}
|
||||
|
||||
public Socket getSocket() {
|
||||
return socket;
|
||||
}
|
||||
|
||||
public abstract boolean isResponseBodyOK();
|
||||
}
|
||||
Reference in New Issue
Block a user