• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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