5#include <emscripten/fetch.h>
12EmscriptenHttpClient::EmscriptenHttpClient() {
16EmscriptenHttpClient::~EmscriptenHttpClient() {
20void EmscriptenHttpClient::OnFetchSuccess(emscripten_fetch_t* fetch) {
21 FetchResult* result =
static_cast<FetchResult*
>(fetch->userData);
24 std::lock_guard<std::mutex> lock(result->mutex);
25 result->success =
true;
26 result->status_code = fetch->status;
27 result->body = std::string(fetch->data, fetch->numBytes);
33 result->completed =
true;
35 result->cv.notify_one();
37 emscripten_fetch_close(fetch);
40void EmscriptenHttpClient::OnFetchError(emscripten_fetch_t* fetch) {
41 FetchResult* result =
static_cast<FetchResult*
>(fetch->userData);
44 std::lock_guard<std::mutex> lock(result->mutex);
45 result->success =
false;
46 result->status_code = fetch->status;
48 if (fetch->status == 0) {
49 result->error_message =
"Network error or CORS blocking";
51 result->error_message =
"HTTP error: " + std::to_string(fetch->status);
54 result->completed =
true;
56 result->cv.notify_one();
58 emscripten_fetch_close(fetch);
61void EmscriptenHttpClient::OnFetchProgress(emscripten_fetch_t* fetch) {
67absl::StatusOr<HttpResponse> EmscriptenHttpClient::PerformFetch(
68 const std::string& method,
69 const std::string& url,
70 const std::string& body,
77 emscripten_fetch_attr_t attr;
78 emscripten_fetch_attr_init(&attr);
81 strncpy(attr.requestMethod, method.c_str(),
sizeof(attr.requestMethod) - 1);
82 attr.requestMethod[
sizeof(attr.requestMethod) - 1] =
'\0';
86 attr.attributes = EMSCRIPTEN_FETCH_LOAD_TO_MEMORY;
89 attr.onsuccess = OnFetchSuccess;
90 attr.onerror = OnFetchError;
91 attr.onprogress = OnFetchProgress;
92 attr.userData = &result;
95 attr.timeoutMSecs = timeout_seconds_ * 1000;
98 std::vector<const char*> header_strings;
99 std::vector<std::string> header_storage;
101 for (
const auto& [key, value] : headers) {
102 header_storage.push_back(key);
103 header_storage.push_back(value);
107 if ((method ==
"POST" || method ==
"PUT") && !body.empty()) {
108 bool has_content_type =
false;
109 for (
const auto& [key, value] : headers) {
110 if (key ==
"Content-Type") {
111 has_content_type =
true;
115 if (!has_content_type) {
116 header_storage.push_back(
"Content-Type");
117 header_storage.push_back(
"application/json");
122 for (
const auto& str : header_storage) {
123 header_strings.push_back(str.c_str());
125 header_strings.push_back(
nullptr);
127 if (!header_strings.empty() && header_strings.size() > 1) {
128 attr.requestHeaders = header_strings.data();
132 if (!body.empty() && (method ==
"POST" || method ==
"PUT")) {
133 attr.requestData = body.c_str();
134 attr.requestDataSize = body.length();
138 emscripten_fetch_t* fetch = emscripten_fetch(&attr, url.c_str());
141 return absl::InternalError(
"Failed to initiate fetch request");
146 std::unique_lock<std::mutex> lock(result.mutex);
147 result.cv.wait(lock, [&result] {
return result.completed; });
151 if (!result.success) {
152 return absl::UnavailableError(result.error_message.empty()
153 ?
"Fetch request failed"
154 : result.error_message);
158 HttpResponse response;
159 response.status_code = result.status_code;
160 response.body = result.body;
161 response.headers = result.headers;
166absl::StatusOr<HttpResponse> EmscriptenHttpClient::Get(
167 const std::string& url,
169 return PerformFetch(
"GET", url,
"", headers);
172absl::StatusOr<HttpResponse> EmscriptenHttpClient::Post(
173 const std::string& url,
174 const std::string& body,
176 return PerformFetch(
"POST", url, body, headers);
179absl::StatusOr<HttpResponse> EmscriptenHttpClient::Put(
180 const std::string& url,
181 const std::string& body,
183 return PerformFetch(
"PUT", url, body, headers);
186absl::StatusOr<HttpResponse> EmscriptenHttpClient::Delete(
187 const std::string& url,
189 return PerformFetch(
"DELETE", url,
"", headers);
std::map< std::string, std::string > Headers
HTTP headers type definition.