1/*
2 * Copyright (C) 2013 Apple Inc. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
7 * 1. Redistributions of source code must retain the above copyright
8 *    notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 *    notice, this list of conditions and the following disclaimer in the
11 *    documentation and/or other materials provided with the distribution.
12 *
13 * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
14 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
15 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
17 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
18 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
19 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
20 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
21 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
22 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
23 * THE POSSIBILITY OF SUCH DAMAGE.
24 */
25
26#include "config.h"
27#include "BlobRegistrationData.h"
28
29#if ENABLE(BLOB) && ENABLE(NETWORK_PROCESS)
30
31#include "ArgumentCoders.h"
32#include "DataReference.h"
33#include "WebCoreArgumentCoders.h"
34#include <WebCore/BlobData.h>
35
36using namespace WebCore;
37
38namespace WebKit {
39
40BlobRegistrationData::BlobRegistrationData()
41{
42}
43
44BlobRegistrationData::BlobRegistrationData(PassOwnPtr<BlobData> data)
45    : m_data(data)
46{
47    const BlobDataItemList& items = m_data->items();
48    size_t fileCount = 0;
49    for (size_t i = 0, count = items.size(); i < count; ++i) {
50        // File path can be empty when submitting a form file input without a file, see bug 111778.
51        if (items[i].type == BlobDataItem::File && !items[i].path.isEmpty())
52            ++fileCount;
53    }
54
55    m_sandboxExtensions.allocate(fileCount);
56    size_t extensionIndex = 0;
57    for (size_t i = 0, count = items.size(); i < count; ++i) {
58        const BlobDataItem& item = items[i];
59        if (item.type == BlobDataItem::File && !items[i].path.isEmpty())
60            SandboxExtension::createHandle(item.path, SandboxExtension::ReadOnly, m_sandboxExtensions[extensionIndex++]);
61    }
62}
63
64BlobRegistrationData::~BlobRegistrationData()
65{
66}
67
68PassOwnPtr<BlobData> BlobRegistrationData::releaseData() const
69{
70    return m_data.release();
71}
72
73void BlobRegistrationData::encode(CoreIPC::ArgumentEncoder& encoder) const
74{
75    encoder << m_data->contentType();
76    encoder << m_data->contentDisposition();
77
78    const BlobDataItemList& items = m_data->items();
79    encoder << static_cast<uint64_t>(items.size());
80    for (size_t i = 0, count = items.size(); i < count; ++i) {
81        const BlobDataItem& item = items[i];
82        encoder << static_cast<uint32_t>(item.type);
83        switch (item.type) {
84        case BlobDataItem::Data:
85            // There is no way to create a partial data item.
86            ASSERT(!item.offset);
87            ASSERT(item.length == BlobDataItem::toEndOfFile);
88            encoder << CoreIPC::DataReference(reinterpret_cast<const uint8_t*>(item.data->data()), item.data->length());
89            break;
90        case BlobDataItem::File:
91            encoder << item.offset;
92            encoder << item.length;
93            encoder << item.expectedModificationTime;
94            encoder << item.path;
95            break;
96        case BlobDataItem::Blob:
97            encoder << item.offset;
98            encoder << item.length;
99            encoder << item.url;
100            break;
101        }
102    }
103
104    encoder << m_sandboxExtensions;
105}
106
107bool BlobRegistrationData::decode(CoreIPC::ArgumentDecoder& decoder, BlobRegistrationData& result)
108{
109    ASSERT(!result.m_data);
110    result.m_data = BlobData::create();
111
112    String contentType;
113    if (!decoder.decode(contentType))
114        return false;
115    result.m_data->setContentType(contentType);
116
117    String contentDisposition;
118    if (!decoder.decode(contentDisposition))
119        return false;
120    result.m_data->setContentDisposition(contentDisposition);
121
122    uint64_t itemCount;
123    if (!decoder.decode(itemCount))
124        return false;
125
126    for (uint64_t i = 0; i < itemCount; ++i) {
127        uint32_t type;
128        if (!decoder.decode(type))
129            return false;
130        switch (type) {
131        case BlobDataItem::Data: {
132            CoreIPC::DataReference data;
133            if (!decoder.decode(data))
134                return false;
135            RefPtr<RawData> rawData = RawData::create();
136            rawData->mutableData()->append(data.data(), data.size());
137            result.m_data->appendData(rawData.release(), 0, BlobDataItem::toEndOfFile);
138            break;
139        }
140        case BlobDataItem::File: {
141            long long offset;
142            if (!decoder.decode(offset))
143                return false;
144            long long length;
145            if (!decoder.decode(length))
146                return false;
147            double expectedModificationTime;
148            if (!decoder.decode(expectedModificationTime))
149                return false;
150            String path;
151            if (!decoder.decode(path))
152                return false;
153            result.m_data->appendFile(path, offset, length, expectedModificationTime);
154            break;
155        }
156        case BlobDataItem::Blob: {
157            long long offset;
158            if (!decoder.decode(offset))
159                return false;
160            long long length;
161            if (!decoder.decode(length))
162                return false;
163            String url;
164            if (!decoder.decode(url))
165                return false;
166            result.m_data->appendBlob(KURL(KURL(), url), offset, length);
167            break;
168        }
169        default:
170            return false;
171        }
172    }
173
174    if (!decoder.decode(result.m_sandboxExtensions))
175        return false;
176
177    return true;
178}
179
180}
181
182#endif // ENABLE(BLOB) && ENABLE(NETWORK_PROCESS)
183