1
2
3
4
5
6
7
8
9
10
11
12
13
14 package org.eclipse.jetty.server;
15
16 import java.io.IOException;
17 import java.net.InetAddress;
18 import java.net.Socket;
19 import java.net.UnknownHostException;
20 import java.util.concurrent.atomic.AtomicLong;
21
22 import javax.servlet.ServletRequest;
23
24 import org.eclipse.jetty.http.HttpBuffers;
25 import org.eclipse.jetty.http.HttpFields;
26 import org.eclipse.jetty.http.HttpHeaders;
27 import org.eclipse.jetty.http.HttpSchemes;
28 import org.eclipse.jetty.io.Connection;
29 import org.eclipse.jetty.io.EndPoint;
30 import org.eclipse.jetty.io.EofException;
31 import org.eclipse.jetty.util.component.AbstractLifeCycle;
32 import org.eclipse.jetty.util.component.AggregateLifeCycle;
33 import org.eclipse.jetty.util.component.Dumpable;
34 import org.eclipse.jetty.util.component.LifeCycle;
35 import org.eclipse.jetty.util.log.Log;
36 import org.eclipse.jetty.util.log.Logger;
37 import org.eclipse.jetty.util.statistic.CounterStatistic;
38 import org.eclipse.jetty.util.statistic.SampleStatistic;
39 import org.eclipse.jetty.util.thread.ThreadPool;
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54 public abstract class AbstractConnector extends HttpBuffers implements Connector, Dumpable
55 {
56 private static final Logger LOG = Log.getLogger(AbstractConnector.class);
57
58 private String _name;
59
60 private Server _server;
61 private ThreadPool _threadPool;
62 private String _host;
63 private int _port = 0;
64 private String _integralScheme = HttpSchemes.HTTPS;
65 private int _integralPort = 0;
66 private String _confidentialScheme = HttpSchemes.HTTPS;
67 private int _confidentialPort = 0;
68 private int _acceptQueueSize = 0;
69 private int _acceptors = 1;
70 private int _acceptorPriorityOffset = 0;
71 private boolean _useDNS;
72 private boolean _forwarded;
73 private String _hostHeader;
74
75 private String _forwardedHostHeader = HttpHeaders.X_FORWARDED_HOST;
76 private String _forwardedServerHeader = HttpHeaders.X_FORWARDED_SERVER;
77 private String _forwardedForHeader = HttpHeaders.X_FORWARDED_FOR;
78 private String _forwardedProtoHeader = HttpHeaders.X_FORWARDED_PROTO;
79 private String _forwardedCipherSuiteHeader;
80 private String _forwardedSslSessionIdHeader;
81 private boolean _reuseAddress = true;
82
83 protected int _maxIdleTime = 200000;
84 protected int _lowResourceMaxIdleTime = -1;
85 protected int _soLingerTime = -1;
86
87 private transient Thread[] _acceptorThread;
88
89 private final AtomicLong _statsStartedAt = new AtomicLong(-1L);
90
91
92 private final CounterStatistic _connectionStats = new CounterStatistic();
93
94 private final SampleStatistic _requestStats = new SampleStatistic();
95
96 private final SampleStatistic _connectionDurationStats = new SampleStatistic();
97
98
99
100
101 public AbstractConnector()
102 {
103 }
104
105
106
107
108 public Server getServer()
109 {
110 return _server;
111 }
112
113
114 public void setServer(Server server)
115 {
116 _server = server;
117 }
118
119
120 public ThreadPool getThreadPool()
121 {
122 return _threadPool;
123 }
124
125
126 public void setThreadPool(ThreadPool pool)
127 {
128 _threadPool = pool;
129 }
130
131
132
133
134 public void setHost(String host)
135 {
136 _host = host;
137 }
138
139
140
141
142 public String getHost()
143 {
144 return _host;
145 }
146
147
148 public void setPort(int port)
149 {
150 _port = port;
151 }
152
153
154 public int getPort()
155 {
156 return _port;
157 }
158
159
160
161
162
163 public int getMaxIdleTime()
164 {
165 return _maxIdleTime;
166 }
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188 public void setMaxIdleTime(int maxIdleTime)
189 {
190 _maxIdleTime = maxIdleTime;
191 }
192
193
194
195
196
197 public int getLowResourcesMaxIdleTime()
198 {
199 return _lowResourceMaxIdleTime;
200 }
201
202
203
204
205
206
207 public void setLowResourcesMaxIdleTime(int maxIdleTime)
208 {
209 _lowResourceMaxIdleTime = maxIdleTime;
210 }
211
212
213
214
215
216
217 public final int getLowResourceMaxIdleTime()
218 {
219 return getLowResourcesMaxIdleTime();
220 }
221
222
223
224
225
226
227
228 public final void setLowResourceMaxIdleTime(int maxIdleTime)
229 {
230 setLowResourcesMaxIdleTime(maxIdleTime);
231 }
232
233
234
235
236
237 public int getSoLingerTime()
238 {
239 return _soLingerTime;
240 }
241
242
243
244
245
246 public int getAcceptQueueSize()
247 {
248 return _acceptQueueSize;
249 }
250
251
252
253
254
255
256 public void setAcceptQueueSize(int acceptQueueSize)
257 {
258 _acceptQueueSize = acceptQueueSize;
259 }
260
261
262
263
264
265 public int getAcceptors()
266 {
267 return _acceptors;
268 }
269
270
271
272
273
274
275 public void setAcceptors(int acceptors)
276 {
277 if (acceptors > 2 * Runtime.getRuntime().availableProcessors())
278 LOG.warn("Acceptors should be <=2*availableProcessors: " + this);
279 _acceptors = acceptors;
280 }
281
282
283
284
285
286
287 public void setSoLingerTime(int soLingerTime)
288 {
289 _soLingerTime = soLingerTime;
290 }
291
292
293 @Override
294 protected void doStart() throws Exception
295 {
296 if (_server == null)
297 throw new IllegalStateException("No server");
298
299
300 open();
301
302 super.doStart();
303
304 if (_threadPool == null)
305 _threadPool = _server.getThreadPool();
306 if (_threadPool != _server.getThreadPool() && (_threadPool instanceof LifeCycle))
307 ((LifeCycle)_threadPool).start();
308
309
310 synchronized (this)
311 {
312 _acceptorThread = new Thread[getAcceptors()];
313
314 for (int i = 0; i < _acceptorThread.length; i++)
315 _threadPool.dispatch(new Acceptor(i));
316 if (_threadPool.isLowOnThreads())
317 LOG.warn("insufficient threads configured for {}",this);
318 }
319
320 LOG.info("Started {}",this);
321 }
322
323
324 @Override
325 protected void doStop() throws Exception
326 {
327 try
328 {
329 close();
330 }
331 catch (IOException e)
332 {
333 LOG.warn(e);
334 }
335
336 if (_threadPool != _server.getThreadPool() && _threadPool instanceof LifeCycle)
337 ((LifeCycle)_threadPool).stop();
338
339 super.doStop();
340
341 Thread[] acceptors = null;
342 synchronized (this)
343 {
344 acceptors = _acceptorThread;
345 _acceptorThread = null;
346 }
347 if (acceptors != null)
348 {
349 for (int i = 0; i < acceptors.length; i++)
350 {
351 Thread thread = acceptors[i];
352 if (thread != null)
353 thread.interrupt();
354 }
355 }
356 }
357
358
359 public void join() throws InterruptedException
360 {
361 Thread[] threads = _acceptorThread;
362 if (threads != null)
363 for (int i = 0; i < threads.length; i++)
364 if (threads[i] != null)
365 threads[i].join();
366 }
367
368
369 protected void configure(Socket socket) throws IOException
370 {
371 try
372 {
373 socket.setTcpNoDelay(true);
374 if (_soLingerTime >= 0)
375 socket.setSoLinger(true,_soLingerTime / 1000);
376 else
377 socket.setSoLinger(false,0);
378 }
379 catch (Exception e)
380 {
381 LOG.ignore(e);
382 }
383 }
384
385
386 public void customize(EndPoint endpoint, Request request) throws IOException
387 {
388 if (isForwarded())
389 checkForwardedHeaders(endpoint,request);
390 }
391
392
393 protected void checkForwardedHeaders(EndPoint endpoint, Request request) throws IOException
394 {
395 HttpFields httpFields = request.getConnection().getRequestFields();
396
397
398 if (getForwardedCipherSuiteHeader()!=null)
399 {
400 String cipher_suite=httpFields.getStringField(getForwardedCipherSuiteHeader());
401 if (cipher_suite!=null)
402 request.setAttribute("javax.servlet.request.cipher_suite",cipher_suite);
403 }
404 if (getForwardedSslSessionIdHeader()!=null)
405 {
406 String ssl_session_id=httpFields.getStringField(getForwardedSslSessionIdHeader());
407 if(ssl_session_id!=null)
408 {
409 request.setAttribute("javax.servlet.request.ssl_session_id", ssl_session_id);
410 request.setScheme(HttpSchemes.HTTPS);
411 }
412 }
413
414
415 String forwardedHost = getLeftMostFieldValue(httpFields,getForwardedHostHeader());
416 String forwardedServer = getLeftMostFieldValue(httpFields,getForwardedServerHeader());
417 String forwardedFor = getLeftMostFieldValue(httpFields,getForwardedForHeader());
418 String forwardedProto = getLeftMostFieldValue(httpFields,getForwardedProtoHeader());
419
420 if (_hostHeader != null)
421 {
422
423 httpFields.put(HttpHeaders.HOST_BUFFER,_hostHeader);
424 request.setServerName(null);
425 request.setServerPort(-1);
426 request.getServerName();
427 }
428 else if (forwardedHost != null)
429 {
430
431 httpFields.put(HttpHeaders.HOST_BUFFER,forwardedHost);
432 request.setServerName(null);
433 request.setServerPort(-1);
434 request.getServerName();
435 }
436 else if (forwardedServer != null)
437 {
438
439 request.setServerName(forwardedServer);
440 }
441
442 if (forwardedFor != null)
443 {
444 request.setRemoteAddr(forwardedFor);
445 InetAddress inetAddress = null;
446
447 if (_useDNS)
448 {
449 try
450 {
451 inetAddress = InetAddress.getByName(forwardedFor);
452 }
453 catch (UnknownHostException e)
454 {
455 LOG.ignore(e);
456 }
457 }
458
459 request.setRemoteHost(inetAddress == null?forwardedFor:inetAddress.getHostName());
460 }
461
462 if (forwardedProto != null)
463 {
464 request.setScheme(forwardedProto);
465 }
466 }
467
468
469 protected String getLeftMostFieldValue(HttpFields fields, String header)
470 {
471 if (header == null)
472 return null;
473
474 String headerValue = fields.getStringField(header);
475
476 if (headerValue == null)
477 return null;
478
479 int commaIndex = headerValue.indexOf(',');
480
481 if (commaIndex == -1)
482 {
483
484 return headerValue;
485 }
486
487
488 return headerValue.substring(0,commaIndex);
489 }
490
491
492 public void persist(EndPoint endpoint) throws IOException
493 {
494 }
495
496
497
498
499
500 public int getConfidentialPort()
501 {
502 return _confidentialPort;
503 }
504
505
506
507
508
509
510 public String getConfidentialScheme()
511 {
512 return _confidentialScheme;
513 }
514
515
516
517
518
519 public boolean isIntegral(Request request)
520 {
521 return false;
522 }
523
524
525
526
527
528 public int getIntegralPort()
529 {
530 return _integralPort;
531 }
532
533
534
535
536
537 public String getIntegralScheme()
538 {
539 return _integralScheme;
540 }
541
542
543
544
545
546 public boolean isConfidential(Request request)
547 {
548 return _forwarded && request.getScheme().equalsIgnoreCase(HttpSchemes.HTTPS);
549 }
550
551
552
553
554
555
556 public void setConfidentialPort(int confidentialPort)
557 {
558 _confidentialPort = confidentialPort;
559 }
560
561
562
563
564
565
566 public void setConfidentialScheme(String confidentialScheme)
567 {
568 _confidentialScheme = confidentialScheme;
569 }
570
571
572
573
574
575
576 public void setIntegralPort(int integralPort)
577 {
578 _integralPort = integralPort;
579 }
580
581
582
583
584
585
586 public void setIntegralScheme(String integralScheme)
587 {
588 _integralScheme = integralScheme;
589 }
590
591
592 protected abstract void accept(int acceptorID) throws IOException, InterruptedException;
593
594
595 public void stopAccept(int acceptorID) throws Exception
596 {
597 }
598
599
600 public boolean getResolveNames()
601 {
602 return _useDNS;
603 }
604
605
606 public void setResolveNames(boolean resolve)
607 {
608 _useDNS = resolve;
609 }
610
611
612
613
614
615
616
617 public boolean isForwarded()
618 {
619 return _forwarded;
620 }
621
622
623
624
625
626
627
628
629
630
631
632
633
634 public void setForwarded(boolean check)
635 {
636 if (check)
637 LOG.debug("{} is forwarded",this);
638 _forwarded = check;
639 }
640
641
642 public String getHostHeader()
643 {
644 return _hostHeader;
645 }
646
647
648
649
650
651
652
653
654
655 public void setHostHeader(String hostHeader)
656 {
657 _hostHeader = hostHeader;
658 }
659
660
661
662
663
664
665 public String getForwardedHostHeader()
666 {
667 return _forwardedHostHeader;
668 }
669
670
671
672
673
674
675
676 public void setForwardedHostHeader(String forwardedHostHeader)
677 {
678 _forwardedHostHeader = forwardedHostHeader;
679 }
680
681
682
683
684
685
686 public String getForwardedServerHeader()
687 {
688 return _forwardedServerHeader;
689 }
690
691
692
693
694
695
696
697 public void setForwardedServerHeader(String forwardedServerHeader)
698 {
699 _forwardedServerHeader = forwardedServerHeader;
700 }
701
702
703
704
705
706 public String getForwardedForHeader()
707 {
708 return _forwardedForHeader;
709 }
710
711
712
713
714
715
716
717 public void setForwardedForHeader(String forwardedRemoteAddressHeader)
718 {
719 _forwardedForHeader = forwardedRemoteAddressHeader;
720 }
721
722
723
724
725
726
727
728
729 public String getForwardedProtoHeader()
730 {
731 return _forwardedProtoHeader;
732 }
733
734
735
736
737
738
739
740
741
742 public void setForwardedProtoHeader(String forwardedProtoHeader)
743 {
744 _forwardedProtoHeader = forwardedProtoHeader;
745 }
746
747
748
749
750
751 public String getForwardedCipherSuiteHeader()
752 {
753 return _forwardedCipherSuiteHeader;
754 }
755
756
757
758
759
760
761 public void setForwardedCipherSuiteHeader(String forwardedCipherSuite)
762 {
763 _forwardedCipherSuiteHeader = forwardedCipherSuite;
764 }
765
766
767
768
769
770 public String getForwardedSslSessionIdHeader()
771 {
772 return _forwardedSslSessionIdHeader;
773 }
774
775
776
777
778
779
780 public void setForwardedSslSessionIdHeader(String forwardedSslSessionId)
781 {
782 _forwardedSslSessionIdHeader = forwardedSslSessionId;
783 }
784
785
786 @Override
787 public String toString()
788 {
789 String name = this.getClass().getName();
790 int dot = name.lastIndexOf('.');
791 if (dot > 0)
792 name = name.substring(dot + 1);
793
794 return name + "@" + (getHost() == null?"0.0.0.0":getHost()) + ":" + (getLocalPort() <= 0?getPort():getLocalPort()) + " "
795 + AbstractLifeCycle.getState(this);
796 }
797
798
799
800
801 private class Acceptor implements Runnable
802 {
803 int _acceptor = 0;
804
805 Acceptor(int id)
806 {
807 _acceptor = id;
808 }
809
810
811 public void run()
812 {
813 Thread current = Thread.currentThread();
814 String name;
815 synchronized (AbstractConnector.this)
816 {
817 if (_acceptorThread == null)
818 return;
819
820 _acceptorThread[_acceptor] = current;
821 name = _acceptorThread[_acceptor].getName();
822 current.setName(name + " Acceptor" + _acceptor + " " + AbstractConnector.this);
823 }
824 int old_priority = current.getPriority();
825
826 try
827 {
828 current.setPriority(old_priority - _acceptorPriorityOffset);
829 while (isRunning() && getConnection() != null)
830 {
831 try
832 {
833 accept(_acceptor);
834 }
835 catch (EofException e)
836 {
837 LOG.ignore(e);
838 }
839 catch (IOException e)
840 {
841 LOG.ignore(e);
842 }
843 catch (InterruptedException x)
844 {
845
846 LOG.ignore(x);
847 }
848 catch (ThreadDeath e)
849 {
850 throw e;
851 }
852 catch (Throwable e)
853 {
854 LOG.warn(e);
855 }
856 }
857 }
858 finally
859 {
860 current.setPriority(old_priority);
861 current.setName(name);
862
863 synchronized (AbstractConnector.this)
864 {
865 if (_acceptorThread != null)
866 _acceptorThread[_acceptor] = null;
867 }
868 }
869 }
870 }
871
872
873 public String getName()
874 {
875 if (_name == null)
876 _name = (getHost() == null?"0.0.0.0":getHost()) + ":" + (getLocalPort() <= 0?getPort():getLocalPort());
877 return _name;
878 }
879
880
881 public void setName(String name)
882 {
883 _name = name;
884 }
885
886
887
888
889
890 public int getRequests()
891 {
892 return (int)_requestStats.getTotal();
893 }
894
895
896
897
898
899 public long getConnectionsDurationTotal()
900 {
901 return _connectionDurationStats.getTotal();
902 }
903
904
905
906
907
908 public int getConnections()
909 {
910 return (int)_connectionStats.getTotal();
911 }
912
913
914
915
916
917 public int getConnectionsOpen()
918 {
919 return (int)_connectionStats.getCurrent();
920 }
921
922
923
924
925
926 public int getConnectionsOpenMax()
927 {
928 return (int)_connectionStats.getMax();
929 }
930
931
932
933
934
935 public double getConnectionsDurationMean()
936 {
937 return _connectionDurationStats.getMean();
938 }
939
940
941
942
943
944 public long getConnectionsDurationMax()
945 {
946 return _connectionDurationStats.getMax();
947 }
948
949
950
951
952
953 public double getConnectionsDurationStdDev()
954 {
955 return _connectionDurationStats.getStdDev();
956 }
957
958
959
960
961
962 public double getConnectionsRequestsMean()
963 {
964 return _requestStats.getMean();
965 }
966
967
968
969
970
971 public int getConnectionsRequestsMax()
972 {
973 return (int)_requestStats.getMax();
974 }
975
976
977
978
979
980 public double getConnectionsRequestsStdDev()
981 {
982 return _requestStats.getStdDev();
983 }
984
985
986
987
988
989 public void statsReset()
990 {
991 updateNotEqual(_statsStartedAt,-1,System.currentTimeMillis());
992
993 _requestStats.reset();
994 _connectionStats.reset();
995 _connectionDurationStats.reset();
996 }
997
998
999 public void setStatsOn(boolean on)
1000 {
1001 if (on && _statsStartedAt.get() != -1)
1002 return;
1003
1004 if (LOG.isDebugEnabled())
1005 LOG.debug("Statistics on = " + on + " for " + this);
1006
1007 statsReset();
1008 _statsStartedAt.set(on?System.currentTimeMillis():-1);
1009 }
1010
1011
1012
1013
1014
1015 public boolean getStatsOn()
1016 {
1017 return _statsStartedAt.get() != -1;
1018 }
1019
1020
1021
1022
1023
1024 public long getStatsOnMs()
1025 {
1026 long start = _statsStartedAt.get();
1027
1028 return (start != -1)?(System.currentTimeMillis() - start):0;
1029 }
1030
1031
1032 protected void connectionOpened(Connection connection)
1033 {
1034 if (_statsStartedAt.get() == -1)
1035 return;
1036
1037 _connectionStats.increment();
1038 }
1039
1040
1041 protected void connectionUpgraded(Connection oldConnection, Connection newConnection)
1042 {
1043 _requestStats.set((oldConnection instanceof HttpConnection)?((HttpConnection)oldConnection).getRequests():0);
1044 }
1045
1046
1047 protected void connectionClosed(Connection connection)
1048 {
1049 connection.closed();
1050
1051 if (_statsStartedAt.get() == -1)
1052 return;
1053
1054 long duration = System.currentTimeMillis() - connection.getTimeStamp();
1055 int requests = (connection instanceof HttpConnection)?((HttpConnection)connection).getRequests():0;
1056 _requestStats.set(requests);
1057 _connectionStats.decrement();
1058 _connectionDurationStats.set(duration);
1059 }
1060
1061
1062
1063
1064
1065 public int getAcceptorPriorityOffset()
1066 {
1067 return _acceptorPriorityOffset;
1068 }
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078 public void setAcceptorPriorityOffset(int offset)
1079 {
1080 _acceptorPriorityOffset = offset;
1081 }
1082
1083
1084
1085
1086
1087 public boolean getReuseAddress()
1088 {
1089 return _reuseAddress;
1090 }
1091
1092
1093
1094
1095
1096
1097 public void setReuseAddress(boolean reuseAddress)
1098 {
1099 _reuseAddress = reuseAddress;
1100 }
1101
1102
1103 public boolean isLowResources()
1104 {
1105 if (_threadPool != null)
1106 return _threadPool.isLowOnThreads();
1107 return _server.getThreadPool().isLowOnThreads();
1108 }
1109
1110
1111 private void updateNotEqual(AtomicLong valueHolder, long compare, long value)
1112 {
1113 long oldValue = valueHolder.get();
1114 while (compare != oldValue)
1115 {
1116 if (valueHolder.compareAndSet(oldValue,value))
1117 break;
1118 oldValue = valueHolder.get();
1119 }
1120 }
1121
1122
1123 public String dump()
1124 {
1125 return AggregateLifeCycle.dump(this);
1126 }
1127
1128
1129 public void dump(Appendable out, String indent) throws IOException
1130 {
1131 out.append(String.valueOf(this)).append("\n");
1132 }
1133
1134 }