1 /* 2 * Copyright (c) 2005, 2010, Oracle and/or its affiliates. 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. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * 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 if (startLine == null) { 56 return; 57 } 58 /* skip blank lines */ 59 } while (startLine == null ? false : startLine.equals ("")); 60 } 61 62 63 char[] buf = new char [BUF_LEN]; 64 int pos; 65 StringBuffer lineBuf; 66 67 public InputStream inputStream () { 68 return is; 69 } 70 71 public OutputStream outputStream () { 72 return os; 73 } 74 75 /** 76 * read a line from the stream returning as a String. 77 * Not used for reading headers. 78 */ 79 80 public String readLine () throws IOException { 81 boolean gotCR = false, gotLF = false; 82 pos = 0; lineBuf = new StringBuffer(); 83 while (!gotLF) { 84 int c = is.read(); 85 if (c == -1) { 86 return null; 87 } 88 if (gotCR) { 89 if (c == LF) { 90 gotLF = true; 91 } else { 92 gotCR = false; 93 consume (CR); 94 consume (c); 95 } 96 } else { 97 if (c == CR) { 98 gotCR = true; 99 } else { 100 consume (c); 101 } 102 } 103 } 104 lineBuf.append (buf, 0, pos); 105 return new String (lineBuf); 106 } 107 108 private void consume (int c) { 109 if (pos == BUF_LEN) { 110 lineBuf.append (buf); 111 pos = 0; 112 } 113 buf[pos++] = (char)c; 114 } 115 116 /** 117 * returns the request line (first line of a request) 118 */ 119 public String requestLine () { 120 return startLine; 121 } 122 123 Headers hdrs = null; 124 125 Headers headers () throws IOException { 126 if (hdrs != null) { 127 return hdrs; 128 } 129 hdrs = new Headers(); 130 131 char s[] = new char[10]; 132 int len = 0; 133 134 int firstc = is.read(); 135 136 // check for empty headers 137 if (firstc == CR || firstc == LF) { 138 int c = is.read(); 139 if (c == CR || c == LF) { 140 return hdrs; 141 } 142 s[0] = (char)firstc; 143 len = 1; 144 firstc = c; 145 } 146 147 while (firstc != LF && firstc != CR && firstc >= 0) { 148 int keyend = -1; 149 int c; 150 boolean inKey = firstc > ' '; 151 s[len++] = (char) firstc; 152 parseloop:{ 153 while ((c = is.read()) >= 0) { 154 switch (c) { 155 case ':': 156 if (inKey && len > 0) 157 keyend = len; 158 inKey = false; 159 break; 160 case '\t': 161 c = ' '; 162 case ' ': 163 inKey = false; 164 break; 165 case CR: 166 case LF: 167 firstc = is.read(); 168 if (c == CR && firstc == LF) { 169 firstc = is.read(); 170 if (firstc == CR) 171 firstc = is.read(); 172 } 173 if (firstc == LF || firstc == CR || firstc > ' ') 174 break parseloop; 175 /* continuation */ 176 c = ' '; 177 break; 178 } 179 if (len >= s.length) { 180 char ns[] = new char[s.length * 2]; 181 System.arraycopy(s, 0, ns, 0, len); 182 s = ns; 183 } 184 s[len++] = (char) c; 185 } 186 firstc = -1; 187 } 188 while (len > 0 && s[len - 1] <= ' ') 189 len--; 190 String k; 191 if (keyend <= 0) { 192 k = null; 193 keyend = 0; 194 } else { 195 k = String.copyValueOf(s, 0, keyend); 196 if (keyend < len && s[keyend] == ':') 197 keyend++; 198 while (keyend < len && s[keyend] <= ' ') 199 keyend++; 200 } 201 String v; 202 if (keyend >= len) 203 v = new String(); 204 else 205 v = String.copyValueOf(s, keyend, len - keyend); 206 hdrs.add (k,v); 207 len = 0; 208 } 209 return hdrs; 210 } 211 212 /** 213 * Implements blocking reading semantics on top of a non-blocking channel 214 */ 215 216 static class ReadStream extends InputStream { 217 SocketChannel channel; 218 ByteBuffer chanbuf; 219 byte[] one; 220 private boolean closed = false, eof = false; 221 ByteBuffer markBuf; /* reads may be satisifed from this buffer */ 222 boolean marked; 223 boolean reset; 224 int readlimit; 225 static long readTimeout; 226 ServerImpl server; 227 final static int BUFSIZE = 8 * 1024; 228 229 public ReadStream (ServerImpl server, SocketChannel chan) throws IOException { 230 this.channel = chan; 231 this.server = server; 232 chanbuf = ByteBuffer.allocate (BUFSIZE); 233 chanbuf.clear(); 234 one = new byte[1]; 235 closed = marked = reset = false; 236 } 237 238 public synchronized int read (byte[] b) throws IOException { 239 return read (b, 0, b.length); 240 } 241 242 public synchronized int read () throws IOException { 243 int result = read (one, 0, 1); 244 if (result == 1) { 245 return one[0] & 0xFF; 246 } else { 247 return -1; 248 } 249 } 250 251 public synchronized int read (byte[] b, int off, int srclen) throws IOException { 252 253 int canreturn, willreturn; 254 255 if (closed) 256 throw new IOException ("Stream closed"); 257 258 if (eof) { 259 return -1; 260 } 261 262 assert channel.isBlocking(); 263 264 if (off < 0 || srclen < 0|| srclen > (b.length-off)) { 265 throw new IndexOutOfBoundsException (); 266 } 267 268 if (reset) { /* satisfy from markBuf */ 269 canreturn = markBuf.remaining (); 270 willreturn = canreturn>srclen ? srclen : canreturn; 271 markBuf.get(b, off, willreturn); 272 if (canreturn == willreturn) { 273 reset = false; 274 } 275 } else { /* satisfy from channel */ 276 chanbuf.clear (); 277 if (srclen < BUFSIZE) { 278 chanbuf.limit (srclen); 279 } 280 do { 281 willreturn = channel.read (chanbuf); 282 } while (willreturn == 0); 283 if (willreturn == -1) { 284 eof = true; 285 return -1; 286 } 287 chanbuf.flip (); 288 chanbuf.get(b, off, willreturn); 289 290 if (marked) { /* copy into markBuf */ 291 try { 292 markBuf.put (b, off, willreturn); 293 } catch (BufferOverflowException e) { 294 marked = false; 295 } 296 } 297 } 298 return willreturn; 299 } 300 301 public boolean markSupported () { 302 return true; 303 } 304 305 /* Does not query the OS socket */ 306 public synchronized int available () throws IOException { 307 if (closed) 308 throw new IOException ("Stream is closed"); 309 310 if (eof) 311 return -1; 312 313 if (reset) 314 return markBuf.remaining(); 315 316 return chanbuf.remaining(); 317 } 318 319 public void close () throws IOException { 320 if (closed) { 321 return; 322 } 323 channel.close (); 324 closed = true; 325 } 326 327 public synchronized void mark (int readlimit) { 328 if (closed) 329 return; 330 this.readlimit = readlimit; 331 markBuf = ByteBuffer.allocate (readlimit); 332 marked = true; 333 reset = false; 334 } 335 336 public synchronized void reset () throws IOException { 337 if (closed ) 338 return; 339 if (!marked) 340 throw new IOException ("Stream not marked"); 341 marked = false; 342 reset = true; 343 markBuf.flip (); 344 } 345 } 346 347 static class WriteStream extends java.io.OutputStream { 348 SocketChannel channel; 349 ByteBuffer buf; 350 SelectionKey key; 351 boolean closed; 352 byte[] one; 353 ServerImpl server; 354 355 public WriteStream (ServerImpl server, SocketChannel channel) throws IOException { 356 this.channel = channel; 357 this.server = server; 358 assert channel.isBlocking(); 359 closed = false; 360 one = new byte [1]; 361 buf = ByteBuffer.allocate (4096); 362 } 363 364 public synchronized void write (int b) throws IOException { 365 one[0] = (byte)b; 366 write (one, 0, 1); 367 } 368 369 public synchronized void write (byte[] b) throws IOException { 370 write (b, 0, b.length); 371 } 372 373 public synchronized void write (byte[] b, int off, int len) throws IOException { 374 int l = len; 375 if (closed) 376 throw new IOException ("stream is closed"); 377 378 int cap = buf.capacity(); 379 if (cap < len) { 380 int diff = len - cap; 381 buf = ByteBuffer.allocate (2*(cap+diff)); 382 } 383 buf.clear(); 384 buf.put (b, off, len); 385 buf.flip (); 386 int n; 387 while ((n = channel.write (buf)) < l) { 388 l -= n; 389 if (l == 0) 390 return; 391 } 392 } 393 394 public void close () throws IOException { 395 if (closed) 396 return; 397 //server.logStackTrace ("Request.OS.close: isOpen="+channel.isOpen()); 398 channel.close (); 399 closed = true; 400 } 401 } 402 }