[WTF] Add makeUnique<T>, which ensures T is fast-allocated, makeUnique / makeUniqueWi...
[WebKit-https.git] / Source / WebKit / NetworkProcess / soup / WebKitSoupRequestInputStream.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 "WebKitSoupRequestInputStream.h"
22
23 #include <wtf/MainThread.h>
24 #include <wtf/RunLoop.h>
25 #include <wtf/glib/GRefPtr.h>
26 #include <wtf/glib/GUniquePtr.h>
27
28 struct AsyncReadData {
29     WTF_MAKE_STRUCT_FAST_ALLOCATED;
30     AsyncReadData(GRefPtr<GTask>&& task, void* buffer, gsize count)
31         : task(WTFMove(task))
32         , buffer(buffer)
33         , count(count)
34     {
35     }
36
37     GRefPtr<GTask> task;
38     void* buffer;
39     size_t count;
40 };
41
42 struct _WebKitSoupRequestInputStreamPrivate {
43     WTF_MAKE_STRUCT_FAST_ALLOCATED;
44     uint64_t contentLength;
45     uint64_t bytesReceived;
46     uint64_t bytesRead;
47
48     GUniquePtr<GError> error;
49
50     std::unique_ptr<AsyncReadData> pendingAsyncRead;
51 };
52
53 G_DEFINE_TYPE(WebKitSoupRequestInputStream, webkit_soup_request_input_stream, G_TYPE_MEMORY_INPUT_STREAM)
54
55 static void webkitSoupRequestInputStreamReadAsyncResultComplete(GTask* task, void* buffer, gsize count)
56 {
57     WebKitSoupRequestInputStream* stream = WEBKIT_SOUP_REQUEST_INPUT_STREAM(g_task_get_source_object(task));
58     GError* error = nullptr;
59     gssize bytesRead = G_INPUT_STREAM_GET_CLASS(stream)->read_fn(G_INPUT_STREAM(stream), buffer, count, g_task_get_cancellable(task), &error);
60     if (!error) {
61         stream->priv->bytesRead += bytesRead;
62         g_task_return_int(task, bytesRead);
63     } else
64         g_task_return_error(task, error);
65 }
66
67 static void webkitSoupRequestInputStreamPendingReadAsyncComplete(WebKitSoupRequestInputStream* stream)
68 {
69     if (auto data = WTFMove(stream->priv->pendingAsyncRead))
70         webkitSoupRequestInputStreamReadAsyncResultComplete(data->task.get(), data->buffer, data->count);
71 }
72
73 static bool webkitSoupRequestInputStreamHasDataToRead(WebKitSoupRequestInputStream* stream)
74 {
75     return stream->priv->bytesRead < stream->priv->bytesReceived;
76 }
77
78 static bool webkitSoupRequestInputStreamIsWaitingForData(WebKitSoupRequestInputStream* stream)
79 {
80     return !stream->priv->contentLength || stream->priv->bytesReceived < stream->priv->contentLength;
81 }
82
83 static void webkitSoupRequestInputStreamReadAsync(GInputStream* inputStream, void* buffer, gsize count, int /*priority*/, GCancellable* cancellable, GAsyncReadyCallback callback, gpointer userData)
84 {
85     ASSERT(RunLoop::isMain());
86     WebKitSoupRequestInputStream* stream = WEBKIT_SOUP_REQUEST_INPUT_STREAM(inputStream);
87     GRefPtr<GTask> task = adoptGRef(g_task_new(stream, cancellable, callback, userData));
88
89     if (!webkitSoupRequestInputStreamHasDataToRead(stream) && !webkitSoupRequestInputStreamIsWaitingForData(stream)) {
90         g_task_return_int(task.get(), 0);
91         return;
92     }
93
94     if (stream->priv->error.get()) {
95         g_task_return_error(task.get(), stream->priv->error.release());
96         return;
97     }
98
99     if (webkitSoupRequestInputStreamHasDataToRead(stream)) {
100         webkitSoupRequestInputStreamReadAsyncResultComplete(task.get(), buffer, count);
101         return;
102     }
103
104     stream->priv->pendingAsyncRead = makeUnique<AsyncReadData>(WTFMove(task), buffer, count);
105 }
106
107 static gssize webkitSoupRequestInputStreamReadFinish(GInputStream* inputStream, GAsyncResult* result, GError** error)
108 {
109     g_return_val_if_fail(g_task_is_valid(result, inputStream), 0);
110
111     return g_task_propagate_int(G_TASK(result), error);
112 }
113
114 static void webkitSoupRequestInputStreamFinalize(GObject* object)
115 {
116     WEBKIT_SOUP_REQUEST_INPUT_STREAM(object)->priv->~WebKitSoupRequestInputStreamPrivate();
117     G_OBJECT_CLASS(webkit_soup_request_input_stream_parent_class)->finalize(object);
118 }
119
120 static void webkit_soup_request_input_stream_init(WebKitSoupRequestInputStream* stream)
121 {
122     WebKitSoupRequestInputStreamPrivate* priv = G_TYPE_INSTANCE_GET_PRIVATE(stream, WEBKIT_TYPE_SOUP_REQUEST_INPUT_STREAM, WebKitSoupRequestInputStreamPrivate);
123     stream->priv = priv;
124     new (priv) WebKitSoupRequestInputStreamPrivate();
125 }
126
127 static void webkit_soup_request_input_stream_class_init(WebKitSoupRequestInputStreamClass* requestStreamClass)
128 {
129     GObjectClass* gObjectClass = G_OBJECT_CLASS(requestStreamClass);
130     gObjectClass->finalize = webkitSoupRequestInputStreamFinalize;
131
132     GInputStreamClass* inputStreamClass = G_INPUT_STREAM_CLASS(requestStreamClass);
133     inputStreamClass->read_async = webkitSoupRequestInputStreamReadAsync;
134     inputStreamClass->read_finish = webkitSoupRequestInputStreamReadFinish;
135
136     g_type_class_add_private(requestStreamClass, sizeof(WebKitSoupRequestInputStreamPrivate));
137 }
138
139 GInputStream* webkitSoupRequestInputStreamNew(uint64_t contentLength)
140 {
141     WebKitSoupRequestInputStream* stream = WEBKIT_SOUP_REQUEST_INPUT_STREAM(g_object_new(WEBKIT_TYPE_SOUP_REQUEST_INPUT_STREAM, NULL));
142     stream->priv->contentLength = contentLength;
143     return G_INPUT_STREAM(stream);
144 }
145
146 void webkitSoupRequestInputStreamAddData(WebKitSoupRequestInputStream* stream, const void* data, size_t dataLength)
147 {
148     ASSERT(RunLoop::isMain());
149
150     if (webkitSoupRequestInputStreamFinished(stream))
151         return;
152
153     if (dataLength) {
154         // Truncate the dataLength to the contentLength if it's known.
155         if (stream->priv->contentLength && stream->priv->bytesReceived + dataLength > stream->priv->contentLength)
156             dataLength = stream->priv->contentLength - stream->priv->bytesReceived;
157         stream->priv->bytesReceived += dataLength;
158         g_memory_input_stream_add_data(G_MEMORY_INPUT_STREAM(stream), g_memdup(data, dataLength), dataLength, g_free);
159     } else {
160         // We have received all the data, set contentLength to bytesReceived to indicate we have finished.
161         stream->priv->contentLength = stream->priv->bytesReceived;
162         // If there's a pending read to complete, read_fn will return 0 because we haven't added more data to the
163         // memory input stream. And if there isn't a pending read, the next call to read_async will return 0 too, because
164         // webkitSoupRequestInputStreamFinished() is now TRUE.
165     }
166
167     webkitSoupRequestInputStreamPendingReadAsyncComplete(stream);
168 }
169
170 void webkitSoupRequestInputStreamDidFailWithError(WebKitSoupRequestInputStream* stream, const WebCore::ResourceError& resourceError)
171 {
172     GUniquePtr<GError> error(g_error_new(g_quark_from_string(resourceError.domain().utf8().data()), resourceError.errorCode(), "%s", resourceError.localizedDescription().utf8().data()));
173     if (auto data = WTFMove(stream->priv->pendingAsyncRead))
174         g_task_return_error(data->task.get(), error.release());
175     else {
176         stream->priv->contentLength = stream->priv->bytesReceived;
177         stream->priv->error = WTFMove(error);
178     }
179 }
180
181 bool webkitSoupRequestInputStreamFinished(WebKitSoupRequestInputStream* stream)
182 {
183     return !webkitSoupRequestInputStreamIsWaitingForData(stream);
184 }