aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/cowboy_rest.erl4
-rw-r--r--test/handlers/content_types_accepted_h.erl23
-rw-r--r--test/rest_handler_SUITE.erl54
3 files changed, 61 insertions, 20 deletions
diff --git a/src/cowboy_rest.erl b/src/cowboy_rest.erl
index 606f47f..76eda79 100644
--- a/src/cowboy_rest.erl
+++ b/src/cowboy_rest.erl
@@ -1060,6 +1060,10 @@ accept_resource(Req, State) ->
{CTA, Req2, State2} ->
CTA2 = [normalize_content_types(P) || P <- CTA],
try cowboy_req:parse_header(<<"content-type">>, Req2) of
+ %% We do not match against the boundary parameter for multipart.
+ {Type = <<"multipart">>, SubType, Params} ->
+ ContentType = {Type, SubType, lists:keydelete(<<"boundary">>, 1, Params)},
+ choose_content_type(Req2, State2, ContentType, CTA2);
ContentType ->
choose_content_type(Req2, State2, ContentType, CTA2)
catch _:_ ->
diff --git a/test/handlers/content_types_accepted_h.erl b/test/handlers/content_types_accepted_h.erl
new file mode 100644
index 0000000..7aec1bb
--- /dev/null
+++ b/test/handlers/content_types_accepted_h.erl
@@ -0,0 +1,23 @@
+%% This module accepts a multipart media type with parameters
+%% that do not include boundary.
+
+-module(content_types_accepted_h).
+
+-export([init/2]).
+-export([allowed_methods/2]).
+-export([content_types_accepted/2]).
+-export([put_multipart_mixed/2]).
+
+init(Req, Opts) ->
+ {cowboy_rest, Req, Opts}.
+
+allowed_methods(Req, State) ->
+ {[<<"PUT">>], Req, State}.
+
+content_types_accepted(Req=#{qs := <<"multipart">>}, State) ->
+ {[
+ {{<<"multipart">>, <<"mixed">>, [{<<"v">>, <<"1">>}]}, put_multipart_mixed}
+ ], Req, State}.
+
+put_multipart_mixed(Req, State) ->
+ {true, Req, State}.
diff --git a/test/rest_handler_SUITE.erl b/test/rest_handler_SUITE.erl
index 363f789..88d3554 100644
--- a/test/rest_handler_SUITE.erl
+++ b/test/rest_handler_SUITE.erl
@@ -47,6 +47,7 @@ init_dispatch(_) ->
charset_in_content_types_provided_implicit_h, []},
{"/charset_in_content_types_provided_implicit_no_callback",
charset_in_content_types_provided_implicit_no_callback_h, []},
+ {"/content_types_accepted", content_types_accepted_h, []},
{"/if_range", if_range_h, []},
{"/provide_callback_missing", provide_callback_missing_h, []},
{"/provide_range_callback", provide_range_callback_h, []},
@@ -69,26 +70,6 @@ do_decode(Headers, Body) ->
%% Tests.
-error_on_malformed_if_match(Config) ->
- doc("A malformed If-Match header must result in a 400 response."),
- ConnPid = gun_open(Config),
- Ref = gun:get(ConnPid, "/", [
- {<<"accept-encoding">>, <<"gzip">>},
- {<<"if-match">>, <<"bad">>}
- ]),
- {response, _, 400, _} = gun:await(ConnPid, Ref),
- ok.
-
-error_on_malformed_if_none_match(Config) ->
- doc("A malformed If-None-Match header must result in a 400 response."),
- ConnPid = gun_open(Config),
- Ref = gun:get(ConnPid, "/", [
- {<<"accept-encoding">>, <<"gzip">>},
- {<<"if-none-match">>, <<"bad">>}
- ]),
- {response, _, 400, _} = gun:await(ConnPid, Ref),
- ok.
-
charset_in_content_types_provided(Config) ->
doc("When a charset is matched explictly in content_types_provided, "
"that charset is used and the charsets_provided callback is ignored."),
@@ -287,6 +268,39 @@ charsets_provided_empty_noheader(Config) ->
{response, _, 406, _} = gun:await(ConnPid, Ref),
ok.
+content_types_accepted_ignore_multipart_boundary(Config) ->
+ doc("When a multipart content-type is provided for the request "
+ "body, the boundary parameter is not expected to be returned "
+ "from the content_types_accepted callback and will be "
+ "automatically ignored."),
+ ConnPid = gun_open(Config),
+ Ref = gun:put(ConnPid, "/content_types_accepted?multipart", [
+ {<<"accept-encoding">>, <<"gzip">>},
+ {<<"content-type">>, <<"multipart/mixed; boundary=abcdef; v=1">>}
+ ], <<"Not really multipart!">>),
+ {response, _, 204, _} = gun:await(ConnPid, Ref),
+ ok.
+
+error_on_malformed_if_match(Config) ->
+ doc("A malformed If-Match header must result in a 400 response."),
+ ConnPid = gun_open(Config),
+ Ref = gun:get(ConnPid, "/", [
+ {<<"accept-encoding">>, <<"gzip">>},
+ {<<"if-match">>, <<"bad">>}
+ ]),
+ {response, _, 400, _} = gun:await(ConnPid, Ref),
+ ok.
+
+error_on_malformed_if_none_match(Config) ->
+ doc("A malformed If-None-Match header must result in a 400 response."),
+ ConnPid = gun_open(Config),
+ Ref = gun:get(ConnPid, "/", [
+ {<<"accept-encoding">>, <<"gzip">>},
+ {<<"if-none-match">>, <<"bad">>}
+ ]),
+ {response, _, 400, _} = gun:await(ConnPid, Ref),
+ ok.
+
if_range_etag_equal(Config) ->
doc("When the if-range header matches, a 206 partial content "
"response is expected for an otherwise valid range request. (RFC7233 3.2)"),