~ubuntu-branches/ubuntu/raring/qtwebkit-source/raring-proposed

« back to all changes in this revision

Viewing changes to Source/WebCore/platform/network/FormData.cpp

  • Committer: Package Import Robot
  • Author(s): Jonathan Riddell
  • Date: 2013-02-18 14:24:18 UTC
  • Revision ID: package-import@ubuntu.com-20130218142418-eon0jmjg3nj438uy
Tags: upstream-2.3
ImportĀ upstreamĀ versionĀ 2.3

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * Copyright (C) 2004, 2006, 2008, 2011 Apple Inc. All rights reserved.
 
3
 * Copyright (C) 2009 Google Inc. All rights reserved.
 
4
 * Copyright (C) 2012 Digia Plc. and/or its subsidiary(-ies)
 
5
 *
 
6
 * This library is free software; you can redistribute it and/or
 
7
 * modify it under the terms of the GNU Library General Public
 
8
 * License as published by the Free Software Foundation; either
 
9
 * version 2 of the License, or (at your option) any later version.
 
10
 *
 
11
 * This library is distributed in the hope that it will be useful,
 
12
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 
13
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
 
14
 * Library General Public License for more details.
 
15
 *
 
16
 * You should have received a copy of the GNU Library General Public License
 
17
 * along with this library; see the file COPYING.LIB. If not, write to
 
18
 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
 
19
 * Boston, MA 02110-1301, USA.
 
20
 */
 
21
 
 
22
#include "config.h"
 
23
 
 
24
#include "FormData.h"
 
25
 
 
26
#include "BlobData.h"
 
27
#include "BlobRegistryImpl.h"
 
28
#include "BlobURL.h"
 
29
#include "Chrome.h"
 
30
#include "ChromeClient.h"
 
31
#include "Document.h"
 
32
#include "File.h"
 
33
#include "FileSystem.h"
 
34
#include "FormDataBuilder.h"
 
35
#include "FormDataList.h"
 
36
#include "MIMETypeRegistry.h"
 
37
#include "Page.h"
 
38
#include "PlatformMemoryInstrumentation.h"
 
39
#include "TextEncoding.h"
 
40
#include <wtf/Decoder.h>
 
41
#include <wtf/Encoder.h>
 
42
#include <wtf/MemoryInstrumentationVector.h>
 
43
 
 
44
namespace WebCore {
 
45
 
 
46
inline FormData::FormData()
 
47
    : m_identifier(0)
 
48
    , m_hasGeneratedFiles(false)
 
49
    , m_alwaysStream(false)
 
50
    , m_containsPasswordData(false)
 
51
{
 
52
}
 
53
 
 
54
inline FormData::FormData(const FormData& data)
 
55
    : RefCounted<FormData>()
 
56
    , m_elements(data.m_elements)
 
57
    , m_identifier(data.m_identifier)
 
58
    , m_hasGeneratedFiles(false)
 
59
    , m_alwaysStream(false)
 
60
    , m_containsPasswordData(data.m_containsPasswordData)
 
61
{
 
62
    // We shouldn't be copying FormData that hasn't already removed its generated files
 
63
    // but just in case, make sure the new FormData is ready to generate its own files.
 
64
    if (data.m_hasGeneratedFiles) {
 
65
        size_t n = m_elements.size();
 
66
        for (size_t i = 0; i < n; ++i) {
 
67
            FormDataElement& e = m_elements[i];
 
68
            if (e.m_type == FormDataElement::encodedFile)
 
69
                e.m_generatedFilename = String();
 
70
        }
 
71
    }
 
72
}
 
73
 
 
74
FormData::~FormData()
 
75
{
 
76
    // This cleanup should've happened when the form submission finished.
 
77
    // Just in case, let's assert, and do the cleanup anyway in release builds.
 
78
    ASSERT(!m_hasGeneratedFiles);
 
79
    removeGeneratedFilesIfNeeded();
 
80
}
 
81
 
 
82
PassRefPtr<FormData> FormData::create()
 
83
{
 
84
    return adoptRef(new FormData);
 
85
}
 
86
 
 
87
PassRefPtr<FormData> FormData::create(const void* data, size_t size)
 
88
{
 
89
    RefPtr<FormData> result = create();
 
90
    result->appendData(data, size);
 
91
    return result.release();
 
92
}
 
93
 
 
94
PassRefPtr<FormData> FormData::create(const CString& string)
 
95
{
 
96
    RefPtr<FormData> result = create();
 
97
    result->appendData(string.data(), string.length());
 
98
    return result.release();
 
99
}
 
100
 
 
101
PassRefPtr<FormData> FormData::create(const Vector<char>& vector)
 
102
{
 
103
    RefPtr<FormData> result = create();
 
104
    result->appendData(vector.data(), vector.size());
 
105
    return result.release();
 
106
}
 
107
 
 
108
PassRefPtr<FormData> FormData::create(const FormDataList& list, const TextEncoding& encoding, EncodingType encodingType)
 
109
{
 
110
    RefPtr<FormData> result = create();
 
111
    result->appendKeyValuePairItems(list, encoding, false, 0, encodingType);
 
112
    return result.release();
 
113
}
 
114
 
 
115
PassRefPtr<FormData> FormData::createMultiPart(const FormDataList& list, const TextEncoding& encoding, Document* document)
 
116
{
 
117
    RefPtr<FormData> result = create();
 
118
    result->appendKeyValuePairItems(list, encoding, true, document);
 
119
    return result.release();
 
120
}
 
121
 
 
122
PassRefPtr<FormData> FormData::copy() const
 
123
{
 
124
    return adoptRef(new FormData(*this));
 
125
}
 
126
 
 
127
PassRefPtr<FormData> FormData::deepCopy() const
 
128
{
 
129
    RefPtr<FormData> formData(create());
 
130
 
 
131
    formData->m_alwaysStream = m_alwaysStream;
 
132
 
 
133
    size_t n = m_elements.size();
 
134
    formData->m_elements.reserveInitialCapacity(n);
 
135
    for (size_t i = 0; i < n; ++i) {
 
136
        const FormDataElement& e = m_elements[i];
 
137
        switch (e.m_type) {
 
138
        case FormDataElement::data:
 
139
            formData->m_elements.append(FormDataElement(e.m_data));
 
140
            break;
 
141
        case FormDataElement::encodedFile:
 
142
#if ENABLE(BLOB)
 
143
            formData->m_elements.append(FormDataElement(e.m_filename, e.m_fileStart, e.m_fileLength, e.m_expectedFileModificationTime, e.m_shouldGenerateFile));
 
144
#else
 
145
            formData->m_elements.append(FormDataElement(e.m_filename, e.m_shouldGenerateFile));
 
146
#endif
 
147
            break;
 
148
#if ENABLE(BLOB)
 
149
        case FormDataElement::encodedBlob:
 
150
            formData->m_elements.append(FormDataElement(e.m_url));
 
151
            break;
 
152
#endif
 
153
#if ENABLE(FILE_SYSTEM)
 
154
        case FormDataElement::encodedURL:
 
155
            formData->m_elements.append(FormDataElement(e.m_url, e.m_fileStart, e.m_fileLength, e.m_expectedFileModificationTime));
 
156
            break;
 
157
#endif
 
158
        }
 
159
    }
 
160
    return formData.release();
 
161
}
 
162
 
 
163
void FormData::appendData(const void* data, size_t size)
 
164
{
 
165
    if (m_elements.isEmpty() || m_elements.last().m_type != FormDataElement::data)
 
166
        m_elements.append(FormDataElement());
 
167
    FormDataElement& e = m_elements.last();
 
168
    size_t oldSize = e.m_data.size();
 
169
    e.m_data.grow(oldSize + size);
 
170
    memcpy(e.m_data.data() + oldSize, data, size);
 
171
}
 
172
 
 
173
void FormData::appendFile(const String& filename, bool shouldGenerateFile)
 
174
{
 
175
#if ENABLE(BLOB)
 
176
    m_elements.append(FormDataElement(filename, 0, BlobDataItem::toEndOfFile, invalidFileTime(), shouldGenerateFile));
 
177
#else
 
178
    m_elements.append(FormDataElement(filename, shouldGenerateFile));
 
179
#endif
 
180
}
 
181
 
 
182
#if ENABLE(BLOB)
 
183
void FormData::appendFileRange(const String& filename, long long start, long long length, double expectedModificationTime, bool shouldGenerateFile)
 
184
{
 
185
    m_elements.append(FormDataElement(filename, start, length, expectedModificationTime, shouldGenerateFile));
 
186
}
 
187
 
 
188
void FormData::appendBlob(const KURL& blobURL)
 
189
{
 
190
    m_elements.append(FormDataElement(blobURL));
 
191
}
 
192
#endif
 
193
#if ENABLE(FILE_SYSTEM)
 
194
void FormData::appendURL(const KURL& url)
 
195
{
 
196
    m_elements.append(FormDataElement(url, 0, BlobDataItem::toEndOfFile, invalidFileTime()));
 
197
}
 
198
 
 
199
void FormData::appendURLRange(const KURL& url, long long start, long long length, double expectedModificationTime)
 
200
{
 
201
    m_elements.append(FormDataElement(url, start, length, expectedModificationTime));
 
202
}
 
203
#endif
 
204
 
 
205
void FormData::appendKeyValuePairItems(const FormDataList& list, const TextEncoding& encoding, bool isMultiPartForm, Document* document, EncodingType encodingType)
 
206
{
 
207
    if (isMultiPartForm)
 
208
        m_boundary = FormDataBuilder::generateUniqueBoundaryString();
 
209
 
 
210
    Vector<char> encodedData;
 
211
 
 
212
    const Vector<FormDataList::Item>& items = list.items();
 
213
    size_t formDataListSize = items.size();
 
214
    ASSERT(!(formDataListSize % 2));
 
215
    for (size_t i = 0; i < formDataListSize; i += 2) {
 
216
        const FormDataList::Item& key = items[i];
 
217
        const FormDataList::Item& value = items[i + 1];
 
218
        if (isMultiPartForm) {
 
219
            Vector<char> header;
 
220
            FormDataBuilder::beginMultiPartHeader(header, m_boundary.data(), key.data());
 
221
 
 
222
            bool shouldGenerateFile = false;
 
223
 
 
224
            // If the current type is blob, then we also need to include the filename
 
225
            if (value.blob()) {
 
226
                String name;
 
227
                if (value.blob()->isFile()) {
 
228
                    File* file = toFile(value.blob());
 
229
                    // For file blob, use the filename (or relative path if it is present) as the name.
 
230
#if ENABLE(DIRECTORY_UPLOAD)                
 
231
                    name = file->webkitRelativePath().isEmpty() ? file->name() : file->webkitRelativePath();
 
232
#else
 
233
                    name = file->name();
 
234
#endif
 
235
                    // Let the application specify a filename if it's going to generate a replacement file for the upload.
 
236
                    const String& path = file->path();
 
237
                    if (!path.isEmpty()) {
 
238
                        if (Page* page = document->page()) {
 
239
                            String generatedFileName;
 
240
                            shouldGenerateFile = page->chrome()->client()->shouldReplaceWithGeneratedFileForUpload(path, generatedFileName);
 
241
                            if (shouldGenerateFile)
 
242
                                name = generatedFileName;
 
243
                        }
 
244
                    }
 
245
                } else {
 
246
                    // For non-file blob, use the filename if it is passed in FormData.append().
 
247
                    if (!value.filename().isEmpty())
 
248
                        name = value.filename();
 
249
                    else
 
250
                        name = "blob";
 
251
                }
 
252
 
 
253
                // We have to include the filename=".." part in the header, even if the filename is empty
 
254
                FormDataBuilder::addFilenameToMultiPartHeader(header, encoding, name);
 
255
 
 
256
                // Add the content type if available, or "application/octet-stream" otherwise (RFC 1867).
 
257
                String contentType;
 
258
                if (value.blob()->type().isEmpty())
 
259
                    contentType = "application/octet-stream";
 
260
                else
 
261
                    contentType = value.blob()->type();
 
262
                FormDataBuilder::addContentTypeToMultiPartHeader(header, contentType.latin1());
 
263
            }
 
264
 
 
265
            FormDataBuilder::finishMultiPartHeader(header);
 
266
 
 
267
            // Append body
 
268
            appendData(header.data(), header.size());
 
269
            if (value.blob()) {
 
270
                if (value.blob()->isFile()) {
 
271
                    File* file = toFile(value.blob());
 
272
                    // Do not add the file if the path is empty.
 
273
                    if (!file->path().isEmpty())
 
274
                        appendFile(file->path(), shouldGenerateFile);
 
275
#if ENABLE(FILE_SYSTEM)
 
276
                    if (!file->fileSystemURL().isEmpty())
 
277
                        appendURL(file->fileSystemURL());
 
278
#endif
 
279
                }
 
280
#if ENABLE(BLOB)
 
281
                else
 
282
                    appendBlob(value.blob()->url());
 
283
#endif
 
284
            } else
 
285
                appendData(value.data().data(), value.data().length());
 
286
            appendData("\r\n", 2);
 
287
        } else {
 
288
            // Omit the name "isindex" if it's the first form data element.
 
289
            // FIXME: Why is this a good rule? Is this obsolete now?
 
290
            if (encodedData.isEmpty() && key.data() == "isindex")
 
291
                FormDataBuilder::encodeStringAsFormData(encodedData, value.data());
 
292
            else
 
293
                FormDataBuilder::addKeyValuePairAsFormData(encodedData, key.data(), value.data(), encodingType);
 
294
        }
 
295
    }
 
296
 
 
297
    if (isMultiPartForm)
 
298
        FormDataBuilder::addBoundaryToMultiPartHeader(encodedData, m_boundary.data(), true);
 
299
 
 
300
    appendData(encodedData.data(), encodedData.size());
 
301
}
 
302
 
 
303
void FormData::flatten(Vector<char>& data) const
 
304
{
 
305
    // Concatenate all the byte arrays, but omit any files.
 
306
    data.clear();
 
307
    size_t n = m_elements.size();
 
308
    for (size_t i = 0; i < n; ++i) {
 
309
        const FormDataElement& e = m_elements[i];
 
310
        if (e.m_type == FormDataElement::data)
 
311
            data.append(e.m_data.data(), static_cast<size_t>(e.m_data.size()));
 
312
    }
 
313
}
 
314
 
 
315
String FormData::flattenToString() const
 
316
{
 
317
    Vector<char> bytes;
 
318
    flatten(bytes);
 
319
    return Latin1Encoding().decode(reinterpret_cast<const char*>(bytes.data()), bytes.size());
 
320
}
 
321
 
 
322
#if ENABLE(BLOB)
 
323
static void appendBlobResolved(FormData* formData, const KURL& url)
 
324
{
 
325
    RefPtr<BlobStorageData> blobData = static_cast<BlobRegistryImpl&>(blobRegistry()).getBlobDataFromURL(KURL(ParsedURLString, url));
 
326
    if (!blobData)
 
327
        return;
 
328
 
 
329
    BlobDataItemList::const_iterator it = blobData->items().begin();
 
330
    const BlobDataItemList::const_iterator itend = blobData->items().end();
 
331
    for (; it != itend; ++it) {
 
332
        const BlobDataItem& blobItem = *it;
 
333
        if (blobItem.type == BlobDataItem::Data)
 
334
            formData->appendData(blobItem.data->data() + static_cast<int>(blobItem.offset), static_cast<int>(blobItem.length));
 
335
        else if (blobItem.type == BlobDataItem::File)
 
336
            formData->appendFileRange(blobItem.path, blobItem.offset, blobItem.length, blobItem.expectedModificationTime);
 
337
        else if (blobItem.type == BlobDataItem::Blob)
 
338
            appendBlobResolved(formData, blobItem.url);
 
339
        else
 
340
            ASSERT_NOT_REACHED();
 
341
    }
 
342
}
 
343
 
 
344
PassRefPtr<FormData> FormData::resolveBlobReferences()
 
345
{
 
346
    // First check if any blobs needs to be resolved, or we can take the fast path.
 
347
    bool hasBlob = false;
 
348
    Vector<FormDataElement>::const_iterator it = elements().begin();
 
349
    const Vector<FormDataElement>::const_iterator itend = elements().end();
 
350
    for (; it != itend; ++it) {
 
351
        if (it->m_type == FormDataElement::encodedBlob) {
 
352
            hasBlob = true;
 
353
            break;
 
354
        }
 
355
    }
 
356
 
 
357
    if (!hasBlob)
 
358
        return this;
 
359
 
 
360
    // Create a copy to append the result into.
 
361
    RefPtr<FormData> newFormData = FormData::create();
 
362
    newFormData->setAlwaysStream(alwaysStream());
 
363
    newFormData->setIdentifier(identifier());
 
364
    it = elements().begin();
 
365
    for (; it != itend; ++it) {
 
366
        const FormDataElement& element = *it;
 
367
        if (element.m_type == FormDataElement::data)
 
368
            newFormData->appendData(element.m_data.data(), element.m_data.size());
 
369
        else if (element.m_type == FormDataElement::encodedFile)
 
370
            newFormData->appendFileRange(element.m_filename, element.m_fileStart, element.m_fileLength, element.m_expectedFileModificationTime, element.m_shouldGenerateFile);
 
371
        else if (element.m_type == FormDataElement::encodedBlob)
 
372
            appendBlobResolved(newFormData.get(), element.m_url);
 
373
        else
 
374
            ASSERT_NOT_REACHED();
 
375
    }
 
376
    return newFormData.release();
 
377
}
 
378
#endif
 
379
 
 
380
void FormData::generateFiles(Document* document)
 
381
{
 
382
    ASSERT(!m_hasGeneratedFiles);
 
383
 
 
384
    if (m_hasGeneratedFiles)
 
385
        return;
 
386
 
 
387
    Page* page = document->page();
 
388
    if (!page)
 
389
        return;
 
390
    ChromeClient* client = page->chrome()->client();
 
391
 
 
392
    size_t n = m_elements.size();
 
393
    for (size_t i = 0; i < n; ++i) {
 
394
        FormDataElement& e = m_elements[i];
 
395
        if (e.m_type == FormDataElement::encodedFile && e.m_shouldGenerateFile) {
 
396
            e.m_generatedFilename = client->generateReplacementFile(e.m_filename);
 
397
            m_hasGeneratedFiles = true;
 
398
        }
 
399
    }
 
400
}
 
401
 
 
402
void FormData::removeGeneratedFilesIfNeeded()
 
403
{
 
404
    if (!m_hasGeneratedFiles)
 
405
        return;
 
406
 
 
407
    size_t n = m_elements.size();
 
408
    for (size_t i = 0; i < n; ++i) {
 
409
        FormDataElement& e = m_elements[i];
 
410
        if (e.m_type == FormDataElement::encodedFile && !e.m_generatedFilename.isEmpty()) {
 
411
            ASSERT(e.m_shouldGenerateFile);
 
412
            String directory = directoryName(e.m_generatedFilename);
 
413
            deleteFile(e.m_generatedFilename);
 
414
            deleteEmptyDirectory(directory);
 
415
            e.m_generatedFilename = String();
 
416
        }
 
417
    }
 
418
    m_hasGeneratedFiles = false;
 
419
}
 
420
 
 
421
void FormData::reportMemoryUsage(MemoryObjectInfo* memoryObjectInfo) const
 
422
{
 
423
    MemoryClassInfo info(memoryObjectInfo, this, PlatformMemoryTypes::Loader);
 
424
    info.addMember(m_boundary);
 
425
}
 
426
 
 
427
static void encode(Encoder& encoder, const FormDataElement& element)
 
428
{
 
429
    encoder.encodeUInt32(element.m_type);
 
430
 
 
431
    switch (element.m_type) {
 
432
    case FormDataElement::data:
 
433
        encoder.encodeBytes(reinterpret_cast<const uint8_t*>(element.m_data.data()), element.m_data.size());
 
434
        return;
 
435
 
 
436
    case FormDataElement::encodedFile:
 
437
        encoder.encodeString(element.m_filename);
 
438
        encoder.encodeBool(element.m_shouldGenerateFile);
 
439
#if ENABLE(BLOB)
 
440
        encoder.encodeInt64(element.m_fileStart);
 
441
        encoder.encodeInt64(element.m_fileLength);
 
442
        encoder.encodeDouble(element.m_expectedFileModificationTime);
 
443
#else
 
444
        encoder.encodeInt64(0);
 
445
        encoder.encodeInt64(0);
 
446
        encoder.encodeDouble(invalidFileTime());
 
447
#endif
 
448
        return;
 
449
 
 
450
#if ENABLE(BLOB)
 
451
    case FormDataElement::encodedBlob:
 
452
        encoder.encodeString(element.m_url.string());
 
453
        return;
 
454
#endif
 
455
 
 
456
#if ENABLE(FILE_SYSTEM)
 
457
    case FormDataElement::encodedURL:
 
458
        encoder.encodeString(element.m_url.string());
 
459
        encoder.encodeInt64(element.m_fileStart);
 
460
        encoder.encodeInt64(element.m_fileLength);
 
461
        encoder.encodeDouble(element.m_expectedFileModificationTime);
 
462
        return;
 
463
#endif
 
464
    }
 
465
 
 
466
    ASSERT_NOT_REACHED();
 
467
}
 
468
 
 
469
static bool decode(Decoder& decoder, FormDataElement& element)
 
470
{
 
471
    uint32_t type;
 
472
    if (!decoder.decodeUInt32(type))
 
473
        return false;
 
474
 
 
475
    switch (type) {
 
476
    case FormDataElement::data: {
 
477
        element.m_type = FormDataElement::data;
 
478
        Vector<uint8_t> data;
 
479
        if (!decoder.decodeBytes(data))
 
480
            return false;
 
481
        size_t size = data.size();
 
482
        element.m_data.resize(size);
 
483
        memcpy(element.m_data.data(), data.data(), size);
 
484
        return true;
 
485
    }
 
486
 
 
487
    case FormDataElement::encodedFile:
 
488
#if ENABLE(FILE_SYSTEM)
 
489
    case FormDataElement::encodedURL:
 
490
#endif
 
491
    {
 
492
        element.m_type = static_cast<FormDataElement::Type>(type);
 
493
        String filenameOrURL;
 
494
        if (!decoder.decodeString(filenameOrURL))
 
495
            return false;
 
496
        if (type == FormDataElement::encodedFile && !decoder.decodeBool(element.m_shouldGenerateFile))
 
497
            return false;
 
498
        int64_t fileStart;
 
499
        if (!decoder.decodeInt64(fileStart))
 
500
            return false;
 
501
        if (fileStart < 0)
 
502
            return false;
 
503
        int64_t fileLength;
 
504
        if (!decoder.decodeInt64(fileLength))
 
505
            return false;
 
506
        if (fileLength < fileStart)
 
507
            return false;
 
508
        double expectedFileModificationTime;
 
509
        if (!decoder.decodeDouble(expectedFileModificationTime))
 
510
            return false;
 
511
 
 
512
#if ENABLE(FILE_SYSTEM)
 
513
        if (type == FormDataElement::encodedURL)
 
514
            element.m_url = KURL(KURL(), filenameOrURL);
 
515
        else
 
516
#endif
 
517
        element.m_filename = filenameOrURL;
 
518
 
 
519
#if ENABLE(BLOB)
 
520
        element.m_fileStart = fileStart;
 
521
        element.m_fileLength = fileLength;
 
522
        element.m_expectedFileModificationTime = expectedFileModificationTime;
 
523
#endif
 
524
        return true;
 
525
    }
 
526
 
 
527
#if ENABLE(BLOB)
 
528
    case FormDataElement::encodedBlob:
 
529
        element.m_type = FormDataElement::encodedBlob;
 
530
        String blobURLString;
 
531
        if (!decoder.decodeString(blobURLString))
 
532
            return false;
 
533
        element.m_url = KURL(KURL(), blobURLString);
 
534
        return true;
 
535
#endif
 
536
 
 
537
    }
 
538
 
 
539
    return false;
 
540
}
 
541
 
 
542
void FormData::encodeForBackForward(Encoder& encoder) const
 
543
{
 
544
    encoder.encodeBool(m_alwaysStream);
 
545
 
 
546
    encoder.encodeBytes(reinterpret_cast<const uint8_t*>(m_boundary.data()), m_boundary.size());
 
547
 
 
548
    size_t size = m_elements.size();
 
549
    encoder.encodeUInt64(size);
 
550
    for (size_t i = 0; i < size; ++i)
 
551
        encode(encoder, m_elements[i]);
 
552
 
 
553
    encoder.encodeBool(m_hasGeneratedFiles);
 
554
 
 
555
    encoder.encodeInt64(m_identifier);
 
556
}
 
557
 
 
558
PassRefPtr<FormData> FormData::decodeForBackForward(Decoder& decoder)
 
559
{
 
560
    RefPtr<FormData> data = FormData::create();
 
561
 
 
562
    if (!decoder.decodeBool(data->m_alwaysStream))
 
563
        return 0;
 
564
 
 
565
    Vector<uint8_t> boundary;
 
566
    if (!decoder.decodeBytes(boundary))
 
567
        return 0;
 
568
    size_t size = boundary.size();
 
569
    data->m_boundary.resize(size);
 
570
    memcpy(data->m_boundary.data(), boundary.data(), size);
 
571
 
 
572
    uint64_t elementsSize;
 
573
    if (!decoder.decodeUInt64(elementsSize))
 
574
        return 0;
 
575
    for (size_t i = 0; i < elementsSize; ++i) {
 
576
        FormDataElement element;
 
577
        if (!decode(decoder, element))
 
578
            return 0;
 
579
        data->m_elements.append(element);
 
580
    }
 
581
 
 
582
    if (!decoder.decodeBool(data->m_hasGeneratedFiles))
 
583
        return 0;
 
584
 
 
585
    if (!decoder.decodeInt64(data->m_identifier))
 
586
        return 0;
 
587
 
 
588
    return data.release();
 
589
}
 
590
 
 
591
} // namespace WebCore