jdk/src/share/classes/sun/net/httpserver/Request.java
changeset 2 90ce3da70b43
child 2612 d7fb0809c7e4
child 1511 65ddd8f149f3
equal deleted inserted replaced
0:fd16c54261b3 2:90ce3da70b43
       
     1 /*
       
     2  * Copyright 2005-2006 Sun Microsystems, Inc.  All Rights Reserved.
       
     3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
       
     4  *
       
     5  * This code is free software; you can redistribute it and/or modify it
       
     6  * under the terms of the GNU General Public License version 2 only, as
       
     7  * published by the Free Software Foundation.  Sun designates this
       
     8  * particular file as subject to the "Classpath" exception as provided
       
     9  * by Sun in the LICENSE file that accompanied this code.
       
    10  *
       
    11  * This code is distributed in the hope that it will be useful, but WITHOUT
       
    12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
       
    13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
       
    14  * version 2 for more details (a copy is included in the LICENSE file that
       
    15  * accompanied this code).
       
    16  *
       
    17  * You should have received a copy of the GNU General Public License version
       
    18  * 2 along with this work; if not, write to the Free Software Foundation,
       
    19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
       
    20  *
       
    21  * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
       
    22  * CA 95054 USA or visit www.sun.com if you need additional information or
       
    23  * have any questions.
       
    24  */
       
    25 
       
    26 package sun.net.httpserver;
       
    27 
       
    28 import java.util.*;
       
    29 import java.nio.*;
       
    30 import java.net.*;
       
    31 import java.io.*;
       
    32 import java.nio.channels.*;
       
    33 import com.sun.net.httpserver.*;
       
    34 import com.sun.net.httpserver.spi.*;
       
    35 
       
    36 /**
       
    37  */
       
    38 class Request {
       
    39 
       
    40     final static int BUF_LEN = 2048;
       
    41     final static byte CR = 13;
       
    42     final static byte LF = 10;
       
    43 
       
    44     private String startLine;
       
    45     private SocketChannel chan;
       
    46     private InputStream is;
       
    47     private OutputStream os;
       
    48 
       
    49     Request (InputStream rawInputStream, OutputStream rawout) throws IOException {
       
    50         this.chan = chan;
       
    51         is = rawInputStream;
       
    52         os = rawout;
       
    53         do {
       
    54             startLine = readLine();
       
    55             /* skip blank lines */
       
    56         } while (startLine.equals (""));
       
    57     }
       
    58 
       
    59 
       
    60     char[] buf = new char [BUF_LEN];
       
    61     int pos;
       
    62     StringBuffer lineBuf;
       
    63 
       
    64     public InputStream inputStream () {
       
    65         return is;
       
    66     }
       
    67 
       
    68     public OutputStream outputStream () {
       
    69         return os;
       
    70     }
       
    71 
       
    72     /**
       
    73      * read a line from the stream returning as a String.
       
    74      * Not used for reading headers.
       
    75      */
       
    76 
       
    77     public String readLine () throws IOException {
       
    78         boolean gotCR = false, gotLF = false;
       
    79         pos = 0; lineBuf = new StringBuffer();
       
    80         while (!gotLF) {
       
    81             int c = is.read();
       
    82             if (c == -1) {
       
    83                 return null;
       
    84             }
       
    85             if (gotCR) {
       
    86                 if (c == LF) {
       
    87                     gotLF = true;
       
    88                 } else {
       
    89                     gotCR = false;
       
    90                     consume (CR);
       
    91                     consume (c);
       
    92                 }
       
    93             } else {
       
    94                 if (c == CR) {
       
    95                     gotCR = true;
       
    96                 } else {
       
    97                     consume (c);
       
    98                 }
       
    99             }
       
   100         }
       
   101         lineBuf.append (buf, 0, pos);
       
   102         return new String (lineBuf);
       
   103     }
       
   104 
       
   105     private void consume (int c) {
       
   106         if (pos == BUF_LEN) {
       
   107             lineBuf.append (buf);
       
   108             pos = 0;
       
   109         }
       
   110         buf[pos++] = (char)c;
       
   111     }
       
   112 
       
   113     /**
       
   114      * returns the request line (first line of a request)
       
   115      */
       
   116     public String requestLine () {
       
   117         return startLine;
       
   118     }
       
   119 
       
   120     Headers hdrs = null;
       
   121 
       
   122     Headers headers () throws IOException {
       
   123         if (hdrs != null) {
       
   124             return hdrs;
       
   125         }
       
   126         hdrs = new Headers();
       
   127 
       
   128         char s[] = new char[10];
       
   129         int firstc = is.read();
       
   130         while (firstc != LF && firstc != CR && firstc >= 0) {
       
   131             int len = 0;
       
   132             int keyend = -1;
       
   133             int c;
       
   134             boolean inKey = firstc > ' ';
       
   135             s[len++] = (char) firstc;
       
   136     parseloop:{
       
   137                 while ((c = is.read()) >= 0) {
       
   138                     switch (c) {
       
   139                       case ':':
       
   140                         if (inKey && len > 0)
       
   141                             keyend = len;
       
   142                         inKey = false;
       
   143                         break;
       
   144                       case '\t':
       
   145                         c = ' ';
       
   146                       case ' ':
       
   147                         inKey = false;
       
   148                         break;
       
   149                       case CR:
       
   150                       case LF:
       
   151                         firstc = is.read();
       
   152                         if (c == CR && firstc == LF) {
       
   153                             firstc = is.read();
       
   154                             if (firstc == CR)
       
   155                                 firstc = is.read();
       
   156                         }
       
   157                         if (firstc == LF || firstc == CR || firstc > ' ')
       
   158                             break parseloop;
       
   159                         /* continuation */
       
   160                         c = ' ';
       
   161                         break;
       
   162                     }
       
   163                     if (len >= s.length) {
       
   164                         char ns[] = new char[s.length * 2];
       
   165                         System.arraycopy(s, 0, ns, 0, len);
       
   166                         s = ns;
       
   167                     }
       
   168                     s[len++] = (char) c;
       
   169                 }
       
   170                 firstc = -1;
       
   171             }
       
   172             while (len > 0 && s[len - 1] <= ' ')
       
   173                 len--;
       
   174             String k;
       
   175             if (keyend <= 0) {
       
   176                 k = null;
       
   177                 keyend = 0;
       
   178             } else {
       
   179                 k = String.copyValueOf(s, 0, keyend);
       
   180                 if (keyend < len && s[keyend] == ':')
       
   181                     keyend++;
       
   182                 while (keyend < len && s[keyend] <= ' ')
       
   183                     keyend++;
       
   184             }
       
   185             String v;
       
   186             if (keyend >= len)
       
   187                 v = new String();
       
   188             else
       
   189                 v = String.copyValueOf(s, keyend, len - keyend);
       
   190             hdrs.add (k,v);
       
   191         }
       
   192         return hdrs;
       
   193     }
       
   194 
       
   195     /**
       
   196      * Implements blocking reading semantics on top of a non-blocking channel
       
   197      */
       
   198 
       
   199     static class ReadStream extends InputStream {
       
   200         SocketChannel channel;
       
   201         SelectorCache sc;
       
   202         Selector selector;
       
   203         ByteBuffer chanbuf;
       
   204         SelectionKey key;
       
   205         int available;
       
   206         byte[] one;
       
   207         boolean closed = false, eof = false;
       
   208         ByteBuffer markBuf; /* reads may be satisifed from this buffer */
       
   209         boolean marked;
       
   210         boolean reset;
       
   211         int readlimit;
       
   212         static long readTimeout;
       
   213         ServerImpl server;
       
   214 
       
   215         static {
       
   216             readTimeout = ServerConfig.getReadTimeout();
       
   217         }
       
   218 
       
   219         public ReadStream (ServerImpl server, SocketChannel chan) throws IOException {
       
   220             this.channel = chan;
       
   221             this.server = server;
       
   222             sc = SelectorCache.getSelectorCache();
       
   223             selector = sc.getSelector();
       
   224             chanbuf = ByteBuffer.allocate (8* 1024);
       
   225             key = chan.register (selector, SelectionKey.OP_READ);
       
   226             available = 0;
       
   227             one = new byte[1];
       
   228             closed = marked = reset = false;
       
   229         }
       
   230 
       
   231         public synchronized int read (byte[] b) throws IOException {
       
   232             return read (b, 0, b.length);
       
   233         }
       
   234 
       
   235         public synchronized int read () throws IOException {
       
   236             int result = read (one, 0, 1);
       
   237             if (result == 1) {
       
   238                 return one[0] & 0xFF;
       
   239             } else {
       
   240                 return -1;
       
   241             }
       
   242         }
       
   243 
       
   244         public synchronized int read (byte[] b, int off, int srclen) throws IOException {
       
   245 
       
   246             int canreturn, willreturn;
       
   247 
       
   248             if (closed)
       
   249                 throw new IOException ("Stream closed");
       
   250 
       
   251             if (eof) {
       
   252                 return -1;
       
   253             }
       
   254 
       
   255             if (reset) { /* satisfy from markBuf */
       
   256                 canreturn = markBuf.remaining ();
       
   257                 willreturn = canreturn>srclen ? srclen : canreturn;
       
   258                 markBuf.get(b, off, willreturn);
       
   259                 if (canreturn == willreturn) {
       
   260                     reset = false;
       
   261                 }
       
   262             } else { /* satisfy from channel */
       
   263                 canreturn = available();
       
   264                 while (canreturn == 0 && !eof) {
       
   265                     block ();
       
   266                     canreturn = available();
       
   267                 }
       
   268                 if (eof) {
       
   269                     return -1;
       
   270                 }
       
   271                 willreturn = canreturn>srclen ? srclen : canreturn;
       
   272                 chanbuf.get(b, off, willreturn);
       
   273                 available -= willreturn;
       
   274 
       
   275                 if (marked) { /* copy into markBuf */
       
   276                     try {
       
   277                         markBuf.put (b, off, willreturn);
       
   278                     } catch (BufferOverflowException e) {
       
   279                         marked = false;
       
   280                     }
       
   281                 }
       
   282             }
       
   283             return willreturn;
       
   284         }
       
   285 
       
   286         public synchronized int available () throws IOException {
       
   287             if (closed)
       
   288                 throw new IOException ("Stream is closed");
       
   289 
       
   290             if (eof)
       
   291                 return -1;
       
   292 
       
   293             if (reset)
       
   294                 return markBuf.remaining();
       
   295 
       
   296             if (available > 0)
       
   297                 return available;
       
   298 
       
   299             chanbuf.clear ();
       
   300             available = channel.read (chanbuf);
       
   301             if (available > 0) {
       
   302                 chanbuf.flip();
       
   303             } else if (available == -1) {
       
   304                 eof = true;
       
   305                 available = 0;
       
   306             }
       
   307             return available;
       
   308         }
       
   309 
       
   310         /**
       
   311          * block() only called when available==0 and buf is empty
       
   312          */
       
   313         private synchronized void block () throws IOException {
       
   314             long currtime = server.getTime();
       
   315             long maxtime = currtime + readTimeout;
       
   316 
       
   317             while (currtime < maxtime) {
       
   318                 if (selector.select (readTimeout) == 1) {
       
   319                     selector.selectedKeys().clear();
       
   320                     available ();
       
   321                     return;
       
   322                 }
       
   323                 currtime = server.getTime();
       
   324             }
       
   325             throw new SocketTimeoutException ("no data received");
       
   326         }
       
   327 
       
   328         public void close () throws IOException {
       
   329             if (closed) {
       
   330                 return;
       
   331             }
       
   332             channel.close ();
       
   333             selector.selectNow();
       
   334             sc.freeSelector(selector);
       
   335             closed = true;
       
   336         }
       
   337 
       
   338         public synchronized void mark (int readlimit) {
       
   339             if (closed)
       
   340                 return;
       
   341             this.readlimit = readlimit;
       
   342             markBuf = ByteBuffer.allocate (readlimit);
       
   343             marked = true;
       
   344             reset = false;
       
   345         }
       
   346 
       
   347         public synchronized void reset () throws IOException {
       
   348             if (closed )
       
   349                 return;
       
   350             if (!marked)
       
   351                 throw new IOException ("Stream not marked");
       
   352             marked = false;
       
   353             reset = true;
       
   354             markBuf.flip ();
       
   355         }
       
   356     }
       
   357 
       
   358     static class WriteStream extends java.io.OutputStream {
       
   359         SocketChannel channel;
       
   360         ByteBuffer buf;
       
   361         SelectionKey key;
       
   362         SelectorCache sc;
       
   363         Selector selector;
       
   364         boolean closed;
       
   365         byte[] one;
       
   366         ServerImpl server;
       
   367         static long writeTimeout;
       
   368 
       
   369         static {
       
   370             writeTimeout = ServerConfig.getWriteTimeout();
       
   371         }
       
   372 
       
   373         public WriteStream (ServerImpl server, SocketChannel channel) throws IOException {
       
   374             this.channel = channel;
       
   375             this.server = server;
       
   376             sc = SelectorCache.getSelectorCache();
       
   377             selector = sc.getSelector();
       
   378             key = channel.register (selector, SelectionKey.OP_WRITE);
       
   379             closed = false;
       
   380             one = new byte [1];
       
   381             buf = ByteBuffer.allocate (4096);
       
   382         }
       
   383 
       
   384         public synchronized void write (int b) throws IOException {
       
   385             one[0] = (byte)b;
       
   386             write (one, 0, 1);
       
   387         }
       
   388 
       
   389         public synchronized void write (byte[] b) throws IOException {
       
   390             write (b, 0, b.length);
       
   391         }
       
   392 
       
   393         public synchronized void write (byte[] b, int off, int len) throws IOException {
       
   394             int l = len;
       
   395             if (closed)
       
   396                 throw new IOException ("stream is closed");
       
   397 
       
   398             int cap = buf.capacity();
       
   399             if (cap < len) {
       
   400                 int diff = len - cap;
       
   401                 buf = ByteBuffer.allocate (2*(cap+diff));
       
   402             }
       
   403             buf.clear();
       
   404             buf.put (b, off, len);
       
   405             buf.flip ();
       
   406             int n;
       
   407             while ((n = channel.write (buf)) < l) {
       
   408                 l -= n;
       
   409                 if (l == 0)
       
   410                     return;
       
   411                 block();
       
   412             }
       
   413         }
       
   414 
       
   415         void block () throws IOException {
       
   416             long currtime = server.getTime();
       
   417             long maxtime = currtime + writeTimeout;
       
   418 
       
   419             while (currtime < maxtime) {
       
   420                 if (selector.select (writeTimeout) == 1) {
       
   421                     selector.selectedKeys().clear ();
       
   422                     return;
       
   423                 }
       
   424                 currtime = server.getTime();
       
   425             }
       
   426             throw new SocketTimeoutException ("write blocked too long");
       
   427         }
       
   428 
       
   429 
       
   430         public void close () throws IOException {
       
   431             if (closed)
       
   432                 return;
       
   433             channel.close ();
       
   434             selector.selectNow();
       
   435             sc.freeSelector(selector);
       
   436             closed = true;
       
   437         }
       
   438     }
       
   439 }