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 / +698 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 2550-2555 Link Here
2550
    return dav_created(r, NULL, "Collection", 0);
2551
    return dav_created(r, NULL, "Collection", 0);
2551
}
2552
}
2552
2553
2554
// copied from mod_proxy - maybe add to core or lib?
2555
DAV_DECLARE(dav_error *) dav_remote_copymove_create_socket(apr_pool_t *p, apr_sockaddr_t *addr, apr_socket_t **newsock)
2556
{
2557
	apr_status_t rv;
2558
2559
	while (addr) {
2560
        if ((rv = apr_socket_create(newsock, addr->family,
2561
                                    SOCK_STREAM, 0, p)) != APR_SUCCESS) {
2562
            /*
2563
             * this could be an IPv6 address from the DNS but the
2564
             * local machine won't give us an IPv6 socket; hopefully the
2565
             * DNS returned an additional address to try
2566
             */
2567
            addr = addr->next;
2568
            continue;
2569
        }
2570
2571
        rv = apr_socket_connect(*newsock, addr);
2572
2573
        /* if an error occurred, loop round and try again */
2574
        if (rv != APR_SUCCESS) {
2575
            apr_socket_close(*newsock);
2576
            addr = addr->next;
2577
            continue;
2578
        }
2579
2580
        return 0;
2581
	}
2582
2583
	return dav_new_error(p, HTTP_INTERNAL_SERVER_ERROR, 0, "Socket creating failed");
2584
}
2585
2586
DAV_DECLARE(dav_error *) dav_remote_create_connection(apr_pool_t *p, apr_uri_t *uri, server_rec *s, conn_rec **conn)
2587
{
2588
	apr_status_t rv;
2589
	apr_sockaddr_t *src_addr;
2590
	apr_socket_t *socket;
2591
	dav_error *err;
2592
2593
	rv = apr_sockaddr_info_get(&src_addr, uri->hostname, APR_UNSPEC, uri->port, 0, p);
2594
    if (APR_SUCCESS != rv) {
2595
        return dav_new_error(p, HTTP_BAD_REQUEST, 0, apr_pstrcat(p, "DNS lookup failure for: ", uri->hostname, NULL));
2596
    }
2597
2598
	if (NULL != (err = dav_remote_copymove_create_socket(p, src_addr, &socket))) {
2599
		return err;
2600
	}
2601
2602
	*conn = (conn_rec *)ap_run_create_connection(p, s, socket, 0, NULL, apr_bucket_alloc_create(p));
2603
2604
	if (!*conn) {
2605
		// will it have memory to create error message? i guess not, let the caller check!
2606
		return 0;
2607
	}
2608
2609
    /* set up the connection filters */
2610
    rv = ap_run_pre_connection(*conn, socket);
2611
    if (rv != OK && rv != DONE) {
2612
        (*conn)->aborted = 1;
2613
        return dav_new_error(p, HTTP_INTERNAL_SERVER_ERROR, 0, "pre_connection setup failed");
2614
    }
2615
2616
	return 0;
2617
}
2618
2619
DAV_DECLARE(dav_error *) dav_remote_close_connection(request_rec *r)
2620
{
2621
	// TODO: find a better way to do it
2622
	r->connection = 0;
2623
}
2624
2625
DAV_DECLARE(request_rec *) dav_remote_make_fake_request(request_rec *r)
2626
{
2627
	request_rec *rp = apr_pcalloc(r->pool, sizeof(*r));
2628
2629
    rp->pool            = r->pool;
2630
    rp->status          = HTTP_OK;
2631
2632
    rp->headers_in      = apr_table_make(r->pool, 12);
2633
    rp->subprocess_env  = apr_table_make(r->pool, 12);
2634
    rp->headers_out     = apr_table_make(r->pool, 12);
2635
    rp->err_headers_out = apr_table_make(r->pool, 5);
2636
    rp->notes           = apr_table_make(r->pool, 5);
2637
2638
    rp->server = r->server;
2639
    rp->proxyreq = r->proxyreq;
2640
    rp->request_time = r->request_time;
2641
2642
    rp->connection = 0;
2643
2644
    // TODO: is it ok to do that?
2645
    rp->request_config = r->request_config;
2646
    rp->per_dir_config = r->per_dir_config;
2647
}
2648
2649
DAV_DECLARE(dav_error *) dav_remote_set_connection(request_rec *r, apr_uri_t *resource_uri)
2650
{
2651
	dav_error *err;
2652
	conn_rec *conn;
2653
2654
	if (r->connection && !r->connection->aborted && (r->connection->keepalive == AP_CONN_KEEPALIVE)) {
2655
		return 0;
2656
	}
2657
2658
	if (NULL != (err = dav_remote_create_connection(r->pool, resource_uri, r->server, &conn))) {
2659
		return err;
2660
	}
2661
2662
	conn->keepalive = AP_CONN_KEEPALIVE;
2663
2664
	r->connection      = conn;
2665
	r->output_filters  = conn->output_filters;
2666
	r->input_filters   = conn->input_filters;
2667
	r->proto_output_filters  = conn->output_filters;
2668
	r->proto_input_filters   = conn->input_filters;
2669
2670
	return 0;
2671
}
2672
2673
DAV_DECLARE(dav_error *) dav_remote_send_resource_content(request_rec *r, const dav_resource *resource)
2674
{
2675
	dav_error *err;
2676
	apr_bucket_brigade *request_brigade;
2677
	apr_bucket *e;
2678
	apr_status_t rv;
2679
2680
    /* okay... time to deliver the content */
2681
    if ((err = (*resource->hooks->deliver)(resource,
2682
                                           r->output_filters)) != NULL) {
2683
        return dav_push_error(r->pool, err->status, 0,
2684
                             "Unable to deliver content.",
2685
                             err);
2686
    }
2687
2688
	request_brigade =  apr_brigade_create(r->pool, r->connection->bucket_alloc);
2689
2690
	e = apr_bucket_flush_create(r->connection->bucket_alloc);
2691
	APR_BRIGADE_INSERT_TAIL(request_brigade, e);
2692
2693
    rv = ap_pass_brigade(r->output_filters, request_brigade);
2694
2695
    return NULL;
2696
}
2697
2698
struct dav_remote_send_headers_wrapper {
2699
	apr_bucket_alloc_t *bucket_alloc;
2700
	apr_bucket_brigade *request_brigade;
2701
	apr_pool_t *p;
2702
};
2703
2704
int dav_remote_send_header(void *rec, const char *key, const char *value)
2705
{
2706
	struct dav_remote_send_headers_wrapper *wrapper = (struct dav_remote_send_headers_wrapper *)rec;
2707
2708
	apr_bucket_brigade *request_brigade = wrapper->request_brigade;
2709
	apr_bucket *e;
2710
	char *buf;
2711
2712
	buf = apr_pstrcat(wrapper->p, key, ": ", value, CRLF, NULL);
2713
	e = apr_bucket_pool_create(buf, strlen(buf), wrapper->p, wrapper->bucket_alloc);
2714
	ap_xlate_proto_to_ascii(buf, strlen(buf));
2715
	APR_BRIGADE_INSERT_TAIL(request_brigade, e);
2716
}
2717
2718
DAV_DECLARE(dav_error *) dav_remote_read_status_line(request_rec *r)
2719
{
2720
    apr_bucket_brigade *response_brigade;
2721
2722
    char buff[HUGE_STRING_LEN];
2723
	char *buff_p = buff;
2724
	char keepchar;
2725
	apr_size_t len;
2726
2727
    response_brigade = apr_brigade_create(r->pool, r->connection->bucket_alloc);
2728
    ap_rgetline(&buff_p, sizeof(buff), &len, r, 0, response_brigade);
2729
2730
    if (!apr_date_checkmask(buff, "HTTP/#.# ###*")) {
2731
    	return dav_new_error(r->pool, HTTP_BAD_GATEWAY, 0, "Invalid response status line");
2732
    }
2733
2734
    int major, minor;
2735
2736
    if (2 != sscanf(buff, "HTTP/%u.%u", &major, &minor)) {
2737
        major = 1;
2738
        minor = 1;
2739
    }
2740
    else if ((buff[5] != '1') || (len >= sizeof(buff) - 1)) {
2741
        return dav_new_error(r->pool, HTTP_BAD_GATEWAY, 0, "Invalid response status line");
2742
    }
2743
2744
    keepchar = buff[12];
2745
    buff[12] = '\0';
2746
    r->status = atoi(&buff[9]);
2747
2748
    if (keepchar != '\0') {
2749
     	buff[12] = keepchar;
2750
    } else {
2751
        /* 2616 requires the space in Status-Line; the origin
2752
         * server may have sent one but ap_rgetline_core will
2753
         * have stripped it. */
2754
    	buff[12] = ' ';
2755
        buff[13] = '\0';
2756
    }
2757
    r->status_line = apr_pstrdup(r->pool, &buff[9]);
2758
2759
    return 0;
2760
}
2761
2762
DAV_DECLARE(dav_error *) dav_remote_read_response_headers(request_rec *r)
2763
{
2764
	dav_error *err;
2765
    apr_bucket_brigade *response_brigade;
2766
	apr_size_t len;
2767
	apr_status_t rv;
2768
    char buff[HUGE_STRING_LEN];
2769
	char *buff_p = buff;
2770
	char *value, *end;
2771
2772
	apr_table_clear(r->headers_in);
2773
2774
	response_brigade = apr_brigade_create(r->pool, r->connection->bucket_alloc);
2775
    if (APR_SUCCESS != (rv = ap_rgetline(&buff_p, sizeof(buff), &len, r, 0, response_brigade))) {
2776
    	return dav_new_error(r->pool, HTTP_BAD_GATEWAY, 0, "Error reading response header");
2777
    }
2778
2779
    while (0 < len) {
2780
    	if (!(value = strchr(buff, ':'))) {
2781
    	    if (APR_SUCCESS != (rv = ap_rgetline(&buff_p, sizeof(buff), &len, r, 0, response_brigade))) {
2782
    	    	return dav_new_error(r->pool, HTTP_BAD_GATEWAY, 0, "Error reading response header");
2783
    	    }
2784
    	}
2785
2786
        *value = '\0';
2787
        ++value;
2788
        /* XXX: RFC2068 defines only SP and HT as whitespace, this test is
2789
         * wrong... and so are many others probably.
2790
         */
2791
        while (apr_isspace(*value))
2792
            ++value;            /* Skip to start of value   */
2793
2794
        /* should strip trailing whitespace as well */
2795
        for (end = &value[strlen(value)-1]; end > value && apr_isspace(*end); --end)
2796
            *end = '\0';
2797
2798
        apr_table_add(r->headers_in, buff, value);
2799
2800
	    if (APR_SUCCESS != (rv = ap_rgetline(&buff_p, sizeof(buff), &len, r, 0, response_brigade))) {
2801
	    	return dav_new_error(r->pool, HTTP_BAD_GATEWAY, 0, "Error reading response header");
2802
	    }
2803
    }
2804
2805
    return 0;
2806
}
2807
2808
typedef DAV_DECLARE(dav_error *) (* write_request_content_callback) (request_rec *, void *data);
2809
typedef DAV_DECLARE(dav_error *) (* read_reponse_content_callback) (request_rec *, void *data);
2810
2811
DAV_DECLARE(dav_error *) dav_remote_skip_response_content(request_rec *r, void *unused)
2812
{
2813
	apr_size_t content_length;
2814
	apr_size_t to_read;
2815
    apr_bucket_brigade *response_brigade;
2816
    apr_bucket *e;
2817
    int seen_eos = 0;
2818
	const char *content_length_str;
2819
    apr_bucket_alloc_t *bucket_alloc = r->connection->bucket_alloc;
2820
	char buff[HUGE_STRING_LEN];
2821
    char *buff_p = buff;
2822
2823
	if (NULL == apr_table_get(r->headers_in, "Keep-Alive")) { // we can close the connection now
2824
		dav_remote_close_connection(r);
2825
		return NULL;
2826
	}
2827
2828
	content_length_str = apr_table_get(r->headers_in, "Content-Length");
2829
	if (NULL == content_length_str) {
2830
		return NULL; // no content
2831
	}
2832
2833
	content_length = atoi(content_length_str);
2834
	if (0 == content_length) {
2835
		return NULL; // no content
2836
	}
2837
2838
	if (content_length < 0) {
2839
		dav_remote_close_connection(r);
2840
		return dav_new_error(r->pool, HTTP_BAD_GATEWAY, 0, "Invalid Content-Length of response");
2841
	}
2842
2843
	while (0 < content_length) {
2844
		response_brigade = apr_brigade_create(r->pool, bucket_alloc);
2845
2846
        do {
2847
            apr_status_t rc;
2848
2849
            rc = ap_get_brigade(r->input_filters, response_brigade, AP_MODE_READBYTES,
2850
                                APR_BLOCK_READ, DAV_READ_BLOCKSIZE);
2851
2852
            if (rc != APR_SUCCESS) {
2853
                return dav_new_error(r->pool, HTTP_INTERNAL_SERVER_ERROR, 0,
2854
                                    "Could not get next bucket brigade");
2855
            }
2856
2857
            for (e = APR_BRIGADE_FIRST(response_brigade);
2858
                 e != APR_BRIGADE_SENTINEL(response_brigade);
2859
                 e = APR_BUCKET_NEXT(e))
2860
            {
2861
                const char *data;
2862
                apr_size_t len;
2863
2864
                if (APR_BUCKET_IS_EOS(e)) {
2865
                    seen_eos = 1;
2866
                    break;
2867
                }
2868
2869
                if (APR_BUCKET_IS_METADATA(e)) {
2870
                    continue;
2871
                }
2872
2873
                rc = apr_bucket_read(e, &data, &len, APR_BLOCK_READ);
2874
                content_length -= len;
2875
2876
                if (rc != APR_SUCCESS) {
2877
                	printf("2\n");
2878
                    return dav_new_error(r->pool, HTTP_BAD_REQUEST, 0,
2879
                                        "An error occurred while reading "
2880
                                        "the request body.");
2881
                }
2882
            }
2883
2884
            apr_brigade_cleanup(response_brigade);
2885
        } while (!seen_eos && content_length > 0);
2886
	}
2887
2888
	return NULL;
2889
}
2890
2891
DAV_DECLARE(dav_error *) dav_remote_skip_head_response_content(request_rec *r, void *unused)
2892
{
2893
	// nothing to do
2894
	return NULL;
2895
}
2896
2897
DAV_DECLARE(dav_error *) dav_remote_method_request(request_rec *r, const char *method, apr_uri_t *resource_uri,
2898
		const char *resource_path, const dav_resource *resource,
2899
		write_request_content_callback write_request_content, void *write_request_content_data,
2900
		read_reponse_content_callback read_response_content, void *read_response_content_data)
2901
{
2902
    apr_status_t rv;
2903
    dav_error *err;
2904
    apr_bucket_alloc_t *bucket_alloc = r->connection->bucket_alloc;
2905
    apr_bucket_brigade *request_brigade;
2906
    apr_bucket *e;
2907
	char *buf;
2908
2909
	// as I see nobody in httpd check for NULL results of malloc/apr_palloc, so why I should?
2910
    request_brigade = apr_brigade_create(r->pool, bucket_alloc);
2911
2912
    // request line
2913
	buf = apr_pstrcat(r->pool, method, " ", resource_uri->path, " HTTP/1.1", CRLF, NULL);
2914
	e = apr_bucket_pool_create(buf, strlen(buf), r->pool, bucket_alloc);
2915
	ap_xlate_proto_to_ascii(buf, strlen(buf));
2916
	APR_BRIGADE_INSERT_TAIL(request_brigade, e);
2917
2918
	// headers
2919
	struct dav_remote_send_headers_wrapper wrapper;
2920
	wrapper.bucket_alloc = bucket_alloc;
2921
	wrapper.request_brigade = request_brigade;
2922
	wrapper.p = r->pool;
2923
2924
	apr_table_do(dav_remote_send_header, &wrapper, r->headers_out, 0);
2925
2926
	// empty line after headers
2927
	buf = apr_pstrcat(r->pool, CRLF, NULL);
2928
	e = apr_bucket_pool_create(buf, strlen(buf), r->pool, bucket_alloc);
2929
	ap_xlate_proto_to_ascii(buf, strlen(buf));
2930
	APR_BRIGADE_INSERT_TAIL(request_brigade, e);
2931
2932
	e = apr_bucket_flush_create(bucket_alloc);
2933
	APR_BRIGADE_INSERT_TAIL(request_brigade, e);
2934
2935
	// send it now
2936
    rv = ap_pass_brigade(r->output_filters, request_brigade);
2937
2938
	if (rv != APR_SUCCESS) {
2939
		return dav_new_error(r->pool, HTTP_INTERNAL_SERVER_ERROR, 0, "Sending request failed");
2940
	}
2941
2942
    // for PUT requests
2943
    if (NULL != write_request_content) {
2944
    	if (NULL != (err = write_request_content(r, write_request_content_data))) {
2945
    		return dav_push_error(r->pool, err->status, 0,
2946
    				apr_pstrcat(r->pool, "Could not write request for ", method, " for ", resource_path, NULL), err);
2947
    	}
2948
    }
2949
2950
	if (NULL != (err = dav_remote_read_status_line(r))) {
2951
		return dav_push_error(r->pool, err->status, 0,
2952
				apr_pstrcat(r->pool, "Could not read status for ", method, " for ", resource_path, NULL), err);
2953
	}
2954
2955
	if (NULL != (err = dav_remote_read_response_headers(r))) {
2956
		return dav_push_error(r->pool, err->status, 0,
2957
				apr_pstrcat(r->pool, "Could not read response headers for ", method, " for ", resource_path, NULL), err);
2958
	}
2959
2960
	if (NULL == read_response_content) {
2961
		read_response_content = dav_remote_skip_response_content;
2962
	}
2963
2964
	if (NULL != (err = read_response_content(r, read_response_content_data))) {
2965
		return dav_push_error(r->pool, err->status, 0,
2966
				apr_pstrcat(r->pool, "Could not read response content for ", method, " for ", resource_path, NULL), err);
2967
	}
2968
2969
	// MOVED PERMANENTLY - check with '/' at the end
2970
	if ((r->status == HTTP_MOVED_PERMANENTLY) && (resource_uri->path[strlen(resource_uri->path) - 1] != '/')) {
2971
		resource_path = apr_pstrcat(r->pool, resource_path, "/", NULL);
2972
		// TODO: do something with it
2973
		if (strcmp(resource_path, apr_table_get(r->headers_in, "Location")) != 0) {
2974
			return dav_new_error(r->pool, HTTP_INTERNAL_SERVER_ERROR, 0, "No idea what to do...");
2975
		}
2976
2977
		resource_uri->path = apr_pstrcat(r->pool, resource_uri->path, "/", NULL);
2978
2979
		return dav_remote_method_request(r, method, resource_uri, resource_path, resource, NULL, NULL, NULL, NULL);
2980
	}
2981
2982
	return NULL;
2983
}
2984
2985
DAV_DECLARE(dav_error *) dav_remote_resource_exists(request_rec *r, apr_uri_t *resource_uri,
2986
		const char *resource_path, const dav_resource *resource, int *exists)
2987
{
2988
	dav_error *err;
2989
2990
	*exists = 0;
2991
2992
	if (NULL != (err = dav_remote_set_connection(r, resource_uri))) {
2993
		return dav_push_error(r->pool, err->status, 0, "Unable to create connection in dav_remote_resource_exists.", err);
2994
	}
2995
2996
	apr_table_clear(r->headers_out);
2997
	apr_table_add(r->headers_out, "Host", resource_uri->hostname);
2998
	apr_table_add(r->headers_out, "Content-Length", "0");
2999
	apr_table_add(r->headers_out, "Depth", "0");
3000
	apr_table_add(r->headers_out, "Connection", "Keep-Alive");
3001
3002
	if (NULL != (err = dav_remote_method_request(r, "HEAD", resource_uri, resource_path,
3003
			resource, NULL, NULL, dav_remote_skip_head_response_content, NULL))) {
3004
		return dav_push_error(r->pool, err->status, 0, "HEAD in dav_remote_resource_exists failed.", err);
3005
	}
3006
3007
	*exists = r->status != 404;
3008
	return NULL;
3009
}
3010
3011
DAV_DECLARE(dav_error *) dav_remote_resource_delete(request_rec *r, apr_uri_t *resource_uri,
3012
		const char *resource_path, const dav_resource *resource)
3013
{
3014
	dav_error *err;
3015
3016
	if (NULL != (err = dav_remote_set_connection(r, resource_uri))) {
3017
		return dav_push_error(r->pool, err->status, 0, "Unable to create connection in dav_remote_resource_delete.", err);
3018
	}
3019
3020
	apr_table_clear(r->headers_out);
3021
	apr_table_add(r->headers_out, "Host", resource_uri->hostname);
3022
	apr_table_add(r->headers_out, "Content-Length", "0");
3023
	apr_table_add(r->headers_out, "Connection", "Keep-Alive");
3024
3025
	if (NULL != (err = dav_remote_method_request(r, "DELETE", resource_uri, resource_path, resource, NULL, NULL, NULL, NULL))) {
3026
		return dav_push_error(r->pool, err->status, 0, "DELETE in dav_remote_resource_delete failed.", err);
3027
	}
3028
3029
	if (r->status == 200 || r->status == 202 || r->status == 204 || r->status == 404)
3030
		return NULL;
3031
	else
3032
		return dav_new_error(r->pool, r->status, 0, "DELETE refused by remote server");
3033
}
3034
3035
DAV_DECLARE(dav_error *) dav_remote_resource_mkcol(request_rec *r, apr_uri_t *resource_uri,
3036
		const char *resource_path, const dav_resource *resource, int overwrite)
3037
{
3038
	dav_error *err;
3039
3040
	if (NULL != (err = dav_remote_set_connection(r, resource_uri))) {
3041
		return dav_push_error(r->pool, err->status, 0, "Unable to create connection in dav_remote_resource_delete.", err);
3042
	}
3043
3044
	apr_table_clear(r->headers_out);
3045
	apr_table_add(r->headers_out, "Host", resource_uri->hostname);
3046
	apr_table_add(r->headers_out, "Content-Length", "0");
3047
	apr_table_add(r->headers_out, "Connection", "Keep-Alive");
3048
3049
	if (!overwrite) {
3050
		apr_table_add(r->headers_out, "If-None-Match", "*");
3051
	}
3052
3053
	if (NULL != (err = dav_remote_method_request(r, "MKCOL", resource_uri, resource_path, resource, NULL, NULL, NULL, NULL))) {
3054
		return dav_push_error(r->pool, err->status, 0, "MKCOL in dav_remote_resource_mkcol failed.", err);
3055
	}
3056
3057
	if (r->status != 201)
3058
		return dav_new_error(r->pool, r->status, 0, "Remote server refused to make collection");
3059
	else
3060
		return NULL;
3061
}
3062
3063
DAV_DECLARE(dav_error *) dav_remote_resource_put(request_rec *r, apr_uri_t *resource_uri,
3064
		const char *resource_path, const dav_resource *resource, int overwrite)
3065
{
3066
	dav_error *err;
3067
3068
	if (NULL != (err = dav_remote_set_connection(r, resource_uri))) {
3069
		return dav_push_error(r->pool, err->status, 0, "Unable to create connection in dav_remote_resource_delete.", err);
3070
	}
3071
3072
	apr_table_clear(r->headers_out);
3073
	apr_table_add(r->headers_out, "Host", resource_uri->hostname);
3074
	apr_table_add(r->headers_out, "Connection", "Keep-Alive");
3075
3076
	if (!overwrite) {
3077
		apr_table_add(r->headers_out, "If-None-Match", "*");
3078
	}
3079
3080
    if ((err = (*resource->hooks->set_headers)(r, resource)) != NULL) {
3081
        return dav_push_error(r->pool, err->status, 0,
3082
                             "Unable to set up HTTP headers.",
3083
                             err);
3084
    }
3085
3086
    apr_table_unset(r->headers_out, "Accept-Ranges");
3087
    apr_table_unset(r->headers_out, "ETag");
3088
3089
	if (NULL != (err = dav_remote_method_request(r, "PUT", resource_uri, resource_path, resource,
3090
			dav_remote_send_resource_content, (void *)resource,
3091
			NULL, NULL))) {
3092
		return dav_push_error(r->pool, err->status, 0, "DELETE in dav_remote_resource_delete failed.", err);
3093
	}
3094
3095
	if (r->status != 201 && r->status != 204)
3096
		return dav_new_error(r->pool, r->status, 0, "Remote server does not accept resource");
3097
	else
3098
		return NULL;
3099
}
3100
3101
struct dav_remote_copymove_copy_walk_ctx
3102
{
3103
	const char *base_uri;
3104
	request_rec *r;
3105
	apr_uri_t *dest_uri;
3106
	const char *dest;
3107
	int overwrite;
3108
};
3109
3110
DAV_DECLARE(dav_error *) dav_remote_copymove_copy_walk(dav_walk_resource *wres, int calltype)
3111
{
3112
	struct dav_remote_copymove_copy_walk_ctx *ctx = (struct dav_remote_copymove_copy_walk_ctx *)wres->walk_ctx;
3113
	const char *new_resource_path;
3114
	apr_uri_t new_resource_uri;
3115
	dav_error *err;
3116
3117
	if (strncmp(wres->resource->uri, ctx->base_uri, strlen(ctx->base_uri)) != 0) {
3118
		return dav_new_error(wres->pool, HTTP_INTERNAL_SERVER_ERROR, 0, "Invalid uri of subresource");
3119
	}
3120
3121
	new_resource_path = apr_pstrcat(wres->pool, ctx->dest, &(wres->resource->uri[strlen(ctx->base_uri)]), NULL);
3122
3123
	// shallow copy, only cange the path
3124
	new_resource_uri = *ctx->dest_uri;
3125
	new_resource_uri.path = apr_pstrcat(wres->pool, ctx->dest_uri->path, &(wres->resource->uri[strlen(ctx->base_uri)]), NULL);
3126
3127
	if (wres->resource->collection) {
3128
		if (NULL != (err = dav_remote_resource_mkcol(ctx->r, &new_resource_uri, new_resource_path, wres->resource, ctx->overwrite)))
3129
			return err;
3130
	} else {
3131
		if (NULL != (err = dav_remote_resource_put(ctx->r, &new_resource_uri, new_resource_path, wres->resource, ctx->overwrite)))
3132
			return err;
3133
	}
3134
3135
	return NULL;
3136
}
3137
3138
DAV_DECLARE(dav_error *) dav_remote_copymove(request_rec *r, dav_resource *resource, const char *dest, int overwrite, int depth)
3139
{
3140
	dav_error *err;
3141
	apr_uri_t dest_uri;
3142
	conn_rec *conn;
3143
    request_rec *rp;
3144
    int exists;
3145
	int deleted;
3146
	dav_walk_params walk_params = { 0 };
3147
	dav_response *response;
3148
3149
    if (APR_SUCCESS != apr_uri_parse(r->pool, dest, &dest_uri)) {
3150
        ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
3151
                      "Destination URI cannot be parsed.", NULL);
3152
        return dav_new_error(r->pool, HTTP_BAD_REQUEST, 0, "Destination URI cannot be parsed.");
3153
    }
3154
3155
    if (!dest_uri.port) {
3156
    	dest_uri.port = apr_uri_port_of_scheme(dest_uri.scheme);
3157
    }
3158
3159
    // 1. create request
3160
    rp = dav_remote_make_fake_request(r);
3161
3162
   	if (!overwrite) {
3163
   	    // 2. check if exists
3164
   	   	if (NULL != (err = dav_remote_resource_exists(rp, &dest_uri, dest, resource, &exists))) {
3165
   	   		return err;
3166
   	   	}
3167
3168
   	   	if (exists) {
3169
   	        return dav_new_error(r->pool, HTTP_PRECONDITION_FAILED, 0, "Destination resource already exists.");
3170
   	   	}
3171
    }
3172
   	else {
3173
   		// 2. delete old resource
3174
   		if (NULL != (err = dav_remote_resource_delete(rp, &dest_uri, dest, resource))) {
3175
   			return err;
3176
   		}
3177
   	}
3178
3179
   	struct dav_remote_copymove_copy_walk_ctx ctx;
3180
	ctx.base_uri = resource->uri;
3181
	ctx.r = rp;
3182
	ctx.dest_uri = &dest_uri;
3183
	ctx.dest = dest;
3184
	ctx.overwrite = overwrite;
3185
3186
   	walk_params.walk_type = DAV_WALKTYPE_AUTH | DAV_WALKTYPE_NORMAL;
3187
   	walk_params.func = dav_remote_copymove_copy_walk;
3188
   	walk_params.walk_ctx = &ctx;
3189
   	walk_params.pool = r->pool;
3190
   	walk_params.root = resource;
3191
3192
   	// 3. copy resources/collections
3193
   	if (NULL != (err = (*resource->hooks->walk)(&walk_params, depth, &response))) {
3194
   		return err;
3195
   	}
3196
3197
	return NULL;
3198
}
3199
2553
/* handle the COPY and MOVE methods */
3200
/* handle the COPY and MOVE methods */
2554
static int dav_method_copymove(request_rec *r, int is_move)
3201
static int dav_method_copymove(request_rec *r, int is_move)
2555
{
3202
{
Lines 2559-2567 Link Here
2559
    dav_auto_version_info dst_av_info = { 0 };
3206
    dav_auto_version_info dst_av_info = { 0 };
2560
    const char *body;
3207
    const char *body;
2561
    const char *dest;
3208
    const char *dest;
2562
    dav_error *err;
3209
    dav_error *err = NULL;
2563
    dav_error *err2;
3210
    dav_error *err2 = NULL;
2564
    dav_error *err3;
3211
    dav_error *err3 = NULL;
2565
    dav_response *multi_response;
3212
    dav_response *multi_response;
2566
    dav_lookup_result lookup;
3213
    dav_lookup_result lookup;
2567
    int is_dir;
3214
    int is_dir;
Lines 2571-2576 Link Here
2571
    dav_lockdb *lockdb;
3218
    dav_lockdb *lockdb;
2572
    int replace_dest;
3219
    int replace_dest;
2573
    int resnew_state;
3220
    int resnew_state;
3221
    int remote = 0;
2574
3222
2575
    /* Ask repository module to resolve the resource */
3223
    /* Ask repository module to resolve the resource */
2576
    err = dav_get_resource(r, !is_move /* label_allowed */,
3224
    err = dav_get_resource(r, !is_move /* label_allowed */,
Lines 2609-2614 Link Here
2609
        return HTTP_BAD_REQUEST;
3257
        return HTTP_BAD_REQUEST;
2610
    }
3258
    }
2611
3259
3260
    /* get and parse the overwrite header value */
3261
    if ((overwrite = dav_get_overwrite(r)) < 0) {
3262
        /* dav_get_overwrite() supplies additional information for the
3263
         * default message. */
3264
        return HTTP_BAD_REQUEST;
3265
    }
3266
2612
    lookup = dav_lookup_uri(dest, r, 1 /* must_be_absolute */);
3267
    lookup = dav_lookup_uri(dest, r, 1 /* must_be_absolute */);
2613
    if (lookup.rnew == NULL) {
3268
    if (lookup.rnew == NULL) {
2614
        if (lookup.err.status == HTTP_BAD_REQUEST) {
3269
        if (lookup.err.status == HTTP_BAD_REQUEST) {
Lines 2618-2628 Link Here
2618
            return HTTP_BAD_REQUEST;
3273
            return HTTP_BAD_REQUEST;
2619
        }
3274
        }
2620
3275
3276
        if (lookup.err.status == HTTP_BAD_GATEWAY) {
3277
            err = dav_get_resource(r, 1 /* label_allowed */, 0 /* use_checked_in */,
3278
                                   &resource);
3279
            remote = 1;
3280
        }
3281
3282
        if (!remote) {
2621
        /* ### this assumes that dav_lookup_uri() only generates a status
3283
        /* ### this assumes that dav_lookup_uri() only generates a status
2622
         * ### that Apache can provide a status line for!! */
3284
         * ### that Apache can provide a status line for!! */
2623
3285
2624
        return dav_error_response(r, lookup.err.status, lookup.err.desc);
3286
        return dav_error_response(r, lookup.err.status, lookup.err.desc);
2625
    }
3287
    }
3288
    }
3289
3290
    if (!remote) {
2626
    if (lookup.rnew->status != HTTP_OK) {
3291
    if (lookup.rnew->status != HTTP_OK) {
2627
        const char *auth = apr_table_get(lookup.rnew->err_headers_out,
3292
        const char *auth = apr_table_get(lookup.rnew->err_headers_out,
2628
                                        "WWW-Authenticate");
3293
                                        "WWW-Authenticate");
Lines 2651-2671 Link Here
2651
3316
2652
    /* are the two resources handled by the same repository? */
3317
    /* are the two resources handled by the same repository? */
2653
    if (resource->hooks != resnew->hooks) {
3318
    if (resource->hooks != resnew->hooks) {
2654
        /* ### this message exposes some backend config, but screw it... */
3319
    		err = dav_get_resource(r, 1 /* label_allowed */, 0 /* use_checked_in */,
2655
        return dav_error_response(r, HTTP_BAD_GATEWAY,
3320
                               &resource);
2656
                                  "Destination URI is handled by a "
3321
    		remote = 1;
2657
                                  "different repository than the source URI. "
2658
                                  "MOVE or COPY between repositories is "
2659
                                  "not possible.");
2660
    }
3322
    }
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
    }
3323
    }
2668
3324
3325
    // recheck remote, maybe it changed
3326
    if (!remote) {
2669
    /* quick failure test: if dest exists and overwrite is false. */
3327
    /* quick failure test: if dest exists and overwrite is false. */
2670
    if (resnew->exists && !overwrite) {
3328
    if (resnew->exists && !overwrite) {
2671
        /* Supply some text for the error response body. */
3329
        /* Supply some text for the error response body. */
Lines 2679-2685 Link Here
2679
        /* Supply some text for the error response body. */
3337
        /* Supply some text for the error response body. */
2680
        return dav_error_response(r, HTTP_FORBIDDEN,
3338
        return dav_error_response(r, HTTP_FORBIDDEN,
2681
                                  "Source and Destination URIs are the same.");
3339
                                  "Source and Destination URIs are the same.");
2682
3340
    	}
2683
    }
3341
    }
2684
3342
2685
    is_dir = resource->collection;
3343
    is_dir = resource->collection;
Lines 2732-2737 Link Here
2732
        return dav_handle_err(r, err, multi_response);
3390
        return dav_handle_err(r, err, multi_response);
2733
    }
3391
    }
2734
3392
3393
    if (!remote)
3394
    {
2735
    /*
3395
    /*
2736
     * Check If-Headers and existing locks for destination. Note that we
3396
     * Check If-Headers and existing locks for destination. Note that we
2737
     * use depth==infinity since the target (hierarchy) will be deleted
3397
     * use depth==infinity since the target (hierarchy) will be deleted
Lines 2778-2783 Link Here
2778
                                  "Destination collection contains the Source "
3438
                                  "Destination collection contains the Source "
2779
                                  "and Overwrite has been specified.");
3439
                                  "and Overwrite has been specified.");
2780
    }
3440
    }
3441
    }
2781
3442
2782
    /* ### for now, we don't need anything in the body */
3443
    /* ### for now, we don't need anything in the body */
2783
    if ((result = ap_discard_request_body(r)) != OK) {
3444
    if ((result = ap_discard_request_body(r)) != OK) {
Lines 2818-2823 Link Here
2818
        }
3479
        }
2819
    }
3480
    }
2820
3481
3482
    if (!remote)
3483
    {
2821
    /*
3484
    /*
2822
     * Remember the initial state of the destination, so the lock system
3485
     * Remember the initial state of the destination, so the lock system
2823
     * can be notified as to how it changed.
3486
     * can be notified as to how it changed.
Lines 2894-2906 Link Here
2894
    /* perform any auto-versioning cleanup */
3557
    /* perform any auto-versioning cleanup */
2895
    err2 = dav_auto_checkin(r, NULL, err != NULL /* undo if error */,
3558
    err2 = dav_auto_checkin(r, NULL, err != NULL /* undo if error */,
2896
                            0 /*unlock*/, &dst_av_info);
3559
                            0 /*unlock*/, &dst_av_info);
3560
    }
2897
3561
2898
    if (is_move) {
3562
    if (is_move) {
2899
        err3 = dav_auto_checkin(r, NULL, err != NULL /* undo if error */,
3563
        err3 = dav_auto_checkin(r, NULL, err != NULL /* undo if error */,
2900
                                0 /*unlock*/, &src_av_info);
3564
                                0 /*unlock*/, &src_av_info);
2901
    }
3565
    }
2902
    else
2903
        err3 = NULL;
2904
3566
2905
    /* check for error from remove/copy/move operations */
3567
    /* check for error from remove/copy/move operations */
2906
    if (err != NULL) {
3568
    if (err != NULL) {
Lines 2935-2940 Link Here
2935
        dav_log_err(r, err, APLOG_WARNING);
3597
        dav_log_err(r, err, APLOG_WARNING);
2936
    }
3598
    }
2937
3599
3600
    if (!remote) {
2938
    /* propagate any indirect locks at the target */
3601
    /* propagate any indirect locks at the target */
2939
    if (lockdb != NULL) {
3602
    if (lockdb != NULL) {
2940
3603
Lines 2953-2962 Link Here
2953
            return dav_handle_err(r, err, NULL);
3616
            return dav_handle_err(r, err, NULL);
2954
        }
3617
        }
2955
    }
3618
    }
3619
    }
3620
3621
    if (remote) {
3622
    	if (NULL != (err = dav_remote_copymove(r, resource, dest, overwrite, depth))) {
3623
    		return dav_handle_err(r, err, NULL);
3624
    	}
3625
3626
    	if (is_move) {
3627
    		if (NULL != (err = (*resource->hooks->remove_resource)(resource, &multi_response))) {
3628
    			return dav_handle_err(r, err, NULL);
3629
    		}
3630
    	}
2956
3631
2957
    /* return an appropriate response (HTTP_CREATED or HTTP_NO_CONTENT) */
3632
    /* return an appropriate response (HTTP_CREATED or HTTP_NO_CONTENT) */
3633
    	return dav_created(r, dest, "Destination", 0);
3634
    }
3635
    else {
3636
    	/* return an appropriate response (HTTP_CREATED or HTTP_NO_CONTENT) */
2958
    return dav_created(r, lookup.rnew->uri, "Destination",
3637
    return dav_created(r, lookup.rnew->uri, "Destination",
2959
                       resnew_state == DAV_RESOURCE_EXISTS);
3638
                       resnew_state == DAV_RESOURCE_EXISTS);
3639
    }
2960
}
3640
}
2961
3641
2962
/* dav_method_lock:  Handler to implement the DAV LOCK method
3642
/* 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