Instantly share code, notes, and snippets.
Created
March 28, 2010 15:45
-
Save claesjac/346813 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
diff --git a/include/curl/curl.h b/include/curl/curl.h | |
index e635968..e413958 100644 | |
--- a/include/curl/curl.h | |
+++ b/include/curl/curl.h | |
@@ -172,6 +172,21 @@ typedef int (*curl_progress_callback)(void *clientp, | |
double ultotal, | |
double ulnow); | |
+struct curl_cookie { | |
+ char *name; /* <this> = value */ | |
+ char *value; /* name = <this> */ | |
+ char *path; /* path = <this> */ | |
+ char *domain; /* domain = <this> */ | |
+ curl_off_t expires; /* expires = <this> */ | |
+ | |
+ /* RFC 2109 keywords. Version=1 means 2109-compliant cookie sending */ | |
+ char *version; /* Version = <value> */ | |
+ char *maxage; /* Max-Age = <value> */ | |
+ | |
+ int secure; /* whether the 'secure' keyword was used */ | |
+ int httponly; /* true if the httponly directive is present */ | |
+}; | |
+ | |
#ifndef CURL_MAX_WRITE_SIZE | |
/* Tests have proven that 20K is a very bad buffer size for uploads on | |
Windows, while 16K for some odd reason performed a lot better. | |
@@ -1316,6 +1331,10 @@ typedef enum { | |
/* Let the application define a custom write method for RTP data */ | |
CINIT(INTERLEAVEFUNCTION, FUNCTIONPOINT, 196), | |
+ /* feed cookies into cookie engine but as curl_cookie structs instead of | |
+ strings */ | |
+ CINIT(COOKIELIST_STRUCT, OBJECTPOINT, 197), | |
+ | |
CURLOPT_LASTENTRY /* the last unused */ | |
} CURLoption; | |
@@ -1764,9 +1783,10 @@ typedef enum { | |
CURLINFO_RTSP_CLIENT_CSEQ = CURLINFO_LONG + 37, | |
CURLINFO_RTSP_SERVER_CSEQ = CURLINFO_LONG + 38, | |
CURLINFO_RTSP_CSEQ_RECV = CURLINFO_LONG + 39, | |
+ CURLINFO_COOKIELIST_STRUCT = CURLINFO_SLIST + 40, | |
/* Fill in new entries below here! */ | |
- CURLINFO_LASTONE = 39 | |
+ CURLINFO_LASTONE = 40 | |
} CURLINFO; | |
/* CURLINFO_RESPONSE_CODE is the new name for the option previously known as | |
diff --git a/lib/cookie.c b/lib/cookie.c | |
index 21617ad..8ae11d0 100644 | |
--- a/lib/cookie.c | |
+++ b/lib/cookie.c | |
@@ -133,6 +133,108 @@ static bool tailmatch(const char *little, const char *bigone) | |
return (bool)Curl_raw_equal(little, bigone+biglen-littlelen); | |
} | |
+static bool replace_old_cookie(struct SessionHandle *data, struct Cookie** co_ptr, struct CookieInfo *c) | |
+{ | |
+ struct Cookie *co = *co_ptr; | |
+ struct Cookie *clist = c->cookies; | |
+ struct Cookie *lastc=NULL; | |
+ bool replace_old = FALSE; | |
+ | |
+ while(clist) { | |
+ if(Curl_raw_equal(clist->name, co->name)) { | |
+ /* the names are identical */ | |
+ | |
+ if(clist->domain && *co->domain) { | |
+ if(Curl_raw_equal(clist->domain, co->domain)) | |
+ /* The domains are identical */ | |
+ replace_old=TRUE; | |
+ } | |
+ else if(!clist->domain && !co->domain) | |
+ replace_old = TRUE; | |
+ | |
+ if(replace_old) { | |
+ /* the domains were identical */ | |
+ if(clist->path && co->path) { | |
+ if(Curl_raw_equal(clist->path, co->path)) { | |
+ replace_old = TRUE; | |
+ } | |
+ else | |
+ replace_old = FALSE; | |
+ } | |
+ else if(!clist->path && !co->path) | |
+ replace_old = TRUE; | |
+ else | |
+ replace_old = FALSE; | |
+ } | |
+ | |
+ if(replace_old && !co->livecookie && clist->livecookie) { | |
+ /* Both cookies matched fine, except that the already present | |
+ cookie is "live", which means it was set from a header, while | |
+ the new one isn't "live" and thus only read from a file. We let | |
+ live cookies stay alive */ | |
+ | |
+ /* Free the newcomer and get out of here! */ | |
+ freecookie(co); | |
+ *co_ptr = NULL; | |
+ return FALSE; | |
+ } | |
+ | |
+ if(replace_old) { | |
+ co->next = clist->next; /* get the next-pointer first */ | |
+ | |
+ /* then free all the old pointers */ | |
+ free(clist->name); | |
+ if(clist->value) | |
+ free(clist->value); | |
+ if(clist->domain) | |
+ free(clist->domain); | |
+ if(clist->path) | |
+ free(clist->path); | |
+ if(clist->expirestr) | |
+ free(clist->expirestr); | |
+ | |
+ if(clist->version) | |
+ free(clist->version); | |
+ if(clist->maxage) | |
+ free(clist->maxage); | |
+ | |
+ *clist = *co; /* then store all the new data */ | |
+ | |
+ free(co); /* free the newly alloced memory */ | |
+ *co_ptr = clist; /* point to the previous struct instead */ | |
+ | |
+ /* We have replaced a cookie, now skip the rest of the list but | |
+ make sure the 'lastc' pointer is properly set */ | |
+ do { | |
+ lastc = clist; | |
+ clist = clist->next; | |
+ } while(clist); | |
+ break; | |
+ } | |
+ } | |
+ | |
+ lastc = clist; | |
+ clist = clist->next; | |
+ } | |
+ | |
+ if(!replace_old) { | |
+ /* then make the last item point on this new one */ | |
+ if(lastc) | |
+ lastc->next = co; | |
+ else | |
+ c->cookies = co; | |
+ } | |
+ | |
+ if(c->running) | |
+ /* Only show this when NOT reading the cookies from a file */ | |
+ infof(data, "%s cookie %s=\"%s\" for domain %s, path %s, " | |
+ "expire %" FORMAT_OFF_T "\n", | |
+ replace_old?"Replaced":"Added", co->name, co->value, | |
+ co->domain, co->path, co->expires); | |
+ | |
+ return replace_old; | |
+} | |
+ | |
/* | |
* Load cookies from all given cookie files (CURLOPT_COOKIEFILE). | |
*/ | |
@@ -190,10 +292,8 @@ Curl_cookie_add(struct SessionHandle *data, | |
used to get default path for the cookie | |
unless set */ | |
{ | |
- struct Cookie *clist; | |
char name[MAX_NAME]; | |
struct Cookie *co; | |
- struct Cookie *lastc=NULL; | |
time_t now = time(NULL); | |
bool replace_old = FALSE; | |
bool badcookie = FALSE; /* cookies are good by default. mmmmm yummy */ | |
@@ -598,103 +698,70 @@ Curl_cookie_add(struct SessionHandle *data, | |
/* now, we have parsed the incoming line, we must now check if this | |
superceeds an already existing cookie, which it may if the previous have | |
the same domain and path as this */ | |
+ replace_old = replace_old_cookie(data, &co, c); | |
+ | |
+ /* if this is a live cookie then replaces_old_cookie will free co and we | |
+ must prematurely abort */ | |
+ if (co == NULL) | |
+ return; | |
+ | |
+ c->numcookies++; /* one more cookie in the jar */ | |
+ return co; | |
+} | |
- clist = c->cookies; | |
- replace_old = FALSE; | |
- while(clist) { | |
- if(Curl_raw_equal(clist->name, co->name)) { | |
- /* the names are identical */ | |
- | |
- if(clist->domain && co->domain) { | |
- if(Curl_raw_equal(clist->domain, co->domain)) | |
- /* The domains are identical */ | |
- replace_old=TRUE; | |
- } | |
- else if(!clist->domain && !co->domain) | |
- replace_old = TRUE; | |
- | |
- if(replace_old) { | |
- /* the domains were identical */ | |
- | |
- if(clist->path && co->path) { | |
- if(Curl_raw_equal(clist->path, co->path)) { | |
- replace_old = TRUE; | |
- } | |
- else | |
- replace_old = FALSE; | |
- } | |
- else if(!clist->path && !co->path) | |
- replace_old = TRUE; | |
- else | |
- replace_old = FALSE; | |
- | |
- } | |
- | |
- if(replace_old && !co->livecookie && clist->livecookie) { | |
- /* Both cookies matched fine, except that the already present | |
- cookie is "live", which means it was set from a header, while | |
- the new one isn't "live" and thus only read from a file. We let | |
- live cookies stay alive */ | |
- | |
- /* Free the newcomer and get out of here! */ | |
- freecookie(co); | |
- return NULL; | |
- } | |
- | |
- if(replace_old) { | |
- co->next = clist->next; /* get the next-pointer first */ | |
- | |
- /* then free all the old pointers */ | |
- free(clist->name); | |
- if(clist->value) | |
- free(clist->value); | |
- if(clist->domain) | |
- free(clist->domain); | |
- if(clist->path) | |
- free(clist->path); | |
- if(clist->expirestr) | |
- free(clist->expirestr); | |
- | |
- if(clist->version) | |
- free(clist->version); | |
- if(clist->maxage) | |
- free(clist->maxage); | |
- | |
- *clist = *co; /* then store all the new data */ | |
- | |
- free(co); /* free the newly alloced memory */ | |
- co = clist; /* point to the previous struct instead */ | |
+/**************************************************************************** | |
+ * | |
+ * Curl_cookie_add_slist() | |
+ * | |
+ * Add all cookies from a list of curl_cookie structs | |
+ * | |
+ ***************************************************************************/ | |
+void | |
+Curl_cookie_add_slist(struct SessionHandle *data, | |
+ /* The 'data' pointer here may be NULL at times, and thus | |
+ must only be used very carefully for things that can deal | |
+ with data being NULL. Such as infof() and similar */ | |
+ struct CookieInfo *c, | |
+ struct curl_slist *list | |
+) | |
+{ | |
+ struct curl_slist *entry = list; | |
+ struct curl_cookie *cc; | |
+ struct Cookie *co; | |
+ bool replace_old = FALSE; | |
- /* We have replaced a cookie, now skip the rest of the list but | |
- make sure the 'lastc' pointer is properly set */ | |
- do { | |
- lastc = clist; | |
- clist = clist->next; | |
- } while(clist); | |
- break; | |
- } | |
+ if(!entry) | |
+ return; | |
+ | |
+ while(entry) { | |
+ cc = (struct curl_cookie *) entry->data; | |
+ co = calloc(1, sizeof(struct Cookie)); | |
+ if (co == NULL) | |
+ return; /* Can't allocate memory for the cookie so we're going to fail all */ | |
+ | |
+ co->name = strdup(cc->name); | |
+ co->value = strdup(cc->value); | |
+ co->path = strdup(cc->path); | |
+ co->domain = strdup(cc->domain); | |
+ co->expires = cc->expires; | |
+ co->version = strdup(cc->version); | |
+ co->maxage = strdup(cc->maxage); | |
+ | |
+ co->secure = cc->secure; | |
+ co->httponly = cc->httponly; | |
+ | |
+ co->livecookie = c->running; | |
+ | |
+ /* we must now check if this superceeds an already existing cookie, | |
+ which it may if the previous have the same domain and path as this */ | |
+ replace_old = replace_old_cookie(data, &co, c); | |
+ | |
+ if (co != NULL) { | |
+ c->numcookies++; /* one more cookie in the jar */ | |
} | |
- lastc = clist; | |
- clist = clist->next; | |
- } | |
- | |
- if(c->running) | |
- /* Only show this when NOT reading the cookies from a file */ | |
- infof(data, "%s cookie %s=\"%s\" for domain %s, path %s, " | |
- "expire %" FORMAT_OFF_T "\n", | |
- replace_old?"Replaced":"Added", co->name, co->value, | |
- co->domain, co->path, co->expires); | |
- | |
- if(!replace_old) { | |
- /* then make the last item point on this new one */ | |
- if(lastc) | |
- lastc->next = co; | |
- else | |
- c->cookies = co; | |
+ | |
+ entry = entry->next; | |
} | |
- | |
- c->numcookies++; /* one more cookie in the jar */ | |
- return co; | |
} | |
/***************************************************************************** | |
@@ -1132,4 +1199,46 @@ struct curl_slist *Curl_cookie_list(struct SessionHandle *data) | |
return list; | |
} | |
+struct curl_slist *Curl_cookie_struct_list(struct SessionHandle *data) | |
+{ | |
+ struct curl_slist *list = NULL; | |
+ struct curl_slist *beg; | |
+ struct Cookie *c; | |
+ struct curl_cookie *cc; | |
+ | |
+ if((data->cookies == NULL) || | |
+ (data->cookies->numcookies == 0)) | |
+ return NULL; | |
+ | |
+ c = data->cookies->cookies; | |
+ | |
+ beg = list; | |
+ while(c) { | |
+ cc = (struct curl_cookie *) malloc(sizeof(struct curl_cookie)); | |
+ memset(cc, 0, sizeof(struct curl_cookie)); | |
+ | |
+ cc->name = c->name; | |
+ cc->value = c->value; | |
+ cc->path = c->path; | |
+ cc->domain = c->domain; | |
+ cc->expires = c->expires; | |
+ cc->version = c->version; | |
+ cc->maxage = c->maxage; | |
+ cc->secure = c->secure; | |
+ cc->httponly = c->httponly; | |
+ | |
+ list = curl_slist_append(list, (char *) cc); | |
+ if(list == NULL) { | |
+ curl_slist_free_all(beg); | |
+ return NULL; | |
+ } | |
+ else if(beg == NULL) { | |
+ beg = list; | |
+ } | |
+ c = c->next; | |
+ } | |
+ | |
+ return list; | |
+} | |
+ | |
#endif /* CURL_DISABLE_HTTP || CURL_DISABLE_COOKIES */ | |
diff --git a/lib/cookie.h b/lib/cookie.h | |
index e8c005f..03b4110 100644 | |
--- a/lib/cookie.h | |
+++ b/lib/cookie.h | |
@@ -99,9 +99,11 @@ int Curl_cookie_output(struct CookieInfo *, const char *); | |
#if defined(CURL_DISABLE_HTTP) || defined(CURL_DISABLE_COOKIES) | |
#define Curl_cookie_list(x) NULL | |
+#define Curl_cookie_struct_list(x) NULL | |
#define Curl_cookie_loadfiles(x) do { } while (0) | |
#else | |
struct curl_slist *Curl_cookie_list(struct SessionHandle *data); | |
+struct curl_slist *Curl_cookie_struct_list(struct SessionHandle *data); | |
void Curl_cookie_loadfiles(struct SessionHandle *data); | |
#endif | |
diff --git a/lib/getinfo.c b/lib/getinfo.c | |
index 7a0ed71..14b43bf 100644 | |
--- a/lib/getinfo.c | |
+++ b/lib/getinfo.c | |
@@ -204,6 +204,9 @@ CURLcode Curl_getinfo(struct SessionHandle *data, CURLINFO info, ...) | |
case CURLINFO_COOKIELIST: | |
*param_slistp = Curl_cookie_list(data); | |
break; | |
+ case CURLINFO_COOKIELIST_STRUCT: | |
+ *param_slistp = Curl_cookie_struct_list(data); | |
+ break; | |
case CURLINFO_FTP_ENTRY_PATH: | |
/* Return the entrypath string from the most recent connection. | |
This pointer was copied from the connectdata structure by FTP. | |
diff --git a/lib/url.c b/lib/url.c | |
index 357f213..a1987af 100644 | |
--- a/lib/url.c | |
+++ b/lib/url.c | |
@@ -1369,6 +1369,11 @@ CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option, | |
free(argptr); | |
break; | |
+ | |
+ case CURLOPT_COOKIELIST_STRUCT: | |
+ Curl_cookie_add_slist(data, data->cookies, va_arg(param, struct curl_slist *)); | |
+ break; | |
+ | |
#endif /* CURL_DISABLE_COOKIES */ | |
case CURLOPT_HTTPGET: |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment