Source Code Cross Referenced for Request.java in  » Web-Server » Brazil » sunlabs » brazil » server » 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 » Brazil » sunlabs.brazil.server 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


0001:        /*
0002:         * Request.java
0003:         *
0004:         * Brazil project web application Framework,
0005:         * export version: 1.1 
0006:         * Copyright (c) 1998-2000 Sun Microsystems, Inc.
0007:         *
0008:         * Sun Public License Notice
0009:         *
0010:         * The contents of this file are subject to the Sun Public License Version 
0011:         * 1.0 (the "License"). You may not use this file except in compliance with 
0012:         * the License. A copy of the License is included as the file "license.terms",
0013:         * and also available at http://www.sun.com/
0014:         * 
0015:         * The Original Code is from:
0016:         *    Brazil project web application Framework release 1.1.
0017:         * The Initial Developer of the Original Code is: suhler.
0018:         * Portions created by suhler are Copyright (C) Sun Microsystems, Inc.
0019:         * All Rights Reserved.
0020:         * 
0021:         * Contributor(s): cstevens, rinaldo, suhler.
0022:         *
0023:         * Version:  1.47
0024:         * Created by suhler on 98/09/14
0025:         * Last modified by suhler on 00/12/05 13:12:36
0026:         */
0027:
0028:        package sunlabs.brazil.server;
0029:
0030:        import sunlabs.brazil.util.http.HttpInputStream;
0031:        import sunlabs.brazil.util.http.HttpUtil;
0032:        import sunlabs.brazil.util.http.MimeHeaders;
0033:
0034:        import java.io.InputStream;
0035:        import java.io.BufferedInputStream;
0036:        import java.io.BufferedOutputStream;
0037:        import java.io.FilterOutputStream;
0038:        import java.io.OutputStream;
0039:        import java.io.IOException;
0040:        import java.net.Socket;
0041:        import java.util.Hashtable;
0042:        import java.util.Properties;
0043:        import java.util.StringTokenizer;
0044:
0045:        /**
0046:         * Represents an HTTP transaction.   A new instance is created
0047:         * by the server for each connection.
0048:         * <p>
0049:         * Provides a set of accessor functions to fetch the individual fields
0050:         * of the HTTP request.
0051:         * <p>
0052:         * Utility methods that are generically useful for manipulating HTTP
0053:         * requests are included here as well.  An instance of this class is
0054:         * passed to handlers.  There will be exactly one request object per thead
0055:         * at any time.
0056:         * <p>
0057:         * The fields
0058:         * {@link #headers}, 
0059:         * {@link #query}, and
0060:         * {@link #url}, and the method
0061:         * {@link #getQueryData()}
0062:         * are most often used to examine the content of the request.
0063:         * The field
0064:         * {@link #props}
0065:         * contains information about the server, or up-stream handlers.
0066:         * <p>
0067:         * The methods
0068:         * {@link #sendResponse(String, String, int)} and
0069:         * {@link Request#sendError(int, String)}
0070:         * are commonly used to return content to the client.  The methods
0071:         * {@link #addHeader(String)} and
0072:         * {@link #setStatus(int)} can be used to modify the response headers
0073:         * and return code respectively before the response is sent.
0074:         * <p>
0075:         * Many of the other methods are used internally, but can be useful to
0076:         * handlers that need finer control over the output that the above methods
0077:         * provide.  Note that the order of the methods is important.  For instance,
0078:         * the user cannot change the HTTP response headers (by calling the
0079:         * <code>addHeader</code> method or by modifying the
0080:         * <code>responseHeaders</code> field) after having already sent an HTTP
0081:         * response.
0082:         * <p>
0083:         * A number of the fields in the <code>Request</code> object are public,
0084:         * by design.  Many of the methods are convenience methods; the underlying
0085:         * data fields are meant to be accessed for more complicated operations,
0086:         * such as changing the URL or deleting HTTP response headers.  
0087:         *
0088:         * @see		Handler
0089:         * @see		Server
0090:         *
0091:         * @author	Stephen Uhler (stephen.uhler@sun.com)
0092:         * @author	Colin Stevens (colin.stevens@sun.com)
0093:         * @version	1.47, 00/12/05
0094:         */
0095:        public class Request {
0096:            Server server;
0097:            Socket sock;
0098:            HttpInputStream in;
0099:
0100:            /**
0101:             * A set of properties local to this request.  Created with
0102:             * <code>server.props</code> as the default.  This is useful for
0103:             * handlers that wish to communicate via properties to down-stream
0104:             * handlers, such as modifying a server property for a particular
0105:             * request.  
0106:             * <p>
0107:             * This variable is declared as a <code>Request.RechainableProperties</code>,
0108:             * which provides the ability to reorder the properties in an existing
0109:             * request, to insert a whole new set of properties into a request w/o
0110:             * having to copy those properties one by one into the request's
0111:             * properties.  If the user does not need this functionality, this
0112:             * variable may be accessed simply as a normal <code>Properties</code>.
0113:             */
0114:            public RechainableProperties props;
0115:
0116:            /**
0117:             * The HTTP response to the client is written to this stream.  Normally
0118:             * the convenience methods, such as <code>sendResponse</code>, are used
0119:             * to send the response, but this field is available if a handler
0120:             * needs to generate the response specially.
0121:             * <p>
0122:             * If the user chooses to write the response directly to this stream, the
0123:             * user is still encouraged to use the convenience methods, such as
0124:             * <code>sendHeaders</code>, to first send the HTTP response headers.
0125:             * The {@link sunlabs.brazil.filter.FilterHandler}
0126:             * examines the HTTP response headers
0127:             * set by the convenience methods to determine whether to filter the
0128:             * output.  
0129:             * <p>
0130:             * Note that the HTTP response headers will <b>not</b> automatically be
0131:             * sent as a side effect if the user writes to this stream.  The user
0132:             * would either need to call the convenience method
0133:             * <code>sendHeaders</code> or need to generate the HTTP response headers
0134:             * themselves.
0135:             * <p>
0136:             * This variable is declared as a <code>Request.HttpOutputStream</code>,
0137:             * which provides the convenience method <code>writeBytes</code> to write
0138:             * the byte representation of a string back to the client.  If the user
0139:             * does not need this functionality, this variable may be accessed
0140:             * simply as a normal <code>OutputStream</code>.
0141:             *
0142:             * @see	#sendResponse(String, String, int)
0143:             * @see	#sendHeaders(int, String, int)
0144:             */
0145:            public HttpOutputStream out;
0146:
0147:            /*
0148:             * How many requests this <code>Request</code> will handle.  If this goes
0149:             * to 0, then the connection will be closed even if
0150:             * <code>keepAlive</code> is true.
0151:             */
0152:            private int requestsLeft;
0153:
0154:            //-----------------------------------------------------------------------
0155:
0156:            /**
0157:             * The HTTP request method, such as "GET", "POST", or "PUT".
0158:             */
0159:            public String method;
0160:
0161:            /**
0162:             * The URL specified in the request, not including any "?" query
0163:             * string.
0164:             */
0165:            public String url;
0166:
0167:            /**
0168:             * The query string specified after the URL, or <code>""</code> if no
0169:             * query string was specified.
0170:             */
0171:            public String query;
0172:
0173:            /**
0174:             * The HTTP protocol specified in the request, either "HTTP/1.0" or
0175:             * "HTTP/1.1".
0176:             *
0177:             * @see	#version
0178:             */
0179:            public String protocol;
0180:
0181:            /**
0182:             * Derived from {@link #protocol}, the version of the HTTP protocol
0183:             * used for this request.  Either <code>10</code> for "HTTP/1.0" or
0184:             * <code>11</code> for "HTTP/1.1".
0185:             */
0186:            public int version;
0187:
0188:            /**
0189:             * The HTTP request headers.  Keys and values in this table correspond
0190:             * the field names and values from each line in the HTTP header;
0191:             * field names are case-insensitive, but the case of the values is
0192:             * preserved.  The order of entries in this table corresponds to the
0193:             * order in which the request headers were seen.  Multiple header lines
0194:             * with the same key are stored as separate entries in the table.
0195:             */
0196:            public MimeHeaders headers;
0197:
0198:            /**
0199:             * The uploaded content of this request, usually from a POST.  Set to
0200:             * <code>null</code> if the request has no content.
0201:             */
0202:            public byte[] postData;
0203:
0204:            /**
0205:             * <code>true</code> if the client requested a persistent connection,
0206:             * <code>false</code> otherwise.  Derived from the {@link #protocol} and
0207:             * the {@link #headers},
0208:             * <p>
0209:             * When "Keep-Alive" is requested, the client can issue multiple,
0210:             * consecutive requests via a single socket connection.  By default: <ul>
0211:             * <li> HTTP/1.0 requests are not Keep-Alive, unless the
0212:             * "Connection: Keep-Alive" header was present.
0213:             * <li> HTTP/1.1 requests are Keep-Alive, unless the "Connection: close"
0214:             * header was present.
0215:             * </ul>
0216:             * The user can change this value from <code>true</code> to
0217:             * <code>false</code> to forcefully close the connection to the client
0218:             * after sending the response.  The user can change this value from
0219:             * <code>false</code> to <code>true</code> if the client is using a
0220:             * different header to request a persistent connection.  See
0221:             * {@link #connectionHeader}.
0222:             * <p>
0223:             * Regardless of this value, if an error is detected while receiving
0224:             * or responding to an HTTP request, the connection will be closed.
0225:             */
0226:            public boolean keepAlive;
0227:
0228:            /**
0229:             * The header "Connection" usually controls whether the client
0230:             * connection will be of type "Keep-Alive" or "close".  The same
0231:             * header is written back to the client in the response headers.
0232:             * <p>
0233:             * The field {@link #keepAlive} is set based on the value of the
0234:             * "Connection" header.  However, not all clients use "Connection"
0235:             * to request that the connection be kept alive.  For instance (although
0236:             * it does not appear in the HTTP/1.0 or HTTP/1.1 documentation) both
0237:             * Netscape and IE use the "Proxy-Connection" header when issuing
0238:             * requests via an HTTP proxy.  If a <code>Handler</code> is written to
0239:             * respond to HTTP proxy requests, it should set <code>keepAlive</code>
0240:             * depending on the value of the "Proxy-Connection" header, and set
0241:             * <code>connectionHeader</code> to "Proxy-Connection", since the
0242:             * convenience methods like <code>setResponse()</code> use these fields
0243:             * when constructing the response.  The server does not handle the
0244:             * "Proxy-Connection" header by default, since trying to pre-anticipate
0245:             * all the exceptions to the specification is a "slippery slope".
0246:             */
0247:            public String connectionHeader;
0248:
0249:            //-----------------------------------------------------------------------
0250:
0251:            int statusCode;
0252:            String statusPhrase;
0253:
0254:            /**
0255:             * The HTTP response headers.  Keys and values in this table correspond
0256:             * to the HTTP headers that will be written back to the client when
0257:             * the response is sent.  The order of entries in this table corresponds
0258:             * to the order in which the HTTP headers will be sent.  Multiple header
0259:             * lines with the same key will be stored as separate entries in the
0260:             * table.
0261:             *
0262:             * @see	#addHeader(String, String)
0263:             */
0264:            public MimeHeaders responseHeaders;
0265:
0266:            /*
0267:             * True if the headers have already been sent, so that if sendError()
0268:             * is called in the middle of sending a response, it won't send the
0269:             * headers again, but will cause the connection to be closed afterwards.
0270:             */
0271:            private boolean headersSent;
0272:
0273:            /**
0274:             * Time stamp for start of this request - set, but not used.
0275:             */
0276:            public long startMillis;
0277:
0278:            /**
0279:             * Create a new http request.  Requests are created by the server for
0280:             * use by handlers.
0281:             *
0282:             * @param	server
0283:             *		The server that owns this request.
0284:             *
0285:             * @param	sock
0286:             *		The socket of the incoming HTTP request.
0287:             */
0288:            Request(Server server, Socket sock) {
0289:                this .server = server;
0290:                this .sock = sock;
0291:
0292:                try {
0293:                    in = new HttpInputStream(new BufferedInputStream(sock
0294:                            .getInputStream()));
0295:                    out = new HttpOutputStream(new BufferedOutputStream(sock
0296:                            .getOutputStream()));
0297:                } catch (IOException e) {
0298:                    /*
0299:                     * Logically we shouldn't get an error obtaining the streams from
0300:                     * the socket, but if it does, it will be caught later as a
0301:                     * NullPointerException by the Connection.run() method the first
0302:                     * time we attempt to read from the socket.
0303:                     */
0304:                }
0305:
0306:                requestsLeft = server.maxRequests;
0307:                keepAlive = true;
0308:
0309:                props = new RechainableProperties(server.props);
0310:
0311:                headers = new MimeHeaders();
0312:                responseHeaders = new MimeHeaders();
0313:            }
0314:
0315:            /**
0316:             * Returns a string representation of this <code>Request</code>.
0317:             * The string representation is the first line (the method line) of the
0318:             * HTTP request that this <code>Request</code> is handling.  Useful for
0319:             * debugging.
0320:             *
0321:             * @return	The string representation of this <code>Request</code>.
0322:             */
0323:            public String toString() {
0324:                StringBuffer sb = new StringBuffer();
0325:
0326:                sb.append(method).append(' ').append(url);
0327:                if ((query != null) && (query.length() > 0)) {
0328:                    sb.append('?').append(query);
0329:                }
0330:                sb.append(' ').append(protocol);
0331:                return sb.toString();
0332:            }
0333:
0334:            /**
0335:             * Reads an HTTP request from the socket.
0336:             *
0337:             * @param props	The server props associated with this request
0338:             *
0339:             * @return	<code>true</code> if the request was successfully read and
0340:             *		parsed, <code>false</code> if the request was malformed.
0341:             *
0342:             * @throws	IOException
0343:             *		if there was an IOException reading from the socket.  See
0344:             *		the socket documentation for a description of socket
0345:             *		exceptions.
0346:             */
0347:            boolean getRequest(Properties defaults) throws IOException {
0348:                /*
0349:                 * Reset state.
0350:                 */
0351:
0352:                requestsLeft--;
0353:                connectionHeader = "Connection";
0354:                props.clear();
0355:                props.setDefaults(defaults);
0356:
0357:                method = null;
0358:                url = null;
0359:                query = null;
0360:                protocol = null;
0361:                headers.clear();
0362:                postData = null;
0363:
0364:                statusCode = 200;
0365:                statusPhrase = "OK";
0366:                responseHeaders.clear();
0367:                startMillis = System.currentTimeMillis();
0368:                out.bytesWritten = 0;
0369:
0370:                /*
0371:                 * Get first line of HTTP request (the method line).
0372:                 */
0373:
0374:                String line;
0375:                while (true) {
0376:                    line = in.readLine();
0377:                    if (line == null) {
0378:                        return false;
0379:                    } else if (line.length() > 0) {
0380:                        break;
0381:                    }
0382:                    log(Server.LOG_INFORMATIONAL, "Skipping blank line");
0383:                }
0384:
0385:                log(Server.LOG_LOG, "Request " + requestsLeft + " " + line);
0386:
0387:                StringTokenizer st = new StringTokenizer(line);
0388:                int count = st.countTokens();
0389:                if (count != 3) {
0390:                    sendError(400, line, null);
0391:                    return false;
0392:                }
0393:
0394:                method = st.nextToken();
0395:                url = st.nextToken();
0396:                protocol = st.nextToken();
0397:
0398:                if ((method.equals("GET") == false)
0399:                        && (method.equals("POST") == false)
0400:                        && (method.equals("PUT") == false)) {
0401:                    sendError(501, method, null);
0402:                    return false;
0403:                }
0404:
0405:                if (protocol.equals("HTTP/1.0")) {
0406:                    version = 10;
0407:                } else if (protocol.equals("HTTP/1.1")) {
0408:                    version = 11;
0409:                } else {
0410:                    sendError(505, line, null);
0411:                    return false;
0412:                }
0413:
0414:                /*
0415:                 * Separate query string from URL.
0416:                 */
0417:
0418:                int index = url.indexOf('?');
0419:                if (index >= 0) {
0420:                    query = url.substring(index + 1);
0421:                    url = url.substring(0, index);
0422:                } else {
0423:                    query = "";
0424:                }
0425:
0426:                headers.read(in);
0427:
0428:                /*
0429:                 * Remember POST data.  "Transfer-Encoding: chunked" is not handled
0430:                 * yet.
0431:                 */
0432:
0433:                String str;
0434:
0435:                str = getRequestHeader("Content-Length");
0436:                if (str != null) {
0437:                    try {
0438:                        postData = new byte[Integer.parseInt(str)];
0439:                    } catch (Exception e) {
0440:                        sendError(411, str, null);
0441:                        return false;
0442:                    } catch (OutOfMemoryError e) {
0443:                        sendError(411, str, null);
0444:                        return false;
0445:                    }
0446:                    in.readFully(postData);
0447:                }
0448:
0449:                str = getRequestHeader(connectionHeader);
0450:                if ("Keep-Alive".equalsIgnoreCase(str)) {
0451:                    keepAlive = true;
0452:                } else if ("close".equalsIgnoreCase(str)) {
0453:                    keepAlive = false;
0454:                } else if (version > 10) {
0455:                    keepAlive = true;
0456:                } else {
0457:                    keepAlive = false;
0458:                }
0459:
0460:                return true;
0461:            }
0462:
0463:            boolean shouldKeepAlive() {
0464:                return (requestsLeft > 0) && keepAlive;
0465:            }
0466:
0467:            /**
0468:             * The socket from which the HTTP request was received, and to where the
0469:             * HTTP response will be written.  The user should not directly read from
0470:             * or write to this socket.  The socket is provided other purposes, for
0471:             * example, imagine a handler that provided different content depending
0472:             * upon the IP address of the client.
0473:             *
0474:             * @return	The client socket that issued this HTTP request.
0475:             */
0476:            public Socket getSocket() {
0477:                return sock;
0478:            }
0479:
0480:            /**
0481:             * Logs a message by calling <code>Server.log</code>.  Typically a
0482:             * message is generated on the console or in a log file, if the
0483:             * <code>level</code> is less than the current server log setting. 
0484:             *
0485:             * @param	level
0486:             *		The severity of the message.  
0487:             *
0488:             * @param	message
0489:             *		The message that will be logged.
0490:             *
0491:             * @see	Server#log(int, Object, String)
0492:             */
0493:            public void log(int level, String message) {
0494:                server.log(level, null, message);
0495:            }
0496:
0497:            /**
0498:             * Logs a message by calling <code>Server.log</code>.  Typically a
0499:             * message is generated on the console or in a log file, if the
0500:             * <code>level</code> is less than the current server log setting. 
0501:             *
0502:             * @param	level
0503:             *		The severity of the message.  
0504:             *
0505:             * @param	obj
0506:             *		The object that the message relates to.
0507:             *
0508:             * @param	message
0509:             *		The message that will be logged.
0510:             *
0511:             * @see	Server#log(int, Object, String)
0512:             */
0513:            public void log(int level, Object obj, String message) {
0514:                server.log(level, obj, message);
0515:            }
0516:
0517:            /*
0518:             *-----------------------------------------------------------------------
0519:             * Request methods.
0520:             *-----------------------------------------------------------------------
0521:             */
0522:
0523:            /**
0524:             * Returns the value that the given case-insensitive key maps to
0525:             * in the HTTP request headers.  In order to do fancier things like
0526:             * changing or deleting an existing request header, the user may directly
0527:             * access the <code>headers</code> field.
0528:             *
0529:             * @param	key
0530:             *		The key to look for in the HTTP request headers.  May not
0531:             *		be <code>null</code>.
0532:             *
0533:             * @return	The value to which the given key is mapped, or
0534:             *		<code>null</code> if the key is not in the headers.
0535:             *
0536:             * @see	#headers
0537:             */
0538:            public String getRequestHeader(String key) {
0539:                return headers.get(key);
0540:            }
0541:
0542:            /*
0543:             *-----------------------------------------------------------------------
0544:             * Response methods.
0545:             *-----------------------------------------------------------------------
0546:             */
0547:
0548:            /**
0549:             * Sets the status code of the HTTP response.  The default status
0550:             * code for a response is <code>200</code> if this method is not
0551:             * called.
0552:             * <p>
0553:             * An HTTP status phrase will be chosen based on the given
0554:             * status code.  For example, the status code <code>404</code> will get
0555:             * the status phrase "Not Found".
0556:             * <p>
0557:             * If this method is called, it must be called before
0558:             * <code>sendHeaders</code> is either directly or indirectly called.
0559:             * Otherwise, it will have no effect.
0560:             *
0561:             * @param	code
0562:             *		The HTTP status code, such as <code>200</code> or
0563:             *		<code>404</code>.  If < 0, the HTTP status code will
0564:             *		not be changed.
0565:             *
0566:             * @see	#sendHeaders(int, String, int)
0567:             */
0568:            public void setStatus(int code) {
0569:                if (code >= 0) {
0570:                    setStatus(code, HttpUtil.getStatusPhrase(code));
0571:                }
0572:
0573:            }
0574:
0575:            /**
0576:             * Set the HTTP status code and status phrase of this request.  The given
0577:             * status will be sent to the client when the user directly or indirectly
0578:             * calls the method <code>sendHeaders</code>.  The given status phrase
0579:             * replaces the default HTTP status phrase normally associated with the
0580:             * given status code.
0581:             *
0582:             * @param	code
0583:             *		The HTTP status code, such as <code>200</code> or
0584:             *		<code>404</code>.
0585:             *
0586:             * @param	message
0587:             *		The HTTP status phrase, such as <code>"Okey dokey"</code> or
0588:             *		<code>"I don't see it"</code>.
0589:             *
0590:             * @see	#sendHeaders(int, String, int)
0591:             */
0592:            private void setStatus(int code, String message) {
0593:                this .statusCode = code;
0594:                this .statusPhrase = message;
0595:            }
0596:
0597:            /**
0598:             * Return the status code.
0599:             */
0600:
0601:            public int getStatus() {
0602:                return statusCode;
0603:            }
0604:
0605:            /**
0606:             * Return uses of this socket
0607:             */
0608:
0609:            public int getReuseCount() {
0610:                return server.maxRequests - requestsLeft;
0611:            }
0612:
0613:            /**
0614:             * Adds a response header to the HTTP response.  In order to do fancier
0615:             * things like appending a value to an existing response header, the
0616:             * user may directly access the <code>responseHeaders</code> field.
0617:             * <p>
0618:             * If this method is called, it must be called before
0619:             * <code>sendHeaders</code> is either directly or indirectly called.
0620:             * Otherwise, it will have no effect.
0621:             *
0622:             * @param	key
0623:             *		The header name.  
0624:             *
0625:             * @param	value
0626:             *		The value for the request header.
0627:             *
0628:             * @see	#sendHeaders(int, String, int)
0629:             * @see	#responseHeaders
0630:             */
0631:            public void addHeader(String key, String value) {
0632:                responseHeaders.add(key, value);
0633:            }
0634:
0635:            /**
0636:             * Adds a response header to the HTTP response.  In order to do fancier
0637:             * things like appending a value to an existing response header, the
0638:             * user may directly access the <code>responseHeaders</code> field.
0639:             * <p>
0640:             * If this method is called, it must be called before
0641:             * <code>sendHeaders</code> is either directly or indirectly called.
0642:             * Otherwise, it will have no effect.
0643:             *
0644:             * @param	line
0645:             *		The HTTP response header, of the form
0646:             *		"<code>key</code>: <code>value</code>".
0647:             *
0648:             * @see	#sendHeaders(int, String, int)
0649:             * @see	#responseHeaders
0650:             */
0651:            public void addHeader(String line) {
0652:                int dots = line.indexOf(':');
0653:                String key = line.substring(0, dots);
0654:                String value = line.substring(dots + 1).trim();
0655:                addHeader(key, value);
0656:            }
0657:
0658:            /**
0659:             * Sends an HTTP response to the client.  
0660:             * <p>
0661:             * This method first calls <code>sendHeaders</code> to send the HTTP
0662:             * response headers, then sends the given byte array as the HTTP
0663:             * response body.
0664:             * <p>
0665:             * The "Content-Length" will be set to the length of the given byte array.
0666:             * The "Content-Type" will be set to the given MIME type.
0667:             *
0668:             * @param	body
0669:             *		The array of bytes to send as the HTTP response body.  May
0670:             *		not be <code>null</code>.
0671:             *
0672:             * @param	type
0673:             *		The MIME type of the response, such as "text/html".  May be
0674:             *		<code>null</code> to use the existing "Content-Type"
0675:             *		response header (if any).
0676:             *
0677:             * @throws	IOException
0678:             *		if there was an I/O error while sending the response to
0679:             *		the client.
0680:             *
0681:             * @see	#sendHeaders(int, String, int)
0682:             */
0683:            public void sendResponse(byte[] body, String type)
0684:                    throws IOException {
0685:                sendHeaders(-1, type, body.length);
0686:                out.write(body);
0687:            }
0688:
0689:            /**
0690:             * Sends an HTTP response to the client.  
0691:             * <p>
0692:             * This method first calls <code>sendHeaders</code> to send the HTTP
0693:             * response headers.  It then writes out the given string to the client
0694:             * as a sequence of bytes.  Each character in the string is written out
0695:             * by discarding its high eight bits.
0696:             * <p>
0697:             * The "Content-Length" will be set to the length of the string.
0698:             * The "Content-Type" will be set to the given MIME type.
0699:             *
0700:             * @param	body
0701:             *		The string to send as the HTTP response body.  May
0702:             *		not be <code>null</code>.
0703:             *
0704:             * @param	type
0705:             *		The MIME type of the response, such as "text/html".  May be
0706:             *		<code>null</code> to preserve the existing "Content-Type"
0707:             *		response header (if any).
0708:             *
0709:             * @param	code
0710:             *		The HTTP status code for the response, such as
0711:             *		<code>200</code>.  May be < 0 to preserve the existing
0712:             *		status code.
0713:             *
0714:             * @throws	IOException
0715:             *		if there was an I/O error while sending the response to
0716:             *		the client. 
0717:             *
0718:             * @see	#sendHeaders(int, String, int)
0719:             */
0720:            public void sendResponse(String body, String type, int code)
0721:                    throws IOException {
0722:                sendHeaders(code, type, body.length());
0723:                out.writeBytes(body);
0724:            }
0725:
0726:            /**
0727:             * Convenience method that sends an HTTP response to the client
0728:             * with a "Content-Type" of "text/html" and the default HTTP status
0729:             * code.
0730:             *
0731:             * @param	body
0732:             *		The string to send as the HTTP response body.
0733:             *
0734:             * @see	#sendResponse(String, String, int)
0735:             */
0736:            public void sendResponse(String body) throws IOException {
0737:                sendResponse(body, "text/html", -1);
0738:            }
0739:
0740:            /**
0741:             * Convenience method that sends an HTTP response to the client
0742:             * with the default HTTP status code.
0743:             * 
0744:             * @param	body
0745:             *		The string to send as the HTTP response body.  
0746:             *
0747:             * @param	type
0748:             *		The MIME type of the response.
0749:             *
0750:             * @see	#sendResponse(String, String, int)
0751:             */
0752:            public void sendResponse(String body, String type)
0753:                    throws IOException {
0754:                sendResponse(body, type, -1);
0755:            }
0756:
0757:            /**
0758:             * Sends the contents of the given input stream as the HTTP response.
0759:             * <p>
0760:             * This method first calls <code>sendHeaders</code> to send the HTTP
0761:             * response headers.  It then transfers a total of <code>length</code>
0762:             * bytes of data from the given input stream to the client as the
0763:             * HTTP response body.
0764:             * <p>
0765:             * This method takes care of setting the "Content-Length" header
0766:             * if the actual content length is known, or the "Transfer-Encoding"
0767:             * header if the content length is not known (for HTTP/1.1 clients only).
0768:             * <p>
0769:             * This method may set the <code>keepAlive</code> to <code>false</code>
0770:             * before returning, if fewer than <code>length</code> bytes could be
0771:             * read.
0772:             *
0773:             * @param	in
0774:             *		The input stream to read from.  
0775:             *
0776:             * @param	length
0777:             *		The content length.  The number of bytes to send to the
0778:             *		client.  May be < 0, in which case this method will read
0779:             *		until reaching the end of the input stream.
0780:             * 
0781:             * @param	type
0782:             *		The MIME type of the response, such as "text/html".  May be
0783:             *		<code>null</code> to preserve the existing "Content-Type"
0784:             *		response header (if any).
0785:             *
0786:             * @param	code
0787:             *		The HTTP status code for the response, such as
0788:             *		<code>200</code>.  May be < 0 to preserve the existing
0789:             *		status code.
0790:             *
0791:             * @throws	IOException
0792:             *		if there was an I/O error while sending the response to
0793:             *		the client. 
0794:             */
0795:            public void sendResponse(InputStream in, int length, String type,
0796:                    int code) throws IOException {
0797:                HttpInputStream hin = new HttpInputStream(in);
0798:
0799:                byte[] buf = new byte[server.bufsize];
0800:
0801:                if (length >= 0) {
0802:                    sendHeaders(code, type, length);
0803:                    if (hin.copyTo(out, length, buf) != length) {
0804:                        keepAlive = false;
0805:                    }
0806:                } else if (version <= 10) {
0807:                    keepAlive = false;
0808:                    sendHeaders(code, type, -1);
0809:                    hin.copyTo(out, -1, buf);
0810:                } else {
0811:                    addHeader("Transfer-Encoding", "chunked");
0812:                    sendHeaders(code, type, -1);
0813:
0814:                    while (true) {
0815:                        int count = hin.read(buf);
0816:                        if (count < 0) {
0817:                            out.writeBytes("0\r\n\r\n");
0818:                            break;
0819:                        }
0820:                        out.writeBytes(Integer.toHexString(count) + "\r\n");
0821:                        out.write(buf, 0, count);
0822:                        out.writeBytes("\r\n");
0823:                    }
0824:                }
0825:            }
0826:
0827:            /**
0828:             * Sends a HTTP error response to the client.  
0829:             *
0830:             * @param	code
0831:             *		The HTTP status code.
0832:             *
0833:             * @param	clientMessage
0834:             *		A short message to be included in the error response
0835:             *		and logged to the server.
0836:             */
0837:            public void sendError(int code, String clientMessage) {
0838:                sendError(code, clientMessage, null);
0839:            }
0840:
0841:            /**
0842:             * Sends a HTTP error response to the client.  
0843:             *
0844:             * @param	code
0845:             *		The HTTP status code.
0846:             *
0847:             * @param	clientMessage
0848:             *		A short message to be included in the error response.
0849:             *
0850:             * @param	logMessage
0851:             *		A short message to be logged to the server.  This message is
0852:             *		<b>not</b> sent to the client.
0853:             */
0854:            public void sendError(int code, String clientMessage,
0855:                    String logMessage) {
0856:                setStatus(code);
0857:                server.errorCount++;
0858:
0859:                String message = clientMessage;
0860:                if (message == null) {
0861:                    message = logMessage;
0862:                    logMessage = null;
0863:                }
0864:                log(Server.LOG_LOG, "Error", statusCode + " " + statusPhrase
0865:                        + ": " + message);
0866:                if (logMessage != null) {
0867:                    log(Server.LOG_LOG, logMessage);
0868:                }
0869:
0870:                keepAlive = false;
0871:                if (headersSent) {
0872:                    /*
0873:                     * The headers have already been sent.  We can't send an error
0874:                     * message in the middle of an existing response, so just close
0875:                     * this request.
0876:                     */
0877:
0878:                    return;
0879:                }
0880:
0881:                String body = "<html>\n<head>\n"
0882:                        + "<title>Error: "
0883:                        + statusCode
0884:                        + "</title>\n"
0885:                        + "<body>\nGot the error: <b>"
0886:                        + statusPhrase
0887:                        + "</b><br>\nwhile trying to obtain <b>"
0888:                        + ((url == null) ? "unknown URL" : HttpUtil
0889:                                .htmlEncode(url)) + "</b><br>\n"
0890:                        + HttpUtil.htmlEncode(clientMessage)
0891:                        + "\n</body>\n</html>";
0892:
0893:                try {
0894:                    sendResponse(body, "text/html", statusCode);
0895:                } catch (IOException e) {
0896:                    /*
0897:                     * Don't throw an error in the process of sending an error
0898:                     * message!
0899:                     */
0900:                }
0901:            }
0902:
0903:            /**
0904:             * Sends the HTTP status line and response headers to the client.  This
0905:             * method is automatically invoked by <code>sendResponse</code>, but
0906:             * can be manually invoked if the user needs direct access to the
0907:             * client's output stream.  If this method is not called, then the
0908:             * HTTP status and response headers will not automatically be sent to
0909:             * the client; the user would be responsible for forming the entire
0910:             * HTTP response.
0911:             * <p>
0912:             * The user may call the <code>addHeader</code> method or modify the
0913:             * <code>responseHeaders</code> field before calling this method.
0914:             * This method then adds a number of HTTP headers, as follows: <ul>
0915:             * <li> "Date" - the current time, if this header is not already present.
0916:             * <li> "Server" - the server's name (from <code>server.name</code>), if
0917:             *	    this header is not already present.
0918:             * <li> "Connection" - "Keep-Alive" or "close", depending upon the
0919:             *	    <code>keepAlive</code> field.
0920:             * <li> "Content-Length" - set to the given <code>length</code>.
0921:             * <li> "Content-Type" - set to the given <code>type</code>.
0922:             * </ul>
0923:             * <p>
0924:             * The string used for "Connection" header actually comes from the
0925:             * <code>connectionHeader</code> field.
0926:             *
0927:             * @param	code
0928:             *		The HTTP status code for the response, such as
0929:             *		<code>200</code>.  May be < 0 to preserve the existing
0930:             *		status code.
0931:             *
0932:             * @param	type
0933:             *		The MIME type of the response, such as "text/html".  May be
0934:             *		<code>null</code> to preserve the existing "Content-Type"
0935:             *		response header (if any).
0936:             *
0937:             * @param	length
0938:             *		The length of the response body.  May be < 0 if the length
0939:             *		is unknown and/or to preserve the existing "Content-Length"
0940:             *		response header (if any).
0941:             *
0942:             * @throws	IOException
0943:             *		if there was an I/O error while sending the headers to
0944:             *		the client. 
0945:             *
0946:             * @see	#setStatus(int)
0947:             * @see	#addHeader(String, String)
0948:             * @see	#sendResponse(String, String, int)
0949:             * @see	#connectionHeader
0950:             */
0951:            public void sendHeaders(int code, String type, int length)
0952:                    throws IOException {
0953:                setStatus(code);
0954:                if ((length == 0) && (statusCode == 200)) {
0955:                    /*
0956:                     * No Content.
0957:                     */
0958:                    setStatus(204);
0959:                }
0960:
0961:                responseHeaders.putIfNotPresent("Date", HttpUtil.formatTime());
0962:                if (server.name != null) {
0963:                    responseHeaders.putIfNotPresent("Server", server.name);
0964:                }
0965:                String str = shouldKeepAlive() ? "Keep-Alive" : "close";
0966:                responseHeaders.put(connectionHeader, str);
0967:                if (length >= 0) {
0968:                    responseHeaders.put("Content-Length", Integer
0969:                            .toString(length));
0970:                }
0971:                if (type != null) {
0972:                    responseHeaders.put("Content-Type", type);
0973:                }
0974:
0975:                out.sendHeaders(this );
0976:                headersSent = true;
0977:            }
0978:
0979:            /**
0980:             * Send the response headers to the client.
0981:             *  This consists of standard plus added headers.  The handler is reponsible
0982:             *  for sending the reponse body.
0983:             *
0984:             * @param type	The document mime type
0985:             * @param length	the document length
0986:             * 
0987:             * @see Request#addHeader(String)
0988:             * @see Request#sendResponse(String)
0989:             * @see Request#setStatus(int)
0990:             */
0991:
0992:            /**
0993:             * Responds to an HTTP request with a redirection reply, telling the
0994:             * client that the requested url has moved.  Generally, this is used if
0995:             * the client did not put a '/' on the end of a directory.
0996:             *
0997:             * @param	url
0998:             *		The URL the client should have requested.  This URL may be
0999:             *		fully-qualified (in the form "http://....") or host-relative
1000:             *		(in the form "/...").
1001:             *
1002:             * @param	body
1003:             *		The body of the redirect response, or <code>null</code> to
1004:             *		send a hardcoded message.
1005:             */
1006:            public void redirect(String url, String body) throws IOException {
1007:                if (url.startsWith("/")) {
1008:                    url = serverUrl() + url;
1009:                }
1010:                addHeader("Location", url);
1011:                if (body == null) {
1012:                    body = "<title>Moved</title><h1>look for <a href=" + url
1013:                            + ">" + url + "</h1>";
1014:                }
1015:                sendResponse(body, "text/html", 302);
1016:            }
1017:
1018:            /**
1019:             * Returns the server's fully-qualified base URL.  This is "http://"
1020:             * followed by the server's hostname and port.
1021:             * <p>
1022:             * If the HTTP request header "Host" is present, it specifies the
1023:             * hostname and port that will be used instead of the server's internal
1024:             * name for itself.  Due bugs in certain browsers, when using the server's
1025:             * internal name, the port number will be elided if it is <code>80</code>.
1026:             *
1027:             * @return	The string representation of the server's URL.
1028:             */
1029:            public String serverUrl() {
1030:                String host = headers.get("Host");
1031:                if (host == null) {
1032:                    host = server.hostName;
1033:                }
1034:                int index = host.lastIndexOf(":");
1035:                if ((index < 0) && (server.listen.getLocalPort() != 80)) {
1036:                    host += ":" + server.listen.getLocalPort();
1037:                }
1038:                return server.protocol + "://" + host;
1039:            }
1040:
1041:            /**
1042:             * Retrieves the query data as a hashtable.
1043:             * This includes both the query information included as part of the url 
1044:             * and any posted "application/x-www-form-urlencoded" data.
1045:             *
1046:             * @param   table
1047:             *		An existing hashtable in which to put the query data as
1048:             *		name/value pairs.  May be <code>null</code>, in which case
1049:             *		a new hashtable is allocated.
1050:             *
1051:             * @returns	The hashtable in which the query data was stored.
1052:             */
1053:            public Hashtable getQueryData(Hashtable table) {
1054:                if (table == null) {
1055:                    table = new Hashtable();
1056:                }
1057:                HttpUtil.extractQuery(query, table);
1058:                if (postData != null) {
1059:                    String contentType = headers.get("Content-Type");
1060:                    if ("application/x-www-form-urlencoded".equals(contentType)) {
1061:                        HttpUtil.extractQuery(new String(postData), table);
1062:                    }
1063:                }
1064:                return table;
1065:            }
1066:
1067:            /**
1068:             * Retrieves the query data as a hashtable.
1069:             * This includes both the query information included as part of the url 
1070:             * and any posted "application/x-www-form-urlencoded" data.
1071:             *
1072:             * @returns	The hashtable in which the query data was stored.
1073:             */
1074:            public Hashtable getQueryData() {
1075:                return getQueryData(null);
1076:            }
1077:
1078:            /**
1079:             * The <code>RechainableProperties</code> is similar to a standard
1080:             * <code>Properties</code>, except that the defaults can be changed
1081:             * at any time.  The defaults for a standard <code>Properties</code>
1082:             * object can only be set once, when the object is constructed.
1083:             * <p>
1084:             * It is is useful in a certain set of circumstances to build a chain
1085:             * of request properties, and be able to insert new sets of properties
1086:             * anywhere in the chain.
1087:             * <p>
1088:             * NOTE:<br>This implementation is fundamentally broken.  By using the
1089:             * built-in Properties class, the data is bound to the link pointer, so
1090:             * one table may be chained onto excactly one list.
1091:             */
1092:            public static class RechainableProperties extends Properties {
1093:                public RechainableProperties() {
1094:                    this (null);
1095:                }
1096:
1097:                public RechainableProperties(Properties defaults) {
1098:                    super (defaults);
1099:                }
1100:
1101:                /**
1102:                 * Set the default properties for this object.
1103:                 * @param change	The new default properties.  Use this
1104:                 *			with care: no attempt is made to detect loops.
1105:                 * @returns		The previous value of the default properties.
1106:                 */
1107:
1108:                public Properties setDefaults(Properties change) {
1109:                    /*
1110:                    if (change == this) {
1111:                        throw new RuntimeException("Infinite loop in properties chain");
1112:                    }
1113:                     */
1114:                    Properties old = this .defaults;
1115:                    this .defaults = change;
1116:                    return old;
1117:                }
1118:
1119:                /**
1120:                 * Return the current "default" properties for this object.
1121:                 */
1122:
1123:                public Properties getDefaults() {
1124:                    return this .defaults;
1125:                }
1126:            }
1127:
1128:            /**
1129:             * The <code>HttpOutputStream</code> provides the convenience method
1130:             * <code>writeBytes</code> for writing the byte representation of a
1131:             * string, without bringing in the overhead and the deprecated warnings
1132:             * associated with a <code>java.io.DataOutputStream</code>.
1133:             * <p>
1134:             * The other methods in this class are here to allow the 
1135:             * <code>FilterHandler</code> and <code>ChainSawHandler</code> to
1136:             * alter the behavior in an implememtation specific way.  This behavior
1137:             * is unfortunate, and might go away when a better strategy comes along.
1138:             */
1139:            public static class HttpOutputStream extends FilterOutputStream {
1140:                /**
1141:                 * Count the number of bytes that are written to this stream
1142:                 */
1143:
1144:                public int bytesWritten = 0;
1145:
1146:                public HttpOutputStream(OutputStream out) {
1147:                    super (out);
1148:                }
1149:
1150:                public void writeBytes(String s) throws IOException {
1151:                    int len = s.length();
1152:                    for (int i = 0; i < len; i++) {
1153:                        this .out.write((byte) s.charAt(i));
1154:                    }
1155:                }
1156:
1157:                public void write(byte b) throws IOException {
1158:                    this .out.write(b);
1159:                    bytesWritten++;
1160:                }
1161:
1162:                public void write(byte[] buf, int off, int len)
1163:                        throws IOException {
1164:                    this .out.write(buf, off, len);
1165:                    bytesWritten += len;
1166:                }
1167:
1168:                public void sendHeaders(Request request) throws IOException {
1169:                    writeBytes(request.protocol + " " + request.statusCode
1170:                            + " " + request.statusPhrase + "\r\n");
1171:                    request.responseHeaders.print(this .out);
1172:                    writeBytes("\r\n");
1173:                }
1174:            }
1175:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.