1
#include "source/extensions/http/cache_v2/file_system_http_cache/lookup_context.h"
2

            
3
#include "source/extensions/http/cache_v2/file_system_http_cache/cache_file_fixed_block.h"
4
#include "source/extensions/http/cache_v2/file_system_http_cache/cache_file_header.pb.h"
5
#include "source/extensions/http/cache_v2/file_system_http_cache/cache_file_header_proto_util.h"
6
#include "source/extensions/http/cache_v2/file_system_http_cache/cache_file_reader.h"
7
#include "source/extensions/http/cache_v2/file_system_http_cache/file_system_http_cache.h"
8

            
9
namespace Envoy {
10
namespace Extensions {
11
namespace HttpFilters {
12
namespace CacheV2 {
13
namespace FileSystemHttpCache {
14

            
15
FileLookupContext::FileLookupContext(Event::Dispatcher& dispatcher, AsyncFileHandle handle,
16
                                     HttpCache::LookupCallback&& callback)
17
15
    : dispatcher_(dispatcher), file_handle_(std::move(handle)), callback_(std::move(callback)) {}
18

            
19
void FileLookupContext::begin(Event::Dispatcher& dispatcher, AsyncFileHandle handle,
20
15
                              HttpCache::LookupCallback&& callback) {
21
  // bare pointer because this object owns itself - it gets captured in
22
  // lambdas and is deleted when 'done' is eventually called.
23
15
  FileLookupContext* p = new FileLookupContext(dispatcher, std::move(handle), std::move(callback));
24
15
  p->getHeaderBlock();
25
15
}
26

            
27
15
void FileLookupContext::done(absl::StatusOr<LookupResult>&& result) {
28
15
  if (!result.ok() || result.value().cache_reader_ == nullptr) {
29
7
    auto queued = file_handle_->close(nullptr, [](absl::Status) {});
30
7
    ASSERT(queued.ok(), queued.status().ToString());
31
7
  }
32
15
  auto cb = std::move(callback_);
33
15
  delete this;
34
15
  cb(std::move(result));
35
15
}
36

            
37
4
absl::Status cacheEntryInvalidStatus() { return absl::DataLossError("corrupted cache file"); }
38

            
39
15
void FileLookupContext::getHeaderBlock() {
40
15
  auto queued =
41
15
      file_handle_->read(&dispatcher_, 0, CacheFileFixedBlock::size(),
42
15
                         [this](absl::StatusOr<Buffer::InstancePtr> read_result) -> void {
43
15
                           if (!read_result.ok()) {
44
1
                             return done(read_result.status());
45
1
                           }
46
14
                           if (read_result.value()->length() != CacheFileFixedBlock::size()) {
47
1
                             return done(cacheEntryInvalidStatus());
48
1
                           }
49
13
                           header_block_.populateFromStringView(read_result.value()->toString());
50
13
                           if (!header_block_.isValid()) {
51
1
                             return done(cacheEntryInvalidStatus());
52
1
                           }
53
12
                           if (header_block_.trailerSize()) {
54
4
                             getTrailers();
55
8
                           } else {
56
8
                             getHeaders();
57
8
                           }
58
12
                         });
59
15
  ASSERT(queued.ok(), queued.status().ToString());
60
15
}
61

            
62
10
void FileLookupContext::getHeaders() {
63
10
  auto queued =
64
10
      file_handle_->read(&dispatcher_, header_block_.offsetToHeaders(), header_block_.headerSize(),
65
10
                         [this](absl::StatusOr<Buffer::InstancePtr> read_result) -> void {
66
10
                           if (!read_result.ok()) {
67
1
                             return done(read_result.status());
68
1
                           }
69
9
                           if (read_result.value()->length() != header_block_.headerSize()) {
70
1
                             return done(cacheEntryInvalidStatus());
71
1
                           }
72
8
                           auto header_proto = makeCacheFileHeaderProto(*read_result.value());
73
8
                           result_.response_headers_ = headersFromHeaderProto(header_proto);
74
8
                           result_.response_metadata_ = metadataFromHeaderProto(header_proto);
75
8
                           result_.body_length_ = header_block_.bodySize();
76
8
                           result_.cache_reader_ =
77
8
                               std::make_unique<CacheFileReader>(std::move(file_handle_));
78
8
                           return done(std::move(result_));
79
9
                         });
80
10
  ASSERT(queued.ok(), queued.status().ToString());
81
10
}
82

            
83
4
void FileLookupContext::getTrailers() {
84
4
  auto queued = file_handle_->read(
85
4
      &dispatcher_, header_block_.offsetToTrailers(), header_block_.trailerSize(),
86
4
      [this](absl::StatusOr<Buffer::InstancePtr> read_result) -> void {
87
4
        if (!read_result.ok()) {
88
1
          return done(read_result.status());
89
1
        }
90
3
        if (read_result.value()->length() != header_block_.trailerSize()) {
91
1
          return done(cacheEntryInvalidStatus());
92
1
        }
93
2
        auto trailer_proto = makeCacheFileTrailerProto(*read_result.value());
94
2
        result_.response_trailers_ = trailersFromTrailerProto(trailer_proto);
95
2
        getHeaders();
96
2
      });
97
4
  ASSERT(queued.ok(), queued.status().ToString());
98
4
}
99

            
100
} // namespace FileSystemHttpCache
101
} // namespace CacheV2
102
} // namespace HttpFilters
103
} // namespace Extensions
104
} // namespace Envoy