From 879ac38e89ebcb858c3f299f9e272d1ddbe9d021 Mon Sep 17 00:00:00 2001 From: Marc Worrell Date: Thu, 18 Apr 2024 16:57:56 +0200 Subject: [PATCH] mod_base: let controller_id accept an extension on the id for content negotation (#3729) * mod_base: let controller_id accept an extension on the id for content negotation * Add .jsonld mimetype/extension mappings --- .../src/support/z_cowmachine_middleware.erl | 3 +- .../src/support/z_media_identify.erl | 2 + .../src/controllers/controller_id.erl | 39 ++++++++++++++++++- 3 files changed, 41 insertions(+), 3 deletions(-) diff --git a/apps/zotonic_core/src/support/z_cowmachine_middleware.erl b/apps/zotonic_core/src/support/z_cowmachine_middleware.erl index 9dcb34dd1a..0ffff3ec59 100644 --- a/apps/zotonic_core/src/support/z_cowmachine_middleware.erl +++ b/apps/zotonic_core/src/support/z_cowmachine_middleware.erl @@ -25,7 +25,8 @@ -behaviour(cowboy_middleware). -export([ - execute/2 + execute/2, + set_accept_context/2 ]). -include_lib("../../include/zotonic.hrl"). diff --git a/apps/zotonic_core/src/support/z_media_identify.erl b/apps/zotonic_core/src/support/z_media_identify.erl index 949e5e047b..ec6c38720c 100644 --- a/apps/zotonic_core/src/support/z_media_identify.erl +++ b/apps/zotonic_core/src/support/z_media_identify.erl @@ -516,6 +516,7 @@ extension({A, B, _}, PreferExtension) -> extension(<>, PreferExtension); extension(Mime, PreferExtension) when is_list(Mime) -> extension(list_to_binary(Mime), PreferExtension); +extension(<<"application/ld+json">>, _PreferExtension) -> <<".jsonld">>; extension(<<"image/jpeg">>, _PreferExtension) -> <<".jpg">>; extension(<<"application/vnd.ms-excel">>, _) -> <<".xls">>; extension(<<"text/plain">>, _PreferExtension) -> <<".txt">>; @@ -559,6 +560,7 @@ first_extension([ Ext | _ ]) -> -spec guess_mime( file:filename_all() ) -> mime_type(). guess_mime(File) -> case z_string:to_lower( filename:extension( File ) ) of + <<".jsonld">> -> <<"application/ld+json">>; <<".bert">> -> <<"application/x-bert">>; % Fonts have since 2017 their own mime types- https://tools.ietf.org/html/rfc8081#section-4.4.5 <<".woff">> -> <<"font/woff">>; diff --git a/apps/zotonic_mod_base/src/controllers/controller_id.erl b/apps/zotonic_mod_base/src/controllers/controller_id.erl index 569e15c230..903e1d9841 100644 --- a/apps/zotonic_mod_base/src/controllers/controller_id.erl +++ b/apps/zotonic_mod_base/src/controllers/controller_id.erl @@ -100,6 +100,8 @@ find_html([ {{<<"text">>, <<"html">>, _}, _} = Prov | _CTs ]) -> find_html([ _ | CTs ]) -> find_html(CTs). +% Fetch id from the request. Check if the id has an extension, if so split it +% and set the accept header. get_id(Context) -> case z_context:get(id, Context) of undefined -> @@ -109,9 +111,42 @@ get_id(Context) -> <<>> -> {undefined, Context}; Id -> - RscId = m_rsc:rid(Id, Context), - {RscId, z_context:set(id, {ok, RscId}, Context)} + case maybe_split_extension(Id) of + {Root, Ext} -> + RscId = m_rsc:rid(Root, Context), + Context1 = z_cowmachine_middleware:set_accept_context(Ext, Context), + {RscId, z_context:set(id, {ok, RscId}, Context1)}; + false -> + RscId = m_rsc:rid(Id, Context), + {RscId, z_context:set(id, {ok, RscId}, Context)} + end end; {ok, Id} -> {Id, Context} end. + +maybe_split_extension(<<"http:", _/binary>>) -> + false; +maybe_split_extension(<<"https:", _/binary>>) -> + false; +maybe_split_extension(Id) -> + case filename:extension(Id) of + <<".", Ext/binary>> when Ext =/= <<>> -> + Root = filename:rootname(Id), + case is_name_like(Root) of + true -> + {Root, Ext}; + false -> + false + end; + _ -> + false + end. + +is_name_like(<<>>) -> true; +is_name_like(<<$_, R/binary>>) -> is_name_like(R); +is_name_like(<>) when C < $0 -> false; +is_name_like(<>) when C > $9, C < $A -> false; +is_name_like(<>) when C > $Z, C < $a -> false; +is_name_like(<>) when C > $z, C < 128 -> false; +is_name_like(<<_, R/binary>>) -> is_name_like(R).