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 2012/06/21 19:17:02 UTC

svn commit: r1352627 - in /subversion/trunk/subversion/libsvn_ra_serf: property.c update.c

Author: cmpilato
Date: Thu Jun 21 17:17:01 2012
New Revision: 1352627

URL: http://svn.apache.org/viewvc?rev=1352627&view=rev
Log:
Give ra_serf the power to properly recognize non-existent properties
explicitly requested.

* subversion/libsvn_ra_serf/property.c
  (prop_state_e): Add STATUS state.
  (parse_status_code): New helper function.
  (propfind_ttable): Add record for STATUS state, and flip the bit
    that lets us handle the "propstat" closure with our custom
    callback.
  (propfind_opened): Now store the 'ns' and 'name' values on the
    PROPSTAT state, not the PROPVAL.
  (propfind_closed): Handle the STATUS closure, parsing the status
    code and leaving a note if it indicates that the property value
    isn't worthy of remembrance.  Also handle the PROPSTAT closure,
    where we can finally consult that status note and remove the
    property value we just stored.

* subversion/libsvn_ra_serf/update.c
  (try_get_wc_contents): Let empty-string checksums return to raising
    red flags.

Modified:
    subversion/trunk/subversion/libsvn_ra_serf/property.c
    subversion/trunk/subversion/libsvn_ra_serf/update.c

Modified: subversion/trunk/subversion/libsvn_ra_serf/property.c
URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/libsvn_ra_serf/property.c?rev=1352627&r1=1352626&r2=1352627&view=diff
==============================================================================
--- subversion/trunk/subversion/libsvn_ra_serf/property.c (original)
+++ subversion/trunk/subversion/libsvn_ra_serf/property.c Thu Jun 21 17:17:01 2012
@@ -46,6 +46,7 @@ typedef enum prop_state_e {
   RESPONSE,
   HREF,
   PROPSTAT,
+  STATUS,
   PROP,
   PROPVAL,
   COLLECTION,
@@ -107,7 +108,10 @@ static const svn_ra_serf__xml_transition
     TRUE, { NULL }, TRUE },
 
   { RESPONSE, D_, "propstat", PROPSTAT,
-    FALSE, { NULL }, FALSE },
+    FALSE, { NULL }, TRUE },
+
+  { PROPSTAT, D_, "status", STATUS,
+    TRUE, { NULL }, TRUE },
 
   { PROPSTAT, D_, "prop", PROP,
     FALSE, { NULL }, FALSE },
@@ -125,6 +129,29 @@ static const svn_ra_serf__xml_transition
 };
 
 
+/* Return the HTTP status code contained in STATUS_LINE, or 0 if
+   there's a problem parsing it. */
+static int parse_status_code(const char *status_line)
+{
+  /* STATUS_LINE should be of form: "HTTP/1.1 200 OK" */
+  if (status_line[0] == 'H' &&
+      status_line[1] == 'T' &&
+      status_line[2] == 'T' &&
+      status_line[3] == 'P' &&
+      status_line[4] == '/' &&
+      (status_line[5] >= '0' && status_line[5] <= '9') &&
+      status_line[6] == '.' &&
+      (status_line[7] >= '0' && status_line[7] <= '9') &&
+      status_line[8] == ' ')
+    {
+      char *reason;
+
+      return apr_strtoi64(status_line + 8, &reason, 10);
+    }
+  return 0;
+}
+
+
 /* Conforms to svn_ra_serf__xml_opened_t  */
 static svn_error_t *
 propfind_opened(svn_ra_serf__xml_estate_t *xes,
@@ -135,8 +162,8 @@ propfind_opened(svn_ra_serf__xml_estate_
 {
   if (entered_state == PROPVAL)
     {
-      svn_ra_serf__xml_note(xes, PROPVAL, "ns", tag->namespace);
-      svn_ra_serf__xml_note(xes, PROPVAL, "name", tag->name);
+      svn_ra_serf__xml_note(xes, PROPSTAT, "ns", tag->namespace);
+      svn_ra_serf__xml_note(xes, PROPSTAT, "name", tag->name);
     }
 
   return SVN_NO_ERROR;
@@ -193,7 +220,17 @@ propfind_closed(svn_ra_serf__xml_estate_
     {
       svn_ra_serf__xml_note(xes, PROPVAL, "altvalue", cdata->data);
     }
-  else
+  else if (leaving_state == STATUS)
+    {
+      /* Parse the status field, and remember if this is a property
+         that we wish to ignore.  (Typically, if it's not a 200, the
+         status will be 404 to indicate that a property we
+         specifically requested from the server doesn't exist.)  */
+      int status = parse_status_code(cdata->data);
+      if (status != 200)
+        svn_ra_serf__xml_note(xes, PROPSTAT, "ignore-prop", "*");
+    }
+  else if (leaving_state == PROPVAL)
     {
       const char *encoding = apr_hash_get(attrs, "V:encoding",
                                           APR_HASH_KEY_STRING);
@@ -204,8 +241,6 @@ propfind_closed(svn_ra_serf__xml_estate_
       const char *name;
       const char *altvalue;
 
-      SVN_ERR_ASSERT(leaving_state == PROPVAL);
-
       if (encoding)
         {
           if (strcmp(encoding, "base64") != 0)
@@ -225,7 +260,16 @@ propfind_closed(svn_ra_serf__xml_estate_
 
       /* The current path sits on the RESPONSE state. Gather up all the
          state from this PROPVAL to the (grandparent) RESPONSE state,
-         and grab the path from there.  */
+         and grab the path from there.
+
+         Now, it would be nice if we could, at this point, know that
+         the status code for this property indicated a problem -- then
+         we could simply bail out here and ignore the property.
+         Sadly, though, we might get the status code *after* we get
+         the property value.  So we'll carry on with our processing
+         here, setting the property and value as expected.  But later,
+         we might turn around and delete this property upon learning
+         that its status code was not a 200.  */
       gathered = svn_ra_serf__xml_gather_since(xes, RESPONSE);
 
       /* These will be dup'd into CTX->POOL, as necessary.  */
@@ -233,9 +277,9 @@ propfind_closed(svn_ra_serf__xml_estate_
       if (path == NULL)
         path = ctx->path;
 
-      ns = apr_hash_get(attrs, "ns", APR_HASH_KEY_STRING);
+      ns = apr_hash_get(gathered, "ns", APR_HASH_KEY_STRING);
       name = apr_pstrdup(ctx->pool,
-                         apr_hash_get(attrs, "name", APR_HASH_KEY_STRING));
+                         apr_hash_get(gathered, "name", APR_HASH_KEY_STRING));
 
       altvalue = apr_hash_get(attrs, "altvalue", APR_HASH_KEY_STRING);
       if (altvalue != NULL)
@@ -245,6 +289,32 @@ propfind_closed(svn_ra_serf__xml_estate_
                                 path, ctx->rev, ns, name, val_str,
                                 ctx->pool);
     }
+  else
+    {
+      apr_hash_t *gathered;
+
+      SVN_ERR_ASSERT(leaving_state == PROPSTAT);
+
+      /* If we've squirreled away a note that says we want to ignore
+         this property, then we'll ignore this property.
+         Unfortunately, we might have gotten this note after we
+         already set the property, so we have to turn right around and
+         delete it.  */
+      gathered = svn_ra_serf__xml_gather_since(xes, RESPONSE);
+      if (apr_hash_get(gathered, "ignore-prop", APR_HASH_KEY_STRING))
+        {
+          const char *path = apr_hash_get(gathered, "path",
+                                          APR_HASH_KEY_STRING);
+          if (path == NULL)
+            path = ctx->path;
+          svn_ra_serf__set_ver_prop(ctx->ret_props, path, ctx->rev,
+                                    apr_hash_get(gathered, "ns",
+                                                 APR_HASH_KEY_STRING),
+                                    apr_hash_get(gathered, "name",
+                                                 APR_HASH_KEY_STRING),
+                                    NULL, ctx->pool);
+        }
+    }
 
   return SVN_NO_ERROR;
 }

Modified: subversion/trunk/subversion/libsvn_ra_serf/update.c
URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/libsvn_ra_serf/update.c?rev=1352627&r1=1352626&r2=1352627&view=diff
==============================================================================
--- subversion/trunk/subversion/libsvn_ra_serf/update.c (original)
+++ subversion/trunk/subversion/libsvn_ra_serf/update.c Thu Jun 21 17:17:01 2012
@@ -2858,34 +2858,17 @@ try_get_wc_contents(svn_boolean_t *found
       return SVN_NO_ERROR;
     }
 
-
   svn_props = apr_hash_get(props, SVN_DAV_PROP_NS_DAV, APR_HASH_KEY_STRING);
   if (!svn_props)
     {
-      /* No checksum property in response. */
+      /* No properties -- therefore no checksum property -- in response. */
       return SVN_NO_ERROR;
     }
 
-  /* If we are talking to an old server, then the sha1-checksum property
-     will not exist. In our property parsing code, we don't bother to
-     check the <status> element which would indicate a 404. That section
-     needs to name the 404'd property, so our parsing code only sees:
-
-       <g0:sha1-checksum/>
-
-     That is parsed as an empty string value for the property.
-
-     When checking the property, if it is missing (NULL), or the above
-     empty string, then we know the property doesn't exist.
-
-     Strictly speaking, we could start parsing <status> and omit any
-     properties that were 404'd. But the 404 only happens when we ask
-     for a specific property, and it is easier to just check for the
-     empty string. Since it isn't a legal value in this case, we won't
-     get confused with a truly existent property.  */
   sha1_checksum_prop = svn_prop_get_value(svn_props, "sha1-checksum");
-  if (sha1_checksum_prop == NULL || *sha1_checksum_prop == '\0')
+  if (sha1_checksum_prop == NULL)
     {
+      /* No checksum property in response. */
       return SVN_NO_ERROR;
     }