View | Details | Raw Unified | Return to bug 45449
Collapse All | Expand All

(-)httpd-2.2.9-orig/modules/dav/fs/repos.c (-1 / +1 lines)
Lines 37-43 Link Here
37
37
38
38
39
/* to assist in debugging mod_dav's GET handling */
39
/* to assist in debugging mod_dav's GET handling */
40
#define DEBUG_GET_HANDLER       0
40
#define DEBUG_GET_HANDLER       1
41
41
42
#define DAV_FS_COPY_BLOCKSIZE   16384   /* copy 16k at a time */
42
#define DAV_FS_COPY_BLOCKSIZE   16384   /* copy 16k at a time */
43
43
(-)httpd-2.2.9-orig/modules/dav/main/mod_dav.c (-18 / +770 lines)
Lines 55-60 Link Here
55
#include "http_main.h"
55
#include "http_main.h"
56
#include "http_protocol.h"
56
#include "http_protocol.h"
57
#include "http_request.h"
57
#include "http_request.h"
58
#include "util_ebcdic.h"
58
#include "util_script.h"
59
#include "util_script.h"
59
60
60
#include "mod_dav.h"
61
#include "mod_dav.h"
Lines 103-108 Link Here
103
};
104
};
104
static int dav_methods[DAV_M_LAST];
105
static int dav_methods[DAV_M_LAST];
105
106
107
typedef struct
108
{
109
	char *token;
110
	char *path;
111
} dav_remote_lock_token;
106
112
107
static int dav_init_handler(apr_pool_t *p, apr_pool_t *plog, apr_pool_t *ptemp,
113
static int dav_init_handler(apr_pool_t *p, apr_pool_t *plog, apr_pool_t *ptemp,
108
                             server_rec *s)
114
                             server_rec *s)
Lines 2550-2555 Link Here
2550
    return dav_created(r, NULL, "Collection", 0);
2556
    return dav_created(r, NULL, "Collection", 0);
2551
}
2557
}
2552
2558
2559
// copied from mod_proxy - maybe add to core or lib?
2560
DAV_DECLARE(dav_error *) dav_remote_copymove_create_socket(apr_pool_t *p, apr_sockaddr_t *addr, apr_socket_t **newsock)
2561
{
2562
	apr_status_t rv;
2563
2564
	while (addr) {
2565
        if ((rv = apr_socket_create(newsock, addr->family,
2566
                                    SOCK_STREAM, 0, p)) != APR_SUCCESS) {
2567
            /*
2568
             * this could be an IPv6 address from the DNS but the
2569
             * local machine won't give us an IPv6 socket; hopefully the
2570
             * DNS returned an additional address to try
2571
             */
2572
            addr = addr->next;
2573
            continue;
2574
        }
2575
2576
        rv = apr_socket_connect(*newsock, addr);
2577
2578
        /* if an error occurred, loop round and try again */
2579
        if (rv != APR_SUCCESS) {
2580
            apr_socket_close(*newsock);
2581
            addr = addr->next;
2582
            continue;
2583
        }
2584
2585
        return 0;
2586
	}
2587
2588
	return dav_new_error(p, HTTP_INTERNAL_SERVER_ERROR, 0, "Socket creating failed");
2589
}
2590
2591
DAV_DECLARE(dav_error *) dav_remote_create_connection(apr_pool_t *p, apr_uri_t *uri, server_rec *s, conn_rec **conn)
2592
{
2593
	apr_status_t rv;
2594
	apr_sockaddr_t *src_addr;
2595
	apr_socket_t *socket;
2596
	dav_error *err;
2597
2598
	rv = apr_sockaddr_info_get(&src_addr, uri->hostname, APR_UNSPEC, uri->port, 0, p);
2599
    if (APR_SUCCESS != rv) {
2600
        return dav_new_error(p, HTTP_BAD_REQUEST, 0, apr_pstrcat(p, "DNS lookup failure for: ", uri->hostname, NULL));
2601
    }
2602
2603
	if (NULL != (err = dav_remote_copymove_create_socket(p, src_addr, &socket))) {
2604
		return err;
2605
	}
2606
2607
	*conn = (conn_rec *)ap_run_create_connection(p, s, socket, 0, NULL, apr_bucket_alloc_create(p));
2608
2609
	if (!*conn) {
2610
		// will it have memory to create error message? i guess not, let the caller check!
2611
		return 0;
2612
	}
2613
2614
    /* set up the connection filters */
2615
    rv = ap_run_pre_connection(*conn, socket);
2616
    if (rv != OK && rv != DONE) {
2617
        (*conn)->aborted = 1;
2618
        return dav_new_error(p, HTTP_INTERNAL_SERVER_ERROR, 0, "pre_connection setup failed");
2619
    }
2620
2621
	return 0;
2622
}
2623
2624
DAV_DECLARE(dav_error *) dav_remote_close_connection(request_rec *r)
2625
{
2626
	// TODO: find a better way to do it
2627
	r->connection = 0;
2628
}
2629
2630
DAV_DECLARE(request_rec *) dav_remote_make_fake_request(request_rec *r)
2631
{
2632
	request_rec *rp = apr_pcalloc(r->pool, sizeof(*r));
2633
2634
    rp->pool            = r->pool;
2635
    rp->status          = HTTP_OK;
2636
2637
    rp->headers_in      = apr_table_make(r->pool, 12);
2638
    rp->subprocess_env  = apr_table_make(r->pool, 12);
2639
    rp->headers_out     = apr_table_make(r->pool, 12);
2640
    rp->err_headers_out = apr_table_make(r->pool, 5);
2641
    rp->notes           = apr_table_make(r->pool, 5);
2642
2643
    rp->server = r->server;
2644
    rp->proxyreq = r->proxyreq;
2645
    rp->request_time = r->request_time;
2646
2647
    rp->connection = 0;
2648
2649
    // TODO: is it ok to do that?
2650
    rp->request_config = r->request_config;
2651
    rp->per_dir_config = r->per_dir_config;
2652
}
2653
2654
DAV_DECLARE(dav_error *) dav_remote_set_connection(request_rec *r, apr_uri_t *resource_uri)
2655
{
2656
	dav_error *err;
2657
	conn_rec *conn;
2658
2659
	if (r->connection && !r->connection->aborted && (r->connection->keepalive == AP_CONN_KEEPALIVE)) {
2660
		return 0;
2661
	}
2662
2663
	if (NULL != (err = dav_remote_create_connection(r->pool, resource_uri, r->server, &conn))) {
2664
		return err;
2665
	}
2666
2667
	conn->keepalive = AP_CONN_KEEPALIVE;
2668
2669
	r->connection      = conn;
2670
	r->output_filters  = conn->output_filters;
2671
	r->input_filters   = conn->input_filters;
2672
	r->proto_output_filters  = conn->output_filters;
2673
	r->proto_input_filters   = conn->input_filters;
2674
2675
	return 0;
2676
}
2677
2678
DAV_DECLARE(dav_error *) dav_remote_send_resource_content(request_rec *r, const dav_resource *resource)
2679
{
2680
	dav_error *err;
2681
	apr_bucket_brigade *request_brigade;
2682
	apr_bucket *e;
2683
	apr_status_t rv;
2684
2685
    /* okay... time to deliver the content */
2686
    if ((err = (*resource->hooks->deliver)(resource,
2687
                                           r->output_filters)) != NULL) {
2688
        return dav_push_error(r->pool, err->status, 0,
2689
                             "Unable to deliver content.",
2690
                             err);
2691
    }
2692
2693
	request_brigade =  apr_brigade_create(r->pool, r->connection->bucket_alloc);
2694
2695
	e = apr_bucket_flush_create(r->connection->bucket_alloc);
2696
	APR_BRIGADE_INSERT_TAIL(request_brigade, e);
2697
2698
    if (APR_SUCCESS != (rv = ap_pass_brigade(r->output_filters, request_brigade)))
2699
    	return dav_new_error(r->pool, HTTP_INTERNAL_SERVER_ERROR, 0, "Sending content failed");
2700
    else
2701
    	return NULL;
2702
}
2703
2704
DAV_DECLARE(dav_error *) dav_remote_send_string(request_rec *r, const char *string)
2705
{
2706
	dav_error *err;
2707
	apr_bucket_brigade *request_brigade;
2708
	apr_bucket *e;
2709
	apr_status_t rv;
2710
2711
	request_brigade =  apr_brigade_create(r->pool, r->connection->bucket_alloc);
2712
2713
	e = apr_bucket_pool_create(string, strlen(string), r->pool, r->connection->bucket_alloc);
2714
	ap_xlate_proto_to_ascii(string, strlen(string));
2715
	APR_BRIGADE_INSERT_TAIL(request_brigade, e);
2716
2717
	e = apr_bucket_flush_create(r->connection->bucket_alloc);
2718
	APR_BRIGADE_INSERT_TAIL(request_brigade, e);
2719
2720
    if (APR_SUCCESS != (rv = ap_pass_brigade(r->output_filters, request_brigade)))
2721
    	return dav_new_error(r->pool, HTTP_INTERNAL_SERVER_ERROR, 0, "Sending content failed");
2722
    else
2723
    	return NULL;
2724
}
2725
2726
struct dav_remote_send_headers_wrapper {
2727
	apr_bucket_alloc_t *bucket_alloc;
2728
	apr_bucket_brigade *request_brigade;
2729
	apr_pool_t *p;
2730
};
2731
2732
int dav_remote_send_header(void *rec, const char *key, const char *value)
2733
{
2734
	struct dav_remote_send_headers_wrapper *wrapper = (struct dav_remote_send_headers_wrapper *)rec;
2735
2736
	apr_bucket_brigade *request_brigade = wrapper->request_brigade;
2737
	apr_bucket *e;
2738
	char *buf;
2739
2740
	buf = apr_pstrcat(wrapper->p, key, ": ", value, CRLF, NULL);
2741
	e = apr_bucket_pool_create(buf, strlen(buf), wrapper->p, wrapper->bucket_alloc);
2742
	ap_xlate_proto_to_ascii(buf, strlen(buf));
2743
	APR_BRIGADE_INSERT_TAIL(request_brigade, e);
2744
}
2745
2746
DAV_DECLARE(dav_error *) dav_remote_read_status_line(request_rec *r)
2747
{
2748
    apr_bucket_brigade *response_brigade;
2749
2750
    char buff[HUGE_STRING_LEN];
2751
	char *buff_p = buff;
2752
	char keepchar;
2753
	apr_size_t len;
2754
2755
    response_brigade = apr_brigade_create(r->pool, r->connection->bucket_alloc);
2756
    ap_rgetline(&buff_p, sizeof(buff), &len, r, 0, response_brigade);
2757
2758
    if (!apr_date_checkmask(buff, "HTTP/#.# ###*")) {
2759
    	return dav_new_error(r->pool, HTTP_BAD_GATEWAY, 0, "Invalid response status line");
2760
    }
2761
2762
    int major, minor;
2763
2764
    if (2 != sscanf(buff, "HTTP/%u.%u", &major, &minor)) {
2765
        major = 1;
2766
        minor = 1;
2767
    }
2768
    else if ((buff[5] != '1') || (len >= sizeof(buff) - 1)) {
2769
        return dav_new_error(r->pool, HTTP_BAD_GATEWAY, 0, "Invalid response status line");
2770
    }
2771
2772
    keepchar = buff[12];
2773
    buff[12] = '\0';
2774
    r->status = atoi(&buff[9]);
2775
2776
    if (keepchar != '\0') {
2777
     	buff[12] = keepchar;
2778
    } else {
2779
        /* 2616 requires the space in Status-Line; the origin
2780
         * server may have sent one but ap_rgetline_core will
2781
         * have stripped it. */
2782
    	buff[12] = ' ';
2783
        buff[13] = '\0';
2784
    }
2785
    r->status_line = apr_pstrdup(r->pool, &buff[9]);
2786
2787
    return 0;
2788
}
2789
2790
DAV_DECLARE(dav_error *) dav_remote_read_response_headers(request_rec *r)
2791
{
2792
	dav_error *err;
2793
    apr_bucket_brigade *response_brigade;
2794
	apr_size_t len;
2795
	apr_status_t rv;
2796
    char buff[HUGE_STRING_LEN];
2797
	char *buff_p = buff;
2798
	char *value, *end;
2799
2800
	apr_table_clear(r->headers_in);
2801
2802
	response_brigade = apr_brigade_create(r->pool, r->connection->bucket_alloc);
2803
    if (APR_SUCCESS != (rv = ap_rgetline(&buff_p, sizeof(buff), &len, r, 0, response_brigade))) {
2804
    	return dav_new_error(r->pool, HTTP_BAD_GATEWAY, 0, "Error reading response header");
2805
    }
2806
2807
    while (0 < len) {
2808
    	if (!(value = strchr(buff, ':'))) {
2809
    	    if (APR_SUCCESS != (rv = ap_rgetline(&buff_p, sizeof(buff), &len, r, 0, response_brigade))) {
2810
    	    	return dav_new_error(r->pool, HTTP_BAD_GATEWAY, 0, "Error reading response header");
2811
    	    }
2812
    	}
2813
2814
        *value = '\0';
2815
        ++value;
2816
        /* XXX: RFC2068 defines only SP and HT as whitespace, this test is
2817
         * wrong... and so are many others probably.
2818
         */
2819
        while (apr_isspace(*value))
2820
            ++value;            /* Skip to start of value   */
2821
2822
        /* should strip trailing whitespace as well */
2823
        for (end = &value[strlen(value)-1]; end > value && apr_isspace(*end); --end)
2824
            *end = '\0';
2825
2826
        apr_table_add(r->headers_in, buff, value);
2827
2828
	    if (APR_SUCCESS != (rv = ap_rgetline(&buff_p, sizeof(buff), &len, r, 0, response_brigade))) {
2829
	    	return dav_new_error(r->pool, HTTP_BAD_GATEWAY, 0, "Error reading response header");
2830
	    }
2831
    }
2832
2833
    return 0;
2834
}
2835
2836
typedef DAV_DECLARE(dav_error *) (* write_request_content_callback) (request_rec *, void *data);
2837
typedef DAV_DECLARE(dav_error *) (* read_reponse_content_callback) (request_rec *, void *data);
2838
2839
DAV_DECLARE(dav_error *) dav_remote_skip_response_content(request_rec *r, void *unused)
2840
{
2841
	if (APR_SUCCESS != ap_discard_request_body(r))
2842
		return dav_new_error(r->pool, HTTP_INTERNAL_SERVER_ERROR, 0, "Error during discarding response body");
2843
2844
	return NULL;
2845
}
2846
2847
DAV_DECLARE(dav_error *) dav_remote_method_request(request_rec *r, const char *method, apr_uri_t *resource_uri,
2848
		const char *resource_path, const dav_resource *resource,
2849
		write_request_content_callback write_request_content, void *write_request_content_data,
2850
		read_reponse_content_callback read_response_content, void *read_response_content_data)
2851
{
2852
    apr_status_t rv;
2853
    dav_error *err;
2854
    apr_bucket_alloc_t *bucket_alloc = r->connection->bucket_alloc;
2855
    apr_bucket_brigade *request_brigade;
2856
    apr_bucket *e;
2857
    ap_filter_t *http_in_filter;
2858
	char *buf;
2859
2860
	// as I see nobody in httpd check for NULL results of malloc/apr_palloc, so why I should?
2861
    request_brigade = apr_brigade_create(r->pool, bucket_alloc);
2862
2863
    // request line
2864
	buf = apr_pstrcat(r->pool, method, " ", resource_uri->path, " HTTP/1.1", CRLF, NULL);
2865
	e = apr_bucket_pool_create(buf, strlen(buf), r->pool, bucket_alloc);
2866
	ap_xlate_proto_to_ascii(buf, strlen(buf));
2867
	APR_BRIGADE_INSERT_TAIL(request_brigade, e);
2868
2869
	// headers
2870
	struct dav_remote_send_headers_wrapper wrapper;
2871
	wrapper.bucket_alloc = bucket_alloc;
2872
	wrapper.request_brigade = request_brigade;
2873
	wrapper.p = r->pool;
2874
2875
	apr_table_do(dav_remote_send_header, &wrapper, r->headers_out, 0);
2876
2877
	// empty line after headers
2878
	buf = apr_pstrcat(r->pool, CRLF, NULL);
2879
	e = apr_bucket_pool_create(buf, strlen(buf), r->pool, bucket_alloc);
2880
	ap_xlate_proto_to_ascii(buf, strlen(buf));
2881
	APR_BRIGADE_INSERT_TAIL(request_brigade, e);
2882
2883
	e = apr_bucket_flush_create(bucket_alloc);
2884
	APR_BRIGADE_INSERT_TAIL(request_brigade, e);
2885
2886
	// send it now
2887
    rv = ap_pass_brigade(r->output_filters, request_brigade);
2888
2889
	if (rv != APR_SUCCESS) {
2890
		return dav_new_error(r->pool, HTTP_INTERNAL_SERVER_ERROR, 0, "Sending request failed");
2891
	}
2892
2893
    // for PUT requests
2894
    if (NULL != write_request_content) {
2895
    	if (NULL != (err = write_request_content(r, write_request_content_data))) {
2896
    		return dav_push_error(r->pool, err->status, 0,
2897
    				apr_pstrcat(r->pool, "Could not write request for ", method, " for ", resource_path, NULL), err);
2898
    	}
2899
    }
2900
2901
	if (NULL != (err = dav_remote_read_status_line(r))) {
2902
		return dav_push_error(r->pool, err->status, 0,
2903
				apr_pstrcat(r->pool, "Could not read status for ", method, " for ", resource_path, NULL), err);
2904
	}
2905
2906
	if (NULL != (err = dav_remote_read_response_headers(r))) {
2907
		return dav_push_error(r->pool, err->status, 0,
2908
				apr_pstrcat(r->pool, "Could not read response headers for ", method, " for ", resource_path, NULL), err);
2909
	}
2910
2911
	http_in_filter = ap_add_input_filter("HTTP_IN", NULL, r, r->connection);
2912
2913
	if (NULL == read_response_content) {
2914
		read_response_content = dav_remote_skip_response_content;
2915
	}
2916
2917
	if (NULL != (err = read_response_content(r, read_response_content_data))) {
2918
		return dav_push_error(r->pool, err->status, 0,
2919
				apr_pstrcat(r->pool, "Could not read response content for ", method, " for ", resource_path, NULL), err);
2920
	}
2921
2922
	ap_remove_input_filter(http_in_filter);
2923
2924
	// MOVED PERMANENTLY - check with '/' at the end
2925
	if ((r->status == HTTP_MOVED_PERMANENTLY) && (resource_uri->path[strlen(resource_uri->path) - 1] != '/')) {
2926
		apr_uri_t *resource_with_slash_uri = apr_palloc(r->pool, sizeof(apr_uri_t));
2927
2928
		resource_path = apr_pstrcat(r->pool, resource_path, "/", NULL);
2929
		// TODO: do something with it
2930
		if (strcmp(resource_path, apr_table_get(r->headers_in, "Location")) != 0) {
2931
			return dav_new_error(r->pool, HTTP_INTERNAL_SERVER_ERROR, 0, "No idea what to do...");
2932
		}
2933
2934
		*resource_with_slash_uri = *resource_uri;
2935
		resource_with_slash_uri->path = apr_pstrcat(r->pool, resource_uri->path, "/", NULL);
2936
2937
		return dav_remote_method_request(r, method, resource_with_slash_uri, resource_path, resource, NULL, NULL, NULL, NULL);
2938
	}
2939
2940
	return NULL;
2941
}
2942
2943
DAV_DECLARE(dav_error *) dav_remote_resource_exists(request_rec *r, apr_uri_t *resource_uri,
2944
		const char *resource_path, const dav_resource *resource, int *exists)
2945
{
2946
	dav_error *err;
2947
2948
	*exists = 0;
2949
2950
	if (NULL != (err = dav_remote_set_connection(r, resource_uri))) {
2951
		return dav_push_error(r->pool, err->status, 0, "Unable to create connection in dav_remote_resource_exists.", err);
2952
	}
2953
2954
	apr_table_clear(r->headers_out);
2955
	apr_table_add(r->headers_out, "Host", resource_uri->hostname);
2956
	apr_table_add(r->headers_out, "Content-Length", "0");
2957
	apr_table_add(r->headers_out, "Depth", "0");
2958
	apr_table_add(r->headers_out, "Connection", "Keep-Alive");
2959
2960
	if (NULL != (err = dav_remote_method_request(r, "HEAD", resource_uri, resource_path,
2961
			resource,
2962
			NULL, NULL,
2963
			NULL, NULL))) {
2964
		return dav_push_error(r->pool, err->status, 0, "HEAD in dav_remote_resource_exists failed.", err);
2965
	}
2966
2967
	*exists = r->status != 404;
2968
	return NULL;
2969
}
2970
2971
DAV_DECLARE(dav_error *) dav_remote_resource_delete(request_rec *r, apr_uri_t *resource_uri,
2972
		const char *resource_path, const dav_resource *resource)
2973
{
2974
	dav_error *err;
2975
2976
	if (NULL != (err = dav_remote_set_connection(r, resource_uri))) {
2977
		return dav_push_error(r->pool, err->status, 0, "Unable to create connection in dav_remote_resource_delete.", err);
2978
	}
2979
2980
	apr_table_clear(r->headers_out);
2981
	apr_table_add(r->headers_out, "Host", resource_uri->hostname);
2982
	apr_table_add(r->headers_out, "Content-Length", "0");
2983
	apr_table_add(r->headers_out, "Connection", "Keep-Alive");
2984
2985
	if (NULL != (err = dav_remote_method_request(r, "DELETE", resource_uri, resource_path, resource, NULL, NULL, NULL, NULL))) {
2986
		return dav_push_error(r->pool, err->status, 0, "DELETE in dav_remote_resource_delete failed.", err);
2987
	}
2988
2989
	if (r->status == 200 || r->status == 202 || r->status == 204 || r->status == 404)
2990
		return NULL;
2991
	else
2992
		return dav_new_error(r->pool, r->status, 0, "DELETE refused by remote server");
2993
}
2994
2995
DAV_DECLARE(dav_error *) dav_remote_resource_mkcol(request_rec *r, apr_uri_t *resource_uri,
2996
		const char *resource_path, const dav_resource *resource, int overwrite, dav_remote_lock_token token)
2997
{
2998
	dav_error *err;
2999
3000
	if (NULL != (err = dav_remote_set_connection(r, resource_uri))) {
3001
		return dav_push_error(r->pool, err->status, 0, "Unable to create connection in dav_remote_resource_delete.", err);
3002
	}
3003
3004
	apr_table_clear(r->headers_out);
3005
	apr_table_add(r->headers_out, "Host", resource_uri->hostname);
3006
	apr_table_add(r->headers_out, "Content-Length", "0");
3007
	apr_table_add(r->headers_out, "Connection", "Keep-Alive");
3008
3009
	if (!overwrite) {
3010
		apr_table_add(r->headers_out, "If-None-Match", "*");
3011
	}
3012
3013
	if (token.token && token.path) {
3014
		apr_table_add(r->headers_out, "If", apr_pstrcat(r->pool, "<", token.path, "> (", token.token, ")", NULL));
3015
	}
3016
3017
	if (NULL != (err = dav_remote_method_request(r, "MKCOL", resource_uri, resource_path, resource, NULL, NULL, NULL, NULL))) {
3018
		return dav_push_error(r->pool, err->status, 0, "MKCOL in dav_remote_resource_mkcol failed.", err);
3019
	}
3020
3021
	if (r->status != 201)
3022
		return dav_new_error(r->pool, r->status, 0, "Remote server refused to make collection");
3023
	else
3024
		return NULL;
3025
}
3026
3027
DAV_DECLARE(dav_error *) dav_remote_resource_put(request_rec *r, apr_uri_t *resource_uri,
3028
		const char *resource_path, const dav_resource *resource, int overwrite, dav_remote_lock_token token)
3029
{
3030
	dav_error *err;
3031
3032
	if (NULL != (err = dav_remote_set_connection(r, resource_uri))) {
3033
		return dav_push_error(r->pool, err->status, 0, "Unable to create connection in dav_remote_resource_delete.", err);
3034
	}
3035
3036
	apr_table_clear(r->headers_out);
3037
	apr_table_add(r->headers_out, "Host", resource_uri->hostname);
3038
	apr_table_add(r->headers_out, "Connection", "Keep-Alive");
3039
3040
	if (!overwrite) {
3041
		apr_table_add(r->headers_out, "If-None-Match", "*");
3042
	}
3043
3044
	if (token.token && token.path) {
3045
		apr_table_add(r->headers_out, "If", apr_pstrcat(r->pool, "<", token.path, "> (", token.token, ")", NULL));
3046
	}
3047
3048
    if ((err = (*resource->hooks->set_headers)(r, resource)) != NULL) {
3049
        return dav_push_error(r->pool, err->status, 0,
3050
                             "Unable to set up HTTP headers.",
3051
                             err);
3052
    }
3053
3054
    apr_table_unset(r->headers_out, "Accept-Ranges");
3055
    apr_table_unset(r->headers_out, "ETag");
3056
3057
	if (NULL != (err = dav_remote_method_request(r, "PUT", resource_uri, resource_path, resource,
3058
			dav_remote_send_resource_content, (void *)resource,
3059
			NULL, NULL))) {
3060
		return dav_push_error(r->pool, err->status, 0, "DELETE in dav_remote_resource_delete failed.", err);
3061
	}
3062
3063
	if (r->status != 201 && r->status != 204)
3064
		return dav_new_error(r->pool, r->status, 0, "Remote server does not accept resource");
3065
	else
3066
		return NULL;
3067
}
3068
3069
DAV_DECLARE(dav_error *) dav_remote_resource_lock(request_rec *r, apr_uri_t *resource_uri,
3070
		const char *resource_path, const dav_resource *resource, const char *owner, dav_remote_lock_token *token)
3071
{
3072
	dav_error *err;
3073
	char *content;
3074
	apr_xml_doc *xmlDoc;
3075
3076
	token->token = NULL;
3077
	token->path = NULL;
3078
3079
	if (NULL != (err = dav_remote_set_connection(r, resource_uri))) {
3080
		return dav_push_error(r->pool, err->status, 0, "Unable to create connection in dav_remote_resource_delete.", err);
3081
	}
3082
3083
	// create LOCK request
3084
	content = apr_pstrcat(r->pool,
3085
			"<?xml version=\"1.0\" encoding=\"utf-8\" ?>\n"
3086
			"<D:lockinfo xmlns:D='DAV:'>\n"
3087
			"  <D:lockscope><D:exclusive/></D:lockscope>\n"
3088
			"  <D:locktype><D:write/></D:locktype>\n"
3089
			"  <D:owner>\n"
3090
			"       <D:href>", owner, "</D:href>\n"
3091
			"  </D:owner>\n"
3092
			"</D:lockinfo>",
3093
			NULL
3094
	);
3095
3096
	apr_table_clear(r->headers_out);
3097
	apr_table_add(r->headers_out, "Host", resource_uri->hostname);
3098
	apr_table_add(r->headers_out, "Content-Type", "text/xml; charset=\"utf-8\"");
3099
	apr_table_add(r->headers_out, "Content-Length", apr_itoa(r->pool, strlen(content)));
3100
	apr_table_add(r->headers_out, "Connection", "Keep-Alive");
3101
	apr_table_add(r->headers_out, "Depth", "Infinity");
3102
	// only LOCK null resources
3103
	apr_table_add(r->headers_out, "If-None-Match", "*");
3104
3105
	if (NULL != (err = dav_remote_method_request(r, "LOCK", resource_uri, resource_path, resource,
3106
			dav_remote_send_string, content,
3107
			NULL, NULL))) {
3108
		return dav_push_error(r->pool, err->status, 0, "LOCK in dav_remote_resource_mkcol failed.", err);
3109
	}
3110
3111
	if (r->status == 200) {
3112
		token->token = apr_table_get(r->headers_in, "Lock-Token");
3113
		token->path = apr_pstrdup(r->pool, resource_uri->path);
3114
		return NULL;
3115
	}
3116
3117
	if (r->status == 423) {
3118
		return dav_new_error(r->pool, r->status, 0, "Resource already locked");
3119
	}
3120
3121
	return NULL;
3122
}
3123
3124
DAV_DECLARE(dav_error *) dav_remote_resource_unlock(request_rec *r, apr_uri_t *resource_uri,
3125
		const char *resource_path, const dav_resource *resource, dav_remote_lock_token *token)
3126
{
3127
	dav_error *err;
3128
	char *content;
3129
	apr_xml_doc *xmlDoc;
3130
3131
	if (NULL == token->token || NULL == token->path)
3132
		return 0; // no need
3133
3134
	if (NULL != (err = dav_remote_set_connection(r, resource_uri))) {
3135
		return dav_push_error(r->pool, err->status, 0, "Unable to create connection in dav_remote_resource_delete.", err);
3136
	}
3137
3138
	apr_table_clear(r->headers_out);
3139
	apr_table_add(r->headers_out, "Host", resource_uri->hostname);
3140
	apr_table_add(r->headers_out, "Connection", "Keep-Alive");
3141
	apr_table_add(r->headers_out, "Lock-Token", token->token);
3142
3143
	if (NULL != (err = dav_remote_method_request(r, "UNLOCK", resource_uri, resource_path, resource,
3144
			NULL, NULL,
3145
			NULL, NULL))) {
3146
		return dav_push_error(r->pool, err->status, 0, "LOCK in dav_remote_resource_mkcol failed.", err);
3147
	}
3148
3149
	if (r->status != 204) {
3150
		return dav_new_error(r->pool, r->status, 0, "Unable to unlock resource");
3151
	}
3152
3153
	return NULL;
3154
}
3155
3156
struct dav_remote_copymove_copy_walk_ctx
3157
{
3158
	request_rec *r;
3159
	const char *base_uri;
3160
	apr_uri_t *dest_uri;
3161
	const char *dest;
3162
	dav_remote_lock_token token;
3163
	int overwrite;
3164
};
3165
3166
DAV_DECLARE(dav_error *) dav_remote_copymove_walk(dav_walk_resource *wres, int calltype)
3167
{
3168
	struct dav_remote_copymove_copy_walk_ctx *ctx = (struct dav_remote_copymove_copy_walk_ctx *)wres->walk_ctx;
3169
	char *new_resource_path;
3170
	apr_uri_t new_resource_uri;
3171
	dav_error *err;
3172
3173
	if (strncmp(wres->resource->uri, ctx->base_uri, strlen(ctx->base_uri)) != 0) {
3174
		return dav_new_error(wres->pool, HTTP_INTERNAL_SERVER_ERROR, 0, "Invalid uri of subresource");
3175
	}
3176
3177
	new_resource_path = apr_pstrcat(wres->pool, ctx->dest, &(wres->resource->uri[strlen(ctx->base_uri)]), NULL);
3178
3179
	// shallow copy, only cange the path
3180
	new_resource_uri = *ctx->dest_uri;
3181
	new_resource_uri.path = apr_pstrcat(wres->pool, ctx->dest_uri->path, &(wres->resource->uri[strlen(ctx->base_uri)]), NULL);
3182
3183
	if (wres->resource->collection) {
3184
		new_resource_path[strlen(new_resource_path) - 1] = '\0';
3185
		new_resource_uri.path[strlen(new_resource_uri.path) - 1] = '\0';
3186
3187
		if (NULL != (err = dav_remote_resource_mkcol(ctx->r, &new_resource_uri, new_resource_path, wres->resource, ctx->overwrite, ctx->token)))
3188
			return err;
3189
	} else {
3190
		if (NULL != (err = dav_remote_resource_put(ctx->r, &new_resource_uri, new_resource_path, wres->resource, ctx->overwrite, ctx->token)))
3191
			return err;
3192
	}
3193
3194
	return NULL;
3195
}
3196
3197
DAV_DECLARE(dav_error *) dav_remote_copymove(request_rec *r, dav_resource *resource, const char *dest, int overwrite, int depth)
3198
{
3199
	dav_error *err = NULL;
3200
	dav_error *lock_err = NULL;
3201
	apr_uri_t dest_uri;
3202
	conn_rec *conn;
3203
    request_rec *rp;
3204
    int exists;
3205
	int deleted;
3206
	dav_walk_params walk_params = { 0 };
3207
	dav_response *response;
3208
	const char *lock_owner;
3209
	dav_remote_lock_token token;
3210
3211
    if (APR_SUCCESS != apr_uri_parse(r->pool, dest, &dest_uri)) {
3212
        ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
3213
                      "Destination URI cannot be parsed.", NULL);
3214
        return dav_new_error(r->pool, HTTP_BAD_REQUEST, 0, "Destination URI cannot be parsed.");
3215
    }
3216
3217
    if (!dest_uri.port) {
3218
    	dest_uri.port = apr_uri_port_of_scheme(dest_uri.scheme);
3219
    }
3220
3221
    // 1. create request
3222
    rp = dav_remote_make_fake_request(r);
3223
3224
   	if (!overwrite) {
3225
   	    // 2. check if exists
3226
   	   	if (NULL != (err = dav_remote_resource_exists(rp, &dest_uri, dest, resource, &exists))) {
3227
   	   		return err;
3228
   	   	}
3229
3230
   	   	if (exists) {
3231
   	        return dav_new_error(r->pool, HTTP_PRECONDITION_FAILED, 0, "Destination resource already exists.");
3232
   	   	}
3233
    }
3234
   	else {
3235
   		// 2. delete old resource
3236
   		if (NULL != (err = dav_remote_resource_delete(rp, &dest_uri, dest, resource))) {
3237
   			return err;
3238
   		}
3239
   	}
3240
3241
   	// 3. gain lock on NULL resource
3242
   	lock_owner = r->unparsed_uri;
3243
   	if (NULL != (err = dav_remote_resource_lock(rp, &dest_uri, dest, resource, lock_owner, &token))) {
3244
   		return err;
3245
	}
3246
3247
   	struct dav_remote_copymove_copy_walk_ctx ctx;
3248
	ctx.base_uri = resource->uri;
3249
	ctx.r = rp;
3250
	ctx.dest_uri = &dest_uri;
3251
	ctx.dest = dest;
3252
	ctx.overwrite = overwrite;
3253
	ctx.token = token;
3254
3255
   	walk_params.walk_type = DAV_WALKTYPE_AUTH | DAV_WALKTYPE_NORMAL;
3256
   	walk_params.func = dav_remote_copymove_walk;
3257
   	walk_params.walk_ctx = &ctx;
3258
   	walk_params.pool = r->pool;
3259
   	walk_params.root = resource;
3260
3261
   	// 4. copy resources/collections
3262
   	err = (*resource->hooks->walk)(&walk_params, depth, &response);
3263
3264
   	// 5. release lock
3265
   	if (NULL != (err = dav_remote_resource_unlock(rp, &dest_uri, dest, resource, &token))) {
3266
   		return err;
3267
	}
3268
3269
	return NULL;
3270
}
3271
2553
/* handle the COPY and MOVE methods */
3272
/* handle the COPY and MOVE methods */
2554
static int dav_method_copymove(request_rec *r, int is_move)
3273
static int dav_method_copymove(request_rec *r, int is_move)
2555
{
3274
{
Lines 2559-2567 Link Here
2559
    dav_auto_version_info dst_av_info = { 0 };
3278
    dav_auto_version_info dst_av_info = { 0 };
2560
    const char *body;
3279
    const char *body;
2561
    const char *dest;
3280
    const char *dest;
2562
    dav_error *err;
3281
    dav_error *err = NULL;
2563
    dav_error *err2;
3282
    dav_error *err2 = NULL;
2564
    dav_error *err3;
3283
    dav_error *err3 = NULL;
2565
    dav_response *multi_response;
3284
    dav_response *multi_response;
2566
    dav_lookup_result lookup;
3285
    dav_lookup_result lookup;
2567
    int is_dir;
3286
    int is_dir;
Lines 2571-2576 Link Here
2571
    dav_lockdb *lockdb;
3290
    dav_lockdb *lockdb;
2572
    int replace_dest;
3291
    int replace_dest;
2573
    int resnew_state;
3292
    int resnew_state;
3293
    int remote = 0;
2574
3294
2575
    /* Ask repository module to resolve the resource */
3295
    /* Ask repository module to resolve the resource */
2576
    err = dav_get_resource(r, !is_move /* label_allowed */,
3296
    err = dav_get_resource(r, !is_move /* label_allowed */,
Lines 2609-2614 Link Here
2609
        return HTTP_BAD_REQUEST;
3329
        return HTTP_BAD_REQUEST;
2610
    }
3330
    }
2611
3331
3332
    /* get and parse the overwrite header value */
3333
    if ((overwrite = dav_get_overwrite(r)) < 0) {
3334
        /* dav_get_overwrite() supplies additional information for the
3335
         * default message. */
3336
        return HTTP_BAD_REQUEST;
3337
    }
3338
2612
    lookup = dav_lookup_uri(dest, r, 1 /* must_be_absolute */);
3339
    lookup = dav_lookup_uri(dest, r, 1 /* must_be_absolute */);
2613
    if (lookup.rnew == NULL) {
3340
    if (lookup.rnew == NULL) {
2614
        if (lookup.err.status == HTTP_BAD_REQUEST) {
3341
        if (lookup.err.status == HTTP_BAD_REQUEST) {
Lines 2618-2628 Link Here
2618
            return HTTP_BAD_REQUEST;
3345
            return HTTP_BAD_REQUEST;
2619
        }
3346
        }
2620
3347
3348
        if (lookup.err.status == HTTP_BAD_GATEWAY) {
3349
            err = dav_get_resource(r, 1 /* label_allowed */, 0 /* use_checked_in */,
3350
                                   &resource);
3351
            remote = 1;
3352
        }
3353
3354
        if (!remote) {
2621
        /* ### this assumes that dav_lookup_uri() only generates a status
3355
        /* ### this assumes that dav_lookup_uri() only generates a status
2622
         * ### that Apache can provide a status line for!! */
3356
         * ### that Apache can provide a status line for!! */
2623
3357
2624
        return dav_error_response(r, lookup.err.status, lookup.err.desc);
3358
        return dav_error_response(r, lookup.err.status, lookup.err.desc);
2625
    }
3359
    }
3360
    }
3361
3362
    if (!remote) {
2626
    if (lookup.rnew->status != HTTP_OK) {
3363
    if (lookup.rnew->status != HTTP_OK) {
2627
        const char *auth = apr_table_get(lookup.rnew->err_headers_out,
3364
        const char *auth = apr_table_get(lookup.rnew->err_headers_out,
2628
                                        "WWW-Authenticate");
3365
                                        "WWW-Authenticate");
Lines 2651-2671 Link Here
2651
3388
2652
    /* are the two resources handled by the same repository? */
3389
    /* are the two resources handled by the same repository? */
2653
    if (resource->hooks != resnew->hooks) {
3390
    if (resource->hooks != resnew->hooks) {
2654
        /* ### this message exposes some backend config, but screw it... */
3391
    		err = dav_get_resource(r, 1 /* label_allowed */, 0 /* use_checked_in */,
2655
        return dav_error_response(r, HTTP_BAD_GATEWAY,
3392
                               &resource);
2656
                                  "Destination URI is handled by a "
3393
    		remote = 1;
2657
                                  "different repository than the source URI. "
2658
                                  "MOVE or COPY between repositories is "
2659
                                  "not possible.");
2660
    }
3394
    }
2661
2662
    /* get and parse the overwrite header value */
2663
    if ((overwrite = dav_get_overwrite(r)) < 0) {
2664
        /* dav_get_overwrite() supplies additional information for the
2665
         * default message. */
2666
        return HTTP_BAD_REQUEST;
2667
    }
3395
    }
2668
3396
3397
    // recheck remote, maybe it changed
3398
    if (!remote) {
2669
    /* quick failure test: if dest exists and overwrite is false. */
3399
    /* quick failure test: if dest exists and overwrite is false. */
2670
    if (resnew->exists && !overwrite) {
3400
    if (resnew->exists && !overwrite) {
2671
        /* Supply some text for the error response body. */
3401
        /* Supply some text for the error response body. */
Lines 2679-2685 Link Here
2679
        /* Supply some text for the error response body. */
3409
        /* Supply some text for the error response body. */
2680
        return dav_error_response(r, HTTP_FORBIDDEN,
3410
        return dav_error_response(r, HTTP_FORBIDDEN,
2681
                                  "Source and Destination URIs are the same.");
3411
                                  "Source and Destination URIs are the same.");
2682
3412
    	}
2683
    }
3413
    }
2684
3414
2685
    is_dir = resource->collection;
3415
    is_dir = resource->collection;
Lines 2732-2737 Link Here
2732
        return dav_handle_err(r, err, multi_response);
3462
        return dav_handle_err(r, err, multi_response);
2733
    }
3463
    }
2734
3464
3465
    if (!remote)
3466
    {
2735
    /*
3467
    /*
2736
     * Check If-Headers and existing locks for destination. Note that we
3468
     * Check If-Headers and existing locks for destination. Note that we
2737
     * use depth==infinity since the target (hierarchy) will be deleted
3469
     * use depth==infinity since the target (hierarchy) will be deleted
Lines 2778-2783 Link Here
2778
                                  "Destination collection contains the Source "
3510
                                  "Destination collection contains the Source "
2779
                                  "and Overwrite has been specified.");
3511
                                  "and Overwrite has been specified.");
2780
    }
3512
    }
3513
    }
2781
3514
2782
    /* ### for now, we don't need anything in the body */
3515
    /* ### for now, we don't need anything in the body */
2783
    if ((result = ap_discard_request_body(r)) != OK) {
3516
    if ((result = ap_discard_request_body(r)) != OK) {
Lines 2818-2823 Link Here
2818
        }
3551
        }
2819
    }
3552
    }
2820
3553
3554
    if (!remote)
3555
    {
2821
    /*
3556
    /*
2822
     * Remember the initial state of the destination, so the lock system
3557
     * Remember the initial state of the destination, so the lock system
2823
     * can be notified as to how it changed.
3558
     * can be notified as to how it changed.
Lines 2894-2906 Link Here
2894
    /* perform any auto-versioning cleanup */
3629
    /* perform any auto-versioning cleanup */
2895
    err2 = dav_auto_checkin(r, NULL, err != NULL /* undo if error */,
3630
    err2 = dav_auto_checkin(r, NULL, err != NULL /* undo if error */,
2896
                            0 /*unlock*/, &dst_av_info);
3631
                            0 /*unlock*/, &dst_av_info);
3632
    }
2897
3633
2898
    if (is_move) {
3634
    if (is_move) {
2899
        err3 = dav_auto_checkin(r, NULL, err != NULL /* undo if error */,
3635
        err3 = dav_auto_checkin(r, NULL, err != NULL /* undo if error */,
2900
                                0 /*unlock*/, &src_av_info);
3636
                                0 /*unlock*/, &src_av_info);
2901
    }
3637
    }
2902
    else
2903
        err3 = NULL;
2904
3638
2905
    /* check for error from remove/copy/move operations */
3639
    /* check for error from remove/copy/move operations */
2906
    if (err != NULL) {
3640
    if (err != NULL) {
Lines 2935-2940 Link Here
2935
        dav_log_err(r, err, APLOG_WARNING);
3669
        dav_log_err(r, err, APLOG_WARNING);
2936
    }
3670
    }
2937
3671
3672
    if (!remote) {
2938
    /* propagate any indirect locks at the target */
3673
    /* propagate any indirect locks at the target */
2939
    if (lockdb != NULL) {
3674
    if (lockdb != NULL) {
2940
3675
Lines 2953-2962 Link Here
2953
            return dav_handle_err(r, err, NULL);
3688
            return dav_handle_err(r, err, NULL);
2954
        }
3689
        }
2955
    }
3690
    }
3691
    }
3692
3693
    if (remote) {
3694
    	if (NULL != (err = dav_remote_copymove(r, resource, dest, overwrite, depth))) {
3695
    		return dav_handle_err(r, err, NULL);
3696
    	}
3697
3698
    	if (is_move) {
3699
    		if (NULL != (err = (*resource->hooks->remove_resource)(resource, &multi_response))) {
3700
    			return dav_handle_err(r, err, NULL);
3701
    		}
3702
    	}
2956
3703
2957
    /* return an appropriate response (HTTP_CREATED or HTTP_NO_CONTENT) */
3704
    /* return an appropriate response (HTTP_CREATED or HTTP_NO_CONTENT) */
3705
    	return dav_created(r, dest, "Destination", 0);
3706
    }
3707
    else {
3708
    	/* return an appropriate response (HTTP_CREATED or HTTP_NO_CONTENT) */
2958
    return dav_created(r, lookup.rnew->uri, "Destination",
3709
    return dav_created(r, lookup.rnew->uri, "Destination",
2959
                       resnew_state == DAV_RESOURCE_EXISTS);
3710
                       resnew_state == DAV_RESOURCE_EXISTS);
3711
    }
2960
}
3712
}
2961
3713
2962
/* dav_method_lock:  Handler to implement the DAV LOCK method
3714
/* dav_method_lock:  Handler to implement the DAV LOCK method
(-)httpd-2.2.9-orig/modules/dav/main/util.c (-2 / +1 lines)
Lines 216-225 Link Here
216
           request. the port must match our port.
216
           request. the port must match our port.
217
        */
217
        */
218
        port = r->connection->local_addr->port;
218
        port = r->connection->local_addr->port;
219
219
        if (strcasecmp(comp.scheme, scheme) != 0
220
        if (strcasecmp(comp.scheme, scheme) != 0
220
#ifdef APACHE_PORT_HANDLING_IS_BUSTED
221
            || comp.port != port
221
            || comp.port != port
222
#endif
223
            ) {
222
            ) {
224
            result.err.status = HTTP_BAD_GATEWAY;
223
            result.err.status = HTTP_BAD_GATEWAY;
225
            result.err.desc = apr_psprintf(r->pool,
224
            result.err.desc = apr_psprintf(r->pool,
(-)httpd-2.2.9-orig/modules/http/http_filters.c (-1 / +1 lines)
Lines 1372-1378 Link Here
1372
            }
1372
            }
1373
1373
1374
            /* These are metadata buckets. */
1374
            /* These are metadata buckets. */
1375
            if (bucket->length == 0) {
1375
            if (APR_BUCKET_IS_METADATA(bucket)) {
1376
                continue;
1376
                continue;
1377
            }
1377
            }
1378
1378

Return to bug 45449