static void populateHeadersObject(ScriptObject* object, const HTTPHeaderMap& headers) { HTTPHeaderMap::const_iterator end = headers.end(); for (HTTPHeaderMap::const_iterator it = headers.begin(); it != end; ++it) { object->set(it->first.string(), it->second); } }
bool WebSocketHandshake::processHeaders(const HTTPHeaderMap& headers) { for (HTTPHeaderMap::const_iterator it = headers.begin(); it != headers.end(); ++it) { switch (m_mode) { case Normal: if (it->first == "websocket-origin") m_wsOrigin = it->second; else if (it->first == "websocket-location") m_wsLocation = it->second; else if (it->first == "websocket-protocol") m_wsProtocol = it->second; else if (it->first == "set-cookie") m_setCookie = it->second; else if (it->first == "set-cookie2") m_setCookie2 = it->second; continue; case Incomplete: case Failed: case Connected: ASSERT_NOT_REACHED(); } ASSERT_NOT_REACHED(); } return true; }
void WebSocketServerConnection::upgradeToWebSocketServerConnection(PassRefPtr<HTTPRequest> request) { ASSERT(request); ASSERT(m_mode == HTTP); m_mode = WebSocket; RefPtr<HTTPRequest> protectedRequest(request); // Ask the client if we should upgrade for this or not. if (!m_client->didReceiveWebSocketUpgradeHTTPRequest(this, protectedRequest)) { shutdownNow(); return; } // Build and send the WebSocket handshake response. const HTTPHeaderMap& requestHeaders = protectedRequest->headerFields(); String accept = WebSocketHandshake::getExpectedWebSocketAccept(requestHeaders.get("Sec-WebSocket-Key")); HTTPHeaderMap responseHeaders; responseHeaders.add("Upgrade", requestHeaders.get("Upgrade")); responseHeaders.add("Connection", requestHeaders.get("Connection")); responseHeaders.add("Sec-WebSocket-Accept", accept); sendHTTPResponseHeader(101, "WebSocket Protocol Handshake", responseHeaders); m_client->didEstablishWebSocketConnection(this, protectedRequest); }
void CurlDownload::addHeaders(const ResourceRequest& request) { if (request.httpHeaderFields().size() > 0) { struct curl_slist* headers = 0; HTTPHeaderMap customHeaders = request.httpHeaderFields(); HTTPHeaderMap::const_iterator end = customHeaders.end(); for (HTTPHeaderMap::const_iterator it = customHeaders.begin(); it != end; ++it) { const String& value = it->value; String headerString(it->key); if (value.isEmpty()) // Insert the ; to tell curl that this header has an empty value. headerString.append(";"); else { headerString.append(": "); headerString.append(value); } CString headerLatin1 = headerString.latin1(); headers = curl_slist_append(headers, headerLatin1.data()); } if (headers) { curl_easy_setopt(m_curlHandle, CURLOPT_HTTPHEADER, headers); m_customHeaders = headers; } } }
void WebInspectorServer::didReceiveUnrecognizedHTTPRequest(WebSocketServerConnection* connection, PassRefPtr<HTTPRequest> request) { // request->url() contains only the path extracted from the HTTP request line // and URL is poor at parsing incomplete URLs, so extract the interesting parts manually. String path = request->url(); size_t pathEnd = path.find('?'); if (pathEnd == notFound) pathEnd = path.find('#'); if (pathEnd != notFound) path.truncate(pathEnd); // Ask for the complete payload in memory for the sake of simplicity. A more efficient way would be // to ask for header data and then let the platform abstraction write the payload straight on the connection. Vector<char> body; String contentType; bool found = platformResourceForPath(path, body, contentType); HTTPHeaderMap headerFields; headerFields.set("Connection", "close"); headerFields.set("Content-Length", String::number(body.size())); if (found) headerFields.set("Content-Type", contentType); // Send when ready and close immediately afterwards. connection->sendHTTPResponseHeader(found ? 200 : 404, found ? "OK" : "Not Found", headerFields); connection->sendRawData(body.data(), body.size()); connection->shutdownAfterSendOrNow(); }
bool ArgumentCoder<ResourceResponse>::decode(ArgumentDecoder* decoder, ResourceResponse& resourceResponse) { if (kShouldSerializeWebCoreData) { bool responseIsNull; if (!decoder->decode(responseIsNull)) return false; if (responseIsNull) { resourceResponse = ResourceResponse(); return true; } ResourceResponse response; String url; if (!decoder->decode(url)) return false; response.setURL(KURL(KURL(), url)); int32_t httpStatusCode; if (!decoder->decode(httpStatusCode)) return false; response.setHTTPStatusCode(httpStatusCode); HTTPHeaderMap headers; if (!decoder->decode(headers)) return false; for (HTTPHeaderMap::const_iterator it = headers.begin(), end = headers.end(); it != end; ++it) response.setHTTPHeaderField(it->key, it->value); String mimeType; if (!decoder->decode(mimeType)) return false; response.setMimeType(mimeType); String textEncodingName; if (!decoder->decode(textEncodingName)) return false; response.setTextEncodingName(textEncodingName); int64_t contentLength; if (!decoder->decode(contentLength)) return false; response.setExpectedContentLength(contentLength); String httpStatusText; if (!decoder->decode(httpStatusText)) return false; response.setHTTPStatusText(httpStatusText); String suggestedFilename; if (!decoder->decode(suggestedFilename)) return false; response.setSuggestedFilename(suggestedFilename); resourceResponse = response; } return decodePlatformData(decoder, resourceResponse); }
void InspectorResourceAgent::willLoadXHR(ThreadableLoaderClient* client, const String& method, const KURL& url, bool async, PassRefPtr<FormData> formData, const HTTPHeaderMap& headers, bool includeCredentials) { RefPtr<XHRReplayData> xhrReplayData = XHRReplayData::create(method, url, async, formData, includeCredentials); HTTPHeaderMap::const_iterator end = headers.end(); for (HTTPHeaderMap::const_iterator it = headers.begin(); it!= end; ++it) xhrReplayData->addHeader(it->key, it->value); m_pendingXHRReplayData.set(client, xhrReplayData); }
static PassRefPtr<InspectorObject> buildObjectForHeaders(const HTTPHeaderMap& headers) { RefPtr<InspectorObject> headersObject = InspectorObject::create(); HTTPHeaderMap::const_iterator end = headers.end(); for (HTTPHeaderMap::const_iterator it = headers.begin(); it != end; ++it) headersObject->setString(it->first.string(), it->second); return headersObject; }
bool PreflightResultCacheItem::allowsCrossSiteHeaders(const HTTPHeaderMap& requestHeaders) const { HTTPHeaderMap::const_iterator end = requestHeaders.end(); for (HTTPHeaderMap::const_iterator it = requestHeaders.begin(); it != end; ++it) { if (!m_headers.contains(it->first) && !isOnAccessControlSimpleRequestHeaderWhitelist(it->first)) return false; } return true; }
NPError PluginView::handlePost(const char* url, const char* target, uint32 len, const char* buf, bool file, void* notifyData, bool sendNotification, bool allowHeaders) { if (!url || !len || !buf) return NPERR_INVALID_PARAM; FrameLoadRequest frameLoadRequest; HTTPHeaderMap headerFields; Vector<char> buffer; if (file) { NPError readResult = handlePostReadFile(buffer, len, buf); if(readResult != NPERR_NO_ERROR) return readResult; } else { buffer.resize(len); memcpy(buffer.data(), buf, len); } const char* postData = buffer.data(); int postDataLength = buffer.size(); if (allowHeaders) { if (startsWithBlankLine(buffer)) { postData++; postDataLength--; } else { int location = locationAfterFirstBlankLine(buffer); if (location != -1) { // If the blank line is somewhere in the middle of the buffer, everything before is the header headerFields = parseRFC822HeaderFields(buffer, location); unsigned dataLength = buffer.size() - location; // Sometimes plugins like to set Content-Length themselves when they post, // but WebFoundation does not like that. So we will remove the header // and instead truncate the data to the requested length. String contentLength = headerFields.get("Content-Length"); if (!contentLength.isNull()) dataLength = min(contentLength.toInt(), (int)dataLength); headerFields.remove("Content-Length"); postData += location; postDataLength = dataLength; } } } frameLoadRequest.resourceRequest().setHTTPMethod("POST"); frameLoadRequest.resourceRequest().setURL(makeURL(m_baseURL, url)); frameLoadRequest.resourceRequest().addHTTPHeaderFields(headerFields); frameLoadRequest.resourceRequest().setHTTPBody(FormData::create(postData, postDataLength)); frameLoadRequest.setFrameName(target); return load(frameLoadRequest, sendNotification, notifyData); }
bool CrossOriginPreflightResultCacheItem::allowsCrossOriginHeaders(const HTTPHeaderMap& requestHeaders, String& errorDescription) const { HTTPHeaderMap::const_iterator end = requestHeaders.end(); for (HTTPHeaderMap::const_iterator it = requestHeaders.begin(); it != end; ++it) { if (!m_headers.contains(it->first) && !isOnAccessControlSimpleRequestHeaderWhitelist(it->first, it->second)) { errorDescription = "Request header field " + it->first.string() + " is not allowed by Access-Control-Allow-Headers."; return false; } } return true; }
static NPError parsePostBuffer(bool isFile, const char *buffer, uint32_t length, bool parseHeaders, HTTPHeaderMap& headerFields, Vector<uint8_t>& bodyData) { RefPtr<SharedBuffer> fileContents; const char* postBuffer = 0; uint32_t postBufferSize = 0; if (isFile) { fileContents = SharedBuffer::createWithContentsOfFile(String::fromUTF8(buffer)); if (!fileContents) return NPERR_FILE_NOT_FOUND; postBuffer = fileContents->data(); postBufferSize = fileContents->size(); // FIXME: The NPAPI spec states that the file should be deleted here. } else { postBuffer = buffer; postBufferSize = length; } if (parseHeaders) { if (startsWithBlankLine(postBuffer, postBufferSize)) { postBuffer++; postBufferSize--; } else { int location = locationAfterFirstBlankLine(postBuffer, postBufferSize); if (location != -1) { // If the blank line is somewhere in the middle of the buffer, everything before is the header headerFields = parseRFC822HeaderFields(postBuffer, location); unsigned dataLength = postBufferSize - location; // Sometimes plugins like to set Content-Length themselves when they post, // but WebFoundation does not like that. So we will remove the header // and instead truncate the data to the requested length. String contentLength = headerFields.get("Content-Length"); if (!contentLength.isNull()) dataLength = min(contentLength.toInt(), (int)dataLength); headerFields.remove("Content-Length"); postBuffer += location; postBufferSize = dataLength; } } } ASSERT(bodyData.isEmpty()); bodyData.append(postBuffer, postBufferSize); return NPERR_NO_ERROR; }
bool isSimpleCrossOriginAccessRequest(const String& method, const HTTPHeaderMap& headerMap) { if (!isOnAccessControlSimpleRequestMethodWhitelist(method)) return false; HTTPHeaderMap::const_iterator end = headerMap.end(); for (HTTPHeaderMap::const_iterator it = headerMap.begin(); it != end; ++it) { if (!isOnAccessControlSimpleRequestHeaderWhitelist(it->first, it->second)) return false; } return true; }
bool FetchUtils::isSimpleOrForbiddenRequest(const String& method, const HTTPHeaderMap& headerMap) { if (!isSimpleMethod(method)) return false; HTTPHeaderMap::const_iterator end = headerMap.end(); for (HTTPHeaderMap::const_iterator it = headerMap.begin(); it != end; ++it) { if (!isSimpleHeader(it->key, it->value) && !isForbiddenHeaderName(it->key)) return false; } return true; }
bool ResourceHandle::startHttp(String urlString) { if (!session) { session = soup_session_async_new(); soup_session_add_feature(session, SOUP_SESSION_FEATURE(getCookieJar())); const char* soup_debug = g_getenv("WEBKIT_SOUP_LOGGING"); if (soup_debug) { int soup_debug_level = atoi(soup_debug); SoupLogger* logger = soup_logger_new(static_cast<SoupLoggerLogLevel>(soup_debug_level), -1); soup_logger_attach(logger, session); g_object_unref(logger); } } SoupMessage* msg; msg = soup_message_new(request().httpMethod().utf8().data(), urlString.utf8().data()); g_signal_connect(msg, "restarted", G_CALLBACK(restartedCallback), this); g_signal_connect(msg, "got-headers", G_CALLBACK(gotHeadersCallback), this); g_signal_connect(msg, "got-chunk", G_CALLBACK(gotChunkCallback), this); HTTPHeaderMap customHeaders = d->m_request.httpHeaderFields(); if (!customHeaders.isEmpty()) { HTTPHeaderMap::const_iterator end = customHeaders.end(); for (HTTPHeaderMap::const_iterator it = customHeaders.begin(); it != end; ++it) soup_message_headers_append(msg->request_headers, it->first.utf8().data(), it->second.utf8().data()); } FormData* httpBody = d->m_request.httpBody(); if (httpBody && !httpBody->isEmpty()) { // Making a copy of the request body isn't the most efficient way to // serialize it, but by far the most simple. Dealing with individual // FormData elements and shared buffers should be more memory // efficient. // // This possibly isn't handling file uploads/attachments, for which // shared buffers or streaming should definitely be used. Vector<char> body; httpBody->flatten(body); soup_message_set_request(msg, d->m_request.httpContentType().utf8().data(), SOUP_MEMORY_COPY, body.data(), body.size()); } d->m_msg = static_cast<SoupMessage*>(g_object_ref(msg)); soup_session_queue_message(session, d->m_msg, finishedCallback, this); return true; }
static void addHeadersFromHashMap(CFMutableURLRequestRef request, const HTTPHeaderMap& requestHeaders) { if (!requestHeaders.size()) return; HTTPHeaderMap::const_iterator end = requestHeaders.end(); for (HTTPHeaderMap::const_iterator it = requestHeaders.begin(); it != end; ++it) { CFStringRef key = it->first.createCFString(); CFStringRef value = it->second.createCFString(); CFURLRequestSetHTTPHeaderFieldValue(request, key, value); CFRelease(key); CFRelease(value); } }
static void addHeaders(JSContextRef context, JSObjectRef object, const HTTPHeaderMap& headers) { ASSERT_ARG(context, context); ASSERT_ARG(object, object); HTTPHeaderMap::const_iterator end = headers.end(); for (HTTPHeaderMap::const_iterator it = headers.begin(); it != end; ++it) { JSStringRef field = JSStringCreateWithCharacters(it->first.characters(), it->first.length()); JSStringRef valueString = JSStringCreateWithCharacters(it->second.characters(), it->second.length()); JSValueRef value = JSValueMakeString(context, valueString); JSObjectSetProperty(context, object, field, value, kJSPropertyAttributeNone, 0); JSStringRelease(field); JSStringRelease(valueString); } }
static inline void setHeaderFields(CFMutableURLRequestRef request, const HTTPHeaderMap& requestHeaders) { // Remove existing headers first, as some of them may no longer be present in the map. RetainPtr<CFDictionaryRef> oldHeaderFields(AdoptCF, CFURLRequestCopyAllHTTPHeaderFields(request)); CFIndex oldHeaderFieldCount = CFDictionaryGetCount(oldHeaderFields.get()); if (oldHeaderFieldCount) { Vector<CFStringRef> oldHeaderFieldNames(oldHeaderFieldCount); CFDictionaryGetKeysAndValues(oldHeaderFields.get(), reinterpret_cast<const void**>(&oldHeaderFieldNames[0]), 0); for (CFIndex i = 0; i < oldHeaderFieldCount; ++i) CFURLRequestSetHTTPHeaderFieldValue(request, oldHeaderFieldNames[i], 0); } for (HTTPHeaderMap::const_iterator it = requestHeaders.begin(), end = requestHeaders.end(); it != end; ++it) CFURLRequestSetHTTPHeaderFieldValue(request, it->key.string().createCFString().get(), it->value.createCFString().get()); }
bool FetchUtils::isSimpleRequest(const String& method, const HTTPHeaderMap& headerMap) { if (!isSimpleMethod(method)) return false; HTTPHeaderMap::const_iterator end = headerMap.end(); for (HTTPHeaderMap::const_iterator it = headerMap.begin(); it != end; ++it) { // Preflight is required for MIME types that can not be sent via form // submission. if (!isSimpleHeader(it->key, it->value)) return false; } return true; }
static bool canSkipPrelight(PreflightResultCache::iterator cacheIt, bool includeCredentials, const String& method, const HTTPHeaderMap& requestHeaders) { PreflightResultCacheItem* item = cacheIt->second; if (item->m_absoluteExpiryTime < currentTime()) return false; if (includeCredentials && !item->m_credentials) return false; if (!item->m_methods->contains(method) && method != "GET" && method != "POST") return false; HTTPHeaderMap::const_iterator end = requestHeaders.end(); for (HTTPHeaderMap::const_iterator it = requestHeaders.begin(); it != end; ++it) { if (!item->m_headers->contains(it->first) && !isOnAccessControlSimpleRequestHeaderWhitelist(it->first)) return false; } return true; }
static ParsedContentRange parseContentRangeInHeader(const HTTPHeaderMap& headers) { String contentRangeValue = headers.get(HTTPHeaderName::ContentRange); if (contentRangeValue.isEmpty()) return ParsedContentRange(); return ParsedContentRange(contentRangeValue); }
void WebSocketServerConnection::sendHTTPResponseHeader(int statusCode, const String& statusText, const HTTPHeaderMap& headerFields) { StringBuilder builder; builder.append("HTTP/1.1 "); builder.append(String::number(statusCode)); builder.append(" "); builder.append(statusText); builder.append("\r\n"); HTTPHeaderMap::const_iterator end = headerFields.end(); for (HTTPHeaderMap::const_iterator it = headerFields.begin(); it != end; ++it) { builder.append(it->first); builder.append(": "); builder.append(it->second + "\r\n"); } builder.append("\r\n"); CString header = builder.toString().latin1(); m_socket->send(header.data(), header.length()); }
SoupMessage* ResourceRequest::toSoupMessage() const { SoupMessage* soupMessage = soup_message_new(httpMethod().utf8().data(), url().string().utf8().data()); if (!soupMessage) return 0; HTTPHeaderMap headers = httpHeaderFields(); SoupMessageHeaders* soupHeaders = soupMessage->request_headers; if (!headers.isEmpty()) { HTTPHeaderMap::const_iterator end = headers.end(); for (HTTPHeaderMap::const_iterator it = headers.begin(); it != end; ++it) soup_message_headers_append(soupHeaders, it->first.string().utf8().data(), it->second.utf8().data()); } // Body data is only handled at ResourceHandleSoup::startHttp for // now; this is because this may not be a good place to go // openning and mmapping files. We should maybe revisit this. return soupMessage; }
static std::optional<std::chrono::system_clock::time_point> parseDateValueInHeader(const HTTPHeaderMap& headers, HTTPHeaderName headerName) { String headerValue = headers.get(headerName); if (headerValue.isEmpty()) return { }; // This handles all date formats required by RFC2616: // Sun, 06 Nov 1994 08:49:37 GMT ; RFC 822, updated by RFC 1123 // Sunday, 06-Nov-94 08:49:37 GMT ; RFC 850, obsoleted by RFC 1036 // Sun Nov 6 08:49:37 1994 ; ANSI C's asctime() format return parseHTTPDate(headerValue); }
SoupMessage* ResourceResponse::toSoupMessage() const { // This GET here is just because SoupMessage wants it, we dn't really know. SoupMessage* soupMessage = soup_message_new("GET", url().string().utf8().data()); if (!soupMessage) return 0; soupMessage->status_code = httpStatusCode(); HTTPHeaderMap headers = httpHeaderFields(); SoupMessageHeaders* soupHeaders = soupMessage->response_headers; if (!headers.isEmpty()) { HTTPHeaderMap::const_iterator end = headers.end(); for (HTTPHeaderMap::const_iterator it = headers.begin(); it != end; ++it) soup_message_headers_append(soupHeaders, it->first.string().utf8().data(), it->second.utf8().data()); } // Body data is not in the message. return soupMessage; }
static double parseDateValueInHeader(const HTTPHeaderMap& headers, const AtomicString& headerName) { const AtomicString& headerValue = headers.get(headerName); if (headerValue.isEmpty()) return std::numeric_limits<double>::quiet_NaN(); // This handles all date formats required by RFC2616: // Sun, 06 Nov 1994 08:49:37 GMT ; RFC 822, updated by RFC 1123 // Sunday, 06-Nov-94 08:49:37 GMT ; RFC 850, obsoleted by RFC 1036 // Sun Nov 6 08:49:37 1994 ; ANSI C's asctime() format double dateInMilliseconds = parseDate(headerValue); if (!std::isfinite(dateInMilliseconds)) return std::numeric_limits<double>::quiet_NaN(); return dateInMilliseconds / 1000; }
void ResourceHandleManager::initializeHandle(ResourceHandle* job) { KURL kurl = job->request().url(); // Remove any fragment part, otherwise curl will send it as part of the request. kurl.setRef(""); ResourceHandleInternal* d = job->getInternal(); String url = kurl.string(); if (kurl.isLocalFile()) { String query = kurl.query(); // Remove any query part sent to a local file. if (!query.isEmpty()) url = url.left(url.find(query)); // Determine the MIME type based on the path. d->m_response.setMimeType(MIMETypeRegistry::getMIMETypeForPath(url)); } d->m_handle = curl_easy_init(); #ifndef NDEBUG if (getenv("DEBUG_CURL")) curl_easy_setopt(d->m_handle, CURLOPT_VERBOSE, 1); #endif curl_easy_setopt(d->m_handle, CURLOPT_PRIVATE, job); curl_easy_setopt(d->m_handle, CURLOPT_ERRORBUFFER, m_curlErrorBuffer); curl_easy_setopt(d->m_handle, CURLOPT_WRITEFUNCTION, writeCallback); curl_easy_setopt(d->m_handle, CURLOPT_WRITEDATA, job); curl_easy_setopt(d->m_handle, CURLOPT_HEADERFUNCTION, headerCallback); curl_easy_setopt(d->m_handle, CURLOPT_WRITEHEADER, job); curl_easy_setopt(d->m_handle, CURLOPT_AUTOREFERER, 1); curl_easy_setopt(d->m_handle, CURLOPT_FOLLOWLOCATION, 1); curl_easy_setopt(d->m_handle, CURLOPT_MAXREDIRS, 10); curl_easy_setopt(d->m_handle, CURLOPT_HTTPAUTH, CURLAUTH_ANY); curl_easy_setopt(d->m_handle, CURLOPT_SHARE, m_curlShareHandle); curl_easy_setopt(d->m_handle, CURLOPT_DNS_CACHE_TIMEOUT, 60 * 5); // 5 minutes // FIXME: Enable SSL verification when we have a way of shipping certs // and/or reporting SSL errors to the user. if (ignoreSSLErrors) curl_easy_setopt(d->m_handle, CURLOPT_SSL_VERIFYPEER, false); // enable gzip and deflate through Accept-Encoding: curl_easy_setopt(d->m_handle, CURLOPT_ENCODING, ""); // url must remain valid through the request ASSERT(!d->m_url); // url is in ASCII so latin1() will only convert it to char* without character translation. d->m_url = strdup(url.latin1().data()); curl_easy_setopt(d->m_handle, CURLOPT_URL, d->m_url); if (m_cookieJarFileName) { curl_easy_setopt(d->m_handle, CURLOPT_COOKIEFILE, m_cookieJarFileName); curl_easy_setopt(d->m_handle, CURLOPT_COOKIEJAR, m_cookieJarFileName); } struct curl_slist* headers = 0; if (job->request().httpHeaderFields().size() > 0) { HTTPHeaderMap customHeaders = job->request().httpHeaderFields(); HTTPHeaderMap::const_iterator end = customHeaders.end(); for (HTTPHeaderMap::const_iterator it = customHeaders.begin(); it != end; ++it) { String key = it->first; String value = it->second; String headerString(key); headerString.append(": "); headerString.append(value); CString headerLatin1 = headerString.latin1(); headers = curl_slist_append(headers, headerLatin1.data()); } } if ("GET" == job->request().httpMethod()) curl_easy_setopt(d->m_handle, CURLOPT_HTTPGET, TRUE); else if ("POST" == job->request().httpMethod()) setupPOST(job, &headers); else if ("PUT" == job->request().httpMethod()) setupPUT(job, &headers); else if ("HEAD" == job->request().httpMethod()) curl_easy_setopt(d->m_handle, CURLOPT_NOBODY, TRUE); if (headers) { curl_easy_setopt(d->m_handle, CURLOPT_HTTPHEADER, headers); d->m_customHeaders = headers; } }
void ResourceRequestBase::addHTTPHeaderFields(const HTTPHeaderMap& headerFields) { HTTPHeaderMap::const_iterator end = headerFields.end(); for (HTTPHeaderMap::const_iterator it = headerFields.begin(); it != end; ++it) addHTTPHeaderField(it->first, it->second); }
static HTTPHeaderMap parseRFC822HeaderFields(const char* bytes, unsigned length) { String lastHeaderKey; HTTPHeaderMap headerFields; // Loop over lines until we're past the header, or we can't find any more end-of-lines while (const char* endOfLine = findEndOfLine(bytes, length)) { const char* line = bytes; int lineLength = endOfLine - bytes; // Move bytes to the character after the terminator as returned by findEndOfLine. bytes = endOfLine + 1; if ((*endOfLine == '\r') && (*bytes == '\n')) bytes++; // Safe since findEndOfLine won't return a spanning CRLF. length -= (bytes - line); if (!lineLength) { // Blank line; we're at the end of the header break; } if (*line == ' ' || *line == '\t') { // Continuation of the previous header if (lastHeaderKey.isNull()) { // malformed header; ignore it and continue continue; } // Merge the continuation of the previous header String currentValue = headerFields.get(lastHeaderKey); String newValue(line, lineLength); headerFields.set(lastHeaderKey, currentValue + newValue); } else { // Brand new header const char* colon = line; while (*colon != ':' && colon != endOfLine) colon++; if (colon == endOfLine) { // malformed header; ignore it and continue continue; } lastHeaderKey = capitalizeRFC822HeaderFieldName(String(line, colon - line)); String value; for (colon++; colon != endOfLine; colon++) { if (*colon != ' ' && *colon != '\t') break; } if (colon == endOfLine) value = ""; else value = String(colon, endOfLine - colon); String oldValue = headerFields.get(lastHeaderKey); if (!oldValue.isNull()) value = oldValue + ", " + value; headerFields.set(lastHeaderKey, value); } } return headerFields; }
void ResourceRequest::addHTTPHeaderFields(const HTTPHeaderMap& headerFields) { HTTPHeaderMap::const_iterator end = headerFields.end(); for (HTTPHeaderMap::const_iterator it = headerFields.begin(); it != end; ++it) addHTTPHeaderField(it->key, it->value); }