Skip to content

feat: add max_*_size options - #67

Open
kevinschweikert wants to merge 1 commit into
gleam-lang:mainfrom
kevinschweikert:feat/max-size-options
Open

kevinschweikert wants to merge 1 commit into
gleam-lang:mainfrom
kevinschweikert:feat/max-size-options

Conversation

@kevinschweikert

@kevinschweikert kevinschweikert commented Oct 24, 2026 •

Copy link
Copy Markdown

inets 9.7.2 introduced two new options:

  • max_body_size
  • max_header_size

The default configuration keeps the documented OTP defaults

Closes #66

Comment thread src/gleam/httpc.gleam Outdated
BodyFormat(BodyFormat)
SocketOpts(List(SocketOpt))
Ipv6HostWithBrackets(Bool)
MaxHeaderSize(Dynamic)

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is there a better way to type this? the option takes either {bytes, N} or nolimit. So either a tuple or a single atom.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It should be a new type rather than Dynamic, as it would be invalid for it to be values other than those two and Dynamic means anything.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed by introducing a private ErlMaxSize type

@lpil lpil left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you!!! I've left a bunch of notes inline.

Comment thread src/gleam/httpc.gleam Outdated
Comment on lines +19 to +22
/// The header of the response is longer than configured
HeaderTooLong(max_size: Int)
/// The responses `Content-Length` header exceeded the limit
ResponseBodyTooBig

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's use the same format for both new error variants.

Perhaps HeaderToLarge and BodyTooLarge?

I don't think having the max size from the configuration is overly useful here. Is it possible to get the name of the header?

Could you change the documentation to these please:

One of the response headers was larger than max_header_size.

The response body was larger than max_body_size.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would propose ResponseHeaderTooLarge and ResponseBodyTooLarge to align with ResponseTimeout so that it is consistent with the existing naming scheme and it clearly says that the issue is the response and not the request.

I don't see a way to get the offending header because the max size is summed across all headers. the erlang error just returns the number of configured max bytes which is a bit redundant in our case.

Comment thread src/gleam/httpc.gleam Outdated
BodyFormat(BodyFormat)
SocketOpts(List(SocketOpt))
Ipv6HostWithBrackets(Bool)
MaxHeaderSize(Dynamic)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It should be a new type rather than Dynamic, as it would be invalid for it to be values other than those two and Dynamic means anything.

Comment thread src/gleam/httpc.gleam Outdated
Comment on lines +206 to +211
/// Max header size (cummulative)
///
max_header_size: MaxSize,
/// Max body size
///
max_body_size: MaxSize,

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This documentation is very sparse, please add more detail.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done! I've used the same wording as OTP

Comment thread src/gleam/httpc.gleam
verify_tls: True,
follow_redirects: False,
timeout: 30_000,
max_header_size: Bytes(10_240),

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's go for 2kb rather than 1kib.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just so you know i set the same default as httpc itself:

https://www.erlang.org/doc/apps/inets/httpc.html#request/5

max_header_size - Maximum total number of bytes allowed for the response headers (cumulative across all header lines). If the server sends headers exceeding this limit, the request fails with {error, {header_too_long, {max, MaxSize}}}.

The atom nolimit disables the check (not recommended).

Default is 10240 (same as the max_header_size configuration for httpd).

Comment thread src/gleam/httpc.gleam
follow_redirects: False,
timeout: 30_000,
max_header_size: Bytes(10_240),
max_body_size: Nolimit,

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is there a reason to ever permit no limit? Surely the same problem exists with the body, and a limit is always desired.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same here, this is the httpc default:

https://www.erlang.org/doc/apps/inets/httpc.html#request/5

max_body_size - Maximum number of bytes allowed for the response body. If the Content-Length of the response exceeds this limit, the request fails with {error, body_too_big}.

The atom nolimit disables the check.

Default is nolimit.

Comment thread src/gleam/httpc.gleam Outdated
Builder(..config, timeout:)
}

/// Maximum total number of bytes allowed for the response headers (cumulative across all header lines)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Wrap long lines please, and sentences end with a full-stop.

Please write the documentation in the style of the other builder functions, and include a description of what happens if it is exceeded.

Set the maximum size limit in bytes for the combination of all the headers of the response.

The default is 20000 bytes.

If a response's headers are larger than this limit then the XYZ error is returned.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done!

Comment thread src/gleam/httpc.gleam Outdated
Builder(..config, max_header_size:)
}

/// Maximum number of bytes allowed for the response body.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same for this documentation.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done!

Comment thread test/mock_server.gleam Outdated

["header_size", size_bytes_str], _ -> {
let assert Ok(size_bytes) = int.parse(size_bytes_str)
let header = list.repeat("a", size_bytes) |> string.join("")

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Use string.repeat please 🙏

This test checks only a single header, but the feature it across all headers, so verify that behaviour please.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah i didn't know string.repeat existed! Fixed!

The tests are a bit tricky to write. I changed the implementation to return two headers so the cumulative behaviour can be tested. But the server itself also injects some headers like date, connection and content-length which are out of reach in the http handler. so the test has to assert with some overhead margins.

Comment thread CHANGELOG.md Outdated
## Unreleased

- Fixed a bug where requests to IPv6 literal hosts would fail.
- Added `max_body_size` and `max_header_size` to the configuration options

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Document the other additions too please, and sentences end with a full stop.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done!

@kevinschweikert

Copy link
Copy Markdown
Author

@lpil i hope i adressed everything. Let me know if anything still needs changing!

inets 9.7.2 introduced two new options:

- max_body_size
- max_header_size
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Support max_header_size

2 participants