@@ -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+
187260void 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);
0 commit comments