Skip to content

Commit

Permalink
in_http: Implement support for CORS preflight requests
Browse files Browse the repository at this point in the history
To receive a 'application/json' request from another origin, we need
to be able to handle CORS preflight requests. Otherwise, browsers will
refuse to interact with us.

https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS#Preflighted_requests

This patch adds support for the feature.

Signed-off-by: Fujimoto Seiji <fujimoto@clear-code.com>
  • Loading branch information
Fujimoto Seiji committed Oct 5, 2018
1 parent 500ed50 commit f19da57
Show file tree
Hide file tree
Showing 2 changed files with 61 additions and 0 deletions.
38 changes: 38 additions & 0 deletions lib/fluent/plugin/in_http.rb
Expand Up @@ -342,6 +342,10 @@ def on_headers_complete(headers)
# For multiple X-Forwarded-For headers. Use first header value.
v = v.first if v.is_a?(Array)
@remote_addr = v.split(",").first
when /Access-Control-Request-Method/i
@access_control_request_method = v
when /Access-Control-Request-Headers/i
@access_control_request_headers = v
end
}
if expect
Expand All @@ -367,9 +371,43 @@ def on_body(chunk)
@body << chunk
end

# Web browsers can send an OPTIONS request before performing POST
# to check if cross-origin requests are supported.
def handle_options_request
# Is CORS enabled in the first place?
if @cors_allow_origins.nil?
return send_response_and_close("403 Forbidden", {}, "")
end

# in_http does not support HTTP methods except POST
if @access_control_request_method != 'POST'
return send_response_and_close("403 Forbidden", {}, "")
end

header = {
"Access-Control-Allow-Methods": "POST",
"Access-Control-Allow-Headers": @access_control_request_headers || "",
}

# Check the origin and send back a CORS response
if @cors_allow_origins.include?('*')
header["Access-Control-Allow-Origin"] = "*"
send_response_and_close("200 OK", header, "")
elsif @cors_allow_origins.include?(@origin)
header["Access-Control-Allow-Origin"] = @origin
send_response_and_close("200 OK", header, "")
else
send_response_and_close("403 Forbidden", {}, "")
end
end

def on_message_complete
return if closing?

if @parser.http_method == 'OPTIONS'
return handle_options_request()
end

# CORS check
# ==========
# For every incoming request, we check if we have some CORS
Expand Down
23 changes: 23 additions & 0 deletions test/plugin/test_in_http.rb
Expand Up @@ -624,6 +624,23 @@ def test_cors_allowed_wildcard
end
end

def test_cors_preflight
d = create_driver(CONFIG + 'cors_allow_origins ["*"]')

d.run do
header = {
"Origin" => "http://foo.com",
"Access-Control-Request-Method" => "POST",
"Access-Control-Request-Headers" => "Content-Type",
}
res = options("/cors.test", {}, header)

assert_equal "200", res.code
assert_equal "*", res["Access-Control-Allow-Origin"]
assert_equal "POST", res["Access-Control-Allow-Methods"]
end
end

def test_content_encoding_gzip
d = create_driver

Expand Down Expand Up @@ -744,6 +761,12 @@ def test_if_content_type_is_initialized_properly
assert_equal $test_in_http_connection_object_ids[0], $test_in_http_connection_object_ids[1]
end

def options(path, params, header = {})
http = Net::HTTP.new("127.0.0.1", PORT)
req = Net::HTTP::Options.new(path, header)
http.request(req)
end

def post(path, params, header = {}, &block)
http = Net::HTTP.new("127.0.0.1", PORT)
req = Net::HTTP::Post.new(path, header)
Expand Down

0 comments on commit f19da57

Please sign in to comment.