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/ServerImpl.java
38918 views
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.net.*;
29
import java.io.*;
30
import java.nio.channels.*;
31
import java.util.*;
32
import java.util.concurrent.*;
33
import java.util.logging.Logger;
34
import java.util.logging.Level;
35
import javax.net.ssl.*;
36
import com.sun.net.httpserver.*;
37
import java.security.AccessController;
38
import java.security.PrivilegedAction;
39
import sun.net.httpserver.HttpConnection.State;
40
41
/**
42
* Provides implementation for both HTTP and HTTPS
43
*/
44
class ServerImpl implements TimeSource {
45
46
private String protocol;
47
private boolean https;
48
private Executor executor;
49
private HttpsConfigurator httpsConfig;
50
private SSLContext sslContext;
51
private ContextList contexts;
52
private InetSocketAddress address;
53
private ServerSocketChannel schan;
54
private Selector selector;
55
private SelectionKey listenerKey;
56
private Set<HttpConnection> idleConnections;
57
private Set<HttpConnection> allConnections;
58
/* following two are used to keep track of the times
59
* when a connection/request is first received
60
* and when we start to send the response
61
*/
62
private Set<HttpConnection> reqConnections;
63
private Set<HttpConnection> rspConnections;
64
private List<Event> events;
65
private Object lolock = new Object();
66
private volatile boolean finished = false;
67
private volatile boolean terminating = false;
68
private boolean bound = false;
69
private boolean started = false;
70
private volatile long time; /* current time */
71
private volatile long subticks = 0;
72
private volatile long ticks; /* number of clock ticks since server started */
73
private HttpServer wrapper;
74
75
final static int CLOCK_TICK = ServerConfig.getClockTick();
76
final static long IDLE_INTERVAL = ServerConfig.getIdleInterval();
77
final static int MAX_IDLE_CONNECTIONS = ServerConfig.getMaxIdleConnections();
78
final static long TIMER_MILLIS = ServerConfig.getTimerMillis ();
79
final static long MAX_REQ_TIME=getTimeMillis(ServerConfig.getMaxReqTime());
80
final static long MAX_RSP_TIME=getTimeMillis(ServerConfig.getMaxRspTime());
81
final static boolean timer1Enabled = MAX_REQ_TIME != -1 || MAX_RSP_TIME != -1;
82
83
private Timer timer, timer1;
84
private Logger logger;
85
86
ServerImpl (
87
HttpServer wrapper, String protocol, InetSocketAddress addr, int backlog
88
) throws IOException {
89
90
this.protocol = protocol;
91
this.wrapper = wrapper;
92
this.logger = Logger.getLogger ("com.sun.net.httpserver");
93
ServerConfig.checkLegacyProperties (logger);
94
https = protocol.equalsIgnoreCase ("https");
95
this.address = addr;
96
contexts = new ContextList();
97
schan = ServerSocketChannel.open();
98
if (addr != null) {
99
ServerSocket socket = schan.socket();
100
socket.bind (addr, backlog);
101
bound = true;
102
}
103
selector = Selector.open ();
104
schan.configureBlocking (false);
105
listenerKey = schan.register (selector, SelectionKey.OP_ACCEPT);
106
dispatcher = new Dispatcher();
107
idleConnections = Collections.synchronizedSet (new HashSet<HttpConnection>());
108
allConnections = Collections.synchronizedSet (new HashSet<HttpConnection>());
109
reqConnections = Collections.synchronizedSet (new HashSet<HttpConnection>());
110
rspConnections = Collections.synchronizedSet (new HashSet<HttpConnection>());
111
time = System.currentTimeMillis();
112
timer = new Timer ("server-timer", true);
113
timer.schedule (new ServerTimerTask(), CLOCK_TICK, CLOCK_TICK);
114
if (timer1Enabled) {
115
timer1 = new Timer ("server-timer1", true);
116
timer1.schedule (new ServerTimerTask1(),TIMER_MILLIS,TIMER_MILLIS);
117
logger.config ("HttpServer timer1 enabled period in ms: "+TIMER_MILLIS);
118
logger.config ("MAX_REQ_TIME: "+MAX_REQ_TIME);
119
logger.config ("MAX_RSP_TIME: "+MAX_RSP_TIME);
120
}
121
events = new LinkedList<Event>();
122
logger.config ("HttpServer created "+protocol+" "+ addr);
123
}
124
125
public void bind (InetSocketAddress addr, int backlog) throws IOException {
126
if (bound) {
127
throw new BindException ("HttpServer already bound");
128
}
129
if (addr == null) {
130
throw new NullPointerException ("null address");
131
}
132
ServerSocket socket = schan.socket();
133
socket.bind (addr, backlog);
134
bound = true;
135
}
136
137
public void start () {
138
if (!bound || started || finished) {
139
throw new IllegalStateException ("server in wrong state");
140
}
141
if (executor == null) {
142
executor = new DefaultExecutor();
143
}
144
Thread t = new Thread (dispatcher);
145
started = true;
146
t.start();
147
}
148
149
public void setExecutor (Executor executor) {
150
if (started) {
151
throw new IllegalStateException ("server already started");
152
}
153
this.executor = executor;
154
}
155
156
private static class DefaultExecutor implements Executor {
157
public void execute (Runnable task) {
158
task.run();
159
}
160
}
161
162
public Executor getExecutor () {
163
return executor;
164
}
165
166
public void setHttpsConfigurator (HttpsConfigurator config) {
167
if (config == null) {
168
throw new NullPointerException ("null HttpsConfigurator");
169
}
170
if (started) {
171
throw new IllegalStateException ("server already started");
172
}
173
this.httpsConfig = config;
174
sslContext = config.getSSLContext();
175
}
176
177
public HttpsConfigurator getHttpsConfigurator () {
178
return httpsConfig;
179
}
180
181
public void stop (int delay) {
182
if (delay < 0) {
183
throw new IllegalArgumentException ("negative delay parameter");
184
}
185
terminating = true;
186
try { schan.close(); } catch (IOException e) {}
187
selector.wakeup();
188
long latest = System.currentTimeMillis() + delay * 1000;
189
while (System.currentTimeMillis() < latest) {
190
delay();
191
if (finished) {
192
break;
193
}
194
}
195
finished = true;
196
selector.wakeup();
197
synchronized (allConnections) {
198
for (HttpConnection c : allConnections) {
199
c.close();
200
}
201
}
202
allConnections.clear();
203
idleConnections.clear();
204
timer.cancel();
205
if (timer1Enabled) {
206
timer1.cancel();
207
}
208
}
209
210
Dispatcher dispatcher;
211
212
public synchronized HttpContextImpl createContext (String path, HttpHandler handler) {
213
if (handler == null || path == null) {
214
throw new NullPointerException ("null handler, or path parameter");
215
}
216
HttpContextImpl context = new HttpContextImpl (protocol, path, handler, this);
217
contexts.add (context);
218
logger.config ("context created: " + path);
219
return context;
220
}
221
222
public synchronized HttpContextImpl createContext (String path) {
223
if (path == null) {
224
throw new NullPointerException ("null path parameter");
225
}
226
HttpContextImpl context = new HttpContextImpl (protocol, path, null, this);
227
contexts.add (context);
228
logger.config ("context created: " + path);
229
return context;
230
}
231
232
public synchronized void removeContext (String path) throws IllegalArgumentException {
233
if (path == null) {
234
throw new NullPointerException ("null path parameter");
235
}
236
contexts.remove (protocol, path);
237
logger.config ("context removed: " + path);
238
}
239
240
public synchronized void removeContext (HttpContext context) throws IllegalArgumentException {
241
if (!(context instanceof HttpContextImpl)) {
242
throw new IllegalArgumentException ("wrong HttpContext type");
243
}
244
contexts.remove ((HttpContextImpl)context);
245
logger.config ("context removed: " + context.getPath());
246
}
247
248
public InetSocketAddress getAddress() {
249
return AccessController.doPrivileged(
250
new PrivilegedAction<InetSocketAddress>() {
251
public InetSocketAddress run() {
252
return
253
(InetSocketAddress)schan.socket()
254
.getLocalSocketAddress();
255
}
256
});
257
}
258
259
Selector getSelector () {
260
return selector;
261
}
262
263
void addEvent (Event r) {
264
synchronized (lolock) {
265
events.add (r);
266
selector.wakeup();
267
}
268
}
269
270
/* main server listener task */
271
272
class Dispatcher implements Runnable {
273
274
private void handleEvent (Event r) {
275
ExchangeImpl t = r.exchange;
276
HttpConnection c = t.getConnection();
277
try {
278
if (r instanceof WriteFinishedEvent) {
279
280
int exchanges = endExchange();
281
if (terminating && exchanges == 0) {
282
finished = true;
283
}
284
responseCompleted (c);
285
LeftOverInputStream is = t.getOriginalInputStream();
286
if (!is.isEOF()) {
287
t.close = true;
288
}
289
if (t.close || idleConnections.size() >= MAX_IDLE_CONNECTIONS) {
290
c.close();
291
allConnections.remove (c);
292
} else {
293
if (is.isDataBuffered()) {
294
/* don't re-enable the interestops, just handle it */
295
requestStarted (c);
296
handle (c.getChannel(), c);
297
} else {
298
connsToRegister.add (c);
299
}
300
}
301
}
302
} catch (IOException e) {
303
logger.log (
304
Level.FINER, "Dispatcher (1)", e
305
);
306
c.close();
307
}
308
}
309
310
final LinkedList<HttpConnection> connsToRegister =
311
new LinkedList<HttpConnection>();
312
313
void reRegister (HttpConnection c) {
314
/* re-register with selector */
315
try {
316
SocketChannel chan = c.getChannel();
317
chan.configureBlocking (false);
318
SelectionKey key = chan.register (selector, SelectionKey.OP_READ);
319
key.attach (c);
320
c.selectionKey = key;
321
c.time = getTime() + IDLE_INTERVAL;
322
idleConnections.add (c);
323
} catch (IOException e) {
324
dprint(e);
325
logger.log(Level.FINER, "Dispatcher(8)", e);
326
c.close();
327
}
328
}
329
330
public void run() {
331
while (!finished) {
332
try {
333
List<Event> list = null;
334
synchronized (lolock) {
335
if (events.size() > 0) {
336
list = events;
337
events = new LinkedList<Event>();
338
}
339
}
340
341
if (list != null) {
342
for (Event r: list) {
343
handleEvent (r);
344
}
345
}
346
347
for (HttpConnection c : connsToRegister) {
348
reRegister(c);
349
}
350
connsToRegister.clear();
351
352
selector.select(1000);
353
354
/* process the selected list now */
355
Set<SelectionKey> selected = selector.selectedKeys();
356
Iterator<SelectionKey> iter = selected.iterator();
357
while (iter.hasNext()) {
358
SelectionKey key = iter.next();
359
iter.remove ();
360
if (key.equals (listenerKey)) {
361
if (terminating) {
362
continue;
363
}
364
SocketChannel chan = schan.accept();
365
366
// Set TCP_NODELAY, if appropriate
367
if (ServerConfig.noDelay()) {
368
chan.socket().setTcpNoDelay(true);
369
}
370
371
if (chan == null) {
372
continue; /* cancel something ? */
373
}
374
chan.configureBlocking (false);
375
SelectionKey newkey = chan.register (selector, SelectionKey.OP_READ);
376
HttpConnection c = new HttpConnection ();
377
c.selectionKey = newkey;
378
c.setChannel (chan);
379
newkey.attach (c);
380
requestStarted (c);
381
allConnections.add (c);
382
} else {
383
try {
384
if (key.isReadable()) {
385
boolean closed;
386
SocketChannel chan = (SocketChannel)key.channel();
387
HttpConnection conn = (HttpConnection)key.attachment();
388
389
key.cancel();
390
chan.configureBlocking (true);
391
if (idleConnections.remove(conn)) {
392
// was an idle connection so add it
393
// to reqConnections set.
394
requestStarted (conn);
395
}
396
handle (chan, conn);
397
} else {
398
assert false;
399
}
400
} catch (CancelledKeyException e) {
401
handleException(key, null);
402
} catch (IOException e) {
403
handleException(key, e);
404
}
405
}
406
}
407
// call the selector just to process the cancelled keys
408
selector.selectNow();
409
} catch (IOException e) {
410
logger.log (Level.FINER, "Dispatcher (4)", e);
411
} catch (Exception e) {
412
logger.log (Level.FINER, "Dispatcher (7)", e);
413
}
414
}
415
try {selector.close(); } catch (Exception e) {}
416
}
417
418
private void handleException (SelectionKey key, Exception e) {
419
HttpConnection conn = (HttpConnection)key.attachment();
420
if (e != null) {
421
logger.log (Level.FINER, "Dispatcher (2)", e);
422
}
423
closeConnection(conn);
424
}
425
426
public void handle (SocketChannel chan, HttpConnection conn)
427
throws IOException
428
{
429
try {
430
Exchange t = new Exchange (chan, protocol, conn);
431
executor.execute (t);
432
} catch (HttpError e1) {
433
logger.log (Level.FINER, "Dispatcher (4)", e1);
434
closeConnection(conn);
435
} catch (IOException e) {
436
logger.log (Level.FINER, "Dispatcher (5)", e);
437
closeConnection(conn);
438
}
439
}
440
}
441
442
static boolean debug = ServerConfig.debugEnabled ();
443
444
static synchronized void dprint (String s) {
445
if (debug) {
446
System.out.println (s);
447
}
448
}
449
450
static synchronized void dprint (Exception e) {
451
if (debug) {
452
System.out.println (e);
453
e.printStackTrace();
454
}
455
}
456
457
Logger getLogger () {
458
return logger;
459
}
460
461
private void closeConnection(HttpConnection conn) {
462
conn.close();
463
allConnections.remove(conn);
464
switch (conn.getState()) {
465
case REQUEST:
466
reqConnections.remove(conn);
467
break;
468
case RESPONSE:
469
rspConnections.remove(conn);
470
break;
471
case IDLE:
472
idleConnections.remove(conn);
473
break;
474
}
475
assert !reqConnections.remove(conn);
476
assert !rspConnections.remove(conn);
477
assert !idleConnections.remove(conn);
478
}
479
480
/* per exchange task */
481
482
class Exchange implements Runnable {
483
SocketChannel chan;
484
HttpConnection connection;
485
HttpContextImpl context;
486
InputStream rawin;
487
OutputStream rawout;
488
String protocol;
489
ExchangeImpl tx;
490
HttpContextImpl ctx;
491
boolean rejected = false;
492
493
Exchange (SocketChannel chan, String protocol, HttpConnection conn) throws IOException {
494
this.chan = chan;
495
this.connection = conn;
496
this.protocol = protocol;
497
}
498
499
public void run () {
500
/* context will be null for new connections */
501
context = connection.getHttpContext();
502
boolean newconnection;
503
SSLEngine engine = null;
504
String requestLine = null;
505
SSLStreams sslStreams = null;
506
try {
507
if (context != null ) {
508
this.rawin = connection.getInputStream();
509
this.rawout = connection.getRawOutputStream();
510
newconnection = false;
511
} else {
512
/* figure out what kind of connection this is */
513
newconnection = true;
514
if (https) {
515
if (sslContext == null) {
516
logger.warning ("SSL connection received. No https contxt created");
517
throw new HttpError ("No SSL context established");
518
}
519
sslStreams = new SSLStreams (ServerImpl.this, sslContext, chan);
520
rawin = sslStreams.getInputStream();
521
rawout = sslStreams.getOutputStream();
522
engine = sslStreams.getSSLEngine();
523
connection.sslStreams = sslStreams;
524
} else {
525
rawin = new BufferedInputStream(
526
new Request.ReadStream (
527
ServerImpl.this, chan
528
));
529
rawout = new Request.WriteStream (
530
ServerImpl.this, chan
531
);
532
}
533
connection.raw = rawin;
534
connection.rawout = rawout;
535
}
536
Request req = new Request (rawin, rawout);
537
requestLine = req.requestLine();
538
if (requestLine == null) {
539
/* connection closed */
540
closeConnection(connection);
541
return;
542
}
543
int space = requestLine.indexOf (' ');
544
if (space == -1) {
545
reject (Code.HTTP_BAD_REQUEST,
546
requestLine, "Bad request line");
547
return;
548
}
549
String method = requestLine.substring (0, space);
550
int start = space+1;
551
space = requestLine.indexOf(' ', start);
552
if (space == -1) {
553
reject (Code.HTTP_BAD_REQUEST,
554
requestLine, "Bad request line");
555
return;
556
}
557
String uriStr = requestLine.substring (start, space);
558
URI uri = new URI (uriStr);
559
start = space+1;
560
String version = requestLine.substring (start);
561
Headers headers = req.headers();
562
String s = headers.getFirst ("Transfer-encoding");
563
long clen = 0L;
564
if (s !=null && s.equalsIgnoreCase ("chunked")) {
565
clen = -1L;
566
} else {
567
s = headers.getFirst ("Content-Length");
568
if (s != null) {
569
clen = Long.parseLong(s);
570
}
571
if (clen == 0) {
572
requestCompleted (connection);
573
}
574
}
575
ctx = contexts.findContext (protocol, uri.getPath());
576
if (ctx == null) {
577
reject (Code.HTTP_NOT_FOUND,
578
requestLine, "No context found for request");
579
return;
580
}
581
connection.setContext (ctx);
582
if (ctx.getHandler() == null) {
583
reject (Code.HTTP_INTERNAL_ERROR,
584
requestLine, "No handler for context");
585
return;
586
}
587
tx = new ExchangeImpl (
588
method, uri, req, clen, connection
589
);
590
String chdr = headers.getFirst("Connection");
591
Headers rheaders = tx.getResponseHeaders();
592
593
if (chdr != null && chdr.equalsIgnoreCase ("close")) {
594
tx.close = true;
595
}
596
if (version.equalsIgnoreCase ("http/1.0")) {
597
tx.http10 = true;
598
if (chdr == null) {
599
tx.close = true;
600
rheaders.set ("Connection", "close");
601
} else if (chdr.equalsIgnoreCase ("keep-alive")) {
602
rheaders.set ("Connection", "keep-alive");
603
int idle=(int)(ServerConfig.getIdleInterval()/1000);
604
int max=ServerConfig.getMaxIdleConnections();
605
String val = "timeout="+idle+", max="+max;
606
rheaders.set ("Keep-Alive", val);
607
}
608
}
609
610
if (newconnection) {
611
connection.setParameters (
612
rawin, rawout, chan, engine, sslStreams,
613
sslContext, protocol, ctx, rawin
614
);
615
}
616
/* check if client sent an Expect 100 Continue.
617
* In that case, need to send an interim response.
618
* In future API may be modified to allow app to
619
* be involved in this process.
620
*/
621
String exp = headers.getFirst("Expect");
622
if (exp != null && exp.equalsIgnoreCase ("100-continue")) {
623
logReply (100, requestLine, null);
624
sendReply (
625
Code.HTTP_CONTINUE, false, null
626
);
627
}
628
/* uf is the list of filters seen/set by the user.
629
* sf is the list of filters established internally
630
* and which are not visible to the user. uc and sc
631
* are the corresponding Filter.Chains.
632
* They are linked together by a LinkHandler
633
* so that they can both be invoked in one call.
634
*/
635
List<Filter> sf = ctx.getSystemFilters();
636
List<Filter> uf = ctx.getFilters();
637
638
Filter.Chain sc = new Filter.Chain(sf, ctx.getHandler());
639
Filter.Chain uc = new Filter.Chain(uf, new LinkHandler (sc));
640
641
/* set up the two stream references */
642
tx.getRequestBody();
643
tx.getResponseBody();
644
if (https) {
645
uc.doFilter (new HttpsExchangeImpl (tx));
646
} else {
647
uc.doFilter (new HttpExchangeImpl (tx));
648
}
649
650
} catch (IOException e1) {
651
logger.log (Level.FINER, "ServerImpl.Exchange (1)", e1);
652
closeConnection(connection);
653
} catch (NumberFormatException e3) {
654
reject (Code.HTTP_BAD_REQUEST,
655
requestLine, "NumberFormatException thrown");
656
} catch (URISyntaxException e) {
657
reject (Code.HTTP_BAD_REQUEST,
658
requestLine, "URISyntaxException thrown");
659
} catch (Exception e4) {
660
logger.log (Level.FINER, "ServerImpl.Exchange (2)", e4);
661
closeConnection(connection);
662
}
663
}
664
665
/* used to link to 2 or more Filter.Chains together */
666
667
class LinkHandler implements HttpHandler {
668
Filter.Chain nextChain;
669
670
LinkHandler (Filter.Chain nextChain) {
671
this.nextChain = nextChain;
672
}
673
674
public void handle (HttpExchange exchange) throws IOException {
675
nextChain.doFilter (exchange);
676
}
677
}
678
679
void reject (int code, String requestStr, String message) {
680
rejected = true;
681
logReply (code, requestStr, message);
682
sendReply (
683
code, false, "<h1>"+code+Code.msg(code)+"</h1>"+message
684
);
685
closeConnection(connection);
686
}
687
688
void sendReply (
689
int code, boolean closeNow, String text)
690
{
691
try {
692
StringBuilder builder = new StringBuilder (512);
693
builder.append ("HTTP/1.1 ")
694
.append (code).append (Code.msg(code)).append ("\r\n");
695
696
if (text != null && text.length() != 0) {
697
builder.append ("Content-Length: ")
698
.append (text.length()).append ("\r\n")
699
.append ("Content-Type: text/html\r\n");
700
} else {
701
builder.append ("Content-Length: 0\r\n");
702
text = "";
703
}
704
if (closeNow) {
705
builder.append ("Connection: close\r\n");
706
}
707
builder.append ("\r\n").append (text);
708
String s = builder.toString();
709
byte[] b = s.getBytes("ISO8859_1");
710
rawout.write (b);
711
rawout.flush();
712
if (closeNow) {
713
closeConnection(connection);
714
}
715
} catch (IOException e) {
716
logger.log (Level.FINER, "ServerImpl.sendReply", e);
717
closeConnection(connection);
718
}
719
}
720
721
}
722
723
void logReply (int code, String requestStr, String text) {
724
if (!logger.isLoggable(Level.FINE)) {
725
return;
726
}
727
if (text == null) {
728
text = "";
729
}
730
String r;
731
if (requestStr.length() > 80) {
732
r = requestStr.substring (0, 80) + "<TRUNCATED>";
733
} else {
734
r = requestStr;
735
}
736
String message = r + " [" + code + " " +
737
Code.msg(code) + "] ("+text+")";
738
logger.fine (message);
739
}
740
741
long getTicks() {
742
return ticks;
743
}
744
745
public long getTime() {
746
return time;
747
}
748
749
void delay () {
750
Thread.yield();
751
try {
752
Thread.sleep (200);
753
} catch (InterruptedException e) {}
754
}
755
756
private int exchangeCount = 0;
757
758
synchronized void startExchange () {
759
exchangeCount ++;
760
}
761
762
synchronized int endExchange () {
763
exchangeCount --;
764
assert exchangeCount >= 0;
765
return exchangeCount;
766
}
767
768
HttpServer getWrapper () {
769
return wrapper;
770
}
771
772
void requestStarted (HttpConnection c) {
773
c.creationTime = getTime();
774
c.setState (State.REQUEST);
775
reqConnections.add (c);
776
}
777
778
// called after a request has been completely read
779
// by the server. This stops the timer which would
780
// close the connection if the request doesn't arrive
781
// quickly enough. It then starts the timer
782
// that ensures the client reads the response in a timely
783
// fashion.
784
785
void requestCompleted (HttpConnection c) {
786
assert c.getState() == State.REQUEST;
787
reqConnections.remove (c);
788
c.rspStartedTime = getTime();
789
rspConnections.add (c);
790
c.setState (State.RESPONSE);
791
}
792
793
// called after response has been sent
794
void responseCompleted (HttpConnection c) {
795
assert c.getState() == State.RESPONSE;
796
rspConnections.remove (c);
797
c.setState (State.IDLE);
798
}
799
800
/**
801
* TimerTask run every CLOCK_TICK ms
802
*/
803
class ServerTimerTask extends TimerTask {
804
public void run () {
805
LinkedList<HttpConnection> toClose = new LinkedList<HttpConnection>();
806
time = System.currentTimeMillis();
807
ticks ++;
808
synchronized (idleConnections) {
809
for (HttpConnection c : idleConnections) {
810
if (c.time <= time) {
811
toClose.add (c);
812
}
813
}
814
for (HttpConnection c : toClose) {
815
idleConnections.remove (c);
816
allConnections.remove (c);
817
c.close();
818
}
819
}
820
}
821
}
822
823
class ServerTimerTask1 extends TimerTask {
824
825
// runs every TIMER_MILLIS
826
public void run () {
827
LinkedList<HttpConnection> toClose = new LinkedList<HttpConnection>();
828
time = System.currentTimeMillis();
829
synchronized (reqConnections) {
830
if (MAX_REQ_TIME != -1) {
831
for (HttpConnection c : reqConnections) {
832
if (c.creationTime + TIMER_MILLIS + MAX_REQ_TIME <= time) {
833
toClose.add (c);
834
}
835
}
836
for (HttpConnection c : toClose) {
837
logger.log (Level.FINE, "closing: no request: " + c);
838
reqConnections.remove (c);
839
allConnections.remove (c);
840
c.close();
841
}
842
}
843
}
844
toClose = new LinkedList<HttpConnection>();
845
synchronized (rspConnections) {
846
if (MAX_RSP_TIME != -1) {
847
for (HttpConnection c : rspConnections) {
848
if (c.rspStartedTime + TIMER_MILLIS +MAX_RSP_TIME <= time) {
849
toClose.add (c);
850
}
851
}
852
for (HttpConnection c : toClose) {
853
logger.log (Level.FINE, "closing: no response: " + c);
854
rspConnections.remove (c);
855
allConnections.remove (c);
856
c.close();
857
}
858
}
859
}
860
}
861
}
862
863
void logStackTrace (String s) {
864
logger.finest (s);
865
StringBuilder b = new StringBuilder ();
866
StackTraceElement[] e = Thread.currentThread().getStackTrace();
867
for (int i=0; i<e.length; i++) {
868
b.append (e[i].toString()).append("\n");
869
}
870
logger.finest (b.toString());
871
}
872
873
static long getTimeMillis(long secs) {
874
if (secs == -1) {
875
return -1;
876
} else {
877
return secs * 1000;
878
}
879
}
880
}
881
882