Adds support for headers in QNetworkProxy.

The API is the same that is present on QNetworkRequest class. Since
these are HTTP headers, this only affects proxies of type HttpProxy and
HttpCachingProxy.

This was created as a general solution to the problem pointed out in
QTBUG-19569(some proxies only accept request with specific User Agents).
In the same way that there are cases where setting the User Agent is
desired there might be reasons to set other headers, hence the support
for any header.

Change-Id: Ifd04f34d29eedb6c2a3f0b50708244996b12a123
Task: QTBUG-19569
Reviewed-by: Shane Kearns <shane.kearns@accenture.com>
This commit is contained in:
Jonas M. Gastal 2011-11-23 15:11:03 -02:00 committed by Qt by Nokia
parent 8f1868e7c3
commit 4cffc72023
3 changed files with 137 additions and 9 deletions

View File

@ -221,6 +221,7 @@
#ifndef QT_NO_NETWORKPROXY
#include "private/qnetworkproxy_p.h"
#include "private/qnetworkrequest_p.h"
#include "private/qsocks5socketengine_p.h"
#include "private/qhttpsocketengine_p.h"
#include "qauthenticator.h"
@ -385,6 +386,7 @@ public:
quint16 port;
QNetworkProxy::ProxyType type;
bool capabilitiesSet;
QNetworkHeadersPrivate headers;
inline QNetworkProxyPrivate(QNetworkProxy::ProxyType t = QNetworkProxy::DefaultProxy,
const QString &h = QString(), quint16 p = 0,
@ -703,6 +705,116 @@ QNetworkProxy QNetworkProxy::applicationProxy()
return QNetworkProxy();
}
/*!
Returns the value of the known network header \a header if it is
in use for this proxy. If it is not present, returns QVariant()
(i.e., an invalid variant).
\sa QNetworkRequest::KnownHeaders, rawHeader(), setHeader()
*/
QVariant QNetworkProxy::header(QNetworkRequest::KnownHeaders header) const
{
if (d->type != HttpProxy && d->type != HttpCachingProxy)
return QVariant();
return d->headers.cookedHeaders.value(header);
}
/*!
Sets the value of the known header \a header to be \a value,
overriding any previously set headers. This operation also sets
the equivalent raw HTTP header.
If the proxy is not of type HttpProxy or HttpCachingProxy this has no
effect.
\sa QNetworkRequest::KnownHeaders, setRawHeader(), header()
*/
void QNetworkProxy::setHeader(QNetworkRequest::KnownHeaders header, const QVariant &value)
{
if (d->type == HttpProxy || d->type == HttpCachingProxy)
d->headers.setCookedHeader(header, value);
}
/*!
Returns true if the raw header \a headerName is in use for this
proxy. Returns false if the proxy is not of type HttpProxy or
HttpCachingProxy.
\sa rawHeader(), setRawHeader()
*/
bool QNetworkProxy::hasRawHeader(const QByteArray &headerName) const
{
if (d->type != HttpProxy && d->type != HttpCachingProxy)
return false;
return d->headers.findRawHeader(headerName) != d->headers.rawHeaders.constEnd();
}
/*!
Returns the raw form of header \a headerName. If no such header is
present or the proxy is not of type HttpProxy or HttpCachingProxy,
an empty QByteArray is returned, which may be indistinguishable
from a header that is present but has no content (use hasRawHeader()
to find out if the header exists or not).
Raw headers can be set with setRawHeader() or with setHeader().
\sa header(), setRawHeader()
*/
QByteArray QNetworkProxy::rawHeader(const QByteArray &headerName) const
{
if (d->type != HttpProxy && d->type != HttpCachingProxy)
return QByteArray();
QNetworkHeadersPrivate::RawHeadersList::ConstIterator it =
d->headers.findRawHeader(headerName);
if (it != d->headers.rawHeaders.constEnd())
return it->second;
return QByteArray();
}
/*!
Returns a list of all raw headers that are set in this network
proxy. The list is in the order that the headers were set.
If the proxy is not of type HttpProxy or HttpCachingProxy an empty
QList is returned.
\sa hasRawHeader(), rawHeader()
*/
QList<QByteArray> QNetworkProxy::rawHeaderList() const
{
if (d->type != HttpProxy && d->type != HttpCachingProxy)
return QList<QByteArray>();
return d->headers.rawHeadersKeys();
}
/*!
Sets the header \a headerName to be of value \a headerValue. If \a
headerName corresponds to a known header (see
QNetworkRequest::KnownHeaders), the raw format will be parsed and
the corresponding "cooked" header will be set as well.
For example:
\snippet doc/src/snippets/code/src_network_access_qnetworkrequest.cpp 0
will also set the known header LastModifiedHeader to be the
QDateTime object of the parsed date.
Note: setting the same header twice overrides the previous
setting. To accomplish the behaviour of multiple HTTP headers of
the same name, you should concatenate the two values, separating
them with a comma (",") and set one single raw header.
If the proxy is not of type HttpProxy or HttpCachingProxy this has no
effect.
\sa QNetworkRequest::KnownHeaders, setHeader(), hasRawHeader(), rawHeader()
*/
void QNetworkProxy::setRawHeader(const QByteArray &headerName, const QByteArray &headerValue)
{
if (d->type == HttpProxy || d->type == HttpCachingProxy)
d->headers.setRawHeader(headerName, headerValue);
}
class QNetworkProxyQueryPrivate: public QSharedData
{
public:

View File

@ -43,6 +43,7 @@
#define QNETWORKPROXY_H
#include <QtNetwork/qhostaddress.h>
#include <QtNetwork/qnetworkrequest.h>
#include <QtCore/qshareddata.h>
#ifndef QT_NO_NETWORKPROXY
@ -174,6 +175,16 @@ public:
static void setApplicationProxy(const QNetworkProxy &proxy);
static QNetworkProxy applicationProxy();
// "cooked" headers
QVariant header(QNetworkRequest::KnownHeaders header) const;
void setHeader(QNetworkRequest::KnownHeaders header, const QVariant &value);
// raw headers:
bool hasRawHeader(const QByteArray &headerName) const;
QList<QByteArray> rawHeaderList() const;
QByteArray rawHeader(const QByteArray &headerName) const;
void setRawHeader(const QByteArray &headerName, const QByteArray &value);
private:
QSharedDataPointer<QNetworkProxyPrivate> d;
};

View File

@ -502,15 +502,20 @@ void QHttpSocketEngine::slotSocketConnected()
QByteArray data = method;
data += path;
data += " HTTP/1.1\r\n";
data += "Proxy-Connection: keep-alive\r\n"
"User-Agent: ";
QVariant v = property("_q_user-agent");
if (v.isValid())
data += v.toByteArray();
else
data += "Mozilla/5.0";
data += "\r\n"
"Host: " + peerAddress + "\r\n";
data += "Proxy-Connection: keep-alive\r\n";
data += "Host: " + peerAddress + "\r\n";
if (!d->proxy.hasRawHeader("User-Agent")) {
data += "User-Agent: ";
QVariant v = property("_q_user-agent");
if (v.isValid())
data += v.toByteArray();
else
data += "Mozilla/5.0";
data += "\r\n";
}
foreach (const QByteArray &header, d->proxy.rawHeaderList()) {
data += header + ": " + d->proxy.rawHeader(header) + "\r\n";
}
QAuthenticatorPrivate *priv = QAuthenticatorPrivate::getPrivate(d->authenticator);
//qDebug() << "slotSocketConnected: priv=" << priv << (priv ? (int)priv->method : -1);
if (priv && priv->method != QAuthenticatorPrivate::None) {