All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.apache.openejb.webadmin.httpd.HttpRequestImpl Maven / Gradle / Ivy

The newest version!
/**
 * 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.openejb.webadmin.httpd;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.DataInput;
import java.io.DataInputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.net.URLDecoder;
import java.rmi.RemoteException;
import java.util.HashMap;
import java.util.Hashtable;
import java.util.Iterator;
import java.util.Map;
import java.util.StringTokenizer;

import javax.naming.InitialContext;
import javax.naming.NamingException;

import org.apache.commons.fileupload.MultipartStream;
import org.apache.openejb.webadmin.HttpRequest;
import org.apache.openejb.webadmin.HttpSession;
import org.apache.openejb.core.stateful.StatefulEjbObjectHandler;
import org.apache.openejb.loader.FileUtils;

/** A class to take care of HTTP Requests.  It parses headers, content, form and url
 * parameters.
 * @author David Blevins
 * @author Tim Urberg
 */
public class HttpRequestImpl implements HttpRequest {
    public static final String FORM_URL_ENCODED = "application/x-www-form-urlencoded";
    public static final String MULITPART_FORM_DATA = "multipart/form-data";
    public static final String FILENAME = "filename";
    public static final String NAME = "name";

    /** 5.1   Request-Line */
    private String line;
    /** 5.1.1    Method */
    private int method;
    /** 5.1.2    Request-URI */
    private URL uri;
    /** the headers for this page */
    private HashMap headers;
    /** the form parameters for this page */
    private HashMap formParams = new HashMap();
    /** the URL (or query) parameters for this page */
    private HashMap queryParams = new HashMap();
    /** the content of the body of this page */
    private byte[] body;
    private String[][] formParamsArray;


    private String methodString;
    private String pathString;


    /**
     * @return Returns the methodString.
     */
    public String getMethodString() {
        return methodString;
    }

    /**
     * @return Returns the pathString.
     */
    public String getPathString() {
        return pathString;
    }

    /** Gets a header based the header name passed in.
     * @param name The name of the header to get
     * @return The value of the header
     */
    public String getHeader(String name) {
        return (String) headers.get(name);
    }

    /** Gets a form parameter based on the name passed in.
     * @param name The name of the form parameter to get
     * @return The value of the parameter
     */
    public String getFormParameter(String name) {
        return (String) formParams.get(name);
    }

    /** Gets all the form parameters in the form of a two-dimentional array
     *  The second dimention has two indexes which contain the key and value
     *  for example:
     *  
     *  for(int i=0; i
     *
     *  All values are strings
     * @return All the form parameters
     */
    public String[][] getFormParameters() {
        Iterator keys = formParams.keySet().iterator();
        String[][] returnValue = new String[formParams.size()][2];

        String temp;
        int i = 0;
        while (keys.hasNext()) {
            temp = (String) keys.next();
            returnValue[i][0] = temp;
            returnValue[i++][1] = (String) formParams.get(temp);
        }

        return returnValue;
    }

    /** Gets a URL (or query) parameter based on the name passed in.
     * @param name The name of the URL (or query) parameter
     * @return The value of the URL (or query) parameter
     */
    public String getQueryParameter(String name) {
        return (String) queryParams.get(name);
    }

    /** Gets an integer value of the request method.  These values are:
     *
     * OPTIONS = 0
     * GET     = 1
     * HEAD    = 2
     * POST    = 3
     * PUT     = 4
     * DELETE  = 5
     * TRACE   = 6
     * CONNECT = 7
     * UNSUPPORTED = 8
     * @return The integer value of the method
     */
    public int getMethod() {
        return method;
    }

    /** Gets the URI for the current URL page.
     * @return The URI
     */
    public URL getURI() {
        return uri;
    }

    /*------------------------------------------------------------*/
    /*  Methods for reading in and parsing a request              */
    /*------------------------------------------------------------*/
    /** parses the request into the 3 different parts, request, headers, and body
     * @param input the data input for this page
     * @throws IOException if an exception is thrown
     */
    protected void readMessage(InputStream input) throws IOException {
        DataInput in = new DataInputStream(input);

        readRequestLine(in);
        readHeaders(in);
        readBody(in);
    }

    private String requestLine;

    protected String getRequestLine(){
        return requestLine;
    }
    /** reads and parses the request line
     * @param in the input to be read
     * @throws IOException if an exception is thrown
     */
    private void readRequestLine(DataInput in) throws IOException {

        try {
            line = in.readLine();
            requestLine = line;
//            System.out.println(line);
        } catch (Exception e) {
            throw new IOException(
                "Could not read the HTTP Request Line :"
                    + e.getClass().getName()
                    + " : "
                    + e.getMessage());
        }

        StringTokenizer lineParts = new StringTokenizer(line, " ");
        /* [1] Parse the method */
        parseMethod(lineParts);
        /* [2] Parse the URI */
        parseURI(lineParts);
    }

    /** parses the method for this page
     * @param lineParts a StringTokenizer of the request line
     * @throws IOException if an exeption is thrown
     */
    private void parseMethod(StringTokenizer lineParts) throws IOException {
        String token = null;
        try {
            token = lineParts.nextToken();
        } catch (Exception e) {
            throw new IOException(
                "Could not parse the HTTP Request Method :"
                    + e.getClass().getName()
                    + " : "
                    + e.getMessage());
        }

        if (token.equalsIgnoreCase("GET")) {
            method = GET;
        } else if (token.equalsIgnoreCase("POST")) {
            method = POST;
        } else {
            method = UNSUPPORTED;
            throw new IOException("Unsupported HTTP Request Method :" + token);
        }
    }

    /** parses the URI into the different parts
     * @param lineParts a StringTokenizer of the URI
     * @throws IOException if an exeption is thrown
     */
    private void parseURI(StringTokenizer lineParts) throws IOException {
        String token = null;
        try {
            token = lineParts.nextToken();
        } catch (Exception e) {
            throw new IOException(
                "Could not parse the HTTP Request Method :"
                    + e.getClass().getName()
                    + " : "
                    + e.getMessage());
        }

        try {
            uri = new URL("http", "localhost", token);
        } catch (java.net.MalformedURLException e) {
            throw new IOException("Malformed URL :" + token + " Exception: " + e.getMessage());
        }

        parseQueryParams(uri.getQuery());
    }

    /** parses the URL (or query) parameters
     * @param query the URL (or query) parameters to be parsed
     * @throws IOException if an exception is thrown
     */
    private void parseQueryParams(String query) throws IOException {
        if (query == null)
            return;
        StringTokenizer parameters = new StringTokenizer(query, "&");

        while (parameters.hasMoreTokens()) {
            StringTokenizer param = new StringTokenizer(parameters.nextToken(), "=");

            /* [1] Parse the Name */
            if (!param.hasMoreTokens())
                continue;
            String name = URLDecoder.decode(param.nextToken());
            if (name == null)
                continue;

            /* [2] Parse the Value */
            if (!param.hasMoreTokens())
                continue;
            String value = URLDecoder.decode(param.nextToken());
            if (value == null)
                continue;

            //System.out.println("[] "+name+" = "+value);
            queryParams.put(name, value);
        }
    }

    /** reads the headers from the data input sent from the browser
     * @param in the data input sent from the browser
     * @throws IOException if an exeption is thrown
     */
    private void readHeaders(DataInput in) throws IOException {
//        System.out.println("\nREQUEST");
        headers = new HashMap();
        while (true) {
            // Header Field
            String hf = null;

            try {
                hf = in.readLine();
                //System.out.println(hf);
            } catch (Exception e) {
                throw new IOException(
                    "Could not read the HTTP Request Header Field :"
                        + e.getClass().getName()
                        + " : "
                        + e.getMessage());
            }

            if (hf == null || hf.equals("")) {
                break;
            }

            /* [1] parse the name */
            int colonIndex = hf.indexOf((int) ':');
            String name = hf.substring(0, colonIndex);
            if (name == null)
                break;

            /* [2] Parse the Value */
            String value = hf.substring(colonIndex + 1, hf.length());
            if (value == null)
                break;
            value = value.trim();
            headers.put(name, value);
        }

        //temp-debug-------------------------------------------
        //java.util.Iterator myKeys = headers.keySet().iterator();
        //String temp = null;
        //while(myKeys.hasNext()) {
        //    temp = (String)myKeys.next();
        //    System.out.println("Test: " + temp + "=" + headers.get(temp));
        //}
        //end temp-debug---------------------------------------
    }

    /** reads the body from the data input passed in
     * @param in the data input with the body of the page
     * @throws IOException if an exception is thrown
     */
    private void readBody(DataInput in) throws IOException {
        readRequestBody(in);
        //System.out.println("Body Length: " + body.length);
        // Content-type: application/x-www-form-urlencoded
        // or multipart/form-data
        String type = getHeader(HttpRequest.HEADER_CONTENT_TYPE);
        if (FORM_URL_ENCODED.equals(type)) {
            parseFormParams();
        } else if (type != null && type.startsWith(MULITPART_FORM_DATA)) {
            parseMultiPartFormParams();
        }
    }

    /** reads the request line of the data input
     * @param in the data input that contains the request line
     * @throws IOException if an exception is thrown
     */
    private void readRequestBody(DataInput in) throws IOException {
        // Content-length: 384
        String len = getHeader(HttpRequest.HEADER_CONTENT_LENGTH);
        //System.out.println("readRequestBody Content-Length: " + len);

        int length = -1;
        if (len != null) {
            try {
                length = Integer.parseInt(len);
            } catch (Exception e) {
                //don't care
            }
        }

        if (length < 1) {
            this.body = new byte[0];
        } else if (length > 0) {
            this.body = new byte[length];

            try {
                in.readFully(body);
            } catch (Exception e) {
                throw new IOException(
                    "Could not read the HTTP Request Body :"
                        + e.getClass().getName()
                        + " : "
                        + e.getMessage());
            }
        }
    }

    /** parses form parameters into the formParams variable
     * @throws IOException if an exeption is thrown
     */
    private void parseFormParams() throws IOException {
        String rawParams = new String(body);
        //System.out.println("rawParams: " + rawParams);
        StringTokenizer parameters = new StringTokenizer(rawParams, "&");
        String name = null;
        String value = null;

        while (parameters.hasMoreTokens()) {
            StringTokenizer param = new StringTokenizer(parameters.nextToken(), "=");

            /* [1] Parse the Name */
            name = URLDecoder.decode(param.nextToken());
            if (name == null)
                break;

            /* [2] Parse the Value */
            if (param.hasMoreTokens()) {
                value = URLDecoder.decode(param.nextToken());
            } else {
                value = ""; //if there is no token set value to blank string
            }

            if (value == null)
                value = "";

            formParams.put(name, value);
            //System.out.println(name + ": " + value);
        }
    }

    /**
     * A method which parses form parameters that are multipart/form-data
     * according to 
     * RFC 1867.  Currently multipart/mixed is not implemented.
     */
    private void parseMultiPartFormParams() throws IOException {
        /* see http://www.ietf.org/rfc/rfc1867.txt */
        ByteArrayOutputStream output;
        StringBuffer multiPartBuffer;
        int j;
        Map headerMap;
        boolean isFile;
        String fileName = null;
        byte[] outputArray;
        FileOutputStream fos;

        String contentType = getHeader(HttpRequest.HEADER_CONTENT_TYPE);
        int boundaryIndex = contentType.indexOf("boundary=");
        if (boundaryIndex < 0) {
            throw new IOException("the request was rejected because no multipart boundary was found");
        }
        byte[] boundary = contentType.substring(boundaryIndex + 9).getBytes();

        ByteArrayInputStream input = new ByteArrayInputStream(body);
        MultipartStream multi = new MultipartStream(input, boundary);

        boolean nextPart = multi.skipPreamble();
        while (nextPart) {
            try {
                output = new ByteArrayOutputStream();
                multi.readBodyData(output);
                outputArray = output.toByteArray();
                multiPartBuffer = new StringBuffer(50);
                isFile = false;
                File jarFileInTempDir;
                j = 0;

                for (int i = 0; i < outputArray.length; i++) {
                    //first check for \r\n end of line
                    if (outputArray[i] == 13 && outputArray[i + 1] == 10) {
                        //we've come to the end of a line
                        headerMap = parseMultiPartHeader(multiPartBuffer);
                        if (headerMap.get(NAME) != null) {
                            fileName = (String) headerMap.get(NAME);
                        }

                        //add the filename if there is one
                        if (fileName != null && headerMap.get(FILENAME) != null) {
                            this.formParams.put(fileName, headerMap.get(FILENAME));
                            isFile = true;
                        }

                        if (outputArray[i + 2] == 13 && outputArray[i + 3] == 10) {
                            //we've reached the blank line
                            i+=4;
                            j = i;
                            break;
                        } else {
                            i++;
                        }

                        multiPartBuffer = new StringBuffer(50);
                    } else {
                        multiPartBuffer.append((char) outputArray[i]);
                    }
                }

                //here we know that we have a file and that we need to write it
                if (isFile) {
                    //create file
                    jarFileInTempDir = new File((String) this.formParams.get(fileName));
                    if (!jarFileInTempDir.exists()) {
                        jarFileInTempDir.createNewFile();
                    }

                    //write the byte array to the file
                    fos = new FileOutputStream(jarFileInTempDir);
                    fos.write(outputArray, j, outputArray.length-j);
                    fos.close();
                } else { //form data, not a file
                    multiPartBuffer = new StringBuffer(outputArray.length-j);
                    for (int i = j; i < outputArray.length; i++) {
                        multiPartBuffer.append((char)outputArray[i]);
                    }

                    this.formParams.put(
                        fileName,
                        multiPartBuffer.toString());
                }

                nextPart = multi.readBoundary();
            } catch (MultipartStream.MalformedStreamException mse) {
                throw new IOException(mse.getMessage());
            }
        }
    }

    /**
     * Parses the first one or two lines of a multipart.  The usual headers are
     * Content-Dispostion or Content-Type.
     *
     * @param headerBuffer - the header string to be parsed
     * @return a map of of header info and their values
     */
    private Map parseMultiPartHeader(StringBuffer headerBuffer) throws IOException {
        Map headerMap = new HashMap();
        int colonIndex = headerBuffer.toString().indexOf(":");
        String headerName = headerBuffer.substring(0, colonIndex);
        StringTokenizer headerValueToken =
            new StringTokenizer(headerBuffer.substring(colonIndex + 1, headerBuffer.length()), ";");

        String currentToken;
        //loop through the tokens of semi-colon
        while (headerValueToken.hasMoreTokens()) {
            currentToken = headerValueToken.nextToken();
            if (currentToken.indexOf("=") > -1) {
                headerMap.put(
                    currentToken.substring(0, currentToken.indexOf("=")).trim(),
                    currentToken
                        .substring(currentToken.indexOf("=") + 2, currentToken.length() - 1)
                        .trim());
            } else {
                headerMap.put(headerName, currentToken.trim());
            }
        }

        //first get rid of any path that might already be there then
        //change the path of the file name to a temp directory
        String fileName = (String) headerMap.get(FILENAME);
        if (fileName != null) {
            StringBuffer temp;
            if (fileName.indexOf("\\") > -1) {
                temp = new StringBuffer(fileName).reverse();
                fileName = temp.delete(temp.toString().indexOf("\\"), temp.length()).reverse().toString();
            }

            temp = new StringBuffer();
            temp.append(FileUtils.createTempDirectory().getAbsolutePath());
            temp.append(System.getProperty("file.separator"));
            temp.append(fileName);
            headerMap.put(FILENAME, temp.toString());
        }

        return headerMap;
    }

    private HashMap cookies;

    protected HashMap getCookies(){
        if (cookies != null) return cookies;

        cookies = new HashMap();

        String cookieHeader = getHeader(HEADER_COOKIE);
        if (cookieHeader == null ) return cookies;

        StringTokenizer tokens = new StringTokenizer(cookieHeader, ";");
        while (tokens.hasMoreTokens()){
            StringTokenizer token = new StringTokenizer(tokens.nextToken(),"=");
            String name = token.nextToken();
            String value = token.nextToken();
            cookies.put(name, value);
        }
        return cookies;
    }

    protected static final String EJBSESSIONID = "EJBSESSIONID";

    protected String getCookie(String name){
        return (String) getCookies().get(name);
    }

    public HttpSession getSession() {
        return getSession(true);
    }

    private WebSession session;

    public HttpSession getSession(boolean create) {
        if (session != null) return session;

        String id = getCookie(EJBSESSIONID);

        if (id != null) {
            session = (WebSession)sessions.get(id);
        }

        if (session == null && create){
            session = createSession();
            sessions.put(session.getId(), session);
        }
        return session;
    }

    private static final Hashtable sessions = new Hashtable();

    private WebSession createSession(){
        // Lookup/create sessions
        WebSessionHome home = null;

        try {
            home = (WebSessionHome)new InitialContext().lookup("java:openejb/local/httpd/session");
        } catch (NamingException e) {
            // TODO Auto-generated catch block
            throw new IllegalStateException("The WebSessionBean has not been deployed. "+
                    " This is required for the HTTPd service to provide HttpSession support. "+
                    e.getClass().getName()+": "+e.getMessage());
        }


        WebSession session = null;
        try {
            session = home.create();
        } catch (RemoteException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        // mark them as nocopy
        Object obj = org.apache.openejb.util.proxy.ProxyManager.getInvocationHandler(session);
        StatefulEjbObjectHandler handler = (StatefulEjbObjectHandler) obj;
        handler.setIntraVmCopyMode(false);
        return session;
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy