cURL / Mailing Lists / curl-library / Single Mail

curl-library

Re: Simple cookie interface!

From: Peteris Krumins [Newsgroups] <pknewsgroups_at_gmail.com>
Date: Wed, 27 Jul 2005 11:09:34 +0300

Daniel Stenberg wrote:

> On Thu, 21 Jul 2005, Peteris Krumins [Newsgroups] wrote:
>
>> I have added simple cookie interface to libcurl as, according to
>> http://curl.haxx.se/mail/lib-2004-12/0195.html.
>
>
> Neat. Thanks for your work! I have some suggestions though:

Okay. I have made the changes and added documentation for the interface
setopt/getinfo options in man pages.

Patch attached. (patch against curl-7.14.0).

--
P.Krumins
If you or your company found this patch useful and it saved you some 
hours of work you might want to buy me a gift!
Look at my wishlist:
http://www.amazon.co.uk/exec/obidos/registry/3LQJRP8M89NE6

Index: docs/libcurl/curl_easy_getinfo.3
===================================================================
--- docs/libcurl/curl_easy_getinfo.3 (.../curl-7.14.0) (revision 48)
+++ docs/libcurl/curl_easy_getinfo.3 (.../branches/curl-7.14.0-cookie-interface) (revision 48)
@@ -132,6 +132,13 @@
 how many times libcurl successfully reused existing connection(s) or not. See
 the Connection Options of \fIcurl_easy_setopt(3)\fP to see how libcurl tries
 to make persistent connections to save time. (Added in 7.12.3)
+.IP CURLINFO_COOKIELIST
+Pass a pointer to a 'struct curl_slist *' to receive a linked-list of all
+cookies cURL knows (expired ones, too). Don't forget to
+\fIcurl_slist_free_all(3)\fP the list after it has been used.
+If there are no cookies (cookies for the handle have not been enabled or
+simply none have been received) 'struct curl_slist *' will be set to
+point to NULL.
 .SH RETURN VALUE
 If the operation was successful, CURLE_OK is returned. Otherwise an
 appropriate error code will be returned.
Index: docs/libcurl/curl_easy_setopt.3
===================================================================
--- docs/libcurl/curl_easy_setopt.3 (.../curl-7.14.0) (revision 48)
+++ docs/libcurl/curl_easy_setopt.3 (.../branches/curl-7.14.0-cookie-interface) (revision 48)
@@ -640,6 +640,12 @@
 loads all cookies, independent if they are session cookies are not. Session
 cookies are cookies without expiry date and they are meant to be alive and
 existing for this "session" only.
+.IP CURLOPT_COOKIELIST
+Pass a char * to a cookie string. Cookie can be either in Netscape / Mozilla
+format or just regular HTTP-style header (Set-Cookie: ...) format.
+The passed string will get modified so make sure it's writable.
+If cURL cookie engine was not enabled it will enable its cookie engine.
+Passing a magic string "ALL" will erase all cookies known by cURL.
 .IP CURLOPT_HTTPGET
 Pass a long. If the long is non-zero, this forces the HTTP request to get back
 to GET. usable if a POST, HEAD, PUT or a custom request have been used
Index: docs/examples/Makefile.in
===================================================================
--- docs/examples/Makefile.in (.../curl-7.14.0) (revision 48)
+++ docs/examples/Makefile.in (.../branches/curl-7.14.0-cookie-interface) (revision 48)
@@ -209,7 +209,8 @@
  post-callback.c multi-app.c multi-double.c multi-single.c \
  multi-post.c fopen.c simplepost.c makefile.dj curlx.c https.c \
  multi-debugcallback.c fileupload.c getinfo.c ftp3rdparty.c debug.c \
- anyauthput.c htmltitle.cc htmltidy.c opensslthreadlock.c
+ anyauthput.c htmltitle.cc htmltidy.c opensslthreadlock.c \
+ cookie_interface.c
 
 all: all-am
 
Index: docs/examples/cookie_interface.c
===================================================================
--- docs/examples/cookie_interface.c (.../curl-7.14.0) (revision 0)
+++ docs/examples/cookie_interface.c (.../branches/curl-7.14.0-cookie-interface) (revision 48)
@@ -0,0 +1,110 @@
+/*****************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * This example shows usage of simple cookie interface.
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#include <time.h>
+
+#include <curl/curl.h>
+
+static void
+print_cookies(CURL *curl)
+{
+ CURLcode res;
+ struct curl_slist *cookies;
+ struct curl_slist *nc;
+ int i;
+
+ printf("Cookies, curl knows:\n");
+ res = curl_easy_getinfo(curl, CURLINFO_COOKIELIST, &cookies);
+ if (res != CURLE_OK) {
+ fprintf(stderr, "Curl curl_easy_getinfo failed: %s\n", curl_easy_strerror(res));
+ exit(1);
+ }
+ nc = cookies, i = 1;
+ while (nc) {
+ printf("[%d]: %s\n", i, nc->data);
+ nc = nc->next;
+ i++;
+ }
+ if (i == 1) {
+ printf("(none)\n");
+ }
+ curl_slist_free_all(cookies);
+}
+
+int
+main(void)
+{
+ CURL *curl;
+ CURLcode res;
+
+ curl_global_init(CURL_GLOBAL_ALL);
+ curl = curl_easy_init();
+ if (curl) {
+ char nline[256];
+
+ curl_easy_setopt(curl, CURLOPT_URL, "http://www.google.com/"); /* google.com sets "PREF" cookie */
+ curl_easy_setopt(curl, CURLOPT_VERBOSE, 1);
+ curl_easy_setopt(curl, CURLOPT_COOKIEFILE, ""); /* just to start the cookie engine */
+ res = curl_easy_perform(curl);
+ if (res != CURLE_OK) {
+ fprintf(stderr, "Curl perform failed: %s\n", curl_easy_strerror(res));
+ return 1;
+ }
+
+ print_cookies(curl);
+
+ printf("Erasing curl's knowledge of cookies!\n");
+ curl_easy_setopt(curl, CURLOPT_COOKIELIST, NULL);
+
+ print_cookies(curl);
+
+ printf("-----------------------------------------------\n"
+ "Setting a cookie \"PREF\" via cookie interface:\n");
+#ifdef WIN32
+#define snprintf _snprintf
+#endif
+ /* Netscape format cookie */
+ snprintf(nline, 256, "%s\t%s\t%s\t%s\t%u\t%s\t%s",
+ ".google.com", "TRUE", "/", "FALSE", time(NULL) + 31337, "PREF", "hello google, i like you very much!");
+ res = curl_easy_setopt(curl, CURLOPT_COOKIELIST, nline);
+ if (res != CURLE_OK) {
+ fprintf(stderr, "Curl curl_easy_setopt failed: %s\n", curl_easy_strerror(res));
+ return 1;
+ }
+
+ /* HTTP-header style cookie */
+ snprintf(nline, 256,
+ "Set-Cookie: OLD_PREF=3d141414bf4209321; "
+ "expires=Sun, 17-Jan-2038 19:14:07 GMT; path=/; domain=.google.com");
+ res = curl_easy_setopt(curl, CURLOPT_COOKIELIST, nline);
+ if (res != CURLE_OK) {
+ fprintf(stderr, "Curl curl_easy_setopt failed: %s\n", curl_easy_strerror(res));
+ return 1;
+ }
+
+ print_cookies(curl);
+
+ res = curl_easy_perform(curl);
+ if (res != CURLE_OK) {
+ fprintf(stderr, "Curl perform failed: %s\n", curl_easy_strerror(res));
+ return 1;
+ }
+ }
+ else {
+ fprintf(stderr, "Curl init failed!\n");
+ return 1;
+ }
+
+ curl_global_cleanup();
+ return 0;
+}
Index: docs/examples/makefile.dj
===================================================================
--- docs/examples/makefile.dj (.../curl-7.14.0) (revision 48)
+++ docs/examples/makefile.dj (.../branches/curl-7.14.0-cookie-interface) (revision 48)
@@ -20,7 +20,8 @@
             multi-double.exe multi-post.exe multi-single.exe \
             persistant.exe post-callback.exe postit2.exe \
             sepheaders.exe simple.exe simplessl.exe https.exe \
- ftp3rdparty.exe getinfo.exe anyauthput.exe
+ ftp3rdparty.exe getinfo.exe anyauthput.exe \
+ cookie_interface.exe
 
 all: $(PROGRAMS)
 
Index: lib/cookie.c
===================================================================
--- lib/cookie.c (.../curl-7.14.0) (revision 48)
+++ lib/cookie.c (.../branches/curl-7.14.0-cookie-interface) (revision 48)
@@ -85,6 +85,9 @@
 #include <stdlib.h>
 #include <string.h>
 
+#define _MPRINTF_REPLACE /* without this on windows OS we get undefined reference to snprintf */
+#include <curl/mprintf.h>
+
 #include "urldata.h"
 #include "cookie.h"
 #include "strequal.h"
@@ -816,6 +819,34 @@
    }
 }
 
+/* get_netscape_format()
+ *
+ * Formats a string for Netscape output file, w/o a newline at the end.
+ *
+ * Function returns a char * to a formatted line. Has to be free()d
+*/
+static char *get_netscape_format(const struct Cookie *co)
+{
+ return aprintf(
+ "%s%s\t" /* domain */
+ "%s\t" /* tailmatch */
+ "%s\t" /* path */
+ "%s\t" /* secure */
+ "%u\t" /* expires */
+ "%s\t" /* name */
+ "%s", /* value */
+ /* Make sure all domains are prefixed with a dot if they allow
+ tailmatching. This is Mozilla-style. */
+ (co->tailmatch && co->domain && co->domain[0] != '.')? ".":"",
+ co->domain?co->domain:"unknown",
+ co->tailmatch?"TRUE":"FALSE",
+ co->path?co->path:"/",
+ co->secure?"TRUE":"FALSE",
+ (unsigned int)co->expires,
+ co->name,
+ co->value?co->value:"");
+}
+
 /*
  * Curl_cookie_output()
  *
@@ -847,6 +878,8 @@
   }
 
   if(c) {
+ char *format_ptr;
+
     fputs("# Netscape HTTP Cookie File\n"
           "# http://www.netscape.com/newsref/std/cookie_spec.html\n"
           "# This file was generated by libcurl! Edit at your own risk.\n\n",
@@ -854,26 +887,13 @@
     co = c->cookies;
 
     while(co) {
- fprintf(out,
- "%s%s\t" /* domain */
- "%s\t" /* tailmatch */
- "%s\t" /* path */
- "%s\t" /* secure */
- "%u\t" /* expires */
- "%s\t" /* name */
- "%s\n", /* value */
-
- /* Make sure all domains are prefixed with a dot if they allow
- tailmatching. This is Mozilla-style. */
- (co->tailmatch && co->domain && co->domain[0] != '.')? ".":"",
- co->domain?co->domain:"unknown",
- co->tailmatch?"TRUE":"FALSE",
- co->path?co->path:"/",
- co->secure?"TRUE":"FALSE",
- (unsigned int)co->expires,
- co->name,
- co->value?co->value:"");
-
+ format_ptr = get_netscape_format(co);
+ if (format_ptr == NULL) {
+ fprintf(out, "#\n# Fatal libcurl error\n");
+ return 1;
+ }
+ fprintf(out, "%s\n", format_ptr);
+ free(format_ptr);
       co=co->next;
     }
   }
@@ -884,4 +904,34 @@
   return 0;
 }
 
+struct curl_slist *Curl_cookie_list(struct SessionHandle *data)
+{
+ struct curl_slist *list = NULL;
+ struct curl_slist *beg;
+ struct Cookie *c;
+ char *line;
+
+ if (data->cookies == NULL) return NULL;
+ if (data->cookies->numcookies == 0) return NULL;
+
+ c = data->cookies->cookies;
+
+ beg = list;
+ while (c) {
+ /* fill the list with _all_ the cookies we know */
+ line = get_netscape_format(c);
+ if (line == NULL) {
+ /* get_netscape_format returns null only if we run out of memory */
+
+ curl_slist_free_all(beg); /* free some memory */
+ return NULL;
+ }
+ list = curl_slist_append(list, line);
+ free(line);
+ c = c->next;
+ }
+
+ return list;
+}
+
 #endif /* CURL_DISABLE_HTTP || CURL_DISABLE_COOKIES */
Index: lib/cookie.h
===================================================================
--- lib/cookie.h (.../curl-7.14.0) (revision 48)
+++ lib/cookie.h (.../branches/curl-7.14.0-cookie-interface) (revision 48)
@@ -92,4 +92,6 @@
 void Curl_cookie_cleanup(struct CookieInfo *);
 int Curl_cookie_output(struct CookieInfo *, char *);
 
+struct curl_slist *Curl_cookie_list(struct SessionHandle *data);
+
 #endif
Index: lib/getinfo.c
===================================================================
--- lib/getinfo.c (.../curl-7.14.0) (revision 48)
+++ lib/getinfo.c (.../branches/curl-7.14.0-cookie-interface) (revision 48)
@@ -184,6 +184,9 @@
   case CURLINFO_SSL_ENGINES:
     *param_slistp = Curl_ssl_engines_list(data);
     break;
+ case CURLINFO_COOKIELIST:
+ *param_slistp = Curl_cookie_list(data);
+ break;
   default:
     return CURLE_BAD_FUNCTION_ARGUMENT;
   }
Index: lib/url.c
===================================================================
--- lib/url.c (.../curl-7.14.0) (revision 48)
+++ lib/url.c (.../branches/curl-7.14.0-cookie-interface) (revision 48)
@@ -1396,6 +1396,41 @@
     data->set.ftp_account = va_arg(param, char *);
     break;
 
+ case CURLOPT_COOKIELIST:
+ {
+ char *line = va_arg(param, char *);
+
+ if (line == NULL) {
+ break;
+ }
+ if (strequal(line, "ALL")) {
+ if (data->cookies == NULL) {
+ break;
+ }
+ else {
+ /* clear all cookies */
+ Curl_cookie_freelist(data->cookies->cookies);
+ data->cookies->cookies = NULL;
+ break;
+ }
+ }
+
+ if (!data->cookies) {
+ /* if cookie engine was not running, activate it */
+ data->cookies = Curl_cookie_init(data, NULL, NULL, TRUE);
+ }
+
+ if (checkprefix("Set-Cookie:", line)) {
+ /* HTTP Header format line */
+ Curl_cookie_add(data, data->cookies, TRUE, line + 11, NULL, NULL);
+ }
+ else {
+ /* Netscape format line */
+ Curl_cookie_add(data, data->cookies, FALSE, line, NULL, NULL);
+ }
+ }
+ break;
+
   default:
     /* unknown tag and its companion, just ignore: */
     result = CURLE_FAILED_INIT; /* correct this */
Index: include/curl/curl.h
===================================================================
--- include/curl/curl.h (.../curl-7.14.0) (revision 48)
+++ include/curl/curl.h (.../branches/curl-7.14.0-cookie-interface) (revision 48)
@@ -890,6 +890,9 @@
      "account" info */
   CINIT(FTP_ACCOUNT, OBJECTPOINT, 134),
 
+ /* feed cookies into cookie engine */
+ CINIT(COOKIELIST, OBJECTPOINT, 135),
+
   CURLOPT_LASTENTRY /* the last unused */
 } CURLoption;
 
@@ -1244,6 +1247,7 @@
   CURLINFO_OS_ERRNO = CURLINFO_LONG + 25,
   CURLINFO_NUM_CONNECTS = CURLINFO_LONG + 26,
   CURLINFO_SSL_ENGINES = CURLINFO_SLIST + 27,
+ CURLINFO_COOKIELIST = CURLINFO_SLIST + 28,
   /* Fill in new entries below here! */
 
   CURLINFO_LASTONE = 28
Received on 2005-07-27