Networking example

Below you can find source code of a networking example that showcases usage of the libbase functionality for performing network requests. This example is located in the /examples/networking/ directory in the repository and - if enabled - will be built along the libbase library itself.

CMakeLists.txt
 1add_executable(networking "")
 2
 3target_compile_options(networking
 4  PRIVATE
 5    ${LIBBASE_COMPILE_FLAGS}
 6)
 7
 8target_link_libraries(networking
 9  PRIVATE
10    libbase
11    libbase_net
12)
13
14target_sources(networking
15  PRIVATE
16    main.cc
17)
main.cc
  1#include <thread>
  2
  3#include "base/bind.h"
  4#include "base/callback.h"
  5#include "base/init.h"
  6#include "base/logging.h"
  7#include "base/message_loop/run_loop.h"
  8#include "base/net/init.h"
  9#include "base/net/simple_url_loader.h"
 10#include "base/net/url_request.h"
 11#include "base/sequence_checker.h"
 12#include "base/timer/elapsed_timer.h"
 13
 14void LogNetResponse(const base::net::ResourceResponse& response) {
 15  LOG(INFO) << "Result: " << static_cast<int>(response.result);
 16  LOG(INFO) << "HTTP code: " << response.code;
 17  LOG(INFO) << "Final URL: " << response.final_url;
 18  LOG(INFO) << "Downloaded " << response.data.size() << " bytes";
 19  LOG(INFO) << "Latency: " << response.timing_connect.InMilliseconds() << "ms";
 20  LOG(INFO) << "Headers";
 21  for (const auto& [h, v] : response.headers) {
 22    LOG(INFO) << "  " << h << ": " << v;
 23  }
 24  LOG_IF(INFO, !response.data.empty())
 25      << "Content:\n"
 26      << std::string{response.data.begin(), response.data.end()};
 27}
 28
 29void NetExampleGet() {
 30  base::RunLoop run_loop{};
 31
 32  // Try to download and signal on finish
 33  base::net::SimpleUrlLoader::DownloadUnbounded(
 34      base::net::ResourceRequest{
 35          "https://www.google.com/robots.txt",
 36          base::net::kDefaultHeaders,
 37          base::net::kNoPost,
 38          true,
 39          base::Seconds(5),
 40      },
 41      base::BindOnce([](base::net::ResourceResponse response) {
 42        LogNetResponse(response);
 43      }).Then(run_loop.QuitClosure()));
 44
 45  // Runs all tasks until the quit callback is called
 46  run_loop.Run();
 47}
 48
 49void NetExamplePost() {
 50  base::RunLoop run_loop{};
 51
 52  // Try to download and signal on finish
 53  const std::string data_str = "{\"key\": \"value\"}";
 54  base::net::SimpleUrlLoader::DownloadUnbounded(
 55      base::net::ResourceRequest{
 56          "https://httpbin.org/post",
 57          {"Content-Type: application/json"},
 58          std::vector<uint8_t>{data_str.begin(), data_str.end()},
 59          false,
 60          base::Seconds(5),
 61      },
 62      base::BindOnce([](base::net::ResourceResponse response) {
 63        LogNetResponse(response);
 64      }).Then(run_loop.QuitClosure()));
 65
 66  run_loop.Run();
 67}
 68
 69class UrlRequestExampleUser : public base::net::UrlRequest::Client {
 70 public:
 71  UrlRequestExampleUser(base::OnceClosure finished_closure)
 72      : finished_closure_(std::move(finished_closure)), request_(this) {}
 73
 74  void Download(base::net::ResourceRequest request) {
 75    DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
 76    request_.Start(std::move(request));
 77  }
 78
 79  void OnResponseStarted(const base::net::UrlRequest* request,
 80                         int code,
 81                         std::string final_url,
 82                         std::map<std::string, std::string> headers) override {
 83    DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
 84    DCHECK_EQ(request, &request_);
 85
 86    LOG(INFO) << __FUNCTION__ << "() code: " << code;
 87    LOG(INFO) << __FUNCTION__ << "() final_url: " << final_url;
 88    for (const auto& [k, v] : headers) {
 89      LOG(INFO) << __FUNCTION__ << "() header[" << k << "]: " << v;
 90    }
 91  }
 92
 93  void OnWriteData(const base::net::UrlRequest* request,
 94                   std::vector<uint8_t> chunk) override {
 95    DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
 96    DCHECK_EQ(request, &request_);
 97
 98    LOG(INFO) << __FUNCTION__ << "() received bytes: " << chunk.size();
 99  }
100
101  void OnRequestFinished(const base::net::UrlRequest* request,
102                         base::net::Result result) override {
103    DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
104    DCHECK_EQ(request, &request_);
105
106    LOG(INFO) << __FUNCTION__ << "() result: " << static_cast<int>(result);
107    std::move(finished_closure_).Run();
108  }
109
110 private:
111  SEQUENCE_CHECKER(sequence_checker_);
112  base::OnceClosure finished_closure_;
113  base::net::UrlRequest request_;
114};
115
116void NetExampleUrlRequest() {
117  base::RunLoop run_loop;
118
119  UrlRequestExampleUser url_request_user{run_loop.QuitClosure()};
120  url_request_user.Download(base::net::ResourceRequest{
121      "https://www.google.com/robots.txt",
122      base::net::kDefaultHeaders,
123      base::net::kNoPost,
124      false,
125      base::Seconds(5),
126  });
127
128  run_loop.Run();
129}
130
131int main(int argc, char* argv[]) {
132  base::Initialize(argc, argv, base::InitOptions{});
133  base::net::Initialize(base::net::InitOptions{});
134
135  const auto timer = base::ElapsedTimer{};
136
137  NetExampleGet();
138  NetExamplePost();
139  NetExampleUrlRequest();
140
141  LOG(INFO) << "Example finished in " << timer.Elapsed().InMillisecondsF()
142            << "ms";
143
144  base::net::Deinitialize();
145  base::Deinitialize();
146  return 0;
147}