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 #include "core/platform/network/FormData.h" 24 25 #include "core/fileapi/File.h" 26 #include "core/html/FormDataList.h" 27 #include "core/platform/FileSystem.h" 28 #include "core/platform/network/BlobData.h" 29 #include "core/platform/network/FormDataBuilder.h" 30 #include "wtf/text/TextEncoding.h" 31 32 namespace WebCore { 33 34 inline FormData::FormData() 35 : m_identifier(0) 36 , m_alwaysStream(false) 37 , m_containsPasswordData(false) 38 { 39 } 40 41 inline FormData::FormData(const FormData& data) 42 : RefCounted<FormData>() 43 , m_elements(data.m_elements) 44 , m_identifier(data.m_identifier) 45 , m_alwaysStream(false) 46 , m_containsPasswordData(data.m_containsPasswordData) 47 { 48 } 49 50 FormData::~FormData() 51 { 52 } 53 54 PassRefPtr<FormData> FormData::create() 55 { 56 return adoptRef(new FormData); 57 } 58 59 PassRefPtr<FormData> FormData::create(const void* data, size_t size) 60 { 61 RefPtr<FormData> result = create(); 62 result->appendData(data, size); 63 return result.release(); 64 } 65 66 PassRefPtr<FormData> FormData::create(const CString& string) 67 { 68 RefPtr<FormData> result = create(); 69 result->appendData(string.data(), string.length()); 70 return result.release(); 71 } 72 73 PassRefPtr<FormData> FormData::create(const Vector<char>& vector) 74 { 75 RefPtr<FormData> result = create(); 76 result->appendData(vector.data(), vector.size()); 77 return result.release(); 78 } 79 80 PassRefPtr<FormData> FormData::create(const FormDataList& list, const WTF::TextEncoding& encoding, EncodingType encodingType) 81 { 82 RefPtr<FormData> result = create(); 83 result->appendKeyValuePairItems(list, encoding, false, 0, encodingType); 84 return result.release(); 85 } 86 87 PassRefPtr<FormData> FormData::createMultiPart(const FormDataList& list, const WTF::TextEncoding& encoding, Document* document) 88 { 89 RefPtr<FormData> result = create(); 90 result->appendKeyValuePairItems(list, encoding, true, document); 91 return result.release(); 92 } 93 94 PassRefPtr<FormData> FormData::copy() const 95 { 96 return adoptRef(new FormData(*this)); 97 } 98 99 PassRefPtr<FormData> FormData::deepCopy() const 100 { 101 RefPtr<FormData> formData(create()); 102 103 formData->m_alwaysStream = m_alwaysStream; 104 105 size_t n = m_elements.size(); 106 formData->m_elements.reserveInitialCapacity(n); 107 for (size_t i = 0; i < n; ++i) { 108 const FormDataElement& e = m_elements[i]; 109 switch (e.m_type) { 110 case FormDataElement::data: 111 formData->m_elements.uncheckedAppend(FormDataElement(e.m_data)); 112 break; 113 case FormDataElement::encodedFile: 114 formData->m_elements.uncheckedAppend(FormDataElement(e.m_filename, e.m_fileStart, e.m_fileLength, e.m_expectedFileModificationTime)); 115 break; 116 case FormDataElement::encodedBlob: 117 formData->m_elements.uncheckedAppend(FormDataElement(e.m_url)); 118 break; 119 case FormDataElement::encodedURL: 120 formData->m_elements.uncheckedAppend(FormDataElement(e.m_url, e.m_fileStart, e.m_fileLength, e.m_expectedFileModificationTime)); 121 break; 122 } 123 } 124 return formData.release(); 125 } 126 127 void FormData::appendData(const void* data, size_t size) 128 { 129 if (m_elements.isEmpty() || m_elements.last().m_type != FormDataElement::data) 130 m_elements.append(FormDataElement()); 131 FormDataElement& e = m_elements.last(); 132 size_t oldSize = e.m_data.size(); 133 e.m_data.grow(oldSize + size); 134 memcpy(e.m_data.data() + oldSize, data, size); 135 } 136 137 void FormData::appendFile(const String& filename) 138 { 139 m_elements.append(FormDataElement(filename, 0, BlobDataItem::toEndOfFile, invalidFileTime())); 140 } 141 142 void FormData::appendFileRange(const String& filename, long long start, long long length, double expectedModificationTime) 143 { 144 m_elements.append(FormDataElement(filename, start, length, expectedModificationTime)); 145 } 146 147 void FormData::appendBlob(const KURL& blobURL) 148 { 149 m_elements.append(FormDataElement(blobURL)); 150 } 151 152 void FormData::appendURL(const KURL& url) 153 { 154 m_elements.append(FormDataElement(url, 0, BlobDataItem::toEndOfFile, invalidFileTime())); 155 } 156 157 void FormData::appendURLRange(const KURL& url, long long start, long long length, double expectedModificationTime) 158 { 159 m_elements.append(FormDataElement(url, start, length, expectedModificationTime)); 160 } 161 162 void FormData::appendKeyValuePairItems(const FormDataList& list, const WTF::TextEncoding& encoding, bool isMultiPartForm, Document* document, EncodingType encodingType) 163 { 164 if (isMultiPartForm) 165 m_boundary = FormDataBuilder::generateUniqueBoundaryString(); 166 167 Vector<char> encodedData; 168 169 const Vector<FormDataList::Item>& items = list.items(); 170 size_t formDataListSize = items.size(); 171 ASSERT(!(formDataListSize % 2)); 172 for (size_t i = 0; i < formDataListSize; i += 2) { 173 const FormDataList::Item& key = items[i]; 174 const FormDataList::Item& value = items[i + 1]; 175 if (isMultiPartForm) { 176 Vector<char> header; 177 FormDataBuilder::beginMultiPartHeader(header, m_boundary.data(), key.data()); 178 179 // If the current type is blob, then we also need to include the filename 180 if (value.blob()) { 181 String name; 182 if (value.blob()->isFile()) { 183 File* file = toFile(value.blob()); 184 // For file blob, use the filename (or relative path if it is present) as the name. 185 name = file->webkitRelativePath().isEmpty() ? file->name() : file->webkitRelativePath(); 186 187 // If a filename is passed in FormData.append(), use it instead of the file blob's name. 188 if (!value.filename().isNull()) 189 name = value.filename(); 190 } else { 191 // For non-file blob, use the filename if it is passed in FormData.append(). 192 if (!value.filename().isNull()) 193 name = value.filename(); 194 else 195 name = "blob"; 196 } 197 198 // We have to include the filename=".." part in the header, even if the filename is empty 199 FormDataBuilder::addFilenameToMultiPartHeader(header, encoding, name); 200 201 // Add the content type if available, or "application/octet-stream" otherwise (RFC 1867). 202 String contentType; 203 if (value.blob()->type().isEmpty()) 204 contentType = "application/octet-stream"; 205 else 206 contentType = value.blob()->type(); 207 FormDataBuilder::addContentTypeToMultiPartHeader(header, contentType.latin1()); 208 } 209 210 FormDataBuilder::finishMultiPartHeader(header); 211 212 // Append body 213 appendData(header.data(), header.size()); 214 if (value.blob()) { 215 if (value.blob()->isFile()) { 216 File* file = toFile(value.blob()); 217 // Do not add the file if the path is empty. 218 if (!file->path().isEmpty()) 219 appendFile(file->path()); 220 if (!file->fileSystemURL().isEmpty()) 221 appendURL(file->fileSystemURL()); 222 } 223 else 224 appendBlob(value.blob()->url()); 225 } else 226 appendData(value.data().data(), value.data().length()); 227 appendData("\r\n", 2); 228 } else { 229 // Omit the name "isindex" if it's the first form data element. 230 // FIXME: Why is this a good rule? Is this obsolete now? 231 if (encodedData.isEmpty() && key.data() == "isindex") 232 FormDataBuilder::encodeStringAsFormData(encodedData, value.data()); 233 else 234 FormDataBuilder::addKeyValuePairAsFormData(encodedData, key.data(), value.data(), encodingType); 235 } 236 } 237 238 if (isMultiPartForm) 239 FormDataBuilder::addBoundaryToMultiPartHeader(encodedData, m_boundary.data(), true); 240 241 appendData(encodedData.data(), encodedData.size()); 242 } 243 244 void FormData::flatten(Vector<char>& data) const 245 { 246 // Concatenate all the byte arrays, but omit any files. 247 data.clear(); 248 size_t n = m_elements.size(); 249 for (size_t i = 0; i < n; ++i) { 250 const FormDataElement& e = m_elements[i]; 251 if (e.m_type == FormDataElement::data) 252 data.append(e.m_data.data(), static_cast<size_t>(e.m_data.size())); 253 } 254 } 255 256 String FormData::flattenToString() const 257 { 258 Vector<char> bytes; 259 flatten(bytes); 260 return Latin1Encoding().decode(reinterpret_cast<const char*>(bytes.data()), bytes.size()); 261 } 262 263 } // namespace WebCore 264