From 3d314d4b3df4db0904c3241e2f0f69c1fb71a8bc Mon Sep 17 00:00:00 2001 From: wbaumann Date: Fri, 18 Apr 2014 19:59:48 +0000 Subject: [PATCH] Improve cookie support --- ChangeLog | 4 ++ etc/davfs2.conf | 4 +- man/davfs2.conf.5 | 12 ++-- man/davfs2.conf.5.pot | 21 +++--- man/de/davfs2.conf.5.po | 34 +++++----- man/es/davfs2.conf.5.po | 31 +++++---- src/defaults.h | 4 +- src/mount_davfs.c | 8 +-- src/mount_davfs.h | 2 +- src/webdav.c | 142 ++++++++++++++++++++++++++-------------- 10 files changed, 159 insertions(+), 103 deletions(-) diff --git a/ChangeLog b/ChangeLog index 6d52c2d..d87277f 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,6 +1,10 @@ ChangeLog for davfs2 -------------------- +2014-04-18 Werner Baumann (werner.baumann@onlinehome.de) + * defaults.h, mount_davfs.h, mount_davfs.c, webdav.c: + Improve cookie support (sr #107907, bug #41438). + 2014-04-13 Werner Baumann (werner.baumann@onlinehome.de) * cache.c, defaults.h, mount_davfs.c, mount_davfs.h: Add mount option grpid (sr #108432, Thanks to diff --git a/etc/davfs2.conf b/etc/davfs2.conf index 2bddd54..6728245 100644 --- a/etc/davfs2.conf +++ b/etc/davfs2.conf @@ -1,4 +1,4 @@ -# davfs2 configuration file 2014-04-06 +# davfs2 configuration file 2014-04-18 # version 12 # ------------------------------------ @@ -41,7 +41,7 @@ # use_expect100 0 # if_match_bug 0 # drop_weak_etags 0 -# allow_cookie 0 +# n_cookies 0 # precheck 1 # ignore_dav_header 0 # use_compression 1 diff --git a/man/davfs2.conf.5 b/man/davfs2.conf.5 index 38b3054..d5432e5 100644 --- a/man/davfs2.conf.5 +++ b/man/davfs2.conf.5 @@ -1,4 +1,4 @@ -.TH @CONFIGFILE@ 5 2012\-02\-01 @PACKAGE_STRING@ +.TH @CONFIGFILE@ 5 2014\-04\-18 @PACKAGE_STRING@ .SH NAME @@ -264,12 +264,12 @@ etag is not used at all and the resource cannot be cached. Default: 0 .TP -.B allow_cookie +.B n_cookies Some servers will only work when they are allowed to set a cookie and this -cookie is returned in subsequent requests. This option adds very simple -cookie support. It supports just one cookie which should usually be -a session ID. -0 = no, 1 = yes. +cookie is returned in subsequent requests. This option sets the number of +cookies you are willing to accept and include in subsequent requests. davfs2 +will only care for the name and the value of the cookie and ignore all of +the possible attributes. .br Default: 0 diff --git a/man/davfs2.conf.5.pot b/man/davfs2.conf.5.pot index a1f45f1..0ce095d 100644 --- a/man/davfs2.conf.5.pot +++ b/man/davfs2.conf.5.pot @@ -7,7 +7,7 @@ msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" -"POT-Creation-Date: 2014-04-06 18:16+0300\n" +"POT-Creation-Date: 2014-04-18 18:25+0300\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" @@ -25,7 +25,7 @@ msgstr "" #. type: TH #: davfs2.conf.5:1 #, no-wrap -msgid "2012-02-01" +msgid "2014-04-18" msgstr "" #. type: TH @@ -550,16 +550,17 @@ msgstr "" #. type: TP #: davfs2.conf.5:266 #, no-wrap -msgid "B" +msgid "B" msgstr "" #. type: Plain text #: davfs2.conf.5:273 msgid "" "Some servers will only work when they are allowed to set a cookie and this " -"cookie is returned in subsequent requests. This option adds very simple " -"cookie support. It supports just one cookie which should usually be a " -"session ID. 0 = no, 1 = yes." +"cookie is returned in subsequent requests. This option sets the number of " +"cookies you are willing to accept and include in subsequent requests. davfs2 " +"will only care for the name and the value of the cookie and ignore all of " +"the possible attributes." msgstr "" #. type: TP @@ -1088,7 +1089,7 @@ msgid "Includes config, kernel, cache and http." msgstr "" #. type: SH -#: davfs2.conf.5:513 mount.davfs.8:536 umount.davfs.8:79 +#: davfs2.conf.5:513 mount.davfs.8:547 umount.davfs.8:79 #, no-wrap msgid "AUTHORS" msgstr "" @@ -1101,18 +1102,18 @@ msgid "" msgstr "" #. type: SH -#: davfs2.conf.5:519 mount.davfs.8:553 umount.davfs.8:84 +#: davfs2.conf.5:519 mount.davfs.8:564 umount.davfs.8:84 #, no-wrap msgid "DAVFS2 HOME" msgstr "" #. type: Plain text -#: davfs2.conf.5:522 mount.davfs.8:556 umount.davfs.8:87 +#: davfs2.conf.5:522 mount.davfs.8:567 umount.davfs.8:87 msgid "@PACKAGE_BUGREPORT@" msgstr "" #. type: SH -#: davfs2.conf.5:524 mount.davfs.8:558 umount.davfs.8:89 +#: davfs2.conf.5:524 mount.davfs.8:569 umount.davfs.8:89 #, no-wrap msgid "SEE ALSO" msgstr "" diff --git a/man/de/davfs2.conf.5.po b/man/de/davfs2.conf.5.po index 36346f9..d0a7abb 100644 --- a/man/de/davfs2.conf.5.po +++ b/man/de/davfs2.conf.5.po @@ -6,8 +6,8 @@ msgid "" msgstr "" "Project-Id-Version: davfs2 1.5.0\n" -"POT-Creation-Date: 2014-04-06 18:16+0300\n" -"PO-Revision-Date: 2014-04-06 18:20+0200\n" +"POT-Creation-Date: 2014-04-18 18:25+0300\n" +"PO-Revision-Date: 2014-04-18 18:30+0200\n" "Last-Translator: Werner Baumann \n" "Language-Team: \n" "Language: \n" @@ -25,8 +25,8 @@ msgstr "@CONFIGFILE@" #. type: TH #: davfs2.conf.5:1 #, no-wrap -msgid "2012-02-01" -msgstr "2012-02-01" +msgid "2014-04-18" +msgstr "2014-04-18" # type: TH #. type: TH @@ -740,22 +740,24 @@ msgstr "0 = nein, 1 = ja." #. type: TP #: davfs2.conf.5:266 #, no-wrap -msgid "B" -msgstr "B" +msgid "B" +msgstr "B" # type: Plain text #. type: Plain text #: davfs2.conf.5:273 msgid "" "Some servers will only work when they are allowed to set a cookie and this " -"cookie is returned in subsequent requests. This option adds very simple " -"cookie support. It supports just one cookie which should usually be a " -"session ID. 0 = no, 1 = yes." +"cookie is returned in subsequent requests. This option sets the number of " +"cookies you are willing to accept and include in subsequent requests. davfs2 " +"will only care for the name and the value of the cookie and ignore all of " +"the possible attributes." msgstr "" "Manche Server verweigern den Dienst, wenn ihnen nicht erlaubt is ein Cookie " -"zu setzen. Diese Option fügt sehr einfche Unterstützung für Cookies hinzu. " -"Es wird nur ein Cookie unterstützt, welches normalerweise eine Session-ID " -"sein sollte. 0 = nein, 1 = ja." +"zu setzen. Diese Option legt fest, wie vile Cookies akzeptiert und in den " +"folgenden Requests gesendet werden. davfs2 kümmert sich nur um den Namen und " +"den Wert von Cookies und ignoriert alle eventuellen zusätzlichen " +"Eigenschaften der Cookies." # type: TP #. type: TP @@ -1465,7 +1467,7 @@ msgstr "Beinhaltet config, kernel, cache und http." # type: SH #. type: SH -#: davfs2.conf.5:513 mount.davfs.8:536 umount.davfs.8:79 +#: davfs2.conf.5:513 mount.davfs.8:547 umount.davfs.8:79 #, no-wrap msgid "AUTHORS" msgstr "AUTOREN" @@ -1482,20 +1484,20 @@ msgstr "" # type: SH #. type: SH -#: davfs2.conf.5:519 mount.davfs.8:553 umount.davfs.8:84 +#: davfs2.conf.5:519 mount.davfs.8:564 umount.davfs.8:84 #, no-wrap msgid "DAVFS2 HOME" msgstr "DAVFS2 HOME" # type: TH #. type: Plain text -#: davfs2.conf.5:522 mount.davfs.8:556 umount.davfs.8:87 +#: davfs2.conf.5:522 mount.davfs.8:567 umount.davfs.8:87 msgid "@PACKAGE_BUGREPORT@" msgstr "@PACKAGE_BUGREPORT@" # type: SH #. type: SH -#: davfs2.conf.5:524 mount.davfs.8:558 umount.davfs.8:89 +#: davfs2.conf.5:524 mount.davfs.8:569 umount.davfs.8:89 #, no-wrap msgid "SEE ALSO" msgstr "SIEHE AUCH" diff --git a/man/es/davfs2.conf.5.po b/man/es/davfs2.conf.5.po index b6df473..a84e6b3 100644 --- a/man/es/davfs2.conf.5.po +++ b/man/es/davfs2.conf.5.po @@ -7,7 +7,7 @@ msgid "" msgstr "" "Project-Id-Version: davfs2.conf.5\n" -"POT-Creation-Date: 2014-04-06 18:16+0300\n" +"POT-Creation-Date: 2014-04-18 18:25+0300\n" "PO-Revision-Date: 2007-04-26 01:24-0300\n" "Last-Translator: Luciano Bello \n" "Language-Team: Español \n" @@ -24,11 +24,13 @@ msgstr "" msgid "@CONFIGFILE@" msgstr "@CONFIGFILE@" +# type: TH #. type: TH #: davfs2.conf.5:1 -#, no-wrap -msgid "2012-02-01" -msgstr "" +#, fuzzy, no-wrap +#| msgid "2011-04-03" +msgid "2014-04-18" +msgstr "2011-04-03" # type: TH #. type: TH @@ -712,18 +714,19 @@ msgstr "0 = no, 1 = sí." # type: TP #. type: TP #: davfs2.conf.5:266 -#, no-wrap -msgid "B" +#, fuzzy, no-wrap +#| msgid "B" +msgid "B" msgstr "B" -# type: Plain text #. type: Plain text #: davfs2.conf.5:273 msgid "" "Some servers will only work when they are allowed to set a cookie and this " -"cookie is returned in subsequent requests. This option adds very simple " -"cookie support. It supports just one cookie which should usually be a " -"session ID. 0 = no, 1 = yes." +"cookie is returned in subsequent requests. This option sets the number of " +"cookies you are willing to accept and include in subsequent requests. davfs2 " +"will only care for the name and the value of the cookie and ignore all of " +"the possible attributes." msgstr "" # type: TP @@ -1388,7 +1391,7 @@ msgstr "" # type: SH #. type: SH -#: davfs2.conf.5:513 mount.davfs.8:536 umount.davfs.8:79 +#: davfs2.conf.5:513 mount.davfs.8:547 umount.davfs.8:79 #, no-wrap msgid "AUTHORS" msgstr "AUTORES" @@ -1405,20 +1408,20 @@ msgstr "" # type: SH #. type: SH -#: davfs2.conf.5:519 mount.davfs.8:553 umount.davfs.8:84 +#: davfs2.conf.5:519 mount.davfs.8:564 umount.davfs.8:84 #, no-wrap msgid "DAVFS2 HOME" msgstr "DAVFS2 HOME" # type: TH #. type: Plain text -#: davfs2.conf.5:522 mount.davfs.8:556 umount.davfs.8:87 +#: davfs2.conf.5:522 mount.davfs.8:567 umount.davfs.8:87 msgid "@PACKAGE_BUGREPORT@" msgstr "@PACKAGE_BUGREPORT@" # type: SH #. type: SH -#: davfs2.conf.5:524 mount.davfs.8:558 umount.davfs.8:89 +#: davfs2.conf.5:524 mount.davfs.8:569 umount.davfs.8:89 #, no-wrap msgid "SEE ALSO" msgstr "VER TAMBIÉN" diff --git a/src/defaults.h b/src/defaults.h index f16df62..6ae20d0 100644 --- a/src/defaults.h +++ b/src/defaults.h @@ -185,9 +185,9 @@ May be overridden by system config file and user config file. */ #define DAV_DROP_WEAK_ETAGS 0 -/* Wether to allow a cookie to be set and included in requests. +/* How many cookies to store and include in requests. May be overridden by system config file and user config file. */ -#define DAV_ALLOW_COOKIE 0 +#define DAV_N_COOKIES 0 /* Check on server whether a file exists or has been modified before locking a new file or changing an existant one. diff --git a/src/mount_davfs.c b/src/mount_davfs.c index 73586c3..0433935 100644 --- a/src/mount_davfs.c +++ b/src/mount_davfs.c @@ -1686,7 +1686,7 @@ new_args(void) args->expect100 = DAV_EXPECT100; args->if_match_bug = DAV_IF_MATCH_BUG; args->drop_weak_etags = DAV_DROP_WEAK_ETAGS; - args->allow_cookie = DAV_ALLOW_COOKIE; + args->n_cookies = DAV_N_COOKIES; args->precheck = DAV_PRECHECK; args->ignore_dav_header = DAV_IGNORE_DAV_HEADER; args->use_compression = DAV_USE_COMPRESSION; @@ -1783,7 +1783,7 @@ log_dbg_config(dav_args *args) syslog(LOG_MAKEPRI(LOG_DAEMON, LOG_DEBUG), " drop_weak_etags: %i", args->drop_weak_etags); syslog(LOG_MAKEPRI(LOG_DAEMON, LOG_DEBUG), - " allow_cookie: %i", args->allow_cookie); + " n_cookies: %i", args->n_cookies); syslog(LOG_MAKEPRI(LOG_DAEMON, LOG_DEBUG), " precheck: %i", args->precheck); syslog(LOG_MAKEPRI(LOG_DAEMON, LOG_DEBUG), @@ -2168,8 +2168,8 @@ read_config(dav_args *args, const char * filename, int system) args->if_match_bug = arg_to_int(parmv[1], 10, parmv[0]); } else if (strcmp(parmv[0], "drop_weak_etags") == 0) { args->drop_weak_etags = arg_to_int(parmv[1], 10, parmv[0]); - } else if (strcmp(parmv[0], "allow_cookie") == 0) { - args->allow_cookie = arg_to_int(parmv[1], 10, parmv[0]); + } else if (strcmp(parmv[0], "n_cookies") == 0) { + args->n_cookies = arg_to_int(parmv[1], 10, parmv[0]); } else if (strcmp(parmv[0], "precheck") == 0) { args->precheck = arg_to_int(parmv[1], 10, parmv[0]); } else if (strcmp(parmv[0], "ignore_dav_header") == 0) { diff --git a/src/mount_davfs.h b/src/mount_davfs.h index 5e8e98f..778b47d 100644 --- a/src/mount_davfs.h +++ b/src/mount_davfs.h @@ -89,7 +89,7 @@ typedef struct { int expect100; /* User config file, system config file */ int if_match_bug; /* User config file, system config file */ int drop_weak_etags; /* User config file, system config file */ - int allow_cookie; /* User config file, system config file */ + int n_cookies; /* User config file, system config file */ int precheck; /* User config file, system config file */ int ignore_dav_header; /* User config file, system config file */ int use_compression; /* User config file, system config file */ diff --git a/src/webdav.c b/src/webdav.c index d0202eb..798d10f 100644 --- a/src/webdav.c +++ b/src/webdav.c @@ -231,8 +231,10 @@ static FILE *log_stream; /* A user defined header that is added to all requests. */ char *custom_header; -/* Session cookie. */ -static char *cookie; +/* Array of max. n_cookies cookie strings. NULL if configuration option + allow_cookies is 0. The array must be allocated by dav_init_webdav. */ +static int n_cookies; +static char **cookie_list; /* Private function prototypes and inline functions */ @@ -278,6 +280,9 @@ auth(void *userdata, const char *realm, int attempt, char *user, char *pwd); static int file_reader(void *userdata, const char *block, size_t length); +static void +get_cookies(ne_request *req, void *userdata, const ne_status *status); + static void lock_result(void *userdata, const struct ne_lock *lock, const ne_uri *uri, const ne_status *status); @@ -294,9 +299,6 @@ quota_reader(void *userdata, const char *block, size_t length); static int ssl_verify(void *userdata, int failures, const ne_ssl_certificate *cert); -static int -update_cookie(ne_request *req, void *userdata, const ne_status *status); - /* Public functions */ /*==================*/ @@ -412,11 +414,16 @@ dav_init_webdav(dav_args *args) if (args->header) { custom_header = xstrdup(args->header); - ne_hook_pre_send(session, add_header, custom_header); } - if (args->allow_cookie) - ne_hook_post_send(session, update_cookie, NULL); + if (args->n_cookies) { + n_cookies = args->n_cookies; + cookie_list = (char **) xcalloc(n_cookies, sizeof(char *)); + ne_hook_post_headers(session, get_cookies, NULL); + } + + if (custom_header || cookie_list) + ne_hook_pre_send(session, add_header, NULL); use_expect100 = args->expect100; has_if_match_bug = args->if_match_bug; @@ -1440,7 +1447,20 @@ replace_slashes(char **name) static void add_header(ne_request *req, void *userdata, ne_buffer *header) { - ne_buffer_zappend(header, (char *) userdata); + if (custom_header) + ne_buffer_zappend(header, custom_header); + + if (cookie_list && cookie_list[0]) { + ne_buffer_zappend(header, "Cookie: "); + ne_buffer_zappend(header, cookie_list[0]); + int i = 1; + while (i < n_cookies && cookie_list[i]) { + ne_buffer_zappend(header, ", "); + ne_buffer_zappend(header, cookie_list[i]); + i++; + } + ne_buffer_zappend(header, "\r\n"); + } } @@ -1519,6 +1539,71 @@ file_reader(void *userdata, const char *block, size_t length) } +/* A ne_post_header_fn to read cookies from the Set-Cookie header and + store them in the global arrray of strings cookie_list. The cookies + will be send in the Cookie header of subsequent requests. + Only the "name=value" part of the cookie is stored. All attributes + are completely ignored. + When a cookie with the same name as an already stored cookie, but with + a different value is received, it's value is updated if necessary. + Only n_cookies cookies will be stored. If the server sends more + different cookies these will be ignored. + status must be of class 2XX or 3XX, otherwise the cookie is ignored. */ +static void +get_cookies(ne_request *req, void *userdata, const ne_status *status) +{ + if (status->klass != 2 && status->klass != 3) + return; + + const char *cookie_hdr = ne_get_response_header(req, "Set-Cookie"); + if (!cookie_hdr) + return; + + const char *next = cookie_hdr; + while (next) { + const char *start = next; + next = strchr(start, ','); + const char *end = strchr(start, ';'); + if (next) { + if (!end || end > next) + end = next; + next++; + } else if (!end) { + end = start + strlen(start); + } + + while (start < end && *start == ' ') + start++; + while (end > start && *(end - 1) == ' ') + end--; + + if ((start + 4) > end || *start == '=' || *(end - 1) == '=') + continue; + + char *es = strchr(start, '='); + if (!es) + continue; + size_t nl = es - start; + size_t vl = end - es - 1; + + int i = 0; + for (i = 0; i < n_cookies; i++) { + if (!cookie_list[i]) { + cookie_list[i] = xstrndup(start, end - start); + break; + } + if (strncmp(cookie_list[i], start, nl) == 0) { + if (strncmp(cookie_list[i] + nl + 1, es + 1, vl) != 0) { + free(cookie_list[i]); + cookie_list[i] = xstrndup(start, end - start); + } + break; + } + } + } +} + + /* If the owner of this lock is the same as global variable owner, lock is stored in the global lock store locks and a pointer to the lock is returned in userdata. @@ -1822,42 +1907,3 @@ ssl_verify(void *userdata, int failures, const ne_ssl_certificate *cert) return ret; } - -static int -update_cookie(ne_request *req, void *userdata, const ne_status *status) -{ - if (status->klass != 2) - return NE_OK; - - const char *cookie_hdr = ne_get_response_header(req, "Set-Cookie2"); - if (!cookie_hdr) { - cookie_hdr = ne_get_response_header(req, "Set-Cookie"); - } - if (!cookie_hdr) - return NE_OK; - - if (cookie && strstr(cookie_hdr, cookie) == cookie_hdr) - return NE_OK; - - char *sep = strpbrk(cookie_hdr, "\",; \n\r\0"); - if (!sep) - return NE_OK; - if (*sep == '\"') - sep = strpbrk(sep + 1, "\""); - if (!sep) - return NE_OK; - - if (cookie) { - ne_unhook_pre_send(session, add_header, cookie); - free(cookie); - cookie = NULL; - } - - char *value = xstrndup(cookie_hdr, sep - cookie_hdr + 1); - cookie = xasprintf("Cookie: $Version=1;%s\r\n", value); - free(value); - - ne_hook_pre_send(session, add_header, cookie); - return NE_OK; -} -