18e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project/*
28e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project * Copyright (C) 2005, 2006, 2008 Apple Inc.  All rights reserved.
38e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project *
48e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project * Redistribution and use in source and binary forms, with or without
58e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project * modification, are permitted provided that the following conditions
68e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project * are met:
78e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project *
88e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project * 1.  Redistributions of source code must retain the above copyright
98e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project *     notice, this list of conditions and the following disclaimer.
108e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project * 2.  Redistributions in binary form must reproduce the above copyright
118e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project *     notice, this list of conditions and the following disclaimer in the
128e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project *     documentation and/or other materials provided with the distribution.
138e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project * 3.  Neither the name of Apple Computer, Inc. ("Apple") nor the names of
148e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project *     its contributors may be used to endorse or promote products derived
158e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project *     from this software without specific prior written permission.
168e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project *
178e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
188e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
198e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
208e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
218e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
228e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
238e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
248e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
258e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
268e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
278e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project */
288e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
298e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project/* originally written by Becky Willrich, additional code by Darin Adler */
308e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
318e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project#import "config.h"
328e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project#import "FormDataStreamMac.h"
338e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
34cad810f21b803229eb11403f9209855525a25d57Steve Block#if !USE(CFNETWORK)
35cad810f21b803229eb11403f9209855525a25d57Steve Block
365ddde30071f639962dd557c453f2ad01f8f0fd00Kristian Monsen#import "BlobRegistryImpl.h"
370bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch#import "FileSystem.h"
388e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project#import "FormData.h"
398e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project#import "ResourceHandle.h"
408e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project#import "ResourceHandleClient.h"
418e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project#import "SchedulePair.h"
428e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project#import "WebCoreSystemInterface.h"
438e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project#import <sys/stat.h>
448e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project#import <sys/types.h>
458e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project#import <wtf/Assertions.h>
468e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project#import <wtf/HashMap.h>
478e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project#import <wtf/MainThread.h>
48635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project#import <wtf/StdLibExtras.h>
498e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project#import <wtf/Threading.h>
508e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
51e14391e94c850b8bd03680c23b38978db68687a8John Reck#if PLATFORM(IOS)
52e14391e94c850b8bd03680c23b38978db68687a8John Reck#import <MacErrors.h>
53e14391e94c850b8bd03680c23b38978db68687a8John Reck#else
54e14391e94c850b8bd03680c23b38978db68687a8John Reck#import <CoreServices/CoreServices.h>
55e14391e94c850b8bd03680c23b38978db68687a8John Reck#endif
56e14391e94c850b8bd03680c23b38978db68687a8John Reck
578e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Projectnamespace WebCore {
588e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
598e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Projecttypedef HashMap<CFReadStreamRef, RefPtr<FormData> > StreamFormDataMap;
608e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Projectstatic StreamFormDataMap& getStreamFormDataMap()
618e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
62635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    DEFINE_STATIC_LOCAL(StreamFormDataMap, streamFormDataMap, ());
638e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    return streamFormDataMap;
648e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
658e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
668e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Projecttypedef HashMap<CFReadStreamRef, RefPtr<ResourceHandle> > StreamResourceHandleMap;
678e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Projectstatic StreamResourceHandleMap& getStreamResourceHandleMap()
688e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
69635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    DEFINE_STATIC_LOCAL(StreamResourceHandleMap, streamResourceHandleMap, ());
708e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    return streamResourceHandleMap;
718e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
728e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
738e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Projectvoid associateStreamWithResourceHandle(NSInputStream *stream, ResourceHandle* resourceHandle)
748e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
758e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    ASSERT(isMainThread());
768e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
778e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    ASSERT(resourceHandle);
788e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
798e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    if (!stream)
808e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        return;
818e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
828e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    if (!getStreamFormDataMap().contains((CFReadStreamRef)stream))
838e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        return;
848e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
858e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    ASSERT(!getStreamResourceHandleMap().contains((CFReadStreamRef)stream));
868e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    getStreamResourceHandleMap().set((CFReadStreamRef)stream, resourceHandle);
878e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
888e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
898e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Projectvoid disassociateStreamWithResourceHandle(NSInputStream *stream)
908e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
918e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    ASSERT(isMainThread());
928e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
938e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    if (!stream)
948e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        return;
958e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
968e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    getStreamResourceHandleMap().remove((CFReadStreamRef)stream);
978e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
988e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
998e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Projectstruct DidSendDataCallbackData {
1008e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    DidSendDataCallbackData(CFReadStreamRef stream_, unsigned long long bytesSent_, unsigned long long streamLength_)
1018e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        : stream(stream_)
1028e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        , bytesSent(bytesSent_)
1038e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        , streamLength(streamLength_)
1048e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    {
1058e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    }
1068e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
1078e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    CFReadStreamRef stream;
1088e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    unsigned long long bytesSent;
1098e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    unsigned long long streamLength;
1108e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project};
1118e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
1128e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Projectstatic void performDidSendDataCallback(void* context)
1138e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
1148e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    ASSERT(isMainThread());
1158e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
1168e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    DidSendDataCallbackData* data = static_cast<DidSendDataCallbackData*>(context);
1178e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    ResourceHandle* resourceHandle = getStreamResourceHandleMap().get(data->stream).get();
1188e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
1198e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    if (resourceHandle && resourceHandle->client())
1208e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        resourceHandle->client()->didSendData(resourceHandle, data->bytesSent, data->streamLength);
1218e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
1228e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    delete data;
1238e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
1248e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
1258e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Projectstatic void formEventCallback(CFReadStreamRef stream, CFStreamEventType type, void* context);
1268e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
1278e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Projectstruct FormContext {
1288e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    FormData* formData;
1298e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    unsigned long long streamLength;
1308e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project};
1318e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
1328e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Projectstruct FormStreamFields {
1338e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    SchedulePairHashSet scheduledRunLoopPairs;
1348e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    Vector<FormDataElement> remainingElements; // in reverse order
1358e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    CFReadStreamRef currentStream;
136dd8bb3de4f353a81954234999f1fea748aee2ea9Ben Murdoch#if ENABLE(BLOB)
137dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    long long currentStreamRangeLength;
138dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block#endif
1398e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    char* currentData;
1408e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    CFReadStreamRef formStream;
1418e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    unsigned long long streamLength;
1428e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    unsigned long long bytesSent;
1438e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project};
1448e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
1458e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Projectstatic void closeCurrentStream(FormStreamFields *form)
1468e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
1478e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    if (form->currentStream) {
1488e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        CFReadStreamClose(form->currentStream);
1498e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        CFReadStreamSetClient(form->currentStream, kCFStreamEventNone, NULL, NULL);
1508e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        CFRelease(form->currentStream);
1518e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        form->currentStream = NULL;
152dd8bb3de4f353a81954234999f1fea748aee2ea9Ben Murdoch#if ENABLE(BLOB)
1535ddde30071f639962dd557c453f2ad01f8f0fd00Kristian Monsen        form->currentStreamRangeLength = BlobDataItem::toEndOfFile;
154dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block#endif
1558e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    }
1568e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    if (form->currentData) {
1578e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        fastFree(form->currentData);
1588e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        form->currentData = 0;
1598e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    }
1608e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
1618e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
162545e470e52f0ac6a3a072bf559c796b42c6066b6Ben Murdoch// Return false if we cannot advance the stream. Currently the only possible failure is that the underlying file has been removed or changed since File.slice.
163dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Blockstatic bool advanceCurrentStream(FormStreamFields* form)
1648e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
1658e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    closeCurrentStream(form);
1668e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
1678e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    if (form->remainingElements.isEmpty())
168dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block        return true;
1698e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
1708e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    // Create the new stream.
1718e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    FormDataElement& nextInput = form->remainingElements.last();
172545e470e52f0ac6a3a072bf559c796b42c6066b6Ben Murdoch
1738e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    if (nextInput.m_type == FormDataElement::data) {
1748e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        size_t size = nextInput.m_data.size();
1758e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        char* data = nextInput.m_data.releaseBuffer();
1768e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        form->currentStream = CFReadStreamCreateWithBytesNoCopy(0, reinterpret_cast<const UInt8*>(data), size, kCFAllocatorNull);
1778e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        form->currentData = data;
1788e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    } else {
179dd8bb3de4f353a81954234999f1fea748aee2ea9Ben Murdoch#if ENABLE(BLOB)
180dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block        // Check if the file has been changed or not if required.
1815ddde30071f639962dd557c453f2ad01f8f0fd00Kristian Monsen        if (nextInput.m_expectedFileModificationTime != BlobDataItem::doNotCheckFileChange) {
182dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block            time_t fileModificationTime;
183dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block            if (!getFileModificationTime(nextInput.m_filename, fileModificationTime) || fileModificationTime != static_cast<time_t>(nextInput.m_expectedFileModificationTime))
184dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block                return false;
185dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block        }
186dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block#endif
1878e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        const String& path = nextInput.m_shouldGenerateFile ? nextInput.m_generatedFilename : nextInput.m_filename;
1882fc2651226baac27029e38c9d6ef883fa32084dbSteve Block        form->currentStream = CFReadStreamCreateWithFile(0, pathAsURL(path).get());
189545e470e52f0ac6a3a072bf559c796b42c6066b6Ben Murdoch        if (!form->currentStream) {
190545e470e52f0ac6a3a072bf559c796b42c6066b6Ben Murdoch            // The file must have been removed or become unreadable.
191545e470e52f0ac6a3a072bf559c796b42c6066b6Ben Murdoch            return false;
192545e470e52f0ac6a3a072bf559c796b42c6066b6Ben Murdoch        }
193dd8bb3de4f353a81954234999f1fea748aee2ea9Ben Murdoch#if ENABLE(BLOB)
194dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block        if (nextInput.m_fileStart > 0) {
1952bde8e466a4451c7319e3a072d118917957d6554Steve Block            RetainPtr<CFNumberRef> position(AdoptCF, CFNumberCreate(0, kCFNumberLongLongType, &nextInput.m_fileStart));
1962bde8e466a4451c7319e3a072d118917957d6554Steve Block            CFReadStreamSetProperty(form->currentStream, kCFStreamPropertyFileCurrentOffset, position.get());
197dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block        }
198dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block        form->currentStreamRangeLength = nextInput.m_fileLength;
199dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block#endif
2008e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    }
2018e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    form->remainingElements.removeLast();
2028e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
2038e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    // Set up the callback.
2048e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    CFStreamClientContext context = { 0, form, NULL, NULL, NULL };
2058e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    CFReadStreamSetClient(form->currentStream, kCFStreamEventHasBytesAvailable | kCFStreamEventErrorOccurred | kCFStreamEventEndEncountered,
2068e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        formEventCallback, &context);
2078e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
2088e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    // Schedule with the current set of run loops.
2098e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    SchedulePairHashSet::iterator end = form->scheduledRunLoopPairs.end();
2108e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    for (SchedulePairHashSet::iterator it = form->scheduledRunLoopPairs.begin(); it != end; ++it)
2118e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        CFReadStreamScheduleWithRunLoop(form->currentStream, (*it)->runLoop(), (*it)->mode());
212dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block
213dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    return true;
2148e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
2158e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
216dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Blockstatic bool openNextStream(FormStreamFields* form)
2178e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
2188e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    // Skip over any streams we can't open.
219dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    if (!advanceCurrentStream(form))
220dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block        return false;
221dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    while (form->currentStream && !CFReadStreamOpen(form->currentStream)) {
222dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block        if (!advanceCurrentStream(form))
223dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block            return false;
224dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    }
225dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    return true;
2268e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
2278e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
2288e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Projectstatic void* formCreate(CFReadStreamRef stream, void* context)
2298e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
2308e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    FormContext* formContext = static_cast<FormContext*>(context);
2318e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
2328e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    FormStreamFields* newInfo = new FormStreamFields;
2338e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    newInfo->currentStream = NULL;
234dd8bb3de4f353a81954234999f1fea748aee2ea9Ben Murdoch#if ENABLE(BLOB)
2355ddde30071f639962dd557c453f2ad01f8f0fd00Kristian Monsen    newInfo->currentStreamRangeLength = BlobDataItem::toEndOfFile;
236dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block#endif
2378e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    newInfo->currentData = 0;
2388e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    newInfo->formStream = stream; // Don't retain. That would create a reference cycle.
2398e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    newInfo->streamLength = formContext->streamLength;
2408e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    newInfo->bytesSent = 0;
2418e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
2428e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    FormData* formData = formContext->formData;
2438e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
2448e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    // Append in reverse order since we remove elements from the end.
2458e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    size_t size = formData->elements().size();
2468f72e70a9fd78eec56623b3a62e68f16b7b27e28Feng Qian    newInfo->remainingElements.reserveInitialCapacity(size);
2478e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    for (size_t i = 0; i < size; ++i)
2488e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        newInfo->remainingElements.append(formData->elements()[size - i - 1]);
2498e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
2508e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    getStreamFormDataMap().set(stream, adoptRef(formData));
2518e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
2528e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    return newInfo;
2538e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
2548e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
2558e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Projectstatic void formFinalize(CFReadStreamRef stream, void* context)
2568e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
2578e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    FormStreamFields* form = static_cast<FormStreamFields*>(context);
2588e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
2598e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    getStreamFormDataMap().remove(stream);
2608e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
2618e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    closeCurrentStream(form);
2628e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    delete form;
2638e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
2648e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
265635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Projectstatic Boolean formOpen(CFReadStreamRef, CFStreamError* error, Boolean* openComplete, void* context)
2668e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
2678e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    FormStreamFields* form = static_cast<FormStreamFields*>(context);
2688e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
269dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    bool opened = openNextStream(form);
2708e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
271dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    *openComplete = opened;
272dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    error->error = opened ? 0 : fnfErr;
273dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    return opened;
2748e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
2758e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
2768e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Projectstatic CFIndex formRead(CFReadStreamRef stream, UInt8* buffer, CFIndex bufferLength, CFStreamError* error, Boolean* atEOF, void* context)
2778e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
2788e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    FormStreamFields* form = static_cast<FormStreamFields*>(context);
2798e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
2808e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    while (form->currentStream) {
281dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block        CFIndex bytesToRead = bufferLength;
282dd8bb3de4f353a81954234999f1fea748aee2ea9Ben Murdoch#if ENABLE(BLOB)
2835ddde30071f639962dd557c453f2ad01f8f0fd00Kristian Monsen        if (form->currentStreamRangeLength != BlobDataItem::toEndOfFile && form->currentStreamRangeLength < bytesToRead)
284dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block            bytesToRead = static_cast<CFIndex>(form->currentStreamRangeLength);
285dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block#endif
286dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block        CFIndex bytesRead = CFReadStreamRead(form->currentStream, buffer, bytesToRead);
2878e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        if (bytesRead < 0) {
2888e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            *error = CFReadStreamGetError(form->currentStream);
2898e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            return -1;
2908e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        }
2918e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        if (bytesRead > 0) {
2928e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            error->error = 0;
2938e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            *atEOF = FALSE;
2948e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            form->bytesSent += bytesRead;
295dd8bb3de4f353a81954234999f1fea748aee2ea9Ben Murdoch#if ENABLE(BLOB)
2965ddde30071f639962dd557c453f2ad01f8f0fd00Kristian Monsen            if (form->currentStreamRangeLength != BlobDataItem::toEndOfFile)
297dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block                form->currentStreamRangeLength -= bytesRead;
298dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block#endif
2998e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
3008e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            if (!ResourceHandle::didSendBodyDataDelegateExists()) {
3018e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project                // FIXME: Figure out how to only do this when a ResourceHandleClient is available.
3028e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project                DidSendDataCallbackData* data = new DidSendDataCallbackData(stream, form->bytesSent, form->streamLength);
3038e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project                callOnMainThread(performDidSendDataCallback, data);
3048e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            }
3058e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
3068e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            return bytesRead;
3078e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        }
3088e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        openNextStream(form);
3098e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    }
3108e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
3118e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    error->error = 0;
3128e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    *atEOF = TRUE;
3138e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    return 0;
3148e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
3158e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
3168e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Projectstatic Boolean formCanRead(CFReadStreamRef stream, void* context)
3178e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
3188e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    FormStreamFields* form = static_cast<FormStreamFields*>(context);
3198e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
3208e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    while (form->currentStream && CFReadStreamGetStatus(form->currentStream) == kCFStreamStatusAtEnd) {
3218e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        openNextStream(form);
3228e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    }
3238e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    if (!form->currentStream) {
3248e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        wkSignalCFReadStreamEnd(stream);
3258e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        return FALSE;
3268e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    }
3278e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    return CFReadStreamHasBytesAvailable(form->currentStream);
3288e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
3298e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
330635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Projectstatic void formClose(CFReadStreamRef, void* context)
3318e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
3328e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    FormStreamFields* form = static_cast<FormStreamFields*>(context);
3338e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
3348e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    closeCurrentStream(form);
3358e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
3368e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
337635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Projectstatic void formSchedule(CFReadStreamRef, CFRunLoopRef runLoop, CFStringRef runLoopMode, void* context)
3388e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
3398e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    FormStreamFields* form = static_cast<FormStreamFields*>(context);
3408e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
3418e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    if (form->currentStream)
3428e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        CFReadStreamScheduleWithRunLoop(form->currentStream, runLoop, runLoopMode);
3438e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    form->scheduledRunLoopPairs.add(SchedulePair::create(runLoop, runLoopMode));
3448e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
3458e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
346635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Projectstatic void formUnschedule(CFReadStreamRef, CFRunLoopRef runLoop, CFStringRef runLoopMode, void* context)
3478e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
3488e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    FormStreamFields* form = static_cast<FormStreamFields*>(context);
3498e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
3508e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    if (form->currentStream)
3518e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        CFReadStreamUnscheduleFromRunLoop(form->currentStream, runLoop, runLoopMode);
3528e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    form->scheduledRunLoopPairs.remove(SchedulePair::create(runLoop, runLoopMode));
3538e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
3548e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
3558e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Projectstatic void formEventCallback(CFReadStreamRef stream, CFStreamEventType type, void* context)
3568e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
3578e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    FormStreamFields* form = static_cast<FormStreamFields*>(context);
3588e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
3598e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    switch (type) {
3608e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    case kCFStreamEventHasBytesAvailable:
3618e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        wkSignalCFReadStreamHasBytes(form->formStream);
3628e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        break;
3638e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    case kCFStreamEventErrorOccurred: {
3648e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        CFStreamError readStreamError = CFReadStreamGetError(stream);
3658e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        wkSignalCFReadStreamError(form->formStream, &readStreamError);
3668e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        break;
3678e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    }
3688e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    case kCFStreamEventEndEncountered:
3698e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        openNextStream(form);
3708e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        if (!form->currentStream) {
3718e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            wkSignalCFReadStreamEnd(form->formStream);
3728e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        }
3738e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        break;
3748e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    case kCFStreamEventNone:
3758e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        LOG_ERROR("unexpected kCFStreamEventNone");
3768e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        break;
3778e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    case kCFStreamEventOpenCompleted:
3788e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        LOG_ERROR("unexpected kCFStreamEventOpenCompleted");
3798e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        break;
3808e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    case kCFStreamEventCanAcceptBytes:
3818e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        LOG_ERROR("unexpected kCFStreamEventCanAcceptBytes");
3828e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        break;
3838e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    }
3848e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
3858e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
3868e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Projectvoid setHTTPBody(NSMutableURLRequest *request, PassRefPtr<FormData> formData)
3878e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
3888e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    if (!formData)
3898e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        return;
3908e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
3918e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    size_t count = formData->elements().size();
3928e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
3938e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    // Handle the common special case of one piece of form data, with no files.
3948e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    if (count == 1 && !formData->alwaysStream()) {
3958e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        const FormDataElement& element = formData->elements()[0];
3968e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        if (element.m_type == FormDataElement::data) {
3978e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            NSData *data = [[NSData alloc] initWithBytes:element.m_data.data() length:element.m_data.size()];
3988e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            [request setHTTPBody:data];
3998e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            [data release];
4008e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            return;
4018e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        }
4028e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    }
4038e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
4045ddde30071f639962dd557c453f2ad01f8f0fd00Kristian Monsen#if ENABLE(BLOB)
4055ddde30071f639962dd557c453f2ad01f8f0fd00Kristian Monsen    // Check if there is a blob in the form data.
4065ddde30071f639962dd557c453f2ad01f8f0fd00Kristian Monsen    bool hasBlob = false;
4075ddde30071f639962dd557c453f2ad01f8f0fd00Kristian Monsen    for (size_t i = 0; i < count; ++i) {
4085ddde30071f639962dd557c453f2ad01f8f0fd00Kristian Monsen        const FormDataElement& element = formData->elements()[i];
4095ddde30071f639962dd557c453f2ad01f8f0fd00Kristian Monsen        if (element.m_type == FormDataElement::encodedBlob) {
4105ddde30071f639962dd557c453f2ad01f8f0fd00Kristian Monsen            hasBlob = true;
4115ddde30071f639962dd557c453f2ad01f8f0fd00Kristian Monsen            break;
4125ddde30071f639962dd557c453f2ad01f8f0fd00Kristian Monsen        }
4135ddde30071f639962dd557c453f2ad01f8f0fd00Kristian Monsen    }
4145ddde30071f639962dd557c453f2ad01f8f0fd00Kristian Monsen
4155ddde30071f639962dd557c453f2ad01f8f0fd00Kristian Monsen    // If yes, we have to resolve all the blob references and regenerate the form data with only data and file types.
4165ddde30071f639962dd557c453f2ad01f8f0fd00Kristian Monsen    if (hasBlob) {
4175ddde30071f639962dd557c453f2ad01f8f0fd00Kristian Monsen        RefPtr<FormData> newFormData = FormData::create();
4185ddde30071f639962dd557c453f2ad01f8f0fd00Kristian Monsen        newFormData->setAlwaysStream(formData->alwaysStream());
4195ddde30071f639962dd557c453f2ad01f8f0fd00Kristian Monsen        newFormData->setIdentifier(formData->identifier());
4205ddde30071f639962dd557c453f2ad01f8f0fd00Kristian Monsen        for (size_t i = 0; i < count; ++i) {
4215ddde30071f639962dd557c453f2ad01f8f0fd00Kristian Monsen            const FormDataElement& element = formData->elements()[i];
4225ddde30071f639962dd557c453f2ad01f8f0fd00Kristian Monsen            if (element.m_type == FormDataElement::data)
4235ddde30071f639962dd557c453f2ad01f8f0fd00Kristian Monsen                newFormData->appendData(element.m_data.data(), element.m_data.size());
4245ddde30071f639962dd557c453f2ad01f8f0fd00Kristian Monsen            else if (element.m_type == FormDataElement::encodedFile)
4255ddde30071f639962dd557c453f2ad01f8f0fd00Kristian Monsen                newFormData->appendFile(element.m_filename, element.m_shouldGenerateFile);
4265ddde30071f639962dd557c453f2ad01f8f0fd00Kristian Monsen            else {
4275ddde30071f639962dd557c453f2ad01f8f0fd00Kristian Monsen                ASSERT(element.m_type == FormDataElement::encodedBlob);
4285ddde30071f639962dd557c453f2ad01f8f0fd00Kristian Monsen                RefPtr<BlobStorageData> blobData = static_cast<BlobRegistryImpl&>(blobRegistry()).getBlobDataFromURL(KURL(ParsedURLString, element.m_blobURL));
4295ddde30071f639962dd557c453f2ad01f8f0fd00Kristian Monsen                if (blobData) {
4305ddde30071f639962dd557c453f2ad01f8f0fd00Kristian Monsen                    for (size_t j = 0; j < blobData->items().size(); ++j) {
4315ddde30071f639962dd557c453f2ad01f8f0fd00Kristian Monsen                        const BlobDataItem& blobItem = blobData->items()[j];
4325ddde30071f639962dd557c453f2ad01f8f0fd00Kristian Monsen                        if (blobItem.type == BlobDataItem::Data) {
433a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch                            newFormData->appendData(blobItem.data->data() + static_cast<int>(blobItem.offset), static_cast<int>(blobItem.length));
4345ddde30071f639962dd557c453f2ad01f8f0fd00Kristian Monsen                        } else {
4355ddde30071f639962dd557c453f2ad01f8f0fd00Kristian Monsen                            ASSERT(blobItem.type == BlobDataItem::File);
4365ddde30071f639962dd557c453f2ad01f8f0fd00Kristian Monsen                            newFormData->appendFileRange(blobItem.path, blobItem.offset, blobItem.length, blobItem.expectedModificationTime);
4375ddde30071f639962dd557c453f2ad01f8f0fd00Kristian Monsen                        }
4385ddde30071f639962dd557c453f2ad01f8f0fd00Kristian Monsen                    }
4395ddde30071f639962dd557c453f2ad01f8f0fd00Kristian Monsen                }
4405ddde30071f639962dd557c453f2ad01f8f0fd00Kristian Monsen            }
4415ddde30071f639962dd557c453f2ad01f8f0fd00Kristian Monsen        }
4425ddde30071f639962dd557c453f2ad01f8f0fd00Kristian Monsen        formData = newFormData;
4435ddde30071f639962dd557c453f2ad01f8f0fd00Kristian Monsen        count = formData->elements().size();
4445ddde30071f639962dd557c453f2ad01f8f0fd00Kristian Monsen    }
4455ddde30071f639962dd557c453f2ad01f8f0fd00Kristian Monsen#endif
4465ddde30071f639962dd557c453f2ad01f8f0fd00Kristian Monsen
4478e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    // Precompute the content length so NSURLConnection doesn't use chunked mode.
4488e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    long long length = 0;
4498e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    for (size_t i = 0; i < count; ++i) {
4508e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        const FormDataElement& element = formData->elements()[i];
4518e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        if (element.m_type == FormDataElement::data)
4528e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            length += element.m_data.size();
4538e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        else {
454dd8bb3de4f353a81954234999f1fea748aee2ea9Ben Murdoch#if ENABLE(BLOB)
455dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block            // If we're sending the file range, use the existing range length for now. We will detect if the file has been changed right before we read the file and abort the operation if necessary.
4565ddde30071f639962dd557c453f2ad01f8f0fd00Kristian Monsen            if (element.m_fileLength != BlobDataItem::toEndOfFile) {
457dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block                length += element.m_fileLength;
458dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block                continue;
459dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block            }
460dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block#endif
4610bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch            long long fileSize;
4620bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch            if (getFileSize(element.m_shouldGenerateFile ? element.m_generatedFilename : element.m_filename, fileSize))
4630bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch                length += fileSize;
4648e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        }
4658e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    }
4668e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
4678e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    // Set the length.
4688e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    [request setValue:[NSString stringWithFormat:@"%lld", length] forHTTPHeaderField:@"Content-Length"];
4698e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
4708e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    // Create and set the stream.
4718e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
4728e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    // Pass the length along with the formData so it does not have to be recomputed.
4738e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    FormContext formContext = { formData.releaseRef(), length };
4748e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
475231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block    RetainPtr<CFReadStreamRef> stream(AdoptCF, wkCreateCustomCFReadStream(formCreate, formFinalize,
4768e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        formOpen, formRead, formCanRead, formClose, formSchedule, formUnschedule,
477231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block        &formContext));
478231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block    [request setHTTPBodyStream:(NSInputStream *)stream.get()];
4798e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
4808e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
4818e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source ProjectFormData* httpBodyFromStream(NSInputStream* stream)
4828e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
4838e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    return getStreamFormDataMap().get((CFReadStreamRef)stream).get();
4848e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
4858e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
4868e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project} // namespace WebCore
487cad810f21b803229eb11403f9209855525a25d57Steve Block
488cad810f21b803229eb11403f9209855525a25d57Steve Block#endif // !USE(CFNETWORK)
489