You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@subversion.apache.org by cm...@apache.org on 2010/08/31 18:47:23 UTC
svn commit: r991239 - in /subversion/trunk: ./ subversion/include/
subversion/libsvn_ra_serf/ subversion/mod_dav_svn/
subversion/mod_dav_svn/posts/
Author: cmpilato
Date: Tue Aug 31 16:47:22 2010
New Revision: 991239
URL: http://svn.apache.org/viewvc?rev=991239&view=rev
Log:
Add code to parse skel-type request bodies in mod_dav_svn (honoring
the LimitRequestBody Apache configuration directive), and start using
it to create commit transactions.
NOTE: Clients using ra_serf to perform commits against older 1.7-to-be
HTTP servers will fail. I'd prefer to close the gap of "any old
POST request we can't figure out should create a commit
transaction" now before we release 1.7. ra_neon doesn't have
this problem because it never used the new POST approach.
* subversion/include/svn_dav.h
(SVN_SKEL_MIME_TYPE): New.
* subversion/mod_dav_svn/dav_svn.h
(dav_svn__parse_request_skel, dav_svn__post_create_txn): New prototypes.
(dav_svn__posts_list): New static list.
* subversion/mod_dav_svn/util.c
(request_body_to_string, dav_svn__parse_request_skel): New functions.
* subversion/mod_dav_svn/posts/,
* subversion/mod_dav_svn/posts/create_txn.c
New.
* subversion/mod_dav_svn/repos.c
(handle_post_request): New function.
(dav_svn__method_post): Tweak this thing to expect skel-type POST
requests, which are handed off to a dispatcher function.
* subversion/libsvn_ra_serf/commit.c
(create_txn_post_body): New body delegate function.
(open_root): Register create_txn_post_body() as a body delegate when
issuing the POST request to create a new transaction.
* build.conf
(mod_dav_svn): Add posts/*.c to the sources list.
Added:
subversion/trunk/subversion/mod_dav_svn/posts/ (with props)
subversion/trunk/subversion/mod_dav_svn/posts/create_txn.c (with props)
Modified:
subversion/trunk/build.conf
subversion/trunk/subversion/include/svn_dav.h
subversion/trunk/subversion/libsvn_ra_serf/commit.c
subversion/trunk/subversion/mod_dav_svn/dav_svn.h
subversion/trunk/subversion/mod_dav_svn/repos.c
subversion/trunk/subversion/mod_dav_svn/util.c
Modified: subversion/trunk/build.conf
URL: http://svn.apache.org/viewvc/subversion/trunk/build.conf?rev=991239&r1=991238&r2=991239&view=diff
==============================================================================
--- subversion/trunk/build.conf (original)
+++ subversion/trunk/build.conf Tue Aug 31 16:47:22 2010
@@ -345,7 +345,7 @@ msvc-export = svn_wc.h private\svn_wc_pr
description = Subversion plug-in for the Apache DAV module
type = apache-mod
path = subversion/mod_dav_svn
-sources = *.c reports/*.c
+sources = *.c reports/*.c posts/*.c
libs = libsvn_repos libsvn_fs libsvn_delta libsvn_subr
nonlibs = apr aprutil
install = apache-mod
Modified: subversion/trunk/subversion/include/svn_dav.h
URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/include/svn_dav.h?rev=991239&r1=991238&r2=991239&view=diff
==============================================================================
--- subversion/trunk/subversion/include/svn_dav.h (original)
+++ subversion/trunk/subversion/include/svn_dav.h Tue Aug 31 16:47:22 2010
@@ -43,6 +43,12 @@ extern "C" {
*/
#define SVN_SVNDIFF_MIME_TYPE "application/vnd.svn-svndiff"
+/** This is the MIME type that Subversion users for its "skel" format.
+ *
+ * This is an application type, for the "svn" vendor. The specific subtype
+ * is "skel".
+ */
+#define SVN_SKEL_MIME_TYPE "application/vnd.svn-skel"
/** This header is *TEMPORARILY* used to transmit the delta base to the
* server. It contains a version resource URL for what is on the client.
Modified: subversion/trunk/subversion/libsvn_ra_serf/commit.c
URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/libsvn_ra_serf/commit.c?rev=991239&r1=991238&r2=991239&view=diff
==============================================================================
--- subversion/trunk/subversion/libsvn_ra_serf/commit.c (original)
+++ subversion/trunk/subversion/libsvn_ra_serf/commit.c Tue Aug 31 16:47:22 2010
@@ -1061,6 +1061,18 @@ svndiff_stream_write(void *file_baton,
/* POST against 'me' resource handlers. */
+/* Implements svn_ra_serf__request_body_delegate_t */
+static svn_error_t *
+create_txn_post_body(serf_bucket_t **body_bkt,
+ void *baton,
+ serf_bucket_alloc_t *alloc,
+ apr_pool_t *pool)
+{
+ *body_bkt = SERF_BUCKET_SIMPLE_STRING("( create-txn )", alloc);
+ return SVN_NO_ERROR;
+}
+
+
/* Handler baton for POST request. */
typedef struct
{
@@ -1140,6 +1152,9 @@ open_root(void *edit_baton,
/* Create our activity URL now on the server. */
handler = apr_pcalloc(ctx->pool, sizeof(*handler));
handler->method = "POST";
+ handler->body_type = SVN_SKEL_MIME_TYPE;
+ handler->body_delegate = create_txn_post_body;
+ handler->body_delegate_baton = NULL;
handler->path = ctx->session->me_resource;
handler->conn = ctx->session->conns[0];
handler->session = ctx->session;
Modified: subversion/trunk/subversion/mod_dav_svn/dav_svn.h
URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/mod_dav_svn/dav_svn.h?rev=991239&r1=991238&r2=991239&view=diff
==============================================================================
--- subversion/trunk/subversion/mod_dav_svn/dav_svn.h (original)
+++ subversion/trunk/subversion/mod_dav_svn/dav_svn.h Tue Aug 31 16:47:22 2010
@@ -37,6 +37,7 @@
#include "svn_path.h"
#include "svn_xml.h"
#include "private/svn_dav_protocol.h"
+#include "private/svn_skel.h"
#include "mod_authz_svn.h"
#ifdef __cplusplus
@@ -419,7 +420,7 @@ dav_svn__store_activity(const dav_svn_re
const char *txn_name);
-/* HTTP protocol v2: client does POST against 'me' resource. */
+/* POST request handler. (Used by HTTP protocol v2 clients only.) */
int dav_svn__method_post(request_rec *r);
@@ -640,6 +641,23 @@ dav_svn__get_deleted_rev_report(const da
const apr_xml_doc *doc,
ap_filter_t *output);
+
+/*** posts/ ***/
+
+/* The list of Subversion's custom POSTs. */
+/* ### should move these report names to a public header to share with
+ ### the client (and third parties). */
+static const char * dav_svn__posts_list[] = {
+ "create-txn",
+ NULL
+};
+
+/* The various POST handlers, defined in posts/, and used by repos.c. */
+dav_error *
+dav_svn__post_create_txn(const dav_resource *resource,
+ svn_skel_t *request_skel,
+ ap_filter_t *output);
+
/*** authz.c ***/
/* A baton needed by dav_svn__authz_read_func(). */
@@ -890,6 +908,13 @@ dav_svn__final_flush_or_error(request_re
*/
int dav_svn__error_response_tag(request_rec *r, dav_error *err);
+
+/* Set *SKEL to a parsed skel read from the body of request R, and
+ * allocated in POOL.
+ */
+int dav_svn__parse_request_skel(svn_skel_t **skel, request_rec *r,
+ apr_pool_t *pool);
+
/*** mirror.c ***/
/* Perform the fixup hook for the R request. */
Propchange: subversion/trunk/subversion/mod_dav_svn/posts/
------------------------------------------------------------------------------
--- svn:ignore (added)
+++ svn:ignore Tue Aug 31 16:47:22 2010
@@ -0,0 +1 @@
+.libs
Added: subversion/trunk/subversion/mod_dav_svn/posts/create_txn.c
URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/mod_dav_svn/posts/create_txn.c?rev=991239&view=auto
==============================================================================
--- subversion/trunk/subversion/mod_dav_svn/posts/create_txn.c (added)
+++ subversion/trunk/subversion/mod_dav_svn/posts/create_txn.c Tue Aug 31 16:47:22 2010
@@ -0,0 +1,54 @@
+/*
+ * create_txn.c: mod_dav_svn POST handler for creating a commit transaction
+ *
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ * ====================================================================
+ */
+
+#include <httpd.h>
+#include <mod_dav.h>
+
+#include "svn_dav.h"
+#include "../dav_svn.h"
+
+/* Respond to a "create-txn" POST request.
+ *
+ * Syntax: ( create-txn )
+ */
+dav_error *
+dav_svn__post_create_txn(const dav_resource *resource,
+ svn_skel_t *request_skel,
+ ap_filter_t *output)
+{
+ const char *txn_name;
+ dav_error *derr;
+ request_rec *r = resource->info->r;
+
+ /* Create a Subversion repository transaction based on HEAD. */
+ if ((derr = dav_svn__create_txn(resource->info->repos, &txn_name,
+ resource->pool)))
+ return derr;
+
+ /* Build a "201 Created" response with header that tells the
+ client our new transaction's name. */
+ apr_table_set(r->headers_out, SVN_DAV_TXN_NAME_HEADER, txn_name);
+ r->status = HTTP_CREATED;
+
+ return NULL;
+}
Propchange: subversion/trunk/subversion/mod_dav_svn/posts/create_txn.c
------------------------------------------------------------------------------
svn:eol-style = native
Modified: subversion/trunk/subversion/mod_dav_svn/repos.c
URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/mod_dav_svn/repos.c?rev=991239&r1=991238&r2=991239&view=diff
==============================================================================
--- subversion/trunk/subversion/mod_dav_svn/repos.c (original)
+++ subversion/trunk/subversion/mod_dav_svn/repos.c Tue Aug 31 16:47:22 2010
@@ -4263,58 +4263,73 @@ dav_svn__create_version_resource(dav_res
}
-/* POST handler for HTTP protocol v2.
-
- Currently we allow POSTs only against the "me resource", which may
- in the future act as a dispatcher of sorts for handling potentially
- many different kinds of operations as specified by the body of the
- POST request itself.
-
- ### TODO: Define what the format of those POST bodies might be. If
- ### XML, we have access to Apache's streamy XML parsing code, but
- ### ... it's XML. Meh. If skels, we get skels! But we need to
- ### write our own streamy skel parsing routine around a brigade
- ### read loop. Ewww...
- ###
- ### Today we only support transaction creation requests, but we
- ### could conceivable support the likes of a multi-path lock
- ### and/or unlock request, or some other thing for which stock
- ### WebDAV doesn't work or doesn't work well enough.
- ###
- ### Fortunately, today we don't use the POST body at all, and we'll
- ### be able to get away with not defining the body format in the
- ### future thanks to the following:
-
- As a special consideration, an empty POST body is interpreted as a
- simple request to create a new commit transaction based on the HEAD
- revision. The new transaction name will be returned via a custom
- response header SVN_DAV_TXN_NAME_HEADER.
-*/
+
+static dav_error *
+handle_post_request(request_rec *r,
+ dav_resource *resource,
+ ap_filter_t *output)
+{
+ svn_skel_t *request_skel;
+ int status;
+ apr_pool_t *pool = resource->pool;
+
+ /* Make sure our skel-based request parses okay, has an initial atom
+ that identifies what kind of action is expected, and that that
+ action is something we understand. */
+ status = dav_svn__parse_request_skel(&request_skel, r, pool);
+
+ if (status != OK)
+ return dav_new_error(pool, status, 0,
+ "Error parsing skel POST request body.");
+
+ if (svn_skel__list_length(request_skel) < 1)
+ return dav_new_error(pool, HTTP_BAD_REQUEST, 0,
+ "Unable to identify skel POST request flavor.");
+
+ if (svn_skel__matches_atom(request_skel->children, "create-txn"))
+ {
+ return dav_svn__post_create_txn(resource, request_skel, output);
+ }
+ else
+ {
+ return dav_new_error(pool, HTTP_BAD_REQUEST, 0,
+ "Unsupported skel POST request flavor.");
+ }
+ /* NOTREACHED */
+}
+
int dav_svn__method_post(request_rec *r)
{
dav_resource *resource;
dav_error *derr;
- const char *txn_name;
+ const char *content_type;
+ /* We only allow POSTs against the "me resource" right now. */
derr = get_resource(r, dav_svn__get_root_dir(r),
"ignored", 0, &resource);
if (derr != NULL)
return derr->status;
-
if (resource->info->restype != DAV_SVN_RESTYPE_ME)
return HTTP_BAD_REQUEST;
- /* Create a Subversion repository transaction based on HEAD. */
- derr = dav_svn__create_txn(resource->info->repos, &txn_name, resource->pool);
+ /* Pass skel-type POST request handling off to a dispatcher; any
+ other type of request is considered bogus. */
+ content_type = apr_table_get(r->headers_in, "content-type");
+ if (content_type && (strcmp(content_type, SVN_SKEL_MIME_TYPE) == 0))
+ {
+ derr = handle_post_request(r, resource, r->output_filters);
+ }
+ else
+ {
+ derr = dav_new_error(resource->pool, HTTP_BAD_REQUEST, 0,
+ "Unsupported POST request type.");
+ }
+
+ /* If something went wrong above, we'll generate a response back to
+ the client with (hopefully) some helpful information. */
if (derr)
return dav_svn__error_response_tag(r, derr);
-
- /* Build a "201 Created" response with header that tells the client
- our new transaction's name. */
- apr_table_set(resource->info->r->headers_out, SVN_DAV_TXN_NAME_HEADER,
- txn_name);
- r->status = HTTP_CREATED;
-
+
return OK;
}
Modified: subversion/trunk/subversion/mod_dav_svn/util.c
URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/mod_dav_svn/util.c?rev=991239&r1=991238&r2=991239&view=diff
==============================================================================
--- subversion/trunk/subversion/mod_dav_svn/util.c (original)
+++ subversion/trunk/subversion/mod_dav_svn/util.c Tue Aug 31 16:47:22 2010
@@ -28,6 +28,7 @@
#include <mod_dav.h>
#include <http_protocol.h>
+#include <http_core.h>
#include "svn_error.h"
#include "svn_fs.h"
@@ -611,3 +612,137 @@ dav_svn__error_response_tag(request_rec
*/
return DONE;
}
+
+
+/* Set *REQUEST_STR to a string containing the contents of the body of
+ request R, allocated from POOL.
+
+ NOTE: This was shamelessly stolen and modified from Apache's
+ ap_xml_parse_input(). */
+static int
+request_body_to_string(svn_string_t **request_str,
+ request_rec *r,
+ apr_pool_t *pool)
+{
+ apr_bucket_brigade *brigade;
+ int seen_eos;
+ apr_status_t status;
+ apr_off_t total_read = 0;
+ apr_off_t limit_req_body = ap_get_limit_req_body(r);
+ int result = HTTP_BAD_REQUEST;
+ const char *content_length_str;
+ char *endp;
+ apr_off_t content_length;
+ svn_stringbuf_t *buf;
+
+ *request_str = NULL;
+
+ content_length_str = apr_table_get(r->headers_in, "Content-Length");
+ if (content_length_str)
+ {
+ if (apr_strtoff(&content_length, content_length_str, &endp, 10)
+ || endp == content_length_str || *endp || content_length < 0)
+ {
+ ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, "Invalid Content-Length");
+ return HTTP_REQUEST_ENTITY_TOO_LARGE;
+ }
+ }
+ if (limit_req_body && (limit_req_body < content_length))
+ {
+ ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
+ "Requested content-length of %" APR_OFF_T_FMT " is larger "
+ "than the configured limit of %" APR_OFF_T_FMT,
+ content_length, limit_req_body);
+ return HTTP_REQUEST_ENTITY_TOO_LARGE;
+ }
+
+ if (content_length)
+ {
+ buf = svn_stringbuf_create_ensure(content_length, pool);
+ }
+ else
+ {
+ buf = svn_stringbuf_create("", pool);
+ }
+
+ brigade = apr_brigade_create(r->pool, r->connection->bucket_alloc);
+ seen_eos = 0;
+ total_read = 0;
+
+ do
+ {
+ apr_bucket *bucket;
+
+ status = ap_get_brigade(r->input_filters, brigade, AP_MODE_READBYTES,
+ APR_BLOCK_READ, 2048);
+ if (status != APR_SUCCESS)
+ goto cleanup;
+
+ for (bucket = APR_BRIGADE_FIRST(brigade);
+ bucket != APR_BRIGADE_SENTINEL(brigade);
+ bucket = APR_BUCKET_NEXT(bucket))
+ {
+ const char *data;
+ apr_size_t len;
+
+ if (APR_BUCKET_IS_EOS(bucket))
+ {
+ seen_eos = 1;
+ break;
+ }
+
+ if (APR_BUCKET_IS_METADATA(bucket))
+ continue;
+
+ status = apr_bucket_read(bucket, &data, &len, APR_BLOCK_READ);
+ if (status != APR_SUCCESS)
+ goto cleanup;
+
+ total_read += len;
+ if (limit_req_body && total_read > limit_req_body)
+ {
+ ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
+ "Request body is larger than the configured "
+ "limit of %lu", (unsigned long)limit_req_body);
+ result = HTTP_REQUEST_ENTITY_TOO_LARGE;
+ goto cleanup;
+ }
+
+ svn_stringbuf_appendbytes(buf, data, len);
+ }
+
+ apr_brigade_cleanup(brigade);
+ }
+ while (!seen_eos);
+
+ apr_brigade_destroy(brigade);
+
+ /* Make an svn_string_t from our svn_stringbuf_t. */
+ *request_str = svn_string_create("", pool);
+ (*request_str)->data = buf->data;
+ (*request_str)->len = buf->len;
+ return OK;
+
+ cleanup:
+ apr_brigade_destroy(brigade);
+
+ /* Apache will supply a default error, plus the error log above. */
+ return result;
+}
+
+int
+dav_svn__parse_request_skel(svn_skel_t **skel,
+ request_rec *r,
+ apr_pool_t *pool)
+{
+ svn_string_t *skel_str;
+ int status;
+
+ *skel = NULL;
+ status = request_body_to_string(&skel_str, r, pool);
+ if (status != OK)
+ return OK;
+
+ *skel = svn_skel__parse(skel_str->data, skel_str->len, pool);
+ return OK;
+}
Re: svn commit: r991239 - in /subversion/trunk: ./ subversion/include/
subversion/libsvn_ra_serf/ subversion/mod_dav_svn/ subversion/mod_dav_svn/posts/
Posted by "C. Michael Pilato" <cm...@collab.net>.
On 09/14/2010 10:07 AM, Philip Martin wrote:
> What is the purpose of dav_svn__posts_list? It doesn't seem to be
> used and it leads to compiler warnings.
I intend to broadcast the list of support POSTs in the OPTIONs request (like
we do REPORT types), but haven't gotten around to it yet.
--
C. Michael Pilato <cm...@collab.net>
CollabNet <> www.collab.net <> Distributed Development On Demand
Re: svn commit: r991239 - in /subversion/trunk: ./ subversion/include/ subversion/libsvn_ra_serf/ subversion/mod_dav_svn/ subversion/mod_dav_svn/posts/
Posted by Philip Martin <ph...@wandisco.com>.
cmpilato@apache.org writes:
> Author: cmpilato
> Date: Tue Aug 31 16:47:22 2010
> New Revision: 991239
>
> URL: http://svn.apache.org/viewvc?rev=991239&view=rev
> Log:
> Add code to parse skel-type request bodies in mod_dav_svn (honoring
> the LimitRequestBody Apache configuration directive), and start using
> it to create commit transactions.
>
> NOTE: Clients using ra_serf to perform commits against older 1.7-to-be
> HTTP servers will fail. I'd prefer to close the gap of "any old
> POST request we can't figure out should create a commit
> transaction" now before we release 1.7. ra_neon doesn't have
> this problem because it never used the new POST approach.
>
> * subversion/include/svn_dav.h
> (SVN_SKEL_MIME_TYPE): New.
>
> * subversion/mod_dav_svn/dav_svn.h
> (dav_svn__parse_request_skel, dav_svn__post_create_txn): New prototypes.
> (dav_svn__posts_list): New static list.
What is the purpose of dav_svn__posts_list? It doesn't seem to be
used and it leads to compiler warnings.
--
Philip