| 
									
										
										
										
											2020-06-01 21:33:23 +02:00
										 |  |  | /*
 | 
					
						
							|  |  |  |  * Copyright (c) 2020, Andreas Kling <kling@serenityos.org> | 
					
						
							|  |  |  |  * All rights reserved. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * Redistribution and use in source and binary forms, with or without | 
					
						
							|  |  |  |  * modification, are permitted provided that the following conditions are met: | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * 1. Redistributions of source code must retain the above copyright notice, this | 
					
						
							|  |  |  |  *    list of conditions and the following disclaimer. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * 2. Redistributions in binary form must reproduce the above copyright notice, | 
					
						
							|  |  |  |  *    this list of conditions and the following disclaimer in the documentation | 
					
						
							|  |  |  |  *    and/or other materials provided with the distribution. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" | 
					
						
							|  |  |  |  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | 
					
						
							|  |  |  |  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | 
					
						
							|  |  |  |  * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE | 
					
						
							|  |  |  |  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | 
					
						
							|  |  |  |  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR | 
					
						
							|  |  |  |  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER | 
					
						
							|  |  |  |  * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, | 
					
						
							|  |  |  |  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | 
					
						
							|  |  |  |  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #pragma once
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #include <AK/ByteBuffer.h>
 | 
					
						
							|  |  |  | #include <AK/HashMap.h>
 | 
					
						
							|  |  |  | #include <AK/HashTable.h>
 | 
					
						
							|  |  |  | #include <AK/Noncopyable.h>
 | 
					
						
							|  |  |  | #include <AK/RefCounted.h>
 | 
					
						
							|  |  |  | #include <AK/URL.h>
 | 
					
						
							| 
									
										
										
										
											2020-06-01 22:09:38 +02:00
										 |  |  | #include <AK/WeakPtr.h>
 | 
					
						
							|  |  |  | #include <AK/Weakable.h>
 | 
					
						
							| 
									
										
										
										
											2020-06-02 20:27:26 +02:00
										 |  |  | #include <LibGfx/Forward.h>
 | 
					
						
							| 
									
										
										
										
											2020-06-01 21:33:23 +02:00
										 |  |  | #include <LibWeb/Forward.h>
 | 
					
						
							| 
									
										
										
										
											2020-06-01 21:58:29 +02:00
										 |  |  | #include <LibWeb/Loader/LoadRequest.h>
 | 
					
						
							| 
									
										
										
										
											2020-06-01 21:33:23 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | namespace Web { | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | class ResourceClient; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | class Resource : public RefCounted<Resource> { | 
					
						
							|  |  |  |     AK_MAKE_NONCOPYABLE(Resource); | 
					
						
							|  |  |  |     AK_MAKE_NONMOVABLE(Resource); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | public: | 
					
						
							| 
									
										
										
										
											2020-06-02 20:27:26 +02:00
										 |  |  |     enum class Type { | 
					
						
							|  |  |  |         Generic, | 
					
						
							|  |  |  |         Image, | 
					
						
							|  |  |  |     }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     static NonnullRefPtr<Resource> create(Badge<ResourceLoader>, Type, const LoadRequest&); | 
					
						
							|  |  |  |     virtual ~Resource(); | 
					
						
							| 
									
										
										
										
											2020-06-01 21:33:23 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-06-05 23:32:23 +02:00
										 |  |  |     Type type() const { return m_type; } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-06-01 21:33:23 +02:00
										 |  |  |     bool is_loaded() const { return m_loaded; } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     bool is_failed() const { return m_failed; } | 
					
						
							|  |  |  |     const String& error() const { return m_error; } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     bool has_encoded_data() const { return !m_encoded_data.is_null(); } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-06-01 21:58:29 +02:00
										 |  |  |     const URL& url() const { return m_request.url(); } | 
					
						
							| 
									
										
										
										
											2020-06-01 21:33:23 +02:00
										 |  |  |     const ByteBuffer& encoded_data() const { return m_encoded_data; } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-06-06 13:38:08 +02:00
										 |  |  |     const HashMap<String, String, CaseInsensitiveStringTraits>& response_headers() const { return m_response_headers; } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-06-01 21:33:23 +02:00
										 |  |  |     void register_client(Badge<ResourceClient>, ResourceClient&); | 
					
						
							|  |  |  |     void unregister_client(Badge<ResourceClient>, ResourceClient&); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-06-06 14:02:43 +02:00
										 |  |  |     const String& encoding() const { return m_encoding; } | 
					
						
							|  |  |  |     const String& mime_type() const { return m_mime_type; } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-06-01 22:09:38 +02:00
										 |  |  |     void for_each_client(Function<void(ResourceClient&)>); | 
					
						
							| 
									
										
										
										
											2020-06-01 21:33:23 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
											  
											
												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
										 |  |  |     void did_load(Badge<ResourceLoader>, ReadonlyBytes data, const HashMap<String, String, CaseInsensitiveStringTraits>& headers); | 
					
						
							| 
									
										
										
										
											2020-06-01 21:33:23 +02:00
										 |  |  |     void did_fail(Badge<ResourceLoader>, const String& error); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-06-02 20:27:26 +02:00
										 |  |  | protected: | 
					
						
							|  |  |  |     explicit Resource(Type, const LoadRequest&); | 
					
						
							| 
									
										
										
										
											2020-06-01 21:33:23 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-06-02 20:27:26 +02:00
										 |  |  | private: | 
					
						
							| 
									
										
										
										
											2020-06-01 21:58:29 +02:00
										 |  |  |     LoadRequest m_request; | 
					
						
							| 
									
										
										
										
											2020-06-01 21:33:23 +02:00
										 |  |  |     ByteBuffer m_encoded_data; | 
					
						
							| 
									
										
										
										
											2020-06-02 20:27:26 +02:00
										 |  |  |     Type m_type { Type::Generic }; | 
					
						
							| 
									
										
										
										
											2020-06-01 21:33:23 +02:00
										 |  |  |     bool m_loaded { false }; | 
					
						
							|  |  |  |     bool m_failed { false }; | 
					
						
							|  |  |  |     String m_error; | 
					
						
							| 
									
										
										
										
											2020-06-06 14:02:43 +02:00
										 |  |  |     String m_encoding; | 
					
						
							|  |  |  |     String m_mime_type; | 
					
						
							| 
									
										
										
										
											2020-06-01 21:33:23 +02:00
										 |  |  |     HashMap<String, String, CaseInsensitiveStringTraits> m_response_headers; | 
					
						
							|  |  |  |     HashTable<ResourceClient*> m_clients; | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-06-01 22:09:38 +02:00
										 |  |  | class ResourceClient : public Weakable<ResourceClient> { | 
					
						
							| 
									
										
										
										
											2020-06-01 21:33:23 +02:00
										 |  |  | public: | 
					
						
							|  |  |  |     virtual ~ResourceClient(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     virtual void resource_did_load() { } | 
					
						
							|  |  |  |     virtual void resource_did_fail() { } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | protected: | 
					
						
							| 
									
										
										
										
											2020-06-05 23:32:23 +02:00
										 |  |  |     virtual Resource::Type client_type() const { return Resource::Type::Generic; } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-06-01 21:33:23 +02:00
										 |  |  |     Resource* resource() { return m_resource; } | 
					
						
							|  |  |  |     const Resource* resource() const { return m_resource; } | 
					
						
							|  |  |  |     void set_resource(Resource*); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | private: | 
					
						
							|  |  |  |     RefPtr<Resource> m_resource; | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | } |