Class: Dommy::Headers

Inherits:
Object
  • Object
show all
Includes:
Bridge::Methods
Defined in:
lib/dommy/fetch.rb

Overview

WHATWG ‘Headers`. Names are stored lowercased and compared case-insensitively; iteration (`keys`/`values`/`entries`/`forEach`) is sorted by name with duplicate values combined by “, ” (the spec’s “sort and combine” output). ‘new Headers(init)` fills from a record (Hash → set per key), a sequence (Array of `[name, value]` pairs → append), or another Headers instance.

Constant Summary collapse

HEADER_NAME =

RFC 7230 token — a valid header name (one or more of these bytes).

/\A[!#$%&'*+\-.^_`|~0-9A-Za-z]+\z/.freeze
HTTP_WHITESPACE =

Leading/trailing HTTP whitespace (tab or space) trimmed from a value.

/\A[\t ]+|[\t ]+\z/.freeze

Class Method Summary collapse

Instance Method Summary collapse

Methods included from Bridge::Methods

included

Constructor Details

#initialize(init = nil) ⇒ Headers

Returns a new instance of Headers.



604
605
606
607
608
# File 'lib/dommy/fetch.rb', line 604

def initialize(init = nil)
  @list = [] # ordered [lowercased name, value] pairs (duplicates allowed)
  @guard = :none # :none (mutable) or :immutable (Response.error/redirect)
  fill(init)
end

Class Method Details

.canonical(name) ⇒ Object

RFC 7230 Title-Case form of a header name. Retained as a public helper; the Headers store itself is lowercased per the WHATWG spec.



711
712
713
# File 'lib/dommy/fetch.rb', line 711

def self.canonical(name)
  name.split("-").map(&:capitalize).join("-")
end

Instance Method Details

#__js_call__(method, args) ⇒ Object



665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
# File 'lib/dommy/fetch.rb', line 665

def __js_call__(method, args)
  case method
  when "set"
    set_value(args[0], args[1])
    nil
  when "append"
    append_value(args[0], args[1])
    nil
  when "delete"
    ensure_mutable!
    name = validate_name!(args[0])
    @list.reject! { |n, _| n == name }
    nil
  when "get"
    get_combined(validate_name!(args[0]))
  when "has"
    name = validate_name!(args[0])
    @list.any? { |n, _| n == name }
  when "keys"
    sort_and_combine.map(&:first)
  when "values"
    sort_and_combine.map(&:last)
  when "entries"
    sort_and_combine
  when "getSetCookie"
    # WHATWG: Set-Cookie's individual values, in insertion order (never
    # combined, unlike every other header).
    @list.select { |n, _| n == "set-cookie" }.map(&:last)
  when "forEach"
    # WHATWG: forEach(callback) — callback(value, key, headers), in the
    # sort-and-combine order. `self` is the third argument so
    # `(_, _, h) => h.get(...)` works the same as in a browser.
    cb = args[0]
    sort_and_combine.each do |k, v|
      if cb.respond_to?(:__js_call__)
        cb.__js_call__("call", [v, k, self])
      elsif cb.respond_to?(:call)
        cb.call(v, k, self)
      end
    end
    nil
  end
end

#__js_get__(_key) ⇒ Object



655
656
657
# File 'lib/dommy/fetch.rb', line 655

def __js_get__(_key)
  nil
end

#__js_set__(_key, _value) ⇒ Object



659
660
661
# File 'lib/dommy/fetch.rb', line 659

def __js_set__(_key, _value)
  Bridge::UNHANDLED
end

#__raw_pairs__Object

Internal: a copy of the raw [name, value] pairs — lets one Headers be filled from another without losing duplicates or split Set-Cookie values.



642
643
644
# File 'lib/dommy/fetch.rb', line 642

def __raw_pairs__
  @list.map(&:dup)
end

#fill(init) ⇒ Object

WHATWG “fill”: a record (Hash) sets each key; a sequence (Array) appends each [name, value] pair (a non-2-element member is a TypeError); another Headers is copied pair-for-pair.



622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
# File 'lib/dommy/fetch.rb', line 622

def fill(init)
  case init
  when Headers
    init.__raw_pairs__.each { |name, value| append_value(name, value) }
  when Array
    init.each do |pair|
      unless pair.is_a?(Array) && pair.length == 2
        raise Bridge::TypeError,
          "Failed to construct 'Headers': The provided value cannot be converted to a sequence of [name, value] pairs."
      end
      append_value(pair[0], pair[1])
    end
  when Hash
    init.each { |name, value| set_value(name, value) }
  end
  nil
end

#make_immutable!Object

WHATWG: mark these headers immutable — the guard ‘Response.error()` / `Response.redirect()` give their headers. Any later set/append/delete then raises a TypeError. (Other guards — request/request-no-cors/response forbidden-name filtering — are out of scope: fetch here is stubbed.)



614
615
616
617
# File 'lib/dommy/fetch.rb', line 614

def make_immutable!
  @guard = :immutable
  self
end

#to_hObject

A plain Hash of name => combined value (duplicate names combined by “, ”; Set-Cookie collapses to its combined value — use getSetCookie for the split list). For callers that want a simple record.



649
650
651
652
653
# File 'lib/dommy/fetch.rb', line 649

def to_h
  sort_and_combine.each_with_object({}) do |(name, value), out|
    out[name] = out.key?(name) ? "#{out[name]}, #{value}" : value
  end
end