Main Page | Modules | Data Structures | Directories | File List | Data Fields | Globals

header.c

00001 /*
00002  * Copyright (c) 2005, 2006 by KoanLogic s.r.l. <http://www.koanlogic.com>
00003  * All rights reserved.
00004  *
00005  * This file is part of KLone, and as such it is subject to the license stated
00006  * in the LICENSE file which you have received as part of this distribution.
00007  *
00008  * $Id: header.c,v 1.20 2007/10/26 11:21:51 tho Exp $
00009  */
00010 
00011 #include "klone_conf.h"
00012 #include <u/libu.h>
00013 #include <klone/os.h>
00014 #include <klone/header.h>
00015 #include <klone/utils.h>
00016 
00029 int header_set_field(header_t *h, const char *name, const char *value)
00030 {
00031     field_t* n = NULL, *ex;
00032 
00033     dbg_err_if (h == NULL);
00034     dbg_err_if (name == NULL);
00035     dbg_err_if (value == NULL);
00036 
00037     /* modify existing field if already set */
00038     if((ex = header_get_field(h, name)) == NULL)
00039     {
00040         dbg_err_if(field_create(name, value, &n));
00041         dbg_err_if(header_add_field(h, n));
00042     } else
00043         dbg_err_if(field_set(ex, name, value));
00044 
00045     return 0;
00046 err:
00047     if(n)
00048         field_free(n);
00049     return ~0;
00050 }
00051 
00062 int header_clear(header_t *h)
00063 {
00064     field_t *f;
00065     
00066     dbg_return_if (h == NULL, ~0);
00067     
00068     /* free all items */
00069     while((f = TAILQ_FIRST(&h->fields)) != NULL)
00070     {
00071         header_del_field(h, f);
00072         field_free(f);
00073     }
00074 
00075     return 0;
00076 }
00077 
00088 size_t header_field_count(header_t *h)
00089 {
00090     dbg_return_if (h == NULL, 0);
00091 
00092     return h->nfields;
00093 }
00094 
00106 field_t *header_get_fieldn(header_t *h, size_t idx)
00107 {
00108     field_t *f;
00109     size_t i = 0;
00110 
00111     dbg_goto_if (h == NULL, notfound);
00112     nop_goto_if (idx >= h->nfields, notfound);
00113 
00114     TAILQ_FOREACH(f, &h->fields, np)
00115     {
00116         if(i == idx)
00117             return f;
00118         ++i;
00119     }
00120 
00121 notfound:
00122     return NULL;
00123 }
00124 
00138 field_t *header_get_field(header_t *h, const char *name)
00139 {
00140     field_t *f = NULL;
00141 
00142     dbg_goto_if (h == NULL, notfound);
00143     dbg_goto_if (name == NULL, notfound);
00144 
00145     TAILQ_FOREACH(f, &h->fields, np)
00146         if(strcasecmp(f->name, name) == 0)
00147             return f;
00148 
00149 notfound:
00150     return NULL;
00151 }
00152 
00166 const char *header_get_field_value(header_t *h, const char *name)
00167 {
00168     field_t *f;
00169 
00170     dbg_return_if (h == NULL, NULL);
00171     dbg_return_if (name == NULL, NULL);
00172     
00173     f = header_get_field(h, name);
00174 
00175     return f ? field_get_value(f) : NULL;
00176 }
00177 
00189 int header_del_field(header_t *h, field_t *f)
00190 {
00191     dbg_return_if (h == NULL, ~0);
00192     dbg_return_if (f == NULL, ~0);
00193 
00194     TAILQ_REMOVE(&h->fields, f, np);
00195     h->nfields--;
00196 
00197     return 0;
00198 }
00199 
00211 int header_add_field(header_t *h, field_t *f)
00212 {
00213     dbg_return_if (h == NULL, ~0);
00214     dbg_return_if (f == NULL, ~0);
00215 
00216     TAILQ_INSERT_TAIL(&h->fields, f, np);
00217     h->nfields++;
00218 
00219     return 0;
00220 }
00221 
00222 static int header_process_line(header_t *h, u_string_t *line, int mode)
00223 {
00224     field_t *ex, *f = NULL;
00225     const char *p;
00226 
00227     dbg_err_if (h == NULL);
00228     dbg_err_if (line == NULL);
00229     
00230     if(!u_string_len(line))
00231         return 0;
00232 
00233     /* alloc a new field */
00234     dbg_err_if(field_create(NULL, NULL, &f));
00235 
00236     /* parse and set name, value and params */
00237     dbg_err_if(field_set_from_line(f, u_string_c(line)));
00238 
00239     /* add to this header */
00240     switch(mode)
00241     {
00242     case HLM_ADD:
00243         dbg_err_if(header_add_field(h, f));
00244         break;
00245     case HLM_OVERRIDE:
00246         if((ex = header_get_field(h, field_get_name(f))) != NULL)
00247         {
00248             header_del_field(h, ex);
00249             field_free(ex); ex = NULL;
00250         }
00251         dbg_err_if(header_add_field(h, f));
00252         break;
00253     case HLM_KEEP:
00254         if((ex = header_get_field(h, field_get_name(f))) == NULL)
00255             dbg_err_if(header_add_field(h, f));
00256         else {
00257             field_free(f); f = NULL;
00258         }
00259         break;
00260     default:
00261         crit_err("unknown header load mode");
00262     }
00263 
00264     return 0;
00265 err:
00266     if(f)
00267         field_free(f);
00268     return ~0;
00269 }
00270 
00271 /* load from environment. change each HTTP_name=value to name=value (replacing
00272    '_' with '-' */
00273 int header_load_from_cgienv(header_t *h)
00274 {
00275     extern char **environ;
00276     enum { BUFSZ = 256 };
00277     int i;
00278     size_t blen, t;
00279     char *e, *eq, buf[BUFSZ];
00280 
00281     /* add HTTP_* to header field list */
00282     for(i = 0; environ[i]; ++i)
00283     {
00284         e = environ[i];
00285         if(strlen(e) > 5 && strncmp("HTTP_", e, 5) == 0)
00286         {
00287             memset(buf, 0, sizeof(buf));
00288 
00289             /* make a copy of e so we can modify it */
00290             strncpy(buf, e + 5, MIN(BUFSZ, strlen(e + 5)));
00291             buf[BUFSZ-1] = 0;
00292 
00293             eq = strchr(buf, '=');
00294             if(eq == NULL)
00295                 continue; /* malformed */
00296 
00297             *eq = 0; /* put a \0 between name and value */
00298 
00299             /* subst '_' with '-' */
00300             for(t = 0, blen = strlen(buf); t < blen; ++t)
00301                 if(buf[t] == '_')
00302                     buf[t] = '-';
00303 
00304             dbg_if(header_set_field(h, buf, 1 + eq));
00305         }
00306     }
00307 
00308     return 0;
00309 err:
00310     return ~0;
00311 }
00312 
00313 int header_load_ex(header_t *h , io_t *io, int mode)
00314 {
00315     enum { HEADER_MAX_FIELD_COUNT = 256 }; /* max num of header fields */
00316     u_string_t *line = NULL, *unfolded = NULL;
00317     const char *ln;
00318     size_t len, c;
00319 
00320     dbg_err_if (h == NULL);
00321     dbg_err_if (io == NULL);
00322 
00323     dbg_err_if(u_string_create(NULL, 0, &line));
00324     dbg_err_if(u_string_create(NULL, 0, &unfolded));
00325 
00326     for(c = HEADER_MAX_FIELD_COUNT; u_getline(io, line) == 0; --c)
00327     {
00328         warn_err_ifm(c == 0, "too much header fields");
00329 
00330         ln = u_string_c(line);
00331         len = u_string_len(line);
00332 
00333         /* remove trailing nl(s) */
00334         while(len && u_isnl(ln[len-1]))
00335             u_string_set_length(line, --len);
00336 
00337         if(u_string_len(line) == 0)
00338             break; /* empty line */
00339 
00340         if(u_isblank(ln[0])) 
00341         {   /* this is a chunk of a folded line */
00342             dbg_err_if(u_string_append(unfolded, ln, u_string_len(line)));
00343         } else {
00344             if(u_string_len(unfolded))
00345             {
00346                 /* go process this (already unfolded) line */
00347                 header_process_line(h, unfolded, mode);
00348                 u_string_clear(unfolded);
00349             }
00350             /* this may be the first line of a folded line so wait next lines */
00351             u_string_copy(unfolded, line);
00352         }
00353     }
00354 
00355     if(u_string_len(unfolded))
00356         header_process_line(h, unfolded, mode);
00357 
00358     u_string_free(unfolded);
00359     u_string_free(line);
00360 
00361     return 0;
00362 err:
00363     if(line)
00364         u_string_free(line);
00365     if(unfolded)
00366         u_string_free(unfolded);
00367     return ~0;
00368 }
00369 
00370 int header_load(header_t *h , io_t *io)
00371 {
00372     return header_load_ex(h, io, HLM_ADD);
00373 }
00374 
00375 int header_create(header_t **ph)
00376 {
00377     header_t *h = NULL;
00378 
00379     dbg_err_if (ph == NULL);
00380 
00381     h = u_zalloc(sizeof(header_t));
00382     dbg_err_if(h == NULL);
00383 
00384     TAILQ_INIT(&h->fields);
00385 
00386     *ph = h;
00387 
00388     return 0;
00389 err:
00390     return ~0;
00391 }
00392 
00393 int header_free(header_t *h)
00394 {
00395     if (h)
00396     {
00397         (void) header_clear(h);
00398         U_FREE(h);
00399     }
00400 
00401     return 0;
00402 }