001: /*
002: * Licensed to the Apache Software Foundation (ASF) under one or more
003: * contributor license agreements. See the NOTICE file distributed with
004: * this work for additional information regarding copyright ownership.
005: * The ASF licenses this file to You under the Apache License, Version 2.0
006: * (the "License"); you may not use this file except in compliance with
007: * the License. You may obtain a copy of the License at
008: *
009: * http://www.apache.org/licenses/LICENSE-2.0
010: *
011: * Unless required by applicable law or agreed to in writing, software
012: * distributed under the License is distributed on an "AS IS" BASIS,
013: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014: * See the License for the specific language governing permissions and
015: * limitations under the License.
016: */
017:
018: package org.apache.coyote.http11;
019:
020: import java.net.InetAddress;
021: import java.net.Socket;
022: import java.net.URLEncoder;
023: import java.util.HashMap;
024: import java.util.Iterator;
025: import java.util.concurrent.ConcurrentLinkedQueue;
026: import java.util.concurrent.Executor;
027: import java.util.concurrent.atomic.AtomicInteger;
028: import java.util.concurrent.atomic.AtomicLong;
029:
030: import javax.management.MBeanRegistration;
031: import javax.management.MBeanServer;
032: import javax.management.ObjectName;
033:
034: import org.apache.coyote.ActionCode;
035: import org.apache.coyote.ActionHook;
036: import org.apache.coyote.Adapter;
037: import org.apache.coyote.ProtocolHandler;
038: import org.apache.coyote.RequestGroupInfo;
039: import org.apache.coyote.RequestInfo;
040: import org.apache.tomcat.util.modeler.Registry;
041: import org.apache.tomcat.util.net.JIoEndpoint;
042: import org.apache.tomcat.util.net.SSLImplementation;
043: import org.apache.tomcat.util.net.ServerSocketFactory;
044: import org.apache.tomcat.util.net.JIoEndpoint.Handler;
045: import org.apache.tomcat.util.res.StringManager;
046:
047: /**
048: * Abstract the protocol implementation, including threading, etc.
049: * Processor is single threaded and specific to stream-based protocols,
050: * will not fit Jk protocols like JNI.
051: *
052: * @author Remy Maucherat
053: * @author Costin Manolache
054: */
055: public class Http11Protocol implements ProtocolHandler,
056: MBeanRegistration {
057:
058: protected static org.apache.juli.logging.Log log = org.apache.juli.logging.LogFactory
059: .getLog(Http11Protocol.class);
060:
061: /**
062: * The string manager for this package.
063: */
064: protected static StringManager sm = StringManager
065: .getManager(Constants.Package);
066:
067: // ------------------------------------------------------------ Constructor
068:
069: public Http11Protocol() {
070: setSoLinger(Constants.DEFAULT_CONNECTION_LINGER);
071: setSoTimeout(Constants.DEFAULT_CONNECTION_TIMEOUT);
072: //setServerSoTimeout(Constants.DEFAULT_SERVER_SOCKET_TIMEOUT);
073: setTcpNoDelay(Constants.DEFAULT_TCP_NO_DELAY);
074: }
075:
076: // ----------------------------------------------------------------- Fields
077:
078: protected Http11ConnectionHandler cHandler = new Http11ConnectionHandler(
079: this );
080: protected JIoEndpoint endpoint = new JIoEndpoint();
081:
082: // *
083: protected ObjectName tpOname = null;
084: // *
085: protected ObjectName rgOname = null;
086:
087: protected ServerSocketFactory socketFactory = null;
088: protected SSLImplementation sslImplementation = null;
089:
090: // ----------------------------------------- ProtocolHandler Implementation
091: // *
092:
093: protected HashMap<String, Object> attributes = new HashMap<String, Object>();
094:
095: /**
096: * Set a property.
097: */
098: public void setProperty(String name, String value) {
099: setAttribute(name, value);
100: }
101:
102: /**
103: * Get a property
104: */
105: public String getProperty(String name) {
106: return (String) getAttribute(name);
107: }
108:
109: /**
110: * Pass config info
111: */
112: public void setAttribute(String name, Object value) {
113: if (log.isTraceEnabled()) {
114: log.trace(sm.getString("http11protocol.setattribute", name,
115: value));
116: }
117: attributes.put(name, value);
118: }
119:
120: public Object getAttribute(String key) {
121: return attributes.get(key);
122: }
123:
124: public Iterator getAttributeNames() {
125: return attributes.keySet().iterator();
126: }
127:
128: /**
129: * The adapter, used to call the connector.
130: */
131: protected Adapter adapter;
132:
133: public void setAdapter(Adapter adapter) {
134: this .adapter = adapter;
135: }
136:
137: public Adapter getAdapter() {
138: return adapter;
139: }
140:
141: public void init() throws Exception {
142: endpoint.setName(getName());
143: endpoint.setHandler(cHandler);
144:
145: // Verify the validity of the configured socket factory
146: try {
147: if (isSSLEnabled()) {
148: sslImplementation = SSLImplementation
149: .getInstance(sslImplementationName);
150: socketFactory = sslImplementation
151: .getServerSocketFactory();
152: endpoint.setServerSocketFactory(socketFactory);
153: } else if (socketFactoryName != null) {
154: socketFactory = (ServerSocketFactory) Class.forName(
155: socketFactoryName).newInstance();
156: endpoint.setServerSocketFactory(socketFactory);
157: }
158: } catch (Exception ex) {
159: log
160: .error(
161: sm
162: .getString("http11protocol.socketfactory.initerror"),
163: ex);
164: throw ex;
165: }
166:
167: if (socketFactory != null) {
168: Iterator<String> attE = attributes.keySet().iterator();
169: while (attE.hasNext()) {
170: String key = attE.next();
171: Object v = attributes.get(key);
172: socketFactory.setAttribute(key, v);
173: }
174: }
175:
176: try {
177: endpoint.init();
178: } catch (Exception ex) {
179: log.error(
180: sm.getString("http11protocol.endpoint.initerror"),
181: ex);
182: throw ex;
183: }
184: if (log.isInfoEnabled())
185: log.info(sm.getString("http11protocol.init", getName()));
186:
187: }
188:
189: public void start() throws Exception {
190: if (this .domain != null) {
191: try {
192: tpOname = new ObjectName(domain + ":"
193: + "type=ThreadPool,name=" + getName());
194: Registry.getRegistry(null, null).registerComponent(
195: endpoint, tpOname, null);
196: } catch (Exception e) {
197: log.error("Can't register endpoint");
198: }
199: rgOname = new ObjectName(domain
200: + ":type=GlobalRequestProcessor,name=" + getName());
201: Registry.getRegistry(null, null).registerComponent(
202: cHandler.global, rgOname, null);
203: }
204:
205: try {
206: endpoint.start();
207: } catch (Exception ex) {
208: log.error(sm
209: .getString("http11protocol.endpoint.starterror"),
210: ex);
211: throw ex;
212: }
213: if (log.isInfoEnabled())
214: log.info(sm.getString("http11protocol.start", getName()));
215: }
216:
217: public void pause() throws Exception {
218: try {
219: endpoint.pause();
220: } catch (Exception ex) {
221: log.error(sm
222: .getString("http11protocol.endpoint.pauseerror"),
223: ex);
224: throw ex;
225: }
226: if (log.isInfoEnabled())
227: log.info(sm.getString("http11protocol.pause", getName()));
228: }
229:
230: public void resume() throws Exception {
231: try {
232: endpoint.resume();
233: } catch (Exception ex) {
234: log.error(sm
235: .getString("http11protocol.endpoint.resumeerror"),
236: ex);
237: throw ex;
238: }
239: if (log.isInfoEnabled())
240: log.info(sm.getString("http11protocol.resume", getName()));
241: }
242:
243: public void destroy() throws Exception {
244: if (log.isInfoEnabled())
245: log.info(sm.getString("http11protocol.stop", getName()));
246: endpoint.destroy();
247: if (tpOname != null)
248: Registry.getRegistry(null, null).unregisterComponent(
249: tpOname);
250: if (rgOname != null)
251: Registry.getRegistry(null, null).unregisterComponent(
252: rgOname);
253: }
254:
255: public String getName() {
256: String encodedAddr = "";
257: if (getAddress() != null) {
258: encodedAddr = "" + getAddress();
259: if (encodedAddr.startsWith("/"))
260: encodedAddr = encodedAddr.substring(1);
261: encodedAddr = URLEncoder.encode(encodedAddr) + "-";
262: }
263: return ("http-" + encodedAddr + endpoint.getPort());
264: }
265:
266: // ------------------------------------------------------------- Properties
267:
268: /**
269: * Processor cache.
270: */
271: protected int processorCache = -1;
272:
273: public int getProcessorCache() {
274: return this .processorCache;
275: }
276:
277: public void setProcessorCache(int processorCache) {
278: this .processorCache = processorCache;
279: }
280:
281: protected int socketBuffer = 9000;
282:
283: public int getSocketBuffer() {
284: return socketBuffer;
285: }
286:
287: public void setSocketBuffer(int socketBuffer) {
288: this .socketBuffer = socketBuffer;
289: }
290:
291: /**
292: * This field indicates if the protocol is secure from the perspective of
293: * the client (= https is used).
294: */
295: protected boolean secure;
296:
297: public boolean getSecure() {
298: return secure;
299: }
300:
301: public void setSecure(boolean b) {
302: secure = b;
303: }
304:
305: protected boolean SSLEnabled = false;
306:
307: public boolean isSSLEnabled() {
308: return SSLEnabled;
309: }
310:
311: public void setSSLEnabled(boolean SSLEnabled) {
312: this .SSLEnabled = SSLEnabled;
313: }
314:
315: /**
316: * Name of the socket factory.
317: */
318: protected String socketFactoryName = null;
319:
320: public String getSocketFactory() {
321: return socketFactoryName;
322: }
323:
324: public void setSocketFactory(String valueS) {
325: socketFactoryName = valueS;
326: }
327:
328: /**
329: * Name of the SSL implementation.
330: */
331: protected String sslImplementationName = null;
332:
333: public String getSSLImplementation() {
334: return sslImplementationName;
335: }
336:
337: public void setSSLImplementation(String valueS) {
338: sslImplementationName = valueS;
339: setSecure(true);
340: }
341:
342: // HTTP
343: /**
344: * Maximum number of requests which can be performed over a keepalive
345: * connection. The default is the same as for Apache HTTP Server.
346: */
347: protected int maxKeepAliveRequests = 100;
348:
349: public int getMaxKeepAliveRequests() {
350: return maxKeepAliveRequests;
351: }
352:
353: public void setMaxKeepAliveRequests(int mkar) {
354: maxKeepAliveRequests = mkar;
355: }
356:
357: // HTTP
358: /**
359: * The number of seconds Tomcat will wait for a subsequent request
360: * before closing the connection. The default is the same as for
361: * Apache HTTP Server (15 000 milliseconds).
362: */
363: protected int keepAliveTimeout = -1;
364:
365: public int getKeepAliveTimeout() {
366: return keepAliveTimeout;
367: }
368:
369: public void setKeepAliveTimeout(int timeout) {
370: keepAliveTimeout = timeout;
371: }
372:
373: // HTTP
374: /**
375: * This timeout represents the socket timeout which will be used while
376: * the adapter execution is in progress, unless disableUploadTimeout
377: * is set to true. The default is the same as for Apache HTTP Server
378: * (300 000 milliseconds).
379: */
380: protected int timeout = 300000;
381:
382: public int getTimeout() {
383: return timeout;
384: }
385:
386: public void setTimeout(int timeout) {
387: this .timeout = timeout;
388: }
389:
390: // *
391: /**
392: * Maximum size of the post which will be saved when processing certain
393: * requests, such as a POST.
394: */
395: protected int maxSavePostSize = 4 * 1024;
396:
397: public int getMaxSavePostSize() {
398: return maxSavePostSize;
399: }
400:
401: public void setMaxSavePostSize(int valueI) {
402: maxSavePostSize = valueI;
403: }
404:
405: // HTTP
406: /**
407: * Maximum size of the HTTP message header.
408: */
409: protected int maxHttpHeaderSize = 8 * 1024;
410:
411: public int getMaxHttpHeaderSize() {
412: return maxHttpHeaderSize;
413: }
414:
415: public void setMaxHttpHeaderSize(int valueI) {
416: maxHttpHeaderSize = valueI;
417: }
418:
419: // HTTP
420: /**
421: * If true, the regular socket timeout will be used for the full duration
422: * of the connection.
423: */
424: protected boolean disableUploadTimeout = true;
425:
426: public boolean getDisableUploadTimeout() {
427: return disableUploadTimeout;
428: }
429:
430: public void setDisableUploadTimeout(boolean isDisabled) {
431: disableUploadTimeout = isDisabled;
432: }
433:
434: // HTTP
435: /**
436: * Integrated compression support.
437: */
438: protected String compression = "off";
439:
440: public String getCompression() {
441: return compression;
442: }
443:
444: public void setCompression(String valueS) {
445: compression = valueS;
446: }
447:
448: // HTTP
449: protected String noCompressionUserAgents = null;
450:
451: public String getNoCompressionUserAgents() {
452: return noCompressionUserAgents;
453: }
454:
455: public void setNoCompressionUserAgents(String valueS) {
456: noCompressionUserAgents = valueS;
457: }
458:
459: // HTTP
460: protected String compressableMimeTypes = "text/html,text/xml,text/plain";
461:
462: public String getCompressableMimeType() {
463: return compressableMimeTypes;
464: }
465:
466: public void setCompressableMimeType(String valueS) {
467: compressableMimeTypes = valueS;
468: }
469:
470: // HTTP
471: protected int compressionMinSize = 2048;
472:
473: public int getCompressionMinSize() {
474: return compressionMinSize;
475: }
476:
477: public void setCompressionMinSize(int valueI) {
478: compressionMinSize = valueI;
479: }
480:
481: // HTTP
482: /**
483: * User agents regular expressions which should be restricted to HTTP/1.0 support.
484: */
485: protected String restrictedUserAgents = null;
486:
487: public String getRestrictedUserAgents() {
488: return restrictedUserAgents;
489: }
490:
491: public void setRestrictedUserAgents(String valueS) {
492: restrictedUserAgents = valueS;
493: }
494:
495: // HTTP
496: /**
497: * Server header.
498: */
499: protected String server;
500:
501: public void setServer(String server) {
502: this .server = server;
503: }
504:
505: public String getServer() {
506: return server;
507: }
508:
509: public Executor getExecutor() {
510: return endpoint.getExecutor();
511: }
512:
513: public void setExecutor(Executor executor) {
514: endpoint.setExecutor(executor);
515: }
516:
517: public int getMaxThreads() {
518: return endpoint.getMaxThreads();
519: }
520:
521: public void setMaxThreads(int maxThreads) {
522: endpoint.setMaxThreads(maxThreads);
523: }
524:
525: public int getThreadPriority() {
526: return endpoint.getThreadPriority();
527: }
528:
529: public void setThreadPriority(int threadPriority) {
530: endpoint.setThreadPriority(threadPriority);
531: }
532:
533: public int getBacklog() {
534: return endpoint.getBacklog();
535: }
536:
537: public void setBacklog(int backlog) {
538: endpoint.setBacklog(backlog);
539: }
540:
541: public int getPort() {
542: return endpoint.getPort();
543: }
544:
545: public void setPort(int port) {
546: endpoint.setPort(port);
547: }
548:
549: public InetAddress getAddress() {
550: return endpoint.getAddress();
551: }
552:
553: public void setAddress(InetAddress ia) {
554: endpoint.setAddress(ia);
555: }
556:
557: public boolean getTcpNoDelay() {
558: return endpoint.getTcpNoDelay();
559: }
560:
561: public void setTcpNoDelay(boolean tcpNoDelay) {
562: endpoint.setTcpNoDelay(tcpNoDelay);
563: }
564:
565: public int getSoLinger() {
566: return endpoint.getSoLinger();
567: }
568:
569: public void setSoLinger(int soLinger) {
570: endpoint.setSoLinger(soLinger);
571: }
572:
573: public int getSoTimeout() {
574: return endpoint.getSoTimeout();
575: }
576:
577: public void setSoTimeout(int soTimeout) {
578: endpoint.setSoTimeout(soTimeout);
579: }
580:
581: // HTTP
582: /**
583: * Return the Keep-Alive policy for the connection.
584: */
585: public boolean getKeepAlive() {
586: return ((maxKeepAliveRequests != 0) && (maxKeepAliveRequests != 1));
587: }
588:
589: // HTTP
590: /**
591: * Set the keep-alive policy for this connection.
592: */
593: public void setKeepAlive(boolean keepAlive) {
594: if (!keepAlive) {
595: setMaxKeepAliveRequests(1);
596: }
597: }
598:
599: /*
600: * Note: All the following are JSSE/java.io specific attributes.
601: */
602:
603: public String getKeystore() {
604: return (String) getAttribute("keystore");
605: }
606:
607: public void setKeystore(String k) {
608: setAttribute("keystore", k);
609: }
610:
611: public String getKeypass() {
612: return (String) getAttribute("keypass");
613: }
614:
615: public void setKeypass(String k) {
616: attributes.put("keypass", k);
617: //setAttribute("keypass", k);
618: }
619:
620: public String getKeytype() {
621: return (String) getAttribute("keystoreType");
622: }
623:
624: public void setKeytype(String k) {
625: setAttribute("keystoreType", k);
626: }
627:
628: public String getClientauth() {
629: return (String) getAttribute("clientauth");
630: }
631:
632: public void setClientauth(String k) {
633: setAttribute("clientauth", k);
634: }
635:
636: public String getProtocols() {
637: return (String) getAttribute("protocols");
638: }
639:
640: public void setProtocols(String k) {
641: setAttribute("protocols", k);
642: }
643:
644: public String getAlgorithm() {
645: return (String) getAttribute("algorithm");
646: }
647:
648: public void setAlgorithm(String k) {
649: setAttribute("algorithm", k);
650: }
651:
652: public String getCiphers() {
653: return (String) getAttribute("ciphers");
654: }
655:
656: public void setCiphers(String ciphers) {
657: setAttribute("ciphers", ciphers);
658: }
659:
660: public String getKeyAlias() {
661: return (String) getAttribute("keyAlias");
662: }
663:
664: public void setKeyAlias(String keyAlias) {
665: setAttribute("keyAlias", keyAlias);
666: }
667:
668: // ----------------------------------- Http11ConnectionHandler Inner Class
669:
670: protected static class Http11ConnectionHandler implements Handler {
671:
672: protected Http11Protocol proto;
673: protected AtomicLong registerCount = new AtomicLong(0);
674: protected RequestGroupInfo global = new RequestGroupInfo();
675:
676: protected ConcurrentLinkedQueue<Http11Processor> recycledProcessors = new ConcurrentLinkedQueue<Http11Processor>() {
677: protected AtomicInteger size = new AtomicInteger(0);
678:
679: public boolean offer(Http11Processor processor) {
680: boolean offer = (proto.processorCache == -1) ? true
681: : (size.get() < proto.processorCache);
682: //avoid over growing our cache or add after we have stopped
683: boolean result = false;
684: if (offer) {
685: result = super .offer(processor);
686: if (result) {
687: size.incrementAndGet();
688: }
689: }
690: if (!result)
691: unregister(processor);
692: return result;
693: }
694:
695: public Http11Processor poll() {
696: Http11Processor result = super .poll();
697: if (result != null) {
698: size.decrementAndGet();
699: }
700: return result;
701: }
702:
703: public void clear() {
704: Http11Processor next = poll();
705: while (next != null) {
706: unregister(next);
707: next = poll();
708: }
709: super .clear();
710: size.set(0);
711: }
712: };
713:
714: Http11ConnectionHandler(Http11Protocol proto) {
715: this .proto = proto;
716: }
717:
718: public boolean process(Socket socket) {
719: Http11Processor processor = recycledProcessors.poll();
720: try {
721:
722: if (processor == null) {
723: processor = createProcessor();
724: }
725:
726: if (processor instanceof ActionHook) {
727: ((ActionHook) processor).action(
728: ActionCode.ACTION_START, null);
729: }
730:
731: if (proto.secure && (proto.sslImplementation != null)) {
732: processor.setSSLSupport(proto.sslImplementation
733: .getSSLSupport(socket));
734: } else {
735: processor.setSSLSupport(null);
736: }
737:
738: processor.process(socket);
739: return false;
740:
741: } catch (java.net.SocketException e) {
742: // SocketExceptions are normal
743: Http11Protocol.log
744: .debug(
745: sm
746: .getString("http11protocol.proto.socketexception.debug"),
747: e);
748: } catch (java.io.IOException e) {
749: // IOExceptions are normal
750: Http11Protocol.log
751: .debug(
752: sm
753: .getString("http11protocol.proto.ioexception.debug"),
754: e);
755: }
756: // Future developers: if you discover any other
757: // rare-but-nonfatal exceptions, catch them here, and log as
758: // above.
759: catch (Throwable e) {
760: // any other exception or error is odd. Here we log it
761: // with "ERROR" level, so it will show up even on
762: // less-than-verbose logs.
763: Http11Protocol.log.error(sm
764: .getString("http11protocol.proto.error"), e);
765: } finally {
766: // if(proto.adapter != null) proto.adapter.recycle();
767: // processor.recycle();
768:
769: if (processor instanceof ActionHook) {
770: ((ActionHook) processor).action(
771: ActionCode.ACTION_STOP, null);
772: }
773: recycledProcessors.offer(processor);
774: }
775: return false;
776: }
777:
778: protected Http11Processor createProcessor() {
779: Http11Processor processor = new Http11Processor(
780: proto.maxHttpHeaderSize, proto.endpoint);
781: processor.setAdapter(proto.adapter);
782: processor
783: .setMaxKeepAliveRequests(proto.maxKeepAliveRequests);
784: processor.setKeepAliveTimeout(proto.keepAliveTimeout);
785: processor.setTimeout(proto.timeout);
786: processor
787: .setDisableUploadTimeout(proto.disableUploadTimeout);
788: processor.setCompression(proto.compression);
789: processor.setCompressionMinSize(proto.compressionMinSize);
790: processor
791: .setNoCompressionUserAgents(proto.noCompressionUserAgents);
792: processor
793: .setCompressableMimeTypes(proto.compressableMimeTypes);
794: processor
795: .setRestrictedUserAgents(proto.restrictedUserAgents);
796: processor.setSocketBuffer(proto.socketBuffer);
797: processor.setMaxSavePostSize(proto.maxSavePostSize);
798: processor.setServer(proto.server);
799: register(processor);
800: return processor;
801: }
802:
803: protected void register(Http11Processor processor) {
804: if (proto.getDomain() != null) {
805: synchronized (this ) {
806: try {
807: long count = registerCount.incrementAndGet();
808: RequestInfo rp = processor.getRequest()
809: .getRequestProcessor();
810: rp.setGlobalProcessor(global);
811: ObjectName rpName = new ObjectName(proto
812: .getDomain()
813: + ":type=RequestProcessor,worker="
814: + proto.getName()
815: + ",name=HttpRequest"
816: + count);
817: if (log.isDebugEnabled()) {
818: log.debug("Register " + rpName);
819: }
820: Registry.getRegistry(null, null)
821: .registerComponent(rp, rpName, null);
822: rp.setRpName(rpName);
823: } catch (Exception e) {
824: log.warn("Error registering request");
825: }
826: }
827: }
828: }
829:
830: protected void unregister(Http11Processor processor) {
831: if (proto.getDomain() != null) {
832: synchronized (this ) {
833: try {
834: RequestInfo rp = processor.getRequest()
835: .getRequestProcessor();
836: rp.setGlobalProcessor(null);
837: ObjectName rpName = rp.getRpName();
838: if (log.isDebugEnabled()) {
839: log.debug("Unregister " + rpName);
840: }
841: Registry.getRegistry(null, null)
842: .unregisterComponent(rpName);
843: rp.setRpName(null);
844: } catch (Exception e) {
845: log.warn("Error unregistering request", e);
846: }
847: }
848: }
849: }
850:
851: }
852:
853: // -------------------- JMX related methods --------------------
854:
855: // *
856: protected String domain;
857: protected ObjectName oname;
858: protected MBeanServer mserver;
859:
860: public ObjectName getObjectName() {
861: return oname;
862: }
863:
864: public String getDomain() {
865: return domain;
866: }
867:
868: public ObjectName preRegister(MBeanServer server, ObjectName name)
869: throws Exception {
870: oname = name;
871: mserver = server;
872: domain = name.getDomain();
873: return name;
874: }
875:
876: public void postRegister(Boolean registrationDone) {
877: }
878:
879: public void preDeregister() throws Exception {
880: }
881:
882: public void postDeregister() {
883: }
884: }
|