예제 #1
0
//
// 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;
}
예제 #2
0
파일: kcookieserver.cpp 프로젝트: KDE/kio
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 &currentCookie = 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();
}
예제 #3
0
//
// 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;
}