View Javadoc

1   //
2   //  ========================================================================
3   //  Copyright (c) 1995-2013 Mort Bay Consulting Pty. Ltd.
4   //  ------------------------------------------------------------------------
5   //  All rights reserved. This program and the accompanying materials
6   //  are made available under the terms of the Eclipse Public License v1.0
7   //  and Apache License v2.0 which accompanies this distribution.
8   //
9   //      The Eclipse Public License is available at
10  //      http://www.eclipse.org/legal/epl-v10.html
11  //
12  //      The Apache License v2.0 is available at
13  //      http://www.opensource.org/licenses/apache2.0.php
14  //
15  //  You may elect to redistribute this code under either of these licenses.
16  //  ========================================================================
17  //
18  
19  package org.eclipse.jetty.server;
20  
21  import java.io.IOException;
22  import java.net.InetAddress;
23  import java.net.Socket;
24  import java.net.UnknownHostException;
25  import java.util.concurrent.atomic.AtomicLong;
26  
27  import javax.servlet.ServletRequest;
28  
29  import org.eclipse.jetty.http.HttpBuffers;
30  import org.eclipse.jetty.http.HttpBuffersImpl;
31  import org.eclipse.jetty.http.HttpFields;
32  import org.eclipse.jetty.http.HttpHeaders;
33  import org.eclipse.jetty.http.HttpSchemes;
34  import org.eclipse.jetty.io.Buffers;
35  import org.eclipse.jetty.io.Buffers.Type;
36  import org.eclipse.jetty.io.Connection;
37  import org.eclipse.jetty.io.EndPoint;
38  import org.eclipse.jetty.io.EofException;
39  import org.eclipse.jetty.util.component.AggregateLifeCycle;
40  import org.eclipse.jetty.util.component.Dumpable;
41  import org.eclipse.jetty.util.log.Log;
42  import org.eclipse.jetty.util.log.Logger;
43  import org.eclipse.jetty.util.statistic.CounterStatistic;
44  import org.eclipse.jetty.util.statistic.SampleStatistic;
45  import org.eclipse.jetty.util.thread.ThreadPool;
46  
47  /**
48   * Abstract Connector implementation. This abstract implementation of the Connector interface provides:
49   * <ul>
50   * <li>AbstractLifeCycle implementation</li>
51   * <li>Implementations for connector getters and setters</li>
52   * <li>Buffer management</li>
53   * <li>Socket configuration</li>
54   * <li>Base acceptor thread</li>
55   * <li>Optional reverse proxy headers checking</li>
56   * </ul>
57   */
58  public abstract class AbstractConnector extends AggregateLifeCycle implements HttpBuffers, Connector, Dumpable
59  {
60      private static final Logger LOG = Log.getLogger(AbstractConnector.class);
61  
62      private String _name;
63  
64      private Server _server;
65      private ThreadPool _threadPool;
66      private String _host;
67      private int _port = 0;
68      private String _integralScheme = HttpSchemes.HTTPS;
69      private int _integralPort = 0;
70      private String _confidentialScheme = HttpSchemes.HTTPS;
71      private int _confidentialPort = 0;
72      private int _acceptQueueSize = 0;
73      private int _acceptors = 1;
74      private int _acceptorPriorityOffset = 0;
75      private boolean _useDNS;
76      private boolean _forwarded;
77      private String _hostHeader;
78  
79      private String _forwardedHostHeader = HttpHeaders.X_FORWARDED_HOST;
80      private String _forwardedServerHeader = HttpHeaders.X_FORWARDED_SERVER;
81      private String _forwardedForHeader = HttpHeaders.X_FORWARDED_FOR;
82      private String _forwardedProtoHeader = HttpHeaders.X_FORWARDED_PROTO;
83      private String _forwardedCipherSuiteHeader;
84      private String _forwardedSslSessionIdHeader;
85      private boolean _reuseAddress = true;
86  
87      protected int _maxIdleTime = 200000;
88      protected int _lowResourceMaxIdleTime = -1;
89      protected int _soLingerTime = -1;
90  
91      private transient Thread[] _acceptorThreads;
92  
93      private final AtomicLong _statsStartedAt = new AtomicLong(-1L);
94  
95      /** connections to server */
96      private final CounterStatistic _connectionStats = new CounterStatistic();
97      /** requests per connection */
98      private final SampleStatistic _requestStats = new SampleStatistic();
99      /** duration of a connection */
100     private final SampleStatistic _connectionDurationStats = new SampleStatistic();
101 
102     protected final HttpBuffersImpl _buffers = new HttpBuffersImpl();
103 
104     /* ------------------------------------------------------------ */
105     /**
106      */
107     public AbstractConnector()
108     {
109         addBean(_buffers);
110     }
111 
112     /* ------------------------------------------------------------ */
113     /*
114      */
115     public Server getServer()
116     {
117         return _server;
118     }
119 
120     /* ------------------------------------------------------------ */
121     public void setServer(Server server)
122     {
123         _server = server;
124     }
125 
126     /* ------------------------------------------------------------ */
127     public ThreadPool getThreadPool()
128     {
129         return _threadPool;
130     }
131 
132     /* ------------------------------------------------------------ */
133     /** Set the ThreadPool.
134      * The threadpool passed is added via {@link #addBean(Object)} so that 
135      * it's lifecycle may be managed as a {@link AggregateLifeCycle}.
136      * @param pool the threadPool to set
137      */
138     public void setThreadPool(ThreadPool pool)
139     {
140         removeBean(_threadPool);
141         _threadPool = pool;
142         addBean(_threadPool);
143     }
144 
145     /* ------------------------------------------------------------ */
146     /**
147      */
148     public void setHost(String host)
149     {
150         _host = host;
151     }
152 
153     /* ------------------------------------------------------------ */
154     /*
155      */
156     public String getHost()
157     {
158         return _host;
159     }
160 
161     /* ------------------------------------------------------------ */
162     public void setPort(int port)
163     {
164         _port = port;
165     }
166 
167     /* ------------------------------------------------------------ */
168     public int getPort()
169     {
170         return _port;
171     }
172 
173     /* ------------------------------------------------------------ */
174     /**
175      * @return Returns the maxIdleTime.
176      */
177     public int getMaxIdleTime()
178     {
179         return _maxIdleTime;
180     }
181 
182     /* ------------------------------------------------------------ */
183     /**
184      * Set the maximum Idle time for a connection, which roughly translates to the {@link Socket#setSoTimeout(int)} call, although with NIO implementations
185      * other mechanisms may be used to implement the timeout. The max idle time is applied:
186      * <ul>
187      * <li>When waiting for a new request to be received on a connection</li>
188      * <li>When reading the headers and content of a request</li>
189      * <li>When writing the headers and content of a response</li>
190      * </ul>
191      * Jetty interprets this value as the maximum time between some progress being made on the connection. So if a single byte is read or written, then the
192      * timeout (if implemented by jetty) is reset. However, in many instances, the reading/writing is delegated to the JVM, and the semantic is more strictly
193      * enforced as the maximum time a single read/write operation can take. Note, that as Jetty supports writes of memory mapped file buffers, then a write may
194      * take many 10s of seconds for large content written to a slow device.
195      * <p>
196      * Previously, Jetty supported separate idle timeouts and IO operation timeouts, however the expense of changing the value of soTimeout was significant, so
197      * these timeouts were merged. With the advent of NIO, it may be possible to again differentiate these values (if there is demand).
198      *
199      * @param maxIdleTime
200      *            The maxIdleTime to set.
201      */
202     public void setMaxIdleTime(int maxIdleTime)
203     {
204         _maxIdleTime = maxIdleTime;
205     }
206 
207     /* ------------------------------------------------------------ */
208     /**
209      * @return Returns the maxIdleTime when resources are low.
210      */
211     public int getLowResourcesMaxIdleTime()
212     {
213         return _lowResourceMaxIdleTime;
214     }
215 
216     /* ------------------------------------------------------------ */
217     /**
218      * @param maxIdleTime
219      *            The maxIdleTime to set when resources are low.
220      */
221     public void setLowResourcesMaxIdleTime(int maxIdleTime)
222     {
223         _lowResourceMaxIdleTime = maxIdleTime;
224     }
225 
226     /* ------------------------------------------------------------ */
227     /**
228      * @return Returns the maxIdleTime when resources are low.
229      * @deprecated
230      */
231     @Deprecated
232     public final int getLowResourceMaxIdleTime()
233     {
234         return getLowResourcesMaxIdleTime();
235     }
236 
237     /* ------------------------------------------------------------ */
238     /**
239      * @param maxIdleTime
240      *            The maxIdleTime to set when resources are low.
241      * @deprecated
242      */
243     @Deprecated
244     public final void setLowResourceMaxIdleTime(int maxIdleTime)
245     {
246         setLowResourcesMaxIdleTime(maxIdleTime);
247     }
248 
249     /* ------------------------------------------------------------ */
250     /**
251      * @return Returns the soLingerTime.
252      */
253     public int getSoLingerTime()
254     {
255         return _soLingerTime;
256     }
257 
258     /* ------------------------------------------------------------ */
259     /**
260      * @return Returns the acceptQueueSize.
261      */
262     public int getAcceptQueueSize()
263     {
264         return _acceptQueueSize;
265     }
266 
267     /* ------------------------------------------------------------ */
268     /**
269      * @param acceptQueueSize
270      *            The acceptQueueSize to set.
271      */
272     public void setAcceptQueueSize(int acceptQueueSize)
273     {
274         _acceptQueueSize = acceptQueueSize;
275     }
276 
277     /* ------------------------------------------------------------ */
278     /**
279      * @return Returns the number of acceptor threads.
280      */
281     public int getAcceptors()
282     {
283         return _acceptors;
284     }
285 
286     /* ------------------------------------------------------------ */
287     /**
288      * @param acceptors
289      *            The number of acceptor threads to set.
290      */
291     public void setAcceptors(int acceptors)
292     {
293         if (acceptors > 2 * Runtime.getRuntime().availableProcessors())
294             LOG.warn("Acceptors should be <=2*availableProcessors: " + this);
295         _acceptors = acceptors;
296     }
297 
298     /* ------------------------------------------------------------ */
299     /**
300      * @param soLingerTime
301      *            The soLingerTime to set or -1 to disable.
302      */
303     public void setSoLingerTime(int soLingerTime)
304     {
305         _soLingerTime = soLingerTime;
306     }
307 
308     /* ------------------------------------------------------------ */
309     @Override
310     protected void doStart() throws Exception
311     {
312         if (_server == null)
313             throw new IllegalStateException("No server");
314 
315         // open listener port
316         open();
317 
318         if (_threadPool == null)
319         {
320             _threadPool = _server.getThreadPool();
321             addBean(_threadPool,false);
322         }
323 
324         super.doStart();
325 
326         // Start selector thread
327         synchronized (this)
328         {
329             _acceptorThreads = new Thread[getAcceptors()];
330 
331             for (int i = 0; i < _acceptorThreads.length; i++)
332                 if (!_threadPool.dispatch(new Acceptor(i)))
333                     throw new IllegalStateException("!accepting");
334             if (_threadPool.isLowOnThreads())
335                 LOG.warn("insufficient threads configured for {}",this);
336         }
337 
338         LOG.info("Started {}",this);
339     }
340 
341     /* ------------------------------------------------------------ */
342     @Override
343     protected void doStop() throws Exception
344     {
345         try
346         {
347             close();
348         }
349         catch (IOException e)
350         {
351             LOG.warn(e);
352         }
353 
354         super.doStop();
355 
356         Thread[] acceptors;
357         synchronized (this)
358         {
359             acceptors = _acceptorThreads;
360             _acceptorThreads = null;
361         }
362         if (acceptors != null)
363         {
364             for (Thread thread : acceptors)
365             {
366                 if (thread != null)
367                     thread.interrupt();
368             }
369         }
370     }
371 
372     /* ------------------------------------------------------------ */
373     public void join() throws InterruptedException
374     {
375         Thread[] threads;
376         synchronized(this)
377         {
378             threads=_acceptorThreads;
379         }
380         if (threads != null)
381             for (Thread thread : threads)
382                 if (thread != null)
383                     thread.join();
384     }
385 
386     /* ------------------------------------------------------------ */
387     protected void configure(Socket socket) throws IOException
388     {
389         try
390         {
391             socket.setTcpNoDelay(true);
392             if (_soLingerTime >= 0)
393                 socket.setSoLinger(true,_soLingerTime / 1000);
394             else
395                 socket.setSoLinger(false,0);
396         }
397         catch (Exception e)
398         {
399             LOG.ignore(e);
400         }
401     }
402 
403     /* ------------------------------------------------------------ */
404     public void customize(EndPoint endpoint, Request request) throws IOException
405     {
406         if (isForwarded())
407             checkForwardedHeaders(endpoint,request);
408     }
409 
410     /* ------------------------------------------------------------ */
411     protected void checkForwardedHeaders(EndPoint endpoint, Request request) throws IOException
412     {
413         HttpFields httpFields = request.getConnection().getRequestFields();
414 
415         // Do SSL first
416         if (getForwardedCipherSuiteHeader()!=null)
417         {
418             String cipher_suite=httpFields.getStringField(getForwardedCipherSuiteHeader());
419             if (cipher_suite!=null)
420                 request.setAttribute("javax.servlet.request.cipher_suite",cipher_suite);
421         }
422         if (getForwardedSslSessionIdHeader()!=null)
423         {
424             String ssl_session_id=httpFields.getStringField(getForwardedSslSessionIdHeader());
425             if(ssl_session_id!=null)
426             {
427                 request.setAttribute("javax.servlet.request.ssl_session_id", ssl_session_id);
428                 request.setScheme(HttpSchemes.HTTPS);
429             }
430         }
431 
432         // Retrieving headers from the request
433         String forwardedHost = getLeftMostFieldValue(httpFields,getForwardedHostHeader());
434         String forwardedServer = getLeftMostFieldValue(httpFields,getForwardedServerHeader());
435         String forwardedFor = getLeftMostFieldValue(httpFields,getForwardedForHeader());
436         String forwardedProto = getLeftMostFieldValue(httpFields,getForwardedProtoHeader());
437 
438         if (_hostHeader != null)
439         {
440             // Update host header
441             httpFields.put(HttpHeaders.HOST_BUFFER,_hostHeader);
442             request.setServerName(null);
443             request.setServerPort(-1);
444             request.getServerName();
445         }
446         else if (forwardedHost != null)
447         {
448             // Update host header
449             httpFields.put(HttpHeaders.HOST_BUFFER,forwardedHost);
450             request.setServerName(null);
451             request.setServerPort(-1);
452             request.getServerName();
453         }
454         else if (forwardedServer != null)
455         {
456             // Use provided server name
457             request.setServerName(forwardedServer);
458         }
459 
460         if (forwardedFor != null)
461         {
462             request.setRemoteAddr(forwardedFor);
463             InetAddress inetAddress = null;
464 
465             if (_useDNS)
466             {
467                 try
468                 {
469                     inetAddress = InetAddress.getByName(forwardedFor);
470                 }
471                 catch (UnknownHostException e)
472                 {
473                     LOG.ignore(e);
474                 }
475             }
476 
477             request.setRemoteHost(inetAddress == null?forwardedFor:inetAddress.getHostName());
478         }
479 
480         if (forwardedProto != null)
481         {
482             request.setScheme(forwardedProto);
483         }
484     }
485 
486     /* ------------------------------------------------------------ */
487     protected String getLeftMostFieldValue(HttpFields fields, String header)
488     {
489         if (header == null)
490             return null;
491 
492         String headerValue = fields.getStringField(header);
493 
494         if (headerValue == null)
495             return null;
496 
497         int commaIndex = headerValue.indexOf(',');
498 
499         if (commaIndex == -1)
500         {
501             // Single value
502             return headerValue;
503         }
504 
505         // The left-most value is the farthest downstream client
506         return headerValue.substring(0,commaIndex);
507     }
508 
509     /* ------------------------------------------------------------ */
510     public void persist(EndPoint endpoint) throws IOException
511     {
512     }
513 
514     /* ------------------------------------------------------------ */
515     /*
516      * @see org.eclipse.jetty.server.Connector#getConfidentialPort()
517      */
518     public int getConfidentialPort()
519     {
520         return _confidentialPort;
521     }
522 
523     /* ------------------------------------------------------------ */
524     /* ------------------------------------------------------------ */
525     /*
526      * @see org.eclipse.jetty.server.Connector#getConfidentialScheme()
527      */
528     public String getConfidentialScheme()
529     {
530         return _confidentialScheme;
531     }
532 
533     /* ------------------------------------------------------------ */
534     /*
535      * @see org.eclipse.jetty.server.Connector#isConfidential(org.eclipse.jetty.server .Request)
536      */
537     public boolean isIntegral(Request request)
538     {
539         return false;
540     }
541 
542     /* ------------------------------------------------------------ */
543     /*
544      * @see org.eclipse.jetty.server.Connector#getConfidentialPort()
545      */
546     public int getIntegralPort()
547     {
548         return _integralPort;
549     }
550 
551     /* ------------------------------------------------------------ */
552     /*
553      * @see org.eclipse.jetty.server.Connector#getIntegralScheme()
554      */
555     public String getIntegralScheme()
556     {
557         return _integralScheme;
558     }
559 
560     /* ------------------------------------------------------------ */
561     /*
562      * @see org.eclipse.jetty.server.Connector#isConfidential(org.eclipse.jetty.server.Request)
563      */
564     public boolean isConfidential(Request request)
565     {
566         return _forwarded && request.getScheme().equalsIgnoreCase(HttpSchemes.HTTPS);
567     }
568 
569     /* ------------------------------------------------------------ */
570     /**
571      * @param confidentialPort
572      *            The confidentialPort to set.
573      */
574     public void setConfidentialPort(int confidentialPort)
575     {
576         _confidentialPort = confidentialPort;
577     }
578 
579     /* ------------------------------------------------------------ */
580     /**
581      * @param confidentialScheme
582      *            The confidentialScheme to set.
583      */
584     public void setConfidentialScheme(String confidentialScheme)
585     {
586         _confidentialScheme = confidentialScheme;
587     }
588 
589     /* ------------------------------------------------------------ */
590     /**
591      * @param integralPort
592      *            The integralPort to set.
593      */
594     public void setIntegralPort(int integralPort)
595     {
596         _integralPort = integralPort;
597     }
598 
599     /* ------------------------------------------------------------ */
600     /**
601      * @param integralScheme
602      *            The integralScheme to set.
603      */
604     public void setIntegralScheme(String integralScheme)
605     {
606         _integralScheme = integralScheme;
607     }
608 
609     /* ------------------------------------------------------------ */
610     protected abstract void accept(int acceptorID) throws IOException, InterruptedException;
611 
612     /* ------------------------------------------------------------ */
613     public void stopAccept(int acceptorID) throws Exception
614     {
615     }
616 
617     /* ------------------------------------------------------------ */
618     public boolean getResolveNames()
619     {
620         return _useDNS;
621     }
622 
623     /* ------------------------------------------------------------ */
624     public void setResolveNames(boolean resolve)
625     {
626         _useDNS = resolve;
627     }
628 
629     /* ------------------------------------------------------------ */
630     /**
631      * Is reverse proxy handling on?
632      *
633      * @return true if this connector is checking the x-forwarded-for/host/server headers
634      */
635     public boolean isForwarded()
636     {
637         return _forwarded;
638     }
639 
640     /* ------------------------------------------------------------ */
641     /**
642      * Set reverse proxy handling. If set to true, then the X-Forwarded headers (or the headers set in their place) are looked for to set the request protocol,
643      * host, server and client ip.
644      *
645      * @param check
646      *            true if this connector is checking the x-forwarded-for/host/server headers
647      * @see #setForwardedForHeader(String)
648      * @see #setForwardedHostHeader(String)
649      * @see #setForwardedProtoHeader(String)
650      * @see #setForwardedServerHeader(String)
651      */
652     public void setForwarded(boolean check)
653     {
654         if (check)
655             LOG.debug("{} is forwarded",this);
656         _forwarded = check;
657     }
658 
659     /* ------------------------------------------------------------ */
660     public String getHostHeader()
661     {
662         return _hostHeader;
663     }
664 
665     /* ------------------------------------------------------------ */
666     /**
667      * Set a forced valued for the host header to control what is returned by {@link ServletRequest#getServerName()} and {@link ServletRequest#getServerPort()}.
668      * This value is only used if {@link #isForwarded()} is true.
669      *
670      * @param hostHeader
671      *            The value of the host header to force.
672      */
673     public void setHostHeader(String hostHeader)
674     {
675         _hostHeader = hostHeader;
676     }
677 
678     /* ------------------------------------------------------------ */
679     /*
680      *
681      * @see #setForwarded(boolean)
682      */
683     public String getForwardedHostHeader()
684     {
685         return _forwardedHostHeader;
686     }
687 
688     /* ------------------------------------------------------------ */
689     /**
690      * @param forwardedHostHeader
691      *            The header name for forwarded hosts (default x-forwarded-host)
692      * @see #setForwarded(boolean)
693      */
694     public void setForwardedHostHeader(String forwardedHostHeader)
695     {
696         _forwardedHostHeader = forwardedHostHeader;
697     }
698 
699     /* ------------------------------------------------------------ */
700     /**
701      * @return the header name for forwarded server.
702      * @see #setForwarded(boolean)
703      */
704     public String getForwardedServerHeader()
705     {
706         return _forwardedServerHeader;
707     }
708 
709     /* ------------------------------------------------------------ */
710     /**
711      * @param forwardedServerHeader
712      *            The header name for forwarded server (default x-forwarded-server)
713      * @see #setForwarded(boolean)
714      */
715     public void setForwardedServerHeader(String forwardedServerHeader)
716     {
717         _forwardedServerHeader = forwardedServerHeader;
718     }
719 
720     /* ------------------------------------------------------------ */
721     /**
722      * @see #setForwarded(boolean)
723      */
724     public String getForwardedForHeader()
725     {
726         return _forwardedForHeader;
727     }
728 
729     /* ------------------------------------------------------------ */
730     /**
731      * @param forwardedRemoteAddressHeader
732      *            The header name for forwarded for (default x-forwarded-for)
733      * @see #setForwarded(boolean)
734      */
735     public void setForwardedForHeader(String forwardedRemoteAddressHeader)
736     {
737         _forwardedForHeader = forwardedRemoteAddressHeader;
738     }
739 
740     /* ------------------------------------------------------------ */
741     /**
742      * Get the forwardedProtoHeader.
743      *
744      * @return the forwardedProtoHeader (default X-Forwarded-For)
745      * @see #setForwarded(boolean)
746      */
747     public String getForwardedProtoHeader()
748     {
749         return _forwardedProtoHeader;
750     }
751 
752     /* ------------------------------------------------------------ */
753     /**
754      * Set the forwardedProtoHeader.
755      *
756      * @param forwardedProtoHeader
757      *            the forwardedProtoHeader to set (default X-Forwarded-For)
758      * @see #setForwarded(boolean)
759      */
760     public void setForwardedProtoHeader(String forwardedProtoHeader)
761     {
762         _forwardedProtoHeader = forwardedProtoHeader;
763     }
764 
765     /* ------------------------------------------------------------ */
766     /**
767      * @return The header name holding a forwarded cipher suite (default null)
768      */
769     public String getForwardedCipherSuiteHeader()
770     {
771         return _forwardedCipherSuiteHeader;
772     }
773 
774     /* ------------------------------------------------------------ */
775     /**
776      * @param forwardedCipherSuite
777      *            The header name holding a forwarded cipher suite (default null)
778      */
779     public void setForwardedCipherSuiteHeader(String forwardedCipherSuite)
780     {
781         _forwardedCipherSuiteHeader = forwardedCipherSuite;
782     }
783 
784     /* ------------------------------------------------------------ */
785     /**
786      * @return The header name holding a forwarded SSL Session ID (default null)
787      */
788     public String getForwardedSslSessionIdHeader()
789     {
790         return _forwardedSslSessionIdHeader;
791     }
792 
793     /* ------------------------------------------------------------ */
794     /**
795      * @param forwardedSslSessionId
796      *            The header name holding a forwarded SSL Session ID (default null)
797      */
798     public void setForwardedSslSessionIdHeader(String forwardedSslSessionId)
799     {
800         _forwardedSslSessionIdHeader = forwardedSslSessionId;
801     }
802 
803     public int getRequestBufferSize()
804     {
805         return _buffers.getRequestBufferSize();
806     }
807 
808     public void setRequestBufferSize(int requestBufferSize)
809     {
810         _buffers.setRequestBufferSize(requestBufferSize);
811     }
812 
813     public int getRequestHeaderSize()
814     {
815         return _buffers.getRequestHeaderSize();
816     }
817 
818     public void setRequestHeaderSize(int requestHeaderSize)
819     {
820         _buffers.setRequestHeaderSize(requestHeaderSize);
821     }
822 
823     public int getResponseBufferSize()
824     {
825         return _buffers.getResponseBufferSize();
826     }
827 
828     public void setResponseBufferSize(int responseBufferSize)
829     {
830         _buffers.setResponseBufferSize(responseBufferSize);
831     }
832 
833     public int getResponseHeaderSize()
834     {
835         return _buffers.getResponseHeaderSize();
836     }
837 
838     public void setResponseHeaderSize(int responseHeaderSize)
839     {
840         _buffers.setResponseHeaderSize(responseHeaderSize);
841     }
842 
843     public Type getRequestBufferType()
844     {
845         return _buffers.getRequestBufferType();
846     }
847 
848     public Type getRequestHeaderType()
849     {
850         return _buffers.getRequestHeaderType();
851     }
852 
853     public Type getResponseBufferType()
854     {
855         return _buffers.getResponseBufferType();
856     }
857 
858     public Type getResponseHeaderType()
859     {
860         return _buffers.getResponseHeaderType();
861     }
862 
863     public void setRequestBuffers(Buffers requestBuffers)
864     {
865         _buffers.setRequestBuffers(requestBuffers);
866     }
867 
868     public void setResponseBuffers(Buffers responseBuffers)
869     {
870         _buffers.setResponseBuffers(responseBuffers);
871     }
872 
873     public Buffers getRequestBuffers()
874     {
875         return _buffers.getRequestBuffers();
876     }
877 
878     public Buffers getResponseBuffers()
879     {
880         return _buffers.getResponseBuffers();
881     }
882 
883     public void setMaxBuffers(int maxBuffers)
884     {
885         _buffers.setMaxBuffers(maxBuffers);
886     }
887 
888     public int getMaxBuffers()
889     {
890         return _buffers.getMaxBuffers();
891     }
892 
893     /* ------------------------------------------------------------ */
894     @Override
895     public String toString()
896     {
897         return String.format("%s@%s:%d",
898                 getClass().getSimpleName(),
899                 getHost()==null?"0.0.0.0":getHost(),
900                 getLocalPort()<=0?getPort():getLocalPort());
901     }
902 
903     /* ------------------------------------------------------------ */
904     /* ------------------------------------------------------------ */
905     /* ------------------------------------------------------------ */
906     private class Acceptor implements Runnable
907     {
908         int _acceptor = 0;
909 
910         Acceptor(int id)
911         {
912             _acceptor = id;
913         }
914 
915         /* ------------------------------------------------------------ */
916         public void run()
917         {
918             Thread current = Thread.currentThread();
919             String name;
920             synchronized (AbstractConnector.this)
921             {
922                 if (_acceptorThreads == null)
923                     return;
924 
925                 _acceptorThreads[_acceptor] = current;
926                 name = _acceptorThreads[_acceptor].getName();
927                 current.setName(name + " Acceptor" + _acceptor + " " + AbstractConnector.this);
928             }
929             int old_priority = current.getPriority();
930 
931             try
932             {
933                 current.setPriority(old_priority - _acceptorPriorityOffset);
934                 while (isRunning() && getConnection() != null)
935                 {
936                     try
937                     {
938                         accept(_acceptor);
939                     }
940                     catch (EofException e)
941                     {
942                         LOG.ignore(e);
943                     }
944                     catch (IOException e)
945                     {
946                         LOG.ignore(e);
947                     }
948                     catch (InterruptedException x)
949                     {
950                         // Connector has been stopped
951                         LOG.ignore(x);
952                     }
953                     catch (Throwable e)
954                     {
955                         LOG.warn(e);
956                     }
957                 }
958             }
959             finally
960             {
961                 current.setPriority(old_priority);
962                 current.setName(name);
963 
964                 synchronized (AbstractConnector.this)
965                 {
966                     if (_acceptorThreads != null)
967                         _acceptorThreads[_acceptor] = null;
968                 }
969             }
970         }
971     }
972 
973     /* ------------------------------------------------------------ */
974     public String getName()
975     {
976         if (_name == null)
977             _name = (getHost() == null?"0.0.0.0":getHost()) + ":" + (getLocalPort() <= 0?getPort():getLocalPort());
978         return _name;
979     }
980 
981     /* ------------------------------------------------------------ */
982     public void setName(String name)
983     {
984         _name = name;
985     }
986 
987     /* ------------------------------------------------------------ */
988     /**
989      * @return Get the number of requests handled by this connector since last call of statsReset(). If setStatsOn(false) then this is undefined.
990      */
991     public int getRequests()
992     {
993         return (int)_requestStats.getTotal();
994     }
995 
996     /* ------------------------------------------------------------ */
997     /**
998      * @return Returns the connectionsDurationTotal.
999      */
1000     public long getConnectionsDurationTotal()
1001     {
1002         return _connectionDurationStats.getTotal();
1003     }
1004 
1005     /* ------------------------------------------------------------ */
1006     /**
1007      * @return Number of connections accepted by the server since statsReset() called. Undefined if setStatsOn(false).
1008      */
1009     public int getConnections()
1010     {
1011         return (int)_connectionStats.getTotal();
1012     }
1013 
1014     /* ------------------------------------------------------------ */
1015     /**
1016      * @return Number of connections currently open that were opened since statsReset() called. Undefined if setStatsOn(false).
1017      */
1018     public int getConnectionsOpen()
1019     {
1020         return (int)_connectionStats.getCurrent();
1021     }
1022 
1023     /* ------------------------------------------------------------ */
1024     /**
1025      * @return Maximum number of connections opened simultaneously since statsReset() called. Undefined if setStatsOn(false).
1026      */
1027     public int getConnectionsOpenMax()
1028     {
1029         return (int)_connectionStats.getMax();
1030     }
1031 
1032     /* ------------------------------------------------------------ */
1033     /**
1034      * @return Mean duration in milliseconds of open connections since statsReset() called. Undefined if setStatsOn(false).
1035      */
1036     public double getConnectionsDurationMean()
1037     {
1038         return _connectionDurationStats.getMean();
1039     }
1040 
1041     /* ------------------------------------------------------------ */
1042     /**
1043      * @return Maximum duration in milliseconds of an open connection since statsReset() called. Undefined if setStatsOn(false).
1044      */
1045     public long getConnectionsDurationMax()
1046     {
1047         return _connectionDurationStats.getMax();
1048     }
1049 
1050     /* ------------------------------------------------------------ */
1051     /**
1052      * @return Standard deviation of duration in milliseconds of open connections since statsReset() called. Undefined if setStatsOn(false).
1053      */
1054     public double getConnectionsDurationStdDev()
1055     {
1056         return _connectionDurationStats.getStdDev();
1057     }
1058 
1059     /* ------------------------------------------------------------ */
1060     /**
1061      * @return Mean number of requests per connection since statsReset() called. Undefined if setStatsOn(false).
1062      */
1063     public double getConnectionsRequestsMean()
1064     {
1065         return _requestStats.getMean();
1066     }
1067 
1068     /* ------------------------------------------------------------ */
1069     /**
1070      * @return Maximum number of requests per connection since statsReset() called. Undefined if setStatsOn(false).
1071      */
1072     public int getConnectionsRequestsMax()
1073     {
1074         return (int)_requestStats.getMax();
1075     }
1076 
1077     /* ------------------------------------------------------------ */
1078     /**
1079      * @return Standard deviation of number of requests per connection since statsReset() called. Undefined if setStatsOn(false).
1080      */
1081     public double getConnectionsRequestsStdDev()
1082     {
1083         return _requestStats.getStdDev();
1084     }
1085 
1086     /* ------------------------------------------------------------ */
1087     /**
1088      * Reset statistics.
1089      */
1090     public void statsReset()
1091     {
1092         updateNotEqual(_statsStartedAt,-1,System.currentTimeMillis());
1093 
1094         _requestStats.reset();
1095         _connectionStats.reset();
1096         _connectionDurationStats.reset();
1097     }
1098 
1099     /* ------------------------------------------------------------ */
1100     public void setStatsOn(boolean on)
1101     {
1102         if (on && _statsStartedAt.get() != -1)
1103             return;
1104 
1105         if (LOG.isDebugEnabled())
1106             LOG.debug("Statistics on = " + on + " for " + this);
1107 
1108         statsReset();
1109         _statsStartedAt.set(on?System.currentTimeMillis():-1);
1110     }
1111 
1112     /* ------------------------------------------------------------ */
1113     /**
1114      * @return True if statistics collection is turned on.
1115      */
1116     public boolean getStatsOn()
1117     {
1118         return _statsStartedAt.get() != -1;
1119     }
1120 
1121     /* ------------------------------------------------------------ */
1122     /**
1123      * @return Timestamp stats were started at.
1124      */
1125     public long getStatsOnMs()
1126     {
1127         long start = _statsStartedAt.get();
1128 
1129         return (start != -1)?(System.currentTimeMillis() - start):0;
1130     }
1131 
1132     /* ------------------------------------------------------------ */
1133     protected void connectionOpened(Connection connection)
1134     {
1135         if (_statsStartedAt.get() == -1)
1136             return;
1137 
1138         _connectionStats.increment();
1139     }
1140 
1141     /* ------------------------------------------------------------ */
1142     protected void connectionUpgraded(Connection oldConnection, Connection newConnection)
1143     {
1144         _requestStats.set((oldConnection instanceof AbstractHttpConnection)?((AbstractHttpConnection)oldConnection).getRequests():0);
1145     }
1146 
1147     /* ------------------------------------------------------------ */
1148     protected void connectionClosed(Connection connection)
1149     {
1150         connection.onClose();
1151 
1152         if (_statsStartedAt.get() == -1)
1153             return;
1154 
1155         long duration = System.currentTimeMillis() - connection.getTimeStamp();
1156         int requests = (connection instanceof AbstractHttpConnection)?((AbstractHttpConnection)connection).getRequests():0;
1157         _requestStats.set(requests);
1158         _connectionStats.decrement();
1159         _connectionDurationStats.set(duration);
1160     }
1161 
1162     /* ------------------------------------------------------------ */
1163     /**
1164      * @return the acceptorPriority
1165      */
1166     public int getAcceptorPriorityOffset()
1167     {
1168         return _acceptorPriorityOffset;
1169     }
1170 
1171     /* ------------------------------------------------------------ */
1172     /**
1173      * Set the priority offset of the acceptor threads. The priority is adjusted by this amount (default 0) to either favour the acceptance of new threads and
1174      * newly active connections or to favour the handling of already dispatched connections.
1175      *
1176      * @param offset
1177      *            the amount to alter the priority of the acceptor threads.
1178      */
1179     public void setAcceptorPriorityOffset(int offset)
1180     {
1181         _acceptorPriorityOffset = offset;
1182     }
1183 
1184     /* ------------------------------------------------------------ */
1185     /**
1186      * @return True if the the server socket will be opened in SO_REUSEADDR mode.
1187      */
1188     public boolean getReuseAddress()
1189     {
1190         return _reuseAddress;
1191     }
1192 
1193     /* ------------------------------------------------------------ */
1194     /**
1195      * @param reuseAddress
1196      *            True if the the server socket will be opened in SO_REUSEADDR mode.
1197      */
1198     public void setReuseAddress(boolean reuseAddress)
1199     {
1200         _reuseAddress = reuseAddress;
1201     }
1202 
1203     /* ------------------------------------------------------------ */
1204     public boolean isLowResources()
1205     {
1206         if (_threadPool != null)
1207             return _threadPool.isLowOnThreads();
1208         return _server.getThreadPool().isLowOnThreads();
1209     }
1210 
1211     /* ------------------------------------------------------------ */
1212     private void updateNotEqual(AtomicLong valueHolder, long compare, long value)
1213     {
1214         long oldValue = valueHolder.get();
1215         while (compare != oldValue)
1216         {
1217             if (valueHolder.compareAndSet(oldValue,value))
1218                 break;
1219             oldValue = valueHolder.get();
1220         }
1221     }
1222 }