Module: Sentiero::Web::BodyReader
- Defined in:
- lib/sentiero/web/body_reader.rb
Overview
Reads a request body (optionally gzip-encoded) with a hard 512KB cap on BOTH the compressed and decompressed size, so a gzip bomb can't blow past it. Shared by the two untrusted-input lanes (EventsApp, IngestApp), which differ only in the response they build from the error symbol.
Constant Summary collapse
- MAX_BODY_SIZE =
512 KB
524_288- ERRORS =
error symbol => [http_status, message]
{ too_large: [413, "request body too large"], bad_gzip: [400, "invalid gzip encoding"] }.freeze
Class Method Summary collapse
-
.read(env) ⇒ Object
[body, nil] on success, or [nil, :too_large | :bad_gzip] on failure.
Class Method Details
.read(env) ⇒ Object
[body, nil] on success, or [nil, :too_large | :bad_gzip] on failure.
24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 |
# File 'lib/sentiero/web/body_reader.rb', line 24 def read(env) raw = env["rack.input"].read(MAX_BODY_SIZE + 1) || "" env["rack.input"].rewind if env["rack.input"].respond_to?(:rewind) return [nil, :too_large] if raw.bytesize > MAX_BODY_SIZE if env["HTTP_CONTENT_ENCODING"]&.downcase == "gzip" begin gz = Zlib::GzipReader.new(StringIO.new(raw)) raw = gz.read(MAX_BODY_SIZE + 1) || "" gz.close rescue Zlib::GzipFile::Error return [nil, :bad_gzip] end return [nil, :too_large] if raw.bytesize > MAX_BODY_SIZE end [raw, nil] end |