> If people *really* think that this functionality is needed,
My boss think ;) And I agree with him ;)

> than
> re-using COPY seems to make more sense (we could define a new variant
> that takes a Source header instead of the currently mandatory
> Destination header).
I've attached a path thats allows a COPY of resource to remote server. 
It ignores Overwrite and don't yet check for return values.

It contains two thinks that I would like to get your opinion of:

1. it defines DEBUG_GET_HANDLER so the deliver and set_headers dav hooks 
are defined
comments says that these functions are not properly implemented, could 
someone point me how to implement them properly, so the 
DEBUG_GET_HANDLER think could be finally removed?

2. it removes APACHE_PORT_HANDLING_IS_BUSTED from dav/main/utils.c
this code was added in 2002 to prevent some bug, but for me checking 
ports works ok...

And the question: is there any way to check if destination url points to 
remote server? I'm using servers with different ports, so the port 
checking workd, but what about server-names, ips, aliases and so on?

Best regards
  Rafał Malinowski

----------------------------------------------------
Tysiące pomysłów na urządzanie domu, mieszkania, 
ogrodu w jednym miejscu! 
Zobacz jak mógłbyś zamieszkać.
Kliknij: http://klik.wp.pl/?adr=www.dom.wp.pl&sid=419
diff -bBru httpd-2.2.9-orig/modules/dav/fs/repos.c httpd-2.2.9/modules/dav/fs/repos.c
--- httpd-2.2.9-orig/modules/dav/fs/repos.c	2008-01-02 10:41:46.000000000 +0100
+++ httpd-2.2.9/modules/dav/fs/repos.c	2008-07-17 20:53:48.000000000 +0200
@@ -37,7 +37,7 @@
 
 
 /* to assist in debugging mod_dav's GET handling */
-#define DEBUG_GET_HANDLER       0
+#define DEBUG_GET_HANDLER       1
 
 #define DAV_FS_COPY_BLOCKSIZE   16384   /* copy 16k at a time */
 
diff -bBru httpd-2.2.9-orig/modules/dav/main/mod_dav.c httpd-2.2.9/modules/dav/main/mod_dav.c
--- httpd-2.2.9-orig/modules/dav/main/mod_dav.c	2008-05-27 17:57:23.000000000 +0200
+++ httpd-2.2.9/modules/dav/main/mod_dav.c	2008-07-18 19:22:45.000000000 +0200
@@ -55,6 +55,7 @@
 #include "http_main.h"
 #include "http_protocol.h"
 #include "http_request.h"
+#include "util_ebcdic.h"
 #include "util_script.h"
 
 #include "mod_dav.h"
@@ -829,6 +830,11 @@
         return HTTP_NOT_FOUND;
     }
 
+//	printf("resource: %p\n", resource);
+//	printf("resource hooks: %p\n", resource->hooks);
+//	printf("resource hooks set_headers: %p\n", resource->hooks->set_headers);
+//	printf("resource hooks deliver: %p\n", resource->hooks->deliver);
+
     /* set up the HTTP headers for the response */
     if ((err = (*resource->hooks->set_headers)(r, resource)) != NULL) {
         err = dav_push_error(r->pool, err->status, 0,
@@ -2550,6 +2556,202 @@
     return dav_created(r, NULL, "Collection", 0);
 }
 
+DAV_DECLARE(dav_error *) dav_remote_copymove_create_socket(apr_pool_t *p, apr_sockaddr_t *addr, apr_socket_t **newsock)
+{
+	apr_status_t rv;
+
+	while (addr) {
+        if ((rv = apr_socket_create(newsock, addr->family,
+                                    SOCK_STREAM, 0, p)) != APR_SUCCESS) {
+            /*
+             * this could be an IPv6 address from the DNS but the
+             * local machine won't give us an IPv6 socket; hopefully the
+             * DNS returned an additional address to try
+             */
+            addr = addr->next;
+            continue;
+        }
+
+        rv = apr_socket_connect(*newsock, addr);
+
+        /* if an error occurred, loop round and try again */
+        if (rv != APR_SUCCESS) {
+            apr_socket_close(*newsock);
+            addr = addr->next;
+            continue;
+        }
+
+        return 0;
+	}
+
+	// TODO: good error code?
+	return dav_new_error(p, HTTP_INTERNAL_SERVER_ERROR, 0, "Socket creating failed");
+}
+
+DAV_DECLARE(dav_error *) dav_remote_copymove_create_connection(apr_pool_t *p, apr_uri_t *uri, server_rec *s, conn_rec **conn)
+{
+	apr_status_t rv;
+	apr_sockaddr_t *src_addr;
+	apr_socket_t *socket;
+	dav_error *err;
+
+	rv = apr_sockaddr_info_get(&src_addr, uri->hostname, APR_UNSPEC, uri->port, 0, p);
+    if (APR_SUCCESS != rv) {
+        return dav_new_error(p, HTTP_BAD_REQUEST, 0, apr_pstrcat(p, "DNS lookup failure for: ", uri->hostname, NULL));
+    }
+
+	err = dav_remote_copymove_create_socket(p, src_addr, &socket);
+	if (NULL != err) {
+		return err;
+	}
+
+	*conn = (conn_rec *)ap_run_create_connection(p, s, socket, 0, NULL, apr_bucket_alloc_create(p));
+
+	if (!*conn) {
+		// will it have memory to create error message? i guess not, let the caller check!
+		return 0;
+	}
+
+    /* set up the connection filters */
+    rv = ap_run_pre_connection(*conn, socket);
+    if (rv != OK && rv != DONE) {
+        (*conn)->aborted = 1;
+        return dav_new_error(p, HTTP_INTERNAL_SERVER_ERROR, 0, "pre_connection setup failed");
+    }
+
+	return 0;
+}
+
+void dav_remote_copymove_make_fake_request(conn_rec *conn, request_rec *r, request_rec **rp)
+{
+	(*rp) = apr_pcalloc(r->pool, sizeof(*r));
+
+    (*rp)->pool            = r->pool;
+    (*rp)->status          = HTTP_OK;
+
+    (*rp)->headers_in      = apr_table_make(r->pool, 12);
+    (*rp)->subprocess_env  = apr_table_make(r->pool, 12);
+    (*rp)->headers_out     = apr_table_make(r->pool, 12);
+    (*rp)->err_headers_out = apr_table_make(r->pool, 5);
+    (*rp)->notes           = apr_table_make(r->pool, 5);
+
+    (*rp)->server = r->server;
+    (*rp)->proxyreq = r->proxyreq;
+    (*rp)->request_time = r->request_time;
+    (*rp)->connection      = conn;
+    (*rp)->output_filters  = conn->output_filters;
+    (*rp)->input_filters   = conn->input_filters;
+    (*rp)->proto_output_filters  = conn->output_filters;
+    (*rp)->proto_input_filters   = conn->input_filters;
+
+    (*rp)->request_config = ap_create_request_config(r->pool);
+    (*rp)->per_dir_config = r->per_dir_config; // hope it will not crash
+}
+
+DAV_DECLARE(dav_error *) dav_remote_copymove_send_headers(request_rec *r, dav_resource *resource, apr_uri_t *uri)
+{
+    apr_status_t rv;
+    dav_error *err;
+    apr_bucket_alloc_t *bucket_alloc = r->connection->bucket_alloc;
+    apr_bucket_brigade *request_brigade;
+    apr_bucket *e;
+	char *buf;
+
+	// as I see nobody in httpd check for NULL results of malloc/apr_palloc, so why I should?
+    request_brigade = apr_brigade_create(r->pool, bucket_alloc);
+
+	buf = apr_pstrcat(r->pool, "PUT", " ", uri->path, " HTTP/1.1", CRLF, NULL);
+	e = apr_bucket_pool_create(buf, strlen(buf), r->pool, bucket_alloc);
+	ap_xlate_proto_to_ascii(buf, strlen(buf));
+	APR_BRIGADE_INSERT_TAIL(request_brigade, e);
+
+	buf = apr_pstrcat(r->pool, "Host: ", uri->hostname, CRLF, NULL);
+	e = apr_bucket_pool_create(buf, strlen(buf), r->pool, bucket_alloc);
+	ap_xlate_proto_to_ascii(buf, strlen(buf));
+	APR_BRIGADE_INSERT_TAIL(request_brigade, e);
+
+    /* set up the HTTP headers for the response */
+    if ((err = (*resource->hooks->set_headers)(r, resource)) != NULL) {
+        return dav_push_error(r->pool, err->status, 0,
+                             "Unable to set up HTTP headers.",
+                             err);
+    }
+
+    // only need Content-Length header now
+	buf = apr_pstrcat(r->pool, "Content-Length: ", apr_table_get(r->headers_out, "Content-Length"), CRLF, CRLF, NULL);
+	e = apr_bucket_pool_create(buf, strlen(buf), r->pool, bucket_alloc);
+	ap_xlate_proto_to_ascii(buf, strlen(buf));
+	APR_BRIGADE_INSERT_TAIL(request_brigade, e);
+
+	rv = ap_pass_brigade(r->output_filters, request_brigade);
+//	apr_brigade_cleanup(request_brigade);
+
+	if (rv != APR_SUCCESS) {
+		return dav_new_error(r->pool, HTTP_INTERNAL_SERVER_ERROR, 0, "Sending request failed");
+	}
+
+	return 0;
+}
+
+DAV_DECLARE(dav_error *) dav_remote_copymove_send_content(request_rec *r, dav_resource *resource)
+{
+	dav_error *err;
+
+    /* okay... time to deliver the content */
+    if ((err = (*resource->hooks->deliver)(resource,
+                                           r->output_filters)) != NULL) {
+        return dav_push_error(r->pool, err->status, 0,
+                             "Unable to deliver content.",
+                             err);
+    }
+
+    return NULL;
+}
+
+static int dav_remote_copymove(request_rec *r, dav_resource *resource, const char *dest, int is_move)
+{
+	dav_error *err;
+	apr_uri_t dest_uri;
+	conn_rec *conn;
+    request_rec *rp;
+
+    if (APR_SUCCESS != apr_uri_parse(r->pool, dest, &dest_uri)) {
+        ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
+                      "Destination URI cannot be parsed.", NULL);
+    	return HTTP_BAD_REQUEST;
+    }
+
+    if (!dest_uri.port) {
+    	dest_uri.port = apr_uri_port_of_scheme(dest_uri.scheme);
+    }
+
+    // TODO: check overwrite, use propfind ??
+
+    // 1. create connection
+    if ((err = dav_remote_copymove_create_connection(r->pool, &dest_uri, r->server, &conn)) != NULL) {
+        return dav_handle_err(r, err, NULL);
+    }
+
+    // 2. create request
+    dav_remote_copymove_make_fake_request(conn, r, &rp);
+
+    // 3. send headers
+    if ((err = dav_remote_copymove_send_headers(rp, resource, &dest_uri)) != NULL) {
+        return dav_handle_err(r, err, NULL);
+    }
+
+    // 4. send content
+    if ((err = dav_remote_copymove_send_content(rp, resource)) != NULL) {
+        return dav_handle_err(r, err, NULL);
+    }
+
+//    if ((err = dav_remote_copymove_read_status_line(rp->pool, rp)) != NULL) {
+//    	return dav_handle_err(r, err, NULL);
+//    }
+
+	return HTTP_NO_CONTENT;
+}
+
 /* handle the COPY and MOVE methods */
 static int dav_method_copymove(request_rec *r, int is_move)
 {
@@ -2618,6 +2820,12 @@
             return HTTP_BAD_REQUEST;
         }
 
+        if (!is_move && lookup.err.status == HTTP_BAD_GATEWAY) {
+            err = dav_get_resource(r, 1 /* label_allowed */, 0 /* use_checked_in */,
+                                   &resource);
+        	return dav_remote_copymove(r, resource, dest, is_move);
+        }
+
         /* ### this assumes that dav_lookup_uri() only generates a status
          * ### that Apache can provide a status line for!! */
 
@@ -2650,13 +2859,11 @@
         return dav_handle_err(r, err, NULL);
 
     /* are the two resources handled by the same repository? */
-    if (resource->hooks != resnew->hooks) {
+    if (!is_move && resource->hooks != resnew->hooks) {
+        err = dav_get_resource(r, 1 /* label_allowed */, 0 /* use_checked_in */,
+                               &resource);
         /* ### this message exposes some backend config, but screw it... */
-        return dav_error_response(r, HTTP_BAD_GATEWAY,
-                                  "Destination URI is handled by a "
-                                  "different repository than the source URI. "
-                                  "MOVE or COPY between repositories is "
-                                  "not possible.");
+    	return dav_remote_copymove(r, resource, dest, is_move);
     }
 
     /* get and parse the overwrite header value */
diff -bBru httpd-2.2.9-orig/modules/dav/main/util.c httpd-2.2.9/modules/dav/main/util.c
--- httpd-2.2.9-orig/modules/dav/main/util.c	2008-01-05 10:45:07.000000000 +0100
+++ httpd-2.2.9/modules/dav/main/util.c	2008-07-17 19:19:19.000000000 +0200
@@ -216,10 +216,9 @@
            request. the port must match our port.
         */
         port = r->connection->local_addr->port;
+
         if (strcasecmp(comp.scheme, scheme) != 0
-#ifdef APACHE_PORT_HANDLING_IS_BUSTED
             || comp.port != port
-#endif
             ) {
             result.err.status = HTTP_BAD_GATEWAY;
             result.err.desc = apr_psprintf(r->pool,

Reply via email to