Kannel: Open Source WAP and SMS gateway  svn-r5335
cookies.c File Reference
#include <string.h>
#include <ctype.h>
#include "gwlib/gwlib.h"
#include "wsp.h"
#include "cookies.h"

Go to the source code of this file.

Functions

static Octstrget_header_value (Octstr *)
 
static Cookieparse_cookie (Octstr *)
 
static void add_cookie_to_cache (const WSPMachine *, Cookie *)
 
static void expire_cookies (List *)
 
static void cookie_destroy (void *)
 
static int have_cookie (List *, Cookie *)
 
static int parse_http_date (const char *)
 
Cookiecookie_create (void)
 
void cookies_destroy (List *cookies)
 
int get_cookies (List *headers, const WSPMachine *sm)
 
int set_cookies (List *headers, WSPMachine *sm)
 
static int month_index (const char *s)
 

Variables

static Cookie emptyCookie
 
static const char * months []
 

Function Documentation

◆ add_cookie_to_cache()

static void add_cookie_to_cache ( const WSPMachine sm,
Cookie value 
)
static

Definition at line 344 of file cookies.c.

References gw_assert(), and gwlist_append().

Referenced by get_cookies().

345 {
346  gw_assert(sm != NULL);
347  gw_assert(sm->cookies != NULL);
348  gw_assert(value != NULL);
349 
350  gwlist_append(sm->cookies, value);
351 
352  return;
353 }
gw_assert(wtls_machine->packet_to_send !=NULL)
void gwlist_append(List *list, void *item)
Definition: list.c:179

◆ cookie_create()

Cookie* cookie_create ( void  )

Definition at line 88 of file cookies.c.

References emptyCookie.

Referenced by parse_cookie().

89 {
90  Cookie *p;
91 
92  p = gw_malloc(sizeof(Cookie)); /* Never returns NULL */
93 
94  *p = emptyCookie;
95  p -> max_age = -1;
96  time (&p -> birth);
97  return p;
98 }
static Cookie emptyCookie
Definition: cookies.c:85

◆ cookie_destroy()

static void cookie_destroy ( void *  p)
static

Definition at line 455 of file cookies.c.

References debug(), _cookie::domain, _cookie::name, octstr_destroy(), _cookie::path, _cookie::value, and _cookie::version.

Referenced by cookies_destroy(), expire_cookies(), get_cookies(), have_cookie(), and parse_cookie().

456 {
457  Cookie *cookie;
458 
459  if (p == NULL)
460  return;
461  cookie = p;
462 
463  octstr_destroy(cookie->name);
464  octstr_destroy(cookie->value);
465  octstr_destroy(cookie->version);
466  octstr_destroy(cookie->domain);
467  octstr_destroy(cookie->path);
468 
469  gw_free(cookie);
470  debug("wap.wsp.http", 0, "cookie_destroy: Destroyed cookie");
471  return;
472 }
void octstr_destroy(Octstr *ostr)
Definition: octstr.c:324
void debug(const char *place, int err, const char *fmt,...)
Definition: log.c:726

◆ cookies_destroy()

void cookies_destroy ( List cookies)

Definition at line 100 of file cookies.c.

References cookie_destroy(), gwlib_assert_init(), and gwlist_destroy().

101 {
103 
104  if (cookies == NULL)
105  return;
106 
107  gwlist_destroy(cookies, cookie_destroy);
108 }
static void cookie_destroy(void *)
Definition: cookies.c:455
void() gwlib_assert_init(void)
Definition: gwlib.c:72
void gwlist_destroy(List *list, gwlist_item_destructor_t *destructor)
Definition: list.c:145

◆ expire_cookies()

static void expire_cookies ( List cookies)
static

Definition at line 419 of file cookies.c.

References _cookie::birth, cookie_destroy(), debug(), error(), gw_assert(), gwlist_delete(), gwlist_get(), gwlist_len(), _cookie::max_age, _cookie::name, and octstr_get_cstr.

Referenced by set_cookies().

420 {
421  Cookie *value = NULL;
422  time_t now = 0;
423  long pos = 0;
424 
425  if (cookies == NULL) {
426  error(0, "expire_cookies: Null argument(s) - no Cookie list");
427  return;
428  }
429 
430  /* Walk through the cookie cache */
431 
432  time(&now);
433 
434  if (gwlist_len(cookies) > 0) {
435  debug("wap.wsp.http", 0, "expire_cookies: Cookies in cache");
436  for (pos = 0; pos < gwlist_len(cookies); pos++) {
437  value = gwlist_get(cookies, pos);
438  gw_assert(value != NULL);
439 
440  if (value->max_age != -1) { /* Interesting value */
441  if (value->max_age + value->birth < now) {
442  debug("wap.wsp.http", 0, "expire_cookies: Expired cookie (%s)",
443  octstr_get_cstr(value->name));
444  cookie_destroy(value);
445  gwlist_delete(cookies, pos, 1);
446  }
447  }
448  }
449  } else
450  debug("wap.wsp.http", 0, "expire_cookies: No cookies in cache");
451 
452  return;
453 }
void error(int err, const char *fmt,...)
Definition: log.c:648
gw_assert(wtls_machine->packet_to_send !=NULL)
long gwlist_len(List *list)
Definition: list.c:166
void * gwlist_get(List *list, long pos)
Definition: list.c:292
#define octstr_get_cstr(ostr)
Definition: octstr.h:233
static void cookie_destroy(void *)
Definition: cookies.c:455
void gwlist_delete(List *list, long pos, long count)
Definition: list.c:232
void debug(const char *place, int err, const char *fmt,...)
Definition: log.c:726

◆ get_cookies()

int get_cookies ( List headers,
const WSPMachine sm 
)

Definition at line 111 of file cookies.c.

References add_cookie_to_cache(), cookie_destroy(), debug(), error(), get_header_value(), gwlist_get(), gwlist_len(), have_cookie(), info(), name, octstr_get_cstr, and parse_cookie().

Referenced by return_reply().

112 {
113  Octstr *header = NULL;
114  Octstr *value = NULL;
115  Cookie *cookie = NULL;
116  long pos = 0;
117 
118  /*
119  * This can happen if the user aborts while the HTTP request is pending from the server.
120  * In that case, the session machine is destroyed and is not available to this function
121  * for cookie caching.
122  */
123 
124  if (sm == NULL) {
125  info (0, "No session machine for cookie retrieval");
126  return 0;
127  }
128 
129  for (pos = 0; pos < gwlist_len(headers); pos++) {
130  header = gwlist_get(headers, pos);
131  /* debug ("wap.wsp.http", 0, "get_cookies: Examining header (%s)", octstr_get_cstr (header)); */
132  if (strncasecmp ("set-cookie", octstr_get_cstr (header),10) == 0) {
133  debug ("wap.wsp.http", 0, "Caching cookie (%s)", octstr_get_cstr (header));
134 
135  if ((value = get_header_value (header)) == NULL) {
136  error (0, "get_cookies: No value in (%s)", octstr_get_cstr(header));
137  continue;
138  }
139 
140  /* Parse the received cookie */
141  if ((cookie = parse_cookie(value)) != NULL) {
142 
143  /* Check to see if this cookie is already present */
144  if (have_cookie(sm->cookies, cookie) == 1) {
145  debug("wap.wsp.http", 0, "parse_cookie: Cookie present");
146  cookie_destroy(cookie);
147  continue;
148  } else {
149  add_cookie_to_cache(sm, cookie);
150  debug("wap.wsp.http", 0, "get_cookies: Added (%s)",
151  octstr_get_cstr(cookie -> name));
152  }
153  }
154  }
155  }
156 
157  debug("wap.wsp.http", 0, "get_cookies: End");
158  return 0;
159 }
void error(int err, const char *fmt,...)
Definition: log.c:648
void info(int err, const char *fmt,...)
Definition: log.c:672
long gwlist_len(List *list)
Definition: list.c:166
void * gwlist_get(List *list, long pos)
Definition: list.c:292
#define octstr_get_cstr(ostr)
Definition: octstr.h:233
static int have_cookie(List *, Cookie *)
Definition: cookies.c:361
static Octstr * get_header_value(Octstr *)
Definition: cookies.c:218
static void cookie_destroy(void *)
Definition: cookies.c:455
static Cookie * parse_cookie(Octstr *)
Definition: cookies.c:248
char * name
Definition: smsc_cimd2.c:212
Definition: octstr.c:118
void debug(const char *place, int err, const char *fmt,...)
Definition: log.c:726
static void add_cookie_to_cache(const WSPMachine *, Cookie *)
Definition: cookies.c:344

◆ get_header_value()

static Octstr * get_header_value ( Octstr header)
static

Definition at line 218 of file cookies.c.

References colon, debug(), error(), octstr_copy, octstr_get_cstr, octstr_len(), octstr_search_char(), and octstr_strip_blanks().

Referenced by get_cookies().

219 {
220  Octstr *h = NULL;
221  long colon = -1;
222 
223  if (header == NULL) {
224  error(0, "get_header_value: NULL argument");
225  return NULL;
226  }
227 
228  octstr_strip_blanks(header);
229  colon = octstr_search_char(header, ':', 0);
230  if (colon == -1) {
231  error(0, "get_header_value: Malformed header (%s)", octstr_get_cstr (header));
232  return NULL;
233  } else {
234  h = octstr_copy(header, colon + 1, octstr_len(header));
236  }
237 
238  debug("wap.wsp.http", 0, "get_header_value: Value (%s)", octstr_get_cstr (h));
239  return h;
240 }
void error(int err, const char *fmt,...)
Definition: log.c:648
void octstr_strip_blanks(Octstr *text)
Definition: octstr.c:1346
#define octstr_get_cstr(ostr)
Definition: octstr.h:233
#define octstr_copy(ostr, from, len)
Definition: octstr.h:178
long octstr_search_char(const Octstr *ostr, int ch, long pos)
Definition: octstr.c:1012
static Octstr * colon
Definition: smsc_smasi.c:218
long octstr_len(const Octstr *ostr)
Definition: octstr.c:342
Definition: octstr.c:118
void debug(const char *place, int err, const char *fmt,...)
Definition: log.c:726

◆ have_cookie()

static int have_cookie ( List cookies,
Cookie cookie 
)
static

Definition at line 361 of file cookies.c.

References cookie_destroy(), debug(), _cookie::domain, error(), gwlist_delete(), gwlist_get(), gwlist_len(), _cookie::max_age, _cookie::name, octstr_compare(), octstr_get_cstr, and _cookie::path.

Referenced by get_cookies().

362 {
363  Cookie *value = NULL;
364  long pos = 0;
365 
366  if (cookies == NULL || cookie == NULL) {
367  error(0, "have_cookie: Null argument(s) - no Cookie list, Cookie or both");
368  return 0;
369  }
370 
371  /* Walk through the cookie cache, comparing cookie */
372  while (pos < gwlist_len(cookies)) {
373  value = gwlist_get(cookies, pos);
374 
375  /* octstr_compare() now only returns 0 on an exact match or if both args are 0 */
376  debug ("wap.wsp.http", 0, "have_cookie: Comparing name (%s:%s), path (%s:%s), domain (%s:%s)",
377  octstr_get_cstr(cookie->name), octstr_get_cstr(value->name),
378  octstr_get_cstr(cookie->path), octstr_get_cstr(value->path),
379  octstr_get_cstr(cookie->domain), octstr_get_cstr(value->domain));
380 
381  /* Match on no value or value and value equality for name, path and domain */
382  if (
383  (value->name == NULL ||
384  ((value->name != NULL && cookie->name != NULL) && octstr_compare(value->name, cookie->name) == 0)) &&
385  (value->path == NULL ||
386  ((value->path != NULL && cookie->path != NULL) && octstr_compare(value->path, cookie->path) == 0)) &&
387  (value->domain == NULL ||
388  ((value->domain != NULL && cookie->domain != NULL) && octstr_compare(value->domain, cookie->domain) == 0))
389  ) {
390 
391  /* We have a match according to 4.3.3 - discard the old one */
392  cookie_destroy(value);
393  gwlist_delete(cookies, pos, 1);
394 
395  /* Discard the new cookie also if max-age is 0 - set if expiry date is up */
396  if (cookie->max_age == 0) {
397  debug("wap.wsp.http", 0, "have_cookie: Discarding expired cookie (%s)",
398  octstr_get_cstr(cookie->name));
399  return 1;
400  }
401 
402  debug("wap.wsp.http", 0, "have_cookie: Updating cached cookie (%s)",
403  octstr_get_cstr (cookie->name));
404  break;
405  } else {
406  pos++;
407  }
408  }
409 
410  return 0;
411 }
void error(int err, const char *fmt,...)
Definition: log.c:648
long gwlist_len(List *list)
Definition: list.c:166
void * gwlist_get(List *list, long pos)
Definition: list.c:292
#define octstr_get_cstr(ostr)
Definition: octstr.h:233
static void cookie_destroy(void *)
Definition: cookies.c:455
void gwlist_delete(List *list, long pos, long count)
Definition: list.c:232
void debug(const char *place, int err, const char *fmt,...)
Definition: log.c:726
int octstr_compare(const Octstr *ostr1, const Octstr *ostr2)
Definition: octstr.c:871

◆ month_index()

static int month_index ( const char *  s)
static

Definition at line 508 of file cookies.c.

References months.

Referenced by parse_http_date().

509 {
510  const char **p = &months[0];
511  int i = 0;
512 
513  while (*p != NULL) {
514  if (strcmp(s, *p) == 0)
515  return i;
516  p++, i++;
517  }
518 
519  return -1;
520 }
static const char * months[]
Definition: cookies.c:503

◆ parse_cookie()

static Cookie * parse_cookie ( Octstr cookiestr)
static

Definition at line 248 of file cookies.c.

References cookie_create(), cookie_destroy(), error(), _cookie::max_age, _cookie::name, octstr_append_cstr(), octstr_create, octstr_get_cstr, parse_http_date(), and _cookie::value.

Referenced by get_cookies().

249 {
250  char *v = NULL;
251  char *p = NULL;
252  int delta = 0;
253  Cookie *c = NULL;
254  Octstr **f = NULL;
255 
256  if (cookiestr == NULL) {
257  error(0, "parse_cookie: NULL argument");
258  return NULL;
259  }
260 
261  v = gw_strdup(octstr_get_cstr (cookiestr));
262  p = strtok(v, ";");
263 
264  c = cookie_create(); /* Never returns NULL */
265 
266  while (p != NULL) {
267  while (isspace((int)*p)) p++; /* Skip leading whitespace */
268 
269  if (strncasecmp("version", p, 7) == 0)
270  f = &c -> version;
271  else if (strncasecmp("path", p, 4) == 0)
272  f = &c -> path;
273  else if (strncasecmp("domain", p, 6) == 0)
274  f = &c -> domain; /* XXX DAVI: Shouldn't we check if domain is similar
275  * to real domain, and to set domain to
276  * real domain if not set by header ??? */
277  else if (strncasecmp("max-age", p, 7) == 0) {
278  c -> max_age = atol(strrchr (p, '=') + 1);
279  p = strtok(NULL, ";");
280  continue;
281  }
282  else if (strncasecmp("expires", p, 7) == 0) {
283  delta = parse_http_date(p);
284  if (delta != -1)
285  c->max_age = delta;
286  p = strtok(NULL, ";");
287  continue;
288  }
289  else if (strncasecmp("comment", p, 7) == 0 ) { /* Ignore comments */
290  p = strtok(NULL, ";");
291  continue;
292  }
293  else if (strncasecmp("secure", p, 6) == 0 ) { /* XXX DAVI: this should processed */
294  p = strtok(NULL, ";");
295  continue;
296  }
297  else { /* Name value pair - this should be first */
298  char *equals = NULL;
299 
300  if ((equals = strchr(p, '=')) != NULL) {
301  *equals = '\0';
302 
303  c->name = octstr_create(p);
304  c->value = octstr_create(equals + 1);
305  } else {
306  error(0, "parse_cookie: Bad name=value cookie component (%s)", p);
307  cookie_destroy(c);
308  return NULL;
309  }
310  p = strtok(NULL, ";");
311  continue;
312  }
313 
314  if (*f != NULL) { /* Undefined behaviour - 4.2.2 */
315  error(0, "parse_cookie: Duplicate cookie field (%s), discarding", p);
316  p = strtok(NULL, ";");
317  continue;
318  }
319 
320  *f = octstr_create("$");
321  octstr_append_cstr(*f, p);
322  p = strtok(NULL, ";");
323  }
324 
325  /* Process version - 4.3.4
326  * XXX DAVI: Altough it seems to be "MUST" in RFC, no one sends a Version
327  * tag when it's value is "0"
328  if (c->version == NULL) {
329  c->version = octstr_create("");
330  octstr_append_cstr(c->version, "$Version=\"0\";");
331  }
332  */
333 
334  gw_free (v);
335  return c;
336 }
void error(int err, const char *fmt,...)
Definition: log.c:648
void octstr_append_cstr(Octstr *ostr, const char *cstr)
Definition: octstr.c:1511
#define octstr_get_cstr(ostr)
Definition: octstr.h:233
static void cookie_destroy(void *)
Definition: cookies.c:455
static int parse_http_date(const char *)
Definition: cookies.c:522
Cookie * cookie_create(void)
Definition: cookies.c:88
#define octstr_create(cstr)
Definition: octstr.h:125
Definition: octstr.c:118

◆ parse_http_date()

static int parse_http_date ( const char *  expires)
static

Definition at line 522 of file cookies.c.

References date(), debug(), error(), gw_mktime(), MAX_HTTP_DATE_LENGTH, and month_index().

Referenced by parse_cookie().

523 {
524  struct tm ti;
525  char *p = NULL;
526  char *date = NULL;
527  char month[MAX_HTTP_DATE_LENGTH];
528  time_t rv;
529  time_t now;
530 
531  memset(&ti, 0, sizeof(struct tm));
532 
533  /* Break up the Expires: header */
534  if (!(date = strchr(expires, '='))) {
535  error(0, "parse_http_date: Bogus expires type=value header (%s)", expires);
536  return -1;
537  } else {
538  date++;
539  while (isspace((int)*date))
540  ++date;
541  }
542 
543  /* Onto the date value */
544  if (!(p = strchr (date,' '))) {
545  error(0, "parse_http_date: Bogus date string (%s)", date);
546  return -1;
547  } else
548  while (isspace((int)*p))
549  ++p;
550 
551  if (MAX_HTTP_DATE_LENGTH < strlen(p)) {
552  error(0, "parse_http_date: %s blows length limit (%d)", date, MAX_HTTP_DATE_LENGTH);
553  return -1;
554  }
555 
556  if (isalpha((int)*p)) {
557  /* ctime */
558  sscanf(p, (strstr(p, "DST") ? "%s %d %d:%d:%d %*s %d" : "%s %d %d:%d:%d %d"),
559  month, &ti.tm_mday, &ti.tm_hour, &ti.tm_min,
560  &ti.tm_sec, &ti.tm_year);
561  ti.tm_year -= 1900;
562 
563  } else if (p[2] == '-') {
564  /* RFC 850 (normal HTTP) */
565  char buf[MAX_HTTP_DATE_LENGTH];
566 
567  sscanf(p, "%s %d:%d:%d", buf, &ti.tm_hour, &ti.tm_min, &ti.tm_sec);
568  buf[2] = '\0';
569  ti.tm_mday = atoi(buf);
570  buf[6] = '\0';
571 
572  strcpy(month, &buf[3]);
573  ti.tm_year = atoi(&buf[7]);
574 
575  /* Prevent wraparound from ambiguity */
576 
577  if (ti.tm_year < 70) {
578  ti.tm_year += 100;
579  } else if (ti.tm_year > 1900) {
580  ti.tm_year -= 1900;
581  }
582  } else {
583  /* RFC 822 */
584  sscanf(p,"%d %s %d %d:%d:%d",&ti.tm_mday, month, &ti.tm_year,
585  &ti.tm_hour, &ti.tm_min, &ti.tm_sec);
586 
587  /*
588  * since tm_year is years since 1900 and the year we parsed
589  * is absolute, we need to subtract 1900 years from it
590  */
591  ti.tm_year -= 1900;
592  }
593 
594  ti.tm_mon = month_index(month);
595  if (ti.tm_mon == -1) {
596  error(0, "parse_http_date () failed on bad month value (%s)", month);
597  return -1;
598  }
599 
600  ti.tm_isdst = -1;
601 
602  rv = gw_mktime(&ti);
603  if (ti.tm_isdst)
604  rv -= 3600;
605 
606  if (rv == -1) {
607  error(0, "parse_http_date(): mktime() was unable to resolve date/time: %s",
608  asctime(&ti));
609  return -1;
610  }
611 
612  debug("parse_http_date", 0, "Parsed date (%s) as: %s", date, asctime(&ti));
613 
614  /*
615  * If rv is valid, it should be some time in the (near) future. Normalise this to
616  * a max-age semantic so we can use the same expiry mechanism
617  */
618  now = time(NULL);
619 
620  if (rv - now < 0) {
621  /* This is bad - set the delta to 0 so we expire next time around */
622  error(0, "parse_http_date () Expiry time (%s) (delta=%ld) is in the past !",
623  asctime(&ti), rv-now);
624  return 0;
625  }
626 
627  return rv - now;
628 }
void error(int err, const char *fmt,...)
Definition: log.c:648
static int month_index(const char *s)
Definition: cookies.c:508
time_t gw_mktime(struct tm *tm)
Definition: protected.c:153
#define MAX_HTTP_DATE_LENGTH
Definition: cookies.h:106
void debug(const char *place, int err, const char *fmt,...)
Definition: log.c:726
static int date(int hex)

◆ set_cookies()

int set_cookies ( List headers,
WSPMachine sm 
)

Definition at line 162 of file cookies.c.

References debug(), _cookie::domain, error(), expire_cookies(), gwlist_append(), gwlist_get(), gwlist_len(), _cookie::name, octstr_append(), octstr_append_char(), octstr_create, octstr_get_cstr, _cookie::path, _cookie::value, and _cookie::version.

Referenced by start_fetch().

163 {
164  Cookie *value = NULL;
165  Octstr *cookie = NULL;
166  long pos = 0;
167 
168  if (headers == NULL || sm == NULL) {
169  error (0, "set_cookies: Null argument(s) - no headers, WSPMachine or both");
170  return -1;
171  }
172 
173  /* Expire cookies that have timed out */
174  expire_cookies(sm->cookies);
175 
176  /* Walk through the cookie cache, adding the cookie to the request headers */
177  if (gwlist_len(sm->cookies) > 0) {
178  debug("wap.wsp.http", 0, "set_cookies: Cookies in cache");
179 
180  for (pos = 0; pos < gwlist_len(sm->cookies); pos++) {
181  value = gwlist_get(sm->cookies, pos);
182 
183  cookie = octstr_create("Cookie: ");
184  if (value->version)
185  octstr_append(cookie, value->version);
186  octstr_append(cookie, value->name);
187  octstr_append_char(cookie, '=');
188  octstr_append(cookie, value->value);
189 
190  if (value->path) {
191  octstr_append_char(cookie, ';');
192  octstr_append(cookie, value->path);
193  }
194  if (value->domain) {
195  octstr_append_char(cookie, ';');
196  octstr_append(cookie, value->domain);
197  }
198 
199  gwlist_append(headers, cookie);
200  debug("wap.wsp.http", 0, "set_cookies: Added (%s)", octstr_get_cstr (cookie));
201  }
202  } else
203  debug("wap.wsp.http", 0, "set_cookies: No cookies in cache");
204 
205  return 0;
206 }
void error(int err, const char *fmt,...)
Definition: log.c:648
void gwlist_append(List *list, void *item)
Definition: list.c:179
void octstr_append(Octstr *ostr1, const Octstr *ostr2)
Definition: octstr.c:1504
long gwlist_len(List *list)
Definition: list.c:166
void * gwlist_get(List *list, long pos)
Definition: list.c:292
void octstr_append_char(Octstr *ostr, int ch)
Definition: octstr.c:1517
#define octstr_get_cstr(ostr)
Definition: octstr.h:233
static void expire_cookies(List *)
Definition: cookies.c:419
#define octstr_create(cstr)
Definition: octstr.h:125
Definition: octstr.c:118
void debug(const char *place, int err, const char *fmt,...)
Definition: log.c:726

Variable Documentation

◆ emptyCookie

Cookie emptyCookie
static

Definition at line 85 of file cookies.c.

Referenced by cookie_create().

◆ months

const char* months[]
static
Initial value:
= {
"Jan", "Feb", "Mar", "Apr", "May", "Jun",
"Jul", "Aug", "Sep", "Oct", "Nov", "Dec", NULL
}

Definition at line 503 of file cookies.c.

Referenced by month_index().

See file LICENSE for details about the license agreement for using, modifying, copying or deriving work from this software.