f6d4588825d3f87f23817d7181b4d8aa50918953
[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  * Copyright (C) 2012 Digia Plc. and/or its subsidiary(-ies)
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Library General Public
8  * License as published by the Free Software Foundation; either
9  * version 2 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14  * Library General Public License for more details.
15  *
16  * You should have received a copy of the GNU Library General Public License
17  * along with this library; see the file COPYING.LIB. If not, write to
18  * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
19  * Boston, MA 02110-1301, USA.
20  */
21
22 #include "config.h"
23
24 #include "FormData.h"
25
26 #include "BlobData.h"
27 #include "BlobRegistryImpl.h"
28 #include "BlobURL.h"
29 #include "Chrome.h"
30 #include "ChromeClient.h"
31 #include "Document.h"
32 #include "File.h"
33 #include "FileSystem.h"
34 #include "FormDataBuilder.h"
35 #include "FormDataList.h"
36 #include "MIMETypeRegistry.h"
37 #include "Page.h"
38 #include "PlatformMemoryInstrumentation.h"
39 #include "TextEncoding.h"
40 #include <wtf/Decoder.h>
41 #include <wtf/Encoder.h>
42 #include <wtf/MemoryInstrumentationVector.h>
43
44 namespace WebCore {
45
46 inline FormData::FormData()
47     : m_identifier(0)
48     , m_hasGeneratedFiles(false)
49     , m_alwaysStream(false)
50     , m_containsPasswordData(false)
51 {
52 }
53
54 inline FormData::FormData(const FormData& data)
55     : RefCounted<FormData>()
56     , m_elements(data.m_elements)
57     , m_identifier(data.m_identifier)
58     , m_hasGeneratedFiles(false)
59     , m_alwaysStream(false)
60     , m_containsPasswordData(data.m_containsPasswordData)
61 {
62     // We shouldn't be copying FormData that hasn't already removed its generated files
63     // but just in case, make sure the new FormData is ready to generate its own files.
64     if (data.m_hasGeneratedFiles) {
65         size_t n = m_elements.size();
66         for (size_t i = 0; i < n; ++i) {
67             FormDataElement& e = m_elements[i];
68             if (e.m_type == FormDataElement::encodedFile)
69                 e.m_generatedFilename = String();
70         }
71     }
72 }
73
74 FormData::~FormData()
75 {
76     // This cleanup should've happened when the form submission finished.
77     // Just in case, let's assert, and do the cleanup anyway in release builds.
78     ASSERT(!m_hasGeneratedFiles);
79     removeGeneratedFilesIfNeeded();
80 }
81
82 PassRefPtr<FormData> FormData::create()
83 {
84     return adoptRef(new FormData);
85 }
86
87 PassRefPtr<FormData> FormData::create(const void* data, size_t size)
88 {
89     RefPtr<FormData> result = create();
90     result->appendData(data, size);
91     return result.release();
92 }
93
94 PassRefPtr<FormData> FormData::create(const CString& string)
95 {
96     RefPtr<FormData> result = create();
97     result->appendData(string.data(), string.length());
98     return result.release();
99 }
100
101 PassRefPtr<FormData> FormData::create(const Vector<char>& vector)
102 {
103     RefPtr<FormData> result = create();
104     result->appendData(vector.data(), vector.size());
105     return result.release();
106 }
107
108 PassRefPtr<FormData> FormData::create(const FormDataList& list, const TextEncoding& encoding, EncodingType encodingType)
109 {
110     RefPtr<FormData> result = create();
111     result->appendKeyValuePairItems(list, encoding, false, 0, encodingType);
112     return result.release();
113 }
114
115 PassRefPtr<FormData> FormData::createMultiPart(const FormDataList& list, const TextEncoding& encoding, Document* document)
116 {
117     RefPtr<FormData> result = create();
118     result->appendKeyValuePairItems(list, encoding, true, document);
119     return result.release();
120 }
121
122 PassRefPtr<FormData> FormData::copy() const
123 {
124     return adoptRef(new FormData(*this));
125 }
126
127 PassRefPtr<FormData> FormData::deepCopy() const
128 {
129     RefPtr<FormData> formData(create());
130
131     formData->m_alwaysStream = m_alwaysStream;
132
133     size_t n = m_elements.size();
134     formData->m_elements.reserveInitialCapacity(n);
135     for (size_t i = 0; i < n; ++i) {
136         const FormDataElement& e = m_elements[i];
137         switch (e.m_type) {
138         case FormDataElement::data:
139             formData->m_elements.append(FormDataElement(e.m_data));
140             break;
141         case FormDataElement::encodedFile:
142 #if ENABLE(BLOB)
143             formData->m_elements.append(FormDataElement(e.m_filename, e.m_fileStart, e.m_fileLength, e.m_expectedFileModificationTime, e.m_shouldGenerateFile));
144 #else
145             formData->m_elements.append(FormDataElement(e.m_filename, e.m_shouldGenerateFile));
146 #endif
147             break;
148 #if ENABLE(BLOB)
149         case FormDataElement::encodedBlob:
150             formData->m_elements.append(FormDataElement(e.m_url));
151             break;
152 #endif
153 #if ENABLE(FILE_SYSTEM)
154         case FormDataElement::encodedURL:
155             formData->m_elements.append(FormDataElement(e.m_url, e.m_fileStart, e.m_fileLength, e.m_expectedFileModificationTime));
156             break;
157 #endif
158         }
159     }
160     return formData.release();
161 }
162
163 void FormData::appendData(const void* data, size_t size)
164 {
165     if (m_elements.isEmpty() || m_elements.last().m_type != FormDataElement::data)
166         m_elements.append(FormDataElement());
167     FormDataElement& e = m_elements.last();
168     size_t oldSize = e.m_data.size();
169     e.m_data.grow(oldSize + size);
170     memcpy(e.m_data.data() + oldSize, data, size);
171 }
172
173 void FormData::appendFile(const String& filename, bool shouldGenerateFile)
174 {
175 #if ENABLE(BLOB)
176     m_elements.append(FormDataElement(filename, 0, BlobDataItem::toEndOfFile, invalidFileTime(), shouldGenerateFile));
177 #else
178     m_elements.append(FormDataElement(filename, shouldGenerateFile));
179 #endif
180 }
181
182 #if ENABLE(BLOB)
183 void FormData::appendFileRange(const String& filename, long long start, long long length, double expectedModificationTime, bool shouldGenerateFile)
184 {
185     m_elements.append(FormDataElement(filename, start, length, expectedModificationTime, shouldGenerateFile));
186 }
187
188 void FormData::appendBlob(const KURL& blobURL)
189 {
190     m_elements.append(FormDataElement(blobURL));
191 }
192 #endif
193 #if ENABLE(FILE_SYSTEM)
194 void FormData::appendURL(const KURL& url)
195 {
196     m_elements.append(FormDataElement(url, 0, BlobDataItem::toEndOfFile, invalidFileTime()));
197 }
198
199 void FormData::appendURLRange(const KURL& url, long long start, long long length, double expectedModificationTime)
200 {
201     m_elements.append(FormDataElement(url, start, length, expectedModificationTime));
202 }
203 #endif
204
205 void FormData::appendKeyValuePairItems(const FormDataList& list, const TextEncoding& encoding, bool isMultiPartForm, Document* document, EncodingType encodingType)
206 {
207     if (isMultiPartForm)
208         m_boundary = FormDataBuilder::generateUniqueBoundaryString();
209
210     Vector<char> encodedData;
211
212     const Vector<FormDataList::Item>& items = list.items();
213     size_t formDataListSize = items.size();
214     ASSERT(!(formDataListSize % 2));
215     for (size_t i = 0; i < formDataListSize; i += 2) {
216         const FormDataList::Item& key = items[i];
217         const FormDataList::Item& value = items[i + 1];
218         if (isMultiPartForm) {
219             Vector<char> header;
220             FormDataBuilder::beginMultiPartHeader(header, m_boundary.data(), key.data());
221
222             bool shouldGenerateFile = false;
223
224             // If the current type is blob, then we also need to include the filename
225             if (value.blob()) {
226                 String name;
227                 if (value.blob()->isFile()) {
228                     File* file = toFile(value.blob());
229                     // For file blob, use the filename (or relative path if it is present) as the name.
230 #if ENABLE(DIRECTORY_UPLOAD)                
231                     name = file->webkitRelativePath().isEmpty() ? file->name() : file->webkitRelativePath();
232 #else
233                     name = file->name();
234 #endif
235                     // Let the application specify a filename if it's going to generate a replacement file for the upload.
236                     const String& path = file->path();
237                     if (!path.isEmpty()) {
238                         if (Page* page = document->page()) {
239                             String generatedFileName;
240                             shouldGenerateFile = page->chrome()->client()->shouldReplaceWithGeneratedFileForUpload(path, generatedFileName);
241                             if (shouldGenerateFile)
242                                 name = generatedFileName;
243                         }
244                     }
245
246                     // If a filename is passed in FormData.append(), use it instead of the file blob's name.
247                     if (!value.filename().isNull())
248                         name = value.filename();
249                 } else {
250                     // For non-file blob, use the filename if it is passed in FormData.append().
251                     if (!value.filename().isNull())
252                         name = value.filename();
253                     else
254                         name = "blob";
255                 }
256
257                 // We have to include the filename=".." part in the header, even if the filename is empty
258                 FormDataBuilder::addFilenameToMultiPartHeader(header, encoding, name);
259
260                 // Add the content type if available, or "application/octet-stream" otherwise (RFC 1867).
261                 String contentType;
262                 if (value.blob()->type().isEmpty())
263                     contentType = "application/octet-stream";
264                 else
265                     contentType = value.blob()->type();
266                 FormDataBuilder::addContentTypeToMultiPartHeader(header, contentType.latin1());
267             }
268
269             FormDataBuilder::finishMultiPartHeader(header);
270
271             // Append body
272             appendData(header.data(), header.size());
273             if (value.blob()) {
274                 if (value.blob()->isFile()) {
275                     File* file = toFile(value.blob());
276                     // Do not add the file if the path is empty.
277                     if (!file->path().isEmpty())
278                         appendFile(file->path(), shouldGenerateFile);
279 #if ENABLE(FILE_SYSTEM)
280                     if (!file->fileSystemURL().isEmpty())
281                         appendURL(file->fileSystemURL());
282 #endif
283                 }
284 #if ENABLE(BLOB)
285                 else
286                     appendBlob(value.blob()->url());
287 #endif
288             } else
289                 appendData(value.data().data(), value.data().length());
290             appendData("\r\n", 2);
291         } else {
292             // Omit the name "isindex" if it's the first form data element.
293             // FIXME: Why is this a good rule? Is this obsolete now?
294             if (encodedData.isEmpty() && key.data() == "isindex")
295                 FormDataBuilder::encodeStringAsFormData(encodedData, value.data());
296             else
297                 FormDataBuilder::addKeyValuePairAsFormData(encodedData, key.data(), value.data(), encodingType);
298         }
299     }
300
301     if (isMultiPartForm)
302         FormDataBuilder::addBoundaryToMultiPartHeader(encodedData, m_boundary.data(), true);
303
304     appendData(encodedData.data(), encodedData.size());
305 }
306
307 void FormData::flatten(Vector<char>& data) const
308 {
309     // Concatenate all the byte arrays, but omit any files.
310     data.clear();
311     size_t n = m_elements.size();
312     for (size_t i = 0; i < n; ++i) {
313         const FormDataElement& e = m_elements[i];
314         if (e.m_type == FormDataElement::data)
315             data.append(e.m_data.data(), static_cast<size_t>(e.m_data.size()));
316     }
317 }
318
319 String FormData::flattenToString() const
320 {
321     Vector<char> bytes;
322     flatten(bytes);
323     return Latin1Encoding().decode(reinterpret_cast<const char*>(bytes.data()), bytes.size());
324 }
325
326 #if ENABLE(BLOB)
327 static void appendBlobResolved(FormData* formData, const KURL& url)
328 {
329     if (!blobRegistry().isBlobRegistryImpl()) {
330         LOG_ERROR("Tried to resolve a blob without a usable registry");
331         return;
332     }
333     BlobStorageData* blobData = static_cast<BlobRegistryImpl&>(blobRegistry()).getBlobDataFromURL(KURL(ParsedURLString, url));
334     if (!blobData) {
335         LOG_ERROR("Could not get blob data from a registry");
336         return;
337     }
338
339     BlobDataItemList::const_iterator it = blobData->items().begin();
340     const BlobDataItemList::const_iterator itend = blobData->items().end();
341     for (; it != itend; ++it) {
342         const BlobDataItem& blobItem = *it;
343         if (blobItem.type == BlobDataItem::Data)
344             formData->appendData(blobItem.data->data() + static_cast<int>(blobItem.offset), static_cast<int>(blobItem.length));
345         else if (blobItem.type == BlobDataItem::File)
346             formData->appendFileRange(blobItem.path, blobItem.offset, blobItem.length, blobItem.expectedModificationTime);
347         else if (blobItem.type == BlobDataItem::Blob)
348             appendBlobResolved(formData, blobItem.url);
349         else
350             ASSERT_NOT_REACHED();
351     }
352 }
353
354 PassRefPtr<FormData> FormData::resolveBlobReferences()
355 {
356     // First check if any blobs needs to be resolved, or we can take the fast path.
357     bool hasBlob = false;
358     Vector<FormDataElement>::const_iterator it = elements().begin();
359     const Vector<FormDataElement>::const_iterator itend = elements().end();
360     for (; it != itend; ++it) {
361         if (it->m_type == FormDataElement::encodedBlob) {
362             hasBlob = true;
363             break;
364         }
365     }
366
367     if (!hasBlob)
368         return this;
369
370     // Create a copy to append the result into.
371     RefPtr<FormData> newFormData = FormData::create();
372     newFormData->setAlwaysStream(alwaysStream());
373     newFormData->setIdentifier(identifier());
374     it = elements().begin();
375     for (; it != itend; ++it) {
376         const FormDataElement& element = *it;
377         if (element.m_type == FormDataElement::data)
378             newFormData->appendData(element.m_data.data(), element.m_data.size());
379         else if (element.m_type == FormDataElement::encodedFile)
380             newFormData->appendFileRange(element.m_filename, element.m_fileStart, element.m_fileLength, element.m_expectedFileModificationTime, element.m_shouldGenerateFile);
381         else if (element.m_type == FormDataElement::encodedBlob)
382             appendBlobResolved(newFormData.get(), element.m_url);
383         else
384             ASSERT_NOT_REACHED();
385     }
386     return newFormData.release();
387 }
388 #endif
389
390 void FormData::generateFiles(Document* document)
391 {
392     ASSERT(!m_hasGeneratedFiles);
393
394     if (m_hasGeneratedFiles)
395         return;
396
397     Page* page = document->page();
398     if (!page)
399         return;
400     ChromeClient* client = page->chrome()->client();
401
402     size_t n = m_elements.size();
403     for (size_t i = 0; i < n; ++i) {
404         FormDataElement& e = m_elements[i];
405         if (e.m_type == FormDataElement::encodedFile && e.m_shouldGenerateFile) {
406             e.m_generatedFilename = client->generateReplacementFile(e.m_filename);
407             m_hasGeneratedFiles = true;
408         }
409     }
410 }
411
412 void FormData::removeGeneratedFilesIfNeeded()
413 {
414     if (!m_hasGeneratedFiles)
415         return;
416
417     size_t n = m_elements.size();
418     for (size_t i = 0; i < n; ++i) {
419         FormDataElement& e = m_elements[i];
420         if (e.m_type == FormDataElement::encodedFile && !e.m_generatedFilename.isEmpty()) {
421             ASSERT(e.m_shouldGenerateFile);
422             String directory = directoryName(e.m_generatedFilename);
423             deleteFile(e.m_generatedFilename);
424             deleteEmptyDirectory(directory);
425             e.m_generatedFilename = String();
426         }
427     }
428     m_hasGeneratedFiles = false;
429 }
430
431 void FormData::reportMemoryUsage(MemoryObjectInfo* memoryObjectInfo) const
432 {
433     MemoryClassInfo info(memoryObjectInfo, this, PlatformMemoryTypes::Loader);
434     info.addMember(m_boundary, "boundary");
435     info.addMember(m_elements, "elements");
436 }
437
438 void FormDataElement::reportMemoryUsage(MemoryObjectInfo* memoryObjectInfo) const
439 {
440     MemoryClassInfo info(memoryObjectInfo, this, PlatformMemoryTypes::Loader);
441     info.addMember(m_data, "data");
442     info.addMember(m_filename, "filename");
443 #if ENABLE(BLOB)
444     info.addMember(m_url, "url");
445 #endif
446     info.addMember(m_generatedFilename, "generatedFilename");
447 }
448
449 static void encodeElement(Encoder& encoder, const FormDataElement& element)
450 {
451     encoder.encodeUInt32(element.m_type);
452
453     switch (element.m_type) {
454     case FormDataElement::data:
455         encoder.encodeBytes(reinterpret_cast<const uint8_t*>(element.m_data.data()), element.m_data.size());
456         return;
457
458     case FormDataElement::encodedFile:
459         encoder.encodeString(element.m_filename);
460         encoder.encodeString(element.m_generatedFilename);
461         encoder.encodeBool(element.m_shouldGenerateFile);
462 #if ENABLE(BLOB)
463         encoder.encodeInt64(element.m_fileStart);
464         encoder.encodeInt64(element.m_fileLength);
465         encoder.encodeDouble(element.m_expectedFileModificationTime);
466 #else
467         encoder.encodeInt64(0);
468         encoder.encodeInt64(0);
469         encoder.encodeDouble(invalidFileTime());
470 #endif
471         return;
472
473 #if ENABLE(BLOB)
474     case FormDataElement::encodedBlob:
475         encoder.encodeString(element.m_url.string());
476         return;
477 #endif
478
479 #if ENABLE(FILE_SYSTEM)
480     case FormDataElement::encodedURL:
481         encoder.encodeString(element.m_url.string());
482         encoder.encodeInt64(element.m_fileStart);
483         encoder.encodeInt64(element.m_fileLength);
484         encoder.encodeDouble(element.m_expectedFileModificationTime);
485         return;
486 #endif
487     }
488
489     ASSERT_NOT_REACHED();
490 }
491
492 static bool decodeElement(Decoder& decoder, FormDataElement& element)
493 {
494     uint32_t type;
495     if (!decoder.decodeUInt32(type))
496         return false;
497
498     switch (type) {
499     case FormDataElement::data: {
500         element.m_type = FormDataElement::data;
501         Vector<uint8_t> data;
502         if (!decoder.decodeBytes(data))
503             return false;
504         size_t size = data.size();
505         element.m_data.resize(size);
506         memcpy(element.m_data.data(), data.data(), size);
507         return true;
508     }
509
510     case FormDataElement::encodedFile:
511 #if ENABLE(FILE_SYSTEM)
512     case FormDataElement::encodedURL:
513 #endif
514     {
515         element.m_type = static_cast<FormDataElement::Type>(type);
516         String filenameOrURL;
517         if (!decoder.decodeString(filenameOrURL))
518             return false;
519         if (type == FormDataElement::encodedFile) {
520             if (!decoder.decodeString(element.m_generatedFilename))
521                 return false;
522             if (!decoder.decodeBool(element.m_shouldGenerateFile))
523                 return false;
524         }
525         int64_t fileStart;
526         if (!decoder.decodeInt64(fileStart))
527             return false;
528         if (fileStart < 0)
529             return false;
530         int64_t fileLength;
531         if (!decoder.decodeInt64(fileLength))
532             return false;
533         if (fileLength != BlobDataItem::toEndOfFile && fileLength < fileStart)
534             return false;
535         double expectedFileModificationTime;
536         if (!decoder.decodeDouble(expectedFileModificationTime))
537             return false;
538
539 #if ENABLE(FILE_SYSTEM)
540         if (type == FormDataElement::encodedURL)
541             element.m_url = KURL(KURL(), filenameOrURL);
542         else
543 #endif
544         element.m_filename = filenameOrURL;
545
546 #if ENABLE(BLOB)
547         element.m_fileStart = fileStart;
548         element.m_fileLength = fileLength;
549         element.m_expectedFileModificationTime = expectedFileModificationTime;
550 #endif
551         return true;
552     }
553
554 #if ENABLE(BLOB)
555     case FormDataElement::encodedBlob:
556         element.m_type = FormDataElement::encodedBlob;
557         String blobURLString;
558         if (!decoder.decodeString(blobURLString))
559             return false;
560         element.m_url = KURL(KURL(), blobURLString);
561         return true;
562 #endif
563
564     }
565
566     return false;
567 }
568
569 void FormData::encode(Encoder& encoder) const
570 {
571     encoder.encodeBool(m_alwaysStream);
572
573     encoder.encodeBytes(reinterpret_cast<const uint8_t*>(m_boundary.data()), m_boundary.size());
574
575     size_t size = m_elements.size();
576     encoder.encodeUInt64(size);
577     for (size_t i = 0; i < size; ++i)
578         encodeElement(encoder, m_elements[i]);
579
580     encoder.encodeBool(m_hasGeneratedFiles);
581
582     encoder.encodeInt64(m_identifier);
583 }
584
585 PassRefPtr<FormData> FormData::decode(Decoder& decoder)
586 {
587     RefPtr<FormData> data = FormData::create();
588
589     if (!decoder.decodeBool(data->m_alwaysStream))
590         return 0;
591
592     Vector<uint8_t> boundary;
593     if (!decoder.decodeBytes(boundary))
594         return 0;
595     size_t size = boundary.size();
596     data->m_boundary.resize(size);
597     memcpy(data->m_boundary.data(), boundary.data(), size);
598
599     uint64_t elementsSize;
600     if (!decoder.decodeUInt64(elementsSize))
601         return 0;
602     for (size_t i = 0; i < elementsSize; ++i) {
603         FormDataElement element;
604         if (!decodeElement(decoder, element))
605             return 0;
606         data->m_elements.append(element);
607     }
608
609     if (!decoder.decodeBool(data->m_hasGeneratedFiles))
610         return 0;
611
612     if (!decoder.decodeInt64(data->m_identifier))
613         return 0;
614
615     return data.release();
616 }
617
618 } // namespace WebCore