Home | History | Annotate | Download | only in html
      1 /*
      2  * Copyright (C) 2005, 2006, 2008 Apple Inc. All rights reserved.
      3  *
      4  * This library is free software; you can redistribute it and/or
      5  * modify it under the terms of the GNU Library General Public
      6  * License as published by the Free Software Foundation; either
      7  * version 2 of the License, or (at your option) any later version.
      8  *
      9  * This library is distributed in the hope that it will be useful,
     10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
     11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
     12  * Library General Public License for more details.
     13  *
     14  * You should have received a copy of the GNU Library General Public License
     15  * along with this library; see the file COPYING.LIB.  If not, write to
     16  * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
     17  * Boston, MA 02110-1301, USA.
     18  *
     19  */
     20 
     21 #include "config.h"
     22 #include "core/html/FormDataList.h"
     23 
     24 #include "core/fileapi/File.h"
     25 #include "platform/network/FormDataBuilder.h"
     26 #include "platform/text/LineEnding.h"
     27 
     28 namespace WebCore {
     29 
     30 FormDataList::FormDataList(const WTF::TextEncoding& c)
     31     : m_encoding(c)
     32 {
     33 }
     34 
     35 void FormDataList::appendString(const String& string)
     36 {
     37     CString encodedString = m_encoding.encode(string, WTF::EntitiesForUnencodables);
     38     m_items.append(normalizeLineEndingsToCRLF(encodedString));
     39 }
     40 
     41 void FormDataList::appendString(const CString& string)
     42 {
     43     m_items.append(string);
     44 }
     45 
     46 void FormDataList::appendBlob(PassRefPtrWillBeRawPtr<Blob> blob, const String& filename)
     47 {
     48     m_items.append(Item(blob, filename));
     49 }
     50 
     51 PassRefPtr<FormData> FormDataList::createFormData(FormData::EncodingType encodingType)
     52 {
     53     RefPtr<FormData> result = FormData::create();
     54     appendKeyValuePairItemsTo(result.get(), m_encoding, false, encodingType);
     55     return result.release();
     56 }
     57 
     58 PassRefPtr<FormData> FormDataList::createMultiPartFormData()
     59 {
     60     RefPtr<FormData> result = FormData::create();
     61     appendKeyValuePairItemsTo(result.get(), m_encoding, true);
     62     return result.release();
     63 }
     64 
     65 void FormDataList::appendKeyValuePairItemsTo(FormData* formData, const WTF::TextEncoding& encoding, bool isMultiPartForm, FormData::EncodingType encodingType)
     66 {
     67     if (isMultiPartForm)
     68         formData->setBoundary(FormDataBuilder::generateUniqueBoundaryString());
     69 
     70     Vector<char> encodedData;
     71 
     72     const WillBeHeapVector<Item>& items = this->items();
     73     size_t formDataListSize = items.size();
     74     ASSERT(!(formDataListSize % 2));
     75     for (size_t i = 0; i < formDataListSize; i += 2) {
     76         const FormDataList::Item& key = items[i];
     77         const FormDataList::Item& value = items[i + 1];
     78         if (isMultiPartForm) {
     79             Vector<char> header;
     80             FormDataBuilder::beginMultiPartHeader(header, formData->boundary().data(), key.data());
     81 
     82             // If the current type is blob, then we also need to include the filename
     83             if (value.blob()) {
     84                 String name;
     85                 if (value.blob()->isFile()) {
     86                     File* file = toFile(value.blob());
     87                     // For file blob, use the filename (or relative path if it is present) as the name.
     88                     name = file->webkitRelativePath().isEmpty() ? file->name() : file->webkitRelativePath();
     89 
     90                     // If a filename is passed in FormData.append(), use it instead of the file blob's name.
     91                     if (!value.filename().isNull())
     92                         name = value.filename();
     93                 } else {
     94                     // For non-file blob, use the filename if it is passed in FormData.append().
     95                     if (!value.filename().isNull())
     96                         name = value.filename();
     97                     else
     98                         name = "blob";
     99                 }
    100 
    101                 // We have to include the filename=".." part in the header, even if the filename is empty
    102                 FormDataBuilder::addFilenameToMultiPartHeader(header, encoding, name);
    103 
    104                 // Add the content type if available, or "application/octet-stream" otherwise (RFC 1867).
    105                 String contentType;
    106                 if (value.blob()->type().isEmpty())
    107                     contentType = "application/octet-stream";
    108                 else
    109                     contentType = value.blob()->type();
    110                 FormDataBuilder::addContentTypeToMultiPartHeader(header, contentType.latin1());
    111             }
    112 
    113             FormDataBuilder::finishMultiPartHeader(header);
    114 
    115             // Append body
    116             formData->appendData(header.data(), header.size());
    117             if (value.blob()) {
    118                 if (value.blob()->hasBackingFile()) {
    119                     File* file = toFile(value.blob());
    120                     // Do not add the file if the path is empty.
    121                     if (!file->path().isEmpty())
    122                         formData->appendFile(file->path());
    123                     if (!file->fileSystemURL().isEmpty())
    124                         formData->appendFileSystemURL(file->fileSystemURL());
    125                 } else {
    126                     formData->appendBlob(value.blob()->uuid(), value.blob()->blobDataHandle());
    127                 }
    128             } else {
    129                 formData->appendData(value.data().data(), value.data().length());
    130             }
    131             formData->appendData("\r\n", 2);
    132         } else {
    133             FormDataBuilder::addKeyValuePairAsFormData(encodedData, key.data(), value.data(), encodingType);
    134         }
    135     }
    136 
    137     if (isMultiPartForm)
    138         FormDataBuilder::addBoundaryToMultiPartHeader(encodedData, formData->boundary().data(), true);
    139 
    140     formData->appendData(encodedData.data(), encodedData.size());
    141 }
    142 
    143 void FormDataList::trace(Visitor* visitor)
    144 {
    145     visitor->trace(m_items);
    146 }
    147 
    148 void FormDataList::Item::trace(Visitor* visitor)
    149 {
    150     visitor->trace(m_blob);
    151 }
    152 
    153 } // namespace
    154