Home | History | Annotate | Download | only in server
      1 /*
      2  * Copyright (c) 2004, 2011, Oracle and/or its affiliates. All rights reserved.
      3  *
      4  * Redistribution and use in source and binary forms, with or without
      5  * modification, are permitted provided that the following conditions
      6  * are met:
      7  *
      8  *   - Redistributions of source code must retain the above copyright
      9  *     notice, this list of conditions and the following disclaimer.
     10  *
     11  *   - Redistributions in binary form must reproduce the above copyright
     12  *     notice, this list of conditions and the following disclaimer in the
     13  *     documentation and/or other materials provided with the distribution.
     14  *
     15  *   - Neither the name of Oracle nor the names of its
     16  *     contributors may be used to endorse or promote products derived
     17  *     from this software without specific prior written permission.
     18  *
     19  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
     20  * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
     21  * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     22  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR
     23  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
     24  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
     25  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
     26  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
     27  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
     28  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
     29  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     30  */
     31 
     32 /*
     33  * This source code is provided to illustrate the usage of a given feature
     34  * or technique and has been deliberately simplified. Additional steps
     35  * required for a production-quality application, such as security checks,
     36  * input validation and proper error handling, might not be present in
     37  * this sample code.
     38  */
     39 
     40 
     41 import java.net.*;
     42 import java.nio.*;
     43 import java.nio.charset.*;
     44 import java.util.regex.*;
     45 
     46 /**
     47  * An encapsulation of the request received.
     48  * <P>
     49  * The static method parse() is responsible for creating this
     50  * object.
     51  *
     52  * @author Mark Reinhold
     53  * @author Brad R. Wetmore
     54  */
     55 class Request {
     56 
     57     /**
     58      * A helper class for parsing HTTP command actions.
     59      */
     60     static class Action {
     61 
     62         private String name;
     63         private Action(String name) { this.name = name; }
     64         public String toString() { return name; }
     65 
     66         static Action GET = new Action("GET");
     67         static Action PUT = new Action("PUT");
     68         static Action POST = new Action("POST");
     69         static Action HEAD = new Action("HEAD");
     70 
     71         static Action parse(String s) {
     72             if (s.equals("GET"))
     73                 return GET;
     74             if (s.equals("PUT"))
     75                 return PUT;
     76             if (s.equals("POST"))
     77                 return POST;
     78             if (s.equals("HEAD"))
     79                 return HEAD;
     80             throw new IllegalArgumentException(s);
     81         }
     82     }
     83 
     84     private Action action;
     85     private String version;
     86     private URI uri;
     87 
     88     Action action() { return action; }
     89     String version() { return version; }
     90     URI uri() { return uri; }
     91 
     92     private Request(Action a, String v, URI u) {
     93         action = a;
     94         version = v;
     95         uri = u;
     96     }
     97 
     98     public String toString() {
     99         return (action + " " + version + " " + uri);
    100     }
    101 
    102     static boolean isComplete(ByteBuffer bb) {
    103         int p = bb.position() - 4;
    104         if (p < 0)
    105             return false;
    106         return (((bb.get(p + 0) == '\r') &&
    107                  (bb.get(p + 1) == '\n') &&
    108                  (bb.get(p + 2) == '\r') &&
    109                  (bb.get(p + 3) == '\n')));
    110     }
    111 
    112     private static Charset ascii = Charset.forName("US-ASCII");
    113 
    114     /*
    115      * The expected message format is first compiled into a pattern,
    116      * and is then compared against the inbound character buffer to
    117      * determine if there is a match.  This convienently tokenizes
    118      * our request into usable pieces.
    119      *
    120      * This uses Matcher "expression capture groups" to tokenize
    121      * requests like:
    122      *
    123      *     GET /dir/file HTTP/1.1
    124      *     Host: hostname
    125      *
    126      * into:
    127      *
    128      *     group[1] = "GET"
    129      *     group[2] = "/dir/file"
    130      *     group[3] = "1.1"
    131      *     group[4] = "hostname"
    132      *
    133      * The text in between the parens are used to captured the regexp text.
    134      */
    135     private static Pattern requestPattern
    136         = Pattern.compile("\\A([A-Z]+) +([^ ]+) +HTTP/([0-9\\.]+)$"
    137                           + ".*^Host: ([^ ]+)$.*\r\n\r\n\\z",
    138                           Pattern.MULTILINE | Pattern.DOTALL);
    139 
    140     static Request parse(ByteBuffer bb) throws MalformedRequestException {
    141 
    142         CharBuffer cb = ascii.decode(bb);
    143         Matcher m = requestPattern.matcher(cb);
    144         if (!m.matches())
    145             throw new MalformedRequestException();
    146         Action a;
    147         try {
    148             a = Action.parse(m.group(1));
    149         } catch (IllegalArgumentException x) {
    150             throw new MalformedRequestException();
    151         }
    152         URI u;
    153         try {
    154             u = new URI("http://"
    155                         + m.group(4)
    156                         + m.group(2));
    157         } catch (URISyntaxException x) {
    158             throw new MalformedRequestException();
    159         }
    160         return new Request(a, m.group(3), u);
    161     }
    162 }
    163