static HTTPBody toHTTPBody(const FormData& formData) { HTTPBody httpBody; for (const auto& formDataElement : formData.elements()) { HTTPBody::Element element; switch (formDataElement.m_type) { case FormDataElement::Type::Data: element.type = HTTPBody::Element::Type::Data; element.data = formDataElement.m_data; break; case FormDataElement::Type::EncodedFile: element.filePath = formDataElement.m_filename; element.fileStart = formDataElement.m_fileStart; if (formDataElement.m_fileLength != BlobDataItem::toEndOfFile) element.fileLength = formDataElement.m_fileLength; if (formDataElement.m_expectedFileModificationTime != invalidFileTime()) element.expectedFileModificationTime = formDataElement.m_expectedFileModificationTime; break; case FormDataElement::Type::EncodedBlob: element.blobURLString = formDataElement.m_url.string(); break; } httpBody.elements.append(WTF::move(element)); } return httpBody; }
CFArrayRef arrayFromFormData(const FormData& d) { size_t size = d.elements().size(); CFMutableArrayRef a = CFArrayCreateMutable(0, d.elements().size(), &kCFTypeArrayCallBacks); for (size_t i = 0; i < size; ++i) { const FormDataElement& e = d.elements()[i]; if (e.m_type == FormDataElement::data) { CFDataRef data = CFDataCreate(0, (const UInt8*)e.m_data.data(), e.m_data.size()); CFArrayAppendValue(a, data); CFRelease(data); } else { ASSERT(e.m_type == FormDataElement::encodedFile); CFStringRef filename = e.m_filename.createCFString(); CFArrayAppendValue(a, filename); CFRelease(filename); } } return a; }
static void* formCreate(CFReadStreamRef stream, void* context) { FormData* formData = static_cast<FormData*>(context); CFSetCallBacks runLoopAndModeCallBacks = { 0, pairRetain, pairRelease, NULL, pairEqual, pairHash }; FormStreamFields* newInfo = new FormStreamFields; newInfo->scheduledRunLoopPairs = CFSetCreateMutable(0, 0, &runLoopAndModeCallBacks); newInfo->currentStream = NULL; newInfo->currentData = 0; newInfo->formStream = stream; // Don't retain. That would create a reference cycle. // Append in reverse order since we remove elements from the end. size_t size = formData->elements().size(); newInfo->remainingElements.reserveCapacity(size); for (size_t i = 0; i < size; ++i) newInfo->remainingElements.append(formData->elements()[size - i - 1]); getStreamFormDatas().set(stream, adoptRef(formData)); return newInfo; }
static bool startHttp(ResourceHandle* handle) { ASSERT(handle); SoupSession* session = handle->defaultSession(); ensureSessionIsInitialized(session); ResourceHandleInternal* d = handle->getInternal(); ResourceRequest request(handle->request()); KURL url(request.url()); url.removeFragmentIdentifier(); request.setURL(url); d->m_msg = request.toSoupMessage(); if (!d->m_msg) return false; if(!handle->shouldContentSniff()) soup_message_disable_feature(d->m_msg, SOUP_TYPE_CONTENT_SNIFFER); g_signal_connect(d->m_msg, "restarted", G_CALLBACK(restartedCallback), handle); g_signal_connect(d->m_msg, "got-headers", G_CALLBACK(gotHeadersCallback), handle); g_signal_connect(d->m_msg, "content-sniffed", G_CALLBACK(contentSniffedCallback), handle); g_signal_connect(d->m_msg, "got-chunk", G_CALLBACK(gotChunkCallback), handle); g_object_set_data(G_OBJECT(d->m_msg), "resourceHandle", reinterpret_cast<void*>(handle)); FormData* httpBody = d->m_request.httpBody(); if (httpBody && !httpBody->isEmpty()) { size_t numElements = httpBody->elements().size(); // handle the most common case (i.e. no file upload) if (numElements < 2) { Vector<char> body; httpBody->flatten(body); soup_message_set_request(d->m_msg, d->m_request.httpContentType().utf8().data(), SOUP_MEMORY_COPY, body.data(), body.size()); } else { /* * we have more than one element to upload, and some may * be (big) files, which we will want to mmap instead of * copying into memory; TODO: support upload of non-local * (think sftp://) files by using GIO? */ soup_message_body_set_accumulate(d->m_msg->request_body, FALSE); for (size_t i = 0; i < numElements; i++) { const FormDataElement& element = httpBody->elements()[i]; if (element.m_type == FormDataElement::data) soup_message_body_append(d->m_msg->request_body, SOUP_MEMORY_TEMPORARY, element.m_data.data(), element.m_data.size()); else { /* * mapping for uploaded files code inspired by technique used in * libsoup's simple-httpd test */ GError* error = 0; gchar* fileName = filenameFromString(element.m_filename); GMappedFile* fileMapping = g_mapped_file_new(fileName, false, &error); g_free(fileName); if (error) { g_error_free(error); g_signal_handlers_disconnect_matched(d->m_msg, G_SIGNAL_MATCH_DATA, 0, 0, 0, 0, handle); g_object_unref(d->m_msg); d->m_msg = 0; return false; } SoupBuffer* soupBuffer = soup_buffer_new_with_owner(g_mapped_file_get_contents(fileMapping), g_mapped_file_get_length(fileMapping), fileMapping, #if GLIB_CHECK_VERSION(2, 21, 3) reinterpret_cast<GDestroyNotify>(g_mapped_file_unref)); #else reinterpret_cast<GDestroyNotify>(g_mapped_file_free)); #endif soup_message_body_append_buffer(d->m_msg->request_body, soupBuffer); soup_buffer_free(soupBuffer); } } } }