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 |