| // Copyright 2014 The Chromium Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "mojo/public/cpp/bindings/lib/validation_errors.h" |
| |
| #include "base/strings/stringprintf.h" |
| #include "mojo/public/cpp/bindings/message.h" |
| |
| namespace mojo { |
| namespace internal { |
| namespace { |
| |
| ValidationErrorObserverForTesting* g_validation_error_observer = nullptr; |
| SerializationWarningObserverForTesting* g_serialization_warning_observer = |
| nullptr; |
| bool g_suppress_logging = false; |
| |
| } // namespace |
| |
| const char* ValidationErrorToString(ValidationError error) { |
| switch (error) { |
| case VALIDATION_ERROR_NONE: |
| return "VALIDATION_ERROR_NONE"; |
| case VALIDATION_ERROR_MISALIGNED_OBJECT: |
| return "VALIDATION_ERROR_MISALIGNED_OBJECT"; |
| case VALIDATION_ERROR_ILLEGAL_MEMORY_RANGE: |
| return "VALIDATION_ERROR_ILLEGAL_MEMORY_RANGE"; |
| case VALIDATION_ERROR_UNEXPECTED_STRUCT_HEADER: |
| return "VALIDATION_ERROR_UNEXPECTED_STRUCT_HEADER"; |
| case VALIDATION_ERROR_UNEXPECTED_ARRAY_HEADER: |
| return "VALIDATION_ERROR_UNEXPECTED_ARRAY_HEADER"; |
| case VALIDATION_ERROR_ILLEGAL_HANDLE: |
| return "VALIDATION_ERROR_ILLEGAL_HANDLE"; |
| case VALIDATION_ERROR_UNEXPECTED_INVALID_HANDLE: |
| return "VALIDATION_ERROR_UNEXPECTED_INVALID_HANDLE"; |
| case VALIDATION_ERROR_ILLEGAL_POINTER: |
| return "VALIDATION_ERROR_ILLEGAL_POINTER"; |
| case VALIDATION_ERROR_UNEXPECTED_NULL_POINTER: |
| return "VALIDATION_ERROR_UNEXPECTED_NULL_POINTER"; |
| case VALIDATION_ERROR_ILLEGAL_INTERFACE_ID: |
| return "VALIDATION_ERROR_ILLEGAL_INTERFACE_ID"; |
| case VALIDATION_ERROR_UNEXPECTED_INVALID_INTERFACE_ID: |
| return "VALIDATION_ERROR_UNEXPECTED_INVALID_INTERFACE_ID"; |
| case VALIDATION_ERROR_MESSAGE_HEADER_INVALID_FLAGS: |
| return "VALIDATION_ERROR_MESSAGE_HEADER_INVALID_FLAGS"; |
| case VALIDATION_ERROR_MESSAGE_HEADER_MISSING_REQUEST_ID: |
| return "VALIDATION_ERROR_MESSAGE_HEADER_MISSING_REQUEST_ID"; |
| case VALIDATION_ERROR_MESSAGE_HEADER_UNKNOWN_METHOD: |
| return "VALIDATION_ERROR_MESSAGE_HEADER_UNKNOWN_METHOD"; |
| case VALIDATION_ERROR_DIFFERENT_SIZED_ARRAYS_IN_MAP: |
| return "VALIDATION_ERROR_DIFFERENT_SIZED_ARRAYS_IN_MAP"; |
| case VALIDATION_ERROR_UNKNOWN_UNION_TAG: |
| return "VALIDATION_ERROR_UNKNOWN_UNION_TAG"; |
| case VALIDATION_ERROR_UNKNOWN_ENUM_VALUE: |
| return "VALIDATION_ERROR_UNKNOWN_ENUM_VALUE"; |
| case VALIDATION_ERROR_DESERIALIZATION_FAILED: |
| return "VALIDATION_ERROR_DESERIALIZATION_FAILED"; |
| case VALIDATION_ERROR_MAX_RECURSION_DEPTH: |
| return "VALIDATION_ERROR_MAX_RECURSION_DEPTH"; |
| } |
| |
| return "Unknown error"; |
| } |
| |
| void ReportValidationError(ValidationContext* context, |
| ValidationError error, |
| const char* description) { |
| if (g_validation_error_observer) { |
| g_validation_error_observer->set_last_error(error); |
| return; |
| } |
| |
| if (description) { |
| if (!g_suppress_logging) { |
| LOG(ERROR) << "Invalid message: " << ValidationErrorToString(error) |
| << " (" << description << ")"; |
| } |
| if (context->message()) { |
| context->message()->NotifyBadMessage( |
| base::StringPrintf("Validation failed for %s [%s (%s)]", |
| context->description().data(), |
| ValidationErrorToString(error), description)); |
| } |
| } else { |
| if (!g_suppress_logging) |
| LOG(ERROR) << "Invalid message: " << ValidationErrorToString(error); |
| if (context->message()) { |
| context->message()->NotifyBadMessage( |
| base::StringPrintf("Validation failed for %s [%s]", |
| context->description().data(), |
| ValidationErrorToString(error))); |
| } |
| } |
| } |
| |
| void ReportValidationErrorForMessage( |
| mojo::Message* message, |
| ValidationError error, |
| const char* description) { |
| ValidationContext validation_context(nullptr, 0, 0, 0, message, description); |
| ReportValidationError(&validation_context, error); |
| } |
| |
| ScopedSuppressValidationErrorLoggingForTests |
| ::ScopedSuppressValidationErrorLoggingForTests() |
| : was_suppressed_(g_suppress_logging) { |
| g_suppress_logging = true; |
| } |
| |
| ScopedSuppressValidationErrorLoggingForTests |
| ::~ScopedSuppressValidationErrorLoggingForTests() { |
| g_suppress_logging = was_suppressed_; |
| } |
| |
| ValidationErrorObserverForTesting::ValidationErrorObserverForTesting( |
| const base::Closure& callback) |
| : last_error_(VALIDATION_ERROR_NONE), callback_(callback) { |
| DCHECK(!g_validation_error_observer); |
| g_validation_error_observer = this; |
| } |
| |
| ValidationErrorObserverForTesting::~ValidationErrorObserverForTesting() { |
| DCHECK(g_validation_error_observer == this); |
| g_validation_error_observer = nullptr; |
| } |
| |
| bool ReportSerializationWarning(ValidationError error) { |
| if (g_serialization_warning_observer) { |
| g_serialization_warning_observer->set_last_warning(error); |
| return true; |
| } |
| |
| return false; |
| } |
| |
| SerializationWarningObserverForTesting::SerializationWarningObserverForTesting() |
| : last_warning_(VALIDATION_ERROR_NONE) { |
| DCHECK(!g_serialization_warning_observer); |
| g_serialization_warning_observer = this; |
| } |
| |
| SerializationWarningObserverForTesting:: |
| ~SerializationWarningObserverForTesting() { |
| DCHECK(g_serialization_warning_observer == this); |
| g_serialization_warning_observer = nullptr; |
| } |
| |
| } // namespace internal |
| } // namespace mojo |