Source Code Cross Referenced for Client.java in  » Web-Server » Jigsaw » org » w3c » jigsaw » http » 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 » Web Server » Jigsaw » org.w3c.jigsaw.http 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


0001:        // Client.java
0002:        // $Id: Client.java,v 1.80 2004/08/30 16:04:44 ylafon Exp $
0003:        // (c) COPYRIGHT MIT and INRIA, 1996.
0004:        // Please first read the full copyright statement in file COPYRIGHT.html
0005:
0006:        package org.w3c.jigsaw.http;
0007:
0008:        import java.io.DataOutputStream;
0009:        import java.io.InputStream;
0010:        import java.io.IOException;
0011:        import java.io.PipedInputStream;
0012:        import java.io.InterruptedIOException;
0013:
0014:        import java.net.InetAddress;
0015:        import java.net.URL;
0016:
0017:        import org.w3c.www.http.HTTP;
0018:        import org.w3c.www.http.HttpParserException;
0019:
0020:        import org.w3c.www.mime.MimeParser;
0021:        import org.w3c.www.mime.MimeParserException;
0022:        import org.w3c.www.mime.MimeParserFactory;
0023:
0024:        import org.w3c.tools.resources.ProtocolException;
0025:        import org.w3c.tools.resources.ResourceException;
0026:
0027:        import org.w3c.tools.timers.EventHandler;
0028:
0029:        import org.w3c.jigsaw.servlet.JigsawHttpServletResponse;
0030:        import org.w3c.jigsaw.servlet.ServletWrapper;
0031:
0032:        /**
0033:         * The request timeout event, to be delivered by the timer package.
0034:         * Handling timers is expensive, and can be a bottleneck, this is the only
0035:         * event Jigsaw will set during processing a request.
0036:         * No other timeing events are used (ie closing a persistent connection is
0037:         * not triggered by some timing, but rather by the load of the server).
0038:         */
0039:
0040:        class RequestTimeout {
0041:            Client client = null;
0042:
0043:            RequestTimeout(Client client) {
0044:                this .client = client;
0045:            }
0046:        }
0047:
0048:        /**
0049:         * Client instances keep track of a specific connection with a browser.
0050:         * This abstract class is responsible for handling an HTTP connection, as
0051:         * described by an input and output stream, from right after the connection
0052:         * is accepted, until the connection has to be shutdown. It provides
0053:         * all the methods to run the HTTP dialog, and leave it to subclasses to
0054:         * implement the accept connection and the persistent connections strategy.
0055:         * <p>Customizing this class is done by subclassing it, and implementing
0056:         * the abstract methods.
0057:         * <p>For sample implementations, you can check the socket and mux sub
0058:         * packages.
0059:         * @see ClientFactory
0060:         * @see org.w3c.jigsaw.http.socket.SocketClient
0061:         * @see org.w3c.jigsaw.http.mux.MuxClient
0062:         */
0063:
0064:        public abstract class Client implements  EventHandler {
0065:            private static final boolean debuglog = false;
0066:            private final static byte hexaTable[] = { (byte) '0', (byte) '1',
0067:                    (byte) '2', (byte) '3', (byte) '4', (byte) '5', (byte) '6',
0068:                    (byte) '7', (byte) '8', (byte) '9', (byte) 'A', (byte) 'B',
0069:                    (byte) 'C', (byte) 'D', (byte) 'E', (byte) 'F' };
0070:            /**
0071:             * The continue reply, if ever needed is created only once.
0072:             */
0073:            private Reply contreply = null;
0074:            /**
0075:             * The Mime factory instance we use to create requests.
0076:             */
0077:            private MimeParserFactory factory = null;
0078:            /**
0079:             * The uniq integer identifier for that client.
0080:             */
0081:            protected int identifier = -1;
0082:            /**
0083:             * The server context responsible for that client.
0084:             */
0085:            protected httpd server = null;
0086:            /**
0087:             * Is this client in debug mode ?
0088:             */
0089:            protected boolean debug = false;
0090:            /**
0091:             * The buffer used to emit copy data back to the client.
0092:             */
0093:            protected byte buffer[] = null;
0094:            /**
0095:             * Is this client currently <em>running</em>.
0096:             * A client starts <em>running</em> when its <code>startConnection</code>
0097:             * method is invoked, with the HTTP transport streams. It stops running
0098:             * either because of an interruption, triggered by a call to 
0099:             * <code>interruptConnection</code> or by the <code>idleConnection</code>,
0100:             * returning <strong>true</strong>, or because the connection has to be 
0101:             * closed.
0102:             * <p>In all these cases, the <code>stopConnection</code> method is 
0103:             * invoked.
0104:             */
0105:            private boolean running = false;
0106:            /**
0107:             * When runnin, the HTTP major version used to discuss with that client.
0108:             */
0109:            private short major = -1;
0110:            /**
0111:             * WHen running, the HTTP minor version used to discuss with that client.
0112:             */
0113:            private short minor = -1;
0114:            /**
0115:             * When running, the input stream from which this client gets HTTP.
0116:             */
0117:            private InputStream input = null;
0118:            /**
0119:             * When running, the output stream to which this client emits HTTP.
0120:             */
0121:            private DataOutputStream output = null;
0122:            /**
0123:             * When processing a request, the handle to the pending timer.
0124:             */
0125:            private Object timer = null;
0126:            /**
0127:             * When running, the Mime parser instance to parse current input stream.
0128:             */
0129:            private MimeParser parser = null;
0130:            /**
0131:             * When running, the interrupt flag.
0132:             */
0133:            private boolean interrupted = false;
0134:            /**
0135:             * Number of requests handled within this client context.
0136:             */
0137:            protected int reqcount = 0;
0138:
0139:            /**
0140:             * flags to avoid multiple 100-Continue during multiple stages of a 
0141:             * request 
0142:             */
0143:            protected boolean cont = false;
0144:            /**
0145:             * The number of bytes in the body of the previously handled request
0146:             */
0147:            protected long prev_body_count = 0;
0148:            /**
0149:             * HTTP lenient mode?
0150:             */
0151:            private boolean lenient = true;
0152:
0153:            /**
0154:             * the current URI
0155:             */
0156:            public URL currentURI = null;
0157:            /**
0158:             * timeout on IO?
0159:             */
0160:            private boolean timedout;
0161:
0162:            /**
0163:             * Sets this client next timer. 
0164:             * Timers are used only to limit the duration of a request processing.
0165:             * Only one timer can be pending at any time for a given client, 
0166:             * setting some new timer if one is already pending will kill
0167:             * the previous one.
0168:             * @param ms The number of milliseconds after which the timer should
0169:             *    expire.
0170:             * @param data The call data for the tevent timer handler.
0171:             */
0172:
0173:            private synchronized void setTimeout(int ms, Object data) {
0174:                if (timer != null) {
0175:                    server.timer.recallTimer(timer);
0176:                    timer = null;
0177:                }
0178:                timer = server.timer.registerTimer(ms, this , data);
0179:            }
0180:
0181:            /**
0182:             * Remove any pending timer.
0183:             */
0184:
0185:            private synchronized void removeTimeout() {
0186:                if (timer != null)
0187:                    server.timer.recallTimer(timer);
0188:            }
0189:
0190:            /**
0191:             * Handle timer events. 
0192:             * For the time being, timer events are only used
0193:             * to detect an overrunning request, so this handler just kills the 
0194:             * correponding client.
0195:             * @param data The timer closure.
0196:             * @param time The absolute time at which the event was triggered.
0197:             * @see org.w3c.tools.timers.EventManager
0198:             * @see org.w3c.tools.timers.EventHandler
0199:             */
0200:
0201:            public synchronized void handleTimerEvent(Object data, long time) {
0202:                timer = null;
0203:                // This request has taken to long to fullfill, abort it
0204:                Reply abort = new Reply(this );
0205:                abort.setStatus(HTTP.REQUEST_TIMEOUT);
0206:                interruptConnection(true);
0207:            }
0208:
0209:            /**
0210:             * Terminate the connection that is currently handled.
0211:             * This method closes the currently handled input and output stream, 
0212:             * removes any pending timers and cleanup the client state, so it is ready
0213:             * to handle any new connection.
0214:             * If the client is bound to a thread, the thread is throw an exception at
0215:             */
0216:
0217:            private synchronized void terminate() {
0218:                if (!running)
0219:                    return;
0220:                removeTimeout();
0221:                try {
0222:                    if (output != null) {
0223:                        output.flush();
0224:                        output.close();
0225:                    }
0226:                } catch (IOException ex) {
0227:                }
0228:                try {
0229:                    if (input != null)
0230:                        input.close();
0231:                } catch (IOException ex) {
0232:                }
0233:                input = null;
0234:                output = null;
0235:                parser = null;
0236:                major = -1;
0237:                minor = -1;
0238:                interrupted = false;
0239:                running = false;
0240:            }
0241:
0242:            /**
0243:             * Request has been processed into Reply, should we keep connection alive ?
0244:             * Test wether we can keep the connection alive, after the given
0245:             * reply has been emited. 
0246:             * @param request The request to examine.
0247:             * @param reply Its computed reply.
0248:             */
0249:
0250:            protected boolean tryKeepConnection(Request request, Reply reply) {
0251:                // The server doesn't want any keep connection
0252:                if (!server.getClientKeepConnection())
0253:                    return false;
0254:                if (!request.canKeepConnection()) {
0255:                    if (reply.tryKeepConnection()) {
0256:                        reply.addConnection("close");
0257:                    }
0258:                    return false;
0259:                }
0260:                return reply.tryKeepConnection();
0261:            }
0262:
0263:            /**
0264:             * Read the next request from our current input stream.
0265:             * @return a Request instance, or <strong>null</strong> if interrupted.
0266:             * @exception IOException If some IO error occured.
0267:             * @exception ClientException If either an IO error happened or bad
0268:             * HTTP was received. In both cases the connection needs to be closed.
0269:             */
0270:
0271:            protected Request getNextRequest() throws ClientException,
0272:                    IOException {
0273:                Request request = null;
0274:                cont = false; // reinit the continue
0275:                timedout = false;
0276:                try {
0277:                    request = (Request) parser.parse(lenient);
0278:                } catch (InterruptedIOException timex) {
0279:                    timedout = true;
0280:                    return null;
0281:                } catch (IOException ex) {
0282:                    // The connection has probably been closed prematurely:
0283:                    return null;
0284:                } catch (HttpParserException ex) {
0285:                    if (debug) {
0286:                        System.out.println("+++ " + this  + " got exception:");
0287:                        ex.printStackTrace();
0288:                    }
0289:                    throw new ClientException(this , ex);
0290:                } catch (MimeParserException ex) {
0291:                    if (debug) {
0292:                        System.out.println("+++ " + this  + " got exception:");
0293:                        ex.printStackTrace();
0294:                    }
0295:                    throw new ClientException(this , ex);
0296:                }
0297:                if (debug)
0298:                    request.dump(System.out);
0299:                return request;
0300:            }
0301:
0302:            /**
0303:             * Run chunk encoding on the provided stream to emit reply's body.
0304:             * @param is The reply's body that has to be chunk encoded.
0305:             * @exception IOException If IO error occurs.
0306:             */
0307:
0308:            protected int chunkTransfer(InputStream is, Reply reply)
0309:                    throws IOException {
0310:                byte zeroChunk[] = { ((byte) 48), ((byte) 13), ((byte) 10) };//0\r\n
0311:                byte crlf[] = { ((byte) 13), ((byte) 10) };
0312:                byte bheader[] = new byte[32];
0313:                int blen = 0;
0314:                int written = 0;
0315:                int got = 0;
0316:                int sgot;
0317:                String header = null;
0318:
0319:                try {
0320:                    // Emit the reply stream:
0321:                    while (got >= 0) {
0322:                        if (got == 0) {
0323:                            try {
0324:                                got = is.read(buffer);
0325:                            } catch (IOException ioex) {
0326:                                if (reply.hasState(ServletWrapper.RUNNER)
0327:                                        && (is instanceof  PipedInputStream)) {
0328:                                    // here, the problem may be that multiple
0329:                                    // threads are writing to the PipedOutputStream
0330:                                    // and the IOError may exists
0331:                                    if (!reply.hasState(ServletWrapper.ENDED)) {
0332:                                        got = 0;
0333:                                        continue;
0334:                                    }
0335:                                }
0336:                                throw ioex;
0337:                            }
0338:                            continue;
0339:                        }
0340:                        // Emit a full chunk: header first, followed by the body
0341:                        // we dump the hexa size of the header backward
0342:                        sgot = got;
0343:                        blen = 3;
0344:                        bheader[30] = ((byte) 13); // \r
0345:                        bheader[31] = ((byte) 10); // \n
0346:                        while (sgot > 15) {
0347:                            bheader[32 - blen] = hexaTable[sgot % 16];
0348:                            sgot >>= 4;
0349:                            blen++;
0350:                        }
0351:                        bheader[32 - blen] = hexaTable[sgot];
0352:                        output.write(bheader, 32 - blen, blen);
0353:                        output.write(buffer, 0, got);
0354:                        output.write(crlf, 0, 2);
0355:                        output.flush();
0356:                        written += (blen + got);
0357:                        try {
0358:                            got = is.read(buffer);
0359:                        } catch (IOException ioex) {
0360:                            if (reply.hasState(ServletWrapper.RUNNER)
0361:                                    && (is instanceof  PipedInputStream)) {
0362:                                // here, the problem may be that multiple
0363:                                // threads are writing to the PipedOutputStream
0364:                                // and the IOError may exists
0365:                                if (!reply.hasState(ServletWrapper.ENDED)) {
0366:                                    got = 0;
0367:                                    continue;
0368:                                }
0369:                            }
0370:                            throw ioex;
0371:                        }
0372:                    }
0373:                } catch (IOException ex) {
0374:                    // To cope with Java's exec bug 
0375:                    // Anyway, if this really fails, the output will fail below too
0376:                    if (debug) {
0377:                        ex.printStackTrace();
0378:                    }
0379:                }
0380:                // Emit the 0 chunk:
0381:                output.write(zeroChunk, 0, 3);
0382:                // FIXME trailers should be sent here
0383:                output.write(crlf, 0, 2);
0384:                output.flush();
0385:                return written + blen;
0386:            }
0387:
0388:            /**
0389:             * Emit the given reply to the client.
0390:             * @param reply The reply to be emited.
0391:             * @return The number of body bytes emited, or <strong>-1</strong> if
0392:             * no bytes needed to be emitted.
0393:             * @exception IOException If some IO error occurs.
0394:             */
0395:
0396:            protected int emitReply(Reply reply) throws IOException {
0397:                boolean chunkable = false;
0398:                // Emit the reply if needed:
0399:                if (reply.getStatus() == HTTP.DONE)
0400:                    return -1;
0401:                InputStream is = reply.openStream();
0402:                if (is == null) {
0403:                    if (debug)
0404:                        reply.dump(System.out);
0405:                    reply.emit(output);
0406:                    return -1;
0407:                } else {
0408:                    chunkable = reply.canChunkTransfer();
0409:                    if (debug)
0410:                        reply.dump(System.out);
0411:                    if (reply.getStatus() != HTTP.NOHEADER)
0412:                        reply.emit(output);
0413:                }
0414:                // No shuffler available, perform the job ourselves.
0415:                if (buffer == null)
0416:                    buffer = new byte[getServer().getClientBufferSize()];
0417:                // Check if we can chunk the reply back:
0418:                int written = 0;
0419:                try {
0420:                    if (chunkable) {
0421:                        written = chunkTransfer(is, reply);
0422:                    } else {
0423:                        int got = 0;
0424:                        while (got >= 0) {
0425:                            output.write(buffer, 0, got);
0426:                            written += got;
0427:                            try {
0428:                                got = is.read(buffer, 0, buffer.length);
0429:                            } catch (IOException ioex) {
0430:                                if (reply.hasState(ServletWrapper.RUNNER)
0431:                                        && (is instanceof  PipedInputStream)) {
0432:                                    // here, the problem may be that multiple
0433:                                    // threads are writing to the PipedOutputStream
0434:                                    // and the IOError may exists
0435:                                    if (!reply.hasState(ServletWrapper.ENDED)) {
0436:                                        got = 0;
0437:                                        continue;
0438:                                    }
0439:                                }
0440:                                throw ioex;
0441:                            }
0442:                        }
0443:                    }
0444:                } finally {
0445:                    is.close();
0446:                }
0447:                return written;
0448:            }
0449:
0450:            /**
0451:             * Process a request.
0452:             * This methods processs the request to the point that a reply is 
0453:             * available. This methods sets a timeout, to limit the duration of this 
0454:             * request processing. 
0455:             * @param request The request to process.
0456:             * @exception ClientException If either the timeout expires or the entity
0457:             *     was unable to handle the request.
0458:             */
0459:
0460:            protected Reply processRequest(Request request)
0461:                    throws ClientException {
0462:                Reply reply = null;
0463:                setTimeout(server.getRequestTimeOut(), new RequestTimeout(this ));
0464:                try {
0465:                    reply = (Reply) server.perform(request);
0466:                } catch (ProtocolException ex) {
0467:                    if (debug) {
0468:                        System.out.println("+++ " + this  + " got exception:");
0469:                        ex.printStackTrace();
0470:                    }
0471:                    if ((reply != null) && reply.hasStream()) {
0472:                        try {
0473:                            reply.openStream().close();
0474:                        } catch (Exception cex) {
0475:                        }
0476:                    }
0477:                    if (ex.hasReply()) {
0478:                        return (Reply) ex.getReply();
0479:                    } else {
0480:                        throw new ClientException(this , ex);
0481:                    }
0482:                } catch (ResourceException ex2) {
0483:                    throw new ClientException(this , ex2);
0484:                }
0485:                if (reply == null) {
0486:                    String errmsg = "target resource emited a null Reply.";
0487:                    throw new ClientException(this , errmsg);
0488:                }
0489:                reqcount++;
0490:                return reply;
0491:            }
0492:
0493:            /**
0494:             * Start processing the given connection.
0495:             * This is the entry point for sub classes, in order to make the client
0496:             * start processing the HTTP protocol on the given input and output
0497:             * streams.
0498:             * <p>Before this method returns, both provided streams are <em>always
0499:             * </em> closed, and the <code>stopConnection</code> method invoked.
0500:             * @param in The input stream to receive HTTP requests.
0501:             * @param out The output stream to send HTTP replies.
0502:             * @return A boolean <strong>true</strong> if this method returns because
0503:             * of an interruption, <strong>false</strong> otherwsie (ie the connection
0504:             * was gracefully shutdown).
0505:             * @exception ClientException If some severe error has occured and the
0506:             * current connection needs to be terminated.
0507:             */
0508:
0509:            protected boolean startConnection(InputStream in,
0510:                    DataOutputStream out) throws ClientException {
0511:                boolean keep = true;
0512:                long tstart = 0;
0513:                long tend = 0;
0514:                Request request = null;
0515:                Reply reply = null;
0516:                int sent = 0;
0517:                int processed = 0;
0518:                ClientException err = null;
0519:
0520:                this .input = in;
0521:                this .output = out;
0522:                this .parser = new MimeParser(input, factory);
0523:                try {
0524:                    running = true;
0525:                    alive_loop: while ((!interrupted) && keep) {
0526:                        // Get the next available request, and  mark client as used:
0527:                        try {
0528:                            // mark the stream, if some bytes are to be eaten
0529:                            if (prev_body_count > 0) {
0530:                                input.mark(2048);
0531:                            }
0532:                            if (processed == 0) {
0533:                                // Always run for the first request, 
0534:                                // update client's infos
0535:                                if ((request = getNextRequest()) == null)
0536:                                    break alive_loop;
0537:                                major = request.getMajorVersion();
0538:                                minor = request.getMinorVersion();
0539:                            } else {
0540:                                if (interrupted = idleConnection())
0541:                                    break alive_loop;
0542:                                while ((request = getNextRequest()) == null) {
0543:                                    if (timedout) {
0544:                                        continue;
0545:                                    } else {
0546:                                        break alive_loop;
0547:                                    }
0548:                                }
0549:                                // the gateway case, the major/minor _may_ change
0550:                                major = request.getMajorVersion();
0551:                                minor = request.getMinorVersion();
0552:                                usedConnection();
0553:                            }
0554:                        } catch (ClientException cex) {
0555:                            if (cex.ex != null
0556:                                    && (cex.ex instanceof  HttpParserException)) {
0557:                                HttpParserException hex = (HttpParserException) cex.ex;
0558:                                if (!hex.hasRequest()) {
0559:                                    throw (cex);
0560:                                }
0561:                                request = (Request) hex.getRequest();
0562:                                if (processed == 0) {
0563:                                    major = request.getMajorVersion();
0564:                                    minor = request.getMinorVersion();
0565:                                }
0566:                                usedConnection();
0567:                                reply = (Reply) request.makeBadRequestReply();
0568:                                reply.setContentLength(0);
0569:                                reply.addConnection("close");
0570:                                // Inital keep alive check, emit the reply:
0571:                                keep = false;
0572:                                sent = emitReply(reply);
0573:                                // Semi-fake log entry
0574:                                log(request, reply, 0, 0);
0575:                                processed++;
0576:                                // a bad request is still a request...
0577:                                reqcount++;
0578:                                break alive_loop;
0579:                            } else if (cex.ex != null
0580:                                    && (cex.ex instanceof  MimeParserException)) {
0581:                                reply = new Reply(this );
0582:                                reply.setStatus(HTTP.BAD_REQUEST);
0583:                                reply.setContentLength(0);
0584:                                reply.addConnection("close");
0585:                                keep = false;
0586:                                sent = emitReply(reply);
0587:                                // Semi-fake log entry
0588:                                log(request, reply, 0, 0);
0589:                                processed++;
0590:                                // a bad request is still a request...
0591:                                reqcount++;
0592:                                break alive_loop;
0593:                            }
0594:                            throw (cex);
0595:                        } catch (Exception genex) {
0596:                            if (debug)
0597:                                genex.printStackTrace();
0598:                            // some bytes may have to be eaten
0599:                            // abomination, very ugly hack!
0600:                            if (genex.getMessage().startsWith("Bad request")
0601:                                    && (prev_body_count > 0)) {
0602:                                // check if the error is due to a
0603:                                usedConnection();
0604:                                if (debug)
0605:                                    System.out.println("Error after a body "
0606:                                            + "request! (Skipping: "
0607:                                            + prev_body_count + " bytes)");
0608:                                // now try to eat some data...
0609:                                input.reset();
0610:                                byte b[] = new byte[(int) prev_body_count];
0611:                                prev_body_count -= input.read(b);
0612:                                prev_body_count -= input.skip(prev_body_count);
0613:                                break alive_loop;
0614:                            }
0615:                            throw (genex);
0616:                        }
0617:                        // Some traces if required:
0618:                        if (debuglog)
0619:                            System.out.println(this  + ": request "
0620:                                    + request.getURL());
0621:                        // Process request, and time it:
0622:                        currentURI = request.getURL();
0623:                        tstart = System.currentTimeMillis();
0624:                        reply = processRequest(request);
0625:                        tend = System.currentTimeMillis();
0626:                        currentURI = null;
0627:                        // Inital keep alive check, emit the reply:
0628:                        if (keep)
0629:                            keep = tryKeepConnection(request, reply);
0630:                        sent = emitReply(reply);
0631:                        // Second keep alive check:
0632:                        if (reply.hasContentLength() && (sent >= 0)
0633:                                && (reply.getContentLength() != sent))
0634:                            keep = false;
0635:                        // Log and/or traces:
0636:                        if (debuglog)
0637:                            System.out.println(this  + ", cl="
0638:                                    + reply.getContentLength() + ", size="
0639:                                    + sent);
0640:                        // will be -1 if there is no body
0641:                        prev_body_count = request.getContentLength();
0642:                        log(request, reply, sent, tend - tstart);
0643:                        processed++;
0644:                        // If we can keep alive, and if the client doesn't do
0645:                        // pipelining, be clever:
0646:                        // We should compare against 0 here, we use 2 because of a
0647:                        // well-known client bug, that emits an extra CRLF at the end
0648:                        // of forms POSTing
0649:                        // Note we're doing that very last, so that if the socket is 
0650:                        // closed by peer, we really have *already* done everything
0651:                        if (keep /*&& (in.available() <= 2)*/)
0652:                            output.flush();
0653:                        // be clever again... in case of protocol switching,
0654:                        // we must free everything and let the other client use the
0655:                        // streams
0656:                        if (reply.getStatus() == HTTP.SWITCHING) {
0657:                            input = null;
0658:                            output = null;
0659:                            throw new Exception("Switching");
0660:                        }
0661:                        // hack for servlets
0662:                        if (request.hasState(JigsawHttpServletResponse.STREAM)) {
0663:                            try {
0664:                                PipedInputStream pis;
0665:                                pis = (PipedInputStream) request
0666:                                        .getState(JigsawHttpServletResponse.STREAM);
0667:                                pis.close();
0668:                            } catch (ClassCastException ccex) {
0669:                                // do nothing
0670:                            } catch (IOException pisioex) {
0671:                                // fail silently also
0672:                            }
0673:                        }
0674:                    }
0675:                } catch (IOException ex) {
0676:                    if (debug) {
0677:                        System.out.println("+++ " + this  + " got IOException:");
0678:                        ex.printStackTrace();
0679:                    }
0680:                    // Close any stream pending
0681:                    try {
0682:                        InputStream i = null;
0683:                        if (reply != null) {
0684:                            if ((i = reply.openStream()) != null)
0685:                                i.close();
0686:                        }
0687:                    } catch (IOException ioex) {
0688:                    }
0689:                    err = new ClientException(this , ex);
0690:                } catch (ClientException ex) {
0691:                    if (debug) {
0692:                        System.out.println("+++ " + this 
0693:                                + " got ClientException:");
0694:                        ex.printStackTrace();
0695:                    }
0696:                    try {
0697:                        InputStream i = null;
0698:                        if (reply != null) {
0699:                            if ((i = reply.openStream()) != null)
0700:                                i.close();
0701:                        }
0702:                    } catch (IOException ioex) {
0703:                    }
0704:                    err = ex;
0705:                } catch (NullPointerException nex) {
0706:                    if (debug) {
0707:                        System.out.println("+++ " + this  + " got exception:");
0708:                        nex.printStackTrace();
0709:                    }
0710:                    if (currentURI != null) {
0711:                        err = new ClientException(this , nex, currentURI
0712:                                .toString());
0713:                    } else {
0714:                        err = new ClientException(this , nex);
0715:                    }
0716:                } catch (Exception ex) {
0717:                    if (debug) {
0718:                        System.out.println("+++ " + this  + " got exception:");
0719:                        ex.printStackTrace();
0720:                    }
0721:                    err = new ClientException(this , ex);
0722:                } finally {
0723:                    currentURI = null;
0724:                    // Absorb incoming data to avoid RST TCP packets:
0725:                    if ((err == null) && (request != null)
0726:                            && (request.getContentLength() > 0)
0727:                            && (reply != null)
0728:                            && (reply.getStatus() != HTTP.SWITCHING)
0729:                            && (reply.getStatus() / 100 != 2)) {
0730:                        // The request may have failed...
0731:                        try {
0732:                            InputStream i = request.getInputStream();
0733:                            if (i != null) {
0734:                                while (i.available() > 0)
0735:                                    i.read(buffer, 0, buffer.length);
0736:                            }
0737:                        } catch (Exception ex) {
0738:                        }
0739:                    }
0740:                    if ((request != null)
0741:                            && (request
0742:                                    .hasState(JigsawHttpServletResponse.STREAM))) {
0743:                        try {
0744:                            PipedInputStream pis;
0745:                            pis = (PipedInputStream) request
0746:                                    .getState(JigsawHttpServletResponse.STREAM);
0747:                            pis.close();
0748:                        } catch (ClassCastException ccex) {
0749:                            // do nothing
0750:                        } catch (IOException pisioex) {
0751:                            // fail silently also
0752:                        } catch (Exception ex) {
0753:                            // be sure not to cause any trouble :)
0754:                        }
0755:                    }
0756:                    terminate();
0757:                    if (reply == null || (reply.getStatus() != HTTP.SWITCHING)) {
0758:                        stopConnection();
0759:                        if (reply != null) {
0760:                            try {
0761:                                reply.openStream().close();
0762:                            } catch (Exception roex) {
0763:                            }
0764:                            ;
0765:                        }
0766:                    }
0767:                    if (err != null)
0768:                        throw err;
0769:                }
0770:                return interrupted;
0771:            }
0772:
0773:            /**
0774:             * Interrupt the currently handled connection.
0775:             * This method will make best effort to interrupt any thread currently
0776:             * processing the connection.
0777:             * @param now Make sure the thread is interrupted right now if 
0778:             * <strong>true</strong>, otherwise, just schedule an interruption
0779:             * after the current request (if any) has been processed.
0780:             */
0781:
0782:            protected synchronized void interruptConnection(boolean now) {
0783:                if (running) {
0784:                    interrupted = true;
0785:                    if (now)
0786:                        terminate();
0787:                }
0788:            }
0789:
0790:            /**
0791:             * Send a 100 HTTP continue message on the currently handled connection.
0792:             * This method will take care of creating the appropriate HTTP
0793:             * continue reply, and will emit that reply only if the spoken HTTP
0794:             * version allows for it.
0795:             * @exception IOException If some IO error occured.
0796:             */
0797:
0798:            public int sendContinue() throws IOException {
0799:                if (cont)
0800:                    return -1;
0801:                if ((major > 1) || ((major == 1) && (minor >= 1))) {
0802:                    if (contreply == null)
0803:                        contreply = new Reply(this , null, major, minor,
0804:                                HTTP.CONTINUE);
0805:                    int len = emitReply(contreply);
0806:                    output.flush();
0807:                    cont = true;
0808:                    return len;
0809:                }
0810:                return -1;
0811:            }
0812:
0813:            /**
0814:             * Send a 100 HTTP continue message on the currently handled connection.
0815:             * This method will take care of creating the appropriate HTTP
0816:             * continue reply, and will emit that reply only if the spoken HTTP
0817:             * version allows for it.
0818:             * @exception IOException If some IO error occured.
0819:             */
0820:
0821:            public int sendContinue(Reply contReply) throws IOException {
0822:                if (contReply == null) {
0823:                    return sendContinue();
0824:                }
0825:                if ((major > 1) || ((major == 1) && (minor >= 1))) {
0826:                    int len = emitReply(contReply);
0827:                    output.flush();
0828:                    cont = true;
0829:                    return len;
0830:                }
0831:                return -1;
0832:            }
0833:
0834:            /**
0835:             * Get this client identifier.
0836:             * @return An integer identifying uniquely this client's context.
0837:             */
0838:
0839:            public final int getIdentifier() {
0840:                return identifier;
0841:            }
0842:
0843:            /**
0844:             * Is this client currently <em>running</em> for a connection.
0845:             * @return A boolean, <strong>true</strong> if it is, 
0846:             * <strong>false</strong> otherwise.
0847:             */
0848:
0849:            public final synchronized boolean isRunning() {
0850:                return running;
0851:            }
0852:
0853:            /**
0854:             * Get the HTTP major version number spoken on the current connection.
0855:             * @return The HTTP major version number, or <strong>-1</strong> if that
0856:             * client is not running.
0857:             */
0858:
0859:            public final short getMajorVersion() {
0860:                return major;
0861:            }
0862:
0863:            /**
0864:             * Get the HTTP minor version number spoken on the current connection.
0865:             * @return The HTTP minor version number, or <strong>-1</strong> if 
0866:             * that client is not running.
0867:             */
0868:
0869:            public final short getMinorVersion() {
0870:                return minor;
0871:            }
0872:
0873:            /**
0874:             * Does this client has an interrupt pending ?
0875:             * @return A boolean, <strong>true</strong> if an interrupt is pending,
0876:             * <strong>false</strong> otherwise.
0877:             */
0878:
0879:            public final boolean isInterrupted() {
0880:                return interrupted;
0881:            }
0882:
0883:            /**
0884:             * Get the total number of requests handled within this client context.
0885:             * @return An integer giving the number of requests handled.
0886:             */
0887:
0888:            public final int getRequestCount() {
0889:                return reqcount;
0890:            }
0891:
0892:            /**
0893:             * Get the server context responsible for this client context.
0894:             * @return An httpd instance.
0895:             */
0896:
0897:            public final httpd getServer() {
0898:                return server;
0899:            }
0900:
0901:            /**
0902:             * Emit an error message on behalf of that client.
0903:             * @param msg The error message to output.
0904:             */
0905:
0906:            public final void error(String msg) {
0907:                server.errlog(this , msg);
0908:            }
0909:
0910:            /**
0911:             * Emit a trace on behalf of the given client.
0912:             * @param msg The trace to output.
0913:             */
0914:
0915:            public final void trace(String msg) {
0916:                server.trace(this , msg);
0917:            }
0918:
0919:            /**
0920:             * Log the given HTTP transaction.
0921:             * @param request The request that has been processed.
0922:             * @param reply The generated reply.
0923:             * @param nbytes Number of content bytes sent along with the reply.
0924:             * @param duration The processing time for that request in milliseconds.
0925:             */
0926:
0927:            public void log(Request request, Reply reply, int nbytes,
0928:                    long duration) {
0929:                server.log(this , request, reply, nbytes, duration);
0930:            }
0931:
0932:            /**
0933:             * Get this client input stream.
0934:             * @return An instance of InputStream, or <strong>null</strong> if the 
0935:             * client is not handling any connection at that time.
0936:             */
0937:
0938:            public InputStream getInputStream() {
0939:                return input;
0940:            }
0941:
0942:            /**
0943:             * Get this client output stream.
0944:             * @return An instance of OutputStream, or <strong>null</strong> if the
0945:             * client is not handling any connection at that time.
0946:             */
0947:
0948:            public DataOutputStream getOutputStream() {
0949:                return output;
0950:            }
0951:
0952:            /**
0953:             * Get the IP address of the host that runs the client described by this
0954:             * context.
0955:             * @return An InetAddress instance, or <strong>null</strong> if that client
0956:             * is not handling any connection at that given time.
0957:             */
0958:
0959:            abstract public InetAddress getInetAddress();
0960:
0961:            /**
0962:             * Client callback - The client is about to block, getting next request.
0963:             * This method is triggered by the client instance itself, before
0964:             * reading next request from the input stream provided at
0965:             * <code>startConnection</code> time.
0966:             * @return A boolean, if <strong>true</strong>, the client will consider
0967:             * itself interrupted, and terminate the connection it is current handling.
0968:             */
0969:
0970:            abstract protected boolean idleConnection();
0971:
0972:            /**
0973:             * Client callback - A full request has been received on input stream.
0974:             * This method is called by the client itself, before starting processing
0975:             * the newly received request. The purpose of this callback is typically
0976:             * to mark that client <em>buzy</em>.
0977:             */
0978:
0979:            abstract protected void usedConnection();
0980:
0981:            /**
0982:             * Client callback -  The current connection has been terminated.
0983:             * This client has finished processing the connection provided
0984:             * at <code>startConnection</code> time, it is now stopped.
0985:             */
0986:
0987:            abstract protected void stopConnection();
0988:
0989:            /**
0990:             * Get the thread powering that client, if any.
0991:             * This method is called to kill the client (by interrupting the thread
0992:             * used to run it).
0993:             * @return A Thread instance, or <strong>null</strong>.
0994:             */
0995:
0996:            abstract protected Thread getThread();
0997:
0998:            /**
0999:             * Initialize this client.
1000:             * It is up to this method to initialize:
1001:             * <dl>
1002:             * <dt>parser<dd>The MimeParser to be used to parse incomminf requests.
1003:             * </dl>
1004:             * @param server The server responsible for that client.
1005:             * @param factory The factory that created this client.
1006:             * @param identifier The uniq identifier for this client.
1007:             */
1008:
1009:            protected void initialize(httpd server, int identifier) {
1010:                this.server = server;
1011:                this.lenient = server.isLenient();
1012:                this.identifier = identifier;
1013:                this.debug = server.getClientDebug();
1014:                this.factory = server.getMimeClientFactory(this);
1015:            }
1016:
1017:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.