1b381365edadcac463c07d045ad29b43ef96099a1Alex Vakulenko// Copyright 2014 The Chromium OS Authors. All rights reserved. 2b381365edadcac463c07d045ad29b43ef96099a1Alex Vakulenko// Use of this source code is governed by a BSD-style license that can be 3b381365edadcac463c07d045ad29b43ef96099a1Alex Vakulenko// found in the LICENSE file. 4b381365edadcac463c07d045ad29b43ef96099a1Alex Vakulenko 59ed0cab99f18acb3570a35e9408f24355f6b8324Alex Vakulenko#include <brillo/dbus/utils.h> 6b381365edadcac463c07d045ad29b43ef96099a1Alex Vakulenko 700ceab8b84907509eaec878e1ae11ea36c18d441Alex Vakulenko#include <tuple> 800ceab8b84907509eaec878e1ae11ea36c18d441Alex Vakulenko#include <vector> 900ceab8b84907509eaec878e1ae11ea36c18d441Alex Vakulenko 10b381365edadcac463c07d045ad29b43ef96099a1Alex Vakulenko#include <base/bind.h> 119ed0cab99f18acb3570a35e9408f24355f6b8324Alex Vakulenko#include <brillo/errors/error_codes.h> 129ed0cab99f18acb3570a35e9408f24355f6b8324Alex Vakulenko#include <brillo/strings/string_utils.h> 13b381365edadcac463c07d045ad29b43ef96099a1Alex Vakulenko 149ed0cab99f18acb3570a35e9408f24355f6b8324Alex Vakulenkonamespace brillo { 15b381365edadcac463c07d045ad29b43ef96099a1Alex Vakulenkonamespace dbus_utils { 16b381365edadcac463c07d045ad29b43ef96099a1Alex Vakulenko 17b381365edadcac463c07d045ad29b43ef96099a1Alex Vakulenkostd::unique_ptr<dbus::Response> CreateDBusErrorResponse( 18b381365edadcac463c07d045ad29b43ef96099a1Alex Vakulenko dbus::MethodCall* method_call, 19f437e3b367869af7cb5a53153284566164b48a7cAlex Vakulenko const std::string& error_name, 20f437e3b367869af7cb5a53153284566164b48a7cAlex Vakulenko const std::string& error_message) { 218c0f19284a22373b42e16d1422c48988c9ea71dcAlex Vakulenko return dbus::ErrorResponse::FromMethodCall(method_call, error_name, 228c0f19284a22373b42e16d1422c48988c9ea71dcAlex Vakulenko error_message); 23b381365edadcac463c07d045ad29b43ef96099a1Alex Vakulenko} 24b381365edadcac463c07d045ad29b43ef96099a1Alex Vakulenko 25b381365edadcac463c07d045ad29b43ef96099a1Alex Vakulenkostd::unique_ptr<dbus::Response> GetDBusError(dbus::MethodCall* method_call, 269ed0cab99f18acb3570a35e9408f24355f6b8324Alex Vakulenko const brillo::Error* error) { 27f437e3b367869af7cb5a53153284566164b48a7cAlex Vakulenko CHECK(error) << "Error object must be specified"; 28f437e3b367869af7cb5a53153284566164b48a7cAlex Vakulenko std::string error_name = DBUS_ERROR_FAILED; // Default error code. 29b381365edadcac463c07d045ad29b43ef96099a1Alex Vakulenko std::string error_message; 30b381365edadcac463c07d045ad29b43ef96099a1Alex Vakulenko 31b381365edadcac463c07d045ad29b43ef96099a1Alex Vakulenko // Special case for "dbus" error domain. 32b381365edadcac463c07d045ad29b43ef96099a1Alex Vakulenko // Pop the error code and message from the error chain and use them as the 33b381365edadcac463c07d045ad29b43ef96099a1Alex Vakulenko // actual D-Bus error message. 34b381365edadcac463c07d045ad29b43ef96099a1Alex Vakulenko if (error->GetDomain() == errors::dbus::kDomain) { 35f437e3b367869af7cb5a53153284566164b48a7cAlex Vakulenko error_name = error->GetCode(); 36b381365edadcac463c07d045ad29b43ef96099a1Alex Vakulenko error_message = error->GetMessage(); 37b381365edadcac463c07d045ad29b43ef96099a1Alex Vakulenko error = error->GetInnerError(); 38b381365edadcac463c07d045ad29b43ef96099a1Alex Vakulenko } 39b381365edadcac463c07d045ad29b43ef96099a1Alex Vakulenko 40b381365edadcac463c07d045ad29b43ef96099a1Alex Vakulenko // Append any inner errors to the error message. 41b381365edadcac463c07d045ad29b43ef96099a1Alex Vakulenko while (error) { 42b381365edadcac463c07d045ad29b43ef96099a1Alex Vakulenko // Format error string as "domain/code:message". 43b381365edadcac463c07d045ad29b43ef96099a1Alex Vakulenko if (!error_message.empty()) 44b381365edadcac463c07d045ad29b43ef96099a1Alex Vakulenko error_message += ';'; 4505d29044d14a60775ed6c51c75a414eb0cb50347Alex Vakulenko error_message += 4605d29044d14a60775ed6c51c75a414eb0cb50347Alex Vakulenko error->GetDomain() + '/' + error->GetCode() + ':' + error->GetMessage(); 47b381365edadcac463c07d045ad29b43ef96099a1Alex Vakulenko error = error->GetInnerError(); 48b381365edadcac463c07d045ad29b43ef96099a1Alex Vakulenko } 49f437e3b367869af7cb5a53153284566164b48a7cAlex Vakulenko return CreateDBusErrorResponse(method_call, error_name, error_message); 50b381365edadcac463c07d045ad29b43ef96099a1Alex Vakulenko} 51b381365edadcac463c07d045ad29b43ef96099a1Alex Vakulenko 529ed0cab99f18acb3570a35e9408f24355f6b8324Alex Vakulenkovoid AddDBusError(brillo::ErrorPtr* error, 53f437e3b367869af7cb5a53153284566164b48a7cAlex Vakulenko const std::string& dbus_error_name, 5400ceab8b84907509eaec878e1ae11ea36c18d441Alex Vakulenko const std::string& dbus_error_message) { 55852ff001e232f6fcc2bddd10d97c609d7461cda2Vitaly Buka std::vector<std::string> parts = string_utils::Split(dbus_error_message, ";"); 5600ceab8b84907509eaec878e1ae11ea36c18d441Alex Vakulenko std::vector<std::tuple<std::string, std::string, std::string>> errors; 5700ceab8b84907509eaec878e1ae11ea36c18d441Alex Vakulenko for (const std::string& part : parts) { 5800ceab8b84907509eaec878e1ae11ea36c18d441Alex Vakulenko // Each part should be in format of "domain/code:message" 5900ceab8b84907509eaec878e1ae11ea36c18d441Alex Vakulenko size_t slash_pos = part.find('/'); 6000ceab8b84907509eaec878e1ae11ea36c18d441Alex Vakulenko size_t colon_pos = part.find(':'); 6105d29044d14a60775ed6c51c75a414eb0cb50347Alex Vakulenko if (slash_pos != std::string::npos && colon_pos != std::string::npos && 6200ceab8b84907509eaec878e1ae11ea36c18d441Alex Vakulenko slash_pos < colon_pos) { 63f437e3b367869af7cb5a53153284566164b48a7cAlex Vakulenko // If we have both '/' and ':' and in proper order, then we have a 6400ceab8b84907509eaec878e1ae11ea36c18d441Alex Vakulenko // correctly encoded error object. 6500ceab8b84907509eaec878e1ae11ea36c18d441Alex Vakulenko std::string domain = part.substr(0, slash_pos); 6600ceab8b84907509eaec878e1ae11ea36c18d441Alex Vakulenko std::string code = part.substr(slash_pos + 1, colon_pos - slash_pos - 1); 6700ceab8b84907509eaec878e1ae11ea36c18d441Alex Vakulenko std::string message = part.substr(colon_pos + 1); 6800ceab8b84907509eaec878e1ae11ea36c18d441Alex Vakulenko errors.emplace_back(domain, code, message); 6900ceab8b84907509eaec878e1ae11ea36c18d441Alex Vakulenko } else if (slash_pos == std::string::npos && 7005d29044d14a60775ed6c51c75a414eb0cb50347Alex Vakulenko colon_pos == std::string::npos && errors.empty()) { 7100ceab8b84907509eaec878e1ae11ea36c18d441Alex Vakulenko // If we don't have both '/' and ':' and this is the first error object, 7200ceab8b84907509eaec878e1ae11ea36c18d441Alex Vakulenko // then we had a D-Bus error at the top of the error chain. 73f437e3b367869af7cb5a53153284566164b48a7cAlex Vakulenko errors.emplace_back(errors::dbus::kDomain, dbus_error_name, part); 7400ceab8b84907509eaec878e1ae11ea36c18d441Alex Vakulenko } else { 7500ceab8b84907509eaec878e1ae11ea36c18d441Alex Vakulenko // We have a malformed part. The whole D-Bus error was most likely 7600ceab8b84907509eaec878e1ae11ea36c18d441Alex Vakulenko // not generated by GetDBusError(). To be safe, stop parsing it 7700ceab8b84907509eaec878e1ae11ea36c18d441Alex Vakulenko // and return the error as received from D-Bus. 7800ceab8b84907509eaec878e1ae11ea36c18d441Alex Vakulenko errors.clear(); // Remove any errors accumulated so far. 7905d29044d14a60775ed6c51c75a414eb0cb50347Alex Vakulenko errors.emplace_back( 8005d29044d14a60775ed6c51c75a414eb0cb50347Alex Vakulenko errors::dbus::kDomain, dbus_error_name, dbus_error_message); 8100ceab8b84907509eaec878e1ae11ea36c18d441Alex Vakulenko break; 8200ceab8b84907509eaec878e1ae11ea36c18d441Alex Vakulenko } 8300ceab8b84907509eaec878e1ae11ea36c18d441Alex Vakulenko } 8400ceab8b84907509eaec878e1ae11ea36c18d441Alex Vakulenko 8500ceab8b84907509eaec878e1ae11ea36c18d441Alex Vakulenko // Go backwards and add the parsed errors to the error chain. 8600ceab8b84907509eaec878e1ae11ea36c18d441Alex Vakulenko for (auto it = errors.crbegin(); it != errors.crend(); ++it) { 8705d29044d14a60775ed6c51c75a414eb0cb50347Alex Vakulenko Error::AddTo( 8805d29044d14a60775ed6c51c75a414eb0cb50347Alex Vakulenko error, FROM_HERE, std::get<0>(*it), std::get<1>(*it), std::get<2>(*it)); 8900ceab8b84907509eaec878e1ae11ea36c18d441Alex Vakulenko } 9000ceab8b84907509eaec878e1ae11ea36c18d441Alex Vakulenko} 9100ceab8b84907509eaec878e1ae11ea36c18d441Alex Vakulenko 92b381365edadcac463c07d045ad29b43ef96099a1Alex Vakulenko} // namespace dbus_utils 939ed0cab99f18acb3570a35e9408f24355f6b8324Alex Vakulenko} // namespace brillo 94