IncrementalReadLoopReadRequest.cpp 3.9 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485
  1. /*
  2. * Copyright (c) 2024, Kenneth Myhra <kennethmyhra@serenityos.org>
  3. *
  4. * SPDX-License-Identifier: BSD-2-Clause
  5. */
  6. #include <LibJS/Runtime/TypedArray.h>
  7. #include <LibWeb/Fetch/Infrastructure/IncrementalReadLoopReadRequest.h>
  8. #include <LibWeb/HTML/Scripting/TemporaryExecutionContext.h>
  9. namespace Web::Fetch::Infrastructure {
  10. JS_DEFINE_ALLOCATOR(IncrementalReadLoopReadRequest);
  11. void IncrementalReadLoopReadRequest::on_chunk(JS::Value chunk)
  12. {
  13. auto& realm = m_reader->realm();
  14. // 1. Let continueAlgorithm be null.
  15. JS::GCPtr<JS::HeapFunction<void()>> continue_algorithm;
  16. // 2. If chunk is not a Uint8Array object, then set continueAlgorithm to this step: run processBodyError given a TypeError.
  17. if (!chunk.is_object() || !is<JS::Uint8Array>(chunk.as_object())) {
  18. continue_algorithm = JS::create_heap_function(realm.heap(), [&realm, process_body_error = m_process_body_error] {
  19. process_body_error->function()(JS::TypeError::create(realm, "Chunk data is not Uint8Array"sv));
  20. });
  21. }
  22. // 3. Otherwise:
  23. else {
  24. // 1. Let bytes be a copy of chunk.
  25. // NOTE: Implementations are strongly encouraged to use an implementation strategy that avoids this copy where possible.
  26. auto& uint8_array = static_cast<JS::Uint8Array&>(chunk.as_object());
  27. auto bytes = MUST(ByteBuffer::copy(uint8_array.data()));
  28. // 2. Set continueAlgorithm to these steps:
  29. continue_algorithm = JS::create_heap_function(realm.heap(), [bytes = move(bytes), body = m_body, reader = m_reader, task_destination = m_task_destination, process_body_chunk = m_process_body_chunk, process_end_of_body = m_process_end_of_body, process_body_error = m_process_body_error] {
  30. HTML::TemporaryExecutionContext execution_context { reader->realm(), HTML::TemporaryExecutionContext::CallbacksEnabled::Yes };
  31. // 1. Run processBodyChunk given bytes.
  32. process_body_chunk->function()(move(bytes));
  33. // 2. Perform the incrementally-read loop given reader, taskDestination, processBodyChunk, processEndOfBody, and processBodyError.
  34. body->incrementally_read_loop(reader, task_destination, process_body_chunk, process_end_of_body, process_body_error);
  35. });
  36. }
  37. // 4. Queue a fetch task given continueAlgorithm and taskDestination.
  38. Fetch::Infrastructure::queue_fetch_task(m_task_destination, *continue_algorithm);
  39. }
  40. void IncrementalReadLoopReadRequest::on_close()
  41. {
  42. // 1. Queue a fetch task given processEndOfBody and taskDestination.
  43. Fetch::Infrastructure::queue_fetch_task(m_task_destination, JS::create_heap_function(m_reader->heap(), [this] {
  44. m_process_end_of_body->function()();
  45. }));
  46. }
  47. void IncrementalReadLoopReadRequest::on_error(JS::Value error)
  48. {
  49. // 1. Queue a fetch task to run processBodyError given e, with taskDestination.
  50. Fetch::Infrastructure::queue_fetch_task(m_task_destination, JS::create_heap_function(m_reader->heap(), [this, error = move(error)] {
  51. m_process_body_error->function()(error);
  52. }));
  53. }
  54. IncrementalReadLoopReadRequest::IncrementalReadLoopReadRequest(JS::NonnullGCPtr<Body> body, JS::NonnullGCPtr<Streams::ReadableStreamDefaultReader> reader, JS::NonnullGCPtr<JS::Object> task_destination, Body::ProcessBodyChunkCallback process_body_chunk, Body::ProcessEndOfBodyCallback process_end_of_body, Body::ProcessBodyErrorCallback process_body_error)
  55. : m_body(body)
  56. , m_reader(reader)
  57. , m_task_destination(task_destination)
  58. , m_process_body_chunk(process_body_chunk)
  59. , m_process_end_of_body(process_end_of_body)
  60. , m_process_body_error(process_body_error)
  61. {
  62. }
  63. void IncrementalReadLoopReadRequest::visit_edges(Visitor& visitor)
  64. {
  65. Base::visit_edges(visitor);
  66. visitor.visit(m_body);
  67. visitor.visit(m_reader);
  68. visitor.visit(m_task_destination);
  69. visitor.visit(m_process_body_chunk);
  70. visitor.visit(m_process_end_of_body);
  71. visitor.visit(m_process_body_error);
  72. }
  73. }