Back to index

avfs  1.0.1
Classes | Defines | Functions | Variables
dav_locks.c File Reference
#include "config.h"
#include "http_request.h"
#include "dav_locks.h"
#include "dav_basic.h"
#include "dav_props.h"
#include "uri.h"
#include "dav_207.h"
#include "neon_i18n.h"
#include "hip_xml.h"
#include "ne_alloc.h"

Go to the source code of this file.

Classes

struct  submit_locks
struct  dav_lock_session_s
struct  request_locks
struct  discover_ctx

Defines

#define HOOK_ID   "http://webdav.org/neon/hooks/webdav-locking"
#define DAV_ELM_LOCK_FIRST   (DAV_ELM_207_UNUSED)
#define DAV_ELM_lockdiscovery   (DAV_ELM_LOCK_FIRST)
#define DAV_ELM_activelock   (DAV_ELM_LOCK_FIRST + 1)
#define DAV_ELM_lockscope   (DAV_ELM_LOCK_FIRST + 2)
#define DAV_ELM_locktype   (DAV_ELM_LOCK_FIRST + 3)
#define DAV_ELM_depth   (DAV_ELM_LOCK_FIRST + 4)
#define DAV_ELM_owner   (DAV_ELM_LOCK_FIRST + 5)
#define DAV_ELM_timeout   (DAV_ELM_LOCK_FIRST + 6)
#define DAV_ELM_locktoken   (DAV_ELM_LOCK_FIRST + 7)
#define DAV_ELM_lockinfo   (DAV_ELM_LOCK_FIRST + 8)
#define DAV_ELM_write   (DAV_ELM_LOCK_FIRST + 9)
#define DAV_ELM_exclusive   (DAV_ELM_LOCK_FIRST + 10)
#define DAV_ELM_shared   (DAV_ELM_LOCK_FIRST + 11)
#define A(x)   { "DAV:", #x, DAV_ELM_ ## x, HIP_XML_COLLECT } /* ANY */
#define D(x)   { "DAV:", #x, DAV_ELM_ ## x, 0 } /* normal */
#define C(x)   { "DAV:", #x, DAV_ELM_ ## x, HIP_XML_CDATA } /* (#PCDATA) */
#define E(x)   { "DAV:", #x, DAV_ELM_ ## x, 0 /* LEAF */ } /* EMPTY */

Functions

static void * create (void *session, http_req *req, const char *method, const char *uri)
static void pre_send (void *private, sbuffer req)
static void destroy (void *private)
dav_lock_session * dav_lock_register (http_session *sess)
void dav_lock_unregister (dav_lock_session *sess)
static void submit_lock (struct request_locks *rl, struct dav_lock *lock, const char *uri)
struct dav_lockdav_lock_find (dav_lock_session *sess, const char *uri)
void dav_lock_using_parent (http_req *req, const char *uri)
int dav_lock_iterate (dav_lock_session *sess, dav_lock_walkfunc func, void *userdata)
void dav_lock_using_resource (http_req *req, const char *uri, int depth)
void dav_lock_add (dav_lock_session *sess, struct dav_lock *lock)
void dav_lock_remove (dav_lock_session *sess, struct dav_lock *lock)
struct dav_lockdav_lock_copy (const struct dav_lock *lock)
void dav_lock_free (struct dav_lock *lock)
int dav_unlock (http_session *sess, struct dav_lock *lock)
static int check_context (hip_xml_elmid parent, hip_xml_elmid child)
static int parse_depth (const char *depth)
static long parse_timeout (const char *timeout)
static void discover_results (void *userdata, const char *href, const dav_prop_result_set *set)
static int end_element_common (struct dav_lock *l, const struct hip_xml_elm *elm, const char *cdata)
static int end_element_ldisc (void *userdata, const struct hip_xml_elm *elm, const char *cdata)
static int end_element_lock (void *userdata, const struct hip_xml_elm *elm, const char *cdata)
static void * create_private (void *userdata, const char *uri)
int dav_lock_discover (http_session *sess, const char *uri, dav_lock_result callback, void *userdata)
int dav_lock (http_session *sess, struct dav_lock *lock)

Variables

static http_request_hooks lock_hooks
static struct hip_xml_elm []
static const dav_propname lock_props []

Class Documentation

struct submit_locks

Definition at line 51 of file dav_locks.c.

Collaboration diagram for submit_locks:
Class Members
struct dav_lock * lock
struct submit_locks * next
const char * uri
struct dav_lock_session_s

Definition at line 57 of file dav_locks.c.

Collaboration diagram for dav_lock_session_s:
Class Members
struct dav_lock * locks
struct request_locks

Definition at line 62 of file dav_locks.c.

Collaboration diagram for request_locks:
Class Members
struct submit_locks * locks
dav_lock_session * session
struct discover_ctx

Definition at line 68 of file dav_locks.c.

Collaboration diagram for discover_ctx:
Class Members
dav_lock_result results
void * userdata

Define Documentation

#define A (   x)    { "DAV:", #x, DAV_ELM_ ## x, HIP_XML_COLLECT } /* ANY */
#define C (   x)    { "DAV:", #x, DAV_ELM_ ## x, HIP_XML_CDATA } /* (#PCDATA) */
#define D (   x)    { "DAV:", #x, DAV_ELM_ ## x, 0 } /* normal */

Definition at line 94 of file dav_locks.c.

#define DAV_ELM_depth   (DAV_ELM_LOCK_FIRST + 4)

Definition at line 97 of file dav_locks.c.

Definition at line 103 of file dav_locks.c.

Definition at line 91 of file dav_locks.c.

Definition at line 93 of file dav_locks.c.

Definition at line 101 of file dav_locks.c.

Definition at line 95 of file dav_locks.c.

Definition at line 100 of file dav_locks.c.

Definition at line 96 of file dav_locks.c.

#define DAV_ELM_owner   (DAV_ELM_LOCK_FIRST + 5)

Definition at line 98 of file dav_locks.c.

#define DAV_ELM_shared   (DAV_ELM_LOCK_FIRST + 11)

Definition at line 104 of file dav_locks.c.

#define DAV_ELM_timeout   (DAV_ELM_LOCK_FIRST + 6)

Definition at line 99 of file dav_locks.c.

#define DAV_ELM_write   (DAV_ELM_LOCK_FIRST + 9)

Definition at line 102 of file dav_locks.c.

#define E (   x)    { "DAV:", #x, DAV_ELM_ ## x, 0 /* LEAF */ } /* EMPTY */
#define HOOK_ID   "http://webdav.org/neon/hooks/webdav-locking"

Definition at line 47 of file dav_locks.c.


Function Documentation

static int check_context ( hip_xml_elmid  parent,
hip_xml_elmid  child 
) [static]

Definition at line 364 of file dav_locks.c.

                                                                    {
    DEBUG(DEBUG_XML, "dav_locks: check_context %d in %d\n", child, parent);
    switch (parent) {
    case HIP_ELM_root:
       /* TODO: for LOCK requests only...
        * shouldn't allow this for PROPFIND really */
       if (child == DAV_ELM_prop)
           return HIP_XML_VALID;
       break;     
    case DAV_ELM_prop:
       if (child == DAV_ELM_lockdiscovery)
           return HIP_XML_VALID;
       break;
    case DAV_ELM_lockdiscovery:
       if (child == DAV_ELM_activelock)
           return HIP_XML_VALID;
       break;
    case DAV_ELM_activelock:
       switch (child) {
       case DAV_ELM_lockscope:
       case DAV_ELM_locktype:
       case DAV_ELM_depth:
       case DAV_ELM_owner:
       case DAV_ELM_timeout:
       case DAV_ELM_locktoken:
           return HIP_XML_VALID;
       default:
           break;
       }
       break;
    case DAV_ELM_lockscope:
       switch (child) {
       case DAV_ELM_exclusive:
       case DAV_ELM_shared:
           return HIP_XML_VALID;
       default:
           break;
       }
    case DAV_ELM_locktype:
       if (child == DAV_ELM_write)
           return HIP_XML_VALID;
       break;
       /* ... depth is PCDATA, owner is COLLECT, timeout is PCDATA */
    case DAV_ELM_locktoken:
       if (child == DAV_ELM_href)
           return HIP_XML_VALID;
       break;
    }
    return HIP_XML_DECLINE;
}

Here is the caller graph for this function:

static void * create ( void *  session,
http_req *  req,
const char *  method,
const char *  uri 
) [static]

Definition at line 130 of file dav_locks.c.

{
    struct request_locks *rl = ne_calloc(sizeof *rl);
    rl->session = session;
    return rl;
}
static void* create_private ( void *  userdata,
const char *  uri 
) [static]

Definition at line 515 of file dav_locks.c.

{
    return ne_calloc(sizeof(struct dav_lock));
}

Here is the caller graph for this function:

int dav_lock ( http_session *  sess,
struct dav_lock lock 
)

Definition at line 545 of file dav_locks.c.

{
    http_req *req = http_request_create(sess, "LOCK", lock->uri);
    sbuffer body = sbuffer_create();
    hip_xml_parser *parser = hip_xml_create();
    int ret, parse_failed;

    hip_xml_push_handler(parser, lock_elms, check_context, 
                      NULL, end_element_lock, lock);
    
    /* Create the body */
    sbuffer_concat(body, "<?xml version=\"1.0\" encoding=\"utf-8\"?>" EOL
                  "<lockinfo xmlns='DAV:'>" EOL " <lockscope>",
                  lock->scope==dav_lockscope_exclusive?
                  "<exclusive/>":"<shared/>",
                  "</lockscope>" EOL
                  "<locktype><write/></locktype>", NULL);

    if (lock->owner) {
       sbuffer_concat(body, "<owner>", lock->owner, "</owner>" EOL, NULL);
    }
    sbuffer_zappend(body, "</lockinfo>" EOL);

    http_set_request_body_buffer(req, sbuffer_data(body));
    http_add_response_body_reader(req, http_accept_2xx, 
                              hip_xml_parse_v, parser);
    http_add_request_header(req, "Content-Type", "text/xml");
    dav_add_depth_header(req, lock->depth);

    /* TODO: 
     * By 2518, we need this only if we are creating a lock-null resource.
     * Since we don't KNOW whether the lock we're given is a lock-null
     * or not, we cover our bases.
     */
    dav_lock_using_parent(req, lock->uri);
    /* This one is clearer from 2518 sec 8.10.4. */
    dav_lock_using_resource(req, lock->uri, lock->depth);

    ret = http_request_dispatch(req);

    sbuffer_destroy(body);
    parse_failed = !hip_xml_valid(parser);
    
    if (ret == HTTP_OK && http_get_status(req)->klass == 2) {
       if (parse_failed) {
           ret = HTTP_ERROR;
           http_set_error(sess, hip_xml_get_error(parser));
       }
       else if (http_get_status(req)->code == 207) {
           ret = HTTP_ERROR;
           /* TODO: set the error string appropriately */
       }
    } else {
       ret = HTTP_ERROR;
    }

    http_request_destroy(req);
    hip_xml_destroy(parser);

    /* TODO: free the list */
    return ret;
}

Here is the call graph for this function:

void dav_lock_add ( dav_lock_session *  sess,
struct dav_lock lock 
)

Definition at line 295 of file dav_locks.c.

{
    if (sess->locks != NULL) {
       sess->locks->prev = lock;
    }
    lock->prev = NULL;
    lock->next = sess->locks;
    sess->locks = lock;
}
struct dav_lock* dav_lock_copy ( const struct dav_lock lock) [read]

Definition at line 317 of file dav_locks.c.

{
    struct dav_lock *ret = ne_calloc(sizeof *ret);

    ret->uri = ne_strdup(lock->uri);
    ret->depth = lock->depth;
    ret->type = lock->type;
    ret->scope = lock->scope;
    ret->token = ne_strdup(lock->token);
    ret->owner = ne_strdup(lock->owner);
    ret->timeout = lock->timeout;

    return ret;
}
int dav_lock_discover ( http_session *  sess,
const char *  uri,
dav_lock_result  callback,
void *  userdata 
)

Definition at line 521 of file dav_locks.c.

{
    dav_propfind_handler *handler;
    struct discover_ctx ctx = {0};
    int ret;
    
    ctx.results = callback;
    ctx.userdata = userdata;

    handler = dav_propfind_create(sess, uri, DAV_DEPTH_ZERO);

    dav_propfind_set_complex(handler, lock_props, create_private, NULL);
    
    hip_xml_push_handler(dav_propfind_get_parser(handler), lock_elms, 
                      check_context, NULL, end_element_ldisc, handler);
    
    ret = dav_propfind_named(handler, discover_results, &ctx);
    
    dav_propfind_destroy(handler);

    return ret;
}

Here is the call graph for this function:

struct dav_lock* dav_lock_find ( dav_lock_session *  sess,
const char *  uri 
) [read]

Definition at line 203 of file dav_locks.c.

{
    struct dav_lock *cur;
    for (cur = sess->locks; cur != NULL; cur = cur->next) {
       if (uri_compare(uri, cur->uri) == 0) 
           return cur;
    }
    return NULL;
}
void dav_lock_free ( struct dav_lock lock)

Definition at line 332 of file dav_locks.c.

{
    HTTP_FREE(lock->uri);
    HTTP_FREE(lock->owner);
    HTTP_FREE(lock->token);
    free(lock);
}
int dav_lock_iterate ( dav_lock_session *  sess,
dav_lock_walkfunc  func,
void *  userdata 
)

Definition at line 237 of file dav_locks.c.

{
    struct dav_lock *lock;
    int count = 0;

    for (lock = sess->locks; lock != NULL; lock = lock->next) {
       if (func != NULL) {
           (*func)(lock, userdata);
       }
       count++;
    }
    
    return count;
}
dav_lock_session* dav_lock_register ( http_session *  sess)

Definition at line 168 of file dav_locks.c.

{
    dav_lock_session *locksess = ne_calloc(sizeof *locksess);

    /* Register the hooks */
    http_add_hooks(sess, &lock_hooks, locksess);
    
    return locksess;
}
void dav_lock_remove ( dav_lock_session *  sess,
struct dav_lock lock 
)

Definition at line 305 of file dav_locks.c.

{
    if (lock->prev != NULL) {
       lock->prev->next = lock->next;
    } else {
       sess->locks = lock->next;
    }
    if (lock->next != NULL) {
       lock->next->prev = lock->prev;
    }
}
void dav_lock_unregister ( dav_lock_session *  sess)

Definition at line 178 of file dav_locks.c.

{
    /* FIXME: free the lock list */
    free(sess);
}
void dav_lock_using_parent ( http_req *  req,
const char *  uri 
)

Definition at line 213 of file dav_locks.c.

{
    struct request_locks *rl = http_get_hook_private(req, HOOK_ID);
    char *parent;

    if (rl == NULL)
       return;       

    parent = uri_parent(uri);

    if (parent != NULL) {
       struct dav_lock *lock;
       /* Find any locks on the parent resource.
        * FIXME: should check for depth-infinity locks too. */
       lock = dav_lock_find(rl->session, parent);
       if (lock) {
           DEBUG(DEBUG_LOCKS, "Locked parent, %s on %s\n", lock->token, 
                lock->uri);
           submit_lock(rl, lock, uri);
       }
       free(parent);
    }
}

Here is the call graph for this function:

void dav_lock_using_resource ( http_req *  req,
const char *  uri,
int  depth 
)

Definition at line 253 of file dav_locks.c.

{
    /* Grab the private cookie for this request */
    struct request_locks *rl = http_get_hook_private(req, HOOK_ID);
    struct dav_lock *lock; /* all the known locks */
    int match;

    if (rl == NULL)
       return;       

    /* Iterate over the list of session locks to see if any of
     * them apply to this resource */
    for (lock = rl->session->locks; lock != NULL; lock = lock->next) {
       
       match = 0;
       
       if (depth == DAV_DEPTH_INFINITE && uri_childof(uri, lock->uri)) {
           /* Case 1: this is a depth-infinity request which will 
            * modify a lock somewhere inside the collection. */
           DEBUG(DEBUG_LOCKS, "Has child: %s\n", lock->token);
           match = 1;
       } 
       else if (uri_compare(uri, lock->uri) == 0) {
           /* Case 2: this request is directly on a locked resource */
           DEBUG(DEBUG_LOCKS, "Has direct lock: %s\n", lock->token);
           match = 1;
       }
       else if (lock->depth == DAV_DEPTH_INFINITE && 
               uri_childof(lock->uri, uri)) {
           /* Case 3: there is a higher-up infinite-depth lock which
            * covers the resource that this request will modify. */
           DEBUG(DEBUG_LOCKS, "Is child of: %s\n", lock->token);
           match = 1;
       }
       
       if (match) {
           submit_lock(rl, lock, uri);
       }
    }

}

Here is the call graph for this function:

int dav_unlock ( http_session *  sess,
struct dav_lock lock 
)

Definition at line 340 of file dav_locks.c.

{
    http_req *req = http_request_create(sess, "UNLOCK", lock->uri);
    int ret;
    
    http_print_request_header(req, "Lock-Token", "<%s>", lock->token);
    
    /* TODO: need this or not?
     * it definitely goes away when lock-null resources go away */
    dav_lock_using_parent(req, lock->uri);

    ret = http_request_dispatch(req);
    
    if (ret == HTTP_OK && http_get_status(req)->klass == 2) {
       ret = HTTP_OK;    
    } else {
       ret = HTTP_ERROR;
    }

    http_request_destroy(req);
    
    return ret;
}
static void destroy ( void *  private) [static]

Definition at line 155 of file dav_locks.c.

{
    struct request_locks *rl = priv;
    struct submit_locks *lock, *next;
    
    for (lock = rl->locks; lock != NULL; lock = next) {
       next = lock->next;
       free(lock);
    }
    
    free(rl);
}

Here is the caller graph for this function:

static void discover_results ( void *  userdata,
const char *  href,
const dav_prop_result_set *  set 
) [static]

Definition at line 438 of file dav_locks.c.

{
    struct discover_ctx *ctx = userdata;
    struct dav_lock *lock = dav_propset_private(set);

    if (lock == NULL)
       return;

    lock->uri = ne_strdup(href);

    ctx->results(ctx->userdata, lock, 
               href, dav_propset_status(set, &lock_props[0]));

    
    dav_lock_free(lock);

    DEBUG(DEBUG_LOCKS, "End of response for %s\n", href);
}

Here is the caller graph for this function:

static int end_element_common ( struct dav_lock l,
const struct hip_xml_elm elm,
const char *  cdata 
) [static]

Definition at line 459 of file dav_locks.c.

{
    switch (elm->id){ 
    case DAV_ELM_write:
       l->type = dav_locktype_write;
       break;
    case DAV_ELM_exclusive:
       l->scope = dav_lockscope_exclusive;
       break;
    case DAV_ELM_shared:
       l->scope = dav_lockscope_shared;
       break;
    case DAV_ELM_depth:
       DEBUG(DEBUG_LOCKS, "Got depth: %s\n", cdata);
       l->depth = parse_depth(cdata);
       if (l->depth == -1) {
           return -1;
       }
       break;
    case DAV_ELM_timeout:
       DEBUG(DEBUG_LOCKS, "Got timeout: %s\n", cdata);
       l->timeout = parse_timeout(cdata);
       if (l->timeout == DAV_TIMEOUT_INVALID) {
           return -1;
       }
       break;
    case DAV_ELM_owner:
       l->owner = strdup(cdata);
       break;
    case DAV_ELM_href:
       l->token = strdup(cdata);
       break;
    }
    return 0;
}

Here is the call graph for this function:

Here is the caller graph for this function:

static int end_element_ldisc ( void *  userdata,
const struct hip_xml_elm elm,
const char *  cdata 
) [static]

Definition at line 498 of file dav_locks.c.

{
    struct dav_lock *lock = dav_propfind_current_private(userdata);

    return end_element_common(lock, elm, cdata);
}

Here is the call graph for this function:

Here is the caller graph for this function:

static int end_element_lock ( void *  userdata,
const struct hip_xml_elm elm,
const char *  cdata 
) [static]

Definition at line 508 of file dav_locks.c.

{
    struct dav_lock *lock = userdata;
    return end_element_common(lock, elm, cdata);
}

Here is the call graph for this function:

Here is the caller graph for this function:

static int parse_depth ( const char *  depth) [static]

Definition at line 415 of file dav_locks.c.

                                          {
    if (strcasecmp(depth, "infinity") == 0) {
       return DAV_DEPTH_INFINITE;
    } else if (isdigit(depth[0])) {
       return atoi(depth);
    } else {
       return -1;
    }
}

Here is the caller graph for this function:

static long parse_timeout ( const char *  timeout) [static]

Definition at line 425 of file dav_locks.c.

                                               {
    if (strcasecmp(timeout, "infinite") == 0) {
       return DAV_TIMEOUT_INFINITE;
    } else if (strncasecmp(timeout, "Second-", 7) == 0) {
       long to = strtol(timeout, NULL, 10);
       if (to == LONG_MIN || to == LONG_MAX)
           return DAV_TIMEOUT_INVALID;
       return to;
    } else {
       return DAV_TIMEOUT_INVALID;
    }
}

Here is the caller graph for this function:

static void pre_send ( void *  private,
sbuffer  req 
) [static]

Definition at line 138 of file dav_locks.c.

{
    struct request_locks *rl = private;
    
    if (rl->locks != NULL) {
       struct submit_locks *item;

       /* Add in the If header */
       sbuffer_zappend(req, "If:");
       for (item = rl->locks; item != NULL; item = item->next) {
           sbuffer_concat(req, " <", item->lock->uri, "> (<",
                        item->lock->token, ">)", NULL);
       }
       sbuffer_zappend(req, EOL);
    }
}

Here is the caller graph for this function:

static void submit_lock ( struct request_locks rl,
struct dav_lock lock,
const char *  uri 
) [static]

Definition at line 185 of file dav_locks.c.

{
    struct submit_locks *slock;

    /* Check for dups */
    for (slock = rl->locks; slock != NULL; slock = slock->next) {
       if (strcasecmp(slock->lock->token, lock->token) == 0)
           return;
    }

    slock = ne_calloc(sizeof *slock);
    slock->lock = lock;
    slock->uri = uri;
    slock->next = rl->locks;
    rl->locks = slock;
}

Here is the caller graph for this function:


Variable Documentation

struct hip_xml_elm[] [static]
Initial value:
 {
#define A(x) 
#define D(x) 
#define C(x) 
#define E(x) 
    D(lockdiscovery), D(activelock),
    D(prop),
    D(lockscope), D(locktype), C(depth), A(owner), C(timeout), D(locktoken),
    
    D(lockinfo), D(lockscope), D(locktype),
    E(write), E(exclusive), E(shared),
    C(href),




    { NULL, 0, 0 }
}

Definition at line 106 of file dav_locks.c.

Initial value:

Definition at line 80 of file dav_locks.c.

Initial value:
 {
    { "DAV:", "lockdiscovery" },
    { NULL }
}

Definition at line 125 of file dav_locks.c.