diff --git a/.gitmodules b/.gitmodules index 07cd7d41d2389e..342921210124da 100644 --- a/.gitmodules +++ b/.gitmodules @@ -331,3 +331,7 @@ url = https://github.com/awslabs/amazon-kinesis-video-streams-webrtc-sdk-c platforms = esp32 recursive = true +[submodule "third_party/uriparser/repo"] + path = third_party/uriparser/repo + url = https://github.com/uriparser/uriparser.git + branch = uriparser-0.9.9 \ No newline at end of file diff --git a/src/app/clusters/push-av-stream-transport-server/BUILD.gn b/src/app/clusters/push-av-stream-transport-server/BUILD.gn index b7322b244432e4..002b77489d400b 100644 --- a/src/app/clusters/push-av-stream-transport-server/BUILD.gn +++ b/src/app/clusters/push-av-stream-transport-server/BUILD.gn @@ -30,6 +30,7 @@ source_set("push-av-stream-transport-server") { "${chip_root}/src/app/clusters/tls-client-management-server", "${chip_root}/src/app/server-cluster", "${chip_root}/src/lib/core:types", + "${chip_root}/third_party/uriparser:uriparser", "${chip_root}/zzz_generated/app-common/clusters/PushAvStreamTransport", ] public_configs = [ "${chip_root}/src:includes" ] diff --git a/src/app/clusters/push-av-stream-transport-server/app_config_dependent_sources.cmake b/src/app/clusters/push-av-stream-transport-server/app_config_dependent_sources.cmake index 0053a93e48257a..36a0cd8c9071b0 100644 --- a/src/app/clusters/push-av-stream-transport-server/app_config_dependent_sources.cmake +++ b/src/app/clusters/push-av-stream-transport-server/app_config_dependent_sources.cmake @@ -23,4 +23,11 @@ TARGET_SOURCES( "${CLUSTER_DIR}/push-av-stream-transport-delegate.h" "${CLUSTER_DIR}/CodegenIntegration.cpp" "${CLUSTER_DIR}/CodegenIntegration.h" -) \ No newline at end of file +) + +# Build and link uriparser library +if(NOT TARGET uriparser::uriparser) + add_subdirectory("${CHIP_ROOT}/third_party/uriparser" "${CMAKE_BINARY_DIR}/uriparser") +endif() + +target_link_libraries(${APP_TARGET} PRIVATE uriparser::uriparser) \ No newline at end of file diff --git a/src/app/clusters/push-av-stream-transport-server/push-av-stream-transport-logic.cpp b/src/app/clusters/push-av-stream-transport-server/push-av-stream-transport-logic.cpp index b2a2a53ef7fc45..8d9060e4098ca5 100644 --- a/src/app/clusters/push-av-stream-transport-server/push-av-stream-transport-logic.cpp +++ b/src/app/clusters/push-av-stream-transport-server/push-av-stream-transport-logic.cpp @@ -30,6 +30,7 @@ #include #include #include +#include static constexpr uint16_t kMaxConnectionId = 65535; // This is also invalid connectionID static constexpr uint16_t kMaxEndpointId = 65534; @@ -43,6 +44,34 @@ using namespace chip::app::Clusters::PushAvStreamTransport::Attributes; using namespace Protocols::InteractionModel; using chip::Protocols::InteractionModel::Status; +namespace { +bool hasHttpsScheme(const UriUriA & uri) +{ + if (!uri.scheme.first || !uri.scheme.afterLast) + return false; + + std::string scheme(uri.scheme.first, uri.scheme.afterLast); + return scheme == "https"; +} + +bool isValidRFC3986Uri(const std::string & uriStr) +{ + UriUriA uri; + const char * errorPos; + + int result = uriParseSingleUriA(&uri, uriStr.c_str(), &errorPos); + if (result != URI_SUCCESS) + { + return false; + } + + bool isHttps = hasHttpsScheme(uri); + + uriFreeUriMembersA(&uri); + return isHttps; +} +} // namespace + namespace chip { namespace app { namespace Clusters { @@ -234,14 +263,14 @@ void PushAvStreamTransportServerLogic::PushAVStreamTransportDeallocateCallback(S bool PushAvStreamTransportServerLogic::ValidateUrl(const std::string & url) { - const std::string https = "https://"; - - // Check minimum length and https prefix - if (url.size() <= https.size() || url.substr(0, https.size()) != https) + if (!isValidRFC3986Uri(url)) { + ChipLogError(Camera, "URL is not a valid RFC3986 URI: %s", url.c_str()); return false; } + const std::string https = "https://"; + // Check that URL does not contain fragment character '#' if (url.find('#') != std::string::npos) { diff --git a/third_party/uriparser/BUILD.gn b/third_party/uriparser/BUILD.gn new file mode 100644 index 00000000000000..de48e3db7329ef --- /dev/null +++ b/third_party/uriparser/BUILD.gn @@ -0,0 +1,101 @@ +# Copyright (c) 2024 Project CHIP Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import("//build_overrides/build.gni") +import("//build_overrides/chip.gni") + +config("uriparser_config") { + include_dirs = [ + "repo/include", + ".", + ] + + # Enable both char and wchar_t support by default + defines = [ + "URI_ENABLE_ANSI=1", + "URI_ENABLE_UNICODE=1", + ] +} + +config("uriparser_config_disable_warnings") { + cflags = [ + "-Wno-unused-parameter", + "-Wno-shadow", + ] +} + +source_set("uriparser") { + sources = [ + # Header files + "UriConfig.h", + "repo/include/uriparser/Uri.h", + "repo/include/uriparser/UriBase.h", + "repo/include/uriparser/UriDefsAnsi.h", + "repo/include/uriparser/UriDefsConfig.h", + "repo/include/uriparser/UriDefsUnicode.h", + "repo/include/uriparser/UriIp4.h", + + # Source files + "repo/src/UriCommon.c", + "repo/src/UriCommon.h", + "repo/src/UriCompare.c", + "repo/src/UriCopy.c", + "repo/src/UriCopy.h", + "repo/src/UriEscape.c", + "repo/src/UriFile.c", + "repo/src/UriIp4.c", + "repo/src/UriIp4Base.c", + "repo/src/UriIp4Base.h", + "repo/src/UriMemory.c", + "repo/src/UriMemory.h", + "repo/src/UriNormalize.c", + "repo/src/UriNormalize.h", + "repo/src/UriNormalizeBase.c", + "repo/src/UriNormalizeBase.h", + "repo/src/UriParse.c", + "repo/src/UriParseBase.c", + "repo/src/UriParseBase.h", + "repo/src/UriQuery.c", + "repo/src/UriRecompose.c", + "repo/src/UriResolve.c", + "repo/src/UriSetFragment.c", + "repo/src/UriSetHostAuto.c", + "repo/src/UriSetHostBase.h", + "repo/src/UriSetHostCommon.c", + "repo/src/UriSetHostCommon.h", + "repo/src/UriSetHostIp4.c", + "repo/src/UriSetHostIp6.c", + "repo/src/UriSetHostIpFuture.c", + "repo/src/UriSetHostRegName.c", + "repo/src/UriSetPath.c", + "repo/src/UriSetPort.c", + "repo/src/UriSetQuery.c", + "repo/src/UriSetScheme.c", + "repo/src/UriSetUserInfo.c", + "repo/src/UriShorten.c", + "repo/src/UriVersion.c", + ] + + public_configs = [ ":uriparser_config" ] + + configs += [ ":uriparser_config_disable_warnings" ] + + # Build as static library by default + defines = [ + "URI_LIBRARY_BUILD", + "URI_STATIC_BUILD", + ] + + include_dirs = [ "repo/src" ] +} diff --git a/third_party/uriparser/CMakeLists.txt b/third_party/uriparser/CMakeLists.txt new file mode 100644 index 00000000000000..df68f5033290af --- /dev/null +++ b/third_party/uriparser/CMakeLists.txt @@ -0,0 +1,64 @@ +# +# Copyright (c) 2025 Project CHIP Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +# CMakeLists.txt for building uriparser as a library +# This can be used with ESP-IDF via add_subdirectory +# + +if(NOT TARGET uriparser::uriparser) + # Collect all source files + file(GLOB URIPARSER_SOURCES + "${CMAKE_CURRENT_SOURCE_DIR}/repo/src/*.c" + ) + + # Create static library + add_library(uriparser STATIC ${URIPARSER_SOURCES}) + add_library(uriparser::uriparser ALIAS uriparser) + + # Set include directories + target_include_directories(uriparser PUBLIC + "${CMAKE_CURRENT_SOURCE_DIR}/repo/include" + "$" + ) + + target_include_directories(uriparser PRIVATE + "${CMAKE_CURRENT_SOURCE_DIR}/repo/src" + "${CMAKE_CURRENT_SOURCE_DIR}" + ) + + # Add compile definitions matching BUILD.gn + target_compile_definitions(uriparser PRIVATE + URI_LIBRARY_BUILD + URI_STATIC_BUILD + ) + + target_compile_definitions(uriparser PUBLIC + URI_ENABLE_ANSI=1 + URI_ENABLE_UNICODE=1 + ) + + # Disable warnings for uriparser source files + target_compile_options(uriparser PRIVATE + -Wno-unused-parameter + -Wno-shadow + -Wno-sign-conversion + ) + + set_target_properties(uriparser PROPERTIES + C_STANDARD 99 + C_STANDARD_REQUIRED ON + C_EXTENSIONS ON + ) +endif() diff --git a/third_party/uriparser/UriConfig.h b/third_party/uriparser/UriConfig.h new file mode 100644 index 00000000000000..fdc12d3ba6c3b1 --- /dev/null +++ b/third_party/uriparser/UriConfig.h @@ -0,0 +1,11 @@ +#ifndef URI_CONFIG_H +#define URI_CONFIG_H + +/* Universal configuration for uriparser - works on all platforms */ +#define PACKAGE_VERSION "0.9.9" + +/* Disable optional features for maximum compatibility */ +/* #undef HAVE_WPRINTF */ +/* #undef HAVE_REALLOCARRAY */ + +#endif /* !defined(URI_CONFIG_H) */ diff --git a/third_party/uriparser/repo b/third_party/uriparser/repo new file mode 160000 index 00000000000000..1d7403f9788600 --- /dev/null +++ b/third_party/uriparser/repo @@ -0,0 +1 @@ +Subproject commit 1d7403f97886002ad2d0ef3f0377b49a0725a3c2