From 4fedb336311604253153eafe81f33a77b44a0b2f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lo=C3=AFc=20Hoguin?= Date: Wed, 14 Nov 2018 18:03:40 +0100 Subject: Ignore the boundary parameter when accepting multipart --- src/cowboy_rest.erl | 4 +++ test/handlers/content_types_accepted_h.erl | 23 +++++++++++++ test/rest_handler_SUITE.erl | 54 +++++++++++++++++++----------- 3 files changed, 61 insertions(+), 20 deletions(-) create mode 100644 test/handlers/content_types_accepted_h.erl 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)"), -- cgit v1.2.3