You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@subversion.apache.org by hw...@apache.org on 2010/09/15 21:32:38 UTC

svn commit: r997472 [15/41] - in /subversion/branches/py-tests-as-modules: ./ build/ build/ac-macros/ build/generator/ build/generator/templates/ contrib/server-side/ notes/ notes/tree-conflicts/ notes/wc-ng/ subversion/bindings/javahl/native/ subversi...

Modified: subversion/branches/py-tests-as-modules/subversion/libsvn_ra_neon/props.c
URL: http://svn.apache.org/viewvc/subversion/branches/py-tests-as-modules/subversion/libsvn_ra_neon/props.c?rev=997472&r1=997471&r2=997472&view=diff
==============================================================================
--- subversion/branches/py-tests-as-modules/subversion/libsvn_ra_neon/props.c (original)
+++ subversion/branches/py-tests-as-modules/subversion/libsvn_ra_neon/props.c Wed Sep 15 19:32:26 2010
@@ -1031,36 +1031,22 @@ svn_error_t *svn_ra_neon__get_baseline_i
 }
 
 
-/* Helper function for svn_ra_neon__do_proppatch() below. */
-static void
-append_setprop(svn_stringbuf_t *body,
-               const char *name,
-               const svn_string_t *value,
-               apr_pool_t *pool)
+/* Helper function for append_setprop() below. */
+static svn_error_t *
+get_encoding_and_cdata(const char **encoding_p,
+                       const char **cdata_p,
+                       const svn_string_t *value,
+                       apr_pool_t *pool)
 {
-  const char *encoding = "";
+  const char *encoding;
   const char *xml_safe;
-  const char *xml_tag_name;
 
-  /* Map property names to namespaces */
-#define NSLEN (sizeof(SVN_PROP_PREFIX) - 1)
-  if (strncmp(name, SVN_PROP_PREFIX, NSLEN) == 0)
-    {
-      xml_tag_name = apr_pstrcat(pool, "S:", name + NSLEN, NULL);
-    }
-#undef NSLEN
-  else
+  /* Easy out. */
+  if (value == NULL)
     {
-      xml_tag_name = apr_pstrcat(pool, "C:", name, NULL);
-    }
-
-  /* If there is no value, just generate an empty tag and get outta
-     here. */
-  if (! value)
-    {
-      svn_stringbuf_appendcstr(body,
-                               apr_psprintf(pool, "<%s />", xml_tag_name));
-      return;
+      *encoding_p = "";
+      *cdata_p = "";
+      return SVN_NO_ERROR;
     }
 
   /* If a property is XML-safe, XML-encode it.  Else, base64-encode
@@ -1070,6 +1056,7 @@ append_setprop(svn_stringbuf_t *body,
       svn_stringbuf_t *xml_esc = NULL;
       svn_xml_escape_cdata_string(&xml_esc, value, pool);
       xml_safe = xml_esc->data;
+      encoding = "";
     }
   else
     {
@@ -1079,11 +1066,41 @@ append_setprop(svn_stringbuf_t *body,
       xml_safe = base64ed->data;
     }
 
+  *encoding_p = encoding;
+  *cdata_p = xml_safe;
+  return SVN_NO_ERROR;
+}
+
+/* Helper function for svn_ra_neon__do_proppatch() below. */
+static svn_error_t *
+append_setprop(svn_stringbuf_t *body,
+               const char *name,
+               const svn_string_t *value,
+               apr_pool_t *pool)
+{
+  const char *encoding;
+  const char *xml_safe;
+  const char *xml_tag_name;
+
+  /* Map property names to namespaces */
+#define NSLEN (sizeof(SVN_PROP_PREFIX) - 1)
+  if (strncmp(name, SVN_PROP_PREFIX, NSLEN) == 0)
+    {
+      xml_tag_name = apr_pstrcat(pool, "S:", name + NSLEN, NULL);
+    }
+#undef NSLEN
+  else
+    {
+      xml_tag_name = apr_pstrcat(pool, "C:", name, NULL);
+    }
+
+  SVN_ERR(get_encoding_and_cdata(&encoding, &xml_safe, value, pool));
+
   svn_stringbuf_appendcstr(body,
                            apr_psprintf(pool,"<%s %s>%s</%s>",
                                         xml_tag_name, encoding,
                                         xml_safe, xml_tag_name));
-  return;
+  return SVN_NO_ERROR;
 }
 
 
@@ -1124,7 +1141,7 @@ svn_ra_neon__do_proppatch(svn_ra_neon__s
           void *val;
           svn_pool_clear(subpool);
           apr_hash_this(hi, &key, NULL, &val);
-          append_setprop(body, key, val, subpool);
+          SVN_ERR(append_setprop(body, key, val, subpool));
         }
       svn_stringbuf_appendcstr(body, "</D:prop></D:set>");
     }
@@ -1138,7 +1155,7 @@ svn_ra_neon__do_proppatch(svn_ra_neon__s
         {
           const char *name = APR_ARRAY_IDX(prop_deletes, n, const char *);
           svn_pool_clear(subpool);
-          append_setprop(body, name, NULL, subpool);
+          SVN_ERR(append_setprop(body, name, NULL, subpool));
         }
       svn_stringbuf_appendcstr(body, "</D:prop></D:remove>");
     }

Modified: subversion/branches/py-tests-as-modules/subversion/libsvn_ra_neon/ra_neon.h
URL: http://svn.apache.org/viewvc/subversion/branches/py-tests-as-modules/subversion/libsvn_ra_neon/ra_neon.h?rev=997472&r1=997471&r2=997472&view=diff
==============================================================================
--- subversion/branches/py-tests-as-modules/subversion/libsvn_ra_neon/ra_neon.h (original)
+++ subversion/branches/py-tests-as-modules/subversion/libsvn_ra_neon/ra_neon.h Wed Sep 15 19:32:26 2010
@@ -57,6 +57,7 @@ extern "C" {
 #define SVN_RA_NEON__XML_CDATA   (1<<1)
 #define SVN_RA_NEON__XML_COLLECT ((1<<2) | SVN_RA_NEON__XML_CDATA)
 
+/* ### Related to anonymous enum below? */
 typedef int svn_ra_neon__xml_elmid;
 
 /** XML element */
@@ -98,7 +99,8 @@ typedef struct svn_ra_neon__session_t {
   void *callback_baton;
 
   svn_auth_iterstate_t *auth_iterstate; /* state of authentication retries */
-  const char *auth_username;            /* last authenticated username used */
+  svn_boolean_t auth_used;              /* Save authorization state after
+                                           successful usage */
 
   svn_auth_iterstate_t *p11pin_iterstate; /* state of PKCS#11 pin retries */
 
@@ -200,8 +202,9 @@ typedef struct {
  *
  * Register a pool cleanup for any allocated Neon resources.
  */
-svn_ra_neon__request_t *
-svn_ra_neon__request_create(svn_ra_neon__session_t *sess,
+svn_error_t *
+svn_ra_neon__request_create(svn_ra_neon__request_t **request,
+                            svn_ra_neon__session_t *sess,
                             const char *method, const char *url,
                             apr_pool_t *pool);
 
@@ -383,6 +386,13 @@ svn_error_t *svn_ra_neon__get_file_revs(
                                         apr_pool_t *pool);
 
 
+/* Local duplicate of svn_ra_get_path_relative_to_root(). */
+svn_error_t *svn_ra_neon__get_path_relative_to_root(svn_ra_session_t *session,
+                                                    const char **rel_path,
+                                                    const char *url,
+                                                    apr_pool_t *pool);
+
+
 /*
 ** SVN_RA_NEON__LP_*: local properties for RA/DAV
 **
@@ -665,7 +675,8 @@ typedef svn_error_t * (*svn_ra_neon__end
  * Register a pool cleanup on the pool of REQ to clean up any allocated
  * Neon resources.
  *
- * ACCPT indicates whether the parser wants read the response body
+ * Return the new parser.  Also attach it to REQ if ACCPT is non-null.
+ * ACCPT indicates whether the parser wants to read the response body
  * or not.  Pass NULL for ACCPT when you don't want the returned parser
  * to be attached to REQ.
  */
@@ -730,6 +741,7 @@ svn_ra_neon__check_parse_error(const cha
                                ne_xml_parser *xml_parser,
                                const char *url);
 
+/* ### Related to svn_ra_neon__xml_elmid? */
 /* ### add SVN_RA_NEON_ to these to prefix conflicts with (sys) headers? */
 enum {
   /* Redefine Neon elements */
@@ -935,12 +947,10 @@ svn_ra_neon__maybe_store_auth_info_after
    NULL, as this will cause Neon to generate a "Content-Length: 0"
    header (which is important to some proxies).
 
-   OKAY_1 and OKAY_2 are the "acceptable" result codes. Anything other
-   than one of these will generate an error. OKAY_1 should always be
-   specified (e.g. as 200); use 0 for OKAY_2 if a second result code is
-   not allowed.
-
- */
+   OKAY_1 and OKAY_2 are the "acceptable" result codes.  Anything
+   other than one of these will generate an error.  OKAY_1 should
+   always be specified (e.g. as 200); use 0 for OKAY_2 if additional
+   result codes aren't allowed.  */
 svn_error_t *
 svn_ra_neon__request_dispatch(int *code_p,
                               svn_ra_neon__request_t *request,
@@ -963,8 +973,9 @@ svn_ra_neon__simple_request(int *code,
                             const char *url,
                             apr_hash_t *extra_headers,
                             const char *body,
-                            int okay_1, int okay_2, apr_pool_t *pool);
-
+                            int okay_1,
+                            int okay_2,
+                            apr_pool_t *pool);
 
 /* Convenience statement macro for setting headers in a hash */
 #define svn_ra_neon__set_header(hash, hdr, val) \
@@ -1022,6 +1033,7 @@ svn_error_t *
 svn_ra_neon__get_locks(svn_ra_session_t *session,
                        apr_hash_t **locks,
                        const char *path,
+                       svn_depth_t depth,
                        apr_pool_t *pool);
 
 /*
@@ -1098,14 +1110,22 @@ svn_ra_neon__has_capability(svn_ra_sessi
    RAS->capabilities with the server's capabilities as read from the
    response headers.  Use POOL only for temporary allocation.
 
+   If the RELOCATION_LOCATION is non-NULL, allow the OPTIONS response
+   to report a server-dictated redirect or relocation (HTTP 301 or 302
+   error codes), setting *RELOCATION_LOCATION to the value of the
+   corrected repository URL.  Otherwise, such responses from the
+   server will generate an error.  (In either case, no capabilities are
+   exchanged if there is, in fact, such a response from the server.)
+
    If the server is kind enough to tell us the current youngest
    revision of the target repository, set *YOUNGEST_REV to that value;
    set it to SVN_INVALID_REVNUM otherwise.
 
-  NOTE:  This function also expects the server to announce the
+   NOTE:  This function also expects the server to announce the
    activity collection.  */
 svn_error_t *
 svn_ra_neon__exchange_capabilities(svn_ra_neon__session_t *ras,
+                                   const char **relocation_location,
                                    svn_revnum_t *youngest_rev,
                                    apr_pool_t *pool);
 

Modified: subversion/branches/py-tests-as-modules/subversion/libsvn_ra_neon/session.c
URL: http://svn.apache.org/viewvc/subversion/branches/py-tests-as-modules/subversion/libsvn_ra_neon/session.c?rev=997472&r1=997471&r2=997472&view=diff
==============================================================================
--- subversion/branches/py-tests-as-modules/subversion/libsvn_ra_neon/session.c (original)
+++ subversion/branches/py-tests-as-modules/subversion/libsvn_ra_neon/session.c Wed Sep 15 19:32:26 2010
@@ -94,8 +94,8 @@ static int request_auth(void *userdata, 
   void *creds;
   svn_auth_cred_simple_t *simple_creds;
 
-  /* Start by clearing the cache of any previously-fetched username. */
-  ras->auth_username = NULL;
+  /* Start by marking the current credentials invalid. */
+  ras->auth_used = FALSE;
 
   /* No auth_baton?  Give up. */
   if (! ras->callbacks->auth_baton)
@@ -135,13 +135,14 @@ static int request_auth(void *userdata, 
     }
   simple_creds = creds;
 
+  /* Make svn_ra_neon__request_dispatch store the credentials after it
+     sees a succesful response */
+  ras->auth_used = TRUE;
+
   /* ### silently truncates username/password to 256 chars. */
   apr_cpystrn(username, simple_creds->username, NE_ABUFSIZ);
   apr_cpystrn(password, simple_creds->password, NE_ABUFSIZ);
 
-  /* Cache the fetched username in ra_session. */
-  ras->auth_username = apr_pstrdup(ras->pool, simple_creds->username);
-
   return 0;
 }
 
@@ -771,6 +772,7 @@ ensure_neon_initialized(void)
 
 static svn_error_t *
 svn_ra_neon__open(svn_ra_session_t *session,
+                  const char **corrected_url,
                   const char *repos_URL,
                   const svn_ra_callbacks2_t *callbacks,
                   void *callback_baton,
@@ -1072,7 +1074,8 @@ svn_ra_neon__open(svn_ra_session_t *sess
 
   session->priv = ras;
 
-  return svn_ra_neon__exchange_capabilities(ras, &ignored_revnum, pool);
+  return svn_ra_neon__exchange_capabilities(ras, corrected_url,
+                                            &ignored_revnum, pool);
 }
 
 
@@ -1128,6 +1131,33 @@ static svn_error_t *svn_ra_neon__get_rep
   return SVN_NO_ERROR;
 }
 
+/* Copied from svn_ra_get_path_relative_to_root() and de-vtable-ized
+   to prevent a dependency cycle. */
+svn_error_t *
+svn_ra_neon__get_path_relative_to_root(svn_ra_session_t *session,
+                                       const char **rel_path,
+                                       const char *url,
+                                       apr_pool_t *pool)
+{
+  const char *root_url;
+
+  SVN_ERR(svn_ra_neon__get_repos_root(session, &root_url, pool));
+  if (strcmp(root_url, url) == 0)
+    {
+      *rel_path = "";
+    }
+  else
+    {
+      *rel_path = svn_uri_is_child(root_url, url, pool);
+      if (! *rel_path)
+        return svn_error_createf(SVN_ERR_RA_ILLEGAL_URL, NULL,
+                                 _("'%s' isn't a child of repository root "
+                                   "URL '%s'"),
+                                 url, root_url);
+      *rel_path = svn_path_uri_decode(*rel_path, pool);
+    }
+  return SVN_NO_ERROR;
+}
 
 static svn_error_t *svn_ra_neon__do_get_uuid(svn_ra_session_t *session,
                                              const char **uuid,
@@ -1143,7 +1173,6 @@ static svn_error_t *svn_ra_neon__do_get_
       SVN_ERR(svn_ra_neon__search_for_starting_props(&rsrc, &lopped_path,
                                                      ras, ras->url->data,
                                                      pool));
-      SVN_ERR(svn_ra_neon__maybe_store_auth_info(ras, pool));
 
       if (! ras->uuid)
         {

Modified: subversion/branches/py-tests-as-modules/subversion/libsvn_ra_neon/util.c
URL: http://svn.apache.org/viewvc/subversion/branches/py-tests-as-modules/subversion/libsvn_ra_neon/util.c?rev=997472&r1=997471&r2=997472&view=diff
==============================================================================
--- subversion/branches/py-tests-as-modules/subversion/libsvn_ra_neon/util.c (original)
+++ subversion/branches/py-tests-as-modules/subversion/libsvn_ra_neon/util.c Wed Sep 15 19:32:26 2010
@@ -82,6 +82,7 @@ xml_parser_create(svn_ra_neon__request_t
  * for our custom error parser - could use the ne_basic.h interfaces.
  */
 
+/* List of XML elements expected in 207 Multi-Status responses. */
 static const svn_ra_neon__xml_elm_t multistatus_elements[] =
   { { "DAV:", "multistatus", ELEM_multistatus, 0 },
     { "DAV:", "response", ELEM_response, 0 },
@@ -99,6 +100,21 @@ static const svn_ra_neon__xml_elm_t mult
   };
 
 
+/* Sparse matrix listing the permitted child elements of each element.
+
+   The permitted direct children of the element named in the first column are
+   the elements named in the remainder of the row.
+
+   There may be any number of rows, and any number of columns in each row; any
+   non-positive value (such as SVN_RA_NEON__XML_INVALID) serves as a sentinel.
+
+   The last element in a row is returned if the head-of-row element is found
+   with a child that's not listed in the remainder of the row.  The singleton
+   element of the last (sentinel) row is returned if a tag-with-children is
+   found that isn't the head of any row.
+
+   See validate_element().
+ */
 static const int multistatus_nesting_table[][5] =
   { { ELEM_root, ELEM_multistatus, SVN_RA_NEON__XML_INVALID },
     { ELEM_multistatus, ELEM_response, ELEM_responsedescription,
@@ -115,6 +131,11 @@ static const int multistatus_nesting_tab
   };
 
 
+/* PARENT and CHILD are enum values of ELEM_* type.
+   Return a positive integer if CHILD is a valid direct child of PARENT, and
+   a negative integer (SVN_RA_NEON__XML_INVALID or SVN_RA_NEON__XML_DECLINE,
+   at the moment) otherwise.
+ */
 static int
 validate_element(int parent, int child)
 {
@@ -148,6 +169,7 @@ typedef struct
   svn_boolean_t contains_error;
 } multistatus_baton_t;
 
+/* Implements svn_ra_neon__startelm_cb_t. */
 static svn_error_t *
 start_207_element(int *elem, void *baton, int parent,
                   const char *nspace, const char *name, const char **atts)
@@ -193,6 +215,7 @@ start_207_element(int *elem, void *baton
   return SVN_NO_ERROR;
 }
 
+/* Implements svn_ra_neon__endelm_cb_t . */
 static svn_error_t *
 end_207_element(void *baton, int state,
                 const char *nspace, const char *name)
@@ -269,23 +292,24 @@ end_207_element(void *baton, int state,
 }
 
 
-static ne_xml_parser *
+/* Create a status parser attached to the request REQ.  Detected errors
+   will be returned there. */
+static void
 multistatus_parser_create(svn_ra_neon__request_t *req)
 {
   multistatus_baton_t *b = apr_pcalloc(req->pool, sizeof(*b));
-  ne_xml_parser *multistatus_parser =
-    svn_ra_neon__xml_parser_create(req, ne_accept_207,
-                                   start_207_element,
-                                   svn_ra_neon__xml_collect_cdata,
-                                   end_207_element, b);
+
+  /* Create a parser, attached to REQ. (Ignore the return value.) */
+  svn_ra_neon__xml_parser_create(req, ne_accept_207,
+                                 start_207_element,
+                                 svn_ra_neon__xml_collect_cdata,
+                                 end_207_element, b);
   b->cdata = svn_stringbuf_create("", req->pool);
   b->description = svn_stringbuf_create("", req->pool);
   b->req = req;
 
   b->propname = svn_stringbuf_create("", req->pool);
   b->propstat_description = svn_stringbuf_create("", req->pool);
-
-  return multistatus_parser;
 }
 
 
@@ -354,21 +378,24 @@ path_from_url(const char *url)
   return *p == '\0' ? "/" : p;
 }
 
-svn_ra_neon__request_t *
-svn_ra_neon__request_create(svn_ra_neon__session_t *sess,
+svn_error_t *
+svn_ra_neon__request_create(svn_ra_neon__request_t **request,
+                            svn_ra_neon__session_t *sess,
                             const char *method, const char *url,
                             apr_pool_t *pool)
 {
   apr_pool_t *reqpool = svn_pool_create(pool);
-  svn_ra_neon__request_t *req = apr_pcalloc(reqpool, sizeof(*req));
+  svn_ra_neon__request_t *req;
+  const char *path;
 
   /* We never want to send Neon an absolute URL, since that can cause
      problems with some servers (for example, those that may be accessed
      using different server names from different locations, or those that
      want to rewrite the incoming URL).  If the URL passed in is absolute,
      convert it to a path-absolute relative URL. */
-  const char *path = path_from_url(url);
+  path = path_from_url(url);
 
+  req = apr_pcalloc(reqpool, sizeof(*req));
   req->ne_sess = sess->main_session_busy ? sess->ne_sess2 : sess->ne_sess;
   req->ne_req = ne_request_create(req->ne_sess, method, path);
   req->sess = sess;
@@ -387,7 +414,8 @@ svn_ra_neon__request_create(svn_ra_neon_
                             dav_request_cleanup,
                             apr_pool_cleanup_null);
 
-  return req;
+  *request = req;
+  return SVN_NO_ERROR;
 }
 
 static apr_status_t
@@ -399,6 +427,10 @@ compressed_body_reader_cleanup(void *bat
   return APR_SUCCESS;
 }
 
+/* Attach READER as a response reader for the request REQ, with the
+ * acceptance function ACCPT.  The response body data will be decompressed,
+ * if compressed, before being passed to READER.  USERDATA will be passed as
+ * the first argument to the acceptance and reader callbacks. */
 static void
 attach_ne_body_reader(svn_ra_neon__request_t *req,
                       ne_accept_response accpt,
@@ -558,6 +590,7 @@ generate_error(svn_ra_neon__request_t *r
 
         case 301:
         case 302:
+        case 307:
           return svn_error_create
             (SVN_ERR_RA_DAV_RELOCATED, NULL,
              apr_psprintf(pool,
@@ -742,7 +775,18 @@ start_err_element(void *baton, int paren
                                  atts);
 
         if (errcode_str && *err)
-          (*err)->apr_err = atoi(errcode_str);
+          {
+            apr_int64_t val;
+            svn_error_t *err2;
+
+            err2 = svn_cstring_atoi64(&val, errcode_str);
+            if (err2)
+              {
+                svn_error_clear(err2);
+                break;
+              }
+            (*err)->apr_err = (apr_status_t)val;
+          }
 
         break;
       }
@@ -1259,12 +1303,10 @@ parsed_request(svn_ra_neon__request_t *r
                                                  success_parser, pool));
 
   /* run the request and get the resulting status code. */
-  SVN_ERR(svn_ra_neon__request_dispatch(status_code,
-                                        req, extra_headers, body,
-                                        (strcmp(method, "PROPFIND") == 0)
-                                        ? 207 : 200,
-                                        0, /* not used */
-                                        pool));
+  SVN_ERR(svn_ra_neon__request_dispatch(
+              status_code, req, extra_headers, body,
+              (strcmp(method, "PROPFIND") == 0) ? 207 : 200,
+              0, pool));
 
   if (spool_response)
     {
@@ -1309,14 +1351,16 @@ svn_ra_neon__parsed_request(svn_ra_neon_
                             apr_pool_t *pool)
 {
   /* create/prep the request */
-  svn_ra_neon__request_t* req = svn_ra_neon__request_create(sess, method, url,
-                                                           pool);
-  svn_error_t *err = parsed_request(req,
-                                    sess, method, url, body, body_file,
-                                    set_parser,
-                                    startelm_cb, cdata_cb, endelm_cb,
-                                    baton, extra_headers, status_code,
-                                    spool_response, pool);
+  svn_ra_neon__request_t* req;
+  svn_error_t *err;
+
+  SVN_ERR(svn_ra_neon__request_create(&req, sess, method, url, pool));
+
+  err = parsed_request(req, sess, method, url, body, body_file,
+                       set_parser, startelm_cb, cdata_cb, endelm_cb,
+                       baton, extra_headers, status_code, spool_response,
+                       pool);
+
   svn_ra_neon__request_destroy(req);
   return err;
 }
@@ -1331,13 +1375,12 @@ svn_ra_neon__simple_request(int *code,
                             const char *body,
                             int okay_1, int okay_2, apr_pool_t *pool)
 {
-  svn_ra_neon__request_t *req =
-    svn_ra_neon__request_create(ras, method, url, pool);
+  svn_ra_neon__request_t *req;
   svn_error_t *err;
 
-  /* we don't need the status parser: it's attached to the request
-     and detected errors will be returned there... */
-  (void) multistatus_parser_create(req);
+  SVN_ERR(svn_ra_neon__request_create(&req, ras, method, url, pool));
+
+  multistatus_parser_create(req);
 
   /* svn_ra_neon__request_dispatch() adds the custom error response
      reader.  Neon will take care of the Content-Length calculation */
@@ -1483,6 +1526,15 @@ svn_ra_neon__request_dispatch(int *code_
   req->code_desc = apr_pstrdup(pool, statstruct->reason_phrase);
   req->code = statstruct->code;
 
+  /* If we see a successful request that used authentication, we should store
+     the credentials for future use. */
+  if (req->sess->auth_used
+      && statstruct->code < 400)
+    {
+      req->sess->auth_used = FALSE;
+      SVN_ERR(svn_ra_neon__maybe_store_auth_info(req->sess, pool));
+    }
+
   if (code_p)
      *code_p = req->code;
 
@@ -1510,5 +1562,8 @@ svn_ra_neon__request_get_location(svn_ra
                                   apr_pool_t *pool)
 {
   const char *val = ne_get_response_header(request->ne_req, "Location");
-  return val ? svn_uri_canonicalize(val, pool) : NULL;
+  return val ? svn_uri_join(request->url,
+                            svn_uri_canonicalize(val, pool),
+                            pool)
+             : NULL;
 }

Modified: subversion/branches/py-tests-as-modules/subversion/libsvn_ra_serf/auth.c
URL: http://svn.apache.org/viewvc/subversion/branches/py-tests-as-modules/subversion/libsvn_ra_serf/auth.c?rev=997472&r1=997471&r2=997472&view=diff
==============================================================================
--- subversion/branches/py-tests-as-modules/subversion/libsvn_ra_serf/auth.c (original)
+++ subversion/branches/py-tests-as-modules/subversion/libsvn_ra_serf/auth.c Wed Sep 15 19:32:26 2010
@@ -54,6 +54,7 @@ setup_request_basic_auth(svn_ra_serf__co
                          serf_bucket_t *hdrs_bkt);
 #endif
 
+#if ! SERF_VERSION_AT_LEAST(0, 4, 0)
 static svn_error_t *
 handle_proxy_basic_auth(svn_ra_serf__handler_t *ctx,
                         serf_request_t *request,
@@ -73,6 +74,9 @@ setup_request_proxy_basic_auth(svn_ra_se
                                const char *uri,
                                serf_bucket_t *hdrs_bkt);
 
+#endif
+
+#if ! SERF_VERSION_AT_LEAST(0, 4, 0) || defined(SVN_RA_SERF_SSPI_ENABLED)
 static svn_error_t *
 default_auth_response_handler(svn_ra_serf__handler_t *ctx,
                               serf_request_t *request,
@@ -81,6 +85,7 @@ default_auth_response_handler(svn_ra_ser
 {
   return SVN_NO_ERROR;
 }
+#endif
 
 /*** Global variables. ***/
 static const svn_ra_serf__auth_protocol_t serf_auth_protocols[] = {
@@ -166,10 +171,11 @@ svn_ra_serf__encode_auth_header(const ch
                                 const char *data, apr_size_t data_len,
                                 apr_pool_t *pool)
 {
-  apr_size_t encoded_len, proto_len;
+  int encoded_len;
+  size_t proto_len;
   char *ptr;
 
-  encoded_len = apr_base64_encode_len(data_len);
+  encoded_len = apr_base64_encode_len((int) data_len);
   proto_len = strlen(protocol);
 
   ptr = apr_palloc(pool, encoded_len + proto_len + 1);
@@ -179,7 +185,7 @@ svn_ra_serf__encode_auth_header(const ch
   ptr += proto_len;
   *ptr++ = ' ';
 
-  apr_base64_encode(ptr, data, data_len);
+  apr_base64_encode(ptr, data, (int) data_len);
 }
 
 /**
@@ -506,6 +512,7 @@ setup_request_basic_auth(svn_ra_serf__co
 }
 #endif
 
+#if ! SERF_VERSION_AT_LEAST(0, 4, 0)
 static svn_error_t *
 handle_proxy_basic_auth(svn_ra_serf__handler_t *ctx,
                         serf_request_t *request,
@@ -574,3 +581,4 @@ setup_request_proxy_basic_auth(svn_ra_se
 
   return SVN_NO_ERROR;
 }
+#endif

Modified: subversion/branches/py-tests-as-modules/subversion/libsvn_ra_serf/blame.c
URL: http://svn.apache.org/viewvc/subversion/branches/py-tests-as-modules/subversion/libsvn_ra_serf/blame.c?rev=997472&r1=997471&r2=997472&view=diff
==============================================================================
--- subversion/branches/py-tests-as-modules/subversion/libsvn_ra_serf/blame.c (original)
+++ subversion/branches/py-tests-as-modules/subversion/libsvn_ra_serf/blame.c Wed Sep 15 19:32:26 2010
@@ -330,7 +330,7 @@ end_blame(svn_ra_serf__xml_parser_t *par
   else if (state == TXDELTA &&
            strcmp(name.name, "txdelta") == 0)
     {
-      svn_stream_close(info->stream);
+      SVN_ERR(svn_stream_close(info->stream));
 
       svn_ra_serf__xml_pop_state(parser);
     }
@@ -382,8 +382,10 @@ cdata_blame(svn_ra_serf__xml_parser_t *p
   return SVN_NO_ERROR;
 }
 
-static serf_bucket_t*
-create_file_revs_body(void *baton,
+/* Implements svn_ra_serf__request_body_delegate_t */
+static svn_error_t *
+create_file_revs_body(serf_bucket_t **body_bkt,
+                      void *baton,
                       serf_bucket_alloc_t *alloc,
                       apr_pool_t *pool)
 {
@@ -419,7 +421,8 @@ create_file_revs_body(void *baton,
   svn_ra_serf__add_close_tag_buckets(buckets, alloc,
                                      "S:file-revs-report");
 
-  return buckets;
+  *body_bkt = buckets;
+  return SVN_NO_ERROR;
 }
 
 svn_error_t *
@@ -483,8 +486,10 @@ svn_ra_serf__get_file_revs(svn_ra_sessio
   err = svn_ra_serf__context_run_wait(&blame_ctx->done, session, pool);
 
   err = svn_error_compose_create(
-                svn_ra_serf__error_on_status(status_code, handler->path),
-                err);
+            svn_ra_serf__error_on_status(status_code,
+                                         handler->path,
+                                         parser_ctx->location),
+            err);
 
   return svn_error_return(err);
 }

Modified: subversion/branches/py-tests-as-modules/subversion/libsvn_ra_serf/commit.c
URL: http://svn.apache.org/viewvc/subversion/branches/py-tests-as-modules/subversion/libsvn_ra_serf/commit.c?rev=997472&r1=997471&r2=997472&view=diff
==============================================================================
--- subversion/branches/py-tests-as-modules/subversion/libsvn_ra_serf/commit.c (original)
+++ subversion/branches/py-tests-as-modules/subversion/libsvn_ra_serf/commit.c Wed Sep 15 19:32:26 2010
@@ -220,20 +220,28 @@ static svn_error_t *
 return_response_err(svn_ra_serf__handler_t *handler,
                     svn_ra_serf__simple_request_context_t *ctx)
 {
+  svn_error_t *err;
+
+  /* Ye Olde Fallback Error */
+  err = svn_error_compose_create(
+            ctx->server_error.error,
+            svn_error_createf(SVN_ERR_RA_DAV_REQUEST_FAILED, NULL,
+                              "%s of '%s': %d %s",
+                              handler->method, handler->path,
+                              ctx->status, ctx->reason));
+
   /* Try to return one of the standard errors for 301, 404, etc.,
      then look for an error embedded in the response.  */
-  return svn_error_compose_create(
-    svn_ra_serf__error_on_status(ctx->status, handler->path),
-    svn_error_compose_create(
-      ctx->server_error.error,
-      svn_error_createf(SVN_ERR_RA_DAV_REQUEST_FAILED, NULL,
-                        "%s of '%s': %d %s",
-                        handler->method, handler->path,
-                        ctx->status, ctx->reason)));
+  return svn_error_compose_create(svn_ra_serf__error_on_status(ctx->status,
+                                                               handler->path,
+                                                               ctx->location),
+                                  err);
 }
 
-static serf_bucket_t *
-create_checkout_body(void *baton,
+/* Implements svn_ra_serf__request_body_delegate_t */
+static svn_error_t *
+create_checkout_body(serf_bucket_t **bkt,
+                     void *baton,
                      serf_bucket_alloc_t *alloc,
                      apr_pool_t *pool)
 {
@@ -257,7 +265,8 @@ create_checkout_body(void *baton,
   svn_ra_serf__add_tag_buckets(body_bkt, "D:apply-to-version", NULL, alloc);
   svn_ra_serf__add_close_tag_buckets(body_bkt, alloc, "D:checkout");
 
-  return body_bkt;
+  *bkt = body_bkt;
+  return SVN_NO_ERROR;
 }
 
 /* Implements svn_ra_serf__response_handler_t */
@@ -627,6 +636,46 @@ checkout_file(file_context_t *file)
   return SVN_NO_ERROR;
 }
 
+/* Helper function for proppatch_walker() below. */
+static svn_error_t *
+get_encoding_and_cdata(const char **encoding_p,
+                       serf_bucket_t **cdata_bkt_p,
+                       serf_bucket_alloc_t *alloc,
+                       const svn_string_t *value,
+                       apr_pool_t *pool)
+{
+  const char *encoding;
+  const char *cdata;
+  apr_size_t len; /* of cdata */
+
+  SVN_ERR_ASSERT(value);
+
+  /* If a property is XML-safe, XML-encode it.  Else, base64-encode
+     it. */
+  if (svn_xml_is_xml_safe(value->data, value->len))
+    {
+      svn_stringbuf_t *xml_esc = NULL;
+      svn_xml_escape_cdata_string(&xml_esc, value, pool);
+      encoding = NULL;
+      cdata = xml_esc->data;
+      len = xml_esc->len;
+    }
+  else
+    {
+      const svn_string_t *base64ed = svn_base64_encode_string2(value, TRUE,
+                                                               pool);
+      encoding = "base64";
+      cdata = base64ed->data;
+      len = base64ed->len;
+    }
+
+  /* ENCODING, CDATA, and LEN are now set. */
+
+  *encoding_p = encoding;
+  *cdata_bkt_p = SERF_BUCKET_SIMPLE_STRING_LEN(cdata, len, alloc);
+  return SVN_NO_ERROR;
+}
+
 static svn_error_t *
 proppatch_walker(void *baton,
                  const char *ns, apr_ssize_t ns_len,
@@ -635,15 +684,11 @@ proppatch_walker(void *baton,
                  apr_pool_t *pool)
 {
   serf_bucket_t *body_bkt = baton;
+  serf_bucket_t *cdata_bkt;
   serf_bucket_alloc_t *alloc;
-  svn_boolean_t binary_prop;
+  const char *encoding;
   char *prop_name;
 
-  if (svn_xml_is_xml_safe(val->data, val->len))
-    binary_prop = FALSE;
-  else
-    binary_prop = TRUE;
-
   /* Use the namespace prefix instead of adding the xmlns attribute to support
      property names containing ':' */
   if (strcmp(ns, SVN_DAV_PROP_NS_SVN) == 0)
@@ -654,28 +699,18 @@ proppatch_walker(void *baton,
 
   alloc = body_bkt->allocator;
 
+  SVN_ERR(get_encoding_and_cdata(&encoding, &cdata_bkt, alloc, val, pool));
+
   svn_ra_serf__add_open_tag_buckets(body_bkt, alloc, prop_name,
-                                    "V:encoding", binary_prop ? "base64" : NULL,
+                                    "V:encoding", encoding,
                                     NULL);
-
-  if (binary_prop)
-    {
-      serf_bucket_t *tmp_bkt;
-      val = svn_base64_encode_string2(val, TRUE, pool);
-      tmp_bkt = SERF_BUCKET_SIMPLE_STRING_LEN(val->data, val->len, alloc);
-      serf_bucket_aggregate_append(body_bkt, tmp_bkt);
-    }
-  else
-    {
-      svn_ra_serf__add_cdata_len_buckets(body_bkt, alloc, val->data, val->len);
-    }
-
-
+  serf_bucket_aggregate_append(body_bkt, cdata_bkt);
   svn_ra_serf__add_close_tag_buckets(body_bkt, alloc, prop_name);
+
   return SVN_NO_ERROR;
 }
 
-static apr_status_t
+static svn_error_t *
 setup_proppatch_headers(serf_bucket_t *headers,
                         void *baton,
                         apr_pool_t *pool)
@@ -706,11 +741,13 @@ setup_proppatch_headers(serf_bucket_t *h
         }
     }
 
-  return APR_SUCCESS;
+  return SVN_NO_ERROR;
 }
 
-static serf_bucket_t *
-create_proppatch_body(void *baton,
+/* Implements svn_ra_serf__request_body_delegate_t */
+static svn_error_t *
+create_proppatch_body(serf_bucket_t **bkt,
+                      void *baton,
                       serf_bucket_alloc_t *alloc,
                       apr_pool_t *pool)
 {
@@ -732,9 +769,9 @@ create_proppatch_body(void *baton,
       svn_ra_serf__add_open_tag_buckets(body_bkt, alloc, "D:set", NULL);
       svn_ra_serf__add_open_tag_buckets(body_bkt, alloc, "D:prop", NULL);
 
-      svn_ra_serf__walk_all_props(ctx->changed_props, ctx->path,
-                                  SVN_INVALID_REVNUM,
-                                  proppatch_walker, body_bkt, pool);
+      SVN_ERR(svn_ra_serf__walk_all_props(ctx->changed_props, ctx->path,
+                                          SVN_INVALID_REVNUM,
+                                          proppatch_walker, body_bkt, pool));
 
       svn_ra_serf__add_close_tag_buckets(body_bkt, alloc, "D:prop");
       svn_ra_serf__add_close_tag_buckets(body_bkt, alloc, "D:set");
@@ -745,9 +782,9 @@ create_proppatch_body(void *baton,
       svn_ra_serf__add_open_tag_buckets(body_bkt, alloc, "D:remove", NULL);
       svn_ra_serf__add_open_tag_buckets(body_bkt, alloc, "D:prop", NULL);
 
-      svn_ra_serf__walk_all_props(ctx->removed_props, ctx->path,
-                                  SVN_INVALID_REVNUM,
-                                  proppatch_walker, body_bkt, pool);
+      SVN_ERR(svn_ra_serf__walk_all_props(ctx->removed_props, ctx->path,
+                                          SVN_INVALID_REVNUM,
+                                          proppatch_walker, body_bkt, pool));
 
       svn_ra_serf__add_close_tag_buckets(body_bkt, alloc, "D:prop");
       svn_ra_serf__add_close_tag_buckets(body_bkt, alloc, "D:remove");
@@ -755,7 +792,8 @@ create_proppatch_body(void *baton,
 
   svn_ra_serf__add_close_tag_buckets(body_bkt, alloc, "D:propertyupdate");
 
-  return body_bkt;
+  *bkt = body_bkt;
+  return SVN_NO_ERROR;
 }
 
 static svn_error_t*
@@ -797,8 +835,10 @@ proppatch_resource(proppatch_context_t *
   return SVN_NO_ERROR;
 }
 
-static serf_bucket_t *
-create_put_body(void *baton,
+/* Implements svn_ra_serf__request_body_delegate_t */
+static svn_error_t *
+create_put_body(serf_bucket_t **body_bkt,
+                void *baton,
                 serf_bucket_alloc_t *alloc,
                 apr_pool_t *pool)
 {
@@ -821,18 +861,22 @@ create_put_body(void *baton,
   offset = 0;
   apr_file_seek(ctx->svndiff, APR_SET, &offset);
 
-  return serf_bucket_file_create(ctx->svndiff, alloc);
+  *body_bkt = serf_bucket_file_create(ctx->svndiff, alloc);
+  return SVN_NO_ERROR;
 }
 
-static serf_bucket_t *
-create_empty_put_body(void *baton,
+/* Implements svn_ra_serf__request_body_delegate_t */
+static svn_error_t *
+create_empty_put_body(serf_bucket_t **body_bkt,
+                      void *baton,
                       serf_bucket_alloc_t *alloc,
                       apr_pool_t *pool)
 {
-  return SERF_BUCKET_SIMPLE_STRING("", alloc);
+  *body_bkt = SERF_BUCKET_SIMPLE_STRING("", alloc);
+  return SVN_NO_ERROR;
 }
 
-static apr_status_t
+static svn_error_t *
 setup_put_headers(serf_bucket_t *headers,
                   void *baton,
                   apr_pool_t *pool)
@@ -877,7 +921,7 @@ setup_put_headers(serf_bucket_t *headers
   return APR_SUCCESS;
 }
 
-static apr_status_t
+static svn_error_t *
 setup_copy_file_headers(serf_bucket_t *headers,
                         void *baton,
                         apr_pool_t *pool)
@@ -896,10 +940,10 @@ setup_copy_file_headers(serf_bucket_t *h
   serf_bucket_headers_set(headers, "Depth", "0");
   serf_bucket_headers_set(headers, "Overwrite", "T");
 
-  return APR_SUCCESS;
+  return SVN_NO_ERROR;
 }
 
-static apr_status_t
+static svn_error_t *
 setup_copy_dir_headers(serf_bucket_t *headers,
                        void *baton,
                        apr_pool_t *pool)
@@ -940,10 +984,10 @@ setup_copy_dir_headers(serf_bucket_t *he
                apr_pstrdup(dir->commit->pool, dir->name), APR_HASH_KEY_STRING,
                (void*)1);
 
-  return APR_SUCCESS;
+  return SVN_NO_ERROR;
 }
 
-static apr_status_t
+static svn_error_t *
 setup_delete_headers(serf_bucket_t *headers,
                      void *baton,
                      apr_pool_t *pool)
@@ -973,11 +1017,13 @@ setup_delete_headers(serf_bucket_t *head
         }
     }
 
-  return APR_SUCCESS;
+  return SVN_NO_ERROR;
 }
 
-static serf_bucket_t *
-create_delete_body(void *baton,
+/* Implements svn_ra_serf__request_body_delegate_t */
+static svn_error_t *
+create_delete_body(serf_bucket_t **body_bkt,
+                   void *baton,
                    serf_bucket_alloc_t *alloc,
                    apr_pool_t *pool)
 {
@@ -991,7 +1037,8 @@ create_delete_body(void *baton,
   svn_ra_serf__merge_lock_token_list(ctx->lock_token_hash, ctx->path,
                                      body, alloc, pool);
 
-  return body;
+  *body_bkt = body;
+  return SVN_NO_ERROR;
 }
 
 /* Helper function to write the svndiff stream to temporary file. */
@@ -1014,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
 {
@@ -1093,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;
@@ -1992,8 +2054,9 @@ close_edit(void *edit_baton,
     }
 
   /* Inform the WC that we did a commit.  */
-  SVN_ERR(ctx->callback(svn_ra_serf__merge_get_commit_info(merge_ctx),
-                        ctx->callback_baton, pool));
+  if (ctx->callback)
+    SVN_ERR(ctx->callback(svn_ra_serf__merge_get_commit_info(merge_ctx),
+                          ctx->callback_baton, pool));
 
   /* If we're using activities, DELETE our completed activity.  */
   if (ctx->activity_url)

Modified: subversion/branches/py-tests-as-modules/subversion/libsvn_ra_serf/get_deleted_rev.c
URL: http://svn.apache.org/viewvc/subversion/branches/py-tests-as-modules/subversion/libsvn_ra_serf/get_deleted_rev.c?rev=997472&r1=997471&r2=997472&view=diff
==============================================================================
--- subversion/branches/py-tests-as-modules/subversion/libsvn_ra_serf/get_deleted_rev.c (original)
+++ subversion/branches/py-tests-as-modules/subversion/libsvn_ra_serf/get_deleted_rev.c Wed Sep 15 19:32:26 2010
@@ -136,8 +136,10 @@ cdata_getdrev(svn_ra_serf__xml_parser_t 
   return SVN_NO_ERROR;
 }
 
-static serf_bucket_t*
-create_getdrev_body(void *baton,
+/* Implements svn_ra_serf__request_body_delegate_t */
+static svn_error_t *
+create_getdrev_body(serf_bucket_t **body_bkt,
+                    void *baton,
                     serf_bucket_alloc_t *alloc,
                     apr_pool_t *pool)
 {
@@ -169,7 +171,8 @@ create_getdrev_body(void *baton,
   svn_ra_serf__add_close_tag_buckets(buckets, alloc,
                                      "S:get-deleted-rev-report");
 
-  return buckets;
+  *body_bkt = buckets;
+  return SVN_NO_ERROR;
 }
 
 svn_error_t *

Modified: subversion/branches/py-tests-as-modules/subversion/libsvn_ra_serf/getdate.c
URL: http://svn.apache.org/viewvc/subversion/branches/py-tests-as-modules/subversion/libsvn_ra_serf/getdate.c?rev=997472&r1=997471&r2=997472&view=diff
==============================================================================
--- subversion/branches/py-tests-as-modules/subversion/libsvn_ra_serf/getdate.c (original)
+++ subversion/branches/py-tests-as-modules/subversion/libsvn_ra_serf/getdate.c Wed Sep 15 19:32:26 2010
@@ -164,8 +164,10 @@ cdata_getdate(svn_ra_serf__xml_parser_t 
   return SVN_NO_ERROR;
 }
 
-static serf_bucket_t*
-create_getdate_body(void *baton,
+/* Implements svn_ra_serf__request_body_delegate_t */
+static svn_error_t *
+create_getdate_body(serf_bucket_t **body_bkt,
+                    void *baton,
                     serf_bucket_alloc_t *alloc,
                     apr_pool_t *pool)
 {
@@ -186,7 +188,8 @@ create_getdate_body(void *baton,
 
   svn_ra_serf__add_close_tag_buckets(buckets, alloc, "S:dated-rev-report");
 
-  return buckets;
+  *body_bkt = buckets;
+  return SVN_NO_ERROR;
 }
 
 svn_error_t *

Modified: subversion/branches/py-tests-as-modules/subversion/libsvn_ra_serf/getlocations.c
URL: http://svn.apache.org/viewvc/subversion/branches/py-tests-as-modules/subversion/libsvn_ra_serf/getlocations.c?rev=997472&r1=997471&r2=997472&view=diff
==============================================================================
--- subversion/branches/py-tests-as-modules/subversion/libsvn_ra_serf/getlocations.c (original)
+++ subversion/branches/py-tests-as-modules/subversion/libsvn_ra_serf/getlocations.c Wed Sep 15 19:32:26 2010
@@ -180,8 +180,10 @@ end_getloc(svn_ra_serf__xml_parser_t *pa
   return SVN_NO_ERROR;
 }
 
-static serf_bucket_t*
-create_get_locations_body(void *baton,
+/* Implements svn_ra_serf__request_body_delegate_t */
+static svn_error_t *
+create_get_locations_body(serf_bucket_t **body_bkt,
+                          void *baton,
                           serf_bucket_alloc_t *alloc,
                           apr_pool_t *pool)
 {
@@ -216,7 +218,8 @@ create_get_locations_body(void *baton,
   svn_ra_serf__add_close_tag_buckets(buckets, alloc,
                                      "S:get-locations");
 
-  return buckets;
+  *body_bkt = buckets;
+  return SVN_NO_ERROR;
 }
 
 svn_error_t *
@@ -277,7 +280,9 @@ svn_ra_serf__get_locations(svn_ra_sessio
   err = svn_ra_serf__context_run_wait(&loc_ctx->done, session, pool);
 
   SVN_ERR(svn_error_compose_create(
-              svn_ra_serf__error_on_status(loc_ctx->status_code, req_url),
+              svn_ra_serf__error_on_status(loc_ctx->status_code,
+                                           req_url,
+                                           parser_ctx->location),
               err));
 
   return SVN_NO_ERROR;

Modified: subversion/branches/py-tests-as-modules/subversion/libsvn_ra_serf/getlocationsegments.c
URL: http://svn.apache.org/viewvc/subversion/branches/py-tests-as-modules/subversion/libsvn_ra_serf/getlocationsegments.c?rev=997472&r1=997471&r2=997472&view=diff
==============================================================================
--- subversion/branches/py-tests-as-modules/subversion/libsvn_ra_serf/getlocationsegments.c (original)
+++ subversion/branches/py-tests-as-modules/subversion/libsvn_ra_serf/getlocationsegments.c Wed Sep 15 19:32:26 2010
@@ -126,8 +126,10 @@ end_gls(svn_ra_serf__xml_parser_t *parse
   return SVN_NO_ERROR;
 }
 
-static serf_bucket_t *
-create_gls_body(void *baton,
+/* Implements svn_ra_serf__request_body_delegate_t */
+static svn_error_t *
+create_gls_body(serf_bucket_t **body_bkt,
+                void *baton,
                 serf_bucket_alloc_t *alloc,
                 apr_pool_t *pool)
 {
@@ -163,7 +165,8 @@ create_gls_body(void *baton,
   svn_ra_serf__add_close_tag_buckets(buckets, alloc,
                                      "S:get-location-segments");
 
-  return buckets;
+  *body_bkt = buckets;
+  return SVN_NO_ERROR;
 }
 
 svn_error_t *
@@ -181,7 +184,7 @@ svn_ra_serf__get_location_segments(svn_r
   svn_ra_serf__handler_t *handler;
   svn_ra_serf__xml_parser_t *parser_ctx;
   const char *relative_url, *basecoll_url, *req_url;
-  svn_error_t *err;
+  svn_error_t *err, *err2;
 
   gls_ctx = apr_pcalloc(pool, sizeof(*gls_ctx));
   gls_ctx->path = path;
@@ -230,8 +233,15 @@ svn_ra_serf__get_location_segments(svn_r
                             _("Location segment report failed on '%s'@'%ld'"),
                               path, peg_revision);
 
-  /* ### Leaks err */
-  SVN_ERR(svn_ra_serf__error_on_status(gls_ctx->status_code, handler->path));
+  err2 = svn_ra_serf__error_on_status(gls_ctx->status_code,
+                                      handler->path,
+                                      parser_ctx->location);
+  if (err2)
+    {
+      /* Prefer err2 to err. */
+      svn_error_clear(err);
+      return err2;
+    }
 
   svn_pool_destroy(gls_ctx->subpool);
 

Modified: subversion/branches/py-tests-as-modules/subversion/libsvn_ra_serf/getlocks.c
URL: http://svn.apache.org/viewvc/subversion/branches/py-tests-as-modules/subversion/libsvn_ra_serf/getlocks.c?rev=997472&r1=997471&r2=997472&view=diff
==============================================================================
--- subversion/branches/py-tests-as-modules/subversion/libsvn_ra_serf/getlocks.c (original)
+++ subversion/branches/py-tests-as-modules/subversion/libsvn_ra_serf/getlocks.c Wed Sep 15 19:32:26 2010
@@ -76,6 +76,10 @@ typedef struct {
 typedef struct {
   apr_pool_t *pool;
 
+  /* target and requested depth of the operation. */
+  const char *path; 
+  svn_depth_t requested_depth;
+
   /* return hash */
   apr_hash_t *hash;
 
@@ -180,8 +184,32 @@ end_getlocks(svn_ra_serf__xml_parser_t *
   else if (state == LOCK &&
            strcmp(name.name, "lock") == 0)
     {
-      apr_hash_set(lock_ctx->hash, info->lock->path, APR_HASH_KEY_STRING,
-                   info->lock);
+      /* Filter out unwanted paths.  Since Subversion only allows
+         locks on files, we can treat depth=immediates the same as
+         depth=files for filtering purposes.  Meaning, we'll keep
+         this lock if:
+
+         a) its path is the very path we queried, or
+         b) we've asked for a fully recursive answer, or
+         c) we've asked for depth=files or depth=immediates, and this
+            lock is on an immediate child of our query path.
+      */
+      if ((strcmp(lock_ctx->path, info->lock->path) == 0)
+          || (lock_ctx->requested_depth == svn_depth_infinity))
+        {
+          apr_hash_set(lock_ctx->hash, info->lock->path,
+                       APR_HASH_KEY_STRING, info->lock);
+        }
+      else if ((lock_ctx->requested_depth == svn_depth_files) ||
+               (lock_ctx->requested_depth == svn_depth_immediates))
+        {
+          const char *rel_uri = svn_uri_is_child(lock_ctx->path,
+                                                 info->lock->path,
+                                                 info->pool);
+          if (rel_uri && (svn_path_component_count(rel_uri) == 1))
+            apr_hash_set(lock_ctx->hash, info->lock->path,
+                         APR_HASH_KEY_STRING, info->lock);
+        }
 
       svn_ra_serf__xml_pop_state(parser);
     }
@@ -267,43 +295,52 @@ cdata_getlocks(svn_ra_serf__xml_parser_t
   return SVN_NO_ERROR;
 }
 
-static serf_bucket_t*
-create_getlocks_body(void *baton,
+/* Implements svn_ra_serf__request_body_delegate_t */
+static svn_error_t *
+create_getlocks_body(serf_bucket_t **body_bkt,
+                     void *baton,
                      serf_bucket_alloc_t *alloc,
                      apr_pool_t *pool)
 {
+  lock_context_t *lock_ctx = baton;
   serf_bucket_t *buckets;
 
   buckets = serf_bucket_aggregate_create(alloc);
 
-  svn_ra_serf__add_open_tag_buckets(buckets, alloc, "S:get-locks-report",
-                                    "xmlns:S", SVN_XML_NAMESPACE,
-                                    NULL);
+  svn_ra_serf__add_open_tag_buckets(
+    buckets, alloc, "S:get-locks-report", "xmlns:S", SVN_XML_NAMESPACE,
+    "depth", svn_depth_to_word(lock_ctx->requested_depth), NULL);
   svn_ra_serf__add_close_tag_buckets(buckets, alloc, "S:get-locks-report");
 
-  return buckets;
+  *body_bkt = buckets;
+  return SVN_NO_ERROR;
 }
 
 svn_error_t *
 svn_ra_serf__get_locks(svn_ra_session_t *ra_session,
                        apr_hash_t **locks,
                        const char *path,
+                       svn_depth_t depth,
                        apr_pool_t *pool)
 {
   lock_context_t *lock_ctx;
   svn_ra_serf__session_t *session = ra_session->priv;
   svn_ra_serf__handler_t *handler;
   svn_ra_serf__xml_parser_t *parser_ctx;
-  const char *req_url;
+  const char *req_url, *rel_path;
   int status_code;
 
+  req_url = svn_path_url_add_component2(session->repos_url.path, path, pool);
+  SVN_ERR(svn_ra_serf__get_relative_path(&rel_path, req_url, session,
+                                         NULL, pool));
+
   lock_ctx = apr_pcalloc(pool, sizeof(*lock_ctx));
   lock_ctx->pool = pool;
+  lock_ctx->path = apr_pstrcat(pool, "/", rel_path, NULL);
+  lock_ctx->requested_depth = depth;
   lock_ctx->hash = apr_hash_make(pool);
   lock_ctx->done = FALSE;
 
-  req_url = svn_path_url_add_component2(session->repos_url.path, path, pool);
-
   handler = apr_pcalloc(pool, sizeof(*handler));
 
   handler->method = "REPORT";

Modified: subversion/branches/py-tests-as-modules/subversion/libsvn_ra_serf/locks.c
URL: http://svn.apache.org/viewvc/subversion/branches/py-tests-as-modules/subversion/libsvn_ra_serf/locks.c?rev=997472&r1=997471&r2=997472&view=diff
==============================================================================
--- subversion/branches/py-tests-as-modules/subversion/libsvn_ra_serf/locks.c (original)
+++ subversion/branches/py-tests-as-modules/subversion/libsvn_ra_serf/locks.c Wed Sep 15 19:32:26 2010
@@ -321,7 +321,7 @@ static const svn_ra_serf__dav_props_t lo
   { NULL }
 };
 
-static apr_status_t
+static svn_error_t *
 set_lock_headers(serf_bucket_t *headers,
                  void *baton,
                  apr_pool_t *pool)
@@ -430,8 +430,10 @@ handle_lock(serf_request_t *request,
                                         handler_baton, pool);
 }
 
-static serf_bucket_t*
-create_getlock_body(void *baton,
+/* Implements svn_ra_serf__request_body_delegate_t */
+static svn_error_t *
+create_getlock_body(serf_bucket_t **body_bkt,
+                    void *baton,
                     serf_bucket_alloc_t *alloc,
                     apr_pool_t *pool)
 {
@@ -448,21 +450,24 @@ create_getlock_body(void *baton,
   svn_ra_serf__add_close_tag_buckets(buckets, alloc, "prop");
   svn_ra_serf__add_close_tag_buckets(buckets, alloc, "propfind");
 
-  return buckets;
+  *body_bkt = buckets;
+  return SVN_NO_ERROR;
 }
 
-static apr_status_t
+static svn_error_t*
 setup_getlock_headers(serf_bucket_t *headers,
                       void *baton,
                       apr_pool_t *pool)
 {
   serf_bucket_headers_set(headers, "Depth", "0");
 
-  return APR_SUCCESS;
+  return SVN_NO_ERROR;
 }
 
-static serf_bucket_t*
-create_lock_body(void *baton,
+/* Implements svn_ra_serf__request_body_delegate_t */
+static svn_error_t *
+create_lock_body(serf_bucket_t **body_bkt,
+                 void *baton,
                  serf_bucket_alloc_t *alloc,
                  apr_pool_t *pool)
 {
@@ -492,7 +497,8 @@ create_lock_body(void *baton,
 
   svn_ra_serf__add_close_tag_buckets(buckets, alloc, "lockinfo");
 
-  return buckets;
+  *body_bkt = buckets;
+  return SVN_NO_ERROR;
 }
 
 svn_error_t *
@@ -651,7 +657,7 @@ struct unlock_context_t {
   svn_boolean_t force;
 };
 
-static apr_status_t
+static svn_error_t *
 set_unlock_headers(serf_bucket_t *headers,
                    void *baton,
                    apr_pool_t *pool)
@@ -665,7 +671,7 @@ set_unlock_headers(serf_bucket_t *header
                               SVN_DAV_OPTION_LOCK_BREAK);
     }
 
-  return APR_SUCCESS;
+  return SVN_NO_ERROR;
 }
 
 svn_error_t *

Modified: subversion/branches/py-tests-as-modules/subversion/libsvn_ra_serf/log.c
URL: http://svn.apache.org/viewvc/subversion/branches/py-tests-as-modules/subversion/libsvn_ra_serf/log.c?rev=997472&r1=997471&r2=997472&view=diff
==============================================================================
--- subversion/branches/py-tests-as-modules/subversion/libsvn_ra_serf/log.c (original)
+++ subversion/branches/py-tests-as-modules/subversion/libsvn_ra_serf/log.c Wed Sep 15 19:32:26 2010
@@ -459,8 +459,9 @@ cdata_log(svn_ra_serf__xml_parser_t *par
   return SVN_NO_ERROR;
 }
 
-static serf_bucket_t *
-create_log_body(void *baton,
+static svn_error_t *
+create_log_body(serf_bucket_t **body_bkt,
+                void *baton,
                 serf_bucket_alloc_t *alloc,
                 apr_pool_t *pool)
 {
@@ -550,7 +551,8 @@ create_log_body(void *baton,
   svn_ra_serf__add_close_tag_buckets(buckets, alloc,
                                      "S:log-report");
 
-  return buckets;
+  *body_bkt = buckets;
+  return SVN_NO_ERROR;
 }
 
 svn_error_t *

Modified: subversion/branches/py-tests-as-modules/subversion/libsvn_ra_serf/merge.c
URL: http://svn.apache.org/viewvc/subversion/branches/py-tests-as-modules/subversion/libsvn_ra_serf/merge.c?rev=997472&r1=997471&r2=997472&view=diff
==============================================================================
--- subversion/branches/py-tests-as-modules/subversion/libsvn_ra_serf/merge.c (original)
+++ subversion/branches/py-tests-as-modules/subversion/libsvn_ra_serf/merge.c Wed Sep 15 19:32:26 2010
@@ -405,7 +405,7 @@ cdata_merge(svn_ra_serf__xml_parser_t *p
   return SVN_NO_ERROR;
 }
 
-static apr_status_t
+static svn_error_t *
 setup_merge_headers(serf_bucket_t *headers,
                     void *baton,
                     apr_pool_t *pool)
@@ -418,7 +418,7 @@ setup_merge_headers(serf_bucket_t *heade
                               SVN_DAV_OPTION_RELEASE_LOCKS);
     }
 
-  return APR_SUCCESS;
+  return SVN_NO_ERROR;
 }
 
 void
@@ -469,8 +469,9 @@ svn_ra_serf__merge_lock_token_list(apr_h
   svn_ra_serf__add_close_tag_buckets(body, alloc, "S:lock-token-list");
 }
 
-static serf_bucket_t*
-create_merge_body(void *baton,
+static svn_error_t*
+create_merge_body(serf_bucket_t **bkt,
+                  void *baton,
                   serf_bucket_alloc_t *alloc,
                   apr_pool_t *pool)
 {
@@ -508,7 +509,9 @@ create_merge_body(void *baton,
 
   svn_ra_serf__add_close_tag_buckets(body_bkt, alloc, "D:merge");
 
-  return body_bkt;
+  *bkt = body_bkt;
+
+  return SVN_NO_ERROR;
 }
 
 svn_error_t *

Modified: subversion/branches/py-tests-as-modules/subversion/libsvn_ra_serf/mergeinfo.c
URL: http://svn.apache.org/viewvc/subversion/branches/py-tests-as-modules/subversion/libsvn_ra_serf/mergeinfo.c?rev=997472&r1=997471&r2=997472&view=diff
==============================================================================
--- subversion/branches/py-tests-as-modules/subversion/libsvn_ra_serf/mergeinfo.c (original)
+++ subversion/branches/py-tests-as-modules/subversion/libsvn_ra_serf/mergeinfo.c Wed Sep 15 19:32:26 2010
@@ -176,8 +176,9 @@ cdata_handler(svn_ra_serf__xml_parser_t 
   return SVN_NO_ERROR;
 }
 
-static serf_bucket_t *
-create_mergeinfo_body(void *baton,
+static svn_error_t *
+create_mergeinfo_body(serf_bucket_t **bkt,
+                      void *baton,
                       serf_bucket_alloc_t *alloc,
                       apr_pool_t *pool)
 {
@@ -221,7 +222,8 @@ create_mergeinfo_body(void *baton,
   svn_ra_serf__add_close_tag_buckets(body_bkt, alloc,
                                      "S:" SVN_DAV__MERGEINFO_REPORT);
 
-  return body_bkt;
+  *bkt = body_bkt;
+  return SVN_NO_ERROR;
 }
 
 /* Request a mergeinfo-report from the URL attached to SESSION,
@@ -290,12 +292,12 @@ svn_ra_serf__get_mergeinfo(svn_ra_sessio
 
   err = svn_ra_serf__context_run_wait(&mergeinfo_ctx->done, session, pool);
 
-  err2 = svn_ra_serf__error_on_status(status_code, handler->path);
-
+  err2 = svn_ra_serf__error_on_status(status_code, handler->path,
+                                      parser_ctx->location);
   if (err2)
     {
       svn_error_clear(err);
-      SVN_ERR(err2);
+      return err2;
     }
 
   SVN_ERR(err);

Modified: subversion/branches/py-tests-as-modules/subversion/libsvn_ra_serf/options.c
URL: http://svn.apache.org/viewvc/subversion/branches/py-tests-as-modules/subversion/libsvn_ra_serf/options.c?rev=997472&r1=997471&r2=997472&view=diff
==============================================================================
--- subversion/branches/py-tests-as-modules/subversion/libsvn_ra_serf/options.c (original)
+++ subversion/branches/py-tests-as-modules/subversion/libsvn_ra_serf/options.c Wed Sep 15 19:32:26 2010
@@ -210,8 +210,9 @@ cdata_options(svn_ra_serf__xml_parser_t 
   return SVN_NO_ERROR;
 }
 
-static serf_bucket_t*
-create_options_body(void *baton,
+static svn_error_t *
+create_options_body(serf_bucket_t **body_bkt,
+                    void *baton,
                     serf_bucket_alloc_t *alloc,
                     apr_pool_t *pool)
 {
@@ -224,7 +225,8 @@ create_options_body(void *baton,
   svn_ra_serf__add_tag_buckets(body, "D:activity-collection-set", NULL, alloc);
   svn_ra_serf__add_close_tag_buckets(body, alloc, "D:options");
 
-  return body;
+  *body_bkt = body;
+  return SVN_NO_ERROR;
 }
 
 svn_boolean_t*
@@ -394,6 +396,8 @@ options_response_handler(serf_request_t 
   serf_bucket_t *hdrs = serf_bucket_response_get_headers(response);
 
   /* Start out assuming all capabilities are unsupported. */
+  apr_hash_set(orc->session->capabilities, SVN_RA_CAPABILITY_PARTIAL_REPLAY,
+               APR_HASH_KEY_STRING, capability_no);
   apr_hash_set(orc->session->capabilities, SVN_RA_CAPABILITY_DEPTH,
                APR_HASH_KEY_STRING, capability_no);
   apr_hash_set(orc->session->capabilities, SVN_RA_CAPABILITY_MERGEINFO,
@@ -472,24 +476,37 @@ svn_ra_serf__create_options_req(svn_ra_s
 
 /** Capabilities exchange. */
 
-/* Exchange capabilities with the server, by sending an OPTIONS
-   request announcing the client's capabilities, and by filling
-   SERF_SESS->capabilities with the server's capabilities as read
-   from the response headers.  Use POOL only for temporary allocation. */
 svn_error_t *
 svn_ra_serf__exchange_capabilities(svn_ra_serf__session_t *serf_sess,
+                                   const char **corrected_url,
                                    apr_pool_t *pool)
 {
   svn_ra_serf__options_context_t *opt_ctx;
+  svn_error_t *err;
 
   /* This routine automatically fills in serf_sess->capabilities */
   svn_ra_serf__create_options_req(&opt_ctx, serf_sess, serf_sess->conns[0],
                                   serf_sess->repos_url.path, pool);
 
-  SVN_ERR(svn_ra_serf__context_run_wait(
-    svn_ra_serf__get_options_done_ptr(opt_ctx), serf_sess, pool));
+  err = svn_ra_serf__context_run_wait(
+            svn_ra_serf__get_options_done_ptr(opt_ctx), serf_sess, pool);
 
-  return SVN_NO_ERROR;
+  /* If our caller cares about server redirections, and our response
+     carries such a thing, report as much.  We'll disregard ERR --
+     it's most likely just a complaint about the response body not
+     successfully parsing as XML or somesuch. */
+  if (corrected_url && (opt_ctx->status_code == 301))
+    {
+      svn_error_clear(err);
+      *corrected_url = opt_ctx->parser_ctx->location;
+      return SVN_NO_ERROR;
+    }
+                        
+  return svn_error_compose_create(
+             svn_ra_serf__error_on_status(opt_ctx->status_code,
+                                          serf_sess->repos_url.path,
+                                          opt_ctx->parser_ctx->location),
+             err);
 }
 
 
@@ -515,7 +532,7 @@ svn_ra_serf__has_capability(svn_ra_sessi
 
   /* If any capability is unknown, they're all unknown, so ask. */
   if (cap_result == NULL)
-    SVN_ERR(svn_ra_serf__exchange_capabilities(serf_sess, pool));
+    SVN_ERR(svn_ra_serf__exchange_capabilities(serf_sess, NULL, pool));
 
   /* Try again, now that we've fetched the capabilities. */
   cap_result = apr_hash_get(serf_sess->capabilities,

Modified: subversion/branches/py-tests-as-modules/subversion/libsvn_ra_serf/property.c
URL: http://svn.apache.org/viewvc/subversion/branches/py-tests-as-modules/subversion/libsvn_ra_serf/property.c?rev=997472&r1=997471&r2=997472&view=diff
==============================================================================
--- subversion/branches/py-tests-as-modules/subversion/libsvn_ra_serf/property.c (original)
+++ subversion/branches/py-tests-as-modules/subversion/libsvn_ra_serf/property.c Wed Sep 15 19:32:26 2010
@@ -162,6 +162,16 @@ svn_ra_serf__get_ver_prop(apr_hash_t *pr
   return NULL;
 }
 
+const svn_string_t *
+svn_ra_serf__get_prop_string(apr_hash_t *props,
+                             const char *path,
+                             const char *ns,
+                             const char *name)
+{
+  return svn_ra_serf__get_ver_prop_string(props, path, SVN_INVALID_REVNUM,
+                                          ns, name);
+}
+
 const char *
 svn_ra_serf__get_prop(apr_hash_t *props,
                       const char *path,
@@ -420,7 +430,7 @@ cdata_propfind(svn_ra_serf__xml_parser_t
   return SVN_NO_ERROR;
 }
 
-static apr_status_t
+static svn_error_t *
 setup_propfind_headers(serf_bucket_t *headers,
                         void *setup_baton,
                         apr_pool_t *pool)
@@ -437,14 +447,15 @@ setup_propfind_headers(serf_bucket_t *he
       serf_bucket_headers_setn(headers, "Label", ctx->label);
     }
 
-  return APR_SUCCESS;
+  return SVN_NO_ERROR;
 }
 
 #define PROPFIND_HEADER "<?xml version=\"1.0\" encoding=\"utf-8\"?><propfind xmlns=\"DAV:\">"
 #define PROPFIND_TRAILER "</propfind>"
 
-static serf_bucket_t*
-create_propfind_body(void *setup_baton,
+static svn_error_t *
+create_propfind_body(serf_bucket_t **bkt,
+                     void *setup_baton,
                      serf_bucket_alloc_t *alloc,
                      apr_pool_t *pool)
 {
@@ -515,7 +526,8 @@ create_propfind_body(void *setup_baton,
                                       alloc);
   serf_bucket_aggregate_append(body_bkt, tmp);
 
-  return body_bkt;
+  *bkt = body_bkt;
+  return SVN_NO_ERROR;
 }
 
 static svn_boolean_t
@@ -700,7 +712,8 @@ svn_ra_serf__wait_for_props(svn_ra_serf_
 
   err = svn_ra_serf__context_run_wait(&prop_ctx->done, sess, pool);
 
-  err2 = svn_ra_serf__error_on_status(prop_ctx->status_code, prop_ctx->path);
+  err2 = svn_ra_serf__error_on_status(prop_ctx->status_code,
+                                      prop_ctx->path, NULL);
   if (err2)
     {
       svn_error_clear(err);
@@ -735,7 +748,7 @@ svn_ra_serf__retrieve_props(apr_hash_t *
   return SVN_NO_ERROR;
 }
 
-void
+svn_error_t *
 svn_ra_serf__walk_all_props(apr_hash_t *props,
                             const char *name,
                             svn_revnum_t rev,
@@ -750,14 +763,14 @@ svn_ra_serf__walk_all_props(apr_hash_t *
 
   if (!ver_props)
     {
-      return;
+      return SVN_NO_ERROR;
     }
 
   path_props = apr_hash_get(ver_props, name, strlen(name));
 
   if (!path_props)
     {
-      return;
+      return SVN_NO_ERROR;
     }
 
   for (ns_hi = apr_hash_first(pool, path_props); ns_hi;
@@ -777,12 +790,15 @@ svn_ra_serf__walk_all_props(apr_hash_t *
 
           apr_hash_this(name_hi, &prop_name, &prop_len, &prop_val);
           /* use a subpool? */
-          walker(baton, ns_name, ns_len, prop_name, prop_len, prop_val, pool);
+          SVN_ERR(walker(baton, ns_name, ns_len, prop_name, prop_len,
+                         prop_val, pool));
         }
     }
+
+  return SVN_NO_ERROR;
 }
 
-void
+svn_error_t *
 svn_ra_serf__walk_all_paths(apr_hash_t *props,
                             svn_revnum_t rev,
                             svn_ra_serf__path_rev_walker_t walker,
@@ -796,7 +812,7 @@ svn_ra_serf__walk_all_paths(apr_hash_t *
 
   if (!ver_props)
     {
-      return;
+      return SVN_NO_ERROR;
     }
 
   for (path_hi = apr_hash_first(pool, ver_props); path_hi;
@@ -825,11 +841,13 @@ svn_ra_serf__walk_all_paths(apr_hash_t *
 
               apr_hash_this(name_hi, &prop_name, &prop_len, &prop_val);
               /* use a subpool? */
-              walker(baton, path_name, path_len, ns_name, ns_len,
-                     prop_name, prop_len, prop_val, pool);
+              SVN_ERR(walker(baton, path_name, path_len, ns_name, ns_len,
+                             prop_name, prop_len, prop_val, pool));
             }
         }
     }
+
+  return SVN_NO_ERROR;
 }
 
 static svn_error_t *

Modified: subversion/branches/py-tests-as-modules/subversion/libsvn_ra_serf/ra_serf.h
URL: http://svn.apache.org/viewvc/subversion/branches/py-tests-as-modules/subversion/libsvn_ra_serf/ra_serf.h?rev=997472&r1=997471&r2=997472&view=diff
==============================================================================
--- subversion/branches/py-tests-as-modules/subversion/libsvn_ra_serf/ra_serf.h (original)
+++ subversion/branches/py-tests-as-modules/subversion/libsvn_ra_serf/ra_serf.h Wed Sep 15 19:32:26 2010
@@ -78,7 +78,7 @@ typedef enum
 } svn_ra_serf__authn_types;
 
 /* A serf connection and optionally associated SSL context.  */
-typedef struct {
+typedef struct svn_ra_serf__connection_t {
   /* Our connection to a server. */
   serf_connection_t *conn;
 
@@ -254,7 +254,7 @@ struct svn_ra_serf__session_t {
 /*
  * Structure which represents a DAV element with a NAMESPACE and NAME.
  */
-typedef struct {
+typedef struct svn_ra_serf__dav_props_t {
   /* Element namespace */
   const char *namespace;
   /* Element name */
@@ -408,7 +408,7 @@ svn_ra_serf__handle_client_cert_pw(void 
  *
  * If CONTENT_TYPE is not-NULL, it will be sent as the Content-Type header.
  */
-void
+svn_error_t *
 svn_ra_serf__setup_serf_req(serf_request_t *request,
                             serf_bucket_t **req_bkt, serf_bucket_t **hdrs_bkt,
                             svn_ra_serf__connection_t *conn,
@@ -444,19 +444,20 @@ typedef svn_error_t *
                                 apr_pool_t *pool);
 
 /* Callback for when a request body is needed. */
-typedef serf_bucket_t*
-(*svn_ra_serf__request_body_delegate_t)(void *baton,
+typedef svn_error_t *
+(*svn_ra_serf__request_body_delegate_t)(serf_bucket_t **body_bkt,
+                                        void *baton,
                                         serf_bucket_alloc_t *alloc,
                                         apr_pool_t *pool);
 
 /* Callback for when request headers are needed. */
-typedef apr_status_t
+typedef svn_error_t *
 (*svn_ra_serf__request_header_delegate_t)(serf_bucket_t *headers,
                                           void *baton,
                                           apr_pool_t *pool);
 
 /* Callback for when a response has an error. */
-typedef apr_status_t
+typedef svn_error_t *
 (*svn_ra_serf__response_error_t)(serf_request_t *request,
                                  serf_bucket_t *response,
                                  int status_code,
@@ -466,7 +467,7 @@ typedef apr_status_t
  * Structure that can be passed to our default handler to guide the
  * execution of the request through its lifecycle.
  */
-typedef struct {
+typedef struct svn_ra_serf__handler_t {
   /* The HTTP method string of the request */
   const char *method;
 
@@ -623,6 +624,10 @@ struct svn_ra_serf__xml_parser_t {
    */
   int *status_code;
 
+  /* If non-NULL, this is the value of the response's Location header.
+   */
+  const char *location;
+
   /* If non-NULL, this value will be set to TRUE when the response is
    * completed.
    */
@@ -652,7 +657,7 @@ struct svn_ra_serf__xml_parser_t {
 /*
  * Parses a server-side error message into a local Subversion error.
  */
-typedef struct {
+typedef struct svn_ra_serf__server_error_t {
   /* Our local representation of the error. */
   svn_error_t *error;
 
@@ -679,13 +684,17 @@ typedef struct {
 } svn_ra_serf__server_error_t;
 
 /* A simple request context that can be passed to handle_status_only. */
-typedef struct {
+typedef struct svn_ra_serf__simple_request_context_t {
   /* The HTTP status code of the response */
   int status;
 
   /* The HTTP status line of the response */
   const char *reason;
 
+  /* The Location header value of the response, or NULL if there
+     wasn't one. */
+  const char *location;
+
   /* This value is set to TRUE when the response is completed. */
   svn_boolean_t done;
 
@@ -775,6 +784,13 @@ svn_ra_serf__response_discard_handler(se
                                       void *baton,
                                       apr_pool_t *pool);
 
+/* Return the value of the RESPONSE's Location header if any, or NULL
+ * otherwise.  All allocations will be made in POOL.
+ */
+const char *
+svn_ra_serf__response_get_location(serf_bucket_t *response,
+                                   apr_pool_t *pool);
+
 /** XML helper functions. **/
 
 /*
@@ -963,7 +979,7 @@ typedef svn_error_t *
                                  const svn_string_t *val,
                                  apr_pool_t *pool);
 
-void
+svn_error_t *
 svn_ra_serf__walk_all_props(apr_hash_t *props,
                             const char *name,
                             svn_revnum_t rev,
@@ -978,7 +994,7 @@ typedef svn_error_t *
                                   const char *name, apr_ssize_t name_len,
                                   const svn_string_t *val,
                                   apr_pool_t *pool);
-void
+svn_error_t *
 svn_ra_serf__walk_all_paths(apr_hash_t *props,
                             svn_revnum_t rev,
                             svn_ra_serf__path_rev_walker_t walker,
@@ -1017,12 +1033,21 @@ const svn_string_t *
 svn_ra_serf__get_ver_prop_string(apr_hash_t *props,
                                  const char *path, svn_revnum_t rev,
                                  const char *ns, const char *name);
+
+/* Wraps svn_ra_serf__get_ver_prop_string(). */
 const char *
 svn_ra_serf__get_ver_prop(apr_hash_t *props,
                           const char *path, svn_revnum_t rev,
                           const char *ns, const char *name);
 
-/* Same as get_prop, but for the unknown revision */
+/* Same as get_ver_prop_string, but for the unknown revision */
+const svn_string_t *
+svn_ra_serf__get_prop_string(apr_hash_t *props,
+                             const char *path,
+                             const char *ns,
+                             const char *name);
+
+/* Same as get_ver_prop, but for the unknown revision */
 const char *
 svn_ra_serf__get_prop(apr_hash_t *props,
                       const char *path,
@@ -1347,6 +1372,7 @@ svn_error_t *
 svn_ra_serf__get_locks(svn_ra_session_t *ra_session,
                        apr_hash_t **locks,
                        const char *path,
+                       svn_depth_t depth,
                        apr_pool_t *pool);
 
 svn_error_t * svn_ra_serf__get_mergeinfo(svn_ra_session_t *ra_session,
@@ -1358,11 +1384,20 @@ svn_error_t * svn_ra_serf__get_mergeinfo
                                          apr_pool_t *pool);
 
 /* Exchange capabilities with the server, by sending an OPTIONS
-   request announcing the client's capabilities, and by filling
-   SERF_SESS->capabilities with the server's capabilities as read
-   from the response headers.  Use POOL only for temporary allocation. */
+ * request announcing the client's capabilities, and by filling
+ * SERF_SESS->capabilities with the server's capabilities as read from
+ * the response headers.  Use POOL only for temporary allocation.
+ *
+ * If the CORRECTED_URL is non-NULL, allow the OPTIONS response to
+ * report a server-dictated redirect or relocation (HTTP 301 or 302
+ * error codes), setting *CORRECTED_URL to the value of the corrected
+ * repository URL.  Otherwise, such responses from the server will
+ * generate an error.  (In either case, no capabilities are exchanged
+ * if there is, in fact, such a response from the server.)
+ */
 svn_error_t *
 svn_ra_serf__exchange_capabilities(svn_ra_serf__session_t *serf_sess,
+                                   const char **corrected_url,
                                    apr_pool_t *pool);
 
 /* Implements the has_capability RA layer function. */
@@ -1497,11 +1532,14 @@ svn_ra_serf__encode_auth_header(const ch
 /*** General utility functions ***/
 
 /**
- * Convert an HTTP status code resulting from a WebDAV request to the relevant
- * error code.
+ * Convert an HTTP STATUS_CODE resulting from a WebDAV request against
+ * PATH to the relevant error code.  Use the response-supplied LOCATION
+ * where it necessary.
  */
 svn_error_t *
-svn_ra_serf__error_on_status(int status_code, const char *path);
+svn_ra_serf__error_on_status(int status_code,
+                             const char *path,
+                             const char *location);
 
 #ifdef __cplusplus
 }

Modified: subversion/branches/py-tests-as-modules/subversion/libsvn_ra_serf/replay.c
URL: http://svn.apache.org/viewvc/subversion/branches/py-tests-as-modules/subversion/libsvn_ra_serf/replay.c?rev=997472&r1=997471&r2=997472&view=diff
==============================================================================
--- subversion/branches/py-tests-as-modules/subversion/libsvn_ra_serf/replay.c (original)
+++ subversion/branches/py-tests-as-modules/subversion/libsvn_ra_serf/replay.c Wed Sep 15 19:32:26 2010
@@ -183,9 +183,10 @@ start_replay(svn_ra_serf__xml_parser_t *
       /* Create a pool for the commit editor. */
       ctx->dst_rev_pool = svn_pool_create(ctx->src_rev_pool);
       ctx->props = apr_hash_make(ctx->dst_rev_pool);
-      svn_ra_serf__walk_all_props(ctx->revs_props, ctx->report_target,
-                                  ctx->revision, svn_ra_serf__set_bare_props,
-                                  ctx->props, ctx->dst_rev_pool);
+      SVN_ERR(svn_ra_serf__walk_all_props(ctx->revs_props, ctx->report_target,
+                                          ctx->revision,
+                                          svn_ra_serf__set_bare_props,
+                                          ctx->props, ctx->dst_rev_pool));
       if (ctx->revstart_func)
         {
           SVN_ERR(ctx->revstart_func(ctx->revision, ctx->replay_baton,
@@ -563,8 +564,9 @@ cdata_replay(svn_ra_serf__xml_parser_t *
   return SVN_NO_ERROR;
 }
 
-static serf_bucket_t *
-create_replay_body(void *baton,
+static svn_error_t *
+create_replay_body(serf_bucket_t **bkt,
+                   void *baton,
                    serf_bucket_alloc_t *alloc,
                    apr_pool_t *pool)
 {
@@ -594,7 +596,8 @@ create_replay_body(void *baton,
 
   svn_ra_serf__add_close_tag_buckets(body_bkt, alloc, "S:replay-report");
 
-  return body_bkt;
+  *bkt = body_bkt;
+  return SVN_NO_ERROR;
 }
 
 svn_error_t *
@@ -717,6 +720,7 @@ svn_ra_serf__replay_range(svn_ra_session
   while (active_reports || rev <= end_revision)
     {
       apr_status_t status;
+      svn_error_t *err;
       svn_ra_serf__list_t *done_list;
       svn_ra_serf__list_t *done_reports = NULL;
       replay_context_t *replay_ctx;
@@ -801,8 +805,12 @@ svn_ra_serf__replay_range(svn_ra_session
       status = serf_context_run(session->context, session->timeout,
                                 pool);
 
+      err = session->pending_error;
+      session->pending_error = NULL;
+
       if (APR_STATUS_IS_TIMEUP(status))
         {
+          svn_error_clear(err);
           return svn_error_create(SVN_ERR_RA_DAV_CONN_TIMEOUT,
                                   NULL,
                                   _("Connection timed out"));
@@ -821,10 +829,9 @@ svn_ra_serf__replay_range(svn_ra_session
           active_reports--;
         }
 
+      SVN_ERR(err);
       if (status)
         {
-          SVN_ERR(session->pending_error);
-
           return svn_error_wrap_apr(status,
                                     _("Error retrieving replay REPORT (%d)"),
                                     status);

Modified: subversion/branches/py-tests-as-modules/subversion/libsvn_ra_serf/serf.c
URL: http://svn.apache.org/viewvc/subversion/branches/py-tests-as-modules/subversion/libsvn_ra_serf/serf.c?rev=997472&r1=997471&r2=997472&view=diff
==============================================================================
--- subversion/branches/py-tests-as-modules/subversion/libsvn_ra_serf/serf.c (original)
+++ subversion/branches/py-tests-as-modules/subversion/libsvn_ra_serf/serf.c Wed Sep 15 19:32:26 2010
@@ -331,6 +331,7 @@ svn_ra_serf__progress(void *progress_bat
 
 static svn_error_t *
 svn_ra_serf__open(svn_ra_session_t *session,
+                  const char **corrected_url,
                   const char *repos_URL,
                   const svn_ra_callbacks2_t *callbacks,
                   void *callback_baton,
@@ -342,6 +343,9 @@ svn_ra_serf__open(svn_ra_session_t *sess
   apr_uri_t url;
   const char *client_string = NULL;
 
+  if (corrected_url)
+    *corrected_url = NULL;
+
   serf_sess = apr_pcalloc(pool, sizeof(*serf_sess));
   serf_sess->pool = svn_pool_create(pool);
   serf_sess->bkt_alloc = serf_bucket_allocator_create(serf_sess->pool, NULL,
@@ -452,7 +456,7 @@ svn_ra_serf__open(svn_ra_session_t *sess
 
   session->priv = serf_sess;
 
-  return svn_ra_serf__exchange_capabilities(serf_sess, pool);
+  return svn_ra_serf__exchange_capabilities(serf_sess, corrected_url, pool);
 }
 
 static svn_error_t *
@@ -541,8 +545,9 @@ svn_ra_serf__rev_proplist(svn_ra_session
                                       propfind_path, rev, "0", all_props,
                                       pool));
 
-  svn_ra_serf__walk_all_props(props, propfind_path, rev,
-                              svn_ra_serf__set_bare_props, *ret_props, pool);
+  SVN_ERR(svn_ra_serf__walk_all_props(props, propfind_path, rev,
+                                      svn_ra_serf__set_bare_props, *ret_props,
+                                      pool));
 
   return SVN_NO_ERROR;
 }
@@ -716,7 +721,7 @@ dirent_walker(void *baton,
         }
       else if (strcmp(name, "getcontentlength") == 0)
         {
-          entry->size = apr_atoi64(val->data);
+          SVN_ERR(svn_cstring_atoi64(&entry->size, val->data));
         }
       else if (strcmp(name, "resourcetype") == 0)
         {
@@ -801,13 +806,13 @@ svn_ra_serf__stat(svn_ra_session_t *ra_s
           return SVN_NO_ERROR;
         }
       else
-        return err;
+        return svn_error_return(err);
     }
 
   entry = apr_pcalloc(pool, sizeof(*entry));
 
-  svn_ra_serf__walk_all_props(props, path, fetched_rev, dirent_walker, entry,
-                              pool);
+  SVN_ERR(svn_ra_serf__walk_all_props(props, path, fetched_rev, dirent_walker,
+                                      entry, pool));
 
   *dirent = entry;
 
@@ -902,8 +907,8 @@ svn_ra_serf__get_dir(svn_ra_session_t *r
       dirent_walk.base_paths = apr_hash_make(pool);
       dirent_walk.orig_path = svn_uri_canonicalize(path, pool);
 
-      svn_ra_serf__walk_all_paths(props, revision, path_dirent_walker,
-                                  &dirent_walk, pool);
+      SVN_ERR(svn_ra_serf__walk_all_paths(props, revision, path_dirent_walker,
+                                          &dirent_walk, pool));
 
       *dirents = dirent_walk.base_paths;
     }
@@ -920,9 +925,9 @@ svn_ra_serf__get_dir(svn_ra_session_t *r
       /* Check if the path is really a directory. */
       SVN_ERR(resource_is_directory (props, path, revision));
 
-      svn_ra_serf__walk_all_props(props, path, revision,
-                                  svn_ra_serf__set_flat_props,
-                                  *ret_props, pool);
+      SVN_ERR(svn_ra_serf__walk_all_props(props, path, revision,
+                                          svn_ra_serf__set_flat_props,
+                                          *ret_props, pool));
     }
 
   return SVN_NO_ERROR;