97
83
const char *merge_resource_url; /* URL of resource to be merged. */
98
84
const char *merge_url; /* URL at which the MERGE request is aimed. */
104
86
svn_commit_info_t *commit_info;
92
#define S_ SVN_XML_NAMESPACE
93
static const svn_ra_serf__xml_transition_t merge_ttable[] = {
94
{ INITIAL, D_, "merge-response", MERGE_RESPONSE,
95
FALSE, { NULL }, FALSE },
97
{ MERGE_RESPONSE, D_, "updated-set", UPDATED_SET,
98
FALSE, { NULL }, FALSE },
100
{ UPDATED_SET, D_, "response", RESPONSE,
101
FALSE, { NULL }, TRUE },
103
{ RESPONSE, D_, "href", HREF,
104
TRUE, { NULL }, TRUE },
106
{ RESPONSE, D_, "propstat", PROPSTAT,
107
FALSE, { NULL }, FALSE },
111
{ PROPSTAT, D_, "status", STATUS,
112
FALSE, { NULL }, FALSE },
115
{ PROPSTAT, D_, "prop", PROP,
116
FALSE, { NULL }, FALSE },
118
{ PROP, D_, "resourcetype", RESOURCE_TYPE,
119
FALSE, { NULL }, FALSE },
121
{ RESOURCE_TYPE, D_, "baseline", BASELINE,
122
FALSE, { NULL }, TRUE },
124
{ RESOURCE_TYPE, D_, "collection", COLLECTION,
125
FALSE, { NULL }, TRUE },
127
{ PROP, D_, "checked-in", SKIP_HREF,
128
FALSE, { NULL }, FALSE },
130
{ SKIP_HREF, D_, "href", CHECKED_IN,
131
TRUE, { NULL }, TRUE },
133
{ PROP, D_, SVN_DAV__VERSION_NAME, VERSION_NAME,
134
TRUE, { NULL }, TRUE },
136
{ PROP, D_, SVN_DAV__CREATIONDATE, DATE,
137
TRUE, { NULL }, TRUE },
139
{ PROP, D_, "creator-displayname", AUTHOR,
140
TRUE, { NULL }, TRUE },
142
{ PROP, S_, "post-commit-err", POST_COMMIT_ERR,
143
TRUE, { NULL }, TRUE },
108
static merge_info_t *
109
push_state(svn_ra_serf__xml_parser_t *parser,
110
svn_ra_serf__merge_context_t *ctx,
115
svn_ra_serf__xml_push_state(parser, state);
117
if (state == RESPONSE)
119
info = apr_palloc(parser->state->pool, sizeof(*info));
120
info->pool = parser->state->pool;
121
info->props = apr_hash_make(info->pool);
123
parser->state->private = info;
126
return parser->state->private;
130
start_merge(svn_ra_serf__xml_parser_t *parser,
132
svn_ra_serf__dav_props_t name,
135
svn_ra_serf__merge_context_t *ctx = userData;
139
state = parser->state->current_state;
142
strcmp(name.name, "merge-response") == 0)
144
push_state(parser, ctx, MERGE_RESPONSE);
146
else if (state == NONE)
148
/* do nothing as we haven't seen our valid start tag yet. */
150
else if (state == MERGE_RESPONSE &&
151
strcmp(name.name, "updated-set") == 0)
153
push_state(parser, ctx, UPDATED_SET);
155
else if (state == UPDATED_SET &&
156
strcmp(name.name, "response") == 0)
158
push_state(parser, ctx, RESPONSE);
160
else if (state == RESPONSE &&
161
strcmp(name.name, "href") == 0)
163
info = push_state(parser, ctx, PROP_VAL);
165
info->prop_ns = name.namespace;
166
info->prop_name = apr_pstrdup(info->pool, name.name);
167
info->prop_val = NULL;
168
info->prop_val_len = 0;
170
else if (state == RESPONSE &&
171
strcmp(name.name, "propstat") == 0)
173
push_state(parser, ctx, PROPSTAT);
175
else if (state == PROPSTAT &&
176
strcmp(name.name, "prop") == 0)
178
push_state(parser, ctx, PROP);
180
else if (state == PROPSTAT &&
181
strcmp(name.name, "status") == 0)
183
/* Do nothing for now. */
185
else if (state == PROP &&
186
strcmp(name.name, "resourcetype") == 0)
188
info = push_state(parser, ctx, RESOURCE_TYPE);
191
else if (state == RESOURCE_TYPE &&
192
strcmp(name.name, "baseline") == 0)
194
info = parser->state->private;
196
info->type = BASELINE;
198
else if (state == RESOURCE_TYPE &&
199
strcmp(name.name, "collection") == 0)
201
info = parser->state->private;
203
info->type = COLLECTION;
205
else if (state == PROP &&
206
strcmp(name.name, "checked-in") == 0)
208
info = push_state(parser, ctx, IGNORE_PROP_NAME);
210
info->prop_ns = name.namespace;
211
info->prop_name = apr_pstrdup(info->pool, name.name);
212
info->prop_val = NULL;
213
info->prop_val_len = 0;
215
else if (state == PROP)
217
push_state(parser, ctx, PROP_VAL);
219
else if (state == IGNORE_PROP_NAME)
221
push_state(parser, ctx, PROP_VAL);
223
else if (state == NEED_PROP_NAME)
225
info = push_state(parser, ctx, PROP_VAL);
226
info->prop_ns = name.namespace;
227
info->prop_name = apr_pstrdup(info->pool, name.name);
228
info->prop_val = NULL;
229
info->prop_val_len = 0;
233
SVN_ERR_MALFUNCTION();
240
end_merge(svn_ra_serf__xml_parser_t *parser,
242
svn_ra_serf__dav_props_t name)
244
svn_ra_serf__merge_context_t *ctx = userData;
248
state = parser->state->current_state;
249
info = parser->state->private;
253
/* nothing to close yet. */
257
if (state == RESPONSE &&
258
strcmp(name.name, "response") == 0)
260
if (info->type == BASELINE)
149
/* Conforms to svn_ra_serf__xml_closed_t */
151
merge_closed(svn_ra_serf__xml_estate_t *xes,
154
const svn_string_t *cdata,
156
apr_pool_t *scratch_pool)
158
merge_context_t *merge_ctx = baton;
160
if (leaving_state == RESPONSE)
164
rtype = svn_hash_gets(attrs, "resourcetype");
166
/* rtype can only be "baseline" or "collection" (or NULL). We can
167
keep this check simple. */
168
if (rtype && *rtype == 'b')
264
str = apr_hash_get(info->props, SVN_DAV__VERSION_NAME,
265
APR_HASH_KEY_STRING);
268
ctx->commit_info->revision = SVN_STR_TO_REV(str);
172
rev_str = svn_hash_gets(attrs, "revision");
174
merge_ctx->commit_info->revision = SVN_STR_TO_REV(rev_str);
272
ctx->commit_info->revision = SVN_INVALID_REVNUM;
275
ctx->commit_info->date =
276
apr_pstrdup(ctx->pool,
277
apr_hash_get(info->props, SVN_DAV__CREATIONDATE,
278
APR_HASH_KEY_STRING));
280
ctx->commit_info->author =
281
apr_pstrdup(ctx->pool,
282
apr_hash_get(info->props, "creator-displayname",
283
APR_HASH_KEY_STRING));
285
ctx->commit_info->post_commit_err =
286
apr_pstrdup(ctx->pool,
287
apr_hash_get(info->props,
288
"post-commit-err", APR_HASH_KEY_STRING));
176
merge_ctx->commit_info->revision = SVN_INVALID_REVNUM;
178
merge_ctx->commit_info->date =
179
apr_pstrdup(merge_ctx->pool,
180
svn_hash_gets(attrs, "date"));
182
merge_ctx->commit_info->author =
183
apr_pstrdup(merge_ctx->pool,
184
svn_hash_gets(attrs, "author"));
186
merge_ctx->commit_info->post_commit_err =
187
apr_pstrdup(merge_ctx->pool,
188
svn_hash_gets(attrs, "post-commit-err"));
292
192
const char *href;
294
href = apr_hash_get(info->props, "href", APR_HASH_KEY_STRING);
295
if (! svn_urlpath__is_ancestor(ctx->merge_url, href))
297
return svn_error_createf(SVN_ERR_RA_DAV_REQUEST_FAILED, NULL,
298
_("A MERGE response for '%s' is not "
299
"a child of the destination ('%s')"),
300
href, ctx->merge_url);
194
href = svn_urlpath__skip_ancestor(
195
merge_ctx->merge_url,
196
svn_hash_gets(attrs, "href"));
199
return svn_error_createf(SVN_ERR_RA_DAV_REQUEST_FAILED, NULL,
200
_("A MERGE response for '%s' is not "
201
"a child of the destination ('%s')"),
202
href, merge_ctx->merge_url);
303
204
/* We now need to dive all the way into the WC to update the
306
if ((! SVN_RA_SERF__HAVE_HTTPV2_SUPPORT(ctx->session))
307
&& ctx->session->wc_callbacks->push_wc_prop)
206
if (!SVN_RA_SERF__HAVE_HTTPV2_SUPPORT(merge_ctx->session)
207
&& merge_ctx->session->wc_callbacks->push_wc_prop)
209
const char *checked_in;
309
210
svn_string_t checked_in_str;
310
const char *checked_in;
312
/* From the above check, we know that CTX->MERGE_URL is
313
an ancestor of HREF. All that remains is to
314
determine of HREF is the same as CTX->MERGE_URL, or --
315
if not -- is relative value as a child thereof. */
316
href = svn_urlpath__is_child(ctx->merge_url, href, NULL);
320
checked_in = apr_hash_get(info->props, "checked-in",
321
APR_HASH_KEY_STRING);
212
checked_in = svn_hash_gets(attrs, "checked-in");
322
213
checked_in_str.data = checked_in;
323
214
checked_in_str.len = strlen(checked_in);
325
SVN_ERR(ctx->session->wc_callbacks->push_wc_prop(
326
ctx->session->wc_callback_baton, href,
327
SVN_RA_SERF__WC_CHECKED_IN_URL, &checked_in_str, info->pool));
216
SVN_ERR(merge_ctx->session->wc_callbacks->push_wc_prop(
217
merge_ctx->session->wc_callback_baton,
219
SVN_RA_SERF__WC_CHECKED_IN_URL,
331
svn_ra_serf__xml_pop_state(parser);
333
else if (state == PROPSTAT &&
334
strcmp(name.name, "propstat") == 0)
336
svn_ra_serf__xml_pop_state(parser);
338
else if (state == PROP &&
339
strcmp(name.name, "prop") == 0)
341
svn_ra_serf__xml_pop_state(parser);
343
else if (state == RESOURCE_TYPE &&
344
strcmp(name.name, "resourcetype") == 0)
346
svn_ra_serf__xml_pop_state(parser);
348
else if (state == IGNORE_PROP_NAME || state == NEED_PROP_NAME)
350
svn_ra_serf__xml_pop_state(parser);
352
else if (state == PROP_VAL)
354
if (!info->prop_name)
356
info->prop_name = apr_pstrdup(info->pool, name.name);
358
info->prop_val = apr_pstrmemdup(info->pool, info->prop_val,
360
if (strcmp(info->prop_name, "href") == 0)
361
info->prop_val = svn_urlpath__canonicalize(info->prop_val,
364
/* Set our property. */
365
apr_hash_set(info->props, info->prop_name, APR_HASH_KEY_STRING,
368
info->prop_ns = NULL;
369
info->prop_name = NULL;
370
info->prop_val = NULL;
371
info->prop_val_len = 0;
373
svn_ra_serf__xml_pop_state(parser);
380
cdata_merge(svn_ra_serf__xml_parser_t *parser,
385
svn_ra_serf__merge_context_t *ctx = userData;
391
state = parser->state->current_state;
392
info = parser->state->private;
394
if (state == PROP_VAL)
396
svn_ra_serf__expand_string(&info->prop_val, &info->prop_val_len,
397
data, len, parser->state->pool);
225
else if (leaving_state == BASELINE)
227
svn_ra_serf__xml_note(xes, RESPONSE, "resourcetype", "baseline");
229
else if (leaving_state == COLLECTION)
231
svn_ra_serf__xml_note(xes, RESPONSE, "resourcetype", "collection");
236
const char *value = cdata->data;
238
if (leaving_state == HREF)
241
value = svn_urlpath__canonicalize(value, scratch_pool);
243
else if (leaving_state == CHECKED_IN)
246
value = svn_urlpath__canonicalize(value, scratch_pool);
248
else if (leaving_state == VERSION_NAME)
250
else if (leaving_state == DATE)
252
else if (leaving_state == AUTHOR)
254
else if (leaving_state == POST_COMMIT_ERR)
255
name = "post-commit-err";
257
SVN_ERR_MALFUNCTION();
259
svn_ra_serf__xml_note(xes, RESPONSE, name, value);
403
266
static svn_error_t *
404
267
setup_merge_headers(serf_bucket_t *headers,
406
269
apr_pool_t *pool)
408
svn_ra_serf__merge_context_t *ctx = baton;
271
merge_context_t *ctx = baton;
410
273
if (!ctx->keep_locks)