00001 /******************************************************************************* 00002 00003 @file Servlet.d 00004 00005 Copyright (C) 2004 Kris Bell 00006 00007 This software is provided 'as-is', without any express or implied 00008 warranty. In no event will the authors be held liable for damages 00009 of any kind arising from the use of this software. 00010 00011 Permission is hereby granted to anyone to use this software for any 00012 purpose, including commercial applications, and to alter it and/or 00013 redistribute it freely, subject to the following restrictions: 00014 00015 1. The origin of this software must not be misrepresented; you must 00016 not claim that you wrote the original software. If you use this 00017 software in a product, an acknowledgment within documentation of 00018 said product would be appreciated but is not required. 00019 00020 2. Altered source versions must be plainly marked as such, and must 00021 not be misrepresented as being the original software. 00022 00023 3. This notice may not be removed or altered from any distribution 00024 of the source. 00025 00026 00027 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 00028 00029 00030 @version Initial version, April 2004 00031 @author Kris 00032 00033 00034 *******************************************************************************/ 00035 00036 module mango.servlet.Servlet; 00037 00038 public import mango.io.Exception; 00039 00040 public import mango.servlet.ServletConfig; 00041 00042 public import mango.http.server.HttpHeaders, 00043 mango.http.server.HttpResponse; 00044 00045 public import mango.servlet.model.IServletRequest, 00046 mango.servlet.model.IServletResponse; 00047 00048 00049 /****************************************************************************** 00050 00051 The fundamental Servlet exception 00052 00053 ******************************************************************************/ 00054 00055 class ServletException : IOException 00056 { 00057 /********************************************************************** 00058 00059 Construct this exception with the provided message 00060 00061 **********************************************************************/ 00062 00063 this (char[] msg) 00064 { 00065 super (msg); 00066 } 00067 } 00068 00069 00070 /****************************************************************************** 00071 00072 Exception to indicate a service is unavailable 00073 00074 ******************************************************************************/ 00075 00076 class UnavailableException : ServletException 00077 { 00078 /********************************************************************** 00079 00080 Construct this exception with the provided message 00081 00082 **********************************************************************/ 00083 00084 this (char[] msg) 00085 { 00086 super (msg); 00087 } 00088 } 00089 00090 00091 /****************************************************************************** 00092 00093 The basic servlet class. This is a bit different from the Java 00094 style servlets, as the class hierarchy is effectively inverted. 00095 00096 Servlet, by itself, does not break out each request-method. It 00097 provides only the most basic functionality. See MethodServlet 00098 for additional functionalty. 00099 00100 ******************************************************************************/ 00101 00102 class Servlet 00103 { 00104 /********************************************************************** 00105 00106 Service is the main entry point for all servlets. 00107 00108 **********************************************************************/ 00109 00110 abstract void service (IServletRequest request, IServletResponse response); 00111 00112 /********************************************************************** 00113 00114 Init is called when the servlet is first registered. 00115 00116 **********************************************************************/ 00117 00118 void init (ServletConfig config) 00119 { 00120 } 00121 } 00122 00123 00124 /****************************************************************************** 00125 00126 Extends the basic servlet with individual signatures for handling 00127 each request method. 00128 00129 ******************************************************************************/ 00130 00131 class MethodServlet : Servlet 00132 { 00133 00134 /********************************************************************** 00135 00136 Default response for unimplemented requests. 00137 00138 **********************************************************************/ 00139 00140 static private void error (IServletResponse response) 00141 { 00142 response.sendError (HttpResponses.MethodNotAllowed); 00143 } 00144 00145 /********************************************************************** 00146 00147 Handle a GET request 00148 00149 **********************************************************************/ 00150 00151 void doGet (IServletRequest request, IServletResponse response) 00152 { 00153 error (response); 00154 } 00155 00156 /********************************************************************** 00157 00158 Handle a HEAD request 00159 00160 **********************************************************************/ 00161 00162 void doHead (IServletRequest request, IServletResponse response) 00163 { 00164 error (response); 00165 } 00166 00167 /********************************************************************** 00168 00169 Handle a POST request 00170 00171 **********************************************************************/ 00172 00173 void doPost (IServletRequest request, IServletResponse response) 00174 { 00175 error (response); 00176 } 00177 00178 /********************************************************************** 00179 00180 Handle a DELETE request 00181 00182 **********************************************************************/ 00183 00184 void doDelete (IServletRequest request, IServletResponse response) 00185 { 00186 error (response); 00187 } 00188 00189 /********************************************************************** 00190 00191 Handle a PUT request 00192 00193 **********************************************************************/ 00194 00195 void doPut (IServletRequest request, IServletResponse response) 00196 { 00197 error (response); 00198 } 00199 00200 /********************************************************************** 00201 00202 Handle an OPTIONS request 00203 00204 **********************************************************************/ 00205 00206 void doOptions (IServletRequest request, IServletResponse response) 00207 { 00208 error (response); 00209 } 00210 00211 /********************************************************************** 00212 00213 Handle a TRACE request 00214 00215 **********************************************************************/ 00216 00217 void doTrace (IServletRequest request, IServletResponse response) 00218 { 00219 error (response); 00220 } 00221 00222 /********************************************************************** 00223 00224 overridable implementation of getLastModified() returns 00225 -1 to say it doesn't know. 00226 00227 **********************************************************************/ 00228 00229 long getLastModified (IServletRequest request) 00230 { 00231 return -1; 00232 } 00233 00234 /********************************************************************** 00235 00236 Preamble for GET requests that tries to figure out if 00237 we can simply return a NotModified status to the UA. 00238 00239 Servlets supporting such notions should override the 00240 getLastModified() method above, and have it do the 00241 appropriate thing. 00242 00243 **********************************************************************/ 00244 00245 void get (IServletRequest request, IServletResponse response) 00246 { 00247 long lastModified = getLastModified (request); 00248 if (lastModified == -1) 00249 doGet (request, response); 00250 else 00251 { 00252 long ifModifiedSince = request.getHeaders.getDate (HttpHeader.IfModifiedSince); 00253 if (ifModifiedSince < (lastModified / 1000 * 1000)) 00254 { 00255 response.getHeaders.addDate (HttpHeader.LastModified, lastModified); 00256 doGet (request, response); 00257 } 00258 else 00259 response.setStatus (HttpResponses.NotModified); 00260 } 00261 } 00262 00263 /********************************************************************** 00264 00265 Service implementation for method specific isolation. 00266 00267 **********************************************************************/ 00268 00269 void service (IServletRequest request, IServletResponse response) 00270 { 00271 char[] method = request.getMethod(); 00272 00273 switch (method[0]) 00274 { 00275 case 'G': 00276 get (request, response); 00277 break; 00278 00279 case 'H': 00280 doHead (request, response); 00281 break; 00282 00283 case 'O': 00284 doOptions (request, response); 00285 break; 00286 00287 case 'T': 00288 doTrace (request, response); 00289 break; 00290 00291 case 'D': 00292 doDelete (request, response); 00293 break; 00294 00295 case 'P': 00296 if (method[1] == 'O') 00297 doPost (request, response); 00298 else 00299 doPut (request, response); 00300 break; 00301 00302 default: 00303 response.sendError (HttpResponses.NotImplemented); 00304 break; 00305 } 00306 } 00307 } 00308 00309 00310 /****************************************************************************** 00311 00312 This class is intended to be compatible with a Java GenericServlet. 00313 Note that the ServletContext is available from the ServletRequest 00314 class, so this error-prone approach of accessing context via the 00315 configuration is rendered totally redundant. 00316 00317 ******************************************************************************/ 00318 00319 class CompatibleServlet : MethodServlet 00320 { 00321 private ServletConfig config; 00322 00323 /********************************************************************** 00324 00325 Servlet must implement the init() method 00326 00327 **********************************************************************/ 00328 00329 abstract void init (); 00330 00331 /********************************************************************** 00332 00333 Optional init() with ServletConfig passed to it. 00334 00335 **********************************************************************/ 00336 00337 void init (ServletConfig config) 00338 { 00339 this.config = config; 00340 init (); 00341 } 00342 00343 /********************************************************************** 00344 00345 Return the configuration passed with init() 00346 00347 **********************************************************************/ 00348 00349 ServletConfig getConfig () 00350 { 00351 return config; 00352 } 00353 } 00354 00355