Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add general Rack::BadRequest. #2019

Merged
merged 1 commit into from Jan 20, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
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