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;
362 synchronized(this)
363 {
364 threads= _acceptorThread;
365 }
366 if (threads != null)
367 for (int i = 0; i < threads.length; i++)
368 if (threads[i] != null)
369 threads[i].join();
370 }
371
372
373 protected void configure(Socket socket) throws IOException
374 {
375 try
376 {
377 socket.setTcpNoDelay(true);
378 if (_soLingerTime >= 0)
379 socket.setSoLinger(true,_soLingerTime / 1000);
380 else
381 socket.setSoLinger(false,0);
382 }
383 catch (Exception e)
384 {
385 LOG.ignore(e);
386 }
387 }
388
389
390 public void customize(EndPoint endpoint, Request request) throws IOException
391 {
392 if (isForwarded())
393 checkForwardedHeaders(endpoint,request);
394 }
395
396
397 protected void checkForwardedHeaders(EndPoint endpoint, Request request) throws IOException
398 {
399 HttpFields httpFields = request.getConnection().getRequestFields();
400
401
402 if (getForwardedCipherSuiteHeader()!=null)
403 {
404 String cipher_suite=httpFields.getStringField(getForwardedCipherSuiteHeader());
405 if (cipher_suite!=null)
406 request.setAttribute("javax.servlet.request.cipher_suite",cipher_suite);
407 }
408 if (getForwardedSslSessionIdHeader()!=null)
409 {
410 String ssl_session_id=httpFields.getStringField(getForwardedSslSessionIdHeader());
411 if(ssl_session_id!=null)
412 {
413 request.setAttribute("javax.servlet.request.ssl_session_id", ssl_session_id);
414 request.setScheme(HttpSchemes.HTTPS);
415 }
416 }
417
418
419 String forwardedHost = getLeftMostFieldValue(httpFields,getForwardedHostHeader());
420 String forwardedServer = getLeftMostFieldValue(httpFields,getForwardedServerHeader());
421 String forwardedFor = getLeftMostFieldValue(httpFields,getForwardedForHeader());
422 String forwardedProto = getLeftMostFieldValue(httpFields,getForwardedProtoHeader());
423
424 if (_hostHeader != null)
425 {
426
427 httpFields.put(HttpHeaders.HOST_BUFFER,_hostHeader);
428 request.setServerName(null);
429 request.setServerPort(-1);
430 request.getServerName();
431 }
432 else if (forwardedHost != null)
433 {
434
435 httpFields.put(HttpHeaders.HOST_BUFFER,forwardedHost);
436 request.setServerName(null);
437 request.setServerPort(-1);
438 request.getServerName();
439 }
440 else if (forwardedServer != null)
441 {
442
443 request.setServerName(forwardedServer);
444 }
445
446 if (forwardedFor != null)
447 {
448 request.setRemoteAddr(forwardedFor);
449 InetAddress inetAddress = null;
450
451 if (_useDNS)
452 {
453 try
454 {
455 inetAddress = InetAddress.getByName(forwardedFor);
456 }
457 catch (UnknownHostException e)
458 {
459 LOG.ignore(e);
460 }
461 }
462
463 request.setRemoteHost(inetAddress == null?forwardedFor:inetAddress.getHostName());
464 }
465
466 if (forwardedProto != null)
467 {
468 request.setScheme(forwardedProto);
469 }
470 }
471
472
473 protected String getLeftMostFieldValue(HttpFields fields, String header)
474 {
475 if (header == null)
476 return null;
477
478 String headerValue = fields.getStringField(header);
479
480 if (headerValue == null)
481 return null;
482
483 int commaIndex = headerValue.indexOf(',');
484
485 if (commaIndex == -1)
486 {
487
488 return headerValue;
489 }
490
491
492 return headerValue.substring(0,commaIndex);
493 }
494
495
496 public void persist(EndPoint endpoint) throws IOException
497 {
498 }
499
500
501
502
503
504 public int getConfidentialPort()
505 {
506 return _confidentialPort;
507 }
508
509
510
511
512
513
514 public String getConfidentialScheme()
515 {
516 return _confidentialScheme;
517 }
518
519
520
521
522
523 public boolean isIntegral(Request request)
524 {
525 return false;
526 }
527
528
529
530
531
532 public int getIntegralPort()
533 {
534 return _integralPort;
535 }
536
537
538
539
540
541 public String getIntegralScheme()
542 {
543 return _integralScheme;
544 }
545
546
547
548
549
550 public boolean isConfidential(Request request)
551 {
552 return _forwarded && request.getScheme().equalsIgnoreCase(HttpSchemes.HTTPS);
553 }
554
555
556
557
558
559
560 public void setConfidentialPort(int confidentialPort)
561 {
562 _confidentialPort = confidentialPort;
563 }
564
565
566
567
568
569
570 public void setConfidentialScheme(String confidentialScheme)
571 {
572 _confidentialScheme = confidentialScheme;
573 }
574
575
576
577
578
579
580 public void setIntegralPort(int integralPort)
581 {
582 _integralPort = integralPort;
583 }
584
585
586
587
588
589
590 public void setIntegralScheme(String integralScheme)
591 {
592 _integralScheme = integralScheme;
593 }
594
595
596 protected abstract void accept(int acceptorID) throws IOException, InterruptedException;
597
598
599 public void stopAccept(int acceptorID) throws Exception
600 {
601 }
602
603
604 public boolean getResolveNames()
605 {
606 return _useDNS;
607 }
608
609
610 public void setResolveNames(boolean resolve)
611 {
612 _useDNS = resolve;
613 }
614
615
616
617
618
619
620
621 public boolean isForwarded()
622 {
623 return _forwarded;
624 }
625
626
627
628
629
630
631
632
633
634
635
636
637
638 public void setForwarded(boolean check)
639 {
640 if (check)
641 LOG.debug("{} is forwarded",this);
642 _forwarded = check;
643 }
644
645
646 public String getHostHeader()
647 {
648 return _hostHeader;
649 }
650
651
652
653
654
655
656
657
658
659 public void setHostHeader(String hostHeader)
660 {
661 _hostHeader = hostHeader;
662 }
663
664
665
666
667
668
669 public String getForwardedHostHeader()
670 {
671 return _forwardedHostHeader;
672 }
673
674
675
676
677
678
679
680 public void setForwardedHostHeader(String forwardedHostHeader)
681 {
682 _forwardedHostHeader = forwardedHostHeader;
683 }
684
685
686
687
688
689
690 public String getForwardedServerHeader()
691 {
692 return _forwardedServerHeader;
693 }
694
695
696
697
698
699
700
701 public void setForwardedServerHeader(String forwardedServerHeader)
702 {
703 _forwardedServerHeader = forwardedServerHeader;
704 }
705
706
707
708
709
710 public String getForwardedForHeader()
711 {
712 return _forwardedForHeader;
713 }
714
715
716
717
718
719
720
721 public void setForwardedForHeader(String forwardedRemoteAddressHeader)
722 {
723 _forwardedForHeader = forwardedRemoteAddressHeader;
724 }
725
726
727
728
729
730
731
732
733 public String getForwardedProtoHeader()
734 {
735 return _forwardedProtoHeader;
736 }
737
738
739
740
741
742
743
744
745
746 public void setForwardedProtoHeader(String forwardedProtoHeader)
747 {
748 _forwardedProtoHeader = forwardedProtoHeader;
749 }
750
751
752
753
754
755 public String getForwardedCipherSuiteHeader()
756 {
757 return _forwardedCipherSuiteHeader;
758 }
759
760
761
762
763
764
765 public void setForwardedCipherSuiteHeader(String forwardedCipherSuite)
766 {
767 _forwardedCipherSuiteHeader = forwardedCipherSuite;
768 }
769
770
771
772
773
774 public String getForwardedSslSessionIdHeader()
775 {
776 return _forwardedSslSessionIdHeader;
777 }
778
779
780
781
782
783
784 public void setForwardedSslSessionIdHeader(String forwardedSslSessionId)
785 {
786 _forwardedSslSessionIdHeader = forwardedSslSessionId;
787 }
788
789
790 @Override
791 public String toString()
792 {
793 String name = this.getClass().getName();
794 int dot = name.lastIndexOf('.');
795 if (dot > 0)
796 name = name.substring(dot + 1);
797
798 return name + "@" + (getHost() == null?"0.0.0.0":getHost()) + ":" + (getLocalPort() <= 0?getPort():getLocalPort()) + " "
799 + AbstractLifeCycle.getState(this);
800 }
801
802
803
804
805 private class Acceptor implements Runnable
806 {
807 int _acceptor = 0;
808
809 Acceptor(int id)
810 {
811 _acceptor = id;
812 }
813
814
815 public void run()
816 {
817 Thread current = Thread.currentThread();
818 String name;
819 synchronized (AbstractConnector.this)
820 {
821 if (_acceptorThread == null)
822 return;
823
824 _acceptorThread[_acceptor] = current;
825 name = _acceptorThread[_acceptor].getName();
826 current.setName(name + " Acceptor" + _acceptor + " " + AbstractConnector.this);
827 }
828 int old_priority = current.getPriority();
829
830 try
831 {
832 current.setPriority(old_priority - _acceptorPriorityOffset);
833 while (isRunning() && getConnection() != null)
834 {
835 try
836 {
837 accept(_acceptor);
838 }
839 catch (EofException e)
840 {
841 LOG.ignore(e);
842 }
843 catch (IOException e)
844 {
845 LOG.ignore(e);
846 }
847 catch (InterruptedException x)
848 {
849
850 LOG.ignore(x);
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 AbstractHttpConnection)?((AbstractHttpConnection)oldConnection).getRequests():0);
1044 }
1045
1046
1047 protected void connectionClosed(Connection connection)
1048 {
1049 connection.onClose();
1050
1051 if (_statsStartedAt.get() == -1)
1052 return;
1053
1054 long duration = System.currentTimeMillis() - connection.getTimeStamp();
1055 int requests = (connection instanceof AbstractHttpConnection)?((AbstractHttpConnection)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 }