1 /* 2 * Copyright (C) 2004, 2006, 2008 Apple Inc. All rights reserved. 3 * Copyright (C) 2009 Google Inc. All rights reserved. 4 * 5 * This library is free software; you can redistribute it and/or 6 * modify it under the terms of the GNU Library General Public 7 * License as published by the Free Software Foundation; either 8 * version 2 of the License, or (at your option) any later version. 9 * 10 * This library is distributed in the hope that it will be useful, 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 * Library General Public License for more details. 14 * 15 * You should have received a copy of the GNU Library General Public License 16 * along with this library; see the file COPYING.LIB. If not, write to 17 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 18 * Boston, MA 02110-1301, USA. 19 */ 20 21 #include "config.h" 22 #include "FormData.h" 23 24 #include "CString.h" 25 #include "ChromeClient.h" 26 #include "FileSystem.h" 27 #include "TextEncoding.h" 28 29 namespace WebCore { 30 31 inline FormData::FormData() 32 : m_identifier(0) 33 , m_hasGeneratedFiles(false) 34 , m_alwaysStream(false) 35 { 36 } 37 38 inline FormData::FormData(const FormData& data) 39 : RefCounted<FormData>() 40 , m_elements(data.m_elements) 41 , m_identifier(data.m_identifier) 42 , m_hasGeneratedFiles(false) 43 , m_alwaysStream(false) 44 { 45 // We shouldn't be copying FormData that hasn't already removed its generated files 46 // but just in case, make sure the new FormData is ready to generate its own files. 47 if (data.m_hasGeneratedFiles) { 48 size_t n = m_elements.size(); 49 for (size_t i = 0; i < n; ++i) { 50 FormDataElement& e = m_elements[i]; 51 if (e.m_type == FormDataElement::encodedFile) 52 e.m_generatedFilename = String(); 53 } 54 } 55 } 56 57 FormData::~FormData() 58 { 59 // This cleanup should've happened when the form submission finished. 60 // Just in case, let's assert, and do the cleanup anyway in release builds. 61 ASSERT(!m_hasGeneratedFiles); 62 removeGeneratedFilesIfNeeded(); 63 } 64 65 PassRefPtr<FormData> FormData::create() 66 { 67 return adoptRef(new FormData); 68 } 69 70 PassRefPtr<FormData> FormData::create(const void* data, size_t size) 71 { 72 RefPtr<FormData> result = create(); 73 result->appendData(data, size); 74 return result.release(); 75 } 76 77 PassRefPtr<FormData> FormData::create(const CString& string) 78 { 79 RefPtr<FormData> result = create(); 80 result->appendData(string.data(), string.length()); 81 return result.release(); 82 } 83 84 PassRefPtr<FormData> FormData::create(const Vector<char>& vector) 85 { 86 RefPtr<FormData> result = create(); 87 result->appendData(vector.data(), vector.size()); 88 return result.release(); 89 } 90 91 PassRefPtr<FormData> FormData::copy() const 92 { 93 return adoptRef(new FormData(*this)); 94 } 95 96 PassRefPtr<FormData> FormData::deepCopy() const 97 { 98 RefPtr<FormData> formData(create()); 99 100 formData->m_alwaysStream = m_alwaysStream; 101 102 size_t n = m_elements.size(); 103 formData->m_elements.reserveInitialCapacity(n); 104 for (size_t i = 0; i < n; ++i) { 105 const FormDataElement& e = m_elements[i]; 106 switch (e.m_type) { 107 case FormDataElement::data: 108 formData->m_elements.append(FormDataElement(e.m_data)); 109 break; 110 case FormDataElement::encodedFile: 111 formData->m_elements.append(FormDataElement(e.m_filename, e.m_shouldGenerateFile)); 112 break; 113 } 114 } 115 return formData.release(); 116 } 117 118 void FormData::appendData(const void* data, size_t size) 119 { 120 if (m_elements.isEmpty() || m_elements.last().m_type != FormDataElement::data) 121 m_elements.append(FormDataElement()); 122 FormDataElement& e = m_elements.last(); 123 size_t oldSize = e.m_data.size(); 124 e.m_data.grow(oldSize + size); 125 memcpy(e.m_data.data() + oldSize, data, size); 126 } 127 128 void FormData::appendFile(const String& filename, bool shouldGenerateFile) 129 { 130 m_elements.append(FormDataElement(filename, shouldGenerateFile)); 131 } 132 133 void FormData::flatten(Vector<char>& data) const 134 { 135 // Concatenate all the byte arrays, but omit any files. 136 data.clear(); 137 size_t n = m_elements.size(); 138 for (size_t i = 0; i < n; ++i) { 139 const FormDataElement& e = m_elements[i]; 140 if (e.m_type == FormDataElement::data) { 141 size_t oldSize = data.size(); 142 size_t delta = e.m_data.size(); 143 data.grow(oldSize + delta); 144 memcpy(data.data() + oldSize, e.m_data.data(), delta); 145 } 146 } 147 } 148 149 String FormData::flattenToString() const 150 { 151 Vector<char> bytes; 152 flatten(bytes); 153 return Latin1Encoding().decode(bytes.data(), bytes.size()); 154 } 155 156 void FormData::generateFiles(ChromeClient* client) 157 { 158 ASSERT(!m_hasGeneratedFiles); 159 160 if (m_hasGeneratedFiles) 161 return; 162 163 size_t n = m_elements.size(); 164 for (size_t i = 0; i < n; ++i) { 165 FormDataElement& e = m_elements[i]; 166 if (e.m_type == FormDataElement::encodedFile && e.m_shouldGenerateFile) { 167 e.m_generatedFilename = client->generateReplacementFile(e.m_filename); 168 m_hasGeneratedFiles = true; 169 } 170 } 171 } 172 173 void FormData::removeGeneratedFilesIfNeeded() 174 { 175 if (!m_hasGeneratedFiles) 176 return; 177 178 size_t n = m_elements.size(); 179 for (size_t i = 0; i < n; ++i) { 180 FormDataElement& e = m_elements[i]; 181 if (e.m_type == FormDataElement::encodedFile && !e.m_generatedFilename.isEmpty()) { 182 ASSERT(e.m_shouldGenerateFile); 183 String directory = directoryName(e.m_generatedFilename); 184 deleteFile(e.m_generatedFilename); 185 deleteEmptyDirectory(directory); 186 e.m_generatedFilename = String(); 187 } 188 } 189 m_hasGeneratedFiles = false; 190 } 191 192 } // namespace WebCore 193