GCC Code Coverage Report
Directory: cvmfs/ Exec Total Coverage
File: cvmfs/object_fetcher.h Lines: 180 201 89.6 %
Date: 2019-02-03 02:48:13 Branches: 124 196 63.3 %

Line Branch Exec Source
1
/**
2
 * This file is part of the CernVM File System.
3
 */
4
5
#ifndef CVMFS_OBJECT_FETCHER_H_
6
#define CVMFS_OBJECT_FETCHER_H_
7
8
#include <unistd.h>
9
10
#include <string>
11
12
#include "catalog.h"
13
#include "download.h"
14
#include "history_sqlite.h"
15
#include "manifest.h"
16
#include "manifest_fetch.h"
17
#include "reflog.h"
18
#include "signature.h"
19
#include "util/posix.h"
20
21
/**
22
 * Trait class to define the concrete object types produced by the methods of
23
 * concrete instantiations of AbstractObjectFetcher<>. For each implementation
24
 * of AbstractObjectFetcher<> one needs to provide a specialisation of this
25
 * trait. Note that this specialisation can be templated with the actual para-
26
 * meters, hence the parameter space does not explode.
27
 *
28
 * See: http://stackoverflow.com/questions/6006614/
29
 *      c-static-polymorphism-crtp-and-using-typedefs-from-derived-classes
30
 */
31
template <class ConcreteObjectFetcherT>
32
struct object_fetcher_traits;
33
34
175
struct ObjectFetcherFailures {
35
  enum Failures {
36
    kFailOk,
37
    kFailNotFound,
38
    kFailLocalIO,
39
    kFailNetwork,
40
    kFailDecompression,
41
    kFailManifestNameMismatch,
42
    kFailManifestSignatureMismatch,
43
    kFailBadData,
44
    kFailUnknown,
45
46
    kFailNumEntries
47
  };
48
};
49
50
4
inline const char* Code2Ascii(const ObjectFetcherFailures::Failures error) {
51
  const char *texts[ObjectFetcherFailures::kFailNumEntries + 1];
52
4
  texts[0] = "OK";
53
4
  texts[1] = "object not found";
54
4
  texts[2] = "local I/O failure";
55
4
  texts[3] = "network failure";
56
4
  texts[4] = "decompression failed";
57
4
  texts[5] = "manifest name doesn't match";
58
4
  texts[6] = "manifest signature is invalid";
59
4
  texts[7] = "bad data received";
60
4
  texts[8] = "no text";
61
4
  return texts[error];
62
}
63
64
/**
65
 * This is the default class implementing the data object fetching strategy. It
66
 * is meant to be used when CVMFS specific data structures need to be downloaded
67
 * from a backend storage of a repository.
68
 *
69
 * ObjectFetchers are supposed to be configured for one specific repository. How
70
 * this is done depends on the concrete implementation of this base class. When
71
 * a concrete implementation of ObjectFetcher<> needs to deal with files on the
72
 * local file system it is obliged to take measures for proper cleanup of those
73
 * files after usage.
74
 *
75
 * It abstracts all accesses to external file or HTTP resources and gathers this
76
 * access logic in one central point. This also comes in handy when unit testing
77
 * components that depend on downloading CVMFS data structures from a repository
78
 * backend storage like CatalogTraversal<> or GarbageCollector<>.
79
 */
80
template <class DerivedT>
81
175
class AbstractObjectFetcher : public ObjectFetcherFailures {
82
 public:
83
  typedef typename object_fetcher_traits<DerivedT>::CatalogTN CatalogTN;
84
  typedef typename object_fetcher_traits<DerivedT>::HistoryTN HistoryTN;
85
  typedef typename object_fetcher_traits<DerivedT>::ReflogTN  ReflogTN;
86
87
  typedef ObjectFetcherFailures::Failures Failures;
88
89
  static const std::string kManifestFilename;
90
  static const std::string kReflogFilename;
91
92
 public:
93
  /**
94
   * Fetches and opens the manifest of the repository this object fetcher is
95
   * configured for. Note that the user is responsible to clean up this object.
96
   *
97
   * @param manifest  pointer to a manifest object pointer
98
   * @return          failure code, specifying the action's result
99
   */
100
166
  Failures FetchManifest(manifest::Manifest** manifest) {
101
166
    return static_cast<DerivedT*>(this)->FetchManifest(manifest);
102
  }
103
104
  /**
105
   * Downloads and opens (read-only) a history database. Note that the user is
106
   * responsible to remove the history object after usage. The fetched SQLite
107
   * database file will be unlinked automatically during the destruction of the
108
   * HistoryTN object.
109
   *
110
   * @param history       pointer to a history database object pointer
111
   * @param history_hash  (optional) the content hash of the history database
112
   *                                 if left blank, the latest one is downloaded
113
   * @return              failure code, specifying the action's result
114
   */
115
73
  Failures FetchHistory(HistoryTN        **history,
116
                        const shash::Any  &history_hash = shash::Any()) {
117
    // retrieve the current HEAD history hash (if nothing else given)
118
    shash::Any effective_history_hash = (!history_hash.IsNull())
119
            ? history_hash
120

73
            : GetHistoryHash();
121

73
    if (effective_history_hash.IsNull()) {
122
      return kFailNotFound;
123
    }
124



73
    assert(history_hash.suffix == shash::kSuffixHistory ||
125
           history_hash.IsNull());
126
127
    // download the history hash
128
73
    std::string path;
129
73
    const Failures retval = Fetch(effective_history_hash, &path);
130

73
    if (retval != kFailOk) {
131
9
      return retval;
132
    }
133
134
    // open the history file
135
64
    *history = HistoryTN::Open(path);
136

64
    if (NULL == *history) {
137
1
      return kFailLocalIO;
138
    }
139
140
63
    (*history)->TakeDatabaseFileOwnership();
141
63
    return kFailOk;
142
  }
143
144
  /**
145
   * Downloads and opens a catalog. Note that the user is responsible to remove
146
   * the catalog object after usage.
147
   *
148
   * @param catalog_hash   the content hash of the catalog object
149
   * @param catalog_path   the root_path the catalog is mounted on
150
   * @param catalog        pointer to the fetched catalog object pointer
151
   * @param is_nested      a hint if the catalog to be loaded is a nested one
152
   * @param parent         (optional) parent catalog of the requested catalog
153
   * @return               failure code, specifying the action's result
154
   */
155
6228
  Failures FetchCatalog(const shash::Any   &catalog_hash,
156
                        const std::string  &catalog_path,
157
                              CatalogTN   **catalog,
158
                        const bool          is_nested = false,
159
                              CatalogTN    *parent    = NULL) {
160

6228
    assert(!catalog_hash.IsNull());
161

6228
    assert(catalog_hash.suffix == shash::kSuffixCatalog);
162
163
6228
    std::string path;
164
6228
    const Failures retval = Fetch(catalog_hash, &path);
165

6228
    if (retval != kFailOk) {
166
28
      return retval;
167
    }
168
169
6200
    *catalog = CatalogTN::AttachFreely(catalog_path,
170
                                       path,
171
                                       catalog_hash,
172
                                       parent,
173
                                       is_nested);
174

6200
    if (NULL == *catalog) {
175
1
      return kFailLocalIO;
176
    }
177
178
6199
    (*catalog)->TakeDatabaseFileOwnership();
179
6199
    return kFailOk;
180
  }
181
182
9
  Failures FetchReflog(const shash::Any &reflog_hash, ReflogTN **reflog) {
183

9
    assert(!reflog_hash.IsNull());
184

9
    assert(reflog_hash.suffix == shash::kSuffixNone);
185
186
9
    std::string tmp_path;
187
9
    const bool decompress = false;
188
9
    const bool nocache = true;
189
9
    Failures failure = Fetch(kReflogFilename, decompress, nocache, &tmp_path);
190

9
    if (failure != kFailOk) {
191
      return failure;
192
    }
193
194
    // Ensure data integrity
195
9
    shash::Any computed_hash(reflog_hash.algorithm);
196
9
    ReflogTN::HashDatabase(tmp_path, &computed_hash);
197

9
    if (computed_hash != reflog_hash) {
198
3
      unlink(tmp_path.c_str());
199
3
      return kFailBadData;
200
    }
201
202
6
    *reflog = ReflogTN::Open(tmp_path);
203

6
    if (NULL == *reflog) {
204
      return kFailLocalIO;
205
    }
206
207
6
    (*reflog)->TakeDatabaseFileOwnership();
208
6
    return kFailOk;
209
  }
210
211
166
  Failures FetchManifest(UniquePtr<manifest::Manifest> *manifest) {
212
166
    manifest::Manifest *raw_manifest_ptr = NULL;
213
166
    Failures failure = FetchManifest(&raw_manifest_ptr);
214

166
    if (failure == kFailOk) *manifest = raw_manifest_ptr;
215
166
    return failure;
216
  }
217
218
67
  Failures FetchHistory(UniquePtr<HistoryTN>  *history,
219
                        const shash::Any      &history_hash = shash::Any()) {
220
67
    HistoryTN *raw_history_ptr = NULL;
221
67
    Failures failure = FetchHistory(&raw_history_ptr, history_hash);
222

67
    if (failure == kFailOk) *history = raw_history_ptr;
223
67
    return failure;
224
  }
225
226
11
  Failures FetchCatalog(const shash::Any            &catalog_hash,
227
                        const std::string           &catalog_path,
228
                              UniquePtr<CatalogTN>  *catalog,
229
                        const bool                   is_nested = false,
230
                              CatalogTN             *parent    = NULL) {
231
11
    CatalogTN *raw_catalog_ptr = NULL;
232
    Failures failure = FetchCatalog(catalog_hash,
233
                                    catalog_path,
234
                                    &raw_catalog_ptr,
235
                                    is_nested,
236
11
                                    parent);
237

11
    if (failure == kFailOk) *catalog = raw_catalog_ptr;
238
11
    return failure;
239
  }
240
241
3
  Failures FetchReflog(const shash::Any &reflog_hash,
242
                       UniquePtr<ReflogTN> *reflog)
243
  {
244
3
    ReflogTN *raw_reflog_ptr = NULL;
245
3
    Failures failure = FetchReflog(reflog_hash, &raw_reflog_ptr);
246

3
    if (failure == kFailOk) *reflog = raw_reflog_ptr;
247
3
    return failure;
248
  }
249
250
  std::string GetUrl(const shash::Any &hash) const {
251
    return static_cast<DerivedT*>(this)->GetUrl(hash);
252
  }
253
254
3
  bool HasHistory() {
255
3
    shash::Any history_hash = GetHistoryHash();
256
3
    return !history_hash.IsNull();
257
  }
258
259
29
  const std::string& temporary_directory() const {
260
29
    return temporary_directory_;
261
  }
262
263
 protected:
264
175
  explicit AbstractObjectFetcher(const std::string &temp_dir)
265
175
    : temporary_directory_(temp_dir) {}
266
267
  /**
268
   * Internal function used to download objects defined by the given content
269
   * hash. This needs to be implemented depending on the concrete implementation
270
   * of this base class.
271
   *
272
   * @param object_hash  the content hash of the object to be downloaded
273
   * @param file_path    temporary file path to store the download result
274
   * @return             failure code (if not kFailOk, file_path is invalid)
275
   */
276
6301
  Failures Fetch(const shash::Any &object_hash, std::string *file_path) {
277
6301
    return static_cast<DerivedT*>(this)->Fetch(object_hash, file_path);
278
  }
279
280
9
  Failures Fetch(const std::string &relative_path,
281
                 const bool         decompress,
282
                 const bool         nocache,
283
                       std::string *file_path) {
284
    return static_cast<DerivedT*>(this)->Fetch(relative_path,
285
                                               decompress,
286
                                               nocache,
287
9
                                               file_path);
288
  }
289
290
  /**
291
   * Retrieves the history content hash of the HEAD history database from the
292
   * repository's manifest
293
   *
294
   * @return  the content hash of the HEAD history db or a null-hash on error
295
   */
296
64
  shash::Any GetHistoryHash() {
297
64
    UniquePtr<manifest::Manifest> manifest;
298
64
    const Failures retval = FetchManifest(&manifest);
299
300






64
    if (retval != kFailOk   ||
301
        !manifest.IsValid() ||
302
        manifest->history().IsNull()) {
303
      return shash::Any();
304
    }
305
306
64
    return manifest->history();
307
  }
308
309
 private:
310
  const std::string temporary_directory_;
311
};
312
313
template <class DerivedT>
314

30
const std::string AbstractObjectFetcher<DerivedT>::kManifestFilename =
315
                                                              ".cvmfspublished";
316
template <class DerivedT>
317

60
const std::string AbstractObjectFetcher<DerivedT>::kReflogFilename =
318
                                                                 ".cvmfsreflog";
319
320
321
/**
322
 * This is an AbstractObjectFetcher<> accessing locally stored repository files.
323
 * Note that this implementation does not take care of any repository signature
324
 * verification.
325
 */
326
template <class CatalogT = catalog::Catalog,
327
          class HistoryT = history::SqliteHistory,
328
          class ReflogT  = manifest::Reflog>
329
class LocalObjectFetcher :
330
  public AbstractObjectFetcher<LocalObjectFetcher<CatalogT, HistoryT, ReflogT> >
331
10
{
332
 protected:
333
  typedef LocalObjectFetcher<CatalogT, HistoryT, ReflogT> ThisTN;
334
  typedef AbstractObjectFetcher<ThisTN>                   BaseTN;
335
336
 public:
337
  typedef typename BaseTN::Failures Failures;
338
339
 public:
340
  /**
341
   * LocalObjectFetcher can reside on the stack or the heap.
342
   *
343
   * @param base_path  the path to the repository's backend storage
344
   * @param temp_dir   location to store decompressed tmp data
345
   */
346
10
  LocalObjectFetcher(const std::string &base_path,
347
                     const std::string &temp_dir)
348
    : BaseTN(temp_dir)
349
10
    , base_path_(base_path) {}
350
351
  using BaseTN::FetchManifest;  // un-hiding convenience overload
352
7
  Failures FetchManifest(manifest::Manifest** manifest) {
353
7
    const std::string path = BuildPath(BaseTN::kManifestFilename);
354
7
    if (!FileExists(path)) {
355
      return BaseTN::kFailNotFound;
356
    }
357
358
7
    *manifest = manifest::Manifest::LoadFile(path);
359
    return (*manifest != NULL) ? BaseTN::kFailOk
360
7
                               : BaseTN::kFailUnknown;
361
  }
362
363
  std::string GetUrl(const shash::Any &hash) const {
364
    return "file://" + BuildPath(BuildRelativePath(hash));
365
  }
366
367
13
  Failures Fetch(const shash::Any &object_hash, std::string *file_path) {
368
13
    assert(file_path != NULL);
369
13
    file_path->clear();
370
371
13
    const std::string relative_path = BuildRelativePath(object_hash);
372
13
    const bool        decompress    = true;
373
13
    const bool        nocache       = false;
374
13
    return Fetch(relative_path, decompress, nocache, file_path);
375
  }
376
377
378
16
  Failures Fetch(const std::string &relative_path,
379
                 const bool         decompress,
380
                 const bool         nocache,
381
                       std::string *file_path) {
382
16
    assert(file_path != NULL);
383
16
    file_path->clear();
384
385
    // check if the requested file object is available locally
386
16
    const std::string source = BuildPath(relative_path);
387
16
    if (!FileExists(source)) {
388
3
      LogCvmfs(kLogDownload, kLogDebug, "failed to locate file '%s'",
389
               relative_path.c_str());
390
3
      return BaseTN::kFailNotFound;
391
    }
392
393
    // create a temporary file to store the (decompressed) object file
394
    const std::string tmp_path = BaseTN::temporary_directory() + "/" +
395
13
                                 GetFileName(relative_path);
396
13
    FILE *f = CreateTempFile(tmp_path, 0600, "w", file_path);
397
13
    if (NULL == f) {
398
      LogCvmfs(kLogDownload, kLogStderr,
399
               "failed to create temp file '%s' (errno: %d)",
400
               tmp_path.c_str(), errno);
401
      return BaseTN::kFailLocalIO;
402
    }
403
404
    // decompress or copy the requested object file
405
    const bool success = (decompress)
406
      ? zlib::DecompressPath2File(source, f)
407
13
      : CopyPath2File(source, f);
408
13
    fclose(f);
409
410
    // check the decompression success and remove the temporary file otherwise
411
13
    if (!success) {
412
2
      LogCvmfs(kLogDownload, kLogDebug, "failed to fetch file from '%s' "
413
                                        "to '%s' (errno: %d)",
414
               source.c_str(), file_path->c_str(), errno);
415
2
      unlink(file_path->c_str());
416
2
      file_path->clear();
417
2
      return BaseTN::kFailDecompression;
418
    }
419
420
11
    return BaseTN::kFailOk;
421
  }
422
423
 protected:
424
23
  std::string BuildPath(const std::string &relative_path) const {
425
23
    return base_path_ + "/" + relative_path;
426
  }
427
428
13
  std::string BuildRelativePath(const shash::Any &hash) const {
429
13
    return "data/" + hash.MakePath();
430
  }
431
432
 private:
433
  const std::string base_path_;
434
};
435
436
template <class CatalogT, class HistoryT, class ReflogT>
437
struct object_fetcher_traits<LocalObjectFetcher<CatalogT, HistoryT, ReflogT> > {
438
    typedef CatalogT CatalogTN;
439
    typedef HistoryT HistoryTN;
440
    typedef ReflogT  ReflogTN;
441
};
442
443
444
/**
445
 * This implements the AbstractObjectFetcher<> to retrieve repository objects
446
 * from a remote location through HTTP. It verifies the repository's signature
447
 * and the downloaded data integrity.
448
 */
449
template <class CatalogT = catalog::Catalog,
450
          class HistoryT = history::SqliteHistory,
451
          class ReflogT  = manifest::Reflog>
452
class HttpObjectFetcher :
453
  public AbstractObjectFetcher<HttpObjectFetcher<CatalogT, HistoryT, ReflogT> >
454
10
{
455
 protected:
456
  typedef HttpObjectFetcher<CatalogT, HistoryT, ReflogT>  ThisTN;
457
  typedef AbstractObjectFetcher<ThisTN>                   BaseTN;
458
459
 public:
460
  typedef typename BaseTN::Failures Failures;
461
462
 public:
463
  /**
464
   * HttpObjectFetcher<> contains external DownloadManager and SignatureManager
465
   * hence it essentially is a wrapper object and can be copied.
466
   *
467
   * @param repo_name      the name of the repository to download objects from
468
   * @param repo_url       the URL to the repository's backend storage
469
   * @param temp_dir       location to store decompressed tmp data
470
   * @param download_mgr   pointer to the download manager to be used
471
   * @param signature_mgr  pointer to the signature manager to be used
472
   *
473
   * @return               a HttpObjectFetcher<> object or NULL on error
474
   */
475
10
  HttpObjectFetcher(const std::string           &repo_name,
476
                    const std::string           &repo_url,
477
                    const std::string           &temp_dir,
478
                    download::DownloadManager   *download_mgr,
479
                    signature::SignatureManager *signature_mgr)
480
    : BaseTN(temp_dir)
481
    , repo_url_(repo_url)
482
    , repo_name_(repo_name)
483
    , download_manager_(download_mgr)
484
10
    , signature_manager_(signature_mgr) {}
485
486
 public:
487
  using BaseTN::FetchManifest;  // un-hiding convenience overload
488
7
  Failures FetchManifest(manifest::Manifest** manifest) {
489
7
    const std::string url = BuildUrl(BaseTN::kManifestFilename);
490
491
    // Download manifest file
492
7
    struct manifest::ManifestEnsemble manifest_ensemble;
493
    manifest::Failures retval = manifest::Fetch(
494
                                  repo_url_,
495
                                  repo_name_,
496
                                  0,
497
                                  NULL,
498
                                  signature_manager_,
499
                                  download_manager_,
500
7
                                  &manifest_ensemble);
501
502
    // Check if manifest was loaded correctly
503

7
    switch (retval) {
504
      case manifest::kFailOk:
505
7
        break;
506
507
      case manifest::kFailNameMismatch:
508
        LogCvmfs(kLogDownload, kLogDebug,
509
                 "repository name mismatch. No name provided?");
510
        return BaseTN::kFailManifestNameMismatch;
511
512
      case manifest::kFailBadSignature:
513
      case manifest::kFailBadCertificate:
514
      case manifest::kFailBadWhitelist:
515
        LogCvmfs(kLogDownload, kLogDebug,
516
                 "repository signature mismatch. No key(s) provided?");
517
        return BaseTN::kFailManifestSignatureMismatch;
518
519
      default:
520
        LogCvmfs(kLogDownload, kLogDebug,
521
                 "failed to load manifest (%d - %s)",
522
                 retval, Code2Ascii(retval));
523
        return BaseTN::kFailUnknown;
524
    }
525
526
7
    assert(retval == manifest::kFailOk);
527
7
    *manifest = new manifest::Manifest(*manifest_ensemble.manifest);
528
    return (*manifest != NULL) ? BaseTN::kFailOk
529
7
                               : BaseTN::kFailUnknown;
530
  }
531
532
  std::string GetUrl(const shash::Any &hash) const {
533
    return BuildUrl(BuildRelativeUrl(hash));
534
  }
535
536
13
  Failures Fetch(const shash::Any &object_hash, std::string *object_file) {
537
13
    assert(object_file != NULL);
538
13
    assert(!object_hash.IsNull());
539
540
13
    const bool decompress = true;
541
13
    const bool nocache = false;
542
13
    const std::string url = BuildRelativeUrl(object_hash);
543
13
    return Download(url, decompress, nocache, &object_hash, object_file);
544
  }
545
546
3
  Failures Fetch(const std::string &relative_path,
547
                 const bool         decompress,
548
                 const bool         nocache,
549
                       std::string *file_path) {
550
3
    const shash::Any *expected_hash = NULL;
551
    return Download(relative_path, decompress, nocache, expected_hash,
552
3
                    file_path);
553
  }
554
555
 protected:
556
23
  std::string BuildUrl(const std::string &relative_path) const {
557
23
    return repo_url_ + "/" + relative_path;
558
  }
559
560
13
  std::string BuildRelativeUrl(const shash::Any &hash) const {
561
13
    return "data/" + hash.MakePath();
562
  }
563
564
16
  Failures Download(const std::string &relative_path,
565
                    const bool         decompress,
566
                    const bool         nocache,
567
                    const shash::Any  *expected_hash,
568
                          std::string *file_path) {
569
16
    file_path->clear();
570
571
    // create temporary file to host the fetching result
572
    const std::string tmp_path = BaseTN::temporary_directory() + "/" +
573
16
                                 GetFileName(relative_path);
574
16
    FILE *f = CreateTempFile(tmp_path, 0600, "w", file_path);
575
16
    if (NULL == f) {
576
      LogCvmfs(kLogDownload, kLogStderr,
577
               "failed to create temp file '%s' (errno: %d)",
578
               tmp_path.c_str(), errno);
579
      return BaseTN::kFailLocalIO;
580
    }
581
582
    // fetch and decompress the requested object
583
16
    const std::string url = BuildUrl(relative_path);
584
16
    const bool probe_hosts = false;
585
    download::JobInfo download_job(&url,
586
                                        decompress,
587
                                        probe_hosts,
588
                                        f,
589
16
                                        expected_hash);
590
16
    download_job.force_nocache = nocache;
591
16
    download::Failures retval = download_manager_->Fetch(&download_job);
592
16
    const bool success = (retval == download::kFailOk);
593
16
    fclose(f);
594
595
    // check if download worked and remove temporary file if not
596
16
    if (!success) {
597
5
      LogCvmfs(kLogDownload, kLogDebug, "failed to download file "
598
                                        "%s to '%s' (%d - %s)",
599
               relative_path.c_str(), file_path->c_str(),
600
               retval, Code2Ascii(retval));
601
5
      unlink(file_path->c_str());
602
5
      file_path->clear();
603
604
      // hand out the error status
605

5
      switch (retval) {
606
        case download::kFailLocalIO:
607
          return BaseTN::kFailLocalIO;
608
609
        case download::kFailBadUrl:
610
        case download::kFailProxyResolve:
611
        case download::kFailHostResolve:
612
        case download::kFailUnsupportedProtocol:
613
          return BaseTN::kFailNetwork;
614
615
        case download::kFailProxyHttp:
616
        case download::kFailHostHttp:
617
          return (download_job.http_code == 404)
618
            ? BaseTN::kFailNotFound
619
2
            : BaseTN::kFailNetwork;
620
621
        case download::kFailBadData:
622
        case download::kFailTooBig:
623
          return BaseTN::kFailBadData;
624
625
        default:
626

3
          if (download::IsProxyTransferError(retval) ||
627
              download::IsHostTransferError(retval)) {
628
3
            return BaseTN::kFailNetwork;
629
          }
630
          return BaseTN::kFailUnknown;
631
      }
632
    }
633
634
11
    assert(success);
635
11
    return BaseTN::kFailOk;
636
  }
637
638
 private:
639
  const std::string            repo_url_;
640
  const std::string            repo_name_;
641
  download::DownloadManager   *download_manager_;
642
  signature::SignatureManager *signature_manager_;
643
};
644
645
template <class CatalogT, class HistoryT, class ReflogT>
646
struct object_fetcher_traits<HttpObjectFetcher<CatalogT, HistoryT, ReflogT> > {
647
    typedef CatalogT CatalogTN;
648
    typedef HistoryT HistoryTN;
649
    typedef ReflogT  ReflogTN;
650
};
651
652
#endif  // CVMFS_OBJECT_FETCHER_H_