Changeset 112482 in webkit
- Timestamp:
- Mar 28, 2012 5:58:42 PM (12 years ago)
- Location:
- trunk/Source/WebCore
- Files:
-
- 8 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/Source/WebCore/ChangeLog
r112481 r112482 1 2012-03-28 Alexey Proskuryakov <ap@apple.com> 2 3 [Win] Some Blob tests crash in CFNetwork in advanceCurrentStream(FormStreamFields*) 4 https://bugs.webkit.org/show_bug.cgi?id=82386 5 <rdar://problem/11121501> 6 7 Reviewed by Brady Eidson. 8 9 Covered by existing tests. 10 11 * platform/network/cf/FormDataStreamCFNet.cpp: 12 * platform/network/cf/FormDataStreamCFNet.h: 13 Moved low level implementation from FormDataStreamMac, and exposed an additional function 14 to implement Foundation-based API on top of this. 15 16 * platform/network/mac/FormDataStreamMac.h: 17 * platform/network/mac/FormDataStreamMac.mm: 18 Rely on toll-free bridging and implementation details to make this work without duplicating 19 code. 20 Note that httpBodyFromStream is confusing - I don't see how it can work when sending serialized 21 requests across process boundary. We probably only get away with this because we don't attempt 22 to send requests to UI process once they already have streams associated with them. 23 24 * WebCore.vcproj/WebCore.vcproj: Added missing platform/cf files. 25 26 * platform/cf/FileSystemCF.cpp: Fixed include style. 27 28 * platform/win/FileSystemWin.cpp: (WebCore::fileSystemRepresentation): Ifdef out a broken 29 implementation. 30 1 31 2012-03-28 Adrienne Walker <enne@google.com> 2 32 -
trunk/Source/WebCore/WebCore.vcproj/WebCore.vcproj
r112453 r112482 28386 28386 </File> 28387 28387 <File 28388 RelativePath="..\platform\cf\FileSystemCF.cpp" 28389 > 28390 </File> 28391 <File 28388 28392 RelativePath="..\platform\cf\KURLCFNet.cpp" 28389 28393 > … … 28391 28395 <File 28392 28396 RelativePath="..\platform\cf\RetainPtr.h" 28397 > 28398 </File> 28399 <File 28400 RelativePath="..\platform\cf\SchedulePair.cpp" 28401 > 28402 </File> 28403 <File 28404 RelativePath="..\platform\cf\SchedulePair.h" 28393 28405 > 28394 28406 </File> -
trunk/Source/WebCore/platform/cf/FileSystemCF.cpp
r76614 r112482 27 27 */ 28 28 29 #i mport"config.h"30 #i mport"FileSystem.h"29 #include "config.h" 30 #include "FileSystem.h" 31 31 32 #i mport"PlatformString.h"33 #i mport<wtf/RetainPtr.h>34 #i mport<wtf/text/CString.h>32 #include "PlatformString.h" 33 #include <wtf/RetainPtr.h> 34 #include <wtf/text/CString.h> 35 35 36 36 namespace WebCore { -
trunk/Source/WebCore/platform/network/cf/FormDataStreamCFNet.cpp
r92530 r112482 1 1 /* 2 * Copyright (C) 2005, 2006, 2007 Apple Inc. All rights reserved.2 * Copyright (C) 2005, 2006, 2007, 2012 Apple Inc. All rights reserved. 3 3 * 4 4 * Redistribution and use in source and binary forms, with or without … … 27 27 */ 28 28 29 /* originally written by Becky Willrich, additional code by Darin Adler */30 31 29 #include "config.h" 32 30 #include "FormDataStreamCFNet.h" 33 31 34 #if USE(CFNETWORK) 35 32 #include "BlobRegistryImpl.h" 36 33 #include "FileSystem.h" 37 34 #include "FormData.h" 38 #include <CFNetwork/CFURLRequestPriv.h> 35 #include "SchedulePair.h" 36 #include <sys/stat.h> 39 37 #include <sys/types.h> 40 38 #include <wtf/Assertions.h> 41 39 #include <wtf/HashMap.h> 40 #include <wtf/MainThread.h> 42 41 #include <wtf/RetainPtr.h> 43 #include <wtf/text/CString.h> 42 #include <wtf/StdLibExtras.h> 43 #include <wtf/Threading.h> 44 45 #if PLATFORM(IOS) 46 #include <MacErrors.h> 47 #else 48 #include <CoreServices/CoreServices.h> 49 #endif 44 50 45 51 #if PLATFORM(MAC) 46 #include "WebCoreSystemInterface.h" 52 extern "C" void CFURLRequestSetHTTPRequestBody(CFMutableURLRequestRef mutableHTTPRequest, CFDataRef httpBody); 53 extern "C" void CFURLRequestSetHTTPHeaderFieldValue(CFMutableURLRequestRef mutableHTTPRequest, CFStringRef httpHeaderField, CFStringRef httpHeaderFieldValue); 54 extern "C" void CFURLRequestSetHTTPRequestBodyStream(CFMutableURLRequestRef req, CFReadStreamRef bodyStream); 55 extern "C" CFReadStreamRef CFURLRequestCopyHTTPRequestBodyStream(CFURLRequestRef request); 47 56 #elif PLATFORM(WIN) 48 #include <WebKitSystemInterface/WebKitSystemInterface.h> 49 #endif 57 #include <CFNetwork/CFURLRequest.h> 58 #endif 59 60 typedef struct { 61 CFIndex version; /* == 1 */ 62 void *(*create)(CFReadStreamRef stream, void *info); 63 void (*finalize)(CFReadStreamRef stream, void *info); 64 CFStringRef (*copyDescription)(CFReadStreamRef stream, void *info); 65 Boolean (*open)(CFReadStreamRef stream, CFStreamError *error, Boolean *openComplete, void *info); 66 Boolean (*openCompleted)(CFReadStreamRef stream, CFStreamError *error, void *info); 67 CFIndex (*read)(CFReadStreamRef stream, UInt8 *buffer, CFIndex bufferLength, CFStreamError *error, Boolean *atEOF, void *info); 68 const UInt8 *(*getBuffer)(CFReadStreamRef stream, CFIndex maxBytesToRead, CFIndex *numBytesRead, CFStreamError *error, Boolean *atEOF, void *info); 69 Boolean (*canRead)(CFReadStreamRef stream, void *info); 70 void (*close)(CFReadStreamRef stream, void *info); 71 CFTypeRef (*copyProperty)(CFReadStreamRef stream, CFStringRef propertyName, void *info); 72 Boolean (*setProperty)(CFReadStreamRef stream, CFStringRef propertyName, CFTypeRef propertyValue, void *info); 73 void (*requestEvents)(CFReadStreamRef stream, CFOptionFlags streamEvents, void *info); 74 void (*schedule)(CFReadStreamRef stream, CFRunLoopRef runLoop, CFStringRef runLoopMode, void *info); 75 void (*unschedule)(CFReadStreamRef stream, CFRunLoopRef runLoop, CFStringRef runLoopMode, void *info); 76 } CFReadStreamCallBacksV1; 77 78 #if PLATFORM(WIN) 79 #define EXTERN extern "C" __declspec(dllimport) 80 #else 81 #define EXTERN extern "C" 82 #endif 83 84 EXTERN void CFReadStreamSignalEvent(CFReadStreamRef stream, CFStreamEventType event, const void *error); 85 EXTERN CFReadStreamRef CFReadStreamCreate(CFAllocatorRef alloc, const void *callbacks, void *info); 50 86 51 87 namespace WebCore { 52 88 53 void setHTTPBody(CFMutableURLRequestRef request, PassRefPtr<FormData> formData) 54 { 55 if (!formData) { 56 wkCFURLRequestSetHTTPRequestBodyParts(request, 0); 89 static Mutex& streamFieldsMapMutex() 90 { 91 DEFINE_STATIC_LOCAL(Mutex, staticMutex, ()); 92 return staticMutex; 93 } 94 95 static void formEventCallback(CFReadStreamRef stream, CFStreamEventType type, void* context); 96 97 struct FormContext { 98 RefPtr<FormData> formData; 99 unsigned long long streamLength; 100 }; 101 102 struct FormStreamFields { 103 RefPtr<FormData> formData; 104 SchedulePairHashSet scheduledRunLoopPairs; 105 Vector<FormDataElement> remainingElements; // in reverse order 106 CFReadStreamRef currentStream; 107 #if ENABLE(BLOB) 108 long long currentStreamRangeLength; 109 #endif 110 char* currentData; 111 CFReadStreamRef formStream; 112 unsigned long long streamLength; 113 unsigned long long bytesSent; 114 }; 115 116 typedef HashMap<CFReadStreamRef, FormStreamFields*> StreamFieldsMap; 117 static StreamFieldsMap& streamFieldsMap() 118 { 119 DEFINE_STATIC_LOCAL(StreamFieldsMap, streamFieldsMap, ()); 120 return streamFieldsMap; 121 } 122 123 static void closeCurrentStream(FormStreamFields *form) 124 { 125 if (form->currentStream) { 126 CFReadStreamClose(form->currentStream); 127 CFReadStreamSetClient(form->currentStream, kCFStreamEventNone, 0, 0); 128 CFRelease(form->currentStream); 129 form->currentStream = 0; 130 #if ENABLE(BLOB) 131 form->currentStreamRangeLength = BlobDataItem::toEndOfFile; 132 #endif 133 } 134 if (form->currentData) { 135 fastFree(form->currentData); 136 form->currentData = 0; 137 } 138 } 139 140 // 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. 141 static bool advanceCurrentStream(FormStreamFields* form) 142 { 143 closeCurrentStream(form); 144 145 if (form->remainingElements.isEmpty()) 146 return true; 147 148 // Create the new stream. 149 FormDataElement& nextInput = form->remainingElements.last(); 150 151 if (nextInput.m_type == FormDataElement::data) { 152 size_t size = nextInput.m_data.size(); 153 char* data = nextInput.m_data.releaseBuffer(); 154 form->currentStream = CFReadStreamCreateWithBytesNoCopy(0, reinterpret_cast<const UInt8*>(data), size, kCFAllocatorNull); 155 form->currentData = data; 156 } else { 157 #if ENABLE(BLOB) 158 // Check if the file has been changed or not if required. 159 if (nextInput.m_expectedFileModificationTime != BlobDataItem::doNotCheckFileChange) { 160 time_t fileModificationTime; 161 if (!getFileModificationTime(nextInput.m_filename, fileModificationTime) || fileModificationTime != static_cast<time_t>(nextInput.m_expectedFileModificationTime)) 162 return false; 163 } 164 #endif 165 const String& path = nextInput.m_shouldGenerateFile ? nextInput.m_generatedFilename : nextInput.m_filename; 166 form->currentStream = CFReadStreamCreateWithFile(0, pathAsURL(path).get()); 167 if (!form->currentStream) { 168 // The file must have been removed or become unreadable. 169 return false; 170 } 171 #if ENABLE(BLOB) 172 if (nextInput.m_fileStart > 0) { 173 RetainPtr<CFNumberRef> position(AdoptCF, CFNumberCreate(0, kCFNumberLongLongType, &nextInput.m_fileStart)); 174 CFReadStreamSetProperty(form->currentStream, kCFStreamPropertyFileCurrentOffset, position.get()); 175 } 176 form->currentStreamRangeLength = nextInput.m_fileLength; 177 #endif 178 } 179 form->remainingElements.removeLast(); 180 181 // Set up the callback. 182 CFStreamClientContext context = { 0, form, 0, 0, 0 }; 183 CFReadStreamSetClient(form->currentStream, kCFStreamEventHasBytesAvailable | kCFStreamEventErrorOccurred | kCFStreamEventEndEncountered, 184 formEventCallback, &context); 185 186 // Schedule with the current set of run loops. 187 SchedulePairHashSet::iterator end = form->scheduledRunLoopPairs.end(); 188 for (SchedulePairHashSet::iterator it = form->scheduledRunLoopPairs.begin(); it != end; ++it) 189 CFReadStreamScheduleWithRunLoop(form->currentStream, (*it)->runLoop(), (*it)->mode()); 190 191 return true; 192 } 193 194 static bool openNextStream(FormStreamFields* form) 195 { 196 // Skip over any streams we can't open. 197 if (!advanceCurrentStream(form)) 198 return false; 199 while (form->currentStream && !CFReadStreamOpen(form->currentStream)) { 200 if (!advanceCurrentStream(form)) 201 return false; 202 } 203 return true; 204 } 205 206 static void* formCreate(CFReadStreamRef stream, void* context) 207 { 208 FormContext* formContext = static_cast<FormContext*>(context); 209 210 FormStreamFields* newInfo = new FormStreamFields; 211 newInfo->formData = formContext->formData.release(); 212 newInfo->currentStream = 0; 213 #if ENABLE(BLOB) 214 newInfo->currentStreamRangeLength = BlobDataItem::toEndOfFile; 215 #endif 216 newInfo->currentData = 0; 217 newInfo->formStream = stream; // Don't retain. That would create a reference cycle. 218 newInfo->streamLength = formContext->streamLength; 219 newInfo->bytesSent = 0; 220 221 // Append in reverse order since we remove elements from the end. 222 size_t size = newInfo->formData->elements().size(); 223 newInfo->remainingElements.reserveInitialCapacity(size); 224 for (size_t i = 0; i < size; ++i) 225 newInfo->remainingElements.append(newInfo->formData->elements()[size - i - 1]); 226 227 MutexLocker locker(streamFieldsMapMutex()); 228 ASSERT(!streamFieldsMap().contains(stream)); 229 streamFieldsMap().add(stream, newInfo); 230 231 return newInfo; 232 } 233 234 static void formFinishFinalizationOnMainThread(void* context) 235 { 236 OwnPtr<FormStreamFields> form = adoptPtr(static_cast<FormStreamFields*>(context)); 237 238 closeCurrentStream(form.get()); 239 } 240 241 static void formFinalize(CFReadStreamRef stream, void* context) 242 { 243 FormStreamFields* form = static_cast<FormStreamFields*>(context); 244 245 MutexLocker locker(streamFieldsMapMutex()); 246 247 ASSERT(form->formStream == stream); 248 ASSERT(streamFieldsMap().get(stream) == context); 249 250 // Do this right away because the CFReadStreamRef is being deallocated. 251 // We can't wait to remove this from the map until we finish finalizing 252 // on the main thread because in theory the freed memory could be reused 253 // for a new CFReadStream before that runs. 254 streamFieldsMap().remove(stream); 255 256 callOnMainThread(formFinishFinalizationOnMainThread, form); 257 } 258 259 static Boolean formOpen(CFReadStreamRef, CFStreamError* error, Boolean* openComplete, void* context) 260 { 261 FormStreamFields* form = static_cast<FormStreamFields*>(context); 262 263 bool opened = openNextStream(form); 264 265 *openComplete = opened; 266 error->error = opened ? 0 : fnfErr; 267 return opened; 268 } 269 270 static CFIndex formRead(CFReadStreamRef, UInt8* buffer, CFIndex bufferLength, CFStreamError* error, Boolean* atEOF, void* context) 271 { 272 FormStreamFields* form = static_cast<FormStreamFields*>(context); 273 274 while (form->currentStream) { 275 CFIndex bytesToRead = bufferLength; 276 #if ENABLE(BLOB) 277 if (form->currentStreamRangeLength != BlobDataItem::toEndOfFile && form->currentStreamRangeLength < bytesToRead) 278 bytesToRead = static_cast<CFIndex>(form->currentStreamRangeLength); 279 #endif 280 CFIndex bytesRead = CFReadStreamRead(form->currentStream, buffer, bytesToRead); 281 if (bytesRead < 0) { 282 *error = CFReadStreamGetError(form->currentStream); 283 return -1; 284 } 285 if (bytesRead > 0) { 286 error->error = 0; 287 *atEOF = FALSE; 288 form->bytesSent += bytesRead; 289 #if ENABLE(BLOB) 290 if (form->currentStreamRangeLength != BlobDataItem::toEndOfFile) 291 form->currentStreamRangeLength -= bytesRead; 292 #endif 293 294 return bytesRead; 295 } 296 openNextStream(form); 297 } 298 299 error->error = 0; 300 *atEOF = TRUE; 301 return 0; 302 } 303 304 static Boolean formCanRead(CFReadStreamRef stream, void* context) 305 { 306 FormStreamFields* form = static_cast<FormStreamFields*>(context); 307 308 while (form->currentStream && CFReadStreamGetStatus(form->currentStream) == kCFStreamStatusAtEnd) 309 openNextStream(form); 310 311 if (!form->currentStream) { 312 CFReadStreamSignalEvent(stream, kCFStreamEventEndEncountered, 0); 313 return FALSE; 314 } 315 return CFReadStreamHasBytesAvailable(form->currentStream); 316 } 317 318 static void formClose(CFReadStreamRef, void* context) 319 { 320 FormStreamFields* form = static_cast<FormStreamFields*>(context); 321 322 closeCurrentStream(form); 323 } 324 325 static void formSchedule(CFReadStreamRef, CFRunLoopRef runLoop, CFStringRef runLoopMode, void* context) 326 { 327 FormStreamFields* form = static_cast<FormStreamFields*>(context); 328 329 if (form->currentStream) 330 CFReadStreamScheduleWithRunLoop(form->currentStream, runLoop, runLoopMode); 331 form->scheduledRunLoopPairs.add(SchedulePair::create(runLoop, runLoopMode)); 332 } 333 334 static void formUnschedule(CFReadStreamRef, CFRunLoopRef runLoop, CFStringRef runLoopMode, void* context) 335 { 336 FormStreamFields* form = static_cast<FormStreamFields*>(context); 337 338 if (form->currentStream) 339 CFReadStreamUnscheduleFromRunLoop(form->currentStream, runLoop, runLoopMode); 340 form->scheduledRunLoopPairs.remove(SchedulePair::create(runLoop, runLoopMode)); 341 } 342 343 static void formEventCallback(CFReadStreamRef stream, CFStreamEventType type, void* context) 344 { 345 FormStreamFields* form = static_cast<FormStreamFields*>(context); 346 347 switch (type) { 348 case kCFStreamEventHasBytesAvailable: 349 CFReadStreamSignalEvent(form->formStream, kCFStreamEventHasBytesAvailable, 0); 350 break; 351 case kCFStreamEventErrorOccurred: { 352 CFStreamError readStreamError = CFReadStreamGetError(stream); 353 CFReadStreamSignalEvent(form->formStream, kCFStreamEventErrorOccurred, &readStreamError); 354 break; 355 } 356 case kCFStreamEventEndEncountered: 357 openNextStream(form); 358 if (!form->currentStream) 359 CFReadStreamSignalEvent(form->formStream, kCFStreamEventEndEncountered, 0); 360 break; 361 case kCFStreamEventNone: 362 LOG_ERROR("unexpected kCFStreamEventNone"); 363 break; 364 case kCFStreamEventOpenCompleted: 365 LOG_ERROR("unexpected kCFStreamEventOpenCompleted"); 366 break; 367 case kCFStreamEventCanAcceptBytes: 368 LOG_ERROR("unexpected kCFStreamEventCanAcceptBytes"); 369 break; 370 } 371 } 372 373 void setHTTPBody(CFMutableURLRequestRef request, PassRefPtr<FormData> prpFormData) 374 { 375 RefPtr<FormData> formData = prpFormData; 376 377 if (!formData) 57 378 return; 58 } 59 379 60 380 size_t count = formData->elements().size(); 61 381 62 if (count == 0)63 return;64 65 382 // Handle the common special case of one piece of form data, with no files. 66 if (count == 1 ) {383 if (count == 1 && !formData->alwaysStream()) { 67 384 const FormDataElement& element = formData->elements()[0]; 68 385 if (element.m_type == FormDataElement::data) { 69 CFDataRef data = CFDataCreate(0, reinterpret_cast<const UInt8 *>(element.m_data.data()), element.m_data.size()); 70 CFURLRequestSetHTTPRequestBody(request, data); 71 CFRelease(data); 386 RetainPtr<CFDataRef> data = adoptCF(CFDataCreate(0, reinterpret_cast<const UInt8 *>(element.m_data.data()), element.m_data.size())); 387 CFURLRequestSetHTTPRequestBody(request, data.get()); 72 388 return; 73 389 } 74 390 } 75 391 76 RetainPtr<CFMutableArrayRef> array(AdoptCF, CFArrayCreateMutable(0, 0, &kCFTypeArrayCallBacks)); 77 392 #if ENABLE(BLOB) 393 // Check if there is a blob in the form data. 394 bool hasBlob = false; 78 395 for (size_t i = 0; i < count; ++i) { 79 396 const FormDataElement& element = formData->elements()[i]; 80 if (element.m_type == FormDataElement::data) { 81 RetainPtr<CFDataRef> data(AdoptCF, CFDataCreate(0, reinterpret_cast<const UInt8*>(element.m_data.data()), element.m_data.size())); 82 CFArrayAppendValue(array.get(), data.get()); 83 } else { 84 RetainPtr<CFStringRef> filename(AdoptCF, element.m_filename.createCFString()); 85 CFArrayAppendValue(array.get(), filename.get()); 86 } 87 } 88 89 wkCFURLRequestSetHTTPRequestBodyParts(request, array.get()); 397 if (element.m_type == FormDataElement::encodedBlob) { 398 hasBlob = true; 399 break; 400 } 401 } 402 403 // If yes, we have to resolve all the blob references and regenerate the form data with only data and file types. 404 if (hasBlob) { 405 RefPtr<FormData> newFormData = FormData::create(); 406 newFormData->setAlwaysStream(formData->alwaysStream()); 407 newFormData->setIdentifier(formData->identifier()); 408 for (size_t i = 0; i < count; ++i) { 409 const FormDataElement& element = formData->elements()[i]; 410 if (element.m_type == FormDataElement::data) 411 newFormData->appendData(element.m_data.data(), element.m_data.size()); 412 else if (element.m_type == FormDataElement::encodedFile) 413 newFormData->appendFile(element.m_filename, element.m_shouldGenerateFile); 414 else { 415 ASSERT(element.m_type == FormDataElement::encodedBlob); 416 RefPtr<BlobStorageData> blobData = static_cast<BlobRegistryImpl&>(blobRegistry()).getBlobDataFromURL(KURL(ParsedURLString, element.m_blobURL)); 417 if (blobData) { 418 for (size_t j = 0; j < blobData->items().size(); ++j) { 419 const BlobDataItem& blobItem = blobData->items()[j]; 420 if (blobItem.type == BlobDataItem::Data) 421 newFormData->appendData(blobItem.data->data() + static_cast<int>(blobItem.offset), static_cast<int>(blobItem.length)); 422 else { 423 ASSERT(blobItem.type == BlobDataItem::File); 424 newFormData->appendFileRange(blobItem.path, blobItem.offset, blobItem.length, blobItem.expectedModificationTime); 425 } 426 } 427 } 428 } 429 } 430 formData = newFormData.release(); 431 count = formData->elements().size(); 432 } 433 #endif 434 435 // Precompute the content length so NSURLConnection doesn't use chunked mode. 436 long long length = 0; 437 for (size_t i = 0; i < count; ++i) { 438 const FormDataElement& element = formData->elements()[i]; 439 if (element.m_type == FormDataElement::data) 440 length += element.m_data.size(); 441 else { 442 #if ENABLE(BLOB) 443 // 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. 444 if (element.m_fileLength != BlobDataItem::toEndOfFile) { 445 length += element.m_fileLength; 446 continue; 447 } 448 #endif 449 long long fileSize; 450 if (getFileSize(element.m_shouldGenerateFile ? element.m_generatedFilename : element.m_filename, fileSize)) 451 length += fileSize; 452 } 453 } 454 455 // Set the length. 456 RetainPtr<CFStringRef> lengthString = adoptCF(CFStringCreateWithFormat(0, 0, CFSTR("%lld"), length)); 457 CFURLRequestSetHTTPHeaderFieldValue(request, CFSTR("Content-Length"), lengthString.get()); 458 459 // Create and set the stream. 460 461 // Pass the length along with the formData so it does not have to be recomputed. 462 FormContext formContext = { formData.release(), length }; 463 464 CFReadStreamCallBacksV1 callBacks = { 1, formCreate, formFinalize, 0, formOpen, 0, formRead, 0, formCanRead, formClose, 0, 0, 0, formSchedule, formUnschedule 465 }; 466 RetainPtr<CFReadStreamRef> stream = adoptCF(CFReadStreamCreate(0, static_cast<const void*>(&callBacks), &formContext)); 467 468 CFURLRequestSetHTTPRequestBodyStream(request, stream.get()); 469 } 470 471 FormData* httpBodyFromStream(CFReadStreamRef stream) 472 { 473 if (!stream) 474 return 0; 475 476 MutexLocker locker(streamFieldsMapMutex()); 477 FormStreamFields* formStream = streamFieldsMap().get(stream); 478 if (!formStream) 479 return 0; 480 return formStream->formData.get(); 90 481 } 91 482 92 483 PassRefPtr<FormData> httpBodyFromRequest(CFURLRequestRef request) 93 484 { 94 RetainPtr<CFDataRef> bodyData(AdoptCF, CFURLRequestCopyHTTPRequestBody(request)); 95 if (bodyData) 96 return FormData::create(CFDataGetBytePtr(bodyData.get()), CFDataGetLength(bodyData.get())); 97 98 RetainPtr<CFArrayRef> bodyParts(AdoptCF, wkCFURLRequestCopyHTTPRequestBodyParts(request)); 99 if (bodyParts) { 100 RefPtr<FormData> formData = FormData::create(); 101 102 CFIndex count = CFArrayGetCount(bodyParts.get()); 103 for (CFIndex i = 0; i < count; i++) { 104 CFTypeRef bodyPart = CFArrayGetValueAtIndex(bodyParts.get(), i); 105 CFTypeID typeID = CFGetTypeID(bodyPart); 106 if (typeID == CFStringGetTypeID()) { 107 String filename = (CFStringRef)bodyPart; 108 formData->appendFile(filename); 109 } else if (typeID == CFDataGetTypeID()) { 110 CFDataRef data = (CFDataRef)bodyPart; 111 formData->appendData(CFDataGetBytePtr(data), CFDataGetLength(data)); 112 } else 113 ASSERT_NOT_REACHED(); 114 } 115 return formData.release(); 116 } 117 118 // FIXME: what to do about arbitrary body streams? 119 return 0; 485 RetainPtr<CFReadStreamRef> bodyStream = adoptCF(CFURLRequestCopyHTTPRequestBodyStream(request)); 486 return httpBodyFromStream(bodyStream.get()); 120 487 } 121 488 122 489 } // namespace WebCore 123 124 #endif // USE(CFNETWORK) -
trunk/Source/WebCore/platform/network/cf/FormDataStreamCFNet.h
r74943 r112482 1 1 /* 2 * Copyright (C) 2005, 2006, 2007 Apple Inc. All rights reserved.2 * Copyright (C) 2005, 2006, 2007, 2012 Apple Inc. All rights reserved. 3 3 * 4 4 * Redistribution and use in source and binary forms, with or without … … 30 30 #define FormDataStreamCFNet_h 31 31 32 #if USE(CFNETWORK)33 34 #include <CoreFoundation/CoreFoundation.h>35 32 #include <wtf/Forward.h> 36 33 … … 39 36 40 37 namespace WebCore { 41 class FormData;42 void setHTTPBody(CFMutableURLRequestRef, PassRefPtr<FormData>);43 PassRefPtr<FormData> httpBodyFromRequest(CFURLRequestRef);44 }45 38 46 #endif // USE(CFNETWORK) 39 class FormData; 40 41 void setHTTPBody(CFMutableURLRequestRef, PassRefPtr<FormData>); 42 PassRefPtr<FormData> httpBodyFromRequest(CFURLRequestRef); 43 44 FormData* httpBodyFromStream(CFReadStreamRef); 45 46 } // namespace WebCore 47 47 48 48 #endif // FormDataStreamCFNet_h -
trunk/Source/WebCore/platform/network/mac/FormDataStreamMac.h
r112162 r112482 32 32 #if !USE(CFNETWORK) 33 33 34 #include "FormData.h"34 #include <wtf/Forward.h> 35 35 36 @class NSInputStream; 36 37 @class NSMutableURLRequest; 37 38 -
trunk/Source/WebCore/platform/network/mac/FormDataStreamMac.mm
r112302 r112482 32 32 #if !USE(CFNETWORK) 33 33 34 #import "BlobRegistryImpl.h"35 #import "FileSystem.h"36 34 #import "FormData.h" 37 #import "SchedulePair.h" 38 #import "WebCoreSystemInterface.h" 39 #import <sys/stat.h> 40 #import <sys/types.h> 41 #import <wtf/Assertions.h> 42 #import <wtf/MainThread.h> 43 #import <wtf/StdLibExtras.h> 44 #import <wtf/Threading.h> 35 #import "FormDataStreamCFNet.h" 36 #import <wtf/PassRefPtr.h> 45 37 46 #if PLATFORM(IOS) 47 #import <MacErrors.h> 48 #else 49 #import <CoreServices/CoreServices.h> 50 #endif 38 @interface NSURLRequest (WebNSURLRequestDetails) 39 - (CFURLRequestRef)_CFURLRequest; 40 @end 51 41 52 42 namespace WebCore { 53 43 54 static Mutex& streamFieldsMapMutex()44 void setHTTPBody(NSMutableURLRequest *request, PassRefPtr<FormData> prpFormData) 55 45 { 56 DEFINE_STATIC_LOCAL(Mutex, staticMutex, ()); 57 return staticMutex; 46 setHTTPBody(const_cast<CFMutableURLRequestRef>([request _CFURLRequest]), prpFormData); 58 47 } 59 48 60 static void formEventCallback(CFReadStreamRef stream, CFStreamEventType type, void* context); 61 62 struct FormContext { 63 RefPtr<FormData> formData; 64 unsigned long long streamLength; 65 }; 66 67 struct FormStreamFields { 68 RefPtr<FormData> formData; 69 SchedulePairHashSet scheduledRunLoopPairs; 70 Vector<FormDataElement> remainingElements; // in reverse order 71 CFReadStreamRef currentStream; 72 #if ENABLE(BLOB) 73 long long currentStreamRangeLength; 74 #endif 75 char* currentData; 76 CFReadStreamRef formStream; 77 unsigned long long streamLength; 78 unsigned long long bytesSent; 79 }; 80 81 typedef HashMap<CFReadStreamRef, FormStreamFields*> StreamFieldsMap; 82 static StreamFieldsMap& streamFieldsMap() 49 FormData* httpBodyFromStream(NSInputStream *stream) 83 50 { 84 DEFINE_STATIC_LOCAL(StreamFieldsMap, streamFieldsMap, ()); 85 return streamFieldsMap; 86 } 87 88 static void closeCurrentStream(FormStreamFields *form) 89 { 90 if (form->currentStream) { 91 CFReadStreamClose(form->currentStream); 92 CFReadStreamSetClient(form->currentStream, kCFStreamEventNone, NULL, NULL); 93 CFRelease(form->currentStream); 94 form->currentStream = NULL; 95 #if ENABLE(BLOB) 96 form->currentStreamRangeLength = BlobDataItem::toEndOfFile; 97 #endif 98 } 99 if (form->currentData) { 100 fastFree(form->currentData); 101 form->currentData = 0; 102 } 103 } 104 105 // 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. 106 static bool advanceCurrentStream(FormStreamFields* form) 107 { 108 closeCurrentStream(form); 109 110 if (form->remainingElements.isEmpty()) 111 return true; 112 113 // Create the new stream. 114 FormDataElement& nextInput = form->remainingElements.last(); 115 116 if (nextInput.m_type == FormDataElement::data) { 117 size_t size = nextInput.m_data.size(); 118 char* data = nextInput.m_data.releaseBuffer(); 119 form->currentStream = CFReadStreamCreateWithBytesNoCopy(0, reinterpret_cast<const UInt8*>(data), size, kCFAllocatorNull); 120 form->currentData = data; 121 } else { 122 #if ENABLE(BLOB) 123 // Check if the file has been changed or not if required. 124 if (nextInput.m_expectedFileModificationTime != BlobDataItem::doNotCheckFileChange) { 125 time_t fileModificationTime; 126 if (!getFileModificationTime(nextInput.m_filename, fileModificationTime) || fileModificationTime != static_cast<time_t>(nextInput.m_expectedFileModificationTime)) 127 return false; 128 } 129 #endif 130 const String& path = nextInput.m_shouldGenerateFile ? nextInput.m_generatedFilename : nextInput.m_filename; 131 form->currentStream = CFReadStreamCreateWithFile(0, pathAsURL(path).get()); 132 if (!form->currentStream) { 133 // The file must have been removed or become unreadable. 134 return false; 135 } 136 #if ENABLE(BLOB) 137 if (nextInput.m_fileStart > 0) { 138 RetainPtr<CFNumberRef> position(AdoptCF, CFNumberCreate(0, kCFNumberLongLongType, &nextInput.m_fileStart)); 139 CFReadStreamSetProperty(form->currentStream, kCFStreamPropertyFileCurrentOffset, position.get()); 140 } 141 form->currentStreamRangeLength = nextInput.m_fileLength; 142 #endif 143 } 144 form->remainingElements.removeLast(); 145 146 // Set up the callback. 147 CFStreamClientContext context = { 0, form, NULL, NULL, NULL }; 148 CFReadStreamSetClient(form->currentStream, kCFStreamEventHasBytesAvailable | kCFStreamEventErrorOccurred | kCFStreamEventEndEncountered, 149 formEventCallback, &context); 150 151 // Schedule with the current set of run loops. 152 SchedulePairHashSet::iterator end = form->scheduledRunLoopPairs.end(); 153 for (SchedulePairHashSet::iterator it = form->scheduledRunLoopPairs.begin(); it != end; ++it) 154 CFReadStreamScheduleWithRunLoop(form->currentStream, (*it)->runLoop(), (*it)->mode()); 155 156 return true; 157 } 158 159 static bool openNextStream(FormStreamFields* form) 160 { 161 // Skip over any streams we can't open. 162 if (!advanceCurrentStream(form)) 163 return false; 164 while (form->currentStream && !CFReadStreamOpen(form->currentStream)) { 165 if (!advanceCurrentStream(form)) 166 return false; 167 } 168 return true; 169 } 170 171 static void* formCreate(CFReadStreamRef stream, void* context) 172 { 173 FormContext* formContext = static_cast<FormContext*>(context); 174 175 FormStreamFields* newInfo = new FormStreamFields; 176 newInfo->formData = formContext->formData.release(); 177 newInfo->currentStream = NULL; 178 #if ENABLE(BLOB) 179 newInfo->currentStreamRangeLength = BlobDataItem::toEndOfFile; 180 #endif 181 newInfo->currentData = 0; 182 newInfo->formStream = stream; // Don't retain. That would create a reference cycle. 183 newInfo->streamLength = formContext->streamLength; 184 newInfo->bytesSent = 0; 185 186 // Append in reverse order since we remove elements from the end. 187 size_t size = newInfo->formData->elements().size(); 188 newInfo->remainingElements.reserveInitialCapacity(size); 189 for (size_t i = 0; i < size; ++i) 190 newInfo->remainingElements.append(newInfo->formData->elements()[size - i - 1]); 191 192 MutexLocker locker(streamFieldsMapMutex()); 193 ASSERT(!streamFieldsMap().contains(stream)); 194 streamFieldsMap().add(stream, newInfo); 195 196 return newInfo; 197 } 198 199 static void formFinishFinalizationOnMainThread(void* context) 200 { 201 OwnPtr<FormStreamFields> form = adoptPtr(static_cast<FormStreamFields*>(context)); 202 203 closeCurrentStream(form.get()); 204 } 205 206 static void formFinalize(CFReadStreamRef stream, void* context) 207 { 208 FormStreamFields* form = static_cast<FormStreamFields*>(context); 209 210 MutexLocker locker(streamFieldsMapMutex()); 211 212 ASSERT(form->formStream == stream); 213 ASSERT(streamFieldsMap().get(stream) == context); 214 215 // Do this right away because the CFReadStreamRef is being deallocated. 216 // We can't wait to remove this from the map until we finish finalizing 217 // on the main thread because in theory the freed memory could be reused 218 // for a new CFReadStream before that runs. 219 streamFieldsMap().remove(stream); 220 221 callOnMainThread(formFinishFinalizationOnMainThread, form); 222 } 223 224 static Boolean formOpen(CFReadStreamRef, CFStreamError* error, Boolean* openComplete, void* context) 225 { 226 FormStreamFields* form = static_cast<FormStreamFields*>(context); 227 228 bool opened = openNextStream(form); 229 230 *openComplete = opened; 231 error->error = opened ? 0 : fnfErr; 232 return opened; 233 } 234 235 static CFIndex formRead(CFReadStreamRef, UInt8* buffer, CFIndex bufferLength, CFStreamError* error, Boolean* atEOF, void* context) 236 { 237 FormStreamFields* form = static_cast<FormStreamFields*>(context); 238 239 while (form->currentStream) { 240 CFIndex bytesToRead = bufferLength; 241 #if ENABLE(BLOB) 242 if (form->currentStreamRangeLength != BlobDataItem::toEndOfFile && form->currentStreamRangeLength < bytesToRead) 243 bytesToRead = static_cast<CFIndex>(form->currentStreamRangeLength); 244 #endif 245 CFIndex bytesRead = CFReadStreamRead(form->currentStream, buffer, bytesToRead); 246 if (bytesRead < 0) { 247 *error = CFReadStreamGetError(form->currentStream); 248 return -1; 249 } 250 if (bytesRead > 0) { 251 error->error = 0; 252 *atEOF = FALSE; 253 form->bytesSent += bytesRead; 254 #if ENABLE(BLOB) 255 if (form->currentStreamRangeLength != BlobDataItem::toEndOfFile) 256 form->currentStreamRangeLength -= bytesRead; 257 #endif 258 259 return bytesRead; 260 } 261 openNextStream(form); 262 } 263 264 error->error = 0; 265 *atEOF = TRUE; 266 return 0; 267 } 268 269 static Boolean formCanRead(CFReadStreamRef stream, void* context) 270 { 271 FormStreamFields* form = static_cast<FormStreamFields*>(context); 272 273 while (form->currentStream && CFReadStreamGetStatus(form->currentStream) == kCFStreamStatusAtEnd) { 274 openNextStream(form); 275 } 276 if (!form->currentStream) { 277 wkSignalCFReadStreamEnd(stream); 278 return FALSE; 279 } 280 return CFReadStreamHasBytesAvailable(form->currentStream); 281 } 282 283 static void formClose(CFReadStreamRef, void* context) 284 { 285 FormStreamFields* form = static_cast<FormStreamFields*>(context); 286 287 closeCurrentStream(form); 288 } 289 290 static void formSchedule(CFReadStreamRef, CFRunLoopRef runLoop, CFStringRef runLoopMode, void* context) 291 { 292 FormStreamFields* form = static_cast<FormStreamFields*>(context); 293 294 if (form->currentStream) 295 CFReadStreamScheduleWithRunLoop(form->currentStream, runLoop, runLoopMode); 296 form->scheduledRunLoopPairs.add(SchedulePair::create(runLoop, runLoopMode)); 297 } 298 299 static void formUnschedule(CFReadStreamRef, CFRunLoopRef runLoop, CFStringRef runLoopMode, void* context) 300 { 301 FormStreamFields* form = static_cast<FormStreamFields*>(context); 302 303 if (form->currentStream) 304 CFReadStreamUnscheduleFromRunLoop(form->currentStream, runLoop, runLoopMode); 305 form->scheduledRunLoopPairs.remove(SchedulePair::create(runLoop, runLoopMode)); 306 } 307 308 static void formEventCallback(CFReadStreamRef stream, CFStreamEventType type, void* context) 309 { 310 FormStreamFields* form = static_cast<FormStreamFields*>(context); 311 312 switch (type) { 313 case kCFStreamEventHasBytesAvailable: 314 wkSignalCFReadStreamHasBytes(form->formStream); 315 break; 316 case kCFStreamEventErrorOccurred: { 317 CFStreamError readStreamError = CFReadStreamGetError(stream); 318 wkSignalCFReadStreamError(form->formStream, &readStreamError); 319 break; 320 } 321 case kCFStreamEventEndEncountered: 322 openNextStream(form); 323 if (!form->currentStream) { 324 wkSignalCFReadStreamEnd(form->formStream); 325 } 326 break; 327 case kCFStreamEventNone: 328 LOG_ERROR("unexpected kCFStreamEventNone"); 329 break; 330 case kCFStreamEventOpenCompleted: 331 LOG_ERROR("unexpected kCFStreamEventOpenCompleted"); 332 break; 333 case kCFStreamEventCanAcceptBytes: 334 LOG_ERROR("unexpected kCFStreamEventCanAcceptBytes"); 335 break; 336 } 337 } 338 339 void setHTTPBody(NSMutableURLRequest *request, PassRefPtr<FormData> prpFormData) 340 { 341 RefPtr<FormData> formData = prpFormData; 342 343 if (!formData) 344 return; 345 346 size_t count = formData->elements().size(); 347 348 // Handle the common special case of one piece of form data, with no files. 349 if (count == 1 && !formData->alwaysStream()) { 350 const FormDataElement& element = formData->elements()[0]; 351 if (element.m_type == FormDataElement::data) { 352 NSData *data = [[NSData alloc] initWithBytes:element.m_data.data() length:element.m_data.size()]; 353 [request setHTTPBody:data]; 354 [data release]; 355 return; 356 } 357 } 358 359 #if ENABLE(BLOB) 360 // Check if there is a blob in the form data. 361 bool hasBlob = false; 362 for (size_t i = 0; i < count; ++i) { 363 const FormDataElement& element = formData->elements()[i]; 364 if (element.m_type == FormDataElement::encodedBlob) { 365 hasBlob = true; 366 break; 367 } 368 } 369 370 // If yes, we have to resolve all the blob references and regenerate the form data with only data and file types. 371 if (hasBlob) { 372 RefPtr<FormData> newFormData = FormData::create(); 373 newFormData->setAlwaysStream(formData->alwaysStream()); 374 newFormData->setIdentifier(formData->identifier()); 375 for (size_t i = 0; i < count; ++i) { 376 const FormDataElement& element = formData->elements()[i]; 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->appendFile(element.m_filename, element.m_shouldGenerateFile); 381 else { 382 ASSERT(element.m_type == FormDataElement::encodedBlob); 383 RefPtr<BlobStorageData> blobData = static_cast<BlobRegistryImpl&>(blobRegistry()).getBlobDataFromURL(KURL(ParsedURLString, element.m_blobURL)); 384 if (blobData) { 385 for (size_t j = 0; j < blobData->items().size(); ++j) { 386 const BlobDataItem& blobItem = blobData->items()[j]; 387 if (blobItem.type == BlobDataItem::Data) { 388 newFormData->appendData(blobItem.data->data() + static_cast<int>(blobItem.offset), static_cast<int>(blobItem.length)); 389 } else { 390 ASSERT(blobItem.type == BlobDataItem::File); 391 newFormData->appendFileRange(blobItem.path, blobItem.offset, blobItem.length, blobItem.expectedModificationTime); 392 } 393 } 394 } 395 } 396 } 397 formData = newFormData.release(); 398 count = formData->elements().size(); 399 } 400 #endif 401 402 // Precompute the content length so NSURLConnection doesn't use chunked mode. 403 long long length = 0; 404 for (size_t i = 0; i < count; ++i) { 405 const FormDataElement& element = formData->elements()[i]; 406 if (element.m_type == FormDataElement::data) 407 length += element.m_data.size(); 408 else { 409 #if ENABLE(BLOB) 410 // 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. 411 if (element.m_fileLength != BlobDataItem::toEndOfFile) { 412 length += element.m_fileLength; 413 continue; 414 } 415 #endif 416 long long fileSize; 417 if (getFileSize(element.m_shouldGenerateFile ? element.m_generatedFilename : element.m_filename, fileSize)) 418 length += fileSize; 419 } 420 } 421 422 // Set the length. 423 [request setValue:[NSString stringWithFormat:@"%lld", length] forHTTPHeaderField:@"Content-Length"]; 424 425 // Create and set the stream. 426 427 // Pass the length along with the formData so it does not have to be recomputed. 428 FormContext formContext = { formData.release(), length }; 429 430 RetainPtr<CFReadStreamRef> stream(AdoptCF, wkCreateCustomCFReadStream(formCreate, formFinalize, 431 formOpen, formRead, formCanRead, formClose, formSchedule, formUnschedule, 432 &formContext)); 433 [request setHTTPBodyStream:(NSInputStream *)stream.get()]; 434 } 435 436 FormData* httpBodyFromStream(NSInputStream* stream) 437 { 438 MutexLocker locker(streamFieldsMapMutex()); 439 FormStreamFields* formStream = streamFieldsMap().get(reinterpret_cast<CFReadStreamRef>(stream)); 440 if (!formStream) 441 return 0; 442 return formStream->formData.get(); 51 return httpBodyFromStream(reinterpret_cast<CFReadStreamRef>(stream)); 443 52 } 444 53 -
trunk/Source/WebCore/platform/win/FileSystemWin.cpp
r108353 r112482 124 124 } 125 125 126 #if !USE(CF) 127 126 128 CString fileSystemRepresentation(const String&) 127 129 { 130 ASSERT_NOT_REACHED(); 128 131 return ""; 129 132 } 133 134 #endif !USE(CF) 130 135 131 136 bool makeAllDirectories(const String& path)
Note: See TracChangeset
for help on using the changeset viewer.