KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > caucho > server > http > HttpRequest


1 /*
2  * Copyright (c) 1998-2006 Caucho Technology -- all rights reserved
3  *
4  * This file is part of Resin(R) Open Source
5  *
6  * Each copy or derived work must preserve the copyright notice and this
7  * notice unmodified.
8  *
9  * Resin Open Source is free software; you can redistribute it and/or modify
10  * it under the terms of the GNU General Public License as published by
11  * the Free Software Foundation; either version 2 of the License, or
12  * (at your option) any later version.
13  *
14  * Resin Open Source is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, or any warranty
17  * of NON-INFRINGEMENT. See the GNU General Public License for more
18  * details.
19  *
20  * You should have received a copy of the GNU General Public License
21  * along with Resin Open Source; if not, write to the
22  *
23  * Free Software Foundation, Inc.
24  * 59 Temple Place, Suite 330
25  * Boston, MA 02111-1307 USA
26  *
27  * @author Scott Ferguson
28  */

29
30 package com.caucho.server.http;
31
32 import com.caucho.log.Log;
33 import com.caucho.server.cluster.Server;
34 import com.caucho.server.connection.AbstractHttpRequest;
35 import com.caucho.server.connection.Connection;
36 import com.caucho.server.dispatch.BadRequestException;
37 import com.caucho.server.dispatch.DispatchServer;
38 import com.caucho.server.dispatch.Invocation;
39 import com.caucho.server.dispatch.InvocationDecoder;
40 import com.caucho.server.port.ServerRequest;
41 import com.caucho.server.port.TcpConnection;
42 import com.caucho.server.webapp.ErrorPageManager;
43 import com.caucho.util.CharBuffer;
44 import com.caucho.util.CharSegment;
45 import com.caucho.vfs.ClientDisconnectException;
46 import com.caucho.vfs.QSocket;
47 import com.caucho.vfs.ReadStream;
48
49 import java.io.IOException JavaDoc;
50 import java.io.InterruptedIOException JavaDoc;
51 import java.security.cert.X509Certificate JavaDoc;
52 import java.util.ArrayList JavaDoc;
53 import java.util.Collections JavaDoc;
54 import java.util.Enumeration JavaDoc;
55 import java.util.logging.Level JavaDoc;
56 import java.util.logging.Logger JavaDoc;
57
58 /**
59  * Handles a new request from an HTTP connection.
60  */

61 public class HttpRequest extends AbstractHttpRequest
62   implements ServerRequest {
63   static final Logger JavaDoc log = Log.open(HttpRequest.class);
64
65   static final int HTTP_0_9 = 0x0009;
66   static final int HTTP_1_0 = 0x0100;
67   static final int HTTP_1_1 = 0x0101;
68
69   static final CharBuffer _getCb = new CharBuffer("GET");
70   static final CharBuffer _headCb = new CharBuffer("HEAD");
71   static final CharBuffer _postCb = new CharBuffer("POST");
72
73   static final char []_hostCb = "Host".toCharArray();
74   static final char []_userAgentCb = "User-Agent".toCharArray();
75
76   static final CharBuffer _http11Cb = new CharBuffer("HTTP/1.1");
77   static final CharBuffer _http10Cb = new CharBuffer("HTTP/1.0");
78
79   private String JavaDoc _scheme; // "http:" or "https:"
80
private boolean _isSecure;
81
82   private CharBuffer _method; // "GET"
83
private String JavaDoc _methodString;
84
85   private CharBuffer _uriHost; // www.caucho.com:8080
86
private CharSequence JavaDoc _host;
87   private CharBuffer _hostBuffer = new CharBuffer();
88
89   private final byte []_uri; // "/path/test.jsp/Junk?query=7"
90
private int _uriLength;
91
92   private int _urlLengthMax = 8192;
93
94   private CharBuffer _protocol; // "HTTP/1.0"
95
private int _version;
96
97   private final InvocationKey _invocationKey = new InvocationKey();
98
99   private final char []_headerBuffer = new char[16 * 1024];
100
101   private CharSegment []_headerKeys;
102   private CharSegment []_headerValues;
103   private int _headerCapacity = 256;
104   private int _headerSize;
105
106   private ChunkedInputStream _chunkedInputStream = new ChunkedInputStream();
107   private ContentLengthStream _contentLengthStream = new ContentLengthStream();
108
109   private ErrorPageManager _errorManager = new ErrorPageManager();
110
111   private boolean _initAttributes;
112
113   /**
114    * Creates a new HttpRequest. New connections reuse the request.
115    *
116    * @param server the owning server.
117    */

118   HttpRequest(DispatchServer server, Connection conn)
119   {
120     super(server, conn);
121
122     _response = new HttpResponse(this);
123     _response.init(conn.getWriteStream());
124
125     // _urlLengthMax = server.getURLLengthMax();
126

127     // XXX: response.setIgnoreClientDisconnect(server.getIgnoreClientDisconnect());
128

129     _uri = new byte[_urlLengthMax];
130
131     _method = new CharBuffer();
132     _uriHost = new CharBuffer();
133     _protocol = new CharBuffer();
134
135     _headerCapacity = 256;
136     _headerSize = 0;
137     _headerKeys = new CharSegment[_headerCapacity];
138     _headerValues = new CharSegment[_headerCapacity];
139     for (int i = 0; i < _headerCapacity; i++) {
140       _headerKeys[i] = new CharSegment();
141       _headerValues[i] = new CharSegment();
142     }
143   }
144
145   /**
146    * Return true if the request waits for a read before beginning.
147    */

148   public final boolean isWaitForRead()
149   {
150     return true;
151   }
152   
153   /**
154    * Handles a new HTTP request.
155    *
156    * <p>Note: ClientDisconnectException must be rethrown to
157    * the caller.
158    *
159    * @return true if the connection should stay open (keepalive)
160    */

161   public boolean handleRequest()
162     throws IOException JavaDoc
163   {
164     boolean hasRequest = false;
165     try {
166       start();
167       _response.start();
168
169       try {
170     try {
171       if (! readRequest(_rawRead)) {
172         if (log.isLoggable(Level.FINE))
173           log.fine(dbgId() + "read timeout");
174
175         return false;
176       }
177
178       setStartTime();
179
180       hasRequest = true;
181
182       _isSecure = _conn.isSecure() || _conn.getLocalPort() == 443;
183
184       if (_protocol.length() == 0)
185         _protocol.append("HTTP/0.9");
186
187       if (log.isLoggable(Level.FINE)) {
188         log.fine(dbgId() + _method + " " +
189              new String JavaDoc(_uri, 0, _uriLength) + " " + _protocol);
190         log.fine(dbgId() + "Remote-IP: " + _conn.getRemoteHost() + ":" + _conn.getRemotePort());
191       }
192
193       parseHeaders(_rawRead);
194
195       if (getVersion() >= HTTP_1_1 && isForce10()) {
196         _protocol.clear();
197         _protocol.append("HTTP/1.0");
198         _version = HTTP_1_0;
199       }
200     } catch (ClientDisconnectException e) {
201       throw e;
202     } catch (Throwable JavaDoc e) {
203       log.log(Level.FINER, e.toString(), e);
204
205       throw new BadRequestException(String.valueOf(e));
206     }
207
208     CharSequence JavaDoc host = getHost();
209     if (host == null && getVersion() >= HTTP_1_1)
210       throw new BadRequestException("HTTP/1.1 requires host");
211
212     String JavaDoc ipHost = _conn.getVirtualHost();
213     if (ipHost != null)
214       host = ipHost;
215
216     _invocationKey.init(_isSecure,
217                 host, _conn.getLocalPort(),
218                 _uri, _uriLength);
219
220     Invocation invocation;
221
222     invocation = _server.getInvocation(_invocationKey);
223
224     if (invocation == null) {
225       invocation = _server.createInvocation();
226       invocation.setSecure(_isSecure);
227
228       if (host != null) {
229         String JavaDoc hostName = host.toString().toLowerCase();
230
231         invocation.setHost(hostName);
232         invocation.setPort(_conn.getLocalPort());
233
234         // Default host name if the host doesn't have a canonical
235
// name
236
int p = hostName.indexOf(':');
237         if (p > 0)
238           invocation.setHostName(hostName.substring(0, p));
239         else
240           invocation.setHostName(hostName);
241       }
242
243       InvocationDecoder decoder = _server.getInvocationDecoder();
244
245       decoder.splitQueryAndUnescape(invocation, _uri, _uriLength);
246
247       if (_server.isModified()) {
248         log.info("<server> is modified");
249
250         _invocation = invocation;
251         if (_server instanceof Server)
252           _invocation.setWebApp(((Server) _server).getErrorWebApp());
253
254         restartServer();
255         return false;
256       }
257
258       _server.buildInvocation(_invocationKey.clone(), invocation);
259     }
260
261     setInvocation(invocation);
262
263     invocation.service(this, _response);
264       } finally {
265     finish();
266       }
267     } catch (ClientDisconnectException e) {
268       _response.killCache();
269
270       throw e;
271     } catch (Throwable JavaDoc e) {
272       log.log(Level.FINE, e.toString(), e);
273
274       _response.killCache();
275       killKeepalive();
276
277       try {
278         _errorManager.sendServletError(e, this, _response);
279       } catch (ClientDisconnectException e1) {
280         throw e1;
281       } catch (Throwable JavaDoc e1) {
282         log.log(Level.FINE, e1.toString(), e1);
283       }
284
285       return false;
286     } finally {
287       if (hasRequest)
288         _response.finish();
289       else
290     super.finish();
291     }
292
293     if (log.isLoggable(Level.FINE)) {
294       log.fine(dbgId() +
295                (isKeepalive() ? "keepalive" : "no-keepalive"));
296     }
297
298     return isKeepalive();
299   }
300
301   /**
302    * There are some bogus clients that can't deal with HTTP/1.1 even
303    * though they advertise it.
304    */

305   private boolean isForce10()
306   {
307     return false;
308   }
309
310   /**
311    * Returns true for the top-level request, but false for any include()
312    * or forward()
313    */

314   public boolean isTop()
315   {
316     return true;
317   }
318
319   protected boolean checkLogin()
320   {
321     return true;
322   }
323
324   /**
325    * Clear the request variables in preparation for a new request.
326    *
327    * @param s the read stream for the request
328    */

329   protected void start()
330     throws IOException JavaDoc
331   {
332     super.start();
333
334     _method.clear();
335     _methodString = null;
336     _protocol.clear();
337     _uriLength = 0;
338     _uriHost.clear();
339     _host = null;
340
341     _headerSize = 0;
342     _initAttributes = false;
343   }
344
345   /**
346    * Returns true for a secure connection.
347    */

348   public boolean isSecure()
349   {
350     return _isSecure;
351   }
352
353   /**
354    * Read the first line of a request:
355    *
356    * GET [http://www.caucho.com[:80]]/path [HTTP/1.x]
357    *
358    * @return true if the request is valid
359    */

360   private boolean readRequest(ReadStream s)
361     throws IOException JavaDoc
362   {
363     int i = 0;
364
365     byte []readBuffer = s.getBuffer();
366     int readOffset = s.getOffset();
367     int readLength = s.getLength();
368     int ch;
369
370     if (readOffset >= readLength) {
371       try {
372         if ((readLength = s.fillBuffer()) < 0)
373           return false;
374       } catch (InterruptedIOException JavaDoc e) {
375         log.fine(dbgId() + "keepalive timeout");
376         return false;
377       }
378       readOffset = 0;
379     }
380     ch = readBuffer[readOffset++];
381
382     // conn.setAccessTime(getDate());
383

384     // skip leading whitespace
385
while (ch == ' ' || ch == '\t' || ch == '\r' || ch == '\n') {
386       if (readOffset >= readLength) {
387         if ((readLength = s.fillBuffer()) < 0)
388           return false;
389
390         readOffset = 0;
391       }
392       ch = readBuffer[readOffset++];
393     }
394
395     char []buffer = _method.getBuffer();
396     int length = buffer.length;
397     int offset = 0;
398
399     // scan method
400
while (true) {
401       if (length <= offset) {
402       }
403       else if (ch >= 'a' && ch <= 'z')
404     buffer[offset++] = ((char) (ch + 'A' - 'a'));
405       else if (ch > ' ')
406     buffer[offset++] = (char) ch;
407       else
408     break;
409
410       if (readLength <= readOffset) {
411         if ((readLength = s.fillBuffer()) < 0)
412           return false;
413
414         readOffset = 0;
415       }
416       ch = readBuffer[readOffset++];
417     }
418
419     _method.setLength(offset);
420
421     // skip whitespace
422
while (ch == ' ' || ch == '\t') {
423       if (readOffset >= readLength) {
424         if ((readLength = s.fillBuffer()) < 0)
425           return false;
426
427         readOffset = 0;
428       }
429
430       ch = readBuffer[readOffset++];
431     }
432
433     byte []uriBuffer = _uri;
434     int uriLength = 0;
435
436     // skip 'http:'
437
if (ch != '/') {
438       while (ch > ' ' && ch != '/') {
439         if (readOffset >= readLength) {
440           if ((readLength = s.fillBuffer()) < 0)
441             return false;
442           readOffset = 0;
443         }
444         ch = readBuffer[readOffset++];
445       }
446
447       if (readOffset >= readLength) {
448         if ((readLength = s.fillBuffer()) < 0) {
449           if (ch == '/') {
450             uriBuffer[uriLength++] = (byte) ch;
451             _uriLength = uriLength;
452           }
453
454           return true;
455         }
456         readOffset = 0;
457       }
458
459       int ch1 = readBuffer[readOffset++];
460
461       if (ch1 != '/') {
462         uriBuffer[uriLength++] = (byte) ch;
463         ch = ch1;
464       }
465       else {
466         // read host
467
host:
468         while (true) {
469           if (readOffset >= readLength) {
470             if ((readLength = s.fillBuffer()) < 0) {
471               return true;
472             }
473             readOffset = 0;
474           }
475           ch = readBuffer[readOffset++];
476
477           switch (ch) {
478           case ' ': case '\t': case '\n': case '\r':
479             break host;
480
481           case '?':
482             break host;
483
484           case '/':
485             break host;
486
487           default:
488             _uriHost.append((char) ch);
489             break;
490           }
491         }
492       }
493     }
494
495     // read URI
496
uri:
497     while (true) {
498       switch (ch) {
499       case ' ': case '\t': case '\n': case '\r':
500     break uri;
501
502       default:
503         // There's no check for overrunning the length because
504
// allowing resizing would allow a DOS memory attack and
505
// also lets us save a bit of efficiency.
506
uriBuffer[uriLength++] = (byte) ch;
507         break;
508       }
509
510       if (readOffset >= readLength) {
511         readOffset = 0;
512         if ((readLength = s.fillBuffer()) < 0) {
513           _uriLength = uriLength;
514           return true;
515         }
516       }
517       ch = readBuffer[readOffset++];
518     }
519
520     _uriLength = uriLength;
521
522     // skip whitespace
523
while (ch == ' ' || ch == '\t') {
524       if (readOffset >= readLength) {
525         readOffset = 0;
526         if ((readLength = s.fillBuffer()) < 0)
527           return true;
528       }
529       ch = readBuffer[readOffset++];
530     }
531
532     buffer = _protocol.getBuffer();
533     length = buffer.length;
534     offset = 0;
535     // scan protocol
536
while (ch != ' ' && ch != '\t' && ch != '\r' && ch != '\n') {
537       if (offset >= length) {
538       }
539       else if (ch >= 'a' && ch <= 'z')
540     buffer[offset++] = ((char) (ch + 'A' - 'a'));
541       else
542     buffer[offset++] = (char) ch;
543
544       if (readOffset >= readLength) {
545         readOffset = 0;
546         if ((readLength = s.fillBuffer()) < 0) {
547           _protocol.setLength(offset);
548           return true;
549         }
550       }
551       ch = readBuffer[readOffset++];
552     }
553     _protocol.setLength(offset);
554
555     if (offset != 8) {
556       _protocol.append("HTTP/0.9");
557       _version = HTTP_0_9;
558     }
559     else if (buffer[7] == '1') // && _protocol.equals(_http11Cb))
560
_version = HTTP_1_1;
561     else if (buffer[7] == '0') // && _protocol.equals(_http10Cb))
562
_version = HTTP_1_0;
563     else
564       _version = HTTP_0_9;
565
566     // skip to end of line
567
while (ch != '\n') {
568       if (readOffset >= readLength) {
569         if ((readLength = s.fillBuffer()) < 0)
570           return true;
571         readOffset = 0;
572       }
573       ch = readBuffer[readOffset++];
574     }
575
576     s.setOffset(readOffset);
577
578     return true;
579   }
580
581   /**
582    * Parses headers from the read stream.
583    *
584    * @param s the input read stream
585    */

586   private void parseHeaders(ReadStream s) throws IOException JavaDoc
587   {
588     // This is still slowest part of the web server. I don't see how
589
// to improve it much more, but there must be a way.
590
int version = getVersion();
591
592     if (version < HTTP_1_0) {
593       return;
594     }
595
596     if (version < HTTP_1_1)
597       killKeepalive();
598
599     byte []readBuffer = s.getBuffer();
600     int readOffset = s.getOffset();
601     int readLength = s.getLength();
602
603     char []headerBuffer = _headerBuffer;
604     int headerOffset = 1;
605     int headerBufferSize = headerBuffer.length;
606     headerBuffer[0] = 'z';
607     int headerSize = 0;
608     _headerSize = 0;
609
610     CharSegment []headerKeys = _headerKeys;
611     CharSegment []headerValues = _headerValues;
612
613     boolean debug = log.isLoggable(Level.FINE);
614
615     while (true) {
616       int ch;
617
618       int keyOffset = headerOffset;
619
620       // scan the key
621
while (true) {
622         if (readLength <= readOffset) {
623           readOffset = 0;
624           if ((readLength = s.fillBuffer()) <= 0)
625             return;
626         }
627         ch = readBuffer[readOffset++];
628
629         if (ch == '\n') {
630           s.setOffset(readOffset);
631           return;
632         }
633         else if (ch == ':')
634           break;
635
636         headerBuffer[headerOffset++] = (char) ch;
637       }
638
639       while (headerBuffer[headerOffset - 1] == ' ')
640         headerOffset--;
641
642       int keyLength = headerOffset - keyOffset;
643       headerKeys[headerSize].init(headerBuffer, keyOffset, keyLength);
644
645       do {
646         if (readLength <= readOffset) {
647           readOffset = 0;
648           if ((readLength = s.fillBuffer()) <= 0)
649             return;
650         }
651         ch = readBuffer[readOffset++];
652       } while (ch == ' ' || ch == '\t');
653
654       int valueOffset = headerOffset;
655
656       // scan the value
657
while (true) {
658         if (readLength <= readOffset) {
659           readOffset = 0;
660           if ((readLength = s.fillBuffer()) <= 0)
661             break;
662         }
663
664         if (ch == '\n') {
665           int ch1 = readBuffer[readOffset];
666
667           if (ch1 == ' ' || ch1 == '\t') {
668             ch = ' ';
669             readOffset++;
670
671             if (headerBuffer[headerOffset - 1] == '\r')
672               headerOffset--;
673           }
674           else
675             break;
676         }
677
678         headerBuffer[headerOffset++] = (char) ch;
679
680         ch = readBuffer[readOffset++];
681       }
682
683       while (headerBuffer[headerOffset - 1] <= ' ')
684         headerOffset--;
685
686       int valueLength = headerOffset - valueOffset;
687       headerValues[headerSize].init(headerBuffer, valueOffset, valueLength);
688
689       addHeaderInt(headerBuffer, keyOffset, keyLength,
690            headerValues[headerSize]);
691
692       if (debug) {
693         log.fine(dbgId() +
694                  headerKeys[headerSize] + ": " + headerValues[headerSize]);
695       }
696
697       headerSize++;
698       _headerSize = headerSize;
699     }
700   }
701
702   /**
703    * Returns the HTTP version of the request based on getProtocol().
704    */

705   int getVersion()
706   {
707     if (_version > 0)
708       return _version;
709
710     CharSegment protocol = getProtocolBuffer();
711     if (protocol.length() < 8) {
712       _version = HTTP_0_9;
713       return _version;
714     }
715
716     if (protocol.equals("HTTP/1.0")) {
717       _version = HTTP_1_0;
718       return _version;
719     }
720     else if (protocol.equals("HTTP/1.1")) {
721       _version = HTTP_1_1;
722       return HTTP_1_1;
723     }
724     else if (protocol.equals("HTTP/0.9")) {
725       _version = HTTP_0_9;
726       return HTTP_0_9;
727     }
728
729     int i = protocol.indexOf('/');
730     int len = protocol.length();
731     int major = 0;
732     for (i++; i < len; i++) {
733       char ch = protocol.charAt(i);
734
735       if (ch >= '0' && ch <= '9')
736     major = 10 * major + ch - '0';
737       else if (ch == '.')
738     break;
739       else {
740     _version = HTTP_1_0;
741     return _version;
742       }
743     }
744
745     int minor = 0;
746     for (i++; i < len; i++) {
747       char ch = protocol.charAt(i);
748
749       if (ch >= '0' && ch <= '9')
750     minor = 10 * minor + ch - '0';
751       else
752     break;
753     }
754
755     _version = 256 * major + minor;
756
757     return _version;
758   }
759
760   /**
761    * Returns the header.
762    */

763   public String JavaDoc getMethod()
764   {
765     if (_methodString == null) {
766       CharSegment cb = getMethodBuffer();
767       if (cb.length() == 0) {
768         _methodString = "GET";
769         return _methodString;
770       }
771
772       switch (cb.charAt(0)) {
773       case 'G':
774         _methodString = cb.equals(_getCb) ? "GET" : cb.toString();
775         break;
776
777       case 'H':
778         _methodString = cb.equals(_headCb) ? "HEAD" : cb.toString();
779         break;
780
781       case 'P':
782         _methodString = cb.equals(_postCb) ? "POST" : cb.toString();
783         break;
784
785       default:
786         _methodString = cb.toString();
787       }
788     }
789
790     return _methodString;
791
792   }
793
794   /**
795    * Returns a buffer containing the request method.
796    */

797   public CharSegment getMethodBuffer()
798   {
799     return _method;
800   }
801
802   /**
803    * Returns the virtual host of the request
804    */

805   protected CharSequence JavaDoc getHost()
806   {
807     if (_host != null)
808       return _host;
809
810     String JavaDoc virtualHost = _conn.getVirtualHost();
811     if (virtualHost != null)
812       _host = virtualHost;
813     else if (_uriHost.length() > 0)
814       _host = _uriHost;
815     else
816       _host = _hostHeader;
817
818     return _host;
819   }
820
821   /**
822    * Returns the byte buffer containing the request URI
823    */

824   public byte []getUriBuffer()
825   {
826     return _uri;
827   }
828
829   /**
830    * Returns the length of the request URI
831    */

832   public int getUriLength()
833   {
834     return _uriLength;
835   }
836
837   /**
838    * Returns the protocol.
839    */

840   public String JavaDoc getProtocol()
841   {
842     switch (_version) {
843     case HTTP_1_1:
844       return "HTTP/1.1";
845     case HTTP_1_0:
846       return "HTTP/1.0";
847     case HTTP_0_9:
848     default:
849       return "HTTP/0.9";
850     }
851   }
852
853   /**
854    * Returns a char segment containing the protocol.
855    */

856   public CharSegment getProtocolBuffer()
857   {
858     return _protocol;
859   }
860
861   /**
862    * Adds a new header. Used only by the caching to simulate
863    * If-Modified-Since.
864    *
865    * @param key the key of the new header
866    * @param value the value for the new header
867    */

868   public void setHeader(String JavaDoc key, String JavaDoc value)
869   {
870     int tail;
871
872     if (_headerSize > 0) {
873       tail = (_headerValues[_headerSize - 1].getOffset() +
874               _headerValues[_headerSize - 1].getLength());
875     }
876     else
877       tail = 0;
878
879     char []headerBuffer = _headerBuffer;
880     for (int i = key.length() - 1; i >= 0; i--)
881       headerBuffer[tail + i] = key.charAt(i);
882
883     _headerKeys[_headerSize].init(headerBuffer, tail, key.length());
884
885     tail += key.length();
886
887     for (int i = value.length() - 1; i >= 0; i--)
888       headerBuffer[tail + i] = value.charAt(i);
889
890     _headerValues[_headerSize].init(headerBuffer, tail, value.length());
891     _headerSize++;
892   }
893
894   /**
895    * Returns the number of headers.
896    */

897   @Override JavaDoc
898   public int getHeaderSize()
899   {
900     return _headerSize;
901   }
902
903   /**
904    * Returns the header key
905    */

906   @Override JavaDoc
907   public CharSegment getHeaderKey(int index)
908   {
909     return _headerKeys[index];
910   }
911
912   /**
913    * Returns the header value
914    */

915   @Override JavaDoc
916   public CharSegment getHeaderValue(int index)
917   {
918     return _headerValues[index];
919   }
920
921   /**
922    * Returns the header.
923    */

924   public String JavaDoc getHeader(String JavaDoc key)
925   {
926     CharSegment buf = getHeaderBuffer(key);
927     if (buf != null)
928       return buf.toString();
929     else
930       return null;
931   }
932
933   /**
934    * Returns the matching header.
935    *
936    * @param testBuf header key
937    * @param length length of the key.
938    */

939   public CharSegment getHeaderBuffer(char []testBuf, int length)
940   {
941     char []keyBuf = _headerBuffer;
942     CharSegment []headerKeys = _headerKeys;
943
944     for (int i = _headerSize - 1; i >= 0; i--) {
945       CharSegment key = headerKeys[i];
946
947       if (key.length() != length)
948         continue;
949
950       int offset = key.getOffset();
951       int j;
952       for (j = length - 1; j >= 0; j--) {
953         char a = testBuf[j];
954         char b = keyBuf[offset + j];
955         if (a == b)
956           continue;
957
958         if (a >= 'A' && a <= 'Z')
959           a += 'a' - 'A';
960         if (b >= 'A' && b <= 'Z')
961           b += 'a' - 'A';
962         if (a != b)
963           break;
964       }
965
966       if (j < 0)
967         return _headerValues[i];
968     }
969
970     return null;
971   }
972
973   /**
974    * Returns the header value for the key, returned as a CharSegment.
975    */

976   public CharSegment getHeaderBuffer(String JavaDoc key)
977   {
978     int i = matchNextHeader(0, key);
979
980     if (i >= 0)
981       return _headerValues[i];
982     else
983       return null;
984   }
985
986   /**
987    * Fills an ArrayList with the header values matching the key.
988    *
989    * @param values ArrayList which will contain the maching values.
990    * @param key the header key to select.
991    */

992   public void getHeaderBuffers(String JavaDoc key, ArrayList JavaDoc<CharSegment> values)
993   {
994     int i = -1;
995     while ((i = matchNextHeader(i + 1, key)) >= 0)
996       values.add(_headerValues[i]);
997   }
998
999   /**
1000   * Return an enumeration of headers matching a key.
1001   *
1002   * @param key the header key to match.
1003   * @return the enumeration of the headers.
1004   */

1005  public Enumeration JavaDoc getHeaders(String JavaDoc key)
1006  {
1007    ArrayList JavaDoc<String JavaDoc> values = new ArrayList JavaDoc<String JavaDoc>();
1008    int i = -1;
1009    while ((i = matchNextHeader(i + 1, key)) >= 0)
1010      values.add(_headerValues[i].toString());
1011
1012    return Collections.enumeration(values);
1013  }
1014
1015  /**
1016   * Returns the index of the next header matching the key.
1017   *
1018   * @param i header index to start search
1019   * @param key header key to match
1020   *
1021   * @return the index of the next header matching, or -1.
1022   */

1023  private int matchNextHeader(int i, String JavaDoc key)
1024  {
1025    int size = _headerSize;
1026    int length = key.length();
1027
1028    char []keyBuf = _headerBuffer;
1029
1030    for (; i < size; i++) {
1031      CharSegment header = _headerKeys[i];
1032
1033      if (header.length() != length)
1034        continue;
1035
1036      int offset = header.getOffset();
1037
1038      int j;
1039      for (j = 0; j < length; j++) {
1040        char a = key.charAt(j);
1041        char b = keyBuf[offset + j];
1042        if (a == b)
1043          continue;
1044
1045        if (a >= 'A' && a <= 'Z')
1046          a += 'a' - 'A';
1047        if (b >= 'A' && b <= 'Z')
1048          b += 'a' - 'A';
1049        if (a != b)
1050          break;
1051      }
1052
1053      if (j == length)
1054        return i;
1055    }
1056
1057    return -1;
1058  }
1059
1060  /**
1061   * Returns an enumeration of all the header keys.
1062   */

1063  public Enumeration JavaDoc getHeaderNames()
1064  {
1065    ArrayList JavaDoc<String JavaDoc> names = new ArrayList JavaDoc<String JavaDoc>();
1066
1067    for (int i = 0; i < _headerSize; i++) {
1068      CharSegment name = _headerKeys[i];
1069
1070      int j;
1071      for (j = 0; j < names.size(); j++) {
1072    String JavaDoc oldName = names.get(j);
1073    if (name.matches(oldName))
1074      break;
1075      }
1076      if (j == names.size())
1077    names.add(j, name.toString());
1078    }
1079
1080    return Collections.enumeration(names);
1081  }
1082
1083  /**
1084   * Returns a stream for reading POST data.
1085   */

1086  public boolean initStream(ReadStream readStream, ReadStream rawRead)
1087    throws IOException JavaDoc
1088  {
1089    int contentLength = getContentLength();
1090
1091    // needed to avoid auto-flush on read conflicting with partially
1092
// generated response
1093
rawRead.setSibling(null);
1094
1095    String JavaDoc te;
1096    if (contentLength < 0 && HTTP_1_1 <= getVersion() &&
1097    (te = getHeader("Transfer-Encoding")) != null) {
1098      _chunkedInputStream.init(rawRead);
1099      readStream.init(_chunkedInputStream, null);
1100      return true;
1101    }
1102    // Otherwise use content-length
1103
else if (contentLength >= 0) {
1104      _contentLengthStream.init(rawRead, contentLength);
1105      _readStream.init(_contentLengthStream, null);
1106
1107      return true;
1108    }
1109    else if (getMethod().equals("POST")) {
1110      _contentLengthStream.init(rawRead, 0);
1111      _readStream.init(_contentLengthStream, null);
1112
1113      throw new com.caucho.server.dispatch.BadRequestException("POST requires content-length");
1114    }
1115
1116    else {
1117      _contentLengthStream.init(rawRead, 0);
1118      _readStream.init(_contentLengthStream, null);
1119
1120      return false;
1121    }
1122  }
1123
1124  protected void skip()
1125    throws IOException JavaDoc
1126  {
1127    if (getMethod() == "GET")
1128      return;
1129
1130    super.skip();
1131  }
1132
1133  /**
1134   * Prints the remote address into a buffer.
1135   *
1136   * @param buffer the buffer which will contain the address.
1137   * @param offset the initial offset into the buffer.
1138   *
1139   * @return the final offset into the buffer.
1140   */

1141  /*
1142  public int printRemoteAddr(byte []buffer, int offset)
1143    throws IOException
1144  {
1145    Connection conn = getConnection();
1146
1147    if (! (conn instanceof TcpConnection))
1148      return super.printRemoteAddr(buffer, offset);
1149
1150    QSocket socket = ((TcpConnection) conn).getSocket();
1151
1152    if (socket instanceof QJniSocket) {
1153      QJniSocket jniSocket = (QJniSocket) socket;
1154      long ip = jniSocket.getRemoteIP();
1155
1156      for (int i = 24; i >= 0; i -= 8) {
1157        int value = (int) (ip >> i) & 0xff;
1158
1159        if (value < 10)
1160          buffer[offset++] = (byte) (value + '0');
1161        else if (value < 100) {
1162          buffer[offset++] = (byte) (value / 10 + '0');
1163          buffer[offset++] = (byte) (value % 10 + '0');
1164        }
1165        else {
1166          buffer[offset++] = (byte) (value / 100 + '0');
1167          buffer[offset++] = (byte) (value / 10 % 10 + '0');
1168          buffer[offset++] = (byte) (value % 10 + '0');
1169        }
1170
1171        if (i != 0)
1172          buffer[offset++] = (byte) '.';
1173      }
1174    }
1175    else {
1176      InetAddress addr = conn.getRemoteAddress();
1177
1178      if (addr == null) {
1179        buffer[offset++] = (byte) '0';
1180        buffer[offset++] = (byte) '.';
1181        buffer[offset++] = (byte) '0';
1182        buffer[offset++] = (byte) '.';
1183        buffer[offset++] = (byte) '0';
1184        buffer[offset++] = (byte) '.';
1185        buffer[offset++] = (byte) '0';
1186
1187        return offset;
1188      }
1189
1190      byte []bytes = addr.getAddress();
1191      for (int i = 0; i < bytes.length; i++) {
1192        if (i != 0)
1193          buffer[offset++] = (byte) '.';
1194
1195        int value = bytes[i] & 0xff;
1196
1197        if (value < 10)
1198          buffer[offset++] = (byte) (value + '0');
1199        else if (value < 100) {
1200          buffer[offset++] = (byte) (value / 10 + '0');
1201          buffer[offset++] = (byte) (value % 10 + '0');
1202        }
1203        else {
1204          buffer[offset++] = (byte) (value / 100 + '0');
1205          buffer[offset++] = (byte) (value / 10 % 10 + '0');
1206          buffer[offset++] = (byte) (value % 10 + '0');
1207        }
1208      }
1209    }
1210
1211    return offset;
1212  }
1213  */

1214
1215  /**
1216   * Returns the client's remote host name.
1217   */

1218  /*
1219  public String getRemoteHost()
1220  {
1221    Connection conn = getConnection();
1222
1223    if (conn instanceof TcpConnection) {
1224      QSocket socket = ((TcpConnection) conn).getSocket();
1225
1226      if (socket instanceof QJniSocket) {
1227        QJniSocket jniSocket = (QJniSocket) socket;
1228        long ip = jniSocket.getRemoteIP();
1229
1230        CharBuffer cb = _cb;
1231        cb.clear();
1232
1233        for (int i = 24; i >= 0; i -= 8) {
1234          int value = (int) (ip >> i) & 0xff;
1235
1236          if (value < 10)
1237            cb.append((char) (value + '0'));
1238          else if (value < 100) {
1239            cb.append((char) (value / 10 + '0'));
1240            cb.append((char) (value % 10 + '0'));
1241          }
1242          else {
1243            cb.append((char) (value / 100 + '0'));
1244            cb.append((char) (value / 10 % 10 + '0'));
1245            cb.append((char) (value % 10 + '0'));
1246          }
1247
1248          if (i != 0)
1249            cb.append('.');
1250        }
1251
1252        return cb.toString();
1253      }
1254    }
1255
1256    InetAddress addr = conn.getRemoteAddress();
1257
1258    byte []bytes = addr.getAddress();
1259    CharBuffer cb = _cb;
1260    cb.clear();
1261    for (int i = 0; i < bytes.length; i++) {
1262      int value = bytes[i] & 0xff;
1263
1264      if (i != 0)
1265        cb.append('.');
1266
1267      if (value < 10)
1268        cb.append((char) (value + '0'));
1269      else if (value < 100) {
1270        cb.append((char) (value / 10 + '0'));
1271        cb.append((char) (value % 10 + '0'));
1272      }
1273      else {
1274        cb.append((char) (value / 100 + '0'));
1275        cb.append((char) (value / 10 % 10 + '0'));
1276        cb.append((char) (value % 10 + '0'));
1277      }
1278    }
1279
1280    return cb.toString();
1281  }
1282  */

1283
1284  /**
1285   * Returns the named attribute.
1286   */

1287  public Object JavaDoc getAttribute(String JavaDoc name)
1288  {
1289    if (! _initAttributes)
1290      initAttributes();
1291
1292    return super.getAttribute(name);
1293  }
1294
1295  /**
1296   * Returns an enumeration of the attribute names.
1297   */

1298  public Enumeration JavaDoc<String JavaDoc> getAttributeNames()
1299  {
1300    if (! _initAttributes)
1301      initAttributes();
1302
1303    return super.getAttributeNames();
1304  }
1305
1306  /**
1307   * For SSL connections, use the SSL identifier.
1308   */

1309  public String JavaDoc findSessionIdFromConnection()
1310  {
1311    TcpConnection tcpConn = _tcpConn;
1312    
1313    if (! _isSecure || tcpConn == null)
1314      return null;
1315
1316    QSocket socket = tcpConn.getSocket(); // XXX:
1317
/*
1318    if (! (socket instanceof SSLSocket))
1319      return null;
1320
1321    SSLSession sslSession = ((SSLSocket) socket).getSession();
1322    if (sslSession == null)
1323      return null;
1324
1325    byte []sessionId = sslSession.getId();
1326    if (sessionId == null)
1327      return null;
1328
1329    CharBuffer cb = CharBuffer.allocate();
1330    Base64.encode(cb, sessionId, 0, sessionId.length);
1331    for (int i = cb.length() - 1; i >= 0; i--) {
1332      char ch = cb.charAt(i);
1333      if (ch == '/')
1334        cb.setCharAt(i, '-');
1335    }
1336
1337    return cb.close();
1338    */

1339    return null;
1340  }
1341
1342  /**
1343   * Returns the raw input stream.
1344   */

1345  public ReadStream getRawInput()
1346  {
1347    return _rawRead;
1348  }
1349
1350  /**
1351   * Initialize any special attributes.
1352   */

1353  private void initAttributes()
1354  {
1355    _initAttributes = true;
1356
1357    TcpConnection tcpConn = _tcpConn;
1358    
1359    if (! _isSecure || tcpConn == null)
1360      return;
1361
1362    QSocket socket = tcpConn.getSocket();
1363
1364    String JavaDoc cipherSuite = socket.getCipherSuite();
1365    super.setAttribute("javax.servlet.request.cipher_suite", cipherSuite);
1366
1367    int keySize = socket.getCipherBits();
1368    if (keySize != 0)
1369      super.setAttribute("javax.servlet.request.key_size",
1370                         new Integer JavaDoc(keySize));
1371
1372    try {
1373      X509Certificate JavaDoc []certs = socket.getClientCertificates();
1374      if (certs != null && certs.length > 0) {
1375        super.setAttribute("javax.servlet.request.X509Certificate", certs[0]);
1376        super.setAttribute(com.caucho.server.security.AbstractAuthenticator.LOGIN_NAME,
1377                           certs[0].getSubjectDN());
1378      }
1379    } catch (Exception JavaDoc e) {
1380      log.log(Level.FINER, e.toString(), e);
1381    }
1382  }
1383  
1384  public void protocolCloseEvent()
1385  {
1386  }
1387
1388  /**
1389   * Cleans up at the end of the request
1390   */

1391  public void finish()
1392    throws IOException JavaDoc
1393  {
1394    super.finish();
1395
1396    skip();
1397  }
1398
1399  String JavaDoc dbgId()
1400  {
1401    if ("".equals(_server.getServerId()))
1402      return "[" + _conn.getId() + "] ";
1403    else
1404      return "[" + _server.getServerId() + ", " + _conn.getId() + "] ";
1405  }
1406
1407  public String JavaDoc toString()
1408  {
1409    return "HttpRequest" + dbgId();
1410  }
1411}
1412
Popular Tags