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