From 9865d0618c5f33b1c02a01f9875ab259b6e99d6f Mon Sep 17 00:00:00 2001 From: Grigory Starinkin Date: Wed, 3 Dec 2025 10:41:18 +0000 Subject: [PATCH 1/2] upgrade opentelemetry_api to 1.5.0 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This to fix the following compilation error on test: ``` $ rebar3 ct ===> Verifying dependencies... ===> Analyzing applications... ===> Compiling opentelemetry ===> Compiling _build/test/lib/opentelemetry/src/otel_span_utils.erl failed ┌─ _build/test/lib/opentelemetry/src/otel_span_utils.erl: │ 92 │ {ParentSpanCtx#span_ctx{span_id=SpanId, hex_span_id=HexSpanId}, ParentSpanId, ParentIsRemote} │ ╰── field hex_span_id undefined in record span_ctx ┌─ _build/test/lib/opentelemetry/src/otel_span_utils.erl: │ 101 │ hex_trace_id=HexTraceId, │ ╰── field hex_trace_id undefined in record span_ctx ┌─ _build/test/lib/opentelemetry/src/otel_span_utils.erl: │ 103 │ hex_span_id=HexSpanId, │ ╰── field hex_span_id undefined in record span_ctx ┌─ _build/test/lib/opentelemetry/src/otel_span_utils.erl: │ 91 │ HexSpanId = otel_utils:encode_hex(<>), │ ╰── Warning: variable 'HexSpanId' is unused ┌─ _build/test/lib/opentelemetry/src/otel_span_utils.erl: │ 97 │ HexTraceId = otel_utils:encode_hex(<>), │ ╰── Warning: variable 'HexTraceId' is unused ┌─ _build/test/lib/opentelemetry/src/otel_span_utils.erl: │ 99 │ HexSpanId = otel_utils:encode_hex(<>), │ ╰── Warning: variable 'HexSpanId' is unused ``` this is necessary as there are new fields got introduced in the the https://github.com/open-telemetry/opentelemetry-erlang/pull/874 --- instrumentation/opentelemetry_cowboy/rebar.lock | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/instrumentation/opentelemetry_cowboy/rebar.lock b/instrumentation/opentelemetry_cowboy/rebar.lock index 1ec82aab..a050d192 100644 --- a/instrumentation/opentelemetry_cowboy/rebar.lock +++ b/instrumentation/opentelemetry_cowboy/rebar.lock @@ -2,7 +2,7 @@ [{<<"cowboy">>,{pkg,<<"cowboy">>,<<"2.12.0">>},1}, {<<"cowboy_telemetry">>,{pkg,<<"cowboy_telemetry">>,<<"0.4.0">>},0}, {<<"cowlib">>,{pkg,<<"cowlib">>,<<"2.13.0">>},2}, - {<<"opentelemetry_api">>,{pkg,<<"opentelemetry_api">>,<<"1.4.0">>},0}, + {<<"opentelemetry_api">>,{pkg,<<"opentelemetry_api">>,<<"1.5.0">>},0}, {<<"opentelemetry_semantic_conventions">>, {pkg,<<"opentelemetry_semantic_conventions">>,<<"1.27.0">>}, 0}, @@ -17,7 +17,7 @@ {<<"cowboy">>, <<"F276D521A1FF88B2B9B4C54D0E753DA6C66DD7BE6C9FCA3D9418B561828A3731">>}, {<<"cowboy_telemetry">>, <<"F239F68B588EFA7707ABCE16A84D0D2ACF3A0F50571F8BB7F56A15865AAE820C">>}, {<<"cowlib">>, <<"DB8F7505D8332D98EF50A3EF34B34C1AFDDEC7506E4EE4DD4A3A266285D282CA">>}, - {<<"opentelemetry_api">>, <<"63CA1742F92F00059298F478048DFB826F4B20D49534493D6919A0DB39B6DB04">>}, + {<<"opentelemetry_api">>, <<"1A676F3E3340CAB81C763E939A42E11A70C22863F645AA06AAFEFC689B5550CF">>}, {<<"opentelemetry_semantic_conventions">>, <<"ACD0194A94A1E57D63DA982EE9F4A9F88834AE0B31B0BD850815FE9BE4BBB45F">>}, {<<"opentelemetry_telemetry">>, <<"410AB4D76B0921F42DBCCBE5A7C831B8125282850BE649EE1F70050D3961118A">>}, {<<"otel_http">>, <<"B17385986C7F1B862F5D577F72614ECAA29DE40392B7618869999326B9A61D8A">>}, @@ -27,7 +27,7 @@ {<<"cowboy">>, <<"8A7ABE6D183372CEB21CAA2709BEC928AB2B72E18A3911AA1771639BEF82651E">>}, {<<"cowboy_telemetry">>, <<"7D98BAC1EE4565D31B62D59F8823DFD8356A169E7FCBB83831B8A5397404C9DE">>}, {<<"cowlib">>, <<"E1E1284DC3FC030A64B1AD0D8382AE7E99DA46C3246B815318A4B848873800A4">>}, - {<<"opentelemetry_api">>, <<"3DFBBFAA2C2ED3121C5C483162836C4F9027DEF469C41578AF5EF32589FCFC58">>}, + {<<"opentelemetry_api">>, <<"F53EC8A1337AE4A487D43AC89DA4BD3A3C99DDF576655D071DEED8B56A2D5DDA">>}, {<<"opentelemetry_semantic_conventions">>, <<"9681CCAA24FD3D810B4461581717661FD85FF7019B082C2DFF89C7D5B1FC2864">>}, {<<"opentelemetry_telemetry">>, <<"641AB469DEB181957AC6D59BCE6E1321D5FE2A56DF444FC9C19AFCAD623AB253">>}, {<<"otel_http">>, <<"F2BEADF922C8CFEB0965488DD736C95CC6EA8B9EFCE89466B3904D317D7CC717">>}, From 71cca4b6cdefc16108ca2029046c1dd3c9993cf7 Mon Sep 17 00:00:00 2001 From: Grigory Starinkin Date: Wed, 3 Dec 2025 10:46:48 +0000 Subject: [PATCH 2/2] fix(opentelemetry_cowboy): prevent telemetry handler crash on invalid HTTP/2 scheme Cowboy does not validate the `:scheme` pseudo-header per RFC 9113, which states that scheme "is not restricted to http and https" and can be used for non-HTTP schemes via proxies/gateways. This means Cowboy passes through any value from the HTTP/2 HEADERS frame without validation. When a malformed or unexpected scheme value reaches `extract_scheme/2`, the case clause crashes because it only handles `<<"http">>` and `<<"https">>`. This crash causes Erlang's telemetry library to permanently detach the handler for the affected node, resulting in all subsequent requests losing OpenTelemetry tracing until the node is restarted. In production, this manifests as "almost all" requests suddenly missing trace IDs, with the root cause being a single malformed HTTP/2 request that crashed the telemetry handler. The fix introduces a configurable `valid_schemes` option that maps scheme binaries to atoms. Unknown schemes now return `undefined` instead of crashing, which is consistent with how `otel_http:extract_scheme/2` already handles unknown schemes from headers. The default configuration preserves backwards compatibility by only accepting `http` and `https`. Users who need to support additional schemes (e.g., `ws`, `wss`) can extend the map via configuration. Reproduction repository: https://github.com/velimir/scheme_crash Fixes: https://github.com/open-telemetry/opentelemetry-erlang-contrib/issues/567 --- .../src/opentelemetry_cowboy.erl | 14 ++++++------- .../test/opentelemetry_cowboy_SUITE.erl | 20 ++++++++++++++++++- 2 files changed, 25 insertions(+), 9 deletions(-) diff --git a/instrumentation/opentelemetry_cowboy/src/opentelemetry_cowboy.erl b/instrumentation/opentelemetry_cowboy/src/opentelemetry_cowboy.erl index 8c31ce4f..6e341e6c 100644 --- a/instrumentation/opentelemetry_cowboy/src/opentelemetry_cowboy.erl +++ b/instrumentation/opentelemetry_cowboy/src/opentelemetry_cowboy.erl @@ -95,7 +95,8 @@ default_opts() -> scheme_headers => [<<"forwarded">>, <<"x-forwarded-proto">>], scheme_headers_sort_fn => undefined, server_address_headers => [<<"forwarded">>, <<"x-forwarded-host">>, <<"host">>], - server_address_headers_sort_fn => undefined + server_address_headers_sort_fn => undefined, + valid_schemes => #{<<"http">> => http, <<"https">> => https} }. ?DOC(""" @@ -114,6 +115,7 @@ Supported options: * `scheme_headers_sort_fn` - Custom scheme header sort fn. See `otel_http` for more info. Default: `undefined` * `server_address_headers` - Headers to use for extracting original server address info. Default: `[<<"forwarded">>, <<"x-forwarded-host">>, <<"host">>]` * `server_address_headers_sort_fn` - Custom server header sort fn. See `otel_http` for more info. Default: `undefined` +* `valid_schemes` - Map of valid scheme binaries to atoms. Unknown schemes return `undefined`. Default: `#{<<"http">> => http, <<"https">> => https}` """). -spec setup() -> ok. setup() -> @@ -227,7 +229,8 @@ otel_http_extract_scheme(Headers, SortFn) -> extract_scheme(Req, Config) -> #{ scheme_headers := SchemeHeaders, - scheme_headers_sort_fn := SortFn + scheme_headers_sort_fn := SortFn, + valid_schemes := ValidSchemes } = Config, #{ headers := Headers, @@ -236,12 +239,7 @@ extract_scheme(Req, Config) -> SchemeHeaders1 = extract_headers(Headers, SchemeHeaders), case otel_http_extract_scheme(SchemeHeaders1, SortFn) of undefined -> - case ReqScheme of - <<"http">> -> - http; - <<"https">> -> - https - end; + maps:get(ReqScheme, ValidSchemes, undefined); ParsedScheme -> ParsedScheme end. diff --git a/instrumentation/opentelemetry_cowboy/test/opentelemetry_cowboy_SUITE.erl b/instrumentation/opentelemetry_cowboy/test/opentelemetry_cowboy_SUITE.erl index cda7cf64..be0dc4ed 100644 --- a/instrumentation/opentelemetry_cowboy/test/opentelemetry_cowboy_SUITE.erl +++ b/instrumentation/opentelemetry_cowboy/test/opentelemetry_cowboy_SUITE.erl @@ -31,7 +31,8 @@ all() -> idle_timeout_request, chunk_timeout_request, bad_request, - binary_status_code_request + binary_status_code_request, + invalid_scheme_returns_undefined ]. init_per_suite(Config) -> @@ -507,3 +508,20 @@ binary_status_code_request(_Config) -> after 1000 -> ct:fail(binary_status_code_request) end. + +invalid_scheme_returns_undefined(_Config) -> + Opts = #{ + valid_schemes => #{<<"https">> => https} + }, + opentelemetry_cowboy:setup(Opts), + Port = 62662, + {ok, {{_Version, 200, _ReasonPhrase}, _Headers, _Body}} = + httpc:request(get, {"http://localhost:8080/success", []}, [], [{socket_opts, [{port, Port}]}]), + receive + {span, #span{name=Name,attributes=Attributes,kind=Kind}} -> + ?assertEqual('GET', Name), + ?assertEqual(?SPAN_KIND_SERVER, Kind), + ?assertEqual(undefined, maps:get(?URL_SCHEME, otel_attributes:map(Attributes))) + after + 1000 -> ct:fail(invalid_scheme_returns_undefined) + end.