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 2013/04/09 16:27:47 UTC

svn commit: r1466055 - in /subversion/trunk/subversion/mod_dav_svn: dav_svn.h repos.c

Author: cmpilato
Date: Tue Apr  9 14:27:47 2013
New Revision: 1466055

URL: http://svn.apache.org/r1466055
Log:
Accept "kw=1" parameter in mod_dav_svn GET query string as a flag
which means "perform keyword substitution on the returned file content
stream".

* subversion/mod_dav_svn/dav_svn.h
  (struct dav_resource_private): add keyword_subst flag.

* subversion/mod_dav_svn/repos.c
  (svn_subst.h): Add #include.
  (parse_querystring): Set keyword_subst flag if query string contains
    "kw" parameter with value "1", and preserve that flag's state when
    redirecting.
  (set_headers): Don't send "Content-length" header when doing keyword
    substitution as we can't know the size of the resulting stream.
  (deliver): Perform keyword substitution on the returned stream if
    requested.

Patch by: jinfroster <jinfroster{_AT_}mail.ru>
          (Tweaked by me.)

Modified:
    subversion/trunk/subversion/mod_dav_svn/dav_svn.h
    subversion/trunk/subversion/mod_dav_svn/repos.c

Modified: subversion/trunk/subversion/mod_dav_svn/dav_svn.h
URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/mod_dav_svn/dav_svn.h?rev=1466055&r1=1466054&r2=1466055&view=diff
==============================================================================
--- subversion/trunk/subversion/mod_dav_svn/dav_svn.h (original)
+++ subversion/trunk/subversion/mod_dav_svn/dav_svn.h Tue Apr  9 14:27:47 2013
@@ -284,11 +284,15 @@ struct dav_resource_private {
   svn_boolean_t auto_checked_out;
 
   /* was this resource fetched using our public peg-/working-rev CGI
-     interface (ie: /path/to/item?p=PEGREV]? */
+     interface (ie: /path/to/item?p=PEGREV)? */
   svn_boolean_t pegged;
 
   /* Cache any revprop change error */
   svn_error_t *revprop_error;
+
+  /* was keyword substitution requested using our public CGI interface
+     (ie: /path/to/item?kw=1)? */
+  svn_boolean_t keyword_subst;
 };
 
 

Modified: subversion/trunk/subversion/mod_dav_svn/repos.c
URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/mod_dav_svn/repos.c?rev=1466055&r1=1466054&r2=1466055&view=diff
==============================================================================
--- subversion/trunk/subversion/mod_dav_svn/repos.c (original)
+++ subversion/trunk/subversion/mod_dav_svn/repos.c Tue Apr  9 14:27:47 2013
@@ -49,6 +49,7 @@
 #include "svn_version.h"
 #include "svn_props.h"
 #include "svn_ctype.h"
+#include "svn_subst.h"
 #include "mod_dav_svn.h"
 #include "svn_ra.h"  /* for SVN_RA_CAPABILITY_* */
 #include "svn_dirent_uri.h"
@@ -1821,6 +1822,12 @@ parse_querystring(request_rec *r, const 
   apr_table_t *pairs = querystring_to_table(query, pool);
   const char *prevstr = apr_table_get(pairs, "p");
   const char *wrevstr;
+  const char *keyword_subst;
+
+  /* Will we be doing keyword substitution? */
+  keyword_subst = apr_table_get(pairs, "kw");
+  if (keyword_subst && (strcmp(keyword_subst, "1") == 0))
+    comb->priv.keyword_subst = TRUE;
 
   if (prevstr)
     {
@@ -1880,7 +1887,7 @@ parse_querystring(request_rec *r, const 
     }
   else
     {
-      const char *newpath;
+      const char *newpath, *location;
       apr_hash_t *locations;
       apr_array_header_t *loc_revs = apr_array_make(pool, 1,
                                                     sizeof(svn_revnum_t));
@@ -1909,15 +1916,17 @@ parse_querystring(request_rec *r, const 
       /* Redirect folks to a canonical, peg-revision-only location.
          If they used a peg revision in this request, we can use a
          permanent redirect.  If they didn't (peg-rev is HEAD), we can
-         only use a temporary redirect. */
-      apr_table_setn(r->headers_out, "Location",
-                     ap_construct_url(r->pool,
-                                  apr_psprintf(r->pool, "%s%s?p=%ld",
+         only use a temporary redirect.  In either case, preserve the
+         "keyword_subst" state in the redirected location, too.  */
+      location = ap_construct_url(r->pool,
+                                  apr_psprintf(r->pool, "%s%s?p=%ld%s",
                                                (comb->priv.repos->root_path[1]
                                                 ? comb->priv.repos->root_path
                                                 : ""),
-                                               newpath, working_rev),
-                                      r));
+                                               newpath, working_rev,
+                                               keyword_subst ? "&kw=1" : ""),
+                                  r);
+      apr_table_setn(r->headers_out, "Location", location);
       return dav_svn__new_error(r->pool,
                                 prevstr ? HTTP_MOVED_PERMANENTLY
                                         : HTTP_MOVED_TEMPORARILY,
@@ -3025,19 +3034,23 @@ set_headers(request_rec *r, const dav_re
         mimetype = "text/plain";
 
 
-      /* if we aren't sending a diff, then we know the length of the file,
-         so set up the Content-Length header */
-      serr = svn_fs_file_length(&length,
-                                resource->info->root.root,
-                                resource->info->repos_path,
-                                resource->pool);
-      if (serr != NULL)
-        {
-          return dav_svn__convert_err(serr, HTTP_INTERNAL_SERVER_ERROR,
-                                      "could not fetch the resource length",
-                                      resource->pool);
+      /* if we aren't sending a diff and aren't expanding keywords,
+         then we know the exact length of the file, so set up the
+         Content-Length header. */
+      if (! resource->info->keyword_subst)
+        {
+          serr = svn_fs_file_length(&length,
+                                    resource->info->root.root,
+                                    resource->info->repos_path,
+                                    resource->pool);
+          if (serr != NULL)
+            {
+              return dav_svn__convert_err(serr, HTTP_INTERNAL_SERVER_ERROR,
+                                          "could not fetch the resource length",
+                                          resource->pool);
+            }
+          ap_set_content_length(r, (apr_off_t) length);
         }
-      ap_set_content_length(r, (apr_off_t) length);
     }
 
   /* set the discovered MIME type */
@@ -3563,6 +3576,71 @@ deliver(const dav_resource *resource, ap
                                       resource->pool);
         }
 
+      /* Perform keywords substitution if requested by client */
+      if (resource->info->keyword_subst)
+        {
+          svn_string_t *keywords;
+
+          serr = svn_fs_node_prop(&keywords,
+                                  resource->info->root.root,
+                                  resource->info->repos_path,
+                                  SVN_PROP_KEYWORDS,
+                                  resource->pool);
+          if (serr != NULL)
+            return dav_svn__convert_err(serr, HTTP_INTERNAL_SERVER_ERROR,
+                                        "could not get fetch '"
+                                        SVN_PROP_KEYWORDS "' property for "
+                                        "for keywords substitution",
+                                        resource->pool);
+
+          if (keywords)
+            {
+              apr_hash_t *kw;
+              svn_revnum_t cmt_rev;
+              const char *str_cmt_rev, *str_uri;
+              const char *cmt_date, *cmt_author;
+              apr_time_t when = 0;
+
+              serr = svn_repos_get_committed_info(&cmt_rev,
+                                                  &cmt_date,
+                                                  &cmt_author,
+                                                  resource->info->root.root,
+                                                  resource->info->repos_path,
+                                                  resource->pool);
+              if (serr != NULL)
+                return dav_svn__convert_err(serr, HTTP_INTERNAL_SERVER_ERROR,
+                                            "could not fetch committed info "
+                                            "for keywords substitution",
+                                            resource->pool);
+
+              serr = svn_time_from_cstring(&when, cmt_date, resource->pool);
+              if (serr != NULL)
+                return dav_svn__convert_err(serr, HTTP_INTERNAL_SERVER_ERROR,
+                                            "could not parse committed date "
+                                            "for keywords substitution",
+                                            resource->pool);
+              str_cmt_rev = apr_psprintf(resource->pool, "%ld", cmt_rev);
+              str_uri = apr_pstrcat(resource->pool,
+                                    resource->info->repos->base_url,
+                                    ap_escape_uri(resource->pool,
+                                                  resource->info->r->uri),
+                                    NULL);
+              serr = svn_subst_build_keywords2(&kw, keywords->data,
+                                               str_cmt_rev, str_uri, when,
+                                               cmt_author, resource->pool);
+              if (serr != NULL)
+                return dav_svn__convert_err(serr, HTTP_INTERNAL_SERVER_ERROR,
+                                            "could not perform keywords "
+                                            "substitution", resource->pool);
+
+              /* Replace the raw file STREAM with a wrapper that
+                 handles keyword translation. */
+              stream = svn_subst_stream_translated(
+                           svn_stream_disown(stream, resource->pool),
+                           NULL, FALSE, kw, TRUE, resource->pool);
+            }
+        }
+
       /* ### one day in the future, we can create a custom bucket type
          ### which will read from the FS stream on demand */