/* * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. * * Copyright (c) 2012 Oracle and/or its affiliates. All rights reserved. * * The contents of this file are subject to the terms of either the GNU * General Public License Version 2 only ("GPL") or the Common Development * and Distribution License("CDDL") (collectively, the "License"). You * may not use this file except in compliance with the License. You can * obtain a copy of the License at * https://glassfish.dev.java.net/public/CDDL+GPL_1_1.html * or packager/legal/LICENSE.txt. See the License for the specific * language governing permissions and limitations under the License. * * When distributing the software, include this License Header Notice in each * file and include the License file at packager/legal/LICENSE.txt. * * GPL Classpath Exception: * Oracle designates this particular file as subject to the "Classpath" * exception as provided by Oracle in the GPL Version 2 section of the License * file that accompanied this code. * * Modifications: * If applicable, add the following below the License Header, with the fields * enclosed by brackets [] replaced by your own identifying information: * "Portions Copyright [year] [name of copyright owner]" * * Contributor(s): * If you wish your version of this file to be governed by only the CDDL or * only the GPL Version 2, indicate your decision by adding "[Contributor] * elects to include this software in this distribution under the [CDDL or GPL * Version 2] license." If you don't indicate a single choice of license, a * recipient has the option to distribute your version of this file under * either the CDDL, the GPL Version 2 or to extend the choice of license to * its licensees as provided above. However, if you add GPL Version 2 code * and therefore, elected the GPL Version 2 license, then the option applies * only if the new code is made subject to such option by the copyright * holder. * * * This file incorporates work covered by the following copyright and * permission notice: * * 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.UnknownHostException; import java.util.ArrayList; import java.util.List; /** * 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 boolean DEBUG = Boolean.getBoolean("debug"); public static final String CRLF = "\r\n"; public static final String INFO_100 = "HTTP/1.1 100"; public static final String OK_200 = "HTTP/1.1 200"; public static final String REDIRECT_302 = "HTTP/1.1 302"; public static final String FAIL_400 = "HTTP/1.1 400"; public static final String FAIL_404 = "HTTP/1.1 404"; public static final String FAIL_413 = "HTTP/1.1 413"; 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 SESSION_COOKIE_HEADER_PREFIX = "Set-Cookie: JSESSIONID="; private Socket socket; private Writer writer; private BufferedReader reader; private String host = "localhost"; private int port = 8080; private String[] request; private boolean useContinue = false; private int requestPause = 1000; private String responseLine; private List<String> responseHeaders = new ArrayList<String>(); private String responseBody; private boolean useContentLength; protected void setHost(String theHost) { host = theHost; } protected void setPort(int thePort) { port = thePort; } public void setRequest(String[] theRequest) { request = theRequest; } public void setUseContinue(boolean theUseContinueFlag) { useContinue = theUseContinueFlag; } public boolean getUseContinue() { return useContinue; } public void setRequestPause(int theRequestPause) { requestPause = theRequestPause; } public String getResponseLine() { return responseLine; } public List<String> getResponseHeaders() { return responseHeaders; } public String getResponseBody() { return responseBody; } public void setUseContentLength(boolean b) { useContentLength = b; } public String getSessionId() { for (String header : responseHeaders) { if (header.startsWith(SESSION_COOKIE_HEADER_PREFIX)) { header = header.substring(SESSION_COOKIE_HEADER_PREFIX.length()); header = header.substring(0, header.indexOf(';')); return header; } } return null; } public void connect(int connectTimeout, int soTimeout) throws UnknownHostException, IOException { final String encoding = "ISO-8859-1"; SocketAddress addr = new InetSocketAddress(host, port); socket = new Socket(); socket.setSoTimeout(soTimeout); socket.connect(addr,connectTimeout); OutputStream os = socket.getOutputStream(); 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); } public void processRequest() throws IOException, InterruptedException { processRequest(true); } public void processRequest(boolean readBody) throws IOException, InterruptedException { sendRequest(); readResponse(readBody); } public void sendRequest() throws InterruptedException, IOException { // Send the request boolean first = true; for (String requestPart : request) { if (first) { first = false; } else { Thread.sleep(requestPause); } writer.write(requestPart); writer.flush(); debug(requestPart); } } public void readResponse(boolean readBody) throws IOException { // Reset fields use to hold response responseLine = null; responseHeaders.clear(); responseBody = null; // Read the response 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 the map String line = readLine(); int cl = -1; while (line!=null && line.length() > 0) { responseHeaders.add(line); line = readLine(); if (line != null && line.startsWith("Content-Length: ")) { cl = Integer.parseInt(line.substring(16)); } } // Read the body, if any StringBuilder builder = new StringBuilder(); if (readBody) { if (cl > -1 && useContentLength) { char[] body = new char[cl]; reader.read(body); builder.append(body); } else { line = readLine(); while (line != null) { builder.append(line); line = readLine(); } } } responseBody = builder.toString(); } public String readLine() throws IOException { String line = reader.readLine(); if (line != null) { debug(line); } return line; } public void disconnect() throws IOException { if (writer != null) { try { writer.close(); } catch(Throwable t) { } } if (reader != null) { try { reader.close(); } catch(Throwable t) { } } if (socket != null) { try { socket.close(); } catch(Throwable t) { } } } public void reset() { socket = null; writer = null; reader = null; request = null; requestPause = 1000; useContinue = false; responseLine = null; responseHeaders = new ArrayList<String>(); responseBody = null; } public boolean isResponse100() { return getResponseLine().startsWith(INFO_100); } public boolean isResponse200() { return getResponseLine().startsWith(OK_200); } public boolean isResponse302() { return getResponseLine().startsWith(REDIRECT_302); } public boolean isResponse400() { return getResponseLine().startsWith(FAIL_400); } public boolean isResponse404() { return getResponseLine().startsWith(FAIL_404); } public boolean isResponse413() { return getResponseLine().startsWith(FAIL_413); } public boolean isResponse50x() { return getResponseLine().startsWith(FAIL_50X); } public boolean isResponse500() { return getResponseLine().startsWith(FAIL_500); } public boolean isResponse501() { return getResponseLine().startsWith(FAIL_501); } public Socket getSocket() { return socket; } public abstract boolean isResponseBodyOK(); private void debug(String message) { if (DEBUG) { System.out.println(message); } } }