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
18 package org.apache.coyote.http11;
19
20 import java.net.InetAddress;
21 import java.net.Socket;
22 import java.net.URLEncoder;
23 import java.util.HashMap;
24 import java.util.Iterator;
25 import java.util.concurrent.ConcurrentLinkedQueue;
26 import java.util.concurrent.Executor;
27 import java.util.concurrent.atomic.AtomicInteger;
28 import java.util.concurrent.atomic.AtomicLong;
29
30 import javax.management.MBeanRegistration;
31 import javax.management.MBeanServer;
32 import javax.management.ObjectName;
33
34 import org.apache.coyote.ActionCode;
35 import org.apache.coyote.ActionHook;
36 import org.apache.coyote.Adapter;
37 import org.apache.coyote.ProtocolHandler;
38 import org.apache.coyote.RequestGroupInfo;
39 import org.apache.coyote.RequestInfo;
40 import org.apache.tomcat.util.modeler.Registry;
41 import org.apache.tomcat.util.net.JIoEndpoint;
42 import org.apache.tomcat.util.net.SSLImplementation;
43 import org.apache.tomcat.util.net.ServerSocketFactory;
44 import org.apache.tomcat.util.net.JIoEndpoint.Handler;
45 import org.apache.tomcat.util.res.StringManager;
46
47
48 /**
49 * Abstract the protocol implementation, including threading, etc.
50 * Processor is single threaded and specific to stream-based protocols,
51 * will not fit Jk protocols like JNI.
52 *
53 * @author Remy Maucherat
54 * @author Costin Manolache
55 */
56 public class Http11Protocol
57 implements ProtocolHandler, MBeanRegistration {
58
59
60 protected static org.apache.juli.logging.Log log
61 = org.apache.juli.logging.LogFactory.getLog(Http11Protocol.class);
62
63 /**
64 * The string manager for this package.
65 */
66 protected static StringManager sm =
67 StringManager.getManager(Constants.Package);
68
69
70 // ------------------------------------------------------------ Constructor
71
72
73 public Http11Protocol() {
74 setSoLinger(Constants.DEFAULT_CONNECTION_LINGER);
75 setSoTimeout(Constants.DEFAULT_CONNECTION_TIMEOUT);
76 //setServerSoTimeout(Constants.DEFAULT_SERVER_SOCKET_TIMEOUT);
77 setTcpNoDelay(Constants.DEFAULT_TCP_NO_DELAY);
78 }
79
80
81 // ----------------------------------------------------------------- Fields
82
83
84 protected Http11ConnectionHandler cHandler = new Http11ConnectionHandler(this);
85 protected JIoEndpoint endpoint = new JIoEndpoint();
86
87
88 // *
89 protected ObjectName tpOname = null;
90 // *
91 protected ObjectName rgOname = null;
92
93
94 protected ServerSocketFactory socketFactory = null;
95 protected SSLImplementation sslImplementation = null;
96
97
98 // ----------------------------------------- ProtocolHandler Implementation
99 // *
100
101
102 protected HashMap<String, Object> attributes = new HashMap<String, Object>();
103
104
105 /**
106 * Pass config info
107 */
108 public void setAttribute(String name, Object value) {
109 if (log.isTraceEnabled()) {
110 log.trace(sm.getString("http11protocol.setattribute", name, value));
111 }
112 attributes.put(name, value);
113 }
114
115 public Object getAttribute(String key) {
116 return attributes.get(key);
117 }
118
119 public Iterator getAttributeNames() {
120 return attributes.keySet().iterator();
121 }
122
123 /**
124 * Set a property.
125 */
126 public void setProperty(String name, String value) {
127 setAttribute(name, value);
128 }
129
130 /**
131 * Get a property
132 */
133 public String getProperty(String name) {
134 return (String)getAttribute(name);
135 }
136
137 /**
138 * The adapter, used to call the connector.
139 */
140 protected Adapter adapter;
141 public void setAdapter(Adapter adapter) { this.adapter = adapter; }
142 public Adapter getAdapter() { return adapter; }
143
144
145 public void init() throws Exception {
146 endpoint.setName(getName());
147 endpoint.setHandler(cHandler);
148
149 // Verify the validity of the configured socket factory
150 try {
151 if (isSSLEnabled()) {
152 sslImplementation =
153 SSLImplementation.getInstance(sslImplementationName);
154 socketFactory = sslImplementation.getServerSocketFactory();
155 endpoint.setServerSocketFactory(socketFactory);
156 } else if (socketFactoryName != null) {
157 socketFactory = (ServerSocketFactory) Class.forName(socketFactoryName).newInstance();
158 endpoint.setServerSocketFactory(socketFactory);
159 }
160 } catch (Exception ex) {
161 log.error(sm.getString("http11protocol.socketfactory.initerror"),
162 ex);
163 throw ex;
164 }
165
166 if (socketFactory!=null) {
167 Iterator<String> attE = attributes.keySet().iterator();
168 while( attE.hasNext() ) {
169 String key = attE.next();
170 Object v=attributes.get(key);
171 socketFactory.setAttribute(key, v);
172 }
173 }
174
175 try {
176 endpoint.init();
177 } catch (Exception ex) {
178 log.error(sm.getString("http11protocol.endpoint.initerror"), ex);
179 throw ex;
180 }
181 if (log.isInfoEnabled())
182 log.info(sm.getString("http11protocol.init", getName()));
183
184 }
185
186 public void start() throws Exception {
187 if (this.domain != null) {
188 try {
189 tpOname = new ObjectName
190 (domain + ":" + "type=ThreadPool,name=" + getName());
191 Registry.getRegistry(null, null)
192 .registerComponent(endpoint, tpOname, null );
193 } catch (Exception e) {
194 log.error("Can't register endpoint");
195 }
196 rgOname=new ObjectName
197 (domain + ":type=GlobalRequestProcessor,name=" + getName());
198 Registry.getRegistry(null, null).registerComponent
199 ( cHandler.global, rgOname, null );
200 }
201
202 try {
203 endpoint.start();
204 } catch (Exception ex) {
205 log.error(sm.getString("http11protocol.endpoint.starterror"), ex);
206 throw ex;
207 }
208 if (log.isInfoEnabled())
209 log.info(sm.getString("http11protocol.start", getName()));
210 }
211
212 public void pause() throws Exception {
213 try {
214 endpoint.pause();
215 } catch (Exception ex) {
216 log.error(sm.getString("http11protocol.endpoint.pauseerror"), ex);
217 throw ex;
218 }
219 if (log.isInfoEnabled())
220 log.info(sm.getString("http11protocol.pause", getName()));
221 }
222
223 public void resume() throws Exception {
224 try {
225 endpoint.resume();
226 } catch (Exception ex) {
227 log.error(sm.getString("http11protocol.endpoint.resumeerror"), ex);
228 throw ex;
229 }
230 if (log.isInfoEnabled())
231 log.info(sm.getString("http11protocol.resume", getName()));
232 }
233
234 public void destroy() throws Exception {
235 if (log.isInfoEnabled())
236 log.info(sm.getString("http11protocol.stop", getName()));
237 endpoint.destroy();
238 if (tpOname!=null)
239 Registry.getRegistry(null, null).unregisterComponent(tpOname);
240 if (rgOname != null)
241 Registry.getRegistry(null, null).unregisterComponent(rgOname);
242 }
243
244 public String getName() {
245 String encodedAddr = "";
246 if (getAddress() != null) {
247 encodedAddr = "" + getAddress();
248 if (encodedAddr.startsWith("/"))
249 encodedAddr = encodedAddr.substring(1);
250 encodedAddr = URLEncoder.encode(encodedAddr) + "-";
251 }
252 return ("http-" + encodedAddr + endpoint.getPort());
253 }
254
255 // ------------------------------------------------------------- Properties
256
257
258 /**
259 * Processor cache.
260 */
261 protected int processorCache = -1;
262 public int getProcessorCache() { return this.processorCache; }
263 public void setProcessorCache(int processorCache) { this.processorCache = processorCache; }
264
265 protected int socketBuffer = 9000;
266 public int getSocketBuffer() { return socketBuffer; }
267 public void setSocketBuffer(int socketBuffer) { this.socketBuffer = socketBuffer; }
268
269 /**
270 * This field indicates if the protocol is secure from the perspective of
271 * the client (= https is used).
272 */
273 protected boolean secure;
274 public boolean getSecure() { return secure; }
275 public void setSecure(boolean b) { secure = b; }
276
277 protected boolean SSLEnabled = false;
278 public boolean isSSLEnabled() { return SSLEnabled;}
279 public void setSSLEnabled(boolean SSLEnabled) {this.SSLEnabled = SSLEnabled;}
280
281 /**
282 * Name of the socket factory.
283 */
284 protected String socketFactoryName = null;
285 public String getSocketFactory() { return socketFactoryName; }
286 public void setSocketFactory(String valueS) { socketFactoryName = valueS; }
287
288 /**
289 * Name of the SSL implementation.
290 */
291 protected String sslImplementationName=null;
292 public String getSSLImplementation() { return sslImplementationName; }
293 public void setSSLImplementation( String valueS) {
294 sslImplementationName = valueS;
295 setSecure(true);
296 }
297
298
299 // HTTP
300 /**
301 * Maximum number of requests which can be performed over a keepalive
302 * connection. The default is the same as for Apache HTTP Server.
303 */
304 protected int maxKeepAliveRequests = 100;
305 public int getMaxKeepAliveRequests() { return maxKeepAliveRequests; }
306 public void setMaxKeepAliveRequests(int mkar) { maxKeepAliveRequests = mkar; }
307
308 // HTTP
309 /**
310 * The number of seconds Tomcat will wait for a subsequent request
311 * before closing the connection. The default is the same as for
312 * Apache HTTP Server (15 000 milliseconds).
313 */
314 protected int keepAliveTimeout = -1;
315 public int getKeepAliveTimeout() { return keepAliveTimeout; }
316 public void setKeepAliveTimeout(int timeout) { keepAliveTimeout = timeout; }
317
318 // HTTP
319 /**
320 * This timeout represents the socket timeout which will be used while
321 * the adapter execution is in progress, unless disableUploadTimeout
322 * is set to true. The default is the same as for Apache HTTP Server
323 * (300 000 milliseconds).
324 */
325 protected int timeout = 300000;
326 public int getTimeout() { return timeout; }
327 public void setTimeout(int timeout) { this.timeout = timeout; }
328
329
330 // *
331 /**
332 * Maximum size of the post which will be saved when processing certain
333 * requests, such as a POST.
334 */
335 protected int maxSavePostSize = 4 * 1024;
336 public int getMaxSavePostSize() { return maxSavePostSize; }
337 public void setMaxSavePostSize(int valueI) { maxSavePostSize = valueI; }
338
339
340 // HTTP
341 /**
342 * Maximum size of the HTTP message header.
343 */
344 protected int maxHttpHeaderSize = 8 * 1024;
345 public int getMaxHttpHeaderSize() { return maxHttpHeaderSize; }
346 public void setMaxHttpHeaderSize(int valueI) { maxHttpHeaderSize = valueI; }
347
348
349 // HTTP
350 /**
351 * If true, the regular socket timeout will be used for the full duration
352 * of the connection.
353 */
354 protected boolean disableUploadTimeout = true;
355 public boolean getDisableUploadTimeout() { return disableUploadTimeout; }
356 public void setDisableUploadTimeout(boolean isDisabled) { disableUploadTimeout = isDisabled; }
357
358
359 // HTTP
360 /**
361 * Integrated compression support.
362 */
363 protected String compression = "off";
364 public String getCompression() { return compression; }
365 public void setCompression(String valueS) { compression = valueS; }
366
367
368 // HTTP
369 protected String noCompressionUserAgents = null;
370 public String getNoCompressionUserAgents() { return noCompressionUserAgents; }
371 public void setNoCompressionUserAgents(String valueS) { noCompressionUserAgents = valueS; }
372
373
374 // HTTP
375 protected String compressableMimeTypes = "text/html,text/xml,text/plain";
376 public String getCompressableMimeType() { return compressableMimeTypes; }
377 public void setCompressableMimeType(String valueS) { compressableMimeTypes = valueS; }
378
379
380 // HTTP
381 protected int compressionMinSize = 2048;
382 public int getCompressionMinSize() { return compressionMinSize; }
383 public void setCompressionMinSize(int valueI) { compressionMinSize = valueI; }
384
385
386 // HTTP
387 /**
388 * User agents regular expressions which should be restricted to HTTP/1.0 support.
389 */
390 protected String restrictedUserAgents = null;
391 public String getRestrictedUserAgents() { return restrictedUserAgents; }
392 public void setRestrictedUserAgents(String valueS) { restrictedUserAgents = valueS; }
393
394 // HTTP
395 /**
396 * Server header.
397 */
398 protected String server;
399 public void setServer( String server ) { this.server = server; }
400 public String getServer() { return server; }
401
402 public Executor getExecutor() { return endpoint.getExecutor(); }
403 public void setExecutor(Executor executor) { endpoint.setExecutor(executor); }
404
405 public int getMaxThreads() { return endpoint.getMaxThreads(); }
406 public void setMaxThreads(int maxThreads) { endpoint.setMaxThreads(maxThreads); }
407
408 public int getThreadPriority() { return endpoint.getThreadPriority(); }
409 public void setThreadPriority(int threadPriority) { endpoint.setThreadPriority(threadPriority); }
410
411 public int getBacklog() { return endpoint.getBacklog(); }
412 public void setBacklog(int backlog) { endpoint.setBacklog(backlog); }
413
414 public int getPort() { return endpoint.getPort(); }
415 public void setPort(int port) { endpoint.setPort(port); }
416
417 public InetAddress getAddress() { return endpoint.getAddress(); }
418 public void setAddress(InetAddress ia) { endpoint.setAddress(ia); }
419
420 public boolean getTcpNoDelay() { return endpoint.getTcpNoDelay(); }
421 public void setTcpNoDelay(boolean tcpNoDelay) { endpoint.setTcpNoDelay(tcpNoDelay); }
422
423 public int getSoLinger() { return endpoint.getSoLinger(); }
424 public void setSoLinger(int soLinger) { endpoint.setSoLinger(soLinger); }
425
426 public int getSoTimeout() { return endpoint.getSoTimeout(); }
427 public void setSoTimeout(int soTimeout) { endpoint.setSoTimeout(soTimeout); }
428
429 // HTTP
430 /**
431 * Return the Keep-Alive policy for the connection.
432 */
433 public boolean getKeepAlive() {
434 return ((maxKeepAliveRequests != 0) && (maxKeepAliveRequests != 1));
435 }
436
437 // HTTP
438 /**
439 * Set the keep-alive policy for this connection.
440 */
441 public void setKeepAlive(boolean keepAlive) {
442 if (!keepAlive) {
443 setMaxKeepAliveRequests(1);
444 }
445 }
446
447 /*
448 * Note: All the following are JSSE/java.io specific attributes.
449 */
450
451 public String getKeystore() {
452 return (String) getAttribute("keystore");
453 }
454
455 public void setKeystore( String k ) {
456 setAttribute("keystore", k);
457 }
458
459 public String getKeypass() {
460 return (String) getAttribute("keypass");
461 }
462
463 public void setKeypass( String k ) {
464 attributes.put("keypass", k);
465 //setAttribute("keypass", k);
466 }
467
468 public String getKeytype() {
469 return (String) getAttribute("keystoreType");
470 }
471
472 public void setKeytype( String k ) {
473 setAttribute("keystoreType", k);
474 }
475
476 public String getClientauth() {
477 return (String) getAttribute("clientauth");
478 }
479
480 public void setClientauth( String k ) {
481 setAttribute("clientauth", k);
482 }
483
484 public String getProtocols() {
485 return (String) getAttribute("protocols");
486 }
487
488 public void setProtocols(String k) {
489 setAttribute("protocols", k);
490 }
491
492 public String getAlgorithm() {
493 return (String) getAttribute("algorithm");
494 }
495
496 public void setAlgorithm( String k ) {
497 setAttribute("algorithm", k);
498 }
499
500 public String getCiphers() {
501 return (String) getAttribute("ciphers");
502 }
503
504 public void setCiphers(String ciphers) {
505 setAttribute("ciphers", ciphers);
506 }
507
508 public String getKeyAlias() {
509 return (String) getAttribute("keyAlias");
510 }
511
512 public void setKeyAlias(String keyAlias) {
513 setAttribute("keyAlias", keyAlias);
514 }
515
516 // ----------------------------------- Http11ConnectionHandler Inner Class
517
518 protected static class Http11ConnectionHandler implements Handler {
519
520 protected Http11Protocol proto;
521 protected AtomicLong registerCount = new AtomicLong(0);
522 protected RequestGroupInfo global = new RequestGroupInfo();
523
524 protected ConcurrentLinkedQueue<Http11Processor> recycledProcessors =
525 new ConcurrentLinkedQueue<Http11Processor>() {
526 protected AtomicInteger size = new AtomicInteger(0);
527 public boolean offer(Http11Processor processor) {
528 boolean offer = (proto.processorCache == -1) ? true : (size.get() < proto.processorCache);
529 //avoid over growing our cache or add after we have stopped
530 boolean result = false;
531 if ( offer ) {
532 result = super.offer(processor);
533 if ( result ) {
534 size.incrementAndGet();
535 }
536 }
537 if (!result) unregister(processor);
538 return result;
539 }
540
541 public Http11Processor poll() {
542 Http11Processor result = super.poll();
543 if ( result != null ) {
544 size.decrementAndGet();
545 }
546 return result;
547 }
548
549 public void clear() {
550 Http11Processor next = poll();
551 while ( next != null ) {
552 unregister(next);
553 next = poll();
554 }
555 super.clear();
556 size.set(0);
557 }
558 };
559
560 Http11ConnectionHandler(Http11Protocol proto) {
561 this.proto = proto;
562 }
563
564 public boolean process(Socket socket) {
565 Http11Processor processor = recycledProcessors.poll();
566 try {
567
568 if (processor == null) {
569 processor = createProcessor();
570 }
571
572 if (processor instanceof ActionHook) {
573 ((ActionHook) processor).action(ActionCode.ACTION_START, null);
574 }
575
576 if (proto.secure && (proto.sslImplementation != null)) {
577 processor.setSSLSupport
578 (proto.sslImplementation.getSSLSupport(socket));
579 } else {
580 processor.setSSLSupport(null);
581 }
582
583 processor.process(socket);
584 return false;
585
586 } catch(java.net.SocketException e) {
587 // SocketExceptions are normal
588 Http11Protocol.log.debug
589 (sm.getString
590 ("http11protocol.proto.socketexception.debug"), e);
591 } catch (java.io.IOException e) {
592 // IOExceptions are normal
593 Http11Protocol.log.debug
594 (sm.getString
595 ("http11protocol.proto.ioexception.debug"), e);
596 }
597 // Future developers: if you discover any other
598 // rare-but-nonfatal exceptions, catch them here, and log as
599 // above.
600 catch (Throwable e) {
601 // any other exception or error is odd. Here we log it
602 // with "ERROR" level, so it will show up even on
603 // less-than-verbose logs.
604 Http11Protocol.log.error
605 (sm.getString("http11protocol.proto.error"), e);
606 } finally {
607 // if(proto.adapter != null) proto.adapter.recycle();
608 // processor.recycle();
609
610 if (processor instanceof ActionHook) {
611 ((ActionHook) processor).action(ActionCode.ACTION_STOP, null);
612 }
613 recycledProcessors.offer(processor);
614 }
615 return false;
616 }
617
618 protected Http11Processor createProcessor() {
619 Http11Processor processor =
620 new Http11Processor(proto.maxHttpHeaderSize, proto.endpoint);
621 processor.setAdapter(proto.adapter);
622 processor.setMaxKeepAliveRequests(proto.maxKeepAliveRequests);
623 processor.setKeepAliveTimeout(proto.keepAliveTimeout);
624 processor.setTimeout(proto.timeout);
625 processor.setDisableUploadTimeout(proto.disableUploadTimeout);
626 processor.setCompressionMinSize(proto.compressionMinSize);
627 processor.setCompression(proto.compression);
628 processor.setNoCompressionUserAgents(proto.noCompressionUserAgents);
629 processor.setCompressableMimeTypes(proto.compressableMimeTypes);
630 processor.setRestrictedUserAgents(proto.restrictedUserAgents);
631 processor.setSocketBuffer(proto.socketBuffer);
632 processor.setMaxSavePostSize(proto.maxSavePostSize);
633 processor.setServer(proto.server);
634 register(processor);
635 return processor;
636 }
637
638 protected void register(Http11Processor processor) {
639 if (proto.getDomain() != null) {
640 synchronized (this) {
641 try {
642 long count = registerCount.incrementAndGet();
643 RequestInfo rp = processor.getRequest().getRequestProcessor();
644 rp.setGlobalProcessor(global);
645 ObjectName rpName = new ObjectName
646 (proto.getDomain() + ":type=RequestProcessor,worker="
647 + proto.getName() + ",name=HttpRequest" + count);
648 if (log.isDebugEnabled()) {
649 log.debug("Register " + rpName);
650 }
651 Registry.getRegistry(null, null).registerComponent(rp, rpName, null);
652 rp.setRpName(rpName);
653 } catch (Exception e) {
654 log.warn("Error registering request");
655 }
656 }
657 }
658 }
659
660 protected void unregister(Http11Processor processor) {
661 if (proto.getDomain() != null) {
662 synchronized (this) {
663 try {
664 RequestInfo rp = processor.getRequest().getRequestProcessor();
665 rp.setGlobalProcessor(null);
666 ObjectName rpName = rp.getRpName();
667 if (log.isDebugEnabled()) {
668 log.debug("Unregister " + rpName);
669 }
670 Registry.getRegistry(null, null).unregisterComponent(rpName);
671 rp.setRpName(null);
672 } catch (Exception e) {
673 log.warn("Error unregistering request", e);
674 }
675 }
676 }
677 }
678
679 }
680
681
682 // -------------------- JMX related methods --------------------
683
684 // *
685 protected String domain;
686 protected ObjectName oname;
687 protected MBeanServer mserver;
688
689 public ObjectName getObjectName() {
690 return oname;
691 }
692
693 public String getDomain() {
694 return domain;
695 }
696
697 public ObjectName preRegister(MBeanServer server,
698 ObjectName name) throws Exception {
699 oname=name;
700 mserver=server;
701 domain=name.getDomain();
702 return name;
703 }
704
705 public void postRegister(Boolean registrationDone) {
706 }
707
708 public void preDeregister() throws Exception {
709 }
710
711 public void postDeregister() {
712 }
713 }