[WTF] Add makeUnique<T>, which ensures T is fast-allocated, makeUnique / makeUniqueWi...
[WebKit-https.git] / Source / WebCore / platform / network / curl / CurlFormDataStream.cpp
1 /*
2  * Copyright (C) 2008 Apple Inc.  All rights reserved.
3  * Copyright (C) 2006 Michael Emmel mike.emmel@gmail.com
4  * Copyright (C) 2007 Alp Toker <alp.toker@collabora.co.uk>
5  * Copyright (C) 2007 Holger Hans Peter Freyther
6  * Copyright (C) 2008 Collabora Ltd.
7  * Copyright (C) 2018 Sony Interactive Entertainment Inc.
8  * All rights reserved.
9  *
10  * Redistribution and use in source and binary forms, with or without
11  * modification, are permitted provided that the following conditions
12  * are met:
13  * 1. Redistributions of source code must retain the above copyright
14  *    notice, this list of conditions and the following disclaimer.
15  * 2. Redistributions in binary form must reproduce the above copyright
16  *    notice, this list of conditions and the following disclaimer in the
17  *    documentation and/or other materials provided with the distribution.
18  *
19  * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
20  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
23  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
24  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
25  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
26  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
27  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30  */
31
32 #include "config.h"
33 #include "CurlFormDataStream.h"
34
35 #if USE(CURL)
36
37 #include "BlobRegistry.h"
38 #include "CurlContext.h"
39 #include "Logging.h"
40 #include <wtf/MainThread.h>
41
42 namespace WebCore {
43
44 CurlFormDataStream::CurlFormDataStream(const FormData* formData, PAL::SessionID sessionID)
45     : m_sessionID(sessionID)
46 {
47     ASSERT(isMainThread());
48
49     if (!formData || formData->isEmpty())
50         return;
51
52     m_formData = formData->isolatedCopy();
53
54     // Resolve the blob elements so the formData can correctly report it's size.
55     m_formData = m_formData->resolveBlobReferences(blobRegistry().blobRegistryImpl());
56 }
57
58 CurlFormDataStream::~CurlFormDataStream()
59 {
60
61 }
62
63 void CurlFormDataStream::clean()
64 {
65     if (m_postData)
66         m_postData = nullptr;
67
68     if (m_fileHandle != FileSystem::invalidPlatformFileHandle) {
69         FileSystem::closeFile(m_fileHandle);
70         m_fileHandle = FileSystem::invalidPlatformFileHandle;
71     }
72 }
73
74 const Vector<char>* CurlFormDataStream::getPostData()
75 {
76     if (!m_formData)
77         return nullptr;
78
79     if (!m_postData)
80         m_postData = makeUnique<Vector<char>>(m_formData->flatten());
81
82     return m_postData.get();
83 }
84
85 bool CurlFormDataStream::shouldUseChunkTransfer()
86 {
87     computeContentLength();
88
89     return m_shouldUseChunkTransfer;
90 }
91
92 unsigned long long CurlFormDataStream::totalSize()
93 {
94     computeContentLength();
95
96     return m_totalSize;
97 }
98
99 void CurlFormDataStream::computeContentLength()
100 {
101     if (!m_formData || m_isContentLengthUpdated)
102         return;
103
104     m_isContentLengthUpdated = true;
105
106     for (const auto& element : m_formData->elements())
107         m_totalSize += element.lengthInBytes(m_sessionID);
108 }
109
110 Optional<size_t> CurlFormDataStream::read(char* buffer, size_t size)
111 {
112     if (!m_formData)
113         return WTF::nullopt;
114
115     const auto totalElementSize = m_formData->elements().size();
116     if (m_elementPosition >= totalElementSize)
117         return 0;
118
119     size_t totalReadBytes = 0;
120
121     while ((m_elementPosition < totalElementSize) && (totalReadBytes < size)) {
122         const auto& element = m_formData->elements().at(m_elementPosition);
123
124         size_t bufferSize = size - totalReadBytes;
125         char* bufferPosition = buffer + totalReadBytes;
126
127         Optional<size_t> readBytes = switchOn(element.data,
128             [&] (const Vector<char>& bytes) {
129                 return readFromData(bytes, bufferPosition, bufferSize);
130             }, [&] (const FormDataElement::EncodedFileData& fileData) {
131                 return readFromFile(fileData, bufferPosition, bufferSize);
132             }, [] (const FormDataElement::EncodedBlobData& blobData) {
133                 ASSERT_NOT_REACHED();
134                 return WTF::nullopt;
135             }
136         );
137
138         if (!readBytes)
139             return WTF::nullopt;
140
141         totalReadBytes += *readBytes;
142     }
143
144     m_totalReadSize += totalReadBytes;
145
146     return totalReadBytes;
147 }
148
149 Optional<size_t> CurlFormDataStream::readFromFile(const FormDataElement::EncodedFileData& fileData, char* buffer, size_t size)
150 {
151     if (m_fileHandle == FileSystem::invalidPlatformFileHandle)
152         m_fileHandle = FileSystem::openFile(fileData.filename, FileSystem::FileOpenMode::Read);
153
154     if (!FileSystem::isHandleValid(m_fileHandle)) {
155         LOG(Network, "Curl - Failed while trying to open %s for upload\n", fileData.filename.utf8().data());
156         m_fileHandle = FileSystem::invalidPlatformFileHandle;
157         return WTF::nullopt;
158     }
159
160     auto readBytes = FileSystem::readFromFile(m_fileHandle, buffer, size);
161     if (readBytes < 0) {
162         LOG(Network, "Curl - Failed while trying to read %s for upload\n", fileData.filename.utf8().data());
163         FileSystem::closeFile(m_fileHandle);
164         m_fileHandle = FileSystem::invalidPlatformFileHandle;
165         return WTF::nullopt;
166     }
167
168     if (!readBytes) {
169         FileSystem::closeFile(m_fileHandle);
170         m_fileHandle = FileSystem::invalidPlatformFileHandle;
171         m_elementPosition++;
172     }
173
174     return readBytes;
175 }
176
177 Optional<size_t> CurlFormDataStream::readFromData(const Vector<char>& data, char* buffer, size_t size)
178 {
179     size_t elementSize = data.size() - m_dataOffset;
180     const char* elementBuffer = data.data() + m_dataOffset;
181
182     size_t readBytes = elementSize > size ? size : elementSize;
183     memcpy(buffer, elementBuffer, readBytes);
184
185     if (elementSize > readBytes)
186         m_dataOffset += readBytes;
187     else {
188         m_dataOffset = 0;
189         m_elementPosition++;
190     }
191
192     return readBytes;
193 }
194
195 } // namespace WebCore
196
197 #endif