linzer 0.7.9.beta2 → 0.7.9

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
data/lib/linzer/http.rb CHANGED
@@ -78,6 +78,14 @@ module Linzer
78
78
  private
79
79
 
80
80
  # Executes a signed HTTP request.
81
+ #
82
+ # Validates inputs, builds and signs the request, then sends it.
83
+ #
84
+ # @param verb [Symbol] the HTTP method (e.g. +:get+, +:post+)
85
+ # @param uri [String] the request URI
86
+ # @param options [Hash] request options
87
+ # @return [Net::HTTPResponse] the response
88
+ # @raise [Linzer::Error] if the verb or key is invalid
81
89
  def request(verb, uri, options = {})
82
90
  validate_verb(verb)
83
91
 
@@ -100,10 +108,16 @@ module Linzer
100
108
  do_request(http, uri, verb, options[:data], signature, headers)
101
109
  end
102
110
 
111
+ # Returns the default covered components for signing.
112
+ # @return [Array<String>]
103
113
  def default_components
104
114
  Linzer::Options::DEFAULT[:covered_components]
105
115
  end
106
116
 
117
+ # Validates that the HTTP verb is recognized.
118
+ #
119
+ # @param verb [Symbol] the HTTP method
120
+ # @raise [Linzer::Error] if the verb is unknown
107
121
  def validate_verb(verb)
108
122
  method_name = verb.to_s.upcase
109
123
  if !known_http_methods.include?(method_name)
@@ -111,17 +125,32 @@ module Linzer
111
125
  end
112
126
  end
113
127
 
128
+ # Validates that the signing key is present and usable.
129
+ #
130
+ # @param key [Linzer::Key] the signing key
131
+ # @return [Linzer::Key] the validated key
132
+ # @raise [Linzer::Error] if the key is nil or does not respond to +#sign+
114
133
  def validate_key(key)
115
134
  raise Linzer::Error, "Key can not be nil!" if !key
116
135
  raise Linzer::Error, "Key object is invalid!" if !key.respond_to?(:sign)
117
136
  key
118
137
  end
119
138
 
139
+ # Builds request headers, adding a default User-Agent if not present.
140
+ #
141
+ # @param headers [Hash] user-provided headers
142
+ # @return [Hash] headers with User-Agent ensured
120
143
  def build_headers(headers)
121
144
  return headers if headers.transform_keys(&:downcase).key?("user-agent")
122
145
  headers.merge({"user-agent" => "Linzer/#{Linzer::VERSION}"})
123
146
  end
124
147
 
148
+ # Builds a Net::HTTP request object for the given method and URI.
149
+ #
150
+ # @param method [Symbol] the HTTP method
151
+ # @param uri [String] the request URI
152
+ # @param headers [Hash] request headers to set
153
+ # @return [Net::HTTPRequest] the constructed request
125
154
  def build_request(method, uri, headers)
126
155
  request_class = Net::HTTP.const_get(method.to_s.capitalize)
127
156
  request = request_class.new(URI(uri))
@@ -129,7 +158,10 @@ module Linzer
129
158
  request
130
159
  end
131
160
 
132
- # Determines if the HTTP method typically has a request body.
161
+ # Checks if the HTTP method typically carries a request body.
162
+ #
163
+ # @param verb [Symbol] the HTTP method
164
+ # @return [Boolean] +true+ for POST, PUT, PATCH, and WebDAV write methods
133
165
  def with_body?(verb)
134
166
  # common HTTP
135
167
  return false if %i[get head options trace delete].include?(verb)
@@ -142,6 +174,16 @@ module Linzer
142
174
  true
143
175
  end
144
176
 
177
+ # Sends the HTTP request with the signature headers attached.
178
+ #
179
+ # @param http [Net::HTTP] the HTTP connection
180
+ # @param uri [String] the request URI
181
+ # @param verb [Symbol] the HTTP method
182
+ # @param data [String, nil] the request body
183
+ # @param signature [Linzer::Signature] the generated signature
184
+ # @param headers [Hash] request headers
185
+ # @return [Net::HTTPResponse] the response
186
+ # @raise [Linzer::Error] if a body is required but not provided
145
187
  def do_request(http, uri, verb, data, signature, headers)
146
188
  if with_body?(verb)
147
189
  if !data
@@ -10,8 +10,8 @@ module Linzer
10
10
  # implements field retrieval, header access, and signature attachment
11
11
  # for a specific HTTP message type.
12
12
  #
13
- # @abstract Subclass and implement {#header}, {#attach!}, {#derived},
14
- # and {#field} to create a new adapter.
13
+ # @abstract Subclass and implement {#header}, {#derived}, and {#field}
14
+ # to create a new adapter.
15
15
  #
16
16
  # @see Rack::Request Rack request adapter
17
17
  # @see Rack::Response Rack response adapter
@@ -84,19 +84,48 @@ module Linzer
84
84
  raise Linzer::Error, "Sub-classes are required to implement this method!"
85
85
  end
86
86
 
87
+ # Checks whether the request contains HTTP Message Signature headers.
88
+ #
89
+ # Returns true if either the "signature-input" or "signature" header
90
+ # is present.
91
+ #
92
+ # @return [Boolean] true if the request includes HTTP Message Signature headers
93
+ def has_signature?
94
+ !!header("signature-input") || !!header("signature")
95
+ end
96
+
87
97
  # Attaches a signature to the underlying HTTP message.
88
98
  #
89
- # @abstract Subclasses must implement this method.
90
99
  # @param signature [Signature] The signature to attach
91
100
  # @return [Object] The underlying HTTP message
92
101
  def attach!(signature)
93
- raise Linzer::Error, "Sub-classes are required to implement this method!"
102
+ signature_headers = signature.to_h
103
+
104
+ unless has_signature?
105
+ signature_headers.each { |h, v| set_header!(h, v) }
106
+ return @operation
107
+ end
108
+
109
+ signature_headers.each do |hdr, value|
110
+ merged = Starry.parse_dictionary(String(header(hdr)))
111
+ merged.merge!(Starry.parse_dictionary(value))
112
+ set_header!(hdr, Starry.serialize_dictionary(merged))
113
+ end
114
+
115
+ @operation
116
+ rescue Starry::ParseError => e
117
+ raise Error,
118
+ "Cannot attach signature, invalid signature header(s)!",
119
+ cause: e
94
120
  end
95
121
 
96
122
  private
97
123
 
98
124
  # Parses a field name string into a FieldId.
99
- # @return [FieldId, nil] The parsed identifier, or nil if invalid
125
+ #
126
+ # @param field_name [String] the component identifier string
127
+ # @return [FieldId, nil] the parsed identifier, or +nil+ if invalid
128
+ # @raise [Error] if +@status+ is used in a request message
100
129
  def parse_field_name(field_name)
101
130
  field_id = FieldId.new(field_name: field_name)
102
131
  component = field_id.item
@@ -117,8 +146,12 @@ module Linzer
117
146
  raise Linzer::Error, msg unless message.request?
118
147
  end
119
148
 
120
- # Validates component identifier parameters.
121
- # @return [Object, nil] The validated name, or nil if invalid
149
+ # Validates component identifier parameters against RFC 9421 rules.
150
+ #
151
+ # @param name [Starry::Item] the parsed component identifier
152
+ # @param method [Symbol] +:derived+ or +:field+
153
+ # @return [Starry::Item, nil] the validated name, or +nil+ if
154
+ # the parameter combination is invalid
122
155
  def validate_parameters(name, method)
123
156
  has_unknown = name.parameters.any? { |p, _| !KNOWN_PARAMETERS.include?(p) }
124
157
  return nil if has_unknown
@@ -149,6 +182,13 @@ module Linzer
149
182
  private_constant :KNOWN_PARAMETERS
150
183
 
151
184
  # Retrieves a component value with parameter processing.
185
+ #
186
+ # Handles +;req+, +;sf+, +;key+, and +;bs+ parameters by
187
+ # delegating to the corresponding helper methods.
188
+ #
189
+ # @param name [Starry::Item] the parsed component identifier
190
+ # @param method [Symbol] +:derived+ or +:field+
191
+ # @return [String, Integer, nil] the component value
152
192
  def retrieve(name, method)
153
193
  if !name.parameters.empty?
154
194
  valid_params = validate_parameters(name, method)
@@ -176,6 +216,10 @@ module Linzer
176
216
  end
177
217
 
178
218
  # Processes a structured field value with optional key extraction.
219
+ #
220
+ # @param value [String] the raw header value to parse as a dictionary
221
+ # @param key [String, nil] if present, extracts a single dictionary member
222
+ # @return [String] the serialized structured field value
179
223
  # @see https://www.rfc-editor.org/rfc/rfc9421.html#section-2.1.1
180
224
  def sf(value, key = nil)
181
225
  dict = Starry.parse_dictionary(value)
@@ -188,19 +232,31 @@ module Linzer
188
232
  end
189
233
  end
190
234
 
191
- # Binary-wraps a field value.
235
+ # Binary-wraps a field value as a byte sequence.
236
+ #
237
+ # @param value [String] the header value to wrap
238
+ # @return [String] the serialized byte sequence
192
239
  # @see https://www.rfc-editor.org/rfc/rfc9421.html#section-2.1.3
193
240
  def bs(value)
194
241
  Starry.serialize(value.encode(Encoding::ASCII_8BIT))
195
242
  end
196
243
 
197
244
  # Retrieves a trailer field value.
245
+ #
198
246
  # @abstract Subclasses should implement if trailer support is needed.
247
+ # @param trailer [Object] the trailer field identifier
248
+ # @return [String, nil] the trailer value
249
+ # @raise [Error] always, since no built-in adapters support trailers
199
250
  def tr(trailer)
200
251
  raise Error, "Sub-classes are required to implement this method!"
201
252
  end
202
253
 
203
- # Retrieves a field from the attached request.
254
+ # Retrieves a field from the attached request (for +;req+ parameter).
255
+ #
256
+ # @param field [Starry::Item] the component identifier
257
+ # @param method [Symbol] +:derived+ or +:field+
258
+ # @return [String, nil] the value from the attached request, or
259
+ # +nil+ if no request is attached
204
260
  def req(field, method)
205
261
  attached_request? ? @attached_request[String(field)] : nil
206
262
  end
@@ -0,0 +1,63 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Linzer
4
+ class Message
5
+ module Adapter
6
+ module Faraday
7
+ # Adapter for {::Faraday::Request} objects from the faraday gem.
8
+ #
9
+ # Extends the generic request adapter with faraday-specific
10
+ # derived component retrieval, field lookup, and URI handling.
11
+ #
12
+ # @note Not loaded automatically to avoid making faraday a hard
13
+ # dependency. Require +"linzer/faraday"+ to register this adapter.
14
+ #
15
+ # @see Generic::Request
16
+ # @see https://github.com/lostisland/faraday faraday gem
17
+ class Request < Generic::Request
18
+ private
19
+
20
+ # Resolves a derived component value from the request.
21
+ #
22
+ # @param name [Starry::Item] the parsed component identifier
23
+ # @return [String, nil] the derived value, or +nil+ if unknown
24
+ def derived(name)
25
+ url = @operation.path
26
+ case name.value
27
+ when "@method" then @operation.http_method.to_s.upcase
28
+ when "@target-uri" then uri.to_s
29
+ when "@authority" then url.authority.downcase
30
+ when "@scheme" then url.scheme.downcase
31
+ when "@request-target" then uri.request_uri
32
+ when "@path" then url.path
33
+ when "@query" then "?%s" % String(uri_query)
34
+ when "@query-param" then query_param(uri_query, name)
35
+ end
36
+ end
37
+
38
+ # Builds the full URI including query parameters.
39
+ #
40
+ # @return [URI] the complete request URI with encoded query string
41
+ def uri
42
+ uri = @operation.path.dup
43
+ uri.query = URI.encode_www_form(@operation.params)
44
+ uri
45
+ end
46
+
47
+ # Returns the raw query string from the request URI.
48
+ #
49
+ # Prefers the raw query string from the URI when available,
50
+ # as Faraday normalises percent-encoding when parsing params
51
+ # (e.g. +%2D+ becomes +-+), which would break signature
52
+ # verification.
53
+ #
54
+ # @return [String, nil] the raw query string
55
+ def uri_query
56
+ url = @operation.path
57
+ url.query || uri.query
58
+ end
59
+ end
60
+ end
61
+ end
62
+ end
63
+ end
@@ -0,0 +1,46 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Linzer
4
+ class Message
5
+ module Adapter
6
+ module Faraday
7
+ # Adapter for {::Faraday::Response} objects from the faraday gem.
8
+ #
9
+ # Extends the generic response adapter with faraday-specific
10
+ # derived component retrieval (e.g. +@status+) and header
11
+ # attachment.
12
+ #
13
+ # @note Not loaded automatically to avoid making faraday a hard
14
+ # dependency. Require +"linzer/faraday"+ to register this adapter.
15
+ #
16
+ # @see Generic::Response
17
+ # @see https://github.com/lostisland/faraday faraday gem
18
+ class Response < Generic::Response
19
+ private
20
+
21
+ # Resolves a derived component value from the response.
22
+ #
23
+ # @param name [Starry::Item] the parsed component identifier
24
+ # @return [Integer, nil] the HTTP status code for +@status+,
25
+ # or +nil+ if the component is unknown
26
+ def derived(name)
27
+ case name.value
28
+ when "@status" then @operation.status.to_i
29
+ end
30
+ end
31
+
32
+ # Sets a header on the underlying HTTP message.
33
+ #
34
+ # If a header with the given name already exists, its value is overwritten.
35
+ #
36
+ # @param header [String] the header name
37
+ # @param value [String] the header value
38
+ # @return [String] the value assigned to the header
39
+ def set_header!(header, value)
40
+ @operation.headers[header] = value
41
+ end
42
+ end
43
+ end
44
+ end
45
+ end
46
+ end
@@ -40,42 +40,49 @@ module Linzer
40
40
  @operation[name]
41
41
  end
42
42
 
43
- # Attaches a signature to the request.
44
- # @param signature [Signature] The signature to attach
45
- # @return [Object] The underlying request object
46
- def attach!(signature)
47
- signature.to_h.each { |h, v| @operation[h] = v }
48
- @operation
49
- end
50
-
51
43
  private
52
44
 
53
45
  def derived(name)
54
- unimplemented_method = 'Derived field "@method" lookup is not implemented!'
46
+ unimplemented_method = 'Derived field "%s" lookup is not implemented!'
47
+
48
+ uri = @operation.uri rescue nil
49
+ raise Error, unimplemented_method % name.value if uri.nil?
50
+
55
51
  case name.value
56
- when "@method" then raise Error, unimplemented_method
57
- when "@target-uri" then @operation.uri.to_s
58
- when "@authority" then @operation.uri.authority.downcase
59
- when "@scheme" then @operation.uri.scheme.downcase
60
- when "@request-target" then @operation.uri.request_uri
61
- when "@path" then @operation.uri.path
62
- when "@query" then "?%s" % String(@operation.uri.query)
63
- when "@query-param" then query_param(name)
52
+ when "@method" then raise Error, unimplemented_method % name.value
53
+ when "@target-uri" then uri.to_s
54
+ when "@authority" then uri.authority.downcase
55
+ when "@scheme" then uri.scheme.downcase
56
+ when "@request-target" then uri.request_uri
57
+ when "@path" then uri.path
58
+ when "@query" then "?%s" % String(uri.query)
59
+ when "@query-param" then query_param(uri.query, name)
64
60
  end
65
61
  end
66
62
 
67
- def query_param(name)
63
+ # Sets a header on the underlying HTTP message.
64
+ #
65
+ # If a header with the given name already exists, its value is overwritten.
66
+ #
67
+ # @param header [String] the header name
68
+ # @param value [String] the header value
69
+ # @return [String] the value assigned to the header
70
+ def set_header!(header, value)
71
+ @operation[header] = value
72
+ end
73
+
74
+ def query_param(uri_query, name)
68
75
  param_name = name.parameters["name"]
69
76
  return nil if !param_name
70
77
  decoded_param_name = URI.decode_uri_component(param_name)
71
- params = CGI.parse(@operation.uri.query)
78
+ params = CGI.parse(uri_query)
72
79
  URI.encode_uri_component(params[decoded_param_name]&.first)
73
80
  end
74
81
 
75
82
  def field(name)
76
83
  has_tr = name.parameters["tr"]
77
84
  return nil if has_tr # HTTP requests don't have trailer fields
78
- value = @operation[name.value.to_s]
85
+ value = header(name.value.to_s)
79
86
  value.dup&.strip
80
87
  end
81
88
  end
@@ -31,16 +31,19 @@ module Linzer
31
31
  @operation[name]
32
32
  end
33
33
 
34
- # Attaches a signature to the response.
35
- # @param signature [Signature] The signature to attach
36
- # @return [Object] The underlying response object
37
- def attach!(signature)
38
- signature.to_h.each { |h, v| @operation[h] = v }
39
- @operation
40
- end
41
-
42
34
  private
43
35
 
36
+ # Sets a header on the underlying HTTP message.
37
+ #
38
+ # If a header with the given name already exists, its value is overwritten.
39
+ #
40
+ # @param header [String] the header name
41
+ # @param value [String] the header value
42
+ # @return [String] the value assigned to the header
43
+ def set_header!(header, value)
44
+ @operation[header] = value
45
+ end
46
+
44
47
  def derived(name)
45
48
  raise Linzer::Error, "Sub-classes are required to implement this method!"
46
49
  end
@@ -20,22 +20,30 @@ module Linzer
20
20
  @operation.headers[name]
21
21
  end
22
22
 
23
- # Attaches a signature to the response.
24
- # @param signature [Signature] The signature to attach
25
- # @return [Object] The underlying response object
26
- def attach!(signature)
27
- signature.to_h.each { |h, v| @operation.headers[h] = v }
28
- @operation
29
- end
30
-
31
23
  private
32
24
 
25
+ # Retrieves an HTTP field value from the request or response headers.
26
+ #
27
+ # @param name [Starry::Item] the parsed component identifier
28
+ # @return [String, nil] the stripped header value, or +nil+ if the
29
+ # field has a +tr+ (trailer) parameter or is not present
33
30
  def field(name)
34
31
  has_tr = name.parameters["tr"]
35
32
  return nil if has_tr # XXX: is there a library actually supporting trailers?
36
33
  value = @operation.headers[name.value.to_s]
37
34
  value.dup&.strip
38
35
  end
36
+
37
+ # Sets a header on the underlying HTTP message.
38
+ #
39
+ # If a header with the given name already exists, its value is overwritten.
40
+ #
41
+ # @param header [String] the header name
42
+ # @param value [String] the header value
43
+ # @return [String] the value assigned to the header
44
+ def set_header!(header, value)
45
+ @operation.headers[header] = value
46
+ end
39
47
  end
40
48
  end
41
49
  end
@@ -15,6 +15,14 @@ module Linzer
15
15
 
16
16
  private
17
17
 
18
+ # Resolves a derived component value from the request.
19
+ #
20
+ # Overrides the generic implementation for http.rb-specific
21
+ # accessor methods: +uri.host+ for +@authority+ and
22
+ # +verb+ for +@method+.
23
+ #
24
+ # @param name [Starry::Item] the parsed component identifier
25
+ # @return [String, nil] the derived value
18
26
  def derived(name)
19
27
  return @operation.uri.host if name.value == "@authority"
20
28
  return @operation.verb.to_s.upcase if name.value == "@method"
@@ -19,6 +19,13 @@ module Linzer
19
19
 
20
20
  private
21
21
 
22
+ # Resolves a derived component value from the response.
23
+ #
24
+ # Uses +HTTP::Response#status+ converted to Integer for
25
+ # the +@status+ component.
26
+ #
27
+ # @param name [Starry::Item] the parsed component identifier
28
+ # @return [Integer, nil] the HTTP status code, or +nil+ if unknown
22
29
  def derived(name)
23
30
  case name.value
24
31
  when "@status" then @operation.status.to_i
@@ -14,6 +14,14 @@ module Linzer
14
14
  class Request < Generic::Request
15
15
  private
16
16
 
17
+ # Resolves a derived component value from the request.
18
+ #
19
+ # Overrides the generic implementation to use
20
+ # +Net::HTTPRequest#method+ for the +@method+ component,
21
+ # which returns the HTTP verb as an uppercase string.
22
+ #
23
+ # @param name [Starry::Item] the parsed component identifier
24
+ # @return [String, nil] the derived value
17
25
  def derived(name)
18
26
  return @operation.method if name.value == "@method"
19
27
  super
@@ -11,6 +11,13 @@ module Linzer
11
11
  class Response < Generic::Response
12
12
  private
13
13
 
14
+ # Resolves a derived component value from the response.
15
+ #
16
+ # Uses +Net::HTTPResponse#code+ (a String) converted to Integer
17
+ # for the +@status+ component.
18
+ #
19
+ # @param name [Starry::Item] the parsed component identifier
20
+ # @return [Integer, nil] the HTTP status code, or +nil+ if unknown
14
21
  def derived(name)
15
22
  case name.value
16
23
  when "@status" then @operation.code.to_i
@@ -24,11 +24,19 @@ module Linzer
24
24
 
25
25
  private
26
26
 
27
+ # Validates that the operation is exclusively a request or response.
28
+ # @raise [Error] if the operation is both or neither
27
29
  def validate
28
30
  msg = "Message instance must be an HTTP request or response"
29
31
  raise Error.new msg if response? == request?
30
32
  end
31
33
 
34
+ # Validates that a header name is non-empty.
35
+ #
36
+ # @param name [String] the header name
37
+ # @return [String] the validated header name
38
+ # @raise [ArgumentError] if the name is blank
39
+ # @raise [Linzer::Error] if the name is otherwise invalid
32
40
  def validate_header_name(name)
33
41
  raise ArgumentError.new, "Blank header name." if name.empty?
34
42
  name.to_str
@@ -40,6 +48,13 @@ module Linzer
40
48
  # :nocov:
41
49
  end
42
50
 
51
+ # Converts an HTTP header name to Rack's environment key format.
52
+ #
53
+ # Rack stores headers as uppercase with underscores and an +HTTP_+
54
+ # prefix, except for +Content-Type+ and +Content-Length+.
55
+ #
56
+ # @param field_name [String] the HTTP header name (e.g. +"content-type"+)
57
+ # @return [String] the Rack env key (e.g. +"CONTENT_TYPE"+ or +"HTTP_ACCEPT"+)
43
58
  def rack_header_name(field_name)
44
59
  validate_header_name field_name
45
60
 
@@ -52,6 +67,10 @@ module Linzer
52
67
  end
53
68
  end
54
69
 
70
+ # Resolves a derived component value from the Rack request/response.
71
+ #
72
+ # @param name [Starry::Item] the parsed component identifier
73
+ # @return [String, nil] the derived value, or +nil+ if unknown
55
74
  def derived(name)
56
75
  method = DERIVED_COMPONENT[name.value]
57
76
 
@@ -64,6 +83,11 @@ module Linzer
64
83
  value || derive(@operation, method)
65
84
  end
66
85
 
86
+ # Retrieves an HTTP field value from the Rack request or response.
87
+ #
88
+ # @param name [Starry::Item] the parsed component identifier
89
+ # @return [String, nil] the stripped header value, or +nil+ if the
90
+ # field has a +tr+ (trailer) parameter or is not present
67
91
  def field(name)
68
92
  has_tr = name.parameters["tr"]
69
93
  return nil if has_tr
@@ -79,6 +103,14 @@ module Linzer
79
103
  field_value.dup&.strip
80
104
  end
81
105
 
106
+ # Invokes a method on the Rack operation to extract a derived value.
107
+ #
108
+ # Applies post-processing for +@query+ (prepends +?+) and
109
+ # +@authority+/+@scheme+ (downcases).
110
+ #
111
+ # @param operation [Rack::Request, Rack::Response] the Rack object
112
+ # @param method [Symbol] the method to call
113
+ # @return [String, nil] the derived value
82
114
  def derive(operation, method)
83
115
  return nil unless operation.respond_to?(method)
84
116
  value = operation.public_send(method)
@@ -87,6 +119,11 @@ module Linzer
87
119
  value
88
120
  end
89
121
 
122
+ # Extracts a single query parameter value by name.
123
+ #
124
+ # @param name [Starry::Item] the component with a +name+ parameter
125
+ # @return [String, nil] the percent-encoded parameter value, or
126
+ # +nil+ if the parameter is missing or not found
90
127
  def query_param(name)
91
128
  param_name = name.parameters["name"]
92
129
  return nil if !param_name
@@ -27,14 +27,17 @@ module Linzer
27
27
  @operation.get_header(rack_header_name(name))
28
28
  end
29
29
 
30
- # Attaches a signature to the request.
31
- # @param signature [Signature] The signature to attach
32
- # @return [::Rack::Request] The request with signature headers
33
- def attach!(signature)
34
- signature.to_h.each do |h, v|
35
- @operation.set_header(rack_header_name(h), v)
36
- end
37
- @operation
30
+ private
31
+
32
+ # Sets a header on the underlying HTTP message.
33
+ #
34
+ # If a header with the given name already exists, its value is overwritten.
35
+ #
36
+ # @param header [String] the header name
37
+ # @param value [String] the header value
38
+ # @return [String] the value assigned to the header
39
+ def set_header!(header, value)
40
+ @operation.set_header(rack_header_name(header), value)
38
41
  end
39
42
  end
40
43
  end
@@ -28,14 +28,17 @@ module Linzer
28
28
  @operation.get_header(name)
29
29
  end
30
30
 
31
- # Attaches a signature to the response.
32
- # @param signature [Signature] The signature to attach
33
- # @return [::Rack::Response] The response with signature headers
34
- def attach!(signature)
35
- signature.to_h.each do |h, v|
36
- @operation.set_header(h, v)
37
- end
38
- @operation
31
+ private
32
+
33
+ # Sets a header on the underlying HTTP message.
34
+ #
35
+ # If a header with the given name already exists, its value is overwritten.
36
+ #
37
+ # @param header [String] the header name
38
+ # @param value [String] the header value
39
+ # @return [String] the value assigned to the header
40
+ def set_header!(header, value)
41
+ @operation.set_header(header, value)
39
42
  end
40
43
  end
41
44
  end