1 | /* |
2 | * Copyright (C) 2016 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 "WebKitWebViewSessionState.h" |
22 | |
23 | #include "WebKitWebViewSessionStatePrivate.h" |
24 | #include <WebCore/BackForwardItemIdentifier.h> |
25 | #include <wtf/glib/GRefPtr.h> |
26 | #include <wtf/glib/GUniquePtr.h> |
27 | |
28 | using namespace WebKit; |
29 | |
30 | struct _WebKitWebViewSessionState { |
31 | _WebKitWebViewSessionState(SessionState&& state) |
32 | : sessionState(WTFMove(state)) |
33 | , referenceCount(1) |
34 | { |
35 | } |
36 | |
37 | SessionState sessionState; |
38 | int referenceCount; |
39 | }; |
40 | |
41 | G_DEFINE_BOXED_TYPE(WebKitWebViewSessionState, webkit_web_view_session_state, webkit_web_view_session_state_ref, webkit_web_view_session_state_unref) |
42 | |
43 | // Version information: |
44 | // - Version 2: removed backforward list item identifier since it's always regenerated. |
45 | // - Version 1: initial version. |
46 | static const guint16 g_sessionStateVersion = 2; |
47 | #define HTTP_BODY_ELEMENT_TYPE_STRING_V1 "(uaysxmxmds)" |
48 | #define HTTP_BODY_ELEMENT_FORMAT_STRING_V1 "(uay&sxmxmd&s)" |
49 | #define HTTP_BODY_TYPE_STRING_V1 "m(sa" HTTP_BODY_ELEMENT_TYPE_STRING_V1 ")" |
50 | #define HTTP_BODY_FORMAT_STRING_V1 "m(&sa" HTTP_BODY_ELEMENT_TYPE_STRING_V1 ")" |
51 | #define FRAME_STATE_TYPE_STRING_V1 "(ssssasmayxx(ii)d" HTTP_BODY_TYPE_STRING_V1 "av)" |
52 | #define FRAME_STATE_FORMAT_STRING_V1 "(&s&s&s&sasmayxx(ii)d@" HTTP_BODY_TYPE_STRING_V1 "av)" |
53 | #define BACK_FORWARD_LIST_ITEM_TYPE_STRING_V1 "(ts" FRAME_STATE_TYPE_STRING_V1 "u)" |
54 | #define BACK_FORWARD_LIST_ITEM_TYPE_STRING_V2 "(s" FRAME_STATE_TYPE_STRING_V1 "u)" |
55 | #define BACK_FORWARD_LIST_ITEM_FORMAT_STRING_V1 "(t&s@" FRAME_STATE_TYPE_STRING_V1 "u)" |
56 | #define BACK_FORWARD_LIST_ITEM_FORMAT_STRING_V2 "(&s@" FRAME_STATE_TYPE_STRING_V1 "u)" |
57 | #define SESSION_STATE_TYPE_STRING_V1 "(qa" BACK_FORWARD_LIST_ITEM_TYPE_STRING_V1 "mu)" |
58 | #define SESSION_STATE_TYPE_STRING_V2 "(qa" BACK_FORWARD_LIST_ITEM_TYPE_STRING_V2 "mu)" |
59 | |
60 | // Use our own enum types to ensure the serialized format even if the core enums change. |
61 | enum ExternalURLsPolicy { |
62 | Allow, |
63 | AllowExternalSchemes, |
64 | NotAllow |
65 | }; |
66 | |
67 | static inline unsigned toExternalURLsPolicy(WebCore::ShouldOpenExternalURLsPolicy policy) |
68 | { |
69 | switch (policy) { |
70 | case WebCore::ShouldOpenExternalURLsPolicy::ShouldAllow: |
71 | return ExternalURLsPolicy::Allow; |
72 | case WebCore::ShouldOpenExternalURLsPolicy::ShouldAllowExternalSchemes: |
73 | return ExternalURLsPolicy::AllowExternalSchemes; |
74 | case WebCore::ShouldOpenExternalURLsPolicy::ShouldNotAllow: |
75 | return ExternalURLsPolicy::NotAllow; |
76 | } |
77 | |
78 | return ExternalURLsPolicy::NotAllow; |
79 | } |
80 | |
81 | static inline WebCore::ShouldOpenExternalURLsPolicy toWebCoreExternalURLsPolicy(unsigned policy) |
82 | { |
83 | switch (policy) { |
84 | case ExternalURLsPolicy::Allow: |
85 | return WebCore::ShouldOpenExternalURLsPolicy::ShouldAllow; |
86 | case ExternalURLsPolicy::AllowExternalSchemes: |
87 | return WebCore::ShouldOpenExternalURLsPolicy::ShouldAllowExternalSchemes; |
88 | case ExternalURLsPolicy::NotAllow: |
89 | return WebCore::ShouldOpenExternalURLsPolicy::ShouldNotAllow; |
90 | } |
91 | |
92 | return WebCore::ShouldOpenExternalURLsPolicy::ShouldNotAllow; |
93 | } |
94 | |
95 | enum HTMLBodyElementType { |
96 | Data, |
97 | File, |
98 | Blob |
99 | }; |
100 | |
101 | static inline unsigned toHTMLBodyElementType(HTTPBody::Element::Type type) |
102 | { |
103 | switch (type) { |
104 | case HTTPBody::Element::Type::Data: |
105 | return HTMLBodyElementType::Data; |
106 | case HTTPBody::Element::Type::File: |
107 | return HTMLBodyElementType::File; |
108 | case HTTPBody::Element::Type::Blob: |
109 | return HTMLBodyElementType::Blob; |
110 | } |
111 | |
112 | return HTMLBodyElementType::Data; |
113 | } |
114 | |
115 | static inline HTTPBody::Element::Type toHTTPBodyElementType(unsigned type) |
116 | { |
117 | switch (type) { |
118 | case HTMLBodyElementType::Data: |
119 | return HTTPBody::Element::Type::Data; |
120 | case HTMLBodyElementType::File: |
121 | return HTTPBody::Element::Type::File; |
122 | case HTMLBodyElementType::Blob: |
123 | return HTTPBody::Element::Type::Blob; |
124 | } |
125 | |
126 | return HTTPBody::Element::Type::Data; |
127 | } |
128 | |
129 | static inline void encodeHTTPBody(GVariantBuilder* sessionBuilder, const HTTPBody& httpBody) |
130 | { |
131 | g_variant_builder_open(sessionBuilder, G_VARIANT_TYPE("(sa" HTTP_BODY_ELEMENT_TYPE_STRING_V1 ")" )); |
132 | g_variant_builder_add(sessionBuilder, "s" , httpBody.contentType.utf8().data()); |
133 | g_variant_builder_open(sessionBuilder, G_VARIANT_TYPE("a" HTTP_BODY_ELEMENT_TYPE_STRING_V1)); |
134 | g_variant_builder_open(sessionBuilder, G_VARIANT_TYPE(HTTP_BODY_ELEMENT_TYPE_STRING_V1)); |
135 | for (const auto& element : httpBody.elements) { |
136 | g_variant_builder_add(sessionBuilder, "u" , toHTMLBodyElementType(element.type)); |
137 | g_variant_builder_open(sessionBuilder, G_VARIANT_TYPE("ay" )); |
138 | for (auto item : element.data) |
139 | g_variant_builder_add(sessionBuilder, "y" , item); |
140 | g_variant_builder_close(sessionBuilder); |
141 | g_variant_builder_add(sessionBuilder, "s" , element.filePath.utf8().data()); |
142 | g_variant_builder_add(sessionBuilder, "x" , element.fileStart); |
143 | if (element.fileLength) |
144 | g_variant_builder_add(sessionBuilder, "mx" , TRUE, element.fileLength.value()); |
145 | else |
146 | g_variant_builder_add(sessionBuilder, "mx" , FALSE); |
147 | if (element.expectedFileModificationTime) |
148 | g_variant_builder_add(sessionBuilder, "md" , TRUE, element.expectedFileModificationTime.value()); |
149 | else |
150 | g_variant_builder_add(sessionBuilder, "md" , FALSE); |
151 | g_variant_builder_add(sessionBuilder, "s" , element.blobURLString.utf8().data()); |
152 | } |
153 | g_variant_builder_close(sessionBuilder); |
154 | g_variant_builder_close(sessionBuilder); |
155 | g_variant_builder_close(sessionBuilder); |
156 | } |
157 | |
158 | static inline void encodeFrameState(GVariantBuilder* sessionBuilder, const FrameState& frameState) |
159 | { |
160 | g_variant_builder_add(sessionBuilder, "s" , frameState.urlString.utf8().data()); |
161 | g_variant_builder_add(sessionBuilder, "s" , frameState.originalURLString.utf8().data()); |
162 | g_variant_builder_add(sessionBuilder, "s" , frameState.referrer.utf8().data()); |
163 | g_variant_builder_add(sessionBuilder, "s" , frameState.target.utf8().data()); |
164 | g_variant_builder_open(sessionBuilder, G_VARIANT_TYPE("as" )); |
165 | for (const auto& state : frameState.documentState) |
166 | g_variant_builder_add(sessionBuilder, "s" , state.utf8().data()); |
167 | g_variant_builder_close(sessionBuilder); |
168 | if (!frameState.stateObjectData) |
169 | g_variant_builder_add(sessionBuilder, "may" , FALSE); |
170 | else { |
171 | g_variant_builder_open(sessionBuilder, G_VARIANT_TYPE("may" )); |
172 | g_variant_builder_open(sessionBuilder, G_VARIANT_TYPE("ay" )); |
173 | for (auto item : frameState.stateObjectData.value()) |
174 | g_variant_builder_add(sessionBuilder, "y" , item); |
175 | g_variant_builder_close(sessionBuilder); |
176 | g_variant_builder_close(sessionBuilder); |
177 | } |
178 | g_variant_builder_add(sessionBuilder, "x" , frameState.documentSequenceNumber); |
179 | g_variant_builder_add(sessionBuilder, "x" , frameState.itemSequenceNumber); |
180 | g_variant_builder_add(sessionBuilder, "(ii)" , frameState.scrollPosition.x(), frameState.scrollPosition.y()); |
181 | g_variant_builder_add(sessionBuilder, "d" , static_cast<gdouble>(frameState.pageScaleFactor)); |
182 | if (!frameState.httpBody) |
183 | g_variant_builder_add(sessionBuilder, HTTP_BODY_TYPE_STRING_V1, FALSE); |
184 | else { |
185 | g_variant_builder_open(sessionBuilder, G_VARIANT_TYPE(HTTP_BODY_TYPE_STRING_V1)); |
186 | encodeHTTPBody(sessionBuilder, frameState.httpBody.value()); |
187 | g_variant_builder_close(sessionBuilder); |
188 | } |
189 | g_variant_builder_open(sessionBuilder, G_VARIANT_TYPE("av" )); |
190 | for (const auto& child : frameState.children) { |
191 | GVariantBuilder frameStateBuilder; |
192 | g_variant_builder_init(&frameStateBuilder, G_VARIANT_TYPE(FRAME_STATE_TYPE_STRING_V1)); |
193 | encodeFrameState(&frameStateBuilder, child); |
194 | g_variant_builder_add(sessionBuilder, "v" , g_variant_builder_end(&frameStateBuilder)); |
195 | } |
196 | g_variant_builder_close(sessionBuilder); |
197 | } |
198 | |
199 | static inline void encodePageState(GVariantBuilder* sessionBuilder, const PageState& pageState) |
200 | { |
201 | g_variant_builder_add(sessionBuilder, "s" , pageState.title.utf8().data()); |
202 | g_variant_builder_open(sessionBuilder, G_VARIANT_TYPE(FRAME_STATE_TYPE_STRING_V1)); |
203 | encodeFrameState(sessionBuilder, pageState.mainFrameState); |
204 | g_variant_builder_close(sessionBuilder); |
205 | g_variant_builder_add(sessionBuilder, "u" , toExternalURLsPolicy(pageState.shouldOpenExternalURLsPolicy)); |
206 | } |
207 | |
208 | static inline void encodeBackForwardListItemState(GVariantBuilder* sessionBuilder, const BackForwardListItemState& item) |
209 | { |
210 | g_variant_builder_open(sessionBuilder, G_VARIANT_TYPE(BACK_FORWARD_LIST_ITEM_TYPE_STRING_V2)); |
211 | encodePageState(sessionBuilder, item.pageState); |
212 | g_variant_builder_close(sessionBuilder); |
213 | } |
214 | |
215 | static inline void encodeBackForwardListState(GVariantBuilder* sessionBuilder, const BackForwardListState& backForwardListState) |
216 | { |
217 | g_variant_builder_open(sessionBuilder, G_VARIANT_TYPE("a" BACK_FORWARD_LIST_ITEM_TYPE_STRING_V2)); |
218 | for (const auto& item : backForwardListState.items) |
219 | encodeBackForwardListItemState(sessionBuilder, item); |
220 | g_variant_builder_close(sessionBuilder); |
221 | |
222 | if (backForwardListState.currentIndex) |
223 | g_variant_builder_add(sessionBuilder, "mu" , TRUE, backForwardListState.currentIndex.value()); |
224 | else |
225 | g_variant_builder_add(sessionBuilder, "mu" , FALSE); |
226 | } |
227 | |
228 | static GBytes* encodeSessionState(const SessionState& sessionState) |
229 | { |
230 | GVariantBuilder sessionBuilder; |
231 | g_variant_builder_init(&sessionBuilder, G_VARIANT_TYPE(SESSION_STATE_TYPE_STRING_V2)); |
232 | g_variant_builder_add(&sessionBuilder, "q" , g_sessionStateVersion); |
233 | encodeBackForwardListState(&sessionBuilder, sessionState.backForwardListState); |
234 | GRefPtr<GVariant> variant = g_variant_builder_end(&sessionBuilder); |
235 | return g_variant_get_data_as_bytes(variant.get()); |
236 | } |
237 | |
238 | static inline bool decodeHTTPBody(GVariant* httpBodyVariant, HTTPBody& httpBody) |
239 | { |
240 | gboolean hasHTTPBody; |
241 | const char* contentType; |
242 | GUniqueOutPtr<GVariantIter> elementsIter; |
243 | g_variant_get(httpBodyVariant, HTTP_BODY_FORMAT_STRING_V1, &hasHTTPBody, &contentType, &elementsIter.outPtr()); |
244 | if (!hasHTTPBody) |
245 | return false; |
246 | httpBody.contentType = String::fromUTF8(contentType); |
247 | gsize elementsLength = g_variant_iter_n_children(elementsIter.get()); |
248 | if (!elementsLength) |
249 | return true; |
250 | httpBody.elements.reserveInitialCapacity(elementsLength); |
251 | unsigned type; |
252 | GVariantIter* dataIter; |
253 | const char* filePath; |
254 | gint64 fileStart; |
255 | gboolean hasFileLength; |
256 | gint64 fileLength; |
257 | gboolean hasFileModificationTime; |
258 | gdouble fileModificationTime; |
259 | const char* blobURLString; |
260 | while (g_variant_iter_loop(elementsIter.get(), HTTP_BODY_ELEMENT_FORMAT_STRING_V1, &type, &dataIter, &filePath, &fileStart, &hasFileLength, &fileLength, &hasFileModificationTime, &fileModificationTime, &blobURLString)) { |
261 | HTTPBody::Element element; |
262 | element.type = toHTTPBodyElementType(type); |
263 | if (gsize dataLength = g_variant_iter_n_children(dataIter)) { |
264 | element.data.reserveInitialCapacity(dataLength); |
265 | guchar dataValue; |
266 | while (g_variant_iter_next(dataIter, "y" , &dataValue)) |
267 | element.data.uncheckedAppend(dataValue); |
268 | } |
269 | element.filePath = String::fromUTF8(filePath); |
270 | element.fileStart = fileStart; |
271 | if (hasFileLength) |
272 | element.fileLength = fileLength; |
273 | if (hasFileModificationTime) |
274 | element.expectedFileModificationTime = WallTime::fromRawSeconds(fileModificationTime); |
275 | element.blobURLString = String::fromUTF8(blobURLString); |
276 | |
277 | httpBody.elements.uncheckedAppend(WTFMove(element)); |
278 | } |
279 | |
280 | return true; |
281 | } |
282 | |
283 | static inline void decodeFrameState(GVariant* frameStateVariant, FrameState& frameState) |
284 | { |
285 | const char* urlString; |
286 | const char* originalURLString; |
287 | const char* referrer; |
288 | const char* target; |
289 | GUniqueOutPtr<GVariantIter> documentStateIter; |
290 | GUniqueOutPtr<GVariantIter> stateObjectDataIter; |
291 | gint64 documentSequenceNumber; |
292 | gint64 itemSequenceNumber; |
293 | gint32 scrollPositionX, scrollPositionY; |
294 | gdouble pageScaleFactor; |
295 | GVariant* httpBodyVariant; |
296 | GUniqueOutPtr<GVariantIter> childrenIter; |
297 | g_variant_get(frameStateVariant, FRAME_STATE_FORMAT_STRING_V1, &urlString, &originalURLString, &referrer, &target, |
298 | &documentStateIter.outPtr(), &stateObjectDataIter.outPtr(), &documentSequenceNumber, &itemSequenceNumber, |
299 | &scrollPositionX, &scrollPositionY, &pageScaleFactor, &httpBodyVariant, &childrenIter.outPtr()); |
300 | frameState.urlString = String::fromUTF8(urlString); |
301 | frameState.originalURLString = String::fromUTF8(originalURLString); |
302 | // frameState.referrer must not be an empty string since we never want to |
303 | // send an empty Referer header. Bug #159606. |
304 | if (strlen(referrer)) |
305 | frameState.referrer = String::fromUTF8(referrer); |
306 | frameState.target = String::fromUTF8(target); |
307 | if (gsize documentStateLength = g_variant_iter_n_children(documentStateIter.get())) { |
308 | frameState.documentState.reserveInitialCapacity(documentStateLength); |
309 | const char* documentStateString; |
310 | while (g_variant_iter_next(documentStateIter.get(), "&s" , &documentStateString)) |
311 | frameState.documentState.uncheckedAppend(String::fromUTF8(documentStateString)); |
312 | } |
313 | if (stateObjectDataIter) { |
314 | Vector<uint8_t> stateObjectVector; |
315 | if (gsize stateObjectDataLength = g_variant_iter_n_children(stateObjectDataIter.get())) { |
316 | stateObjectVector.reserveInitialCapacity(stateObjectDataLength); |
317 | guchar stateObjectDataValue; |
318 | while (g_variant_iter_next(stateObjectDataIter.get(), "y" , &stateObjectDataValue)) |
319 | stateObjectVector.uncheckedAppend(stateObjectDataValue); |
320 | } |
321 | frameState.stateObjectData = WTFMove(stateObjectVector); |
322 | } |
323 | frameState.documentSequenceNumber = documentSequenceNumber; |
324 | frameState.itemSequenceNumber = itemSequenceNumber; |
325 | frameState.scrollPosition.setX(scrollPositionX); |
326 | frameState.scrollPosition.setY(scrollPositionY); |
327 | frameState.pageScaleFactor = pageScaleFactor; |
328 | HTTPBody httpBody; |
329 | if (decodeHTTPBody(httpBodyVariant, httpBody)) |
330 | frameState.httpBody = WTFMove(httpBody); |
331 | g_variant_unref(httpBodyVariant); |
332 | while (GRefPtr<GVariant> child = adoptGRef(g_variant_iter_next_value(childrenIter.get()))) { |
333 | FrameState childFrameState; |
334 | GRefPtr<GVariant> childVariant = adoptGRef(g_variant_get_variant(child.get())); |
335 | decodeFrameState(childVariant.get(), childFrameState); |
336 | frameState.children.append(WTFMove(childFrameState)); |
337 | } |
338 | } |
339 | |
340 | static inline void decodeBackForwardListItemStateV1(GVariantIter* backForwardListStateIter, BackForwardListState& backForwardListState) |
341 | { |
342 | guint64 identifier; |
343 | const char* title; |
344 | GVariant* frameStateVariant; |
345 | unsigned shouldOpenExternalURLsPolicy; |
346 | while (g_variant_iter_loop(backForwardListStateIter, BACK_FORWARD_LIST_ITEM_FORMAT_STRING_V1, &identifier, &title, &frameStateVariant, &shouldOpenExternalURLsPolicy)) { |
347 | BackForwardListItemState state; |
348 | state.pageState.title = String::fromUTF8(title); |
349 | decodeFrameState(frameStateVariant, state.pageState.mainFrameState); |
350 | state.pageState.shouldOpenExternalURLsPolicy = toWebCoreExternalURLsPolicy(shouldOpenExternalURLsPolicy); |
351 | backForwardListState.items.uncheckedAppend(WTFMove(state)); |
352 | } |
353 | } |
354 | |
355 | static inline void decodeBackForwardListItemState(GVariantIter* backForwardListStateIter, BackForwardListState& backForwardListState, guint16 version) |
356 | { |
357 | gsize backForwardListStateLength = g_variant_iter_n_children(backForwardListStateIter); |
358 | if (!backForwardListStateLength) |
359 | return; |
360 | |
361 | backForwardListState.items.reserveInitialCapacity(backForwardListStateLength); |
362 | if (version == 1) { |
363 | decodeBackForwardListItemStateV1(backForwardListStateIter, backForwardListState); |
364 | return; |
365 | } |
366 | |
367 | const char* title; |
368 | GVariant* frameStateVariant; |
369 | unsigned shouldOpenExternalURLsPolicy; |
370 | while (g_variant_iter_loop(backForwardListStateIter, BACK_FORWARD_LIST_ITEM_FORMAT_STRING_V2, &title, &frameStateVariant, &shouldOpenExternalURLsPolicy)) { |
371 | BackForwardListItemState state; |
372 | state.pageState.title = String::fromUTF8(title); |
373 | decodeFrameState(frameStateVariant, state.pageState.mainFrameState); |
374 | state.pageState.shouldOpenExternalURLsPolicy = toWebCoreExternalURLsPolicy(shouldOpenExternalURLsPolicy); |
375 | backForwardListState.items.uncheckedAppend(WTFMove(state)); |
376 | } |
377 | } |
378 | |
379 | static bool decodeSessionState(GBytes* data, SessionState& sessionState) |
380 | { |
381 | static const char* sessionStateTypeStringVersions[] = { |
382 | SESSION_STATE_TYPE_STRING_V2, |
383 | SESSION_STATE_TYPE_STRING_V1, |
384 | nullptr |
385 | }; |
386 | const char* sessionStateTypeString = nullptr; |
387 | GRefPtr<GVariant> variant; |
388 | for (unsigned i = 0; sessionStateTypeStringVersions[i]; ++i) { |
389 | sessionStateTypeString = sessionStateTypeStringVersions[i]; |
390 | variant = g_variant_new_from_bytes(G_VARIANT_TYPE(sessionStateTypeString), data, FALSE); |
391 | if (g_variant_is_normal_form(variant.get())) |
392 | break; |
393 | variant = nullptr; |
394 | } |
395 | if (!variant) |
396 | return false; |
397 | |
398 | guint16 version; |
399 | GUniqueOutPtr<GVariantIter> backForwardListStateIter; |
400 | gboolean hasCurrentIndex; |
401 | guint32 currentIndex; |
402 | g_variant_get(variant.get(), sessionStateTypeString, &version, &backForwardListStateIter.outPtr(), &hasCurrentIndex, ¤tIndex); |
403 | if (!version || version > g_sessionStateVersion) |
404 | return false; |
405 | |
406 | decodeBackForwardListItemState(backForwardListStateIter.get(), sessionState.backForwardListState, version); |
407 | |
408 | if (hasCurrentIndex) |
409 | sessionState.backForwardListState.currentIndex = std::min<uint32_t>(currentIndex, sessionState.backForwardListState.items.size() - 1); |
410 | return true; |
411 | } |
412 | |
413 | WebKitWebViewSessionState* webkitWebViewSessionStateCreate(SessionState&& sessionState) |
414 | { |
415 | WebKitWebViewSessionState* state = static_cast<WebKitWebViewSessionState*>(fastMalloc(sizeof(WebKitWebViewSessionState))); |
416 | new (state) WebKitWebViewSessionState(WTFMove(sessionState)); |
417 | return state; |
418 | } |
419 | |
420 | const SessionState& webkitWebViewSessionStateGetSessionState(WebKitWebViewSessionState* state) |
421 | { |
422 | return state->sessionState; |
423 | } |
424 | |
425 | /** |
426 | * webkit_web_view_session_state_new: |
427 | * @data: a #GBytes |
428 | * |
429 | * Creates a new #WebKitWebViewSessionState from serialized data. |
430 | * |
431 | * Returns: (transfer full): a new #WebKitWebViewSessionState, or %NULL if @data doesn't contain a |
432 | * valid serialized #WebKitWebViewSessionState. |
433 | * |
434 | * Since: 2.12 |
435 | */ |
436 | WebKitWebViewSessionState* webkit_web_view_session_state_new(GBytes* data) |
437 | { |
438 | g_return_val_if_fail(data, nullptr); |
439 | |
440 | SessionState sessionState; |
441 | if (!decodeSessionState(data, sessionState)) |
442 | return nullptr; |
443 | return webkitWebViewSessionStateCreate(WTFMove(sessionState)); |
444 | } |
445 | |
446 | /** |
447 | * webkit_web_view_session_state_ref: |
448 | * @state: a #WebKitWebViewSessionState |
449 | * |
450 | * Atomically increments the reference count of @state by one. This |
451 | * function is MT-safe and may be called from any thread. |
452 | * |
453 | * Returns: The passed in #WebKitWebViewSessionState |
454 | * |
455 | * Since: 2.12 |
456 | */ |
457 | WebKitWebViewSessionState* webkit_web_view_session_state_ref(WebKitWebViewSessionState* state) |
458 | { |
459 | g_return_val_if_fail(state, nullptr); |
460 | g_atomic_int_inc(&state->referenceCount); |
461 | return state; |
462 | } |
463 | |
464 | /** |
465 | * webkit_web_view_session_state_unref: |
466 | * @state: a #WebKitWebViewSessionState |
467 | * |
468 | * Atomically decrements the reference count of @state by one. If the |
469 | * reference count drops to 0, all memory allocated by the #WebKitWebViewSessionState is |
470 | * released. This function is MT-safe and may be called from any thread. |
471 | * |
472 | * Since: 2.12 |
473 | */ |
474 | void webkit_web_view_session_state_unref(WebKitWebViewSessionState* state) |
475 | { |
476 | g_return_if_fail(state); |
477 | if (g_atomic_int_dec_and_test(&state->referenceCount)) { |
478 | state->~WebKitWebViewSessionState(); |
479 | fastFree(state); |
480 | } |
481 | } |
482 | |
483 | /** |
484 | * webkit_web_view_session_state_serialize: |
485 | * @state: a #WebKitWebViewSessionState |
486 | * |
487 | * Serializes a #WebKitWebViewSessionState. |
488 | * |
489 | * Returns: (transfer full): a #GBytes containing the @state serialized. |
490 | * |
491 | * Since: 2.12 |
492 | */ |
493 | GBytes* webkit_web_view_session_state_serialize(WebKitWebViewSessionState* state) |
494 | { |
495 | g_return_val_if_fail(state, nullptr); |
496 | |
497 | return encodeSessionState(state->sessionState); |
498 | } |
499 | |