[GTK][WPE] Stop using legacy custom protocol implementation
[WebKit-https.git] / Source / WebKit / UIProcess / API / glib / WebKitURISchemeRequest.cpp
1 /*
2  * Copyright (C) 2012 Igalia S.L.
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Library General Public
6  * License as published by the Free Software Foundation; either
7  * version 2 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Library General Public License for more details.
13  *
14  * You should have received a copy of the GNU Library General Public License
15  * along with this library; see the file COPYING.LIB.  If not, write to
16  * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
17  * Boston, MA 02110-1301, USA.
18  */
19
20 #include "config.h"
21 #include "WebKitURISchemeRequest.h"
22
23 #include "APIData.h"
24 #include "WebKitPrivate.h"
25 #include "WebKitURISchemeRequestPrivate.h"
26 #include "WebKitWebContextPrivate.h"
27 #include "WebKitWebView.h"
28 #include "WebPageProxy.h"
29 #include <WebCore/GUniquePtrSoup.h>
30 #include <WebCore/ResourceError.h>
31 #include <WebCore/URLSoup.h>
32 #include <libsoup/soup.h>
33 #include <wtf/glib/GRefPtr.h>
34 #include <wtf/glib/RunLoopSourcePriority.h>
35 #include <wtf/glib/WTFGType.h>
36 #include <wtf/text/CString.h>
37
38 using namespace WebKit;
39 using namespace WebCore;
40
41 /**
42  * SECTION: WebKitURISchemeRequest
43  * @Short_description: Represents a URI scheme request
44  * @Title: WebKitURISchemeRequest
45  *
46  * If you register a particular URI scheme in a #WebKitWebContext,
47  * using webkit_web_context_register_uri_scheme(), you have to provide
48  * a #WebKitURISchemeRequestCallback. After that, when a URI request
49  * is made with that particular scheme, your callback will be
50  * called. There you will be able to access properties such as the
51  * scheme, the URI and path, and the #WebKitWebView that initiated the
52  * request, and also finish the request with
53  * webkit_uri_scheme_request_finish().
54  *
55  */
56
57 static const unsigned int gReadBufferSize = 8192;
58
59 struct _WebKitURISchemeRequestPrivate {
60     WebKitWebContext* webContext;
61     RefPtr<WebURLSchemeTask> task;
62
63     RefPtr<WebPageProxy> initiatingPage;
64     CString uri;
65     GUniquePtr<SoupURI> soupURI;
66
67     GRefPtr<GInputStream> stream;
68     uint64_t streamLength;
69     GRefPtr<GCancellable> cancellable;
70     char readBuffer[gReadBufferSize];
71     uint64_t bytesRead;
72     CString mimeType;
73 };
74
75 WEBKIT_DEFINE_TYPE(WebKitURISchemeRequest, webkit_uri_scheme_request, G_TYPE_OBJECT)
76
77 static void webkit_uri_scheme_request_class_init(WebKitURISchemeRequestClass*)
78 {
79 }
80
81 WebKitURISchemeRequest* webkitURISchemeRequestCreate(WebKitWebContext* webContext, WebPageProxy& page, WebURLSchemeTask& task)
82 {
83     WebKitURISchemeRequest* request = WEBKIT_URI_SCHEME_REQUEST(g_object_new(WEBKIT_TYPE_URI_SCHEME_REQUEST, nullptr));
84     request->priv->webContext = webContext;
85     request->priv->task = &task;
86     request->priv->initiatingPage = &page;
87     return request;
88 }
89
90 void webkitURISchemeRequestCancel(WebKitURISchemeRequest* request)
91 {
92     g_cancellable_cancel(request->priv->cancellable.get());
93 }
94
95 /**
96  * webkit_uri_scheme_request_get_scheme:
97  * @request: a #WebKitURISchemeRequest
98  *
99  * Get the URI scheme of @request
100  *
101  * Returns: the URI scheme of @request
102  */
103 const char* webkit_uri_scheme_request_get_scheme(WebKitURISchemeRequest* request)
104 {
105     g_return_val_if_fail(WEBKIT_IS_URI_SCHEME_REQUEST(request), nullptr);
106
107     if (!request->priv->soupURI)
108         request->priv->soupURI = urlToSoupURI(request->priv->task->request().url());
109
110     return request->priv->soupURI->scheme;
111 }
112
113 /**
114  * webkit_uri_scheme_request_get_uri:
115  * @request: a #WebKitURISchemeRequest
116  *
117  * Get the URI of @request
118  *
119  * Returns: the full URI of @request
120  */
121 const char* webkit_uri_scheme_request_get_uri(WebKitURISchemeRequest* request)
122 {
123     g_return_val_if_fail(WEBKIT_IS_URI_SCHEME_REQUEST(request), nullptr);
124
125     if (request->priv->uri.isNull())
126         request->priv->uri = request->priv->task->request().url().string().utf8();
127
128     return request->priv->uri.data();
129 }
130
131 /**
132  * webkit_uri_scheme_request_get_path:
133  * @request: a #WebKitURISchemeRequest
134  *
135  * Get the URI path of @request
136  *
137  * Returns: the URI path of @request
138  */
139 const char* webkit_uri_scheme_request_get_path(WebKitURISchemeRequest* request)
140 {
141     g_return_val_if_fail(WEBKIT_IS_URI_SCHEME_REQUEST(request), nullptr);
142
143     if (!request->priv->soupURI)
144         request->priv->soupURI = urlToSoupURI(request->priv->task->request().url());
145
146     return request->priv->soupURI->path;
147 }
148
149 /**
150  * webkit_uri_scheme_request_get_web_view:
151  * @request: a #WebKitURISchemeRequest
152  *
153  * Get the #WebKitWebView that initiated the request.
154  *
155  * Returns: (transfer none): the #WebKitWebView that initiated @request.
156  */
157 WebKitWebView* webkit_uri_scheme_request_get_web_view(WebKitURISchemeRequest* request)
158 {
159     g_return_val_if_fail(WEBKIT_IS_URI_SCHEME_REQUEST(request), nullptr);
160
161     return webkitWebContextGetWebViewForPage(request->priv->webContext, request->priv->initiatingPage.get());
162 }
163
164 static void webkitURISchemeRequestReadCallback(GInputStream* inputStream, GAsyncResult* result, WebKitURISchemeRequest* schemeRequest)
165 {
166     GRefPtr<WebKitURISchemeRequest> request = adoptGRef(schemeRequest);
167     GUniqueOutPtr<GError> error;
168     gssize bytesRead = g_input_stream_read_finish(inputStream, result, &error.outPtr());
169     if (bytesRead == -1) {
170         webkit_uri_scheme_request_finish_error(request.get(), error.get());
171         return;
172     }
173
174     WebKitURISchemeRequestPrivate* priv = request->priv;
175     // Need to check the stream before proceeding as it can be cancelled if finish_error
176     // was previously call, which won't be detected by g_input_stream_read_finish().
177     if (!priv->stream)
178         return;
179
180     if (!priv->bytesRead) {
181         ResourceResponse response(priv->task->request().url(), String::fromUTF8(priv->mimeType.data()), priv->streamLength, emptyString());
182         priv->task->didReceiveResponse(response);
183     }
184
185     if (!bytesRead) {
186         priv->task->didComplete({ });
187         return;
188     }
189
190     priv->task->didReceiveData(SharedBuffer::create(priv->readBuffer, bytesRead));
191     priv->bytesRead += bytesRead;
192     g_input_stream_read_async(inputStream, priv->readBuffer, gReadBufferSize, RunLoopSourcePriority::AsyncIONetwork, priv->cancellable.get(),
193         reinterpret_cast<GAsyncReadyCallback>(webkitURISchemeRequestReadCallback), g_object_ref(request.get()));
194 }
195
196 /**
197  * webkit_uri_scheme_request_finish:
198  * @request: a #WebKitURISchemeRequest
199  * @stream: a #GInputStream to read the contents of the request
200  * @stream_length: the length of the stream or -1 if not known
201  * @mime_type: (allow-none): the content type of the stream or %NULL if not known
202  *
203  * Finish a #WebKitURISchemeRequest by setting the contents of the request and its mime type.
204  */
205 void webkit_uri_scheme_request_finish(WebKitURISchemeRequest* request, GInputStream* inputStream, gint64 streamLength, const gchar* mimeType)
206 {
207     g_return_if_fail(WEBKIT_IS_URI_SCHEME_REQUEST(request));
208     g_return_if_fail(G_IS_INPUT_STREAM(inputStream));
209     g_return_if_fail(streamLength == -1 || streamLength >= 0);
210
211     request->priv->stream = inputStream;
212     // We use -1 in the API for consistency with soup when the content length is not known, but 0 internally.
213     request->priv->streamLength = streamLength == -1 ? 0 : streamLength;
214     request->priv->cancellable = adoptGRef(g_cancellable_new());
215     request->priv->bytesRead = 0;
216     request->priv->mimeType = mimeType;
217     g_input_stream_read_async(inputStream, request->priv->readBuffer, gReadBufferSize, RunLoopSourcePriority::AsyncIONetwork, request->priv->cancellable.get(),
218         reinterpret_cast<GAsyncReadyCallback>(webkitURISchemeRequestReadCallback), g_object_ref(request));
219 }
220
221 /**
222  * webkit_uri_scheme_request_finish_error:
223  * @request: a #WebKitURISchemeRequest
224  * @error: a #GError that will be passed to the #WebKitWebView
225  *
226  * Finish a #WebKitURISchemeRequest with a #GError.
227  *
228  * Since: 2.2
229  */
230 void webkit_uri_scheme_request_finish_error(WebKitURISchemeRequest* request, GError* error)
231 {
232     g_return_if_fail(WEBKIT_IS_URI_SCHEME_REQUEST(request));
233     g_return_if_fail(error);
234
235     WebKitURISchemeRequestPrivate* priv = request->priv;
236     priv->stream = nullptr;
237     ResourceError resourceError(g_quark_to_string(error->domain), toWebCoreError(error->code), priv->task->request().url(), String::fromUTF8(error->message));
238     priv->task->didComplete(resourceError);
239 }