Commit 581b273e authored by Leon Han's avatar Leon Han Committed by Commit Bot

[webnfc] Refactor/Refine impl for "Creating Web NFC message" algorithm

This CL implements strictly the "Creating Web NFC message" algorithm
described at http://w3c.github.io/web-nfc/#creating-web-nfc-message.

1.
Changes the Web IDL definition for NDEFRecordData from
"typedef (DOMString or unrestricted double or ArrayBuffer or Dictionary) NDEFRecordData;"
to
"typedef any NDEFRecordData;"

2.
Adds verification of NDEFRecordInit when creating NDEFRecord, i.e. makes
NDEFRecord ctor throw exceptions in case of invalid NDEFRecordInit.
Also, the same thing for NDEFMessage and NFCReadingEvent.

3.
Changes code flow for Step 10.9 of "9.10.1 The push() method" described
at https://w3c.github.io/web-nfc/#the-push-method.
"
Let output be the notation for the NDEF message to be created by UA, as
the result of passing message to create Web NFC message. If this throws
an exception, reject p with that exception and abort these steps.
"
Previously,
  NDEFMessageSource (NDEFMessageInit) -Validity check->
  -Mojo TypeConverter-> Mojom NDEFMessagePtr
Now,
  Remove "Validity check" and "Mojo TypeConverter" mentioned above,
  instead, we reuse the process of creating NDEFMessage from
  NDEFMessageSource (NDEFMessageInit), then the next step converting
  NDEFMessage to Mojom NDEFMessagePtr is quite an easy job.

BUG=520391

Change-Id: I628981e556f89ffdd0f883da0cfa99b20a6f8300
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1767719
Commit-Queue: Leon Han <leon.han@intel.com>
Reviewed-by: default avatarDaniel Cheng <dcheng@chromium.org>
Reviewed-by: default avatarReilly Grant <reillyg@chromium.org>
Reviewed-by: default avatarRijubrata Bhaumik <rijubrata.bhaumik@intel.com>
Cr-Commit-Position: refs/heads/master@{#693539}
parent 972da046
...@@ -8,7 +8,6 @@ import android.net.Uri; ...@@ -8,7 +8,6 @@ import android.net.Uri;
import android.os.Build; import android.os.Build;
import org.chromium.base.ApiCompatibilityUtils; import org.chromium.base.ApiCompatibilityUtils;
import org.chromium.base.Log;
import org.chromium.device.mojom.NdefMessage; import org.chromium.device.mojom.NdefMessage;
import org.chromium.device.mojom.NdefRecord; import org.chromium.device.mojom.NdefRecord;
import org.chromium.device.mojom.NdefRecordType; import org.chromium.device.mojom.NdefRecordType;
...@@ -29,8 +28,6 @@ public final class NdefMessageUtils { ...@@ -29,8 +28,6 @@ public final class NdefMessageUtils {
private static final String TEXT_MIME = "text/plain"; private static final String TEXT_MIME = "text/plain";
private static final String JSON_MIME = "application/json"; private static final String JSON_MIME = "application/json";
private static final String OCTET_STREAM_MIME = "application/octet-stream"; private static final String OCTET_STREAM_MIME = "application/octet-stream";
private static final String CHARSET_UTF8 = ";charset=UTF-8";
private static final String CHARSET_UTF16 = ";charset=UTF-16";
/** /**
* Converts mojo NdefMessage to android.nfc.NdefMessage * Converts mojo NdefMessage to android.nfc.NdefMessage
...@@ -85,37 +82,21 @@ public final class NdefMessageUtils { ...@@ -85,37 +82,21 @@ public final class NdefMessageUtils {
return webNdefMessage; return webNdefMessage;
} }
/**
* Returns charset of mojo NdefRecord. Only applicable for URL and TEXT records.
* If charset cannot be determined, UTF-8 charset is used by default.
*/
private static String getCharset(NdefRecord record) {
if (record.mediaType.endsWith(CHARSET_UTF8)) return "UTF-8";
// When 16bit WTF::String data is converted to bytearray, it is in LE byte order, without
// BOM. By default, Android interprets UTF-16 charset without BOM as UTF-16BE, thus, use
// UTF-16LE as encoding for text data.
if (record.mediaType.endsWith(CHARSET_UTF16)) return "UTF-16LE";
Log.w(TAG, "Unknown charset, defaulting to UTF-8.");
return "UTF-8";
}
/** /**
* Converts mojo NdefRecord to android.nfc.NdefRecord * Converts mojo NdefRecord to android.nfc.NdefRecord
* |record.data| should always be treated as "UTF-8" encoding bytes, this is guaranteed by the
* sender (Blink).
*/ */
private static android.nfc.NdefRecord toNdefRecord(NdefRecord record) private static android.nfc.NdefRecord toNdefRecord(NdefRecord record)
throws InvalidNdefMessageException, IllegalArgumentException, throws InvalidNdefMessageException, IllegalArgumentException,
UnsupportedEncodingException { UnsupportedEncodingException {
switch (record.recordType) { switch (record.recordType) {
case NdefRecordType.URL: case NdefRecordType.URL:
return android.nfc.NdefRecord.createUri( return android.nfc.NdefRecord.createUri(new String(record.data, "UTF-8"));
new String(record.data, getCharset(record)));
case NdefRecordType.TEXT: case NdefRecordType.TEXT:
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
return android.nfc.NdefRecord.createTextRecord( return android.nfc.NdefRecord.createTextRecord(
"en-US", new String(record.data, getCharset(record))); "en-US", new String(record.data, "UTF-8"));
} else { } else {
return android.nfc.NdefRecord.createMime(TEXT_MIME, record.data); return android.nfc.NdefRecord.createMime(TEXT_MIME, record.data);
} }
......
...@@ -5,23 +5,57 @@ ...@@ -5,23 +5,57 @@
#include "third_party/blink/renderer/modules/nfc/ndef_message.h" #include "third_party/blink/renderer/modules/nfc/ndef_message.h"
#include "services/device/public/mojom/nfc.mojom-blink.h" #include "services/device/public/mojom/nfc.mojom-blink.h"
#include "third_party/blink/renderer/bindings/modules/v8/string_or_array_buffer_or_ndef_message_init.h"
#include "third_party/blink/renderer/modules/nfc/ndef_message_init.h" #include "third_party/blink/renderer/modules/nfc/ndef_message_init.h"
#include "third_party/blink/renderer/modules/nfc/ndef_record.h" #include "third_party/blink/renderer/modules/nfc/ndef_record.h"
#include "third_party/blink/renderer/platform/bindings/exception_state.h"
namespace blink { namespace blink {
// static // static
NDEFMessage* NDEFMessage::Create(const NDEFMessageInit* init) { NDEFMessage* NDEFMessage::Create(const NDEFMessageInit* init,
return MakeGarbageCollected<NDEFMessage>(init); ExceptionState& exception_state) {
NDEFMessage* message = MakeGarbageCollected<NDEFMessage>();
message->url_ = init->url();
if (init->hasRecords()) {
for (const NDEFRecordInit* record_init : init->records()) {
NDEFRecord* record = NDEFRecord::Create(record_init, exception_state);
if (exception_state.HadException())
return nullptr;
DCHECK(record);
message->records_.push_back(record);
}
}
return message;
} }
NDEFMessage::NDEFMessage(const NDEFMessageInit* init) : url_(init->url()) { // static
if (init->hasRecords()) { NDEFMessage* NDEFMessage::Create(const NDEFMessageSource& source,
for (const NDEFRecordInit* record_init : init->records()) ExceptionState& exception_state) {
records_.push_back(NDEFRecord::Create(record_init)); if (source.IsString()) {
NDEFMessage* message = MakeGarbageCollected<NDEFMessage>();
message->records_.push_back(
MakeGarbageCollected<NDEFRecord>(source.GetAsString()));
return message;
}
if (source.IsArrayBuffer()) {
NDEFMessage* message = MakeGarbageCollected<NDEFMessage>();
message->records_.push_back(
MakeGarbageCollected<NDEFRecord>(source.GetAsArrayBuffer()));
return message;
}
if (source.IsNDEFMessageInit()) {
return Create(source.GetAsNDEFMessageInit(), exception_state);
} }
NOTREACHED();
return nullptr;
} }
NDEFMessage::NDEFMessage() = default;
NDEFMessage::NDEFMessage(const device::mojom::blink::NDEFMessage& message) NDEFMessage::NDEFMessage(const device::mojom::blink::NDEFMessage& message)
: url_(message.url) { : url_(message.url) {
for (wtf_size_t i = 0; i < message.data.size(); ++i) { for (wtf_size_t i = 0; i < message.data.size(); ++i) {
......
...@@ -13,17 +13,22 @@ ...@@ -13,17 +13,22 @@
namespace blink { namespace blink {
class ExceptionState;
class NDEFMessageInit; class NDEFMessageInit;
class NDEFRecord; class NDEFRecord;
class StringOrArrayBufferOrNDEFMessageInit;
using NDEFMessageSource = StringOrArrayBufferOrNDEFMessageInit;
class MODULES_EXPORT NDEFMessage final : public ScriptWrappable { class MODULES_EXPORT NDEFMessage final : public ScriptWrappable {
DEFINE_WRAPPERTYPEINFO(); DEFINE_WRAPPERTYPEINFO();
public: public:
static NDEFMessage* Create(const NDEFMessageInit*); static NDEFMessage* Create(const NDEFMessageInit*, ExceptionState&);
static NDEFMessage* Create(const NDEFMessageSource&, ExceptionState&);
NDEFMessage(const NDEFMessageInit*); NDEFMessage();
NDEFMessage(const device::mojom::blink::NDEFMessage&); explicit NDEFMessage(const device::mojom::blink::NDEFMessage&);
const String& url() const; const String& url() const;
const HeapVector<Member<NDEFRecord>>& records() const; const HeapVector<Member<NDEFRecord>>& records() const;
......
...@@ -8,6 +8,7 @@ ...@@ -8,6 +8,7 @@
RuntimeEnabled=WebNFC, RuntimeEnabled=WebNFC,
SecureContext, SecureContext,
Constructor(NDEFMessageInit messageInit), Constructor(NDEFMessageInit messageInit),
RaisesException=Constructor,
Exposed=Window Exposed=Window
] interface NDEFMessage { ] interface NDEFMessage {
readonly attribute USVString url; readonly attribute USVString url;
......
...@@ -24,22 +24,32 @@ class MODULES_EXPORT NDEFRecord final : public ScriptWrappable { ...@@ -24,22 +24,32 @@ class MODULES_EXPORT NDEFRecord final : public ScriptWrappable {
DEFINE_WRAPPERTYPEINFO(); DEFINE_WRAPPERTYPEINFO();
public: public:
static NDEFRecord* Create(const NDEFRecordInit*); static NDEFRecord* Create(const NDEFRecordInit*, ExceptionState&);
NDEFRecord(const NDEFRecordInit*); // Construct a "text" record from a string.
NDEFRecord(const device::mojom::blink::NDEFRecordPtr&); explicit NDEFRecord(const String&);
// Construct a "opaque" record from an array buffer.
explicit NDEFRecord(DOMArrayBuffer*);
NDEFRecord(const String&, const String&, WTF::Vector<uint8_t>);
explicit NDEFRecord(const device::mojom::blink::NDEFRecordPtr&);
const String& recordType() const; const String& recordType() const;
const String& mediaType() const; const String& mediaType() const;
String toText() const; String toText() const;
DOMArrayBuffer* toArrayBuffer() const; DOMArrayBuffer* toArrayBuffer() const;
ScriptValue toJSON(ScriptState*, ExceptionState& exception_state) const; ScriptValue toJSON(ScriptState*, ExceptionState&) const;
const WTF::Vector<uint8_t>& data() const;
void Trace(blink::Visitor*) override; void Trace(blink::Visitor*) override;
private: private:
String record_type_; String record_type_;
String media_type_; String media_type_;
// Holds the NDEFRecord.[[PayloadData]] bytes defined at
// https://w3c.github.io/web-nfc/#the-ndefrecord-interface.
WTF::Vector<uint8_t> data_; WTF::Vector<uint8_t> data_;
}; };
......
...@@ -8,6 +8,7 @@ ...@@ -8,6 +8,7 @@
RuntimeEnabled=WebNFC, RuntimeEnabled=WebNFC,
SecureContext, SecureContext,
Constructor(NDEFRecordInit recordInit), Constructor(NDEFRecordInit recordInit),
RaisesException=Constructor,
Exposed=Window Exposed=Window
] interface NDEFRecord { ] interface NDEFRecord {
readonly attribute NDEFRecordType recordType; readonly attribute NDEFRecordType recordType;
......
...@@ -6,7 +6,7 @@ ...@@ -6,7 +6,7 @@
enum NDEFRecordType { "empty", "text", "url", "json", "opaque" }; enum NDEFRecordType { "empty", "text", "url", "json", "opaque" };
typedef (DOMString or unrestricted double or ArrayBuffer or Dictionary) NDEFRecordData; typedef any NDEFRecordData;
dictionary NDEFRecordInit { dictionary NDEFRecordInit {
NDEFRecordType recordType; NDEFRecordType recordType;
......
...@@ -9,6 +9,7 @@ namespace blink { ...@@ -9,6 +9,7 @@ namespace blink {
const char kNfcJsonMimePostfix[] = "+json"; const char kNfcJsonMimePostfix[] = "+json";
const char kNfcJsonMimePrefix[] = "application/"; const char kNfcJsonMimePrefix[] = "application/";
const char kNfcJsonMimeType[] = "application/json"; const char kNfcJsonMimeType[] = "application/json";
const char kNfcJsonTextMimeType[] = "text/json";
const char kNfcOpaqueMimeType[] = "application/octet-stream"; const char kNfcOpaqueMimeType[] = "application/octet-stream";
const char kNfcPlainTextMimeType[] = "text/plain"; const char kNfcPlainTextMimeType[] = "text/plain";
const char kNfcPlainTextMimePrefix[] = "text/"; const char kNfcPlainTextMimePrefix[] = "text/";
...@@ -21,15 +22,17 @@ const char kNfcNotSupported[] = ...@@ -21,15 +22,17 @@ const char kNfcNotSupported[] =
"No NFC adapter or cannot establish connection."; "No NFC adapter or cannot establish connection.";
const char kNfcNotReadable[] = "NFC is not enabled."; const char kNfcNotReadable[] = "NFC is not enabled.";
const char kNfcTextRecordTypeError[] = const char kNfcTextRecordTypeError[] =
"The data for 'text' NDEFRecords must be of String or UnrestrctedDouble."; "The data for 'text' NDEFRecords must be of String.";
const char kNfcSetIdError[] = "Cannot set WebNFC Id."; const char kNfcSetIdError[] = "Cannot set WebNFC Id.";
const char kNfcTextRecordMediaTypeError[] = const char kNfcTextRecordMediaTypeError[] =
"Invalid media type for 'text' record."; "Invalid media type for 'text' record.";
const char kNfcUrlRecordTypeError[] = const char kNfcUrlRecordTypeError[] =
"The data for 'url' NDEFRecord must be of String type."; "The data for 'url' NDEFRecord must be of String type.";
const char kNfcUrlRecordParseError[] = "Cannot parse data for 'url' record."; const char kNfcUrlRecordParseError[] = "Cannot parse data for 'url' record.";
const char kNfcJsonRecordTypeError[] = const char kNfcJsonRecordNoDataError[] =
"The data for 'json' NDEFRecord must be of Object type."; "The data for 'json' NDEFRecord is missing.";
const char kNfcJsonRecordStringifyError[] =
"Cannot stringify data for 'json' record.";
const char kNfcJsonRecordMediaTypeError[] = const char kNfcJsonRecordMediaTypeError[] =
"Invalid media type for 'json' record."; "Invalid media type for 'json' record.";
const char kNfcOpaqueRecordTypeError[] = const char kNfcOpaqueRecordTypeError[] =
......
...@@ -5,18 +5,13 @@ ...@@ -5,18 +5,13 @@
#ifndef THIRD_PARTY_BLINK_RENDERER_MODULES_NFC_NFC_CONSTANTS_H_ #ifndef THIRD_PARTY_BLINK_RENDERER_MODULES_NFC_NFC_CONSTANTS_H_
#define THIRD_PARTY_BLINK_RENDERER_MODULES_NFC_NFC_CONSTANTS_H_ #define THIRD_PARTY_BLINK_RENDERER_MODULES_NFC_NFC_CONSTANTS_H_
#include "third_party/blink/renderer/bindings/modules/v8/string_or_array_buffer_or_ndef_message_init.h"
#include "third_party/blink/renderer/bindings/modules/v8/string_or_unrestricted_double_or_array_buffer_or_dictionary.h"
namespace blink { namespace blink {
using NDEFMessageSource = blink::StringOrArrayBufferOrNDEFMessageInit;
using NDEFRecordData =
blink::StringOrUnrestrictedDoubleOrArrayBufferOrDictionary;
extern const char kNfcJsonMimePostfix[]; extern const char kNfcJsonMimePostfix[];
extern const char kNfcJsonMimePrefix[]; extern const char kNfcJsonMimePrefix[];
extern const char kNfcJsonMimeType[]; extern const char kNfcJsonMimeType[];
extern const char kNfcJsonTextMimeType[];
extern const char kNfcOpaqueMimeType[]; extern const char kNfcOpaqueMimeType[];
extern const char kNfcPlainTextMimeType[]; extern const char kNfcPlainTextMimeType[];
extern const char kNfcPlainTextMimePrefix[]; extern const char kNfcPlainTextMimePrefix[];
...@@ -32,7 +27,8 @@ extern const char kNfcSetIdError[]; ...@@ -32,7 +27,8 @@ extern const char kNfcSetIdError[];
extern const char kNfcTextRecordMediaTypeError[]; extern const char kNfcTextRecordMediaTypeError[];
extern const char kNfcUrlRecordTypeError[]; extern const char kNfcUrlRecordTypeError[];
extern const char kNfcUrlRecordParseError[]; extern const char kNfcUrlRecordParseError[];
extern const char kNfcJsonRecordTypeError[]; extern const char kNfcJsonRecordNoDataError[];
extern const char kNfcJsonRecordStringifyError[];
extern const char kNfcJsonRecordMediaTypeError[]; extern const char kNfcJsonRecordMediaTypeError[];
extern const char kNfcOpaqueRecordTypeError[]; extern const char kNfcOpaqueRecordTypeError[];
extern const char kNfcRecordTypeError[]; extern const char kNfcRecordTypeError[];
......
...@@ -6,14 +6,27 @@ ...@@ -6,14 +6,27 @@
#include "third_party/blink/renderer/modules/nfc/ndef_message.h" #include "third_party/blink/renderer/modules/nfc/ndef_message.h"
#include "third_party/blink/renderer/modules/nfc/nfc_reading_event_init.h" #include "third_party/blink/renderer/modules/nfc/nfc_reading_event_init.h"
#include "third_party/blink/renderer/platform/bindings/exception_state.h"
namespace blink { namespace blink {
// static
NFCReadingEvent* NFCReadingEvent::Create(const AtomicString& event_type,
const NFCReadingEventInit* init,
ExceptionState& exception_state) {
NDEFMessage* message = NDEFMessage::Create(init->message(), exception_state);
if (exception_state.HadException())
return nullptr;
DCHECK(message);
return MakeGarbageCollected<NFCReadingEvent>(event_type, init, message);
}
NFCReadingEvent::NFCReadingEvent(const AtomicString& event_type, NFCReadingEvent::NFCReadingEvent(const AtomicString& event_type,
const NFCReadingEventInit* initializer) const NFCReadingEventInit* init,
: Event(event_type, initializer), NDEFMessage* message)
serial_number_(initializer->serialNumber()), : Event(event_type, init),
message_(NDEFMessage::Create(initializer->message())) {} serial_number_(init->serialNumber()),
message_(message) {}
NFCReadingEvent::NFCReadingEvent(const AtomicString& event_type, NFCReadingEvent::NFCReadingEvent(const AtomicString& event_type,
const String& serial_number, const String& serial_number,
......
...@@ -11,6 +11,7 @@ ...@@ -11,6 +11,7 @@
namespace blink { namespace blink {
class ExceptionState;
class NDEFMessage; class NDEFMessage;
class NFCReadingEventInit; class NFCReadingEventInit;
...@@ -18,12 +19,13 @@ class NFCReadingEvent final : public Event { ...@@ -18,12 +19,13 @@ class NFCReadingEvent final : public Event {
DEFINE_WRAPPERTYPEINFO(); DEFINE_WRAPPERTYPEINFO();
public: public:
static NFCReadingEvent* Create(const AtomicString& event_type, static NFCReadingEvent* Create(const AtomicString&,
const NFCReadingEventInit* initializer) { const NFCReadingEventInit*,
return MakeGarbageCollected<NFCReadingEvent>(event_type, initializer); ExceptionState&);
}
NFCReadingEvent(const AtomicString&, const NFCReadingEventInit*); NFCReadingEvent(const AtomicString&,
const NFCReadingEventInit*,
NDEFMessage*);
NFCReadingEvent(const AtomicString&, const String&, NDEFMessage*); NFCReadingEvent(const AtomicString&, const String&, NDEFMessage*);
~NFCReadingEvent() override; ~NFCReadingEvent() override;
......
...@@ -9,6 +9,7 @@ ...@@ -9,6 +9,7 @@
RuntimeEnabled=WebNFC, RuntimeEnabled=WebNFC,
SecureContext, SecureContext,
Constructor(DOMString type, NFCReadingEventInit eventInitDict), Constructor(DOMString type, NFCReadingEventInit eventInitDict),
RaisesException=Constructor,
Exposed=Window Exposed=Window
] interface NFCReadingEvent : Event { ] interface NFCReadingEvent : Event {
readonly attribute DOMString serialNumber; readonly attribute DOMString serialNumber;
......
...@@ -8,213 +8,45 @@ ...@@ -8,213 +8,45 @@
#include <utility> #include <utility>
#include "services/device/public/mojom/nfc.mojom-blink.h" #include "services/device/public/mojom/nfc.mojom-blink.h"
#include "third_party/blink/renderer/core/typed_arrays/dom_array_buffer.h"
#include "third_party/blink/renderer/modules/nfc/ndef_message.h" #include "third_party/blink/renderer/modules/nfc/ndef_message.h"
#include "third_party/blink/renderer/modules/nfc/ndef_record.h" #include "third_party/blink/renderer/modules/nfc/ndef_record.h"
#include "third_party/blink/renderer/modules/nfc/nfc_push_options.h" #include "third_party/blink/renderer/modules/nfc/nfc_push_options.h"
#include "third_party/blink/renderer/modules/nfc/nfc_scan_options.h" #include "third_party/blink/renderer/modules/nfc/nfc_scan_options.h"
#include "third_party/blink/renderer/modules/nfc/nfc_utils.h" #include "third_party/blink/renderer/modules/nfc/nfc_utils.h"
#include "third_party/blink/renderer/platform/wtf/text/string_utf8_adaptor.h"
#include "third_party/blink/renderer/platform/wtf/text/wtf_string.h" #include "third_party/blink/renderer/platform/wtf/text/wtf_string.h"
using device::mojom::blink::NDEFCompatibility;
using device::mojom::blink::NDEFMessage; using device::mojom::blink::NDEFMessage;
using device::mojom::blink::NDEFMessagePtr; using device::mojom::blink::NDEFMessagePtr;
using device::mojom::blink::NDEFRecord; using device::mojom::blink::NDEFRecord;
using device::mojom::blink::NDEFRecordPtr; using device::mojom::blink::NDEFRecordPtr;
using device::mojom::blink::NDEFRecordType;
using device::mojom::blink::NDEFRecordTypeFilter; using device::mojom::blink::NDEFRecordTypeFilter;
using device::mojom::blink::NFCPushOptions; using device::mojom::blink::NFCPushOptions;
using device::mojom::blink::NFCPushOptionsPtr; using device::mojom::blink::NFCPushOptionsPtr;
using device::mojom::blink::NFCPushTarget;
using device::mojom::blink::NFCScanOptions; using device::mojom::blink::NFCScanOptions;
using device::mojom::blink::NFCScanOptionsPtr; using device::mojom::blink::NFCScanOptionsPtr;
using WTF::String;
namespace {
void SetMediaType(NDEFRecordPtr& recordPtr,
const String& recordMediaType,
const String& defaultMediaType) {
recordPtr->media_type =
recordMediaType.IsEmpty() ? defaultMediaType : recordMediaType;
}
} // anonymous namespace
// Mojo type converters // Mojo type converters
namespace mojo { namespace mojo {
Vector<uint8_t> TypeConverter<Vector<uint8_t>, String>::Convert( NDEFRecordPtr TypeConverter<NDEFRecordPtr, ::blink::NDEFRecord*>::Convert(
const String& string) { const ::blink::NDEFRecord* record) {
StringUTF8Adaptor utf8_string(string); return NDEFRecord::New(blink::StringToNDEFRecordType(record->recordType()),
Vector<uint8_t> array; record->mediaType(), record->data());
array.Append(utf8_string.data(), utf8_string.size());
return array;
}
Vector<uint8_t> TypeConverter<Vector<uint8_t>, blink::DOMArrayBuffer*>::Convert(
blink::DOMArrayBuffer* buffer) {
Vector<uint8_t> array;
array.Append(static_cast<uint8_t*>(buffer->Data()), buffer->ByteLength());
return array;
}
NDEFRecordPtr TypeConverter<NDEFRecordPtr, String>::Convert(
const String& string) {
NDEFRecordPtr record = NDEFRecord::New();
record->record_type = NDEFRecordType::TEXT;
record->media_type =
StringView(blink::kNfcPlainTextMimeType) + blink::kNfcCharSetUTF8;
record->data = mojo::ConvertTo<Vector<uint8_t>>(string);
return record;
}
NDEFRecordPtr TypeConverter<NDEFRecordPtr, blink::DOMArrayBuffer*>::Convert(
blink::DOMArrayBuffer* buffer) {
NDEFRecordPtr record = NDEFRecord::New();
record->record_type = NDEFRecordType::OPAQUE_RECORD;
record->media_type = blink::kNfcOpaqueMimeType;
record->data = mojo::ConvertTo<Vector<uint8_t>>(buffer);
return record;
}
NDEFMessagePtr TypeConverter<NDEFMessagePtr, String>::Convert(
const String& string) {
NDEFMessagePtr message = NDEFMessage::New();
message->data.push_back(NDEFRecord::From(string));
return message;
}
base::Optional<Vector<uint8_t>>
TypeConverter<base::Optional<Vector<uint8_t>>, blink::NDEFRecordData>::Convert(
const blink::NDEFRecordData& value) {
if (value.IsUnrestrictedDouble()) {
return mojo::ConvertTo<Vector<uint8_t>>(
String::Number(value.GetAsUnrestrictedDouble()));
}
if (value.IsString()) {
return mojo::ConvertTo<Vector<uint8_t>>(value.GetAsString());
}
// TODO(https://crbug.com/520391): Remove this duplicate code for stringifying
// json, by reusing the same code in NDEFRecord ctor. i.e. Make users of this
// type converter:
// 1. first construct a NDEFRecord from the given NDEFRecordInit, the
// NDEFRecord ctor would stringify json.
// 2. then convert the NDEFRecord into an mojom::NDEFRecordPtr, which should
// be just simple.
if (value.IsDictionary()) {
v8::Local<v8::String> jsonString;
blink::Dictionary dictionary = value.GetAsDictionary();
v8::Isolate* isolate = dictionary.GetIsolate();
v8::TryCatch try_catch(isolate);
// https://w3c.github.io/web-nfc/#mapping-json-to-ndef
// If serialization throws, reject promise with a "SyntaxError" exception.
if (!v8::JSON::Stringify(dictionary.V8Context(), dictionary.V8Value())
.ToLocal(&jsonString) ||
try_catch.HasCaught()) {
return base::nullopt;
}
String string =
blink::ToBlinkString<String>(jsonString, blink::kDoNotExternalize);
return mojo::ConvertTo<Vector<uint8_t>>(string);
}
if (value.IsArrayBuffer()) {
return mojo::ConvertTo<Vector<uint8_t>>(value.GetAsArrayBuffer());
}
return base::nullopt;
} }
NDEFRecordPtr TypeConverter<NDEFRecordPtr, blink::NDEFRecordInit*>::Convert( NDEFMessagePtr TypeConverter<NDEFMessagePtr, ::blink::NDEFMessage*>::Convert(
const blink::NDEFRecordInit* record) { const ::blink::NDEFMessage* message) {
NDEFRecordPtr recordPtr = NDEFRecord::New();
if (record->hasRecordType()) {
recordPtr->record_type =
blink::StringToNDEFRecordType(record->recordType());
} else {
recordPtr->record_type = blink::DeduceRecordTypeFromDataType(record);
}
// If record type is "empty", no need to set media type or data.
// https://w3c.github.io/web-nfc/#creating-web-nfc-message
if (recordPtr->record_type == NDEFRecordType::EMPTY)
return recordPtr;
switch (recordPtr->record_type) {
case NDEFRecordType::TEXT:
case NDEFRecordType::URL:
SetMediaType(recordPtr, record->mediaType(),
blink::kNfcPlainTextMimeType);
recordPtr->media_type = recordPtr->media_type + blink::kNfcCharSetUTF8;
break;
case NDEFRecordType::JSON:
SetMediaType(recordPtr, record->mediaType(), blink::kNfcJsonMimeType);
break;
case NDEFRecordType::OPAQUE_RECORD:
SetMediaType(recordPtr, record->mediaType(), blink::kNfcOpaqueMimeType);
break;
default:
NOTREACHED();
break;
}
auto recordData =
mojo::ConvertTo<base::Optional<Vector<uint8_t>>>(record->data());
// If JS object cannot be converted to uint8_t array, return null,
// interrupt NDEFMessage conversion algorithm and reject promise with
// SyntaxError exception.
if (!recordData)
return nullptr;
recordPtr->data = recordData.value();
return recordPtr;
}
NDEFMessagePtr TypeConverter<NDEFMessagePtr, blink::NDEFMessageInit*>::Convert(
const blink::NDEFMessageInit* message) {
NDEFMessagePtr messagePtr = NDEFMessage::New(); NDEFMessagePtr messagePtr = NDEFMessage::New();
messagePtr->url = message->url(); messagePtr->url = message->url();
messagePtr->data.resize(message->records().size()); messagePtr->data.resize(message->records().size());
for (wtf_size_t i = 0; i < message->records().size(); ++i) { for (wtf_size_t i = 0; i < message->records().size(); ++i) {
NDEFRecordPtr record = NDEFRecord::From(message->records()[i].Get()); NDEFRecordPtr record = NDEFRecord::From(message->records()[i].Get());
if (record.is_null()) DCHECK(record);
return nullptr;
messagePtr->data[i] = std::move(record); messagePtr->data[i] = std::move(record);
} }
return messagePtr; return messagePtr;
} }
NDEFMessagePtr TypeConverter<NDEFMessagePtr, blink::DOMArrayBuffer*>::Convert(
blink::DOMArrayBuffer* buffer) {
NDEFMessagePtr message = NDEFMessage::New();
message->data.push_back(NDEFRecord::From(buffer));
return message;
}
NDEFMessagePtr TypeConverter<NDEFMessagePtr, blink::NDEFMessageSource>::Convert(
const blink::NDEFMessageSource& message) {
if (message.IsString())
return NDEFMessage::From(message.GetAsString());
if (message.IsNDEFMessageInit())
return NDEFMessage::From(message.GetAsNDEFMessageInit());
if (message.IsArrayBuffer())
return NDEFMessage::From(message.GetAsArrayBuffer());
NOTREACHED();
return nullptr;
}
NFCPushOptionsPtr NFCPushOptionsPtr
TypeConverter<NFCPushOptionsPtr, const blink::NFCPushOptions*>::Convert( TypeConverter<NFCPushOptionsPtr, const blink::NFCPushOptions*>::Convert(
const blink::NFCPushOptions* pushOptions) { const blink::NFCPushOptions* pushOptions) {
......
...@@ -7,103 +7,46 @@ ...@@ -7,103 +7,46 @@
#include "mojo/public/cpp/bindings/type_converter.h" #include "mojo/public/cpp/bindings/type_converter.h"
#include "services/device/public/mojom/nfc.mojom-blink-forward.h" #include "services/device/public/mojom/nfc.mojom-blink-forward.h"
#include "third_party/blink/renderer/modules/nfc/nfc_constants.h"
#include "third_party/blink/renderer/platform/wtf/forward.h" #include "third_party/blink/renderer/platform/wtf/forward.h"
namespace blink { namespace blink {
class DOMArrayBuffer;
class NDEFRecordInit; class NDEFRecord;
class NDEFMessageInit; class NDEFMessage;
class NFCScanOptions; class NFCScanOptions;
class NFCPushOptions; class NFCPushOptions;
} // namespace blink } // namespace blink
// Mojo type converters // Mojo type converters
namespace mojo { namespace mojo {
template <>
struct TypeConverter<Vector<uint8_t>, WTF::String> {
static Vector<uint8_t> Convert(const WTF::String& string);
};
template <>
struct TypeConverter<Vector<uint8_t>, blink::DOMArrayBuffer*> {
static Vector<uint8_t> Convert(blink::DOMArrayBuffer* buffer);
};
template <>
struct TypeConverter<device::mojom::blink::NDEFRecordPtr, WTF::String> {
static device::mojom::blink::NDEFRecordPtr Convert(const WTF::String& string);
};
template <> template <>
struct TypeConverter<device::mojom::blink::NDEFRecordPtr, struct TypeConverter<device::mojom::blink::NDEFRecordPtr,
blink::DOMArrayBuffer*> { ::blink::NDEFRecord*> {
static device::mojom::blink::NDEFRecordPtr Convert( static device::mojom::blink::NDEFRecordPtr Convert(
blink::DOMArrayBuffer* buffer); const ::blink::NDEFRecord* record);
};
template <>
struct TypeConverter<device::mojom::blink::NDEFMessagePtr, WTF::String> {
static device::mojom::blink::NDEFMessagePtr Convert(
const WTF::String& string);
};
template <>
struct TypeConverter<base::Optional<Vector<uint8_t>>, blink::NDEFRecordData> {
static base::Optional<Vector<uint8_t>> Convert(
const blink::NDEFRecordData& value);
};
template <>
struct TypeConverter<device::mojom::blink::NDEFRecordPtr,
blink::NDEFRecordInit*> {
static device::mojom::blink::NDEFRecordPtr Convert(
const blink::NDEFRecordInit* record);
};
template <>
struct TypeConverter<device::mojom::blink::NDEFMessagePtr,
blink::NDEFMessageInit*> {
static device::mojom::blink::NDEFMessagePtr Convert(
const blink::NDEFMessageInit* message);
};
template <>
struct TypeConverter<device::mojom::blink::NDEFMessagePtr,
blink::DOMArrayBuffer*> {
static device::mojom::blink::NDEFMessagePtr Convert(
blink::DOMArrayBuffer* buffer);
}; };
// TODO(https://crbug.com/520391): Add a creator function like
// static NDEFMessage* NDEFMessage::Create(const NDEFMessageSource&);
// which constructs NDEFMessage with
// - validity check of the input NDEFMessageSource, and
// - data serialization of each record (duplicated with code of this type
// converter),
// after that we can convert the NDEFMessage easily to a
// device::mojom::blink::NDEFMessagePtr. This enables us to remove this type
// converter and a bunch of sub converters it depends on.
template <> template <>
struct TypeConverter<device::mojom::blink::NDEFMessagePtr, struct TypeConverter<device::mojom::blink::NDEFMessagePtr,
blink::NDEFMessageSource> { ::blink::NDEFMessage*> {
static device::mojom::blink::NDEFMessagePtr Convert( static device::mojom::blink::NDEFMessagePtr Convert(
const blink::NDEFMessageSource& message); const ::blink::NDEFMessage* message);
}; };
template <> template <>
struct TypeConverter<device::mojom::blink::NFCPushOptionsPtr, struct TypeConverter<device::mojom::blink::NFCPushOptionsPtr,
const blink::NFCPushOptions*> { const ::blink::NFCPushOptions*> {
static device::mojom::blink::NFCPushOptionsPtr Convert( static device::mojom::blink::NFCPushOptionsPtr Convert(
const blink::NFCPushOptions* pushOptions); const ::blink::NFCPushOptions* pushOptions);
}; };
template <> template <>
struct TypeConverter<device::mojom::blink::NFCScanOptionsPtr, struct TypeConverter<device::mojom::blink::NFCScanOptionsPtr,
const blink::NFCScanOptions*> { const ::blink::NFCScanOptions*> {
static device::mojom::blink::NFCScanOptionsPtr Convert( static device::mojom::blink::NFCScanOptionsPtr Convert(
const blink::NFCScanOptions* scanOptions); const ::blink::NFCScanOptions* scanOptions);
}; };
} // namespace mojo } // namespace mojo
......
...@@ -20,193 +20,6 @@ using device::mojom::blink::NFCPushTarget; ...@@ -20,193 +20,6 @@ using device::mojom::blink::NFCPushTarget;
namespace blink { namespace blink {
ScriptPromise RejectIfInvalidTextRecord(ScriptState* script_state,
const NDEFRecordInit* record) {
const NDEFRecordData& value = record->data();
if (!value.IsString() && !(value.IsUnrestrictedDouble() &&
!std::isnan(value.GetAsUnrestrictedDouble()))) {
return ScriptPromise::Reject(
script_state, V8ThrowException::CreateTypeError(
script_state->GetIsolate(), kNfcTextRecordTypeError));
}
if (record->hasMediaType() &&
!record->mediaType().StartsWithIgnoringASCIICase(
kNfcPlainTextMimePrefix)) {
return ScriptPromise::RejectWithDOMException(
script_state,
MakeGarbageCollected<DOMException>(DOMExceptionCode::kSyntaxError,
kNfcTextRecordMediaTypeError));
}
return ScriptPromise();
}
ScriptPromise RejectIfInvalidURLRecord(ScriptState* script_state,
const NDEFRecordInit* record) {
if (!record->data().IsString()) {
return ScriptPromise::Reject(
script_state, V8ThrowException::CreateTypeError(
script_state->GetIsolate(), kNfcUrlRecordTypeError));
}
if (!KURL(NullURL(), record->data().GetAsString()).IsValid()) {
return ScriptPromise::RejectWithDOMException(
script_state,
MakeGarbageCollected<DOMException>(DOMExceptionCode::kSyntaxError,
kNfcUrlRecordParseError));
}
return ScriptPromise();
}
ScriptPromise RejectIfInvalidJSONRecord(ScriptState* script_state,
const NDEFRecordInit* record) {
if (!record->data().IsDictionary()) {
return ScriptPromise::Reject(
script_state, V8ThrowException::CreateTypeError(
script_state->GetIsolate(), kNfcJsonRecordTypeError));
}
// If JSON record has media type, it must be equal to "application/json" or
// start with "application/" and end with "+json".
if (record->hasMediaType() &&
(record->mediaType() != kNfcJsonMimeType &&
!(record->mediaType().StartsWithIgnoringASCIICase(kNfcJsonMimePrefix) &&
record->mediaType().EndsWithIgnoringASCIICase(kNfcJsonMimePostfix)))) {
return ScriptPromise::RejectWithDOMException(
script_state,
MakeGarbageCollected<DOMException>(DOMExceptionCode::kSyntaxError,
kNfcJsonRecordMediaTypeError));
}
return ScriptPromise();
}
ScriptPromise RejectIfInvalidOpaqueRecord(ScriptState* script_state,
const NDEFRecordInit* record) {
if (!record->data().IsArrayBuffer()) {
return ScriptPromise::Reject(
script_state,
V8ThrowException::CreateTypeError(script_state->GetIsolate(),
kNfcOpaqueRecordTypeError));
}
return ScriptPromise();
}
ScriptPromise RejectIfInvalidNDEFRecord(ScriptState* script_state,
const NDEFRecordInit* record) {
NDEFRecordType type;
if (record->hasRecordType()) {
type = StringToNDEFRecordType(record->recordType());
} else {
type = DeduceRecordTypeFromDataType(record);
// https://w3c.github.io/web-nfc/#creating-web-nfc-message
// If NDEFRecord.recordType is not set and record type cannot be deduced
// from NDEFRecord.data, reject promise with TypeError.
if (type == NDEFRecordType::EMPTY) {
return ScriptPromise::Reject(
script_state, V8ThrowException::CreateTypeError(
script_state->GetIsolate(), kNfcRecordTypeError));
}
}
// Non-empty records must have data.
if (!record->hasData() && (type != NDEFRecordType::EMPTY)) {
return ScriptPromise::Reject(
script_state, V8ThrowException::CreateTypeError(
script_state->GetIsolate(), kNfcRecordDataError));
}
switch (type) {
case NDEFRecordType::TEXT:
return RejectIfInvalidTextRecord(script_state, record);
case NDEFRecordType::URL:
return RejectIfInvalidURLRecord(script_state, record);
case NDEFRecordType::JSON:
return RejectIfInvalidJSONRecord(script_state, record);
case NDEFRecordType::OPAQUE_RECORD:
return RejectIfInvalidOpaqueRecord(script_state, record);
case NDEFRecordType::EMPTY:
return ScriptPromise();
}
NOTREACHED();
return ScriptPromise::Reject(
script_state, V8ThrowException::CreateTypeError(
script_state->GetIsolate(), kNfcRecordError));
}
ScriptPromise RejectIfInvalidNDEFRecordArray(
ScriptState* script_state,
const HeapVector<Member<NDEFRecordInit>>& records) {
for (const auto& record : records) {
ScriptPromise isValidRecord =
RejectIfInvalidNDEFRecord(script_state, record);
if (!isValidRecord.IsEmpty())
return isValidRecord;
}
return ScriptPromise();
}
ScriptPromise RejectIfInvalidNDEFMessageSource(
ScriptState* script_state,
const NDEFMessageSource& push_message) {
// If NDEFMessageSource of invalid type, reject promise with TypeError
if (!push_message.IsNDEFMessageInit() && !push_message.IsString() &&
!push_message.IsArrayBuffer()) {
return ScriptPromise::Reject(
script_state, V8ThrowException::CreateTypeError(
script_state->GetIsolate(), kNfcMsgTypeError));
}
if (push_message.IsNDEFMessageInit()) {
// https://w3c.github.io/web-nfc/#the-push-method
// If NDEFMessage.records is empty, reject promise with TypeError
const NDEFMessageInit* message = push_message.GetAsNDEFMessageInit();
if (!message->hasRecords() || message->records().IsEmpty()) {
return ScriptPromise::Reject(
script_state, V8ThrowException::CreateTypeError(
script_state->GetIsolate(), kNfcEmptyMsg));
}
return RejectIfInvalidNDEFRecordArray(script_state, message->records());
}
return ScriptPromise();
}
// https://w3c.github.io/web-nfc/#creating-web-nfc-message Step 2.1
// If NDEFRecord type is not provided, deduce NDEFRecord type from JS data type:
// String or Number => 'text' record
// ArrayBuffer => 'opaque' record
// Dictionary, JSON serializable Object => 'json' record
NDEFRecordType DeduceRecordTypeFromDataType(
const blink::NDEFRecordInit* record) {
if (record->hasData()) {
const blink::NDEFRecordData& value = record->data();
if (value.IsString() || (value.IsUnrestrictedDouble() &&
!std::isnan(value.GetAsUnrestrictedDouble()))) {
return NDEFRecordType::TEXT;
}
if (value.IsDictionary()) {
return NDEFRecordType::JSON;
}
if (value.IsArrayBuffer()) {
return NDEFRecordType::OPAQUE_RECORD;
}
}
return NDEFRecordType::EMPTY;
}
size_t GetNDEFMessageSize(const device::mojom::blink::NDEFMessagePtr& message) { size_t GetNDEFMessageSize(const device::mojom::blink::NDEFMessagePtr& message) {
size_t message_size = message->url.CharactersSizeInBytes(); size_t message_size = message->url.CharactersSizeInBytes();
for (wtf_size_t i = 0; i < message->data.size(); ++i) { for (wtf_size_t i = 0; i < message->data.size(); ++i) {
......
...@@ -16,32 +16,6 @@ namespace blink { ...@@ -16,32 +16,6 @@ namespace blink {
class DOMException; class DOMException;
ScriptPromise RejectIfInvalidTextRecord(ScriptState* script_state,
const NDEFRecordInit* record);
ScriptPromise RejectIfInvalidURLRecord(ScriptState* script_state,
const NDEFRecordInit* record);
ScriptPromise RejectIfInvalidJSONRecord(ScriptState* script_state,
const NDEFRecordInit* record);
ScriptPromise RejectIfInvalidOpaqueRecord(ScriptState* script_state,
const NDEFRecordInit* record);
ScriptPromise RejectIfInvalidNDEFRecord(ScriptState* script_state,
const NDEFRecordInit* record);
ScriptPromise RejectIfInvalidNDEFRecordArray(
ScriptState* script_state,
const HeapVector<Member<NDEFRecordInit>>& records);
ScriptPromise RejectIfInvalidNDEFMessageSource(
ScriptState* script_state,
const NDEFMessageSource& push_message);
device::mojom::blink::NDEFRecordType DeduceRecordTypeFromDataType(
const blink::NDEFRecordInit* record);
size_t GetNDEFMessageSize(const device::mojom::blink::NDEFMessagePtr& message); size_t GetNDEFMessageSize(const device::mojom::blink::NDEFMessagePtr& message);
bool SetNDEFMessageURL(const String& origin, bool SetNDEFMessageURL(const String& origin,
......
...@@ -8,6 +8,7 @@ ...@@ -8,6 +8,7 @@
#include "mojo/public/cpp/bindings/callback_helpers.h" #include "mojo/public/cpp/bindings/callback_helpers.h"
#include "third_party/blink/renderer/bindings/core/v8/script_promise.h" #include "third_party/blink/renderer/bindings/core/v8/script_promise.h"
#include "third_party/blink/renderer/bindings/modules/v8/string_or_array_buffer_or_ndef_message_init.h"
#include "third_party/blink/renderer/core/dom/abort_signal.h" #include "third_party/blink/renderer/core/dom/abort_signal.h"
#include "third_party/blink/renderer/core/dom/dom_exception.h" #include "third_party/blink/renderer/core/dom/dom_exception.h"
#include "third_party/blink/renderer/modules/nfc/nfc_push_options.h" #include "third_party/blink/renderer/modules/nfc/nfc_push_options.h"
...@@ -35,7 +36,8 @@ void NFCWriter::Trace(blink::Visitor* visitor) { ...@@ -35,7 +36,8 @@ void NFCWriter::Trace(blink::Visitor* visitor) {
// https://w3c.github.io/web-nfc/#the-push-method // https://w3c.github.io/web-nfc/#the-push-method
ScriptPromise NFCWriter::push(ScriptState* script_state, ScriptPromise NFCWriter::push(ScriptState* script_state,
const NDEFMessageSource& push_message, const NDEFMessageSource& push_message,
const NFCPushOptions* options) { const NFCPushOptions* options,
ExceptionState& exception_state) {
ExecutionContext* execution_context = GetExecutionContext(); ExecutionContext* execution_context = GetExecutionContext();
// https://w3c.github.io/web-nfc/#security-policies // https://w3c.github.io/web-nfc/#security-policies
// WebNFC API must be only accessible from top level browsing context. // WebNFC API must be only accessible from top level browsing context.
...@@ -54,11 +56,6 @@ ScriptPromise NFCWriter::push(ScriptState* script_state, ...@@ -54,11 +56,6 @@ ScriptPromise NFCWriter::push(ScriptState* script_state,
DOMExceptionCode::kAbortError, kNfcCancelled)); DOMExceptionCode::kAbortError, kNfcCancelled));
} }
ScriptPromise is_valid_message =
RejectIfInvalidNDEFMessageSource(script_state, push_message);
if (!is_valid_message.IsEmpty())
return is_valid_message;
// 9. If timeout value is NaN or negative, reject promise with "TypeError" // 9. If timeout value is NaN or negative, reject promise with "TypeError"
// and abort these steps. // and abort these steps.
if (options->hasTimeout() && if (options->hasTimeout() &&
...@@ -68,13 +65,24 @@ ScriptPromise NFCWriter::push(ScriptState* script_state, ...@@ -68,13 +65,24 @@ ScriptPromise NFCWriter::push(ScriptState* script_state,
script_state->GetIsolate(), kNfcInvalidPushTimeout)); script_state->GetIsolate(), kNfcInvalidPushTimeout));
} }
auto message = device::mojom::blink::NDEFMessage::From(push_message); // Step 10.8: Run "create Web NFC message", if this throws an exception,
if (!message) { // reject p with that exception and abort these steps.
return ScriptPromise::RejectWithDOMException( NDEFMessage* ndef_message =
script_state, MakeGarbageCollected<DOMException>( NDEFMessage::Create(push_message, exception_state);
DOMExceptionCode::kSyntaxError, kNfcMsgConvertError)); if (exception_state.HadException()) {
return ScriptPromise();
} }
// If NDEFMessage.records is empty, reject promise with TypeError
if (ndef_message->records().size() == 0) {
return ScriptPromise::Reject(script_state,
V8ThrowException::CreateTypeError(
script_state->GetIsolate(), kNfcEmptyMsg));
}
auto message = device::mojom::blink::NDEFMessage::From(ndef_message);
DCHECK(message);
if (!SetNDEFMessageURL(execution_context->GetSecurityOrigin()->ToString(), if (!SetNDEFMessageURL(execution_context->GetSecurityOrigin()->ToString(),
message)) { message)) {
return ScriptPromise::RejectWithDOMException( return ScriptPromise::RejectWithDOMException(
......
...@@ -15,8 +15,12 @@ ...@@ -15,8 +15,12 @@
namespace blink { namespace blink {
class NFCPushOptions; class NFCPushOptions;
class ExceptionState;
class ExecutionContext; class ExecutionContext;
class ScriptPromise; class ScriptPromise;
class StringOrArrayBufferOrNDEFMessageInit;
using NDEFMessageSource = StringOrArrayBufferOrNDEFMessageInit;
class NFCWriter : public ScriptWrappable, public ContextClient { class NFCWriter : public ScriptWrappable, public ContextClient {
DEFINE_WRAPPERTYPEINFO(); DEFINE_WRAPPERTYPEINFO();
...@@ -33,7 +37,8 @@ class NFCWriter : public ScriptWrappable, public ContextClient { ...@@ -33,7 +37,8 @@ class NFCWriter : public ScriptWrappable, public ContextClient {
// Pushes NDEFMessageSource asynchronously to NFC tag / peer. // Pushes NDEFMessageSource asynchronously to NFC tag / peer.
ScriptPromise push(ScriptState*, ScriptPromise push(ScriptState*,
const NDEFMessageSource&, const NDEFMessageSource&,
const NFCPushOptions*); const NFCPushOptions*,
ExceptionState&);
// Called by NFCProxy for notification about connection error. // Called by NFCProxy for notification about connection error.
void OnMojoConnectionError(); void OnMojoConnectionError();
......
...@@ -15,5 +15,5 @@ typedef (DOMString or ArrayBuffer or NDEFMessageInit) NDEFMessageSource; ...@@ -15,5 +15,5 @@ typedef (DOMString or ArrayBuffer or NDEFMessageInit) NDEFMessageSource;
ConstructorCallWith=ExecutionContext, ConstructorCallWith=ExecutionContext,
Exposed=Window Exposed=Window
] interface NFCWriter { ] interface NFCWriter {
[CallWith=ScriptState] Promise<void> push (NDEFMessageSource message, optional NFCPushOptions options); [CallWith=ScriptState, RaisesException] Promise<void> push (NDEFMessageSource message, optional NFCPushOptions options);
}; };
...@@ -12,12 +12,8 @@ ...@@ -12,12 +12,8 @@
}, 'NDEFRecord constructor without init dict'); }, 'NDEFRecord constructor without init dict');
test(() => { test(() => {
const record = new NDEFRecord(null); assert_throws(new TypeError, () => new NDEFRecord(null),
assert_equals(record.recordType.length, 0, 'empty recordType'); "The record has neither type nor data.");
assert_equals(record.mediaType.length, 0, 'empty mediaType');
assert_equals(record.toText(), null, 'toText() returns null');
assert_equals(record.toArrayBuffer(), null, 'toArrayBuffer() returns null');
assert_equals(record.toJSON(), null, 'toJSON() returns null');
}, 'NDEFRecord constructor with null init dict'); }, 'NDEFRecord constructor with null init dict');
test(() => { test(() => {
......
...@@ -23,19 +23,15 @@ const invalid_type_messages = ...@@ -23,19 +23,15 @@ const invalid_type_messages =
// NDEFRecord must have data. // NDEFRecord must have data.
createMessage([createTextRecord()]), createMessage([createTextRecord()]),
// NDEFRecord.data for 'text' record must be number or string. // NDEFRecord.data for 'text' record must be a string.
createMessage([createTextRecord(test_buffer_data)]), createMessage([createTextRecord(test_buffer_data)]),
createMessage([createTextRecord(test_json_data)]), createMessage([createTextRecord(test_json_data)]),
createMessage([createTextRecord(test_number_data)]),
// https://w3c.github.io/web-nfc/#dfn-map-a-json-object-to-ndef // https://w3c.github.io/web-nfc/#dfn-map-a-json-object-to-ndef
// NDEFRecord must have data. // NDEFRecord must have data.
createMessage([createJsonRecord()]), createMessage([createJsonRecord()]),
// NDEFRecord.data for 'json' record must be object.
createMessage([createJsonRecord(test_buffer_data)]),
createMessage([createJsonRecord(test_number_data)]),
createMessage([createJsonRecord(test_text_data)]),
// https://w3c.github.io/web-nfc/#dfn-map-a-url-to-ndef // https://w3c.github.io/web-nfc/#dfn-map-a-url-to-ndef
// NDEFRecord must have data. // NDEFRecord must have data.
createMessage([createUrlRecord()]), createMessage([createUrlRecord()]),
...@@ -59,16 +55,16 @@ const invalid_syntax_messages = ...@@ -59,16 +55,16 @@ const invalid_syntax_messages =
[ [
// NDEFRecord.mediaType for 'text' record must be 'text/*'. // NDEFRecord.mediaType for 'text' record must be 'text/*'.
createMessage([createRecord('text', 'application/json', createMessage([createRecord('text', 'application/json',
test_number_data)]), test_text_data)]),
// Data for 'url' record, must be a valid URL. // Data for 'url' record, must be a valid URL.
createMessage([createUrlRecord('Invalid URL:// Data')]), createMessage([createUrlRecord('Invalid URL:// Data')]),
// NDEFRecord.mediaType for 'json' record must be 'application/json' or // A JSON MIME type is any MIME type whose subtype ends in "+json" or
// starts with 'application/' and ends with '+json'. // whose essence is "application/json" or "text/json".
createMessage([createRecord('json', 'image/png', test_json_data)]), createMessage([createRecord('json', 'image/png', test_json_data)]),
createMessage([createRecord('json', 'application/x+y', test_json_data)]), createMessage([createRecord('json', 'application/x+y', test_json_data)]),
createMessage([createRecord('json', 'custom/app+json', test_json_data)]), createMessage([createRecord('json', 'custom/app+jsonx', test_json_data)]),
]; ];
const invalid_signals = [ const invalid_signals = [
...@@ -195,8 +191,8 @@ promise_test(async t => { ...@@ -195,8 +191,8 @@ promise_test(async t => {
const writer = new NFCWriter(); const writer = new NFCWriter();
const message = createMessage([createRecord('json','application/json', const message = createMessage([createRecord('json','application/json',
{ get x(){ return this; } })]); { get x(){ return this; } })]);
await promise_rejects(t, 'SyntaxError', writer.push(message)); await promise_rejects(t, new TypeError(), writer.push(message));
}, "Reject promise with SyntaxError if 'json' record cannot be serialized."); }, "Reject promise with exceptions thrown from serializing the 'json' record data.");
promise_test(async t => { promise_test(async t => {
const writer = new NFCWriter(); const writer = new NFCWriter();
...@@ -251,8 +247,8 @@ nfc_test(async (t, mockNFC) => { ...@@ -251,8 +247,8 @@ nfc_test(async (t, mockNFC) => {
const writer = new NFCWriter(); const writer = new NFCWriter();
let message = createMessage([createTextRecord(test_text_data), let message = createMessage([createTextRecord(test_text_data),
createJsonRecord(test_json_data), createJsonRecord(test_json_data),
createJsonRecord(test_number_data),
createOpaqueRecord(test_buffer_data), createOpaqueRecord(test_buffer_data),
createTextRecord(test_number_data),
createUrlRecord(test_url_data)], createUrlRecord(test_url_data)],
test_message_origin); test_message_origin);
await writer.push(message); await writer.push(message);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment