1 /*
2 * Copyright 1999-2004 The Apache Software Foundation
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 package org.apache.coyote.http11;
18
19 import java.io.IOException;
20 import java.io.InputStream;
21 import java.io.OutputStream;
22 import java.net.InetAddress;
23 import java.net.Socket;
24 import java.net.URLEncoder;
25 import java.util.Enumeration;
26 import java.util.Hashtable;
27 import java.util.Iterator;
28
29 import org.apache.coyote.ActionCode;
30 import org.apache.coyote.ActionHook;
31 import org.apache.coyote.Adapter;
32 import org.apache.coyote.ProtocolHandler;
33 import org.apache.coyote.RequestGroupInfo;
34 import org.apache.coyote.RequestInfo;
35 import org.apache.tomcat.util.net.PoolTcpEndpoint;
36 import org.apache.tomcat.util.net.SSLImplementation;
37 import org.apache.tomcat.util.net.SSLSupport;
38 import org.apache.tomcat.util.net.ServerSocketFactory;
39 import org.apache.tomcat.util.net.TcpConnection;
40 import org.apache.tomcat.util.net.TcpConnectionHandler;
41 import org.apache.tomcat.util.res.StringManager;
42 import org.apache.tomcat.util.threads.ThreadPool;
43 import org.apache.tomcat.util.threads.ThreadWithAttributes;
44
45
46 /**
47 * Abstract the protocol implementation, including threading, etc.
48 * Processor is single threaded and specific to stream-based protocols,
49 * will not fit Jk protocols like JNI.
50 *
51 * @author Remy Maucherat
52 * @author Costin Manolache
53 */
54 public class Http11BaseProtocol implements ProtocolHandler
55 {
56 public Http11BaseProtocol() {
57 }
58
59 /**
60 * The string manager for this package.
61 */
62 protected static StringManager sm =
63 StringManager.getManager(Constants.Package);
64
65 /** Pass config info
66 */
67 public void setAttribute( String name, Object value ) {
68 if( log.isTraceEnabled())
69 log.trace(sm.getString("http11protocol.setattribute", name, value));
70
71 attributes.put(name, value);
72 }
73
74 public Object getAttribute( String key ) {
75 if( log.isTraceEnabled())
76 log.trace(sm.getString("http11protocol.getattribute", key));
77 return attributes.get(key);
78 }
79
80 public Iterator getAttributeNames() {
81 return attributes.keySet().iterator();
82 }
83
84 /**
85 * Set a property.
86 */
87 public void setProperty(String name, String value) {
88 setAttribute(name, value);
89 }
90
91 /**
92 * Get a property
93 */
94 public String getProperty(String name) {
95 return (String)getAttribute(name);
96 }
97
98 /** The adapter, used to call the connector
99 */
100 public void setAdapter(Adapter adapter) {
101 this.adapter=adapter;
102 }
103
104 public Adapter getAdapter() {
105 return adapter;
106 }
107
108 protected Http11ConnectionHandler createConnectionHandler() {
109 Http11ConnectionHandler cHandler = new Http11ConnectionHandler( this );
110 setSoLinger(Constants.DEFAULT_CONNECTION_LINGER);
111 setSoTimeout(Constants.DEFAULT_CONNECTION_TIMEOUT);
112 setServerSoTimeout(Constants.DEFAULT_SERVER_SOCKET_TIMEOUT);
113 setTcpNoDelay(Constants.DEFAULT_TCP_NO_DELAY);
114 return cHandler ;
115 }
116
117 /** Start the protocol
118 */
119 public void init() throws Exception {
120 cHandler = createConnectionHandler() ;
121 ep.setConnectionHandler( cHandler );
122 try {
123 checkSocketFactory();
124 } catch( Exception ex ) {
125 log.error(sm.getString("http11protocol.socketfactory.initerror"),
126 ex);
127 throw ex;
128 }
129
130 if( socketFactory!=null ) {
131 Enumeration attE=attributes.keys();
132 while( attE.hasMoreElements() ) {
133 String key=(String)attE.nextElement();
134 Object v=attributes.get( key );
135 socketFactory.setAttribute( key, v );
136 }
137 }
138
139 // XXX get domain from registration
140 try {
141 ep.initEndpoint();
142 } catch (Exception ex) {
143 log.error(sm.getString("http11protocol.endpoint.initerror"), ex);
144 throw ex;
145 }
146 if(log.isInfoEnabled())
147 log.info(sm.getString("http11protocol.init", getName()));
148
149 }
150
151 public void start() throws Exception {
152 try {
153 ep.startEndpoint();
154 } catch (Exception ex) {
155 log.error(sm.getString("http11protocol.endpoint.starterror"), ex);
156 throw ex;
157 }
158 if(log.isInfoEnabled())
159 log.info(sm.getString("http11protocol.start", getName()));
160 }
161
162 public void pause() throws Exception {
163 try {
164 ep.pauseEndpoint();
165 } catch (Exception ex) {
166 log.error(sm.getString("http11protocol.endpoint.pauseerror"), ex);
167 throw ex;
168 }
169 if(log.isInfoEnabled())
170 log.info(sm.getString("http11protocol.pause", getName()));
171 }
172
173 public void resume() throws Exception {
174 try {
175 ep.resumeEndpoint();
176 } catch (Exception ex) {
177 log.error(sm.getString("http11protocol.endpoint.resumeerror"), ex);
178 throw ex;
179 }
180 if(log.isInfoEnabled())
181 log.info(sm.getString("http11protocol.resume", getName()));
182 }
183
184 public void destroy() throws Exception {
185 if(log.isInfoEnabled())
186 log.info(sm.getString("http11protocol.stop", getName()));
187 ep.stopEndpoint();
188 }
189
190 // -------------------- Properties--------------------
191 protected ThreadPool tp=ThreadPool.createThreadPool(true);
192 protected PoolTcpEndpoint ep=new PoolTcpEndpoint(tp);
193 protected boolean secure;
194
195 protected ServerSocketFactory socketFactory;
196 protected SSLImplementation sslImplementation;
197 // socket factory attriubtes ( XXX replace with normal setters )
198 protected Hashtable attributes = new Hashtable();
199 protected String socketFactoryName=null;
200 protected String sslImplementationName=null;
201
202 private int maxKeepAliveRequests=100; // as in Apache HTTPD server
203 private int timeout = 300000; // 5 minutes as in Apache HTTPD server
204 private int maxSavePostSize = 4 * 1024;
205 private int maxHttpHeaderSize = 4 * 1024;
206 private String reportedname;
207 private int socketCloseDelay=-1;
208 private boolean disableUploadTimeout = true;
209 private int socketBuffer = 9000;
210 private Adapter adapter;
211 protected Http11ConnectionHandler cHandler;
212
213 /**
214 * Compression value.
215 */
216 private String compression = "off";
217 private String noCompressionUserAgents = null;
218 private String restrictedUserAgents = null;
219 private String compressableMimeTypes = "text/html,text/xml,text/plain";
220 private int compressionMinSize = 2048;
221
222 private String server;
223
224 // -------------------- Pool setup --------------------
225
226 public int getMaxThreads() {
227 return ep.getMaxThreads();
228 }
229
230 public void setMaxThreads( int maxThreads ) {
231 ep.setMaxThreads(maxThreads);
232 setAttribute("maxThreads", "" + maxThreads);
233 }
234
235 public int getMaxSpareThreads() {
236 return ep.getMaxSpareThreads();
237 }
238
239 public void setMaxSpareThreads( int maxThreads ) {
240 ep.setMaxSpareThreads(maxThreads);
241 setAttribute("maxSpareThreads", "" + maxThreads);
242 }
243
244 public int getMinSpareThreads() {
245 return ep.getMinSpareThreads();
246 }
247
248 public void setMinSpareThreads( int minSpareThreads ) {
249 ep.setMinSpareThreads(minSpareThreads);
250 setAttribute("minSpareThreads", "" + minSpareThreads);
251 }
252
253 public void setThreadPriority(int threadPriority) {
254 ep.setThreadPriority(threadPriority);
255 setAttribute("threadPriority", "" + threadPriority);
256 }
257
258 public int getThreadPriority() {
259 return ep.getThreadPriority();
260 }
261
262 public void setStrategy(String strategy) {
263 ep.setStrategy(strategy);
264 setAttribute("strategy", strategy);
265 }
266
267 public String getStrategy() {
268 return ep.getStrategy();
269 }
270
271 // -------------------- Tcp setup --------------------
272
273 public int getBacklog() {
274 return ep.getBacklog();
275 }
276
277 public void setBacklog( int i ) {
278 ep.setBacklog(i);
279 setAttribute("backlog", "" + i);
280 }
281
282 public int getPort() {
283 return ep.getPort();
284 }
285
286 public void setPort( int port ) {
287 ep.setPort(port);
288 setAttribute("port", "" + port);
289 }
290
291 public InetAddress getAddress() {
292 return ep.getAddress();
293 }
294
295 public void setAddress(InetAddress ia) {
296 ep.setAddress( ia );
297 setAttribute("address", "" + ia);
298 }
299
300 public String getName() {
301 String encodedAddr = "";
302 if (getAddress() != null) {
303 encodedAddr = "" + getAddress();
304 if (encodedAddr.startsWith("/"))
305 encodedAddr = encodedAddr.substring(1);
306 encodedAddr = URLEncoder.encode(encodedAddr) + "-";
307 }
308 return ("http-" + encodedAddr + ep.getPort());
309 }
310
311 public String getSocketFactory() {
312 return socketFactoryName;
313 }
314
315 public void setSocketFactory( String valueS ) {
316 socketFactoryName = valueS;
317 setAttribute("socketFactory", valueS);
318 }
319
320 public String getSSLImplementation() {
321 return sslImplementationName;
322 }
323
324 public void setSSLImplementation( String valueS) {
325 sslImplementationName = valueS;
326 setSecure(true);
327 setAttribute("sslImplementation", valueS);
328 }
329
330 public boolean getTcpNoDelay() {
331 return ep.getTcpNoDelay();
332 }
333
334 public void setTcpNoDelay( boolean b ) {
335 ep.setTcpNoDelay( b );
336 setAttribute("tcpNoDelay", "" + b);
337 }
338
339 public boolean getDisableUploadTimeout() {
340 return disableUploadTimeout;
341 }
342
343 public void setDisableUploadTimeout(boolean isDisabled) {
344 disableUploadTimeout = isDisabled;
345 }
346
347 public int getSocketBuffer() {
348 return socketBuffer;
349 }
350
351 public void setSocketBuffer(int valueI) {
352 socketBuffer = valueI;
353 }
354
355 public String getCompression() {
356 return compression;
357 }
358
359 public void setCompression(String valueS) {
360 compression = valueS;
361 setAttribute("compression", valueS);
362 }
363
364 public int getMaxSavePostSize() {
365 return maxSavePostSize;
366 }
367
368 public void setMaxSavePostSize(int valueI) {
369 maxSavePostSize = valueI;
370 setAttribute("maxSavePostSize", "" + valueI);
371 }
372
373 public int getMaxHttpHeaderSize() {
374 return maxHttpHeaderSize;
375 }
376
377 public void setMaxHttpHeaderSize(int valueI) {
378 maxHttpHeaderSize = valueI;
379 setAttribute("maxHttpHeaderSize", "" + valueI);
380 }
381
382 public String getRestrictedUserAgents() {
383 return restrictedUserAgents;
384 }
385
386 public void setRestrictedUserAgents(String valueS) {
387 restrictedUserAgents = valueS;
388 setAttribute("restrictedUserAgents", valueS);
389 }
390
391 public String getNoCompressionUserAgents() {
392 return noCompressionUserAgents;
393 }
394
395 public void setNoCompressionUserAgents(String valueS) {
396 noCompressionUserAgents = valueS;
397 setAttribute("noCompressionUserAgents", valueS);
398 }
399
400 public String getCompressableMimeType() {
401 return compressableMimeTypes;
402 }
403
404 public void setCompressableMimeType(String valueS) {
405 compressableMimeTypes = valueS;
406 setAttribute("compressableMimeTypes", valueS);
407 }
408
409 public int getCompressionMinSize() {
410 return compressionMinSize;
411 }
412
413 public void setCompressionMinSize(int valueI) {
414 compressionMinSize = valueI;
415 setAttribute("compressionMinSize", "" + valueI);
416 }
417
418 public int getSoLinger() {
419 return ep.getSoLinger();
420 }
421
422 public void setSoLinger( int i ) {
423 ep.setSoLinger( i );
424 setAttribute("soLinger", "" + i);
425 }
426
427 public int getSoTimeout() {
428 return ep.getSoTimeout();
429 }
430
431 public void setSoTimeout( int i ) {
432 ep.setSoTimeout(i);
433 setAttribute("soTimeout", "" + i);
434 }
435
436 public int getServerSoTimeout() {
437 return ep.getServerSoTimeout();
438 }
439
440 public void setServerSoTimeout( int i ) {
441 ep.setServerSoTimeout(i);
442 setAttribute("serverSoTimeout", "" + i);
443 }
444
445 public String getKeystore() {
446 return getProperty("keystore");
447 }
448
449 public void setKeystore( String k ) {
450 setAttribute("keystore", k);
451 }
452
453 public String getKeypass() {
454 return getProperty("keypass");
455 }
456
457 public void setKeypass( String k ) {
458 attributes.put("keypass", k);
459 //setAttribute("keypass", k);
460 }
461
462 public String getKeytype() {
463 return getProperty("keystoreType");
464 }
465
466 public void setKeytype( String k ) {
467 setAttribute("keystoreType", k);
468 }
469
470 public String getClientauth() {
471 return getProperty("clientauth");
472 }
473
474 public void setClientauth( String k ) {
475 setAttribute("clientauth", k);
476 }
477
478 public String getProtocol() {
479 return getProperty("protocol");
480 }
481
482 public void setProtocol( String k ) {
483 setSecure(true);
484 setAttribute("protocol", k);
485 }
486
487 public String getProtocols() {
488 return getProperty("protocols");
489 }
490
491 public void setProtocols(String k) {
492 setAttribute("protocols", k);
493 }
494
495 public String getAlgorithm() {
496 return getProperty("algorithm");
497 }
498
499 public void setAlgorithm( String k ) {
500 setAttribute("algorithm", k);
501 }
502
503 public boolean getSecure() {
504 return secure;
505 }
506
507 public void setSecure( boolean b ) {
508 secure=b;
509 setAttribute("secure", "" + b);
510 }
511
512 public String getCiphers() {
513 return getProperty("ciphers");
514 }
515
516 public void setCiphers(String ciphers) {
517 setAttribute("ciphers", ciphers);
518 }
519
520 public String getKeyAlias() {
521 return getProperty("keyAlias");
522 }
523
524 public void setKeyAlias(String keyAlias) {
525 setAttribute("keyAlias", keyAlias);
526 }
527
528 public int getMaxKeepAliveRequests() {
529 return maxKeepAliveRequests;
530 }
531
532 /** Set the maximum number of Keep-Alive requests that we will honor.
533 */
534 public void setMaxKeepAliveRequests(int mkar) {
535 maxKeepAliveRequests = mkar;
536 setAttribute("maxKeepAliveRequests", "" + mkar);
537 }
538
539 /**
540 * Return the Keep-Alive policy for the connection.
541 */
542 public boolean getKeepAlive() {
543 return ((maxKeepAliveRequests != 0) && (maxKeepAliveRequests != 1));
544 }
545
546 /**
547 * Set the keep-alive policy for this connection.
548 */
549 public void setKeepAlive(boolean keepAlive) {
550 if (!keepAlive) {
551 setMaxKeepAliveRequests(1);
552 }
553 }
554
555 public int getSocketCloseDelay() {
556 return socketCloseDelay;
557 }
558
559 public void setSocketCloseDelay( int d ) {
560 socketCloseDelay=d;
561 setAttribute("socketCloseDelay", "" + d);
562 }
563
564 public void setServer( String server ) {
565 this.server = server;
566 }
567
568 public String getServer() {
569 return server;
570 }
571
572
573 private static ServerSocketFactory string2SocketFactory( String val)
574 throws ClassNotFoundException, IllegalAccessException,
575 InstantiationException
576 {
577 Class chC=Class.forName( val );
578 return (ServerSocketFactory)chC.newInstance();
579 }
580
581 public int getTimeout() {
582 return timeout;
583 }
584
585 public void setTimeout( int timeouts ) {
586 timeout = timeouts;
587 setAttribute("timeout", "" + timeouts);
588 }
589
590 public String getReportedname() {
591 return reportedname;
592 }
593
594 public void setReportedname( String reportedName) {
595 reportedname = reportedName;
596 }
597
598 // -------------------- Connection handler --------------------
599 public static final int THREAD_DATA_PROCESSOR=1;
600 public static final int THREAD_DATA_OBJECT_NAME=2;
601
602 static class Http11ConnectionHandler implements TcpConnectionHandler {
603 Http11BaseProtocol proto;
604 static int count=0;
605 RequestGroupInfo global=new RequestGroupInfo();
606
607 Http11ConnectionHandler( Http11BaseProtocol proto ) {
608 this.proto=proto;
609 }
610
611 public void setAttribute( String name, Object value ) {
612 }
613
614 public void setServer( Object o ) {
615 }
616
617 public Object[] init() {
618 Object thData[]=new Object[3];
619
620 Http11Processor processor =
621 new Http11Processor(proto.maxHttpHeaderSize);
622 processor.setAdapter( proto.adapter );
623 processor.setThreadPool( proto.tp );
624 processor.setEndpoint( proto.ep );
625 processor.setMaxKeepAliveRequests( proto.maxKeepAliveRequests );
626 processor.setTimeout( proto.timeout );
627 processor.setDisableUploadTimeout( proto.disableUploadTimeout );
628 processor.setCompression( proto.compression );
629 processor.setCompressionMinSize( proto.compressionMinSize);
630 processor.setNoCompressionUserAgents( proto.noCompressionUserAgents);
631 processor.setCompressableMimeTypes( proto.compressableMimeTypes);
632 processor.setRestrictedUserAgents( proto.restrictedUserAgents);
633 processor.setSocketBuffer( proto.socketBuffer );
634 processor.setMaxSavePostSize( proto.maxSavePostSize );
635 processor.setServer( proto.server );
636
637 thData[Http11BaseProtocol.THREAD_DATA_PROCESSOR]=processor;
638
639 return thData;
640 }
641
642 public void processConnection(TcpConnection connection,
643 Object thData[]) {
644 Socket socket=null;
645 Http11Processor processor=null;
646 try {
647 processor=(Http11Processor)thData[Http11BaseProtocol.THREAD_DATA_PROCESSOR];
648
649 if (processor instanceof ActionHook) {
650 ((ActionHook) processor).action(ActionCode.ACTION_START, null);
651 }
652 socket=connection.getSocket();
653
654 InputStream in = socket.getInputStream();
655 OutputStream out = socket.getOutputStream();
656
657 if( proto.secure ) {
658 SSLSupport sslSupport=null;
659 if(proto.sslImplementation != null)
660 sslSupport = proto.sslImplementation.getSSLSupport(socket);
661 processor.setSSLSupport(sslSupport);
662 } else {
663 processor.setSSLSupport( null );
664 }
665 processor.setSocket( socket );
666
667 processor.process(in, out);
668
669 // If unread input arrives after the shutdownInput() call
670 // below and before or during the socket.close(), an error
671 // may be reported to the client. To help troubleshoot this
672 // type of error, provide a configurable delay to give the
673 // unread input time to arrive so it can be successfully read
674 // and discarded by shutdownInput().
675 if( proto.socketCloseDelay >= 0 ) {
676 try {
677 Thread.sleep(proto.socketCloseDelay);
678 } catch (InterruptedException ie) { /* ignore */ }
679 }
680
681 TcpConnection.shutdownInput( socket );
682 } catch(java.net.SocketException e) {
683 // SocketExceptions are normal
684 Http11BaseProtocol.log.debug
685 (sm.getString
686 ("http11protocol.proto.socketexception.debug"), e);
687 } catch (IOException e) {
688 // IOExceptions are normal
689 Http11BaseProtocol.log.debug
690 (sm.getString
691 ("http11protocol.proto.ioexception.debug"), e);
692 }
693 // Future developers: if you discover any other
694 // rare-but-nonfatal exceptions, catch them here, and log as
695 // above.
696 catch (Throwable e) {
697 // any other exception or error is odd. Here we log it
698 // with "ERROR" level, so it will show up even on
699 // less-than-verbose logs.
700 Http11BaseProtocol.log.error
701 (sm.getString("http11protocol.proto.error"), e);
702 } finally {
703 // if(proto.adapter != null) proto.adapter.recycle();
704 // processor.recycle();
705
706 if (processor instanceof ActionHook) {
707 ((ActionHook) processor).action(ActionCode.ACTION_STOP, null);
708 }
709 // recycle kernel sockets ASAP
710 try { if (socket != null) socket.close (); }
711 catch (IOException e) { /* ignore */ }
712 }
713 }
714 }
715
716 protected static org.apache.commons.logging.Log log
717 = org.apache.commons.logging.LogFactory.getLog(Http11BaseProtocol.class);
718
719 // -------------------- Various implementation classes --------------------
720
721 /** Sanity check and socketFactory setup.
722 * IMHO it is better to stop the show on a broken connector,
723 * then leave Tomcat running and broken.
724 * @exception TomcatException Unable to resolve classes
725 */
726 private void checkSocketFactory() throws Exception {
727 if (secure) {
728 try {
729 // The SSL setup code has been moved into
730 // SSLImplementation since SocketFactory doesn't
731 // provide a wide enough interface
732 sslImplementation =
733 SSLImplementation.getInstance(sslImplementationName);
734 socketFactory = sslImplementation.getServerSocketFactory();
735 ep.setServerSocketFactory(socketFactory);
736 } catch (ClassNotFoundException e){
737 throw e;
738 }
739 } else if (socketFactoryName != null) {
740 try {
741 socketFactory = string2SocketFactory(socketFactoryName);
742 ep.setServerSocketFactory(socketFactory);
743 } catch(Exception sfex) {
744 throw sfex;
745 }
746 }
747 }
748
749 }