utils.cc revision 852ff001e232f6fcc2bddd10d97c609d7461cda2
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 5b381365edadcac463c07d045ad29b43ef96099a1Alex Vakulenko#include <chromeos/dbus/utils.h> 6b381365edadcac463c07d045ad29b43ef96099a1Alex Vakulenko 700ceab8b84907509eaec878e1ae11ea36c18d441Alex Vakulenko#include <tuple> 800ceab8b84907509eaec878e1ae11ea36c18d441Alex Vakulenko#include <vector> 900ceab8b84907509eaec878e1ae11ea36c18d441Alex Vakulenko 10b381365edadcac463c07d045ad29b43ef96099a1Alex Vakulenko#include <base/bind.h> 11b381365edadcac463c07d045ad29b43ef96099a1Alex Vakulenko#include <base/memory/scoped_ptr.h> 1215104669cca242889ef13408ac79d24766434b22Alex Vakulenko#include <chromeos/errors/error_codes.h> 1300ceab8b84907509eaec878e1ae11ea36c18d441Alex Vakulenko#include <chromeos/strings/string_utils.h> 14b381365edadcac463c07d045ad29b43ef96099a1Alex Vakulenko 15b381365edadcac463c07d045ad29b43ef96099a1Alex Vakulenkonamespace chromeos { 16b381365edadcac463c07d045ad29b43ef96099a1Alex Vakulenkonamespace dbus_utils { 17b381365edadcac463c07d045ad29b43ef96099a1Alex Vakulenko 18b381365edadcac463c07d045ad29b43ef96099a1Alex Vakulenkostd::unique_ptr<dbus::Response> CreateDBusErrorResponse( 19b381365edadcac463c07d045ad29b43ef96099a1Alex Vakulenko dbus::MethodCall* method_call, 20f437e3b367869af7cb5a53153284566164b48a7cAlex Vakulenko const std::string& error_name, 21f437e3b367869af7cb5a53153284566164b48a7cAlex Vakulenko const std::string& error_message) { 2205d29044d14a60775ed6c51c75a414eb0cb50347Alex Vakulenko auto resp = dbus::ErrorResponse::FromMethodCall( 2305d29044d14a60775ed6c51c75a414eb0cb50347Alex Vakulenko method_call, error_name, error_message); 24b381365edadcac463c07d045ad29b43ef96099a1Alex Vakulenko return std::unique_ptr<dbus::Response>(resp.release()); 25b381365edadcac463c07d045ad29b43ef96099a1Alex Vakulenko} 26b381365edadcac463c07d045ad29b43ef96099a1Alex Vakulenko 27b381365edadcac463c07d045ad29b43ef96099a1Alex Vakulenkostd::unique_ptr<dbus::Response> GetDBusError(dbus::MethodCall* method_call, 28b381365edadcac463c07d045ad29b43ef96099a1Alex Vakulenko const chromeos::Error* error) { 29f437e3b367869af7cb5a53153284566164b48a7cAlex Vakulenko CHECK(error) << "Error object must be specified"; 30f437e3b367869af7cb5a53153284566164b48a7cAlex Vakulenko std::string error_name = DBUS_ERROR_FAILED; // Default error code. 31b381365edadcac463c07d045ad29b43ef96099a1Alex Vakulenko std::string error_message; 32b381365edadcac463c07d045ad29b43ef96099a1Alex Vakulenko 33b381365edadcac463c07d045ad29b43ef96099a1Alex Vakulenko // Special case for "dbus" error domain. 34b381365edadcac463c07d045ad29b43ef96099a1Alex Vakulenko // Pop the error code and message from the error chain and use them as the 35b381365edadcac463c07d045ad29b43ef96099a1Alex Vakulenko // actual D-Bus error message. 36b381365edadcac463c07d045ad29b43ef96099a1Alex Vakulenko if (error->GetDomain() == errors::dbus::kDomain) { 37f437e3b367869af7cb5a53153284566164b48a7cAlex Vakulenko error_name = error->GetCode(); 38b381365edadcac463c07d045ad29b43ef96099a1Alex Vakulenko error_message = error->GetMessage(); 39b381365edadcac463c07d045ad29b43ef96099a1Alex Vakulenko error = error->GetInnerError(); 40b381365edadcac463c07d045ad29b43ef96099a1Alex Vakulenko } 41b381365edadcac463c07d045ad29b43ef96099a1Alex Vakulenko 42b381365edadcac463c07d045ad29b43ef96099a1Alex Vakulenko // Append any inner errors to the error message. 43b381365edadcac463c07d045ad29b43ef96099a1Alex Vakulenko while (error) { 44b381365edadcac463c07d045ad29b43ef96099a1Alex Vakulenko // Format error string as "domain/code:message". 45b381365edadcac463c07d045ad29b43ef96099a1Alex Vakulenko if (!error_message.empty()) 46b381365edadcac463c07d045ad29b43ef96099a1Alex Vakulenko error_message += ';'; 4705d29044d14a60775ed6c51c75a414eb0cb50347Alex Vakulenko error_message += 4805d29044d14a60775ed6c51c75a414eb0cb50347Alex Vakulenko error->GetDomain() + '/' + error->GetCode() + ':' + error->GetMessage(); 49b381365edadcac463c07d045ad29b43ef96099a1Alex Vakulenko error = error->GetInnerError(); 50b381365edadcac463c07d045ad29b43ef96099a1Alex Vakulenko } 51f437e3b367869af7cb5a53153284566164b48a7cAlex Vakulenko return CreateDBusErrorResponse(method_call, error_name, error_message); 52b381365edadcac463c07d045ad29b43ef96099a1Alex Vakulenko} 53b381365edadcac463c07d045ad29b43ef96099a1Alex Vakulenko 5400ceab8b84907509eaec878e1ae11ea36c18d441Alex Vakulenkovoid AddDBusError(chromeos::ErrorPtr* error, 55f437e3b367869af7cb5a53153284566164b48a7cAlex Vakulenko const std::string& dbus_error_name, 5600ceab8b84907509eaec878e1ae11ea36c18d441Alex Vakulenko const std::string& dbus_error_message) { 57852ff001e232f6fcc2bddd10d97c609d7461cda2Vitaly Buka std::vector<std::string> parts = string_utils::Split(dbus_error_message, ";"); 5800ceab8b84907509eaec878e1ae11ea36c18d441Alex Vakulenko std::vector<std::tuple<std::string, std::string, std::string>> errors; 5900ceab8b84907509eaec878e1ae11ea36c18d441Alex Vakulenko for (const std::string& part : parts) { 6000ceab8b84907509eaec878e1ae11ea36c18d441Alex Vakulenko // Each part should be in format of "domain/code:message" 6100ceab8b84907509eaec878e1ae11ea36c18d441Alex Vakulenko size_t slash_pos = part.find('/'); 6200ceab8b84907509eaec878e1ae11ea36c18d441Alex Vakulenko size_t colon_pos = part.find(':'); 6305d29044d14a60775ed6c51c75a414eb0cb50347Alex Vakulenko if (slash_pos != std::string::npos && colon_pos != std::string::npos && 6400ceab8b84907509eaec878e1ae11ea36c18d441Alex Vakulenko slash_pos < colon_pos) { 65f437e3b367869af7cb5a53153284566164b48a7cAlex Vakulenko // If we have both '/' and ':' and in proper order, then we have a 6600ceab8b84907509eaec878e1ae11ea36c18d441Alex Vakulenko // correctly encoded error object. 6700ceab8b84907509eaec878e1ae11ea36c18d441Alex Vakulenko std::string domain = part.substr(0, slash_pos); 6800ceab8b84907509eaec878e1ae11ea36c18d441Alex Vakulenko std::string code = part.substr(slash_pos + 1, colon_pos - slash_pos - 1); 6900ceab8b84907509eaec878e1ae11ea36c18d441Alex Vakulenko std::string message = part.substr(colon_pos + 1); 7000ceab8b84907509eaec878e1ae11ea36c18d441Alex Vakulenko errors.emplace_back(domain, code, message); 7100ceab8b84907509eaec878e1ae11ea36c18d441Alex Vakulenko } else if (slash_pos == std::string::npos && 7205d29044d14a60775ed6c51c75a414eb0cb50347Alex Vakulenko colon_pos == std::string::npos && errors.empty()) { 7300ceab8b84907509eaec878e1ae11ea36c18d441Alex Vakulenko // If we don't have both '/' and ':' and this is the first error object, 7400ceab8b84907509eaec878e1ae11ea36c18d441Alex Vakulenko // then we had a D-Bus error at the top of the error chain. 75f437e3b367869af7cb5a53153284566164b48a7cAlex Vakulenko errors.emplace_back(errors::dbus::kDomain, dbus_error_name, part); 7600ceab8b84907509eaec878e1ae11ea36c18d441Alex Vakulenko } else { 7700ceab8b84907509eaec878e1ae11ea36c18d441Alex Vakulenko // We have a malformed part. The whole D-Bus error was most likely 7800ceab8b84907509eaec878e1ae11ea36c18d441Alex Vakulenko // not generated by GetDBusError(). To be safe, stop parsing it 7900ceab8b84907509eaec878e1ae11ea36c18d441Alex Vakulenko // and return the error as received from D-Bus. 8000ceab8b84907509eaec878e1ae11ea36c18d441Alex Vakulenko errors.clear(); // Remove any errors accumulated so far. 8105d29044d14a60775ed6c51c75a414eb0cb50347Alex Vakulenko errors.emplace_back( 8205d29044d14a60775ed6c51c75a414eb0cb50347Alex Vakulenko errors::dbus::kDomain, dbus_error_name, dbus_error_message); 8300ceab8b84907509eaec878e1ae11ea36c18d441Alex Vakulenko break; 8400ceab8b84907509eaec878e1ae11ea36c18d441Alex Vakulenko } 8500ceab8b84907509eaec878e1ae11ea36c18d441Alex Vakulenko } 8600ceab8b84907509eaec878e1ae11ea36c18d441Alex Vakulenko 8700ceab8b84907509eaec878e1ae11ea36c18d441Alex Vakulenko // Go backwards and add the parsed errors to the error chain. 8800ceab8b84907509eaec878e1ae11ea36c18d441Alex Vakulenko for (auto it = errors.crbegin(); it != errors.crend(); ++it) { 8905d29044d14a60775ed6c51c75a414eb0cb50347Alex Vakulenko Error::AddTo( 9005d29044d14a60775ed6c51c75a414eb0cb50347Alex Vakulenko error, FROM_HERE, std::get<0>(*it), std::get<1>(*it), std::get<2>(*it)); 9100ceab8b84907509eaec878e1ae11ea36c18d441Alex Vakulenko } 9200ceab8b84907509eaec878e1ae11ea36c18d441Alex Vakulenko} 9300ceab8b84907509eaec878e1ae11ea36c18d441Alex Vakulenko 94b381365edadcac463c07d045ad29b43ef96099a1Alex Vakulenko} // namespace dbus_utils 95b381365edadcac463c07d045ad29b43ef96099a1Alex Vakulenko} // namespace chromeos 96