~svn/ubuntu/raring/subversion/ppa

« back to all changes in this revision

Viewing changes to subversion/mod_dav_svn/log.c

  • Committer: Bazaar Package Importer
  • Author(s): Adam Conrad
  • Date: 2005-12-05 01:26:14 UTC
  • mfrom: (1.1.2 upstream)
  • Revision ID: james.westby@ubuntu.com-20051205012614-qom4xfypgtsqc2xq
Tags: 1.2.3dfsg1-3ubuntu1
Merge with the final Debian release of 1.2.3dfsg1-3, bringing in
fixes to the clean target, better documentation of the libdb4.3
upgrade and build fixes to work with swig1.3_1.3.27.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * log.c: handle the log-report request and response
 
3
 *
 
4
 * ====================================================================
 
5
 * Copyright (c) 2000-2004 CollabNet.  All rights reserved.
 
6
 *
 
7
 * This software is licensed as described in the file COPYING, which
 
8
 * you should have received as part of this distribution.  The terms
 
9
 * are also available at http://subversion.tigris.org/license-1.html.
 
10
 * If newer versions of this license are posted there, you may use a
 
11
 * newer version instead, at your option.
 
12
 *
 
13
 * This software consists of voluntary contributions made by many
 
14
 * individuals.  For exact contribution history, see the revision
 
15
 * history and logs, available at http://subversion.tigris.org/.
 
16
 * ====================================================================
 
17
 */
 
18
 
 
19
 
 
20
 
 
21
#include <apr_pools.h>
 
22
#include <apr_strings.h>
 
23
#include <apr_xml.h>
 
24
#include <mod_dav.h>
 
25
 
 
26
#include "svn_repos.h"
 
27
#include "svn_types.h"
 
28
#include "svn_xml.h"
 
29
#include "svn_path.h"
 
30
#include "svn_dav.h"
 
31
 
 
32
#include "dav_svn.h"
 
33
 
 
34
 
 
35
struct log_receiver_baton
 
36
{
 
37
  /* this buffers the output for a bit and is automatically flushed,
 
38
     at appropriate times, by the Apache filter system. */
 
39
  apr_bucket_brigade *bb;
 
40
 
 
41
  /* where to deliver the output */
 
42
  ap_filter_t *output;
 
43
 
 
44
  /* Whether we've written the <S:log-report> header.  Allows for lazy
 
45
     writes to support mod_dav-based error handling. */
 
46
  svn_boolean_t needs_header;
 
47
};
 
48
 
 
49
 
 
50
/* If LRB->needs_header is true, send the "<S:log-report>" start
 
51
   element and set LRB->needs_header to zero.  Else do nothing.
 
52
   This is basically duplicated in file_revs.c.  Consider factoring if
 
53
   duplicating again. */
 
54
static svn_error_t * maybe_send_header(struct log_receiver_baton *lrb)
 
55
{
 
56
  if (lrb->needs_header)
 
57
    {
 
58
      SVN_ERR( dav_svn__send_xml(lrb->bb, lrb->output,
 
59
                                 DAV_XML_HEADER DEBUG_CR
 
60
                                 "<S:log-report xmlns:S=\"" SVN_XML_NAMESPACE
 
61
                                 "\" " "xmlns:D=\"DAV:\">" DEBUG_CR) );
 
62
      lrb->needs_header = FALSE;
 
63
    }
 
64
  return SVN_NO_ERROR;
 
65
}
 
66
 
 
67
/* This implements `svn_log_message_receiver_t'.
 
68
   BATON is a `struct log_receiver_baton *'.  */
 
69
static svn_error_t * log_receiver(void *baton,
 
70
                                  apr_hash_t *changed_paths,
 
71
                                  svn_revnum_t rev,
 
72
                                  const char *author,
 
73
                                  const char *date,
 
74
                                  const char *msg,
 
75
                                  apr_pool_t *pool)
 
76
{
 
77
  struct log_receiver_baton *lrb = baton;
 
78
 
 
79
  SVN_ERR( maybe_send_header(lrb) );
 
80
 
 
81
  SVN_ERR( dav_svn__send_xml(lrb->bb, lrb->output,
 
82
                             "<S:log-item>" DEBUG_CR "<D:version-name>%ld"
 
83
                             "</D:version-name>" DEBUG_CR, rev) );
 
84
 
 
85
  if (author)
 
86
    SVN_ERR( dav_svn__send_xml(lrb->bb, lrb->output,
 
87
                               "<D:creator-displayname>%s"
 
88
                               "</D:creator-displayname>" DEBUG_CR,
 
89
                               apr_xml_quote_string(pool, author, 0)) );
 
90
 
 
91
  /* ### this should be DAV:creation-date, but we need to format
 
92
     ### that date a bit differently */
 
93
  if (date)
 
94
    SVN_ERR( dav_svn__send_xml(lrb->bb, lrb->output,
 
95
                               "<S:date>%s</S:date>" DEBUG_CR,
 
96
                               apr_xml_quote_string(pool, date, 0)) );
 
97
 
 
98
  if (msg)
 
99
    SVN_ERR( dav_svn__send_xml(lrb->bb, lrb->output,
 
100
                               "<D:comment>%s</D:comment>" DEBUG_CR,
 
101
                               apr_xml_quote_string
 
102
                               (pool, svn_xml_fuzzy_escape (msg, pool), 0)) );
 
103
 
 
104
 
 
105
  if (changed_paths)
 
106
    {
 
107
      apr_hash_index_t *hi;
 
108
      char *path;
 
109
 
 
110
      for (hi = apr_hash_first(pool, changed_paths);
 
111
           hi != NULL;
 
112
           hi = apr_hash_next(hi))
 
113
        {
 
114
          void *val;
 
115
          svn_log_changed_path_t *log_item;
 
116
          
 
117
          apr_hash_this(hi, (void *) &path, NULL, &val);
 
118
          log_item = val;
 
119
 
 
120
          /* ### todo: is there a D: namespace equivalent for
 
121
             `changed-path'?  Should use it if so. */
 
122
          switch (log_item->action)
 
123
            {
 
124
            case 'A':
 
125
              if (log_item->copyfrom_path 
 
126
                  && SVN_IS_VALID_REVNUM(log_item->copyfrom_rev))
 
127
                SVN_ERR( dav_svn__send_xml(lrb->bb, lrb->output, 
 
128
                                           "<S:added-path"
 
129
                                           " copyfrom-path=\"%s\"" 
 
130
                                           " copyfrom-rev=\"%ld\">"
 
131
                                           "%s</S:added-path>" DEBUG_CR,
 
132
                                           apr_xml_quote_string
 
133
                                           (pool, 
 
134
                                            log_item->copyfrom_path,
 
135
                                            1), /* escape quotes */
 
136
                                           log_item->copyfrom_rev,
 
137
                                           apr_xml_quote_string(pool,
 
138
                                                                path, 0)) );
 
139
              else
 
140
                SVN_ERR( dav_svn__send_xml(lrb->bb, lrb->output,
 
141
                                           "<S:added-path>%s</S:added-path>" 
 
142
                                           DEBUG_CR, 
 
143
                                           apr_xml_quote_string(pool, path,
 
144
                                                                0)) );
 
145
              break;
 
146
 
 
147
            case 'R':
 
148
              if (log_item->copyfrom_path 
 
149
                  && SVN_IS_VALID_REVNUM(log_item->copyfrom_rev))
 
150
                SVN_ERR( dav_svn__send_xml(lrb->bb, lrb->output,
 
151
                                           "<S:replaced-path"
 
152
                                           " copyfrom-path=\"%s\"" 
 
153
                                           " copyfrom-rev=\"%ld\">"
 
154
                                           "%s</S:replaced-path>" DEBUG_CR,
 
155
                                           apr_xml_quote_string
 
156
                                           (pool, 
 
157
                                            log_item->copyfrom_path,
 
158
                                            1), /* escape quotes */
 
159
                                           log_item->copyfrom_rev,
 
160
                                           apr_xml_quote_string(pool,
 
161
                                                                path, 0)) );
 
162
              else
 
163
                SVN_ERR( dav_svn__send_xml(lrb->bb, lrb->output,
 
164
                                           "<S:replaced-path>%s"
 
165
                                           "</S:replaced-path>" DEBUG_CR,
 
166
                                           apr_xml_quote_string(pool, path,
 
167
                                                                0)) );
 
168
              break;
 
169
 
 
170
            case 'D':
 
171
              SVN_ERR( dav_svn__send_xml(lrb->bb, lrb->output,
 
172
                                         "<S:deleted-path>%s</S:deleted-path>" 
 
173
                                         DEBUG_CR,
 
174
                                         apr_xml_quote_string(pool, path,
 
175
                                                              0)) );
 
176
              break;
 
177
 
 
178
            case 'M':
 
179
              SVN_ERR( dav_svn__send_xml(lrb->bb, lrb->output,
 
180
                                         "<S:modified-path>%s"
 
181
                                         "</S:modified-path>" DEBUG_CR,
 
182
                                         apr_xml_quote_string(pool, path, 0)) );
 
183
              break;
 
184
              
 
185
            default:
 
186
              break;
 
187
            }
 
188
        }
 
189
    }
 
190
 
 
191
  SVN_ERR( dav_svn__send_xml(lrb->bb, lrb->output, "</S:log-item>" DEBUG_CR) );
 
192
 
 
193
  return SVN_NO_ERROR;
 
194
}
 
195
 
 
196
 
 
197
 
 
198
 
 
199
dav_error * dav_svn__log_report(const dav_resource *resource,
 
200
                                const apr_xml_doc *doc,
 
201
                                ap_filter_t *output)
 
202
{
 
203
  svn_error_t *serr;
 
204
  apr_status_t apr_err;
 
205
  dav_error *derr = NULL;
 
206
  apr_xml_elem *child;
 
207
  struct log_receiver_baton lrb;
 
208
  dav_svn_authz_read_baton arb;
 
209
  const dav_svn_repos *repos = resource->info->repos;
 
210
  const char *target = NULL;
 
211
  int limit = 0;
 
212
  int ns;
 
213
 
 
214
  /* These get determined from the request document. */
 
215
  svn_revnum_t start = SVN_INVALID_REVNUM;   /* defaults to HEAD */
 
216
  svn_revnum_t end = SVN_INVALID_REVNUM;     /* defaults to HEAD */
 
217
  svn_boolean_t discover_changed_paths = 0;  /* off by default */
 
218
  svn_boolean_t strict_node_history = 0;     /* off by default */
 
219
  apr_array_header_t *paths
 
220
    = apr_array_make(resource->pool, 0, sizeof(const char *));
 
221
 
 
222
  /* Sanity check. */
 
223
  ns = dav_svn_find_ns(doc->namespaces, SVN_XML_NAMESPACE);
 
224
  if (ns == -1)
 
225
    {
 
226
      return dav_new_error_tag(resource->pool, HTTP_BAD_REQUEST, 0,
 
227
                               "The request does not contain the 'svn:' "
 
228
                               "namespace, so it is not going to have certain "
 
229
                               "required elements.",
 
230
                               SVN_DAV_ERROR_NAMESPACE,
 
231
                               SVN_DAV_ERROR_TAG);
 
232
    }
 
233
  
 
234
  /* ### todo: okay, now go fill in svn_ra_dav__get_log() based on the
 
235
     syntax implied below... */
 
236
  for (child = doc->root->first_child; child != NULL; child = child->next)
 
237
    {
 
238
      /* if this element isn't one of ours, then skip it */
 
239
      if (child->ns != ns)
 
240
        continue;
 
241
 
 
242
      if (strcmp(child->name, "start-revision") == 0)
 
243
        start = SVN_STR_TO_REV(dav_xml_get_cdata(child, resource->pool, 1));
 
244
      else if (strcmp(child->name, "end-revision") == 0)
 
245
        end = SVN_STR_TO_REV(dav_xml_get_cdata(child, resource->pool, 1));
 
246
      else if (strcmp(child->name, "limit") == 0)
 
247
        limit = atoi(child->first_cdata.first->text);
 
248
      else if (strcmp(child->name, "discover-changed-paths") == 0)
 
249
        discover_changed_paths = 1; /* presence indicates positivity */
 
250
      else if (strcmp(child->name, "strict-node-history") == 0)
 
251
        strict_node_history = 1; /* presence indicates positivity */
 
252
      else if (strcmp(child->name, "path") == 0)
 
253
        {
 
254
          const char *rel_path = dav_xml_get_cdata(child, resource->pool, 0);
 
255
          if ((derr = dav_svn__test_canonical (rel_path, resource->pool)))
 
256
            return derr;
 
257
          target = svn_path_join(resource->info->repos_path, rel_path, 
 
258
                                 resource->pool);
 
259
          (*((const char **)(apr_array_push (paths)))) = target;
 
260
        }
 
261
      /* else unknown element; skip it */
 
262
    }
 
263
 
 
264
  /* Build authz read baton */
 
265
  arb.r = resource->info->r;
 
266
  arb.repos = resource->info->repos;
 
267
 
 
268
  /* Build log receiver baton */
 
269
  lrb.bb = apr_brigade_create(resource->pool,  /* not the subpool! */
 
270
                              output->c->bucket_alloc);
 
271
  lrb.output = output;
 
272
  lrb.needs_header = TRUE;
 
273
 
 
274
  /* Our svn_log_message_receiver_t sends the <S:log-report> header in
 
275
     a lazy fashion.  Before writing the first log message, it assures
 
276
     that the header has already been sent (checking the needs_header
 
277
     flag in our log_receiver_baton structure). */
 
278
 
 
279
  /* Send zero or more log items. */
 
280
  serr = svn_repos_get_logs3(repos->repos,
 
281
                             paths,
 
282
                             start,
 
283
                             end,
 
284
                             limit,
 
285
                             discover_changed_paths,
 
286
                             strict_node_history,
 
287
                             dav_svn_authz_read,
 
288
                             &arb,
 
289
                             log_receiver,
 
290
                             &lrb,
 
291
                             resource->pool);
 
292
  if (serr)
 
293
    {
 
294
      derr = dav_svn_convert_err(serr, HTTP_BAD_REQUEST, serr->message,
 
295
                                 resource->pool);
 
296
      goto cleanup;
 
297
    }
 
298
  
 
299
  if ((serr = maybe_send_header(&lrb)))
 
300
    {
 
301
      derr = dav_svn_convert_err(serr, HTTP_INTERNAL_SERVER_ERROR,
 
302
                                 "Error beginning REPORT response.",
 
303
                                 resource->pool);
 
304
      goto cleanup;
 
305
    }
 
306
    
 
307
  if ((serr = dav_svn__send_xml(lrb.bb, lrb.output, "</S:log-report>"
 
308
                                DEBUG_CR)))
 
309
    {
 
310
      derr = dav_svn_convert_err(serr, HTTP_INTERNAL_SERVER_ERROR,
 
311
                                 "Error ending REPORT response.",
 
312
                                 resource->pool);
 
313
      goto cleanup;
 
314
    }
 
315
 
 
316
 cleanup:
 
317
 
 
318
  /* Flush the contents of the brigade (returning an error only if we
 
319
     don't already have one). */
 
320
  if (((apr_err = ap_fflush(output, lrb.bb))) && (! derr))
 
321
    derr = dav_svn_convert_err(svn_error_create(apr_err, 0, NULL),
 
322
                               HTTP_INTERNAL_SERVER_ERROR,
 
323
                               "Error flushing brigade.",
 
324
                               resource->pool);
 
325
  return derr;
 
326
}