blob: f19772f9190e9adb922f1417de47af1ea2551e7d [file] [log] [blame]
J. Duke319a3b92007-12-01 00:00:00 +00001/*
2 * Copyright 2004 Sun Microsystems, Inc. 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 Sun Microsystems 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
32import java.net.*;
33import java.nio.*;
34import java.nio.charset.*;
35import java.util.regex.*;
36
37/**
38 * An encapsulation of the request received.
39 * <P>
40 * The static method parse() is responsible for creating this
41 * object.
42 *
43 * @author Mark Reinhold
44 * @author Brad R. Wetmore
45 */
46class Request {
47
48 /**
49 * A helper class for parsing HTTP command actions.
50 */
51 static class Action {
52
53 private String name;
54 private Action(String name) { this.name = name; }
55 public String toString() { return name; }
56
57 static Action GET = new Action("GET");
58 static Action PUT = new Action("PUT");
59 static Action POST = new Action("POST");
60 static Action HEAD = new Action("HEAD");
61
62 static Action parse(String s) {
63 if (s.equals("GET"))
64 return GET;
65 if (s.equals("PUT"))
66 return PUT;
67 if (s.equals("POST"))
68 return POST;
69 if (s.equals("HEAD"))
70 return HEAD;
71 throw new IllegalArgumentException(s);
72 }
73 }
74
75 private Action action;
76 private String version;
77 private URI uri;
78
79 Action action() { return action; }
80 String version() { return version; }
81 URI uri() { return uri; }
82
83 private Request(Action a, String v, URI u) {
84 action = a;
85 version = v;
86 uri = u;
87 }
88
89 public String toString() {
90 return (action + " " + version + " " + uri);
91 }
92
93 static boolean isComplete(ByteBuffer bb) {
94 int p = bb.position() - 4;
95 if (p < 0)
96 return false;
97 return (((bb.get(p + 0) == '\r') &&
98 (bb.get(p + 1) == '\n') &&
99 (bb.get(p + 2) == '\r') &&
100 (bb.get(p + 3) == '\n')));
101 }
102
103 private static Charset ascii = Charset.forName("US-ASCII");
104
105 /*
106 * The expected message format is first compiled into a pattern,
107 * and is then compared against the inbound character buffer to
108 * determine if there is a match. This convienently tokenizes
109 * our request into usable pieces.
110 *
111 * This uses Matcher "expression capture groups" to tokenize
112 * requests like:
113 *
114 * GET /dir/file HTTP/1.1
115 * Host: hostname
116 *
117 * into:
118 *
119 * group[1] = "GET"
120 * group[2] = "/dir/file"
121 * group[3] = "1.1"
122 * group[4] = "hostname"
123 *
124 * The text in between the parens are used to captured the regexp text.
125 */
126 private static Pattern requestPattern
127 = Pattern.compile("\\A([A-Z]+) +([^ ]+) +HTTP/([0-9\\.]+)$"
128 + ".*^Host: ([^ ]+)$.*\r\n\r\n\\z",
129 Pattern.MULTILINE | Pattern.DOTALL);
130
131 static Request parse(ByteBuffer bb) throws MalformedRequestException {
132
133 CharBuffer cb = ascii.decode(bb);
134 Matcher m = requestPattern.matcher(cb);
135 if (!m.matches())
136 throw new MalformedRequestException();
137 Action a;
138 try {
139 a = Action.parse(m.group(1));
140 } catch (IllegalArgumentException x) {
141 throw new MalformedRequestException();
142 }
143 URI u;
144 try {
145 u = new URI("http://"
146 + m.group(4)
147 + m.group(2));
148 } catch (URISyntaxException x) {
149 throw new MalformedRequestException();
150 }
151 return new Request(a, m.group(3), u);
152 }
153}