5 RECEIVING COOKIE INFORMATION
6 ============================
8 struct CookieInfo *cookie_init(char *file);
10 Inits a cookie struct to store data in a local file. This is always
11 called before any cookies are set.
13 int cookies_set(struct CookieInfo *cookie, char *cookie_line);
15 The 'cookie_line' parameter is a full "Set-cookie:" line as
16 received from a server.
18 The function need to replace previously stored lines that this new
21 It may remove lines that are expired.
23 It should return an indication of success/error.
26 SENDING COOKIE INFORMATION
27 ==========================
29 struct Cookies *cookie_getlist(struct CookieInfo *cookie,
30 char *host, char *path, bool secure);
32 For a given host and path, return a linked list of cookies that
33 the client should send to the server if used now. The secure
34 boolean informs the cookie if a secure connection is achieved or
37 It shall only return cookies that haven't expired.
40 Example set of cookies:
42 Set-cookie: PRODUCTINFO=webxpress; domain=.fidelity.com; path=/; secure
43 Set-cookie: PERSONALIZE=none;expires=Monday, 13-Jun-1988 03:04:55 GMT;
44 domain=.fidelity.com; path=/ftgw; secure
45 Set-cookie: FidHist=none;expires=Monday, 13-Jun-1988 03:04:55 GMT;
46 domain=.fidelity.com; path=/; secure
47 Set-cookie: FidOrder=none;expires=Monday, 13-Jun-1988 03:04:55 GMT;
48 domain=.fidelity.com; path=/; secure
49 Set-cookie: DisPend=none;expires=Monday, 13-Jun-1988 03:04:55 GMT;
50 domain=.fidelity.com; path=/; secure
51 Set-cookie: FidDis=none;expires=Monday, 13-Jun-1988 03:04:55 GMT;
52 domain=.fidelity.com; path=/; secure
54 Session_Key@6791a9e0-901a-11d0-a1c8-9b012c88aa77=none;expires=Monday,
55 13-Jun-1988 03:04:55 GMT; domain=.fidelity.com; path=/; secure
66 /****************************************************************************
70 * Add a single cookie line to the cookie keeping object.
72 ***************************************************************************/
74 struct Cookie
*cookie_add(struct CookieInfo
*c
,
75 bool httpheader
, /* TRUE if HTTP header-style line */
76 char *lineptr
) /* first non-space of the line */
79 char what
[MAX_COOKIE_LINE
];
84 time_t now
= time(NULL
);
85 bool replace_old
= FALSE
;
87 /* First, alloc and init a new struct for it */
88 co
= (struct Cookie
*)malloc(sizeof(struct Cookie
));
90 return NULL
; /* bail out if we're this low on memory */
92 /* clear the whole struct first */
93 memset(co
, 0, sizeof(struct Cookie
));
96 /* This line was read off a HTTP-header */
98 semiptr
=strchr(lineptr
, ';'); /* first, find a semicolon */
101 *semiptr
='\0'; /* zero terminate for a while */
102 /* we have a <what>=<this> pair or a 'secure' word here */
103 if(strchr(ptr
, '=')) {
104 if(2 == sscanf(ptr
, "%" MAX_NAME_TXT
"[^=]=%"
105 MAX_COOKIE_LINE_TXT
"[^\r\n]",
107 /* this is a legal <what>=<this> pair */
108 if(strequal("path", name
)) {
109 co
->path
=strdup(what
);
111 else if(strequal("domain", name
)) {
112 co
->domain
=strdup(what
);
114 else if(strequal("expires", name
)) {
115 co
->expirestr
=strdup(what
);
116 co
->expires
= get_date(what
, &now
);
119 co
->name
= strdup(name
);
120 co
->value
= strdup(what
);
123 ;/* this is the second (or more) name we don't know
127 /* this is an "illegal" <what>=<this> pair */
131 if(sscanf(ptr
, "%" MAX_COOKIE_LINE_TXT
"[^\r\n]",
133 if(strequal("secure", what
))
136 ; /* unsupported keyword without assign! */
139 *semiptr
=';'; /* put the semicolon back */
141 while(ptr
&& *ptr
&& isspace((int)*ptr
))
143 semiptr
=strchr(ptr
, ';'); /* now, find the next semicolon */
147 /* This line is NOT a HTTP header style line, we do offer support for
148 reading the odd netscape cookies-file format here */
152 if(lineptr
[0]=='#') {
153 /* don't even try the comments */
157 /* strip off the possible end-of-line characters */
158 if(ptr
=strchr(lineptr
, '\r'))
159 *ptr
=0; /* clear it */
160 if(ptr
=strchr(lineptr
, '\n'))
161 *ptr
=0; /* clear it */
163 firstptr
=strtok(lineptr
, "\t"); /* first tokenize it on the TAB */
165 /* Here's a quick check to eliminate normal HTTP-headers from this */
166 if(!firstptr
|| strchr(firstptr
, ':')) {
171 /* Now loop through the fields and init the struct we already have
173 for(ptr
=firstptr
, fields
=0; ptr
; ptr
=strtok(NULL
, "\t"), fields
++) {
176 co
->domain
= strdup(ptr
);
179 /* what _is_ this field for? */
182 co
->path
= strdup(ptr
);
185 co
->secure
= strequal(ptr
, "TRUE");
188 co
->expires
= atoi(ptr
);
191 co
->name
= strdup(ptr
);
194 co
->value
= strdup(ptr
);
200 /* we did not find the sufficient number of fields to recognize this
201 as a valid line, abort and go home */
218 /* now, we have parsed the incoming line, we must now check if this
219 superceeds an already existing cookie, which it may if the previous have
220 the same domain and path as this */
225 if(strequal(clist
->name
, co
->name
)) {
226 /* the names are identical */
228 if(clist
->domain
&& co
->domain
) {
229 if(strequal(clist
->domain
, co
->domain
))
232 else if(!clist
->domain
&& !co
->domain
)
236 /* the domains were identical */
238 if(clist
->path
&& co
->path
) {
239 if(strequal(clist
->path
, co
->path
)) {
245 else if(!clist
->path
&& !co
->path
)
253 co
->next
= clist
->next
; /* get the next-pointer first */
255 /* then free all the old pointers */
265 free(clist
->expirestr
);
267 *clist
= *co
; /* then store all the new data */
276 /* first, point to our "next" */
277 co
->next
= c
->cookies
;
278 /* then make ourselves first in the list */
284 /*****************************************************************************
288 * Inits a cookie struct to read data from a local file. This is always
289 * called before any cookies are set. File may be NULL.
291 ****************************************************************************/
292 struct CookieInfo
*cookie_init(char *file
)
294 char line
[MAX_COOKIE_LINE
];
295 struct CookieInfo
*c
;
298 c
= (struct CookieInfo
*)malloc(sizeof(struct CookieInfo
));
300 return NULL
; /* failed to get memory */
301 memset(c
, 0, sizeof(struct CookieInfo
));
302 c
->filename
= strdup(file
?file
:"none"); /* copy the name just in case */
304 fp
= file
?fopen(file
, "r"):NULL
;
306 while(fgets(line
, MAX_COOKIE_LINE
, fp
)) {
307 if(strnequal("Set-Cookie:", line
, 11)) {
308 /* This is a cookie line, get it! */
309 char *lineptr
=&line
[11];
310 while(*lineptr
&& isspace((int)*lineptr
))
313 cookie_add(c
, TRUE
, lineptr
);
316 /* This might be a netscape cookie-file line, get it! */
318 while(*lineptr
&& isspace((int)*lineptr
))
321 cookie_add(c
, FALSE
, lineptr
);
330 /*****************************************************************************
334 * For a given host and path, return a linked list of cookies that the
335 * client should send to the server if used now. The secure boolean informs
336 * the cookie if a secure connection is achieved or not.
338 * It shall only return cookies that haven't expired.
340 ****************************************************************************/
342 struct Cookie
*cookie_getlist(struct CookieInfo
*c
,
343 char *host
, char *path
, bool secure
)
345 struct Cookie
*newco
;
347 time_t now
= time(NULL
);
348 int hostlen
=strlen(host
);
351 struct Cookie
*mainco
=NULL
;
353 if(!c
|| !c
->cookies
)
354 return NULL
; /* no cookie struct or no cookies in the struct */
359 /* only process this cookie if it is not expired or had no expire
360 date AND that if the cookie requires we're secure we must only
361 continue if we are! */
362 if( (co
->expires
<=0 || (co
->expires
> now
)) &&
363 (co
->secure
?secure
:TRUE
) ) {
365 /* now check if the domain is correct */
366 domlen
=co
->domain
?strlen(co
->domain
):0;
369 strequal(host
+(hostlen
-domlen
), co
->domain
)) ) {
370 /* the right part of the host matches the domain stuff in the
373 /* now check the left part of the path with the cookies path
376 strnequal(path
, co
->path
, strlen(co
->path
))) {
378 /* and now, we know this is a match and we should create an
379 entry for the return-linked-list */
381 newco
= (struct Cookie
*)malloc(sizeof(struct Cookie
));
383 /* first, copy the whole source cookie: */
384 memcpy(newco
, co
, sizeof(struct Cookie
));
386 /* then modify our next */
387 newco
->next
= mainco
;
389 /* point the main to us */
398 return mainco
; /* return the new list */
402 /*****************************************************************************
406 * Free a list previously returned by cookie_getlist();
408 ****************************************************************************/
410 void cookie_freelist(struct Cookie
*co
)
416 free(co
); /* we only free the struct since the "members" are all
423 /*****************************************************************************
427 * Free a "cookie object" previous created with cookie_init().
429 ****************************************************************************/
430 void cookie_cleanup(struct CookieInfo
*c
)