summaryrefslogtreecommitdiffstats
path: root/src/network/access
diff options
context:
space:
mode:
Diffstat (limited to 'src/network/access')
-rw-r--r--src/network/access/access.pri9
-rw-r--r--src/network/access/qhttpnetworkconnection.cpp45
-rw-r--r--src/network/access/qhttpnetworkconnection_p.h2
-rw-r--r--src/network/access/qhttpnetworkconnectionchannel.cpp123
-rw-r--r--src/network/access/qhttpnetworkconnectionchannel_p.h3
-rw-r--r--src/network/access/qhttpnetworkreply.cpp6
-rw-r--r--src/network/access/qhttpnetworkreply_p.h1
-rw-r--r--src/network/access/qhttpthreaddelegate.cpp518
-rw-r--r--src/network/access/qhttpthreaddelegate_p.h285
-rw-r--r--src/network/access/qnetworkaccessauthenticationmanager.cpp297
-rw-r--r--src/network/access/qnetworkaccessauthenticationmanager_p.h (renamed from src/network/access/qnetworkaccessdatabackend_p.h)55
-rw-r--r--src/network/access/qnetworkaccessbackend.cpp22
-rw-r--r--src/network/access/qnetworkaccessbackend_p.h15
-rw-r--r--src/network/access/qnetworkaccessfilebackend.cpp2
-rw-r--r--src/network/access/qnetworkaccessftpbackend.cpp4
-rw-r--r--src/network/access/qnetworkaccesshttpbackend.cpp800
-rw-r--r--src/network/access/qnetworkaccesshttpbackend_p.h43
-rw-r--r--src/network/access/qnetworkaccessmanager.cpp312
-rw-r--r--src/network/access/qnetworkaccessmanager.h4
-rw-r--r--src/network/access/qnetworkaccessmanager_p.h12
-rw-r--r--src/network/access/qnetworkcookie.cpp21
-rw-r--r--src/network/access/qnetworkcookiejar.cpp63
-rw-r--r--src/network/access/qnetworkcookiejar_p.h3
-rw-r--r--src/network/access/qnetworkcookiejartlds_p.h6481
-rw-r--r--src/network/access/qnetworkcookiejartlds_p.h.INFO17
-rw-r--r--src/network/access/qnetworkdiskcache.cpp2
-rw-r--r--src/network/access/qnetworkreplyfileimpl.cpp48
-rw-r--r--src/network/access/qnetworkreplyfileimpl_p.h6
-rw-r--r--src/network/access/qnetworkreplyimpl.cpp76
-rw-r--r--src/network/access/qnetworkreplyimpl_p.h3
-rw-r--r--src/network/access/qnetworkrequest.cpp7
-rw-r--r--src/network/access/qnetworkrequest.h4
32 files changed, 8381 insertions, 908 deletions
diff --git a/src/network/access/access.pri b/src/network/access/access.pri
index 4c21ba5..57a79b3 100644
--- a/src/network/access/access.pri
+++ b/src/network/access/access.pri
@@ -8,6 +8,7 @@ HEADERS += \
access/qhttpnetworkreply_p.h \
access/qhttpnetworkconnection_p.h \
access/qhttpnetworkconnectionchannel_p.h \
+ access/qnetworkaccessauthenticationmanager_p.h \
access/qnetworkaccessmanager.h \
access/qnetworkaccessmanager_p.h \
access/qnetworkaccesscache_p.h \
@@ -21,6 +22,7 @@ HEADERS += \
access/qnetworkcookie_p.h \
access/qnetworkcookiejar.h \
access/qnetworkcookiejar_p.h \
+ access/qnetworkcookiejartlds_p.h \
access/qnetworkrequest.h \
access/qnetworkrequest_p.h \
access/qnetworkreply.h \
@@ -31,7 +33,8 @@ HEADERS += \
access/qabstractnetworkcache_p.h \
access/qabstractnetworkcache.h \
access/qnetworkdiskcache_p.h \
- access/qnetworkdiskcache.h
+ access/qnetworkdiskcache.h \
+ access/qhttpthreaddelegate_p.h
SOURCES += \
access/qftp.cpp \
@@ -41,6 +44,7 @@ SOURCES += \
access/qhttpnetworkreply.cpp \
access/qhttpnetworkconnection.cpp \
access/qhttpnetworkconnectionchannel.cpp \
+ access/qnetworkaccessauthenticationmanager.cpp \
access/qnetworkaccessmanager.cpp \
access/qnetworkaccesscache.cpp \
access/qnetworkaccessbackend.cpp \
@@ -57,6 +61,7 @@ SOURCES += \
access/qnetworkreplydataimpl.cpp \
access/qnetworkreplyfileimpl.cpp \
access/qabstractnetworkcache.cpp \
- access/qnetworkdiskcache.cpp
+ access/qnetworkdiskcache.cpp \
+ access/qhttpthreaddelegate.cpp
include($$PWD/../../3rdparty/zlib_dependency.pri)
diff --git a/src/network/access/qhttpnetworkconnection.cpp b/src/network/access/qhttpnetworkconnection.cpp
index e94b099..29ae5b0 100644
--- a/src/network/access/qhttpnetworkconnection.cpp
+++ b/src/network/access/qhttpnetworkconnection.cpp
@@ -286,7 +286,13 @@ void QHttpNetworkConnectionPrivate::emitReplyError(QAbstractSocket *socket,
int i = indexOf(socket);
// remove the corrupt data if any
reply->d_func()->eraseData();
+
+ // Clean the channel
channels[i].close();
+ channels[i].reply = 0;
+ channels[i].request = QHttpNetworkRequest();
+ channels[i].requeueCurrentlyPipelinedRequests();
+
// send the next request
QMetaObject::invokeMethod(q, "_q_startNextRequest", Qt::QueuedConnection);
}
@@ -481,7 +487,7 @@ void QHttpNetworkConnectionPrivate::requeueRequest(const HttpMessagePair &pair)
QMetaObject::invokeMethod(q, "_q_startNextRequest", Qt::QueuedConnection);
}
-void QHttpNetworkConnectionPrivate::dequeueAndSendRequest(QAbstractSocket *socket)
+bool QHttpNetworkConnectionPrivate::dequeueRequest(QAbstractSocket *socket)
{
Q_ASSERT(socket);
@@ -494,8 +500,7 @@ void QHttpNetworkConnectionPrivate::dequeueAndSendRequest(QAbstractSocket *socke
prepareRequest(messagePair);
channels[i].request = messagePair.first;
channels[i].reply = messagePair.second;
- channels[i].sendRequest();
- return;
+ return true;
}
if (!lowPriorityQueue.isEmpty()) {
@@ -505,9 +510,9 @@ void QHttpNetworkConnectionPrivate::dequeueAndSendRequest(QAbstractSocket *socke
prepareRequest(messagePair);
channels[i].request = messagePair.first;
channels[i].reply = messagePair.second;
- channels[i].sendRequest();
- return;
+ return true;
}
+ return false;
}
// this is called from _q_startNextRequest and when a request has been sent down a socket from the channel
@@ -759,7 +764,7 @@ void QHttpNetworkConnectionPrivate::_q_startNextRequest()
//resend the necessary ones.
for (int i = 0; i < channelCount; ++i) {
- if (channels[i].resendCurrent) {
+ if (channels[i].resendCurrent && (channels[i].state != QHttpNetworkConnectionChannel::ClosingState)) {
channels[i].resendCurrent = false;
channels[i].state = QHttpNetworkConnectionChannel::IdleState;
@@ -778,17 +783,8 @@ void QHttpNetworkConnectionPrivate::_q_startNextRequest()
// try to get a free AND connected socket
for (int i = 0; i < channelCount; ++i) {
if (!channels[i].reply && !channels[i].isSocketBusy() && channels[i].socket->state() == QAbstractSocket::ConnectedState) {
- dequeueAndSendRequest(channels[i].socket);
- }
- }
-
- // return fast if there is nothing to do
- if (highPriorityQueue.isEmpty() && lowPriorityQueue.isEmpty())
- return;
- // try to get a free unconnected socket
- for (int i = 0; i < channelCount; ++i) {
- if (!channels[i].reply && !channels[i].isSocketBusy()) {
- dequeueAndSendRequest(channels[i].socket);
+ if (dequeueRequest(channels[i].socket))
+ channels[i].sendRequest();
}
}
@@ -805,6 +801,21 @@ void QHttpNetworkConnectionPrivate::_q_startNextRequest()
for (int i = 0; i < channelCount; i++)
if (channels[i].socket->state() == QAbstractSocket::ConnectedState)
fillPipeline(channels[i].socket);
+
+ // If there is not already any connected channels we need to connect a new one.
+ // We do not pair the channel with the request until we know if it is
+ // connected or not. This is to reuse connected channels before we connect new once.
+ int queuedRequest = highPriorityQueue.count() + lowPriorityQueue.count();
+ for (int i = 0; i < channelCount; ++i) {
+ if (channels[i].socket->state() == QAbstractSocket::ConnectingState)
+ queuedRequest--;
+ if ( queuedRequest <=0 )
+ break;
+ if (!channels[i].reply && !channels[i].isSocketBusy() && (channels[i].socket->state() == QAbstractSocket::UnconnectedState)) {
+ channels[i].ensureConnection();
+ queuedRequest--;
+ }
+ }
}
diff --git a/src/network/access/qhttpnetworkconnection_p.h b/src/network/access/qhttpnetworkconnection_p.h
index d4748c1..874ea22 100644
--- a/src/network/access/qhttpnetworkconnection_p.h
+++ b/src/network/access/qhttpnetworkconnection_p.h
@@ -161,7 +161,7 @@ public:
QHttpNetworkReply *queueRequest(const QHttpNetworkRequest &request);
void requeueRequest(const HttpMessagePair &pair); // e.g. after pipeline broke
- void dequeueAndSendRequest(QAbstractSocket *socket);
+ bool dequeueRequest(QAbstractSocket *socket);
void prepareRequest(HttpMessagePair &request);
void fillPipeline(QAbstractSocket *socket);
diff --git a/src/network/access/qhttpnetworkconnectionchannel.cpp b/src/network/access/qhttpnetworkconnectionchannel.cpp
index 079f608..6564b4b 100644
--- a/src/network/access/qhttpnetworkconnectionchannel.cpp
+++ b/src/network/access/qhttpnetworkconnectionchannel.cpp
@@ -91,8 +91,10 @@ void QHttpNetworkConnectionChannel::init()
#else
socket = new QTcpSocket;
#endif
+#ifndef QT_NO_NETWORKPROXY
// Set by QNAM anyway, but let's be safe here
socket->setProxy(QNetworkProxy::NoProxy);
+#endif
QObject::connect(socket, SIGNAL(bytesWritten(qint64)),
this, SLOT(_q_bytesWritten(qint64)),
@@ -145,10 +147,12 @@ void QHttpNetworkConnectionChannel::init()
void QHttpNetworkConnectionChannel::close()
{
- socket->blockSignals(true);
+ if (socket->state() == QAbstractSocket::UnconnectedState)
+ state = QHttpNetworkConnectionChannel::IdleState;
+ else
+ state = QHttpNetworkConnectionChannel::ClosingState;
+
socket->close();
- socket->blockSignals(false);
- state = QHttpNetworkConnectionChannel::IdleState;
}
@@ -253,7 +257,7 @@ bool QHttpNetworkConnectionChannel::sendRequest()
#endif
{
// get pointer to upload data
- qint64 currentReadSize;
+ qint64 currentReadSize = 0;
qint64 desiredReadSize = qMin(socketWriteMaxSize, bytesTotal - written);
const char *readPointer = uploadByteDevice->readPointer(desiredReadSize, currentReadSize);
@@ -476,7 +480,8 @@ void QHttpNetworkConnectionChannel::_q_receiveReply()
}
#ifndef QT_NO_COMPRESS
else if (!expand(false)) { // expand a chunk if possible
- return; // ### expand failed
+ // If expand() failed we can just return, it had already called connection->emitReplyError()
+ return;
}
#endif
}
@@ -499,6 +504,7 @@ void QHttpNetworkConnectionChannel::_q_receiveReply()
// called when unexpectedly reading a -1 or when data is expected but socket is closed
void QHttpNetworkConnectionChannel::handleUnexpectedEOF()
{
+ Q_ASSERT(reply);
if (reconnectAttempts <= 0) {
// too many errors reading/receiving/parsing the status, close the socket and emit error
requeueCurrentlyPipelinedRequests();
@@ -521,7 +527,8 @@ bool QHttpNetworkConnectionChannel::ensureConnection()
// resend this request after we receive the disconnected signal
if (socketState == QAbstractSocket::ClosingState) {
- resendCurrent = true;
+ if (reply)
+ resendCurrent = true;
return false;
}
@@ -581,13 +588,15 @@ bool QHttpNetworkConnectionChannel::ensureConnection()
#endif
} else {
// In case of no proxy we can use the Unbuffered QTcpSocket
+#ifndef QT_NO_NETWORKPROXY
if (connection->d_func()->networkProxy.type() == QNetworkProxy::NoProxy
&& connection->cacheProxy().type() == QNetworkProxy::NoProxy
&& connection->transparentProxy().type() == QNetworkProxy::NoProxy) {
+#endif
socket->connectToHost(connectHost, connectPort, QIODevice::ReadWrite | QIODevice::Unbuffered);
// For an Unbuffered QTcpSocket, the read buffer size has a special meaning.
socket->setReadBufferSize(1*1024);
-
+#ifndef QT_NO_NETWORKPROXY
} else {
socket->connectToHost(connectHost, connectPort);
@@ -596,6 +605,7 @@ bool QHttpNetworkConnectionChannel::ensureConnection()
// here and there.
socket->setReadBufferSize(64*1024);
}
+#endif
}
return false;
}
@@ -643,32 +653,44 @@ bool QHttpNetworkConnectionChannel::expand(bool dataComplete)
void QHttpNetworkConnectionChannel::allDone()
{
+ Q_ASSERT(reply);
#ifndef QT_NO_COMPRESS
// expand the whole data.
- if (reply->d_func()->expectContent() && reply->d_func()->autoDecompress && !reply->d_func()->streamEnd)
- expand(true); // ### if expand returns false, its an error
+ if (reply->d_func()->expectContent() && reply->d_func()->autoDecompress && !reply->d_func()->streamEnd) {
+ bool expandResult = expand(true);
+ // If expand() failed we can just return, it had already called connection->emitReplyError()
+ if (!expandResult)
+ return;
+ }
#endif
+
+ if (!reply) {
+ qWarning() << "QHttpNetworkConnectionChannel::allDone() called without reply. Please report at http://bugreports.qt.nokia.com/";
+ return;
+ }
+
// while handling 401 & 407, we might reset the status code, so save this.
bool emitFinished = reply->d_func()->shouldEmitSignals();
- handleStatus();
- // ### at this point there should be no more data on the socket
- // close if server requested
bool connectionCloseEnabled = reply->d_func()->isConnectionCloseEnabled();
- if (connectionCloseEnabled)
- close();
+ detectPipeliningSupport();
+
+ handleStatus();
+ // handleStatus() might have removed the reply because it already called connection->emitReplyError()
+
// queue the finished signal, this is required since we might send new requests from
// slot connected to it. The socket will not fire readyRead signal, if we are already
// in the slot connected to readyRead
- if (emitFinished)
+ if (reply && emitFinished)
QMetaObject::invokeMethod(reply, "finished", Qt::QueuedConnection);
+
+
// reset the reconnection attempts after we receive a complete reply.
// in case of failures, each channel will attempt two reconnects before emitting error.
reconnectAttempts = 2;
- detectPipeliningSupport();
-
// now the channel can be seen as free/idle again, all signal emissions for the reply have been done
- this->state = QHttpNetworkConnectionChannel::IdleState;
+ if (state != QHttpNetworkConnectionChannel::ClosingState)
+ state = QHttpNetworkConnectionChannel::IdleState;
// if it does not need to be sent again we can set it to 0
// the previous code did not do that and we had problems with accidental re-sending of a
@@ -717,6 +739,9 @@ void QHttpNetworkConnectionChannel::allDone()
// leading whitespace.
QMetaObject::invokeMethod(connection, "_q_startNextRequest", Qt::QueuedConnection);
} else if (alreadyPipelinedRequests.isEmpty()) {
+ if (connectionCloseEnabled)
+ if (socket->state() != QAbstractSocket::UnconnectedState)
+ close();
if (qobject_cast<QHttpNetworkConnection*>(connection))
QMetaObject::invokeMethod(connection, "_q_startNextRequest", Qt::QueuedConnection);
}
@@ -724,6 +749,7 @@ void QHttpNetworkConnectionChannel::allDone()
void QHttpNetworkConnectionChannel::detectPipeliningSupport()
{
+ Q_ASSERT(reply);
// detect HTTP Pipelining support
QByteArray serverHeaderField;
if (
@@ -807,6 +833,7 @@ void QHttpNetworkConnectionChannel::handleStatus()
bool QHttpNetworkConnectionChannel::resetUploadData()
{
+ Q_ASSERT(reply);
QNonContiguousByteDevice* uploadByteDevice = request.uploadByteDevice();
if (!uploadByteDevice)
return true;
@@ -864,7 +891,8 @@ void QHttpNetworkConnectionChannel::closeAndResendCurrentRequest()
{
requeueCurrentlyPipelinedRequests();
close();
- resendCurrent = true;
+ if (reply)
+ resendCurrent = true;
if (qobject_cast<QHttpNetworkConnection*>(connection))
QMetaObject::invokeMethod(connection, "_q_startNextRequest", Qt::QueuedConnection);
}
@@ -892,15 +920,18 @@ bool QHttpNetworkConnectionChannel::isSocketReading() const
//private slots
void QHttpNetworkConnectionChannel::_q_readyRead()
{
- // We got a readyRead but no bytes are available..
- // This happens for the Unbuffered QTcpSocket
- // Also check if socket is in ConnectedState since
- // this function may also be invoked via the event loop.
if (socket->state() == QAbstractSocket::ConnectedState && socket->bytesAvailable() == 0) {
+ // We got a readyRead but no bytes are available..
+ // This happens for the Unbuffered QTcpSocket
+ // Also check if socket is in ConnectedState since
+ // this function may also be invoked via the event loop.
char c;
qint64 ret = socket->peek(&c, 1);
if (ret < 0) {
- socket->disconnectFromHost();
+ _q_error(socket->error());
+ // We still need to handle the reply so it emits its signals etc.
+ if (reply)
+ _q_receiveReply();
return;
}
}
@@ -923,6 +954,12 @@ void QHttpNetworkConnectionChannel::_q_bytesWritten(qint64 bytes)
void QHttpNetworkConnectionChannel::_q_disconnected()
{
+ if (state == QHttpNetworkConnectionChannel::ClosingState) {
+ state = QHttpNetworkConnectionChannel::IdleState;
+ QMetaObject::invokeMethod(connection, "_q_startNextRequest", Qt::QueuedConnection);
+ return;
+ }
+
// read the available data before closing
if (isSocketWaiting() || isSocketReading()) {
if (reply) {
@@ -960,10 +997,10 @@ void QHttpNetworkConnectionChannel::_q_connected()
//channels[i].reconnectAttempts = 2;
if (!pendingEncrypt) {
state = QHttpNetworkConnectionChannel::IdleState;
+ if (!reply)
+ connection->d_func()->dequeueRequest(socket);
if (reply)
sendRequest();
- else
- close();
}
}
@@ -991,8 +1028,20 @@ void QHttpNetworkConnectionChannel::_q_error(QAbstractSocket::SocketError socket
} else {
errorCode = QNetworkReply::RemoteHostClosedError;
}
+ } else if (state == QHttpNetworkConnectionChannel::ReadingState) {
+ if (!reply->d_func()->expectContent()) {
+ // No content expected, this is a valid way to have the connection closed by the server
+ return;
+ }
+ if (reply->contentLength() == -1 && !reply->d_func()->isChunked()) {
+ // There was no content-length header and it's not chunked encoding,
+ // so this is a valid way to have the connection closed by the server
+ return;
+ }
+ // ok, we got a disconnect even though we did not expect it
+ errorCode = QNetworkReply::RemoteHostClosedError;
} else {
- return;
+ errorCode = QNetworkReply::RemoteHostClosedError;
}
break;
case QAbstractSocket::SocketTimeoutError:
@@ -1017,9 +1066,13 @@ void QHttpNetworkConnectionChannel::_q_error(QAbstractSocket::SocketError socket
QPointer<QHttpNetworkConnection> that = connection;
QString errorString = connection->d_func()->errorDetail(errorCode, socket, socket->errorString());
+ // Need to dequeu the request so that we can emit the error.
+ if (!reply)
+ connection->d_func()->dequeueRequest(socket);
if (reply) {
reply->d_func()->errorString = errorString;
emit reply->finishedWithError(errorCode, errorString);
+ reply = 0;
}
// send the next request
QMetaObject::invokeMethod(that, "_q_startNextRequest", Qt::QueuedConnection);
@@ -1031,7 +1084,11 @@ void QHttpNetworkConnectionChannel::_q_error(QAbstractSocket::SocketError socket
#ifndef QT_NO_NETWORKPROXY
void QHttpNetworkConnectionChannel::_q_proxyAuthenticationRequired(const QNetworkProxy &proxy, QAuthenticator* auth)
{
- connection->d_func()->emitProxyAuthenticationRequired(this, proxy, auth);
+ // Need to dequeue the request before we can emit the error.
+ if (!reply)
+ connection->d_func()->dequeueRequest(socket);
+ if (reply)
+ connection->d_func()->emitProxyAuthenticationRequired(this, proxy, auth);
}
#endif
@@ -1047,7 +1104,10 @@ void QHttpNetworkConnectionChannel::_q_encrypted()
return; // ### error
state = QHttpNetworkConnectionChannel::IdleState;
pendingEncrypt = false;
- sendRequest();
+ if (!reply)
+ connection->d_func()->dequeueRequest(socket);
+ if (reply)
+ sendRequest();
}
void QHttpNetworkConnectionChannel::_q_sslErrors(const QList<QSslError> &errors)
@@ -1058,7 +1118,10 @@ void QHttpNetworkConnectionChannel::_q_sslErrors(const QList<QSslError> &errors)
// Also pause the connection because socket notifiers may fire while an user
// dialog is displaying
connection->d_func()->pauseConnection();
- emit reply->sslErrors(errors);
+ if (pendingEncrypt && !reply)
+ connection->d_func()->dequeueRequest(socket);
+ if (reply)
+ emit reply->sslErrors(errors);
connection->d_func()->resumeConnection();
}
diff --git a/src/network/access/qhttpnetworkconnectionchannel_p.h b/src/network/access/qhttpnetworkconnectionchannel_p.h
index 8cbc689..893d75e 100644
--- a/src/network/access/qhttpnetworkconnectionchannel_p.h
+++ b/src/network/access/qhttpnetworkconnectionchannel_p.h
@@ -95,7 +95,8 @@ public:
WritingState = 2, // writing the data
WaitingState = 4, // waiting for reply
ReadingState = 8, // reading the reply
- BusyState = (ConnectingState|WritingState|WaitingState|ReadingState)
+ ClosingState = 16,
+ BusyState = (ConnectingState|WritingState|WaitingState|ReadingState|ClosingState)
};
QAbstractSocket *socket;
bool ssl;
diff --git a/src/network/access/qhttpnetworkreply.cpp b/src/network/access/qhttpnetworkreply.cpp
index 7f6b71f..704cf3a 100644
--- a/src/network/access/qhttpnetworkreply.cpp
+++ b/src/network/access/qhttpnetworkreply.cpp
@@ -177,6 +177,12 @@ qint64 QHttpNetworkReply::bytesAvailableNextBlock() const
return -1;
}
+bool QHttpNetworkReply::readAnyAvailable() const
+{
+ Q_D(const QHttpNetworkReply);
+ return (d->responseData.bufferCount() > 0);
+}
+
QByteArray QHttpNetworkReply::readAny()
{
Q_D(QHttpNetworkReply);
diff --git a/src/network/access/qhttpnetworkreply_p.h b/src/network/access/qhttpnetworkreply_p.h
index 1856d7a..cc0f671 100644
--- a/src/network/access/qhttpnetworkreply_p.h
+++ b/src/network/access/qhttpnetworkreply_p.h
@@ -125,6 +125,7 @@ public:
qint64 bytesAvailable() const;
qint64 bytesAvailableNextBlock() const;
+ bool readAnyAvailable() const;
QByteArray readAny();
QByteArray readAll();
void setDownstreamLimited(bool t);
diff --git a/src/network/access/qhttpthreaddelegate.cpp b/src/network/access/qhttpthreaddelegate.cpp
new file mode 100644
index 0000000..81410a4
--- /dev/null
+++ b/src/network/access/qhttpthreaddelegate.cpp
@@ -0,0 +1,518 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtNetwork module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qhttpthreaddelegate_p.h"
+
+#include <QThread>
+#include <QTimer>
+#include <QAuthenticator>
+#include <QEventLoop>
+
+#include "private/qhttpnetworkreply_p.h"
+#include "private/qnetworkaccesscache_p.h"
+#include "private/qnoncontiguousbytedevice_p.h"
+
+
+QT_BEGIN_NAMESPACE
+
+static QNetworkReply::NetworkError statusCodeFromHttp(int httpStatusCode, const QUrl &url)
+{
+ QNetworkReply::NetworkError code;
+ // we've got an error
+ switch (httpStatusCode) {
+ case 401: // Authorization required
+ code = QNetworkReply::AuthenticationRequiredError;
+ break;
+
+ case 403: // Access denied
+ code = QNetworkReply::ContentOperationNotPermittedError;
+ break;
+
+ case 404: // Not Found
+ code = QNetworkReply::ContentNotFoundError;
+ break;
+
+ case 405: // Method Not Allowed
+ code = QNetworkReply::ContentOperationNotPermittedError;
+ break;
+
+ case 407:
+ code = QNetworkReply::ProxyAuthenticationRequiredError;
+ break;
+
+ default:
+ if (httpStatusCode > 500) {
+ // some kind of server error
+ code = QNetworkReply::ProtocolUnknownError;
+ } else if (httpStatusCode >= 400) {
+ // content error we did not handle above
+ code = QNetworkReply::UnknownContentError;
+ } else {
+ qWarning("QNetworkAccess: got HTTP status code %d which is not expected from url: \"%s\"",
+ httpStatusCode, qPrintable(url.toString()));
+ code = QNetworkReply::ProtocolFailure;
+ }
+ }
+
+ return code;
+}
+
+
+static QByteArray makeCacheKey(QUrl &url, QNetworkProxy *proxy)
+{
+ QByteArray result;
+ QUrl copy = url;
+ bool isEncrypted = copy.scheme().toLower() == QLatin1String("https");
+ copy.setPort(copy.port(isEncrypted ? 443 : 80));
+ result = copy.toEncoded(QUrl::RemoveUserInfo | QUrl::RemovePath |
+ QUrl::RemoveQuery | QUrl::RemoveFragment);
+
+#ifndef QT_NO_NETWORKPROXY
+ if (proxy && proxy->type() != QNetworkProxy::NoProxy) {
+ QUrl key;
+
+ switch (proxy->type()) {
+ case QNetworkProxy::Socks5Proxy:
+ key.setScheme(QLatin1String("proxy-socks5"));
+ break;
+
+ case QNetworkProxy::HttpProxy:
+ case QNetworkProxy::HttpCachingProxy:
+ key.setScheme(QLatin1String("proxy-http"));
+ break;
+
+ default:
+ break;
+ }
+
+ if (!key.scheme().isEmpty()) {
+ key.setUserName(proxy->user());
+ key.setHost(proxy->hostName());
+ key.setPort(proxy->port());
+ key.setEncodedQuery(result);
+ result = key.toEncoded();
+ }
+ }
+#endif
+
+ return "http-connection:" + result;
+}
+
+class QNetworkAccessCachedHttpConnection: public QHttpNetworkConnection,
+ public QNetworkAccessCache::CacheableObject
+{
+ // Q_OBJECT
+public:
+ QNetworkAccessCachedHttpConnection(const QString &hostName, quint16 port, bool encrypt)
+ : QHttpNetworkConnection(hostName, port, encrypt)
+ {
+ setExpires(true);
+ setShareable(true);
+ }
+
+ virtual void dispose()
+ {
+#if 0 // sample code; do this right with the API
+ Q_ASSERT(!isWorking());
+#endif
+ delete this;
+ }
+};
+
+
+QThreadStorage<QNetworkAccessCache *> QHttpThreadDelegate::connections;
+
+
+QHttpThreadDelegate::~QHttpThreadDelegate()
+{
+ // It could be that the main thread has asked us to shut down, so we need to delete the HTTP reply
+ if (httpReply) {
+ delete httpReply;
+ }
+
+ // Get the object cache that stores our QHttpNetworkConnection objects
+ // and release the entry for this QHttpNetworkConnection
+ if (connections.hasLocalData() && !cacheKey.isEmpty()) {
+ connections.localData()->releaseEntry(cacheKey);
+ }
+}
+
+
+QHttpThreadDelegate::QHttpThreadDelegate(QObject *parent) :
+ QObject(parent)
+ , ssl(false)
+ , downloadBufferMaximumSize(0)
+ , pendingDownloadData(0)
+ , pendingDownloadProgress(0)
+ , synchronous(false)
+ , incomingStatusCode(0)
+ , isPipeliningUsed(false)
+ , incomingContentLength(-1)
+ , incomingErrorCode(QNetworkReply::NoError)
+ , downloadBuffer(0)
+ , httpConnection(0)
+ , httpReply(0)
+{
+}
+
+// This is invoked as BlockingQueuedConnection from QNetworkAccessHttpBackend in the user thread
+void QHttpThreadDelegate::startRequestSynchronously()
+{
+ synchronous = true;
+
+ QEventLoop synchronousRequestLoop;
+ this->synchronousRequestLoop = &synchronousRequestLoop;
+
+ // Worst case timeout
+ QTimer::singleShot(30*1000, this, SLOT(abortRequest()));
+
+ QMetaObject::invokeMethod(this, "startRequest", Qt::QueuedConnection);
+ synchronousRequestLoop.exec();
+
+ connections.localData()->releaseEntry(cacheKey);
+ connections.setLocalData(0);
+
+}
+
+
+// This is invoked as QueuedConnection from QNetworkAccessHttpBackend in the user thread
+void QHttpThreadDelegate::startRequest()
+{
+ // Check QThreadStorage for the QNetworkAccessCache
+ // If not there, create this connection cache
+ if (!connections.hasLocalData()) {
+ connections.setLocalData(new QNetworkAccessCache());
+ }
+
+ // check if we have an open connection to this host
+ QUrl urlCopy = httpRequest.url();
+ urlCopy.setPort(urlCopy.port(ssl ? 443 : 80));
+
+ if (transparentProxy.type() != QNetworkProxy::NoProxy)
+ cacheKey = makeCacheKey(urlCopy, &transparentProxy);
+ else if (cacheProxy.type() != QNetworkProxy::NoProxy)
+ cacheKey = makeCacheKey(urlCopy, &cacheProxy);
+ else
+ cacheKey = makeCacheKey(urlCopy, 0);
+
+
+ // the http object is actually a QHttpNetworkConnection
+ httpConnection = static_cast<QNetworkAccessCachedHttpConnection *>(connections.localData()->requestEntryNow(cacheKey));
+ if (httpConnection == 0) {
+ // no entry in cache; create an object
+ // the http object is actually a QHttpNetworkConnection
+ httpConnection = new QNetworkAccessCachedHttpConnection(urlCopy.host(), urlCopy.port(), ssl);
+#ifndef QT_NO_OPENSSL
+ // Set the QSslConfiguration from this QNetworkRequest.
+ if (ssl) {
+ httpConnection->setSslConfiguration(incomingSslConfiguration);
+ }
+#endif
+
+#ifndef QT_NO_NETWORKPROXY
+ httpConnection->setTransparentProxy(transparentProxy);
+ httpConnection->setCacheProxy(cacheProxy);
+#endif
+
+ // cache the QHttpNetworkConnection corresponding to this cache key
+ connections.localData()->addEntry(cacheKey, httpConnection);
+ }
+
+
+ // Send the request to the connection
+ httpReply = httpConnection->sendRequest(httpRequest);
+ httpReply->setParent(this);
+
+ // Connect the reply signals that we need to handle and then forward
+ if (synchronous) {
+ connect(httpReply,SIGNAL(headerChanged()), this, SLOT(synchronousHeaderChangedSlot()));
+ connect(httpReply,SIGNAL(finished()), this, SLOT(synchronousFinishedSlot()));
+ connect(httpReply,SIGNAL(finishedWithError(QNetworkReply::NetworkError, const QString)),
+ this, SLOT(synchronousFinishedWithErrorSlot(QNetworkReply::NetworkError,QString)));
+
+ connect(httpReply, SIGNAL(authenticationRequired(QHttpNetworkRequest,QAuthenticator*)),
+ this, SLOT(synchronousAuthenticationRequiredSlot(QHttpNetworkRequest,QAuthenticator*)));
+ connect(httpReply, SIGNAL(proxyAuthenticationRequired(QNetworkProxy,QAuthenticator*)),
+ this, SLOT(synchronousProxyAuthenticationRequiredSlot(QNetworkProxy,QAuthenticator*)));
+
+ // Don't care about ignored SSL errors for now in the synchronous HTTP case.
+ } else if (!synchronous) {
+ connect(httpReply,SIGNAL(headerChanged()), this, SLOT(headerChangedSlot()));
+ connect(httpReply,SIGNAL(finished()), this, SLOT(finishedSlot()));
+ connect(httpReply,SIGNAL(finishedWithError(QNetworkReply::NetworkError, const QString)),
+ this, SLOT(finishedWithErrorSlot(QNetworkReply::NetworkError,QString)));
+ // some signals are only interesting when normal asynchronous style is used
+ connect(httpReply,SIGNAL(readyRead()), this, SLOT(readyReadSlot()));
+ connect(httpReply,SIGNAL(dataReadProgress(int, int)), this, SLOT(dataReadProgressSlot(int,int)));
+ connect(httpReply, SIGNAL(cacheCredentials(QHttpNetworkRequest,QAuthenticator*)),
+ this, SLOT(cacheCredentialsSlot(QHttpNetworkRequest,QAuthenticator*)));
+#ifndef QT_NO_OPENSSL
+ connect(httpReply,SIGNAL(sslErrors(const QList<QSslError>)), this, SLOT(sslErrorsSlot(QList<QSslError>)));
+#endif
+
+ // In the asynchronous HTTP case we can just forward those signals
+ // Connect the reply signals that we can directly forward
+ connect(httpReply, SIGNAL(authenticationRequired(QHttpNetworkRequest,QAuthenticator*)),
+ this, SIGNAL(authenticationRequired(QHttpNetworkRequest,QAuthenticator*)));
+ connect(httpReply, SIGNAL(proxyAuthenticationRequired(QNetworkProxy,QAuthenticator*)),
+ this, SIGNAL(proxyAuthenticationRequired(QNetworkProxy,QAuthenticator*)));
+ }
+}
+
+// This gets called from the user thread or by the synchronous HTTP timeout timer
+void QHttpThreadDelegate::abortRequest()
+{
+ if (httpReply) {
+ delete httpReply;
+ httpReply = 0;
+ this->deleteLater();
+ }
+
+ // Got aborted by the timeout timer
+ if (synchronous)
+ incomingErrorCode = QNetworkReply::TimeoutError;
+}
+
+void QHttpThreadDelegate::readyReadSlot()
+{
+ // Don't do in zerocopy case
+ if (!downloadBuffer.isNull())
+ return;
+
+ while (httpReply->readAnyAvailable()) {
+ pendingDownloadData->fetchAndAddRelease(1);
+ emit downloadData(httpReply->readAny());
+ }
+}
+
+void QHttpThreadDelegate::finishedSlot()
+{
+ if (!httpReply) {
+ qWarning() << "QHttpThreadDelegate::finishedSlot: HTTP reply had already been deleted, internal problem. Please report.";
+ return;
+ }
+
+ // If there is still some data left emit that now
+ while (httpReply->readAnyAvailable()) {
+ pendingDownloadData->fetchAndAddRelease(1);
+ emit downloadData(httpReply->readAny());
+ }
+
+#ifndef QT_NO_OPENSSL
+ if (ssl)
+ emit sslConfigurationChanged(httpReply->sslConfiguration());
+#endif
+
+ if (httpReply->statusCode() >= 400) {
+ // it's an error reply
+ QString msg = QLatin1String(QT_TRANSLATE_NOOP("QNetworkReply",
+ "Error downloading %1 - server replied: %2"));
+ msg = msg.arg(QString::fromAscii(httpRequest.url().toEncoded()), httpReply->reasonPhrase());
+ emit error(statusCodeFromHttp(httpReply->statusCode(), httpRequest.url()), msg);
+ }
+
+ emit downloadFinished();
+
+ QMetaObject::invokeMethod(httpReply, "deleteLater", Qt::QueuedConnection);
+ QMetaObject::invokeMethod(this, "deleteLater", Qt::QueuedConnection);
+ httpReply = 0;
+}
+
+void QHttpThreadDelegate::synchronousFinishedSlot()
+{
+ if (httpReply->statusCode() >= 400) {
+ // it's an error reply
+ QString msg = QLatin1String(QT_TRANSLATE_NOOP("QNetworkReply",
+ "Error downloading %1 - server replied: %2"));
+ incomingErrorDetail = msg.arg(QString::fromAscii(httpRequest.url().toEncoded()), httpReply->reasonPhrase());
+ incomingErrorCode = statusCodeFromHttp(httpReply->statusCode(), httpRequest.url());
+ }
+
+ synchronousDownloadData = httpReply->readAll();
+
+ QMetaObject::invokeMethod(httpReply, "deleteLater", Qt::QueuedConnection);
+ QMetaObject::invokeMethod(synchronousRequestLoop, "quit", Qt::QueuedConnection);
+ httpReply = 0;
+}
+
+void QHttpThreadDelegate::finishedWithErrorSlot(QNetworkReply::NetworkError errorCode, const QString &detail)
+{
+ if (!httpReply) {
+ qWarning() << "QHttpThreadDelegate::finishedWithErrorSlot: HTTP reply had already been deleted, internal problem. Please report.";
+ return;
+ }
+
+#ifndef QT_NO_OPENSSL
+ if (ssl)
+ emit sslConfigurationChanged(httpReply->sslConfiguration());
+#endif
+ emit error(errorCode,detail);
+ emit downloadFinished();
+
+
+ QMetaObject::invokeMethod(httpReply, "deleteLater", Qt::QueuedConnection);
+ QMetaObject::invokeMethod(this, "deleteLater", Qt::QueuedConnection);
+ httpReply = 0;
+}
+
+
+void QHttpThreadDelegate::synchronousFinishedWithErrorSlot(QNetworkReply::NetworkError errorCode, const QString &detail)
+{
+ incomingErrorCode = errorCode;
+ incomingErrorDetail = detail;
+
+ QMetaObject::invokeMethod(httpReply, "deleteLater", Qt::QueuedConnection);
+ QMetaObject::invokeMethod(synchronousRequestLoop, "quit", Qt::QueuedConnection);
+ httpReply = 0;
+}
+
+static void downloadBufferDeleter(char *ptr)
+{
+ delete[] ptr;
+}
+
+void QHttpThreadDelegate::headerChangedSlot()
+{
+#ifndef QT_NO_OPENSSL
+ if (ssl)
+ emit sslConfigurationChanged(httpReply->sslConfiguration());
+#endif
+
+ // Is using a zerocopy buffer allowed by user and possible with this reply?
+ if (httpReply->supportsUserProvidedDownloadBuffer()
+ && downloadBufferMaximumSize > 0) {
+ char *buf = new char[httpReply->contentLength()]; // throws if allocation fails
+ if (buf) {
+ downloadBuffer = QSharedPointer<char>(buf, downloadBufferDeleter);
+ httpReply->setUserProvidedDownloadBuffer(buf);
+ }
+ }
+
+ // We fetch this into our own
+ incomingHeaders = httpReply->header();
+ incomingStatusCode = httpReply->statusCode();
+ incomingReasonPhrase = httpReply->reasonPhrase();
+ isPipeliningUsed = httpReply->isPipeliningUsed();
+ incomingContentLength = httpReply->contentLength();
+
+ emit downloadMetaData(incomingHeaders,
+ incomingStatusCode,
+ incomingReasonPhrase,
+ isPipeliningUsed,
+ downloadBuffer,
+ incomingContentLength);
+}
+
+void QHttpThreadDelegate::synchronousHeaderChangedSlot()
+{
+ // Store the information we need in this object, the QNetworkAccessHttpBackend will later read it
+ incomingHeaders = httpReply->header();
+ incomingStatusCode = httpReply->statusCode();
+ incomingReasonPhrase = httpReply->reasonPhrase();
+ isPipeliningUsed = httpReply->isPipeliningUsed();
+ incomingContentLength = httpReply->contentLength();
+}
+
+
+void QHttpThreadDelegate::dataReadProgressSlot(int done, int total)
+{
+ // If we don't have a download buffer don't attempt to go this codepath
+ // It is not used by QNetworkAccessHttpBackend
+ if (downloadBuffer.isNull())
+ return;
+
+ pendingDownloadProgress->fetchAndAddRelease(1);
+ emit downloadProgress(done, total);
+}
+
+void QHttpThreadDelegate::cacheCredentialsSlot(const QHttpNetworkRequest &request, QAuthenticator *authenticator)
+{
+ authenticationManager->cacheCredentials(request.url(), authenticator);
+}
+
+
+#ifndef QT_NO_OPENSSL
+void QHttpThreadDelegate::sslErrorsSlot(const QList<QSslError> &errors)
+{
+ emit sslConfigurationChanged(httpReply->sslConfiguration());
+
+ bool ignoreAll = false;
+ QList<QSslError> specificErrors;
+ emit sslErrors(errors, &ignoreAll, &specificErrors);
+ if (ignoreAll)
+ httpReply->ignoreSslErrors();
+ if (!specificErrors.isEmpty())
+ httpReply->ignoreSslErrors(specificErrors);
+}
+#endif
+
+void QHttpThreadDelegate::synchronousAuthenticationRequiredSlot(const QHttpNetworkRequest &request, QAuthenticator *a)
+{
+ Q_UNUSED(request);
+
+ // Ask the credential cache
+ QNetworkAuthenticationCredential credential = authenticationManager->fetchCachedCredentials(httpRequest.url(), a);
+ if (!credential.isNull()) {
+ a->setUser(credential.user);
+ a->setPassword(credential.password);
+ }
+
+ // Disconnect this connection now since we only want to ask the authentication cache once.
+ QObject::disconnect(this, SLOT(synchronousAuthenticationRequiredSlot(QHttpNetworkRequest,QAuthenticator*)));
+}
+
+#ifndef QT_NO_NETWORKPROXY
+void QHttpThreadDelegate::synchronousProxyAuthenticationRequiredSlot(const QNetworkProxy &p, QAuthenticator *a)
+{
+ // Ask the credential cache
+ QNetworkAuthenticationCredential credential = authenticationManager->fetchCachedProxyCredentials(p, a);
+ if (!credential.isNull()) {
+ a->setUser(credential.user);
+ a->setPassword(credential.password);
+ }
+
+ // Disconnect this connection now since we only want to ask the authentication cache once.
+ QObject::disconnect(this, SLOT(synchronousProxyAuthenticationRequiredSlot(QNetworkProxy,QAuthenticator*)));
+}
+
+#endif
+
+QT_END_NAMESPACE
diff --git a/src/network/access/qhttpthreaddelegate_p.h b/src/network/access/qhttpthreaddelegate_p.h
new file mode 100644
index 0000000..3b598aa
--- /dev/null
+++ b/src/network/access/qhttpthreaddelegate_p.h
@@ -0,0 +1,285 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtNetwork module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QHTTPTHREADDELEGATE_H
+#define QHTTPTHREADDELEGATE_H
+
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists for the convenience
+// of the Network Access API. This header file may change from
+// version to version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <QObject>
+#include <QThreadStorage>
+#include <QNetworkProxy>
+#include <QSslConfiguration>
+#include <QSslError>
+#include <QList>
+#include <QNetworkReply>
+#include "qhttpnetworkrequest_p.h"
+#include "qhttpnetworkconnection_p.h"
+#include <QSharedPointer>
+#include "qsslconfiguration.h"
+#include "private/qnoncontiguousbytedevice_p.h"
+#include "qnetworkaccessauthenticationmanager_p.h"
+
+QT_BEGIN_NAMESPACE
+
+class QAuthenticator;
+class QHttpNetworkReply;
+class QEventLoop;
+class QNetworkAccessCache;
+class QNetworkAccessCachedHttpConnection;
+
+class QHttpThreadDelegate : public QObject
+{
+ Q_OBJECT
+public:
+ explicit QHttpThreadDelegate(QObject *parent = 0);
+
+ ~QHttpThreadDelegate();
+
+ // incoming
+ bool ssl;
+#ifndef QT_NO_OPENSSL
+ QSslConfiguration incomingSslConfiguration;
+#endif
+ QHttpNetworkRequest httpRequest;
+ qint64 downloadBufferMaximumSize;
+ // From backend, modified by us for signal compression
+ QSharedPointer<QAtomicInt> pendingDownloadData;
+ QSharedPointer<QAtomicInt> pendingDownloadProgress;
+#ifndef QT_NO_NETWORKPROXY
+ QNetworkProxy cacheProxy;
+ QNetworkProxy transparentProxy;
+#endif
+ QSharedPointer<QNetworkAccessAuthenticationManager> authenticationManager;
+ bool synchronous;
+
+ // outgoing, Retrieved in the synchronous HTTP case
+ QByteArray synchronousDownloadData;
+ QList<QPair<QByteArray,QByteArray> > incomingHeaders;
+ int incomingStatusCode;
+ QString incomingReasonPhrase;
+ bool isPipeliningUsed;
+ qint64 incomingContentLength;
+ QNetworkReply::NetworkError incomingErrorCode;
+ QString incomingErrorDetail;
+
+protected:
+ // The zerocopy download buffer, if used:
+ QSharedPointer<char> downloadBuffer;
+ // The QHttpNetworkConnection that is used
+ QNetworkAccessCachedHttpConnection *httpConnection;
+ QByteArray cacheKey;
+ QHttpNetworkReply *httpReply;
+
+ // Used for implementing the synchronous HTTP, see startRequestSynchronously()
+ QEventLoop *synchronousRequestLoop;
+
+signals:
+ void authenticationRequired(const QHttpNetworkRequest &request, QAuthenticator *);
+#ifndef QT_NO_NETWORKPROXY
+ void proxyAuthenticationRequired(const QNetworkProxy &, QAuthenticator *);
+#endif
+#ifndef QT_NO_OPENSSL
+ void sslErrors(const QList<QSslError> &, bool *, QList<QSslError> *);
+ void sslConfigurationChanged(const QSslConfiguration);
+#endif
+ void downloadMetaData(QList<QPair<QByteArray,QByteArray> >,int,QString,bool,QSharedPointer<char>,qint64);
+ void downloadProgress(qint64, qint64);
+ void downloadData(QByteArray);
+ void error(QNetworkReply::NetworkError, const QString);
+ void downloadFinished();
+public slots:
+ // This are called via QueuedConnection from user thread
+ void startRequest();
+ void abortRequest();
+ // This is called with a BlockingQueuedConnection from user thread
+ void startRequestSynchronously();
+protected slots:
+ // From QHttp*
+ void readyReadSlot();
+ void finishedSlot();
+ void finishedWithErrorSlot(QNetworkReply::NetworkError errorCode, const QString &detail = QString());
+ void synchronousFinishedSlot();
+ void synchronousFinishedWithErrorSlot(QNetworkReply::NetworkError errorCode, const QString &detail = QString());
+ void headerChangedSlot();
+ void synchronousHeaderChangedSlot();
+ void dataReadProgressSlot(int done, int total);
+ void cacheCredentialsSlot(const QHttpNetworkRequest &request, QAuthenticator *authenticator);
+#ifndef QT_NO_OPENSSL
+ void sslErrorsSlot(const QList<QSslError> &errors);
+#endif
+
+ void synchronousAuthenticationRequiredSlot(const QHttpNetworkRequest &request, QAuthenticator *);
+#ifndef QT_NO_NETWORKPROXY
+ void synchronousProxyAuthenticationRequiredSlot(const QNetworkProxy &, QAuthenticator *);
+#endif
+
+protected:
+ // Cache for all the QHttpNetworkConnection objects.
+ // This is per thread.
+ static QThreadStorage<QNetworkAccessCache *> connections;
+
+};
+
+// This QNonContiguousByteDevice is connected to the QNetworkAccessHttpBackend
+// and represents the PUT/POST data.
+class QNonContiguousByteDeviceThreadForwardImpl : public QNonContiguousByteDevice
+{
+ Q_OBJECT
+protected:
+ bool wantDataPending;
+ qint64 m_amount;
+ char *m_data;
+ QByteArray m_dataArray;
+ bool m_atEnd;
+ qint64 m_size;
+public:
+ QNonContiguousByteDeviceThreadForwardImpl(bool aE, qint64 s)
+ : QNonContiguousByteDevice(),
+ wantDataPending(false),
+ m_amount(0),
+ m_data(0),
+ m_atEnd(aE),
+ m_size(s)
+ {
+ }
+
+ ~QNonContiguousByteDeviceThreadForwardImpl()
+ {
+ }
+
+ const char* readPointer(qint64 maximumLength, qint64 &len)
+ {
+ if (m_amount == 0 && wantDataPending == false) {
+ len = 0;
+ wantDataPending = true;
+ emit wantData(maximumLength);
+ } else if (m_amount == 0 && wantDataPending == true) {
+ // Do nothing, we already sent a wantData signal and wait for results
+ len = 0;
+ } else if (m_amount > 0) {
+ len = m_amount;
+ return m_data;
+ }
+ // cannot happen
+ return 0;
+ }
+
+ bool advanceReadPointer(qint64 a)
+ {
+ if (m_data == 0)
+ return false;
+
+ m_amount -= a;
+ m_data += a;
+
+ // To main thread to inform about our state
+ emit processedData(a);
+
+ // FIXME possible optimization, already ask user thread for some data
+
+ return true;
+ }
+
+ bool atEnd()
+ {
+ if (m_amount > 0)
+ return false;
+ else
+ return m_atEnd;
+ }
+
+ bool reset()
+ {
+ m_amount = 0;
+ m_data = 0;
+
+ // Communicate as BlockingQueuedConnection
+ bool b = false;
+ emit resetData(&b);
+ return b;
+ }
+
+ qint64 size()
+ {
+ return m_size;
+ }
+
+public slots:
+ // From user thread:
+ void haveDataSlot(QByteArray dataArray, bool dataAtEnd, qint64 dataSize)
+ {
+ wantDataPending = false;
+
+ m_dataArray = dataArray;
+ m_data = const_cast<char*>(m_dataArray.constData());
+ m_amount = dataArray.size();
+
+ m_atEnd = dataAtEnd;
+ m_size = dataSize;
+
+ // This will tell the HTTP code (QHttpNetworkConnectionChannel) that we have data available now
+ emit readyRead();
+ }
+
+signals:
+ // void readyRead(); in parent class
+ // void readProgress(qint64 current, qint64 total); happens in the main thread with the real bytedevice
+
+ // to main thread:
+ void wantData(qint64);
+ void processedData(qint64);
+ void resetData(bool *b);
+};
+
+QT_END_NAMESPACE
+
+#endif // QHTTPTHREADDELEGATE_H
diff --git a/src/network/access/qnetworkaccessauthenticationmanager.cpp b/src/network/access/qnetworkaccessauthenticationmanager.cpp
new file mode 100644
index 0000000..d2bf00a
--- /dev/null
+++ b/src/network/access/qnetworkaccessauthenticationmanager.cpp
@@ -0,0 +1,297 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtNetwork module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qnetworkaccessmanager.h"
+#include "qnetworkaccessmanager_p.h"
+#include "qnetworkaccessauthenticationmanager_p.h"
+
+#include "QtCore/qbuffer.h"
+#include "QtCore/qurl.h"
+#include "QtCore/qvector.h"
+#include "QtCore/QMutexLocker"
+#include "QtNetwork/qauthenticator.h"
+
+QT_BEGIN_NAMESPACE
+
+
+
+
+class QNetworkAuthenticationCache: private QVector<QNetworkAuthenticationCredential>,
+ public QNetworkAccessCache::CacheableObject
+{
+public:
+ QNetworkAuthenticationCache()
+ {
+ setExpires(false);
+ setShareable(true);
+ reserve(1);
+ }
+
+ QNetworkAuthenticationCredential *findClosestMatch(const QString &domain)
+ {
+ iterator it = qLowerBound(begin(), end(), domain);
+ if (it == end() && !isEmpty())
+ --it;
+ if (it == end() || !domain.startsWith(it->domain))
+ return 0;
+ return &*it;
+ }
+
+ void insert(const QString &domain, const QString &user, const QString &password)
+ {
+ QNetworkAuthenticationCredential *closestMatch = findClosestMatch(domain);
+ if (closestMatch && closestMatch->domain == domain) {
+ // we're overriding the current credentials
+ closestMatch->user = user;
+ closestMatch->password = password;
+ } else {
+ QNetworkAuthenticationCredential newCredential;
+ newCredential.domain = domain;
+ newCredential.user = user;
+ newCredential.password = password;
+
+ if (closestMatch)
+ QVector<QNetworkAuthenticationCredential>::insert(++closestMatch, newCredential);
+ else
+ QVector<QNetworkAuthenticationCredential>::insert(end(), newCredential);
+ }
+ }
+
+ virtual void dispose() { delete this; }
+};
+
+#ifndef QT_NO_NETWORKPROXY
+static QByteArray proxyAuthenticationKey(const QNetworkProxy &proxy, const QString &realm)
+{
+ QUrl key;
+
+ switch (proxy.type()) {
+ case QNetworkProxy::Socks5Proxy:
+ key.setScheme(QLatin1String("proxy-socks5"));
+ break;
+
+ case QNetworkProxy::HttpProxy:
+ case QNetworkProxy::HttpCachingProxy:
+ key.setScheme(QLatin1String("proxy-http"));
+ break;
+
+ case QNetworkProxy::FtpCachingProxy:
+ key.setScheme(QLatin1String("proxy-ftp"));
+ break;
+
+ case QNetworkProxy::DefaultProxy:
+ case QNetworkProxy::NoProxy:
+ // shouldn't happen
+ return QByteArray();
+
+ // no default:
+ // let there be errors if a new proxy type is added in the future
+ }
+
+ if (key.scheme().isEmpty())
+ // proxy type not handled
+ return QByteArray();
+
+ key.setUserName(proxy.user());
+ key.setHost(proxy.hostName());
+ key.setPort(proxy.port());
+ key.setFragment(realm);
+ return "auth:" + key.toEncoded();
+}
+#endif
+
+static inline QByteArray authenticationKey(const QUrl &url, const QString &realm)
+{
+ QUrl copy = url;
+ copy.setFragment(realm);
+ return "auth:" + copy.toEncoded(QUrl::RemovePassword | QUrl::RemovePath | QUrl::RemoveQuery);
+}
+
+
+#ifndef QT_NO_NETWORKPROXY
+void QNetworkAccessAuthenticationManager::cacheProxyCredentials(const QNetworkProxy &p,
+ const QAuthenticator *authenticator)
+{
+ Q_ASSERT(authenticator);
+ Q_ASSERT(p.type() != QNetworkProxy::DefaultProxy);
+ Q_ASSERT(p.type() != QNetworkProxy::NoProxy);
+
+ QMutexLocker mutexLocker(&mutex);
+
+ QString realm = authenticator->realm();
+ QNetworkProxy proxy = p;
+ proxy.setUser(authenticator->user());
+ // Set two credentials: one with the username and one without
+ do {
+ // Set two credentials actually: one with and one without the realm
+ do {
+ QByteArray cacheKey = proxyAuthenticationKey(proxy, realm);
+ if (cacheKey.isEmpty())
+ return; // should not happen
+
+ QNetworkAuthenticationCache *auth = new QNetworkAuthenticationCache;
+ auth->insert(QString(), authenticator->user(), authenticator->password());
+ authenticationCache.addEntry(cacheKey, auth); // replace the existing one, if there's any
+
+ if (realm.isEmpty()) {
+ break;
+ } else {
+ realm.clear();
+ }
+ } while (true);
+
+ if (proxy.user().isEmpty())
+ break;
+ else
+ proxy.setUser(QString());
+ } while (true);
+}
+
+QNetworkAuthenticationCredential
+QNetworkAccessAuthenticationManager::fetchCachedProxyCredentials(const QNetworkProxy &p,
+ const QAuthenticator *authenticator)
+{
+ QNetworkProxy proxy = p;
+ if (proxy.type() == QNetworkProxy::DefaultProxy) {
+ proxy = QNetworkProxy::applicationProxy();
+ }
+ if (!proxy.password().isEmpty())
+ return QNetworkAuthenticationCredential(); // no need to set credentials if it already has them
+
+ QString realm;
+ if (authenticator)
+ realm = authenticator->realm();
+
+ QMutexLocker mutexLocker(&mutex);
+ QByteArray cacheKey = proxyAuthenticationKey(proxy, realm);
+ if (cacheKey.isEmpty())
+ return QNetworkAuthenticationCredential();
+ if (!authenticationCache.hasEntry(cacheKey))
+ return QNetworkAuthenticationCredential();
+
+ QNetworkAuthenticationCache *auth =
+ static_cast<QNetworkAuthenticationCache *>(authenticationCache.requestEntryNow(cacheKey));
+ QNetworkAuthenticationCredential cred = *auth->findClosestMatch(QString());
+ authenticationCache.releaseEntry(cacheKey);
+
+ // proxy cache credentials always have exactly one item
+ Q_ASSERT_X(!cred.isNull(), "QNetworkAccessManager",
+ "Internal inconsistency: found a cache key for a proxy, but it's empty");
+ return cred;
+}
+
+#endif
+
+void QNetworkAccessAuthenticationManager::cacheCredentials(const QUrl &url,
+ const QAuthenticator *authenticator)
+{
+ Q_ASSERT(authenticator);
+ QString domain = QString::fromLatin1("/"); // FIXME: make QAuthenticator return the domain
+ QString realm = authenticator->realm();
+
+ QMutexLocker mutexLocker(&mutex);
+
+ // Set two credentials actually: one with and one without the username in the URL
+ QUrl copy = url;
+ copy.setUserName(authenticator->user());
+ do {
+ QByteArray cacheKey = authenticationKey(copy, realm);
+ if (authenticationCache.hasEntry(cacheKey)) {
+ QNetworkAuthenticationCache *auth =
+ static_cast<QNetworkAuthenticationCache *>(authenticationCache.requestEntryNow(cacheKey));
+ auth->insert(domain, authenticator->user(), authenticator->password());
+ authenticationCache.releaseEntry(cacheKey);
+ } else {
+ QNetworkAuthenticationCache *auth = new QNetworkAuthenticationCache;
+ auth->insert(domain, authenticator->user(), authenticator->password());
+ authenticationCache.addEntry(cacheKey, auth);
+ }
+
+ if (copy.userName().isEmpty()) {
+ break;
+ } else {
+ copy.setUserName(QString());
+ }
+ } while (true);
+}
+
+/*!
+ Fetch the credential data from the credential cache.
+
+ If auth is 0 (as it is when called from createRequest()), this will try to
+ look up with an empty realm. That fails in most cases for HTTP (because the
+ realm is seldom empty for HTTP challenges). In any case, QHttpNetworkConnection
+ never sends the credentials on the first attempt: it needs to find out what
+ authentication methods the server supports.
+
+ For FTP, realm is always empty.
+*/
+QNetworkAuthenticationCredential
+QNetworkAccessAuthenticationManager::fetchCachedCredentials(const QUrl &url,
+ const QAuthenticator *authentication)
+{
+ if (!url.password().isEmpty())
+ return QNetworkAuthenticationCredential(); // no need to set credentials if it already has them
+
+ QString realm;
+ if (authentication)
+ realm = authentication->realm();
+
+ QByteArray cacheKey = authenticationKey(url, realm);
+
+ QMutexLocker mutexLocker(&mutex);
+ if (!authenticationCache.hasEntry(cacheKey))
+ return QNetworkAuthenticationCredential();
+
+ QNetworkAuthenticationCache *auth =
+ static_cast<QNetworkAuthenticationCache *>(authenticationCache.requestEntryNow(cacheKey));
+ QNetworkAuthenticationCredential cred = *auth->findClosestMatch(url.path());
+ authenticationCache.releaseEntry(cacheKey);
+ return cred;
+}
+
+void QNetworkAccessAuthenticationManager::clearCache()
+{
+ authenticationCache.clear();
+}
+
+QT_END_NAMESPACE
+
diff --git a/src/network/access/qnetworkaccessdatabackend_p.h b/src/network/access/qnetworkaccessauthenticationmanager_p.h
index 18569ec..d2347b1 100644
--- a/src/network/access/qnetworkaccessdatabackend_p.h
+++ b/src/network/access/qnetworkaccessauthenticationmanager_p.h
@@ -39,8 +39,8 @@
**
****************************************************************************/
-#ifndef QNETWORKACCESSDATABACKEND_P_H
-#define QNETWORKACCESSDATABACKEND_P_H
+#ifndef QNETWORKACCESSAUTHENTICATIONMANAGER_P_H
+#define QNETWORKACCESSAUTHENTICATIONMANAGER_P_H
//
// W A R N I N G
@@ -53,30 +53,53 @@
// We mean it.
//
+#include "qnetworkaccessmanager.h"
+#include "qnetworkaccesscache_p.h"
#include "qnetworkaccessbackend_p.h"
+#include "QtNetwork/qnetworkproxy.h"
+#include "QtCore/QMutex"
QT_BEGIN_NAMESPACE
-class QNetworkAccessDataBackend: public QNetworkAccessBackend
+class QAuthenticator;
+class QAbstractNetworkCache;
+class QNetworkAuthenticationCredential;
+class QNetworkCookieJar;
+
+class QNetworkAuthenticationCredential
{
public:
- QNetworkAccessDataBackend();
- virtual ~QNetworkAccessDataBackend();
-
- virtual void open();
- virtual void closeDownstreamChannel();
- virtual void closeUpstreamChannel();
- virtual bool waitForDownstreamReadyRead(int msecs);
- virtual bool waitForUpstreamBytesWritten(int msecs);
-
- virtual bool processRequestSynchronously();
+ QString domain;
+ QString user;
+ QString password;
+ bool isNull() {
+ return domain.isNull();
+ }
};
+Q_DECLARE_TYPEINFO(QNetworkAuthenticationCredential, Q_MOVABLE_TYPE);
+inline bool operator<(const QNetworkAuthenticationCredential &t1, const QString &t2)
+{ return t1.domain < t2; }
-class QNetworkAccessDataBackendFactory: public QNetworkAccessBackendFactory
+class QNetworkAccessAuthenticationManager
{
public:
- virtual QNetworkAccessBackend *create(QNetworkAccessManager::Operation op,
- const QNetworkRequest &request) const;
+ QNetworkAccessAuthenticationManager() { };
+
+ void cacheCredentials(const QUrl &url, const QAuthenticator *auth);
+ QNetworkAuthenticationCredential fetchCachedCredentials(const QUrl &url,
+ const QAuthenticator *auth = 0);
+
+#ifndef QT_NO_NETWORKPROXY
+ void cacheProxyCredentials(const QNetworkProxy &proxy, const QAuthenticator *auth);
+ QNetworkAuthenticationCredential fetchCachedProxyCredentials(const QNetworkProxy &proxy,
+ const QAuthenticator *auth = 0);
+#endif
+
+ void clearCache();
+
+protected:
+ QNetworkAccessCache authenticationCache;
+ QMutex mutex;
};
QT_END_NAMESPACE
diff --git a/src/network/access/qnetworkaccessbackend.cpp b/src/network/access/qnetworkaccessbackend.cpp
index fd1fa60..5aedac9 100644
--- a/src/network/access/qnetworkaccessbackend.cpp
+++ b/src/network/access/qnetworkaccessbackend.cpp
@@ -106,12 +106,10 @@ QNetworkAccessBackend *QNetworkAccessManagerPrivate::findBackend(QNetworkAccessM
QNonContiguousByteDevice* QNetworkAccessBackend::createUploadByteDevice()
{
- QNonContiguousByteDevice* device = 0;
-
if (reply->outgoingDataBuffer)
- device = QNonContiguousByteDeviceFactory::create(reply->outgoingDataBuffer);
+ uploadByteDevice = QSharedPointer<QNonContiguousByteDevice>(QNonContiguousByteDeviceFactory::create(reply->outgoingDataBuffer));
else if (reply->outgoingData) {
- device = QNonContiguousByteDeviceFactory::create(reply->outgoingData);
+ uploadByteDevice = QSharedPointer<QNonContiguousByteDevice>(QNonContiguousByteDeviceFactory::create(reply->outgoingData));
} else {
return 0;
}
@@ -120,14 +118,13 @@ QNonContiguousByteDevice* QNetworkAccessBackend::createUploadByteDevice()
reply->request.attribute(QNetworkRequest::DoNotBufferUploadDataAttribute,
QVariant(false)) == QVariant(true);
if (bufferDisallowed)
- device->disableReset();
-
- // make sure we delete this later
- device->setParent(this);
+ uploadByteDevice->disableReset();
- connect(device, SIGNAL(readProgress(qint64,qint64)), this, SLOT(emitReplyUploadProgress(qint64,qint64)));
+ // We want signal emissions only for normal asynchronous uploads
+ if (!isSynchronous())
+ connect(uploadByteDevice.data(), SIGNAL(readProgress(qint64,qint64)), this, SLOT(emitReplyUploadProgress(qint64,qint64)));
- return device;
+ return uploadByteDevice.data();
}
// need to have this function since the reply is a private member variable
@@ -327,11 +324,6 @@ void QNetworkAccessBackend::authenticationRequired(QAuthenticator *authenticator
manager->authenticationRequired(this, authenticator);
}
-void QNetworkAccessBackend::cacheCredentials(QAuthenticator *authenticator)
-{
- manager->cacheCredentials(this->reply->url, authenticator);
-}
-
void QNetworkAccessBackend::metaDataChanged()
{
reply->metaDataChanged();
diff --git a/src/network/access/qnetworkaccessbackend_p.h b/src/network/access/qnetworkaccessbackend_p.h
index 26ee61a..644ae2d 100644
--- a/src/network/access/qnetworkaccessbackend_p.h
+++ b/src/network/access/qnetworkaccessbackend_p.h
@@ -70,7 +70,6 @@ class QNetworkAccessManagerPrivate;
class QNetworkReplyImplPrivate;
class QAbstractNetworkCache;
class QNetworkCacheMetaData;
-class QNetworkAccessBackendUploadIODevice;
class QNonContiguousByteDevice;
// Should support direct file upload from disk or download to disk.
@@ -175,7 +174,6 @@ protected:
// Create the device used for reading the upload data
QNonContiguousByteDevice* createUploadByteDevice();
-
// these functions control the downstream mechanism
// that is, data that has come via the connection and is going out the backend
qint64 nextDownstreamBlockSize() const;
@@ -185,6 +183,8 @@ protected:
void writeDownstreamDataDownloadBuffer(qint64, qint64);
char* getDownloadBuffer(qint64);
+ QSharedPointer<QNonContiguousByteDevice> uploadByteDevice;
+
public slots:
// for task 251801, needs to be a slot to be called asynchronously
void writeDownstreamData(QIODevice *data);
@@ -196,19 +196,22 @@ protected slots:
void proxyAuthenticationRequired(const QNetworkProxy &proxy, QAuthenticator *auth);
#endif
void authenticationRequired(QAuthenticator *auth);
- void cacheCredentials(QAuthenticator *auth);
void metaDataChanged();
void redirectionRequested(const QUrl &destination);
void sslErrors(const QList<QSslError> &errors);
void emitReplyUploadProgress(qint64 bytesSent, qint64 bytesTotal);
+protected:
+ // FIXME In the long run we should get rid of our QNAM architecture
+ // and scrap this ReplyImpl/Backend distinction.
+ QNetworkAccessManagerPrivate *manager;
+ QNetworkReplyImplPrivate *reply;
+
private:
friend class QNetworkAccessManager;
friend class QNetworkAccessManagerPrivate;
- friend class QNetworkAccessBackendUploadIODevice;
friend class QNetworkReplyImplPrivate;
- QNetworkAccessManagerPrivate *manager;
- QNetworkReplyImplPrivate *reply;
+
bool synchronous;
};
diff --git a/src/network/access/qnetworkaccessfilebackend.cpp b/src/network/access/qnetworkaccessfilebackend.cpp
index 6da0722..7ebf626 100644
--- a/src/network/access/qnetworkaccessfilebackend.cpp
+++ b/src/network/access/qnetworkaccessfilebackend.cpp
@@ -75,6 +75,8 @@ QNetworkAccessFileBackendFactory::create(QNetworkAccessManager::Operation op,
//
// this construct here must match the one below in open()
QFileInfo fi(url.toString(QUrl::RemoveAuthority | QUrl::RemoveFragment | QUrl::RemoveQuery));
+ if ((url.scheme().length()==1) && fi.exists())
+ qWarning("QNetworkAccessFileBackendFactory: URL has no schema set, use file:// for files");
if (fi.exists() || (op == QNetworkAccessManager::PutOperation && fi.dir().exists()))
return new QNetworkAccessFileBackend;
}
diff --git a/src/network/access/qnetworkaccessftpbackend.cpp b/src/network/access/qnetworkaccessftpbackend.cpp
index bad010f..e34e6bb 100644
--- a/src/network/access/qnetworkaccessftpbackend.cpp
+++ b/src/network/access/qnetworkaccessftpbackend.cpp
@@ -307,8 +307,10 @@ void QNetworkAccessFtpBackend::ftpDone()
// logged in successfully, send the stat requests (if supported)
QString command = url().path();
command.prepend(QLatin1String("%1 "));
- if (supportsSize)
+ if (supportsSize) {
+ ftp->rawCommand(QLatin1String("TYPE I"));
sizeId = ftp->rawCommand(command.arg(QLatin1String("SIZE"))); // get size
+ }
if (supportsMdtm)
mdtmId = ftp->rawCommand(command.arg(QLatin1String("MDTM"))); // get modified time
if (!supportsSize && !supportsMdtm)
diff --git a/src/network/access/qnetworkaccesshttpbackend.cpp b/src/network/access/qnetworkaccesshttpbackend.cpp
index 79c43fa..a031cd0 100644
--- a/src/network/access/qnetworkaccesshttpbackend.cpp
+++ b/src/network/access/qnetworkaccesshttpbackend.cpp
@@ -52,60 +52,19 @@
#include "QtCore/qdatetime.h"
#include "QtCore/qelapsedtimer.h"
#include "QtNetwork/qsslconfiguration.h"
+#include "qhttpthreaddelegate_p.h"
+#include "qthread.h"
#ifndef QT_NO_HTTP
#include <string.h> // for strchr
-QT_BEGIN_NAMESPACE
+Q_DECLARE_METATYPE(QSharedPointer<char>)
-enum {
- DefaultHttpPort = 80,
- DefaultHttpsPort = 443
-};
+QT_BEGIN_NAMESPACE
class QNetworkProxy;
-static QByteArray makeCacheKey(QNetworkAccessHttpBackend *backend, QNetworkProxy *proxy)
-{
- QByteArray result;
- QUrl copy = backend->url();
- bool isEncrypted = copy.scheme().toLower() == QLatin1String("https");
- copy.setPort(copy.port(isEncrypted ? DefaultHttpsPort : DefaultHttpPort));
- result = copy.toEncoded(QUrl::RemoveUserInfo | QUrl::RemovePath |
- QUrl::RemoveQuery | QUrl::RemoveFragment);
-
-#ifndef QT_NO_NETWORKPROXY
- if (proxy->type() != QNetworkProxy::NoProxy) {
- QUrl key;
-
- switch (proxy->type()) {
- case QNetworkProxy::Socks5Proxy:
- key.setScheme(QLatin1String("proxy-socks5"));
- break;
-
- case QNetworkProxy::HttpProxy:
- case QNetworkProxy::HttpCachingProxy:
- key.setScheme(QLatin1String("proxy-http"));
- break;
-
- default:
- break;
- }
-
- if (!key.scheme().isEmpty()) {
- key.setUserName(proxy->user());
- key.setHost(proxy->hostName());
- key.setPort(proxy->port());
- key.setEncodedQuery(result);
- result = key.toEncoded();
- }
- }
-#endif
-
- return "http-connection:" + result;
-}
-
static inline bool isSeparator(register char c)
{
static const char separators[] = "()<>@,;:\\\"/[]?={}";
@@ -230,71 +189,13 @@ QNetworkAccessHttpBackendFactory::create(QNetworkAccessManager::Operation op,
return 0;
}
-static QNetworkReply::NetworkError statusCodeFromHttp(int httpStatusCode, const QUrl &url)
-{
- QNetworkReply::NetworkError code;
- // we've got an error
- switch (httpStatusCode) {
- case 401: // Authorization required
- code = QNetworkReply::AuthenticationRequiredError;
- break;
-
- case 403: // Access denied
- code = QNetworkReply::ContentOperationNotPermittedError;
- break;
-
- case 404: // Not Found
- code = QNetworkReply::ContentNotFoundError;
- break;
-
- case 405: // Method Not Allowed
- code = QNetworkReply::ContentOperationNotPermittedError;
- break;
-
- case 407:
- code = QNetworkReply::ProxyAuthenticationRequiredError;
- break;
-
- default:
- if (httpStatusCode > 500) {
- // some kind of server error
- code = QNetworkReply::ProtocolUnknownError;
- } else if (httpStatusCode >= 400) {
- // content error we did not handle above
- code = QNetworkReply::UnknownContentError;
- } else {
- qWarning("QNetworkAccess: got HTTP status code %d which is not expected from url: \"%s\"",
- httpStatusCode, qPrintable(url.toString()));
- code = QNetworkReply::ProtocolFailure;
- }
- }
-
- return code;
-}
-
-class QNetworkAccessCachedHttpConnection: public QHttpNetworkConnection,
- public QNetworkAccessCache::CacheableObject
-{
- // Q_OBJECT
-public:
- QNetworkAccessCachedHttpConnection(const QString &hostName, quint16 port, bool encrypt)
- : QHttpNetworkConnection(hostName, port, encrypt)
- {
- setExpires(true);
- setShareable(true);
- }
-
- virtual void dispose()
- {
-#if 0 // sample code; do this right with the API
- Q_ASSERT(!isWorking());
-#endif
- delete this;
- }
-};
-
QNetworkAccessHttpBackend::QNetworkAccessHttpBackend()
- : QNetworkAccessBackend(), httpReply(0), http(0), uploadDevice(0)
+ : QNetworkAccessBackend()
+ , statusCode(0)
+ , pendingDownloadDataEmissions(new QAtomicInt())
+ , pendingDownloadProgressEmissions(new QAtomicInt())
+ , loadingFromCache(false)
+ , usingZerocopyDownloadBuffer(false)
#ifndef QT_NO_OPENSSL
, pendingSslConfiguration(0), pendingIgnoreAllSslErrors(false)
#endif
@@ -304,44 +205,14 @@ QNetworkAccessHttpBackend::QNetworkAccessHttpBackend()
QNetworkAccessHttpBackend::~QNetworkAccessHttpBackend()
{
- if (http)
- disconnectFromHttp();
+ // This will do nothing if the request was already finished or aborted
+ emit abortHttpRequest();
+
#ifndef QT_NO_OPENSSL
delete pendingSslConfiguration;
#endif
}
-void QNetworkAccessHttpBackend::disconnectFromHttp()
-{
- if (http) {
- // This is abut disconnecting signals, not about disconnecting TCP connections
- disconnect(http, 0, this, 0);
-
- // Get the object cache that stores our QHttpNetworkConnection objects
- QNetworkAccessCache *cache = QNetworkAccessManagerPrivate::getObjectCache(this);
-
- // synchronous calls are not put into the cache, so for them the key is empty
- if (!cacheKey.isEmpty())
- cache->releaseEntry(cacheKey);
- }
-
- // This is abut disconnecting signals, not about disconnecting TCP connections
- if (httpReply)
- disconnect(httpReply, 0, this, 0);
-
- http = 0;
- httpReply = 0;
- cacheKey.clear();
-}
-
-void QNetworkAccessHttpBackend::finished()
-{
- if (http)
- disconnectFromHttp();
- // call parent
- QNetworkAccessBackend::finished();
-}
-
/*
For a given httpRequest
1) If AlwaysNetwork, return
@@ -362,6 +233,11 @@ void QNetworkAccessHttpBackend::validateCache(QHttpNetworkRequest &httpRequest,
return;
}
+ // The disk cache API does not currently support partial content retrieval.
+ // That is why we don't use the disk cache for any such requests.
+ if (request().hasRawHeader("Range"))
+ return;
+
QAbstractNetworkCache *nc = networkCache();
if (!nc)
return; // no local cache
@@ -487,9 +363,82 @@ static QHttpNetworkRequest::Priority convert(const QNetworkRequest::Priority& pr
void QNetworkAccessHttpBackend::postRequest()
{
+ QThread *thread = 0;
+ if (isSynchronous()) {
+ // A synchronous HTTP request uses its own thread
+ thread = new QThread();
+ QObject::connect(thread, SIGNAL(finished()), thread, SLOT(deleteLater()));
+ thread->start();
+ } else if (!manager->httpThread) {
+ // We use the manager-global thread.
+ // At some point we could switch to having multiple threads if it makes sense.
+ manager->httpThread = new QThread();
+ QObject::connect(manager->httpThread, SIGNAL(finished()), manager->httpThread, SLOT(deleteLater()));
+ manager->httpThread->start();
+#ifndef QT_NO_NETWORKPROXY
+ qRegisterMetaType<QNetworkProxy>("QNetworkProxy");
+#endif
+#ifndef QT_NO_OPENSSL
+ qRegisterMetaType<QList<QSslError> >("QList<QSslError>");
+ qRegisterMetaType<QSslConfiguration>("QSslConfiguration");
+#endif
+ qRegisterMetaType<QList<QPair<QByteArray,QByteArray> > >("QList<QPair<QByteArray,QByteArray> >");
+ qRegisterMetaType<QHttpNetworkRequest>("QHttpNetworkRequest");
+ qRegisterMetaType<QNetworkReply::NetworkError>("QNetworkReply::NetworkError");
+ qRegisterMetaType<QSharedPointer<char> >("QSharedPointer<char>");
+
+ thread = manager->httpThread;
+ } else {
+ // Asynchronous request, thread already exists
+ thread = manager->httpThread;
+ }
+
+ QUrl url = request().url();
+ httpRequest.setUrl(url);
+
+ bool ssl = url.scheme().toLower() == QLatin1String("https");
+ setAttribute(QNetworkRequest::ConnectionEncryptedAttribute, ssl);
+ httpRequest.setSsl(ssl);
+
+
+#ifndef QT_NO_NETWORKPROXY
+ QNetworkProxy transparentProxy, cacheProxy;
+
+ foreach (const QNetworkProxy &p, proxyList()) {
+ // use the first proxy that works
+ // for non-encrypted connections, any transparent or HTTP proxy
+ // for encrypted, only transparent proxies
+ if (!ssl
+ && (p.capabilities() & QNetworkProxy::CachingCapability)
+ && (p.type() == QNetworkProxy::HttpProxy ||
+ p.type() == QNetworkProxy::HttpCachingProxy)) {
+ cacheProxy = p;
+ transparentProxy = QNetworkProxy::NoProxy;
+ break;
+ }
+ if (p.isTransparentProxy()) {
+ transparentProxy = p;
+ cacheProxy = QNetworkProxy::NoProxy;
+ break;
+ }
+ }
+
+ // check if at least one of the proxies
+ if (transparentProxy.type() == QNetworkProxy::DefaultProxy &&
+ cacheProxy.type() == QNetworkProxy::DefaultProxy) {
+ // unsuitable proxies
+ QMetaObject::invokeMethod(this, "error", isSynchronous() ? Qt::DirectConnection : Qt::QueuedConnection,
+ Q_ARG(QNetworkReply::NetworkError, QNetworkReply::ProxyNotFoundError),
+ Q_ARG(QString, tr("No suitable proxy found")));
+ QMetaObject::invokeMethod(this, "finished", isSynchronous() ? Qt::DirectConnection : Qt::QueuedConnection);
+ return;
+ }
+#endif
+
+
bool loadedFromCache = false;
- QHttpNetworkRequest httpRequest;
httpRequest.setPriority(convert(request().priority()));
+
switch (operation()) {
case QNetworkAccessManager::GetOperation:
httpRequest.setOperation(QHttpNetworkRequest::Get);
@@ -504,13 +453,13 @@ void QNetworkAccessHttpBackend::postRequest()
case QNetworkAccessManager::PostOperation:
invalidateCache();
httpRequest.setOperation(QHttpNetworkRequest::Post);
- httpRequest.setUploadByteDevice(createUploadByteDevice());
+ createUploadByteDevice();
break;
case QNetworkAccessManager::PutOperation:
invalidateCache();
httpRequest.setOperation(QHttpNetworkRequest::Put);
- httpRequest.setUploadByteDevice(createUploadByteDevice());
+ createUploadByteDevice();
break;
case QNetworkAccessManager::DeleteOperation:
@@ -521,7 +470,7 @@ void QNetworkAccessHttpBackend::postRequest()
case QNetworkAccessManager::CustomOperation:
invalidateCache(); // for safety reasons, we don't know what the operation does
httpRequest.setOperation(QHttpNetworkRequest::Custom);
- httpRequest.setUploadByteDevice(createUploadByteDevice());
+ createUploadByteDevice();
httpRequest.setCustomVerb(request().attribute(
QNetworkRequest::CustomVerbAttribute).toByteArray());
break;
@@ -530,11 +479,6 @@ void QNetworkAccessHttpBackend::postRequest()
break; // can't happen
}
- bool encrypt = (url().scheme().toLower() == QLatin1String("https"));
- httpRequest.setSsl(encrypt);
-
- httpRequest.setUrl(url());
-
QList<QByteArray> headers = request().rawHeaderList();
if (resumeOffset != 0) {
if (headers.contains("Range")) {
@@ -558,6 +502,7 @@ void QNetworkAccessHttpBackend::postRequest()
httpRequest.setHeaderField("Range", "bytes=" + QByteArray::number(resumeOffset) + '-');
}
}
+
foreach (const QByteArray &header, headers)
httpRequest.setHeaderField(header, request().rawHeader(header));
@@ -576,30 +521,155 @@ void QNetworkAccessHttpBackend::postRequest()
QNetworkRequest::Automatic).toInt()) == QNetworkRequest::Manual)
httpRequest.setWithCredentials(false);
- httpReply = http->sendRequest(httpRequest);
- httpReply->setParent(this);
+
+ // Create the HTTP thread delegate
+ QHttpThreadDelegate *delegate = new QHttpThreadDelegate;
+
+ // For the synchronous HTTP, this is the normal way the delegate gets deleted
+ // For the asynchronous HTTP this is a safety measure, the delegate deletes itself when HTTP is finished
+ connect(thread, SIGNAL(finished()), delegate, SLOT(deleteLater()));
+
+ // Set the properties it needs
+ delegate->httpRequest = httpRequest;
+#ifndef QT_NO_NETWORKPROXY
+ delegate->cacheProxy = cacheProxy;
+ delegate->transparentProxy = transparentProxy;
+#endif
+ delegate->ssl = ssl;
#ifndef QT_NO_OPENSSL
- if (pendingSslConfiguration)
- httpReply->setSslConfiguration(*pendingSslConfiguration);
- if (pendingIgnoreAllSslErrors)
- httpReply->ignoreSslErrors();
- httpReply->ignoreSslErrors(pendingIgnoreSslErrorsList);
- connect(httpReply, SIGNAL(sslErrors(QList<QSslError>)),
- SLOT(sslErrors(QList<QSslError>)));
+ if (ssl)
+ delegate->incomingSslConfiguration = request().sslConfiguration();
#endif
- connect(httpReply, SIGNAL(finished()), SLOT(replyFinished()));
- connect(httpReply, SIGNAL(finishedWithError(QNetworkReply::NetworkError,QString)),
- SLOT(httpError(QNetworkReply::NetworkError,QString)));
- connect(httpReply, SIGNAL(headerChanged()), SLOT(replyHeaderChanged()));
- connect(httpReply, SIGNAL(cacheCredentials(QHttpNetworkRequest,QAuthenticator*)),
- SLOT(httpCacheCredentials(QHttpNetworkRequest,QAuthenticator*)));
+ // Do we use synchronous HTTP?
+ delegate->synchronous = isSynchronous();
+
+ // The authentication manager is used to avoid the BlockingQueuedConnection communication
+ // from HTTP thread to user thread in some cases.
+ delegate->authenticationManager = manager->authenticationManager;
+
+ if (!isSynchronous()) {
+ // Tell our zerocopy policy to the delegate
+ delegate->downloadBufferMaximumSize =
+ request().attribute(QNetworkRequest::MaximumDownloadBufferSizeAttribute).toLongLong();
+
+ // These atomic integers are used for signal compression
+ delegate->pendingDownloadData = pendingDownloadDataEmissions;
+ delegate->pendingDownloadProgress = pendingDownloadProgressEmissions;
+
+ // Connect the signals of the delegate to us
+ connect(delegate, SIGNAL(downloadData(QByteArray)),
+ this, SLOT(replyDownloadData(QByteArray)),
+ Qt::QueuedConnection);
+ connect(delegate, SIGNAL(downloadFinished()),
+ this, SLOT(replyFinished()),
+ Qt::QueuedConnection);
+ connect(delegate, SIGNAL(downloadMetaData(QList<QPair<QByteArray,QByteArray> >,int,QString,bool,QSharedPointer<char>,qint64)),
+ this, SLOT(replyDownloadMetaData(QList<QPair<QByteArray,QByteArray> >,int,QString,bool,QSharedPointer<char>,qint64)),
+ Qt::QueuedConnection);
+ connect(delegate, SIGNAL(downloadProgress(qint64,qint64)),
+ this, SLOT(replyDownloadProgressSlot(qint64,qint64)),
+ Qt::QueuedConnection);
+ connect(delegate, SIGNAL(error(QNetworkReply::NetworkError,QString)),
+ this, SLOT(httpError(QNetworkReply::NetworkError, const QString)),
+ Qt::QueuedConnection);
+#ifndef QT_NO_OPENSSL
+ connect(delegate, SIGNAL(sslConfigurationChanged(QSslConfiguration)),
+ this, SLOT(replySslConfigurationChanged(QSslConfiguration)),
+ Qt::QueuedConnection);
+#endif
+ // Those need to report back, therefire BlockingQueuedConnection
+ connect(delegate, SIGNAL(authenticationRequired(QHttpNetworkRequest,QAuthenticator*)),
+ this, SLOT(httpAuthenticationRequired(QHttpNetworkRequest,QAuthenticator*)),
+ Qt::BlockingQueuedConnection);
#ifndef QT_NO_NETWORKPROXY
- connect(httpReply, SIGNAL(proxyAuthenticationRequired(QNetworkProxy,QAuthenticator*)),
- SLOT(proxyAuthenticationRequired(QNetworkProxy,QAuthenticator*)));
+ connect (delegate, SIGNAL(proxyAuthenticationRequired(QNetworkProxy,QAuthenticator*)),
+ this, SLOT(proxyAuthenticationRequired(QNetworkProxy,QAuthenticator*)),
+ Qt::BlockingQueuedConnection);
+#endif
+#ifndef QT_NO_OPENSSL
+ connect(delegate, SIGNAL(sslErrors(QList<QSslError>,bool*,QList<QSslError>*)),
+ this, SLOT(replySslErrors(const QList<QSslError> &, bool *, QList<QSslError> *)),
+ Qt::BlockingQueuedConnection);
#endif
- connect(httpReply, SIGNAL(authenticationRequired(const QHttpNetworkRequest,QAuthenticator*)),
- SLOT(httpAuthenticationRequired(const QHttpNetworkRequest,QAuthenticator*)));
+ // This signal we will use to start the request.
+ connect(this, SIGNAL(startHttpRequest()), delegate, SLOT(startRequest()));
+ connect(this, SIGNAL(abortHttpRequest()), delegate, SLOT(abortRequest()));
+
+ if (uploadByteDevice) {
+ QNonContiguousByteDeviceThreadForwardImpl *forwardUploadDevice =
+ new QNonContiguousByteDeviceThreadForwardImpl(uploadByteDevice->atEnd(), uploadByteDevice->size());
+ if (uploadByteDevice->isResetDisabled())
+ forwardUploadDevice->disableReset();
+ forwardUploadDevice->setParent(delegate); // needed to make sure it is moved on moveToThread()
+ delegate->httpRequest.setUploadByteDevice(forwardUploadDevice);
+
+ // From main thread to user thread:
+ QObject::connect(this, SIGNAL(haveUploadData(QByteArray, bool, qint64)),
+ forwardUploadDevice, SLOT(haveDataSlot(QByteArray, bool, qint64)), Qt::QueuedConnection);
+ QObject::connect(uploadByteDevice.data(), SIGNAL(readyRead()),
+ forwardUploadDevice, SIGNAL(readyRead()),
+ Qt::QueuedConnection);
+
+ // From http thread to user thread:
+ QObject::connect(forwardUploadDevice, SIGNAL(wantData(qint64)),
+ this, SLOT(wantUploadDataSlot(qint64)));
+ QObject::connect(forwardUploadDevice, SIGNAL(processedData(qint64)),
+ this, SLOT(sentUploadDataSlot(qint64)));
+ connect(forwardUploadDevice, SIGNAL(resetData(bool*)),
+ this, SLOT(resetUploadDataSlot(bool*)),
+ Qt::BlockingQueuedConnection); // this is the only one with BlockingQueued!
+ }
+ } else if (isSynchronous()) {
+ connect(this, SIGNAL(startHttpRequestSynchronously()), delegate, SLOT(startRequestSynchronously()), Qt::BlockingQueuedConnection);
+
+ if (uploadByteDevice) {
+ // For the synchronous HTTP use case the use thread (this one here) is blocked
+ // so we cannot use the asynchronous upload architecture.
+ // We therefore won't use the QNonContiguousByteDeviceThreadForwardImpl but directly
+ // use the uploadByteDevice provided to us by the QNetworkReplyImpl.
+ // The code that is in QNetworkReplyImplPrivate::setup() makes sure it is safe to use from a thread
+ // since it only wraps a QRingBuffer
+ delegate->httpRequest.setUploadByteDevice(uploadByteDevice.data());
+ }
+ }
+
+
+ // Move the delegate to the http thread
+ delegate->moveToThread(thread);
+ // This call automatically moves the uploadDevice too for the asynchronous case.
+
+ // Send an signal to the delegate so it starts working in the other thread
+ if (isSynchronous()) {
+ emit startHttpRequestSynchronously(); // This one is BlockingQueuedConnection, so it will return when all work is done
+
+ if (delegate->incomingErrorCode != QNetworkReply::NoError) {
+ replyDownloadMetaData
+ (delegate->incomingHeaders,
+ delegate->incomingStatusCode,
+ delegate->incomingReasonPhrase,
+ delegate->isPipeliningUsed,
+ QSharedPointer<char>(),
+ delegate->incomingContentLength);
+ httpError(delegate->incomingErrorCode, delegate->incomingErrorDetail);
+ } else {
+ replyDownloadMetaData
+ (delegate->incomingHeaders,
+ delegate->incomingStatusCode,
+ delegate->incomingReasonPhrase,
+ delegate->isPipeliningUsed,
+ QSharedPointer<char>(),
+ delegate->incomingContentLength);
+ replyDownloadData(delegate->synchronousDownloadData);
+ }
+
+ // End the thread. It will delete itself from the finished() signal
+ thread->quit();
+
+ finished();
+ } else {
+ emit startHttpRequest(); // Signal to the HTTP thread and go back to user.
+ }
}
void QNetworkAccessHttpBackend::invalidateCache()
@@ -611,159 +681,52 @@ void QNetworkAccessHttpBackend::invalidateCache()
void QNetworkAccessHttpBackend::open()
{
- QUrl url = request().url();
- bool encrypt = url.scheme().toLower() == QLatin1String("https");
- setAttribute(QNetworkRequest::ConnectionEncryptedAttribute, encrypt);
-
- // set the port number in the reply if it wasn't set
- url.setPort(url.port(encrypt ? DefaultHttpsPort : DefaultHttpPort));
-
- QNetworkProxy *theProxy = 0;
-#ifndef QT_NO_NETWORKPROXY
- QNetworkProxy transparentProxy, cacheProxy;
-
- foreach (const QNetworkProxy &p, proxyList()) {
- // use the first proxy that works
- // for non-encrypted connections, any transparent or HTTP proxy
- // for encrypted, only transparent proxies
- if (!encrypt
- && (p.capabilities() & QNetworkProxy::CachingCapability)
- && (p.type() == QNetworkProxy::HttpProxy ||
- p.type() == QNetworkProxy::HttpCachingProxy)) {
- cacheProxy = p;
- transparentProxy = QNetworkProxy::NoProxy;
- theProxy = &cacheProxy;
- break;
- }
- if (p.isTransparentProxy()) {
- transparentProxy = p;
- cacheProxy = QNetworkProxy::NoProxy;
- theProxy = &transparentProxy;
- break;
- }
- }
-
- // check if at least one of the proxies
- if (transparentProxy.type() == QNetworkProxy::DefaultProxy &&
- cacheProxy.type() == QNetworkProxy::DefaultProxy) {
- // unsuitable proxies
- if (isSynchronous()) {
- error(QNetworkReply::ProxyNotFoundError, tr("No suitable proxy found"));
- finished();
- } else {
- QMetaObject::invokeMethod(this, "error", Qt::QueuedConnection,
- Q_ARG(QNetworkReply::NetworkError, QNetworkReply::ProxyNotFoundError),
- Q_ARG(QString, tr("No suitable proxy found")));
- QMetaObject::invokeMethod(this, "finished", Qt::QueuedConnection);
- }
- return;
- }
-#endif
-
- if (isSynchronous()) {
- // for synchronous requests, we just create a new connection
- http = new QHttpNetworkConnection(1, url.host(), url.port(), encrypt, this);
-#ifndef QT_NO_NETWORKPROXY
- http->setTransparentProxy(transparentProxy);
- http->setCacheProxy(cacheProxy);
-#endif
- postRequest();
- processRequestSynchronously();
- } else {
- // check if we have an open connection to this host
- cacheKey = makeCacheKey(this, theProxy);
- QNetworkAccessCache *cache = QNetworkAccessManagerPrivate::getObjectCache(this);
- // the http object is actually a QHttpNetworkConnection
- http = static_cast<QNetworkAccessCachedHttpConnection *>(cache->requestEntryNow(cacheKey));
- if (http == 0) {
- // no entry in cache; create an object
- // the http object is actually a QHttpNetworkConnection
- http = new QNetworkAccessCachedHttpConnection(url.host(), url.port(), encrypt);
-
-#ifndef QT_NO_NETWORKPROXY
- http->setTransparentProxy(transparentProxy);
- http->setCacheProxy(cacheProxy);
-#endif
-
- // cache the QHttpNetworkConnection corresponding to this cache key
- cache->addEntry(cacheKey, static_cast<QNetworkAccessCachedHttpConnection *>(http.data()));
- }
- postRequest();
- }
+ postRequest();
}
void QNetworkAccessHttpBackend::closeDownstreamChannel()
{
- // this indicates that the user closed the stream while the reply isn't finished yet
+ // FIXME Maybe we can get rid of this whole architecture part
}
void QNetworkAccessHttpBackend::downstreamReadyWrite()
{
- readFromHttp();
- if (httpReply && httpReply->bytesAvailable() == 0 && httpReply->isFinished())
- replyFinished();
+ // FIXME Maybe we can get rid of this whole architecture part
}
void QNetworkAccessHttpBackend::setDownstreamLimited(bool b)
{
- if (httpReply)
- httpReply->setDownstreamLimited(b);
+ Q_UNUSED(b);
+ // We know that readBuffer maximum size limiting is broken since quite a while.
+ // The task to fix this is QTBUG-15065
}
-void QNetworkAccessHttpBackend::replyReadyRead()
+void QNetworkAccessHttpBackend::replyDownloadData(QByteArray d)
{
- readFromHttp();
-}
-
-void QNetworkAccessHttpBackend::readFromHttp()
-{
- if (!httpReply)
+ int pendingSignals = (int)pendingDownloadDataEmissions->fetchAndAddAcquire(-1) - 1;
+
+ if (pendingSignals > 0) {
+ // Some more signal emissions to this slot are pending.
+ // Instead of writing the downstream data, we wait
+ // and do it in the next call we get
+ // (signal comppression)
+ pendingDownloadData.append(d);
return;
-
- // We read possibly more than nextDownstreamBlockSize(), but
- // this is not a critical thing since it is already in the
- // memory anyway
-
- QByteDataBuffer list;
-
- while (httpReply->bytesAvailable() != 0 && nextDownstreamBlockSize() != 0 && nextDownstreamBlockSize() > list.byteAmount()) {
- list.append(httpReply->readAny());
}
- if (!list.isEmpty())
- writeDownstreamData(list);
+ pendingDownloadData.append(d);
+ d.clear();
+ writeDownstreamData(pendingDownloadData);
+ pendingDownloadData.clear();
}
void QNetworkAccessHttpBackend::replyFinished()
{
- if (httpReply->bytesAvailable())
- // we haven't read everything yet. Wait some more.
+ // We are already loading from cache, we still however
+ // got this signal because it was posted already
+ if (loadingFromCache)
return;
- int statusCode = httpReply->statusCode();
- if (statusCode >= 400) {
- // it's an error reply
- QString msg = QLatin1String(QT_TRANSLATE_NOOP("QNetworkReply",
- "Error downloading %1 - server replied: %2"));
- msg = msg.arg(url().toString(), httpReply->reasonPhrase());
- error(statusCodeFromHttp(httpReply->statusCode(), httpReply->url()), msg);
- }
-
-#ifndef QT_NO_OPENSSL
- // store the SSL configuration now
- // once we call finished(), we won't have access to httpReply anymore
- QSslConfiguration sslConfig = httpReply->sslConfiguration();
- if (pendingSslConfiguration) {
- *pendingSslConfiguration = sslConfig;
- } else if (!sslConfig.isNull()) {
- QT_TRY {
- pendingSslConfiguration = new QSslConfiguration(sslConfig);
- } QT_CATCH(...) {
- qWarning("QNetworkAccess: could not allocate a QSslConfiguration object for a SSL connection.");
- }
- }
-#endif
-
finished();
}
@@ -785,12 +748,27 @@ void QNetworkAccessHttpBackend::checkForRedirect(const int statusCode)
}
}
-void QNetworkAccessHttpBackend::replyHeaderChanged()
+void QNetworkAccessHttpBackend::replyDownloadMetaData
+ (QList<QPair<QByteArray,QByteArray> > hm,
+ int sc,QString rp,bool pu,
+ QSharedPointer<char> db,
+ qint64 contentLength)
{
- setAttribute(QNetworkRequest::HttpPipeliningWasUsedAttribute, httpReply->isPipeliningUsed());
+ statusCode = sc;
+ reasonPhrase = rp;
+
+ // Download buffer
+ if (!db.isNull()) {
+ reply->setDownloadBuffer(db, contentLength);
+ usingZerocopyDownloadBuffer = true;
+ } else {
+ usingZerocopyDownloadBuffer = false;
+ }
+
+ setAttribute(QNetworkRequest::HttpPipeliningWasUsedAttribute, pu);
// reconstruct the HTTP header
- QList<QPair<QByteArray, QByteArray> > headerMap = httpReply->header();
+ QList<QPair<QByteArray, QByteArray> > headerMap = hm;
QList<QPair<QByteArray, QByteArray> >::ConstIterator it = headerMap.constBegin(),
end = headerMap.constEnd();
QByteArray header;
@@ -807,11 +785,10 @@ void QNetworkAccessHttpBackend::replyHeaderChanged()
setRawHeader(it->first, value);
}
- setAttribute(QNetworkRequest::HttpStatusCodeAttribute, httpReply->statusCode());
- setAttribute(QNetworkRequest::HttpReasonPhraseAttribute, httpReply->reasonPhrase());
+ setAttribute(QNetworkRequest::HttpStatusCodeAttribute, statusCode);
+ setAttribute(QNetworkRequest::HttpReasonPhraseAttribute, reasonPhrase);
// is it a redirection?
- const int statusCode = httpReply->statusCode();
checkForRedirect(statusCode);
if (statusCode >= 500 && statusCode < 600) {
@@ -854,29 +831,21 @@ void QNetworkAccessHttpBackend::replyHeaderChanged()
setCachingEnabled(true);
}
- // Check if a download buffer is supported from the HTTP reply
- char *buf = 0;
- if (httpReply->supportsUserProvidedDownloadBuffer()) {
- // Check if a download buffer is supported by the user
- buf = getDownloadBuffer(httpReply->contentLength());
- if (buf) {
- httpReply->setUserProvidedDownloadBuffer(buf);
- // If there is a download buffer we react on the progress signal
- connect(httpReply, SIGNAL(dataReadProgress(int,int)), SLOT(replyDownloadProgressSlot(int,int)));
- }
- }
-
- // If there is no buffer, we react on the readyRead signal
- if (!buf) {
- connect(httpReply, SIGNAL(readyRead()), SLOT(replyReadyRead()));
- }
-
metaDataChanged();
}
-void QNetworkAccessHttpBackend::replyDownloadProgressSlot(int received, int total)
+void QNetworkAccessHttpBackend::replyDownloadProgressSlot(qint64 received, qint64 total)
{
// we can be sure here that there is a download buffer
+
+ int pendingSignals = (int)pendingDownloadProgressEmissions->fetchAndAddAcquire(-1) - 1;
+ if (pendingSignals > 0) {
+ // Let's ignore this signal and look at the next one coming in
+ // (signal comppression)
+ return;
+ }
+
+ // Now do the actual notification of new bytes
writeDownstreamDataDownloadBuffer(received, total);
}
@@ -886,20 +855,62 @@ void QNetworkAccessHttpBackend::httpAuthenticationRequired(const QHttpNetworkReq
authenticationRequired(auth);
}
-void QNetworkAccessHttpBackend::httpCacheCredentials(const QHttpNetworkRequest &,
- QAuthenticator *auth)
-{
- cacheCredentials(auth);
-}
-
void QNetworkAccessHttpBackend::httpError(QNetworkReply::NetworkError errorCode,
const QString &errorString)
{
#if defined(QNETWORKACCESSHTTPBACKEND_DEBUG)
qDebug() << "http error!" << errorCode << errorString;
#endif
+
error(errorCode, errorString);
- finished();
+}
+
+#ifndef QT_NO_OPENSSL
+void QNetworkAccessHttpBackend::replySslErrors(
+ const QList<QSslError> &list, bool *ignoreAll, QList<QSslError> *toBeIgnored)
+{
+ // Go to generic backend
+ sslErrors(list);
+ // Check if the callback set any ignore and return this here to http thread
+ if (pendingIgnoreAllSslErrors)
+ *ignoreAll = true;
+ if (!pendingIgnoreSslErrorsList.isEmpty())
+ *toBeIgnored = pendingIgnoreSslErrorsList;
+}
+
+void QNetworkAccessHttpBackend::replySslConfigurationChanged(const QSslConfiguration &c)
+{
+ // Receiving the used SSL configuration from the HTTP thread
+ if (pendingSslConfiguration)
+ *pendingSslConfiguration = c;
+ else if (!c.isNull())
+ pendingSslConfiguration = new QSslConfiguration(c);
+}
+#endif
+
+// Coming from QNonContiguousByteDeviceThreadForwardImpl in HTTP thread
+void QNetworkAccessHttpBackend::resetUploadDataSlot(bool *r)
+{
+ *r = uploadByteDevice->reset();
+}
+
+// Coming from QNonContiguousByteDeviceThreadForwardImpl in HTTP thread
+void QNetworkAccessHttpBackend::sentUploadDataSlot(qint64 amount)
+{
+ uploadByteDevice->advanceReadPointer(amount);
+}
+
+// Coming from QNonContiguousByteDeviceThreadForwardImpl in HTTP thread
+void QNetworkAccessHttpBackend::wantUploadDataSlot(qint64 maxSize)
+{
+ // call readPointer
+ qint64 currentUploadDataLength = 0;
+ char *data = const_cast<char*>(uploadByteDevice->readPointer(maxSize, currentUploadDataLength));
+ // Let's make a copy of this data
+ QByteArray dataArray(data, currentUploadDataLength);
+
+ // Communicate back to HTTP thread
+ emit haveUploadData(dataArray, uploadByteDevice->atEnd(), uploadByteDevice->size());
}
/*
@@ -950,8 +961,10 @@ bool QNetworkAccessHttpBackend::sendCacheContents(const QNetworkCacheMetaData &m
#if defined(QNETWORKACCESSHTTPBACKEND_DEBUG)
qDebug() << "Successfully sent cache:" << url() << contents->size() << "bytes";
#endif
- if (httpReply)
- disconnect(httpReply, SIGNAL(finished()), this, SLOT(replyFinished()));
+
+ // Set the following flag so we can ignore some signals from HTTP thread
+ // that would still come
+ loadingFromCache = true;
return true;
}
@@ -964,39 +977,29 @@ void QNetworkAccessHttpBackend::copyFinished(QIODevice *dev)
#ifndef QT_NO_OPENSSL
void QNetworkAccessHttpBackend::ignoreSslErrors()
{
- if (httpReply)
- httpReply->ignoreSslErrors();
- else
- pendingIgnoreAllSslErrors = true;
+ pendingIgnoreAllSslErrors = true;
}
void QNetworkAccessHttpBackend::ignoreSslErrors(const QList<QSslError> &errors)
{
- if (httpReply) {
- httpReply->ignoreSslErrors(errors);
- } else {
- // the pending list is set if QNetworkReply::ignoreSslErrors(const QList<QSslError> &errors)
- // is called before QNetworkAccessManager::get() (or post(), etc.)
- pendingIgnoreSslErrorsList = errors;
- }
+ // the pending list is set if QNetworkReply::ignoreSslErrors(const QList<QSslError> &errors)
+ // is called before QNetworkAccessManager::get() (or post(), etc.)
+ pendingIgnoreSslErrorsList = errors;
}
void QNetworkAccessHttpBackend::fetchSslConfiguration(QSslConfiguration &config) const
{
- if (httpReply)
- config = httpReply->sslConfiguration();
- else if (pendingSslConfiguration)
+ if (pendingSslConfiguration)
config = *pendingSslConfiguration;
+ else
+ config = request().sslConfiguration();
}
void QNetworkAccessHttpBackend::setSslConfiguration(const QSslConfiguration &newconfig)
{
- if (httpReply)
- httpReply->setSslConfiguration(newconfig);
- else if (pendingSslConfiguration)
- *pendingSslConfiguration = newconfig;
- else
- pendingSslConfiguration = new QSslConfiguration(newconfig);
+ // Setting a SSL configuration on a reply is not supported. The user needs to set
+ // her/his QSslConfiguration on the QNetworkRequest.
+ Q_UNUSED(newconfig);
}
#endif
@@ -1101,7 +1104,7 @@ QNetworkCacheMetaData QNetworkAccessHttpBackend::fetchCacheMetaData(const QNetwo
bool canDiskCache;
// only cache GET replies by default, all other replies (POST, PUT, DELETE)
// are not cacheable by default (according to RFC 2616 section 9)
- if (httpReply->request().operation() == QHttpNetworkRequest::Get) {
+ if (httpRequest.operation() == QHttpNetworkRequest::Get) {
canDiskCache = true;
// 14.32
@@ -1119,7 +1122,7 @@ QNetworkCacheMetaData QNetworkAccessHttpBackend::fetchCacheMetaData(const QNetwo
canDiskCache = false;
// responses to POST might be cacheable
- } else if (httpReply->request().operation() == QHttpNetworkRequest::Post) {
+ } else if (httpRequest.operation() == QHttpNetworkRequest::Post) {
canDiskCache = false;
// some pages contain "expires:" and "cache-control: no-cache" field,
@@ -1133,12 +1136,11 @@ QNetworkCacheMetaData QNetworkAccessHttpBackend::fetchCacheMetaData(const QNetwo
}
metaData.setSaveToDisk(canDiskCache);
- int statusCode = httpReply->statusCode();
QNetworkCacheMetaData::AttributesMap attributes;
if (statusCode != 304) {
// update the status code
attributes.insert(QNetworkRequest::HttpStatusCodeAttribute, statusCode);
- attributes.insert(QNetworkRequest::HttpReasonPhraseAttribute, httpReply->reasonPhrase());
+ attributes.insert(QNetworkRequest::HttpReasonPhraseAttribute, reasonPhrase);
} else {
// this is a redirection, keep the attributes intact
attributes = oldMetaData.attributes();
@@ -1154,7 +1156,8 @@ bool QNetworkAccessHttpBackend::canResume() const
return false;
// Can only resume if server/resource supports Range header.
- if (httpReply->headerField("Accept-Ranges", "none") == "none")
+ QByteArray acceptRangesheaderName("Accept-Ranges");
+ if (!hasRawHeader(acceptRangesheaderName) || rawHeader(acceptRangesheaderName) == "none")
return false;
// We only support resuming for byte ranges.
@@ -1166,7 +1169,7 @@ bool QNetworkAccessHttpBackend::canResume() const
// If we're using a download buffer then we don't support resuming/migration
// right now. Too much trouble.
- if (httpReply->userProvidedDownloadBuffer())
+ if (usingZerocopyDownloadBuffer)
return false;
return true;
@@ -1177,87 +1180,6 @@ void QNetworkAccessHttpBackend::setResumeOffset(quint64 offset)
resumeOffset = offset;
}
-bool QNetworkAccessHttpBackend::processRequestSynchronously()
-{
- QHttpNetworkConnectionChannel *channel = &http->channels()[0];
-
- // Disconnect all socket signals. They will only confuse us when using waitFor*
- QObject::disconnect(channel->socket, 0, 0, 0);
-
- qint64 timeout = 20*1000; // 20 sec
- QElapsedTimer timeoutTimer;
-
- bool waitResult = channel->socket->waitForConnected(timeout);
- timeoutTimer.start();
-
- if (!waitResult || channel->socket->state() != QAbstractSocket::ConnectedState) {
- error(QNetworkReply::UnknownNetworkError, QLatin1String("could not connect"));
- return false;
- }
- channel->_q_connected(); // this will send the request (via sendRequest())
-
-#ifndef QT_NO_OPENSSL
- if (http->isSsl()) {
- qint64 remainingTimeEncrypted = timeout - timeoutTimer.elapsed();
- if (!static_cast<QSslSocket *>(channel->socket)->waitForEncrypted(remainingTimeEncrypted)) {
- error(QNetworkReply::SslHandshakeFailedError,
- QLatin1String("could not encrypt or timeout while encrypting"));
- return false;
- }
- channel->_q_encrypted();
- }
-#endif
-
- // if we get a 401 or 407, we might need to send the request twice, see below
- bool authenticating = false;
-
- do {
- channel->sendRequest();
-
- qint64 remainingTimeBytesWritten;
- while(channel->socket->bytesToWrite() > 0 ||
- channel->state == QHttpNetworkConnectionChannel::WritingState) {
- remainingTimeBytesWritten = timeout - timeoutTimer.elapsed();
- channel->sendRequest(); // triggers channel->socket->write()
- if (!channel->socket->waitForBytesWritten(remainingTimeBytesWritten)) {
- error(QNetworkReply::TimeoutError,
- QLatin1String("could not write bytes to socket or timeout while writing"));
- return false;
- }
- }
-
- qint64 remainingTimeBytesRead = timeout - timeoutTimer.elapsed();
- // Loop for at most remainingTime until either the socket disconnects
- // or the reply is finished
- do {
- waitResult = channel->socket->waitForReadyRead(remainingTimeBytesRead);
- remainingTimeBytesRead = timeout - timeoutTimer.elapsed();
- if (!waitResult || remainingTimeBytesRead <= 0
- || channel->socket->state() != QAbstractSocket::ConnectedState) {
- error(QNetworkReply::TimeoutError,
- QLatin1String("could not read from socket or timeout while reading"));
- return false;
- }
-
- if (channel->socket->bytesAvailable())
- channel->_q_readyRead();
-
- if (!httpReply)
- return false; // we got a 401 or 407 and cannot handle it (it might happen that
- // disconnectFromHttp() was called, in that case the reply is zero)
- // ### I am quite sure this does not work for NTLM
- // ### how about uploading to an auth / proxyAuth site?
-
- authenticating = (httpReply->statusCode() == 401 || httpReply->statusCode() == 407);
-
- if (httpReply->isFinished())
- break;
- } while (remainingTimeBytesRead > 0);
- } while (authenticating);
-
- return true;
-}
-
QT_END_NAMESPACE
#endif // QT_NO_HTTP
diff --git a/src/network/access/qnetworkaccesshttpbackend_p.h b/src/network/access/qnetworkaccesshttpbackend_p.h
index 7064d4a..712dd2f 100644
--- a/src/network/access/qnetworkaccesshttpbackend_p.h
+++ b/src/network/access/qnetworkaccesshttpbackend_p.h
@@ -61,6 +61,8 @@
#include "QtCore/qpointer.h"
#include "QtCore/qdatetime.h"
+#include "QtCore/qsharedpointer.h"
+#include "qatomic.h"
#ifndef QT_NO_HTTP
@@ -99,24 +101,44 @@ public:
bool canResume() const;
void setResumeOffset(quint64 offset);
- virtual bool processRequestSynchronously();
+signals:
+ // To HTTP thread:
+ void startHttpRequest();
+ void abortHttpRequest();
+ void startHttpRequestSynchronously();
+
+ void haveUploadData(QByteArray dataArray, bool dataAtEnd, qint64 dataSize);
private slots:
- void replyReadyRead();
+ // From HTTP thread:
+ void replyDownloadData(QByteArray);
void replyFinished();
- void replyHeaderChanged();
- void replyDownloadProgressSlot(int,int);
+ void replyDownloadMetaData(QList<QPair<QByteArray,QByteArray> >,int,QString,bool,QSharedPointer<char>,qint64);
+ void replyDownloadProgressSlot(qint64,qint64);
void httpAuthenticationRequired(const QHttpNetworkRequest &request, QAuthenticator *auth);
- void httpCacheCredentials(const QHttpNetworkRequest &request, QAuthenticator *auth);
void httpError(QNetworkReply::NetworkError error, const QString &errorString);
+#ifndef QT_NO_OPENSSL
+ void replySslErrors(const QList<QSslError> &, bool *, QList<QSslError> *);
+ void replySslConfigurationChanged(const QSslConfiguration&);
+#endif
+
+ // From QNonContiguousByteDeviceThreadForwardImpl in HTTP thread:
+ void resetUploadDataSlot(bool *r);
+ void wantUploadDataSlot(qint64);
+ void sentUploadDataSlot(qint64);
+
bool sendCacheContents(const QNetworkCacheMetaData &metaData);
- void finished(); // override
private:
- QHttpNetworkReply *httpReply;
- QPointer<QHttpNetworkConnection> http;
- QByteArray cacheKey;
- QNetworkAccessBackendUploadIODevice *uploadDevice;
+ QHttpNetworkRequest httpRequest; // There is also a copy in the HTTP thread
+ int statusCode;
+ QString reasonPhrase;
+ // Will be increased by HTTP thread:
+ QSharedPointer<QAtomicInt> pendingDownloadDataEmissions;
+ QSharedPointer<QAtomicInt> pendingDownloadProgressEmissions;
+ bool loadingFromCache;
+ QByteDataBuffer pendingDownloadData;
+ bool usingZerocopyDownloadBuffer;
#ifndef QT_NO_OPENSSL
QSslConfiguration *pendingSslConfiguration;
@@ -126,7 +148,6 @@ private:
quint64 resumeOffset;
- void disconnectFromHttp();
void validateCache(QHttpNetworkRequest &httpRequest, bool &loadedFromCache);
void invalidateCache();
void postRequest();
diff --git a/src/network/access/qnetworkaccessmanager.cpp b/src/network/access/qnetworkaccessmanager.cpp
index 27b7945..7e75045 100644
--- a/src/network/access/qnetworkaccessmanager.cpp
+++ b/src/network/access/qnetworkaccessmanager.cpp
@@ -48,6 +48,7 @@
#include "qabstractnetworkcache.h"
#include "QtNetwork/qnetworksession.h"
+#include "QtNetwork/private/qsharednetworksession_p.h"
#include "qnetworkaccesshttpbackend_p.h"
#include "qnetworkaccessftpbackend_p.h"
@@ -64,6 +65,8 @@
#include "QtNetwork/qsslconfiguration.h"
#include "QtNetwork/qnetworkconfigmanager.h"
+#include "qthread.h"
+
QT_BEGIN_NAMESPACE
#ifndef QT_NO_HTTP
@@ -340,107 +343,6 @@ static void ensureInitialized()
QNetworkReply::sslConfiguration(), QNetworkReply::ignoreSslErrors()
*/
-class QNetworkAuthenticationCredential
-{
-public:
- QString domain;
- QString user;
- QString password;
-};
-Q_DECLARE_TYPEINFO(QNetworkAuthenticationCredential, Q_MOVABLE_TYPE);
-inline bool operator<(const QNetworkAuthenticationCredential &t1, const QString &t2)
-{ return t1.domain < t2; }
-
-class QNetworkAuthenticationCache: private QVector<QNetworkAuthenticationCredential>,
- public QNetworkAccessCache::CacheableObject
-{
-public:
- QNetworkAuthenticationCache()
- {
- setExpires(false);
- setShareable(true);
- reserve(1);
- }
-
- QNetworkAuthenticationCredential *findClosestMatch(const QString &domain)
- {
- iterator it = qLowerBound(begin(), end(), domain);
- if (it == end() && !isEmpty())
- --it;
- if (it == end() || !domain.startsWith(it->domain))
- return 0;
- return &*it;
- }
-
- void insert(const QString &domain, const QString &user, const QString &password)
- {
- QNetworkAuthenticationCredential *closestMatch = findClosestMatch(domain);
- if (closestMatch && closestMatch->domain == domain) {
- // we're overriding the current credentials
- closestMatch->user = user;
- closestMatch->password = password;
- } else {
- QNetworkAuthenticationCredential newCredential;
- newCredential.domain = domain;
- newCredential.user = user;
- newCredential.password = password;
-
- if (closestMatch)
- QVector<QNetworkAuthenticationCredential>::insert(++closestMatch, newCredential);
- else
- QVector<QNetworkAuthenticationCredential>::insert(end(), newCredential);
- }
- }
-
- virtual void dispose() { delete this; }
-};
-
-#ifndef QT_NO_NETWORKPROXY
-static QByteArray proxyAuthenticationKey(const QNetworkProxy &proxy, const QString &realm)
-{
- QUrl key;
-
- switch (proxy.type()) {
- case QNetworkProxy::Socks5Proxy:
- key.setScheme(QLatin1String("proxy-socks5"));
- break;
-
- case QNetworkProxy::HttpProxy:
- case QNetworkProxy::HttpCachingProxy:
- key.setScheme(QLatin1String("proxy-http"));
- break;
-
- case QNetworkProxy::FtpCachingProxy:
- key.setScheme(QLatin1String("proxy-ftp"));
- break;
-
- case QNetworkProxy::DefaultProxy:
- case QNetworkProxy::NoProxy:
- // shouldn't happen
- return QByteArray();
-
- // no default:
- // let there be errors if a new proxy type is added in the future
- }
-
- if (key.scheme().isEmpty())
- // proxy type not handled
- return QByteArray();
-
- key.setUserName(proxy.user());
- key.setHost(proxy.hostName());
- key.setPort(proxy.port());
- key.setFragment(realm);
- return "auth:" + key.toEncoded();
-}
-#endif
-
-static inline QByteArray authenticationKey(const QUrl &url, const QString &realm)
-{
- QUrl copy = url;
- copy.setFragment(realm);
- return "auth:" + copy.toEncoded(QUrl::RemovePassword | QUrl::RemovePath | QUrl::RemoveQuery);
-}
/*!
Constructs a QNetworkAccessManager object that is the center of
@@ -1123,10 +1025,10 @@ void QNetworkAccessManagerPrivate::authenticationRequired(QNetworkAccessBackend
// also called when last URL is empty, e.g. on first call
if (backend->reply->urlForLastAuthentication.isEmpty()
|| url != backend->reply->urlForLastAuthentication) {
- QNetworkAuthenticationCredential *cred = fetchCachedCredentials(url, authenticator);
- if (cred) {
- authenticator->setUser(cred->user);
- authenticator->setPassword(cred->password);
+ QNetworkAuthenticationCredential cred = authenticationManager->fetchCachedCredentials(url, authenticator);
+ if (!cred.isNull()) {
+ authenticator->setUser(cred.user);
+ authenticator->setPassword(cred.password);
backend->reply->urlForLastAuthentication = url;
return;
}
@@ -1139,7 +1041,7 @@ void QNetworkAccessManagerPrivate::authenticationRequired(QNetworkAccessBackend
backend->reply->urlForLastAuthentication = url;
emit q->authenticationRequired(backend->reply->q_func(), authenticator);
- cacheCredentials(url, authenticator);
+ authenticationManager->cacheCredentials(url, authenticator);
}
#ifndef QT_NO_NETWORKPROXY
@@ -1156,10 +1058,10 @@ void QNetworkAccessManagerPrivate::proxyAuthenticationRequired(QNetworkAccessBac
// possible solution: some tracking inside the authenticator
// or a new function proxyAuthenticationSucceeded(true|false)
if (proxy != backend->reply->lastProxyAuthentication) {
- QNetworkAuthenticationCredential *cred = fetchCachedProxyCredentials(proxy);
- if (cred) {
- authenticator->setUser(cred->user);
- authenticator->setPassword(cred->password);
+ QNetworkAuthenticationCredential cred = authenticationManager->fetchCachedProxyCredentials(proxy);
+ if (!cred.isNull()) {
+ authenticator->setUser(cred.user);
+ authenticator->setPassword(cred.password);
return;
}
}
@@ -1171,75 +1073,7 @@ void QNetworkAccessManagerPrivate::proxyAuthenticationRequired(QNetworkAccessBac
backend->reply->lastProxyAuthentication = proxy;
emit q->proxyAuthenticationRequired(proxy, authenticator);
- cacheProxyCredentials(proxy, authenticator);
-}
-
-void QNetworkAccessManagerPrivate::cacheProxyCredentials(const QNetworkProxy &p,
- const QAuthenticator *authenticator)
-{
- Q_ASSERT(authenticator);
- Q_ASSERT(p.type() != QNetworkProxy::DefaultProxy);
- Q_ASSERT(p.type() != QNetworkProxy::NoProxy);
-
- QString realm = authenticator->realm();
- QNetworkProxy proxy = p;
- proxy.setUser(authenticator->user());
- // Set two credentials: one with the username and one without
- do {
- // Set two credentials actually: one with and one without the realm
- do {
- QByteArray cacheKey = proxyAuthenticationKey(proxy, realm);
- if (cacheKey.isEmpty())
- return; // should not happen
-
- QNetworkAuthenticationCache *auth = new QNetworkAuthenticationCache;
- auth->insert(QString(), authenticator->user(), authenticator->password());
- objectCache.addEntry(cacheKey, auth); // replace the existing one, if there's any
-
- if (realm.isEmpty()) {
- break;
- } else {
- realm.clear();
- }
- } while (true);
-
- if (proxy.user().isEmpty())
- break;
- else
- proxy.setUser(QString());
- } while (true);
-}
-
-QNetworkAuthenticationCredential *
-QNetworkAccessManagerPrivate::fetchCachedProxyCredentials(const QNetworkProxy &p,
- const QAuthenticator *authenticator)
-{
- QNetworkProxy proxy = p;
- if (proxy.type() == QNetworkProxy::DefaultProxy) {
- proxy = QNetworkProxy::applicationProxy();
- }
- if (!proxy.password().isEmpty())
- return 0; // no need to set credentials if it already has them
-
- QString realm;
- if (authenticator)
- realm = authenticator->realm();
-
- QByteArray cacheKey = proxyAuthenticationKey(proxy, realm);
- if (cacheKey.isEmpty())
- return 0;
- if (!objectCache.hasEntry(cacheKey))
- return 0;
-
- QNetworkAuthenticationCache *auth =
- static_cast<QNetworkAuthenticationCache *>(objectCache.requestEntryNow(cacheKey));
- QNetworkAuthenticationCredential *cred = auth->findClosestMatch(QString());
- objectCache.releaseEntry(cacheKey);
-
- // proxy cache credentials always have exactly one item
- Q_ASSERT_X(cred, "QNetworkAccessManager",
- "Internal inconsistency: found a cache key for a proxy, but it's empty");
- return cred;
+ authenticationManager->cacheProxyCredentials(proxy, authenticator);
}
QList<QNetworkProxy> QNetworkAccessManagerPrivate::queryProxy(const QNetworkProxyQuery &query)
@@ -1263,77 +1097,25 @@ QList<QNetworkProxy> QNetworkAccessManagerPrivate::queryProxy(const QNetworkProx
}
#endif
-void QNetworkAccessManagerPrivate::cacheCredentials(const QUrl &url,
- const QAuthenticator *authenticator)
-{
- Q_ASSERT(authenticator);
- QString domain = QString::fromLatin1("/"); // FIXME: make QAuthenticator return the domain
- QString realm = authenticator->realm();
-
- // Set two credentials actually: one with and one without the username in the URL
- QUrl copy = url;
- copy.setUserName(authenticator->user());
- do {
- QByteArray cacheKey = authenticationKey(copy, realm);
- if (objectCache.hasEntry(cacheKey)) {
- QNetworkAuthenticationCache *auth =
- static_cast<QNetworkAuthenticationCache *>(objectCache.requestEntryNow(cacheKey));
- auth->insert(domain, authenticator->user(), authenticator->password());
- objectCache.releaseEntry(cacheKey);
- } else {
- QNetworkAuthenticationCache *auth = new QNetworkAuthenticationCache;
- auth->insert(domain, authenticator->user(), authenticator->password());
- objectCache.addEntry(cacheKey, auth);
- }
-
- if (copy.userName().isEmpty()) {
- break;
- } else {
- copy.setUserName(QString());
- }
- } while (true);
-}
-
-/*!
- Fetch the credential data from the credential cache.
-
- If auth is 0 (as it is when called from createRequest()), this will try to
- look up with an empty realm. That fails in most cases for HTTP (because the
- realm is seldom empty for HTTP challenges). In any case, QHttpNetworkConnection
- never sends the credentials on the first attempt: it needs to find out what
- authentication methods the server supports.
-
- For FTP, realm is always empty.
-*/
-QNetworkAuthenticationCredential *
-QNetworkAccessManagerPrivate::fetchCachedCredentials(const QUrl &url,
- const QAuthenticator *authentication)
-{
- if (!url.password().isEmpty())
- return 0; // no need to set credentials if it already has them
-
- QString realm;
- if (authentication)
- realm = authentication->realm();
-
- QByteArray cacheKey = authenticationKey(url, realm);
- if (!objectCache.hasEntry(cacheKey))
- return 0;
-
- QNetworkAuthenticationCache *auth =
- static_cast<QNetworkAuthenticationCache *>(objectCache.requestEntryNow(cacheKey));
- QNetworkAuthenticationCredential *cred = auth->findClosestMatch(url.path());
- objectCache.releaseEntry(cacheKey);
- return cred;
-}
-
void QNetworkAccessManagerPrivate::clearCache(QNetworkAccessManager *manager)
{
manager->d_func()->objectCache.clear();
+ manager->d_func()->authenticationManager->clearCache();
+
+ if (manager->d_func()->httpThread) {
+ // The thread will deleteLater() itself from its finished() signal
+ manager->d_func()->httpThread->quit();
+ manager->d_func()->httpThread = 0;
+ }
}
QNetworkAccessManagerPrivate::~QNetworkAccessManagerPrivate()
{
+ if (httpThread) {
+ // The thread will deleteLater() itself from its finished() signal
+ httpThread->quit();
+ httpThread = 0;
+ }
}
#ifndef QT_NO_BEARERMANAGEMENT
@@ -1343,11 +1125,8 @@ void QNetworkAccessManagerPrivate::createSession(const QNetworkConfiguration &co
initializeSession = false;
- if (networkSession)
- delete networkSession;
-
if (!config.isValid()) {
- networkSession = 0;
+ networkSession.clear();
online = false;
if (networkAccessible == QNetworkAccessManager::NotAccessible)
@@ -1358,18 +1137,13 @@ void QNetworkAccessManagerPrivate::createSession(const QNetworkConfiguration &co
return;
}
- networkSession = new QNetworkSession(config, q);
+ networkSession = QSharedNetworkSessionManager::getSession(config);
- QObject::connect(networkSession, SIGNAL(opened()), q, SIGNAL(networkSessionConnected()));
- QObject::connect(networkSession, SIGNAL(closed()), q, SLOT(_q_networkSessionClosed()));
- QObject::connect(networkSession, SIGNAL(stateChanged(QNetworkSession::State)),
- q, SLOT(_q_networkSessionStateChanged(QNetworkSession::State)));
- QObject::connect(networkSession, SIGNAL(newConfigurationActivated()),
- q, SLOT(_q_networkSessionNewConfigurationActivated()));
- QObject::connect(networkSession,
- SIGNAL(preferredConfigurationChanged(QNetworkConfiguration,bool)),
- q,
- SLOT(_q_networkSessionPreferredConfigurationChanged(QNetworkConfiguration,bool)));
+ QObject::connect(networkSession.data(), SIGNAL(opened()), q, SIGNAL(networkSessionConnected()), Qt::QueuedConnection);
+ //QueuedConnection is used to avoid deleting the networkSession inside its closed signal
+ QObject::connect(networkSession.data(), SIGNAL(closed()), q, SLOT(_q_networkSessionClosed()), Qt::QueuedConnection);
+ QObject::connect(networkSession.data(), SIGNAL(stateChanged(QNetworkSession::State)),
+ q, SLOT(_q_networkSessionStateChanged(QNetworkSession::State)), Qt::QueuedConnection);
_q_networkSessionStateChanged(networkSession->state());
}
@@ -1379,32 +1153,16 @@ void QNetworkAccessManagerPrivate::_q_networkSessionClosed()
if (networkSession) {
networkConfiguration = networkSession->configuration().identifier();
- networkSession->deleteLater();
- networkSession = 0;
+ networkSession.clear();
}
}
-void QNetworkAccessManagerPrivate::_q_networkSessionNewConfigurationActivated()
-{
- Q_Q(QNetworkAccessManager);
-
- if (networkSession) {
- networkSession->accept();
-
- emit q->networkSessionConnected();
- }
-}
-
-void QNetworkAccessManagerPrivate::_q_networkSessionPreferredConfigurationChanged(const QNetworkConfiguration &, bool)
-{
- if (networkSession)
- networkSession->migrate();
-}
-
void QNetworkAccessManagerPrivate::_q_networkSessionStateChanged(QNetworkSession::State state)
{
Q_Q(QNetworkAccessManager);
+ if (state == QNetworkSession::Connected)
+ emit q->networkSessionConnected();
if (online) {
if (state != QNetworkSession::Connected && state != QNetworkSession::Roaming) {
online = false;
diff --git a/src/network/access/qnetworkaccessmanager.h b/src/network/access/qnetworkaccessmanager.h
index f3e502c..d67b8ac 100644
--- a/src/network/access/qnetworkaccessmanager.h
+++ b/src/network/access/qnetworkaccessmanager.h
@@ -156,13 +156,13 @@ protected:
private:
friend class QNetworkReplyImplPrivate;
+ friend class QNetworkAccessHttpBackend;
+
Q_DECLARE_PRIVATE(QNetworkAccessManager)
Q_PRIVATE_SLOT(d_func(), void _q_replyFinished())
Q_PRIVATE_SLOT(d_func(), void _q_replySslErrors(QList<QSslError>))
#if !defined(QT_NO_BEARERMANAGEMENT) && !defined(QT_MOBILITY_BEARER)
Q_PRIVATE_SLOT(d_func(), void _q_networkSessionClosed())
- Q_PRIVATE_SLOT(d_func(), void _q_networkSessionNewConfigurationActivated())
- Q_PRIVATE_SLOT(d_func(), void _q_networkSessionPreferredConfigurationChanged(QNetworkConfiguration,bool))
Q_PRIVATE_SLOT(d_func(), void _q_networkSessionStateChanged(QNetworkSession::State))
#endif
};
diff --git a/src/network/access/qnetworkaccessmanager_p.h b/src/network/access/qnetworkaccessmanager_p.h
index ee16c25..ee6ad70 100644
--- a/src/network/access/qnetworkaccessmanager_p.h
+++ b/src/network/access/qnetworkaccessmanager_p.h
@@ -59,6 +59,7 @@
#include "private/qobject_p.h"
#include "QtNetwork/qnetworkproxy.h"
#include "QtNetwork/qnetworksession.h"
+#include "qnetworkaccessauthenticationmanager_p.h"
QT_BEGIN_NAMESPACE
@@ -72,6 +73,7 @@ class QNetworkAccessManagerPrivate: public QObjectPrivate
public:
QNetworkAccessManagerPrivate()
: networkCache(0), cookieJar(0),
+ httpThread(0),
#ifndef QT_NO_NETWORKPROXY
proxyFactory(0),
#endif
@@ -81,7 +83,8 @@ public:
online(false),
initializeSession(true),
#endif
- cookieJarCreated(false)
+ cookieJarCreated(false),
+ authenticationManager(new QNetworkAccessAuthenticationManager)
{ }
~QNetworkAccessManagerPrivate();
@@ -121,6 +124,8 @@ public:
QNetworkCookieJar *cookieJar;
+ QThread *httpThread;
+
#ifndef QT_NO_NETWORKPROXY
QNetworkProxy proxy;
@@ -128,7 +133,7 @@ public:
#endif
#ifndef QT_NO_BEARERMANAGEMENT
- QNetworkSession *networkSession;
+ QSharedPointer<QNetworkSession> networkSession;
QString networkConfiguration;
QNetworkAccessManager::NetworkAccessibility networkAccessible;
bool online;
@@ -137,6 +142,9 @@ public:
bool cookieJarCreated;
+ // The cache with authorization data:
+ QSharedPointer<QNetworkAccessAuthenticationManager> authenticationManager;
+
// this cache can be used by individual backends to cache e.g. their TCP connections to a server
// and use the connections for multiple requests.
QNetworkAccessCache objectCache;
diff --git a/src/network/access/qnetworkcookie.cpp b/src/network/access/qnetworkcookie.cpp
index 70ea5c2..c2a6925 100644
--- a/src/network/access/qnetworkcookie.cpp
+++ b/src/network/access/qnetworkcookie.cpp
@@ -359,7 +359,7 @@ void QNetworkCookie::setValue(const QByteArray &value)
}
// ### move this to qnetworkcookie_p.h and share with qnetworkaccesshttpbackend
-static QPair<QByteArray, QByteArray> nextField(const QByteArray &text, int &position)
+static QPair<QByteArray, QByteArray> nextField(const QByteArray &text, int &position, bool isNameValue)
{
// format is one of:
// (1) token
@@ -394,13 +394,22 @@ static QPair<QByteArray, QByteArray> nextField(const QByteArray &text, int &posi
// quoted-string = ( <"> *(qdtext | quoted-pair ) <"> )
// qdtext = <any TEXT except <">>
// quoted-pair = "\" CHAR
+
+ // If its NAME=VALUE, retain the value as is
+ // refer to ttp://bugreports.qt.nokia.com/browse/QTBUG-17746
+ if (isNameValue)
+ second += '"';
++i;
while (i < length) {
register char c = text.at(i);
if (c == '"') {
// end of quoted text
+ if (isNameValue)
+ second += '"';
break;
} else if (c == '\\') {
+ if (isNameValue)
+ second += '\\';
++i;
if (i >= length)
// broken line
@@ -476,10 +485,12 @@ QByteArray QNetworkCookie::toRawForm(RawForm form) const
result = d->name;
result += '=';
- if (d->value.contains(';') ||
+ if ((d->value.contains(';') ||
d->value.contains(',') ||
d->value.contains(' ') ||
- d->value.contains('"')) {
+ d->value.contains('"')) &&
+ (!d->value.startsWith('"') &&
+ !d->value.endsWith('"'))) {
result += '"';
QByteArray value = d->value;
@@ -947,7 +958,7 @@ QList<QNetworkCookie> QNetworkCookiePrivate::parseSetCookieHeaderLine(const QByt
QNetworkCookie cookie;
// The first part is always the "NAME=VALUE" part
- QPair<QByteArray,QByteArray> field = nextField(cookieString, position);
+ QPair<QByteArray,QByteArray> field = nextField(cookieString, position, true);
if (field.first.isEmpty() || field.second.isNull())
// parsing error
break;
@@ -965,7 +976,7 @@ QList<QNetworkCookie> QNetworkCookiePrivate::parseSetCookieHeaderLine(const QByt
case ';':
// new field in the cookie
- field = nextField(cookieString, position);
+ field = nextField(cookieString, position, false);
field.first = field.first.toLower(); // everything but the NAME=VALUE is case-insensitive
if (field.first == "expires") {
diff --git a/src/network/access/qnetworkcookiejar.cpp b/src/network/access/qnetworkcookiejar.cpp
index 65d9bf5..53fab9f 100644
--- a/src/network/access/qnetworkcookiejar.cpp
+++ b/src/network/access/qnetworkcookiejar.cpp
@@ -40,6 +40,7 @@
****************************************************************************/
#include "qnetworkcookiejar.h"
+#include "qnetworkcookiejartlds_p.h"
#include "qnetworkcookiejar_p.h"
#include "QtNetwork/qnetworkcookie.h"
@@ -157,7 +158,8 @@ static inline bool isParentDomain(QString domain, QString reference)
jar. Default values for path and domain are taken from the \a
url object.
- Returns true if one or more cookes are set for url otherwise false.
+ Returns true if one or more cookies are set for \a url,
+ otherwise false.
If a cookie already exists in the cookie jar, it will be
overridden by those in \a cookieList.
@@ -208,16 +210,14 @@ bool QNetworkCookieJar::setCookiesFromUrl(const QList<QNetworkCookie> &cookieLis
QString domain = cookie.domain();
if (!(isParentDomain(domain, defaultDomain)
- || isParentDomain(defaultDomain, domain))) {
- continue; // not accepted
- }
-
- // reject if domain is like ".com"
- // (i.e., reject if domain does not contain embedded dots, see RFC 2109 section 4.3.2)
- // this is just a rudimentary check and does not cover all cases
- if (domain.lastIndexOf(QLatin1Char('.')) == 0)
- continue; // not accepted
-
+ || isParentDomain(defaultDomain, domain)))
+ continue; // not accepted
+
+ // the check for effective TLDs makes the "embedded dot" rule from RFC 2109 section 4.3.2
+ // redundant; the "leading dot" rule has been relaxed anyway, see above
+ // we remove the leading dot for this check
+ if (QNetworkCookieJarPrivate::isEffectiveTLD(domain.remove(0, 1)))
+ continue; // not accepted
}
QList<QNetworkCookie>::Iterator it = d->allCookies.begin(),
@@ -250,7 +250,7 @@ bool QNetworkCookieJar::setCookiesFromUrl(const QList<QNetworkCookie> &cookieLis
If more than one cookie with the same name is found, but with
differing paths, the one with longer path is returned before the
one with shorter path. In other words, this function returns
- cookies sorted by path length.
+ cookies sorted decreasingly by path length.
The default QNetworkCookieJar class implements only a very basic
security policy (it makes sure that the cookies' domain and path
@@ -304,4 +304,43 @@ QList<QNetworkCookie> QNetworkCookieJar::cookiesForUrl(const QUrl &url) const
return result;
}
+bool QNetworkCookieJarPrivate::isEffectiveTLD(const QString &domain)
+{
+ // for domain 'foo.bar.com':
+ // 1. return if TLD table contains 'foo.bar.com'
+ if (containsTLDEntry(domain))
+ return true;
+
+ if (domain.contains(QLatin1Char('.'))) {
+ int count = domain.size() - domain.indexOf(QLatin1Char('.'));
+ QString wildCardDomain;
+ wildCardDomain.reserve(count + 1);
+ wildCardDomain.append(QLatin1Char('*'));
+ wildCardDomain.append(domain.right(count));
+ // 2. if table contains '*.bar.com',
+ // test if table contains '!foo.bar.com'
+ if (containsTLDEntry(wildCardDomain)) {
+ QString exceptionDomain;
+ exceptionDomain.reserve(domain.size() + 1);
+ exceptionDomain.append(QLatin1Char('!'));
+ exceptionDomain.append(domain);
+ return (! containsTLDEntry(exceptionDomain));
+ }
+ }
+ return false;
+}
+
+bool QNetworkCookieJarPrivate::containsTLDEntry(const QString &entry)
+{
+ int index = qHash(entry) % tldCount;
+ int currentDomainIndex = tldIndices[index];
+ while (currentDomainIndex < tldIndices[index+1]) {
+ QString currentEntry = QString::fromUtf8(tldData + currentDomainIndex);
+ if (currentEntry == entry)
+ return true;
+ currentDomainIndex += qstrlen(tldData + currentDomainIndex) + 1; // +1 for the ending \0
+ }
+ return false;
+}
+
QT_END_NAMESPACE
diff --git a/src/network/access/qnetworkcookiejar_p.h b/src/network/access/qnetworkcookiejar_p.h
index ce5a87a..d6dc450 100644
--- a/src/network/access/qnetworkcookiejar_p.h
+++ b/src/network/access/qnetworkcookiejar_p.h
@@ -63,6 +63,9 @@ class QNetworkCookieJarPrivate: public QObjectPrivate
public:
QList<QNetworkCookie> allCookies;
+ static bool Q_AUTOTEST_EXPORT isEffectiveTLD(const QString &domain);
+ static bool containsTLDEntry(const QString &entry);
+
Q_DECLARE_PUBLIC(QNetworkCookieJar)
};
diff --git a/src/network/access/qnetworkcookiejartlds_p.h b/src/network/access/qnetworkcookiejartlds_p.h
new file mode 100644
index 0000000..b06d881
--- /dev/null
+++ b/src/network/access/qnetworkcookiejartlds_p.h
@@ -0,0 +1,6481 @@
+// Version: MPL 1.1/GPL 2.0/LGPL 2.1
+//
+// The contents of this file are subject to the Mozilla Public License Version
+// 1.1 (the "License"); you may not use this file except in compliance with
+// the License. You may obtain a copy of the License at
+// http://www.mozilla.org/MPL/
+//
+// Software distributed under the License is distributed on an "AS IS" basis,
+// WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+// for the specific language governing rights and limitations under the
+// License.
+//
+// The Original Code is the Public Suffix List.
+//
+// The Initial Developer of the Original Code is
+// Jo Hermans <jo.hermans@gmail.com>.
+// Portions created by the Initial Developer are Copyright (C) 2007
+// the Initial Developer. All Rights Reserved.
+//
+// Contributor(s):
+// Ruben Arakelyan <ruben@wackomenace.co.uk>
+// Gervase Markham <gerv@gerv.net>
+// Pamela Greene <pamg.bugs@gmail.com>
+// David Triendl <david@triendl.name>
+// Jothan Frakes <jothan@gmail.com>
+// The kind representatives of many TLD registries
+//
+// Alternatively, the contents of this file may be used under the terms of
+// either the GNU General Public License Version 2 or later (the "GPL"), or
+// the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+// in which case the provisions of the GPL or the LGPL are applicable instead
+// of those above. If you wish to allow use of your version of this file only
+// under the terms of either the GPL or the LGPL, and not to allow others to
+// use your version of this file under the terms of the MPL, indicate your
+// decision by deleting the provisions above and replace them with the notice
+// and other provisions required by the GPL or the LGPL. If you do not delete
+// the provisions above, a recipient may use your version of this file under
+// the terms of any one of the MPL, the GPL or the LGPL.
+//
+
+#ifndef QNETWORKCOOKIEJARTLD_P_H
+#define QNETWORKCOOKIEJARTLD_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists for the convenience
+// of the Network Access framework. This header file may change from
+// version to version without notice, or even be removed.
+//
+// We mean it.
+//
+
+QT_BEGIN_NAMESPACE
+
+// note to maintainer:
+// this file should be updated before each release ->
+// for instructions see the program at
+// util/network/cookiejar-generateTLDs
+
+static const quint16 tldCount = 3949;
+static const quint16 tldIndices[] = {
+0,
+7,
+14,
+14,
+20,
+51,
+61,
+93,
+100,
+100,
+116,
+159,
+167,
+180,
+180,
+193,
+234,
+234,
+234,
+255,
+255,
+255,
+280,
+280,
+287,
+287,
+295,
+303,
+313,
+326,
+326,
+380,
+393,
+413,
+419,
+419,
+419,
+424,
+438,
+438,
+469,
+515,
+515,
+515,
+534,
+534,
+557,
+557,
+557,
+557,
+572,
+572,
+572,
+579,
+587,
+597,
+612,
+612,
+624,
+636,
+648,
+662,
+687,
+709,
+714,
+740,
+766,
+789,
+789,
+805,
+805,
+810,
+815,
+815,
+824,
+824,
+831,
+857,
+869,
+891,
+891,
+916,
+916,
+916,
+927,
+934,
+964,
+971,
+987,
+987,
+987,
+1008,
+1008,
+1016,
+1016,
+1030,
+1030,
+1052,
+1075,
+1075,
+1082,
+1087,
+1115,
+1135,
+1135,
+1135,
+1172,
+1178,
+1178,
+1178,
+1202,
+1207,
+1220,
+1220,
+1266,
+1266,
+1266,
+1266,
+1272,
+1290,
+1316,
+1316,
+1332,
+1332,
+1339,
+1339,
+1352,
+1352,
+1389,
+1389,
+1408,
+1415,
+1437,
+1444,
+1489,
+1489,
+1502,
+1502,
+1512,
+1518,
+1539,
+1555,
+1562,
+1584,
+1598,
+1607,
+1607,
+1607,
+1632,
+1652,
+1652,
+1658,
+1658,
+1675,
+1682,
+1709,
+1733,
+1748,
+1776,
+1783,
+1783,
+1790,
+1797,
+1826,
+1850,
+1850,
+1856,
+1880,
+1887,
+1901,
+1921,
+1947,
+1961,
+1967,
+1967,
+1967,
+1972,
+1986,
+1986,
+1986,
+2009,
+2029,
+2029,
+2047,
+2061,
+2075,
+2075,
+2075,
+2075,
+2075,
+2075,
+2082,
+2082,
+2124,
+2124,
+2129,
+2162,
+2162,
+2162,
+2236,
+2256,
+2263,
+2276,
+2283,
+2313,
+2313,
+2347,
+2380,
+2387,
+2387,
+2387,
+2431,
+2438,
+2445,
+2452,
+2459,
+2459,
+2469,
+2490,
+2516,
+2527,
+2540,
+2540,
+2586,
+2610,
+2630,
+2630,
+2653,
+2660,
+2669,
+2693,
+2693,
+2710,
+2710,
+2719,
+2719,
+2734,
+2740,
+2740,
+2753,
+2753,
+2763,
+2770,
+2775,
+2782,
+2789,
+2802,
+2820,
+2827,
+2827,
+2841,
+2855,
+2855,
+2865,
+2872,
+2884,
+2884,
+2919,
+2937,
+2955,
+2962,
+3012,
+3042,
+3073,
+3083,
+3083,
+3100,
+3105,
+3112,
+3131,
+3131,
+3166,
+3180,
+3187,
+3194,
+3211,
+3218,
+3223,
+3233,
+3249,
+3259,
+3268,
+3314,
+3314,
+3324,
+3324,
+3336,
+3336,
+3336,
+3336,
+3350,
+3363,
+3376,
+3398,
+3416,
+3445,
+3464,
+3488,
+3488,
+3497,
+3545,
+3552,
+3552,
+3552,
+3566,
+3573,
+3573,
+3573,
+3581,
+3581,
+3603,
+3603,
+3615,
+3621,
+3621,
+3683,
+3683,
+3710,
+3710,
+3716,
+3716,
+3748,
+3770,
+3791,
+3803,
+3810,
+3817,
+3833,
+3846,
+3846,
+3852,
+3876,
+3876,
+3882,
+3903,
+3910,
+3939,
+3939,
+3939,
+3947,
+3962,
+3962,
+3981,
+3994,
+4021,
+4030,
+4042,
+4085,
+4085,
+4096,
+4096,
+4104,
+4123,
+4123,
+4123,
+4143,
+4154,
+4164,
+4194,
+4194,
+4194,
+4205,
+4205,
+4222,
+4238,
+4301,
+4309,
+4322,
+4331,
+4331,
+4331,
+4331,
+4331,
+4347,
+4365,
+4375,
+4375,
+4385,
+4398,
+4412,
+4430,
+4430,
+4437,
+4447,
+4463,
+4472,
+4472,
+4472,
+4484,
+4484,
+4484,
+4484,
+4484,
+4490,
+4490,
+4511,
+4511,
+4522,
+4522,
+4522,
+4522,
+4528,
+4528,
+4534,
+4551,
+4551,
+4551,
+4564,
+4583,
+4583,
+4611,
+4611,
+4611,
+4622,
+4622,
+4649,
+4668,
+4677,
+4692,
+4692,
+4692,
+4705,
+4723,
+4723,
+4723,
+4729,
+4729,
+4743,
+4743,
+4750,
+4750,
+4763,
+4770,
+4776,
+4776,
+4776,
+4793,
+4811,
+4811,
+4811,
+4821,
+4821,
+4841,
+4857,
+4891,
+4897,
+4903,
+4903,
+4903,
+4919,
+4935,
+4942,
+4958,
+4958,
+4975,
+4975,
+4975,
+4985,
+4985,
+5020,
+5032,
+5032,
+5040,
+5053,
+5068,
+5079,
+5079,
+5101,
+5115,
+5115,
+5135,
+5154,
+5161,
+5161,
+5168,
+5168,
+5184,
+5210,
+5210,
+5238,
+5255,
+5278,
+5285,
+5308,
+5318,
+5327,
+5327,
+5333,
+5333,
+5340,
+5348,
+5355,
+5366,
+5377,
+5384,
+5408,
+5415,
+5422,
+5435,
+5442,
+5482,
+5482,
+5482,
+5482,
+5498,
+5527,
+5534,
+5541,
+5572,
+5572,
+5572,
+5579,
+5591,
+5602,
+5602,
+5621,
+5621,
+5646,
+5664,
+5671,
+5671,
+5681,
+5696,
+5707,
+5716,
+5716,
+5723,
+5723,
+5732,
+5742,
+5742,
+5763,
+5770,
+5776,
+5790,
+5790,
+5797,
+5806,
+5816,
+5832,
+5882,
+5882,
+5882,
+5882,
+5893,
+5934,
+5934,
+5965,
+5965,
+5980,
+5980,
+5980,
+5980,
+6007,
+6017,
+6034,
+6051,
+6065,
+6075,
+6075,
+6091,
+6097,
+6097,
+6109,
+6109,
+6109,
+6122,
+6147,
+6168,
+6168,
+6191,
+6191,
+6191,
+6191,
+6191,
+6198,
+6217,
+6224,
+6224,
+6231,
+6245,
+6252,
+6252,
+6270,
+6270,
+6284,
+6305,
+6315,
+6322,
+6322,
+6322,
+6329,
+6329,
+6329,
+6353,
+6361,
+6361,
+6375,
+6391,
+6405,
+6405,
+6415,
+6431,
+6431,
+6431,
+6431,
+6458,
+6475,
+6475,
+6475,
+6482,
+6489,
+6496,
+6496,
+6503,
+6520,
+6520,
+6520,
+6527,
+6527,
+6544,
+6561,
+6573,
+6573,
+6580,
+6580,
+6587,
+6587,
+6592,
+6592,
+6592,
+6592,
+6599,
+6599,
+6612,
+6633,
+6649,
+6649,
+6669,
+6676,
+6683,
+6683,
+6713,
+6720,
+6727,
+6736,
+6736,
+6746,
+6770,
+6807,
+6814,
+6827,
+6846,
+6846,
+6864,
+6864,
+6864,
+6864,
+6881,
+6888,
+6888,
+6888,
+6914,
+6935,
+6935,
+6935,
+6953,
+6959,
+6966,
+6983,
+6983,
+6983,
+7013,
+7023,
+7023,
+7023,
+7023,
+7037,
+7044,
+7058,
+7079,
+7086,
+7123,
+7134,
+7155,
+7168,
+7178,
+7203,
+7227,
+7236,
+7258,
+7265,
+7274,
+7274,
+7303,
+7303,
+7314,
+7314,
+7345,
+7352,
+7367,
+7377,
+7388,
+7388,
+7402,
+7402,
+7409,
+7421,
+7421,
+7467,
+7484,
+7484,
+7484,
+7491,
+7532,
+7532,
+7539,
+7546,
+7546,
+7553,
+7573,
+7573,
+7573,
+7580,
+7587,
+7594,
+7594,
+7594,
+7606,
+7606,
+7637,
+7637,
+7637,
+7664,
+7664,
+7664,
+7677,
+7684,
+7701,
+7723,
+7723,
+7723,
+7723,
+7734,
+7734,
+7734,
+7748,
+7748,
+7748,
+7748,
+7759,
+7759,
+7775,
+7775,
+7782,
+7789,
+7817,
+7824,
+7831,
+7836,
+7865,
+7865,
+7876,
+7901,
+7901,
+7908,
+7918,
+7938,
+7945,
+7945,
+7957,
+7964,
+7979,
+7986,
+7994,
+8007,
+8007,
+8014,
+8021,
+8061,
+8061,
+8071,
+8088,
+8131,
+8138,
+8153,
+8160,
+8160,
+8160,
+8175,
+8183,
+8197,
+8211,
+8211,
+8211,
+8243,
+8243,
+8243,
+8243,
+8259,
+8259,
+8259,
+8259,
+8259,
+8266,
+8275,
+8281,
+8281,
+8281,
+8281,
+8288,
+8288,
+8309,
+8309,
+8309,
+8330,
+8330,
+8330,
+8330,
+8337,
+8343,
+8343,
+8360,
+8370,
+8370,
+8380,
+8380,
+8386,
+8386,
+8397,
+8415,
+8415,
+8428,
+8454,
+8460,
+8475,
+8492,
+8526,
+8554,
+8554,
+8583,
+8583,
+8583,
+8598,
+8607,
+8617,
+8617,
+8642,
+8652,
+8652,
+8652,
+8662,
+8688,
+8688,
+8704,
+8704,
+8747,
+8765,
+8775,
+8783,
+8811,
+8835,
+8835,
+8835,
+8850,
+8859,
+8884,
+8910,
+8919,
+8952,
+8978,
+8978,
+8991,
+8991,
+8991,
+8999,
+8999,
+8999,
+9030,
+9030,
+9030,
+9030,
+9030,
+9041,
+9048,
+9048,
+9054,
+9054,
+9054,
+9086,
+9108,
+9108,
+9119,
+9119,
+9130,
+9144,
+9152,
+9161,
+9174,
+9194,
+9207,
+9207,
+9207,
+9232,
+9242,
+9242,
+9271,
+9290,
+9308,
+9308,
+9308,
+9308,
+9320,
+9333,
+9343,
+9356,
+9379,
+9379,
+9379,
+9395,
+9395,
+9406,
+9419,
+9419,
+9419,
+9419,
+9450,
+9485,
+9485,
+9497,
+9497,
+9505,
+9517,
+9528,
+9528,
+9551,
+9564,
+9586,
+9586,
+9608,
+9608,
+9626,
+9626,
+9626,
+9653,
+9653,
+9681,
+9681,
+9681,
+9698,
+9698,
+9698,
+9714,
+9729,
+9737,
+9737,
+9765,
+9765,
+9765,
+9765,
+9765,
+9825,
+9844,
+9866,
+9880,
+9880,
+9880,
+9880,
+9886,
+9895,
+9895,
+9895,
+9895,
+9895,
+9913,
+9913,
+9924,
+9958,
+9958,
+9967,
+9975,
+9975,
+9975,
+9981,
+9998,
+9998,
+9998,
+10012,
+10036,
+10036,
+10066,
+10079,
+10097,
+10121,
+10133,
+10142,
+10142,
+10142,
+10156,
+10173,
+10173,
+10173,
+10196,
+10205,
+10205,
+10205,
+10205,
+10218,
+10234,
+10240,
+10240,
+10240,
+10264,
+10273,
+10286,
+10286,
+10286,
+10286,
+10299,
+10299,
+10309,
+10309,
+10339,
+10358,
+10358,
+10374,
+10374,
+10390,
+10390,
+10413,
+10413,
+10439,
+10461,
+10467,
+10467,
+10467,
+10492,
+10492,
+10501,
+10528,
+10528,
+10528,
+10539,
+10583,
+10583,
+10583,
+10613,
+10613,
+10619,
+10628,
+10645,
+10645,
+10645,
+10650,
+10671,
+10687,
+10709,
+10709,
+10709,
+10709,
+10709,
+10727,
+10727,
+10727,
+10727,
+10733,
+10733,
+10768,
+10768,
+10773,
+10780,
+10788,
+10788,
+10797,
+10797,
+10835,
+10835,
+10845,
+10852,
+10861,
+10861,
+10861,
+10861,
+10861,
+10861,
+10861,
+10875,
+10888,
+10907,
+10907,
+10907,
+10920,
+10920,
+10932,
+10946,
+10977,
+10977,
+10997,
+11008,
+11037,
+11059,
+11059,
+11059,
+11067,
+11067,
+11067,
+11067,
+11067,
+11077,
+11091,
+11102,
+11102,
+11112,
+11125,
+11129,
+11129,
+11154,
+11154,
+11154,
+11164,
+11164,
+11189,
+11189,
+11189,
+11189,
+11189,
+11196,
+11196,
+11227,
+11238,
+11247,
+11256,
+11265,
+11265,
+11286,
+11307,
+11330,
+11337,
+11378,
+11378,
+11389,
+11413,
+11454,
+11469,
+11475,
+11475,
+11475,
+11475,
+11503,
+11503,
+11503,
+11503,
+11534,
+11534,
+11550,
+11550,
+11557,
+11557,
+11557,
+11557,
+11574,
+11585,
+11585,
+11603,
+11626,
+11643,
+11643,
+11643,
+11643,
+11663,
+11663,
+11682,
+11696,
+11696,
+11696,
+11696,
+11706,
+11706,
+11706,
+11706,
+11723,
+11723,
+11757,
+11757,
+11773,
+11795,
+11813,
+11836,
+11836,
+11883,
+11903,
+11952,
+11965,
+11965,
+11984,
+11997,
+12008,
+12008,
+12008,
+12024,
+12043,
+12065,
+12071,
+12099,
+12129,
+12140,
+12140,
+12146,
+12161,
+12161,
+12161,
+12161,
+12167,
+12167,
+12180,
+12186,
+12208,
+12226,
+12243,
+12243,
+12252,
+12252,
+12274,
+12289,
+12302,
+12302,
+12313,
+12313,
+12313,
+12313,
+12358,
+12358,
+12358,
+12369,
+12375,
+12391,
+12391,
+12391,
+12391,
+12405,
+12410,
+12416,
+12416,
+12436,
+12436,
+12436,
+12443,
+12443,
+12462,
+12477,
+12492,
+12492,
+12503,
+12519,
+12525,
+12531,
+12571,
+12571,
+12591,
+12591,
+12601,
+12641,
+12641,
+12641,
+12657,
+12657,
+12657,
+12699,
+12699,
+12699,
+12712,
+12728,
+12744,
+12761,
+12769,
+12782,
+12793,
+12823,
+12836,
+12851,
+12863,
+12890,
+12900,
+12900,
+12900,
+12910,
+12910,
+12924,
+12924,
+12924,
+12924,
+12924,
+12952,
+12984,
+13003,
+13038,
+13038,
+13056,
+13056,
+13056,
+13056,
+13074,
+13081,
+13093,
+13103,
+13103,
+13112,
+13119,
+13132,
+13132,
+13132,
+13141,
+13151,
+13183,
+13193,
+13206,
+13206,
+13206,
+13236,
+13252,
+13267,
+13267,
+13294,
+13307,
+13307,
+13307,
+13343,
+13349,
+13349,
+13349,
+13375,
+13375,
+13375,
+13384,
+13384,
+13384,
+13393,
+13393,
+13393,
+13402,
+13414,
+13425,
+13445,
+13467,
+13485,
+13499,
+13509,
+13528,
+13528,
+13549,
+13549,
+13559,
+13570,
+13570,
+13570,
+13570,
+13598,
+13637,
+13647,
+13647,
+13661,
+13673,
+13682,
+13687,
+13694,
+13694,
+13720,
+13733,
+13742,
+13748,
+13771,
+13795,
+13795,
+13814,
+13821,
+13821,
+13855,
+13862,
+13862,
+13862,
+13874,
+13874,
+13897,
+13909,
+13909,
+13947,
+13947,
+13952,
+13952,
+13970,
+13979,
+13979,
+13979,
+14008,
+14049,
+14049,
+14049,
+14049,
+14049,
+14049,
+14060,
+14083,
+14083,
+14091,
+14101,
+14101,
+14101,
+14101,
+14118,
+14136,
+14195,
+14195,
+14195,
+14213,
+14213,
+14232,
+14232,
+14253,
+14253,
+14258,
+14275,
+14275,
+14304,
+14311,
+14311,
+14318,
+14318,
+14318,
+14318,
+14318,
+14318,
+14325,
+14325,
+14345,
+14345,
+14379,
+14389,
+14422,
+14422,
+14422,
+14422,
+14435,
+14441,
+14441,
+14460,
+14460,
+14471,
+14471,
+14481,
+14495,
+14495,
+14495,
+14502,
+14502,
+14502,
+14502,
+14524,
+14533,
+14541,
+14552,
+14552,
+14552,
+14552,
+14563,
+14563,
+14568,
+14568,
+14585,
+14595,
+14602,
+14628,
+14628,
+14645,
+14672,
+14678,
+14697,
+14697,
+14734,
+14757,
+14764,
+14771,
+14771,
+14771,
+14796,
+14815,
+14822,
+14845,
+14861,
+14861,
+14861,
+14873,
+14873,
+14873,
+14902,
+14920,
+14920,
+14926,
+14926,
+14926,
+14941,
+14949,
+14949,
+14949,
+14949,
+14949,
+14960,
+14960,
+14971,
+14971,
+14998,
+15003,
+15003,
+15003,
+15013,
+15013,
+15027,
+15027,
+15027,
+15043,
+15053,
+15063,
+15074,
+15083,
+15093,
+15093,
+15121,
+15121,
+15128,
+15128,
+15144,
+15144,
+15144,
+15144,
+15165,
+15170,
+15170,
+15170,
+15170,
+15170,
+15170,
+15170,
+15186,
+15206,
+15206,
+15206,
+15224,
+15236,
+15236,
+15252,
+15258,
+15258,
+15258,
+15258,
+15264,
+15277,
+15288,
+15307,
+15307,
+15318,
+15328,
+15328,
+15334,
+15334,
+15363,
+15399,
+15399,
+15422,
+15438,
+15447,
+15447,
+15456,
+15456,
+15456,
+15495,
+15495,
+15495,
+15495,
+15511,
+15511,
+15530,
+15557,
+15566,
+15582,
+15590,
+15590,
+15604,
+15604,
+15625,
+15635,
+15655,
+15655,
+15655,
+15655,
+15655,
+15665,
+15675,
+15675,
+15675,
+15675,
+15675,
+15682,
+15682,
+15682,
+15694,
+15719,
+15749,
+15749,
+15794,
+15794,
+15837,
+15854,
+15854,
+15861,
+15861,
+15861,
+15861,
+15884,
+15900,
+15911,
+15931,
+15931,
+15931,
+15931,
+15931,
+15963,
+15963,
+15996,
+16006,
+16013,
+16024,
+16034,
+16049,
+16049,
+16049,
+16059,
+16059,
+16059,
+16059,
+16059,
+16059,
+16059,
+16064,
+16075,
+16104,
+16104,
+16117,
+16124,
+16124,
+16124,
+16124,
+16130,
+16145,
+16159,
+16190,
+16193,
+16196,
+16210,
+16224,
+16243,
+16255,
+16261,
+16280,
+16283,
+16292,
+16295,
+16295,
+16301,
+16304,
+16322,
+16325,
+16328,
+16349,
+16355,
+16382,
+16408,
+16414,
+16414,
+16414,
+16458,
+16477,
+16480,
+16485,
+16488,
+16514,
+16520,
+16530,
+16530,
+16546,
+16562,
+16597,
+16603,
+16622,
+16622,
+16646,
+16669,
+16672,
+16715,
+16715,
+16715,
+16718,
+16718,
+16727,
+16733,
+16752,
+16770,
+16787,
+16794,
+16810,
+16827,
+16840,
+16850,
+16876,
+16901,
+16901,
+16901,
+16916,
+16919,
+16926,
+16943,
+16972,
+16978,
+16978,
+16978,
+16981,
+17008,
+17008,
+17016,
+17053,
+17053,
+17053,
+17053,
+17072,
+17086,
+17105,
+17139,
+17153,
+17162,
+17162,
+17177,
+17177,
+17177,
+17177,
+17195,
+17218,
+17221,
+17221,
+17237,
+17276,
+17276,
+17300,
+17319,
+17339,
+17357,
+17370,
+17383,
+17400,
+17407,
+17419,
+17439,
+17439,
+17449,
+17465,
+17475,
+17504,
+17527,
+17527,
+17534,
+17548,
+17564,
+17564,
+17598,
+17598,
+17601,
+17630,
+17649,
+17669,
+17669,
+17679,
+17686,
+17757,
+17776,
+17796,
+17810,
+17840,
+17840,
+17877,
+17884,
+17884,
+17911,
+17936,
+17970,
+17980,
+17995,
+17995,
+18008,
+18011,
+18036,
+18075,
+18097,
+18097,
+18104,
+18115,
+18115,
+18129,
+18134,
+18141,
+18141,
+18157,
+18180,
+18190,
+18217,
+18224,
+18252,
+18284,
+18284,
+18296,
+18299,
+18312,
+18322,
+18338,
+18348,
+18348,
+18363,
+18372,
+18387,
+18387,
+18390,
+18402,
+18445,
+18445,
+18445,
+18466,
+18479,
+18479,
+18498,
+18508,
+18511,
+18511,
+18511,
+18511,
+18511,
+18526,
+18558,
+18586,
+18622,
+18643,
+18670,
+18686,
+18710,
+18720,
+18739,
+18739,
+18742,
+18745,
+18771,
+18774,
+18777,
+18791,
+18813,
+18816,
+18822,
+18839,
+18845,
+18851,
+18854,
+18878,
+18881,
+18896,
+18896,
+18899,
+18926,
+18937,
+18940,
+18953,
+18963,
+19010,
+19010,
+19017,
+19046,
+19060,
+19060,
+19087,
+19095,
+19101,
+19101,
+19128,
+19146,
+19157,
+19157,
+19188,
+19198,
+19205,
+19223,
+19230,
+19255,
+19280,
+19280,
+19283,
+19292,
+19301,
+19320,
+19323,
+19323,
+19341,
+19341,
+19365,
+19378,
+19381,
+19394,
+19423,
+19433,
+19440,
+19466,
+19490,
+19490,
+19490,
+19497,
+19504,
+19511,
+19511,
+19518,
+19545,
+19568,
+19575,
+19575,
+19583,
+19586,
+19592,
+19592,
+19609,
+19622,
+19629,
+19641,
+19641,
+19656,
+19673,
+19700,
+19723,
+19733,
+19746,
+19759,
+19769,
+19782,
+19789,
+19795,
+19831,
+19834,
+19841,
+19851,
+19854,
+19880,
+19895,
+19898,
+19898,
+19911,
+19922,
+19950,
+20020,
+20030,
+20059,
+20062,
+20089,
+20107,
+20151,
+20154,
+20175,
+20205,
+20208,
+20229,
+20229,
+20255,
+20261,
+20261,
+20283,
+20335,
+20362,
+20385,
+20392,
+20392,
+20392,
+20392,
+20418,
+20418,
+20418,
+20418,
+20443,
+20446,
+20446,
+20452,
+20452,
+20467,
+20467,
+20489,
+20489,
+20498,
+20525,
+20554,
+20560,
+20575,
+20589,
+20589,
+20589,
+20614,
+20652,
+20659,
+20659,
+20668,
+20679,
+20679,
+20679,
+20685,
+20685,
+20685,
+20685,
+20685,
+20685,
+20696,
+20733,
+20760,
+20766,
+20769,
+20792,
+20792,
+20792,
+20792,
+20813,
+20813,
+20813,
+20813,
+20826,
+20826,
+20846,
+20862,
+20880,
+20887,
+20901,
+20908,
+20933,
+20938,
+20958,
+20969,
+20978,
+20978,
+20978,
+20985,
+20985,
+20985,
+21000,
+21010,
+21010,
+21014,
+21026,
+21033,
+21041,
+21041,
+21051,
+21051,
+21064,
+21071,
+21113,
+21120,
+21120,
+21127,
+21134,
+21142,
+21164,
+21164,
+21164,
+21188,
+21195,
+21208,
+21215,
+21226,
+21226,
+21226,
+21238,
+21249,
+21255,
+21255,
+21265,
+21279,
+21296,
+21301,
+21315,
+21321,
+21331,
+21331,
+21331,
+21337,
+21343,
+21343,
+21351,
+21351,
+21361,
+21368,
+21383,
+21383,
+21389,
+21413,
+21437,
+21449,
+21462,
+21478,
+21506,
+21534,
+21546,
+21546,
+21557,
+21580,
+21595,
+21595,
+21595,
+21595,
+21626,
+21626,
+21646,
+21670,
+21676,
+21688,
+21688,
+21716,
+21731,
+21762,
+21762,
+21762,
+21762,
+21762,
+21783,
+21789,
+21799,
+21828,
+21828,
+21837,
+21845,
+21868,
+21874,
+21874,
+21880,
+21880,
+21889,
+21901,
+21910,
+21941,
+21941,
+21959,
+21959,
+21959,
+21966,
+21966,
+21972,
+21972,
+21995,
+22011,
+22043,
+22043,
+22051,
+22051,
+22060,
+22060,
+22060,
+22074,
+22086,
+22086,
+22099,
+22099,
+22120,
+22120,
+22134,
+22144,
+22150,
+22158,
+22164,
+22164,
+22171,
+22199,
+22210,
+22210,
+22210,
+22220,
+22228,
+22228,
+22239,
+22261,
+22304,
+22304,
+22312,
+22349,
+22349,
+22349,
+22357,
+22381,
+22381,
+22390,
+22390,
+22390,
+22390,
+22402,
+22413,
+22413,
+22422,
+22422,
+22445,
+22445,
+22445,
+22456,
+22456,
+22469,
+22479,
+22501,
+22512,
+22528,
+22528,
+22528,
+22528,
+22528,
+22528,
+22528,
+22540,
+22540,
+22546,
+22546,
+22546,
+22546,
+22569,
+22591,
+22591,
+22591,
+22591,
+22610,
+22655,
+22655,
+22667,
+22667,
+22677,
+22677,
+22692,
+22692,
+22702,
+22702,
+22702,
+22717,
+22736,
+22750,
+22755,
+22780,
+22785,
+22822,
+22844,
+22859,
+22871,
+22909,
+22949,
+22962,
+22973,
+22979,
+22988,
+23007,
+23027,
+23035,
+23072,
+23082,
+23082,
+23109,
+23116,
+23130,
+23158,
+23166,
+23166,
+23172,
+23177,
+23189,
+23219,
+23219,
+23250,
+23273,
+23281,
+23281,
+23281,
+23281,
+23281,
+23287,
+23287,
+23299,
+23305,
+23315,
+23315,
+23321,
+23328,
+23334,
+23355,
+23355,
+23355,
+23355,
+23355,
+23366,
+23390,
+23396,
+23396,
+23396,
+23396,
+23402,
+23418,
+23424,
+23424,
+23438,
+23446,
+23446,
+23446,
+23500,
+23525,
+23569,
+23592,
+23592,
+23592,
+23605,
+23614,
+23614,
+23614,
+23627,
+23633,
+23657,
+23673,
+23673,
+23673,
+23689,
+23689,
+23701,
+23701,
+23701,
+23713,
+23713,
+23713,
+23738,
+23758,
+23775,
+23775,
+23794,
+23794,
+23803,
+23803,
+23803,
+23803,
+23813,
+23826,
+23845,
+23845,
+23845,
+23845,
+23872,
+23872,
+23872,
+23888,
+23888,
+23900,
+23900,
+23906,
+23906,
+23906,
+23906,
+23906,
+23924,
+23924,
+23924,
+23930,
+23930,
+23939,
+23949,
+23971,
+23971,
+23971,
+24000,
+24012,
+24042,
+24042,
+24042,
+24042,
+24042,
+24070,
+24076,
+24094,
+24094,
+24094,
+24123,
+24123,
+24123,
+24134,
+24150,
+24150,
+24150,
+24150,
+24150,
+24150,
+24155,
+24179,
+24179,
+24189,
+24189,
+24189,
+24198,
+24198,
+24218,
+24218,
+24218,
+24234,
+24251,
+24257,
+24276,
+24305,
+24321,
+24321,
+24321,
+24334,
+24334,
+24334,
+24349,
+24356,
+24361,
+24372,
+24372,
+24372,
+24388,
+24396,
+24396,
+24402,
+24410,
+24410,
+24428,
+24428,
+24450,
+24450,
+24467,
+24485,
+24495,
+24495,
+24495,
+24507,
+24507,
+24514,
+24531,
+24531,
+24531,
+24531,
+24531,
+24537,
+24537,
+24558,
+24572,
+24584,
+24584,
+24601,
+24601,
+24607,
+24615,
+24615,
+24632,
+24632,
+24632,
+24632,
+24661,
+24676,
+24676,
+24724,
+24751,
+24751,
+24774,
+24774,
+24783,
+24793,
+24793,
+24793,
+24813,
+24819,
+24819,
+24826,
+24826,
+24842,
+24858,
+24872,
+24872,
+24890,
+24890,
+24890,
+24890,
+24890,
+24890,
+24890,
+24890,
+24890,
+24906,
+24906,
+24917,
+24928,
+24947,
+24947,
+24947,
+24947,
+24947,
+24947,
+24947,
+24947,
+24947,
+24963,
+24983,
+24991,
+24991,
+24991,
+24991,
+24991,
+24991,
+24991,
+24991,
+25007,
+25007,
+25007,
+25007,
+25007,
+25007,
+25007,
+25030,
+25040,
+25040,
+25040,
+25040,
+25040,
+25059,
+25097,
+25132,
+25149,
+25159,
+25169,
+25169,
+25169,
+25192,
+25192,
+25192,
+25192,
+25205,
+25205,
+25216,
+25221,
+25221,
+25233,
+25233,
+25240,
+25250,
+25256,
+25273,
+25273,
+25303,
+25321,
+25321,
+25321,
+25333,
+25333,
+25333,
+25333,
+25370,
+25370,
+25402,
+25418,
+25418,
+25439,
+25439,
+25454,
+25454,
+25454,
+25463,
+25477,
+25526,
+25526,
+25526,
+25526,
+25545,
+25562,
+25572,
+25572,
+25582,
+25582,
+25582,
+25597,
+25610,
+25634,
+25641,
+25641,
+25641,
+25668,
+25668,
+25675,
+25707,
+25727,
+25727,
+25741,
+25756,
+25756,
+25779,
+25811,
+25811,
+25811,
+25817,
+25817,
+25817,
+25827,
+25827,
+25827,
+25827,
+25827,
+25836,
+25836,
+25836,
+25836,
+25850,
+25850,
+25860,
+25884,
+25901,
+25922,
+25936,
+25946,
+25969,
+25969,
+25969,
+25969,
+25975,
+25975,
+25987,
+25987,
+26065,
+26065,
+26065,
+26084,
+26084,
+26103,
+26128,
+26141,
+26151,
+26169,
+26169,
+26169,
+26180,
+26191,
+26191,
+26191,
+26197,
+26197,
+26205,
+26211,
+26235,
+26235,
+26235,
+26235,
+26235,
+26235,
+26245,
+26245,
+26259,
+26259,
+26259,
+26259,
+26284,
+26284,
+26325,
+26325,
+26355,
+26364,
+26364,
+26402,
+26418,
+26418,
+26425,
+26432,
+26432,
+26454,
+26504,
+26513,
+26525,
+26525,
+26525,
+26525,
+26525,
+26545,
+26545,
+26571,
+26590,
+26597,
+26597,
+26597,
+26597,
+26597,
+26639,
+26648,
+26659,
+26666,
+26672,
+26672,
+26672,
+26672,
+26672,
+26694,
+26701,
+26701,
+26701,
+26724,
+26724,
+26746,
+26753,
+26774,
+26774,
+26774,
+26774,
+26806,
+26824,
+26824,
+26830,
+26852,
+26882,
+26882,
+26889,
+26889,
+26889,
+26889,
+26889,
+26889,
+26903,
+26911,
+26918,
+26918,
+26928,
+26948,
+26948,
+26970,
+26970,
+26985,
+26996,
+27045,
+27045,
+27058,
+27058,
+27068,
+27068,
+27104,
+27155,
+27155,
+27155,
+27155,
+27155,
+27172,
+27172,
+27172,
+27172,
+27189,
+27195,
+27195,
+27223,
+27223,
+27223,
+27223,
+27244,
+27290,
+27322,
+27332,
+27364,
+27371,
+27371,
+27371,
+27401,
+27401,
+27417,
+27417,
+27431,
+27470,
+27470,
+27470,
+27470,
+27484,
+27484,
+27484,
+27484,
+27484,
+27496,
+27496,
+27515,
+27515,
+27543,
+27560,
+27576,
+27604,
+27622,
+27631,
+27631,
+27638,
+27649,
+27672,
+27682,
+27682,
+27682,
+27707,
+27717,
+27724,
+27732,
+27755,
+27755,
+27755,
+27768,
+27768,
+27783,
+27789,
+27799,
+27799,
+27799,
+27818,
+27826,
+27838,
+27848,
+27848,
+27848,
+27855,
+27862,
+27862,
+27896,
+27921,
+27921,
+27943,
+27954,
+27954,
+27976,
+27976,
+27976,
+27985,
+28002,
+28012,
+28019,
+28034,
+28034,
+28046,
+28068,
+28097,
+28122,
+28122,
+28131,
+28137,
+28151,
+28151,
+28172,
+28190,
+28196,
+28211,
+28211,
+28264,
+28273,
+28286,
+28324,
+28324,
+28324,
+28354,
+28354,
+28361,
+28397,
+28417,
+28417,
+28424,
+28435,
+28461,
+28461,
+28470,
+28483,
+28483,
+28483,
+28483,
+28483,
+28483,
+28483,
+28515,
+28531,
+28531,
+28549,
+28575,
+28575,
+28575,
+28582,
+28599,
+28615,
+28630,
+28630,
+28672,
+28711,
+28723,
+28723,
+28731,
+28752,
+28752,
+28752,
+28763,
+28763,
+28775,
+28775,
+28775,
+28775,
+28775,
+28775,
+28805,
+28814,
+28830,
+28861,
+28882,
+28882,
+28902,
+28918,
+28937,
+28952,
+28959,
+28998,
+29009,
+29009,
+29009,
+29009,
+29019,
+29019,
+29019,
+29019,
+29019,
+29057,
+29069,
+29076,
+29076,
+29076,
+29076,
+29076,
+29082,
+29082,
+29082,
+29117,
+29117,
+29117,
+29117,
+29134,
+29134,
+29159,
+29159,
+29185,
+29185,
+29196,
+29196,
+29242,
+29248,
+29256,
+29280,
+29301,
+29307,
+29307,
+29307,
+29314,
+29314,
+29338,
+29356,
+29367,
+29367,
+29381,
+29391,
+29399,
+29399,
+29414,
+29434,
+29434,
+29441,
+29473,
+29484,
+29503,
+29520,
+29520,
+29548,
+29565,
+29572,
+29572,
+29572,
+29572,
+29572,
+29597,
+29597,
+29620,
+29655,
+29660,
+29660,
+29660,
+29667,
+29674,
+29688,
+29698,
+29705,
+29728,
+29740,
+29740,
+29761,
+29761,
+29767,
+29780,
+29787,
+29794,
+29794,
+29807,
+29820,
+29820,
+29820,
+29820,
+29832,
+29844,
+29855,
+29855,
+29855,
+29867,
+29867,
+29867,
+29867,
+29881,
+29881,
+29905,
+29905,
+29905,
+29923,
+29923,
+29948,
+29948,
+29948,
+29976,
+29986,
+29996,
+29996,
+30030,
+30030,
+30054,
+30054,
+30070,
+30070,
+30070,
+30077,
+30077,
+30087,
+30107,
+30107,
+30115,
+30141,
+30178,
+30178,
+30201,
+30201,
+30201,
+30207,
+30229,
+30239,
+30254,
+30268,
+30277,
+30311,
+30323,
+30323,
+30331,
+30331,
+30331,
+30331,
+30331,
+30353,
+30365,
+30374,
+30374,
+30374,
+30380,
+30380,
+30380,
+30380,
+30410,
+30410,
+30410,
+30443,
+30443,
+30453,
+30462,
+30472,
+30472,
+30472,
+30472,
+30472,
+30472,
+30489,
+30500,
+30500,
+30500,
+30532,
+30532,
+30553,
+30577,
+30599,
+30599,
+30609,
+30640,
+30640,
+30640,
+30664,
+30676,
+30676,
+30676,
+30692,
+30719,
+30728,
+30728,
+30742,
+30742,
+30749,
+30749,
+30760,
+30770,
+30770,
+30783,
+30783,
+30783,
+30804,
+30847,
+30847,
+30847,
+30847,
+30857,
+30857,
+30857,
+30857,
+30875,
+30875,
+30895,
+30895,
+30921,
+30926,
+30926,
+30926,
+30945,
+30945,
+30945,
+30945,
+30959,
+30959,
+30959,
+30959,
+30972,
+30972,
+30984,
+31011,
+31011,
+31048,
+31056,
+31056,
+31070,
+31077,
+31077,
+31110,
+31110,
+31115,
+31122,
+31139,
+31159,
+31159,
+31165,
+31171,
+31171,
+31197,
+31204,
+31211,
+31211,
+31221,
+31228,
+31228,
+31245,
+31245,
+31245,
+31252,
+31265,
+31265,
+31265,
+31265,
+31294,
+31305,
+31320,
+31333,
+31333,
+31333,
+31343,
+31350,
+31357,
+31369,
+31369,
+31379,
+31385,
+31391,
+31407,
+31407,
+31407,
+31423,
+31423,
+31423,
+31434,
+31454,
+31470,
+31511,
+31521,
+31521,
+31521,
+31542,
+31582,
+31582,
+31597,
+31597,
+31597,
+31614,
+31623,
+31645,
+31645,
+31661,
+31661,
+31669,
+31669,
+31676,
+31676,
+31706,
+31720,
+31726,
+31743,
+31785,
+31804,
+31817,
+31817,
+31835,
+31846,
+31863,
+31885,
+31885,
+31896,
+31907,
+31907,
+31907,
+31922,
+31922,
+31929,
+31929,
+31929,
+31936,
+31943,
+31949,
+31949,
+31949,
+31959,
+32006,
+32024,
+32031,
+32031,
+32038,
+32063,
+32095,
+32095,
+32105,
+32105,
+32105,
+32105,
+32105,
+32125,
+32134,
+32140,
+32176,
+32185,
+32195,
+32195,
+32195,
+32195,
+32202,
+32202,
+32218,
+32236,
+32259,
+32294,
+32300,
+32305,
+32305,
+32305,
+32323,
+32337,
+32352,
+32359,
+32374,
+32381,
+32388,
+32388,
+32388,
+32402,
+32402,
+32402,
+32402,
+32418,
+32428,
+32428,
+32428,
+32450,
+32450,
+32450,
+32462,
+32467,
+32480,
+32480,
+32480,
+32487,
+32502,
+32509,
+32525,
+32560,
+32570,
+32583,
+32597,
+32623,
+32637,
+32644,
+32667,
+32707,
+32725,
+32725,
+32747,
+32747,
+32751,
+32758,
+32789,
+32807,
+32824,
+32824,
+32824,
+32824,
+32843,
+32843,
+32850,
+32876,
+32908,
+32915,
+32946,
+32965,
+32965,
+32982,
+33002,
+33009,
+33029,
+33064,
+33084,
+33098,
+33098,
+33098,
+33098,
+33110,
+33110,
+33151,
+33158,
+33180,
+33198,
+33205,
+33227,
+33227,
+33237,
+33237,
+33253,
+33258,
+33277,
+33292,
+33315,
+33315,
+33333,
+33348,
+33348,
+33348,
+33348,
+33348,
+33348,
+33348,
+33355,
+33355,
+33355,
+33390,
+33408,
+33423,
+33437,
+33452,
+33458,
+33465,
+33480,
+33480,
+33487,
+33494,
+33504,
+33511,
+33551,
+33551,
+33558,
+33589,
+33595,
+33595,
+33602,
+33627,
+33644,
+33668,
+33668,
+33668,
+33676,
+33676,
+33716,
+33728,
+33747,
+33747,
+33769,
+33775,
+33789,
+33803,
+33803,
+33810,
+33810,
+33810,
+33820,
+33820,
+33820,
+33820,
+33843,
+33843,
+33843,
+33879,
+33889,
+33889,
+33889,
+33903,
+33917,
+33931,
+33959,
+33993,
+34000,
+34014,
+34037,
+34043,
+34055,
+34055,
+34077,
+34083,
+34090,
+34099,
+34099,
+34115,
+34115,
+34133,
+34140,
+34167,
+34172,
+34184,
+34221,
+34245,
+34252,
+34252,
+34259,
+34318,
+34318,
+34325,
+34325,
+34352,
+34400,
+34415,
+34422,
+34422,
+34431,
+34438,
+34445,
+34445,
+34473,
+34473,
+34489,
+34489,
+34489,
+34489,
+34499,
+34499,
+34499,
+34516,
+34536,
+34551,
+34564,
+34580,
+34580,
+34580,
+34589,
+34589,
+34589,
+34613,
+34648,
+34648,
+34648,
+34655,
+34664,
+34681,
+34681,
+34698,
+34698,
+34720,
+34736,
+34749,
+34749,
+34765,
+34778,
+34785,
+34795,
+34819,
+34819,
+34829,
+34841,
+34848,
+34854,
+34854,
+34854,
+34878,
+34894,
+34894,
+34900,
+34917,
+34934,
+34940,
+34970,
+34998,
+34998,
+35004,
+35004,
+35012,
+35012,
+35012,
+35020,
+35020,
+35032,
+35038,
+35062,
+35062,
+35062,
+35068,
+35068,
+35082,
+35092,
+35096,
+35107,
+35118,
+35134,
+35155,
+35155,
+35166,
+35178,
+35178,
+35195,
+35201,
+35201,
+35201,
+35226,
+35226,
+35226,
+35226,
+35256,
+35262,
+35272,
+35280,
+35299,
+35332,
+35354,
+35354,
+35354,
+35370,
+35386,
+35417,
+35417,
+35460,
+35473,
+35478,
+35495,
+35504,
+35504,
+35518,
+35552,
+35589,
+35624,
+35624,
+35637,
+35637,
+35643,
+35643,
+35669,
+35682,
+35695,
+35702,
+35709,
+35709,
+35726,
+35739,
+35749,
+35756,
+35756,
+35778,
+35803,
+35810,
+35829,
+35883,
+35899,
+35905,
+35911,
+35911,
+35923,
+35947,
+35954,
+35980,
+35987,
+36034,
+36052,
+36063,
+36095,
+36106,
+36106,
+36113,
+36120,
+36140,
+36140,
+36153,
+36160,
+36160,
+36167,
+36203,
+36203,
+36218,
+36218,
+36225,
+36253,
+36259,
+36284,
+36296,
+36310,
+36324,
+36331,
+36344,
+36367,
+36367,
+36367,
+36412,
+36412,
+36422,
+36463,
+36463,
+36463,
+36479,
+36490,
+36513,
+36520,
+36520,
+36527,
+36527,
+36527,
+36540,
+36574,
+36594,
+36594,
+36605,
+36621,
+36621,
+36641,
+36641,
+36641,
+36659,
+36682,
+36682,
+36682,
+36682,
+36705,
+36705,
+36705,
+36720,
+36720,
+36755,
+36755,
+36771,
+36771,
+36771,
+36788,
+36806,
+36835,
+36845,
+36875,
+36875,
+36903,
+36921,
+36928,
+36928,
+36940,
+36940,
+36940,
+36966,
+36966,
+36973,
+36983,
+36998,
+37004,
+37014,
+37024,
+37024,
+37032,
+37038,
+37038,
+37061,
+37074,
+37074,
+37091,
+37098,
+37105,
+37105,
+37133,
+37141,
+37141,
+37148,
+37191,
+37191,
+37197,
+37197,
+37210,
+37224,
+37224,
+37231,
+37250,
+37257,
+37273,
+37273,
+37280,
+37287,
+37294,
+37300,
+37307,
+37330,
+37348,
+37348,
+37359,
+37359,
+37359,
+37377,
+37392,
+37398,
+37412,
+37431,
+37469,
+37486,
+37508,
+37517,
+37535,
+37535,
+37542,
+37542,
+37549,
+37549,
+37549,
+37549,
+37556,
+37576,
+37576,
+37583,
+37590,
+37597,
+37604,
+37604,
+37621,
+37635,
+37676,
+37676,
+37704,
+37711,
+37728,
+37728,
+37737,
+37737,
+37737,
+37750,
+37757,
+37778,
+37785,
+37785,
+37819,
+37826,
+37833,
+37843,
+37850,
+37869,
+37914,
+37921,
+37935,
+37942,
+37949,
+37982,
+38013,
+38013,
+38013,
+38023,
+38057,
+38077,
+38097,
+38110,
+38117,
+38123,
+38133,
+38133,
+38133,
+38140,
+38140,
+38148,
+38159,
+38179,
+38192,
+38205,
+38218,
+38218,
+38218,
+38218,
+38218,
+38218,
+38218,
+38218,
+38218,
+38218,
+38218,
+38218,
+38225,
+38225,
+38230,
+38246,
+38258,
+38280,
+38287,
+38294,
+38294,
+38294,
+38301,
+38318,
+38318,
+38340,
+38371,
+38371,
+38384,
+38420,
+38440,
+38453,
+38481,
+38506,
+38522,
+38534,
+38559,
+38559,
+38559,
+38564,
+38564,
+38581,
+38604,
+38604,
+38611,
+38620,
+38626,
+38635,
+38635,
+38635,
+38666,
+38674,
+38688,
+38693,
+38710,
+38722,
+38722,
+38722,
+38729,
+38734,
+38752,
+38792,
+38818,
+38825,
+38861,
+38902,
+38934,
+38949,
+38949,
+38960,
+38969,
+38985,
+38985,
+38996,
+39013,
+39024,
+39024,
+39032,
+39061,
+39074,
+39089,
+39123,
+39123,
+39123,
+39140,
+39161,
+39180,
+39206,
+39215,
+39254,
+39261,
+39277,
+39284,
+39314,
+39314,
+39330,
+39340,
+39340,
+39371,
+39371,
+39392,
+39430,
+39430,
+39437,
+39444,
+39461,
+39468,
+39468,
+39485,
+39517,
+39524,
+39538,
+39543,
+39548,
+39555,
+39581,
+39588,
+39588,
+39609,
+39609,
+39616,
+39652,
+39670,
+39677,
+39677,
+39684,
+39691,
+39702,
+39717,
+39717,
+39717,
+39724,
+39749,
+39760,
+39766,
+39775,
+39791,
+39791,
+39814,
+39827,
+39827,
+39837,
+39859};
+
+static const char tldData[] = {
+"com.cn\0"
+"com.co\0"
+"hb.cn\0"
+"med.br\0conf.lv\0wallonie.museum\0"
+"namsos.no\0"
+"\xe7\xb6\xb2\xe7\xbb\x9c.hk\0farmers.museum\0rel.pl\0"
+"com.cu\0"
+"military.museum\0"
+"*.jm\0convent.museum\0cymru.museum\0malvik.no\0"
+"univ.sn\0"
+"gliding.aero\0"
+"wodzislaw.pl\0"
+"com.dm\0!pref.iwate.jp\0tran\xc3\xb8y.no\0pila.pl\0"
+"mb.it\0*.ke\0lib.ri.us\0"
+"com.ec\0*.kh\0tr\xc3\xb8gstad.no\0"
+"com.ee\0"
+"mobi.gp\0"
+"gran.no\0"
+"wa.gov.au\0"
+"com.dz\0kg.kr\0"
+"zoological.museum\0gjerstad.no\0haugesund.no\0kharkov.ua\0"
+"walbrzych.pl\0"
+"civilization.museum\0"
+"ha.no\0"
+"*.kw\0"
+"med.ec\0com.es\0"
+"med.ee\0otago.museum\0svelvik.no\0"
+"art.ht\0amber.museum\0elvendrell.museum\0rost.no\0"
+"jx.cn\0gratangen.no\0"
+"association.aero\0ca.it\0"
+"zaporizhzhe.ua\0"
+"com.fr\0"
+"szex.hu\0"
+"e-burg.ru\0"
+"com.ge\0bokn.no\0"
+"mordovia.ru\0"
+"com.gh\0*.mm\0"
+"com.gi\0z.se\0"
+"cahcesuolo.no\0"
+"hurdal.no\0joshkar-ola.ru\0"
+"cadaques.museum\0ma.us\0"
+"a.bg\0"
+"com.gn\0bozen.it\0tambov.ru\0"
+"*.gifu.jp\0*.tokyo.jp\0*.mt\0"
+"com.gp\0travel\0cc.tx.us\0"
+"com.gr\0hemne.no\0"
+"*.ni\0"
+"*.mz\0"
+"cc.il.us\0"
+"com.gy\0"
+"zj.cn\0oksnes.no\0museum.tt\0"
+"com.hk\0*.np\0"
+"rc.it\0baseball.museum\0"
+"com.hn\0exhibition.museum\0"
+"h\xc3\xa1""bmer.no\0"
+"com.hr\0"
+"fg.it\0stathelle.no\0defense.tn\0"
+"com.ht\0"
+"qld.gov.au\0*.nz\0"
+"davvenj\xc3\xa1rga.no\0*.om\0"
+"vang.no\0"
+"*.kumamoto.jp\0"
+"vercelli.it\0usenet.pl\0"
+"com.io\0stalbans.museum\0"
+"com.iq\0"
+"*.pg\0"
+"com.is\0klabu.no\0skiptvet.no\0"
+"med.ht\0field.museum\0"
+"gr.it\0gj\xc3\xb8vik.no\0tromsa.no\0lib.mi.us\0"
+"ca.na\0"
+"hagebostad.no\0k12.ma.us\0"
+"*.qa\0"
+"*.niigata.jp\0"
+"monzaebrianza.it\0com.jo\0comunica\xc3\xa7\xc3\xb5""es.museum\0"
+"gr.jp\0"
+"ballangen.no\0*.py\0"
+"scienceandindustry.museum\0"
+"nuoro.it\0com.kg\0"
+"com.ki\0"
+"im.it\0idv.tw\0"
+"*.akita.jp\0com.km\0r\xc3\xb8ros.no\0sopot.pl\0"
+"!pref.yamanashi.jp\0"
+"com.kp\0"
+"!pref.kochi.jp\0com.la\0"
+"com.lb\0"
+"com.lc\0stjordalshalsen.no\0sigdal.no\0cc.nm.us\0"
+"samnanger.no\0"
+"drobak.no\0"
+"vt.it\0"
+"catering.aero\0com.ky\0"
+"com.kz\0cc.ca.us\0"
+"com.lk\0"
+"grosseto.it\0mosvik.no\0"
+"namsskogan.no\0"
+"loten.no\0"
+"chirurgiens-dentistes.fr\0"
+"com.lr\0bremanger.no\0"
+"gs.cn\0"
+"com.lv\0lib.co.us\0"
+"com.mg\0"
+"passenger-association.aero\0"
+"com.ly\0yekaterinburg.ru\0"
+"vladivostok.ru\0"
+"com.mk\0beeldengeluid.museum\0"
+"com.ml\0"
+"art.pl\0"
+"com.mo\0"
+"britishcolumbia.museum\0tx.us\0"
+"com.na\0sakhalin.ru\0*.sv\0"
+"mc.it\0"
+"amsterdam.museum\0udm.ru\0"
+"com.mu\0"
+"com.mv\0com.nf\0"
+"com.mw\0com.ng\0il.us\0"
+"geometre-expert.fr\0com.mx\0"
+"med.ly\0com.my\0"
+"ag.it\0"
+"*.tr\0"
+"!pref.oita.jp\0"
+"hoyanger.no\0skedsmo.no\0"
+"com.nr\0turystyka.pl\0"
+"koebenhavn.museum\0"
+"quebec.museum\0"
+"stord.no\0*.uk\0"
+"act.au\0"
+"br.it\0cb.it\0gyeonggi.kr\0jobs.tt\0lib.hi.us\0"
+"*.ve\0"
+"*.saga.jp\0wildlife.museum\0com.pa\0"
+"monzabrianza.it\0sciencehistory.museum\0stange.no\0oskol.ru\0principe.st\0*.uy\0"
+"plaza.museum\0com.pe\0"
+"com.pf\0"
+"eigersund.no\0"
+"com.ph\0"
+"manx.museum\0marylhurst.museum\0"
+"md.ci\0pi.it\0schweiz.museum\0com.pk\0"
+"grp.lk\0fr\xc3\xb8ya.no\0com.pl\0press.se\0"
+"us.com\0"
+"b.bg\0cremona.it\0communication.museum\0art.sn\0"
+"med.pa\0"
+"com.pr\0"
+"com.ps\0"
+"com.pt\0"
+"k12.in.us\0"
+"ah.cn\0bahcavuotna.no\0"
+"sondrio.it\0arkhangelsk.ru\0"
+"cargo.aero\0"
+"council.aero\0"
+"museum.mv\0hattfjelldal.no\0spydeberg.no\0med.pl\0"
+"niepce.museum\0museum.mw\0"
+"anthropology.museum\0"
+"pharmacien.fr\0smola.no\0"
+"fin.ec\0"
+"selbu.no\0"
+"workinggroup.aero\0nm.us\0"
+"museum.no\0com.re\0"
+"cc.vt.us\0"
+"village.museum\0"
+"ca.us\0"
+"*.sapporo.jp\0"
+"teramo.it\0"
+"com.ro\0"
+"*.ye\0"
+"com.sa\0"
+"com.sb\0"
+"so.it\0com.sc\0"
+"jolster.no\0com.sd\0"
+"com.ru\0"
+"com.rw\0com.sg\0"
+"sydney.museum\0"
+"sa.edu.au\0"
+"tom.ru\0"
+"com.sl\0*.za\0"
+"\xe7\xbd\x91\xe7\xb5\xa1.hk\0naturbruksgymn.se\0com.sn\0"
+"assedic.fr\0com.so\0"
+"!pref.mie.jp\0*.yu\0"
+"med.sa\0"
+"newspaper.museum\0holmestrand.no\0dnepropetrovsk.ua\0"
+"christiansburg.museum\0roan.no\0"
+"pesaro-urbino.it\0med.sd\0com.st\0"
+"s\xc3\xb8gne.no\0"
+"nuernberg.museum\0"
+"*.zm\0"
+"com.sy\0"
+"*.nagano.jp\0com.tj\0"
+"nt.gov.au\0news.hu\0paderborn.museum\0"
+"boston.museum\0"
+"com.tn\0"
+"com.to\0"
+"broadcast.museum\0"
+"com.ua\0"
+"*.zw\0"
+"baikal.ru\0"
+"bykle.no\0com.tt\0"
+"verdal.no\0"
+"roros.no\0"
+"fi.cr\0carboniaiglesias.it\0chuvashia.ru\0com.tw\0"
+"k12.ca.us\0"
+"eidsvoll.no\0"
+"*.ishikawa.jp\0"
+"dolls.museum\0"
+"naval.museum\0"
+"karasjok.no\0tysvar.no\0"
+"bielawa.pl\0com.vc\0"
+"svalbard.no\0deatnu.no\0rnd.ru\0"
+"grandrapids.museum\0"
+"bauern.museum\0k12.pr.us\0"
+"press.ma\0"
+"*.kagawa.jp\0fribourg.museum\0przeworsk.pl\0com.vi\0"
+"com.uz\0"
+"babia-gora.pl\0"
+"com.vn\0"
+"med.pro\0"
+"suedtirol.it\0kursk.ru\0"
+"bonn.museum\0"
+"lt.it\0"
+"design.aero\0microlight.aero\0americanantiques.museum\0meland.no\0"
+"insurance.aero\0aarborte.no\0"
+"kh.ua\0"
+"macerata.it\0architecture.museum\0"
+"rovigo.it\0rawa-maz.pl\0"
+"store.nf\0levanger.no\0"
+"b\xc3\xa1jddar.no\0"
+"not.br\0"
+"com.ws\0"
+"!pref.kagawa.jp\0"
+"!omanpost.om\0"
+"vt.us\0"
+"gs.ah.no\0vladikavkaz.ru\0"
+"no.it\0"
+"in.na\0szkola.pl\0a.se\0"
+"aid.pl\0"
+"workshop.museum\0vegarshei.no\0"
+"sund.no\0"
+"bs.it\0flora.no\0"
+"agriculture.museum\0"
+"koeln.museum\0"
+"minnesota.museum\0k12.il.us\0"
+"froya.no\0"
+"aeroport.fr\0"
+"davvenjarga.no\0zgora.pl\0ivano-frankivsk.ua\0"
+"*.gunma.jp\0"
+"amot.no\0"
+"mus.br\0chungbuk.kr\0"
+"ggf.br\0lorenskog.no\0"
+"jeonbuk.kr\0"
+"k12.vi.us\0"
+"c.bg\0sande.more-og-romsdal.no\0"
+"perugia.it\0"
+"massa-carrara.it\0"
+"michigan.museum\0"
+"archaeology.museum\0mosj\xc3\xb8""en.no\0czest.pl\0koenig.ru\0\xe0\xb6\xbd\xe0\xb6\x82\xe0\xb6\x9a\xe0\xb7\x8f\0"
+"mobi.tt\0"
+"kraanghke.no\0"
+"cc.in.us\0"
+"re.it\0lib.vt.us\0"
+"dell-ogliastra.it\0"
+"s\xc3\xb8mna.no\0"
+"k12.wv.us\0"
+"gok.pk\0fh.se\0"
+"luzern.museum\0"
+"fi.it\0swidnica.pl\0"
+"cbg.ru\0"
+"latina.it\0"
+"vibovalentia.it\0"
+"modum.no\0"
+"safety.aero\0"
+"sp.it\0"
+"science.museum\0ah.no\0"
+"norddal.no\0"
+"cc.na\0"
+"re.kr\0"
+"dielddanuorri.no\0"
+"force.museum\0"
+"torino.it\0cc.md.us\0"
+"artanddesign.museum\0pisz.pl\0"
+"olsztyn.pl\0"
+"unsa.ba\0rade.no\0vinnica.ua\0"
+"in.rs\0astrakhan.ru\0"
+"sogne.no\0"
+"homebuilt.aero\0"
+"polkowice.pl\0"
+"hole.no\0health.vn\0"
+"fj.cn\0"
+"davvesiida.no\0"
+"vic.au\0"
+"kongsberg.no\0"
+"pub.sa\0"
+"vv.it\0"
+"!pref.tottori.jp\0"
+"*.sendai.jp\0in.th\0"
+"lib.pa.us\0"
+"chiropractic.museum\0"
+"mobi.na\0aca.pro\0"
+"konyvelo.hu\0sciencecenters.museum\0"
+"he.cn\0"
+"in.ua\0"
+"!city.nagoya.jp\0"
+"muenchen.museum\0"
+"psi.br\0"
+"maryland.museum\0"
+"!statecouncil.om\0"
+"tr\xc3\xa6na.no\0"
+"!pref.yamagata.jp\0jewishart.museum\0"
+"lu.it\0me.it\0"
+"chel.ru\0"
+"tatarstan.ru\0"
+"adult.ht\0in.us\0"
+"kafjord.no\0"
+"\xd7\x99\xd7\xa8\xd7\x95\xd7\xa9\xd7\x9c\xd7\x99\xd7\x9d.museum\0"
+"net.ac\0k12.ec\0"
+"net.ae\0bashkiria.ru\0"
+"net.af\0!omantel.om\0"
+"net.ag\0"
+"net.ai\0"
+"!pref.toyama.jp\0"
+"net.al\0timekeeping.museum\0"
+"net.an\0design.museum\0fin.tn\0"
+"ethnology.museum\0"
+"perso.ht\0asker.no\0b.se\0"
+"net.ba\0"
+"net.bb\0flanders.museum\0"
+"mincom.tn\0"
+"frana.no\0"
+"bt.it\0"
+"net.bh\0"
+"auto.pl\0"
+"net.az\0"
+"treviso.it\0"
+"war.museum\0"
+"net.bm\0"
+"langevag.no\0m\xc3\xa5lselv.no\0"
+"net.bo\0"
+"gol.no\0"
+"folkebibl.no\0"
+"net.br\0"
+"net.bs\0troandin.no\0saotome.st\0lib.tn.us\0"
+"md.us\0k12.ut.us\0"
+"d.bg\0cambridge.museum\0\xc3\xa5s.no\0"
+"net.ci\0"
+"net.bz\0"
+"sch.ae\0undersea.museum\0odda.no\0"
+"net.cn\0"
+"net.co\0c.la\0"
+"gliwice.pl\0"
+"aurskog-h\xc3\xb8land.no\0"
+"andria-trani-barletta.it\0"
+"net.cu\0loab\xc3\xa1t.no\0"
+"rep.kp\0"
+"\xe7\xbb\x84\xe7\xb9\x94.hk\0"
+"gallery.museum\0"
+"\xc3\xb8rland.no\0"
+"store.ro\0"
+"net.dm\0"
+"somna.no\0"
+"hemnes.no\0"
+"ringebu.no\0k12.ky.us\0"
+"net.ec\0"
+"dn.ua\0"
+"tarnobrzeg.pl\0"
+"soc.lk\0"
+"romsa.no\0"
+"bamble.no\0"
+"net.dz\0lutsk.ua\0"
+"barlettatraniandria.it\0ta.it\0countryestate.museum\0"
+"kaszuby.pl\0"
+"*.yamaguchi.jp\0cranbrook.museum\0store.st\0"
+"southcarolina.museum\0lib.md.us\0"
+"textile.museum\0"
+"cheltenham.museum\0hurum.no\0"
+"*.oita.jp\0"
+"shop.ht\0cc.me.us\0"
+"shop.hu\0turin.it\0"
+"louvre.museum\0"
+"k12.ar.us\0"
+"consulting.aero\0"
+"gv.ao\0"
+"sauherad.no\0"
+"gv.at\0net.ge\0"
+"ostre-toten.no\0lib.ok.us\0"
+"net.gg\0pilots.museum\0"
+"2000.hu\0geology.museum\0"
+"net.gn\0"
+"mazowsze.pl\0bir.ru\0"
+"net.gp\0"
+"net.gr\0"
+"oxford.museum\0"
+"per.la\0"
+"eastafrica.museum\0"
+"meeres.museum\0"
+"net.gy\0*.shizuoka.jp\0"
+"\xe5\x95\x86\xe6\xa5\xad.tw\0"
+"net.hk\0"
+"net.hn\0"
+"philadelphiaarea.museum\0"
+"osen.no\0"
+"net.ht\0net.id\0"
+"fundacio.museum\0"
+"j\xc3\xb8rpeland.no\0"
+"\xe6\x95\x99\xe8\x82\xb2.hk\0"
+"divtasvuodna.no\0"
+"student.aero\0sch.gg\0net.im\0"
+"\xe7\xbd\x91\xe7\xbb\x9c.cn\0net.in\0"
+"net.iq\0"
+"net.ir\0"
+"net.is\0"
+"net.je\0"
+"kepno.pl\0lapy.pl\0"
+"per.nf\0"
+"gov\0*.shimane.jp\0"
+"artcenter.museum\0"
+"k\xc3\xa5""fjord.no\0"
+"net.jo\0"
+"eu.int\0"
+"c.se\0"
+"net.kg\0"
+"ce.it\0net.ki\0"
+"sch.id\0os.hedmark.no\0"
+"columbus.museum\0"
+"arteducation.museum\0"
+"net.kn\0"
+"kr.com\0"
+"net.la\0bushey.museum\0cc.gu.us\0"
+"net.lb\0"
+"net.lc\0"
+"gs.bu.no\0"
+"e164.arpa\0"
+"chieti.it\0labour.museum\0"
+"sch.ir\0creation.museum\0krodsherad.no\0"
+"net.ky\0"
+"net.kz\0me.us\0"
+"e.bg\0sch.je\0net.lk\0"
+"zlg.br\0suwalki.pl\0"
+"\xe5\x80\x8b\xe4\xba\xba.hk\0net.ma\0"
+"net.lr\0"
+"sch.jo\0notaires.km\0net.me\0"
+"net.lv\0karate.museum\0"
+"net.ly\0karm\xc3\xb8y.no\0"
+"rg.it\0"
+"net.mk\0"
+"net.ml\0evenes.no\0"
+"ngo.lk\0net.mo\0egyptian.museum\0"
+"marine.ru\0"
+"realestate.pl\0"
+"net.mu\0"
+"net.mv\0net.nf\0"
+"net.mw\0net.ng\0gda.pl\0"
+"net.mx\0"
+"freemasonry.museum\0net.my\0enebakk.no\0"
+"karlsoy.no\0"
+"\xe7\xbd\x91\xe7\xbb\x9c.hk\0\xc3\xb8rskog.no\0"
+"randaberg.no\0"
+"club.aero\0"
+"certification.aero\0sr.it\0"
+"center.museum\0so.gov.pl\0"
+"caa.aero\0"
+"sch.lk\0tvedestrand.no\0"
+"net.nr\0"
+"luroy.no\0"
+"aukra.no\0s\xc3\xa1lat.no\0lib.me.us\0"
+"ddr.museum\0"
+"york.museum\0stryn.no\0k12.nm.us\0"
+"per.sg\0"
+"judaica.museum\0"
+"verona.it\0"
+"agdenes.no\0"
+"cng.br\0sch.ly\0"
+"net.pa\0"
+"author.aero\0"
+"naturalhistory.museum\0steiermark.museum\0bu.no\0"
+"sn\xc3\xa5sa.no\0net.pe\0"
+"net.ph\0"
+"savannahga.museum\0batsfjord.no\0lib.oh.us\0"
+"net.pk\0"
+"net.pl\0"
+"net.pn\0"
+"washingtondc.museum\0"
+"net.pr\0"
+"net.ps\0"
+"net.pt\0"
+"nordkapp.no\0"
+"emergency.aero\0krokstadelva.no\0"
+"satx.museum\0ngo.ph\0omsk.ru\0"
+"texas.museum\0"
+"ngo.pl\0"
+"mantova.it\0gu.us\0"
+"!pref.shiga.jp\0isa.us\0"
+"usa.museum\0"
+"gb.net\0k12.vi\0"
+"iveland.no\0"
+"tempio-olbia.it\0"
+"net.sa\0"
+"net.sb\0"
+"works.aero\0net.sc\0komvux.se\0"
+"net.sd\0"
+"net.ru\0"
+"0.bg\0"
+"forlicesena.it\0net.rw\0net.sg\0"
+"klodzko.pl\0"
+"detroit.museum\0wegrow.pl\0"
+"net.sl\0"
+"glogow.pl\0"
+"store.bb\0air.museum\0"
+"net.so\0"
+"katowice.pl\0"
+"nsk.ru\0"
+"pisa.it\0eid.no\0"
+"net.st\0"
+"film.hu\0"
+"tuva.ru\0d.se\0"
+"net.th\0"
+"net.sy\0"
+"viterbo.it\0tsaritsyn.ru\0perso.sn\0net.tj\0"
+"lib.gu.us\0"
+"plc.co.im\0sec.ps\0"
+"r\xc3\xa1hkker\xc3\xa1vju.no\0kazimierz-dolny.pl\0net.tn\0"
+"net.to\0"
+"veterinaire.km\0"
+"net.ua\0"
+"info.ht\0net.tt\0"
+"info.hu\0"
+"exchange.aero\0"
+"sch.sa\0net.tw\0"
+"andriatranibarletta.it\0perso.tn\0"
+"f.bg\0malselv.no\0"
+"net.vc\0"
+"trana.no\0"
+"ns.ca\0"
+"net.vi\0"
+"lucca.it\0oristano.it\0"
+"usarts.museum\0net.vn\0"
+"gon.pk\0"
+"pl.ua\0"
+"eastcoast.museum\0"
+"novara.it\0"
+"k12.ks.us\0"
+"dp.ua\0"
+"nesseby.no\0"
+"!pref.wakayama.jp\0"
+"repbody.aero\0"
+"jamison.museum\0lugansk.ua\0"
+"ss.it\0"
+"alessandria.it\0"
+"hadsel.no\0net.ws\0"
+"\xe0\xae\x9a\xe0\xae\xbf\xe0\xae\x99\xe0\xaf\x8d\xe0\xae\x95\xe0\xae\xaa\xe0\xaf\x8d\xe0\xae\xaa\xe0\xaf\x82\xe0\xae\xb0\xe0\xaf\x8d\0"
+"veterinaire.fr\0leirfjord.no\0"
+"massacarrara.it\0north.museum\0"
+"project.museum\0"
+"other.nf\0"
+"k12.nh.us\0"
+"mat.br\0artgallery.museum\0"
+"sr.gov.pl\0"
+"gamvik.no\0"
+"info.ec\0lancashire.museum\0"
+"fm.br\0ltd.co.im\0"
+"americana.museum\0southwest.museum\0cc.ak.us\0"
+"enna.it\0lunner.no\0"
+"v\xc3\xa5gan.no\0"
+"mari.ru\0"
+"accident-investigation.aero\0"
+"sor-aurdal.no\0lib.ny.us\0"
+"novosibirsk.ru\0"
+"bjugn.no\0"
+"n\xc3\xa6r\xc3\xb8y.no\0ostrowwlkp.pl\0"
+"info.bb\0foundation.museum\0"
+"brand.se\0"
+"info.at\0!pref.akita.jp\0l\xc3\xb8ten.no\0"
+"coal.museum\0miners.museum\0"
+"glass.museum\0"
+"info.az\0"
+"frog.museum\0szczytno.pl\0nov.ru\0"
+"sunndal.no\0"
+"gen.in\0"
+"gx.cn\0"
+"web.co\0*.mie.jp\0hobol.no\0\xe5\x8f\xb0\xe6\xb9\xbe\0"
+"logistics.aero\0plo.ps\0"
+"erotika.hu\0"
+"torsken.no\0"
+"exeter.museum\0"
+"info.co\0"
+"selje.no\0"
+"storfjord.no\0"
+"barum.no\0lind\xc3\xa5s.no\0"
+"leasing.aero\0"
+"championship.aero\0fst.br\0"
+"lierne.no\0"
+"!gobiernoelectronico.ar\0""1.bg\0"
+"corporation.museum\0"
+"al.it\0*.miyagi.jp\0"
+"*.aomori.jp\0"
+"\xd8\xa7\xd9\x84\xd8\xa7\xd8\xb1\xd8\xaf\xd9\x86\0"
+"amursk.ru\0"
+"vestvagoy.no\0"
+"\xd8\xa7\xdb\x8c\xd8\xb1\xd8\xa7\xd9\x86.ir\0cc.fl.us\0"
+"os.hordaland.no\0"
+"pistoia.it\0"
+"tver.ru\0e.se\0"
+"res.in\0*.yamagata.jp\0syzran.ru\0"
+"capebreton.museum\0sandnessj\xc3\xb8""en.no\0"
+"ternopil.ua\0"
+"shop.pl\0"
+"tank.museum\0"
+"m\xc3\xa5s\xc3\xb8y.no\0"
+"potenza.it\0time.museum\0"
+"mjondalen.no\0"
+"eng.br\0nedre-eiker.no\0"
+"air-surveillance.aero\0"
+"nt.au\0am.br\0pn.it\0"
+"oystre-slidre.no\0ug.gov.pl\0"
+"g.bg\0nesodden.no\0vologda.ru\0"
+"parma.it\0tula.ru\0"
+"*.nara.jp\0ak.us\0"
+"nt.ca\0konin.pl\0"
+"kiev.ua\0"
+"skierv\xc3\xa1.no\0vestre-toten.no\0"
+"ri.it\0botanical.museum\0farsund.no\0veg\xc3\xa5rshei.no\0dagestan.ru\0"
+"ind.br\0k-uralsk.ru\0"
+"rahkkeravju.no\0cmw.ru\0"
+"canada.museum\0"
+"fm.it\0"
+"cc.wi.us\0"
+"web.id\0aver\xc3\xb8y.no\0"
+"dudinka.ru\0"
+"baghdad.museum\0fitjar.no\0grane.no\0"
+"gs.fm.no\0"
+"sumy.ua\0"
+"al.no\0"
+"westfalen.museum\0"
+"oregon.museum\0"
+"bruxelles.museum\0elk.pl\0"
+"planetarium.museum\0sn\xc3\xa5""ase.no\0"
+"s\xc3\xb8rreisa.no\0"
+"gs.st.no\0skien.no\0"
+"bible.museum\0ivanovo.ru\0"
+"avellino.it\0"
+"tgory.pl\0"
+"family.museum\0"
+"ppg.br\0k12.as.us\0"
+"trader.aero\0gorlice.pl\0"
+"cc.al.us\0"
+"ogliastra.it\0"
+"is.it\0lib.nv.us\0"
+"dr.na\0"
+"media.hu\0nesna.no\0fl.us\0"
+"uri.arpa\0"
+"bjerkreim.no\0"
+"charter.aero\0"
+"genova.it\0"
+"it.ao\0botany.museum\0hapmir.no\0"
+"educational.museum\0"
+"helsinki.museum\0"
+"memorial.museum\0"
+"web.lk\0pharmacy.museum\0"
+"aircraft.aero\0appspot.com\0"
+"ferrara.it\0beskidy.pl\0"
+"hi.cn\0"
+"taxi.aero\0flekkefjord.no\0"
+"varoy.no\0"
+"ragusa.it\0ambulance.museum\0"
+"can.museum\0"
+"*.osaka.jp\0isleofman.museum\0fm.no\0warmia.pl\0"
+"educator.aero\0asmatart.museum\0"
+"mi.it\0"
+"kutno.pl\0"
+"skedsmokorset.no\0"
+"2.bg\0"
+"*.kagoshima.jp\0km.ua\0"
+"!city.sendai.jp\0"
+"web.nf\0st.no\0cc.ri.us\0"
+"reggiocalabria.it\0"
+"wi.us\0"
+"ancona.it\0newjersey.museum\0nnov.ru\0"
+"f.se\0"
+"ind.in\0"
+"info.vn\0"
+"andoy.no\0"
+"ch.it\0fredrikstad.no\0guovdageaidnu.no\0"
+"fjaler.no\0"
+"sa.com\0"
+"gs.nt.no\0"
+"masfjorden.no\0"
+"pordenone.it\0"
+"po.it\0basel.museum\0"
+"chambagri.fr\0"
+"h.bg\0web.pk\0"
+"london.museum\0"
+"sciencecenter.museum\0\xe0\xb9\x84\xe0\xb8\x97\xe0\xb8\xa2\0"
+"unbi.ba\0augustow.pl\0"
+"wolomin.pl\0"
+"notaires.fr\0tcm.museum\0al.us\0"
+"nu.ca\0!pref.nagano.jp\0"
+"info.tn\0"
+"lib.wa.us\0"
+"ed.ao\0info.tt\0"
+"barreau.bj\0"
+"k12.wy.us\0"
+"pp.az\0gop.pk\0"
+"int\0"
+"l\xc3\xb8renskog.no\0podhale.pl\0"
+"voagat.no\0"
+"telekommunikation.museum\0"
+"qld.au\0"
+"te.it\0freiburg.museum\0snasa.no\0"
+"gjemnes.no\0"
+"sejny.pl\0"
+"media.pl\0"
+"skjak.no\0"
+"watchandclock.museum\0"
+"ed.ci\0pacific.museum\0"
+"theater.museum\0info.ro\0"
+"uk.com\0"
+"campobasso.it\0aquarium.museum\0tysv\xc3\xa6r.no\0"
+"kragero.no\0"
+"windmill.museum\0info.sd\0"
+"sologne.museum\0sande.m\xc3\xb8re-og-romsdal.no\0"
+"nt.no\0cc.mi.us\0"
+"ed.cr\0"
+"academy.museum\0zachpomor.pl\0"
+"tananger.no\0v\xc3\xa1rgg\xc3\xa1t.no\0ri.us\0"
+"federation.aero\0"
+"web.tj\0"
+"matta-varjjat.no\0"
+"steigen.no\0"
+"local\0akrehamn.no\0"
+"!pref.chiba.jp\0info.pk\0"
+"info.pl\0""6bone.pl\0"
+"klepp.no\0kherson.ua\0"
+"ketrzyn.pl\0info.pr\0"
+"sweden.museum\0"
+"lardal.no\0"
+"!retina.ar\0gz.cn\0"
+"barletta-trani-andria.it\0vikna.no\0"
+"bearalv\xc3\xa1hki.no\0"
+"broker.aero\0gov.nc.tr\0"
+"info.na\0k12.fl.us\0"
+"hembygdsforbund.museum\0"
+"entertainment.aero\0jerusalem.museum\0l\xc3\xa6rdal.no\0"
+"hitra.no\0sogndal.no\0"
+"farmequipment.museum\0info.mv\0info.nf\0\xc3\xa5lg\xc3\xa5rd.no\0"
+"la-spezia.it\0"
+"skanland.no\0fam.pk\0"
+"skole.museum\0"
+"art.museum\0"
+"presidio.museum\0"
+"3.bg\0public.museum\0"
+"h\xc3\xb8yanger.no\0zagan.pl\0"
+"an.it\0"
+"philadelphia.museum\0info.nr\0"
+"pesarourbino.it\0g\xc3\xa1ivuotna.no\0"
+"poltava.ua\0"
+"nt.ro\0"
+"station.museum\0"
+"mi.th\0"
+"altoadige.it\0"
+"nu.it\0"
+"usculture.museum\0g.se\0"
+"h\xc3\xa1mm\xc3\xa1rfeasta.no\0"
+"daegu.kr\0info.la\0"
+"dovre.no\0"
+"ci.it\0horology.museum\0"
+"bergbau.museum\0"
+"press.museum\0"
+"gangwon.kr\0"
+"!city.kitakyushu.jp\0sor-varanger.no\0cc.hi.us\0"
+"fuossko.no\0"
+"zp.ua\0"
+"american.museum\0"
+"fl\xc3\xa5.no\0mi.us\0"
+"i.bg\0"
+"od.ua\0"
+"encyclopedic.museum\0"
+"ind.tn\0"
+"midatlantic.museum\0"
+"newyork.museum\0"
+"castres.museum\0"
+"act.edu.au\0"
+"topology.museum\0"
+"ed.jp\0"
+"of.by\0"
+"iris.arpa\0inf.br\0askim.no\0pyatigorsk.ru\0"
+"nord-fron.no\0nsn.us\0"
+"beardu.no\0"
+"agrar.hu\0corvette.museum\0chtr.k12.ma.us\0"
+"figueres.museum\0"
+"!pref.gunma.jp\0medizinhistorisches.museum\0"
+"tjeldsund.no\0"
+"nebraska.museum\0"
+"bellevue.museum\0"
+"abo.pa\0k12.al.us\0"
+"info.ki\0"
+"inf.cu\0sv.it\0"
+"jfk.museum\0"
+"!city.osaka.jp\0swinoujscie.pl\0"
+"bydgoszcz.pl\0"
+"!city.kyoto.jp\0"
+"uvic.museum\0"
+"madrid.museum\0steinkjer.no\0"
+"lib.ma.us\0"
+"sirdal.no\0"
+"n\xc3\xb8tter\xc3\xb8y.no\0"
+"taranto.it\0starnberg.museum\0"
+"vic.gov.au\0pvt.ge\0pors\xc3\xa1\xc5\x8bgu.no\0"
+"naroy.no\0ris\xc3\xb8r.no\0"
+"va.it\0salem.museum\0starachowice.pl\0"
+"!nawrastelecom.om\0"
+"town.museum\0te.ua\0"
+"se.net\0"
+"kemerovo.ru\0"
+"lerdal.no\0"
+"gs.va.no\0"
+"kms.ru\0"
+"consulado.st\0"
+"haram.no\0"
+"tysnes.no\0"
+"!pref.ibaraki.jp\0hamburg.museum\0"
+"\xc3\xa5rdal.no\0"
+"airline.aero\0"
+"crew.aero\0newhampshire.museum\0"
+"muenster.museum\0"
+"aerodrome.aero\0"
+"heroy.nordland.no\0belau.pw\0"
+"kamchatka.ru\0"
+"b\xc3\xa5""d\xc3\xa5""ddj\xc3\xa5.no\0lillehammer.no\0hi.us\0"
+"hk.cn\0"
+"!city.kobe.jp\0berlevag.no\0"
+"ardal.no\0"
+"askoy.no\0"
+"vardo.no\0"
+"fyresdal.no\0"
+"sassari.it\0"
+"video.hu\0drammen.no\0"
+"lyngen.no\0nakhodka.ru\0"
+"ip6.arpa\0games.hu\0"
+"online.museum\0"
+"k12.sd.us\0"
+"4.bg\0sebastopol.ua\0"
+"ao.it\0atlanta.museum\0"
+"lebork.pl\0"
+"ravenna.it\0"
+"railway.museum\0songdalen.no\0"
+"!pref.shimane.jp\0delaware.museum\0ed.pw\0"
+"f\xc3\xb8rde.no\0"
+"living.museum\0"
+"juif.museum\0"
+"lomza.pl\0"
+"h.se\0"
+"!bl.uk\0"
+"portland.museum\0\xe7\xb5\x84\xe7\xb9\x94.tw\0"
+"stj\xc3\xb8rdal.no\0"
+"lecce.it\0"
+"bz.it\0"
+"farmstead.museum\0va.no\0"
+"express.aero\0!nacion.ar\0"
+"presse.km\0gs.of.no\0"
+"\xe5\x8f\xb0\xe7\x81\xa3\0"
+"og.ao\0gyeongbuk.kr\0vestv\xc3\xa5g\xc3\xb8y.no\0"
+"prd.fr\0"
+"pp.ru\0pp.se\0"
+"forum.hu\0!pref.saga.jp\0"
+"kvalsund.no\0"
+"!city.kawasaki.jp\0n\xc3\xa5\xc3\xa5mesjevuemie.no\0"
+"j.bg\0"
+"vlaanderen.museum\0"
+"cc.va.us\0"
+"\xd8\xa7\xd9\x8a\xd8\xb1\xd8\xa7\xd9\x86.ir\0alabama.museum\0"
+"school.museum\0her\xc3\xb8y.m\xc3\xb8re-og-romsdal.no\0"
+"\xc3\xa5seral.no\0"
+"traniandriabarletta.it\0"
+"flog.br\0"
+"presse.ml\0"
+"k\xc3\xa1r\xc3\xa1\xc5\xa1johka.no\0"
+"historisch.museum\0"
+"farm.museum\0palmsprings.museum\0oslo.no\0dyroy.no\0stranda.no\0"
+"gs.rl.no\0r\xc3\xa5""de.no\0"
+"bomlo.no\0s\xc3\xb8rum.no\0"
+"jan-mayen.no\0ivgu.no\0"
+"coop\0"
+"agr.br\0k12.ak.us\0"
+"!nic.ar\0catanzaro.it\0fusa.no\0"
+"hu.com\0"
+"inf.mk\0"
+"vet.br\0"
+"k12.mt.us\0k12.nd.us\0"
+"vlog.br\0\xe5\x85\xac\xe5\x8f\xb8.cn\0sandnessjoen.no\0"
+"lib.az.us\0"
+"nsw.edu.au\0of.no\0\xc3\xb8stre-toten.no\0"
+"*.okinawa.jp\0"
+"vb.it\0"
+"asso.fr\0firenze.it\0"
+"trieste.it\0"
+"\xe5\x85\xac\xe5\x8f\xb8.hk\0"
+"museet.museum\0"
+"prd.km\0"
+"navuotna.no\0lib.ca.us\0"
+"cc.nv.us\0"
+"asso.gp\0"
+"meraker.no\0"
+"h\xc3\xa1pmir.no\0"
+"i.ph\0"
+"sx.cn\0jeonnam.kr\0"
+"halden.no\0"
+"fed.us\0"
+"medio-campidano.it\0tsk.ru\0"
+"barcelona.museum\0"
+"giessen.museum\0roma.museum\0"
+"hl.cn\0"
+"\xe0\xae\x87\xe0\xae\xb2\xe0\xae\x99\xe0\xaf\x8d\xe0\xae\x95\xe0\xaf\x88\0"
+"biz.bb\0benevento.it\0rl.no\0bygland.no\0"
+"port.fr\0asso.ht\0prd.mg\0"
+"biz.at\0"
+"tra.kp\0"
+"*.aichi.jp\0khabarovsk.ru\0"
+"campidano-medio.it\0"
+"biz.az\0"
+"newmexico.museum\0va.us\0"
+"finearts.museum\0"
+"murmansk.ru\0"
+"\xc3\xb8rsta.no\0radom.pl\0k12.sc.us\0"
+"5.bg\0kvinesdal.no\0"
+"ap.it\0"
+"*.fukushima.jp\0"
+"asso.bj\0"
+"mad.museum\0"
+"lebesby.no\0"
+"og.it\0glas.museum\0sauda.no\0"
+"i.se\0"
+"k12.tx.us\0"
+"asso.ci\0mk.ua\0"
+"cesena-forli.it\0"
+"lowicz.pl\0"
+"k12.id.us\0"
+"tas.gov.au\0"
+"lukow.pl\0"
+"utazas.hu\0"
+"maritimo.museum\0bjark\xc3\xb8y.no\0"
+"adm.br\0"
+"pr.it\0lib.vi.us\0"
+"bergamo.it\0k12.va.us\0"
+"k.bg\0"
+"railroad.museum\0"
+"!british-library.uk\0"
+"cincinnati.museum\0"
+"sorreisa.no\0"
+"asso.dz\0!nel.uk\0"
+"rm.it\0"
+"nv.us\0"
+"nx.cn\0gos.pk\0"
+"vic.edu.au\0"
+"biella.it\0tjome.no\0"
+"r\xc3\xb8yken.no\0"
+"beiarn.no\0"
+"qc.ca\0"
+"georgia.museum\0square.museum\0"
+"labor.museum\0omasvuotna.no\0cc.la.us\0"
+"br.com\0reggioemilia.it\0"
+"kristiansund.no\0"
+"sorum.no\0"
+"orsta.no\0"
+"furniture.museum\0surrey.museum\0eng.pro\0"
+"asn.lv\0balat.no\0"
+"lavangen.no\0sld.pa\0"
+"fla.no\0k12.ms.us\0k12.nc.us\0"
+"bardu.no\0"
+"donostia.museum\0"
+"club.tw\0"
+"elburg.museum\0"
+"gs.hl.no\0lodingen.no\0"
+"samara.ru\0"
+"vc.it\0*.nagasaki.jp\0"
+"fosnes.no\0"
+"fuel.aero\0"
+"qc.com\0"
+"skjervoy.no\0"
+"bill.museum\0kv\xc3\xa6""fjord.no\0"
+"skydiving.aero\0*.tokushima.jp\0"
+"!congresodelalengua3.ar\0laquila.it\0k12.ct.us\0"
+"gorge.museum\0linz.museum\0sherbrooke.museum\0"
+"tranoy.no\0ing.pa\0"
+"ptz.ru\0"
+"kr.it\0prato.it\0stat.no\0"
+"\xd0\xb8\xd0\xba\xd0\xbe\xd0\xbc.museum\0"
+"cosenza.it\0"
+"stj\xc3\xb8rdalshalsen.no\0"
+"finland.museum\0leka.no\0cc.pr.us\0"
+"historichouses.museum\0s\xc3\xa1l\xc3\xa1t.no\0"
+"venice.it\0"
+"biz.ki\0"
+"g\xc3\xa1ls\xc3\xa1.no\0"
+"\xe7\xbb\x84\xe7\xbb\x87.hk\0"
+"*.yamanashi.jp\0"
+"rad\xc3\xb8y.no\0"
+"6.bg\0"
+"fareast.ru\0"
+"paragliding.aero\0ba.it\0aq.it\0"
+"sk\xc3\xa5nland.no\0"
+"its.me\0"
+"us.na\0"
+"hl.no\0cc.ga.us\0"
+"ac\0granvin.no\0"
+"ad\0qld.edu.au\0!city.sapporo.jp\0"
+"ae\0"
+"af\0"
+"ag\0crotone.it\0"
+"dallas.museum\0"
+"ai\0brussels.museum\0"
+"dali.museum\0"
+"la.us\0"
+"al\0salzburg.museum\0"
+"am\0"
+"an\0cl.it\0"
+"ao\0"
+"aq\0ba\0"
+"bb\0"
+"as\0lajolla.museum\0"
+"at\0"
+"be\0"
+"bf\0inderoy.no\0snz.ru\0"
+"aw\0bg\0"
+"ax\0bh\0cim.br\0ltd.gi\0biz.mv\0"
+"bi\0xz.cn\0\xe7\xb5\x84\xe7\xb9\x94.hk\0biz.mw\0"
+"az\0bj\0"
+"bm\0tranibarlettaandria.it\0naamesjevuemie.no\0"
+"chattanooga.museum\0"
+"bo\0"
+"l.bg\0"
+"ca\0"
+"br\0stateofdelaware.museum\0"
+"bs\0cc\0"
+"cd\0biz.nr\0"
+"cf\0berlev\xc3\xa5g.no\0"
+"bw\0cg\0snaase.no\0"
+"ch\0harvestcelebration.museum\0ck.ua\0"
+"by\0ci\0"
+"bz\0bahccavuotna.no\0"
+"cl\0yuzhno-sakhalinsk.ru\0"
+"cm\0halsa.no\0lyngdal.no\0"
+"cn\0"
+"co\0rn.it\0childrens.museum\0frankfurt.museum\0"
+"cr\0"
+"pskov.ru\0"
+"cu\0de\0"
+"cv\0fr.it\0lib.ky.us\0"
+"aseral.no\0kvam.no\0"
+"cx\0hellas.museum\0"
+"hof.no\0"
+"cz\0dj\0k12.la.us\0"
+"dk\0moscow.museum\0"
+"sosnowiec.pl\0"
+"dm\0biz.pk\0"
+"schokoladen.museum\0biz.pl\0"
+"far.br\0arna.no\0tynset.no\0"
+"even\xc3\xa1\xc5\xa1\xc5\xa1i.no\0"
+"ec\0"
+"biz.pr\0"
+"ee\0celtic.museum\0"
+"scientist.aero\0modern.museum\0"
+"pr.us\0"
+"dz\0"
+"mj\xc3\xb8ndalen.no\0s\xc3\xb8r-odal.no\0"
+"!nic.tr\0"
+"conference.aero\0vestnes.no\0k12.mn.us\0"
+"!pref.hiroshima.jp\0"
+"es\0trapani.it\0"
+"fermo.it\0vard\xc3\xb8.no\0"
+"eu\0gs.hm.no\0r\xc3\xb8""d\xc3\xb8y.no\0stordal.no\0"
+"gc.ca\0!nhs.uk\0"
+"jgora.pl\0"
+"fi\0stjordal.no\0"
+"fm\0!mediaphone.om\0"
+"kirov.ru\0pvt.k12.ma.us\0"
+"fo\0"
+"ga\0hyllestad.no\0"
+"gov.ac\0fr\0andriabarlettatrani.it\0ga.us\0"
+"gov.ae\0gd\0estate.museum\0"
+"gov.af\0ge\0tolga.no\0"
+"gf\0asso.re\0cc.oh.us\0"
+"gg\0florida.museum\0"
+"presse.ci\0gh\0"
+"gi\0k12.dc.us\0"
+"ltd.lk\0orland.no\0"
+"gov.al\0"
+"gl\0tokke.no\0"
+"hanggliding.aero\0gm\0"
+"hareid.no\0"
+"gov.ba\0tj.cn\0gp\0"
+"gov.bb\0gq\0"
+"gov.as\0gr\0agrigento.it\0lc.it\0"
+"gs\0kalmykia.ru\0aero.tt\0"
+"gov.bf\0"
+"county.museum\0"
+"gov.bh\0hn.cn\0gw\0"
+"gov.az\0gy\0assn.lk\0guernsey.museum\0"
+"hk\0"
+"gov.bm\0h\xc3\xa6gebostad.no\0biz.tj\0"
+"hm\0computer.museum\0"
+"gov.bo\0hn\0kl\xc3\xa6""bu.no\0"
+"pulawy.pl\0"
+"gov.br\0"
+"trd.br\0gov.bs\0hr\0reggio-calabria.it\0historyofscience.museum\0lipetsk.ru\0"
+"gov.cd\0*.nagoya.jp\0"
+"ht\0id\0spjelkavik.no\0"
+"hu\0ie\0aero.mv\0"
+"marketplace.aero\0mn.it\0biz.tt\0"
+"gov.by\0saintlouis.museum\0mer\xc3\xa5ker.no\0"
+"gov.bz\0"
+"7.bg\0gov.cl\0virtual.museum\0"
+"gov.cm\0vennesla.no\0kr.ua\0"
+"gov.cn\0im\0ar.it\0galsa.no\0rovno.ua\0"
+"gov.co\0in\0"
+"io\0limanowa.pl\0"
+"iq\0k12.ga.us\0"
+"ir\0"
+"riik.ee\0is\0\xc3\xa1laheadju.no\0"
+"gov.cu\0it\0hawaii.museum\0seaport.museum\0"
+"je\0pubol.museum\0hm.no\0"
+"gov.cx\0"
+"*.chiba.jp\0"
+"*.kawasaki.jp\0"
+"k.se\0"
+"gov.dm\0"
+"aland.fi\0vik.no\0"
+"yk.ca\0jo\0kobierzyce.pl\0"
+"jp\0biz.vn\0"
+"presse.fr\0lib.il.us\0\xe9\xa6\x99\xe6\xb8\xaf\0"
+"gov.ec\0"
+"transport.museum\0bronnoy.no\0"
+"slg.br\0gov.ee\0asso.nc\0bievat.no\0"
+"nyny.museum\0"
+"kg\0"
+"mo-i-rana.no\0"
+"gov.dz\0ki\0"
+"monmouth.museum\0"
+"suldal.no\0"
+"bc.ca\0km\0zt.ua\0"
+"pt.it\0kn\0"
+"fineart.museum\0"
+"la\0"
+"kr\0gulen.no\0"
+"m.bg\0mo.cn\0lc\0alaheadju.no\0g\xc3\xa1\xc5\x8bgaviika.no\0"
+"nowaruda.pl\0cc.ut.us\0"
+"br\xc3\xb8nn\xc3\xb8y.no\0"
+"ky\0li\0overhalla.no\0"
+"kz\0khv.ru\0"
+"lk\0"
+"artdeco.museum\0"
+"ma\0fortworth.museum\0kostroma.ru\0"
+"ro.it\0kirkenes.no\0vestby.no\0"
+"urbino-pesaro.it\0ls\0mc\0alstahaug.no\0"
+"blog.br\0gov.ge\0lt\0md\0"
+"lu\0me\0botanicgarden.museum\0"
+"gov.gg\0lv\0oh.us\0"
+"gov.gh\0mg\0valley.museum\0"
+"gov.gi\0mh\0"
+"ly\0sandiego.museum\0"
+"mk\0"
+"ml\0"
+"gov.gn\0rollag.no\0naklo.pl\0"
+"mn\0"
+"mo\0"
+"mp\0leirvik.no\0"
+"gov.gr\0mq\0na\0cc.ks.us\0"
+"mr\0"
+"ms\0nc\0"
+"valer.hedmark.no\0"
+"mu\0ne\0"
+"mv\0nf\0"
+"mw\0"
+"mx\0nord-odal.no\0jur.pro\0"
+"my\0"
+"gov.hk\0name.hr\0"
+"nl\0"
+"astronomy.museum\0lib.nm.us\0"
+"catania.it\0"
+"no\0"
+"skjerv\xc3\xb8y.no\0"
+"k12.ne.us\0"
+"monza-e-della-brianza.it\0!pref.fukushima.jp\0nr\0"
+"gov.ie\0"
+"stuttgart.museum\0nu\0cc.mn.us\0"
+"karasjohka.no\0"
+"engine.aero\0bearalvahki.no\0"
+"oyer.no\0"
+"ve.it\0"
+"gov.im\0froland.no\0cc.ar.us\0"
+"gov.in\0magadan.ru\0"
+"pescara.it\0"
+"gov.iq\0usdecorativearts.museum\0"
+"gov.ir\0pa\0"
+"gov.is\0"
+"gov.it\0lavagis.no\0"
+"gov.je\0"
+"naustdal.no\0pe\0k12.or.us\0"
+"gd.cn\0carraramassa.it\0pf\0"
+"ph\0"
+"cc.ny.us\0"
+"rissa.no\0"
+"info\0pk\0pomorze.pl\0"
+"pl\0"
+"gov.jo\0asso.km\0pn\0"
+"*.okayama.jp\0cieszyn.pl\0"
+"freight.aero\0"
+"pr\0"
+"narvik.no\0ps\0"
+"!pref.aichi.jp\0elverum.no\0pt\0"
+"edunet.tn\0"
+"gov.kg\0"
+"flatanger.no\0marker.no\0pw\0"
+"gov.ki\0nuremberg.museum\0"
+"aip.ee\0"
+"gov.km\0"
+"gov.kn\0"
+"gov.kp\0"
+"rieti.it\0gov.la\0bajddar.no\0"
+"gov.lb\0aviation.museum\0"
+"gov.lc\0"
+"asso.mc\0"
+"re\0"
+"ut.us\0"
+"sa.gov.au\0gov.ky\0"
+"mo.it\0gov.kz\0"
+"gov.lk\0"
+"iraq.museum\0"
+"badajoz.museum\0"
+"8.bg\0inder\xc3\xb8y.no\0"
+"monticello.museum\0ro\0ks.ua\0"
+"gov.ma\0svizzera.museum\0"
+"gov.lr\0sa\0"
+"matera.it\0sb\0"
+"gov.lt\0rs\0sc\0"
+"gov.me\0sd\0"
+"gov.lv\0ru\0se\0"
+"gov.mg\0"
+"rw\0sg\0"
+"gov.ly\0assisi.museum\0kids.museum\0sh\0"
+"si\0"
+"gov.mk\0"
+"gov.ml\0sk\0"
+"sl\0"
+"gov.mn\0airguard.museum\0sm\0"
+"gov.mo\0l.se\0sn\0"
+"so\0"
+"gov.mr\0ks.us\0"
+"name.az\0sr\0"
+"naturhistorisches.museum\0tc\0"
+"trainer.aero\0cn.it\0urbinopesaro.it\0gov.mu\0nativeamerican.museum\0st\0td\0"
+"gov.mv\0su\0"
+"trentino.it\0gov.mw\0gov.ng\0tf\0"
+"tg\0"
+"co.ae\0venezia.it\0gov.my\0th\0"
+"!pref.ehime.jp\0sy\0"
+"co.ag\0lewismiller.museum\0ostrowiec.pl\0sz\0tj\0"
+"tk\0"
+"motorcycle.museum\0tl\0"
+"birdart.museum\0trogstad.no\0tm\0"
+"tn\0"
+"humanities.museum\0to\0"
+"pu.it\0gov.nr\0ua\0lib.ut.us\0"
+"co.ao\0"
+"co.ba\0trondheim.no\0tt\0"
+"in-addr.arpa\0tempioolbia.it\0!city.yokohama.jp\0mn.us\0"
+"n.bg\0schoenbrunn.museum\0tv\0"
+"co.at\0aremark.no\0tw\0ug\0"
+"jus.br\0"
+"co.bi\0bialowieza.pl\0ar.us\0"
+"audnedaln.no\0kustanai.ru\0"
+"va\0"
+"us\0vc\0"
+"newport.museum\0"
+"kopervik.no\0gov.ph\0vg\0"
+"ny.us\0vi\0"
+"co.bw\0finn\xc3\xb8y.no\0gov.pk\0uz\0"
+"honefoss.no\0gov.pl\0lanbib.se\0"
+"co.ci\0"
+"gov.pn\0intl.tn\0"
+"act.gov.au\0vn\0"
+"television.museum\0gov.pr\0"
+"sykkylven.no\0v\xc3\xa5ler.hedmark.no\0gov.ps\0"
+"gov.pt\0"
+"co.cr\0vu\0"
+"legnica.pl\0"
+"sa.au\0"
+"bjarkoy.no\0"
+"openair.museum\0birkenes.no\0lib.nj.us\0"
+"fylkesbibl.no\0holt\xc3\xa5len.no\0"
+"iz.hr\0"
+"ws\0"
+"oceanographique.museum\0"
+"b\xc3\xa1id\xc3\xa1r.no\0cc.mo.us\0"
+"\xc3\xb8ygarden.no\0"
+"contemporary.museum\0"
+"gb.com\0cc.as.us\0"
+"belluno.it\0gov.sa\0"
+"gov.sb\0"
+"gov.rs\0gov.sc\0"
+"gov.sd\0"
+"!pref.nagasaki.jp\0gov.ru\0"
+"asia\0"
+"sa.cr\0gov.rw\0gov.sg\0"
+"kuzbass.ru\0"
+"gs.vf.no\0"
+"gov.sl\0"
+"norfolk.museum\0"
+"k12.de.us\0"
+"mil\0"
+"rendalen.no\0"
+"gov.st\0"
+"agro.pl\0"
+"orkdal.no\0"
+"le.it\0gov.sy\0"
+"gov.tj\0"
+"co.gg\0nore-og-uvdal.no\0v\xc3\xa5ler.\xc3\xb8stfold.no\0"
+"gov.tl\0"
+"gov.tn\0"
+"gov.to\0"
+"kids.us\0"
+"equipment.aero\0gov.ua\0"
+"!city.niigata.jp\0gov.tt\0"
+"sel.no\0"
+"l\xc3\xa4ns.museum\0"
+"gov.tw\0"
+"rennebu.no\0"
+"egersund.no\0"
+"medecin.km\0"
+"co.gy\0"
+"!mecon.ar\0"
+"berlin.museum\0"
+"carrara-massa.it\0"
+"9.bg\0"
+"pri.ee\0gov.vc\0"
+"at.it\0"
+"muosat.no\0"
+"co.id\0"
+"co.hu\0"
+"etne.no\0"
+"\xc3\xa1lt\xc3\xa1.no\0"
+"gov.vn\0"
+"modelling.aero\0"
+"co.im\0"
+"co.in\0\xc3\xa5krehamn.no\0m.se\0"
+"gouv.fr\0*.kitakyushu.jp\0"
+"narviika.no\0"
+"rennes\xc3\xb8y.no\0"
+"co.ir\0afjord.no\0"
+"lea\xc5\x8bgaviika.no\0buryatia.ru\0"
+"co.it\0coastaldefence.museum\0"
+"co.je\0vf.no\0"
+"osteroy.no\0"
+"uslivinghistory.museum\0"
+"aerobatic.aero\0"
+"mesaverde.museum\0mining.museum\0"
+"a\xc3\xa9roport.ci\0gov.ws\0"
+"co.jp\0copenhagen.museum\0"
+"pv.it\0"
+"r\xc3\xb8mskog.no\0"
+"vossevangen.no\0porsanger.no\0"
+"salat.no\0mo.us\0"
+"o.bg\0imperia.it\0carrier.museum\0"
+"carbonia-iglesias.it\0"
+"as.us\0"
+"alvdal.no\0"
+"state.museum\0mandal.no\0cn.ua\0"
+"cuneo.it\0"
+"gouv.ht\0"
+"!city.okayama.jp\0co.kr\0"
+"co.lc\0"
+"sa.it\0"
+"donna.no\0"
+"sortland.no\0"
+"tomsk.ru\0"
+"birthplace.museum\0l\xc3\xb8""dingen.no\0"
+"ge.it\0orenburg.ru\0"
+"cn.com\0"
+"co.ma\0"
+"co.ls\0skaun.no\0name.vn\0"
+"navigation.aero\0"
+"cagliari.it\0co.me\0portal.museum\0"
+"gouv.bj\0"
+"udine.it\0"
+"engineer.aero\0"
+"szczecin.pl\0"
+"wales.museum\0"
+"co.na\0bo.telemark.no\0"
+"austin.museum\0"
+"k12.mo.us\0"
+"co.mu\0"
+"gouv.ci\0"
+"co.mw\0"
+"esp.br\0"
+"naturalhistorymuseum.museum\0"
+"mosjoen.no\0"
+"solund.no\0"
+"name.tj\0"
+"sand\xc3\xb8y.no\0"
+"kunstunddesign.museum\0"
+"cartoonart.museum\0collection.museum\0gsm.pl\0"
+"aure.no\0"
+"!pref.yamaguchi.jp\0historical.museum\0"
+"name.tt\0"
+"england.museum\0valle.no\0"
+"cc.ok.us\0"
+"salangen.no\0"
+"gloppen.no\0"
+"cc.co.us\0"
+"contemporaryart.museum\0"
+"tas.edu.au\0"
+"trading.aero\0"
+"mazury.pl\0"
+"!pref.aomori.jp\0co.pl\0"
+"opoczno.pl\0"
+"*.kobe.jp\0co.pn\0"
+"oppegard.no\0"
+"co.pw\0"
+"saltdal.no\0smolensk.ru\0"
+"na.it\0\xc4\x8d\xc3\xa1hcesuolo.no\0"
+"vgs.no\0evenassi.no\0"
+"parachuting.aero\0jl.cn\0maritime.museum\0bd.se\0"
+"badaddja.no\0"
+"bergen.no\0"
+"brussel.museum\0"
+"avoues.fr\0"
+"cesenaforli.it\0"
+"oregontrail.museum\0"
+"ullensaker.no\0"
+"jobs\0"
+"accident-prevention.aero\0"
+"n.se\0"
+"association.museum\0california.museum\0"
+"cultural.museum\0co.rs\0"
+"zoology.museum\0"
+"pruszkow.pl\0"
+"control.aero\0nt.edu.au\0net\0komforb.se\0"
+"lincoln.museum\0aurland.no\0name.pr\0co.rw\0"
+"ostroleka.pl\0"
+"isernia.it\0"
+"tm.fr\0"
+"gs.ol.no\0"
+"nb.ca\0marnardal.no\0"
+"williamsburg.museum\0"
+"!jet.uk\0"
+"suisse.museum\0\xc3\xa5""fjord.no\0flakstad.no\0"
+"karmoy.no\0"
+"yn.cn\0chesapeakebay.museum\0"
+"nsw.au\0"
+"amur.ru\0co.st\0"
+"imb.br\0siellak.no\0\xe7\xb6\xb2\xe8\xb7\xaf.tw\0"
+"name.na\0"
+"co.th\0"
+"p.bg\0"
+"co.sz\0co.tj\0"
+"name.mv\0\xc3\xa5lesund.no\0lib.in.us\0"
+"lucerne.museum\0naumburg.museum\0"
+"society.museum\0name.my\0"
+"tinn.no\0"
+"co.tt\0"
+"unj\xc3\xa1rga.no\0"
+"co.ug\0"
+"lib.wy.us\0"
+"co.tz\0"
+"ass.km\0"
+"ok.us\0"
+"tm.hu\0kongsvinger.no\0"
+"ibestad.no\0"
+"juedisches.museum\0co.us\0"
+"cq.cn\0"
+"rs.ba\0"
+"wa.edu.au\0co.vi\0"
+"co.uz\0"
+"health.museum\0"
+"grue.no\0"
+"automotive.museum\0journalism.museum\0settlement.museum\0"
+"qh.cn\0interactive.museum\0"
+"snillfjord.no\0!national-library-scotland.uk\0"
+"balsfjord.no\0lib.nh.us\0"
+"kolobrzeg.pl\0"
+"gs.tm.no\0"
+"h\xc3\xb8nefoss.no\0"
+"ol.no\0"
+"music.museum\0moareke.no\0"
+"b\xc3\xb8.nordland.no\0"
+"name.mk\0lier.no\0"
+"eidfjord.no\0"
+"sc.cn\0tm.km\0"
+"jelenia-gora.pl\0sanok.pl\0"
+"intelligence.museum\0"
+"srv.br\0elblag.pl\0"
+"judygarland.museum\0"
+"padua.it\0"
+"k12.co.us\0"
+"lindesnes.no\0"
+"name.jo\0izhevsk.ru\0"
+"yorkshire.museum\0mel\xc3\xb8y.no\0"
+"tm.mc\0lib.pr.us\0"
+"hjartdal.no\0"
+"tm.mg\0"
+"bari.it\0milano.it\0"
+"lg.jp\0"
+"zgrad.ru\0"
+"sm\xc3\xb8la.no\0"
+"communications.museum\0"
+"arts.co\0seoul.kr\0engerdal.no\0"
+"oster\xc3\xb8y.no\0"
+"\xe6\x95\x8e\xe8\x82\xb2.hk\0foggia.it\0verran.no\0"
+"orskog.no\0voronezh.ru\0kv.ua\0"
+"av.it\0"
+"tm.no\0nissedal.no\0"
+"historisches.museum\0gs.mr.no\0"
+"medecin.fr\0"
+"montreal.museum\0"
+"o.se\0"
+"!metro.tokyo.jp\0sola.no\0"
+"k12.tn.us\0"
+"floro.no\0"
+"milan.it\0*.shiga.jp\0"
+"berkeley.museum\0"
+"maintenance.aero\0"
+"ws.na\0"
+"lindas.no\0cc.ia.us\0"
+"brescia.it\0embroidery.museum\0"
+"arezzo.it\0tm.pl\0"
+"r\xc3\xa6lingen.no\0"
+"burghof.museum\0"
+"rec.br\0"
+"q.bg\0"
+"!nawras.om\0"
+"hammarfeasta.no\0"
+"moss.no\0"
+"on.ca\0"
+"gouv.rw\0"
+"luxembourg.museum\0"
+"rec.co\0british.museum\0"
+"reggio-emilia.it\0"
+"gouv.sn\0lib.wv.us\0"
+"avocat.fr\0"
+"simbirsk.ru\0"
+"jar.ru\0"
+"monza-brianza.it\0"
+"tm.ro\0"
+"imageandsound.museum\0"
+"jpn.com\0mr.no\0"
+"siracusa.it\0"
+"norilsk.ru\0tm.se\0"
+"tn.it\0"
+"jeju.kr\0"
+"!pref.fukuoka.jp\0"
+"*.hyogo.jp\0portlligat.museum\0"
+"!pref.osaka.jp\0"
+"siena.it\0sc.kr\0omaha.museum\0saskatchewan.museum\0"
+"phoenix.museum\0vanylven.no\0"
+"botanicalgarden.museum\0"
+"turek.pl\0"
+"vagsoy.no\0"
+"riodejaneiro.museum\0"
+"vi.it\0"
+"uy.com\0"
+"kristiansand.no\0"
+"sd.cn\0trento.it\0"
+"muncie.museum\0"
+"berg.no\0meldal.no\0"
+"nes.buskerud.no\0"
+"saratov.ru\0"
+"gs.oslo.no\0"
+"harstad.no\0vaga.no\0"
+"research.museum\0"
+"brunel.museum\0ia.us\0"
+"test.tj\0"
+"columbia.museum\0"
+"ms.it\0stockholm.museum\0"
+"reklam.hu\0"
+"pomorskie.pl\0lg.ua\0"
+"bg.it\0historicalsociety.museum\0rns.tn\0"
+"mallorca.museum\0surgut.ru\0cc.sc.us\0"
+"ushistory.museum\0"
+"palana.ru\0"
+"snoasa.no\0"
+"naturalsciences.museum\0"
+"yaroslavl.ru\0"
+"unjarga.no\0"
+"p.se\0"
+"ingatlan.hu\0"
+"irc.pl\0"
+"savona.it\0"
+"cr.it\0"
+"test.ru\0cc.tn.us\0"
+"ms.kr\0museumvereniging.museum\0"
+"time.no\0k12.ia.us\0"
+"vladimir.ru\0"
+"correios-e-telecomunica\xc3\xa7\xc3\xb5""es.museum\0"
+"gouv.km\0nationalfirearms.museum\0"
+"m\xc3\xa1latvuopmi.no\0"
+"aero\0yosemite.museum\0"
+"r.bg\0school.na\0"
+"cc.vi.us\0"
+"*.wakayama.jp\0"
+"beauxarts.museum\0averoy.no\0ullensvang.no\0bar.pro\0"
+"!city.hiroshima.jp\0"
+"b\xc3\xa1hccavuotna.no\0"
+"frosta.no\0"
+"gdynia.pl\0"
+"medical.museum\0"
+"embaixada.st\0"
+"balsan.it\0vantaa.museum\0"
+"za.net\0"
+"!city.saitama.jp\0lib.ks.us\0"
+"fnd.br\0"
+"ru.com\0se.com\0hol.no\0modalen.no\0"
+"gouv.ml\0chukotka.ru\0"
+"malopolska.pl\0"
+"mansion.museum\0"
+"iki.fi\0children.museum\0"
+"cyber.museum\0rec.nf\0mo\xc3\xa5reke.no\0"
+"to.it\0"
+"hasvik.no\0"
+"\xc3\xb8yer.no\0"
+"arts.ro\0sc.ug\0"
+"lib.ar.us\0"
+"sc.tz\0cc.ms.us\0cc.nc.us\0"
+"etc.br\0poznan.pl\0"
+"cnt.br\0viking.museum\0"
+"*.miyazaki.jp\0"
+"melhus.no\0"
+"skodje.no\0vevelstad.no\0"
+"sc.us\0"
+"upow.gov.pl\0"
+"!city.fukuoka.jp\0brandywinevalley.museum\0natuurwetenschappen.museum\0tranby.no\0"
+"bahn.museum\0msk.ru\0"
+"delmenhorst.museum\0"
+"russia.museum\0fuoisku.no\0"
+"shell.museum\0"
+"r\xc3\xa1isa.no\0"
+"hs.kr\0udmurtia.ru\0"
+"palermo.it\0"
+"pilot.aero\0"
+"tn.us\0"
+"priv.hu\0"
+"li.it\0"
+"kr\xc3\xa5""anghke.no\0mosreg.ru\0"
+"lib.fl.us\0"
+"plants.museum\0"
+"ulsan.kr\0national.museum\0"
+"mil.ac\0!pref.nara.jp\0surgeonshall.museum\0"
+"mil.ae\0santacruz.museum\0vi.us\0"
+"wlocl.pl\0"
+"mt.it\0napoli.it\0alaska.museum\0arts.nf\0"
+"missoula.museum\0"
+"rec.ro\0"
+"mil.al\0"
+"marburg.museum\0waw.pl\0"
+"pharmaciens.km\0indianapolis.museum\0larsson.museum\0"
+"cc.sd.us\0"
+"mil.ba\0mobi\0"
+"indianmarket.museum\0"
+"recreation.aero\0padova.it\0"
+"varese.it\0parti.se\0"
+"mil.az\0"
+"mil.bo\0!pref.kagoshima.jp\0khmelnitskiy.ua\0"
+"rygge.no\0"
+"os\xc3\xb8yro.no\0"
+"mil.br\0"
+"cs.it\0"
+"austevoll.no\0fjell.no\0"
+"mil.by\0"
+"!pref.tokushima.jp\0org\0"
+"mil.cn\0gs.svalbard.no\0"
+"mil.co\0"
+"pz.it\0lib.va.us\0\xd1\x80\xd1\x84\0"
+"\xe4\xb8\xaa\xe4\xba\xba.hk\0ms.us\0nc.us\0k12.wi.us\0"
+"s.bg\0drangedal.no\0"
+"en.it\0"
+"culturalcenter.museum\0"
+"house.museum\0divttasvuotna.no\0"
+"fhs.no\0"
+"circus.museum\0"
+"priv.at\0"
+"mil.ec\0"
+"ruovat.no\0"
+"midsund.no\0vagan.no\0"
+"casadelamoneda.museum\0"
+"bristol.museum\0"
+"and.museum\0"
+"ascolipiceno.it\0computerhistory.museum\0vyatka.ru\0"
+"uhren.museum\0"
+"lahppi.no\0"
+"*.yokohama.jp\0cody.museum\0lib.al.us\0"
+"colonialwilliamsburg.museum\0indian.museum\0cc.ky.us\0"
+"tp.it\0biev\xc3\xa1t.no\0"
+"can.br\0royken.no\0"
+"id.ir\0"
+"mediocampidano.it\0tromso.no\0"
+"kartuzy.pl\0k12.ok.us\0"
+"*.saitama.jp\0stjohn.museum\0m\xc3\xa1tta-v\xc3\xa1rjjat.no\0"
+"mil.ge\0trani-barletta-andria.it\0"
+"lib.as.us\0"
+"swiebodzin.pl\0cc.mt.us\0cc.nd.us\0"
+"mil.gh\0"
+"science-fiction.museum\0\xd9\x82\xd8\xb7\xd8\xb1\0"
+"airtraffic.aero\0"
+"konskowola.pl\0"
+"scienceandhistory.museum\0nysa.pl\0sd.us\0"
+"balestrand.no\0"
+"oygarden.no\0"
+"her\xc3\xb8y.nordland.no\0"
+"!pref.ishikawa.jp\0strand.no\0"
+"\xe7\xb5\x84\xe7\xbb\x87.hk\0mil.hn\0"
+"gob.bo\0volda.no\0"
+"losangeles.museum\0larvik.no\0"
+"university.museum\0"
+"cc.dc.us\0"
+"mil.id\0"
+"sorfold.no\0"
+"watch-and-clock.museum\0"
+"flor\xc3\xb8.no\0"
+"nittedal.no\0oppeg\xc3\xa5rd.no\0"
+"k12.ri.us\0"
+"gob.cl\0"
+"komi.ru\0"
+"government.aero\0mil.in\0"
+"mil.iq\0id.lv\0"
+"culture.museum\0"
+"id.ly\0"
+"raholt.no\0"
+"lubin.pl\0grozny.ru\0"
+"kchr.ru\0"
+"nikolaev.ua\0"
+"lib.sd.us\0"
+"de.com\0"
+"mil.jo\0"
+"*.kanagawa.jp\0gaular.no\0miasta.pl\0"
+"bi.it\0rnu.tn\0uzhgorod.ua\0"
+"idrett.no\0v\xc3\xa5gs\xc3\xb8y.no\0"
+"wroclaw.pl\0"
+"res.aero\0ne.jp\0mil.kg\0"
+"\xc3\xa5mli.no\0"
+"education.museum\0"
+"dgca.aero\0"
+"mil.km\0"
+"trolley.museum\0"
+"cci.fr\0r.se\0"
+"archaeological.museum\0"
+"monzaedellabrianza.it\0mil.kr\0"
+"gob.es\0kvafjord.no\0ky.us\0"
+"lecco.it\0"
+"ct.it\0"
+"magazine.aero\0"
+"operaunite.com\0ne.kr\0"
+"mil.kz\0skoczow.pl\0"
+"nf.ca\0"
+"western.museum\0"
+"kunst.museum\0gaivuotna.no\0karpacz.pl\0spb.ru\0cc.id.us\0"
+"slask.pl\0"
+"youth.museum\0"
+"adv.br\0campidanomedio.it\0!songfest.om\0"
+"geelvinck.museum\0\xd8\xa7\xd9\x85\xd8\xa7\xd8\xb1\xd8\xa7\xd8\xaa\0"
+"mil.lv\0"
+"fie.ee\0mil.mg\0mt.us\0nd.us\0k12.vt.us\0"
+"t.bg\0ushuaia.museum\0"
+"off.ai\0"
+"irkutsk.ru\0"
+"stor-elvdal.no\0tourism.tn\0"
+"penza.ru\0"
+"bj.cn\0\xe4\xb8\xad\xe5\x9b\xbd\0"
+"civilwar.museum\0mil.mv\0opole.pl\0"
+"nes.akershus.no\0"
+"mil.my\0karelia.ru\0"
+"como.it\0sande.vestfold.no\0"
+"\xe4\xb8\xad\xe5\x9c\x8b\0"
+"gob.hn\0lib.la.us\0"
+"mil.no\0cc.wv.us\0"
+"boleslawiec.pl\0"
+"!pref.niigata.jp\0gs.sf.no\0dc.us\0k12.mi.us\0"
+"museum\0dep.no\0kv\xc3\xa6nangen.no\0l\xc3\xa1hppi.no\0"
+"film.museum\0"
+"frei.no\0"
+"notodden.no\0risor.no\0"
+"messina.it\0"
+"eidsberg.no\0"
+"krakow.pl\0lib.mt.us\0lib.nd.us\0"
+"rauma.no\0"
+"mulhouse.museum\0"
+"sibenik.museum\0grong.no\0mil.pe\0"
+"budejju.no\0k12.nv.us\0"
+"stavanger.no\0mil.ph\0"
+"forli-cesena.it\0"
+"naples.it\0cc.ne.us\0"
+"s\xc3\xb8r-aurdal.no\0"
+"mil.pl\0"
+"vibo-valentia.it\0ski.museum\0siedlce.pl\0"
+"bus.museum\0"
+"tozsde.hu\0"
+"!pref.shizuoka.jp\0santabarbara.museum\0"
+"zhitomir.ua\0"
+"pro.az\0"
+"ne.pw\0"
+"pro.br\0orkanger.no\0b\xc3\xb8.telemark.no\0"
+"roma.it\0cc.ct.us\0"
+"heritage.museum\0giske.no\0"
+"!pref.kumamoto.jp\0prof.pr\0"
+"*.kochi.jp\0"
+"andria-barletta-trani.it\0*.toyama.jp\0sveio.no\0"
+"id.us\0"
+"bolt.hu\0"
+"fetsund.no\0porsgrunn.no\0"
+"iglesias-carbonia.it\0"
+"sf.no\0"
+"mil.ru\0"
+"from.hr\0asnes.no\0mil.rw\0"
+"alesund.no\0sos.pl\0"
+"livorno.it\0"
+"crafts.museum\0"
+"aquila.it\0"
+"vega.no\0"
+"jewelry.museum\0"
+"sk\xc3\xa1nit.no\0chita.ru\0"
+"pro.ec\0"
+"fortmissoula.museum\0j\xc3\xb8lster.no\0"
+"pro\0mil.st\0"
+"busan.kr\0lib.ga.us\0"
+"dellogliastra.it\0"
+"aosta.it\0chungnam.kr\0gob.mx\0"
+"mil.sy\0k12.hi.us\0"
+"mil.tj\0"
+"ulan-ude.ru\0mil.to\0wv.us\0"
+"luster.no\0volgograd.ru\0"
+"pa.it\0kommunalforbund.se\0lib.tx.us\0"
+"s.se\0"
+"qsl.br\0"
+"mil.tw\0"
+"est.pr\0ens.tn\0"
+"lib.id.us\0"
+"mil.tz\0"
+"uscountryestate.museum\0"
+"agents.aero\0"
+"\xc3\xb8vre-eiker.no\0ne.ug\0"
+"pb.ao\0"
+"gob.pa\0ne.tz\0"
+"tur.br\0"
+"mil.vc\0"
+"or.at\0gob.pe\0"
+"s\xc3\xb8r-fron.no\0"
+"or.bi\0ne.us\0"
+"u.bg\0gob.pk\0"
+"stavern.no\0"
+"brindisi.it\0"
+"aknoluokta.no\0"
+"!pref.kyoto.jp\0tydal.no\0"
+"plc.ly\0muos\xc3\xa1t.no\0"
+"or.ci\0hamaroy.no\0priv.pl\0"
+"vestre-slidre.no\0gniezno.pl\0"
+"\xe7\xae\x87\xe4\xba\xba.hk\0"
+"andebu.no\0"
+"nieruchomosci.pl\0\xd8\xa7\xd9\x84\xd8\xb3\xd8\xb9\xd9\x88\xd8\xaf\xd9\x8a\xd8\xa9\0"
+"or.cr\0pro.ht\0bolzano.it\0"
+"ct.us\0k12.md.us\0"
+"za.org\0"
+"!icnet.uk\0"
+"localhistory.museum\0"
+"firm.ht\0"
+"lel.br\0tr.it\0kvanangen.no\0"
+"sondre-land.no\0t\xc3\xb8nsberg.no\0vefsn.no\0"
+"nature.museum\0yamal.ru\0"
+"rv.ua\0"
+"lans.museum\0lib.ne.us\0"
+"lur\xc3\xb8y.no\0"
+"eu.com\0firm.in\0"
+"hjelmeland.no\0"
+"gs.tr.no\0"
+"casino.hu\0essex.museum\0tourism.pl\0"
+"rennesoy.no\0"
+"priv.no\0"
+"baths.museum\0mytis.ru\0"
+"tingvoll.no\0"
+"cc.az.us\0"
+"sh.cn\0"
+"!pref.miyazaki.jp\0s\xc3\xb8rfold.no\0"
+"aurskog-holand.no\0malatvuopmi.no\0"
+"lib.ct.us\0"
+"cc.pa.us\0"
+"pa.gov.pl\0"
+"firm.co\0cc.de.us\0"
+"nrw.museum\0"
+"daejeon.kr\0livinghistory.museum\0"
+"gildeskal.no\0lund.no\0"
+"\xc3\xb8ksnes.no\0stavropol.ru\0"
+"b\xc3\xa6rum.no\0r\xc3\xb8yrvik.no\0"
+"osoyro.no\0"
+"priv.me\0sula.no\0!parliament.uk\0"
+"nationalheritage.museum\0"
+"jaworzno.pl\0"
+"dinosaur.museum\0"
+"garden.museum\0trust.museum\0"
+"turen.tn\0"
+"kautokeino.no\0"
+"pro.na\0"
+"gorizia.it\0"
+"siljan.no\0"
+"or.id\0pro.mv\0"
+"bieszczady.pl\0www.ro\0"
+"lib.ee\0antiques.museum\0brasil.museum\0tr.no\0"
+"aejrie.no\0"
+"!pref.hokkaido.jp\0"
+"schlesisches.museum\0"
+"huissier-justice.fr\0or.it\0"
+"t.se\0"
+"environment.museum\0"
+"vindafjord.no\0"
+"edu.ac\0or.jp\0"
+"tree.museum\0"
+"groundhandling.aero\0edu.af\0"
+"rochester.museum\0sanfrancisco.museum\0"
+"ebiz.tw\0"
+"kirovograd.ua\0"
+"edu.al\0"
+"edu.an\0\xc3\xa1k\xc5\x8boluokta.no\0v\xc3\xa5g\xc3\xa5.no\0"
+"v.bg\0"
+"edu.ba\0"
+"edu.bb\0nesset.no\0"
+"hornindal.no\0pro.pr\0"
+"or.kr\0"
+"az.us\0"
+"edu.bh\0volkenkunde.museum\0"
+"edu.bi\0"
+"edu.az\0"
+"b\xc3\xb8mlo.no\0"
+"edu.bm\0"
+"edu.bo\0tyumen.ru\0"
+"edu.br\0"
+"edu.bs\0pa.us\0"
+"alto-adige.it\0whaling.museum\0"
+"*.iwate.jp\0"
+"edu.ci\0law.pro\0"
+"edu.bz\0de.us\0"
+"lib.ak.us\0"
+"edu.cn\0"
+"edu.co\0"
+"laspezia.it\0"
+"baidar.no\0"
+"ts.it\0"
+"or.na\0"
+"edu.cu\0hotel.lk\0"
+"show.aero\0or.mu\0"
+"sandnes.no\0"
+"museumcenter.museum\0"
+"edu.dm\0kazan.ru\0"
+"biz\0caltanissetta.it\0odessa.ua\0k12.oh.us\0"
+"crimea.ua\0"
+"research.aero\0lom.no\0"
+"edu.ec\0florence.it\0clock.museum\0sshn.se\0"
+"edu.ee\0game.tw\0"
+"!pref.okinawa.jp\0"
+"ilawa.pl\0"
+"edu.dz\0indiana.museum\0"
+"gs.jan-mayen.no\0"
+"publ.pt\0"
+"nom.ad\0"
+"skanit.no\0gdansk.pl\0k12.pa.us\0"
+"nom.ag\0edu.es\0"
+"if.ua\0"
+"pro.tt\0lib.de.us\0"
+"environmentalconservation.museum\0cc.or.us\0"
+"bern.museum\0nat.tn\0"
+"rubtsovsk.ru\0"
+"!educ.ar\0masoy.no\0"
+"bologna.it\0"
+"\xc3\xa5snes.no\0fhv.se\0"
+"*.tottori.jp\0radoy.no\0"
+"romskog.no\0"
+"malbork.pl\0"
+"olbiatempio.it\0"
+"edu.ge\0"
+"edu.gh\0"
+"edu.gi\0"
+"or.pw\0"
+"hob\xc3\xb8l.no\0"
+"nom.br\0edu.gn\0virginia.museum\0mbone.pl\0!nls.uk\0"
+"seljord.no\0pro.vn\0"
+"edu.gp\0"
+"edu.gr\0"
+"!uba.ar\0!pref.saitama.jp\0"
+"greta.fr\0gs.aa.no\0kvinnherad.no\0"
+"lib.sc.us\0"
+"js.cn\0nom.co\0edu.hk\0"
+"lesja.no\0"
+"bl.it\0"
+"edu.hn\0\xc3\xb8ystre-slidre.no\0mari-el.ru\0"
+"hotel.hu\0"
+"rindal.no\0"
+"edu.ht\0"
+"!pref.miyagi.jp\0"
+"midtre-gauldal.no\0"
+"xj.cn\0australia.museum\0"
+"ab.ca\0salvadordali.museum\0olawa.pl\0"
+"pc.it\0"
+"u.se\0"
+"edu.in\0b\xc3\xa1l\xc3\xa1t.no\0"
+"ln.cn\0alta.no\0"
+"chelyabinsk.ru\0"
+"edu.iq\0"
+"ontario.museum\0"
+"edu.is\0"
+"edu.it\0"
+"b\xc3\xa5tsfjord.no\0"
+"trysil.no\0or.th\0"
+"utsira.no\0"
+"nom.es\0edu.jo\0fhsk.se\0"
+"bale.museum\0"
+"w.bg\0"
+"lillesand.no\0"
+"edu.kg\0"
+"amusement.aero\0"
+"edu.ki\0"
+"fauske.no\0or.ug\0"
+"int.az\0askvoll.no\0eidskog.no\0cv.ua\0"
+"algard.no\0"
+"edu.km\0or.tz\0"
+"nom.fr\0edu.kn\0"
+"*.ibaraki.jp\0hoylandet.no\0"
+"int.bo\0edu.kp\0"
+"edu.la\0"
+"si.it\0edu.lb\0travel.pl\0"
+"edu.lc\0mx.na\0n\xc3\xa1vuotna.no\0ovre-eiker.no\0"
+"aa.no\0!siemens.om\0"
+"sciences.museum\0or.us\0"
+"cat\0"
+"edu.ky\0"
+"int.ci\0edu.kz\0firm.ro\0cc.wy.us\0"
+"edu.lk\0vaapste.no\0"
+"!pref.tochigi.jp\0"
+"int.co\0podlasie.pl\0"
+"edu.lr\0"
+"karikatur.museum\0jamal.ru\0"
+"gjovik.no\0krager\xc3\xb8.no\0k12.az.us\0"
+"edu.me\0"
+"ud.it\0edu.lv\0entomology.museum\0"
+"edu.mg\0moskenes.no\0"
+"\xe6\x94\xbf\xe5\xba\x9c.hk\0edu.ly\0"
+"stpetersburg.museum\0"
+"edu.mk\0"
+"edu.ml\0nordreisa.no\0"
+"!pref.fukui.jp\0lib.ms.us\0lib.nc.us\0"
+"edu.mn\0\xd9\x81\xd9\x84\xd8\xb3\xd8\xb7\xd9\x8a\xd9\x86\0"
+"fot.br\0edu.mo\0"
+"iron.museum\0"
+"asti.it\0annefrank.museum\0stv.ru\0cc.nh.us\0"
+"edu.mv\0"
+"lodi.it\0edu.mw\0edu.ng\0"
+"gwangju.kr\0edu.mx\0"
+"edu.my\0"
+"soundandvision.museum\0"
+"lenvik.no\0"
+"ballooning.aero\0"
+"name\0"
+"jogasz.hu\0frogn.no\0"
+"history.museum\0"
+"consultant.aero\0edu.nr\0"
+"manchester.museum\0"
+"*.hiroshima.jp\0"
+"pol.dz\0"
+"*.tochigi.jp\0heimatunduhren.museum\0"
+"!pref.kanagawa.jp\0"
+"firm.nf\0edu.pa\0"
+"coop.ht\0pc.pl\0"
+"chicago.museum\0"
+"vn.ua\0"
+"edu.pe\0"
+"tana.no\0edu.pf\0"
+"edu.ph\0"
+"nom.km\0"
+"travel.tt\0"
+"edu.pk\0"
+"experts-comptables.fr\0edu.pl\0bryansk.ru\0"
+"edu.pn\0"
+"evje-og-hornnes.no\0warszawa.pl\0"
+"ac.ae\0"
+"edu.pr\0"
+"vaksdal.no\0edu.ps\0dni.us\0"
+"po.gov.pl\0edu.pt\0"
+"nordre-land.no\0vadso.no\0"
+"rnrt.tn\0"
+"sport.hu\0!pref.gifu.jp\0voss.no\0targi.pl\0"
+"flesberg.no\0"
+"photography.museum\0"
+"modena.it\0tonsberg.no\0"
+"ac.at\0"
+"ac.be\0coop.br\0"
+"services.aero\0"
+"nom.mg\0"
+"wielun.pl\0"
+"jefferson.museum\0wy.us\0"
+"pd.it\0ot.it\0neues.museum\0slattum.no\0"
+"vdonsk.ru\0"
+"ar.com\0edu.sa\0"
+"\xc3\xa5l.no\0edu.sb\0"
+"edu.rs\0edu.sc\0"
+"ac.ci\0int.is\0edu.sd\0!tsk.tr\0"
+"br\xc3\xb8nn\xc3\xb8ysund.no\0and\xc3\xb8y.no\0edu.ru\0"
+"pol.ht\0"
+"edu.rw\0edu.sg\0"
+"gyeongnam.kr\0olecko.pl\0"
+"ac.cn\0"
+"graz.museum\0"
+"coldwar.museum\0edu.sl\0"
+"ac.cr\0"
+"edu.sn\0"
+"hamar.no\0"
+"histoire.museum\0"
+"!city.shizuoka.jp\0"
+"edu.st\0"
+"oceanographic.museum\0nh.us\0"
+"x.bg\0"
+"surnadal.no\0"
+"fc.it\0costume.museum\0stalowa-wola.pl\0"
+"valer.ostfold.no\0edu.sy\0"
+"edu.tj\0"
+"arq.br\0"
+"aeroclub.aero\0odo.br\0pe.ca\0\xe7\xb6\xb2\xe7\xb5\xa1.cn\0bronnoysund.no\0nom.pa\0"
+"edu.to\0"
+"paleo.museum\0nom.pe\0edu.ua\0"
+"int.la\0trustee.museum\0forsand.no\0krasnoyarsk.ru\0"
+"!pref.hyogo.jp\0"
+"edu.tt\0"
+"zarow.pl\0"
+"edu.tw\0"
+"nom.pl\0"
+"community.museum\0kvitsoy.no\0"
+"int.lk\0tychy.pl\0"
+"k12.me.us\0"
+"jondal.no\0edu.vc\0"
+"illustration.museum\0"
+"clinton.museum\0"
+"tas.au\0es.kr\0"
+"production.aero\0"
+"rodoy.no\0"
+"database.museum\0bodo.no\0"
+"anthro.museum\0landes.museum\0edu.vn\0"
+"nom.re\0"
+"altai.ru\0"
+"filatelia.museum\0"
+"sk.ca\0lezajsk.pl\0"
+"rockart.museum\0int.mv\0"
+"int.mw\0herad.no\0"
+"eti.br\0ac.gn\0"
+"fedje.no\0nom.ro\0"
+"money.museum\0"
+"\xd9\x85\xd8\xb5\xd8\xb1\0"
+"horten.no\0"
+"gangaviika.no\0mielec.pl\0"
+"uw.gov.pl\0"
+"moma.museum\0"
+"edu.ws\0"
+"go.ci\0"
+"tv.bo\0technology.museum\0"
+"s\xc3\xb8ndre-land.no\0"
+"tv.br\0"
+"jor.br\0lib.dc.us\0"
+"arboretum.museum\0"
+"go.cr\0"
+"artsandcrafts.museum\0\xd8\xaa\xd9\x88\xd9\x86\xd8\xb3\0"
+"psc.br\0ac.id\0!city.chiba.jp\0"
+"wa.au\0"
+"rome.it\0"
+"amli.no\0"
+"ac.im\0lo.it\0"
+"ac.in\0"
+"\xe7\xb6\xb2\xe7\xb5\xa1.hk\0durham.museum\0"
+"ac.ir\0"
+"torino.museum\0"
+"loabat.no\0"
+"com\0"
+"nalchik.ru\0"
+"yakutia.ru\0"
+"settlers.museum\0"
+"!promocion.ar\0int.pt\0"
+"union.aero\0"
+"utah.museum\0"
+"giehtavuoatna.no\0"
+"ac.jp\0"
+"air-traffic-control.aero\0"
+"silk.museum\0usantiques.museum\0"
+"bn.it\0"
+"kalisz.pl\0"
+"perm.ru\0"
+"aoste.it\0bindal.no\0"
+"coloradoplateau.museum\0k12.gu.us\0"
+"frosinone.it\0forde.no\0"
+"epilepsy.museum\0"
+"olbia-tempio.it\0"
+"journalist.aero\0ac.kr\0*.sch.uk\0"
+"nic.im\0sciencesnaturelles.museum\0bedzin.pl\0"
+"nic.in\0pe.it\0"
+"w.se\0"
+"!pref.okayama.jp\0"
+"urn.arpa\0"
+"cinema.museum\0"
+"monza.it\0versailles.museum\0int.ru\0"
+"andasuolo.no\0skj\xc3\xa5k.no\0chernovtsy.ua\0"
+"nyc.museum\0int.rw\0paroch.k12.ma.us\0"
+"ringerike.no\0"
+"ac.ma\0"
+"org.ac\0civilaviation.aero\0"
+"rakkestad.no\0"
+"org.ae\0ac.me\0"
+"org.af\0"
+"org.ag\0"
+"org.ai\0stokke.no\0"
+"airport.aero\0"
+"finnoy.no\0"
+"org.al\0"
+"org.an\0y.bg\0habmer.no\0"
+"stadt.museum\0holtalen.no\0"
+"int.tj\0"
+"org.ba\0gjerdrum.no\0"
+"org.bb\0ascoli-piceno.it\0molde.no\0r\xc3\xb8st.no\0tysfjord.no\0"
+"pe.kr\0rybnik.pl\0"
+"go.id\0"
+"ac.mu\0"
+"ac.mw\0ac.ng\0"
+"org.bh\0\xc3\xa5mot.no\0rana.no\0"
+"org.bi\0"
+"org.az\0belgorod.ru\0int.tt\0"
+"ae.org\0"
+"group.aero\0posts-and-telecommunications.museum\0"
+"org.bm\0salerno.it\0"
+"etnedal.no\0"
+"org.bo\0*.hokkaido.jp\0donetsk.ua\0"
+"ostroda.pl\0"
+"org.br\0"
+"org.bs\0"
+"go.it\0h\xc3\xb8ylandet.no\0"
+"zgorzelec.pl\0"
+"org.bw\0"
+"org.ci\0"
+"org.bz\0vicenza.it\0resistance.museum\0"
+"missile.museum\0"
+"org.cn\0"
+"org.co\0assassination.museum\0"
+"go.jp\0"
+"tv.it\0austrheim.no\0ac.pa\0"
+"verbania.it\0"
+"palace.museum\0"
+"tmp.br\0int.vn\0"
+"org.cu\0"
+"paris.museum\0"
+"media.aero\0hokksund.no\0"
+"arts.museum\0gemological.museum\0hammerfest.no\0"
+"k12.ny.us\0"
+"org.dm\0hemsedal.no\0ringsaker.no\0sklep.pl\0"
+"h\xc3\xa5.no\0cc.nj.us\0"
+"rzeszow.pl\0"
+"go.kr\0gjesdal.no\0ac.pr\0"
+"org.ec\0"
+"org.ee\0"
+"media.museum\0"
+"terni.it\0touch.museum\0zakopane.pl\0"
+"journal.aero\0org.dz\0"
+"incheon.kr\0"
+"b\xc3\xa1hcavuotna.no\0"
+"leksvik.no\0ulvik.no\0"
+"plantation.museum\0"
+"org.es\0loyalist.museum\0"
+"gildesk\xc3\xa5l.no\0bytom.pl\0"
+"bo.nordland.no\0"
+"ambulance.aero\0iglesiascarbonia.it\0"
+"tw.cn\0\xe6\x96\xb0\xe5\x8a\xa0\xe5\x9d\xa1\0"
+"chocolate.museum\0"
+"pittsburgh.museum\0"
+"royrvik.no\0sor-odal.no\0ac.rs\0"
+"kaluga.ru\0"
+"org.ge\0erotica.hu\0ac.ru\0ac.se\0"
+"org.gg\0leangaviika.no\0ac.rw\0"
+"org.gh\0v\xc3\xa6r\xc3\xb8y.no\0"
+"org.gi\0"
+"jevnaker.no\0"
+"org.gn\0tv.na\0leikanger.no\0"
+"org.gp\0"
+"ask\xc3\xb8y.no\0"
+"org.gr\0wroc.pl\0"
+"ad.jp\0"
+"powiat.pl\0"
+"tj\xc3\xb8me.no\0"
+"coop.tt\0"
+"ac.th\0"
+"mragowo.pl\0ac.sz\0ac.tj\0"
+"org.hk\0bo.it\0"
+"philately.museum\0"
+"org.hn\0"
+"fet.no\0"
+"axis.museum\0mansions.museum\0"
+"wiki.br\0"
+"org.ht\0"
+"org.hu\0piacenza.it\0scotland.museum\0cpa.pro\0"
+"ac.ug\0"
+"coop.mv\0x.se\0"
+"coop.mw\0ac.tz\0"
+"bmd.br\0"
+"org.im\0ralingen.no\0"
+"org.in\0"
+"cz.it\0lib.ia.us\0"
+"org.iq\0"
+"org.ir\0"
+"org.is\0"
+"nl.ca\0"
+"org.je\0"
+"childrensgarden.museum\0"
+"kvits\xc3\xb8y.no\0go.pw\0"
+"sokndal.no\0"
+"ra.it\0grimstad.no\0"
+"denmark.museum\0"
+"ac.vn\0"
+"ecn.br\0org.jo\0"
+"bialystok.pl\0nj.us\0"
+"z.bg\0bilbao.museum\0stargard.pl\0nic.tj\0"
+"eisenbahn.museum\0"
+"fe.it\0bryne.no\0vrn.ru\0"
+"cc.wa.us\0"
+"sex.hu\0skierva.no\0"
+"org.kg\0"
+"org.ki\0"
+"org.km\0"
+"org.kn\0khakassia.ru\0"
+"org.kp\0"
+"org.la\0"
+"org.lb\0"
+"org.lc\0"
+"francaise.museum\0"
+"panama.museum\0"
+"rotorcraft.aero\0gateway.museum\0olkusz.pl\0"
+"org.ky\0czeladz.pl\0ryazan.ru\0"
+"org.kz\0"
+"org.lk\0dyr\xc3\xb8y.no\0"
+"raisa.no\0"
+"dlugoleka.pl\0"
+"org.ma\0"
+"org.lr\0prochowice.pl\0"
+"org.ls\0"
+"org.me\0sandoy.no\0s\xc3\xb8r-varanger.no\0"
+"org.lv\0"
+"org.mg\0"
+"tel\0go.th\0"
+"org.ly\0"
+"steam.museum\0go.tj\0"
+"org.mk\0pasadena.museum\0jessheim.no\0lib.mn.us\0"
+"org.ml\0"
+"software.aero\0"
+"org.mn\0"
+"org.mo\0"
+"*.fukui.jp\0decorativearts.museum\0"
+"spy.museum\0org.na\0jorpeland.no\0"
+"vads\xc3\xb8.no\0"
+"org.mu\0building.museum\0gausdal.no\0"
+"org.mv\0nannestad.no\0"
+"org.mw\0org.ng\0go.ug\0"
+"vr.it\0org.mx\0"
+"org.my\0"
+"go.tz\0"
+"oppdal.no\0"
+"uk.net\0"
+"coop.km\0"
+"*.kyoto.jp\0"
+"sarpsborg.no\0org.nr\0"
+"chernigov.ua\0"
+"ha.cn\0no.com\0"
+"space.museum\0"
+"org.pa\0"
+"*.ar\0"
+"usgarden.museum\0"
+"*.bd\0org.pe\0"
+"*.au\0org.pf\0um.gov.pl\0"
+"bio.br\0"
+"org.ph\0"
+"org.pk\0"
+"fr\xc3\xa6na.no\0org.pl\0"
+"nord-aurdal.no\0org.pn\0"
+"*.bn\0handson.museum\0agrinet.tn\0"
+"kviteseid.no\0"
+"rel.ht\0virtuel.museum\0atm.pl\0org.pr\0"
+"org.ps\0cherkassy.ua\0"
+"org.pt\0wa.us\0"
+"*.bt\0arendal.no\0magnitka.ru\0"
+"depot.museum\0porsangu.no\0"
+"laakesvuemie.no\0"
+"sor-fron.no\0"
+"heroy.more-og-romsdal.no\0"
+"*.ck\0"
+"!rakpetroleum.om\0"
+"kr\xc3\xb8""dsherad.no\0mail.pl\0"
+"mod.gi\0"
+"gs.nl.no\0"
+"mb.ca\0"
+"pavia.it\0"
+"civilisation.museum\0folldal.no\0"
+"suli.hu\0"
+"brumunddal.no\0"
+"*.cy\0"
+"pg.it\0troms\xc3\xb8.no\0"
+"sex.pl\0y.se\0"
+"org.ro\0"
+"*.do\0"
+"caserta.it\0org.sa\0"
+"za.com\0halloffame.museum\0org.sb\0lviv.ua\0"
+"mill.museum\0org.rs\0org.sc\0"
+"org.sd\0"
+"idv.hk\0!omanmobile.om\0org.ru\0org.se\0"
+"langev\xc3\xa5g.no\0r\xc3\xa5holt.no\0starostwo.gov.pl\0"
+"trani-andria-barletta.it\0org.sg\0"
+"*.eg\0hvaler.no\0"
+"*.ehime.jp\0"
+"gmina.pl\0"
+"bod\xc3\xb8.no\0org.sl\0"
+"edu\0org.sn\0"
+"org.so\0lib.wi.us\0"
+"kommune.no\0"
+"nome.pt\0"
+"*.er\0namdalseid.no\0k12.wa.us\0"
+"nm.cn\0org.st\0"
+"*.et\0d\xc3\xb8nna.no\0"
+"jewish.museum\0preservation.museum\0"
+"slupsk.pl\0org.sy\0"
+"art.br\0org.sz\0org.tj\0"
+"ntr.br\0*.fj\0ski.no\0"
+"*.fk\0rimini.it\0grajewo.pl\0"
+"loppa.no\0"
+"franziskaner.museum\0notteroy.no\0org.tn\0"
+"org.to\0"
+"nesoddtangen.no\0"
+"org.ua\0"
+"discovery.museum\0wloclawek.pl\0"
+"lakas.hu\0org.tt\0"
+"kurgan.ru\0"
+"baltimore.museum\0nkz.ru\0org.tw\0"
+"com.ac\0castle.museum\0"
+"*.fukuoka.jp\0sandefjord.no\0varggat.no\0"
+"com.af\0"
+"com.ag\0"
+"ato.br\0k12.nj.us\0"
+"com.ai\0"
+"city.hu\0oryol.ru\0"
+"com.al\0nl.no\0mielno.pl\0cc.ma.us\0"
+"org.vc\0"
+"com.an\0g12.br\0"
+"*.gt\0"
+"*.gu\0"
+"com.ba\0"
+"com.bb\0americanart.museum\0"
+"org.vi\0"
+"kunstsammlung.museum\0"
+"com.aw\0"
+"flight.aero\0com.bh\0lib.mo.us\0org.vn\0"
+"com.bi\0adygeya.ru\0"
+"com.az\0"
+"art.dz\0"
+"com.bm\0"
+"dr\xc3\xb8""bak.no\0"
+"com.bo\0isla.pr\0"
+"com.br\0"
+"com.bs\0ustka.pl\0kuban.ru\0"
+"press.aero\0"
+"vs.it\0"
+"meloy.no\0"
+"*.il\0ulm.museum\0"
+"com.by\0com.ci\0genoa.it\0"
+"com.bz\0sn.cn\0"
+"lib.or.us\0"
+"santafe.museum\0org.ws\0"
+};
+
+QT_END_NAMESPACE
+
+#endif // QNETWORKCOOKIEJARTLD_P_H
diff --git a/src/network/access/qnetworkcookiejartlds_p.h.INFO b/src/network/access/qnetworkcookiejartlds_p.h.INFO
new file mode 100644
index 0000000..57a8d0e
--- /dev/null
+++ b/src/network/access/qnetworkcookiejartlds_p.h.INFO
@@ -0,0 +1,17 @@
+The file qnetworkcookiejartlds_p.h is generated from the Public Suffix
+List (see [1] and [2]), by the program residing at
+util/network/cookiejar-generateTLDs in the Qt source tree.
+
+That program generates a character array and an index array from the
+list to provide fast lookups of elements within C++.
+
+Those arrays in qnetworkcookiejartlds_p.h are derived from the Public
+Suffix List ([2]), which was originally provided by
+Jo Hermans <jo.hermans@gmail.com>.
+
+The file qnetworkcookiejartlds_p.h was last generated Friday,
+November 19th 15:24 2010.
+
+----
+[1] list: http://mxr.mozilla.org/mozilla-central/source/netwerk/dns/effective_tld_names.dat?raw=1
+[2] homepage: http://publicsuffix.org/
diff --git a/src/network/access/qnetworkdiskcache.cpp b/src/network/access/qnetworkdiskcache.cpp
index d35f0ce..2040b01 100644
--- a/src/network/access/qnetworkdiskcache.cpp
+++ b/src/network/access/qnetworkdiskcache.cpp
@@ -404,7 +404,7 @@ QIODevice *QNetworkDiskCache::data(const QUrl &url)
// ### verify that QFile uses the fd size and not the file name
qint64 size = file->size() - file->pos();
const uchar *p = 0;
-#ifndef Q_OS_WINCE
+#if !defined(Q_OS_WINCE) && !defined(Q_OS_INTEGRITY)
p = file->map(file->pos(), size);
#endif
if (p) {
diff --git a/src/network/access/qnetworkreplyfileimpl.cpp b/src/network/access/qnetworkreplyfileimpl.cpp
index 686eb5f..babee32 100644
--- a/src/network/access/qnetworkreplyfileimpl.cpp
+++ b/src/network/access/qnetworkreplyfileimpl.cpp
@@ -49,15 +49,10 @@
QT_BEGIN_NAMESPACE
QNetworkReplyFileImplPrivate::QNetworkReplyFileImplPrivate()
- : QNetworkReplyPrivate(), fileEngine(0), fileSize(0), filePos(0)
+ : QNetworkReplyPrivate(), realFileSize(0)
{
}
-QNetworkReplyFileImplPrivate::~QNetworkReplyFileImplPrivate()
-{
- delete fileEngine;
-}
-
QNetworkReplyFileImpl::~QNetworkReplyFileImpl()
{
}
@@ -112,15 +107,15 @@ QNetworkReplyFileImpl::QNetworkReplyFileImpl(QObject *parent, const QNetworkRequ
return;
}
- d->fileEngine = QAbstractFileEngine::create(fileName);
- bool opened = d->fileEngine->open(QIODevice::ReadOnly | QIODevice::Unbuffered);
+ d->realFile.setFileName(fileName);
+ bool opened = d->realFile.open(QIODevice::ReadOnly | QIODevice::Unbuffered);
// could we open the file?
if (!opened) {
QString msg = QCoreApplication::translate("QNetworkAccessFileBackend", "Error opening %1: %2")
- .arg(fileName, d->fileEngine->errorString());
+ .arg(d->realFile.fileName(), d->realFile.errorString());
- if (fi.exists()) {
+ if (d->realFile.exists()) {
setError(QNetworkReply::ContentAccessDenied, msg);
QMetaObject::invokeMethod(this, "error", Qt::QueuedConnection,
Q_ARG(QNetworkReply::NetworkError, QNetworkReply::ContentAccessDenied));
@@ -133,13 +128,13 @@ QNetworkReplyFileImpl::QNetworkReplyFileImpl(QObject *parent, const QNetworkRequ
return;
}
- d->fileSize = fi.size();
setHeader(QNetworkRequest::LastModifiedHeader, fi.lastModified());
- setHeader(QNetworkRequest::ContentLengthHeader, d->fileSize);
+ d->realFileSize = fi.size();
+ setHeader(QNetworkRequest::ContentLengthHeader, d->realFileSize);
QMetaObject::invokeMethod(this, "metaDataChanged", Qt::QueuedConnection);
QMetaObject::invokeMethod(this, "downloadProgress", Qt::QueuedConnection,
- Q_ARG(qint64, d->fileSize), Q_ARG(qint64, d->fileSize));
+ Q_ARG(qint64, d->realFileSize), Q_ARG(qint64, d->realFileSize));
QMetaObject::invokeMethod(this, "readyRead", Qt::QueuedConnection);
QMetaObject::invokeMethod(this, "finished", Qt::QueuedConnection);
}
@@ -147,25 +142,20 @@ void QNetworkReplyFileImpl::close()
{
Q_D(QNetworkReplyFileImpl);
QNetworkReply::close();
- if (d->fileEngine)
- d->fileEngine->close();
+ d->realFile.close();
}
void QNetworkReplyFileImpl::abort()
{
Q_D(QNetworkReplyFileImpl);
QNetworkReply::close();
- if (d->fileEngine)
- d->fileEngine->close();
+ d->realFile.close();
}
qint64 QNetworkReplyFileImpl::bytesAvailable() const
{
Q_D(const QNetworkReplyFileImpl);
- if (!d->fileEngine)
- return 0;
-
- return QNetworkReply::bytesAvailable() + d->fileSize - d->filePos;
+ return QNetworkReply::bytesAvailable() + d->realFile.bytesAvailable();
}
bool QNetworkReplyFileImpl::isSequential () const
@@ -176,7 +166,7 @@ bool QNetworkReplyFileImpl::isSequential () const
qint64 QNetworkReplyFileImpl::size() const
{
Q_D(const QNetworkReplyFileImpl);
- return d->fileSize;
+ return d->realFileSize;
}
/*!
@@ -185,17 +175,11 @@ qint64 QNetworkReplyFileImpl::size() const
qint64 QNetworkReplyFileImpl::readData(char *data, qint64 maxlen)
{
Q_D(QNetworkReplyFileImpl);
- if (!d->fileEngine)
+ qint64 ret = d->realFile.read(data, maxlen);
+ if (ret == 0 && bytesAvailable() == 0)
return -1;
-
- qint64 ret = d->fileEngine->read(data, maxlen);
- if (ret == 0 && bytesAvailable() == 0) {
- return -1; // everything had been read
- } else if (ret > 0) {
- d->filePos += ret;
- }
-
- return ret;
+ else
+ return ret;
}
diff --git a/src/network/access/qnetworkreplyfileimpl_p.h b/src/network/access/qnetworkreplyfileimpl_p.h
index 2bd64f8..c5126de 100644
--- a/src/network/access/qnetworkreplyfileimpl_p.h
+++ b/src/network/access/qnetworkreplyfileimpl_p.h
@@ -86,11 +86,9 @@ class QNetworkReplyFileImplPrivate: public QNetworkReplyPrivate
{
public:
QNetworkReplyFileImplPrivate();
- ~QNetworkReplyFileImplPrivate();
- QAbstractFileEngine *fileEngine;
- qint64 fileSize;
- qint64 filePos;
+ QFile realFile;
+ qint64 realFileSize;
Q_DECLARE_PUBLIC(QNetworkReplyFileImpl)
};
diff --git a/src/network/access/qnetworkreplyimpl.cpp b/src/network/access/qnetworkreplyimpl.cpp
index 50dbcc2..1c9fa3e 100644
--- a/src/network/access/qnetworkreplyimpl.cpp
+++ b/src/network/access/qnetworkreplyimpl.cpp
@@ -57,7 +57,7 @@ Q_DECLARE_METATYPE(QSharedPointer<char>)
QT_BEGIN_NAMESPACE
inline QNetworkReplyImplPrivate::QNetworkReplyImplPrivate()
- : backend(0), outgoingData(0), outgoingDataBuffer(0),
+ : backend(0), outgoingData(0),
copyDevice(0),
cacheEnabled(false), cacheSaveDevice(0),
notificationHandlingPaused(false),
@@ -97,7 +97,7 @@ void QNetworkReplyImplPrivate::_q_startOperation()
// state changes.
state = WaitingForSession;
- QNetworkSession *session = manager->d_func()->networkSession;
+ QNetworkSession *session = manager->d_func()->networkSession.data();
if (session) {
Q_Q(QNetworkReplyImpl);
@@ -115,7 +115,7 @@ void QNetworkReplyImplPrivate::_q_startOperation()
}
#endif
- if (backend->isSynchronous()) {
+ if (backend && backend->isSynchronous()) {
state = Finished;
q_func()->setFinished(true);
} else {
@@ -212,7 +212,7 @@ void QNetworkReplyImplPrivate::_q_bufferOutgoingData()
if (!outgoingDataBuffer) {
// first call, create our buffer
- outgoingDataBuffer = new QRingBuffer();
+ outgoingDataBuffer = QSharedPointer<QRingBuffer>(new QRingBuffer());
QObject::connect(outgoingData, SIGNAL(readyRead()), q, SLOT(_q_bufferOutgoingData()));
QObject::connect(outgoingData, SIGNAL(readChannelFinished()), q, SLOT(_q_bufferOutgoingDataFinished()));
@@ -257,7 +257,7 @@ void QNetworkReplyImplPrivate::_q_networkSessionConnected()
if (manager.isNull())
return;
- QNetworkSession *session = manager->d_func()->networkSession;
+ QNetworkSession *session = manager->d_func()->networkSession.data();
if (!session)
return;
@@ -306,20 +306,22 @@ void QNetworkReplyImplPrivate::setup(QNetworkAccessManager::Operation op, const
// Internal code that does a HTTP reply for the synchronous Ajax
// in QtWebKit.
QVariant synchronousHttpAttribute = req.attribute(
- static_cast<QNetworkRequest::Attribute>(QNetworkRequest::DownloadBufferAttribute + 1));
- if (synchronousHttpAttribute.toBool()) {
- backend->setSynchronous(true);
- if (outgoingData && outgoingData->isSequential()) {
- outgoingDataBuffer = new QRingBuffer();
- QByteArray data;
- do {
- data = outgoingData->readAll();
- if (data.isEmpty())
- break;
- outgoingDataBuffer->append(data);
- } while (1);
- }
+ static_cast<QNetworkRequest::Attribute>(QNetworkRequest::SynchronousRequestAttribute));
+ // The synchronous HTTP is a corner case, we will put all upload data in one big QByteArray in the outgoingDataBuffer.
+ // Yes, this is not the most efficient thing to do, but on the other hand synchronous XHR needs to die anyway.
+ if (synchronousHttpAttribute.toBool() && outgoingData) {
+ outgoingDataBuffer = QSharedPointer<QRingBuffer>(new QRingBuffer());
+ qint64 previousDataSize = 0;
+ do {
+ previousDataSize = outgoingDataBuffer->size();
+ outgoingDataBuffer->append(outgoingData->readAll());
+ } while (outgoingDataBuffer->size() != previousDataSize);
}
+
+ if (backend)
+ backend->setSynchronous(synchronousHttpAttribute.toBool());
+
+
if (outgoingData && backend && !backend->isSynchronous()) {
// there is data to be uploaded, e.g. HTTP POST.
@@ -349,10 +351,6 @@ void QNetworkReplyImplPrivate::setup(QNetworkAccessManager::Operation op, const
}
}
} else {
- // No outgoing data (e.g. HTTP GET request)
- // or no backend
- // if no backend, _q_startOperation will handle the error of this
-
// for HTTP, we want to send out the request as fast as possible to the network, without
// invoking methods in a QueuedConnection
#ifndef QT_NO_HTTP
@@ -362,7 +360,7 @@ void QNetworkReplyImplPrivate::setup(QNetworkAccessManager::Operation op, const
QMetaObject::invokeMethod(q, "_q_startOperation", Qt::QueuedConnection);
}
#else
- if (backend->isSynchronous())
+ if (backend && backend->isSynchronous())
_q_startOperation();
else
QMetaObject::invokeMethod(q, "_q_startOperation", Qt::QueuedConnection);
@@ -516,6 +514,13 @@ void QNetworkReplyImplPrivate::initCacheSaveDevice()
{
Q_Q(QNetworkReplyImpl);
+ // The disk cache does not support partial content, so don't even try to
+ // save any such content into the cache.
+ if (q->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt() == 206) {
+ cacheEnabled = false;
+ return;
+ }
+
// save the meta data
QNetworkCacheMetaData metaData;
metaData.setUrl(url);
@@ -634,8 +639,9 @@ char* QNetworkReplyImplPrivate::getDownloadBuffer(qint64 size)
{
Q_Q(QNetworkReplyImpl);
- // Check attribute() if allocating a buffer of that size can be allowed
if (!downloadBuffer) {
+ // We are requested to create it
+ // Check attribute() if allocating a buffer of that size can be allowed
QVariant bufferAllocationPolicy = request.attribute(QNetworkRequest::MaximumDownloadBufferSizeAttribute);
if (bufferAllocationPolicy.isValid() && bufferAllocationPolicy.toLongLong() >= size) {
downloadBufferCurrentSize = 0;
@@ -650,6 +656,18 @@ char* QNetworkReplyImplPrivate::getDownloadBuffer(qint64 size)
return downloadBuffer;
}
+void QNetworkReplyImplPrivate::setDownloadBuffer(QSharedPointer<char> sp, qint64 size)
+{
+ Q_Q(QNetworkReplyImpl);
+
+ downloadBufferPointer = sp;
+ downloadBuffer = downloadBufferPointer.data();
+ downloadBufferCurrentSize = 0;
+ downloadBufferMaximumSize = size;
+ q->setAttribute(QNetworkRequest::DownloadBufferAttribute, qVariantFromValue<QSharedPointer<char> > (downloadBufferPointer));
+}
+
+
void QNetworkReplyImplPrivate::appendDownstreamDataDownloadBuffer(qint64 bytesReceived, qint64 bytesTotal)
{
Q_Q(QNetworkReplyImpl);
@@ -693,7 +711,7 @@ void QNetworkReplyImplPrivate::finished()
if (!manager.isNull()) {
#ifndef QT_NO_BEARERMANAGEMENT
- QNetworkSession *session = manager->d_func()->networkSession;
+ QNetworkSession *session = manager->d_func()->networkSession.data();
if (session && session->state() == QNetworkSession::Roaming &&
state == Working && errorCode != QNetworkReply::OperationCanceledError) {
// only content with a known size will fail with a temporary network failure error
@@ -746,6 +764,11 @@ void QNetworkReplyImplPrivate::finished()
void QNetworkReplyImplPrivate::error(QNetworkReplyImpl::NetworkError code, const QString &errorMessage)
{
Q_Q(QNetworkReplyImpl);
+ // Can't set and emit multiple errors.
+ if (errorCode != QNetworkReply::NoError) {
+ qWarning() << "QNetworkReplyImplPrivate::error: Internal problem, this method must only be called once.";
+ return;
+ }
errorCode = code;
q->setErrorString(errorMessage);
@@ -803,9 +826,6 @@ QNetworkReplyImpl::~QNetworkReplyImpl()
// save had been properly finished. So if it is still enabled it means we got deleted/aborted.
if (d->isCachingEnabled())
d->networkCache()->remove(url());
-
- if (d->outgoingDataBuffer)
- delete d->outgoingDataBuffer;
}
void QNetworkReplyImpl::abort()
diff --git a/src/network/access/qnetworkreplyimpl_p.h b/src/network/access/qnetworkreplyimpl_p.h
index 238bee5..1a9ab7e 100644
--- a/src/network/access/qnetworkreplyimpl_p.h
+++ b/src/network/access/qnetworkreplyimpl_p.h
@@ -164,6 +164,7 @@ public:
void appendDownstreamData(QIODevice *data);
void appendDownstreamData(const QByteArray &data);
+ void setDownloadBuffer(QSharedPointer<char> sp, qint64 size);
char* getDownloadBuffer(qint64 size);
void appendDownstreamDataDownloadBuffer(qint64, qint64);
@@ -175,7 +176,7 @@ public:
QNetworkAccessBackend *backend;
QIODevice *outgoingData;
- QRingBuffer *outgoingDataBuffer;
+ QSharedPointer<QRingBuffer> outgoingDataBuffer;
QIODevice *copyDevice;
QAbstractNetworkCache *networkCache() const;
diff --git a/src/network/access/qnetworkrequest.cpp b/src/network/access/qnetworkrequest.cpp
index fc33e8d..a48a26f 100644
--- a/src/network/access/qnetworkrequest.cpp
+++ b/src/network/access/qnetworkrequest.cpp
@@ -226,6 +226,8 @@ QT_BEGIN_NAMESPACE
\omitvalue DownloadBufferAttribute
+ \omitvalue SynchronousRequestAttribute
+
\value User
Special type. Additional information can be passed in
QVariants with types ranging from User to UserMax. The default
@@ -529,8 +531,9 @@ QSslConfiguration QNetworkRequest::sslConfiguration() const
/*!
Sets this network request's SSL configuration to be \a config. The
settings that apply are the private key, the local certificate,
- the SSL protocol (SSLv2, SSLv3, TLSv1 where applicable) and the
- ciphers that the SSL backend is allowed to use.
+ the SSL protocol (SSLv2, SSLv3, TLSv1 where applicable), the CA
+ certificates and the ciphers that the SSL backend is allowed to
+ use.
By default, no SSL configuration is set, which allows the backends
to choose freely what configuration is best for them.
diff --git a/src/network/access/qnetworkrequest.h b/src/network/access/qnetworkrequest.h
index 586e6ff..b5ef109 100644
--- a/src/network/access/qnetworkrequest.h
+++ b/src/network/access/qnetworkrequest.h
@@ -84,9 +84,7 @@ public:
CookieSaveControlAttribute,
MaximumDownloadBufferSizeAttribute, // internal
DownloadBufferAttribute, // internal
-
- // (DownloadBufferAttribute + 1) is reserved internal for QSynchronousHttpNetworkReply
- // add the enum in 4.8
+ SynchronousRequestAttribute, // internal
User = 1000,
UserMax = 32767