History

My first initial commit with all of mine experimental changes.

Dmitry Kabak (userdima committed 13 years ago

Commit d37b88d1 parent 3f5b46618352 files · +2598093 −-8690Browse files

Showing the changes to java/pkg/sun/net/httpserver/ExchangeImpl.java (1 of 18352 files). Show all

Unified · Split

java/pkg/sun/net/httpserver/ExchangeImpl.java+456−0
@@ -0,0 +1,456 @@
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
26package sun.net.httpserver;
27
28import java.io.*;
29import java.net.*;
30import javax.net.ssl.*;
31import java.util.*;
32import java.util.logging.Logger;
33import java.text.*;
34import com.sun.net.httpserver.*;
35
36class ExchangeImpl {
37
38 Headers reqHdrs, rspHdrs;
39 Request req;
40 String method;
41 boolean writefinished;
42 URI uri;
43 HttpConnection connection;
44 long reqContentLen;
45 long rspContentLen;
46 /* raw streams which access the socket directly */
47 InputStream ris;
48 OutputStream ros;
49 Thread thread;
50 /* close the underlying connection when this exchange finished */
51 boolean close;
52 boolean closed;
53 boolean http10 = false;
54
55 /* for formatting the Date: header */
56 private static final String pattern = "EEE, dd MMM yyyy HH:mm:ss zzz";
57 private static final TimeZone gmtTZ = TimeZone.getTimeZone("GMT");
58 private static final ThreadLocal<DateFormat> dateFormat =
59 new ThreadLocal<DateFormat>() {
60 @Override protected DateFormat initialValue() {
61 DateFormat df = new SimpleDateFormat(pattern, Locale.US);
62 df.setTimeZone(gmtTZ);
63 return df;
64 }
65 };
66
67 private static final String HEAD = "HEAD";
68
69 /* streams which take care of the HTTP protocol framing
70 * and are passed up to higher layers
71 */
72 InputStream uis;
73 OutputStream uos;
74 LeftOverInputStream uis_orig; // uis may have be a user supplied wrapper
75 PlaceholderOutputStream uos_orig;
76
77 boolean sentHeaders; /* true after response headers sent */
78 Map<String,Object> attributes;
79 int rcode = -1;
80 HttpPrincipal principal;
81 ServerImpl server;
82
83 ExchangeImpl (
84 String m, URI u, Request req, long len, HttpConnection connection
85 ) throws IOException {
86 this.req = req;
87 this.reqHdrs = req.headers();
88 this.rspHdrs = new Headers();
89 this.method = m;
90 this.uri = u;
91 this.connection = connection;
92 this.reqContentLen = len;
93 /* ros only used for headers, body written directly to stream */
94 this.ros = req.outputStream();
95 this.ris = req.inputStream();
96 server = getServerImpl();
97 server.startExchange();
98 }
99
100 public Headers getRequestHeaders () {
101 return new UnmodifiableHeaders (reqHdrs);
102 }
103
104 public Headers getResponseHeaders () {
105 return rspHdrs;
106 }
107
108 public URI getRequestURI () {
109 return uri;
110 }
111
112 public String getRequestMethod (){
113 return method;
114 }
115
116 public HttpContextImpl getHttpContext (){
117 return connection.getHttpContext();
118 }
119
120 private boolean isHeadRequest() {
121 return HEAD.equals(getRequestMethod());
122 }
123
124 public void close () {
125 if (closed) {
126 return;
127 }
128 closed = true;
129
130 /* close the underlying connection if,
131 * a) the streams not set up yet, no response can be sent, or
132 * b) if the wrapper output stream is not set up, or
133 * c) if the close of the input/outpu stream fails
134 */
135 try {
136 if (uis_orig == null || uos == null) {
137 connection.close();
138 return;
139 }
140 if (!uos_orig.isWrapped()) {
141 connection.close();
142 return;
143 }
144 if (!uis_orig.isClosed()) {
145 uis_orig.close();
146 }
147 uos.close();
148 } catch (IOException e) {
149 connection.close();
150 }
151 }
152
153 public InputStream getRequestBody () {
154 if (uis != null) {
155 return uis;
156 }
157 if (reqContentLen == -1L) {
158 uis_orig = new ChunkedInputStream (this, ris);
159 uis = uis_orig;
160 } else {
161 uis_orig = new FixedLengthInputStream (this, ris, reqContentLen);
162 uis = uis_orig;
163 }
164 return uis;
165 }
166
167 LeftOverInputStream getOriginalInputStream () {
168 return uis_orig;
169 }
170
171 public int getResponseCode () {
172 return rcode;
173 }
174
175 public OutputStream getResponseBody () {
176 /* TODO. Change spec to remove restriction below. Filters
177 * cannot work with this restriction
178 *
179 * if (!sentHeaders) {
180 * throw new IllegalStateException ("headers not sent");
181 * }
182 */
183 if (uos == null) {
184 uos_orig = new PlaceholderOutputStream (null);
185 uos = uos_orig;
186 }
187 return uos;
188 }
189
190
191 /* returns the place holder stream, which is the stream
192 * returned from the 1st call to getResponseBody()
193 * The "real" ouputstream is then placed inside this
194 */
195 PlaceholderOutputStream getPlaceholderResponseBody () {
196 getResponseBody();
197 return uos_orig;
198 }
199
200 public void sendResponseHeaders (int rCode, long contentLen)
201 throws IOException
202 {
203 if (sentHeaders) {
204 throw new IOException ("headers already sent");
205 }
206 this.rcode = rCode;
207 String statusLine = "HTTP/1.1 "+rCode+Code.msg(rCode)+"\r\n";
208 OutputStream tmpout = new BufferedOutputStream (ros);
209 PlaceholderOutputStream o = getPlaceholderResponseBody();
210 tmpout.write (bytes(statusLine, 0), 0, statusLine.length());
211 boolean noContentToSend = false; // assume there is content
212 rspHdrs.set ("Date", dateFormat.get().format (new Date()));
213
214 /* check for response type that is not allowed to send a body */
215
216 if ((rCode>=100 && rCode <200) /* informational */
217 ||(rCode == 204) /* no content */
218 ||(rCode == 304)) /* not modified */
219 {
220 if (contentLen != -1) {
221 Logger logger = server.getLogger();
222 String msg = "sendResponseHeaders: rCode = "+ rCode
223 + ": forcing contentLen = -1";
224 logger.warning (msg);
225 }
226 contentLen = -1;
227 }
228
229 if (isHeadRequest()) {
230 /* HEAD requests should not set a content length by passing it
231 * through this API, but should instead manually set the required
232 * headers.*/
233 if (contentLen >= 0) {
234 final Logger logger = server.getLogger();
235 String msg =
236 "sendResponseHeaders: being invoked with a content length for a HEAD request";
237 logger.warning (msg);
238 }
239 noContentToSend = true;
240 contentLen = 0;
241 } else { /* not a HEAD request */
242 if (contentLen == 0) {
243 if (http10) {
244 o.setWrappedStream (new UndefLengthOutputStream (this, ros));
245 close = true;
246 } else {
247 rspHdrs.set ("Transfer-encoding", "chunked");
248 o.setWrappedStream (new ChunkedOutputStream (this, ros));
249 }
250 } else {
251 if (contentLen == -1) {
252 noContentToSend = true;
253 contentLen = 0;
254 }
255 rspHdrs.set("Content-length", Long.toString(contentLen));
256 o.setWrappedStream (new FixedLengthOutputStream (this, ros, contentLen));
257 }
258 }
259 write (rspHdrs, tmpout);
260 this.rspContentLen = contentLen;
261 tmpout.flush() ;
262 tmpout = null;
263 sentHeaders = true;
264 if (noContentToSend) {
265 WriteFinishedEvent e = new WriteFinishedEvent (this);
266 server.addEvent (e);
267 closed = true;
268 }
269 server.logReply (rCode, req.requestLine(), null);
270 }
271
272 void write (Headers map, OutputStream os) throws IOException {
273 Set<Map.Entry<String,List<String>>> entries = map.entrySet();
274 for (Map.Entry<String,List<String>> entry : entries) {
275 String key = entry.getKey();
276 byte[] buf;
277 List<String> values = entry.getValue();
278 for (String val : values) {
279 int i = key.length();
280 buf = bytes (key, 2);
281 buf[i++] = ':';
282 buf[i++] = ' ';
283 os.write (buf, 0, i);
284 buf = bytes (val, 2);
285 i = val.length();
286 buf[i++] = '\r';
287 buf[i++] = '\n';
288 os.write (buf, 0, i);
289 }
290 }
291 os.write ('\r');
292 os.write ('\n');
293 }
294
295 private byte[] rspbuf = new byte [128]; // used by bytes()
296
297 /**
298 * convert string to byte[], using rspbuf
299 * Make sure that at least "extra" bytes are free at end
300 * of rspbuf. Reallocate rspbuf if not big enough.
301 * caller must check return value to see if rspbuf moved
302 */
303 private byte[] bytes (String s, int extra) {
304 int slen = s.length();
305 if (slen+extra > rspbuf.length) {
306 int diff = slen + extra - rspbuf.length;
307 rspbuf = new byte [2* (rspbuf.length + diff)];
308 }
309 char c[] = s.toCharArray();
310 for (int i=0; i<c.length; i++) {
311 rspbuf[i] = (byte)c[i];
312 }
313 return rspbuf;
314 }
315
316 public InetSocketAddress getRemoteAddress (){
317 Socket s = connection.getChannel().socket();
318 InetAddress ia = s.getInetAddress();
319 int port = s.getPort();
320 return new InetSocketAddress (ia, port);
321 }
322
323 public InetSocketAddress getLocalAddress (){
324 Socket s = connection.getChannel().socket();
325 InetAddress ia = s.getLocalAddress();
326 int port = s.getLocalPort();
327 return new InetSocketAddress (ia, port);
328 }
329
330 public String getProtocol (){
331 String reqline = req.requestLine();
332 int index = reqline.lastIndexOf (' ');
333 return reqline.substring (index+1);
334 }
335
336 public SSLSession getSSLSession () {
337 SSLEngine e = connection.getSSLEngine();
338 if (e == null) {
339 return null;
340 }
341 return e.getSession();
342 }
343
344 public Object getAttribute (String name) {
345 if (name == null) {
346 throw new NullPointerException ("null name parameter");
347 }
348 if (attributes == null) {
349 attributes = getHttpContext().getAttributes();
350 }
351 return attributes.get (name);
352 }
353
354 public void setAttribute (String name, Object value) {
355 if (name == null) {
356 throw new NullPointerException ("null name parameter");
357 }
358 if (attributes == null) {
359 attributes = getHttpContext().getAttributes();
360 }
361 attributes.put (name, value);
362 }
363
364 public void setStreams (InputStream i, OutputStream o) {
365 assert uis != null;
366 if (i != null) {
367 uis = i;
368 }
369 if (o != null) {
370 uos = o;
371 }
372 }
373
374 /**
375 * PP
376 */
377 HttpConnection getConnection () {
378 return connection;
379 }
380
381 ServerImpl getServerImpl () {
382 return getHttpContext().getServerImpl();
383 }
384
385 public HttpPrincipal getPrincipal () {
386 return principal;
387 }
388
389 void setPrincipal (HttpPrincipal principal) {
390 this.principal = principal;
391 }
392
393 static ExchangeImpl get (HttpExchange t) {
394 if (t instanceof HttpExchangeImpl) {
395 return ((HttpExchangeImpl)t).getExchangeImpl();
396 } else {
397 assert t instanceof HttpsExchangeImpl;
398 return ((HttpsExchangeImpl)t).getExchangeImpl();
399 }
400 }
401}
402
403/**
404 * An OutputStream which wraps another stream
405 * which is supplied either at creation time, or sometime later.
406 * If a caller/user tries to write to this stream before
407 * the wrapped stream has been provided, then an IOException will
408 * be thrown.
409 */
410class PlaceholderOutputStream extends java.io.OutputStream {
411
412 OutputStream wrapped;
413
414 PlaceholderOutputStream (OutputStream os) {
415 wrapped = os;
416 }
417
418 void setWrappedStream (OutputStream os) {
419 wrapped = os;
420 }
421
422 boolean isWrapped () {
423 return wrapped != null;
424 }
425
426 private void checkWrap () throws IOException {
427 if (wrapped == null) {
428 throw new IOException ("response headers not sent yet");
429 }
430 }
431
432 public void write(int b) throws IOException {
433 checkWrap();
434 wrapped.write (b);
435 }
436
437 public void write(byte b[]) throws IOException {
438 checkWrap();
439 wrapped.write (b);
440 }
441
442 public void write(byte b[], int off, int len) throws IOException {
443 checkWrap();
444 wrapped.write (b, off, len);
445 }
446
447 public void flush() throws IOException {
448 checkWrap();
449 wrapped.flush();
450 }
451
452 public void close() throws IOException {
453 checkWrap();
454 wrapped.close();
455 }
456}