* www/release-process.html
[svn.git] / subversion / mod_dav_svn / mirror.c
blob03d7154e34de05a89c91fb7e38d051d465d9b004
1 /*
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>
21 #include <httpd.h>
22 #include <http_core.h>
24 #include "dav_svn.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) {
34 const char *seg;
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) {
41 return OK;
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,
52 "/", seg, NULL);
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);
59 return OK;
62 typedef struct locate_ctx_t
64 const apr_strmatch_pattern *pattern;
65 apr_size_t pattern_len;
66 apr_uri_t uri;
67 const char *localpath;
68 apr_size_t localpath_len;
69 const char *remotepath;
70 apr_size_t remotepath_len;
71 } locate_ctx_t;
73 apr_status_t dav_svn__location_in_filter(ap_filter_t *f,
74 apr_bucket_brigade *bb,
75 ap_input_mode_t mode,
76 apr_read_type_e block,
77 apr_off_t readbytes)
79 request_rec *r = f->r;
80 locate_ctx_t *ctx = f->ctx;
81 apr_status_t rv;
82 apr_bucket *bkt;
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);
92 if (!f->ctx) {
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);
105 if (rv) {
106 return rv;
109 bkt = APR_BRIGADE_FIRST(bb);
110 while (bkt != APR_BRIGADE_SENTINEL(bb)) {
112 const char *data, *match;
113 apr_size_t len;
115 if (APR_BUCKET_IS_METADATA(bkt)) {
116 bkt = APR_BUCKET_NEXT(bkt);
117 continue;
120 /* read */
121 apr_bucket_read(bkt, &data, &len, APR_BLOCK_READ);
122 match = apr_strmatch(ctx->pattern, data, len);
123 if (match) {
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,
131 ctx->remotepath_len,
132 r->pool, bb->bucket_alloc);
133 APR_BUCKET_INSERT_BEFORE(bkt, next_bucket);
135 else {
136 bkt = APR_BUCKET_NEXT(bkt);
139 return APR_SUCCESS;
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");
154 if (location) {
155 start_foo = ap_strstr_c(location, master_uri);
157 if (start_foo) {
158 const char *new_uri;
159 start_foo += strlen(master_uri);
160 new_uri = ap_construct_url(r->pool,
161 apr_pstrcat(r->pool,
162 dav_svn__get_root_dir(r),
163 start_foo, NULL),
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;
177 apr_bucket *bkt;
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);
187 if (!f->ctx) {
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;
203 apr_size_t len;
205 /* read */
206 apr_bucket_read(bkt, &data, &len, APR_BLOCK_READ);
207 match = apr_strmatch(ctx->pattern, data, len);
208 if (match) {
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,
216 ctx->localpath_len,
217 r->pool, bb->bucket_alloc);
218 APR_BUCKET_INSERT_BEFORE(bkt, next_bucket);
220 else {
221 bkt = APR_BUCKET_NEXT(bkt);
224 return ap_pass_brigade(f->next, bb);