1 /*
2 * Licensed to the Apache Software Foundation (ASF) under one or more
3 * contributor license agreements. See the NOTICE file distributed with
4 * this work for additional information regarding copyright ownership.
5 * The ASF licenses this file to You under the Apache License, Version 2.0
6 * (the "License"); you may not use this file except in compliance with
7 * the License. You may obtain a copy of the License at
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 */
17
18
19 package org.apache.catalina.connector;
20
21
22 import java.io.InputStream;
23 import java.io.IOException;
24 import java.io.BufferedReader;
25 import java.io.UnsupportedEncodingException;
26 import java.security.Principal;
27 import java.text.SimpleDateFormat;
28 import java.util.ArrayList;
29 import java.util.Enumeration;
30 import java.util.HashMap;
31 import java.util.Iterator;
32 import java.util.Locale;
33 import java.util.Map;
34 import java.util.TimeZone;
35 import java.util.TreeMap;
36
37 import javax.security.auth.Subject;
38 import javax.servlet.FilterChain;
39 import javax.servlet.RequestDispatcher;
40 import javax.servlet.ServletContext;
41 import javax.servlet.ServletInputStream;
42 import javax.servlet.ServletRequestAttributeEvent;
43 import javax.servlet.ServletRequestAttributeListener;
44 import javax.servlet.http.Cookie;
45 import javax.servlet.http.HttpServletRequest;
46 import javax.servlet.http.HttpSession;
47
48 import org.apache.tomcat.util.buf.B2CConverter;
49 import org.apache.tomcat.util.buf.MessageBytes;
50 import org.apache.tomcat.util.buf.StringCache;
51 import org.apache.tomcat.util.http.Cookies;
52 import org.apache.tomcat.util.http.FastHttpDateFormat;
53 import org.apache.tomcat.util.http.Parameters;
54 import org.apache.tomcat.util.http.ServerCookie;
55 import org.apache.tomcat.util.http.mapper.MappingData;
56
57 import org.apache.coyote.ActionCode;
58
59 import org.apache.catalina.Context;
60 import org.apache.catalina.Globals;
61 import org.apache.catalina.Host;
62 import org.apache.catalina.Manager;
63 import org.apache.catalina.Realm;
64 import org.apache.catalina.Session;
65 import org.apache.catalina.Wrapper;
66 import org.apache.catalina.core.ApplicationFilterFactory;
67 import org.apache.catalina.realm.GenericPrincipal;
68 import org.apache.catalina.util.Enumerator;
69 import org.apache.catalina.util.ParameterMap;
70 import org.apache.catalina.util.RequestUtil;
71 import org.apache.catalina.util.StringManager;
72 import org.apache.catalina.util.StringParser;
73
74
75 /**
76 * Wrapper object for the Coyote request.
77 *
78 * @author Remy Maucherat
79 * @author Craig R. McClanahan
80 * @version $Revision: 608944 $ $Date: 2008-01-04 18:59:38 +0100 (ven., 04 janv. 2008) $
81 */
82
83 public class Request
84 implements HttpServletRequest {
85
86
87 // ----------------------------------------------------------- Constructors
88
89
90 static {
91 // Ensure that classes are loaded for SM
92 new StringCache.ByteEntry();
93 new StringCache.CharEntry();
94 }
95
96 public Request() {
97
98 formats[0].setTimeZone(GMT_ZONE);
99 formats[1].setTimeZone(GMT_ZONE);
100 formats[2].setTimeZone(GMT_ZONE);
101
102 }
103
104
105 // ------------------------------------------------------------- Properties
106
107
108 /**
109 * Coyote request.
110 */
111 protected org.apache.coyote.Request coyoteRequest;
112
113 /**
114 * Set the Coyote request.
115 *
116 * @param coyoteRequest The Coyote request
117 */
118 public void setCoyoteRequest(org.apache.coyote.Request coyoteRequest) {
119 this.coyoteRequest = coyoteRequest;
120 inputBuffer.setRequest(coyoteRequest);
121 }
122
123 /**
124 * Get the Coyote request.
125 */
126 public org.apache.coyote.Request getCoyoteRequest() {
127 return (this.coyoteRequest);
128 }
129
130
131 // ----------------------------------------------------- Variables
132
133
134 protected static final TimeZone GMT_ZONE = TimeZone.getTimeZone("GMT");
135
136
137 /**
138 * The string manager for this package.
139 */
140 protected static StringManager sm =
141 StringManager.getManager(Constants.Package);
142
143
144 /**
145 * The set of cookies associated with this Request.
146 */
147 protected Cookie[] cookies = null;
148
149
150 /**
151 * The set of SimpleDateFormat formats to use in getDateHeader().
152 *
153 * Notice that because SimpleDateFormat is not thread-safe, we can't
154 * declare formats[] as a static variable.
155 */
156 protected SimpleDateFormat formats[] = {
157 new SimpleDateFormat("EEE, dd MMM yyyy HH:mm:ss zzz", Locale.US),
158 new SimpleDateFormat("EEEEEE, dd-MMM-yy HH:mm:ss zzz", Locale.US),
159 new SimpleDateFormat("EEE MMMM d HH:mm:ss yyyy", Locale.US)
160 };
161
162
163 /**
164 * The default Locale if none are specified.
165 */
166 protected static Locale defaultLocale = Locale.getDefault();
167
168
169 /**
170 * The attributes associated with this Request, keyed by attribute name.
171 */
172 protected HashMap attributes = new HashMap();
173
174
175 /**
176 * List of read only attributes for this Request.
177 */
178 private HashMap readOnlyAttributes = new HashMap();
179
180
181 /**
182 * The preferred Locales assocaited with this Request.
183 */
184 protected ArrayList locales = new ArrayList();
185
186
187 /**
188 * Internal notes associated with this request by Catalina components
189 * and event listeners.
190 */
191 private transient HashMap notes = new HashMap();
192
193
194 /**
195 * Authentication type.
196 */
197 protected String authType = null;
198
199
200 /**
201 * Associated event.
202 */
203 protected CometEventImpl event = null;
204
205
206 /**
207 * Comet state
208 */
209 protected boolean comet = false;
210
211
212 /**
213 * The current dispatcher type.
214 */
215 protected Object dispatcherType = null;
216
217
218 /**
219 * The associated input buffer.
220 */
221 protected InputBuffer inputBuffer = new InputBuffer();
222
223
224 /**
225 * ServletInputStream.
226 */
227 protected CoyoteInputStream inputStream =
228 new CoyoteInputStream(inputBuffer);
229
230
231 /**
232 * Reader.
233 */
234 protected CoyoteReader reader = new CoyoteReader(inputBuffer);
235
236
237 /**
238 * Using stream flag.
239 */
240 protected boolean usingInputStream = false;
241
242
243 /**
244 * Using writer flag.
245 */
246 protected boolean usingReader = false;
247
248
249 /**
250 * User principal.
251 */
252 protected Principal userPrincipal = null;
253
254
255 /**
256 * Session parsed flag.
257 */
258 protected boolean sessionParsed = false;
259
260
261 /**
262 * Request parameters parsed flag.
263 */
264 protected boolean parametersParsed = false;
265
266
267 /**
268 * Cookies parsed flag.
269 */
270 protected boolean cookiesParsed = false;
271
272
273 /**
274 * Secure flag.
275 */
276 protected boolean secure = false;
277
278
279 /**
280 * The Subject associated with the current AccessControllerContext
281 */
282 protected transient Subject subject = null;
283
284
285 /**
286 * Post data buffer.
287 */
288 protected static int CACHED_POST_LEN = 8192;
289 protected byte[] postData = null;
290
291
292 /**
293 * Hash map used in the getParametersMap method.
294 */
295 protected ParameterMap parameterMap = new ParameterMap();
296
297
298 /**
299 * The currently active session for this request.
300 */
301 protected Session session = null;
302
303
304 /**
305 * The current request dispatcher path.
306 */
307 protected Object requestDispatcherPath = null;
308
309
310 /**
311 * Was the requested session ID received in a cookie?
312 */
313 protected boolean requestedSessionCookie = false;
314
315
316 /**
317 * The requested session ID (if any) for this request.
318 */
319 protected String requestedSessionId = null;
320
321
322 /**
323 * Was the requested session ID received in a URL?
324 */
325 protected boolean requestedSessionURL = false;
326
327
328 /**
329 * Parse locales.
330 */
331 protected boolean localesParsed = false;
332
333
334 /**
335 * The string parser we will use for parsing request lines.
336 */
337 private StringParser parser = new StringParser();
338
339
340 /**
341 * Local port
342 */
343 protected int localPort = -1;
344
345 /**
346 * Remote address.
347 */
348 protected String remoteAddr = null;
349
350
351 /**
352 * Remote host.
353 */
354 protected String remoteHost = null;
355
356
357 /**
358 * Remote port
359 */
360 protected int remotePort = -1;
361
362 /**
363 * Local address
364 */
365 protected String localAddr = null;
366
367
368 /**
369 * Local address
370 */
371 protected String localName = null;
372
373
374 // --------------------------------------------------------- Public Methods
375
376
377 /**
378 * Release all object references, and initialize instance variables, in
379 * preparation for reuse of this object.
380 */
381 public void recycle() {
382
383 context = null;
384 wrapper = null;
385
386 dispatcherType = null;
387 requestDispatcherPath = null;
388
389 comet = false;
390 if (event != null) {
391 event.clear();
392 event = null;
393 }
394
395 authType = null;
396 inputBuffer.recycle();
397 usingInputStream = false;
398 usingReader = false;
399 userPrincipal = null;
400 subject = null;
401 sessionParsed = false;
402 parametersParsed = false;
403 cookiesParsed = false;
404 locales.clear();
405 localesParsed = false;
406 secure = false;
407 remoteAddr = null;
408 remoteHost = null;
409 remotePort = -1;
410 localPort = -1;
411 localAddr = null;
412 localName = null;
413
414 attributes.clear();
415 notes.clear();
416 cookies = null;
417
418 if (session != null) {
419 session.endAccess();
420 }
421 session = null;
422 requestedSessionCookie = false;
423 requestedSessionId = null;
424 requestedSessionURL = false;
425
426 if (Globals.IS_SECURITY_ENABLED || Connector.RECYCLE_FACADES) {
427 parameterMap = new ParameterMap();
428 } else {
429 parameterMap.setLocked(false);
430 parameterMap.clear();
431 }
432
433 mappingData.recycle();
434
435 if (Globals.IS_SECURITY_ENABLED || Connector.RECYCLE_FACADES) {
436 if (facade != null) {
437 facade.clear();
438 facade = null;
439 }
440 if (inputStream != null) {
441 inputStream.clear();
442 inputStream = null;
443 }
444 if (reader != null) {
445 reader.clear();
446 reader = null;
447 }
448 }
449
450 }
451
452
453 /**
454 * Clear cached encoders (to save memory for Comet requests).
455 */
456 public void clearEncoders() {
457 inputBuffer.clearEncoders();
458 }
459
460
461 /**
462 * Clear cached encoders (to save memory for Comet requests).
463 */
464 public boolean read()
465 throws IOException {
466 return (inputBuffer.realReadBytes(null, 0, 0) > 0);
467 }
468
469
470 // -------------------------------------------------------- Request Methods
471
472
473 /**
474 * Associated Catalina connector.
475 */
476 protected Connector connector;
477
478 /**
479 * Return the Connector through which this Request was received.
480 */
481 public Connector getConnector() {
482 return (this.connector);
483 }
484
485 /**
486 * Set the Connector through which this Request was received.
487 *
488 * @param connector The new connector
489 */
490 public void setConnector(Connector connector) {
491 this.connector = connector;
492 }
493
494
495 /**
496 * Associated context.
497 */
498 protected Context context = null;
499
500 /**
501 * Return the Context within which this Request is being processed.
502 */
503 public Context getContext() {
504 return (this.context);
505 }
506
507
508 /**
509 * Set the Context within which this Request is being processed. This
510 * must be called as soon as the appropriate Context is identified, because
511 * it identifies the value to be returned by <code>getContextPath()</code>,
512 * and thus enables parsing of the request URI.
513 *
514 * @param context The newly associated Context
515 */
516 public void setContext(Context context) {
517 this.context = context;
518 }
519
520
521 /**
522 * Filter chain associated with the request.
523 */
524 protected FilterChain filterChain = null;
525
526 /**
527 * Get filter chain associated with the request.
528 */
529 public FilterChain getFilterChain() {
530 return (this.filterChain);
531 }
532
533 /**
534 * Set filter chain associated with the request.
535 *
536 * @param filterChain new filter chain
537 */
538 public void setFilterChain(FilterChain filterChain) {
539 this.filterChain = filterChain;
540 }
541
542
543 /**
544 * Return the Host within which this Request is being processed.
545 */
546 public Host getHost() {
547 if (getContext() == null)
548 return null;
549 return (Host) getContext().getParent();
550 //return ((Host) mappingData.host);
551 }
552
553
554 /**
555 * Set the Host within which this Request is being processed. This
556 * must be called as soon as the appropriate Host is identified, and
557 * before the Request is passed to a context.
558 *
559 * @param host The newly associated Host
560 */
561 public void setHost(Host host) {
562 mappingData.host = host;
563 }
564
565
566 /**
567 * Descriptive information about this Request implementation.
568 */
569 protected static final String info =
570 "org.apache.coyote.catalina.CoyoteRequest/1.0";
571
572 /**
573 * Return descriptive information about this Request implementation and
574 * the corresponding version number, in the format
575 * <code><description>/<version></code>.
576 */
577 public String getInfo() {
578 return (info);
579 }
580
581
582 /**
583 * Mapping data.
584 */
585 protected MappingData mappingData = new MappingData();
586
587 /**
588 * Return mapping data.
589 */
590 public MappingData getMappingData() {
591 return (mappingData);
592 }
593
594
595 /**
596 * The facade associated with this request.
597 */
598 protected RequestFacade facade = null;
599
600 /**
601 * Return the <code>ServletRequest</code> for which this object
602 * is the facade. This method must be implemented by a subclass.
603 */
604 public HttpServletRequest getRequest() {
605 if (facade == null) {
606 facade = new RequestFacade(this);
607 }
608 return (facade);
609 }
610
611
612 /**
613 * The response with which this request is associated.
614 */
615 protected org.apache.catalina.connector.Response response = null;
616
617 /**
618 * Return the Response with which this Request is associated.
619 */
620 public org.apache.catalina.connector.Response getResponse() {
621 return (this.response);
622 }
623
624 /**
625 * Set the Response with which this Request is associated.
626 *
627 * @param response The new associated response
628 */
629 public void setResponse(org.apache.catalina.connector.Response response) {
630 this.response = response;
631 }
632
633 /**
634 * Return the input stream associated with this Request.
635 */
636 public InputStream getStream() {
637 if (inputStream == null) {
638 inputStream = new CoyoteInputStream(inputBuffer);
639 }
640 return inputStream;
641 }
642
643 /**
644 * Set the input stream associated with this Request.
645 *
646 * @param stream The new input stream
647 */
648 public void setStream(InputStream stream) {
649 // Ignore
650 }
651
652
653 /**
654 * URI byte to char converter (not recycled).
655 */
656 protected B2CConverter URIConverter = null;
657
658 /**
659 * Return the URI converter.
660 */
661 protected B2CConverter getURIConverter() {
662 return URIConverter;
663 }
664
665 /**
666 * Set the URI converter.
667 *
668 * @param URIConverter the new URI connverter
669 */
670 protected void setURIConverter(B2CConverter URIConverter) {
671 this.URIConverter = URIConverter;
672 }
673
674
675 /**
676 * Associated wrapper.
677 */
678 protected Wrapper wrapper = null;
679
680 /**
681 * Return the Wrapper within which this Request is being processed.
682 */
683 public Wrapper getWrapper() {
684 return (this.wrapper);
685 }
686
687
688 /**
689 * Set the Wrapper within which this Request is being processed. This
690 * must be called as soon as the appropriate Wrapper is identified, and
691 * before the Request is ultimately passed to an application servlet.
692 * @param wrapper The newly associated Wrapper
693 */
694 public void setWrapper(Wrapper wrapper) {
695 this.wrapper = wrapper;
696 }
697
698
699 // ------------------------------------------------- Request Public Methods
700
701
702 /**
703 * Create and return a ServletInputStream to read the content
704 * associated with this Request.
705 *
706 * @exception IOException if an input/output error occurs
707 */
708 public ServletInputStream createInputStream()
709 throws IOException {
710 if (inputStream == null) {
711 inputStream = new CoyoteInputStream(inputBuffer);
712 }
713 return inputStream;
714 }
715
716
717 /**
718 * Perform whatever actions are required to flush and close the input
719 * stream or reader, in a single operation.
720 *
721 * @exception IOException if an input/output error occurs
722 */
723 public void finishRequest() throws IOException {
724 // The reader and input stream don't need to be closed
725 }
726
727
728 /**
729 * Return the object bound with the specified name to the internal notes
730 * for this request, or <code>null</code> if no such binding exists.
731 *
732 * @param name Name of the note to be returned
733 */
734 public Object getNote(String name) {
735 return (notes.get(name));
736 }
737
738
739 /**
740 * Return an Iterator containing the String names of all notes bindings
741 * that exist for this request.
742 */
743 public Iterator getNoteNames() {
744 return (notes.keySet().iterator());
745 }
746
747
748 /**
749 * Remove any object bound to the specified name in the internal notes
750 * for this request.
751 *
752 * @param name Name of the note to be removed
753 */
754 public void removeNote(String name) {
755 notes.remove(name);
756 }
757
758
759 /**
760 * Bind an object to a specified name in the internal notes associated
761 * with this request, replacing any existing binding for this name.
762 *
763 * @param name Name to which the object should be bound
764 * @param value Object to be bound to the specified name
765 */
766 public void setNote(String name, Object value) {
767 notes.put(name, value);
768 }
769
770
771 /**
772 * Set the content length associated with this Request.
773 *
774 * @param length The new content length
775 */
776 public void setContentLength(int length) {
777 // Not used
778 }
779
780
781 /**
782 * Set the content type (and optionally the character encoding)
783 * associated with this Request. For example,
784 * <code>text/html; charset=ISO-8859-4</code>.
785 *
786 * @param type The new content type
787 */
788 public void setContentType(String type) {
789 // Not used
790 }
791
792
793 /**
794 * Set the protocol name and version associated with this Request.
795 *
796 * @param protocol Protocol name and version
797 */
798 public void setProtocol(String protocol) {
799 // Not used
800 }
801
802
803 /**
804 * Set the IP address of the remote client associated with this Request.
805 *
806 * @param remoteAddr The remote IP address
807 */
808 public void setRemoteAddr(String remoteAddr) {
809 // Not used
810 }
811
812
813 /**
814 * Set the fully qualified name of the remote client associated with this
815 * Request.
816 *
817 * @param remoteHost The remote host name
818 */
819 public void setRemoteHost(String remoteHost) {
820 // Not used
821 }
822
823
824 /**
825 * Set the name of the scheme associated with this request. Typical values
826 * are <code>http</code>, <code>https</code>, and <code>ftp</code>.
827 *
828 * @param scheme The scheme
829 */
830 public void setScheme(String scheme) {
831 // Not used
832 }
833
834
835 /**
836 * Set the value to be returned by <code>isSecure()</code>
837 * for this Request.
838 *
839 * @param secure The new isSecure value
840 */
841 public void setSecure(boolean secure) {
842 this.secure = secure;
843 }
844
845
846 /**
847 * Set the name of the server (virtual host) to process this request.
848 *
849 * @param name The server name
850 */
851 public void setServerName(String name) {
852 coyoteRequest.serverName().setString(name);
853 }
854
855
856 /**
857 * Set the port number of the server to process this request.
858 *
859 * @param port The server port
860 */
861 public void setServerPort(int port) {
862 coyoteRequest.setServerPort(port);
863 }
864
865
866 // ------------------------------------------------- ServletRequest Methods
867
868
869 /**
870 * Return the specified request attribute if it exists; otherwise, return
871 * <code>null</code>.
872 *
873 * @param name Name of the request attribute to return
874 */
875 public Object getAttribute(String name) {
876
877 if (name.equals(Globals.DISPATCHER_TYPE_ATTR)) {
878 return (dispatcherType == null)
879 ? ApplicationFilterFactory.REQUEST_INTEGER
880 : dispatcherType;
881 } else if (name.equals(Globals.DISPATCHER_REQUEST_PATH_ATTR)) {
882 return (requestDispatcherPath == null)
883 ? getRequestPathMB().toString()
884 : requestDispatcherPath.toString();
885 }
886
887 Object attr=attributes.get(name);
888
889 if(attr!=null)
890 return(attr);
891
892 attr = coyoteRequest.getAttribute(name);
893 if(attr != null)
894 return attr;
895 if( isSSLAttribute(name) ) {
896 coyoteRequest.action(ActionCode.ACTION_REQ_SSL_ATTRIBUTE,
897 coyoteRequest);
898 attr = coyoteRequest.getAttribute(Globals.CERTIFICATES_ATTR);
899 if( attr != null) {
900 attributes.put(Globals.CERTIFICATES_ATTR, attr);
901 }
902 attr = coyoteRequest.getAttribute(Globals.CIPHER_SUITE_ATTR);
903 if(attr != null) {
904 attributes.put(Globals.CIPHER_SUITE_ATTR, attr);
905 }
906 attr = coyoteRequest.getAttribute(Globals.KEY_SIZE_ATTR);
907 if(attr != null) {
908 attributes.put(Globals.KEY_SIZE_ATTR, attr);
909 }
910 attr = coyoteRequest.getAttribute(Globals.SSL_SESSION_ID_ATTR);
911 if(attr != null) {
912 attributes.put(Globals.SSL_SESSION_ID_ATTR, attr);
913 }
914 attr = attributes.get(name);
915 }
916 return attr;
917 }
918
919
920 /**
921 * Test if a given name is one of the special Servlet-spec SSL attributes.
922 */
923 static boolean isSSLAttribute(String name) {
924 return Globals.CERTIFICATES_ATTR.equals(name) ||
925 Globals.CIPHER_SUITE_ATTR.equals(name) ||
926 Globals.KEY_SIZE_ATTR.equals(name) ||
927 Globals.SSL_SESSION_ID_ATTR.equals(name);
928 }
929
930 /**
931 * Return the names of all request attributes for this Request, or an
932 * empty <code>Enumeration</code> if there are none.
933 */
934 public Enumeration getAttributeNames() {
935 if (isSecure()) {
936 getAttribute(Globals.CERTIFICATES_ATTR);
937 }
938 return new Enumerator(attributes.keySet(), true);
939 }
940
941
942 /**
943 * Return the character encoding for this Request.
944 */
945 public String getCharacterEncoding() {
946 return (coyoteRequest.getCharacterEncoding());
947 }
948
949
950 /**
951 * Return the content length for this Request.
952 */
953 public int getContentLength() {
954 return (coyoteRequest.getContentLength());
955 }
956
957
958 /**
959 * Return the content type for this Request.
960 */
961 public String getContentType() {
962 return (coyoteRequest.getContentType());
963 }
964
965
966 /**
967 * Return the servlet input stream for this Request. The default
968 * implementation returns a servlet input stream created by
969 * <code>createInputStream()</code>.
970 *
971 * @exception IllegalStateException if <code>getReader()</code> has
972 * already been called for this request
973 * @exception IOException if an input/output error occurs
974 */
975 public ServletInputStream getInputStream() throws IOException {
976
977 if (usingReader)
978 throw new IllegalStateException
979 (sm.getString("coyoteRequest.getInputStream.ise"));
980
981 usingInputStream = true;
982 if (inputStream == null) {
983 inputStream = new CoyoteInputStream(inputBuffer);
984 }
985 return inputStream;
986
987 }
988
989
990 /**
991 * Return the preferred Locale that the client will accept content in,
992 * based on the value for the first <code>Accept-Language</code> header
993 * that was encountered. If the request did not specify a preferred
994 * language, the server's default Locale is returned.
995 */
996 public Locale getLocale() {
997
998 if (!localesParsed)
999 parseLocales();
1000
1001 if (locales.size() > 0) {
1002 return ((Locale) locales.get(0));
1003 } else {
1004 return (defaultLocale);
1005 }
1006
1007 }
1008
1009
1010 /**
1011 * Return the set of preferred Locales that the client will accept
1012 * content in, based on the values for any <code>Accept-Language</code>
1013 * headers that were encountered. If the request did not specify a
1014 * preferred language, the server's default Locale is returned.
1015 */
1016 public Enumeration getLocales() {
1017
1018 if (!localesParsed)
1019 parseLocales();
1020
1021 if (locales.size() > 0)
1022 return (new Enumerator(locales));
1023 ArrayList results = new ArrayList();
1024 results.add(defaultLocale);
1025 return (new Enumerator(results));
1026
1027 }
1028
1029
1030 /**
1031 * Return the value of the specified request parameter, if any; otherwise,
1032 * return <code>null</code>. If there is more than one value defined,
1033 * return only the first one.
1034 *
1035 * @param name Name of the desired request parameter
1036 */
1037 public String getParameter(String name) {
1038
1039 if (!parametersParsed)
1040 parseParameters();
1041
1042 return coyoteRequest.getParameters().getParameter(name);
1043
1044 }
1045
1046
1047
1048 /**
1049 * Returns a <code>Map</code> of the parameters of this request.
1050 * Request parameters are extra information sent with the request.
1051 * For HTTP servlets, parameters are contained in the query string
1052 * or posted form data.
1053 *
1054 * @return A <code>Map</code> containing parameter names as keys
1055 * and parameter values as map values.
1056 */
1057 public Map getParameterMap() {
1058
1059 if (parameterMap.isLocked())
1060 return parameterMap;
1061
1062 Enumeration enumeration = getParameterNames();
1063 while (enumeration.hasMoreElements()) {
1064 String name = enumeration.nextElement().toString();
1065 String[] values = getParameterValues(name);
1066 parameterMap.put(name, values);
1067 }
1068
1069 parameterMap.setLocked(true);
1070
1071 return parameterMap;
1072
1073 }
1074
1075
1076 /**
1077 * Return the names of all defined request parameters for this request.
1078 */
1079 public Enumeration getParameterNames() {
1080
1081 if (!parametersParsed)
1082 parseParameters();
1083
1084 return coyoteRequest.getParameters().getParameterNames();
1085
1086 }
1087
1088
1089 /**
1090 * Return the defined values for the specified request parameter, if any;
1091 * otherwise, return <code>null</code>.
1092 *
1093 * @param name Name of the desired request parameter
1094 */
1095 public String[] getParameterValues(String name) {
1096
1097 if (!parametersParsed)
1098 parseParameters();
1099
1100 return coyoteRequest.getParameters().getParameterValues(name);
1101
1102 }
1103
1104
1105 /**
1106 * Return the protocol and version used to make this Request.
1107 */
1108 public String getProtocol() {
1109 return coyoteRequest.protocol().toString();
1110 }
1111
1112
1113 /**
1114 * Read the Reader wrapping the input stream for this Request. The
1115 * default implementation wraps a <code>BufferedReader</code> around the
1116 * servlet input stream returned by <code>createInputStream()</code>.
1117 *
1118 * @exception IllegalStateException if <code>getInputStream()</code>
1119 * has already been called for this request
1120 * @exception IOException if an input/output error occurs
1121 */
1122 public BufferedReader getReader() throws IOException {
1123
1124 if (usingInputStream)
1125 throw new IllegalStateException
1126 (sm.getString("coyoteRequest.getReader.ise"));
1127
1128 usingReader = true;
1129 inputBuffer.checkConverter();
1130 if (reader == null) {
1131 reader = new CoyoteReader(inputBuffer);
1132 }
1133 return reader;
1134
1135 }
1136
1137
1138 /**
1139 * Return the real path of the specified virtual path.
1140 *
1141 * @param path Path to be translated
1142 *
1143 * @deprecated As of version 2.1 of the Java Servlet API, use
1144 * <code>ServletContext.getRealPath()</code>.
1145 */
1146 public String getRealPath(String path) {
1147
1148 if (context == null)
1149 return (null);
1150 ServletContext servletContext = context.getServletContext();
1151 if (servletContext == null)
1152 return (null);
1153 else {
1154 try {
1155 return (servletContext.getRealPath(path));
1156 } catch (IllegalArgumentException e) {
1157 return (null);
1158 }
1159 }
1160
1161 }
1162
1163
1164 /**
1165 * Return the remote IP address making this Request.
1166 */
1167 public String getRemoteAddr() {
1168 if (remoteAddr == null) {
1169 coyoteRequest.action
1170 (ActionCode.ACTION_REQ_HOST_ADDR_ATTRIBUTE, coyoteRequest);
1171 remoteAddr = coyoteRequest.remoteAddr().toString();
1172 }
1173 return remoteAddr;
1174 }
1175
1176
1177 /**
1178 * Return the remote host name making this Request.
1179 */
1180 public String getRemoteHost() {
1181 if (remoteHost == null) {
1182 if (!connector.getEnableLookups()) {
1183 remoteHost = getRemoteAddr();
1184 } else {
1185 coyoteRequest.action
1186 (ActionCode.ACTION_REQ_HOST_ATTRIBUTE, coyoteRequest);
1187 remoteHost = coyoteRequest.remoteHost().toString();
1188 }
1189 }
1190 return remoteHost;
1191 }
1192
1193 /**
1194 * Returns the Internet Protocol (IP) source port of the client
1195 * or last proxy that sent the request.
1196 */
1197 public int getRemotePort(){
1198 if (remotePort == -1) {
1199 coyoteRequest.action
1200 (ActionCode.ACTION_REQ_REMOTEPORT_ATTRIBUTE, coyoteRequest);
1201 remotePort = coyoteRequest.getRemotePort();
1202 }
1203 return remotePort;
1204 }
1205
1206 /**
1207 * Returns the host name of the Internet Protocol (IP) interface on
1208 * which the request was received.
1209 */
1210 public String getLocalName(){
1211 if (localName == null) {
1212 coyoteRequest.action
1213 (ActionCode.ACTION_REQ_LOCAL_NAME_ATTRIBUTE, coyoteRequest);
1214 localName = coyoteRequest.localName().toString();
1215 }
1216 return localName;
1217 }
1218
1219 /**
1220 * Returns the Internet Protocol (IP) address of the interface on
1221 * which the request was received.
1222 */
1223 public String getLocalAddr(){
1224 if (localAddr == null) {
1225 coyoteRequest.action
1226 (ActionCode.ACTION_REQ_LOCAL_ADDR_ATTRIBUTE, coyoteRequest);
1227 localAddr = coyoteRequest.localAddr().toString();
1228 }
1229 return localAddr;
1230 }
1231
1232
1233 /**
1234 * Returns the Internet Protocol (IP) port number of the interface
1235 * on which the request was received.
1236 */
1237 public int getLocalPort(){
1238 if (localPort == -1){
1239 coyoteRequest.action
1240 (ActionCode.ACTION_REQ_LOCALPORT_ATTRIBUTE, coyoteRequest);
1241 localPort = coyoteRequest.getLocalPort();
1242 }
1243 return localPort;
1244 }
1245
1246 /**
1247 * Return a RequestDispatcher that wraps the resource at the specified
1248 * path, which may be interpreted as relative to the current request path.
1249 *
1250 * @param path Path of the resource to be wrapped
1251 */
1252 public RequestDispatcher getRequestDispatcher(String path) {
1253
1254 if (context == null)
1255 return (null);
1256
1257 // If the path is already context-relative, just pass it through
1258 if (path == null)
1259 return (null);
1260 else if (path.startsWith("/"))
1261 return (context.getServletContext().getRequestDispatcher(path));
1262
1263 // Convert a request-relative path to a context-relative one
1264 String servletPath = (String) getAttribute(Globals.INCLUDE_SERVLET_PATH_ATTR);
1265 if (servletPath == null)
1266 servletPath = getServletPath();
1267
1268 // Add the path info, if there is any
1269 String pathInfo = getPathInfo();
1270 String requestPath = null;
1271
1272 if (pathInfo == null) {
1273 requestPath = servletPath;
1274 } else {
1275 requestPath = servletPath + pathInfo;
1276 }
1277
1278 int pos = requestPath.lastIndexOf('/');
1279 String relative = null;
1280 if (pos >= 0) {
1281 relative = RequestUtil.normalize
1282 (requestPath.substring(0, pos + 1) + path);
1283 } else {
1284 relative = RequestUtil.normalize(requestPath + path);
1285 }
1286
1287 return (context.getServletContext().getRequestDispatcher(relative));
1288
1289 }
1290
1291
1292 /**
1293 * Return the scheme used to make this Request.
1294 */
1295 public String getScheme() {
1296 return (coyoteRequest.scheme().toString());
1297 }
1298
1299
1300 /**
1301 * Return the server name responding to this Request.
1302 */
1303 public String getServerName() {
1304 return (coyoteRequest.serverName().toString());
1305 }
1306
1307
1308 /**
1309 * Return the server port responding to this Request.
1310 */
1311 public int getServerPort() {
1312 return (coyoteRequest.getServerPort());
1313 }
1314
1315
1316 /**
1317 * Was this request received on a secure connection?
1318 */
1319 public boolean isSecure() {
1320 return (secure);
1321 }
1322
1323
1324 /**
1325 * Remove the specified request attribute if it exists.
1326 *
1327 * @param name Name of the request attribute to remove
1328 */
1329 public void removeAttribute(String name) {
1330 Object value = null;
1331 boolean found = false;
1332
1333 // Remove the specified attribute
1334 // Check for read only attribute
1335 // requests are per thread so synchronization unnecessary
1336 if (readOnlyAttributes.containsKey(name)) {
1337 return;
1338 }
1339
1340 // Pass special attributes to the native layer
1341 if (name.startsWith("org.apache.tomcat.")) {
1342 coyoteRequest.getAttributes().remove(name);
1343 }
1344
1345 found = attributes.containsKey(name);
1346 if (found) {
1347 value = attributes.get(name);
1348 attributes.remove(name);
1349 } else {
1350 return;
1351 }
1352
1353 // Notify interested application event listeners
1354 Object listeners[] = context.getApplicationEventListeners();
1355 if ((listeners == null) || (listeners.length == 0))
1356 return;
1357 ServletRequestAttributeEvent event =
1358 new ServletRequestAttributeEvent(context.getServletContext(),
1359 getRequest(), name, value);
1360 for (int i = 0; i < listeners.length; i++) {
1361 if (!(listeners[i] instanceof ServletRequestAttributeListener))
1362 continue;
1363 ServletRequestAttributeListener listener =
1364 (ServletRequestAttributeListener) listeners[i];
1365 try {
1366 listener.attributeRemoved(event);
1367 } catch (Throwable t) {
1368 context.getLogger().error(sm.getString("coyoteRequest.attributeEvent"), t);
1369 // Error valve will pick this execption up and display it to user
1370 attributes.put( Globals.EXCEPTION_ATTR, t );
1371 }
1372 }
1373 }
1374
1375
1376 /**
1377 * Set the specified request attribute to the specified value.
1378 *
1379 * @param name Name of the request attribute to set
1380 * @param value The associated value
1381 */
1382 public void setAttribute(String name, Object value) {
1383
1384 // Name cannot be null
1385 if (name == null)
1386 throw new IllegalArgumentException
1387 (sm.getString("coyoteRequest.setAttribute.namenull"));
1388
1389 // Null value is the same as removeAttribute()
1390 if (value == null) {
1391 removeAttribute(name);
1392 return;
1393 }
1394
1395 if (name.equals(Globals.DISPATCHER_TYPE_ATTR)) {
1396 dispatcherType = value;
1397 return;
1398 } else if (name.equals(Globals.DISPATCHER_REQUEST_PATH_ATTR)) {
1399 requestDispatcherPath = value;
1400 return;
1401 }
1402
1403 Object oldValue = null;
1404 boolean replaced = false;
1405
1406 // Add or replace the specified attribute
1407 // Check for read only attribute
1408 // requests are per thread so synchronization unnecessary
1409 if (readOnlyAttributes.containsKey(name)) {
1410 return;
1411 }
1412
1413 oldValue = attributes.put(name, value);
1414 if (oldValue != null) {
1415 replaced = true;
1416 }
1417
1418 // Pass special attributes to the native layer
1419 if (name.startsWith("org.apache.tomcat.")) {
1420 coyoteRequest.setAttribute(name, value);
1421 }
1422
1423 // Notify interested application event listeners
1424 Object listeners[] = context.getApplicationEventListeners();
1425 if ((listeners == null) || (listeners.length == 0))
1426 return;
1427 ServletRequestAttributeEvent event = null;
1428 if (replaced)
1429 event =
1430 new ServletRequestAttributeEvent(context.getServletContext(),
1431 getRequest(), name, oldValue);
1432 else
1433 event =
1434 new ServletRequestAttributeEvent(context.getServletContext(),
1435 getRequest(), name, value);
1436
1437 for (int i = 0; i < listeners.length; i++) {
1438 if (!(listeners[i] instanceof ServletRequestAttributeListener))
1439 continue;
1440 ServletRequestAttributeListener listener =
1441 (ServletRequestAttributeListener) listeners[i];
1442 try {
1443 if (replaced) {
1444 listener.attributeReplaced(event);
1445 } else {
1446 listener.attributeAdded(event);
1447 }
1448 } catch (Throwable t) {
1449 context.getLogger().error(sm.getString("coyoteRequest.attributeEvent"), t);
1450 // Error valve will pick this execption up and display it to user
1451 attributes.put( Globals.EXCEPTION_ATTR, t );
1452 }
1453 }
1454 }
1455
1456
1457 /**
1458 * Overrides the name of the character encoding used in the body of
1459 * this request. This method must be called prior to reading request
1460 * parameters or reading input using <code>getReader()</code>.
1461 *
1462 * @param enc The character encoding to be used
1463 *
1464 * @exception UnsupportedEncodingException if the specified encoding
1465 * is not supported
1466 *
1467 * @since Servlet 2.3
1468 */
1469 public void setCharacterEncoding(String enc)
1470 throws UnsupportedEncodingException {
1471
1472 if (usingReader)
1473 return;
1474
1475 // Ensure that the specified encoding is valid
1476 byte buffer[] = new byte[1];
1477 buffer[0] = (byte) 'a';
1478 String dummy = new String(buffer, enc);
1479
1480 // Save the validated encoding
1481 coyoteRequest.setCharacterEncoding(enc);
1482
1483 }
1484
1485
1486 // ---------------------------------------------------- HttpRequest Methods
1487
1488
1489 /**
1490 * Add a Cookie to the set of Cookies associated with this Request.
1491 *
1492 * @param cookie The new cookie
1493 */
1494 public void addCookie(Cookie cookie) {
1495
1496 if (!cookiesParsed)
1497 parseCookies();
1498
1499 int size = 0;
1500 if (cookies != null) {
1501 size = cookies.length;
1502 }
1503
1504 Cookie[] newCookies = new Cookie[size + 1];
1505 for (int i = 0; i < size; i++) {
1506 newCookies[i] = cookies[i];
1507 }
1508 newCookies[size] = cookie;
1509
1510 cookies = newCookies;
1511
1512 }
1513
1514
1515 /**
1516 * Add a Header to the set of Headers associated with this Request.
1517 *
1518 * @param name The new header name
1519 * @param value The new header value
1520 */
1521 public void addHeader(String name, String value) {
1522 // Not used
1523 }
1524
1525
1526 /**
1527 * Add a Locale to the set of preferred Locales for this Request. The
1528 * first added Locale will be the first one returned by getLocales().
1529 *
1530 * @param locale The new preferred Locale
1531 */
1532 public void addLocale(Locale locale) {
1533 locales.add(locale);
1534 }
1535
1536
1537 /**
1538 * Add a parameter name and corresponding set of values to this Request.
1539 * (This is used when restoring the original request on a form based
1540 * login).
1541 *
1542 * @param name Name of this request parameter
1543 * @param values Corresponding values for this request parameter
1544 */
1545 public void addParameter(String name, String values[]) {
1546 coyoteRequest.getParameters().addParameterValues(name, values);
1547 }
1548
1549
1550 /**
1551 * Clear the collection of Cookies associated with this Request.
1552 */
1553 public void clearCookies() {
1554 cookiesParsed = true;
1555 cookies = null;
1556 }
1557
1558
1559 /**
1560 * Clear the collection of Headers associated with this Request.
1561 */
1562 public void clearHeaders() {
1563 // Not used
1564 }
1565
1566
1567 /**
1568 * Clear the collection of Locales associated with this Request.
1569 */
1570 public void clearLocales() {
1571 locales.clear();
1572 }
1573
1574
1575 /**
1576 * Clear the collection of parameters associated with this Request.
1577 */
1578 public void clearParameters() {
1579 // Not used
1580 }
1581
1582
1583 /**
1584 * Set the authentication type used for this request, if any; otherwise
1585 * set the type to <code>null</code>. Typical values are "BASIC",
1586 * "DIGEST", or "SSL".
1587 *
1588 * @param type The authentication type used
1589 */
1590 public void setAuthType(String type) {
1591 this.authType = type;
1592 }
1593
1594
1595 /**
1596 * Set the context path for this Request. This will normally be called
1597 * when the associated Context is mapping the Request to a particular
1598 * Wrapper.
1599 *
1600 * @param path The context path
1601 */
1602 public void setContextPath(String path) {
1603
1604 if (path == null) {
1605 mappingData.contextPath.setString("");
1606 } else {
1607 mappingData.contextPath.setString(path);
1608 }
1609
1610 }
1611
1612
1613 /**
1614 * Set the HTTP request method used for this Request.
1615 *
1616 * @param method The request method
1617 */
1618 public void setMethod(String method) {
1619 // Not used
1620 }
1621
1622
1623 /**
1624 * Set the query string for this Request. This will normally be called
1625 * by the HTTP Connector, when it parses the request headers.
1626 *
1627 * @param query The query string
1628 */
1629 public void setQueryString(String query) {
1630 // Not used
1631 }
1632
1633
1634 /**
1635 * Set the path information for this Request. This will normally be called
1636 * when the associated Context is mapping the Request to a particular
1637 * Wrapper.
1638 *
1639 * @param path The path information
1640 */
1641 public void setPathInfo(String path) {
1642 mappingData.pathInfo.setString(path);
1643 }
1644
1645
1646 /**
1647 * Set a flag indicating whether or not the requested session ID for this
1648 * request came in through a cookie. This is normally called by the
1649 * HTTP Connector, when it parses the request headers.
1650 *
1651 * @param flag The new flag
1652 */
1653 public void setRequestedSessionCookie(boolean flag) {
1654
1655 this.requestedSessionCookie = flag;
1656
1657 }
1658
1659
1660 /**
1661 * Set the requested session ID for this request. This is normally called
1662 * by the HTTP Connector, when it parses the request headers.
1663 *
1664 * @param id The new session id
1665 */
1666 public void setRequestedSessionId(String id) {
1667
1668 this.requestedSessionId = id;
1669
1670 }
1671
1672
1673 /**
1674 * Set a flag indicating whether or not the requested session ID for this
1675 * request came in through a URL. This is normally called by the
1676 * HTTP Connector, when it parses the request headers.
1677 *
1678 * @param flag The new flag
1679 */
1680 public void setRequestedSessionURL(boolean flag) {
1681
1682 this.requestedSessionURL = flag;
1683
1684 }
1685
1686
1687 /**
1688 * Set the unparsed request URI for this Request. This will normally be
1689 * called by the HTTP Connector, when it parses the request headers.
1690 *
1691 * @param uri The request URI
1692 */
1693 public void setRequestURI(String uri) {
1694 // Not used
1695 }
1696
1697
1698 /**
1699 * Set the decoded request URI.
1700 *
1701 * @param uri The decoded request URI
1702 */
1703 public void setDecodedRequestURI(String uri) {
1704 // Not used
1705 }
1706
1707
1708 /**
1709 * Get the decoded request URI.
1710 *
1711 * @return the URL decoded request URI
1712 */
1713 public String getDecodedRequestURI() {
1714 return (coyoteRequest.decodedURI().toString());
1715 }
1716
1717
1718 /**
1719 * Get the decoded request URI.
1720 *
1721 * @return the URL decoded request URI
1722 */
1723 public MessageBytes getDecodedRequestURIMB() {
1724 return (coyoteRequest.decodedURI());
1725 }
1726
1727
1728 /**
1729 * Set the servlet path for this Request. This will normally be called
1730 * when the associated Context is mapping the Request to a particular
1731 * Wrapper.
1732 *
1733 * @param path The servlet path
1734 */
1735 public void setServletPath(String path) {
1736 if (path != null)
1737 mappingData.wrapperPath.setString(path);
1738 }
1739
1740
1741 /**
1742 * Set the Principal who has been authenticated for this Request. This
1743 * value is also used to calculate the value to be returned by the
1744 * <code>getRemoteUser()</code> method.
1745 *
1746 * @param principal The user Principal
1747 */
1748 public void setUserPrincipal(Principal principal) {
1749
1750 if (Globals.IS_SECURITY_ENABLED){
1751 HttpSession session = getSession(false);
1752 if ( (subject != null) &&
1753 (!subject.getPrincipals().contains(principal)) ){
1754 subject.getPrincipals().add(principal);
1755 } else if (session != null &&
1756 session.getAttribute(Globals.SUBJECT_ATTR) == null) {
1757 subject = new Subject();
1758 subject.getPrincipals().add(principal);
1759 }
1760 if (session != null){
1761 session.setAttribute(Globals.SUBJECT_ATTR, subject);
1762 }
1763 }
1764
1765 this.userPrincipal = principal;
1766 }
1767
1768
1769 // --------------------------------------------- HttpServletRequest Methods
1770
1771
1772 /**
1773 * Return the authentication type used for this Request.
1774 */
1775 public String getAuthType() {
1776 return (authType);
1777 }
1778
1779
1780 /**
1781 * Return the portion of the request URI used to select the Context
1782 * of the Request.
1783 */
1784 public String getContextPath() {
1785 return (mappingData.contextPath.toString());
1786 }
1787
1788
1789 /**
1790 * Get the context path.
1791 *
1792 * @return the context path
1793 */
1794 public MessageBytes getContextPathMB() {
1795 return (mappingData.contextPath);
1796 }
1797
1798
1799 /**
1800 * Return the set of Cookies received with this Request.
1801 */
1802 public Cookie[] getCookies() {
1803
1804 if (!cookiesParsed)
1805 parseCookies();
1806
1807 return cookies;
1808
1809 }
1810
1811
1812 /**
1813 * Set the set of cookies recieved with this Request.
1814 */
1815 public void setCookies(Cookie[] cookies) {
1816
1817 this.cookies = cookies;
1818
1819 }
1820
1821
1822 /**
1823 * Return the value of the specified date header, if any; otherwise
1824 * return -1.
1825 *
1826 * @param name Name of the requested date header
1827 *
1828 * @exception IllegalArgumentException if the specified header value
1829 * cannot be converted to a date
1830 */
1831 public long getDateHeader(String name) {
1832
1833 String value = getHeader(name);
1834 if (value == null)
1835 return (-1L);
1836
1837 // Attempt to convert the date header in a variety of formats
1838 long result = FastHttpDateFormat.parseDate(value, formats);
1839 if (result != (-1L)) {
1840 return result;
1841 }
1842 throw new IllegalArgumentException(value);
1843
1844 }
1845
1846
1847 /**
1848 * Return the first value of the specified header, if any; otherwise,
1849 * return <code>null</code>
1850 *
1851 * @param name Name of the requested header
1852 */
1853 public String getHeader(String name) {
1854 return coyoteRequest.getHeader(name);
1855 }
1856
1857
1858 /**
1859 * Return all of the values of the specified header, if any; otherwise,
1860 * return an empty enumeration.
1861 *
1862 * @param name Name of the requested header
1863 */
1864 public Enumeration getHeaders(String name) {
1865 return coyoteRequest.getMimeHeaders().values(name);
1866 }
1867
1868
1869 /**
1870 * Return the names of all headers received with this request.
1871 */
1872 public Enumeration getHeaderNames() {
1873 return coyoteRequest.getMimeHeaders().names();
1874 }
1875
1876
1877 /**
1878 * Return the value of the specified header as an integer, or -1 if there
1879 * is no such header for this request.
1880 *
1881 * @param name Name of the requested header
1882 *
1883 * @exception IllegalArgumentException if the specified header value
1884 * cannot be converted to an integer
1885 */
1886 public int getIntHeader(String name) {
1887
1888 String value = getHeader(name);
1889 if (value == null) {
1890 return (-1);
1891 } else {
1892 return (Integer.parseInt(value));
1893 }
1894
1895 }
1896
1897
1898 /**
1899 * Return the HTTP request method used in this Request.
1900 */
1901 public String getMethod() {
1902 return coyoteRequest.method().toString();
1903 }
1904
1905
1906 /**
1907 * Return the path information associated with this Request.
1908 */
1909 public String getPathInfo() {
1910 return (mappingData.pathInfo.toString());
1911 }
1912
1913
1914 /**
1915 * Get the path info.
1916 *
1917 * @return the path info
1918 */
1919 public MessageBytes getPathInfoMB() {
1920 return (mappingData.pathInfo);
1921 }
1922
1923
1924 /**
1925 * Return the extra path information for this request, translated
1926 * to a real path.
1927 */
1928 public String getPathTranslated() {
1929
1930 if (context == null)
1931 return (null);
1932
1933 if (getPathInfo() == null) {
1934 return (null);
1935 } else {
1936 return (context.getServletContext().getRealPath(getPathInfo()));
1937 }
1938
1939 }
1940
1941
1942 /**
1943 * Return the query string associated with this request.
1944 */
1945 public String getQueryString() {
1946 String queryString = coyoteRequest.queryString().toString();
1947 if (queryString == null || queryString.equals("")) {
1948 return (null);
1949 } else {
1950 return queryString;
1951 }
1952 }
1953
1954
1955 /**
1956 * Return the name of the remote user that has been authenticated
1957 * for this Request.
1958 */
1959 public String getRemoteUser() {
1960
1961 if (userPrincipal != null) {
1962 return (userPrincipal.getName());
1963 } else {
1964 return (null);
1965 }
1966
1967 }
1968
1969
1970 /**
1971 * Get the request path.
1972 *
1973 * @return the request path
1974 */
1975 public MessageBytes getRequestPathMB() {
1976 return (mappingData.requestPath);
1977 }
1978
1979
1980 /**
1981 * Return the session identifier included in this request, if any.
1982 */
1983 public String getRequestedSessionId() {
1984 return (requestedSessionId);
1985 }
1986
1987
1988 /**
1989 * Return the request URI for this request.
1990 */
1991 public String getRequestURI() {
1992 return coyoteRequest.requestURI().toString();
1993 }
1994
1995
1996 /**
1997 * Reconstructs the URL the client used to make the request.
1998 * The returned URL contains a protocol, server name, port
1999 * number, and server path, but it does not include query
2000 * string parameters.
2001 * <p>
2002 * Because this method returns a <code>StringBuffer</code>,
2003 * not a <code>String</code>, you can modify the URL easily,
2004 * for example, to append query parameters.
2005 * <p>
2006 * This method is useful for creating redirect messages and
2007 * for reporting errors.
2008 *
2009 * @return A <code>StringBuffer</code> object containing the
2010 * reconstructed URL
2011 */
2012 public StringBuffer getRequestURL() {
2013
2014 StringBuffer url = new StringBuffer();
2015 String scheme = getScheme();
2016 int port = getServerPort();
2017 if (port < 0)
2018 port = 80; // Work around java.net.URL bug
2019
2020 url.append(scheme);
2021 url.append("://");
2022 url.append(getServerName());
2023 if ((scheme.equals("http") && (port != 80))
2024 || (scheme.equals("https") && (port != 443))) {
2025 url.append(':');
2026 url.append(port);
2027 }
2028 url.append(getRequestURI());
2029
2030 return (url);
2031
2032 }
2033
2034
2035 /**
2036 * Return the portion of the request URI used to select the servlet
2037 * that will process this request.
2038 */
2039 public String getServletPath() {
2040 return (mappingData.wrapperPath.toString());
2041 }
2042
2043
2044 /**
2045 * Get the servlet path.
2046 *
2047 * @return the servlet path
2048 */
2049 public MessageBytes getServletPathMB() {
2050 return (mappingData.wrapperPath);
2051 }
2052
2053
2054 /**
2055 * Return the session associated with this Request, creating one
2056 * if necessary.
2057 */
2058 public HttpSession getSession() {
2059 Session session = doGetSession(true);
2060 if (session != null) {
2061 return session.getSession();
2062 } else {
2063 return null;
2064 }
2065 }
2066
2067
2068 /**
2069 * Return the session associated with this Request, creating one
2070 * if necessary and requested.
2071 *
2072 * @param create Create a new session if one does not exist
2073 */
2074 public HttpSession getSession(boolean create) {
2075 Session session = doGetSession(create);
2076 if (session != null) {
2077 return session.getSession();
2078 } else {
2079 return null;
2080 }
2081 }
2082
2083
2084 /**
2085 * Return <code>true</code> if the session identifier included in this
2086 * request came from a cookie.
2087 */
2088 public boolean isRequestedSessionIdFromCookie() {
2089
2090 if (requestedSessionId != null)
2091 return (requestedSessionCookie);
2092 else
2093 return (false);
2094
2095 }
2096
2097
2098 /**
2099 * Return <code>true</code> if the session identifier included in this
2100 * request came from the request URI.
2101 */
2102 public boolean isRequestedSessionIdFromURL() {
2103
2104 if (requestedSessionId != null)
2105 return (requestedSessionURL);
2106 else
2107 return (false);
2108
2109 }
2110
2111
2112 /**
2113 * Return <code>true</code> if the session identifier included in this
2114 * request came from the request URI.
2115 *
2116 * @deprecated As of Version 2.1 of the Java Servlet API, use
2117 * <code>isRequestedSessionIdFromURL()</code> instead.
2118 */
2119 public boolean isRequestedSessionIdFromUrl() {
2120 return (isRequestedSessionIdFromURL());
2121 }
2122
2123
2124 /**
2125 * Return <code>true</code> if the session identifier included in this
2126 * request identifies a valid session.
2127 */
2128 public boolean isRequestedSessionIdValid() {
2129
2130 if (requestedSessionId == null)
2131 return (false);
2132 if (context == null)
2133 return (false);
2134 Manager manager = context.getManager();
2135 if (manager == null)
2136 return (false);
2137 Session session = null;
2138 try {
2139 session = manager.findSession(requestedSessionId);
2140 } catch (IOException e) {
2141 session = null;
2142 }
2143 if ((session != null) && session.isValid())
2144 return (true);
2145 else
2146 return (false);
2147
2148 }
2149
2150
2151 /**
2152 * Return <code>true</code> if the authenticated user principal
2153 * possesses the specified role name.
2154 *
2155 * @param role Role name to be validated
2156 */
2157 public boolean isUserInRole(String role) {
2158
2159 // Have we got an authenticated principal at all?
2160 if (userPrincipal == null)
2161 return (false);
2162
2163 // Identify the Realm we will use for checking role assignmenets
2164 if (context == null)
2165 return (false);
2166 Realm realm = context.getRealm();
2167 if (realm == null)
2168 return (false);
2169
2170 // Check for a role alias defined in a <security-role-ref> element
2171 if (wrapper != null) {
2172 String realRole = wrapper.findSecurityReference(role);
2173 if ((realRole != null) &&
2174 realm.hasRole(userPrincipal, realRole))
2175 return (true);
2176 }
2177
2178 // Check for a role defined directly as a <security-role>
2179 return (realm.hasRole(userPrincipal, role));
2180
2181 }
2182
2183
2184 /**
2185 * Return the principal that has been authenticated for this Request.
2186 */
2187 public Principal getPrincipal() {
2188 return (userPrincipal);
2189 }
2190
2191
2192 /**
2193 * Return the principal that has been authenticated for this Request.
2194 */
2195 public Principal getUserPrincipal() {
2196 if (userPrincipal instanceof GenericPrincipal) {
2197 return ((GenericPrincipal) userPrincipal).getUserPrincipal();
2198 } else {
2199 return (userPrincipal);
2200 }
2201 }
2202
2203
2204 /**
2205 * Return the session associated with this Request, creating one
2206 * if necessary.
2207 */
2208 public Session getSessionInternal() {
2209 return doGetSession(true);
2210 }
2211
2212
2213 /**
2214 * Return the session associated with this Request, creating one
2215 * if necessary and requested.
2216 *
2217 * @param create Create a new session if one does not exist
2218 */
2219 public Session getSessionInternal(boolean create) {
2220 return doGetSession(create);
2221 }
2222
2223
2224 /**
2225 * Get the event associated with the request.
2226 * @return
2227 */
2228 public CometEventImpl getEvent() {
2229 if (event == null) {
2230 event = new CometEventImpl(this, response);
2231 }
2232 return event;
2233 }
2234
2235
2236 /**
2237 * Return true if the current request is handling Comet traffic.
2238 */
2239 public boolean isComet() {
2240 return comet;
2241 }
2242
2243
2244 /**
2245 * Set comet state.
2246 */
2247 public void setComet(boolean comet) {
2248 this.comet = comet;
2249 }
2250
2251
2252 /**
2253 * Return true if bytes are available.
2254 */
2255 public boolean getAvailable() {
2256 return (inputBuffer.available() > 0);
2257 }
2258
2259
2260 // ------------------------------------------------------ Protected Methods
2261
2262
2263 protected Session doGetSession(boolean create) {
2264
2265 // There cannot be a session if no context has been assigned yet
2266 if (context == null)
2267 return (null);
2268
2269 // Return the current session if it exists and is valid
2270 if ((session != null) && !session.isValid())
2271 session = null;
2272 if (session != null)
2273 return (session);
2274
2275 // Return the requested session if it exists and is valid
2276 Manager manager = null;
2277 if (context != null)
2278 manager = context.getManager();
2279 if (manager == null)
2280 return (null); // Sessions are not supported
2281 if (requestedSessionId != null) {
2282 try {
2283 session = manager.findSession(requestedSessionId);
2284 } catch (IOException e) {
2285 session = null;
2286 }
2287 if ((session != null) && !session.isValid())
2288 session = null;
2289 if (session != null) {
2290 session.access();
2291 return (session);
2292 }
2293 }
2294
2295 // Create a new session if requested and the response is not committed
2296 if (!create)
2297 return (null);
2298 if ((context != null) && (response != null) &&
2299 context.getCookies() &&
2300 response.getResponse().isCommitted()) {
2301 throw new IllegalStateException
2302 (sm.getString("coyoteRequest.sessionCreateCommitted"));
2303 }
2304
2305 // Attempt to reuse session id if one was submitted in a cookie
2306 // Do not reuse the session id if it is from a URL, to prevent possible
2307 // phishing attacks
2308 if (connector.getEmptySessionPath()
2309 && isRequestedSessionIdFromCookie()) {
2310 session = manager.createSession(getRequestedSessionId());
2311 } else {
2312 session = manager.createSession(null);
2313 }
2314
2315 // Creating a new session cookie based on that session
2316 if ((session != null) && (getContext() != null)
2317 && getContext().getCookies()) {
2318 Cookie cookie = new Cookie(Globals.SESSION_COOKIE_NAME,
2319 session.getIdInternal());
2320 configureSessionCookie(cookie);
2321 response.addCookieInternal(cookie);
2322 }
2323
2324 if (session != null) {
2325 session.access();
2326 return (session);
2327 } else {
2328 return (null);
2329 }
2330
2331 }
2332
2333 /**
2334 * Configures the given JSESSIONID cookie.
2335 *
2336 * @param cookie The JSESSIONID cookie to be configured
2337 */
2338 protected void configureSessionCookie(Cookie cookie) {
2339 cookie.setMaxAge(-1);
2340 String contextPath = null;
2341 if (!connector.getEmptySessionPath() && (getContext() != null)) {
2342 contextPath = getContext().getEncodedPath();
2343 }
2344 if ((contextPath != null) && (contextPath.length() > 0)) {
2345 cookie.setPath(contextPath);
2346 } else {
2347 cookie.setPath("/");
2348 }
2349 if (isSecure()) {
2350 cookie.setSecure(true);
2351 }
2352 }
2353
2354 protected String unescape(String s) {
2355 if (s==null) return null;
2356 if (s.indexOf('\\') == -1) return s;
2357 StringBuffer buf = new StringBuffer();
2358 for (int i=0; i<s.length(); i++) {
2359 char c = s.charAt(i);
2360 if (c!='\\') buf.append(c);
2361 else {
2362 if (++i >= s.length()) throw new IllegalArgumentException();//invalid escape, hence invalid cookie
2363 c = s.charAt(i);
2364 buf.append(c);
2365 }
2366 }
2367 return buf.toString();
2368 }
2369
2370 /**
2371 * Parse cookies.
2372 */
2373 protected void parseCookies() {
2374
2375 cookiesParsed = true;
2376
2377 Cookies serverCookies = coyoteRequest.getCookies();
2378 int count = serverCookies.getCookieCount();
2379 if (count <= 0)
2380 return;
2381
2382 cookies = new Cookie[count];
2383
2384 int idx=0;
2385 for (int i = 0; i < count; i++) {
2386 ServerCookie scookie = serverCookies.getCookie(i);
2387 try {
2388 /*
2389 we must unescape the '\\' escape character
2390 */
2391 Cookie cookie = new Cookie(scookie.getName().toString(),null);
2392 int version = scookie.getVersion();
2393 cookie.setVersion(version);
2394 cookie.setValue(unescape(scookie.getValue().toString()));
2395 cookie.setPath(unescape(scookie.getPath().toString()));
2396 String domain = scookie.getDomain().toString();
2397 if (domain!=null) cookie.setDomain(unescape(domain));//avoid NPE
2398 String comment = scookie.getComment().toString();
2399 cookie.setComment(version==1?unescape(comment):null);
2400 cookies[idx++] = cookie;
2401 } catch(IllegalArgumentException e) {
2402 // Ignore bad cookie
2403 }
2404 }
2405 if( idx < count ) {
2406 Cookie [] ncookies = new Cookie[idx];
2407 System.arraycopy(cookies, 0, ncookies, 0, idx);
2408 cookies = ncookies;
2409 }
2410
2411 }
2412
2413 /**
2414 * Parse request parameters.
2415 */
2416 protected void parseParameters() {
2417
2418 parametersParsed = true;
2419
2420 Parameters parameters = coyoteRequest.getParameters();
2421
2422 // getCharacterEncoding() may have been overridden to search for
2423 // hidden form field containing request encoding
2424 String enc = getCharacterEncoding();
2425
2426 boolean useBodyEncodingForURI = connector.getUseBodyEncodingForURI();
2427 if (enc != null) {
2428 parameters.setEncoding(enc);
2429 if (useBodyEncodingForURI) {
2430 parameters.setQueryStringEncoding(enc);
2431 }
2432 } else {
2433 parameters.setEncoding
2434 (org.apache.coyote.Constants.DEFAULT_CHARACTER_ENCODING);
2435 if (useBodyEncodingForURI) {
2436 parameters.setQueryStringEncoding
2437 (org.apache.coyote.Constants.DEFAULT_CHARACTER_ENCODING);
2438 }
2439 }
2440
2441 parameters.handleQueryParameters();
2442
2443 if (usingInputStream || usingReader)
2444 return;
2445
2446 if (!getMethod().equalsIgnoreCase("POST"))
2447 return;
2448
2449 String contentType = getContentType();
2450 if (contentType == null)
2451 contentType = "";
2452 int semicolon = contentType.indexOf(';');
2453 if (semicolon >= 0) {
2454 contentType = contentType.substring(0, semicolon).trim();
2455 } else {
2456 contentType = contentType.trim();
2457 }
2458 if (!("application/x-www-form-urlencoded".equals(contentType)))
2459 return;
2460
2461 int len = getContentLength();
2462
2463 if (len > 0) {
2464 int maxPostSize = connector.getMaxPostSize();
2465 if ((maxPostSize > 0) && (len > maxPostSize)) {
2466 if (context.getLogger().isDebugEnabled()) {
2467 context.getLogger().debug("Post too large");
2468 }
2469 return;
2470 }
2471 byte[] formData = null;
2472 if (len < CACHED_POST_LEN) {
2473 if (postData == null)
2474 postData = new byte[CACHED_POST_LEN];
2475 formData = postData;
2476 } else {
2477 formData = new byte[len];
2478 }
2479 try {
2480 if (readPostBody(formData, len) != len) {
2481 return;
2482 }
2483 } catch (IOException e) {
2484 // Client disconnect
2485 if (context.getLogger().isDebugEnabled()) {
2486 context.getLogger().debug(
2487 sm.getString("coyoteRequest.parseParameters"), e);
2488 }
2489 return;
2490 }
2491 parameters.processParameters(formData, 0, len);
2492 }
2493
2494 }
2495
2496
2497 /**
2498 * Read post body in an array.
2499 */
2500 protected int readPostBody(byte body[], int len)
2501 throws IOException {
2502
2503 int offset = 0;
2504 do {
2505 int inputLen = getStream().read(body, offset, len - offset);
2506 if (inputLen <= 0) {
2507 return offset;
2508 }
2509 offset += inputLen;
2510 } while ((len - offset) > 0);
2511 return len;
2512
2513 }
2514
2515
2516 /**
2517 * Parse request locales.
2518 */
2519 protected void parseLocales() {
2520
2521 localesParsed = true;
2522
2523 Enumeration values = getHeaders("accept-language");
2524
2525 while (values.hasMoreElements()) {
2526 String value = values.nextElement().toString();
2527 parseLocalesHeader(value);
2528 }
2529
2530 }
2531
2532
2533 /**
2534 * Parse accept-language header value.
2535 */
2536 protected void parseLocalesHeader(String value) {
2537
2538 // Store the accumulated languages that have been requested in
2539 // a local collection, sorted by the quality value (so we can
2540 // add Locales in descending order). The values will be ArrayLists
2541 // containing the corresponding Locales to be added
2542 TreeMap locales = new TreeMap();
2543
2544 // Preprocess the value to remove all whitespace
2545 int white = value.indexOf(' ');
2546 if (white < 0)
2547 white = value.indexOf('\t');
2548 if (white >= 0) {
2549 StringBuffer sb = new StringBuffer();
2550 int len = value.length();
2551 for (int i = 0; i < len; i++) {
2552 char ch = value.charAt(i);
2553 if ((ch != ' ') && (ch != '\t'))
2554 sb.append(ch);
2555 }
2556 value = sb.toString();
2557 }
2558
2559 // Process each comma-delimited language specification
2560 parser.setString(value); // ASSERT: parser is available to us
2561 int length = parser.getLength();
2562 while (true) {
2563
2564 // Extract the next comma-delimited entry
2565 int start = parser.getIndex();
2566 if (start >= length)
2567 break;
2568 int end = parser.findChar(',');
2569 String entry = parser.extract(start, end).trim();
2570 parser.advance(); // For the following entry
2571
2572 // Extract the quality factor for this entry
2573 double quality = 1.0;
2574 int semi = entry.indexOf(";q=");
2575 if (semi >= 0) {
2576 try {
2577 quality = Double.parseDouble(entry.substring(semi + 3));
2578 } catch (NumberFormatException e) {
2579 quality = 0.0;
2580 }
2581 entry = entry.substring(0, semi);
2582 }
2583
2584 // Skip entries we are not going to keep track of
2585 if (quality < 0.00005)
2586 continue; // Zero (or effectively zero) quality factors
2587 if ("*".equals(entry))
2588 continue; // FIXME - "*" entries are not handled
2589
2590 // Extract the language and country for this entry
2591 String language = null;
2592 String country = null;
2593 String variant = null;
2594 int dash = entry.indexOf('-');
2595 if (dash < 0) {
2596 language = entry;
2597 country = "";
2598 variant = "";
2599 } else {
2600 language = entry.substring(0, dash);
2601 country = entry.substring(dash + 1);
2602 int vDash = country.indexOf('-');
2603 if (vDash > 0) {
2604 String cTemp = country.substring(0, vDash);
2605 variant = country.substring(vDash + 1);
2606 country = cTemp;
2607 } else {
2608 variant = "";
2609 }
2610 }
2611 if (!isAlpha(language) || !isAlpha(country) || !isAlpha(variant)) {
2612 continue;
2613 }
2614
2615 // Add a new Locale to the list of Locales for this quality level
2616 Locale locale = new Locale(language, country, variant);
2617 Double key = new Double(-quality); // Reverse the order
2618 ArrayList values = (ArrayList) locales.get(key);
2619 if (values == null) {
2620 values = new ArrayList();
2621 locales.put(key, values);
2622 }
2623 values.add(locale);
2624
2625 }
2626
2627 // Process the quality values in highest->lowest order (due to
2628 // negating the Double value when creating the key)
2629 Iterator keys = locales.keySet().iterator();
2630 while (keys.hasNext()) {
2631 Double key = (Double) keys.next();
2632 ArrayList list = (ArrayList) locales.get(key);
2633 Iterator values = list.iterator();
2634 while (values.hasNext()) {
2635 Locale locale = (Locale) values.next();
2636 addLocale(locale);
2637 }
2638 }
2639
2640 }
2641
2642
2643 protected static final boolean isAlpha(String value) {
2644 for (int i = 0; i < value.length(); i++) {
2645 char c = value.charAt(i);
2646 if (!((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z'))) {
2647 return false;
2648 }
2649 }
2650 return true;
2651 }
2652
2653 }