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 |
DAV_DECLARE(dav_error *) dav_remote_copymove_create_socket(apr_pool_t *p, apr_sockaddr_t *addr, apr_socket_t **newsock) |
2555 |
{ |
2556 |
apr_status_t rv; |
2557 |
|
2558 |
while (addr) { |
2559 |
if ((rv = apr_socket_create(newsock, addr->family, |
2560 |
SOCK_STREAM, 0, p)) != APR_SUCCESS) { |
2561 |
/* |
2562 |
* this could be an IPv6 address from the DNS but the |
2563 |
* local machine won't give us an IPv6 socket; hopefully the |
2564 |
* DNS returned an additional address to try |
2565 |
*/ |
2566 |
addr = addr->next; |
2567 |
continue; |
2568 |
} |
2569 |
|
2570 |
rv = apr_socket_connect(*newsock, addr); |
2571 |
|
2572 |
/* if an error occurred, loop round and try again */ |
2573 |
if (rv != APR_SUCCESS) { |
2574 |
apr_socket_close(*newsock); |
2575 |
addr = addr->next; |
2576 |
continue; |
2577 |
} |
2578 |
|
2579 |
return 0; |
2580 |
} |
2581 |
|
2582 |
// TODO: good error code? |
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 |
rp->request_config = ap_create_request_config(r->pool); |
2645 |
rp->per_dir_config = r->per_dir_config; // hope it will not crash |
2646 |
} |
2647 |
|
2648 |
DAV_DECLARE(dav_error *) dav_remote_set_connection(request_rec *r, apr_uri_t *resource_uri) |
2649 |
{ |
2650 |
dav_error *err; |
2651 |
conn_rec *conn; |
2652 |
|
2653 |
if (r->connection) { |
2654 |
return 0; |
2655 |
} |
2656 |
if (NULL != (err = dav_remote_create_connection(r->pool, resource_uri, r->server, &conn))) { |
2657 |
return err; |
2658 |
} |
2659 |
|
2660 |
r->connection = conn; |
2661 |
r->output_filters = conn->output_filters; |
2662 |
r->input_filters = conn->input_filters; |
2663 |
r->proto_output_filters = conn->output_filters; |
2664 |
r->proto_input_filters = conn->input_filters; |
2665 |
|
2666 |
return 0; |
2667 |
} |
2668 |
|
2669 |
DAV_DECLARE(dav_error *) dav_remote_send_resource_content(request_rec *r, dav_resource *resource) |
2670 |
{ |
2671 |
dav_error *err; |
2672 |
apr_bucket_brigade *request_brigade; |
2673 |
apr_bucket *e; |
2674 |
apr_status_t rv; |
2675 |
|
2676 |
/* okay... time to deliver the content */ |
2677 |
if ((err = (*resource->hooks->deliver)(resource, |
2678 |
r->output_filters)) != NULL) { |
2679 |
return dav_push_error(r->pool, err->status, 0, |
2680 |
"Unable to deliver content.", |
2681 |
err); |
2682 |
} |
2683 |
|
2684 |
request_brigade = apr_brigade_create(r->pool, r->connection->bucket_alloc); |
2685 |
|
2686 |
e = apr_bucket_flush_create(r->connection->bucket_alloc); |
2687 |
APR_BRIGADE_INSERT_TAIL(request_brigade, e); |
2688 |
|
2689 |
rv = ap_pass_brigade(r->output_filters, request_brigade); |
2690 |
|
2691 |
return NULL; |
2692 |
} |
2693 |
|
2694 |
struct dav_remote_send_headers_wrapper { |
2695 |
apr_bucket_alloc_t *bucket_alloc; |
2696 |
apr_bucket_brigade *request_brigade; |
2697 |
apr_pool_t *p; |
2698 |
}; |
2699 |
|
2700 |
int dav_remote_send_headers(void *rec, const char *key, const char *value) |
2701 |
{ |
2702 |
struct dav_remote_send_headers_wrapper *wrapper = (struct dav_remote_send_headers_wrapper *)rec; |
2703 |
|
2704 |
apr_bucket_brigade *request_brigade = wrapper->request_brigade; |
2705 |
apr_bucket *e; |
2706 |
char *buf; |
2707 |
|
2708 |
buf = apr_pstrcat(wrapper->p, key, ": ", value, CRLF, NULL); |
2709 |
e = apr_bucket_pool_create(buf, strlen(buf), wrapper->p, wrapper->bucket_alloc); |
2710 |
ap_xlate_proto_to_ascii(buf, strlen(buf)); |
2711 |
APR_BRIGADE_INSERT_TAIL(request_brigade, e); |
2712 |
} |
2713 |
|
2714 |
DAV_DECLARE(dav_error *) dav_remote_read_status_line(request_rec *r) |
2715 |
{ |
2716 |
apr_bucket_brigade *response_brigade; |
2717 |
|
2718 |
char buff[HUGE_STRING_LEN]; |
2719 |
char *buff_p = buff; |
2720 |
char keepchar; |
2721 |
apr_size_t len; |
2722 |
|
2723 |
response_brigade = apr_brigade_create(r->pool, r->connection->bucket_alloc); |
2724 |
ap_rgetline(&buff_p, sizeof(buff), &len, r, 0, response_brigade); |
2725 |
|
2726 |
if (!apr_date_checkmask(buff, "HTTP/#.# ###*")) { |
2727 |
return dav_new_error(r->pool, HTTP_BAD_GATEWAY, 0, "Invalid response status line"); |
2728 |
} |
2729 |
|
2730 |
int major, minor; |
2731 |
|
2732 |
if (2 != sscanf(buff, "HTTP/%u.%u", &major, &minor)) { |
2733 |
major = 1; |
2734 |
minor = 1; |
2735 |
} |
2736 |
else if ((buff[5] != '1') || (len >= sizeof(buff) - 1)) { |
2737 |
return dav_new_error(r->pool, HTTP_BAD_GATEWAY, 0, "Invalid response status line"); |
2738 |
} |
2739 |
|
2740 |
keepchar = buff[12]; |
2741 |
buff[12] = '\0'; |
2742 |
r->status = atoi(&buff[9]); |
2743 |
|
2744 |
if (keepchar != '\0') { |
2745 |
buff[12] = keepchar; |
2746 |
} else { |
2747 |
/* 2616 requires the space in Status-Line; the origin |
2748 |
* server may have sent one but ap_rgetline_core will |
2749 |
* have stripped it. */ |
2750 |
buff[12] = ' '; |
2751 |
buff[13] = '\0'; |
2752 |
} |
2753 |
r->status_line = apr_pstrdup(r->pool, &buff[9]); |
2754 |
|
2755 |
return 0; |
2756 |
} |
2757 |
|
2758 |
DAV_DECLARE(dav_error *) dav_remote_read_response_headers(request_rec *r) |
2759 |
{ |
2760 |
dav_error *err; |
2761 |
apr_bucket_brigade *response_brigade; |
2762 |
apr_size_t len; |
2763 |
apr_status_t rv; |
2764 |
char buff[HUGE_STRING_LEN]; |
2765 |
char *buff_p = buff; |
2766 |
char *value, *end; |
2767 |
|
2768 |
apr_table_clear(r->headers_in); |
2769 |
|
2770 |
response_brigade = apr_brigade_create(r->pool, r->connection->bucket_alloc); |
2771 |
if (APR_SUCCESS != (rv = ap_rgetline(&buff_p, sizeof(buff), &len, r, 0, response_brigade))) { |
2772 |
return dav_new_error(r->pool, HTTP_BAD_GATEWAY, 0, "Error reading response header"); |
2773 |
} |
2774 |
|
2775 |
while (0 < len) { |
2776 |
if (!(value = strchr(buff, ':'))) { |
2777 |
if (APR_SUCCESS != (rv = ap_rgetline(&buff_p, sizeof(buff), &len, r, 0, response_brigade))) { |
2778 |
return dav_new_error(r->pool, HTTP_BAD_GATEWAY, 0, "Error reading response header"); |
2779 |
} |
2780 |
} |
2781 |
|
2782 |
*value = '\0'; |
2783 |
++value; |
2784 |
/* XXX: RFC2068 defines only SP and HT as whitespace, this test is |
2785 |
* wrong... and so are many others probably. |
2786 |
*/ |
2787 |
while (apr_isspace(*value)) |
2788 |
++value; /* Skip to start of value */ |
2789 |
|
2790 |
/* should strip trailing whitespace as well */ |
2791 |
for (end = &value[strlen(value)-1]; end > value && apr_isspace(*end); --end) |
2792 |
*end = '\0'; |
2793 |
|
2794 |
apr_table_add(r->headers_in, buff, value); |
2795 |
|
2796 |
if (APR_SUCCESS != (rv = ap_rgetline(&buff_p, sizeof(buff), &len, r, 0, response_brigade))) { |
2797 |
return dav_new_error(r->pool, HTTP_BAD_GATEWAY, 0, "Error reading response header"); |
2798 |
} |
2799 |
} |
2800 |
|
2801 |
return 0; |
2802 |
} |
2803 |
|
2804 |
typedef dav_error * (* write_request_content_callback) (request_rec *, void *data); |
2805 |
typedef dav_error * (* read_reponse_content_callback) (request_rec *, void *data); |
2806 |
|
2807 |
DAV_DECLARE(dav_error *) dav_remote_skip_response_content(request_rec *r, void *unused) |
2808 |
{ |
2809 |
apr_size_t content_length; |
2810 |
apr_size_t to_read; |
2811 |
apr_bucket_brigade *response_brigade; |
2812 |
apr_bucket *e; |
2813 |
int seen_eos; |
2814 |
const char *content_length_str; |
2815 |
apr_bucket_alloc_t *bucket_alloc = r->connection->bucket_alloc; |
2816 |
char buff[HUGE_STRING_LEN]; |
2817 |
char *buff_p = buff; |
2818 |
|
2819 |
if (NULL == apr_table_get(r->headers_in, "Keep-Alive")) { // we can close the connection now |
2820 |
dav_remote_close_connection(r); |
2821 |
return 0; |
2822 |
} |
2823 |
|
2824 |
content_length_str = apr_table_get(r->headers_in, "Content-Length"); |
2825 |
if (!content_length_str) { |
2826 |
return 0; // no content |
2827 |
} |
2828 |
|
2829 |
content_length = atoi(content_length_str); |
2830 |
if (!content_length) { |
2831 |
return 0; // no content |
2832 |
} |
2833 |
|
2834 |
if (content_length < 0) { |
2835 |
dav_remote_close_connection(r); |
2836 |
return dav_new_error(r->pool, HTTP_BAD_GATEWAY, 0, "Invalid Content-Length of response"); |
2837 |
} |
2838 |
|
2839 |
while (0 < content_length) { |
2840 |
response_brigade = apr_brigade_create(r->pool, bucket_alloc); |
2841 |
|
2842 |
do { |
2843 |
apr_status_t rc; |
2844 |
|
2845 |
rc = ap_get_brigade(r->input_filters, response_brigade, AP_MODE_READBYTES, |
2846 |
APR_BLOCK_READ, DAV_READ_BLOCKSIZE); |
2847 |
|
2848 |
if (rc != APR_SUCCESS) { |
2849 |
return dav_new_error(r->pool, HTTP_INTERNAL_SERVER_ERROR, 0, |
2850 |
"Could not get next bucket brigade"); |
2851 |
} |
2852 |
|
2853 |
for (e = APR_BRIGADE_FIRST(response_brigade); |
2854 |
e != APR_BRIGADE_SENTINEL(response_brigade); |
2855 |
e = APR_BUCKET_NEXT(e)) |
2856 |
{ |
2857 |
const char *data; |
2858 |
apr_size_t len; |
2859 |
|
2860 |
if (APR_BUCKET_IS_EOS(e)) { |
2861 |
seen_eos = 1; |
2862 |
break; |
2863 |
} |
2864 |
|
2865 |
if (APR_BUCKET_IS_METADATA(e)) { |
2866 |
continue; |
2867 |
} |
2868 |
|
2869 |
rc = apr_bucket_read(e, &data, &len, APR_BLOCK_READ); |
2870 |
content_length -= len; |
2871 |
|
2872 |
if (rc != APR_SUCCESS) { |
2873 |
return dav_new_error(r->pool, HTTP_BAD_REQUEST, 0, |
2874 |
"An error occurred while reading " |
2875 |
"the request body."); |
2876 |
} |
2877 |
} |
2878 |
|
2879 |
apr_brigade_cleanup(response_brigade); |
2880 |
} while (!seen_eos); |
2881 |
|
2882 |
|
2883 |
|
2884 |
} |
2885 |
|
2886 |
return 0; |
2887 |
} |
2888 |
|
2889 |
DAV_DECLARE(dav_error *) dav_remote_method_request(request_rec *r, const char *method, apr_uri_t *resource_uri, |
2890 |
const char *resource_path, dav_resource *resource, |
2891 |
write_request_content_callback write_request_content, void *write_request_content_data, |
2892 |
read_reponse_content_callback read_response_content, void *read_response_content_data) |
2893 |
{ |
2894 |
apr_status_t rv; |
2895 |
dav_error *err; |
2896 |
apr_bucket_alloc_t *bucket_alloc = r->connection->bucket_alloc; |
2897 |
apr_bucket_brigade *request_brigade; |
2898 |
apr_bucket *e; |
2899 |
char *buf; |
2900 |
|
2901 |
// as I see nobody in httpd check for NULL results of malloc/apr_palloc, so why I should? |
2902 |
request_brigade = apr_brigade_create(r->pool, bucket_alloc); |
2903 |
|
2904 |
buf = apr_pstrcat(r->pool, method, " ", resource_uri->path, " HTTP/1.1", CRLF, NULL); |
2905 |
e = apr_bucket_pool_create(buf, strlen(buf), r->pool, bucket_alloc); |
2906 |
ap_xlate_proto_to_ascii(buf, strlen(buf)); |
2907 |
APR_BRIGADE_INSERT_TAIL(request_brigade, e); |
2908 |
|
2909 |
struct dav_remote_send_headers_wrapper wrapper; |
2910 |
wrapper.bucket_alloc = bucket_alloc; |
2911 |
wrapper.request_brigade = request_brigade; |
2912 |
wrapper.p = r->pool; |
2913 |
|
2914 |
apr_table_do(dav_remote_send_headers, &wrapper, r->headers_out, 0); |
2915 |
|
2916 |
buf = apr_pstrcat(r->pool, CRLF, NULL); |
2917 |
e = apr_bucket_pool_create(buf, strlen(buf), r->pool, bucket_alloc); |
2918 |
ap_xlate_proto_to_ascii(buf, strlen(buf)); |
2919 |
APR_BRIGADE_INSERT_TAIL(request_brigade, e); |
2920 |
|
2921 |
e = apr_bucket_flush_create(bucket_alloc); |
2922 |
APR_BRIGADE_INSERT_TAIL(request_brigade, e); |
2923 |
|
2924 |
rv = ap_pass_brigade(r->output_filters, request_brigade); |
2925 |
|
2926 |
if (NULL != write_request_content) { |
2927 |
write_request_content(r, write_request_content_data); |
2928 |
} |
2929 |
|
2930 |
if (rv != APR_SUCCESS) { |
2931 |
return dav_new_error(r->pool, HTTP_INTERNAL_SERVER_ERROR, 0, "Sending request failed"); |
2932 |
} |
2933 |
|
2934 |
if (NULL != (err = dav_remote_read_status_line(r))) { |
2935 |
return dav_push_error(r->pool, err->status, 0, "read_status in dav_remote_method_request failed.", err); |
2936 |
} |
2937 |
|
2938 |
if (NULL != (err = dav_remote_read_response_headers(r))) { |
2939 |
return dav_push_error(r->pool, err->status, 0, "read_response_headers in dav_remote_method_request failed.", err); |
2940 |
} |
2941 |
|
2942 |
if (NULL == read_response_content) { |
2943 |
read_response_content = dav_remote_skip_response_content; |
2944 |
} |
2945 |
|
2946 |
if (NULL != (err = read_response_content(r, read_response_content_data))) { |
2947 |
return dav_push_error(r->pool, err->status, 0, "read_reponse_content_callback in dav_remote_method_request failed.", err); |
2948 |
} |
2949 |
|
2950 |
// MOVED PERMANENTLY - check with '/' at the end |
2951 |
if ((r->status == HTTP_MOVED_PERMANENTLY) && (resource_uri->path[strlen(resource_uri->path) - 1] != '/')) { |
2952 |
resource_path = apr_pstrcat(r->pool, resource_path, "/", NULL); |
2953 |
if (strcmp(resource_path, apr_table_get(r->headers_in, "Location")) != 0) { |
2954 |
return dav_new_error(r->pool, HTTP_INTERNAL_SERVER_ERROR, 0, "No idea what to do..."); |
2955 |
} |
2956 |
|
2957 |
resource_uri->path = apr_pstrcat(r->pool, resource_uri->path, "/", NULL); |
2958 |
|
2959 |
return dav_remote_method_request(r, method, resource_uri, resource_path, resource, NULL, NULL, NULL, NULL); |
2960 |
} |
2961 |
|
2962 |
return NULL; |
2963 |
} |
2964 |
|
2965 |
DAV_DECLARE(dav_error *) dav_remote_resource_exists(request_rec *r, apr_uri_t *resource_uri, const char *resource_path, dav_resource *resource, int *exists) |
2966 |
{ |
2967 |
dav_error *err; |
2968 |
conn_rec *conn; |
2969 |
|
2970 |
*exists = 0; |
2971 |
|
2972 |
if (NULL != (err = dav_remote_set_connection(r, resource_uri))) { |
2973 |
return dav_push_error(r->pool, err->status, 0, "Unable to create connection in dav_remote_resource_exists.", err); |
2974 |
} |
2975 |
|
2976 |
apr_table_clear(r->headers_out); |
2977 |
apr_table_add(r->headers_out, "Host", resource_uri->hostname); |
2978 |
apr_table_add(r->headers_out, "Content-Length", "0"); |
2979 |
apr_table_add(r->headers_out, "Depth", "0"); |
2980 |
apr_table_add(r->headers_out, "Connection", "Keep-Alive"); |
2981 |
|
2982 |
if (NULL != (err = dav_remote_method_request(r, "HEAD", resource_uri, resource_path, resource, NULL, NULL, NULL, NULL))) { |
2983 |
return dav_push_error(r->pool, err->status, 0, "HEAD in dav_remote_resource_exists failed.", err); |
2984 |
} |
2985 |
|
2986 |
*exists = r->status != 404; |
2987 |
return 0; |
2988 |
} |
2989 |
|
2990 |
DAV_DECLARE(dav_error *) dav_remote_resource_delete(request_rec *r, apr_uri_t *resource_uri, const char *resource_path, dav_resource *resource, int *deleted) |
2991 |
{ |
2992 |
dav_error *err; |
2993 |
conn_rec *conn; |
2994 |
|
2995 |
if (NULL != (err = dav_remote_set_connection(r, resource_uri))) { |
2996 |
return dav_push_error(r->pool, err->status, 0, "Unable to create connection in dav_remote_resource_delete.", err); |
2997 |
} |
2998 |
|
2999 |
apr_table_clear(r->headers_out); |
3000 |
apr_table_add(r->headers_out, "Host", resource_uri->hostname); |
3001 |
apr_table_add(r->headers_out, "Content-Length", "0"); |
3002 |
apr_table_add(r->headers_out, "Connection", "Keep-Alive"); |
3003 |
|
3004 |
if (NULL != (err = dav_remote_method_request(r, "DELETE", resource_uri, resource_path, resource, NULL, NULL, NULL, NULL))) { |
3005 |
return dav_push_error(r->pool, err->status, 0, "DELETE in dav_remote_resource_delete failed.", err); |
3006 |
} |
3007 |
|
3008 |
*deleted = r->status == 200 || r->status == 202 || r->status == 204 || r->status == 404; |
3009 |
|
3010 |
return 0; |
3011 |
} |
3012 |
|
3013 |
DAV_DECLARE(dav_error *) dav_remote_resource_put(request_rec *r, apr_uri_t *resource_uri, const char *resource_path, dav_resource *resource) |
3014 |
{ |
3015 |
dav_error *err; |
3016 |
conn_rec *conn; |
3017 |
|
3018 |
if (NULL != (err = dav_remote_set_connection(r, resource_uri))) { |
3019 |
return dav_push_error(r->pool, err->status, 0, "Unable to create connection in dav_remote_resource_delete.", err); |
3020 |
} |
3021 |
|
3022 |
apr_table_clear(r->headers_out); |
3023 |
apr_table_add(r->headers_out, "Host", resource_uri->hostname); |
3024 |
apr_table_add(r->headers_out, "Connection", "Keep-Alive"); |
3025 |
|
3026 |
if ((err = (*resource->hooks->set_headers)(r, resource)) != NULL) { |
3027 |
return dav_push_error(r->pool, err->status, 0, |
3028 |
"Unable to set up HTTP headers.", |
3029 |
err); |
3030 |
} |
3031 |
|
3032 |
if (NULL != (err = dav_remote_method_request(r, "PUT", resource_uri, resource_path, resource, |
3033 |
dav_remote_send_resource_content, resource, |
3034 |
NULL, NULL))) { |
3035 |
return dav_push_error(r->pool, err->status, 0, "DELETE in dav_remote_resource_delete failed.", err); |
3036 |
} |
3037 |
|
3038 |
if (r->status != 201 && r->status != 204) { |
3039 |
return dav_new_error(r->pool, r->status, 0, "Remote server does not accept resource"); |
3040 |
} |
3041 |
|
3042 |
return 0; |
3043 |
} |
3044 |
|
3045 |
static int dav_remote_copymove(request_rec *r, dav_resource *resource, const char *dest, int is_move, int overwrite) |
3046 |
{ |
3047 |
dav_error *err; |
3048 |
apr_uri_t dest_uri; |
3049 |
conn_rec *conn; |
3050 |
request_rec *rp; |
3051 |
int exists; |
3052 |
int deleted; |
3053 |
|
3054 |
if (APR_SUCCESS != apr_uri_parse(r->pool, dest, &dest_uri)) { |
3055 |
ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, |
3056 |
"Destination URI cannot be parsed.", NULL); |
3057 |
return HTTP_BAD_REQUEST; |
3058 |
} |
3059 |
|
3060 |
if (!dest_uri.port) { |
3061 |
dest_uri.port = apr_uri_port_of_scheme(dest_uri.scheme); |
3062 |
} |
3063 |
|
3064 |
// 1. create request |
3065 |
rp = dav_remote_make_fake_request(r); |
3066 |
|
3067 |
|
3068 |
if (!overwrite) { |
3069 |
// 2. check if exists |
3070 |
if (NULL != (err = dav_remote_resource_exists(rp, &dest_uri, dest, resource, &exists))) { |
3071 |
return dav_handle_err(r, err, NULL); |
3072 |
} |
3073 |
|
3074 |
if (exists) |
3075 |
return HTTP_PRECONDITION_FAILED; |
3076 |
} |
3077 |
else { |
3078 |
// 2. delete old resource |
3079 |
if (NULL != (err = dav_remote_resource_delete(rp, &dest_uri, dest, resource, &deleted))) { |
3080 |
return dav_handle_err(r, err, NULL); |
3081 |
} |
3082 |
|
3083 |
if (!deleted) |
3084 |
return HTTP_FORBIDDEN; |
3085 |
} |
3086 |
|
3087 |
// 3. send content |
3088 |
if ((err = dav_remote_resource_put(rp, &dest_uri, dest, resource)) != NULL) { |
3089 |
return dav_handle_err(r, err, NULL); |
3090 |
} |
3091 |
|
3092 |
return HTTP_NO_CONTENT; |
3093 |
} |
3094 |
|
2553 |
/* handle the COPY and MOVE methods */ |
3095 |
/* handle the COPY and MOVE methods */ |
2554 |
static int dav_method_copymove(request_rec *r, int is_move) |
3096 |
static int dav_method_copymove(request_rec *r, int is_move) |
2555 |
{ |
3097 |
{ |
Lines 2609-2614
Link Here
|
2609 |
return HTTP_BAD_REQUEST; |
3151 |
return HTTP_BAD_REQUEST; |
2610 |
} |
3152 |
} |
2611 |
|
3153 |
|
|
|
3154 |
/* get and parse the overwrite header value */ |
3155 |
if ((overwrite = dav_get_overwrite(r)) < 0) { |
3156 |
/* dav_get_overwrite() supplies additional information for the |
3157 |
* default message. */ |
3158 |
return HTTP_BAD_REQUEST; |
3159 |
} |
3160 |
|
2612 |
lookup = dav_lookup_uri(dest, r, 1 /* must_be_absolute */); |
3161 |
lookup = dav_lookup_uri(dest, r, 1 /* must_be_absolute */); |
2613 |
if (lookup.rnew == NULL) { |
3162 |
if (lookup.rnew == NULL) { |
2614 |
if (lookup.err.status == HTTP_BAD_REQUEST) { |
3163 |
if (lookup.err.status == HTTP_BAD_REQUEST) { |
Lines 2618-2623
Link Here
|
2618 |
return HTTP_BAD_REQUEST; |
3167 |
return HTTP_BAD_REQUEST; |
2619 |
} |
3168 |
} |
2620 |
|
3169 |
|
|
|
3170 |
if (!is_move && lookup.err.status == HTTP_BAD_GATEWAY) { |
3171 |
err = dav_get_resource(r, 1 /* label_allowed */, 0 /* use_checked_in */, |
3172 |
&resource); |
3173 |
return dav_remote_copymove(r, resource, dest, is_move, overwrite); |
3174 |
} |
3175 |
|
2621 |
/* ### this assumes that dav_lookup_uri() only generates a status |
3176 |
/* ### this assumes that dav_lookup_uri() only generates a status |
2622 |
* ### that Apache can provide a status line for!! */ |
3177 |
* ### that Apache can provide a status line for!! */ |
2623 |
|
3178 |
|
Lines 2650-2669
Link Here
|
2650 |
return dav_handle_err(r, err, NULL); |
3206 |
return dav_handle_err(r, err, NULL); |
2651 |
|
3207 |
|
2652 |
/* are the two resources handled by the same repository? */ |
3208 |
/* are the two resources handled by the same repository? */ |
2653 |
if (resource->hooks != resnew->hooks) { |
3209 |
if (!is_move && resource->hooks != resnew->hooks) { |
|
|
3210 |
err = dav_get_resource(r, 1 /* label_allowed */, 0 /* use_checked_in */, |
3211 |
&resource); |
2654 |
/* ### this message exposes some backend config, but screw it... */ |
3212 |
/* ### this message exposes some backend config, but screw it... */ |
2655 |
return dav_error_response(r, HTTP_BAD_GATEWAY, |
3213 |
return dav_remote_copymove(r, resource, dest, is_move, overwrite); |
2656 |
"Destination URI is handled by a " |
|
|
2657 |
"different repository than the source URI. " |
2658 |
"MOVE or COPY between repositories is " |
2659 |
"not possible."); |
2660 |
} |
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 |
} |
3214 |
} |
2668 |
|
3215 |
|
2669 |
/* quick failure test: if dest exists and overwrite is false. */ |
3216 |
/* quick failure test: if dest exists and overwrite is false. */ |