Class: FunctionsFramework::CloudEvents::HttpBinding
- Inherits:
-
Object
- Object
- FunctionsFramework::CloudEvents::HttpBinding
- Defined in:
- lib/functions_framework/cloud_events/http_binding.rb
Overview
HTTP binding for CloudEvents.
This class implements HTTP binding, including unmarshalling of events from Rack environment data, and marshalling of events to Rack environment data. It supports binary (i.e. header-based) HTTP content, as well as structured (body-based) content that can delegate to formatters such as JSON.
See https://github.com/cloudevents/spec/blob/master/http-protocol-binding.md
Class Method Summary collapse
-
.default ⇒ Object
Returns a default binding, with JSON supported.
Instance Method Summary collapse
-
#decode_batched_content(input, format, **format_args) ⇒ Array<FunctionsFramework::CloudEvents::Event>
Decode a batch of events from the given content data.
-
#decode_binary_content(env, content_type) ⇒ FunctionsFramework::CloudEvents::Event?
Decode an event from the given Rack environment in binary content mode.
-
#decode_rack_env(env, **format_args) ⇒ FunctionsFramework::CloudEvents::Event, ...
Decode an event from the given Rack environment hash.
-
#decode_structured_content(input, format, **format_args) ⇒ FunctionsFramework::CloudEvents::Event
Decode a single event from the given content data.
-
#encode_batched_content(events, format, **format_args) ⇒ Array(headers,String)
Encode a batch of events to content data in the given format.
-
#encode_binary_content(event) ⇒ Array(headers,String)
Encode an event to content and headers, in binary content mode.
-
#encode_structured_content(event, format, **format_args) ⇒ Array(headers,String)
Encode a single event to content data in the given format.
-
#initialize ⇒ HttpBinding
constructor
Create an empty HTTP binding.
-
#register_batched_formatter(type, formatter) ⇒ self
Register a batch formatter for the given type.
-
#register_structured_formatter(type, formatter) ⇒ self
Register a formatter for the given type.
Constructor Details
#initialize ⇒ HttpBinding
Create an empty HTTP binding.
46 47 48 49 |
# File 'lib/functions_framework/cloud_events/http_binding.rb', line 46 def initialize @structured_formatters = {} @batched_formatters = {} end |
Class Method Details
.default ⇒ Object
Returns a default binding, with JSON supported.
33 34 35 36 37 38 39 40 41 |
# File 'lib/functions_framework/cloud_events/http_binding.rb', line 33 def self.default @default ||= begin http_binding = new json_format = JsonFormat.new http_binding.register_structured_formatter "json", json_format http_binding.register_batched_formatter "json", json_format http_binding end end |
Instance Method Details
#decode_batched_content(input, format, **format_args) ⇒ Array<FunctionsFramework::CloudEvents::Event>
Decode a batch of events from the given content data. This should be
passed the request body, if the Content-Type is of the form
application/cloudevents-batch+format
.
145 146 147 148 149 150 151 152 |
# File 'lib/functions_framework/cloud_events/http_binding.rb', line 145 def decode_batched_content input, format, **format_args handlers = @batched_formatters[format] || [] handlers.reverse_each do |handler| events = handler.decode_batch input, **format_args return events if events end raise HttpContentError, "Unknown cloudevents batch format: #{format.inspect}" end |
#decode_binary_content(env, content_type) ⇒ FunctionsFramework::CloudEvents::Event?
Decode an event from the given Rack environment in binary content mode.
164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 |
# File 'lib/functions_framework/cloud_events/http_binding.rb', line 164 def decode_binary_content env, content_type spec_version = env["HTTP_CE_SPECVERSION"] return nil if spec_version.nil? raise SpecVersionError, "Unrecognized specversion: #{spec_version}" unless spec_version == "1.0" input = env["rack.input"] data = if input input.set_encoding content_type.charset if content_type&.charset input.read end attributes = { "spec_version" => spec_version, "data" => data } attributes["data_content_type"] = content_type if content_type omit_names = ["specversion", "spec_version", "data", "datacontenttype", "data_content_type"] env.each do |key, value| match = /^HTTP_CE_(\w+)$/.match key next unless match attr_name = match[1].downcase attributes[attr_name] = value unless omit_names.include? attr_name end Event.create spec_version: spec_version, attributes: attributes end |
#decode_rack_env(env, **format_args) ⇒ FunctionsFramework::CloudEvents::Event, ...
Decode an event from the given Rack environment hash. Following the CloudEvents spec, this chooses a handler based on the Content-Type of the request.
99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 |
# File 'lib/functions_framework/cloud_events/http_binding.rb', line 99 def decode_rack_env env, **format_args content_type_header = env["CONTENT_TYPE"] content_type = ContentType.new content_type_header if content_type_header input = env["rack.input"] if input && content_type&.media_type == "application" case content_type.subtype_prefix when "cloudevents" input.set_encoding content_type.charset if content_type.charset return decode_structured_content input.read, content_type.subtype_format, **format_args when "cloudevents-batch" input.set_encoding content_type.charset if content_type.charset return decode_batched_content input.read, content_type.subtype_format, **format_args end end decode_binary_content env, content_type end |
#decode_structured_content(input, format, **format_args) ⇒ FunctionsFramework::CloudEvents::Event
Decode a single event from the given content data. This should be
passed the request body, if the Content-Type is of the form
application/cloudevents+format
.
126 127 128 129 130 131 132 133 |
# File 'lib/functions_framework/cloud_events/http_binding.rb', line 126 def decode_structured_content input, format, **format_args handlers = @structured_formatters[format] || [] handlers.reverse_each do |handler| event = handler.decode input, **format_args return event if event end raise HttpContentError, "Unknown cloudevents format: #{format.inspect}" end |
#encode_batched_content(events, format, **format_args) ⇒ Array(headers,String)
Encode a batch of events to content data in the given format.
The result is a two-element array where the first element is a headers
list (as defined in the Rack specification) and the second is a string
containing the HTTP body content. The headers list will contain only
one header, a Content-Type
whose value is of the form
application/cloudevents-batch+format
.
223 224 225 226 227 228 229 230 |
# File 'lib/functions_framework/cloud_events/http_binding.rb', line 223 def encode_batched_content events, format, **format_args handlers = @batched_formatters[format] || [] handlers.reverse_each do |handler| content = handler.encode_batch events, **format_args return [{ "Content-Type" => "application/cloudevents-batch+#{format}" }, content] if content end raise HttpContentError, "Unknown cloudevents format: #{format.inspect}" end |
#encode_binary_content(event) ⇒ Array(headers,String)
Encode an event to content and headers, in binary content mode.
The result is a two-element array where the first element is a headers list (as defined in the Rack specification) and the second is a string containing the HTTP body content.
242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 |
# File 'lib/functions_framework/cloud_events/http_binding.rb', line 242 def encode_binary_content event headers = {} body = nil event.to_h.each do |key, value| if key == "data" body = value elsif key == "datacontenttype" headers["Content-Type"] = value else headers["CE-#{key}"] = value end end if body.is_a? ::String headers["Content-Type"] ||= if body.encoding == ::Encoding.ASCII_8BIT "application/octet-stream" else "text/plain; charset=#{body.encoding.name.downcase}" end elsif body.nil? headers.delete "Content-Type" else body = ::JSON.dump body headers["Content-Type"] ||= "application/json; charset=#{body.encoding.name.downcase}" end [headers, body] end |
#encode_structured_content(event, format, **format_args) ⇒ Array(headers,String)
Encode a single event to content data in the given format.
The result is a two-element array where the first element is a headers
list (as defined in the Rack specification) and the second is a string
containing the HTTP body content. The headers list will contain only
one header, a Content-Type
whose value is of the form
application/cloudevents+format
.
199 200 201 202 203 204 205 206 |
# File 'lib/functions_framework/cloud_events/http_binding.rb', line 199 def encode_structured_content event, format, **format_args handlers = @structured_formatters[format] || [] handlers.reverse_each do |handler| content = handler.encode event, **format_args return [{ "Content-Type" => "application/cloudevents+#{format}" }, content] if content end raise HttpContentError, "Unknown cloudevents format: #{format.inspect}" end |
#register_batched_formatter(type, formatter) ⇒ self
Register a batch formatter for the given type.
A batch formatter must respond to the methods #encode_batch
and
#decode_batch
. See JsonFormat for
an example.
80 81 82 83 84 |
# File 'lib/functions_framework/cloud_events/http_binding.rb', line 80 def register_batched_formatter type, formatter formatters = @batched_formatters[type.to_s.strip.downcase] ||= [] formatters << formatter unless formatters.include? formatter self end |
#register_structured_formatter(type, formatter) ⇒ self
Register a formatter for the given type.
A formatter must respond to the methods #encode
and #decode
. See
JsonFormat for an example.
62 63 64 65 66 |
# File 'lib/functions_framework/cloud_events/http_binding.rb', line 62 def register_structured_formatter type, formatter formatters = @structured_formatters[type.to_s.strip.downcase] ||= [] formatters << formatter unless formatters.include? formatter self end |