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

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