1 /*
2 * Licensed to the Apache Software Foundation (ASF) under one or more
3 * contributor license agreements. See the NOTICE file distributed with
4 * this work for additional information regarding copyright ownership.
5 * The ASF licenses this file to You under the Apache License, Version 2.0
6 * (the "License"); you may not use this file except in compliance with
7 * the License. You may obtain a copy of the License at
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 */
17 package org.apache.catalina.connector;
18
19 import java.io.UnsupportedEncodingException;
20 import java.net.InetAddress;
21 import java.nio.charset.Charset;
22 import java.nio.charset.StandardCharsets;
23 import java.util.Arrays;
24 import java.util.HashSet;
25
26 import javax.management.ObjectName;
27
28 import org.apache.catalina.Globals;
29 import org.apache.catalina.LifecycleException;
30 import org.apache.catalina.LifecycleState;
31 import org.apache.catalina.Service;
32 import org.apache.catalina.core.AprLifecycleListener;
33 import org.apache.catalina.util.LifecycleMBeanBase;
34 import org.apache.coyote.AbstractProtocol;
35 import org.apache.coyote.Adapter;
36 import org.apache.coyote.ProtocolHandler;
37 import org.apache.coyote.UpgradeProtocol;
38 import org.apache.coyote.ajp.AbstractAjpProtocol;
39 import org.apache.coyote.http11.AbstractHttp11JsseProtocol;
40 import org.apache.juli.logging.Log;
41 import org.apache.juli.logging.LogFactory;
42 import org.apache.tomcat.util.IntrospectionUtils;
43 import org.apache.tomcat.util.buf.B2CConverter;
44 import org.apache.tomcat.util.net.SSLHostConfig;
45 import org.apache.tomcat.util.net.openssl.OpenSSLImplementation;
46 import org.apache.tomcat.util.res.StringManager;
47
48
49 /**
50 * Implementation of a Coyote connector.
51 *
52 * @author Craig R. McClanahan
53 * @author Remy Maucherat
54 */
55 public class Connector extends LifecycleMBeanBase {
56
57 private static final Log log = LogFactory.getLog(Connector.class);
58
59
60 /**
61 * Alternate flag to enable recycling of facades.
62 */
63 public static final boolean RECYCLE_FACADES =
64 Boolean.parseBoolean(System.getProperty("org.apache.catalina.connector.RECYCLE_FACADES", "false"));
65
66
67 public static final String INTERNAL_EXECUTOR_NAME = "Internal";
68
69
70 // ------------------------------------------------------------ Constructor
71
72 /**
73 * Defaults to using HTTP/1.1 NIO implementation.
74 */
75 public Connector() {
76 this("org.apache.coyote.http11.Http11NioProtocol");
77 }
78
79
80 public Connector(String protocol) {
81 boolean aprConnector = AprLifecycleListener.isAprAvailable() &&
82 AprLifecycleListener.getUseAprConnector();
83
84 if ("HTTP/1.1".equals(protocol) || protocol == null) {
85 if (aprConnector) {
86 protocolHandlerClassName = "org.apache.coyote.http11.Http11AprProtocol";
87 } else {
88 protocolHandlerClassName = "org.apache.coyote.http11.Http11NioProtocol";
89 }
90 } else if ("AJP/1.3".equals(protocol)) {
91 if (aprConnector) {
92 protocolHandlerClassName = "org.apache.coyote.ajp.AjpAprProtocol";
93 } else {
94 protocolHandlerClassName = "org.apache.coyote.ajp.AjpNioProtocol";
95 }
96 } else {
97 protocolHandlerClassName = protocol;
98 }
99
100 // Instantiate protocol handler
101 ProtocolHandler p = null;
102 try {
103 Class<?> clazz = Class.forName(protocolHandlerClassName);
104 p = (ProtocolHandler) clazz.getConstructor().newInstance();
105 } catch (Exception e) {
106 log.error(sm.getString(
107 "coyoteConnector.protocolHandlerInstantiationFailed"), e);
108 } finally {
109 this.protocolHandler = p;
110 }
111
112 // Default for Connector depends on this system property
113 setThrowOnFailure(Boolean.getBoolean("org.apache.catalina.startup.EXIT_ON_INIT_FAILURE"));
114 }
115
116
117 // ----------------------------------------------------- Instance Variables
118
119
120 /**
121 * The <code>Service</code> we are associated with (if any).
122 */
123 protected Service service = null;
124
125
126 /**
127 * Do we allow TRACE ?
128 */
129 protected boolean allowTrace = false;
130
131
132 /**
133 * Default timeout for asynchronous requests (ms).
134 */
135 protected long asyncTimeout = 30000;
136
137
138 /**
139 * The "enable DNS lookups" flag for this Connector.
140 */
141 protected boolean enableLookups = false;
142
143
144 /*
145 * Is generation of X-Powered-By response header enabled/disabled?
146 */
147 protected boolean xpoweredBy = false;
148
149
150 /**
151 * The server name to which we should pretend requests to this Connector
152 * were directed. This is useful when operating Tomcat behind a proxy
153 * server, so that redirects get constructed accurately. If not specified,
154 * the server name included in the <code>Host</code> header is used.
155 */
156 protected String proxyName = null;
157
158
159 /**
160 * The server port to which we should pretend requests to this Connector
161 * were directed. This is useful when operating Tomcat behind a proxy
162 * server, so that redirects get constructed accurately. If not specified,
163 * the port number specified by the <code>port</code> property is used.
164 */
165 protected int proxyPort = 0;
166
167
168 /**
169 * The flag that controls recycling of the facades of the request
170 * processing objects. If set to <code>true</code> the object facades
171 * will be discarded when the request is recycled. If the security
172 * manager is enabled, this setting is ignored and object facades are
173 * always discarded.
174 */
175 protected boolean discardFacades = RECYCLE_FACADES;
176
177
178 /**
179 * The redirect port for non-SSL to SSL redirects.
180 */
181 protected int redirectPort = 443;
182
183
184 /**
185 * The request scheme that will be set on all requests received
186 * through this connector.
187 */
188 protected String scheme = "http";
189
190
191 /**
192 * The secure connection flag that will be set on all requests received
193 * through this connector.
194 */
195 protected boolean secure = false;
196
197
198 /**
199 * The string manager for this package.
200 */
201 protected static final StringManager sm = StringManager.getManager(Connector.class);
202
203
204 /**
205 * The maximum number of cookies permitted for a request. Use a value less
206 * than zero for no limit. Defaults to 200.
207 */
208 private int maxCookieCount = 200;
209
210 /**
211 * The maximum number of parameters (GET plus POST) which will be
212 * automatically parsed by the container. 10000 by default. A value of less
213 * than 0 means no limit.
214 */
215 protected int maxParameterCount = 10000;
216
217 /**
218 * Maximum size of a POST which will be automatically parsed by the
219 * container. 2MB by default.
220 */
221 protected int maxPostSize = 2 * 1024 * 1024;
222
223
224 /**
225 * Maximum size of a POST which will be saved by the container
226 * during authentication. 4kB by default
227 */
228 protected int maxSavePostSize = 4 * 1024;
229
230 /**
231 * Comma-separated list of HTTP methods that will be parsed according
232 * to POST-style rules for application/x-www-form-urlencoded request bodies.
233 */
234 protected String parseBodyMethods = "POST";
235
236 /**
237 * A Set of methods determined by {@link #parseBodyMethods}.
238 */
239 protected HashSet<String> parseBodyMethodsSet;
240
241
242 /**
243 * Flag to use IP-based virtual hosting.
244 */
245 protected boolean useIPVHosts = false;
246
247
248 /**
249 * Coyote Protocol handler class name.
250 * See {@link #Connector()} for current default.
251 */
252 protected final String protocolHandlerClassName;
253
254
255 /**
256 * Coyote protocol handler.
257 */
258 protected final ProtocolHandler protocolHandler;
259
260
261 /**
262 * Coyote adapter.
263 */
264 protected Adapter adapter = null;
265
266
267 private Charset uriCharset = StandardCharsets.UTF_8;
268
269
270 /**
271 * URI encoding as body.
272 */
273 protected boolean useBodyEncodingForURI = false;
274
275
276 // ------------------------------------------------------------- Properties
277
278 /**
279 * Return a property from the protocol handler.
280 *
281 * @param name the property name
282 * @return the property value
283 */
284 public Object getProperty(String name) {
285 if (protocolHandler == null) {
286 return null;
287 }
288 return IntrospectionUtils.getProperty(protocolHandler, name);
289 }
290
291
292 /**
293 * Set a property on the protocol handler.
294 *
295 * @param name the property name
296 * @param value the property value
297 * @return <code>true</code> if the property was successfully set
298 */
299 public boolean setProperty(String name, String value) {
300 if (protocolHandler == null) {
301 return false;
302 }
303 return IntrospectionUtils.setProperty(protocolHandler, name, value);
304 }
305
306
307 /**
308 * Return a property from the protocol handler.
309 *
310 * @param name the property name
311 * @return the property value
312 */
313 public Object getAttribute(String name) {
314 return getProperty(name);
315 }
316
317
318 /**
319 * Set a property on the protocol handler.
320 *
321 * @param name the property name
322 * @param value the property value
323 */
324 public void setAttribute(String name, Object value) {
325 setProperty(name, String.valueOf(value));
326 }
327
328
329 /**
330 * @return the <code>Service</code> with which we are associated (if any).
331 */
332 public Service getService() {
333 return this.service;
334 }
335
336
337 /**
338 * Set the <code>Service</code> with which we are associated (if any).
339 *
340 * @param service The service that owns this Engine
341 */
342 public void setService(Service service) {
343 this.service = service;
344 }
345
346
347 /**
348 * @return <code>true</code> if the TRACE method is allowed. Default value
349 * is <code>false</code>.
350 */
351 public boolean getAllowTrace() {
352 return this.allowTrace;
353 }
354
355
356 /**
357 * Set the allowTrace flag, to disable or enable the TRACE HTTP method.
358 *
359 * @param allowTrace The new allowTrace flag
360 */
361 public void setAllowTrace(boolean allowTrace) {
362 this.allowTrace = allowTrace;
363 setProperty("allowTrace", String.valueOf(allowTrace));
364 }
365
366
367 /**
368 * @return the default timeout for async requests in ms.
369 */
370 public long getAsyncTimeout() {
371 return asyncTimeout;
372 }
373
374
375 /**
376 * Set the default timeout for async requests.
377 *
378 * @param asyncTimeout The new timeout in ms.
379 */
380 public void setAsyncTimeout(long asyncTimeout) {
381 this.asyncTimeout= asyncTimeout;
382 setProperty("asyncTimeout", String.valueOf(asyncTimeout));
383 }
384
385
386 /**
387 * @return <code>true</code> if the object facades are discarded, either
388 * when the discardFacades value is <code>true</code> or when the
389 * security manager is enabled.
390 */
391 public boolean getDiscardFacades() {
392 return discardFacades || Globals.IS_SECURITY_ENABLED;
393 }
394
395
396 /**
397 * Set the recycling strategy for the object facades.
398 * @param discardFacades the new value of the flag
399 */
400 public void setDiscardFacades(boolean discardFacades) {
401 this.discardFacades = discardFacades;
402 }
403
404
405 /**
406 * @return the "enable DNS lookups" flag.
407 */
408 public boolean getEnableLookups() {
409 return this.enableLookups;
410 }
411
412
413 /**
414 * Set the "enable DNS lookups" flag.
415 *
416 * @param enableLookups The new "enable DNS lookups" flag value
417 */
418 public void setEnableLookups(boolean enableLookups) {
419 this.enableLookups = enableLookups;
420 setProperty("enableLookups", String.valueOf(enableLookups));
421 }
422
423
424 public int getMaxCookieCount() {
425 return maxCookieCount;
426 }
427
428
429 public void setMaxCookieCount(int maxCookieCount) {
430 this.maxCookieCount = maxCookieCount;
431 }
432
433
434 /**
435 * @return the maximum number of parameters (GET plus POST) that will be
436 * automatically parsed by the container. A value of less than 0 means no
437 * limit.
438 */
439 public int getMaxParameterCount() {
440 return maxParameterCount;
441 }
442
443
444 /**
445 * Set the maximum number of parameters (GET plus POST) that will be
446 * automatically parsed by the container. A value of less than 0 means no
447 * limit.
448 *
449 * @param maxParameterCount The new setting
450 */
451 public void setMaxParameterCount(int maxParameterCount) {
452 this.maxParameterCount = maxParameterCount;
453 setProperty("maxParameterCount", String.valueOf(maxParameterCount));
454 }
455
456
457 /**
458 * @return the maximum size of a POST which will be automatically
459 * parsed by the container.
460 */
461 public int getMaxPostSize() {
462 return maxPostSize;
463 }
464
465
466 /**
467 * Set the maximum size of a POST which will be automatically
468 * parsed by the container.
469 *
470 * @param maxPostSize The new maximum size in bytes of a POST which will
471 * be automatically parsed by the container
472 */
473 public void setMaxPostSize(int maxPostSize) {
474 this.maxPostSize = maxPostSize;
475 setProperty("maxPostSize", String.valueOf(maxPostSize));
476 }
477
478
479 /**
480 * @return the maximum size of a POST which will be saved by the container
481 * during authentication.
482 */
483 public int getMaxSavePostSize() {
484 return maxSavePostSize;
485 }
486
487
488 /**
489 * Set the maximum size of a POST which will be saved by the container
490 * during authentication.
491 *
492 * @param maxSavePostSize The new maximum size in bytes of a POST which will
493 * be saved by the container during authentication.
494 */
495 public void setMaxSavePostSize(int maxSavePostSize) {
496 this.maxSavePostSize = maxSavePostSize;
497 setProperty("maxSavePostSize", String.valueOf(maxSavePostSize));
498 }
499
500
501 /**
502 * @return the HTTP methods which will support body parameters parsing
503 */
504 public String getParseBodyMethods() {
505 return this.parseBodyMethods;
506 }
507
508
509 /**
510 * Set list of HTTP methods which should allow body parameter
511 * parsing. This defaults to <code>POST</code>.
512 *
513 * @param methods Comma separated list of HTTP method names
514 */
515 public void setParseBodyMethods(String methods) {
516
517 HashSet<String> methodSet = new HashSet<>();
518
519 if (null != methods) {
520 methodSet.addAll(Arrays.asList(methods.split("\\s*,\\s*")));
521 }
522
523 if (methodSet.contains("TRACE")) {
524 throw new IllegalArgumentException(sm.getString("coyoteConnector.parseBodyMethodNoTrace"));
525 }
526
527 this.parseBodyMethods = methods;
528 this.parseBodyMethodsSet = methodSet;
529 setProperty("parseBodyMethods", methods);
530 }
531
532
533 protected boolean isParseBodyMethod(String method) {
534 return parseBodyMethodsSet.contains(method);
535 }
536
537
538 /**
539 * @return the port number on which this connector is configured to listen
540 * for requests. The special value of 0 means select a random free port
541 * when the socket is bound.
542 */
543 public int getPort() {
544 // Try shortcut that should work for nearly all uses first as it does
545 // not use reflection and is therefore faster.
546 if (protocolHandler instanceof AbstractProtocol<?>) {
547 return ((AbstractProtocol<?>) protocolHandler).getPort();
548 }
549 // Fall back for custom protocol handlers not based on AbstractProtocol
550 Object port = getProperty("port");
551 if (port instanceof Integer) {
552 return ((Integer) port).intValue();
553 }
554 // Usually means an invalid protocol has been configured
555 return -1;
556 }
557
558
559 /**
560 * Set the port number on which we listen for requests.
561 *
562 * @param port The new port number
563 */
564 public void setPort(int port) {
565 setProperty("port", String.valueOf(port));
566 }
567
568
569 public int getPortOffset() {
570 // Try shortcut that should work for nearly all uses first as it does
571 // not use reflection and is therefore faster.
572 if (protocolHandler instanceof AbstractProtocol<?>) {
573 return ((AbstractProtocol<?>) protocolHandler).getPortOffset();
574 }
575 // Fall back for custom protocol handlers not based on AbstractProtocol
576 Object port = getProperty("portOffset");
577 if (port instanceof Integer) {
578 return ((Integer) port).intValue();
579 }
580 // Usually means an invalid protocol has been configured.
581 return 0;
582 }
583
584
585 public void setPortOffset(int portOffset) {
586 setProperty("portOffset", String.valueOf(portOffset));
587 }
588
589
590 public int getPortWithOffset() {
591 int port = getPort();
592 // Zero is a special case and negative values are invalid
593 if (port > 0) {
594 return port + getPortOffset();
595 }
596 return port;
597 }
598
599
600 /**
601 * @return the port number on which this connector is listening to requests.
602 * If the special value for {@link #getPort} of zero is used then this method
603 * will report the actual port bound.
604 */
605 public int getLocalPort() {
606 return ((Integer) getProperty("localPort")).intValue();
607 }
608
609
610 /**
611 * @return the Coyote protocol handler in use.
612 */
613 public String getProtocol() {
614 if (("org.apache.coyote.http11.Http11NioProtocol".equals(getProtocolHandlerClassName()) &&
615 (!AprLifecycleListener.isAprAvailable() || !AprLifecycleListener.getUseAprConnector())) ||
616 "org.apache.coyote.http11.Http11AprProtocol".equals(getProtocolHandlerClassName()) &&
617 AprLifecycleListener.getUseAprConnector()) {
618 return "HTTP/1.1";
619 } else if (("org.apache.coyote.ajp.AjpNioProtocol".equals(getProtocolHandlerClassName()) &&
620 (!AprLifecycleListener.isAprAvailable() || !AprLifecycleListener.getUseAprConnector())) ||
621 "org.apache.coyote.ajp.AjpAprProtocol".equals(getProtocolHandlerClassName()) &&
622 AprLifecycleListener.getUseAprConnector()) {
623 return "AJP/1.3";
624 }
625 return getProtocolHandlerClassName();
626 }
627
628
629 /**
630 * @return the class name of the Coyote protocol handler in use.
631 */
632 public String getProtocolHandlerClassName() {
633 return this.protocolHandlerClassName;
634 }
635
636
637 /**
638 * @return the protocol handler associated with the connector.
639 */
640 public ProtocolHandler getProtocolHandler() {
641 return this.protocolHandler;
642 }
643
644
645 /**
646 * @return the proxy server name for this Connector.
647 */
648 public String getProxyName() {
649 return this.proxyName;
650 }
651
652
653 /**
654 * Set the proxy server name for this Connector.
655 *
656 * @param proxyName The new proxy server name
657 */
658 public void setProxyName(String proxyName) {
659
660 if(proxyName != null && proxyName.length() > 0) {
661 this.proxyName = proxyName;
662 } else {
663 this.proxyName = null;
664 }
665 setProperty("proxyName", this.proxyName);
666 }
667
668
669 /**
670 * @return the proxy server port for this Connector.
671 */
672 public int getProxyPort() {
673 return this.proxyPort;
674 }
675
676
677 /**
678 * Set the proxy server port for this Connector.
679 *
680 * @param proxyPort The new proxy server port
681 */
682 public void setProxyPort(int proxyPort) {
683 this.proxyPort = proxyPort;
684 setProperty("proxyPort", String.valueOf(proxyPort));
685 }
686
687
688 /**
689 * @return the port number to which a request should be redirected if
690 * it comes in on a non-SSL port and is subject to a security constraint
691 * with a transport guarantee that requires SSL.
692 */
693 public int getRedirectPort() {
694 return this.redirectPort;
695 }
696
697
698 /**
699 * Set the redirect port number.
700 *
701 * @param redirectPort The redirect port number (non-SSL to SSL)
702 */
703 public void setRedirectPort(int redirectPort) {
704 this.redirectPort = redirectPort;
705 setProperty("redirectPort", String.valueOf(redirectPort));
706 }
707
708
709 public int getRedirectPortWithOffset() {
710 return getRedirectPort() + getPortOffset();
711 }
712
713
714 /**
715 * @return the scheme that will be assigned to requests received
716 * through this connector. Default value is "http".
717 */
718 public String getScheme() {
719 return this.scheme;
720 }
721
722
723 /**
724 * Set the scheme that will be assigned to requests received through
725 * this connector.
726 *
727 * @param scheme The new scheme
728 */
729 public void setScheme(String scheme) {
730 this.scheme = scheme;
731 }
732
733
734 /**
735 * @return the secure connection flag that will be assigned to requests
736 * received through this connector. Default value is "false".
737 */
738 public boolean getSecure() {
739 return this.secure;
740 }
741
742
743 /**
744 * Set the secure connection flag that will be assigned to requests
745 * received through this connector.
746 *
747 * @param secure The new secure connection flag
748 */
749 public void setSecure(boolean secure) {
750 this.secure = secure;
751 setProperty("secure", Boolean.toString(secure));
752 }
753
754
755 /**
756 * @return the name of character encoding to be used for the URI using the
757 * original case.
758 */
759 public String getURIEncoding() {
760 return uriCharset.name();
761 }
762
763
764 /**
765 *
766 * @return The Charset to use to convert raw URI bytes (after %nn decoding)
767 * to characters. This will never be null
768 */
769 public Charset getURICharset() {
770 return uriCharset;
771 }
772
773 /**
774 * Set the URI encoding to be used for the URI.
775 *
776 * @param URIEncoding The new URI character encoding.
777 */
778 public void setURIEncoding(String URIEncoding) {
779 try {
780 uriCharset = B2CConverter.getCharset(URIEncoding);
781 } catch (UnsupportedEncodingException e) {
782 log.error(sm.getString("coyoteConnector.invalidEncoding",
783 URIEncoding, uriCharset.name()), e);
784 }
785 }
786
787
788 /**
789 * @return the true if the entity body encoding should be used for the URI.
790 */
791 public boolean getUseBodyEncodingForURI() {
792 return this.useBodyEncodingForURI;
793 }
794
795
796 /**
797 * Set if the entity body encoding should be used for the URI.
798 *
799 * @param useBodyEncodingForURI The new value for the flag.
800 */
801 public void setUseBodyEncodingForURI(boolean useBodyEncodingForURI) {
802 this.useBodyEncodingForURI = useBodyEncodingForURI;
803 setProperty("useBodyEncodingForURI", String.valueOf(useBodyEncodingForURI));
804 }
805
806 /**
807 * Indicates whether the generation of an X-Powered-By response header for
808 * Servlet-generated responses is enabled or disabled for this Connector.
809 *
810 * @return <code>true</code> if generation of X-Powered-By response header is enabled,
811 * false otherwise
812 */
813 public boolean getXpoweredBy() {
814 return xpoweredBy;
815 }
816
817
818 /**
819 * Enables or disables the generation of an X-Powered-By header (with value
820 * Servlet/2.5) for all servlet-generated responses returned by this
821 * Connector.
822 *
823 * @param xpoweredBy true if generation of X-Powered-By response header is
824 * to be enabled, false otherwise
825 */
826 public void setXpoweredBy(boolean xpoweredBy) {
827 this.xpoweredBy = xpoweredBy;
828 setProperty("xpoweredBy", String.valueOf(xpoweredBy));
829 }
830
831
832 /**
833 * Enable the use of IP-based virtual hosting.
834 *
835 * @param useIPVHosts <code>true</code> if Hosts are identified by IP,
836 * <code>false</code> if Hosts are identified by name.
837 */
838 public void setUseIPVHosts(boolean useIPVHosts) {
839 this.useIPVHosts = useIPVHosts;
840 setProperty("useIPVHosts", String.valueOf(useIPVHosts));
841 }
842
843
844 /**
845 * Test if IP-based virtual hosting is enabled.
846 *
847 * @return <code>true</code> if IP vhosts are enabled
848 */
849 public boolean getUseIPVHosts() {
850 return useIPVHosts;
851 }
852
853
854 public String getExecutorName() {
855 Object obj = protocolHandler.getExecutor();
856 if (obj instanceof org.apache.catalina.Executor) {
857 return ((org.apache.catalina.Executor) obj).getName();
858 }
859 return INTERNAL_EXECUTOR_NAME;
860 }
861
862
863 public void addSslHostConfig(SSLHostConfig sslHostConfig) {
864 protocolHandler.addSslHostConfig(sslHostConfig);
865 }
866
867
868 public SSLHostConfig[] findSslHostConfigs() {
869 return protocolHandler.findSslHostConfigs();
870 }
871
872
873 public void addUpgradeProtocol(UpgradeProtocol upgradeProtocol) {
874 protocolHandler.addUpgradeProtocol(upgradeProtocol);
875 }
876
877
878 public UpgradeProtocol[] findUpgradeProtocols() {
879 return protocolHandler.findUpgradeProtocols();
880 }
881
882
883 // --------------------------------------------------------- Public Methods
884
885 /**
886 * Create (or allocate) and return a Request object suitable for
887 * specifying the contents of a Request to the responsible Container.
888 *
889 * @return a new Servlet request object
890 */
891 public Request createRequest() {
892 return new Request(this);
893 }
894
895
896 /**
897 * Create (or allocate) and return a Response object suitable for
898 * receiving the contents of a Response from the responsible Container.
899 *
900 * @return a new Servlet response object
901 */
902 public Response createResponse() {
903 if (protocolHandler instanceof AbstractAjpProtocol<?>) {
904 int packetSize = ((AbstractAjpProtocol<?>) protocolHandler).getPacketSize();
905 return new Response(packetSize - org.apache.coyote.ajp.Constants.SEND_HEAD_LEN);
906 } else {
907 return new Response();
908 }
909 }
910
911
912 protected String createObjectNameKeyProperties(String type) {
913
914 Object addressObj = getProperty("address");
915
916 StringBuilder sb = new StringBuilder("type=");
917 sb.append(type);
918 sb.append(",port=");
919 int port = getPortWithOffset();
920 if (port > 0) {
921 sb.append(port);
922 } else {
923 sb.append("auto-");
924 sb.append(getProperty("nameIndex"));
925 }
926 String address = "";
927 if (addressObj instanceof InetAddress) {
928 address = ((InetAddress) addressObj).getHostAddress();
929 } else if (addressObj != null) {
930 address = addressObj.toString();
931 }
932 if (address.length() > 0) {
933 sb.append(",address=");
934 sb.append(ObjectName.quote(address));
935 }
936 return sb.toString();
937 }
938
939
940 /**
941 * Pause the connector.
942 */
943 public void pause() {
944 try {
945 if (protocolHandler != null) {
946 protocolHandler.pause();
947 }
948 } catch (Exception e) {
949 log.error(sm.getString("coyoteConnector.protocolHandlerPauseFailed"), e);
950 }
951 }
952
953
954 /**
955 * Resume the connector.
956 */
957 public void resume() {
958 try {
959 if (protocolHandler != null) {
960 protocolHandler.resume();
961 }
962 } catch (Exception e) {
963 log.error(sm.getString("coyoteConnector.protocolHandlerResumeFailed"), e);
964 }
965 }
966
967
968 @Override
969 protected void initInternal() throws LifecycleException {
970
971 super.initInternal();
972
973 if (protocolHandler == null) {
974 throw new LifecycleException(
975 sm.getString("coyoteConnector.protocolHandlerInstantiationFailed"));
976 }
977
978 // Initialize adapter
979 adapter = new CoyoteAdapter(this);
980 protocolHandler.setAdapter(adapter);
981 if (service != null) {
982 protocolHandler.setUtilityExecutor(service.getServer().getUtilityExecutor());
983 }
984
985 // Make sure parseBodyMethodsSet has a default
986 if (null == parseBodyMethodsSet) {
987 setParseBodyMethods(getParseBodyMethods());
988 }
989
990 if (protocolHandler.isAprRequired() && !AprLifecycleListener.isInstanceCreated()) {
991 throw new LifecycleException(sm.getString("coyoteConnector.protocolHandlerNoAprListener",
992 getProtocolHandlerClassName()));
993 }
994 if (protocolHandler.isAprRequired() && !AprLifecycleListener.isAprAvailable()) {
995 throw new LifecycleException(sm.getString("coyoteConnector.protocolHandlerNoAprLibrary",
996 getProtocolHandlerClassName()));
997 }
998 if (AprLifecycleListener.isAprAvailable() && AprLifecycleListener.getUseOpenSSL() &&
999 protocolHandler instanceof AbstractHttp11JsseProtocol) {
1000 AbstractHttp11JsseProtocol<?> jsseProtocolHandler =
1001 (AbstractHttp11JsseProtocol<?>) protocolHandler;
1002 if (jsseProtocolHandler.isSSLEnabled() &&
1003 jsseProtocolHandler.getSslImplementationName() == null) {
1004 // OpenSSL is compatible with the JSSE configuration, so use it if APR is available
1005 jsseProtocolHandler.setSslImplementationName(OpenSSLImplementation.class.getName());
1006 }
1007 }
1008
1009 try {
1010 protocolHandler.init();
1011 } catch (Exception e) {
1012 throw new LifecycleException(
1013 sm.getString("coyoteConnector.protocolHandlerInitializationFailed"), e);
1014 }
1015 }
1016
1017
1018 /**
1019 * Begin processing requests via this Connector.
1020 *
1021 * @exception LifecycleException if a fatal startup error occurs
1022 */
1023 @Override
1024 protected void startInternal() throws LifecycleException {
1025
1026 // Validate settings before starting
1027 if (getPortWithOffset() < 0) {
1028 throw new LifecycleException(sm.getString(
1029 "coyoteConnector.invalidPort", Integer.valueOf(getPortWithOffset())));
1030 }
1031
1032 setState(LifecycleState.STARTING);
1033
1034 try {
1035 protocolHandler.start();
1036 } catch (Exception e) {
1037 throw new LifecycleException(
1038 sm.getString("coyoteConnector.protocolHandlerStartFailed"), e);
1039 }
1040 }
1041
1042
1043 /**
1044 * Terminate processing requests via this Connector.
1045 *
1046 * @exception LifecycleException if a fatal shutdown error occurs
1047 */
1048 @Override
1049 protected void stopInternal() throws LifecycleException {
1050
1051 setState(LifecycleState.STOPPING);
1052
1053 try {
1054 if (protocolHandler != null) {
1055 protocolHandler.stop();
1056 }
1057 } catch (Exception e) {
1058 throw new LifecycleException(
1059 sm.getString("coyoteConnector.protocolHandlerStopFailed"), e);
1060 }
1061 }
1062
1063
1064 @Override
1065 protected void destroyInternal() throws LifecycleException {
1066 try {
1067 if (protocolHandler != null) {
1068 protocolHandler.destroy();
1069 }
1070 } catch (Exception e) {
1071 throw new LifecycleException(
1072 sm.getString("coyoteConnector.protocolHandlerDestroyFailed"), e);
1073 }
1074
1075 if (getService() != null) {
1076 getService().removeConnector(this);
1077 }
1078
1079 super.destroyInternal();
1080 }
1081
1082
1083 /**
1084 * Provide a useful toString() implementation as it may be used when logging
1085 * Lifecycle errors to identify the component.
1086 */
1087 @Override
1088 public String toString() {
1089 // Not worth caching this right now
1090 StringBuilder sb = new StringBuilder("Connector[");
1091 sb.append(getProtocol());
1092 sb.append('-');
1093 int port = getPortWithOffset();
1094 if (port > 0) {
1095 sb.append(port);
1096 } else {
1097 sb.append("auto-");
1098 sb.append(getProperty("nameIndex"));
1099 }
1100 sb.append(']');
1101 return sb.toString();
1102 }
1103
1104
1105 // -------------------- JMX registration --------------------
1106
1107 @Override
1108 protected String getDomainInternal() {
1109 Service s = getService();
1110 if (s == null) {
1111 return null;
1112 } else {
1113 return service.getDomain();
1114 }
1115 }
1116
1117 @Override
1118 protected String getObjectNameKeyProperties() {
1119 return createObjectNameKeyProperties("Connector");
1120 }
1121
1122 }
1123