diff --git a/README.md b/README.md index 396ce33..2bd2345 100644 --- a/README.md +++ b/README.md @@ -195,15 +195,26 @@ std::shared_ptr res = This feature was contributed by [underscorediscovery](https://github.com/yhirose/cpp-httplib/pull/23). +### Basic Authentication + +```cpp +httplib::Client cli("httplib.org"); + +auto res = cli.Get("/basic-auth/hello/world", { + httplib::make_basic_authentication_header("hello", "world") +}); +// res->status should be 200 +// res->body should be "{\n \"authenticated\": true, \n \"user\": \"hello\"\n}\n". +``` + ### Range ```cpp -httplib::Client cli("httpbin.org", 80); +httplib::Client cli("httpbin.org"); -// 'Range: bytes=1-10' -httplib::Headers headers = { httplib::make_range_header(1, 10) }; - -auto res = cli.Get("/range/32", headers); +auto res = cli.Get("/range/32", { + httplib::make_range_header(1, 10) // 'Range: bytes=1-10' +}); // res->status should be 206. // res->body should be "bcdefghijk". ``` diff --git a/httplib.h b/httplib.h index 1e986ad..5adfc2a 100644 --- a/httplib.h +++ b/httplib.h @@ -529,6 +529,38 @@ inline size_t to_utf8(int code, char *buff) { return 0; } +// NOTE: This code came up with the following stackoverflow post: +// https://stackoverflow.com/questions/180947/base64-decode-snippet-in-c +inline std::string base64_encode(const std::string &in) { + static const auto lookup = + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; + + std::string out; + out.reserve(in.size()); + + int val = 0; + int valb = -6; + + for (uint8_t c : in) { + val = (val << 8) + c; + valb += 8; + while (valb >= 0) { + out.push_back(lookup[(val >> valb) & 0x3F]); + valb -= 6; + } + } + + if (valb > -6) { + out.push_back(lookup[((val << 8) >> (valb + 8)) & 0x3F]); + } + + while (out.size() % 4) { + out.push_back('='); + } + + return out; +} + inline bool is_file(const std::string &path) { struct stat st; return stat(path.c_str(), &st) >= 0 && S_ISREG(st.st_mode); @@ -1439,6 +1471,12 @@ inline std::pair make_range_header(uint64_t value, return std::make_pair("Range", field); } + +inline std::pair +make_basic_authentication_header(const std::string& username, const std::string& password) { + auto field = "Basic " + detail::base64_encode(username + ":" + password); + return std::make_pair("Authorization", field); +} // Request implementation inline bool Request::has_header(const char *key) const { return detail::has_header(headers, key); diff --git a/test/test.cc b/test/test.cc index b278bca..14006a2 100644 --- a/test/test.cc +++ b/test/test.cc @@ -327,8 +327,9 @@ TEST(BaseAuthTest, FromHTTPWatch) { } { - httplib::Headers headers = {{"Authorization", "Basic aGVsbG86d29ybGQ="}}; - auto res = cli.Get("/basic-auth/hello/world", headers); + auto res = cli.Get("/basic-auth/hello/world", { + httplib::make_basic_authentication_header("hello", "world") + }); ASSERT_TRUE(res != nullptr); EXPECT_EQ(res->body, "{\n \"authenticated\": true, \n \"user\": \"hello\"\n}\n");