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