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
FormData()31 inline FormData::FormData()
32 : m_identifier(0)
33 , m_hasGeneratedFiles(false)
34 , m_alwaysStream(false)
35 {
36 }
37
FormData(const FormData & data)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
~FormData()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
create()65 PassRefPtr<FormData> FormData::create()
66 {
67 return adoptRef(new FormData);
68 }
69
create(const void * data,size_t size)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
create(const CString & string)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
create(const Vector<char> & vector)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
copy() const91 PassRefPtr<FormData> FormData::copy() const
92 {
93 return adoptRef(new FormData(*this));
94 }
95
deepCopy() const96 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
appendData(const void * data,size_t size)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
appendFile(const String & filename,bool shouldGenerateFile)128 void FormData::appendFile(const String& filename, bool shouldGenerateFile)
129 {
130 m_elements.append(FormDataElement(filename, shouldGenerateFile));
131 }
132
flatten(Vector<char> & data) const133 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
flattenToString() const149 String FormData::flattenToString() const
150 {
151 Vector<char> bytes;
152 flatten(bytes);
153 return Latin1Encoding().decode(bytes.data(), bytes.size());
154 }
155
generateFiles(ChromeClient * client)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
removeGeneratedFilesIfNeeded()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