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