1820
1822
apr_table_t *pairs = querystring_to_table(query, pool);
1821
1823
const char *prevstr = apr_table_get(pairs, "p");
1822
1824
const char *wrevstr;
1825
const char *keyword_subst;
1827
/* Will we be doing keyword substitution? */
1828
keyword_subst = apr_table_get(pairs, "kw");
1829
if (keyword_subst && (strcmp(keyword_subst, "1") == 0))
1830
comb->priv.keyword_subst = TRUE;
1834
while (*prevstr == 'r')
1826
1836
peg_rev = SVN_STR_TO_REV(prevstr);
1827
1837
if (!SVN_IS_VALID_REVNUM(peg_rev))
1828
1838
return dav_svn__new_error(pool, HTTP_BAD_REQUEST, 0,
1904
1916
/* Redirect folks to a canonical, peg-revision-only location.
1905
1917
If they used a peg revision in this request, we can use a
1906
1918
permanent redirect. If they didn't (peg-rev is HEAD), we can
1907
only use a temporary redirect. */
1908
apr_table_setn(r->headers_out, "Location",
1909
ap_construct_url(r->pool,
1910
apr_psprintf(r->pool, "%s%s?p=%ld",
1919
only use a temporary redirect. In either case, preserve the
1920
"keyword_subst" state in the redirected location, too. */
1921
location = ap_construct_url(r->pool,
1922
apr_psprintf(r->pool, "%s%s?p=%ld%s",
1911
1923
(comb->priv.repos->root_path[1]
1912
1924
? comb->priv.repos->root_path
1914
newpath, working_rev),
1926
newpath, working_rev,
1927
keyword_subst ? "&kw=1" : ""),
1929
apr_table_setn(r->headers_out, "Location", location);
1916
1930
return dav_svn__new_error(r->pool,
1917
1931
prevstr ? HTTP_MOVED_PERMANENTLY
1918
1932
: HTTP_MOVED_TEMPORARILY,
2142
2154
/* construct FS configuration parameters */
2143
2155
fs_config = apr_hash_make(r->connection->pool);
2144
apr_hash_set(fs_config,
2145
SVN_FS_CONFIG_FSFS_CACHE_DELTAS,
2146
APR_HASH_KEY_STRING,
2147
dav_svn__get_txdelta_cache_flag(r) ? "1" : "0");
2148
apr_hash_set(fs_config,
2149
SVN_FS_CONFIG_FSFS_CACHE_FULLTEXTS,
2150
APR_HASH_KEY_STRING,
2151
dav_svn__get_fulltext_cache_flag(r) ? "1" : "0");
2156
svn_hash_sets(fs_config, SVN_FS_CONFIG_FSFS_CACHE_DELTAS,
2157
dav_svn__get_txdelta_cache_flag(r) ? "1" :"0");
2158
svn_hash_sets(fs_config, SVN_FS_CONFIG_FSFS_CACHE_FULLTEXTS,
2159
dav_svn__get_fulltext_cache_flag(r) ? "1" :"0");
2160
svn_hash_sets(fs_config, SVN_FS_CONFIG_FSFS_CACHE_REVPROPS,
2161
dav_svn__get_revprop_cache_flag(r) ? "1" :"0");
2153
2163
/* Disallow BDB/event until issue 4157 is fixed. */
2154
2164
if (!strcmp(ap_show_mpm(), "event"))
2568
/* Given an apache request R and a ROOT_PATH to the svn location
2569
block, set *KIND to the node-kind of the URI's associated
2570
(revision, path) pair, if possible.
2572
Public uris, baseline collections, version resources, and working
2573
(non-baseline) resources all have associated (revision, path)
2574
pairs, and thus one of {svn_node_file, svn_node_dir, svn_node_none}
2577
If URI is something more abstract, then set *KIND to
2578
svn_node_unknown. This is true for baselines, working baselines,
2579
version controled configurations, activities, histories, and other
2583
resource_kind(request_rec *r,
2585
const char *root_path,
2586
svn_node_kind_t *kind)
2590
dav_resource *resource;
2591
svn_revnum_t base_rev;
2592
svn_fs_root_t *base_rev_root;
2595
/* Temporarily insert the uri that the user actually wants us to
2596
convert into a resource. Typically, this is already r->uri, so
2597
this is usually a no-op. But sometimes the caller may pass in
2598
the Destination: header uri.
2600
### WHAT WE REALLY WANT here is to refactor get_resource,
2601
so that some alternate interface actually allows us to specify
2602
the URI to process, i.e. not always process r->uri.
2605
r->uri = apr_pstrdup(r->pool, uri);
2607
/* parse the uri and prep the associated resource. */
2608
derr = get_resource(r, root_path,
2609
/* ### I can't believe that every single
2610
parser ignores the LABEL and USE_CHECKED_IN
2614
/* Restore r back to normal. */
2620
if (resource->type == DAV_RESOURCE_TYPE_REGULAR)
2622
/* Either a public URI or a bc. In both cases, prep_regular()
2623
has already set the 'exists' and 'collection' flags by
2624
querying the appropriate revision root and path. */
2625
if (! resource->exists)
2626
*kind = svn_node_none;
2628
*kind = resource->collection ? svn_node_dir : svn_node_file;
2631
else if (resource->type == DAV_RESOURCE_TYPE_VERSION)
2633
if (resource->baselined) /* bln */
2634
*kind = svn_node_unknown;
2638
derr = fs_check_path(kind, resource->info->root.root,
2639
resource->info->repos_path, r->pool);
2645
else if (resource->type == DAV_RESOURCE_TYPE_WORKING)
2647
if (resource->baselined) /* wbl */
2648
*kind = svn_node_unknown;
2652
/* don't call fs_check_path on the txn, but on the original
2653
revision that the txn is based on. */
2654
base_rev = svn_fs_txn_base_revision(resource->info->root.txn);
2655
serr = svn_fs_revision_root(&base_rev_root,
2656
resource->info->repos->fs,
2659
return dav_svn__convert_err
2660
(serr, HTTP_INTERNAL_SERVER_ERROR,
2661
apr_psprintf(r->pool,
2662
"Could not open root of revision %ld",
2666
derr = fs_check_path(kind, base_rev_root,
2667
resource->info->repos_path, r->pool);
2674
/* act, his, vcc, or some other private resource */
2675
*kind = svn_node_unknown;
2682
2585
static dav_error *
2683
2586
open_stream(const dav_resource *resource,
2684
2587
dav_stream_mode mode,
3021
2923
apr_table_setn(r->headers_out, "ETag",
3022
2924
dav_svn__getetag(resource, resource->pool));
3025
2926
/* As version resources don't change, encourage caching. */
3026
/* ### FIXME: This conditional is wrong -- type is often REGULAR,
3027
### and the resource doesn't seem to be baselined. */
3028
if (resource->type == DAV_RESOURCE_TYPE_VERSION)
2927
if ((resource->type == DAV_RESOURCE_TYPE_REGULAR
2928
&& resource->versioned && !resource->collection)
2929
|| resource->type == DAV_RESOURCE_TYPE_VERSION)
3029
2930
/* Cache resource for one week (specified in seconds). */
3030
2931
apr_table_setn(r->headers_out, "Cache-Control", "max-age=604800");
3033
2933
/* we accept byte-ranges */
3034
2934
apr_table_setn(r->headers_out, "Accept-Ranges", "bytes");
3116
3016
mimetype = "text/plain";
3119
/* if we aren't sending a diff, then we know the length of the file,
3120
so set up the Content-Length header */
3121
serr = svn_fs_file_length(&length,
3122
resource->info->root.root,
3123
resource->info->repos_path,
3019
/* if we aren't sending a diff and aren't expanding keywords,
3020
then we know the exact length of the file, so set up the
3021
Content-Length header. */
3022
if (! resource->info->keyword_subst)
3127
return dav_svn__convert_err(serr, HTTP_INTERNAL_SERVER_ERROR,
3128
"could not fetch the resource length",
3024
serr = svn_fs_file_length(&length,
3025
resource->info->root.root,
3026
resource->info->repos_path,
3030
return dav_svn__convert_err(serr, HTTP_INTERNAL_SERVER_ERROR,
3031
"could not fetch the resource length",
3034
ap_set_content_length(r, (apr_off_t) length);
3131
ap_set_content_length(r, (apr_off_t) length);
3134
3038
/* set the discovered MIME type */
3654
3558
resource->pool);
3561
/* Perform keywords substitution if requested by client */
3562
if (resource->info->keyword_subst)
3564
svn_string_t *keywords;
3566
serr = svn_fs_node_prop(&keywords,
3567
resource->info->root.root,
3568
resource->info->repos_path,
3572
return dav_svn__convert_err(serr, HTTP_INTERNAL_SERVER_ERROR,
3573
"could not get fetch '"
3574
SVN_PROP_KEYWORDS "' property for "
3575
"for keywords substitution",
3581
svn_revnum_t cmt_rev;
3582
const char *str_cmt_rev, *str_uri, *str_root;
3583
const char *cmt_date, *cmt_author;
3584
apr_time_t when = 0;
3586
serr = svn_repos_get_committed_info(&cmt_rev,
3589
resource->info->root.root,
3590
resource->info->repos_path,
3593
return dav_svn__convert_err(serr, HTTP_INTERNAL_SERVER_ERROR,
3594
"could not fetch committed info "
3595
"for keywords substitution",
3598
serr = svn_time_from_cstring(&when, cmt_date, resource->pool);
3600
return dav_svn__convert_err(serr, HTTP_INTERNAL_SERVER_ERROR,
3601
"could not parse committed date "
3602
"for keywords substitution",
3604
str_cmt_rev = apr_psprintf(resource->pool, "%ld", cmt_rev);
3605
str_uri = apr_pstrcat(resource->pool,
3606
resource->info->repos->base_url,
3607
ap_escape_uri(resource->pool,
3608
resource->info->r->uri),
3610
str_root = apr_pstrcat(resource->pool,
3611
resource->info->repos->base_url,
3612
resource->info->repos->root_path,
3615
serr = svn_subst_build_keywords3(&kw, keywords->data,
3616
str_cmt_rev, str_uri, str_root,
3620
return dav_svn__convert_err(serr, HTTP_INTERNAL_SERVER_ERROR,
3621
"could not perform keywords "
3622
"substitution", resource->pool);
3624
/* Replace the raw file STREAM with a wrapper that
3625
handles keyword translation. */
3626
stream = svn_subst_stream_translated(
3627
svn_stream_disown(stream, resource->pool),
3628
NULL, FALSE, kw, TRUE, resource->pool);
3657
3632
/* ### one day in the future, we can create a custom bucket type
3658
3633
### which will read from the FS stream on demand */
4451
4426
return dav_svn__new_error(pool, HTTP_BAD_REQUEST, 0,
4452
4427
"Unable to identify skel POST request flavor.");
4454
if (svn_skel__matches_atom(request_skel->children, "create-txn"))
4429
post_skel = request_skel->children;
4431
/* NOTE: If you add POST handlers here, you'll want to advertise
4432
that the server supports them, too. See version.c:get_option(). */
4434
if (svn_skel__matches_atom(post_skel, "create-txn"))
4456
4436
return dav_svn__post_create_txn(resource, request_skel, output);
4438
else if (svn_skel__matches_atom(post_skel, "create-txn-with-props"))
4460
return dav_svn__new_error(pool, HTTP_BAD_REQUEST, 0,
4461
"Unsupported skel POST request flavor.");
4440
return dav_svn__post_create_txn_with_props(resource,
4441
request_skel, output);
4444
return dav_svn__new_error(pool, HTTP_BAD_REQUEST, 0,
4445
"Unsupported skel POST request flavor.");
4449
/* A stripped down version of mod_dav's dav_handle_err so that POST
4450
errors, which are not passed via mod_dav, are handled in the same
4451
way as errors for requests that are passed via mod_dav. */
4453
handle_err(request_rec *r, dav_error *err)
4455
dav_error *stackerr = err;
4457
dav_svn__log_err(r, err, APLOG_ERR);
4459
/* our error messages are safe; tell Apache this */
4460
apr_table_setn(r->notes, "verbose-error-to", "*");
4462
/* We might be able to generate a standard <D:error> response.
4463
Search the error stack for an errortag. */
4464
while (stackerr != NULL && stackerr->tagname == NULL)
4465
stackerr = stackerr->prev;
4467
if (stackerr != NULL && stackerr->tagname != NULL)
4468
return dav_svn__error_response_tag(r, stackerr);
4466
4474
int dav_svn__method_post(request_rec *r)