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