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  
22  import javax.servlet.ServletRequest;
23  
24  import org.eclipse.jetty.http.HttpBuffers;
25  import org.eclipse.jetty.http.HttpBuffersImpl;
26  import org.eclipse.jetty.http.HttpFields;
27  import org.eclipse.jetty.http.HttpHeaders;
28  import org.eclipse.jetty.http.HttpSchemes;
29  import org.eclipse.jetty.io.Buffers;
30  import org.eclipse.jetty.io.Buffers.Type;
31  import org.eclipse.jetty.io.Connection;
32  import org.eclipse.jetty.io.EndPoint;
33  import org.eclipse.jetty.io.EofException;
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  public abstract class AbstractConnector extends AggregateLifeCycle implements HttpBuffers, Connector, Dumpable
54  {
55      private static final Logger LOG = Log.getLogger(AbstractConnector.class);
56  
57      private String _name;
58  
59      private Server _server;
60      private ThreadPool _threadPool;
61      private String _host;
62      private int _port = 0;
63      private String _integralScheme = HttpSchemes.HTTPS;
64      private int _integralPort = 0;
65      private String _confidentialScheme = HttpSchemes.HTTPS;
66      private int _confidentialPort = 0;
67      private int _acceptQueueSize = 0;
68      private int _acceptors = 1;
69      private int _acceptorPriorityOffset = 0;
70      private boolean _useDNS;
71      private boolean _forwarded;
72      private String _hostHeader;
73  
74      private String _forwardedHostHeader = HttpHeaders.X_FORWARDED_HOST;
75      private String _forwardedServerHeader = HttpHeaders.X_FORWARDED_SERVER;
76      private String _forwardedForHeader = HttpHeaders.X_FORWARDED_FOR;
77      private String _forwardedProtoHeader = HttpHeaders.X_FORWARDED_PROTO;
78      private String _forwardedCipherSuiteHeader;
79      private String _forwardedSslSessionIdHeader;
80      private boolean _reuseAddress = true;
81  
82      protected int _maxIdleTime = 200000;
83      protected int _lowResourceMaxIdleTime = -1;
84      protected int _soLingerTime = -1;
85  
86      private transient Thread[] _acceptorThreads;
87  
88      private final AtomicLong _statsStartedAt = new AtomicLong(-1L);
89  
90      /** connections to server */
91      private final CounterStatistic _connectionStats = new CounterStatistic();
92      /** requests per connection */
93      private final SampleStatistic _requestStats = new SampleStatistic();
94      /** duration of a connection */
95      private final SampleStatistic _connectionDurationStats = new SampleStatistic();
96  
97      protected final HttpBuffersImpl _buffers = new HttpBuffersImpl();
98  
99      /* ------------------------------------------------------------ */
100     /**
101      */
102     public AbstractConnector()
103     {
104         addBean(_buffers);
105     }
106 
107     /* ------------------------------------------------------------ */
108     /*
109      */
110     public Server getServer()
111     {
112         return _server;
113     }
114 
115     /* ------------------------------------------------------------ */
116     public void setServer(Server server)
117     {
118         _server = server;
119     }
120 
121     /* ------------------------------------------------------------ */
122     public ThreadPool getThreadPool()
123     {
124         return _threadPool;
125     }
126 
127     /* ------------------------------------------------------------ */
128     /** Set the ThreadPool.
129      * The threadpool passed is added via {@link #addBean(Object)} so that 
130      * it's lifecycle may be managed as a {@link AggregateLifeCycle}.
131      * @param pool the threadPool to set
132      */
133     public void setThreadPool(ThreadPool pool)
134     {
135         removeBean(_threadPool);
136         _threadPool = pool;
137         addBean(_threadPool);
138     }
139 
140     /* ------------------------------------------------------------ */
141     /**
142      */
143     public void setHost(String host)
144     {
145         _host = host;
146     }
147 
148     /* ------------------------------------------------------------ */
149     /*
150      */
151     public String getHost()
152     {
153         return _host;
154     }
155 
156     /* ------------------------------------------------------------ */
157     public void setPort(int port)
158     {
159         _port = port;
160     }
161 
162     /* ------------------------------------------------------------ */
163     public int getPort()
164     {
165         return _port;
166     }
167 
168     /* ------------------------------------------------------------ */
169     /**
170      * @return Returns the maxIdleTime.
171      */
172     public int getMaxIdleTime()
173     {
174         return _maxIdleTime;
175     }
176 
177     /* ------------------------------------------------------------ */
178     /**
179      * Set the maximum Idle time for a connection, which roughly translates to the {@link Socket#setSoTimeout(int)} call, although with NIO implementations
180      * other mechanisms may be used to implement the timeout. The max idle time is applied:
181      * <ul>
182      * <li>When waiting for a new request to be received on a connection</li>
183      * <li>When reading the headers and content of a request</li>
184      * <li>When writing the headers and content of a response</li>
185      * </ul>
186      * 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
187      * 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
188      * 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
189      * take many 10s of seconds for large content written to a slow device.
190      * <p>
191      * Previously, Jetty supported separate idle timeouts and IO operation timeouts, however the expense of changing the value of soTimeout was significant, so
192      * these timeouts were merged. With the advent of NIO, it may be possible to again differentiate these values (if there is demand).
193      *
194      * @param maxIdleTime
195      *            The maxIdleTime to set.
196      */
197     public void setMaxIdleTime(int maxIdleTime)
198     {
199         _maxIdleTime = maxIdleTime;
200     }
201 
202     /* ------------------------------------------------------------ */
203     /**
204      * @return Returns the maxIdleTime when resources are low.
205      */
206     public int getLowResourcesMaxIdleTime()
207     {
208         return _lowResourceMaxIdleTime;
209     }
210 
211     /* ------------------------------------------------------------ */
212     /**
213      * @param maxIdleTime
214      *            The maxIdleTime to set when resources are low.
215      */
216     public void setLowResourcesMaxIdleTime(int maxIdleTime)
217     {
218         _lowResourceMaxIdleTime = maxIdleTime;
219     }
220 
221     /* ------------------------------------------------------------ */
222     /**
223      * @return Returns the maxIdleTime when resources are low.
224      * @deprecated
225      */
226     @Deprecated
227     public final int getLowResourceMaxIdleTime()
228     {
229         return getLowResourcesMaxIdleTime();
230     }
231 
232     /* ------------------------------------------------------------ */
233     /**
234      * @param maxIdleTime
235      *            The maxIdleTime to set when resources are low.
236      * @deprecated
237      */
238     @Deprecated
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      * @see #setForwardedForHeader(String)
643      * @see #setForwardedHostHeader(String)
644      * @see #setForwardedProtoHeader(String)
645      * @see #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",
893                 getClass().getSimpleName(),
894                 getHost()==null?"0.0.0.0":getHost(),
895                 getLocalPort()<=0?getPort():getLocalPort());
896     }
897 
898     /* ------------------------------------------------------------ */
899     /* ------------------------------------------------------------ */
900     /* ------------------------------------------------------------ */
901     private class Acceptor implements Runnable
902     {
903         int _acceptor = 0;
904 
905         Acceptor(int id)
906         {
907             _acceptor = id;
908         }
909 
910         /* ------------------------------------------------------------ */
911         public void run()
912         {
913             Thread current = Thread.currentThread();
914             String name;
915             synchronized (AbstractConnector.this)
916             {
917                 if (_acceptorThreads == null)
918                     return;
919 
920                 _acceptorThreads[_acceptor] = current;
921                 name = _acceptorThreads[_acceptor].getName();
922                 current.setName(name + " Acceptor" + _acceptor + " " + AbstractConnector.this);
923             }
924             int old_priority = current.getPriority();
925 
926             try
927             {
928                 current.setPriority(old_priority - _acceptorPriorityOffset);
929                 while (isRunning() && getConnection() != null)
930                 {
931                     try
932                     {
933                         accept(_acceptor);
934                     }
935                     catch (EofException e)
936                     {
937                         LOG.ignore(e);
938                     }
939                     catch (IOException e)
940                     {
941                         LOG.ignore(e);
942                     }
943                     catch (InterruptedException x)
944                     {
945                         // Connector has been stopped
946                         LOG.ignore(x);
947                     }
948                     catch (Throwable e)
949                     {
950                         LOG.warn(e);
951                     }
952                 }
953             }
954             finally
955             {
956                 current.setPriority(old_priority);
957                 current.setName(name);
958 
959                 synchronized (AbstractConnector.this)
960                 {
961                     if (_acceptorThreads != null)
962                         _acceptorThreads[_acceptor] = null;
963                 }
964             }
965         }
966     }
967 
968     /* ------------------------------------------------------------ */
969     public String getName()
970     {
971         if (_name == null)
972             _name = (getHost() == null?"0.0.0.0":getHost()) + ":" + (getLocalPort() <= 0?getPort():getLocalPort());
973         return _name;
974     }
975 
976     /* ------------------------------------------------------------ */
977     public void setName(String name)
978     {
979         _name = name;
980     }
981 
982     /* ------------------------------------------------------------ */
983     /**
984      * @return Get the number of requests handled by this connector since last call of statsReset(). If setStatsOn(false) then this is undefined.
985      */
986     public int getRequests()
987     {
988         return (int)_requestStats.getTotal();
989     }
990 
991     /* ------------------------------------------------------------ */
992     /**
993      * @return Returns the connectionsDurationTotal.
994      */
995     public long getConnectionsDurationTotal()
996     {
997         return _connectionDurationStats.getTotal();
998     }
999 
1000     /* ------------------------------------------------------------ */
1001     /**
1002      * @return Number of connections accepted by the server since statsReset() called. Undefined if setStatsOn(false).
1003      */
1004     public int getConnections()
1005     {
1006         return (int)_connectionStats.getTotal();
1007     }
1008 
1009     /* ------------------------------------------------------------ */
1010     /**
1011      * @return Number of connections currently open that were opened since statsReset() called. Undefined if setStatsOn(false).
1012      */
1013     public int getConnectionsOpen()
1014     {
1015         return (int)_connectionStats.getCurrent();
1016     }
1017 
1018     /* ------------------------------------------------------------ */
1019     /**
1020      * @return Maximum number of connections opened simultaneously since statsReset() called. Undefined if setStatsOn(false).
1021      */
1022     public int getConnectionsOpenMax()
1023     {
1024         return (int)_connectionStats.getMax();
1025     }
1026 
1027     /* ------------------------------------------------------------ */
1028     /**
1029      * @return Mean duration in milliseconds of open connections since statsReset() called. Undefined if setStatsOn(false).
1030      */
1031     public double getConnectionsDurationMean()
1032     {
1033         return _connectionDurationStats.getMean();
1034     }
1035 
1036     /* ------------------------------------------------------------ */
1037     /**
1038      * @return Maximum duration in milliseconds of an open connection since statsReset() called. Undefined if setStatsOn(false).
1039      */
1040     public long getConnectionsDurationMax()
1041     {
1042         return _connectionDurationStats.getMax();
1043     }
1044 
1045     /* ------------------------------------------------------------ */
1046     /**
1047      * @return Standard deviation of duration in milliseconds of open connections since statsReset() called. Undefined if setStatsOn(false).
1048      */
1049     public double getConnectionsDurationStdDev()
1050     {
1051         return _connectionDurationStats.getStdDev();
1052     }
1053 
1054     /* ------------------------------------------------------------ */
1055     /**
1056      * @return Mean number of requests per connection since statsReset() called. Undefined if setStatsOn(false).
1057      */
1058     public double getConnectionsRequestsMean()
1059     {
1060         return _requestStats.getMean();
1061     }
1062 
1063     /* ------------------------------------------------------------ */
1064     /**
1065      * @return Maximum number of requests per connection since statsReset() called. Undefined if setStatsOn(false).
1066      */
1067     public int getConnectionsRequestsMax()
1068     {
1069         return (int)_requestStats.getMax();
1070     }
1071 
1072     /* ------------------------------------------------------------ */
1073     /**
1074      * @return Standard deviation of number of requests per connection since statsReset() called. Undefined if setStatsOn(false).
1075      */
1076     public double getConnectionsRequestsStdDev()
1077     {
1078         return _requestStats.getStdDev();
1079     }
1080 
1081     /* ------------------------------------------------------------ */
1082     /**
1083      * Reset statistics.
1084      */
1085     public void statsReset()
1086     {
1087         updateNotEqual(_statsStartedAt,-1,System.currentTimeMillis());
1088 
1089         _requestStats.reset();
1090         _connectionStats.reset();
1091         _connectionDurationStats.reset();
1092     }
1093 
1094     /* ------------------------------------------------------------ */
1095     public void setStatsOn(boolean on)
1096     {
1097         if (on && _statsStartedAt.get() != -1)
1098             return;
1099 
1100         if (LOG.isDebugEnabled())
1101             LOG.debug("Statistics on = " + on + " for " + this);
1102 
1103         statsReset();
1104         _statsStartedAt.set(on?System.currentTimeMillis():-1);
1105     }
1106 
1107     /* ------------------------------------------------------------ */
1108     /**
1109      * @return True if statistics collection is turned on.
1110      */
1111     public boolean getStatsOn()
1112     {
1113         return _statsStartedAt.get() != -1;
1114     }
1115 
1116     /* ------------------------------------------------------------ */
1117     /**
1118      * @return Timestamp stats were started at.
1119      */
1120     public long getStatsOnMs()
1121     {
1122         long start = _statsStartedAt.get();
1123 
1124         return (start != -1)?(System.currentTimeMillis() - start):0;
1125     }
1126 
1127     /* ------------------------------------------------------------ */
1128     protected void connectionOpened(Connection connection)
1129     {
1130         if (_statsStartedAt.get() == -1)
1131             return;
1132 
1133         _connectionStats.increment();
1134     }
1135 
1136     /* ------------------------------------------------------------ */
1137     protected void connectionUpgraded(Connection oldConnection, Connection newConnection)
1138     {
1139         _requestStats.set((oldConnection instanceof AbstractHttpConnection)?((AbstractHttpConnection)oldConnection).getRequests():0);
1140     }
1141 
1142     /* ------------------------------------------------------------ */
1143     protected void connectionClosed(Connection connection)
1144     {
1145         connection.onClose();
1146 
1147         if (_statsStartedAt.get() == -1)
1148             return;
1149 
1150         long duration = System.currentTimeMillis() - connection.getTimeStamp();
1151         int requests = (connection instanceof AbstractHttpConnection)?((AbstractHttpConnection)connection).getRequests():0;
1152         _requestStats.set(requests);
1153         _connectionStats.decrement();
1154         _connectionDurationStats.set(duration);
1155     }
1156 
1157     /* ------------------------------------------------------------ */
1158     /**
1159      * @return the acceptorPriority
1160      */
1161     public int getAcceptorPriorityOffset()
1162     {
1163         return _acceptorPriorityOffset;
1164     }
1165 
1166     /* ------------------------------------------------------------ */
1167     /**
1168      * 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
1169      * newly active connections or to favour the handling of already dispatched connections.
1170      *
1171      * @param offset
1172      *            the amount to alter the priority of the acceptor threads.
1173      */
1174     public void setAcceptorPriorityOffset(int offset)
1175     {
1176         _acceptorPriorityOffset = offset;
1177     }
1178 
1179     /* ------------------------------------------------------------ */
1180     /**
1181      * @return True if the the server socket will be opened in SO_REUSEADDR mode.
1182      */
1183     public boolean getReuseAddress()
1184     {
1185         return _reuseAddress;
1186     }
1187 
1188     /* ------------------------------------------------------------ */
1189     /**
1190      * @param reuseAddress
1191      *            True if the the server socket will be opened in SO_REUSEADDR mode.
1192      */
1193     public void setReuseAddress(boolean reuseAddress)
1194     {
1195         _reuseAddress = reuseAddress;
1196     }
1197 
1198     /* ------------------------------------------------------------ */
1199     public boolean isLowResources()
1200     {
1201         if (_threadPool != null)
1202             return _threadPool.isLowOnThreads();
1203         return _server.getThreadPool().isLowOnThreads();
1204     }
1205 
1206     /* ------------------------------------------------------------ */
1207     private void updateNotEqual(AtomicLong valueHolder, long compare, long value)
1208     {
1209         long oldValue = valueHolder.get();
1210         while (compare != oldValue)
1211         {
1212             if (valueHolder.compareAndSet(oldValue,value))
1213                 break;
1214             oldValue = valueHolder.get();
1215         }
1216     }
1217 }