1
Fork 0
mirror of https://github.com/RGBCube/serenity synced 2025-05-31 06:48:12 +00:00

LibWeb: Begin support for requesting blob URLs with Fetch infrastructure

This does not yet implement requests with a Range header.
This commit is contained in:
Timothy Flynn 2023-08-01 18:53:39 -04:00 committed by Linus Groh
parent 9957d48f48
commit a14f6e42a8
2 changed files with 82 additions and 2 deletions

View file

@ -31,6 +31,8 @@
#include <LibWeb/Fetch/Infrastructure/PortBlocking.h>
#include <LibWeb/Fetch/Infrastructure/Task.h>
#include <LibWeb/Fetch/Infrastructure/URL.h>
#include <LibWeb/FileAPI/Blob.h>
#include <LibWeb/FileAPI/BlobURLStore.h>
#include <LibWeb/HTML/EventLoop/EventLoop.h>
#include <LibWeb/HTML/Scripting/Environments.h>
#include <LibWeb/HTML/Window.h>
@ -718,8 +720,83 @@ WebIDL::ExceptionOr<JS::NonnullGCPtr<PendingResponse>> scheme_fetch(JS::Realm& r
}
// -> "blob"
else if (request->current_url().scheme() == "blob"sv) {
// FIXME: Support 'blob://' URLs
return PendingResponse::create(vm, request, Infrastructure::Response::network_error(vm, "Request has 'blob:' URL which is currently unsupported"sv));
auto const& store = FileAPI::blob_url_store();
// 1. Let blobURLEntry be requests current URLs blob URL entry.
auto blob_url_entry = store.get(TRY_OR_THROW_OOM(vm, request->current_url().to_string()));
// 2. If requests method is not `GET`, blobURLEntry is null, or blobURLEntrys object is not a Blob object,
// then return a network error. [FILEAPI]
if (request->method() != "GET"sv.bytes() || !blob_url_entry.has_value()) {
// FIXME: Handle "blobURLEntrys object is not a Blob object". It could be a MediaSource object, but we
// have not yet implemented the Media Source Extensions spec.
return PendingResponse::create(vm, request, Infrastructure::Response::network_error(vm, "Request has an invalid 'blob:' URL"sv));
}
// 3. Let blob be blobURLEntrys object.
auto const& blob = blob_url_entry->object;
// 4. Let response be a new response.
auto response = Infrastructure::Response::create(vm);
// 5. Let fullLength be blobs size.
auto full_length = blob->size();
// 6. Let serializedFullLength be fullLength, serialized and isomorphic encoded.
auto serialized_full_length = TRY_OR_THROW_OOM(vm, String::number(full_length));
// 7. Let type be blobs type.
auto const& type = blob->type();
// 8. If requests header list does not contain `Range`:
if (!request->header_list()->contains("Range"sv.bytes())) {
// 1. Let bodyWithType be the result of safely extracting blob.
auto body_with_type = TRY(safely_extract_body(realm, blob));
// 2. Set responses status message to `OK`.
response->set_status_message(MUST(ByteBuffer::copy("OK"sv.bytes())));
// 3. Set responses body to bodyWithTypes body.
response->set_body(move(body_with_type.body));
// 4. Set responses header list to « (`Content-Length`, serializedFullLength), (`Content-Type`, type) ».
auto content_length_header = TRY_OR_THROW_OOM(vm, Infrastructure::Header::from_string_pair("Content-Length"sv, serialized_full_length));
TRY_OR_THROW_OOM(vm, response->header_list()->append(move(content_length_header)));
auto content_type_header = TRY_OR_THROW_OOM(vm, Infrastructure::Header::from_string_pair("Content-Type"sv, type));
TRY_OR_THROW_OOM(vm, response->header_list()->append(move(content_type_header)));
}
// FIXME: 9. Otherwise:
else {
// 1. Set responses range-requested flag.
// 2. Let rangeHeader be the result of getting `Range` from requests header list.
// 3. Let rangeValue be the result of parsing a single range header value given rangeHeader and true.
// 4. If rangeValue is failure, then return a network error.
// 5. Let (rangeStart, rangeEnd) be rangeValue.
// 6. If rangeStart is null:
// 1. Set rangeStart to fullLength rangeEnd.
// 2. Set rangeEnd to rangeStart + rangeEnd 1.
// 7. Otherwise:
// 1. If rangeStart is greater than or equal to fullLength, then return a network error.
// 2. If rangeEnd is null or rangeEnd is greater than or equal to fullLength, then set rangeEnd to fullLength 1.
// 8. Let slicedBlob be the result of invoking slice blob given blob, rangeStart, rangeEnd + 1, and type.
// 9. Let slicedBodyWithType be the result of safely extracting slicedBlob.
// 10. Set responses body to slicedBodyWithTypes body.
// 11. Let serializedSlicedLength be slicedBlobs size, serialized and isomorphic encoded.
// 12. Let contentRange be `bytes `.
// 13. Append rangeStart, serialized and isomorphic encoded, to contentRange.
// 14. Append 0x2D (-) to contentRange.
// 15. Append rangeEnd, serialized and isomorphic encoded to contentRange.
// 16. Append 0x2F (/) to contentRange.
// 17. Append serializedFullLength to contentRange.
// 18. Set responses status to 206.
// 19. Set responses status message to `Partial Content`.
// 20. Set responses header list to « (`Content-Length`, serializedSlicedLength), (`Content-Type`, type), (`Content-Range`, contentRange) ».
return PendingResponse::create(vm, request, Infrastructure::Response::network_error(vm, "Request has a 'blob:' URL with a Content-Range header, which is currently unsupported"sv));
}
// 10. Return response.
return PendingResponse::create(vm, request, response);
}
// -> "data"
else if (request->current_url().scheme() == "data"sv) {