9665bbd1c4d8f527eb20d833f82fdb9de6844af6
[WebKit-https.git] / Source / WebCore / platform / network / FormData.cpp
1 /*
2  * Copyright (C) 2004, 2006, 2008, 2011 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
23 #include "FormData.h"
24
25 #include "BlobData.h"
26 #include "BlobURL.h"
27 #include "Chrome.h"
28 #include "ChromeClient.h"
29 #include "Document.h"
30 #include "File.h"
31 #include "FileSystem.h"
32 #include "FormDataBuilder.h"
33 #include "FormDataList.h"
34 #include "MIMETypeRegistry.h"
35 #include "Page.h"
36 #include "TextEncoding.h"
37 #include <wtf/Decoder.h>
38 #include <wtf/Encoder.h>
39
40 namespace WebCore {
41
42 inline FormData::FormData()
43     : m_identifier(0)
44     , m_hasGeneratedFiles(false)
45     , m_alwaysStream(false)
46 {
47 }
48
49 inline FormData::FormData(const FormData& data)
50     : RefCounted<FormData>()
51     , m_elements(data.m_elements)
52     , m_identifier(data.m_identifier)
53     , m_hasGeneratedFiles(false)
54     , m_alwaysStream(false)
55 {
56     // We shouldn't be copying FormData that hasn't already removed its generated files
57     // but just in case, make sure the new FormData is ready to generate its own files.
58     if (data.m_hasGeneratedFiles) {
59         size_t n = m_elements.size();
60         for (size_t i = 0; i < n; ++i) {
61             FormDataElement& e = m_elements[i];
62             if (e.m_type == FormDataElement::encodedFile)
63                 e.m_generatedFilename = String();
64         }
65     }
66 }
67
68 FormData::~FormData()
69 {
70     // This cleanup should've happened when the form submission finished.
71     // Just in case, let's assert, and do the cleanup anyway in release builds.
72     ASSERT(!m_hasGeneratedFiles);
73     removeGeneratedFilesIfNeeded();
74 }
75
76 PassRefPtr<FormData> FormData::create()
77 {
78     return adoptRef(new FormData);
79 }
80
81 PassRefPtr<FormData> FormData::create(const void* data, size_t size)
82 {
83     RefPtr<FormData> result = create();
84     result->appendData(data, size);
85     return result.release();
86 }
87
88 PassRefPtr<FormData> FormData::create(const CString& string)
89 {
90     RefPtr<FormData> result = create();
91     result->appendData(string.data(), string.length());
92     return result.release();
93 }
94
95 PassRefPtr<FormData> FormData::create(const Vector<char>& vector)
96 {
97     RefPtr<FormData> result = create();
98     result->appendData(vector.data(), vector.size());
99     return result.release();
100 }
101
102 PassRefPtr<FormData> FormData::create(const FormDataList& list, const TextEncoding& encoding, EncodingType encodingType)
103 {
104     RefPtr<FormData> result = create();
105     result->appendKeyValuePairItems(list, encoding, false, 0, encodingType);
106     return result.release();
107 }
108
109 PassRefPtr<FormData> FormData::createMultiPart(const FormDataList& list, const TextEncoding& encoding, Document* document)
110 {
111     RefPtr<FormData> result = create();
112     result->appendKeyValuePairItems(list, encoding, true, document);
113     return result.release();
114 }
115
116 PassRefPtr<FormData> FormData::copy() const
117 {
118     return adoptRef(new FormData(*this));
119 }
120
121 PassRefPtr<FormData> FormData::deepCopy() const
122 {
123     RefPtr<FormData> formData(create());
124
125     formData->m_alwaysStream = m_alwaysStream;
126
127     size_t n = m_elements.size();
128     formData->m_elements.reserveInitialCapacity(n);
129     for (size_t i = 0; i < n; ++i) {
130         const FormDataElement& e = m_elements[i];
131         switch (e.m_type) {
132         case FormDataElement::data:
133             formData->m_elements.append(FormDataElement(e.m_data));
134             break;
135         case FormDataElement::encodedFile:
136 #if ENABLE(BLOB)
137             formData->m_elements.append(FormDataElement(e.m_filename, e.m_fileStart, e.m_fileLength, e.m_expectedFileModificationTime, e.m_shouldGenerateFile));
138 #else
139             formData->m_elements.append(FormDataElement(e.m_filename, e.m_shouldGenerateFile));
140 #endif
141             break;
142 #if ENABLE(BLOB)
143         case FormDataElement::encodedBlob:
144             formData->m_elements.append(FormDataElement(e.m_blobURL));
145             break;
146 #endif
147         }
148     }
149     return formData.release();
150 }
151
152 void FormData::appendData(const void* data, size_t size)
153 {
154     if (m_elements.isEmpty() || m_elements.last().m_type != FormDataElement::data)
155         m_elements.append(FormDataElement());
156     FormDataElement& e = m_elements.last();
157     size_t oldSize = e.m_data.size();
158     e.m_data.grow(oldSize + size);
159     memcpy(e.m_data.data() + oldSize, data, size);
160 }
161
162 void FormData::appendFile(const String& filename, bool shouldGenerateFile)
163 {
164 #if ENABLE(BLOB)
165     m_elements.append(FormDataElement(filename, 0, BlobDataItem::toEndOfFile, BlobDataItem::doNotCheckFileChange, shouldGenerateFile));
166 #else
167     m_elements.append(FormDataElement(filename, shouldGenerateFile));
168 #endif
169 }
170
171 #if ENABLE(BLOB)
172 void FormData::appendFileRange(const String& filename, long long start, long long length, double expectedModificationTime, bool shouldGenerateFile)
173 {
174     m_elements.append(FormDataElement(filename, start, length, expectedModificationTime, shouldGenerateFile));
175 }
176
177 void FormData::appendBlob(const KURL& blobURL)
178 {
179     m_elements.append(FormDataElement(blobURL));
180 }
181 #endif
182
183 void FormData::appendKeyValuePairItems(const FormDataList& list, const TextEncoding& encoding, bool isMultiPartForm, Document* document, EncodingType encodingType)
184 {
185     if (isMultiPartForm)
186         m_boundary = FormDataBuilder::generateUniqueBoundaryString();
187
188     Vector<char> encodedData;
189
190     const Vector<FormDataList::Item>& items = list.items();
191     size_t formDataListSize = items.size();
192     ASSERT(!(formDataListSize % 2));
193     for (size_t i = 0; i < formDataListSize; i += 2) {
194         const FormDataList::Item& key = items[i];
195         const FormDataList::Item& value = items[i + 1];
196         if (isMultiPartForm) {
197             Vector<char> header;
198             FormDataBuilder::beginMultiPartHeader(header, m_boundary.data(), key.data());
199
200             bool shouldGenerateFile = false;
201
202             // If the current type is blob, then we also need to include the filename
203             if (value.blob()) {
204                 String name;
205                 if (value.blob()->isFile()) {
206                     // For file blob, use the filename (or relative path if it is present) as the name.
207                     File* file = static_cast<File*>(value.blob());
208 #if ENABLE(DIRECTORY_UPLOAD)                
209                     name = file->webkitRelativePath().isEmpty() ? file->name() : file->webkitRelativePath();
210 #else
211                     name = file->name();
212 #endif
213                     // Let the application specify a filename if it's going to generate a replacement file for the upload.
214                     const String& path = file->path();
215                     if (!path.isEmpty()) {
216                         if (Page* page = document->page()) {
217                             String generatedFileName;
218                             shouldGenerateFile = page->chrome()->client()->shouldReplaceWithGeneratedFileForUpload(path, generatedFileName);
219                             if (shouldGenerateFile)
220                                 name = generatedFileName;
221                         }
222                     }
223                 } else {
224                     // For non-file blob, use the filename if it is passed in FormData.append().
225                     if (!value.filename().isEmpty())
226                         name = value.filename();
227                     else
228                         name = "blob";
229                 }
230
231                 // We have to include the filename=".." part in the header, even if the filename is empty
232                 FormDataBuilder::addFilenameToMultiPartHeader(header, encoding, name);
233
234                 // Add the content type if available, or "application/octet-stream" otherwise (RFC 1867).
235                 String contentType;
236                 if (value.blob()->type().isEmpty())
237                     contentType = "application/octet-stream";
238                 else
239                     contentType = value.blob()->type();
240                 FormDataBuilder::addContentTypeToMultiPartHeader(header, contentType.latin1());
241             }
242
243             FormDataBuilder::finishMultiPartHeader(header);
244
245             // Append body
246             appendData(header.data(), header.size());
247             if (value.blob()) {
248                 if (value.blob()->isFile()) {
249                     // Do not add the file if the path is empty.
250                     if (!static_cast<File*>(value.blob())->path().isEmpty())
251                         appendFile(static_cast<File*>(value.blob())->path(), shouldGenerateFile);
252                 }
253 #if ENABLE(BLOB)
254                 else
255                     appendBlob(value.blob()->url());
256 #endif
257             } else
258                 appendData(value.data().data(), value.data().length());
259             appendData("\r\n", 2);
260         } else {
261             // Omit the name "isindex" if it's the first form data element.
262             // FIXME: Why is this a good rule? Is this obsolete now?
263             if (encodedData.isEmpty() && key.data() == "isindex")
264                 FormDataBuilder::encodeStringAsFormData(encodedData, value.data());
265             else
266                 FormDataBuilder::addKeyValuePairAsFormData(encodedData, key.data(), value.data(), encodingType);
267         }
268     }
269
270     if (isMultiPartForm)
271         FormDataBuilder::addBoundaryToMultiPartHeader(encodedData, m_boundary.data(), true);
272
273     appendData(encodedData.data(), encodedData.size());
274 }
275
276 void FormData::flatten(Vector<char>& data) const
277 {
278     // Concatenate all the byte arrays, but omit any files.
279     data.clear();
280     size_t n = m_elements.size();
281     for (size_t i = 0; i < n; ++i) {
282         const FormDataElement& e = m_elements[i];
283         if (e.m_type == FormDataElement::data)
284             data.append(e.m_data.data(), static_cast<size_t>(e.m_data.size()));
285     }
286 }
287
288 String FormData::flattenToString() const
289 {
290     Vector<char> bytes;
291     flatten(bytes);
292     return Latin1Encoding().decode(reinterpret_cast<const char*>(bytes.data()), bytes.size());
293 }
294
295 void FormData::generateFiles(Document* document)
296 {
297     ASSERT(!m_hasGeneratedFiles);
298
299     if (m_hasGeneratedFiles)
300         return;
301
302     Page* page = document->page();
303     if (!page)
304         return;
305     ChromeClient* client = page->chrome()->client();
306
307     size_t n = m_elements.size();
308     for (size_t i = 0; i < n; ++i) {
309         FormDataElement& e = m_elements[i];
310         if (e.m_type == FormDataElement::encodedFile && e.m_shouldGenerateFile) {
311             e.m_generatedFilename = client->generateReplacementFile(e.m_filename);
312             m_hasGeneratedFiles = true;
313         }
314     }
315 }
316
317 void FormData::removeGeneratedFilesIfNeeded()
318 {
319     if (!m_hasGeneratedFiles)
320         return;
321
322     size_t n = m_elements.size();
323     for (size_t i = 0; i < n; ++i) {
324         FormDataElement& e = m_elements[i];
325         if (e.m_type == FormDataElement::encodedFile && !e.m_generatedFilename.isEmpty()) {
326             ASSERT(e.m_shouldGenerateFile);
327             String directory = directoryName(e.m_generatedFilename);
328             deleteFile(e.m_generatedFilename);
329             deleteEmptyDirectory(directory);
330             e.m_generatedFilename = String();
331         }
332     }
333     m_hasGeneratedFiles = false;
334 }
335
336 static void encode(Encoder& encoder, const FormDataElement& element)
337 {
338     encoder.encodeUInt32(element.m_type);
339
340     switch (element.m_type) {
341     case FormDataElement::data:
342         encoder.encodeBytes(reinterpret_cast<const uint8_t*>(element.m_data.data()), element.m_data.size());
343         return;
344
345     case FormDataElement::encodedFile:
346         encoder.encodeString(element.m_filename);
347         encoder.encodeBool(element.m_shouldGenerateFile);
348 #if ENABLE(BLOB)
349         encoder.encodeInt64(element.m_fileStart);
350         encoder.encodeInt64(element.m_fileLength);
351         encoder.encodeDouble(element.m_expectedFileModificationTime);
352 #else
353         encoder.encodeInt64(0);
354         encoder.encodeInt64(0);
355         encoder.encodeDouble(0);
356 #endif
357         return;
358
359 #if ENABLE(BLOB)
360     case FormDataElement::encodedBlob:
361         encoder.encodeString(element.m_blobURL.string());
362         return;
363 #endif
364     }
365
366     ASSERT_NOT_REACHED();
367 }
368
369 static bool decode(Decoder& decoder, FormDataElement& element)
370 {
371     uint32_t type;
372     if (!decoder.decodeUInt32(type))
373         return false;
374
375     switch (type) {
376     case FormDataElement::data: {
377         element.m_type = FormDataElement::data;
378         Vector<uint8_t> data;
379         if (!decoder.decodeBytes(data))
380             return false;
381         size_t size = data.size();
382         element.m_data.resize(size);
383         memcpy(element.m_data.data(), data.data(), size);
384         return true;
385     }
386
387     case FormDataElement::encodedFile: {
388         element.m_type = FormDataElement::encodedFile;
389         if (!decoder.decodeString(element.m_filename))
390             return false;
391         if (!decoder.decodeBool(element.m_shouldGenerateFile))
392             return false;
393         int64_t fileStart;
394         if (!decoder.decodeInt64(fileStart))
395             return false;
396         if (fileStart < 0)
397             return false;
398         int64_t fileLength;
399         if (!decoder.decodeInt64(fileLength))
400             return false;
401         if (fileLength < fileStart)
402             return false;
403         double expectedFileModificationTime;
404         if (!decoder.decodeDouble(expectedFileModificationTime))
405             return false;
406 #if ENABLE(BLOB)
407         element.m_fileStart = fileStart;
408         element.m_fileLength = fileLength;
409         element.m_expectedFileModificationTime = expectedFileModificationTime;
410 #endif
411         return true;
412     }
413
414 #if ENABLE(BLOB)
415     case FormDataElement::encodedBlob:
416         element.m_type = FormDataElement::encodedBlob;
417         String blobURLString;
418         if (!decoder.decodeString(blobURLString))
419             return false;
420         element.m_blobURL = KURL(KURL(), blobURLString);
421         return true;
422 #endif
423     }
424
425     return false;
426 }
427
428 void FormData::encodeForBackForward(Encoder& encoder) const
429 {
430     encoder.encodeBool(m_alwaysStream);
431
432     encoder.encodeBytes(reinterpret_cast<const uint8_t*>(m_boundary.data()), m_boundary.size());
433
434     size_t size = m_elements.size();
435     encoder.encodeUInt64(size);
436     for (size_t i = 0; i < size; ++i)
437         encode(encoder, m_elements[i]);
438
439     encoder.encodeBool(m_hasGeneratedFiles);
440
441     encoder.encodeInt64(m_identifier);
442 }
443
444 PassRefPtr<FormData> FormData::decodeForBackForward(Decoder& decoder)
445 {
446     RefPtr<FormData> data = FormData::create();
447
448     if (!decoder.decodeBool(data->m_alwaysStream))
449         return 0;
450
451     Vector<uint8_t> boundary;
452     if (!decoder.decodeBytes(boundary))
453         return 0;
454     size_t size = boundary.size();
455     data->m_boundary.resize(size);
456     memcpy(data->m_boundary.data(), boundary.data(), size);
457
458     uint64_t elementsSize;
459     if (!decoder.decodeUInt64(elementsSize))
460         return 0;
461     for (size_t i = 0; i < elementsSize; ++i) {
462         FormDataElement element;
463         if (!decode(decoder, element))
464             return 0;
465         data->m_elements.append(element);
466     }
467
468     if (!decoder.decodeBool(data->m_hasGeneratedFiles))
469         return 0;
470
471     if (!decoder.decodeInt64(data->m_identifier))
472         return 0;
473
474     return data.release();
475 }
476
477 } // namespace WebCore