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.
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
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.
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.
33 #include "CurlFormDataStream.h"
37 #include "CurlContext.h"
39 #include <wtf/MainThread.h>
43 CurlFormDataStream::CurlFormDataStream(const FormData* formData)
45 ASSERT(isMainThread());
47 if (!formData || formData->isEmpty())
50 m_formData = formData->isolatedCopy();
52 // Resolve the blob elements so the formData can correctly report it's size.
53 m_formData = m_formData->resolveBlobReferences();
56 CurlFormDataStream::~CurlFormDataStream()
61 void CurlFormDataStream::clean()
66 if (m_fileHandle != FileSystem::invalidPlatformFileHandle) {
67 FileSystem::closeFile(m_fileHandle);
68 m_fileHandle = FileSystem::invalidPlatformFileHandle;
72 const Vector<char>* CurlFormDataStream::getPostData()
78 m_postData = std::make_unique<Vector<char>>(m_formData->flatten());
80 return m_postData.get();
83 bool CurlFormDataStream::shouldUseChunkTransfer()
85 computeContentLength();
87 return m_shouldUseChunkTransfer;
90 unsigned long long CurlFormDataStream::totalSize()
92 computeContentLength();
97 void CurlFormDataStream::computeContentLength()
99 static auto maxCurlOffT = CurlHandle::maxCurlOffT();
101 if (!m_formData || m_isContentLengthUpdated)
104 m_isContentLengthUpdated = true;
106 for (const auto& element : m_formData->elements()) {
107 if (element.m_type == FormDataElement::Type::EncodedFile) {
109 if (FileSystem::getFileSize(element.m_filename, fileSize)) {
110 if (fileSize > maxCurlOffT) {
111 // File size is too big for specifying it to curl
112 m_shouldUseChunkTransfer = true;
115 m_totalSize += fileSize;
117 m_shouldUseChunkTransfer = true;
119 m_totalSize += element.m_data.size();
123 std::optional<size_t> CurlFormDataStream::read(char* buffer, size_t size)
128 const auto totalElementSize = m_formData->elements().size();
129 if (m_elementPosition >= totalElementSize)
132 size_t totalReadBytes = 0;
134 while ((m_elementPosition < totalElementSize) && (totalReadBytes < size)) {
135 const auto& element = m_formData->elements().at(m_elementPosition);
137 std::optional<size_t> readBytes;
138 size_t bufferSize = size - totalReadBytes;
139 char* bufferPosition = buffer + totalReadBytes;
141 if (element.m_type == FormDataElement::Type::EncodedFile)
142 readBytes = readFromFile(element, bufferPosition, bufferSize);
144 readBytes = readFromData(element, bufferPosition, bufferSize);
149 totalReadBytes += *readBytes;
152 m_totalReadSize += totalReadBytes;
154 return totalReadBytes;
157 std::optional<size_t> CurlFormDataStream::readFromFile(const FormDataElement& element, char* buffer, size_t size)
159 if (m_fileHandle == FileSystem::invalidPlatformFileHandle)
160 m_fileHandle = FileSystem::openFile(element.m_filename, FileSystem::FileOpenMode::Read);
162 if (!FileSystem::isHandleValid(m_fileHandle)) {
163 LOG(Network, "Curl - Failed while trying to open %s for upload\n", element.m_filename.utf8().data());
164 m_fileHandle = FileSystem::invalidPlatformFileHandle;
168 auto readBytes = FileSystem::readFromFile(m_fileHandle, buffer, size);
170 LOG(Network, "Curl - Failed while trying to read %s for upload\n", element.m_filename.utf8().data());
171 FileSystem::closeFile(m_fileHandle);
172 m_fileHandle = FileSystem::invalidPlatformFileHandle;
177 FileSystem::closeFile(m_fileHandle);
178 m_fileHandle = FileSystem::invalidPlatformFileHandle;
185 std::optional<size_t> CurlFormDataStream::readFromData(const FormDataElement& element, char* buffer, size_t size)
187 size_t elementSize = element.m_data.size() - m_dataOffset;
188 const char* elementBuffer = element.m_data.data() + m_dataOffset;
190 size_t readBytes = elementSize > size ? size : elementSize;
191 memcpy(buffer, elementBuffer, readBytes);
193 if (elementSize > readBytes)
194 m_dataOffset += readBytes;
203 } // namespace WebCore