Aktualizr
C++ SOTA Client
All Classes Namespaces Files Functions Variables Enumerations Enumerator Pages
httpfake.h
1 #ifndef HTTPFAKE_H_
2 #define HTTPFAKE_H_
3 
4 #include <boost/algorithm/hex.hpp>
5 #include <boost/algorithm/string.hpp>
6 #include <boost/filesystem.hpp>
7 #include <chrono>
8 #include <fstream>
9 #include <string>
10 #include <thread>
11 
12 #include "json/json.h"
13 
14 #include "crypto/crypto.h"
15 #include "http/httpinterface.h"
16 #include "logging/logging.h"
17 #include "metafake.h"
18 #include "utilities/utils.h"
19 
20 enum class ProvisioningResult { kOK, kFailure };
21 
22 class HttpFake : public HttpInterface {
23  public:
24  // old style HttpFake with centralized multi repo and url rewriting
25  HttpFake(const boost::filesystem::path &test_dir_in, std::string flavor = "",
26  const boost::filesystem::path &meta_dir_in = "")
27  : test_dir(test_dir_in), flavor_(std::move(flavor)), meta_dir(meta_dir_in) {
28  if (meta_dir.empty()) {
29  meta_dir = temp_meta_dir.Path();
30  MetaFake meta(meta_dir);
31  }
32  }
33 
34  virtual ~HttpFake() {}
35 
36  void setCerts(const std::string &ca, CryptoSource ca_source, const std::string &cert, CryptoSource cert_source,
37  const std::string &pkey, CryptoSource pkey_source) override {
38  (void)ca;
39  (void)ca_source;
40  (void)cert;
41  (void)cert_source;
42  (void)pkey;
43  (void)pkey_source;
44  }
45 
46  // rewrite xxx/yyy.json to xxx/yyy_flavor.json
47  bool rewrite(std::string &url, const std::string &pattern) {
48  size_t pat_pos = url.find(pattern);
49  if (pat_pos == std::string::npos) {
50  return false;
51  }
52  size_t ext_pos = pattern.find(".json");
53  if (ext_pos == std::string::npos) {
54  LOG_ERROR << "Invalid pattern";
55  url = "";
56  return false;
57  }
58 
59  url.replace(pat_pos + ext_pos, std::string(".json").size(), "_" + flavor_ + ".json");
60  return true;
61  }
62 
63  virtual HttpResponse handle_event(const std::string &url, const Json::Value &data) {
64  (void)url;
65  (void)data;
66  // do something in child instances
67  return HttpResponse("", 400, CURLE_OK, "");
68  }
69 
70  HttpResponse get(const std::string &url, int64_t maxsize) override {
71  (void)maxsize;
72  std::cout << "URL requested: " << url << "\n";
73 
74  std::string new_url = url;
75  if (!flavor_.empty()) {
76  rewrite(new_url, "director/targets.json") || rewrite(new_url, "repo/timestamp.json") ||
77  rewrite(new_url, "repo/targets.json") || rewrite(new_url, "snapshot.json");
78 
79  if (new_url != url) {
80  std::cout << "Rewritten to: " << new_url << "\n";
81  }
82  }
83 
84  const boost::filesystem::path path = meta_dir / new_url.substr(tls_server.size());
85 
86  std::cout << "file served: " << path << "\n";
87 
88  if (boost::filesystem::exists(path)) {
89  return HttpResponse(Utils::readFile(path), 200, CURLE_OK, "");
90  } else {
91  std::cout << "not found: " << path << "\n";
92  return HttpResponse({}, 404, CURLE_OK, "");
93  }
94  }
95 
96  HttpResponse post(const std::string &url, const std::string &content_type, const std::string &data) override {
97  (void)url;
98  (void)content_type;
99  (void)data;
100  return HttpResponse({}, 200, CURLE_OK, "");
101  }
102 
103  HttpResponse post(const std::string &url, const Json::Value &data) override {
104  if (url.find("/devices") != std::string::npos || url.find("/director/ecus") != std::string::npos || url.empty()) {
105  LOG_ERROR << "OK create device";
106  Utils::writeFile((test_dir / "post.json").string(), data);
107  if (provisioningResponse == ProvisioningResult::kOK) {
108  return HttpResponse(Utils::readFile("tests/test_data/cred.p12"), 200, CURLE_OK, "");
109  } else {
110  return HttpResponse("", 400, CURLE_OK, "");
111  }
112  } else if (url.find("/events") != std::string::npos) {
113  return handle_event(url, data);
114  }
115 
116  return HttpResponse("", 400, CURLE_OK, "");
117  }
118 
119  HttpResponse put(const std::string &url, const std::string &content_type, const std::string &data) override {
120  (void)url;
121  (void)content_type;
122  (void)data;
123  return HttpResponse({}, 200, CURLE_OK, "");
124  }
125 
126  HttpResponse put(const std::string &url, const Json::Value &data) override {
127  last_manifest = data;
128  return HttpResponse(url, 200, CURLE_OK, "");
129  }
130 
131  std::future<HttpResponse> downloadAsync(const std::string &url, curl_write_callback write_cb,
132  curl_xferinfo_callback progress_cb, void *userp, curl_off_t from,
133  CurlHandler *easyp) override {
134  (void)userp;
135  (void)from;
136  (void)easyp;
137  (void)progress_cb;
138 
139  std::cout << "URL requested: " << url << "\n";
140  const boost::filesystem::path path = meta_dir / url.substr(tls_server.size());
141  std::cout << "file served: " << path << "\n";
142 
143  std::promise<HttpResponse> resp_promise;
144  auto resp_future = resp_promise.get_future();
145  std::thread(
146  [path, write_cb, progress_cb, userp, url](std::promise<HttpResponse> promise) {
147  std::string content = Utils::readFile(path.string());
148  for (unsigned int i = 0; i < content.size(); ++i) {
149  write_cb(const_cast<char *>(&content[i]), 1, 1, userp);
150  progress_cb(userp, 0, 0, 0, 0);
151  if (url.find("downloads/repo/targets/primary_firmware.txt") != std::string::npos) {
152  std::this_thread::sleep_for(std::chrono::milliseconds(100)); // Simulate big file
153  }
154  }
155  promise.set_value(HttpResponse(content, 200, CURLE_OK, ""));
156  },
157  std::move(resp_promise))
158  .detach();
159 
160  return resp_future;
161  }
162 
163  HttpResponse download(const std::string &url, curl_write_callback write_cb, curl_xferinfo_callback progress_cb,
164  void *userp, curl_off_t from) override {
165  return downloadAsync(url, write_cb, progress_cb, userp, from, nullptr).get();
166  }
167 
168  const std::string tls_server = "https://tlsserver.com";
169  ProvisioningResult provisioningResponse{ProvisioningResult::kOK};
170  Json::Value last_manifest;
171 
172  protected:
173  boost::filesystem::path test_dir;
174  std::string flavor_;
175  boost::filesystem::path meta_dir;
176  TemporaryDirectory temp_meta_dir;
177 };
178 
179 #endif // HTTPFAKE_H_
HttpFake
Definition: httpfake.h:22
HttpInterface
Definition: httpinterface.h:38
data
General data structures.
Definition: types.cc:44
HttpResponse
Definition: httpinterface.h:17
TemporaryDirectory
Definition: utils.h:82
MetaFake
Definition: metafake.h:14