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