Skip to content

Commit

Permalink
Use multimap instead of map for headers
Browse files Browse the repository at this point in the history
Signed-off-by: Darshan Sen <raisinten@gmail.com>
  • Loading branch information
RaisinTen committed Apr 4, 2024
1 parent 4738ba6 commit 8a1aacc
Show file tree
Hide file tree
Showing 5 changed files with 41 additions and 15 deletions.
16 changes: 9 additions & 7 deletions include/benoni/http.h
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
#define BENONI_HTTP_H_

#include <functional> // std::function
#include <map> // std::map
#include <map> // std::multimap
#include <optional> // std::optional
#include <string> // std::string
#include <variant> // std::variant
Expand All @@ -27,12 +27,14 @@ class RequestOptions {
public:
Method method() const { return method_; }
const std::string &body() const { return body_; }
const std::map<std::string, std::string> &headers() const { return headers_; }
const std::multimap<std::string, std::string> &headers() const {
return headers_;
}
const std::optional<int> &timeout() const { return timeout_; }

private:
RequestOptions(Method method, std::string body,
std::map<std::string, std::string> headers,
std::multimap<std::string, std::string> headers,
std::optional<int> timeout)
: method_{method}, body_{std::move(body)}, headers_{std::move(headers)},
timeout_{std::move(timeout)} {}
Expand All @@ -41,7 +43,7 @@ class RequestOptions {

Method method_;
std::string body_;
std::map<std::string, std::string> headers_;
std::multimap<std::string, std::string> headers_;
std::optional<int> timeout_;
};

Expand All @@ -58,7 +60,7 @@ class RequestOptionsBuilder {
}

RequestOptionsBuilder &
set_headers(std::map<std::string, std::string> headers) {
set_headers(std::multimap<std::string, std::string> headers) {
headers_ = std::move(headers);
return *this;
}
Expand All @@ -76,14 +78,14 @@ class RequestOptionsBuilder {
private:
Method method_ = Method::GET;
std::string body_;
std::map<std::string, std::string> headers_;
std::multimap<std::string, std::string> headers_;
std::optional<int> timeout_;
};

struct Response {
std::string body;
uint16_t status;
std::map<std::string, std::string> headers;
std::multimap<std::string, std::string> headers;
};

auto request(const std::string &url, RequestOptions options,
Expand Down
13 changes: 11 additions & 2 deletions src/apple/http.mm
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
#import <Foundation/Foundation.h>

#include <map> // std::map
#include <sstream> // std::istringstream
#include <string> // std::string
#include <variant> // std::variant

Expand All @@ -11,7 +12,7 @@
struct HTTPTaskContext {
std::function<void(std::variant<std::string, benoni::Response>)> callback;
uint16_t status;
std::map<std::string, std::string> headers;
std::multimap<std::string, std::string> headers;
NSMutableData *data;
NSStringEncoding encoding;
};
Expand Down Expand Up @@ -92,8 +93,16 @@ - (void)URLSession:(NSURLSession *)session
auto &headers = context->headers;
NSDictionary *allHeaderFields = [httpResponse allHeaderFields];
for (NSString *headerField in allHeaderFields) {
headers[[headerField UTF8String]] =
std::string key = [headerField UTF8String];
std::string value =
[[allHeaderFields objectForKey:headerField] UTF8String];

// Splitting the header value by commas (common delimiter)
std::istringstream value_stream(value);
std::string single_value;
while (std::getline(value_stream, single_value, ',')) {
headers.emplace(key, single_value);
}
}
}

Expand Down
10 changes: 8 additions & 2 deletions src/linux/http.cc
Original file line number Diff line number Diff line change
Expand Up @@ -39,13 +39,19 @@ auto stream_close_callback(GObject *source_object, GAsyncResult *res,

g_object_unref(stream);

std::map<std::string, std::string> headers;
std::multimap<std::string, std::string> headers;
soup_message_headers_foreach(
async_http_context->message->response_headers,
[](const char *name, const char *value, gpointer user_data) {
auto &headers =
*static_cast<std::map<std::string, std::string> *>(user_data);
headers[name] = value;

// Splitting the header value by commas (common delimiter)
std::istringstream value_stream(value);
std::string single_value;
while (std::getline(value_stream, single_value, ',')) {
headers.emplace(name, single_value);
}
},
&headers);

Expand Down
12 changes: 10 additions & 2 deletions src/win32/http.cc
Original file line number Diff line number Diff line change
Expand Up @@ -336,7 +336,15 @@ class HTTPClient {
}

for (DWORD i = 0; i < dwHeadersCount; ++i) {
headers_[pHeaders[i].pszName] = pHeaders[i].pszValue;
std::string key = pHeaders[i].pszName;
std::string value = pHeaders[i].pszValue;

// Splitting the header value by commas (common delimiter)
std::istringstream value_stream(value);
std::string single_value;
while (std::getline(value_stream, single_value, ',')) {
headers.emplace(key, single_value);
}
}
}

Expand Down Expand Up @@ -423,7 +431,7 @@ class HTTPClient {
Request request_;

uint16_t status_;
std::map<std::string, std::string> headers_;
std::multimap<std::string, std::string> headers_;
DWORD dwSize_;
std::stringstream body_;
};
Expand Down
5 changes: 3 additions & 2 deletions test/unit/postman-echo-get.cc
Original file line number Diff line number Diff line change
Expand Up @@ -37,8 +37,9 @@ int main() {
exit(EXIT_FAILURE);
}

if (response.headers["Content-Type"] !=
"application/json; charset=utf-8") {
auto content_type = response.headers.find("Content-Type");
if (content_type == response.headers.end() ||
content_type->second != "application/json; charset=utf-8") {
std::cout << "unexpected content type in response headers: ["
<< std::endl;
for (const auto &[key, value] : response.headers) {
Expand Down

0 comments on commit 8a1aacc

Please sign in to comment.