Main Page | Class Hierarchy | Alphabetical List | Class List | File List | Class Members | File Members | Related Pages

HttpTokens.d

Go to the documentation of this file.
00001 /*******************************************************************************
00002 
00003         @file HttpTokens.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.HttpTokens;
00040 
00041 private import  mango.utils.Text;
00042 
00043 private import  mango.io.Token,
00044                 mango.io.Buffer,
00045                 mango.io.Tokenizer;
00046 
00047 private import  mango.format.Int,
00048                 mango.format.DateTime;
00049 
00050 private import  mango.io.model.IBuffer,
00051                 mango.io.model.IWriter;
00052 
00053 private import  mango.http.utils.TokenStack;
00054 
00055 /******************************************************************************
00056 
00057         Struct used to expose freachable HttpToken instances.
00058 
00059 ******************************************************************************/
00060 
00061 struct HttpToken
00062 {
00063         char[]          name,
00064                         value;
00065 }
00066 
00067 /******************************************************************************
00068 
00069         Maintains a set of HTTP tokens. These tokens include headers, query-
00070         parameters, and anything else vaguely similar. Both input and output
00071         are supported, though a subclass may choose to expose as read-only.
00072 
00073         All tokens are mapped directly onto a buffer, so there is no memory
00074         allocation or copying involved. 
00075 
00076         Note that this class does not support deleting tokens. Supporting
00077         such operations require a different approach, such as mapping the
00078         tokens into a temporary buffer, and then setting token content in
00079         the stack to be null when it is deleted. This could be implemented
00080         as a wrapper upon the subclasses of HttpToken.
00081 
00082 ******************************************************************************/
00083 
00084 class HttpTokens : IWritable
00085 {
00086         protected TokenStack    stack;
00087 
00088         private IBuffer         input,
00089                                 output;
00090         private bool            parsed;
00091         private bool            inclusive;
00092         private char            seperator;
00093         private char[1]         sepString;
00094         static private char[]   emptyString;
00095 
00096         /**********************************************************************
00097                 
00098                 Setup an empty character array for later assignment.
00099 
00100         **********************************************************************/
00101 
00102         static this ()
00103         {
00104                 emptyString = new char[0];
00105         }
00106 
00107         /**********************************************************************
00108                 
00109                 Construct a set of tokens based upon the given delimeter, 
00110                 and an indication of whether said delimeter should be
00111                 considered part of the left side (effectively the name).
00112         
00113                 The latter is useful with headers, since the seperating
00114                 ':' character should really be considered part of the 
00115                 name for purposes of subsequent token matching.
00116 
00117         **********************************************************************/
00118 
00119         this (char seperator, bool inclusive = false)
00120         {
00121                 stack = new TokenStack();
00122 
00123                 this.inclusive = inclusive;
00124                 this.seperator = seperator;
00125                 
00126                 // convert seperator into a string, for later use
00127                 sepString[0] = seperator;
00128 
00129                 // pre-construct an empty buffer for wrapping char[] parsing
00130                 input = new Buffer;
00131         }
00132 
00133         /**********************************************************************
00134                 
00135                 Clone a source set of HttpTokens
00136 
00137         **********************************************************************/
00138 
00139         this (HttpTokens source)
00140         {
00141                 stack = source.stack.clone();
00142                 input = null;
00143                 output = source.output;
00144                 parsed = true;
00145                 inclusive = source.inclusive;
00146                 seperator = source.seperator;
00147                 sepString[0] = source.sepString[0];
00148         }
00149 
00150         /**********************************************************************
00151                 
00152                 Read all tokens. Everything is mapped rather than being 
00153                 allocated & copied
00154 
00155         **********************************************************************/
00156 
00157         abstract void parse (IBuffer input);
00158 
00159         /**********************************************************************
00160                 
00161                 Parse an input string.
00162 
00163         **********************************************************************/
00164 
00165         void parse (char[] content)
00166         {
00167                 input.setValidContent (content);
00168                 parse (input);       
00169         }
00170 
00171         /**********************************************************************
00172                 
00173                 Reset this set of tokens.
00174 
00175         **********************************************************************/
00176 
00177         void reset ()
00178         {
00179                 stack.reset();
00180                 parsed = false;
00181 
00182                 // reset output buffer, if it was configured
00183                 if (output)
00184                     output.clear();
00185         }
00186 
00187         /**********************************************************************
00188                 
00189                 Have tokens been parsed yet?
00190 
00191         **********************************************************************/
00192 
00193         bool isParsed ()
00194         {
00195                 return parsed;
00196         }
00197 
00198         /**********************************************************************
00199                 
00200                 Indicate whether tokens have been parsed or not.
00201 
00202         **********************************************************************/
00203 
00204         void setParsed (bool parsed)
00205         {
00206                 this.parsed = parsed;
00207         }
00208 
00209         /**********************************************************************
00210                 
00211                 Return the value of the provided header, or null if the
00212                 header does not exist
00213 
00214         **********************************************************************/
00215 
00216         char[] get (char[] name)
00217         {
00218                 Token token = stack.findToken (name);
00219                 if (token)
00220                    {
00221                    HttpToken element;
00222 
00223                    if (split (token, element))
00224                        return element.value;
00225                    }
00226                 return null;
00227         }
00228 
00229         /**********************************************************************
00230                 
00231                 Return the integer value of the provided header, or -1 
00232                 if the header does not exist
00233 
00234         **********************************************************************/
00235 
00236         int getInt (char[] name)
00237         {       
00238                 int ret = -1;
00239 
00240                 char[] value = get (name);
00241 
00242                 if (value.length)
00243                     ret = Int.parse (value);
00244 
00245                 return ret;
00246         }
00247 
00248         /**********************************************************************
00249                 
00250                 Return the date value of the provided header, or -1 
00251                 if the header does not exist
00252 
00253         **********************************************************************/
00254 
00255         long getDate (char[] name)
00256         {
00257                 long   date  = -1;
00258                 char[] value = get (name);
00259 
00260                 if (value.length)
00261                     date = DateTime.parse (value);
00262 
00263                 return date;
00264         }
00265 
00266         /**********************************************************************
00267 
00268                 Iterate over the set of tokens
00269 
00270         **********************************************************************/
00271 
00272         int opApply (int delegate(inout HttpToken) dg)
00273         {
00274                 HttpToken element;
00275                 int       result = 0;
00276 
00277                 foreach (Token t; stack)
00278                          if (split (t, element))
00279                             {
00280                             result = dg (element);
00281                             if (result)
00282                                 break;
00283                             }
00284                 return result;
00285         }
00286 
00287         /**********************************************************************
00288 
00289                 Output the token list to the provided writer
00290 
00291         **********************************************************************/
00292 
00293         void write (IWriter writer)
00294         {
00295                 foreach (Token token; stack)
00296                         {
00297                         char[] content = token.toString;
00298                         if (content.length)
00299                             writer.put(content).cr();
00300                         }                           
00301         }
00302 
00303         /**********************************************************************
00304 
00305                 split basic token into an HttpToken
00306 
00307         **********************************************************************/
00308 
00309         final private bool split (Token t, inout HttpToken element)
00310         {
00311                 char[] s = t.toString();
00312 
00313                 if (s.length)
00314                    {
00315                    int i = Text.indexOf (s, seperator);
00316 
00317                    // we should always find the seperator
00318                    if (i > 0)
00319                       {
00320                       int j = (inclusive) ? i+1 : i;
00321                       element.name = s[0..j];
00322                       element.value = (i < s.length) ? s[i+1..s.length] : emptyString;
00323                       return true;
00324                       }
00325                    else
00326                       {
00327                       // throw new IOException("Invalid token '"~s~"'");
00328                       }
00329                    }
00330                 return false;                           
00331         }
00332 
00333         /**********************************************************************
00334 
00335                 Create a filter for iterating over the tokens matching
00336                 a particular name. 
00337         
00338         **********************************************************************/
00339 
00340         FilteredTokens createFilter (char[] match)
00341         {
00342                 return new FilteredTokens (this, match);
00343         }
00344 
00345         /**********************************************************************
00346 
00347                 Implements a filter for iterating over tokens matching
00348                 a particular name. We do it like this because there's no 
00349                 means of passing additional information to an opApply() 
00350                 method.
00351         
00352         **********************************************************************/
00353 
00354         private class FilteredTokens 
00355         {       
00356                 private char[]          match;
00357                 private HttpTokens      tokens;
00358 
00359                 /**************************************************************
00360 
00361                         Construct this filter upon the given tokens, and
00362                         set the pattern to match against.
00363 
00364                 **************************************************************/
00365 
00366                 this (HttpTokens tokens, char[] match)
00367                 {
00368                         this.match = match;
00369                         this.tokens = tokens;
00370                 }
00371 
00372                 /**************************************************************
00373 
00374                         Iterate over all tokens matching the given name
00375 
00376                 **************************************************************/
00377 
00378                 int opApply (int delegate(inout HttpToken) dg)
00379                 {
00380                         HttpToken       element;
00381                         int             result = 0;
00382                         
00383                         foreach (Token token; tokens.stack)
00384                                  if (tokens.stack.isMatch (token, match))
00385                                      if (tokens.split (token, element))
00386                                         {
00387                                         result = dg (element);
00388                                         if (result)
00389                                             break;
00390                                         }
00391                         return result;
00392                 }
00393 
00394         }
00395 
00396 
00397         /**********************************************************************
00398         ****************** these should be exposed carefully ******************
00399         **********************************************************************/
00400 
00401 
00402         /**********************************************************************
00403                 
00404                 Set the output buffer for adding tokens to. This is used
00405                 by the various MutableXXXX classes.
00406 
00407         **********************************************************************/
00408 
00409         protected void setOutputBuffer (IBuffer output)
00410         {
00411                 this.output = output;
00412         }
00413 
00414         /**********************************************************************
00415                 
00416                 Return the buffer used for output.
00417 
00418         **********************************************************************/
00419 
00420         protected IBuffer getOutputBuffer ()
00421         {
00422                 return output;
00423         }
00424 
00425         /**********************************************************************
00426                 
00427                 Return a char[] representing the output. An empty array
00428                 is returned if output was not configured.
00429 
00430         **********************************************************************/
00431 
00432         char[] toOutputString ()
00433         {
00434                 static const char[0] Null;
00435 
00436                 if (output)
00437                     return output.toString;
00438                 return Null;
00439         }
00440 
00441         /**********************************************************************
00442                 
00443                 Add a token with the given name. The content is provided
00444                 via the specified delegate. We stuff this name & content
00445                 into the output buffer, and map a new Token onto the
00446                 appropriate buffer slice.
00447 
00448         **********************************************************************/
00449 
00450         protected void add (char[] name, void delegate (IBuffer) dg)
00451         {
00452                 // save the buffer write-position
00453                 int prior = output.getLimit;
00454 
00455                 // add the name
00456                 output.append (name);
00457 
00458                 // don't append seperator if it's already part of the name
00459                 if (! inclusive)
00460                       output.append (sepString);
00461                 
00462                 // add the value
00463                 dg (output);
00464 
00465                 // map new token onto buffer slice
00466                 int limit = output.getLimit;
00467                 stack.push (output.toString[prior..limit]);
00468         }
00469 
00470         /**********************************************************************
00471                 
00472                 Add a simple name/value pair to the output
00473 
00474         **********************************************************************/
00475 
00476         protected void add (char[] name, char[] value)
00477         {
00478                 void addValue (IBuffer buffer)
00479                 {
00480                         buffer.append (value);
00481                 }
00482 
00483                 add (name, &addValue);
00484         }
00485 
00486         /**********************************************************************
00487                 
00488                 Add a name/integer pair to the output
00489 
00490         **********************************************************************/
00491 
00492         protected void addInt (char[] name, int value)
00493         {
00494                 char[16] tmp;
00495 
00496                 add (name, Int.format (tmp, value));
00497         }
00498 
00499 
00500         /**********************************************************************
00501                
00502                Add a name/date(long) pair to the output
00503                 
00504         **********************************************************************/
00505 
00506         protected void addDate (char[] name, long value)
00507         {
00508                 char[32] tmp;
00509 
00510                 add (name, DateTime.format (tmp, value));
00511         }
00512 }

Generated on Sun Mar 6 00:30:57 2005 for Mango by doxygen 1.3.6