]> granicus.if.org Git - apache/commitdiff
Implement the MERGE method: fill in dav_method_merge(); add merge() function
authorGreg Stein <gstein@apache.org>
Sat, 14 Apr 2001 12:45:30 +0000 (12:45 +0000)
committerGreg Stein <gstein@apache.org>
Sat, 14 Apr 2001 12:45:30 +0000 (12:45 +0000)
to dav_hooks_vsn.

git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/trunk@88855 13f79535-47bb-0310-9956-ffa450edef68

modules/dav/main/mod_dav.c
modules/dav/main/mod_dav.h

index bfa8d780296fa230765c07588e333ae25f0c0734..4e4a352cdaeb7b11349360c127826fbc0b781c78 100644 (file)
@@ -357,7 +357,7 @@ static const char *dav_cmd_davparam(cmd_parms *cmd, void *config,
 static int dav_error_response(request_rec *r, int status, const char *body)
 {
     r->status = status;
-    r->status_line = ap_get_status_line(status);
+    r->status_line = ap_get_status_line(status);       /* ### needed? */
     r->content_type = "text/html";
 
     /* since we're returning DONE, ensure the request body is consumed. */
@@ -397,7 +397,7 @@ static const char *dav_xml_escape_uri(apr_pool_t *p, const char *uri)
     if (ap_strchr_c(e_uri, '&') == NULL)
        return e_uri;
 
-    /* more work needed... sigh. */
+    /* there was a '&', so more work is needed... sigh. */
 
     /*
     ** Note: this is a teeny bit of overkill since we know there are no
@@ -4054,8 +4054,137 @@ static int dav_method_baseline_control(request_rec *r)
 
 static int dav_method_merge(request_rec *r)
 {
-    /* ### */
-    return HTTP_METHOD_NOT_ALLOWED;
+    dav_resource *resource;
+    dav_resource *source_resource;
+    const dav_hooks_vsn *vsn_hooks = DAV_GET_HOOKS_VSN(r);
+    dav_error *err;
+    int result;
+    ap_xml_doc *doc;
+    ap_xml_elem *source_elem;
+    ap_xml_elem *href_elem;
+    ap_xml_elem *prop_elem;
+    const char *source;
+    int no_auto_merge;
+    int no_checkout;
+    dav_lookup_result lookup;
+
+    /* If no versioning provider, decline the request */
+    if (vsn_hooks == NULL)
+        return DECLINED;
+
+    if ((result = ap_xml_parse_input(r, &doc)) != OK)
+       return result;
+
+    if (doc == NULL || !dav_validate_root(doc, "merge")) {
+        /* This supplies additional information for the default msg. */
+        ap_log_rerror(APLOG_MARK, APLOG_ERR | APLOG_NOERRNO, 0, r,
+                     "The request body must be present and must be a "
+                     "DAV:merge element.");
+       return HTTP_BAD_REQUEST;
+    }
+
+    if ((source_elem = dav_find_child(doc->root, "source")) == NULL) {
+        /* This supplies additional information for the default msg. */
+        ap_log_rerror(APLOG_MARK, APLOG_ERR | APLOG_NOERRNO, 0, r,
+                     "The DAV:merge element must contain a DAV:source "
+                     "element.");
+       return HTTP_BAD_REQUEST;
+    }
+    if ((href_elem = dav_find_child(source_elem, "href")) == NULL) {
+        /* This supplies additional information for the default msg. */
+        ap_log_rerror(APLOG_MARK, APLOG_ERR | APLOG_NOERRNO, 0, r,
+                     "The DAV:source element must contain a DAV:href "
+                     "element.");
+       return HTTP_BAD_REQUEST;
+    }
+    source = dav_xml_get_cdata(href_elem, r->pool, 1 /* strip_white */);
+
+    /* get a subrequest for the source, so that we can get a dav_resource
+       for that source. */
+    lookup = dav_lookup_uri(source, r);
+    if (lookup.rnew == NULL) {
+        if (lookup.err.status == HTTP_BAD_REQUEST) {
+           /* This supplies additional information for the default message. */
+           ap_log_rerror(APLOG_MARK, APLOG_ERR | APLOG_NOERRNO, 0, r,
+                         lookup.err.desc);
+           return HTTP_BAD_REQUEST;
+       }
+
+       /* ### this assumes that dav_lookup_uri() only generates a status
+        * ### that Apache can provide a status line for!! */
+
+       return dav_error_response(r, lookup.err.status, lookup.err.desc);
+    }
+    if (lookup.rnew->status != HTTP_OK) {
+        /* ### how best to report this... */
+        return dav_error_response(r, lookup.rnew->status,
+                                 "Merge source URI had an error.");
+    }
+    err = dav_get_resource(lookup.rnew, 0 /* label_allowed */,
+                          0 /* use_checked_in */, &source_resource);
+    if (err != NULL)
+        return dav_handle_err(r, err, NULL);
+
+    no_auto_merge = dav_find_child(doc->root, "no-auto-merge") != NULL;
+    no_checkout = dav_find_child(doc->root, "no-checkout") != NULL;
+
+    prop_elem = dav_find_child(doc->root, "prop");
+
+    /* ### check RFC. I believe the DAV:merge element may contain any
+       ### element also allowed within DAV:checkout. need to extract them
+       ### here, and pass them along.
+       ### if so, then refactor the CHECKOUT method handling so we can reuse
+       ### the code. maybe create a structure to hold CHECKOUT parameters
+       ### which can be passed to the checkout() and merge() hooks. */
+
+    /* Ask repository module to resolve the resource */
+    err = dav_get_resource(r, 0 /* label_allowed */, 0 /* use_checked_in */,
+                          &resource);
+    if (err != NULL)
+        return dav_handle_err(r, err, NULL);
+    if (!resource->exists) {
+        /* Apache will supply a default error for this. */
+        return HTTP_NOT_FOUND;
+    }
+
+    /* ### check the source and target resources flags/types */
+
+    /* ### do lock checks, once behavior is defined */
+
+    /* set the Cache-Control header, per the spec */
+    /* ### correct? */
+    apr_table_setn(r->headers_out, "Cache-Control", "no-cache");
+
+    /* Initialize these values for a standard MERGE response. If the MERGE
+       is going to do something different (i.e. an error), then it must
+       return a dav_error, and we'll reset these values properly. */
+    r->status = HTTP_OK;
+    r->status_line = ap_get_status_line(HTTP_OK);      /* ### needed? */
+    r->content_type = "text/xml";
+
+    /* ### should we do any preliminary response generation? probably not,
+       ### because we may have an error, thus demanding something else in
+       ### the response body. */
+
+    /* Do the merge, including any response generation. */
+    if ((err = (*vsn_hooks->merge)(resource, source_resource,
+                                  no_auto_merge, no_checkout,
+                                  prop_elem,
+                                  r->output_filters)) != NULL) {
+        /* ### is err->status the right error here? */
+       err = dav_push_error(r->pool, err->status, 0,
+                            apr_psprintf(r->pool,
+                                         "Could not MERGE resource \"%s\" "
+                                         "into \"%s\".",
+                                         ap_escape_html(r->pool, source),
+                                         ap_escape_html(r->pool, r->uri)),
+                            err);
+        return dav_handle_err(r, err, NULL);
+    }
+
+    /* the response was fully generated by the merge() hook. */
+    /* ### urk. does this prevent logging? need to check... */
+    return DONE;
 }
 
 static int dav_method_bind(request_rec *r)
index 29a2c619b95f493980f453fcd873f71e7223b785..012cee10752b27a739c447656d532629804e0a07 100644 (file)
@@ -65,6 +65,7 @@
 #include "apr_tables.h"
 
 #include "httpd.h"
+#include "util_filter.h"
 #include "util_xml.h"
 
 #include <limits.h>     /* for INT_MAX */
@@ -2112,6 +2113,19 @@ struct dav_hooks_vsn
     ** it should be set to NULL.
     */
     dav_error * (*make_activity)(dav_resource *resource);
+
+    /*
+    ** Merge a resource (tree) into target resource (tree).
+    **
+    ** ### more doc...
+    **
+    ** This hook is optional; if the provider does not support merging,
+    ** then this should be set to NULL.
+    */
+    dav_error * (*merge)(dav_resource *target, dav_resource *source,
+                        int no_auto_merge, int no_checkout,
+                        ap_xml_elem *prop_elem,
+                        ap_filter_t *output);
 };