Module: Hitch::MCP::Internal::MediaType

Defined in:
app/models/hitch/mcp/internal/media_type.rb

Overview

Strict media negotiation for the endpoint (RFC 7231 ยง5.3): the request body must be exactly application/json, and Accept must admit both response framings the protocol may use.

Constant Summary collapse

ACCEPT_TYPES =
%w[application/json text/event-stream].freeze
MEDIA_TYPE_PATTERN =
%r{\A[A-Za-z0-9!#$%&'*+.^_`|~-]+/[A-Za-z0-9!#$%&'*+.^_`|~-]+\z}
PARAMETER_PATTERN =
/\A[A-Za-z0-9!#$%&'*+.^_`|~-]+=[^;\s]+\z/
QUALITY_PATTERN =
/\A(?:0(?:\.\d{0,3})?|1(?:\.0{0,3})?)\z/

Class Method Summary collapse

Class Method Details

.accept_entry(entry) ⇒ Object



41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
# File 'app/models/hitch/mcp/internal/media_type.rb', line 41

def accept_entry(entry)
  media_type, *parameters = entry.split(";", -1).map { |part| HeaderField.trim_ows(part) }
  return [ nil, nil ] unless media_type&.match?(MEDIA_TYPE_PATTERN)

  quality = 1.0
  quality_seen = false
  parameters.each do |parameter|
    name, raw_value = parameter.to_s.split("=", 2)
    return [ nil, nil ] unless name && raw_value
    next unless name.casecmp?("q")
    return [ nil, nil ] if quality_seen || !raw_value.match?(QUALITY_PATTERN)

    quality_seen = true
    quality = raw_value.to_f
  end
  [ media_type.downcase, quality ]
end

.accepts_required_types?(value) ⇒ Boolean

Returns:

  • (Boolean)


27
28
29
30
31
32
33
34
35
36
37
38
39
# File 'app/models/hitch/mcp/internal/media_type.rb', line 27

def accepts_required_types?(value)
  return false unless value.is_a?(String) && value.valid_encoding?
  return false if value.empty? || HeaderField::CONTROLS.match?(value)

  accepted = {}
  value.split(",", -1).each do |entry|
    media_type, quality = accept_entry(entry)
    return false unless media_type

    accepted[media_type] = true if ACCEPT_TYPES.include?(media_type) && quality.positive?
  end
  ACCEPT_TYPES.all? { |media_type| accepted[media_type] }
end

.json_content_type?(value) ⇒ Boolean

Returns:

  • (Boolean)


17
18
19
20
21
22
23
24
25
# File 'app/models/hitch/mcp/internal/media_type.rb', line 17

def json_content_type?(value)
  return false unless value.is_a?(String) && value.valid_encoding?
  return false if value.empty? || value.include?(",") || HeaderField::CONTROLS.match?(value)

  media_type, *parameters = value.split(";", -1).map { |part| HeaderField.trim_ows(part) }
  return false unless media_type&.downcase == "application/json"

  parameters.all? { |parameter| parameter&.match?(PARAMETER_PATTERN) }
end