cURL / Mailing Lists / curl-library / Single Mail

curl-library

Simple cookie interface!

From: Peteris Krumins [Newsgroups] <pknewsgroups_at_gmail.com>
Date: Thu, 21 Jul 2005 13:09:13 +0300

Hello!

I have added simple cookie interface to libcurl as, according to
http://curl.haxx.se/mail/lib-2004-12/0195.html.

It works just like said there,
curl_easy_getinfo() - CURLINFO_COOKIELIST returns a curl_slist with all
known cookies in Netscape format
(expired ones, too)

curl_easy_setopt() - CURLOPT_COOKIELIST sets a cookie, one at a time.
Cookie can be passed
either HTTP-header style (Set-Cookie: ) or Netscape format.
If cookie engine was not active before adding a cookie, it will be
activated.
If NULL is passed instead of a cookie, all cookies are erased.

I created an example program to show how it works.

Patch attached. (patch against curl 7.14.0).

Enjoy!

--
P.Krumins

Index: docs/examples/Makefile.in
===================================================================
--- docs/examples/Makefile.in (revision 31)
+++ docs/examples/Makefile.in (revision 33)
@@ -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 (revision 0)
+++ docs/examples/cookie_interface.c (revision 33)
@@ -0,0 +1,113 @@
+/*****************************************************************************
+ * _ _ ____ _
+ * 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 (revision 31)
+++ docs/examples/makefile.dj (revision 33)
@@ -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 (revision 31)
+++ lib/cookie.c (revision 33)
@@ -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,67 @@
    }
 }
 
+/* number_of_digits()
+ *
+ * Returns numer of digits in an unsigned integer
+ *
+*/
+static int number_of_digits(unsigned int integer)
+{
+ int len = 1;
+ while (integer > 10) {
+ integer /= 10;
+ len++;
+ }
+ return len;
+}
+
+/* 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)
+{
+ int memory_needed;
+ char *return_string;
+
+ memory_needed = strlen((co->tailmatch && co->domain && co->domain[0] != '.')? ".":"");
+ memory_needed += strlen(co->domain?co->domain:"unknown");
+ memory_needed += strlen(co->tailmatch?"TRUE":"FALSE");
+ memory_needed += strlen(co->path?co->path:"/");
+ memory_needed += strlen(co->secure?"TRUE":"FALSE");
+ memory_needed += number_of_digits((unsigned int)co->expires);
+ memory_needed += strlen(co->name);
+ memory_needed += strlen(co->value?co->value:"");
+ memory_needed += 7; /* 6 tabs and '\0' */
+
+ return_string = malloc(sizeof(char) * memory_needed);
+ if (return_string == NULL) return NULL;
+
+ snprintf(return_string, sizeof(char) * memory_needed,
+ "%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:"");
+
+ return return_string;
+}
+
 /*
  * Curl_cookie_output()
  *
@@ -847,6 +911,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 +920,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 +937,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 (revision 31)
+++ lib/cookie.h (revision 33)
@@ -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 (revision 31)
+++ lib/getinfo.c (revision 33)
@@ -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 (revision 31)
+++ lib/url.c (revision 33)
@@ -1396,6 +1396,36 @@
     data->set.ftp_account = va_arg(param, char *);
     break;
 
+ case CURLOPT_COOKIELIST:
+ {
+ char *line = va_arg(param, char *);
+
+ if (line == NULL) {
+ 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 (revision 31)
+++ include/curl/curl.h (revision 33)
@@ -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-21