• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2005, 2006, 2007 Apple Inc.  All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  *
8  * 1.  Redistributions of source code must retain the above copyright
9  *     notice, this list of conditions and the following disclaimer.
10  * 2.  Redistributions in binary form must reproduce the above copyright
11  *     notice, this list of conditions and the following disclaimer in the
12  *     documentation and/or other materials provided with the distribution.
13  * 3.  Neither the name of Apple Computer, Inc. ("Apple") nor the names of
14  *     its contributors may be used to endorse or promote products derived
15  *     from this software without specific prior written permission.
16  *
17  * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
18  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
19  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
20  * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
21  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
22  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
23  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
24  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27  */
28 
29 /* originally written by Becky Willrich, additional code by Darin Adler */
30 
31 #include "config.h"
32 #include "FormDataStreamCFNet.h"
33 
34 #include "CString.h"
35 #include "FileSystem.h"
36 #include "FormData.h"
37 #include <CFNetwork/CFURLRequestPriv.h>
38 #include <CoreFoundation/CFStreamAbstract.h>
39 #include <WebKitSystemInterface/WebKitSystemInterface.h>
40 #include <sys/types.h>
41 #include <wtf/Assertions.h>
42 #include <wtf/HashMap.h>
43 #include <wtf/RetainPtr.h>
44 
45 #define USE_V1_CFSTREAM_CALLBACKS
46 #ifdef USE_V1_CFSTREAM_CALLBACKS
47 typedef CFReadStreamCallBacksV1 WCReadStreamCallBacks;
48 #else
49 typedef CFReadStreamCallBacks WCReadStreamCallBacks;
50 #endif
51 
52 namespace WebCore {
53 
getStreamFormDatas()54 static HashMap<CFReadStreamRef, RefPtr<FormData> >& getStreamFormDatas()
55 {
56     static HashMap<CFReadStreamRef, RefPtr<FormData> > streamFormDatas;
57     return streamFormDatas;
58 }
59 
60 static void formEventCallback(CFReadStreamRef stream, CFStreamEventType type, void* context);
61 
62 struct FormStreamFields {
63     CFMutableSetRef scheduledRunLoopPairs;
64     Vector<FormDataElement> remainingElements; // in reverse order
65     CFReadStreamRef currentStream;
66     char* currentData;
67     CFReadStreamRef formStream;
68 };
69 
70 struct SchedulePair {
71     CFRunLoopRef runLoop;
72     CFStringRef mode;
73 };
74 
pairRetain(CFAllocatorRef alloc,const void * value)75 static const void* pairRetain(CFAllocatorRef alloc, const void* value)
76 {
77     const SchedulePair* pair = static_cast<const SchedulePair*>(value);
78 
79     SchedulePair* result = new SchedulePair;
80     CFRetain(pair->runLoop);
81     result->runLoop = pair->runLoop;
82     result->mode = CFStringCreateCopy(alloc, pair->mode);
83     return result;
84 }
85 
pairRelease(CFAllocatorRef alloc,const void * value)86 static void pairRelease(CFAllocatorRef alloc, const void* value)
87 {
88     const SchedulePair* pair = static_cast<const SchedulePair*>(value);
89 
90     CFRelease(pair->runLoop);
91     CFRelease(pair->mode);
92     delete pair;
93 }
94 
pairEqual(const void * a,const void * b)95 static Boolean pairEqual(const void* a, const void* b)
96 {
97     const SchedulePair* pairA = static_cast<const SchedulePair*>(a);
98     const SchedulePair* pairB = static_cast<const SchedulePair*>(b);
99 
100     return pairA->runLoop == pairB->runLoop && CFEqual(pairA->mode, pairB->mode);
101 }
102 
pairHash(const void * value)103 static CFHashCode pairHash(const void* value)
104 {
105     const SchedulePair* pair = static_cast<const SchedulePair*>(value);
106 
107     return (CFHashCode)pair->runLoop ^ CFHash(pair->mode);
108 }
109 
closeCurrentStream(FormStreamFields * form)110 static void closeCurrentStream(FormStreamFields *form)
111 {
112     if (form->currentStream) {
113         CFReadStreamClose(form->currentStream);
114         CFReadStreamSetClient(form->currentStream, kCFStreamEventNone, NULL, NULL);
115         CFRelease(form->currentStream);
116         form->currentStream = NULL;
117     }
118     if (form->currentData) {
119         fastFree(form->currentData);
120         form->currentData = 0;
121     }
122 }
123 
scheduleWithPair(const void * value,void * context)124 static void scheduleWithPair(const void* value, void* context)
125 {
126     const SchedulePair* pair = static_cast<const SchedulePair*>(value);
127     CFReadStreamRef stream = (CFReadStreamRef)context;
128 
129     CFReadStreamScheduleWithRunLoop(stream, pair->runLoop, pair->mode);
130 }
131 
advanceCurrentStream(FormStreamFields * form)132 static void advanceCurrentStream(FormStreamFields *form)
133 {
134     closeCurrentStream(form);
135 
136     if (form->remainingElements.isEmpty())
137         return;
138 
139     // Create the new stream.
140     FormDataElement& nextInput = form->remainingElements.last();
141     if (nextInput.m_type == FormDataElement::data) {
142         size_t size = nextInput.m_data.size();
143         char* data = nextInput.m_data.releaseBuffer();
144         form->currentStream = CFReadStreamCreateWithBytesNoCopy(0, reinterpret_cast<const UInt8*>(data), size, kCFAllocatorNull);
145         form->currentData = data;
146     } else {
147         CFStringRef filename = nextInput.m_filename.createCFString();
148 #if PLATFORM(WIN)
149         CFURLRef fileURL = CFURLCreateWithFileSystemPath(0, filename, kCFURLWindowsPathStyle, FALSE);
150 #else
151         CFURLRef fileURL = CFURLCreateWithFileSystemPath(0, filename, kCFURLPOSIXPathStyle, FALSE);
152 #endif
153         CFRelease(filename);
154         form->currentStream = CFReadStreamCreateWithFile(0, fileURL);
155         CFRelease(fileURL);
156     }
157     form->remainingElements.removeLast();
158 
159     // Set up the callback.
160     CFStreamClientContext context = { 0, form, NULL, NULL, NULL };
161     CFReadStreamSetClient(form->currentStream, kCFStreamEventHasBytesAvailable | kCFStreamEventErrorOccurred | kCFStreamEventEndEncountered,
162         formEventCallback, &context);
163 
164     // Schedule with the current set of run loops.
165     CFSetApplyFunction(form->scheduledRunLoopPairs, scheduleWithPair, form->currentStream);
166 }
167 
openNextStream(FormStreamFields * form)168 static void openNextStream(FormStreamFields* form)
169 {
170     // Skip over any streams we can't open.
171     // For some purposes we might want to return an error, but the current CFURLConnection
172     // can't really do anything useful with an error at this point, so this is better.
173     advanceCurrentStream(form);
174     while (form->currentStream && !CFReadStreamOpen(form->currentStream))
175         advanceCurrentStream(form);
176 }
177 
formCreate(CFReadStreamRef stream,void * context)178 static void* formCreate(CFReadStreamRef stream, void* context)
179 {
180     FormData* formData = static_cast<FormData*>(context);
181 
182     CFSetCallBacks runLoopAndModeCallBacks = { 0, pairRetain, pairRelease, NULL, pairEqual, pairHash };
183 
184     FormStreamFields* newInfo = new FormStreamFields;
185     newInfo->scheduledRunLoopPairs = CFSetCreateMutable(0, 0, &runLoopAndModeCallBacks);
186     newInfo->currentStream = NULL;
187     newInfo->currentData = 0;
188     newInfo->formStream = stream; // Don't retain. That would create a reference cycle.
189 
190     // Append in reverse order since we remove elements from the end.
191     size_t size = formData->elements().size();
192     newInfo->remainingElements.reserveCapacity(size);
193     for (size_t i = 0; i < size; ++i)
194         newInfo->remainingElements.append(formData->elements()[size - i - 1]);
195 
196     getStreamFormDatas().set(stream, adoptRef(formData));
197 
198     return newInfo;
199 }
200 
formFinalize(CFReadStreamRef stream,void * context)201 static void formFinalize(CFReadStreamRef stream, void* context)
202 {
203     FormStreamFields* form = static_cast<FormStreamFields*>(context);
204 
205     getStreamFormDatas().remove(stream);
206 
207     closeCurrentStream(form);
208     CFRelease(form->scheduledRunLoopPairs);
209     delete form;
210 }
211 
formOpen(CFReadStreamRef stream,CFStreamError * error,Boolean * openComplete,void * context)212 static Boolean formOpen(CFReadStreamRef stream, CFStreamError* error, Boolean* openComplete, void* context)
213 {
214     FormStreamFields* form = static_cast<FormStreamFields*>(context);
215 
216     openNextStream(form);
217 
218     *openComplete = TRUE;
219     error->error = 0;
220     return TRUE;
221 }
222 
formRead(CFReadStreamRef stream,UInt8 * buffer,CFIndex bufferLength,CFStreamError * error,Boolean * atEOF,void * context)223 static CFIndex formRead(CFReadStreamRef stream, UInt8* buffer, CFIndex bufferLength, CFStreamError* error, Boolean* atEOF, void* context)
224 {
225     FormStreamFields* form = static_cast<FormStreamFields*>(context);
226 
227     while (form->currentStream) {
228         CFIndex bytesRead = CFReadStreamRead(form->currentStream, buffer, bufferLength);
229         if (bytesRead < 0) {
230             *error = CFReadStreamGetError(form->currentStream);
231             return -1;
232         }
233         if (bytesRead > 0) {
234             error->error = 0;
235             *atEOF = FALSE;
236             return bytesRead;
237         }
238         openNextStream(form);
239     }
240 
241     error->error = 0;
242     *atEOF = TRUE;
243     return 0;
244 }
245 
formCanRead(CFReadStreamRef stream,void * context)246 static Boolean formCanRead(CFReadStreamRef stream, void* context)
247 {
248     FormStreamFields* form = static_cast<FormStreamFields*>(context);
249 
250     while (form->currentStream && CFReadStreamGetStatus(form->currentStream) == kCFStreamStatusAtEnd) {
251         openNextStream(form);
252     }
253     if (!form->currentStream) {
254         CFReadStreamSignalEvent(stream, kCFStreamEventEndEncountered, 0);
255         return FALSE;
256     }
257     return CFReadStreamHasBytesAvailable(form->currentStream);
258 }
259 
formClose(CFReadStreamRef stream,void * context)260 static void formClose(CFReadStreamRef stream, void* context)
261 {
262     FormStreamFields* form = static_cast<FormStreamFields*>(context);
263 
264     closeCurrentStream(form);
265 }
266 
formSchedule(CFReadStreamRef stream,CFRunLoopRef runLoop,CFStringRef runLoopMode,void * context)267 static void formSchedule(CFReadStreamRef stream, CFRunLoopRef runLoop, CFStringRef runLoopMode, void* context)
268 {
269     FormStreamFields* form = static_cast<FormStreamFields*>(context);
270 
271     if (form->currentStream)
272         CFReadStreamScheduleWithRunLoop(form->currentStream, runLoop, runLoopMode);
273     SchedulePair pair = { runLoop, runLoopMode };
274     CFSetAddValue(form->scheduledRunLoopPairs, &pair);
275 }
276 
formUnschedule(CFReadStreamRef stream,CFRunLoopRef runLoop,CFStringRef runLoopMode,void * context)277 static void formUnschedule(CFReadStreamRef stream, CFRunLoopRef runLoop, CFStringRef runLoopMode, void* context)
278 {
279     FormStreamFields* form = static_cast<FormStreamFields*>(context);
280 
281     if (form->currentStream)
282         CFReadStreamUnscheduleFromRunLoop(form->currentStream, runLoop, runLoopMode);
283     SchedulePair pair = { runLoop, runLoopMode };
284     CFSetRemoveValue(form->scheduledRunLoopPairs, &pair);
285 }
286 
formEventCallback(CFReadStreamRef stream,CFStreamEventType type,void * context)287 static void formEventCallback(CFReadStreamRef stream, CFStreamEventType type, void* context)
288 {
289     FormStreamFields* form = static_cast<FormStreamFields*>(context);
290 
291     switch (type) {
292     case kCFStreamEventHasBytesAvailable:
293         CFReadStreamSignalEvent(form->formStream, kCFStreamEventHasBytesAvailable, 0);
294         break;
295     case kCFStreamEventErrorOccurred: {
296         CFStreamError readStreamError = CFReadStreamGetError(stream);
297         CFReadStreamSignalEvent(form->formStream, kCFStreamEventErrorOccurred, &readStreamError);
298         break;
299     }
300     case kCFStreamEventEndEncountered:
301         openNextStream(form);
302         if (!form->currentStream)
303             CFReadStreamSignalEvent(form->formStream, kCFStreamEventEndEncountered, 0);
304         break;
305     case kCFStreamEventNone:
306         LOG_ERROR("unexpected kCFStreamEventNone");
307         break;
308     case kCFStreamEventOpenCompleted:
309         LOG_ERROR("unexpected kCFStreamEventOpenCompleted");
310         break;
311     case kCFStreamEventCanAcceptBytes:
312         LOG_ERROR("unexpected kCFStreamEventCanAcceptBytes");
313         break;
314     }
315 }
316 
setHTTPBody(CFMutableURLRequestRef request,PassRefPtr<FormData> formData)317 void setHTTPBody(CFMutableURLRequestRef request, PassRefPtr<FormData> formData)
318 {
319     if (!formData) {
320         wkCFURLRequestSetHTTPRequestBodyParts(request, 0);
321         return;
322     }
323 
324     size_t count = formData->elements().size();
325 
326     if (count == 0)
327         return;
328 
329     // Handle the common special case of one piece of form data, with no files.
330     if (count == 1) {
331         const FormDataElement& element = formData->elements()[0];
332         if (element.m_type == FormDataElement::data) {
333             CFDataRef data = CFDataCreate(0, reinterpret_cast<const UInt8 *>(element.m_data.data()), element.m_data.size());
334             CFURLRequestSetHTTPRequestBody(request, data);
335             CFRelease(data);
336             return;
337         }
338     }
339 
340     RetainPtr<CFMutableArrayRef> array(AdoptCF, CFArrayCreateMutable(0, 0, &kCFTypeArrayCallBacks));
341 
342     for (size_t i = 0; i < count; ++i) {
343         const FormDataElement& element = formData->elements()[i];
344         if (element.m_type == FormDataElement::data) {
345             RetainPtr<CFDataRef> data(AdoptCF, CFDataCreate(0, reinterpret_cast<const UInt8*>(element.m_data.data()), element.m_data.size()));
346             CFArrayAppendValue(array.get(), data.get());
347         } else {
348             RetainPtr<CFStringRef> filename(AdoptCF, element.m_filename.createCFString());
349             CFArrayAppendValue(array.get(), filename.get());
350         }
351     }
352 
353     wkCFURLRequestSetHTTPRequestBodyParts(request, array.get());
354 }
355 
httpBodyFromRequest(CFURLRequestRef request)356 PassRefPtr<FormData> httpBodyFromRequest(CFURLRequestRef request)
357 {
358     if (RetainPtr<CFDataRef> bodyData = CFURLRequestCopyHTTPRequestBody(request))
359         return FormData::create(CFDataGetBytePtr(bodyData.get()), CFDataGetLength(bodyData.get()));
360 
361     if (RetainPtr<CFArrayRef> bodyParts = wkCFURLRequestCopyHTTPRequestBodyParts(request)) {
362         RefPtr<FormData> formData = FormData::create();
363 
364         CFIndex count = CFArrayGetCount(bodyParts.get());
365         for (CFIndex i = 0; i < count; i++) {
366             CFTypeRef bodyPart = CFArrayGetValueAtIndex(bodyParts.get(), i);
367             CFTypeID typeID = CFGetTypeID(bodyPart);
368             if (typeID == CFStringGetTypeID()) {
369                 String filename = (CFStringRef)bodyPart;
370                 formData->appendFile(filename);
371             } else if (typeID == CFDataGetTypeID()) {
372                 CFDataRef data = (CFDataRef)bodyPart;
373                 formData->appendData(CFDataGetBytePtr(data), CFDataGetLength(data));
374             } else
375                 ASSERT_NOT_REACHED();
376         }
377         return formData.release();
378     }
379 
380     // FIXME: what to do about arbitrary body streams?
381     return 0;
382 }
383 
384 }
385