001: /*
002: * <copyright>
003: *
004: * Copyright 1997-2007 BBNT Solutions, LLC
005: * under sponsorship of the Defense Advanced Research Projects
006: * Agency (DARPA).
007: *
008: * You can redistribute this software and/or modify it under the
009: * terms of the Cougaar Open Source License as published on the
010: * Cougaar Open Source Website (www.cougaar.org).
011: *
012: * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
013: * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
014: * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
015: * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
016: * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
017: * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
018: * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
019: * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
020: * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
021: * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
022: * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
023: *
024: * </copyright>
025: */
026:
027: package org.cougaar.lib.web.micro.base;
028:
029: import java.io.BufferedReader;
030: import java.io.ByteArrayInputStream;
031: import java.io.InputStream;
032: import java.io.InputStreamReader;
033: import java.io.IOException;
034: import java.io.UnsupportedEncodingException;
035: import java.security.Principal;
036: import java.text.DateFormat;
037: import java.text.ParseException;
038: import java.text.SimpleDateFormat;
039: import java.util.ArrayList;
040: import java.util.Collections;
041: import java.util.Date;
042: import java.util.Enumeration;
043: import java.util.HashMap;
044: import java.util.List;
045: import java.util.Locale;
046: import java.util.Map;
047: import javax.servlet.RequestDispatcher;
048: import javax.servlet.ServletInputStream;
049: import javax.servlet.http.Cookie;
050: import javax.servlet.http.HttpServletRequest;
051: import javax.servlet.http.HttpSession;
052:
053: /**
054: * An implementation of the http-servlet-request interface.
055: * <p>
056: * Note that some methods are not currently supported, e.g. sessions and
057: * cookies.
058: */
059: public class HttpServletRequestImpl implements HttpServletRequest {
060:
061: // from Tomcat HttpRequestBase:
062: private static final String[] DATE_FORMATS = {
063: "EEE, dd MMM yyyy HH:mm:ss zzz",
064: "EEEEEE, dd-MMM-yy HH:mm:ss zzz",
065: "EEE MMMM d HH:mm:ss yyyy", };
066:
067: private final RequestCallback callback;
068:
069: private final String contextPath;
070:
071: private final String clientAddr;
072: private final String clientHost;
073:
074: private String scheme;
075: private String serverHost;
076: private int serverPort;
077: private String servletPath;
078:
079: private String method;
080: private String requestURI;
081: private String pathInfo;
082: private String queryString;
083: private Map parameters = new HashMap();
084:
085: private String protocol;
086:
087: private Map headers = new HashMap();
088:
089: private ServletInputStream inputStream;
090: private boolean made_reader = false;
091:
092: public HttpServletRequestImpl(RequestCallback callback, Map metaData) {
093: this .callback = callback;
094:
095: // save metaData
096: this .contextPath = _get(metaData, "contextPath");
097: this .clientAddr = _get(metaData, "clientAddr");
098: this .clientHost = _get(metaData, "clientHost");
099: parseServerURL(_get(metaData, "serverURL"));
100:
101: // read data
102: parseRequest();
103: parseHeaders();
104: parseInputStream();
105: }
106:
107: private static String _get(Map m, String key) {
108: return (m == null ? null : (String) m.get(key));
109: }
110:
111: // parse server base url, e.g.:
112: // http://bar.com:80/foo
113: private void parseServerURL(String s) {
114: try {
115: String serverURL = s.trim();
116: int scheme_sep = serverURL.indexOf("://");
117: if (scheme_sep <= 0) {
118: throw new IllegalArgumentException("Missing scheme");
119: }
120: scheme = serverURL.substring(0, scheme_sep);
121: int name_start = scheme_sep + 3;
122: int port_sep = serverURL.indexOf(':', name_start);
123: int path_sep = serverURL.indexOf('/', name_start);
124: if (path_sep < 0) {
125: path_sep = serverURL.length();
126: }
127: if (port_sep > 0 && port_sep < path_sep) {
128: serverHost = serverURL.substring(name_start, port_sep);
129: serverPort = Integer.parseInt(serverURL.substring(
130: port_sep + 1, path_sep));
131: } else {
132: serverHost = serverURL.substring(name_start, path_sep);
133: serverPort = (scheme.equals("http") ? 80 : scheme
134: .equals("https") ? 443 : -1);
135: }
136: if (serverHost.length() == 0) {
137: throw new IllegalArgumentException("Missing host");
138: }
139: if (serverPort <= 0) {
140: throw new IllegalArgumentException("Invalid port: "
141: + serverPort);
142: }
143: servletPath = (path_sep < serverURL.length() ? serverURL
144: .substring(path_sep) : "/");
145: if (servletPath.length() == 0
146: || servletPath.charAt(0) != '/') {
147: throw new IllegalArgumentException(
148: "Invalid servletPath: " + servletPath);
149: }
150: } catch (Exception e) {
151: throw new IllegalArgumentException("Invalid serverURL: "
152: + s);
153: }
154: }
155:
156: // parse request line, e.g.:
157: // GET /foo/test?x=y HTTP/1.0
158: private void parseRequest() {
159: String request;
160: try {
161: request = callback.readRequest();
162: } catch (IOException ioe) {
163: throw new RuntimeException("Unable to read request line");
164: }
165:
166: try {
167: int begin = request.indexOf(' ', 1);
168: int end = request.indexOf(' ', begin + 1);
169: method = request.substring(0, begin).trim();
170: String uri = request.substring(begin + 1, end).trim();
171: protocol = request.substring(end + 1).trim();
172:
173: // remove "http://blah:123/path" to be just "/path"
174: requestURI = uri;
175: int scheme_sep = uri.indexOf("://");
176: if (scheme_sep > 0) {
177: int slash_sep = uri.indexOf('/', scheme_sep + 1);
178: requestURI = (slash_sep > 0 ? uri.substring(slash_sep)
179: : "/");
180: }
181:
182: // remove excess "/"s in "///path" to be just "/path"
183: for (int len = requestURI.length(); len > 1
184: && requestURI.charAt(1) == '/'; len--) {
185: requestURI = requestURI.substring(1);
186: }
187:
188: // extract and parse query parameters
189: int query_sep = requestURI.indexOf('?');
190: if (query_sep > 0) {
191: queryString = requestURI.substring(query_sep + 1);
192: requestURI = requestURI.substring(0, query_sep);
193: parseParameters(queryString);
194: }
195:
196: // set our "pathInfo" subpath relative to the base path
197: if (servletPath != null
198: && requestURI.startsWith(servletPath)
199: && requestURI.length() > servletPath.length()) {
200: pathInfo = requestURI.substring(servletPath.length());
201: }
202: } catch (Exception e) {
203: throw new IllegalArgumentException("Invalid request line: "
204: + request);
205: }
206: }
207:
208: // parse url/post parameters, e.g.:
209: // x=y&foo=bar
210: private void parseParameters(String s) {
211: String[] sa = s.split("&");
212: for (int i = 0; i < sa.length; i++) {
213: String sai = sa[i];
214: int eq_sep = sai.indexOf('=');
215: if (eq_sep <= 0)
216: continue;
217: String name = sai.substring(0, eq_sep);
218: String value = sai.substring(eq_sep + 1);
219: Object o = parameters.get(name);
220: if (o == null) {
221: parameters.put(name, value);
222: } else {
223: if (!(o instanceof List)) {
224: List l = new ArrayList();
225: l.add(o);
226: parameters.put(name, l);
227: o = l;
228: }
229: ((List) o).add(value);
230: }
231: }
232: }
233:
234: // parse headers, e.g.:
235: // bar: qux
236: // Content-Length: 1234
237: private void parseHeaders() {
238: List header_lines;
239: try {
240: header_lines = callback.readHeaders();
241: } catch (IOException e) {
242: throw new RuntimeException("Unable to read header lines");
243: }
244:
245: for (int i = 0; i < header_lines.size(); i++) {
246: String header = (String) header_lines.get(i);
247: if (header.length() == 0)
248: break;
249: int sep = header.indexOf(':');
250: if (sep < 0)
251: continue;
252: String name = header.substring(0, sep).trim();
253: String value = header.substring(sep + 1).trim();
254: Object o = headers.get(name);
255: if (o == null) {
256: headers.put(name, value);
257: } else {
258: if (!(o instanceof List)) {
259: List l = new ArrayList();
260: l.add(o);
261: headers.put(name, l);
262: o = l;
263: }
264: ((List) o).add(value);
265: }
266: }
267: }
268:
269: // parse post-data input stream
270: //
271: // We must fully read the stream before we create our response stream,
272: // That's why we create our "inputStream" here instead of waiting until
273: // "getInputStream()/getReader()" is called.
274: private void parseInputStream() {
275: int contentLength = getContentLength();
276: byte[] body;
277: try {
278: body = callback.readBody(contentLength);
279: } catch (IOException ioe) {
280: throw new RuntimeException("Unable to read body["
281: + contentLength + "]");
282: }
283:
284: if ("post".equalsIgnoreCase(method)) {
285: // read posted parameters, reset body to zero
286: parseParameters(new String(body));
287: body = new byte[0];
288: }
289:
290: final InputStream is = new ByteArrayInputStream(body);
291: inputStream = new ServletInputStream() {
292: public int read() throws IOException {
293: return is.read();
294: }
295:
296: public int read(byte b[], int off, int len)
297: throws IOException {
298: return is.read(b, off, len);
299: }
300:
301: public long skip(long n) throws IOException {
302: return is.skip(n);
303: }
304:
305: public int available() throws IOException {
306: return is.available();
307: }
308:
309: public boolean markSupported() {
310: return is.markSupported();
311: }
312:
313: public void mark(int readAheadLimit) {
314: is.mark(readAheadLimit);
315: }
316:
317: public void reset() throws IOException {
318: is.reset();
319: }
320:
321: public void close() throws IOException {
322: is.close();
323: }
324: };
325: }
326:
327: // server info
328: public String getContextPath() {
329: return contextPath;
330: }
331:
332: public String getServerName() {
333: return serverHost;
334: }
335:
336: public int getServerPort() {
337: return serverPort;
338: }
339:
340: // client info
341: public String getRemoteAddr() {
342: return clientAddr;
343: }
344:
345: public String getRemoteHost() {
346: return clientHost;
347: }
348:
349: // request info
350: public boolean isSecure() {
351: return "https".equals(getScheme());
352: }
353:
354: public String getScheme() {
355: return scheme;
356: }
357:
358: public String getMethod() {
359: return method;
360: }
361:
362: public String getPathInfo() {
363: return pathInfo;
364: }
365:
366: public String getServletPath() {
367: return servletPath;
368: }
369:
370: public String getQueryString() {
371: return queryString;
372: }
373:
374: public String getRequestURI() {
375: return requestURI;
376: }
377:
378: public String getProtocol() {
379: return protocol;
380: }
381:
382: public StringBuffer getRequestURL() {
383: StringBuffer ret = new StringBuffer();
384: ret.append(getScheme()).append("://").append(getServerName());
385: int port = getServerPort();
386: if (port < 0) {
387: port = 80;
388: }
389: if ((scheme.equals("http") && (port != 80))
390: || (scheme.equals("https") && (port != 443))) {
391: ret.append(":").append(port);
392: }
393: ret.append(getRequestURI());
394: return ret;
395: }
396:
397: public String getParameter(String name) {
398: Object o = parameters.get(name);
399: return (o == null ? null : o instanceof String ? (String) o
400: : (String) ((List) o).get(0));
401: }
402:
403: public String[] getParameterValues(String name) {
404: Object o = parameters.get(name);
405: return (o == null ? null
406: : o instanceof String ? new String[] { (String) o }
407: : (String[]) ((List) o)
408: .toArray(new String[((List) o).size()]));
409: }
410:
411: public Enumeration getParameterNames() {
412: return Collections.enumeration(parameters.keySet());
413: }
414:
415: public Map getParameterMap() {
416: Map ret = new HashMap();
417: for (Enumeration en = getParameterNames(); en.hasMoreElements();) {
418: String s = (String) en.nextElement();
419: ret.put(s, getParameterValues(s));
420: }
421: return ret;
422: }
423:
424: // header info
425: public String getHeader(String name) {
426: Object o = headers.get(name);
427: return (o == null ? null : o instanceof String ? (String) o
428: : (String) ((List) o).get(0));
429: }
430:
431: public Enumeration getHeaders(String name) {
432: Object o = headers.get(name);
433: List l = (o == null ? Collections.EMPTY_LIST
434: : o instanceof String ? Collections.singletonList(o)
435: : (List) o);
436: return Collections.enumeration(l);
437: }
438:
439: public Enumeration getHeaderNames() {
440: return Collections.enumeration(headers.keySet());
441: }
442:
443: public int getIntHeader(String name) {
444: String s = getHeader(name);
445: if (s == null)
446: return -1;
447: return Integer.parseInt(s);
448: }
449:
450: public int getContentLength() {
451: return getIntHeader("Content-Length");
452: }
453:
454: public String getContentType() {
455: return getHeader("Content-Type");
456: }
457:
458: public long getDateHeader(String name) {
459: String s = getHeader(name);
460: if (s == null)
461: return -1;
462: for (int i = 0; i < DATE_FORMATS.length; i++) {
463: DateFormat format = new SimpleDateFormat(DATE_FORMATS[i]);
464: try {
465: Date date = format.parse(s);
466: return date.getTime();
467: } catch (ParseException e) {
468: }
469: }
470: throw new IllegalArgumentException(s);
471: }
472:
473: // body info
474: public ServletInputStream getInputStream() throws IOException {
475: if (made_reader) {
476: throw new IllegalStateException("Already made reader");
477: }
478: made_reader = true;
479: return inputStream;
480: }
481:
482: public BufferedReader getReader() throws IOException {
483: return new BufferedReader(new InputStreamReader(
484: getInputStream()));
485: }
486:
487: // unsupported:
488: // HttpServletRequest:
489: public String getPathTranslated() {
490: die();
491: return null;
492: }
493:
494: public Cookie[] getCookies() {
495: die();
496: return null;
497: }
498:
499: public String getAuthType() {
500: die();
501: return null;
502: }
503:
504: public String getRemoteUser() {
505: die();
506: return null;
507: }
508:
509: public boolean isUserInRole(String role) {
510: die();
511: return false;
512: }
513:
514: public Principal getUserPrincipal() {
515: die();
516: return null;
517: }
518:
519: public String getRequestedSessionId() {
520: die();
521: return null;
522: }
523:
524: public HttpSession getSession(boolean create) {
525: die();
526: return null;
527: }
528:
529: public HttpSession getSession() {
530: die();
531: return null;
532: }
533:
534: public boolean isRequestedSessionIdValid() {
535: die();
536: return false;
537: }
538:
539: public boolean isRequestedSessionIdFromCookie() {
540: die();
541: return false;
542: }
543:
544: public boolean isRequestedSessionIdFromURL() {
545: die();
546: return false;
547: }
548:
549: public boolean isRequestedSessionIdFromUrl() {
550: die();
551: return false;
552: }
553:
554: // ServletRequest:
555: public String getCharacterEncoding() {
556: die();
557: return null;
558: }
559:
560: public void setCharacterEncoding(String env)
561: throws UnsupportedEncodingException {
562: die();
563: }
564:
565: public Object getAttribute(String name) {
566: die();
567: return null;
568: }
569:
570: public Enumeration getAttributeNames() {
571: die();
572: return null;
573: }
574:
575: public void setAttribute(String name, Object o) {
576: die();
577: }
578:
579: public void removeAttribute(String name) {
580: die();
581: }
582:
583: public Locale getLocale() {
584: die();
585: return null;
586: }
587:
588: public Enumeration getLocales() {
589: die();
590: return null;
591: }
592:
593: public RequestDispatcher getRequestDispatcher(String path) {
594: die();
595: return null;
596: }
597:
598: public String getRealPath(String path) {
599: die();
600: return null;
601: }
602:
603: private void die() {
604: throw new UnsupportedOperationException();
605: }
606: }
|