Class: Biryani::HTTP::RequestBuilder

Inherits:
Object
  • Object
show all
Defined in:
lib/biryani/http/request.rb

Constant Summary collapse

PSEUDO_HEADER_FIELDS =
[':authority', ':method', ':path', ':scheme'].freeze

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initializeRequestBuilder

Returns a new instance of RequestBuilder.



29
30
31
# File 'lib/biryani/http/request.rb', line 29

def initialize
  @h = {}
end

Class Method Details

.build(h, s) ⇒ Request, ConnectionError

Parameters:

  • h (Hash<String, Array<String>>)
  • s (String)

Returns:



83
84
85
86
87
88
89
90
91
92
93
94
# File 'lib/biryani/http/request.rb', line 83

def self.build(h, s)
  return ConnectionError.new(ErrorCode::PROTOCOL_ERROR, 'missing pseudo-header fields') unless PSEUDO_HEADER_FIELDS.all? { |x| h.key?(x) }
  return ConnectionError.new(ErrorCode::PROTOCOL_ERROR, 'invalid content-length') if h.key?('content-length') && !s.empty? && s.length != h['content-length'].to_i

  scheme = h[':scheme'][0]
  domain = h[':authority'][0]
  path = h[':path'][0]
  uri = URI("#{scheme}://#{domain}#{path}")
  method = h[':method'][0]
  h['cookie'] = [h['cookie'].join('; ')] if h.key?('cookie')
  Request.new(method, uri, h, s)
end

Instance Method Details

#build(s) ⇒ Request

Parameters:

  • s (String)

Returns:



73
74
75
76
77
# File 'lib/biryani/http/request.rb', line 73

def build(s)
  # `Ractor.send(req, move: true)` moves entries in HPACK::DynamicTable; therefore, a `dup` call is required.
  h = @h.transform_values { |x| x.map(&:dup) }
  self.class.build(h, s)
end

#field(name, value) ⇒ nil, ConnectioError

rubocop: disable Metrics/AbcSize rubocop: disable Metrics/CyclomaticComplexity rubocop: disable Metrics/PerceivedComplexity

Parameters:

  • name (String)
  • value (String)

Returns:

  • (nil, ConnectioError)


40
41
42
43
44
45
46
47
48
49
50
51
52
53
# File 'lib/biryani/http/request.rb', line 40

def field(name, value)
  return ConnectionError.new(ErrorCode::PROTOCOL_ERROR, 'field name has uppercase letter') if name.downcase != name
  return ConnectionError.new(ErrorCode::PROTOCOL_ERROR, 'unknown pseudo-header field name') if name[0] == ':' && !PSEUDO_HEADER_FIELDS.include?(name)
  return ConnectionError.new(ErrorCode::PROTOCOL_ERROR, 'appear pseudo-header fields after regular fields') if name[0] == ':' && @h.any? { |name_, _| name_[0] != ':' }
  return ConnectionError.new(ErrorCode::PROTOCOL_ERROR, 'duplicated pseudo-header fields') if PSEUDO_HEADER_FIELDS.include?(name) && @h.key?(name)
  return ConnectionError.new(ErrorCode::PROTOCOL_ERROR, "invalid `#{name}` field") if PSEUDO_HEADER_FIELDS.include?(name) && value.empty?
  return ConnectionError.new(ErrorCode::PROTOCOL_ERROR, 'connection-specific field is forbidden') if name == 'connection'
  return ConnectionError.new(ErrorCode::PROTOCOL_ERROR, '`TE` field has a value other than `trailers`') if name == 'te' && value != 'trailers'

  @h[name] = [] unless @h.key?(name)
  @h[name] << value

  nil
end

#fields(arr) ⇒ nil, ConnectioError

Parameters:

  • arr (Array)

Returns:

  • (nil, ConnectioError)


61
62
63
64
65
66
67
68
# File 'lib/biryani/http/request.rb', line 61

def fields(arr)
  arr.each do |name, value|
    err = field(name, value)
    return err unless err.nil?
  end

  nil
end