Improve cookie support

This commit is contained in:
wbaumann
2014-04-18 19:59:48 +00:00
parent aebcb3c26f
commit 3d314d4b3d
10 changed files with 159 additions and 103 deletions

View File

@ -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.

View File

@ -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) {

View File

@ -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 */

View File

@ -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;
}