Home » openejb-3.1.2-src » org.apache » openejb » webadmin » httpd » [javadoc | source]

    1   /**
    2    * Licensed to the Apache Software Foundation (ASF) under one or more
    3    * contributor license agreements.  See the NOTICE file distributed with
    4    * this work for additional information regarding copyright ownership.
    5    * The ASF licenses this file to You under the Apache License, Version 2.0
    6    * (the "License"); you may not use this file except in compliance with
    7    * the License.  You may obtain a copy of the License at
    8    *
    9    *     http://www.apache.org/licenses/LICENSE-2.0
   10    *
   11    * Unless required by applicable law or agreed to in writing, software
   12    * distributed under the License is distributed on an "AS IS" BASIS,
   13    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   14    * See the License for the specific language governing permissions and
   15    * limitations under the License.
   16    */
   17   package org.apache.openejb.webadmin.httpd;
   18   
   19   import java.io.ByteArrayInputStream;
   20   import java.io.ByteArrayOutputStream;
   21   import java.io.DataInput;
   22   import java.io.DataInputStream;
   23   import java.io.File;
   24   import java.io.FileOutputStream;
   25   import java.io.IOException;
   26   import java.io.InputStream;
   27   import java.net.URL;
   28   import java.net.URLDecoder;
   29   import java.rmi.RemoteException;
   30   import java.util.HashMap;
   31   import java.util.Hashtable;
   32   import java.util.Iterator;
   33   import java.util.Map;
   34   import java.util.StringTokenizer;
   35   
   36   import javax.naming.InitialContext;
   37   import javax.naming.NamingException;
   38   
   39   import org.apache.commons.fileupload.MultipartStream;
   40   import org.apache.openejb.webadmin.HttpRequest;
   41   import org.apache.openejb.webadmin.HttpSession;
   42   import org.apache.openejb.core.stateful.StatefulEjbObjectHandler;
   43   import org.apache.openejb.loader.FileUtils;
   44   
   45   /** A class to take care of HTTP Requests.  It parses headers, content, form and url
   46    * parameters.
   47    * @author <a href="mailto:david.blevins@visi.com">David Blevins</a>
   48    * @author <a href="mailto:tim_urberg@yahoo.com">Tim Urberg</a>
   49    */
   50   public class HttpRequestImpl implements HttpRequest {
   51       public static final String FORM_URL_ENCODED = "application/x-www-form-urlencoded";
   52       public static final String MULITPART_FORM_DATA = "multipart/form-data";
   53       public static final String FILENAME = "filename";
   54       public static final String NAME = "name";
   55   
   56       /** 5.1   Request-Line */
   57       private String line;
   58       /** 5.1.1    Method */
   59       private int method;
   60       /** 5.1.2    Request-URI */
   61       private URL uri;
   62       /** the headers for this page */
   63       private HashMap headers;
   64       /** the form parameters for this page */
   65       private HashMap formParams = new HashMap();
   66       /** the URL (or query) parameters for this page */
   67       private HashMap queryParams = new HashMap();
   68       /** the content of the body of this page */
   69       private byte[] body;
   70       private String[][] formParamsArray;
   71   
   72   
   73       private String methodString;
   74       private String pathString;
   75   
   76   
   77       /**
   78        * @return Returns the methodString.
   79        */
   80       public String getMethodString() {
   81           return methodString;
   82       }
   83   
   84       /**
   85        * @return Returns the pathString.
   86        */
   87       public String getPathString() {
   88           return pathString;
   89       }
   90   
   91       /** Gets a header based the header name passed in.
   92        * @param name The name of the header to get
   93        * @return The value of the header
   94        */
   95       public String getHeader(String name) {
   96           return (String) headers.get(name);
   97       }
   98   
   99       /** Gets a form parameter based on the name passed in.
  100        * @param name The name of the form parameter to get
  101        * @return The value of the parameter
  102        */
  103       public String getFormParameter(String name) {
  104           return (String) formParams.get(name);
  105       }
  106   
  107       /** Gets all the form parameters in the form of a two-dimentional array
  108        *  The second dimention has two indexes which contain the key and value
  109        *  for example:
  110        *  <code>
  111        *  for(int i=0; i<formParams.length; i++) {
  112        *     key = formParams[i][0];
  113        *     value = formParams[i][1];
  114        *  }
  115        *  </code>
  116        *
  117        *  All values are strings
  118        * @return All the form parameters
  119        */
  120       public String[][] getFormParameters() {
  121           Iterator keys = formParams.keySet().iterator();
  122           String[][] returnValue = new String[formParams.size()][2];
  123   
  124           String temp;
  125           int i = 0;
  126           while (keys.hasNext()) {
  127               temp = (String) keys.next();
  128               returnValue[i][0] = temp;
  129               returnValue[i++][1] = (String) formParams.get(temp);
  130           }
  131   
  132           return returnValue;
  133       }
  134   
  135       /** Gets a URL (or query) parameter based on the name passed in.
  136        * @param name The name of the URL (or query) parameter
  137        * @return The value of the URL (or query) parameter
  138        */
  139       public String getQueryParameter(String name) {
  140           return (String) queryParams.get(name);
  141       }
  142   
  143       /** Gets an integer value of the request method.  These values are:
  144        *
  145        * OPTIONS = 0
  146        * GET     = 1
  147        * HEAD    = 2
  148        * POST    = 3
  149        * PUT     = 4
  150        * DELETE  = 5
  151        * TRACE   = 6
  152        * CONNECT = 7
  153        * UNSUPPORTED = 8
  154        * @return The integer value of the method
  155        */
  156       public int getMethod() {
  157           return method;
  158       }
  159   
  160       /** Gets the URI for the current URL page.
  161        * @return The URI
  162        */
  163       public URL getURI() {
  164           return uri;
  165       }
  166   
  167       /*------------------------------------------------------------*/
  168       /*  Methods for reading in and parsing a request              */
  169       /*------------------------------------------------------------*/
  170       /** parses the request into the 3 different parts, request, headers, and body
  171        * @param input the data input for this page
  172        * @throws IOException if an exception is thrown
  173        */
  174       protected void readMessage(InputStream input) throws IOException {
  175           DataInput in = new DataInputStream(input);
  176   
  177           readRequestLine(in);
  178           readHeaders(in);
  179           readBody(in);
  180       }
  181   
  182       private String requestLine;
  183   
  184       protected String getRequestLine(){
  185           return requestLine;
  186       }
  187       /** reads and parses the request line
  188        * @param in the input to be read
  189        * @throws IOException if an exception is thrown
  190        */
  191       private void readRequestLine(DataInput in) throws IOException {
  192   
  193           try {
  194               line = in.readLine();
  195               requestLine = line;
  196   //            System.out.println(line);
  197           } catch (Exception e) {
  198               throw new IOException(
  199                   "Could not read the HTTP Request Line :"
  200                       + e.getClass().getName()
  201                       + " : "
  202                       + e.getMessage());
  203           }
  204   
  205           StringTokenizer lineParts = new StringTokenizer(line, " ");
  206           /* [1] Parse the method */
  207           parseMethod(lineParts);
  208           /* [2] Parse the URI */
  209           parseURI(lineParts);
  210       }
  211   
  212       /** parses the method for this page
  213        * @param lineParts a StringTokenizer of the request line
  214        * @throws IOException if an exeption is thrown
  215        */
  216       private void parseMethod(StringTokenizer lineParts) throws IOException {
  217           String token = null;
  218           try {
  219               token = lineParts.nextToken();
  220           } catch (Exception e) {
  221               throw new IOException(
  222                   "Could not parse the HTTP Request Method :"
  223                       + e.getClass().getName()
  224                       + " : "
  225                       + e.getMessage());
  226           }
  227   
  228           if (token.equalsIgnoreCase("GET")) {
  229               method = GET;
  230           } else if (token.equalsIgnoreCase("POST")) {
  231               method = POST;
  232           } else {
  233               method = UNSUPPORTED;
  234               throw new IOException("Unsupported HTTP Request Method :" + token);
  235           }
  236       }
  237   
  238       /** parses the URI into the different parts
  239        * @param lineParts a StringTokenizer of the URI
  240        * @throws IOException if an exeption is thrown
  241        */
  242       private void parseURI(StringTokenizer lineParts) throws IOException {
  243           String token = null;
  244           try {
  245               token = lineParts.nextToken();
  246           } catch (Exception e) {
  247               throw new IOException(
  248                   "Could not parse the HTTP Request Method :"
  249                       + e.getClass().getName()
  250                       + " : "
  251                       + e.getMessage());
  252           }
  253   
  254           try {
  255               uri = new URL("http", "localhost", token);
  256           } catch (java.net.MalformedURLException e) {
  257               throw new IOException("Malformed URL :" + token + " Exception: " + e.getMessage());
  258           }
  259   
  260           parseQueryParams(uri.getQuery());
  261       }
  262   
  263       /** parses the URL (or query) parameters
  264        * @param query the URL (or query) parameters to be parsed
  265        * @throws IOException if an exception is thrown
  266        */
  267       private void parseQueryParams(String query) throws IOException {
  268           if (query == null)
  269               return;
  270           StringTokenizer parameters = new StringTokenizer(query, "&");
  271   
  272           while (parameters.hasMoreTokens()) {
  273               StringTokenizer param = new StringTokenizer(parameters.nextToken(), "=");
  274   
  275               /* [1] Parse the Name */
  276               if (!param.hasMoreTokens())
  277                   continue;
  278               String name = URLDecoder.decode(param.nextToken());
  279               if (name == null)
  280                   continue;
  281   
  282               /* [2] Parse the Value */
  283               if (!param.hasMoreTokens())
  284                   continue;
  285               String value = URLDecoder.decode(param.nextToken());
  286               if (value == null)
  287                   continue;
  288   
  289               //System.out.println("[] "+name+" = "+value);
  290               queryParams.put(name, value);
  291           }
  292       }
  293   
  294       /** reads the headers from the data input sent from the browser
  295        * @param in the data input sent from the browser
  296        * @throws IOException if an exeption is thrown
  297        */
  298       private void readHeaders(DataInput in) throws IOException {
  299   //        System.out.println("\nREQUEST");
  300           headers = new HashMap();
  301           while (true) {
  302               // Header Field
  303               String hf = null;
  304   
  305               try {
  306                   hf = in.readLine();
  307                   //System.out.println(hf);
  308               } catch (Exception e) {
  309                   throw new IOException(
  310                       "Could not read the HTTP Request Header Field :"
  311                           + e.getClass().getName()
  312                           + " : "
  313                           + e.getMessage());
  314               }
  315   
  316               if (hf == null || hf.equals("")) {
  317                   break;
  318               }
  319   
  320               /* [1] parse the name */
  321               int colonIndex = hf.indexOf((int) ':');
  322               String name = hf.substring(0, colonIndex);
  323               if (name == null)
  324                   break;
  325   
  326               /* [2] Parse the Value */
  327               String value = hf.substring(colonIndex + 1, hf.length());
  328               if (value == null)
  329                   break;
  330               value = value.trim();
  331               headers.put(name, value);
  332           }
  333   
  334           //temp-debug-------------------------------------------
  335           //java.util.Iterator myKeys = headers.keySet().iterator();
  336           //String temp = null;
  337           //while(myKeys.hasNext()) {
  338           //    temp = (String)myKeys.next();
  339           //    System.out.println("Test: " + temp + "=" + headers.get(temp));
  340           //}
  341           //end temp-debug---------------------------------------
  342       }
  343   
  344       /** reads the body from the data input passed in
  345        * @param in the data input with the body of the page
  346        * @throws IOException if an exception is thrown
  347        */
  348       private void readBody(DataInput in) throws IOException {
  349           readRequestBody(in);
  350           //System.out.println("Body Length: " + body.length);
  351           // Content-type: application/x-www-form-urlencoded
  352           // or multipart/form-data
  353           String type = getHeader(HttpRequest.HEADER_CONTENT_TYPE);
  354           if (FORM_URL_ENCODED.equals(type)) {
  355               parseFormParams();
  356           } else if (type != null && type.startsWith(MULITPART_FORM_DATA)) {
  357               parseMultiPartFormParams();
  358           }
  359       }
  360   
  361       /** reads the request line of the data input
  362        * @param in the data input that contains the request line
  363        * @throws IOException if an exception is thrown
  364        */
  365       private void readRequestBody(DataInput in) throws IOException {
  366           // Content-length: 384
  367           String len = getHeader(HttpRequest.HEADER_CONTENT_LENGTH);
  368           //System.out.println("readRequestBody Content-Length: " + len);
  369   
  370           int length = -1;
  371           if (len != null) {
  372               try {
  373                   length = Integer.parseInt(len);
  374               } catch (Exception e) {
  375                   //don't care
  376               }
  377           }
  378   
  379           if (length < 1) {
  380               this.body = new byte[0];
  381           } else if (length > 0) {
  382               this.body = new byte[length];
  383   
  384               try {
  385                   in.readFully(body);
  386               } catch (Exception e) {
  387                   throw new IOException(
  388                       "Could not read the HTTP Request Body :"
  389                           + e.getClass().getName()
  390                           + " : "
  391                           + e.getMessage());
  392               }
  393           }
  394       }
  395   
  396       /** parses form parameters into the formParams variable
  397        * @throws IOException if an exeption is thrown
  398        */
  399       private void parseFormParams() throws IOException {
  400           String rawParams = new String(body);
  401           //System.out.println("rawParams: " + rawParams);
  402           StringTokenizer parameters = new StringTokenizer(rawParams, "&");
  403           String name = null;
  404           String value = null;
  405   
  406           while (parameters.hasMoreTokens()) {
  407               StringTokenizer param = new StringTokenizer(parameters.nextToken(), "=");
  408   
  409               /* [1] Parse the Name */
  410               name = URLDecoder.decode(param.nextToken());
  411               if (name == null)
  412                   break;
  413   
  414               /* [2] Parse the Value */
  415               if (param.hasMoreTokens()) {
  416                   value = URLDecoder.decode(param.nextToken());
  417               } else {
  418                   value = ""; //if there is no token set value to blank string
  419               }
  420   
  421               if (value == null)
  422                   value = "";
  423   
  424               formParams.put(name, value);
  425               //System.out.println(name + ": " + value);
  426           }
  427       }
  428   
  429       /**
  430        * A method which parses form parameters that are multipart/form-data
  431        * according to <a href="http://www.ietf.org/rfc/rfc1867.txt" target="_blank">
  432        * RFC 1867</a>.  Currently multipart/mixed is not implemented.
  433        */
  434       private void parseMultiPartFormParams() throws IOException {
  435           /* see http://www.ietf.org/rfc/rfc1867.txt */
  436           ByteArrayOutputStream output;
  437           StringBuffer multiPartBuffer;
  438           int j;
  439           Map headerMap;
  440           boolean isFile;
  441           String fileName = null;
  442           byte[] outputArray;
  443           FileOutputStream fos;
  444   
  445           String contentType = getHeader(HttpRequest.HEADER_CONTENT_TYPE);
  446           int boundaryIndex = contentType.indexOf("boundary=");
  447           if (boundaryIndex < 0) {
  448               throw new IOException("the request was rejected because no multipart boundary was found");
  449           }
  450           byte[] boundary = contentType.substring(boundaryIndex + 9).getBytes();
  451   
  452           ByteArrayInputStream input = new ByteArrayInputStream(body);
  453           MultipartStream multi = new MultipartStream(input, boundary);
  454   
  455           boolean nextPart = multi.skipPreamble();
  456           while (nextPart) {
  457               try {
  458                   output = new ByteArrayOutputStream();
  459                   multi.readBodyData(output);
  460                   outputArray = output.toByteArray();
  461                   multiPartBuffer = new StringBuffer(50);
  462                   isFile = false;
  463                   File jarFileInTempDir;
  464                   j = 0;
  465   
  466                   for (int i = 0; i < outputArray.length; i++) {
  467                       //first check for \r\n end of line
  468                       if (outputArray[i] == 13 && outputArray[i + 1] == 10) {
  469                           //we've come to the end of a line
  470                           headerMap = parseMultiPartHeader(multiPartBuffer);
  471                           if (headerMap.get(NAME) != null) {
  472                               fileName = (String) headerMap.get(NAME);
  473                           }
  474   
  475                           //add the filename if there is one
  476                           if (fileName != null && headerMap.get(FILENAME) != null) {
  477                               this.formParams.put(fileName, headerMap.get(FILENAME));
  478                               isFile = true;
  479                           }
  480   
  481                           if (outputArray[i + 2] == 13 && outputArray[i + 3] == 10) {
  482                               //we've reached the blank line
  483                               i+=4;
  484                               j = i;
  485                               break;
  486                           } else {
  487                               i++;
  488                           }
  489   
  490                           multiPartBuffer = new StringBuffer(50);
  491                       } else {
  492                           multiPartBuffer.append((char) outputArray[i]);
  493                       }
  494                   }
  495   
  496                   //here we know that we have a file and that we need to write it
  497                   if (isFile) {
  498                       //create file
  499                       jarFileInTempDir = new File((String) this.formParams.get(fileName));
  500                       if (!jarFileInTempDir.exists()) {
  501                           jarFileInTempDir.createNewFile();
  502                       }
  503   
  504                       //write the byte array to the file
  505                       fos = new FileOutputStream(jarFileInTempDir);
  506                       fos.write(outputArray, j, outputArray.length-j);
  507                       fos.close();
  508                   } else { //form data, not a file
  509                       multiPartBuffer = new StringBuffer(outputArray.length-j);
  510                       for (int i = j; i < outputArray.length; i++) {
  511                           multiPartBuffer.append((char)outputArray[i]);
  512                       }
  513   
  514                       this.formParams.put(
  515                           fileName,
  516                           multiPartBuffer.toString());
  517                   }
  518   
  519                   nextPart = multi.readBoundary();
  520               } catch (MultipartStream.MalformedStreamException mse) {
  521                   throw new IOException(mse.getMessage());
  522               }
  523           }
  524       }
  525   
  526       /**
  527        * Parses the first one or two lines of a multipart.  The usual headers are
  528        * Content-Dispostion or Content-Type.
  529        *
  530        * @param headerBuffer - the header string to be parsed
  531        * @return a map of of header info and their values
  532        */
  533       private Map parseMultiPartHeader(StringBuffer headerBuffer) throws IOException {
  534           Map headerMap = new HashMap();
  535           int colonIndex = headerBuffer.toString().indexOf(":");
  536           String headerName = headerBuffer.substring(0, colonIndex);
  537           StringTokenizer headerValueToken =
  538               new StringTokenizer(headerBuffer.substring(colonIndex + 1, headerBuffer.length()), ";");
  539   
  540           String currentToken;
  541           //loop through the tokens of semi-colon
  542           while (headerValueToken.hasMoreTokens()) {
  543               currentToken = headerValueToken.nextToken();
  544               if (currentToken.indexOf("=") > -1) {
  545                   headerMap.put(
  546                       currentToken.substring(0, currentToken.indexOf("=")).trim(),
  547                       currentToken
  548                           .substring(currentToken.indexOf("=") + 2, currentToken.length() - 1)
  549                           .trim());
  550               } else {
  551                   headerMap.put(headerName, currentToken.trim());
  552               }
  553           }
  554   
  555           //first get rid of any path that might already be there then
  556           //change the path of the file name to a temp directory
  557           String fileName = (String) headerMap.get(FILENAME);
  558           if (fileName != null) {
  559               StringBuffer temp;
  560               if (fileName.indexOf("\\") > -1) {
  561                   temp = new StringBuffer(fileName).reverse();
  562                   fileName = temp.delete(temp.toString().indexOf("\\"), temp.length()).reverse().toString();
  563               }
  564   
  565               temp = new StringBuffer();
  566               temp.append(FileUtils.createTempDirectory().getAbsolutePath());
  567               temp.append(System.getProperty("file.separator"));
  568               temp.append(fileName);
  569               headerMap.put(FILENAME, temp.toString());
  570           }
  571   
  572           return headerMap;
  573       }
  574   
  575       private HashMap cookies;
  576   
  577       protected HashMap getCookies(){
  578           if (cookies != null) return cookies;
  579   
  580           cookies = new HashMap();
  581   
  582           String cookieHeader = getHeader(HEADER_COOKIE);
  583           if (cookieHeader == null ) return cookies;
  584   
  585           StringTokenizer tokens = new StringTokenizer(cookieHeader, ";");
  586           while (tokens.hasMoreTokens()){
  587               StringTokenizer token = new StringTokenizer(tokens.nextToken(),"=");
  588               String name = token.nextToken();
  589               String value = token.nextToken();
  590               cookies.put(name, value);
  591           }
  592           return cookies;
  593       }
  594   
  595       protected static final String EJBSESSIONID = "EJBSESSIONID";
  596   
  597       protected String getCookie(String name){
  598           return (String) getCookies().get(name);
  599       }
  600   
  601       public HttpSession getSession() {
  602           return getSession(true);
  603       }
  604   
  605       private WebSession session;
  606   
  607       public HttpSession getSession(boolean create) {
  608           if (session != null) return session;
  609   
  610           String id = getCookie(EJBSESSIONID);
  611   
  612           if (id != null) {
  613               session = (WebSession)sessions.get(id);
  614           }
  615   
  616           if (session == null && create){
  617               session = createSession();
  618               sessions.put(session.getId(), session);
  619           }
  620           return session;
  621       }
  622   
  623       private static final Hashtable sessions = new Hashtable();
  624   
  625       private WebSession createSession(){
  626           // Lookup/create sessions
  627           WebSessionHome home = null;
  628   
  629           try {
  630               home = (WebSessionHome)new InitialContext().lookup("java:openejb/local/httpd/session");
  631           } catch (NamingException e) {
  632               // TODO Auto-generated catch block
  633               throw new IllegalStateException("The WebSessionBean has not been deployed. "+
  634                       " This is required for the HTTPd service to provide HttpSession support. "+
  635                       e.getClass().getName()+": "+e.getMessage());
  636           }
  637   
  638   
  639           WebSession session = null;
  640           try {
  641               session = home.create();
  642           } catch (RemoteException e) {
  643               // TODO Auto-generated catch block
  644               e.printStackTrace();
  645           }
  646           // mark them as nocopy
  647           Object obj = org.apache.openejb.util.proxy.ProxyManager.getInvocationHandler(session);
  648           StatefulEjbObjectHandler handler = (StatefulEjbObjectHandler) obj;
  649           handler.setIntraVmCopyMode(false);
  650           return session;
  651       }
  652   }

Home » openejb-3.1.2-src » org.apache » openejb » webadmin » httpd » [javadoc | source]