Skip to content

Commit 2fd7b70

Browse files
kalenikaliaksandrtrflynn89
authored andcommitted
LibWeb: Implement file: protocol support for load_unbuffered()
Preparation work before enabling unbuffered fetching by default.
1 parent fa46efa commit 2fd7b70

File tree

2 files changed

+109
-67
lines changed

2 files changed

+109
-67
lines changed

Libraries/LibWeb/Loader/ResourceLoader.cpp

Lines changed: 100 additions & 67 deletions
Original file line numberDiff line numberDiff line change
@@ -184,6 +184,79 @@ static bool should_block_request(LoadRequest const& request)
184184
return false;
185185
}
186186

187+
template<typename FileHandler, typename ErrorHandler>
188+
void ResourceLoader::handle_file_load_request(LoadRequest& request, FileHandler on_file, ErrorHandler on_error)
189+
{
190+
auto page = request.page();
191+
if (!page) {
192+
auto const error_message = ByteString("INTERNAL ERROR: No Page for file scheme request"sv);
193+
on_error(error_message);
194+
return;
195+
}
196+
197+
auto const& url = request.url().value();
198+
199+
FileRequest file_request(url.file_path(), [this, request, on_file, on_error, url](ErrorOr<i32> file_or_error) mutable {
200+
--m_pending_loads;
201+
if (on_load_counter_change)
202+
on_load_counter_change();
203+
204+
if (file_or_error.is_error()) {
205+
auto const message = ByteString::formatted("{}", file_or_error.error());
206+
on_error(message);
207+
return;
208+
}
209+
210+
auto const fd = file_or_error.value();
211+
212+
auto maybe_is_valid_directory = Core::Directory::is_valid_directory(fd);
213+
if (!maybe_is_valid_directory.is_error() && maybe_is_valid_directory.value()) {
214+
auto maybe_response = load_file_directory_page(url);
215+
if (maybe_response.is_error()) {
216+
auto const message = ByteString::formatted("{}", maybe_response.error());
217+
on_error(message);
218+
return;
219+
}
220+
221+
FileLoadResult load_result;
222+
load_result.data = maybe_response.value().bytes();
223+
load_result.response_headers.set("Content-Type"sv, "text/html"sv);
224+
on_file(load_result);
225+
return;
226+
}
227+
228+
auto st_or_error = Core::System::fstat(fd);
229+
if (st_or_error.is_error()) {
230+
on_error(ByteString::formatted("{}", st_or_error.error()));
231+
return;
232+
}
233+
234+
auto maybe_file = Core::File::adopt_fd(fd, Core::File::OpenMode::Read);
235+
if (maybe_file.is_error()) {
236+
on_error(ByteString::formatted("{}", maybe_file.error()));
237+
return;
238+
}
239+
240+
auto file = maybe_file.release_value();
241+
auto maybe_data = file->read_until_eof();
242+
if (maybe_data.is_error()) {
243+
on_error(ByteString::formatted("{}", maybe_data.error()));
244+
return;
245+
}
246+
247+
FileLoadResult load_result;
248+
load_result.data = maybe_data.value().bytes();
249+
load_result.response_headers = response_headers_for_file(request.url()->file_path(), st_or_error.value().st_mtime);
250+
on_file(load_result);
251+
});
252+
253+
page->client().request_file(move(file_request));
254+
255+
++m_pending_loads;
256+
if (on_load_counter_change)
257+
on_load_counter_change();
258+
}
259+
187260
void ResourceLoader::load(LoadRequest& request, GC::Root<SuccessCallback> success_callback, GC::Root<ErrorCallback> error_callback, Optional<u32> timeout, GC::Root<TimeoutCallback> timeout_callback)
188261
{
189262
auto const& url = request.url().value();
@@ -309,74 +382,17 @@ void ResourceLoader::load(LoadRequest& request, GC::Root<SuccessCallback> succes
309382
}
310383

311384
if (url.scheme() == "file") {
312-
auto page = request.page();
313-
if (!page) {
314-
log_failure(request, "INTERNAL ERROR: No Page for file scheme request");
315-
return;
316-
}
317-
318-
FileRequest file_request(url.file_path(), [this, success_callback, error_callback, request, respond_directory_page](ErrorOr<i32> file_or_error) {
319-
--m_pending_loads;
320-
if (on_load_counter_change)
321-
on_load_counter_change();
322-
323-
if (file_or_error.is_error()) {
324-
log_failure(request, file_or_error.error());
325-
if (error_callback)
326-
error_callback->function()(ByteString::formatted("{}", file_or_error.error()), {}, {}, {}, {}, {});
327-
return;
328-
}
329-
330-
auto const fd = file_or_error.value();
331-
332-
// When local file is a directory use file directory loader to generate response
333-
auto maybe_is_valid_directory = Core::Directory::is_valid_directory(fd);
334-
if (!maybe_is_valid_directory.is_error() && maybe_is_valid_directory.value()) {
335-
respond_directory_page(request, request.url().value(), success_callback, error_callback);
336-
return;
337-
}
338-
339-
auto st_or_error = Core::System::fstat(fd);
340-
if (st_or_error.is_error()) {
341-
log_failure(request, st_or_error.error());
342-
if (error_callback)
343-
error_callback->function()(ByteString::formatted("{}", st_or_error.error()), {}, {}, {}, {}, {});
344-
return;
345-
}
346-
347-
// Try to read file normally
348-
auto maybe_file = Core::File::adopt_fd(fd, Core::File::OpenMode::Read);
349-
if (maybe_file.is_error()) {
350-
log_failure(request, maybe_file.error());
351-
if (error_callback)
352-
error_callback->function()(ByteString::formatted("{}", maybe_file.error()), {}, {}, {}, {}, {});
353-
return;
354-
}
355-
356-
auto file = maybe_file.release_value();
357-
auto maybe_data = file->read_until_eof();
358-
if (maybe_data.is_error()) {
359-
log_failure(request, maybe_data.error());
385+
handle_file_load_request(
386+
request,
387+
[success_callback, request](FileLoadResult const& load_result) {
388+
log_success(request);
389+
success_callback->function()(load_result.data, load_result.timing_info, load_result.response_headers, {}, {});
390+
},
391+
[error_callback, request](ByteString const& error_message) {
392+
log_failure(request, error_message);
360393
if (error_callback)
361-
error_callback->function()(ByteString::formatted("{}", maybe_data.error()), {}, {}, {}, {}, {});
362-
return;
363-
}
364-
365-
auto data = maybe_data.release_value();
366-
auto response_headers = response_headers_for_file(request.url()->file_path(), st_or_error.value().st_mtime);
367-
368-
// FIXME: Implement timing info for file requests.
369-
Requests::RequestTimingInfo fixme_implement_timing_info {};
370-
371-
log_success(request);
372-
success_callback->function()(data, fixme_implement_timing_info, response_headers, {}, {});
373-
});
374-
375-
page->client().request_file(move(file_request));
376-
377-
++m_pending_loads;
378-
if (on_load_counter_change)
379-
on_load_counter_change();
394+
error_callback->function()(error_message, {}, {}, {}, {}, {});
395+
});
380396

381397
return;
382398
}
@@ -458,6 +474,23 @@ void ResourceLoader::load_unbuffered(LoadRequest& request, GC::Root<OnHeadersRec
458474
return;
459475
}
460476

477+
if (url.scheme() == "file"sv) {
478+
handle_file_load_request(
479+
request,
480+
[request, on_headers_received, on_data_received, on_complete](FileLoadResult const& load_result) {
481+
log_success(request);
482+
on_headers_received->function()(load_result.response_headers, {}, {});
483+
on_data_received->function()(load_result.data);
484+
on_complete->function()(true, load_result.timing_info, {});
485+
},
486+
[on_complete, request](ByteString const& message) {
487+
log_failure(request, message);
488+
on_complete->function()(false, {}, StringView(message));
489+
});
490+
491+
return;
492+
}
493+
461494
if (!url.scheme().is_one_of("http"sv, "https"sv)) {
462495
// FIXME: Non-network requests from fetch should not go through this path.
463496
on_complete->function()(false, {}, "Cannot establish connection non-network scheme"sv);

Libraries/LibWeb/Loader/ResourceLoader.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
#include <LibGC/Function.h>
1515
#include <LibHTTP/HeaderMap.h>
1616
#include <LibRequests/Forward.h>
17+
#include <LibRequests/RequestTimingInfo.h>
1718
#include <LibURL/URL.h>
1819
#include <LibWeb/Forward.h>
1920
#include <LibWeb/Loader/UserAgent.h>
@@ -72,6 +73,14 @@ class WEB_API ResourceLoader : public Core::EventReceiver {
7273
private:
7374
explicit ResourceLoader(GC::Heap&, NonnullRefPtr<Requests::RequestClient>);
7475

76+
struct FileLoadResult {
77+
ReadonlyBytes data;
78+
HTTP::HeaderMap response_headers;
79+
Requests::RequestTimingInfo timing_info;
80+
};
81+
template<typename FileHandler, typename ErrorHandler>
82+
void handle_file_load_request(LoadRequest& request, FileHandler on_file, ErrorHandler on_error);
83+
7584
RefPtr<Requests::Request> start_network_request(LoadRequest const&);
7685
void handle_network_response_headers(LoadRequest const&, HTTP::HeaderMap const&);
7786
void finish_network_request(NonnullRefPtr<Requests::Request>);

0 commit comments

Comments
 (0)