QNetworkReply* KVNetworkAccessManager::createRequest(Operation op, const QNetworkRequest &req, QIODevice *outgoingData)
{
	QNetworkRequest request = req;
	request.setRawHeader("User-Agent", "Mozilla/5.0 (Windows NT 6.1; WOW64; rv:28.0) Gecko/20100101 Firefox/28.0");

	if(op == PostOperation) {
		//qDebug() << "POST" << request.url().path();
		// If the request addressed to API - translate this request
		if(request.url().host() != "localhost" && request.url().host() != "127.0.0.1" && !request.url().host().contains(".dmm.com")) {
			QNetworkReply *r = QNetworkAccessManager::createRequest(op, request, outgoingData);
			KVNetworkReply *reply = new KVNetworkReply(r->parent(), r, this, translation);
			return reply;
		}
	}
	else if(op == GetOperation)
	{
		// If the request addressed to DMM - create hacked cookies
		if(request.url().host().contains(".dmm.com"))
		{
			QNetworkCookie languageCookie;
			languageCookie.setDomain(".dmm.com");
			languageCookie.setPath("/");
			languageCookie.setName("cklg");
			languageCookie.setValue("ja");
			languageCookie.setExpirationDate(QDateTime::currentDateTime().addYears(1));

			QNetworkCookie locationCookie;
			locationCookie.setDomain(".dmm.com");
			locationCookie.setPath("/");
			locationCookie.setName("ckcy");
			locationCookie.setValue("1");
			locationCookie.setExpirationDate(QDateTime::currentDateTime().addYears(1));

			if(cookieHack)
			{
				cookieJar()->insertCookie(languageCookie);
				cookieJar()->insertCookie(locationCookie);
			}
			else
			{
				cookieJar()->deleteCookie(languageCookie);
				cookieJar()->deleteCookie(locationCookie);
			}
		}
	}

	QNetworkReply *reply = QNetworkAccessManager::createRequest(op, request, outgoingData);

	// If the request if for an SWF or MP3 file, track it and report progress
	if(req.url().path().endsWith(".swf") || req.url().path().endsWith(".mp3"))
	{
		connect(reply, SIGNAL(metaDataChanged()), this, SLOT(trackedGETMetaDataChanged()));
		connect(reply, SIGNAL(readyRead()), this, SLOT(trackedGETReadyRead()));
		connect(reply, SIGNAL(finished()), this, SLOT(trackedGETFinished()));
	}

	return reply;
}
Ejemplo n.º 2
0
void ChatService::startLoginRequest()
{
    _buddylist_poll_timer->stop();
    
    qDebug() << _network->cookieJar()->cookiesForUrl(QUrl(FACEBOOK_URL)).count() << " cookies";
    QList<QNetworkCookie> cookies;
    
    QMap<QString, QString> params;
    QUrl url(FACEBOOK_LOGIN_URL);

    QNetworkCookie cookie;
    cookie.setDomain(".facebook.com");
    cookie.setPath("/");

    // facebook uses this cookie to test for cookie support
    // if we dont set it it thinks we don't support cookies.
    cookie.setName("test_cookie");
    cookie.setValue("1");
    cookies << cookie;

    cookie.setName("isfbe");
    cookie.setValue("false");
    cookies << cookie;

    _network->cookieJar()->setCookiesFromUrl(cookies, QUrl(FACEBOOK_URL));

    qDebug() << _network->cookieJar()->cookiesForUrl(QUrl(FACEBOOK_URL)).count() << " cookies";

    // it seems those are not really needed, until I figure what
    // are they for
    //params.insert("md5pass", "0");
    //params.insert("noerror", "1");

    params.insert("email", _login);
    params.insert("pass", _password);
    params.insert("persistent", "1");
    params.insert("login", "Login");
    params.insert("charset_test", "€,´,€,´,水,Д,Є");

    QString data = encodePostParams(params);
    qDebug() << data;

    QNetworkReply *reply = _network->post(QNetworkRequest(url), data.toAscii());
    reply->setParent(this);
    
    QObject::connect(reply, SIGNAL(finished()), this, SLOT(slotLoginRequestFinished()));
    QObject::connect(reply, SIGNAL(error(QNetworkReply::NetworkError)), this, SLOT(slotLoginRequestError(QNetworkReply::NetworkError)));
}
Ejemplo n.º 3
0
void CookieJar::loadCookies()
{
    QString fName = m_appPath;
    fName += "cookies";
    QSettings cnFile(fName, QSettings::IniFormat);

    setVkLogin(cnFile.value("login").toString());

    QList<QNetworkCookie> cookies;
    int size = cnFile.beginReadArray("cookies");
    for(int i=0; i<size; i++) {
        QNetworkCookie cook;

        cnFile.setArrayIndex(i);

        cook.setName(cnFile.value("name").toByteArray());
        cook.setValue(cnFile.value("value").toByteArray());
        cook.setDomain(cnFile.value("domain").toByteArray());
        cook.setPath(cnFile.value("path").toByteArray());

        cookies.insert(i, cook);
    }
    cnFile.endArray();

    setAllCookies(cookies);
}
Ejemplo n.º 4
0
void NResponse::setSessionCookie(const QString & sessionId, bool secured)
{
    QNetworkCookie sessionCookie;
    sessionCookie.setHttpOnly (true);
    sessionCookie.setName ("nawis_sessionId");
    sessionCookie.setPath ("/");
    sessionCookie.setSecure(secured);
    sessionCookie.setValue(sessionId.toAscii());

    m_httpHeader.setValue("Set-Cookie", sessionCookie.toRawForm(QNetworkCookie::Full));
}
Ejemplo n.º 5
0
QNetworkCookie CookieDialog::cookie()
{
    QNetworkCookie cookie;
    cookie.setDomain(m_domainLineEdit->text());
    cookie.setName(m_nameLineEdit->text().toLatin1());
    cookie.setValue(m_valueLineEdit->text().toLatin1());
    cookie.setExpirationDate(QDateTime(m_dateEdit->date()));
    cookie.setPath(m_pathLineEdit->text());
    cookie.setSecure(m_isSecureComboBox->currentText() == tr("yes"));
    cookie.setHttpOnly(m_isHttpOnlyComboBox->currentText() == tr("yes"));
    return cookie;
}
Ejemplo n.º 6
0
void CookieJar::setCookies(const QVariantList &cookies)
{
    QList<QNetworkCookie> newCookies;
    for (int i = 0; i < cookies.size(); ++i) {
        QNetworkCookie nc;
        QVariantMap cookie = cookies.at(i).toMap();

        //
        // The field of domain and cookie name/value MUST be set, otherwise skip it.
        //
        if (cookie["domain"].isNull() || cookie["domain"].toString().isEmpty()
                || cookie["name"].isNull() || cookie["name"].toString().isEmpty()
                || cookie["value"].isNull()
           ) {
            continue;
        } else {
            nc.setDomain(cookie["domain"].toString());
            nc.setName(cookie["name"].toByteArray());
            nc.setValue(cookie["value"].toByteArray());
        }

        if (cookie["path"].isNull() || cookie["path"].toString().isEmpty()) {
            nc.setPath("/");
        } else {
            nc.setPath(cookie["path"].toString());
        }

        if (cookie["httponly"].isNull()) {
            nc.setHttpOnly(false);
        } else {
            nc.setHttpOnly(cookie["httponly"].toBool());
        }

        if (cookie["secure"].isNull()) {
            nc.setSecure(false);
        } else {
            nc.setSecure(cookie["secure"].toBool());
        }

        if (!cookie["expires"].isNull()) {
            QString datetime = cookie["expires"].toString().replace(" GMT", "");
            QDateTime expires = QDateTime::fromString(datetime, "ddd, dd MMM yyyy hh:mm:ss");
            if (expires.isValid()) {
                nc.setExpirationDate(expires);
            }
        }

        newCookies.append(nc);
    }

    this->setAllCookies(newCookies);
}
Ejemplo n.º 7
0
void OnetAvatar::getCookies()
{
    /* TODO: replace with central cookies storage */

    QList<QNetworkCookie> cookies;
    QNetworkCookie cookie;

    QStringList constCookies;
    constCookies << "onet_ubi" << "onet_cid" << "onet_sid" << "onet_uid" << "onetzuo_ticket" << "onet_uoi" << "onet_sgn";
    foreach (const QString &constCookie, constCookies)
    {
        cookie.setName(constCookie.toLatin1());
        cookie.setValue(Settings::instance()->get(constCookie).toLatin1());
        cookies.append(cookie);
    }
Ejemplo n.º 8
0
void CookieJar::read()
{
    qDebug() << Q_FUNC_INFO;
    qDebug() << COOKIE_PATH;
    QFile f(COOKIE);

    if(!f.exists())
    {
        return;
    }

    if (!f.open(QIODevice::ReadOnly | QIODevice::Text))
    {
        return;
    }

    QList<QNetworkCookie> list;

    while(!f.atEnd())
    {
        QList<QByteArray> spl = f.readLine().split(';');
        QList<QByteArray> cookie = spl[0].split('=');

        if(cookie.length() < 2 || cookie[0].isEmpty() || cookie[1].isEmpty())
        {
            continue;
        }

        QMap<QByteArray, QByteArray> add;
        for(int cnt = 1; spl.length() > cnt; cnt++)
        {
            QList<QByteArray> t = spl[cnt].split('=');
            if(t.count() > 1)
            {
                add[t[0].trimmed()] = t[1].trimmed();
            }
        }

        QNetworkCookie c;
        c.setName(cookie[0]);
        c.setValue(cookie[1]);
        c.setPath(add["path"]);
        c.setDomain(add["domain"]);
        c.setExpirationDate(QDateTime::fromString(add["expires"]));
        list.append(c);
    }
    setAllCookies(list);
}
Ejemplo n.º 9
0
QVariant NicoLiveManager::makePostData(QString session_id)
{
    QVariant postData;

    // make cookies
    QList <QNetworkCookie> cookies;
    QNetworkCookie ck;
    ck.toRawForm(QNetworkCookie::NameAndValueOnly);
    ck.setName("user_session");

    QByteArray user_id_ba;
    user_id_ba.append(session_id);

    ck.setValue(user_id_ba);
    cookies.append(ck);

    postData.setValue(cookies);
    return postData;
}
Ejemplo n.º 10
0
PostMonster::HttpResponse Common::deserializeResponse(const QJsonObject &jsonResponse)
{
    PostMonster::HttpResponse response;

    response.mimeType = jsonResponse["mimeType"].toString().toLatin1();
    response.status = jsonResponse["status"].toInt();

    QByteArray body;
    body.append(jsonResponse["body"].toString());
    response.body.append(QByteArray::fromBase64(body));

    foreach (const QJsonValue &jsonHeader, jsonResponse["headers"].toArray()) {
        QNetworkReply::RawHeaderPair header;
        header.first.append(jsonHeader.toObject()["name"].toString());
        header.second.append(jsonHeader.toObject()["value"].toString());

        response.headers << header;
    }

    foreach (const QJsonValue &value, jsonResponse["cookies"].toArray()) {
        const QJsonObject &jsonCookie = value.toObject();
        QNetworkCookie cookie;

        if (jsonCookie.contains("expire"))
            cookie.setExpirationDate(QDateTime::fromString(jsonCookie["expire"].toString(),
                                                           Qt::ISODate));
        if (jsonCookie["httpOnly"].toBool())
            cookie.setHttpOnly(true);
        if (jsonCookie["secure"].toBool())
            cookie.setSecure(true);
        if (jsonCookie.contains("path"))
            cookie.setPath(jsonCookie["path"].toString());

        cookie.setName(jsonCookie["name"].toString().toLatin1());
        cookie.setValue(jsonCookie["value"].toString().toLatin1());

        response.cookies << cookie;
    }

    return response;
}
Ejemplo n.º 11
0
PostMonster::HttpRequest Common::deserializeRequest(const QJsonObject &jsonRequest)
{
    PostMonster::HttpRequest request;

    request.url = jsonRequest["url"].toString();
    request.method = jsonRequest["method"].toString().toLatin1();
    request.encoding = jsonRequest["encoding"].toString().toLatin1();
    request.body = QByteArray::fromBase64(jsonRequest["body"].toString().toLatin1());

    foreach (const QJsonValue &value, jsonRequest["headers"].toArray()) {
        const QJsonObject &jsonHeader = value.toObject();
        QNetworkReply::RawHeaderPair header;

        header.first = jsonHeader["name"].toString().toLatin1();
        header.second = jsonHeader["value"].toString().toLatin1();

        request.headers << header;
    }

    foreach (const QJsonValue &value, jsonRequest["cookies"].toArray()) {
        const QJsonObject &jsonCookie = value.toObject();
        QNetworkCookie cookie;

        if (jsonCookie.contains("expire"))
            cookie.setExpirationDate(QDateTime::fromString(jsonCookie["expire"].toString(),
                                                           Qt::ISODate));
        if (jsonCookie["httpOnly"].toBool())
            cookie.setHttpOnly(true);
        if (jsonCookie["secure"].toBool())
            cookie.setSecure(true);
        if (jsonCookie.contains("path"))
            cookie.setPath(jsonCookie["path"].toString());

        cookie.setName(jsonCookie["name"].toString().toLatin1());
        cookie.setValue(jsonCookie["value"].toString().toLatin1());

        request.cookies << cookie;
    }

    return request;
}
Ejemplo n.º 12
0
bool CookieJar::setCookie(const QString& cookieName, const QString& value, int maxAge, const QString& path, const QString& domain, bool isSecure)
{
	QNetworkCookie cookie;
	QUrl url = QString(isSecure ? "https://" : "http://" + QString(domain.startsWith('.') ? "www" : "") + domain + (path.isEmpty() ? "/" : path));
#ifdef U_CJ_DEBUG
	qDebug() << Q_FUNC_INFO << allCookies().count() << url;
#endif
	cookie.setName(cookieName.toUtf8());
	cookie.setValue(value.toUtf8());
	cookie.setDomain(domain);
	cookie.setPath(path);
	cookie.setSecure(isSecure);

	if(maxAge != 0) {
		QDateTime expireDate = QDateTime::currentDateTimeUtc().addSecs(maxAge);
		cookie.setExpirationDate(expireDate);
	}
#ifdef U_CJ_DEBUG
	qDebug() << Q_FUNC_INFO << cookie;
#endif
	return setCookiesFromUrl(QList<QNetworkCookie>() << cookie, url);
}
Ejemplo n.º 13
0
QList<QNetworkCookie> QNetworkCookiePrivate::parseSetCookieHeaderLine(const QByteArray &cookieString)
{
    // According to http://wp.netscape.com/newsref/std/cookie_spec.html,<
    // the Set-Cookie response header is of the format:
    //
    //   Set-Cookie: NAME=VALUE; expires=DATE; path=PATH; domain=DOMAIN_NAME; secure
    //
    // where only the NAME=VALUE part is mandatory
    //
    // We do not support RFC 2965 Set-Cookie2-style cookies

    QList<QNetworkCookie> result;
    QDateTime now = QDateTime::currentDateTime().toUTC();

    int position = 0;
    const int length = cookieString.length();
    while (position < length) {
        QNetworkCookie cookie;

        // The first part is always the "NAME=VALUE" part
        QPair<QByteArray,QByteArray> field = nextField(cookieString, position, true);
        if (field.first.isEmpty() || field.second.isNull())
            // parsing error
            break;
        cookie.setName(field.first);
        cookie.setValue(field.second);

        position = nextNonWhitespace(cookieString, position);
        bool endOfCookie = false;
        while (!endOfCookie && position < length) {
            switch (cookieString.at(position++)) {
            case ',':
                // end of the cookie
                endOfCookie = true;
                break;

            case ';':
                // new field in the cookie
                field = nextField(cookieString, position, false);
                field.first = field.first.toLower(); // everything but the NAME=VALUE is case-insensitive

                if (field.first == "expires") {
                    position -= field.second.length();
                    int end;
                    for (end = position; end < length; ++end)
                        if (isValueSeparator(cookieString.at(end)))
                            break;

                    QByteArray dateString = cookieString.mid(position, end - position).trimmed();
                    position = end;
                    QDateTime dt = parseDateString(dateString.toLower());
                    if (!dt.isValid()) {
                        return result;
                    }
                    cookie.setExpirationDate(dt);
                } else if (field.first == "domain") {
                    QByteArray rawDomain = field.second;
                    QString maybeLeadingDot;
                    if (rawDomain.startsWith('.')) {
                        maybeLeadingDot = QLatin1Char('.');
                        rawDomain = rawDomain.mid(1);
                    }

                    QString normalizedDomain = QUrl::fromAce(QUrl::toAce(QString::fromUtf8(rawDomain)));
                    if (normalizedDomain.isEmpty() && !rawDomain.isEmpty())
                        return result;
                    cookie.setDomain(maybeLeadingDot + normalizedDomain);
                } else if (field.first == "max-age") {
                    bool ok = false;
                    int secs = field.second.toInt(&ok);
                    if (!ok)
                        return result;
                    cookie.setExpirationDate(now.addSecs(secs));
                } else if (field.first == "path") {
                    QString path = QUrl::fromPercentEncoding(field.second);
                    cookie.setPath(path);
                } else if (field.first == "secure") {
                    cookie.setSecure(true);
                } else if (field.first == "httponly") {
                    cookie.setHttpOnly(true);
                } else if (field.first == "comment") {
                    //cookie.setComment(QString::fromUtf8(field.second));
                } else if (field.first == "version") {
                    if (field.second != "1") {
                        // oops, we don't know how to handle this cookie
                        return result;
                    }
                } else {
                    // got an unknown field in the cookie
                    // what do we do?
                }

                position = nextNonWhitespace(cookieString, position);
            }
        }

        if (!cookie.name().isEmpty())
            result += cookie;
    }

    return result;
}
Ejemplo n.º 14
0
void SourcesSettingsWindow::save()
{
	m_site->setSetting("name", ui->lineSiteName->text(), m_site->url());
	QStringList referers = QStringList() << "none" << "host" << "page" << "image";
	QStringList referers_preview = QStringList() << "" << "none" << "host" << "page" << "image";
	QStringList referers_image = QStringList() << "" << "none" << "host" << "page" << "details" << "image";
	m_site->setSetting("referer", referers[ui->comboReferer->currentIndex()], "none");
	m_site->setSetting("referer_preview", referers_preview[ui->comboRefererPreview->currentIndex()], "");
	m_site->setSetting("referer_image", referers_image[ui->comboRefererImage->currentIndex()], "");
	m_site->setSetting("ignore/always", ui->spinIgnoreAlways->value(), 0);
	m_site->setSetting("ignore/1", ui->spinIgnore1->value(), 0);
	m_site->setSetting("ssl", ui->checkSsl->isChecked(), false);

	m_site->setSetting("download/imagesperpage", ui->spinImagesPerPage->value(), 200);
	m_site->setSetting("download/simultaneous", ui->spinSimultaneousDownloads->value(), 10);
	m_site->setSetting("download/throttle_details", ui->spinThrottleDetails->value(), 0);
	m_site->setSetting("download/throttle_image", ui->spinThrottleImage->value(), 0);
	m_site->setSetting("download/throttle_page", ui->spinThrottlePage->value(), 0);
	m_site->setSetting("download/throttle_retry", ui->spinThrottleRetry->value(), 0);
	m_site->setSetting("download/throttle_thumbnail", ui->spinThrottleThumbnail->value(), 0);

	QStringList sources = QStringList() << "" << "xml" << "json" << "regex" << "rss";
	m_site->setSetting("sources/usedefault", ui->checkSourcesDefault->isChecked(), true);
	m_site->setSetting("sources/source_1", sources[qMax(0, ui->comboSources1->currentIndex())], m_globalSettings->value("source_1", sources[0]).toString());
	m_site->setSetting("sources/source_2", sources[qMax(0, ui->comboSources2->currentIndex())], m_globalSettings->value("source_2", sources[1]).toString());
	m_site->setSetting("sources/source_3", sources[qMax(0, ui->comboSources3->currentIndex())], m_globalSettings->value("source_3", sources[2]).toString());
	m_site->setSetting("sources/source_4", sources[qMax(0, ui->comboSources4->currentIndex())], m_globalSettings->value("source_4", sources[3]).toString());


	m_site->setSetting("auth/pseudo", ui->lineAuthPseudo->text(), "");
	m_site->setSetting("auth/password", ui->lineAuthPassword->text(), "");

	// Login
	QStringList types = QStringList() << "url" << "get" << "post" << "oauth1" << "oauth2";
	m_site->setSetting("login/type", types[ui->comboLoginType->currentIndex()], "url");
	m_site->setSetting("login/get/url", ui->lineLoginGetUrl->text(), "");
	m_site->setSetting("login/get/pseudo", ui->lineLoginGetPseudo->text(), "");
	m_site->setSetting("login/get/password", ui->lineLoginGetPassword->text(), "");
	m_site->setSetting("login/get/cookie", ui->lineLoginGetCookie->text(), "");
	m_site->setSetting("login/post/url", ui->lineLoginPostUrl->text(), "");
	m_site->setSetting("login/post/pseudo", ui->lineLoginPostPseudo->text(), "");
	m_site->setSetting("login/post/password", ui->lineLoginPostPassword->text(), "");
	m_site->setSetting("login/post/cookie", ui->lineLoginPostCookie->text(), "");
	m_site->setSetting("login/oauth1/requestTokenUrl", ui->lineLoginOAuth1RequestTokenUrl->text(), "");
	m_site->setSetting("login/oauth1/authorizeUrl", ui->lineLoginOAuth1AuthorizeUrl->text(), "");
	m_site->setSetting("login/oauth1/accessTokenUrl", ui->lineLoginOAuth1AccessTokenUrl->text(), "");
	m_site->setSetting("login/oauth2/requestUrl", ui->lineLoginOAuth2RequestUrl->text(), "");
	m_site->setSetting("login/oauth2/tokenUrl", ui->lineLoginOAuth2TokenUrl->text(), "");
	m_site->setSetting("login/oauth2/refreshTokenUrl", ui->lineLoginOAuth2RefreshTokenUrl->text(), "");
	m_site->setSetting("login/oauth2/scope", ui->lineLoginOAuth2Scope->text(), "");
	m_site->setSetting("login/maxPage", ui->spinLoginMaxPage->value(), 0);

	// Cookies
	QList<QVariant> cookies;
	for (int i = 0; i < ui->tableCookies->rowCount(); ++i)
	{
		if (ui->tableCookies->item(i, 0)->text().isEmpty())
			continue;

		QNetworkCookie cookie;
		cookie.setName(ui->tableCookies->item(i, 0)->text().toLatin1());
		cookie.setValue(ui->tableCookies->item(i, 1)->text().toLatin1());
		cookies.append(cookie.toRawForm());
	}
	m_site->setSetting("cookies", cookies, QList<QVariant>());

	// Headers
	QMap<QString, QVariant> headers;
	for (int i = 0; i < ui->tableHeaders->rowCount(); ++i)
	{
		if (ui->tableHeaders->item(i, 0)->text().isEmpty())
			continue;

		headers.insert(ui->tableHeaders->item(i, 0)->text(), ui->tableHeaders->item(i, 1)->text());
	}
	m_site->setSetting("headers", headers, QMap<QString, QVariant>());

	m_site->syncSettings();

	m_site->loadConfig();
}
Ejemplo n.º 15
0
QList<QNetworkCookie> QNetworkCookiePrivate::parseSetCookieHeaderLine(const QByteArray &cookieString)
{
    // According to http://wp.netscape.com/newsref/std/cookie_spec.html,<
    // the Set-Cookie response header is of the format:
    //
    //   Set-Cookie: NAME=VALUE; expires=DATE; path=PATH; domain=DOMAIN_NAME; secure
    //
    // where only the NAME=VALUE part is mandatory
    //
    // We do not support RFC 2965 Set-Cookie2-style cookies

    QList<QNetworkCookie> result;
    const QDateTime now = QDateTime::currentDateTimeUtc();

    int position = 0;
    const int length = cookieString.length();
    while (position < length) {
        QNetworkCookie cookie;

        // The first part is always the "NAME=VALUE" part
        QPair<QByteArray,QByteArray> field = nextField(cookieString, position, true);
        if (field.first.isEmpty())
            // parsing error
            break;
        cookie.setName(field.first);
        cookie.setValue(field.second);

        position = nextNonWhitespace(cookieString, position);
        while (position < length) {
            switch (cookieString.at(position++)) {
            case ';':
                // new field in the cookie
                field = nextField(cookieString, position, false);
                field.first = field.first.toLower(); // everything but the NAME=VALUE is case-insensitive

                if (field.first == "expires") {
                    position -= field.second.length();
                    int end;
                    for (end = position; end < length; ++end)
                        if (isValueSeparator(cookieString.at(end)))
                            break;

                    QByteArray dateString = cookieString.mid(position, end - position).trimmed();
                    position = end;
                    QDateTime dt = parseDateString(dateString.toLower());
                    if (dt.isValid())
                        cookie.setExpirationDate(dt);
                    //if unparsed, ignore the attribute but not the whole cookie (RFC6265 section 5.2.1)
                } else if (field.first == "domain") {
                    QByteArray rawDomain = field.second;
                    //empty domain should be ignored (RFC6265 section 5.2.3)
                    if (!rawDomain.isEmpty()) {
                        QString maybeLeadingDot;
                        if (rawDomain.startsWith('.')) {
                            maybeLeadingDot = QLatin1Char('.');
                            rawDomain = rawDomain.mid(1);
                        }

                        //IDN domains are required by RFC6265, accepting utf8 as well doesn't break any test cases.
                        QString normalizedDomain = QUrl::fromAce(QUrl::toAce(QString::fromUtf8(rawDomain)));
                        if (!normalizedDomain.isEmpty()) {
                            cookie.setDomain(maybeLeadingDot + normalizedDomain);
                        } else {
                            //Normalization fails for malformed domains, e.g. "..example.org", reject the cookie now
                            //rather than accepting it but never sending it due to domain match failure, as the
                            //strict reading of RFC6265 would indicate.
                            return result;
                        }
                    }
                } else if (field.first == "max-age") {
                    bool ok = false;
                    int secs = field.second.toInt(&ok);
                    if (ok) {
                        if (secs <= 0) {
                            //earliest representable time (RFC6265 section 5.2.2)
                            cookie.setExpirationDate(QDateTime::fromSecsSinceEpoch(0));
                        } else {
                            cookie.setExpirationDate(now.addSecs(secs));
                        }
                    }
                    //if unparsed, ignore the attribute but not the whole cookie (RFC6265 section 5.2.2)
                } else if (field.first == "path") {
                    if (field.second.startsWith('/')) {
                        // ### we should treat cookie paths as an octet sequence internally
                        // However RFC6265 says we should assume UTF-8 for presentation as a string
                        cookie.setPath(QString::fromUtf8(field.second));
                    } else {
                        // if the path doesn't start with '/' then set the default path (RFC6265 section 5.2.4)
                        // and also IETF test case path0030 which has valid and empty path in the same cookie
                        cookie.setPath(QString());
                    }
                } else if (field.first == "secure") {
                    cookie.setSecure(true);
                } else if (field.first == "httponly") {
                    cookie.setHttpOnly(true);
                } else {
                    // ignore unknown fields in the cookie (RFC6265 section 5.2, rule 6)
                }

                position = nextNonWhitespace(cookieString, position);
            }
        }

        if (!cookie.name().isEmpty())
            result += cookie;
    }

    return result;
}