> 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,