Add SameSite API to QNetworkCookie
Change-Id: I3f8b25418154f74bb55fa978b03465f75771d015 Reviewed-by: Mårten Nordheim <marten.nordheim@qt.io>
This commit is contained in:
parent
c0a17ecfaf
commit
37bd7b5733
@ -222,6 +222,29 @@ void QNetworkCookie::setSecure(bool enable)
|
|||||||
d->secure = enable;
|
d->secure = enable;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Returns the "SameSite" option if specified in the cookie
|
||||||
|
string, \c SameSite::Default if not present.
|
||||||
|
|
||||||
|
\since 6.1
|
||||||
|
\sa setSameSite()
|
||||||
|
*/
|
||||||
|
QNetworkCookie::SameSite QNetworkCookie::sameSite() const
|
||||||
|
{
|
||||||
|
return d->sameSite;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Sets the "SameSite" option of this cookie to \a sameSite.
|
||||||
|
|
||||||
|
\since 6.1
|
||||||
|
\sa sameSite()
|
||||||
|
*/
|
||||||
|
void QNetworkCookie::setSameSite(QNetworkCookie::SameSite sameSite)
|
||||||
|
{
|
||||||
|
d->sameSite = sameSite;
|
||||||
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
\since 4.5
|
\since 4.5
|
||||||
|
|
||||||
@ -435,6 +458,49 @@ static QPair<QByteArray, QByteArray> nextField(const QByteArray &text, int &posi
|
|||||||
\sa toRawForm(), parseCookies()
|
\sa toRawForm(), parseCookies()
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\enum QNetworkCookie::SameSite
|
||||||
|
\since 6.1
|
||||||
|
|
||||||
|
\value Default SameSite is not set. Can be interpreted as None or Lax by the browser.
|
||||||
|
\value None Cookies can be sent in all contexts. This used to be default, but
|
||||||
|
recent browsers made Lax default, and will now require the cookie to be both secure and to set SameSite=None.
|
||||||
|
\value Lax Cookies are sent on first party requests and GET requests initiated by third party website.
|
||||||
|
This is the default in modern browsers (since mid 2020).
|
||||||
|
\value Strict Cookies will only be sent in a first-party context.
|
||||||
|
|
||||||
|
\sa setSameSite(), sameSite()
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
QByteArray sameSiteToRawString(QNetworkCookie::SameSite samesite)
|
||||||
|
{
|
||||||
|
switch (samesite) {
|
||||||
|
case QNetworkCookie::SameSite::None:
|
||||||
|
return QByteArrayLiteral("None");
|
||||||
|
case QNetworkCookie::SameSite::Lax:
|
||||||
|
return QByteArrayLiteral("Lax");
|
||||||
|
case QNetworkCookie::SameSite::Strict:
|
||||||
|
return QByteArrayLiteral("Strict");
|
||||||
|
case QNetworkCookie::SameSite::Default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return QByteArray();
|
||||||
|
}
|
||||||
|
|
||||||
|
QNetworkCookie::SameSite sameSiteFromRawString(QByteArray str)
|
||||||
|
{
|
||||||
|
str = str.toLower();
|
||||||
|
if (str == QByteArrayLiteral("none"))
|
||||||
|
return QNetworkCookie::SameSite::None;
|
||||||
|
if (str == QByteArrayLiteral("lax"))
|
||||||
|
return QNetworkCookie::SameSite::Lax;
|
||||||
|
if (str == QByteArrayLiteral("strict"))
|
||||||
|
return QNetworkCookie::SameSite::Strict;
|
||||||
|
return QNetworkCookie::SameSite::Default;
|
||||||
|
}
|
||||||
|
} // namespace
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
Returns the raw form of this QNetworkCookie. The QByteArray
|
Returns the raw form of this QNetworkCookie. The QByteArray
|
||||||
returned by this function is suitable for an HTTP header, either
|
returned by this function is suitable for an HTTP header, either
|
||||||
@ -460,9 +526,9 @@ QByteArray QNetworkCookie::toRawForm(RawForm form) const
|
|||||||
result += "; secure";
|
result += "; secure";
|
||||||
if (isHttpOnly())
|
if (isHttpOnly())
|
||||||
result += "; HttpOnly";
|
result += "; HttpOnly";
|
||||||
if (!d->sameSite.isEmpty()) {
|
if (d->sameSite != SameSite::Default) {
|
||||||
result += "; SameSite=";
|
result += "; SameSite=";
|
||||||
result += d->sameSite;
|
result += sameSiteToRawString(d->sameSite);
|
||||||
}
|
}
|
||||||
if (!isSessionCookie()) {
|
if (!isSessionCookie()) {
|
||||||
result += "; expires=";
|
result += "; expires=";
|
||||||
@ -999,7 +1065,7 @@ QList<QNetworkCookie> QNetworkCookiePrivate::parseSetCookieHeaderLine(const QByt
|
|||||||
} else if (field.first == "httponly") {
|
} else if (field.first == "httponly") {
|
||||||
cookie.setHttpOnly(true);
|
cookie.setHttpOnly(true);
|
||||||
} else if (field.first == "samesite") {
|
} else if (field.first == "samesite") {
|
||||||
cookie.d->sameSite = field.second;
|
cookie.setSameSite(sameSiteFromRawString(field.second));
|
||||||
} else {
|
} else {
|
||||||
// ignore unknown fields in the cookie (RFC6265 section 5.2, rule 6)
|
// ignore unknown fields in the cookie (RFC6265 section 5.2, rule 6)
|
||||||
}
|
}
|
||||||
|
@ -57,11 +57,19 @@ class QUrl;
|
|||||||
class QNetworkCookiePrivate;
|
class QNetworkCookiePrivate;
|
||||||
class Q_NETWORK_EXPORT QNetworkCookie
|
class Q_NETWORK_EXPORT QNetworkCookie
|
||||||
{
|
{
|
||||||
|
Q_GADGET
|
||||||
public:
|
public:
|
||||||
enum RawForm {
|
enum RawForm {
|
||||||
NameAndValueOnly,
|
NameAndValueOnly,
|
||||||
Full
|
Full
|
||||||
};
|
};
|
||||||
|
enum class SameSite {
|
||||||
|
Default,
|
||||||
|
None,
|
||||||
|
Lax,
|
||||||
|
Strict
|
||||||
|
};
|
||||||
|
Q_ENUM(SameSite)
|
||||||
|
|
||||||
explicit QNetworkCookie(const QByteArray &name = QByteArray(), const QByteArray &value = QByteArray());
|
explicit QNetworkCookie(const QByteArray &name = QByteArray(), const QByteArray &value = QByteArray());
|
||||||
QNetworkCookie(const QNetworkCookie &other);
|
QNetworkCookie(const QNetworkCookie &other);
|
||||||
@ -79,6 +87,8 @@ public:
|
|||||||
void setSecure(bool enable);
|
void setSecure(bool enable);
|
||||||
bool isHttpOnly() const;
|
bool isHttpOnly() const;
|
||||||
void setHttpOnly(bool enable);
|
void setHttpOnly(bool enable);
|
||||||
|
SameSite sameSite() const;
|
||||||
|
void setSameSite(SameSite sameSite);
|
||||||
|
|
||||||
bool isSessionCookie() const;
|
bool isSessionCookie() const;
|
||||||
QDateTime expirationDate() const;
|
QDateTime expirationDate() const;
|
||||||
|
@ -53,24 +53,25 @@
|
|||||||
|
|
||||||
#include <QtNetwork/private/qtnetworkglobal_p.h>
|
#include <QtNetwork/private/qtnetworkglobal_p.h>
|
||||||
#include "QtCore/qdatetime.h"
|
#include "QtCore/qdatetime.h"
|
||||||
|
#include "QtNetwork/qnetworkcookie.h"
|
||||||
|
|
||||||
QT_BEGIN_NAMESPACE
|
QT_BEGIN_NAMESPACE
|
||||||
|
|
||||||
class QNetworkCookiePrivate: public QSharedData
|
class QNetworkCookiePrivate: public QSharedData
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
inline QNetworkCookiePrivate() : secure(false), httpOnly(false) { }
|
QNetworkCookiePrivate() = default;
|
||||||
static QList<QNetworkCookie> parseSetCookieHeaderLine(const QByteArray &cookieString);
|
static QList<QNetworkCookie> parseSetCookieHeaderLine(const QByteArray &cookieString);
|
||||||
|
|
||||||
QDateTime expirationDate;
|
QDateTime expirationDate;
|
||||||
QString domain;
|
QString domain;
|
||||||
QString path;
|
QString path;
|
||||||
QString comment;
|
QString comment;
|
||||||
QByteArray sameSite;
|
|
||||||
QByteArray name;
|
QByteArray name;
|
||||||
QByteArray value;
|
QByteArray value;
|
||||||
bool secure;
|
QNetworkCookie::SameSite sameSite = QNetworkCookie::SameSite::Default;
|
||||||
bool httpOnly;
|
bool secure = false;
|
||||||
|
bool httpOnly = false;
|
||||||
};
|
};
|
||||||
|
|
||||||
static inline bool isLWS(char c)
|
static inline bool isLWS(char c)
|
||||||
|
@ -44,6 +44,8 @@ private slots:
|
|||||||
|
|
||||||
void parseMultipleCookies_data();
|
void parseMultipleCookies_data();
|
||||||
void parseMultipleCookies();
|
void parseMultipleCookies();
|
||||||
|
|
||||||
|
void sameSite();
|
||||||
};
|
};
|
||||||
|
|
||||||
void tst_QNetworkCookie::getterSetter()
|
void tst_QNetworkCookie::getterSetter()
|
||||||
@ -683,5 +685,16 @@ void tst_QNetworkCookie::parseMultipleCookies()
|
|||||||
QCOMPARE(result, expectedCookies);
|
QCOMPARE(result, expectedCookies);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void tst_QNetworkCookie::sameSite()
|
||||||
|
{
|
||||||
|
QList<QNetworkCookie> result = QNetworkCookie::parseCookies(QByteArrayLiteral("a=b;domain=qt-project.org"));
|
||||||
|
QCOMPARE(result.first().sameSite(), QNetworkCookie::SameSite::Default);
|
||||||
|
result = QNetworkCookie::parseCookies(QByteArrayLiteral("a=b;domain=qt-project.org;samesite=strict"));
|
||||||
|
QCOMPARE(result.first().sameSite(), QNetworkCookie::SameSite::Strict);
|
||||||
|
result = QNetworkCookie::parseCookies(QByteArrayLiteral("a=b;domain=qt-project.org;samesite=none;secure"));
|
||||||
|
QCOMPARE(result.first().sameSite(), QNetworkCookie::SameSite::None);
|
||||||
|
QCOMPARE(result.first().toRawForm(), QByteArrayLiteral("a=b; secure; SameSite=None; domain=qt-project.org"));
|
||||||
|
|
||||||
|
}
|
||||||
QTEST_MAIN(tst_QNetworkCookie)
|
QTEST_MAIN(tst_QNetworkCookie)
|
||||||
#include "tst_qnetworkcookie.moc"
|
#include "tst_qnetworkcookie.moc"
|
||||||
|
Loading…
x
Reference in New Issue
Block a user