KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > quadcap > http > server22 > HttpRequest


1 package com.quadcap.http.server22;
2
3 /* Copyright 1997 - 2003 Quadcap Software. All rights reserved.
4  *
5  * This software is distributed under the Quadcap Free Software License.
6  * This software may be used or modified for any purpose, personal or
7  * commercial. Open Source redistributions are permitted. Commercial
8  * redistribution of larger works derived from, or works which bundle
9  * this software requires a "Commercial Redistribution License"; see
10  * http://www.quadcap.com/purchase.
11  *
12  * Redistributions qualify as "Open Source" under one of the following terms:
13  *
14  * Redistributions are made at no charge beyond the reasonable cost of
15  * materials and delivery.
16  *
17  * Redistributions are accompanied by a copy of the Source Code or by an
18  * irrevocable offer to provide a copy of the Source Code for up to three
19  * years at the cost of materials and delivery. Such redistributions
20  * must allow further use, modification, and redistribution of the Source
21  * Code under substantially the same terms as this license.
22  *
23  * Redistributions of source code must retain the copyright notices as they
24  * appear in each source code file, these license terms, and the
25  * disclaimer/limitation of liability set forth as paragraph 6 below.
26  *
27  * Redistributions in binary form must reproduce this Copyright Notice,
28  * these license terms, and the disclaimer/limitation of liability set
29  * forth as paragraph 6 below, in the documentation and/or other materials
30  * provided with the distribution.
31  *
32  * The Software is provided on an "AS IS" basis. No warranty is
33  * provided that the Software is free of defects, or fit for a
34  * particular purpose.
35  *
36  * Limitation of Liability. Quadcap Software shall not be liable
37  * for any damages suffered by the Licensee or any third party resulting
38  * from use of the Software.
39  */

40
41 import java.util.Collections JavaDoc;
42 import java.util.Comparator JavaDoc;
43 import java.util.Date JavaDoc;
44 import java.util.Enumeration JavaDoc;
45 import java.util.Hashtable JavaDoc;
46 import java.util.Locale JavaDoc;
47 import java.util.Vector JavaDoc;
48
49 import java.io.BufferedReader JavaDoc;
50 import java.io.ByteArrayInputStream JavaDoc;
51 import java.io.IOException JavaDoc;
52 import java.io.InputStream JavaDoc;
53 import java.io.InputStreamReader JavaDoc;
54 import java.io.PushbackInputStream JavaDoc;
55
56 import java.net.InetAddress JavaDoc;
57
58 import java.text.DateFormat JavaDoc;
59
60 import java.security.Principal JavaDoc;
61
62 import javax.servlet.RequestDispatcher JavaDoc;
63 import javax.servlet.ServletInputStream JavaDoc;
64 import javax.servlet.http.Cookie JavaDoc;
65 import javax.servlet.http.HttpServletRequest JavaDoc;
66 import javax.servlet.http.HttpSession JavaDoc;
67
68 import com.quadcap.http.util.HeaderParser;
69
70 import com.quadcap.util.Debug;
71 import com.quadcap.util.Util;
72
73 import com.quadcap.io.URLDecodeInputStream;
74
75 import com.quadcap.util.text.OctetMap;
76 import com.quadcap.util.text.Scanner;
77
78
79 /**
80  * This class encapsulates the information that makes up a single HTTP
81  * request, including the method, URI, and the headers.
82  *
83  * @author Stan Bailes
84  */

85 public class HttpRequest implements HttpServletRequest JavaDoc {
86     WebWorker w;
87     HttpResponse res;
88     HttpInputStream his;
89     HttpDispatcher rd;
90     HSession session = null;
91     BufferedReader JavaDoc reader = null;
92
93     Scanner scanner;
94     static OctetMap mapM = new OctetMap('&');
95     static {
96     mapM.include('\r');
97     mapM.include('\n');
98     }
99     static OctetMap mapE = new OctetMap('=');
100     static OctetMap mapQuote = new OctetMap('"');
101
102     String JavaDoc method = null;
103     String JavaDoc uri = null;
104     String JavaDoc pathInfo = null;
105     String JavaDoc queryString = null;
106     int queryStringStart = 0;
107     int queryStringLen = 0;
108     String JavaDoc protocol = null;
109     byte[] headers = new byte[4096];
110     int[] hOffsets = new int[32];
111     Hashtable JavaDoc parameters = new Hashtable JavaDoc();
112     Hashtable JavaDoc attributes = null;
113     boolean getInputStreamCalled = false;
114     boolean getReaderCalled = false;
115                                                                
116     static DateFormat JavaDoc dateFormat = DateFormat.getInstance();
117
118     static final int CR = '\r';
119
120     Cookie JavaDoc[] cookies = null;
121     boolean badRequest = false;
122
123     static final String JavaDoc methodGET = "GET";
124     static final String JavaDoc methodHEAD = "HEAD";
125     static final String JavaDoc methodPOST = "POST";
126
127     static final String JavaDoc proto_09 = "HTTP/0.9";
128     static final String JavaDoc proto_10 = "HTTP/1.0";
129     static final String JavaDoc proto_11 = "HTTP/1.1";
130
131     /**
132      * Using the specified worker's input stream, read an HTTP request,
133      * and construct a new <code>HttpRequest</code> object to represent it.
134      *
135      * @param w the worker
136      */

137     public HttpRequest(WebWorker w) {
138         this.w = w;
139         this.scanner = new Scanner(null);
140     }
141
142     /**
143      * Reset the request object and bind it to the input stream.
144      */

145     public void reset(HttpInputStream is) throws IOException JavaDoc {
146         //Jni j2 = new Jni("HttpRequest");
147
//j2.reset();
148
this.his = is;
149         parameters.clear();
150         attributes = null;
151         method = null;
152         uri = null;
153         pathInfo = null;
154         queryString = null;
155         protocol = null;
156         reader = null;
157         session = null;
158         rd = null;
159         cookies = null;
160         queryStringStart = 0;
161         getInputStreamCalled = false;
162         getReaderCalled = false;
163
164         //j2.dump("clear");
165
int hsize = is.getInputStream().readHeaders(headers, hOffsets);
166         //Debug.println(Util.strBytes(headers, 0, hsize));
167
//j2.dump("readHeaders");
168
int lim = hOffsets[1];
169         int pos = 0;
170         while (headers[pos] == '\r' || headers[pos] == '\n') pos++;
171         int start = pos;
172         while (headers[pos] != ' ' && pos < lim) pos++;
173
174         final byte b1 = headers[start];
175         if (b1 == 'G') {
176             if (headers[start+1] == 'E') {
177                 if (headers[start+2] == 'T') {
178                     method = methodGET;
179                 }
180             }
181         } else if (b1 == 'P') {
182             if (headers[start+1] == 'O') {
183                 if (headers[start+2] == 'S') {
184                     if (headers[start+3] == 'T') {
185                         method = methodPOST;
186                     }
187                 }
188             }
189         } else if (b1 == 'H') {
190             if (headers[start+1] == 'E') {
191                 if (headers[start+2] == 'A') {
192                     if (headers[start+3] == 'D') {
193                         method = methodHEAD;
194                     }
195                 }
196             }
197         }
198         if (method == null) {
199             method = new String JavaDoc(headers, start, pos - start);
200             if (method.equalsIgnoreCase("get")) {
201                 method = methodGET;
202             } else if (method.equalsIgnoreCase("post")) {
203                 method = methodPOST;
204             } else if (method.equalsIgnoreCase("head")) {
205                 method = methodHEAD;
206             }
207         }
208         
209         //j2.dump("getMethod");
210
while (headers[pos] == ' ' && pos < lim) pos++;
211         start = pos;
212         while (headers[pos] != ' ' && headers[pos] != '?' && pos < lim) pos++;
213         uri = new String JavaDoc(headers, start, pos - start);
214         //j2.dump("getUri");
215
if (headers[pos] == '?') {
216             start = ++pos;
217             while (headers[pos] != ' ' && headers[pos] != '\r'&& pos < lim) {
218                 pos++;
219             }
220             queryStringStart = start;
221             queryStringLen = pos - start;
222             parseParameters(parameters,
223                             new ByteArrayInputStream JavaDoc(headers, start,
224                                                      pos-start));
225             
226         }
227         while (headers[pos] == ' ' && pos < lim) pos++;
228         start = pos;
229         if (pos < lim) {
230             for (byte c = headers[pos];
231                  c != '\r' && c != '\n' && c != ' ';
232                  c = headers[pos]) {
233                 if (++pos >= lim) break;
234             }
235         }
236         protocol = proto_10;
237         try {
238             if (headers[pos-1] == '0') {
239                 protocol = proto_10;
240             } else if (headers[pos-1] == '1') {
241                 protocol = proto_11;
242             }
243             if (protocol == null) {
244                 protocol = new String JavaDoc(headers, start, pos - start);
245             }
246         } catch (Throwable JavaDoc t) {}
247         //j2.dump("getProto");
248

249     int cl = getContentLength();
250     if (cl >= 0) {
251         is.setContentLength(cl);
252     }
253     }
254
255     final void maybeParsePostData() {
256     if (!getReaderCalled && !getInputStreamCalled &&
257             method == methodPOST) {
258             String JavaDoc type = getContentType();
259             if (type != null &&
260                 type.equals("application/x-www-form-urlencoded"))
261             {
262                 scanner.reset(his);
263                 parseParameters(parameters, scanner);
264             }
265     }
266     }
267
268     boolean badRequest() { return badRequest; }
269
270     public void setURI(String JavaDoc s) {
271     try {
272         Scanner scanner =
273         new Scanner(new ByteArrayInputStream JavaDoc(s.getBytes()));
274         this.uri = scanner.parseWhile(OctetMap.uriChars);
275         if (scanner.peek() == '?') {
276         scanner.matchChar('?');
277         queryString = scanner.parseWhile(OctetMap.uriChars);
278         parseParameters(parameters,
279                 new ByteArrayInputStream JavaDoc(queryString.getBytes()));
280         } else {
281         queryString = "";
282         }
283     } catch (IOException JavaDoc e) {}
284     }
285
286     /**
287      * ----- ServletRequest methods
288      */

289     
290     /**
291      * Returns the size of the request entity data, or -1 if not known.
292      * Same as the CGI variable CONTENT_LENGTH.
293      */

294     public int getContentLength() {
295         String JavaDoc s = getHeader("Content-Length");
296         if (s == null) return -1;
297         try {
298             return Integer.parseInt(s);
299         } catch (Exception JavaDoc e) {
300             return -1;
301         }
302     }
303     
304     /**
305      * Returns the Internet Media Type of the request entity data, or
306      * null if not known. Same as the CGI variable CONTENT_TYPE.
307      */

308     public String JavaDoc getContentType() {
309         return getHeader("Content-Type");
310     }
311
312     /**
313      * Returns the protocol and version of the request as a string of
314      * the form <code>&lt;protocol&gt;/&lt;major version&gt;.&lt;minor
315      * version&gt</code>. Same as the CGI variable SERVER_PROTOCOL.
316      */

317     public String JavaDoc getProtocol() {
318         return protocol;
319     }
320
321     /**
322      * Returns the scheme of the URL used in this request, for example
323      * "http", "https", or "ftp". Different schemes have different
324      * rules for constructing URLs, as noted in RFC 1738. The URL used
325      * to create a request may be reconstructed using this scheme, the
326      * server name and port, and additional information such as URIs.
327      */

328     public String JavaDoc getScheme() {
329         return "HTTP";
330     }
331
332     /**
333      * Returns the host name of the server that received the request.
334      * Same as the CGI variable SERVER_NAME.
335      */

336     public String JavaDoc getServerName() {
337         return w.getHostName();
338     }
339
340     /**
341      * Returns the port number on which this request was received.
342      * Same as the CGI variable SERVER_PORT.
343      */

344     public int getServerPort() {
345         return w.getPort();
346     }
347
348     /**
349      * Returns the IP address of the agent that sent the request.
350      * Same as the CGI variable REMOTE_ADDR.
351      */

352     public String JavaDoc getRemoteAddr() {
353         return w.getRemoteAddr();
354     }
355
356     /**
357      * Returns the fully qualified host name of the agent that sent the
358      * request. Same as the CGI variable REMOTE_HOST.
359      */

360     public String JavaDoc getRemoteHost() {
361         return w.getRemoteHost();
362     }
363
364     /**
365      * Applies alias rules to the specified virtual path and returns
366      * the corresponding real path, or null if the translation can not
367      * be performed for any reason. For example, an HTTP servlet would
368      * resolve the path using the virtual docroot, if virtual hosting
369      * is enabled, and with the default docroot otherwise. Calling
370      * this method with the string "/" as an argument returns the
371      * document root.
372      *
373      * @param path the virtual path to be translated to a real path
374      */

375     public String JavaDoc getRealPath(String JavaDoc path) {
376         WebApplication app = rd.getContext();
377         return app.getRealPath(path);
378     }
379
380     /**
381      * Returns an input stream for reading binary data in the request body.
382      *
383      * @exception IllegalStateException if getReader has been
384      * called on this same request.
385      * @exception IOException on other I/O related errors.
386      */

387     public ServletInputStream JavaDoc getInputStream() throws IOException JavaDoc {
388         if (getReaderCalled) {
389             throw new IllegalStateException JavaDoc("getReader() already called");
390         }
391         getInputStreamCalled = true;
392     return w.getHttpInputStream();
393     }
394
395     /**
396      * Returns a string containing the lone value of the specified
397      * parameter, or null if the parameter does not exist. For example,
398      * in an HTTP servlet this method would return the value of the
399      * specified query string parameter. Servlet writers should use
400      * this method only when they are sure that there is only one value
401      * for the parameter. If the parameter has (or could have)
402      * multiple values, servlet writers should use
403      * getParameterValues. If a multiple valued parameter name is
404      * passed as an argument, the return value is implementation
405      * dependent.
406      *
407      *
408      * @param name the name of the parameter whose value is required.
409      */

410     public String JavaDoc getParameter(String JavaDoc name) {
411         maybeParsePostData();
412         String JavaDoc[] s = (String JavaDoc[])parameters.get(name);
413         if (s == null) return null;
414         return s[0];
415     }
416
417     /**
418      * Returns the values of the specified parameter for the request as
419      * an array of strings, or null if the named parameter does not
420      * exist. For example, in an HTTP servlet this method would return
421      * the values of the specified query string or posted form as an
422      * array of strings.
423      *
424      * @param name the name of the parameter whose value is required.
425      */

426     public String JavaDoc[] getParameterValues(String JavaDoc name) {
427         maybeParsePostData();
428         String JavaDoc[] ret =(String JavaDoc[])parameters.get(name);
429     return ret;
430     }
431
432     /**
433      * Returns the parameter names for this request as an enumeration
434      * of strings, or an empty enumeration if there are no parameters
435      * or the input stream is empty. The input stream would be empty
436      * if all the data had been read from the stream returned by the
437      * method getInputStream.
438      */

439     public Enumeration JavaDoc getParameterNames() {
440         maybeParsePostData();
441         return parameters.keys();
442     }
443
444     /**
445      * Returns the value of the named attribute of the request, or
446      * null if the attribute does not exist.
447      *
448      * @param name the name of the attribute whose value is required
449      */

450     public Object JavaDoc getAttribute(String JavaDoc name) {
451         Object JavaDoc obj = null;
452     if (attributes != null) obj = attributes.get(name);
453     return obj;
454     }
455
456     /**
457      * Set the value of the named attribute
458      *
459      * @param name the name of the attribute
460      * @param obj the value
461      */

462     public void setAttribute(String JavaDoc name, Object JavaDoc obj) {
463     if (attributes == null) attributes = new Hashtable JavaDoc();
464     attributes.put(name, obj);
465     }
466
467     /**
468      * Return an enumeration of all attribute names of this service
469      */

470     public Enumeration JavaDoc getAttributeNames() {
471     if (attributes == null) return new Vector JavaDoc().elements();
472     return attributes.keys();
473     }
474
475     /**
476      * Remove an attribute from the request
477      */

478     public void removeAttribute(String JavaDoc name) {
479         attributes.remove(name);
480     }
481
482     /**
483      * Returns a buffered reader for reading text in the request body.
484      * This translates character set encodings as appropriate.
485      *
486      *
487      * @exception UnsupportedEncodingException if the character set encoding
488      * is unsupported, so the text can't be correctly decoded.
489      * @exception IllegalStateException if getInputStream has been
490      * called on this same request.
491      * @exception IOException on other I/O related errors.
492      */

493     public BufferedReader JavaDoc getReader() throws IOException JavaDoc {
494         if (getInputStreamCalled) {
495             throw new IllegalStateException JavaDoc("getInputStream() already called");
496         }
497         if (reader == null) {
498             reader =
499                 new BufferedReader JavaDoc(new InputStreamReader JavaDoc(getInputStream()));
500         }
501         getReaderCalled = true;
502         return reader;
503     }
504
505     /**
506      * Returns the character set encoding for the input of this request.
507      */

508     public String JavaDoc getCharacterEncoding () {
509         String JavaDoc s = getContentType();
510         if (s == null) return null;
511         
512         int idx = s.indexOf(';');
513         while (idx > 0) {
514             s = s.substring(idx+1).trim();
515             idx = s.indexOf(';');
516             String JavaDoc c = s;
517             if (idx > 0) {
518                 c = s.substring(0, idx).trim();
519             }
520             if (c.startsWith("charset=")) {
521                 return c.substring(8);
522             }
523         }
524         return null;
525     }
526
527     /**
528      * ----- HttpServletRequest methods -----
529      */

530
531     /**
532      * Gets the array of cookies found in this request.
533      *
534      * @return the array of cookies found in this request
535      */

536     public Cookie JavaDoc[] getCookies() {
537         if (cookies == null) {
538             CookieParser cp = new CookieParser(getHeader("Cookie"));
539             try {
540                 cookies = cp.parseCookies();
541             } catch (IOException JavaDoc e) {
542                 Debug.print(e);
543                 cookies = new Cookie JavaDoc[0];
544             }
545         }
546         return cookies;
547     }
548
549     /**
550      * Gets the HTTP method (for example, GET, POST, PUT) with which
551      * this request was made. Same as the CGI variable REQUEST_METHOD.
552      *
553      * @return the HTTP method with which this request was made
554      */

555     public String JavaDoc getMethod() {
556         return method;
557     }
558
559     /**
560      * Gets, from the first line of the HTTP request, the part of this
561      * request's URI that is to the left of any query string.
562      * For example,
563      *
564      * <blockquote>
565      * <table>
566      * <tr align=left><th>First line of HTTP request<th>
567      * <th>Return from <code>getRequestURI</code>
568      * <tr><td>POST /some/path.html HTTP/1.1<td><td>/some/path.html
569      * <tr><td>GET http://foo.bar/a.html HTTP/1.0
570      * <td><td>http://foo.bar/a.html
571      * <tr><td>HEAD /xyz?a=b HTTP/1.1<td><td>/xyz
572      * </table>
573      * </blockquote>
574      *
575      * <p>To reconstruct a URL with a URL scheme and host, use the
576      * method javax.servlet.http.HttpUtils.getRequestURL, which returns
577      * a StringBuffer.
578      *
579      * @return this request's URI
580      */

581     public String JavaDoc getRequestURI() {
582         return uri;
583     }
584
585     /**
586      * Gets the part of this request's URI that refers to the servlet
587      * being invoked. Analogous to the CGI variable SCRIPT_NAME.
588      *
589      * @return the servlet being invoked, as contained in this
590      * request's URI
591      */

592     public String JavaDoc getServletPath() {
593     return rd.getServletPath();
594     }
595
596     /**
597      * Gets any optional extra path information following the servlet
598      * path of this request's URI, but immediately preceding its query
599      * string. Same as the CGI variable PATH_INFO.
600      *
601      * @return the optional path information following the servlet
602      * path, but before the query string, in this request's URI; null
603      * if this request's URI contains no extra path information
604      */

605     public String JavaDoc getPathInfo() {
606     return rd.getPathInfo();
607     }
608
609     /**
610      * Gets any optional extra path information following the servlet
611      * path of this request's URI, but immediately preceding its query
612      * string, and translates it to a real path. Similar to the CGI
613      * variable PATH_TRANSLATED
614      *
615      * @return extra path information translated to a real path or null
616      * if no extra path information is in the request's URI
617      */

618     public String JavaDoc getPathTranslated() {
619         return null;
620     }
621
622     /**
623      * Gets any query string that is part of the HTTP request URI.
624      * Same as the CGI variable QUERY_STRING.
625      *
626      * @return query string that is part of this request's URI, or null
627      * if it contains no query string
628      */

629     public String JavaDoc getQueryString() {
630         if (queryString == null) {
631             if (queryStringStart > 0) {
632                 queryString = new String JavaDoc(headers, queryStringStart,
633                                          (queryStringLen));
634             }
635         }
636         return queryString;
637     }
638
639     /**
640      * Gets the name of the user making this request. The user name is
641      * set with HTTP authentication. Whether the user name will
642      * continue to be sent with each subsequent communication is
643      * browser-dependent. Same as the CGI variable REMOTE_USER.
644      *
645      * @return the name of the user making this request, or null if not
646      * known.
647      */

648     public String JavaDoc getRemoteUser() {
649         return null;
650     }
651
652     /**
653      * Gets the authentication scheme of this request. Same as the CGI
654      * variable AUTH_TYPE.
655      *
656      * @return this request's authentication scheme, or null if none.
657      */

658     public String JavaDoc getAuthType() {
659         return null;
660     }
661
662     /**
663      * Gets the value of the requested header field of this request.
664      * The case of the header field name is ignored.
665      *
666      * @param name the String containing the name of the requested
667      * header field
668      * @return the value of the requested header field, or null if not
669      * known.
670      */

671     public String JavaDoc getHeader(String JavaDoc name) {
672         String JavaDoc ret = null;
673         int hcnt = hOffsets[0];
674         for (int i = 1; i < hcnt; i++) {
675             int off = hOffsets[i];
676             int lim = hOffsets[i+1];
677             int pos = off;
678             while (headers[pos] != ':' && pos < lim) pos++;
679             String JavaDoc hdr = new String JavaDoc(headers, off, pos - off);
680             if (name.equalsIgnoreCase(hdr)) {
681                 ret = new String JavaDoc(headers, pos+1, lim-pos-1).trim();
682                 break;
683             }
684         }
685     return ret;
686     }
687
688
689     /**
690      * Gets the value of the specified integer header field of this
691      * request. The case of the header field name is ignored. If the
692      * header can't be converted to an integer, the method throws a
693      * NumberFormatException.
694      *
695      * @param name the String containing the name of the requested
696      * header field
697      * @return the value of the requested header field, or -1 if not
698      * found.
699      */

700     public int getIntHeader(String JavaDoc name) {
701         int ret = -1;
702         String JavaDoc val = getHeader(name);
703         if (val != null) {
704             ret = Integer.parseInt(val);
705         }
706         return ret;
707     }
708
709     /**
710      * Gets the value of the requested date header field of this
711      * request. If the header can't be converted to a date, the method
712      * throws an IllegalArgumentException. The case of the header
713      * field name is ignored.
714      *
715      * @param name the String containing the name of the requested
716      * header field
717      * @return the value the requested date header field, or -1 if not
718      * found.
719      */

720     public long getDateHeader(String JavaDoc name) {
721         long ret = -1;
722         String JavaDoc val = getHeader(name);
723         if (val != null) {
724             try {
725         synchronized (dateFormat) {
726             Date JavaDoc d = dateFormat.parse(val);
727             ret = d.getTime();
728         }
729             } catch (Exception JavaDoc e) {
730             }
731         }
732         return ret;
733     }
734
735     /**
736      * Gets the header names for this request.
737      *
738      * @return an enumeration of strings representing the header names
739      * for this request. Some server implementations do not allow
740      * headers to be accessed in this way, in which case this method
741      * will return null.
742      */

743     public Enumeration JavaDoc getHeaders() {
744         return getHeaderNames();
745     }
746
747     public Enumeration JavaDoc getHeaders(String JavaDoc name) {
748         Vector JavaDoc v = new Vector JavaDoc();
749         int hcnt = hOffsets[0];
750         for (int i = 1; i < hcnt; i++) {
751             int off = hOffsets[i];
752             int lim = hOffsets[i+1];
753             int pos = off;
754             while (headers[pos] != ':' && pos < lim) pos++;
755             if (name.equalsIgnoreCase(new String JavaDoc(headers, off, pos-off))) {
756                 pos++;
757                 int len = lim - pos;
758                 v.addElement(new String JavaDoc(headers, pos, len).trim());
759             }
760         }
761         return v.elements();
762     }
763
764     public Enumeration JavaDoc getHeaderNames() {
765         Vector JavaDoc v = new Vector JavaDoc();
766         int hcnt = hOffsets[0];
767         for (int i = 1; i < hcnt; i++) {
768             int off = hOffsets[i];
769             int lim = hOffsets[i+1];
770             int pos = off;
771             while (headers[pos] != ':' && pos < lim) pos++;
772             v.addElement(new String JavaDoc(headers, off, pos-off));
773         }
774         return v.elements();
775     }
776
777     /**
778      * Gets the current valid session associated with this request, if
779      * create is false or, if necessary, creates a new session for the
780      * request, if create is true.
781      *
782      * <p><b>Note</b>: to ensure the session is properly maintained,
783      * the servlet developer must call this method (at least once)
784      * before any output is written to the response.
785      *
786      * <p>Additionally, application-writers need to be aware that newly
787      * created sessions (that is, sessions for which
788      * <code>HttpSession.isNew</code> returns true) do not have any
789      * application-specific state.
790      *
791      * @return the session associated with this request or null if
792      * create was false and no valid session is associated
793      * with this request.
794      */

795     public HttpSession JavaDoc getSession(boolean create) {
796         if (session == null) {
797             WebApplication app = rd.getContext();
798             String JavaDoc sessionId = getRequestedSessionId();
799             if (sessionId != null) {
800                 session = app.getSession(sessionId);
801             } else if (create) {
802                 session = app.createSession();
803                 sessionId = session.getId();
804             }
805             if (sessionId != null) {
806                 Cookie JavaDoc c = new Cookie JavaDoc("sessionId", sessionId);
807                 c.setPath(getContextPath());
808                 res.addCookie(c);
809             }
810         }
811         if (session != null) session.updateLastAccess();
812         return session;
813     }
814    
815     /**
816      * Gets the current valid session associated with this request, and
817      * if necessary, creates a new session for the request.
818      *
819      * @return the session associated with this request.
820      */

821     public HttpSession JavaDoc getSession() {
822     return getSession(true);
823     }
824
825     /**
826      * Gets the session id specified with this request. This may
827      * differ from the actual session id. For example, if the request
828      * specified an id for an invalid session, then this will get a new
829      * session with a new id.
830      *
831      * @return the session id specified by this request, or null if the
832      * request did not specify a session id
833      *
834      */

835     public String JavaDoc getRequestedSessionId() {
836         String JavaDoc sessionId = null;
837         getCookies();
838         WebApplication app = rd.getContext();
839         boolean foundSession = false;
840         for (int i = 0; i < cookies.length; i++) {
841             Cookie JavaDoc c = cookies[i];
842             if (c.getName().equals("sessionId")) {
843                 sessionId = c.getValue();
844                 if (app.getSession(sessionId) != null) {
845                     foundSession = true;
846                     break;
847 // } else {
848
// Debug.println("invalid session id: " + sessionId);
849
}
850             }
851         }
852         if (sessionId != null && !foundSession) {
853             sessionId = app.createSession().getId();
854         }
855         return sessionId;
856     }
857
858     /**
859      * Checks whether this request is associated with a session that
860      * is valid in the current session context. If it is not valid,
861      * the requested session will never be returned from the
862      * <code>getSession</code> method.
863      *
864      * @return true if this request is assocated with a session that is
865      * valid in the current session context.
866      *
867      */

868     public boolean isRequestedSessionIdValid() {
869         HSession sess = null;
870         String JavaDoc sessionId = getRequestedSessionId();
871         if (sessionId != null) {
872             sess = rd.getContext().getSession(sessionId);
873         }
874         return (sess != null && sess.isValid());
875     }
876
877     /**
878      * Checks whether the session id specified by this request came in
879      * as a cookie. (The requested session may not be one returned by
880      * the <code>getSession</code> method.)
881      *
882      * @return true if the session id specified by this request came in
883      * as a cookie; false otherwise
884      *
885      */

886     public boolean isRequestedSessionIdFromCookie() {
887         return true;
888     }
889
890     /**
891      * Checks whether the session id specified by this request came in
892      * as part of the URL. (The requested session may not be the one
893      * returned by the <code>getSession</code> method.)
894      *
895      * @return true if the session id specified by the request for this
896      * session came in as part of the URL; false otherwise
897      *
898      */

899     public boolean isRequestedSessionIdFromURL() {
900         return false;
901     }
902     public boolean isRequestedSessionIdFromUrl() {
903         return false;
904     }
905
906     /**
907      * ---- private parsing helpers
908      */

909
910     
911     /**
912      * Parsing helper: Get the next bytes all of which are in the
913      * specified map
914      *
915      * @param map the octet map specifying the bytes we want
916      */

917     String JavaDoc getToken(OctetMap map) throws IOException JavaDoc {
918     scanner.skipWhile(OctetMap.wsChars);
919     return scanner.parseWhile(map);
920     }
921
922     static OctetMap versionMap = new OctetMap("HhTtPp/1.0");
923     
924     /**
925      * Parse the http version field from the request line
926      *
927      * @return the http protocol and version
928      *
929      * @exception IOException if the version field is incorrect
930      */

931     String JavaDoc parseHttpVersion() throws IOException JavaDoc {
932     scanner.skipWhile(OctetMap.wsChars);
933         return scanner.parseWhile(versionMap);
934     }
935
936     static final String JavaDoc urlDecode(String JavaDoc s) {
937     StringBuffer JavaDoc sb = null;
938     for (int i = 0; i < s.length(); i++) {
939         char c = s.charAt(i);
940         switch (c) {
941         case '+':
942         if (sb == null) sb = new StringBuffer JavaDoc(s.substring(0, i));
943         sb.append(' ');
944         break;
945         case '%':
946         if (sb == null) sb = new StringBuffer JavaDoc(s.substring(0, i));
947         try {
948             sb.append((char) Integer.parseInt(s.substring(i+1, i+3),
949                               16));
950             i += 2;
951         } catch (NumberFormatException JavaDoc e) {
952             throw new IllegalArgumentException JavaDoc();
953         } catch (StringIndexOutOfBoundsException JavaDoc e) {
954             String JavaDoc rest = s.substring(i);
955             sb.append(rest);
956             if (rest.length()==2) i++;
957         }
958         break;
959         default:
960         if (sb != null) sb.append(c);
961         }
962     }
963     return sb == null ? s : sb.toString();
964     }
965
966     /**
967      * Parse a set of parameters from the specified input stream.
968      *
969      * @param is the input stream
970      * @return a table containing the parameters as String -> String[]
971      * entries.
972      */

973     public static void parseParameters(Hashtable JavaDoc params, InputStream JavaDoc is) {
974     parseParameters(params, new Scanner(is));
975     }
976
977     public static void parseParameters(Hashtable JavaDoc params, Scanner s) {
978     try {
979         do {
980         String JavaDoc name = urlDecode(s.parseUntil(mapE));
981         s.matchChar('=');
982         String JavaDoc val = urlDecode(s.parseUntil(mapM));
983         String JavaDoc[] vals = (String JavaDoc[])params.get(name);
984         if (vals == null) {
985             vals = new String JavaDoc[1];
986         } else {
987             String JavaDoc[] oldvals = vals;
988             vals = new String JavaDoc[vals.length+1];
989             for (int i = 0; i < oldvals.length; i++) {
990             vals[i] = oldvals[i];
991             }
992         }
993         vals[vals.length-1] = val;
994         params.put(name, vals);
995         s.matchChar('&');
996         } while (s.peek() >= 0);
997     } catch (IOException JavaDoc e) {
998     }
999     }
1000
1001    /**
1002     * Associate this request with its matching response. We need this
1003     * to facilitate session management via cookies
1004     *
1005     * @param res the HttpResponse that goes with this request
1006     */

1007    void setResponse(HttpResponse res) { this.res = res; }
1008
1009    /**
1010     * Return the portion of the request URI that specifies the context
1011     * for this request
1012     */

1013    public String JavaDoc getContextPath() {
1014        return rd.getContextPath();
1015    }
1016
1017    /**
1018     * Returns a boolean indicating whether the authenticated user is
1019     * included in the indicated 'role'.
1020     */

1021    public boolean isUserInRole(String JavaDoc role) {
1022        return false; // XXX implement me
1023
}
1024
1025    /**
1026     * Return a Principal object indicating the identity of the user
1027     * associated with this request.
1028     */

1029    public Principal JavaDoc getUserPrincipal() {
1030        return null; // XXX implement me
1031
}
1032
1033    /**
1034     * Return the preferred Locale that the client will accept content
1035     * from based on the <code>Accept-Language</code> header, or the
1036     * server default Locale
1037     */

1038    public Locale JavaDoc getLocale() {
1039        Locale JavaDoc locale = null;
1040        String JavaDoc accept = getHeader("Accept-Language");
1041        if (accept != null) {
1042            int idx = accept.indexOf(',');
1043            if (idx > 0) {
1044                accept = accept.substring(0, idx).trim();
1045            }
1046            locale = makeLocale(accept);
1047        } else {
1048            locale = Locale.getDefault();
1049        }
1050        return locale;
1051    }
1052
1053    final Locale JavaDoc makeLocale(String JavaDoc s) {
1054        int idx = s.indexOf(';');
1055        if (idx > 0) {
1056            s = s.substring(0, idx).trim();
1057        }
1058        idx = s.indexOf('-');
1059        String JavaDoc lang = null;
1060        String JavaDoc country = "";
1061        if (idx > 0) {
1062            lang = s.substring(0, idx);
1063            country = s.substring(idx+1);
1064        } else {
1065            lang = s;
1066        }
1067        return new Locale JavaDoc(lang, country);
1068    }
1069
1070    final float getLangQual(String JavaDoc s) {
1071        float q = 1.0f;
1072        int idx = s.indexOf(';');
1073        if (idx > 0) {
1074            s = s.substring(idx+1).trim();
1075            idx = s.indexOf("q=");
1076            if (idx >= 0) {
1077                q =Float.parseFloat(s.substring(idx+2));
1078            }
1079        }
1080        return q;
1081    }
1082    
1083    final int compareAccept(String JavaDoc a, String JavaDoc b) {
1084        float aq = getLangQual(a);
1085        float bq = getLangQual(b);
1086        if (aq < bq) return -1;
1087        if (aq > bq) return 1;
1088        return 0;
1089    }
1090
1091    public Enumeration JavaDoc getLocales() {
1092        String JavaDoc accept = getHeader("Accept-Language");
1093        if (accept == null) {
1094            Vector JavaDoc v = new Vector JavaDoc();
1095            v.addElement(Locale.getDefault());
1096            return v.elements();
1097        }
1098        Vector JavaDoc v = Util.split(accept, ',');
1099        Comparator JavaDoc c = new Comparator JavaDoc() {
1100            public int compare(Object JavaDoc a, Object JavaDoc b) {
1101                return compareAccept(a.toString(), b.toString());
1102            }
1103        };
1104        Collections.sort(v, c);
1105        final Enumeration JavaDoc e = v.elements();
1106        return new Enumeration JavaDoc() {
1107            public boolean hasMoreElements() {
1108                return e.hasMoreElements();
1109            }
1110            public Object JavaDoc nextElement() {
1111                return makeLocale(e.nextElement().toString());
1112            }
1113        };
1114    }
1115                
1116    public RequestDispatcher JavaDoc getRequestDispatcher(String JavaDoc path) {
1117        return rd.getContext().getRelativeRequestDispatcher(path, this);
1118    }
1119
1120    public boolean isSecure() {
1121        return false;
1122    }
1123
1124    final void setRequestDispatcher(HttpDispatcher rd) {
1125        this.rd = rd;
1126    }
1127
1128}
1129
Popular Tags