Hello!

I've spent some time examining r1866425 [1] ('Last-Modified' header) and I
would like to suggest a patch with some rework related to this code.

I see two main problems in r1866425: usage of the pointer comparison (which is
hackish and relies on the implementation of parse_uri()) and using -1 for
'bad time' value.

APR_DATE_BAD is defined in APR headers by the way and it's value is 0 (zero),
not -1.  Anyway, it is better to avoid 'special values' for APR_TIME_T if
possible.

I've attached a patch that removes both problems and also reduces code
coupling (since get_last_modified() function cannot be actually reused anywhere
but in set_headers()).  Also I've removed RESOURCE_LACKS_ETAG_POTENTIAL() check
which is now redundant.

Log message:
[[[
Rework r1866425 ('Last-Modified' header).  Do not use pointer comparison
and 'special value' for APR_TIME_T.

* subversion/mod_dav_svn/dav_svn.h
  (dav_resource_private): Add new member IS_PUBLIC_URI.

* subversion/mod_dav_svn/repos.c
  (parse_uri,
   get_parentpath_resource): Set IS_PUBLIC_URI to TRUE for 'public' URIs (not
   under '/!svn/')
  (get_last_modified): Delete.
  (set_headers): Rework of 'Last-Modified' related code.

Patch by: sergey.raevskiy{_AT_}visualsvn.com
]]]

[1] https://svn.apache.org/r1866425
Index: subversion/mod_dav_svn/dav_svn.h
===================================================================
--- subversion/mod_dav_svn/dav_svn.h    (revision 1870923)
+++ subversion/mod_dav_svn/dav_svn.h    (working copy)
@@ -303,6 +303,9 @@ struct dav_resource_private {
   /* whether this resource parameters are fixed and won't change
      between requests. */
   svn_boolean_t idempotent;
+
+  /* resource is accessed by 'public' uri (not under "!svn") */
+  svn_boolean_t is_public_uri;
 };
 
 
Index: subversion/mod_dav_svn/repos.c
===================================================================
--- subversion/mod_dav_svn/repos.c      (revision 1870923)
+++ subversion/mod_dav_svn/repos.c      (working copy)
@@ -714,6 +714,8 @@ parse_uri(dav_resource_combined *comb,
       && ((ch = uri[len2]) == '/' || ch == '\0')
       && memcmp(uri, special_uri, len2) == 0)
     {
+      comb->priv.is_public_uri = FALSE;
+
       if (ch == '\0')
         {
           /* URI was "/root/!svn". It exists, but has restricted usage. */
@@ -789,6 +791,8 @@ parse_uri(dav_resource_combined *comb,
       /* The location of these resources corresponds directly to the URI,
          and we keep the leading "/". */
       comb->priv.repos_path = comb->priv.uri_path->data;
+
+      comb->priv.is_public_uri = TRUE;
     }
 
   return FALSE;
@@ -1596,6 +1600,7 @@ get_parentpath_resource(request_rec *r,
   comb->priv.r = r;
   comb->priv.repos_path = "Collection of Repositories";
   comb->priv.root = *droot;
+  comb->priv.is_public_uri = TRUE;
   droot->rev = SVN_INVALID_REVNUM;
 
   comb->priv.repos = repos;
@@ -3139,50 +3144,6 @@ seek_stream(dav_stream *stream, apr_off_t abs_posi
        && resource->baselined))
 
 
-/* Return the last modification time of RESOURCE, or -1 if the DAV
-   resource type is not handled, or if an error occurs.  Temporary
-   allocations are made from RESOURCE->POOL. */
-static apr_time_t
-get_last_modified(const dav_resource *resource)
-{
-  apr_time_t last_modified;
-  svn_error_t *serr;
-  svn_revnum_t created_rev;
-  svn_string_t *date_time;
-
-  if (RESOURCE_LACKS_ETAG_POTENTIAL(resource))
-    return -1;
-
-  if ((serr = svn_fs_node_created_rev(&created_rev, resource->info->root.root,
-                                      resource->info->repos_path,
-                                      resource->pool)))
-    {
-      svn_error_clear(serr);
-      return -1;
-    }
-
-  if ((serr = svn_fs_revision_prop2(&date_time, resource->info->repos->fs,
-                                    created_rev, SVN_PROP_REVISION_DATE,
-                                    TRUE, resource->pool, resource->pool)))
-    {
-      svn_error_clear(serr);
-      return -1;
-    }
-
-  if (date_time == NULL || date_time->data == NULL)
-    return -1;
-
-  if ((serr = svn_time_from_cstring(&last_modified, date_time->data,
-                                    resource->pool)))
-    {
-      svn_error_clear(serr);
-      return -1;
-    }
-
-  return last_modified;
-}
-
-
 const char *
 dav_svn__getetag(const dav_resource *resource, apr_pool_t *pool)
 {
@@ -3264,20 +3225,42 @@ set_headers(request_rec *r, const dav_resource *re
     return NULL;
 
   if ((resource->type == DAV_RESOURCE_TYPE_REGULAR) 
-      && (resource->info->repos_path == resource->info->uri_path->data))
+      && resource->info->is_public_uri)
     {
       /* Include Last-Modified header for 'external' GET or HEAD requests
          (i.e. requests to URI's not under /!svn), to support usage of an
          SVN server as a file server, where the client needs timestamps
          for instance to use as "last modification time" of files on disk. */
-      const apr_time_t last_modified = get_last_modified(resource);
-      if (last_modified != -1)
+
+      svn_revnum_t created_rev;
+      svn_string_t *date_str = NULL;
+
+      serr = svn_fs_node_created_rev(&created_rev, resource->info->root.root,
+                                     resource->info->repos_path,
+                                     resource->pool);
+
+      if (serr == NULL)
         {
-          /* Note the modification time for the requested resource, and
-             include the Last-Modified header in the response. */
-          ap_update_mtime(r, last_modified);
-          ap_set_last_modified(r);
-        }  
+          serr = svn_fs_revision_prop2(&date_str, resource->info->repos->fs,
+                                       created_rev, SVN_PROP_REVISION_DATE,
+                                       TRUE, resource->pool, resource->pool);
+        }
+
+      if ((serr == NULL) && date_str && date_str->data)
+        {
+          apr_time_t mtime;
+          serr = svn_time_from_cstring(&mtime, date_str->data, resource->pool);
+
+          if (serr == NULL)
+            {
+              /* Note the modification time for the requested resource, and
+                 include the Last-Modified header in the response. */
+              ap_update_mtime(r, mtime);
+              ap_set_last_modified(r);
+            }
+        }
+
+      svn_error_clear(serr);
     }
 
   /* generate our etag and place it into the output */

Reply via email to