dexter has uploaded this change for review. ( 
https://gerrit.osmocom.org/c/onomondo-eim/+/43175?usp=email )


Change subject: esipa_json_handler: Add ESipa JSON bindings
......................................................................

esipa_json_handler: Add ESipa JSON bindings

Since SGP.32, version 1.2, the JSON ESipa bindings are mandatory
for the eIM (for the IPAd they are still optional). With this
patch we add support for the JSON ESipa bindings.

Change-Id: Id73ae78a976608fe6f367f8c3b92d8b7b4e195d4
Related: SYS#8100
---
M src/esipa_asn1_http_handler.erl
M src/esipa_json_handler.erl
A src/esipa_json_http_handler.erl
M src/onomondo_eim_app.erl
4 files changed, 479 insertions(+), 41 deletions(-)



  git pull ssh://gerrit.osmocom.org:29418/onomondo-eim refs/changes/75/43175/1

diff --git a/src/esipa_asn1_http_handler.erl b/src/esipa_asn1_http_handler.erl
index 5f6ff9d..3b03826 100644
--- a/src/esipa_asn1_http_handler.erl
+++ b/src/esipa_asn1_http_handler.erl
@@ -25,7 +25,7 @@
                 {ok, IpaToEim} = esipa_asn1_codec:decode_ipa_to_eim(Data),
                 {EsipaMsgType, _} = IpaToEim,
                 logger:info(
-                    "Handling incoming IPAd request: ~p,~nPeer=~p, Pid=~p~n",
+                    "Handling incoming IPAd request (ASN.1): ~p,~nPeer=~p, 
Pid=~p~n",
                     [EsipaMsgType, maps:get(peer, Req0), maps:get(pid, Req0)]
                 ),
                 logger:debug(
@@ -64,7 +64,7 @@
                 maps:get(pid, Req0), [{[{procedureError, abortedOrder}]}], 
Reason
             ),
             logger:info(
-                "Handling of IPAd request terminated unexpectedly, Reason=~p 
Pid=~p~n",
+                "Handling of IPAd request (ASN.1) terminated unexpectedly, 
Reason=~p Pid=~p~n",
                 [Reason, maps:get(pid, Req0)]
             ),
             cowboy_req:reply(500, ?RESPONSE_HEADERS, <<"Internal Server 
Error">>, Req0)
diff --git a/src/esipa_json_handler.erl b/src/esipa_json_handler.erl
index 62b4396..c5d8368 100644
--- a/src/esipa_json_handler.erl
+++ b/src/esipa_json_handler.erl
@@ -2,47 +2,419 @@
 %
 % SPDX-License-Identifier: AGPL-3.0-only
 %
+% Author: Philipp Maier <[email protected]> / sysmocom - s.f.m.c. GmbH
+
 -module(esipa_json_handler).
--behavior(cowboy_handler).

--export([init/2]).
+-export([handle_json/2]).

-init(Req0, State) ->
-    Path = cowboy_req:path(Req0),
-    Req =
-        case is_esipa_endpoint(Path) of
+% Decode hex-string to binary
+to_binary(absent) ->
+    absent;
+to_binary(HexStr) ->
+    utils:hex_to_binary(HexStr).
+
+% Encode binary to hex-string
+to_hex(absent) ->
+    absent;
+to_hex(Binary) ->
+    utils:binary_to_hex(Binary).
+
+% Decode binary from base64
+from_base64(absent) ->
+    absent;
+from_base64(ValueBase64) ->
+    base64:decode(ValueBase64).
+
+% Encode binary to base64
+to_base64(absent) ->
+    absent;
+to_base64(ValueBinary) ->
+    base64:encode(ValueBinary).
+
+% Decode base64 encoded string to map (ASN.1)
+from_base64asn1(_, _, absent) ->
+    absent;
+from_base64asn1(Asn1SpecName, Asn1TypeName, Asn1ValueBase64) ->
+    Asn1ValueBin = base64:decode(Asn1ValueBase64),
+    {ok, Asn1ValueMap} = Asn1SpecName:decode(Asn1TypeName, Asn1ValueBin),
+    Asn1ValueMap.
+
+% Encode map (ASN.1) to base64 encoded string
+to_base64asn1(_, _, absent) ->
+    absent;
+to_base64asn1(Asn1SpecName, Asn1TypeName, Asn1ValueMap) ->
+    {ok, Asn1ValueBin} = Asn1SpecName:encode(Asn1TypeName, Asn1ValueMap),
+    base64:encode(Asn1ValueBin).
+
+% Join a list of tuples into a map
+join_loop(Map, []) ->
+    Map;
+join_loop(Map, [TuplesHead | TuplesTail]) ->
+    {Key, Value} = TuplesHead,
+    case Value of
+        absent ->
+            join_loop(Map, TuplesTail);
+        _ ->
+            join_loop(maps:merge(Map, #{Key => Value}), TuplesTail)
+    end.
+join(Tuples) ->
+    join_loop(#{}, Tuples).
+
+% Chose the first (there should only be exactly one) non-absent member from 
the given tuple list
+choose([]) ->
+    throw("missing required JSON element (choice, oneOf)");
+choose([TuplesHead | TuplesTail]) ->
+    {_, Value} = TuplesHead,
+    case Value of
+        absent ->
+            choose(TuplesTail);
+        _ ->
+            TuplesHead
+    end.
+
+%GSMA SGP.32, section 6.4.1.1
+handle_json(Pid, {<<"/gsma/rsp2/esipa/initiateAuthentication">>, EsipaReq}) ->
+    Req = join([
+        {euiccChallenge, from_base64(maps:get(<<"euiccChallenge">>, EsipaReq, 
absent))},
+        {euiccInfo1,
+            from_base64asn1(
+                'RSPDefinitions', 'EUICCInfo1', maps:get(<<"euiccInfo1">>, 
EsipaReq, absent)
+            )},
+        {smdpAddress, maps:get(<<"smdpAddress">>, EsipaReq, absent)},
+        {eimTransactionId, to_binary(maps:get(<<"eimTransactionId">>, 
EsipaReq, absent))}
+    ]),
+    EsipaReqAsn = {initiateAuthenticationRequestEsipa, Req},
+
+    EimToIpaAsn = esipa_asn1_handler:handle_asn1(Pid, EsipaReqAsn),
+
+    case EimToIpaAsn of
+        {initiateAuthenticationResponseEsipa,
+            {initiateAuthenticationOkEsipa, InitiateAuthenticationOkEsipa}} ->
+            join([
+                {header, #{
+                    <<"functionExecutionStatus">> => #{<<"status">> => 
<<"Executed-Success">>}
+                }},
+                {transactionId,
+                    to_hex(maps:get(transactionId, 
InitiateAuthenticationOkEsipa, absent))},
+                {serverSigned1,
+                    to_base64asn1(
+                        'RSPDefinitions',
+                        'ServerSigned1',
+                        maps:get(serverSigned1, InitiateAuthenticationOkEsipa)
+                    )},
+                {serverSignature1,
+                    to_base64(maps:get(serverSignature1, 
InitiateAuthenticationOkEsipa))},
+                {euiccCiPKIdentifierToBeUsed,
+                    to_base64(
+                        maps:get(euiccCiPKIdentifierToBeUsed, 
InitiateAuthenticationOkEsipa)
+                    )},
+                {serverCertificate,
+                    to_base64asn1(
+                        'PKIX1Explicit88',
+                        'Certificate',
+                        maps:get(serverCertificate, 
InitiateAuthenticationOkEsipa)
+                    )},
+                {matchingId, maps:get(matchingId, 
InitiateAuthenticationOkEsipa, absent)},
+                {ctxParams1,
+                    to_base64asn1(
+                        'RSPDefinitions',
+                        'CtxParams1',
+                        maps:get(ctxParams1, InitiateAuthenticationOkEsipa, 
absent)
+                    )}
+            ]);
+        _ ->
+            join([{header, #{<<"functionExecutionStatus">> => #{<<"status">> 
=> <<"Failed">>}}}])
+    end;
+%GSMA SGP.32, section 6.4.1.2
+handle_json(Pid, {<<"/gsma/rsp2/esipa/authenticateClient">>, EsipaReq}) ->
+    Req = join([
+        {transactionId, to_binary(maps:get(<<"transactionId">>, EsipaReq))},
+        {authenticateServerResponse,
+            from_base64asn1(
+                'SGP32Definitions',
+                'SGP32-AuthenticateServerResponse',
+                maps:get(<<"authenticateServerResponse">>, EsipaReq)
+            )}
+    ]),
+    EsipaReqAsn = {authenticateClientRequestEsipa, Req},
+
+    EimToIpaAsn = esipa_asn1_handler:handle_asn1(Pid, EsipaReqAsn),
+
+    case EimToIpaAsn of
+        {authenticateClientResponseEsipa,
+            {authenticateClientOkDPEsipa, AuthenticateClientOkDPEsipa}} ->
+            join([
+                {header, #{
+                    <<"functionExecutionStatus">> => #{<<"status">> => 
<<"Executed-Success">>}
+                }},
+                {transactionId,
+                    to_hex(maps:get(transactionId, 
AuthenticateClientOkDPEsipa, absent))},
+                % (The profileMetadata field has different spellings, 
JSON:"profileMetadata", ASN.1:"profileMetaData")
+                {profileMetadata,
+                    to_base64asn1(
+                        'SGP32Definitions',
+                        'SGP32-StoreMetadataRequest',
+                        maps:get(profileMetaData, AuthenticateClientOkDPEsipa, 
absent)
+                    )},
+                {smdpSigned2,
+                    to_base64asn1(
+                        'RSPDefinitions',
+                        'SmdpSigned2',
+                        maps:get(smdpSigned2, AuthenticateClientOkDPEsipa)
+                    )},
+                {smdpSignature2,
+                    to_base64(
+                        maps:get(smdpSignature2, AuthenticateClientOkDPEsipa)
+                    )},
+                {smdpCertificate,
+                    to_base64asn1(
+                        'PKIX1Explicit88',
+                        'Certificate',
+                        maps:get(smdpCertificate, AuthenticateClientOkDPEsipa)
+                    )},
+                {hashCc,
+                    to_base64(
+                        maps:get(hashCc, AuthenticateClientOkDPEsipa, absent)
+                    )}
+            ]);
+        _ ->
+            join([{header, #{<<"functionExecutionStatus">> => #{<<"status">> 
=> <<"Failed">>}}}])
+    end;
+%GSMA SGP.32, section 6.4.1.3
+handle_json(Pid, {<<"/gsma/rsp2/esipa/getBoundProfilePackage">>, EsipaReq}) ->
+    Req = join([
+        {transactionId, to_binary(maps:get(<<"transactionId">>, EsipaReq))},
+        {prepareDownloadResponse,
+            from_base64asn1(
+                'SGP32Definitions',
+                'SGP32-PrepareDownloadResponse',
+                maps:get(<<"prepareDownloadResponse">>, EsipaReq)
+            )}
+    ]),
+    EsipaReqAsn = {getBoundProfilePackageRequestEsipa, Req},
+
+    EimToIpaAsn = esipa_asn1_handler:handle_asn1(Pid, EsipaReqAsn),
+
+    case EimToIpaAsn of
+        {getBoundProfilePackageResponseEsipa,
+            {getBoundProfilePackageOkEsipa, GetBoundProfilePackageOkEsipa}} ->
+            join([
+                {header, #{
+                    <<"functionExecutionStatus">> => #{<<"status">> => 
<<"Executed-Success">>}
+                }},
+                {transactionId,
+                    to_hex(maps:get(transactionId, 
GetBoundProfilePackageOkEsipa, absent))},
+                {boundProfilePackage,
+                    to_base64asn1(
+                        'RSPDefinitions',
+                        'BoundProfilePackage',
+                        maps:get(boundProfilePackage, 
GetBoundProfilePackageOkEsipa)
+                    )}
+            ]);
+        {getBoundProfilePackageResponseEsipa,
+            {getBoundProfilePackageErrorEsipa, 
_GetBoundProfilePackageErrorEsipa}} ->
+            join([{header, #{<<"functionExecutionStatus">> => #{<<"status">> 
=> <<"Failed">>}}}]);
+        _ ->
+            join([{header, #{<<"functionExecutionStatus">> => #{<<"status">> 
=> <<"Failed">>}}}])
+    end;
+%GSMA SGP.32, section 6.4.1.5
+handle_json(Pid, {<<"/gsma/rsp2/esipa/getEimPackage">>, EsipaReq}) ->
+    NotifyStateChange =
+        case maps:get(<<"notifyStateChange">>, EsipaReq, false) of
             true ->
-                cowboy_req:reply(
-                    501,
-                    #{
-                        <<"content-type">> => <<"application/json">>
-                    },
-                    <<"{}">>,
-                    Req0
-                );
-            false ->
-                cowboy_req:reply(
-                    404,
-                    #{
-                        <<"content-type">> => <<"text/plain">>
-                    },
-                    <<"Not Found">>,
-                    Req0
-                )
+                {notifyStateChange, 'NULL'};
+            _ ->
+                {notifyStateChange, absent}
         end,
-    {ok, Req, State}.
+    StateChangeCause =
+        case maps:get(<<"stateChangeCause">>, EsipaReq, absent) of
+            absent ->
+                {stateChangeCause, absent};
+            0 ->
+                {stateChangeCause, otherEim};
+            1 ->
+                {stateChangeCause, fallback};
+            2 ->
+                {stateChangeCause, emergencyProfile};
+            3 ->
+                {stateChangeCause, local};
+            4 ->
+                {stateChangeCause, reset};
+            5 ->
+                {stateChangeCause, immediateEnableProfile};
+            6 ->
+                {stateChangeCause, deviceChange};
+            7 ->
+                {stateChangeCause, undefined};
+            StateChangeCauseInt ->
+                % TODO: print warning
+                {stateChangeCause, StateChangeCauseInt}
+        end,
+    Req = join([
+        {eidValue, to_binary(maps:get(<<"eidValue">>, EsipaReq))},
+        NotifyStateChange,
+        StateChangeCause,
+        {rPLMN, to_binary(maps:get(<<"rPlmn">>, EsipaReq, absent))}
+    ]),
+    EsipaReqAsn = {getEimPackageRequest, Req},

-is_esipa_endpoint(Path) ->
-    lists:member(
-        Path,
-        [
-            <<"/gsma/rsp2/esipa/initiateAuthentication">>,
-            <<"/gsma/rsp2/esipa/authenticateClient">>,
-            <<"/gsma/rsp2/esipa/getBoundProfilePackage">>,
-            <<"/gsma/rsp2/esipa/transferEimPackage">>,
-            <<"/gsma/rsp2/esipa/getEimPackage">>,
-            <<"/gsma/rsp2/esipa/provideEimPackageResult">>,
-            <<"/gsma/rsp2/esipa/handleNotification">>,
-            <<"/gsma/rsp2/esipa/cancelSession">>
-        ]
-    ).
+    EimToIpaAsn = esipa_asn1_handler:handle_asn1(Pid, EsipaReqAsn),
+
+    case EimToIpaAsn of
+        {getEimPackageResponse, {euiccPackageRequest, EuiccPackageRequest}} ->
+            join([
+                {header, #{
+                    <<"functionExecutionStatus">> => #{<<"status">> => 
<<"Executed-Success">>}
+                }},
+                {euiccPackageRequest,
+                    to_base64asn1(
+                        'SGP32Definitions', 'EuiccPackageRequest', 
EuiccPackageRequest
+                    )}
+            ]);
+        {getEimPackageResponse, {ipaEuiccDataRequest, IpaEuiccDataRequest}} ->
+            join([
+                {header, #{
+                    <<"functionExecutionStatus">> => #{<<"status">> => 
<<"Executed-Success">>}
+                }},
+                {ipaEuiccDataRequest,
+                    to_base64asn1(
+                        'SGP32Definitions', 'IpaEuiccDataRequest', 
IpaEuiccDataRequest
+                    )}
+            ]);
+        {getEimPackageResponse, {profileDownloadTriggerRequest, 
ProfileDownloadTriggerRequest}} ->
+            join([
+                {header, #{
+                    <<"functionExecutionStatus">> => #{<<"status">> => 
<<"Executed-Success">>}
+                }},
+                {profileDownloadTriggerRequest,
+                    to_base64asn1(
+                        'SGP32Definitions',
+                        'ProfileDownloadTriggerRequest',
+                        ProfileDownloadTriggerRequest
+                    )}
+            ]);
+        {getEimPackageResponse, {eimPackageError, EimPackageError}} ->
+            EimPackageErrorInt =
+                case EimPackageError of
+                    noEimPackageAvailable ->
+                        1;
+                    eidNotFound ->
+                        2;
+                    invalidEid ->
+                        3;
+                    missingEid ->
+                        4;
+                    _ ->
+                        127
+                end,
+            join([
+                {header, #{
+                    <<"functionExecutionStatus">> => #{<<"status">> => 
<<"Executed-Success">>}
+                }},
+                {eimPackageError, EimPackageErrorInt}
+            ]);
+        _ ->
+            join([{header, #{<<"functionExecutionStatus">> => #{<<"status">> 
=> <<"Failed">>}}}])
+    end;
+%GSMA SGP.32, section 6.4.1.6
+handle_json(Pid, {<<"/gsma/rsp2/esipa/provideEimPackageResult">>, EsipaReq}) ->
+    Req = join([
+        {eidValue, to_binary(maps:get(<<"eidValue">>, EsipaReq, absent))},
+        {eimPackageResult,
+            from_base64asn1(
+                'SGP32Definitions', 'EimPackageResult', 
maps:get(<<"eimPackageResult">>, EsipaReq)
+            )}
+    ]),
+    EsipaReqAsn = {provideEimPackageResult, Req},
+
+    EimToIpaAsn = esipa_asn1_handler:handle_asn1(Pid, EsipaReqAsn),
+
+    case EimToIpaAsn of
+        {provideEimPackageResultResponse, {eimAcknowledgements, 
EimAcknowledgements}} ->
+            join([
+                {header, #{
+                    <<"functionExecutionStatus">> => #{<<"status">> => 
<<"Executed-Success">>}
+                }},
+                {eimAcknowledgements,
+                    to_base64asn1(
+                        'SGP32Definitions', 'EimAcknowledgements', 
EimAcknowledgements
+                    )}
+            ]);
+        {provideEimPackageResultResponse, {emptyResponse, #{}}} ->
+            join([
+                {header, #{
+                    <<"functionExecutionStatus">> => #{<<"status">> => 
<<"Executed-Success">>}
+                }}
+            ]);
+        {provideEimPackageResultError,
+            {provideEimPackageResultError, _ProvideEimPackageResultError}} ->
+            join([{header, #{<<"functionExecutionStatus">> => #{<<"status">> 
=> <<"Failed">>}}}]);
+        _ ->
+            join([{header, #{<<"functionExecutionStatus">> => #{<<"status">> 
=> <<"Failed">>}}}])
+    end;
+%GSMA SGP.32, section 6.4.1.7
+handle_json(Pid, {<<"/gsma/rsp2/esipa/handleNotification">>, EsipaReq}) ->
+    Req = choose([
+        {pendingNotification,
+            from_base64asn1(
+                'SGP32Definitions',
+                'SGP32-PendingNotification',
+                maps:get(<<"pendingNotification">>, EsipaReq, absent)
+            )},
+        {provideEimPackageResult,
+            from_base64asn1(
+                'SGP32Definitions',
+                'ProvideEimPackageResult',
+                maps:get(<<"provideEimPackageResult">>, EsipaReq, absent)
+            )}
+    ]),
+    EsipaReqAsn = {handleNotificationEsipa, Req},
+
+    EimToIpaAsn = esipa_asn1_handler:handle_asn1(Pid, EsipaReqAsn),
+
+    case EimToIpaAsn of
+        emptyResponse ->
+            join([
+                {header, #{
+                    <<"functionExecutionStatus">> => #{<<"status">> => 
<<"Executed-Success">>}
+                }}
+            ]);
+        _ ->
+            join([{header, #{<<"functionExecutionStatus">> => #{<<"status">> 
=> <<"Failed">>}}}])
+    end;
+%GSMA SGP.32, section 6.4.1.8
+handle_json(Pid, {<<"/gsma/rsp2/esipa/cancelSession">>, EsipaReq}) ->
+    Req = join([
+        {transactionId, to_binary(maps:get(<<"transactionId">>, EsipaReq))},
+        {cancelSessionResponse,
+            from_base64asn1(
+                'SGP32Definitions',
+                'SGP32-CancelSessionResponse',
+                maps:get(<<"cancelSessionResponse">>, EsipaReq)
+            )}
+    ]),
+    EsipaReqAsn = {cancelSessionRequestEsipa, Req},
+
+    EimToIpaAsn = esipa_asn1_handler:handle_asn1(Pid, EsipaReqAsn),
+
+    case EimToIpaAsn of
+        {cancelSessionResponseEsipa, {cancelSessionOk, _CancelSessionOk}} ->
+            join([
+                {header, #{
+                    <<"functionExecutionStatus">> => #{<<"status">> => 
<<"Executed-Success">>}
+                }}
+            ]);
+        {cancelSessionResponseEsipa, {cancelSessionError, 
_CancelSessionError}} ->
+            join([{header, #{<<"functionExecutionStatus">> => #{<<"status">> 
=> <<"Failed">>}}}]);
+        _ ->
+            join([{header, #{<<"functionExecutionStatus">> => #{<<"status">> 
=> <<"Failed">>}}}])
+    end;
+%Unsupported request
+handle_json(Pid, Request) ->
+    mnesia_db_work:finish(Pid, [{[{procedureError, abortedOrder}]}], 
unsupported),
+    logger:info(
+        "Handling of IPAd request failed, the request type is 
unsupported,~nRequest=~p,~nPid=~p~n",
+        [Request, Pid]
+    ),
+    {error, unsupported_request}.
diff --git a/src/esipa_json_http_handler.erl b/src/esipa_json_http_handler.erl
new file mode 100644
index 0000000..7d2de97
--- /dev/null
+++ b/src/esipa_json_http_handler.erl
@@ -0,0 +1,66 @@
+% Copyright (c) 2025 Onomondo ApS & sysmocom - s.f.m.c. GmbH. All rights 
reserved.
+%
+% SPDX-License-Identifier: AGPL-3.0-only
+%
+-module(esipa_json_http_handler).
+-behavior(cowboy_handler).
+
+-define(RESPONSE_HEADERS, #{
+    <<"content-type">> => <<"application/json;charset=UTF-8">>,
+    <<"x-admin-protocol">> => <<"gsma/rsp/v2.1.0">>
+}).
+
+-export([init/2, terminate/3]).
+
+init(Req0, State) ->
+    Req =
+        case cowboy_req:header(<<"content-type">>, Req0) of
+            <<"application/json;charset=UTF-8">> ->
+                {ok, Data, _Req1} = cowboy_req:read_body(Req0),
+                IpaToEim = jiffy:decode(Data, [return_maps]),
+                Path = cowboy_req:path(Req0),
+                logger:info(
+                    "Handling incoming IPAd request (JSON): ~p,~nPeer=~p, 
Pid=~p~n",
+                    [Path, maps:get(peer, Req0), maps:get(pid, Req0)]
+                ),
+                logger:debug(
+                    "Rx ESipa JSON,~nPeer=~p, Pid=~p,~nIpaToEim=~p~n",
+                    [maps:get(peer, Req0), maps:get(pid, Req0), IpaToEim]
+                ),
+                EimToIpa = esipa_json_handler:handle_json(maps:get(pid, Req0), 
{Path, IpaToEim}),
+                logger:debug(
+                    "Tx ESipa JSON,~nPeer=~p,Pid=~p,~nEimToIpa=~p~n",
+                    [maps:get(peer, Req0), maps:get(pid, Req0), EimToIpa]
+                ),
+                case EimToIpa of
+                    {error, unsupported_request} ->
+                        cowboy_req:reply(
+                            400,
+                            ?RESPONSE_HEADERS,
+                            <<"Unsupported Request">>,
+                            Req0
+                        );
+                    _ ->
+                        EncodedRespBody = jiffy:encode(EimToIpa, [force_utf8]),
+                        cowboy_req:reply(200, ?RESPONSE_HEADERS, 
EncodedRespBody, Req0)
+                end;
+            _ ->
+                cowboy_req:reply(415, ?RESPONSE_HEADERS, <<"Unsupported 
content-type">>, Req0)
+        end,
+    {ok, Req, State}.
+
+% Handle termination of HTTP requests
+terminate(Reason, Req0, _State) ->
+    case Reason of
+        normal ->
+            ok;
+        _ ->
+            mnesia_db_work:finish(
+                maps:get(pid, Req0), [{[{procedureError, abortedOrder}]}], 
Reason
+            ),
+            logger:info(
+                "Handling of IPAd request (JSON) terminated unexpectedly, 
Reason=~p Pid=~p~n",
+                [Reason, maps:get(pid, Req0)]
+            ),
+            cowboy_req:reply(500, ?RESPONSE_HEADERS, <<"Internal Server 
Error">>, Req0)
+    end.
diff --git a/src/onomondo_eim_app.erl b/src/onomondo_eim_app.erl
index 89ffd4a..e796c96 100644
--- a/src/onomondo_eim_app.erl
+++ b/src/onomondo_eim_app.erl
@@ -51,7 +51,7 @@
     cowboy_router:compile([
         {'_', [
             % SGP.32 Section 6.4.1
-            {"/gsma/rsp2/esipa/[...]", esipa_json_handler, []},
+            {"/gsma/rsp2/esipa/[...]", esipa_json_http_handler, []},
             % SGP.32 Section 6.1.1: Any function execution request using ASN.1 
binding SHALL be sent to the generic
             % HTTP path 'gsma/rsp2/asn1'
             {"/gsma/rsp2/asn1", esipa_asn1_http_handler, []},

--
To view, visit https://gerrit.osmocom.org/c/onomondo-eim/+/43175?usp=email
To unsubscribe, or for help writing mail filters, visit 
https://gerrit.osmocom.org/settings?usp=email

Gerrit-MessageType: newchange
Gerrit-Project: onomondo-eim
Gerrit-Branch: master
Gerrit-Change-Id: Id73ae78a976608fe6f367f8c3b92d8b7b4e195d4
Gerrit-Change-Number: 43175
Gerrit-PatchSet: 1
Gerrit-Owner: dexter <[email protected]>

Reply via email to