Skip to content

Commit

Permalink
Add max request size limit (#124)
Browse files Browse the repository at this point in the history
  • Loading branch information
maddsua authored Feb 4, 2024
1 parent f480d05 commit a4dc043
Show file tree
Hide file tree
Showing 22 changed files with 214 additions and 135 deletions.
51 changes: 22 additions & 29 deletions core/compression/streams.hpp
Original file line number Diff line number Diff line change
@@ -1,9 +1,8 @@
#ifndef __LIB_MADDSUA_LAMBDA_EXTRA_COMPRESSION_STREAMS__
#define __LIB_MADDSUA_LAMBDA_EXTRA_COMPRESSION_STREAMS__

#include "../utils/utils.hpp"

#include <cstring>
#include <cstdint>
#include <brotli/encode.h>
#include <brotli/decode.h>
#include <zlib.h>
Expand All @@ -12,45 +11,39 @@

namespace Lambda::Compress::Streams {

using namespace Lambda::Literals;
static const size_t defaultChunkSize = 128 * 1024;

class BrotliCompressStream {
public:
BrotliEncoderState* stream = nullptr;
static const size_t chunk = 128_KB;
struct BrotliCompressStream {
BrotliEncoderState* stream = nullptr;
static const size_t chunk = defaultChunkSize;

BrotliCompressStream();
~BrotliCompressStream();
BrotliCompressStream();
~BrotliCompressStream();
};

class BrotliDecompressStream {
public:
BrotliDecoderState* stream = nullptr;
static const size_t chunk = 128_KB;
struct BrotliDecompressStream {
BrotliDecoderState* stream = nullptr;
static const size_t chunk = defaultChunkSize;

BrotliDecompressStream();
~BrotliDecompressStream();
BrotliDecompressStream();
~BrotliDecompressStream();
};

class ZlibStream {
public:
z_stream stream;
static const size_t chunk = 128_KB;

ZlibStream();
struct ZlibStream {
z_stream stream;
static const size_t chunk = defaultChunkSize;

ZlibStream();
};

class ZlibCompressStream : public ZlibStream {
public:
ZlibCompressStream(int compression, int winbits);
~ZlibCompressStream();
struct ZlibCompressStream : ZlibStream {
ZlibCompressStream(int compression, int winbits);
~ZlibCompressStream();
};

class ZlibDecompressStream : public ZlibStream {
public:
ZlibDecompressStream(int winbits);
~ZlibDecompressStream();
struct ZlibDecompressStream : ZlibStream {
ZlibDecompressStream(int winbits);
~ZlibDecompressStream();
};

};
Expand Down
1 change: 0 additions & 1 deletion core/core.mk
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@
include core/compression/compression.mk
include core/crypto/crypto.mk
include core/encoding/encoding.mk
include core/html/html.mk
include core/http/http.mk
include core/json/json.mk
include core/network/network.mk
Expand Down
17 changes: 0 additions & 17 deletions core/html/html.mk

This file was deleted.

11 changes: 0 additions & 11 deletions core/html/templates.cpp

This file was deleted.

18 changes: 0 additions & 18 deletions core/html/templates.hpp

This file was deleted.

7 changes: 7 additions & 0 deletions core/http/http.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -165,12 +165,19 @@ namespace Lambda::HTTP {
std::string m_text;

public:

enum struct Type {
Unknown, Info, Success, Redirect, ClientError, ServerError
};

Status();
Status(uint32_t code);
Status(uint32_t code, const std::string& text);

uint32_t code() const noexcept;
const std::string& text() const noexcept;

Type type() const noexcept;
};

struct Response {
Expand Down
12 changes: 12 additions & 0 deletions core/http/status.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,18 @@ Status::Status(uint32_t code) {
uint32_t Status::code() const noexcept {
return this->m_code;
}

const std::string& Status::text() const noexcept {
return this->m_text;
}

Status::Type Status::type() const noexcept {

if (this->m_code < 200) return Type::Info;
else if (this->m_code >= 200 && this->m_code < 300) return Type::Success;
else if (this->m_code >= 300 && this->m_code < 400) return Type::Redirect;
else if (this->m_code >= 400 && this->m_code < 500) return Type::ClientError;
else if (this->m_code >= 500) return Type::ServerError;

return Type::Unknown;
}
27 changes: 25 additions & 2 deletions core/server/handlers/connection.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ void Handlers::connectionHandler(
};

const auto& conninfo = conn.info();
std::optional<std::string> handlerError;

if (config.loglevel.connections) fprintf(stdout,
"%s%s:%i connected on %i\n",
Expand All @@ -30,8 +31,30 @@ void Handlers::connectionHandler(

try {

auto connctx = IncomingConnection(conn, config.transport);
handlerCallback(connctx);
auto connctx = IncomingConnection(conn, config);

try {

handlerCallback(connctx);

} catch(const std::exception& e) {
handlerError = e.what();
} catch(...) {
handlerError = "unhandled exception";
}

if (handlerError.has_value()) {

if (config.loglevel.requests) fprintf(stderr,
"%s%s crashed: %s\n",
createLogTimeStamp().c_str(),
"tcp handler",
handlerError.value().c_str()
);

auto errorResponse = Pages::renderErrorPage(500, handlerError.value(), config.errorResponseType);
connctx.respond(errorResponse);
}

} catch(const std::exception& e) {

Expand Down
39 changes: 2 additions & 37 deletions core/server/handlers/serverless.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@
#include "../../../build_options.hpp"
#include "../../polyfill/polyfill.hpp"
#include "../../crypto/crypto.hpp"
#include "../../html/templates.hpp"
#include "../../json/json.hpp"
#include "../../crypto/crypto.hpp"

Expand All @@ -21,9 +20,6 @@ using namespace Lambda;
using namespace Lambda::Server;
using namespace Lambda::Server::Handlers;

Lambda::HTTP::Response renderServerErrorPage(std::string message);
Lambda::HTTP::Response composeServerErrorResponse(std::string message);

void Handlers::serverlessHandler(
Network::TCP::Connection&& conn,
const ServeOptions& config,
Expand All @@ -49,7 +45,7 @@ void Handlers::serverlessHandler(

try {

auto connctx = IncomingConnection(conn, config.transport);
auto connctx = IncomingConnection(conn, config);
while (auto nextOpt = connctx.nextRequest()){

if (!nextOpt.has_value()) break;
Expand All @@ -76,9 +72,7 @@ void Handlers::serverlessHandler(

if (handlerError.has_value()) {

response = config.errorResponseType == ErrorResponseType::JSON ?
composeServerErrorResponse(handlerError.value()) :
renderServerErrorPage(handlerError.value());
response = Pages::renderErrorPage(500, handlerError.value(), config.errorResponseType);

if (config.loglevel.requests) fprintf(stderr,
"%s%s crashed: %s\n",
Expand Down Expand Up @@ -129,32 +123,3 @@ void Handlers::serverlessHandler(
conninfo.hostPort
);
}

Lambda::HTTP::Response renderServerErrorPage(std::string message) {

auto templateSource = HTML::Templates::servicePage();

auto pagehtml = HTML::renderTemplate(templateSource, {
{ "svcpage_statuscode", std::to_string(500) },
{ "svcpage_statustext", "service error" },
{ "svcpage_message_text", "Function handler crashed: " + message }
});

return Lambda::HTTP::Response(500, {
{ "Content-Type", "text/html" }
}, pagehtml);
}

Lambda::HTTP::Response composeServerErrorResponse(std::string message) {

JSON::Map responseObject = {
{ "ok", false },
{ "status", "failed" },
{ "context", "function handler crashed" },
{ "what", message }
};

return Lambda::HTTP::Response(500, {
{"content-type", "application/json"}
}, JSON::stringify(responseObject));
}
10 changes: 7 additions & 3 deletions core/server/http/connection.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,13 @@ using namespace Lambda::Server::HTTPTransport;

IncomingConnection::IncomingConnection(
Network::TCP::Connection& conn,
const HTTPTransportOptions& opts
) : ctx({ conn, opts, conn.info() }) {}

const ServeOptions& opts
) : ctx({
conn,
opts.transport,
conn.info(),
opts.errorResponseType
}) {}

std::optional<HTTP::Request> IncomingConnection::nextRequest() {

Expand Down
23 changes: 21 additions & 2 deletions core/server/http/transport.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
#include <algorithm>
#include <map>
#include <set>
#include <iterator>

using namespace Lambda;
using namespace Lambda::Network;
Expand Down Expand Up @@ -41,6 +42,15 @@ std::optional<IncomingRequest> HTTPTransport::requestReader(HTTPReaderContext& c

ctx.buffer.insert(ctx.buffer.end(), newBytes.begin(), newBytes.end());
headerEnded = std::search(ctx.buffer.begin(), ctx.buffer.end(), patternEndHeader.begin(), patternEndHeader.end());

if (ctx.buffer.size() > ctx.topts.maxRequestSize) {

auto errorResponse = Pages::renderErrorPage(413, "Request size too large", ctx.errorResponseType);
writeResponse(errorResponse, { ContentEncodings::None, false, ctx.conn });
ctx.conn.end();

throw std::runtime_error("request header size too big");
}
}

if (!ctx.buffer.size() || headerEnded == ctx.buffer.end()) {
Expand All @@ -59,7 +69,7 @@ std::optional<IncomingRequest> HTTPTransport::requestReader(HTTPReaderContext& c
auto& requestUrlString = headerStartLine.at(1);

IncomingRequest next;
next.request.method = Lambda::HTTP::Method(requestMethodString);
next.request.method = HTTP::Method(requestMethodString);

for (size_t i = 1; i < headerFields.size(); i++) {

Expand Down Expand Up @@ -127,7 +137,7 @@ std::optional<IncomingRequest> HTTPTransport::requestReader(HTTPReaderContext& c
}
}

if (ctx.options.reuseConnections) {
if (ctx.topts.reuseConnections) {
auto connectionHeader = next.request.headers.get("connection");
if (ctx.keepAlive) ctx.keepAlive = !Strings::includes(connectionHeader, "close");
else ctx.keepAlive = Strings::includes(connectionHeader, "keep-alive");
Expand All @@ -153,6 +163,15 @@ std::optional<IncomingRequest> HTTPTransport::requestReader(HTTPReaderContext& c

if (bodySize) {

if ((std::distance(ctx.buffer.begin(), headerEnded) + bodySize) > ctx.topts.maxRequestSize) {

auto errorResponse = Pages::renderErrorPage(413, "Request size too large", ctx.errorResponseType);
writeResponse(errorResponse, { ContentEncodings::None, false, ctx.conn });
ctx.conn.end();

throw std::runtime_error("total request size too big");
}

if (!ctx.conn.active()) {
throw std::runtime_error("connection was terminated before request body could be received");
}
Expand Down
2 changes: 1 addition & 1 deletion core/server/http/upgrade.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ WebsocketContext IncomingConnection::upgrateToWebsocket(const HTTP::Request& ini
this->ctx.buffer.clear();

this->activeProto = ActiveProtocol::WS;
return WebsocketContext(this->ctx.conn);
return WebsocketContext(this->ctx.conn, this->ctx.topts);
}

WebsocketContext IncomingConnection::upgrateToWebsocket() {
Expand Down
Loading

0 comments on commit a4dc043

Please sign in to comment.