Source Code Cross Referenced for Http11NioProcessor.java in  » Sevlet-Container » apache-tomcat-6.0.14 » org » apache » coyote » http11 » Java Source Code / Java DocumentationJava Source Code and Java Documentation

Java Source Code / Java Documentation
1. 6.0 JDK Core
2. 6.0 JDK Modules
3. 6.0 JDK Modules com.sun
4. 6.0 JDK Modules com.sun.java
5. 6.0 JDK Modules sun
6. 6.0 JDK Platform
7. Ajax
8. Apache Harmony Java SE
9. Aspect oriented
10. Authentication Authorization
11. Blogger System
12. Build
13. Byte Code
14. Cache
15. Chart
16. Chat
17. Code Analyzer
18. Collaboration
19. Content Management System
20. Database Client
21. Database DBMS
22. Database JDBC Connection Pool
23. Database ORM
24. Development
25. EJB Server geronimo
26. EJB Server GlassFish
27. EJB Server JBoss 4.2.1
28. EJB Server resin 3.1.5
29. ERP CRM Financial
30. ESB
31. Forum
32. GIS
33. Graphic Library
34. Groupware
35. HTML Parser
36. IDE
37. IDE Eclipse
38. IDE Netbeans
39. Installer
40. Internationalization Localization
41. Inversion of Control
42. Issue Tracking
43. J2EE
44. JBoss
45. JMS
46. JMX
47. Library
48. Mail Clients
49. Net
50. Parser
51. PDF
52. Portal
53. Profiler
54. Project Management
55. Report
56. RSS RDF
57. Rule Engine
58. Science
59. Scripting
60. Search Engine
61. Security
62. Sevlet Container
63. Source Control
64. Swing Library
65. Template Engine
66. Test Coverage
67. Testing
68. UML
69. Web Crawler
70. Web Framework
71. Web Mail
72. Web Server
73. Web Services
74. Web Services apache cxf 2.0.1
75. Web Services AXIS2
76. Wiki Engine
77. Workflow Engines
78. XML
79. XML UI
Java
Java Tutorial
Java Open Source
Jar File Download
Java Articles
Java Products
Java by API
Photoshop Tutorials
Maya Tutorials
Flash Tutorials
3ds-Max Tutorials
Illustrator Tutorials
GIMP Tutorials
C# / C Sharp
C# / CSharp Tutorial
C# / CSharp Open Source
ASP.Net
ASP.NET Tutorial
JavaScript DHTML
JavaScript Tutorial
JavaScript Reference
HTML / CSS
HTML CSS Reference
C / ANSI-C
C Tutorial
C++
C++ Tutorial
Ruby
PHP
Python
Python Tutorial
Python Open Source
SQL Server / T-SQL
SQL Server / T-SQL Tutorial
Oracle PL / SQL
Oracle PL/SQL Tutorial
PostgreSQL
SQL / MySQL
MySQL Tutorial
VB.Net
VB.Net Tutorial
Flash / Flex / ActionScript
VBA / Excel / Access / Word
XML
XML Tutorial
Microsoft Office PowerPoint 2007 Tutorial
Microsoft Office Excel 2007 Tutorial
Microsoft Office Word 2007 Tutorial
Java Source Code / Java Documentation » Sevlet Container » apache tomcat 6.0.14 » org.apache.coyote.http11 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


0001:        /*
0002:         *  Licensed to the Apache Software Foundation (ASF) under one or more
0003:         *  contributor license agreements.  See the NOTICE file distributed with
0004:         *  this work for additional information regarding copyright ownership.
0005:         *  The ASF licenses this file to You under the Apache License, Version 2.0
0006:         *  (the "License"); you may not use this file except in compliance with
0007:         *  the License.  You may obtain a copy of the License at
0008:         *
0009:         *      http://www.apache.org/licenses/LICENSE-2.0
0010:         *
0011:         *  Unless required by applicable law or agreed to in writing, software
0012:         *  distributed under the License is distributed on an "AS IS" BASIS,
0013:         *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
0014:         *  See the License for the specific language governing permissions and
0015:         *  limitations under the License.
0016:         */
0017:
0018:        package org.apache.coyote.http11;
0019:
0020:        import java.io.IOException;
0021:        import java.io.InterruptedIOException;
0022:        import java.net.InetAddress;
0023:        import java.nio.channels.SelectionKey;
0024:        import java.util.StringTokenizer;
0025:        import java.util.regex.Pattern;
0026:        import java.util.regex.PatternSyntaxException;
0027:
0028:        import org.apache.coyote.ActionCode;
0029:        import org.apache.coyote.ActionHook;
0030:        import org.apache.coyote.Adapter;
0031:        import org.apache.coyote.Request;
0032:        import org.apache.coyote.RequestInfo;
0033:        import org.apache.coyote.Response;
0034:        import org.apache.coyote.http11.filters.BufferedInputFilter;
0035:        import org.apache.coyote.http11.filters.ChunkedInputFilter;
0036:        import org.apache.coyote.http11.filters.ChunkedOutputFilter;
0037:        import org.apache.coyote.http11.filters.GzipOutputFilter;
0038:        import org.apache.coyote.http11.filters.IdentityInputFilter;
0039:        import org.apache.coyote.http11.filters.IdentityOutputFilter;
0040:        import org.apache.coyote.http11.filters.SavedRequestInputFilter;
0041:        import org.apache.coyote.http11.filters.VoidInputFilter;
0042:        import org.apache.coyote.http11.filters.VoidOutputFilter;
0043:        import org.apache.tomcat.util.buf.Ascii;
0044:        import org.apache.tomcat.util.buf.ByteChunk;
0045:        import org.apache.tomcat.util.buf.HexUtils;
0046:        import org.apache.tomcat.util.buf.MessageBytes;
0047:        import org.apache.tomcat.util.http.FastHttpDateFormat;
0048:        import org.apache.tomcat.util.http.MimeHeaders;
0049:        import org.apache.tomcat.util.net.NioChannel;
0050:        import org.apache.tomcat.util.net.NioEndpoint;
0051:        import org.apache.tomcat.util.net.SSLSupport;
0052:        import org.apache.tomcat.util.net.SocketStatus;
0053:        import org.apache.tomcat.util.net.NioEndpoint.Handler.SocketState;
0054:        import org.apache.tomcat.util.res.StringManager;
0055:        import org.apache.tomcat.util.net.NioEndpoint.KeyAttachment;
0056:
0057:        /**
0058:         * Processes HTTP requests.
0059:         *
0060:         * @author Remy Maucherat
0061:         * @author Filip Hanik
0062:         */
0063:        public class Http11NioProcessor implements  ActionHook {
0064:
0065:            /**
0066:             * Logger.
0067:             */
0068:            protected static org.apache.juli.logging.Log log = org.apache.juli.logging.LogFactory
0069:                    .getLog(Http11NioProcessor.class);
0070:
0071:            /**
0072:             * The string manager for this package.
0073:             */
0074:            protected static StringManager sm = StringManager
0075:                    .getManager(Constants.Package);
0076:
0077:            /**
0078:             * SSL information.
0079:             */
0080:            protected SSLSupport sslSupport;
0081:
0082:            // ----------------------------------------------------------- Constructors
0083:
0084:            public Http11NioProcessor(int rxBufSize, int txBufSize,
0085:                    int maxHttpHeaderSize, NioEndpoint endpoint) {
0086:
0087:                this .endpoint = endpoint;
0088:
0089:                request = new Request();
0090:                int readTimeout = endpoint.getSoTimeout();
0091:                inputBuffer = new InternalNioInputBuffer(request,
0092:                        maxHttpHeaderSize, readTimeout);
0093:                request.setInputBuffer(inputBuffer);
0094:
0095:                response = new Response();
0096:                response.setHook(this );
0097:                outputBuffer = new InternalNioOutputBuffer(response,
0098:                        maxHttpHeaderSize, readTimeout);
0099:                response.setOutputBuffer(outputBuffer);
0100:                request.setResponse(response);
0101:
0102:                ssl = endpoint.isSSLEnabled();
0103:
0104:                initializeFilters();
0105:
0106:                // Cause loading of HexUtils
0107:                int foo = HexUtils.DEC[0];
0108:
0109:                // Cause loading of FastHttpDateFormat
0110:                FastHttpDateFormat.getCurrentDate();
0111:
0112:            }
0113:
0114:            // ----------------------------------------------------- Instance Variables
0115:
0116:            /**
0117:             * Associated adapter.
0118:             */
0119:            protected Adapter adapter = null;
0120:
0121:            /**
0122:             * Request object.
0123:             */
0124:            protected Request request = null;
0125:
0126:            /**
0127:             * Response object.
0128:             */
0129:            protected Response response = null;
0130:
0131:            /**
0132:             * Input.
0133:             */
0134:            protected InternalNioInputBuffer inputBuffer = null;
0135:
0136:            /**
0137:             * Output.
0138:             */
0139:            protected InternalNioOutputBuffer outputBuffer = null;
0140:
0141:            /**
0142:             * Error flag.
0143:             */
0144:            protected boolean error = false;
0145:
0146:            /**
0147:             * Keep-alive.
0148:             */
0149:            protected boolean keepAlive = true;
0150:
0151:            /**
0152:             * HTTP/1.1 flag.
0153:             */
0154:            protected boolean http11 = true;
0155:
0156:            /**
0157:             * HTTP/0.9 flag.
0158:             */
0159:            protected boolean http09 = false;
0160:
0161:            /**
0162:             * Sendfile data.
0163:             */
0164:            protected NioEndpoint.SendfileData sendfileData = null;
0165:
0166:            /**
0167:             * Comet used.
0168:             */
0169:            protected boolean comet = false;
0170:
0171:            /**
0172:             * Closed flag, a Comet async thread can 
0173:             * signal for this Nio processor to be closed and recycled instead
0174:             * of waiting for a timeout.
0175:             * Closed by HttpServletResponse.getWriter().close()
0176:             */
0177:            protected boolean cometClose = false;
0178:
0179:            /**
0180:             * Content delimitator for the request (if false, the connection will
0181:             * be closed at the end of the request).
0182:             */
0183:            protected boolean contentDelimitation = true;
0184:
0185:            /**
0186:             * Is there an expectation ?
0187:             */
0188:            protected boolean expectation = false;
0189:
0190:            /**
0191:             * List of restricted user agents.
0192:             */
0193:            protected Pattern[] restrictedUserAgents = null;
0194:
0195:            /**
0196:             * Maximum number of Keep-Alive requests to honor.
0197:             */
0198:            protected int maxKeepAliveRequests = -1;
0199:
0200:            /**
0201:             * SSL enabled ?
0202:             */
0203:            protected boolean ssl = false;
0204:
0205:            /**
0206:             * Socket associated with the current connection.
0207:             */
0208:            protected NioChannel socket = null;
0209:
0210:            /**
0211:             * Remote Address associated with the current connection.
0212:             */
0213:            protected String remoteAddr = null;
0214:
0215:            /**
0216:             * Remote Host associated with the current connection.
0217:             */
0218:            protected String remoteHost = null;
0219:
0220:            /**
0221:             * Local Host associated with the current connection.
0222:             */
0223:            protected String localName = null;
0224:
0225:            /**
0226:             * Local port to which the socket is connected
0227:             */
0228:            protected int localPort = -1;
0229:
0230:            /**
0231:             * Remote port to which the socket is connected
0232:             */
0233:            protected int remotePort = -1;
0234:
0235:            /**
0236:             * The local Host address.
0237:             */
0238:            protected String localAddr = null;
0239:
0240:            /**
0241:             * Maximum timeout on uploads. 5 minutes as in Apache HTTPD server.
0242:             */
0243:            protected int timeout = 300000;
0244:
0245:            /**
0246:             * Flag to disable setting a different time-out on uploads.
0247:             */
0248:            protected boolean disableUploadTimeout = false;
0249:
0250:            /**
0251:             * Allowed compression level.
0252:             */
0253:            protected int compressionLevel = 0;
0254:
0255:            /**
0256:             * Minimum contentsize to make compression.
0257:             */
0258:            protected int compressionMinSize = 2048;
0259:
0260:            /**
0261:             * Socket buffering.
0262:             */
0263:            protected int socketBuffer = -1;
0264:
0265:            /**
0266:             * Max save post size.
0267:             */
0268:            protected int maxSavePostSize = 4 * 1024;
0269:
0270:            /**
0271:             * List of user agents to not use gzip with
0272:             */
0273:            protected Pattern noCompressionUserAgents[] = null;
0274:
0275:            /**
0276:             * List of MIMES which could be gzipped
0277:             */
0278:            protected String[] compressableMimeTypes = { "text/html",
0279:                    "text/xml", "text/plain" };
0280:
0281:            /**
0282:             * Host name (used to avoid useless B2C conversion on the host name).
0283:             */
0284:            protected char[] hostNameC = new char[0];
0285:
0286:            /**
0287:             * Associated endpoint.
0288:             */
0289:            protected NioEndpoint endpoint;
0290:
0291:            /**
0292:             * Allow a customized the server header for the tin-foil hat folks.
0293:             */
0294:            protected String server = null;
0295:
0296:            // ------------------------------------------------------------- Properties
0297:
0298:            /**
0299:             * Return compression level.
0300:             */
0301:            public String getCompression() {
0302:                switch (compressionLevel) {
0303:                case 0:
0304:                    return "off";
0305:                case 1:
0306:                    return "on";
0307:                case 2:
0308:                    return "force";
0309:                }
0310:                return "off";
0311:            }
0312:
0313:            /**
0314:             * Set compression level.
0315:             */
0316:            public void setCompression(String compression) {
0317:                if (compression.equals("on")) {
0318:                    this .compressionLevel = 1;
0319:                } else if (compression.equals("force")) {
0320:                    this .compressionLevel = 2;
0321:                } else if (compression.equals("off")) {
0322:                    this .compressionLevel = 0;
0323:                } else {
0324:                    try {
0325:                        // Try to parse compression as an int, which would give the
0326:                        // minimum compression size
0327:                        compressionMinSize = Integer.parseInt(compression);
0328:                        this .compressionLevel = 1;
0329:                    } catch (Exception e) {
0330:                        this .compressionLevel = 0;
0331:                    }
0332:                }
0333:            }
0334:
0335:            /**
0336:             * Set Minimum size to trigger compression.
0337:             */
0338:            public void setCompressionMinSize(int compressionMinSize) {
0339:                this .compressionMinSize = compressionMinSize;
0340:            }
0341:
0342:            /**
0343:             * Add user-agent for which gzip compression didn't works
0344:             * The user agent String given will be exactly matched
0345:             * to the user-agent header submitted by the client.
0346:             *
0347:             * @param userAgent user-agent string
0348:             */
0349:            public void addNoCompressionUserAgent(String userAgent) {
0350:                try {
0351:                    Pattern nRule = Pattern.compile(userAgent);
0352:                    noCompressionUserAgents = addREArray(
0353:                            noCompressionUserAgents, nRule);
0354:                } catch (PatternSyntaxException pse) {
0355:                    log.error(sm.getString("http11processor.regexp.error",
0356:                            userAgent), pse);
0357:                }
0358:            }
0359:
0360:            /**
0361:             * Set no compression user agent list (this method is best when used with
0362:             * a large number of connectors, where it would be better to have all of
0363:             * them referenced a single array).
0364:             */
0365:            public void setNoCompressionUserAgents(
0366:                    Pattern[] noCompressionUserAgents) {
0367:                this .noCompressionUserAgents = noCompressionUserAgents;
0368:            }
0369:
0370:            /**
0371:             * Set no compression user agent list.
0372:             * List contains users agents separated by ',' :
0373:             *
0374:             * ie: "gorilla,desesplorer,tigrus"
0375:             */
0376:            public void setNoCompressionUserAgents(
0377:                    String noCompressionUserAgents) {
0378:                if (noCompressionUserAgents != null) {
0379:                    StringTokenizer st = new StringTokenizer(
0380:                            noCompressionUserAgents, ",");
0381:
0382:                    while (st.hasMoreTokens()) {
0383:                        addNoCompressionUserAgent(st.nextToken().trim());
0384:                    }
0385:                }
0386:            }
0387:
0388:            /**
0389:             * Add a mime-type which will be compressable
0390:             * The mime-type String will be exactly matched
0391:             * in the response mime-type header .
0392:             *
0393:             * @param mimeType mime-type string
0394:             */
0395:            public void addCompressableMimeType(String mimeType) {
0396:                compressableMimeTypes = addStringArray(compressableMimeTypes,
0397:                        mimeType);
0398:            }
0399:
0400:            /**
0401:             * Set compressable mime-type list (this method is best when used with
0402:             * a large number of connectors, where it would be better to have all of
0403:             * them referenced a single array).
0404:             */
0405:            public void setCompressableMimeTypes(String[] compressableMimeTypes) {
0406:                this .compressableMimeTypes = compressableMimeTypes;
0407:            }
0408:
0409:            /**
0410:             * Set compressable mime-type list
0411:             * List contains users agents separated by ',' :
0412:             *
0413:             * ie: "text/html,text/xml,text/plain"
0414:             */
0415:            public void setCompressableMimeTypes(String compressableMimeTypes) {
0416:                if (compressableMimeTypes != null) {
0417:                    StringTokenizer st = new StringTokenizer(
0418:                            compressableMimeTypes, ",");
0419:
0420:                    while (st.hasMoreTokens()) {
0421:                        addCompressableMimeType(st.nextToken().trim());
0422:                    }
0423:                }
0424:            }
0425:
0426:            /**
0427:             * Return the list of restricted user agents.
0428:             */
0429:            public String[] findCompressableMimeTypes() {
0430:                return (compressableMimeTypes);
0431:            }
0432:
0433:            // --------------------------------------------------------- Public Methods
0434:
0435:            /**
0436:             * Add input or output filter.
0437:             *
0438:             * @param className class name of the filter
0439:             */
0440:            protected void addFilter(String className) {
0441:                try {
0442:                    Class clazz = Class.forName(className);
0443:                    Object obj = clazz.newInstance();
0444:                    if (obj instanceof  InputFilter) {
0445:                        inputBuffer.addFilter((InputFilter) obj);
0446:                    } else if (obj instanceof  OutputFilter) {
0447:                        outputBuffer.addFilter((OutputFilter) obj);
0448:                    } else {
0449:                        log.warn(sm.getString("http11processor.filter.unknown",
0450:                                className));
0451:                    }
0452:                } catch (Exception e) {
0453:                    log.error(sm.getString("http11processor.filter.error",
0454:                            className), e);
0455:                }
0456:            }
0457:
0458:            /**
0459:             * General use method
0460:             *
0461:             * @param sArray the StringArray
0462:             * @param value string
0463:             */
0464:            private String[] addStringArray(String sArray[], String value) {
0465:                String[] result = null;
0466:                if (sArray == null) {
0467:                    result = new String[1];
0468:                    result[0] = value;
0469:                } else {
0470:                    result = new String[sArray.length + 1];
0471:                    for (int i = 0; i < sArray.length; i++)
0472:                        result[i] = sArray[i];
0473:                    result[sArray.length] = value;
0474:                }
0475:                return result;
0476:            }
0477:
0478:            /**
0479:             * General use method
0480:             *
0481:             * @param rArray the REArray
0482:             * @param value Obj
0483:             */
0484:            private Pattern[] addREArray(Pattern rArray[], Pattern value) {
0485:                Pattern[] result = null;
0486:                if (rArray == null) {
0487:                    result = new Pattern[1];
0488:                    result[0] = value;
0489:                } else {
0490:                    result = new Pattern[rArray.length + 1];
0491:                    for (int i = 0; i < rArray.length; i++)
0492:                        result[i] = rArray[i];
0493:                    result[rArray.length] = value;
0494:                }
0495:                return result;
0496:            }
0497:
0498:            /**
0499:             * General use method
0500:             *
0501:             * @param sArray the StringArray
0502:             * @param value string
0503:             */
0504:            private boolean inStringArray(String sArray[], String value) {
0505:                for (int i = 0; i < sArray.length; i++) {
0506:                    if (sArray[i].equals(value)) {
0507:                        return true;
0508:                    }
0509:                }
0510:                return false;
0511:            }
0512:
0513:            /**
0514:             * Checks if any entry in the string array starts with the specified value
0515:             *
0516:             * @param sArray the StringArray
0517:             * @param value string
0518:             */
0519:            private boolean startsWithStringArray(String sArray[], String value) {
0520:                if (value == null)
0521:                    return false;
0522:                for (int i = 0; i < sArray.length; i++) {
0523:                    if (value.startsWith(sArray[i])) {
0524:                        return true;
0525:                    }
0526:                }
0527:                return false;
0528:            }
0529:
0530:            /**
0531:             * Add restricted user-agent (which will downgrade the connector
0532:             * to HTTP/1.0 mode). The user agent String given will be matched
0533:             * via regexp to the user-agent header submitted by the client.
0534:             *
0535:             * @param userAgent user-agent string
0536:             */
0537:            public void addRestrictedUserAgent(String userAgent) {
0538:                try {
0539:                    Pattern nRule = Pattern.compile(userAgent);
0540:                    restrictedUserAgents = addREArray(restrictedUserAgents,
0541:                            nRule);
0542:                } catch (PatternSyntaxException pse) {
0543:                    log.error(sm.getString("http11processor.regexp.error",
0544:                            userAgent), pse);
0545:                }
0546:            }
0547:
0548:            /**
0549:             * Set restricted user agent list (this method is best when used with
0550:             * a large number of connectors, where it would be better to have all of
0551:             * them referenced a single array).
0552:             */
0553:            public void setRestrictedUserAgents(Pattern[] restrictedUserAgents) {
0554:                this .restrictedUserAgents = restrictedUserAgents;
0555:            }
0556:
0557:            /**
0558:             * Set restricted user agent list (which will downgrade the connector
0559:             * to HTTP/1.0 mode). List contains users agents separated by ',' :
0560:             *
0561:             * ie: "gorilla,desesplorer,tigrus"
0562:             */
0563:            public void setRestrictedUserAgents(String restrictedUserAgents) {
0564:                if (restrictedUserAgents != null) {
0565:                    StringTokenizer st = new StringTokenizer(
0566:                            restrictedUserAgents, ",");
0567:                    while (st.hasMoreTokens()) {
0568:                        addRestrictedUserAgent(st.nextToken().trim());
0569:                    }
0570:                }
0571:            }
0572:
0573:            /**
0574:             * Return the list of restricted user agents.
0575:             */
0576:            public String[] findRestrictedUserAgents() {
0577:                String[] sarr = new String[restrictedUserAgents.length];
0578:
0579:                for (int i = 0; i < restrictedUserAgents.length; i++)
0580:                    sarr[i] = restrictedUserAgents[i].toString();
0581:
0582:                return (sarr);
0583:            }
0584:
0585:            /**
0586:             * Set the maximum number of Keep-Alive requests to honor.
0587:             * This is to safeguard from DoS attacks.  Setting to a negative
0588:             * value disables the check.
0589:             */
0590:            public void setMaxKeepAliveRequests(int mkar) {
0591:                maxKeepAliveRequests = mkar;
0592:            }
0593:
0594:            /**
0595:             * Return the number of Keep-Alive requests that we will honor.
0596:             */
0597:            public int getMaxKeepAliveRequests() {
0598:                return maxKeepAliveRequests;
0599:            }
0600:
0601:            /**
0602:             * Set the maximum size of a POST which will be buffered in SSL mode.
0603:             */
0604:            public void setMaxSavePostSize(int msps) {
0605:                maxSavePostSize = msps;
0606:            }
0607:
0608:            /**
0609:             * Return the maximum size of a POST which will be buffered in SSL mode.
0610:             */
0611:            public int getMaxSavePostSize() {
0612:                return maxSavePostSize;
0613:            }
0614:
0615:            /**
0616:             * Set the flag to control upload time-outs.
0617:             */
0618:            public void setDisableUploadTimeout(boolean isDisabled) {
0619:                disableUploadTimeout = isDisabled;
0620:            }
0621:
0622:            /**
0623:             * Get the flag that controls upload time-outs.
0624:             */
0625:            public boolean getDisableUploadTimeout() {
0626:                return disableUploadTimeout;
0627:            }
0628:
0629:            /**
0630:             * Set the socket buffer flag.
0631:             */
0632:            public void setSocketBuffer(int socketBuffer) {
0633:                this .socketBuffer = socketBuffer;
0634:                outputBuffer.setSocketBuffer(socketBuffer);
0635:            }
0636:
0637:            /**
0638:             * Get the socket buffer flag.
0639:             */
0640:            public int getSocketBuffer() {
0641:                return socketBuffer;
0642:            }
0643:
0644:            /**
0645:             * Set the upload timeout.
0646:             */
0647:            public void setTimeout(int timeouts) {
0648:                timeout = timeouts;
0649:            }
0650:
0651:            /**
0652:             * Get the upload timeout.
0653:             */
0654:            public int getTimeout() {
0655:                return timeout;
0656:            }
0657:
0658:            /**
0659:             * Set the server header name.
0660:             */
0661:            public void setServer(String server) {
0662:                if (server == null || server.equals("")) {
0663:                    this .server = null;
0664:                } else {
0665:                    this .server = server;
0666:                }
0667:            }
0668:
0669:            /**
0670:             * Get the server header name.
0671:             */
0672:            public String getServer() {
0673:                return server;
0674:            }
0675:
0676:            /** Get the request associated with this processor.
0677:             *
0678:             * @return The request
0679:             */
0680:            public Request getRequest() {
0681:                return request;
0682:            }
0683:
0684:            /**
0685:             * Process pipelined HTTP requests using the specified input and output
0686:             * streams.
0687:             *
0688:             * @throws IOException error during an I/O operation
0689:             */
0690:            public SocketState event(SocketStatus status) throws IOException {
0691:
0692:                RequestInfo rp = request.getRequestProcessor();
0693:
0694:                try {
0695:                    rp.setStage(org.apache.coyote.Constants.STAGE_SERVICE);
0696:                    error = !adapter.event(request, response, status);
0697:                    if (!error) {
0698:                        NioEndpoint.KeyAttachment attach = (NioEndpoint.KeyAttachment) socket
0699:                                .getAttachment(false);
0700:                        if (attach != null) {
0701:                            attach.setComet(comet);
0702:                            if (comet) {
0703:                                Integer comettimeout = (Integer) request
0704:                                        .getAttribute("org.apache.tomcat.comet.timeout");
0705:                                if (comettimeout != null)
0706:                                    attach.setTimeout(comettimeout.longValue());
0707:                            } else {
0708:                                //reset the timeout
0709:                                attach.setTimeout(endpoint
0710:                                        .getSocketProperties().getSoTimeout());
0711:                            }
0712:
0713:                        }
0714:                    }
0715:                } catch (InterruptedIOException e) {
0716:                    error = true;
0717:                } catch (Throwable t) {
0718:                    log.error(sm.getString("http11processor.request.process"),
0719:                            t);
0720:                    // 500 - Internal Server Error
0721:                    response.setStatus(500);
0722:                    error = true;
0723:                }
0724:
0725:                rp.setStage(org.apache.coyote.Constants.STAGE_ENDED);
0726:
0727:                if (error) {
0728:                    recycle();
0729:                    return SocketState.CLOSED;
0730:                } else if (!comet) {
0731:                    recycle();
0732:                    return SocketState.OPEN;
0733:                } else {
0734:                    return SocketState.LONG;
0735:                }
0736:            }
0737:
0738:            /**
0739:             * Process pipelined HTTP requests using the specified input and output
0740:             * streams.
0741:             *
0742:             * @throws IOException error during an I/O operation
0743:             */
0744:            public SocketState process(NioChannel socket) throws IOException {
0745:                RequestInfo rp = request.getRequestProcessor();
0746:                rp.setStage(org.apache.coyote.Constants.STAGE_PARSE);
0747:
0748:                // Set the remote address
0749:                remoteAddr = null;
0750:                remoteHost = null;
0751:                localAddr = null;
0752:                localName = null;
0753:                remotePort = -1;
0754:                localPort = -1;
0755:
0756:                // Setting up the socket
0757:                this .socket = socket;
0758:                inputBuffer.setSocket(socket);
0759:                outputBuffer.setSocket(socket);
0760:                inputBuffer.setSelectorPool(endpoint.getSelectorPool());
0761:                outputBuffer.setSelectorPool(endpoint.getSelectorPool());
0762:
0763:                // Error flag
0764:                error = false;
0765:                keepAlive = true;
0766:                comet = false;
0767:
0768:                int keepAliveLeft = maxKeepAliveRequests;
0769:                long soTimeout = endpoint.getSoTimeout();
0770:
0771:                int limit = 0;
0772:
0773:                boolean keptAlive = false;
0774:                boolean openSocket = false;
0775:                boolean recycle = true;
0776:                while (!error && keepAlive && !comet) {
0777:
0778:                    // Parsing the request header
0779:                    try {
0780:                        if (!disableUploadTimeout && keptAlive && soTimeout > 0) {
0781:                            socket.getIOChannel().socket().setSoTimeout(
0782:                                    (int) soTimeout);
0783:                            inputBuffer.readTimeout = soTimeout;
0784:                        }
0785:                        if (!inputBuffer.parseRequestLine(keptAlive
0786:                                && (endpoint.getCurrentThreadsBusy() >= limit))) {
0787:                            // This means that no data is available right now
0788:                            // (long keepalive), so that the processor should be recycled
0789:                            // and the method should return true
0790:                            openSocket = true;
0791:                            // Add the socket to the poller
0792:                            socket.getPoller().add(socket);
0793:                            break;
0794:                        }
0795:                        keptAlive = true;
0796:                        if (!inputBuffer.parseHeaders()) {
0797:                            openSocket = true;
0798:                            socket.getPoller().add(socket);
0799:                            recycle = false;
0800:                            break;
0801:                        }
0802:                        request.setStartTime(System.currentTimeMillis());
0803:                        if (!disableUploadTimeout) { //only for body, not for request headers
0804:                            socket.getIOChannel().socket().setSoTimeout(
0805:                                    (int) timeout);
0806:                            inputBuffer.readTimeout = soTimeout;
0807:                        }
0808:                    } catch (IOException e) {
0809:                        error = true;
0810:                        break;
0811:                    } catch (Throwable t) {
0812:                        if (log.isDebugEnabled()) {
0813:                            log.debug(sm
0814:                                    .getString("http11processor.header.parse"),
0815:                                    t);
0816:                        }
0817:                        // 400 - Bad Request
0818:                        response.setStatus(400);
0819:                        error = true;
0820:                    }
0821:
0822:                    // Setting up filters, and parse some request headers
0823:                    rp.setStage(org.apache.coyote.Constants.STAGE_PREPARE);
0824:                    try {
0825:                        prepareRequest();
0826:                    } catch (Throwable t) {
0827:                        if (log.isDebugEnabled()) {
0828:                            log
0829:                                    .debug(
0830:                                            sm
0831:                                                    .getString("http11processor.request.prepare"),
0832:                                            t);
0833:                        }
0834:                        // 400 - Internal Server Error
0835:                        response.setStatus(400);
0836:                        error = true;
0837:                    }
0838:
0839:                    if (maxKeepAliveRequests > 0 && --keepAliveLeft == 0)
0840:                        keepAlive = false;
0841:
0842:                    // Process the request in the adapter
0843:                    if (!error) {
0844:                        try {
0845:                            rp
0846:                                    .setStage(org.apache.coyote.Constants.STAGE_SERVICE);
0847:                            adapter.service(request, response);
0848:                            // Handle when the response was committed before a serious
0849:                            // error occurred.  Throwing a ServletException should both
0850:                            // set the status to 500 and set the errorException.
0851:                            // If we fail here, then the response is likely already
0852:                            // committed, so we can't try and set headers.
0853:                            if (keepAlive && !error) { // Avoid checking twice.
0854:                                error = response.getErrorException() != null
0855:                                        || statusDropsConnection(response
0856:                                                .getStatus());
0857:                            }
0858:                            // Comet support
0859:                            SelectionKey key = socket.getIOChannel().keyFor(
0860:                                    socket.getPoller().getSelector());
0861:                            if (key != null) {
0862:                                NioEndpoint.KeyAttachment attach = (NioEndpoint.KeyAttachment) key
0863:                                        .attachment();
0864:                                if (attach != null) {
0865:                                    attach.setComet(comet);
0866:                                    if (comet) {
0867:                                        Integer comettimeout = (Integer) request
0868:                                                .getAttribute("org.apache.tomcat.comet.timeout");
0869:                                        if (comettimeout != null)
0870:                                            attach.setTimeout(comettimeout
0871:                                                    .longValue());
0872:                                    }
0873:                                }
0874:                            }
0875:                        } catch (InterruptedIOException e) {
0876:                            error = true;
0877:                        } catch (Throwable t) {
0878:                            log
0879:                                    .error(
0880:                                            sm
0881:                                                    .getString("http11processor.request.process"),
0882:                                            t);
0883:                            // 500 - Internal Server Error
0884:                            response.setStatus(500);
0885:                            error = true;
0886:                        }
0887:                    }
0888:
0889:                    // Finish the handling of the request
0890:                    if (!comet) {
0891:                        endRequest();
0892:                    }
0893:
0894:                    // If there was an error, make sure the request is counted as
0895:                    // and error, and update the statistics counter
0896:                    if (error) {
0897:                        response.setStatus(500);
0898:                    }
0899:                    request.updateCounters();
0900:
0901:                    if (!comet) {
0902:                        // Next request
0903:                        inputBuffer.nextRequest();
0904:                        outputBuffer.nextRequest();
0905:                    }
0906:
0907:                    // Do sendfile as needed: add socket to sendfile and end
0908:                    if (sendfileData != null && !error) {
0909:                        KeyAttachment ka = (KeyAttachment) socket
0910:                                .getAttachment(false);
0911:                        ka.setSendfileData(sendfileData);
0912:                        sendfileData.keepAlive = keepAlive;
0913:                        SelectionKey key = socket.getIOChannel().keyFor(
0914:                                socket.getPoller().getSelector());
0915:                        //do the first write on this thread, might as well
0916:                        openSocket = socket.getPoller().processSendfile(key,
0917:                                ka, true);
0918:                        break;
0919:                    }
0920:
0921:                    rp.setStage(org.apache.coyote.Constants.STAGE_KEEPALIVE);
0922:
0923:                }
0924:
0925:                rp.setStage(org.apache.coyote.Constants.STAGE_ENDED);
0926:
0927:                if (comet) {
0928:                    if (error) {
0929:                        recycle();
0930:                        return SocketState.CLOSED;
0931:                    } else {
0932:                        return SocketState.LONG;
0933:                    }
0934:                } else {
0935:                    if (recycle)
0936:                        recycle();
0937:                    return (openSocket) ? SocketState.OPEN : SocketState.CLOSED;
0938:                }
0939:
0940:            }
0941:
0942:            public void endRequest() {
0943:
0944:                // Finish the handling of the request
0945:                try {
0946:                    inputBuffer.endRequest();
0947:                } catch (IOException e) {
0948:                    error = true;
0949:                } catch (Throwable t) {
0950:                    log
0951:                            .error(
0952:                                    sm
0953:                                            .getString("http11processor.request.finish"),
0954:                                    t);
0955:                    // 500 - Internal Server Error
0956:                    response.setStatus(500);
0957:                    error = true;
0958:                }
0959:                try {
0960:                    outputBuffer.endRequest();
0961:                } catch (IOException e) {
0962:                    error = true;
0963:                } catch (Throwable t) {
0964:                    log.error(sm.getString("http11processor.response.finish"),
0965:                            t);
0966:                    error = true;
0967:                }
0968:
0969:            }
0970:
0971:            public void recycle() {
0972:                inputBuffer.recycle();
0973:                outputBuffer.recycle();
0974:                this .socket = null;
0975:                this .cometClose = false;
0976:                this .comet = false;
0977:            }
0978:
0979:            // ----------------------------------------------------- ActionHook Methods
0980:
0981:            /**
0982:             * Send an action to the connector.
0983:             *
0984:             * @param actionCode Type of the action
0985:             * @param param Action parameter
0986:             */
0987:            public void action(ActionCode actionCode, Object param) {
0988:
0989:                if (actionCode == ActionCode.ACTION_COMMIT) {
0990:                    // Commit current response
0991:
0992:                    if (response.isCommitted())
0993:                        return;
0994:
0995:                    // Validate and write response headers
0996:
0997:                    try {
0998:                        prepareResponse();
0999:                        outputBuffer.commit();
1000:                    } catch (IOException e) {
1001:                        // Set error flag
1002:                        error = true;
1003:                    }
1004:
1005:                } else if (actionCode == ActionCode.ACTION_ACK) {
1006:
1007:                    // Acknowlege request
1008:
1009:                    // Send a 100 status back if it makes sense (response not committed
1010:                    // yet, and client specified an expectation for 100-continue)
1011:
1012:                    if ((response.isCommitted()) || !expectation)
1013:                        return;
1014:
1015:                    inputBuffer.setSwallowInput(true);
1016:                    try {
1017:                        outputBuffer.sendAck();
1018:                    } catch (IOException e) {
1019:                        // Set error flag
1020:                        error = true;
1021:                    }
1022:
1023:                } else if (actionCode == ActionCode.ACTION_CLIENT_FLUSH) {
1024:
1025:                    try {
1026:                        outputBuffer.flush();
1027:                    } catch (IOException e) {
1028:                        // Set error flag
1029:                        error = true;
1030:                        response.setErrorException(e);
1031:                    }
1032:
1033:                } else if (actionCode == ActionCode.ACTION_CLOSE) {
1034:                    // Close
1035:
1036:                    // End the processing of the current request, and stop any further
1037:                    // transactions with the client
1038:
1039:                    comet = false;
1040:                    cometClose = true;
1041:                    SelectionKey key = socket.getIOChannel().keyFor(
1042:                            socket.getPoller().getSelector());
1043:                    if (key != null) {
1044:                        NioEndpoint.KeyAttachment attach = (NioEndpoint.KeyAttachment) key
1045:                                .attachment();
1046:                        if (attach != null && attach.getComet()) {
1047:                            //if this is a comet connection
1048:                            //then execute the connection closure at the next selector loop
1049:                            request.getAttributes().remove(
1050:                                    "org.apache.tomcat.comet.timeout");
1051:                            //attach.setTimeout(5000); //force a cleanup in 5 seconds
1052:                            //attach.setError(true); //this has caused concurrency errors
1053:                        }
1054:                    }
1055:
1056:                    try {
1057:                        outputBuffer.endRequest();
1058:                    } catch (IOException e) {
1059:                        // Set error flag
1060:                        error = true;
1061:                    }
1062:
1063:                } else if (actionCode == ActionCode.ACTION_RESET) {
1064:
1065:                    // Reset response
1066:
1067:                    // Note: This must be called before the response is committed
1068:
1069:                    outputBuffer.reset();
1070:
1071:                } else if (actionCode == ActionCode.ACTION_CUSTOM) {
1072:
1073:                    // Do nothing
1074:
1075:                } else if (actionCode == ActionCode.ACTION_REQ_HOST_ADDR_ATTRIBUTE) {
1076:
1077:                    // Get remote host address
1078:                    if ((remoteAddr == null) && (socket != null)) {
1079:                        InetAddress inetAddr = socket.getIOChannel().socket()
1080:                                .getInetAddress();
1081:                        if (inetAddr != null) {
1082:                            remoteAddr = inetAddr.getHostAddress();
1083:                        }
1084:                    }
1085:                    request.remoteAddr().setString(remoteAddr);
1086:
1087:                } else if (actionCode == ActionCode.ACTION_REQ_LOCAL_NAME_ATTRIBUTE) {
1088:
1089:                    // Get local host name
1090:                    if ((localName == null) && (socket != null)) {
1091:                        InetAddress inetAddr = socket.getIOChannel().socket()
1092:                                .getLocalAddress();
1093:                        if (inetAddr != null) {
1094:                            localName = inetAddr.getHostName();
1095:                        }
1096:                    }
1097:                    request.localName().setString(localName);
1098:
1099:                } else if (actionCode == ActionCode.ACTION_REQ_HOST_ATTRIBUTE) {
1100:
1101:                    // Get remote host name
1102:                    if ((remoteHost == null) && (socket != null)) {
1103:                        InetAddress inetAddr = socket.getIOChannel().socket()
1104:                                .getInetAddress();
1105:                        if (inetAddr != null) {
1106:                            remoteHost = inetAddr.getHostName();
1107:                        }
1108:                        if (remoteHost == null) {
1109:                            if (remoteAddr != null) {
1110:                                remoteHost = remoteAddr;
1111:                            } else { // all we can do is punt
1112:                                request.remoteHost().recycle();
1113:                            }
1114:                        }
1115:                    }
1116:                    request.remoteHost().setString(remoteHost);
1117:
1118:                } else if (actionCode == ActionCode.ACTION_REQ_LOCAL_ADDR_ATTRIBUTE) {
1119:
1120:                    if (localAddr == null)
1121:                        localAddr = socket.getIOChannel().socket()
1122:                                .getLocalAddress().getHostAddress();
1123:
1124:                    request.localAddr().setString(localAddr);
1125:
1126:                } else if (actionCode == ActionCode.ACTION_REQ_REMOTEPORT_ATTRIBUTE) {
1127:
1128:                    if ((remotePort == -1) && (socket != null)) {
1129:                        remotePort = socket.getIOChannel().socket().getPort();
1130:                    }
1131:                    request.setRemotePort(remotePort);
1132:
1133:                } else if (actionCode == ActionCode.ACTION_REQ_LOCALPORT_ATTRIBUTE) {
1134:
1135:                    if ((localPort == -1) && (socket != null)) {
1136:                        localPort = socket.getIOChannel().socket()
1137:                                .getLocalPort();
1138:                    }
1139:                    request.setLocalPort(localPort);
1140:
1141:                } else if (actionCode == ActionCode.ACTION_REQ_SSL_ATTRIBUTE) {
1142:
1143:                    try {
1144:                        if (sslSupport != null) {
1145:                            Object sslO = sslSupport.getCipherSuite();
1146:                            if (sslO != null)
1147:                                request.setAttribute(
1148:                                        SSLSupport.CIPHER_SUITE_KEY, sslO);
1149:                            sslO = sslSupport.getPeerCertificateChain(false);
1150:                            if (sslO != null)
1151:                                request.setAttribute(
1152:                                        SSLSupport.CERTIFICATE_KEY, sslO);
1153:                            sslO = sslSupport.getKeySize();
1154:                            if (sslO != null)
1155:                                request.setAttribute(SSLSupport.KEY_SIZE_KEY,
1156:                                        sslO);
1157:                            sslO = sslSupport.getSessionId();
1158:                            if (sslO != null)
1159:                                request.setAttribute(SSLSupport.SESSION_ID_KEY,
1160:                                        sslO);
1161:                        }
1162:                    } catch (Exception e) {
1163:                        log.warn(sm.getString("http11processor.socket.ssl"), e);
1164:                    }
1165:
1166:                } else if (actionCode == ActionCode.ACTION_REQ_SSL_CERTIFICATE) {
1167:
1168:                    if (sslSupport != null) {
1169:                        /*
1170:                         * Consume and buffer the request body, so that it does not
1171:                         * interfere with the client's handshake messages
1172:                         */
1173:                        InputFilter[] inputFilters = inputBuffer.getFilters();
1174:                        ((BufferedInputFilter) inputFilters[Constants.BUFFERED_FILTER])
1175:                                .setLimit(maxSavePostSize);
1176:                        inputBuffer
1177:                                .addActiveFilter(inputFilters[Constants.BUFFERED_FILTER]);
1178:                        try {
1179:                            Object sslO = sslSupport
1180:                                    .getPeerCertificateChain(true);
1181:                            if (sslO != null) {
1182:                                request.setAttribute(
1183:                                        SSLSupport.CERTIFICATE_KEY, sslO);
1184:                            }
1185:                        } catch (Exception e) {
1186:                            log.warn(
1187:                                    sm.getString("http11processor.socket.ssl"),
1188:                                    e);
1189:                        }
1190:                    }
1191:
1192:                } else if (actionCode == ActionCode.ACTION_REQ_SET_BODY_REPLAY) {
1193:                    ByteChunk body = (ByteChunk) param;
1194:
1195:                    InputFilter savedBody = new SavedRequestInputFilter(body);
1196:                    savedBody.setRequest(request);
1197:
1198:                    InternalNioInputBuffer internalBuffer = (InternalNioInputBuffer) request
1199:                            .getInputBuffer();
1200:                    internalBuffer.addActiveFilter(savedBody);
1201:
1202:                } else if (actionCode == ActionCode.ACTION_AVAILABLE) {
1203:                    request.setAvailable(inputBuffer.available());
1204:                } else if (actionCode == ActionCode.ACTION_COMET_BEGIN) {
1205:                    comet = true;
1206:                } else if (actionCode == ActionCode.ACTION_COMET_END) {
1207:                    comet = false;
1208:                }
1209:
1210:            }
1211:
1212:            // ------------------------------------------------------ Connector Methods
1213:
1214:            /**
1215:             * Set the associated adapter.
1216:             *
1217:             * @param adapter the new adapter
1218:             */
1219:            public void setAdapter(Adapter adapter) {
1220:                this .adapter = adapter;
1221:            }
1222:
1223:            public void setSslSupport(SSLSupport sslSupport) {
1224:                this .sslSupport = sslSupport;
1225:            }
1226:
1227:            /**
1228:             * Get the associated adapter.
1229:             *
1230:             * @return the associated adapter
1231:             */
1232:            public Adapter getAdapter() {
1233:                return adapter;
1234:            }
1235:
1236:            public SSLSupport getSslSupport() {
1237:                return sslSupport;
1238:            }
1239:
1240:            // ------------------------------------------------------ Protected Methods
1241:
1242:            /**
1243:             * After reading the request headers, we have to setup the request filters.
1244:             */
1245:            protected void prepareRequest() {
1246:
1247:                http11 = true;
1248:                http09 = false;
1249:                contentDelimitation = false;
1250:                expectation = false;
1251:                sendfileData = null;
1252:                if (ssl) {
1253:                    request.scheme().setString("https");
1254:                }
1255:                MessageBytes protocolMB = request.protocol();
1256:                if (protocolMB.equals(Constants.HTTP_11)) {
1257:                    http11 = true;
1258:                    protocolMB.setString(Constants.HTTP_11);
1259:                } else if (protocolMB.equals(Constants.HTTP_10)) {
1260:                    http11 = false;
1261:                    keepAlive = false;
1262:                    protocolMB.setString(Constants.HTTP_10);
1263:                } else if (protocolMB.equals("")) {
1264:                    // HTTP/0.9
1265:                    http09 = true;
1266:                    http11 = false;
1267:                    keepAlive = false;
1268:                } else {
1269:                    // Unsupported protocol
1270:                    http11 = false;
1271:                    error = true;
1272:                    // Send 505; Unsupported HTTP version
1273:                    response.setStatus(505);
1274:                }
1275:
1276:                MessageBytes methodMB = request.method();
1277:                if (methodMB.equals(Constants.GET)) {
1278:                    methodMB.setString(Constants.GET);
1279:                } else if (methodMB.equals(Constants.POST)) {
1280:                    methodMB.setString(Constants.POST);
1281:                }
1282:
1283:                MimeHeaders headers = request.getMimeHeaders();
1284:
1285:                // Check connection header
1286:                MessageBytes connectionValueMB = headers.getValue("connection");
1287:                if (connectionValueMB != null) {
1288:                    ByteChunk connectionValueBC = connectionValueMB
1289:                            .getByteChunk();
1290:                    if (findBytes(connectionValueBC, Constants.CLOSE_BYTES) != -1) {
1291:                        keepAlive = false;
1292:                    } else if (findBytes(connectionValueBC,
1293:                            Constants.KEEPALIVE_BYTES) != -1) {
1294:                        keepAlive = true;
1295:                    }
1296:                }
1297:
1298:                MessageBytes expectMB = null;
1299:                if (http11)
1300:                    expectMB = headers.getValue("expect");
1301:                if ((expectMB != null)
1302:                        && (expectMB.indexOfIgnoreCase("100-continue", 0) != -1)) {
1303:                    inputBuffer.setSwallowInput(false);
1304:                    expectation = true;
1305:                }
1306:
1307:                // Check user-agent header
1308:                if ((restrictedUserAgents != null) && ((http11) || (keepAlive))) {
1309:                    MessageBytes userAgentValueMB = headers
1310:                            .getValue("user-agent");
1311:                    // Check in the restricted list, and adjust the http11
1312:                    // and keepAlive flags accordingly
1313:                    if (userAgentValueMB != null) {
1314:                        String userAgentValue = userAgentValueMB.toString();
1315:                        for (int i = 0; i < restrictedUserAgents.length; i++) {
1316:                            if (restrictedUserAgents[i].matcher(userAgentValue)
1317:                                    .matches()) {
1318:                                http11 = false;
1319:                                keepAlive = false;
1320:                                break;
1321:                            }
1322:                        }
1323:                    }
1324:                }
1325:
1326:                // Check for a full URI (including protocol://host:port/)
1327:                ByteChunk uriBC = request.requestURI().getByteChunk();
1328:                if (uriBC.startsWithIgnoreCase("http", 0)) {
1329:
1330:                    int pos = uriBC.indexOf("://", 0, 3, 4);
1331:                    int uriBCStart = uriBC.getStart();
1332:                    int slashPos = -1;
1333:                    if (pos != -1) {
1334:                        byte[] uriB = uriBC.getBytes();
1335:                        slashPos = uriBC.indexOf('/', pos + 3);
1336:                        if (slashPos == -1) {
1337:                            slashPos = uriBC.getLength();
1338:                            // Set URI as "/"
1339:                            request.requestURI().setBytes(uriB,
1340:                                    uriBCStart + pos + 1, 1);
1341:                        } else {
1342:                            request.requestURI().setBytes(uriB,
1343:                                    uriBCStart + slashPos,
1344:                                    uriBC.getLength() - slashPos);
1345:                        }
1346:                        MessageBytes hostMB = headers.setValue("host");
1347:                        hostMB.setBytes(uriB, uriBCStart + pos + 3, slashPos
1348:                                - pos - 3);
1349:                    }
1350:
1351:                }
1352:
1353:                // Input filter setup
1354:                InputFilter[] inputFilters = inputBuffer.getFilters();
1355:
1356:                // Parse transfer-encoding header
1357:                MessageBytes transferEncodingValueMB = null;
1358:                if (http11)
1359:                    transferEncodingValueMB = headers
1360:                            .getValue("transfer-encoding");
1361:                if (transferEncodingValueMB != null) {
1362:                    String transferEncodingValue = transferEncodingValueMB
1363:                            .toString();
1364:                    // Parse the comma separated list. "identity" codings are ignored
1365:                    int startPos = 0;
1366:                    int commaPos = transferEncodingValue.indexOf(',');
1367:                    String encodingName = null;
1368:                    while (commaPos != -1) {
1369:                        encodingName = transferEncodingValue.substring(
1370:                                startPos, commaPos).toLowerCase().trim();
1371:                        if (!addInputFilter(inputFilters, encodingName)) {
1372:                            // Unsupported transfer encoding
1373:                            error = true;
1374:                            // 501 - Unimplemented
1375:                            response.setStatus(501);
1376:                        }
1377:                        startPos = commaPos + 1;
1378:                        commaPos = transferEncodingValue.indexOf(',', startPos);
1379:                    }
1380:                    encodingName = transferEncodingValue.substring(startPos)
1381:                            .toLowerCase().trim();
1382:                    if (!addInputFilter(inputFilters, encodingName)) {
1383:                        // Unsupported transfer encoding
1384:                        error = true;
1385:                        // 501 - Unimplemented
1386:                        response.setStatus(501);
1387:                    }
1388:                }
1389:
1390:                // Parse content-length header
1391:                long contentLength = request.getContentLengthLong();
1392:                if (contentLength >= 0 && !contentDelimitation) {
1393:                    inputBuffer
1394:                            .addActiveFilter(inputFilters[Constants.IDENTITY_FILTER]);
1395:                    contentDelimitation = true;
1396:                }
1397:
1398:                MessageBytes valueMB = headers.getValue("host");
1399:
1400:                // Check host header
1401:                if (http11 && (valueMB == null)) {
1402:                    error = true;
1403:                    // 400 - Bad request
1404:                    response.setStatus(400);
1405:                }
1406:
1407:                parseHost(valueMB);
1408:
1409:                if (!contentDelimitation) {
1410:                    // If there's no content length 
1411:                    // (broken HTTP/1.0 or HTTP/1.1), assume
1412:                    // the client is not broken and didn't send a body
1413:                    inputBuffer
1414:                            .addActiveFilter(inputFilters[Constants.VOID_FILTER]);
1415:                    contentDelimitation = true;
1416:                }
1417:
1418:                // Advertise sendfile support through a request attribute
1419:                if (endpoint.getUseSendfile())
1420:                    request.setAttribute("org.apache.tomcat.sendfile.support",
1421:                            Boolean.TRUE);
1422:                // Advertise comet support through a request attribute
1423:                request.setAttribute("org.apache.tomcat.comet.support",
1424:                        Boolean.TRUE);
1425:                // Advertise comet timeout support
1426:                request.setAttribute("org.apache.tomcat.comet.timeout.support",
1427:                        Boolean.TRUE);
1428:
1429:            }
1430:
1431:            /**
1432:             * Parse host.
1433:             */
1434:            public void parseHost(MessageBytes valueMB) {
1435:
1436:                if (valueMB == null || valueMB.isNull()) {
1437:                    // HTTP/1.0
1438:                    // Default is what the socket tells us. Overriden if a host is
1439:                    // found/parsed
1440:                    request.setServerPort(endpoint.getPort());
1441:                    return;
1442:                }
1443:
1444:                ByteChunk valueBC = valueMB.getByteChunk();
1445:                byte[] valueB = valueBC.getBytes();
1446:                int valueL = valueBC.getLength();
1447:                int valueS = valueBC.getStart();
1448:                int colonPos = -1;
1449:                if (hostNameC.length < valueL) {
1450:                    hostNameC = new char[valueL];
1451:                }
1452:
1453:                boolean ipv6 = (valueB[valueS] == '[');
1454:                boolean bracketClosed = false;
1455:                for (int i = 0; i < valueL; i++) {
1456:                    char b = (char) valueB[i + valueS];
1457:                    hostNameC[i] = b;
1458:                    if (b == ']') {
1459:                        bracketClosed = true;
1460:                    } else if (b == ':') {
1461:                        if (!ipv6 || bracketClosed) {
1462:                            colonPos = i;
1463:                            break;
1464:                        }
1465:                    }
1466:                }
1467:
1468:                if (colonPos < 0) {
1469:                    if (!ssl) {
1470:                        // 80 - Default HTTP port
1471:                        request.setServerPort(80);
1472:                    } else {
1473:                        // 443 - Default HTTPS port
1474:                        request.setServerPort(443);
1475:                    }
1476:                    request.serverName().setChars(hostNameC, 0, valueL);
1477:                } else {
1478:
1479:                    request.serverName().setChars(hostNameC, 0, colonPos);
1480:
1481:                    int port = 0;
1482:                    int mult = 1;
1483:                    for (int i = valueL - 1; i > colonPos; i--) {
1484:                        int charValue = HexUtils.DEC[(int) valueB[i + valueS]];
1485:                        if (charValue == -1) {
1486:                            // Invalid character
1487:                            error = true;
1488:                            // 400 - Bad request
1489:                            response.setStatus(400);
1490:                            break;
1491:                        }
1492:                        port = port + (charValue * mult);
1493:                        mult = 10 * mult;
1494:                    }
1495:                    request.setServerPort(port);
1496:
1497:                }
1498:
1499:            }
1500:
1501:            /**
1502:             * Check for compression
1503:             */
1504:            private boolean isCompressable() {
1505:
1506:                // Nope Compression could works in HTTP 1.0 also
1507:                // cf: mod_deflate
1508:
1509:                // Compression only since HTTP 1.1
1510:                // if (! http11)
1511:                //    return false;
1512:
1513:                // Check if browser support gzip encoding
1514:                MessageBytes acceptEncodingMB = request.getMimeHeaders()
1515:                        .getValue("accept-encoding");
1516:
1517:                if ((acceptEncodingMB == null)
1518:                        || (acceptEncodingMB.indexOf("gzip") == -1))
1519:                    return false;
1520:
1521:                // Check if content is not allready gzipped
1522:                MessageBytes contentEncodingMB = response.getMimeHeaders()
1523:                        .getValue("Content-Encoding");
1524:
1525:                if ((contentEncodingMB != null)
1526:                        && (contentEncodingMB.indexOf("gzip") != -1))
1527:                    return false;
1528:
1529:                // If force mode, allways compress (test purposes only)
1530:                if (compressionLevel == 2)
1531:                    return true;
1532:
1533:                // Check for incompatible Browser
1534:                if (noCompressionUserAgents != null) {
1535:                    MessageBytes userAgentValueMB = request.getMimeHeaders()
1536:                            .getValue("user-agent");
1537:                    if (userAgentValueMB != null) {
1538:                        String userAgentValue = userAgentValueMB.toString();
1539:
1540:                        // If one Regexp rule match, disable compression
1541:                        for (int i = 0; i < noCompressionUserAgents.length; i++)
1542:                            if (noCompressionUserAgents[i].matcher(
1543:                                    userAgentValue).matches())
1544:                                return false;
1545:                    }
1546:                }
1547:
1548:                // Check if suffisant len to trig the compression
1549:                long contentLength = response.getContentLengthLong();
1550:                if ((contentLength == -1)
1551:                        || (contentLength > compressionMinSize)) {
1552:                    // Check for compatible MIME-TYPE
1553:                    if (compressableMimeTypes != null) {
1554:                        return (startsWithStringArray(compressableMimeTypes,
1555:                                response.getContentType()));
1556:                    }
1557:                }
1558:
1559:                return false;
1560:            }
1561:
1562:            /**
1563:             * When committing the response, we have to validate the set of headers, as
1564:             * well as setup the response filters.
1565:             */
1566:            protected void prepareResponse() throws IOException {
1567:
1568:                boolean entityBody = true;
1569:                contentDelimitation = false;
1570:
1571:                OutputFilter[] outputFilters = outputBuffer.getFilters();
1572:
1573:                if (http09 == true) {
1574:                    // HTTP/0.9
1575:                    outputBuffer
1576:                            .addActiveFilter(outputFilters[Constants.IDENTITY_FILTER]);
1577:                    return;
1578:                }
1579:
1580:                int statusCode = response.getStatus();
1581:                if ((statusCode == 204) || (statusCode == 205)
1582:                        || (statusCode == 304)) {
1583:                    // No entity body
1584:                    outputBuffer
1585:                            .addActiveFilter(outputFilters[Constants.VOID_FILTER]);
1586:                    entityBody = false;
1587:                    contentDelimitation = true;
1588:                }
1589:
1590:                MessageBytes methodMB = request.method();
1591:                if (methodMB.equals("HEAD")) {
1592:                    // No entity body
1593:                    outputBuffer
1594:                            .addActiveFilter(outputFilters[Constants.VOID_FILTER]);
1595:                    contentDelimitation = true;
1596:                }
1597:
1598:                // Sendfile support
1599:                if (this .endpoint.getUseSendfile()) {
1600:                    String fileName = (String) request
1601:                            .getAttribute("org.apache.tomcat.sendfile.filename");
1602:                    if (fileName != null) {
1603:                        // No entity body sent here
1604:                        outputBuffer
1605:                                .addActiveFilter(outputFilters[Constants.VOID_FILTER]);
1606:                        contentDelimitation = true;
1607:                        sendfileData = new NioEndpoint.SendfileData();
1608:                        sendfileData.fileName = fileName;
1609:                        sendfileData.pos = ((Long) request
1610:                                .getAttribute("org.apache.tomcat.sendfile.start"))
1611:                                .longValue();
1612:                        sendfileData.length = ((Long) request
1613:                                .getAttribute("org.apache.tomcat.sendfile.end"))
1614:                                .longValue()
1615:                                - sendfileData.pos;
1616:                    }
1617:                }
1618:
1619:                // Check for compression
1620:                boolean useCompression = false;
1621:                if (entityBody && (compressionLevel > 0)
1622:                        && (sendfileData == null)) {
1623:                    useCompression = isCompressable();
1624:                    // Change content-length to -1 to force chunking
1625:                    if (useCompression) {
1626:                        response.setContentLength(-1);
1627:                    }
1628:                }
1629:
1630:                MimeHeaders headers = response.getMimeHeaders();
1631:                if (!entityBody) {
1632:                    response.setContentLength(-1);
1633:                } else {
1634:                    String contentType = response.getContentType();
1635:                    if (contentType != null) {
1636:                        headers.setValue("Content-Type").setString(contentType);
1637:                    }
1638:                    String contentLanguage = response.getContentLanguage();
1639:                    if (contentLanguage != null) {
1640:                        headers.setValue("Content-Language").setString(
1641:                                contentLanguage);
1642:                    }
1643:                }
1644:
1645:                long contentLength = response.getContentLengthLong();
1646:                if (contentLength != -1) {
1647:                    headers.setValue("Content-Length").setLong(contentLength);
1648:                    outputBuffer
1649:                            .addActiveFilter(outputFilters[Constants.IDENTITY_FILTER]);
1650:                    contentDelimitation = true;
1651:                } else {
1652:                    if (entityBody && http11 && keepAlive) {
1653:                        outputBuffer
1654:                                .addActiveFilter(outputFilters[Constants.CHUNKED_FILTER]);
1655:                        contentDelimitation = true;
1656:                        headers.addValue(Constants.TRANSFERENCODING).setString(
1657:                                Constants.CHUNKED);
1658:                    } else {
1659:                        outputBuffer
1660:                                .addActiveFilter(outputFilters[Constants.IDENTITY_FILTER]);
1661:                    }
1662:                }
1663:
1664:                if (useCompression) {
1665:                    outputBuffer
1666:                            .addActiveFilter(outputFilters[Constants.GZIP_FILTER]);
1667:                    headers.setValue("Content-Encoding").setString("gzip");
1668:                    // Make Proxies happy via Vary (from mod_deflate)
1669:                    headers.setValue("Vary").setString("Accept-Encoding");
1670:                }
1671:
1672:                // Add date header
1673:                headers.setValue("Date").setString(
1674:                        FastHttpDateFormat.getCurrentDate());
1675:
1676:                // FIXME: Add transfer encoding header
1677:
1678:                if ((entityBody) && (!contentDelimitation)) {
1679:                    // Mark as close the connection after the request, and add the
1680:                    // connection: close header
1681:                    keepAlive = false;
1682:                }
1683:
1684:                // If we know that the request is bad this early, add the
1685:                // Connection: close header.
1686:                keepAlive = keepAlive && !statusDropsConnection(statusCode);
1687:                if (!keepAlive) {
1688:                    headers.addValue(Constants.CONNECTION).setString(
1689:                            Constants.CLOSE);
1690:                } else if (!http11 && !error) {
1691:                    headers.addValue(Constants.CONNECTION).setString(
1692:                            Constants.KEEPALIVE);
1693:                }
1694:
1695:                // Build the response header
1696:                outputBuffer.sendStatus();
1697:
1698:                // Add server header
1699:                if (server != null) {
1700:                    headers.setValue("Server").setString(server);
1701:                } else {
1702:                    outputBuffer.write(Constants.SERVER_BYTES);
1703:                }
1704:
1705:                int size = headers.size();
1706:                for (int i = 0; i < size; i++) {
1707:                    outputBuffer.sendHeader(headers.getName(i), headers
1708:                            .getValue(i));
1709:                }
1710:                outputBuffer.endHeaders();
1711:
1712:            }
1713:
1714:            /**
1715:             * Initialize standard input and output filters.
1716:             */
1717:            protected void initializeFilters() {
1718:
1719:                // Create and add the identity filters.
1720:                inputBuffer.addFilter(new IdentityInputFilter());
1721:                outputBuffer.addFilter(new IdentityOutputFilter());
1722:
1723:                // Create and add the chunked filters.
1724:                inputBuffer.addFilter(new ChunkedInputFilter());
1725:                outputBuffer.addFilter(new ChunkedOutputFilter());
1726:
1727:                // Create and add the void filters.
1728:                inputBuffer.addFilter(new VoidInputFilter());
1729:                outputBuffer.addFilter(new VoidOutputFilter());
1730:
1731:                // Create and add buffered input filter
1732:                inputBuffer.addFilter(new BufferedInputFilter());
1733:
1734:                // Create and add the chunked filters.
1735:                //inputBuffer.addFilter(new GzipInputFilter());
1736:                outputBuffer.addFilter(new GzipOutputFilter());
1737:
1738:            }
1739:
1740:            /**
1741:             * Add an input filter to the current request.
1742:             *
1743:             * @return false if the encoding was not found (which would mean it is
1744:             * unsupported)
1745:             */
1746:            protected boolean addInputFilter(InputFilter[] inputFilters,
1747:                    String encodingName) {
1748:                if (encodingName.equals("identity")) {
1749:                    // Skip
1750:                } else if (encodingName.equals("chunked")) {
1751:                    inputBuffer
1752:                            .addActiveFilter(inputFilters[Constants.CHUNKED_FILTER]);
1753:                    contentDelimitation = true;
1754:                } else {
1755:                    for (int i = 2; i < inputFilters.length; i++) {
1756:                        if (inputFilters[i].getEncodingName().toString()
1757:                                .equals(encodingName)) {
1758:                            inputBuffer.addActiveFilter(inputFilters[i]);
1759:                            return true;
1760:                        }
1761:                    }
1762:                    return false;
1763:                }
1764:                return true;
1765:            }
1766:
1767:            /**
1768:             * Specialized utility method: find a sequence of lower case bytes inside
1769:             * a ByteChunk.
1770:             */
1771:            protected int findBytes(ByteChunk bc, byte[] b) {
1772:
1773:                byte first = b[0];
1774:                byte[] buff = bc.getBuffer();
1775:                int start = bc.getStart();
1776:                int end = bc.getEnd();
1777:
1778:                // Look for first char
1779:                int srcEnd = b.length;
1780:
1781:                for (int i = start; i <= (end - srcEnd); i++) {
1782:                    if (Ascii.toLower(buff[i]) != first)
1783:                        continue;
1784:                    // found first char, now look for a match
1785:                    int myPos = i + 1;
1786:                    for (int srcPos = 1; srcPos < srcEnd;) {
1787:                        if (Ascii.toLower(buff[myPos++]) != b[srcPos++])
1788:                            break;
1789:                        if (srcPos == srcEnd)
1790:                            return i - start; // found it
1791:                    }
1792:                }
1793:                return -1;
1794:
1795:            }
1796:
1797:            /**
1798:             * Determine if we must drop the connection because of the HTTP status
1799:             * code.  Use the same list of codes as Apache/httpd.
1800:             */
1801:            protected boolean statusDropsConnection(int status) {
1802:                return status == 400 /* SC_BAD_REQUEST */|| status == 408 /* SC_REQUEST_TIMEOUT */
1803:                        || status == 411 /* SC_LENGTH_REQUIRED */
1804:                        || status == 413 /* SC_REQUEST_ENTITY_TOO_LARGE */
1805:                        || status == 414 /* SC_REQUEST_URI_TOO_LARGE */
1806:                        || status == 500 /* SC_INTERNAL_SERVER_ERROR */
1807:                        || status == 503 /* SC_SERVICE_UNAVAILABLE */
1808:                        || status == 501 /* SC_NOT_IMPLEMENTED */;
1809:            }
1810:
1811:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.