1 // 2 // ======================================================================== 3 // Copyright (c) 1995-2014 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 */ AbstractConnector()107 public AbstractConnector() 108 { 109 addBean(_buffers); 110 } 111 112 /* ------------------------------------------------------------ */ 113 /* 114 */ getServer()115 public Server getServer() 116 { 117 return _server; 118 } 119 120 /* ------------------------------------------------------------ */ setServer(Server server)121 public void setServer(Server server) 122 { 123 _server = server; 124 } 125 126 /* ------------------------------------------------------------ */ getThreadPool()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 */ setThreadPool(ThreadPool pool)138 public void setThreadPool(ThreadPool pool) 139 { 140 removeBean(_threadPool); 141 _threadPool = pool; 142 addBean(_threadPool); 143 } 144 145 /* ------------------------------------------------------------ */ 146 /** 147 */ setHost(String host)148 public void setHost(String host) 149 { 150 _host = host; 151 } 152 153 /* ------------------------------------------------------------ */ 154 /* 155 */ getHost()156 public String getHost() 157 { 158 return _host; 159 } 160 161 /* ------------------------------------------------------------ */ setPort(int port)162 public void setPort(int port) 163 { 164 _port = port; 165 } 166 167 /* ------------------------------------------------------------ */ getPort()168 public int getPort() 169 { 170 return _port; 171 } 172 173 /* ------------------------------------------------------------ */ 174 /** 175 * @return Returns the maxIdleTime. 176 */ getMaxIdleTime()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 */ setMaxIdleTime(int maxIdleTime)202 public void setMaxIdleTime(int maxIdleTime) 203 { 204 _maxIdleTime = maxIdleTime; 205 } 206 207 /* ------------------------------------------------------------ */ 208 /** 209 * @return Returns the maxIdleTime when resources are low. 210 */ getLowResourcesMaxIdleTime()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 */ setLowResourcesMaxIdleTime(int maxIdleTime)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 getLowResourceMaxIdleTime()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 setLowResourceMaxIdleTime(int maxIdleTime)244 public final void setLowResourceMaxIdleTime(int maxIdleTime) 245 { 246 setLowResourcesMaxIdleTime(maxIdleTime); 247 } 248 249 /* ------------------------------------------------------------ */ 250 /** 251 * @return Returns the soLingerTime. 252 */ getSoLingerTime()253 public int getSoLingerTime() 254 { 255 return _soLingerTime; 256 } 257 258 /* ------------------------------------------------------------ */ 259 /** 260 * @return Returns the acceptQueueSize. 261 */ getAcceptQueueSize()262 public int getAcceptQueueSize() 263 { 264 return _acceptQueueSize; 265 } 266 267 /* ------------------------------------------------------------ */ 268 /** 269 * @param acceptQueueSize 270 * The acceptQueueSize to set. 271 */ setAcceptQueueSize(int acceptQueueSize)272 public void setAcceptQueueSize(int acceptQueueSize) 273 { 274 _acceptQueueSize = acceptQueueSize; 275 } 276 277 /* ------------------------------------------------------------ */ 278 /** 279 * @return Returns the number of acceptor threads. 280 */ getAcceptors()281 public int getAcceptors() 282 { 283 return _acceptors; 284 } 285 286 /* ------------------------------------------------------------ */ 287 /** 288 * @param acceptors 289 * The number of acceptor threads to set. 290 */ setAcceptors(int acceptors)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 */ setSoLingerTime(int soLingerTime)303 public void setSoLingerTime(int soLingerTime) 304 { 305 _soLingerTime = soLingerTime; 306 } 307 308 /* ------------------------------------------------------------ */ 309 @Override doStart()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 doStop()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 /* ------------------------------------------------------------ */ join()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 /* ------------------------------------------------------------ */ configure(Socket socket)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 /* ------------------------------------------------------------ */ customize(EndPoint endpoint, Request request)404 public void customize(EndPoint endpoint, Request request) throws IOException 405 { 406 if (isForwarded()) 407 checkForwardedHeaders(endpoint,request); 408 } 409 410 /* ------------------------------------------------------------ */ checkForwardedHeaders(EndPoint endpoint, Request request)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 /* ------------------------------------------------------------ */ getLeftMostFieldValue(HttpFields fields, String header)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 /* ------------------------------------------------------------ */ persist(EndPoint endpoint)510 public void persist(EndPoint endpoint) throws IOException 511 { 512 } 513 514 /* ------------------------------------------------------------ */ 515 /* 516 * @see org.eclipse.jetty.server.Connector#getConfidentialPort() 517 */ getConfidentialPort()518 public int getConfidentialPort() 519 { 520 return _confidentialPort; 521 } 522 523 /* ------------------------------------------------------------ */ 524 /* ------------------------------------------------------------ */ 525 /* 526 * @see org.eclipse.jetty.server.Connector#getConfidentialScheme() 527 */ getConfidentialScheme()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 */ isIntegral(Request request)537 public boolean isIntegral(Request request) 538 { 539 return false; 540 } 541 542 /* ------------------------------------------------------------ */ 543 /* 544 * @see org.eclipse.jetty.server.Connector#getConfidentialPort() 545 */ getIntegralPort()546 public int getIntegralPort() 547 { 548 return _integralPort; 549 } 550 551 /* ------------------------------------------------------------ */ 552 /* 553 * @see org.eclipse.jetty.server.Connector#getIntegralScheme() 554 */ getIntegralScheme()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 */ isConfidential(Request request)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 */ setConfidentialPort(int confidentialPort)574 public void setConfidentialPort(int confidentialPort) 575 { 576 _confidentialPort = confidentialPort; 577 } 578 579 /* ------------------------------------------------------------ */ 580 /** 581 * @param confidentialScheme 582 * The confidentialScheme to set. 583 */ setConfidentialScheme(String confidentialScheme)584 public void setConfidentialScheme(String confidentialScheme) 585 { 586 _confidentialScheme = confidentialScheme; 587 } 588 589 /* ------------------------------------------------------------ */ 590 /** 591 * @param integralPort 592 * The integralPort to set. 593 */ setIntegralPort(int integralPort)594 public void setIntegralPort(int integralPort) 595 { 596 _integralPort = integralPort; 597 } 598 599 /* ------------------------------------------------------------ */ 600 /** 601 * @param integralScheme 602 * The integralScheme to set. 603 */ setIntegralScheme(String integralScheme)604 public void setIntegralScheme(String integralScheme) 605 { 606 _integralScheme = integralScheme; 607 } 608 609 /* ------------------------------------------------------------ */ accept(int acceptorID)610 protected abstract void accept(int acceptorID) throws IOException, InterruptedException; 611 612 /* ------------------------------------------------------------ */ stopAccept(int acceptorID)613 public void stopAccept(int acceptorID) throws Exception 614 { 615 } 616 617 /* ------------------------------------------------------------ */ getResolveNames()618 public boolean getResolveNames() 619 { 620 return _useDNS; 621 } 622 623 /* ------------------------------------------------------------ */ setResolveNames(boolean resolve)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 */ isForwarded()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 */ setForwarded(boolean check)652 public void setForwarded(boolean check) 653 { 654 if (check) 655 LOG.debug("{} is forwarded",this); 656 _forwarded = check; 657 } 658 659 /* ------------------------------------------------------------ */ getHostHeader()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 */ setHostHeader(String hostHeader)673 public void setHostHeader(String hostHeader) 674 { 675 _hostHeader = hostHeader; 676 } 677 678 /* ------------------------------------------------------------ */ 679 /* 680 * 681 * @see #setForwarded(boolean) 682 */ getForwardedHostHeader()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 */ setForwardedHostHeader(String forwardedHostHeader)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 */ getForwardedServerHeader()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 */ setForwardedServerHeader(String forwardedServerHeader)715 public void setForwardedServerHeader(String forwardedServerHeader) 716 { 717 _forwardedServerHeader = forwardedServerHeader; 718 } 719 720 /* ------------------------------------------------------------ */ 721 /** 722 * @see #setForwarded(boolean) 723 */ getForwardedForHeader()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 */ setForwardedForHeader(String forwardedRemoteAddressHeader)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 */ getForwardedProtoHeader()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 */ setForwardedProtoHeader(String forwardedProtoHeader)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 */ getForwardedCipherSuiteHeader()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 */ setForwardedCipherSuiteHeader(String forwardedCipherSuite)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 */ getForwardedSslSessionIdHeader()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 */ setForwardedSslSessionIdHeader(String forwardedSslSessionId)798 public void setForwardedSslSessionIdHeader(String forwardedSslSessionId) 799 { 800 _forwardedSslSessionIdHeader = forwardedSslSessionId; 801 } 802 getRequestBufferSize()803 public int getRequestBufferSize() 804 { 805 return _buffers.getRequestBufferSize(); 806 } 807 setRequestBufferSize(int requestBufferSize)808 public void setRequestBufferSize(int requestBufferSize) 809 { 810 _buffers.setRequestBufferSize(requestBufferSize); 811 } 812 getRequestHeaderSize()813 public int getRequestHeaderSize() 814 { 815 return _buffers.getRequestHeaderSize(); 816 } 817 setRequestHeaderSize(int requestHeaderSize)818 public void setRequestHeaderSize(int requestHeaderSize) 819 { 820 _buffers.setRequestHeaderSize(requestHeaderSize); 821 } 822 getResponseBufferSize()823 public int getResponseBufferSize() 824 { 825 return _buffers.getResponseBufferSize(); 826 } 827 setResponseBufferSize(int responseBufferSize)828 public void setResponseBufferSize(int responseBufferSize) 829 { 830 _buffers.setResponseBufferSize(responseBufferSize); 831 } 832 getResponseHeaderSize()833 public int getResponseHeaderSize() 834 { 835 return _buffers.getResponseHeaderSize(); 836 } 837 setResponseHeaderSize(int responseHeaderSize)838 public void setResponseHeaderSize(int responseHeaderSize) 839 { 840 _buffers.setResponseHeaderSize(responseHeaderSize); 841 } 842 getRequestBufferType()843 public Type getRequestBufferType() 844 { 845 return _buffers.getRequestBufferType(); 846 } 847 getRequestHeaderType()848 public Type getRequestHeaderType() 849 { 850 return _buffers.getRequestHeaderType(); 851 } 852 getResponseBufferType()853 public Type getResponseBufferType() 854 { 855 return _buffers.getResponseBufferType(); 856 } 857 getResponseHeaderType()858 public Type getResponseHeaderType() 859 { 860 return _buffers.getResponseHeaderType(); 861 } 862 setRequestBuffers(Buffers requestBuffers)863 public void setRequestBuffers(Buffers requestBuffers) 864 { 865 _buffers.setRequestBuffers(requestBuffers); 866 } 867 setResponseBuffers(Buffers responseBuffers)868 public void setResponseBuffers(Buffers responseBuffers) 869 { 870 _buffers.setResponseBuffers(responseBuffers); 871 } 872 getRequestBuffers()873 public Buffers getRequestBuffers() 874 { 875 return _buffers.getRequestBuffers(); 876 } 877 getResponseBuffers()878 public Buffers getResponseBuffers() 879 { 880 return _buffers.getResponseBuffers(); 881 } 882 setMaxBuffers(int maxBuffers)883 public void setMaxBuffers(int maxBuffers) 884 { 885 _buffers.setMaxBuffers(maxBuffers); 886 } 887 getMaxBuffers()888 public int getMaxBuffers() 889 { 890 return _buffers.getMaxBuffers(); 891 } 892 893 /* ------------------------------------------------------------ */ 894 @Override toString()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 Acceptor(int id)910 Acceptor(int id) 911 { 912 _acceptor = id; 913 } 914 915 /* ------------------------------------------------------------ */ run()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 /* ------------------------------------------------------------ */ getName()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 /* ------------------------------------------------------------ */ setName(String name)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 */ getRequests()991 public int getRequests() 992 { 993 return (int)_requestStats.getTotal(); 994 } 995 996 /* ------------------------------------------------------------ */ 997 /** 998 * @return Returns the connectionsDurationTotal. 999 */ getConnectionsDurationTotal()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 */ getConnections()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 */ getConnectionsOpen()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 */ getConnectionsOpenMax()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 */ getConnectionsDurationMean()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 */ getConnectionsDurationMax()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 */ getConnectionsDurationStdDev()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 */ getConnectionsRequestsMean()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 */ getConnectionsRequestsMax()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 */ getConnectionsRequestsStdDev()1081 public double getConnectionsRequestsStdDev() 1082 { 1083 return _requestStats.getStdDev(); 1084 } 1085 1086 /* ------------------------------------------------------------ */ 1087 /** 1088 * Reset statistics. 1089 */ statsReset()1090 public void statsReset() 1091 { 1092 updateNotEqual(_statsStartedAt,-1,System.currentTimeMillis()); 1093 1094 _requestStats.reset(); 1095 _connectionStats.reset(); 1096 _connectionDurationStats.reset(); 1097 } 1098 1099 /* ------------------------------------------------------------ */ setStatsOn(boolean on)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 */ getStatsOn()1116 public boolean getStatsOn() 1117 { 1118 return _statsStartedAt.get() != -1; 1119 } 1120 1121 /* ------------------------------------------------------------ */ 1122 /** 1123 * @return Timestamp stats were started at. 1124 */ getStatsOnMs()1125 public long getStatsOnMs() 1126 { 1127 long start = _statsStartedAt.get(); 1128 1129 return (start != -1)?(System.currentTimeMillis() - start):0; 1130 } 1131 1132 /* ------------------------------------------------------------ */ connectionOpened(Connection connection)1133 protected void connectionOpened(Connection connection) 1134 { 1135 if (_statsStartedAt.get() == -1) 1136 return; 1137 1138 _connectionStats.increment(); 1139 } 1140 1141 /* ------------------------------------------------------------ */ connectionUpgraded(Connection oldConnection, Connection newConnection)1142 protected void connectionUpgraded(Connection oldConnection, Connection newConnection) 1143 { 1144 _requestStats.set((oldConnection instanceof AbstractHttpConnection)?((AbstractHttpConnection)oldConnection).getRequests():0); 1145 } 1146 1147 /* ------------------------------------------------------------ */ connectionClosed(Connection connection)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 */ getAcceptorPriorityOffset()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 */ setAcceptorPriorityOffset(int offset)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 */ getReuseAddress()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 */ setReuseAddress(boolean reuseAddress)1198 public void setReuseAddress(boolean reuseAddress) 1199 { 1200 _reuseAddress = reuseAddress; 1201 } 1202 1203 /* ------------------------------------------------------------ */ isLowResources()1204 public boolean isLowResources() 1205 { 1206 if (_threadPool != null) 1207 return _threadPool.isLowOnThreads(); 1208 return _server.getThreadPool().isLowOnThreads(); 1209 } 1210 1211 /* ------------------------------------------------------------ */ updateNotEqual(AtomicLong valueHolder, long compare, long value)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 } 1223