1 /* 2 * Copyright (C) 2005, 2006, 2008 Apple Inc. All rights reserved. 3 * 4 * This library is free software; you can redistribute it and/or 5 * modify it under the terms of the GNU Library General Public 6 * License as published by the Free Software Foundation; either 7 * version 2 of the License, or (at your option) any later version. 8 * 9 * This library is distributed in the hope that it will be useful, 10 * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 * Library General Public License for more details. 13 * 14 * You should have received a copy of the GNU Library General Public License 15 * along with this library; see the file COPYING.LIB. If not, write to 16 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 17 * Boston, MA 02110-1301, USA. 18 * 19 */ 20 21 #include "config.h" 22 #include "core/html/FormDataList.h" 23 24 #include "core/fileapi/File.h" 25 #include "platform/network/FormDataBuilder.h" 26 #include "platform/text/LineEnding.h" 27 28 namespace WebCore { 29 30 FormDataList::FormDataList(const WTF::TextEncoding& c) 31 : m_encoding(c) 32 { 33 } 34 35 void FormDataList::appendString(const String& string) 36 { 37 CString encodedString = m_encoding.encode(string, WTF::EntitiesForUnencodables); 38 m_items.append(normalizeLineEndingsToCRLF(encodedString)); 39 } 40 41 void FormDataList::appendString(const CString& string) 42 { 43 m_items.append(string); 44 } 45 46 void FormDataList::appendBlob(PassRefPtr<Blob> blob, const String& filename) 47 { 48 m_items.append(Item(blob, filename)); 49 } 50 51 PassRefPtr<FormData> FormDataList::createFormData(const WTF::TextEncoding& encoding, FormData::EncodingType encodingType) 52 { 53 RefPtr<FormData> result = FormData::create(); 54 appendKeyValuePairItemsTo(result.get(), encoding, false, encodingType); 55 return result.release(); 56 } 57 58 PassRefPtr<FormData> FormDataList::createMultiPartFormData(const WTF::TextEncoding& encoding) 59 { 60 RefPtr<FormData> result = FormData::create(); 61 appendKeyValuePairItemsTo(result.get(), encoding, true); 62 return result.release(); 63 } 64 65 void FormDataList::appendKeyValuePairItemsTo(FormData* formData, const WTF::TextEncoding& encoding, bool isMultiPartForm, FormData::EncodingType encodingType) 66 { 67 if (isMultiPartForm) 68 formData->setBoundary(FormDataBuilder::generateUniqueBoundaryString()); 69 70 Vector<char> encodedData; 71 72 const Vector<FormDataList::Item>& items = this->items(); 73 size_t formDataListSize = items.size(); 74 ASSERT(!(formDataListSize % 2)); 75 for (size_t i = 0; i < formDataListSize; i += 2) { 76 const FormDataList::Item& key = items[i]; 77 const FormDataList::Item& value = items[i + 1]; 78 if (isMultiPartForm) { 79 Vector<char> header; 80 FormDataBuilder::beginMultiPartHeader(header, formData->boundary().data(), key.data()); 81 82 // If the current type is blob, then we also need to include the filename 83 if (value.blob()) { 84 String name; 85 if (value.blob()->isFile()) { 86 File* file = toFile(value.blob()); 87 // For file blob, use the filename (or relative path if it is present) as the name. 88 name = file->webkitRelativePath().isEmpty() ? file->name() : file->webkitRelativePath(); 89 90 // If a filename is passed in FormData.append(), use it instead of the file blob's name. 91 if (!value.filename().isNull()) 92 name = value.filename(); 93 } else { 94 // For non-file blob, use the filename if it is passed in FormData.append(). 95 if (!value.filename().isNull()) 96 name = value.filename(); 97 else 98 name = "blob"; 99 } 100 101 // We have to include the filename=".." part in the header, even if the filename is empty 102 FormDataBuilder::addFilenameToMultiPartHeader(header, encoding, name); 103 104 // Add the content type if available, or "application/octet-stream" otherwise (RFC 1867). 105 String contentType; 106 if (value.blob()->type().isEmpty()) 107 contentType = "application/octet-stream"; 108 else 109 contentType = value.blob()->type(); 110 FormDataBuilder::addContentTypeToMultiPartHeader(header, contentType.latin1()); 111 } 112 113 FormDataBuilder::finishMultiPartHeader(header); 114 115 // Append body 116 formData->appendData(header.data(), header.size()); 117 if (value.blob()) { 118 if (value.blob()->hasBackingFile()) { 119 File* file = toFile(value.blob()); 120 // Do not add the file if the path is empty. 121 if (!file->path().isEmpty()) 122 formData->appendFile(file->path()); 123 if (!file->fileSystemURL().isEmpty()) 124 formData->appendFileSystemURL(file->fileSystemURL()); 125 } else { 126 formData->appendBlob(value.blob()->uuid(), value.blob()->blobDataHandle()); 127 } 128 } else { 129 formData->appendData(value.data().data(), value.data().length()); 130 } 131 formData->appendData("\r\n", 2); 132 } else { 133 // Omit the name "isindex" if it's the first form data element. 134 // FIXME: Why is this a good rule? Is this obsolete now? 135 if (encodedData.isEmpty() && key.data() == "isindex") 136 FormDataBuilder::encodeStringAsFormData(encodedData, value.data()); 137 else 138 FormDataBuilder::addKeyValuePairAsFormData(encodedData, key.data(), value.data(), encodingType); 139 } 140 } 141 142 if (isMultiPartForm) 143 FormDataBuilder::addBoundaryToMultiPartHeader(encodedData, formData->boundary().data(), true); 144 145 formData->appendData(encodedData.data(), encodedData.size()); 146 } 147 148 } // namespace 149