Skip to content

Commit

Permalink
Fix bad cookie serialization (#157)
Browse files Browse the repository at this point in the history
* Create main.cpp

* Update tests.mk

* Create cookie.test.mk

* Update testbuild.yml

* Update http.hpp

* Update cookies.cpp

* Update http.hpp

* Update main.cpp

* Update main.cpp

* Added stupid headers test
  • Loading branch information
maddsua authored Feb 10, 2024
1 parent 3b2ab35 commit 3be6cab
Show file tree
Hide file tree
Showing 10 changed files with 111 additions and 16 deletions.
4 changes: 4 additions & 0 deletions .github/workflows/testbuild.yml
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,10 @@ jobs:
run: make test.errors
- name: VFS test
run: make test.vfs
- name: HTTP/Cookie test
run: make test.cookie
- name: HTTP/Headers test
run: make test.headers

build_examples:
needs: build_lib
Expand Down
8 changes: 4 additions & 4 deletions core/http/cookies.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ void Cookies::set(const std::string& key, const std::string& value) {
this->m_set_queue[keyNormalized] = { value };
}

void Cookies::set(const std::string& key, const std::string& value, const std::initializer_list<SetParam>& props) {
void Cookies::set(const std::string& key, const std::string& value, const std::initializer_list<CookieParams>& props) {
const auto keyNormalized = Strings::toLowerCase(key);
this->m_data[keyNormalized] = value;
this->m_set_queue[keyNormalized] = { value, props };
Expand Down Expand Up @@ -96,15 +96,15 @@ std::vector<std::string> Cookies::serialize() const {
return temp;
}

Cookies::SetParam::SetParam(const std::string& init) {
Cookies::CookieParams::CookieParams(const std::string& init) {
this->key = init;
}

Cookies::SetParam::SetParam(const char* init) {
Cookies::CookieParams::CookieParams(const char* init) {
this->key = init;
}

Cookies::SetParam::SetParam(std::initializer_list<std::string> init) {
Cookies::CookieParams::CookieParams(std::initializer_list<std::string> init) {

for (auto itr = init.begin(); itr != init.end(); itr++) {

Expand Down
16 changes: 8 additions & 8 deletions core/http/http.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -73,22 +73,22 @@ namespace Lambda::HTTP {
class Cookies {
protected:

struct SetParam {
struct CookieParams {
std::string key;
std::string value;

SetParam(const std::string& init);
SetParam(const char* init);
SetParam(std::initializer_list<std::string> init);
CookieParams(const std::string& init);
CookieParams(const char* init);
CookieParams(std::initializer_list<std::string> init);
};

struct SetItem {
struct CookieData {
std::string value;
std::initializer_list<SetParam> props;
std::vector<CookieParams> props;
};

std::unordered_map<std::string, std::string> m_data;
std::map<std::string, SetItem> m_set_queue;
std::map<std::string, CookieData> m_set_queue;

public:
Cookies() = default;
Expand All @@ -102,7 +102,7 @@ namespace Lambda::HTTP {
std::string get(const std::string& key) const;
bool has(const std::string& key) const;
void set(const std::string& key, const std::string& value);
void set(const std::string& key, const std::string& value, const std::initializer_list<SetParam>& props);
void set(const std::string& key, const std::string& value, const std::initializer_list<CookieParams>& props);
void del(const std::string& key);
std::vector<KVpair> entries() const;
size_t size() const noexcept;
Expand Down
7 changes: 4 additions & 3 deletions core/http/kvcontainer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -14,15 +14,16 @@ KVContainer::KVContainer(KVContainer&& other) {
KVContainer::KVContainer(const std::initializer_list<KVpair>& init) {
for (const auto& entry : init) {

const auto keyNormalized = Strings::toLowerCase(entry.first);
const auto keyNormalized = Strings::trim(Strings::toLowerCase(entry.first));
const auto element = this->m_data.find(keyNormalized);
const auto valueNormalized = Strings::trim(entry.second);

if (element == this->m_data.end()) {
this->m_data[keyNormalized] = { entry.second };
this->m_data[keyNormalized] = { valueNormalized };
continue;
}

element->second.push_back(entry.second);
element->second.push_back(valueNormalized);
}
}

Expand Down
2 changes: 1 addition & 1 deletion examples/api_server/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ int main(int argc, char const *argv[]) {
newCookies.set("userid", "test_user_0");
newCookies.set("x_lambda", "control", {
"Secure",
{"expires", "23 Oct 2077 08:28:00 GMT"}
{ "expires", "23 Oct 2077 08:28:00 GMT" }
});
response.setCookies(newCookies);
}
Expand Down
11 changes: 11 additions & 0 deletions tests/cookie/cookie.test.mk
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@

# Test cookie core/http module
TEST_COOKIE_TARGET = $(EXEPFX)cookie.test$(EXEEXT)
test.cookie: $(TEST_COOKIE_TARGET)
$(TEST_COOKIE_TARGET)

$(TEST_COOKIE_TARGET): tests/cookie/main.o $(LIB_CORE_HTTP) $(LIB_CORE_POLYFILL)
g++ $(CFLAGS) tests/cookie/main.cpp $(LIB_CORE_HTTP) $(LIB_CORE_POLYFILL) -o $(TEST_COOKIE_TARGET)

tests/cookie/main.o: tests/cookie/main.cpp
g++ -c $(CFLAGS) tests/cookie/main.cpp -o tests/cookie/main.o
35 changes: 35 additions & 0 deletions tests/cookie/main.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
#include <iostream>
#include <stdexcept>

#include "../../lambda.hpp"

using namespace Lambda;

int main(int argc, char const *argv[]) {

/*
Check for serialization errors resulling in incorrect or garbage data
*/
static const std::string compareValid = "userid=test_user_0\nx_lambda=control; Secure; expires=23 Oct 2077 08:28:00 GMT";

for (size_t i = 0; i < 100; i++) {

auto newCookies = HTTP::Cookies();
newCookies.set("userid", "test_user_0");
newCookies.set("x_lambda", "control", {
"Secure",
{ "expires", "23 Oct 2077 08:28:00 GMT" }
});

const auto generated = Strings::join(newCookies.serialize(), "\n");

if (generated != compareValid) {
std::cout << "Cookie run # " << i << " produced invalid result:\n" << generated << "\n\n";
throw std::runtime_error("Invalid serialization result");
}
}

puts("Cookie serialization test ok");

return 0;
}
11 changes: 11 additions & 0 deletions tests/headers/headers.test.mk
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@

# Test headers core/http module
TEST_HEADERS_TARGET = $(EXEPFX)headers.test$(EXEEXT)
test.headers: $(TEST_HEADERS_TARGET)
$(TEST_HEADERS_TARGET)

$(TEST_HEADERS_TARGET): tests/headers/main.o $(LIB_CORE_HTTP) $(LIB_CORE_POLYFILL)
g++ $(CFLAGS) tests/headers/main.cpp $(LIB_CORE_HTTP) $(LIB_CORE_POLYFILL) -o $(TEST_HEADERS_TARGET)

tests/headers/main.o: tests/headers/main.cpp
g++ -c $(CFLAGS) tests/headers/main.cpp -o tests/headers/main.o
31 changes: 31 additions & 0 deletions tests/headers/main.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
#include <iostream>
#include <stdexcept>

#include "../../lambda.hpp"

using namespace Lambda;

static const std::string compareData = "connection: upgrade\r\ncontent-length: 100\r\ncontent-encoding: br\r\n";

int main(int argc, char const *argv[]) {

HTTP::Headers headers = {
{ "ContenT-encoDinG", "br" },
{ " content-length \t", "\t 100 " },
{ "connection", "upgrade" }
};

std::string headersSerialized;

for (const auto& item : headers.entries()) {
headersSerialized += item.first + ": " + item.second + "\r\n";
}

if (headersSerialized != compareData) {
throw std::runtime_error("Serialized data mistmatch");
}

puts("Headers serialization test ok");

return 0;
}
2 changes: 2 additions & 0 deletions tests/tests.mk
Original file line number Diff line number Diff line change
Expand Up @@ -9,3 +9,5 @@ include tests/strings/strings.test.mk
include tests/errors/errors.test.mk
include tests/tcp/tcp.test.mk
include tests/vfs/vfs.test.mk
include tests/cookie/cookie.test.mk
include tests/headers/headers.test.mk

0 comments on commit 3be6cab

Please sign in to comment.