Annotation of libwww/Library/src/HTCookie.c, revision 2.1
2.1 ! frystyk 1: /*
! 2: ** SIMPLE HTTP COOKIE FILTER HANDLER
! 3: **
! 4: ** (c) COPYRIGHT MIT 1999.
! 5: ** Please first read the full copyright statement in the file COPYRIGH.
! 6: ** @(#) $Id: HTCache.c,v 2.66 1999/03/14 02:01:08 frystyk Exp $
! 7: **
! 8: ** Written based on Jim Raven's code sent to the <www-lib@w3.org> list
! 9: **
! 10: ** History:
! 11: ** JR: Sent code to the list
! 12: ** HFN: Made a libwww module
! 13: **
! 14: */
! 15:
! 16: /* Library include files */
! 17: #include "wwwsys.h"
! 18: #include "WWWUtil.h"
! 19: #include "WWWCore.h"
! 20: #include "WWWHTTP.h"
! 21: #include "WWWMIME.h"
! 22: #include "HTCookie.h" /* Implemented here */
! 23:
! 24: /* Interface to persistent cookie jar */
! 25: PRIVATE HTCookieSetCallback * SetCookie = NULL;
! 26: PRIVATE void * SetCookieContext = NULL;
! 27:
! 28: PRIVATE HTCookieFindCallback * FindCookie = NULL;
! 29: PRIVATE void * FindCookieContext = NULL;
! 30:
! 31: /* Are cookies enabled */
! 32: PRIVATE BOOL baking_cookies = NO;
! 33:
! 34: /* Our cookies */
! 35: struct _HTCookie {
! 36: char * name;
! 37: char * value;
! 38: char * domain;
! 39: char * path;
! 40: time_t expiration;
! 41: BOOL secure;
! 42: };
! 43:
! 44: /* Hold all cookies found for a single request */
! 45: typedef struct _HTCookieHolder {
! 46: HTRequest * request;
! 47: HTList * cookies;
! 48: } HTCookieHolder;
! 49:
! 50: /* List of current cookie holders */
! 51: PRIVATE HTList * cookie_holder = NULL;
! 52:
! 53: /* What should we do with cookies? */
! 54: PRIVATE HTCookieMode CookieMode = HT_COOKIE_PROMPT;
! 55:
! 56: /* ------------------------------------------------------------------------- */
! 57:
! 58: PRIVATE HTCookie * HTCookie_new (void)
! 59: {
! 60: HTCookie * me = NULL;
! 61: if ((me = (HTCookie *) HT_CALLOC(1, sizeof(HTCookie))) == NULL)
! 62: HT_OUTOFMEM("HTCookie_new");
! 63: return me;
! 64: }
! 65:
! 66: PRIVATE BOOL HTCookie_delete (HTCookie * me)
! 67: {
! 68: if (me) {
! 69: HT_FREE(me->name);
! 70: HT_FREE(me->value);
! 71: HT_FREE(me->domain);
! 72: HT_FREE(me->path);
! 73: HT_FREE(me);
! 74: return YES;
! 75: }
! 76: return NO;
! 77: }
! 78:
! 79: PUBLIC BOOL HTCookie_setName (HTCookie * me, const char * name)
! 80: {
! 81: if (me && name) {
! 82: me->name = StrAllocCopy(me->name, name);
! 83: return YES;
! 84: }
! 85: return NO;
! 86: }
! 87:
! 88: PUBLIC char * HTCookie_name (HTCookie * me)
! 89: {
! 90: return me ? me->name : NULL;
! 91: }
! 92:
! 93: PUBLIC BOOL HTCookie_setValue (HTCookie * me, const char * value)
! 94: {
! 95: if (me && value) {
! 96: me->value = StrAllocCopy(me->value, value);
! 97: return YES;
! 98: }
! 99: return NO;
! 100: }
! 101:
! 102: PUBLIC char * HTCookie_value (HTCookie * me)
! 103: {
! 104: return me ? me->value : NULL;
! 105: }
! 106:
! 107: PUBLIC BOOL HTCookie_setDomain (HTCookie * me, const char * domain)
! 108: {
! 109: if (me && domain) {
! 110: me->domain = StrAllocCopy(me->domain, domain);
! 111: return YES;
! 112: }
! 113: return NO;
! 114: }
! 115:
! 116: PUBLIC char * HTCookie_domain (HTCookie * me)
! 117: {
! 118: return me ? me->domain : NULL;
! 119: }
! 120:
! 121: PUBLIC BOOL HTCookie_setPath (HTCookie * me, const char * path)
! 122: {
! 123: if (me && path) {
! 124: me->path = StrAllocCopy(me->path, path);
! 125: return YES;
! 126: }
! 127: return NO;
! 128: }
! 129:
! 130: PUBLIC char * HTCookie_path (HTCookie * me)
! 131: {
! 132: return me ? me->path : NULL;
! 133: }
! 134:
! 135: PUBLIC time_t HTCookie_setExpiration (HTCookie * me, time_t expiration)
! 136: {
! 137: if (me) {
! 138: me->expiration = expiration;
! 139: return YES;
! 140: }
! 141: return NO;
! 142: }
! 143:
! 144: PUBLIC time_t HTCookie_expiration (HTCookie * me)
! 145: {
! 146: return me ? me->expiration : -1;
! 147: }
! 148:
! 149: PUBLIC time_t HTCookie_setSecure (HTCookie * me, BOOL secure)
! 150: {
! 151: if (me) {
! 152: me->secure = secure;
! 153: return YES;
! 154: }
! 155: return NO;
! 156: }
! 157:
! 158: PUBLIC BOOL HTCookie_isSecure (HTCookie * me)
! 159: {
! 160: return me ? me->secure : NO;
! 161: }
! 162:
! 163: /* ------------------------------------------------------------------------- */
! 164:
! 165: PRIVATE BOOL HTCookieHolder_addCookie (HTRequest * request, HTCookie * cookie)
! 166: {
! 167: if (request && cookie) {
! 168: HTList * cur = cookie_holder;
! 169: HTCookieHolder * pres = NULL;
! 170:
! 171: /* Make sure that we have a cookie holder list */
! 172: if (!cookie_holder) cookie_holder = HTList_new();
! 173:
! 174: /* See if we already have a cookie holder for this request */
! 175: while ((pres = (HTCookieHolder *) HTList_nextObject(cur))) {
! 176: if (pres->request == request) break;
! 177: }
! 178:
! 179: /* If found then use existing cookie holder, otherwise create new one */
! 180: if (!pres) {
! 181: if ((pres = (HTCookieHolder *) HT_CALLOC(1, sizeof(HTCookieHolder))) == NULL)
! 182: HT_OUTOFMEM("HTCookieHolder_newCookie");
! 183: pres->request = request;
! 184: pres->cookies = HTList_new();
! 185:
! 186: /* Add to cookie holder list */
! 187: HTList_addObject(cookie_holder, pres);
! 188: }
! 189:
! 190: /* Now add the cookie */
! 191: HTList_addObject(pres->cookies, cookie);
! 192:
! 193: return YES;
! 194: }
! 195: return NO;
! 196: }
! 197:
! 198: PRIVATE HTCookieHolder * HTCookieHolder_find (HTRequest * request)
! 199: {
! 200: if (request) {
! 201: HTList * cur = cookie_holder;
! 202: HTCookieHolder * pres = NULL;
! 203: while ((pres = (HTCookieHolder *) HTList_nextObject(cur))) {
! 204: if (pres->request == request) return pres;
! 205: }
! 206: }
! 207: return NULL;
! 208: }
! 209:
! 210: PRIVATE BOOL HTCookieHolder_delete (HTCookieHolder * me)
! 211: {
! 212: if (me) {
! 213: if (me->cookies) {
! 214: HTList * cookies = me->cookies;
! 215: HTCookie * cookie;
! 216: while ((cookie = (HTCookie *) HTList_nextObject(cookies)))
! 217: HTCookie_delete(cookie);
! 218: }
! 219: HTList_removeObject(cookie_holder, me);
! 220: HT_FREE(me);
! 221: return YES;
! 222: }
! 223: return NO;
! 224: }
! 225:
! 226: PRIVATE BOOL HTCookieHolder_deleteAll (void)
! 227: {
! 228: if (cookie_holder) {
! 229: HTList * cur = cookie_holder;
! 230: HTCookieHolder * pres = NULL;
! 231: while ((pres = (HTCookieHolder *) HTList_nextObject(cur))) {
! 232: HTCookieHolder_delete(pres);
! 233: }
! 234: HTList_delete(cookie_holder);
! 235: cookie_holder = NULL;
! 236: return YES;
! 237: }
! 238: return NO;
! 239: }
! 240:
! 241: /* ------------------------------------------------------------------------- */
! 242:
! 243: /*
! 244: ** MIME header parser for the Set-Cookie header field. We parse the cookies
! 245: ** and create HTCookie objects and store them in the cookie holder so that
! 246: ** the cookie after filter can deal with them accordingly.
! 247: */
! 248: PRIVATE int HTCookie_parseSetCookie (HTRequest * request, HTResponse * response,
! 249: char * token, char * value)
! 250:
! 251: {
! 252: char * cookie_name = HTNextField(&value);
! 253: char * cookie_value = HTNextField(&value);
! 254: if (cookie_name && *cookie_name && cookie_value) {
! 255: HTCookie * cookie = HTCookie_new();
! 256: char * param_pair;
! 257:
! 258: HTCookie_setName(cookie, cookie_name);
! 259: HTCookie_setValue(cookie, cookie_value);
! 260:
! 261: /* Add the cookie to our holder */
! 262: HTCookieHolder_addCookie(request, cookie);
! 263:
! 264: /* Parse cookie parameters */
! 265: while ((param_pair = HTNextParam(&value))) {
! 266: char * tok = HTNextField(¶m_pair);
! 267: char * val = param_pair;
! 268: if (tok) {
! 269: if (!strcasecomp(tok, "expires") && val && *val) {
! 270: HTTRACE(STREAM_TRACE, "Cookie...... Expires `%s\'\n" _ val);
! 271: HTCookie_setExpiration(cookie, HTParseTime(val, NULL, YES));
! 272: } else if (!strcasecomp(tok, "domain") && val && *val) {
! 273: HTTRACE(STREAM_TRACE, "Cookie...... Domain `%s\'\n" _ val);
! 274: HTCookie_setDomain(cookie, val);
! 275: } else if (!strcasecomp(tok, "path") && val && *val) {
! 276: HTTRACE(STREAM_TRACE, "Cookie...... Path `%s\'\n" _ val);
! 277: HTCookie_setPath(cookie, val);
! 278: } else if (!strcasecomp(tok, "secure")) {
! 279: HTTRACE(STREAM_TRACE, "Cookie...... Secure `%s\'\n" _ val);
! 280: HTCookie_setSecure(cookie, YES);
! 281: } else
! 282: HTTRACE(STREAM_TRACE, "Cookie...... Unknown `%s\' with value `%s\'\n" _
! 283: tok _ val ? val : "<null>");
! 284: }
! 285: }
! 286: }
! 287: return HT_OK;
! 288: }
! 289:
! 290: /*
! 291: ** Check whether the application provides us with a cookie or more.
! 292: */
! 293: PRIVATE int HTCookie_beforeFilter (HTRequest * request, void * param, int mode)
! 294: {
! 295: if (CookieMode!=HT_COOKIE_TOSS && FindCookie) {
! 296: HTAssocList * cookies = (*FindCookie)(request, FindCookieContext);
! 297: if (cookies) {
! 298: HTChunk * cookie_header = HTChunk_new(64);
! 299: HTAssoc * pres;
! 300: BOOL first=YES;
! 301: while ((pres = (HTAssoc *) HTAssocList_nextObject(cookies))) {
! 302: if (!first) HTChunk_putc(cookie_header, ',');
! 303: HTChunk_puts(cookie_header, HTAssoc_name(pres));
! 304: HTChunk_putc(cookie_header, '=');
! 305: HTChunk_puts(cookie_header, HTAssoc_value(pres));
! 306: first = NO;
! 307: }
! 308: HTRequest_addExtraHeader(request, "Cookie", HTChunk_data(cookie_header));
! 309: HTChunk_delete(cookie_header);
! 310:
! 311: /* Also delete the association list */
! 312: HTAssocList_delete(cookies);
! 313: }
! 314: }
! 315: return HT_OK;
! 316: }
! 317:
! 318: /*
! 319: ** Check the response to see if we got a cookie or more.
! 320: ** If so then figure out what to do with it (prompt user, store, etc.)
! 321: */
! 322: PRIVATE int HTCookie_afterFilter (HTRequest * request, HTResponse * response,
! 323: void * param, int status)
! 324: {
! 325: if (CookieMode!=HT_COOKIE_TOSS && SetCookie) {
! 326: HTCookieHolder * holder = HTCookieHolder_find(request);
! 327: if (holder) {
! 328: HTList * cookies = holder->cookies;
! 329: HTCookie * pres;
! 330: while ((pres = (HTCookie *) HTAssocList_nextObject(cookies))) {
! 331:
! 332: /* check to see if we should prompt user here */
! 333:
! 334: (*SetCookie)(request, pres, SetCookieContext);
! 335: }
! 336:
! 337: /* Delete cookie holder */
! 338: HTCookieHolder_delete(holder);
! 339: }
! 340: }
! 341: return HT_OK;
! 342: }
! 343:
! 344: /* ------------------------------------------------------------------------- */
! 345:
! 346: /*
! 347: ** Start and stop the cookie engine
! 348: */
! 349: PUBLIC BOOL HTCookie_init (void)
! 350: {
! 351: if (!baking_cookies) {
! 352:
! 353: /* Register the SetCookie header parser */
! 354: HTHeader_addParser("Set-Cookie", NO, HTCookie_parseSetCookie);
! 355:
! 356: /* Register the cookie before and after filters */
! 357: HTNet_addBefore(HTCookie_beforeFilter, "http://*", NULL, HT_FILTER_MIDDLE);
! 358: HTNet_addAfter(HTCookie_afterFilter, "http://*", NULL, HT_ALL, HT_FILTER_MIDDLE);
! 359:
! 360: baking_cookies = YES;
! 361: return YES;
! 362: }
! 363: return NO;
! 364: }
! 365:
! 366: PUBLIC BOOL HTCookie_terminate (void)
! 367: {
! 368: /* Unregister Set-Cookie header parser */
! 369: HTHeader_deleteParser("Set-Cookie");
! 370:
! 371: /* Unregister the cookie before and after filters */
! 372: HTNet_deleteBefore(HTCookie_beforeFilter);
! 373: HTNet_deleteAfter(HTCookie_afterFilter);
! 374:
! 375: /* Delete all pending cookies */
! 376: HTCookieHolder_deleteAll();
! 377: return YES;
! 378: }
! 379:
! 380: PUBLIC BOOL HTCookie_setCookieMode (HTCookieMode mode)
! 381: {
! 382: CookieMode = mode;
! 383: return YES;
! 384: }
! 385:
! 386: /*
! 387: ** Callbacks can be used by the application to set and retrieve cookies
! 388: ** from a persistent cookie jar as libwww doesn't provide a persistent
! 389: ** storage for this kind of thing and they probably should be secured
! 390: ** anyway.
! 391: */
! 392: PUBLIC BOOL HTCookie_setCallbacks (HTCookieSetCallback * setCookie,
! 393: void * setCookieContext,
! 394: HTCookieFindCallback * findCookie,
! 395: void * findCookieContext)
! 396: {
! 397: if (setCookie && findCookie) {
! 398: HTTRACE(APP_TRACE, "Cookie...... Registering cookie callbacks\n");
! 399: SetCookie = setCookie;
! 400: SetCookieContext = setCookieContext;
! 401:
! 402: FindCookie = findCookie;
! 403: FindCookieContext = findCookieContext;
! 404: return YES;
! 405: }
! 406: return NO;
! 407: }
! 408:
! 409: PUBLIC BOOL HTCookie_deleteCallbacks (void)
! 410: {
! 411: HTTRACE(APP_TRACE, "Cookie...... Unregistering cookie callbacks\n");
! 412: SetCookie = NULL;
! 413: SetCookieContext = NULL;
! 414: FindCookie = NULL;
! 415: FindCookieContext = NULL;
! 416: return YES;
! 417: }
Webmaster