00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039
00040
00041
00042
00043
00044
00045
00046
00047
00048
00049
00050
00051
00052
00053
00054
00055
00056
00057
00058
00059
00060
00061
00062
00063
00064
00065
00066
00067
00068
00069 #include <string.h>
00070 #include <ctype.h>
00071
00072 #include "gwlib/gwlib.h"
00073 #include "wsp.h"
00074 #include "cookies.h"
00075
00076
00077
00078 static Octstr *get_header_value(Octstr*);
00079 static Cookie *parse_cookie(Octstr*);
00080 static void add_cookie_to_cache(const WSPMachine*, Cookie*);
00081 static void expire_cookies(List*);
00082 static void cookie_destroy(void*);
00083 static int have_cookie(List*, Cookie*);
00084 static int parse_http_date(const char*);
00085 static Cookie emptyCookie;
00086
00087
00088 Cookie *cookie_create(void)
00089 {
00090 Cookie *p;
00091
00092 p = gw_malloc(sizeof(Cookie));
00093
00094 *p = emptyCookie;
00095 p -> max_age = -1;
00096 time (&p -> birth);
00097 return p;
00098 }
00099
00100 void cookies_destroy(List *cookies)
00101 {
00102 gwlib_assert_init();
00103
00104 if (cookies == NULL)
00105 return;
00106
00107 gwlist_destroy(cookies, cookie_destroy);
00108 }
00109
00110
00111 int get_cookies(List *headers, const WSPMachine *sm)
00112 {
00113 Octstr *header = NULL;
00114 Octstr *value = NULL;
00115 Cookie *cookie = NULL;
00116 long pos = 0;
00117
00118
00119
00120
00121
00122
00123
00124 if (sm == NULL) {
00125 info (0, "No session machine for cookie retrieval");
00126 return 0;
00127 }
00128
00129 for (pos = 0; pos < gwlist_len(headers); pos++) {
00130 header = gwlist_get(headers, pos);
00131
00132 if (strncasecmp ("set-cookie", octstr_get_cstr (header),10) == 0) {
00133 debug ("wap.wsp.http", 0, "Caching cookie (%s)", octstr_get_cstr (header));
00134
00135 if ((value = get_header_value (header)) == NULL) {
00136 error (0, "get_cookies: No value in (%s)", octstr_get_cstr(header));
00137 continue;
00138 }
00139
00140
00141 if ((cookie = parse_cookie(value)) != NULL) {
00142
00143
00144 if (have_cookie(sm->cookies, cookie) == 1) {
00145 debug("wap.wsp.http", 0, "parse_cookie: Cookie present");
00146 cookie_destroy(cookie);
00147 continue;
00148 } else {
00149 add_cookie_to_cache(sm, cookie);
00150 debug("wap.wsp.http", 0, "get_cookies: Added (%s)",
00151 octstr_get_cstr(cookie -> name));
00152 }
00153 }
00154 }
00155 }
00156
00157 debug("wap.wsp.http", 0, "get_cookies: End");
00158 return 0;
00159 }
00160
00161
00162 int set_cookies(List *headers, WSPMachine *sm)
00163 {
00164 Cookie *value = NULL;
00165 Octstr *cookie = NULL;
00166 long pos = 0;
00167
00168 if (headers == NULL || sm == NULL) {
00169 error (0, "set_cookies: Null argument(s) - no headers, WSPMachine or both");
00170 return -1;
00171 }
00172
00173
00174 expire_cookies(sm->cookies);
00175
00176
00177 if (gwlist_len(sm->cookies) > 0) {
00178 debug("wap.wsp.http", 0, "set_cookies: Cookies in cache");
00179
00180 for (pos = 0; pos < gwlist_len(sm->cookies); pos++) {
00181 value = gwlist_get(sm->cookies, pos);
00182
00183 cookie = octstr_create("Cookie: ");
00184 if (value->version)
00185 octstr_append(cookie, value->version);
00186 octstr_append(cookie, value->name);
00187 octstr_append_char(cookie, '=');
00188 octstr_append(cookie, value->value);
00189
00190 if (value->path) {
00191 octstr_append_char(cookie, ';');
00192 octstr_append(cookie, value->path);
00193 }
00194 if (value->domain) {
00195 octstr_append_char(cookie, ';');
00196 octstr_append(cookie, value->domain);
00197 }
00198
00199 gwlist_append(headers, cookie);
00200 debug("wap.wsp.http", 0, "set_cookies: Added (%s)", octstr_get_cstr (cookie));
00201 }
00202 } else
00203 debug("wap.wsp.http", 0, "set_cookies: No cookies in cache");
00204
00205 return 0;
00206 }
00207
00208
00209
00210
00211
00212
00213
00214
00215
00216
00217
00218 static Octstr *get_header_value(Octstr *header)
00219 {
00220 Octstr *h = NULL;
00221 long colon = -1;
00222
00223 if (header == NULL) {
00224 error(0, "get_header_value: NULL argument");
00225 return NULL;
00226 }
00227
00228 octstr_strip_blanks(header);
00229 colon = octstr_search_char(header, ':', 0);
00230 if (colon == -1) {
00231 error(0, "get_header_value: Malformed header (%s)", octstr_get_cstr (header));
00232 return NULL;
00233 } else {
00234 h = octstr_copy(header, colon + 1, octstr_len(header));
00235 octstr_strip_blanks(h);
00236 }
00237
00238 debug("wap.wsp.http", 0, "get_header_value: Value (%s)", octstr_get_cstr (h));
00239 return h;
00240 }
00241
00242
00243
00244
00245
00246
00247
00248 static Cookie *parse_cookie(Octstr *cookiestr)
00249 {
00250 char *v = NULL;
00251 char *p = NULL;
00252 int delta = 0;
00253 Cookie *c = NULL;
00254 Octstr **f = NULL;
00255
00256 if (cookiestr == NULL) {
00257 error(0, "parse_cookie: NULL argument");
00258 return NULL;
00259 }
00260
00261 v = gw_strdup(octstr_get_cstr (cookiestr));
00262 p = strtok(v, ";");
00263
00264 c = cookie_create();
00265
00266 while (p != NULL) {
00267 while (isspace((int)*p)) p++;
00268
00269 if (strncasecmp("version", p, 7) == 0)
00270 f = &c -> version;
00271 else if (strncasecmp("path", p, 4) == 0)
00272 f = &c -> path;
00273 else if (strncasecmp("domain", p, 6) == 0)
00274 f = &c -> domain;
00275
00276
00277 else if (strncasecmp("max-age", p, 7) == 0) {
00278 c -> max_age = atol(strrchr (p, '=') + 1);
00279 p = strtok(NULL, ";");
00280 continue;
00281 }
00282 else if (strncasecmp("expires", p, 7) == 0) {
00283 delta = parse_http_date(p);
00284 if (delta != -1)
00285 c->max_age = delta;
00286 p = strtok(NULL, ";");
00287 continue;
00288 }
00289 else if (strncasecmp("comment", p, 7) == 0 ) {
00290 p = strtok(NULL, ";");
00291 continue;
00292 }
00293 else if (strncasecmp("secure", p, 6) == 0 ) {
00294 p = strtok(NULL, ";");
00295 continue;
00296 }
00297 else {
00298 char *equals = NULL;
00299
00300 if ((equals = strrchr(p, '=')) != NULL) {
00301 *equals = '\0';
00302
00303 c->name = octstr_create(p);
00304 c->value = octstr_create(equals + 1);
00305 } else {
00306 error(0, "parse_cookie: Bad name=value cookie component (%s)", p);
00307 cookie_destroy(c);
00308 return NULL;
00309 }
00310 p = strtok(NULL, ";");
00311 continue;
00312 }
00313
00314 if (*f != NULL) {
00315 error(0, "parse_cookie: Duplicate cookie field (%s), discarding", p);
00316 p = strtok(NULL, ";");
00317 continue;
00318 }
00319
00320 *f = octstr_create("$");
00321 octstr_append_cstr(*f, p);
00322 p = strtok(NULL, ";");
00323 }
00324
00325
00326
00327
00328
00329
00330
00331
00332
00333
00334 gw_free (v);
00335 return c;
00336 }
00337
00338
00339
00340
00341
00342
00343
00344 static void add_cookie_to_cache(const WSPMachine *sm, Cookie *value)
00345 {
00346 gw_assert(sm != NULL);
00347 gw_assert(sm->cookies != NULL);
00348 gw_assert(value != NULL);
00349
00350 gwlist_append(sm->cookies, value);
00351
00352 return;
00353 }
00354
00355
00356
00357
00358
00359
00360
00361 static int have_cookie(List *cookies, Cookie *cookie)
00362 {
00363 Cookie *value = NULL;
00364 long pos = 0;
00365
00366 if (cookies == NULL || cookie == NULL) {
00367 error(0, "have_cookie: Null argument(s) - no Cookie list, Cookie or both");
00368 return 0;
00369 }
00370
00371
00372 while (pos < gwlist_len(cookies)) {
00373 value = gwlist_get(cookies, pos);
00374
00375
00376 debug ("wap.wsp.http", 0, "have_cookie: Comparing name (%s:%s), path (%s:%s), domain (%s:%s)",
00377 octstr_get_cstr(cookie->name), octstr_get_cstr(value->name),
00378 octstr_get_cstr(cookie->path), octstr_get_cstr(value->path),
00379 octstr_get_cstr(cookie->domain), octstr_get_cstr(value->domain));
00380
00381
00382 if (
00383 (value->name == NULL ||
00384 ((value->name != NULL && cookie->name != NULL) && octstr_compare(value->name, cookie->name) == 0)) &&
00385 (value->path == NULL ||
00386 ((value->path != NULL && cookie->path != NULL) && octstr_compare(value->path, cookie->path) == 0)) &&
00387 (value->domain == NULL ||
00388 ((value->domain != NULL && cookie->domain != NULL) && octstr_compare(value->domain, cookie->domain) == 0))
00389 ) {
00390
00391
00392 cookie_destroy(value);
00393 gwlist_delete(cookies, pos, 1);
00394
00395
00396 if (cookie->max_age == 0) {
00397 debug("wap.wsp.http", 0, "have_cookie: Discarding expired cookie (%s)",
00398 octstr_get_cstr(cookie->name));
00399 return 1;
00400 }
00401
00402 debug("wap.wsp.http", 0, "have_cookie: Updating cached cookie (%s)",
00403 octstr_get_cstr (cookie->name));
00404 break;
00405 } else {
00406 pos++;
00407 }
00408 }
00409
00410 return 0;
00411 }
00412
00413
00414
00415
00416
00417
00418
00419 static void expire_cookies(List *cookies)
00420 {
00421 Cookie *value = NULL;
00422 time_t now = 0;
00423 long pos = 0;
00424
00425 if (cookies == NULL) {
00426 error(0, "expire_cookies: Null argument(s) - no Cookie list");
00427 return;
00428 }
00429
00430
00431
00432 time(&now);
00433
00434 if (gwlist_len(cookies) > 0) {
00435 debug("wap.wsp.http", 0, "expire_cookies: Cookies in cache");
00436 for (pos = 0; pos < gwlist_len(cookies); pos++) {
00437 value = gwlist_get(cookies, pos);
00438 gw_assert(value != NULL);
00439
00440 if (value->max_age != -1) {
00441 if (value->max_age + value->birth < now) {
00442 debug("wap.wsp.http", 0, "expire_cookies: Expired cookie (%s)",
00443 octstr_get_cstr(value->name));
00444 cookie_destroy(value);
00445 gwlist_delete(cookies, pos, 1);
00446 }
00447 }
00448 }
00449 } else
00450 debug("wap.wsp.http", 0, "expire_cookies: No cookies in cache");
00451
00452 return;
00453 }
00454
00455 static void cookie_destroy(void *p)
00456 {
00457 Cookie *cookie;
00458
00459 if (p == NULL)
00460 return;
00461 cookie = p;
00462
00463 octstr_destroy(cookie->name);
00464 octstr_destroy(cookie->value);
00465 octstr_destroy(cookie->version);
00466 octstr_destroy(cookie->domain);
00467 octstr_destroy(cookie->path);
00468
00469 gw_free(cookie);
00470 debug("wap.wsp.http", 0, "cookie_destroy: Destroyed cookie");
00471 return;
00472 }
00473
00474
00475
00476
00477
00478
00479
00480
00481
00482
00483
00484
00485
00486
00487
00488
00489
00490
00491
00492
00493
00494
00495
00496
00497
00498
00499
00500
00501
00502
00503 static const char* months[] = {
00504 "Jan", "Feb", "Mar", "Apr", "May", "Jun",
00505 "Jul", "Aug", "Sep", "Oct", "Nov", "Dec", NULL
00506 };
00507
00508 static int month_index(const char *s)
00509 {
00510 const char **p = &months[0];
00511 int i = 0;
00512
00513 while (*p != NULL) {
00514 if (strcmp(s, *p) == 0)
00515 return i;
00516 p++, i++;
00517 }
00518
00519 return -1;
00520 }
00521
00522 static int parse_http_date(const char *expires)
00523 {
00524 struct tm ti;
00525 char *p = NULL;
00526 char *date = NULL;
00527 char month[MAX_HTTP_DATE_LENGTH];
00528 time_t rv;
00529 time_t now;
00530
00531 memset(&ti, 0, sizeof(struct tm));
00532
00533
00534 if (!(date = strchr(expires, '='))) {
00535 error(0, "parse_http_date: Bogus expires type=value header (%s)", expires);
00536 return -1;
00537 } else {
00538 date++;
00539 while (isspace((int)*date))
00540 ++date;
00541 }
00542
00543
00544 if (!(p = strchr (date,' '))) {
00545 error(0, "parse_http_date: Bogus date string (%s)", date);
00546 return -1;
00547 } else
00548 while (isspace((int)*p))
00549 ++p;
00550
00551 if (MAX_HTTP_DATE_LENGTH < strlen(p)) {
00552 error(0, "parse_http_date: %s blows length limit (%d)", date, MAX_HTTP_DATE_LENGTH);
00553 return -1;
00554 }
00555
00556 if (isalpha((int)*p)) {
00557
00558 sscanf(p, (strstr(p, "DST") ? "%s %d %d:%d:%d %*s %d" : "%s %d %d:%d:%d %d"),
00559 month, &ti.tm_mday, &ti.tm_hour, &ti.tm_min,
00560 &ti.tm_sec, &ti.tm_year);
00561 ti.tm_year -= 1900;
00562
00563 } else if (p[2] == '-') {
00564
00565 char buf[MAX_HTTP_DATE_LENGTH];
00566
00567 sscanf(p, "%s %d:%d:%d", buf, &ti.tm_hour, &ti.tm_min, &ti.tm_sec);
00568 buf[2] = '\0';
00569 ti.tm_mday = atoi(buf);
00570 buf[6] = '\0';
00571
00572 strcpy(month, &buf[3]);
00573 ti.tm_year = atoi(&buf[7]);
00574
00575
00576
00577 if (ti.tm_year < 70) {
00578 ti.tm_year += 100;
00579 } else if (ti.tm_year > 1900) {
00580 ti.tm_year -= 1900;
00581 }
00582 } else {
00583
00584 sscanf(p,"%d %s %d %d:%d:%d",&ti.tm_mday, month, &ti.tm_year,
00585 &ti.tm_hour, &ti.tm_min, &ti.tm_sec);
00586
00587
00588
00589
00590
00591 ti.tm_year -= 1900;
00592 }
00593
00594 ti.tm_mon = month_index(month);
00595 if (ti.tm_mon == -1) {
00596 error(0, "parse_http_date () failed on bad month value (%s)", month);
00597 return -1;
00598 }
00599
00600 ti.tm_isdst = -1;
00601
00602 rv = gw_mktime(&ti);
00603 if (ti.tm_isdst)
00604 rv -= 3600;
00605
00606 if (rv == -1) {
00607 error(0, "parse_http_date(): mktime() was unable to resolve date/time: %s",
00608 asctime(&ti));
00609 return -1;
00610 }
00611
00612 debug("parse_http_date", 0, "Parsed date (%s) as: %s", date, asctime(&ti));
00613
00614
00615
00616
00617
00618 now = time(NULL);
00619
00620 if (rv - now < 0) {
00621
00622 error(0, "parse_http_date () Expiry time (%s) (delta=%ld) is in the past !",
00623 asctime(&ti), rv-now);
00624 return 0;
00625 }
00626
00627 return rv - now;
00628 }
00629
See file LICENSE for details about the license agreement for using,
modifying, copying or deriving work from this software.