// // This function parses cookie_headers and returns a linked list of // KHttpCookie objects for all cookies found in cookie_headers. // If no cookies could be found 0 is returned. // // cookie_headers should be a concatenation of all lines of a HTTP-header // which start with "Set-Cookie". The lines should be separated by '\n's. // KHttpCookieList KCookieJar::makeCookies(const QString &_url, const QCString &cookie_headers, long windowId) { KHttpCookieList cookieList; KHttpCookieList cookieList2; KHttpCookiePtr lastCookie = 0; const char *cookieStr = cookie_headers.data(); QString Name; QString Value; QString fqdn; QString path; bool crossDomain = false; if (!parseURL(_url, fqdn, path)) { // Error parsing _url return KHttpCookieList(); } QString defaultPath; int i = path.findRev('/'); if (i > 0) defaultPath = path.left(i); // The hard stuff :) for(;;) { // check for "Set-Cookie" if (strncmp(cookieStr, "Cross-Domain\n", 13) == 0) { cookieStr += 13; crossDomain = true; } else if (strncasecmp(cookieStr, "Set-Cookie:", 11) == 0) { cookieStr = parseNameValue(cookieStr+11, Name, Value, true); // Host = FQDN // Default domain = "" // Default path according to rfc2109 KHttpCookie *cookie = new KHttpCookie(fqdn, L1(""), defaultPath, Name, Value); if (windowId) cookie->mWindowIds.append(windowId); cookie->mCrossDomain = crossDomain; // Insert cookie in chain cookieList.append(cookie); lastCookie = cookie; } else if (strncasecmp(cookieStr, "Set-Cookie2:", 12) == 0) { // Attempt to follow rfc2965 cookieStr = parseNameValue(cookieStr+12, Name, Value, true, true); // Host = FQDN // Default domain = "" // Default path according to rfc2965 KHttpCookie *cookie = new KHttpCookie(fqdn, L1(""), defaultPath, Name, Value); if (windowId) cookie->mWindowIds.append(windowId); cookie->mCrossDomain = crossDomain; // Insert cookie in chain cookieList2.append(cookie); lastCookie = cookie; } else { // This is not the start of a cookie header, skip till next line. while (*cookieStr && *cookieStr != '\n') cookieStr++; if (*cookieStr == '\n') cookieStr++; if (!*cookieStr) break; // End of cookie_headers else continue; // end of this header, continue with next. } while ((*cookieStr == ';') || (*cookieStr == ' ')) { cookieStr++; // Name-Value pair follows cookieStr = parseNameValue(cookieStr, Name, Value); QCString cName = Name.lower().latin1(); if (cName == "domain") { QString dom = Value.lower(); // RFC2965 3.2.2: If an explicitly specified value does not // start with a dot, the user agent supplies a leading dot if(dom.length() && dom[0] != '.') dom.prepend("."); // remove a trailing dot if(dom.length() > 2 && dom[dom.length()-1] == '.') dom = dom.left(dom.length()-1); if(dom.contains('.') > 1 || dom == ".local") lastCookie->mDomain = dom; } else if (cName == "max-age") { int max_age = Value.toInt(); if (max_age == 0) lastCookie->mExpireDate = 1; else lastCookie->mExpireDate = time(0)+max_age; } else if (cName == "expires") { // Parse brain-dead netscape cookie-format lastCookie->mExpireDate = KRFCDate::parseDate(Value); // Workaround for servers that send the expiration date in // 'Wed Sep 12 07:00:00 2007 GMT' format. See BR# 145244. if (lastCookie->mExpireDate == 0) lastCookie->mExpireDate = KRFCDate::parseDate(fixupDateTime(Value)); } else if (cName == "path") { if (Value.isEmpty()) lastCookie->mPath = QString::null; // Catch "" <> QString::null else lastCookie->mPath = KURL::decode_string(Value); lastCookie->mExplicitPath = true; } else if (cName == "version") { lastCookie->mProtocolVersion = Value.toInt(); } else if ((cName == "secure") || (cName.isEmpty() && Value.lower() == L1("secure"))) { lastCookie->mSecure = true; } else if ((cName == "httponly") || (cName.isEmpty() && Value.lower() == L1("httponly"))) { lastCookie->mHttpOnly = true; } } if (*cookieStr == '\0') break; // End of header // Skip ';' or '\n' cookieStr++; } // RFC2965 cookies come last so that they override netscape cookies. while( !cookieList2.isEmpty() && (lastCookie = cookieList2.take(0)) ) { removeDuplicateFromList(&cookieList, lastCookie, true); cookieList.append(lastCookie); } return cookieList; }
void KCookieServer::checkCookies(KHttpCookieList *cookieList, qlonglong windowId) { KHttpCookieList *list; if (cookieList) { list = cookieList; } else { list = mPendingCookies; } QMutableListIterator<KHttpCookie> cookieIterator(*list); while (cookieIterator.hasNext()) { KHttpCookie &cookie = cookieIterator.next(); const KCookieAdvice advice = mCookieJar->cookieAdvice(cookie); switch (advice) { case KCookieAccept: case KCookieAcceptForSession: mCookieJar->addCookie(cookie); cookieIterator.remove(); break; case KCookieReject: cookieIterator.remove(); break; case KCookieDunno: case KCookieAsk: break; } } if (cookieList || list->isEmpty()) { return; } // Collect all pending cookies with the same host as the first pending cookie const KHttpCookie ¤tCookie = mPendingCookies->first(); KHttpCookieList currentList; currentList.append(currentCookie); const QString currentHost = currentCookie.host(); QList<int> shownCookies; shownCookies << 0; for (int i = 1 /*first already done*/; i < mPendingCookies->count(); ++i) { const KHttpCookie &cookie = (*mPendingCookies)[i]; if (cookie.host() == currentHost) { currentList.append(cookie); shownCookies << i; } } //qDebug() << shownCookies; KCookieWin *kw = new KCookieWin(0L, currentList, mCookieJar->preferredDefaultPolicy(), mCookieJar->showCookieDetails()); if (windowId > 0) { KWindowSystem::setMainWindow(kw, windowId); } KCookieAdvice userAdvice = kw->advice(mCookieJar, currentCookie); delete kw; // Save the cookie config if it has changed mCookieJar->saveConfig(mConfig); // Apply the user's choice to all cookies that are currently // queued for this host (or just the first one, if the user asks for that). QMutableListIterator<KHttpCookie> cookieIterator2(*mPendingCookies); int pendingCookieIndex = -1; while (cookieIterator2.hasNext()) { ++pendingCookieIndex; KHttpCookie &cookie = cookieIterator2.next(); if (cookie.host() != currentHost) { continue; } if (mCookieJar->preferredDefaultPolicy() == KCookieJar::ApplyToShownCookiesOnly && !shownCookies.contains(pendingCookieIndex)) { // User chose "only those cookies", and this one was added while the dialog was up -> skip break; } switch (userAdvice) { case KCookieAccept: case KCookieAcceptForSession: // Store the user's choice for the cookie. // This is only used to check later if the cookie should expire // at the end of the session. The choice is not saved on disk. cookie.setUserSelectedAdvice(userAdvice); mCookieJar->addCookie(cookie); cookieIterator2.remove(); break; case KCookieReject: cookieIterator2.remove(); break; case KCookieDunno: case KCookieAsk: qCWarning(KIO_COOKIEJAR) << "userAdvice not accept or reject, this should never happen!"; break; } } // Check if we can handle any request QMutableListIterator<CookieRequest *> requestIterator(*mRequestList); while (requestIterator.hasNext()) { CookieRequest *request = requestIterator.next(); if (!cookiesPending(request->url)) { const QString res = mCookieJar->findCookies(request->url, request->DOM, request->windowId); QDBusConnection::sessionBus().send(request->reply.createReply(res)); delete request; requestIterator.remove(); } } saveCookieJar(); }
// // Looks for cookies in the cookie jar which are appropriate for _url. // Returned is a string containing all appropriate cookies in a format // which can be added to a HTTP-header without any additional processing. // QString KCookieJar::findCookies(const QString &_url, bool useDOMFormat, long windowId, KHttpCookieList *pendingCookies) { QString cookieStr; QStringList domains; QString fqdn; QString path; KHttpCookiePtr cookie; KCookieAdvice advice = m_globalAdvice; if (!parseURL(_url, fqdn, path)) return cookieStr; bool secureRequest = (_url.find( L1("https://"), 0, false) == 0 || _url.find( L1("webdavs://"), 0, false) == 0); // kdDebug(7104) << "findCookies: URL= " << _url << ", secure = " << secureRequest << endl; extractDomains(fqdn, domains); KHttpCookieList allCookies; for(QStringList::ConstIterator it = domains.begin(); true; ++it) { KHttpCookieList *cookieList; if (it == domains.end()) { cookieList = pendingCookies; // Add pending cookies pendingCookies = 0; if (!cookieList) break; } else { QString key = (*it).isNull() ? L1("") : (*it); cookieList = m_cookieDomains[key]; if (!cookieList) continue; // No cookies for this domain } if (cookieList->getAdvice() != KCookieDunno) advice = cookieList->getAdvice(); for ( cookie=cookieList->first(); cookie != 0; cookie=cookieList->next() ) { // If the we are setup to automatically accept all session cookies and to // treat all cookies as session cookies or the current cookie is a session // cookie, then send the cookie back regardless of either policy. if (advice == KCookieReject && !(m_autoAcceptSessionCookies && (m_ignoreCookieExpirationDate || cookie->expireDate() == 0))) continue; if (!cookie->match(fqdn, domains, path)) continue; if( cookie->isSecure() && !secureRequest ) continue; if( cookie->isHttpOnly() && useDOMFormat ) continue; // Do not send expired cookies. if ( cookie->isExpired (time(0)) ) { // Note there is no need to actually delete the cookie here // since the cookieserver will invoke ::saveCookieJar because // of the state change below. This will then do the job of // deleting the cookie for us. m_cookiesChanged = true; continue; } if (windowId && (cookie->windowIds().find(windowId) == cookie->windowIds().end())) { cookie->windowIds().append(windowId); } if (it == domains.end()) // Only needed when processing pending cookies removeDuplicateFromList(&allCookies, cookie); allCookies.append(cookie); } if (it == domains.end()) break; // Finished. } int cookieCount = 0; int protVersion=0; for ( cookie=allCookies.first(); cookie != 0; cookie=allCookies.next() ) { if (cookie->protocolVersion() > protVersion) protVersion = cookie->protocolVersion(); } for ( cookie=allCookies.first(); cookie != 0; cookie=allCookies.next() ) { if (useDOMFormat) { if (cookieCount > 0) cookieStr += L1("; "); cookieStr += cookie->cookieStr(true); } else { if (cookieCount == 0) { cookieStr += L1("Cookie: "); if (protVersion > 0) { QString version; version.sprintf("$Version=%d; ", protVersion); // Without quotes cookieStr += version; } } else { cookieStr += L1("; "); } cookieStr += cookie->cookieStr(false); } cookieCount++; } return cookieStr; }