| 
									
										
										
										
											2020-01-18 09:38:21 +01:00
										 |  |  | /*
 | 
					
						
							|  |  |  |  * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org> | 
					
						
							| 
									
										
										
										
											2022-02-26 09:09:45 -07:00
										 |  |  |  * Copyright (c) 2022, the SerenityOS developers. | 
					
						
							| 
									
										
										
										
											2020-01-18 09:38:21 +01:00
										 |  |  |  * | 
					
						
							| 
									
										
										
										
											2021-04-22 01:24:48 -07:00
										 |  |  |  * SPDX-License-Identifier: BSD-2-Clause | 
					
						
							| 
									
										
										
										
											2020-01-18 09:38:21 +01:00
										 |  |  |  */ | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-01-15 21:46:23 +01:00
										 |  |  | #include <AK/Debug.h>
 | 
					
						
							| 
									
										
										
										
											2020-02-06 15:04:03 +01:00
										 |  |  | #include <LibCore/NetworkJob.h>
 | 
					
						
							|  |  |  | #include <LibCore/NetworkResponse.h>
 | 
					
						
							| 
									
										
										
										
											2019-04-07 14:36:10 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-02-02 12:34:39 +01:00
										 |  |  | namespace Core { | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-02-10 01:00:18 +01:00
										 |  |  | NetworkJob::NetworkJob(Stream& output_stream) | 
					
						
							| 
									
										
											  
											
												ProtocolServer: Stream the downloaded data if possible
This patchset makes ProtocolServer stream the downloads to its client
(LibProtocol), and as such changes the download API; a possible
download lifecycle could be as such:
notation = client->server:'>', server->client:'<', pipe activity:'*'
```
> StartDownload(GET, url, headers, {})
< Response(0, fd 8)
* {data, 1024b}
< HeadersBecameAvailable(0, response_headers, 200)
< DownloadProgress(0, 4K, 1024)
* {data, 1024b}
* {data, 1024b}
< DownloadProgress(0, 4K, 2048)
* {data, 1024b}
< DownloadProgress(0, 4K, 1024)
< DownloadFinished(0, true, 4K)
```
Since managing the received file descriptor is a pain, LibProtocol
implements `Download::stream_into(OutputStream)`, which can be used to
stream the download into any given output stream (be it a file, or
memory, or writing stuff with a delay, etc.).
Also, as some of the users of this API require all the downloaded data
upfront, LibProtocol also implements `set_should_buffer_all_input()`,
which causes the download instance to buffer all the data until the
download is complete, and to call the `on_buffered_download_finish`
hook.
											
										 
											2020-12-26 17:14:12 +03:30
										 |  |  |     : m_output_stream(output_stream) | 
					
						
							| 
									
										
										
										
											2019-04-07 14:36:10 +02:00
										 |  |  | { | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-02-08 23:05:44 +01:00
										 |  |  | void NetworkJob::start(Core::Socket&) | 
					
						
							| 
									
										
										
										
											2020-01-30 17:21:10 -06:00
										 |  |  | { | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-09-30 12:19:54 +03:30
										 |  |  | void NetworkJob::shutdown(ShutdownMode) | 
					
						
							| 
									
										
										
										
											2020-01-30 17:21:10 -06:00
										 |  |  | { | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-02-02 12:34:39 +01:00
										 |  |  | void NetworkJob::did_finish(NonnullRefPtr<NetworkResponse>&& response) | 
					
						
							| 
									
										
										
										
											2019-04-07 14:36:10 +02:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2021-09-19 18:18:19 +04:30
										 |  |  |     if (is_cancelled()) | 
					
						
							|  |  |  |         return; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-11-23 21:42:02 +01:00
										 |  |  |     // NOTE: We protect ourselves here, since the on_finish callback may otherwise
 | 
					
						
							|  |  |  |     //       trigger destruction of this job somehow.
 | 
					
						
							| 
									
										
										
										
											2020-02-02 12:34:39 +01:00
										 |  |  |     NonnullRefPtr<NetworkJob> protector(*this); | 
					
						
							| 
									
										
										
										
											2019-11-23 21:42:02 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-04-07 14:36:10 +02:00
										 |  |  |     m_response = move(response); | 
					
						
							| 
									
										
										
										
											2022-01-22 19:40:33 -05:00
										 |  |  |     dbgln_if(NETWORKJOB_DEBUG, "{} job did_finish", *this); | 
					
						
							| 
									
										
										
										
											2021-02-23 20:42:32 +01:00
										 |  |  |     VERIFY(on_finish); | 
					
						
							| 
									
										
										
										
											2019-04-07 14:36:10 +02:00
										 |  |  |     on_finish(true); | 
					
						
							| 
									
										
										
										
											2021-09-30 12:19:54 +03:30
										 |  |  |     shutdown(ShutdownMode::DetachFromSocket); | 
					
						
							| 
									
										
										
										
											2019-04-07 14:36:10 +02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-02-02 12:34:39 +01:00
										 |  |  | void NetworkJob::did_fail(Error error) | 
					
						
							| 
									
										
										
										
											2019-04-07 14:36:10 +02:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2021-09-19 18:18:19 +04:30
										 |  |  |     if (is_cancelled()) | 
					
						
							|  |  |  |         return; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-11-23 21:42:02 +01:00
										 |  |  |     // NOTE: We protect ourselves here, since the on_finish callback may otherwise
 | 
					
						
							|  |  |  |     //       trigger destruction of this job somehow.
 | 
					
						
							| 
									
										
										
										
											2020-02-02 12:34:39 +01:00
										 |  |  |     NonnullRefPtr<NetworkJob> protector(*this); | 
					
						
							| 
									
										
										
										
											2019-11-23 21:42:02 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-04-07 14:36:10 +02:00
										 |  |  |     m_error = error; | 
					
						
							| 
									
										
										
										
											2022-01-22 19:40:33 -05:00
										 |  |  |     dbgln_if(NETWORKJOB_DEBUG, "{}{{{:p}}} job did_fail! error: {} ({})", class_name(), this, (unsigned)error, to_string(error)); | 
					
						
							| 
									
										
										
										
											2021-02-23 20:42:32 +01:00
										 |  |  |     VERIFY(on_finish); | 
					
						
							| 
									
										
										
										
											2019-04-07 14:36:10 +02:00
										 |  |  |     on_finish(false); | 
					
						
							| 
									
										
										
										
											2021-09-30 12:19:54 +03:30
										 |  |  |     shutdown(ShutdownMode::DetachFromSocket); | 
					
						
							| 
									
										
										
										
											2019-06-22 22:46:05 +02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-06-11 00:56:35 +01:00
										 |  |  | void NetworkJob::did_progress(Optional<u64> total_size, u64 downloaded) | 
					
						
							| 
									
										
										
										
											2020-05-03 09:01:06 +04:30
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2021-09-19 18:18:19 +04:30
										 |  |  |     if (is_cancelled()) | 
					
						
							|  |  |  |         return; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-05-03 09:01:06 +04:30
										 |  |  |     // NOTE: We protect ourselves here, since the callback may otherwise
 | 
					
						
							|  |  |  |     //       trigger destruction of this job somehow.
 | 
					
						
							|  |  |  |     NonnullRefPtr<NetworkJob> protector(*this); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (on_progress) | 
					
						
							|  |  |  |         on_progress(total_size, downloaded); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-04-01 20:58:27 +03:00
										 |  |  | char const* to_string(NetworkJob::Error error) | 
					
						
							| 
									
										
										
										
											2019-06-22 22:46:05 +02:00
										 |  |  | { | 
					
						
							|  |  |  |     switch (error) { | 
					
						
							| 
									
										
										
										
											2020-02-02 12:34:39 +01:00
										 |  |  |     case NetworkJob::Error::ProtocolFailed: | 
					
						
							| 
									
										
										
										
											2019-06-22 22:46:05 +02:00
										 |  |  |         return "ProtocolFailed"; | 
					
						
							| 
									
										
										
										
											2020-02-02 12:34:39 +01:00
										 |  |  |     case NetworkJob::Error::ConnectionFailed: | 
					
						
							| 
									
										
										
										
											2019-06-22 22:46:05 +02:00
										 |  |  |         return "ConnectionFailed"; | 
					
						
							| 
									
										
										
										
											2020-02-02 12:34:39 +01:00
										 |  |  |     case NetworkJob::Error::TransmissionFailed: | 
					
						
							| 
									
										
										
										
											2019-06-22 22:46:05 +02:00
										 |  |  |         return "TransmissionFailed"; | 
					
						
							| 
									
										
										
										
											2020-02-02 12:34:39 +01:00
										 |  |  |     case NetworkJob::Error::Cancelled: | 
					
						
							| 
									
										
										
										
											2019-09-21 17:32:26 +02:00
										 |  |  |         return "Cancelled"; | 
					
						
							| 
									
										
										
										
											2019-06-22 22:46:05 +02:00
										 |  |  |     default: | 
					
						
							|  |  |  |         return "(Unknown error)"; | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2019-04-07 14:36:10 +02:00
										 |  |  | } | 
					
						
							| 
									
										
										
										
											2020-02-02 12:34:39 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  | } |