Source Code Cross Referenced for Http11Processor.java in  » Sevlet-Container » tomcat-connectors » 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 » tomcat connectors » org.apache.coyote.http11 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


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