Source code: org/apache/ajp/tomcat4/Ajp13Request.java
1 /*
2 * Copyright 1999-2004 The Apache Software Foundation
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 package org.apache.ajp.tomcat4;
18
19 import java.io.IOException;
20 import java.io.UnsupportedEncodingException;
21 import java.util.ArrayList;
22 import java.util.Iterator;
23 import java.util.Locale;
24 import java.util.TreeMap;
25
26 import javax.servlet.ServletInputStream;
27 import javax.servlet.http.Cookie;
28 import javax.servlet.http.HttpServletRequest;
29
30 import org.apache.catalina.Globals;
31 import org.apache.catalina.connector.HttpRequestBase;
32 import org.apache.catalina.util.StringParser;
33 import org.apache.tomcat.util.buf.MessageBytes;
34 import org.apache.tomcat.util.http.BaseRequest;
35 import org.apache.tomcat.util.http.Cookies;
36 import org.apache.tomcat.util.http.MimeHeaders;
37 import org.apache.tomcat.util.http.ServerCookie;
38
39 public class Ajp13Request extends HttpRequestBase {
40
41 private static final String match =
42 ";" + Globals.SESSION_PARAMETER_NAME + "=";
43
44 private static int id = 1;
45
46 private Ajp13Logger logger = new Ajp13Logger();
47 private int debug;
48
49 public Ajp13Request(Ajp13Connector connector) {
50 super();
51 this.debug = connector.getDebug();
52 this.logger.setConnector(connector);
53 this.logger.setName("Ajp13Request[" + (id++) + "]");
54 }
55
56 public void recycle() {
57 super.recycle();
58 }
59
60 void setAjpRequest(BaseRequest ajp) throws UnsupportedEncodingException {
61 // XXX make this guy wrap AjpRequest so
62 // we're more efficient (that's the whole point of
63 // all of the MessageBytes in AjpRequest)
64
65 setMethod(ajp.method().toString());
66 setProtocol(ajp.protocol().toString());
67 setRequestURI(ajp.requestURI().toString());
68 setRemoteAddr(ajp.remoteAddr().toString());
69 setRemoteHost(ajp.remoteHost().toString());
70 setServerName(ajp.serverName().toString());
71 setServerPort(ajp.getServerPort());
72
73 if ((!(((Ajp13Connector) connector).getTomcatAuthentication()))
74 && (ajp.remoteUser() != null)) {
75 setUserPrincipal(new Ajp13Principal(ajp.remoteUser().toString()));
76 } else {
77 setUserPrincipal(null);
78 }
79
80 setAuthType(ajp.authType().toString());
81 setAuthorization(ajp.authorization().toString());
82 setQueryString(ajp.queryString().toString());
83 setScheme(ajp.getScheme());
84 setSecure(ajp.getSecure());
85 setContentLength(ajp.getContentLength());
86
87 String contentType = ajp.contentType().toString();
88 if (contentType != null) {
89 setContentType(contentType);
90 }
91
92 MimeHeaders mheaders = ajp.headers();
93 int nheaders = mheaders.size();
94 for (int i = 0; i < nheaders; ++i) {
95 MessageBytes name = mheaders.getName(i);
96 MessageBytes value = mheaders.getValue(i);
97 addHeader(name.toString(), value.toString());
98 if ("accept-language".equals(name.toString()))
99 parseLocalesHeader(value.toString());
100 }
101
102 Iterator itr = ajp.getAttributeNames();
103 while (itr.hasNext()) {
104 String name = (String)itr.next();
105 setAttribute(name, ajp.getAttribute(name));
106 }
107
108 addCookies(ajp.cookies());
109 }
110
111 // public Object getAttribute(String name) {
112 // return ajp.getAttribute(name);
113 // }
114
115 // public Enumeration getAttributeNames() {
116 // return new Enumerator(ajp.getAttributeNames());
117 // }
118
119 public void setRequestURI(String uri) {
120 int semicolon = uri.indexOf(match);
121 if (semicolon >= 0) {
122 String rest = uri.substring(semicolon + match.length());
123 int semicolon2 = rest.indexOf(";");
124 if (semicolon2 >= 0) {
125 setRequestedSessionId(rest.substring(0, semicolon2));
126 rest = rest.substring(semicolon2);
127 } else {
128 setRequestedSessionId(rest);
129 rest = "";
130 }
131 setRequestedSessionURL(true);
132 uri = uri.substring(0, semicolon) + rest;
133 if (debug >= 1)
134 logger.log(" Requested URL session id is " +
135 ((HttpServletRequest) getRequest())
136 .getRequestedSessionId());
137 } else {
138 setRequestedSessionId(null);
139 setRequestedSessionURL(false);
140 }
141
142 super.setRequestURI(uri);
143 }
144
145 private void addCookies(Cookies cookies) {
146 int ncookies = cookies.getCookieCount();
147 for (int j = 0; j < ncookies; j++) {
148 ServerCookie scookie = cookies.getCookie(j);
149 Cookie cookie = new Cookie(scookie.getName().toString(),
150 scookie.getValue().toString());
151 if (cookie.getName().equals(Globals.SESSION_COOKIE_NAME)) {
152 // Override anything requested in the URL
153 if (!isRequestedSessionIdFromCookie()) {
154 // Accept only the first session id cookie
155 setRequestedSessionId(cookie.getValue());
156 setRequestedSessionCookie(true);
157 setRequestedSessionURL(false);
158 if (debug > 0) {
159 logger.log(" Requested cookie session id is " +
160 ((HttpServletRequest) getRequest())
161 .getRequestedSessionId());
162 }
163 }
164 }
165 if (debug > 0) {
166 logger.log(" Adding cookie " + cookie.getName() + "=" +
167 cookie.getValue());
168 }
169 addCookie(cookie);
170 }
171 }
172
173 public ServletInputStream createInputStream() throws IOException {
174 return (ServletInputStream)getStream();
175 }
176
177
178 /**
179 * Parse accept-language header value.
180 */
181 protected void parseLocalesHeader(String value) {
182
183 // Store the accumulated languages that have been requested in
184 // a local collection, sorted by the quality value (so we can
185 // add Locales in descending order). The values will be ArrayLists
186 // containing the corresponding Locales to be added
187 TreeMap locales = new TreeMap();
188
189 // Preprocess the value to remove all whitespace
190 int white = value.indexOf(' ');
191 if (white < 0)
192 white = value.indexOf('\t');
193 if (white >= 0) {
194 StringBuffer sb = new StringBuffer();
195 int len = value.length();
196 for (int i = 0; i < len; i++) {
197 char ch = value.charAt(i);
198 if ((ch != ' ') && (ch != '\t'))
199 sb.append(ch);
200 }
201 value = sb.toString();
202 }
203
204 // Process each comma-delimited language specification
205 StringParser parser = new StringParser();
206 parser.setString(value);
207 int length = parser.getLength();
208 while (true) {
209
210 // Extract the next comma-delimited entry
211 int start = parser.getIndex();
212 if (start >= length)
213 break;
214 int end = parser.findChar(',');
215 String entry = parser.extract(start, end).trim();
216 parser.advance(); // For the following entry
217
218 // Extract the quality factor for this entry
219 double quality = 1.0;
220 int semi = entry.indexOf(";q=");
221 if (semi >= 0) {
222 try {
223 quality = Double.parseDouble(entry.substring(semi + 3));
224 } catch (NumberFormatException e) {
225 quality = 0.0;
226 }
227 entry = entry.substring(0, semi);
228 }
229
230 // Skip entries we are not going to keep track of
231 if (quality < 0.00005)
232 continue; // Zero (or effectively zero) quality factors
233 if ("*".equals(entry))
234 continue; // FIXME - "*" entries are not handled
235
236 // Extract the language and country for this entry
237 String language = null;
238 String country = null;
239 String variant = null;
240 int dash = entry.indexOf('-');
241 if (dash < 0) {
242 language = entry;
243 country = "";
244 variant = "";
245 } else {
246 language = entry.substring(0, dash);
247 country = entry.substring(dash + 1);
248 int vDash = country.indexOf('-');
249 if (vDash > 0) {
250 String cTemp = country.substring(0, vDash);
251 variant = country.substring(vDash + 1);
252 country = cTemp;
253 } else {
254 variant = "";
255 }
256 }
257
258 // Add a new Locale to the list of Locales for this quality level
259 Locale locale = new Locale(language, country, variant);
260 Double key = new Double(-quality); // Reverse the order
261 ArrayList values = (ArrayList) locales.get(key);
262 if (values == null) {
263 values = new ArrayList();
264 locales.put(key, values);
265 }
266 values.add(locale);
267
268 }
269
270 // Process the quality values in highest->lowest order (due to
271 // negating the Double value when creating the key)
272 Iterator keys = locales.keySet().iterator();
273 while (keys.hasNext()) {
274 Double key = (Double) keys.next();
275 ArrayList list = (ArrayList) locales.get(key);
276 Iterator values = list.iterator();
277 while (values.hasNext()) {
278 Locale locale = (Locale) values.next();
279 addLocale(locale);
280 }
281 }
282
283 }
284 }
285
286 class Ajp13Principal implements java.security.Principal {
287 String user;
288
289 Ajp13Principal(String user) {
290 this.user = user;
291 }
292 public boolean equals(Object o) {
293 if (o == null) {
294 return false;
295 } else if (!(o instanceof Ajp13Principal)) {
296 return false;
297 } else if (o == this) {
298 return true;
299 } else if (this.user == null && ((Ajp13Principal)o).user == null) {
300 return true;
301 } else if (user != null) {
302 return user.equals( ((Ajp13Principal)o).user);
303 } else {
304 return false;
305 }
306 }
307
308 public String getName() {
309 return user;
310 }
311
312 public int hashCode() {
313 if (user == null) return 0;
314 else return user.hashCode();
315 }
316
317 public String toString() {
318 return getName();
319 }
320 }