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