diff options
29 files changed, 1401 insertions, 234 deletions
diff --git a/src/3rd_party/CMakeLists.txt b/src/3rd_party/CMakeLists.txt index c0c6bbfa67..951c437e59 100644 --- a/src/3rd_party/CMakeLists.txt +++ b/src/3rd_party/CMakeLists.txt @@ -169,12 +169,13 @@ if(ENABLE_LOG) endif() set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_CURRENT_SOURCE_DIR}") -set(CMAKE_SOURCE_PREFIX ${CMAKE_SOURCE_PREFIX} "${3RD_PARTY_INSTALL_PREFIX}") -find_package (BSON) -message (STATUS "bson installed in " ${BSON_LIBS_DIRECTORY} " , " ${BSON_INCLUDE_DIRECTORY}) -message (STATUS "emhashmap installed in " ${EMHASHMAP_LIBS_DIRECTORY} " , " ${EMHASHMAP_INCLUDE_DIRECTORY}) +set(CMAKE_PREFIX_PATH ${CMAKE_PREFIX_PATH} "${3RD_PARTY_INSTALL_PREFIX}/etc") +set(ENV{PKG_CONFIG_PATH} $ENV{CMAKE_PREFIX_PATH} "${3RD_PARTY_INSTALL_PREFIX}/etc") +find_package(PkgConfig) +pkg_check_modules(BSON libbson) +message (STATUS "bson installed in " ${BSON_LIBDIR} ", " ${BSON_INCLUDEDIR}) -if (${BSON_LIB} MATCHES "BSON_LIB-NOTFOUND") +if ((NOT "${BSON_FOUND}") OR ("${BSON_VERSION}" VERSION_LESS "1.2.0")) message (STATUS "Building bson required") set(BSON_LIB_SOURCE_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/bson_c_lib CACHE INTERNAL "Sources of bson library" FORCE) set(BSON_LIBS_DIRECTORY ${3RD_PARTY_INSTALL_PREFIX}/lib CACHE INTERNAL "Installation path of bson libraries" FORCE) @@ -188,20 +189,19 @@ if (${BSON_LIB} MATCHES "BSON_LIB-NOTFOUND") endif() include(ExternalProject) ExternalProject_Add(libbson - GIT_REPOSITORY "http://github.com/smartdevicelink/bson_c_lib.git" + GIT_REPOSITORY "https://github.com/smartdevicelink/bson_c_lib.git" GIT_TAG "master" BINARY_DIR ${BSON_LIB_SOURCE_DIRECTORY} INSTALL_DIR ${3RD_PARTY_INSTALL_PREFIX} DOWNLOAD_DIR ${BSON_LIB_SOURCE_DIRECTORY} SOURCE_DIR ${BSON_LIB_SOURCE_DIRECTORY} - CONFIGURE_COMMAND touch aclocal.m4 configure.ac Makefile.am Makefile.in configure config.h.in && ./configure --prefix=${3RD_PARTY_INSTALL_PREFIX} + CONFIGURE_COMMAND touch aclocal.m4 configure.ac Makefile.am Makefile.in configure config.h.in libbson.pc.in && ./configure --prefix=${3RD_PARTY_INSTALL_PREFIX} BUILD_COMMAND make - INSTALL_COMMAND ${BSON_INSTALL_COMMAND}) + INSTALL_COMMAND ${BSON_INSTALL_COMMAND} + UPDATE_COMMAND git pull) else() - get_filename_component(BSON_LIBS_DIRECTORY ${BSON_LIB} DIRECTORY) - get_filename_component(EMHASHMAP_LIBS_DIRECTORY ${EMHASHMAP_LIB} DIRECTORY) - set(BSON_LIBS_DIRECTORY ${BSON_LIBS_DIRECTORY} CACHE INTERNAL "Installation path of bson libraries" FORCE) - set(EMHASHMAP_LIBS_DIRECTORY ${BSON_LIBS_DIRECTORY} CACHE INTERNAL "Installation path of emashmap libraries" FORCE) + set(BSON_LIBS_DIRECTORY ${BSON_LIBDIR} CACHE INTERNAL "Installation path of bson libraries" FORCE) + set(EMHASHMAP_LIBS_DIRECTORY ${BSON_LIBDIR} CACHE INTERNAL "Installation path of emashmap libraries" FORCE) add_custom_target( libbson DEPENDS ${BSON_LIBS_DIRECTORY} diff --git a/src/3rd_party/FindBSON.cmake b/src/3rd_party/FindBSON.cmake deleted file mode 100644 index 91d53624f1..0000000000 --- a/src/3rd_party/FindBSON.cmake +++ /dev/null @@ -1,26 +0,0 @@ -set(INCLUDE_PATH "${CMAKE_SOURCE_PREFIX}/include") -set(LIB_PATH "${CMAKE_SOURCE_PREFIX}/lib") - -find_path(BSON_INCLUDE_DIRECTORY bson_object.h bson_array.h bson_util.h - PATHS "${INCLUDE_PATH}") - -find_library(BSON_LIB - NAMES bson - PATHS ${LIB_PATH}) - -find_path(EMHASHMAP_INCLUDE_DIRECTORY emhashmap.h - PATHS ${INCLUDE_PATH} - PATH_SUFFIXES emhashmap) - -find_library(EMHASHMAP_LIB - NAMES emhashmap - PATHS ${LIB_PATH}) - - -include(FindPackageHandleStandardArgs) - -find_package_handle_standard_args(BSON DEFAULT_MSG BSON_INCLUDE_DIRECTORY BSON_LIB - EMHASHMAP_INCLUDE_DIRECTORY EMHASHMAP_LIB) - -mark_as_advanced(BSON_INCLUDE_DIRECTORY BSON_LIB) -mark_as_advanced(EMHASHMAP_INCLUDE_DIRECTORY EMHASHMAP_LIB) diff --git a/src/components/application_manager/include/application_manager/smart_object_keys.h b/src/components/application_manager/include/application_manager/smart_object_keys.h index c5c50e5da1..65ec4f15c3 100644 --- a/src/components/application_manager/include/application_manager/smart_object_keys.h +++ b/src/components/application_manager/include/application_manager/smart_object_keys.h @@ -321,6 +321,19 @@ extern const char* service_published; extern const char* service_active; extern const char* app_service_id; extern const char* service_data; +extern const char* media_service_data; +extern const char* weather_service_data; +extern const char* location; +extern const char* current_forecast; +extern const char* minute_forecast; +extern const char* hourly_forecast; +extern const char* multiday_forecast; +extern const char* weather_icon; +extern const char* navigation_service_data; +extern const char* origin; +extern const char* destination; +extern const char* instructions; +extern const char* location_details; extern const char* request_service_active; extern const char* app_services; extern const char* update_reason; diff --git a/src/components/application_manager/rpc_plugins/app_service_rpc_plugin/include/app_service_rpc_plugin/commands/hmi/as_get_app_service_data_request_from_hmi.h b/src/components/application_manager/rpc_plugins/app_service_rpc_plugin/include/app_service_rpc_plugin/commands/hmi/as_get_app_service_data_request_from_hmi.h index 7b175fc0d4..531d1816e9 100644 --- a/src/components/application_manager/rpc_plugins/app_service_rpc_plugin/include/app_service_rpc_plugin/commands/hmi/as_get_app_service_data_request_from_hmi.h +++ b/src/components/application_manager/rpc_plugins/app_service_rpc_plugin/include/app_service_rpc_plugin/commands/hmi/as_get_app_service_data_request_from_hmi.h @@ -88,6 +88,12 @@ class ASGetAppServiceDataRequestFromHMI void on_event(const app_mngr::event_engine::MobileEvent& event) OVERRIDE; private: + void GetWeatherImagePaths(smart_objects::SmartObject& data, + application_manager::ApplicationSharedPtr app); + void GetNavigationImagePaths(smart_objects::SmartObject& data, + application_manager::ApplicationSharedPtr app); + bool ValidateResponse(smart_objects::SmartObject& message_params); + DISALLOW_COPY_AND_ASSIGN(ASGetAppServiceDataRequestFromHMI); }; diff --git a/src/components/application_manager/rpc_plugins/app_service_rpc_plugin/include/app_service_rpc_plugin/commands/hmi/on_as_app_service_data_notification.h b/src/components/application_manager/rpc_plugins/app_service_rpc_plugin/include/app_service_rpc_plugin/commands/hmi/on_as_app_service_data_notification.h index 30af13038a..cff7c8e5b8 100644 --- a/src/components/application_manager/rpc_plugins/app_service_rpc_plugin/include/app_service_rpc_plugin/commands/hmi/on_as_app_service_data_notification.h +++ b/src/components/application_manager/rpc_plugins/app_service_rpc_plugin/include/app_service_rpc_plugin/commands/hmi/on_as_app_service_data_notification.h @@ -70,6 +70,12 @@ class OnASAppServiceDataNotification virtual void Run(); private: + void GetWeatherImagePaths(smart_objects::SmartObject& data, + application_manager::ApplicationSharedPtr app); + void GetNavigationImagePaths(smart_objects::SmartObject& data, + application_manager::ApplicationSharedPtr app); + bool ValidateParams(smart_objects::SmartObject& message_params); + DISALLOW_COPY_AND_ASSIGN(OnASAppServiceDataNotification); }; diff --git a/src/components/application_manager/rpc_plugins/app_service_rpc_plugin/src/app_service_mobile_command_factory.cc b/src/components/application_manager/rpc_plugins/app_service_rpc_plugin/src/app_service_mobile_command_factory.cc index 7a62f7a4c7..76be96cf8f 100644 --- a/src/components/application_manager/rpc_plugins/app_service_rpc_plugin/src/app_service_mobile_command_factory.cc +++ b/src/components/application_manager/rpc_plugins/app_service_rpc_plugin/src/app_service_mobile_command_factory.cc @@ -111,9 +111,15 @@ app_mngr::CommandCreator& AppServiceMobileCommandFactory::buildCommandCreator( switch (function_id) { case mobile_apis::FunctionID::PublishAppServiceID: - return mobile_apis::messageType::request == message_type - ? factory.GetCreator<commands::PublishAppServiceRequest>() - : factory.GetCreator<commands::PublishAppServiceResponse>(); + if (app_mngr::commands::Command::CommandSource::SOURCE_MOBILE == source && + mobile_apis::messageType::response != message_type) { + return factory.GetCreator<commands::PublishAppServiceRequest>(); + } else if (app_mngr::commands::Command::CommandSource::SOURCE_SDL == + source && + mobile_apis::messageType::request != message_type) { + return factory.GetCreator<commands::PublishAppServiceResponse>(); + } + break; case mobile_apis::FunctionID::OnAppServiceDataID: return app_mngr::commands::Command::CommandSource::SOURCE_MOBILE == source ? factory.GetCreator< diff --git a/src/components/application_manager/rpc_plugins/app_service_rpc_plugin/src/commands/hmi/as_get_app_service_data_request_from_hmi.cc b/src/components/application_manager/rpc_plugins/app_service_rpc_plugin/src/commands/hmi/as_get_app_service_data_request_from_hmi.cc index a339ffb9a6..2da8834b96 100644 --- a/src/components/application_manager/rpc_plugins/app_service_rpc_plugin/src/commands/hmi/as_get_app_service_data_request_from_hmi.cc +++ b/src/components/application_manager/rpc_plugins/app_service_rpc_plugin/src/commands/hmi/as_get_app_service_data_request_from_hmi.cc @@ -31,6 +31,7 @@ */ #include "app_service_rpc_plugin/commands/hmi/as_get_app_service_data_request_from_hmi.h" +#include "application_manager/app_service_manager.h" #include "application_manager/application_impl.h" #include "application_manager/rpc_service.h" #include "interfaces/MOBILE_API.h" @@ -70,30 +71,180 @@ void ASGetAppServiceDataRequestFromHMI::Run() { true); } +void ASGetAppServiceDataRequestFromHMI::GetWeatherImagePaths( + smart_objects::SmartObject& data, ApplicationSharedPtr app) { + if (data[strings::location].keyExists(strings::location_image)) { + MessageHelper::VerifyImage(data[strings::location][strings::location_image], + app, + application_manager_); + } + + if (data.keyExists(strings::current_forecast) && + data[strings::current_forecast].keyExists(strings::weather_icon)) { + MessageHelper::VerifyImage( + data[strings::current_forecast][strings::weather_icon], + app, + application_manager_); + } + + if (data.keyExists(strings::minute_forecast)) { + smart_objects::SmartObject& minute_forecast = + data[strings::minute_forecast]; + for (size_t i = 0; i < minute_forecast.length(); i++) { + if (minute_forecast[i].keyExists(strings::weather_icon)) { + MessageHelper::VerifyImage(minute_forecast[i][strings::weather_icon], + app, + application_manager_); + } + } + } + + if (data.keyExists(strings::hourly_forecast)) { + smart_objects::SmartObject& hourly_forecast = + data[strings::hourly_forecast]; + for (size_t i = 0; i < hourly_forecast.length(); i++) { + if (hourly_forecast[i].keyExists(strings::weather_icon)) { + MessageHelper::VerifyImage(hourly_forecast[i][strings::weather_icon], + app, + application_manager_); + } + } + } + + if (data.keyExists(strings::multiday_forecast)) { + smart_objects::SmartObject& multiday_forecast = + data[strings::multiday_forecast]; + for (size_t i = 0; i < multiday_forecast.length(); i++) { + if (multiday_forecast[i].keyExists(strings::weather_icon)) { + MessageHelper::VerifyImage(multiday_forecast[i][strings::weather_icon], + app, + application_manager_); + } + } + } +} + +void ASGetAppServiceDataRequestFromHMI::GetNavigationImagePaths( + smart_objects::SmartObject& data, ApplicationSharedPtr app) { + if (data.keyExists(strings::origin) && + data[strings::origin].keyExists(strings::location_image)) { + MessageHelper::VerifyImage(data[strings::origin][strings::location_image], + app, + application_manager_); + } + + if (data.keyExists(strings::destination) && + data[strings::destination].keyExists(strings::location_image)) { + MessageHelper::VerifyImage( + data[strings::destination][strings::location_image], + app, + application_manager_); + } + + if (data.keyExists(strings::instructions)) { + smart_objects::SmartObject& instructions = data[strings::instructions]; + for (size_t i = 0; i < instructions.length(); i++) { + if (instructions[i].keyExists(strings::image)) { + MessageHelper::VerifyImage( + instructions[i][strings::image], app, application_manager_); + } + + if (instructions[i].keyExists(strings::location_details) && + instructions[i][strings::location_details].keyExists( + strings::location_image)) { + MessageHelper::VerifyImage( + instructions[i][strings::location_details][strings::location_image], + app, + application_manager_); + } + } + } +} + +bool ASGetAppServiceDataRequestFromHMI::ValidateResponse( + smart_objects::SmartObject& message_params) { + if (!message_params.keyExists(strings::service_data)) { + LOG4CXX_DEBUG( + logger_, + "GASD response received without any service data, passing through"); + return true; + } + smart_objects::SmartObject& service_data = + message_params[strings::service_data]; + std::string service_type = service_data[strings::service_type].asString(); + mobile_apis::AppServiceType::eType service_type_value; + const std::string& service_id = service_data[strings::service_id].asString(); + auto service = + application_manager_.GetAppServiceManager().FindServiceByID(service_id); + if (!service) { + LOG4CXX_ERROR(logger_, + "GASD response received with an unpublished service ID"); + SendErrorResponse( + correlation_id(), + hmi_apis::FunctionID::AppService_GetAppServiceData, + hmi_apis::Common_Result::GENERIC_ERROR, + "The provider responded with incorrect data", + application_manager::commands::Command::SOURCE_SDL_TO_HMI); + return false; + } + + using namespace ns_smart_device_link::ns_smart_objects; + if (service && service->mobile_service && + EnumConversionHelper<mobile_apis::AppServiceType::eType>::StringToEnum( + service_type, &service_type_value)) { + auto app = application_manager_.application(service->connection_key); + if (!app) { + LOG4CXX_ERROR(logger_, + "Failed to find service provider for GASD response"); + SendErrorResponse( + correlation_id(), + hmi_apis::FunctionID::AppService_GetAppServiceData, + hmi_apis::Common_Result::GENERIC_ERROR, + "The provider responded with incorrect data", + application_manager::commands::Command::SOURCE_SDL_TO_HMI); + return false; + } + + if (service_type_value == mobile_apis::AppServiceType::WEATHER && + service_data.keyExists(strings::weather_service_data)) { + GetWeatherImagePaths(service_data[strings::weather_service_data], app); + } + + if (service_type_value == mobile_apis::AppServiceType::NAVIGATION && + service_data.keyExists(strings::navigation_service_data)) { + GetNavigationImagePaths(service_data[strings::navigation_service_data], + app); + } + } + return true; +} + void ASGetAppServiceDataRequestFromHMI::on_event( const event_engine::Event& event) { - const smart_objects::SmartObject& event_message = event.smart_object(); + smart_objects::SmartObject event_message(event.smart_object()); - auto msg_params = event_message[strings::msg_params]; + auto& msg_params = event_message[strings::msg_params]; hmi_apis::Common_Result::eType result = static_cast<hmi_apis::Common_Result::eType>( event_message[strings::params][hmi_response::code].asInt()); bool success = IsHMIResultSuccess(result, HmiInterfaces::HMI_INTERFACE_AppService); - SendResponse(success, - correlation_id(), - hmi_apis::FunctionID::AppService_GetAppServiceData, - result, - &msg_params, - application_manager::commands::Command::SOURCE_SDL_TO_HMI); + if (ValidateResponse(msg_params)) { + SendResponse(success, + correlation_id(), + hmi_apis::FunctionID::AppService_GetAppServiceData, + result, + &msg_params, + application_manager::commands::Command::SOURCE_SDL_TO_HMI); + } } void ASGetAppServiceDataRequestFromHMI::on_event( const event_engine::MobileEvent& event) { - const smart_objects::SmartObject& event_message = event.smart_object(); + smart_objects::SmartObject event_message(event.smart_object()); - auto msg_params = event_message[strings::msg_params]; + auto& msg_params = event_message[strings::msg_params]; mobile_apis::Result::eType mobile_result = static_cast<mobile_apis::Result::eType>( @@ -102,19 +253,18 @@ void ASGetAppServiceDataRequestFromHMI::on_event( MessageHelper::MobileToHMIResult(mobile_result); bool success = IsMobileResultSuccess(mobile_result); - SendResponse(success, - correlation_id(), - hmi_apis::FunctionID::AppService_GetAppServiceData, - result, - &msg_params, - application_manager::commands::Command::SOURCE_SDL_TO_HMI); + if (ValidateResponse(msg_params)) { + SendResponse(success, + correlation_id(), + hmi_apis::FunctionID::AppService_GetAppServiceData, + result, + &msg_params, + application_manager::commands::Command::SOURCE_SDL_TO_HMI); + } } void ASGetAppServiceDataRequestFromHMI::onTimeOut() { LOG4CXX_AUTO_TRACE(logger_); - smart_objects::SmartObject response_params; - response_params[strings::info] = - "The provider did not respond to the request"; SendErrorResponse(correlation_id(), hmi_apis::FunctionID::AppService_GetAppServiceData, hmi_apis::Common_Result::GENERIC_ERROR, diff --git a/src/components/application_manager/rpc_plugins/app_service_rpc_plugin/src/commands/hmi/on_as_app_service_data_notification.cc b/src/components/application_manager/rpc_plugins/app_service_rpc_plugin/src/commands/hmi/on_as_app_service_data_notification.cc index 80dd88c15f..e90de23837 100644 --- a/src/components/application_manager/rpc_plugins/app_service_rpc_plugin/src/commands/hmi/on_as_app_service_data_notification.cc +++ b/src/components/application_manager/rpc_plugins/app_service_rpc_plugin/src/commands/hmi/on_as_app_service_data_notification.cc @@ -31,6 +31,11 @@ */ #include "app_service_rpc_plugin/commands/hmi/on_as_app_service_data_notification.h" +#include "application_manager/app_service_manager.h" +#include "application_manager/application_impl.h" +#include "application_manager/message_helper.h" +#include "interfaces/MOBILE_API.h" +#include "smart_objects/enum_schema_item.h" namespace app_service_rpc_plugin { using namespace application_manager; @@ -50,10 +55,147 @@ OnASAppServiceDataNotification::OnASAppServiceDataNotification( OnASAppServiceDataNotification::~OnASAppServiceDataNotification() {} +void OnASAppServiceDataNotification::GetWeatherImagePaths( + smart_objects::SmartObject& data, ApplicationSharedPtr app) { + if (data[strings::location].keyExists(strings::location_image)) { + MessageHelper::VerifyImage(data[strings::location][strings::location_image], + app, + application_manager_); + } + + if (data.keyExists(strings::current_forecast) && + data[strings::current_forecast].keyExists(strings::weather_icon)) { + MessageHelper::VerifyImage( + data[strings::current_forecast][strings::weather_icon], + app, + application_manager_); + } + + if (data.keyExists(strings::minute_forecast)) { + smart_objects::SmartObject& minute_forecast = + data[strings::minute_forecast]; + for (size_t i = 0; i < minute_forecast.length(); i++) { + if (minute_forecast[i].keyExists(strings::weather_icon)) { + MessageHelper::VerifyImage(minute_forecast[i][strings::weather_icon], + app, + application_manager_); + } + } + } + + if (data.keyExists(strings::hourly_forecast)) { + smart_objects::SmartObject& hourly_forecast = + data[strings::hourly_forecast]; + for (size_t i = 0; i < hourly_forecast.length(); i++) { + if (hourly_forecast[i].keyExists(strings::weather_icon)) { + MessageHelper::VerifyImage(hourly_forecast[i][strings::weather_icon], + app, + application_manager_); + } + } + } + + if (data.keyExists(strings::multiday_forecast)) { + smart_objects::SmartObject& multiday_forecast = + data[strings::multiday_forecast]; + for (size_t i = 0; i < multiday_forecast.length(); i++) { + if (multiday_forecast[i].keyExists(strings::weather_icon)) { + MessageHelper::VerifyImage(multiday_forecast[i][strings::weather_icon], + app, + application_manager_); + } + } + } +} + +void OnASAppServiceDataNotification::GetNavigationImagePaths( + smart_objects::SmartObject& data, ApplicationSharedPtr app) { + if (data.keyExists(strings::origin) && + data[strings::origin].keyExists(strings::location_image)) { + MessageHelper::VerifyImage(data[strings::origin][strings::location_image], + app, + application_manager_); + } + + if (data.keyExists(strings::destination) && + data[strings::destination].keyExists(strings::location_image)) { + MessageHelper::VerifyImage( + data[strings::destination][strings::location_image], + app, + application_manager_); + } + + if (data.keyExists(strings::instructions)) { + smart_objects::SmartObject& instructions = data[strings::instructions]; + for (size_t i = 0; i < instructions.length(); i++) { + if (instructions[i].keyExists(strings::image)) { + MessageHelper::VerifyImage( + instructions[i][strings::image], app, application_manager_); + } + + if (instructions[i].keyExists(strings::location_details) && + instructions[i][strings::location_details].keyExists( + strings::location_image)) { + MessageHelper::VerifyImage( + instructions[i][strings::location_details][strings::location_image], + app, + application_manager_); + } + } + } +} + +bool OnASAppServiceDataNotification::ValidateParams( + smart_objects::SmartObject& message_params) { + if (!message_params.keyExists(strings::service_data)) { + LOG4CXX_DEBUG(logger_, + "OASD notification received without any service data"); + return false; + } + smart_objects::SmartObject& service_data = + message_params[strings::service_data]; + std::string service_type = service_data[strings::service_type].asString(); + mobile_apis::AppServiceType::eType service_type_value; + const std::string& service_id = service_data[strings::service_id].asString(); + auto service = + application_manager_.GetAppServiceManager().FindServiceByID(service_id); + if (!service) { + LOG4CXX_ERROR(logger_, + "OASD notification received with an unpublished service ID"); + return false; + } + + using namespace ns_smart_device_link::ns_smart_objects; + if (service && service->mobile_service && + EnumConversionHelper<mobile_apis::AppServiceType::eType>::StringToEnum( + service_type, &service_type_value)) { + auto app = application_manager_.application(service->connection_key); + if (!app) { + LOG4CXX_ERROR(logger_, + "Failed to find service provider for OASD message"); + return false; + } + + if (service_type_value == mobile_apis::AppServiceType::WEATHER && + service_data.keyExists(strings::weather_service_data)) { + GetWeatherImagePaths(service_data[strings::weather_service_data], app); + } + + if (service_type_value == mobile_apis::AppServiceType::NAVIGATION && + service_data.keyExists(strings::navigation_service_data)) { + GetNavigationImagePaths(service_data[strings::navigation_service_data], + app); + } + } + return true; +} + void OnASAppServiceDataNotification::Run() { LOG4CXX_AUTO_TRACE(logger_); LOG4CXX_DEBUG(logger_, "Sending AS data to HMI"); - SendNotification(); + if (ValidateParams((*message_)[strings::msg_params])) { + SendNotification(); + } } } // namespace commands diff --git a/src/components/application_manager/rpc_plugins/rc_rpc_plugin/include/rc_rpc_plugin/rc_command_factory.h b/src/components/application_manager/rpc_plugins/rc_rpc_plugin/include/rc_rpc_plugin/rc_command_factory.h index 0cae8dd4de..aa01b608b4 100644 --- a/src/components/application_manager/rpc_plugins/rc_rpc_plugin/include/rc_rpc_plugin/rc_command_factory.h +++ b/src/components/application_manager/rpc_plugins/rc_rpc_plugin/include/rc_rpc_plugin/rc_command_factory.h @@ -74,12 +74,18 @@ class RCCommandFactory : public application_manager::CommandFactory { private: app_mngr::CommandCreator& get_mobile_creator_factory( - mobile_apis::FunctionID::eType id, - mobile_apis::messageType::eType message_type) const; + const mobile_apis::FunctionID::eType id, + const mobile_apis::messageType::eType message_type, + const app_mngr::commands::Command::CommandSource source) const; + app_mngr::CommandCreator& get_mobile_command_creator( + const mobile_apis::FunctionID::eType id, + const mobile_apis::messageType::eType message_type) const; + app_mngr::CommandCreator& get_mobile_notification_creator( + const mobile_apis::FunctionID::eType id) const; app_mngr::CommandCreator& get_hmi_creator_factory( - hmi_apis::FunctionID::eType id, - hmi_apis::messageType::eType message_type) const; + const hmi_apis::FunctionID::eType id, + const hmi_apis::messageType::eType message_type) const; RCCommandParams params_; }; diff --git a/src/components/application_manager/rpc_plugins/rc_rpc_plugin/src/rc_command_factory.cc b/src/components/application_manager/rpc_plugins/rc_rpc_plugin/src/rc_command_factory.cc index 67329f2a31..93c230dfc3 100644 --- a/src/components/application_manager/rpc_plugins/rc_rpc_plugin/src/rc_command_factory.cc +++ b/src/components/application_manager/rpc_plugins/rc_rpc_plugin/src/rc_command_factory.cc @@ -144,7 +144,7 @@ CommandSharedPtr RCCommandFactory::CreateCommand( static_cast<mobile_apis::FunctionID::eType>( (*message)[strings::params][strings::function_id].asInt()); - return get_mobile_creator_factory(function_id, message_type) + return get_mobile_creator_factory(function_id, message_type, source) .create(message); } } @@ -161,52 +161,91 @@ bool RCCommandFactory::IsAbleToProcess( hmi_apis::messageType::INVALID_ENUM) .CanBeCreated(); } else { - return get_mobile_creator_factory( - static_cast<mobile_api::FunctionID::eType>(function_id), - mobile_api::messageType::INVALID_ENUM) - .CanBeCreated(); + auto id = static_cast<mobile_apis::FunctionID::eType>(function_id); + return get_mobile_command_creator(id, + mobile_apis::messageType::INVALID_ENUM) + .CanBeCreated() || + get_mobile_notification_creator(id).CanBeCreated(); } } -CommandCreator& RCCommandFactory::get_mobile_creator_factory( - mobile_api::FunctionID::eType id, - mobile_api::messageType::eType message_type) const { +CommandCreator& RCCommandFactory::get_mobile_command_creator( + const mobile_apis::FunctionID::eType id, + const mobile_apis::messageType::eType message_type) const { LOG4CXX_DEBUG(logger_, - "CreateMobileCommand function_id: " << id << " message_type: " - << message_type); + "get_mobile_command_creator function_id: " + << id << " message_type: " << message_type); RCCommandCreatorFactory rc_factory(params_); - switch (id) { case mobile_apis::FunctionID::ButtonPressID: { - return mobile_api::messageType::request == message_type + return mobile_apis::messageType::request == message_type ? rc_factory.GetCreator<commands::ButtonPressRequest>() : rc_factory.GetCreator<commands::ButtonPressResponse>(); } case mobile_apis::FunctionID::GetInteriorVehicleDataID: { - return mobile_api::messageType::request == message_type + return mobile_apis::messageType::request == message_type ? rc_factory .GetCreator<commands::GetInteriorVehicleDataRequest>() : rc_factory .GetCreator<commands::GetInteriorVehicleDataResponse>(); } case mobile_apis::FunctionID::SetInteriorVehicleDataID: { - return mobile_api::messageType::request == message_type + return mobile_apis::messageType::request == message_type ? rc_factory .GetCreator<commands::SetInteriorVehicleDataRequest>() : rc_factory .GetCreator<commands::SetInteriorVehicleDataResponse>(); } + default: {} + } + return rc_factory.GetCreator<RCInvalidCommand>(); +} + +CommandCreator& RCCommandFactory::get_mobile_notification_creator( + const mobile_apis::FunctionID::eType id) const { + RCCommandCreatorFactory rc_factory(params_); + switch (id) { case mobile_apis::FunctionID::OnInteriorVehicleDataID: { return rc_factory .GetCreator<commands::OnInteriorVehicleDataNotification>(); } - default: { return rc_factory.GetCreator<RCInvalidCommand>(); } + default: {} + } + return rc_factory.GetCreator<RCInvalidCommand>(); +} + +CommandCreator& RCCommandFactory::get_mobile_creator_factory( + const mobile_apis::FunctionID::eType id, + const mobile_apis::messageType::eType message_type, + const app_mngr::commands::Command::CommandSource source) const { + RCCommandCreatorFactory rc_factory(params_); + switch (message_type) { + case mobile_apis::messageType::request: { + if (app_mngr::commands::Command::CommandSource::SOURCE_MOBILE == source) { + return get_mobile_command_creator(id, message_type); + } + break; + } + case mobile_apis::messageType::response: { + if (app_mngr::commands::Command::CommandSource::SOURCE_SDL == source) { + return get_mobile_command_creator(id, message_type); + } + break; + } + case mobile_apis::messageType::notification: { + if (app_mngr::commands::Command::CommandSource::SOURCE_SDL == source) { + return get_mobile_notification_creator(id); + } + break; + } + default: {} } + return rc_factory.GetCreator<RCInvalidCommand>(); } CommandCreator& RCCommandFactory::get_hmi_creator_factory( - hmi_apis::FunctionID::eType id, - hmi_apis::messageType::eType message_type) const { + const hmi_apis::FunctionID::eType id, + const hmi_apis::messageType::eType message_type) const { LOG4CXX_DEBUG(logger_, "CreateHMICommand function_id: " << id << " message_type: " << message_type); diff --git a/src/components/application_manager/rpc_plugins/sdl_rpc_plugin/include/sdl_rpc_plugin/mobile_command_factory.h b/src/components/application_manager/rpc_plugins/sdl_rpc_plugin/include/sdl_rpc_plugin/mobile_command_factory.h index d8f790c70e..132b68aaec 100644 --- a/src/components/application_manager/rpc_plugins/sdl_rpc_plugin/include/sdl_rpc_plugin/mobile_command_factory.h +++ b/src/components/application_manager/rpc_plugins/sdl_rpc_plugin/include/sdl_rpc_plugin/mobile_command_factory.h @@ -59,9 +59,16 @@ class MobileCommandFactory : public app_mngr::CommandFactory { private: app_mngr::CommandCreator& get_creator_factory( - mobile_apis::FunctionID::eType id, - mobile_apis::messageType::eType message_type, - app_mngr::commands::Command::CommandSource source) const; + const mobile_apis::FunctionID::eType id, + const mobile_apis::messageType::eType message_type, + const app_mngr::commands::Command::CommandSource source) const; + app_mngr::CommandCreator& get_command_creator( + const mobile_apis::FunctionID::eType id, + const mobile_apis::messageType::eType message_type) const; + app_mngr::CommandCreator& get_notification_creator( + const mobile_apis::FunctionID::eType id) const; + app_mngr::CommandCreator& get_notification_from_mobile_creator( + const mobile_apis::FunctionID::eType id) const; app_mngr::ApplicationManager& application_manager_; app_mngr::rpc_service::RPCService& rpc_service_; diff --git a/src/components/application_manager/rpc_plugins/sdl_rpc_plugin/src/mobile_command_factory.cc b/src/components/application_manager/rpc_plugins/sdl_rpc_plugin/src/mobile_command_factory.cc index 8c37e5729d..1a1d4f725c 100644 --- a/src/components/application_manager/rpc_plugins/sdl_rpc_plugin/src/mobile_command_factory.cc +++ b/src/components/application_manager/rpc_plugins/sdl_rpc_plugin/src/mobile_command_factory.cc @@ -137,13 +137,11 @@ CREATE_LOGGERPTR_GLOBAL(logger_, "ApplicationManager") namespace sdl_rpc_plugin { using namespace application_manager; -CommandCreator& MobileCommandFactory::get_creator_factory( - mobile_apis::FunctionID::eType id, - mobile_apis::messageType::eType message_type, - app_mngr::commands::Command::CommandSource source) const { +CommandCreator& MobileCommandFactory::get_command_creator( + const mobile_apis::FunctionID::eType id, + const mobile_apis::messageType::eType message_type) const { CommandCreatorFactory factory( application_manager_, rpc_service_, hmi_capabilities_, policy_handler_); - switch (id) { case mobile_apis::FunctionID::RegisterAppInterfaceID: { return mobile_api::messageType::request == message_type @@ -182,7 +180,6 @@ CommandCreator& MobileCommandFactory::get_creator_factory( ? factory.GetCreator<commands::AddSubMenuRequest>() : factory.GetCreator<commands::AddSubMenuResponse>(); } - case mobile_apis::FunctionID::DeleteSubMenuID: { return mobile_api::messageType::request == message_type ? factory.GetCreator<commands::DeleteSubMenuRequest>() @@ -215,7 +212,6 @@ CommandCreator& MobileCommandFactory::get_creator_factory( ? factory.GetCreator<commands::PerformAudioPassThruRequest>() : factory.GetCreator<commands::PerformAudioPassThruResponse>(); } - case mobile_apis::FunctionID::CreateInteractionChoiceSetID: { return mobile_api::messageType::request == message_type ? factory.GetCreator< @@ -298,7 +294,6 @@ CommandCreator& MobileCommandFactory::get_creator_factory( ? factory.GetCreator<commands::ScrollableMessageRequest>() : factory.GetCreator<commands::ScrollableMessageResponse>(); } - case mobile_apis::FunctionID::AlertManeuverID: { return mobile_api::messageType::request == message_type ? factory.GetCreator<commands::AlertManeuverRequest>() @@ -361,6 +356,20 @@ CommandCreator& MobileCommandFactory::get_creator_factory( : factory .GetCreator<commands::GetCloudAppPropertiesResponse>(); } + case mobile_apis::FunctionID::GenericResponseID: { + using app_mngr::commands::Command; + return factory.GetCreator<commands::GenericResponse>(); + } + default: {} + } + return factory.GetCreator<InvalidCommand>(); +} + +CommandCreator& MobileCommandFactory::get_notification_creator( + const mobile_apis::FunctionID::eType id) const { + CommandCreatorFactory factory( + application_manager_, rpc_service_, hmi_capabilities_, policy_handler_); + switch (id) { case mobile_apis::FunctionID::OnButtonEventID: { return factory.GetCreator<commands::mobile::OnButtonEventNotification>(); } @@ -391,11 +400,7 @@ CommandCreator& MobileCommandFactory::get_creator_factory( return factory.GetCreator<commands::OnPermissionsChangeNotification>(); } case mobile_apis::FunctionID::OnHMIStatusID: { - using app_mngr::commands::Command; - return Command::CommandSource::SOURCE_MOBILE == source - ? factory.GetCreator< - commands::OnHMIStatusNotificationFromMobile>() - : factory.GetCreator<commands::OnHMIStatusNotification>(); + return factory.GetCreator<commands::OnHMIStatusNotification>(); } case mobile_apis::FunctionID::OnKeyboardInputID: { return factory @@ -413,19 +418,60 @@ CommandCreator& MobileCommandFactory::get_creator_factory( .GetCreator<commands::mobile::OnSystemRequestNotification>(); } case mobile_apis::FunctionID::OnHashChangeID: { - using app_mngr::commands::Command; return factory.GetCreator<commands::mobile::OnHashChangeNotification>(); } case mobile_apis::FunctionID::OnWayPointChangeID: { - using app_mngr::commands::Command; return factory.GetCreator<commands::OnWayPointChangeNotification>(); } - case mobile_apis::FunctionID::GenericResponseID: { - using app_mngr::commands::Command; - return factory.GetCreator<commands::GenericResponse>(); + default: {} + } + return factory.GetCreator<InvalidCommand>(); +} + +CommandCreator& MobileCommandFactory::get_notification_from_mobile_creator( + const mobile_apis::FunctionID::eType id) const { + CommandCreatorFactory factory( + application_manager_, rpc_service_, hmi_capabilities_, policy_handler_); + switch (id) { + case mobile_apis::FunctionID::OnHMIStatusID: { + return factory.GetCreator<commands::OnHMIStatusNotificationFromMobile>(); } - default: { return factory.GetCreator<InvalidCommand>(); } + default: {} + } + return factory.GetCreator<InvalidCommand>(); +} + +CommandCreator& MobileCommandFactory::get_creator_factory( + const mobile_apis::FunctionID::eType id, + const mobile_apis::messageType::eType message_type, + const app_mngr::commands::Command::CommandSource source) const { + switch (message_type) { + case mobile_api::messageType::request: { + if (app_mngr::commands::Command::CommandSource::SOURCE_MOBILE == source) { + return get_command_creator(id, message_type); + } + break; + } + case mobile_api::messageType::response: { + if (app_mngr::commands::Command::CommandSource::SOURCE_SDL == source) { + return get_command_creator(id, message_type); + } + break; + } + case mobile_api::messageType::notification: { + if (app_mngr::commands::Command::CommandSource::SOURCE_SDL == source) { + return get_notification_creator(id); + } else if (app_mngr::commands::Command::CommandSource::SOURCE_MOBILE == + source) { + return get_notification_from_mobile_creator(id); + } + break; + } + default: {} } + CommandCreatorFactory factory( + application_manager_, rpc_service_, hmi_capabilities_, policy_handler_); + return factory.GetCreator<InvalidCommand>(); } MobileCommandFactory::MobileCommandFactory( @@ -442,12 +488,10 @@ bool MobileCommandFactory::IsAbleToProcess( const int32_t function_id, const application_manager::commands::Command::CommandSource message_source) const { - using app_mngr::commands::Command; - return get_creator_factory( - static_cast<mobile_apis::FunctionID::eType>(function_id), - mobile_apis::messageType::INVALID_ENUM, - message_source) - .CanBeCreated(); + auto id = static_cast<mobile_apis::FunctionID::eType>(function_id); + return get_command_creator(id, mobile_apis::messageType::INVALID_ENUM) + .CanBeCreated() || + get_notification_creator(id).CanBeCreated(); } CommandSharedPtr MobileCommandFactory::CreateCommand( diff --git a/src/components/application_manager/rpc_plugins/sdl_rpc_plugin/test/commands/mobile/system_request_test.cc b/src/components/application_manager/rpc_plugins/sdl_rpc_plugin/test/commands/mobile/system_request_test.cc index 14441d450e..7351cd67d3 100644 --- a/src/components/application_manager/rpc_plugins/sdl_rpc_plugin/test/commands/mobile/system_request_test.cc +++ b/src/components/application_manager/rpc_plugins/sdl_rpc_plugin/test/commands/mobile/system_request_test.cc @@ -229,6 +229,37 @@ TEST_F(SystemRequestTest, Run_RequestTypeDisallowed_SendDisallowedResponse) { command->Run(); } +TEST_F(SystemRequestTest, Run_RequestType_IconURL_Success) { + PreConditions(); + MessageSharedPtr msg = CreateIVSUMessage(); + (*msg)[am::strings::msg_params][am::strings::request_type] = + mobile_apis::RequestType::ICON_URL; + + const std::string url = "https://www.appsfakeiconurlendpoint.com/icon.png"; + + (*msg)[am::strings::msg_params][am::strings::file_name] = url; + const std::vector<uint8_t> binary_data = {1u, 2u}; + (*msg)[am::strings::params][am::strings::binary_data] = binary_data; + + EXPECT_CALL( + mock_policy_handler_, + IsRequestTypeAllowed(kAppPolicyId, mobile_apis::RequestType::ICON_URL)) + .WillOnce(Return(true)); + EXPECT_CALL(app_mngr_settings_, app_icons_folder()) + .WillOnce(ReturnRef(kAppStorageFolder)); + EXPECT_CALL(app_mngr_, PolicyIDByIconUrl(url)).WillOnce(Return(kAppPolicyId)); + + EXPECT_CALL(app_mngr_, + SaveBinary(binary_data, kAppStorageFolder, kAppPolicyId, 0u)) + .WillOnce(Return(mobile_apis::Result::SUCCESS)); + + EXPECT_CALL(app_mngr_, SetIconFileFromSystemRequest(kAppPolicyId)).Times(1); + + std::shared_ptr<SystemRequest> command(CreateCommand<SystemRequest>(msg)); + ASSERT_TRUE(command->Init()); + command->Run(); +} + } // namespace system_request } // namespace mobile_commands_test } // namespace commands_test diff --git a/src/components/application_manager/rpc_plugins/vehicle_info_plugin/include/vehicle_info_plugin/vehicle_info_mobile_command_factory.h b/src/components/application_manager/rpc_plugins/vehicle_info_plugin/include/vehicle_info_plugin/vehicle_info_mobile_command_factory.h index 9743aee769..41bd355852 100644 --- a/src/components/application_manager/rpc_plugins/vehicle_info_plugin/include/vehicle_info_plugin/vehicle_info_mobile_command_factory.h +++ b/src/components/application_manager/rpc_plugins/vehicle_info_plugin/include/vehicle_info_plugin/vehicle_info_mobile_command_factory.h @@ -63,8 +63,15 @@ class VehicleInfoMobileCommandFactory : public app_mngr::CommandFactory { app_mngr::HMICapabilities& hmi_capabilities_; policy::PolicyHandlerInterface& policy_handler_; - app_mngr::CommandCreator& buildCommandCreator( - const int32_t function_id, const int32_t message_type) const; + app_mngr::CommandCreator& get_creator_factory( + const mobile_apis::FunctionID::eType function_id, + const mobile_apis::messageType::eType message_type, + const app_mngr::commands::Command::CommandSource source) const; + app_mngr::CommandCreator& get_command_creator( + const mobile_apis::FunctionID::eType id, + const mobile_apis::messageType::eType message_type) const; + app_mngr::CommandCreator& get_notification_creator( + const mobile_apis::FunctionID::eType id) const; DISALLOW_COPY_AND_ASSIGN(VehicleInfoMobileCommandFactory); }; diff --git a/src/components/application_manager/rpc_plugins/vehicle_info_plugin/src/vehicle_info_mobile_command_factory.cc b/src/components/application_manager/rpc_plugins/vehicle_info_plugin/src/vehicle_info_mobile_command_factory.cc index 7d1d25560a..dffc836a89 100644 --- a/src/components/application_manager/rpc_plugins/vehicle_info_plugin/src/vehicle_info_mobile_command_factory.cc +++ b/src/components/application_manager/rpc_plugins/vehicle_info_plugin/src/vehicle_info_mobile_command_factory.cc @@ -69,8 +69,6 @@ VehicleInfoMobileCommandFactory::VehicleInfoMobileCommandFactory( app_mngr::CommandSharedPtr VehicleInfoMobileCommandFactory::CreateCommand( const app_mngr::commands::MessageSharedPtr& message, app_mngr::commands::Command::CommandSource source) { - UNUSED(source); - const mobile_apis::FunctionID::eType function_id = static_cast<mobile_apis::FunctionID::eType>( (*message)[strings::params][strings::function_id].asInt()); @@ -91,54 +89,102 @@ app_mngr::CommandSharedPtr VehicleInfoMobileCommandFactory::CreateCommand( "HMICommandFactory::CreateCommand function_id: " << function_id << ", message type: " << message_type_str); - return buildCommandCreator(function_id, message_type).create(message); + return get_creator_factory(function_id, message_type, source).create(message); } bool VehicleInfoMobileCommandFactory::IsAbleToProcess( const int32_t function_id, const app_mngr::commands::Command::CommandSource source) const { UNUSED(source); - return buildCommandCreator(function_id, - mobile_apis::messageType::INVALID_ENUM) - .CanBeCreated(); + auto id = static_cast<mobile_apis::FunctionID::eType>(function_id); + return get_command_creator(id, mobile_apis::messageType::INVALID_ENUM) + .CanBeCreated() || + get_notification_creator(id).CanBeCreated(); } -app_mngr::CommandCreator& VehicleInfoMobileCommandFactory::buildCommandCreator( - const int32_t function_id, const int32_t message_type) const { +app_mngr::CommandCreator& VehicleInfoMobileCommandFactory::get_command_creator( + const mobile_apis::FunctionID::eType id, + const mobile_apis::messageType::eType message_type) const { auto factory = app_mngr::CommandCreatorFactory( application_manager_, rpc_service_, hmi_capabilities_, policy_handler_); - - switch (function_id) { - case mobile_apis::FunctionID::GetVehicleDataID: + switch (id) { + case mobile_apis::FunctionID::GetVehicleDataID: { return mobile_apis::messageType::request == message_type ? factory.GetCreator<commands::GetVehicleDataRequest>() : factory.GetCreator<commands::GetVehicleDataResponse>(); - case mobile_apis::FunctionID::SubscribeVehicleDataID: + } + case mobile_apis::FunctionID::SubscribeVehicleDataID: { return mobile_apis::messageType::request == message_type ? factory.GetCreator<commands::SubscribeVehicleDataRequest>() : factory.GetCreator<commands::SubscribeVehicleDataResponse>(); - case mobile_apis::FunctionID::UnsubscribeVehicleDataID: + } + case mobile_apis::FunctionID::UnsubscribeVehicleDataID: { return mobile_apis::messageType::request == message_type ? factory.GetCreator<commands::UnsubscribeVehicleDataRequest>() : factory .GetCreator<commands::UnsubscribeVehicleDataResponse>(); - case mobile_apis::FunctionID::OnVehicleDataID: - return factory.GetCreator<commands::OnVehicleDataNotification>(); - case mobile_apis::FunctionID::ReadDIDID: + } + case mobile_apis::FunctionID::ReadDIDID: { return mobile_apis::messageType::request == message_type ? factory.GetCreator<commands::ReadDIDRequest>() : factory.GetCreator<commands::ReadDIDResponse>(); - case mobile_apis::FunctionID::GetDTCsID: + } + case mobile_apis::FunctionID::GetDTCsID: { return mobile_apis::messageType::request == message_type ? factory.GetCreator<commands::GetDTCsRequest>() : factory.GetCreator<commands::GetDTCsResponse>(); - case mobile_apis::FunctionID::DiagnosticMessageID: + } + case mobile_apis::FunctionID::DiagnosticMessageID: { return mobile_apis::messageType::request == message_type ? factory.GetCreator<commands::DiagnosticMessageRequest>() : factory.GetCreator<commands::DiagnosticMessageResponse>(); - default: - LOG4CXX_WARN(logger_, "Unsupported function_id: " << function_id); - return factory.GetCreator<app_mngr::InvalidCommand>(); + } + default: {} + } + return factory.GetCreator<app_mngr::InvalidCommand>(); +} + +app_mngr::CommandCreator& +VehicleInfoMobileCommandFactory::get_notification_creator( + const mobile_apis::FunctionID::eType id) const { + auto factory = app_mngr::CommandCreatorFactory( + application_manager_, rpc_service_, hmi_capabilities_, policy_handler_); + switch (id) { + case mobile_apis::FunctionID::OnVehicleDataID: { + return factory.GetCreator<commands::OnVehicleDataNotification>(); + } + default: {} + } + return factory.GetCreator<app_mngr::InvalidCommand>(); +} + +app_mngr::CommandCreator& VehicleInfoMobileCommandFactory::get_creator_factory( + const mobile_apis::FunctionID::eType id, + const mobile_apis::messageType::eType message_type, + const app_mngr::commands::Command::CommandSource source) const { + switch (message_type) { + case mobile_apis::messageType::request: { + if (app_mngr::commands::Command::CommandSource::SOURCE_MOBILE == source) { + return get_command_creator(id, message_type); + } + break; + } + case mobile_apis::messageType::response: { + if (app_mngr::commands::Command::CommandSource::SOURCE_SDL == source) { + return get_command_creator(id, message_type); + } + break; + } + case mobile_apis::messageType::notification: { + if (app_mngr::commands::Command::CommandSource::SOURCE_SDL == source) { + return get_notification_creator(id); + } + break; + } + default: {} } + auto factory = app_mngr::CommandCreatorFactory( + application_manager_, rpc_service_, hmi_capabilities_, policy_handler_); + return factory.GetCreator<app_mngr::InvalidCommand>(); } } // namespace vehicle_info_plugin diff --git a/src/components/application_manager/src/commands/command_notification_from_mobile_impl.cc b/src/components/application_manager/src/commands/command_notification_from_mobile_impl.cc index fa1006de2f..bd4fa58c8f 100644 --- a/src/components/application_manager/src/commands/command_notification_from_mobile_impl.cc +++ b/src/components/application_manager/src/commands/command_notification_from_mobile_impl.cc @@ -90,7 +90,7 @@ void CommandNotificationFromMobileImpl::SendNotificationToHMI( const hmi_apis::FunctionID::eType& hmi_function_id) { (*message_)[strings::params][strings::protocol_type] = hmi_protocol_type_; (*message_)[strings::params][strings::function_id] = hmi_function_id; - rpc_service_.SendMessageToHMI(message_); + rpc_service_.ManageHMICommand(message_, SOURCE_SDL_TO_HMI); } void CommandNotificationFromMobileImpl::SendNotificationToConsumers( diff --git a/src/components/application_manager/src/commands/notification_from_hmi.cc b/src/components/application_manager/src/commands/notification_from_hmi.cc index b6bb8d4e3c..5e1314bad3 100644 --- a/src/components/application_manager/src/commands/notification_from_hmi.cc +++ b/src/components/application_manager/src/commands/notification_from_hmi.cc @@ -84,7 +84,7 @@ void NotificationFromHMI::SendNotificationToMobile( void NotificationFromHMI::SendNotificationToHMI(MessageSharedPtr& message) { (*message)[strings::params][strings::protocol_type] = hmi_protocol_type_; - rpc_service_.SendMessageToHMI(message); + rpc_service_.ManageHMICommand(message, SOURCE_SDL_TO_HMI); } void NotificationFromHMI::CreateHMIRequest( diff --git a/src/components/application_manager/src/smart_object_keys.cc b/src/components/application_manager/src/smart_object_keys.cc index a1dedd1d64..48e293a782 100644 --- a/src/components/application_manager/src/smart_object_keys.cc +++ b/src/components/application_manager/src/smart_object_keys.cc @@ -288,6 +288,19 @@ const char* service_published = "servicePublished"; const char* service_active = "serviceActive"; const char* app_service_id = "appServiceId"; const char* service_data = "serviceData"; +const char* media_service_data = "mediaServiceData"; +const char* weather_service_data = "weatherServiceData"; +const char* location = "location"; +const char* current_forecast = "currentForecast"; +const char* minute_forecast = "minuteForecast"; +const char* hourly_forecast = "hourlyForecast"; +const char* multiday_forecast = "multidayForecast"; +const char* weather_icon = "weatherIcon"; +const char* navigation_service_data = "navigationServiceData"; +const char* origin = "origin"; +const char* destination = "destination"; +const char* instructions = "instructions"; +const char* location_details = "locationDetails"; const char* request_service_active = "requestServiceActive"; const char* app_services = "appServices"; const char* update_reason = "updateReason"; diff --git a/src/components/application_manager/test/application_manager_impl_test.cc b/src/components/application_manager/test/application_manager_impl_test.cc index 3405006859..804959e1db 100644 --- a/src/components/application_manager/test/application_manager_impl_test.cc +++ b/src/components/application_manager/test/application_manager_impl_test.cc @@ -229,6 +229,7 @@ class ApplicationManagerImplTest : public ::testing::Test { #if defined(CLOUD_APP_WEBSOCKET_TRANSPORT_SUPPORT) void AddCloudAppToPendingDeviceMap(); + void CreatePendingApplication(); #endif uint32_t app_id_; NiceMock<policy_test::MockPolicySettings> mock_policy_settings_; @@ -1476,8 +1477,7 @@ void ApplicationManagerImplTest::AddCloudAppToPendingDeviceMap() { app_manager_impl_->RefreshCloudAppInformation(); } -TEST_F(ApplicationManagerImplTest, CreatePendingApplication) { - // Add to pending device map. Calls refresh cloud app +void ApplicationManagerImplTest::CreatePendingApplication() { AddCloudAppToPendingDeviceMap(); // CreatePendingApplication @@ -1507,6 +1507,10 @@ TEST_F(ApplicationManagerImplTest, CreatePendingApplication) { EXPECT_EQ(1u, app_list.size()); } +TEST_F(ApplicationManagerImplTest, CreatePendingApplication) { + CreatePendingApplication(); +} + TEST_F(ApplicationManagerImplTest, SetPendingState) { AddCloudAppToPendingDeviceMap(); AddMockApplication(); @@ -1666,6 +1670,62 @@ TEST_F(ApplicationManagerImplTest, app_manager_impl_->RegisterApplication(request_for_registration_ptr); EXPECT_EQ(0, application.use_count()); } + +TEST_F(ApplicationManagerImplTest, PolicyIDByIconUrl_Success) { + app_manager_impl_->SetMockPolicyHandler(mock_policy_handler_); + std::vector<std::string> enabled_apps{"1234"}; + EXPECT_CALL(*mock_policy_handler_, GetEnabledCloudApps(_)) + .WillOnce(SetArgReferee<0>(enabled_apps)); + EXPECT_CALL(*mock_policy_handler_, GetCloudAppParameters(_, _, _, _, _, _, _)) + .WillOnce(DoAll(SetArgReferee<1>(kEnabled), + SetArgReferee<2>(kEndpoint2), + SetArgReferee<3>(kCertificate), + SetArgReferee<4>(kAuthToken), + SetArgReferee<5>(kTransportType), + SetArgReferee<6>(kHybridAppPreferenceStr), + Return(true))); + + std::vector<std::string> nicknames{"CloudApp"}; + EXPECT_CALL(*mock_policy_handler_, GetInitialAppData(_, _, _)) + .WillOnce(DoAll(SetArgPointee<1>(nicknames), Return(true))); + + const std::string url = "https://www.fakeiconurl.com/icon.png"; + EXPECT_CALL(*mock_policy_handler_, GetIconUrl("1234")) + .WillRepeatedly(Return(url)); + + app_manager_impl_->RefreshCloudAppInformation(); + + std::string result = app_manager_impl_->PolicyIDByIconUrl(url); + EXPECT_EQ(result, "1234"); +} + +TEST_F(ApplicationManagerImplTest, SetIconFileFromSystemRequest_Success) { + CreatePendingApplication(); + Mock::VerifyAndClearExpectations(mock_message_helper_); + + file_system::CreateDirectory(kDirectoryName); + const std::string full_icon_path = kDirectoryName + "/1234"; + ASSERT_TRUE(file_system::CreateFile(full_icon_path)); + + const std::string url = "https://www.fakeiconurl.com/icon.png"; + EXPECT_CALL(*mock_policy_handler_, GetIconUrl("1234")) + .WillRepeatedly(Return(url)); + + smart_objects::SmartObject dummy_object(smart_objects::SmartType_Map); + smart_objects::SmartObjectSPtr sptr = + std::make_shared<smart_objects::SmartObject>(dummy_object); + + EXPECT_CALL(*mock_message_helper_, + CreateModuleInfoSO( + hmi_apis::FunctionID::BasicCommunication_UpdateAppList, _)) + .WillOnce(Return(sptr)); + EXPECT_CALL(*mock_rpc_service_, ManageHMICommand(sptr, _)).Times(1); + EXPECT_CALL(mock_application_manager_settings_, app_icons_folder()) + .WillOnce(ReturnRef(kDirectoryName)); + app_manager_impl_->SetIconFileFromSystemRequest("1234"); + EXPECT_TRUE(file_system::RemoveDirectory(kDirectoryName, true)); +} + #endif // CLOUD_APP_WEBSOCKET_TRANSPORT_SUPPORT } // namespace application_manager_test } // namespace components diff --git a/src/components/policy/policy_regular/test/sql_pt_representation_test.cc b/src/components/policy/policy_regular/test/sql_pt_representation_test.cc index dc11e11f12..d456aa26e4 100644 --- a/src/components/policy/policy_regular/test/sql_pt_representation_test.cc +++ b/src/components/policy/policy_regular/test/sql_pt_representation_test.cc @@ -322,6 +322,8 @@ class SQLPTRepresentationTest : public SQLPTRepresentation, app_policies["1234"]["steal_focus"] = Json::Value(false); app_policies["1234"]["RequestType"] = Json::Value(Json::arrayValue); app_policies["1234"]["app_services"] = Json::Value(Json::objectValue); + app_policies["1234"]["icon_url"] = + Json::Value("http:://www.sdl.com/image.png"); app_policies["1234"]["app_services"]["MEDIA"] = Json::Value(Json::objectValue); app_policies["1234"]["app_services"]["MEDIA"]["service_names"] = @@ -1745,6 +1747,11 @@ TEST_F(SQLPTRepresentationTest, Save_SetPolicyTableThenSave_ExpectSavedToPT) { EXPECT_TRUE(handled_rpcs.is_initialized()); EXPECT_EQ(handled_rpcs[0].function_id, 41); + + policy_table::ApplicationPolicies& apps = policies.apps; + auto icon_url = *(apps[kAppId].icon_url); + + EXPECT_EQ(std::string(icon_url), "http:://www.sdl.com/image.png"); } } // namespace policy_test diff --git a/src/components/protocol_handler/src/protocol_handler_impl.cc b/src/components/protocol_handler/src/protocol_handler_impl.cc index e0768b3adf..222ca635d0 100644 --- a/src/components/protocol_handler/src/protocol_handler_impl.cc +++ b/src/components/protocol_handler/src/protocol_handler_impl.cc @@ -1501,11 +1501,18 @@ uint32_t get_hash_id(const ProtocolPacket& packet) { return HASH_ID_WRONG; } if (packet.protocol_version() >= PROTOCOL_VERSION_5) { - BsonObject obj = bson_object_from_bytes(packet.data()); - const uint32_t hash_id = - (uint32_t)bson_object_get_int32(&obj, strings::hash_id); - bson_object_deinitialize(&obj); - return hash_id; + BsonObject obj; + size_t obj_size = bson_object_from_bytes_len( + &obj, packet.data(), packet.total_data_bytes()); + if (obj_size > 0) { + const uint32_t hash_id = + (uint32_t)bson_object_get_int32(&obj, strings::hash_id); + bson_object_deinitialize(&obj); + return hash_id; + } else { + LOG4CXX_WARN(logger_, "Failed to parse BSON field for hash ID"); + return HASH_ID_WRONG; + } } else { const uint32_t hash_be = *(reinterpret_cast<uint32_t*>(packet.data())); const uint32_t hash_le = BE_TO_LE32(hash_be); @@ -1637,7 +1644,13 @@ RESULT_CODE ProtocolHandlerImpl::HandleControlMessageStartSession( BsonObject bson_obj; if (packet->data() != NULL) { - bson_obj = bson_object_from_bytes(packet->data()); + size_t bson_obj_size = bson_object_from_bytes_len( + &bson_obj, packet->data(), packet->total_data_bytes()); + if (bson_obj_size == 0) { + LOG4CXX_WARN(logger_, + "Failed to parse BSON field of start service packet"); + bson_object_initialize_default(&bson_obj); + } } else { bson_object_initialize_default(&bson_obj); } @@ -1730,33 +1743,42 @@ void ProtocolHandlerImpl::NotifySessionStarted( // when video service is successfully started, copy input parameters // ("width", "height", "videoProtocol", "videoCodec") to the ACK packet if (packet->service_type() == kMobileNav && packet->data() != NULL) { - BsonObject req_param = bson_object_from_bytes(packet->data()); - BsonElement* element = NULL; - - if ((element = bson_object_get(&req_param, strings::height)) != NULL && - element->type == TYPE_INT32) { - bson_object_put_int32(start_session_ack_params.get(), - strings::height, - bson_object_get_int32(&req_param, strings::height)); - } - if ((element = bson_object_get(&req_param, strings::width)) != NULL && - element->type == TYPE_INT32) { - bson_object_put_int32(start_session_ack_params.get(), - strings::width, - bson_object_get_int32(&req_param, strings::width)); - } - char* protocol = - bson_object_get_string(&req_param, strings::video_protocol); - if (protocol != NULL) { - bson_object_put_string( - start_session_ack_params.get(), strings::video_protocol, protocol); - } - char* codec = bson_object_get_string(&req_param, strings::video_codec); - if (codec != NULL) { - bson_object_put_string( - start_session_ack_params.get(), strings::video_codec, codec); + BsonObject req_param; + size_t req_param_size = bson_object_from_bytes_len( + &req_param, packet->data(), packet->total_data_bytes()); + if (req_param_size > 0) { + BsonElement* element = NULL; + + if ((element = bson_object_get(&req_param, strings::height)) != NULL && + element->type == TYPE_INT32) { + bson_object_put_int32( + start_session_ack_params.get(), + strings::height, + bson_object_get_int32(&req_param, strings::height)); + } + if ((element = bson_object_get(&req_param, strings::width)) != NULL && + element->type == TYPE_INT32) { + bson_object_put_int32( + start_session_ack_params.get(), + strings::width, + bson_object_get_int32(&req_param, strings::width)); + } + char* protocol = + bson_object_get_string(&req_param, strings::video_protocol); + if (protocol != NULL) { + bson_object_put_string( + start_session_ack_params.get(), strings::video_protocol, protocol); + } + char* codec = bson_object_get_string(&req_param, strings::video_codec); + if (codec != NULL) { + bson_object_put_string( + start_session_ack_params.get(), strings::video_codec, codec); + } + bson_object_deinitialize(&req_param); + } else { + LOG4CXX_WARN(logger_, + "Failed to parse BSON field of start service (video)"); } - bson_object_deinitialize(&req_param); } std::shared_ptr<utils::SemanticVersion> fullVersion; @@ -1765,16 +1787,24 @@ void ProtocolHandlerImpl::NotifySessionStarted( // could still be a payload, in which case we can get the real protocol // version if (packet->service_type() == kRpc && packet->data() != NULL) { - BsonObject request_params = bson_object_from_bytes(packet->data()); - char* version_param = - bson_object_get_string(&request_params, strings::protocol_version); - std::string version_string(version_param == NULL ? "" : version_param); - fullVersion = std::make_shared<utils::SemanticVersion>(version_string); - // Constructed payloads added in Protocol v5 - if (fullVersion->major_version_ < PROTOCOL_VERSION_5) { - rejected_params.push_back(std::string(strings::protocol_version)); + BsonObject request_params; + size_t request_params_size = bson_object_from_bytes_len( + &request_params, packet->data(), packet->total_data_bytes()); + if (request_params_size > 0) { + char* version_param = + bson_object_get_string(&request_params, strings::protocol_version); + std::string version_string(version_param == NULL ? "" : version_param); + fullVersion = std::make_shared<utils::SemanticVersion>(version_string); + // Constructed payloads added in Protocol v5 + if (fullVersion->major_version_ < PROTOCOL_VERSION_5) { + rejected_params.push_back(std::string(strings::protocol_version)); + } + bson_object_deinitialize(&request_params); + } else { + LOG4CXX_WARN(logger_, + "Failed to parse start service packet for version string"); + fullVersion = std::make_shared<utils::SemanticVersion>(); } - bson_object_deinitialize(&request_params); } else { fullVersion = std::make_shared<utils::SemanticVersion>(); } diff --git a/src/components/transport_manager/include/transport_manager/cloud/cloud_device.h b/src/components/transport_manager/include/transport_manager/cloud/cloud_device.h index 47a82e7921..9c25be2a3e 100644 --- a/src/components/transport_manager/include/transport_manager/cloud/cloud_device.h +++ b/src/components/transport_manager/include/transport_manager/cloud/cloud_device.h @@ -43,22 +43,33 @@ namespace transport_manager { namespace transport_adapter { +struct CloudAppEndpoint { + std::string host; + std::string port; + std::string path; + std::string query; + std::string fragment; +}; + class CloudDevice : public Device { public: CloudDevice(std::string& host, std::string& port, std::string& name); + CloudDevice(CloudAppEndpoint endpoint, std::string& name); + virtual const std::string& GetHost() const; virtual const std::string& GetPort() const; + virtual const std::string GetTarget() const; + protected: virtual bool IsSameAs(const Device* other_device) const; virtual ApplicationList GetApplicationList() const; private: - const std::string host_; - const std::string port_; + const CloudAppEndpoint endpoint_; }; } // namespace transport_adapter diff --git a/src/components/transport_manager/src/cloud/cloud_device.cc b/src/components/transport_manager/src/cloud/cloud_device.cc index 35510f4cf8..c1ad186ded 100644 --- a/src/components/transport_manager/src/cloud/cloud_device.cc +++ b/src/components/transport_manager/src/cloud/cloud_device.cc @@ -42,7 +42,15 @@ CREATE_LOGGERPTR_GLOBAL(logger_, "TransportManager") CloudDevice::CloudDevice(std::string& host, std::string& port, std::string& name) - : Device(name, std::string(name)), host_(host), port_(port) {} + : Device(name, std::string(name)) + , endpoint_(CloudAppEndpoint{.host = host, + .port = port, + .path = "/", + .query = "", + .fragment = ""}) {} + +CloudDevice::CloudDevice(CloudAppEndpoint endpoint, std::string& name) + : Device(name, std::string(name)), endpoint_(endpoint) {} bool CloudDevice::IsSameAs(const Device* other) const { LOG4CXX_TRACE(logger_, "enter. device: " << other); @@ -54,12 +62,18 @@ bool CloudDevice::IsSameAs(const Device* other) const { return false; } - if (host_ != other_cloud_device->GetHost()) { + if (GetHost() != other_cloud_device->GetHost()) { + return false; + } + + if (GetPort() != other_cloud_device->GetPort()) { return false; } - if (port_ != other_cloud_device->GetPort()) { + + if (GetTarget() != other_cloud_device->GetTarget()) { return false; } + return true; } @@ -68,11 +82,15 @@ ApplicationList CloudDevice::GetApplicationList() const { } const std::string& CloudDevice::GetHost() const { - return host_; + return endpoint_.host; } const std::string& CloudDevice::GetPort() const { - return port_; + return endpoint_.port; +} + +const std::string CloudDevice::GetTarget() const { + return endpoint_.path + endpoint_.query + endpoint_.fragment; } } // namespace transport_adapter diff --git a/src/components/transport_manager/src/cloud/cloud_websocket_transport_adapter.cc b/src/components/transport_manager/src/cloud/cloud_websocket_transport_adapter.cc index e141a65ec0..622531b120 100644 --- a/src/components/transport_manager/src/cloud/cloud_websocket_transport_adapter.cc +++ b/src/components/transport_manager/src/cloud/cloud_websocket_transport_adapter.cc @@ -80,15 +80,20 @@ void CloudWebsocketTransportAdapter::CreateDevice(const std::string& uid) { return; } - // Port after second colon in valid endpoint string - std::size_t pos_port = uid.find(":"); - pos_port = uid.find(":", pos_port + 1); + std::string protocol_pattern = "(wss?)"; + std::string host_pattern = + "(([^?#%\\\\/@:\\s]{1,})\\:?([^?#%\\\\/@\\s]*)\\@?([^?#%\\\\/\\s]*))"; + std::string port_pattern = "(\\d{2,5})"; + // Optional parameters + std::string path_pattern = "((\\/[^\\/#?\\s]+)*)?\\/?"; + std::string query_pattern = "(\\?[^=&#\\s]*=?[^#\\s]*&?)?"; + std::string fragment_pattern = "(#[^\\s]*)?"; // Extract host and port from endpoint string - boost::regex group_pattern( - "(wss?:\\/\\/)([A-Z\\d\\.-]{2,}\\.?([A-Z]{2,})?)(:)(\\d{2,5})(\\/" - "[A-Z\\d\\.-]+)*\\/?", - boost::regex::icase); + boost::regex group_pattern(protocol_pattern + ":\\/\\/" + host_pattern + ":" + + port_pattern + path_pattern + query_pattern + + fragment_pattern, + boost::regex::icase); boost::smatch results; std::string str = uid; @@ -97,20 +102,30 @@ void CloudWebsocketTransportAdapter::CreateDevice(const std::string& uid) { return; } - std::string host = results[2]; - std::string port = results[5]; + LOG4CXX_DEBUG(logger_, "#Results: " << results.size()); + std::string results_str; + for (size_t i = 0; i < results.size(); i++) { + results_str += " R[" + std::to_string(i) + "]:"; + results_str += + (results[i].length() != 0) ? results[i] : std::string("<EMPTY>"); + } + LOG4CXX_DEBUG(logger_, "Results: " << results_str); - LOG4CXX_DEBUG(logger_, - "Results: " << results[0] << " " << results[1] << " " - << results[2] << " " << results[3] << " " - << results[4] << " " << results[5] << " "); std::string device_id = uid; - LOG4CXX_DEBUG( - logger_, - "Creating Cloud Device For Host: " << host << " and Port: " << port); + CloudAppEndpoint endpoint{.host = results[2], + .port = results[6], + .path = results[7] + "/", + .query = results[9], + .fragment = results[10]}; + + LOG4CXX_DEBUG(logger_, + "Creating Cloud Device For Host: " + << endpoint.host << " at Port: " << endpoint.port + << " with Target: " + << (endpoint.path + endpoint.query + endpoint.fragment)); - auto cloud_device = std::make_shared<CloudDevice>(host, port, device_id); + auto cloud_device = std::make_shared<CloudDevice>(endpoint, device_id); DeviceVector devices{cloud_device}; diff --git a/src/components/transport_manager/src/cloud/websocket_client_connection.cc b/src/components/transport_manager/src/cloud/websocket_client_connection.cc index a93a27ba40..ec2fb0bcfb 100644 --- a/src/components/transport_manager/src/cloud/websocket_client_connection.cc +++ b/src/components/transport_manager/src/cloud/websocket_client_connection.cc @@ -160,11 +160,11 @@ TransportAdapter::Error WebsocketClientConnection::Start() { // Perform websocket handshake if (cloud_properties.cloud_transport_type == "WS") { - ws_.handshake(host, "/", ec); + ws_.handshake(host, cloud_device->GetTarget(), ec); } #ifdef ENABLE_SECURITY else if (cloud_properties.cloud_transport_type == "WSS") { - wss_.handshake(host, "/", ec); + wss_.handshake(host, cloud_device->GetTarget(), ec); } #endif // ENABLE_SECURITY if (ec) { diff --git a/src/components/transport_manager/test/include/transport_manager/cloud/sample_websocket_server.h b/src/components/transport_manager/test/include/transport_manager/cloud/sample_websocket_server.h index a60aefc7b0..a8b801c1fe 100644 --- a/src/components/transport_manager/test/include/transport_manager/cloud/sample_websocket_server.h +++ b/src/components/transport_manager/test/include/transport_manager/cloud/sample_websocket_server.h @@ -34,8 +34,6 @@ #ifndef SRC_COMPONENTS_TRANSPORT_MANAGER_TEST_INCLUDE_TRANSPORT_MANAGER_CLOUD_SAMPLE_WEBSOCKET_SERVER_H_ #define SRC_COMPONENTS_TRANSPORT_MANAGER_TEST_INCLUDE_TRANSPORT_MANAGER_CLOUD_SAMPLE_WEBSOCKET_SERVER_H_ -#include <unistd.h> -#include <algorithm> #include <boost/asio/bind_executor.hpp> #include <boost/asio/ip/tcp.hpp> #include <boost/asio/placeholders.hpp> @@ -46,13 +44,11 @@ #include <boost/beast/websocket/ssl.hpp> #include <boost/make_shared.hpp> #include <boost/thread/thread.hpp> -#include <cstdlib> -#include <functional> #include <iostream> -#include <memory> +#include <queue> +#include <set> #include <string> #include <thread> -#include <vector> namespace sample { namespace websocket { @@ -70,19 +66,31 @@ class WSSession { class WSServer { public: explicit WSServer(tcp::socket&& socket); + void AddURLRoute(const std::string& route); + // Start the asynchronous operation void Run(); - void OnAccept(beast::error_code ec); private: + void OnWebsocketHandshake(const boost::system::error_code& ec); + void OnAccept(beast::error_code ec); + // Check if route can be handled by the server + bool CanHandleRoute(const std::string& route); + std::string ParseRouteFromTarget(const std::string& target); + websocket::stream<tcp::socket> ws_; beast::flat_buffer buffer_; boost::asio::strand<boost::asio::io_context::executor_type> strand_; + http::request<http::string_body> req_; + std::set<std::string> url_routes_; }; public: WSSession(const std::string& address, uint16_t port); + // Start Accepting incoming connections void Run(); void Stop(); + // Add route endpoint which can be handled the server + void AddRoute(const std::string& route); private: void on_accept(boost::system::error_code ec); @@ -94,6 +102,7 @@ class WSSession { beast::flat_buffer buffer_; boost::asio::ip::tcp::endpoint endpoint_; std::shared_ptr<WSServer> ws_; + std::queue<std::string> buffered_routes_; }; // Accepts incoming connections and launches the sessions @@ -103,14 +112,23 @@ class WSSSession { public: // Take ownership of the socket WSSServer(tcp::socket&& socket, ssl::context& ctx); + void AddURLRoute(const std::string& route); // Start the asynchronous operation void Run(); + + private: void OnSSLHandshake(beast::error_code ec); + void OnWebsocketHandshake(const boost::system::error_code& ec); void OnAccept(beast::error_code ec); - private: + // Check if route can be handled by the server + bool CanHandleRoute(const std::string& route); + std::string ParseRouteFromTarget(const std::string& target); + websocket::stream<ssl::stream<tcp::socket> > wss_; beast::flat_buffer buffer_; + http::request<http::string_body> req_; + std::set<std::string> url_routes_; }; public: @@ -121,6 +139,8 @@ class WSSSession { // Start accepting incoming connections void Run(); void Stop(); + // Add route endpoint which can be handled the server + void AddRoute(const std::string& route); private: void do_accept(); @@ -133,9 +153,10 @@ class WSSSession { ssl::context ctx_; tcp::endpoint endpoint_; std::shared_ptr<WSSServer> wss_; + std::queue<std::string> buffered_routes_; }; } // namespace websocket } // namespace sample -#endif // SRC_COMPONENTS_TRANSPORT_MANAGER_TEST_INCLUDE_TRANSPORT_MANAGER_CLOUD_SAMPLE_WEBSOCKET_SERVER_H_
\ No newline at end of file +#endif // SRC_COMPONENTS_TRANSPORT_MANAGER_TEST_INCLUDE_TRANSPORT_MANAGER_CLOUD_SAMPLE_WEBSOCKET_SERVER_H_ diff --git a/src/components/transport_manager/test/sample_websocket_server.cc b/src/components/transport_manager/test/sample_websocket_server.cc index 56899e72e2..917184a361 100644 --- a/src/components/transport_manager/test/sample_websocket_server.cc +++ b/src/components/transport_manager/test/sample_websocket_server.cc @@ -1,3 +1,35 @@ +/* + * Copyright (c) 2019, Ford Motor Company + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following + * disclaimer in the documentation and/or other materials provided with the + * distribution. + * + * Neither the name of the Ford Motor Company nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + #include "transport_manager/cloud/sample_websocket_server.h" namespace { @@ -13,20 +45,78 @@ namespace websocket { WSSession::WSServer::WSServer(tcp::socket&& socket) : ws_(std::move(socket)), strand_(ws_.get_executor()) {} +void WSSession::WSServer::AddURLRoute(const std::string& target) { + url_routes_.insert(ParseRouteFromTarget(target)); +} + void WSSession::WSServer::Run() { - // Accept the websocket handshake - ws_.async_accept(boost::asio::bind_executor( - strand_, std::bind(&WSServer::OnAccept, this, std::placeholders::_1))); + req_ = {}; + http::async_read( + ws_.next_layer(), + buffer_, + req_, + std::bind(&WSServer::OnWebsocketHandshake, this, std::placeholders::_1)); +} + +void WSSession::WSServer::OnWebsocketHandshake( + const boost::system::error_code& ec) { + if (ec) { + return Fail("ERROR_HTTP_REQUEST_READ", ec); + } + if (websocket::is_upgrade(req_)) { + // Check target + std::string route = ParseRouteFromTarget(req_.target().to_string()); + if (!CanHandleRoute(route)) { + auto error = boost::system::errc::make_error_code( + boost::system::errc::address_not_available); + ws_.next_layer().close(); + return Fail("ERROR_INVALID_TARGET", error); + } + // Accept the websocket handshake + ws_.async_accept( + req_, + boost::asio::bind_executor( + strand_, + std::bind(&WSServer::OnAccept, this, std::placeholders::_1))); + } } void WSSession::WSServer::OnAccept(beast::error_code ec) { if (ec) { - return Fail("ERROR_CONNECTION_ACCEPT", ec); + return Fail("ERROR_WEBSOCKET_HANDSHAKE", ec); + } +} + +bool WSSession::WSServer::CanHandleRoute(const std::string& route) { + if (url_routes_.find(route) == url_routes_.end()) { + return false; + } + return true; +} + +std::string WSSession::WSServer::ParseRouteFromTarget( + const std::string& target) { + std::string route = target; + // Remove fragment + auto fragment_pos = route.find('#'); + if (fragment_pos != std::string::npos) { + route = route.substr(0, fragment_pos); + } + // Remove query + auto query_pos = route.find('?'); + if (query_pos != std::string::npos) { + route = route.substr(0, query_pos); } + + return route; } WSSession::WSSession(const std::string& address, uint16_t port) - : address_(address), port_(port), acceptor_(ioc_), socket_(ioc_) { + : address_(address) + , port_(port) + , acceptor_(ioc_) + , socket_(ioc_) + , ws_(nullptr) { endpoint_ = {boost::asio::ip::make_address(address), port}; boost::system::error_code error; @@ -76,6 +166,14 @@ void WSSession::Stop() { } } +void WSSession::AddRoute(const std::string& route) { + if (ws_ == nullptr) { + buffered_routes_.push(route); + return; + } + ws_->AddURLRoute(route); +} + void WSSession::on_accept(boost::system::error_code ec) { if (ec) { Fail("ERROR_ON_ACCEPT", ec); @@ -85,12 +183,20 @@ void WSSession::on_accept(boost::system::error_code ec) { // Make websocket object and start ws_ = std::make_shared<WSServer>(std::move(socket_)); + // Load routes stored in buffer + while (!buffered_routes_.empty()) { + ws_->AddURLRoute(buffered_routes_.front()); + buffered_routes_.pop(); + } ws_->Run(); } WSSSession::WSSServer::WSSServer(tcp::socket&& socket, ssl::context& ctx) : wss_(std::move(socket), ctx) {} +void WSSSession::WSSServer::AddURLRoute(const std::string& target) { + url_routes_.insert(ParseRouteFromTarget(target)); +} void WSSSession::WSSServer::Run() { // Perform the SSL handshake wss_.next_layer().async_handshake( @@ -103,9 +209,32 @@ void WSSSession::WSSServer::OnSSLHandshake(beast::error_code ec) { return Fail("ERROR_SSL_HANDSHAKE", ec); } - // Accept the websocket handshake - wss_.async_accept( - std::bind(&WSSServer::OnAccept, this, std::placeholders::_1)); + req_ = {}; + http::async_read( + wss_.next_layer(), + buffer_, + req_, + std::bind(&WSSServer::OnWebsocketHandshake, this, std::placeholders::_1)); +} + +void WSSSession::WSSServer::OnWebsocketHandshake( + const boost::system::error_code& ec) { + if (ec) { + return Fail("ERROR_HTTP_REQUEST_READ", ec); + } + if (websocket::is_upgrade(req_)) { + // Check target + std::string route = ParseRouteFromTarget(req_.target().to_string()); + if (!CanHandleRoute(route)) { + auto error = boost::system::errc::make_error_code( + boost::system::errc::address_not_available); + wss_.next_layer().next_layer().close(); + return Fail("ERROR_INVALID_TARGET", error); + } + // Accept the websocket handshake + wss_.async_accept( + req_, std::bind(&WSSServer::OnAccept, this, std::placeholders::_1)); + } } void WSSSession::WSSServer::OnAccept(beast::error_code ec) { @@ -114,11 +243,38 @@ void WSSSession::WSSServer::OnAccept(beast::error_code ec) { } } +bool WSSSession::WSSServer::CanHandleRoute(const std::string& route) { + if (url_routes_.find(route) == url_routes_.end()) { + return false; + } + return true; +} + +std::string WSSSession::WSSServer::ParseRouteFromTarget( + const std::string& target) { + std::string route = target; + // Remove fragment + auto fragment_pos = route.find('#'); + if (fragment_pos != std::string::npos) { + route = route.substr(0, fragment_pos); + } + // Remove query + auto query_pos = route.find('?'); + if (query_pos != std::string::npos) { + route = route.substr(0, query_pos); + } + + return route; +} + WSSSession::WSSSession(const std::string& address, uint16_t port, const std::string& certificate, const std::string& private_key) - : acceptor_(ioc_), socket_(ioc_), ctx_(ssl::context::sslv23_server) { + : acceptor_(ioc_) + , socket_(ioc_) + , ctx_(ssl::context::sslv23_server) + , wss_(nullptr) { beast::error_code ec; endpoint_ = {boost::asio::ip::make_address(address), port}; @@ -185,6 +341,14 @@ void WSSSession::Stop() { } } +void WSSSession::AddRoute(const std::string& route) { + if (wss_ == nullptr) { + buffered_routes_.push(route); + return; + } + wss_->AddURLRoute(route); +} + void WSSSession::do_accept() { if (acceptor_.is_open()) { acceptor_.async_accept( @@ -202,8 +366,13 @@ void WSSSession::on_accept(boost::system::error_code ec) { } // Create the session and run it wss_ = std::make_shared<WSSServer>(std::move(socket_), ctx_); + // Load routes stored in buffer + while (!buffered_routes_.empty()) { + wss_->AddURLRoute(buffered_routes_.front()); + buffered_routes_.pop(); + } wss_->Run(); } } // namespace websocket -} // namespace sample
\ No newline at end of file +} // namespace sample diff --git a/src/components/transport_manager/test/transport_adapter_test.cc b/src/components/transport_manager/test/transport_adapter_test.cc index 3cef78493d..56386db201 100644 --- a/src/components/transport_manager/test/transport_adapter_test.cc +++ b/src/components/transport_manager/test/transport_adapter_test.cc @@ -42,6 +42,8 @@ #include "utils/test_async_waiter.h" #include "protocol/raw_message.h" +#include "transport_manager/cloud/cloud_device.h" +#include "transport_manager/cloud/cloud_websocket_transport_adapter.h" #include "transport_manager/transport_adapter/connection.h" #include "transport_manager/transport_adapter/transport_adapter_controller.h" #include "transport_manager/transport_adapter/transport_adapter_impl.h" @@ -84,6 +86,139 @@ class TransportAdapterTest : public ::testing::Test { std::string dev_id; std::string uniq_id; int app_handle; + +#if defined(CLOUD_APP_WEBSOCKET_TRANSPORT_SUPPORT) + struct TestEndpoint { + std::string test_string; + std::string host; + std::string port; + std::string target; + }; + + CloudAppProperties test_cloud_properties_{.endpoint = "", + .certificate = "no cert", + .enabled = true, + .auth_token = "no auth token", + .cloud_transport_type = "WS", + .hybrid_app_preference = "CLOUD"}; + std::vector<std::string> kWebsocketProtocols{"ws://", "wss://"}; + + std::vector<TestEndpoint> kValidTestEndpoints{ + // Host and port + TestEndpoint{"localhost:40/", "localhost", "40", "/"}, + TestEndpoint{"[::1]:40", "[::1]", "40", "/"}, + TestEndpoint{"username:password@localhost.com:80", + "username:password@localhost.com", + "80", + "/"}, + // With path + TestEndpoint{ + "localhost:440/file.html", "localhost", "440", "/file.html/"}, + TestEndpoint{"101.180.1.213:23234/folder/img_index(1)/file.html", + "101.180.1.213", + "23234", + "/folder/img_index(1)/file.html/"}, + TestEndpoint{"[2600:3c00::f03c:91ff:fe73:2b08]:31333/folder/img_index(1)/" + "file.html", + "[2600:3c00::f03c:91ff:fe73:2b08]", + "31333", + "/folder/img_index(1)/file.html/"}, + // With query and/or fragment + TestEndpoint{ + "username@localhost:22/folder/img_index(1)/" + "file.html?eventId=2345&eventName='some%20event'&eventSuccess=true", + "username@localhost", + "22", + "/folder/img_index(1)/file.html/" + "?eventId=2345&eventName='some%20event'&eventSuccess=" + "true"}, + TestEndpoint{"username@localhost.com:80/folder/img_index(1)/" + "file.html?eventId=2345&eventName='some%20event'&" + "eventSuccess=true#section1", + "username@localhost.com", + "80", + "/folder/img_index(1)/file.html/" + "?eventId=2345&eventName='some%20event'&eventSuccess=true#" + "section1"}, + TestEndpoint{ + "localhost:443/" + "?eventId=2345&eventName='some%20event'&eventSuccess=true#section1", + "localhost", + "443", + "/?eventId=2345&eventName='some%20event'&eventSuccess=true#" + "section1"}, + TestEndpoint{"a1-b2.com:443/folder/img_index(1)/file.html#section1", + "a1-b2.com", + "443", + "/folder/img_index(1)/file.html/#section1"}, + TestEndpoint{"a1-b2.com:23#section1", "a1-b2.com", "23", "/#section1"}}; + + std::vector<TestEndpoint> kInvalidTestEndpoints{ + // Invalid hostname + TestEndpoint{"/localhost:80", "localhost", "80", "/"}, + TestEndpoint{"local?host:80", "local?host", "80", "/"}, + TestEndpoint{"local#host:80", "local#host", "80", "/"}, + TestEndpoint{"local\%host:80", "local\%host", "80", "/"}, + TestEndpoint{"local\\host:80", "local\\host", "80", "/"}, + TestEndpoint{"local/host:80", "local/host", "80", "/"}, + TestEndpoint{"local host:80", "local host", "80", "/"}, + TestEndpoint{"local\thost:80", "local\thost", "80", "/"}, + TestEndpoint{":80#section1", "", "80", "/#section1"}, + // Invalid port + TestEndpoint{"username:password@localhost.com", + "username:password@localhost.com", + "", + "/"}, + TestEndpoint{"username:password@localhost.com:5", + "username:password@localhost.com", + "5", + "/"}, + TestEndpoint{"201.123.213:2h32/", "201.123.213", "2h32", "/"}}; + std::vector<TestEndpoint> kIncorrectTestEndpoints{ + // Incorrect port number + TestEndpoint{"201.123.1.213:232454/folder/img_index(1)/file.html", + "201.123.1.213", + "232454", + "/folder/img_index(1)/file.html/"}, + // Incorrect path + TestEndpoint{"201.123.1.213:232//folder/img_index(1)/file.html", + "201.123.1.213", + "232", + "//folder/img_index(1)/file.html/"}, + TestEndpoint{"201.123.1.213:232/folder/img_index(1)//file.html", + "201.123.1.213", + "232", + "/folder/img_index(1)//file.html/"}, + TestEndpoint{"201.123.1.213:232/folder/img index(1)//file.html", + "201.123.1.213", + "232", + "/folder/img index(1)//file.html/"}, + TestEndpoint{"201.123.1.213:232/folder/img\tindex(1)//file.html", + "201.123.1.213", + "232", + "/folder/img\tindex(1)//file.html/"}, + // Incorrect query + TestEndpoint{"username@localhost:443/?eventId=2345&eventName='some " + "event'&eventSuccess=true", + "username@localhost", + "443", + "?eventId=2345&eventName='some event'&eventSuccess=true"}, + TestEndpoint{"username@localhost:443/" + "?eventId=2345&eventName='some\tevent'&eventSuccess=true", + "username@localhost", + "443", + "?eventId=2345&eventName='some\tevent'&eventSuccess=true"}, + // Incorrect fragment + TestEndpoint{"a1(b2).com:80/folder/img_index(1)/file.html#section 1", + "a1(b2).com", + "80", + "/folder/img_index(1)/file.html#section 1"}, + TestEndpoint{"a1(b2).com:80/folder/img_index(1)/file.html#section\t1", + "a1(b2).com", + "80", + "/folder/img_index(1)/file.html#section\t1"}}; + +#endif // CLOUD_APP_WEBSOCKET_TRANSPORT_SUPPORT }; TEST_F(TransportAdapterTest, Init) { @@ -609,6 +744,83 @@ TEST_F(TransportAdapterTest, EXPECT_CALL(*serverMock, Terminate()); } + +TEST_F(TransportAdapterTest, WebsocketEndpointParsing_SUCCESS) { + std::shared_ptr<CloudWebsocketTransportAdapter> cta = + std::make_shared<CloudWebsocketTransportAdapter>( + last_state_, transport_manager_settings); + + for (auto protocol : kWebsocketProtocols) { + for (auto endpoint : kValidTestEndpoints) { + test_cloud_properties_.endpoint = protocol + endpoint.test_string; + cta->SetAppCloudTransportConfig("cloud app", test_cloud_properties_); + + auto ta = std::dynamic_pointer_cast<TransportAdapter>(cta); + ASSERT_NE(ta.use_count(), 0); + + ta->CreateDevice(test_cloud_properties_.endpoint); + + auto device = cta->FindDevice(test_cloud_properties_.endpoint); + ASSERT_NE(device.use_count(), 0); + + std::shared_ptr<CloudDevice> cloud_device = + std::dynamic_pointer_cast<CloudDevice>(device); + ASSERT_NE(cloud_device.use_count(), 0); + + EXPECT_EQ(cloud_device->GetHost(), endpoint.host); + EXPECT_EQ(cloud_device->GetPort(), endpoint.port); + EXPECT_EQ(cloud_device->GetTarget(), endpoint.target); + } + } +} +TEST_F(TransportAdapterTest, WebsocketEndpointParsing_INVALID) { + std::shared_ptr<CloudWebsocketTransportAdapter> cta = + std::make_shared<CloudWebsocketTransportAdapter>( + last_state_, transport_manager_settings); + + for (auto protocol : kWebsocketProtocols) { + for (auto endpoint : kInvalidTestEndpoints) { + test_cloud_properties_.endpoint = protocol + endpoint.test_string; + cta->SetAppCloudTransportConfig("cloud app", test_cloud_properties_); + + auto ta = std::dynamic_pointer_cast<TransportAdapter>(cta); + ASSERT_NE(ta.use_count(), 0); + + ta->CreateDevice(test_cloud_properties_.endpoint); + + auto device = cta->FindDevice(test_cloud_properties_.endpoint); + EXPECT_EQ(device.use_count(), 0); + } + } +} +TEST_F(TransportAdapterTest, WebsocketEndpointParsing_INCORRECT) { + std::shared_ptr<CloudWebsocketTransportAdapter> cta = + std::make_shared<CloudWebsocketTransportAdapter>( + last_state_, transport_manager_settings); + + for (auto protocol : kWebsocketProtocols) { + for (auto endpoint : kIncorrectTestEndpoints) { + test_cloud_properties_.endpoint = protocol + endpoint.test_string; + cta->SetAppCloudTransportConfig("cloud app", test_cloud_properties_); + + auto ta = std::dynamic_pointer_cast<TransportAdapter>(cta); + ASSERT_NE(ta.use_count(), 0); + + ta->CreateDevice(test_cloud_properties_.endpoint); + + auto device = cta->FindDevice(test_cloud_properties_.endpoint); + ASSERT_NE(device.use_count(), 0); + + std::shared_ptr<CloudDevice> cloud_device = + std::dynamic_pointer_cast<CloudDevice>(device); + ASSERT_NE(cloud_device.use_count(), 0); + + EXPECT_FALSE(cloud_device->GetHost() == endpoint.host && + cloud_device->GetPort() == endpoint.port && + cloud_device->GetTarget() == endpoint.target); + } + } +} #endif // CLOUD_APP_WEBSOCKET_TRANSPORT_SUPPORT TEST_F(TransportAdapterTest, DisconnectDevice_DeviceAddedConnectionCreated) { diff --git a/src/components/transport_manager/test/websocket_connection_test.cc b/src/components/transport_manager/test/websocket_connection_test.cc index 9f9793765a..db3bc598b1 100644 --- a/src/components/transport_manager/test/websocket_connection_test.cc +++ b/src/components/transport_manager/test/websocket_connection_test.cc @@ -84,14 +84,16 @@ class WebsocketConnectionTest : public ::testing::Test { ASSERT_NE(client_out.connection.use_count(), 0); } - void StartWSServer() { + void StartWSServer(std::string path) { ws_session = std::make_shared<websocket::WSSession>(kHost, kPort); + ws_session->AddRoute(path); ws_session->Run(); } - void StartWSSServer() { + void StartWSSServer(std::string path) { wss_session = std::make_shared<websocket::WSSSession>( kHost, kPort, kCertificate, kPrivateKey); + wss_session->AddRoute(path); wss_session->Run(); } @@ -115,6 +117,10 @@ class WebsocketConnectionTest : public ::testing::Test { WebsocketClient ws_client; std::string kHost = "127.0.0.1"; uint16_t kPort = 8080; + std::string kPath = "/folder/file.html/"; + std::string kQuery = "?eventId=2345&eventName='Test'&expectedResult=true"; + std::string kFragment = "#section_1"; + // Sample certificate for localhost std::string kCertificate = "-----BEGIN " @@ -262,7 +268,39 @@ class WebsocketConnectionTest : public ::testing::Test { TEST_F(WebsocketConnectionTest, WSConnection_SUCCESS) { transport_manager::transport_adapter::CloudAppProperties properties{ - .endpoint = "ws://" + kHost + ":" + std::to_string(kPort) + "/", + .endpoint = "ws://" + kHost + ":" + std::to_string(kPort), + .certificate = "no cert", + .enabled = true, + .auth_token = "auth_token", + .cloud_transport_type = "WS", + .hybrid_app_preference = "CLOUD"}; + + // Start server + std::thread t1(&WebsocketConnectionTest::StartWSServer, this, "/"); + usleep(5000); + + // Start client + InitWebsocketClient(properties, ws_client); + std::shared_ptr<WebsocketClientConnection> ws_connection = + ws_client.connection; + + // Check websocket connection + TransportAdapter::Error ret_code = ws_connection->Start(); + EXPECT_EQ(TransportAdapter::OK, ret_code); + + // Stop client + ret_code = ws_connection->Disconnect(); + EXPECT_EQ(TransportAdapter::OK, ret_code); + + // Stop server thread + ws_session->Stop(); + t1.join(); +} + +TEST_F(WebsocketConnectionTest, WSConnection_SUCCESS_ValidTarget) { + transport_manager::transport_adapter::CloudAppProperties properties{ + .endpoint = "ws://" + kHost + ":" + std::to_string(kPort) + kPath + + kQuery + kFragment, .certificate = "no cert", .enabled = true, .auth_token = "auth_token", @@ -270,8 +308,8 @@ TEST_F(WebsocketConnectionTest, WSConnection_SUCCESS) { .hybrid_app_preference = "CLOUD"}; // Start server - std::thread t1(&WebsocketConnectionTest::StartWSServer, this); - sleep(1); + std::thread t1(&WebsocketConnectionTest::StartWSServer, this, kPath); + usleep(5000); // Start client InitWebsocketClient(properties, ws_client); @@ -291,9 +329,41 @@ TEST_F(WebsocketConnectionTest, WSConnection_SUCCESS) { t1.join(); } +TEST_F(WebsocketConnectionTest, WSConnection_FAILURE_InvalidTarget) { + transport_manager::transport_adapter::CloudAppProperties properties{ + .endpoint = "ws://" + kHost + ":" + std::to_string(kPort) + kPath + + kQuery + kFragment, + .certificate = "no cert", + .enabled = true, + .auth_token = "auth_token", + .cloud_transport_type = "WS", + .hybrid_app_preference = "CLOUD"}; + + // Start server + std::thread t1(&WebsocketConnectionTest::StartWSServer, this, "/"); + usleep(5000); + + // Start client + InitWebsocketClient(properties, ws_client); + std::shared_ptr<WebsocketClientConnection> ws_connection = + ws_client.connection; + + // Check websocket connection + TransportAdapter::Error ret_code = ws_connection->Start(); + EXPECT_EQ(TransportAdapter::FAIL, ret_code); + + // Stop client + ret_code = ws_connection->Disconnect(); + EXPECT_EQ(TransportAdapter::OK, ret_code); + + // Stop server thread + ws_session->Stop(); + t1.join(); +} + TEST_F(WebsocketConnectionTest, WSSConnection_SUCCESS) { transport_manager::transport_adapter::CloudAppProperties properties{ - .endpoint = "wss://" + kHost + ":" + std::to_string(kPort) + "/", + .endpoint = "wss://" + kHost + ":" + std::to_string(kPort), .certificate = kCACertificate, .enabled = true, .auth_token = "auth_token", @@ -301,8 +371,8 @@ TEST_F(WebsocketConnectionTest, WSSConnection_SUCCESS) { .hybrid_app_preference = "CLOUD"}; // Start server - std::thread t1(&WebsocketConnectionTest::StartWSSServer, this); - sleep(1); + std::thread t1(&WebsocketConnectionTest::StartWSSServer, this, "/"); + usleep(5000); // Start client InitWebsocketClient(properties, ws_client); @@ -322,9 +392,73 @@ TEST_F(WebsocketConnectionTest, WSSConnection_SUCCESS) { t1.join(); } +TEST_F(WebsocketConnectionTest, WSSConnection_SUCCESS_ValidTarget) { + transport_manager::transport_adapter::CloudAppProperties properties{ + .endpoint = "wss://" + kHost + ":" + std::to_string(kPort) + kPath, + .certificate = kCACertificate, + .enabled = true, + .auth_token = "auth_token", + .cloud_transport_type = "WSS", + .hybrid_app_preference = "CLOUD"}; + + // Start server + std::thread t1(&WebsocketConnectionTest::StartWSSServer, + this, + (kPath + kQuery + kFragment)); + usleep(5000); + + // Start client + InitWebsocketClient(properties, ws_client); + std::shared_ptr<WebsocketClientConnection> wss_connection = + ws_client.connection; + + // Check websocket connection + TransportAdapter::Error ret_code = wss_connection->Start(); + EXPECT_EQ(TransportAdapter::OK, ret_code); + + // Stop client + ret_code = wss_connection->Disconnect(); + EXPECT_EQ(TransportAdapter::OK, ret_code); + + // Stop server thread + wss_session->Stop(); + t1.join(); +} + +TEST_F(WebsocketConnectionTest, WSSConnection_FAILURE_InvalidTarget) { + transport_manager::transport_adapter::CloudAppProperties properties{ + .endpoint = "wss://" + kHost + ":" + std::to_string(kPort), + .certificate = kCACertificate, + .enabled = true, + .auth_token = "auth_token", + .cloud_transport_type = "WSS", + .hybrid_app_preference = "CLOUD"}; + + // Start server + std::thread t1(&WebsocketConnectionTest::StartWSSServer, this, kPath); + usleep(5000); + + // Start client + InitWebsocketClient(properties, ws_client); + std::shared_ptr<WebsocketClientConnection> wss_connection = + ws_client.connection; + + // Check websocket connection + TransportAdapter::Error ret_code = wss_connection->Start(); + EXPECT_EQ(TransportAdapter::FAIL, ret_code); + + // Stop client + ret_code = wss_connection->Disconnect(); + EXPECT_EQ(TransportAdapter::OK, ret_code); + + // Stop server thread + wss_session->Stop(); + t1.join(); +} + TEST_F(WebsocketConnectionTest, WSSConnection_FAILURE_IncorrectCert) { transport_manager::transport_adapter::CloudAppProperties properties{ - .endpoint = "wss://" + kHost + ":" + std::to_string(kPort) + "/", + .endpoint = "wss://" + kHost + ":" + std::to_string(kPort), .certificate = kIncorrectCertificate, .enabled = true, .auth_token = "auth_token", @@ -332,8 +466,8 @@ TEST_F(WebsocketConnectionTest, WSSConnection_FAILURE_IncorrectCert) { .hybrid_app_preference = "CLOUD"}; // Start server - std::thread t1(&WebsocketConnectionTest::StartWSSServer, this); - sleep(1); + std::thread t1(&WebsocketConnectionTest::StartWSSServer, this, "/"); + usleep(5000); // Start client InitWebsocketClient(properties, ws_client); |