Source Code Cross Referenced for HmuxRequest.java in  » EJB-Server-resin-3.1.5 » resin » com » caucho » server » hmux » 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 » EJB Server resin 3.1.5 » resin » com.caucho.server.hmux 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


0001:        /*
0002:         * Copyright (c) 1998-2008 Caucho Technology -- all rights reserved
0003:         *
0004:         * This file is part of Resin(R) Open Source
0005:         *
0006:         * Each copy or derived work must preserve the copyright notice and this
0007:         * notice unmodified.
0008:         *
0009:         * Resin Open Source is free software; you can redistribute it and/or modify
0010:         * it under the terms of the GNU General Public License as published by
0011:         * the Free Software Foundation; either version 2 of the License, or
0012:         * (at your option) any later version.
0013:         *
0014:         * Resin Open Source is distributed in the hope that it will be useful,
0015:         * but WITHOUT ANY WARRANTY; without even the implied warranty of
0016:         * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, or any warranty
0017:         * of NON-INFRINGEMENT.  See the GNU General Public License for more
0018:         * details.
0019:         *
0020:         * You should have received a copy of the GNU General Public License
0021:         * along with Resin Open Source; if not, write to the
0022:         *
0023:         *   Free Software Foundation, Inc.
0024:         *   59 Temple Place, Suite 330
0025:         *   Boston, MA 02111-1307  USA
0026:         *
0027:         * @author Scott Ferguson
0028:         */
0029:
0030:        package com.caucho.server.hmux;
0031:
0032:        import com.caucho.log.Log;
0033:        import com.caucho.server.cluster.BackingManager;
0034:        import com.caucho.server.cluster.Cluster;
0035:        import com.caucho.server.connection.AbstractHttpRequest;
0036:        import com.caucho.server.connection.Connection;
0037:        import com.caucho.server.dispatch.DispatchServer;
0038:        import com.caucho.server.dispatch.Invocation;
0039:        import com.caucho.server.dispatch.InvocationDecoder;
0040:        import com.caucho.server.http.InvocationKey;
0041:        import com.caucho.server.port.ServerRequest;
0042:        import com.caucho.server.webapp.ErrorPageManager;
0043:        import com.caucho.util.ByteBuffer;
0044:        import com.caucho.util.CharBuffer;
0045:        import com.caucho.util.CharSegment;
0046:        import com.caucho.vfs.ClientDisconnectException;
0047:        import com.caucho.vfs.ReadStream;
0048:        import com.caucho.vfs.StreamImpl;
0049:        import com.caucho.vfs.WriteStream;
0050:
0051:        import java.io.IOException;
0052:        import java.io.InputStream;
0053:        import java.io.InterruptedIOException;
0054:        import java.net.InetAddress;
0055:        import java.security.cert.CertificateFactory;
0056:        import java.security.cert.X509Certificate;
0057:        import java.util.ArrayList;
0058:        import java.util.Collections;
0059:        import java.util.Enumeration;
0060:        import java.util.HashSet;
0061:        import java.util.logging.Level;
0062:        import java.util.logging.Logger;
0063:
0064:        /**
0065:         * Handles requests from a remote dispatcher.  For example, mod_caucho
0066:         * and the IIS plugin use this protocol to talk to the backend.
0067:         *
0068:         * <p>Packets are straightforward:
0069:         * <pre>code l2 l1 l0 contents</pre>
0070:         * Where code is the code of the packet and l2-0 give 12 bits of length.
0071:         *
0072:         * <p>The protocol is designed to allow pipelining and buffering whenever
0073:         * possible.  So most commands are not acked.  Data from the frontend (POST)
0074:         * does need acks to prevent deadlocks at either end while waiting
0075:         * for new data.
0076:         *
0077:         * <p>The overriding protocol is controlled by requests from the
0078:         * frontend server.
0079:         * 
0080:         * <p>A ping request:
0081:         * <pre>
0082:         * Frontend       Backend
0083:         * CSE_PING
0084:         * CSE_END
0085:         *                CSE_END
0086:         * <pre>
0087:         * 
0088:         * <p>A GET request:
0089:         * <pre>
0090:         * Frontend       Backend
0091:         * CSE_METHOD
0092:         * ...
0093:         * CSE_HEADER/CSE_VALUE
0094:         * CSE_END
0095:         *                CSE_DATA
0096:         *                CSE_DATA
0097:         *                CSE_END
0098:         * <pre>
0099:         * 
0100:         * <p>Short POST:
0101:         * <pre>
0102:         * Frontend       Backend
0103:         * CSE_METHOD
0104:         * ...
0105:         * CSE_HEADER/CSE_VALUE
0106:         * CSE_DATA
0107:         * CSE_END
0108:         *                CSE_DATA
0109:         *                CSE_DATA
0110:         *                CSE_END
0111:         * <pre>
0112:         * 
0113:         * <p>Long POST:
0114:         * <pre>
0115:         * Frontend       Backend
0116:         * CSE_METHOD
0117:         * ...
0118:         * CSE_HEADER/CSE_VALUE
0119:         * CSE_DATA
0120:         *                CSE_DATA (optional)
0121:         * CSE_DATA
0122:         *                CSE_ACK
0123:         *                CSE_DATA (optional)
0124:         * CSE_DATA
0125:         *                CSE_ACK
0126:         * CSE_END
0127:         *                CSE_DATA
0128:         *                CSE_END
0129:         * <pre>
0130:         * 
0131:         */
0132:        public class HmuxRequest extends AbstractHttpRequest implements 
0133:                ServerRequest {
0134:            private static final Logger log = Logger
0135:                    .getLogger(HmuxRequest.class.getName());
0136:
0137:            // HMUX channel control codes
0138:            public static final int HMUX_CHANNEL = 'C';
0139:            public static final int HMUX_ACK = 'A';
0140:            public static final int HMUX_ERROR = 'E';
0141:            public static final int HMUX_YIELD = 'Y';
0142:            public static final int HMUX_QUIT = 'Q';
0143:            public static final int HMUX_EXIT = 'X';
0144:
0145:            public static final int HMUX_DATA = 'D';
0146:            public static final int HMUX_URI = 'U';
0147:            public static final int HMUX_STRING = 'S';
0148:            public static final int HMUX_HEADER = 'H';
0149:            public static final int HMUX_PROTOCOL = 'P';
0150:            public static final int HMUX_META_HEADER = 'M';
0151:
0152:            // The following are HTTP codes
0153:            public static final int CSE_NULL = '?';
0154:            public static final int CSE_PATH_INFO = 'b';
0155:            public static final int CSE_PROTOCOL = 'c';
0156:            public static final int CSE_REMOTE_USER = 'd';
0157:            public static final int CSE_QUERY_STRING = 'e';
0158:            public static final int HMUX_FLUSH = 'f';
0159:            public static final int CSE_SERVER_PORT = 'g';
0160:            public static final int CSE_REMOTE_HOST = 'h';
0161:            public static final int CSE_REMOTE_ADDR = 'i';
0162:            public static final int CSE_REMOTE_PORT = 'j';
0163:            public static final int CSE_REAL_PATH = 'k';
0164:            public static final int CSE_SCRIPT_FILENAME = 'l';
0165:            public static final int HMUX_METHOD = 'm';
0166:            public static final int CSE_AUTH_TYPE = 'n';
0167:            public static final int CSE_URI = 'o';
0168:            public static final int CSE_CONTENT_LENGTH = 'p';
0169:            public static final int CSE_CONTENT_TYPE = 'q';
0170:            public static final int CSE_IS_SECURE = 'r';
0171:            public static final int HMUX_STATUS = 's';
0172:            public static final int CSE_CLIENT_CERT = 't';
0173:            public static final int CSE_SERVER_TYPE = 'u';
0174:            public static final int HMUX_SERVER_NAME = 'v';
0175:
0176:            public static final int CSE_SEND_HEADER = 'G';
0177:
0178:            public static final int CSE_DATA = 'D';
0179:            public static final int CSE_FLUSH = 'F';
0180:            public static final int CSE_KEEPALIVE = 'K';
0181:            public static final int CSE_ACK = 'A';
0182:            public static final int CSE_END = 'Z';
0183:            public static final int CSE_CLOSE = 'X';
0184:
0185:            // other, specialized protocols
0186:            public static final int CSE_QUERY = 'Q';
0187:            public static final int CSE_PING = 'P';
0188:
0189:            public static final int HMUX_CLUSTER_PROTOCOL = 0x101;
0190:            public static final int HMUX_DISPATCH_PROTOCOL = 0x102;
0191:            public static final int HMUX_JMS_PROTOCOL = 0x103;
0192:
0193:            public enum ProtocolResult {
0194:                QUIT, EXIT, YIELD
0195:            };
0196:
0197:            static final int HTTP_0_9 = 0x0009;
0198:            static final int HTTP_1_0 = 0x0100;
0199:            static final int HTTP_1_1 = 0x0101;
0200:
0201:            private static final int HEADER_CAPACITY = 256;
0202:
0203:            static final CharBuffer _getCb = new CharBuffer("GET");
0204:            static final CharBuffer _headCb = new CharBuffer("HEAD");
0205:            static final CharBuffer _postCb = new CharBuffer("POST");
0206:
0207:            private final CharBuffer _method; // "GET"
0208:            private String _methodString; // "GET"
0209:            // private CharBuffer scheme;       // "http:"
0210:            private CharBuffer _host; // www.caucho.com
0211:            private int _port; // :80
0212:
0213:            private ByteBuffer _uri; // "/path/test.jsp/Junk"
0214:            private CharBuffer _protocol; // "HTTP/1.0"
0215:            private int _version;
0216:
0217:            private CharBuffer _remoteAddr;
0218:            private CharBuffer _remoteHost;
0219:            private CharBuffer _serverName;
0220:            private CharBuffer _serverPort;
0221:            private CharBuffer _remotePort;
0222:
0223:            private boolean _isSecure;
0224:            private ByteBuffer _clientCert;
0225:
0226:            private CharBuffer[] _headerKeys;
0227:            private CharBuffer[] _headerValues;
0228:            private int _headerSize;
0229:
0230:            private byte[] _lengthBuf;
0231:
0232:            private int _serverType;
0233:
0234:            // write stream from the connection
0235:            private WriteStream _rawWrite;
0236:            // servlet write stream
0237:            private WriteStream _writeStream;
0238:
0239:            // StreamImpl to break reads and writes to the underlying protocol
0240:            private ServletFilter _filter;
0241:            private int _pendingData;
0242:
0243:            private InvocationKey _invocationKey = new InvocationKey();
0244:
0245:            private CharBuffer _cb1;
0246:            private CharBuffer _cb2;
0247:            private boolean _hasRequest;
0248:
0249:            private AbstractClusterRequest _clusterRequest;
0250:            private HmuxDispatchRequest _dispatchRequest;
0251:            private BackingManager _backingManager;
0252:            private Cluster _cluster;
0253:
0254:            private HmuxProtocol _hmuxProtocol;
0255:            private ErrorPageManager _errorManager = new ErrorPageManager();
0256:
0257:            private int _srunIndex;
0258:
0259:            public HmuxRequest(DispatchServer server, Connection conn,
0260:                    HmuxProtocol protocol) {
0261:                super (server, conn);
0262:
0263:                _hmuxProtocol = protocol;
0264:
0265:                _response = new HmuxResponse(this );
0266:
0267:                _rawWrite = conn.getWriteStream();
0268:                _writeStream = new WriteStream();
0269:                _writeStream.setReuseBuffer(true);
0270:
0271:                // XXX: response.setIgnoreClientDisconnect(server.getIgnoreClientDisconnect());
0272:
0273:                _cluster = Cluster.getLocal();
0274:                if (_cluster != null) {
0275:                    try {
0276:                        Class cl = Class
0277:                                .forName("com.caucho.server.hmux.HmuxClusterRequest");
0278:
0279:                        _clusterRequest = (AbstractClusterRequest) cl
0280:                                .newInstance();
0281:                        _clusterRequest.setRequest(this );
0282:                        _clusterRequest.setCluster(_cluster);
0283:                    } catch (ClassNotFoundException e) {
0284:                        log.finer(e.toString());
0285:                    } catch (Throwable e) {
0286:                        log.log(Level.FINER, e.toString(), e);
0287:                    }
0288:                }
0289:
0290:                _dispatchRequest = new HmuxDispatchRequest(this );
0291:
0292:                _uri = new ByteBuffer();
0293:
0294:                _method = new CharBuffer();
0295:                _host = new CharBuffer();
0296:                _protocol = new CharBuffer();
0297:
0298:                _headerKeys = new CharBuffer[HEADER_CAPACITY];
0299:                _headerValues = new CharBuffer[_headerKeys.length];
0300:                for (int i = 0; i < _headerKeys.length; i++) {
0301:                    _headerKeys[i] = new CharBuffer();
0302:                    _headerValues[i] = new CharBuffer();
0303:                }
0304:
0305:                _remoteHost = new CharBuffer();
0306:                _remoteAddr = new CharBuffer();
0307:                _serverName = new CharBuffer();
0308:                _serverPort = new CharBuffer();
0309:                _remotePort = new CharBuffer();
0310:
0311:                _clientCert = new ByteBuffer();
0312:
0313:                _cb1 = new CharBuffer();
0314:                _cb2 = new CharBuffer();
0315:
0316:                _lengthBuf = new byte[16];
0317:
0318:                _filter = new ServletFilter();
0319:            }
0320:
0321:            public boolean isWaitForRead() {
0322:                return true;
0323:            }
0324:
0325:            /**
0326:             * Handles a new request.  Initializes the protocol handler and
0327:             * the request streams.
0328:             *
0329:             * <p>Note: ClientDisconnectException must be rethrown to
0330:             * the caller.
0331:             */
0332:            public boolean handleRequest() throws IOException {
0333:                // XXX: should be moved to TcpConnection
0334:                Thread thread = Thread.currentThread();
0335:                thread.setContextClassLoader(_server.getClassLoader());
0336:
0337:                if (log.isLoggable(Level.FINE))
0338:                    log.fine(dbgId() + "start request");
0339:
0340:                _filter.init(this , _rawRead, _rawWrite);
0341:                _writeStream.init(_filter);
0342:                // _writeStream.setWritePrefix(3);
0343:
0344:                _response.init(_writeStream);
0345:
0346:                _serverType = 0;
0347:                _uri.setLength(0);
0348:
0349:                boolean hasRequest = false;
0350:
0351:                try {
0352:                    start();
0353:                    _response.start();
0354:
0355:                    try {
0356:                        if (!scanHeaders()) {
0357:                            killKeepalive();
0358:                            return false;
0359:                        } else if (_uri.size() == 0) {
0360:                            return true;
0361:                        }
0362:                    } catch (InterruptedIOException e) {
0363:                        killKeepalive();
0364:                        log.fine(dbgId() + "interrupted keepalive");
0365:                        return false;
0366:                    }
0367:
0368:                    if (_isSecure)
0369:                        getClientCertificate();
0370:
0371:                    hasRequest = true;
0372:                    // setStartDate();
0373:
0374:                    if (_server == null || _server.isDestroyed()) {
0375:                        log.fine(dbgId() + "server is closed");
0376:
0377:                        try {
0378:                            _writeStream.setDisableClose(false);
0379:                            _writeStream.close();
0380:                        } catch (Throwable e) {
0381:                        }
0382:
0383:                        try {
0384:                            _readStream.setDisableClose(false);
0385:                            _readStream.close();
0386:                        } catch (Throwable e) {
0387:                        }
0388:
0389:                        return false;
0390:                    }
0391:
0392:                    _filter.setPending(_pendingData);
0393:
0394:                    try {
0395:                        if (_method.getLength() == 0)
0396:                            throw new RuntimeException(
0397:                                    "HTTP protocol exception");
0398:
0399:                        _invocationKey.init(_isSecure, getHost(),
0400:                                getServerPort(), _uri.getBuffer(), _uri
0401:                                        .getLength());
0402:
0403:                        Invocation invocation;
0404:
0405:                        invocation = _server.getInvocation(_invocationKey);
0406:
0407:                        if (invocation == null) {
0408:                            invocation = _server.createInvocation();
0409:
0410:                            if (_host != null)
0411:                                invocation.setHost(_host.toString());
0412:
0413:                            invocation.setPort(getServerPort());
0414:
0415:                            InvocationDecoder decoder = _server
0416:                                    .getInvocationDecoder();
0417:
0418:                            decoder.splitQueryAndUnescape(invocation, _uri
0419:                                    .getBuffer(), _uri.getLength());
0420:
0421:                            invocation = _server.buildInvocation(_invocationKey
0422:                                    .clone(), invocation);
0423:                        }
0424:
0425:                        invocation = invocation.getRequestInvocation(this );
0426:
0427:                        setInvocation(invocation);
0428:
0429:                        invocation.service(this , _response);
0430:                    } catch (ClientDisconnectException e) {
0431:                        throw e;
0432:                    } catch (Throwable e) {
0433:                        try {
0434:                            _errorManager.sendServletError(e, this , _response);
0435:                        } catch (ClientDisconnectException e1) {
0436:                            throw e1;
0437:                        } catch (Exception e1) {
0438:                            log.log(Level.FINE, e1.toString(), e1);
0439:                        }
0440:
0441:                        return false;
0442:                    }
0443:                } finally {
0444:                    if (!hasRequest)
0445:                        _response.setHeaderWritten(true);
0446:
0447:                    try {
0448:                        finish();
0449:                        _response.finish();
0450:                    } catch (ClientDisconnectException e) {
0451:                        throw e;
0452:                    } catch (Exception e) {
0453:                        killKeepalive();
0454:                        log.log(Level.FINE, dbgId() + e, e);
0455:                    }
0456:
0457:                    try {
0458:                        _writeStream.setDisableClose(false);
0459:                        _writeStream.close();
0460:                    } catch (ClientDisconnectException e) {
0461:                        killKeepalive();
0462:                        log.log(Level.FINE, dbgId() + e, e);
0463:
0464:                        throw e;
0465:                    } catch (Exception e) {
0466:                        killKeepalive();
0467:                        log.log(Level.FINE, dbgId() + e, e);
0468:                    }
0469:
0470:                    try {
0471:                        _readStream.setDisableClose(false);
0472:                        _readStream.close();
0473:                    } catch (Exception e) {
0474:                        killKeepalive();
0475:                        log.log(Level.FINE, dbgId() + e, e);
0476:                    }
0477:                }
0478:
0479:                boolean allowKeepalive = isKeepalive();
0480:
0481:                if (log.isLoggable(Level.FINE)) {
0482:                    if (allowKeepalive)
0483:                        log.fine(dbgId() + "complete request - keepalive");
0484:                    else
0485:                        log.fine(dbgId() + "complete request");
0486:                }
0487:
0488:                return allowKeepalive;
0489:            }
0490:
0491:            /**
0492:             * Initialize the read stream from the raw stream.
0493:             */
0494:            protected boolean initStream(ReadStream readStream,
0495:                    ReadStream rawStream) throws IOException {
0496:                readStream.init(_filter, null);
0497:
0498:                return true;
0499:            }
0500:
0501:            private void getClientCertificate() {
0502:                String cipher = getHeader("SSL_CIPHER");
0503:                if (cipher == null)
0504:                    cipher = getHeader("HTTPS_CIPHER");
0505:                if (cipher != null)
0506:                    setAttribute("javax.servlet.request.cipher_suite", cipher);
0507:
0508:                String keySize = getHeader("SSL_CIPHER_USEKEYSIZE");
0509:                if (keySize == null)
0510:                    keySize = getHeader("SSL_SECRETKEYSIZE");
0511:                if (keySize != null)
0512:                    setAttribute("javax.servlet.request.key_size", keySize);
0513:
0514:                if (_clientCert.size() == 0)
0515:                    return;
0516:
0517:                try {
0518:                    CertificateFactory cf = CertificateFactory
0519:                            .getInstance("X.509");
0520:                    InputStream is = _clientCert.createInputStream();
0521:                    Object cert = cf.generateCertificate(is);
0522:                    is.close();
0523:                    setAttribute("javax.servlet.request.X509Certificate", cert);
0524:                    setAttribute(
0525:                            com.caucho.server.security.AbstractAuthenticator.LOGIN_NAME,
0526:                            ((X509Certificate) cert).getSubjectDN());
0527:                } catch (Throwable e) {
0528:                    log.log(Level.FINE, e.toString(), e);
0529:                }
0530:            }
0531:
0532:            /**
0533:             * Returns true for the top-level request, but false for any include()
0534:             * or forward()
0535:             */
0536:            public boolean isTop() {
0537:                return true;
0538:            }
0539:
0540:            protected boolean checkLogin() {
0541:                return true;
0542:            }
0543:
0544:            /**
0545:             * Clears variables at the start of a new request.
0546:             */
0547:            protected void start() throws IOException {
0548:                super .start();
0549:
0550:                _method.clear();
0551:                _methodString = null;
0552:                _protocol.clear();
0553:                _version = 0;
0554:                _uri.clear();
0555:                _host.clear();
0556:                _port = 0;
0557:
0558:                _headerSize = 0;
0559:
0560:                _remoteHost.clear();
0561:                _remoteAddr.clear();
0562:                _serverName.clear();
0563:                _serverPort.clear();
0564:                _remotePort.clear();
0565:
0566:                _clientCert.clear();
0567:
0568:                _pendingData = 0;
0569:
0570:                _isSecure = _conn.isSecure();
0571:            }
0572:
0573:            /**
0574:             * Fills request parameters from the stream.
0575:             */
0576:            private boolean scanHeaders() throws IOException {
0577:                boolean hasURI = false;
0578:                CharBuffer cb = _cb;
0579:                boolean isLoggable = log.isLoggable(Level.FINE);
0580:                ReadStream is = _rawRead;
0581:                int code;
0582:                int len;
0583:
0584:                while (true) {
0585:                    code = is.read();
0586:
0587:                    switch (code) {
0588:                    case -1:
0589:                        if (isLoggable)
0590:                            log.fine(dbgId() + "end of file");
0591:                        return false;
0592:
0593:                    case HMUX_CHANNEL:
0594:                        int channel = (is.read() << 8) + is.read();
0595:
0596:                        if (isLoggable)
0597:                            log.fine(dbgId() + "channel " + channel);
0598:                        break;
0599:
0600:                    case HMUX_QUIT:
0601:                        if (isLoggable)
0602:                            log
0603:                                    .fine(dbgId() + (char) code
0604:                                            + ": end of request");
0605:
0606:                        return hasURI;
0607:
0608:                    case HMUX_EXIT:
0609:                        if (isLoggable)
0610:                            log.fine(dbgId() + (char) code + ": end of socket");
0611:
0612:                        killKeepalive();
0613:
0614:                        return hasURI;
0615:
0616:                    case HMUX_PROTOCOL:
0617:                        len = (is.read() << 8) + is.read();
0618:
0619:                        if (len != 4) {
0620:                            log.fine(dbgId() + (char) code
0621:                                    + ": protocol length (" + len
0622:                                    + ") must be 4.");
0623:                            killKeepalive();
0624:                            return false;
0625:                        }
0626:
0627:                        int value = ((is.read() << 24) + (is.read() << 16)
0628:                                + (is.read() << 8) + (is.read()));
0629:
0630:                        int result = HMUX_EXIT;
0631:                        boolean isKeepalive = false;
0632:                        if (value == HMUX_CLUSTER_PROTOCOL) {
0633:                            if (isLoggable)
0634:                                log.fine(dbgId() + (char) code
0635:                                        + ": cluster protocol");
0636:                            _filter.setClientClosed(true);
0637:
0638:                            if (_server == null || _server.isDestroyed()) {
0639:                                return false;
0640:                            }
0641:
0642:                            result = _clusterRequest.handleRequest(is,
0643:                                    _rawWrite);
0644:                        } else if (value == HMUX_DISPATCH_PROTOCOL) {
0645:                            if (isLoggable)
0646:                                log.fine(dbgId() + (char) code
0647:                                        + ": dispatch protocol");
0648:                            _filter.setClientClosed(true);
0649:
0650:                            if (_server == null || _server.isDestroyed()) {
0651:                                return false;
0652:                            }
0653:
0654:                            isKeepalive = _dispatchRequest.handleRequest(is,
0655:                                    _rawWrite);
0656:
0657:                            if (isKeepalive)
0658:                                result = HMUX_QUIT;
0659:                            else
0660:                                result = HMUX_EXIT;
0661:                        } else {
0662:                            if (_server == null || _server.isDestroyed()) {
0663:                                return false;
0664:                            }
0665:
0666:                            HmuxExtension ext = _hmuxProtocol
0667:                                    .getExtension(value);
0668:
0669:                            if (ext != null) {
0670:                                if (isLoggable)
0671:                                    log.fine(dbgId() + (char) code
0672:                                            + ": extension " + ext);
0673:                                _filter.setClientClosed(true);
0674:
0675:                                result = ext.handleRequest(this , is, _rawWrite);
0676:                            } else {
0677:                                log.fine(dbgId() + (char) code
0678:                                        + ": unknown protocol (" + value + ")");
0679:                                result = HMUX_EXIT;
0680:                            }
0681:                        }
0682:
0683:                        if (result == HMUX_YIELD)
0684:                            break;
0685:                        else {
0686:                            if (result == HMUX_QUIT && !allowKeepalive())
0687:                                result = HMUX_EXIT;
0688:
0689:                            if (result == HMUX_QUIT) {
0690:                                _rawWrite.write(HMUX_QUIT);
0691:                                _rawWrite.flush();
0692:                            } else {
0693:                                _rawWrite.write(HMUX_EXIT);
0694:                                _rawWrite.close();
0695:                            }
0696:
0697:                            return result == HMUX_QUIT;
0698:                        }
0699:
0700:                    case HMUX_URI:
0701:                        hasURI = true;
0702:                        len = (is.read() << 8) + is.read();
0703:                        _uri.setLength(len);
0704:                        _rawRead.readAll(_uri.getBuffer(), 0, len);
0705:                        if (isLoggable)
0706:                            log.fine(dbgId() + (char) code + ":uri " + _uri);
0707:                        break;
0708:
0709:                    case HMUX_METHOD:
0710:                        len = (is.read() << 8) + is.read();
0711:                        is.readAll(_method, len);
0712:                        if (isLoggable)
0713:                            log.fine(dbgId() + (char) code + ":method "
0714:                                    + _method);
0715:                        break;
0716:
0717:                    case CSE_REAL_PATH:
0718:                        len = (is.read() << 8) + is.read();
0719:                        _cb1.clear();
0720:                        _rawRead.readAll(_cb1, len);
0721:                        code = _rawRead.read();
0722:                        if (code != HMUX_STRING)
0723:                            throw new IOException(
0724:                                    "protocol expected HMUX_STRING");
0725:                        _cb2.clear();
0726:                        _rawRead.readAll(_cb2, readLength());
0727:
0728:                        //http.setRealPath(cb1.toString(), cb2.toString());
0729:                        if (isLoggable)
0730:                            log.fine(dbgId() + (char) code + " "
0731:                                    + _cb1.toString() + "->" + _cb2.toString());
0732:                        //throw new RuntimeException();
0733:                        break;
0734:
0735:                    case CSE_REMOTE_HOST:
0736:                        len = (is.read() << 8) + is.read();
0737:                        _rawRead.readAll(_remoteHost, len);
0738:                        if (isLoggable)
0739:                            log.fine(dbgId() + (char) code + " " + _remoteHost);
0740:                        break;
0741:
0742:                    case CSE_REMOTE_ADDR:
0743:                        len = (is.read() << 8) + is.read();
0744:                        _rawRead.readAll(_remoteAddr, len);
0745:                        if (isLoggable)
0746:                            log.fine(dbgId() + (char) code + " " + _remoteAddr);
0747:                        break;
0748:
0749:                    case HMUX_SERVER_NAME:
0750:                        len = (is.read() << 8) + is.read();
0751:                        _rawRead.readAll(_serverName, len);
0752:                        if (isLoggable)
0753:                            log.fine(dbgId() + (char) code + " server-host: "
0754:                                    + _serverName);
0755:                        break;
0756:
0757:                    case CSE_REMOTE_PORT:
0758:                        len = (is.read() << 8) + is.read();
0759:                        _rawRead.readAll(_remotePort, len);
0760:                        if (isLoggable)
0761:                            log.fine(dbgId() + (char) code + " remote-port: "
0762:                                    + _remotePort);
0763:                        break;
0764:
0765:                    case CSE_SERVER_PORT:
0766:                        len = (is.read() << 8) + is.read();
0767:                        _rawRead.readAll(_serverPort, len);
0768:                        if (isLoggable)
0769:                            log.fine(dbgId() + (char) code + " server-port: "
0770:                                    + _serverPort);
0771:                        break;
0772:
0773:                    case CSE_QUERY_STRING:
0774:                        len = (is.read() << 8) + is.read();
0775:                        if (len > 0) {
0776:                            _uri.add('?');
0777:                            _uri.ensureCapacity(_uri.getLength() + len);
0778:                            _rawRead.readAll(_uri.getBuffer(),
0779:                                    _uri.getLength(), len);
0780:                            _uri.setLength(_uri.getLength() + len);
0781:                        }
0782:                        break;
0783:
0784:                    case CSE_PROTOCOL:
0785:                        len = (is.read() << 8) + is.read();
0786:                        _rawRead.readAll(_protocol, len);
0787:                        if (isLoggable)
0788:                            log.fine(dbgId() + (char) code + " protocol: "
0789:                                    + _protocol);
0790:                        for (int i = 0; i < len; i++) {
0791:                            char ch = _protocol.charAt(i);
0792:                            if (ch >= '0' && ch <= '9')
0793:                                _version = 16 * _version + ch - '0';
0794:                            else if (ch == '.')
0795:                                _version = 16 * _version;
0796:                        }
0797:                        break;
0798:
0799:                    case HMUX_HEADER:
0800:                        len = (is.read() << 8) + is.read();
0801:
0802:                        int headerSize = _headerSize;
0803:
0804:                        CharBuffer key = _headerKeys[headerSize];
0805:                        key.clear();
0806:
0807:                        CharBuffer valueCb = _headerValues[headerSize];
0808:                        valueCb.clear();
0809:
0810:                        _rawRead.readAll(key, len);
0811:                        code = _rawRead.read();
0812:                        if (code != HMUX_STRING)
0813:                            throw new IOException(
0814:                                    "protocol expected HMUX_STRING at "
0815:                                            + (char) code);
0816:                        _rawRead.readAll(valueCb, readLength());
0817:
0818:                        if (isLoggable)
0819:                            log.fine(dbgId() + "H " + key + "=" + valueCb);
0820:
0821:                        if (addHeaderInt(key.getBuffer(), 0, key.length(),
0822:                                valueCb)) {
0823:                            _headerSize++;
0824:                        }
0825:                        break;
0826:
0827:                    case CSE_CONTENT_LENGTH:
0828:                        len = (is.read() << 8) + is.read();
0829:                        if (_headerKeys.length <= _headerSize)
0830:                            resizeHeaders();
0831:                        _headerKeys[_headerSize].clear();
0832:                        _headerKeys[_headerSize].append("Content-Length");
0833:                        _headerValues[_headerSize].clear();
0834:                        _rawRead.readAll(_headerValues[_headerSize], len);
0835:
0836:                        if (isLoggable)
0837:                            log.fine(dbgId() + (char) code + " content-length="
0838:                                    + _headerValues[_headerSize]);
0839:                        _headerSize++;
0840:                        break;
0841:
0842:                    case CSE_CONTENT_TYPE:
0843:                        len = (is.read() << 8) + is.read();
0844:                        if (_headerKeys.length <= _headerSize)
0845:                            resizeHeaders();
0846:                        _headerKeys[_headerSize].clear();
0847:                        _headerKeys[_headerSize].append("Content-Type");
0848:                        _headerValues[_headerSize].clear();
0849:                        _rawRead.readAll(_headerValues[_headerSize], len);
0850:                        if (isLoggable)
0851:                            log.fine(dbgId() + (char) code + " content-type="
0852:                                    + _headerValues[_headerSize]);
0853:                        _headerSize++;
0854:                        break;
0855:
0856:                    case CSE_IS_SECURE:
0857:                        len = (is.read() << 8) + is.read();
0858:                        _isSecure = true;
0859:                        if (isLoggable)
0860:                            log.fine(dbgId() + "secure");
0861:                        _rawRead.skip(len);
0862:                        break;
0863:
0864:                    case CSE_CLIENT_CERT:
0865:                        len = (is.read() << 8) + is.read();
0866:                        _clientCert.clear();
0867:                        _clientCert.setLength(len);
0868:                        _rawRead.readAll(_clientCert.getBuffer(), 0, len);
0869:                        if (isLoggable)
0870:                            log.fine(dbgId() + (char) code + " cert="
0871:                                    + _clientCert + " len:" + len);
0872:                        break;
0873:
0874:                    case CSE_SERVER_TYPE:
0875:                        len = (is.read() << 8) + is.read();
0876:                        _cb1.clear();
0877:                        _rawRead.readAll(_cb1, len);
0878:                        if (isLoggable)
0879:                            log.fine(dbgId() + (char) code + " server=" + _cb1);
0880:                        if (_cb1.length() > 0)
0881:                            _serverType = _cb1.charAt(0);
0882:                        break;
0883:
0884:                    case CSE_REMOTE_USER:
0885:                        len = (is.read() << 8) + is.read();
0886:                        _cb.clear();
0887:                        _rawRead.readAll(_cb, len);
0888:                        if (isLoggable)
0889:                            log.fine(dbgId() + (char) code + " " + _cb);
0890:                        setAttribute(
0891:                                com.caucho.server.security.AbstractAuthenticator.LOGIN_NAME,
0892:                                new com.caucho.security.BasicPrincipal(_cb
0893:                                        .toString()));
0894:                        break;
0895:
0896:                    case CSE_DATA:
0897:                        len = (is.read() << 8) + is.read();
0898:                        _pendingData = len;
0899:                        if (isLoggable)
0900:                            log.fine(dbgId() + (char) code + " post-data: "
0901:                                    + len);
0902:                        return hasURI;
0903:
0904:                    default:
0905:                        len = (is.read() << 8) + is.read();
0906:
0907:                        if (isLoggable)
0908:                            log.fine(dbgId() + (char) code + " " + len);
0909:                        is.skip(len);
0910:                        break;
0911:                    }
0912:                }
0913:
0914:                // _filter.setClientClosed(true);
0915:
0916:                // return false;
0917:            }
0918:
0919:            private void resizeHeaders() {
0920:                CharBuffer[] newKeys = new CharBuffer[_headerSize * 2];
0921:                CharBuffer[] newValues = new CharBuffer[_headerSize * 2];
0922:
0923:                for (int i = 0; i < _headerSize; i++) {
0924:                    newKeys[i] = _headerKeys[i];
0925:                    newValues[i] = _headerValues[i];
0926:                }
0927:
0928:                for (int i = _headerSize; i < newKeys.length; i++) {
0929:                    newKeys[i] = new CharBuffer();
0930:                    newValues[i] = new CharBuffer();
0931:                }
0932:
0933:                _headerKeys = newKeys;
0934:                _headerValues = newValues;
0935:            }
0936:
0937:            private int readLength() throws IOException {
0938:                return ((_rawRead.read() << 8) + _rawRead.read());
0939:            }
0940:
0941:            /**
0942:             * Returns the header.
0943:             */
0944:            public String getMethod() {
0945:                if (_methodString == null) {
0946:                    CharSegment cb = getMethodBuffer();
0947:                    if (cb.length() == 0) {
0948:                        _methodString = "GET";
0949:                        return _methodString;
0950:                    }
0951:
0952:                    switch (cb.charAt(0)) {
0953:                    case 'G':
0954:                        _methodString = cb.equals(_getCb) ? "GET" : cb
0955:                                .toString();
0956:                        break;
0957:
0958:                    case 'H':
0959:                        _methodString = cb.equals(_headCb) ? "HEAD" : cb
0960:                                .toString();
0961:                        break;
0962:
0963:                    case 'P':
0964:                        _methodString = cb.equals(_postCb) ? "POST" : cb
0965:                                .toString();
0966:                        break;
0967:
0968:                    default:
0969:                        _methodString = cb.toString();
0970:                    }
0971:                }
0972:
0973:                return _methodString;
0974:
0975:            }
0976:
0977:            public CharSegment getMethodBuffer() {
0978:                return _method;
0979:            }
0980:
0981:            /**
0982:             * Returns a char buffer containing the host.
0983:             */
0984:            protected CharBuffer getHost() {
0985:                if (_host.length() > 0)
0986:                    return _host;
0987:
0988:                _host.append(_serverName);
0989:                _host.toLowerCase();
0990:
0991:                return _host;
0992:            }
0993:
0994:            public final byte[] getUriBuffer() {
0995:                return _uri.getBuffer();
0996:            }
0997:
0998:            public final int getUriLength() {
0999:                return _uri.getLength();
1000:            }
1001:
1002:            /**
1003:             * Returns the protocol.
1004:             */
1005:            public String getProtocol() {
1006:                return _protocol.toString();
1007:            }
1008:
1009:            public CharSegment getProtocolBuffer() {
1010:                return _protocol;
1011:            }
1012:
1013:            final int getVersion() {
1014:                return _version;
1015:            }
1016:
1017:            /**
1018:             * Returns true if the request is secure.
1019:             */
1020:            public boolean isSecure() {
1021:                return _isSecure;
1022:            }
1023:
1024:            /**
1025:             * Returns the header.
1026:             */
1027:            public String getHeader(String key) {
1028:                CharSegment buf = getHeaderBuffer(key);
1029:                if (buf != null)
1030:                    return buf.toString();
1031:                else
1032:                    return null;
1033:            }
1034:
1035:            public CharSegment getHeaderBuffer(String key) {
1036:                for (int i = 0; i < _headerSize; i++) {
1037:                    CharBuffer test = _headerKeys[i];
1038:
1039:                    if (test.equalsIgnoreCase(key))
1040:                        return _headerValues[i];
1041:                }
1042:
1043:                return null;
1044:            }
1045:
1046:            public CharSegment getHeaderBuffer(char[] buf, int length) {
1047:                for (int i = 0; i < _headerSize; i++) {
1048:                    CharBuffer test = _headerKeys[i];
1049:
1050:                    if (test.length() != length)
1051:                        continue;
1052:
1053:                    char[] keyBuf = test.getBuffer();
1054:                    int j;
1055:                    for (j = 0; j < length; j++) {
1056:                        char a = buf[j];
1057:                        char b = keyBuf[j];
1058:                        if (a == b)
1059:                            continue;
1060:
1061:                        if (a >= 'A' && a <= 'Z')
1062:                            a += 'a' - 'A';
1063:                        if (b >= 'A' && b <= 'Z')
1064:                            b += 'a' - 'A';
1065:                        if (a != b)
1066:                            break;
1067:                    }
1068:
1069:                    if (j == length)
1070:                        return _headerValues[i];
1071:                }
1072:
1073:                return null;
1074:            }
1075:
1076:            public void setHeader(String key, String value) {
1077:                if (_headerKeys.length <= _headerSize)
1078:                    resizeHeaders();
1079:
1080:                _headerKeys[_headerSize].clear();
1081:                _headerKeys[_headerSize].append(key);
1082:                _headerValues[_headerSize].clear();
1083:                _headerValues[_headerSize].append(value);
1084:                _headerSize++;
1085:            }
1086:
1087:            public void getHeaderBuffers(String key,
1088:                    ArrayList<CharSegment> values) {
1089:                CharBuffer cb = _cb;
1090:
1091:                cb.clear();
1092:                cb.append(key);
1093:
1094:                int size = _headerSize;
1095:                for (int i = 0; i < size; i++) {
1096:                    CharBuffer test = _headerKeys[i];
1097:                    if (test.equalsIgnoreCase(cb))
1098:                        values.add(_headerValues[i]);
1099:                }
1100:            }
1101:
1102:            public Enumeration getHeaderNames() {
1103:                HashSet<String> names = new HashSet<String>();
1104:                for (int i = 0; i < _headerSize; i++)
1105:                    names.add(_headerKeys[i].toString());
1106:
1107:                return Collections.enumeration(names);
1108:            }
1109:
1110:            /**
1111:             * Returns the URI for the request, special casing the IIS issues.
1112:             * Because IIS already escapes the URI before sending it, the URI
1113:             * needs to be re-escaped.
1114:             */
1115:            public String getRequestURI() {
1116:                if (_serverType == 'R')
1117:                    return super .getRequestURI();
1118:
1119:                String _rawURI = super .getRequestURI();
1120:                CharBuffer cb = CharBuffer.allocate();
1121:
1122:                for (int i = 0; i < _rawURI.length(); i++) {
1123:                    char ch = _rawURI.charAt(i);
1124:
1125:                    if (ch <= ' ' || ch >= 0x80 || ch == '%') {
1126:                        addHex(cb, ch);
1127:                    } else
1128:                        cb.append(ch);
1129:                }
1130:
1131:                return cb.close();
1132:            }
1133:
1134:            /**
1135:             * Adds a hex escape.
1136:             *
1137:             * @param cb the char buffer containing the escape.
1138:             * @param ch the character to be escaped.
1139:             */
1140:            private void addHex(CharBuffer cb, int ch) {
1141:                cb.append('%');
1142:
1143:                int d = (ch >> 4) & 0xf;
1144:                if (d < 10)
1145:                    cb.append((char) ('0' + d));
1146:                else
1147:                    cb.append((char) ('a' + d - 10));
1148:
1149:                d = ch & 0xf;
1150:                if (d < 10)
1151:                    cb.append((char) ('0' + d));
1152:                else
1153:                    cb.append((char) ('a' + d - 10));
1154:            }
1155:
1156:            /**
1157:             * Returns the server name.
1158:             */
1159:            public String getServerName() {
1160:                CharBuffer host = getHost();
1161:                if (host == null) {
1162:                    InetAddress addr = getConnection().getRemoteAddress();
1163:                    return addr.getHostName();
1164:                }
1165:
1166:                int p = host.indexOf(':');
1167:                if (p >= 0)
1168:                    return host.substring(0, p);
1169:                else
1170:                    return host.toString();
1171:            }
1172:
1173:            public int getServerPort() {
1174:                int len = _serverPort.length();
1175:                int port = 0;
1176:                for (int i = 0; i < len; i++) {
1177:                    char ch = _serverPort.charAt(i);
1178:                    port = 10 * port + ch - '0';
1179:                }
1180:
1181:                return port;
1182:            }
1183:
1184:            public String getRemoteAddr() {
1185:                return _remoteAddr.toString();
1186:            }
1187:
1188:            public void getRemoteAddr(CharBuffer cb) {
1189:                cb.append(_remoteAddr);
1190:            }
1191:
1192:            public int printRemoteAddr(byte[] buffer, int offset)
1193:                    throws IOException {
1194:                char[] buf = _remoteAddr.getBuffer();
1195:                int len = _remoteAddr.getLength();
1196:
1197:                for (int i = 0; i < len; i++)
1198:                    buffer[offset + i] = (byte) buf[i];
1199:
1200:                return offset + len;
1201:            }
1202:
1203:            public String getRemoteHost() {
1204:                return _remoteHost.toString();
1205:            }
1206:
1207:            /**
1208:             * Called for a connection: close
1209:             */
1210:            protected void connectionClose() {
1211:                // ignore for hmux
1212:            }
1213:
1214:            // Response data
1215:            void writeStatus(CharBuffer message) throws IOException {
1216:                int channel = 2;
1217:
1218:                WriteStream os = _rawWrite;
1219:
1220:                os.write(HMUX_CHANNEL);
1221:                os.write(channel >> 8);
1222:                os.write(channel);
1223:
1224:                writeString(HMUX_STATUS, message);
1225:            }
1226:
1227:            /**
1228:             * Complete sending of all headers.
1229:             */
1230:            void sendHeader() throws IOException {
1231:                writeString(CSE_SEND_HEADER, "");
1232:            }
1233:
1234:            /**
1235:             * Writes a header to the plugin.
1236:             *
1237:             * @param key the header's key
1238:             * @param value the header's value
1239:             */
1240:            void writeHeader(String key, String value) throws IOException {
1241:                writeString(HMUX_HEADER, key);
1242:                writeString(HMUX_STRING, value);
1243:            }
1244:
1245:            /**
1246:             * Writes a header to the plugin.
1247:             *
1248:             * @param key the header's key
1249:             * @param value the header's value
1250:             */
1251:            void writeHeader(String key, CharBuffer value) throws IOException {
1252:                writeString(HMUX_HEADER, key);
1253:                writeString(HMUX_STRING, value);
1254:            }
1255:
1256:            void writeString(int code, String value) throws IOException {
1257:                int len = value.length();
1258:
1259:                WriteStream os = _rawWrite;
1260:
1261:                os.write(code);
1262:                os.write(len >> 8);
1263:                os.write(len);
1264:                os.print(value);
1265:
1266:                if (log.isLoggable(Level.FINE))
1267:                    log.fine(dbgId() + (char) code + " " + value);
1268:            }
1269:
1270:            void writeString(int code, CharBuffer cb) throws IOException {
1271:                int len = cb.length();
1272:
1273:                WriteStream os = _rawWrite;
1274:
1275:                os.write(code);
1276:                os.write(len >> 8);
1277:                os.write(len);
1278:                os.print(cb.getBuffer(), 0, len);
1279:
1280:                if (log.isLoggable(Level.FINE))
1281:                    log.fine(dbgId() + (char) code + " " + cb);
1282:            }
1283:
1284:            public void protocolCloseEvent() {
1285:            }
1286:
1287:            public final String dbgId() {
1288:                String id = _server.getServerId();
1289:
1290:                if (id.equals(""))
1291:                    return "Hmux[" + getConnection().getId() + "] ";
1292:                else
1293:                    return "Hmux[" + id + ":" + getConnection().getId() + "] ";
1294:            }
1295:
1296:            public String toString() {
1297:                return "HmuxRequest" + dbgId();
1298:            }
1299:
1300:            /**
1301:             * Implements the protocol for data reads and writes.  Data from the
1302:             * web server to the JVM must be acked, except for the first data.
1303:             * Data back to the web server needs no ack.
1304:             */
1305:            static class ServletFilter extends StreamImpl {
1306:                HmuxRequest _request;
1307:                ReadStream _is;
1308:                WriteStream _os;
1309:                byte[] _buffer = new byte[16];
1310:                int _pendingData;
1311:                boolean _needsAck;
1312:                boolean _isClosed;
1313:                boolean _isClientClosed;
1314:
1315:                ServletFilter() {
1316:                }
1317:
1318:                void init(HmuxRequest request, ReadStream nextRead,
1319:                        WriteStream nextWrite) {
1320:                    _request = request;
1321:                    _is = nextRead;
1322:                    _os = nextWrite;
1323:                    _pendingData = 0;
1324:                    _isClosed = false;
1325:                    _isClientClosed = false;
1326:                    _needsAck = false;
1327:                }
1328:
1329:                void setPending(int pendingData) {
1330:                    _pendingData = pendingData;
1331:                }
1332:
1333:                void setClientClosed(boolean isClientClosed) {
1334:                    _isClientClosed = isClientClosed;
1335:                }
1336:
1337:                public boolean canRead() {
1338:                    return true;
1339:                }
1340:
1341:                public int getAvailable() {
1342:                    return _pendingData;
1343:                }
1344:
1345:                /**
1346:                 * Reads available data.  If the data needs an ack, then do so.
1347:                 */
1348:                public int read(byte[] buf, int offset, int length)
1349:                        throws IOException {
1350:                    int sublen = _pendingData;
1351:                    ReadStream is = _is;
1352:
1353:                    if (sublen <= 0)
1354:                        return -1;
1355:
1356:                    if (length < sublen)
1357:                        sublen = length;
1358:
1359:                    int readLen = is.read(buf, offset, sublen);
1360:                    _pendingData -= readLen;
1361:
1362:                    if (log.isLoggable(Level.FINEST))
1363:                        log.finest(new String(buf, offset, readLen));
1364:
1365:                    while (_pendingData == 0) {
1366:                        if (_needsAck) {
1367:                            int channel = 2;
1368:
1369:                            _os.write(HMUX_ACK);
1370:                            _os.write(channel >> 8);
1371:                            _os.write(channel);
1372:
1373:                            if (log.isLoggable(Level.FINE))
1374:                                log.fine(_request.dbgId() + "A:ack channel 2");
1375:                        }
1376:
1377:                        _needsAck = false;
1378:
1379:                        int code = is.read();
1380:
1381:                        if (code == HMUX_DATA) {
1382:                            int len = (is.read() << 8) + is.read();
1383:
1384:                            if (log.isLoggable(Level.FINE))
1385:                                log.fine(_request.dbgId() + "D:post-data "
1386:                                        + len);
1387:
1388:                            _pendingData = len;
1389:                        } else if (code == HMUX_QUIT) {
1390:                            if (log.isLoggable(Level.FINE))
1391:                                log.fine(_request.dbgId() + "Q:quit");
1392:
1393:                            return readLen;
1394:                        } else if (code == HMUX_EXIT) {
1395:                            if (log.isLoggable(Level.FINE))
1396:                                log.fine(_request.dbgId() + "X:exit");
1397:
1398:                            _request.killKeepalive();
1399:                            return readLen;
1400:                        } else if (code == HMUX_YIELD) {
1401:                            _needsAck = true;
1402:                        } else if (code == HMUX_CHANNEL) {
1403:                            int channel = (is.read() << 8) + is.read();
1404:
1405:                            if (log.isLoggable(Level.FINE))
1406:                                log.fine(_request.dbgId() + "channel "
1407:                                        + channel);
1408:                        } else if (code < 0) {
1409:                            _request.killKeepalive();
1410:
1411:                            return readLen;
1412:                        } else {
1413:                            _request.killKeepalive();
1414:
1415:                            int len = (is.read() << 8) + is.read();
1416:
1417:                            if (log.isLoggable(Level.FINE))
1418:                                log.fine(_request.dbgId() + "unknown `"
1419:                                        + (char) code + "' " + len);
1420:
1421:                            is.skip(len);
1422:                        }
1423:                    }
1424:
1425:                    return readLen;
1426:                }
1427:
1428:                public boolean canWrite() {
1429:                    return true;
1430:                }
1431:
1432:                /**
1433:                 * Send data back to the web server
1434:                 */
1435:                public void write(byte[] buf, int offset, int length,
1436:                        boolean isEnd) throws IOException {
1437:                    if (log.isLoggable(Level.FINE)) {
1438:                        log.fine(_request.dbgId() + (char) HMUX_DATA + ":data "
1439:                                + length);
1440:
1441:                        if (log.isLoggable(Level.FINEST))
1442:                            log.finest(_request.dbgId() + "data <"
1443:                                    + new String(buf, offset, length) + ">");
1444:                    }
1445:
1446:                    byte[] tempBuf = _buffer;
1447:
1448:                    while (length > 0) {
1449:                        int sublen = length;
1450:
1451:                        if (32 * 1024 < sublen)
1452:                            sublen = 32 * 1024;
1453:
1454:                        // The 3 bytes are already allocated by setPrefixWrite
1455:                        tempBuf[0] = HMUX_DATA;
1456:                        tempBuf[1] = (byte) (sublen >> 8);
1457:                        tempBuf[2] = (byte) sublen;
1458:
1459:                        _os.write(tempBuf, 0, 3);
1460:                        _os.write(buf, offset, sublen);
1461:
1462:                        length -= sublen;
1463:                        offset += sublen;
1464:                    }
1465:                }
1466:
1467:                public void flush() throws IOException {
1468:                    if (log.isLoggable(Level.FINE))
1469:                        log.fine(_request.dbgId() + (char) HMUX_FLUSH
1470:                                + ":flush");
1471:
1472:                    _os.write(HMUX_FLUSH);
1473:                    _os.write(0);
1474:                    _os.write(0);
1475:                    _os.flush();
1476:                }
1477:
1478:                public void close() throws IOException {
1479:                    if (_isClosed)
1480:                        return;
1481:
1482:                    _isClosed = true;
1483:
1484:                    if (_pendingData > 0) {
1485:                        _is.skip(_pendingData);
1486:                        _pendingData = 0;
1487:                    }
1488:
1489:                    boolean keepalive = _request.allowKeepalive();
1490:
1491:                    if (!_isClientClosed) {
1492:                        if (log.isLoggable(Level.FINE)) {
1493:                            if (keepalive)
1494:                                log.fine(_request.dbgId() + (char) HMUX_QUIT
1495:                                        + ": quit channel");
1496:                            else
1497:                                log.fine(_request.dbgId() + (char) HMUX_EXIT
1498:                                        + ": exit socket");
1499:                        }
1500:
1501:                        if (keepalive)
1502:                            _os.write(HMUX_QUIT);
1503:                        else
1504:                            _os.write(HMUX_EXIT);
1505:                    }
1506:
1507:                    if (keepalive)
1508:                        _os.flush();
1509:                    else
1510:                        _os.close();
1511:                    //nextRead.close();
1512:                }
1513:            }
1514:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.