001: /*
002: * Copyright 1999-2004 The Apache Software Foundation
003: *
004: * Licensed under the Apache License, Version 2.0 (the "License");
005: * you may not use this file except in compliance with the License.
006: * You may obtain a copy of the License at
007: *
008: * http://www.apache.org/licenses/LICENSE-2.0
009: *
010: * Unless required by applicable law or agreed to in writing, software
011: * distributed under the License is distributed on an "AS IS" BASIS,
012: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013: * See the License for the specific language governing permissions and
014: * limitations under the License.
015: */
016:
017: package org.apache.ajp.tomcat4;
018:
019: import java.io.IOException;
020: import java.io.UnsupportedEncodingException;
021: import java.util.ArrayList;
022: import java.util.Iterator;
023: import java.util.Locale;
024: import java.util.TreeMap;
025:
026: import javax.servlet.ServletInputStream;
027: import javax.servlet.http.Cookie;
028: import javax.servlet.http.HttpServletRequest;
029:
030: import org.apache.catalina.Globals;
031: import org.apache.catalina.connector.HttpRequestBase;
032: import org.apache.catalina.util.StringParser;
033: import org.apache.tomcat.util.buf.MessageBytes;
034: import org.apache.tomcat.util.http.BaseRequest;
035: import org.apache.tomcat.util.http.Cookies;
036: import org.apache.tomcat.util.http.MimeHeaders;
037: import org.apache.tomcat.util.http.ServerCookie;
038:
039: public class Ajp13Request extends HttpRequestBase {
040:
041: private static final String match = ";"
042: + Globals.SESSION_PARAMETER_NAME + "=";
043:
044: private static int id = 1;
045:
046: private Ajp13Logger logger = new Ajp13Logger();
047: private int debug;
048:
049: public Ajp13Request(Ajp13Connector connector) {
050: super ();
051: this .debug = connector.getDebug();
052: this .logger.setConnector(connector);
053: this .logger.setName("Ajp13Request[" + (id++) + "]");
054: }
055:
056: public void recycle() {
057: super .recycle();
058: }
059:
060: void setAjpRequest(BaseRequest ajp)
061: throws UnsupportedEncodingException {
062: // XXX make this guy wrap AjpRequest so
063: // we're more efficient (that's the whole point of
064: // all of the MessageBytes in AjpRequest)
065:
066: setMethod(ajp.method().toString());
067: setProtocol(ajp.protocol().toString());
068: setRequestURI(ajp.requestURI().toString());
069: setRemoteAddr(ajp.remoteAddr().toString());
070: setRemoteHost(ajp.remoteHost().toString());
071: setServerName(ajp.serverName().toString());
072: setServerPort(ajp.getServerPort());
073:
074: if ((!(((Ajp13Connector) connector).getTomcatAuthentication()))
075: && (ajp.remoteUser() != null)) {
076: setUserPrincipal(new Ajp13Principal(ajp.remoteUser()
077: .toString()));
078: } else {
079: setUserPrincipal(null);
080: }
081:
082: setAuthType(ajp.authType().toString());
083: setAuthorization(ajp.authorization().toString());
084: setQueryString(ajp.queryString().toString());
085: setScheme(ajp.getScheme());
086: setSecure(ajp.getSecure());
087: setContentLength(ajp.getContentLength());
088:
089: String contentType = ajp.contentType().toString();
090: if (contentType != null) {
091: setContentType(contentType);
092: }
093:
094: MimeHeaders mheaders = ajp.headers();
095: int nheaders = mheaders.size();
096: for (int i = 0; i < nheaders; ++i) {
097: MessageBytes name = mheaders.getName(i);
098: MessageBytes value = mheaders.getValue(i);
099: addHeader(name.toString(), value.toString());
100: if ("accept-language".equals(name.toString()))
101: parseLocalesHeader(value.toString());
102: }
103:
104: Iterator itr = ajp.getAttributeNames();
105: while (itr.hasNext()) {
106: String name = (String) itr.next();
107: setAttribute(name, ajp.getAttribute(name));
108: }
109:
110: addCookies(ajp.cookies());
111: }
112:
113: // public Object getAttribute(String name) {
114: // return ajp.getAttribute(name);
115: // }
116:
117: // public Enumeration getAttributeNames() {
118: // return new Enumerator(ajp.getAttributeNames());
119: // }
120:
121: public void setRequestURI(String uri) {
122: int semicolon = uri.indexOf(match);
123: if (semicolon >= 0) {
124: String rest = uri.substring(semicolon + match.length());
125: int semicolon2 = rest.indexOf(";");
126: if (semicolon2 >= 0) {
127: setRequestedSessionId(rest.substring(0, semicolon2));
128: rest = rest.substring(semicolon2);
129: } else {
130: setRequestedSessionId(rest);
131: rest = "";
132: }
133: setRequestedSessionURL(true);
134: uri = uri.substring(0, semicolon) + rest;
135: if (debug >= 1)
136: logger.log(" Requested URL session id is "
137: + ((HttpServletRequest) getRequest())
138: .getRequestedSessionId());
139: } else {
140: setRequestedSessionId(null);
141: setRequestedSessionURL(false);
142: }
143:
144: super .setRequestURI(uri);
145: }
146:
147: private void addCookies(Cookies cookies) {
148: int ncookies = cookies.getCookieCount();
149: for (int j = 0; j < ncookies; j++) {
150: ServerCookie scookie = cookies.getCookie(j);
151: Cookie cookie = new Cookie(scookie.getName().toString(),
152: scookie.getValue().toString());
153: if (cookie.getName().equals(Globals.SESSION_COOKIE_NAME)) {
154: // Override anything requested in the URL
155: if (!isRequestedSessionIdFromCookie()) {
156: // Accept only the first session id cookie
157: setRequestedSessionId(cookie.getValue());
158: setRequestedSessionCookie(true);
159: setRequestedSessionURL(false);
160: if (debug > 0) {
161: logger.log(" Requested cookie session id is "
162: + ((HttpServletRequest) getRequest())
163: .getRequestedSessionId());
164: }
165: }
166: }
167: if (debug > 0) {
168: logger.log(" Adding cookie " + cookie.getName() + "="
169: + cookie.getValue());
170: }
171: addCookie(cookie);
172: }
173: }
174:
175: public ServletInputStream createInputStream() throws IOException {
176: return (ServletInputStream) getStream();
177: }
178:
179: /**
180: * Parse accept-language header value.
181: */
182: protected void parseLocalesHeader(String value) {
183:
184: // Store the accumulated languages that have been requested in
185: // a local collection, sorted by the quality value (so we can
186: // add Locales in descending order). The values will be ArrayLists
187: // containing the corresponding Locales to be added
188: TreeMap locales = new TreeMap();
189:
190: // Preprocess the value to remove all whitespace
191: int white = value.indexOf(' ');
192: if (white < 0)
193: white = value.indexOf('\t');
194: if (white >= 0) {
195: StringBuffer sb = new StringBuffer();
196: int len = value.length();
197: for (int i = 0; i < len; i++) {
198: char ch = value.charAt(i);
199: if ((ch != ' ') && (ch != '\t'))
200: sb.append(ch);
201: }
202: value = sb.toString();
203: }
204:
205: // Process each comma-delimited language specification
206: StringParser parser = new StringParser();
207: parser.setString(value);
208: int length = parser.getLength();
209: while (true) {
210:
211: // Extract the next comma-delimited entry
212: int start = parser.getIndex();
213: if (start >= length)
214: break;
215: int end = parser.findChar(',');
216: String entry = parser.extract(start, end).trim();
217: parser.advance(); // For the following entry
218:
219: // Extract the quality factor for this entry
220: double quality = 1.0;
221: int semi = entry.indexOf(";q=");
222: if (semi >= 0) {
223: try {
224: quality = Double.parseDouble(entry
225: .substring(semi + 3));
226: } catch (NumberFormatException e) {
227: quality = 0.0;
228: }
229: entry = entry.substring(0, semi);
230: }
231:
232: // Skip entries we are not going to keep track of
233: if (quality < 0.00005)
234: continue; // Zero (or effectively zero) quality factors
235: if ("*".equals(entry))
236: continue; // FIXME - "*" entries are not handled
237:
238: // Extract the language and country for this entry
239: String language = null;
240: String country = null;
241: String variant = null;
242: int dash = entry.indexOf('-');
243: if (dash < 0) {
244: language = entry;
245: country = "";
246: variant = "";
247: } else {
248: language = entry.substring(0, dash);
249: country = entry.substring(dash + 1);
250: int vDash = country.indexOf('-');
251: if (vDash > 0) {
252: String cTemp = country.substring(0, vDash);
253: variant = country.substring(vDash + 1);
254: country = cTemp;
255: } else {
256: variant = "";
257: }
258: }
259:
260: // Add a new Locale to the list of Locales for this quality level
261: Locale locale = new Locale(language, country, variant);
262: Double key = new Double(-quality); // Reverse the order
263: ArrayList values = (ArrayList) locales.get(key);
264: if (values == null) {
265: values = new ArrayList();
266: locales.put(key, values);
267: }
268: values.add(locale);
269:
270: }
271:
272: // Process the quality values in highest->lowest order (due to
273: // negating the Double value when creating the key)
274: Iterator keys = locales.keySet().iterator();
275: while (keys.hasNext()) {
276: Double key = (Double) keys.next();
277: ArrayList list = (ArrayList) locales.get(key);
278: Iterator values = list.iterator();
279: while (values.hasNext()) {
280: Locale locale = (Locale) values.next();
281: addLocale(locale);
282: }
283: }
284:
285: }
286: }
287:
288: class Ajp13Principal implements java.security.Principal {
289: String user;
290:
291: Ajp13Principal(String user) {
292: this .user = user;
293: }
294:
295: public boolean equals(Object o) {
296: if (o == null) {
297: return false;
298: } else if (!(o instanceof Ajp13Principal)) {
299: return false;
300: } else if (o == this ) {
301: return true;
302: } else if (this .user == null
303: && ((Ajp13Principal) o).user == null) {
304: return true;
305: } else if (user != null) {
306: return user.equals(((Ajp13Principal) o).user);
307: } else {
308: return false;
309: }
310: }
311:
312: public String getName() {
313: return user;
314: }
315:
316: public int hashCode() {
317: if (user == null)
318: return 0;
319: else
320: return user.hashCode();
321: }
322:
323: public String toString() {
324: return getName();
325: }
326: }
|