Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement Blob methods (text/arraybuffer) #25524

Merged
merged 1 commit into from
Jan 28, 2020
Merged

Implement Blob methods (text/arraybuffer) #25524

merged 1 commit into from
Jan 28, 2020

Conversation

kunalmohan
Copy link
Contributor

#24287 (comment)
#24287 (comment)

r?@jdm


  • There are tests for these changes

@highfive
Copy link

Heads up! This PR modifies the following files:

  • @asajeffrey: components/script/dom/globalscope.rs, components/script/dom/blob.rs, components/script/dom/webidls/Blob.webidl
  • @KiChjang: components/script/dom/globalscope.rs, components/script/dom/blob.rs, components/script/dom/webidls/Blob.webidl

@highfive
Copy link

warning Warning warning

  • These commits modify unsafe code. Please review it carefully!

@highfive highfive added the S-awaiting-review There is new code that needs to be reviewed. label Jan 14, 2020
@jdm
Copy link
Member

jdm commented Jan 14, 2020

@bors-servo try=wpt

bors-servo pushed a commit that referenced this pull request Jan 14, 2020
Implement Blob methods (text/arraybuffer)

<!-- Please describe your changes on the following line: -->
#24287 (comment)
#24287 (comment)

r?@jdm

---
<!-- Thank you for contributing to Servo! Please replace each `[ ]` by `[X]` when the step is complete, and replace `___` with appropriate data: -->
- [X] `./mach build -d` does not report any errors
- [X] `./mach test-tidy` does not report any errors
- [X] These changes fix #24287  (GitHub issue number if applicable)

<!-- Either: -->
- [X] There are tests for these changes

<!-- Also, please make sure that "Allow edits from maintainers" checkbox is checked, so that we can help you if you get stuck somewhere along the way.-->

<!-- Pull requests that do not address these steps are welcome, but they will require additional verification as part of the review process. -->
@bors-servo
Copy link
Contributor

⌛ Trying commit bc10ca9 with merge 6a4c471...

Copy link
Member

@jdm jdm left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good start! Next we need to make use of the new async reading coding.

components/script/dom/blob.rs Outdated Show resolved Hide resolved
@jdm jdm added S-needs-code-changes Changes have not yet been made that were requested by a reviewer. and removed S-awaiting-review There is new code that needs to be reviewed. labels Jan 14, 2020
@bors-servo
Copy link
Contributor

💔 Test failed - status-taskcluster

@highfive highfive added the S-tests-failed The changes caused existing tests to fail. label Jan 14, 2020
@jdm
Copy link
Member

jdm commented Jan 14, 2020

  ▶ Unexpected subtest result in /FileAPI/idlharness.html:
  └ PASS [expected FAIL] Blob interface: new Blob(["TEST"]) must inherit property "text()" with the proper type
  ▶ Unexpected subtest result in /FileAPI/idlharness.html:
  └ PASS [expected FAIL] Blob interface: new Blob(["TEST"]) must inherit property "arrayBuffer()" with the proper type
  ▶ Unexpected subtest result in /FileAPI/idlharness.html:
  └ PASS [expected FAIL] Blob interface: new File(["myFileBits"], "myFileName") must inherit property "text()" with the proper type
  ▶ Unexpected subtest result in /FileAPI/idlharness.html:
  └ PASS [expected FAIL] Blob interface: new File(["myFileBits"], "myFileName") must inherit property "arrayBuffer()" with the proper type
  ▶ Unexpected subtest result in /FileAPI/idlharness.worker.html:
  └ PASS [expected FAIL] Blob interface: new Blob(["TEST"]) must inherit property "text()" with the proper type
  ▶ Unexpected subtest result in /FileAPI/idlharness.worker.html:
  └ PASS [expected FAIL] Blob interface: new Blob(["TEST"]) must inherit property "arrayBuffer()" with the proper type
  ▶ Unexpected subtest result in /FileAPI/idlharness.worker.html:
  └ PASS [expected FAIL] Blob interface: new File(["myFileBits"], "myFileName") must inherit property "text()" with the proper type
  ▶ Unexpected subtest result in /FileAPI/idlharness.worker.html:
  └ PASS [expected FAIL] Blob interface: new File(["myFileBits"], "myFileName") must inherit property "arrayBuffer()" with the proper type

@kunalmohan
Copy link
Contributor Author

Two tests present in /FileAPI/blob/Blob-array-buffer.any.worker.html are now crashing (earlier failing) due to the new changes.
Also below two tests (which are, I guess, unrelated) are passing (along with #25524 (comment)).

▶ Unexpected subtest result in /FileAPI/url/url-in-tags-revoke.window.html:
  └ PASS [expected TIMEOUT] Fetching a blob URL immediately before revoking it works in <script> tags.

  ▶ Unexpected subtest result in /FileAPI/url/url-with-fetch.any.worker.html:
  └ PASS [expected FAIL] Revoke blob URL after calling fetch, fetch should succeed

Should I run update-wpt for these?

Complete log:

▶ CRASH [expected OK] /FileAPI/blob/Blob-array-buffer.any.worker.html
  │ 
  │ 
  │ 
  │ 
  │ Stack trace for thread "WebWorker for http://web-platform.test:8000/FileAPI/blob/Blob-array-buffer.any.worker.js"
  │ stack backtrace:
  │    0: servo::backtrace::print
  └    1: servo::install_crash_handler::handler

  ▶ CRASH [expected OK] /FileAPI/blob/Blob-array-buffer.any.html
  │ 
  │ 
  │ 
  │ 
  │ Stack trace for thread "ScriptThread PipelineId { namespace_id: PipelineNamespaceId(1), index: PipelineIndex(1) }"
  │ stack backtrace:
  │    0: servo::backtrace::print
  │    1: servo::install_crash_handler::handler
  │    2: _ZL15WasmTrapHandleriP9siginfo_tPv
  │              at /home/kunal/.cargo/git/checkouts/mozjs-fa11ffc7d4f1cc2d/5906588/mozjs/js/src/wasm/WasmSignalHandlers.cpp:969
  │    3: <unknown>
  │    4: _ZN2js15DispatchWrapperIN7mozilla7VariantIJNS_17ImmediateMetadataENS_13DelayMetadataEP8JSObjectEEEEC2IRS7_EEOT_
  │              at /mnt/sda1/Documents/webpages/rust/servo/target/release/build/mozjs_sys-a68895a9a474443a/out/dist/include/js/RootingAPI.h:821
  │       _ZN2JS6RootedIN7mozilla7VariantIJN2js17ImmediateMetadataENS3_13DelayMetadataEP8JSObjectEEEEC2IP9JSContextRS8_EERKT_OT0_
  │              at /mnt/sda1/Documents/webpages/rust/servo/target/release/build/mozjs_sys-a68895a9a474443a/out/dist/include/js/RootingAPI.h:1006
  │       _ZN2js24AutoSetNewObjectMetadataC2EP9JSContext
  │              at /home/kunal/.cargo/git/checkouts/mozjs-fa11ffc7d4f1cc2d/5906588/mozjs/js/src/vm/Realm.cpp:928
  │    5: _ZN2js17ArrayBufferObject12createZeroedEP9JSContextjN2JS6HandleIP8JSObjectEE
  │              at /home/kunal/.cargo/git/checkouts/mozjs-fa11ffc7d4f1cc2d/5906588/mozjs/js/src/vm/ArrayBufferObject.cpp:1253
  │    6: <script::dom::blob::Blob as script::dom::bindings::codegen::Bindings::BlobBinding::BlobBinding::BlobMethods>::ArrayBuffer::{{closure}}
  │    7: <script::dom::globalscope::GlobalScope::read_file_async::{{closure}}::resolve_promise<F> as script::task::TaskOnce>::run_once
  │    8: <T as script::task::TaskBox>::run_box
  │    9: script::script_thread::ScriptThread::handle_msg_from_script
  │   10: _ZN6script13script_thread12ScriptThread11handle_msgs17h5c090bd97d42fd24E.llvm.11406202263875604048
  │   11: std::sys_common::backtrace::__rust_begin_short_backtrace
  │   12: _ZN3std9panicking3try7do_call17h3bc312ab8689d34bE.llvm.5922729734672873076
  │   13: __rust_maybe_catch_panic
  │              at src/libpanic_unwind/lib.rs:78
  │   14: core::ops::function::FnOnce::call_once{{vtable.shim}}
  │   15: <alloc::boxed::Box<F> as core::ops::function::FnOnce<A>>::call_once
  │              at /rustc/9b98af84c4aa66392236fff59c86da2130d46d46/src/liballoc/boxed.rs:1022
  │   16: <alloc::boxed::Box<F> as core::ops::function::FnOnce<A>>::call_once
  │              at /rustc/9b98af84c4aa66392236fff59c86da2130d46d46/src/liballoc/boxed.rs:1022
  │       std::sys_common::thread::start_thread
  │              at src/libstd/sys_common/thread.rs:13
  │       std::sys::unix::thread::Thread::new::thread_start
  │              at src/libstd/sys/unix/thread.rs:80
  │   17: start_thread
  │   18: __clone
  └ 

  ▶ OK [expected TIMEOUT] /FileAPI/url/url-in-tags-revoke.window.html

  ▶ Unexpected subtest result in /FileAPI/url/url-in-tags-revoke.window.html:
  └ PASS [expected TIMEOUT] Fetching a blob URL immediately before revoking it works in <script> tags.

  ▶ Unexpected subtest result in /FileAPI/url/url-with-fetch.any.worker.html:
  └ PASS [expected FAIL] Revoke blob URL after calling fetch, fetch should succeed

  ▶ Unexpected subtest result in /FileAPI/idlharness.worker.html:
  └ PASS [expected FAIL] Blob interface: new Blob(["TEST"]) must inherit property "text()" with the proper type

  ▶ Unexpected subtest result in /FileAPI/idlharness.worker.html:
  └ PASS [expected FAIL] Blob interface: new Blob(["TEST"]) must inherit property "arrayBuffer()" with the proper type

  ▶ Unexpected subtest result in /FileAPI/idlharness.worker.html:
  └ PASS [expected FAIL] Blob interface: new File(["myFileBits"], "myFileName") must inherit property "text()" with the proper type

  ▶ Unexpected subtest result in /FileAPI/idlharness.worker.html:
  └ PASS [expected FAIL] Blob interface: new File(["myFileBits"], "myFileName") must inherit property "arrayBuffer()" with the proper type

@jdm
Copy link
Member

jdm commented Jan 15, 2020

I suspect that adding a enter_realm call before invoking the closure (eg.

let _ac = enter_realm(&*global);
) will fix the crashes. And yes, you can go ahead and update all those text expectations.

@highfive highfive added S-awaiting-review There is new code that needs to be reviewed. and removed S-tests-failed The changes caused existing tests to fail. S-needs-code-changes Changes have not yet been made that were requested by a reviewer. labels Jan 15, 2020
@kunalmohan
Copy link
Contributor Author

kunalmohan commented Jan 15, 2020

tests in /FileAPI/url were randomly passing (sometimes), so I did not update test expectations for those.

@kunalmohan kunalmohan requested a review from jdm January 17, 2020 20:51
let trusted_promise = TrustedPromise::new(promise);
let canceller = self.task_canceller(TaskSourceName::FileReading);
let task_source = self.file_reading_task_source();
thread::spawn(move || {
Copy link
Member

@gterzian gterzian Jan 20, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think you can use an IPC route on recv instead of a thread, see for example

ROUTER.add_route(

The route is valid for multiple messages, you wouldn't need the loop on the recv. So instead you could just move a let mut bytes = vec![]; into the route closure, handle each message as now, and queue the task when getting the eof or error message.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am facing some problem in this part. I have made the above changes to some extent. I am facing a couple of errors which I could not figure out how to get past.

error[E0507]: cannot move out of `trusted_promise`, a captured variable in an `FnMut` closure
    --> components/script/task.rs:27:15
     |
27   |           $name(move || $body)
     |                 ^^^^^^^ move out of `trusted_promise` occurs here
     | 
    ::: components/script/dom/globalscope.rs:1259:13
     |
1259 |           let trusted_promise = TrustedPromise::new(promise);
     |               --------------- captured outer variable
...
1279 | /                             task!(resolve_promise: move || {
1280 | |                                 let promise = trusted_promise.root();
     | |                                               ---------------
     | |                                               |
     | |                                               move occurs because `trusted_promise` has type `dom::bindings::refcounted::TrustedPromise`, which does not implement the `Copy` trait
     | |                                               move occurs due to use in closure
1281 | |                                 let _ac = enter_realm(&*promise.global());
1282 | |                                 f(promise, bytes);
1283 | |                             }),
     | |______________________________- in this macro invocation

error[E0507]: cannot move out of `f`, a captured variable in an `FnMut` closure
    --> components/script/task.rs:27:15
     |
27   |           $name(move || $body)
     |                 ^^^^^^^ move out of `f` occurs here
     | 
    ::: components/script/dom/globalscope.rs:1256:9
     |
1256 |           f: Box<dyn Fn(Rc<Promise>, Result<Vec<u8>, Error>) + Send>,
     |           - captured outer variable
...
1279 | /                             task!(resolve_promise: move || {
1280 | |                                 let promise = trusted_promise.root();
1281 | |                                 let _ac = enter_realm(&*promise.global());
1282 | |                                 f(promise, bytes);
     | |                                 -
     | |                                 |
     | |                                 move occurs because `f` has type `std::boxed::Box<dyn std::ops::Fn(std::rc::Rc<dom::promise::Promise>, std::result::Result<std::vec::Vec<u8>, dom::bindings::error::Error>) + std::marker::Send>`, which does not implement the `Copy` trait
     | |                                 move occurs due to use in closure
1283 | |                             }),
     | |______________________________- in this macro invocation

I would need some help here. I have pushed the changes (for you to review). Hopefully it is close to what you had asked for :)

id,
p.clone(),
Box::new(|promise, bytes| {
let bytes = bytes.unwrap();
Copy link
Member

@gterzian gterzian Jan 20, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think both here and in the other method, if bytes is an error, you want to reject the promise, instead of panicking.

See step 3(the "error" case) of https://fetch.spec.whatwg.org/#concept-read-all-bytes-from-readablestream (which is not implemented here due to the lack of stream support, and I just think rejecting the promise is more in the spirit of the spec).

The question would still be, what kind of error? I guess a NetworkError could do.

Copy link
Member

@gterzian gterzian left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks like it's going in the right direction! I've looked at the compile error, and there is also one other comment.

let bytes = Ok(bytes);
let _ = task_source.queue_with_canceller(
task!(resolve_promise: move || {
let promise = trusted_promise.root();
Copy link
Member

@gterzian gterzian Jan 21, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think you need to clone the promise(outside of the task!), and then move the clone into the closure of the task!.

You might want to implement a struct to give the code some more structure, see the examples of TimerListener and MessageListener.

But actually for this one, since you need to queue only one task, you could avoid the clone as described in the other comment.

recv.to_opaque(),
Box::new(move |message| {
let message = message.to();
let mut bytes = vec![];
Copy link
Member

@gterzian gterzian Jan 21, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You also want to create the vec outside of the route, and move it into it, otherwise you will create a new one for each message received.

You might also want to put the bytes inside a struct, together with the trusted promise, as mentioned in the other comment.

I would suggest the following, to give the code more structure:

enum FileBytes {
    /// The initial value when first creating a FileListener,
    Empty(Trusted<Promise>),
    /// The value after having received the Meta message.
    Receiving(Vec<u8>, Trusted<Promise>),
    /// The value after having queued the task resolving the promise.
    Done,
}

Then you could have a struct like:

struct FileListener {
    bytes: FileBytes
    task_source: //
    task_canceller: //
}

which would allow you to express more precisely how the bytes are received and then passed to the promise via the task. In the sense that when receiving ReadFileProgress::Meta, bytes you could assert bytes is FileBytes::Empty, and then transform it into FileBytes::Receiving(bytes), then we you receive the EOF message, you can assert bytes is FileBytes::Receiving(bytes), then take bytes out of FileBytes::Receiving(bytes), move it into the closure of the queued task, and transform FileListener into FileBytes::Done.

And when you receive the Err message, only queue an error if it is either be at FileBytes::Empty or FileBytes::Receiving(bytes), ignore it is it is Done.

Copy link
Contributor Author

@kunalmohan kunalmohan Jan 21, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have made some progress here. First of all, I have used bytes: DomRefCell<FileBytes> in FileListener. But still I am some problems here.

  1. I cannot assert bytes to be Empty or Receiving because TrustedPromise does not implement Debug or PartialEq. For now I have used if let to mutably borrows bytes out of Receiving(bytes) and in the else block used panic!.
  2. I cannot figure out how to transform Empty(trusted_promise) to Receiving(bytes, trusted_promise). I cannot transfer trusted_promise from one enum variant to another. So I removed TrustedPromise from FileBytes in order to get past that. (I am thinking of using Option<TrustedPromise> inside Empty. Maybe that would help. Could not try that today; will do tomorrow.)
  3. Now I am facing a lifetime error. 😞 . I guess I'll have to clone bytes before queuing the task.

I have pushed the changes for you to review.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have removed the lifetime error with clone, but I cannot pass the closure(f) as parameter to handle() since it does not implement Copy or Clone trait. (same for trusted_promise, if passed as parameter instead of enum)

@gterzian
Copy link
Member

Yes you are right, it is tricky to implement this enum as I suggested. Let me play with the code a bit to try to find a solution...

Copy link
Member

@gterzian gterzian left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok so what I suggested earlier with the enum doesn't seem like a good idea, since you can't move out of the struct. I got something to compile which you can see f116542 That seems like a better alternative. It is indeed using options as you suggested.

@kunalmohan
Copy link
Contributor Author

It seems pretty good to me. I tried using Option, but never considered removing the enum. I'll update my code with this and run the tests. Is there anything that is yet to be implemented?

@kunalmohan
Copy link
Contributor Author

I just saw the latest changes you made. (I'll be more careful with the commas and spacing next time 😅 )

@kunalmohan
Copy link
Contributor Author

All of the related tests (which were passing) are crashing at

_ => panic!("Unexpected FileListenerState when receiving Err msg."),

(line 454, globalscope.rs)
I will start debugging these now.

@gterzian
Copy link
Member

(I'll be more careful with the commas and spacing next time

You can simply use ./mach fmt.

All of the related tests (which were passing) are crashing

It might be that the route always gets a last Err, when the corresponding sender is dropped. In that case we should just remove the panic.

I will start debugging these now.

Ok, let me know what you find.

@kunalmohan
Copy link
Contributor Author

kunalmohan commented Jan 23, 2020

In that case we should just remove the panic.

I tried that- replacing it with empty block- all the tests fail-with the NetworkError- in that case.

@highfive highfive added the S-awaiting-review There is new code that needs to be reviewed. label Jan 24, 2020
@kunalmohan
Copy link
Contributor Author

Done!

Copy link
Member

@gterzian gterzian left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM, just two nits.

&self,
id: Uuid,
promise: Rc<Promise>,
callback: Box<dyn Fn(Rc<Promise>, Result<Vec<u8>, Error>) + Send>,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: here we can use FileListenerCallback

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actually, please discard this comment, we already type the callback below when we add it to the file listener, and using FileListenerCallback in the function signature directly will just make its use by the blob more complicated.

So just the space with the doc comment, and it's good to go!

@@ -231,6 +235,23 @@ struct TimerListener {
context: Trusted<GlobalScope>,
}

/// A wrapper for the handling of file data received by the ipc router
Copy link
Member

@gterzian gterzian Jan 25, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: Lets consistently use one space following ///(see below where the space is missing, here it looks like there are two). ./mach fmt doesn't catch this I think.

@kunalmohan
Copy link
Contributor Author

Sorry for the late response. I was on a two-day vacation devoid of any network.
Nevertheless, I have made the required changes.

Copy link
Member

@gterzian gterzian left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok, I finally looked to the actual DOM side of things, and I'm sorry for not having mentioned it earlier, but I have a last few suggestions.

p.clone(),
Box::new(|promise, bytes| match bytes {
Ok(b) => {
let (text, _, _) = UTF_8.decode(&b);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Here I am wondering if we can re-use run_text_data_algorithm

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah no forget about this one, I think what you are doing with UTF_8 fits the spec more, in the light of:

Note: This is different from the behavior of readAsText() to align better with the behavior of Fetch’s text(). Specifically this method will always use UTF-8 as encoding, while FileReader can use a different encoding depending on the blob’s type and passed in encoding name.
https://w3c.github.io/FileAPI/#text-method-algo

I think the other comment is still relevant.

match bytes {
Ok(b) => {
let cx = promise.global().get_cx();
unsafe {
Copy link
Member

@gterzian gterzian Jan 27, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Here I think we can reuse run_array_buffer_data_algorithm

For both suggestions, to see how the results can be resolved into a promise can be seen at

match results {

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also note that in the case of an error being returned by that function, I think it would be more appropriate to reject the promise with it, versus panicking.

}

// https://w3c.github.io/FileAPI/#arraybuffer-method-algo
#[allow(unsafe_code)]
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This could also be removed if we re-use run_array_buffer_data_algorithm

Copy link
Member

@gterzian gterzian left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good, thanks for making that additional change. I have one small comment on the change, after that please squash into one commit and it should be good to go!

match result {
Ok(FetchedData::ArrayBuffer(a)) => promise.resolve_native(&a),
Err(e) => promise.reject_error(e),
_ => {},
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: Here you can actually panic with an appropriate message, like "Unexpected result from run_array_buffer_data_algorithm".


fn read_msg(
object: profile_ipc::IpcReceiver<FileManagerResult<ReadFileProgress>>,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok last thing, this time really :)

Let's just call this arg receiver.

@gterzian
Copy link
Member

@kunalmohan thank you, great work!

@bors-servo r=jdm,gterzian

@bors-servo
Copy link
Contributor

📌 Commit 9859410 has been approved by jdm,gterzian

@highfive highfive added S-awaiting-merge The PR is in the process of compiling and running tests on the automated CI. and removed S-awaiting-review There is new code that needs to be reviewed. labels Jan 28, 2020
bors-servo pushed a commit that referenced this pull request Jan 28, 2020
Implement Blob methods (text/arraybuffer)

<!-- Please describe your changes on the following line: -->
#24287 (comment)
#24287 (comment)

r?@jdm

---
<!-- Thank you for contributing to Servo! Please replace each `[ ]` by `[X]` when the step is complete, and replace `___` with appropriate data: -->
- [X] `./mach build -d` does not report any errors
- [X] `./mach test-tidy` does not report any errors
- [X] These changes fix #24287  (GitHub issue number if applicable)

<!-- Either: -->
- [X] There are tests for these changes

<!-- Also, please make sure that "Allow edits from maintainers" checkbox is checked, so that we can help you if you get stuck somewhere along the way.-->

<!-- Pull requests that do not address these steps are welcome, but they will require additional verification as part of the review process. -->
@bors-servo
Copy link
Contributor

⌛ Testing commit 9859410 with merge 5db2da9...

@bors-servo
Copy link
Contributor

💔 Test failed - status-taskcluster

@highfive highfive added S-tests-failed The changes caused existing tests to fail. and removed S-awaiting-merge The PR is in the process of compiling and running tests on the automated CI. labels Jan 28, 2020
@gterzian
Copy link
Member

@bors-servo retry #25632

@bors-servo
Copy link
Contributor

⌛ Testing commit 9859410 with merge 2b3c4eb...

bors-servo pushed a commit that referenced this pull request Jan 28, 2020
Implement Blob methods (text/arraybuffer)

<!-- Please describe your changes on the following line: -->
#24287 (comment)
#24287 (comment)

r?@jdm

---
<!-- Thank you for contributing to Servo! Please replace each `[ ]` by `[X]` when the step is complete, and replace `___` with appropriate data: -->
- [X] `./mach build -d` does not report any errors
- [X] `./mach test-tidy` does not report any errors
- [X] These changes fix #24287  (GitHub issue number if applicable)

<!-- Either: -->
- [X] There are tests for these changes

<!-- Also, please make sure that "Allow edits from maintainers" checkbox is checked, so that we can help you if you get stuck somewhere along the way.-->

<!-- Pull requests that do not address these steps are welcome, but they will require additional verification as part of the review process. -->
@highfive highfive added S-awaiting-merge The PR is in the process of compiling and running tests on the automated CI. and removed S-tests-failed The changes caused existing tests to fail. labels Jan 28, 2020
@bors-servo
Copy link
Contributor

☀️ Test successful - status-taskcluster
Approved by: jdm,gterzian
Pushing 2b3c4eb to master...

@bors-servo bors-servo merged commit 9859410 into servo:master Jan 28, 2020
@highfive highfive removed the S-awaiting-merge The PR is in the process of compiling and running tests on the automated CI. label Jan 28, 2020
@kunalmohan kunalmohan deleted the 24287-BlobAPI branch January 29, 2020 18:05
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Implement Blob reading APIs (arrayBuffer/text)
5 participants