00001 /******************************************************************************* 00002 00003 @file HttpMessage.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 4. Derivative works are permitted, but they must carry this notice 00027 in full and credit the original source. 00028 00029 00030 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 00031 00032 00033 @version Initial version, April 2004 00034 @author Kris 00035 00036 00037 *******************************************************************************/ 00038 00039 module mango.http.server.HttpMessage; 00040 00041 private import mango.utils.Text; 00042 00043 private import mango.io.Buffer, 00044 mango.io.Exception; 00045 00046 private import mango.io.model.IBuffer, 00047 mango.io.model.IWriter, 00048 mango.io.model.IConduit; 00049 00050 private import mango.http.server.HttpHeaders; 00051 00052 private import mango.http.server.model.IProviderBridge; 00053 00054 00055 /****************************************************************************** 00056 00057 Exception thrown when the http environment is in an invalid state. 00058 This can occur if, for example, a program attempts to update the 00059 output headers after some data has already been written back to 00060 the user-agent. 00061 00062 ******************************************************************************/ 00063 00064 class InvalidStateException : IOException 00065 { 00066 /********************************************************************** 00067 00068 Construct this exception with the provided text string 00069 00070 **********************************************************************/ 00071 00072 this (char[] msg) 00073 { 00074 super (msg); 00075 } 00076 } 00077 00078 00079 /****************************************************************************** 00080 00081 The basic HTTP message. Acts as a base-class for HttpRequest and 00082 HttpResponse. 00083 00084 ******************************************************************************/ 00085 00086 class HttpMessage : IWritable 00087 { 00088 private Buffer buffer; 00089 private IProviderBridge bridge; 00090 private HttpMutableHeaders headers; 00091 00092 private char[] encoding, 00093 mimeType; 00094 00095 /********************************************************************** 00096 00097 Construct this HttpMessage using the specified HttpBridge. 00098 The bridge provides a gateway to both the server and 00099 provider (servicer) instances. 00100 00101 **********************************************************************/ 00102 00103 this (IProviderBridge bridge, IBuffer headerSpace) 00104 { 00105 this.bridge = bridge; 00106 00107 // create a buffer for incoming requests 00108 buffer = new Buffer (HttpHeader.IOBufferSize); 00109 00110 // reuse the input buffer for headers too? 00111 if (headerSpace is null) 00112 headerSpace = buffer; 00113 00114 // create instance of bidi headers 00115 headers = new HttpMutableHeaders (headerSpace); 00116 } 00117 00118 /********************************************************************** 00119 00120 Reset this message 00121 00122 **********************************************************************/ 00123 00124 void reset() 00125 { 00126 encoding = null; 00127 mimeType = null; 00128 headers.reset(); 00129 } 00130 00131 /********************************************************************** 00132 00133 Set the IConduit used by this message; typically this is 00134 the SocketConduit instantiated in response to a connection 00135 request. 00136 00137 Given that the HttpMessage remains live (on a per-thread 00138 basis), this method will be called for each connection 00139 request. 00140 00141 **********************************************************************/ 00142 00143 void setConduit (IConduit conduit) 00144 { 00145 buffer.setConduit (conduit); 00146 buffer.clear(); 00147 } 00148 00149 /********************************************************************** 00150 00151 Return the IConduit in use 00152 00153 **********************************************************************/ 00154 00155 protected final IConduit getConduit () 00156 { 00157 return buffer.getConduit(); 00158 } 00159 00160 /********************************************************************** 00161 00162 Return the buffer bound to our conduit 00163 00164 **********************************************************************/ 00165 00166 protected final IBuffer getBuffer() 00167 { 00168 return buffer; 00169 } 00170 00171 /********************************************************************** 00172 00173 Return the HttpHeaders wrapper 00174 00175 **********************************************************************/ 00176 00177 protected final HttpMutableHeaders getHeader() 00178 { 00179 return headers; 00180 } 00181 00182 /********************************************************************** 00183 00184 Return the bridge used by the this message 00185 00186 **********************************************************************/ 00187 00188 protected final IProviderBridge getBridge() 00189 { 00190 return bridge; 00191 } 00192 00193 /********************************************************************** 00194 00195 Return the encoding string 00196 00197 **********************************************************************/ 00198 00199 char[] getEncoding() 00200 { 00201 return encoding; 00202 } 00203 00204 /********************************************************************** 00205 00206 Return the mime-type in use 00207 00208 **********************************************************************/ 00209 00210 char[] getMimeType() 00211 { 00212 return mimeType; 00213 } 00214 00215 /********************************************************************** 00216 00217 Set the content-type header, and parse it for encoding and 00218 mime-tpye information. 00219 00220 **********************************************************************/ 00221 00222 void setContentType (char[] type) 00223 { 00224 headers.add (HttpHeader.ContentType, type); 00225 setMimeAndEncoding (type); 00226 } 00227 00228 /********************************************************************** 00229 00230 Return the content-type from the headers. 00231 00232 **********************************************************************/ 00233 00234 char[] getContentType() 00235 { 00236 return Text.trim (headers.get (HttpHeader.ContentType)); 00237 } 00238 00239 /********************************************************************** 00240 00241 Parse a text string looking for encoding and mime information 00242 00243 **********************************************************************/ 00244 00245 protected void setMimeAndEncoding (char[] type) 00246 { 00247 encoding = null; 00248 mimeType = type; 00249 00250 if (type) 00251 { 00252 int semi = Text.indexOf (type, ';'); 00253 if (semi >= 0) 00254 { 00255 mimeType = Text.trim (type[0..semi]); 00256 int cs = Text.indexOf (type, "charset=", semi); 00257 if (cs >= 0) 00258 { 00259 cs += 8; 00260 int end = Text.indexOf (type, ' ', cs); 00261 if (end < 0) 00262 end = type.length; 00263 encoding = type[cs..end]; 00264 } 00265 } 00266 } 00267 } 00268 00269 /********************************************************************** 00270 00271 Output our headers to the provided IWriter 00272 00273 **********************************************************************/ 00274 00275 void write (IWriter writer) 00276 { 00277 headers.write (writer); 00278 } 00279 } 00280 00281 00282