16f98adb4805723ead5fca3b93b7cc73e12124bd
[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)
103 {
104     RefPtr<FormData> result = create();
105     result->appendKeyValuePairItems(list, encoding, false, 0);
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)
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
214                     // Let the application specify a filename if it's going to generate a replacement file for the upload.
215                     if (Page* page = document->page()) {
216                         String generatedFileName;
217                         shouldGenerateFile = page->chrome()->client()->shouldReplaceWithGeneratedFileForUpload(file->path(), generatedFileName);
218                         if (shouldGenerateFile)
219                             name = generatedFileName;
220                     }
221                 } else {
222                     // For non-file blob, use the identifier part of the URL as the name.
223                     name = "Blob" + BlobURL::getIdentifier(value.blob()->url());
224                     name = name.replace("-", ""); // For safety, remove '-' from the filename since some servers may not like it.
225                 }
226
227                 // We have to include the filename=".." part in the header, even if the filename is empty
228                 FormDataBuilder::addFilenameToMultiPartHeader(header, encoding, name);
229
230                 // Add the content type if available, or "application/octet-stream" otherwise (RFC 1867).
231                 String contentType;
232                 if (value.blob()->type().isEmpty())
233                     contentType = "application/octet-stream";
234                 else
235                     contentType = value.blob()->type();
236                 FormDataBuilder::addContentTypeToMultiPartHeader(header, contentType.latin1());
237             }
238
239             FormDataBuilder::finishMultiPartHeader(header);
240
241             // Append body
242             appendData(header.data(), header.size());
243             if (value.blob()) {
244                 if (value.blob()->isFile()) {
245                     // Do not add the file if the path is empty.
246                     if (!static_cast<File*>(value.blob())->path().isEmpty())
247                         appendFile(static_cast<File*>(value.blob())->path(), shouldGenerateFile);
248                 }
249 #if ENABLE(BLOB)
250                 else
251                     appendBlob(value.blob()->url());
252 #endif
253             } else
254                 appendData(value.data().data(), value.data().length());
255             appendData("\r\n", 2);
256         } else {
257             // Omit the name "isindex" if it's the first form data element.
258             // FIXME: Why is this a good rule? Is this obsolete now?
259             if (encodedData.isEmpty() && key.data() == "isindex")
260                 FormDataBuilder::encodeStringAsFormData(encodedData, value.data());
261             else
262                 FormDataBuilder::addKeyValuePairAsFormData(encodedData, key.data(), value.data());
263         }
264     }
265
266     if (isMultiPartForm)
267         FormDataBuilder::addBoundaryToMultiPartHeader(encodedData, m_boundary.data(), true);
268
269     appendData(encodedData.data(), encodedData.size());
270 }
271
272 void FormData::flatten(Vector<char>& data) const
273 {
274     // Concatenate all the byte arrays, but omit any files.
275     data.clear();
276     size_t n = m_elements.size();
277     for (size_t i = 0; i < n; ++i) {
278         const FormDataElement& e = m_elements[i];
279         if (e.m_type == FormDataElement::data)
280             data.append(e.m_data.data(), static_cast<size_t>(e.m_data.size()));
281     }
282 }
283
284 String FormData::flattenToString() const
285 {
286     Vector<char> bytes;
287     flatten(bytes);
288     return Latin1Encoding().decode(reinterpret_cast<const char*>(bytes.data()), bytes.size());
289 }
290
291 void FormData::generateFiles(Document* document)
292 {
293     ASSERT(!m_hasGeneratedFiles);
294
295     if (m_hasGeneratedFiles)
296         return;
297
298     Page* page = document->page();
299     if (!page)
300         return;
301     ChromeClient* client = page->chrome()->client();
302
303     size_t n = m_elements.size();
304     for (size_t i = 0; i < n; ++i) {
305         FormDataElement& e = m_elements[i];
306         if (e.m_type == FormDataElement::encodedFile && e.m_shouldGenerateFile) {
307             e.m_generatedFilename = client->generateReplacementFile(e.m_filename);
308             m_hasGeneratedFiles = true;
309         }
310     }
311 }
312
313 void FormData::removeGeneratedFilesIfNeeded()
314 {
315     if (!m_hasGeneratedFiles)
316         return;
317
318     size_t n = m_elements.size();
319     for (size_t i = 0; i < n; ++i) {
320         FormDataElement& e = m_elements[i];
321         if (e.m_type == FormDataElement::encodedFile && !e.m_generatedFilename.isEmpty()) {
322             ASSERT(e.m_shouldGenerateFile);
323             String directory = directoryName(e.m_generatedFilename);
324             deleteFile(e.m_generatedFilename);
325             deleteEmptyDirectory(directory);
326             e.m_generatedFilename = String();
327         }
328     }
329     m_hasGeneratedFiles = false;
330 }
331
332 static void encode(Encoder& encoder, const FormDataElement& element)
333 {
334     encoder.encodeUInt32(element.m_type);
335
336     switch (element.m_type) {
337     case FormDataElement::data:
338         encoder.encodeBytes(reinterpret_cast<const uint8_t*>(element.m_data.data()), element.m_data.size());
339         return;
340
341     case FormDataElement::encodedFile:
342         encoder.encodeString(element.m_filename);
343         encoder.encodeBool(element.m_shouldGenerateFile);
344 #if ENABLE(BLOB)
345         encoder.encodeInt64(element.m_fileStart);
346         encoder.encodeInt64(element.m_fileLength);
347         encoder.encodeDouble(element.m_expectedFileModificationTime);
348 #else
349         encoder.encodeInt64(0);
350         encoder.encodeInt64(0);
351         encoder.encodeDouble(0);
352 #endif
353         return;
354
355 #if ENABLE(BLOB)
356     case FormDataElement::encodedBlob:
357         encoder.encodeString(element.m_blobURL.string());
358         return;
359 #endif
360     }
361
362     ASSERT_NOT_REACHED();
363 }
364
365 static bool decode(Decoder& decoder, FormDataElement& element)
366 {
367     uint32_t type = element.m_type;
368
369     switch (type) {
370     case FormDataElement::data: {
371         element.m_type = FormDataElement::data;
372         Vector<uint8_t> data;
373         if (!decoder.decodeBytes(data))
374             return false;
375         size_t size = data.size();
376         element.m_data.resize(size);
377         memcpy(element.m_data.data(), data.data(), size);
378         return true;
379     }
380
381     case FormDataElement::encodedFile: {
382         element.m_type = FormDataElement::encodedFile;
383         if (!decoder.decodeString(element.m_filename))
384             return false;
385         if (!decoder.decodeBool(element.m_shouldGenerateFile))
386             return false;
387         int64_t fileStart;
388         if (!decoder.decodeInt64(fileStart))
389             return false;
390         if (fileStart < 0)
391             return false;
392         int64_t fileLength;
393         if (!decoder.decodeInt64(fileLength))
394             return false;
395         if (fileLength < fileStart)
396             return false;
397         double expectedFileModificationTime;
398         if (!decoder.decodeDouble(expectedFileModificationTime))
399             return false;
400 #if ENABLE(BLOB)
401         element.m_fileStart = fileStart;
402         element.m_fileLength = fileLength;
403         element.m_expectedFileModificationTime = expectedFileModificationTime;
404 #endif
405         return true;
406     }
407
408 #if ENABLE(BLOB)
409     case FormDataElement::encodedBlob:
410         element.m_type = FormDataElement::encodedBlob;
411         String blobURLString;
412         if (!decoder.decodeString(blobURLString))
413             return false;
414         element.m_blobURL = KURL(KURL(), blobURLString);
415         return true;
416 #endif
417     }
418
419     return false;
420 }
421
422 void FormData::encodeForBackForward(Encoder& encoder) const
423 {
424     encoder.encodeBool(m_alwaysStream);
425
426     encoder.encodeBytes(reinterpret_cast<const uint8_t*>(m_boundary.data()), m_boundary.size());
427
428     size_t size = m_elements.size();
429     encoder.encodeUInt64(size);
430     for (size_t i = 0; i < size; ++i)
431         encode(encoder, m_elements[i]);
432
433     encoder.encodeBool(m_hasGeneratedFiles);
434
435     encoder.encodeBool(m_identifier);
436 }
437
438 PassRefPtr<FormData> FormData::decodeForBackForward(Decoder& decoder)
439 {
440     RefPtr<FormData> data = FormData::create();
441
442     if (!decoder.decodeBool(data->m_alwaysStream))
443         return 0;
444
445     Vector<uint8_t> boundary;
446     if (!decoder.decodeBytes(boundary))
447         return 0;
448     size_t size = boundary.size();
449     data->m_boundary.resize(size);
450     memcpy(data->m_boundary.data(), boundary.data(), size);
451
452     uint64_t elementsSize;
453     if (!decoder.decodeUInt64(elementsSize))
454         return 0;
455     for (size_t i = 0; i < elementsSize; ++i) {
456         FormDataElement element;
457         if (!decode(decoder, element))
458             return 0;
459         data->m_elements.append(element);
460     }
461
462     if (!decoder.decodeBool(data->m_hasGeneratedFiles))
463         return 0;
464
465     if (!decoder.decodeInt64(data->m_identifier))
466         return 0;
467
468     return data.release();
469 }
470
471 } // namespace WebCore