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