Source Code Cross Referenced for AjpAprProcessor.java in  » Sevlet-Container » apache-tomcat-6.0.14 » org » apache » coyote » ajp » 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.ajp 
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.ajp;
0019:
0020:        import java.io.ByteArrayInputStream;
0021:        import java.io.IOException;
0022:        import java.io.InterruptedIOException;
0023:        import java.net.InetAddress;
0024:        import java.nio.ByteBuffer;
0025:        import java.security.cert.CertificateFactory;
0026:        import java.security.cert.X509Certificate;
0027:
0028:        import org.apache.coyote.ActionCode;
0029:        import org.apache.coyote.ActionHook;
0030:        import org.apache.coyote.Adapter;
0031:        import org.apache.coyote.InputBuffer;
0032:        import org.apache.coyote.OutputBuffer;
0033:        import org.apache.coyote.Request;
0034:        import org.apache.coyote.RequestInfo;
0035:        import org.apache.coyote.Response;
0036:        import org.apache.tomcat.jni.Socket;
0037:        import org.apache.tomcat.jni.Status;
0038:        import org.apache.tomcat.util.buf.ByteChunk;
0039:        import org.apache.tomcat.util.buf.HexUtils;
0040:        import org.apache.tomcat.util.buf.MessageBytes;
0041:        import org.apache.tomcat.util.http.HttpMessages;
0042:        import org.apache.tomcat.util.http.MimeHeaders;
0043:        import org.apache.tomcat.util.net.AprEndpoint;
0044:        import org.apache.tomcat.util.res.StringManager;
0045:
0046:        /**
0047:         * Processes HTTP requests.
0048:         *
0049:         * @author Remy Maucherat
0050:         * @author Henri Gomez
0051:         * @author Dan Milstein
0052:         * @author Keith Wannamaker
0053:         * @author Kevin Seguin
0054:         * @author Costin Manolache
0055:         * @author Bill Barker
0056:         */
0057:        public class AjpAprProcessor implements  ActionHook {
0058:
0059:            /**
0060:             * Logger.
0061:             */
0062:            protected static org.apache.juli.logging.Log log = org.apache.juli.logging.LogFactory
0063:                    .getLog(AjpAprProcessor.class);
0064:
0065:            /**
0066:             * The string manager for this package.
0067:             */
0068:            protected static StringManager sm = StringManager
0069:                    .getManager(Constants.Package);
0070:
0071:            // ----------------------------------------------------------- Constructors
0072:
0073:            public AjpAprProcessor(int packetSize, AprEndpoint endpoint) {
0074:
0075:                this .endpoint = endpoint;
0076:
0077:                request = new Request();
0078:                request.setInputBuffer(new SocketInputBuffer());
0079:
0080:                response = new Response();
0081:                response.setHook(this );
0082:                response.setOutputBuffer(new SocketOutputBuffer());
0083:                request.setResponse(response);
0084:
0085:                requestHeaderMessage = new AjpMessage(packetSize);
0086:                responseHeaderMessage = new AjpMessage(packetSize);
0087:                bodyMessage = new AjpMessage(packetSize);
0088:
0089:                // Allocate input and output buffers
0090:                inputBuffer = ByteBuffer.allocateDirect(packetSize * 2);
0091:                inputBuffer.limit(0);
0092:                outputBuffer = ByteBuffer.allocateDirect(packetSize * 2);
0093:
0094:                // Cause loading of HexUtils
0095:                int foo = HexUtils.DEC[0];
0096:
0097:                // Cause loading of HttpMessages
0098:                HttpMessages.getMessage(200);
0099:
0100:            }
0101:
0102:            // ----------------------------------------------------- Instance Variables
0103:
0104:            /**
0105:             * Associated adapter.
0106:             */
0107:            protected Adapter adapter = null;
0108:
0109:            /**
0110:             * Request object.
0111:             */
0112:            protected Request request = null;
0113:
0114:            /**
0115:             * Response object.
0116:             */
0117:            protected Response response = null;
0118:
0119:            /**
0120:             * Header message. Note that this header is merely the one used during the
0121:             * processing of the first message of a "request", so it might not be a request
0122:             * header. It will stay unchanged during the processing of the whole request.
0123:             */
0124:            protected AjpMessage requestHeaderMessage = null;
0125:
0126:            /**
0127:             * Message used for response header composition.
0128:             */
0129:            protected AjpMessage responseHeaderMessage = null;
0130:
0131:            /**
0132:             * Body message.
0133:             */
0134:            protected AjpMessage bodyMessage = null;
0135:
0136:            /**
0137:             * Body message.
0138:             */
0139:            protected MessageBytes bodyBytes = MessageBytes.newInstance();
0140:
0141:            /**
0142:             * State flag.
0143:             */
0144:            protected boolean started = false;
0145:
0146:            /**
0147:             * Error flag.
0148:             */
0149:            protected boolean error = false;
0150:
0151:            /**
0152:             * Socket associated with the current connection.
0153:             */
0154:            protected long socket;
0155:
0156:            /**
0157:             * Host name (used to avoid useless B2C conversion on the host name).
0158:             */
0159:            protected char[] hostNameC = new char[0];
0160:
0161:            /**
0162:             * Associated endpoint.
0163:             */
0164:            protected AprEndpoint endpoint;
0165:
0166:            /**
0167:             * Temp message bytes used for processing.
0168:             */
0169:            protected MessageBytes tmpMB = MessageBytes.newInstance();
0170:
0171:            /**
0172:             * Byte chunk for certs.
0173:             */
0174:            protected MessageBytes certificates = MessageBytes.newInstance();
0175:
0176:            /**
0177:             * End of stream flag.
0178:             */
0179:            protected boolean endOfStream = false;
0180:
0181:            /**
0182:             * Body empty flag.
0183:             */
0184:            protected boolean empty = true;
0185:
0186:            /**
0187:             * First read.
0188:             */
0189:            protected boolean first = true;
0190:
0191:            /**
0192:             * Replay read.
0193:             */
0194:            protected boolean replay = false;
0195:
0196:            /**
0197:             * Finished response.
0198:             */
0199:            protected boolean finished = false;
0200:
0201:            /**
0202:             * Direct buffer used for output.
0203:             */
0204:            protected ByteBuffer outputBuffer = null;
0205:
0206:            /**
0207:             * Direct buffer used for input.
0208:             */
0209:            protected ByteBuffer inputBuffer = null;
0210:
0211:            /**
0212:             * Direct buffer used for sending right away a get body message.
0213:             */
0214:            protected static final ByteBuffer getBodyMessageBuffer;
0215:
0216:            /**
0217:             * Direct buffer used for sending right away a pong message.
0218:             */
0219:            protected static final ByteBuffer pongMessageBuffer;
0220:
0221:            /**
0222:             * End message array.
0223:             */
0224:            protected static final byte[] endMessageArray;
0225:
0226:            /**
0227:             * Direct buffer used for sending explicit flush message.
0228:             */
0229:            protected static final ByteBuffer flushMessageBuffer;
0230:
0231:            // ----------------------------------------------------- Static Initializer
0232:
0233:            static {
0234:
0235:                // Set the get body message buffer
0236:                AjpMessage getBodyMessage = new AjpMessage(16);
0237:                getBodyMessage.reset();
0238:                getBodyMessage.appendByte(Constants.JK_AJP13_GET_BODY_CHUNK);
0239:                getBodyMessage.appendInt(Constants.MAX_READ_SIZE);
0240:                getBodyMessage.end();
0241:                getBodyMessageBuffer = ByteBuffer.allocateDirect(getBodyMessage
0242:                        .getLen());
0243:                getBodyMessageBuffer.put(getBodyMessage.getBuffer(), 0,
0244:                        getBodyMessage.getLen());
0245:
0246:                // Set the read body message buffer
0247:                AjpMessage pongMessage = new AjpMessage(16);
0248:                pongMessage.reset();
0249:                pongMessage.appendByte(Constants.JK_AJP13_CPONG_REPLY);
0250:                pongMessage.end();
0251:                pongMessageBuffer = ByteBuffer.allocateDirect(pongMessage
0252:                        .getLen());
0253:                pongMessageBuffer.put(pongMessage.getBuffer(), 0, pongMessage
0254:                        .getLen());
0255:
0256:                // Allocate the end message array
0257:                AjpMessage endMessage = new AjpMessage(16);
0258:                endMessage.reset();
0259:                endMessage.appendByte(Constants.JK_AJP13_END_RESPONSE);
0260:                endMessage.appendByte(1);
0261:                endMessage.end();
0262:                endMessageArray = new byte[endMessage.getLen()];
0263:                System.arraycopy(endMessage.getBuffer(), 0, endMessageArray, 0,
0264:                        endMessage.getLen());
0265:
0266:                // Set the flush message buffer
0267:                AjpMessage flushMessage = new AjpMessage(16);
0268:                flushMessage.reset();
0269:                flushMessage.appendByte(Constants.JK_AJP13_SEND_BODY_CHUNK);
0270:                flushMessage.appendInt(0);
0271:                flushMessage.appendByte(0);
0272:                flushMessage.end();
0273:                flushMessageBuffer = ByteBuffer.allocateDirect(flushMessage
0274:                        .getLen());
0275:                flushMessageBuffer.put(flushMessage.getBuffer(), 0,
0276:                        flushMessage.getLen());
0277:
0278:            }
0279:
0280:            // ------------------------------------------------------------- Properties
0281:
0282:            /**
0283:             * Use Tomcat authentication ?
0284:             */
0285:            protected boolean tomcatAuthentication = true;
0286:
0287:            public boolean getTomcatAuthentication() {
0288:                return tomcatAuthentication;
0289:            }
0290:
0291:            public void setTomcatAuthentication(boolean tomcatAuthentication) {
0292:                this .tomcatAuthentication = tomcatAuthentication;
0293:            }
0294:
0295:            /**
0296:             * Required secret.
0297:             */
0298:            protected String requiredSecret = null;
0299:
0300:            public void setRequiredSecret(String requiredSecret) {
0301:                this .requiredSecret = requiredSecret;
0302:            }
0303:
0304:            // --------------------------------------------------------- Public Methods
0305:
0306:            /** Get the request associated with this processor.
0307:             *
0308:             * @return The request
0309:             */
0310:            public Request getRequest() {
0311:                return request;
0312:            }
0313:
0314:            /**
0315:             * Process pipelined HTTP requests using the specified input and output
0316:             * streams.
0317:             *
0318:             * @throws IOException error during an I/O operation
0319:             */
0320:            public boolean process(long socket) throws IOException {
0321:                RequestInfo rp = request.getRequestProcessor();
0322:                rp.setStage(org.apache.coyote.Constants.STAGE_PARSE);
0323:
0324:                // Setting up the socket
0325:                this .socket = socket;
0326:                Socket.setrbb(this .socket, inputBuffer);
0327:                Socket.setsbb(this .socket, outputBuffer);
0328:
0329:                // Error flag
0330:                error = false;
0331:
0332:                boolean openSocket = true;
0333:                boolean keptAlive = false;
0334:
0335:                while (started && !error) {
0336:
0337:                    // Parsing the request header
0338:                    try {
0339:                        // Get first message of the request
0340:                        if (!readMessage(requestHeaderMessage, true, keptAlive)) {
0341:                            // This means that no data is available right now
0342:                            // (long keepalive), so that the processor should be recycled
0343:                            // and the method should return true
0344:                            rp
0345:                                    .setStage(org.apache.coyote.Constants.STAGE_ENDED);
0346:                            break;
0347:                        }
0348:                        // Check message type, process right away and break if
0349:                        // not regular request processing
0350:                        int type = requestHeaderMessage.getByte();
0351:                        if (type == Constants.JK_AJP13_CPING_REQUEST) {
0352:                            if (Socket.sendb(socket, pongMessageBuffer, 0,
0353:                                    pongMessageBuffer.position()) < 0) {
0354:                                error = true;
0355:                            }
0356:                            continue;
0357:                        } else if (type != Constants.JK_AJP13_FORWARD_REQUEST) {
0358:                            // Usually the servlet didn't read the previous request body
0359:                            if (log.isDebugEnabled()) {
0360:                                log.debug("Unexpected message: " + type);
0361:                            }
0362:                            continue;
0363:                        }
0364:
0365:                        keptAlive = true;
0366:                        request.setStartTime(System.currentTimeMillis());
0367:                    } catch (IOException e) {
0368:                        error = true;
0369:                        break;
0370:                    } catch (Throwable t) {
0371:                        log.debug(sm.getString("ajpprocessor.header.error"), t);
0372:                        // 400 - Bad Request
0373:                        response.setStatus(400);
0374:                        error = true;
0375:                    }
0376:
0377:                    // Setting up filters, and parse some request headers
0378:                    rp.setStage(org.apache.coyote.Constants.STAGE_PREPARE);
0379:                    try {
0380:                        prepareRequest();
0381:                    } catch (Throwable t) {
0382:                        log.debug(sm.getString("ajpprocessor.request.prepare"),
0383:                                t);
0384:                        // 400 - Internal Server Error
0385:                        response.setStatus(400);
0386:                        error = true;
0387:                    }
0388:
0389:                    // Process the request in the adapter
0390:                    if (!error) {
0391:                        try {
0392:                            rp
0393:                                    .setStage(org.apache.coyote.Constants.STAGE_SERVICE);
0394:                            adapter.service(request, response);
0395:                        } catch (InterruptedIOException e) {
0396:                            error = true;
0397:                        } catch (Throwable t) {
0398:                            log.error(sm
0399:                                    .getString("ajpprocessor.request.process"),
0400:                                    t);
0401:                            // 500 - Internal Server Error
0402:                            response.setStatus(500);
0403:                            error = true;
0404:                        }
0405:                    }
0406:
0407:                    // Finish the response if not done yet
0408:                    if (!finished) {
0409:                        try {
0410:                            finish();
0411:                        } catch (Throwable t) {
0412:                            error = true;
0413:                        }
0414:                    }
0415:
0416:                    // If there was an error, make sure the request is counted as
0417:                    // and error, and update the statistics counter
0418:                    if (error) {
0419:                        response.setStatus(500);
0420:                    }
0421:                    request.updateCounters();
0422:
0423:                    rp.setStage(org.apache.coyote.Constants.STAGE_KEEPALIVE);
0424:                    recycle();
0425:
0426:                }
0427:
0428:                // Add the socket to the poller
0429:                if (!error) {
0430:                    endpoint.getPoller().add(socket);
0431:                } else {
0432:                    openSocket = false;
0433:                }
0434:
0435:                rp.setStage(org.apache.coyote.Constants.STAGE_ENDED);
0436:                recycle();
0437:
0438:                return openSocket;
0439:
0440:            }
0441:
0442:            // ----------------------------------------------------- ActionHook Methods
0443:
0444:            /**
0445:             * Send an action to the connector.
0446:             *
0447:             * @param actionCode Type of the action
0448:             * @param param Action parameter
0449:             */
0450:            public void action(ActionCode actionCode, Object param) {
0451:
0452:                if (actionCode == ActionCode.ACTION_COMMIT) {
0453:
0454:                    if (response.isCommitted())
0455:                        return;
0456:
0457:                    // Validate and write response headers
0458:                    try {
0459:                        prepareResponse();
0460:                    } catch (IOException e) {
0461:                        // Set error flag
0462:                        error = true;
0463:                    }
0464:
0465:                } else if (actionCode == ActionCode.ACTION_CLIENT_FLUSH) {
0466:
0467:                    if (!response.isCommitted()) {
0468:                        // Validate and write response headers
0469:                        try {
0470:                            prepareResponse();
0471:                        } catch (IOException e) {
0472:                            // Set error flag
0473:                            error = true;
0474:                            return;
0475:                        }
0476:                    }
0477:
0478:                    try {
0479:                        flush();
0480:                        // Send explicit flush message
0481:                        if (Socket.sendb(socket, flushMessageBuffer, 0,
0482:                                flushMessageBuffer.position()) < 0) {
0483:                            error = true;
0484:                        }
0485:                    } catch (IOException e) {
0486:                        // Set error flag
0487:                        error = true;
0488:                    }
0489:
0490:                } else if (actionCode == ActionCode.ACTION_CLOSE) {
0491:                    // Close
0492:
0493:                    // End the processing of the current request, and stop any further
0494:                    // transactions with the client
0495:
0496:                    try {
0497:                        finish();
0498:                    } catch (IOException e) {
0499:                        // Set error flag
0500:                        error = true;
0501:                    }
0502:
0503:                } else if (actionCode == ActionCode.ACTION_START) {
0504:
0505:                    started = true;
0506:
0507:                } else if (actionCode == ActionCode.ACTION_STOP) {
0508:
0509:                    started = false;
0510:
0511:                } else if (actionCode == ActionCode.ACTION_REQ_SSL_ATTRIBUTE) {
0512:
0513:                    if (!certificates.isNull()) {
0514:                        ByteChunk certData = certificates.getByteChunk();
0515:                        X509Certificate jsseCerts[] = null;
0516:                        ByteArrayInputStream bais = new ByteArrayInputStream(
0517:                                certData.getBytes(), certData.getStart(),
0518:                                certData.getLength());
0519:                        // Fill the first element.
0520:                        try {
0521:                            CertificateFactory cf = CertificateFactory
0522:                                    .getInstance("X.509");
0523:                            X509Certificate cert = (X509Certificate) cf
0524:                                    .generateCertificate(bais);
0525:                            jsseCerts = new X509Certificate[1];
0526:                            jsseCerts[0] = cert;
0527:                            request.setAttribute(AprEndpoint.CERTIFICATE_KEY,
0528:                                    jsseCerts);
0529:                        } catch (java.security.cert.CertificateException e) {
0530:                            log.error(sm.getString("ajpprocessor.certs.fail"),
0531:                                    e);
0532:                            return;
0533:                        }
0534:                    }
0535:
0536:                } else if (actionCode == ActionCode.ACTION_REQ_HOST_ATTRIBUTE) {
0537:
0538:                    // Get remote host name using a DNS resolution
0539:                    if (request.remoteHost().isNull()) {
0540:                        try {
0541:                            request.remoteHost().setString(
0542:                                    InetAddress.getByName(
0543:                                            request.remoteAddr().toString())
0544:                                            .getHostName());
0545:                        } catch (IOException iex) {
0546:                            // Ignore
0547:                        }
0548:                    }
0549:
0550:                } else if (actionCode == ActionCode.ACTION_REQ_LOCAL_ADDR_ATTRIBUTE) {
0551:
0552:                    // Copy from local name for now, which should simply be an address
0553:                    request.localAddr().setString(
0554:                            request.localName().toString());
0555:
0556:                } else if (actionCode == ActionCode.ACTION_REQ_SET_BODY_REPLAY) {
0557:
0558:                    // Set the given bytes as the content
0559:                    ByteChunk bc = (ByteChunk) param;
0560:                    int length = bc.getLength();
0561:                    bodyBytes.setBytes(bc.getBytes(), bc.getStart(), length);
0562:                    request.setContentLength(length);
0563:                    first = false;
0564:                    empty = false;
0565:                    replay = true;
0566:
0567:                }
0568:
0569:            }
0570:
0571:            // ------------------------------------------------------ Connector Methods
0572:
0573:            /**
0574:             * Set the associated adapter.
0575:             *
0576:             * @param adapter the new adapter
0577:             */
0578:            public void setAdapter(Adapter adapter) {
0579:                this .adapter = adapter;
0580:            }
0581:
0582:            /**
0583:             * Get the associated adapter.
0584:             *
0585:             * @return the associated adapter
0586:             */
0587:            public Adapter getAdapter() {
0588:                return adapter;
0589:            }
0590:
0591:            // ------------------------------------------------------ Protected Methods
0592:
0593:            /**
0594:             * After reading the request headers, we have to setup the request filters.
0595:             */
0596:            protected void prepareRequest() {
0597:
0598:                // Translate the HTTP method code to a String.
0599:                byte methodCode = requestHeaderMessage.getByte();
0600:                if (methodCode != Constants.SC_M_JK_STORED) {
0601:                    String methodName = Constants.methodTransArray[(int) methodCode - 1];
0602:                    request.method().setString(methodName);
0603:                }
0604:
0605:                requestHeaderMessage.getBytes(request.protocol());
0606:                requestHeaderMessage.getBytes(request.requestURI());
0607:
0608:                requestHeaderMessage.getBytes(request.remoteAddr());
0609:                requestHeaderMessage.getBytes(request.remoteHost());
0610:                requestHeaderMessage.getBytes(request.localName());
0611:                request.setLocalPort(requestHeaderMessage.getInt());
0612:
0613:                boolean isSSL = requestHeaderMessage.getByte() != 0;
0614:                if (isSSL) {
0615:                    request.scheme().setString("https");
0616:                }
0617:
0618:                // Decode headers
0619:                MimeHeaders headers = request.getMimeHeaders();
0620:
0621:                int hCount = requestHeaderMessage.getInt();
0622:                for (int i = 0; i < hCount; i++) {
0623:                    String hName = null;
0624:
0625:                    // Header names are encoded as either an integer code starting
0626:                    // with 0xA0, or as a normal string (in which case the first
0627:                    // two bytes are the length).
0628:                    int isc = requestHeaderMessage.peekInt();
0629:                    int hId = isc & 0xFF;
0630:
0631:                    MessageBytes vMB = null;
0632:                    isc &= 0xFF00;
0633:                    if (0xA000 == isc) {
0634:                        requestHeaderMessage.getInt(); // To advance the read position
0635:                        hName = Constants.headerTransArray[hId - 1];
0636:                        vMB = headers.addValue(hName);
0637:                    } else {
0638:                        // reset hId -- if the header currently being read
0639:                        // happens to be 7 or 8 bytes long, the code below
0640:                        // will think it's the content-type header or the
0641:                        // content-length header - SC_REQ_CONTENT_TYPE=7,
0642:                        // SC_REQ_CONTENT_LENGTH=8 - leading to unexpected
0643:                        // behaviour.  see bug 5861 for more information.
0644:                        hId = -1;
0645:                        requestHeaderMessage.getBytes(tmpMB);
0646:                        ByteChunk bc = tmpMB.getByteChunk();
0647:                        vMB = headers.addValue(bc.getBuffer(), bc.getStart(),
0648:                                bc.getLength());
0649:                    }
0650:
0651:                    requestHeaderMessage.getBytes(vMB);
0652:
0653:                    if (hId == Constants.SC_REQ_CONTENT_LENGTH
0654:                            || (hId == -1 && tmpMB
0655:                                    .equalsIgnoreCase("Content-Length"))) {
0656:                        // just read the content-length header, so set it
0657:                        long cl = vMB.getLong();
0658:                        if (cl < Integer.MAX_VALUE)
0659:                            request.setContentLength((int) cl);
0660:                    } else if (hId == Constants.SC_REQ_CONTENT_TYPE
0661:                            || (hId == -1 && tmpMB
0662:                                    .equalsIgnoreCase("Content-Type"))) {
0663:                        // just read the content-type header, so set it
0664:                        ByteChunk bchunk = vMB.getByteChunk();
0665:                        request.contentType().setBytes(bchunk.getBytes(),
0666:                                bchunk.getOffset(), bchunk.getLength());
0667:                    }
0668:                }
0669:
0670:                // Decode extra attributes
0671:                boolean secret = false;
0672:                byte attributeCode;
0673:                while ((attributeCode = requestHeaderMessage.getByte()) != Constants.SC_A_ARE_DONE) {
0674:
0675:                    switch (attributeCode) {
0676:
0677:                    case Constants.SC_A_REQ_ATTRIBUTE:
0678:                        requestHeaderMessage.getBytes(tmpMB);
0679:                        String n = tmpMB.toString();
0680:                        requestHeaderMessage.getBytes(tmpMB);
0681:                        String v = tmpMB.toString();
0682:                        request.setAttribute(n, v);
0683:                        break;
0684:
0685:                    case Constants.SC_A_CONTEXT:
0686:                        requestHeaderMessage.getBytes(tmpMB);
0687:                        // nothing
0688:                        break;
0689:
0690:                    case Constants.SC_A_SERVLET_PATH:
0691:                        requestHeaderMessage.getBytes(tmpMB);
0692:                        // nothing
0693:                        break;
0694:
0695:                    case Constants.SC_A_REMOTE_USER:
0696:                        if (tomcatAuthentication) {
0697:                            // ignore server
0698:                            requestHeaderMessage.getBytes(tmpMB);
0699:                        } else {
0700:                            requestHeaderMessage.getBytes(request
0701:                                    .getRemoteUser());
0702:                        }
0703:                        break;
0704:
0705:                    case Constants.SC_A_AUTH_TYPE:
0706:                        if (tomcatAuthentication) {
0707:                            // ignore server
0708:                            requestHeaderMessage.getBytes(tmpMB);
0709:                        } else {
0710:                            requestHeaderMessage
0711:                                    .getBytes(request.getAuthType());
0712:                        }
0713:                        break;
0714:
0715:                    case Constants.SC_A_QUERY_STRING:
0716:                        requestHeaderMessage.getBytes(request.queryString());
0717:                        break;
0718:
0719:                    case Constants.SC_A_JVM_ROUTE:
0720:                        requestHeaderMessage.getBytes(request.instanceId());
0721:                        break;
0722:
0723:                    case Constants.SC_A_SSL_CERT:
0724:                        request.scheme().setString("https");
0725:                        // SSL certificate extraction is lazy, moved to JkCoyoteHandler
0726:                        requestHeaderMessage.getBytes(certificates);
0727:                        break;
0728:
0729:                    case Constants.SC_A_SSL_CIPHER:
0730:                        request.scheme().setString("https");
0731:                        requestHeaderMessage.getBytes(tmpMB);
0732:                        request.setAttribute(AprEndpoint.CIPHER_SUITE_KEY,
0733:                                tmpMB.toString());
0734:                        break;
0735:
0736:                    case Constants.SC_A_SSL_SESSION:
0737:                        request.scheme().setString("https");
0738:                        requestHeaderMessage.getBytes(tmpMB);
0739:                        request.setAttribute(AprEndpoint.SESSION_ID_KEY, tmpMB
0740:                                .toString());
0741:                        break;
0742:
0743:                    case Constants.SC_A_SSL_KEY_SIZE:
0744:                        request.setAttribute(AprEndpoint.KEY_SIZE_KEY,
0745:                                new Integer(requestHeaderMessage.getInt()));
0746:                        break;
0747:
0748:                    case Constants.SC_A_STORED_METHOD:
0749:                        requestHeaderMessage.getBytes(request.method());
0750:                        break;
0751:
0752:                    case Constants.SC_A_SECRET:
0753:                        requestHeaderMessage.getBytes(tmpMB);
0754:                        if (requiredSecret != null) {
0755:                            secret = true;
0756:                            if (!tmpMB.equals(requiredSecret)) {
0757:                                response.setStatus(403);
0758:                                error = true;
0759:                            }
0760:                        }
0761:                        break;
0762:
0763:                    default:
0764:                        // Ignore unknown attribute for backward compatibility
0765:                        break;
0766:
0767:                    }
0768:
0769:                }
0770:
0771:                // Check if secret was submitted if required
0772:                if ((requiredSecret != null) && !secret) {
0773:                    response.setStatus(403);
0774:                    error = true;
0775:                }
0776:
0777:                // Check for a full URI (including protocol://host:port/)
0778:                ByteChunk uriBC = request.requestURI().getByteChunk();
0779:                if (uriBC.startsWithIgnoreCase("http", 0)) {
0780:
0781:                    int pos = uriBC.indexOf("://", 0, 3, 4);
0782:                    int uriBCStart = uriBC.getStart();
0783:                    int slashPos = -1;
0784:                    if (pos != -1) {
0785:                        byte[] uriB = uriBC.getBytes();
0786:                        slashPos = uriBC.indexOf('/', pos + 3);
0787:                        if (slashPos == -1) {
0788:                            slashPos = uriBC.getLength();
0789:                            // Set URI as "/"
0790:                            request.requestURI().setBytes(uriB,
0791:                                    uriBCStart + pos + 1, 1);
0792:                        } else {
0793:                            request.requestURI().setBytes(uriB,
0794:                                    uriBCStart + slashPos,
0795:                                    uriBC.getLength() - slashPos);
0796:                        }
0797:                        MessageBytes hostMB = headers.setValue("host");
0798:                        hostMB.setBytes(uriB, uriBCStart + pos + 3, slashPos
0799:                                - pos - 3);
0800:                    }
0801:
0802:                }
0803:
0804:                MessageBytes valueMB = request.getMimeHeaders()
0805:                        .getValue("host");
0806:                parseHost(valueMB);
0807:
0808:            }
0809:
0810:            /**
0811:             * Parse host.
0812:             */
0813:            public void parseHost(MessageBytes valueMB) {
0814:
0815:                if (valueMB == null || (valueMB != null && valueMB.isNull())) {
0816:                    // HTTP/1.0
0817:                    // Default is what the socket tells us. Overriden if a host is
0818:                    // found/parsed
0819:                    request.setServerPort(endpoint.getPort());
0820:                    return;
0821:                }
0822:
0823:                ByteChunk valueBC = valueMB.getByteChunk();
0824:                byte[] valueB = valueBC.getBytes();
0825:                int valueL = valueBC.getLength();
0826:                int valueS = valueBC.getStart();
0827:                int colonPos = -1;
0828:                if (hostNameC.length < valueL) {
0829:                    hostNameC = new char[valueL];
0830:                }
0831:
0832:                boolean ipv6 = (valueB[valueS] == '[');
0833:                boolean bracketClosed = false;
0834:                for (int i = 0; i < valueL; i++) {
0835:                    char b = (char) valueB[i + valueS];
0836:                    hostNameC[i] = b;
0837:                    if (b == ']') {
0838:                        bracketClosed = true;
0839:                    } else if (b == ':') {
0840:                        if (!ipv6 || bracketClosed) {
0841:                            colonPos = i;
0842:                            break;
0843:                        }
0844:                    }
0845:                }
0846:
0847:                if (colonPos < 0) {
0848:                    if (request.scheme().equalsIgnoreCase("https")) {
0849:                        // 443 - Default HTTPS port
0850:                        request.setServerPort(443);
0851:                    } else {
0852:                        // 80 - Default HTTTP port
0853:                        request.setServerPort(80);
0854:                    }
0855:                    request.serverName().setChars(hostNameC, 0, valueL);
0856:                } else {
0857:
0858:                    request.serverName().setChars(hostNameC, 0, colonPos);
0859:
0860:                    int port = 0;
0861:                    int mult = 1;
0862:                    for (int i = valueL - 1; i > colonPos; i--) {
0863:                        int charValue = HexUtils.DEC[(int) valueB[i + valueS]];
0864:                        if (charValue == -1) {
0865:                            // Invalid character
0866:                            error = true;
0867:                            // 400 - Bad request
0868:                            response.setStatus(400);
0869:                            break;
0870:                        }
0871:                        port = port + (charValue * mult);
0872:                        mult = 10 * mult;
0873:                    }
0874:                    request.setServerPort(port);
0875:
0876:                }
0877:
0878:            }
0879:
0880:            /**
0881:             * When committing the response, we have to validate the set of headers, as
0882:             * well as setup the response filters.
0883:             */
0884:            protected void prepareResponse() throws IOException {
0885:
0886:                response.setCommitted(true);
0887:
0888:                responseHeaderMessage.reset();
0889:                responseHeaderMessage
0890:                        .appendByte(Constants.JK_AJP13_SEND_HEADERS);
0891:
0892:                // HTTP header contents
0893:                responseHeaderMessage.appendInt(response.getStatus());
0894:                String message = response.getMessage();
0895:                if (message == null) {
0896:                    message = HttpMessages.getMessage(response.getStatus());
0897:                } else {
0898:                    message = message.replace('\n', ' ').replace('\r', ' ');
0899:                }
0900:                tmpMB.setString(message);
0901:                responseHeaderMessage.appendBytes(tmpMB);
0902:
0903:                // Special headers
0904:                MimeHeaders headers = response.getMimeHeaders();
0905:                String contentType = response.getContentType();
0906:                if (contentType != null) {
0907:                    headers.setValue("Content-Type").setString(contentType);
0908:                }
0909:                String contentLanguage = response.getContentLanguage();
0910:                if (contentLanguage != null) {
0911:                    headers.setValue("Content-Language").setString(
0912:                            contentLanguage);
0913:                }
0914:                long contentLength = response.getContentLengthLong();
0915:                if (contentLength >= 0) {
0916:                    headers.setValue("Content-Length").setLong(contentLength);
0917:                }
0918:
0919:                // Other headers
0920:                int numHeaders = headers.size();
0921:                responseHeaderMessage.appendInt(numHeaders);
0922:                for (int i = 0; i < numHeaders; i++) {
0923:                    MessageBytes hN = headers.getName(i);
0924:                    int hC = Constants.getResponseAjpIndex(hN.toString());
0925:                    if (hC > 0) {
0926:                        responseHeaderMessage.appendInt(hC);
0927:                    } else {
0928:                        responseHeaderMessage.appendBytes(hN);
0929:                    }
0930:                    MessageBytes hV = headers.getValue(i);
0931:                    responseHeaderMessage.appendBytes(hV);
0932:                }
0933:
0934:                // Write to buffer
0935:                responseHeaderMessage.end();
0936:                outputBuffer.put(responseHeaderMessage.getBuffer(), 0,
0937:                        responseHeaderMessage.getLen());
0938:
0939:            }
0940:
0941:            /**
0942:             * Finish AJP response.
0943:             */
0944:            protected void finish() throws IOException {
0945:
0946:                if (!response.isCommitted()) {
0947:                    // Validate and write response headers
0948:                    try {
0949:                        prepareResponse();
0950:                    } catch (IOException e) {
0951:                        // Set error flag
0952:                        error = true;
0953:                    }
0954:                }
0955:
0956:                if (finished)
0957:                    return;
0958:
0959:                finished = true;
0960:
0961:                // Add the end message
0962:                if (outputBuffer.position() + endMessageArray.length > outputBuffer
0963:                        .capacity()) {
0964:                    flush();
0965:                }
0966:                outputBuffer.put(endMessageArray);
0967:                flush();
0968:
0969:            }
0970:
0971:            /**
0972:             * Read at least the specified amount of bytes, and place them
0973:             * in the input buffer.
0974:             */
0975:            protected boolean read(int n) throws IOException {
0976:
0977:                if (inputBuffer.capacity() - inputBuffer.limit() <= n
0978:                        - inputBuffer.remaining()) {
0979:                    inputBuffer.compact();
0980:                    inputBuffer.limit(inputBuffer.position());
0981:                    inputBuffer.position(0);
0982:                }
0983:                int nRead;
0984:                while (inputBuffer.remaining() < n) {
0985:                    nRead = Socket.recvbb(socket, inputBuffer.limit(),
0986:                            inputBuffer.capacity() - inputBuffer.limit());
0987:                    if (nRead > 0) {
0988:                        inputBuffer.limit(inputBuffer.limit() + nRead);
0989:                    } else {
0990:                        throw new IOException(sm
0991:                                .getString("ajpprotocol.failedread"));
0992:                    }
0993:                }
0994:
0995:                return true;
0996:
0997:            }
0998:
0999:            /**
1000:             * Read at least the specified amount of bytes, and place them
1001:             * in the input buffer.
1002:             */
1003:            protected boolean readt(int n, boolean useAvailableData)
1004:                    throws IOException {
1005:
1006:                if (useAvailableData && inputBuffer.remaining() == 0) {
1007:                    return false;
1008:                }
1009:                if (inputBuffer.capacity() - inputBuffer.limit() <= n
1010:                        - inputBuffer.remaining()) {
1011:                    inputBuffer.compact();
1012:                    inputBuffer.limit(inputBuffer.position());
1013:                    inputBuffer.position(0);
1014:                }
1015:                int nRead;
1016:                while (inputBuffer.remaining() < n) {
1017:                    nRead = Socket.recvbb(socket, inputBuffer.limit(),
1018:                            inputBuffer.capacity() - inputBuffer.limit());
1019:                    if (nRead > 0) {
1020:                        inputBuffer.limit(inputBuffer.limit() + nRead);
1021:                    } else {
1022:                        if ((-nRead) == Status.ETIMEDOUT
1023:                                || (-nRead) == Status.TIMEUP) {
1024:                            return false;
1025:                        } else {
1026:                            throw new IOException(sm
1027:                                    .getString("ajpprotocol.failedread"));
1028:                        }
1029:                    }
1030:                }
1031:
1032:                return true;
1033:
1034:            }
1035:
1036:            /** Receive a chunk of data. Called to implement the
1037:             *  'special' packet in ajp13 and to receive the data
1038:             *  after we send a GET_BODY packet
1039:             */
1040:            public boolean receive() throws IOException {
1041:
1042:                first = false;
1043:                bodyMessage.reset();
1044:                readMessage(bodyMessage, false, false);
1045:
1046:                // No data received.
1047:                if (bodyMessage.getLen() == 0) {
1048:                    // just the header
1049:                    // Don't mark 'end of stream' for the first chunk.
1050:                    return false;
1051:                }
1052:                int blen = bodyMessage.peekInt();
1053:                if (blen == 0) {
1054:                    return false;
1055:                }
1056:
1057:                bodyMessage.getBytes(bodyBytes);
1058:                empty = false;
1059:                return true;
1060:            }
1061:
1062:            /**
1063:             * Get more request body data from the web server and store it in the
1064:             * internal buffer.
1065:             *
1066:             * @return true if there is more data, false if not.
1067:             */
1068:            private boolean refillReadBuffer() throws IOException {
1069:                // If the server returns an empty packet, assume that that end of
1070:                // the stream has been reached (yuck -- fix protocol??).
1071:                // FORM support
1072:                if (replay) {
1073:                    endOfStream = true; // we've read everything there is
1074:                }
1075:                if (endOfStream) {
1076:                    return false;
1077:                }
1078:
1079:                // Request more data immediately
1080:                Socket.sendb(socket, getBodyMessageBuffer, 0,
1081:                        getBodyMessageBuffer.position());
1082:
1083:                boolean moreData = receive();
1084:                if (!moreData) {
1085:                    endOfStream = true;
1086:                }
1087:                return moreData;
1088:            }
1089:
1090:            /**
1091:             * Read an AJP message.
1092:             *
1093:             * @param first is true if the message is the first in the request, which
1094:             *        will cause a short duration blocking read
1095:             * @return true if the message has been read, false if the short read
1096:             *         didn't return anything
1097:             * @throws IOException any other failure, including incomplete reads
1098:             */
1099:            protected boolean readMessage(AjpMessage message, boolean first,
1100:                    boolean useAvailableData) throws IOException {
1101:
1102:                byte[] buf = message.getBuffer();
1103:                int headerLength = message.getHeaderLength();
1104:
1105:                if (first) {
1106:                    if (!readt(headerLength, useAvailableData)) {
1107:                        return false;
1108:                    }
1109:                } else {
1110:                    read(headerLength);
1111:                }
1112:                inputBuffer.get(message.getBuffer(), 0, headerLength);
1113:                message.processHeader();
1114:                read(message.getLen());
1115:                inputBuffer.get(message.getBuffer(), headerLength, message
1116:                        .getLen());
1117:
1118:                return true;
1119:
1120:            }
1121:
1122:            /**
1123:             * Recycle the processor.
1124:             */
1125:            public void recycle() {
1126:
1127:                // Recycle Request object
1128:                first = true;
1129:                endOfStream = false;
1130:                empty = true;
1131:                replay = false;
1132:                finished = false;
1133:                request.recycle();
1134:                response.recycle();
1135:                certificates.recycle();
1136:
1137:                inputBuffer.clear();
1138:                inputBuffer.limit(0);
1139:                outputBuffer.clear();
1140:
1141:            }
1142:
1143:            /**
1144:             * Callback to write data from the buffer.
1145:             */
1146:            protected void flush() throws IOException {
1147:                if (outputBuffer.position() > 0) {
1148:                    if (Socket.sendbb(socket, 0, outputBuffer.position()) < 0) {
1149:                        throw new IOException(sm
1150:                                .getString("ajpprocessor.failedsend"));
1151:                    }
1152:                    outputBuffer.clear();
1153:                }
1154:            }
1155:
1156:            // ------------------------------------- InputStreamInputBuffer Inner Class
1157:
1158:            /**
1159:             * This class is an input buffer which will read its data from an input
1160:             * stream.
1161:             */
1162:            protected class SocketInputBuffer implements  InputBuffer {
1163:
1164:                /**
1165:                 * Read bytes into the specified chunk.
1166:                 */
1167:                public int doRead(ByteChunk chunk, Request req)
1168:                        throws IOException {
1169:
1170:                    if (endOfStream) {
1171:                        return -1;
1172:                    }
1173:                    if (first && req.getContentLengthLong() > 0) {
1174:                        // Handle special first-body-chunk
1175:                        if (!receive()) {
1176:                            return 0;
1177:                        }
1178:                    } else if (empty) {
1179:                        if (!refillReadBuffer()) {
1180:                            return -1;
1181:                        }
1182:                    }
1183:                    ByteChunk bc = bodyBytes.getByteChunk();
1184:                    chunk.setBytes(bc.getBuffer(), bc.getStart(), bc
1185:                            .getLength());
1186:                    empty = true;
1187:                    return chunk.getLength();
1188:
1189:                }
1190:
1191:            }
1192:
1193:            // ----------------------------------- OutputStreamOutputBuffer Inner Class
1194:
1195:            /**
1196:             * This class is an output buffer which will write data to an output
1197:             * stream.
1198:             */
1199:            protected class SocketOutputBuffer implements  OutputBuffer {
1200:
1201:                /**
1202:                 * Write chunk.
1203:                 */
1204:                public int doWrite(ByteChunk chunk, Response res)
1205:                        throws IOException {
1206:
1207:                    if (!response.isCommitted()) {
1208:                        // Validate and write response headers
1209:                        try {
1210:                            prepareResponse();
1211:                        } catch (IOException e) {
1212:                            // Set error flag
1213:                            error = true;
1214:                        }
1215:                    }
1216:
1217:                    int len = chunk.getLength();
1218:                    // 4 - hardcoded, byte[] marshalling overhead
1219:                    int chunkSize = Constants.MAX_SEND_SIZE;
1220:                    int off = 0;
1221:                    while (len > 0) {
1222:                        int this Time = len;
1223:                        if (this Time > chunkSize) {
1224:                            this Time = chunkSize;
1225:                        }
1226:                        len -= this Time;
1227:                        if (outputBuffer.position() + this Time
1228:                                + Constants.H_SIZE + 4 > outputBuffer
1229:                                .capacity()) {
1230:                            flush();
1231:                        }
1232:                        outputBuffer.put((byte) 0x41);
1233:                        outputBuffer.put((byte) 0x42);
1234:                        outputBuffer.putShort((short) (this Time + 4));
1235:                        outputBuffer.put(Constants.JK_AJP13_SEND_BODY_CHUNK);
1236:                        outputBuffer.putShort((short) this Time);
1237:                        outputBuffer.put(chunk.getBytes(), chunk.getOffset()
1238:                                + off, this Time);
1239:                        outputBuffer.put((byte) 0x00);
1240:                        off += thisTime;
1241:                    }
1242:
1243:                    return chunk.getLength();
1244:
1245:                }
1246:
1247:            }
1248:
1249:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.