OLD | NEW |
(Empty) | |
| 1 // Copyright 2017 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. |
| 4 |
| 5 #include "extensions/renderer/api_last_error.h" |
| 6 |
| 7 #include "gin/converter.h" |
| 8 #include "gin/handle.h" |
| 9 #include "gin/object_template_builder.h" |
| 10 #include "gin/wrappable.h" |
| 11 |
| 12 namespace extensions { |
| 13 |
| 14 namespace { |
| 15 |
| 16 const char kLastErrorProperty[] = "lastError"; |
| 17 |
| 18 class LastErrorObject final : public gin::Wrappable<LastErrorObject> { |
| 19 public: |
| 20 explicit LastErrorObject(const std::string& error) : error_(error) {} |
| 21 |
| 22 static gin::WrapperInfo kWrapperInfo; |
| 23 |
| 24 // gin::Wrappable: |
| 25 gin::ObjectTemplateBuilder GetObjectTemplateBuilder( |
| 26 v8::Isolate* isolate) override { |
| 27 DCHECK(isolate); |
| 28 return Wrappable<LastErrorObject>::GetObjectTemplateBuilder(isolate) |
| 29 .SetProperty("message", &LastErrorObject::GetLastError); |
| 30 } |
| 31 |
| 32 void Reset(const std::string& error) { |
| 33 error_ = error; |
| 34 accessed_ = false; |
| 35 } |
| 36 |
| 37 const std::string& error() const { return error_; } |
| 38 bool accessed() const { return accessed_; } |
| 39 |
| 40 private: |
| 41 std::string GetLastError() { |
| 42 accessed_ = true; |
| 43 return error_; |
| 44 } |
| 45 |
| 46 std::string error_; |
| 47 bool accessed_ = false; |
| 48 |
| 49 DISALLOW_COPY_AND_ASSIGN(LastErrorObject); |
| 50 }; |
| 51 |
| 52 gin::WrapperInfo LastErrorObject::kWrapperInfo = {gin::kEmbedderNativeGin}; |
| 53 |
| 54 } // namespace |
| 55 |
| 56 APILastError::APILastError(const GetParent& get_parent) |
| 57 : get_parent_(get_parent) {} |
| 58 APILastError::APILastError(APILastError&& other) = default; |
| 59 APILastError::~APILastError() = default; |
| 60 |
| 61 void APILastError::SetError(v8::Local<v8::Context> context, |
| 62 const std::string& error) { |
| 63 v8::Isolate* isolate = context->GetIsolate(); |
| 64 DCHECK(isolate); |
| 65 v8::HandleScope handle_scope(isolate); |
| 66 v8::Local<v8::Object> parent = get_parent_.Run(context); |
| 67 if (parent.IsEmpty()) |
| 68 return; |
| 69 v8::Local<v8::String> key = gin::StringToSymbol(isolate, kLastErrorProperty); |
| 70 v8::MaybeLocal<v8::Value> maybe_error = parent->Get(context, key); |
| 71 v8::Local<v8::Value> local_error; |
| 72 if (!maybe_error.ToLocal(&local_error)) |
| 73 return; |
| 74 |
| 75 if (!local_error->IsUndefined()) { |
| 76 // There may be an existing last error to overwrite. |
| 77 LastErrorObject* last_error = nullptr; |
| 78 if (!gin::Converter<LastErrorObject*>::FromV8(context->GetIsolate(), |
| 79 local_error, &last_error)) { |
| 80 // If it's not a real lastError (e.g. if a script manually set it), don't |
| 81 // do anything. |
| 82 return; |
| 83 } |
| 84 last_error->Reset(error); |
| 85 } else { |
| 86 DCHECK(context->GetIsolate()); |
| 87 v8::Local<v8::Value> last_error = |
| 88 gin::CreateHandle(context->GetIsolate(), new LastErrorObject(error)) |
| 89 .ToV8(); |
| 90 DCHECK(!last_error.IsEmpty()); |
| 91 // This Set() can fail, but there's nothing else to do if it does. |
| 92 ignore_result(parent->Set( |
| 93 context, gin::StringToSymbol(isolate, kLastErrorProperty), last_error)); |
| 94 } |
| 95 } |
| 96 |
| 97 void APILastError::ClearError(v8::Local<v8::Context> context, |
| 98 bool report_if_unchecked) { |
| 99 v8::Isolate* isolate = context->GetIsolate(); |
| 100 v8::HandleScope handle_scope(isolate); |
| 101 v8::Local<v8::Object> parent = get_parent_.Run(context); |
| 102 if (parent.IsEmpty()) |
| 103 return; |
| 104 v8::Local<v8::String> key = gin::StringToSymbol(isolate, kLastErrorProperty); |
| 105 v8::MaybeLocal<v8::Value> maybe_error = parent->Get(context, key); |
| 106 v8::Local<v8::Value> local_error; |
| 107 if (!maybe_error.ToLocal(&local_error)) |
| 108 return; |
| 109 LastErrorObject* last_error = nullptr; |
| 110 if (!gin::Converter<LastErrorObject*>::FromV8(context->GetIsolate(), |
| 111 local_error, &last_error)) { |
| 112 return; |
| 113 } |
| 114 |
| 115 if (report_if_unchecked && !last_error->accessed()) { |
| 116 isolate->ThrowException( |
| 117 v8::Exception::Error(gin::StringToV8(isolate, last_error->error()))); |
| 118 } |
| 119 |
| 120 parent->Delete(context, key); |
| 121 } |
| 122 |
| 123 } // namespace extensions |
OLD | NEW |