Skip to content

Commit

Permalink
Add general Rack::BadRequest. (#2019)
Browse files Browse the repository at this point in the history
Used to communicate a class of exceptions that represent 400 Bad Request
semantics.
  • Loading branch information
ioquatix committed Jan 20, 2023
1 parent 54368a0 commit 723b538
Show file tree
Hide file tree
Showing 7 changed files with 40 additions and 8 deletions.
4 changes: 4 additions & 0 deletions CHANGELOG.md
Expand Up @@ -8,6 +8,10 @@ All notable changes to this project will be documented in this file. For info on

- `rack.input` is now optional. ([#1997](https://github.com/rack/rack/pull/1997), [@ioquatix])

### Changed

- Improved handling of multipart requests. `rack.input` is now optional, and if missing, will raise an error which includes `module Rack::BadRequest`. Several other exceptions also include this module. ([#1997](https://github.com/rack/rack/pull/1997), [@ioquatix])

## [3.0.3] - 2022-12-07

### Fixed
Expand Down
1 change: 1 addition & 0 deletions lib/rack.rb
Expand Up @@ -15,6 +15,7 @@
require_relative 'rack/constants'

module Rack
autoload :BadRequest, "rack/bad_request"
autoload :Builder, "rack/builder"
autoload :BodyProxy, "rack/body_proxy"
autoload :Cascade, "rack/cascade"
Expand Down
6 changes: 6 additions & 0 deletions lib/rack/bad_request.rb
@@ -0,0 +1,6 @@
module Rack
# Represents a 400 Bad Request error when input data fails to meet the
# requirements.
module BadRequest
end
end
3 changes: 3 additions & 0 deletions lib/rack/multipart.rb
Expand Up @@ -6,6 +6,8 @@
require_relative 'multipart/parser'
require_relative 'multipart/generator'

require_relative 'bad_request'

module Rack
# A multipart form data parser, adapted from IOWA.
#
Expand All @@ -14,6 +16,7 @@ module Multipart
MULTIPART_BOUNDARY = "AaB03x"

class MissingInputError < StandardError
include BadRequest
end

class << self
Expand Down
18 changes: 14 additions & 4 deletions lib/rack/multipart/parser.rb
Expand Up @@ -3,18 +3,28 @@
require 'strscan'

require_relative '../utils'
require_relative '../bad_request'

module Rack
module Multipart
class MultipartPartLimitError < Errno::EMFILE; end
class MultipartPartLimitError < Errno::EMFILE
include BadRequest
end

# Use specific error class when parsing multipart request
# that ends early.
class EmptyContentError < ::EOFError; end
class EmptyContentError < ::EOFError
include BadRequest
end

# Base class for multipart exceptions that do not subclass from
# other exception classes for backwards compatibility.
class Error < StandardError; end
class BoundaryTooLongError < StandardError
include BadRequest
end

# Prefer to use the BoundaryTooLongError class or Rack::BadRequest.
Error = BoundaryTooLongError

EOL = "\r\n"
MULTIPART = %r|\Amultipart/.*boundary=\"?([^\";,]+)\"?|ni
Expand Down Expand Up @@ -96,7 +106,7 @@ def self.parse(io, content_length, content_type, tmpfile, bufsize, qp)
if boundary.length > 70
# RFC 1521 Section 7.2.1 imposes a 70 character maximum for the boundary.
# Most clients use no more than 55 characters.
raise Error, "multipart boundary size too large (#{boundary.length} characters)"
raise BoundaryTooLongError, "multipart boundary size too large (#{boundary.length} characters)"
end

io = BoundedIO.new(io, content_length) if content_length
Expand Down
14 changes: 11 additions & 3 deletions lib/rack/query_parser.rb
@@ -1,22 +1,30 @@
# frozen_string_literal: true

require_relative 'bad_request'

module Rack
class QueryParser
DEFAULT_SEP = /[&] */n
COMMON_SEP = { ";" => /[;] */n, ";," => /[;,] */n, "&" => /[&] */n }

# ParameterTypeError is the error that is raised when incoming structural
# parameters (parsed by parse_nested_query) contain conflicting types.
class ParameterTypeError < TypeError; end
class ParameterTypeError < TypeError
include BadRequest
end

# InvalidParameterError is the error that is raised when incoming structural
# parameters (parsed by parse_nested_query) contain invalid format or byte
# sequence.
class InvalidParameterError < ArgumentError; end
class InvalidParameterError < ArgumentError
include BadRequest
end

# ParamsTooDeepError is the error that is raised when params are recursively
# nested over the specified limit.
class ParamsTooDeepError < RangeError; end
class ParamsTooDeepError < RangeError
include BadRequest
end

def self.make_default(param_depth_limit)
new Params, param_depth_limit
Expand Down
2 changes: 1 addition & 1 deletion test/spec_multipart.rb
Expand Up @@ -38,7 +38,7 @@ def multipart_file(name)
env = Rack::MockRequest.env_for("/", multipart_fixture(:content_type_and_no_filename, "A"*71))
lambda {
Rack::Multipart.parse_multipart(env)
}.must_raise Rack::Multipart::Error
}.must_raise Rack::Multipart::BoundaryTooLongError
end

it "raises a bad request exception if no body is given but content type indicates a multipart body" do
Expand Down

0 comments on commit 723b538

Please sign in to comment.