Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
PojavLauncherTeam
GitHub Repository: PojavLauncherTeam/openjdk-multiarch-jdk8u
Path: blob/aarch64-shenandoah-jdk8u272-b10/jdk/src/share/classes/sun/net/httpserver/ExchangeImpl.java
38918 views
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.io.*;
29
import java.net.*;
30
import javax.net.ssl.*;
31
import java.util.*;
32
import java.util.logging.Logger;
33
import java.text.*;
34
import com.sun.net.httpserver.*;
35
36
class 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
*/
410
class 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
}
457
458