View Javadoc

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