Repository: ruby-grape/grape
Pull request #2554: Remove Grape::Http::Headers
Author: login: ericproulx
Created: 2025-04-05T14:01:27Z | Merged: 2025-04-10T12:24:51Z

This PR removes `Grape::Http::Headers`. Since most constants `HTTP_` were just literal string and Grape's uses `#frozen_string_literal: true`, it made sense to just use the literal string wherever needed. Here's a list of notable changes:

- `Grape::Http::Headers::SUPPORTED_METHODS` has been moved to `Grape` module.
- `Grape::Http::Headers::HTTP_HEADERS` has been moved to `Grape::Request` and its now called `KNOWN_HEADERS`. The last has been revisited to reflect Rack 3's [KNOWN_HEADERS](https://github.com/rack/rack/blob/4f15e7b814922af79605be4b02c5b7c3044ba206/lib/rack/headers.rb#L9). Its not an exact copy. Grape's version has more.
- `Grape::Util::Lazy::Object` no longer exists. Solely used by `Grape::Http::Headers::HTTP_HEADERS`
- `Grape::Http::Headers.find_supported_method` no long exists. It wasn't used.
- Removes `to_s` when calling `headers` since its not just a plain `{}` but a `Grape::Util::Headers`. Fix #2334 
- Closes #2511


Linked issue #2334: Grape allows invalid headers to be set.
Follow up from <https://github.com/socketry/protocol-rack/issues/2#issuecomment-1577206428>.

The following implementation allows non-string header values.

https://github.com/ruby-grape/grape/blob/d1dfdccca242e00d4d88064a013f92e89a76dbd2/lib/grape/dsl/headers.rb#L13

Technically, all headers should be strings, according to the rack spec.

```ruby
header "x-foo", 123
```

I'm not sure if we should change this. I see several options:

- Emit a warning if it's not a string.
- Convert values to a string.
- Do nothing.
- Later on, map `@header` key values to string values, (or array of string values, allowed by Rack 3+).
Linked issue comments: user: login: dblock
created_at: 2023-06-06T15:41:25Z
body: For Grape users, is the real issue is that it works in Grape with Rack 2.x and not 3.x causing a `NoMethodError: undefined method `split' for 2:Integer`? If so, I think we should do nothing and document that upgrading to Rack 3 causes this. We could error early with "rack 3 doesn't support non-string values", too.
author_association: MEMBER
user: login: dblock
created_at: 2023-06-06T15:46:35Z
body: Other breaking changes with Rack 3, #2298.
author_association: MEMBER
user: login: ioquatix
created_at: 2023-06-06T22:29:57Z
body: No, it's nothing to do with Rack 3, it's always been invalid, even Rack 2 spec does not allow non-string header values.
author_association: CONTRIBUTOR
user: login: dblock
created_at: 2023-06-07T17:27:02Z
body: But it works for users today, except when otherwise (described in https://github.com/socketry/protocol-rack/issues/2). I think Grape should adhere to spec. I like the option of doing `.to_s` on header values, because it's backwards-compatible, but we should look at whether any specs break with that.
author_association: MEMBER
user: login: ioquatix
created_at: 2023-06-07T22:33:11Z
body: If you put `Rack::Lint` in front of the apps (e.g. during testing/CI) it will fail.

I think you should encourage people to use `Rack::Lint` behind Grape in CI. It will report the problem.
author_association: CONTRIBUTOR
user: login: ericproulx
created_at: 2025-02-26T20:19:54Z
body: https://github.com/ruby-grape/grape/pull/2511#issuecomment-2686097022
author_association: CONTRIBUTOR
user: login: ioquatix
created_at: 2025-04-10T19:56:55Z
body: This looks like a step in the right direction, but I still recommend (1) Introducing `Rack::Lint` into tests and (2) using lower case header names.
author_association: CONTRIBUTOR
user: login: dblock
created_at: 2025-04-10T22:45:02Z
body: @ericproulx are you taking ^? Otherwise open an issue?
author_association: MEMBER
user: login: ericproulx
created_at: 2025-04-12T12:59:12Z
body: > [@ericproulx](https://github.com/ericproulx) are you taking ^? Otherwise open an issue?

Yeah, I do have something for the linting.
author_association: CONTRIBUTOR

Diff:
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 478a6b4d5..e6b495d2f 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -9,6 +9,7 @@
 * [#2540](https://github.com/ruby-grape/grape/pull/2540): Introduce Params builder with symbolized short name - [@ericproulx](https://github.com/ericproulx).
 * [#2550](https://github.com/ruby-grape/grape/pull/2550): Drop ActiveSupport 6.0 - [@ericproulx](https://github.com/ericproulx).
 * [#2549](https://github.com/ruby-grape/grape/pull/2549): Delegate cookies management to `Grape::Request` - [@ericproulx](https://github.com/ericproulx).
+* [#2554](https://github.com/ruby-grape/grape/pull/2554): Remove `Grape::Http::Headers` and `Grape::Util::Lazy::Object` - [@ericproulx](https://github.com/ericproulx).
 * Your contribution here.
 
 #### Fixes
diff --git a/UPGRADING.md b/UPGRADING.md
index 9e7b8ade2..2ace6622d 100644
--- a/UPGRADING.md
+++ b/UPGRADING.md
@@ -1,6 +1,18 @@
 Upgrading Grape
 ===============
 
+### Upgrading to >= 2.4.0
+
+#### Grape::Http::Headers, Grape::Util::Lazy::Object
+
+Both have been removed. See [2554](https://github.com/ruby-grape/grape/pull/2554).
+Here are the notable changes:
+
+- Constants like `HTTP_ACCEPT` have been replaced by their literal value.
+- `SUPPORTED_METHODS` has been moved to `Grape` module.
+- `HTTP_HEADERS` has been moved to `Grape::Request` and renamed `KNOWN_HEADERS`. The last has been refreshed with new headers, and it's not lazy anymore.
+- `SUPPORTED_METHODS_WITHOUT_OPTIONS` and `find_supported_method` have been removed.
+
 ### Grape::Middleware::Base
 
 - Constant `TEXT_HTML` has been removed in favor of using literal string 'text/html'.
@@ -30,8 +42,6 @@ For the non provided case, 1.0 was automatically assigned and in a case of multi
 Excluding the [header versioning strategy](https://github.com/ruby-grape/grape?tab=readme-ov-file#header), whenever a media type with the [vendor tree](https://datatracker.ietf.org/doc/html/rfc6838#section-3.2) leading facet `vnd.` like `application/vnd.api+json` was provided, Grape would also consider its closest generic when negotiating. In that case, `application/json` was added to the negotiation. Now, it will just consider the provided media types without considering any closest generics, and you'll need to [register](https://github.com/ruby-grape/grape?tab=readme-ov-file#api-formats) it.
 You can find the official vendor tree registrations on [IANA](https://www.iana.org/assignments/media-types/media-types.xhtml)
 
-### Upgrading to >= 2.4.0
-
 #### Custom Validators
 
 If you now receive an error of `'Grape::Validations.require_validator': unknown validator: your_custom_validation (Grape::Exceptions::UnknownValidator)` after upgrading to 2.4.0 then you will need to ensure that you require the `your_custom_validation` file before your Grape API code is loaded.
diff --git a/lib/grape.rb b/lib/grape.rb
index 91d3f3f8a..a1e6f511c 100644
--- a/lib/grape.rb
+++ b/lib/grape.rb
@@ -59,6 +59,16 @@
 module Grape
   include ActiveSupport::Configurable
 
+  HTTP_SUPPORTED_METHODS = [
+    Rack::GET,
+    Rack::POST,
+    Rack::PUT,
+    Rack::PATCH,
+    Rack::DELETE,
+    Rack::HEAD,
+    Rack::OPTIONS
+  ].freeze
+
   def self.deprecator
     @deprecator ||= ActiveSupport::Deprecation.new('2.0', 'Grape')
   end
diff --git a/lib/grape/api/instance.rb b/lib/grape/api/instance.rb
index facd0f9f9..aa24263a6 100644
--- a/lib/grape/api/instance.rb
+++ b/lib/grape/api/instance.rb
@@ -164,7 +164,7 @@ def call(env)
         status, headers, response = @router.call(env)
         unless cascade?
           headers = Grape::Util::Header.new.merge(headers)
-          headers.delete(Grape::Http::Headers::X_CASCADE)
+          headers.delete('X-Cascade')
         end
 
         [status, headers, response]
diff --git a/lib/grape/dsl/headers.rb b/lib/grape/dsl/headers.rb
index a02bdd588..4c193364f 100644
--- a/lib/grape/dsl/headers.rb
+++ b/lib/grape/dsl/headers.rb
@@ -10,7 +10,7 @@ module Headers
       # 4. Delete a specifc header key-value pair
       def header(key = nil, val = nil)
         if key
-          val ? header[key.to_s] = val : header.delete(key.to_s)
+          val ? header[key] = val : header.delete(key)
         else
           @header ||= Grape::Util::Header.new
         end
diff --git a/lib/grape/dsl/inside_route.rb b/lib/grape/dsl/inside_route.rb
index c5861cc92..2d7568afa 100644
--- a/lib/grape/dsl/inside_route.rb
+++ b/lib/grape/dsl/inside_route.rb
@@ -213,7 +213,7 @@ def redirect(url, permanent: false, body: nil)
           status 302
           body_message ||= "This resource has been moved temporarily to #{url}."
         end
-        header Grape::Http::Headers::LOCATION, url
+        header 'Location', url
         content_type 'text/plain'
         body body_message
       end
@@ -330,7 +330,7 @@ def stream(value = nil)
         return if value.nil? && @stream.nil?
 
         header Rack::CONTENT_LENGTH, nil
-        header Grape::Http::Headers::TRANSFER_ENCODING, nil
+        header 'Transfer-Encoding', nil
         header Rack::CACHE_CONTROL, 'no-cache' # Skips ETag generation (reading the response up front)
         if value.is_a?(String)
           file_body = Grape::ServeStream::FileBody.new(value)
@@ -439,7 +439,7 @@ def entity_representation_for(entity_class, object, options)
       end
 
       def http_version
-        env.fetch(Grape::Http::Headers::HTTP_VERSION) { env[Rack::SERVER_PROTOCOL] }
+        env.fetch('HTTP_VERSION') { env[Rack::SERVER_PROTOCOL] }
       end
 
       def api_format(format)
diff --git a/lib/grape/dsl/routing.rb b/lib/grape/dsl/routing.rb
index c2738f933..8c32db364 100644
--- a/lib/grape/dsl/routing.rb
+++ b/lib/grape/dsl/routing.rb
@@ -158,7 +158,7 @@ def route(methods, paths = ['/'], route_options = {}, &block)
           reset_validations!
         end
 
-        Grape::Http::Headers::SUPPORTED_METHODS.each do |supported_method|
+        Grape::HTTP_SUPPORTED_METHODS.each do |supported_method|
           define_method supported_method.downcase do |*args, &block|
             options = args.extract_options!
             paths = args.first || ['/']
diff --git a/lib/grape/endpoint.rb b/lib/grape/endpoint.rb
index a97181fe3..2e5136fda 100644
--- a/lib/grape/endpoint.rb
+++ b/lib/grape/endpoint.rb
@@ -257,7 +257,7 @@ def run
             header['Allow'] = env[Grape::Env::GRAPE_ALLOWED_METHODS].join(', ')
             raise Grape::Exceptions::MethodNotAllowed.new(header) unless options?
 
-            header Grape::Http::Headers::ALLOW, header['Allow']
+            header 'Allow', header['Allow']
             response_object = ''
             status 204
           else
diff --git a/lib/grape/http/headers.rb b/lib/grape/http/headers.rb
deleted file mode 100644
index eb4d38915..000000000
--- a/lib/grape/http/headers.rb
+++ /dev/null
@@ -1,56 +0,0 @@
-# frozen_string_literal: true
-
-module Grape
-  module Http
-    module Headers
-      HTTP_ACCEPT_VERSION = 'HTTP_ACCEPT_VERSION'
-      HTTP_ACCEPT = 'HTTP_ACCEPT'
-      HTTP_TRANSFER_ENCODING = 'HTTP_TRANSFER_ENCODING'
-      HTTP_VERSION = 'HTTP_VERSION'
-
-      ALLOW = 'Allow'
-      LOCATION = 'Location'
-      X_CASCADE = 'X-Cascade'
-      TRANSFER_ENCODING = 'Transfer-Encoding'
-
-      SUPPORTED_METHODS = [
-        Rack::GET,
-        Rack::POST,
-        Rack::PUT,
-        Rack::PATCH,
-        Rack::DELETE,
-        Rack::HEAD,
-        Rack::OPTIONS
-      ].freeze
-
-      SUPPORTED_METHODS_WITHOUT_OPTIONS = (SUPPORTED_METHODS - [Rack::OPTIONS]).freeze
-
-      HTTP_HEADERS = Grape::Util::Lazy::Object.new do
-        common_http_headers = %w[
-          Version
-          Host
-          Connection
-          Cache-Control
-          Dnt
-          Upgrade-Insecure-Requests
-          User-Agent
-          Sec-Fetch-Dest
-          Accept
-          Sec-Fetch-Site
-          Sec-Fetch-Mode
-          Sec-Fetch-User
-          Accept-Encoding
-          Accept-Language
-          Cookie
-        ].freeze
-        common_http_headers.each_with_object({}) do |header, response|
-          response["HTTP_#{header.upcase.tr('-', '_')}"] = header
-        end.freeze
-      end
-
-      def self.find_supported_method(route_method)
-        Grape::Http::Headers::SUPPORTED_METHODS.detect { |supported_method| supported_method.casecmp(route_method).zero? }
-      end
-    end
-  end
-end
diff --git a/lib/grape/middleware/formatter.rb b/lib/grape/middleware/formatter.rb
index 73b12b454..359792a40 100644
--- a/lib/grape/middleware/formatter.rb
+++ b/lib/grape/middleware/formatter.rb
@@ -119,7 +119,7 @@ def read_body_input?
         (rack_request.post? || rack_request.put? || rack_request.patch? || rack_request.delete?) &&
           !(rack_request.form_data? && rack_request.content_type) &&
           !rack_request.parseable_data? &&
-          (rack_request.content_length.to_i.positive? || rack_request.env[Grape::Http::Headers::HTTP_TRANSFER_ENCODING] == 'chunked')
+          (rack_request.content_length.to_i.positive? || rack_request.env['HTTP_TRANSFER_ENCODING'] == 'chunked')
       end
 
       def negotiate_content_type
@@ -141,7 +141,7 @@ def format_from_extension
       end
 
       def format_from_header
-        accept_header = env[Grape::Http::Headers::HTTP_ACCEPT].try(:scrub)
+        accept_header = env['HTTP_ACCEPT'].try(:scrub)
         return if accept_header.blank?
 
         media_type = Rack::Utils.best_q_match(accept_header, mime_types.keys)
diff --git a/lib/grape/middleware/versioner/accept_version_header.rb b/lib/grape/middleware/versioner/accept_version_header.rb
index aa7a8b353..1d24388f1 100644
--- a/lib/grape/middleware/versioner/accept_version_header.rb
+++ b/lib/grape/middleware/versioner/accept_version_header.rb
@@ -18,9 +18,7 @@ module Versioner
       # route.
       class AcceptVersionHeader < Base
         def before
-          potential_version = env[Grape::Http::Headers::HTTP_ACCEPT_VERSION]
-          potential_version = potential_version.scrub unless potential_version.nil?
-
+          potential_version = env['HTTP_ACCEPT_VERSION'].try(:scrub)
           not_acceptable!('Accept-Version header must be set.') if strict? && potential_version.blank?
 
           return if potential_version.blank?
diff --git a/lib/grape/middleware/versioner/base.rb b/lib/grape/middleware/versioner/base.rb
index 68604f14e..4cd18a8c0 100644
--- a/lib/grape/middleware/versioner/base.rb
+++ b/lib/grape/middleware/versioner/base.rb
@@ -66,7 +66,7 @@ def vendor
         end
 
         def error_headers
-          cascade? ? { Grape::Http::Headers::X_CASCADE => 'pass' } : {}
+          cascade? ? { 'X-Cascade' => 'pass' } : {}
         end
 
         def potential_version_match?(potential_version)
@@ -74,7 +74,7 @@ def potential_version_match?(potential_version)
         end
 
         def version_not_found!
-          throw :error, status: 404, message: '404 API Version Not Found', headers: { Grape::Http::Headers::X_CASCADE => 'pass' }
+          throw :error, status: 404, message: '404 API Version Not Found', headers: { 'X-Cascade' => 'pass' }
         end
       end
     end
diff --git a/lib/grape/middleware/versioner/header.rb b/lib/grape/middleware/versioner/header.rb
index a34a80fc7..5470fe170 100644
--- a/lib/grape/middleware/versioner/header.rb
+++ b/lib/grape/middleware/versioner/header.rb
@@ -49,7 +49,7 @@ def match_best_quality_media_type!
         end
 
         def accept_header
-          env[Grape::Http::Headers::HTTP_ACCEPT]
+          env['HTTP_ACCEPT']
         end
 
         def strict_header_checks!
diff --git a/lib/grape/request.rb b/lib/grape/request.rb
index 45ee801e7..06c389b75 100644
--- a/lib/grape/request.rb
+++ b/lib/grape/request.rb
@@ -3,7 +3,139 @@
 module Grape
   class Request < Rack::Request
     DEFAULT_PARAMS_BUILDER = :hash_with_indifferent_access
-    HTTP_PREFIX = 'HTTP_'
+    # Based on rack 3 KNOWN_HEADERS
+    # https://github.com/rack/rack/blob/4f15e7b814922af79605be4b02c5b7c3044ba206/lib/rack/headers.rb#L10
+
+    KNOWN_HEADERS = %w[
+      Accept
+      Accept-CH
+      Accept-Encoding
+      Accept-Language
+      Accept-Patch
+      Accept-Ranges
+      Accept-Version
+      Access-Control-Allow-Credentials
+      Access-Control-Allow-Headers
+      Access-Control-Allow-Methods
+      Access-Control-Allow-Origin
+      Access-Control-Expose-Headers
+      Access-Control-Max-Age
+      Age
+      Allow
+      Alt-Svc
+      Authorization
+      Cache-Control
+      Client-Ip
+      Connection
+      Content-Disposition
+      Content-Encoding
+      Content-Language
+      Content-Length
+      Content-Location
+      Content-MD5
+      Content-Range
+      Content-Security-Policy
+      Content-Security-Policy-Report-Only
+      Content-Type
+      Cookie
+      Date
+      Delta-Base
+      Dnt
+      ETag
+      Expect-CT
+      Expires
+      Feature-Policy
+      Forwarded
+      Host
+      If-Modified-Since
+      If-None-Match
+      IM
+      Last-Modified
+      Link
+      Location
+      NEL
+      P3P
+      Permissions-Policy
+      Pragma
+      Preference-Applied
+      Proxy-Authenticate
+      Public-Key-Pins
+      Range
+      Referer
+      Referrer-Policy
+      Refresh
+      Report-To
+      Retry-After
+      Sec-Fetch-Dest
+      Sec-Fetch-Mode
+      Sec-Fetch-Site
+      Sec-Fetch-User
+      Server
+      Set-Cookie
+      Status
+      Strict-Transport-Security
+      Timing-Allow-Origin
+      Tk
+      Trailer
+      Transfer-Encoding
+      Upgrade
+      Upgrade-Insecure-Requests
+      User-Agent
+      Vary
+      Version
+      Via
+      Warning
+      WWW-Authenticate
+      X-Accel-Buffering
+      X-Accel-Charset
+      X-Accel-Expires
+      X-Accel-Limit-Rate
+      X-Accel-Mapping
+      X-Accel-Redirect
+      X-Access-Token
+      X-Auth-Request-Access-Token
+      X-Auth-Request-Email
+      X-Auth-Request-Groups
+      X-Auth-Request-Preferred-Username
+      X-Auth-Request-Redirect
+      X-Auth-Request-Token
+      X-Auth-Request-User
+      X-Cascade
+      X-Client-Ip
+      X-Content-Duration
+      X-Content-Security-Policy
+      X-Content-Type-Options
+      X-Correlation-Id
+      X-Download-Options
+      X-Forwarded-Access-Token
+      X-Forwarded-Email
+      X-Forwarded-For
+      X-Forwarded-Groups
+      X-Forwarded-Host
+      X-Forwarded-Port
+      X-Forwarded-Preferred-Username
+      X-Forwarded-Proto
+      X-Forwarded-Scheme
+      X-Forwarded-Ssl
+      X-Forwarded-Uri
+      X-Forwarded-User
+      X-Frame-Options
+      X-HTTP-Method-Override
+      X-Permitted-Cross-Domain-Policies
+      X-Powered-By
+      X-Real-IP
+      X-Redirect-By
+      X-Request-Id
+      X-Requested-With
+      X-Runtime
+      X-Sendfile
+      X-Sendfile-Type
+      X-UA-Compatible
+      X-WebKit-CS
+      X-XSS-Protection
+    ].each_with_object({}) do |header, response|
+      response["HTTP_#{header.upcase.tr('-', '_')}"] = header
+    end.freeze
 
     alias rack_params params
     alias rack_cookies cookies
@@ -49,15 +181,11 @@ def make_params
 
     def build_headers
       each_header.with_object(Grape::Util::Header.new) do |(k, v), headers|
-        next unless k.start_with? HTTP_PREFIX
+        next unless k.start_with? 'HTTP_'
 
-        transformed_header = Grape::Http::Headers::HTTP_HEADERS[k] || transform_header(k)
+        transformed_header = KNOWN_HEADERS.fetch(k) { -k[5..].tr('_', '-').downcase }
         headers[transformed_header] = v
       end
     end
-
-    def transform_header(header)
-      -header[5..].tr('_', '-').downcase
-    end
   end
 end
diff --git a/lib/grape/router.rb b/lib/grape/router.rb
index 99065b6e4..6a9e3f5df 100644
--- a/lib/grape/router.rb
+++ b/lib/grape/router.rb
@@ -42,7 +42,7 @@ def compile!
 
       @union = Regexp.union(@neutral_regexes)
       @neutral_regexes = nil
-      (Grape::Http::Headers::SUPPORTED_METHODS + ['*']).each do |method|
+      (Grape::HTTP_SUPPORTED_METHODS + ['*']).each do |method|
         next unless map.key?(method)
 
         routes = map[method]
@@ -156,7 +156,7 @@ def with_optimization
     end
 
     def default_response
-      headers = Grape::Util::Header.new.merge(Grape::Http::Headers::X_CASCADE => 'pass')
+      headers = Grape::Util::Header.new.merge('X-Cascade' => 'pass')
       [404, headers, ['404 Not Found']]
     end
 
@@ -180,7 +180,7 @@ def prepare_env_from_route(env, route)
     end
 
     def cascade?(response)
-      response && response[1][Grape::Http::Headers::X_CASCADE] == 'pass'
+      response && response[1]['X-Cascade'] == 'pass'
     end
 
     def string_for(input)
diff --git a/lib/grape/router/route.rb b/lib/grape/router/route.rb
index 48599610c..64105be9c 100644
--- a/lib/grape/router/route.rb
+++ b/lib/grape/router/route.rb
@@ -55,7 +55,7 @@ def params_without_input
 
       def upcase_method(method)
         method_s = method.to_s
-        Grape::Http::Headers::SUPPORTED_METHODS.detect { |m| m.casecmp(method_s).zero? } || method_s.upcase
+        Grape::HTTP_SUPPORTED_METHODS.detect { |m| m.casecmp(method_s).zero? } || method_s.upcase
       end
     end
   end
diff --git a/lib/grape/util/lazy/object.rb b/lib/grape/util/lazy/object.rb
deleted file mode 100644
index 6c10dadfc..000000000
--- a/lib/grape/util/lazy/object.rb
+++ /dev/null
@@ -1,45 +0,0 @@
-# frozen_string_literal: true
-
-# Based on https://github.com/HornsAndHooves/lazy_object
-
-module Grape
-  module Util
-    module Lazy
-      class Object < BasicObject
-        attr_reader :callable
-
-        def initialize(&callable)
-          @callable = callable
-        end
-
-        def __target_object__
-          @__target_object__ ||= callable.call
-        end
-
-        def ==(other)
-          __target_object__ == other
-        end
-
-        def !=(other)
-          __target_object__ != other
-        end
-
-        def !
-          !__target_object__
-        end
-
-        def method_missing(method_name, *args, &block)
-          if __target_object__.respond_to?(method_name)
-            __target_object__.send(method_name, *args, &block)
-          else
-            super
-          end
-        end
-
-        def respond_to_missing?(method_name, include_priv = false)
-          __target_object__.respond_to?(method_name, include_priv)
-        end
-      end
-    end
-  end
-end
diff --git a/spec/grape/api/patch_method_helpers_spec.rb b/spec/grape/api/patch_method_helpers_spec.rb
index f91f028a5..ad0a162ba 100644
--- a/spec/grape/api/patch_method_helpers_spec.rb
+++ b/spec/grape/api/patch_method_helpers_spec.rb
@@ -49,12 +49,12 @@ def app
 
   context 'patch' do
     it 'public' do
-      patch '/', {}, Grape::Http::Headers::HTTP_ACCEPT => 'application/vnd.grape-public-v1+json'
+      patch '/', {}, 'HTTP_ACCEPT' => 'application/vnd.grape-public-v1+json'
       expect(last_response.status).to eq 405
     end
 
     it 'private' do
-      patch '/', {}, Grape::Http::Headers::HTTP_ACCEPT => 'application/vnd.grape-private-v1+json'
+      patch '/', {}, 'HTTP_ACCEPT' => 'application/vnd.grape-private-v1+json'
       expect(last_response.status).to eq 405
     end
 
@@ -66,13 +66,13 @@ def app
 
   context 'default' do
     it 'public' do
-      get '/', {}, Grape::Http::Headers::HTTP_ACCEPT => 'application/vnd.grape-public-v1+json'
+      get '/', {}, 'HTTP_ACCEPT' => 'application/vnd.grape-public-v1+json'
       expect(last_response.status).to eq 200
       expect(last_response.body).to eq({ ok: 'public' }.to_json)
     end
 
     it 'private' do
-      get '/', {}, Grape::Http::Headers::HTTP_ACCEPT => 'application/vnd.grape-private-v1+json'
+      get '/', {}, 'HTTP_ACCEPT' => 'application/vnd.grape-private-v1+json'
       expect(last_response.status).to eq 200
       expect(last_response.body).to eq({ ok: 'private' }.to_json)
     end
diff --git a/spec/grape/api_spec.rb b/spec/grape/api_spec.rb
index 013e0741b..f16b31ee2 100644
--- a/spec/grape/api_spec.rb
+++ b/spec/grape/api_spec.rb
@@ -510,7 +510,7 @@ def to_txt
               subject.send(verb) do
                 env[Grape::Env::API_REQUEST_INPUT]
               end
-              send verb, '/', Grape::Json.dump(object), 'CONTENT_TYPE' => 'application/json', Grape::Http::Headers::HTTP_TRANSFER_ENCODING => 'chunked'
+              send verb, '/', Grape::Json.dump(object), 'CONTENT_TYPE' => 'application/json', 'HTTP_TRANSFER_ENCODING' => 'chunked'
               expect(last_response.status).to eq(verb == :post ? 201 : 200)
               expect(last_response.body).to eql Grape::Json.dump(object).to_json
             end
@@ -1307,7 +1307,7 @@ def to_txt
       expect(last_response.content_type).to eq('text/plain')
       expect(last_response.content_length).to be_nil
       expect(last_response.headers[Rack::CACHE_CONTROL]).to eq('no-cache')
-      expect(last_response.headers[Grape::Http::Headers::TRANSFER_ENCODING]).to eq('chunked')
+      expect(last_response.headers['Transfer-Encoding']).to eq('chunked')
 
       expect(last_response.body).to eq("c\r\nThis is some\r\nd\r\n file content\r\n0\r\n\r\n")
     end
@@ -2886,7 +2886,7 @@ def self.call(message, _backtrace, _options, _env, _original_exception)
       end
 
       it 'uses custom formatter' do
-        get '/simple.custom', Grape::Http::Headers::HTTP_ACCEPT => 'application/custom'
+        get '/simple.custom', 'HTTP_ACCEPT' => 'application/custom'
         expect(last_response.body).to eql '{"custom_formatter":"hash"}'
       end
     end
@@ -2915,7 +2915,7 @@ def self.call(object, _env)
       end
 
       it 'uses custom formatter' do
-        get '/simple.custom', Grape::Http::Headers::HTTP_ACCEPT => 'application/custom'
+        get '/simple.custom', 'HTTP_ACCEPT' => 'application/custom'
         expect(last_response.body).to eql '{"custom_formatter":"hash"}'
       end
     end
@@ -3558,7 +3558,7 @@ def self.call(object, _env)
       it 'is able to cascade' do
         subject.mount lambda { |env|
           headers = {}
-          headers[Grape::Http::Headers::X_CASCADE] == 'pass' if env[Rack::PATH_INFO].exclude?('boo')
+          headers['X-Cascade'] == 'pass' if env[Rack::PATH_INFO].exclude?('boo')
           [200, headers, ['Farfegnugen']]
         } => '/'
 
@@ -4058,7 +4058,7 @@ def my_method
       end
 
       it 'forces txt from a non-accepting header' do
-        get '/meaning_of_life', {}, Grape::Http::Headers::HTTP_ACCEPT => 'application/json'
+        get '/meaning_of_life', {}, 'HTTP_ACCEPT' => 'application/json'
         expect(last_response.body).to eq({ meaning_of_life: 42 }.to_s)
       end
     end
@@ -4087,7 +4087,7 @@ def my_method
       end
 
       it 'forces txt from a non-accepting header' do
-        get '/meaning_of_life', {}, Grape::Http::Headers::HTTP_ACCEPT => 'application/json'
+        get '/meaning_of_life', {}, 'HTTP_ACCEPT' => 'application/json'
         expect(last_response.body).to eq({ meaning_of_life: 42 }.to_s)
       end
     end
@@ -4112,7 +4112,7 @@ def my_method
       end
 
       it 'forces json from a non-accepting header' do
-        get '/meaning_of_life', {}, Grape::Http::Headers::HTTP_ACCEPT => 'text/html'
+        get '/meaning_of_life', {}, 'HTTP_ACCEPT' => 'text/html'
         expect(last_response.body).to eq({ meaning_of_life: 42 }.to_json)
       end
 
@@ -4336,14 +4336,14 @@ def before
         subject.version 'v1', using: :path, cascade: true
         get '/v1/hello'
         expect(last_response).to be_not_found
-        expect(last_response.headers[Grape::Http::Headers::X_CASCADE]).to eq('pass')
+        expect(last_response.headers['X-Cascade']).to eq('pass')
       end
 
       it 'does not cascade' do
         subject.version 'v2', using: :path, cascade: false
         get '/v2/hello'
         expect(last_response).to be_not_found
-        expect(last_response.headers.keys).not_to include Grape::Http::Headers::X_CASCADE
+        expect(last_response.headers.keys).not_to include 'X-Cascade'
       end
     end
 
@@ -4352,14 +4352,14 @@ def before
         subject.cascade true
         get '/hello'
         expect(last_response).to be_not_found
-        expect(last_response.headers[Grape::Http::Headers::X_CASCADE]).to eq('pass')
+        expect(last_response.headers['X-Cascade']).to eq('pass')
       end
 
       it 'does not cascade' do
         subject.cascade false
         get '/hello'
         expect(last_response).to be_not_found
-        expect(last_response.headers.keys).not_to include Grape::Http::Headers::X_CASCADE
+        expect(last_response.headers.keys).not_to include 'X-Cascade'
       end
     end
   end
diff --git a/spec/grape/dsl/inside_route_spec.rb b/spec/grape/dsl/inside_route_spec.rb
index 9e72e8087..5e5b8b5d0 100644
--- a/spec/grape/dsl/inside_route_spec.rb
+++ b/spec/grape/dsl/inside_route_spec.rb
@@ -69,7 +69,7 @@ def initialize
       end
 
       it 'sets location header' do
-        expect(subject.header[Grape::Http::Headers::LOCATION]).to eq '/'
+        expect(subject.header['Location']).to eq '/'
       end
     end
 
@@ -83,7 +83,7 @@ def initialize
       end
 
       it 'sets location header' do
-        expect(subject.header[Grape::Http::Headers::LOCATION]).to eq '/'
+        expect(subject.header['Location']).to eq '/'
       end
     end
   end
@@ -205,7 +205,7 @@ def initialize
         before do
           subject.header Rack::CACHE_CONTROL, 'cache'
           subject.header Rack::CONTENT_LENGTH, 123
-          subject.header Grape::Http::Headers::TRANSFER_ENCODING, 'base64'
+          subject.header 'Transfer-Encoding', 'base64'
           subject.sendfile file_path
         end
 
@@ -217,7 +217,7 @@ def initialize
           expect(subject.header).to match(
             Rack::CACHE_CONTROL => 'cache',
             Rack::CONTENT_LENGTH => 123,
-            Grape::Http::Headers::TRANSFER_ENCODING => 'base64'
+            'Transfer-Encoding' => 'base64'
           )
         end
       end
@@ -249,7 +249,7 @@ def initialize
         before do
           subject.header Rack::CACHE_CONTROL, 'cache'
           subject.header Rack::CONTENT_LENGTH, 123
-          subject.header Grape::Http::Headers::TRANSFER_ENCODING, 'base64'
+          subject.header 'Transfer-Encoding', 'base64'
           subject.stream file_path
         end
 
@@ -272,7 +272,7 @@ def initialize
         before do
           subject.header Rack::CACHE_CONTROL, 'cache'
           subject.header Rack::CONTENT_LENGTH, 123
-          subject.header Grape::Http::Headers::TRANSFER_ENCODING, 'base64'
+          subject.header 'Transfer-Encoding', 'base64'
           subject.stream stream_object
         end
 
diff --git a/spec/grape/endpoint_spec.rb b/spec/grape/endpoint_spec.rb
index bcdf5f62e..3f98aacb6 100644
--- a/spec/grape/endpoint_spec.rb
+++ b/spec/grape/endpoint_spec.rb
@@ -1021,12 +1021,12 @@ def memoized
     end
 
     it 'result in a 406 response if they are invalid' do
-      get '/test', {}, Grape::Http::Headers::HTTP_ACCEPT => 'application/vnd.ohanapi.v1+json'
+      get '/test', {}, 'HTTP_ACCEPT' => 'application/vnd.ohanapi.v1+json'
       expect(last_response.status).to eq(406)
     end
 
     it 'result in a 406 response if they cannot be parsed' do
-      get '/test', {}, Grape::Http::Headers::HTTP_ACCEPT => 'application/vnd.ohanapi.v1+json; version=1'
+      get '/test', {}, 'HTTP_ACCEPT' => 'application/vnd.ohanapi.v1+json; version=1'
       expect(last_response.status).to eq(406)
     end
   end
diff --git a/spec/grape/exceptions/invalid_accept_header_spec.rb b/spec/grape/exceptions/invalid_accept_header_spec.rb
index a0bf11139..29884f0dd 100644
--- a/spec/grape/exceptions/invalid_accept_header_spec.rb
+++ b/spec/grape/exceptions/invalid_accept_header_spec.rb
@@ -19,7 +19,7 @@
 
   shared_examples_for 'a not-cascaded request' do
     it 'does not include the X-Cascade=pass header' do
-      expect(last_response.headers).not_to have_key(Grape::Http::Headers::X_CASCADE)
+      expect(last_response.headers).not_to have_key('X-Cascade')
     end
 
     it 'does not accept the request' do
@@ -29,7 +29,7 @@
 
   shared_examples_for 'a rescued request' do
     it 'does not include the X-Cascade=pass header' do
-      expect(last_response.headers[Grape::Http::Headers::X_CASCADE]).to be_nil
+      expect(last_response.headers['X-Cascade']).to be_nil
     end
 
     it 'does show rescue handler processing' do
@@ -56,7 +56,7 @@ def app
     end
 
     context 'that received a request with correct vendor and version' do
-      before { get '/beer', {}, Grape::Http::Headers::HTTP_ACCEPT => 'application/vnd.vendorname-v99' }
+      before { get '/beer', {}, 'HTTP_ACCEPT' => 'application/vnd.vendorname-v99' }
 
       it_behaves_like 'a valid request'
     end
@@ -64,7 +64,7 @@ def app
     context 'that receives' do
       context 'an invalid vendor in the request' do
         before do
-          get '/beer', {}, Grape::Http::Headers::HTTP_ACCEPT => 'application/vnd.invalidvendor-v99',
+          get '/beer', {}, 'HTTP_ACCEPT' => 'application/vnd.invalidvendor-v99',
                            'CONTENT_TYPE' => 'application/json'
         end
 
@@ -88,20 +88,20 @@ def app
     end
 
     context 'that received a request with correct vendor and version' do
-      before { get '/beer', {}, Grape::Http::Headers::HTTP_ACCEPT => 'application/vnd.vendorname-v99' }
+      before { get '/beer', {}, 'HTTP_ACCEPT' => 'application/vnd.vendorname-v99' }
 
       it_behaves_like 'a valid request'
     end
 
     context 'that receives' do
       context 'an invalid version in the request' do
-        before { get '/beer', {}, Grape::Http::Headers::HTTP_ACCEPT => 'application/vnd.vendorname-v77' }
+        before { get '/beer', {}, 'HTTP_ACCEPT' => 'application/vnd.vendorname-v77' }
 
         it_behaves_like 'a not-cascaded request'
       end
 
       context 'an invalid vendor in the request' do
-        before { get '/beer', {}, Grape::Http::Headers::HTTP_ACCEPT => 'application/vnd.invalidvendor-v99' }
+        before { get '/beer', {}, 'HTTP_ACCEPT' => 'application/vnd.invalidvendor-v99' }
 
         it_behaves_like 'a not-cascaded request'
       end
@@ -131,7 +131,7 @@ def app
     end
 
     context 'that received a request with correct vendor and version' do
-      before { get '/beer', {}, Grape::Http::Headers::HTTP_ACCEPT => 'application/vnd.vendorname-v99' }
+      before { get '/beer', {}, 'HTTP_ACCEPT' => 'application/vnd.vendorname-v99' }
 
       it_behaves_like 'a valid request'
     end
@@ -139,7 +139,7 @@ def app
     context 'that receives' do
       context 'an invalid vendor in the request' do
         before do
-          get '/beer', {}, Grape::Http::Headers::HTTP_ACCEPT => 'application/vnd.invalidvendor-v99',
+          get '/beer', {}, 'HTTP_ACCEPT' => 'application/vnd.invalidvendor-v99',
                            'CONTENT_TYPE' => 'application/json'
         end
 
@@ -168,20 +168,20 @@ def app
     end
 
     context 'that received a request with correct vendor and version' do
-      before { get '/beer', {}, Grape::Http::Headers::HTTP_ACCEPT => 'application/vnd.vendorname-v99' }
+      before { get '/beer', {}, 'HTTP_ACCEPT' => 'application/vnd.vendorname-v99' }
 
       it_behaves_like 'a valid request'
     end
 
     context 'that receives' do
       context 'an invalid version in the request' do
-        before { get '/beer', {}, Grape::Http::Headers::HTTP_ACCEPT => 'application/vnd.vendorname-v77' }
+        before { get '/beer', {}, 'HTTP_ACCEPT' => 'application/vnd.vendorname-v77' }
 
         it_behaves_like 'a not-cascaded request'
       end
 
       context 'an invalid vendor in the request' do
-        before { get '/beer', {}, Grape::Http::Headers::HTTP_ACCEPT => 'application/vnd.invalidvendor-v99' }
+        before { get '/beer', {}, 'HTTP_ACCEPT' => 'application/vnd.invalidvendor-v99' }
 
         it_behaves_like 'a not-cascaded request'
       end
@@ -206,7 +206,7 @@ def app
     end
 
     context 'that received a request with correct vendor and version' do
-      before { get '/beer', {}, Grape::Http::Headers::HTTP_ACCEPT => 'application/vnd.vendorname-v99' }
+      before { get '/beer', {}, 'HTTP_ACCEPT' => 'application/vnd.vendorname-v99' }
 
       it_behaves_like 'a valid request'
     end
@@ -214,7 +214,7 @@ def app
     context 'that receives' do
       context 'an invalid version in the request' do
         before do
-          get '/beer', {}, Grape::Http::Headers::HTTP_ACCEPT => 'application/vnd.vendorname-v77',
+          get '/beer', {}, 'HTTP_ACCEPT' => 'application/vnd.vendorname-v77',
                            'CONTENT_TYPE' => 'application/json'
         end
 
@@ -223,7 +223,7 @@ def app
 
       context 'an invalid vendor in the request' do
         before do
-          get '/beer', {}, Grape::Http::Headers::HTTP_ACCEPT => 'application/vnd.invalidvendor-v99',
+          get '/beer', {}, 'HTTP_ACCEPT' => 'application/vnd.invalidvendor-v99',
                            'CONTENT_TYPE' => 'application/json'
         end
 
@@ -247,20 +247,20 @@ def app
     end
 
     context 'that received a request with correct vendor and version' do
-      before { get '/beer', {}, Grape::Http::Headers::HTTP_ACCEPT => 'application/vnd.vendorname-v99' }
+      before { get '/beer', {}, 'HTTP_ACCEPT' => 'application/vnd.vendorname-v99' }
 
       it_behaves_like 'a valid request'
     end
 
     context 'that receives' do
       context 'an invalid version in the request' do
-        before { get '/beer', {}, Grape::Http::Headers::HTTP_ACCEPT => 'application/vnd.vendorname-v77' }
+        before { get '/beer', {}, 'HTTP_ACCEPT' => 'application/vnd.vendorname-v77' }
 
         it_behaves_like 'a cascaded request'
       end
 
       context 'an invalid vendor in the request' do
-        before { get '/beer', {}, Grape::Http::Headers::HTTP_ACCEPT => 'application/vnd.invalidvendor-v99' }
+        before { get '/beer', {}, 'HTTP_ACCEPT' => 'application/vnd.invalidvendor-v99' }
 
         it_behaves_like 'a cascaded request'
       end
@@ -290,7 +290,7 @@ def app
     end
 
     context 'that received a request with correct vendor and version' do
-      before { get '/beer', {}, Grape::Http::Headers::HTTP_ACCEPT => 'application/vnd.vendorname-v99' }
+      before { get '/beer', {}, 'HTTP_ACCEPT' => 'application/vnd.vendorname-v99' }
 
       it_behaves_like 'a valid request'
     end
@@ -298,7 +298,7 @@ def app
     context 'that receives' do
       context 'an invalid version in the request' do
         before do
-          get '/beer', {}, Grape::Http::Headers::HTTP_ACCEPT => 'application/vnd.vendorname-v77',
+          get '/beer', {}, 'HTTP_ACCEPT' => 'application/vnd.vendorname-v77',
                            'CONTENT_TYPE' => 'application/json'
         end
 
@@ -307,7 +307,7 @@ def app
 
       context 'an invalid vendor in the request' do
         before do
-          get '/beer', {}, Grape::Http::Headers::HTTP_ACCEPT => 'application/vnd.invalidvendor-v99',
+          get '/beer', {}, 'HTTP_ACCEPT' => 'application/vnd.invalidvendor-v99',
                            'CONTENT_TYPE' => 'application/json'
         end
 
@@ -336,20 +336,20 @@ def app
     end
 
     context 'that received a request with correct vendor and version' do
-      before { get '/beer', {}, Grape::Http::Headers::HTTP_ACCEPT => 'application/vnd.vendorname-v99' }
+      before { get '/beer', {}, 'HTTP_ACCEPT' => 'application/vnd.vendorname-v99' }
 
       it_behaves_like 'a valid request'
     end
 
     context 'that receives' do
       context 'an invalid version in the request' do
-        before { get '/beer', {}, Grape::Http::Headers::HTTP_ACCEPT => 'application/vnd.vendorname-v77' }
+        before { get '/beer', {}, 'HTTP_ACCEPT' => 'application/vnd.vendorname-v77' }
 
         it_behaves_like 'a cascaded request'
       end
 
       context 'an invalid vendor in the request' do
-        before { get '/beer', {}, Grape::Http::Headers::HTTP_ACCEPT => 'application/vnd.invalidvendor-v99' }
+        before { get '/beer', {}, 'HTTP_ACCEPT' => 'application/vnd.invalidvendor-v99' }
 
         it_behaves_like 'a cascaded request'
       end
diff --git a/spec/grape/middleware/formatter_spec.rb b/spec/grape/middleware/formatter_spec.rb
index af72f029d..807edaad4 100644
--- a/spec/grape/middleware/formatter_spec.rb
+++ b/spec/grape/middleware/formatter_spec.rb
@@ -11,7 +11,7 @@
   context 'serialization' do
     let(:body) { { 'abc' => 'def' } }
     let(:env) do
-      { Rack::PATH_INFO => '/somewhere', Grape::Http::Headers::HTTP_ACCEPT => 'application/json' }
+      { Rack::PATH_INFO => '/somewhere', 'HTTP_ACCEPT' => 'application/json' }
     end
 
     it 'looks at the bodies for possibly serializable data' do
@@ -22,7 +22,7 @@
     context 'default format' do
       let(:body) { ['foo'] }
       let(:env) do
-        { Rack::PATH_INFO => '/somewhere', Grape::Http::Headers::HTTP_ACCEPT => 'application/json' }
+        { Rack::PATH_INFO => '/somewhere', 'HTTP_ACCEPT' => 'application/json' }
       end
 
       it 'calls #to_json since default format is json' do
@@ -39,7 +39,7 @@ def to_json(*_args)
     context 'xml' do
       let(:body) { +'string' }
       let(:env) do
-        { Rack::PATH_INFO => '/somewhere.xml', Grape::Http::Headers::HTTP_ACCEPT => 'application/json' }
+        { Rack::PATH_INFO => '/somewhere.xml', 'HTTP_ACCEPT' => 'application/json' }
       end
 
       it 'calls #to_xml if the content type is xml' do
@@ -57,7 +57,7 @@ def to_xml
   context 'error handling' do
     let(:formatter) { double(:formatter) }
     let(:env) do
-      { Rack::PATH_INFO => '/somewhere.xml', Grape::Http::Headers::HTTP_ACCEPT => 'application/json' }
+      { Rack::PATH_INFO => '/somewhere.xml', 'HTTP_ACCEPT' => 'application/json' }
     end
 
     before do
@@ -76,7 +76,7 @@ def to_xml
       allow(formatter).to receive(:call) { raise StandardError }
 
       expect do
-        catch(:error) { subject.call(Rack::PATH_INFO => '/somewhere.xml', Grape::Http::Headers::HTTP_ACCEPT => 'application/json') }
+        catch(:error) { subject.call(Rack::PATH_INFO => '/somewhere.xml', 'HTTP_ACCEPT' => 'application/json') }
       end.to raise_error(StandardError)
     end
   end
@@ -109,12 +109,12 @@ def to_xml
     end
 
     it 'uses the requested format if provided in headers' do
-      subject.call(Rack::PATH_INFO => '/info', Grape::Http::Headers::HTTP_ACCEPT => 'application/json')
+      subject.call(Rack::PATH_INFO => '/info', 'HTTP_ACCEPT' => 'application/json')
       expect(subject.env[Grape::Env::API_FORMAT]).to eq(:json)
     end
 
     it 'uses the file extension format if provided before headers' do
-      subject.call(Rack::PATH_INFO => '/info.txt', Grape::Http::Headers::HTTP_ACCEPT => 'application/json')
+      subject.call(Rack::PATH_INFO => '/info.txt', 'HTTP_ACCEPT' => 'application/json')
       expect(subject.env[Grape::Env::API_FORMAT]).to eq(:txt)
     end
   end
@@ -122,47 +122,47 @@ def to_xml
   context 'accept header detection' do
     context 'when header contains invalid byte sequence' do
       it 'does not raise an exception' do
-        expect { subject.call(Rack::PATH_INFO => '/info', Grape::Http::Headers::HTTP_ACCEPT => "Hello \x80") }.not_to raise_error
+        expect { subject.call(Rack::PATH_INFO => '/info', 'HTTP_ACCEPT' => "Hello \x80") }.not_to raise_error
       end
     end
 
     it 'detects from the Accept header' do
-      subject.call(Rack::PATH_INFO => '/info', Grape::Http::Headers::HTTP_ACCEPT => 'application/xml')
+      subject.call(Rack::PATH_INFO => '/info', 'HTTP_ACCEPT' => 'application/xml')
       expect(subject.env[Grape::Env::API_FORMAT]).to eq(:xml)
     end
 
     it 'uses quality rankings to determine formats' do
-      subject.call(Rack::PATH_INFO => '/info', Grape::Http::Headers::HTTP_ACCEPT => 'application/json; q=0.3,application/xml; q=1.0')
+      subject.call(Rack::PATH_INFO => '/info', 'HTTP_ACCEPT' => 'application/json; q=0.3,application/xml; q=1.0')
       expect(subject.env[Grape::Env::API_FORMAT]).to eq(:xml)
 
-      subject.call(Rack::PATH_INFO => '/info', Grape::Http::Headers::HTTP_ACCEPT => 'application/json; q=1.0,application/xml; q=0.3')
+      subject.call(Rack::PATH_INFO => '/info', 'HTTP_ACCEPT' => 'application/json; q=1.0,application/xml; q=0.3')
       expect(subject.env[Grape::Env::API_FORMAT]).to eq(:json)
     end
 
     it 'handles quality rankings mixed with nothing' do
-      subject.call(Rack::PATH_INFO => '/info', Grape::Http::Headers::HTTP_ACCEPT => 'application/json,application/xml; q=1.0')
+      subject.call(Rack::PATH_INFO => '/info', 'HTTP_ACCEPT' => 'application/json,application/xml; q=1.0')
       expect(subject.env[Grape::Env::API_FORMAT]).to eq(:xml)
 
-      subject.call(Rack::PATH_INFO => '/info', Grape::Http::Headers::HTTP_ACCEPT => 'application/xml; q=1.0,application/json')
+      subject.call(Rack::PATH_INFO => '/info', 'HTTP_ACCEPT' => 'application/xml; q=1.0,application/json')
       expect(subject.env[Grape::Env::API_FORMAT]).to eq(:json)
     end
 
     it 'handles quality rankings that have a default 1.0 value' do
-      subject.call(Rack::PATH_INFO => '/info', Grape::Http::Headers::HTTP_ACCEPT => 'application/json,application/xml;q=0.5')
+      subject.call(Rack::PATH_INFO => '/info', 'HTTP_ACCEPT' => 'application/json,application/xml;q=0.5')
       expect(subject.env[Grape::Env::API_FORMAT]).to eq(:json)
-      subject.call(Rack::PATH_INFO => '/info', Grape::Http::Headers::HTTP_ACCEPT => 'application/xml;q=0.5,application/json')
+      subject.call(Rack::PATH_INFO => '/info', 'HTTP_ACCEPT' => 'application/xml;q=0.5,application/json')
       expect(subject.env[Grape::Env::API_FORMAT]).to eq(:json)
     end
 
     it 'parses headers with other attributes' do
-      subject.call(Rack::PATH_INFO => '/info', Grape::Http::Headers::HTTP_ACCEPT => 'application/json; abc=2.3; q=1.0,application/xml; q=0.7')
+      subject.call(Rack::PATH_INFO => '/info', 'HTTP_ACCEPT' => 'application/json; abc=2.3; q=1.0,application/xml; q=0.7')
       expect(subject.env[Grape::Env::API_FORMAT]).to eq(:json)
     end
 
     it 'ensures that a quality of 0 is less preferred than any other content type' do
-      subject.call(Rack::PATH_INFO => '/info', Grape::Http::Headers::HTTP_ACCEPT => 'application/json;q=0.0,application/xml')
+      subject.call(Rack::PATH_INFO => '/info', 'HTTP_ACCEPT' => 'application/json;q=0.0,application/xml')
       expect(subject.env[Grape::Env::API_FORMAT]).to eq(:xml)
-      subject.call(Rack::PATH_INFO => '/info', Grape::Http::Headers::HTTP_ACCEPT => 'application/xml,application/json;q=0.0')
+      subject.call(Rack::PATH_INFO => '/info', 'HTTP_ACCEPT' => 'application/xml,application/json;q=0.0')
       expect(subject.env[Grape::Env::API_FORMAT]).to eq(:xml)
     end
 
@@ -171,21 +171,21 @@ def to_xml
         subject { described_class.new(app, content_types: { custom: 'application/vnd.test+json' }) }
 
         it 'uses the custom type' do
-          subject.call(Rack::PATH_INFO => '/info', Grape::Http::Headers::HTTP_ACCEPT => 'application/vnd.test+json')
+          subject.call(Rack::PATH_INFO => '/info', 'HTTP_ACCEPT' => 'application/vnd.test+json')
           expect(subject.env[Grape::Env::API_FORMAT]).to eq(:custom)
         end
       end
 
       context 'when unregistered' do
         it 'returns the default content type text/plain' do
-          r = Rack::MockResponse[*subject.call(Rack::PATH_INFO => '/info', Grape::Http::Headers::HTTP_ACCEPT => 'application/vnd.test+json')]
+          r = Rack::MockResponse[*subject.call(Rack::PATH_INFO => '/info', 'HTTP_ACCEPT' => 'application/vnd.test+json')]
           expect(r.headers[Rack::CONTENT_TYPE]).to eq('text/plain')
         end
       end
     end
 
     it 'parses headers with symbols as hash keys' do
-      subject.call(Rack::PATH_INFO => '/info', Grape::Http::Headers::HTTP_ACCEPT => 'application/xml', system_time: '091293')
+      subject.call(Rack::PATH_INFO => '/info', 'HTTP_ACCEPT' => 'application/xml', system_time: '091293')
       expect(subject.env[:system_time]).to eq('091293')
     end
   end
@@ -214,7 +214,7 @@ def to_xml
 
     it 'is set for vendored with registered type' do
       s = described_class.new(app, content_types: { custom: 'application/vnd.test+json' })
-      _, headers, = s.call(Rack::PATH_INFO => '/info', Grape::Http::Headers::HTTP_ACCEPT => 'application/vnd.test+json')
+      _, headers, = s.call(Rack::PATH_INFO => '/info', 'HTTP_ACCEPT' => 'application/vnd.test+json')
       expect(headers[Rack::CONTENT_TYPE]).to eq('application/vnd.test+json')
     end
   end
@@ -362,7 +362,7 @@ def to_xml
           Rack::REQUEST_METHOD => method,
           'CONTENT_TYPE' => 'application/json',
           Rack::RACK_INPUT => io,
-          Grape::Http::Headers::HTTP_TRANSFER_ENCODING => 'chunked'
+          'HTTP_TRANSFER_ENCODING' => 'chunked'
         )
         expect(subject.env[Rack::RACK_REQUEST_FORM_HASH]['is_boolean']).to be true
         expect(subject.env[Rack::RACK_REQUEST_FORM_HASH]['string']).to eq('thing')
@@ -376,7 +376,7 @@ def to_xml
           Rack::REQUEST_METHOD => method,
           'CONTENT_TYPE' => 'application/json',
           Rack::RACK_INPUT => io,
-          Grape::Http::Headers::HTTP_TRANSFER_ENCODING => 'chunked'
+          'HTTP_TRANSFER_ENCODING' => 'chunked'
         )
         expect(subject.env[Rack::RACK_REQUEST_FORM_HASH]['is_boolean']).to be true
         expect(subject.env[Rack::RACK_REQUEST_FORM_HASH]['string']).to eq('thing')
@@ -420,7 +420,7 @@ def to_xml
     let(:app) { ->(_env) { [200, {}, file_body] } }
     let(:body) { 'data' }
     let(:env) do
-      { Rack::PATH_INFO => '/somewhere', Grape::Http::Headers::HTTP_ACCEPT => 'application/json' }
+      { Rack::PATH_INFO => '/somewhere', 'HTTP_ACCEPT' => 'application/json' }
     end
     let(:headers) do
       if Gem::Version.new(Rack.release) < Gem::Version.new('3.1')
@@ -452,7 +452,7 @@ def self.call(_, _)
 
     let(:app) { ->(_env) { [200, {}, ['']] } }
     let(:env) do
-      Rack::MockRequest.env_for('/hello.invalid', Grape::Http::Headers::HTTP_ACCEPT => 'application/x-invalid')
+      Rack::MockRequest.env_for('/hello.invalid', 'HTTP_ACCEPT' => 'application/x-invalid')
     end
 
     it 'returns response by invalid formatter' do
diff --git a/spec/grape/middleware/versioner/accept_version_header_spec.rb b/spec/grape/middleware/versioner/accept_version_header_spec.rb
index 491abe6f9..7693cb92d 100644
--- a/spec/grape/middleware/versioner/accept_version_header_spec.rb
+++ b/spec/grape/middleware/versioner/accept_version_header_spec.rb
@@ -20,8 +20,8 @@
 
     it 'does not raise an error' do
       expect do
-        subject.call(Grape::Http::Headers::HTTP_ACCEPT_VERSION => "\x80")
-      end.to throw_symbol(:error, status: 406, headers: { Grape::Http::Headers::X_CASCADE => 'pass' }, message: 'The requested version is not supported.')
+        subject.call('HTTP_ACCEPT_VERSION' => "\x80")
+      end.to throw_symbol(:error, status: 406, headers: { 'X-Cascade' => 'pass' }, message: 'The requested version is not supported.')
     end
   end
 
@@ -31,37 +31,37 @@
     end
 
     it 'is set' do
-      status, _, env = subject.call(Grape::Http::Headers::HTTP_ACCEPT_VERSION => 'v1')
+      status, _, env = subject.call('HTTP_ACCEPT_VERSION' => 'v1')
       expect(env[Grape::Env::API_VERSION]).to eql 'v1'
       expect(status).to eq(200)
     end
 
     it 'is set if format provided' do
-      status, _, env = subject.call(Grape::Http::Headers::HTTP_ACCEPT_VERSION => 'v1')
+      status, _, env = subject.call('HTTP_ACCEPT_VERSION' => 'v1')
       expect(env[Grape::Env::API_VERSION]).to eql 'v1'
       expect(status).to eq(200)
     end
 
     it 'fails with 406 Not Acceptable if version is not supported' do
       expect do
-        subject.call(Grape::Http::Headers::HTTP_ACCEPT_VERSION => 'v2').last
+        subject.call('HTTP_ACCEPT_VERSION' => 'v2').last
       end.to throw_symbol(
         :error,
         status: 406,
-        headers: { Grape::Http::Headers::X_CASCADE => 'pass' },
+        headers: { 'X-Cascade' => 'pass' },
         message: 'The requested version is not supported.'
       )
     end
   end
 
   it 'succeeds if :strict is not set' do
-    expect(subject.call(Grape::Http::Headers::HTTP_ACCEPT_VERSION => '').first).to eq(200)
+    expect(subject.call('HTTP_ACCEPT_VERSION' => '').first).to eq(200)
     expect(subject.call({}).first).to eq(200)
   end
 
   it 'succeeds if :strict is set to false' do
     @options[:version_options][:strict] = false
-    expect(subject.call(Grape::Http::Headers::HTTP_ACCEPT_VERSION => '').first).to eq(200)
+    expect(subject.call('HTTP_ACCEPT_VERSION' => '').first).to eq(200)
     expect(subject.call({}).first).to eq(200)
   end
 
@@ -77,24 +77,24 @@
       end.to throw_symbol(
         :error,
         status: 406,
-        headers: { Grape::Http::Headers::X_CASCADE => 'pass' },
+        headers: { 'X-Cascade' => 'pass' },
         message: 'Accept-Version header must be set.'
       )
     end
 
     it 'fails with 406 Not Acceptable if header is empty' do
       expect do
-        subject.call(Grape::Http::Headers::HTTP_ACCEPT_VERSION => '').last
+        subject.call('HTTP_ACCEPT_VERSION' => '').last
       end.to throw_symbol(
         :error,
         status: 406,
-        headers: { Grape::Http::Headers::X_CASCADE => 'pass' },
+        headers: { 'X-Cascade' => 'pass' },
         message: 'Accept-Version header must be set.'
       )
     end
 
     it 'succeeds if proper header is set' do
-      expect(subject.call(Grape::Http::Headers::HTTP_ACCEPT_VERSION => 'v1').first).to eq(200)
+      expect(subject.call('HTTP_ACCEPT_VERSION' => 'v1').first).to eq(200)
     end
   end
 
@@ -118,7 +118,7 @@
 
     it 'fails with 406 Not Acceptable if header is empty' do
       expect do
-        subject.call(Grape::Http::Headers::HTTP_ACCEPT_VERSION => '').last
+        subject.call('HTTP_ACCEPT_VERSION' => '').last
       end.to throw_symbol(
         :error,
         status: 406,
@@ -128,7 +128,7 @@
     end
 
     it 'succeeds if proper header is set' do
-      expect(subject.call(Grape::Http::Headers::HTTP_ACCEPT_VERSION => 'v1').first).to eq(200)
+      expect(subject.call('HTTP_ACCEPT_VERSION' => 'v1').first).to eq(200)
     end
   end
 end
diff --git a/spec/grape/middleware/versioner/header_spec.rb b/spec/grape/middleware/versioner/header_spec.rb
index 12fd837e0..230133cba 100644
--- a/spec/grape/middleware/versioner/header_spec.rb
+++ b/spec/grape/middleware/versioner/header_spec.rb
@@ -16,21 +16,21 @@
 
   context 'api.type and api.subtype' do
     it 'sets type and subtype to first choice of content type if no preference given' do
-      status, _, env = subject.call(Grape::Http::Headers::HTTP_ACCEPT => '*/*')
+      status, _, env = subject.call('HTTP_ACCEPT' => '*/*')
       expect(env[Grape::Env::API_TYPE]).to eql 'application'
       expect(env[Grape::Env::API_SUBTYPE]).to eql 'vnd.vendor+xml'
       expect(status).to eq(200)
     end
 
     it 'sets preferred type' do
-      status, _, env = subject.call(Grape::Http::Headers::HTTP_ACCEPT => 'application/*')
+      status, _, env = subject.call('HTTP_ACCEPT' => 'application/*')
       expect(env[Grape::Env::API_TYPE]).to eql 'application'
       expect(env[Grape::Env::API_SUBTYPE]).to eql 'vnd.vendor+xml'
       expect(status).to eq(200)
     end
 
     it 'sets preferred type and subtype' do
-      status, _, env = subject.call(Grape::Http::Headers::HTTP_ACCEPT => 'text/plain')
+      status, _, env = subject.call('HTTP_ACCEPT' => 'text/plain')
       expect(env[Grape::Env::API_TYPE]).to eql 'text'
       expect(env[Grape::Env::API_SUBTYPE]).to eql 'plain'
       expect(status).to eq(200)
@@ -39,13 +39,13 @@
 
   context 'api.format' do
     it 'is set' do
-      status, _, env = subject.call(Grape::Http::Headers::HTTP_ACCEPT => 'application/vnd.vendor+json')
+      status, _, env = subject.call('HTTP_ACCEPT' => 'application/vnd.vendor+json')
       expect(env[Grape::Env::API_FORMAT]).to eql 'json'
       expect(status).to eq(200)
     end
 
     it 'is nil if not provided' do
-      status, _, env = subject.call(Grape::Http::Headers::HTTP_ACCEPT => 'application/vnd.vendor')
+      status, _, env = subject.call('HTTP_ACCEPT' => 'application/vnd.vendor')
       expect(env[Grape::Env::API_FORMAT]).to be_nil
       expect(status).to eq(200)
     end
@@ -57,13 +57,13 @@
         end
 
         it 'is set' do
-          status, _, env = subject.call(Grape::Http::Headers::HTTP_ACCEPT => 'application/vnd.vendor-v1+json')
+          status, _, env = subject.call('HTTP_ACCEPT' => 'application/vnd.vendor-v1+json')
           expect(env[Grape::Env::API_FORMAT]).to eql 'json'
           expect(status).to eq(200)
         end
 
         it 'is nil if not provided' do
-          status, _, env = subject.call(Grape::Http::Headers::HTTP_ACCEPT => 'application/vnd.vendor-v1')
+          status, _, env = subject.call('HTTP_ACCEPT' => 'application/vnd.vendor-v1')
           expect(env[Grape::Env::API_FORMAT]).to be_nil
           expect(status).to eq(200)
         end
@@ -73,22 +73,22 @@
 
   context 'api.vendor' do
     it 'is set' do
-      status, _, env = subject.call(Grape::Http::Headers::HTTP_ACCEPT => 'application/vnd.vendor')
+      status, _, env = subject.call('HTTP_ACCEPT' => 'application/vnd.vendor')
       expect(env[Grape::Env::API_VENDOR]).to eql 'vendor'
       expect(status).to eq(200)
     end
 
     it 'is set if format provided' do
-      status, _, env = subject.call(Grape::Http::Headers::HTTP_ACCEPT => 'application/vnd.vendor+json')
+      status, _, env = subject.call('HTTP_ACCEPT' => 'application/vnd.vendor+json')
       expect(env[Grape::Env::API_VENDOR]).to eql 'vendor'
       expect(status).to eq(200)
     end
 
     it 'fails with 406 Not Acceptable if vendor is invalid' do
-      expect { subject.call(Grape::Http::Headers::HTTP_ACCEPT => 'application/vnd.othervendor+json').last }
+      expect { subject.call('HTTP_ACCEPT' => 'application/vnd.othervendor+json').last }
         .to raise_exception do |exception|
           expect(exception).to be_a(Grape::Exceptions::InvalidAcceptHeader)
-          expect(exception.headers).to eql(Grape::Http::Headers::X_CASCADE => 'pass')
+          expect(exception.headers).to eql('X-Cascade' => 'pass')
           expect(exception.status).to be 406
           expect(exception.message).to include 'API vendor not found'
         end
@@ -100,22 +100,22 @@
       end
 
       it 'is set' do
-        status, _, env = subject.call(Grape::Http::Headers::HTTP_ACCEPT => 'application/vnd.vendor-v1')
+        status, _, env = subject.call('HTTP_ACCEPT' => 'application/vnd.vendor-v1')
         expect(env[Grape::Env::API_VENDOR]).to eql 'vendor'
         expect(status).to eq(200)
       end
 
       it 'is set if format provided' do
-        status, _, env = subject.call(Grape::Http::Headers::HTTP_ACCEPT => 'application/vnd.vendor-v1+json')
+        status, _, env = subject.call('HTTP_ACCEPT' => 'application/vnd.vendor-v1+json')
         expect(env[Grape::Env::API_VENDOR]).to eql 'vendor'
         expect(status).to eq(200)
       end
 
       it 'fails with 406 Not Acceptable if vendor is invalid' do
-        expect { subject.call(Grape::Http::Headers::HTTP_ACCEPT => 'application/vnd.othervendor-v1+json').last }
+        expect { subject.call('HTTP_ACCEPT' => 'application/vnd.othervendor-v1+json').last }
           .to raise_exception do |exception|
             expect(exception).to be_a(Grape::Exceptions::InvalidAcceptHeader)
-            expect(exception.headers).to eql(Grape::Http::Headers::X_CASCADE => 'pass')
+            expect(exception.headers).to eql('X-Cascade' => 'pass')
             expect(exception.status).to be 406
             expect(exception.message).to include('API vendor not found')
           end
@@ -129,21 +129,21 @@
     end
 
     it 'is set' do
-      status, _, env = subject.call(Grape::Http::Headers::HTTP_ACCEPT => 'application/vnd.vendor-v1')
+      status, _, env = subject.call('HTTP_ACCEPT' => 'application/vnd.vendor-v1')
       expect(env[Grape::Env::API_VERSION]).to eql 'v1'
       expect(status).to eq(200)
     end
 
     it 'is set if format provided' do
-      status, _, env = subject.call(Grape::Http::Headers::HTTP_ACCEPT => 'application/vnd.vendor-v1+json')
+      status, _, env = subject.call('HTTP_ACCEPT' => 'application/vnd.vendor-v1+json')
       expect(env[Grape::Env::API_VERSION]).to eql 'v1'
       expect(status).to eq(200)
     end
 
     it 'fails with 406 Not Acceptable if version is invalid' do
-      expect { subject.call(Grape::Http::Headers::HTTP_ACCEPT => 'application/vnd.vendor-v2+json').last }.to raise_exception do |exception|
+      expect { subject.call('HTTP_ACCEPT' => 'application/vnd.vendor-v2+json').last }.to raise_exception do |exception|
         expect(exception).to be_a(Grape::Exceptions::InvalidVersionHeader)
-        expect(exception.headers).to eql(Grape::Http::Headers::X_CASCADE => 'pass')
+        expect(exception.headers).to eql('X-Cascade' => 'pass')
         expect(exception.status).to be 406
         expect(exception.message).to include('API version not found')
       end
@@ -151,19 +151,19 @@
   end
 
   it 'succeeds if :strict is not set' do
-    expect(subject.call(Grape::Http::Headers::HTTP_ACCEPT => '').first).to eq(200)
+    expect(subject.call('HTTP_ACCEPT' => '').first).to eq(200)
     expect(subject.call({}).first).to eq(200)
   end
 
   it 'succeeds if :strict is set to false' do
     @options[:version_options][:strict] = false
-    expect(subject.call(Grape::Http::Headers::HTTP_ACCEPT => '').first).to eq(200)
+    expect(subject.call('HTTP_ACCEPT' => '').first).to eq(200)
     expect(subject.call({}).first).to eq(200)
   end
 
   it 'succeeds if :strict is set to false and given an invalid header' do
     @options[:version_options][:strict] = false
-    expect(subject.call(Grape::Http::Headers::HTTP_ACCEPT => 'yaml').first).to eq(200)
+    expect(subject.call('HTTP_ACCEPT' => 'yaml').first).to eq(200)
     expect(subject.call({}).first).to eq(200)
   end
 
@@ -176,23 +176,23 @@
     it 'fails with 406 Not Acceptable if header is not set' do
       expect { subject.call({}).last }.to raise_exception do |exception|
         expect(exception).to be_a(Grape::Exceptions::InvalidAcceptHeader)
-        expect(exception.headers).to eql(Grape::Http::Headers::X_CASCADE => 'pass')
+        expect(exception.headers).to eql('X-Cascade' => 'pass')
         expect(exception.status).to be 406
         expect(exception.message).to include('Accept header must be set.')
       end
     end
 
     it 'fails with 406 Not Acceptable if header is empty' do
-      expect { subject.call(Grape::Http::Headers::HTTP_ACCEPT => '').last }.to raise_exception do |exception|
+      expect { subject.call('HTTP_ACCEPT' => '').last }.to raise_exception do |exception|
         expect(exception).to be_a(Grape::Exceptions::InvalidAcceptHeader)
-        expect(exception.headers).to eql(Grape::Http::Headers::X_CASCADE => 'pass')
+        expect(exception.headers).to eql('X-Cascade' => 'pass')
         expect(exception.status).to be 406
         expect(exception.message).to include('Accept header must be set.')
       end
     end
 
     it 'succeeds if proper header is set' do
-      expect(subject.call(Grape::Http::Headers::HTTP_ACCEPT => 'application/vnd.vendor-v1+json').first).to eq(200)
+      expect(subject.call('HTTP_ACCEPT' => 'application/vnd.vendor-v1+json').first).to eq(200)
     end
   end
 
@@ -213,7 +213,7 @@
     end
 
     it 'fails with 406 Not Acceptable if header is application/xml' do
-      expect { subject.call(Grape::Http::Headers::HTTP_ACCEPT => 'application/xml').last }
+      expect { subject.call('HTTP_ACCEPT' => 'application/xml').last }
         .to raise_exception do |exception|
         expect(exception).to be_a(Grape::Exceptions::InvalidAcceptHeader)
         expect(exception.headers).to eql({})
@@ -223,7 +223,7 @@
     end
 
     it 'fails with 406 Not Acceptable if header is empty' do
-      expect { subject.call(Grape::Http::Headers::HTTP_ACCEPT => '').last }.to raise_exception do |exception|
+      expect { subject.call('HTTP_ACCEPT' => '').last }.to raise_exception do |exception|
         expect(exception).to be_a(Grape::Exceptions::InvalidAcceptHeader)
         expect(exception.headers).to eql({})
         expect(exception.status).to be 406
@@ -232,7 +232,7 @@
     end
 
     it 'fails with 406 Not Acceptable if header contains a single invalid accept' do
-      expect { subject.call(Grape::Http::Headers::HTTP_ACCEPT => 'application/json;application/vnd.vendor-v1+json').first }
+      expect { subject.call('HTTP_ACCEPT' => 'application/json;application/vnd.vendor-v1+json').first }
         .to raise_exception do |exception|
         expect(exception).to be_a(Grape::Exceptions::InvalidAcceptHeader)
         expect(exception.headers).to eql({})
@@ -242,7 +242,7 @@
     end
 
     it 'succeeds if proper header is set' do
-      expect(subject.call(Grape::Http::Headers::HTTP_ACCEPT => 'application/vnd.vendor-v1+json').first).to eq(200)
+      expect(subject.call('HTTP_ACCEPT' => 'application/vnd.vendor-v1+json').first).to eq(200)
     end
   end
 
@@ -252,17 +252,17 @@
     end
 
     it 'succeeds with v1' do
-      expect(subject.call(Grape::Http::Headers::HTTP_ACCEPT => 'application/vnd.vendor-v1+json').first).to eq(200)
+      expect(subject.call('HTTP_ACCEPT' => 'application/vnd.vendor-v1+json').first).to eq(200)
     end
 
     it 'succeeds with v2' do
-      expect(subject.call(Grape::Http::Headers::HTTP_ACCEPT => 'application/vnd.vendor-v2+json').first).to eq(200)
+      expect(subject.call('HTTP_ACCEPT' => 'application/vnd.vendor-v2+json').first).to eq(200)
     end
 
     it 'fails with another version' do
-      expect { subject.call(Grape::Http::Headers::HTTP_ACCEPT => 'application/vnd.vendor-v3+json') }.to raise_exception do |exception|
+      expect { subject.call('HTTP_ACCEPT' => 'application/vnd.vendor-v3+json') }.to raise_exception do |exception|
         expect(exception).to be_a(Grape::Exceptions::InvalidVersionHeader)
-        expect(exception.headers).to eql(Grape::Http::Headers::X_CASCADE => 'pass')
+        expect(exception.headers).to eql('X-Cascade' => 'pass')
         expect(exception.status).to be 406
         expect(exception.message).to include('API version not found')
       end
diff --git a/spec/integration/rack_3_0/headers_spec.rb b/spec/integration/rack_3_0/headers_spec.rb
index bd270e129..735807c7e 100644
--- a/spec/integration/rack_3_0/headers_spec.rb
+++ b/spec/integration/rack_3_0/headers_spec.rb
@@ -1,12 +1,12 @@
 # frozen_string_literal: true
 
-describe Grape::Http::Headers do
+describe Grape::API do
   subject { last_response.headers }
 
   describe 'returned headers should all be in lowercase' do
     context 'when setting an header in an API' do
       let(:app) do
-        Class.new(Grape::API) do
+        Class.new(described_class) do
           get do
             header['GRAPE'] = '1'
             return_no_content
@@ -21,7 +21,7 @@
 
     context 'when error!' do
       let(:app) do
-        Class.new(Grape::API) do
+        Class.new(described_class) do
           rescue_from ArgumentError do
             error!('error!', 500, { 'GRAPE' => '1' })
           end
@@ -37,7 +37,7 @@
 
     context 'when redirect' do
       let(:app) do
-        Class.new(Grape::API) do
+        Class.new(described_class) do
           get do
             redirect 'https://www.ruby-grape.org/'
           end
@@ -51,7 +51,7 @@
 
     context 'when options' do
       let(:app) do
-        Class.new(Grape::API) do
+        Class.new(described_class) do
           get { return_no_content }
         end
       end
@@ -63,7 +63,7 @@
 
     context 'when cascade' do
       let(:app) do
-        Class.new(Grape::API) do
+        Class.new(described_class) do
           version 'v0', using: :path, cascade: true
           get { return_no_content }
         end
diff --git a/spec/support/chunked_response.rb b/spec/support/chunked_response.rb
index c74f18f09..4c66e9384 100644
--- a/spec/support/chunked_response.rb
+++ b/spec/support/chunked_response.rb
@@ -58,9 +58,9 @@ def call(env)
 
     if !Rack::Utils::STATUS_WITH_NO_ENTITY_BODY.key?(status.to_i) &&
        !headers[Rack::CONTENT_LENGTH] &&
-       !headers[Grape::Http::Headers::TRANSFER_ENCODING]
+       !headers['Transfer-Encoding']
 
-      headers[Grape::Http::Headers::TRANSFER_ENCODING] = 'chunked'
+      headers['Transfer-Encoding'] = 'chunked'
       response[2] = if headers['trailer']
                       TrailerBody.new(body)
                     else
diff --git a/spec/support/versioned_helpers.rb b/spec/support/versioned_helpers.rb
index c4e841249..ce682e0d7 100644
--- a/spec/support/versioned_helpers.rb
+++ b/spec/support/versioned_helpers.rb
@@ -23,14 +23,14 @@ def versioned_headers(options)
           {}
         when :header
           {
-            Grape::Http::Headers::HTTP_ACCEPT => [
+            'HTTP_ACCEPT' => [
               "application/vnd.#{options[:vendor]}-#{options[:version]}",
               options[:format]
             ].compact.join('+')
           }
         when :accept_version_header
           {
-            Grape::Http::Headers::HTTP_ACCEPT_VERSION => options[:version].to_s
+            'HTTP_ACCEPT_VERSION' => options[:version].to_s
           }
         else
           raise ArgumentError.new("unknown versioning strategy: #{options[:using]}")


Reviews:
user: login: dblock
body: I think this needs an UPGRADING on the invalid header that can be set and the removal of some constants.
state: CHANGES_REQUESTED
author_association: MEMBER
submitted_at: 2025-04-05T19:11:03Z
user: login: ericproulx
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-06T14:35:18Z
user: login: ericproulx
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-06T15:54:10Z
user: login: dblock
state: APPROVED
author_association: MEMBER
submitted_at: 2025-04-09T02:21:21Z

Review comments:
diff_hunk: @@ -9,6 +9,7 @@
 * [#2540](https://github.com/ruby-grape/grape/pull/2540): Introduce Params builder with symbolized short name - [@ericproulx](https://github.com/ericproulx).
 * [#2550](https://github.com/ruby-grape/grape/pull/2550): Drop ActiveSupport 6.0 - [@ericproulx](https://github.com/ericproulx).
 * [#2549](https://github.com/ruby-grape/grape/pull/2549): Delegate cookies management to `Grape::Request` - [@ericproulx](https://github.com/ericproulx).
+* [#2554](https://github.com/ruby-grape/grape/pull/2554): Remove Grape::Http::Headers - [@ericproulx](https://github.com/ericproulx).
path: CHANGELOG.md
user: login: dblock
body: I think you have a fix here for https://github.com/ruby-grape/grape/issues/2334, add?
created_at: 2025-04-05T19:09:03Z
author_association: MEMBER
diff_hunk: @@ -9,6 +9,7 @@
 * [#2540](https://github.com/ruby-grape/grape/pull/2540): Introduce Params builder with symbolized short name - [@ericproulx](https://github.com/ericproulx).
 * [#2550](https://github.com/ruby-grape/grape/pull/2550): Drop ActiveSupport 6.0 - [@ericproulx](https://github.com/ericproulx).
 * [#2549](https://github.com/ruby-grape/grape/pull/2549): Delegate cookies management to `Grape::Request` - [@ericproulx](https://github.com/ericproulx).
+* [#2554](https://github.com/ruby-grape/grape/pull/2554): Remove Grape::Http::Headers - [@ericproulx](https://github.com/ericproulx).
path: CHANGELOG.md
user: login: dblock
body: ```suggestion
* [#2554](https://github.com/ruby-grape/grape/pull/2554): Remove `Grape::Http::Headers` - [@ericproulx](https://github.com/ericproulx).
```
created_at: 2025-04-05T19:09:14Z
author_association: MEMBER
diff_hunk: @@ -9,6 +9,7 @@
 * [#2540](https://github.com/ruby-grape/grape/pull/2540): Introduce Params builder with symbolized short name - [@ericproulx](https://github.com/ericproulx).
 * [#2550](https://github.com/ruby-grape/grape/pull/2550): Drop ActiveSupport 6.0 - [@ericproulx](https://github.com/ericproulx).
 * [#2549](https://github.com/ruby-grape/grape/pull/2549): Delegate cookies management to `Grape::Request` - [@ericproulx](https://github.com/ericproulx).
+* [#2554](https://github.com/ruby-grape/grape/pull/2554): Remove Grape::Http::Headers - [@ericproulx](https://github.com/ericproulx).
path: CHANGELOG.md
user: login: ericproulx
body: Well its a fix .. but not really. We've been using `Grape::Util::Header` for a while and since then, Grape is compliant with Rack's spec about headers.
created_at: 2025-04-06T14:35:18Z
author_association: CONTRIBUTOR
diff_hunk: @@ -1,6 +1,18 @@
 Upgrading Grape
 ===============
 
+### Upgrading to >= 2.4.0
path: UPGRADING.md
user: login: ericproulx
body: @dblock Fix from your [comment](https://github.com/ruby-grape/grape/pull/2553#discussion_r2030178520)
created_at: 2025-04-06T15:54:10Z
author_association: CONTRIBUTOR

PR comments:
user: login: dblock
created_at: 2025-04-09T02:21:36Z
body: Rebase? Feel free to merge yourself.
author_association: MEMBER