KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > mortbay > http > HttpRequest


1 // ========================================================================
2
// $Id: HttpRequest.java,v 1.90 2005/12/21 23:14:38 gregwilkins Exp $
3
// Copyright 1996-2004 Mort Bay Consulting Pty. Ltd.
4
// ------------------------------------------------------------------------
5
// Licensed under the Apache License, Version 2.0 (the "License");
6
// you may not use this file except in compliance with the License.
7
// You may obtain a copy of the License at
8
// http://www.apache.org/licenses/LICENSE-2.0
9
// Unless required by applicable law or agreed to in writing, software
10
// distributed under the License is distributed on an "AS IS" BASIS,
11
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
// See the License for the specific language governing permissions and
13
// limitations under the License.
14
// ========================================================================
15

16 package org.mortbay.http;
17
18 import java.io.IOException JavaDoc;
19 import java.io.InputStream JavaDoc;
20 import java.io.Writer JavaDoc;
21 import java.net.InetAddress JavaDoc;
22 import java.security.Principal JavaDoc;
23 import java.util.Collections JavaDoc;
24 import java.util.Enumeration JavaDoc;
25 import java.util.List JavaDoc;
26 import java.util.ListIterator JavaDoc;
27 import java.util.Map JavaDoc;
28 import java.util.Set JavaDoc;
29
30 import javax.print.URIException JavaDoc;
31 import javax.servlet.http.Cookie JavaDoc;
32
33 import org.apache.commons.logging.Log;
34 import org.mortbay.log.LogFactory;
35 import org.mortbay.util.ByteArrayOutputStream2;
36 import org.mortbay.util.IO;
37 import org.mortbay.util.InetAddrPort;
38 import org.mortbay.util.LazyList;
39 import org.mortbay.util.LineInput;
40 import org.mortbay.util.LogSupport;
41 import org.mortbay.util.MultiMap;
42 import org.mortbay.util.QuotedStringTokenizer;
43 import org.mortbay.util.StringMap;
44 import org.mortbay.util.StringUtil;
45 import org.mortbay.util.TypeUtil;
46 import org.mortbay.util.URI;
47 import org.mortbay.util.UrlEncoded;
48
49 /* ------------------------------------------------------------ */
50 /**
51  * HTTP Request. This class manages the headers, trailers and content streams of a HTTP request. It
52  * can be used for receiving or generating requests.
53  * <P>
54  * This class is not synchronized. It should be explicitly synchronized if it is used by multiple
55  * threads.
56  *
57  * @see HttpResponse
58  * @version $Id: HttpRequest.java,v 1.90 2005/12/21 23:14:38 gregwilkins Exp $
59  * @author Greg Wilkins (gregw)
60  */

61 public class HttpRequest extends HttpMessage
62 {
63     private static Log log = LogFactory.getLog(HttpRequest.class);
64
65     /* ------------------------------------------------------------ */
66     /**
67      * Request METHODS.
68      */

69     public static final String JavaDoc __GET = "GET", __POST = "POST", __HEAD = "HEAD", __PUT = "PUT",
70             __OPTIONS = "OPTIONS", __DELETE = "DELETE", __TRACE = "TRACE", __CONNECT = "CONNECT",
71             __MOVE = "MOVE";
72
73     /* ------------------------------------------------------------ */
74     /**
75      * Max size of the form content. Limits the size of the data a client can push at the server.
76      * Set via the org.mortbay.http.HttpRequest.maxContentSize system property.
77      */

78     public static int __maxFormContentSize = Integer.getInteger(
79             "org.mortbay.http.HttpRequest.maxFormContentSize", 200000).intValue();
80
81     /* ------------------------------------------------------------ */
82     /**
83      * Maximum header line length.
84      */

85     public static int __maxLineLength = 4096;
86
87     public static final StringMap __methodCache = new StringMap(true);
88     public static final StringMap __versionCache = new StringMap(true);
89     static
90     {
91         __methodCache.put(__GET, null);
92         __methodCache.put(__POST, null);
93         __methodCache.put(__HEAD, null);
94         __methodCache.put(__PUT, null);
95         __methodCache.put(__OPTIONS, null);
96         __methodCache.put(__DELETE, null);
97         __methodCache.put(__TRACE, null);
98         __methodCache.put(__CONNECT, null);
99         __methodCache.put(__MOVE, null);
100
101         __versionCache.put(__HTTP_1_1, null);
102         __versionCache.put(__HTTP_1_0, null);
103         __versionCache.put(__HTTP_0_9, null);
104     }
105
106     private static Cookie JavaDoc[] __noCookies = new Cookie JavaDoc[0];
107
108     /* ------------------------------------------------------------ */
109     private String JavaDoc _method = null;
110     private URI _uri = null;
111     private String JavaDoc _host;
112     private String JavaDoc _hostPort;
113     private int _port;
114     private List JavaDoc _te;
115     private MultiMap _parameters;
116     private boolean _paramsExtracted;
117     private boolean _handled;
118     private Cookie JavaDoc[] _cookies;
119     private String JavaDoc[] _lastCookies;
120     private boolean _cookiesExtracted;
121     private long _timeStamp;
122     private String JavaDoc _timeStampStr;
123     private Principal JavaDoc _userPrincipal;
124     private String JavaDoc _authUser;
125     private String JavaDoc _authType;
126     private char[] _uriExpanded;
127
128     /* ------------------------------------------------------------ */
129     /**
130      * Constructor.
131      */

132     public HttpRequest()
133     {
134     }
135
136     /* ------------------------------------------------------------ */
137     /**
138      * Constructor.
139      *
140      * @param connection
141      */

142     public HttpRequest(HttpConnection connection)
143     {
144         super(connection);
145     }
146
147     /* ------------------------------------------------------------ */
148     /**
149      * Get Request TimeStamp
150      *
151      * @return The time that the request was received.
152      */

153     public String JavaDoc getTimeStampStr()
154     {
155         if (_timeStampStr == null && _timeStamp > 0)
156                 _timeStampStr = HttpFields.__dateCache.format(_timeStamp);
157         return _timeStampStr;
158     }
159
160     /* ------------------------------------------------------------ */
161     /**
162      * Get Request TimeStamp
163      *
164      * @return The time that the request was received.
165      */

166     public long getTimeStamp()
167     {
168         return _timeStamp;
169     }
170
171     /* ------------------------------------------------------------ */
172     public void setTimeStamp(long ts)
173     {
174         _timeStamp = ts;
175     }
176
177     /* ------------------------------------------------------------ */
178     /**
179      * @deprecated use getHttpResponse()
180      */

181     public HttpResponse getResponse()
182     {
183         return getHttpResponse();
184     }
185
186     /* ------------------------------------------------------------ */
187     /**
188      * Get the HTTP Response. Get the HTTP Response associated with this request.
189      *
190      * @return associated response
191      */

192     public HttpResponse getHttpResponse()
193     {
194         if (_connection == null) return null;
195         return _connection.getResponse();
196     }
197
198     /* ------------------------------------------------------------ */
199     /**
200      * Is the request handled.
201      *
202      * @return True if the request has been set to handled or the associated response is not
203      * editable.
204      */

205     public boolean isHandled()
206     {
207         if (_handled) return true;
208
209         HttpResponse response = getHttpResponse();
210         return (response != null && response.getState() != HttpMessage.__MSG_EDITABLE);
211     }
212
213     /* ------------------------------------------------------------ */
214     /**
215      * Set the handled status.
216      *
217      * @param handled true or false
218      */

219     public void setHandled(boolean handled)
220     {
221         _handled = handled;
222     }
223
224     /* ------------------------------------------------------------ */
225     /**
226      * Read the request line and header.
227      *
228      * @param in
229      * @exception IOException
230      */

231     public void readHeader(LineInput in) throws IOException JavaDoc
232     {
233         _state = __MSG_BAD;
234
235         // Get start line
236
org.mortbay.util.LineInput.LineBuffer line_buffer;
237
238         do
239         {
240             line_buffer = in.readLineBuffer();
241             if (line_buffer == null) throw new EOFException();
242         }
243         while (line_buffer.size == 0);
244
245         if (line_buffer.size >= __maxLineLength)
246                 throw new HttpException(HttpResponse.__414_Request_URI_Too_Large);
247         decodeRequestLine(line_buffer.buffer, line_buffer.size);
248         _timeStamp = System.currentTimeMillis();
249
250         // Handle version - replace with fast compare
251
if (__HTTP_1_1.equals(_version))
252         {
253             _dotVersion = 1;
254             _version = __HTTP_1_1;
255             _header.read(in);
256             updateMimeType();
257         }
258         else if (__HTTP_0_9.equals(_version))
259         {
260             _dotVersion = -1;
261             _version = __HTTP_0_9;
262         }
263         else
264         {
265             _dotVersion = 0;
266             _version = __HTTP_1_0;
267             _header.read(in);
268             updateMimeType();
269         }
270
271         _handled = false;
272         _state = __MSG_RECEIVED;
273     }
274
275     /* -------------------------------------------------------------- */
276     /**
277      * Write the HTTP request line as it was received.
278      */

279     public void writeRequestLine(Writer JavaDoc writer) throws IOException JavaDoc
280     {
281         writer.write(_method);
282         writer.write(' ');
283         writer.write(_uri != null ? _uri.toString() : "null");
284         writer.write(' ');
285         writer.write(_version);
286     }
287
288     /* -------------------------------------------------------------- */
289     /**
290      * Write the request header. Places the message in __MSG_SENDING state.
291      *
292      * @param writer Http output stream
293      * @exception IOException IO problem
294      */

295     public void writeHeader(Writer JavaDoc writer) throws IOException JavaDoc
296     {
297         if (_state != __MSG_EDITABLE) throw new IllegalStateException JavaDoc("Not MSG_EDITABLE");
298
299         _state = __MSG_BAD;
300         writeRequestLine(writer);
301         writer.write(HttpFields.__CRLF);
302         _header.write(writer);
303         _state = __MSG_SENDING;
304     }
305
306     /* -------------------------------------------------------------- */
307     /**
308      * Return the HTTP request line as it was received.
309      */

310     public String JavaDoc getRequestLine()
311     {
312         return _method + " " + _uri + " " + _version;
313     }
314
315     /* -------------------------------------------------------------- */
316     /**
317      * Get the HTTP method for this request. Returns the method with which the request was made. The
318      * returned value can be "GET", "HEAD", "POST", or an extension method. Same as the CGI variable
319      * REQUEST_METHOD.
320      *
321      * @return The method
322      */

323     public String JavaDoc getMethod()
324     {
325         return _method;
326     }
327
328     /* ------------------------------------------------------------ */
329     public void setMethod(String JavaDoc method)
330     {
331         if (getState() != __MSG_EDITABLE) throw new IllegalStateException JavaDoc("Not EDITABLE");
332         _method = method;
333     }
334
335     /* ------------------------------------------------------------ */
336     public String JavaDoc getVersion()
337     {
338         return _version;
339     }
340
341     /* ------------------------------------------------------------ */
342     /**
343      * Reconstructs the URL the client used to make the request. The returned URL contains a
344      * protocol, server name, port number, and, but it does not include a path.
345      * <p>
346      * Because this method returns a <code>StringBuffer</code>, not a string, you can modify the
347      * URL easily, for example, to append path and query parameters.
348      *
349      * This method is useful for creating redirect messages and for reporting errors.
350      *
351      * @return "scheme://host:port"
352      */

353     public StringBuffer JavaDoc getRootURL()
354     {
355         StringBuffer JavaDoc url = new StringBuffer JavaDoc(48);
356         synchronized (url)
357         {
358             String JavaDoc scheme = getScheme();
359             int port = getPort();
360
361             url.append(scheme);
362             url.append("://");
363             if (_hostPort != null)
364                 url.append(_hostPort);
365             else
366             {
367                 url.append(getHost());
368                 if (port > 0
369                         && ((scheme.equalsIgnoreCase("http") && port != 80) || (scheme
370                                 .equalsIgnoreCase("https") && port != 443)))
371                 {
372                     url.append(':');
373                     url.append(port);
374                 }
375             }
376             return url;
377         }
378     }
379
380     /* ------------------------------------------------------------ */
381     /**
382      * Reconstructs the URL the client used to make the request. The returned URL contains a
383      * protocol, server name, port number, and server path, but it does not include query string
384      * parameters.
385      *
386      * <p>
387      * Because this method returns a <code>StringBuffer</code>, not a string, you can modify the
388      * URL easily, for example, to append query parameters.
389      *
390      * <p>
391      * This method is useful for creating redirect messages and for reporting errors.
392      *
393      * @return a <code>StringBuffer</code> object containing the reconstructed URL
394      *
395      */

396     public StringBuffer JavaDoc getRequestURL()
397     {
398         StringBuffer JavaDoc buf = getRootURL();
399         buf.append(getPath());
400         return buf;
401     }
402
403     /* -------------------------------------------------------------- */
404     /**
405      * Get the full URI.
406      *
407      * @return the request URI (not a clone).
408      */

409     public URI getURI()
410     {
411         return _uri;
412     }
413
414     /* ------------------------------------------------------------ */
415     /**
416      * Get the request Scheme. The scheme is obtained from an absolute URI. If the URI in the
417      * request is not absolute, then the connections default scheme is returned. If there is no
418      * connection "http" is returned.
419      *
420      * @return The request scheme (eg. "http", "https", etc.)
421      */

422     public String JavaDoc getScheme()
423     {
424         String JavaDoc scheme = _uri.getScheme();
425         if (scheme == null && _connection != null) scheme = _connection.getDefaultScheme();
426         return scheme == null ? "http" : scheme;
427     }
428
429     /* ------------------------------------------------------------ */
430     /**
431      * @return True if this request came over an integral channel such as SSL
432      */

433     public boolean isIntegral()
434     {
435         return _connection.getListener().isIntegral(_connection);
436     }
437
438     /* ------------------------------------------------------------ */
439     /**
440      * @return True if this request came over an confidential channel such as SSL.
441      */

442     public boolean isConfidential()
443     {
444         return _connection.getListener().isConfidential(_connection);
445     }
446
447     /* ------------------------------------------------------------ */
448     /**
449      * Get the request host.
450      *
451      * @return The host name obtained from an absolute URI, the HTTP header field, the requests
452      * connection or the local host name.
453      */

454     public String JavaDoc getHost()
455     {
456         // Return already determined host
457
if (_host != null) return _host;
458
459         // Return host from absolute URI
460
_host = _uri.getHost();
461         _port = _uri.getPort();
462         if (_host != null) return _host;
463
464         // Return host from header field
465
_hostPort = _header.get(HttpFields.__Host);
466         _host = _hostPort;
467         _port = 0;
468         if (_host != null && _host.length() > 0)
469         {
470             int colon = _host.lastIndexOf(':');
471             if (colon >= 0)
472             {
473                 if (colon < _host.length())
474                 {
475                     try
476                     {
477                         _port = TypeUtil.parseInt(_host, colon + 1, -1, 10);
478                     }
479                     catch (Exception JavaDoc e)
480                     {
481                         LogSupport.ignore(log, e);
482                     }
483                 }
484                 _host = _host.substring(0, colon);
485             }
486
487             return _host;
488         }
489
490         // Return host from connection
491
if (_connection != null)
492         {
493             _host = _connection.getServerName();
494             _port = _connection.getServerPort();
495             if (_host != null && !InetAddrPort.__0_0_0_0.equals(_host)) return _host;
496         }
497
498         // Return the local host
499
try
500         {
501             _host = InetAddress.getLocalHost().getHostAddress();
502         }
503         catch (java.net.UnknownHostException JavaDoc e)
504         {
505             LogSupport.ignore(log, e);
506         }
507         return _host;
508     }
509
510     /* ------------------------------------------------------------ */
511     /**
512      * Get the request port. The port is obtained either from an absolute URI, the HTTP Host header
513      * field, the connection or the default.
514      *
515      * @return The port. 0 should be interpreted as the default port.
516      */

517     public int getPort()
518     {
519         if (_port > 0) return _port;
520         if (_host != null) return 0;
521         if (_uri.isAbsolute())
522             _port = _uri.getPort();
523         else if (_connection != null) _port = _connection.getServerPort();
524         return _port;
525     }
526
527     /* ------------------------------------------------------------ */
528     /**
529      * Get the request path.
530      *
531      * @return The URI path of the request.
532      */

533     public String JavaDoc getPath()
534     {
535         return _uri.getPath();
536     }
537
538     /* ------------------------------------------------------------ */
539     public void setPath(String JavaDoc path)
540     {
541         if (getState() != __MSG_EDITABLE) throw new IllegalStateException JavaDoc("Not EDITABLE");
542         if (_uri == null)
543             _uri = new URI(path);
544         else
545             _uri.setURI(path);
546     }
547
548     /* ------------------------------------------------------------ */
549     /**
550      * Get the encoded request path.
551      *
552      * @return The path with % encoding.
553      */

554     public String JavaDoc getEncodedPath()
555     {
556         return _uri.getEncodedPath();
557     }
558
559     /* ------------------------------------------------------------ */
560     /**
561      * Get the request query.
562      *
563      * @return the request query excluding the '?'
564      */

565     public String JavaDoc getQuery()
566     {
567         return _uri.getQuery();
568     }
569
570     /* ------------------------------------------------------------ */
571     public void setQuery(String JavaDoc q)
572     {
573         if (getState() != __MSG_EDITABLE) throw new IllegalStateException JavaDoc("Not EDITABLE");
574         _uri.setQuery(q);
575     }
576
577     /* ------------------------------------------------------------ */
578     public String JavaDoc getRemoteAddr()
579     {
580         String JavaDoc addr = "127.0.0.1";
581         HttpConnection connection = getHttpConnection();
582         if (connection != null)
583         {
584             addr = connection.getRemoteAddr();
585             if (addr == null) addr = connection.getRemoteHost();
586         }
587         return addr;
588     }
589
590     /* ------------------------------------------------------------ */
591     public String JavaDoc getRemoteHost()
592     {
593         String JavaDoc host = "127.0.0.1";
594         HttpConnection connection = getHttpConnection();
595         if (connection != null)
596         {
597             host = connection.getRemoteHost();
598             if (host == null) host = connection.getRemoteAddr();
599         }
600         return host;
601     }
602
603     /* ------------------------------------------------------------ */
604     /**
605      * Decode HTTP request line.
606      *
607      * @param buf Character buffer
608      * @param len Length of line in buffer.
609      * @exception IOException
610      */

611     void decodeRequestLine(char[] buf, int len) throws IOException JavaDoc
612     {
613         // Search for first space separated chunk
614
int s1 = -1, s2 = -1, s3 = -1;
615         int state = 0;
616         startloop: for (int i = 0; i < len; i++)
617         {
618             char c = buf[i];
619             switch (state)
620             {
621                 case 0: // leading white
622
if (c == ' ') continue;
623                     state = 1;
624                     s1 = i;
625
626                 case 1: // reading method
627
if (c == ' ')
628                         state = 2;
629                     else
630                     {
631                         s2 = i;
632                         if (c >= 'a' && c <= 'z') buf[i] = (char) (c - 'a' + 'A');
633                     }
634                     continue;
635
636                 case 2: // skip whitespace after method
637
s3 = i;
638                     if (c != ' ') break startloop;
639             }
640         }
641
642         // Search for last space separated chunk
643
int e1 = -1, e2 = -1, e3 = -1;
644         state = 0;
645         endloop: for (int i = len; i-- > 0;)
646         {
647             char c = buf[i];
648             switch (state)
649             {
650                 case 0: // trailing white
651
if (c == ' ') continue;
652                     state = 1;
653                     e1 = i;
654
655                 case 1: // reading Version
656
if (c == ' ')
657                         state = 2;
658                     else
659                         e2 = i;
660                     continue;
661
662                 case 2: // skip whitespace before version
663
e3 = i;
664                     if (c != ' ') break endloop;
665             }
666         }
667
668         // Check sufficient params
669
if (s3 < 0 || e1 < 0 || e3 < s2)
670                 throw new IOException JavaDoc("Bad Request: " + new String JavaDoc(buf, 0, len));
671
672         // get method
673
Map.Entry JavaDoc method = __methodCache.getEntry(buf, s1, s2 - s1 + 1);
674         if (method != null)
675             _method = (String JavaDoc) method.getKey();
676         else
677             _method = new String JavaDoc(buf, s1, s2 - s1 + 1).toUpperCase();
678
679         // get version as uppercase
680
if (s2 != e3 || s3 != e2)
681         {
682             Map.Entry JavaDoc version = __versionCache.getEntry(buf, e2, e1 - e2 + 1);
683             if (version != null)
684                 _version = (String JavaDoc) version.getKey();
685             else
686             {
687                 for (int i = e2; i <= e1; i++)
688                     if (buf[i] >= 'a' && buf[i] <= 'z') buf[i] = (char) (buf[i] - 'a' + 'A');
689                 _version = new String JavaDoc(buf, e2, e1 - e2 + 1);
690             }
691         }
692         else
693         {
694             // missing version
695
_version = __HTTP_0_9;
696             e3 = e1;
697         }
698
699         // handle URI
700
try
701         {
702             String JavaDoc raw_uri =null;
703             if (URI.__CHARSET_IS_DEFAULT)
704                 raw_uri = new String JavaDoc(buf, s3, e3 - s3 + 1);
705             else
706             {
707                 int l=e3-s3+1;
708                 for (int i=0;i<l;i++)
709                 {
710                     char c=buf[s3+i];
711                     
712                     if (c>=0 && c<0x80)
713                         continue;
714                 
715                     if (_uriExpanded==null || _uriExpanded.length<3*l)
716                         _uriExpanded=new char[3*l];
717                     
718                     if (i>0)
719                         System.arraycopy(buf, s3, _uriExpanded, 0, i);
720                     int j=i;
721                     for (;i<l;i++)
722                     {
723                         c=buf[s3+i];
724                         if (c>=0 && c<0x80)
725                             _uriExpanded[j++]=c;
726                         else
727                         {
728                             _uriExpanded[j++]='%';
729                             _uriExpanded[j++]=TypeUtil.toHexChar(0xf&(c>>4));
730                             _uriExpanded[j++]=TypeUtil.toHexChar(0xf&c);
731                         }
732                     }
733                     raw_uri=new String JavaDoc(_uriExpanded, 0, j);
734                 }
735
736                 if (raw_uri==null)
737                     raw_uri = new String JavaDoc(buf, s3, e3 - s3 + 1);
738             }
739            
740             if (_uri == null)
741                 _uri = new URI(raw_uri);
742             else
743                 _uri.setURI(raw_uri);
744         }
745         catch (IllegalArgumentException JavaDoc e)
746         {
747             LogSupport.ignore(log, e);
748             throw new HttpException(HttpResponse.__400_Bad_Request,
749                     new String JavaDoc(buf, s3, e3 - s3 + 1));
750         }
751     }
752
753     /* ------------------------------------------------------------ */
754     /**
755      * Force a removeField. This call ignores the message state and forces a field to be removed
756      * from the request. It is required for the handling of the Connection field.
757      *
758      * @param name The field name
759      * @return The old value or null.
760      */

761     Object JavaDoc forceRemoveField(String JavaDoc name)
762     {
763         int saved_state = _state;
764         try
765         {
766             _state = __MSG_EDITABLE;
767             return removeField(name);
768         }
769         finally
770         {
771             _state = saved_state;
772         }
773     }
774
775     /* ------------------------------------------------------------ */
776     /**
777      * Get the acceptable transfer encodings. The TE field is used to construct a list of acceptable
778      * extension transfer codings in quality order. An empty list implies that only "chunked" is
779      * acceptable. A null list implies that no transfer coding can be applied.
780      *
781      * If the "trailer" coding is found in the TE field, then message trailers are enabled in any
782      * linked response.
783      *
784      * @return List of codings.
785      */

786     public List JavaDoc getAcceptableTransferCodings()
787     {
788         if (_dotVersion < 1) return null;
789         if (_te != null) return _te;
790
791         // Decode any TE field
792
Enumeration JavaDoc tenum = getFieldValues(HttpFields.__TE, HttpFields.__separators);
793
794         if (tenum != null)
795         {
796             // Sort the list
797
List JavaDoc te = HttpFields.qualityList(tenum);
798             int size = te.size();
799             // Process if something there
800
if (size > 0)
801             {
802                 Object JavaDoc acceptable = null;
803
804                 // remove trailer and chunked items.
805
ListIterator JavaDoc iter = te.listIterator();
806                 while (iter.hasNext())
807                 {
808                     String JavaDoc coding = StringUtil.asciiToLowerCase(HttpFields.valueParameters(iter
809                             .next().toString(), null));
810
811                     if (!HttpFields.__Chunked.equalsIgnoreCase(coding))
812                     {
813                         acceptable = LazyList.ensureSize(acceptable, size);
814                         acceptable = LazyList.add(acceptable, coding);
815                     }
816                 }
817                 _te = LazyList.getList(acceptable);
818             }
819             else
820                 _te = Collections.EMPTY_LIST;
821         }
822         else
823             _te = Collections.EMPTY_LIST;
824
825         return _te;
826     }
827
828     /* ------------------------------------------------------------ */
829     /*
830      * Extract Paramters from query string and/or form content.
831      */

832     private void extractParameters()
833     {
834         if (_paramsExtracted) return;
835         _paramsExtracted = true;
836
837         if (_parameters == null) _parameters = new MultiMap(16);
838
839         // Handle query string
840
String JavaDoc encoding = getCharacterEncoding();
841         if (encoding == null)
842         {
843             _uri.putParametersTo(_parameters);
844         }
845         else
846         {
847             // An encoding has been set, so reencode query string.
848
String JavaDoc query = _uri.getQuery();
849             if (query != null) UrlEncoded.decodeTo(query, _parameters, encoding);
850         }
851
852         // handle any content.
853
if (_state == __MSG_RECEIVED)
854         {
855             String JavaDoc content_type = getField(HttpFields.__ContentType);
856          &n