mirror of
https://github.com/lightpanda-io/browser.git
synced 2026-03-21 20:24:42 +00:00
Merge pull request #1499 from lightpanda-io/http_max_response_size
Add http_max_response_size
This commit is contained in:
@@ -103,6 +103,13 @@ pub fn httpMaxRedirects(_: *const Config) u8 {
|
||||
return 10;
|
||||
}
|
||||
|
||||
pub fn httpMaxResponseSize(self: *const Config) ?usize {
|
||||
return switch (self.mode) {
|
||||
inline .serve, .fetch => |opts| opts.common.http_max_response_size,
|
||||
else => unreachable,
|
||||
};
|
||||
}
|
||||
|
||||
pub fn logLevel(self: *const Config) ?log.Level {
|
||||
return switch (self.mode) {
|
||||
inline .serve, .fetch => |opts| opts.common.log_level,
|
||||
@@ -164,6 +171,7 @@ pub const Common = struct {
|
||||
http_max_host_open: ?u8 = null,
|
||||
http_timeout: ?u31 = null,
|
||||
http_connect_timeout: ?u31 = null,
|
||||
http_max_response_size: ?usize = null,
|
||||
tls_verify_host: bool = true,
|
||||
log_level: ?log.Level = null,
|
||||
log_format: ?log.Format = null,
|
||||
@@ -249,6 +257,11 @@ pub fn printUsageAndExit(self: *const Config, success: bool) void {
|
||||
\\ to complete. 0 means it never times out.
|
||||
\\ Defaults to 10000.
|
||||
\\
|
||||
\\--http_max_response_size
|
||||
\\ Limits the acceptable response size for any request
|
||||
\\ (e.g. XHR, fetch, script loading, ...).
|
||||
\\ Defaults to no limit.
|
||||
\\
|
||||
\\--log_level The log level: debug, info, warn, error or fatal.
|
||||
\\ Defaults to
|
||||
++ (if (builtin.mode == .Debug) " info." else "warn.") ++
|
||||
@@ -683,6 +696,19 @@ fn parseCommonArg(
|
||||
return true;
|
||||
}
|
||||
|
||||
if (std.mem.eql(u8, "--http_max_response_size", opt)) {
|
||||
const str = args.next() orelse {
|
||||
log.fatal(.app, "missing argument value", .{ .arg = "--http_max_response_size" });
|
||||
return error.InvalidArgument;
|
||||
};
|
||||
|
||||
common.http_max_response_size = std.fmt.parseInt(usize, str, 10) catch |err| {
|
||||
log.fatal(.app, "invalid argument value", .{ .arg = "--http_max_response_size", .err = err });
|
||||
return error.InvalidArgument;
|
||||
};
|
||||
return true;
|
||||
}
|
||||
|
||||
if (std.mem.eql(u8, "--log_level", opt)) {
|
||||
const str = args.next() orelse {
|
||||
log.fatal(.app, "missing argument value", .{ .arg = "--log_level" });
|
||||
|
||||
@@ -366,17 +366,16 @@ fn makeTransfer(self: *Client, req: Request) !*Transfer {
|
||||
.req = req,
|
||||
.ctx = req.ctx,
|
||||
.client = self,
|
||||
.max_response_size = self.config.httpMaxResponseSize(),
|
||||
};
|
||||
return transfer;
|
||||
}
|
||||
|
||||
fn requestFailed(transfer: *Transfer, err: anyerror, comptime execute_callback: bool) void {
|
||||
// this shouldn't happen, we'll crash in debug mode. But in release, we'll
|
||||
// just noop this state.
|
||||
if (comptime IS_DEBUG) {
|
||||
std.debug.assert(transfer._notified_fail == false);
|
||||
}
|
||||
if (transfer._notified_fail) {
|
||||
// we can force a failed request within a callback, which will eventually
|
||||
// result in this being called again in the more general loop. We do this
|
||||
// because we can raise a more specific error inside a callback in some cases
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -787,6 +786,7 @@ pub const Request = struct {
|
||||
resource_type: ResourceType,
|
||||
credentials: ?[:0]const u8 = null,
|
||||
notification: *Notification,
|
||||
max_response_size: ?usize = null,
|
||||
|
||||
// This is only relevant for intercepted requests. If a request is flagged
|
||||
// as blocking AND is intercepted, then it'll be up to us to wait until
|
||||
@@ -877,6 +877,8 @@ pub const Transfer = struct {
|
||||
// the headers, and the [encoded] body.
|
||||
bytes_received: usize = 0,
|
||||
|
||||
max_response_size: ?usize = null,
|
||||
|
||||
// We'll store the response header here
|
||||
response_header: ?ResponseHeader = null,
|
||||
|
||||
@@ -1125,6 +1127,14 @@ pub const Transfer = struct {
|
||||
}
|
||||
}
|
||||
|
||||
if (transfer.max_response_size) |max_size| {
|
||||
if (transfer.getContentLength()) |cl| {
|
||||
if (cl > max_size) {
|
||||
return error.ResponseTooLarge;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const proceed = transfer.req.header_callback(transfer) catch |err| {
|
||||
log.err(.http, "header_callback", .{ .err = err, .req = transfer });
|
||||
return err;
|
||||
@@ -1276,6 +1286,13 @@ pub const Transfer = struct {
|
||||
}
|
||||
|
||||
transfer.bytes_received += chunk_len;
|
||||
if (transfer.max_response_size) |max_size| {
|
||||
if (transfer.bytes_received > max_size) {
|
||||
requestFailed(transfer, error.ResponseTooLarge, true);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
const chunk = buffer[0..chunk_len];
|
||||
transfer.req.data_callback(transfer, chunk) catch |err| {
|
||||
log.err(.http, "data_callback", .{ .err = err, .req = transfer });
|
||||
|
||||
Reference in New Issue
Block a user