Save This Page
Home » openejb-3.1.2-src » org.apache » openejb » server » 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.server.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.EOFException;
   24   import java.io.IOException;
   25   import java.io.InputStream;
   26   import java.net.URI;
   27   import java.net.URISyntaxException;
   28   import java.net.URLDecoder;
   29   import java.util.HashMap;
   30   import java.util.Map;
   31   import java.util.StringTokenizer;
   32   
   33   /**
   34    * A class to take care of HTTP Requests.  It parses headers, content, form and url
   35    * parameters.
   36    */
   37   public class HttpRequestImpl implements HttpRequest {
   38       private static final String FORM_URL_ENCODED = "application/x-www-form-urlencoded";
   39       private static final String TRANSFER_ENCODING = "Transfer-Encoding";
   40       private static final String CHUNKED = "chunked";
   41       protected static final String EJBSESSIONID = "EJBSESSIONID";
   42   
   43       /**
   44        * 5.1.1    Method
   45        */
   46       private Method method;
   47   
   48       /**
   49        * 5.1.2    Request-URI
   50        */
   51       private URI uri;
   52   
   53       /**
   54        * the headers for this page
   55        */
   56       private final Map<String,String> headers = new HashMap<String,String>();
   57   
   58       /**
   59        * the form parameters for this page
   60        */
   61       private final Map<String,String> formParams = new HashMap<String,String>();
   62   
   63       /**
   64        * the URL (or query) parameters for this page
   65        */
   66       private final Map<String,String> queryParams = new HashMap<String,String>();
   67   
   68       /**
   69        * All form and query parameters.  Query parameters override form parameters.
   70        */
   71       private final Map<String,String> parameters = new HashMap<String,String>();
   72   
   73       /**
   74        * Cookies sent from the client
   75        */
   76       private Map<String,String> cookies;
   77   
   78       /**
   79        * the content of the body of the request
   80        */
   81       private byte[] body;
   82       private InputStream in;
   83       private int length;
   84       private String contentType;
   85   
   86       /**
   87        * the address the request came in on
   88        */
   89       private final URI socketURI;
   90   
   91       /**
   92        * Request scoped data which is set and used by application code.
   93        */
   94       private final Map<String,Object> attributes = new HashMap<String,Object>();
   95   
   96       public HttpRequestImpl(URI socketURI) {
   97           this.socketURI = socketURI;
   98       }
   99   
  100       /**
  101        * Gets a header based the header name passed in.
  102        *
  103        * @param name The name of the header to get
  104        * @return The value of the header
  105        */
  106       public String getHeader(String name) {
  107           return headers.get(name);
  108       }
  109   
  110       /**
  111        * Gets a form parameter based on the name passed in.
  112        *
  113        * @param name The name of the form parameter to get
  114        * @return The value of the parameter
  115        */
  116       public String getFormParameter(String name) {
  117           return formParams.get(name);
  118       }
  119   
  120       public Map<String,String> getFormParameters() {
  121           return new HashMap<String,String>(formParams);
  122       }
  123   
  124       public Map<String,String> getQueryParameters() {
  125           return new HashMap<String,String>(queryParams);
  126       }
  127   
  128       /**
  129        * Gets a URL (or query) parameter based on the name passed in.
  130        *
  131        * @param name The name of the URL (or query) parameter
  132        * @return The value of the URL (or query) parameter
  133        */
  134       public String getQueryParameter(String name) {
  135           return queryParams.get(name);
  136       }
  137   
  138       /**
  139        * Gets the request method.
  140        * @return the request method
  141        */
  142       public Method getMethod() {
  143           return method;
  144       }
  145   
  146       /**
  147        * Gets the URI for the current URL page.
  148        *
  149        * @return the URI
  150        */
  151       public URI getURI() {
  152           return uri;
  153       }
  154   
  155       public int getContentLength() {
  156           return length;
  157       }
  158   
  159       public String getContentType() {
  160           return contentType;
  161       }
  162   
  163       public InputStream getInputStream() throws IOException {
  164           return this.in;
  165       }
  166   
  167       /*------------------------------------------------------------*/
  168       /*  Methods for reading in and parsing a request              */
  169       /*------------------------------------------------------------*/
  170       /**
  171        * parses the request into the 3 different parts, request, headers, and body
  172        *
  173        * @param input the data input for this page
  174        * @throws java.io.IOException if an exception is thrown
  175        */
  176       protected void readMessage(InputStream input) throws IOException {
  177           DataInput in = new DataInputStream(input);
  178   
  179           readRequestLine(in);
  180           readHeaders(in);
  181           readBody(in);
  182   
  183           parameters.putAll(this.getFormParameters());
  184           parameters.putAll(this.getQueryParameters());
  185   
  186           //temp-debug-------------------------------------------
  187           // System.out.println("******************* HEADERS ******************");
  188           // for (Map.Entry<String, String> entry : headers.entrySet()) {
  189           //    System.out.println(entry);
  190           // }
  191           // System.out.println("**********************************************");
  192           // System.out.println(new String(body));
  193           // System.out.println("**********************************************");
  194           //end temp-debug---------------------------------------
  195       }
  196   
  197       /**
  198        * reads and parses the request line
  199        *
  200        * @param in the input to be read
  201        * @throws java.io.IOException if an exception is thrown
  202        */
  203       private void readRequestLine(DataInput in) throws IOException {
  204           String line;
  205           try {
  206               line = in.readLine();
  207   //            System.out.println(line);
  208           } catch (Exception e) {
  209               throw new IOException("Could not read the HTTP Request Line :"
  210                       + e.getClass().getName()
  211                       + " : "
  212                       + e.getMessage());
  213           }
  214   
  215           StringTokenizer lineParts = new StringTokenizer(line, " ");
  216           /* [1] Parse the method */
  217           parseMethod(lineParts);
  218           /* [2] Parse the URI */
  219           parseURI(lineParts);
  220       }
  221   
  222       /**
  223        * parses the method for this page
  224        *
  225        * @param lineParts a StringTokenizer of the request line
  226        * @throws java.io.IOException if an exeption is thrown
  227        */
  228       private void parseMethod(StringTokenizer lineParts) throws IOException {
  229           String token;
  230           try {
  231               token = lineParts.nextToken();
  232           } catch (Exception e) {
  233               throw new IOException("Could not parse the HTTP Request Method :"
  234                       + e.getClass().getName()
  235                       + " : "
  236                       + e.getMessage());
  237           }
  238   
  239           if (token.equalsIgnoreCase("GET")) {
  240               method = Method.GET;
  241           } else if (token.equalsIgnoreCase("POST")) {
  242               method = Method.POST;
  243           } else {
  244               method = Method.UNSUPPORTED;
  245               throw new IOException("Unsupported HTTP Request Method :" + token);
  246           }
  247       }
  248   
  249       /**
  250        * parses the URI into the different parts
  251        *
  252        * @param lineParts a StringTokenizer of the URI
  253        * @throws java.io.IOException if an exeption is thrown
  254        */
  255       private void parseURI(StringTokenizer lineParts) throws IOException {
  256           String token;
  257           try {
  258               token = lineParts.nextToken();
  259           } catch (Exception e) {
  260               throw new IOException("Could not parse the HTTP Request Method :"
  261                       + e.getClass().getName()
  262                       + " : "
  263                       + e.getMessage());
  264           }
  265   
  266           try {
  267               uri = new URI(socketURI.toString()+token);
  268           } catch (URISyntaxException e) {
  269               throw new IOException("Malformed URI :" + token + " Exception: " + e.getMessage());
  270           }
  271   
  272           parseQueryParams(uri.getQuery());
  273       }
  274   
  275       /**
  276        * parses the URL (or query) parameters
  277        *
  278        * @param query the URL (or query) parameters to be parsed
  279        */
  280       private void parseQueryParams(String query) {
  281           if (query == null)
  282               return;
  283           StringTokenizer parameters = new StringTokenizer(query, "&");
  284   
  285           while (parameters.hasMoreTokens()) {
  286               StringTokenizer param = new StringTokenizer(parameters.nextToken(), "=");
  287   
  288               /* [1] Parse the Name */
  289               if (!param.hasMoreTokens())
  290                   continue;
  291               String name = URLDecoder.decode(param.nextToken());
  292               if (name == null)
  293                   continue;
  294   
  295               String value;
  296               /* [2] Parse the Value */
  297               if (!param.hasMoreTokens()){
  298                   value = "";
  299               } else {
  300                   value = URLDecoder.decode(param.nextToken());
  301               }
  302   
  303               //System.out.println("[] "+name+" = "+value);
  304               queryParams.put(name, value);
  305           }
  306       }
  307   
  308       /**
  309        * reads the headers from the data input sent from the browser
  310        *
  311        * @param in the data input sent from the browser
  312        * @throws java.io.IOException if an exeption is thrown
  313        */
  314       private void readHeaders(DataInput in) throws IOException {
  315   //        System.out.println("\nREQUEST");
  316           while (true) {
  317               // Header Field
  318               String hf;
  319   
  320               try {
  321                   hf = in.readLine();
  322                   //System.out.println(hf);
  323               } catch (Exception e) {
  324                   throw new IOException("Could not read the HTTP Request Header Field :"
  325                           + e.getClass().getName()
  326                           + " : "
  327                           + e.getMessage());
  328               }
  329   
  330               if (hf == null || hf.equals("")) {
  331                   break;
  332               }
  333   
  334               /* [1] parse the name */
  335               int colonIndex = hf.indexOf((int) ':');
  336               String name = hf.substring(0, colonIndex);
  337               if (name == null)
  338                   break;
  339   
  340               /* [2] Parse the Value */
  341               String value = hf.substring(colonIndex + 1, hf.length());
  342               if (value == null)
  343                   break;
  344               value = value.trim();
  345               headers.put(name, value);
  346           }
  347           
  348           // Update the URI to be what the client sees the the server as.
  349           String host = headers.get("Host");
  350           if( host!=null ) {
  351               String hostName;
  352               int port = uri.getPort();
  353               int idx = host.indexOf(":");
  354               if( idx >= 0 ) {
  355                   hostName = host.substring(0, idx);
  356                   try {
  357                       port = Integer.parseInt(host.substring(idx+1));
  358                   }
  359                   catch (NumberFormatException ignore) {
  360                   }
  361               } else {
  362                   hostName = host;
  363               }
  364               
  365               try {
  366                   uri = new URI(uri.getScheme(),
  367                           uri.getUserInfo(), hostName, port,
  368                           uri.getPath(), uri.getQuery(),
  369                           uri.getFragment());                
  370               } catch (URISyntaxException ignore) {
  371               }            
  372           }
  373           
  374           //temp-debug-------------------------------------------
  375           //java.util.Iterator myKeys = headers.keySet().iterator();
  376           //String temp = null;
  377           //while(myKeys.hasNext()) {
  378           //    temp = (String)myKeys.next();
  379           //    System.out.println("Test: " + temp + "=" + headers.get(temp));
  380           //}
  381           //end temp-debug---------------------------------------
  382       }
  383   
  384       /**
  385        * reads the body from the data input passed in
  386        *
  387        * @param in the data input with the body of the page
  388        * @throws java.io.IOException if an exception is thrown
  389        */
  390       private void readBody(DataInput in) throws IOException {
  391           //System.out.println("Body Length: " + body.length);
  392           // Content-type: application/x-www-form-urlencoded
  393           // or multipart/form-data
  394           length = parseContentLength();
  395   
  396           contentType = getHeader(HttpRequest.HEADER_CONTENT_TYPE);
  397   
  398           if (method == Method.POST && FORM_URL_ENCODED.equals(contentType)) {
  399               String rawParams;
  400   
  401               try {
  402                   body = readContent(in);
  403                   rawParams = new String(body);
  404               } catch (Exception e) {
  405                   throw (IOException)new IOException("Could not read the HTTP Request Body: " + e.getMessage()).initCause(e);
  406               }
  407   
  408               StringTokenizer parameters = new StringTokenizer(rawParams, "&");
  409               String name;
  410               String value;
  411   
  412               while (parameters.hasMoreTokens()) {
  413                   StringTokenizer param = new StringTokenizer(parameters.nextToken(), "=");
  414   
  415                   /* [1] Parse the Name */
  416                   name = URLDecoder.decode(param.nextToken());
  417                   if (name == null)
  418                       break;
  419   
  420                   /* [2] Parse the Value */
  421                   if (param.hasMoreTokens()) {
  422                       value = URLDecoder.decode(param.nextToken());
  423                   } else {
  424                       value = ""; //if there is no token set value to blank string
  425                   }
  426   
  427                   if (value == null)
  428                       value = "";
  429   
  430                   formParams.put(name, value);
  431                       //System.out.println(name + ": " + value);
  432               }
  433           } else if (method == Method.POST && CHUNKED.equals(headers.get(TRANSFER_ENCODING))) {
  434               try {
  435                   ByteArrayOutputStream out = new ByteArrayOutputStream(4096);
  436                   for (String line = in.readLine(); line != null; line = in.readLine()) {
  437                       // read the size line which is in hex
  438                       String sizeString = line.split(";", 2)[0];
  439                       int size = Integer.parseInt(sizeString, 16);
  440   
  441                       // if size is 0 we are done
  442                       if (size == 0) break;
  443   
  444                       // read the chunk and append to byte array
  445                       byte[] chunk = new byte[size];
  446                       in.readFully(chunk);
  447                       out.write(chunk);
  448   
  449                       // read off the trailing new line characters after the chunk
  450                       in.readLine();
  451                   }
  452                   body = out.toByteArray();
  453                   this.in = new ByteArrayInputStream(body);
  454               } catch (Exception e) {
  455                   throw (IOException)new IOException("Unable to read chunked body").initCause(e);
  456               }
  457           } else if (method == Method.POST){
  458               // TODO This really is terrible
  459               body = readContent(in);
  460               this.in = new ByteArrayInputStream(body);
  461           } else {
  462               body = new byte[0];
  463               this.in = new ByteArrayInputStream(body);
  464           }
  465   
  466       }
  467   
  468       private byte[] readContent(DataInput in) throws IOException {
  469           if (length >= 0) {
  470               byte[] body = new byte[length];
  471               in.readFully(body);
  472               return body;
  473           } else {
  474               ByteArrayOutputStream out = new ByteArrayOutputStream(4096);
  475               try {
  476                   boolean atLineStart = true;
  477                   while (true) {
  478                       byte b = in.readByte();
  479   
  480                       if (b == '\r') {
  481                           // read the next byte
  482                           out.write(b);
  483                           b = in.readByte();
  484                       }
  485   
  486                       if (b == '\n') {
  487                           if (atLineStart) {
  488                               // blank line signals end of data
  489                               break;
  490                           }
  491                           atLineStart = true;
  492                       } else {
  493                           atLineStart = false;
  494                       }
  495                       out.write(b);
  496                   }
  497               } catch (EOFException e) {
  498                   // done reading
  499               }
  500               byte[] body = out.toByteArray();
  501               return body;
  502           }
  503       }
  504   
  505       private int parseContentLength() {
  506           // Content-length: 384
  507           String len = getHeader(HttpRequest.HEADER_CONTENT_LENGTH);
  508           //System.out.println("readRequestBody Content-Length: " + len);
  509   
  510           int length = -1;
  511           if (len != null) {
  512               try {
  513                   length = Integer.parseInt(len);
  514               } catch (Exception e) {
  515                   //don't care
  516               }
  517           }
  518           return length;
  519       }
  520   
  521       protected Map getCookies() {
  522           if (cookies != null) return cookies;
  523   
  524           cookies = new HashMap<String,String>();
  525   
  526           String cookieHeader = getHeader(HEADER_COOKIE);
  527           if (cookieHeader == null) return cookies;
  528   
  529           StringTokenizer tokens = new StringTokenizer(cookieHeader, ";");
  530           while (tokens.hasMoreTokens()) {
  531               StringTokenizer token = new StringTokenizer(tokens.nextToken(), "=");
  532               String name = token.nextToken();
  533               String value = token.nextToken();
  534               cookies.put(name, value);
  535           }
  536           return cookies;
  537       }
  538   
  539       protected String getCookie(String name) {
  540           return (String) getCookies().get(name);
  541       }
  542   
  543       public HttpSession getSession(boolean create) {
  544           return null;
  545       }
  546   
  547       public HttpSession getSession() {
  548           return getSession(true);
  549       }
  550       
  551       public Object getAttribute(String name) {
  552           return attributes.get(name);
  553       }
  554   
  555       public void setAttribute(String name, Object value){
  556           attributes.put(name, value);
  557       }
  558   
  559       public String getParameter(String name) {
  560           return parameters.get(name);
  561       }
  562   
  563       public Map<String,String> getParameters() {
  564           return new HashMap<String,String>(parameters);
  565       }
  566   
  567       public String getRemoteAddr() {
  568           // todo how do we get this value?
  569           return null;
  570       }
  571   }

Save This Page
Home » openejb-3.1.2-src » org.apache » openejb » server » httpd » [javadoc | source]