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