Skip to content

Commit bd1c4df

Browse files
authored
feat: Add HttpBinding#probable_event? (#64)
Signed-off-by: Daniel Azuma <[email protected]>
1 parent 1238143 commit bd1c4df

File tree

2 files changed

+51
-0
lines changed

2 files changed

+51
-0
lines changed

lib/cloud_events/http_binding.rb

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -107,11 +107,33 @@ def register_formatter_methods formatter,
107107
#
108108
attr_accessor :default_encoder_name
109109

110+
##
111+
# Analyze a Rack environment hash and determine whether it is _probably_
112+
# a CloudEvent. This is done by examining headers only, and does not read
113+
# or parse the request body. The result is a best guess: false negatives or
114+
# false positives are possible for edge cases, but the logic should
115+
# generally detect canonically-formatted events.
116+
#
117+
# @param env [Hash] The Rack environment.
118+
# @return [boolean] Whether the request is likely a CloudEvent.
119+
#
120+
def probable_event? env
121+
return true if env["HTTP_CE_SPECVERSION"]
122+
content_type = ContentType.new env["CONTENT_TYPE"].to_s
123+
content_type.media_type == "application" &&
124+
["cloudevents", "cloudevents-batch"].include?(content_type.subtype_base)
125+
end
126+
110127
##
111128
# Decode an event from the given Rack environment hash. Following the
112129
# CloudEvents spec, this chooses a handler based on the Content-Type of
113130
# the request.
114131
#
132+
# Note that this method will read the body (i.e. `rack.input`) stream.
133+
# If you need to access the body after calling this method, you will need
134+
# to rewind the stream. To determine whether the request is a CloudEvent
135+
# without reading the body, use {#probable_event?}.
136+
#
115137
# @param env [Hash] The Rack environment.
116138
# @param allow_opaque [boolean] If true, returns opaque event objects if
117139
# the input is not in a recognized format. If false, raises
@@ -203,6 +225,7 @@ def decode_rack_env env, **format_args
203225
content_type_string = env["CONTENT_TYPE"]
204226
content_type = ContentType.new content_type_string if content_type_string
205227
content = read_with_charset env["rack.input"], content_type&.charset
228+
env["rack.input"].rewind rescue nil
206229
decode_binary_content(content, content_type, env, legacy_data_decode: true) ||
207230
decode_structured_content(content, content_type, false, **format_args)
208231
end

test/test_http_binding.rb

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -458,4 +458,32 @@
458458
assert_equal({ "Content-Type" => "application/cloudevents-batch+json" }, headers)
459459
assert_equal my_json_batch_encoded, body
460460
end
461+
462+
it "detects a probable binary event" do
463+
env = {
464+
"HTTP_CE_SPECVERSION" => "1.0"
465+
}
466+
assert http_binding.probable_event? env
467+
end
468+
469+
it "detects a probable structured event" do
470+
env = {
471+
"CONTENT_TYPE" => "application/cloudevents+myformat"
472+
}
473+
assert http_binding.probable_event? env
474+
end
475+
476+
it "detects a probable batch event" do
477+
env = {
478+
"CONTENT_TYPE" => "application/cloudevents-batch+myformat"
479+
}
480+
assert http_binding.probable_event? env
481+
end
482+
483+
it "detects when something is unlikely an event" do
484+
env = {
485+
"CONTENT_TYPE" => "application/json"
486+
}
487+
refute http_binding.probable_event? env
488+
end
461489
end

0 commit comments

Comments
 (0)