2 * mirror.c: Use a transparent proxy to mirror Subversion instances.
4 * ====================================================================
5 * Copyright (c) 2000-2004 CollabNet. All rights reserved.
7 * This software is licensed as described in the file COPYING, which
8 * you should have received as part of this distribution. The terms
9 * are also available at http://subversion.tigris.org/license-1.html.
10 * If newer versions of this license are posted there, you may use a
11 * newer version instead, at your option.
13 * This software consists of voluntary contributions made by many
14 * individuals. For exact contribution history, see the revision
15 * history and logs, available at http://subversion.tigris.org/.
16 * ====================================================================
19 #include <apr_strmatch.h>
22 #include <http_core.h>
26 int dav_svn__proxy_merge_fixup(request_rec
*r
)
28 const char *root_dir
, *master_uri
;
30 root_dir
= dav_svn__get_root_dir(r
);
31 master_uri
= dav_svn__get_master_uri(r
);
33 if (root_dir
&& master_uri
) {
36 /* We know we can always safely handle these. */
37 if (r
->method_number
== M_PROPFIND
||
38 r
->method_number
== M_GET
||
39 r
->method_number
== M_REPORT
||
40 r
->method_number
== M_OPTIONS
) {
44 seg
= ap_strstr(r
->unparsed_uri
, root_dir
);
45 if (seg
&& (r
->method_number
== M_MERGE
||
46 ap_strstr_c(seg
, dav_svn__get_special_uri(r
)))) {
47 seg
+= strlen(root_dir
);
49 r
->proxyreq
= PROXYREQ_REVERSE
;
50 r
->uri
= r
->unparsed_uri
;
51 r
->filename
= apr_pstrcat(r
->pool
, "proxy:", master_uri
,
53 r
->handler
= "proxy-server";
54 ap_add_output_filter("LocationRewrite", NULL
, r
, r
->connection
);
55 ap_add_output_filter("ReposRewrite", NULL
, r
, r
->connection
);
56 ap_add_input_filter("IncomingRewrite", NULL
, r
, r
->connection
);
62 typedef struct locate_ctx_t
64 const apr_strmatch_pattern
*pattern
;
65 apr_size_t pattern_len
;
67 const char *localpath
;
68 apr_size_t localpath_len
;
69 const char *remotepath
;
70 apr_size_t remotepath_len
;
73 apr_status_t
dav_svn__location_in_filter(ap_filter_t
*f
,
74 apr_bucket_brigade
*bb
,
76 apr_read_type_e block
,
79 request_rec
*r
= f
->r
;
80 locate_ctx_t
*ctx
= f
->ctx
;
83 const char *master_uri
;
85 master_uri
= dav_svn__get_master_uri(r
);
87 if (r
->main
|| !master_uri
) {
88 ap_remove_input_filter(f
);
89 return ap_get_brigade(f
->next
, bb
, mode
, block
, readbytes
);
93 ctx
= f
->ctx
= apr_pcalloc(r
->pool
, sizeof(*ctx
));
95 apr_uri_parse(r
->pool
, master_uri
, &ctx
->uri
);
96 ctx
->remotepath
= ctx
->uri
.path
;
97 ctx
->remotepath_len
= strlen(ctx
->remotepath
);
98 ctx
->localpath
= dav_svn__get_root_dir(r
);
99 ctx
->localpath_len
= strlen(ctx
->localpath
);
100 ctx
->pattern
= apr_strmatch_precompile(r
->pool
, ctx
->localpath
, 0);
101 ctx
->pattern_len
= ctx
->localpath_len
;
104 rv
= ap_get_brigade(f
->next
, bb
, mode
, block
, readbytes
);
109 bkt
= APR_BRIGADE_FIRST(bb
);
110 while (bkt
!= APR_BRIGADE_SENTINEL(bb
)) {
112 const char *data
, *match
;
115 if (APR_BUCKET_IS_METADATA(bkt
)) {
116 bkt
= APR_BUCKET_NEXT(bkt
);
121 apr_bucket_read(bkt
, &data
, &len
, APR_BLOCK_READ
);
122 match
= apr_strmatch(ctx
->pattern
, data
, len
);
124 apr_bucket
*next_bucket
;
125 apr_bucket_split(bkt
, match
- data
);
126 next_bucket
= APR_BUCKET_NEXT(bkt
);
127 apr_bucket_split(next_bucket
, ctx
->pattern_len
);
128 bkt
= APR_BUCKET_NEXT(next_bucket
);
129 apr_bucket_delete(next_bucket
);
130 next_bucket
= apr_bucket_pool_create(ctx
->remotepath
,
132 r
->pool
, bb
->bucket_alloc
);
133 APR_BUCKET_INSERT_BEFORE(bkt
, next_bucket
);
136 bkt
= APR_BUCKET_NEXT(bkt
);
142 apr_status_t
dav_svn__location_header_filter(ap_filter_t
*f
,
143 apr_bucket_brigade
*bb
)
145 request_rec
*r
= f
->r
;
146 const char *master_uri
;
148 master_uri
= dav_svn__get_master_uri(r
);
150 if (!r
->main
&& master_uri
) {
151 const char *location
, *start_foo
= NULL
;
153 location
= apr_table_get(r
->headers_out
, "Location");
155 start_foo
= ap_strstr_c(location
, master_uri
);
159 start_foo
+= strlen(master_uri
);
160 new_uri
= ap_construct_url(r
->pool
,
162 dav_svn__get_root_dir(r
),
165 apr_table_set(r
->headers_out
, "Location", new_uri
);
168 ap_remove_output_filter(f
);
169 return ap_pass_brigade(f
->next
, bb
);
172 apr_status_t
dav_svn__location_body_filter(ap_filter_t
*f
,
173 apr_bucket_brigade
*bb
)
175 request_rec
*r
= f
->r
;
176 locate_ctx_t
*ctx
= f
->ctx
;
178 const char *master_uri
;
180 master_uri
= dav_svn__get_master_uri(r
);
182 if (r
->main
|| !master_uri
) {
183 ap_remove_output_filter(f
);
184 return ap_pass_brigade(f
->next
, bb
);
188 ctx
= f
->ctx
= apr_pcalloc(r
->pool
, sizeof(*ctx
));
190 apr_uri_parse(r
->pool
, master_uri
, &ctx
->uri
);
191 ctx
->remotepath
= ctx
->uri
.path
;
192 ctx
->remotepath_len
= strlen(ctx
->remotepath
);
193 ctx
->localpath
= dav_svn__get_root_dir(r
);
194 ctx
->localpath_len
= strlen(ctx
->localpath
);
195 ctx
->pattern
= apr_strmatch_precompile(r
->pool
, ctx
->remotepath
, 0);
196 ctx
->pattern_len
= ctx
->remotepath_len
;
199 bkt
= APR_BRIGADE_FIRST(bb
);
200 while (bkt
!= APR_BRIGADE_SENTINEL(bb
)) {
202 const char *data
, *match
;
206 apr_bucket_read(bkt
, &data
, &len
, APR_BLOCK_READ
);
207 match
= apr_strmatch(ctx
->pattern
, data
, len
);
209 apr_bucket
*next_bucket
;
210 apr_bucket_split(bkt
, match
- data
);
211 next_bucket
= APR_BUCKET_NEXT(bkt
);
212 apr_bucket_split(next_bucket
, ctx
->pattern_len
);
213 bkt
= APR_BUCKET_NEXT(next_bucket
);
214 apr_bucket_delete(next_bucket
);
215 next_bucket
= apr_bucket_pool_create(ctx
->localpath
,
217 r
->pool
, bb
->bucket_alloc
);
218 APR_BUCKET_INSERT_BEFORE(bkt
, next_bucket
);
221 bkt
= APR_BUCKET_NEXT(bkt
);
224 return ap_pass_brigade(f
->next
, bb
);