diff options
author | Jo Asplin <jo.asplin@nokia.com> | 2011-09-06 13:46:40 +0200 |
---|---|---|
committer | Jo Asplin <jo.asplin@nokia.com> | 2011-09-09 09:32:17 +0200 |
commit | c59f9ad7768a007ca7a49ea11b16617529e86d52 (patch) | |
tree | d481be2a727f8461a76c2b729fc7e93784a3cff1 /tests/auto/network/access | |
parent | 2d41aff1e8557a43268bce631df834bfa79593cf (diff) |
Moved network autotests into new directory structure
Task-number: QTBUG-21223
Change-Id: I55dbf5c42a1c5d938b9e0c9bf7d90457a6c26bbc
Reviewed-on: http://codereview.qt-project.org/4259
Reviewed-by: Qt Sanity Bot <qt_sanity_bot@ovi.com>
Reviewed-by: Sergio Ahumada <sergio.ahumada@nokia.com>
Reviewed-by: Rohan McGovern <rohan.mcgovern@nokia.com>
Diffstat (limited to 'tests/auto/network/access')
77 files changed, 38937 insertions, 0 deletions
diff --git a/tests/auto/network/access/access.pro b/tests/auto/network/access/access.pro new file mode 100644 index 0000000000..53b16f07b8 --- /dev/null +++ b/tests/auto/network/access/access.pro @@ -0,0 +1,20 @@ +TEMPLATE=subdirs +SUBDIRS=\ + qnetworkdiskcache \ + qnetworkcookiejar \ + qnetworkaccessmanager \ + qnetworkcookie \ + qnetworkrequest \ + qhttpnetworkconnection \ + qnetworkreply \ + qnetworkcachemetadata \ + qftp \ + qhttpnetworkreply \ + qhttp \ + qabstractnetworkcache \ + +!contains(QT_CONFIG, private_tests): SUBDIRS -= \ + qhttpnetworkconnection \ + qhttpnetworkreply \ + + diff --git a/tests/auto/network/access/qabstractnetworkcache/.gitignore b/tests/auto/network/access/qabstractnetworkcache/.gitignore new file mode 100644 index 0000000000..72766dddce --- /dev/null +++ b/tests/auto/network/access/qabstractnetworkcache/.gitignore @@ -0,0 +1 @@ +tst_qabstractnetworkcache diff --git a/tests/auto/network/access/qabstractnetworkcache/qabstractnetworkcache.pro b/tests/auto/network/access/qabstractnetworkcache/qabstractnetworkcache.pro new file mode 100644 index 0000000000..4dea3c9c8c --- /dev/null +++ b/tests/auto/network/access/qabstractnetworkcache/qabstractnetworkcache.pro @@ -0,0 +1,14 @@ +load(qttest_p4) +QT += network +QT -= gui +SOURCES += tst_qabstractnetworkcache.cpp + +wince*|symbian: { + testFiles.files = tests + testFiles.path = . + DEPLOYMENT += testFiles +} + +symbian: TARGET.CAPABILITY = NetworkServices + +CONFIG += insignificant_test # QTBUG-20686; note, assumed unstable on all platforms diff --git a/tests/auto/network/access/qabstractnetworkcache/tests/httpcachetest_cachecontrol-expire.cgi b/tests/auto/network/access/qabstractnetworkcache/tests/httpcachetest_cachecontrol-expire.cgi new file mode 100755 index 0000000000..7dc506fc1e --- /dev/null +++ b/tests/auto/network/access/qabstractnetworkcache/tests/httpcachetest_cachecontrol-expire.cgi @@ -0,0 +1,7 @@ +#!/bin/bash +# cache control takes precedence over expires +echo "Cache-Control: max-age=-1" +echo "Expires: Mon, 30 Oct 2028 14:19:41 GMT" +echo "Content-type: text/html"; +echo "" +echo "Hello World!" diff --git a/tests/auto/network/access/qabstractnetworkcache/tests/httpcachetest_cachecontrol.cgi b/tests/auto/network/access/qabstractnetworkcache/tests/httpcachetest_cachecontrol.cgi new file mode 100755 index 0000000000..f2edfc161f --- /dev/null +++ b/tests/auto/network/access/qabstractnetworkcache/tests/httpcachetest_cachecontrol.cgi @@ -0,0 +1,13 @@ +#!/bin/bash +if [ ! -z ${HTTP_IF_MODIFIED_SINCE} ] ; then + echo "Status: 304" + echo "" + exit; +fi + +cc=`echo "${QUERY_STRING}" | sed -e s/%20/\ /g` +echo "Cache-Control: $cc" +echo "Last-Modified: Sat, 31 Oct 1981 06:00:00 GMT" +echo "Content-type: text/html"; +echo "" +echo "Hello World!" diff --git a/tests/auto/network/access/qabstractnetworkcache/tests/httpcachetest_cachecontrol200.cgi b/tests/auto/network/access/qabstractnetworkcache/tests/httpcachetest_cachecontrol200.cgi new file mode 100755 index 0000000000..e44d5ed570 --- /dev/null +++ b/tests/auto/network/access/qabstractnetworkcache/tests/httpcachetest_cachecontrol200.cgi @@ -0,0 +1,9 @@ +#!/bin/bash +cc=`echo "${QUERY_STRING}" | sed -e s/%20/\ /g` +echo "Status: 200" +echo "Cache-Control: $cc" +echo "Last-Modified: Sat, 31 Oct 1981 06:00:00 GMT" +echo "Content-type: text/html"; +echo "X-Script: $0" +echo "" +echo "Hello World!" diff --git a/tests/auto/network/access/qabstractnetworkcache/tests/httpcachetest_etag200.cgi b/tests/auto/network/access/qabstractnetworkcache/tests/httpcachetest_etag200.cgi new file mode 100755 index 0000000000..0966abfdd1 --- /dev/null +++ b/tests/auto/network/access/qabstractnetworkcache/tests/httpcachetest_etag200.cgi @@ -0,0 +1,5 @@ +#!/bin/bash +echo "ETag: foo" +echo "Content-type: text/html"; +echo "" +echo "Hello World!" diff --git a/tests/auto/network/access/qabstractnetworkcache/tests/httpcachetest_etag304.cgi b/tests/auto/network/access/qabstractnetworkcache/tests/httpcachetest_etag304.cgi new file mode 100755 index 0000000000..91a4b922bd --- /dev/null +++ b/tests/auto/network/access/qabstractnetworkcache/tests/httpcachetest_etag304.cgi @@ -0,0 +1,11 @@ +#!/bin/bash +if [ ! -z ${HTTP_IF_NONE_MATCH} ] ; then + echo "Status: 304" + echo "" + exit; +fi + +echo "ETag: foo" +echo "Content-type: text/html"; +echo "" +echo "Hello World!" diff --git a/tests/auto/network/access/qabstractnetworkcache/tests/httpcachetest_expires200.cgi b/tests/auto/network/access/qabstractnetworkcache/tests/httpcachetest_expires200.cgi new file mode 100755 index 0000000000..e18ebc86ad --- /dev/null +++ b/tests/auto/network/access/qabstractnetworkcache/tests/httpcachetest_expires200.cgi @@ -0,0 +1,5 @@ +#!/bin/bash +echo "Expires: Sat, 31 Oct 1981 6:00:00 GMT" +echo "Content-type: text/html"; +echo "" +echo "Hello World!" diff --git a/tests/auto/network/access/qabstractnetworkcache/tests/httpcachetest_expires304.cgi b/tests/auto/network/access/qabstractnetworkcache/tests/httpcachetest_expires304.cgi new file mode 100755 index 0000000000..1c7de1cd77 --- /dev/null +++ b/tests/auto/network/access/qabstractnetworkcache/tests/httpcachetest_expires304.cgi @@ -0,0 +1,11 @@ +#!/bin/bash +if [ ${HTTP_IF_MODIFIED_SINCE} == "Mon, 30 Oct 2028 14:19:41 GMT" ] ; then + echo "Status: 304" + echo "" + exit; +fi + +echo "Expires: Mon, 30 Oct 2028 14:19:41 GMT" +echo "Content-type: text/html"; +echo "" +echo "Hello World!" diff --git a/tests/auto/network/access/qabstractnetworkcache/tests/httpcachetest_expires500.cgi b/tests/auto/network/access/qabstractnetworkcache/tests/httpcachetest_expires500.cgi new file mode 100755 index 0000000000..9615c4f0bd --- /dev/null +++ b/tests/auto/network/access/qabstractnetworkcache/tests/httpcachetest_expires500.cgi @@ -0,0 +1,11 @@ +#!/bin/bash +if [ ! -z ${HTTP_IF_MODIFIED_SINCE} ] ; then + echo "Status: 500" + echo "" + exit; +fi + +echo "Expires: Mon, 30 Oct 2028 14:19:41 GMT" +echo "Content-type: text/html"; +echo "" +echo "Hello World!" diff --git a/tests/auto/network/access/qabstractnetworkcache/tests/httpcachetest_lastModified200.cgi b/tests/auto/network/access/qabstractnetworkcache/tests/httpcachetest_lastModified200.cgi new file mode 100755 index 0000000000..5dc219b1e7 --- /dev/null +++ b/tests/auto/network/access/qabstractnetworkcache/tests/httpcachetest_lastModified200.cgi @@ -0,0 +1,5 @@ +#!/bin/bash +echo "Last-Modified: Sat, 31 Oct 1981 6:00:00 GMT" +echo "Content-type: text/html"; +echo "" +echo "Hello World!" diff --git a/tests/auto/network/access/qabstractnetworkcache/tests/httpcachetest_lastModified304.cgi b/tests/auto/network/access/qabstractnetworkcache/tests/httpcachetest_lastModified304.cgi new file mode 100755 index 0000000000..bdf23bed2f --- /dev/null +++ b/tests/auto/network/access/qabstractnetworkcache/tests/httpcachetest_lastModified304.cgi @@ -0,0 +1,11 @@ +#!/bin/bash +if [ ${HTTP_IF_MODIFIED_SINCE} == "Sat, 31 Oct 1981 06:00:00 GMT" ] ; then + echo "Status: 304" + echo "" + exit; +fi + +echo "Last-Modified: Sat, 31 Oct 1981 06:00:00 GMT" +echo "Content-type: text/html"; +echo "" +echo "Hello World!" diff --git a/tests/auto/network/access/qabstractnetworkcache/tst_qabstractnetworkcache.cpp b/tests/auto/network/access/qabstractnetworkcache/tst_qabstractnetworkcache.cpp new file mode 100644 index 0000000000..244c9b13b5 --- /dev/null +++ b/tests/auto/network/access/qabstractnetworkcache/tst_qabstractnetworkcache.cpp @@ -0,0 +1,416 @@ +/**************************************************************************** +** +** 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 test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** 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. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + + +#include <QtTest/QtTest> +#include <QtNetwork/QtNetwork> +#include "../../../../shared/util.h" +#include "../../../network-settings.h" + +#ifndef QT_NO_BEARERMANAGEMENT +#include <QtNetwork/qnetworkconfigmanager.h> +#include <QtNetwork/qnetworkconfiguration.h> +#include <QtNetwork/qnetworksession.h> +#endif + +#define TESTFILE QString("http://%1/qtest/cgi-bin/").arg(QtNetworkSettings::serverName()) + +class tst_QAbstractNetworkCache : public QObject +{ + Q_OBJECT + +public: + tst_QAbstractNetworkCache(); + virtual ~tst_QAbstractNetworkCache(); + +private slots: + void initTestCase(); + void expires_data(); + void expires(); + void expiresSynchronous_data(); + void expiresSynchronous(); + + void lastModified_data(); + void lastModified(); + void lastModifiedSynchronous_data(); + void lastModifiedSynchronous(); + + void etag_data(); + void etag(); + void etagSynchronous_data(); + void etagSynchronous(); + + void cacheControl_data(); + void cacheControl(); + void cacheControlSynchronous_data(); + void cacheControlSynchronous(); + + void deleteCache(); + +private: + void check(); + void checkSynchronous(); + +#ifndef QT_NO_BEARERMANAGEMENT + QNetworkConfigurationManager *netConfMan; + QNetworkConfiguration networkConfiguration; + QScopedPointer<QNetworkSession> networkSession; +#endif +}; + +class NetworkDiskCache : public QNetworkDiskCache +{ + Q_OBJECT +public: + NetworkDiskCache(QObject *parent = 0) + : QNetworkDiskCache(parent) + , gotData(false) + { + QString location = QDir::tempPath() + QLatin1String("/tst_qnetworkdiskcache/"); + setCacheDirectory(location); + clear(); + } + + QIODevice *data(const QUrl &url) + { + gotData = true; + return QNetworkDiskCache::data(url); + } + + bool gotData; +}; + + +tst_QAbstractNetworkCache::tst_QAbstractNetworkCache() +{ + Q_SET_DEFAULT_IAP + + QCoreApplication::setOrganizationName(QLatin1String("Trolltech")); + QCoreApplication::setApplicationName(QLatin1String("autotest_qabstractnetworkcache")); + QCoreApplication::setApplicationVersion(QLatin1String("1.0")); +} + +tst_QAbstractNetworkCache::~tst_QAbstractNetworkCache() +{ +} + +static bool AlwaysTrue = true; +static bool AlwaysFalse = false; + +Q_DECLARE_METATYPE(QNetworkRequest::CacheLoadControl) + + +void tst_QAbstractNetworkCache::initTestCase() +{ +#ifndef QT_NO_BEARERMANAGEMENT + netConfMan = new QNetworkConfigurationManager(this); + networkConfiguration = netConfMan->defaultConfiguration(); + networkSession.reset(new QNetworkSession(networkConfiguration)); + if (!networkSession->isOpen()) { + networkSession->open(); + QVERIFY(networkSession->waitForOpened(30000)); + } +#endif +} + + +void tst_QAbstractNetworkCache::expires_data() +{ + QTest::addColumn<QNetworkRequest::CacheLoadControl>("cacheLoadControl"); + QTest::addColumn<QString>("url"); + QTest::addColumn<bool>("fetchFromCache"); + + QTest::newRow("304-0") << QNetworkRequest::AlwaysNetwork << "httpcachetest_expires304.cgi" << AlwaysFalse; + QTest::newRow("304-1") << QNetworkRequest::PreferNetwork << "httpcachetest_expires304.cgi" << true; + QTest::newRow("304-2") << QNetworkRequest::AlwaysCache << "httpcachetest_expires304.cgi" << AlwaysTrue; + QTest::newRow("304-3") << QNetworkRequest::PreferCache << "httpcachetest_expires304.cgi" << true; + + QTest::newRow("500-0") << QNetworkRequest::AlwaysNetwork << "httpcachetest_expires500.cgi" << AlwaysFalse; + QTest::newRow("500-1") << QNetworkRequest::PreferNetwork << "httpcachetest_expires500.cgi" << true; + QTest::newRow("500-2") << QNetworkRequest::AlwaysCache << "httpcachetest_expires500.cgi" << AlwaysTrue; + QTest::newRow("500-3") << QNetworkRequest::PreferCache << "httpcachetest_expires500.cgi" << true; + + QTest::newRow("200-0") << QNetworkRequest::AlwaysNetwork << "httpcachetest_expires200.cgi" << AlwaysFalse; + QTest::newRow("200-1") << QNetworkRequest::PreferNetwork << "httpcachetest_expires200.cgi" << false; + QTest::newRow("200-2") << QNetworkRequest::AlwaysCache << "httpcachetest_expires200.cgi" << AlwaysTrue; + QTest::newRow("200-3") << QNetworkRequest::PreferCache << "httpcachetest_expires200.cgi" << false; +} + +void tst_QAbstractNetworkCache::expires() +{ + check(); +} + +void tst_QAbstractNetworkCache::expiresSynchronous_data() +{ + expires_data(); +} + +void tst_QAbstractNetworkCache::expiresSynchronous() +{ + checkSynchronous(); +} + +void tst_QAbstractNetworkCache::lastModified_data() +{ + QTest::addColumn<QNetworkRequest::CacheLoadControl>("cacheLoadControl"); + QTest::addColumn<QString>("url"); + QTest::addColumn<bool>("fetchFromCache"); + + QTest::newRow("304-0") << QNetworkRequest::AlwaysNetwork << "httpcachetest_lastModified304.cgi" << AlwaysFalse; + QTest::newRow("304-1") << QNetworkRequest::PreferNetwork << "httpcachetest_lastModified304.cgi" << true; + QTest::newRow("304-2") << QNetworkRequest::AlwaysCache << "httpcachetest_lastModified304.cgi" << AlwaysTrue; + QTest::newRow("304-3") << QNetworkRequest::PreferCache << "httpcachetest_lastModified304.cgi" << true; + + QTest::newRow("200-0") << QNetworkRequest::AlwaysNetwork << "httpcachetest_lastModified200.cgi" << AlwaysFalse; + QTest::newRow("200-1") << QNetworkRequest::PreferNetwork << "httpcachetest_lastModified200.cgi" << false; + QTest::newRow("200-2") << QNetworkRequest::AlwaysCache << "httpcachetest_lastModified200.cgi" << AlwaysTrue; + QTest::newRow("200-3") << QNetworkRequest::PreferCache << "httpcachetest_lastModified200.cgi" << false; +} + +void tst_QAbstractNetworkCache::lastModified() +{ + check(); +} + +void tst_QAbstractNetworkCache::lastModifiedSynchronous_data() +{ + tst_QAbstractNetworkCache::lastModified_data(); +} + +void tst_QAbstractNetworkCache::lastModifiedSynchronous() +{ + checkSynchronous(); +} + +void tst_QAbstractNetworkCache::etag_data() +{ + QTest::addColumn<QNetworkRequest::CacheLoadControl>("cacheLoadControl"); + QTest::addColumn<QString>("url"); + QTest::addColumn<bool>("fetchFromCache"); + + QTest::newRow("304-0") << QNetworkRequest::AlwaysNetwork << "httpcachetest_etag304.cgi" << AlwaysFalse; + QTest::newRow("304-1") << QNetworkRequest::PreferNetwork << "httpcachetest_etag304.cgi" << true; + QTest::newRow("304-2") << QNetworkRequest::AlwaysCache << "httpcachetest_etag304.cgi" << AlwaysTrue; + QTest::newRow("304-3") << QNetworkRequest::PreferCache << "httpcachetest_etag304.cgi" << true; + + QTest::newRow("200-0") << QNetworkRequest::AlwaysNetwork << "httpcachetest_etag200.cgi" << AlwaysFalse; + QTest::newRow("200-1") << QNetworkRequest::PreferNetwork << "httpcachetest_etag200.cgi" << false; + QTest::newRow("200-2") << QNetworkRequest::AlwaysCache << "httpcachetest_etag200.cgi" << AlwaysTrue; + QTest::newRow("200-3") << QNetworkRequest::PreferCache << "httpcachetest_etag200.cgi" << false; +} + +void tst_QAbstractNetworkCache::etag() +{ + check(); +} + +void tst_QAbstractNetworkCache::etagSynchronous_data() +{ + tst_QAbstractNetworkCache::etag_data(); +} + +void tst_QAbstractNetworkCache::etagSynchronous() +{ + checkSynchronous(); +} + +void tst_QAbstractNetworkCache::cacheControl_data() +{ + QTest::addColumn<QNetworkRequest::CacheLoadControl>("cacheLoadControl"); + QTest::addColumn<QString>("url"); + QTest::addColumn<bool>("fetchFromCache"); + QTest::newRow("200-0") << QNetworkRequest::PreferNetwork << "httpcachetest_cachecontrol.cgi?max-age=-1" << true; + QTest::newRow("200-1") << QNetworkRequest::PreferNetwork << "httpcachetest_cachecontrol-expire.cgi" << false; + + QTest::newRow("200-2") << QNetworkRequest::AlwaysNetwork << "httpcachetest_cachecontrol.cgi?no-cache" << AlwaysFalse; + QTest::newRow("200-3") << QNetworkRequest::PreferNetwork << "httpcachetest_cachecontrol.cgi?no-cache" << false; + QTest::newRow("200-4") << QNetworkRequest::AlwaysCache << "httpcachetest_cachecontrol.cgi?no-cache" << false; + QTest::newRow("200-5") << QNetworkRequest::PreferCache << "httpcachetest_cachecontrol.cgi?no-cache" << false; + + QTest::newRow("304-0") << QNetworkRequest::PreferNetwork << "httpcachetest_cachecontrol.cgi?max-age=1000" << true; + + QTest::newRow("304-1") << QNetworkRequest::AlwaysNetwork << "httpcachetest_cachecontrol.cgi?max-age=1000, must-revalidate" << AlwaysFalse; + QTest::newRow("304-2") << QNetworkRequest::PreferNetwork << "httpcachetest_cachecontrol.cgi?max-age=1000, must-revalidate" << true; + QTest::newRow("304-3") << QNetworkRequest::AlwaysCache << "httpcachetest_cachecontrol.cgi?max-age=1000, must-revalidate" << false; + QTest::newRow("304-4") << QNetworkRequest::PreferCache << "httpcachetest_cachecontrol.cgi?max-age=1000, must-revalidate" << true; + + // see QTBUG-7060 + //QTest::newRow("nokia-boston") << QNetworkRequest::PreferNetwork << "http://waplabdc.nokia-boston.com/browser/users/venkat/cache/Cache_directives/private_1b.asp" << true; + QTest::newRow("304-2b") << QNetworkRequest::PreferNetwork << "httpcachetest_cachecontrol200.cgi?private, max-age=1000" << true; + QTest::newRow("304-4b") << QNetworkRequest::PreferCache << "httpcachetest_cachecontrol200.cgi?private, max-age=1000" << true; +} + +void tst_QAbstractNetworkCache::cacheControl() +{ + check(); +} + +void tst_QAbstractNetworkCache::cacheControlSynchronous_data() +{ + tst_QAbstractNetworkCache::cacheControl_data(); +} + +void tst_QAbstractNetworkCache::cacheControlSynchronous() +{ + checkSynchronous(); +} + +void tst_QAbstractNetworkCache::check() +{ + QFETCH(QNetworkRequest::CacheLoadControl, cacheLoadControl); + QFETCH(QString, url); + QFETCH(bool, fetchFromCache); + + QNetworkAccessManager manager; + NetworkDiskCache *diskCache = new NetworkDiskCache(&manager); + manager.setCache(diskCache); + QCOMPARE(diskCache->gotData, false); + + QUrl realUrl = url.contains("://") ? url : TESTFILE + url; + QNetworkRequest request(realUrl); + + // prime the cache + QNetworkReply *reply = manager.get(request); + QSignalSpy downloaded1(reply, SIGNAL(finished())); + QTRY_COMPARE(downloaded1.count(), 1); + QCOMPARE(diskCache->gotData, false); + QByteArray goodData = reply->readAll(); + + request.setAttribute(QNetworkRequest::CacheLoadControlAttribute, cacheLoadControl); + + // should be in the cache now + QNetworkReply *reply2 = manager.get(request); + QSignalSpy downloaded2(reply2, SIGNAL(finished())); + QTRY_COMPARE(downloaded2.count(), 1); + + QByteArray secondData = reply2->readAll(); + if (!fetchFromCache && cacheLoadControl == QNetworkRequest::AlwaysCache) { + QCOMPARE(reply2->error(), QNetworkReply::ContentNotFoundError); + QCOMPARE(secondData, QByteArray()); + } else { + QCOMPARE(reply2->error(), QNetworkReply::NoError); + QCOMPARE(QString(secondData), QString(goodData)); + QCOMPARE(secondData, goodData); + QCOMPARE(reply2->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(), 200); + } + + if (fetchFromCache) { + QList<QByteArray> rawHeaderList = reply->rawHeaderList(); + QList<QByteArray> rawHeaderList2 = reply2->rawHeaderList(); + qSort(rawHeaderList); + qSort(rawHeaderList2); + } + QCOMPARE(diskCache->gotData, fetchFromCache); +} + +void tst_QAbstractNetworkCache::checkSynchronous() +{ + QSKIP("not working yet, see QTBUG-15221", SkipAll); + + QFETCH(QNetworkRequest::CacheLoadControl, cacheLoadControl); + QFETCH(QString, url); + QFETCH(bool, fetchFromCache); + + QNetworkAccessManager manager; + NetworkDiskCache *diskCache = new NetworkDiskCache(&manager); + manager.setCache(diskCache); + QCOMPARE(diskCache->gotData, false); + + QUrl realUrl = url.contains("://") ? url : TESTFILE + url; + QNetworkRequest request(realUrl); + + request.setAttribute( + QNetworkRequest::SynchronousRequestAttribute, + true); + + // prime the cache + QNetworkReply *reply = manager.get(request); + QVERIFY(reply->isFinished()); // synchronous + QCOMPARE(diskCache->gotData, false); + QByteArray goodData = reply->readAll(); + + request.setAttribute(QNetworkRequest::CacheLoadControlAttribute, cacheLoadControl); + + // should be in the cache now + QNetworkReply *reply2 = manager.get(request); + QVERIFY(reply2->isFinished()); // synchronous + + QByteArray secondData = reply2->readAll(); + if (!fetchFromCache && cacheLoadControl == QNetworkRequest::AlwaysCache) { + QCOMPARE(reply2->error(), QNetworkReply::ContentNotFoundError); + QCOMPARE(secondData, QByteArray()); + } else { + if (reply2->error() != QNetworkReply::NoError) + qDebug() << reply2->errorString(); + QCOMPARE(reply2->error(), QNetworkReply::NoError); + QCOMPARE(QString(secondData), QString(goodData)); + QCOMPARE(secondData, goodData); + QCOMPARE(reply2->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(), 200); + } + + if (fetchFromCache) { + QList<QByteArray> rawHeaderList = reply->rawHeaderList(); + QList<QByteArray> rawHeaderList2 = reply2->rawHeaderList(); + qSort(rawHeaderList); + qSort(rawHeaderList2); + } + QCOMPARE(diskCache->gotData, fetchFromCache); +} + +void tst_QAbstractNetworkCache::deleteCache() +{ + QNetworkAccessManager manager; + NetworkDiskCache *diskCache = new NetworkDiskCache(&manager); + manager.setCache(diskCache); + + QString url = "httpcachetest_cachecontrol.cgi?max-age=1000"; + QNetworkRequest request(QUrl(TESTFILE + url)); + QNetworkReply *reply = manager.get(request); + QSignalSpy downloaded1(reply, SIGNAL(finished())); + manager.setCache(0); + QTRY_COMPARE(downloaded1.count(), 1); +} + + +QTEST_MAIN(tst_QAbstractNetworkCache) +#include "tst_qabstractnetworkcache.moc" + diff --git a/tests/auto/network/access/qftp/.gitattributes b/tests/auto/network/access/qftp/.gitattributes new file mode 100644 index 0000000000..e04709aa2e --- /dev/null +++ b/tests/auto/network/access/qftp/.gitattributes @@ -0,0 +1 @@ +rfc3252.txt -crlf diff --git a/tests/auto/network/access/qftp/.gitignore b/tests/auto/network/access/qftp/.gitignore new file mode 100644 index 0000000000..7a4845df05 --- /dev/null +++ b/tests/auto/network/access/qftp/.gitignore @@ -0,0 +1,2 @@ +tst_qftp +tst_QFtp_activeMode_inittab diff --git a/tests/auto/network/access/qftp/qftp.pro b/tests/auto/network/access/qftp/qftp.pro new file mode 100644 index 0000000000..8f63d6e26e --- /dev/null +++ b/tests/auto/network/access/qftp/qftp.pro @@ -0,0 +1,22 @@ +load(qttest_p4) +SOURCES += tst_qftp.cpp + + +QT = core network network-private + +wince*: { + addFiles.files = rfc3252.txt + addFiles.path = . + DEPLOYMENT += addFiles + DEFINES += SRCDIR=\\\"\\\" +} else:symbian { + addFiles.files = rfc3252.txt + addFiles.path = . + DEPLOYMENT += addFiles + TARGET.EPOCHEAPSIZE="0x100 0x1000000" + TARGET.CAPABILITY = NetworkServices +} else { + DEFINES += SRCDIR=\\\"$$PWD/\\\" +} + +CONFIG+=insignificant_test # uses live qt-test-server, inherently unstable diff --git a/tests/auto/network/access/qftp/rfc3252.txt b/tests/auto/network/access/qftp/rfc3252.txt new file mode 100644 index 0000000000..b80c61bf0a --- /dev/null +++ b/tests/auto/network/access/qftp/rfc3252.txt @@ -0,0 +1,899 @@ + + + + + + +Network Working Group H. Kennedy +Request for Comments: 3252 Mimezine +Category: Informational 1 April 2002 + + + Binary Lexical Octet Ad-hoc Transport + +Status of this Memo + + This memo provides information for the Internet community. It does + not specify an Internet standard of any kind. Distribution of this + memo is unlimited. + +Copyright Notice + + Copyright (C) The Internet Society (2002). All Rights Reserved. + +Abstract + + This document defines a reformulation of IP and two transport layer + protocols (TCP and UDP) as XML applications. + +1. Introduction + +1.1. Overview + + This document describes the Binary Lexical Octet Ad-hoc Transport + (BLOAT): a reformulation of a widely-deployed network-layer protocol + (IP [RFC791]), and two associated transport layer protocols (TCP + [RFC793] and UDP [RFC768]) as XML [XML] applications. It also + describes methods for transporting BLOAT over Ethernet and IEEE 802 + networks as well as encapsulating BLOAT in IP for gatewaying BLOAT + across the public Internet. + +1.2. Motivation + + The wild popularity of XML as a basis for application-level protocols + such as the Blocks Extensible Exchange Protocol [RFC3080], the Simple + Object Access Protocol [SOAP], and Jabber [JABBER] prompted + investigation into the possibility of extending the use of XML in the + protocol stack. Using XML at both the transport and network layer in + addition to the application layer would provide for an amazing amount + of power and flexibility while removing dependencies on proprietary + and hard-to-understand binary protocols. This protocol unification + would also allow applications to use a single XML parser for all + aspects of their operation, eliminating developer time spent figuring + out the intricacies of each new protocol, and moving the hard work of + + + + +Kennedy Informational [Page 1] + +RFC 3252 Binary Lexical Octet Ad-hoc Transport 1 April 2002 + + + parsing to the XML toolset. The use of XML also mitigates concerns + over "network vs. host" byte ordering which is at the root of many + network application bugs. + +1.3. Relation to Existing Protocols + + The reformulations specified in this RFC follow as closely as + possible the spirit of the RFCs on which they are based, and so MAY + contain elements or attributes that would not be needed in a pure + reworking (e.g. length attributes, which are implicit in XML.) + + The layering of network and transport protocols are maintained in + this RFC despite the optimizations that could be made if the line + were somewhat blurred (i.e. merging TCP and IP into a single, larger + element in the DTD) in order to foster future use of this protocol as + a basis for reformulating other protocols (such as ICMP.) + + Other than the encoding, the behavioral aspects of each of the + existing protocols remain unchanged. Routing, address spaces, TCP + congestion control, etc. behave as specified in the extant standards. + Adapting to new standards and experimental algorithm heuristics for + improving performance will become much easier once the move to BLOAT + has been completed. + +1.4. Requirement Levels + + The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", + "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this + document are to be interpreted as described in BCP 14, RFC 2119 + [RFC2119]. + +2. IPoXML + + This protocol MUST be implemented to be compliant with this RFC. + IPoXML is the root protocol REQUIRED for effective use of TCPoXML + (section 3.) and higher-level application protocols. + + The DTD for this document type can be found in section 7.1. + + The routing of IPoXML can be easily implemented on hosts with an XML + parser, as the regular structure lends itself handily to parsing and + validation of the document/datagram and then processing the + destination address, TTL, and checksum before sending it on to its + next-hop. + + The reformulation of IPv4 was chosen over IPv6 [RFC2460] due to the + wider deployment of IPv4 and the fact that implementing IPv6 as XML + would have exceeded the 1500 byte Ethernet MTU. + + + +Kennedy Informational [Page 2] + +RFC 3252 Binary Lexical Octet Ad-hoc Transport 1 April 2002 + + + All BLOAT implementations MUST use - and specify - the UTF-8 encoding + of RFC 2279 [RFC2279]. All BLOAT document/datagrams MUST be well- + formed and include the XMLDecl. + +2.1. IP Description + + A number of items have changed (for the better) from the original IP + specification. Bit-masks, where present have been converted into + human-readable values. IP addresses are listed in their dotted- + decimal notation [RFC1123]. Length and checksum values are present + as decimal integers. + + To calculate the length and checksum fields of the IP element, a + canonicalized form of the element MUST be used. The canonical form + SHALL have no whitespace (including newline characters) between + elements and only one space character between attributes. There + SHALL NOT be a space following the last attribute in an element. + + An iterative method SHOULD be used to calculate checksums, as the + length field will vary based on the size of the checksum. + + The payload element bears special attention. Due to the character + set restrictions of XML, the payload of IP datagrams (which MAY + contain arbitrary data) MUST be encoded for transport. This RFC + REQUIRES the contents of the payload to be encoded in the base-64 + encoding of RFC 2045 [RFC2045], but removes the requirement that the + encoded output MUST be wrapped on 76-character lines. + + + + + + + + + + + + + + + + + + + + + + + + +Kennedy Informational [Page 3] + +RFC 3252 Binary Lexical Octet Ad-hoc Transport 1 April 2002 + + +2.2. Example Datagram + + The following is an example IPoXML datagram with an empty payload: + + <?xml version="1.0" encoding="UTF-8"?> + <!DOCTYPE ip PUBLIC "-//IETF//DTD BLOAT 1.0 IP//EN" "bloat.dtd"> + <ip> + <header length="474"> + <version value="4"/> + <tos precedence="Routine" delay="Normal" throughput="Normal" + relibility="Normal" reserved="0"/> + <total.length value="461"/> + <id value="1"/> + <flags reserved="0" df="dont" mf="last"/> + <offset value="0"/> + <ttl value="255"/> + <protocol value="6"/> + <checksum value="8707"/> + <source address="10.0.0.22"/> + <destination address="10.0.0.1"/> + <options> + <end copied="0" class="0" number="0"/> + </options> + <padding pad="0"/> + </header> + <payload> + </payload> + </ip> + +3. TCPoXML + + This protocol MUST be implemented to be compliant with this RFC. The + DTD for this document type can be found in section 7.2. + +3.1. TCP Description + + A number of items have changed from the original TCP specification. + Bit-masks, where present have been converted into human-readable + values. Length and checksum and port values are present as decimal + integers. + + To calculate the length and checksum fields of the TCP element, a + canonicalized form of the element MUST be used as in section 2.1. + + An iterative method SHOULD be used to calculate checksums as in + section 2.1. + + The payload element MUST be encoded as in section 2.1. + + + +Kennedy Informational [Page 4] + +RFC 3252 Binary Lexical Octet Ad-hoc Transport 1 April 2002 + + + The TCP offset element was expanded to a maximum of 255 from 16 to + allow for the increased size of the header in XML. + + TCPoXML datagrams encapsulated by IPoXML MAY omit the <?xml?> header + as well as the <!DOCTYPE> declaration. + +3.2. Example Datagram + + The following is an example TCPoXML datagram with an empty payload: + + <?xml version="1.0" encoding="UTF-8"?> + <!DOCTYPE tcp PUBLIC "-//IETF//DTD BLOAT 1.0 TCP//EN" "bloat.dtd"> + <tcp> + <tcp.header> + <src port="31415"/> + <dest port="42424"/> + <sequence number="322622954"/> + <acknowledgement number="689715995"/> + <offset number=""/> + <reserved value="0"/> + <control syn="1" ack="1"/> + <window size="1"/> + <urgent pointer="0"/> + <checksum value="2988"/> + <tcp.options> + <tcp.end kind="0"/> + </tcp.options> + <padding pad="0"/> + </tcp.header> + <payload> + </payload> + </tcp> + +4. UDPoXML + + This protocol MUST be implemented to be compliant with this RFC. The + DTD for this document type can be found in section 7.3. + +4.1. UDP Description + + A number of items have changed from the original UDP specification. + Bit-masks, where present have been converted into human-readable + values. Length and checksum and port values are present as decimal + integers. + + + + + + + +Kennedy Informational [Page 5] + +RFC 3252 Binary Lexical Octet Ad-hoc Transport 1 April 2002 + + + To calculate the length and checksum fields of the UDP element, a + canonicalized form of the element MUST be used as in section 2.1. An + iterative method SHOULD be used to calculate checksums as in section + 2.1. + + The payload element MUST be encoded as in section 2.1. + + UDPoXML datagrams encapsulated by IPoXML MAY omit the <?xml?> header + as well as the <!DOCTYPE> declaration. + +4.2. Example Datagram + + The following is an example UDPoXML datagram with an empty payload: + + <?xml version="1.0" encoding="UTF-8"?> + <!DOCTYPE udp PUBLIC "-//IETF//DTD BLOAT 1.0 UDP//EN" "bloat.dtd"> + <udp> + <udp.header> + <src port="31415"/> + <dest port="42424"/> + <udp.length value="143"/> + <checksum value="2988"/> + </udp.header> + <payload> + </payload> + </udp> + +5. Network Transport + + This document provides for the transmission of BLOAT datagrams over + two common families of physical layer transport. Future RFCs will + address additional transports as routing vendors catch up to the + specification, and we begin to see BLOAT routed across the Internet + backbone. + +5.1. Ethernet + + BLOAT is encapsulated in Ethernet datagrams as in [RFC894] with the + exception that the type field of the Ethernet frame MUST contain the + value 0xBEEF. The first 5 octets of the Ethernet frame payload will + be 0x3c 3f 78 6d 6c ("<?xml".) + +5.2. IEEE 802 + + BLOAT is encapsulated in IEEE 802 Networks as in [RFC1042] except + that the protocol type code for IPoXML is 0xBEEF. + + + + + +Kennedy Informational [Page 6] + +RFC 3252 Binary Lexical Octet Ad-hoc Transport 1 April 2002 + + +6. Gatewaying over IP + + In order to facilitate the gradual introduction of BLOAT into the + public Internet, BLOAT MAY be encapsulated in IP as in [RFC2003] to + gateway between networks that run BLOAT natively on their LANs. + +7. DTDs + + The Transport DTDs (7.2. and 7.3.) build on the definitions in the + Network DTD (7.1.) + + The DTDs are referenced by their PubidLiteral and SystemLiteral (from + [XML]) although it is understood that most IPoXML implementations + will not need to pull down the DTD, as it will normally be embedded + in the implementation, and presents something of a catch-22 if you + need to load part of your network protocol over the network. + +7.1. IPoXML DTD + + <!-- + DTD for IP over XML. + Refer to this DTD as: + + <!DOCTYPE ip PUBLIC "-//IETF//DTD BLOAT 1.0 IP//EN" "bloat.dtd"> + --> + <!-- + DTD data types: + + Digits [0..9]+ + + Precedence "NetworkControl | InternetworkControl | + CRITIC | FlashOverride | Flash | Immediate | + Priority | Routine" + + IP4Addr "dotted-decimal" notation of [RFC1123] + + Class [0..3] + + Sec "Unclassified | Confidential | EFTO | MMMM | PROG | + Restricted | Secret | Top Secret | Reserved" + + Compartments [0..65535] + + Handling [0..65535] + + TCC [0..16777216] + + --> + + + +Kennedy Informational [Page 7] + +RFC 3252 Binary Lexical Octet Ad-hoc Transport 1 April 2002 + + + <!ENTITY % Digits "CDATA"> + <!ENTITY % Precedence "CDATA"> + <!ENTITY % IP4Addr "CDATA"> + <!ENTITY % Class "CDATA"> + <!ENTITY % Sec "CDATA"> + <!ENTITY % Compartments "CDATA"> + <!ENTITY % Handling "CDATA"> + <!ENTITY % TCC "CDATA"> + + <!ELEMENT ip (header, payload)> + + <!ELEMENT header (version, tos, total.length, id, flags, offset, ttl, + protocol, checksum, source, destination, options, + padding)> + <!-- length of header in 32-bit words --> + <!ATTLIST header + length %Digits; #REQUIRED> + + <!ELEMENT version EMPTY> + <!-- ip version. SHOULD be "4" --> + <!ATTLIST version + value %Digits; #REQUIRED> + + <!ELEMENT tos EMPTY> + <!ATTLIST tos + precedence %Precedence; #REQUIRED + delay (normal | low) #REQUIRED + throughput (normal | high) #REQUIRED + relibility (normal | high) #REQUIRED + reserved CDATA #FIXED "0"> + + <!ELEMENT total.length EMPTY> + <!-- + total length of datagram (header and payload) in octets, MUST be + less than 65,535 (and SHOULD be less than 1024 for IPoXML on local + ethernets). + --> + <!ATTLIST total.length + value %Digits; #REQUIRED> + + <!ELEMENT id EMPTY> + <!-- 0 <= id <= 65,535 --> + <!ATTLIST id + value %Digits; #REQUIRED> + + <!ELEMENT flags EMPTY> + <!-- df = don't fragment, mf = more fragments --> + <!ATTLIST flags + + + +Kennedy Informational [Page 8] + +RFC 3252 Binary Lexical Octet Ad-hoc Transport 1 April 2002 + + + reserved CDATA #FIXED "0" + df (may|dont) #REQUIRED + mf (last|more) #REQUIRED> + + <!ELEMENT offset EMPTY> + <!-- 0 <= offset <= 8192 measured in 8 octet (64-bit) chunks --> + <!ATTLIST offset + value %Digits; #REQUIRED> + + <!ELEMENT ttl EMPTY> + <!-- 0 <= ttl <= 255 --> + <!ATTLIST ttl + value %Digits; #REQUIRED> + + <!ELEMENT protocol EMPTY> + <!-- 0 <= protocol <= 255 (per IANA) --> + <!ATTLIST protocol + value %Digits; #REQUIRED> + + <!ELEMENT checksum EMPTY> + <!-- 0 <= checksum <= 65535 (over header only) --> + <!ATTLIST checksum + value %Digits; #REQUIRED> + + <!ELEMENT source EMPTY> + <!ATTLIST source + address %IP4Addr; #REQUIRED> + + <!ELEMENT destination EMPTY> + <!ATTLIST destination + address %IP4Addr; #REQUIRED> + + <!ELEMENT options ( end | noop | security | loose | strict | record + | stream | timestamp )*> + + <!ELEMENT end EMPTY> + <!ATTLIST end + copied (0|1) #REQUIRED + class CDATA #FIXED "0" + number CDATA #FIXED "0"> + + <!ELEMENT noop EMPTY> + <!ATTLIST noop + copied (0|1) #REQUIRED + class CDATA #FIXED "0" + number CDATA #FIXED "1"> + + <!ELEMENT security EMPTY> + + + +Kennedy Informational [Page 9] + +RFC 3252 Binary Lexical Octet Ad-hoc Transport 1 April 2002 + + + <!ATTLIST security + copied CDATA #FIXED "1" + class CDATA #FIXED "0" + number CDATA #FIXED "2" + length CDATA #FIXED "11" + security %Sec; #REQUIRED + compartments %Compartments; #REQUIRED + handling %Handling; #REQUIRED + tcc %TCC; #REQUIRED> + <!ELEMENT loose (hop)+> + <!ATTLIST loose + copied CDATA #FIXED "1" + class CDATA #FIXED "0" + number CDATA #FIXED "3" + length %Digits; #REQUIRED + pointer %Digits; #REQUIRED> + + <!ELEMENT hop EMPTY> + <!ATTLIST hop + address %IP4Addr; #REQUIRED> + + <!ELEMENT strict (hop)+> + <!ATTLIST strict + copied CDATA #FIXED "1" + class CDATA #FIXED "0" + number CDATA #FIXED "9" + length %Digits; #REQUIRED + pointer %Digits; #REQUIRED> + + <!ELEMENT record (hop)+> + <!ATTLIST record + copied CDATA #FIXED "0" + class CDATA #FIXED "0" + number CDATA #FIXED "7" + length %Digits; #REQUIRED + pointer %Digits; #REQUIRED> + + <!ELEMENT stream EMPTY> + <!-- 0 <= id <= 65,535 --> + <!ATTLIST stream + copied CDATA #FIXED "1" + class CDATA #FIXED "0" + number CDATA #FIXED "8" + length CDATA #FIXED "4" + id %Digits; #REQUIRED> + + <!ELEMENT timestamp (tstamp)+> + <!-- 0 <= oflw <=15 --> + + + +Kennedy Informational [Page 10] + +RFC 3252 Binary Lexical Octet Ad-hoc Transport 1 April 2002 + + + <!ATTLIST timestamp + copied CDATA #FIXED "0" + class CDATA #FIXED "2" + number CDATA #FIXED "4" + length %Digits; #REQUIRED + pointer %Digits; #REQUIRED + oflw %Digits; #REQUIRED + flag (0 | 1 | 3) #REQUIRED> + + <!ELEMENT tstamp EMPTY> + <!ATTLIST tstamp + time %Digits; #REQUIRED + address %IP4Addr; #IMPLIED> + <!-- + padding to bring header to 32-bit boundary. + pad MUST be "0"* + --> + <!ELEMENT padding EMPTY> + <!ATTLIST padding + pad CDATA #REQUIRED> + + <!-- payload MUST be encoded as base-64 [RFC2045], as modified + by section 2.1 of this RFC --> + <!ELEMENT payload (CDATA)> + +7.2. TCPoXML DTD + + <!-- + DTD for TCP over XML. + Refer to this DTD as: + + <!DOCTYPE tcp PUBLIC "-//IETF//DTD BLOAT 1.0 TCP//EN" "bloat.dtd"> + --> + + <!-- the pseudoheader is only included for checksum calculations --> + <!ELEMENT tcp (tcp.pseudoheader?, tcp.header, payload)> + + <!ELEMENT tcp.header (src, dest, sequence, acknowledgement, offset, + reserved, control, window, checksum, urgent, + tcp.options, padding)> + + <!ELEMENT src EMPTY> + <!-- 0 <= port <= 65,535 --> + <!ATTLIST src + port %Digits; #REQUIRED> + + <!ELEMENT dest EMPTY> + <!-- 0 <= port <= 65,535 --> + + + +Kennedy Informational [Page 11] + +RFC 3252 Binary Lexical Octet Ad-hoc Transport 1 April 2002 + + + <!ATTLIST dest + port %Digits; #REQUIRED> + + <!ELEMENT sequence EMPTY> + <!-- 0 <= number <= 4294967295 --> + <!ATTLIST sequence + number %Digits; #REQUIRED> + + <!ELEMENT acknowledgement EMPTY> + <!-- 0 <= number <= 4294967295 --> + <!ATTLIST acknowledgement + number %Digits; #REQUIRED> + + <!ELEMENT offset EMPTY> + <!-- 0 <= number <= 255 --> + <!ATTLIST offset + number %Digits; #REQUIRED> + + <!ELEMENT reserved EMPTY> + <!ATTLIST reserved + value CDATA #FIXED "0"> + + <!ELEMENT control EMPTY> + <!ATTLIST control + urg (0|1) #IMPLIED + ack (0|1) #IMPLIED + psh (0|1) #IMPLIED + rst (0|1) #IMPLIED + syn (0|1) #IMPLIED + fin (0|1) #IMPLIED> + + <!ELEMENT window EMPTY> + <!-- 0 <= size <= 65,535 --> + <!ATTLIST window + size %Digits; #REQUIRED> + + <!-- + checksum as in ip, but with + the following pseudo-header added into the tcp element: + --> + <!ELEMENT tcp.pseudoheader (source, destination, protocol, + tcp.length)> + + <!-- + tcp header + data length in octets. does not include the size of + + the pseudoheader. + --> + + + +Kennedy Informational [Page 12] + +RFC 3252 Binary Lexical Octet Ad-hoc Transport 1 April 2002 + + + <!ELEMENT tcp.length EMPTY> + <!ATTLIST tcp.length + value %Digits; #REQUIRED> + + <!ELEMENT urgent EMPTY> + <!-- 0 <= pointer <= 65,535 --> + <!ATTLIST urgent + pointer %Digits; #REQUIRED> + + <!ELEMENT tcp.options (tcp.end | tcp.noop | tcp.mss)+> + + <!ELEMENT tcp.end EMPTY> + <!ATTLIST tcp.end + kind CDATA #FIXED "0"> + + <!ELEMENT tcp.noop EMPTY> + <!ATTLIST tcp.noop + kind CDATA #FIXED "1"> + + <!ELEMENT tcp.mss EMPTY> + <!ATTLIST tcp.mss + kind CDATA #FIXED "2" + length CDATA #FIXED "4" + size %Digits; #REQUIRED> + +7.3. UDPoXML DTD + + <!-- + DTD for UDP over XML. + Refer to this DTD as: + + <!DOCTYPE udp PUBLIC "-//IETF//DTD BLOAT 1.0 UDP//EN" "bloat.dtd"> + --> + + <!ELEMENT udp (udp.pseudoheader?, udp.header, payload)> + + <!ELEMENT udp.header (src, dest, udp.length, checksum)> + + <!ELEMENT udp.pseudoheader (source, destination, protocol, + udp.length)> + + <!-- + udp header + data length in octets. does not include the size of + the pseudoheader. + --> + <!ELEMENT udp.length EMPTY> + <!ATTLIST udp.length + value %Digits; #REQUIRED> + + + +Kennedy Informational [Page 13] + +RFC 3252 Binary Lexical Octet Ad-hoc Transport 1 April 2002 + + +8. Security Considerations + + XML, as a subset of SGML, has the same security considerations as + specified in SGML Media Types [RFC1874]. Security considerations + that apply to IP, TCP and UDP also likely apply to BLOAT as it does + not attempt to correct for issues not related to message format. + +9. References + + [JABBER] Miller, J., "Jabber", draft-miller-jabber-00.txt, + February 2002. (Work in Progress) + + [RFC768] Postel, J., "User Datagram Protocol", STD 6, RFC 768, + August 1980. + + [RFC791] Postel, J., "Internet Protocol", STD 5, RFC 791, + September 1981. + + [RFC793] Postel, J., "Transmission Control Protocol", STD 7, RFC + 793, September 1981. + + [RFC894] Hornig, C., "Standard for the Transmission of IP + Datagrams over Ethernet Networks.", RFC 894, April 1984. + + [RFC1042] Postel, J. and J. Reynolds, "Standard for the + Transmission of IP Datagrams Over IEEE 802 Networks", STD + 43, RFC 1042, February 1988. + + [RFC1123] Braden, R., "Requirements for Internet Hosts - + Application and Support", RFC 1123, October 1989. + + [RFC1874] Levinson, E., "SGML Media Types", RFC 1874, December + 1995. + + [RFC2003] Perkins, C., "IP Encapsulation within IP", RFC 2003, + October 1996. + + [RFC2045] Freed, N. and N. Borenstein, "Multipurpose Internet Mail + Extensions (MIME) Part One: Format of Internet Message + Bodies", RFC 2045, November 1996. + + [RFC2119] Bradner, S., "Key words for use in RFCs to Indicate + Requirement Levels", BCP 14, RFC 2119, March 1997. + + [RFC2279] Yergeau, F., "UTF-8, a transformation format of ISO + 10646", RFC 2279, January 1998. + + + + + +Kennedy Informational [Page 14] + +RFC 3252 Binary Lexical Octet Ad-hoc Transport 1 April 2002 + + + [RFC2460] Deering, S. and R. Hinden, "Internet Protocol, Version 6 + (IPv6) Specification", RFC 2460, December 1998. + + [RFC3080] Rose, M., "The Blocks Extensible Exchange Protocol Core", + RFC 3080, March 2001. + + [SOAP] Box, D., Ehnebuske, D., Kakivaya, G., Layman, A., + Mendelsohn, N., Nielsen, H. F., Thatte, S. Winer, D., + "Simple Object Access Protocol (SOAP) 1.1" World Wide Web + Consortium Note, May 2000 http://www.w3.org/TR/SOAP/ + + [XML] Bray, T., Paoli, J., Sperberg-McQueen, C. M., "Extensible + Markup Language (XML)" World Wide Web Consortium + Recommendation REC- xml-19980210. + http://www.w3.org/TR/1998/REC-xml-19980210 + +10. Author's Address + + Hugh Kennedy + Mimezine + 1060 West Addison + Chicago, IL 60613 + USA + + EMail: kennedyh@engin.umich.edu + + + + + + + + + + + + + + + + + + + + + + + + + + +Kennedy Informational [Page 15] + +RFC 3252 Binary Lexical Octet Ad-hoc Transport 1 April 2002 + + +11. Full Copyright Statement + + Copyright (C) The Internet Society (2002). All Rights Reserved. + + This document and translations of it may be copied and furnished to + others, and derivative works that comment on or otherwise explain it + or assist in its implementation may be prepared, copied, published + and distributed, in whole or in part, without restriction of any + kind, provided that the above copyright notice and this paragraph are + included on all such copies and derivative works. However, this + document itself may not be modified in any way, such as by removing + the copyright notice or references to the Internet Society or other + Internet organizations, except as needed for the purpose of + developing Internet standards in which case the procedures for + copyrights defined in the Internet Standards process must be + followed, or as required to translate it into languages other than + English. + + The limited permissions granted above are perpetual and will not be + revoked by the Internet Society or its successors or assigns. + + This document and the information contained herein is provided on an + "AS IS" basis and THE INTERNET SOCIETY AND THE INTERNET ENGINEERING + TASK FORCE DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING + BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE INFORMATION + HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED WARRANTIES OF + MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. + +Acknowledgement + + Funding for the RFC Editor function is currently provided by the + Internet Society. + + + + + + + + + + + + + + + + + + + +Kennedy Informational [Page 16] + diff --git a/tests/auto/network/access/qftp/tst_qftp.cpp b/tests/auto/network/access/qftp/tst_qftp.cpp new file mode 100644 index 0000000000..117ac92ed7 --- /dev/null +++ b/tests/auto/network/access/qftp/tst_qftp.cpp @@ -0,0 +1,2170 @@ +/**************************************************************************** +** +** 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 test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** 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. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + + +#include <QtTest/QtTest> + +#include <qcoreapplication.h> +#include <qfile.h> +#include <qbuffer.h> +#include "qftp.h" +#include <qmap.h> +#include <time.h> +#include <stdlib.h> +#include <QNetworkProxy> +#include <QNetworkConfiguration> +#include <qnetworkconfigmanager.h> +#include <QNetworkSession> +#include <QtNetwork/private/qnetworksession_p.h> + +#include "../../../network-settings.h" + +//TESTED_CLASS= +//TESTED_FILES= + +#ifdef Q_OS_SYMBIAN +// In Symbian OS test data is located in applications private dir +// Application private dir is default serach path for files, so SRCDIR can be set to empty +#define SRCDIR "" +#endif + +#ifndef QT_NO_BEARERMANAGEMENT +Q_DECLARE_METATYPE(QNetworkConfiguration) +#endif + +class tst_QFtp : public QObject +{ + Q_OBJECT + +public: + tst_QFtp(); + virtual ~tst_QFtp(); + + +public slots: + void initTestCase_data(); + void initTestCase(); + void cleanupTestCase(); + void init(); + void cleanup(); +private slots: + void connectToHost_data(); + void connectToHost(); + void connectToUnresponsiveHost(); + void login_data(); + void login(); + void close_data(); + void close(); + + void list_data(); + void list(); + void cd_data(); + void cd(); + void get_data(); + void get(); + void put_data(); + void put(); + void remove(); + void mkdir_data(); + void mkdir(); + void mkdir2(); + void rmdir(); + void rename_data(); + void rename(); + + void commandSequence_data(); + void commandSequence(); + + void abort_data(); + void abort(); + + void bytesAvailable_data(); + void bytesAvailable(); + + void activeMode(); + + void proxy_data(); + void proxy(); + + void binaryAscii(); + + void doneSignal(); + void queueMoreCommandsInDoneSlot(); + + void qtbug7359Crash(); + +protected slots: + void stateChanged( int ); + void listInfo( const QUrlInfo & ); + void readyRead(); + void dataTransferProgress(qint64, qint64); + + void commandStarted( int ); + void commandFinished( int, bool ); + void done( bool ); + void activeModeDone( bool ); + void mkdir2Slot(int id, bool error); + void cdUpSlot(bool); + +private: + QFtp *newFtp(); + void addCommand( QFtp::Command, int ); + bool fileExists( const QString &host, quint16 port, const QString &user, const QString &password, const QString &file, const QString &cdDir = QString::null ); + bool dirExists( const QString &host, quint16 port, const QString &user, const QString &password, const QString &cdDir, const QString &dirToCreate ); + + void renameInit( const QString &host, const QString &user, const QString &password, const QString &createFile ); + void renameCleanup( const QString &host, const QString &user, const QString &password, const QString &fileToDelete ); + + QFtp *ftp; +#ifndef QT_NO_BEARERMANAGEMENT + QSharedPointer<QNetworkSession> networkSessionExplicit; + QSharedPointer<QNetworkSession> networkSessionImplicit; +#endif + + QList<int> ids; // helper to make sure that all expected signals are emitted + int current_id; + + int connectToHost_state; + int close_state; + int login_state; + int cur_state; + struct CommandResult + { + int id; + int success; + }; + QMap< QFtp::Command, CommandResult > resultMap; + typedef QMap<QFtp::Command,CommandResult>::Iterator ResMapIt; + + int done_success; + int commandSequence_success; + + qlonglong bytesAvailable_finishedGet; + qlonglong bytesAvailable_finished; + qlonglong bytesAvailable_done; + + QList<QUrlInfo> listInfo_i; + QByteArray newData_ba; + qlonglong bytesTotal; + qlonglong bytesDone; + + bool inFileDirExistsFunction; + + QString uniqueExtension; +}; + +//#define DUMP_SIGNALS + +const int bytesTotal_init = -10; +const int bytesDone_init = -10; + +tst_QFtp::tst_QFtp() : + ftp(0) +{ +} + +tst_QFtp::~tst_QFtp() +{ +} + +void tst_QFtp::initTestCase_data() +{ + QTest::addColumn<bool>("setProxy"); + QTest::addColumn<int>("proxyType"); + QTest::addColumn<bool>("setSession"); + + QTest::newRow("WithoutProxy") << false << 0 << false; + QTest::newRow("WithSocks5Proxy") << true << int(QNetworkProxy::Socks5Proxy) << false; + //### doesn't work well yet. + //QTest::newRow("WithHttpProxy") << true << int(QNetworkProxy::HttpProxy); + +#ifndef QT_NO_BEARERMANAGEMENT + QTest::newRow("WithoutProxyWithSession") << false << 0 << true; + QTest::newRow("WithSocks5ProxyAndSession") << true << int(QNetworkProxy::Socks5Proxy) << true; +#endif +} + +void tst_QFtp::initTestCase() +{ +#ifndef QT_NO_BEARERMANAGEMENT + QNetworkConfigurationManager manager; + networkSessionImplicit = QSharedPointer<QNetworkSession>(new QNetworkSession(manager.defaultConfiguration())); + networkSessionImplicit->open(); + QVERIFY(networkSessionImplicit->waitForOpened(60000)); //there may be user prompt on 1st connect +#endif +} + +void tst_QFtp::cleanupTestCase() +{ +#ifndef QT_NO_BEARERMANAGEMENT + networkSessionExplicit.clear(); + networkSessionImplicit.clear(); +#endif +} + +void tst_QFtp::init() +{ + QFETCH_GLOBAL(bool, setProxy); + QFETCH_GLOBAL(int, proxyType); + QFETCH_GLOBAL(bool, setSession); + if (setProxy) { + if (proxyType == QNetworkProxy::Socks5Proxy) { + QNetworkProxy::setApplicationProxy(QNetworkProxy(QNetworkProxy::Socks5Proxy, QtNetworkSettings::serverName(), 1080)); + } else if (proxyType == QNetworkProxy::HttpProxy) { + QNetworkProxy::setApplicationProxy(QNetworkProxy(QNetworkProxy::HttpProxy, QtNetworkSettings::serverName(), 3128)); + } + } +#ifndef QT_NO_BEARERMANAGEMENT + if (setSession) { + networkSessionExplicit = networkSessionImplicit; + if (!networkSessionExplicit->isOpen()) { + networkSessionExplicit->open(); + QVERIFY(networkSessionExplicit->waitForOpened(30000)); + } + } else { + networkSessionExplicit.clear(); + } +#endif + + delete ftp; + ftp = 0; + + ids.clear(); + current_id = 0; + + resultMap.clear(); + connectToHost_state = -1; + close_state = -1; + login_state = -1; + cur_state = QFtp::Unconnected; + + listInfo_i.clear(); + newData_ba = QByteArray(); + bytesTotal = bytesTotal_init; + bytesDone = bytesDone_init; + + done_success = -1; + commandSequence_success = -1; + + bytesAvailable_finishedGet = 1234567890; + bytesAvailable_finished = 1234567890; + bytesAvailable_done = 1234567890; + + inFileDirExistsFunction = FALSE; + +#if !defined(Q_OS_WINCE) + srand(time(0)); + uniqueExtension = QString("%1%2%3").arg((qulonglong)this).arg(rand()).arg((qulonglong)time(0)); +#else + srand(0); + uniqueExtension = QString("%1%2%3").arg((qulonglong)this).arg(rand()).arg((qulonglong)(0)); +#endif +} + +void tst_QFtp::cleanup() +{ + if (ftp) { + delete ftp; + ftp = 0; + } + QFETCH_GLOBAL(bool, setProxy); + if (setProxy) { + QNetworkProxy::setApplicationProxy(QNetworkProxy::DefaultProxy); + } + + delete ftp; + ftp = 0; +#ifndef QT_NO_BEARERMANAGEMENT + networkSessionExplicit.clear(); +#endif +} + +void tst_QFtp::connectToHost_data() +{ + QTest::addColumn<QString>("host"); + QTest::addColumn<uint>("port"); + QTest::addColumn<int>("state"); + + QTest::newRow( "ok01" ) << QtNetworkSettings::serverName() << (uint)21 << (int)QFtp::Connected; + QTest::newRow( "error01" ) << QtNetworkSettings::serverName() << (uint)2222 << (int)QFtp::Unconnected; + QTest::newRow( "error02" ) << QString("foo.bar") << (uint)21 << (int)QFtp::Unconnected; +} + +void tst_QFtp::connectToHost() +{ + QFETCH( QString, host ); + QFETCH( uint, port ); + + ftp = newFtp(); + addCommand( QFtp::ConnectToHost, ftp->connectToHost( host, port ) ); + + QTestEventLoop::instance().enterLoop( 61 ); + delete ftp; + ftp = 0; + if ( QTestEventLoop::instance().timeout() ) + QFAIL( "Network operation timed out" ); + + QTEST( connectToHost_state, "state" ); + + ResMapIt it = resultMap.find( QFtp::ConnectToHost ); + QVERIFY( it != resultMap.end() ); + QFETCH( int, state ); + if ( state == QFtp::Connected ) { + QVERIFY( it.value().success == 1 ); + } else { + QVERIFY( it.value().success == 0 ); + } +} + +void tst_QFtp::connectToUnresponsiveHost() +{ + QFETCH_GLOBAL(bool, setProxy); + if (setProxy) + QSKIP( "This test takes too long if we test with proxies too", SkipSingle ); + + QString host = "192.0.2.42"; // IP out of TEST-NET, should be unreachable + uint port = 21; + + ftp = newFtp(); + addCommand( QFtp::ConnectToHost, ftp->connectToHost( host, port ) ); + + qDebug( "About to connect to host that won't reply (this test takes 60 seconds)" ); + QTestEventLoop::instance().enterLoop( 61 ); +#ifdef Q_OS_WIN + /* On Windows, we do not get a timeout, because Winsock is behaving in a strange way: + We issue two "WSAConnect()" calls, after the first, as a result we get WSAEWOULDBLOCK, + after the second, we get WSAEISCONN, which means that the socket is connected, which cannot be. + However, after some seconds we get a socket error saying that the remote host closed the connection, + which can neither be. For this test, that would actually enable us to finish before timout, but handling that case + (in void QFtpPI::error(QAbstractSocket::SocketError e)) breaks + a lot of other stuff in QFtp, so we just expect this test to fail on Windows. + */ + QEXPECT_FAIL("", "timeout not working due to strange Windows socket behaviour (see source file of this test for explanation)", Abort); +#else + QEXPECT_FAIL("", "QTBUG-20687", Abort); +#endif + QVERIFY2(! QTestEventLoop::instance().timeout(), "Network timeout longer than expected (should have been 60 seconds)"); + + QVERIFY( ftp->state() == QFtp::Unconnected); + ResMapIt it = resultMap.find( QFtp::ConnectToHost ); + QVERIFY( it != resultMap.end() ); + QVERIFY( it.value().success == 0 ); + + delete ftp; + ftp = 0; +} + +void tst_QFtp::login_data() +{ + QTest::addColumn<QString>("host"); + QTest::addColumn<uint>("port"); + QTest::addColumn<QString>("user"); + QTest::addColumn<QString>("password"); + QTest::addColumn<int>("success"); + + QTest::newRow( "ok01" ) << QtNetworkSettings::serverName() << (uint)21 << QString() << QString() << 1; + QTest::newRow( "ok02" ) << QtNetworkSettings::serverName() << (uint)21 << QString("ftp") << QString() << 1; + QTest::newRow( "ok03" ) << QtNetworkSettings::serverName() << (uint)21 << QString("ftp") << QString("foo") << 1; + QTest::newRow( "ok04" ) << QtNetworkSettings::serverName() << (uint)21 << QString("ftptest") << QString("password") << 1; + + QTest::newRow( "error01" ) << QtNetworkSettings::serverName() << (uint)21 << QString("foo") << QString() << 0; + QTest::newRow( "error02" ) << QtNetworkSettings::serverName() << (uint)21 << QString("foo") << QString("bar") << 0; +} + +void tst_QFtp::login() +{ + QFETCH( QString, host ); + QFETCH( uint, port ); + QFETCH( QString, user ); + QFETCH( QString, password ); + + ftp = newFtp(); + addCommand( QFtp::ConnectToHost, ftp->connectToHost( host, port ) ); + addCommand( QFtp::Login, ftp->login( user, password ) ); + + QTestEventLoop::instance().enterLoop( 30 ); + delete ftp; + ftp = 0; + if ( QTestEventLoop::instance().timeout() ) + QFAIL( "Network operation timed out" ); + + ResMapIt it = resultMap.find( QFtp::Login ); + QVERIFY( it != resultMap.end() ); + QTEST( it.value().success, "success" ); + + if ( it.value().success ) { + QVERIFY( login_state == QFtp::LoggedIn ); + } else { + QVERIFY( login_state != QFtp::LoggedIn ); + } +} + +void tst_QFtp::close_data() +{ + QTest::addColumn<QString>("host"); + QTest::addColumn<uint>("port"); + QTest::addColumn<QString>("user"); + QTest::addColumn<QString>("password"); + QTest::addColumn<bool>("login"); + + QTest::newRow( "login01" ) << QtNetworkSettings::serverName() << (uint)21 << QString() << QString() << (bool)TRUE; + QTest::newRow( "login02" ) << QtNetworkSettings::serverName() << (uint)21 << QString("ftp") << QString() << (bool)TRUE; + QTest::newRow( "login03" ) << QtNetworkSettings::serverName() << (uint)21 << QString("ftp") << QString("foo") << (bool)TRUE; + QTest::newRow( "login04" ) << QtNetworkSettings::serverName() << (uint)21 << QString("ftptest") << QString("password") << (bool)TRUE; + + QTest::newRow( "no-login01" ) << QtNetworkSettings::serverName() << (uint)21 << QString("") << QString("") << (bool)FALSE; +} + +void tst_QFtp::close() +{ + QFETCH( QString, host ); + QFETCH( uint, port ); + QFETCH( QString, user ); + QFETCH( QString, password ); + QFETCH( bool, login ); + + ftp = newFtp(); + addCommand( QFtp::ConnectToHost, ftp->connectToHost( host, port ) ); + if ( login ) + addCommand( QFtp::Login, ftp->login( user, password ) ); + addCommand( QFtp::Close, ftp->close() ); + + QTestEventLoop::instance().enterLoop( 30 ); + delete ftp; + ftp = 0; + if ( QTestEventLoop::instance().timeout() ) + QFAIL( "Network operation timed out" ); + + QCOMPARE( close_state, (int)QFtp::Unconnected ); + + ResMapIt it = resultMap.find( QFtp::Close ); + QVERIFY( it != resultMap.end() ); + QVERIFY( it.value().success == 1 ); +} + +void tst_QFtp::list_data() +{ + QTest::addColumn<QString>("host"); + QTest::addColumn<uint>("port"); + QTest::addColumn<QString>("user"); + QTest::addColumn<QString>("password"); + QTest::addColumn<QString>("dir"); + QTest::addColumn<int>("success"); + QTest::addColumn<QStringList>("entryNames"); // ### we should rather use a QList<QUrlInfo> here + + QStringList flukeRoot; + flukeRoot << "pub"; + flukeRoot << "qtest"; + QStringList flukeQtest; + flukeQtest << "bigfile"; + flukeQtest << "nonASCII"; + flukeQtest << "rfc3252"; + flukeQtest << "rfc3252.txt"; + flukeQtest << "upload"; + + QTest::newRow( "workDir01" ) << QtNetworkSettings::serverName() << (uint)21 << QString() << QString() << QString() << 1 << flukeRoot; + QTest::newRow( "workDir02" ) << QtNetworkSettings::serverName() << (uint)21 << QString("ftptest") << QString("password") << QString() << 1 << flukeRoot; + + QTest::newRow( "relPath01" ) << QtNetworkSettings::serverName() << (uint)21 << QString() << QString() << QString("qtest") << 1 << flukeQtest; + QTest::newRow( "relPath02" ) << QtNetworkSettings::serverName() << (uint)21 << QString("ftptest") << QString("password") << QString("qtest") << 1 << flukeQtest; + + QTest::newRow( "absPath01" ) << QtNetworkSettings::serverName() << (uint)21 << QString() << QString() << QString("/qtest") << 1 << flukeQtest; + QTest::newRow( "absPath02" ) << QtNetworkSettings::serverName() << (uint)21 << QString("ftptest") << QString("password") << QString("/var/ftp/qtest") << 1 << flukeQtest; + + QTest::newRow( "nonExist01" ) << QtNetworkSettings::serverName() << (uint)21 << QString() << QString() << QString("foo") << 1 << QStringList(); + QTest::newRow( "nonExist02" ) << QtNetworkSettings::serverName() << (uint)21 << QString() << QString() << QString("/foo") << 1 << QStringList(); + // ### The microsoft server does not seem to work properly at the moment -- + // I am also not able to open a data connection with other, non-Qt FTP + // clients to it. + // QTest::newRow( "nonExist03" ) << "ftp.microsoft.com" << (uint)21 << QString() << QString() << QString("/foo") << 0 << QStringList(); + + QStringList susePub; + susePub << "README.mirror-policy" << "axp" << "i386" << "ia64" << "install" << "noarch" << "pubring.gpg-build.suse.de" << "update" << "x86_64"; + QTest::newRow( "epsvNotSupported" ) << QString("ftp.funet.fi") << (uint)21 << QString::fromLatin1("ftp") << QString::fromLatin1("root@") << QString("/pub/Linux/suse/suse") << 1 << susePub; +} + +void tst_QFtp::list() +{ + QFETCH( QString, host ); + QFETCH( uint, port ); + QFETCH( QString, user ); + QFETCH( QString, password ); + QFETCH( QString, dir ); + + ftp = newFtp(); + addCommand( QFtp::ConnectToHost, ftp->connectToHost( host, port ) ); + addCommand( QFtp::Login, ftp->login( user, password ) ); + addCommand( QFtp::List, ftp->list( dir ) ); + addCommand( QFtp::Close, ftp->close() ); + + QTestEventLoop::instance().enterLoop( 30 ); + delete ftp; + ftp = 0; + if ( QTestEventLoop::instance().timeout() ) + QFAIL( "Network operation timed out" ); + + ResMapIt it = resultMap.find( QFtp::List ); + QVERIFY( it != resultMap.end() ); + QTEST( it.value().success, "success" ); + QFETCH( QStringList, entryNames ); + QCOMPARE( listInfo_i.count(), entryNames.count() ); + for ( uint i=0; i < (uint) entryNames.count(); i++ ) { + QCOMPARE( listInfo_i[i].name(), entryNames[i] ); + } +} + +void tst_QFtp::cd_data() +{ + QTest::addColumn<QString>("host"); + QTest::addColumn<uint>("port"); + QTest::addColumn<QString>("user"); + QTest::addColumn<QString>("password"); + QTest::addColumn<QString>("dir"); + QTest::addColumn<int>("success"); + QTest::addColumn<QStringList>("entryNames"); // ### we should rather use a QList<QUrlInfo> here + + QStringList flukeRoot; + flukeRoot << "qtest"; + QStringList flukeQtest; + flukeQtest << "bigfile"; + flukeQtest << "nonASCII"; + flukeQtest << "rfc3252"; + flukeQtest << "rfc3252.txt"; + flukeQtest << "upload"; + + QTest::newRow( "relPath01" ) << QtNetworkSettings::serverName() << (uint)21 << QString() << QString() << QString("qtest") << 1 << flukeQtest; + QTest::newRow( "relPath02" ) << QtNetworkSettings::serverName() << (uint)21 << QString("ftptest") << QString("password") << QString("qtest") << 1 << flukeQtest; + + QTest::newRow( "absPath01" ) << QtNetworkSettings::serverName() << (uint)21 << QString() << QString() << QString("/qtest") << 1 << flukeQtest; + QTest::newRow( "absPath02" ) << QtNetworkSettings::serverName() << (uint)21 << QString("ftptest") << QString("password") << QString("/var/ftp/qtest") << 1 << flukeQtest; + + QTest::newRow( "nonExist01" ) << QtNetworkSettings::serverName() << (uint)21 << QString() << QString() << QString("foo") << 0 << QStringList(); + QTest::newRow( "nonExist03" ) << QtNetworkSettings::serverName() << (uint)21 << QString() << QString() << QString("/foo") << 0 << QStringList(); +} + +void tst_QFtp::cd() +{ + QFETCH( QString, host ); + QFETCH( uint, port ); + QFETCH( QString, user ); + QFETCH( QString, password ); + QFETCH( QString, dir ); + + ftp = newFtp(); + addCommand( QFtp::ConnectToHost, ftp->connectToHost( host, port ) ); + addCommand( QFtp::Login, ftp->login( user, password ) ); + addCommand( QFtp::Cd, ftp->cd( dir ) ); + addCommand( QFtp::List, ftp->list() ); + addCommand( QFtp::Close, ftp->close() ); + + QTestEventLoop::instance().enterLoop( 30 ); + + delete ftp; + ftp = 0; + if ( QTestEventLoop::instance().timeout() ) { + QFAIL( "Network operation timed out" ); + } + + ResMapIt it = resultMap.find( QFtp::Cd ); + QVERIFY( it != resultMap.end() ); + QTEST( it.value().success, "success" ); + QFETCH( QStringList, entryNames ); + QCOMPARE( listInfo_i.count(), entryNames.count() ); + for ( uint i=0; i < (uint) entryNames.count(); i++ ) { + QCOMPARE( listInfo_i[i].name(), entryNames[i] ); + } +} + +void tst_QFtp::get_data() +{ + QTest::addColumn<QString>("host"); + QTest::addColumn<uint>("port"); + QTest::addColumn<QString>("user"); + QTest::addColumn<QString>("password"); + QTest::addColumn<QString>("file"); + QTest::addColumn<int>("success"); + QTest::addColumn<QByteArray>("res"); + QTest::addColumn<bool>("useIODevice"); + + // ### move this into external testdata + QFile file( SRCDIR "rfc3252.txt" ); + QVERIFY( file.open( QIODevice::ReadOnly ) ); + QByteArray rfc3252 = file.readAll(); + + // test the two get() overloads in one routine + for ( int i=0; i<2; i++ ) { + QTest::newRow( QString("relPath01_%1").arg(i).toLatin1().constData() ) << QtNetworkSettings::serverName() << (uint)21 << QString() << QString() + << "qtest/rfc3252" << 1 << rfc3252 << (bool)(i==1); + QTest::newRow( QString("relPath02_%1").arg(i).toLatin1().constData() ) << QtNetworkSettings::serverName() << (uint)21 << QString("ftptest") << QString("password") + << "qtest/rfc3252" << 1 << rfc3252 << (bool)(i==1); + + QTest::newRow( QString("absPath01_%1").arg(i).toLatin1().constData() ) << QtNetworkSettings::serverName() << (uint)21 << QString() << QString() + << "/qtest/rfc3252" << 1 << rfc3252 << (bool)(i==1); + QTest::newRow( QString("absPath02_%1").arg(i).toLatin1().constData() ) << QtNetworkSettings::serverName() << (uint)21 << QString("ftptest") << QString("password") + << "/var/ftp/qtest/rfc3252" << 1 << rfc3252 << (bool)(i==1); + + QTest::newRow( QString("nonExist01_%1").arg(i).toLatin1().constData() ) << QtNetworkSettings::serverName() << (uint)21 << QString() << QString() + << QString("foo") << 0 << QByteArray() << (bool)(i==1); + QTest::newRow( QString("nonExist02_%1").arg(i).toLatin1().constData() ) << QtNetworkSettings::serverName() << (uint)21 << QString() << QString() + << QString("/foo") << 0 << QByteArray() << (bool)(i==1); + } +} + +void tst_QFtp::get() +{ + // for the overload that takes a QIODevice + QByteArray buf_ba; + QBuffer buf( &buf_ba ); + + QFETCH( QString, host ); + QFETCH( uint, port ); + QFETCH( QString, user ); + QFETCH( QString, password ); + QFETCH( QString, file ); + QFETCH( bool, useIODevice ); + + ftp = newFtp(); + addCommand( QFtp::ConnectToHost, ftp->connectToHost( host, port ) ); + addCommand( QFtp::Login, ftp->login( user, password ) ); + if ( useIODevice ) { + buf.open( QIODevice::WriteOnly ); + addCommand( QFtp::Get, ftp->get( file, &buf ) ); + } else { + addCommand( QFtp::Get, ftp->get( file ) ); + } + addCommand( QFtp::Close, ftp->close() ); + + QTestEventLoop::instance().enterLoop( 50 ); + delete ftp; + ftp = 0; + if ( QTestEventLoop::instance().timeout() ) + QFAIL( "Network operation timed out" ); + + ResMapIt it = resultMap.find( QFtp::Get ); + QVERIFY( it != resultMap.end() ); + QTEST( it.value().success, "success" ); + if ( useIODevice ) { + QTEST( buf_ba, "res" ); + } else { + QTEST( newData_ba, "res" ); + } + QVERIFY( bytesTotal != bytesTotal_init ); + if ( bytesTotal != -1 ) { + QVERIFY( bytesDone == bytesTotal ); + } + if ( useIODevice ) { + if ( bytesDone != bytesDone_init ) { + QVERIFY( (int)buf_ba.size() == bytesDone ); + } + } else { + if ( bytesDone != bytesDone_init ) { + QVERIFY( (int)newData_ba.size() == bytesDone ); + } + } +} + +void tst_QFtp::put_data() +{ + QTest::addColumn<QString>("host"); + QTest::addColumn<uint>("port"); + QTest::addColumn<QString>("user"); + QTest::addColumn<QString>("password"); + QTest::addColumn<QString>("file"); + QTest::addColumn<QByteArray>("fileData"); + QTest::addColumn<bool>("useIODevice"); + QTest::addColumn<int>("success"); + + // ### move this into external testdata + QFile file( SRCDIR "rfc3252.txt" ); + QVERIFY( file.open( QIODevice::ReadOnly ) ); + QByteArray rfc3252 = file.readAll(); + + QByteArray bigData( 10*1024*1024, 0 ); + bigData.fill( 'A' ); + + // test the two put() overloads in one routine + for ( int i=0; i<2; i++ ) { + QTest::newRow( QString("relPath01_%1").arg(i).toLatin1().constData() ) << QtNetworkSettings::serverName() << (uint)21 << QString() << QString() + << QString("qtest/upload/rel01_%1") << rfc3252 + << (bool)(i==1) << 1; + /* + QTest::newRow( QString("relPath02_%1").arg(i).toLatin1().constData() ) << QtNetworkSettings::serverName() << (uint)21 << QString("ftptest") << QString("password") + << QString("qtest/upload/rel02_%1") << rfc3252 + << (bool)(i==1) << 1; + QTest::newRow( QString("relPath03_%1").arg(i).toLatin1().constData() ) << QtNetworkSettings::serverName() << (uint)21 << QString("ftptest") << QString("password") + << QString("qtest/upload/rel03_%1") << QByteArray() + << (bool)(i==1) << 1; + QTest::newRow( QString("relPath04_%1").arg(i).toLatin1().constData() ) << QtNetworkSettings::serverName() << (uint)21 << QString("ftptest") << QString("password") + << QString("qtest/upload/rel04_%1") << bigData + << (bool)(i==1) << 1; + + QTest::newRow( QString("absPath01_%1").arg(i).toLatin1().constData() ) << QtNetworkSettings::serverName() << (uint)21 << QString() << QString() + << QString("/qtest/upload/abs01_%1") << rfc3252 + << (bool)(i==1) << 1; + QTest::newRow( QString("absPath02_%1").arg(i).toLatin1().constData() ) << QtNetworkSettings::serverName() << (uint)21 << QString("ftptest") << QString("password") + << QString("/srv/ftp/qtest/upload/abs02_%1") << rfc3252 + << (bool)(i==1) << 1; + + QTest::newRow( QString("nonExist01_%1").arg(i).toLatin1().constData() ) << QtNetworkSettings::serverName() << (uint)21 << QString() << QString() + << QString("foo") << QByteArray() + << (bool)(i==1) << 0; + QTest::newRow( QString("nonExist02_%1").arg(i).toLatin1().constData() ) << QtNetworkSettings::serverName() << (uint)21 << QString() << QString() + << QString("/foo") << QByteArray() + << (bool)(i==1) << 0; +*/ + } +} + +void tst_QFtp::put() +{ + QFETCH( QString, host ); + QFETCH( uint, port ); + QFETCH( QString, user ); + QFETCH( QString, password ); + QFETCH( QString, file ); + QFETCH( QByteArray, fileData ); + QFETCH( bool, useIODevice ); + +#ifdef Q_OS_WIN + QFETCH_GLOBAL(bool, setProxy); + if (setProxy) { + QFETCH_GLOBAL(int, proxyType); + if (proxyType == QNetworkProxy::Socks5Proxy) { + QSKIP("With socks5 the put() test takes too long time on Windows.", SkipAll); + } + } +#endif + + const int timestep = 50; + + if(file.contains('%')) + file = file.arg(uniqueExtension); + + // for the overload that takes a QIODevice + QBuffer buf_fileData( &fileData ); + buf_fileData.open( QIODevice::ReadOnly ); + + ResMapIt it; + ////////////////////////////////////////////////////////////////// + // upload the file + init(); + ftp = newFtp(); + addCommand( QFtp::ConnectToHost, ftp->connectToHost( host, port ) ); + addCommand( QFtp::Login, ftp->login( user, password ) ); + if ( useIODevice ) + addCommand( QFtp::Put, ftp->put( &buf_fileData, file ) ); + else + addCommand( QFtp::Put, ftp->put( fileData, file ) ); + addCommand( QFtp::Close, ftp->close() ); + + for(int time = 0; time <= fileData.length() / 20000; time += timestep) { + QTestEventLoop::instance().enterLoop( timestep ); + if(ftp->currentCommand() == QFtp::None) + break; + } + delete ftp; + ftp = 0; + if ( QTestEventLoop::instance().timeout() ) + QFAIL( "Network operation timed out" ); + + it = resultMap.find( QFtp::Put ); + QVERIFY( it != resultMap.end() ); + QTEST( it.value().success, "success" ); + if ( !it.value().success ) { + QVERIFY( !fileExists( host, port, user, password, file ) ); + return; // the following tests are only meaningful if the file could be put + } + QVERIFY( bytesTotal == (int)fileData.size() ); + QVERIFY( bytesDone == bytesTotal ); + + QVERIFY( fileExists( host, port, user, password, file ) ); + + ////////////////////////////////////////////////////////////////// + // fetch file to make sure that it is equal to the uploaded file + init(); + ftp = newFtp(); + QBuffer buf; + buf.open( QIODevice::WriteOnly ); + addCommand( QFtp::ConnectToHost, ftp->connectToHost( host, port ) ); + addCommand( QFtp::Login, ftp->login( user, password ) ); + addCommand( QFtp::Get, ftp->get( file, &buf ) ); + addCommand( QFtp::Close, ftp->close() ); + + for(int time = 0; time <= fileData.length() / 20000; time += timestep) { + QTestEventLoop::instance().enterLoop( timestep ); + if(ftp->currentCommand() == QFtp::None) + break; + } + delete ftp; + ftp = 0; + if ( QTestEventLoop::instance().timeout() ) + QFAIL( "Network operation timed out" ); + + QVERIFY( done_success == 1 ); + QTEST( buf.buffer(), "fileData" ); + + ////////////////////////////////////////////////////////////////// + // cleanup (i.e. remove the file) -- this also tests the remove command + init(); + ftp = newFtp(); + addCommand( QFtp::ConnectToHost, ftp->connectToHost( host, port ) ); + addCommand( QFtp::Login, ftp->login( user, password ) ); + addCommand( QFtp::Remove, ftp->remove( file ) ); + addCommand( QFtp::Close, ftp->close() ); + + QTestEventLoop::instance().enterLoop( timestep ); + delete ftp; + ftp = 0; + if ( QTestEventLoop::instance().timeout() ) + QFAIL( "Network operation timed out" ); + + it = resultMap.find( QFtp::Remove ); + QVERIFY( it != resultMap.end() ); + QCOMPARE( it.value().success, 1 ); + + QVERIFY( !fileExists( host, port, user, password, file ) ); +} + +void tst_QFtp::remove() +{ + DEPENDS_ON( "put" ); +} + +void tst_QFtp::mkdir_data() +{ + QTest::addColumn<QString>("host"); + QTest::addColumn<uint>("port"); + QTest::addColumn<QString>("user"); + QTest::addColumn<QString>("password"); + QTest::addColumn<QString>("cdDir"); + QTest::addColumn<QString>("dirToCreate"); + QTest::addColumn<int>("success"); + + QTest::newRow( "relPath01" ) << QtNetworkSettings::serverName() << (uint)21 << QString() << QString() + << "qtest/upload" << QString("rel01_%1") << 1; + QTest::newRow( "relPath02" ) << QtNetworkSettings::serverName() << (uint)21 << QString("ftptest") << QString("password") + << "qtest/upload" << QString("rel02_%1") << 1; + QTest::newRow( "relPath03" ) << QtNetworkSettings::serverName() << (uint)21 << QString("ftptest") << QString("password") + << "qtest/upload" << QString("rel03_%1") << 1; + + QTest::newRow( "absPath01" ) << QtNetworkSettings::serverName() << (uint)21 << QString() << QString() + << "." << QString("/qtest/upload/abs01_%1") << 1; + QTest::newRow( "absPath02" ) << QtNetworkSettings::serverName() << (uint)21 << QString("ftptest") << QString("password") + << "." << QString("/var/ftp/qtest/upload/abs02_%1") << 1; + + // QTest::newRow( "nonExist01" ) << QtNetworkSettings::serverName() << (uint)21 << QString() << QString() << QString("foo") << 0; + QTest::newRow( "nonExist01" ) << QtNetworkSettings::serverName() << (uint)21 << QString() << QString() + << "." << QString("foo") << 0; + QTest::newRow( "nonExist02" ) << QtNetworkSettings::serverName() << (uint)21 << QString() << QString() + << "." << QString("/foo") << 0; +} + +void tst_QFtp::mkdir() +{ + QFETCH( QString, host ); + QFETCH( uint, port ); + QFETCH( QString, user ); + QFETCH( QString, password ); + QFETCH( QString, cdDir ); + QFETCH( QString, dirToCreate ); + + if(dirToCreate.contains('%')) + dirToCreate = dirToCreate.arg(uniqueExtension); + + ////////////////////////////////////////////////////////////////// + // create the directory + init(); + ftp = newFtp(); + addCommand( QFtp::ConnectToHost, ftp->connectToHost( host, port ) ); + addCommand( QFtp::Login, ftp->login( user, password ) ); + addCommand( QFtp::Cd, ftp->cd( cdDir ) ); + addCommand( QFtp::Mkdir, ftp->mkdir( dirToCreate ) ); + addCommand( QFtp::Close, ftp->close() ); + + QTestEventLoop::instance().enterLoop( 30 ); + delete ftp; + ftp = 0; + if ( QTestEventLoop::instance().timeout() ) + QFAIL( "Network operation timed out" ); + + ResMapIt it = resultMap.find( QFtp::Mkdir ); + QVERIFY( it != resultMap.end() ); + QTEST( it.value().success, "success" ); + if ( !it.value().success ) { + QVERIFY( !dirExists( host, port, user, password, cdDir, dirToCreate ) ); + return; // the following tests are only meaningful if the dir could be created + } + QVERIFY( dirExists( host, port, user, password, cdDir, dirToCreate ) ); + + ////////////////////////////////////////////////////////////////// + // create the directory again (should always fail!) + init(); + ftp = newFtp(); + addCommand( QFtp::ConnectToHost, ftp->connectToHost( host, port ) ); + addCommand( QFtp::Login, ftp->login( user, password ) ); + addCommand( QFtp::Cd, ftp->cd( cdDir ) ); + addCommand( QFtp::Mkdir, ftp->mkdir( dirToCreate ) ); + addCommand( QFtp::Close, ftp->close() ); + + QTestEventLoop::instance().enterLoop( 30 ); + delete ftp; + ftp = 0; + if ( QTestEventLoop::instance().timeout() ) + QFAIL( "Network operation timed out" ); + + it = resultMap.find( QFtp::Mkdir ); + QVERIFY( it != resultMap.end() ); + QCOMPARE( it.value().success, 0 ); + + ////////////////////////////////////////////////////////////////// + // remove the directory + init(); + ftp = newFtp(); + addCommand( QFtp::ConnectToHost, ftp->connectToHost( host, port ) ); + addCommand( QFtp::Login, ftp->login( user, password ) ); + addCommand( QFtp::Cd, ftp->cd( cdDir ) ); + addCommand( QFtp::Rmdir, ftp->rmdir( dirToCreate ) ); + addCommand( QFtp::Close, ftp->close() ); + + QTestEventLoop::instance().enterLoop( 30 ); + delete ftp; + ftp = 0; + if ( QTestEventLoop::instance().timeout() ) + QFAIL( "Network operation timed out" ); + + it = resultMap.find( QFtp::Rmdir ); + QVERIFY( it != resultMap.end() ); + QCOMPARE( it.value().success, 1 ); + + QVERIFY( !dirExists( host, port, user, password, cdDir, dirToCreate ) ); +} + +void tst_QFtp::mkdir2() +{ + ftp = new QFtp; + ftp->connectToHost(QtNetworkSettings::serverName()); + ftp->login(); + current_id = ftp->cd("kake/test"); + + QEventLoop loop; + connect(ftp, SIGNAL(done(bool)), &loop, SLOT(quit())); + connect(ftp, SIGNAL(commandFinished(int, bool)), this, SLOT(mkdir2Slot(int, bool))); + QTimer::singleShot(5000, &loop, SLOT(quit())); + + QSignalSpy commandStartedSpy(ftp, SIGNAL(commandStarted(int))); + QSignalSpy commandFinishedSpy(ftp, SIGNAL(commandFinished(int, bool))); + + loop.exec(); + + QCOMPARE(commandStartedSpy.count(), 4); // connect, login, cd, mkdir + QCOMPARE(commandFinishedSpy.count(), 4); + + for (int i = 0; i < 4; ++i) + QCOMPARE(commandFinishedSpy.at(i).at(0), commandStartedSpy.at(i).at(0)); + + QVERIFY(!commandFinishedSpy.at(0).at(1).toBool()); + QVERIFY(!commandFinishedSpy.at(1).at(1).toBool()); + QVERIFY(commandFinishedSpy.at(2).at(1).toBool()); + QVERIFY(commandFinishedSpy.at(3).at(1).toBool()); + + delete ftp; + ftp = 0; +} + +void tst_QFtp::mkdir2Slot(int id, bool) +{ + if (id == current_id) + ftp->mkdir("kake/test"); +} + +void tst_QFtp::rmdir() +{ + DEPENDS_ON( "mkdir" ); +} + +void tst_QFtp::rename_data() +{ + QTest::addColumn<QString>("host"); + QTest::addColumn<QString>("user"); + QTest::addColumn<QString>("password"); + QTest::addColumn<QString>("cdDir"); + QTest::addColumn<QString>("oldfile"); + QTest::addColumn<QString>("newfile"); + QTest::addColumn<QString>("createFile"); + QTest::addColumn<QString>("renamedFile"); + QTest::addColumn<int>("success"); + + QTest::newRow("relPath01") << QtNetworkSettings::serverName() << QString() << QString() + << "qtest/upload" + << QString("rel_old01_%1") << QString("rel_new01_%1") + << QString("qtest/upload/rel_old01_%1") << QString("qtest/upload/rel_new01_%1") + << 1; + QTest::newRow("relPath02") << QtNetworkSettings::serverName() << QString("ftptest") << "password" + << "qtest/upload" + << QString("rel_old02_%1") << QString("rel_new02_%1") + << QString("qtest/upload/rel_old02_%1") << QString("qtest/upload/rel_new02_%1") + << 1; + QTest::newRow("relPath03") << QtNetworkSettings::serverName() << QString("ftptest") << "password" + << "qtest/upload" + << QString("rel_old03_%1")<< QString("rel_new03_%1") + << QString("qtest/upload/rel_old03_%1") << QString("qtest/upload/rel_new03_%1") + << 1; + + QTest::newRow("absPath01") << QtNetworkSettings::serverName() << QString() << QString() + << QString() + << QString("/qtest/upload/abs_old01_%1") << QString("/qtest/upload/abs_new01_%1") + << QString("/qtest/upload/abs_old01_%1") << QString("/qtest/upload/abs_new01_%1") + << 1; + QTest::newRow("absPath02") << QtNetworkSettings::serverName() << QString("ftptest") << "password" + << QString() + << QString("/var/ftp/qtest/upload/abs_old02_%1") << QString("/var/ftp/qtest/upload/abs_new02_%1") + << QString("/var/ftp/qtest/upload/abs_old02_%1") << QString("/var/ftp/qtest/upload/abs_new02_%1") + << 1; + + QTest::newRow("nonExist01") << QtNetworkSettings::serverName() << QString() << QString() + << QString() + << QString("foo") << "new_foo" + << QString() << QString() + << 0; + QTest::newRow("nonExist02") << QtNetworkSettings::serverName() << QString() << QString() + << QString() + << QString("/foo") << QString("/new_foo") + << QString() << QString() + << 0; +} + +void tst_QFtp::renameInit( const QString &host, const QString &user, const QString &password, const QString &createFile ) +{ + if ( !createFile.isNull() ) { + // upload the file + init(); + ftp = newFtp(); + addCommand( QFtp::ConnectToHost, ftp->connectToHost( host ) ); + addCommand( QFtp::Login, ftp->login( user, password ) ); + addCommand( QFtp::Put, ftp->put( QByteArray(), createFile ) ); + addCommand( QFtp::Close, ftp->close() ); + + QTestEventLoop::instance().enterLoop( 50 ); + delete ftp; + ftp = 0; + if ( QTestEventLoop::instance().timeout() ) + QFAIL( "Network operation timed out" ); + + ResMapIt it = resultMap.find( QFtp::Put ); + QVERIFY( it != resultMap.end() ); + QVERIFY( it.value().success == 1 ); + + QVERIFY( fileExists( host, 21, user, password, createFile ) ); + } +} + +void tst_QFtp::renameCleanup( const QString &host, const QString &user, const QString &password, const QString &fileToDelete ) +{ + if ( !fileToDelete.isNull() ) { + // cleanup (i.e. remove the file) + init(); + ftp = newFtp(); + addCommand( QFtp::ConnectToHost, ftp->connectToHost( host ) ); + addCommand( QFtp::Login, ftp->login( user, password ) ); + addCommand( QFtp::Remove, ftp->remove( fileToDelete ) ); + addCommand( QFtp::Close, ftp->close() ); + + QTestEventLoop::instance().enterLoop( 30 ); + delete ftp; + ftp = 0; + if ( QTestEventLoop::instance().timeout() ) + QFAIL( "Network operation timed out" ); + + ResMapIt it = resultMap.find( QFtp::Remove ); + QVERIFY( it != resultMap.end() ); + QVERIFY( it.value().success == 1 ); + + QVERIFY( !fileExists( host, 21, user, password, fileToDelete ) ); + } +} + +void tst_QFtp::rename() +{ + QFETCH( QString, host ); + QFETCH( QString, user ); + QFETCH( QString, password ); + QFETCH( QString, cdDir ); + QFETCH( QString, oldfile ); + QFETCH( QString, newfile ); + QFETCH( QString, createFile ); + QFETCH( QString, renamedFile ); + + if(oldfile.contains('%')) + oldfile = oldfile.arg(uniqueExtension); + if(newfile.contains('%')) + newfile = newfile.arg(uniqueExtension); + if(createFile.contains('%')) + createFile = createFile.arg(uniqueExtension); + if(renamedFile.contains('%')) + renamedFile = renamedFile.arg(uniqueExtension); + + renameInit( host, user, password, createFile ); + + init(); + ftp = newFtp(); + addCommand( QFtp::ConnectToHost, ftp->connectToHost( host ) ); + addCommand( QFtp::Login, ftp->login( user, password ) ); + if ( !cdDir.isNull() ) + addCommand( QFtp::Cd, ftp->cd( cdDir ) ); + addCommand( QFtp::Rename, ftp->rename( oldfile, newfile ) ); + addCommand( QFtp::Close, ftp->close() ); + + QTestEventLoop::instance().enterLoop( 30 ); + delete ftp; + ftp = 0; + if ( QTestEventLoop::instance().timeout() ) + QFAIL( "Network operation timed out" ); + + ResMapIt it = resultMap.find( QFtp::Rename ); + QVERIFY( it != resultMap.end() ); + QTEST( it.value().success, "success" ); + + if ( it.value().success ) { + QVERIFY( !fileExists( host, 21, user, password, oldfile, cdDir ) ); + QVERIFY( fileExists( host, 21, user, password, newfile, cdDir ) ); + QVERIFY( fileExists( host, 21, user, password, renamedFile ) ); + } else { + QVERIFY( !fileExists( host, 21, user, password, newfile, cdDir ) ); + QVERIFY( !fileExists( host, 21, user, password, renamedFile ) ); + } + + renameCleanup( host, user, password, renamedFile ); +} + +/* + The commandSequence() test does not test any particular function. It rather + tests a sequence of arbitrary commands specified in the test data. +*/ +class FtpCommand +{ +public: + FtpCommand() : + cmd(QFtp::None) + { } + + FtpCommand( QFtp::Command command ) : + cmd(command) + { } + + FtpCommand( QFtp::Command command, const QStringList &arguments ) : + cmd(command), args(arguments) + { } + + FtpCommand( const FtpCommand &c ) + { *this = c; } + + FtpCommand &operator=( const FtpCommand &c ) + { + this->cmd = c.cmd; + this->args = c.args; + return *this; + } + + QFtp::Command cmd; + QStringList args; +}; +QDataStream &operator<<( QDataStream &s, const FtpCommand &command ) +{ + s << (int)command.cmd; + s << command.args; + return s; +} +QDataStream &operator>>( QDataStream &s, FtpCommand &command ) +{ + int tmp; + s >> tmp; + command.cmd = (QFtp::Command)tmp; + s >> command.args; + return s; +} +Q_DECLARE_METATYPE(QList<FtpCommand>) + +void tst_QFtp::commandSequence_data() +{ + // some "constants" + QStringList argConnectToHost01; + argConnectToHost01 << QtNetworkSettings::serverName() << "21"; + + QStringList argLogin01, argLogin02, argLogin03, argLogin04; + argLogin01 << QString() << QString(); + argLogin02 << "ftp" << QString(); + argLogin03 << "ftp" << "foo"; + argLogin04 << QString("ftptest") << "password"; + + FtpCommand connectToHost01( QFtp::ConnectToHost, argConnectToHost01 ); + FtpCommand login01( QFtp::Login, argLogin01 ); + FtpCommand login02( QFtp::Login, argLogin01 ); + FtpCommand login03( QFtp::Login, argLogin01 ); + FtpCommand login04( QFtp::Login, argLogin01 ); + FtpCommand close01( QFtp::Close ); + + QTest::addColumn<QList<FtpCommand> >("cmds"); + QTest::addColumn<int>("success"); + + // success data + { + QList<FtpCommand> cmds; + cmds << connectToHost01; + QTest::newRow( "simple_ok01" ) << cmds << 1; + } + { + QList<FtpCommand> cmds; + cmds << connectToHost01; + cmds << login01; + QTest::newRow( "simple_ok02" ) << cmds << 1; + } + { + QList<FtpCommand> cmds; + cmds << connectToHost01; + cmds << login01; + cmds << close01; + QTest::newRow( "simple_ok03" ) << cmds << 1; + } + { + QList<FtpCommand> cmds; + cmds << connectToHost01; + cmds << close01; + QTest::newRow( "simple_ok04" ) << cmds << 1; + } + { + QList<FtpCommand> cmds; + cmds << connectToHost01; + cmds << login01; + cmds << close01; + cmds << connectToHost01; + cmds << login02; + cmds << close01; + QTest::newRow( "connect_twice" ) << cmds << 1; + } + + // error data + { + QList<FtpCommand> cmds; + cmds << close01; + QTest::newRow( "error01" ) << cmds << 0; + } + { + QList<FtpCommand> cmds; + cmds << login01; + QTest::newRow( "error02" ) << cmds << 0; + } + { + QList<FtpCommand> cmds; + cmds << login01; + cmds << close01; + QTest::newRow( "error03" ) << cmds << 0; + } + { + QList<FtpCommand> cmds; + cmds << connectToHost01; + cmds << login01; + cmds << close01; + cmds << login01; + QTest::newRow( "error04" ) << cmds << 0; + } +} + +void tst_QFtp::commandSequence() +{ + QFETCH( QList<FtpCommand>, cmds ); + + ftp = newFtp(); + QList<FtpCommand>::iterator it; + for ( it = cmds.begin(); it != cmds.end(); ++it ) { + switch ( (*it).cmd ) { + case QFtp::ConnectToHost: + { + QVERIFY( (*it).args.count() == 2 ); + uint port; + bool portOk; + port = (*it).args[1].toUInt( &portOk ); + QVERIFY( portOk ); + ids << ftp->connectToHost( (*it).args[0], port ); + } + break; + case QFtp::Login: + QVERIFY( (*it).args.count() == 2 ); + ids << ftp->login( (*it).args[0], (*it).args[1] ); + break; + case QFtp::Close: + QVERIFY( (*it).args.count() == 0 ); + ids << ftp->close(); + break; + default: + QFAIL( "Error in test: unexpected enum value" ); + break; + } + } + + QTestEventLoop::instance().enterLoop( 30 ); + delete ftp; + ftp = 0; + if ( QTestEventLoop::instance().timeout() ) + QFAIL( "Network operation timed out" ); + + QTEST( commandSequence_success, "success" ); +} + +void tst_QFtp::abort_data() +{ + QTest::addColumn<QString>("host"); + QTest::addColumn<uint>("port"); + QTest::addColumn<QString>("file"); + QTest::addColumn<QByteArray>("uploadData"); + + QTest::newRow( "get_fluke01" ) << QtNetworkSettings::serverName() << (uint)21 << QString("qtest/bigfile") << QByteArray(); + QTest::newRow( "get_fluke02" ) << QtNetworkSettings::serverName() << (uint)21 << QString("qtest/rfc3252") << QByteArray(); + + // Qt/CE and Symbian test environment has to less memory for this test +#if !defined(Q_OS_WINCE) && !defined(Q_OS_SYMBIAN) + QByteArray bigData( 10*1024*1024, 0 ); +#else + QByteArray bigData( 1*1024*1024, 0 ); +#endif + bigData.fill( 'B' ); + QTest::newRow( "put_fluke01" ) << QtNetworkSettings::serverName() << (uint)21 << QString("qtest/upload/abort_put") << bigData; +} + +void tst_QFtp::abort() +{ + // In case you wonder where the abort() actually happens, look into + // tst_QFtp::dataTransferProgress + // + QFETCH( QString, host ); + QFETCH( uint, port ); + QFETCH( QString, file ); + QFETCH( QByteArray, uploadData ); + + QFtp::Command cmd; + if ( uploadData.size() == 0 ) + cmd = QFtp::Get; + else + cmd = QFtp::Put; + + ftp = newFtp(); + addCommand( QFtp::ConnectToHost, ftp->connectToHost( host, port ) ); + addCommand( QFtp::Login, ftp->login() ); + if ( cmd == QFtp::Get ) + addCommand( cmd, ftp->get( file ) ); + else + addCommand( cmd, ftp->put( uploadData, file ) ); + addCommand( QFtp::Close, ftp->close() ); + + for(int time = 0; time <= uploadData.length() / 30000; time += 30) { + QTestEventLoop::instance().enterLoop( 50 ); + if(ftp->currentCommand() == QFtp::None) + break; + } + delete ftp; + ftp = 0; + if ( QTestEventLoop::instance().timeout() ) + QFAIL( "Network operation timed out" ); + + ResMapIt it = resultMap.find( cmd ); + QVERIFY( it != resultMap.end() ); + // ### how to test the abort? + if ( it.value().success ) { + // The FTP server on fluke is sadly returning a success, even when + // the operation was aborted. So we have to use some heuristics. + if ( host == QtNetworkSettings::serverName() ) { + if ( cmd == QFtp::Get ) { + QVERIFY(bytesDone <= bytesTotal); + } else { + // put commands should always be aborted, since we use really + // big data + QVERIFY( bytesDone != bytesTotal ); + } + } else { + // this could be tested by verifying that no more progress signals are emitted + QVERIFY(bytesDone <= bytesTotal); + } + } else { + QVERIFY( bytesDone != bytesTotal ); + } + + if ( cmd == QFtp::Put ) { + ////////////////////////////////////// + // cleanup (i.e. remove the file) + init(); + ftp = newFtp(); + addCommand( QFtp::ConnectToHost, ftp->connectToHost( host, port ) ); + addCommand( QFtp::Login, ftp->login() ); + addCommand( QFtp::Remove, ftp->remove( file ) ); + addCommand( QFtp::Close, ftp->close() ); + + QTestEventLoop::instance().enterLoop( 30 ); + delete ftp; + ftp = 0; + if ( QTestEventLoop::instance().timeout() ) + QFAIL( "Network operation timed out" ); + + it = resultMap.find( QFtp::Remove ); + QVERIFY( it != resultMap.end() ); + QVERIFY( it.value().success == 1 ); + } +} + +void tst_QFtp::bytesAvailable_data() +{ + QTest::addColumn<QString>("host"); + QTest::addColumn<QString>("file"); + QTest::addColumn<int>("type"); + QTest::addColumn<qlonglong>("bytesAvailFinishedGet"); + QTest::addColumn<qlonglong>("bytesAvailFinished"); + QTest::addColumn<qlonglong>("bytesAvailDone"); + + QTest::newRow( "fluke01" ) << QtNetworkSettings::serverName() << QString("qtest/bigfile") << 0 << (qlonglong)519240 << (qlonglong)519240 << (qlonglong)519240; + QTest::newRow( "fluke02" ) << QtNetworkSettings::serverName() << QString("qtest/rfc3252") << 0 << (qlonglong)25962 << (qlonglong)25962 << (qlonglong)25962; + + QTest::newRow( "fluke03" ) << QtNetworkSettings::serverName() << QString("qtest/bigfile") << 1 << (qlonglong)519240 << (qlonglong)0 << (qlonglong)0; + QTest::newRow( "fluke04" ) << QtNetworkSettings::serverName() << QString("qtest/rfc3252") << 1 << (qlonglong)25962 << (qlonglong)0 << (qlonglong)0; +} + +void tst_QFtp::bytesAvailable() +{ + QFETCH( QString, host ); + QFETCH( QString, file ); + QFETCH( int, type ); + + ftp = newFtp(); + addCommand( QFtp::ConnectToHost, ftp->connectToHost( host ) ); + addCommand( QFtp::Login, ftp->login() ); + addCommand( QFtp::Get, ftp->get( file ) ); + if ( type != 0 ) + addCommand( QFtp::Close, ftp->close() ); + + QTestEventLoop::instance().enterLoop( 40 ); + if ( QTestEventLoop::instance().timeout() ) + QFAIL( "Network operation timed out" ); + + ResMapIt it = resultMap.find( QFtp::Get ); + QVERIFY( it != resultMap.end() ); + QVERIFY( it.value().success ); + + QFETCH(qlonglong, bytesAvailFinishedGet); + QCOMPARE(bytesAvailable_finishedGet, bytesAvailFinishedGet); + + QFETCH(qlonglong, bytesAvailFinished); + QCOMPARE(bytesAvailable_finished, bytesAvailFinished); + + QFETCH(qlonglong, bytesAvailDone); + QCOMPARE(bytesAvailable_done, bytesAvailDone); + + ftp->readAll(); + QVERIFY( ftp->bytesAvailable() == 0 ); + delete ftp; + ftp = 0; +} + +void tst_QFtp::activeMode() +{ + QFile file("tst_QFtp_activeMode_inittab"); + file.open(QIODevice::ReadWrite); + QFtp ftp; + ftp.setTransferMode(QFtp::Active); + ftp.connectToHost(QtNetworkSettings::serverName(), 21); + ftp.login(); + ftp.list(); + ftp.get("/qtest/rfc3252.txt", &file); + connect(&ftp, SIGNAL(done(bool)), SLOT(activeModeDone(bool))); + QTestEventLoop::instance().enterLoop(900); + QFile::remove("tst_QFtp_activeMode_inittab"); + QVERIFY(done_success == 1); + +} + +void tst_QFtp::activeModeDone(bool error) +{ + done_success = error ? -1 : 1; + QTestEventLoop::instance().exitLoop(); +} + +void tst_QFtp::proxy_data() +{ + QTest::addColumn<QString>("host"); + QTest::addColumn<uint>("port"); + QTest::addColumn<QString>("user"); + QTest::addColumn<QString>("password"); + QTest::addColumn<QString>("dir"); + QTest::addColumn<int>("success"); + QTest::addColumn<QStringList>("entryNames"); // ### we should rather use a QList<QUrlInfo> here + + QStringList flukeRoot; + flukeRoot << "qtest"; + QStringList flukeQtest; + flukeQtest << "bigfile"; + flukeQtest << "nonASCII"; + flukeQtest << "rfc3252"; + flukeQtest << "rfc3252.txt"; + flukeQtest << "upload"; + + QTest::newRow( "proxy_relPath01" ) << QtNetworkSettings::serverName() << (uint)21 << QString() << QString() << QString("qtest") << 1 << flukeQtest; + QTest::newRow( "proxy_relPath02" ) << QtNetworkSettings::serverName() << (uint)21 << QString("ftptest") << QString("password") << QString("qtest") << 1 << flukeQtest; + + QTest::newRow( "proxy_absPath01" ) << QtNetworkSettings::serverName() << (uint)21 << QString() << QString() << QString("/qtest") << 1 << flukeQtest; + QTest::newRow( "proxy_absPath02" ) << QtNetworkSettings::serverName() << (uint)21 << QString("ftptest") << QString("password") << QString("/var/ftp/qtest") << 1 << flukeQtest; + + QTest::newRow( "proxy_nonExist01" ) << QtNetworkSettings::serverName() << (uint)21 << QString() << QString() << QString("foo") << 0 << QStringList(); + QTest::newRow( "proxy_nonExist03" ) << QtNetworkSettings::serverName() << (uint)21 << QString() << QString() << QString("/foo") << 0 << QStringList(); +} + +void tst_QFtp::proxy() +{ + QFETCH( QString, host ); + QFETCH( uint, port ); + QFETCH( QString, user ); + QFETCH( QString, password ); + QFETCH( QString, dir ); + + ftp = newFtp(); + addCommand( QFtp::SetProxy, ftp->setProxy( QtNetworkSettings::serverName(), 2121 ) ); + addCommand( QFtp::ConnectToHost, ftp->connectToHost( host, port ) ); + addCommand( QFtp::Login, ftp->login( user, password ) ); + addCommand( QFtp::Cd, ftp->cd( dir ) ); + addCommand( QFtp::List, ftp->list() ); + + QTestEventLoop::instance().enterLoop( 50 ); + + delete ftp; + ftp = 0; + if ( QTestEventLoop::instance().timeout() ) { + QFAIL( "Network operation timed out" ); + } + + ResMapIt it = resultMap.find( QFtp::Cd ); + QVERIFY( it != resultMap.end() ); + QFETCH( int, success ); + QCOMPARE( it.value().success, success ); + QFETCH( QStringList, entryNames ); + QCOMPARE( listInfo_i.count(), entryNames.count() ); + for ( uint i=0; i < (uint) entryNames.count(); i++ ) { + QCOMPARE( listInfo_i[i].name(), entryNames[i] ); + } +} + +void tst_QFtp::binaryAscii() +{ + QString file = "asciifile%1.txt"; + + if(file.contains('%')) + file = file.arg(uniqueExtension); + + QByteArray putData = "a line of text\r\n"; + + init(); + ftp = newFtp(); + addCommand(QFtp::ConnectToHost, ftp->connectToHost(QtNetworkSettings::serverName(), 21)); + addCommand(QFtp::Login, ftp->login("ftptest", "password")); + addCommand(QFtp::Cd, ftp->cd("qtest/upload")); + addCommand(QFtp::Put, ftp->put(putData, file, QFtp::Ascii)); + addCommand(QFtp::Close, ftp->close()); + + QTestEventLoop::instance().enterLoop( 30 ); + delete ftp; + ftp = 0; + if ( QTestEventLoop::instance().timeout() ) + QFAIL( "Network operation timed out" ); + + ResMapIt it = resultMap.find(QFtp::Put); + QVERIFY(it != resultMap.end()); + QVERIFY(it.value().success); + + QByteArray getData; + QBuffer getBuf(&getData); + getBuf.open(QBuffer::WriteOnly); + + init(); + ftp = newFtp(); + addCommand(QFtp::ConnectToHost, ftp->connectToHost(QtNetworkSettings::serverName(), 21)); + addCommand(QFtp::Login, ftp->login("ftptest", "password")); + addCommand(QFtp::Cd, ftp->cd("qtest/upload")); + addCommand(QFtp::Get, ftp->get(file, &getBuf, QFtp::Binary)); + addCommand(QFtp::Close, ftp->close()); + + QTestEventLoop::instance().enterLoop( 30 ); + delete ftp; + ftp = 0; + if ( QTestEventLoop::instance().timeout() ) + QFAIL( "Network operation timed out" ); + + ResMapIt it2 = resultMap.find(QFtp::Get); + QVERIFY(it2 != resultMap.end()); + QVERIFY(it2.value().success); + // most modern ftp servers leave the file as it is by default + // (and do not remove the windows line ending), the -1 below could be + // deleted in the future + QVERIFY(getData.size() == putData.size()-1); + ////////////////////////////////////////////////////////////////// + // cleanup (i.e. remove the file) -- this also tests the remove command + init(); + ftp = newFtp(); + addCommand(QFtp::ConnectToHost, ftp->connectToHost(QtNetworkSettings::serverName(), 21)); + addCommand(QFtp::Login, ftp->login("ftptest", "password")); + addCommand(QFtp::Cd, ftp->cd("qtest/upload")); + addCommand(QFtp::Remove, ftp->remove(file)); + addCommand(QFtp::Close, ftp->close()); + + QTestEventLoop::instance().enterLoop( 30 ); + delete ftp; + ftp = 0; + if ( QTestEventLoop::instance().timeout() ) + QFAIL( "Network operation timed out" ); + + it = resultMap.find( QFtp::Remove ); + QVERIFY( it != resultMap.end() ); + QCOMPARE( it.value().success, 1 ); + + QVERIFY(!fileExists(QtNetworkSettings::serverName(), 21, "ftptest", "password", file)); +} + + +// test QFtp::currentId() and QFtp::currentCommand() +#define CURRENTCOMMAND_TEST \ +{ \ + ResMapIt it; \ + for ( it = resultMap.begin(); it != resultMap.end(); ++it ) { \ + if ( it.value().id == ftp->currentId() ) { \ + QVERIFY( it.key() == ftp->currentCommand() ); \ + } \ +} \ +} + +void tst_QFtp::commandStarted( int id ) +{ +#if defined( DUMP_SIGNALS ) + qDebug( "%d:commandStarted( %d )", ftp->currentId(), id ); +#endif + // make sure that the commandStarted and commandFinished are nested correctly + QVERIFY( current_id == 0 ); + current_id = id; + + QVERIFY( !ids.isEmpty() ); + QVERIFY( ids.first() == id ); + if ( ids.count() > 1 ) { + QVERIFY( ftp->hasPendingCommands() ); + } else { + QVERIFY( !ftp->hasPendingCommands() ); + } + + QVERIFY( ftp->currentId() == id ); + QVERIFY( cur_state == ftp->state() ); + CURRENTCOMMAND_TEST; + + QVERIFY( ftp->error() == QFtp::NoError ); +} + +void tst_QFtp::commandFinished( int id, bool error ) +{ +#if defined( DUMP_SIGNALS ) + qDebug( "%d:commandFinished( %d, %d ) -- errorString: '%s'", + ftp->currentId(), id, (int)error, ftp->errorString().toLatin1().constData() ); +#endif + if ( ftp->currentCommand() == QFtp::Get ) { + bytesAvailable_finishedGet = ftp->bytesAvailable(); + } + bytesAvailable_finished = ftp->bytesAvailable(); + + // make sure that the commandStarted and commandFinished are nested correctly + QVERIFY( current_id == id ); + current_id = 0; + + QVERIFY( !ids.isEmpty() ); + QVERIFY( ids.first() == id ); + if ( !error && ids.count() > 1) { + QVERIFY( ftp->hasPendingCommands() ); + } else { + QVERIFY( !ftp->hasPendingCommands() ); + } + if ( error ) { + QVERIFY( ftp->error() != QFtp::NoError ); + ids.clear(); + } else { + QVERIFY( ftp->error() == QFtp::NoError ); + ids.pop_front(); + } + + QVERIFY( ftp->currentId() == id ); + QVERIFY( cur_state == ftp->state() ); + CURRENTCOMMAND_TEST; + + if ( QTest::currentTestFunction() != QLatin1String("commandSequence") ) { + ResMapIt it = resultMap.find( ftp->currentCommand() ); + QVERIFY( it != resultMap.end() ); + QVERIFY( it.value().success == -1 ); + if ( error ) + it.value().success = 0; + else + it.value().success = 1; + } +} + +void tst_QFtp::done( bool error ) +{ +#if defined( DUMP_SIGNALS ) + qDebug( "%d:done( %d )", ftp->currentId(), (int)error ); +#endif + bytesAvailable_done = ftp->bytesAvailable(); + + QVERIFY( ftp->currentId() == 0 ); + QVERIFY( current_id == 0 ); + QVERIFY( ids.isEmpty() ); + QVERIFY( cur_state == ftp->state() ); + QVERIFY( !ftp->hasPendingCommands() ); + + if ( QTest::currentTestFunction() == QLatin1String("commandSequence") ) { + QVERIFY( commandSequence_success == -1 ); + if ( error ) + commandSequence_success = 0; + else + commandSequence_success = 1; + } + QVERIFY( done_success == -1 ); + if ( error ) { + QVERIFY( ftp->error() != QFtp::NoError ); + done_success = 0; + } else { + QVERIFY( ftp->error() == QFtp::NoError ); + done_success = 1; + } + QTestEventLoop::instance().exitLoop(); +} + +void tst_QFtp::stateChanged( int state ) +{ +#if defined( DUMP_SIGNALS ) + qDebug( "%d: stateChanged( %d )", ftp->currentId(), state ); +#endif + QCOMPARE( ftp->currentId(), current_id ); + CURRENTCOMMAND_TEST; + + QVERIFY( state != cur_state ); + QCOMPARE( state, (int)ftp->state() ); + if ( state != QFtp::Unconnected ) { + // make sure that the states are always emitted in the right order (for + // this, we assume an ordering on the enum values, which they have at + // the moment) + QVERIFY( cur_state < state ); + + // make sure that state changes are only emitted in response to certain + // commands + switch ( state ) { + case QFtp::HostLookup: + case QFtp::Connecting: + case QFtp::Connected: + QCOMPARE( (int)ftp->currentCommand(), (int)QFtp::ConnectToHost ); + break; + case QFtp::LoggedIn: + QCOMPARE( (int)ftp->currentCommand(), (int)QFtp::Login ); + break; + case QFtp::Closing: + QCOMPARE( (int)ftp->currentCommand(), (int)QFtp::Close ); + break; + default: + QWARN( QString("Unexpected state '%1'").arg(state).toLatin1().constData() ); + break; + } + } + cur_state = state; + + if ( QTest::currentTestFunction() == QLatin1String("connectToHost") ) { + switch ( state ) { + case QFtp::HostLookup: + case QFtp::Connecting: + case QFtp::LoggedIn: + case QFtp::Closing: + // ignore + break; + case QFtp::Connected: + case QFtp::Unconnected: + QVERIFY( connectToHost_state == -1 ); + connectToHost_state = state; + break; + default: + QWARN( QString("Unknown state '%1'").arg(state).toLatin1().constData() ); + break; + } + } else if ( QTest::currentTestFunction() == QLatin1String("close") ) { + ResMapIt it = resultMap.find( QFtp::Close ); + if ( it!=resultMap.end() && ftp->currentId()==it.value().id ) { + if ( state == QFtp::Closing ) { + QVERIFY( close_state == -1 ); + close_state = state; + } else if ( state == QFtp::Unconnected ) { + QVERIFY( close_state == QFtp::Closing ); + close_state = state; + } + } + } else if ( QTest::currentTestFunction() == QLatin1String("login") ) { + ResMapIt it = resultMap.find( QFtp::Login ); + if ( it!=resultMap.end() && ftp->currentId()==it.value().id ) { + if ( state == QFtp::LoggedIn ) { + QVERIFY( login_state == -1 ); + login_state = state; + } + } + } +} + +void tst_QFtp::listInfo( const QUrlInfo &i ) +{ +#if defined( DUMP_SIGNALS ) + qDebug( "%d: listInfo( %s )", ftp->currentId(), i.name().toLatin1().constData() ); +#endif + QCOMPARE( ftp->currentId(), current_id ); + if ( ids.count() > 1 ) { + QVERIFY( ftp->hasPendingCommands() ); + } else { + QVERIFY( !ftp->hasPendingCommands() ); + } + QVERIFY( cur_state == ftp->state() ); + CURRENTCOMMAND_TEST; + + if ( QTest::currentTestFunction()==QLatin1String("list") || QTest::currentTestFunction()==QLatin1String("cd") || QTest::currentTestFunction()==QLatin1String("proxy") || inFileDirExistsFunction ) { + ResMapIt it = resultMap.find( QFtp::List ); + QVERIFY( it != resultMap.end() ); + QVERIFY( ftp->currentId() == it.value().id ); + listInfo_i << i; + } +} + +void tst_QFtp::readyRead() +{ +#if defined( DUMP_SIGNALS ) + qDebug( "%d: readyRead(), bytesAvailable == %lu", ftp->currentId(), ftp->bytesAvailable() ); +#endif + QCOMPARE( ftp->currentId(), current_id ); + if ( ids.count() > 1 ) { + QVERIFY( ftp->hasPendingCommands() ); + } else { + QVERIFY( !ftp->hasPendingCommands() ); + } + QVERIFY( cur_state == ftp->state() ); + CURRENTCOMMAND_TEST; + + if ( QTest::currentTestFunction() != QLatin1String("bytesAvailable") ) { + int oldSize = newData_ba.size(); + qlonglong bytesAvail = ftp->bytesAvailable(); + QByteArray ba = ftp->readAll(); + QVERIFY( ba.size() == (int) bytesAvail ); + newData_ba.resize( oldSize + ba.size() ); + memcpy( newData_ba.data()+oldSize, ba.data(), ba.size() ); + + if ( bytesTotal != -1 ) { + QVERIFY( (int)newData_ba.size() <= bytesTotal ); + } + QVERIFY( (int)newData_ba.size() == bytesDone ); + } +} + +void tst_QFtp::dataTransferProgress( qint64 done, qint64 total ) +{ +#if defined( DUMP_SIGNALS ) + qDebug( "%d: dataTransferProgress( %lli, %lli )", ftp->currentId(), done, total ); +#endif + QCOMPARE( ftp->currentId(), current_id ); + if ( ids.count() > 1 ) { + QVERIFY( ftp->hasPendingCommands() ); + } else { + QVERIFY( !ftp->hasPendingCommands() ); + } + QVERIFY( cur_state == ftp->state() ); + CURRENTCOMMAND_TEST; + + if ( bytesTotal == bytesTotal_init ) { + bytesTotal = total; + } else { + QVERIFY( bytesTotal == total ); + } + + QVERIFY( bytesTotal != bytesTotal_init ); + QVERIFY( bytesDone <= done ); + bytesDone = done; + if ( bytesTotal != -1 ) { + QVERIFY( bytesDone <= bytesTotal ); + } + + if ( QTest::currentTestFunction() == QLatin1String("abort") ) { + // ### it would be nice if we could specify in our testdata when to do + // the abort + if ( done >= total/100000 ) { + if ( ids.count() != 1 ) { + // do abort only once + int tmpId = ids.first(); + ids.clear(); + ids << tmpId; + ftp->abort(); + } + } + } +} + + +QFtp *tst_QFtp::newFtp() +{ + QFtp *nFtp = new QFtp( this ); +#ifndef QT_NO_BEARERMANAGEMENT + if (networkSessionExplicit) { + nFtp->setProperty("_q_networksession", QVariant::fromValue(networkSessionExplicit)); + } +#endif + connect( nFtp, SIGNAL(commandStarted(int)), + SLOT(commandStarted(int)) ); + connect( nFtp, SIGNAL(commandFinished(int,bool)), + SLOT(commandFinished(int,bool)) ); + connect( nFtp, SIGNAL(done(bool)), + SLOT(done(bool)) ); + connect( nFtp, SIGNAL(stateChanged(int)), + SLOT(stateChanged(int)) ); + connect( nFtp, SIGNAL(listInfo(const QUrlInfo&)), + SLOT(listInfo(const QUrlInfo&)) ); + connect( nFtp, SIGNAL(readyRead()), + SLOT(readyRead()) ); + connect( nFtp, SIGNAL(dataTransferProgress(qint64, qint64)), + SLOT(dataTransferProgress(qint64, qint64)) ); + + return nFtp; +} + +void tst_QFtp::addCommand( QFtp::Command cmd, int id ) +{ + ids << id; + CommandResult res; + res.id = id; + res.success = -1; + resultMap[ cmd ] = res; +} + +bool tst_QFtp::fileExists( const QString &host, quint16 port, const QString &user, const QString &password, const QString &file, const QString &cdDir ) +{ + init(); + ftp = newFtp(); + // ### make these tests work + if (ftp->currentId() != 0) { + qWarning("ftp->currentId() != 0"); + return FALSE; + } + + if (ftp->state() != QFtp::Unconnected) { + qWarning("ftp->state() != QFtp::Unconnected"); + return FALSE; + } + + addCommand( QFtp::ConnectToHost, ftp->connectToHost( host, port ) ); + addCommand( QFtp::Login, ftp->login( user, password ) ); + if ( !cdDir.isNull() ) + addCommand( QFtp::Cd, ftp->cd( cdDir ) ); + addCommand( QFtp::List, ftp->list( file ) ); + addCommand( QFtp::Close, ftp->close() ); + + inFileDirExistsFunction = TRUE; + QTestEventLoop::instance().enterLoop( 30 ); + delete ftp; + ftp = 0; + if ( QTestEventLoop::instance().timeout() ) { + // ### make this test work + qWarning("tst_QFtp::fileExists: Network operation timed out"); + return FALSE; + } + inFileDirExistsFunction = FALSE; + + ResMapIt it = resultMap.find( QFtp::ConnectToHost ); + // ### make these tests work + if (it == resultMap.end()) { + qWarning("it != resultMap.end()"); + return FALSE; + } + + if (it.value().success == -1) { + qWarning("it.value().success != -1"); + return FALSE; + } + + if ( it.value().success == 1 ) { + for ( uint i=0; i < (uint) listInfo_i.count(); i++ ) { + if ( QFileInfo(listInfo_i[i].name()).fileName() == QFileInfo(file).fileName() ) + return TRUE; + } + } + + //this is not a good warning considering sometime this function is used to test that a file does not exist + //qWarning("file doesn't exist"); + return FALSE; +} + +bool tst_QFtp::dirExists( const QString &host, quint16 port, const QString &user, const QString &password, const QString &cdDir, const QString &dirToCreate ) +{ + init(); + ftp = newFtp(); + // ### make these tests work + // QCOMPARE( ftp->currentId(), 0 ); + // QCOMPARE( (int)ftp->state(), (int)QFtp::Unconnected ); + + addCommand( QFtp::ConnectToHost, ftp->connectToHost( host, port ) ); + addCommand( QFtp::Login, ftp->login( user, password ) ); + if ( dirToCreate.startsWith( "/" ) ) + addCommand( QFtp::Cd, ftp->cd( dirToCreate ) ); + else + addCommand( QFtp::Cd, ftp->cd( cdDir + "/" + dirToCreate ) ); + addCommand( QFtp::Close, ftp->close() ); + + inFileDirExistsFunction = TRUE; + QTestEventLoop::instance().enterLoop( 30 ); + delete ftp; + ftp = 0; + if ( QTestEventLoop::instance().timeout() ) { + // ### make this test work + // QFAIL( "Network operation timed out" ); + qWarning("tst_QFtp::dirExists: Network operation timed out"); + return FALSE; + } + inFileDirExistsFunction = FALSE; + + ResMapIt it = resultMap.find( QFtp::Cd ); + // ### make these tests work + // QVERIFY( it != resultMap.end() ); + // QVERIFY( it.value().success != -1 ); + return it.value().success == 1; +} + +void tst_QFtp::doneSignal() +{ + QFtp ftp; + QSignalSpy spy(&ftp, SIGNAL(done(bool))); + + ftp.connectToHost(QtNetworkSettings::serverName()); + ftp.login("anonymous"); + ftp.list(); + ftp.close(); + + done_success = 0; + connect(&ftp, SIGNAL(done(bool)), &(QTestEventLoop::instance()), SLOT(exitLoop())); + QTestEventLoop::instance().enterLoop(61); + if (QTestEventLoop::instance().timeout()) + QFAIL("Network operation timed out"); + + QTest::qWait(200); + + QCOMPARE(spy.count(), 1); + QCOMPARE(spy.first().first().toBool(), false); +} + +void tst_QFtp::queueMoreCommandsInDoneSlot() +{ + QSKIP("Task 127050 && 113966", SkipSingle); + + QFtp ftp; + QSignalSpy doneSpy(&ftp, SIGNAL(done(bool))); + QSignalSpy commandFinishedSpy(&ftp, SIGNAL(commandFinished(int, bool))); + + this->ftp = &ftp; + connect(&ftp, SIGNAL(done(bool)), this, SLOT(cdUpSlot(bool))); + + ftp.connectToHost("ftp.qt.nokia.com"); + ftp.login(); + ftp.cd("qt"); + ftp.rmdir("qtest-removedir-noexist"); + + while ( ftp.hasPendingCommands() || ftp.currentCommand() != QFtp::None ) { + QCoreApplication::instance()->processEvents(QEventLoop::AllEvents + | QEventLoop::WaitForMoreEvents); + } + + QCOMPARE(doneSpy.count(), 2); + QCOMPARE(doneSpy.first().first().toBool(), true); + QCOMPARE(doneSpy.last().first().toBool(), false); + + QCOMPARE(commandFinishedSpy.count(), 6); + int firstId = commandFinishedSpy.at(0).at(0).toInt(); + QCOMPARE(commandFinishedSpy.at(0).at(1).toBool(), false); + QCOMPARE(commandFinishedSpy.at(1).at(0).toInt(), firstId + 1); + QCOMPARE(commandFinishedSpy.at(1).at(1).toBool(), false); + QCOMPARE(commandFinishedSpy.at(2).at(0).toInt(), firstId + 2); + QCOMPARE(commandFinishedSpy.at(2).at(1).toBool(), false); + QCOMPARE(commandFinishedSpy.at(3).at(0).toInt(), firstId + 3); + QCOMPARE(commandFinishedSpy.at(3).at(1).toBool(), true); + QCOMPARE(commandFinishedSpy.at(4).at(0).toInt(), firstId + 4); + QCOMPARE(commandFinishedSpy.at(4).at(1).toBool(), false); + QCOMPARE(commandFinishedSpy.at(5).at(0).toInt(), firstId + 5); + QCOMPARE(commandFinishedSpy.at(5).at(1).toBool(), false); + + this->ftp = 0; +} + +void tst_QFtp::cdUpSlot(bool error) +{ + if (error) { + ftp->cd(".."); + ftp->cd("qt"); + } +} + +void tst_QFtp::qtbug7359Crash() +{ + QFtp ftp; + ftp.connectToHost("127.0.0.1"); + + QTime t; + int elapsed; + + t.start(); + while ((elapsed = t.elapsed()) < 200) + QCoreApplication::processEvents(QEventLoop::AllEvents, 200 - elapsed); + + ftp.close(); + t.restart(); + while ((elapsed = t.elapsed()) < 1000) + QCoreApplication::processEvents(QEventLoop::AllEvents, 1000 - elapsed); + + ftp.connectToHost("127.0.0.1"); + + t.restart(); + while ((elapsed = t.elapsed()) < 2000) + QCoreApplication::processEvents(QEventLoop::AllEvents, 2000 - elapsed); +} + +QTEST_MAIN(tst_QFtp) + +#include "tst_qftp.moc" diff --git a/tests/auto/network/access/qhttp/.gitattributes b/tests/auto/network/access/qhttp/.gitattributes new file mode 100644 index 0000000000..e04709aa2e --- /dev/null +++ b/tests/auto/network/access/qhttp/.gitattributes @@ -0,0 +1 @@ +rfc3252.txt -crlf diff --git a/tests/auto/network/access/qhttp/.gitignore b/tests/auto/network/access/qhttp/.gitignore new file mode 100644 index 0000000000..00c1f492cd --- /dev/null +++ b/tests/auto/network/access/qhttp/.gitignore @@ -0,0 +1 @@ +tst_qhttp diff --git a/tests/auto/network/access/qhttp/dummyserver.h b/tests/auto/network/access/qhttp/dummyserver.h new file mode 100644 index 0000000000..7c14ae2f14 --- /dev/null +++ b/tests/auto/network/access/qhttp/dummyserver.h @@ -0,0 +1,114 @@ +/**************************************************************************** +** +** 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 test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** 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. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ +// Use if you need + +class DummyHttpServer : public QTcpServer +{ + Q_OBJECT +public: + DummyHttpServer() : phase(Header) + { listen(); } + +protected: + enum { + Header, + Data1, + Data2, + Close + } phase; + void incomingConnection(int socketDescriptor) + { + QSslSocket *socket = new QSslSocket(this); + socket->setSocketDescriptor(socketDescriptor, QAbstractSocket::ConnectedState); + socket->ignoreSslErrors(); + socket->startServerEncryption(); + connect(socket, SIGNAL(readyRead()), SLOT(handleReadyRead())); + } + +public slots: + void handleReadyRead() + { + QTcpSocket *socket = static_cast<QTcpSocket *>(sender()); + socket->readAll(); + if (phase != Header) + return; + + phase = Data1; + static const char header[] = + "HTTP/1.0 200 OK\r\n" + "Date: Fri, 07 Sep 2007 12:33:18 GMT\r\n" + "Server: Apache\r\n" + "Expires:\r\n" + "Cache-Control:\r\n" + "Pragma:\r\n" + "Last-Modified: Thu, 06 Sep 2007 08:52:06 +0000\r\n" + "Etag: a700f59a6ccb1ad39af68d998aa36fb1\r\n" + "Vary: Accept-Encoding\r\n" + "Content-Length: 6560\r\n" + "Connection: close\r\n" + "Content-Type: text/html; charset=utf-8\r\n" + "\r\n"; + + + socket->write(header, sizeof header - 1); + connect(socket, SIGNAL(bytesWritten(qint64)), SLOT(handleBytesWritten()), Qt::QueuedConnection); + } + + void handleBytesWritten() + { + QTcpSocket *socket = static_cast<QTcpSocket *>(sender()); + if (socket->bytesToWrite() != 0) + return; + + if (phase == Data1) { + QByteArray data(4096, 'a'); + socket->write(data); + phase = Data2; + } else if (phase == Data2) { + QByteArray data(2464, 'a'); + socket->write(data); + phase = Close; + } else { + //socket->disconnectFromHost(); + //socket->deleteLater(); + } + } +}; diff --git a/tests/auto/network/access/qhttp/qhttp.pro b/tests/auto/network/access/qhttp/qhttp.pro new file mode 100644 index 0000000000..f01f60f3d7 --- /dev/null +++ b/tests/auto/network/access/qhttp/qhttp.pro @@ -0,0 +1,31 @@ +load(qttest_p4) +SOURCES += tst_qhttp.cpp + + +QT = core network + +wince*: { + webFiles.files = webserver/* + webFiles.path = webserver + cgi.files = webserver/cgi-bin/* + cgi.path = webserver/cgi-bin + addFiles.files = rfc3252.txt trolltech + addFiles.path = . + DEPLOYMENT += addFiles webFiles cgi + DEFINES += SRCDIR=\\\"\\\" +} else:symbian { + webFiles.files = webserver/* + webFiles.path = webserver + cgi.files = webserver/cgi-bin/* + cgi.path = webserver/cgi-bin + addFiles.files = rfc3252.txt trolltech + addFiles.path = . + DEPLOYMENT += addFiles webFiles cgi + TARGET.CAPABILITY = NetworkServices +} else:vxworks*: { + DEFINES += SRCDIR=\\\"\\\" +} else { + DEFINES += SRCDIR=\\\"$$PWD/\\\" +} + +CONFIG+=insignificant_test diff --git a/tests/auto/network/access/qhttp/rfc3252.txt b/tests/auto/network/access/qhttp/rfc3252.txt new file mode 100644 index 0000000000..b80c61bf0a --- /dev/null +++ b/tests/auto/network/access/qhttp/rfc3252.txt @@ -0,0 +1,899 @@ + + + + + + +Network Working Group H. Kennedy +Request for Comments: 3252 Mimezine +Category: Informational 1 April 2002 + + + Binary Lexical Octet Ad-hoc Transport + +Status of this Memo + + This memo provides information for the Internet community. It does + not specify an Internet standard of any kind. Distribution of this + memo is unlimited. + +Copyright Notice + + Copyright (C) The Internet Society (2002). All Rights Reserved. + +Abstract + + This document defines a reformulation of IP and two transport layer + protocols (TCP and UDP) as XML applications. + +1. Introduction + +1.1. Overview + + This document describes the Binary Lexical Octet Ad-hoc Transport + (BLOAT): a reformulation of a widely-deployed network-layer protocol + (IP [RFC791]), and two associated transport layer protocols (TCP + [RFC793] and UDP [RFC768]) as XML [XML] applications. It also + describes methods for transporting BLOAT over Ethernet and IEEE 802 + networks as well as encapsulating BLOAT in IP for gatewaying BLOAT + across the public Internet. + +1.2. Motivation + + The wild popularity of XML as a basis for application-level protocols + such as the Blocks Extensible Exchange Protocol [RFC3080], the Simple + Object Access Protocol [SOAP], and Jabber [JABBER] prompted + investigation into the possibility of extending the use of XML in the + protocol stack. Using XML at both the transport and network layer in + addition to the application layer would provide for an amazing amount + of power and flexibility while removing dependencies on proprietary + and hard-to-understand binary protocols. This protocol unification + would also allow applications to use a single XML parser for all + aspects of their operation, eliminating developer time spent figuring + out the intricacies of each new protocol, and moving the hard work of + + + + +Kennedy Informational [Page 1] + +RFC 3252 Binary Lexical Octet Ad-hoc Transport 1 April 2002 + + + parsing to the XML toolset. The use of XML also mitigates concerns + over "network vs. host" byte ordering which is at the root of many + network application bugs. + +1.3. Relation to Existing Protocols + + The reformulations specified in this RFC follow as closely as + possible the spirit of the RFCs on which they are based, and so MAY + contain elements or attributes that would not be needed in a pure + reworking (e.g. length attributes, which are implicit in XML.) + + The layering of network and transport protocols are maintained in + this RFC despite the optimizations that could be made if the line + were somewhat blurred (i.e. merging TCP and IP into a single, larger + element in the DTD) in order to foster future use of this protocol as + a basis for reformulating other protocols (such as ICMP.) + + Other than the encoding, the behavioral aspects of each of the + existing protocols remain unchanged. Routing, address spaces, TCP + congestion control, etc. behave as specified in the extant standards. + Adapting to new standards and experimental algorithm heuristics for + improving performance will become much easier once the move to BLOAT + has been completed. + +1.4. Requirement Levels + + The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", + "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this + document are to be interpreted as described in BCP 14, RFC 2119 + [RFC2119]. + +2. IPoXML + + This protocol MUST be implemented to be compliant with this RFC. + IPoXML is the root protocol REQUIRED for effective use of TCPoXML + (section 3.) and higher-level application protocols. + + The DTD for this document type can be found in section 7.1. + + The routing of IPoXML can be easily implemented on hosts with an XML + parser, as the regular structure lends itself handily to parsing and + validation of the document/datagram and then processing the + destination address, TTL, and checksum before sending it on to its + next-hop. + + The reformulation of IPv4 was chosen over IPv6 [RFC2460] due to the + wider deployment of IPv4 and the fact that implementing IPv6 as XML + would have exceeded the 1500 byte Ethernet MTU. + + + +Kennedy Informational [Page 2] + +RFC 3252 Binary Lexical Octet Ad-hoc Transport 1 April 2002 + + + All BLOAT implementations MUST use - and specify - the UTF-8 encoding + of RFC 2279 [RFC2279]. All BLOAT document/datagrams MUST be well- + formed and include the XMLDecl. + +2.1. IP Description + + A number of items have changed (for the better) from the original IP + specification. Bit-masks, where present have been converted into + human-readable values. IP addresses are listed in their dotted- + decimal notation [RFC1123]. Length and checksum values are present + as decimal integers. + + To calculate the length and checksum fields of the IP element, a + canonicalized form of the element MUST be used. The canonical form + SHALL have no whitespace (including newline characters) between + elements and only one space character between attributes. There + SHALL NOT be a space following the last attribute in an element. + + An iterative method SHOULD be used to calculate checksums, as the + length field will vary based on the size of the checksum. + + The payload element bears special attention. Due to the character + set restrictions of XML, the payload of IP datagrams (which MAY + contain arbitrary data) MUST be encoded for transport. This RFC + REQUIRES the contents of the payload to be encoded in the base-64 + encoding of RFC 2045 [RFC2045], but removes the requirement that the + encoded output MUST be wrapped on 76-character lines. + + + + + + + + + + + + + + + + + + + + + + + + +Kennedy Informational [Page 3] + +RFC 3252 Binary Lexical Octet Ad-hoc Transport 1 April 2002 + + +2.2. Example Datagram + + The following is an example IPoXML datagram with an empty payload: + + <?xml version="1.0" encoding="UTF-8"?> + <!DOCTYPE ip PUBLIC "-//IETF//DTD BLOAT 1.0 IP//EN" "bloat.dtd"> + <ip> + <header length="474"> + <version value="4"/> + <tos precedence="Routine" delay="Normal" throughput="Normal" + relibility="Normal" reserved="0"/> + <total.length value="461"/> + <id value="1"/> + <flags reserved="0" df="dont" mf="last"/> + <offset value="0"/> + <ttl value="255"/> + <protocol value="6"/> + <checksum value="8707"/> + <source address="10.0.0.22"/> + <destination address="10.0.0.1"/> + <options> + <end copied="0" class="0" number="0"/> + </options> + <padding pad="0"/> + </header> + <payload> + </payload> + </ip> + +3. TCPoXML + + This protocol MUST be implemented to be compliant with this RFC. The + DTD for this document type can be found in section 7.2. + +3.1. TCP Description + + A number of items have changed from the original TCP specification. + Bit-masks, where present have been converted into human-readable + values. Length and checksum and port values are present as decimal + integers. + + To calculate the length and checksum fields of the TCP element, a + canonicalized form of the element MUST be used as in section 2.1. + + An iterative method SHOULD be used to calculate checksums as in + section 2.1. + + The payload element MUST be encoded as in section 2.1. + + + +Kennedy Informational [Page 4] + +RFC 3252 Binary Lexical Octet Ad-hoc Transport 1 April 2002 + + + The TCP offset element was expanded to a maximum of 255 from 16 to + allow for the increased size of the header in XML. + + TCPoXML datagrams encapsulated by IPoXML MAY omit the <?xml?> header + as well as the <!DOCTYPE> declaration. + +3.2. Example Datagram + + The following is an example TCPoXML datagram with an empty payload: + + <?xml version="1.0" encoding="UTF-8"?> + <!DOCTYPE tcp PUBLIC "-//IETF//DTD BLOAT 1.0 TCP//EN" "bloat.dtd"> + <tcp> + <tcp.header> + <src port="31415"/> + <dest port="42424"/> + <sequence number="322622954"/> + <acknowledgement number="689715995"/> + <offset number=""/> + <reserved value="0"/> + <control syn="1" ack="1"/> + <window size="1"/> + <urgent pointer="0"/> + <checksum value="2988"/> + <tcp.options> + <tcp.end kind="0"/> + </tcp.options> + <padding pad="0"/> + </tcp.header> + <payload> + </payload> + </tcp> + +4. UDPoXML + + This protocol MUST be implemented to be compliant with this RFC. The + DTD for this document type can be found in section 7.3. + +4.1. UDP Description + + A number of items have changed from the original UDP specification. + Bit-masks, where present have been converted into human-readable + values. Length and checksum and port values are present as decimal + integers. + + + + + + + +Kennedy Informational [Page 5] + +RFC 3252 Binary Lexical Octet Ad-hoc Transport 1 April 2002 + + + To calculate the length and checksum fields of the UDP element, a + canonicalized form of the element MUST be used as in section 2.1. An + iterative method SHOULD be used to calculate checksums as in section + 2.1. + + The payload element MUST be encoded as in section 2.1. + + UDPoXML datagrams encapsulated by IPoXML MAY omit the <?xml?> header + as well as the <!DOCTYPE> declaration. + +4.2. Example Datagram + + The following is an example UDPoXML datagram with an empty payload: + + <?xml version="1.0" encoding="UTF-8"?> + <!DOCTYPE udp PUBLIC "-//IETF//DTD BLOAT 1.0 UDP//EN" "bloat.dtd"> + <udp> + <udp.header> + <src port="31415"/> + <dest port="42424"/> + <udp.length value="143"/> + <checksum value="2988"/> + </udp.header> + <payload> + </payload> + </udp> + +5. Network Transport + + This document provides for the transmission of BLOAT datagrams over + two common families of physical layer transport. Future RFCs will + address additional transports as routing vendors catch up to the + specification, and we begin to see BLOAT routed across the Internet + backbone. + +5.1. Ethernet + + BLOAT is encapsulated in Ethernet datagrams as in [RFC894] with the + exception that the type field of the Ethernet frame MUST contain the + value 0xBEEF. The first 5 octets of the Ethernet frame payload will + be 0x3c 3f 78 6d 6c ("<?xml".) + +5.2. IEEE 802 + + BLOAT is encapsulated in IEEE 802 Networks as in [RFC1042] except + that the protocol type code for IPoXML is 0xBEEF. + + + + + +Kennedy Informational [Page 6] + +RFC 3252 Binary Lexical Octet Ad-hoc Transport 1 April 2002 + + +6. Gatewaying over IP + + In order to facilitate the gradual introduction of BLOAT into the + public Internet, BLOAT MAY be encapsulated in IP as in [RFC2003] to + gateway between networks that run BLOAT natively on their LANs. + +7. DTDs + + The Transport DTDs (7.2. and 7.3.) build on the definitions in the + Network DTD (7.1.) + + The DTDs are referenced by their PubidLiteral and SystemLiteral (from + [XML]) although it is understood that most IPoXML implementations + will not need to pull down the DTD, as it will normally be embedded + in the implementation, and presents something of a catch-22 if you + need to load part of your network protocol over the network. + +7.1. IPoXML DTD + + <!-- + DTD for IP over XML. + Refer to this DTD as: + + <!DOCTYPE ip PUBLIC "-//IETF//DTD BLOAT 1.0 IP//EN" "bloat.dtd"> + --> + <!-- + DTD data types: + + Digits [0..9]+ + + Precedence "NetworkControl | InternetworkControl | + CRITIC | FlashOverride | Flash | Immediate | + Priority | Routine" + + IP4Addr "dotted-decimal" notation of [RFC1123] + + Class [0..3] + + Sec "Unclassified | Confidential | EFTO | MMMM | PROG | + Restricted | Secret | Top Secret | Reserved" + + Compartments [0..65535] + + Handling [0..65535] + + TCC [0..16777216] + + --> + + + +Kennedy Informational [Page 7] + +RFC 3252 Binary Lexical Octet Ad-hoc Transport 1 April 2002 + + + <!ENTITY % Digits "CDATA"> + <!ENTITY % Precedence "CDATA"> + <!ENTITY % IP4Addr "CDATA"> + <!ENTITY % Class "CDATA"> + <!ENTITY % Sec "CDATA"> + <!ENTITY % Compartments "CDATA"> + <!ENTITY % Handling "CDATA"> + <!ENTITY % TCC "CDATA"> + + <!ELEMENT ip (header, payload)> + + <!ELEMENT header (version, tos, total.length, id, flags, offset, ttl, + protocol, checksum, source, destination, options, + padding)> + <!-- length of header in 32-bit words --> + <!ATTLIST header + length %Digits; #REQUIRED> + + <!ELEMENT version EMPTY> + <!-- ip version. SHOULD be "4" --> + <!ATTLIST version + value %Digits; #REQUIRED> + + <!ELEMENT tos EMPTY> + <!ATTLIST tos + precedence %Precedence; #REQUIRED + delay (normal | low) #REQUIRED + throughput (normal | high) #REQUIRED + relibility (normal | high) #REQUIRED + reserved CDATA #FIXED "0"> + + <!ELEMENT total.length EMPTY> + <!-- + total length of datagram (header and payload) in octets, MUST be + less than 65,535 (and SHOULD be less than 1024 for IPoXML on local + ethernets). + --> + <!ATTLIST total.length + value %Digits; #REQUIRED> + + <!ELEMENT id EMPTY> + <!-- 0 <= id <= 65,535 --> + <!ATTLIST id + value %Digits; #REQUIRED> + + <!ELEMENT flags EMPTY> + <!-- df = don't fragment, mf = more fragments --> + <!ATTLIST flags + + + +Kennedy Informational [Page 8] + +RFC 3252 Binary Lexical Octet Ad-hoc Transport 1 April 2002 + + + reserved CDATA #FIXED "0" + df (may|dont) #REQUIRED + mf (last|more) #REQUIRED> + + <!ELEMENT offset EMPTY> + <!-- 0 <= offset <= 8192 measured in 8 octet (64-bit) chunks --> + <!ATTLIST offset + value %Digits; #REQUIRED> + + <!ELEMENT ttl EMPTY> + <!-- 0 <= ttl <= 255 --> + <!ATTLIST ttl + value %Digits; #REQUIRED> + + <!ELEMENT protocol EMPTY> + <!-- 0 <= protocol <= 255 (per IANA) --> + <!ATTLIST protocol + value %Digits; #REQUIRED> + + <!ELEMENT checksum EMPTY> + <!-- 0 <= checksum <= 65535 (over header only) --> + <!ATTLIST checksum + value %Digits; #REQUIRED> + + <!ELEMENT source EMPTY> + <!ATTLIST source + address %IP4Addr; #REQUIRED> + + <!ELEMENT destination EMPTY> + <!ATTLIST destination + address %IP4Addr; #REQUIRED> + + <!ELEMENT options ( end | noop | security | loose | strict | record + | stream | timestamp )*> + + <!ELEMENT end EMPTY> + <!ATTLIST end + copied (0|1) #REQUIRED + class CDATA #FIXED "0" + number CDATA #FIXED "0"> + + <!ELEMENT noop EMPTY> + <!ATTLIST noop + copied (0|1) #REQUIRED + class CDATA #FIXED "0" + number CDATA #FIXED "1"> + + <!ELEMENT security EMPTY> + + + +Kennedy Informational [Page 9] + +RFC 3252 Binary Lexical Octet Ad-hoc Transport 1 April 2002 + + + <!ATTLIST security + copied CDATA #FIXED "1" + class CDATA #FIXED "0" + number CDATA #FIXED "2" + length CDATA #FIXED "11" + security %Sec; #REQUIRED + compartments %Compartments; #REQUIRED + handling %Handling; #REQUIRED + tcc %TCC; #REQUIRED> + <!ELEMENT loose (hop)+> + <!ATTLIST loose + copied CDATA #FIXED "1" + class CDATA #FIXED "0" + number CDATA #FIXED "3" + length %Digits; #REQUIRED + pointer %Digits; #REQUIRED> + + <!ELEMENT hop EMPTY> + <!ATTLIST hop + address %IP4Addr; #REQUIRED> + + <!ELEMENT strict (hop)+> + <!ATTLIST strict + copied CDATA #FIXED "1" + class CDATA #FIXED "0" + number CDATA #FIXED "9" + length %Digits; #REQUIRED + pointer %Digits; #REQUIRED> + + <!ELEMENT record (hop)+> + <!ATTLIST record + copied CDATA #FIXED "0" + class CDATA #FIXED "0" + number CDATA #FIXED "7" + length %Digits; #REQUIRED + pointer %Digits; #REQUIRED> + + <!ELEMENT stream EMPTY> + <!-- 0 <= id <= 65,535 --> + <!ATTLIST stream + copied CDATA #FIXED "1" + class CDATA #FIXED "0" + number CDATA #FIXED "8" + length CDATA #FIXED "4" + id %Digits; #REQUIRED> + + <!ELEMENT timestamp (tstamp)+> + <!-- 0 <= oflw <=15 --> + + + +Kennedy Informational [Page 10] + +RFC 3252 Binary Lexical Octet Ad-hoc Transport 1 April 2002 + + + <!ATTLIST timestamp + copied CDATA #FIXED "0" + class CDATA #FIXED "2" + number CDATA #FIXED "4" + length %Digits; #REQUIRED + pointer %Digits; #REQUIRED + oflw %Digits; #REQUIRED + flag (0 | 1 | 3) #REQUIRED> + + <!ELEMENT tstamp EMPTY> + <!ATTLIST tstamp + time %Digits; #REQUIRED + address %IP4Addr; #IMPLIED> + <!-- + padding to bring header to 32-bit boundary. + pad MUST be "0"* + --> + <!ELEMENT padding EMPTY> + <!ATTLIST padding + pad CDATA #REQUIRED> + + <!-- payload MUST be encoded as base-64 [RFC2045], as modified + by section 2.1 of this RFC --> + <!ELEMENT payload (CDATA)> + +7.2. TCPoXML DTD + + <!-- + DTD for TCP over XML. + Refer to this DTD as: + + <!DOCTYPE tcp PUBLIC "-//IETF//DTD BLOAT 1.0 TCP//EN" "bloat.dtd"> + --> + + <!-- the pseudoheader is only included for checksum calculations --> + <!ELEMENT tcp (tcp.pseudoheader?, tcp.header, payload)> + + <!ELEMENT tcp.header (src, dest, sequence, acknowledgement, offset, + reserved, control, window, checksum, urgent, + tcp.options, padding)> + + <!ELEMENT src EMPTY> + <!-- 0 <= port <= 65,535 --> + <!ATTLIST src + port %Digits; #REQUIRED> + + <!ELEMENT dest EMPTY> + <!-- 0 <= port <= 65,535 --> + + + +Kennedy Informational [Page 11] + +RFC 3252 Binary Lexical Octet Ad-hoc Transport 1 April 2002 + + + <!ATTLIST dest + port %Digits; #REQUIRED> + + <!ELEMENT sequence EMPTY> + <!-- 0 <= number <= 4294967295 --> + <!ATTLIST sequence + number %Digits; #REQUIRED> + + <!ELEMENT acknowledgement EMPTY> + <!-- 0 <= number <= 4294967295 --> + <!ATTLIST acknowledgement + number %Digits; #REQUIRED> + + <!ELEMENT offset EMPTY> + <!-- 0 <= number <= 255 --> + <!ATTLIST offset + number %Digits; #REQUIRED> + + <!ELEMENT reserved EMPTY> + <!ATTLIST reserved + value CDATA #FIXED "0"> + + <!ELEMENT control EMPTY> + <!ATTLIST control + urg (0|1) #IMPLIED + ack (0|1) #IMPLIED + psh (0|1) #IMPLIED + rst (0|1) #IMPLIED + syn (0|1) #IMPLIED + fin (0|1) #IMPLIED> + + <!ELEMENT window EMPTY> + <!-- 0 <= size <= 65,535 --> + <!ATTLIST window + size %Digits; #REQUIRED> + + <!-- + checksum as in ip, but with + the following pseudo-header added into the tcp element: + --> + <!ELEMENT tcp.pseudoheader (source, destination, protocol, + tcp.length)> + + <!-- + tcp header + data length in octets. does not include the size of + + the pseudoheader. + --> + + + +Kennedy Informational [Page 12] + +RFC 3252 Binary Lexical Octet Ad-hoc Transport 1 April 2002 + + + <!ELEMENT tcp.length EMPTY> + <!ATTLIST tcp.length + value %Digits; #REQUIRED> + + <!ELEMENT urgent EMPTY> + <!-- 0 <= pointer <= 65,535 --> + <!ATTLIST urgent + pointer %Digits; #REQUIRED> + + <!ELEMENT tcp.options (tcp.end | tcp.noop | tcp.mss)+> + + <!ELEMENT tcp.end EMPTY> + <!ATTLIST tcp.end + kind CDATA #FIXED "0"> + + <!ELEMENT tcp.noop EMPTY> + <!ATTLIST tcp.noop + kind CDATA #FIXED "1"> + + <!ELEMENT tcp.mss EMPTY> + <!ATTLIST tcp.mss + kind CDATA #FIXED "2" + length CDATA #FIXED "4" + size %Digits; #REQUIRED> + +7.3. UDPoXML DTD + + <!-- + DTD for UDP over XML. + Refer to this DTD as: + + <!DOCTYPE udp PUBLIC "-//IETF//DTD BLOAT 1.0 UDP//EN" "bloat.dtd"> + --> + + <!ELEMENT udp (udp.pseudoheader?, udp.header, payload)> + + <!ELEMENT udp.header (src, dest, udp.length, checksum)> + + <!ELEMENT udp.pseudoheader (source, destination, protocol, + udp.length)> + + <!-- + udp header + data length in octets. does not include the size of + the pseudoheader. + --> + <!ELEMENT udp.length EMPTY> + <!ATTLIST udp.length + value %Digits; #REQUIRED> + + + +Kennedy Informational [Page 13] + +RFC 3252 Binary Lexical Octet Ad-hoc Transport 1 April 2002 + + +8. Security Considerations + + XML, as a subset of SGML, has the same security considerations as + specified in SGML Media Types [RFC1874]. Security considerations + that apply to IP, TCP and UDP also likely apply to BLOAT as it does + not attempt to correct for issues not related to message format. + +9. References + + [JABBER] Miller, J., "Jabber", draft-miller-jabber-00.txt, + February 2002. (Work in Progress) + + [RFC768] Postel, J., "User Datagram Protocol", STD 6, RFC 768, + August 1980. + + [RFC791] Postel, J., "Internet Protocol", STD 5, RFC 791, + September 1981. + + [RFC793] Postel, J., "Transmission Control Protocol", STD 7, RFC + 793, September 1981. + + [RFC894] Hornig, C., "Standard for the Transmission of IP + Datagrams over Ethernet Networks.", RFC 894, April 1984. + + [RFC1042] Postel, J. and J. Reynolds, "Standard for the + Transmission of IP Datagrams Over IEEE 802 Networks", STD + 43, RFC 1042, February 1988. + + [RFC1123] Braden, R., "Requirements for Internet Hosts - + Application and Support", RFC 1123, October 1989. + + [RFC1874] Levinson, E., "SGML Media Types", RFC 1874, December + 1995. + + [RFC2003] Perkins, C., "IP Encapsulation within IP", RFC 2003, + October 1996. + + [RFC2045] Freed, N. and N. Borenstein, "Multipurpose Internet Mail + Extensions (MIME) Part One: Format of Internet Message + Bodies", RFC 2045, November 1996. + + [RFC2119] Bradner, S., "Key words for use in RFCs to Indicate + Requirement Levels", BCP 14, RFC 2119, March 1997. + + [RFC2279] Yergeau, F., "UTF-8, a transformation format of ISO + 10646", RFC 2279, January 1998. + + + + + +Kennedy Informational [Page 14] + +RFC 3252 Binary Lexical Octet Ad-hoc Transport 1 April 2002 + + + [RFC2460] Deering, S. and R. Hinden, "Internet Protocol, Version 6 + (IPv6) Specification", RFC 2460, December 1998. + + [RFC3080] Rose, M., "The Blocks Extensible Exchange Protocol Core", + RFC 3080, March 2001. + + [SOAP] Box, D., Ehnebuske, D., Kakivaya, G., Layman, A., + Mendelsohn, N., Nielsen, H. F., Thatte, S. Winer, D., + "Simple Object Access Protocol (SOAP) 1.1" World Wide Web + Consortium Note, May 2000 http://www.w3.org/TR/SOAP/ + + [XML] Bray, T., Paoli, J., Sperberg-McQueen, C. M., "Extensible + Markup Language (XML)" World Wide Web Consortium + Recommendation REC- xml-19980210. + http://www.w3.org/TR/1998/REC-xml-19980210 + +10. Author's Address + + Hugh Kennedy + Mimezine + 1060 West Addison + Chicago, IL 60613 + USA + + EMail: kennedyh@engin.umich.edu + + + + + + + + + + + + + + + + + + + + + + + + + + +Kennedy Informational [Page 15] + +RFC 3252 Binary Lexical Octet Ad-hoc Transport 1 April 2002 + + +11. Full Copyright Statement + + Copyright (C) The Internet Society (2002). All Rights Reserved. + + This document and translations of it may be copied and furnished to + others, and derivative works that comment on or otherwise explain it + or assist in its implementation may be prepared, copied, published + and distributed, in whole or in part, without restriction of any + kind, provided that the above copyright notice and this paragraph are + included on all such copies and derivative works. However, this + document itself may not be modified in any way, such as by removing + the copyright notice or references to the Internet Society or other + Internet organizations, except as needed for the purpose of + developing Internet standards in which case the procedures for + copyrights defined in the Internet Standards process must be + followed, or as required to translate it into languages other than + English. + + The limited permissions granted above are perpetual and will not be + revoked by the Internet Society or its successors or assigns. + + This document and the information contained herein is provided on an + "AS IS" basis and THE INTERNET SOCIETY AND THE INTERNET ENGINEERING + TASK FORCE DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING + BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE INFORMATION + HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED WARRANTIES OF + MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. + +Acknowledgement + + Funding for the RFC Editor function is currently provided by the + Internet Society. + + + + + + + + + + + + + + + + + + + +Kennedy Informational [Page 16] + diff --git a/tests/auto/network/access/qhttp/trolltech b/tests/auto/network/access/qhttp/trolltech new file mode 100644 index 0000000000..c155360e8d --- /dev/null +++ b/tests/auto/network/access/qhttp/trolltech @@ -0,0 +1,8 @@ +<html> + <head> + <title>Test</title> + </head> + <body> + <h1>Test</h1> + </body> +</html> diff --git a/tests/auto/network/access/qhttp/tst_qhttp.cpp b/tests/auto/network/access/qhttp/tst_qhttp.cpp new file mode 100644 index 0000000000..8875232714 --- /dev/null +++ b/tests/auto/network/access/qhttp/tst_qhttp.cpp @@ -0,0 +1,1576 @@ +/**************************************************************************** +** +** 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 test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** 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. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + + +#include <QtTest/QtTest> + +#include <qbuffer.h> +#include <qcoreapplication.h> +#include <qfile.h> +#include <qhostinfo.h> +#include <qhttp.h> +#include <qlist.h> +#include <qpointer.h> +#include <qtcpsocket.h> +#include <qtcpserver.h> +#include <qauthenticator.h> +#include <QNetworkProxy> +#ifndef QT_NO_OPENSSL +# include <qsslsocket.h> +#endif + +#include "../../../network-settings.h" + +//TESTED_CLASS= +//TESTED_FILES= + +#ifdef Q_OS_SYMBIAN +// In Symbian OS test data is located in applications private dir +// And underlying Open C have application private dir in default search path +#define SRCDIR "" +#endif + +Q_DECLARE_METATYPE(QHttpResponseHeader) + +class tst_QHttp : public QObject +{ + Q_OBJECT + +public: + tst_QHttp(); + virtual ~tst_QHttp(); + + +public slots: + void initTestCase_data(); + void initTestCase(); + void cleanupTestCase(); + void init(); + void cleanup(); +private slots: + void constructing(); + void invalidRequests(); + void get_data(); + void get(); + void head_data(); + void head(); + void post_data(); + void post(); + void request_data(); + void request(); + void authorization_data(); + void authorization(); + void proxy_data(); + void proxy(); + void proxy2(); + void proxy3(); + void postAuthNtlm(); + void proxyAndSsl(); + void cachingProxyAndSsl(); + void reconnect(); + void setSocket(); + void unexpectedRemoteClose(); + void pctEncodedPath(); + void caseInsensitiveKeys(); + void emptyBodyInReply(); + void abortInReadyRead(); + void abortInResponseHeaderReceived(); + void nestedEventLoop(); + void connectionClose(); + +protected slots: + void stateChanged( int ); + void responseHeaderReceived( const QHttpResponseHeader & ); + void readyRead( const QHttpResponseHeader& ); + void dataSendProgress( int, int ); + void dataReadProgress( int , int ); + + void requestStarted( int ); + void requestFinished( int, bool ); + void done( bool ); + + void reconnect_state(int state); + void proxy2_slot(); + void nestedEventLoop_slot(int id); + + void abortSender(); + void proxyAuthenticationRequired(const QNetworkProxy &, QAuthenticator *auth); + +private: + QHttp *newHttp(bool withAuth = false); + void addRequest( QHttpRequestHeader, int ); + bool headerAreEqual( const QHttpHeader&, const QHttpHeader& ); + + QHttp *http; + + struct RequestResult + { + QHttpRequestHeader req; + QHttpResponseHeader resp; + int success; + }; + QMap< int, RequestResult > resultMap; + typedef QMap<int,RequestResult>::Iterator ResMapIt; + QList<int> ids; // helper to make sure that all expected signals are emitted + + int current_id; + int cur_state; + int done_success; + + QByteArray readyRead_ba; + + int bytesTotalSend; + int bytesDoneSend; + int bytesTotalRead; + int bytesDoneRead; + + int getId; + int headId; + int postId; + + int reconnect_state_connect_count; + + bool connectionWithAuth; + bool proxyAuthCalled; +}; + +class ClosingServer: public QTcpServer +{ + Q_OBJECT +public: + ClosingServer() + { + connect(this, SIGNAL(newConnection()), SLOT(handleConnection())); + listen(); + } + +public slots: + void handleConnection() + { + delete nextPendingConnection(); + } +}; + +//#define DUMP_SIGNALS + +const int bytesTotal_init = -10; +const int bytesDone_init = -10; + +tst_QHttp::tst_QHttp() +{ + Q_SET_DEFAULT_IAP +} + +tst_QHttp::~tst_QHttp() +{ +} + +void tst_QHttp::initTestCase_data() +{ + QTest::addColumn<bool>("setProxy"); + QTest::addColumn<int>("proxyType"); + + QTest::newRow("WithoutProxy") << false << 0; + QTest::newRow("WithSocks5Proxy") << true << int(QNetworkProxy::Socks5Proxy); +} + +void tst_QHttp::initTestCase() +{ +} + +void tst_QHttp::cleanupTestCase() +{ +} + +void tst_QHttp::init() +{ + QFETCH_GLOBAL(bool, setProxy); + if (setProxy) { + QFETCH_GLOBAL(int, proxyType); + if (proxyType == QNetworkProxy::Socks5Proxy) { + QNetworkProxy::setApplicationProxy(QNetworkProxy(QNetworkProxy::Socks5Proxy, QtNetworkSettings::serverName(), 1080)); + } + } + + http = 0; + + resultMap.clear(); + ids.clear(); + + current_id = 0; + cur_state = QHttp::Unconnected; + done_success = -1; + + readyRead_ba = QByteArray(); + + getId = -1; + headId = -1; + postId = -1; +} + +void tst_QHttp::cleanup() +{ + delete http; + http = 0; + + QCoreApplication::processEvents(); + + QFETCH_GLOBAL(bool, setProxy); + if (setProxy) { + QNetworkProxy::setApplicationProxy(QNetworkProxy::DefaultProxy); + } +} + +void tst_QHttp::constructing() +{ + //QHeader + { + QHttpRequestHeader header; + header.addValue("key1", "val1"); + header.addValue("key2", "val2"); + header.addValue("key1", "val3"); + QCOMPARE(header.values().size(), 3); + QCOMPARE(header.allValues("key1").size(), 2); + QVERIFY(header.hasKey("key2")); + QCOMPARE(header.keys().count(), 2); + + } + + { + QHttpResponseHeader header(200); + } +} + +void tst_QHttp::invalidRequests() +{ + QHttp http; + http.setHost("localhost"); // we will not actually connect + + QTest::ignoreMessage(QtWarningMsg, "QHttp: empty path requested is invalid -- using '/'"); + http.get(QString()); + + QTest::ignoreMessage(QtWarningMsg, "QHttp: empty path requested is invalid -- using '/'"); + http.head(QString()); + + QTest::ignoreMessage(QtWarningMsg, "QHttp: empty path requested is invalid -- using '/'"); + http.post(QString(), QByteArray()); + + QTest::ignoreMessage(QtWarningMsg, "QHttp: empty path requested is invalid -- using '/'"); + http.request(QHttpRequestHeader("PROPFIND", QString())); +} + +void tst_QHttp::get_data() +{ + QTest::addColumn<QString>("host"); + QTest::addColumn<uint>("port"); + QTest::addColumn<QString>("path"); + QTest::addColumn<int>("success"); + QTest::addColumn<int>("statusCode"); + QTest::addColumn<QByteArray>("res"); + QTest::addColumn<bool>("useIODevice"); + + // ### move this into external testdata + QFile file( SRCDIR "rfc3252.txt" ); + QVERIFY( file.open( QIODevice::ReadOnly ) ); + QByteArray rfc3252 = file.readAll(); + file.close(); + + file.setFileName( SRCDIR "trolltech" ); + QVERIFY( file.open( QIODevice::ReadOnly ) ); + QByteArray trolltech = file.readAll(); + file.close(); + + // test the two get() modes in one routine + for ( int i=0; i<2; i++ ) { + QTest::newRow(QString("path_01_%1").arg(i).toLatin1()) << QtNetworkSettings::serverName() << 80u + << QString("/qtest/rfc3252.txt") << 1 << 200 << rfc3252 << (bool)(i==1); + QTest::newRow( QString("path_02_%1").arg(i).toLatin1() ) << QString("www.ietf.org") << 80u + << QString("/rfc/rfc3252.txt") << 1 << 200 << rfc3252 << (bool)(i==1); + + QTest::newRow( QString("uri_01_%1").arg(i).toLatin1() ) << QtNetworkSettings::serverName() << 80u + << QString("http://" + QtNetworkSettings::serverName() + "/qtest/rfc3252.txt") << 1 << 200 << rfc3252 << (bool)(i==1); + QTest::newRow( QString("uri_02_%1").arg(i).toLatin1() ) << "www.ietf.org" << 80u + << QString("http://www.ietf.org/rfc/rfc3252.txt") << 1 << 200 << rfc3252 << (bool)(i==1); + + QTest::newRow( QString("fail_01_%1").arg(i).toLatin1() ) << QString("this-host-will-not-exist.") << 80u + << QString("/qtest/rfc3252.txt") << 0 << 0 << QByteArray() << (bool)(i==1); + + QTest::newRow( QString("failprot_01_%1").arg(i).toLatin1() ) << QtNetworkSettings::serverName() << 80u + << QString("/t") << 1 << 404 << QByteArray() << (bool)(i==1); + QTest::newRow( QString("failprot_02_%1").arg(i).toLatin1() ) << QtNetworkSettings::serverName() << 80u + << QString("qtest/rfc3252.txt") << 1 << 400 << QByteArray() << (bool)(i==1); + + // qt.nokia.com/doc uses transfer-encoding=chunked + /* qt.nokia.com/doc no longer seams to be using chuncked encodig. + QTest::newRow( QString("chunked_01_%1").arg(i).toLatin1() ) << QString("test.troll.no") << 80u + << QString("/") << 1 << 200 << trolltech << (bool)(i==1); + */ + QTest::newRow( QString("chunked_02_%1").arg(i).toLatin1() ) << QtNetworkSettings::serverName() << 80u + << QString("/qtest/cgi-bin/rfc.cgi") << 1 << 200 << rfc3252 << (bool)(i==1); + } +} + +void tst_QHttp::get() +{ + // for the overload that takes a QIODevice + QByteArray buf_ba; + QBuffer buf( &buf_ba ); + + QFETCH( QString, host ); + QFETCH( uint, port ); + QFETCH( QString, path ); + QFETCH( bool, useIODevice ); + + http = newHttp(); + QCOMPARE( http->currentId(), 0 ); + QCOMPARE( (int)http->state(), (int)QHttp::Unconnected ); + + addRequest( QHttpRequestHeader(), http->setHost( host, port ) ); + if ( useIODevice ) { + buf.open( QIODevice::WriteOnly ); + getId = http->get( path, &buf ); + } else { + getId = http->get( path ); + } + addRequest( QHttpRequestHeader(), getId ); + + QTestEventLoop::instance().enterLoop( 50 ); + + if ( QTestEventLoop::instance().timeout() ) + QFAIL( "Network operation timed out" ); + + ResMapIt res = resultMap.find( getId ); + QVERIFY( res != resultMap.end() ); + if ( res.value().success!=1 && host=="www.ietf.org" ) { + // The nightly tests fail from time to time. In order to make them more + // stable, add some debug output that might help locate the problem (I + // can't reproduce the problem in the non-nightly builds). + qDebug( "Error %d: %s", http->error(), http->errorString().toLatin1().constData() ); + } + QTEST( res.value().success, "success" ); + if ( res.value().success ) { + QTEST( res.value().resp.statusCode(), "statusCode" ); + + QFETCH( QByteArray, res ); + if ( res.count() > 0 ) { + if ( useIODevice ) { + QCOMPARE(buf_ba, res); + if ( bytesDoneRead != bytesDone_init ) + QVERIFY( (int)buf_ba.size() == bytesDoneRead ); + } else { + QCOMPARE(readyRead_ba, res); + if ( bytesDoneRead != bytesDone_init ) + QVERIFY( (int)readyRead_ba.size() == bytesDoneRead ); + } + } + QVERIFY( bytesTotalRead != bytesTotal_init ); + if ( bytesTotalRead > 0 ) + QVERIFY( bytesDoneRead == bytesTotalRead ); + } else { + QVERIFY( !res.value().resp.isValid() ); + } +} + +void tst_QHttp::head_data() +{ + QTest::addColumn<QString>("host"); + QTest::addColumn<uint>("port"); + QTest::addColumn<QString>("path"); + QTest::addColumn<int>("success"); + QTest::addColumn<int>("statusCode"); + QTest::addColumn<uint>("contentLength"); + + QTest::newRow( "path_01" ) << QtNetworkSettings::serverName() << 80u + << QString("/qtest/rfc3252.txt") << 1 << 200 << 25962u; + + QTest::newRow( "path_02" ) << QString("www.ietf.org") << 80u + << QString("/rfc/rfc3252.txt") << 1 << 200 << 25962u; + + QTest::newRow( "uri_01" ) << QtNetworkSettings::serverName() << 80u + << QString("http://" + QtNetworkSettings::serverName() + "/qtest/rfc3252.txt") << 1 << 200 << 25962u; + + QTest::newRow( "uri_02" ) << QString("www.ietf.org") << 80u + << QString("http://www.ietf.org/rfc/rfc3252.txt") << 1 << 200 << 25962u; + + QTest::newRow( "fail_01" ) << QString("this-host-will-not-exist.") << 80u + << QString("/qtest/rfc3252.txt") << 0 << 0 << 0u; + + QTest::newRow( "failprot_01" ) << QtNetworkSettings::serverName() << 80u + << QString("/t") << 1 << 404 << 0u; + + QTest::newRow( "failprot_02" ) << QtNetworkSettings::serverName() << 80u + << QString("qtest/rfc3252.txt") << 1 << 400 << 0u; + + /* qt.nokia.com/doc no longer seams to be using chuncked encodig. + QTest::newRow( "chunked_01" ) << QString("qt.nokia.com/doc") << 80u + << QString("/index.html") << 1 << 200 << 0u; + */ + QTest::newRow( "chunked_02" ) << QtNetworkSettings::serverName() << 80u + << QString("/qtest/cgi-bin/rfc.cgi") << 1 << 200 << 0u; +} + +void tst_QHttp::head() +{ + QFETCH( QString, host ); + QFETCH( uint, port ); + QFETCH( QString, path ); + + http = newHttp(); + QCOMPARE( http->currentId(), 0 ); + QCOMPARE( (int)http->state(), (int)QHttp::Unconnected ); + + addRequest( QHttpRequestHeader(), http->setHost( host, port ) ); + headId = http->head( path ); + addRequest( QHttpRequestHeader(), headId ); + + QTestEventLoop::instance().enterLoop( 30 ); + if ( QTestEventLoop::instance().timeout() ) + QFAIL( "Network operation timed out" ); + + ResMapIt res = resultMap.find( headId ); + QVERIFY( res != resultMap.end() ); + if ( res.value().success!=1 && host=="www.ietf.org" ) { + // The nightly tests fail from time to time. In order to make them more + // stable, add some debug output that might help locate the problem (I + // can't reproduce the problem in the non-nightly builds). + qDebug( "Error %d: %s", http->error(), http->errorString().toLatin1().constData() ); + } + QTEST( res.value().success, "success" ); + if ( res.value().success ) { + QTEST( res.value().resp.statusCode(), "statusCode" ); + QTEST( res.value().resp.contentLength(), "contentLength" ); + + QCOMPARE( (uint)readyRead_ba.size(), 0u ); + QVERIFY( bytesTotalRead == bytesTotal_init ); + QVERIFY( bytesDoneRead == bytesDone_init ); + } else { + QVERIFY( !res.value().resp.isValid() ); + } +} + +void tst_QHttp::post_data() +{ + QTest::addColumn<QString>("source"); + QTest::addColumn<bool>("useIODevice"); + QTest::addColumn<bool>("useProxy"); + QTest::addColumn<QString>("host"); + QTest::addColumn<int>("port"); + QTest::addColumn<bool>("ssl"); + QTest::addColumn<QString>("path"); + QTest::addColumn<QByteArray>("result"); + + QByteArray md5sum; + md5sum = "d41d8cd98f00b204e9800998ecf8427e"; + QTest::newRow("empty-data") + << QString() << false << false + << QtNetworkSettings::serverName() << 80 << false << "/qtest/cgi-bin/md5sum.cgi" << md5sum; + QTest::newRow("empty-device") + << QString() << true << false + << QtNetworkSettings::serverName() << 80 << false << "/qtest/cgi-bin/md5sum.cgi" << md5sum; + QTest::newRow("proxy-empty-data") + << QString() << false << true + << QtNetworkSettings::serverName() << 80 << false << "/qtest/cgi-bin/md5sum.cgi" << md5sum; + + md5sum = "b3e32ac459b99d3f59318f3ac31e4bee"; + QTest::newRow("data") << "rfc3252.txt" << false << false + << QtNetworkSettings::serverName() << 80 << false << "/qtest/cgi-bin/md5sum.cgi" + << md5sum; + QTest::newRow("device") << "rfc3252.txt" << true << false + << QtNetworkSettings::serverName() << 80 << false << "/qtest/cgi-bin/md5sum.cgi" + << md5sum; + QTest::newRow("proxy-data") << "rfc3252.txt" << false << true + << QtNetworkSettings::serverName() << 80 << false << "/qtest/cgi-bin/md5sum.cgi" + << md5sum; + +#ifndef QT_NO_OPENSSL + md5sum = "d41d8cd98f00b204e9800998ecf8427e"; + QTest::newRow("empty-data-ssl") + << QString() << false << false + << QtNetworkSettings::serverName() << 443 << true << "/qtest/cgi-bin/md5sum.cgi" << md5sum; + QTest::newRow("empty-device-ssl") + << QString() << true << false + << QtNetworkSettings::serverName() << 443 << true << "/qtest/cgi-bin/md5sum.cgi" << md5sum; + QTest::newRow("proxy-empty-data-ssl") + << QString() << false << true + << QtNetworkSettings::serverName() << 443 << true << "/qtest/cgi-bin/md5sum.cgi" << md5sum; + md5sum = "b3e32ac459b99d3f59318f3ac31e4bee"; + QTest::newRow("data-ssl") << "rfc3252.txt" << false << false + << QtNetworkSettings::serverName() << 443 << true << "/qtest/cgi-bin/md5sum.cgi" + << md5sum; + QTest::newRow("device-ssl") << "rfc3252.txt" << true << false + << QtNetworkSettings::serverName() << 443 << true << "/qtest/cgi-bin/md5sum.cgi" + << md5sum; + QTest::newRow("proxy-data-ssl") << "rfc3252.txt" << false << true + << QtNetworkSettings::serverName() << 443 << true << "/qtest/cgi-bin/md5sum.cgi" + << md5sum; +#endif + + // the following test won't work. See task 185996 +/* + QTest::newRow("proxy-device") << "rfc3252.txt" << true << true + << QtNetworkSettings::serverName() << 80 << "/qtest/cgi-bin/md5sum.cgi" + << md5sum; +*/ +} + +void tst_QHttp::post() +{ + QFETCH(QString, source); + QFETCH(bool, useIODevice); + QFETCH(bool, useProxy); + QFETCH(QString, host); + QFETCH(int, port); + QFETCH(bool, ssl); + QFETCH(QString, path); + + http = newHttp(useProxy); +#ifndef QT_NO_OPENSSL + QObject::connect(http, SIGNAL(sslErrors(const QList<QSslError> &)), + http, SLOT(ignoreSslErrors())); +#endif + QCOMPARE(http->currentId(), 0); + QCOMPARE((int)http->state(), (int)QHttp::Unconnected); + if (useProxy) + addRequest(QHttpRequestHeader(), http->setProxy(QtNetworkSettings::serverName(), 3129)); + addRequest(QHttpRequestHeader(), http->setHost(host, (ssl ? QHttp::ConnectionModeHttps : QHttp::ConnectionModeHttp), port)); + + // add the POST request + QFile file(SRCDIR + source); + QBuffer emptyBuffer; + QIODevice *dev; + if (!source.isEmpty()) { + QVERIFY(file.open(QIODevice::ReadOnly)); + dev = &file; + } else { + emptyBuffer.open(QIODevice::ReadOnly); + dev = &emptyBuffer; + } + + if (useIODevice) + postId = http->post(path, dev); + else + postId = http->post(path, dev->readAll()); + addRequest(QHttpRequestHeader(), postId); + + // run request + connect(http, SIGNAL(proxyAuthenticationRequired(QNetworkProxy,QAuthenticator*)), + SLOT(proxyAuthenticationRequired(QNetworkProxy,QAuthenticator*))); + QTestEventLoop::instance().enterLoop( 30 ); + + if ( QTestEventLoop::instance().timeout() ) + QFAIL( "Network operation timed out" ); + + ResMapIt res = resultMap.find(postId); + QVERIFY(res != resultMap.end()); + QVERIFY(res.value().success); + QCOMPARE(res.value().resp.statusCode(), 200); + QTEST(readyRead_ba.trimmed(), "result"); +} + +void tst_QHttp::request_data() +{ + QTest::addColumn<QString>("source"); + QTest::addColumn<bool>("useIODevice"); + QTest::addColumn<bool>("useProxy"); + QTest::addColumn<QString>("host"); + QTest::addColumn<int>("port"); + QTest::addColumn<QString>("method"); + QTest::addColumn<QString>("path"); + QTest::addColumn<QByteArray>("result"); + + QFile source(SRCDIR "rfc3252.txt"); + if (!source.open(QIODevice::ReadOnly)) + return; + + QByteArray contents = source.readAll(); + QByteArray md5sum = QCryptographicHash::hash(contents, QCryptographicHash::Md5).toHex() + '\n'; + QByteArray emptyMd5sum = "d41d8cd98f00b204e9800998ecf8427e\n"; + + QTest::newRow("head") << QString() << false << false << QtNetworkSettings::serverName() << 80 + << "HEAD" << "/qtest/rfc3252.txt" + << QByteArray(); + QTest::newRow("get") << QString() << false << false << QtNetworkSettings::serverName() << 80 + << "GET" << "/qtest/rfc3252.txt" + << contents; + QTest::newRow("post-empty-data") << QString() << false << false + << QtNetworkSettings::serverName() << 80 << "POST" << "/qtest/cgi-bin/md5sum.cgi" + << emptyMd5sum; + QTest::newRow("post-empty-device") << QString() << true << false + << QtNetworkSettings::serverName() << 80 << "POST" << "/qtest/cgi-bin/md5sum.cgi" + << emptyMd5sum; + QTest::newRow("post-data") << "rfc3252.txt" << false << false + << QtNetworkSettings::serverName() << 80 << "POST" << "/qtest/cgi-bin/md5sum.cgi" + << md5sum; + QTest::newRow("post-device") << "rfc3252.txt" << true << false + << QtNetworkSettings::serverName() << 80 << "POST" << "/qtest/cgi-bin/md5sum.cgi" + << md5sum; + + QTest::newRow("proxy-head") << QString() << false << true << QtNetworkSettings::serverName() << 80 + << "HEAD" << "/qtest/rfc3252.txt" + << QByteArray(); + QTest::newRow("proxy-get") << QString() << false << true << QtNetworkSettings::serverName() << 80 + << "GET" << "/qtest/rfc3252.txt" + << contents; + QTest::newRow("proxy-post-empty-data") << QString() << false << true + << QtNetworkSettings::serverName() << 80 << "POST" << "/qtest/cgi-bin/md5sum.cgi" + << emptyMd5sum; + QTest::newRow("proxy-post-data") << "rfc3252.txt" << false << true + << QtNetworkSettings::serverName() << 80 << "POST" << "/qtest/cgi-bin/md5sum.cgi" + << md5sum; + // the following test won't work. See task 185996 +/* + QTest::newRow("proxy-post-device") << "rfc3252.txt" << true << true + << QtNetworkSettings::serverName() << 80 << "POST" << "/qtest/cgi-bin/md5sum.cgi" + << md5sum; +*/ +} + +void tst_QHttp::request() +{ + QFETCH(QString, source); + QFETCH(bool, useIODevice); + QFETCH(bool, useProxy); + QFETCH(QString, host); + QFETCH(int, port); + QFETCH(QString, method); + QFETCH(QString, path); + + http = newHttp(useProxy); + QCOMPARE(http->currentId(), 0); + QCOMPARE((int)http->state(), (int)QHttp::Unconnected); + if (useProxy) + addRequest(QHttpRequestHeader(), http->setProxy(QtNetworkSettings::serverName(), 3129)); + addRequest(QHttpRequestHeader(), http->setHost(host, port)); + + QFile file(SRCDIR + source); + QBuffer emptyBuffer; + QIODevice *dev; + if (!source.isEmpty()) { + QVERIFY(file.open(QIODevice::ReadOnly)); + dev = &file; + } else { + emptyBuffer.open(QIODevice::ReadOnly); + dev = &emptyBuffer; + } + + // prepare the request + QHttpRequestHeader request; + request.setRequest(method, path, 1,1); + request.addValue("Host", host); + int *theId; + + if (method == "POST") + theId = &postId; + else if (method == "GET") + theId = &getId; + else if (method == "HEAD") + theId = &headId; + else + QFAIL("You're lazy! Please implement your test!"); + + // now send the request + if (useIODevice) + *theId = http->request(request, dev); + else + *theId = http->request(request, dev->readAll()); + addRequest(QHttpRequestHeader(), *theId); + + // run request + connect(http, SIGNAL(proxyAuthenticationRequired(QNetworkProxy,QAuthenticator*)), + SLOT(proxyAuthenticationRequired(QNetworkProxy,QAuthenticator*))); + QTestEventLoop::instance().enterLoop( 30 ); + + if ( QTestEventLoop::instance().timeout() ) + QFAIL( "Network operation timed out" ); + + ResMapIt res = resultMap.find(*theId); + QVERIFY(res != resultMap.end()); + QVERIFY(res.value().success); + QCOMPARE(res.value().resp.statusCode(), 200); + QTEST(readyRead_ba, "result"); +} + +void tst_QHttp::authorization_data() +{ + QTest::addColumn<QString>("host"); + QTest::addColumn<QString>("path"); + QTest::addColumn<QString>("user"); + QTest::addColumn<QString>("pass"); + QTest::addColumn<int>("result"); + + QTest::newRow("correct password") << QtNetworkSettings::serverName() + << QString::fromLatin1("/qtest/rfcs-auth/index.html") + << QString::fromLatin1("httptest") + << QString::fromLatin1("httptest") + << 200; + + QTest::newRow("no password") << QtNetworkSettings::serverName() + << QString::fromLatin1("/qtest/rfcs-auth/index.html") + << QString::fromLatin1("") + << QString::fromLatin1("") + << 401; + + QTest::newRow("wrong password") << QtNetworkSettings::serverName() + << QString::fromLatin1("/qtest/rfcs-auth/index.html") + << QString::fromLatin1("maliciu0s") + << QString::fromLatin1("h4X0r") + << 401; +} + +void tst_QHttp::authorization() +{ + QFETCH(QString, host); + QFETCH(QString, path); + QFETCH(QString, user); + QFETCH(QString, pass); + QFETCH(int, result); + + QEventLoop loop; + + QHttp http; + connect(&http, SIGNAL(done(bool)), &loop, SLOT(quit())); + + if (!user.isEmpty()) + http.setUser(user, pass); + http.setHost(host); + int id = http.get(path); + Q_UNUSED(id); + + QTimer::singleShot(5000, &loop, SLOT(quit())); + loop.exec(); + + QCOMPARE(http.lastResponse().statusCode(), result); +} + +void tst_QHttp::proxy_data() +{ + QTest::addColumn<QString>("proxyhost"); + QTest::addColumn<int>("port"); + QTest::addColumn<QString>("host"); + QTest::addColumn<QString>("path"); + QTest::addColumn<QString>("proxyuser"); + QTest::addColumn<QString>("proxypass"); + + QTest::newRow("qt-test-server") << QtNetworkSettings::serverName() << 3128 + << QString::fromLatin1("qt.nokia.com") << QString::fromLatin1("/") + << QString::fromLatin1("") << QString::fromLatin1(""); + QTest::newRow("qt-test-server pct") << QtNetworkSettings::serverName() << 3128 + << QString::fromLatin1("qt.nokia.com") << QString::fromLatin1("/%64eveloper") + << QString::fromLatin1("") << QString::fromLatin1(""); + QTest::newRow("qt-test-server-basic") << QtNetworkSettings::serverName() << 3129 + << QString::fromLatin1("qt.nokia.com") << QString::fromLatin1("/") + << QString::fromLatin1("qsockstest") << QString::fromLatin1("password"); + +#if 0 + // NTLM requires sending the same request three times for it to work + // the tst_QHttp class is too strict to handle the byte counts sent by dataSendProgress + // So don't run this test: + QTest::newRow("qt-test-server-ntlm") << QtNetworkSettings::serverName() << 3130 + << QString::fromLatin1("qt.nokia.com") << QString::fromLatin1("/") + << QString::fromLatin1("qsockstest") << QString::fromLatin1("password"); +#endif +} + +void tst_QHttp::proxy() +{ + QFETCH(QString, proxyhost); + QFETCH(int, port); + QFETCH(QString, host); + QFETCH(QString, path); + QFETCH(QString, proxyuser); + QFETCH(QString, proxypass); + + http = newHttp(!proxyuser.isEmpty()); + + QCOMPARE(http->currentId(), 0); + QCOMPARE((int)http->state(), (int)QHttp::Unconnected); + + addRequest(QHttpRequestHeader(), http->setProxy(proxyhost, port, proxyuser, proxypass)); + addRequest(QHttpRequestHeader(), http->setHost(host)); + getId = http->get(path); + addRequest(QHttpRequestHeader(), getId); + + QTestEventLoop::instance().enterLoop(30); + if (QTestEventLoop::instance().timeout()) + QFAIL("Network operation timed out"); + + ResMapIt res = resultMap.find(getId); + QVERIFY(res != resultMap.end()); + QVERIFY(res.value().success); + QCOMPARE(res.value().resp.statusCode(), 200); +} + +void tst_QHttp::proxy2() +{ + QFETCH_GLOBAL(bool, setProxy); + if (setProxy) + return; + + readyRead_ba.clear(); + + QHttp http; + http.setProxy(QtNetworkSettings::serverName(), 3128); + http.setHost(QtNetworkSettings::serverName()); + http.get("/index.html"); + http.get("/index.html"); + + connect(&http, SIGNAL(requestFinished(int, bool)), + this, SLOT(proxy2_slot())); + QTestEventLoop::instance().enterLoop(30); + QVERIFY(!QTestEventLoop::instance().timeout()); + + QCOMPARE(readyRead_ba.count("Welcome to qt-test-server"), 2); + + readyRead_ba.clear(); +} + +void tst_QHttp::proxy2_slot() +{ + QHttp *http = static_cast<QHttp *>(sender()); + readyRead_ba.append(http->readAll()); + if (!http->hasPendingRequests()) + QTestEventLoop::instance().exitLoop(); +} + +void tst_QHttp::proxy3() +{ + QFETCH_GLOBAL(bool, setProxy); + if (setProxy) + return; + + readyRead_ba.clear(); + + QTcpSocket socket; + socket.setProxy(QNetworkProxy(QNetworkProxy::HttpProxy, QtNetworkSettings::serverName(), 3128)); + + QHttp http; + http.setSocket(&socket); + http.setHost(QtNetworkSettings::serverName()); + http.get("/index.html"); + http.get("/index.html"); + + connect(&http, SIGNAL(requestFinished(int, bool)), + this, SLOT(proxy2_slot())); + QTestEventLoop::instance().enterLoop(30); + QVERIFY(!QTestEventLoop::instance().timeout()); + + QCOMPARE(readyRead_ba.count("Welcome to qt-test-server"), 2); + + readyRead_ba.clear(); +} + +// test QHttp::currentId() and QHttp::currentRequest() +#define CURRENTREQUEST_TEST \ + { \ + ResMapIt res = resultMap.find( http->currentId() ); \ + QVERIFY( res != resultMap.end() ); \ + if ( http->currentId() == getId ) { \ + QCOMPARE( http->currentRequest().method(), QString("GET") ); \ + } else if ( http->currentId() == headId ) { \ + QCOMPARE( http->currentRequest().method(), QString("HEAD") ); \ + } else if ( http->currentId() == postId ) { \ + QCOMPARE( http->currentRequest().method(), QString("POST") ); \ + } else { \ + QVERIFY( headerAreEqual( http->currentRequest(), res.value().req ) ); \ + } \ + } + +void tst_QHttp::requestStarted( int id ) +{ +#if defined( DUMP_SIGNALS ) + qDebug( "%d:requestStarted( %d )", http->currentId(), id ); +#endif + // make sure that the requestStarted and requestFinished are nested correctly + QVERIFY( current_id == 0 ); + current_id = id; + + QVERIFY( !ids.isEmpty() ); + QVERIFY( ids.first() == id ); + if ( ids.count() > 1 ) { + QVERIFY( http->hasPendingRequests() ); + } else { + QVERIFY( !http->hasPendingRequests() ); + } + + QVERIFY( http->currentId() == id ); + QVERIFY( cur_state == http->state() ); + + + + + CURRENTREQUEST_TEST; + + QVERIFY( http->error() == QHttp::NoError ); +} + +void tst_QHttp::requestFinished( int id, bool error ) +{ +#if defined( DUMP_SIGNALS ) + qDebug( "%d:requestFinished( %d, %d ) -- errorString: '%s'", + http->currentId(), id, (int)error, http->errorString().toAscii().data() ); +#endif + // make sure that the requestStarted and requestFinished are nested correctly + QVERIFY( current_id == id ); + current_id = 0; + + QVERIFY( !ids.isEmpty() ); + QVERIFY( ids.first() == id ); + if ( ids.count() > 1 ) { + QVERIFY( http->hasPendingRequests() ); + } else { + QVERIFY( !http->hasPendingRequests() ); + } + + if ( error ) { + QVERIFY( http->error() != QHttp::NoError ); + ids.clear(); + } else { + QVERIFY( http->error() == QHttp::NoError ); + ids.pop_front(); + } + + QVERIFY( http->currentId() == id ); + QVERIFY( cur_state == http->state() ); + CURRENTREQUEST_TEST; + + ResMapIt res = resultMap.find( http->currentId() ); + QVERIFY( res != resultMap.end() ); + QVERIFY( res.value().success == -1 ); + if ( error ) + res.value().success = 0; + else + res.value().success = 1; +} + +void tst_QHttp::done( bool error ) +{ +#if defined( DUMP_SIGNALS ) + qDebug( "%d:done( %d )", http->currentId(), (int)error ); +#endif + QVERIFY( http->currentId() == 0 ); + QVERIFY( current_id == 0 ); + QVERIFY( ids.isEmpty() ); + QVERIFY( cur_state == http->state() ); + QVERIFY( !http->hasPendingRequests() ); + + QVERIFY( done_success == -1 ); + if ( error ) { + QVERIFY( http->error() != QHttp::NoError ); + done_success = 0; + } else { + QVERIFY( http->error() == QHttp::NoError ); + done_success = 1; + } + QTestEventLoop::instance().exitLoop(); +} + +void tst_QHttp::stateChanged( int state ) +{ +#if defined( DUMP_SIGNALS ) + qDebug( "%d: stateChanged( %d )", http->currentId(), state ); +#endif + QCOMPARE( http->currentId(), current_id ); + if ( ids.count() > 0 ) + CURRENTREQUEST_TEST; + + QVERIFY( state != cur_state ); + QVERIFY( state == http->state() ); + if ( state != QHttp::Unconnected && !connectionWithAuth ) { + // make sure that the states are always emitted in the right order (for + // this, we assume an ordering on the enum values, which they have at + // the moment) + // connections with authentication will possibly reconnect, so ignore them + QVERIFY( cur_state < state ); + } + cur_state = state; + + if (state == QHttp::Connecting) { + bytesTotalSend = bytesTotal_init; + bytesDoneSend = bytesDone_init; + bytesTotalRead = bytesTotal_init; + bytesDoneRead = bytesDone_init; + } +} + +void tst_QHttp::responseHeaderReceived( const QHttpResponseHeader &header ) +{ +#if defined( DUMP_SIGNALS ) + qDebug( "%d: responseHeaderReceived(\n---{\n%s}---)", http->currentId(), header.toString().toAscii().data() ); +#endif + QCOMPARE( http->currentId(), current_id ); + if ( ids.count() > 1 ) { + QVERIFY( http->hasPendingRequests() ); + } else { + QVERIFY( !http->hasPendingRequests() ); + } + CURRENTREQUEST_TEST; + + resultMap[ http->currentId() ].resp = header; +} + +void tst_QHttp::readyRead( const QHttpResponseHeader & ) +{ +#if defined( DUMP_SIGNALS ) + qDebug( "%d: readyRead()", http->currentId() ); +#endif + QCOMPARE( http->currentId(), current_id ); + if ( ids.count() > 1 ) { + QVERIFY( http->hasPendingRequests() ); + } else { + QVERIFY( !http->hasPendingRequests() ); + } + QVERIFY( cur_state == http->state() ); + CURRENTREQUEST_TEST; + + if ( QTest::currentTestFunction() != QLatin1String("bytesAvailable") ) { + int oldSize = readyRead_ba.size(); + quint64 bytesAvail = http->bytesAvailable(); + QByteArray ba = http->readAll(); + QVERIFY( (quint64) ba.size() == bytesAvail ); + readyRead_ba.resize( oldSize + ba.size() ); + memcpy( readyRead_ba.data()+oldSize, ba.data(), ba.size() ); + + if ( bytesTotalRead > 0 ) { + QVERIFY( (int)readyRead_ba.size() <= bytesTotalRead ); + } + QVERIFY( (int)readyRead_ba.size() == bytesDoneRead ); + } +} + +void tst_QHttp::dataSendProgress( int done, int total ) +{ +#if defined( DUMP_SIGNALS ) + qDebug( "%d: dataSendProgress( %d, %d )", http->currentId(), done, total ); +#endif + QCOMPARE( http->currentId(), current_id ); + if ( ids.count() > 1 ) { + QVERIFY( http->hasPendingRequests() ); + } else { + QVERIFY( !http->hasPendingRequests() ); + } + QVERIFY( cur_state == http->state() ); + CURRENTREQUEST_TEST; + + if ( bytesTotalSend == bytesTotal_init ) { + bytesTotalSend = total; + } else { + QCOMPARE( bytesTotalSend, total ); + } + + QVERIFY( bytesTotalSend != bytesTotal_init ); + QVERIFY( bytesDoneSend <= done ); + bytesDoneSend = done; + if ( bytesTotalSend > 0 ) { + QVERIFY( bytesDoneSend <= bytesTotalSend ); + } + + if ( QTest::currentTestFunction() == QLatin1String("abort") ) { + // ### it would be nice if we could specify in our testdata when to do + // the abort + if ( done >= total/100000 ) { + if ( ids.count() != 1 ) { + // do abort only once + int tmpId = ids.first(); + ids.clear(); + ids << tmpId; + http->abort(); + } + } + } +} + +void tst_QHttp::dataReadProgress( int done, int total ) +{ +#if defined( DUMP_SIGNALS ) + qDebug( "%d: dataReadProgress( %d, %d )", http->currentId(), done, total ); +#endif + QCOMPARE( http->currentId(), current_id ); + if ( ids.count() > 1 ) { + QVERIFY( http->hasPendingRequests() ); + } else { + QVERIFY( !http->hasPendingRequests() ); + } + QVERIFY( cur_state == http->state() ); + CURRENTREQUEST_TEST; + + if ( bytesTotalRead == bytesTotal_init ) + bytesTotalRead = total; + else { + QVERIFY( bytesTotalRead == total ); + } + + QVERIFY( bytesTotalRead != bytesTotal_init ); + QVERIFY( bytesDoneRead <= done ); + bytesDoneRead = done; + if ( bytesTotalRead > 0 ) { + QVERIFY( bytesDoneRead <= bytesTotalRead ); + } + + if ( QTest::currentTestFunction() == QLatin1String("abort") ) { + // ### it would be nice if we could specify in our testdata when to do + // the abort + if ( done >= total/100000 ) { + if ( ids.count() != 1 ) { + // do abort only once + int tmpId = ids.first(); + ids.clear(); + ids << tmpId; + http->abort(); + } + } + } +} + + +QHttp *tst_QHttp::newHttp(bool withAuth) +{ + QHttp *nHttp = new QHttp( 0 ); + connect( nHttp, SIGNAL(requestStarted(int)), + SLOT(requestStarted(int)) ); + connect( nHttp, SIGNAL(requestFinished(int,bool)), + SLOT(requestFinished(int,bool)) ); + connect( nHttp, SIGNAL(done(bool)), + SLOT(done(bool)) ); + connect( nHttp, SIGNAL(stateChanged(int)), + SLOT(stateChanged(int)) ); + connect( nHttp, SIGNAL(responseHeaderReceived(const QHttpResponseHeader&)), + SLOT(responseHeaderReceived(const QHttpResponseHeader&)) ); + connect( nHttp, SIGNAL(readyRead(const QHttpResponseHeader&)), + SLOT(readyRead(const QHttpResponseHeader&)) ); + connect( nHttp, SIGNAL(dataSendProgress(int,int)), + SLOT(dataSendProgress(int,int)) ); + connect( nHttp, SIGNAL(dataReadProgress(int,int)), + SLOT(dataReadProgress(int,int)) ); + + connectionWithAuth = withAuth; + return nHttp; +} + +void tst_QHttp::addRequest( QHttpRequestHeader header, int id ) +{ + ids << id; + RequestResult res; + res.req = header; + res.success = -1; + resultMap[ id ] = res; +} + +bool tst_QHttp::headerAreEqual( const QHttpHeader &h1, const QHttpHeader &h2 ) +{ + if ( !h1.isValid() ) + return !h2.isValid(); + if ( !h2.isValid() ) + return !h1.isValid(); + + return h1.toString() == h2.toString(); +} + + +void tst_QHttp::reconnect() +{ + reconnect_state_connect_count = 0; + + QHttp http; + + QObject::connect(&http, SIGNAL(stateChanged(int)), this, SLOT(reconnect_state(int))); + http.setHost("trolltech.com", 80); + http.get("/company/index.html"); + http.setHost("trolltech.com", 8080); + http.get("/company/index.html"); + + QTestEventLoop::instance().enterLoop(60); + if (QTestEventLoop::instance().timeout()) + QFAIL("Network operation timed out"); + + QCOMPARE(reconnect_state_connect_count, 1); + + QTestEventLoop::instance().enterLoop(60); + if (QTestEventLoop::instance().timeout()) + QFAIL("Network operation timed out"); + + QCOMPARE(reconnect_state_connect_count, 2); +} + +void tst_QHttp::reconnect_state(int state) +{ + if (state == QHttp::Connecting) { + ++reconnect_state_connect_count; + QTestEventLoop::instance().exitLoop(); + } +} + +void tst_QHttp::setSocket() +{ + QHttp *http = new QHttp; + QPointer<QTcpSocket> replacementSocket = new QTcpSocket; + http->setSocket(replacementSocket); + QCoreApplication::processEvents(); + delete http; + QVERIFY(replacementSocket); + delete replacementSocket; +} + +class Server : public QTcpServer +{ + Q_OBJECT +public: + Server() + { + connect(this, SIGNAL(newConnection()), + this, SLOT(serveConnection())); + } + +private slots: + void serveConnection() + { + QTcpSocket *socket = nextPendingConnection(); + socket->write("HTTP/1.1 404 Not found\r\n" + "content-length: 4\r\n\r\nabcd"); + socket->disconnectFromHost(); + }; +}; + +void tst_QHttp::unexpectedRemoteClose() +{ + QFETCH_GLOBAL(int, proxyType); + if (proxyType == QNetworkProxy::Socks5Proxy) { + // This test doesn't make sense for SOCKS5 + return; + } + + Server server; + server.listen(); + QCoreApplication::instance()->processEvents(); + + QEventLoop loop; + QTimer::singleShot(3000, &loop, SLOT(quit())); + + QHttp http; + QObject::connect(&http, SIGNAL(done(bool)), &loop, SLOT(quit())); + QSignalSpy finishedSpy(&http, SIGNAL(requestFinished(int, bool))); + QSignalSpy doneSpy(&http, SIGNAL(done(bool))); + + http.setHost("localhost", server.serverPort()); + http.get("/"); + http.get("/"); + http.get("/"); + + loop.exec(); + + QCOMPARE(finishedSpy.count(), 4); + QVERIFY(!finishedSpy.at(1).at(1).toBool()); + QVERIFY(!finishedSpy.at(2).at(1).toBool()); + QVERIFY(!finishedSpy.at(3).at(1).toBool()); + QCOMPARE(doneSpy.count(), 1); + QVERIFY(!doneSpy.at(0).at(0).toBool()); +} + +void tst_QHttp::pctEncodedPath() +{ + QHttpRequestHeader header; + header.setRequest("GET", "/index.asp/a=%20&b=%20&c=%20"); + QCOMPARE(header.toString(), QString("GET /index.asp/a=%20&b=%20&c=%20 HTTP/1.1\r\n\r\n")); +} + +void tst_QHttp::caseInsensitiveKeys() +{ + QHttpResponseHeader header("HTTP/1.1 200 OK\r\nContent-Length: 213\r\nX-Been-There: True\r\nLocation: http://www.TrollTech.com/\r\n\r\n"); + QVERIFY(header.hasKey("Content-Length")); + QVERIFY(header.hasKey("X-Been-There")); + QVERIFY(header.hasKey("Location")); + QVERIFY(header.hasKey("content-length")); + QVERIFY(header.hasKey("x-been-there")); + QVERIFY(header.hasKey("location")); + QCOMPARE(header.value("Content-Length"), QString("213")); + QCOMPARE(header.value("X-Been-There"), QString("True")); + QCOMPARE(header.value("Location"), QString("http://www.TrollTech.com/")); + QCOMPARE(header.value("content-length"), QString("213")); + QCOMPARE(header.value("x-been-there"), QString("True")); + QCOMPARE(header.value("location"), QString("http://www.TrollTech.com/")); + QCOMPARE(header.allValues("location"), QStringList("http://www.TrollTech.com/")); + + header.addValue("Content-Length", "213"); + header.addValue("Content-Length", "214"); + header.addValue("Content-Length", "215"); + qDebug() << header.toString(); +} + +void tst_QHttp::proxyAuthenticationRequired(const QNetworkProxy &, QAuthenticator *auth) +{ + proxyAuthCalled = true; + auth->setUser("qsockstest"); + auth->setPassword("password"); +} + +void tst_QHttp::postAuthNtlm() +{ + QSKIP("NTLM not working", SkipAll); + + QHostInfo info = QHostInfo::fromName(QHostInfo::localHostName()); + QByteArray postData("Hello World"); + QHttp http; + + http.setHost(QtNetworkSettings::serverName()); + http.setProxy(QtNetworkSettings::serverName(), 3130); + http.post("/", postData); + + proxyAuthCalled = false; + connect(&http, SIGNAL(proxyAuthenticationRequired(QNetworkProxy,QAuthenticator*)), + SLOT(proxyAuthenticationRequired(QNetworkProxy,QAuthenticator*))); + + QObject::connect(&http, SIGNAL(done(bool)), &QTestEventLoop::instance(), SLOT(exitLoop())); + QTestEventLoop::instance().enterLoop(3); + QObject::disconnect(&http, SIGNAL(done(bool)), &QTestEventLoop::instance(), SLOT(exitLoop())); + + QVERIFY(proxyAuthCalled); + QVERIFY(!QTestEventLoop::instance().timeout()); +}; + +void tst_QHttp::proxyAndSsl() +{ +#ifdef QT_NO_OPENSSL + QSKIP("No OpenSSL support in this platform", SkipAll); +#else + QFETCH_GLOBAL(bool, setProxy); + if (setProxy) + return; + + QHttp http; + + http.setHost(QtNetworkSettings::serverName(), QHttp::ConnectionModeHttps); + http.setProxy(QNetworkProxy(QNetworkProxy::HttpProxy, QtNetworkSettings::serverName(), 3129)); + http.get("/"); + + proxyAuthCalled = false; + connect(&http, SIGNAL(proxyAuthenticationRequired(QNetworkProxy,QAuthenticator*)), + SLOT(proxyAuthenticationRequired(QNetworkProxy,QAuthenticator*))); + connect(&http, SIGNAL(sslErrors(QList<QSslError>)), + &http, SLOT(ignoreSslErrors())); + + QObject::connect(&http, SIGNAL(done(bool)), &QTestEventLoop::instance(), SLOT(exitLoop())); + QTestEventLoop::instance().enterLoop(3); + QObject::disconnect(&http, SIGNAL(done(bool)), &QTestEventLoop::instance(), SLOT(exitLoop())); + + QVERIFY(!QTestEventLoop::instance().timeout()); + QVERIFY(proxyAuthCalled); + + QHttpResponseHeader header = http.lastResponse(); + QVERIFY(header.isValid()); + QVERIFY(header.statusCode() < 400); // Should be 200, but as long as it's not an error, we're happy +#endif +} + +void tst_QHttp::cachingProxyAndSsl() +{ +#ifdef QT_NO_OPENSSL + QSKIP("No OpenSSL support in this platform", SkipAll); +#else + QFETCH_GLOBAL(bool, setProxy); + if (setProxy) + return; + + QHttp http; + + http.setHost(QtNetworkSettings::serverName(), QHttp::ConnectionModeHttps); + http.setProxy(QNetworkProxy(QNetworkProxy::HttpCachingProxy, QtNetworkSettings::serverName(), 3129)); + http.get("/"); + + proxyAuthCalled = false; + connect(&http, SIGNAL(proxyAuthenticationRequired(QNetworkProxy,QAuthenticator*)), + SLOT(proxyAuthenticationRequired(QNetworkProxy,QAuthenticator*))); + + QObject::connect(&http, SIGNAL(done(bool)), &QTestEventLoop::instance(), SLOT(exitLoop())); + QTestEventLoop::instance().enterLoop(3); + QObject::disconnect(&http, SIGNAL(done(bool)), &QTestEventLoop::instance(), SLOT(exitLoop())); + + QVERIFY(!QTestEventLoop::instance().timeout()); + QVERIFY(!proxyAuthCalled); // NOT called! QHttp should get a socket error + QVERIFY(http.state() != QHttp::Connected); + + QHttpResponseHeader header = http.lastResponse(); + QVERIFY(!header.isValid()); +#endif +} + +void tst_QHttp::emptyBodyInReply() +{ + // Note: if this test starts failing, please verify the date on the file + // returned by Apache on http://netiks.troll.no/ + // It is right now hard-coded to the date below + QHttp http; + http.setHost(QtNetworkSettings::serverName()); + + QHttpRequestHeader headers("GET", "/"); + headers.addValue("If-Modified-Since", "Sun, 16 Nov 2008 12:29:51 GMT"); + headers.addValue("Host", QtNetworkSettings::serverName()); + http.request(headers); + + QObject::connect(&http, SIGNAL(done(bool)), &QTestEventLoop::instance(), SLOT(exitLoop())); + QTestEventLoop::instance().enterLoop(10); + QObject::disconnect(&http, SIGNAL(done(bool)), &QTestEventLoop::instance(), SLOT(exitLoop())); + + QVERIFY(!QTestEventLoop::instance().timeout()); + + // check the reply + if (http.lastResponse().statusCode() != 304) { + qWarning() << http.lastResponse().statusCode() << qPrintable(http.lastResponse().reasonPhrase()); + qWarning() << "Last-Modified:" << qPrintable(http.lastResponse().value("last-modified")); + QFAIL("Server replied with the wrong status code; see warning output"); + } +} + +void tst_QHttp::abortSender() +{ + QHttp *http = qobject_cast<QHttp *>(sender()); + if (http) + http->abort(); +} + +void tst_QHttp::abortInReadyRead() +{ + QHttp http; + http.setHost(QtNetworkSettings::serverName()); + http.get("/qtest/bigfile"); + + qRegisterMetaType<QHttpResponseHeader>(); + QSignalSpy spy(&http, SIGNAL(readyRead(QHttpResponseHeader))); + + QObject::connect(&http, SIGNAL(readyRead(QHttpResponseHeader)), this, SLOT(abortSender())); + QObject::connect(&http, SIGNAL(done(bool)), &QTestEventLoop::instance(), SLOT(exitLoop())); + QTestEventLoop::instance().enterLoop(10); + QObject::disconnect(&http, SIGNAL(done(bool)), &QTestEventLoop::instance(), SLOT(exitLoop())); + + QVERIFY2(!QTestEventLoop::instance().timeout(), "Network timeout"); + QVERIFY(http.state() != QHttp::Connected); + + QCOMPARE(spy.count(), 1); +} + +void tst_QHttp::abortInResponseHeaderReceived() +{ + QHttp http; + http.setHost(QtNetworkSettings::serverName()); + http.get("/qtest/bigfile"); + + qRegisterMetaType<QHttpResponseHeader>(); + QSignalSpy spy(&http, SIGNAL(readyRead(QHttpResponseHeader))); + + QObject::connect(&http, SIGNAL(responseHeaderReceived(QHttpResponseHeader)), this, SLOT(abortSender())); + QObject::connect(&http, SIGNAL(done(bool)), &QTestEventLoop::instance(), SLOT(exitLoop())); + QTestEventLoop::instance().enterLoop(10); + QObject::disconnect(&http, SIGNAL(done(bool)), &QTestEventLoop::instance(), SLOT(exitLoop())); + + QVERIFY2(!QTestEventLoop::instance().timeout(), "Network timeout"); + QVERIFY(http.state() != QHttp::Connected); + + QCOMPARE(spy.count(), 0); +} + +void tst_QHttp::connectionClose() +{ + // This was added in response to bug 176822 + QFETCH_GLOBAL(bool, setProxy); + if (setProxy) + return; + + QHttp http; + ClosingServer server; + http.setHost("localhost", QHttp::ConnectionModeHttps, server.serverPort()); + http.get("/login/gateway/processLogin"); + + // another possibility: + //http.setHost("nexus.passport.com", QHttp::ConnectionModeHttps, 443); + //http.get("/rdr/pprdr.asp"); + + QObject::connect(&http, SIGNAL(done(bool)), &QTestEventLoop::instance(), SLOT(exitLoop())); + QTestEventLoop::instance().enterLoop(900); + QObject::disconnect(&http, SIGNAL(done(bool)), &QTestEventLoop::instance(), SLOT(exitLoop())); + + QVERIFY(!QTestEventLoop::instance().timeout()); +} + +void tst_QHttp::nestedEventLoop_slot(int id) +{ + if (!ids.contains(id)) + return; + QEventLoop subloop; + + // 16 seconds: fluke times out in 15 seconds, which triggers a QTcpSocket error + QTimer::singleShot(16000, &subloop, SLOT(quit())); + subloop.exec(); + + QTestEventLoop::instance().exitLoop(); +} + +void tst_QHttp::nestedEventLoop() +{ + QFETCH_GLOBAL(bool, setProxy); + if (setProxy) + return; + + http = new QHttp; + http->setHost(QtNetworkSettings::serverName()); + int getId = http->get("/"); + + ids.clear(); + ids << getId; + + QSignalSpy spy(http, SIGNAL(requestStarted(int))); + QSignalSpy spy2(http, SIGNAL(done(bool))); + + connect(http, SIGNAL(requestFinished(int,bool)), SLOT(nestedEventLoop_slot(int))); + QTestEventLoop::instance().enterLoop(20); + + QVERIFY2(!QTestEventLoop::instance().timeout(), "Network timeout"); + + // Find out how many signals with the first argument equalling our id were found + int spyCount = 0; + for (int i = 0; i < spy.count(); ++i) + if (spy.at(i).at(0).toInt() == getId) + ++spyCount; + + // each signal spied should have been emitted only once + QCOMPARE(spyCount, 1); + QCOMPARE(spy2.count(), 1); +} + +QTEST_MAIN(tst_QHttp) +#include "tst_qhttp.moc" diff --git a/tests/auto/network/access/qhttp/webserver/cgi-bin/retrieve_testfile.cgi b/tests/auto/network/access/qhttp/webserver/cgi-bin/retrieve_testfile.cgi new file mode 100755 index 0000000000..7896c505ca --- /dev/null +++ b/tests/auto/network/access/qhttp/webserver/cgi-bin/retrieve_testfile.cgi @@ -0,0 +1,6 @@ +#!/bin/sh + +echo "Content-type: text/plain"; +echo +cat testfile +echo "no file retrieved" > testfile diff --git a/tests/auto/network/access/qhttp/webserver/cgi-bin/rfc.cgi b/tests/auto/network/access/qhttp/webserver/cgi-bin/rfc.cgi new file mode 100755 index 0000000000..c68688ea31 --- /dev/null +++ b/tests/auto/network/access/qhttp/webserver/cgi-bin/rfc.cgi @@ -0,0 +1,5 @@ +#!/bin/sh + +echo "Content-type: text/plain"; +echo +cat ../rfc3252 diff --git a/tests/auto/network/access/qhttp/webserver/cgi-bin/store_testfile.cgi b/tests/auto/network/access/qhttp/webserver/cgi-bin/store_testfile.cgi new file mode 100755 index 0000000000..e950f2af04 --- /dev/null +++ b/tests/auto/network/access/qhttp/webserver/cgi-bin/store_testfile.cgi @@ -0,0 +1,6 @@ +#!/bin/sh + +echo "Content-type: text/plain"; +echo +echo "file stored under 'testfile'" +cat > testfile diff --git a/tests/auto/network/access/qhttp/webserver/index.html b/tests/auto/network/access/qhttp/webserver/index.html new file mode 100644 index 0000000000..b80c61bf0a --- /dev/null +++ b/tests/auto/network/access/qhttp/webserver/index.html @@ -0,0 +1,899 @@ + + + + + + +Network Working Group H. Kennedy +Request for Comments: 3252 Mimezine +Category: Informational 1 April 2002 + + + Binary Lexical Octet Ad-hoc Transport + +Status of this Memo + + This memo provides information for the Internet community. It does + not specify an Internet standard of any kind. Distribution of this + memo is unlimited. + +Copyright Notice + + Copyright (C) The Internet Society (2002). All Rights Reserved. + +Abstract + + This document defines a reformulation of IP and two transport layer + protocols (TCP and UDP) as XML applications. + +1. Introduction + +1.1. Overview + + This document describes the Binary Lexical Octet Ad-hoc Transport + (BLOAT): a reformulation of a widely-deployed network-layer protocol + (IP [RFC791]), and two associated transport layer protocols (TCP + [RFC793] and UDP [RFC768]) as XML [XML] applications. It also + describes methods for transporting BLOAT over Ethernet and IEEE 802 + networks as well as encapsulating BLOAT in IP for gatewaying BLOAT + across the public Internet. + +1.2. Motivation + + The wild popularity of XML as a basis for application-level protocols + such as the Blocks Extensible Exchange Protocol [RFC3080], the Simple + Object Access Protocol [SOAP], and Jabber [JABBER] prompted + investigation into the possibility of extending the use of XML in the + protocol stack. Using XML at both the transport and network layer in + addition to the application layer would provide for an amazing amount + of power and flexibility while removing dependencies on proprietary + and hard-to-understand binary protocols. This protocol unification + would also allow applications to use a single XML parser for all + aspects of their operation, eliminating developer time spent figuring + out the intricacies of each new protocol, and moving the hard work of + + + + +Kennedy Informational [Page 1] + +RFC 3252 Binary Lexical Octet Ad-hoc Transport 1 April 2002 + + + parsing to the XML toolset. The use of XML also mitigates concerns + over "network vs. host" byte ordering which is at the root of many + network application bugs. + +1.3. Relation to Existing Protocols + + The reformulations specified in this RFC follow as closely as + possible the spirit of the RFCs on which they are based, and so MAY + contain elements or attributes that would not be needed in a pure + reworking (e.g. length attributes, which are implicit in XML.) + + The layering of network and transport protocols are maintained in + this RFC despite the optimizations that could be made if the line + were somewhat blurred (i.e. merging TCP and IP into a single, larger + element in the DTD) in order to foster future use of this protocol as + a basis for reformulating other protocols (such as ICMP.) + + Other than the encoding, the behavioral aspects of each of the + existing protocols remain unchanged. Routing, address spaces, TCP + congestion control, etc. behave as specified in the extant standards. + Adapting to new standards and experimental algorithm heuristics for + improving performance will become much easier once the move to BLOAT + has been completed. + +1.4. Requirement Levels + + The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", + "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this + document are to be interpreted as described in BCP 14, RFC 2119 + [RFC2119]. + +2. IPoXML + + This protocol MUST be implemented to be compliant with this RFC. + IPoXML is the root protocol REQUIRED for effective use of TCPoXML + (section 3.) and higher-level application protocols. + + The DTD for this document type can be found in section 7.1. + + The routing of IPoXML can be easily implemented on hosts with an XML + parser, as the regular structure lends itself handily to parsing and + validation of the document/datagram and then processing the + destination address, TTL, and checksum before sending it on to its + next-hop. + + The reformulation of IPv4 was chosen over IPv6 [RFC2460] due to the + wider deployment of IPv4 and the fact that implementing IPv6 as XML + would have exceeded the 1500 byte Ethernet MTU. + + + +Kennedy Informational [Page 2] + +RFC 3252 Binary Lexical Octet Ad-hoc Transport 1 April 2002 + + + All BLOAT implementations MUST use - and specify - the UTF-8 encoding + of RFC 2279 [RFC2279]. All BLOAT document/datagrams MUST be well- + formed and include the XMLDecl. + +2.1. IP Description + + A number of items have changed (for the better) from the original IP + specification. Bit-masks, where present have been converted into + human-readable values. IP addresses are listed in their dotted- + decimal notation [RFC1123]. Length and checksum values are present + as decimal integers. + + To calculate the length and checksum fields of the IP element, a + canonicalized form of the element MUST be used. The canonical form + SHALL have no whitespace (including newline characters) between + elements and only one space character between attributes. There + SHALL NOT be a space following the last attribute in an element. + + An iterative method SHOULD be used to calculate checksums, as the + length field will vary based on the size of the checksum. + + The payload element bears special attention. Due to the character + set restrictions of XML, the payload of IP datagrams (which MAY + contain arbitrary data) MUST be encoded for transport. This RFC + REQUIRES the contents of the payload to be encoded in the base-64 + encoding of RFC 2045 [RFC2045], but removes the requirement that the + encoded output MUST be wrapped on 76-character lines. + + + + + + + + + + + + + + + + + + + + + + + + +Kennedy Informational [Page 3] + +RFC 3252 Binary Lexical Octet Ad-hoc Transport 1 April 2002 + + +2.2. Example Datagram + + The following is an example IPoXML datagram with an empty payload: + + <?xml version="1.0" encoding="UTF-8"?> + <!DOCTYPE ip PUBLIC "-//IETF//DTD BLOAT 1.0 IP//EN" "bloat.dtd"> + <ip> + <header length="474"> + <version value="4"/> + <tos precedence="Routine" delay="Normal" throughput="Normal" + relibility="Normal" reserved="0"/> + <total.length value="461"/> + <id value="1"/> + <flags reserved="0" df="dont" mf="last"/> + <offset value="0"/> + <ttl value="255"/> + <protocol value="6"/> + <checksum value="8707"/> + <source address="10.0.0.22"/> + <destination address="10.0.0.1"/> + <options> + <end copied="0" class="0" number="0"/> + </options> + <padding pad="0"/> + </header> + <payload> + </payload> + </ip> + +3. TCPoXML + + This protocol MUST be implemented to be compliant with this RFC. The + DTD for this document type can be found in section 7.2. + +3.1. TCP Description + + A number of items have changed from the original TCP specification. + Bit-masks, where present have been converted into human-readable + values. Length and checksum and port values are present as decimal + integers. + + To calculate the length and checksum fields of the TCP element, a + canonicalized form of the element MUST be used as in section 2.1. + + An iterative method SHOULD be used to calculate checksums as in + section 2.1. + + The payload element MUST be encoded as in section 2.1. + + + +Kennedy Informational [Page 4] + +RFC 3252 Binary Lexical Octet Ad-hoc Transport 1 April 2002 + + + The TCP offset element was expanded to a maximum of 255 from 16 to + allow for the increased size of the header in XML. + + TCPoXML datagrams encapsulated by IPoXML MAY omit the <?xml?> header + as well as the <!DOCTYPE> declaration. + +3.2. Example Datagram + + The following is an example TCPoXML datagram with an empty payload: + + <?xml version="1.0" encoding="UTF-8"?> + <!DOCTYPE tcp PUBLIC "-//IETF//DTD BLOAT 1.0 TCP//EN" "bloat.dtd"> + <tcp> + <tcp.header> + <src port="31415"/> + <dest port="42424"/> + <sequence number="322622954"/> + <acknowledgement number="689715995"/> + <offset number=""/> + <reserved value="0"/> + <control syn="1" ack="1"/> + <window size="1"/> + <urgent pointer="0"/> + <checksum value="2988"/> + <tcp.options> + <tcp.end kind="0"/> + </tcp.options> + <padding pad="0"/> + </tcp.header> + <payload> + </payload> + </tcp> + +4. UDPoXML + + This protocol MUST be implemented to be compliant with this RFC. The + DTD for this document type can be found in section 7.3. + +4.1. UDP Description + + A number of items have changed from the original UDP specification. + Bit-masks, where present have been converted into human-readable + values. Length and checksum and port values are present as decimal + integers. + + + + + + + +Kennedy Informational [Page 5] + +RFC 3252 Binary Lexical Octet Ad-hoc Transport 1 April 2002 + + + To calculate the length and checksum fields of the UDP element, a + canonicalized form of the element MUST be used as in section 2.1. An + iterative method SHOULD be used to calculate checksums as in section + 2.1. + + The payload element MUST be encoded as in section 2.1. + + UDPoXML datagrams encapsulated by IPoXML MAY omit the <?xml?> header + as well as the <!DOCTYPE> declaration. + +4.2. Example Datagram + + The following is an example UDPoXML datagram with an empty payload: + + <?xml version="1.0" encoding="UTF-8"?> + <!DOCTYPE udp PUBLIC "-//IETF//DTD BLOAT 1.0 UDP//EN" "bloat.dtd"> + <udp> + <udp.header> + <src port="31415"/> + <dest port="42424"/> + <udp.length value="143"/> + <checksum value="2988"/> + </udp.header> + <payload> + </payload> + </udp> + +5. Network Transport + + This document provides for the transmission of BLOAT datagrams over + two common families of physical layer transport. Future RFCs will + address additional transports as routing vendors catch up to the + specification, and we begin to see BLOAT routed across the Internet + backbone. + +5.1. Ethernet + + BLOAT is encapsulated in Ethernet datagrams as in [RFC894] with the + exception that the type field of the Ethernet frame MUST contain the + value 0xBEEF. The first 5 octets of the Ethernet frame payload will + be 0x3c 3f 78 6d 6c ("<?xml".) + +5.2. IEEE 802 + + BLOAT is encapsulated in IEEE 802 Networks as in [RFC1042] except + that the protocol type code for IPoXML is 0xBEEF. + + + + + +Kennedy Informational [Page 6] + +RFC 3252 Binary Lexical Octet Ad-hoc Transport 1 April 2002 + + +6. Gatewaying over IP + + In order to facilitate the gradual introduction of BLOAT into the + public Internet, BLOAT MAY be encapsulated in IP as in [RFC2003] to + gateway between networks that run BLOAT natively on their LANs. + +7. DTDs + + The Transport DTDs (7.2. and 7.3.) build on the definitions in the + Network DTD (7.1.) + + The DTDs are referenced by their PubidLiteral and SystemLiteral (from + [XML]) although it is understood that most IPoXML implementations + will not need to pull down the DTD, as it will normally be embedded + in the implementation, and presents something of a catch-22 if you + need to load part of your network protocol over the network. + +7.1. IPoXML DTD + + <!-- + DTD for IP over XML. + Refer to this DTD as: + + <!DOCTYPE ip PUBLIC "-//IETF//DTD BLOAT 1.0 IP//EN" "bloat.dtd"> + --> + <!-- + DTD data types: + + Digits [0..9]+ + + Precedence "NetworkControl | InternetworkControl | + CRITIC | FlashOverride | Flash | Immediate | + Priority | Routine" + + IP4Addr "dotted-decimal" notation of [RFC1123] + + Class [0..3] + + Sec "Unclassified | Confidential | EFTO | MMMM | PROG | + Restricted | Secret | Top Secret | Reserved" + + Compartments [0..65535] + + Handling [0..65535] + + TCC [0..16777216] + + --> + + + +Kennedy Informational [Page 7] + +RFC 3252 Binary Lexical Octet Ad-hoc Transport 1 April 2002 + + + <!ENTITY % Digits "CDATA"> + <!ENTITY % Precedence "CDATA"> + <!ENTITY % IP4Addr "CDATA"> + <!ENTITY % Class "CDATA"> + <!ENTITY % Sec "CDATA"> + <!ENTITY % Compartments "CDATA"> + <!ENTITY % Handling "CDATA"> + <!ENTITY % TCC "CDATA"> + + <!ELEMENT ip (header, payload)> + + <!ELEMENT header (version, tos, total.length, id, flags, offset, ttl, + protocol, checksum, source, destination, options, + padding)> + <!-- length of header in 32-bit words --> + <!ATTLIST header + length %Digits; #REQUIRED> + + <!ELEMENT version EMPTY> + <!-- ip version. SHOULD be "4" --> + <!ATTLIST version + value %Digits; #REQUIRED> + + <!ELEMENT tos EMPTY> + <!ATTLIST tos + precedence %Precedence; #REQUIRED + delay (normal | low) #REQUIRED + throughput (normal | high) #REQUIRED + relibility (normal | high) #REQUIRED + reserved CDATA #FIXED "0"> + + <!ELEMENT total.length EMPTY> + <!-- + total length of datagram (header and payload) in octets, MUST be + less than 65,535 (and SHOULD be less than 1024 for IPoXML on local + ethernets). + --> + <!ATTLIST total.length + value %Digits; #REQUIRED> + + <!ELEMENT id EMPTY> + <!-- 0 <= id <= 65,535 --> + <!ATTLIST id + value %Digits; #REQUIRED> + + <!ELEMENT flags EMPTY> + <!-- df = don't fragment, mf = more fragments --> + <!ATTLIST flags + + + +Kennedy Informational [Page 8] + +RFC 3252 Binary Lexical Octet Ad-hoc Transport 1 April 2002 + + + reserved CDATA #FIXED "0" + df (may|dont) #REQUIRED + mf (last|more) #REQUIRED> + + <!ELEMENT offset EMPTY> + <!-- 0 <= offset <= 8192 measured in 8 octet (64-bit) chunks --> + <!ATTLIST offset + value %Digits; #REQUIRED> + + <!ELEMENT ttl EMPTY> + <!-- 0 <= ttl <= 255 --> + <!ATTLIST ttl + value %Digits; #REQUIRED> + + <!ELEMENT protocol EMPTY> + <!-- 0 <= protocol <= 255 (per IANA) --> + <!ATTLIST protocol + value %Digits; #REQUIRED> + + <!ELEMENT checksum EMPTY> + <!-- 0 <= checksum <= 65535 (over header only) --> + <!ATTLIST checksum + value %Digits; #REQUIRED> + + <!ELEMENT source EMPTY> + <!ATTLIST source + address %IP4Addr; #REQUIRED> + + <!ELEMENT destination EMPTY> + <!ATTLIST destination + address %IP4Addr; #REQUIRED> + + <!ELEMENT options ( end | noop | security | loose | strict | record + | stream | timestamp )*> + + <!ELEMENT end EMPTY> + <!ATTLIST end + copied (0|1) #REQUIRED + class CDATA #FIXED "0" + number CDATA #FIXED "0"> + + <!ELEMENT noop EMPTY> + <!ATTLIST noop + copied (0|1) #REQUIRED + class CDATA #FIXED "0" + number CDATA #FIXED "1"> + + <!ELEMENT security EMPTY> + + + +Kennedy Informational [Page 9] + +RFC 3252 Binary Lexical Octet Ad-hoc Transport 1 April 2002 + + + <!ATTLIST security + copied CDATA #FIXED "1" + class CDATA #FIXED "0" + number CDATA #FIXED "2" + length CDATA #FIXED "11" + security %Sec; #REQUIRED + compartments %Compartments; #REQUIRED + handling %Handling; #REQUIRED + tcc %TCC; #REQUIRED> + <!ELEMENT loose (hop)+> + <!ATTLIST loose + copied CDATA #FIXED "1" + class CDATA #FIXED "0" + number CDATA #FIXED "3" + length %Digits; #REQUIRED + pointer %Digits; #REQUIRED> + + <!ELEMENT hop EMPTY> + <!ATTLIST hop + address %IP4Addr; #REQUIRED> + + <!ELEMENT strict (hop)+> + <!ATTLIST strict + copied CDATA #FIXED "1" + class CDATA #FIXED "0" + number CDATA #FIXED "9" + length %Digits; #REQUIRED + pointer %Digits; #REQUIRED> + + <!ELEMENT record (hop)+> + <!ATTLIST record + copied CDATA #FIXED "0" + class CDATA #FIXED "0" + number CDATA #FIXED "7" + length %Digits; #REQUIRED + pointer %Digits; #REQUIRED> + + <!ELEMENT stream EMPTY> + <!-- 0 <= id <= 65,535 --> + <!ATTLIST stream + copied CDATA #FIXED "1" + class CDATA #FIXED "0" + number CDATA #FIXED "8" + length CDATA #FIXED "4" + id %Digits; #REQUIRED> + + <!ELEMENT timestamp (tstamp)+> + <!-- 0 <= oflw <=15 --> + + + +Kennedy Informational [Page 10] + +RFC 3252 Binary Lexical Octet Ad-hoc Transport 1 April 2002 + + + <!ATTLIST timestamp + copied CDATA #FIXED "0" + class CDATA #FIXED "2" + number CDATA #FIXED "4" + length %Digits; #REQUIRED + pointer %Digits; #REQUIRED + oflw %Digits; #REQUIRED + flag (0 | 1 | 3) #REQUIRED> + + <!ELEMENT tstamp EMPTY> + <!ATTLIST tstamp + time %Digits; #REQUIRED + address %IP4Addr; #IMPLIED> + <!-- + padding to bring header to 32-bit boundary. + pad MUST be "0"* + --> + <!ELEMENT padding EMPTY> + <!ATTLIST padding + pad CDATA #REQUIRED> + + <!-- payload MUST be encoded as base-64 [RFC2045], as modified + by section 2.1 of this RFC --> + <!ELEMENT payload (CDATA)> + +7.2. TCPoXML DTD + + <!-- + DTD for TCP over XML. + Refer to this DTD as: + + <!DOCTYPE tcp PUBLIC "-//IETF//DTD BLOAT 1.0 TCP//EN" "bloat.dtd"> + --> + + <!-- the pseudoheader is only included for checksum calculations --> + <!ELEMENT tcp (tcp.pseudoheader?, tcp.header, payload)> + + <!ELEMENT tcp.header (src, dest, sequence, acknowledgement, offset, + reserved, control, window, checksum, urgent, + tcp.options, padding)> + + <!ELEMENT src EMPTY> + <!-- 0 <= port <= 65,535 --> + <!ATTLIST src + port %Digits; #REQUIRED> + + <!ELEMENT dest EMPTY> + <!-- 0 <= port <= 65,535 --> + + + +Kennedy Informational [Page 11] + +RFC 3252 Binary Lexical Octet Ad-hoc Transport 1 April 2002 + + + <!ATTLIST dest + port %Digits; #REQUIRED> + + <!ELEMENT sequence EMPTY> + <!-- 0 <= number <= 4294967295 --> + <!ATTLIST sequence + number %Digits; #REQUIRED> + + <!ELEMENT acknowledgement EMPTY> + <!-- 0 <= number <= 4294967295 --> + <!ATTLIST acknowledgement + number %Digits; #REQUIRED> + + <!ELEMENT offset EMPTY> + <!-- 0 <= number <= 255 --> + <!ATTLIST offset + number %Digits; #REQUIRED> + + <!ELEMENT reserved EMPTY> + <!ATTLIST reserved + value CDATA #FIXED "0"> + + <!ELEMENT control EMPTY> + <!ATTLIST control + urg (0|1) #IMPLIED + ack (0|1) #IMPLIED + psh (0|1) #IMPLIED + rst (0|1) #IMPLIED + syn (0|1) #IMPLIED + fin (0|1) #IMPLIED> + + <!ELEMENT window EMPTY> + <!-- 0 <= size <= 65,535 --> + <!ATTLIST window + size %Digits; #REQUIRED> + + <!-- + checksum as in ip, but with + the following pseudo-header added into the tcp element: + --> + <!ELEMENT tcp.pseudoheader (source, destination, protocol, + tcp.length)> + + <!-- + tcp header + data length in octets. does not include the size of + + the pseudoheader. + --> + + + +Kennedy Informational [Page 12] + +RFC 3252 Binary Lexical Octet Ad-hoc Transport 1 April 2002 + + + <!ELEMENT tcp.length EMPTY> + <!ATTLIST tcp.length + value %Digits; #REQUIRED> + + <!ELEMENT urgent EMPTY> + <!-- 0 <= pointer <= 65,535 --> + <!ATTLIST urgent + pointer %Digits; #REQUIRED> + + <!ELEMENT tcp.options (tcp.end | tcp.noop | tcp.mss)+> + + <!ELEMENT tcp.end EMPTY> + <!ATTLIST tcp.end + kind CDATA #FIXED "0"> + + <!ELEMENT tcp.noop EMPTY> + <!ATTLIST tcp.noop + kind CDATA #FIXED "1"> + + <!ELEMENT tcp.mss EMPTY> + <!ATTLIST tcp.mss + kind CDATA #FIXED "2" + length CDATA #FIXED "4" + size %Digits; #REQUIRED> + +7.3. UDPoXML DTD + + <!-- + DTD for UDP over XML. + Refer to this DTD as: + + <!DOCTYPE udp PUBLIC "-//IETF//DTD BLOAT 1.0 UDP//EN" "bloat.dtd"> + --> + + <!ELEMENT udp (udp.pseudoheader?, udp.header, payload)> + + <!ELEMENT udp.header (src, dest, udp.length, checksum)> + + <!ELEMENT udp.pseudoheader (source, destination, protocol, + udp.length)> + + <!-- + udp header + data length in octets. does not include the size of + the pseudoheader. + --> + <!ELEMENT udp.length EMPTY> + <!ATTLIST udp.length + value %Digits; #REQUIRED> + + + +Kennedy Informational [Page 13] + +RFC 3252 Binary Lexical Octet Ad-hoc Transport 1 April 2002 + + +8. Security Considerations + + XML, as a subset of SGML, has the same security considerations as + specified in SGML Media Types [RFC1874]. Security considerations + that apply to IP, TCP and UDP also likely apply to BLOAT as it does + not attempt to correct for issues not related to message format. + +9. References + + [JABBER] Miller, J., "Jabber", draft-miller-jabber-00.txt, + February 2002. (Work in Progress) + + [RFC768] Postel, J., "User Datagram Protocol", STD 6, RFC 768, + August 1980. + + [RFC791] Postel, J., "Internet Protocol", STD 5, RFC 791, + September 1981. + + [RFC793] Postel, J., "Transmission Control Protocol", STD 7, RFC + 793, September 1981. + + [RFC894] Hornig, C., "Standard for the Transmission of IP + Datagrams over Ethernet Networks.", RFC 894, April 1984. + + [RFC1042] Postel, J. and J. Reynolds, "Standard for the + Transmission of IP Datagrams Over IEEE 802 Networks", STD + 43, RFC 1042, February 1988. + + [RFC1123] Braden, R., "Requirements for Internet Hosts - + Application and Support", RFC 1123, October 1989. + + [RFC1874] Levinson, E., "SGML Media Types", RFC 1874, December + 1995. + + [RFC2003] Perkins, C., "IP Encapsulation within IP", RFC 2003, + October 1996. + + [RFC2045] Freed, N. and N. Borenstein, "Multipurpose Internet Mail + Extensions (MIME) Part One: Format of Internet Message + Bodies", RFC 2045, November 1996. + + [RFC2119] Bradner, S., "Key words for use in RFCs to Indicate + Requirement Levels", BCP 14, RFC 2119, March 1997. + + [RFC2279] Yergeau, F., "UTF-8, a transformation format of ISO + 10646", RFC 2279, January 1998. + + + + + +Kennedy Informational [Page 14] + +RFC 3252 Binary Lexical Octet Ad-hoc Transport 1 April 2002 + + + [RFC2460] Deering, S. and R. Hinden, "Internet Protocol, Version 6 + (IPv6) Specification", RFC 2460, December 1998. + + [RFC3080] Rose, M., "The Blocks Extensible Exchange Protocol Core", + RFC 3080, March 2001. + + [SOAP] Box, D., Ehnebuske, D., Kakivaya, G., Layman, A., + Mendelsohn, N., Nielsen, H. F., Thatte, S. Winer, D., + "Simple Object Access Protocol (SOAP) 1.1" World Wide Web + Consortium Note, May 2000 http://www.w3.org/TR/SOAP/ + + [XML] Bray, T., Paoli, J., Sperberg-McQueen, C. M., "Extensible + Markup Language (XML)" World Wide Web Consortium + Recommendation REC- xml-19980210. + http://www.w3.org/TR/1998/REC-xml-19980210 + +10. Author's Address + + Hugh Kennedy + Mimezine + 1060 West Addison + Chicago, IL 60613 + USA + + EMail: kennedyh@engin.umich.edu + + + + + + + + + + + + + + + + + + + + + + + + + + +Kennedy Informational [Page 15] + +RFC 3252 Binary Lexical Octet Ad-hoc Transport 1 April 2002 + + +11. Full Copyright Statement + + Copyright (C) The Internet Society (2002). All Rights Reserved. + + This document and translations of it may be copied and furnished to + others, and derivative works that comment on or otherwise explain it + or assist in its implementation may be prepared, copied, published + and distributed, in whole or in part, without restriction of any + kind, provided that the above copyright notice and this paragraph are + included on all such copies and derivative works. However, this + document itself may not be modified in any way, such as by removing + the copyright notice or references to the Internet Society or other + Internet organizations, except as needed for the purpose of + developing Internet standards in which case the procedures for + copyrights defined in the Internet Standards process must be + followed, or as required to translate it into languages other than + English. + + The limited permissions granted above are perpetual and will not be + revoked by the Internet Society or its successors or assigns. + + This document and the information contained herein is provided on an + "AS IS" basis and THE INTERNET SOCIETY AND THE INTERNET ENGINEERING + TASK FORCE DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING + BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE INFORMATION + HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED WARRANTIES OF + MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. + +Acknowledgement + + Funding for the RFC Editor function is currently provided by the + Internet Society. + + + + + + + + + + + + + + + + + + + +Kennedy Informational [Page 16] + diff --git a/tests/auto/network/access/qhttp/webserver/rfc3252 b/tests/auto/network/access/qhttp/webserver/rfc3252 new file mode 100644 index 0000000000..b80c61bf0a --- /dev/null +++ b/tests/auto/network/access/qhttp/webserver/rfc3252 @@ -0,0 +1,899 @@ + + + + + + +Network Working Group H. Kennedy +Request for Comments: 3252 Mimezine +Category: Informational 1 April 2002 + + + Binary Lexical Octet Ad-hoc Transport + +Status of this Memo + + This memo provides information for the Internet community. It does + not specify an Internet standard of any kind. Distribution of this + memo is unlimited. + +Copyright Notice + + Copyright (C) The Internet Society (2002). All Rights Reserved. + +Abstract + + This document defines a reformulation of IP and two transport layer + protocols (TCP and UDP) as XML applications. + +1. Introduction + +1.1. Overview + + This document describes the Binary Lexical Octet Ad-hoc Transport + (BLOAT): a reformulation of a widely-deployed network-layer protocol + (IP [RFC791]), and two associated transport layer protocols (TCP + [RFC793] and UDP [RFC768]) as XML [XML] applications. It also + describes methods for transporting BLOAT over Ethernet and IEEE 802 + networks as well as encapsulating BLOAT in IP for gatewaying BLOAT + across the public Internet. + +1.2. Motivation + + The wild popularity of XML as a basis for application-level protocols + such as the Blocks Extensible Exchange Protocol [RFC3080], the Simple + Object Access Protocol [SOAP], and Jabber [JABBER] prompted + investigation into the possibility of extending the use of XML in the + protocol stack. Using XML at both the transport and network layer in + addition to the application layer would provide for an amazing amount + of power and flexibility while removing dependencies on proprietary + and hard-to-understand binary protocols. This protocol unification + would also allow applications to use a single XML parser for all + aspects of their operation, eliminating developer time spent figuring + out the intricacies of each new protocol, and moving the hard work of + + + + +Kennedy Informational [Page 1] + +RFC 3252 Binary Lexical Octet Ad-hoc Transport 1 April 2002 + + + parsing to the XML toolset. The use of XML also mitigates concerns + over "network vs. host" byte ordering which is at the root of many + network application bugs. + +1.3. Relation to Existing Protocols + + The reformulations specified in this RFC follow as closely as + possible the spirit of the RFCs on which they are based, and so MAY + contain elements or attributes that would not be needed in a pure + reworking (e.g. length attributes, which are implicit in XML.) + + The layering of network and transport protocols are maintained in + this RFC despite the optimizations that could be made if the line + were somewhat blurred (i.e. merging TCP and IP into a single, larger + element in the DTD) in order to foster future use of this protocol as + a basis for reformulating other protocols (such as ICMP.) + + Other than the encoding, the behavioral aspects of each of the + existing protocols remain unchanged. Routing, address spaces, TCP + congestion control, etc. behave as specified in the extant standards. + Adapting to new standards and experimental algorithm heuristics for + improving performance will become much easier once the move to BLOAT + has been completed. + +1.4. Requirement Levels + + The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", + "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this + document are to be interpreted as described in BCP 14, RFC 2119 + [RFC2119]. + +2. IPoXML + + This protocol MUST be implemented to be compliant with this RFC. + IPoXML is the root protocol REQUIRED for effective use of TCPoXML + (section 3.) and higher-level application protocols. + + The DTD for this document type can be found in section 7.1. + + The routing of IPoXML can be easily implemented on hosts with an XML + parser, as the regular structure lends itself handily to parsing and + validation of the document/datagram and then processing the + destination address, TTL, and checksum before sending it on to its + next-hop. + + The reformulation of IPv4 was chosen over IPv6 [RFC2460] due to the + wider deployment of IPv4 and the fact that implementing IPv6 as XML + would have exceeded the 1500 byte Ethernet MTU. + + + +Kennedy Informational [Page 2] + +RFC 3252 Binary Lexical Octet Ad-hoc Transport 1 April 2002 + + + All BLOAT implementations MUST use - and specify - the UTF-8 encoding + of RFC 2279 [RFC2279]. All BLOAT document/datagrams MUST be well- + formed and include the XMLDecl. + +2.1. IP Description + + A number of items have changed (for the better) from the original IP + specification. Bit-masks, where present have been converted into + human-readable values. IP addresses are listed in their dotted- + decimal notation [RFC1123]. Length and checksum values are present + as decimal integers. + + To calculate the length and checksum fields of the IP element, a + canonicalized form of the element MUST be used. The canonical form + SHALL have no whitespace (including newline characters) between + elements and only one space character between attributes. There + SHALL NOT be a space following the last attribute in an element. + + An iterative method SHOULD be used to calculate checksums, as the + length field will vary based on the size of the checksum. + + The payload element bears special attention. Due to the character + set restrictions of XML, the payload of IP datagrams (which MAY + contain arbitrary data) MUST be encoded for transport. This RFC + REQUIRES the contents of the payload to be encoded in the base-64 + encoding of RFC 2045 [RFC2045], but removes the requirement that the + encoded output MUST be wrapped on 76-character lines. + + + + + + + + + + + + + + + + + + + + + + + + +Kennedy Informational [Page 3] + +RFC 3252 Binary Lexical Octet Ad-hoc Transport 1 April 2002 + + +2.2. Example Datagram + + The following is an example IPoXML datagram with an empty payload: + + <?xml version="1.0" encoding="UTF-8"?> + <!DOCTYPE ip PUBLIC "-//IETF//DTD BLOAT 1.0 IP//EN" "bloat.dtd"> + <ip> + <header length="474"> + <version value="4"/> + <tos precedence="Routine" delay="Normal" throughput="Normal" + relibility="Normal" reserved="0"/> + <total.length value="461"/> + <id value="1"/> + <flags reserved="0" df="dont" mf="last"/> + <offset value="0"/> + <ttl value="255"/> + <protocol value="6"/> + <checksum value="8707"/> + <source address="10.0.0.22"/> + <destination address="10.0.0.1"/> + <options> + <end copied="0" class="0" number="0"/> + </options> + <padding pad="0"/> + </header> + <payload> + </payload> + </ip> + +3. TCPoXML + + This protocol MUST be implemented to be compliant with this RFC. The + DTD for this document type can be found in section 7.2. + +3.1. TCP Description + + A number of items have changed from the original TCP specification. + Bit-masks, where present have been converted into human-readable + values. Length and checksum and port values are present as decimal + integers. + + To calculate the length and checksum fields of the TCP element, a + canonicalized form of the element MUST be used as in section 2.1. + + An iterative method SHOULD be used to calculate checksums as in + section 2.1. + + The payload element MUST be encoded as in section 2.1. + + + +Kennedy Informational [Page 4] + +RFC 3252 Binary Lexical Octet Ad-hoc Transport 1 April 2002 + + + The TCP offset element was expanded to a maximum of 255 from 16 to + allow for the increased size of the header in XML. + + TCPoXML datagrams encapsulated by IPoXML MAY omit the <?xml?> header + as well as the <!DOCTYPE> declaration. + +3.2. Example Datagram + + The following is an example TCPoXML datagram with an empty payload: + + <?xml version="1.0" encoding="UTF-8"?> + <!DOCTYPE tcp PUBLIC "-//IETF//DTD BLOAT 1.0 TCP//EN" "bloat.dtd"> + <tcp> + <tcp.header> + <src port="31415"/> + <dest port="42424"/> + <sequence number="322622954"/> + <acknowledgement number="689715995"/> + <offset number=""/> + <reserved value="0"/> + <control syn="1" ack="1"/> + <window size="1"/> + <urgent pointer="0"/> + <checksum value="2988"/> + <tcp.options> + <tcp.end kind="0"/> + </tcp.options> + <padding pad="0"/> + </tcp.header> + <payload> + </payload> + </tcp> + +4. UDPoXML + + This protocol MUST be implemented to be compliant with this RFC. The + DTD for this document type can be found in section 7.3. + +4.1. UDP Description + + A number of items have changed from the original UDP specification. + Bit-masks, where present have been converted into human-readable + values. Length and checksum and port values are present as decimal + integers. + + + + + + + +Kennedy Informational [Page 5] + +RFC 3252 Binary Lexical Octet Ad-hoc Transport 1 April 2002 + + + To calculate the length and checksum fields of the UDP element, a + canonicalized form of the element MUST be used as in section 2.1. An + iterative method SHOULD be used to calculate checksums as in section + 2.1. + + The payload element MUST be encoded as in section 2.1. + + UDPoXML datagrams encapsulated by IPoXML MAY omit the <?xml?> header + as well as the <!DOCTYPE> declaration. + +4.2. Example Datagram + + The following is an example UDPoXML datagram with an empty payload: + + <?xml version="1.0" encoding="UTF-8"?> + <!DOCTYPE udp PUBLIC "-//IETF//DTD BLOAT 1.0 UDP//EN" "bloat.dtd"> + <udp> + <udp.header> + <src port="31415"/> + <dest port="42424"/> + <udp.length value="143"/> + <checksum value="2988"/> + </udp.header> + <payload> + </payload> + </udp> + +5. Network Transport + + This document provides for the transmission of BLOAT datagrams over + two common families of physical layer transport. Future RFCs will + address additional transports as routing vendors catch up to the + specification, and we begin to see BLOAT routed across the Internet + backbone. + +5.1. Ethernet + + BLOAT is encapsulated in Ethernet datagrams as in [RFC894] with the + exception that the type field of the Ethernet frame MUST contain the + value 0xBEEF. The first 5 octets of the Ethernet frame payload will + be 0x3c 3f 78 6d 6c ("<?xml".) + +5.2. IEEE 802 + + BLOAT is encapsulated in IEEE 802 Networks as in [RFC1042] except + that the protocol type code for IPoXML is 0xBEEF. + + + + + +Kennedy Informational [Page 6] + +RFC 3252 Binary Lexical Octet Ad-hoc Transport 1 April 2002 + + +6. Gatewaying over IP + + In order to facilitate the gradual introduction of BLOAT into the + public Internet, BLOAT MAY be encapsulated in IP as in [RFC2003] to + gateway between networks that run BLOAT natively on their LANs. + +7. DTDs + + The Transport DTDs (7.2. and 7.3.) build on the definitions in the + Network DTD (7.1.) + + The DTDs are referenced by their PubidLiteral and SystemLiteral (from + [XML]) although it is understood that most IPoXML implementations + will not need to pull down the DTD, as it will normally be embedded + in the implementation, and presents something of a catch-22 if you + need to load part of your network protocol over the network. + +7.1. IPoXML DTD + + <!-- + DTD for IP over XML. + Refer to this DTD as: + + <!DOCTYPE ip PUBLIC "-//IETF//DTD BLOAT 1.0 IP//EN" "bloat.dtd"> + --> + <!-- + DTD data types: + + Digits [0..9]+ + + Precedence "NetworkControl | InternetworkControl | + CRITIC | FlashOverride | Flash | Immediate | + Priority | Routine" + + IP4Addr "dotted-decimal" notation of [RFC1123] + + Class [0..3] + + Sec "Unclassified | Confidential | EFTO | MMMM | PROG | + Restricted | Secret | Top Secret | Reserved" + + Compartments [0..65535] + + Handling [0..65535] + + TCC [0..16777216] + + --> + + + +Kennedy Informational [Page 7] + +RFC 3252 Binary Lexical Octet Ad-hoc Transport 1 April 2002 + + + <!ENTITY % Digits "CDATA"> + <!ENTITY % Precedence "CDATA"> + <!ENTITY % IP4Addr "CDATA"> + <!ENTITY % Class "CDATA"> + <!ENTITY % Sec "CDATA"> + <!ENTITY % Compartments "CDATA"> + <!ENTITY % Handling "CDATA"> + <!ENTITY % TCC "CDATA"> + + <!ELEMENT ip (header, payload)> + + <!ELEMENT header (version, tos, total.length, id, flags, offset, ttl, + protocol, checksum, source, destination, options, + padding)> + <!-- length of header in 32-bit words --> + <!ATTLIST header + length %Digits; #REQUIRED> + + <!ELEMENT version EMPTY> + <!-- ip version. SHOULD be "4" --> + <!ATTLIST version + value %Digits; #REQUIRED> + + <!ELEMENT tos EMPTY> + <!ATTLIST tos + precedence %Precedence; #REQUIRED + delay (normal | low) #REQUIRED + throughput (normal | high) #REQUIRED + relibility (normal | high) #REQUIRED + reserved CDATA #FIXED "0"> + + <!ELEMENT total.length EMPTY> + <!-- + total length of datagram (header and payload) in octets, MUST be + less than 65,535 (and SHOULD be less than 1024 for IPoXML on local + ethernets). + --> + <!ATTLIST total.length + value %Digits; #REQUIRED> + + <!ELEMENT id EMPTY> + <!-- 0 <= id <= 65,535 --> + <!ATTLIST id + value %Digits; #REQUIRED> + + <!ELEMENT flags EMPTY> + <!-- df = don't fragment, mf = more fragments --> + <!ATTLIST flags + + + +Kennedy Informational [Page 8] + +RFC 3252 Binary Lexical Octet Ad-hoc Transport 1 April 2002 + + + reserved CDATA #FIXED "0" + df (may|dont) #REQUIRED + mf (last|more) #REQUIRED> + + <!ELEMENT offset EMPTY> + <!-- 0 <= offset <= 8192 measured in 8 octet (64-bit) chunks --> + <!ATTLIST offset + value %Digits; #REQUIRED> + + <!ELEMENT ttl EMPTY> + <!-- 0 <= ttl <= 255 --> + <!ATTLIST ttl + value %Digits; #REQUIRED> + + <!ELEMENT protocol EMPTY> + <!-- 0 <= protocol <= 255 (per IANA) --> + <!ATTLIST protocol + value %Digits; #REQUIRED> + + <!ELEMENT checksum EMPTY> + <!-- 0 <= checksum <= 65535 (over header only) --> + <!ATTLIST checksum + value %Digits; #REQUIRED> + + <!ELEMENT source EMPTY> + <!ATTLIST source + address %IP4Addr; #REQUIRED> + + <!ELEMENT destination EMPTY> + <!ATTLIST destination + address %IP4Addr; #REQUIRED> + + <!ELEMENT options ( end | noop | security | loose | strict | record + | stream | timestamp )*> + + <!ELEMENT end EMPTY> + <!ATTLIST end + copied (0|1) #REQUIRED + class CDATA #FIXED "0" + number CDATA #FIXED "0"> + + <!ELEMENT noop EMPTY> + <!ATTLIST noop + copied (0|1) #REQUIRED + class CDATA #FIXED "0" + number CDATA #FIXED "1"> + + <!ELEMENT security EMPTY> + + + +Kennedy Informational [Page 9] + +RFC 3252 Binary Lexical Octet Ad-hoc Transport 1 April 2002 + + + <!ATTLIST security + copied CDATA #FIXED "1" + class CDATA #FIXED "0" + number CDATA #FIXED "2" + length CDATA #FIXED "11" + security %Sec; #REQUIRED + compartments %Compartments; #REQUIRED + handling %Handling; #REQUIRED + tcc %TCC; #REQUIRED> + <!ELEMENT loose (hop)+> + <!ATTLIST loose + copied CDATA #FIXED "1" + class CDATA #FIXED "0" + number CDATA #FIXED "3" + length %Digits; #REQUIRED + pointer %Digits; #REQUIRED> + + <!ELEMENT hop EMPTY> + <!ATTLIST hop + address %IP4Addr; #REQUIRED> + + <!ELEMENT strict (hop)+> + <!ATTLIST strict + copied CDATA #FIXED "1" + class CDATA #FIXED "0" + number CDATA #FIXED "9" + length %Digits; #REQUIRED + pointer %Digits; #REQUIRED> + + <!ELEMENT record (hop)+> + <!ATTLIST record + copied CDATA #FIXED "0" + class CDATA #FIXED "0" + number CDATA #FIXED "7" + length %Digits; #REQUIRED + pointer %Digits; #REQUIRED> + + <!ELEMENT stream EMPTY> + <!-- 0 <= id <= 65,535 --> + <!ATTLIST stream + copied CDATA #FIXED "1" + class CDATA #FIXED "0" + number CDATA #FIXED "8" + length CDATA #FIXED "4" + id %Digits; #REQUIRED> + + <!ELEMENT timestamp (tstamp)+> + <!-- 0 <= oflw <=15 --> + + + +Kennedy Informational [Page 10] + +RFC 3252 Binary Lexical Octet Ad-hoc Transport 1 April 2002 + + + <!ATTLIST timestamp + copied CDATA #FIXED "0" + class CDATA #FIXED "2" + number CDATA #FIXED "4" + length %Digits; #REQUIRED + pointer %Digits; #REQUIRED + oflw %Digits; #REQUIRED + flag (0 | 1 | 3) #REQUIRED> + + <!ELEMENT tstamp EMPTY> + <!ATTLIST tstamp + time %Digits; #REQUIRED + address %IP4Addr; #IMPLIED> + <!-- + padding to bring header to 32-bit boundary. + pad MUST be "0"* + --> + <!ELEMENT padding EMPTY> + <!ATTLIST padding + pad CDATA #REQUIRED> + + <!-- payload MUST be encoded as base-64 [RFC2045], as modified + by section 2.1 of this RFC --> + <!ELEMENT payload (CDATA)> + +7.2. TCPoXML DTD + + <!-- + DTD for TCP over XML. + Refer to this DTD as: + + <!DOCTYPE tcp PUBLIC "-//IETF//DTD BLOAT 1.0 TCP//EN" "bloat.dtd"> + --> + + <!-- the pseudoheader is only included for checksum calculations --> + <!ELEMENT tcp (tcp.pseudoheader?, tcp.header, payload)> + + <!ELEMENT tcp.header (src, dest, sequence, acknowledgement, offset, + reserved, control, window, checksum, urgent, + tcp.options, padding)> + + <!ELEMENT src EMPTY> + <!-- 0 <= port <= 65,535 --> + <!ATTLIST src + port %Digits; #REQUIRED> + + <!ELEMENT dest EMPTY> + <!-- 0 <= port <= 65,535 --> + + + +Kennedy Informational [Page 11] + +RFC 3252 Binary Lexical Octet Ad-hoc Transport 1 April 2002 + + + <!ATTLIST dest + port %Digits; #REQUIRED> + + <!ELEMENT sequence EMPTY> + <!-- 0 <= number <= 4294967295 --> + <!ATTLIST sequence + number %Digits; #REQUIRED> + + <!ELEMENT acknowledgement EMPTY> + <!-- 0 <= number <= 4294967295 --> + <!ATTLIST acknowledgement + number %Digits; #REQUIRED> + + <!ELEMENT offset EMPTY> + <!-- 0 <= number <= 255 --> + <!ATTLIST offset + number %Digits; #REQUIRED> + + <!ELEMENT reserved EMPTY> + <!ATTLIST reserved + value CDATA #FIXED "0"> + + <!ELEMENT control EMPTY> + <!ATTLIST control + urg (0|1) #IMPLIED + ack (0|1) #IMPLIED + psh (0|1) #IMPLIED + rst (0|1) #IMPLIED + syn (0|1) #IMPLIED + fin (0|1) #IMPLIED> + + <!ELEMENT window EMPTY> + <!-- 0 <= size <= 65,535 --> + <!ATTLIST window + size %Digits; #REQUIRED> + + <!-- + checksum as in ip, but with + the following pseudo-header added into the tcp element: + --> + <!ELEMENT tcp.pseudoheader (source, destination, protocol, + tcp.length)> + + <!-- + tcp header + data length in octets. does not include the size of + + the pseudoheader. + --> + + + +Kennedy Informational [Page 12] + +RFC 3252 Binary Lexical Octet Ad-hoc Transport 1 April 2002 + + + <!ELEMENT tcp.length EMPTY> + <!ATTLIST tcp.length + value %Digits; #REQUIRED> + + <!ELEMENT urgent EMPTY> + <!-- 0 <= pointer <= 65,535 --> + <!ATTLIST urgent + pointer %Digits; #REQUIRED> + + <!ELEMENT tcp.options (tcp.end | tcp.noop | tcp.mss)+> + + <!ELEMENT tcp.end EMPTY> + <!ATTLIST tcp.end + kind CDATA #FIXED "0"> + + <!ELEMENT tcp.noop EMPTY> + <!ATTLIST tcp.noop + kind CDATA #FIXED "1"> + + <!ELEMENT tcp.mss EMPTY> + <!ATTLIST tcp.mss + kind CDATA #FIXED "2" + length CDATA #FIXED "4" + size %Digits; #REQUIRED> + +7.3. UDPoXML DTD + + <!-- + DTD for UDP over XML. + Refer to this DTD as: + + <!DOCTYPE udp PUBLIC "-//IETF//DTD BLOAT 1.0 UDP//EN" "bloat.dtd"> + --> + + <!ELEMENT udp (udp.pseudoheader?, udp.header, payload)> + + <!ELEMENT udp.header (src, dest, udp.length, checksum)> + + <!ELEMENT udp.pseudoheader (source, destination, protocol, + udp.length)> + + <!-- + udp header + data length in octets. does not include the size of + the pseudoheader. + --> + <!ELEMENT udp.length EMPTY> + <!ATTLIST udp.length + value %Digits; #REQUIRED> + + + +Kennedy Informational [Page 13] + +RFC 3252 Binary Lexical Octet Ad-hoc Transport 1 April 2002 + + +8. Security Considerations + + XML, as a subset of SGML, has the same security considerations as + specified in SGML Media Types [RFC1874]. Security considerations + that apply to IP, TCP and UDP also likely apply to BLOAT as it does + not attempt to correct for issues not related to message format. + +9. References + + [JABBER] Miller, J., "Jabber", draft-miller-jabber-00.txt, + February 2002. (Work in Progress) + + [RFC768] Postel, J., "User Datagram Protocol", STD 6, RFC 768, + August 1980. + + [RFC791] Postel, J., "Internet Protocol", STD 5, RFC 791, + September 1981. + + [RFC793] Postel, J., "Transmission Control Protocol", STD 7, RFC + 793, September 1981. + + [RFC894] Hornig, C., "Standard for the Transmission of IP + Datagrams over Ethernet Networks.", RFC 894, April 1984. + + [RFC1042] Postel, J. and J. Reynolds, "Standard for the + Transmission of IP Datagrams Over IEEE 802 Networks", STD + 43, RFC 1042, February 1988. + + [RFC1123] Braden, R., "Requirements for Internet Hosts - + Application and Support", RFC 1123, October 1989. + + [RFC1874] Levinson, E., "SGML Media Types", RFC 1874, December + 1995. + + [RFC2003] Perkins, C., "IP Encapsulation within IP", RFC 2003, + October 1996. + + [RFC2045] Freed, N. and N. Borenstein, "Multipurpose Internet Mail + Extensions (MIME) Part One: Format of Internet Message + Bodies", RFC 2045, November 1996. + + [RFC2119] Bradner, S., "Key words for use in RFCs to Indicate + Requirement Levels", BCP 14, RFC 2119, March 1997. + + [RFC2279] Yergeau, F., "UTF-8, a transformation format of ISO + 10646", RFC 2279, January 1998. + + + + + +Kennedy Informational [Page 14] + +RFC 3252 Binary Lexical Octet Ad-hoc Transport 1 April 2002 + + + [RFC2460] Deering, S. and R. Hinden, "Internet Protocol, Version 6 + (IPv6) Specification", RFC 2460, December 1998. + + [RFC3080] Rose, M., "The Blocks Extensible Exchange Protocol Core", + RFC 3080, March 2001. + + [SOAP] Box, D., Ehnebuske, D., Kakivaya, G., Layman, A., + Mendelsohn, N., Nielsen, H. F., Thatte, S. Winer, D., + "Simple Object Access Protocol (SOAP) 1.1" World Wide Web + Consortium Note, May 2000 http://www.w3.org/TR/SOAP/ + + [XML] Bray, T., Paoli, J., Sperberg-McQueen, C. M., "Extensible + Markup Language (XML)" World Wide Web Consortium + Recommendation REC- xml-19980210. + http://www.w3.org/TR/1998/REC-xml-19980210 + +10. Author's Address + + Hugh Kennedy + Mimezine + 1060 West Addison + Chicago, IL 60613 + USA + + EMail: kennedyh@engin.umich.edu + + + + + + + + + + + + + + + + + + + + + + + + + + +Kennedy Informational [Page 15] + +RFC 3252 Binary Lexical Octet Ad-hoc Transport 1 April 2002 + + +11. Full Copyright Statement + + Copyright (C) The Internet Society (2002). All Rights Reserved. + + This document and translations of it may be copied and furnished to + others, and derivative works that comment on or otherwise explain it + or assist in its implementation may be prepared, copied, published + and distributed, in whole or in part, without restriction of any + kind, provided that the above copyright notice and this paragraph are + included on all such copies and derivative works. However, this + document itself may not be modified in any way, such as by removing + the copyright notice or references to the Internet Society or other + Internet organizations, except as needed for the purpose of + developing Internet standards in which case the procedures for + copyrights defined in the Internet Standards process must be + followed, or as required to translate it into languages other than + English. + + The limited permissions granted above are perpetual and will not be + revoked by the Internet Society or its successors or assigns. + + This document and the information contained herein is provided on an + "AS IS" basis and THE INTERNET SOCIETY AND THE INTERNET ENGINEERING + TASK FORCE DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING + BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE INFORMATION + HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED WARRANTIES OF + MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. + +Acknowledgement + + Funding for the RFC Editor function is currently provided by the + Internet Society. + + + + + + + + + + + + + + + + + + + +Kennedy Informational [Page 16] + diff --git a/tests/auto/network/access/qhttp/webserver/rfc3252.txt b/tests/auto/network/access/qhttp/webserver/rfc3252.txt new file mode 100644 index 0000000000..b80c61bf0a --- /dev/null +++ b/tests/auto/network/access/qhttp/webserver/rfc3252.txt @@ -0,0 +1,899 @@ + + + + + + +Network Working Group H. Kennedy +Request for Comments: 3252 Mimezine +Category: Informational 1 April 2002 + + + Binary Lexical Octet Ad-hoc Transport + +Status of this Memo + + This memo provides information for the Internet community. It does + not specify an Internet standard of any kind. Distribution of this + memo is unlimited. + +Copyright Notice + + Copyright (C) The Internet Society (2002). All Rights Reserved. + +Abstract + + This document defines a reformulation of IP and two transport layer + protocols (TCP and UDP) as XML applications. + +1. Introduction + +1.1. Overview + + This document describes the Binary Lexical Octet Ad-hoc Transport + (BLOAT): a reformulation of a widely-deployed network-layer protocol + (IP [RFC791]), and two associated transport layer protocols (TCP + [RFC793] and UDP [RFC768]) as XML [XML] applications. It also + describes methods for transporting BLOAT over Ethernet and IEEE 802 + networks as well as encapsulating BLOAT in IP for gatewaying BLOAT + across the public Internet. + +1.2. Motivation + + The wild popularity of XML as a basis for application-level protocols + such as the Blocks Extensible Exchange Protocol [RFC3080], the Simple + Object Access Protocol [SOAP], and Jabber [JABBER] prompted + investigation into the possibility of extending the use of XML in the + protocol stack. Using XML at both the transport and network layer in + addition to the application layer would provide for an amazing amount + of power and flexibility while removing dependencies on proprietary + and hard-to-understand binary protocols. This protocol unification + would also allow applications to use a single XML parser for all + aspects of their operation, eliminating developer time spent figuring + out the intricacies of each new protocol, and moving the hard work of + + + + +Kennedy Informational [Page 1] + +RFC 3252 Binary Lexical Octet Ad-hoc Transport 1 April 2002 + + + parsing to the XML toolset. The use of XML also mitigates concerns + over "network vs. host" byte ordering which is at the root of many + network application bugs. + +1.3. Relation to Existing Protocols + + The reformulations specified in this RFC follow as closely as + possible the spirit of the RFCs on which they are based, and so MAY + contain elements or attributes that would not be needed in a pure + reworking (e.g. length attributes, which are implicit in XML.) + + The layering of network and transport protocols are maintained in + this RFC despite the optimizations that could be made if the line + were somewhat blurred (i.e. merging TCP and IP into a single, larger + element in the DTD) in order to foster future use of this protocol as + a basis for reformulating other protocols (such as ICMP.) + + Other than the encoding, the behavioral aspects of each of the + existing protocols remain unchanged. Routing, address spaces, TCP + congestion control, etc. behave as specified in the extant standards. + Adapting to new standards and experimental algorithm heuristics for + improving performance will become much easier once the move to BLOAT + has been completed. + +1.4. Requirement Levels + + The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", + "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this + document are to be interpreted as described in BCP 14, RFC 2119 + [RFC2119]. + +2. IPoXML + + This protocol MUST be implemented to be compliant with this RFC. + IPoXML is the root protocol REQUIRED for effective use of TCPoXML + (section 3.) and higher-level application protocols. + + The DTD for this document type can be found in section 7.1. + + The routing of IPoXML can be easily implemented on hosts with an XML + parser, as the regular structure lends itself handily to parsing and + validation of the document/datagram and then processing the + destination address, TTL, and checksum before sending it on to its + next-hop. + + The reformulation of IPv4 was chosen over IPv6 [RFC2460] due to the + wider deployment of IPv4 and the fact that implementing IPv6 as XML + would have exceeded the 1500 byte Ethernet MTU. + + + +Kennedy Informational [Page 2] + +RFC 3252 Binary Lexical Octet Ad-hoc Transport 1 April 2002 + + + All BLOAT implementations MUST use - and specify - the UTF-8 encoding + of RFC 2279 [RFC2279]. All BLOAT document/datagrams MUST be well- + formed and include the XMLDecl. + +2.1. IP Description + + A number of items have changed (for the better) from the original IP + specification. Bit-masks, where present have been converted into + human-readable values. IP addresses are listed in their dotted- + decimal notation [RFC1123]. Length and checksum values are present + as decimal integers. + + To calculate the length and checksum fields of the IP element, a + canonicalized form of the element MUST be used. The canonical form + SHALL have no whitespace (including newline characters) between + elements and only one space character between attributes. There + SHALL NOT be a space following the last attribute in an element. + + An iterative method SHOULD be used to calculate checksums, as the + length field will vary based on the size of the checksum. + + The payload element bears special attention. Due to the character + set restrictions of XML, the payload of IP datagrams (which MAY + contain arbitrary data) MUST be encoded for transport. This RFC + REQUIRES the contents of the payload to be encoded in the base-64 + encoding of RFC 2045 [RFC2045], but removes the requirement that the + encoded output MUST be wrapped on 76-character lines. + + + + + + + + + + + + + + + + + + + + + + + + +Kennedy Informational [Page 3] + +RFC 3252 Binary Lexical Octet Ad-hoc Transport 1 April 2002 + + +2.2. Example Datagram + + The following is an example IPoXML datagram with an empty payload: + + <?xml version="1.0" encoding="UTF-8"?> + <!DOCTYPE ip PUBLIC "-//IETF//DTD BLOAT 1.0 IP//EN" "bloat.dtd"> + <ip> + <header length="474"> + <version value="4"/> + <tos precedence="Routine" delay="Normal" throughput="Normal" + relibility="Normal" reserved="0"/> + <total.length value="461"/> + <id value="1"/> + <flags reserved="0" df="dont" mf="last"/> + <offset value="0"/> + <ttl value="255"/> + <protocol value="6"/> + <checksum value="8707"/> + <source address="10.0.0.22"/> + <destination address="10.0.0.1"/> + <options> + <end copied="0" class="0" number="0"/> + </options> + <padding pad="0"/> + </header> + <payload> + </payload> + </ip> + +3. TCPoXML + + This protocol MUST be implemented to be compliant with this RFC. The + DTD for this document type can be found in section 7.2. + +3.1. TCP Description + + A number of items have changed from the original TCP specification. + Bit-masks, where present have been converted into human-readable + values. Length and checksum and port values are present as decimal + integers. + + To calculate the length and checksum fields of the TCP element, a + canonicalized form of the element MUST be used as in section 2.1. + + An iterative method SHOULD be used to calculate checksums as in + section 2.1. + + The payload element MUST be encoded as in section 2.1. + + + +Kennedy Informational [Page 4] + +RFC 3252 Binary Lexical Octet Ad-hoc Transport 1 April 2002 + + + The TCP offset element was expanded to a maximum of 255 from 16 to + allow for the increased size of the header in XML. + + TCPoXML datagrams encapsulated by IPoXML MAY omit the <?xml?> header + as well as the <!DOCTYPE> declaration. + +3.2. Example Datagram + + The following is an example TCPoXML datagram with an empty payload: + + <?xml version="1.0" encoding="UTF-8"?> + <!DOCTYPE tcp PUBLIC "-//IETF//DTD BLOAT 1.0 TCP//EN" "bloat.dtd"> + <tcp> + <tcp.header> + <src port="31415"/> + <dest port="42424"/> + <sequence number="322622954"/> + <acknowledgement number="689715995"/> + <offset number=""/> + <reserved value="0"/> + <control syn="1" ack="1"/> + <window size="1"/> + <urgent pointer="0"/> + <checksum value="2988"/> + <tcp.options> + <tcp.end kind="0"/> + </tcp.options> + <padding pad="0"/> + </tcp.header> + <payload> + </payload> + </tcp> + +4. UDPoXML + + This protocol MUST be implemented to be compliant with this RFC. The + DTD for this document type can be found in section 7.3. + +4.1. UDP Description + + A number of items have changed from the original UDP specification. + Bit-masks, where present have been converted into human-readable + values. Length and checksum and port values are present as decimal + integers. + + + + + + + +Kennedy Informational [Page 5] + +RFC 3252 Binary Lexical Octet Ad-hoc Transport 1 April 2002 + + + To calculate the length and checksum fields of the UDP element, a + canonicalized form of the element MUST be used as in section 2.1. An + iterative method SHOULD be used to calculate checksums as in section + 2.1. + + The payload element MUST be encoded as in section 2.1. + + UDPoXML datagrams encapsulated by IPoXML MAY omit the <?xml?> header + as well as the <!DOCTYPE> declaration. + +4.2. Example Datagram + + The following is an example UDPoXML datagram with an empty payload: + + <?xml version="1.0" encoding="UTF-8"?> + <!DOCTYPE udp PUBLIC "-//IETF//DTD BLOAT 1.0 UDP//EN" "bloat.dtd"> + <udp> + <udp.header> + <src port="31415"/> + <dest port="42424"/> + <udp.length value="143"/> + <checksum value="2988"/> + </udp.header> + <payload> + </payload> + </udp> + +5. Network Transport + + This document provides for the transmission of BLOAT datagrams over + two common families of physical layer transport. Future RFCs will + address additional transports as routing vendors catch up to the + specification, and we begin to see BLOAT routed across the Internet + backbone. + +5.1. Ethernet + + BLOAT is encapsulated in Ethernet datagrams as in [RFC894] with the + exception that the type field of the Ethernet frame MUST contain the + value 0xBEEF. The first 5 octets of the Ethernet frame payload will + be 0x3c 3f 78 6d 6c ("<?xml".) + +5.2. IEEE 802 + + BLOAT is encapsulated in IEEE 802 Networks as in [RFC1042] except + that the protocol type code for IPoXML is 0xBEEF. + + + + + +Kennedy Informational [Page 6] + +RFC 3252 Binary Lexical Octet Ad-hoc Transport 1 April 2002 + + +6. Gatewaying over IP + + In order to facilitate the gradual introduction of BLOAT into the + public Internet, BLOAT MAY be encapsulated in IP as in [RFC2003] to + gateway between networks that run BLOAT natively on their LANs. + +7. DTDs + + The Transport DTDs (7.2. and 7.3.) build on the definitions in the + Network DTD (7.1.) + + The DTDs are referenced by their PubidLiteral and SystemLiteral (from + [XML]) although it is understood that most IPoXML implementations + will not need to pull down the DTD, as it will normally be embedded + in the implementation, and presents something of a catch-22 if you + need to load part of your network protocol over the network. + +7.1. IPoXML DTD + + <!-- + DTD for IP over XML. + Refer to this DTD as: + + <!DOCTYPE ip PUBLIC "-//IETF//DTD BLOAT 1.0 IP//EN" "bloat.dtd"> + --> + <!-- + DTD data types: + + Digits [0..9]+ + + Precedence "NetworkControl | InternetworkControl | + CRITIC | FlashOverride | Flash | Immediate | + Priority | Routine" + + IP4Addr "dotted-decimal" notation of [RFC1123] + + Class [0..3] + + Sec "Unclassified | Confidential | EFTO | MMMM | PROG | + Restricted | Secret | Top Secret | Reserved" + + Compartments [0..65535] + + Handling [0..65535] + + TCC [0..16777216] + + --> + + + +Kennedy Informational [Page 7] + +RFC 3252 Binary Lexical Octet Ad-hoc Transport 1 April 2002 + + + <!ENTITY % Digits "CDATA"> + <!ENTITY % Precedence "CDATA"> + <!ENTITY % IP4Addr "CDATA"> + <!ENTITY % Class "CDATA"> + <!ENTITY % Sec "CDATA"> + <!ENTITY % Compartments "CDATA"> + <!ENTITY % Handling "CDATA"> + <!ENTITY % TCC "CDATA"> + + <!ELEMENT ip (header, payload)> + + <!ELEMENT header (version, tos, total.length, id, flags, offset, ttl, + protocol, checksum, source, destination, options, + padding)> + <!-- length of header in 32-bit words --> + <!ATTLIST header + length %Digits; #REQUIRED> + + <!ELEMENT version EMPTY> + <!-- ip version. SHOULD be "4" --> + <!ATTLIST version + value %Digits; #REQUIRED> + + <!ELEMENT tos EMPTY> + <!ATTLIST tos + precedence %Precedence; #REQUIRED + delay (normal | low) #REQUIRED + throughput (normal | high) #REQUIRED + relibility (normal | high) #REQUIRED + reserved CDATA #FIXED "0"> + + <!ELEMENT total.length EMPTY> + <!-- + total length of datagram (header and payload) in octets, MUST be + less than 65,535 (and SHOULD be less than 1024 for IPoXML on local + ethernets). + --> + <!ATTLIST total.length + value %Digits; #REQUIRED> + + <!ELEMENT id EMPTY> + <!-- 0 <= id <= 65,535 --> + <!ATTLIST id + value %Digits; #REQUIRED> + + <!ELEMENT flags EMPTY> + <!-- df = don't fragment, mf = more fragments --> + <!ATTLIST flags + + + +Kennedy Informational [Page 8] + +RFC 3252 Binary Lexical Octet Ad-hoc Transport 1 April 2002 + + + reserved CDATA #FIXED "0" + df (may|dont) #REQUIRED + mf (last|more) #REQUIRED> + + <!ELEMENT offset EMPTY> + <!-- 0 <= offset <= 8192 measured in 8 octet (64-bit) chunks --> + <!ATTLIST offset + value %Digits; #REQUIRED> + + <!ELEMENT ttl EMPTY> + <!-- 0 <= ttl <= 255 --> + <!ATTLIST ttl + value %Digits; #REQUIRED> + + <!ELEMENT protocol EMPTY> + <!-- 0 <= protocol <= 255 (per IANA) --> + <!ATTLIST protocol + value %Digits; #REQUIRED> + + <!ELEMENT checksum EMPTY> + <!-- 0 <= checksum <= 65535 (over header only) --> + <!ATTLIST checksum + value %Digits; #REQUIRED> + + <!ELEMENT source EMPTY> + <!ATTLIST source + address %IP4Addr; #REQUIRED> + + <!ELEMENT destination EMPTY> + <!ATTLIST destination + address %IP4Addr; #REQUIRED> + + <!ELEMENT options ( end | noop | security | loose | strict | record + | stream | timestamp )*> + + <!ELEMENT end EMPTY> + <!ATTLIST end + copied (0|1) #REQUIRED + class CDATA #FIXED "0" + number CDATA #FIXED "0"> + + <!ELEMENT noop EMPTY> + <!ATTLIST noop + copied (0|1) #REQUIRED + class CDATA #FIXED "0" + number CDATA #FIXED "1"> + + <!ELEMENT security EMPTY> + + + +Kennedy Informational [Page 9] + +RFC 3252 Binary Lexical Octet Ad-hoc Transport 1 April 2002 + + + <!ATTLIST security + copied CDATA #FIXED "1" + class CDATA #FIXED "0" + number CDATA #FIXED "2" + length CDATA #FIXED "11" + security %Sec; #REQUIRED + compartments %Compartments; #REQUIRED + handling %Handling; #REQUIRED + tcc %TCC; #REQUIRED> + <!ELEMENT loose (hop)+> + <!ATTLIST loose + copied CDATA #FIXED "1" + class CDATA #FIXED "0" + number CDATA #FIXED "3" + length %Digits; #REQUIRED + pointer %Digits; #REQUIRED> + + <!ELEMENT hop EMPTY> + <!ATTLIST hop + address %IP4Addr; #REQUIRED> + + <!ELEMENT strict (hop)+> + <!ATTLIST strict + copied CDATA #FIXED "1" + class CDATA #FIXED "0" + number CDATA #FIXED "9" + length %Digits; #REQUIRED + pointer %Digits; #REQUIRED> + + <!ELEMENT record (hop)+> + <!ATTLIST record + copied CDATA #FIXED "0" + class CDATA #FIXED "0" + number CDATA #FIXED "7" + length %Digits; #REQUIRED + pointer %Digits; #REQUIRED> + + <!ELEMENT stream EMPTY> + <!-- 0 <= id <= 65,535 --> + <!ATTLIST stream + copied CDATA #FIXED "1" + class CDATA #FIXED "0" + number CDATA #FIXED "8" + length CDATA #FIXED "4" + id %Digits; #REQUIRED> + + <!ELEMENT timestamp (tstamp)+> + <!-- 0 <= oflw <=15 --> + + + +Kennedy Informational [Page 10] + +RFC 3252 Binary Lexical Octet Ad-hoc Transport 1 April 2002 + + + <!ATTLIST timestamp + copied CDATA #FIXED "0" + class CDATA #FIXED "2" + number CDATA #FIXED "4" + length %Digits; #REQUIRED + pointer %Digits; #REQUIRED + oflw %Digits; #REQUIRED + flag (0 | 1 | 3) #REQUIRED> + + <!ELEMENT tstamp EMPTY> + <!ATTLIST tstamp + time %Digits; #REQUIRED + address %IP4Addr; #IMPLIED> + <!-- + padding to bring header to 32-bit boundary. + pad MUST be "0"* + --> + <!ELEMENT padding EMPTY> + <!ATTLIST padding + pad CDATA #REQUIRED> + + <!-- payload MUST be encoded as base-64 [RFC2045], as modified + by section 2.1 of this RFC --> + <!ELEMENT payload (CDATA)> + +7.2. TCPoXML DTD + + <!-- + DTD for TCP over XML. + Refer to this DTD as: + + <!DOCTYPE tcp PUBLIC "-//IETF//DTD BLOAT 1.0 TCP//EN" "bloat.dtd"> + --> + + <!-- the pseudoheader is only included for checksum calculations --> + <!ELEMENT tcp (tcp.pseudoheader?, tcp.header, payload)> + + <!ELEMENT tcp.header (src, dest, sequence, acknowledgement, offset, + reserved, control, window, checksum, urgent, + tcp.options, padding)> + + <!ELEMENT src EMPTY> + <!-- 0 <= port <= 65,535 --> + <!ATTLIST src + port %Digits; #REQUIRED> + + <!ELEMENT dest EMPTY> + <!-- 0 <= port <= 65,535 --> + + + +Kennedy Informational [Page 11] + +RFC 3252 Binary Lexical Octet Ad-hoc Transport 1 April 2002 + + + <!ATTLIST dest + port %Digits; #REQUIRED> + + <!ELEMENT sequence EMPTY> + <!-- 0 <= number <= 4294967295 --> + <!ATTLIST sequence + number %Digits; #REQUIRED> + + <!ELEMENT acknowledgement EMPTY> + <!-- 0 <= number <= 4294967295 --> + <!ATTLIST acknowledgement + number %Digits; #REQUIRED> + + <!ELEMENT offset EMPTY> + <!-- 0 <= number <= 255 --> + <!ATTLIST offset + number %Digits; #REQUIRED> + + <!ELEMENT reserved EMPTY> + <!ATTLIST reserved + value CDATA #FIXED "0"> + + <!ELEMENT control EMPTY> + <!ATTLIST control + urg (0|1) #IMPLIED + ack (0|1) #IMPLIED + psh (0|1) #IMPLIED + rst (0|1) #IMPLIED + syn (0|1) #IMPLIED + fin (0|1) #IMPLIED> + + <!ELEMENT window EMPTY> + <!-- 0 <= size <= 65,535 --> + <!ATTLIST window + size %Digits; #REQUIRED> + + <!-- + checksum as in ip, but with + the following pseudo-header added into the tcp element: + --> + <!ELEMENT tcp.pseudoheader (source, destination, protocol, + tcp.length)> + + <!-- + tcp header + data length in octets. does not include the size of + + the pseudoheader. + --> + + + +Kennedy Informational [Page 12] + +RFC 3252 Binary Lexical Octet Ad-hoc Transport 1 April 2002 + + + <!ELEMENT tcp.length EMPTY> + <!ATTLIST tcp.length + value %Digits; #REQUIRED> + + <!ELEMENT urgent EMPTY> + <!-- 0 <= pointer <= 65,535 --> + <!ATTLIST urgent + pointer %Digits; #REQUIRED> + + <!ELEMENT tcp.options (tcp.end | tcp.noop | tcp.mss)+> + + <!ELEMENT tcp.end EMPTY> + <!ATTLIST tcp.end + kind CDATA #FIXED "0"> + + <!ELEMENT tcp.noop EMPTY> + <!ATTLIST tcp.noop + kind CDATA #FIXED "1"> + + <!ELEMENT tcp.mss EMPTY> + <!ATTLIST tcp.mss + kind CDATA #FIXED "2" + length CDATA #FIXED "4" + size %Digits; #REQUIRED> + +7.3. UDPoXML DTD + + <!-- + DTD for UDP over XML. + Refer to this DTD as: + + <!DOCTYPE udp PUBLIC "-//IETF//DTD BLOAT 1.0 UDP//EN" "bloat.dtd"> + --> + + <!ELEMENT udp (udp.pseudoheader?, udp.header, payload)> + + <!ELEMENT udp.header (src, dest, udp.length, checksum)> + + <!ELEMENT udp.pseudoheader (source, destination, protocol, + udp.length)> + + <!-- + udp header + data length in octets. does not include the size of + the pseudoheader. + --> + <!ELEMENT udp.length EMPTY> + <!ATTLIST udp.length + value %Digits; #REQUIRED> + + + +Kennedy Informational [Page 13] + +RFC 3252 Binary Lexical Octet Ad-hoc Transport 1 April 2002 + + +8. Security Considerations + + XML, as a subset of SGML, has the same security considerations as + specified in SGML Media Types [RFC1874]. Security considerations + that apply to IP, TCP and UDP also likely apply to BLOAT as it does + not attempt to correct for issues not related to message format. + +9. References + + [JABBER] Miller, J., "Jabber", draft-miller-jabber-00.txt, + February 2002. (Work in Progress) + + [RFC768] Postel, J., "User Datagram Protocol", STD 6, RFC 768, + August 1980. + + [RFC791] Postel, J., "Internet Protocol", STD 5, RFC 791, + September 1981. + + [RFC793] Postel, J., "Transmission Control Protocol", STD 7, RFC + 793, September 1981. + + [RFC894] Hornig, C., "Standard for the Transmission of IP + Datagrams over Ethernet Networks.", RFC 894, April 1984. + + [RFC1042] Postel, J. and J. Reynolds, "Standard for the + Transmission of IP Datagrams Over IEEE 802 Networks", STD + 43, RFC 1042, February 1988. + + [RFC1123] Braden, R., "Requirements for Internet Hosts - + Application and Support", RFC 1123, October 1989. + + [RFC1874] Levinson, E., "SGML Media Types", RFC 1874, December + 1995. + + [RFC2003] Perkins, C., "IP Encapsulation within IP", RFC 2003, + October 1996. + + [RFC2045] Freed, N. and N. Borenstein, "Multipurpose Internet Mail + Extensions (MIME) Part One: Format of Internet Message + Bodies", RFC 2045, November 1996. + + [RFC2119] Bradner, S., "Key words for use in RFCs to Indicate + Requirement Levels", BCP 14, RFC 2119, March 1997. + + [RFC2279] Yergeau, F., "UTF-8, a transformation format of ISO + 10646", RFC 2279, January 1998. + + + + + +Kennedy Informational [Page 14] + +RFC 3252 Binary Lexical Octet Ad-hoc Transport 1 April 2002 + + + [RFC2460] Deering, S. and R. Hinden, "Internet Protocol, Version 6 + (IPv6) Specification", RFC 2460, December 1998. + + [RFC3080] Rose, M., "The Blocks Extensible Exchange Protocol Core", + RFC 3080, March 2001. + + [SOAP] Box, D., Ehnebuske, D., Kakivaya, G., Layman, A., + Mendelsohn, N., Nielsen, H. F., Thatte, S. Winer, D., + "Simple Object Access Protocol (SOAP) 1.1" World Wide Web + Consortium Note, May 2000 http://www.w3.org/TR/SOAP/ + + [XML] Bray, T., Paoli, J., Sperberg-McQueen, C. M., "Extensible + Markup Language (XML)" World Wide Web Consortium + Recommendation REC- xml-19980210. + http://www.w3.org/TR/1998/REC-xml-19980210 + +10. Author's Address + + Hugh Kennedy + Mimezine + 1060 West Addison + Chicago, IL 60613 + USA + + EMail: kennedyh@engin.umich.edu + + + + + + + + + + + + + + + + + + + + + + + + + + +Kennedy Informational [Page 15] + +RFC 3252 Binary Lexical Octet Ad-hoc Transport 1 April 2002 + + +11. Full Copyright Statement + + Copyright (C) The Internet Society (2002). All Rights Reserved. + + This document and translations of it may be copied and furnished to + others, and derivative works that comment on or otherwise explain it + or assist in its implementation may be prepared, copied, published + and distributed, in whole or in part, without restriction of any + kind, provided that the above copyright notice and this paragraph are + included on all such copies and derivative works. However, this + document itself may not be modified in any way, such as by removing + the copyright notice or references to the Internet Society or other + Internet organizations, except as needed for the purpose of + developing Internet standards in which case the procedures for + copyrights defined in the Internet Standards process must be + followed, or as required to translate it into languages other than + English. + + The limited permissions granted above are perpetual and will not be + revoked by the Internet Society or its successors or assigns. + + This document and the information contained herein is provided on an + "AS IS" basis and THE INTERNET SOCIETY AND THE INTERNET ENGINEERING + TASK FORCE DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING + BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE INFORMATION + HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED WARRANTIES OF + MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. + +Acknowledgement + + Funding for the RFC Editor function is currently provided by the + Internet Society. + + + + + + + + + + + + + + + + + + + +Kennedy Informational [Page 16] + diff --git a/tests/auto/network/access/qhttpnetworkconnection/.gitignore b/tests/auto/network/access/qhttpnetworkconnection/.gitignore new file mode 100644 index 0000000000..4fe208868b --- /dev/null +++ b/tests/auto/network/access/qhttpnetworkconnection/.gitignore @@ -0,0 +1 @@ +tst_qhttpnetworkconnection diff --git a/tests/auto/network/access/qhttpnetworkconnection/qhttpnetworkconnection.pro b/tests/auto/network/access/qhttpnetworkconnection/qhttpnetworkconnection.pro new file mode 100644 index 0000000000..1ce5d8a092 --- /dev/null +++ b/tests/auto/network/access/qhttpnetworkconnection/qhttpnetworkconnection.pro @@ -0,0 +1,13 @@ +load(qttest_p4) +SOURCES += tst_qhttpnetworkconnection.cpp +INCLUDEPATH += $$QT_SOURCE_TREE/src/3rdparty/zlib +requires(contains(QT_CONFIG,private_tests)) + +QT = core-private network-private + +symbian: TARGET.CAPABILITY = NetworkServices +symbian: { + INCLUDEPATH += $$MW_LAYER_SYSTEMINCLUDE +} + +CONFIG+=insignificant_test # QTBUG-20981, crashes sometimes diff --git a/tests/auto/network/access/qhttpnetworkconnection/tst_qhttpnetworkconnection.cpp b/tests/auto/network/access/qhttpnetworkconnection/tst_qhttpnetworkconnection.cpp new file mode 100644 index 0000000000..2d30f6bca1 --- /dev/null +++ b/tests/auto/network/access/qhttpnetworkconnection/tst_qhttpnetworkconnection.cpp @@ -0,0 +1,1131 @@ +/**************************************************************************** +** +** 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 test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** 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. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + + +#include <QtTest/QtTest> +#include "private/qhttpnetworkconnection_p.h" +#include "private/qnoncontiguousbytedevice_p.h" +#include <QAuthenticator> + +#include "../../../network-settings.h" + +class tst_QHttpNetworkConnection: public QObject +{ + Q_OBJECT + +public: + tst_QHttpNetworkConnection(); + +public Q_SLOTS: + void finishedReply(); + void finishedWithError(QNetworkReply::NetworkError errorCode, const QString &detail); + void challenge401(const QHttpNetworkRequest &request, QAuthenticator *authenticator); +#ifndef QT_NO_OPENSSL + void sslErrors(const QList<QSslError> &errors); +#endif +private: + bool finishedCalled; + bool finishedWithErrorCalled; + QNetworkReply::NetworkError netErrorCode; + +private Q_SLOTS: + void init(); + void cleanup(); + void initTestCase(); + void cleanupTestCase(); + + void options_data(); + void options(); + void get_data(); + void get(); + void head_data(); + void head(); + void post_data(); + void post(); + void put_data(); + void put(); + void _delete_data(); + void _delete(); + void trace_data(); + void trace(); + void _connect_data(); + void _connect(); +#ifndef QT_NO_COMPRESS + void compression_data(); + void compression(); +#endif +#ifndef QT_NO_OPENSSL + void ignoresslerror_data(); + void ignoresslerror(); +#endif +#ifdef QT_NO_OPENSSL + void nossl_data(); + void nossl(); +#endif + void get401_data(); + void get401(); + + void getMultiple_data(); + void getMultiple(); + void getMultipleWithPipeliningAndMultiplePriorities(); + void getMultipleWithPriorities(); + + void getEmptyWithPipelining(); + + void getAndEverythingShouldBePipelined(); + + void getAndThenDeleteObject(); + void getAndThenDeleteObject_data(); +}; + +tst_QHttpNetworkConnection::tst_QHttpNetworkConnection() +{ + Q_SET_DEFAULT_IAP +} + +void tst_QHttpNetworkConnection::initTestCase() +{ +} + +void tst_QHttpNetworkConnection::cleanupTestCase() +{ +} + +void tst_QHttpNetworkConnection::init() +{ +} + +void tst_QHttpNetworkConnection::cleanup() +{ +} + +void tst_QHttpNetworkConnection::options_data() +{ + // not tested yet +} + +void tst_QHttpNetworkConnection::options() +{ + QEXPECT_FAIL("", "not tested yet", Continue); + QVERIFY(false); +} + +void tst_QHttpNetworkConnection::head_data() +{ + QTest::addColumn<QString>("protocol"); + QTest::addColumn<QString>("host"); + QTest::addColumn<QString>("path"); + QTest::addColumn<ushort>("port"); + QTest::addColumn<bool>("encrypt"); + QTest::addColumn<int>("statusCode"); + QTest::addColumn<QString>("statusString"); + QTest::addColumn<int>("contentLength"); + + QTest::newRow("success-internal") << "http://" << QtNetworkSettings::serverName() << "/qtest/rfc3252.txt" << ushort(80) << false << 200 << "OK" << 25962; + QTest::newRow("success-external") << "http://" << "www.ietf.org" << "/rfc/rfc3252.txt" << ushort(80) << false << 200 << "OK" << 25962; + + QTest::newRow("failure-path") << "http://" << QtNetworkSettings::serverName() << "/t" << ushort(80) << false << 404 << "Not Found" << -1; + QTest::newRow("failure-protocol") << "" << QtNetworkSettings::serverName() << "/qtest/rfc3252.txt" << ushort(80) << false << 400 << "Bad Request" << -1; +} + +void tst_QHttpNetworkConnection::head() +{ + QFETCH(QString, protocol); + QFETCH(QString, host); + QFETCH(QString, path); + QFETCH(ushort, port); + QFETCH(bool, encrypt); + QFETCH(int, statusCode); + QFETCH(QString, statusString); + QFETCH(int, contentLength); + + QHttpNetworkConnection connection(host, port, encrypt); + QCOMPARE(connection.port(), port); + QCOMPARE(connection.hostName(), host); + QCOMPARE(connection.isSsl(), encrypt); + + QHttpNetworkRequest request(protocol + host + path, QHttpNetworkRequest::Head); + QHttpNetworkReply *reply = connection.sendRequest(request); + + QTime stopWatch; + stopWatch.start(); + do { + QCoreApplication::instance()->processEvents(); + if (stopWatch.elapsed() >= 30000) + break; + } while (!reply->isFinished()); + + QCOMPARE(reply->statusCode(), statusCode); + QCOMPARE(reply->reasonPhrase(), statusString); + // only check it if it is set and expected + if (reply->contentLength() != -1 && contentLength != -1) + QCOMPARE(reply->contentLength(), qint64(contentLength)); + + QVERIFY(reply->isFinished()); + + delete reply; +} + +void tst_QHttpNetworkConnection::get_data() +{ + QTest::addColumn<QString>("protocol"); + QTest::addColumn<QString>("host"); + QTest::addColumn<QString>("path"); + QTest::addColumn<ushort>("port"); + QTest::addColumn<bool>("encrypt"); + QTest::addColumn<int>("statusCode"); + QTest::addColumn<QString>("statusString"); + QTest::addColumn<int>("contentLength"); + QTest::addColumn<int>("downloadSize"); + + QTest::newRow("success-internal") << "http://" << QtNetworkSettings::serverName() << "/qtest/rfc3252.txt" << ushort(80) << false << 200 << "OK" << 25962 << 25962; + QTest::newRow("success-external") << "http://" << "www.ietf.org" << "/rfc/rfc3252.txt" << ushort(80) << false << 200 << "OK" << 25962 << 25962; + + QTest::newRow("failure-path") << "http://" << QtNetworkSettings::serverName() << "/t" << ushort(80) << false << 404 << "Not Found" << -1 << -1; + QTest::newRow("failure-protocol") << "" << QtNetworkSettings::serverName() << "/qtest/rfc3252.txt" << ushort(80) << false << 400 << "Bad Request" << -1 << -1; +} + +void tst_QHttpNetworkConnection::get() +{ + QFETCH(QString, protocol); + QFETCH(QString, host); + QFETCH(QString, path); + QFETCH(ushort, port); + QFETCH(bool, encrypt); + QFETCH(int, statusCode); + QFETCH(QString, statusString); + QFETCH(int, contentLength); + QFETCH(int, downloadSize); + + QHttpNetworkConnection connection(host, port, encrypt); + QCOMPARE(connection.port(), port); + QCOMPARE(connection.hostName(), host); + QCOMPARE(connection.isSsl(), encrypt); + + QHttpNetworkRequest request(protocol + host + path); + QHttpNetworkReply *reply = connection.sendRequest(request); + + QTime stopWatch; + stopWatch.start(); + forever { + QCoreApplication::instance()->processEvents(); + if (reply->bytesAvailable()) + break; + if (stopWatch.elapsed() >= 30000) + break; + } + + QCOMPARE(reply->statusCode(), statusCode); + QCOMPARE(reply->reasonPhrase(), statusString); + // only check it if it is set and expected + if (reply->contentLength() != -1 && contentLength != -1) + QCOMPARE(reply->contentLength(), qint64(contentLength)); + + stopWatch.start(); + QByteArray ba; + do { + QCoreApplication::instance()->processEvents(); + while (reply->bytesAvailable()) + ba += reply->readAny(); + if (stopWatch.elapsed() >= 30000) + break; + } while (!reply->isFinished()); + + QVERIFY(reply->isFinished()); + //do not require server generated error pages to be a fixed size + if (downloadSize != -1) + QCOMPARE(ba.size(), downloadSize); + //but check against content length if it was sent + if (reply->contentLength() != -1) + QCOMPARE(ba.size(), (int)reply->contentLength()); + + delete reply; +} + +void tst_QHttpNetworkConnection::finishedReply() +{ + finishedCalled = true; +} + +void tst_QHttpNetworkConnection::finishedWithError(QNetworkReply::NetworkError errorCode, const QString &detail) +{ + Q_UNUSED(detail) + finishedWithErrorCalled = true; + netErrorCode = errorCode; +} + +void tst_QHttpNetworkConnection::put_data() +{ + + QTest::addColumn<QString>("protocol"); + QTest::addColumn<QString>("host"); + QTest::addColumn<QString>("path"); + QTest::addColumn<ushort>("port"); + QTest::addColumn<bool>("encrypt"); + QTest::addColumn<QString>("data"); + QTest::addColumn<bool>("succeed"); + + QTest::newRow("success-internal") << "http://" << QtNetworkSettings::serverName() << "/dav/file1.txt" << ushort(80) << false << "Hello World\nEnd of file\n"<<true; + QTest::newRow("fail-internal") << "http://" << QtNetworkSettings::serverName() << "/dav2/file1.txt" << ushort(80) << false << "Hello World\nEnd of file\n"<<false; + QTest::newRow("fail-host") << "http://" << "fluke-nosuchhost.troll.no" << "/dav2/file1.txt" << ushort(80) << false << "Hello World\nEnd of file\n"<<false; +} + +void tst_QHttpNetworkConnection::put() +{ + QFETCH(QString, protocol); + QFETCH(QString, host); + QFETCH(QString, path); + QFETCH(ushort, port); + QFETCH(bool, encrypt); + QFETCH(QString, data); + QFETCH(bool, succeed); + + QHttpNetworkConnection connection(host, port, encrypt); + QCOMPARE(connection.port(), port); + QCOMPARE(connection.hostName(), host); + QCOMPARE(connection.isSsl(), encrypt); + + QHttpNetworkRequest request(protocol + host + path, QHttpNetworkRequest::Put); + + QByteArray array = data.toLatin1(); + QNonContiguousByteDevice *bd = QNonContiguousByteDeviceFactory::create(&array); + bd->setParent(this); + request.setUploadByteDevice(bd); + + finishedCalled = false; + finishedWithErrorCalled = false; + + QHttpNetworkReply *reply = connection.sendRequest(request); + connect(reply, SIGNAL(finished()), SLOT(finishedReply())); + connect(reply, SIGNAL(finishedWithError(QNetworkReply::NetworkError, const QString &)), + SLOT(finishedWithError(QNetworkReply::NetworkError, const QString &))); + + QTime stopWatch; + stopWatch.start(); + do { + QCoreApplication::instance()->processEvents(); + if (stopWatch.elapsed() >= 30000) + break; + } while (!reply->isFinished() && !finishedCalled && !finishedWithErrorCalled); + + if (reply->isFinished()) { + QByteArray ba; + while (reply->bytesAvailable()) + ba += reply->readAny(); + } else if(finishedWithErrorCalled) { + if(!succeed) { + delete reply; + return; + } else { + QFAIL("Error in PUT"); + } + } else { + QFAIL("PUT timed out"); + } + + int status = reply->statusCode(); + if (status != 200 && status != 201 && status != 204) { + if (succeed) { + qDebug()<<"PUT failed, Status Code:" <<status; + QFAIL("Error in PUT"); + } + } else { + if (!succeed) { + qDebug()<<"PUT Should fail, Status Code:" <<status; + QFAIL("Error in PUT"); + } + } + delete reply; +} + +void tst_QHttpNetworkConnection::post_data() +{ + QTest::addColumn<QString>("protocol"); + QTest::addColumn<QString>("host"); + QTest::addColumn<QString>("path"); + QTest::addColumn<ushort>("port"); + QTest::addColumn<bool>("encrypt"); + QTest::addColumn<QString>("data"); + QTest::addColumn<int>("statusCode"); + QTest::addColumn<QString>("statusString"); + QTest::addColumn<int>("contentLength"); + QTest::addColumn<int>("downloadSize"); + + QTest::newRow("success-internal") << "http://" << QtNetworkSettings::serverName() << "/qtest/cgi-bin/echo.cgi" << ushort(80) << false << "7 bytes" << 200 << "OK" << 7 << 7; + QTest::newRow("failure-internal") << "http://" << QtNetworkSettings::serverName() << "/t" << ushort(80) << false << "Hello World" << 404 << "Not Found" << -1 << -1; +} + +void tst_QHttpNetworkConnection::post() +{ + QFETCH(QString, protocol); + QFETCH(QString, host); + QFETCH(QString, path); + QFETCH(ushort, port); + QFETCH(bool, encrypt); + QFETCH(QString, data); + QFETCH(int, statusCode); + QFETCH(QString, statusString); + QFETCH(int, contentLength); + QFETCH(int, downloadSize); + + QHttpNetworkConnection connection(host, port, encrypt); + QCOMPARE(connection.port(), port); + QCOMPARE(connection.hostName(), host); + QCOMPARE(connection.isSsl(), encrypt); + + QHttpNetworkRequest request(protocol + host + path, QHttpNetworkRequest::Post); + + QByteArray array = data.toLatin1(); + QNonContiguousByteDevice *bd = QNonContiguousByteDeviceFactory::create(&array); + bd->setParent(this); + request.setUploadByteDevice(bd); + + QHttpNetworkReply *reply = connection.sendRequest(request); + + QTime stopWatch; + stopWatch.start(); + forever { + QCoreApplication::instance()->processEvents(); + if (reply->bytesAvailable()) + break; + if (stopWatch.elapsed() >= 30000) + break; + } + + QCOMPARE(reply->statusCode(), statusCode); + QCOMPARE(reply->reasonPhrase(), statusString); + + qint64 cLen = reply->contentLength(); + if (contentLength != -1) { + // only check the content length if test expected it to be set + if (cLen==-1) { + // HTTP 1.1 server may respond with chunked encoding and in that + // case contentLength is not present in reply -> verify that it is the case + QByteArray transferEnc = reply->headerField("Transfer-Encoding"); + QCOMPARE(transferEnc, QByteArray("chunked")); + } else { + QCOMPARE(cLen, qint64(contentLength)); + } + } + + stopWatch.start(); + QByteArray ba; + do { + QCoreApplication::instance()->processEvents(); + while (reply->bytesAvailable()) + ba += reply->readAny(); + if (stopWatch.elapsed() >= 30000) + break; + } while (!reply->isFinished()); + + QVERIFY(reply->isFinished()); + //don't require fixed size for generated error pages + if (downloadSize != -1) + QCOMPARE(ba.size(), downloadSize); + //but do compare with content length if possible + if (cLen != -1) + QCOMPARE(ba.size(), (int)cLen); + + delete reply; +} + +void tst_QHttpNetworkConnection::_delete_data() +{ + // not tested yet +} + +void tst_QHttpNetworkConnection::_delete() +{ + QEXPECT_FAIL("", "not tested yet", Continue); + QVERIFY(false); +} + +void tst_QHttpNetworkConnection::trace_data() +{ + // not tested yet +} + +void tst_QHttpNetworkConnection::trace() +{ + QEXPECT_FAIL("", "not tested yet", Continue); + QVERIFY(false); +} + +void tst_QHttpNetworkConnection::_connect_data() +{ + // not tested yet +} + +void tst_QHttpNetworkConnection::_connect() +{ + QEXPECT_FAIL("", "not tested yet", Continue); + QVERIFY(false); +} + +void tst_QHttpNetworkConnection::challenge401(const QHttpNetworkRequest &request, + QAuthenticator *authenticator) +{ + Q_UNUSED(request) + + QHttpNetworkReply *reply = qobject_cast<QHttpNetworkReply*>(sender()); + if (reply) { + QHttpNetworkConnection *c = reply->connection(); + + QVariant val = c->property("setCredentials"); + if (val.toBool()) { + QVariant user = c->property("username"); + QVariant password = c->property("password"); + authenticator->setUser(user.toString()); + authenticator->setPassword(password.toString()); + c->setProperty("setCredentials", false); + } + } +} + +void tst_QHttpNetworkConnection::get401_data() +{ + QTest::addColumn<QString>("protocol"); + QTest::addColumn<QString>("host"); + QTest::addColumn<QString>("path"); + QTest::addColumn<ushort>("port"); + QTest::addColumn<bool>("encrypt"); + QTest::addColumn<bool>("setCredentials"); + QTest::addColumn<QString>("username"); + QTest::addColumn<QString>("password"); + QTest::addColumn<int>("statusCode"); + + QTest::newRow("no-credentials") << "http://" << QtNetworkSettings::serverName() << "/qtest/rfcs-auth/index.html" << ushort(80) << false << false << "" << ""<<401; + QTest::newRow("invalid-credentials") << "http://" << QtNetworkSettings::serverName() << "/qtest/rfcs-auth/index.html" << ushort(80) << false << true << "test" << "test"<<401; + QTest::newRow("valid-credentials") << "http://" << QtNetworkSettings::serverName() << "/qtest/rfcs-auth/index.html" << ushort(80) << false << true << "httptest" << "httptest"<<200; + QTest::newRow("digest-authentication-invalid") << "http://" << QtNetworkSettings::serverName() << "/qtest/auth-digest/index.html" << ushort(80) << false << true << "wrong" << "wrong"<<401; + QTest::newRow("digest-authentication-valid") << "http://" << QtNetworkSettings::serverName() << "/qtest/auth-digest/index.html" << ushort(80) << false << true << "httptest" << "httptest"<<200; +} + +void tst_QHttpNetworkConnection::get401() +{ + QFETCH(QString, protocol); + QFETCH(QString, host); + QFETCH(QString, path); + QFETCH(ushort, port); + QFETCH(bool, encrypt); + QFETCH(bool, setCredentials); + QFETCH(QString, username); + QFETCH(QString, password); + QFETCH(int, statusCode); + + QHttpNetworkConnection connection(host, port, encrypt); + QCOMPARE(connection.port(), port); + QCOMPARE(connection.hostName(), host); + QCOMPARE(connection.isSsl(), encrypt); + connection.setProperty("setCredentials", setCredentials); + connection.setProperty("username", username); + connection.setProperty("password", password); + + QHttpNetworkRequest request(protocol + host + path); + QHttpNetworkReply *reply = connection.sendRequest(request); + connect(reply, SIGNAL(authenticationRequired(const QHttpNetworkRequest&, QAuthenticator *)), + SLOT(challenge401(const QHttpNetworkRequest&, QAuthenticator *))); + + finishedCalled = false; + finishedWithErrorCalled = false; + + connect(reply, SIGNAL(finished()), SLOT(finishedReply())); + connect(reply, SIGNAL(finishedWithError(QNetworkReply::NetworkError, const QString &)), + SLOT(finishedWithError(QNetworkReply::NetworkError, const QString &))); + + QTime stopWatch; + stopWatch.start(); + forever { + QCoreApplication::instance()->processEvents(); + if (finishedCalled) + break; + if (finishedWithErrorCalled) + break; + if (stopWatch.elapsed() >= 30000) + break; + } + QCOMPARE(reply->statusCode(), statusCode); + delete reply; +} + +#ifndef QT_NO_COMPRESS +void tst_QHttpNetworkConnection::compression_data() +{ + QTest::addColumn<QString>("protocol"); + QTest::addColumn<QString>("host"); + QTest::addColumn<QString>("path"); + QTest::addColumn<ushort>("port"); + QTest::addColumn<bool>("encrypt"); + QTest::addColumn<int>("statusCode"); + QTest::addColumn<QString>("statusString"); + QTest::addColumn<int>("contentLength"); + QTest::addColumn<int>("downloadSize"); + QTest::addColumn<bool>("autoCompress"); + QTest::addColumn<QString>("contentCoding"); + + QTest::newRow("success-autogzip-temp") << "http://" << QtNetworkSettings::serverName() << "/qtest/rfcs/rfc2616.html" << ushort(80) << false << 200 << "OK" << -1 << 418321 << true << ""; + QTest::newRow("success-nogzip-temp") << "http://" << QtNetworkSettings::serverName() << "/qtest/rfcs/rfc2616.html" << ushort(80) << false << 200 << "OK" << 418321 << 418321 << false << "identity"; + QTest::newRow("success-manualgzip-temp") << "http://" << QtNetworkSettings::serverName() << "/qtest/deflate/rfc2616.html" << ushort(80) << false << 200 << "OK" << 119124 << 119124 << false << "gzip"; + +} + +void tst_QHttpNetworkConnection::compression() +{ + QFETCH(QString, protocol); + QFETCH(QString, host); + QFETCH(QString, path); + QFETCH(ushort, port); + QFETCH(bool, encrypt); + QFETCH(int, statusCode); + QFETCH(QString, statusString); + QFETCH(int, contentLength); + QFETCH(int, downloadSize); + QFETCH(bool, autoCompress); + QFETCH(QString, contentCoding); + + QHttpNetworkConnection connection(host, port, encrypt); + QCOMPARE(connection.port(), port); + QCOMPARE(connection.hostName(), host); + QCOMPARE(connection.isSsl(), encrypt); + + QHttpNetworkRequest request(protocol + host + path); + if (!autoCompress) + request.setHeaderField("Accept-Encoding", contentCoding.toLatin1()); + QHttpNetworkReply *reply = connection.sendRequest(request); + QTime stopWatch; + stopWatch.start(); + forever { + QCoreApplication::instance()->processEvents(); + if (reply->bytesAvailable()) + break; + if (stopWatch.elapsed() >= 30000) + break; + } + + QCOMPARE(reply->statusCode(), statusCode); + QCOMPARE(reply->reasonPhrase(), statusString); + bool isLengthOk = (reply->contentLength() == qint64(contentLength) + || reply->contentLength() == qint64(downloadSize) + || reply->contentLength() == -1); //apache2 does not send content-length for compressed pages + + QVERIFY(isLengthOk); + + stopWatch.start(); + QByteArray ba; + do { + QCoreApplication::instance()->processEvents(); + while (reply->bytesAvailable()) + ba += reply->readAny(); + if (stopWatch.elapsed() >= 30000) + break; + } while (!reply->isFinished()); + + QVERIFY(reply->isFinished()); + QCOMPARE(ba.size(), downloadSize); + + delete reply; +} +#endif + +#ifndef QT_NO_OPENSSL +void tst_QHttpNetworkConnection::sslErrors(const QList<QSslError> &errors) +{ + Q_UNUSED(errors) + + QHttpNetworkReply *reply = qobject_cast<QHttpNetworkReply*>(sender()); + if (reply) { + QHttpNetworkConnection *connection = reply->connection(); + + QVariant val = connection->property("ignoreFromSignal"); + if (val.toBool()) + connection->ignoreSslErrors(); + finishedWithErrorCalled = true; + } +} + +void tst_QHttpNetworkConnection::ignoresslerror_data() +{ + QTest::addColumn<QString>("protocol"); + QTest::addColumn<QString>("host"); + QTest::addColumn<QString>("path"); + QTest::addColumn<ushort>("port"); + QTest::addColumn<bool>("encrypt"); + QTest::addColumn<bool>("ignoreInit"); + QTest::addColumn<bool>("ignoreFromSignal"); + QTest::addColumn<int>("statusCode"); + + // This test will work only if the website has ssl errors. + // fluke's certificate is signed by a non-standard authority. + // Since we don't introduce that CA into the SSL verification chain, + // connecting should fail. + QTest::newRow("success-init") << "https://" << QtNetworkSettings::serverName() << "/" << ushort(443) << true << true << false << 200; + QTest::newRow("success-fromSignal") << "https://" << QtNetworkSettings::serverName() << "/" << ushort(443) << true << false << true << 200; + QTest::newRow("failure") << "https://" << QtNetworkSettings::serverName() << "/" << ushort(443) << true << false << false << 100; +} + +void tst_QHttpNetworkConnection::ignoresslerror() +{ + QFETCH(QString, protocol); + QFETCH(QString, host); + QFETCH(QString, path); + QFETCH(ushort, port); + QFETCH(bool, encrypt); + QFETCH(bool, ignoreInit); + QFETCH(bool, ignoreFromSignal); + QFETCH(int, statusCode); + + QHttpNetworkConnection connection(host, port, encrypt); + QCOMPARE(connection.port(), port); + QCOMPARE(connection.hostName(), host); + if (ignoreInit) + connection.ignoreSslErrors(); + QCOMPARE(connection.isSsl(), encrypt); + connection.setProperty("ignoreFromSignal", ignoreFromSignal); + + QHttpNetworkRequest request(protocol + host + path); + QHttpNetworkReply *reply = connection.sendRequest(request); + connect(reply, SIGNAL(sslErrors(const QList<QSslError>&)), + SLOT(sslErrors(const QList<QSslError>&))); + + finishedWithErrorCalled = false; + + connect(reply, SIGNAL(finished()), SLOT(finishedReply())); + + QTime stopWatch; + stopWatch.start(); + forever { + QCoreApplication::instance()->processEvents(); + if (reply->bytesAvailable()) + break; + if (statusCode == 100 && finishedWithErrorCalled) + break; + if (stopWatch.elapsed() >= 30000) + break; + } + QCOMPARE(reply->statusCode(), statusCode); + delete reply; +} +#endif + +#ifdef QT_NO_OPENSSL +Q_DECLARE_METATYPE(QNetworkReply::NetworkError) +void tst_QHttpNetworkConnection::nossl_data() +{ + QTest::addColumn<QString>("protocol"); + QTest::addColumn<QString>("host"); + QTest::addColumn<QString>("path"); + QTest::addColumn<ushort>("port"); + QTest::addColumn<bool>("encrypt"); + QTest::addColumn<QNetworkReply::NetworkError>("networkError"); + + QTest::newRow("protocol-error") << "https://" << QtNetworkSettings::serverName() << "/" << ushort(443) << true <<QNetworkReply::ProtocolUnknownError; +} + +void tst_QHttpNetworkConnection::nossl() +{ + QFETCH(QString, protocol); + QFETCH(QString, host); + QFETCH(QString, path); + QFETCH(ushort, port); + QFETCH(bool, encrypt); + QFETCH(QNetworkReply::NetworkError, networkError); + + QHttpNetworkConnection connection(host, port, encrypt); + QCOMPARE(connection.port(), port); + QCOMPARE(connection.hostName(), host); + + QHttpNetworkRequest request(protocol + host + path); + QHttpNetworkReply *reply = connection.sendRequest(request); + + finishedWithErrorCalled = false; + netErrorCode = QNetworkReply::NoError; + + connect(reply, SIGNAL(finished()), SLOT(finishedReply())); + connect(reply, SIGNAL(finishedWithError(QNetworkReply::NetworkError, const QString &)), + SLOT(finishedWithError(QNetworkReply::NetworkError, const QString &))); + + QTime stopWatch; + stopWatch.start(); + forever { + QCoreApplication::instance()->processEvents(); + if (finishedWithErrorCalled) + break; + if (stopWatch.elapsed() >= 30000) + break; + } + QCOMPARE(netErrorCode, networkError); + delete reply; +} +#endif + + +void tst_QHttpNetworkConnection::getMultiple_data() +{ + QTest::addColumn<quint16>("connectionCount"); + QTest::addColumn<bool>("pipeliningAllowed"); + // send 100 requests. apache will usually force-close after 100 requests in a single tcp connection + QTest::addColumn<int>("requestCount"); + + QTest::newRow("6 connections, no pipelining, 100 requests") << quint16(6) << false << 100; + QTest::newRow("1 connection, no pipelining, 100 requests") << quint16(1) << false << 100; + QTest::newRow("6 connections, pipelining allowed, 100 requests") << quint16(6) << true << 100; + QTest::newRow("1 connection, pipelining allowed, 100 requests") << quint16(1) << true << 100; +} + +void tst_QHttpNetworkConnection::getMultiple() +{ + QFETCH(quint16, connectionCount); + QFETCH(bool, pipeliningAllowed); + QFETCH(int, requestCount); + + QHttpNetworkConnection connection(connectionCount, QtNetworkSettings::serverName()); + + QList<QHttpNetworkRequest*> requests; + QList<QHttpNetworkReply*> replies; + + for (int i = 0; i < requestCount; i++) { + // depending on what you use the results will vary. + // for the "real" results, use a URL that has "internet latency" for you. Then (6 connections, pipelining) will win. + // for LAN latency, you will possibly get that (1 connection, no pipelining) is the fastest + QHttpNetworkRequest *request = new QHttpNetworkRequest("http://" + QtNetworkSettings::serverName() + "/qtest/rfc3252.txt"); + // located in Berlin: + //QHttpNetworkRequest *request = new QHttpNetworkRequest(QUrl("http://klinsmann.nokia.trolltech.de/~berlin/qtcreatorad.gif")); + if (pipeliningAllowed) + request->setPipeliningAllowed(true); + requests.append(request); + QHttpNetworkReply *reply = connection.sendRequest(*request); + replies.append(reply); + } + + QTime stopWatch; + stopWatch.start(); + int finishedCount = 0; + do { + QCoreApplication::instance()->processEvents(); + if (stopWatch.elapsed() >= 60000) + break; + + finishedCount = 0; + for (int i = 0; i < replies.length(); i++) + if (replies.at(i)->isFinished()) + finishedCount++; + + } while (finishedCount != replies.length()); + + // redundant + for (int i = 0; i < replies.length(); i++) + QVERIFY(replies.at(i)->isFinished()); + + qDebug() << "===" << stopWatch.elapsed() << "msec ==="; + + qDeleteAll(requests); + qDeleteAll(replies); +} + +void tst_QHttpNetworkConnection::getMultipleWithPipeliningAndMultiplePriorities() +{ + quint16 requestCount = 100; + + // use 2 connections. + QHttpNetworkConnection connection(2, QtNetworkSettings::serverName()); + + QList<QHttpNetworkRequest*> requests; + QList<QHttpNetworkReply*> replies; + + for (int i = 0; i < requestCount; i++) { + QHttpNetworkRequest *request = 0; + if (i % 3) + request = new QHttpNetworkRequest("http://" + QtNetworkSettings::serverName() + "/qtest/rfc3252.txt", QHttpNetworkRequest::Get); + else + request = new QHttpNetworkRequest("http://" + QtNetworkSettings::serverName() + "/qtest/rfc3252.txt", QHttpNetworkRequest::Head); + + if (i % 2 || i % 3) + request->setPipeliningAllowed(true); + + if (i % 3) + request->setPriority(QHttpNetworkRequest::HighPriority); + else if (i % 5) + request->setPriority(QHttpNetworkRequest::NormalPriority); + else if (i % 7) + request->setPriority(QHttpNetworkRequest::LowPriority); + + requests.append(request); + QHttpNetworkReply *reply = connection.sendRequest(*request); + replies.append(reply); + } + + QTime stopWatch; + stopWatch.start(); + int finishedCount = 0; + do { + QCoreApplication::instance()->processEvents(); + if (stopWatch.elapsed() >= 60000) + break; + + finishedCount = 0; + for (int i = 0; i < replies.length(); i++) + if (replies.at(i)->isFinished()) + finishedCount++; + + } while (finishedCount != replies.length()); + + int pipelinedCount = 0; + for (int i = 0; i < replies.length(); i++) { + QVERIFY(replies.at(i)->isFinished()); + QVERIFY (!(replies.at(i)->request().isPipeliningAllowed() == false + && replies.at(i)->isPipeliningUsed())); + + if (replies.at(i)->isPipeliningUsed()) + pipelinedCount++; + } + + // We allow pipelining for every 2nd,3rd,4th,6th,8th,9th,10th etc request. + // Assume that half of the requests had been pipelined. + // (this is a very relaxed condition, when last measured 79 of 100 + // requests had been pipelined) + QVERIFY(pipelinedCount >= requestCount / 2); + + qDebug() << "===" << stopWatch.elapsed() << "msec ==="; + + qDeleteAll(requests); + qDeleteAll(replies); +} + +class GetMultipleWithPrioritiesReceiver : public QObject +{ + Q_OBJECT +public: + int highPrioReceived; + int lowPrioReceived; + int requestCount; + GetMultipleWithPrioritiesReceiver(int rq) : highPrioReceived(0), lowPrioReceived(0), requestCount(rq) { } +public Q_SLOTS: + void finishedSlot() { + QHttpNetworkReply *reply = (QHttpNetworkReply*) sender(); + if (reply->request().priority() == QHttpNetworkRequest::HighPriority) + highPrioReceived++; + else if (reply->request().priority() == QHttpNetworkRequest::LowPriority) + lowPrioReceived++; + else + QFAIL("Wrong priority!?"); + + QVERIFY(highPrioReceived + 7 >= lowPrioReceived); + + if (highPrioReceived + lowPrioReceived == requestCount) + QTestEventLoop::instance().exitLoop(); + } +}; + +void tst_QHttpNetworkConnection::getMultipleWithPriorities() +{ + quint16 requestCount = 100; + // use 2 connections. + QHttpNetworkConnection connection(2, QtNetworkSettings::serverName()); + GetMultipleWithPrioritiesReceiver receiver(requestCount); + QUrl url("http://" + QtNetworkSettings::serverName() + "/qtest/rfc3252.txt"); + QList<QHttpNetworkRequest*> requests; + QList<QHttpNetworkReply*> replies; + + for (int i = 0; i < requestCount; i++) { + QHttpNetworkRequest *request = 0; + if (i % 3) + request = new QHttpNetworkRequest(url, QHttpNetworkRequest::Get); + else + request = new QHttpNetworkRequest(url, QHttpNetworkRequest::Head); + + if (i % 2) + request->setPriority(QHttpNetworkRequest::HighPriority); + else + request->setPriority(QHttpNetworkRequest::LowPriority); + + requests.append(request); + QHttpNetworkReply *reply = connection.sendRequest(*request); + connect(reply, SIGNAL(finished()), &receiver, SLOT(finishedSlot())); + replies.append(reply); + } + + QTestEventLoop::instance().enterLoop(40); + QVERIFY(!QTestEventLoop::instance().timeout()); + + qDeleteAll(requests); + qDeleteAll(replies); +} + + +class GetEmptyWithPipeliningReceiver : public QObject +{ + Q_OBJECT +public: + int receivedCount; + int requestCount; + GetEmptyWithPipeliningReceiver(int rq) : receivedCount(0),requestCount(rq) { } +public Q_SLOTS: + void finishedSlot() { + QHttpNetworkReply *reply = (QHttpNetworkReply*) sender(); + Q_UNUSED(reply); + receivedCount++; + + if (receivedCount == requestCount) + QTestEventLoop::instance().exitLoop(); + } +}; + +void tst_QHttpNetworkConnection::getEmptyWithPipelining() +{ + quint16 requestCount = 50; + // use 2 connections. + QHttpNetworkConnection connection(2, QtNetworkSettings::serverName()); + GetEmptyWithPipeliningReceiver receiver(requestCount); + + QUrl url("http://" + QtNetworkSettings::serverName() + "/cgi-bin/echo.cgi"); // a get on this = getting an empty file + QList<QHttpNetworkRequest*> requests; + QList<QHttpNetworkReply*> replies; + + for (int i = 0; i < requestCount; i++) { + QHttpNetworkRequest *request = 0; + request = new QHttpNetworkRequest(url, QHttpNetworkRequest::Get); + request->setPipeliningAllowed(true); + + requests.append(request); + QHttpNetworkReply *reply = connection.sendRequest(*request); + connect(reply, SIGNAL(finished()), &receiver, SLOT(finishedSlot())); + replies.append(reply); + } + + QTestEventLoop::instance().enterLoop(20); + QVERIFY(!QTestEventLoop::instance().timeout()); + + qDeleteAll(requests); + qDeleteAll(replies); +} + +class GetAndEverythingShouldBePipelinedReceiver : public QObject +{ + Q_OBJECT +public: + int receivedCount; + int requestCount; + GetAndEverythingShouldBePipelinedReceiver(int rq) : receivedCount(0),requestCount(rq) { } +public Q_SLOTS: + void finishedSlot() { + QHttpNetworkReply *reply = (QHttpNetworkReply*) sender(); + Q_UNUSED(reply); + receivedCount++; + + if (receivedCount == requestCount) + QTestEventLoop::instance().exitLoop(); + } +}; + +void tst_QHttpNetworkConnection::getAndEverythingShouldBePipelined() +{ + quint16 requestCount = 100; + // use 1 connection. + QHttpNetworkConnection connection(1, QtNetworkSettings::serverName()); + QUrl url("http://" + QtNetworkSettings::serverName() + "/qtest/rfc3252.txt"); + QList<QHttpNetworkRequest*> requests; + QList<QHttpNetworkReply*> replies; + + GetAndEverythingShouldBePipelinedReceiver receiver(requestCount); + + for (int i = 0; i < requestCount; i++) { + QHttpNetworkRequest *request = 0; + request = new QHttpNetworkRequest(url, QHttpNetworkRequest::Get); + request->setPipeliningAllowed(true); + requests.append(request); + QHttpNetworkReply *reply = connection.sendRequest(*request); + connect(reply, SIGNAL(finished()), &receiver, SLOT(finishedSlot())); + replies.append(reply); + } + QTestEventLoop::instance().enterLoop(40); + QVERIFY(!QTestEventLoop::instance().timeout()); + + qDeleteAll(requests); + qDeleteAll(replies); + +} + + +void tst_QHttpNetworkConnection::getAndThenDeleteObject_data() +{ + QTest::addColumn<bool>("replyFirst"); + + QTest::newRow("delete-reply-first") << true; + QTest::newRow("delete-connection-first") << false; +} + +void tst_QHttpNetworkConnection::getAndThenDeleteObject() +{ + // yes, this will leak if the testcase fails. I don't care. It must not fail then :P + QHttpNetworkConnection *connection = new QHttpNetworkConnection(QtNetworkSettings::serverName()); + QHttpNetworkRequest request("http://" + QtNetworkSettings::serverName() + "/qtest/bigfile"); + QHttpNetworkReply *reply = connection->sendRequest(request); + reply->setDownstreamLimited(true); + + QTime stopWatch; + stopWatch.start(); + forever { + QCoreApplication::instance()->processEvents(); + if (reply->bytesAvailable()) + break; + if (stopWatch.elapsed() >= 30000) + break; + } + + QVERIFY(reply->bytesAvailable()); + QCOMPARE(reply->statusCode() ,200); + QVERIFY(!reply->isFinished()); // must not be finished + + QFETCH(bool, replyFirst); + + if (replyFirst) { + delete reply; + delete connection; + } else { + delete connection; + delete reply; + } +} + + + +QTEST_MAIN(tst_QHttpNetworkConnection) +#include "tst_qhttpnetworkconnection.moc" diff --git a/tests/auto/network/access/qhttpnetworkreply/.gitignore b/tests/auto/network/access/qhttpnetworkreply/.gitignore new file mode 100644 index 0000000000..fdd4e2be86 --- /dev/null +++ b/tests/auto/network/access/qhttpnetworkreply/.gitignore @@ -0,0 +1 @@ +tst_qhttpnetworkreply diff --git a/tests/auto/network/access/qhttpnetworkreply/qhttpnetworkreply.pro b/tests/auto/network/access/qhttpnetworkreply/qhttpnetworkreply.pro new file mode 100644 index 0000000000..8ce9f6f760 --- /dev/null +++ b/tests/auto/network/access/qhttpnetworkreply/qhttpnetworkreply.pro @@ -0,0 +1,7 @@ +load(qttest_p4) +SOURCES += tst_qhttpnetworkreply.cpp +INCLUDEPATH += $$QT_SOURCE_TREE/src/3rdparty/zlib +requires(contains(QT_CONFIG,private_tests)) + +QT = core-private network-private +symbian: TARGET.CAPABILITY = NetworkServices diff --git a/tests/auto/network/access/qhttpnetworkreply/tst_qhttpnetworkreply.cpp b/tests/auto/network/access/qhttpnetworkreply/tst_qhttpnetworkreply.cpp new file mode 100644 index 0000000000..513b20ec82 --- /dev/null +++ b/tests/auto/network/access/qhttpnetworkreply/tst_qhttpnetworkreply.cpp @@ -0,0 +1,134 @@ +/**************************************************************************** +** +** 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 test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** 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. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + + +#include <QtTest/QtTest> +#include "private/qhttpnetworkconnection_p.h" + +class tst_QHttpNetworkReply: public QObject +{ + Q_OBJECT +private Q_SLOTS: + void init(); + void cleanup(); + void initTestCase(); + void cleanupTestCase(); + + void parseHeader_data(); + void parseHeader(); +}; + + +void tst_QHttpNetworkReply::initTestCase() +{ +} + +void tst_QHttpNetworkReply::cleanupTestCase() +{ +} + +void tst_QHttpNetworkReply::init() +{ +} + +void tst_QHttpNetworkReply::cleanup() +{ +} + +void tst_QHttpNetworkReply::parseHeader_data() +{ + QTest::addColumn<QByteArray>("headers"); + QTest::addColumn<QStringList>("fields"); + QTest::addColumn<QStringList>("values"); + + QTest::newRow("empty-field") << QByteArray("Set-Cookie: \r\n") + << (QStringList() << "Set-Cookie") + << (QStringList() << ""); + QTest::newRow("single-field") << QByteArray("Content-Type: text/html; charset=utf-8\r\n") + << (QStringList() << "Content-Type") + << (QStringList() << "text/html; charset=utf-8"); + QTest::newRow("single-field-continued") << QByteArray("Content-Type: text/html;\r\n" + " charset=utf-8\r\n") + << (QStringList() << "Content-Type") + << (QStringList() << "text/html; charset=utf-8"); + + QTest::newRow("multi-field") << QByteArray("Content-Type: text/html; charset=utf-8\r\n" + "Content-Length: 1024\r\n" + "Content-Encoding: gzip\r\n") + << (QStringList() << "Content-Type" << "Content-Length" << "Content-Encoding") + << (QStringList() << "text/html; charset=utf-8" << "1024" << "gzip"); + QTest::newRow("multi-field-with-emtpy") << QByteArray("Content-Type: text/html; charset=utf-8\r\n" + "Content-Length: 1024\r\n" + "Set-Cookie: \r\n" + "Content-Encoding: gzip\r\n") + << (QStringList() << "Content-Type" << "Content-Length" << "Set-Cookie" << "Content-Encoding") + << (QStringList() << "text/html; charset=utf-8" << "1024" << "" << "gzip"); + + QTest::newRow("lws-field") << QByteArray("Content-Type: text/html; charset=utf-8\r\n" + "Content-Length:\r\n 1024\r\n" + "Content-Encoding: gzip\r\n") + << (QStringList() << "Content-Type" << "Content-Length" << "Content-Encoding") + << (QStringList() << "text/html; charset=utf-8" << "1024" << "gzip"); + + QTest::newRow("duplicated-field") << QByteArray("Vary: Accept-Language\r\n" + "Vary: Cookie\r\n" + "Vary: User-Agent\r\n") + << (QStringList() << "Vary") + << (QStringList() << "Accept-Language, Cookie, User-Agent"); +} + +void tst_QHttpNetworkReply::parseHeader() +{ + QFETCH(QByteArray, headers); + QFETCH(QStringList, fields); + QFETCH(QStringList, values); + + QHttpNetworkReply reply; + reply.parseHeader(headers); + for (int i = 0; i < fields.count(); ++i) { + //qDebug() << "field" << fields.at(i) << "value" << reply.headerField(fields.at(i)) << "expected" << values.at(i); + QString field = reply.headerField(fields.at(i).toLatin1()); + QCOMPARE(field, values.at(i)); + } +} + +QTEST_MAIN(tst_QHttpNetworkReply) +#include "tst_qhttpnetworkreply.moc" diff --git a/tests/auto/network/access/qnetworkaccessmanager/qnetworkaccessmanager.pro b/tests/auto/network/access/qnetworkaccessmanager/qnetworkaccessmanager.pro new file mode 100644 index 0000000000..3ccbffbde8 --- /dev/null +++ b/tests/auto/network/access/qnetworkaccessmanager/qnetworkaccessmanager.pro @@ -0,0 +1,6 @@ +load(qttest_p4) +SOURCES += tst_qnetworkaccessmanager.cpp +QT = core network + +symbian: TARGET.CAPABILITY = NetworkServices + diff --git a/tests/auto/network/access/qnetworkaccessmanager/tst_qnetworkaccessmanager.cpp b/tests/auto/network/access/qnetworkaccessmanager/tst_qnetworkaccessmanager.cpp new file mode 100644 index 0000000000..14804b5187 --- /dev/null +++ b/tests/auto/network/access/qnetworkaccessmanager/tst_qnetworkaccessmanager.cpp @@ -0,0 +1,111 @@ +/**************************************************************************** +** +** 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 test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** 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. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include <QtTest/QtTest> + +#include <QtNetwork/QNetworkAccessManager> +#include <QtNetwork/QNetworkConfigurationManager> + +#include <QtCore/QDebug> + +Q_DECLARE_METATYPE(QNetworkAccessManager::NetworkAccessibility); + +class tst_QNetworkAccessManager : public QObject +{ + Q_OBJECT + +public: + tst_QNetworkAccessManager(); + +private slots: + void networkAccessible(); +}; + +tst_QNetworkAccessManager::tst_QNetworkAccessManager() +{ +} + +void tst_QNetworkAccessManager::networkAccessible() +{ + QNetworkAccessManager manager; + + qRegisterMetaType<QNetworkAccessManager::NetworkAccessibility>("QNetworkAccessManager::NetworkAccessibility"); + + QSignalSpy spy(&manager, + SIGNAL(networkAccessibleChanged(QNetworkAccessManager::NetworkAccessibility))); + + QCOMPARE(manager.networkAccessible(), QNetworkAccessManager::UnknownAccessibility); + + manager.setNetworkAccessible(QNetworkAccessManager::NotAccessible); + + QCOMPARE(spy.count(), 1); + QCOMPARE(spy.takeFirst().at(0).value<QNetworkAccessManager::NetworkAccessibility>(), + QNetworkAccessManager::NotAccessible); + QCOMPARE(manager.networkAccessible(), QNetworkAccessManager::NotAccessible); + + manager.setNetworkAccessible(QNetworkAccessManager::Accessible); + + QCOMPARE(spy.count(), 1); + QCOMPARE(spy.takeFirst().at(0).value<QNetworkAccessManager::NetworkAccessibility>(), + QNetworkAccessManager::UnknownAccessibility); + QCOMPARE(manager.networkAccessible(), QNetworkAccessManager::UnknownAccessibility); + + QNetworkConfigurationManager configManager; + QNetworkConfiguration defaultConfig = configManager.defaultConfiguration(); + if (defaultConfig.isValid()) { + manager.setConfiguration(defaultConfig); + + QCOMPARE(spy.count(), 1); + QCOMPARE(spy.takeFirst().at(0).value<QNetworkAccessManager::NetworkAccessibility>(), + QNetworkAccessManager::Accessible); + QCOMPARE(manager.networkAccessible(), QNetworkAccessManager::Accessible); + + manager.setNetworkAccessible(QNetworkAccessManager::NotAccessible); + + QCOMPARE(spy.count(), 1); + QCOMPARE(QNetworkAccessManager::NetworkAccessibility(spy.takeFirst().at(0).toInt()), + QNetworkAccessManager::NotAccessible); + QCOMPARE(manager.networkAccessible(), QNetworkAccessManager::NotAccessible); + } +} + +QTEST_MAIN(tst_QNetworkAccessManager) +#include "tst_qnetworkaccessmanager.moc" diff --git a/tests/auto/network/access/qnetworkcachemetadata/.gitignore b/tests/auto/network/access/qnetworkcachemetadata/.gitignore new file mode 100644 index 0000000000..76f9e574b1 --- /dev/null +++ b/tests/auto/network/access/qnetworkcachemetadata/.gitignore @@ -0,0 +1 @@ +tst_qnetworkcachemetadata diff --git a/tests/auto/network/access/qnetworkcachemetadata/qnetworkcachemetadata.pro b/tests/auto/network/access/qnetworkcachemetadata/qnetworkcachemetadata.pro new file mode 100644 index 0000000000..ae0941e964 --- /dev/null +++ b/tests/auto/network/access/qnetworkcachemetadata/qnetworkcachemetadata.pro @@ -0,0 +1,7 @@ +load(qttest_p4) +QT -= gui +QT += network +SOURCES += tst_qnetworkcachemetadata.cpp + +symbian: TARGET.CAPABILITY = NetworkServices + diff --git a/tests/auto/network/access/qnetworkcachemetadata/tst_qnetworkcachemetadata.cpp b/tests/auto/network/access/qnetworkcachemetadata/tst_qnetworkcachemetadata.cpp new file mode 100644 index 0000000000..a5b63bd7d5 --- /dev/null +++ b/tests/auto/network/access/qnetworkcachemetadata/tst_qnetworkcachemetadata.cpp @@ -0,0 +1,373 @@ +/**************************************************************************** +** +** 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 test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** 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. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + + +#include <QtTest/QtTest> +#include <qabstractnetworkcache.h> + +#define EXAMPLE_URL "http://user:pass@www.example.com/#foo" + +class tst_QNetworkCacheMetaData : public QObject +{ + Q_OBJECT + +public slots: + void initTestCase(); + void cleanupTestCase(); + void init(); + void cleanup(); + +private slots: + void qnetworkcachemetadata_data(); + void qnetworkcachemetadata(); + + void expirationDate_data(); + void expirationDate(); + void isValid_data(); + void isValid(); + void lastModified_data(); + void lastModified(); + void operatorEqual_data(); + void operatorEqual(); + void operatorEqualEqual_data(); + void operatorEqualEqual(); + void rawHeaders_data(); + void rawHeaders(); + void saveToDisk_data(); + void saveToDisk(); + void url_data(); + void url(); + + void stream(); +}; + +// Subclass that exposes the protected functions. +class SubQNetworkCacheMetaData : public QNetworkCacheMetaData +{ +public:}; + +// This will be called before the first test function is executed. +// It is only called once. +void tst_QNetworkCacheMetaData::initTestCase() +{ +} + +// This will be called after the last test function is executed. +// It is only called once. +void tst_QNetworkCacheMetaData::cleanupTestCase() +{ +} + +// This will be called before each test function is executed. +void tst_QNetworkCacheMetaData::init() +{ +} + +// This will be called after every test function. +void tst_QNetworkCacheMetaData::cleanup() +{ +} + +void tst_QNetworkCacheMetaData::qnetworkcachemetadata_data() +{ +} + +void tst_QNetworkCacheMetaData::qnetworkcachemetadata() +{ + QNetworkCacheMetaData data; + QCOMPARE(data.expirationDate(), QDateTime()); + QCOMPARE(data.isValid(), false); + QCOMPARE(data.lastModified(), QDateTime()); + QCOMPARE(data.operator!=(QNetworkCacheMetaData()), false); + QNetworkCacheMetaData metaData; + QCOMPARE(data.operator=(metaData), QNetworkCacheMetaData()); + QCOMPARE(data.operator==(QNetworkCacheMetaData()), true); + QCOMPARE(data.rawHeaders(), QNetworkCacheMetaData::RawHeaderList()); + QCOMPARE(data.saveToDisk(), true); + QCOMPARE(data.url(), QUrl()); + data.setExpirationDate(QDateTime()); + data.setLastModified(QDateTime()); + data.setRawHeaders(QNetworkCacheMetaData::RawHeaderList()); + data.setSaveToDisk(false); + data.setUrl(QUrl()); +} + +void tst_QNetworkCacheMetaData::expirationDate_data() +{ + QTest::addColumn<QDateTime>("expirationDate"); + QTest::newRow("null") << QDateTime(); + QTest::newRow("now") << QDateTime::currentDateTime(); +} + +// public QDateTime expirationDate() const +void tst_QNetworkCacheMetaData::expirationDate() +{ + QFETCH(QDateTime, expirationDate); + + SubQNetworkCacheMetaData data; + + data.setExpirationDate(expirationDate); + QCOMPARE(data.expirationDate(), expirationDate); +} + +Q_DECLARE_METATYPE(QNetworkCacheMetaData) +void tst_QNetworkCacheMetaData::isValid_data() +{ + QTest::addColumn<QNetworkCacheMetaData>("data"); + QTest::addColumn<bool>("isValid"); + + QNetworkCacheMetaData metaData; + QTest::newRow("null") << metaData << false; + + QNetworkCacheMetaData data1; + data1.setUrl(QUrl(EXAMPLE_URL)); + QTest::newRow("valid-1") << data1 << true; + + QNetworkCacheMetaData data2; + QNetworkCacheMetaData::RawHeaderList headers; + headers.append(QNetworkCacheMetaData::RawHeader("foo", "Bar")); + data2.setRawHeaders(headers); + QTest::newRow("valid-2") << data2 << true; + + QNetworkCacheMetaData data3; + data3.setLastModified(QDateTime::currentDateTime()); + QTest::newRow("valid-3") << data3 << true; + + QNetworkCacheMetaData data4; + data4.setExpirationDate(QDateTime::currentDateTime()); + QTest::newRow("valid-4") << data4 << true; + + QNetworkCacheMetaData data5; + data5.setSaveToDisk(false); + QTest::newRow("valid-5") << data5 << true; +} + +// public bool isValid() const +void tst_QNetworkCacheMetaData::isValid() +{ + QFETCH(QNetworkCacheMetaData, data); + QFETCH(bool, isValid); + + QCOMPARE(data.isValid(), isValid); +} + +void tst_QNetworkCacheMetaData::lastModified_data() +{ + QTest::addColumn<QDateTime>("lastModified"); + QTest::newRow("null") << QDateTime(); + QTest::newRow("now") << QDateTime::currentDateTime(); +} + +// public QDateTime lastModified() const +void tst_QNetworkCacheMetaData::lastModified() +{ + QFETCH(QDateTime, lastModified); + + SubQNetworkCacheMetaData data; + + data.setLastModified(lastModified); + QCOMPARE(data.lastModified(), lastModified); +} + +void tst_QNetworkCacheMetaData::operatorEqual_data() +{ + QTest::addColumn<QNetworkCacheMetaData>("other"); + QTest::newRow("null") << QNetworkCacheMetaData(); + + QNetworkCacheMetaData data; + data.setUrl(QUrl(EXAMPLE_URL)); + QNetworkCacheMetaData::RawHeaderList headers; + headers.append(QNetworkCacheMetaData::RawHeader("foo", "Bar")); + data.setRawHeaders(headers); + data.setLastModified(QDateTime::currentDateTime()); + data.setExpirationDate(QDateTime::currentDateTime()); + data.setSaveToDisk(false); + QTest::newRow("valid") << data; +} + +// public QNetworkCacheMetaData& operator=(QNetworkCacheMetaData const& other) +void tst_QNetworkCacheMetaData::operatorEqual() +{ + QFETCH(QNetworkCacheMetaData, other); + + QNetworkCacheMetaData data = other; + + QCOMPARE(data, other); +} + +void tst_QNetworkCacheMetaData::operatorEqualEqual_data() +{ + QTest::addColumn<QNetworkCacheMetaData>("a"); + QTest::addColumn<QNetworkCacheMetaData>("b"); + QTest::addColumn<bool>("operatorEqualEqual"); + QTest::newRow("null") << QNetworkCacheMetaData() << QNetworkCacheMetaData() << true; + + QNetworkCacheMetaData data1; + data1.setUrl(QUrl(EXAMPLE_URL)); + QTest::newRow("valid-1-1") << data1 << QNetworkCacheMetaData() << false; + QTest::newRow("valid-1-2") << data1 << data1 << true; + + QNetworkCacheMetaData data2; + QNetworkCacheMetaData::RawHeaderList headers; + headers.append(QNetworkCacheMetaData::RawHeader("foo", "Bar")); + data2.setRawHeaders(headers); + QTest::newRow("valid-2-1") << data2 << QNetworkCacheMetaData() << false; + QTest::newRow("valid-2-2") << data2 << data2 << true; + QTest::newRow("valid-2-3") << data2 << data1 << false; + + QNetworkCacheMetaData data3; + data3.setLastModified(QDateTime::currentDateTime()); + QTest::newRow("valid-3-1") << data3 << QNetworkCacheMetaData() << false; + QTest::newRow("valid-3-2") << data3 << data3 << true; + QTest::newRow("valid-3-3") << data3 << data1 << false; + QTest::newRow("valid-3-4") << data3 << data2 << false; + + QNetworkCacheMetaData data4; + data4.setExpirationDate(QDateTime::currentDateTime()); + QTest::newRow("valid-4-1") << data4 << QNetworkCacheMetaData() << false; + QTest::newRow("valid-4-2") << data4 << data4 << true; + QTest::newRow("valid-4-3") << data4 << data1 << false; + QTest::newRow("valid-4-4") << data4 << data2 << false; + QTest::newRow("valid-4-5") << data4 << data3 << false; + + QNetworkCacheMetaData data5; + data5.setSaveToDisk(false); + QTest::newRow("valid-5-1") << data5 << QNetworkCacheMetaData() << false; + QTest::newRow("valid-5-2") << data5 << data5 << true; + QTest::newRow("valid-5-3") << data5 << data1 << false; + QTest::newRow("valid-5-4") << data5 << data2 << false; + QTest::newRow("valid-5-5") << data5 << data3 << false; + QTest::newRow("valid-5-6") << data5 << data4 << false; +} + +// public bool operator==(QNetworkCacheMetaData const& other) const +void tst_QNetworkCacheMetaData::operatorEqualEqual() +{ + QFETCH(QNetworkCacheMetaData, a); + QFETCH(QNetworkCacheMetaData, b); + QFETCH(bool, operatorEqualEqual); + + QCOMPARE(a == b, operatorEqualEqual); +} + +Q_DECLARE_METATYPE(QNetworkCacheMetaData::RawHeaderList) +void tst_QNetworkCacheMetaData::rawHeaders_data() +{ + QTest::addColumn<QNetworkCacheMetaData::RawHeaderList>("rawHeaders"); + QTest::newRow("null") << QNetworkCacheMetaData::RawHeaderList(); + QNetworkCacheMetaData::RawHeaderList headers; + headers.append(QNetworkCacheMetaData::RawHeader("foo", "Bar")); + QTest::newRow("valie") << headers; +} + +// public QNetworkCacheMetaData::RawHeaderList rawHeaders() const +void tst_QNetworkCacheMetaData::rawHeaders() +{ + QFETCH(QNetworkCacheMetaData::RawHeaderList, rawHeaders); + + SubQNetworkCacheMetaData data; + + data.setRawHeaders(rawHeaders); + QCOMPARE(data.rawHeaders(), rawHeaders); +} + +void tst_QNetworkCacheMetaData::saveToDisk_data() +{ + QTest::addColumn<bool>("saveToDisk"); + QTest::newRow("false") << false; + QTest::newRow("true") << true; +} + +// public bool saveToDisk() const +void tst_QNetworkCacheMetaData::saveToDisk() +{ + QFETCH(bool, saveToDisk); + + SubQNetworkCacheMetaData data; + + data.setSaveToDisk(saveToDisk); + QCOMPARE(data.saveToDisk(), saveToDisk); +} + +void tst_QNetworkCacheMetaData::url_data() +{ + QTest::addColumn<QUrl>("url"); + QTest::addColumn<QUrl>("expected"); + QTest::newRow("null") << QUrl() << QUrl(); + QTest::newRow("valid") << QUrl(EXAMPLE_URL) << QUrl("http://user@www.example.com/"); +} + +// public QUrl url() const +void tst_QNetworkCacheMetaData::url() +{ + QFETCH(QUrl, url); + QFETCH(QUrl, expected); + + SubQNetworkCacheMetaData data; + data.setUrl(url); + QCOMPARE(data.url(), expected); +} + +void tst_QNetworkCacheMetaData::stream() +{ + QNetworkCacheMetaData data; + data.setUrl(QUrl(EXAMPLE_URL)); + QNetworkCacheMetaData::RawHeaderList headers; + headers.append(QNetworkCacheMetaData::RawHeader("foo", "Bar")); + data.setRawHeaders(headers); + data.setLastModified(QDateTime::currentDateTime()); + data.setExpirationDate(QDateTime::currentDateTime()); + data.setSaveToDisk(false); + + QBuffer buffer; + buffer.open(QIODevice::ReadWrite); + QDataStream stream(&buffer); + stream << data; + + buffer.seek(0); + QNetworkCacheMetaData data2; + stream >> data2; + QCOMPARE(data2, data); +} + +QTEST_MAIN(tst_QNetworkCacheMetaData) +#include "tst_qnetworkcachemetadata.moc" + diff --git a/tests/auto/network/access/qnetworkcookie/.gitignore b/tests/auto/network/access/qnetworkcookie/.gitignore new file mode 100644 index 0000000000..90d1081d12 --- /dev/null +++ b/tests/auto/network/access/qnetworkcookie/.gitignore @@ -0,0 +1 @@ +tst_qnetworkcookie diff --git a/tests/auto/network/access/qnetworkcookie/qnetworkcookie.pro b/tests/auto/network/access/qnetworkcookie/qnetworkcookie.pro new file mode 100644 index 0000000000..2f31138daf --- /dev/null +++ b/tests/auto/network/access/qnetworkcookie/qnetworkcookie.pro @@ -0,0 +1,5 @@ +load(qttest_p4) +SOURCES += tst_qnetworkcookie.cpp + +QT = core network +symbian: TARGET.CAPABILITY = NetworkServices diff --git a/tests/auto/network/access/qnetworkcookie/tst_qnetworkcookie.cpp b/tests/auto/network/access/qnetworkcookie/tst_qnetworkcookie.cpp new file mode 100644 index 0000000000..a83f6dda91 --- /dev/null +++ b/tests/auto/network/access/qnetworkcookie/tst_qnetworkcookie.cpp @@ -0,0 +1,733 @@ +/**************************************************************************** +** +** 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 test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** 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. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + + +#include <QtTest/QtTest> +#include <QtCore/QUrl> +#include <QtNetwork/QNetworkCookie> + + +class tst_QNetworkCookie: public QObject +{ + Q_OBJECT + +private slots: + void getterSetter(); + + void parseSingleCookie_data(); + void parseSingleCookie(); + + void parseMultipleCookies_data(); + void parseMultipleCookies(); +}; + +QT_BEGIN_NAMESPACE + +namespace QTest { + template<> + char *toString(const QNetworkCookie &cookie) + { + return qstrdup(cookie.toRawForm()); + } + + template<> + char *toString(const QList<QNetworkCookie> &list) + { + QString result = "QList("; + bool first = true; + foreach (QNetworkCookie cookie, list) { + if (!first) + result += ", "; + first = false; + result += QString::fromLatin1("QNetworkCookie(%1)").arg(QLatin1String(cookie.toRawForm())); + } + + return qstrdup(result.append(')').toLocal8Bit()); + } +} + +QT_END_NAMESPACE + +void tst_QNetworkCookie::getterSetter() +{ + QNetworkCookie cookie; + QNetworkCookie otherCookie; + + QVERIFY(cookie == otherCookie); + QCOMPARE(cookie, otherCookie); + QVERIFY(!(cookie != otherCookie)); + + QVERIFY(!cookie.isSecure()); + QVERIFY(cookie.isSessionCookie()); + QVERIFY(!cookie.expirationDate().isValid()); + QVERIFY(cookie.domain().isEmpty()); + QVERIFY(cookie.path().isEmpty()); + QVERIFY(cookie.name().isEmpty()); + QVERIFY(cookie.value().isEmpty()); + + // change something + cookie.setName("foo"); + QVERIFY(!(cookie == otherCookie)); + QVERIFY(cookie != otherCookie); + + // test getters and setters: + QCOMPARE(cookie.name(), QByteArray("foo")); + cookie.setName(0); + QVERIFY(cookie.name().isEmpty()); + + cookie.setValue("bar"); + QCOMPARE(cookie.value(), QByteArray("bar")); + cookie.setValue(0); + QVERIFY(cookie.value().isEmpty()); + + cookie.setPath("/"); + QCOMPARE(cookie.path(), QString("/")); + cookie.setPath(QString()); + QVERIFY(cookie.path().isEmpty()); + + cookie.setDomain(".tld"); + QCOMPARE(cookie.domain(), QString(".tld")); + cookie.setDomain(QString()); + QVERIFY(cookie.domain().isEmpty()); + + QDateTime now = QDateTime::currentDateTime(); + cookie.setExpirationDate(now); + QCOMPARE(cookie.expirationDate(), now); + QVERIFY(!cookie.isSessionCookie()); + cookie.setExpirationDate(QDateTime()); + QVERIFY(!cookie.expirationDate().isValid()); + QVERIFY(cookie.isSessionCookie()); + + cookie.setSecure(true); + QVERIFY(cookie.isSecure()); + cookie.setSecure(false); + QVERIFY(!cookie.isSecure()); + + QVERIFY(cookie == otherCookie); +} + +void tst_QNetworkCookie::parseSingleCookie_data() +{ + QTest::addColumn<QString>("cookieString"); + QTest::addColumn<QNetworkCookie>("expectedCookie"); + + QNetworkCookie cookie; + cookie.setName("a"); + QTest::newRow("basic") << "a=" << cookie; + QTest::newRow("basic2") << " a=" << cookie; + QTest::newRow("basic3") << "a= " << cookie; + QTest::newRow("basic4") << " a= " << cookie; + QTest::newRow("basic5") << " a= ;" << cookie; + QTest::newRow("basic6") << " a=; " << cookie; + QTest::newRow("basic7") << " a =" << cookie; + QTest::newRow("basic8") << " a = " << cookie; + + cookie.setValue("b"); + QTest::newRow("with-value") << "a=b" << cookie; + QTest::newRow("with-value2") << " a=b" << cookie; + QTest::newRow("with-value3") << "a=b " << cookie; + QTest::newRow("with-value4") << " a=b " << cookie; + QTest::newRow("with-value4") << " a=b ;" << cookie; + QTest::newRow("with-value5") << "a =b" << cookie; + QTest::newRow("with-value6") << "a= b" << cookie; + QTest::newRow("with-value7") << "a = b" << cookie; + QTest::newRow("with-value8") << "a = b " << cookie; + + cookie.setValue("\",\""); + QTest::newRow("with-value-with-special1") << "a = \",\" " << cookie; + cookie.setValue("\";\""); + QTest::newRow("with-value-with-special2") << "a = \";\" " << cookie; + cookie.setValue("\" \""); + QTest::newRow("with-value-with-special3") << "a = \" \" " << cookie; + cookie.setValue("\"\\\"\""); + QTest::newRow("with-value-with-special4") << "a = \"\\\"\" " << cookie; + cookie.setValue("\"\\\"a, b; c\\\"\""); + QTest::newRow("with-value-with-special5") << "a = \"\\\"a, b; c\\\"\"" << cookie; + + cookie.setValue("b c"); + QTest::newRow("with-value-with-whitespace") << "a = b c" << cookie; + + cookie.setValue("\"b\""); + QTest::newRow("quoted-value") << "a = \"b\"" << cookie; + cookie.setValue("\"b c\""); + QTest::newRow("quoted-value-with-whitespace") << "a = \"b c\"" << cookie; + + cookie.setValue("b"); + cookie.setSecure(true); + QTest::newRow("secure") << "a=b;secure" << cookie; + QTest::newRow("secure2") << "a=b;secure " << cookie; + QTest::newRow("secure3") << "a=b; secure" << cookie; + QTest::newRow("secure4") << "a=b; secure " << cookie; + QTest::newRow("secure5") << "a=b ;secure" << cookie; + QTest::newRow("secure6") << "a=b ;secure " << cookie; + QTest::newRow("secure7") << "a=b ; secure " << cookie; + QTest::newRow("secure8") << "a=b; Secure" << cookie; + + cookie.setSecure(false); + cookie.setHttpOnly(true); + QTest::newRow("httponly") << "a=b;httponly" << cookie; + QTest::newRow("httponly2") << "a=b;HttpOnly " << cookie; + QTest::newRow("httponly3") << "a=b; httpOnly" << cookie; + QTest::newRow("httponly4") << "a=b; HttpOnly " << cookie; + QTest::newRow("httponly5") << "a=b ;HttpOnly" << cookie; + QTest::newRow("httponly6") << "a=b ;httponly " << cookie; + QTest::newRow("httponly7") << "a=b ; HttpOnly " << cookie; + QTest::newRow("httponly8") << "a=b; Httponly" << cookie; + + cookie.setHttpOnly(false); + cookie.setPath("/"); + QTest::newRow("path1") << "a=b;path=/" << cookie; + QTest::newRow("path2") << "a=b; path=/" << cookie; + QTest::newRow("path3") << "a=b;path=/ " << cookie; + QTest::newRow("path4") << "a=b;path =/ " << cookie; + QTest::newRow("path5") << "a=b;path= / " << cookie; + QTest::newRow("path6") << "a=b;path = / " << cookie; + QTest::newRow("path7") << "a=b;Path = / " << cookie; + QTest::newRow("path8") << "a=b; PATH = / " << cookie; + + cookie.setPath("/foo"); + QTest::newRow("path9") << "a=b;path=/foo" << cookie; + + // some weird paths: + cookie.setPath("/with spaces"); + QTest::newRow("path-with-spaces") << "a=b;path=/with%20spaces" << cookie; + QTest::newRow("path-with-spaces2") << "a=b; path=/with%20spaces " << cookie; + QTest::newRow("path-with-spaces3") << "a=b; path=\"/with spaces\"" << cookie; + QTest::newRow("path-with-spaces4") << "a=b; path = \"/with spaces\" " << cookie; + + cookie.setPath("/with\"Quotes"); + QTest::newRow("path-with-quotes") << "a=b; path = /with%22Quotes" << cookie; + QTest::newRow("path-with-quotes2") << "a=b; path = \"/with\\\"Quotes\"" << cookie; + + cookie.setPath(QString::fromUtf8("/R\303\251sum\303\251")); + QTest::newRow("path-with-utf8") << "a=b;path=/R\303\251sum\303\251" << cookie; + QTest::newRow("path-with-utf8-2") << "a=b;path=/R%C3%A9sum%C3%A9" << cookie; + + cookie.setPath(QString()); + cookie.setDomain("qt.nokia.com"); + QTest::newRow("plain-domain1") << "a=b;domain=qt.nokia.com" << cookie; + QTest::newRow("plain-domain2") << "a=b; domain=qt.nokia.com " << cookie; + QTest::newRow("plain-domain3") << "a=b;domain=QT.NOKIA.COM" << cookie; + QTest::newRow("plain-domain4") << "a=b;DOMAIN = QT.NOKIA.COM" << cookie; + + cookie.setDomain(".qt.nokia.com"); + QTest::newRow("dot-domain1") << "a=b;domain=.qt.nokia.com" << cookie; + QTest::newRow("dot-domain2") << "a=b; domain=.qt.nokia.com" << cookie; + QTest::newRow("dot-domain3") << "a=b; domain=.QT.NOKIA.COM" << cookie; + QTest::newRow("dot-domain4") << "a=b; Domain = .QT.NOKIA.COM" << cookie; + + cookie.setDomain(QString::fromUtf8(".d\303\270gn\303\245pent.troll.no")); + QTest::newRow("idn-domain1") << "a=b;domain=.xn--dgnpent-gxa2o.troll.no" << cookie; + QTest::newRow("idn-domain2") << "a=b;domain=.d\303\270gn\303\245pent.troll.no" << cookie; + QTest::newRow("idn-domain3") << "a=b;domain=.XN--DGNPENT-GXA2O.TROLL.NO" << cookie; + QTest::newRow("idn-domain4") << "a=b;domain=.D\303\230GN\303\205PENT.troll.NO" << cookie; + + cookie.setDomain(".qt.nokia.com"); + cookie.setPath("/"); + QTest::newRow("two-fields") << "a=b;domain=.qt.nokia.com;path=/" << cookie; + QTest::newRow("two-fields2") << "a=b; domain=.qt.nokia.com; path=/" << cookie; + QTest::newRow("two-fields3") << "a=b; domain=.qt.nokia.com ; path=/ " << cookie; + QTest::newRow("two-fields4") << "a=b;path=/; domain=.qt.nokia.com" << cookie; + QTest::newRow("two-fields5") << "a=b; path=/ ; domain=.qt.nokia.com" << cookie; + QTest::newRow("two-fields6") << "a=b; path= / ; domain =.qt.nokia.com" << cookie; + + cookie.setSecure(true); + QTest::newRow("three-fields") << "a=b;domain=.qt.nokia.com;path=/;secure" << cookie; + QTest::newRow("three-fields2") << "a=b;secure;path=/;domain=.qt.nokia.com" << cookie; + QTest::newRow("three-fields3") << "a=b;secure;domain=.qt.nokia.com; path=/" << cookie; + QTest::newRow("three-fields4") << "a = b;secure;domain=.qt.nokia.com; path=/" << cookie; + + cookie = QNetworkCookie(); + cookie.setName("a"); + cookie.setValue("b"); + cookie.setExpirationDate(QDateTime(QDate(2012, 1, 29), QTime(23, 59, 59), Qt::UTC)); + QTest::newRow("broken-expiration1") << "a=b; expires=Sun, 29-Jan-2012 23:59:59;" << cookie; + + cookie.setExpirationDate(QDateTime(QDate(1999, 11, 9), QTime(23, 12, 40), Qt::UTC)); + QTest::newRow("expiration1") << "a=b;expires=Wednesday, 09-Nov-1999 23:12:40 GMT" << cookie; + QTest::newRow("expiration2") << "a=b;expires=Wed, 09-Nov-1999 23:12:40 GMT" << cookie; + QTest::newRow("expiration3") << "a=b; expires=Wednesday, 09-Nov-1999 23:12:40 GMT " << cookie; + QTest::newRow("expiration-utc") << "a=b;expires=Wednesday, 09-Nov-1999 23:12:40 UTC" << cookie; + + cookie.setExpirationDate(QDateTime(QDate(1989, 4, 14), QTime(3, 20, 0, 0), Qt::UTC)); + QTest::newRow("time-0") << "a=b;expires=14 Apr 89 03:20" << cookie; + cookie.setExpirationDate(QDateTime(QDate(1989, 4, 14), QTime(3, 20, 12, 0), Qt::UTC)); + QTest::newRow("time-1") << "a=b;expires=14 Apr 89 03:20:12" << cookie; + cookie.setExpirationDate(QDateTime(QDate(1989, 4, 14), QTime(3, 20, 12, 88), Qt::UTC)); + QTest::newRow("time-2") << "a=b;expires=14 Apr 89 03:20:12.88" << cookie; + cookie.setExpirationDate(QDateTime(QDate(1989, 4, 14), QTime(3, 20, 12, 88), Qt::UTC)); + QTest::newRow("time-3") << "a=b;expires=14 Apr 89 03:20:12.88am" << cookie; + cookie.setExpirationDate(QDateTime(QDate(1989, 4, 14), QTime(15, 20, 12, 88), Qt::UTC)); + QTest::newRow("time-4") << "a=b;expires=14 Apr 89 03:20:12.88pm" << cookie; + cookie.setExpirationDate(QDateTime(QDate(1989, 4, 14), QTime(3, 20, 12, 88), Qt::UTC)); + QTest::newRow("time-5") << "a=b;expires=14 Apr 89 03:20:12.88 Am" << cookie; + cookie.setExpirationDate(QDateTime(QDate(1989, 4, 14), QTime(15, 20, 12, 88), Qt::UTC)); + QTest::newRow("time-6") << "a=b;expires=14 Apr 89 03:20:12.88 PM" << cookie; + cookie.setExpirationDate(QDateTime(QDate(1989, 4, 14), QTime(15, 20, 12, 88), Qt::UTC)); + QTest::newRow("time-7") << "a=b;expires=14 Apr 89 3:20:12.88 PM" << cookie; + + // normal months + cookie.setExpirationDate(QDateTime(QDate(1989, 1, 1), QTime(1, 1), Qt::UTC)); + QTest::newRow("months-1") << "a=b;expires=Jan 1 89 1:1" << cookie; + cookie.setExpirationDate(QDateTime(QDate(1989, 2, 1), QTime(1, 1), Qt::UTC)); + QTest::newRow("months-2") << "a=b;expires=Feb 1 89 1:1" << cookie; + cookie.setExpirationDate(QDateTime(QDate(1989, 3, 1), QTime(1, 1), Qt::UTC)); + QTest::newRow("months-3") << "a=b;expires=mar 1 89 1:1" << cookie; + cookie.setExpirationDate(QDateTime(QDate(1989, 4, 1), QTime(1, 1), Qt::UTC)); + QTest::newRow("months-4") << "a=b;expires=Apr 1 89 1:1" << cookie; + cookie.setExpirationDate(QDateTime(QDate(1989, 5, 1), QTime(1, 1), Qt::UTC)); + QTest::newRow("months-5") << "a=b;expires=May 1 89 1:1" << cookie; + cookie.setExpirationDate(QDateTime(QDate(1989, 6, 1), QTime(1, 1), Qt::UTC)); + QTest::newRow("months-6") << "a=b;expires=Jun 1 89 1:1" << cookie; + cookie.setExpirationDate(QDateTime(QDate(1989, 7, 1), QTime(1, 1), Qt::UTC)); + QTest::newRow("months-7") << "a=b;expires=Jul 1 89 1:1" << cookie; + cookie.setExpirationDate(QDateTime(QDate(1989, 8, 1), QTime(1, 1), Qt::UTC)); + QTest::newRow("months-8") << "a=b;expires=Aug 1 89 1:1" << cookie; + cookie.setExpirationDate(QDateTime(QDate(1989, 9, 1), QTime(1, 1), Qt::UTC)); + QTest::newRow("months-9") << "a=b;expires=Sep 1 89 1:1" << cookie; + cookie.setExpirationDate(QDateTime(QDate(1989, 10, 1), QTime(1, 1), Qt::UTC)); + QTest::newRow("months-10") << "a=b;expires=Oct 1 89 1:1" << cookie; + cookie.setExpirationDate(QDateTime(QDate(1989, 11, 1), QTime(1, 1), Qt::UTC)); + QTest::newRow("months-11") << "a=b;expires=Nov 1 89 1:1" << cookie; + cookie.setExpirationDate(QDateTime(QDate(1989, 12, 1), QTime(1, 1), Qt::UTC)); + QTest::newRow("months-12") << "a=b;expires=Dec 1 89 1:1" << cookie; + + // extra months + cookie.setExpirationDate(QDateTime(QDate(1989, 12, 1), QTime(1, 1), Qt::UTC)); + QTest::newRow("months-13") << "a=b;expires=December 1 89 1:1" << cookie; + QTest::newRow("months-14") << "a=b;expires=1 89 1:1 Dec" << cookie; + //cookie.setExpirationDate(QDateTime()); + //QTest::newRow("months-15") << "a=b;expires=1 89 1:1 De" << cookie; + cookie.setExpirationDate(QDateTime(QDate(2024, 2, 29), QTime(1, 1), Qt::UTC)); + QTest::newRow("months-16") << "a=b;expires=2024 29 Feb 1:1" << cookie; + cookie.setExpirationDate(QDateTime(QDate(2024, 2, 29), QTime(1, 1), Qt::UTC)); + QTest::newRow("months-17") << "a=b;expires=Fri, 29-Feb-2024 01:01:00 GMT" << cookie; + QTest::newRow("months-18") << "a=b;expires=2024 29 Feb 1:1 GMT" << cookie; + + // normal offsets + cookie.setExpirationDate(QDateTime(QDate(1989, 1, 1), QTime(0, 0), Qt::UTC)); + QTest::newRow("zoneoffset-0") << "a=b;expires=Jan 1 89 8:0 PST" << cookie; + cookie.setExpirationDate(QDateTime(QDate(1989, 1, 1), QTime(0, 0), Qt::UTC)); + QTest::newRow("zoneoffset-1") << "a=b;expires=Jan 1 89 8:0 PDT" << cookie; + cookie.setExpirationDate(QDateTime(QDate(1989, 1, 1), QTime(0, 0), Qt::UTC)); + QTest::newRow("zoneoffset-2") << "a=b;expires=Jan 1 89 7:0 MST" << cookie; + cookie.setExpirationDate(QDateTime(QDate(1989, 1, 1), QTime(0, 0), Qt::UTC)); + QTest::newRow("zoneoffset-3") << "a=b;expires=Jan 1 89 7:0 MDT" << cookie; + cookie.setExpirationDate(QDateTime(QDate(1989, 1, 1), QTime(0, 0), Qt::UTC)); + QTest::newRow("zoneoffset-4") << "a=b;expires=Jan 1 89 6:0 CST" << cookie; + cookie.setExpirationDate(QDateTime(QDate(1989, 1, 1), QTime(0, 0), Qt::UTC)); + QTest::newRow("zoneoffset-5") << "a=b;expires=Jan 1 89 6:0 CDT" << cookie; + cookie.setExpirationDate(QDateTime(QDate(1989, 1, 1), QTime(0, 0), Qt::UTC)); + QTest::newRow("zoneoffset-6") << "a=b;expires=Jan 1 89 5:0 EST" << cookie; + cookie.setExpirationDate(QDateTime(QDate(1989, 1, 1), QTime(0, 0), Qt::UTC)); + QTest::newRow("zoneoffset-7") << "a=b;expires=Jan 1 89 5:0 EDT" << cookie; + cookie.setExpirationDate(QDateTime(QDate(1989, 1, 1), QTime(0, 0), Qt::UTC)); + QTest::newRow("zoneoffset-8") << "a=b;expires=Jan 1 89 4:0 AST" << cookie; + cookie.setExpirationDate(QDateTime(QDate(1989, 1, 1), QTime(0, 0), Qt::UTC)); + QTest::newRow("zoneoffset-9") << "a=b;expires=Jan 1 89 3:0 NST" << cookie; + cookie.setExpirationDate(QDateTime(QDate(1989, 1, 1), QTime(0, 0), Qt::UTC)); + QTest::newRow("zoneoffset-10") << "a=b;expires=Jan 1 89 0:0 GMT" << cookie; + cookie.setExpirationDate(QDateTime(QDate(1989, 1, 1), QTime(0, 0), Qt::UTC)); + QTest::newRow("zoneoffset-11") << "a=b;expires=Jan 1 89 0:0 BST" << cookie; + cookie.setExpirationDate(QDateTime(QDate(1989, 1, 2), QTime(0, 0), Qt::UTC)); + QTest::newRow("zoneoffset-12") << "a=b;expires=Jan 1 89 23:0 MET" << cookie; + cookie.setExpirationDate(QDateTime(QDate(1989, 1, 2), QTime(0, 0), Qt::UTC)); + QTest::newRow("zoneoffset-13") << "a=b;expires=Jan 1 89 22:0 EET" << cookie; + cookie.setExpirationDate(QDateTime(QDate(1989, 1, 2), QTime(0, 0), Qt::UTC)); + QTest::newRow("zoneoffset-14") << "a=b;expires=Jan 1 89 15:0 JST" << cookie; + + // extra offsets + cookie.setExpirationDate(QDateTime(QDate(1989, 1, 2), QTime(0, 0), Qt::UTC)); + QTest::newRow("zoneoffset-14") << "a=b;expires=Jan 1 89 15:0 JST+1" << cookie; + cookie.setExpirationDate(QDateTime(QDate(1989, 1, 1), QTime(1, 0), Qt::UTC)); + QTest::newRow("zoneoffset-15") << "a=b;expires=Jan 1 89 0:0 GMT+1" << cookie; + cookie.setExpirationDate(QDateTime(QDate(1989, 1, 1), QTime(0, 0), Qt::UTC)); + QTest::newRow("zoneoffset-15b") << "a=b;expires=Jan 1 89 1:0 GMT-1" << cookie; + cookie.setExpirationDate(QDateTime(QDate(1989, 1, 1), QTime(1, 0), Qt::UTC)); + QTest::newRow("zoneoffset-16") << "a=b;expires=Jan 1 89 0:0 GMT+01" << cookie; + cookie.setExpirationDate(QDateTime(QDate(1989, 1, 1), QTime(1, 5), Qt::UTC)); + QTest::newRow("zoneoffset-17") << "a=b;expires=Jan 1 89 0:0 GMT+0105" << cookie; + cookie.setExpirationDate(QDateTime(QDate(1989, 1, 1), QTime(0, 0), Qt::UTC)); + QTest::newRow("zoneoffset-18") << "a=b;expires=Jan 1 89 0:0 GMT+015" << cookie; + cookie.setExpirationDate(QDateTime(QDate(1989, 1, 1), QTime(0, 0), Qt::UTC)); + QTest::newRow("zoneoffset-19") << "a=b;expires=Jan 1 89 0:0 GM" << cookie; + cookie.setExpirationDate(QDateTime(QDate(1989, 1, 1), QTime(0, 0), Qt::UTC)); + QTest::newRow("zoneoffset-19b") << "a=b;expires=Jan 1 89 0:0 GMT" << cookie; + + // offsets from gmt + cookie.setExpirationDate(QDateTime(QDate(1989, 1, 1), QTime(1, 0), Qt::UTC)); + QTest::newRow("zoneoffset-20") << "a=b;expires=Jan 1 89 0:0 +1" << cookie; + cookie.setExpirationDate(QDateTime(QDate(1989, 1, 1), QTime(1, 0), Qt::UTC)); + QTest::newRow("zoneoffset-21") << "a=b;expires=Jan 1 89 0:0 +01" << cookie; + cookie.setExpirationDate(QDateTime(QDate(1989, 1, 1), QTime(1, 1), Qt::UTC)); + QTest::newRow("zoneoffset-22") << "a=b;expires=Jan 1 89 0:0 +0101" << cookie; + cookie.setExpirationDate(QDateTime(QDate(1989, 1, 1), QTime(0, 0), Qt::UTC)); + QTest::newRow("zoneoffset-23") << "a=b;expires=Jan 1 89 1:0 -1" << cookie; + + // Y2k + cookie.setExpirationDate(QDateTime(QDate(2000, 1, 1), QTime(0, 0), Qt::UTC)); + QTest::newRow("year-0") << "a=b;expires=Jan 1 00 0:0" << cookie; + cookie.setExpirationDate(QDateTime(QDate(1970, 1, 1), QTime(0, 0), Qt::UTC)); + QTest::newRow("year-1") << "a=b;expires=Jan 1 70 0:0" << cookie; + cookie.setExpirationDate(QDateTime(QDate(1971, 1, 1), QTime(0, 0), Qt::UTC)); + QTest::newRow("year-2") << "a=b;expires=Jan 1 71 0:0" << cookie; + + // Day, month, year + cookie.setExpirationDate(QDateTime(QDate(2013, 1, 2), QTime(0, 0), Qt::UTC)); + QTest::newRow("date-0") << "a=b;expires=Jan 2 13 0:0" << cookie; + QTest::newRow("date-1") << "a=b;expires=1-2-13 0:0" << cookie; + QTest::newRow("date-2") << "a=b;expires=1/2/13 0:0" << cookie; + QTest::newRow("date-3") << "a=b;expires=Jan 2 13 0:0" << cookie; + QTest::newRow("date-4") << "a=b;expires=Jan 2, 13 0:0" << cookie; + QTest::newRow("date-5") << "a=b;expires=1-2-13 0:0" << cookie; + QTest::newRow("date-6") << "a=b;expires=1/2/13 0:0" << cookie; + + // Known Year, determine month and day + cookie.setExpirationDate(QDateTime(QDate(1995, 1, 13), QTime(0, 0), Qt::UTC)); + QTest::newRow("knownyear-0") << "a=b;expires=13/1/95 0:0" << cookie; + QTest::newRow("knownyear-1") << "a=b;expires=95/13/1 0:0" << cookie; + QTest::newRow("knownyear-2") << "a=b;expires=1995/1/13 0:0" << cookie; + QTest::newRow("knownyear-3") << "a=b;expires=1995/13/1 0:0" << cookie; + cookie.setExpirationDate(QDateTime(QDate(1995, 1, 2), QTime(0, 0), Qt::UTC)); + QTest::newRow("knownyear-4") << "a=b;expires=1/2/95 0:0" << cookie; + QTest::newRow("knownyear-5") << "a=b;expires=95/1/2 0:0" << cookie; + + // Known Year, Known day, determining month + cookie.setExpirationDate(QDateTime(QDate(1995, 1, 13), QTime(0, 0), Qt::UTC)); + QTest::newRow("knownYD-0") << "a=b;expires=13/1/95 0:0" << cookie; + QTest::newRow("knownYD-1") << "a=b;expires=1/13/95 0:0" << cookie; + QTest::newRow("knownYD-2") << "a=b;expires=95/13/1 0:0" << cookie; + QTest::newRow("knownYD-3") << "a=b;expires=95/1/13 0:0" << cookie; + + // Month comes before Year + cookie.setExpirationDate(QDateTime(QDate(2021, 03, 26), QTime(0, 0), Qt::UTC)); + QTest::newRow("month-0") << "a=b;expires=26/03/21 0:0" << cookie; + cookie.setExpirationDate(QDateTime(QDate(2015, 12, 30), QTime(16, 25, 0, 0), Qt::UTC)); + QTest::newRow("month-1") << "a=b;expires=wed 16:25pm December 2015 30" << cookie; + cookie.setExpirationDate(QDateTime(QDate(2031, 11, 11), QTime(16, 25, 0, 0), Qt::UTC)); + QTest::newRow("month-2") << "a=b;expires=16:25 11 31 11" << cookie; + + // The very ambiguous cases + // Matching Firefox's behavior of guessing month, day, year in those cases + cookie.setExpirationDate(QDateTime(QDate(2013, 10, 2), QTime(0, 0), Qt::UTC)); + QTest::newRow("ambiguousd-0") << "a=b;expires=10/2/13 0:0" << cookie; + cookie.setExpirationDate(QDateTime(QDate(2013, 2, 10), QTime(0, 0), Qt::UTC)); + QTest::newRow("ambiguousd-1") << "a=b;expires=2/10/13 0:0" << cookie; + cookie.setExpirationDate(QDateTime(QDate(2010, 2, 3), QTime(0, 0), Qt::UTC)); + QTest::newRow("ambiguousd-2") << "a=b;expires=2/3/10 0:0" << cookie; + + // FYI If you try these in Firefox it wont set a cookie for the following two string + // because 03 is turned into the year at which point it is expired + cookie.setExpirationDate(QDateTime(QDate(2003, 2, 10), QTime(0, 0), Qt::UTC)); + QTest::newRow("ambiguousd-3") << "a=b;expires=2/10/3 0:0" << cookie; + cookie.setExpirationDate(QDateTime(QDate(2003, 10, 2), QTime(0, 0), Qt::UTC)); + QTest::newRow("ambiguousd-4") << "a=b;expires=10/2/3 0:0" << cookie; + + // These are the cookies that firefox's source says it can parse + cookie.setExpirationDate(QDateTime(QDate(1989, 4, 14), QTime(3, 20, 0, 0), Qt::UTC)); + QTest::newRow("firefox-0") << "a=b;expires=14 Apr 89 03:20" << cookie; + + cookie.setExpirationDate(QDateTime(QDate(1989, 4, 14), QTime(3, 20, 0, 0), Qt::UTC)); + QTest::newRow("firefox-1") << "a=b;expires=14 Apr 89 03:20 GMT" << cookie; + + cookie.setExpirationDate(QDateTime(QDate(1989, 3, 17), QTime(4, 1, 33, 0), Qt::UTC)); + QTest::newRow("firefox-2") << "a=b;expires=Fri, 17 Mar 89 4:01:33" << cookie; + + cookie.setExpirationDate(QDateTime(QDate(1989, 3, 17), QTime(4, 1, 0, 0), Qt::UTC)); + QTest::newRow("firefox-3") << "a=b;expires=Fri, 17 Mar 89 4:01 GMT" << cookie; + + cookie.setExpirationDate(QDateTime(QDate(1989, 1, 16), QTime(16-8, 12, 0, 0), Qt::UTC)); + QTest::newRow("firefox-4") << "a=b;expires=Mon Jan 16 16:12 PDT 1989" << cookie; + + cookie.setExpirationDate(QDateTime(QDate(1989, 1, 16), QTime(17, 42, 0, 0), Qt::UTC)); + QTest::newRow("firefox-5") << "a=b;expires=Mon Jan 16 16:12 +0130 1989" << cookie; + + cookie.setExpirationDate(QDateTime(QDate(1992, 5, 6), QTime(16-9, 41, 0, 0), Qt::UTC)); + QTest::newRow("firefox-6") << "a=b;expires=6 May 1992 16:41-JST (Wednesday)" << cookie; + + cookie.setExpirationDate(QDateTime(QDate(1993, 8, 22), QTime(10, 59, 12, 82), Qt::UTC)); + QTest::newRow("firefox-7") << "a=b;expires=22-AUG-1993 10:59:12.82" << cookie; + + cookie.setExpirationDate(QDateTime(QDate(1993, 8, 22), QTime(22, 59, 0, 0), Qt::UTC)); + QTest::newRow("firefox-8") << "a=b;expires=22-AUG-1993 10:59pm" << cookie; + + cookie.setExpirationDate(QDateTime(QDate(1993, 8, 22), QTime(12, 59, 0, 0), Qt::UTC)); + QTest::newRow("firefox-9") << "a=b;expires=22-AUG-1993 12:59am" << cookie; + + cookie.setExpirationDate(QDateTime(QDate(1993, 8, 22), QTime(12, 59, 0, 0), Qt::UTC)); + QTest::newRow("firefox-10") << "a=b;expires=22-AUG-1993 12:59 PM" << cookie; + + cookie.setExpirationDate(QDateTime(QDate(1995, 8, 4), QTime(15, 54, 0, 0), Qt::UTC)); + QTest::newRow("firefox-11") << "a=b;expires=Friday, August 04, 1995 3:54 PM" << cookie; + + cookie.setExpirationDate(QDateTime(QDate(1995, 6, 21), QTime(16, 24, 34, 0), Qt::UTC)); + QTest::newRow("firefox-12") << "a=b;expires=06/21/95 04:24:34 PM" << cookie; + + cookie.setExpirationDate(QDateTime(QDate(1995, 6, 20), QTime(21, 7, 0, 0), Qt::UTC)); + QTest::newRow("firefox-13") << "a=b;expires=20/06/95 21:07" << cookie; + + cookie.setExpirationDate(QDateTime(QDate(1995, 6, 8), QTime(19-5, 32, 48, 0), Qt::UTC)); + QTest::newRow("firefox-14") << "a=b;expires=95-06-08 19:32:48 EDT" << cookie; + + // Edge cases caught by fuzzing + // These are about the default cause creates dates that don't exits + cookie.setExpirationDate(QDateTime(QDate(2030, 2, 25), QTime(1, 1, 0, 0), Qt::UTC)); + QTest::newRow("fuzz-0") << "a=b; expires=30 -000002 1:1 25;" << cookie; + + cookie.setExpirationDate(QDateTime(QDate(2031, 11, 20), QTime(1, 1, 0, 0), Qt::UTC)); + QTest::newRow("fuzz-1") << "a=b; expires=31 11 20 1:1;" << cookie; + + // April only has 30 days + cookie.setExpirationDate(QDateTime(QDate(2031, 4, 30), QTime(1, 1, 0, 0), Qt::UTC)); + QTest::newRow("fuzz-2") << "a=b; expires=31 30 4 1:1" << cookie; + + // 9 must be the month so 31 can't be the day + cookie.setExpirationDate(QDateTime(QDate(2031, 9, 21), QTime(1, 1, 0, 0), Qt::UTC)); + QTest::newRow("fuzz-3") << "a=b; expires=31 21 9 1:1" << cookie; + + // Year is known, then fallback to defaults of filling in month and day + cookie.setExpirationDate(QDateTime(QDate(2031, 11, 1), QTime(1, 1, 0, 0), Qt::UTC)); + QTest::newRow("fuzz-4") << "a=b; expires=31 11 01 1:1" << cookie; + + // 2 must be the month so 30 can't be the day + cookie.setExpirationDate(QDateTime(QDate(2030, 2, 20), QTime(1, 1, 0, 0), Qt::UTC)); + QTest::newRow("fuzz-5") << "a=b; expires=30 02 20 1:1" << cookie; + + cookie.setExpirationDate(QDateTime(QDate(2021, 12, 22), QTime(1, 1, 0, 0), Qt::UTC)); + QTest::newRow("fuzz-6") << "a=b; expires=2021 12 22 1:1" << cookie; + + cookie.setExpirationDate(QDateTime(QDate(2029, 2, 23), QTime(1, 1, 0, 0), Qt::UTC)); + QTest::newRow("fuzz-7") << "a=b; expires=29 23 Feb 1:1" << cookie; + + // 11 and 6 don't have 31 days + cookie.setExpirationDate(QDateTime(QDate(2031, 11, 06), QTime(1, 1, 0, 0), Qt::UTC)); + QTest::newRow("fuzz-8") << "a=b; expires=31 11 06 1:1" << cookie; + + // two-digit years: + // from 70 until 99, we assume 20th century + cookie.setExpirationDate(QDateTime(QDate(1999, 11, 9), QTime(23, 12, 40), Qt::UTC)); + QTest::newRow("expiration-2digit1") << "a=b; expires=Wednesday, 09-Nov-99 23:12:40 GMT " << cookie; + cookie.setExpirationDate(QDateTime(QDate(1970, 1, 1), QTime(23, 12, 40), Qt::UTC)); + QTest::newRow("expiration-2digit2") << "a=b; expires=Thursday, 01-Jan-70 23:12:40 GMT " << cookie; + // from 00 until 69, we assume 21st century + cookie.setExpirationDate(QDateTime(QDate(2000, 1, 1), QTime(23, 12, 40), Qt::UTC)); + QTest::newRow("expiration-2digit3") << "a=b; expires=Saturday, 01-Jan-00 23:12:40 GMT " << cookie; + cookie.setExpirationDate(QDateTime(QDate(2020, 1, 1), QTime(23, 12, 40), Qt::UTC)); + QTest::newRow("expiration-2digit4") << "a=b; expires=Wednesday, 01-Jan-20 23:12:40 GMT " << cookie; + cookie.setExpirationDate(QDateTime(QDate(2069, 1, 1), QTime(23, 12, 40), Qt::UTC)); + QTest::newRow("expiration-2digit5") << "a=b; expires=Wednesday, 01-Jan-69 23:12:40 GMT " << cookie; + + cookie.setExpirationDate(QDateTime(QDate(1999, 11, 9), QTime(23, 12, 40), Qt::UTC)); + + cookie.setPath("/"); + QTest::newRow("expires+path") << "a=b; expires=Wed, 09-Nov-1999 23:12:40 GMT; path=/" << cookie; + QTest::newRow("path+expires") << "a=b; path=/;expires=Wed, 09-Nov-1999 23:12:40 GMT " << cookie; + + cookie.setDomain(".qt.nokia.com"); + QTest::newRow("full") << "a=b; domain=.qt.nokia.com;expires=Wed, 09-Nov-1999 23:12:40 GMT;path=/" << cookie; + QTest::newRow("full2") << "a=b;path=/; expires=Wed, 09-Nov-1999 23:12:40 GMT ;domain=.qt.nokia.com" << cookie; + + // cookies obtained from the network: + cookie = QNetworkCookie("__siteid", "1"); + cookie.setPath("/"); + cookie.setExpirationDate(QDateTime(QDate(9999, 12, 31), QTime(23, 59, 59), Qt::UTC)); + QTest::newRow("network2") << "__siteid=1; expires=Fri, 31-Dec-9999 23:59:59 GMT; path=/" << cookie; + + cookie = QNetworkCookie("YM.LC", "v=2&m=9993_262838_159_1558_1063_0_5649_4012_3776161073,9426_260205_549_1295_1336_0_5141_4738_3922731647,6733_258196_952_1364_643_0_3560_-1_0,3677_237633_1294_1294_19267_0_3244_29483_4102206176,1315_235149_1693_1541_941_0_3224_1691_1861378060,1858_214311_2100_1298_19538_0_2873_30900_716411652,6258_212007_2506_1285_1017_0_2868_3606_4288540264,3743_207884_2895_1362_2759_0_2545_7114_3388520216,2654_205253_3257_1297_1332_0_2504_4682_3048534803,1891_184881_3660_1291_19079_0_978_29178_2592538685&f=1&n=20&s=date&o=down&e=1196548712&b=Inbox&u=removed"); + cookie.setPath("/"); + cookie.setDomain("mail.yahoo.com"); + QTest::newRow("network3") << "YM.LC=v=2&m=9993_262838_159_1558_1063_0_5649_4012_3776161073,9426_260205_549_1295_1336_0_5141_4738_3922731647,6733_258196_952_1364_643_0_3560_-1_0,3677_237633_1294_1294_19267_0_3244_29483_4102206176,1315_235149_1693_1541_941_0_3224_1691_1861378060,1858_214311_2100_1298_19538_0_2873_30900_716411652,6258_212007_2506_1285_1017_0_2868_3606_4288540264,3743_207884_2895_1362_2759_0_2545_7114_3388520216,2654_205253_3257_1297_1332_0_2504_4682_3048534803,1891_184881_3660_1291_19079_0_978_29178_2592538685&f=1&n=20&s=date&o=down&e=1196548712&b=Inbox&u=removed; path=/; domain=mail.yahoo.com" << cookie; + + cookie = QNetworkCookie("__ac", "\"c2hhdXNtYW46U2FTYW80Wm8%3D\""); + cookie.setPath("/"); + cookie.setExpirationDate(QDateTime(QDate(2008, 8, 30), QTime(20, 21, 49), Qt::UTC)); + QTest::newRow("network4") << "__ac=\"c2hhdXNtYW46U2FTYW80Wm8%3D\"; Path=/; Expires=Sat, 30 Aug 2008 20:21:49 +0000" << cookie; + + // linkedin.com sends cookies in quotes and expects the cookie in quotes + cookie = QNetworkCookie("leo_auth_token", "\"GST:UroVXaxYA3sVSkoVjMNH9bj4dZxVzK2yekgrAUxMfUsyLTNyPjoP60:1298974875:b675566ae32ab36d7a708c0efbf446a5c22b9fca\""); + cookie.setPath("/"); + cookie.setExpirationDate(QDateTime(QDate(2011, 3, 1), QTime(10, 51, 14), Qt::UTC)); + QTest::newRow("network5") << "leo_auth_token=\"GST:UroVXaxYA3sVSkoVjMNH9bj4dZxVzK2yekgrAUxMfUsyLTNyPjoP60:1298974875:b675566ae32ab36d7a708c0efbf446a5c22b9fca\"; Version=1; Max-Age=1799; Expires=Tue, 01-Mar-2011 10:51:14 GMT; Path=/" << cookie; + + +} + +void tst_QNetworkCookie::parseSingleCookie() +{ + QFETCH(QString, cookieString); + QFETCH(QNetworkCookie, expectedCookie); + + QList<QNetworkCookie> result = QNetworkCookie::parseCookies(cookieString.toLatin1()); + + //QEXPECT_FAIL("network2", "QDateTime parsing problem: the date is beyond year 8000", Abort); + QCOMPARE(result.count(), 1); + QEXPECT_FAIL("network3", "Cookie value contains commas, violating the HTTP spec", Abort); + QCOMPARE(result.at(0), expectedCookie); + + result = QNetworkCookie::parseCookies(result.at(0).toRawForm()); + QCOMPARE(result.count(), 1); + + // Drop any millisecond information, if there's any + QDateTime dt = expectedCookie.expirationDate(); + if (dt.isValid()) { + QTime t = dt.time(); + dt.setTime(t.addMSecs(-t.msec())); + expectedCookie.setExpirationDate(dt); + } + + QCOMPARE(result.at(0), expectedCookie); +} + +void tst_QNetworkCookie::parseMultipleCookies_data() +{ + QTest::addColumn<QString>("cookieString"); + QTest::addColumn<QList<QNetworkCookie> >("expectedCookies"); + + QList<QNetworkCookie> list; + QTest::newRow("empty") << "" << list; + + // these are technically empty cookies: + QTest::newRow("invalid-01") << ";" << list; + QTest::newRow("invalid-02") << " " << list; + QTest::newRow("invalid-03") << " ," << list; + QTest::newRow("invalid-04") << ";;,, ; ; , , ; , ;" << list; + + // these are really invalid: + // reason: malformed NAME=VALUE pair + QTest::newRow("invalid-05") << "foo" << list; + QTest::newRow("invalid-06") << "=b" << list; + QTest::newRow("invalid-09") << "foo,a=b" << list; + QTest::newRow("invalid-11") << ";path=/" << list; + + // reason: malformed expiration date string + QTest::newRow("invalid-12") << "a=b;expires=" << list; + QTest::newRow("invalid-13") << "a=b;expires=foobar" << list; + QTest::newRow("invalid-14") << "a=b;expires=foobar, abc" << list; + QTest::newRow("invalid-15") << "a=b;expires=foobar, dd-mmm-yyyy hh:mm:ss GMT; path=/" << list; + QTest::newRow("invalid-16") << "a=b;expires=foobar, 32-Caz-1999 24:01:60 GMT; path=/" << list; + + QNetworkCookie cookie; + cookie.setName("a"); + list += cookie; + cookie.setName("c"); + cookie.setValue("d"); + list += cookie; + QTest::newRow("two-1") << "a=,c=d" << list; + QTest::newRow("two-2") << "a=, c=d" << list; + QTest::newRow("two-3") << "a= ,c=d" << list; + QTest::newRow("two-4") << "a= , c=d" << list; + + list.clear(); + list += cookie; + cookie.setName("a"); + cookie.setValue(QByteArray()); + list += cookie; + QTest::newRow("two-5") << "c=d,a=" << list; + QTest::newRow("two-6") << "c=d, a=" << list; + QTest::newRow("two-7") << "c=d , a=" << list; + + cookie.setName("foo"); + cookie.setValue("bar"); + cookie.setPath("/"); + list += cookie; + QTest::newRow("complex-1") << "c=d, a=, foo=bar; path=/" << list; + + cookie.setName("baz"); + cookie.setDomain(".qt.nokia.com"); + list.prepend(cookie); + QTest::newRow("complex-2") << "baz=bar; path=/; domain=.qt.nokia.com, c=d,a=,foo=bar; path=/" << list; + + // cookies obtained from the network: + cookie = QNetworkCookie("id", "51706646077999719"); + cookie.setDomain(".bluestreak.com"); + cookie.setPath("/"); + cookie.setExpirationDate(QDateTime(QDate(2017, 12, 05), QTime(9, 11, 7), Qt::UTC)); + list << cookie; + cookie.setName("bb"); + cookie.setValue("\\\"K14144t\\\"_AAQ\\\"ototrK_A_ttot44AQ4KwoRQtoto|"); + list << cookie; + cookie.setName("adv"); + cookie.setValue(QByteArray()); + list << cookie; + QTest::newRow("network1") << "id=51706646077999719 bb=\"K14144t\"_AAQ\"ototrK_A_ttot44AQ4KwoRQtoto| adv=; Domain=.bluestreak.com; expires=Tuesday 05-Dec-2017 09:11:07 GMT; path=/;" << list; + + QNetworkCookie cookieA; + cookieA.setName("a"); + cookieA.setValue("b"); + + QNetworkCookie cookieB; + cookieB.setName("c"); + cookieB.setValue("d"); + + // NewLine + cookieA.setExpirationDate(QDateTime(QDate(2009, 3, 10), QTime(7, 0, 0, 0), Qt::UTC)); + cookieB.setExpirationDate(QDateTime(QDate(2009, 3, 20), QTime(7, 0, 0, 0), Qt::UTC)); + list = QList<QNetworkCookie>() << cookieA << cookieB; + QTest::newRow("real-0") << "a=b; expires=Tue Mar 10 07:00:00 2009 GMT\nc=d; expires=Fri Mar 20 07:00:00 2009 GMT" << list; + QTest::newRow("real-1") << "a=b; expires=Tue Mar 10 07:00:00 2009 GMT\n\nc=d; expires=Fri Mar 20 07:00:00 2009 GMT" << list; + QTest::newRow("real-2") << "a=b; expires=Mar 10 07:00:00 2009 GMT, Tue\nc=d; expires=Fri Mar 20 07:00:00 2009 GMT" << list; + + // Match firefox's behavior + cookieA.setPath("/foo"); + list = QList<QNetworkCookie>() << cookieA << cookieB; + QTest::newRow("real-3") << "a=b; expires=Mar 10 07:00:00 2009 GMT, Tue; path=/foo\nc=d; expires=Fri Mar 20 07:00:00 2009 GMT" << list; + + // do not accept cookies with non-alphanumeric characters in domain field (QTBUG-11029) + cookie = QNetworkCookie("NonAlphNumDomName", "NonAlphNumDomValue"); + cookie.setDomain("!@#$%^&*();:."); // the ';' is actually problematic, because it is a separator + list = QList<QNetworkCookie>(); + QTest::newRow("domain-non-alpha-numeric") << "NonAlphNumDomName=NonAlphNumDomValue; domain=!@#$%^&*()" << list; + QTest::newRow("expiration-3digit1") << "a=b; expires=123" << list; // used to ASSERT +} + +void tst_QNetworkCookie::parseMultipleCookies() +{ + QFETCH(QString, cookieString); + QFETCH(QList<QNetworkCookie>, expectedCookies); + + QList<QNetworkCookie> result = QNetworkCookie::parseCookies(cookieString.toLatin1()); + + QEXPECT_FAIL("network1", "Apparently multiple cookies set in one request (and an invalid date)", Abort); + QCOMPARE(result, expectedCookies); +} + +QTEST_MAIN(tst_QNetworkCookie) +#include "tst_qnetworkcookie.moc" diff --git a/tests/auto/network/access/qnetworkcookiejar/.gitignore b/tests/auto/network/access/qnetworkcookiejar/.gitignore new file mode 100644 index 0000000000..918754a274 --- /dev/null +++ b/tests/auto/network/access/qnetworkcookiejar/.gitignore @@ -0,0 +1 @@ +tst_qnetworkcookiejar diff --git a/tests/auto/network/access/qnetworkcookiejar/qnetworkcookiejar.pro b/tests/auto/network/access/qnetworkcookiejar/qnetworkcookiejar.pro new file mode 100644 index 0000000000..4e5f01745a --- /dev/null +++ b/tests/auto/network/access/qnetworkcookiejar/qnetworkcookiejar.pro @@ -0,0 +1,5 @@ +load(qttest_p4) +SOURCES += tst_qnetworkcookiejar.cpp + +QT = core core-private network network-private +symbian: TARGET.CAPABILITY = NetworkServices diff --git a/tests/auto/network/access/qnetworkcookiejar/tst_qnetworkcookiejar.cpp b/tests/auto/network/access/qnetworkcookiejar/tst_qnetworkcookiejar.cpp new file mode 100644 index 0000000000..1b4256bb00 --- /dev/null +++ b/tests/auto/network/access/qnetworkcookiejar/tst_qnetworkcookiejar.cpp @@ -0,0 +1,446 @@ +/**************************************************************************** +** +** 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 test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** 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. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + + +#include <QtTest/QtTest> +#include <QtNetwork/QNetworkCookieJar> +#include "private/qtldurl_p.h" + +class tst_QNetworkCookieJar: public QObject +{ + Q_OBJECT + +private slots: + void getterSetter(); + void setCookiesFromUrl_data(); + void setCookiesFromUrl(); + void cookiesForUrl_data(); + void cookiesForUrl(); + void effectiveTLDs_data(); + void effectiveTLDs(); +}; + +QT_BEGIN_NAMESPACE + +namespace QTest { + template<> + char *toString(const QNetworkCookie &cookie) + { + return qstrdup(cookie.toRawForm()); + } + + template<> + char *toString(const QList<QNetworkCookie> &list) + { + QString result = "QList("; + bool first = true; + foreach (QNetworkCookie cookie, list) { + if (!first) + result += ", "; + first = false; + result += QString::fromLatin1("QNetworkCookie(%1)").arg(QLatin1String(cookie.toRawForm())); + } + + return qstrdup(result.append(')').toLocal8Bit()); + } +} + +QT_END_NAMESPACE + +class MyCookieJar: public QNetworkCookieJar +{ +public: + inline QList<QNetworkCookie> allCookies() const + { return QNetworkCookieJar::allCookies(); } + inline void setAllCookies(const QList<QNetworkCookie> &cookieList) + { QNetworkCookieJar::setAllCookies(cookieList); } +}; + +void tst_QNetworkCookieJar::getterSetter() +{ + MyCookieJar jar; + + QVERIFY(jar.allCookies().isEmpty()); + + QList<QNetworkCookie> list; + QNetworkCookie cookie; + cookie.setName("a"); + list << cookie; + + jar.setAllCookies(list); + QCOMPARE(jar.allCookies(), list); +} + +void tst_QNetworkCookieJar::setCookiesFromUrl_data() +{ + QTest::addColumn<QList<QNetworkCookie> >("preset"); + QTest::addColumn<QNetworkCookie>("newCookie"); + QTest::addColumn<QString>("referenceUrl"); + QTest::addColumn<QList<QNetworkCookie> >("expectedResult"); + QTest::addColumn<bool>("setCookies"); + + QList<QNetworkCookie> preset; + QList<QNetworkCookie> result; + QNetworkCookie cookie; + + cookie.setName("a"); + cookie.setPath("/"); + cookie.setDomain(".foo.tld"); + result += cookie; + QTest::newRow("just-add") << preset << cookie << "http://www.foo.tld" << result << true; + + preset = result; + QTest::newRow("replace-1") << preset << cookie << "http://www.foo.tld" << result << true; + + cookie.setValue("bc"); + result.clear(); + result += cookie; + QTest::newRow("replace-2") << preset << cookie << "http://www.foo.tld" << result << true; + + preset = result; + cookie.setName("d"); + result += cookie; + QTest::newRow("append") << preset << cookie << "http://www.foo.tld" << result << true; + + cookie = preset.at(0); + result = preset; + cookie.setPath("/something"); + result += cookie; + QTest::newRow("diff-path") << preset << cookie << "http://www.foo.tld/something" << result << true; + + preset.clear(); + preset += cookie; + cookie.setPath("/"); + QTest::newRow("diff-path-order") << preset << cookie << "http://www.foo.tld" << result << true; + + preset.clear(); + result.clear(); + QNetworkCookie finalCookie = cookie; + cookie.setDomain("foo.tld"); + finalCookie.setDomain(".foo.tld"); + result += finalCookie; + QTest::newRow("should-add-dot-prefix") << preset << cookie << "http://www.foo.tld" << result << true; + + result.clear(); + cookie.setDomain(""); + finalCookie.setDomain("www.foo.tld"); + result += finalCookie; + QTest::newRow("should-set-default-domain") << preset << cookie << "http://www.foo.tld" << result << true; + + // security test: + result.clear(); + preset.clear(); + cookie.setDomain("something.completely.different"); + QTest::newRow("security-domain-1") << preset << cookie << "http://www.foo.tld" << result << false; + + // we want the cookie to be accepted although the path does not match, see QTBUG-5815 + cookie.setDomain(".foo.tld"); + cookie.setPath("/something"); + result += cookie; + QTest::newRow("security-path-1") << preset << cookie << "http://www.foo.tld" << result << true; + + // check effective TLDs + // 1. co.uk is an effective TLD, should be denied + result.clear(); + preset.clear(); + cookie.setPath("/"); + cookie.setDomain(".co.uk"); + QTest::newRow("effective-tld1-denied") << preset << cookie << "http://something.co.uk" << result << false; + cookie.setDomain("co.uk"); + QTest::newRow("effective-tld1-denied2") << preset << cookie << "http://something.co.uk" << result << false; + cookie.setDomain(".something.co.uk"); + result += cookie; + QTest::newRow("effective-tld1-accepted") << preset << cookie << "http://something.co.uk" << result << true; + + // 2. anything .ar is an effective TLD ('*.ar'), but 'gobiernoelectronico.ar' is an exception + result.clear(); + preset.clear(); + cookie.setDomain(".farmacia.ar"); + QTest::newRow("effective-tld2-denied") << preset << cookie << "http://farmacia.ar" << result << false; + QTest::newRow("effective-tld2-denied2") << preset << cookie << "http://www.farmacia.ar" << result << false; + QTest::newRow("effective-tld2-denied3") << preset << cookie << "http://www.anything.farmacia.ar" << result << false; + cookie.setDomain(".gobiernoelectronico.ar"); + result += cookie; + QTest::newRow("effective-tld2-accepted") << preset << cookie << "http://www.gobiernoelectronico.ar" << result << true; + + + // setting the defaults: + finalCookie = cookie; + finalCookie.setPath("/something/"); + finalCookie.setDomain("www.foo.tld"); + cookie.setPath(""); + cookie.setDomain(""); + result.clear(); + result += finalCookie; + QTest::newRow("defaults-1") << preset << cookie << "http://www.foo.tld/something/" << result << true; + + finalCookie.setPath("/"); + result.clear(); + result += finalCookie; + QTest::newRow("defaults-2") << preset << cookie << "http://www.foo.tld" << result << true; + + // security test: do not accept cookie domains like ".com" nor ".com." (see RFC 2109 section 4.3.2) + result.clear(); + preset.clear(); + cookie.setDomain(".com"); + QTest::newRow("rfc2109-4.3.2-ex3") << preset << cookie << "http://x.foo.com" << result << false; + + result.clear(); + preset.clear(); + cookie.setDomain(".com."); + QTest::newRow("rfc2109-4.3.2-ex3-2") << preset << cookie << "http://x.foo.com" << result << false; +} + +void tst_QNetworkCookieJar::setCookiesFromUrl() +{ + QFETCH(QList<QNetworkCookie>, preset); + QFETCH(QNetworkCookie, newCookie); + QFETCH(QString, referenceUrl); + QFETCH(QList<QNetworkCookie>, expectedResult); + QFETCH(bool, setCookies); + + QList<QNetworkCookie> cookieList; + cookieList += newCookie; + MyCookieJar jar; + jar.setAllCookies(preset); + QCOMPARE(jar.setCookiesFromUrl(cookieList, referenceUrl), setCookies); + + QList<QNetworkCookie> result = jar.allCookies(); + foreach (QNetworkCookie cookie, expectedResult) { + QVERIFY2(result.contains(cookie), cookie.toRawForm()); + result.removeAll(cookie); + } + QVERIFY2(result.isEmpty(), QTest::toString(result)); +} + +void tst_QNetworkCookieJar::cookiesForUrl_data() +{ + QTest::addColumn<QList<QNetworkCookie> >("allCookies"); + QTest::addColumn<QString>("url"); + QTest::addColumn<QList<QNetworkCookie> >("expectedResult"); + + QList<QNetworkCookie> allCookies; + QList<QNetworkCookie> result; + + QTest::newRow("no-cookies") << allCookies << "http://foo.bar/" << result; + + QNetworkCookie cookie; + cookie.setName("a"); + cookie.setPath("/web"); + cookie.setDomain(".nokia.com"); + allCookies += cookie; + + QTest::newRow("no-match-1") << allCookies << "http://foo.bar/" << result; + QTest::newRow("no-match-2") << allCookies << "http://foo.bar/web" << result; + QTest::newRow("no-match-3") << allCookies << "http://foo.bar/web/wiki" << result; + QTest::newRow("no-match-4") << allCookies << "http://nokia.com" << result; + QTest::newRow("no-match-5") << allCookies << "http://qt.nokia.com" << result; + QTest::newRow("no-match-6") << allCookies << "http://nokia.com/webinar" << result; + QTest::newRow("no-match-7") << allCookies << "http://qt.nokia.com/webinar" << result; + + result = allCookies; + QTest::newRow("match-1") << allCookies << "http://nokia.com/web" << result; + QTest::newRow("match-2") << allCookies << "http://nokia.com/web/" << result; + QTest::newRow("match-3") << allCookies << "http://nokia.com/web/content" << result; + QTest::newRow("match-4") << allCookies << "http://qt.nokia.com/web" << result; + QTest::newRow("match-4") << allCookies << "http://qt.nokia.com/web/" << result; + QTest::newRow("match-6") << allCookies << "http://qt.nokia.com/web/content" << result; + + cookie.setPath("/web/wiki"); + allCookies += cookie; + + // exact same results as before: + QTest::newRow("one-match-1") << allCookies << "http://nokia.com/web" << result; + QTest::newRow("one-match-2") << allCookies << "http://nokia.com/web/" << result; + QTest::newRow("one-match-3") << allCookies << "http://nokia.com/web/content" << result; + QTest::newRow("one-match-4") << allCookies << "http://qt.nokia.com/web" << result; + QTest::newRow("one-match-4") << allCookies << "http://qt.nokia.com/web/" << result; + QTest::newRow("one-match-6") << allCookies << "http://qt.nokia.com/web/content" << result; + + result.prepend(cookie); // longer path, it must match first + QTest::newRow("two-matches-1") << allCookies << "http://nokia.com/web/wiki" << result; + QTest::newRow("two-matches-2") << allCookies << "http://qt.nokia.com/web/wiki" << result; + + // invert the order; + allCookies.clear(); + allCookies << result.at(1) << result.at(0); + QTest::newRow("two-matches-3") << allCookies << "http://nokia.com/web/wiki" << result; + QTest::newRow("two-matches-4") << allCookies << "http://qt.nokia.com/web/wiki" << result; + + // expired cookie + allCookies.clear(); + cookie.setExpirationDate(QDateTime::fromString("09-Nov-1999", "dd-MMM-yyyy")); + allCookies += cookie; + result.clear(); + QTest::newRow("exp-match-1") << allCookies << "http://nokia.com/web" << result; + QTest::newRow("exp-match-2") << allCookies << "http://nokia.com/web/" << result; + QTest::newRow("exp-match-3") << allCookies << "http://nokia.com/web/content" << result; + QTest::newRow("exp-match-4") << allCookies << "http://qt.nokia.com/web" << result; + QTest::newRow("exp-match-4") << allCookies << "http://qt.nokia.com/web/" << result; + QTest::newRow("exp-match-6") << allCookies << "http://qt.nokia.com/web/content" << result; + + // path matching + allCookies.clear(); + QNetworkCookie anotherCookie; + anotherCookie.setName("a"); + anotherCookie.setPath("/web"); + anotherCookie.setDomain(".nokia.com"); + allCookies += anotherCookie; + result.clear(); + QTest::newRow("path-unmatch-1") << allCookies << "http://nokia.com/" << result; + QTest::newRow("path-unmatch-2") << allCookies << "http://nokia.com/something/else" << result; + result += anotherCookie; + QTest::newRow("path-match-1") << allCookies << "http://nokia.com/web" << result; + QTest::newRow("path-match-2") << allCookies << "http://nokia.com/web/" << result; + QTest::newRow("path-match-3") << allCookies << "http://nokia.com/web/content" << result; + + // secure cookies + allCookies.clear(); + result.clear(); + QNetworkCookie secureCookie; + secureCookie.setName("a"); + secureCookie.setPath("/web"); + secureCookie.setDomain(".nokia.com"); + secureCookie.setSecure(true); + allCookies += secureCookie; + QTest::newRow("no-match-secure-1") << allCookies << "http://nokia.com/web" << result; + QTest::newRow("no-match-secure-2") << allCookies << "http://qt.nokia.com/web" << result; + result += secureCookie; + QTest::newRow("match-secure-1") << allCookies << "https://nokia.com/web" << result; + QTest::newRow("match-secure-2") << allCookies << "https://qt.nokia.com/web" << result; + +} + +void tst_QNetworkCookieJar::cookiesForUrl() +{ + QFETCH(QList<QNetworkCookie>, allCookies); + QFETCH(QString, url); + QFETCH(QList<QNetworkCookie>, expectedResult); + + MyCookieJar jar; + jar.setAllCookies(allCookies); + + QList<QNetworkCookie> result = jar.cookiesForUrl(url); + QCOMPARE(result, expectedResult); +} + +void tst_QNetworkCookieJar::effectiveTLDs_data() +{ + QTest::addColumn<QString>("domain"); + QTest::addColumn<bool>("isTLD"); + + QTest::newRow("yes1") << "com" << true; + QTest::newRow("yes2") << "de" << true; + QTest::newRow("yes3") << "ulm.museum" << true; + QTest::newRow("yes4") << "krodsherad.no" << true; + QTest::newRow("yes5") << "1.bg" << true; + QTest::newRow("yes6") << "com.cn" << true; + QTest::newRow("yes7") << "org.ws" << true; + QTest::newRow("yes8") << "co.uk" << true; + QTest::newRow("yes9") << "wallonie.museum" << true; + + QTest::newRow("no1") << "anything.com" << false; + QTest::newRow("no2") << "anything.de" << false; + QTest::newRow("no3") << "eselsberg.ulm.museum" << false; + QTest::newRow("no4") << "noe.krodsherad.no" << false; + QTest::newRow("no5") << "2.1.bg" << false; + QTest::newRow("no6") << "foo.com.cn" << false; + QTest::newRow("no7") << "something.org.ws" << false; + QTest::newRow("no8") << "teatime.co.uk" << false; + QTest::newRow("no9") << "bla" << false; + QTest::newRow("no10") << "bla.bla" << false; + + const ushort s1[] = {0x74, 0x72, 0x61, 0x6e, 0xf8, 0x79, 0x2e, 0x6e, 0x6f, 0x00}; // xn--trany-yua.no + const ushort s2[] = {0x5d9, 0x5e8, 0x5d5, 0x5e9, 0x5dc, 0x5d9, 0x5dd, 0x2e, 0x6d, 0x75, 0x73, 0x65, 0x75, 0x6d, 0x00}; // xn--9dbhblg6di.museum + const ushort s3[] = {0x7ec4, 0x7e54, 0x2e, 0x68, 0x6b, 0x00}; // xn--mk0axi.hk + const ushort s4[] = {0x7f51, 0x7edc, 0x2e, 0x63, 0x6e, 0x00}; // xn--io0a7i.cn + const ushort s5[] = {0x72, 0xe1, 0x68, 0x6b, 0x6b, 0x65, 0x72, 0xe1, 0x76, 0x6a, 0x75, 0x2e, 0x6e, 0x6f, 0x00}; // xn--rhkkervju-01af.no + const ushort s6[] = {0xb9a, 0xbbf, 0xb99, 0xbcd, 0xb95, 0xbaa, 0xbcd, 0xbaa, 0xbc2, 0xbb0, 0xbcd, 0x00}; // xn--clchc0ea0b2g2a9gcd + const ushort s7[] = {0x627, 0x644, 0x627, 0x631, 0x62f, 0x646, 0x00}; // xn--mgbayh7gpa + const ushort s8[] = {0x63, 0x6f, 0x72, 0x72, 0x65, 0x69, 0x6f, 0x73, 0x2d, 0x65, 0x2d, 0x74, 0x65, 0x6c, 0x65, + 0x63, 0x6f, 0x6d, 0x75, 0x6e, 0x69, 0x63, 0x61, 0xe7, 0xf5, 0x65, 0x73, 0x2e, 0x6d, 0x75, + 0x73, 0x65, 0x75, 0x6d, 0x00}; // xn--correios-e-telecomunicaes-ghc29a.museum + QTest::newRow("yes-specialchars1") << QString::fromUtf16(s1) << true; + QTest::newRow("yes-specialchars2") << QString::fromUtf16(s2) << true; + QTest::newRow("yes-specialchars3") << QString::fromUtf16(s3) << true; + QTest::newRow("yes-specialchars4") << QString::fromUtf16(s4) << true; + QTest::newRow("yes-specialchars5") << QString::fromUtf16(s5) << true; + QTest::newRow("yes-specialchars6") << QString::fromUtf16(s6) << true; + QTest::newRow("yes-specialchars7") << QString::fromUtf16(s7) << true; + QTest::newRow("yes-specialchars8") << QString::fromUtf16(s8) << true; + + QTest::newRow("no-specialchars1") << QString::fromUtf16(s1).prepend("something") << false; + QTest::newRow("no-specialchars2") << QString::fromUtf16(s2).prepend(QString::fromUtf16(s2)) << false; + QTest::newRow("no-specialchars2.5") << QString::fromUtf16(s2).prepend("whatever") << false; + QTest::newRow("no-specialchars3") << QString::fromUtf16(s3).prepend("foo") << false; + QTest::newRow("no-specialchars4") << QString::fromUtf16(s4).prepend("bar") << false; + QTest::newRow("no-specialchars5") << QString::fromUtf16(s5).prepend(QString::fromUtf16(s2)) << false; + QTest::newRow("no-specialchars6") << QString::fromUtf16(s6).prepend(QLatin1Char('.') + QString::fromUtf16(s6)) << false; + QTest::newRow("no-specialchars7") << QString::fromUtf16(s7).prepend("bla") << false; + QTest::newRow("no-specialchars8") << QString::fromUtf16(s8).append("foo") << false; + + QTest::newRow("exception1") << "pref.iwate.jp" << false; + QTest::newRow("exception2") << "omanpost.om" << false; + QTest::newRow("exception3") << "omantel.om" << false; + QTest::newRow("exception4") << "gobiernoelectronico.ar" << false; + QTest::newRow("exception5") << "pref.ishikawa.jp" << false; + + QTest::newRow("yes-wildcard1") << "*.jm" << true; + QTest::newRow("yes-wildcard1.5") << "anything.jm" << true; + QTest::newRow("yes-wildcard2") << "something.kh" << true; + QTest::newRow("yes-wildcard3") << "whatever.uk" << true; + QTest::newRow("yes-wildcard4") << "anything.shizuoka.jp" << true; + QTest::newRow("yes-wildcard5") << "foo.sch.uk" << true; +} + +void tst_QNetworkCookieJar::effectiveTLDs() +{ +#ifndef QT_BUILD_INTERNAL + QSKIP("Test requires private API", SkipAll); +#endif + QFETCH(QString, domain); + QFETCH(bool, isTLD); + QCOMPARE(qIsEffectiveTLD(domain), isTLD); +} + +QTEST_MAIN(tst_QNetworkCookieJar) +#include "tst_qnetworkcookiejar.moc" + diff --git a/tests/auto/network/access/qnetworkdiskcache/.gitignore b/tests/auto/network/access/qnetworkdiskcache/.gitignore new file mode 100644 index 0000000000..37a1ff2a42 --- /dev/null +++ b/tests/auto/network/access/qnetworkdiskcache/.gitignore @@ -0,0 +1 @@ +tst_qnetworkdiskcache diff --git a/tests/auto/network/access/qnetworkdiskcache/qnetworkdiskcache.pro b/tests/auto/network/access/qnetworkdiskcache/qnetworkdiskcache.pro new file mode 100644 index 0000000000..c05171dac7 --- /dev/null +++ b/tests/auto/network/access/qnetworkdiskcache/qnetworkdiskcache.pro @@ -0,0 +1,7 @@ +load(qttest_p4) +QT -= gui +QT += network +SOURCES += tst_qnetworkdiskcache.cpp + +symbian: TARGET.CAPABILITY = NetworkServices + diff --git a/tests/auto/network/access/qnetworkdiskcache/tst_qnetworkdiskcache.cpp b/tests/auto/network/access/qnetworkdiskcache/tst_qnetworkdiskcache.cpp new file mode 100644 index 0000000000..030eae60a0 --- /dev/null +++ b/tests/auto/network/access/qnetworkdiskcache/tst_qnetworkdiskcache.cpp @@ -0,0 +1,677 @@ +/**************************************************************************** +** +** 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 test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** 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. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + + +#include <QtTest/QtTest> +#include <QtNetwork/QtNetwork> +#include <qnetworkdiskcache.h> +#include "../../../../shared/util.h" + +#define EXAMPLE_URL "http://user:pass@www.example.com/#foo" +//cached objects are organized into these many subdirs +#define NUM_SUBDIRECTORIES 16 + +class tst_QNetworkDiskCache : public QObject +{ + Q_OBJECT + +public slots: + void initTestCase(); + void cleanupTestCase(); + void init(); + void cleanup(); + +private slots: + void qnetworkdiskcache_data(); + void qnetworkdiskcache(); + + void prepare(); + void cacheSize(); + void clear(); + void data_data(); + void data(); + void metaData(); + void remove(); + void setCacheDirectory_data(); + void setCacheDirectory(); + void updateMetaData(); + void fileMetaData(); + void expire(); + + void oldCacheVersionFile_data(); + void oldCacheVersionFile(); + + void sync(); + + void crashWhenParentingCache(); +}; + +// FIXME same as in tst_qnetworkreply.cpp .. could be unified +// Does not work for POST/PUT! +class MiniHttpServer: public QTcpServer +{ + Q_OBJECT +public: + QTcpSocket *client; // always the last one that was received + QByteArray dataToTransmit; + QByteArray receivedData; + bool doClose; + bool multiple; + int totalConnections; + + MiniHttpServer(const QByteArray &data) : client(0), dataToTransmit(data), doClose(true), multiple(false), totalConnections(0) + { + listen(); + connect(this, SIGNAL(newConnection()), this, SLOT(doAccept())); + } + +public slots: + void doAccept() + { + client = nextPendingConnection(); + client->setParent(this); + ++totalConnections; + connect(client, SIGNAL(readyRead()), this, SLOT(readyReadSlot())); + } + + void readyReadSlot() + { + receivedData += client->readAll(); + int doubleEndlPos = receivedData.indexOf("\r\n\r\n"); + + if (doubleEndlPos != -1) { + // multiple requests incoming. remove the bytes of the current one + if (multiple) + receivedData.remove(0, doubleEndlPos+4); + + client->write(dataToTransmit); + if (doClose) { + client->disconnectFromHost(); + disconnect(client, 0, this, 0); + client = 0; + } + } + } +}; + +// Subclass that exposes the protected functions. +class SubQNetworkDiskCache : public QNetworkDiskCache +{ +public: + ~SubQNetworkDiskCache() + { + if (!cacheDirectory().isEmpty()) + clear(); + } + + QNetworkCacheMetaData call_fileMetaData(QString const &fileName) + { return SubQNetworkDiskCache::fileMetaData(fileName); } + + qint64 call_expire() + { return SubQNetworkDiskCache::expire(); } + + void setupWithOne(const QUrl &url, const QNetworkCacheMetaData &metaData = QNetworkCacheMetaData()) + { + setCacheDirectory(QDir::tempPath() + "/diskCache"); + + QIODevice *d = 0; + if (metaData.isValid()) { + d = prepare(metaData); + } else { + QNetworkCacheMetaData m; + m.setUrl(url); + QNetworkCacheMetaData::RawHeader header("content-type", "text/html"); + QNetworkCacheMetaData::RawHeaderList list; + list.append(header); + m.setRawHeaders(list); + d = prepare(m); + } + d->write("Hello World!"); + insert(d); + } +}; + +// This will be called before the first test function is executed. +// It is only called once. +void tst_QNetworkDiskCache::initTestCase() +{ + SubQNetworkDiskCache cache; + cache.setCacheDirectory(QDir::tempPath() + "/diskCache"); + cache.clear(); + QString s = QDir::tempPath() + "/diskCache/"; + QDir dir; + dir.rmdir(s + "data7"); // the number is the internal cache version + dir.rmdir(s + "prepared"); + dir.rmdir(s); + dir.rmdir(s + "http"); // delete directory used by 4.7 and earlier (would make the tests fail) +} + +// This will be called after the last test function is executed. +// It is only called once. +void tst_QNetworkDiskCache::cleanupTestCase() +{ +} + +// This will be called before each test function is executed. +void tst_QNetworkDiskCache::init() +{ +} + +// This will be called after every test function. +void tst_QNetworkDiskCache::cleanup() +{ +} + +void tst_QNetworkDiskCache::qnetworkdiskcache_data() +{ +} + +void tst_QNetworkDiskCache::qnetworkdiskcache() +{ + QUrl url(EXAMPLE_URL); + SubQNetworkDiskCache cache; + QCOMPARE(cache.cacheDirectory(), QString()); + QCOMPARE(cache.cacheSize(), qint64(0)); + cache.clear(); + QCOMPARE(cache.metaData(QUrl()), QNetworkCacheMetaData()); + QCOMPARE(cache.remove(QUrl()), false); + QCOMPARE(cache.remove(url), false); + cache.insert((QIODevice*)0); + cache.setCacheDirectory(QString()); + cache.updateMetaData(QNetworkCacheMetaData()); + cache.prepare(QNetworkCacheMetaData()); + QCOMPARE(cache.call_fileMetaData(QString()), QNetworkCacheMetaData()); + + // leave one hanging around... + QNetworkDiskCache badCache; + QNetworkCacheMetaData metaData; + metaData.setUrl(url); + badCache.prepare(metaData); + badCache.setCacheDirectory(QDir::tempPath() + "/diskCache"); + badCache.prepare(metaData); +} + +void tst_QNetworkDiskCache::prepare() +{ + SubQNetworkDiskCache cache; + cache.setCacheDirectory(QDir::tempPath() + "/diskCache"); + + QUrl url(EXAMPLE_URL); + QNetworkCacheMetaData metaData; + metaData.setUrl(url); + + cache.prepare(metaData); + cache.remove(url); +} + +// public qint64 cacheSize() const +void tst_QNetworkDiskCache::cacheSize() +{ + SubQNetworkDiskCache cache; + cache.setCacheDirectory(QDir::tempPath() + "/diskCache"); + QCOMPARE(cache.cacheSize(), qint64(0)); + + QUrl url(EXAMPLE_URL); + QNetworkCacheMetaData metaData; + metaData.setUrl(url); + QIODevice *d = cache.prepare(metaData); + cache.insert(d); + QVERIFY(cache.cacheSize() > qint64(0)); + + cache.clear(); + QCOMPARE(cache.cacheSize(), qint64(0)); +} + +static QStringList countFiles(const QString dir) +{ + QStringList list; + QDir::Filters filter(QDir::AllEntries | QDir::NoDotAndDotDot); + QDirIterator it(dir, filter, QDirIterator::Subdirectories); + while (it.hasNext()) + list.append(it.next()); + return list; +} + +// public void clear() +void tst_QNetworkDiskCache::clear() +{ + SubQNetworkDiskCache cache; + QUrl url(EXAMPLE_URL); + cache.setupWithOne(url); + QVERIFY(cache.cacheSize() > qint64(0)); + + QString cacheDirectory = cache.cacheDirectory(); + QCOMPARE(countFiles(cacheDirectory).count(), NUM_SUBDIRECTORIES + 3); + cache.clear(); + QCOMPARE(countFiles(cacheDirectory).count(), NUM_SUBDIRECTORIES + 2); + + // don't delete files that it didn't create + QTemporaryFile file(cacheDirectory + "/XXXXXX"); + if (file.open()) { + QCOMPARE(countFiles(cacheDirectory).count(), NUM_SUBDIRECTORIES + 3); + cache.clear(); + QCOMPARE(countFiles(cacheDirectory).count(), NUM_SUBDIRECTORIES + 3); + } +} + +Q_DECLARE_METATYPE(QNetworkCacheMetaData) +void tst_QNetworkDiskCache::data_data() +{ + QTest::addColumn<QNetworkCacheMetaData>("data"); + + QTest::newRow("null") << QNetworkCacheMetaData(); + + QUrl url(EXAMPLE_URL); + QNetworkCacheMetaData metaData; + metaData.setUrl(url); + QNetworkCacheMetaData::RawHeaderList headers; + headers.append(QNetworkCacheMetaData::RawHeader("type", "bin")); + metaData.setRawHeaders(headers); + QTest::newRow("null") << metaData; +} + +// public QIODevice* data(QUrl const& url) +void tst_QNetworkDiskCache::data() +{ + QFETCH(QNetworkCacheMetaData, data); + SubQNetworkDiskCache cache; + QUrl url(EXAMPLE_URL); + cache.setupWithOne(url, data); + + for (int i = 0; i < 3; ++i) { + QIODevice *d = cache.data(url); + QVERIFY(d); + QCOMPARE(d->readAll(), QByteArray("Hello World!")); + delete d; + } +} + +// public QNetworkCacheMetaData metaData(QUrl const& url) +void tst_QNetworkDiskCache::metaData() +{ + SubQNetworkDiskCache cache; + + QUrl url(EXAMPLE_URL); + QNetworkCacheMetaData metaData; + metaData.setUrl(url); + QNetworkCacheMetaData::RawHeaderList headers; + headers.append(QNetworkCacheMetaData::RawHeader("type", "bin")); + metaData.setRawHeaders(headers); + metaData.setLastModified(QDateTime::currentDateTime()); + metaData.setExpirationDate(QDateTime::currentDateTime()); + metaData.setSaveToDisk(true); + + cache.setupWithOne(url, metaData); + + for (int i = 0; i < 3; ++i) { + QNetworkCacheMetaData cacheMetaData = cache.metaData(url); + QVERIFY(cacheMetaData.isValid()); + QCOMPARE(metaData, cacheMetaData); + } +} + +// public bool remove(QUrl const& url) +void tst_QNetworkDiskCache::remove() +{ + SubQNetworkDiskCache cache; + QUrl url(EXAMPLE_URL); + cache.setupWithOne(url); + QString cacheDirectory = cache.cacheDirectory(); + QCOMPARE(countFiles(cacheDirectory).count(), NUM_SUBDIRECTORIES + 3); + cache.remove(url); + QCOMPARE(countFiles(cacheDirectory).count(), NUM_SUBDIRECTORIES + 2); +} + +void tst_QNetworkDiskCache::setCacheDirectory_data() +{ + QTest::addColumn<QString>("cacheDir"); + QTest::newRow("null") << QString(); + QDir dir("foo"); + QTest::newRow("foo") << dir.absolutePath() + QString("/"); +} + +// public void setCacheDirectory(QString const& cacheDir) +void tst_QNetworkDiskCache::setCacheDirectory() +{ + QFETCH(QString, cacheDir); + + SubQNetworkDiskCache cache; + cache.setCacheDirectory(cacheDir); + QCOMPARE(cache.cacheDirectory(), cacheDir); +} + +// public void updateMetaData(QNetworkCacheMetaData const& metaData) +void tst_QNetworkDiskCache::updateMetaData() +{ + QUrl url(EXAMPLE_URL); + SubQNetworkDiskCache cache; + cache.setupWithOne(url); + + QNetworkCacheMetaData metaData = cache.metaData(url); + metaData.setLastModified(QDateTime::currentDateTime()); + cache.updateMetaData(metaData); + QNetworkCacheMetaData newMetaData = cache.metaData(url); + QCOMPARE(newMetaData, metaData); +} + +// protected QNetworkCacheMetaData fileMetaData(QString const& fileName) +void tst_QNetworkDiskCache::fileMetaData() +{ + SubQNetworkDiskCache cache; + QUrl url(EXAMPLE_URL); + cache.setupWithOne(url); + + url.setPassword(QString()); + url.setFragment(QString()); + + QString cacheDirectory = cache.cacheDirectory(); + QStringList list = countFiles(cacheDirectory); + QCOMPARE(list.count(), NUM_SUBDIRECTORIES + 3); + foreach(QString fileName, list) { + QFileInfo info(fileName); + if (info.isFile()) { + QNetworkCacheMetaData metaData = cache.call_fileMetaData(fileName); + QCOMPARE(metaData.url(), url); + } + } + + QTemporaryFile file(cacheDirectory + "/qt_temp.XXXXXX"); + if (file.open()) { + QNetworkCacheMetaData metaData = cache.call_fileMetaData(file.fileName()); + QVERIFY(!metaData.isValid()); + } +} + +// protected qint64 expire() +void tst_QNetworkDiskCache::expire() +{ + SubQNetworkDiskCache cache; + cache.setCacheDirectory(QDir::tempPath() + "/diskCache"); + QCOMPARE(cache.call_expire(), (qint64)0); + QUrl url(EXAMPLE_URL); + cache.setupWithOne(url); + QVERIFY(cache.call_expire() > (qint64)0); + qint64 limit = (1024 * 1024 / 4) * 5; + cache.setMaximumCacheSize(limit); + + qint64 max = cache.maximumCacheSize(); + QCOMPARE(max, limit); + for (int i = 0; i < 10; ++i) { + if (i % 3 == 0) + QTest::qWait(2000); + QNetworkCacheMetaData m; + m.setUrl(QUrl("http://www.foo.com/" + QString::number(i))); + QIODevice *d = cache.prepare(m); + QString bigString; + bigString.fill(QLatin1Char('Z'), (1024 * 1024 / 4)); + d->write(bigString.toLatin1().data()); + cache.insert(d); + QVERIFY(cache.call_expire() < max); + } + + QString cacheDirectory = cache.cacheDirectory(); + QStringList list = countFiles(cacheDirectory); + QStringList cacheList; + foreach(QString fileName, list) { + QFileInfo info(fileName); + if (info.isFile()) { + QNetworkCacheMetaData metaData = cache.call_fileMetaData(fileName); + cacheList.append(metaData.url().toString()); + } + } + qSort(cacheList); + for (int i = 0; i < cacheList.count(); ++i) { + QString fileName = cacheList[i]; + QCOMPARE(fileName, QString("http://www.foo.com/%1").arg(i + 6)); + } +} + +void tst_QNetworkDiskCache::oldCacheVersionFile_data() +{ + QTest::addColumn<int>("pass"); + QTest::newRow("0") << 0; + QTest::newRow("1") << 1; +} + +void tst_QNetworkDiskCache::oldCacheVersionFile() +{ + QFETCH(int, pass); + SubQNetworkDiskCache cache; + QUrl url(EXAMPLE_URL); + cache.setupWithOne(url); + + if (pass == 0) { + QString name; + { + QTemporaryFile file(cache.cacheDirectory() + "/XXXXXX.d"); + file.setAutoRemove(false); + QVERIFY(file.open()); + QDataStream out(&file); + out << qint32(0xe8); + out << qint32(2); + name = file.fileName(); + file.close(); + } + + QVERIFY(QFile::exists(name)); + QNetworkCacheMetaData metaData = cache.call_fileMetaData(name); + QVERIFY(!metaData.isValid()); + QVERIFY(!QFile::exists(name)); + } else { + QStringList files = countFiles(cache.cacheDirectory()); + QCOMPARE(files.count(), NUM_SUBDIRECTORIES + 3); + // find the file + QString cacheFile; + foreach (QString file, files) { + QFileInfo info(file); + if (info.isFile()) + cacheFile = file; + } + QVERIFY(QFile::exists(cacheFile)); + + QFile file(cacheFile); + QVERIFY(file.open(QFile::ReadWrite)); + QDataStream out(&file); + out << qint32(0xe8); + out << qint32(2); + file.close(); + + QIODevice *device = cache.data(url); + QVERIFY(!device); + QVERIFY(!QFile::exists(cacheFile)); + } +} + +class Runner : public QThread +{ + +public: + Runner() + : QThread() + , other(0) + {} + + void run() + { + QByteArray longString = "Hello World, this is some long string, well not really that long"; + for (int j = 0; j < 10; ++j) + longString += longString; + QByteArray longString2 = "Help, I am stuck in an autotest!"; + QUrl url(EXAMPLE_URL); + + QNetworkCacheMetaData metaData; + metaData.setUrl(url); + QNetworkCacheMetaData::RawHeaderList headers; + headers.append(QNetworkCacheMetaData::RawHeader("type", "bin")); + metaData.setRawHeaders(headers); + metaData.setLastModified(dt); + metaData.setSaveToDisk(true); + + QNetworkCacheMetaData metaData2 = metaData; + metaData2.setExpirationDate(dt); + + QNetworkDiskCache cache; + cache.setCacheDirectory(QDir::tempPath() + "/diskCache"); + + int read = 0; + + int i = 0; + for (; i < 5000; ++i) { + if (other && other->isFinished()) + break; + + if (write) { + QNetworkCacheMetaData m; + if (qrand() % 2 == 0) + m = metaData; + else + m = metaData2; + + if (qrand() % 20 == 1) { + //qDebug() << "write update"; + cache.updateMetaData(m); + continue; + } + + QIODevice *device = cache.prepare(m); + if (qrand() % 20 == 1) { + //qDebug() << "write remove"; + cache.remove(url); + continue; + } + QVERIFY(device); + if (qrand() % 2 == 0) + device->write(longString); + else + device->write(longString2); + //qDebug() << "write write" << device->size(); + cache.insert(device); + continue; + } + + QNetworkCacheMetaData gotMetaData = cache.metaData(url); + if (gotMetaData.isValid()) { + QVERIFY(gotMetaData == metaData || gotMetaData == metaData2); + QIODevice *d = cache.data(url); + if (d) { + QByteArray x = d->readAll(); + if (x != longString && x != longString2) { + qDebug() << x.length() << QString(x); + gotMetaData = cache.metaData(url); + qDebug() << (gotMetaData.url().toString()) + << gotMetaData.lastModified() + << gotMetaData.expirationDate() + << gotMetaData.saveToDisk(); + } + if (gotMetaData.isValid()) + QVERIFY(x == longString || x == longString2); + read++; + delete d; + } + } + if (qrand() % 5 == 1) + cache.remove(url); + if (qrand() % 5 == 1) + cache.clear(); + sleep(0); + } + //qDebug() << "read!" << read << i; + } + + QDateTime dt; + bool write; + Runner *other; +}; + +void tst_QNetworkDiskCache::crashWhenParentingCache() +{ + // the trick here is to not send the complete response + // but some data. So we get a readyRead() and it gets tried + // to be saved to the cache + QByteArray data("HTTP/1.0 200 OK\r\nCache-Control: max-age=300\r\nAge: 1\r\nContent-Length: 5\r\n\r\n123"); + MiniHttpServer server(data); + + QNetworkAccessManager *manager = new QNetworkAccessManager(); + QNetworkDiskCache *diskCache = new QNetworkDiskCache(manager); // parent to qnam! + // we expect the temp dir to be cleaned at some point anyway + diskCache->setCacheDirectory(QString("%1/cacheDir_%2").arg(QDir::tempPath()).arg(QCoreApplication::applicationPid())); + manager->setCache(diskCache); + + QUrl url("http://127.0.0.1:" + QString::number(server.serverPort())); + QNetworkRequest request(url); + // request.setAttribute(QNetworkRequest::CacheLoadControlAttribute, QNetworkRequest::AlwaysNetwork); + QNetworkReply *reply = manager->get(request); // new reply is parented to qnam + + // wait for readyRead of reply! + connect(reply, SIGNAL(readyRead()), &QTestEventLoop::instance(), SLOT(exitLoop())); + QTestEventLoop::instance().enterLoop(5); + QVERIFY(!QTestEventLoop::instance().timeout()); + + delete manager; // crashed before.. +} + +void tst_QNetworkDiskCache::sync() +{ + // This tests would be a nice to have, but is currently not supported. + return; + + QTime midnight(0, 0, 0); + qsrand(midnight.secsTo(QTime::currentTime())); + Runner reader; + reader.dt = QDateTime::currentDateTime(); + reader.write = false; + + Runner writer; + writer.dt = reader.dt; + writer.write = true; + + writer.other = &reader; + reader.other = &writer; + + writer.start(); + reader.start(); + writer.wait(); + reader.wait(); +} + +QTEST_MAIN(tst_QNetworkDiskCache) +#include "tst_qnetworkdiskcache.moc" + diff --git a/tests/auto/network/access/qnetworkreply/.gitattributes b/tests/auto/network/access/qnetworkreply/.gitattributes new file mode 100644 index 0000000000..80252cfd34 --- /dev/null +++ b/tests/auto/network/access/qnetworkreply/.gitattributes @@ -0,0 +1,3 @@ +rfc3252.txt -crlf +bigfile -crlf +resource -crlf diff --git a/tests/auto/network/access/qnetworkreply/.gitignore b/tests/auto/network/access/qnetworkreply/.gitignore new file mode 100644 index 0000000000..2797fcd809 --- /dev/null +++ b/tests/auto/network/access/qnetworkreply/.gitignore @@ -0,0 +1,3 @@ +tst_qnetworkreply +echo/echo +echo/echo.exe diff --git a/tests/auto/network/access/qnetworkreply/bigfile b/tests/auto/network/access/qnetworkreply/bigfile new file mode 100644 index 0000000000..cb114a2b0e --- /dev/null +++ b/tests/auto/network/access/qnetworkreply/bigfile @@ -0,0 +1,17980 @@ + + + + + + +Network Working Group H. Kennedy +Request for Comments: 3252 Mimezine +Category: Informational 1 April 2002 + + + Binary Lexical Octet Ad-hoc Transport + +Status of this Memo + + This memo provides information for the Internet community. It does + not specify an Internet standard of any kind. Distribution of this + memo is unlimited. + +Copyright Notice + + Copyright (C) The Internet Society (2002). All Rights Reserved. + +Abstract + + This document defines a reformulation of IP and two transport layer + protocols (TCP and UDP) as XML applications. + +1. Introduction + +1.1. Overview + + This document describes the Binary Lexical Octet Ad-hoc Transport + (BLOAT): a reformulation of a widely-deployed network-layer protocol + (IP [RFC791]), and two associated transport layer protocols (TCP + [RFC793] and UDP [RFC768]) as XML [XML] applications. It also + describes methods for transporting BLOAT over Ethernet and IEEE 802 + networks as well as encapsulating BLOAT in IP for gatewaying BLOAT + across the public Internet. + +1.2. Motivation + + The wild popularity of XML as a basis for application-level protocols + such as the Blocks Extensible Exchange Protocol [RFC3080], the Simple + Object Access Protocol [SOAP], and Jabber [JABBER] prompted + investigation into the possibility of extending the use of XML in the + protocol stack. Using XML at both the transport and network layer in + addition to the application layer would provide for an amazing amount + of power and flexibility while removing dependencies on proprietary + and hard-to-understand binary protocols. This protocol unification + would also allow applications to use a single XML parser for all + aspects of their operation, eliminating developer time spent figuring + out the intricacies of each new protocol, and moving the hard work of + + + + +Kennedy Informational [Page 1] + +RFC 3252 Binary Lexical Octet Ad-hoc Transport 1 April 2002 + + + parsing to the XML toolset. The use of XML also mitigates concerns + over "network vs. host" byte ordering which is at the root of many + network application bugs. + +1.3. Relation to Existing Protocols + + The reformulations specified in this RFC follow as closely as + possible the spirit of the RFCs on which they are based, and so MAY + contain elements or attributes that would not be needed in a pure + reworking (e.g. length attributes, which are implicit in XML.) + + The layering of network and transport protocols are maintained in + this RFC despite the optimizations that could be made if the line + were somewhat blurred (i.e. merging TCP and IP into a single, larger + element in the DTD) in order to foster future use of this protocol as + a basis for reformulating other protocols (such as ICMP.) + + Other than the encoding, the behavioral aspects of each of the + existing protocols remain unchanged. Routing, address spaces, TCP + congestion control, etc. behave as specified in the extant standards. + Adapting to new standards and experimental algorithm heuristics for + improving performance will become much easier once the move to BLOAT + has been completed. + +1.4. Requirement Levels + + The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", + "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this + document are to be interpreted as described in BCP 14, RFC 2119 + [RFC2119]. + +2. IPoXML + + This protocol MUST be implemented to be compliant with this RFC. + IPoXML is the root protocol REQUIRED for effective use of TCPoXML + (section 3.) and higher-level application protocols. + + The DTD for this document type can be found in section 7.1. + + The routing of IPoXML can be easily implemented on hosts with an XML + parser, as the regular structure lends itself handily to parsing and + validation of the document/datagram and then processing the + destination address, TTL, and checksum before sending it on to its + next-hop. + + The reformulation of IPv4 was chosen over IPv6 [RFC2460] due to the + wider deployment of IPv4 and the fact that implementing IPv6 as XML + would have exceeded the 1500 byte Ethernet MTU. + + + +Kennedy Informational [Page 2] + +RFC 3252 Binary Lexical Octet Ad-hoc Transport 1 April 2002 + + + All BLOAT implementations MUST use - and specify - the UTF-8 encoding + of RFC 2279 [RFC2279]. All BLOAT document/datagrams MUST be well- + formed and include the XMLDecl. + +2.1. IP Description + + A number of items have changed (for the better) from the original IP + specification. Bit-masks, where present have been converted into + human-readable values. IP addresses are listed in their dotted- + decimal notation [RFC1123]. Length and checksum values are present + as decimal integers. + + To calculate the length and checksum fields of the IP element, a + canonicalized form of the element MUST be used. The canonical form + SHALL have no whitespace (including newline characters) between + elements and only one space character between attributes. There + SHALL NOT be a space following the last attribute in an element. + + An iterative method SHOULD be used to calculate checksums, as the + length field will vary based on the size of the checksum. + + The payload element bears special attention. Due to the character + set restrictions of XML, the payload of IP datagrams (which MAY + contain arbitrary data) MUST be encoded for transport. This RFC + REQUIRES the contents of the payload to be encoded in the base-64 + encoding of RFC 2045 [RFC2045], but removes the requirement that the + encoded output MUST be wrapped on 76-character lines. + + + + + + + + + + + + + + + + + + + + + + + + +Kennedy Informational [Page 3] + +RFC 3252 Binary Lexical Octet Ad-hoc Transport 1 April 2002 + + +2.2. Example Datagram + + The following is an example IPoXML datagram with an empty payload: + + <?xml version="1.0" encoding="UTF-8"?> + <!DOCTYPE ip PUBLIC "-//IETF//DTD BLOAT 1.0 IP//EN" "bloat.dtd"> + <ip> + <header length="474"> + <version value="4"/> + <tos precedence="Routine" delay="Normal" throughput="Normal" + relibility="Normal" reserved="0"/> + <total.length value="461"/> + <id value="1"/> + <flags reserved="0" df="dont" mf="last"/> + <offset value="0"/> + <ttl value="255"/> + <protocol value="6"/> + <checksum value="8707"/> + <source address="10.0.0.22"/> + <destination address="10.0.0.1"/> + <options> + <end copied="0" class="0" number="0"/> + </options> + <padding pad="0"/> + </header> + <payload> + </payload> + </ip> + +3. TCPoXML + + This protocol MUST be implemented to be compliant with this RFC. The + DTD for this document type can be found in section 7.2. + +3.1. TCP Description + + A number of items have changed from the original TCP specification. + Bit-masks, where present have been converted into human-readable + values. Length and checksum and port values are present as decimal + integers. + + To calculate the length and checksum fields of the TCP element, a + canonicalized form of the element MUST be used as in section 2.1. + + An iterative method SHOULD be used to calculate checksums as in + section 2.1. + + The payload element MUST be encoded as in section 2.1. + + + +Kennedy Informational [Page 4] + +RFC 3252 Binary Lexical Octet Ad-hoc Transport 1 April 2002 + + + The TCP offset element was expanded to a maximum of 255 from 16 to + allow for the increased size of the header in XML. + + TCPoXML datagrams encapsulated by IPoXML MAY omit the <?xml?> header + as well as the <!DOCTYPE> declaration. + +3.2. Example Datagram + + The following is an example TCPoXML datagram with an empty payload: + + <?xml version="1.0" encoding="UTF-8"?> + <!DOCTYPE tcp PUBLIC "-//IETF//DTD BLOAT 1.0 TCP//EN" "bloat.dtd"> + <tcp> + <tcp.header> + <src port="31415"/> + <dest port="42424"/> + <sequence number="322622954"/> + <acknowledgement number="689715995"/> + <offset number=""/> + <reserved value="0"/> + <control syn="1" ack="1"/> + <window size="1"/> + <urgent pointer="0"/> + <checksum value="2988"/> + <tcp.options> + <tcp.end kind="0"/> + </tcp.options> + <padding pad="0"/> + </tcp.header> + <payload> + </payload> + </tcp> + +4. UDPoXML + + This protocol MUST be implemented to be compliant with this RFC. The + DTD for this document type can be found in section 7.3. + +4.1. UDP Description + + A number of items have changed from the original UDP specification. + Bit-masks, where present have been converted into human-readable + values. Length and checksum and port values are present as decimal + integers. + + + + + + + +Kennedy Informational [Page 5] + +RFC 3252 Binary Lexical Octet Ad-hoc Transport 1 April 2002 + + + To calculate the length and checksum fields of the UDP element, a + canonicalized form of the element MUST be used as in section 2.1. An + iterative method SHOULD be used to calculate checksums as in section + 2.1. + + The payload element MUST be encoded as in section 2.1. + + UDPoXML datagrams encapsulated by IPoXML MAY omit the <?xml?> header + as well as the <!DOCTYPE> declaration. + +4.2. Example Datagram + + The following is an example UDPoXML datagram with an empty payload: + + <?xml version="1.0" encoding="UTF-8"?> + <!DOCTYPE udp PUBLIC "-//IETF//DTD BLOAT 1.0 UDP//EN" "bloat.dtd"> + <udp> + <udp.header> + <src port="31415"/> + <dest port="42424"/> + <udp.length value="143"/> + <checksum value="2988"/> + </udp.header> + <payload> + </payload> + </udp> + +5. Network Transport + + This document provides for the transmission of BLOAT datagrams over + two common families of physical layer transport. Future RFCs will + address additional transports as routing vendors catch up to the + specification, and we begin to see BLOAT routed across the Internet + backbone. + +5.1. Ethernet + + BLOAT is encapsulated in Ethernet datagrams as in [RFC894] with the + exception that the type field of the Ethernet frame MUST contain the + value 0xBEEF. The first 5 octets of the Ethernet frame payload will + be 0x3c 3f 78 6d 6c ("<?xml".) + +5.2. IEEE 802 + + BLOAT is encapsulated in IEEE 802 Networks as in [RFC1042] except + that the protocol type code for IPoXML is 0xBEEF. + + + + + +Kennedy Informational [Page 6] + +RFC 3252 Binary Lexical Octet Ad-hoc Transport 1 April 2002 + + +6. Gatewaying over IP + + In order to facilitate the gradual introduction of BLOAT into the + public Internet, BLOAT MAY be encapsulated in IP as in [RFC2003] to + gateway between networks that run BLOAT natively on their LANs. + +7. DTDs + + The Transport DTDs (7.2. and 7.3.) build on the definitions in the + Network DTD (7.1.) + + The DTDs are referenced by their PubidLiteral and SystemLiteral (from + [XML]) although it is understood that most IPoXML implementations + will not need to pull down the DTD, as it will normally be embedded + in the implementation, and presents something of a catch-22 if you + need to load part of your network protocol over the network. + +7.1. IPoXML DTD + + <!-- + DTD for IP over XML. + Refer to this DTD as: + + <!DOCTYPE ip PUBLIC "-//IETF//DTD BLOAT 1.0 IP//EN" "bloat.dtd"> + --> + <!-- + DTD data types: + + Digits [0..9]+ + + Precedence "NetworkControl | InternetworkControl | + CRITIC | FlashOverride | Flash | Immediate | + Priority | Routine" + + IP4Addr "dotted-decimal" notation of [RFC1123] + + Class [0..3] + + Sec "Unclassified | Confidential | EFTO | MMMM | PROG | + Restricted | Secret | Top Secret | Reserved" + + Compartments [0..65535] + + Handling [0..65535] + + TCC [0..16777216] + + --> + + + +Kennedy Informational [Page 7] + +RFC 3252 Binary Lexical Octet Ad-hoc Transport 1 April 2002 + + + <!ENTITY % Digits "CDATA"> + <!ENTITY % Precedence "CDATA"> + <!ENTITY % IP4Addr "CDATA"> + <!ENTITY % Class "CDATA"> + <!ENTITY % Sec "CDATA"> + <!ENTITY % Compartments "CDATA"> + <!ENTITY % Handling "CDATA"> + <!ENTITY % TCC "CDATA"> + + <!ELEMENT ip (header, payload)> + + <!ELEMENT header (version, tos, total.length, id, flags, offset, ttl, + protocol, checksum, source, destination, options, + padding)> + <!-- length of header in 32-bit words --> + <!ATTLIST header + length %Digits; #REQUIRED> + + <!ELEMENT version EMPTY> + <!-- ip version. SHOULD be "4" --> + <!ATTLIST version + value %Digits; #REQUIRED> + + <!ELEMENT tos EMPTY> + <!ATTLIST tos + precedence %Precedence; #REQUIRED + delay (normal | low) #REQUIRED + throughput (normal | high) #REQUIRED + relibility (normal | high) #REQUIRED + reserved CDATA #FIXED "0"> + + <!ELEMENT total.length EMPTY> + <!-- + total length of datagram (header and payload) in octets, MUST be + less than 65,535 (and SHOULD be less than 1024 for IPoXML on local + ethernets). + --> + <!ATTLIST total.length + value %Digits; #REQUIRED> + + <!ELEMENT id EMPTY> + <!-- 0 <= id <= 65,535 --> + <!ATTLIST id + value %Digits; #REQUIRED> + + <!ELEMENT flags EMPTY> + <!-- df = don't fragment, mf = more fragments --> + <!ATTLIST flags + + + +Kennedy Informational [Page 8] + +RFC 3252 Binary Lexical Octet Ad-hoc Transport 1 April 2002 + + + reserved CDATA #FIXED "0" + df (may|dont) #REQUIRED + mf (last|more) #REQUIRED> + + <!ELEMENT offset EMPTY> + <!-- 0 <= offset <= 8192 measured in 8 octet (64-bit) chunks --> + <!ATTLIST offset + value %Digits; #REQUIRED> + + <!ELEMENT ttl EMPTY> + <!-- 0 <= ttl <= 255 --> + <!ATTLIST ttl + value %Digits; #REQUIRED> + + <!ELEMENT protocol EMPTY> + <!-- 0 <= protocol <= 255 (per IANA) --> + <!ATTLIST protocol + value %Digits; #REQUIRED> + + <!ELEMENT checksum EMPTY> + <!-- 0 <= checksum <= 65535 (over header only) --> + <!ATTLIST checksum + value %Digits; #REQUIRED> + + <!ELEMENT source EMPTY> + <!ATTLIST source + address %IP4Addr; #REQUIRED> + + <!ELEMENT destination EMPTY> + <!ATTLIST destination + address %IP4Addr; #REQUIRED> + + <!ELEMENT options ( end | noop | security | loose | strict | record + | stream | timestamp )*> + + <!ELEMENT end EMPTY> + <!ATTLIST end + copied (0|1) #REQUIRED + class CDATA #FIXED "0" + number CDATA #FIXED "0"> + + <!ELEMENT noop EMPTY> + <!ATTLIST noop + copied (0|1) #REQUIRED + class CDATA #FIXED "0" + number CDATA #FIXED "1"> + + <!ELEMENT security EMPTY> + + + +Kennedy Informational [Page 9] + +RFC 3252 Binary Lexical Octet Ad-hoc Transport 1 April 2002 + + + <!ATTLIST security + copied CDATA #FIXED "1" + class CDATA #FIXED "0" + number CDATA #FIXED "2" + length CDATA #FIXED "11" + security %Sec; #REQUIRED + compartments %Compartments; #REQUIRED + handling %Handling; #REQUIRED + tcc %TCC; #REQUIRED> + <!ELEMENT loose (hop)+> + <!ATTLIST loose + copied CDATA #FIXED "1" + class CDATA #FIXED "0" + number CDATA #FIXED "3" + length %Digits; #REQUIRED + pointer %Digits; #REQUIRED> + + <!ELEMENT hop EMPTY> + <!ATTLIST hop + address %IP4Addr; #REQUIRED> + + <!ELEMENT strict (hop)+> + <!ATTLIST strict + copied CDATA #FIXED "1" + class CDATA #FIXED "0" + number CDATA #FIXED "9" + length %Digits; #REQUIRED + pointer %Digits; #REQUIRED> + + <!ELEMENT record (hop)+> + <!ATTLIST record + copied CDATA #FIXED "0" + class CDATA #FIXED "0" + number CDATA #FIXED "7" + length %Digits; #REQUIRED + pointer %Digits; #REQUIRED> + + <!ELEMENT stream EMPTY> + <!-- 0 <= id <= 65,535 --> + <!ATTLIST stream + copied CDATA #FIXED "1" + class CDATA #FIXED "0" + number CDATA #FIXED "8" + length CDATA #FIXED "4" + id %Digits; #REQUIRED> + + <!ELEMENT timestamp (tstamp)+> + <!-- 0 <= oflw <=15 --> + + + +Kennedy Informational [Page 10] + +RFC 3252 Binary Lexical Octet Ad-hoc Transport 1 April 2002 + + + <!ATTLIST timestamp + copied CDATA #FIXED "0" + class CDATA #FIXED "2" + number CDATA #FIXED "4" + length %Digits; #REQUIRED + pointer %Digits; #REQUIRED + oflw %Digits; #REQUIRED + flag (0 | 1 | 3) #REQUIRED> + + <!ELEMENT tstamp EMPTY> + <!ATTLIST tstamp + time %Digits; #REQUIRED + address %IP4Addr; #IMPLIED> + <!-- + padding to bring header to 32-bit boundary. + pad MUST be "0"* + --> + <!ELEMENT padding EMPTY> + <!ATTLIST padding + pad CDATA #REQUIRED> + + <!-- payload MUST be encoded as base-64 [RFC2045], as modified + by section 2.1 of this RFC --> + <!ELEMENT payload (CDATA)> + +7.2. TCPoXML DTD + + <!-- + DTD for TCP over XML. + Refer to this DTD as: + + <!DOCTYPE tcp PUBLIC "-//IETF//DTD BLOAT 1.0 TCP//EN" "bloat.dtd"> + --> + + <!-- the pseudoheader is only included for checksum calculations --> + <!ELEMENT tcp (tcp.pseudoheader?, tcp.header, payload)> + + <!ELEMENT tcp.header (src, dest, sequence, acknowledgement, offset, + reserved, control, window, checksum, urgent, + tcp.options, padding)> + + <!ELEMENT src EMPTY> + <!-- 0 <= port <= 65,535 --> + <!ATTLIST src + port %Digits; #REQUIRED> + + <!ELEMENT dest EMPTY> + <!-- 0 <= port <= 65,535 --> + + + +Kennedy Informational [Page 11] + +RFC 3252 Binary Lexical Octet Ad-hoc Transport 1 April 2002 + + + <!ATTLIST dest + port %Digits; #REQUIRED> + + <!ELEMENT sequence EMPTY> + <!-- 0 <= number <= 4294967295 --> + <!ATTLIST sequence + number %Digits; #REQUIRED> + + <!ELEMENT acknowledgement EMPTY> + <!-- 0 <= number <= 4294967295 --> + <!ATTLIST acknowledgement + number %Digits; #REQUIRED> + + <!ELEMENT offset EMPTY> + <!-- 0 <= number <= 255 --> + <!ATTLIST offset + number %Digits; #REQUIRED> + + <!ELEMENT reserved EMPTY> + <!ATTLIST reserved + value CDATA #FIXED "0"> + + <!ELEMENT control EMPTY> + <!ATTLIST control + urg (0|1) #IMPLIED + ack (0|1) #IMPLIED + psh (0|1) #IMPLIED + rst (0|1) #IMPLIED + syn (0|1) #IMPLIED + fin (0|1) #IMPLIED> + + <!ELEMENT window EMPTY> + <!-- 0 <= size <= 65,535 --> + <!ATTLIST window + size %Digits; #REQUIRED> + + <!-- + checksum as in ip, but with + the following pseudo-header added into the tcp element: + --> + <!ELEMENT tcp.pseudoheader (source, destination, protocol, + tcp.length)> + + <!-- + tcp header + data length in octets. does not include the size of + + the pseudoheader. + --> + + + +Kennedy Informational [Page 12] + +RFC 3252 Binary Lexical Octet Ad-hoc Transport 1 April 2002 + + + <!ELEMENT tcp.length EMPTY> + <!ATTLIST tcp.length + value %Digits; #REQUIRED> + + <!ELEMENT urgent EMPTY> + <!-- 0 <= pointer <= 65,535 --> + <!ATTLIST urgent + pointer %Digits; #REQUIRED> + + <!ELEMENT tcp.options (tcp.end | tcp.noop | tcp.mss)+> + + <!ELEMENT tcp.end EMPTY> + <!ATTLIST tcp.end + kind CDATA #FIXED "0"> + + <!ELEMENT tcp.noop EMPTY> + <!ATTLIST tcp.noop + kind CDATA #FIXED "1"> + + <!ELEMENT tcp.mss EMPTY> + <!ATTLIST tcp.mss + kind CDATA #FIXED "2" + length CDATA #FIXED "4" + size %Digits; #REQUIRED> + +7.3. UDPoXML DTD + + <!-- + DTD for UDP over XML. + Refer to this DTD as: + + <!DOCTYPE udp PUBLIC "-//IETF//DTD BLOAT 1.0 UDP//EN" "bloat.dtd"> + --> + + <!ELEMENT udp (udp.pseudoheader?, udp.header, payload)> + + <!ELEMENT udp.header (src, dest, udp.length, checksum)> + + <!ELEMENT udp.pseudoheader (source, destination, protocol, + udp.length)> + + <!-- + udp header + data length in octets. does not include the size of + the pseudoheader. + --> + <!ELEMENT udp.length EMPTY> + <!ATTLIST udp.length + value %Digits; #REQUIRED> + + + +Kennedy Informational [Page 13] + +RFC 3252 Binary Lexical Octet Ad-hoc Transport 1 April 2002 + + +8. Security Considerations + + XML, as a subset of SGML, has the same security considerations as + specified in SGML Media Types [RFC1874]. Security considerations + that apply to IP, TCP and UDP also likely apply to BLOAT as it does + not attempt to correct for issues not related to message format. + +9. References + + [JABBER] Miller, J., "Jabber", draft-miller-jabber-00.txt, + February 2002. (Work in Progress) + + [RFC768] Postel, J., "User Datagram Protocol", STD 6, RFC 768, + August 1980. + + [RFC791] Postel, J., "Internet Protocol", STD 5, RFC 791, + September 1981. + + [RFC793] Postel, J., "Transmission Control Protocol", STD 7, RFC + 793, September 1981. + + [RFC894] Hornig, C., "Standard for the Transmission of IP + Datagrams over Ethernet Networks.", RFC 894, April 1984. + + [RFC1042] Postel, J. and J. Reynolds, "Standard for the + Transmission of IP Datagrams Over IEEE 802 Networks", STD + 43, RFC 1042, February 1988. + + [RFC1123] Braden, R., "Requirements for Internet Hosts - + Application and Support", RFC 1123, October 1989. + + [RFC1874] Levinson, E., "SGML Media Types", RFC 1874, December + 1995. + + [RFC2003] Perkins, C., "IP Encapsulation within IP", RFC 2003, + October 1996. + + [RFC2045] Freed, N. and N. Borenstein, "Multipurpose Internet Mail + Extensions (MIME) Part One: Format of Internet Message + Bodies", RFC 2045, November 1996. + + [RFC2119] Bradner, S., "Key words for use in RFCs to Indicate + Requirement Levels", BCP 14, RFC 2119, March 1997. + + [RFC2279] Yergeau, F., "UTF-8, a transformation format of ISO + 10646", RFC 2279, January 1998. + + + + + +Kennedy Informational [Page 14] + +RFC 3252 Binary Lexical Octet Ad-hoc Transport 1 April 2002 + + + [RFC2460] Deering, S. and R. Hinden, "Internet Protocol, Version 6 + (IPv6) Specification", RFC 2460, December 1998. + + [RFC3080] Rose, M., "The Blocks Extensible Exchange Protocol Core", + RFC 3080, March 2001. + + [SOAP] Box, D., Ehnebuske, D., Kakivaya, G., Layman, A., + Mendelsohn, N., Nielsen, H. F., Thatte, S. Winer, D., + "Simple Object Access Protocol (SOAP) 1.1" World Wide Web + Consortium Note, May 2000 http://www.w3.org/TR/SOAP/ + + [XML] Bray, T., Paoli, J., Sperberg-McQueen, C. M., "Extensible + Markup Language (XML)" World Wide Web Consortium + Recommendation REC- xml-19980210. + http://www.w3.org/TR/1998/REC-xml-19980210 + +10. Author's Address + + Hugh Kennedy + Mimezine + 1060 West Addison + Chicago, IL 60613 + USA + + EMail: kennedyh@engin.umich.edu + + + + + + + + + + + + + + + + + + + + + + + + + + +Kennedy Informational [Page 15] + +RFC 3252 Binary Lexical Octet Ad-hoc Transport 1 April 2002 + + +11. Full Copyright Statement + + Copyright (C) The Internet Society (2002). All Rights Reserved. + + This document and translations of it may be copied and furnished to + others, and derivative works that comment on or otherwise explain it + or assist in its implementation may be prepared, copied, published + and distributed, in whole or in part, without restriction of any + kind, provided that the above copyright notice and this paragraph are + included on all such copies and derivative works. However, this + document itself may not be modified in any way, such as by removing + the copyright notice or references to the Internet Society or other + Internet organizations, except as needed for the purpose of + developing Internet standards in which case the procedures for + copyrights defined in the Internet Standards process must be + followed, or as required to translate it into languages other than + English. + + The limited permissions granted above are perpetual and will not be + revoked by the Internet Society or its successors or assigns. + + This document and the information contained herein is provided on an + "AS IS" basis and THE INTERNET SOCIETY AND THE INTERNET ENGINEERING + TASK FORCE DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING + BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE INFORMATION + HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED WARRANTIES OF + MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. + +Acknowledgement + + Funding for the RFC Editor function is currently provided by the + Internet Society. + + + + + + + + + + + + + + + + + + + +Kennedy Informational [Page 16] + + + + + + + +Network Working Group H. Kennedy +Request for Comments: 3252 Mimezine +Category: Informational 1 April 2002 + + + Binary Lexical Octet Ad-hoc Transport + +Status of this Memo + + This memo provides information for the Internet community. It does + not specify an Internet standard of any kind. Distribution of this + memo is unlimited. + +Copyright Notice + + Copyright (C) The Internet Society (2002). All Rights Reserved. + +Abstract + + This document defines a reformulation of IP and two transport layer + protocols (TCP and UDP) as XML applications. + +1. Introduction + +1.1. Overview + + This document describes the Binary Lexical Octet Ad-hoc Transport + (BLOAT): a reformulation of a widely-deployed network-layer protocol + (IP [RFC791]), and two associated transport layer protocols (TCP + [RFC793] and UDP [RFC768]) as XML [XML] applications. It also + describes methods for transporting BLOAT over Ethernet and IEEE 802 + networks as well as encapsulating BLOAT in IP for gatewaying BLOAT + across the public Internet. + +1.2. Motivation + + The wild popularity of XML as a basis for application-level protocols + such as the Blocks Extensible Exchange Protocol [RFC3080], the Simple + Object Access Protocol [SOAP], and Jabber [JABBER] prompted + investigation into the possibility of extending the use of XML in the + protocol stack. Using XML at both the transport and network layer in + addition to the application layer would provide for an amazing amount + of power and flexibility while removing dependencies on proprietary + and hard-to-understand binary protocols. This protocol unification + would also allow applications to use a single XML parser for all + aspects of their operation, eliminating developer time spent figuring + out the intricacies of each new protocol, and moving the hard work of + + + + +Kennedy Informational [Page 1] + +RFC 3252 Binary Lexical Octet Ad-hoc Transport 1 April 2002 + + + parsing to the XML toolset. The use of XML also mitigates concerns + over "network vs. host" byte ordering which is at the root of many + network application bugs. + +1.3. Relation to Existing Protocols + + The reformulations specified in this RFC follow as closely as + possible the spirit of the RFCs on which they are based, and so MAY + contain elements or attributes that would not be needed in a pure + reworking (e.g. length attributes, which are implicit in XML.) + + The layering of network and transport protocols are maintained in + this RFC despite the optimizations that could be made if the line + were somewhat blurred (i.e. merging TCP and IP into a single, larger + element in the DTD) in order to foster future use of this protocol as + a basis for reformulating other protocols (such as ICMP.) + + Other than the encoding, the behavioral aspects of each of the + existing protocols remain unchanged. Routing, address spaces, TCP + congestion control, etc. behave as specified in the extant standards. + Adapting to new standards and experimental algorithm heuristics for + improving performance will become much easier once the move to BLOAT + has been completed. + +1.4. Requirement Levels + + The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", + "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this + document are to be interpreted as described in BCP 14, RFC 2119 + [RFC2119]. + +2. IPoXML + + This protocol MUST be implemented to be compliant with this RFC. + IPoXML is the root protocol REQUIRED for effective use of TCPoXML + (section 3.) and higher-level application protocols. + + The DTD for this document type can be found in section 7.1. + + The routing of IPoXML can be easily implemented on hosts with an XML + parser, as the regular structure lends itself handily to parsing and + validation of the document/datagram and then processing the + destination address, TTL, and checksum before sending it on to its + next-hop. + + The reformulation of IPv4 was chosen over IPv6 [RFC2460] due to the + wider deployment of IPv4 and the fact that implementing IPv6 as XML + would have exceeded the 1500 byte Ethernet MTU. + + + +Kennedy Informational [Page 2] + +RFC 3252 Binary Lexical Octet Ad-hoc Transport 1 April 2002 + + + All BLOAT implementations MUST use - and specify - the UTF-8 encoding + of RFC 2279 [RFC2279]. All BLOAT document/datagrams MUST be well- + formed and include the XMLDecl. + +2.1. IP Description + + A number of items have changed (for the better) from the original IP + specification. Bit-masks, where present have been converted into + human-readable values. IP addresses are listed in their dotted- + decimal notation [RFC1123]. Length and checksum values are present + as decimal integers. + + To calculate the length and checksum fields of the IP element, a + canonicalized form of the element MUST be used. The canonical form + SHALL have no whitespace (including newline characters) between + elements and only one space character between attributes. There + SHALL NOT be a space following the last attribute in an element. + + An iterative method SHOULD be used to calculate checksums, as the + length field will vary based on the size of the checksum. + + The payload element bears special attention. Due to the character + set restrictions of XML, the payload of IP datagrams (which MAY + contain arbitrary data) MUST be encoded for transport. This RFC + REQUIRES the contents of the payload to be encoded in the base-64 + encoding of RFC 2045 [RFC2045], but removes the requirement that the + encoded output MUST be wrapped on 76-character lines. + + + + + + + + + + + + + + + + + + + + + + + + +Kennedy Informational [Page 3] + +RFC 3252 Binary Lexical Octet Ad-hoc Transport 1 April 2002 + + +2.2. Example Datagram + + The following is an example IPoXML datagram with an empty payload: + + <?xml version="1.0" encoding="UTF-8"?> + <!DOCTYPE ip PUBLIC "-//IETF//DTD BLOAT 1.0 IP//EN" "bloat.dtd"> + <ip> + <header length="474"> + <version value="4"/> + <tos precedence="Routine" delay="Normal" throughput="Normal" + relibility="Normal" reserved="0"/> + <total.length value="461"/> + <id value="1"/> + <flags reserved="0" df="dont" mf="last"/> + <offset value="0"/> + <ttl value="255"/> + <protocol value="6"/> + <checksum value="8707"/> + <source address="10.0.0.22"/> + <destination address="10.0.0.1"/> + <options> + <end copied="0" class="0" number="0"/> + </options> + <padding pad="0"/> + </header> + <payload> + </payload> + </ip> + +3. TCPoXML + + This protocol MUST be implemented to be compliant with this RFC. The + DTD for this document type can be found in section 7.2. + +3.1. TCP Description + + A number of items have changed from the original TCP specification. + Bit-masks, where present have been converted into human-readable + values. Length and checksum and port values are present as decimal + integers. + + To calculate the length and checksum fields of the TCP element, a + canonicalized form of the element MUST be used as in section 2.1. + + An iterative method SHOULD be used to calculate checksums as in + section 2.1. + + The payload element MUST be encoded as in section 2.1. + + + +Kennedy Informational [Page 4] + +RFC 3252 Binary Lexical Octet Ad-hoc Transport 1 April 2002 + + + The TCP offset element was expanded to a maximum of 255 from 16 to + allow for the increased size of the header in XML. + + TCPoXML datagrams encapsulated by IPoXML MAY omit the <?xml?> header + as well as the <!DOCTYPE> declaration. + +3.2. Example Datagram + + The following is an example TCPoXML datagram with an empty payload: + + <?xml version="1.0" encoding="UTF-8"?> + <!DOCTYPE tcp PUBLIC "-//IETF//DTD BLOAT 1.0 TCP//EN" "bloat.dtd"> + <tcp> + <tcp.header> + <src port="31415"/> + <dest port="42424"/> + <sequence number="322622954"/> + <acknowledgement number="689715995"/> + <offset number=""/> + <reserved value="0"/> + <control syn="1" ack="1"/> + <window size="1"/> + <urgent pointer="0"/> + <checksum value="2988"/> + <tcp.options> + <tcp.end kind="0"/> + </tcp.options> + <padding pad="0"/> + </tcp.header> + <payload> + </payload> + </tcp> + +4. UDPoXML + + This protocol MUST be implemented to be compliant with this RFC. The + DTD for this document type can be found in section 7.3. + +4.1. UDP Description + + A number of items have changed from the original UDP specification. + Bit-masks, where present have been converted into human-readable + values. Length and checksum and port values are present as decimal + integers. + + + + + + + +Kennedy Informational [Page 5] + +RFC 3252 Binary Lexical Octet Ad-hoc Transport 1 April 2002 + + + To calculate the length and checksum fields of the UDP element, a + canonicalized form of the element MUST be used as in section 2.1. An + iterative method SHOULD be used to calculate checksums as in section + 2.1. + + The payload element MUST be encoded as in section 2.1. + + UDPoXML datagrams encapsulated by IPoXML MAY omit the <?xml?> header + as well as the <!DOCTYPE> declaration. + +4.2. Example Datagram + + The following is an example UDPoXML datagram with an empty payload: + + <?xml version="1.0" encoding="UTF-8"?> + <!DOCTYPE udp PUBLIC "-//IETF//DTD BLOAT 1.0 UDP//EN" "bloat.dtd"> + <udp> + <udp.header> + <src port="31415"/> + <dest port="42424"/> + <udp.length value="143"/> + <checksum value="2988"/> + </udp.header> + <payload> + </payload> + </udp> + +5. Network Transport + + This document provides for the transmission of BLOAT datagrams over + two common families of physical layer transport. Future RFCs will + address additional transports as routing vendors catch up to the + specification, and we begin to see BLOAT routed across the Internet + backbone. + +5.1. Ethernet + + BLOAT is encapsulated in Ethernet datagrams as in [RFC894] with the + exception that the type field of the Ethernet frame MUST contain the + value 0xBEEF. The first 5 octets of the Ethernet frame payload will + be 0x3c 3f 78 6d 6c ("<?xml".) + +5.2. IEEE 802 + + BLOAT is encapsulated in IEEE 802 Networks as in [RFC1042] except + that the protocol type code for IPoXML is 0xBEEF. + + + + + +Kennedy Informational [Page 6] + +RFC 3252 Binary Lexical Octet Ad-hoc Transport 1 April 2002 + + +6. Gatewaying over IP + + In order to facilitate the gradual introduction of BLOAT into the + public Internet, BLOAT MAY be encapsulated in IP as in [RFC2003] to + gateway between networks that run BLOAT natively on their LANs. + +7. DTDs + + The Transport DTDs (7.2. and 7.3.) build on the definitions in the + Network DTD (7.1.) + + The DTDs are referenced by their PubidLiteral and SystemLiteral (from + [XML]) although it is understood that most IPoXML implementations + will not need to pull down the DTD, as it will normally be embedded + in the implementation, and presents something of a catch-22 if you + need to load part of your network protocol over the network. + +7.1. IPoXML DTD + + <!-- + DTD for IP over XML. + Refer to this DTD as: + + <!DOCTYPE ip PUBLIC "-//IETF//DTD BLOAT 1.0 IP//EN" "bloat.dtd"> + --> + <!-- + DTD data types: + + Digits [0..9]+ + + Precedence "NetworkControl | InternetworkControl | + CRITIC | FlashOverride | Flash | Immediate | + Priority | Routine" + + IP4Addr "dotted-decimal" notation of [RFC1123] + + Class [0..3] + + Sec "Unclassified | Confidential | EFTO | MMMM | PROG | + Restricted | Secret | Top Secret | Reserved" + + Compartments [0..65535] + + Handling [0..65535] + + TCC [0..16777216] + + --> + + + +Kennedy Informational [Page 7] + +RFC 3252 Binary Lexical Octet Ad-hoc Transport 1 April 2002 + + + <!ENTITY % Digits "CDATA"> + <!ENTITY % Precedence "CDATA"> + <!ENTITY % IP4Addr "CDATA"> + <!ENTITY % Class "CDATA"> + <!ENTITY % Sec "CDATA"> + <!ENTITY % Compartments "CDATA"> + <!ENTITY % Handling "CDATA"> + <!ENTITY % TCC "CDATA"> + + <!ELEMENT ip (header, payload)> + + <!ELEMENT header (version, tos, total.length, id, flags, offset, ttl, + protocol, checksum, source, destination, options, + padding)> + <!-- length of header in 32-bit words --> + <!ATTLIST header + length %Digits; #REQUIRED> + + <!ELEMENT version EMPTY> + <!-- ip version. SHOULD be "4" --> + <!ATTLIST version + value %Digits; #REQUIRED> + + <!ELEMENT tos EMPTY> + <!ATTLIST tos + precedence %Precedence; #REQUIRED + delay (normal | low) #REQUIRED + throughput (normal | high) #REQUIRED + relibility (normal | high) #REQUIRED + reserved CDATA #FIXED "0"> + + <!ELEMENT total.length EMPTY> + <!-- + total length of datagram (header and payload) in octets, MUST be + less than 65,535 (and SHOULD be less than 1024 for IPoXML on local + ethernets). + --> + <!ATTLIST total.length + value %Digits; #REQUIRED> + + <!ELEMENT id EMPTY> + <!-- 0 <= id <= 65,535 --> + <!ATTLIST id + value %Digits; #REQUIRED> + + <!ELEMENT flags EMPTY> + <!-- df = don't fragment, mf = more fragments --> + <!ATTLIST flags + + + +Kennedy Informational [Page 8] + +RFC 3252 Binary Lexical Octet Ad-hoc Transport 1 April 2002 + + + reserved CDATA #FIXED "0" + df (may|dont) #REQUIRED + mf (last|more) #REQUIRED> + + <!ELEMENT offset EMPTY> + <!-- 0 <= offset <= 8192 measured in 8 octet (64-bit) chunks --> + <!ATTLIST offset + value %Digits; #REQUIRED> + + <!ELEMENT ttl EMPTY> + <!-- 0 <= ttl <= 255 --> + <!ATTLIST ttl + value %Digits; #REQUIRED> + + <!ELEMENT protocol EMPTY> + <!-- 0 <= protocol <= 255 (per IANA) --> + <!ATTLIST protocol + value %Digits; #REQUIRED> + + <!ELEMENT checksum EMPTY> + <!-- 0 <= checksum <= 65535 (over header only) --> + <!ATTLIST checksum + value %Digits; #REQUIRED> + + <!ELEMENT source EMPTY> + <!ATTLIST source + address %IP4Addr; #REQUIRED> + + <!ELEMENT destination EMPTY> + <!ATTLIST destination + address %IP4Addr; #REQUIRED> + + <!ELEMENT options ( end | noop | security | loose | strict | record + | stream | timestamp )*> + + <!ELEMENT end EMPTY> + <!ATTLIST end + copied (0|1) #REQUIRED + class CDATA #FIXED "0" + number CDATA #FIXED "0"> + + <!ELEMENT noop EMPTY> + <!ATTLIST noop + copied (0|1) #REQUIRED + class CDATA #FIXED "0" + number CDATA #FIXED "1"> + + <!ELEMENT security EMPTY> + + + +Kennedy Informational [Page 9] + +RFC 3252 Binary Lexical Octet Ad-hoc Transport 1 April 2002 + + + <!ATTLIST security + copied CDATA #FIXED "1" + class CDATA #FIXED "0" + number CDATA #FIXED "2" + length CDATA #FIXED "11" + security %Sec; #REQUIRED + compartments %Compartments; #REQUIRED + handling %Handling; #REQUIRED + tcc %TCC; #REQUIRED> + <!ELEMENT loose (hop)+> + <!ATTLIST loose + copied CDATA #FIXED "1" + class CDATA #FIXED "0" + number CDATA #FIXED "3" + length %Digits; #REQUIRED + pointer %Digits; #REQUIRED> + + <!ELEMENT hop EMPTY> + <!ATTLIST hop + address %IP4Addr; #REQUIRED> + + <!ELEMENT strict (hop)+> + <!ATTLIST strict + copied CDATA #FIXED "1" + class CDATA #FIXED "0" + number CDATA #FIXED "9" + length %Digits; #REQUIRED + pointer %Digits; #REQUIRED> + + <!ELEMENT record (hop)+> + <!ATTLIST record + copied CDATA #FIXED "0" + class CDATA #FIXED "0" + number CDATA #FIXED "7" + length %Digits; #REQUIRED + pointer %Digits; #REQUIRED> + + <!ELEMENT stream EMPTY> + <!-- 0 <= id <= 65,535 --> + <!ATTLIST stream + copied CDATA #FIXED "1" + class CDATA #FIXED "0" + number CDATA #FIXED "8" + length CDATA #FIXED "4" + id %Digits; #REQUIRED> + + <!ELEMENT timestamp (tstamp)+> + <!-- 0 <= oflw <=15 --> + + + +Kennedy Informational [Page 10] + +RFC 3252 Binary Lexical Octet Ad-hoc Transport 1 April 2002 + + + <!ATTLIST timestamp + copied CDATA #FIXED "0" + class CDATA #FIXED "2" + number CDATA #FIXED "4" + length %Digits; #REQUIRED + pointer %Digits; #REQUIRED + oflw %Digits; #REQUIRED + flag (0 | 1 | 3) #REQUIRED> + + <!ELEMENT tstamp EMPTY> + <!ATTLIST tstamp + time %Digits; #REQUIRED + address %IP4Addr; #IMPLIED> + <!-- + padding to bring header to 32-bit boundary. + pad MUST be "0"* + --> + <!ELEMENT padding EMPTY> + <!ATTLIST padding + pad CDATA #REQUIRED> + + <!-- payload MUST be encoded as base-64 [RFC2045], as modified + by section 2.1 of this RFC --> + <!ELEMENT payload (CDATA)> + +7.2. TCPoXML DTD + + <!-- + DTD for TCP over XML. + Refer to this DTD as: + + <!DOCTYPE tcp PUBLIC "-//IETF//DTD BLOAT 1.0 TCP//EN" "bloat.dtd"> + --> + + <!-- the pseudoheader is only included for checksum calculations --> + <!ELEMENT tcp (tcp.pseudoheader?, tcp.header, payload)> + + <!ELEMENT tcp.header (src, dest, sequence, acknowledgement, offset, + reserved, control, window, checksum, urgent, + tcp.options, padding)> + + <!ELEMENT src EMPTY> + <!-- 0 <= port <= 65,535 --> + <!ATTLIST src + port %Digits; #REQUIRED> + + <!ELEMENT dest EMPTY> + <!-- 0 <= port <= 65,535 --> + + + +Kennedy Informational [Page 11] + +RFC 3252 Binary Lexical Octet Ad-hoc Transport 1 April 2002 + + + <!ATTLIST dest + port %Digits; #REQUIRED> + + <!ELEMENT sequence EMPTY> + <!-- 0 <= number <= 4294967295 --> + <!ATTLIST sequence + number %Digits; #REQUIRED> + + <!ELEMENT acknowledgement EMPTY> + <!-- 0 <= number <= 4294967295 --> + <!ATTLIST acknowledgement + number %Digits; #REQUIRED> + + <!ELEMENT offset EMPTY> + <!-- 0 <= number <= 255 --> + <!ATTLIST offset + number %Digits; #REQUIRED> + + <!ELEMENT reserved EMPTY> + <!ATTLIST reserved + value CDATA #FIXED "0"> + + <!ELEMENT control EMPTY> + <!ATTLIST control + urg (0|1) #IMPLIED + ack (0|1) #IMPLIED + psh (0|1) #IMPLIED + rst (0|1) #IMPLIED + syn (0|1) #IMPLIED + fin (0|1) #IMPLIED> + + <!ELEMENT window EMPTY> + <!-- 0 <= size <= 65,535 --> + <!ATTLIST window + size %Digits; #REQUIRED> + + <!-- + checksum as in ip, but with + the following pseudo-header added into the tcp element: + --> + <!ELEMENT tcp.pseudoheader (source, destination, protocol, + tcp.length)> + + <!-- + tcp header + data length in octets. does not include the size of + + the pseudoheader. + --> + + + +Kennedy Informational [Page 12] + +RFC 3252 Binary Lexical Octet Ad-hoc Transport 1 April 2002 + + + <!ELEMENT tcp.length EMPTY> + <!ATTLIST tcp.length + value %Digits; #REQUIRED> + + <!ELEMENT urgent EMPTY> + <!-- 0 <= pointer <= 65,535 --> + <!ATTLIST urgent + pointer %Digits; #REQUIRED> + + <!ELEMENT tcp.options (tcp.end | tcp.noop | tcp.mss)+> + + <!ELEMENT tcp.end EMPTY> + <!ATTLIST tcp.end + kind CDATA #FIXED "0"> + + <!ELEMENT tcp.noop EMPTY> + <!ATTLIST tcp.noop + kind CDATA #FIXED "1"> + + <!ELEMENT tcp.mss EMPTY> + <!ATTLIST tcp.mss + kind CDATA #FIXED "2" + length CDATA #FIXED "4" + size %Digits; #REQUIRED> + +7.3. UDPoXML DTD + + <!-- + DTD for UDP over XML. + Refer to this DTD as: + + <!DOCTYPE udp PUBLIC "-//IETF//DTD BLOAT 1.0 UDP//EN" "bloat.dtd"> + --> + + <!ELEMENT udp (udp.pseudoheader?, udp.header, payload)> + + <!ELEMENT udp.header (src, dest, udp.length, checksum)> + + <!ELEMENT udp.pseudoheader (source, destination, protocol, + udp.length)> + + <!-- + udp header + data length in octets. does not include the size of + the pseudoheader. + --> + <!ELEMENT udp.length EMPTY> + <!ATTLIST udp.length + value %Digits; #REQUIRED> + + + +Kennedy Informational [Page 13] + +RFC 3252 Binary Lexical Octet Ad-hoc Transport 1 April 2002 + + +8. Security Considerations + + XML, as a subset of SGML, has the same security considerations as + specified in SGML Media Types [RFC1874]. Security considerations + that apply to IP, TCP and UDP also likely apply to BLOAT as it does + not attempt to correct for issues not related to message format. + +9. References + + [JABBER] Miller, J., "Jabber", draft-miller-jabber-00.txt, + February 2002. (Work in Progress) + + [RFC768] Postel, J., "User Datagram Protocol", STD 6, RFC 768, + August 1980. + + [RFC791] Postel, J., "Internet Protocol", STD 5, RFC 791, + September 1981. + + [RFC793] Postel, J., "Transmission Control Protocol", STD 7, RFC + 793, September 1981. + + [RFC894] Hornig, C., "Standard for the Transmission of IP + Datagrams over Ethernet Networks.", RFC 894, April 1984. + + [RFC1042] Postel, J. and J. Reynolds, "Standard for the + Transmission of IP Datagrams Over IEEE 802 Networks", STD + 43, RFC 1042, February 1988. + + [RFC1123] Braden, R., "Requirements for Internet Hosts - + Application and Support", RFC 1123, October 1989. + + [RFC1874] Levinson, E., "SGML Media Types", RFC 1874, December + 1995. + + [RFC2003] Perkins, C., "IP Encapsulation within IP", RFC 2003, + October 1996. + + [RFC2045] Freed, N. and N. Borenstein, "Multipurpose Internet Mail + Extensions (MIME) Part One: Format of Internet Message + Bodies", RFC 2045, November 1996. + + [RFC2119] Bradner, S., "Key words for use in RFCs to Indicate + Requirement Levels", BCP 14, RFC 2119, March 1997. + + [RFC2279] Yergeau, F., "UTF-8, a transformation format of ISO + 10646", RFC 2279, January 1998. + + + + + +Kennedy Informational [Page 14] + +RFC 3252 Binary Lexical Octet Ad-hoc Transport 1 April 2002 + + + [RFC2460] Deering, S. and R. Hinden, "Internet Protocol, Version 6 + (IPv6) Specification", RFC 2460, December 1998. + + [RFC3080] Rose, M., "The Blocks Extensible Exchange Protocol Core", + RFC 3080, March 2001. + + [SOAP] Box, D., Ehnebuske, D., Kakivaya, G., Layman, A., + Mendelsohn, N., Nielsen, H. F., Thatte, S. Winer, D., + "Simple Object Access Protocol (SOAP) 1.1" World Wide Web + Consortium Note, May 2000 http://www.w3.org/TR/SOAP/ + + [XML] Bray, T., Paoli, J., Sperberg-McQueen, C. M., "Extensible + Markup Language (XML)" World Wide Web Consortium + Recommendation REC- xml-19980210. + http://www.w3.org/TR/1998/REC-xml-19980210 + +10. Author's Address + + Hugh Kennedy + Mimezine + 1060 West Addison + Chicago, IL 60613 + USA + + EMail: kennedyh@engin.umich.edu + + + + + + + + + + + + + + + + + + + + + + + + + + +Kennedy Informational [Page 15] + +RFC 3252 Binary Lexical Octet Ad-hoc Transport 1 April 2002 + + +11. Full Copyright Statement + + Copyright (C) The Internet Society (2002). All Rights Reserved. + + This document and translations of it may be copied and furnished to + others, and derivative works that comment on or otherwise explain it + or assist in its implementation may be prepared, copied, published + and distributed, in whole or in part, without restriction of any + kind, provided that the above copyright notice and this paragraph are + included on all such copies and derivative works. However, this + document itself may not be modified in any way, such as by removing + the copyright notice or references to the Internet Society or other + Internet organizations, except as needed for the purpose of + developing Internet standards in which case the procedures for + copyrights defined in the Internet Standards process must be + followed, or as required to translate it into languages other than + English. + + The limited permissions granted above are perpetual and will not be + revoked by the Internet Society or its successors or assigns. + + This document and the information contained herein is provided on an + "AS IS" basis and THE INTERNET SOCIETY AND THE INTERNET ENGINEERING + TASK FORCE DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING + BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE INFORMATION + HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED WARRANTIES OF + MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. + +Acknowledgement + + Funding for the RFC Editor function is currently provided by the + Internet Society. + + + + + + + + + + + + + + + + + + + +Kennedy Informational [Page 16] + + + + + + + +Network Working Group H. Kennedy +Request for Comments: 3252 Mimezine +Category: Informational 1 April 2002 + + + Binary Lexical Octet Ad-hoc Transport + +Status of this Memo + + This memo provides information for the Internet community. It does + not specify an Internet standard of any kind. Distribution of this + memo is unlimited. + +Copyright Notice + + Copyright (C) The Internet Society (2002). All Rights Reserved. + +Abstract + + This document defines a reformulation of IP and two transport layer + protocols (TCP and UDP) as XML applications. + +1. Introduction + +1.1. Overview + + This document describes the Binary Lexical Octet Ad-hoc Transport + (BLOAT): a reformulation of a widely-deployed network-layer protocol + (IP [RFC791]), and two associated transport layer protocols (TCP + [RFC793] and UDP [RFC768]) as XML [XML] applications. It also + describes methods for transporting BLOAT over Ethernet and IEEE 802 + networks as well as encapsulating BLOAT in IP for gatewaying BLOAT + across the public Internet. + +1.2. Motivation + + The wild popularity of XML as a basis for application-level protocols + such as the Blocks Extensible Exchange Protocol [RFC3080], the Simple + Object Access Protocol [SOAP], and Jabber [JABBER] prompted + investigation into the possibility of extending the use of XML in the + protocol stack. Using XML at both the transport and network layer in + addition to the application layer would provide for an amazing amount + of power and flexibility while removing dependencies on proprietary + and hard-to-understand binary protocols. This protocol unification + would also allow applications to use a single XML parser for all + aspects of their operation, eliminating developer time spent figuring + out the intricacies of each new protocol, and moving the hard work of + + + + +Kennedy Informational [Page 1] + +RFC 3252 Binary Lexical Octet Ad-hoc Transport 1 April 2002 + + + parsing to the XML toolset. The use of XML also mitigates concerns + over "network vs. host" byte ordering which is at the root of many + network application bugs. + +1.3. Relation to Existing Protocols + + The reformulations specified in this RFC follow as closely as + possible the spirit of the RFCs on which they are based, and so MAY + contain elements or attributes that would not be needed in a pure + reworking (e.g. length attributes, which are implicit in XML.) + + The layering of network and transport protocols are maintained in + this RFC despite the optimizations that could be made if the line + were somewhat blurred (i.e. merging TCP and IP into a single, larger + element in the DTD) in order to foster future use of this protocol as + a basis for reformulating other protocols (such as ICMP.) + + Other than the encoding, the behavioral aspects of each of the + existing protocols remain unchanged. Routing, address spaces, TCP + congestion control, etc. behave as specified in the extant standards. + Adapting to new standards and experimental algorithm heuristics for + improving performance will become much easier once the move to BLOAT + has been completed. + +1.4. Requirement Levels + + The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", + "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this + document are to be interpreted as described in BCP 14, RFC 2119 + [RFC2119]. + +2. IPoXML + + This protocol MUST be implemented to be compliant with this RFC. + IPoXML is the root protocol REQUIRED for effective use of TCPoXML + (section 3.) and higher-level application protocols. + + The DTD for this document type can be found in section 7.1. + + The routing of IPoXML can be easily implemented on hosts with an XML + parser, as the regular structure lends itself handily to parsing and + validation of the document/datagram and then processing the + destination address, TTL, and checksum before sending it on to its + next-hop. + + The reformulation of IPv4 was chosen over IPv6 [RFC2460] due to the + wider deployment of IPv4 and the fact that implementing IPv6 as XML + would have exceeded the 1500 byte Ethernet MTU. + + + +Kennedy Informational [Page 2] + +RFC 3252 Binary Lexical Octet Ad-hoc Transport 1 April 2002 + + + All BLOAT implementations MUST use - and specify - the UTF-8 encoding + of RFC 2279 [RFC2279]. All BLOAT document/datagrams MUST be well- + formed and include the XMLDecl. + +2.1. IP Description + + A number of items have changed (for the better) from the original IP + specification. Bit-masks, where present have been converted into + human-readable values. IP addresses are listed in their dotted- + decimal notation [RFC1123]. Length and checksum values are present + as decimal integers. + + To calculate the length and checksum fields of the IP element, a + canonicalized form of the element MUST be used. The canonical form + SHALL have no whitespace (including newline characters) between + elements and only one space character between attributes. There + SHALL NOT be a space following the last attribute in an element. + + An iterative method SHOULD be used to calculate checksums, as the + length field will vary based on the size of the checksum. + + The payload element bears special attention. Due to the character + set restrictions of XML, the payload of IP datagrams (which MAY + contain arbitrary data) MUST be encoded for transport. This RFC + REQUIRES the contents of the payload to be encoded in the base-64 + encoding of RFC 2045 [RFC2045], but removes the requirement that the + encoded output MUST be wrapped on 76-character lines. + + + + + + + + + + + + + + + + + + + + + + + + +Kennedy Informational [Page 3] + +RFC 3252 Binary Lexical Octet Ad-hoc Transport 1 April 2002 + + +2.2. Example Datagram + + The following is an example IPoXML datagram with an empty payload: + + <?xml version="1.0" encoding="UTF-8"?> + <!DOCTYPE ip PUBLIC "-//IETF//DTD BLOAT 1.0 IP//EN" "bloat.dtd"> + <ip> + <header length="474"> + <version value="4"/> + <tos precedence="Routine" delay="Normal" throughput="Normal" + relibility="Normal" reserved="0"/> + <total.length value="461"/> + <id value="1"/> + <flags reserved="0" df="dont" mf="last"/> + <offset value="0"/> + <ttl value="255"/> + <protocol value="6"/> + <checksum value="8707"/> + <source address="10.0.0.22"/> + <destination address="10.0.0.1"/> + <options> + <end copied="0" class="0" number="0"/> + </options> + <padding pad="0"/> + </header> + <payload> + </payload> + </ip> + +3. TCPoXML + + This protocol MUST be implemented to be compliant with this RFC. The + DTD for this document type can be found in section 7.2. + +3.1. TCP Description + + A number of items have changed from the original TCP specification. + Bit-masks, where present have been converted into human-readable + values. Length and checksum and port values are present as decimal + integers. + + To calculate the length and checksum fields of the TCP element, a + canonicalized form of the element MUST be used as in section 2.1. + + An iterative method SHOULD be used to calculate checksums as in + section 2.1. + + The payload element MUST be encoded as in section 2.1. + + + +Kennedy Informational [Page 4] + +RFC 3252 Binary Lexical Octet Ad-hoc Transport 1 April 2002 + + + The TCP offset element was expanded to a maximum of 255 from 16 to + allow for the increased size of the header in XML. + + TCPoXML datagrams encapsulated by IPoXML MAY omit the <?xml?> header + as well as the <!DOCTYPE> declaration. + +3.2. Example Datagram + + The following is an example TCPoXML datagram with an empty payload: + + <?xml version="1.0" encoding="UTF-8"?> + <!DOCTYPE tcp PUBLIC "-//IETF//DTD BLOAT 1.0 TCP//EN" "bloat.dtd"> + <tcp> + <tcp.header> + <src port="31415"/> + <dest port="42424"/> + <sequence number="322622954"/> + <acknowledgement number="689715995"/> + <offset number=""/> + <reserved value="0"/> + <control syn="1" ack="1"/> + <window size="1"/> + <urgent pointer="0"/> + <checksum value="2988"/> + <tcp.options> + <tcp.end kind="0"/> + </tcp.options> + <padding pad="0"/> + </tcp.header> + <payload> + </payload> + </tcp> + +4. UDPoXML + + This protocol MUST be implemented to be compliant with this RFC. The + DTD for this document type can be found in section 7.3. + +4.1. UDP Description + + A number of items have changed from the original UDP specification. + Bit-masks, where present have been converted into human-readable + values. Length and checksum and port values are present as decimal + integers. + + + + + + + +Kennedy Informational [Page 5] + +RFC 3252 Binary Lexical Octet Ad-hoc Transport 1 April 2002 + + + To calculate the length and checksum fields of the UDP element, a + canonicalized form of the element MUST be used as in section 2.1. An + iterative method SHOULD be used to calculate checksums as in section + 2.1. + + The payload element MUST be encoded as in section 2.1. + + UDPoXML datagrams encapsulated by IPoXML MAY omit the <?xml?> header + as well as the <!DOCTYPE> declaration. + +4.2. Example Datagram + + The following is an example UDPoXML datagram with an empty payload: + + <?xml version="1.0" encoding="UTF-8"?> + <!DOCTYPE udp PUBLIC "-//IETF//DTD BLOAT 1.0 UDP//EN" "bloat.dtd"> + <udp> + <udp.header> + <src port="31415"/> + <dest port="42424"/> + <udp.length value="143"/> + <checksum value="2988"/> + </udp.header> + <payload> + </payload> + </udp> + +5. Network Transport + + This document provides for the transmission of BLOAT datagrams over + two common families of physical layer transport. Future RFCs will + address additional transports as routing vendors catch up to the + specification, and we begin to see BLOAT routed across the Internet + backbone. + +5.1. Ethernet + + BLOAT is encapsulated in Ethernet datagrams as in [RFC894] with the + exception that the type field of the Ethernet frame MUST contain the + value 0xBEEF. The first 5 octets of the Ethernet frame payload will + be 0x3c 3f 78 6d 6c ("<?xml".) + +5.2. IEEE 802 + + BLOAT is encapsulated in IEEE 802 Networks as in [RFC1042] except + that the protocol type code for IPoXML is 0xBEEF. + + + + + +Kennedy Informational [Page 6] + +RFC 3252 Binary Lexical Octet Ad-hoc Transport 1 April 2002 + + +6. Gatewaying over IP + + In order to facilitate the gradual introduction of BLOAT into the + public Internet, BLOAT MAY be encapsulated in IP as in [RFC2003] to + gateway between networks that run BLOAT natively on their LANs. + +7. DTDs + + The Transport DTDs (7.2. and 7.3.) build on the definitions in the + Network DTD (7.1.) + + The DTDs are referenced by their PubidLiteral and SystemLiteral (from + [XML]) although it is understood that most IPoXML implementations + will not need to pull down the DTD, as it will normally be embedded + in the implementation, and presents something of a catch-22 if you + need to load part of your network protocol over the network. + +7.1. IPoXML DTD + + <!-- + DTD for IP over XML. + Refer to this DTD as: + + <!DOCTYPE ip PUBLIC "-//IETF//DTD BLOAT 1.0 IP//EN" "bloat.dtd"> + --> + <!-- + DTD data types: + + Digits [0..9]+ + + Precedence "NetworkControl | InternetworkControl | + CRITIC | FlashOverride | Flash | Immediate | + Priority | Routine" + + IP4Addr "dotted-decimal" notation of [RFC1123] + + Class [0..3] + + Sec "Unclassified | Confidential | EFTO | MMMM | PROG | + Restricted | Secret | Top Secret | Reserved" + + Compartments [0..65535] + + Handling [0..65535] + + TCC [0..16777216] + + --> + + + +Kennedy Informational [Page 7] + +RFC 3252 Binary Lexical Octet Ad-hoc Transport 1 April 2002 + + + <!ENTITY % Digits "CDATA"> + <!ENTITY % Precedence "CDATA"> + <!ENTITY % IP4Addr "CDATA"> + <!ENTITY % Class "CDATA"> + <!ENTITY % Sec "CDATA"> + <!ENTITY % Compartments "CDATA"> + <!ENTITY % Handling "CDATA"> + <!ENTITY % TCC "CDATA"> + + <!ELEMENT ip (header, payload)> + + <!ELEMENT header (version, tos, total.length, id, flags, offset, ttl, + protocol, checksum, source, destination, options, + padding)> + <!-- length of header in 32-bit words --> + <!ATTLIST header + length %Digits; #REQUIRED> + + <!ELEMENT version EMPTY> + <!-- ip version. SHOULD be "4" --> + <!ATTLIST version + value %Digits; #REQUIRED> + + <!ELEMENT tos EMPTY> + <!ATTLIST tos + precedence %Precedence; #REQUIRED + delay (normal | low) #REQUIRED + throughput (normal | high) #REQUIRED + relibility (normal | high) #REQUIRED + reserved CDATA #FIXED "0"> + + <!ELEMENT total.length EMPTY> + <!-- + total length of datagram (header and payload) in octets, MUST be + less than 65,535 (and SHOULD be less than 1024 for IPoXML on local + ethernets). + --> + <!ATTLIST total.length + value %Digits; #REQUIRED> + + <!ELEMENT id EMPTY> + <!-- 0 <= id <= 65,535 --> + <!ATTLIST id + value %Digits; #REQUIRED> + + <!ELEMENT flags EMPTY> + <!-- df = don't fragment, mf = more fragments --> + <!ATTLIST flags + + + +Kennedy Informational [Page 8] + +RFC 3252 Binary Lexical Octet Ad-hoc Transport 1 April 2002 + + + reserved CDATA #FIXED "0" + df (may|dont) #REQUIRED + mf (last|more) #REQUIRED> + + <!ELEMENT offset EMPTY> + <!-- 0 <= offset <= 8192 measured in 8 octet (64-bit) chunks --> + <!ATTLIST offset + value %Digits; #REQUIRED> + + <!ELEMENT ttl EMPTY> + <!-- 0 <= ttl <= 255 --> + <!ATTLIST ttl + value %Digits; #REQUIRED> + + <!ELEMENT protocol EMPTY> + <!-- 0 <= protocol <= 255 (per IANA) --> + <!ATTLIST protocol + value %Digits; #REQUIRED> + + <!ELEMENT checksum EMPTY> + <!-- 0 <= checksum <= 65535 (over header only) --> + <!ATTLIST checksum + value %Digits; #REQUIRED> + + <!ELEMENT source EMPTY> + <!ATTLIST source + address %IP4Addr; #REQUIRED> + + <!ELEMENT destination EMPTY> + <!ATTLIST destination + address %IP4Addr; #REQUIRED> + + <!ELEMENT options ( end | noop | security | loose | strict | record + | stream | timestamp )*> + + <!ELEMENT end EMPTY> + <!ATTLIST end + copied (0|1) #REQUIRED + class CDATA #FIXED "0" + number CDATA #FIXED "0"> + + <!ELEMENT noop EMPTY> + <!ATTLIST noop + copied (0|1) #REQUIRED + class CDATA #FIXED "0" + number CDATA #FIXED "1"> + + <!ELEMENT security EMPTY> + + + +Kennedy Informational [Page 9] + +RFC 3252 Binary Lexical Octet Ad-hoc Transport 1 April 2002 + + + <!ATTLIST security + copied CDATA #FIXED "1" + class CDATA #FIXED "0" + number CDATA #FIXED "2" + length CDATA #FIXED "11" + security %Sec; #REQUIRED + compartments %Compartments; #REQUIRED + handling %Handling; #REQUIRED + tcc %TCC; #REQUIRED> + <!ELEMENT loose (hop)+> + <!ATTLIST loose + copied CDATA #FIXED "1" + class CDATA #FIXED "0" + number CDATA #FIXED "3" + length %Digits; #REQUIRED + pointer %Digits; #REQUIRED> + + <!ELEMENT hop EMPTY> + <!ATTLIST hop + address %IP4Addr; #REQUIRED> + + <!ELEMENT strict (hop)+> + <!ATTLIST strict + copied CDATA #FIXED "1" + class CDATA #FIXED "0" + number CDATA #FIXED "9" + length %Digits; #REQUIRED + pointer %Digits; #REQUIRED> + + <!ELEMENT record (hop)+> + <!ATTLIST record + copied CDATA #FIXED "0" + class CDATA #FIXED "0" + number CDATA #FIXED "7" + length %Digits; #REQUIRED + pointer %Digits; #REQUIRED> + + <!ELEMENT stream EMPTY> + <!-- 0 <= id <= 65,535 --> + <!ATTLIST stream + copied CDATA #FIXED "1" + class CDATA #FIXED "0" + number CDATA #FIXED "8" + length CDATA #FIXED "4" + id %Digits; #REQUIRED> + + <!ELEMENT timestamp (tstamp)+> + <!-- 0 <= oflw <=15 --> + + + +Kennedy Informational [Page 10] + +RFC 3252 Binary Lexical Octet Ad-hoc Transport 1 April 2002 + + + <!ATTLIST timestamp + copied CDATA #FIXED "0" + class CDATA #FIXED "2" + number CDATA #FIXED "4" + length %Digits; #REQUIRED + pointer %Digits; #REQUIRED + oflw %Digits; #REQUIRED + flag (0 | 1 | 3) #REQUIRED> + + <!ELEMENT tstamp EMPTY> + <!ATTLIST tstamp + time %Digits; #REQUIRED + address %IP4Addr; #IMPLIED> + <!-- + padding to bring header to 32-bit boundary. + pad MUST be "0"* + --> + <!ELEMENT padding EMPTY> + <!ATTLIST padding + pad CDATA #REQUIRED> + + <!-- payload MUST be encoded as base-64 [RFC2045], as modified + by section 2.1 of this RFC --> + <!ELEMENT payload (CDATA)> + +7.2. TCPoXML DTD + + <!-- + DTD for TCP over XML. + Refer to this DTD as: + + <!DOCTYPE tcp PUBLIC "-//IETF//DTD BLOAT 1.0 TCP//EN" "bloat.dtd"> + --> + + <!-- the pseudoheader is only included for checksum calculations --> + <!ELEMENT tcp (tcp.pseudoheader?, tcp.header, payload)> + + <!ELEMENT tcp.header (src, dest, sequence, acknowledgement, offset, + reserved, control, window, checksum, urgent, + tcp.options, padding)> + + <!ELEMENT src EMPTY> + <!-- 0 <= port <= 65,535 --> + <!ATTLIST src + port %Digits; #REQUIRED> + + <!ELEMENT dest EMPTY> + <!-- 0 <= port <= 65,535 --> + + + +Kennedy Informational [Page 11] + +RFC 3252 Binary Lexical Octet Ad-hoc Transport 1 April 2002 + + + <!ATTLIST dest + port %Digits; #REQUIRED> + + <!ELEMENT sequence EMPTY> + <!-- 0 <= number <= 4294967295 --> + <!ATTLIST sequence + number %Digits; #REQUIRED> + + <!ELEMENT acknowledgement EMPTY> + <!-- 0 <= number <= 4294967295 --> + <!ATTLIST acknowledgement + number %Digits; #REQUIRED> + + <!ELEMENT offset EMPTY> + <!-- 0 <= number <= 255 --> + <!ATTLIST offset + number %Digits; #REQUIRED> + + <!ELEMENT reserved EMPTY> + <!ATTLIST reserved + value CDATA #FIXED "0"> + + <!ELEMENT control EMPTY> + <!ATTLIST control + urg (0|1) #IMPLIED + ack (0|1) #IMPLIED + psh (0|1) #IMPLIED + rst (0|1) #IMPLIED + syn (0|1) #IMPLIED + fin (0|1) #IMPLIED> + + <!ELEMENT window EMPTY> + <!-- 0 <= size <= 65,535 --> + <!ATTLIST window + size %Digits; #REQUIRED> + + <!-- + checksum as in ip, but with + the following pseudo-header added into the tcp element: + --> + <!ELEMENT tcp.pseudoheader (source, destination, protocol, + tcp.length)> + + <!-- + tcp header + data length in octets. does not include the size of + + the pseudoheader. + --> + + + +Kennedy Informational [Page 12] + +RFC 3252 Binary Lexical Octet Ad-hoc Transport 1 April 2002 + + + <!ELEMENT tcp.length EMPTY> + <!ATTLIST tcp.length + value %Digits; #REQUIRED> + + <!ELEMENT urgent EMPTY> + <!-- 0 <= pointer <= 65,535 --> + <!ATTLIST urgent + pointer %Digits; #REQUIRED> + + <!ELEMENT tcp.options (tcp.end | tcp.noop | tcp.mss)+> + + <!ELEMENT tcp.end EMPTY> + <!ATTLIST tcp.end + kind CDATA #FIXED "0"> + + <!ELEMENT tcp.noop EMPTY> + <!ATTLIST tcp.noop + kind CDATA #FIXED "1"> + + <!ELEMENT tcp.mss EMPTY> + <!ATTLIST tcp.mss + kind CDATA #FIXED "2" + length CDATA #FIXED "4" + size %Digits; #REQUIRED> + +7.3. UDPoXML DTD + + <!-- + DTD for UDP over XML. + Refer to this DTD as: + + <!DOCTYPE udp PUBLIC "-//IETF//DTD BLOAT 1.0 UDP//EN" "bloat.dtd"> + --> + + <!ELEMENT udp (udp.pseudoheader?, udp.header, payload)> + + <!ELEMENT udp.header (src, dest, udp.length, checksum)> + + <!ELEMENT udp.pseudoheader (source, destination, protocol, + udp.length)> + + <!-- + udp header + data length in octets. does not include the size of + the pseudoheader. + --> + <!ELEMENT udp.length EMPTY> + <!ATTLIST udp.length + value %Digits; #REQUIRED> + + + +Kennedy Informational [Page 13] + +RFC 3252 Binary Lexical Octet Ad-hoc Transport 1 April 2002 + + +8. Security Considerations + + XML, as a subset of SGML, has the same security considerations as + specified in SGML Media Types [RFC1874]. Security considerations + that apply to IP, TCP and UDP also likely apply to BLOAT as it does + not attempt to correct for issues not related to message format. + +9. References + + [JABBER] Miller, J., "Jabber", draft-miller-jabber-00.txt, + February 2002. (Work in Progress) + + [RFC768] Postel, J., "User Datagram Protocol", STD 6, RFC 768, + August 1980. + + [RFC791] Postel, J., "Internet Protocol", STD 5, RFC 791, + September 1981. + + [RFC793] Postel, J., "Transmission Control Protocol", STD 7, RFC + 793, September 1981. + + [RFC894] Hornig, C., "Standard for the Transmission of IP + Datagrams over Ethernet Networks.", RFC 894, April 1984. + + [RFC1042] Postel, J. and J. Reynolds, "Standard for the + Transmission of IP Datagrams Over IEEE 802 Networks", STD + 43, RFC 1042, February 1988. + + [RFC1123] Braden, R., "Requirements for Internet Hosts - + Application and Support", RFC 1123, October 1989. + + [RFC1874] Levinson, E., "SGML Media Types", RFC 1874, December + 1995. + + [RFC2003] Perkins, C., "IP Encapsulation within IP", RFC 2003, + October 1996. + + [RFC2045] Freed, N. and N. Borenstein, "Multipurpose Internet Mail + Extensions (MIME) Part One: Format of Internet Message + Bodies", RFC 2045, November 1996. + + [RFC2119] Bradner, S., "Key words for use in RFCs to Indicate + Requirement Levels", BCP 14, RFC 2119, March 1997. + + [RFC2279] Yergeau, F., "UTF-8, a transformation format of ISO + 10646", RFC 2279, January 1998. + + + + + +Kennedy Informational [Page 14] + +RFC 3252 Binary Lexical Octet Ad-hoc Transport 1 April 2002 + + + [RFC2460] Deering, S. and R. Hinden, "Internet Protocol, Version 6 + (IPv6) Specification", RFC 2460, December 1998. + + [RFC3080] Rose, M., "The Blocks Extensible Exchange Protocol Core", + RFC 3080, March 2001. + + [SOAP] Box, D., Ehnebuske, D., Kakivaya, G., Layman, A., + Mendelsohn, N., Nielsen, H. F., Thatte, S. Winer, D., + "Simple Object Access Protocol (SOAP) 1.1" World Wide Web + Consortium Note, May 2000 http://www.w3.org/TR/SOAP/ + + [XML] Bray, T., Paoli, J., Sperberg-McQueen, C. M., "Extensible + Markup Language (XML)" World Wide Web Consortium + Recommendation REC- xml-19980210. + http://www.w3.org/TR/1998/REC-xml-19980210 + +10. Author's Address + + Hugh Kennedy + Mimezine + 1060 West Addison + Chicago, IL 60613 + USA + + EMail: kennedyh@engin.umich.edu + + + + + + + + + + + + + + + + + + + + + + + + + + +Kennedy Informational [Page 15] + +RFC 3252 Binary Lexical Octet Ad-hoc Transport 1 April 2002 + + +11. Full Copyright Statement + + Copyright (C) The Internet Society (2002). All Rights Reserved. + + This document and translations of it may be copied and furnished to + others, and derivative works that comment on or otherwise explain it + or assist in its implementation may be prepared, copied, published + and distributed, in whole or in part, without restriction of any + kind, provided that the above copyright notice and this paragraph are + included on all such copies and derivative works. However, this + document itself may not be modified in any way, such as by removing + the copyright notice or references to the Internet Society or other + Internet organizations, except as needed for the purpose of + developing Internet standards in which case the procedures for + copyrights defined in the Internet Standards process must be + followed, or as required to translate it into languages other than + English. + + The limited permissions granted above are perpetual and will not be + revoked by the Internet Society or its successors or assigns. + + This document and the information contained herein is provided on an + "AS IS" basis and THE INTERNET SOCIETY AND THE INTERNET ENGINEERING + TASK FORCE DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING + BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE INFORMATION + HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED WARRANTIES OF + MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. + +Acknowledgement + + Funding for the RFC Editor function is currently provided by the + Internet Society. + + + + + + + + + + + + + + + + + + + +Kennedy Informational [Page 16] + + + + + + + +Network Working Group H. Kennedy +Request for Comments: 3252 Mimezine +Category: Informational 1 April 2002 + + + Binary Lexical Octet Ad-hoc Transport + +Status of this Memo + + This memo provides information for the Internet community. It does + not specify an Internet standard of any kind. Distribution of this + memo is unlimited. + +Copyright Notice + + Copyright (C) The Internet Society (2002). All Rights Reserved. + +Abstract + + This document defines a reformulation of IP and two transport layer + protocols (TCP and UDP) as XML applications. + +1. Introduction + +1.1. Overview + + This document describes the Binary Lexical Octet Ad-hoc Transport + (BLOAT): a reformulation of a widely-deployed network-layer protocol + (IP [RFC791]), and two associated transport layer protocols (TCP + [RFC793] and UDP [RFC768]) as XML [XML] applications. It also + describes methods for transporting BLOAT over Ethernet and IEEE 802 + networks as well as encapsulating BLOAT in IP for gatewaying BLOAT + across the public Internet. + +1.2. Motivation + + The wild popularity of XML as a basis for application-level protocols + such as the Blocks Extensible Exchange Protocol [RFC3080], the Simple + Object Access Protocol [SOAP], and Jabber [JABBER] prompted + investigation into the possibility of extending the use of XML in the + protocol stack. Using XML at both the transport and network layer in + addition to the application layer would provide for an amazing amount + of power and flexibility while removing dependencies on proprietary + and hard-to-understand binary protocols. This protocol unification + would also allow applications to use a single XML parser for all + aspects of their operation, eliminating developer time spent figuring + out the intricacies of each new protocol, and moving the hard work of + + + + +Kennedy Informational [Page 1] + +RFC 3252 Binary Lexical Octet Ad-hoc Transport 1 April 2002 + + + parsing to the XML toolset. The use of XML also mitigates concerns + over "network vs. host" byte ordering which is at the root of many + network application bugs. + +1.3. Relation to Existing Protocols + + The reformulations specified in this RFC follow as closely as + possible the spirit of the RFCs on which they are based, and so MAY + contain elements or attributes that would not be needed in a pure + reworking (e.g. length attributes, which are implicit in XML.) + + The layering of network and transport protocols are maintained in + this RFC despite the optimizations that could be made if the line + were somewhat blurred (i.e. merging TCP and IP into a single, larger + element in the DTD) in order to foster future use of this protocol as + a basis for reformulating other protocols (such as ICMP.) + + Other than the encoding, the behavioral aspects of each of the + existing protocols remain unchanged. Routing, address spaces, TCP + congestion control, etc. behave as specified in the extant standards. + Adapting to new standards and experimental algorithm heuristics for + improving performance will become much easier once the move to BLOAT + has been completed. + +1.4. Requirement Levels + + The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", + "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this + document are to be interpreted as described in BCP 14, RFC 2119 + [RFC2119]. + +2. IPoXML + + This protocol MUST be implemented to be compliant with this RFC. + IPoXML is the root protocol REQUIRED for effective use of TCPoXML + (section 3.) and higher-level application protocols. + + The DTD for this document type can be found in section 7.1. + + The routing of IPoXML can be easily implemented on hosts with an XML + parser, as the regular structure lends itself handily to parsing and + validation of the document/datagram and then processing the + destination address, TTL, and checksum before sending it on to its + next-hop. + + The reformulation of IPv4 was chosen over IPv6 [RFC2460] due to the + wider deployment of IPv4 and the fact that implementing IPv6 as XML + would have exceeded the 1500 byte Ethernet MTU. + + + +Kennedy Informational [Page 2] + +RFC 3252 Binary Lexical Octet Ad-hoc Transport 1 April 2002 + + + All BLOAT implementations MUST use - and specify - the UTF-8 encoding + of RFC 2279 [RFC2279]. All BLOAT document/datagrams MUST be well- + formed and include the XMLDecl. + +2.1. IP Description + + A number of items have changed (for the better) from the original IP + specification. Bit-masks, where present have been converted into + human-readable values. IP addresses are listed in their dotted- + decimal notation [RFC1123]. Length and checksum values are present + as decimal integers. + + To calculate the length and checksum fields of the IP element, a + canonicalized form of the element MUST be used. The canonical form + SHALL have no whitespace (including newline characters) between + elements and only one space character between attributes. There + SHALL NOT be a space following the last attribute in an element. + + An iterative method SHOULD be used to calculate checksums, as the + length field will vary based on the size of the checksum. + + The payload element bears special attention. Due to the character + set restrictions of XML, the payload of IP datagrams (which MAY + contain arbitrary data) MUST be encoded for transport. This RFC + REQUIRES the contents of the payload to be encoded in the base-64 + encoding of RFC 2045 [RFC2045], but removes the requirement that the + encoded output MUST be wrapped on 76-character lines. + + + + + + + + + + + + + + + + + + + + + + + + +Kennedy Informational [Page 3] + +RFC 3252 Binary Lexical Octet Ad-hoc Transport 1 April 2002 + + +2.2. Example Datagram + + The following is an example IPoXML datagram with an empty payload: + + <?xml version="1.0" encoding="UTF-8"?> + <!DOCTYPE ip PUBLIC "-//IETF//DTD BLOAT 1.0 IP//EN" "bloat.dtd"> + <ip> + <header length="474"> + <version value="4"/> + <tos precedence="Routine" delay="Normal" throughput="Normal" + relibility="Normal" reserved="0"/> + <total.length value="461"/> + <id value="1"/> + <flags reserved="0" df="dont" mf="last"/> + <offset value="0"/> + <ttl value="255"/> + <protocol value="6"/> + <checksum value="8707"/> + <source address="10.0.0.22"/> + <destination address="10.0.0.1"/> + <options> + <end copied="0" class="0" number="0"/> + </options> + <padding pad="0"/> + </header> + <payload> + </payload> + </ip> + +3. TCPoXML + + This protocol MUST be implemented to be compliant with this RFC. The + DTD for this document type can be found in section 7.2. + +3.1. TCP Description + + A number of items have changed from the original TCP specification. + Bit-masks, where present have been converted into human-readable + values. Length and checksum and port values are present as decimal + integers. + + To calculate the length and checksum fields of the TCP element, a + canonicalized form of the element MUST be used as in section 2.1. + + An iterative method SHOULD be used to calculate checksums as in + section 2.1. + + The payload element MUST be encoded as in section 2.1. + + + +Kennedy Informational [Page 4] + +RFC 3252 Binary Lexical Octet Ad-hoc Transport 1 April 2002 + + + The TCP offset element was expanded to a maximum of 255 from 16 to + allow for the increased size of the header in XML. + + TCPoXML datagrams encapsulated by IPoXML MAY omit the <?xml?> header + as well as the <!DOCTYPE> declaration. + +3.2. Example Datagram + + The following is an example TCPoXML datagram with an empty payload: + + <?xml version="1.0" encoding="UTF-8"?> + <!DOCTYPE tcp PUBLIC "-//IETF//DTD BLOAT 1.0 TCP//EN" "bloat.dtd"> + <tcp> + <tcp.header> + <src port="31415"/> + <dest port="42424"/> + <sequence number="322622954"/> + <acknowledgement number="689715995"/> + <offset number=""/> + <reserved value="0"/> + <control syn="1" ack="1"/> + <window size="1"/> + <urgent pointer="0"/> + <checksum value="2988"/> + <tcp.options> + <tcp.end kind="0"/> + </tcp.options> + <padding pad="0"/> + </tcp.header> + <payload> + </payload> + </tcp> + +4. UDPoXML + + This protocol MUST be implemented to be compliant with this RFC. The + DTD for this document type can be found in section 7.3. + +4.1. UDP Description + + A number of items have changed from the original UDP specification. + Bit-masks, where present have been converted into human-readable + values. Length and checksum and port values are present as decimal + integers. + + + + + + + +Kennedy Informational [Page 5] + +RFC 3252 Binary Lexical Octet Ad-hoc Transport 1 April 2002 + + + To calculate the length and checksum fields of the UDP element, a + canonicalized form of the element MUST be used as in section 2.1. An + iterative method SHOULD be used to calculate checksums as in section + 2.1. + + The payload element MUST be encoded as in section 2.1. + + UDPoXML datagrams encapsulated by IPoXML MAY omit the <?xml?> header + as well as the <!DOCTYPE> declaration. + +4.2. Example Datagram + + The following is an example UDPoXML datagram with an empty payload: + + <?xml version="1.0" encoding="UTF-8"?> + <!DOCTYPE udp PUBLIC "-//IETF//DTD BLOAT 1.0 UDP//EN" "bloat.dtd"> + <udp> + <udp.header> + <src port="31415"/> + <dest port="42424"/> + <udp.length value="143"/> + <checksum value="2988"/> + </udp.header> + <payload> + </payload> + </udp> + +5. Network Transport + + This document provides for the transmission of BLOAT datagrams over + two common families of physical layer transport. Future RFCs will + address additional transports as routing vendors catch up to the + specification, and we begin to see BLOAT routed across the Internet + backbone. + +5.1. Ethernet + + BLOAT is encapsulated in Ethernet datagrams as in [RFC894] with the + exception that the type field of the Ethernet frame MUST contain the + value 0xBEEF. The first 5 octets of the Ethernet frame payload will + be 0x3c 3f 78 6d 6c ("<?xml".) + +5.2. IEEE 802 + + BLOAT is encapsulated in IEEE 802 Networks as in [RFC1042] except + that the protocol type code for IPoXML is 0xBEEF. + + + + + +Kennedy Informational [Page 6] + +RFC 3252 Binary Lexical Octet Ad-hoc Transport 1 April 2002 + + +6. Gatewaying over IP + + In order to facilitate the gradual introduction of BLOAT into the + public Internet, BLOAT MAY be encapsulated in IP as in [RFC2003] to + gateway between networks that run BLOAT natively on their LANs. + +7. DTDs + + The Transport DTDs (7.2. and 7.3.) build on the definitions in the + Network DTD (7.1.) + + The DTDs are referenced by their PubidLiteral and SystemLiteral (from + [XML]) although it is understood that most IPoXML implementations + will not need to pull down the DTD, as it will normally be embedded + in the implementation, and presents something of a catch-22 if you + need to load part of your network protocol over the network. + +7.1. IPoXML DTD + + <!-- + DTD for IP over XML. + Refer to this DTD as: + + <!DOCTYPE ip PUBLIC "-//IETF//DTD BLOAT 1.0 IP//EN" "bloat.dtd"> + --> + <!-- + DTD data types: + + Digits [0..9]+ + + Precedence "NetworkControl | InternetworkControl | + CRITIC | FlashOverride | Flash | Immediate | + Priority | Routine" + + IP4Addr "dotted-decimal" notation of [RFC1123] + + Class [0..3] + + Sec "Unclassified | Confidential | EFTO | MMMM | PROG | + Restricted | Secret | Top Secret | Reserved" + + Compartments [0..65535] + + Handling [0..65535] + + TCC [0..16777216] + + --> + + + +Kennedy Informational [Page 7] + +RFC 3252 Binary Lexical Octet Ad-hoc Transport 1 April 2002 + + + <!ENTITY % Digits "CDATA"> + <!ENTITY % Precedence "CDATA"> + <!ENTITY % IP4Addr "CDATA"> + <!ENTITY % Class "CDATA"> + <!ENTITY % Sec "CDATA"> + <!ENTITY % Compartments "CDATA"> + <!ENTITY % Handling "CDATA"> + <!ENTITY % TCC "CDATA"> + + <!ELEMENT ip (header, payload)> + + <!ELEMENT header (version, tos, total.length, id, flags, offset, ttl, + protocol, checksum, source, destination, options, + padding)> + <!-- length of header in 32-bit words --> + <!ATTLIST header + length %Digits; #REQUIRED> + + <!ELEMENT version EMPTY> + <!-- ip version. SHOULD be "4" --> + <!ATTLIST version + value %Digits; #REQUIRED> + + <!ELEMENT tos EMPTY> + <!ATTLIST tos + precedence %Precedence; #REQUIRED + delay (normal | low) #REQUIRED + throughput (normal | high) #REQUIRED + relibility (normal | high) #REQUIRED + reserved CDATA #FIXED "0"> + + <!ELEMENT total.length EMPTY> + <!-- + total length of datagram (header and payload) in octets, MUST be + less than 65,535 (and SHOULD be less than 1024 for IPoXML on local + ethernets). + --> + <!ATTLIST total.length + value %Digits; #REQUIRED> + + <!ELEMENT id EMPTY> + <!-- 0 <= id <= 65,535 --> + <!ATTLIST id + value %Digits; #REQUIRED> + + <!ELEMENT flags EMPTY> + <!-- df = don't fragment, mf = more fragments --> + <!ATTLIST flags + + + +Kennedy Informational [Page 8] + +RFC 3252 Binary Lexical Octet Ad-hoc Transport 1 April 2002 + + + reserved CDATA #FIXED "0" + df (may|dont) #REQUIRED + mf (last|more) #REQUIRED> + + <!ELEMENT offset EMPTY> + <!-- 0 <= offset <= 8192 measured in 8 octet (64-bit) chunks --> + <!ATTLIST offset + value %Digits; #REQUIRED> + + <!ELEMENT ttl EMPTY> + <!-- 0 <= ttl <= 255 --> + <!ATTLIST ttl + value %Digits; #REQUIRED> + + <!ELEMENT protocol EMPTY> + <!-- 0 <= protocol <= 255 (per IANA) --> + <!ATTLIST protocol + value %Digits; #REQUIRED> + + <!ELEMENT checksum EMPTY> + <!-- 0 <= checksum <= 65535 (over header only) --> + <!ATTLIST checksum + value %Digits; #REQUIRED> + + <!ELEMENT source EMPTY> + <!ATTLIST source + address %IP4Addr; #REQUIRED> + + <!ELEMENT destination EMPTY> + <!ATTLIST destination + address %IP4Addr; #REQUIRED> + + <!ELEMENT options ( end | noop | security | loose | strict | record + | stream | timestamp )*> + + <!ELEMENT end EMPTY> + <!ATTLIST end + copied (0|1) #REQUIRED + class CDATA #FIXED "0" + number CDATA #FIXED "0"> + + <!ELEMENT noop EMPTY> + <!ATTLIST noop + copied (0|1) #REQUIRED + class CDATA #FIXED "0" + number CDATA #FIXED "1"> + + <!ELEMENT security EMPTY> + + + +Kennedy Informational [Page 9] + +RFC 3252 Binary Lexical Octet Ad-hoc Transport 1 April 2002 + + + <!ATTLIST security + copied CDATA #FIXED "1" + class CDATA #FIXED "0" + number CDATA #FIXED "2" + length CDATA #FIXED "11" + security %Sec; #REQUIRED + compartments %Compartments; #REQUIRED + handling %Handling; #REQUIRED + tcc %TCC; #REQUIRED> + <!ELEMENT loose (hop)+> + <!ATTLIST loose + copied CDATA #FIXED "1" + class CDATA #FIXED "0" + number CDATA #FIXED "3" + length %Digits; #REQUIRED + pointer %Digits; #REQUIRED> + + <!ELEMENT hop EMPTY> + <!ATTLIST hop + address %IP4Addr; #REQUIRED> + + <!ELEMENT strict (hop)+> + <!ATTLIST strict + copied CDATA #FIXED "1" + class CDATA #FIXED "0" + number CDATA #FIXED "9" + length %Digits; #REQUIRED + pointer %Digits; #REQUIRED> + + <!ELEMENT record (hop)+> + <!ATTLIST record + copied CDATA #FIXED "0" + class CDATA #FIXED "0" + number CDATA #FIXED "7" + length %Digits; #REQUIRED + pointer %Digits; #REQUIRED> + + <!ELEMENT stream EMPTY> + <!-- 0 <= id <= 65,535 --> + <!ATTLIST stream + copied CDATA #FIXED "1" + class CDATA #FIXED "0" + number CDATA #FIXED "8" + length CDATA #FIXED "4" + id %Digits; #REQUIRED> + + <!ELEMENT timestamp (tstamp)+> + <!-- 0 <= oflw <=15 --> + + + +Kennedy Informational [Page 10] + +RFC 3252 Binary Lexical Octet Ad-hoc Transport 1 April 2002 + + + <!ATTLIST timestamp + copied CDATA #FIXED "0" + class CDATA #FIXED "2" + number CDATA #FIXED "4" + length %Digits; #REQUIRED + pointer %Digits; #REQUIRED + oflw %Digits; #REQUIRED + flag (0 | 1 | 3) #REQUIRED> + + <!ELEMENT tstamp EMPTY> + <!ATTLIST tstamp + time %Digits; #REQUIRED + address %IP4Addr; #IMPLIED> + <!-- + padding to bring header to 32-bit boundary. + pad MUST be "0"* + --> + <!ELEMENT padding EMPTY> + <!ATTLIST padding + pad CDATA #REQUIRED> + + <!-- payload MUST be encoded as base-64 [RFC2045], as modified + by section 2.1 of this RFC --> + <!ELEMENT payload (CDATA)> + +7.2. TCPoXML DTD + + <!-- + DTD for TCP over XML. + Refer to this DTD as: + + <!DOCTYPE tcp PUBLIC "-//IETF//DTD BLOAT 1.0 TCP//EN" "bloat.dtd"> + --> + + <!-- the pseudoheader is only included for checksum calculations --> + <!ELEMENT tcp (tcp.pseudoheader?, tcp.header, payload)> + + <!ELEMENT tcp.header (src, dest, sequence, acknowledgement, offset, + reserved, control, window, checksum, urgent, + tcp.options, padding)> + + <!ELEMENT src EMPTY> + <!-- 0 <= port <= 65,535 --> + <!ATTLIST src + port %Digits; #REQUIRED> + + <!ELEMENT dest EMPTY> + <!-- 0 <= port <= 65,535 --> + + + +Kennedy Informational [Page 11] + +RFC 3252 Binary Lexical Octet Ad-hoc Transport 1 April 2002 + + + <!ATTLIST dest + port %Digits; #REQUIRED> + + <!ELEMENT sequence EMPTY> + <!-- 0 <= number <= 4294967295 --> + <!ATTLIST sequence + number %Digits; #REQUIRED> + + <!ELEMENT acknowledgement EMPTY> + <!-- 0 <= number <= 4294967295 --> + <!ATTLIST acknowledgement + number %Digits; #REQUIRED> + + <!ELEMENT offset EMPTY> + <!-- 0 <= number <= 255 --> + <!ATTLIST offset + number %Digits; #REQUIRED> + + <!ELEMENT reserved EMPTY> + <!ATTLIST reserved + value CDATA #FIXED "0"> + + <!ELEMENT control EMPTY> + <!ATTLIST control + urg (0|1) #IMPLIED + ack (0|1) #IMPLIED + psh (0|1) #IMPLIED + rst (0|1) #IMPLIED + syn (0|1) #IMPLIED + fin (0|1) #IMPLIED> + + <!ELEMENT window EMPTY> + <!-- 0 <= size <= 65,535 --> + <!ATTLIST window + size %Digits; #REQUIRED> + + <!-- + checksum as in ip, but with + the following pseudo-header added into the tcp element: + --> + <!ELEMENT tcp.pseudoheader (source, destination, protocol, + tcp.length)> + + <!-- + tcp header + data length in octets. does not include the size of + + the pseudoheader. + --> + + + +Kennedy Informational [Page 12] + +RFC 3252 Binary Lexical Octet Ad-hoc Transport 1 April 2002 + + + <!ELEMENT tcp.length EMPTY> + <!ATTLIST tcp.length + value %Digits; #REQUIRED> + + <!ELEMENT urgent EMPTY> + <!-- 0 <= pointer <= 65,535 --> + <!ATTLIST urgent + pointer %Digits; #REQUIRED> + + <!ELEMENT tcp.options (tcp.end | tcp.noop | tcp.mss)+> + + <!ELEMENT tcp.end EMPTY> + <!ATTLIST tcp.end + kind CDATA #FIXED "0"> + + <!ELEMENT tcp.noop EMPTY> + <!ATTLIST tcp.noop + kind CDATA #FIXED "1"> + + <!ELEMENT tcp.mss EMPTY> + <!ATTLIST tcp.mss + kind CDATA #FIXED "2" + length CDATA #FIXED "4" + size %Digits; #REQUIRED> + +7.3. UDPoXML DTD + + <!-- + DTD for UDP over XML. + Refer to this DTD as: + + <!DOCTYPE udp PUBLIC "-//IETF//DTD BLOAT 1.0 UDP//EN" "bloat.dtd"> + --> + + <!ELEMENT udp (udp.pseudoheader?, udp.header, payload)> + + <!ELEMENT udp.header (src, dest, udp.length, checksum)> + + <!ELEMENT udp.pseudoheader (source, destination, protocol, + udp.length)> + + <!-- + udp header + data length in octets. does not include the size of + the pseudoheader. + --> + <!ELEMENT udp.length EMPTY> + <!ATTLIST udp.length + value %Digits; #REQUIRED> + + + +Kennedy Informational [Page 13] + +RFC 3252 Binary Lexical Octet Ad-hoc Transport 1 April 2002 + + +8. Security Considerations + + XML, as a subset of SGML, has the same security considerations as + specified in SGML Media Types [RFC1874]. Security considerations + that apply to IP, TCP and UDP also likely apply to BLOAT as it does + not attempt to correct for issues not related to message format. + +9. References + + [JABBER] Miller, J., "Jabber", draft-miller-jabber-00.txt, + February 2002. (Work in Progress) + + [RFC768] Postel, J., "User Datagram Protocol", STD 6, RFC 768, + August 1980. + + [RFC791] Postel, J., "Internet Protocol", STD 5, RFC 791, + September 1981. + + [RFC793] Postel, J., "Transmission Control Protocol", STD 7, RFC + 793, September 1981. + + [RFC894] Hornig, C., "Standard for the Transmission of IP + Datagrams over Ethernet Networks.", RFC 894, April 1984. + + [RFC1042] Postel, J. and J. Reynolds, "Standard for the + Transmission of IP Datagrams Over IEEE 802 Networks", STD + 43, RFC 1042, February 1988. + + [RFC1123] Braden, R., "Requirements for Internet Hosts - + Application and Support", RFC 1123, October 1989. + + [RFC1874] Levinson, E., "SGML Media Types", RFC 1874, December + 1995. + + [RFC2003] Perkins, C., "IP Encapsulation within IP", RFC 2003, + October 1996. + + [RFC2045] Freed, N. and N. Borenstein, "Multipurpose Internet Mail + Extensions (MIME) Part One: Format of Internet Message + Bodies", RFC 2045, November 1996. + + [RFC2119] Bradner, S., "Key words for use in RFCs to Indicate + Requirement Levels", BCP 14, RFC 2119, March 1997. + + [RFC2279] Yergeau, F., "UTF-8, a transformation format of ISO + 10646", RFC 2279, January 1998. + + + + + +Kennedy Informational [Page 14] + +RFC 3252 Binary Lexical Octet Ad-hoc Transport 1 April 2002 + + + [RFC2460] Deering, S. and R. Hinden, "Internet Protocol, Version 6 + (IPv6) Specification", RFC 2460, December 1998. + + [RFC3080] Rose, M., "The Blocks Extensible Exchange Protocol Core", + RFC 3080, March 2001. + + [SOAP] Box, D., Ehnebuske, D., Kakivaya, G., Layman, A., + Mendelsohn, N., Nielsen, H. F., Thatte, S. Winer, D., + "Simple Object Access Protocol (SOAP) 1.1" World Wide Web + Consortium Note, May 2000 http://www.w3.org/TR/SOAP/ + + [XML] Bray, T., Paoli, J., Sperberg-McQueen, C. M., "Extensible + Markup Language (XML)" World Wide Web Consortium + Recommendation REC- xml-19980210. + http://www.w3.org/TR/1998/REC-xml-19980210 + +10. Author's Address + + Hugh Kennedy + Mimezine + 1060 West Addison + Chicago, IL 60613 + USA + + EMail: kennedyh@engin.umich.edu + + + + + + + + + + + + + + + + + + + + + + + + + + +Kennedy Informational [Page 15] + +RFC 3252 Binary Lexical Octet Ad-hoc Transport 1 April 2002 + + +11. Full Copyright Statement + + Copyright (C) The Internet Society (2002). All Rights Reserved. + + This document and translations of it may be copied and furnished to + others, and derivative works that comment on or otherwise explain it + or assist in its implementation may be prepared, copied, published + and distributed, in whole or in part, without restriction of any + kind, provided that the above copyright notice and this paragraph are + included on all such copies and derivative works. However, this + document itself may not be modified in any way, such as by removing + the copyright notice or references to the Internet Society or other + Internet organizations, except as needed for the purpose of + developing Internet standards in which case the procedures for + copyrights defined in the Internet Standards process must be + followed, or as required to translate it into languages other than + English. + + The limited permissions granted above are perpetual and will not be + revoked by the Internet Society or its successors or assigns. + + This document and the information contained herein is provided on an + "AS IS" basis and THE INTERNET SOCIETY AND THE INTERNET ENGINEERING + TASK FORCE DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING + BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE INFORMATION + HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED WARRANTIES OF + MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. + +Acknowledgement + + Funding for the RFC Editor function is currently provided by the + Internet Society. + + + + + + + + + + + + + + + + + + + +Kennedy Informational [Page 16] + + + + + + + +Network Working Group H. Kennedy +Request for Comments: 3252 Mimezine +Category: Informational 1 April 2002 + + + Binary Lexical Octet Ad-hoc Transport + +Status of this Memo + + This memo provides information for the Internet community. It does + not specify an Internet standard of any kind. Distribution of this + memo is unlimited. + +Copyright Notice + + Copyright (C) The Internet Society (2002). All Rights Reserved. + +Abstract + + This document defines a reformulation of IP and two transport layer + protocols (TCP and UDP) as XML applications. + +1. Introduction + +1.1. Overview + + This document describes the Binary Lexical Octet Ad-hoc Transport + (BLOAT): a reformulation of a widely-deployed network-layer protocol + (IP [RFC791]), and two associated transport layer protocols (TCP + [RFC793] and UDP [RFC768]) as XML [XML] applications. It also + describes methods for transporting BLOAT over Ethernet and IEEE 802 + networks as well as encapsulating BLOAT in IP for gatewaying BLOAT + across the public Internet. + +1.2. Motivation + + The wild popularity of XML as a basis for application-level protocols + such as the Blocks Extensible Exchange Protocol [RFC3080], the Simple + Object Access Protocol [SOAP], and Jabber [JABBER] prompted + investigation into the possibility of extending the use of XML in the + protocol stack. Using XML at both the transport and network layer in + addition to the application layer would provide for an amazing amount + of power and flexibility while removing dependencies on proprietary + and hard-to-understand binary protocols. This protocol unification + would also allow applications to use a single XML parser for all + aspects of their operation, eliminating developer time spent figuring + out the intricacies of each new protocol, and moving the hard work of + + + + +Kennedy Informational [Page 1] + +RFC 3252 Binary Lexical Octet Ad-hoc Transport 1 April 2002 + + + parsing to the XML toolset. The use of XML also mitigates concerns + over "network vs. host" byte ordering which is at the root of many + network application bugs. + +1.3. Relation to Existing Protocols + + The reformulations specified in this RFC follow as closely as + possible the spirit of the RFCs on which they are based, and so MAY + contain elements or attributes that would not be needed in a pure + reworking (e.g. length attributes, which are implicit in XML.) + + The layering of network and transport protocols are maintained in + this RFC despite the optimizations that could be made if the line + were somewhat blurred (i.e. merging TCP and IP into a single, larger + element in the DTD) in order to foster future use of this protocol as + a basis for reformulating other protocols (such as ICMP.) + + Other than the encoding, the behavioral aspects of each of the + existing protocols remain unchanged. Routing, address spaces, TCP + congestion control, etc. behave as specified in the extant standards. + Adapting to new standards and experimental algorithm heuristics for + improving performance will become much easier once the move to BLOAT + has been completed. + +1.4. Requirement Levels + + The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", + "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this + document are to be interpreted as described in BCP 14, RFC 2119 + [RFC2119]. + +2. IPoXML + + This protocol MUST be implemented to be compliant with this RFC. + IPoXML is the root protocol REQUIRED for effective use of TCPoXML + (section 3.) and higher-level application protocols. + + The DTD for this document type can be found in section 7.1. + + The routing of IPoXML can be easily implemented on hosts with an XML + parser, as the regular structure lends itself handily to parsing and + validation of the document/datagram and then processing the + destination address, TTL, and checksum before sending it on to its + next-hop. + + The reformulation of IPv4 was chosen over IPv6 [RFC2460] due to the + wider deployment of IPv4 and the fact that implementing IPv6 as XML + would have exceeded the 1500 byte Ethernet MTU. + + + +Kennedy Informational [Page 2] + +RFC 3252 Binary Lexical Octet Ad-hoc Transport 1 April 2002 + + + All BLOAT implementations MUST use - and specify - the UTF-8 encoding + of RFC 2279 [RFC2279]. All BLOAT document/datagrams MUST be well- + formed and include the XMLDecl. + +2.1. IP Description + + A number of items have changed (for the better) from the original IP + specification. Bit-masks, where present have been converted into + human-readable values. IP addresses are listed in their dotted- + decimal notation [RFC1123]. Length and checksum values are present + as decimal integers. + + To calculate the length and checksum fields of the IP element, a + canonicalized form of the element MUST be used. The canonical form + SHALL have no whitespace (including newline characters) between + elements and only one space character between attributes. There + SHALL NOT be a space following the last attribute in an element. + + An iterative method SHOULD be used to calculate checksums, as the + length field will vary based on the size of the checksum. + + The payload element bears special attention. Due to the character + set restrictions of XML, the payload of IP datagrams (which MAY + contain arbitrary data) MUST be encoded for transport. This RFC + REQUIRES the contents of the payload to be encoded in the base-64 + encoding of RFC 2045 [RFC2045], but removes the requirement that the + encoded output MUST be wrapped on 76-character lines. + + + + + + + + + + + + + + + + + + + + + + + + +Kennedy Informational [Page 3] + +RFC 3252 Binary Lexical Octet Ad-hoc Transport 1 April 2002 + + +2.2. Example Datagram + + The following is an example IPoXML datagram with an empty payload: + + <?xml version="1.0" encoding="UTF-8"?> + <!DOCTYPE ip PUBLIC "-//IETF//DTD BLOAT 1.0 IP//EN" "bloat.dtd"> + <ip> + <header length="474"> + <version value="4"/> + <tos precedence="Routine" delay="Normal" throughput="Normal" + relibility="Normal" reserved="0"/> + <total.length value="461"/> + <id value="1"/> + <flags reserved="0" df="dont" mf="last"/> + <offset value="0"/> + <ttl value="255"/> + <protocol value="6"/> + <checksum value="8707"/> + <source address="10.0.0.22"/> + <destination address="10.0.0.1"/> + <options> + <end copied="0" class="0" number="0"/> + </options> + <padding pad="0"/> + </header> + <payload> + </payload> + </ip> + +3. TCPoXML + + This protocol MUST be implemented to be compliant with this RFC. The + DTD for this document type can be found in section 7.2. + +3.1. TCP Description + + A number of items have changed from the original TCP specification. + Bit-masks, where present have been converted into human-readable + values. Length and checksum and port values are present as decimal + integers. + + To calculate the length and checksum fields of the TCP element, a + canonicalized form of the element MUST be used as in section 2.1. + + An iterative method SHOULD be used to calculate checksums as in + section 2.1. + + The payload element MUST be encoded as in section 2.1. + + + +Kennedy Informational [Page 4] + +RFC 3252 Binary Lexical Octet Ad-hoc Transport 1 April 2002 + + + The TCP offset element was expanded to a maximum of 255 from 16 to + allow for the increased size of the header in XML. + + TCPoXML datagrams encapsulated by IPoXML MAY omit the <?xml?> header + as well as the <!DOCTYPE> declaration. + +3.2. Example Datagram + + The following is an example TCPoXML datagram with an empty payload: + + <?xml version="1.0" encoding="UTF-8"?> + <!DOCTYPE tcp PUBLIC "-//IETF//DTD BLOAT 1.0 TCP//EN" "bloat.dtd"> + <tcp> + <tcp.header> + <src port="31415"/> + <dest port="42424"/> + <sequence number="322622954"/> + <acknowledgement number="689715995"/> + <offset number=""/> + <reserved value="0"/> + <control syn="1" ack="1"/> + <window size="1"/> + <urgent pointer="0"/> + <checksum value="2988"/> + <tcp.options> + <tcp.end kind="0"/> + </tcp.options> + <padding pad="0"/> + </tcp.header> + <payload> + </payload> + </tcp> + +4. UDPoXML + + This protocol MUST be implemented to be compliant with this RFC. The + DTD for this document type can be found in section 7.3. + +4.1. UDP Description + + A number of items have changed from the original UDP specification. + Bit-masks, where present have been converted into human-readable + values. Length and checksum and port values are present as decimal + integers. + + + + + + + +Kennedy Informational [Page 5] + +RFC 3252 Binary Lexical Octet Ad-hoc Transport 1 April 2002 + + + To calculate the length and checksum fields of the UDP element, a + canonicalized form of the element MUST be used as in section 2.1. An + iterative method SHOULD be used to calculate checksums as in section + 2.1. + + The payload element MUST be encoded as in section 2.1. + + UDPoXML datagrams encapsulated by IPoXML MAY omit the <?xml?> header + as well as the <!DOCTYPE> declaration. + +4.2. Example Datagram + + The following is an example UDPoXML datagram with an empty payload: + + <?xml version="1.0" encoding="UTF-8"?> + <!DOCTYPE udp PUBLIC "-//IETF//DTD BLOAT 1.0 UDP//EN" "bloat.dtd"> + <udp> + <udp.header> + <src port="31415"/> + <dest port="42424"/> + <udp.length value="143"/> + <checksum value="2988"/> + </udp.header> + <payload> + </payload> + </udp> + +5. Network Transport + + This document provides for the transmission of BLOAT datagrams over + two common families of physical layer transport. Future RFCs will + address additional transports as routing vendors catch up to the + specification, and we begin to see BLOAT routed across the Internet + backbone. + +5.1. Ethernet + + BLOAT is encapsulated in Ethernet datagrams as in [RFC894] with the + exception that the type field of the Ethernet frame MUST contain the + value 0xBEEF. The first 5 octets of the Ethernet frame payload will + be 0x3c 3f 78 6d 6c ("<?xml".) + +5.2. IEEE 802 + + BLOAT is encapsulated in IEEE 802 Networks as in [RFC1042] except + that the protocol type code for IPoXML is 0xBEEF. + + + + + +Kennedy Informational [Page 6] + +RFC 3252 Binary Lexical Octet Ad-hoc Transport 1 April 2002 + + +6. Gatewaying over IP + + In order to facilitate the gradual introduction of BLOAT into the + public Internet, BLOAT MAY be encapsulated in IP as in [RFC2003] to + gateway between networks that run BLOAT natively on their LANs. + +7. DTDs + + The Transport DTDs (7.2. and 7.3.) build on the definitions in the + Network DTD (7.1.) + + The DTDs are referenced by their PubidLiteral and SystemLiteral (from + [XML]) although it is understood that most IPoXML implementations + will not need to pull down the DTD, as it will normally be embedded + in the implementation, and presents something of a catch-22 if you + need to load part of your network protocol over the network. + +7.1. IPoXML DTD + + <!-- + DTD for IP over XML. + Refer to this DTD as: + + <!DOCTYPE ip PUBLIC "-//IETF//DTD BLOAT 1.0 IP//EN" "bloat.dtd"> + --> + <!-- + DTD data types: + + Digits [0..9]+ + + Precedence "NetworkControl | InternetworkControl | + CRITIC | FlashOverride | Flash | Immediate | + Priority | Routine" + + IP4Addr "dotted-decimal" notation of [RFC1123] + + Class [0..3] + + Sec "Unclassified | Confidential | EFTO | MMMM | PROG | + Restricted | Secret | Top Secret | Reserved" + + Compartments [0..65535] + + Handling [0..65535] + + TCC [0..16777216] + + --> + + + +Kennedy Informational [Page 7] + +RFC 3252 Binary Lexical Octet Ad-hoc Transport 1 April 2002 + + + <!ENTITY % Digits "CDATA"> + <!ENTITY % Precedence "CDATA"> + <!ENTITY % IP4Addr "CDATA"> + <!ENTITY % Class "CDATA"> + <!ENTITY % Sec "CDATA"> + <!ENTITY % Compartments "CDATA"> + <!ENTITY % Handling "CDATA"> + <!ENTITY % TCC "CDATA"> + + <!ELEMENT ip (header, payload)> + + <!ELEMENT header (version, tos, total.length, id, flags, offset, ttl, + protocol, checksum, source, destination, options, + padding)> + <!-- length of header in 32-bit words --> + <!ATTLIST header + length %Digits; #REQUIRED> + + <!ELEMENT version EMPTY> + <!-- ip version. SHOULD be "4" --> + <!ATTLIST version + value %Digits; #REQUIRED> + + <!ELEMENT tos EMPTY> + <!ATTLIST tos + precedence %Precedence; #REQUIRED + delay (normal | low) #REQUIRED + throughput (normal | high) #REQUIRED + relibility (normal | high) #REQUIRED + reserved CDATA #FIXED "0"> + + <!ELEMENT total.length EMPTY> + <!-- + total length of datagram (header and payload) in octets, MUST be + less than 65,535 (and SHOULD be less than 1024 for IPoXML on local + ethernets). + --> + <!ATTLIST total.length + value %Digits; #REQUIRED> + + <!ELEMENT id EMPTY> + <!-- 0 <= id <= 65,535 --> + <!ATTLIST id + value %Digits; #REQUIRED> + + <!ELEMENT flags EMPTY> + <!-- df = don't fragment, mf = more fragments --> + <!ATTLIST flags + + + +Kennedy Informational [Page 8] + +RFC 3252 Binary Lexical Octet Ad-hoc Transport 1 April 2002 + + + reserved CDATA #FIXED "0" + df (may|dont) #REQUIRED + mf (last|more) #REQUIRED> + + <!ELEMENT offset EMPTY> + <!-- 0 <= offset <= 8192 measured in 8 octet (64-bit) chunks --> + <!ATTLIST offset + value %Digits; #REQUIRED> + + <!ELEMENT ttl EMPTY> + <!-- 0 <= ttl <= 255 --> + <!ATTLIST ttl + value %Digits; #REQUIRED> + + <!ELEMENT protocol EMPTY> + <!-- 0 <= protocol <= 255 (per IANA) --> + <!ATTLIST protocol + value %Digits; #REQUIRED> + + <!ELEMENT checksum EMPTY> + <!-- 0 <= checksum <= 65535 (over header only) --> + <!ATTLIST checksum + value %Digits; #REQUIRED> + + <!ELEMENT source EMPTY> + <!ATTLIST source + address %IP4Addr; #REQUIRED> + + <!ELEMENT destination EMPTY> + <!ATTLIST destination + address %IP4Addr; #REQUIRED> + + <!ELEMENT options ( end | noop | security | loose | strict | record + | stream | timestamp )*> + + <!ELEMENT end EMPTY> + <!ATTLIST end + copied (0|1) #REQUIRED + class CDATA #FIXED "0" + number CDATA #FIXED "0"> + + <!ELEMENT noop EMPTY> + <!ATTLIST noop + copied (0|1) #REQUIRED + class CDATA #FIXED "0" + number CDATA #FIXED "1"> + + <!ELEMENT security EMPTY> + + + +Kennedy Informational [Page 9] + +RFC 3252 Binary Lexical Octet Ad-hoc Transport 1 April 2002 + + + <!ATTLIST security + copied CDATA #FIXED "1" + class CDATA #FIXED "0" + number CDATA #FIXED "2" + length CDATA #FIXED "11" + security %Sec; #REQUIRED + compartments %Compartments; #REQUIRED + handling %Handling; #REQUIRED + tcc %TCC; #REQUIRED> + <!ELEMENT loose (hop)+> + <!ATTLIST loose + copied CDATA #FIXED "1" + class CDATA #FIXED "0" + number CDATA #FIXED "3" + length %Digits; #REQUIRED + pointer %Digits; #REQUIRED> + + <!ELEMENT hop EMPTY> + <!ATTLIST hop + address %IP4Addr; #REQUIRED> + + <!ELEMENT strict (hop)+> + <!ATTLIST strict + copied CDATA #FIXED "1" + class CDATA #FIXED "0" + number CDATA #FIXED "9" + length %Digits; #REQUIRED + pointer %Digits; #REQUIRED> + + <!ELEMENT record (hop)+> + <!ATTLIST record + copied CDATA #FIXED "0" + class CDATA #FIXED "0" + number CDATA #FIXED "7" + length %Digits; #REQUIRED + pointer %Digits; #REQUIRED> + + <!ELEMENT stream EMPTY> + <!-- 0 <= id <= 65,535 --> + <!ATTLIST stream + copied CDATA #FIXED "1" + class CDATA #FIXED "0" + number CDATA #FIXED "8" + length CDATA #FIXED "4" + id %Digits; #REQUIRED> + + <!ELEMENT timestamp (tstamp)+> + <!-- 0 <= oflw <=15 --> + + + +Kennedy Informational [Page 10] + +RFC 3252 Binary Lexical Octet Ad-hoc Transport 1 April 2002 + + + <!ATTLIST timestamp + copied CDATA #FIXED "0" + class CDATA #FIXED "2" + number CDATA #FIXED "4" + length %Digits; #REQUIRED + pointer %Digits; #REQUIRED + oflw %Digits; #REQUIRED + flag (0 | 1 | 3) #REQUIRED> + + <!ELEMENT tstamp EMPTY> + <!ATTLIST tstamp + time %Digits; #REQUIRED + address %IP4Addr; #IMPLIED> + <!-- + padding to bring header to 32-bit boundary. + pad MUST be "0"* + --> + <!ELEMENT padding EMPTY> + <!ATTLIST padding + pad CDATA #REQUIRED> + + <!-- payload MUST be encoded as base-64 [RFC2045], as modified + by section 2.1 of this RFC --> + <!ELEMENT payload (CDATA)> + +7.2. TCPoXML DTD + + <!-- + DTD for TCP over XML. + Refer to this DTD as: + + <!DOCTYPE tcp PUBLIC "-//IETF//DTD BLOAT 1.0 TCP//EN" "bloat.dtd"> + --> + + <!-- the pseudoheader is only included for checksum calculations --> + <!ELEMENT tcp (tcp.pseudoheader?, tcp.header, payload)> + + <!ELEMENT tcp.header (src, dest, sequence, acknowledgement, offset, + reserved, control, window, checksum, urgent, + tcp.options, padding)> + + <!ELEMENT src EMPTY> + <!-- 0 <= port <= 65,535 --> + <!ATTLIST src + port %Digits; #REQUIRED> + + <!ELEMENT dest EMPTY> + <!-- 0 <= port <= 65,535 --> + + + +Kennedy Informational [Page 11] + +RFC 3252 Binary Lexical Octet Ad-hoc Transport 1 April 2002 + + + <!ATTLIST dest + port %Digits; #REQUIRED> + + <!ELEMENT sequence EMPTY> + <!-- 0 <= number <= 4294967295 --> + <!ATTLIST sequence + number %Digits; #REQUIRED> + + <!ELEMENT acknowledgement EMPTY> + <!-- 0 <= number <= 4294967295 --> + <!ATTLIST acknowledgement + number %Digits; #REQUIRED> + + <!ELEMENT offset EMPTY> + <!-- 0 <= number <= 255 --> + <!ATTLIST offset + number %Digits; #REQUIRED> + + <!ELEMENT reserved EMPTY> + <!ATTLIST reserved + value CDATA #FIXED "0"> + + <!ELEMENT control EMPTY> + <!ATTLIST control + urg (0|1) #IMPLIED + ack (0|1) #IMPLIED + psh (0|1) #IMPLIED + rst (0|1) #IMPLIED + syn (0|1) #IMPLIED + fin (0|1) #IMPLIED> + + <!ELEMENT window EMPTY> + <!-- 0 <= size <= 65,535 --> + <!ATTLIST window + size %Digits; #REQUIRED> + + <!-- + checksum as in ip, but with + the following pseudo-header added into the tcp element: + --> + <!ELEMENT tcp.pseudoheader (source, destination, protocol, + tcp.length)> + + <!-- + tcp header + data length in octets. does not include the size of + + the pseudoheader. + --> + + + +Kennedy Informational [Page 12] + +RFC 3252 Binary Lexical Octet Ad-hoc Transport 1 April 2002 + + + <!ELEMENT tcp.length EMPTY> + <!ATTLIST tcp.length + value %Digits; #REQUIRED> + + <!ELEMENT urgent EMPTY> + <!-- 0 <= pointer <= 65,535 --> + <!ATTLIST urgent + pointer %Digits; #REQUIRED> + + <!ELEMENT tcp.options (tcp.end | tcp.noop | tcp.mss)+> + + <!ELEMENT tcp.end EMPTY> + <!ATTLIST tcp.end + kind CDATA #FIXED "0"> + + <!ELEMENT tcp.noop EMPTY> + <!ATTLIST tcp.noop + kind CDATA #FIXED "1"> + + <!ELEMENT tcp.mss EMPTY> + <!ATTLIST tcp.mss + kind CDATA #FIXED "2" + length CDATA #FIXED "4" + size %Digits; #REQUIRED> + +7.3. UDPoXML DTD + + <!-- + DTD for UDP over XML. + Refer to this DTD as: + + <!DOCTYPE udp PUBLIC "-//IETF//DTD BLOAT 1.0 UDP//EN" "bloat.dtd"> + --> + + <!ELEMENT udp (udp.pseudoheader?, udp.header, payload)> + + <!ELEMENT udp.header (src, dest, udp.length, checksum)> + + <!ELEMENT udp.pseudoheader (source, destination, protocol, + udp.length)> + + <!-- + udp header + data length in octets. does not include the size of + the pseudoheader. + --> + <!ELEMENT udp.length EMPTY> + <!ATTLIST udp.length + value %Digits; #REQUIRED> + + + +Kennedy Informational [Page 13] + +RFC 3252 Binary Lexical Octet Ad-hoc Transport 1 April 2002 + + +8. Security Considerations + + XML, as a subset of SGML, has the same security considerations as + specified in SGML Media Types [RFC1874]. Security considerations + that apply to IP, TCP and UDP also likely apply to BLOAT as it does + not attempt to correct for issues not related to message format. + +9. References + + [JABBER] Miller, J., "Jabber", draft-miller-jabber-00.txt, + February 2002. (Work in Progress) + + [RFC768] Postel, J., "User Datagram Protocol", STD 6, RFC 768, + August 1980. + + [RFC791] Postel, J., "Internet Protocol", STD 5, RFC 791, + September 1981. + + [RFC793] Postel, J., "Transmission Control Protocol", STD 7, RFC + 793, September 1981. + + [RFC894] Hornig, C., "Standard for the Transmission of IP + Datagrams over Ethernet Networks.", RFC 894, April 1984. + + [RFC1042] Postel, J. and J. Reynolds, "Standard for the + Transmission of IP Datagrams Over IEEE 802 Networks", STD + 43, RFC 1042, February 1988. + + [RFC1123] Braden, R., "Requirements for Internet Hosts - + Application and Support", RFC 1123, October 1989. + + [RFC1874] Levinson, E., "SGML Media Types", RFC 1874, December + 1995. + + [RFC2003] Perkins, C., "IP Encapsulation within IP", RFC 2003, + October 1996. + + [RFC2045] Freed, N. and N. Borenstein, "Multipurpose Internet Mail + Extensions (MIME) Part One: Format of Internet Message + Bodies", RFC 2045, November 1996. + + [RFC2119] Bradner, S., "Key words for use in RFCs to Indicate + Requirement Levels", BCP 14, RFC 2119, March 1997. + + [RFC2279] Yergeau, F., "UTF-8, a transformation format of ISO + 10646", RFC 2279, January 1998. + + + + + +Kennedy Informational [Page 14] + +RFC 3252 Binary Lexical Octet Ad-hoc Transport 1 April 2002 + + + [RFC2460] Deering, S. and R. Hinden, "Internet Protocol, Version 6 + (IPv6) Specification", RFC 2460, December 1998. + + [RFC3080] Rose, M., "The Blocks Extensible Exchange Protocol Core", + RFC 3080, March 2001. + + [SOAP] Box, D., Ehnebuske, D., Kakivaya, G., Layman, A., + Mendelsohn, N., Nielsen, H. F., Thatte, S. Winer, D., + "Simple Object Access Protocol (SOAP) 1.1" World Wide Web + Consortium Note, May 2000 http://www.w3.org/TR/SOAP/ + + [XML] Bray, T., Paoli, J., Sperberg-McQueen, C. M., "Extensible + Markup Language (XML)" World Wide Web Consortium + Recommendation REC- xml-19980210. + http://www.w3.org/TR/1998/REC-xml-19980210 + +10. Author's Address + + Hugh Kennedy + Mimezine + 1060 West Addison + Chicago, IL 60613 + USA + + EMail: kennedyh@engin.umich.edu + + + + + + + + + + + + + + + + + + + + + + + + + + +Kennedy Informational [Page 15] + +RFC 3252 Binary Lexical Octet Ad-hoc Transport 1 April 2002 + + +11. Full Copyright Statement + + Copyright (C) The Internet Society (2002). All Rights Reserved. + + This document and translations of it may be copied and furnished to + others, and derivative works that comment on or otherwise explain it + or assist in its implementation may be prepared, copied, published + and distributed, in whole or in part, without restriction of any + kind, provided that the above copyright notice and this paragraph are + included on all such copies and derivative works. However, this + document itself may not be modified in any way, such as by removing + the copyright notice or references to the Internet Society or other + Internet organizations, except as needed for the purpose of + developing Internet standards in which case the procedures for + copyrights defined in the Internet Standards process must be + followed, or as required to translate it into languages other than + English. + + The limited permissions granted above are perpetual and will not be + revoked by the Internet Society or its successors or assigns. + + This document and the information contained herein is provided on an + "AS IS" basis and THE INTERNET SOCIETY AND THE INTERNET ENGINEERING + TASK FORCE DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING + BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE INFORMATION + HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED WARRANTIES OF + MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. + +Acknowledgement + + Funding for the RFC Editor function is currently provided by the + Internet Society. + + + + + + + + + + + + + + + + + + + +Kennedy Informational [Page 16] + + + + + + + +Network Working Group H. Kennedy +Request for Comments: 3252 Mimezine +Category: Informational 1 April 2002 + + + Binary Lexical Octet Ad-hoc Transport + +Status of this Memo + + This memo provides information for the Internet community. It does + not specify an Internet standard of any kind. Distribution of this + memo is unlimited. + +Copyright Notice + + Copyright (C) The Internet Society (2002). All Rights Reserved. + +Abstract + + This document defines a reformulation of IP and two transport layer + protocols (TCP and UDP) as XML applications. + +1. Introduction + +1.1. Overview + + This document describes the Binary Lexical Octet Ad-hoc Transport + (BLOAT): a reformulation of a widely-deployed network-layer protocol + (IP [RFC791]), and two associated transport layer protocols (TCP + [RFC793] and UDP [RFC768]) as XML [XML] applications. It also + describes methods for transporting BLOAT over Ethernet and IEEE 802 + networks as well as encapsulating BLOAT in IP for gatewaying BLOAT + across the public Internet. + +1.2. Motivation + + The wild popularity of XML as a basis for application-level protocols + such as the Blocks Extensible Exchange Protocol [RFC3080], the Simple + Object Access Protocol [SOAP], and Jabber [JABBER] prompted + investigation into the possibility of extending the use of XML in the + protocol stack. Using XML at both the transport and network layer in + addition to the application layer would provide for an amazing amount + of power and flexibility while removing dependencies on proprietary + and hard-to-understand binary protocols. This protocol unification + would also allow applications to use a single XML parser for all + aspects of their operation, eliminating developer time spent figuring + out the intricacies of each new protocol, and moving the hard work of + + + + +Kennedy Informational [Page 1] + +RFC 3252 Binary Lexical Octet Ad-hoc Transport 1 April 2002 + + + parsing to the XML toolset. The use of XML also mitigates concerns + over "network vs. host" byte ordering which is at the root of many + network application bugs. + +1.3. Relation to Existing Protocols + + The reformulations specified in this RFC follow as closely as + possible the spirit of the RFCs on which they are based, and so MAY + contain elements or attributes that would not be needed in a pure + reworking (e.g. length attributes, which are implicit in XML.) + + The layering of network and transport protocols are maintained in + this RFC despite the optimizations that could be made if the line + were somewhat blurred (i.e. merging TCP and IP into a single, larger + element in the DTD) in order to foster future use of this protocol as + a basis for reformulating other protocols (such as ICMP.) + + Other than the encoding, the behavioral aspects of each of the + existing protocols remain unchanged. Routing, address spaces, TCP + congestion control, etc. behave as specified in the extant standards. + Adapting to new standards and experimental algorithm heuristics for + improving performance will become much easier once the move to BLOAT + has been completed. + +1.4. Requirement Levels + + The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", + "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this + document are to be interpreted as described in BCP 14, RFC 2119 + [RFC2119]. + +2. IPoXML + + This protocol MUST be implemented to be compliant with this RFC. + IPoXML is the root protocol REQUIRED for effective use of TCPoXML + (section 3.) and higher-level application protocols. + + The DTD for this document type can be found in section 7.1. + + The routing of IPoXML can be easily implemented on hosts with an XML + parser, as the regular structure lends itself handily to parsing and + validation of the document/datagram and then processing the + destination address, TTL, and checksum before sending it on to its + next-hop. + + The reformulation of IPv4 was chosen over IPv6 [RFC2460] due to the + wider deployment of IPv4 and the fact that implementing IPv6 as XML + would have exceeded the 1500 byte Ethernet MTU. + + + +Kennedy Informational [Page 2] + +RFC 3252 Binary Lexical Octet Ad-hoc Transport 1 April 2002 + + + All BLOAT implementations MUST use - and specify - the UTF-8 encoding + of RFC 2279 [RFC2279]. All BLOAT document/datagrams MUST be well- + formed and include the XMLDecl. + +2.1. IP Description + + A number of items have changed (for the better) from the original IP + specification. Bit-masks, where present have been converted into + human-readable values. IP addresses are listed in their dotted- + decimal notation [RFC1123]. Length and checksum values are present + as decimal integers. + + To calculate the length and checksum fields of the IP element, a + canonicalized form of the element MUST be used. The canonical form + SHALL have no whitespace (including newline characters) between + elements and only one space character between attributes. There + SHALL NOT be a space following the last attribute in an element. + + An iterative method SHOULD be used to calculate checksums, as the + length field will vary based on the size of the checksum. + + The payload element bears special attention. Due to the character + set restrictions of XML, the payload of IP datagrams (which MAY + contain arbitrary data) MUST be encoded for transport. This RFC + REQUIRES the contents of the payload to be encoded in the base-64 + encoding of RFC 2045 [RFC2045], but removes the requirement that the + encoded output MUST be wrapped on 76-character lines. + + + + + + + + + + + + + + + + + + + + + + + + +Kennedy Informational [Page 3] + +RFC 3252 Binary Lexical Octet Ad-hoc Transport 1 April 2002 + + +2.2. Example Datagram + + The following is an example IPoXML datagram with an empty payload: + + <?xml version="1.0" encoding="UTF-8"?> + <!DOCTYPE ip PUBLIC "-//IETF//DTD BLOAT 1.0 IP//EN" "bloat.dtd"> + <ip> + <header length="474"> + <version value="4"/> + <tos precedence="Routine" delay="Normal" throughput="Normal" + relibility="Normal" reserved="0"/> + <total.length value="461"/> + <id value="1"/> + <flags reserved="0" df="dont" mf="last"/> + <offset value="0"/> + <ttl value="255"/> + <protocol value="6"/> + <checksum value="8707"/> + <source address="10.0.0.22"/> + <destination address="10.0.0.1"/> + <options> + <end copied="0" class="0" number="0"/> + </options> + <padding pad="0"/> + </header> + <payload> + </payload> + </ip> + +3. TCPoXML + + This protocol MUST be implemented to be compliant with this RFC. The + DTD for this document type can be found in section 7.2. + +3.1. TCP Description + + A number of items have changed from the original TCP specification. + Bit-masks, where present have been converted into human-readable + values. Length and checksum and port values are present as decimal + integers. + + To calculate the length and checksum fields of the TCP element, a + canonicalized form of the element MUST be used as in section 2.1. + + An iterative method SHOULD be used to calculate checksums as in + section 2.1. + + The payload element MUST be encoded as in section 2.1. + + + +Kennedy Informational [Page 4] + +RFC 3252 Binary Lexical Octet Ad-hoc Transport 1 April 2002 + + + The TCP offset element was expanded to a maximum of 255 from 16 to + allow for the increased size of the header in XML. + + TCPoXML datagrams encapsulated by IPoXML MAY omit the <?xml?> header + as well as the <!DOCTYPE> declaration. + +3.2. Example Datagram + + The following is an example TCPoXML datagram with an empty payload: + + <?xml version="1.0" encoding="UTF-8"?> + <!DOCTYPE tcp PUBLIC "-//IETF//DTD BLOAT 1.0 TCP//EN" "bloat.dtd"> + <tcp> + <tcp.header> + <src port="31415"/> + <dest port="42424"/> + <sequence number="322622954"/> + <acknowledgement number="689715995"/> + <offset number=""/> + <reserved value="0"/> + <control syn="1" ack="1"/> + <window size="1"/> + <urgent pointer="0"/> + <checksum value="2988"/> + <tcp.options> + <tcp.end kind="0"/> + </tcp.options> + <padding pad="0"/> + </tcp.header> + <payload> + </payload> + </tcp> + +4. UDPoXML + + This protocol MUST be implemented to be compliant with this RFC. The + DTD for this document type can be found in section 7.3. + +4.1. UDP Description + + A number of items have changed from the original UDP specification. + Bit-masks, where present have been converted into human-readable + values. Length and checksum and port values are present as decimal + integers. + + + + + + + +Kennedy Informational [Page 5] + +RFC 3252 Binary Lexical Octet Ad-hoc Transport 1 April 2002 + + + To calculate the length and checksum fields of the UDP element, a + canonicalized form of the element MUST be used as in section 2.1. An + iterative method SHOULD be used to calculate checksums as in section + 2.1. + + The payload element MUST be encoded as in section 2.1. + + UDPoXML datagrams encapsulated by IPoXML MAY omit the <?xml?> header + as well as the <!DOCTYPE> declaration. + +4.2. Example Datagram + + The following is an example UDPoXML datagram with an empty payload: + + <?xml version="1.0" encoding="UTF-8"?> + <!DOCTYPE udp PUBLIC "-//IETF//DTD BLOAT 1.0 UDP//EN" "bloat.dtd"> + <udp> + <udp.header> + <src port="31415"/> + <dest port="42424"/> + <udp.length value="143"/> + <checksum value="2988"/> + </udp.header> + <payload> + </payload> + </udp> + +5. Network Transport + + This document provides for the transmission of BLOAT datagrams over + two common families of physical layer transport. Future RFCs will + address additional transports as routing vendors catch up to the + specification, and we begin to see BLOAT routed across the Internet + backbone. + +5.1. Ethernet + + BLOAT is encapsulated in Ethernet datagrams as in [RFC894] with the + exception that the type field of the Ethernet frame MUST contain the + value 0xBEEF. The first 5 octets of the Ethernet frame payload will + be 0x3c 3f 78 6d 6c ("<?xml".) + +5.2. IEEE 802 + + BLOAT is encapsulated in IEEE 802 Networks as in [RFC1042] except + that the protocol type code for IPoXML is 0xBEEF. + + + + + +Kennedy Informational [Page 6] + +RFC 3252 Binary Lexical Octet Ad-hoc Transport 1 April 2002 + + +6. Gatewaying over IP + + In order to facilitate the gradual introduction of BLOAT into the + public Internet, BLOAT MAY be encapsulated in IP as in [RFC2003] to + gateway between networks that run BLOAT natively on their LANs. + +7. DTDs + + The Transport DTDs (7.2. and 7.3.) build on the definitions in the + Network DTD (7.1.) + + The DTDs are referenced by their PubidLiteral and SystemLiteral (from + [XML]) although it is understood that most IPoXML implementations + will not need to pull down the DTD, as it will normally be embedded + in the implementation, and presents something of a catch-22 if you + need to load part of your network protocol over the network. + +7.1. IPoXML DTD + + <!-- + DTD for IP over XML. + Refer to this DTD as: + + <!DOCTYPE ip PUBLIC "-//IETF//DTD BLOAT 1.0 IP//EN" "bloat.dtd"> + --> + <!-- + DTD data types: + + Digits [0..9]+ + + Precedence "NetworkControl | InternetworkControl | + CRITIC | FlashOverride | Flash | Immediate | + Priority | Routine" + + IP4Addr "dotted-decimal" notation of [RFC1123] + + Class [0..3] + + Sec "Unclassified | Confidential | EFTO | MMMM | PROG | + Restricted | Secret | Top Secret | Reserved" + + Compartments [0..65535] + + Handling [0..65535] + + TCC [0..16777216] + + --> + + + +Kennedy Informational [Page 7] + +RFC 3252 Binary Lexical Octet Ad-hoc Transport 1 April 2002 + + + <!ENTITY % Digits "CDATA"> + <!ENTITY % Precedence "CDATA"> + <!ENTITY % IP4Addr "CDATA"> + <!ENTITY % Class "CDATA"> + <!ENTITY % Sec "CDATA"> + <!ENTITY % Compartments "CDATA"> + <!ENTITY % Handling "CDATA"> + <!ENTITY % TCC "CDATA"> + + <!ELEMENT ip (header, payload)> + + <!ELEMENT header (version, tos, total.length, id, flags, offset, ttl, + protocol, checksum, source, destination, options, + padding)> + <!-- length of header in 32-bit words --> + <!ATTLIST header + length %Digits; #REQUIRED> + + <!ELEMENT version EMPTY> + <!-- ip version. SHOULD be "4" --> + <!ATTLIST version + value %Digits; #REQUIRED> + + <!ELEMENT tos EMPTY> + <!ATTLIST tos + precedence %Precedence; #REQUIRED + delay (normal | low) #REQUIRED + throughput (normal | high) #REQUIRED + relibility (normal | high) #REQUIRED + reserved CDATA #FIXED "0"> + + <!ELEMENT total.length EMPTY> + <!-- + total length of datagram (header and payload) in octets, MUST be + less than 65,535 (and SHOULD be less than 1024 for IPoXML on local + ethernets). + --> + <!ATTLIST total.length + value %Digits; #REQUIRED> + + <!ELEMENT id EMPTY> + <!-- 0 <= id <= 65,535 --> + <!ATTLIST id + value %Digits; #REQUIRED> + + <!ELEMENT flags EMPTY> + <!-- df = don't fragment, mf = more fragments --> + <!ATTLIST flags + + + +Kennedy Informational [Page 8] + +RFC 3252 Binary Lexical Octet Ad-hoc Transport 1 April 2002 + + + reserved CDATA #FIXED "0" + df (may|dont) #REQUIRED + mf (last|more) #REQUIRED> + + <!ELEMENT offset EMPTY> + <!-- 0 <= offset <= 8192 measured in 8 octet (64-bit) chunks --> + <!ATTLIST offset + value %Digits; #REQUIRED> + + <!ELEMENT ttl EMPTY> + <!-- 0 <= ttl <= 255 --> + <!ATTLIST ttl + value %Digits; #REQUIRED> + + <!ELEMENT protocol EMPTY> + <!-- 0 <= protocol <= 255 (per IANA) --> + <!ATTLIST protocol + value %Digits; #REQUIRED> + + <!ELEMENT checksum EMPTY> + <!-- 0 <= checksum <= 65535 (over header only) --> + <!ATTLIST checksum + value %Digits; #REQUIRED> + + <!ELEMENT source EMPTY> + <!ATTLIST source + address %IP4Addr; #REQUIRED> + + <!ELEMENT destination EMPTY> + <!ATTLIST destination + address %IP4Addr; #REQUIRED> + + <!ELEMENT options ( end | noop | security | loose | strict | record + | stream | timestamp )*> + + <!ELEMENT end EMPTY> + <!ATTLIST end + copied (0|1) #REQUIRED + class CDATA #FIXED "0" + number CDATA #FIXED "0"> + + <!ELEMENT noop EMPTY> + <!ATTLIST noop + copied (0|1) #REQUIRED + class CDATA #FIXED "0" + number CDATA #FIXED "1"> + + <!ELEMENT security EMPTY> + + + +Kennedy Informational [Page 9] + +RFC 3252 Binary Lexical Octet Ad-hoc Transport 1 April 2002 + + + <!ATTLIST security + copied CDATA #FIXED "1" + class CDATA #FIXED "0" + number CDATA #FIXED "2" + length CDATA #FIXED "11" + security %Sec; #REQUIRED + compartments %Compartments; #REQUIRED + handling %Handling; #REQUIRED + tcc %TCC; #REQUIRED> + <!ELEMENT loose (hop)+> + <!ATTLIST loose + copied CDATA #FIXED "1" + class CDATA #FIXED "0" + number CDATA #FIXED "3" + length %Digits; #REQUIRED + pointer %Digits; #REQUIRED> + + <!ELEMENT hop EMPTY> + <!ATTLIST hop + address %IP4Addr; #REQUIRED> + + <!ELEMENT strict (hop)+> + <!ATTLIST strict + copied CDATA #FIXED "1" + class CDATA #FIXED "0" + number CDATA #FIXED "9" + length %Digits; #REQUIRED + pointer %Digits; #REQUIRED> + + <!ELEMENT record (hop)+> + <!ATTLIST record + copied CDATA #FIXED "0" + class CDATA #FIXED "0" + number CDATA #FIXED "7" + length %Digits; #REQUIRED + pointer %Digits; #REQUIRED> + + <!ELEMENT stream EMPTY> + <!-- 0 <= id <= 65,535 --> + <!ATTLIST stream + copied CDATA #FIXED "1" + class CDATA #FIXED "0" + number CDATA #FIXED "8" + length CDATA #FIXED "4" + id %Digits; #REQUIRED> + + <!ELEMENT timestamp (tstamp)+> + <!-- 0 <= oflw <=15 --> + + + +Kennedy Informational [Page 10] + +RFC 3252 Binary Lexical Octet Ad-hoc Transport 1 April 2002 + + + <!ATTLIST timestamp + copied CDATA #FIXED "0" + class CDATA #FIXED "2" + number CDATA #FIXED "4" + length %Digits; #REQUIRED + pointer %Digits; #REQUIRED + oflw %Digits; #REQUIRED + flag (0 | 1 | 3) #REQUIRED> + + <!ELEMENT tstamp EMPTY> + <!ATTLIST tstamp + time %Digits; #REQUIRED + address %IP4Addr; #IMPLIED> + <!-- + padding to bring header to 32-bit boundary. + pad MUST be "0"* + --> + <!ELEMENT padding EMPTY> + <!ATTLIST padding + pad CDATA #REQUIRED> + + <!-- payload MUST be encoded as base-64 [RFC2045], as modified + by section 2.1 of this RFC --> + <!ELEMENT payload (CDATA)> + +7.2. TCPoXML DTD + + <!-- + DTD for TCP over XML. + Refer to this DTD as: + + <!DOCTYPE tcp PUBLIC "-//IETF//DTD BLOAT 1.0 TCP//EN" "bloat.dtd"> + --> + + <!-- the pseudoheader is only included for checksum calculations --> + <!ELEMENT tcp (tcp.pseudoheader?, tcp.header, payload)> + + <!ELEMENT tcp.header (src, dest, sequence, acknowledgement, offset, + reserved, control, window, checksum, urgent, + tcp.options, padding)> + + <!ELEMENT src EMPTY> + <!-- 0 <= port <= 65,535 --> + <!ATTLIST src + port %Digits; #REQUIRED> + + <!ELEMENT dest EMPTY> + <!-- 0 <= port <= 65,535 --> + + + +Kennedy Informational [Page 11] + +RFC 3252 Binary Lexical Octet Ad-hoc Transport 1 April 2002 + + + <!ATTLIST dest + port %Digits; #REQUIRED> + + <!ELEMENT sequence EMPTY> + <!-- 0 <= number <= 4294967295 --> + <!ATTLIST sequence + number %Digits; #REQUIRED> + + <!ELEMENT acknowledgement EMPTY> + <!-- 0 <= number <= 4294967295 --> + <!ATTLIST acknowledgement + number %Digits; #REQUIRED> + + <!ELEMENT offset EMPTY> + <!-- 0 <= number <= 255 --> + <!ATTLIST offset + number %Digits; #REQUIRED> + + <!ELEMENT reserved EMPTY> + <!ATTLIST reserved + value CDATA #FIXED "0"> + + <!ELEMENT control EMPTY> + <!ATTLIST control + urg (0|1) #IMPLIED + ack (0|1) #IMPLIED + psh (0|1) #IMPLIED + rst (0|1) #IMPLIED + syn (0|1) #IMPLIED + fin (0|1) #IMPLIED> + + <!ELEMENT window EMPTY> + <!-- 0 <= size <= 65,535 --> + <!ATTLIST window + size %Digits; #REQUIRED> + + <!-- + checksum as in ip, but with + the following pseudo-header added into the tcp element: + --> + <!ELEMENT tcp.pseudoheader (source, destination, protocol, + tcp.length)> + + <!-- + tcp header + data length in octets. does not include the size of + + the pseudoheader. + --> + + + +Kennedy Informational [Page 12] + +RFC 3252 Binary Lexical Octet Ad-hoc Transport 1 April 2002 + + + <!ELEMENT tcp.length EMPTY> + <!ATTLIST tcp.length + value %Digits; #REQUIRED> + + <!ELEMENT urgent EMPTY> + <!-- 0 <= pointer <= 65,535 --> + <!ATTLIST urgent + pointer %Digits; #REQUIRED> + + <!ELEMENT tcp.options (tcp.end | tcp.noop | tcp.mss)+> + + <!ELEMENT tcp.end EMPTY> + <!ATTLIST tcp.end + kind CDATA #FIXED "0"> + + <!ELEMENT tcp.noop EMPTY> + <!ATTLIST tcp.noop + kind CDATA #FIXED "1"> + + <!ELEMENT tcp.mss EMPTY> + <!ATTLIST tcp.mss + kind CDATA #FIXED "2" + length CDATA #FIXED "4" + size %Digits; #REQUIRED> + +7.3. UDPoXML DTD + + <!-- + DTD for UDP over XML. + Refer to this DTD as: + + <!DOCTYPE udp PUBLIC "-//IETF//DTD BLOAT 1.0 UDP//EN" "bloat.dtd"> + --> + + <!ELEMENT udp (udp.pseudoheader?, udp.header, payload)> + + <!ELEMENT udp.header (src, dest, udp.length, checksum)> + + <!ELEMENT udp.pseudoheader (source, destination, protocol, + udp.length)> + + <!-- + udp header + data length in octets. does not include the size of + the pseudoheader. + --> + <!ELEMENT udp.length EMPTY> + <!ATTLIST udp.length + value %Digits; #REQUIRED> + + + +Kennedy Informational [Page 13] + +RFC 3252 Binary Lexical Octet Ad-hoc Transport 1 April 2002 + + +8. Security Considerations + + XML, as a subset of SGML, has the same security considerations as + specified in SGML Media Types [RFC1874]. Security considerations + that apply to IP, TCP and UDP also likely apply to BLOAT as it does + not attempt to correct for issues not related to message format. + +9. References + + [JABBER] Miller, J., "Jabber", draft-miller-jabber-00.txt, + February 2002. (Work in Progress) + + [RFC768] Postel, J., "User Datagram Protocol", STD 6, RFC 768, + August 1980. + + [RFC791] Postel, J., "Internet Protocol", STD 5, RFC 791, + September 1981. + + [RFC793] Postel, J., "Transmission Control Protocol", STD 7, RFC + 793, September 1981. + + [RFC894] Hornig, C., "Standard for the Transmission of IP + Datagrams over Ethernet Networks.", RFC 894, April 1984. + + [RFC1042] Postel, J. and J. Reynolds, "Standard for the + Transmission of IP Datagrams Over IEEE 802 Networks", STD + 43, RFC 1042, February 1988. + + [RFC1123] Braden, R., "Requirements for Internet Hosts - + Application and Support", RFC 1123, October 1989. + + [RFC1874] Levinson, E., "SGML Media Types", RFC 1874, December + 1995. + + [RFC2003] Perkins, C., "IP Encapsulation within IP", RFC 2003, + October 1996. + + [RFC2045] Freed, N. and N. Borenstein, "Multipurpose Internet Mail + Extensions (MIME) Part One: Format of Internet Message + Bodies", RFC 2045, November 1996. + + [RFC2119] Bradner, S., "Key words for use in RFCs to Indicate + Requirement Levels", BCP 14, RFC 2119, March 1997. + + [RFC2279] Yergeau, F., "UTF-8, a transformation format of ISO + 10646", RFC 2279, January 1998. + + + + + +Kennedy Informational [Page 14] + +RFC 3252 Binary Lexical Octet Ad-hoc Transport 1 April 2002 + + + [RFC2460] Deering, S. and R. Hinden, "Internet Protocol, Version 6 + (IPv6) Specification", RFC 2460, December 1998. + + [RFC3080] Rose, M., "The Blocks Extensible Exchange Protocol Core", + RFC 3080, March 2001. + + [SOAP] Box, D., Ehnebuske, D., Kakivaya, G., Layman, A., + Mendelsohn, N., Nielsen, H. F., Thatte, S. Winer, D., + "Simple Object Access Protocol (SOAP) 1.1" World Wide Web + Consortium Note, May 2000 http://www.w3.org/TR/SOAP/ + + [XML] Bray, T., Paoli, J., Sperberg-McQueen, C. M., "Extensible + Markup Language (XML)" World Wide Web Consortium + Recommendation REC- xml-19980210. + http://www.w3.org/TR/1998/REC-xml-19980210 + +10. Author's Address + + Hugh Kennedy + Mimezine + 1060 West Addison + Chicago, IL 60613 + USA + + EMail: kennedyh@engin.umich.edu + + + + + + + + + + + + + + + + + + + + + + + + + + +Kennedy Informational [Page 15] + +RFC 3252 Binary Lexical Octet Ad-hoc Transport 1 April 2002 + + +11. Full Copyright Statement + + Copyright (C) The Internet Society (2002). All Rights Reserved. + + This document and translations of it may be copied and furnished to + others, and derivative works that comment on or otherwise explain it + or assist in its implementation may be prepared, copied, published + and distributed, in whole or in part, without restriction of any + kind, provided that the above copyright notice and this paragraph are + included on all such copies and derivative works. However, this + document itself may not be modified in any way, such as by removing + the copyright notice or references to the Internet Society or other + Internet organizations, except as needed for the purpose of + developing Internet standards in which case the procedures for + copyrights defined in the Internet Standards process must be + followed, or as required to translate it into languages other than + English. + + The limited permissions granted above are perpetual and will not be + revoked by the Internet Society or its successors or assigns. + + This document and the information contained herein is provided on an + "AS IS" basis and THE INTERNET SOCIETY AND THE INTERNET ENGINEERING + TASK FORCE DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING + BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE INFORMATION + HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED WARRANTIES OF + MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. + +Acknowledgement + + Funding for the RFC Editor function is currently provided by the + Internet Society. + + + + + + + + + + + + + + + + + + + +Kennedy Informational [Page 16] + + + + + + + +Network Working Group H. Kennedy +Request for Comments: 3252 Mimezine +Category: Informational 1 April 2002 + + + Binary Lexical Octet Ad-hoc Transport + +Status of this Memo + + This memo provides information for the Internet community. It does + not specify an Internet standard of any kind. Distribution of this + memo is unlimited. + +Copyright Notice + + Copyright (C) The Internet Society (2002). All Rights Reserved. + +Abstract + + This document defines a reformulation of IP and two transport layer + protocols (TCP and UDP) as XML applications. + +1. Introduction + +1.1. Overview + + This document describes the Binary Lexical Octet Ad-hoc Transport + (BLOAT): a reformulation of a widely-deployed network-layer protocol + (IP [RFC791]), and two associated transport layer protocols (TCP + [RFC793] and UDP [RFC768]) as XML [XML] applications. It also + describes methods for transporting BLOAT over Ethernet and IEEE 802 + networks as well as encapsulating BLOAT in IP for gatewaying BLOAT + across the public Internet. + +1.2. Motivation + + The wild popularity of XML as a basis for application-level protocols + such as the Blocks Extensible Exchange Protocol [RFC3080], the Simple + Object Access Protocol [SOAP], and Jabber [JABBER] prompted + investigation into the possibility of extending the use of XML in the + protocol stack. Using XML at both the transport and network layer in + addition to the application layer would provide for an amazing amount + of power and flexibility while removing dependencies on proprietary + and hard-to-understand binary protocols. This protocol unification + would also allow applications to use a single XML parser for all + aspects of their operation, eliminating developer time spent figuring + out the intricacies of each new protocol, and moving the hard work of + + + + +Kennedy Informational [Page 1] + +RFC 3252 Binary Lexical Octet Ad-hoc Transport 1 April 2002 + + + parsing to the XML toolset. The use of XML also mitigates concerns + over "network vs. host" byte ordering which is at the root of many + network application bugs. + +1.3. Relation to Existing Protocols + + The reformulations specified in this RFC follow as closely as + possible the spirit of the RFCs on which they are based, and so MAY + contain elements or attributes that would not be needed in a pure + reworking (e.g. length attributes, which are implicit in XML.) + + The layering of network and transport protocols are maintained in + this RFC despite the optimizations that could be made if the line + were somewhat blurred (i.e. merging TCP and IP into a single, larger + element in the DTD) in order to foster future use of this protocol as + a basis for reformulating other protocols (such as ICMP.) + + Other than the encoding, the behavioral aspects of each of the + existing protocols remain unchanged. Routing, address spaces, TCP + congestion control, etc. behave as specified in the extant standards. + Adapting to new standards and experimental algorithm heuristics for + improving performance will become much easier once the move to BLOAT + has been completed. + +1.4. Requirement Levels + + The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", + "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this + document are to be interpreted as described in BCP 14, RFC 2119 + [RFC2119]. + +2. IPoXML + + This protocol MUST be implemented to be compliant with this RFC. + IPoXML is the root protocol REQUIRED for effective use of TCPoXML + (section 3.) and higher-level application protocols. + + The DTD for this document type can be found in section 7.1. + + The routing of IPoXML can be easily implemented on hosts with an XML + parser, as the regular structure lends itself handily to parsing and + validation of the document/datagram and then processing the + destination address, TTL, and checksum before sending it on to its + next-hop. + + The reformulation of IPv4 was chosen over IPv6 [RFC2460] due to the + wider deployment of IPv4 and the fact that implementing IPv6 as XML + would have exceeded the 1500 byte Ethernet MTU. + + + +Kennedy Informational [Page 2] + +RFC 3252 Binary Lexical Octet Ad-hoc Transport 1 April 2002 + + + All BLOAT implementations MUST use - and specify - the UTF-8 encoding + of RFC 2279 [RFC2279]. All BLOAT document/datagrams MUST be well- + formed and include the XMLDecl. + +2.1. IP Description + + A number of items have changed (for the better) from the original IP + specification. Bit-masks, where present have been converted into + human-readable values. IP addresses are listed in their dotted- + decimal notation [RFC1123]. Length and checksum values are present + as decimal integers. + + To calculate the length and checksum fields of the IP element, a + canonicalized form of the element MUST be used. The canonical form + SHALL have no whitespace (including newline characters) between + elements and only one space character between attributes. There + SHALL NOT be a space following the last attribute in an element. + + An iterative method SHOULD be used to calculate checksums, as the + length field will vary based on the size of the checksum. + + The payload element bears special attention. Due to the character + set restrictions of XML, the payload of IP datagrams (which MAY + contain arbitrary data) MUST be encoded for transport. This RFC + REQUIRES the contents of the payload to be encoded in the base-64 + encoding of RFC 2045 [RFC2045], but removes the requirement that the + encoded output MUST be wrapped on 76-character lines. + + + + + + + + + + + + + + + + + + + + + + + + +Kennedy Informational [Page 3] + +RFC 3252 Binary Lexical Octet Ad-hoc Transport 1 April 2002 + + +2.2. Example Datagram + + The following is an example IPoXML datagram with an empty payload: + + <?xml version="1.0" encoding="UTF-8"?> + <!DOCTYPE ip PUBLIC "-//IETF//DTD BLOAT 1.0 IP//EN" "bloat.dtd"> + <ip> + <header length="474"> + <version value="4"/> + <tos precedence="Routine" delay="Normal" throughput="Normal" + relibility="Normal" reserved="0"/> + <total.length value="461"/> + <id value="1"/> + <flags reserved="0" df="dont" mf="last"/> + <offset value="0"/> + <ttl value="255"/> + <protocol value="6"/> + <checksum value="8707"/> + <source address="10.0.0.22"/> + <destination address="10.0.0.1"/> + <options> + <end copied="0" class="0" number="0"/> + </options> + <padding pad="0"/> + </header> + <payload> + </payload> + </ip> + +3. TCPoXML + + This protocol MUST be implemented to be compliant with this RFC. The + DTD for this document type can be found in section 7.2. + +3.1. TCP Description + + A number of items have changed from the original TCP specification. + Bit-masks, where present have been converted into human-readable + values. Length and checksum and port values are present as decimal + integers. + + To calculate the length and checksum fields of the TCP element, a + canonicalized form of the element MUST be used as in section 2.1. + + An iterative method SHOULD be used to calculate checksums as in + section 2.1. + + The payload element MUST be encoded as in section 2.1. + + + +Kennedy Informational [Page 4] + +RFC 3252 Binary Lexical Octet Ad-hoc Transport 1 April 2002 + + + The TCP offset element was expanded to a maximum of 255 from 16 to + allow for the increased size of the header in XML. + + TCPoXML datagrams encapsulated by IPoXML MAY omit the <?xml?> header + as well as the <!DOCTYPE> declaration. + +3.2. Example Datagram + + The following is an example TCPoXML datagram with an empty payload: + + <?xml version="1.0" encoding="UTF-8"?> + <!DOCTYPE tcp PUBLIC "-//IETF//DTD BLOAT 1.0 TCP//EN" "bloat.dtd"> + <tcp> + <tcp.header> + <src port="31415"/> + <dest port="42424"/> + <sequence number="322622954"/> + <acknowledgement number="689715995"/> + <offset number=""/> + <reserved value="0"/> + <control syn="1" ack="1"/> + <window size="1"/> + <urgent pointer="0"/> + <checksum value="2988"/> + <tcp.options> + <tcp.end kind="0"/> + </tcp.options> + <padding pad="0"/> + </tcp.header> + <payload> + </payload> + </tcp> + +4. UDPoXML + + This protocol MUST be implemented to be compliant with this RFC. The + DTD for this document type can be found in section 7.3. + +4.1. UDP Description + + A number of items have changed from the original UDP specification. + Bit-masks, where present have been converted into human-readable + values. Length and checksum and port values are present as decimal + integers. + + + + + + + +Kennedy Informational [Page 5] + +RFC 3252 Binary Lexical Octet Ad-hoc Transport 1 April 2002 + + + To calculate the length and checksum fields of the UDP element, a + canonicalized form of the element MUST be used as in section 2.1. An + iterative method SHOULD be used to calculate checksums as in section + 2.1. + + The payload element MUST be encoded as in section 2.1. + + UDPoXML datagrams encapsulated by IPoXML MAY omit the <?xml?> header + as well as the <!DOCTYPE> declaration. + +4.2. Example Datagram + + The following is an example UDPoXML datagram with an empty payload: + + <?xml version="1.0" encoding="UTF-8"?> + <!DOCTYPE udp PUBLIC "-//IETF//DTD BLOAT 1.0 UDP//EN" "bloat.dtd"> + <udp> + <udp.header> + <src port="31415"/> + <dest port="42424"/> + <udp.length value="143"/> + <checksum value="2988"/> + </udp.header> + <payload> + </payload> + </udp> + +5. Network Transport + + This document provides for the transmission of BLOAT datagrams over + two common families of physical layer transport. Future RFCs will + address additional transports as routing vendors catch up to the + specification, and we begin to see BLOAT routed across the Internet + backbone. + +5.1. Ethernet + + BLOAT is encapsulated in Ethernet datagrams as in [RFC894] with the + exception that the type field of the Ethernet frame MUST contain the + value 0xBEEF. The first 5 octets of the Ethernet frame payload will + be 0x3c 3f 78 6d 6c ("<?xml".) + +5.2. IEEE 802 + + BLOAT is encapsulated in IEEE 802 Networks as in [RFC1042] except + that the protocol type code for IPoXML is 0xBEEF. + + + + + +Kennedy Informational [Page 6] + +RFC 3252 Binary Lexical Octet Ad-hoc Transport 1 April 2002 + + +6. Gatewaying over IP + + In order to facilitate the gradual introduction of BLOAT into the + public Internet, BLOAT MAY be encapsulated in IP as in [RFC2003] to + gateway between networks that run BLOAT natively on their LANs. + +7. DTDs + + The Transport DTDs (7.2. and 7.3.) build on the definitions in the + Network DTD (7.1.) + + The DTDs are referenced by their PubidLiteral and SystemLiteral (from + [XML]) although it is understood that most IPoXML implementations + will not need to pull down the DTD, as it will normally be embedded + in the implementation, and presents something of a catch-22 if you + need to load part of your network protocol over the network. + +7.1. IPoXML DTD + + <!-- + DTD for IP over XML. + Refer to this DTD as: + + <!DOCTYPE ip PUBLIC "-//IETF//DTD BLOAT 1.0 IP//EN" "bloat.dtd"> + --> + <!-- + DTD data types: + + Digits [0..9]+ + + Precedence "NetworkControl | InternetworkControl | + CRITIC | FlashOverride | Flash | Immediate | + Priority | Routine" + + IP4Addr "dotted-decimal" notation of [RFC1123] + + Class [0..3] + + Sec "Unclassified | Confidential | EFTO | MMMM | PROG | + Restricted | Secret | Top Secret | Reserved" + + Compartments [0..65535] + + Handling [0..65535] + + TCC [0..16777216] + + --> + + + +Kennedy Informational [Page 7] + +RFC 3252 Binary Lexical Octet Ad-hoc Transport 1 April 2002 + + + <!ENTITY % Digits "CDATA"> + <!ENTITY % Precedence "CDATA"> + <!ENTITY % IP4Addr "CDATA"> + <!ENTITY % Class "CDATA"> + <!ENTITY % Sec "CDATA"> + <!ENTITY % Compartments "CDATA"> + <!ENTITY % Handling "CDATA"> + <!ENTITY % TCC "CDATA"> + + <!ELEMENT ip (header, payload)> + + <!ELEMENT header (version, tos, total.length, id, flags, offset, ttl, + protocol, checksum, source, destination, options, + padding)> + <!-- length of header in 32-bit words --> + <!ATTLIST header + length %Digits; #REQUIRED> + + <!ELEMENT version EMPTY> + <!-- ip version. SHOULD be "4" --> + <!ATTLIST version + value %Digits; #REQUIRED> + + <!ELEMENT tos EMPTY> + <!ATTLIST tos + precedence %Precedence; #REQUIRED + delay (normal | low) #REQUIRED + throughput (normal | high) #REQUIRED + relibility (normal | high) #REQUIRED + reserved CDATA #FIXED "0"> + + <!ELEMENT total.length EMPTY> + <!-- + total length of datagram (header and payload) in octets, MUST be + less than 65,535 (and SHOULD be less than 1024 for IPoXML on local + ethernets). + --> + <!ATTLIST total.length + value %Digits; #REQUIRED> + + <!ELEMENT id EMPTY> + <!-- 0 <= id <= 65,535 --> + <!ATTLIST id + value %Digits; #REQUIRED> + + <!ELEMENT flags EMPTY> + <!-- df = don't fragment, mf = more fragments --> + <!ATTLIST flags + + + +Kennedy Informational [Page 8] + +RFC 3252 Binary Lexical Octet Ad-hoc Transport 1 April 2002 + + + reserved CDATA #FIXED "0" + df (may|dont) #REQUIRED + mf (last|more) #REQUIRED> + + <!ELEMENT offset EMPTY> + <!-- 0 <= offset <= 8192 measured in 8 octet (64-bit) chunks --> + <!ATTLIST offset + value %Digits; #REQUIRED> + + <!ELEMENT ttl EMPTY> + <!-- 0 <= ttl <= 255 --> + <!ATTLIST ttl + value %Digits; #REQUIRED> + + <!ELEMENT protocol EMPTY> + <!-- 0 <= protocol <= 255 (per IANA) --> + <!ATTLIST protocol + value %Digits; #REQUIRED> + + <!ELEMENT checksum EMPTY> + <!-- 0 <= checksum <= 65535 (over header only) --> + <!ATTLIST checksum + value %Digits; #REQUIRED> + + <!ELEMENT source EMPTY> + <!ATTLIST source + address %IP4Addr; #REQUIRED> + + <!ELEMENT destination EMPTY> + <!ATTLIST destination + address %IP4Addr; #REQUIRED> + + <!ELEMENT options ( end | noop | security | loose | strict | record + | stream | timestamp )*> + + <!ELEMENT end EMPTY> + <!ATTLIST end + copied (0|1) #REQUIRED + class CDATA #FIXED "0" + number CDATA #FIXED "0"> + + <!ELEMENT noop EMPTY> + <!ATTLIST noop + copied (0|1) #REQUIRED + class CDATA #FIXED "0" + number CDATA #FIXED "1"> + + <!ELEMENT security EMPTY> + + + +Kennedy Informational [Page 9] + +RFC 3252 Binary Lexical Octet Ad-hoc Transport 1 April 2002 + + + <!ATTLIST security + copied CDATA #FIXED "1" + class CDATA #FIXED "0" + number CDATA #FIXED "2" + length CDATA #FIXED "11" + security %Sec; #REQUIRED + compartments %Compartments; #REQUIRED + handling %Handling; #REQUIRED + tcc %TCC; #REQUIRED> + <!ELEMENT loose (hop)+> + <!ATTLIST loose + copied CDATA #FIXED "1" + class CDATA #FIXED "0" + number CDATA #FIXED "3" + length %Digits; #REQUIRED + pointer %Digits; #REQUIRED> + + <!ELEMENT hop EMPTY> + <!ATTLIST hop + address %IP4Addr; #REQUIRED> + + <!ELEMENT strict (hop)+> + <!ATTLIST strict + copied CDATA #FIXED "1" + class CDATA #FIXED "0" + number CDATA #FIXED "9" + length %Digits; #REQUIRED + pointer %Digits; #REQUIRED> + + <!ELEMENT record (hop)+> + <!ATTLIST record + copied CDATA #FIXED "0" + class CDATA #FIXED "0" + number CDATA #FIXED "7" + length %Digits; #REQUIRED + pointer %Digits; #REQUIRED> + + <!ELEMENT stream EMPTY> + <!-- 0 <= id <= 65,535 --> + <!ATTLIST stream + copied CDATA #FIXED "1" + class CDATA #FIXED "0" + number CDATA #FIXED "8" + length CDATA #FIXED "4" + id %Digits; #REQUIRED> + + <!ELEMENT timestamp (tstamp)+> + <!-- 0 <= oflw <=15 --> + + + +Kennedy Informational [Page 10] + +RFC 3252 Binary Lexical Octet Ad-hoc Transport 1 April 2002 + + + <!ATTLIST timestamp + copied CDATA #FIXED "0" + class CDATA #FIXED "2" + number CDATA #FIXED "4" + length %Digits; #REQUIRED + pointer %Digits; #REQUIRED + oflw %Digits; #REQUIRED + flag (0 | 1 | 3) #REQUIRED> + + <!ELEMENT tstamp EMPTY> + <!ATTLIST tstamp + time %Digits; #REQUIRED + address %IP4Addr; #IMPLIED> + <!-- + padding to bring header to 32-bit boundary. + pad MUST be "0"* + --> + <!ELEMENT padding EMPTY> + <!ATTLIST padding + pad CDATA #REQUIRED> + + <!-- payload MUST be encoded as base-64 [RFC2045], as modified + by section 2.1 of this RFC --> + <!ELEMENT payload (CDATA)> + +7.2. TCPoXML DTD + + <!-- + DTD for TCP over XML. + Refer to this DTD as: + + <!DOCTYPE tcp PUBLIC "-//IETF//DTD BLOAT 1.0 TCP//EN" "bloat.dtd"> + --> + + <!-- the pseudoheader is only included for checksum calculations --> + <!ELEMENT tcp (tcp.pseudoheader?, tcp.header, payload)> + + <!ELEMENT tcp.header (src, dest, sequence, acknowledgement, offset, + reserved, control, window, checksum, urgent, + tcp.options, padding)> + + <!ELEMENT src EMPTY> + <!-- 0 <= port <= 65,535 --> + <!ATTLIST src + port %Digits; #REQUIRED> + + <!ELEMENT dest EMPTY> + <!-- 0 <= port <= 65,535 --> + + + +Kennedy Informational [Page 11] + +RFC 3252 Binary Lexical Octet Ad-hoc Transport 1 April 2002 + + + <!ATTLIST dest + port %Digits; #REQUIRED> + + <!ELEMENT sequence EMPTY> + <!-- 0 <= number <= 4294967295 --> + <!ATTLIST sequence + number %Digits; #REQUIRED> + + <!ELEMENT acknowledgement EMPTY> + <!-- 0 <= number <= 4294967295 --> + <!ATTLIST acknowledgement + number %Digits; #REQUIRED> + + <!ELEMENT offset EMPTY> + <!-- 0 <= number <= 255 --> + <!ATTLIST offset + number %Digits; #REQUIRED> + + <!ELEMENT reserved EMPTY> + <!ATTLIST reserved + value CDATA #FIXED "0"> + + <!ELEMENT control EMPTY> + <!ATTLIST control + urg (0|1) #IMPLIED + ack (0|1) #IMPLIED + psh (0|1) #IMPLIED + rst (0|1) #IMPLIED + syn (0|1) #IMPLIED + fin (0|1) #IMPLIED> + + <!ELEMENT window EMPTY> + <!-- 0 <= size <= 65,535 --> + <!ATTLIST window + size %Digits; #REQUIRED> + + <!-- + checksum as in ip, but with + the following pseudo-header added into the tcp element: + --> + <!ELEMENT tcp.pseudoheader (source, destination, protocol, + tcp.length)> + + <!-- + tcp header + data length in octets. does not include the size of + + the pseudoheader. + --> + + + +Kennedy Informational [Page 12] + +RFC 3252 Binary Lexical Octet Ad-hoc Transport 1 April 2002 + + + <!ELEMENT tcp.length EMPTY> + <!ATTLIST tcp.length + value %Digits; #REQUIRED> + + <!ELEMENT urgent EMPTY> + <!-- 0 <= pointer <= 65,535 --> + <!ATTLIST urgent + pointer %Digits; #REQUIRED> + + <!ELEMENT tcp.options (tcp.end | tcp.noop | tcp.mss)+> + + <!ELEMENT tcp.end EMPTY> + <!ATTLIST tcp.end + kind CDATA #FIXED "0"> + + <!ELEMENT tcp.noop EMPTY> + <!ATTLIST tcp.noop + kind CDATA #FIXED "1"> + + <!ELEMENT tcp.mss EMPTY> + <!ATTLIST tcp.mss + kind CDATA #FIXED "2" + length CDATA #FIXED "4" + size %Digits; #REQUIRED> + +7.3. UDPoXML DTD + + <!-- + DTD for UDP over XML. + Refer to this DTD as: + + <!DOCTYPE udp PUBLIC "-//IETF//DTD BLOAT 1.0 UDP//EN" "bloat.dtd"> + --> + + <!ELEMENT udp (udp.pseudoheader?, udp.header, payload)> + + <!ELEMENT udp.header (src, dest, udp.length, checksum)> + + <!ELEMENT udp.pseudoheader (source, destination, protocol, + udp.length)> + + <!-- + udp header + data length in octets. does not include the size of + the pseudoheader. + --> + <!ELEMENT udp.length EMPTY> + <!ATTLIST udp.length + value %Digits; #REQUIRED> + + + +Kennedy Informational [Page 13] + +RFC 3252 Binary Lexical Octet Ad-hoc Transport 1 April 2002 + + +8. Security Considerations + + XML, as a subset of SGML, has the same security considerations as + specified in SGML Media Types [RFC1874]. Security considerations + that apply to IP, TCP and UDP also likely apply to BLOAT as it does + not attempt to correct for issues not related to message format. + +9. References + + [JABBER] Miller, J., "Jabber", draft-miller-jabber-00.txt, + February 2002. (Work in Progress) + + [RFC768] Postel, J., "User Datagram Protocol", STD 6, RFC 768, + August 1980. + + [RFC791] Postel, J., "Internet Protocol", STD 5, RFC 791, + September 1981. + + [RFC793] Postel, J., "Transmission Control Protocol", STD 7, RFC + 793, September 1981. + + [RFC894] Hornig, C., "Standard for the Transmission of IP + Datagrams over Ethernet Networks.", RFC 894, April 1984. + + [RFC1042] Postel, J. and J. Reynolds, "Standard for the + Transmission of IP Datagrams Over IEEE 802 Networks", STD + 43, RFC 1042, February 1988. + + [RFC1123] Braden, R., "Requirements for Internet Hosts - + Application and Support", RFC 1123, October 1989. + + [RFC1874] Levinson, E., "SGML Media Types", RFC 1874, December + 1995. + + [RFC2003] Perkins, C., "IP Encapsulation within IP", RFC 2003, + October 1996. + + [RFC2045] Freed, N. and N. Borenstein, "Multipurpose Internet Mail + Extensions (MIME) Part One: Format of Internet Message + Bodies", RFC 2045, November 1996. + + [RFC2119] Bradner, S., "Key words for use in RFCs to Indicate + Requirement Levels", BCP 14, RFC 2119, March 1997. + + [RFC2279] Yergeau, F., "UTF-8, a transformation format of ISO + 10646", RFC 2279, January 1998. + + + + + +Kennedy Informational [Page 14] + +RFC 3252 Binary Lexical Octet Ad-hoc Transport 1 April 2002 + + + [RFC2460] Deering, S. and R. Hinden, "Internet Protocol, Version 6 + (IPv6) Specification", RFC 2460, December 1998. + + [RFC3080] Rose, M., "The Blocks Extensible Exchange Protocol Core", + RFC 3080, March 2001. + + [SOAP] Box, D., Ehnebuske, D., Kakivaya, G., Layman, A., + Mendelsohn, N., Nielsen, H. F., Thatte, S. Winer, D., + "Simple Object Access Protocol (SOAP) 1.1" World Wide Web + Consortium Note, May 2000 http://www.w3.org/TR/SOAP/ + + [XML] Bray, T., Paoli, J., Sperberg-McQueen, C. M., "Extensible + Markup Language (XML)" World Wide Web Consortium + Recommendation REC- xml-19980210. + http://www.w3.org/TR/1998/REC-xml-19980210 + +10. Author's Address + + Hugh Kennedy + Mimezine + 1060 West Addison + Chicago, IL 60613 + USA + + EMail: kennedyh@engin.umich.edu + + + + + + + + + + + + + + + + + + + + + + + + + + +Kennedy Informational [Page 15] + +RFC 3252 Binary Lexical Octet Ad-hoc Transport 1 April 2002 + + +11. Full Copyright Statement + + Copyright (C) The Internet Society (2002). All Rights Reserved. + + This document and translations of it may be copied and furnished to + others, and derivative works that comment on or otherwise explain it + or assist in its implementation may be prepared, copied, published + and distributed, in whole or in part, without restriction of any + kind, provided that the above copyright notice and this paragraph are + included on all such copies and derivative works. However, this + document itself may not be modified in any way, such as by removing + the copyright notice or references to the Internet Society or other + Internet organizations, except as needed for the purpose of + developing Internet standards in which case the procedures for + copyrights defined in the Internet Standards process must be + followed, or as required to translate it into languages other than + English. + + The limited permissions granted above are perpetual and will not be + revoked by the Internet Society or its successors or assigns. + + This document and the information contained herein is provided on an + "AS IS" basis and THE INTERNET SOCIETY AND THE INTERNET ENGINEERING + TASK FORCE DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING + BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE INFORMATION + HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED WARRANTIES OF + MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. + +Acknowledgement + + Funding for the RFC Editor function is currently provided by the + Internet Society. + + + + + + + + + + + + + + + + + + + +Kennedy Informational [Page 16] + + + + + + + +Network Working Group H. Kennedy +Request for Comments: 3252 Mimezine +Category: Informational 1 April 2002 + + + Binary Lexical Octet Ad-hoc Transport + +Status of this Memo + + This memo provides information for the Internet community. It does + not specify an Internet standard of any kind. Distribution of this + memo is unlimited. + +Copyright Notice + + Copyright (C) The Internet Society (2002). All Rights Reserved. + +Abstract + + This document defines a reformulation of IP and two transport layer + protocols (TCP and UDP) as XML applications. + +1. Introduction + +1.1. Overview + + This document describes the Binary Lexical Octet Ad-hoc Transport + (BLOAT): a reformulation of a widely-deployed network-layer protocol + (IP [RFC791]), and two associated transport layer protocols (TCP + [RFC793] and UDP [RFC768]) as XML [XML] applications. It also + describes methods for transporting BLOAT over Ethernet and IEEE 802 + networks as well as encapsulating BLOAT in IP for gatewaying BLOAT + across the public Internet. + +1.2. Motivation + + The wild popularity of XML as a basis for application-level protocols + such as the Blocks Extensible Exchange Protocol [RFC3080], the Simple + Object Access Protocol [SOAP], and Jabber [JABBER] prompted + investigation into the possibility of extending the use of XML in the + protocol stack. Using XML at both the transport and network layer in + addition to the application layer would provide for an amazing amount + of power and flexibility while removing dependencies on proprietary + and hard-to-understand binary protocols. This protocol unification + would also allow applications to use a single XML parser for all + aspects of their operation, eliminating developer time spent figuring + out the intricacies of each new protocol, and moving the hard work of + + + + +Kennedy Informational [Page 1] + +RFC 3252 Binary Lexical Octet Ad-hoc Transport 1 April 2002 + + + parsing to the XML toolset. The use of XML also mitigates concerns + over "network vs. host" byte ordering which is at the root of many + network application bugs. + +1.3. Relation to Existing Protocols + + The reformulations specified in this RFC follow as closely as + possible the spirit of the RFCs on which they are based, and so MAY + contain elements or attributes that would not be needed in a pure + reworking (e.g. length attributes, which are implicit in XML.) + + The layering of network and transport protocols are maintained in + this RFC despite the optimizations that could be made if the line + were somewhat blurred (i.e. merging TCP and IP into a single, larger + element in the DTD) in order to foster future use of this protocol as + a basis for reformulating other protocols (such as ICMP.) + + Other than the encoding, the behavioral aspects of each of the + existing protocols remain unchanged. Routing, address spaces, TCP + congestion control, etc. behave as specified in the extant standards. + Adapting to new standards and experimental algorithm heuristics for + improving performance will become much easier once the move to BLOAT + has been completed. + +1.4. Requirement Levels + + The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", + "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this + document are to be interpreted as described in BCP 14, RFC 2119 + [RFC2119]. + +2. IPoXML + + This protocol MUST be implemented to be compliant with this RFC. + IPoXML is the root protocol REQUIRED for effective use of TCPoXML + (section 3.) and higher-level application protocols. + + The DTD for this document type can be found in section 7.1. + + The routing of IPoXML can be easily implemented on hosts with an XML + parser, as the regular structure lends itself handily to parsing and + validation of the document/datagram and then processing the + destination address, TTL, and checksum before sending it on to its + next-hop. + + The reformulation of IPv4 was chosen over IPv6 [RFC2460] due to the + wider deployment of IPv4 and the fact that implementing IPv6 as XML + would have exceeded the 1500 byte Ethernet MTU. + + + +Kennedy Informational [Page 2] + +RFC 3252 Binary Lexical Octet Ad-hoc Transport 1 April 2002 + + + All BLOAT implementations MUST use - and specify - the UTF-8 encoding + of RFC 2279 [RFC2279]. All BLOAT document/datagrams MUST be well- + formed and include the XMLDecl. + +2.1. IP Description + + A number of items have changed (for the better) from the original IP + specification. Bit-masks, where present have been converted into + human-readable values. IP addresses are listed in their dotted- + decimal notation [RFC1123]. Length and checksum values are present + as decimal integers. + + To calculate the length and checksum fields of the IP element, a + canonicalized form of the element MUST be used. The canonical form + SHALL have no whitespace (including newline characters) between + elements and only one space character between attributes. There + SHALL NOT be a space following the last attribute in an element. + + An iterative method SHOULD be used to calculate checksums, as the + length field will vary based on the size of the checksum. + + The payload element bears special attention. Due to the character + set restrictions of XML, the payload of IP datagrams (which MAY + contain arbitrary data) MUST be encoded for transport. This RFC + REQUIRES the contents of the payload to be encoded in the base-64 + encoding of RFC 2045 [RFC2045], but removes the requirement that the + encoded output MUST be wrapped on 76-character lines. + + + + + + + + + + + + + + + + + + + + + + + + +Kennedy Informational [Page 3] + +RFC 3252 Binary Lexical Octet Ad-hoc Transport 1 April 2002 + + +2.2. Example Datagram + + The following is an example IPoXML datagram with an empty payload: + + <?xml version="1.0" encoding="UTF-8"?> + <!DOCTYPE ip PUBLIC "-//IETF//DTD BLOAT 1.0 IP//EN" "bloat.dtd"> + <ip> + <header length="474"> + <version value="4"/> + <tos precedence="Routine" delay="Normal" throughput="Normal" + relibility="Normal" reserved="0"/> + <total.length value="461"/> + <id value="1"/> + <flags reserved="0" df="dont" mf="last"/> + <offset value="0"/> + <ttl value="255"/> + <protocol value="6"/> + <checksum value="8707"/> + <source address="10.0.0.22"/> + <destination address="10.0.0.1"/> + <options> + <end copied="0" class="0" number="0"/> + </options> + <padding pad="0"/> + </header> + <payload> + </payload> + </ip> + +3. TCPoXML + + This protocol MUST be implemented to be compliant with this RFC. The + DTD for this document type can be found in section 7.2. + +3.1. TCP Description + + A number of items have changed from the original TCP specification. + Bit-masks, where present have been converted into human-readable + values. Length and checksum and port values are present as decimal + integers. + + To calculate the length and checksum fields of the TCP element, a + canonicalized form of the element MUST be used as in section 2.1. + + An iterative method SHOULD be used to calculate checksums as in + section 2.1. + + The payload element MUST be encoded as in section 2.1. + + + +Kennedy Informational [Page 4] + +RFC 3252 Binary Lexical Octet Ad-hoc Transport 1 April 2002 + + + The TCP offset element was expanded to a maximum of 255 from 16 to + allow for the increased size of the header in XML. + + TCPoXML datagrams encapsulated by IPoXML MAY omit the <?xml?> header + as well as the <!DOCTYPE> declaration. + +3.2. Example Datagram + + The following is an example TCPoXML datagram with an empty payload: + + <?xml version="1.0" encoding="UTF-8"?> + <!DOCTYPE tcp PUBLIC "-//IETF//DTD BLOAT 1.0 TCP//EN" "bloat.dtd"> + <tcp> + <tcp.header> + <src port="31415"/> + <dest port="42424"/> + <sequence number="322622954"/> + <acknowledgement number="689715995"/> + <offset number=""/> + <reserved value="0"/> + <control syn="1" ack="1"/> + <window size="1"/> + <urgent pointer="0"/> + <checksum value="2988"/> + <tcp.options> + <tcp.end kind="0"/> + </tcp.options> + <padding pad="0"/> + </tcp.header> + <payload> + </payload> + </tcp> + +4. UDPoXML + + This protocol MUST be implemented to be compliant with this RFC. The + DTD for this document type can be found in section 7.3. + +4.1. UDP Description + + A number of items have changed from the original UDP specification. + Bit-masks, where present have been converted into human-readable + values. Length and checksum and port values are present as decimal + integers. + + + + + + + +Kennedy Informational [Page 5] + +RFC 3252 Binary Lexical Octet Ad-hoc Transport 1 April 2002 + + + To calculate the length and checksum fields of the UDP element, a + canonicalized form of the element MUST be used as in section 2.1. An + iterative method SHOULD be used to calculate checksums as in section + 2.1. + + The payload element MUST be encoded as in section 2.1. + + UDPoXML datagrams encapsulated by IPoXML MAY omit the <?xml?> header + as well as the <!DOCTYPE> declaration. + +4.2. Example Datagram + + The following is an example UDPoXML datagram with an empty payload: + + <?xml version="1.0" encoding="UTF-8"?> + <!DOCTYPE udp PUBLIC "-//IETF//DTD BLOAT 1.0 UDP//EN" "bloat.dtd"> + <udp> + <udp.header> + <src port="31415"/> + <dest port="42424"/> + <udp.length value="143"/> + <checksum value="2988"/> + </udp.header> + <payload> + </payload> + </udp> + +5. Network Transport + + This document provides for the transmission of BLOAT datagrams over + two common families of physical layer transport. Future RFCs will + address additional transports as routing vendors catch up to the + specification, and we begin to see BLOAT routed across the Internet + backbone. + +5.1. Ethernet + + BLOAT is encapsulated in Ethernet datagrams as in [RFC894] with the + exception that the type field of the Ethernet frame MUST contain the + value 0xBEEF. The first 5 octets of the Ethernet frame payload will + be 0x3c 3f 78 6d 6c ("<?xml".) + +5.2. IEEE 802 + + BLOAT is encapsulated in IEEE 802 Networks as in [RFC1042] except + that the protocol type code for IPoXML is 0xBEEF. + + + + + +Kennedy Informational [Page 6] + +RFC 3252 Binary Lexical Octet Ad-hoc Transport 1 April 2002 + + +6. Gatewaying over IP + + In order to facilitate the gradual introduction of BLOAT into the + public Internet, BLOAT MAY be encapsulated in IP as in [RFC2003] to + gateway between networks that run BLOAT natively on their LANs. + +7. DTDs + + The Transport DTDs (7.2. and 7.3.) build on the definitions in the + Network DTD (7.1.) + + The DTDs are referenced by their PubidLiteral and SystemLiteral (from + [XML]) although it is understood that most IPoXML implementations + will not need to pull down the DTD, as it will normally be embedded + in the implementation, and presents something of a catch-22 if you + need to load part of your network protocol over the network. + +7.1. IPoXML DTD + + <!-- + DTD for IP over XML. + Refer to this DTD as: + + <!DOCTYPE ip PUBLIC "-//IETF//DTD BLOAT 1.0 IP//EN" "bloat.dtd"> + --> + <!-- + DTD data types: + + Digits [0..9]+ + + Precedence "NetworkControl | InternetworkControl | + CRITIC | FlashOverride | Flash | Immediate | + Priority | Routine" + + IP4Addr "dotted-decimal" notation of [RFC1123] + + Class [0..3] + + Sec "Unclassified | Confidential | EFTO | MMMM | PROG | + Restricted | Secret | Top Secret | Reserved" + + Compartments [0..65535] + + Handling [0..65535] + + TCC [0..16777216] + + --> + + + +Kennedy Informational [Page 7] + +RFC 3252 Binary Lexical Octet Ad-hoc Transport 1 April 2002 + + + <!ENTITY % Digits "CDATA"> + <!ENTITY % Precedence "CDATA"> + <!ENTITY % IP4Addr "CDATA"> + <!ENTITY % Class "CDATA"> + <!ENTITY % Sec "CDATA"> + <!ENTITY % Compartments "CDATA"> + <!ENTITY % Handling "CDATA"> + <!ENTITY % TCC "CDATA"> + + <!ELEMENT ip (header, payload)> + + <!ELEMENT header (version, tos, total.length, id, flags, offset, ttl, + protocol, checksum, source, destination, options, + padding)> + <!-- length of header in 32-bit words --> + <!ATTLIST header + length %Digits; #REQUIRED> + + <!ELEMENT version EMPTY> + <!-- ip version. SHOULD be "4" --> + <!ATTLIST version + value %Digits; #REQUIRED> + + <!ELEMENT tos EMPTY> + <!ATTLIST tos + precedence %Precedence; #REQUIRED + delay (normal | low) #REQUIRED + throughput (normal | high) #REQUIRED + relibility (normal | high) #REQUIRED + reserved CDATA #FIXED "0"> + + <!ELEMENT total.length EMPTY> + <!-- + total length of datagram (header and payload) in octets, MUST be + less than 65,535 (and SHOULD be less than 1024 for IPoXML on local + ethernets). + --> + <!ATTLIST total.length + value %Digits; #REQUIRED> + + <!ELEMENT id EMPTY> + <!-- 0 <= id <= 65,535 --> + <!ATTLIST id + value %Digits; #REQUIRED> + + <!ELEMENT flags EMPTY> + <!-- df = don't fragment, mf = more fragments --> + <!ATTLIST flags + + + +Kennedy Informational [Page 8] + +RFC 3252 Binary Lexical Octet Ad-hoc Transport 1 April 2002 + + + reserved CDATA #FIXED "0" + df (may|dont) #REQUIRED + mf (last|more) #REQUIRED> + + <!ELEMENT offset EMPTY> + <!-- 0 <= offset <= 8192 measured in 8 octet (64-bit) chunks --> + <!ATTLIST offset + value %Digits; #REQUIRED> + + <!ELEMENT ttl EMPTY> + <!-- 0 <= ttl <= 255 --> + <!ATTLIST ttl + value %Digits; #REQUIRED> + + <!ELEMENT protocol EMPTY> + <!-- 0 <= protocol <= 255 (per IANA) --> + <!ATTLIST protocol + value %Digits; #REQUIRED> + + <!ELEMENT checksum EMPTY> + <!-- 0 <= checksum <= 65535 (over header only) --> + <!ATTLIST checksum + value %Digits; #REQUIRED> + + <!ELEMENT source EMPTY> + <!ATTLIST source + address %IP4Addr; #REQUIRED> + + <!ELEMENT destination EMPTY> + <!ATTLIST destination + address %IP4Addr; #REQUIRED> + + <!ELEMENT options ( end | noop | security | loose | strict | record + | stream | timestamp )*> + + <!ELEMENT end EMPTY> + <!ATTLIST end + copied (0|1) #REQUIRED + class CDATA #FIXED "0" + number CDATA #FIXED "0"> + + <!ELEMENT noop EMPTY> + <!ATTLIST noop + copied (0|1) #REQUIRED + class CDATA #FIXED "0" + number CDATA #FIXED "1"> + + <!ELEMENT security EMPTY> + + + +Kennedy Informational [Page 9] + +RFC 3252 Binary Lexical Octet Ad-hoc Transport 1 April 2002 + + + <!ATTLIST security + copied CDATA #FIXED "1" + class CDATA #FIXED "0" + number CDATA #FIXED "2" + length CDATA #FIXED "11" + security %Sec; #REQUIRED + compartments %Compartments; #REQUIRED + handling %Handling; #REQUIRED + tcc %TCC; #REQUIRED> + <!ELEMENT loose (hop)+> + <!ATTLIST loose + copied CDATA #FIXED "1" + class CDATA #FIXED "0" + number CDATA #FIXED "3" + length %Digits; #REQUIRED + pointer %Digits; #REQUIRED> + + <!ELEMENT hop EMPTY> + <!ATTLIST hop + address %IP4Addr; #REQUIRED> + + <!ELEMENT strict (hop)+> + <!ATTLIST strict + copied CDATA #FIXED "1" + class CDATA #FIXED "0" + number CDATA #FIXED "9" + length %Digits; #REQUIRED + pointer %Digits; #REQUIRED> + + <!ELEMENT record (hop)+> + <!ATTLIST record + copied CDATA #FIXED "0" + class CDATA #FIXED "0" + number CDATA #FIXED "7" + length %Digits; #REQUIRED + pointer %Digits; #REQUIRED> + + <!ELEMENT stream EMPTY> + <!-- 0 <= id <= 65,535 --> + <!ATTLIST stream + copied CDATA #FIXED "1" + class CDATA #FIXED "0" + number CDATA #FIXED "8" + length CDATA #FIXED "4" + id %Digits; #REQUIRED> + + <!ELEMENT timestamp (tstamp)+> + <!-- 0 <= oflw <=15 --> + + + +Kennedy Informational [Page 10] + +RFC 3252 Binary Lexical Octet Ad-hoc Transport 1 April 2002 + + + <!ATTLIST timestamp + copied CDATA #FIXED "0" + class CDATA #FIXED "2" + number CDATA #FIXED "4" + length %Digits; #REQUIRED + pointer %Digits; #REQUIRED + oflw %Digits; #REQUIRED + flag (0 | 1 | 3) #REQUIRED> + + <!ELEMENT tstamp EMPTY> + <!ATTLIST tstamp + time %Digits; #REQUIRED + address %IP4Addr; #IMPLIED> + <!-- + padding to bring header to 32-bit boundary. + pad MUST be "0"* + --> + <!ELEMENT padding EMPTY> + <!ATTLIST padding + pad CDATA #REQUIRED> + + <!-- payload MUST be encoded as base-64 [RFC2045], as modified + by section 2.1 of this RFC --> + <!ELEMENT payload (CDATA)> + +7.2. TCPoXML DTD + + <!-- + DTD for TCP over XML. + Refer to this DTD as: + + <!DOCTYPE tcp PUBLIC "-//IETF//DTD BLOAT 1.0 TCP//EN" "bloat.dtd"> + --> + + <!-- the pseudoheader is only included for checksum calculations --> + <!ELEMENT tcp (tcp.pseudoheader?, tcp.header, payload)> + + <!ELEMENT tcp.header (src, dest, sequence, acknowledgement, offset, + reserved, control, window, checksum, urgent, + tcp.options, padding)> + + <!ELEMENT src EMPTY> + <!-- 0 <= port <= 65,535 --> + <!ATTLIST src + port %Digits; #REQUIRED> + + <!ELEMENT dest EMPTY> + <!-- 0 <= port <= 65,535 --> + + + +Kennedy Informational [Page 11] + +RFC 3252 Binary Lexical Octet Ad-hoc Transport 1 April 2002 + + + <!ATTLIST dest + port %Digits; #REQUIRED> + + <!ELEMENT sequence EMPTY> + <!-- 0 <= number <= 4294967295 --> + <!ATTLIST sequence + number %Digits; #REQUIRED> + + <!ELEMENT acknowledgement EMPTY> + <!-- 0 <= number <= 4294967295 --> + <!ATTLIST acknowledgement + number %Digits; #REQUIRED> + + <!ELEMENT offset EMPTY> + <!-- 0 <= number <= 255 --> + <!ATTLIST offset + number %Digits; #REQUIRED> + + <!ELEMENT reserved EMPTY> + <!ATTLIST reserved + value CDATA #FIXED "0"> + + <!ELEMENT control EMPTY> + <!ATTLIST control + urg (0|1) #IMPLIED + ack (0|1) #IMPLIED + psh (0|1) #IMPLIED + rst (0|1) #IMPLIED + syn (0|1) #IMPLIED + fin (0|1) #IMPLIED> + + <!ELEMENT window EMPTY> + <!-- 0 <= size <= 65,535 --> + <!ATTLIST window + size %Digits; #REQUIRED> + + <!-- + checksum as in ip, but with + the following pseudo-header added into the tcp element: + --> + <!ELEMENT tcp.pseudoheader (source, destination, protocol, + tcp.length)> + + <!-- + tcp header + data length in octets. does not include the size of + + the pseudoheader. + --> + + + +Kennedy Informational [Page 12] + +RFC 3252 Binary Lexical Octet Ad-hoc Transport 1 April 2002 + + + <!ELEMENT tcp.length EMPTY> + <!ATTLIST tcp.length + value %Digits; #REQUIRED> + + <!ELEMENT urgent EMPTY> + <!-- 0 <= pointer <= 65,535 --> + <!ATTLIST urgent + pointer %Digits; #REQUIRED> + + <!ELEMENT tcp.options (tcp.end | tcp.noop | tcp.mss)+> + + <!ELEMENT tcp.end EMPTY> + <!ATTLIST tcp.end + kind CDATA #FIXED "0"> + + <!ELEMENT tcp.noop EMPTY> + <!ATTLIST tcp.noop + kind CDATA #FIXED "1"> + + <!ELEMENT tcp.mss EMPTY> + <!ATTLIST tcp.mss + kind CDATA #FIXED "2" + length CDATA #FIXED "4" + size %Digits; #REQUIRED> + +7.3. UDPoXML DTD + + <!-- + DTD for UDP over XML. + Refer to this DTD as: + + <!DOCTYPE udp PUBLIC "-//IETF//DTD BLOAT 1.0 UDP//EN" "bloat.dtd"> + --> + + <!ELEMENT udp (udp.pseudoheader?, udp.header, payload)> + + <!ELEMENT udp.header (src, dest, udp.length, checksum)> + + <!ELEMENT udp.pseudoheader (source, destination, protocol, + udp.length)> + + <!-- + udp header + data length in octets. does not include the size of + the pseudoheader. + --> + <!ELEMENT udp.length EMPTY> + <!ATTLIST udp.length + value %Digits; #REQUIRED> + + + +Kennedy Informational [Page 13] + +RFC 3252 Binary Lexical Octet Ad-hoc Transport 1 April 2002 + + +8. Security Considerations + + XML, as a subset of SGML, has the same security considerations as + specified in SGML Media Types [RFC1874]. Security considerations + that apply to IP, TCP and UDP also likely apply to BLOAT as it does + not attempt to correct for issues not related to message format. + +9. References + + [JABBER] Miller, J., "Jabber", draft-miller-jabber-00.txt, + February 2002. (Work in Progress) + + [RFC768] Postel, J., "User Datagram Protocol", STD 6, RFC 768, + August 1980. + + [RFC791] Postel, J., "Internet Protocol", STD 5, RFC 791, + September 1981. + + [RFC793] Postel, J., "Transmission Control Protocol", STD 7, RFC + 793, September 1981. + + [RFC894] Hornig, C., "Standard for the Transmission of IP + Datagrams over Ethernet Networks.", RFC 894, April 1984. + + [RFC1042] Postel, J. and J. Reynolds, "Standard for the + Transmission of IP Datagrams Over IEEE 802 Networks", STD + 43, RFC 1042, February 1988. + + [RFC1123] Braden, R., "Requirements for Internet Hosts - + Application and Support", RFC 1123, October 1989. + + [RFC1874] Levinson, E., "SGML Media Types", RFC 1874, December + 1995. + + [RFC2003] Perkins, C., "IP Encapsulation within IP", RFC 2003, + October 1996. + + [RFC2045] Freed, N. and N. Borenstein, "Multipurpose Internet Mail + Extensions (MIME) Part One: Format of Internet Message + Bodies", RFC 2045, November 1996. + + [RFC2119] Bradner, S., "Key words for use in RFCs to Indicate + Requirement Levels", BCP 14, RFC 2119, March 1997. + + [RFC2279] Yergeau, F., "UTF-8, a transformation format of ISO + 10646", RFC 2279, January 1998. + + + + + +Kennedy Informational [Page 14] + +RFC 3252 Binary Lexical Octet Ad-hoc Transport 1 April 2002 + + + [RFC2460] Deering, S. and R. Hinden, "Internet Protocol, Version 6 + (IPv6) Specification", RFC 2460, December 1998. + + [RFC3080] Rose, M., "The Blocks Extensible Exchange Protocol Core", + RFC 3080, March 2001. + + [SOAP] Box, D., Ehnebuske, D., Kakivaya, G., Layman, A., + Mendelsohn, N., Nielsen, H. F., Thatte, S. Winer, D., + "Simple Object Access Protocol (SOAP) 1.1" World Wide Web + Consortium Note, May 2000 http://www.w3.org/TR/SOAP/ + + [XML] Bray, T., Paoli, J., Sperberg-McQueen, C. M., "Extensible + Markup Language (XML)" World Wide Web Consortium + Recommendation REC- xml-19980210. + http://www.w3.org/TR/1998/REC-xml-19980210 + +10. Author's Address + + Hugh Kennedy + Mimezine + 1060 West Addison + Chicago, IL 60613 + USA + + EMail: kennedyh@engin.umich.edu + + + + + + + + + + + + + + + + + + + + + + + + + + +Kennedy Informational [Page 15] + +RFC 3252 Binary Lexical Octet Ad-hoc Transport 1 April 2002 + + +11. Full Copyright Statement + + Copyright (C) The Internet Society (2002). All Rights Reserved. + + This document and translations of it may be copied and furnished to + others, and derivative works that comment on or otherwise explain it + or assist in its implementation may be prepared, copied, published + and distributed, in whole or in part, without restriction of any + kind, provided that the above copyright notice and this paragraph are + included on all such copies and derivative works. However, this + document itself may not be modified in any way, such as by removing + the copyright notice or references to the Internet Society or other + Internet organizations, except as needed for the purpose of + developing Internet standards in which case the procedures for + copyrights defined in the Internet Standards process must be + followed, or as required to translate it into languages other than + English. + + The limited permissions granted above are perpetual and will not be + revoked by the Internet Society or its successors or assigns. + + This document and the information contained herein is provided on an + "AS IS" basis and THE INTERNET SOCIETY AND THE INTERNET ENGINEERING + TASK FORCE DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING + BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE INFORMATION + HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED WARRANTIES OF + MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. + +Acknowledgement + + Funding for the RFC Editor function is currently provided by the + Internet Society. + + + + + + + + + + + + + + + + + + + +Kennedy Informational [Page 16] + + + + + + + +Network Working Group H. Kennedy +Request for Comments: 3252 Mimezine +Category: Informational 1 April 2002 + + + Binary Lexical Octet Ad-hoc Transport + +Status of this Memo + + This memo provides information for the Internet community. It does + not specify an Internet standard of any kind. Distribution of this + memo is unlimited. + +Copyright Notice + + Copyright (C) The Internet Society (2002). All Rights Reserved. + +Abstract + + This document defines a reformulation of IP and two transport layer + protocols (TCP and UDP) as XML applications. + +1. Introduction + +1.1. Overview + + This document describes the Binary Lexical Octet Ad-hoc Transport + (BLOAT): a reformulation of a widely-deployed network-layer protocol + (IP [RFC791]), and two associated transport layer protocols (TCP + [RFC793] and UDP [RFC768]) as XML [XML] applications. It also + describes methods for transporting BLOAT over Ethernet and IEEE 802 + networks as well as encapsulating BLOAT in IP for gatewaying BLOAT + across the public Internet. + +1.2. Motivation + + The wild popularity of XML as a basis for application-level protocols + such as the Blocks Extensible Exchange Protocol [RFC3080], the Simple + Object Access Protocol [SOAP], and Jabber [JABBER] prompted + investigation into the possibility of extending the use of XML in the + protocol stack. Using XML at both the transport and network layer in + addition to the application layer would provide for an amazing amount + of power and flexibility while removing dependencies on proprietary + and hard-to-understand binary protocols. This protocol unification + would also allow applications to use a single XML parser for all + aspects of their operation, eliminating developer time spent figuring + out the intricacies of each new protocol, and moving the hard work of + + + + +Kennedy Informational [Page 1] + +RFC 3252 Binary Lexical Octet Ad-hoc Transport 1 April 2002 + + + parsing to the XML toolset. The use of XML also mitigates concerns + over "network vs. host" byte ordering which is at the root of many + network application bugs. + +1.3. Relation to Existing Protocols + + The reformulations specified in this RFC follow as closely as + possible the spirit of the RFCs on which they are based, and so MAY + contain elements or attributes that would not be needed in a pure + reworking (e.g. length attributes, which are implicit in XML.) + + The layering of network and transport protocols are maintained in + this RFC despite the optimizations that could be made if the line + were somewhat blurred (i.e. merging TCP and IP into a single, larger + element in the DTD) in order to foster future use of this protocol as + a basis for reformulating other protocols (such as ICMP.) + + Other than the encoding, the behavioral aspects of each of the + existing protocols remain unchanged. Routing, address spaces, TCP + congestion control, etc. behave as specified in the extant standards. + Adapting to new standards and experimental algorithm heuristics for + improving performance will become much easier once the move to BLOAT + has been completed. + +1.4. Requirement Levels + + The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", + "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this + document are to be interpreted as described in BCP 14, RFC 2119 + [RFC2119]. + +2. IPoXML + + This protocol MUST be implemented to be compliant with this RFC. + IPoXML is the root protocol REQUIRED for effective use of TCPoXML + (section 3.) and higher-level application protocols. + + The DTD for this document type can be found in section 7.1. + + The routing of IPoXML can be easily implemented on hosts with an XML + parser, as the regular structure lends itself handily to parsing and + validation of the document/datagram and then processing the + destination address, TTL, and checksum before sending it on to its + next-hop. + + The reformulation of IPv4 was chosen over IPv6 [RFC2460] due to the + wider deployment of IPv4 and the fact that implementing IPv6 as XML + would have exceeded the 1500 byte Ethernet MTU. + + + +Kennedy Informational [Page 2] + +RFC 3252 Binary Lexical Octet Ad-hoc Transport 1 April 2002 + + + All BLOAT implementations MUST use - and specify - the UTF-8 encoding + of RFC 2279 [RFC2279]. All BLOAT document/datagrams MUST be well- + formed and include the XMLDecl. + +2.1. IP Description + + A number of items have changed (for the better) from the original IP + specification. Bit-masks, where present have been converted into + human-readable values. IP addresses are listed in their dotted- + decimal notation [RFC1123]. Length and checksum values are present + as decimal integers. + + To calculate the length and checksum fields of the IP element, a + canonicalized form of the element MUST be used. The canonical form + SHALL have no whitespace (including newline characters) between + elements and only one space character between attributes. There + SHALL NOT be a space following the last attribute in an element. + + An iterative method SHOULD be used to calculate checksums, as the + length field will vary based on the size of the checksum. + + The payload element bears special attention. Due to the character + set restrictions of XML, the payload of IP datagrams (which MAY + contain arbitrary data) MUST be encoded for transport. This RFC + REQUIRES the contents of the payload to be encoded in the base-64 + encoding of RFC 2045 [RFC2045], but removes the requirement that the + encoded output MUST be wrapped on 76-character lines. + + + + + + + + + + + + + + + + + + + + + + + + +Kennedy Informational [Page 3] + +RFC 3252 Binary Lexical Octet Ad-hoc Transport 1 April 2002 + + +2.2. Example Datagram + + The following is an example IPoXML datagram with an empty payload: + + <?xml version="1.0" encoding="UTF-8"?> + <!DOCTYPE ip PUBLIC "-//IETF//DTD BLOAT 1.0 IP//EN" "bloat.dtd"> + <ip> + <header length="474"> + <version value="4"/> + <tos precedence="Routine" delay="Normal" throughput="Normal" + relibility="Normal" reserved="0"/> + <total.length value="461"/> + <id value="1"/> + <flags reserved="0" df="dont" mf="last"/> + <offset value="0"/> + <ttl value="255"/> + <protocol value="6"/> + <checksum value="8707"/> + <source address="10.0.0.22"/> + <destination address="10.0.0.1"/> + <options> + <end copied="0" class="0" number="0"/> + </options> + <padding pad="0"/> + </header> + <payload> + </payload> + </ip> + +3. TCPoXML + + This protocol MUST be implemented to be compliant with this RFC. The + DTD for this document type can be found in section 7.2. + +3.1. TCP Description + + A number of items have changed from the original TCP specification. + Bit-masks, where present have been converted into human-readable + values. Length and checksum and port values are present as decimal + integers. + + To calculate the length and checksum fields of the TCP element, a + canonicalized form of the element MUST be used as in section 2.1. + + An iterative method SHOULD be used to calculate checksums as in + section 2.1. + + The payload element MUST be encoded as in section 2.1. + + + +Kennedy Informational [Page 4] + +RFC 3252 Binary Lexical Octet Ad-hoc Transport 1 April 2002 + + + The TCP offset element was expanded to a maximum of 255 from 16 to + allow for the increased size of the header in XML. + + TCPoXML datagrams encapsulated by IPoXML MAY omit the <?xml?> header + as well as the <!DOCTYPE> declaration. + +3.2. Example Datagram + + The following is an example TCPoXML datagram with an empty payload: + + <?xml version="1.0" encoding="UTF-8"?> + <!DOCTYPE tcp PUBLIC "-//IETF//DTD BLOAT 1.0 TCP//EN" "bloat.dtd"> + <tcp> + <tcp.header> + <src port="31415"/> + <dest port="42424"/> + <sequence number="322622954"/> + <acknowledgement number="689715995"/> + <offset number=""/> + <reserved value="0"/> + <control syn="1" ack="1"/> + <window size="1"/> + <urgent pointer="0"/> + <checksum value="2988"/> + <tcp.options> + <tcp.end kind="0"/> + </tcp.options> + <padding pad="0"/> + </tcp.header> + <payload> + </payload> + </tcp> + +4. UDPoXML + + This protocol MUST be implemented to be compliant with this RFC. The + DTD for this document type can be found in section 7.3. + +4.1. UDP Description + + A number of items have changed from the original UDP specification. + Bit-masks, where present have been converted into human-readable + values. Length and checksum and port values are present as decimal + integers. + + + + + + + +Kennedy Informational [Page 5] + +RFC 3252 Binary Lexical Octet Ad-hoc Transport 1 April 2002 + + + To calculate the length and checksum fields of the UDP element, a + canonicalized form of the element MUST be used as in section 2.1. An + iterative method SHOULD be used to calculate checksums as in section + 2.1. + + The payload element MUST be encoded as in section 2.1. + + UDPoXML datagrams encapsulated by IPoXML MAY omit the <?xml?> header + as well as the <!DOCTYPE> declaration. + +4.2. Example Datagram + + The following is an example UDPoXML datagram with an empty payload: + + <?xml version="1.0" encoding="UTF-8"?> + <!DOCTYPE udp PUBLIC "-//IETF//DTD BLOAT 1.0 UDP//EN" "bloat.dtd"> + <udp> + <udp.header> + <src port="31415"/> + <dest port="42424"/> + <udp.length value="143"/> + <checksum value="2988"/> + </udp.header> + <payload> + </payload> + </udp> + +5. Network Transport + + This document provides for the transmission of BLOAT datagrams over + two common families of physical layer transport. Future RFCs will + address additional transports as routing vendors catch up to the + specification, and we begin to see BLOAT routed across the Internet + backbone. + +5.1. Ethernet + + BLOAT is encapsulated in Ethernet datagrams as in [RFC894] with the + exception that the type field of the Ethernet frame MUST contain the + value 0xBEEF. The first 5 octets of the Ethernet frame payload will + be 0x3c 3f 78 6d 6c ("<?xml".) + +5.2. IEEE 802 + + BLOAT is encapsulated in IEEE 802 Networks as in [RFC1042] except + that the protocol type code for IPoXML is 0xBEEF. + + + + + +Kennedy Informational [Page 6] + +RFC 3252 Binary Lexical Octet Ad-hoc Transport 1 April 2002 + + +6. Gatewaying over IP + + In order to facilitate the gradual introduction of BLOAT into the + public Internet, BLOAT MAY be encapsulated in IP as in [RFC2003] to + gateway between networks that run BLOAT natively on their LANs. + +7. DTDs + + The Transport DTDs (7.2. and 7.3.) build on the definitions in the + Network DTD (7.1.) + + The DTDs are referenced by their PubidLiteral and SystemLiteral (from + [XML]) although it is understood that most IPoXML implementations + will not need to pull down the DTD, as it will normally be embedded + in the implementation, and presents something of a catch-22 if you + need to load part of your network protocol over the network. + +7.1. IPoXML DTD + + <!-- + DTD for IP over XML. + Refer to this DTD as: + + <!DOCTYPE ip PUBLIC "-//IETF//DTD BLOAT 1.0 IP//EN" "bloat.dtd"> + --> + <!-- + DTD data types: + + Digits [0..9]+ + + Precedence "NetworkControl | InternetworkControl | + CRITIC | FlashOverride | Flash | Immediate | + Priority | Routine" + + IP4Addr "dotted-decimal" notation of [RFC1123] + + Class [0..3] + + Sec "Unclassified | Confidential | EFTO | MMMM | PROG | + Restricted | Secret | Top Secret | Reserved" + + Compartments [0..65535] + + Handling [0..65535] + + TCC [0..16777216] + + --> + + + +Kennedy Informational [Page 7] + +RFC 3252 Binary Lexical Octet Ad-hoc Transport 1 April 2002 + + + <!ENTITY % Digits "CDATA"> + <!ENTITY % Precedence "CDATA"> + <!ENTITY % IP4Addr "CDATA"> + <!ENTITY % Class "CDATA"> + <!ENTITY % Sec "CDATA"> + <!ENTITY % Compartments "CDATA"> + <!ENTITY % Handling "CDATA"> + <!ENTITY % TCC "CDATA"> + + <!ELEMENT ip (header, payload)> + + <!ELEMENT header (version, tos, total.length, id, flags, offset, ttl, + protocol, checksum, source, destination, options, + padding)> + <!-- length of header in 32-bit words --> + <!ATTLIST header + length %Digits; #REQUIRED> + + <!ELEMENT version EMPTY> + <!-- ip version. SHOULD be "4" --> + <!ATTLIST version + value %Digits; #REQUIRED> + + <!ELEMENT tos EMPTY> + <!ATTLIST tos + precedence %Precedence; #REQUIRED + delay (normal | low) #REQUIRED + throughput (normal | high) #REQUIRED + relibility (normal | high) #REQUIRED + reserved CDATA #FIXED "0"> + + <!ELEMENT total.length EMPTY> + <!-- + total length of datagram (header and payload) in octets, MUST be + less than 65,535 (and SHOULD be less than 1024 for IPoXML on local + ethernets). + --> + <!ATTLIST total.length + value %Digits; #REQUIRED> + + <!ELEMENT id EMPTY> + <!-- 0 <= id <= 65,535 --> + <!ATTLIST id + value %Digits; #REQUIRED> + + <!ELEMENT flags EMPTY> + <!-- df = don't fragment, mf = more fragments --> + <!ATTLIST flags + + + +Kennedy Informational [Page 8] + +RFC 3252 Binary Lexical Octet Ad-hoc Transport 1 April 2002 + + + reserved CDATA #FIXED "0" + df (may|dont) #REQUIRED + mf (last|more) #REQUIRED> + + <!ELEMENT offset EMPTY> + <!-- 0 <= offset <= 8192 measured in 8 octet (64-bit) chunks --> + <!ATTLIST offset + value %Digits; #REQUIRED> + + <!ELEMENT ttl EMPTY> + <!-- 0 <= ttl <= 255 --> + <!ATTLIST ttl + value %Digits; #REQUIRED> + + <!ELEMENT protocol EMPTY> + <!-- 0 <= protocol <= 255 (per IANA) --> + <!ATTLIST protocol + value %Digits; #REQUIRED> + + <!ELEMENT checksum EMPTY> + <!-- 0 <= checksum <= 65535 (over header only) --> + <!ATTLIST checksum + value %Digits; #REQUIRED> + + <!ELEMENT source EMPTY> + <!ATTLIST source + address %IP4Addr; #REQUIRED> + + <!ELEMENT destination EMPTY> + <!ATTLIST destination + address %IP4Addr; #REQUIRED> + + <!ELEMENT options ( end | noop | security | loose | strict | record + | stream | timestamp )*> + + <!ELEMENT end EMPTY> + <!ATTLIST end + copied (0|1) #REQUIRED + class CDATA #FIXED "0" + number CDATA #FIXED "0"> + + <!ELEMENT noop EMPTY> + <!ATTLIST noop + copied (0|1) #REQUIRED + class CDATA #FIXED "0" + number CDATA #FIXED "1"> + + <!ELEMENT security EMPTY> + + + +Kennedy Informational [Page 9] + +RFC 3252 Binary Lexical Octet Ad-hoc Transport 1 April 2002 + + + <!ATTLIST security + copied CDATA #FIXED "1" + class CDATA #FIXED "0" + number CDATA #FIXED "2" + length CDATA #FIXED "11" + security %Sec; #REQUIRED + compartments %Compartments; #REQUIRED + handling %Handling; #REQUIRED + tcc %TCC; #REQUIRED> + <!ELEMENT loose (hop)+> + <!ATTLIST loose + copied CDATA #FIXED "1" + class CDATA #FIXED "0" + number CDATA #FIXED "3" + length %Digits; #REQUIRED + pointer %Digits; #REQUIRED> + + <!ELEMENT hop EMPTY> + <!ATTLIST hop + address %IP4Addr; #REQUIRED> + + <!ELEMENT strict (hop)+> + <!ATTLIST strict + copied CDATA #FIXED "1" + class CDATA #FIXED "0" + number CDATA #FIXED "9" + length %Digits; #REQUIRED + pointer %Digits; #REQUIRED> + + <!ELEMENT record (hop)+> + <!ATTLIST record + copied CDATA #FIXED "0" + class CDATA #FIXED "0" + number CDATA #FIXED "7" + length %Digits; #REQUIRED + pointer %Digits; #REQUIRED> + + <!ELEMENT stream EMPTY> + <!-- 0 <= id <= 65,535 --> + <!ATTLIST stream + copied CDATA #FIXED "1" + class CDATA #FIXED "0" + number CDATA #FIXED "8" + length CDATA #FIXED "4" + id %Digits; #REQUIRED> + + <!ELEMENT timestamp (tstamp)+> + <!-- 0 <= oflw <=15 --> + + + +Kennedy Informational [Page 10] + +RFC 3252 Binary Lexical Octet Ad-hoc Transport 1 April 2002 + + + <!ATTLIST timestamp + copied CDATA #FIXED "0" + class CDATA #FIXED "2" + number CDATA #FIXED "4" + length %Digits; #REQUIRED + pointer %Digits; #REQUIRED + oflw %Digits; #REQUIRED + flag (0 | 1 | 3) #REQUIRED> + + <!ELEMENT tstamp EMPTY> + <!ATTLIST tstamp + time %Digits; #REQUIRED + address %IP4Addr; #IMPLIED> + <!-- + padding to bring header to 32-bit boundary. + pad MUST be "0"* + --> + <!ELEMENT padding EMPTY> + <!ATTLIST padding + pad CDATA #REQUIRED> + + <!-- payload MUST be encoded as base-64 [RFC2045], as modified + by section 2.1 of this RFC --> + <!ELEMENT payload (CDATA)> + +7.2. TCPoXML DTD + + <!-- + DTD for TCP over XML. + Refer to this DTD as: + + <!DOCTYPE tcp PUBLIC "-//IETF//DTD BLOAT 1.0 TCP//EN" "bloat.dtd"> + --> + + <!-- the pseudoheader is only included for checksum calculations --> + <!ELEMENT tcp (tcp.pseudoheader?, tcp.header, payload)> + + <!ELEMENT tcp.header (src, dest, sequence, acknowledgement, offset, + reserved, control, window, checksum, urgent, + tcp.options, padding)> + + <!ELEMENT src EMPTY> + <!-- 0 <= port <= 65,535 --> + <!ATTLIST src + port %Digits; #REQUIRED> + + <!ELEMENT dest EMPTY> + <!-- 0 <= port <= 65,535 --> + + + +Kennedy Informational [Page 11] + +RFC 3252 Binary Lexical Octet Ad-hoc Transport 1 April 2002 + + + <!ATTLIST dest + port %Digits; #REQUIRED> + + <!ELEMENT sequence EMPTY> + <!-- 0 <= number <= 4294967295 --> + <!ATTLIST sequence + number %Digits; #REQUIRED> + + <!ELEMENT acknowledgement EMPTY> + <!-- 0 <= number <= 4294967295 --> + <!ATTLIST acknowledgement + number %Digits; #REQUIRED> + + <!ELEMENT offset EMPTY> + <!-- 0 <= number <= 255 --> + <!ATTLIST offset + number %Digits; #REQUIRED> + + <!ELEMENT reserved EMPTY> + <!ATTLIST reserved + value CDATA #FIXED "0"> + + <!ELEMENT control EMPTY> + <!ATTLIST control + urg (0|1) #IMPLIED + ack (0|1) #IMPLIED + psh (0|1) #IMPLIED + rst (0|1) #IMPLIED + syn (0|1) #IMPLIED + fin (0|1) #IMPLIED> + + <!ELEMENT window EMPTY> + <!-- 0 <= size <= 65,535 --> + <!ATTLIST window + size %Digits; #REQUIRED> + + <!-- + checksum as in ip, but with + the following pseudo-header added into the tcp element: + --> + <!ELEMENT tcp.pseudoheader (source, destination, protocol, + tcp.length)> + + <!-- + tcp header + data length in octets. does not include the size of + + the pseudoheader. + --> + + + +Kennedy Informational [Page 12] + +RFC 3252 Binary Lexical Octet Ad-hoc Transport 1 April 2002 + + + <!ELEMENT tcp.length EMPTY> + <!ATTLIST tcp.length + value %Digits; #REQUIRED> + + <!ELEMENT urgent EMPTY> + <!-- 0 <= pointer <= 65,535 --> + <!ATTLIST urgent + pointer %Digits; #REQUIRED> + + <!ELEMENT tcp.options (tcp.end | tcp.noop | tcp.mss)+> + + <!ELEMENT tcp.end EMPTY> + <!ATTLIST tcp.end + kind CDATA #FIXED "0"> + + <!ELEMENT tcp.noop EMPTY> + <!ATTLIST tcp.noop + kind CDATA #FIXED "1"> + + <!ELEMENT tcp.mss EMPTY> + <!ATTLIST tcp.mss + kind CDATA #FIXED "2" + length CDATA #FIXED "4" + size %Digits; #REQUIRED> + +7.3. UDPoXML DTD + + <!-- + DTD for UDP over XML. + Refer to this DTD as: + + <!DOCTYPE udp PUBLIC "-//IETF//DTD BLOAT 1.0 UDP//EN" "bloat.dtd"> + --> + + <!ELEMENT udp (udp.pseudoheader?, udp.header, payload)> + + <!ELEMENT udp.header (src, dest, udp.length, checksum)> + + <!ELEMENT udp.pseudoheader (source, destination, protocol, + udp.length)> + + <!-- + udp header + data length in octets. does not include the size of + the pseudoheader. + --> + <!ELEMENT udp.length EMPTY> + <!ATTLIST udp.length + value %Digits; #REQUIRED> + + + +Kennedy Informational [Page 13] + +RFC 3252 Binary Lexical Octet Ad-hoc Transport 1 April 2002 + + +8. Security Considerations + + XML, as a subset of SGML, has the same security considerations as + specified in SGML Media Types [RFC1874]. Security considerations + that apply to IP, TCP and UDP also likely apply to BLOAT as it does + not attempt to correct for issues not related to message format. + +9. References + + [JABBER] Miller, J., "Jabber", draft-miller-jabber-00.txt, + February 2002. (Work in Progress) + + [RFC768] Postel, J., "User Datagram Protocol", STD 6, RFC 768, + August 1980. + + [RFC791] Postel, J., "Internet Protocol", STD 5, RFC 791, + September 1981. + + [RFC793] Postel, J., "Transmission Control Protocol", STD 7, RFC + 793, September 1981. + + [RFC894] Hornig, C., "Standard for the Transmission of IP + Datagrams over Ethernet Networks.", RFC 894, April 1984. + + [RFC1042] Postel, J. and J. Reynolds, "Standard for the + Transmission of IP Datagrams Over IEEE 802 Networks", STD + 43, RFC 1042, February 1988. + + [RFC1123] Braden, R., "Requirements for Internet Hosts - + Application and Support", RFC 1123, October 1989. + + [RFC1874] Levinson, E., "SGML Media Types", RFC 1874, December + 1995. + + [RFC2003] Perkins, C., "IP Encapsulation within IP", RFC 2003, + October 1996. + + [RFC2045] Freed, N. and N. Borenstein, "Multipurpose Internet Mail + Extensions (MIME) Part One: Format of Internet Message + Bodies", RFC 2045, November 1996. + + [RFC2119] Bradner, S., "Key words for use in RFCs to Indicate + Requirement Levels", BCP 14, RFC 2119, March 1997. + + [RFC2279] Yergeau, F., "UTF-8, a transformation format of ISO + 10646", RFC 2279, January 1998. + + + + + +Kennedy Informational [Page 14] + +RFC 3252 Binary Lexical Octet Ad-hoc Transport 1 April 2002 + + + [RFC2460] Deering, S. and R. Hinden, "Internet Protocol, Version 6 + (IPv6) Specification", RFC 2460, December 1998. + + [RFC3080] Rose, M., "The Blocks Extensible Exchange Protocol Core", + RFC 3080, March 2001. + + [SOAP] Box, D., Ehnebuske, D., Kakivaya, G., Layman, A., + Mendelsohn, N., Nielsen, H. F., Thatte, S. Winer, D., + "Simple Object Access Protocol (SOAP) 1.1" World Wide Web + Consortium Note, May 2000 http://www.w3.org/TR/SOAP/ + + [XML] Bray, T., Paoli, J., Sperberg-McQueen, C. M., "Extensible + Markup Language (XML)" World Wide Web Consortium + Recommendation REC- xml-19980210. + http://www.w3.org/TR/1998/REC-xml-19980210 + +10. Author's Address + + Hugh Kennedy + Mimezine + 1060 West Addison + Chicago, IL 60613 + USA + + EMail: kennedyh@engin.umich.edu + + + + + + + + + + + + + + + + + + + + + + + + + + +Kennedy Informational [Page 15] + +RFC 3252 Binary Lexical Octet Ad-hoc Transport 1 April 2002 + + +11. Full Copyright Statement + + Copyright (C) The Internet Society (2002). All Rights Reserved. + + This document and translations of it may be copied and furnished to + others, and derivative works that comment on or otherwise explain it + or assist in its implementation may be prepared, copied, published + and distributed, in whole or in part, without restriction of any + kind, provided that the above copyright notice and this paragraph are + included on all such copies and derivative works. However, this + document itself may not be modified in any way, such as by removing + the copyright notice or references to the Internet Society or other + Internet organizations, except as needed for the purpose of + developing Internet standards in which case the procedures for + copyrights defined in the Internet Standards process must be + followed, or as required to translate it into languages other than + English. + + The limited permissions granted above are perpetual and will not be + revoked by the Internet Society or its successors or assigns. + + This document and the information contained herein is provided on an + "AS IS" basis and THE INTERNET SOCIETY AND THE INTERNET ENGINEERING + TASK FORCE DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING + BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE INFORMATION + HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED WARRANTIES OF + MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. + +Acknowledgement + + Funding for the RFC Editor function is currently provided by the + Internet Society. + + + + + + + + + + + + + + + + + + + +Kennedy Informational [Page 16] + + + + + + + +Network Working Group H. Kennedy +Request for Comments: 3252 Mimezine +Category: Informational 1 April 2002 + + + Binary Lexical Octet Ad-hoc Transport + +Status of this Memo + + This memo provides information for the Internet community. It does + not specify an Internet standard of any kind. Distribution of this + memo is unlimited. + +Copyright Notice + + Copyright (C) The Internet Society (2002). All Rights Reserved. + +Abstract + + This document defines a reformulation of IP and two transport layer + protocols (TCP and UDP) as XML applications. + +1. Introduction + +1.1. Overview + + This document describes the Binary Lexical Octet Ad-hoc Transport + (BLOAT): a reformulation of a widely-deployed network-layer protocol + (IP [RFC791]), and two associated transport layer protocols (TCP + [RFC793] and UDP [RFC768]) as XML [XML] applications. It also + describes methods for transporting BLOAT over Ethernet and IEEE 802 + networks as well as encapsulating BLOAT in IP for gatewaying BLOAT + across the public Internet. + +1.2. Motivation + + The wild popularity of XML as a basis for application-level protocols + such as the Blocks Extensible Exchange Protocol [RFC3080], the Simple + Object Access Protocol [SOAP], and Jabber [JABBER] prompted + investigation into the possibility of extending the use of XML in the + protocol stack. Using XML at both the transport and network layer in + addition to the application layer would provide for an amazing amount + of power and flexibility while removing dependencies on proprietary + and hard-to-understand binary protocols. This protocol unification + would also allow applications to use a single XML parser for all + aspects of their operation, eliminating developer time spent figuring + out the intricacies of each new protocol, and moving the hard work of + + + + +Kennedy Informational [Page 1] + +RFC 3252 Binary Lexical Octet Ad-hoc Transport 1 April 2002 + + + parsing to the XML toolset. The use of XML also mitigates concerns + over "network vs. host" byte ordering which is at the root of many + network application bugs. + +1.3. Relation to Existing Protocols + + The reformulations specified in this RFC follow as closely as + possible the spirit of the RFCs on which they are based, and so MAY + contain elements or attributes that would not be needed in a pure + reworking (e.g. length attributes, which are implicit in XML.) + + The layering of network and transport protocols are maintained in + this RFC despite the optimizations that could be made if the line + were somewhat blurred (i.e. merging TCP and IP into a single, larger + element in the DTD) in order to foster future use of this protocol as + a basis for reformulating other protocols (such as ICMP.) + + Other than the encoding, the behavioral aspects of each of the + existing protocols remain unchanged. Routing, address spaces, TCP + congestion control, etc. behave as specified in the extant standards. + Adapting to new standards and experimental algorithm heuristics for + improving performance will become much easier once the move to BLOAT + has been completed. + +1.4. Requirement Levels + + The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", + "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this + document are to be interpreted as described in BCP 14, RFC 2119 + [RFC2119]. + +2. IPoXML + + This protocol MUST be implemented to be compliant with this RFC. + IPoXML is the root protocol REQUIRED for effective use of TCPoXML + (section 3.) and higher-level application protocols. + + The DTD for this document type can be found in section 7.1. + + The routing of IPoXML can be easily implemented on hosts with an XML + parser, as the regular structure lends itself handily to parsing and + validation of the document/datagram and then processing the + destination address, TTL, and checksum before sending it on to its + next-hop. + + The reformulation of IPv4 was chosen over IPv6 [RFC2460] due to the + wider deployment of IPv4 and the fact that implementing IPv6 as XML + would have exceeded the 1500 byte Ethernet MTU. + + + +Kennedy Informational [Page 2] + +RFC 3252 Binary Lexical Octet Ad-hoc Transport 1 April 2002 + + + All BLOAT implementations MUST use - and specify - the UTF-8 encoding + of RFC 2279 [RFC2279]. All BLOAT document/datagrams MUST be well- + formed and include the XMLDecl. + +2.1. IP Description + + A number of items have changed (for the better) from the original IP + specification. Bit-masks, where present have been converted into + human-readable values. IP addresses are listed in their dotted- + decimal notation [RFC1123]. Length and checksum values are present + as decimal integers. + + To calculate the length and checksum fields of the IP element, a + canonicalized form of the element MUST be used. The canonical form + SHALL have no whitespace (including newline characters) between + elements and only one space character between attributes. There + SHALL NOT be a space following the last attribute in an element. + + An iterative method SHOULD be used to calculate checksums, as the + length field will vary based on the size of the checksum. + + The payload element bears special attention. Due to the character + set restrictions of XML, the payload of IP datagrams (which MAY + contain arbitrary data) MUST be encoded for transport. This RFC + REQUIRES the contents of the payload to be encoded in the base-64 + encoding of RFC 2045 [RFC2045], but removes the requirement that the + encoded output MUST be wrapped on 76-character lines. + + + + + + + + + + + + + + + + + + + + + + + + +Kennedy Informational [Page 3] + +RFC 3252 Binary Lexical Octet Ad-hoc Transport 1 April 2002 + + +2.2. Example Datagram + + The following is an example IPoXML datagram with an empty payload: + + <?xml version="1.0" encoding="UTF-8"?> + <!DOCTYPE ip PUBLIC "-//IETF//DTD BLOAT 1.0 IP//EN" "bloat.dtd"> + <ip> + <header length="474"> + <version value="4"/> + <tos precedence="Routine" delay="Normal" throughput="Normal" + relibility="Normal" reserved="0"/> + <total.length value="461"/> + <id value="1"/> + <flags reserved="0" df="dont" mf="last"/> + <offset value="0"/> + <ttl value="255"/> + <protocol value="6"/> + <checksum value="8707"/> + <source address="10.0.0.22"/> + <destination address="10.0.0.1"/> + <options> + <end copied="0" class="0" number="0"/> + </options> + <padding pad="0"/> + </header> + <payload> + </payload> + </ip> + +3. TCPoXML + + This protocol MUST be implemented to be compliant with this RFC. The + DTD for this document type can be found in section 7.2. + +3.1. TCP Description + + A number of items have changed from the original TCP specification. + Bit-masks, where present have been converted into human-readable + values. Length and checksum and port values are present as decimal + integers. + + To calculate the length and checksum fields of the TCP element, a + canonicalized form of the element MUST be used as in section 2.1. + + An iterative method SHOULD be used to calculate checksums as in + section 2.1. + + The payload element MUST be encoded as in section 2.1. + + + +Kennedy Informational [Page 4] + +RFC 3252 Binary Lexical Octet Ad-hoc Transport 1 April 2002 + + + The TCP offset element was expanded to a maximum of 255 from 16 to + allow for the increased size of the header in XML. + + TCPoXML datagrams encapsulated by IPoXML MAY omit the <?xml?> header + as well as the <!DOCTYPE> declaration. + +3.2. Example Datagram + + The following is an example TCPoXML datagram with an empty payload: + + <?xml version="1.0" encoding="UTF-8"?> + <!DOCTYPE tcp PUBLIC "-//IETF//DTD BLOAT 1.0 TCP//EN" "bloat.dtd"> + <tcp> + <tcp.header> + <src port="31415"/> + <dest port="42424"/> + <sequence number="322622954"/> + <acknowledgement number="689715995"/> + <offset number=""/> + <reserved value="0"/> + <control syn="1" ack="1"/> + <window size="1"/> + <urgent pointer="0"/> + <checksum value="2988"/> + <tcp.options> + <tcp.end kind="0"/> + </tcp.options> + <padding pad="0"/> + </tcp.header> + <payload> + </payload> + </tcp> + +4. UDPoXML + + This protocol MUST be implemented to be compliant with this RFC. The + DTD for this document type can be found in section 7.3. + +4.1. UDP Description + + A number of items have changed from the original UDP specification. + Bit-masks, where present have been converted into human-readable + values. Length and checksum and port values are present as decimal + integers. + + + + + + + +Kennedy Informational [Page 5] + +RFC 3252 Binary Lexical Octet Ad-hoc Transport 1 April 2002 + + + To calculate the length and checksum fields of the UDP element, a + canonicalized form of the element MUST be used as in section 2.1. An + iterative method SHOULD be used to calculate checksums as in section + 2.1. + + The payload element MUST be encoded as in section 2.1. + + UDPoXML datagrams encapsulated by IPoXML MAY omit the <?xml?> header + as well as the <!DOCTYPE> declaration. + +4.2. Example Datagram + + The following is an example UDPoXML datagram with an empty payload: + + <?xml version="1.0" encoding="UTF-8"?> + <!DOCTYPE udp PUBLIC "-//IETF//DTD BLOAT 1.0 UDP//EN" "bloat.dtd"> + <udp> + <udp.header> + <src port="31415"/> + <dest port="42424"/> + <udp.length value="143"/> + <checksum value="2988"/> + </udp.header> + <payload> + </payload> + </udp> + +5. Network Transport + + This document provides for the transmission of BLOAT datagrams over + two common families of physical layer transport. Future RFCs will + address additional transports as routing vendors catch up to the + specification, and we begin to see BLOAT routed across the Internet + backbone. + +5.1. Ethernet + + BLOAT is encapsulated in Ethernet datagrams as in [RFC894] with the + exception that the type field of the Ethernet frame MUST contain the + value 0xBEEF. The first 5 octets of the Ethernet frame payload will + be 0x3c 3f 78 6d 6c ("<?xml".) + +5.2. IEEE 802 + + BLOAT is encapsulated in IEEE 802 Networks as in [RFC1042] except + that the protocol type code for IPoXML is 0xBEEF. + + + + + +Kennedy Informational [Page 6] + +RFC 3252 Binary Lexical Octet Ad-hoc Transport 1 April 2002 + + +6. Gatewaying over IP + + In order to facilitate the gradual introduction of BLOAT into the + public Internet, BLOAT MAY be encapsulated in IP as in [RFC2003] to + gateway between networks that run BLOAT natively on their LANs. + +7. DTDs + + The Transport DTDs (7.2. and 7.3.) build on the definitions in the + Network DTD (7.1.) + + The DTDs are referenced by their PubidLiteral and SystemLiteral (from + [XML]) although it is understood that most IPoXML implementations + will not need to pull down the DTD, as it will normally be embedded + in the implementation, and presents something of a catch-22 if you + need to load part of your network protocol over the network. + +7.1. IPoXML DTD + + <!-- + DTD for IP over XML. + Refer to this DTD as: + + <!DOCTYPE ip PUBLIC "-//IETF//DTD BLOAT 1.0 IP//EN" "bloat.dtd"> + --> + <!-- + DTD data types: + + Digits [0..9]+ + + Precedence "NetworkControl | InternetworkControl | + CRITIC | FlashOverride | Flash | Immediate | + Priority | Routine" + + IP4Addr "dotted-decimal" notation of [RFC1123] + + Class [0..3] + + Sec "Unclassified | Confidential | EFTO | MMMM | PROG | + Restricted | Secret | Top Secret | Reserved" + + Compartments [0..65535] + + Handling [0..65535] + + TCC [0..16777216] + + --> + + + +Kennedy Informational [Page 7] + +RFC 3252 Binary Lexical Octet Ad-hoc Transport 1 April 2002 + + + <!ENTITY % Digits "CDATA"> + <!ENTITY % Precedence "CDATA"> + <!ENTITY % IP4Addr "CDATA"> + <!ENTITY % Class "CDATA"> + <!ENTITY % Sec "CDATA"> + <!ENTITY % Compartments "CDATA"> + <!ENTITY % Handling "CDATA"> + <!ENTITY % TCC "CDATA"> + + <!ELEMENT ip (header, payload)> + + <!ELEMENT header (version, tos, total.length, id, flags, offset, ttl, + protocol, checksum, source, destination, options, + padding)> + <!-- length of header in 32-bit words --> + <!ATTLIST header + length %Digits; #REQUIRED> + + <!ELEMENT version EMPTY> + <!-- ip version. SHOULD be "4" --> + <!ATTLIST version + value %Digits; #REQUIRED> + + <!ELEMENT tos EMPTY> + <!ATTLIST tos + precedence %Precedence; #REQUIRED + delay (normal | low) #REQUIRED + throughput (normal | high) #REQUIRED + relibility (normal | high) #REQUIRED + reserved CDATA #FIXED "0"> + + <!ELEMENT total.length EMPTY> + <!-- + total length of datagram (header and payload) in octets, MUST be + less than 65,535 (and SHOULD be less than 1024 for IPoXML on local + ethernets). + --> + <!ATTLIST total.length + value %Digits; #REQUIRED> + + <!ELEMENT id EMPTY> + <!-- 0 <= id <= 65,535 --> + <!ATTLIST id + value %Digits; #REQUIRED> + + <!ELEMENT flags EMPTY> + <!-- df = don't fragment, mf = more fragments --> + <!ATTLIST flags + + + +Kennedy Informational [Page 8] + +RFC 3252 Binary Lexical Octet Ad-hoc Transport 1 April 2002 + + + reserved CDATA #FIXED "0" + df (may|dont) #REQUIRED + mf (last|more) #REQUIRED> + + <!ELEMENT offset EMPTY> + <!-- 0 <= offset <= 8192 measured in 8 octet (64-bit) chunks --> + <!ATTLIST offset + value %Digits; #REQUIRED> + + <!ELEMENT ttl EMPTY> + <!-- 0 <= ttl <= 255 --> + <!ATTLIST ttl + value %Digits; #REQUIRED> + + <!ELEMENT protocol EMPTY> + <!-- 0 <= protocol <= 255 (per IANA) --> + <!ATTLIST protocol + value %Digits; #REQUIRED> + + <!ELEMENT checksum EMPTY> + <!-- 0 <= checksum <= 65535 (over header only) --> + <!ATTLIST checksum + value %Digits; #REQUIRED> + + <!ELEMENT source EMPTY> + <!ATTLIST source + address %IP4Addr; #REQUIRED> + + <!ELEMENT destination EMPTY> + <!ATTLIST destination + address %IP4Addr; #REQUIRED> + + <!ELEMENT options ( end | noop | security | loose | strict | record + | stream | timestamp )*> + + <!ELEMENT end EMPTY> + <!ATTLIST end + copied (0|1) #REQUIRED + class CDATA #FIXED "0" + number CDATA #FIXED "0"> + + <!ELEMENT noop EMPTY> + <!ATTLIST noop + copied (0|1) #REQUIRED + class CDATA #FIXED "0" + number CDATA #FIXED "1"> + + <!ELEMENT security EMPTY> + + + +Kennedy Informational [Page 9] + +RFC 3252 Binary Lexical Octet Ad-hoc Transport 1 April 2002 + + + <!ATTLIST security + copied CDATA #FIXED "1" + class CDATA #FIXED "0" + number CDATA #FIXED "2" + length CDATA #FIXED "11" + security %Sec; #REQUIRED + compartments %Compartments; #REQUIRED + handling %Handling; #REQUIRED + tcc %TCC; #REQUIRED> + <!ELEMENT loose (hop)+> + <!ATTLIST loose + copied CDATA #FIXED "1" + class CDATA #FIXED "0" + number CDATA #FIXED "3" + length %Digits; #REQUIRED + pointer %Digits; #REQUIRED> + + <!ELEMENT hop EMPTY> + <!ATTLIST hop + address %IP4Addr; #REQUIRED> + + <!ELEMENT strict (hop)+> + <!ATTLIST strict + copied CDATA #FIXED "1" + class CDATA #FIXED "0" + number CDATA #FIXED "9" + length %Digits; #REQUIRED + pointer %Digits; #REQUIRED> + + <!ELEMENT record (hop)+> + <!ATTLIST record + copied CDATA #FIXED "0" + class CDATA #FIXED "0" + number CDATA #FIXED "7" + length %Digits; #REQUIRED + pointer %Digits; #REQUIRED> + + <!ELEMENT stream EMPTY> + <!-- 0 <= id <= 65,535 --> + <!ATTLIST stream + copied CDATA #FIXED "1" + class CDATA #FIXED "0" + number CDATA #FIXED "8" + length CDATA #FIXED "4" + id %Digits; #REQUIRED> + + <!ELEMENT timestamp (tstamp)+> + <!-- 0 <= oflw <=15 --> + + + +Kennedy Informational [Page 10] + +RFC 3252 Binary Lexical Octet Ad-hoc Transport 1 April 2002 + + + <!ATTLIST timestamp + copied CDATA #FIXED "0" + class CDATA #FIXED "2" + number CDATA #FIXED "4" + length %Digits; #REQUIRED + pointer %Digits; #REQUIRED + oflw %Digits; #REQUIRED + flag (0 | 1 | 3) #REQUIRED> + + <!ELEMENT tstamp EMPTY> + <!ATTLIST tstamp + time %Digits; #REQUIRED + address %IP4Addr; #IMPLIED> + <!-- + padding to bring header to 32-bit boundary. + pad MUST be "0"* + --> + <!ELEMENT padding EMPTY> + <!ATTLIST padding + pad CDATA #REQUIRED> + + <!-- payload MUST be encoded as base-64 [RFC2045], as modified + by section 2.1 of this RFC --> + <!ELEMENT payload (CDATA)> + +7.2. TCPoXML DTD + + <!-- + DTD for TCP over XML. + Refer to this DTD as: + + <!DOCTYPE tcp PUBLIC "-//IETF//DTD BLOAT 1.0 TCP//EN" "bloat.dtd"> + --> + + <!-- the pseudoheader is only included for checksum calculations --> + <!ELEMENT tcp (tcp.pseudoheader?, tcp.header, payload)> + + <!ELEMENT tcp.header (src, dest, sequence, acknowledgement, offset, + reserved, control, window, checksum, urgent, + tcp.options, padding)> + + <!ELEMENT src EMPTY> + <!-- 0 <= port <= 65,535 --> + <!ATTLIST src + port %Digits; #REQUIRED> + + <!ELEMENT dest EMPTY> + <!-- 0 <= port <= 65,535 --> + + + +Kennedy Informational [Page 11] + +RFC 3252 Binary Lexical Octet Ad-hoc Transport 1 April 2002 + + + <!ATTLIST dest + port %Digits; #REQUIRED> + + <!ELEMENT sequence EMPTY> + <!-- 0 <= number <= 4294967295 --> + <!ATTLIST sequence + number %Digits; #REQUIRED> + + <!ELEMENT acknowledgement EMPTY> + <!-- 0 <= number <= 4294967295 --> + <!ATTLIST acknowledgement + number %Digits; #REQUIRED> + + <!ELEMENT offset EMPTY> + <!-- 0 <= number <= 255 --> + <!ATTLIST offset + number %Digits; #REQUIRED> + + <!ELEMENT reserved EMPTY> + <!ATTLIST reserved + value CDATA #FIXED "0"> + + <!ELEMENT control EMPTY> + <!ATTLIST control + urg (0|1) #IMPLIED + ack (0|1) #IMPLIED + psh (0|1) #IMPLIED + rst (0|1) #IMPLIED + syn (0|1) #IMPLIED + fin (0|1) #IMPLIED> + + <!ELEMENT window EMPTY> + <!-- 0 <= size <= 65,535 --> + <!ATTLIST window + size %Digits; #REQUIRED> + + <!-- + checksum as in ip, but with + the following pseudo-header added into the tcp element: + --> + <!ELEMENT tcp.pseudoheader (source, destination, protocol, + tcp.length)> + + <!-- + tcp header + data length in octets. does not include the size of + + the pseudoheader. + --> + + + +Kennedy Informational [Page 12] + +RFC 3252 Binary Lexical Octet Ad-hoc Transport 1 April 2002 + + + <!ELEMENT tcp.length EMPTY> + <!ATTLIST tcp.length + value %Digits; #REQUIRED> + + <!ELEMENT urgent EMPTY> + <!-- 0 <= pointer <= 65,535 --> + <!ATTLIST urgent + pointer %Digits; #REQUIRED> + + <!ELEMENT tcp.options (tcp.end | tcp.noop | tcp.mss)+> + + <!ELEMENT tcp.end EMPTY> + <!ATTLIST tcp.end + kind CDATA #FIXED "0"> + + <!ELEMENT tcp.noop EMPTY> + <!ATTLIST tcp.noop + kind CDATA #FIXED "1"> + + <!ELEMENT tcp.mss EMPTY> + <!ATTLIST tcp.mss + kind CDATA #FIXED "2" + length CDATA #FIXED "4" + size %Digits; #REQUIRED> + +7.3. UDPoXML DTD + + <!-- + DTD for UDP over XML. + Refer to this DTD as: + + <!DOCTYPE udp PUBLIC "-//IETF//DTD BLOAT 1.0 UDP//EN" "bloat.dtd"> + --> + + <!ELEMENT udp (udp.pseudoheader?, udp.header, payload)> + + <!ELEMENT udp.header (src, dest, udp.length, checksum)> + + <!ELEMENT udp.pseudoheader (source, destination, protocol, + udp.length)> + + <!-- + udp header + data length in octets. does not include the size of + the pseudoheader. + --> + <!ELEMENT udp.length EMPTY> + <!ATTLIST udp.length + value %Digits; #REQUIRED> + + + +Kennedy Informational [Page 13] + +RFC 3252 Binary Lexical Octet Ad-hoc Transport 1 April 2002 + + +8. Security Considerations + + XML, as a subset of SGML, has the same security considerations as + specified in SGML Media Types [RFC1874]. Security considerations + that apply to IP, TCP and UDP also likely apply to BLOAT as it does + not attempt to correct for issues not related to message format. + +9. References + + [JABBER] Miller, J., "Jabber", draft-miller-jabber-00.txt, + February 2002. (Work in Progress) + + [RFC768] Postel, J., "User Datagram Protocol", STD 6, RFC 768, + August 1980. + + [RFC791] Postel, J., "Internet Protocol", STD 5, RFC 791, + September 1981. + + [RFC793] Postel, J., "Transmission Control Protocol", STD 7, RFC + 793, September 1981. + + [RFC894] Hornig, C., "Standard for the Transmission of IP + Datagrams over Ethernet Networks.", RFC 894, April 1984. + + [RFC1042] Postel, J. and J. Reynolds, "Standard for the + Transmission of IP Datagrams Over IEEE 802 Networks", STD + 43, RFC 1042, February 1988. + + [RFC1123] Braden, R., "Requirements for Internet Hosts - + Application and Support", RFC 1123, October 1989. + + [RFC1874] Levinson, E., "SGML Media Types", RFC 1874, December + 1995. + + [RFC2003] Perkins, C., "IP Encapsulation within IP", RFC 2003, + October 1996. + + [RFC2045] Freed, N. and N. Borenstein, "Multipurpose Internet Mail + Extensions (MIME) Part One: Format of Internet Message + Bodies", RFC 2045, November 1996. + + [RFC2119] Bradner, S., "Key words for use in RFCs to Indicate + Requirement Levels", BCP 14, RFC 2119, March 1997. + + [RFC2279] Yergeau, F., "UTF-8, a transformation format of ISO + 10646", RFC 2279, January 1998. + + + + + +Kennedy Informational [Page 14] + +RFC 3252 Binary Lexical Octet Ad-hoc Transport 1 April 2002 + + + [RFC2460] Deering, S. and R. Hinden, "Internet Protocol, Version 6 + (IPv6) Specification", RFC 2460, December 1998. + + [RFC3080] Rose, M., "The Blocks Extensible Exchange Protocol Core", + RFC 3080, March 2001. + + [SOAP] Box, D., Ehnebuske, D., Kakivaya, G., Layman, A., + Mendelsohn, N., Nielsen, H. F., Thatte, S. Winer, D., + "Simple Object Access Protocol (SOAP) 1.1" World Wide Web + Consortium Note, May 2000 http://www.w3.org/TR/SOAP/ + + [XML] Bray, T., Paoli, J., Sperberg-McQueen, C. M., "Extensible + Markup Language (XML)" World Wide Web Consortium + Recommendation REC- xml-19980210. + http://www.w3.org/TR/1998/REC-xml-19980210 + +10. Author's Address + + Hugh Kennedy + Mimezine + 1060 West Addison + Chicago, IL 60613 + USA + + EMail: kennedyh@engin.umich.edu + + + + + + + + + + + + + + + + + + + + + + + + + + +Kennedy Informational [Page 15] + +RFC 3252 Binary Lexical Octet Ad-hoc Transport 1 April 2002 + + +11. Full Copyright Statement + + Copyright (C) The Internet Society (2002). All Rights Reserved. + + This document and translations of it may be copied and furnished to + others, and derivative works that comment on or otherwise explain it + or assist in its implementation may be prepared, copied, published + and distributed, in whole or in part, without restriction of any + kind, provided that the above copyright notice and this paragraph are + included on all such copies and derivative works. However, this + document itself may not be modified in any way, such as by removing + the copyright notice or references to the Internet Society or other + Internet organizations, except as needed for the purpose of + developing Internet standards in which case the procedures for + copyrights defined in the Internet Standards process must be + followed, or as required to translate it into languages other than + English. + + The limited permissions granted above are perpetual and will not be + revoked by the Internet Society or its successors or assigns. + + This document and the information contained herein is provided on an + "AS IS" basis and THE INTERNET SOCIETY AND THE INTERNET ENGINEERING + TASK FORCE DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING + BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE INFORMATION + HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED WARRANTIES OF + MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. + +Acknowledgement + + Funding for the RFC Editor function is currently provided by the + Internet Society. + + + + + + + + + + + + + + + + + + + +Kennedy Informational [Page 16] + + + + + + + +Network Working Group H. Kennedy +Request for Comments: 3252 Mimezine +Category: Informational 1 April 2002 + + + Binary Lexical Octet Ad-hoc Transport + +Status of this Memo + + This memo provides information for the Internet community. It does + not specify an Internet standard of any kind. Distribution of this + memo is unlimited. + +Copyright Notice + + Copyright (C) The Internet Society (2002). All Rights Reserved. + +Abstract + + This document defines a reformulation of IP and two transport layer + protocols (TCP and UDP) as XML applications. + +1. Introduction + +1.1. Overview + + This document describes the Binary Lexical Octet Ad-hoc Transport + (BLOAT): a reformulation of a widely-deployed network-layer protocol + (IP [RFC791]), and two associated transport layer protocols (TCP + [RFC793] and UDP [RFC768]) as XML [XML] applications. It also + describes methods for transporting BLOAT over Ethernet and IEEE 802 + networks as well as encapsulating BLOAT in IP for gatewaying BLOAT + across the public Internet. + +1.2. Motivation + + The wild popularity of XML as a basis for application-level protocols + such as the Blocks Extensible Exchange Protocol [RFC3080], the Simple + Object Access Protocol [SOAP], and Jabber [JABBER] prompted + investigation into the possibility of extending the use of XML in the + protocol stack. Using XML at both the transport and network layer in + addition to the application layer would provide for an amazing amount + of power and flexibility while removing dependencies on proprietary + and hard-to-understand binary protocols. This protocol unification + would also allow applications to use a single XML parser for all + aspects of their operation, eliminating developer time spent figuring + out the intricacies of each new protocol, and moving the hard work of + + + + +Kennedy Informational [Page 1] + +RFC 3252 Binary Lexical Octet Ad-hoc Transport 1 April 2002 + + + parsing to the XML toolset. The use of XML also mitigates concerns + over "network vs. host" byte ordering which is at the root of many + network application bugs. + +1.3. Relation to Existing Protocols + + The reformulations specified in this RFC follow as closely as + possible the spirit of the RFCs on which they are based, and so MAY + contain elements or attributes that would not be needed in a pure + reworking (e.g. length attributes, which are implicit in XML.) + + The layering of network and transport protocols are maintained in + this RFC despite the optimizations that could be made if the line + were somewhat blurred (i.e. merging TCP and IP into a single, larger + element in the DTD) in order to foster future use of this protocol as + a basis for reformulating other protocols (such as ICMP.) + + Other than the encoding, the behavioral aspects of each of the + existing protocols remain unchanged. Routing, address spaces, TCP + congestion control, etc. behave as specified in the extant standards. + Adapting to new standards and experimental algorithm heuristics for + improving performance will become much easier once the move to BLOAT + has been completed. + +1.4. Requirement Levels + + The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", + "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this + document are to be interpreted as described in BCP 14, RFC 2119 + [RFC2119]. + +2. IPoXML + + This protocol MUST be implemented to be compliant with this RFC. + IPoXML is the root protocol REQUIRED for effective use of TCPoXML + (section 3.) and higher-level application protocols. + + The DTD for this document type can be found in section 7.1. + + The routing of IPoXML can be easily implemented on hosts with an XML + parser, as the regular structure lends itself handily to parsing and + validation of the document/datagram and then processing the + destination address, TTL, and checksum before sending it on to its + next-hop. + + The reformulation of IPv4 was chosen over IPv6 [RFC2460] due to the + wider deployment of IPv4 and the fact that implementing IPv6 as XML + would have exceeded the 1500 byte Ethernet MTU. + + + +Kennedy Informational [Page 2] + +RFC 3252 Binary Lexical Octet Ad-hoc Transport 1 April 2002 + + + All BLOAT implementations MUST use - and specify - the UTF-8 encoding + of RFC 2279 [RFC2279]. All BLOAT document/datagrams MUST be well- + formed and include the XMLDecl. + +2.1. IP Description + + A number of items have changed (for the better) from the original IP + specification. Bit-masks, where present have been converted into + human-readable values. IP addresses are listed in their dotted- + decimal notation [RFC1123]. Length and checksum values are present + as decimal integers. + + To calculate the length and checksum fields of the IP element, a + canonicalized form of the element MUST be used. The canonical form + SHALL have no whitespace (including newline characters) between + elements and only one space character between attributes. There + SHALL NOT be a space following the last attribute in an element. + + An iterative method SHOULD be used to calculate checksums, as the + length field will vary based on the size of the checksum. + + The payload element bears special attention. Due to the character + set restrictions of XML, the payload of IP datagrams (which MAY + contain arbitrary data) MUST be encoded for transport. This RFC + REQUIRES the contents of the payload to be encoded in the base-64 + encoding of RFC 2045 [RFC2045], but removes the requirement that the + encoded output MUST be wrapped on 76-character lines. + + + + + + + + + + + + + + + + + + + + + + + + +Kennedy Informational [Page 3] + +RFC 3252 Binary Lexical Octet Ad-hoc Transport 1 April 2002 + + +2.2. Example Datagram + + The following is an example IPoXML datagram with an empty payload: + + <?xml version="1.0" encoding="UTF-8"?> + <!DOCTYPE ip PUBLIC "-//IETF//DTD BLOAT 1.0 IP//EN" "bloat.dtd"> + <ip> + <header length="474"> + <version value="4"/> + <tos precedence="Routine" delay="Normal" throughput="Normal" + relibility="Normal" reserved="0"/> + <total.length value="461"/> + <id value="1"/> + <flags reserved="0" df="dont" mf="last"/> + <offset value="0"/> + <ttl value="255"/> + <protocol value="6"/> + <checksum value="8707"/> + <source address="10.0.0.22"/> + <destination address="10.0.0.1"/> + <options> + <end copied="0" class="0" number="0"/> + </options> + <padding pad="0"/> + </header> + <payload> + </payload> + </ip> + +3. TCPoXML + + This protocol MUST be implemented to be compliant with this RFC. The + DTD for this document type can be found in section 7.2. + +3.1. TCP Description + + A number of items have changed from the original TCP specification. + Bit-masks, where present have been converted into human-readable + values. Length and checksum and port values are present as decimal + integers. + + To calculate the length and checksum fields of the TCP element, a + canonicalized form of the element MUST be used as in section 2.1. + + An iterative method SHOULD be used to calculate checksums as in + section 2.1. + + The payload element MUST be encoded as in section 2.1. + + + +Kennedy Informational [Page 4] + +RFC 3252 Binary Lexical Octet Ad-hoc Transport 1 April 2002 + + + The TCP offset element was expanded to a maximum of 255 from 16 to + allow for the increased size of the header in XML. + + TCPoXML datagrams encapsulated by IPoXML MAY omit the <?xml?> header + as well as the <!DOCTYPE> declaration. + +3.2. Example Datagram + + The following is an example TCPoXML datagram with an empty payload: + + <?xml version="1.0" encoding="UTF-8"?> + <!DOCTYPE tcp PUBLIC "-//IETF//DTD BLOAT 1.0 TCP//EN" "bloat.dtd"> + <tcp> + <tcp.header> + <src port="31415"/> + <dest port="42424"/> + <sequence number="322622954"/> + <acknowledgement number="689715995"/> + <offset number=""/> + <reserved value="0"/> + <control syn="1" ack="1"/> + <window size="1"/> + <urgent pointer="0"/> + <checksum value="2988"/> + <tcp.options> + <tcp.end kind="0"/> + </tcp.options> + <padding pad="0"/> + </tcp.header> + <payload> + </payload> + </tcp> + +4. UDPoXML + + This protocol MUST be implemented to be compliant with this RFC. The + DTD for this document type can be found in section 7.3. + +4.1. UDP Description + + A number of items have changed from the original UDP specification. + Bit-masks, where present have been converted into human-readable + values. Length and checksum and port values are present as decimal + integers. + + + + + + + +Kennedy Informational [Page 5] + +RFC 3252 Binary Lexical Octet Ad-hoc Transport 1 April 2002 + + + To calculate the length and checksum fields of the UDP element, a + canonicalized form of the element MUST be used as in section 2.1. An + iterative method SHOULD be used to calculate checksums as in section + 2.1. + + The payload element MUST be encoded as in section 2.1. + + UDPoXML datagrams encapsulated by IPoXML MAY omit the <?xml?> header + as well as the <!DOCTYPE> declaration. + +4.2. Example Datagram + + The following is an example UDPoXML datagram with an empty payload: + + <?xml version="1.0" encoding="UTF-8"?> + <!DOCTYPE udp PUBLIC "-//IETF//DTD BLOAT 1.0 UDP//EN" "bloat.dtd"> + <udp> + <udp.header> + <src port="31415"/> + <dest port="42424"/> + <udp.length value="143"/> + <checksum value="2988"/> + </udp.header> + <payload> + </payload> + </udp> + +5. Network Transport + + This document provides for the transmission of BLOAT datagrams over + two common families of physical layer transport. Future RFCs will + address additional transports as routing vendors catch up to the + specification, and we begin to see BLOAT routed across the Internet + backbone. + +5.1. Ethernet + + BLOAT is encapsulated in Ethernet datagrams as in [RFC894] with the + exception that the type field of the Ethernet frame MUST contain the + value 0xBEEF. The first 5 octets of the Ethernet frame payload will + be 0x3c 3f 78 6d 6c ("<?xml".) + +5.2. IEEE 802 + + BLOAT is encapsulated in IEEE 802 Networks as in [RFC1042] except + that the protocol type code for IPoXML is 0xBEEF. + + + + + +Kennedy Informational [Page 6] + +RFC 3252 Binary Lexical Octet Ad-hoc Transport 1 April 2002 + + +6. Gatewaying over IP + + In order to facilitate the gradual introduction of BLOAT into the + public Internet, BLOAT MAY be encapsulated in IP as in [RFC2003] to + gateway between networks that run BLOAT natively on their LANs. + +7. DTDs + + The Transport DTDs (7.2. and 7.3.) build on the definitions in the + Network DTD (7.1.) + + The DTDs are referenced by their PubidLiteral and SystemLiteral (from + [XML]) although it is understood that most IPoXML implementations + will not need to pull down the DTD, as it will normally be embedded + in the implementation, and presents something of a catch-22 if you + need to load part of your network protocol over the network. + +7.1. IPoXML DTD + + <!-- + DTD for IP over XML. + Refer to this DTD as: + + <!DOCTYPE ip PUBLIC "-//IETF//DTD BLOAT 1.0 IP//EN" "bloat.dtd"> + --> + <!-- + DTD data types: + + Digits [0..9]+ + + Precedence "NetworkControl | InternetworkControl | + CRITIC | FlashOverride | Flash | Immediate | + Priority | Routine" + + IP4Addr "dotted-decimal" notation of [RFC1123] + + Class [0..3] + + Sec "Unclassified | Confidential | EFTO | MMMM | PROG | + Restricted | Secret | Top Secret | Reserved" + + Compartments [0..65535] + + Handling [0..65535] + + TCC [0..16777216] + + --> + + + +Kennedy Informational [Page 7] + +RFC 3252 Binary Lexical Octet Ad-hoc Transport 1 April 2002 + + + <!ENTITY % Digits "CDATA"> + <!ENTITY % Precedence "CDATA"> + <!ENTITY % IP4Addr "CDATA"> + <!ENTITY % Class "CDATA"> + <!ENTITY % Sec "CDATA"> + <!ENTITY % Compartments "CDATA"> + <!ENTITY % Handling "CDATA"> + <!ENTITY % TCC "CDATA"> + + <!ELEMENT ip (header, payload)> + + <!ELEMENT header (version, tos, total.length, id, flags, offset, ttl, + protocol, checksum, source, destination, options, + padding)> + <!-- length of header in 32-bit words --> + <!ATTLIST header + length %Digits; #REQUIRED> + + <!ELEMENT version EMPTY> + <!-- ip version. SHOULD be "4" --> + <!ATTLIST version + value %Digits; #REQUIRED> + + <!ELEMENT tos EMPTY> + <!ATTLIST tos + precedence %Precedence; #REQUIRED + delay (normal | low) #REQUIRED + throughput (normal | high) #REQUIRED + relibility (normal | high) #REQUIRED + reserved CDATA #FIXED "0"> + + <!ELEMENT total.length EMPTY> + <!-- + total length of datagram (header and payload) in octets, MUST be + less than 65,535 (and SHOULD be less than 1024 for IPoXML on local + ethernets). + --> + <!ATTLIST total.length + value %Digits; #REQUIRED> + + <!ELEMENT id EMPTY> + <!-- 0 <= id <= 65,535 --> + <!ATTLIST id + value %Digits; #REQUIRED> + + <!ELEMENT flags EMPTY> + <!-- df = don't fragment, mf = more fragments --> + <!ATTLIST flags + + + +Kennedy Informational [Page 8] + +RFC 3252 Binary Lexical Octet Ad-hoc Transport 1 April 2002 + + + reserved CDATA #FIXED "0" + df (may|dont) #REQUIRED + mf (last|more) #REQUIRED> + + <!ELEMENT offset EMPTY> + <!-- 0 <= offset <= 8192 measured in 8 octet (64-bit) chunks --> + <!ATTLIST offset + value %Digits; #REQUIRED> + + <!ELEMENT ttl EMPTY> + <!-- 0 <= ttl <= 255 --> + <!ATTLIST ttl + value %Digits; #REQUIRED> + + <!ELEMENT protocol EMPTY> + <!-- 0 <= protocol <= 255 (per IANA) --> + <!ATTLIST protocol + value %Digits; #REQUIRED> + + <!ELEMENT checksum EMPTY> + <!-- 0 <= checksum <= 65535 (over header only) --> + <!ATTLIST checksum + value %Digits; #REQUIRED> + + <!ELEMENT source EMPTY> + <!ATTLIST source + address %IP4Addr; #REQUIRED> + + <!ELEMENT destination EMPTY> + <!ATTLIST destination + address %IP4Addr; #REQUIRED> + + <!ELEMENT options ( end | noop | security | loose | strict | record + | stream | timestamp )*> + + <!ELEMENT end EMPTY> + <!ATTLIST end + copied (0|1) #REQUIRED + class CDATA #FIXED "0" + number CDATA #FIXED "0"> + + <!ELEMENT noop EMPTY> + <!ATTLIST noop + copied (0|1) #REQUIRED + class CDATA #FIXED "0" + number CDATA #FIXED "1"> + + <!ELEMENT security EMPTY> + + + +Kennedy Informational [Page 9] + +RFC 3252 Binary Lexical Octet Ad-hoc Transport 1 April 2002 + + + <!ATTLIST security + copied CDATA #FIXED "1" + class CDATA #FIXED "0" + number CDATA #FIXED "2" + length CDATA #FIXED "11" + security %Sec; #REQUIRED + compartments %Compartments; #REQUIRED + handling %Handling; #REQUIRED + tcc %TCC; #REQUIRED> + <!ELEMENT loose (hop)+> + <!ATTLIST loose + copied CDATA #FIXED "1" + class CDATA #FIXED "0" + number CDATA #FIXED "3" + length %Digits; #REQUIRED + pointer %Digits; #REQUIRED> + + <!ELEMENT hop EMPTY> + <!ATTLIST hop + address %IP4Addr; #REQUIRED> + + <!ELEMENT strict (hop)+> + <!ATTLIST strict + copied CDATA #FIXED "1" + class CDATA #FIXED "0" + number CDATA #FIXED "9" + length %Digits; #REQUIRED + pointer %Digits; #REQUIRED> + + <!ELEMENT record (hop)+> + <!ATTLIST record + copied CDATA #FIXED "0" + class CDATA #FIXED "0" + number CDATA #FIXED "7" + length %Digits; #REQUIRED + pointer %Digits; #REQUIRED> + + <!ELEMENT stream EMPTY> + <!-- 0 <= id <= 65,535 --> + <!ATTLIST stream + copied CDATA #FIXED "1" + class CDATA #FIXED "0" + number CDATA #FIXED "8" + length CDATA #FIXED "4" + id %Digits; #REQUIRED> + + <!ELEMENT timestamp (tstamp)+> + <!-- 0 <= oflw <=15 --> + + + +Kennedy Informational [Page 10] + +RFC 3252 Binary Lexical Octet Ad-hoc Transport 1 April 2002 + + + <!ATTLIST timestamp + copied CDATA #FIXED "0" + class CDATA #FIXED "2" + number CDATA #FIXED "4" + length %Digits; #REQUIRED + pointer %Digits; #REQUIRED + oflw %Digits; #REQUIRED + flag (0 | 1 | 3) #REQUIRED> + + <!ELEMENT tstamp EMPTY> + <!ATTLIST tstamp + time %Digits; #REQUIRED + address %IP4Addr; #IMPLIED> + <!-- + padding to bring header to 32-bit boundary. + pad MUST be "0"* + --> + <!ELEMENT padding EMPTY> + <!ATTLIST padding + pad CDATA #REQUIRED> + + <!-- payload MUST be encoded as base-64 [RFC2045], as modified + by section 2.1 of this RFC --> + <!ELEMENT payload (CDATA)> + +7.2. TCPoXML DTD + + <!-- + DTD for TCP over XML. + Refer to this DTD as: + + <!DOCTYPE tcp PUBLIC "-//IETF//DTD BLOAT 1.0 TCP//EN" "bloat.dtd"> + --> + + <!-- the pseudoheader is only included for checksum calculations --> + <!ELEMENT tcp (tcp.pseudoheader?, tcp.header, payload)> + + <!ELEMENT tcp.header (src, dest, sequence, acknowledgement, offset, + reserved, control, window, checksum, urgent, + tcp.options, padding)> + + <!ELEMENT src EMPTY> + <!-- 0 <= port <= 65,535 --> + <!ATTLIST src + port %Digits; #REQUIRED> + + <!ELEMENT dest EMPTY> + <!-- 0 <= port <= 65,535 --> + + + +Kennedy Informational [Page 11] + +RFC 3252 Binary Lexical Octet Ad-hoc Transport 1 April 2002 + + + <!ATTLIST dest + port %Digits; #REQUIRED> + + <!ELEMENT sequence EMPTY> + <!-- 0 <= number <= 4294967295 --> + <!ATTLIST sequence + number %Digits; #REQUIRED> + + <!ELEMENT acknowledgement EMPTY> + <!-- 0 <= number <= 4294967295 --> + <!ATTLIST acknowledgement + number %Digits; #REQUIRED> + + <!ELEMENT offset EMPTY> + <!-- 0 <= number <= 255 --> + <!ATTLIST offset + number %Digits; #REQUIRED> + + <!ELEMENT reserved EMPTY> + <!ATTLIST reserved + value CDATA #FIXED "0"> + + <!ELEMENT control EMPTY> + <!ATTLIST control + urg (0|1) #IMPLIED + ack (0|1) #IMPLIED + psh (0|1) #IMPLIED + rst (0|1) #IMPLIED + syn (0|1) #IMPLIED + fin (0|1) #IMPLIED> + + <!ELEMENT window EMPTY> + <!-- 0 <= size <= 65,535 --> + <!ATTLIST window + size %Digits; #REQUIRED> + + <!-- + checksum as in ip, but with + the following pseudo-header added into the tcp element: + --> + <!ELEMENT tcp.pseudoheader (source, destination, protocol, + tcp.length)> + + <!-- + tcp header + data length in octets. does not include the size of + + the pseudoheader. + --> + + + +Kennedy Informational [Page 12] + +RFC 3252 Binary Lexical Octet Ad-hoc Transport 1 April 2002 + + + <!ELEMENT tcp.length EMPTY> + <!ATTLIST tcp.length + value %Digits; #REQUIRED> + + <!ELEMENT urgent EMPTY> + <!-- 0 <= pointer <= 65,535 --> + <!ATTLIST urgent + pointer %Digits; #REQUIRED> + + <!ELEMENT tcp.options (tcp.end | tcp.noop | tcp.mss)+> + + <!ELEMENT tcp.end EMPTY> + <!ATTLIST tcp.end + kind CDATA #FIXED "0"> + + <!ELEMENT tcp.noop EMPTY> + <!ATTLIST tcp.noop + kind CDATA #FIXED "1"> + + <!ELEMENT tcp.mss EMPTY> + <!ATTLIST tcp.mss + kind CDATA #FIXED "2" + length CDATA #FIXED "4" + size %Digits; #REQUIRED> + +7.3. UDPoXML DTD + + <!-- + DTD for UDP over XML. + Refer to this DTD as: + + <!DOCTYPE udp PUBLIC "-//IETF//DTD BLOAT 1.0 UDP//EN" "bloat.dtd"> + --> + + <!ELEMENT udp (udp.pseudoheader?, udp.header, payload)> + + <!ELEMENT udp.header (src, dest, udp.length, checksum)> + + <!ELEMENT udp.pseudoheader (source, destination, protocol, + udp.length)> + + <!-- + udp header + data length in octets. does not include the size of + the pseudoheader. + --> + <!ELEMENT udp.length EMPTY> + <!ATTLIST udp.length + value %Digits; #REQUIRED> + + + +Kennedy Informational [Page 13] + +RFC 3252 Binary Lexical Octet Ad-hoc Transport 1 April 2002 + + +8. Security Considerations + + XML, as a subset of SGML, has the same security considerations as + specified in SGML Media Types [RFC1874]. Security considerations + that apply to IP, TCP and UDP also likely apply to BLOAT as it does + not attempt to correct for issues not related to message format. + +9. References + + [JABBER] Miller, J., "Jabber", draft-miller-jabber-00.txt, + February 2002. (Work in Progress) + + [RFC768] Postel, J., "User Datagram Protocol", STD 6, RFC 768, + August 1980. + + [RFC791] Postel, J., "Internet Protocol", STD 5, RFC 791, + September 1981. + + [RFC793] Postel, J., "Transmission Control Protocol", STD 7, RFC + 793, September 1981. + + [RFC894] Hornig, C., "Standard for the Transmission of IP + Datagrams over Ethernet Networks.", RFC 894, April 1984. + + [RFC1042] Postel, J. and J. Reynolds, "Standard for the + Transmission of IP Datagrams Over IEEE 802 Networks", STD + 43, RFC 1042, February 1988. + + [RFC1123] Braden, R., "Requirements for Internet Hosts - + Application and Support", RFC 1123, October 1989. + + [RFC1874] Levinson, E., "SGML Media Types", RFC 1874, December + 1995. + + [RFC2003] Perkins, C., "IP Encapsulation within IP", RFC 2003, + October 1996. + + [RFC2045] Freed, N. and N. Borenstein, "Multipurpose Internet Mail + Extensions (MIME) Part One: Format of Internet Message + Bodies", RFC 2045, November 1996. + + [RFC2119] Bradner, S., "Key words for use in RFCs to Indicate + Requirement Levels", BCP 14, RFC 2119, March 1997. + + [RFC2279] Yergeau, F., "UTF-8, a transformation format of ISO + 10646", RFC 2279, January 1998. + + + + + +Kennedy Informational [Page 14] + +RFC 3252 Binary Lexical Octet Ad-hoc Transport 1 April 2002 + + + [RFC2460] Deering, S. and R. Hinden, "Internet Protocol, Version 6 + (IPv6) Specification", RFC 2460, December 1998. + + [RFC3080] Rose, M., "The Blocks Extensible Exchange Protocol Core", + RFC 3080, March 2001. + + [SOAP] Box, D., Ehnebuske, D., Kakivaya, G., Layman, A., + Mendelsohn, N., Nielsen, H. F., Thatte, S. Winer, D., + "Simple Object Access Protocol (SOAP) 1.1" World Wide Web + Consortium Note, May 2000 http://www.w3.org/TR/SOAP/ + + [XML] Bray, T., Paoli, J., Sperberg-McQueen, C. M., "Extensible + Markup Language (XML)" World Wide Web Consortium + Recommendation REC- xml-19980210. + http://www.w3.org/TR/1998/REC-xml-19980210 + +10. Author's Address + + Hugh Kennedy + Mimezine + 1060 West Addison + Chicago, IL 60613 + USA + + EMail: kennedyh@engin.umich.edu + + + + + + + + + + + + + + + + + + + + + + + + + + +Kennedy Informational [Page 15] + +RFC 3252 Binary Lexical Octet Ad-hoc Transport 1 April 2002 + + +11. Full Copyright Statement + + Copyright (C) The Internet Society (2002). All Rights Reserved. + + This document and translations of it may be copied and furnished to + others, and derivative works that comment on or otherwise explain it + or assist in its implementation may be prepared, copied, published + and distributed, in whole or in part, without restriction of any + kind, provided that the above copyright notice and this paragraph are + included on all such copies and derivative works. However, this + document itself may not be modified in any way, such as by removing + the copyright notice or references to the Internet Society or other + Internet organizations, except as needed for the purpose of + developing Internet standards in which case the procedures for + copyrights defined in the Internet Standards process must be + followed, or as required to translate it into languages other than + English. + + The limited permissions granted above are perpetual and will not be + revoked by the Internet Society or its successors or assigns. + + This document and the information contained herein is provided on an + "AS IS" basis and THE INTERNET SOCIETY AND THE INTERNET ENGINEERING + TASK FORCE DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING + BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE INFORMATION + HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED WARRANTIES OF + MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. + +Acknowledgement + + Funding for the RFC Editor function is currently provided by the + Internet Society. + + + + + + + + + + + + + + + + + + + +Kennedy Informational [Page 16] + + + + + + + +Network Working Group H. Kennedy +Request for Comments: 3252 Mimezine +Category: Informational 1 April 2002 + + + Binary Lexical Octet Ad-hoc Transport + +Status of this Memo + + This memo provides information for the Internet community. It does + not specify an Internet standard of any kind. Distribution of this + memo is unlimited. + +Copyright Notice + + Copyright (C) The Internet Society (2002). All Rights Reserved. + +Abstract + + This document defines a reformulation of IP and two transport layer + protocols (TCP and UDP) as XML applications. + +1. Introduction + +1.1. Overview + + This document describes the Binary Lexical Octet Ad-hoc Transport + (BLOAT): a reformulation of a widely-deployed network-layer protocol + (IP [RFC791]), and two associated transport layer protocols (TCP + [RFC793] and UDP [RFC768]) as XML [XML] applications. It also + describes methods for transporting BLOAT over Ethernet and IEEE 802 + networks as well as encapsulating BLOAT in IP for gatewaying BLOAT + across the public Internet. + +1.2. Motivation + + The wild popularity of XML as a basis for application-level protocols + such as the Blocks Extensible Exchange Protocol [RFC3080], the Simple + Object Access Protocol [SOAP], and Jabber [JABBER] prompted + investigation into the possibility of extending the use of XML in the + protocol stack. Using XML at both the transport and network layer in + addition to the application layer would provide for an amazing amount + of power and flexibility while removing dependencies on proprietary + and hard-to-understand binary protocols. This protocol unification + would also allow applications to use a single XML parser for all + aspects of their operation, eliminating developer time spent figuring + out the intricacies of each new protocol, and moving the hard work of + + + + +Kennedy Informational [Page 1] + +RFC 3252 Binary Lexical Octet Ad-hoc Transport 1 April 2002 + + + parsing to the XML toolset. The use of XML also mitigates concerns + over "network vs. host" byte ordering which is at the root of many + network application bugs. + +1.3. Relation to Existing Protocols + + The reformulations specified in this RFC follow as closely as + possible the spirit of the RFCs on which they are based, and so MAY + contain elements or attributes that would not be needed in a pure + reworking (e.g. length attributes, which are implicit in XML.) + + The layering of network and transport protocols are maintained in + this RFC despite the optimizations that could be made if the line + were somewhat blurred (i.e. merging TCP and IP into a single, larger + element in the DTD) in order to foster future use of this protocol as + a basis for reformulating other protocols (such as ICMP.) + + Other than the encoding, the behavioral aspects of each of the + existing protocols remain unchanged. Routing, address spaces, TCP + congestion control, etc. behave as specified in the extant standards. + Adapting to new standards and experimental algorithm heuristics for + improving performance will become much easier once the move to BLOAT + has been completed. + +1.4. Requirement Levels + + The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", + "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this + document are to be interpreted as described in BCP 14, RFC 2119 + [RFC2119]. + +2. IPoXML + + This protocol MUST be implemented to be compliant with this RFC. + IPoXML is the root protocol REQUIRED for effective use of TCPoXML + (section 3.) and higher-level application protocols. + + The DTD for this document type can be found in section 7.1. + + The routing of IPoXML can be easily implemented on hosts with an XML + parser, as the regular structure lends itself handily to parsing and + validation of the document/datagram and then processing the + destination address, TTL, and checksum before sending it on to its + next-hop. + + The reformulation of IPv4 was chosen over IPv6 [RFC2460] due to the + wider deployment of IPv4 and the fact that implementing IPv6 as XML + would have exceeded the 1500 byte Ethernet MTU. + + + +Kennedy Informational [Page 2] + +RFC 3252 Binary Lexical Octet Ad-hoc Transport 1 April 2002 + + + All BLOAT implementations MUST use - and specify - the UTF-8 encoding + of RFC 2279 [RFC2279]. All BLOAT document/datagrams MUST be well- + formed and include the XMLDecl. + +2.1. IP Description + + A number of items have changed (for the better) from the original IP + specification. Bit-masks, where present have been converted into + human-readable values. IP addresses are listed in their dotted- + decimal notation [RFC1123]. Length and checksum values are present + as decimal integers. + + To calculate the length and checksum fields of the IP element, a + canonicalized form of the element MUST be used. The canonical form + SHALL have no whitespace (including newline characters) between + elements and only one space character between attributes. There + SHALL NOT be a space following the last attribute in an element. + + An iterative method SHOULD be used to calculate checksums, as the + length field will vary based on the size of the checksum. + + The payload element bears special attention. Due to the character + set restrictions of XML, the payload of IP datagrams (which MAY + contain arbitrary data) MUST be encoded for transport. This RFC + REQUIRES the contents of the payload to be encoded in the base-64 + encoding of RFC 2045 [RFC2045], but removes the requirement that the + encoded output MUST be wrapped on 76-character lines. + + + + + + + + + + + + + + + + + + + + + + + + +Kennedy Informational [Page 3] + +RFC 3252 Binary Lexical Octet Ad-hoc Transport 1 April 2002 + + +2.2. Example Datagram + + The following is an example IPoXML datagram with an empty payload: + + <?xml version="1.0" encoding="UTF-8"?> + <!DOCTYPE ip PUBLIC "-//IETF//DTD BLOAT 1.0 IP//EN" "bloat.dtd"> + <ip> + <header length="474"> + <version value="4"/> + <tos precedence="Routine" delay="Normal" throughput="Normal" + relibility="Normal" reserved="0"/> + <total.length value="461"/> + <id value="1"/> + <flags reserved="0" df="dont" mf="last"/> + <offset value="0"/> + <ttl value="255"/> + <protocol value="6"/> + <checksum value="8707"/> + <source address="10.0.0.22"/> + <destination address="10.0.0.1"/> + <options> + <end copied="0" class="0" number="0"/> + </options> + <padding pad="0"/> + </header> + <payload> + </payload> + </ip> + +3. TCPoXML + + This protocol MUST be implemented to be compliant with this RFC. The + DTD for this document type can be found in section 7.2. + +3.1. TCP Description + + A number of items have changed from the original TCP specification. + Bit-masks, where present have been converted into human-readable + values. Length and checksum and port values are present as decimal + integers. + + To calculate the length and checksum fields of the TCP element, a + canonicalized form of the element MUST be used as in section 2.1. + + An iterative method SHOULD be used to calculate checksums as in + section 2.1. + + The payload element MUST be encoded as in section 2.1. + + + +Kennedy Informational [Page 4] + +RFC 3252 Binary Lexical Octet Ad-hoc Transport 1 April 2002 + + + The TCP offset element was expanded to a maximum of 255 from 16 to + allow for the increased size of the header in XML. + + TCPoXML datagrams encapsulated by IPoXML MAY omit the <?xml?> header + as well as the <!DOCTYPE> declaration. + +3.2. Example Datagram + + The following is an example TCPoXML datagram with an empty payload: + + <?xml version="1.0" encoding="UTF-8"?> + <!DOCTYPE tcp PUBLIC "-//IETF//DTD BLOAT 1.0 TCP//EN" "bloat.dtd"> + <tcp> + <tcp.header> + <src port="31415"/> + <dest port="42424"/> + <sequence number="322622954"/> + <acknowledgement number="689715995"/> + <offset number=""/> + <reserved value="0"/> + <control syn="1" ack="1"/> + <window size="1"/> + <urgent pointer="0"/> + <checksum value="2988"/> + <tcp.options> + <tcp.end kind="0"/> + </tcp.options> + <padding pad="0"/> + </tcp.header> + <payload> + </payload> + </tcp> + +4. UDPoXML + + This protocol MUST be implemented to be compliant with this RFC. The + DTD for this document type can be found in section 7.3. + +4.1. UDP Description + + A number of items have changed from the original UDP specification. + Bit-masks, where present have been converted into human-readable + values. Length and checksum and port values are present as decimal + integers. + + + + + + + +Kennedy Informational [Page 5] + +RFC 3252 Binary Lexical Octet Ad-hoc Transport 1 April 2002 + + + To calculate the length and checksum fields of the UDP element, a + canonicalized form of the element MUST be used as in section 2.1. An + iterative method SHOULD be used to calculate checksums as in section + 2.1. + + The payload element MUST be encoded as in section 2.1. + + UDPoXML datagrams encapsulated by IPoXML MAY omit the <?xml?> header + as well as the <!DOCTYPE> declaration. + +4.2. Example Datagram + + The following is an example UDPoXML datagram with an empty payload: + + <?xml version="1.0" encoding="UTF-8"?> + <!DOCTYPE udp PUBLIC "-//IETF//DTD BLOAT 1.0 UDP//EN" "bloat.dtd"> + <udp> + <udp.header> + <src port="31415"/> + <dest port="42424"/> + <udp.length value="143"/> + <checksum value="2988"/> + </udp.header> + <payload> + </payload> + </udp> + +5. Network Transport + + This document provides for the transmission of BLOAT datagrams over + two common families of physical layer transport. Future RFCs will + address additional transports as routing vendors catch up to the + specification, and we begin to see BLOAT routed across the Internet + backbone. + +5.1. Ethernet + + BLOAT is encapsulated in Ethernet datagrams as in [RFC894] with the + exception that the type field of the Ethernet frame MUST contain the + value 0xBEEF. The first 5 octets of the Ethernet frame payload will + be 0x3c 3f 78 6d 6c ("<?xml".) + +5.2. IEEE 802 + + BLOAT is encapsulated in IEEE 802 Networks as in [RFC1042] except + that the protocol type code for IPoXML is 0xBEEF. + + + + + +Kennedy Informational [Page 6] + +RFC 3252 Binary Lexical Octet Ad-hoc Transport 1 April 2002 + + +6. Gatewaying over IP + + In order to facilitate the gradual introduction of BLOAT into the + public Internet, BLOAT MAY be encapsulated in IP as in [RFC2003] to + gateway between networks that run BLOAT natively on their LANs. + +7. DTDs + + The Transport DTDs (7.2. and 7.3.) build on the definitions in the + Network DTD (7.1.) + + The DTDs are referenced by their PubidLiteral and SystemLiteral (from + [XML]) although it is understood that most IPoXML implementations + will not need to pull down the DTD, as it will normally be embedded + in the implementation, and presents something of a catch-22 if you + need to load part of your network protocol over the network. + +7.1. IPoXML DTD + + <!-- + DTD for IP over XML. + Refer to this DTD as: + + <!DOCTYPE ip PUBLIC "-//IETF//DTD BLOAT 1.0 IP//EN" "bloat.dtd"> + --> + <!-- + DTD data types: + + Digits [0..9]+ + + Precedence "NetworkControl | InternetworkControl | + CRITIC | FlashOverride | Flash | Immediate | + Priority | Routine" + + IP4Addr "dotted-decimal" notation of [RFC1123] + + Class [0..3] + + Sec "Unclassified | Confidential | EFTO | MMMM | PROG | + Restricted | Secret | Top Secret | Reserved" + + Compartments [0..65535] + + Handling [0..65535] + + TCC [0..16777216] + + --> + + + +Kennedy Informational [Page 7] + +RFC 3252 Binary Lexical Octet Ad-hoc Transport 1 April 2002 + + + <!ENTITY % Digits "CDATA"> + <!ENTITY % Precedence "CDATA"> + <!ENTITY % IP4Addr "CDATA"> + <!ENTITY % Class "CDATA"> + <!ENTITY % Sec "CDATA"> + <!ENTITY % Compartments "CDATA"> + <!ENTITY % Handling "CDATA"> + <!ENTITY % TCC "CDATA"> + + <!ELEMENT ip (header, payload)> + + <!ELEMENT header (version, tos, total.length, id, flags, offset, ttl, + protocol, checksum, source, destination, options, + padding)> + <!-- length of header in 32-bit words --> + <!ATTLIST header + length %Digits; #REQUIRED> + + <!ELEMENT version EMPTY> + <!-- ip version. SHOULD be "4" --> + <!ATTLIST version + value %Digits; #REQUIRED> + + <!ELEMENT tos EMPTY> + <!ATTLIST tos + precedence %Precedence; #REQUIRED + delay (normal | low) #REQUIRED + throughput (normal | high) #REQUIRED + relibility (normal | high) #REQUIRED + reserved CDATA #FIXED "0"> + + <!ELEMENT total.length EMPTY> + <!-- + total length of datagram (header and payload) in octets, MUST be + less than 65,535 (and SHOULD be less than 1024 for IPoXML on local + ethernets). + --> + <!ATTLIST total.length + value %Digits; #REQUIRED> + + <!ELEMENT id EMPTY> + <!-- 0 <= id <= 65,535 --> + <!ATTLIST id + value %Digits; #REQUIRED> + + <!ELEMENT flags EMPTY> + <!-- df = don't fragment, mf = more fragments --> + <!ATTLIST flags + + + +Kennedy Informational [Page 8] + +RFC 3252 Binary Lexical Octet Ad-hoc Transport 1 April 2002 + + + reserved CDATA #FIXED "0" + df (may|dont) #REQUIRED + mf (last|more) #REQUIRED> + + <!ELEMENT offset EMPTY> + <!-- 0 <= offset <= 8192 measured in 8 octet (64-bit) chunks --> + <!ATTLIST offset + value %Digits; #REQUIRED> + + <!ELEMENT ttl EMPTY> + <!-- 0 <= ttl <= 255 --> + <!ATTLIST ttl + value %Digits; #REQUIRED> + + <!ELEMENT protocol EMPTY> + <!-- 0 <= protocol <= 255 (per IANA) --> + <!ATTLIST protocol + value %Digits; #REQUIRED> + + <!ELEMENT checksum EMPTY> + <!-- 0 <= checksum <= 65535 (over header only) --> + <!ATTLIST checksum + value %Digits; #REQUIRED> + + <!ELEMENT source EMPTY> + <!ATTLIST source + address %IP4Addr; #REQUIRED> + + <!ELEMENT destination EMPTY> + <!ATTLIST destination + address %IP4Addr; #REQUIRED> + + <!ELEMENT options ( end | noop | security | loose | strict | record + | stream | timestamp )*> + + <!ELEMENT end EMPTY> + <!ATTLIST end + copied (0|1) #REQUIRED + class CDATA #FIXED "0" + number CDATA #FIXED "0"> + + <!ELEMENT noop EMPTY> + <!ATTLIST noop + copied (0|1) #REQUIRED + class CDATA #FIXED "0" + number CDATA #FIXED "1"> + + <!ELEMENT security EMPTY> + + + +Kennedy Informational [Page 9] + +RFC 3252 Binary Lexical Octet Ad-hoc Transport 1 April 2002 + + + <!ATTLIST security + copied CDATA #FIXED "1" + class CDATA #FIXED "0" + number CDATA #FIXED "2" + length CDATA #FIXED "11" + security %Sec; #REQUIRED + compartments %Compartments; #REQUIRED + handling %Handling; #REQUIRED + tcc %TCC; #REQUIRED> + <!ELEMENT loose (hop)+> + <!ATTLIST loose + copied CDATA #FIXED "1" + class CDATA #FIXED "0" + number CDATA #FIXED "3" + length %Digits; #REQUIRED + pointer %Digits; #REQUIRED> + + <!ELEMENT hop EMPTY> + <!ATTLIST hop + address %IP4Addr; #REQUIRED> + + <!ELEMENT strict (hop)+> + <!ATTLIST strict + copied CDATA #FIXED "1" + class CDATA #FIXED "0" + number CDATA #FIXED "9" + length %Digits; #REQUIRED + pointer %Digits; #REQUIRED> + + <!ELEMENT record (hop)+> + <!ATTLIST record + copied CDATA #FIXED "0" + class CDATA #FIXED "0" + number CDATA #FIXED "7" + length %Digits; #REQUIRED + pointer %Digits; #REQUIRED> + + <!ELEMENT stream EMPTY> + <!-- 0 <= id <= 65,535 --> + <!ATTLIST stream + copied CDATA #FIXED "1" + class CDATA #FIXED "0" + number CDATA #FIXED "8" + length CDATA #FIXED "4" + id %Digits; #REQUIRED> + + <!ELEMENT timestamp (tstamp)+> + <!-- 0 <= oflw <=15 --> + + + +Kennedy Informational [Page 10] + +RFC 3252 Binary Lexical Octet Ad-hoc Transport 1 April 2002 + + + <!ATTLIST timestamp + copied CDATA #FIXED "0" + class CDATA #FIXED "2" + number CDATA #FIXED "4" + length %Digits; #REQUIRED + pointer %Digits; #REQUIRED + oflw %Digits; #REQUIRED + flag (0 | 1 | 3) #REQUIRED> + + <!ELEMENT tstamp EMPTY> + <!ATTLIST tstamp + time %Digits; #REQUIRED + address %IP4Addr; #IMPLIED> + <!-- + padding to bring header to 32-bit boundary. + pad MUST be "0"* + --> + <!ELEMENT padding EMPTY> + <!ATTLIST padding + pad CDATA #REQUIRED> + + <!-- payload MUST be encoded as base-64 [RFC2045], as modified + by section 2.1 of this RFC --> + <!ELEMENT payload (CDATA)> + +7.2. TCPoXML DTD + + <!-- + DTD for TCP over XML. + Refer to this DTD as: + + <!DOCTYPE tcp PUBLIC "-//IETF//DTD BLOAT 1.0 TCP//EN" "bloat.dtd"> + --> + + <!-- the pseudoheader is only included for checksum calculations --> + <!ELEMENT tcp (tcp.pseudoheader?, tcp.header, payload)> + + <!ELEMENT tcp.header (src, dest, sequence, acknowledgement, offset, + reserved, control, window, checksum, urgent, + tcp.options, padding)> + + <!ELEMENT src EMPTY> + <!-- 0 <= port <= 65,535 --> + <!ATTLIST src + port %Digits; #REQUIRED> + + <!ELEMENT dest EMPTY> + <!-- 0 <= port <= 65,535 --> + + + +Kennedy Informational [Page 11] + +RFC 3252 Binary Lexical Octet Ad-hoc Transport 1 April 2002 + + + <!ATTLIST dest + port %Digits; #REQUIRED> + + <!ELEMENT sequence EMPTY> + <!-- 0 <= number <= 4294967295 --> + <!ATTLIST sequence + number %Digits; #REQUIRED> + + <!ELEMENT acknowledgement EMPTY> + <!-- 0 <= number <= 4294967295 --> + <!ATTLIST acknowledgement + number %Digits; #REQUIRED> + + <!ELEMENT offset EMPTY> + <!-- 0 <= number <= 255 --> + <!ATTLIST offset + number %Digits; #REQUIRED> + + <!ELEMENT reserved EMPTY> + <!ATTLIST reserved + value CDATA #FIXED "0"> + + <!ELEMENT control EMPTY> + <!ATTLIST control + urg (0|1) #IMPLIED + ack (0|1) #IMPLIED + psh (0|1) #IMPLIED + rst (0|1) #IMPLIED + syn (0|1) #IMPLIED + fin (0|1) #IMPLIED> + + <!ELEMENT window EMPTY> + <!-- 0 <= size <= 65,535 --> + <!ATTLIST window + size %Digits; #REQUIRED> + + <!-- + checksum as in ip, but with + the following pseudo-header added into the tcp element: + --> + <!ELEMENT tcp.pseudoheader (source, destination, protocol, + tcp.length)> + + <!-- + tcp header + data length in octets. does not include the size of + + the pseudoheader. + --> + + + +Kennedy Informational [Page 12] + +RFC 3252 Binary Lexical Octet Ad-hoc Transport 1 April 2002 + + + <!ELEMENT tcp.length EMPTY> + <!ATTLIST tcp.length + value %Digits; #REQUIRED> + + <!ELEMENT urgent EMPTY> + <!-- 0 <= pointer <= 65,535 --> + <!ATTLIST urgent + pointer %Digits; #REQUIRED> + + <!ELEMENT tcp.options (tcp.end | tcp.noop | tcp.mss)+> + + <!ELEMENT tcp.end EMPTY> + <!ATTLIST tcp.end + kind CDATA #FIXED "0"> + + <!ELEMENT tcp.noop EMPTY> + <!ATTLIST tcp.noop + kind CDATA #FIXED "1"> + + <!ELEMENT tcp.mss EMPTY> + <!ATTLIST tcp.mss + kind CDATA #FIXED "2" + length CDATA #FIXED "4" + size %Digits; #REQUIRED> + +7.3. UDPoXML DTD + + <!-- + DTD for UDP over XML. + Refer to this DTD as: + + <!DOCTYPE udp PUBLIC "-//IETF//DTD BLOAT 1.0 UDP//EN" "bloat.dtd"> + --> + + <!ELEMENT udp (udp.pseudoheader?, udp.header, payload)> + + <!ELEMENT udp.header (src, dest, udp.length, checksum)> + + <!ELEMENT udp.pseudoheader (source, destination, protocol, + udp.length)> + + <!-- + udp header + data length in octets. does not include the size of + the pseudoheader. + --> + <!ELEMENT udp.length EMPTY> + <!ATTLIST udp.length + value %Digits; #REQUIRED> + + + +Kennedy Informational [Page 13] + +RFC 3252 Binary Lexical Octet Ad-hoc Transport 1 April 2002 + + +8. Security Considerations + + XML, as a subset of SGML, has the same security considerations as + specified in SGML Media Types [RFC1874]. Security considerations + that apply to IP, TCP and UDP also likely apply to BLOAT as it does + not attempt to correct for issues not related to message format. + +9. References + + [JABBER] Miller, J., "Jabber", draft-miller-jabber-00.txt, + February 2002. (Work in Progress) + + [RFC768] Postel, J., "User Datagram Protocol", STD 6, RFC 768, + August 1980. + + [RFC791] Postel, J., "Internet Protocol", STD 5, RFC 791, + September 1981. + + [RFC793] Postel, J., "Transmission Control Protocol", STD 7, RFC + 793, September 1981. + + [RFC894] Hornig, C., "Standard for the Transmission of IP + Datagrams over Ethernet Networks.", RFC 894, April 1984. + + [RFC1042] Postel, J. and J. Reynolds, "Standard for the + Transmission of IP Datagrams Over IEEE 802 Networks", STD + 43, RFC 1042, February 1988. + + [RFC1123] Braden, R., "Requirements for Internet Hosts - + Application and Support", RFC 1123, October 1989. + + [RFC1874] Levinson, E., "SGML Media Types", RFC 1874, December + 1995. + + [RFC2003] Perkins, C., "IP Encapsulation within IP", RFC 2003, + October 1996. + + [RFC2045] Freed, N. and N. Borenstein, "Multipurpose Internet Mail + Extensions (MIME) Part One: Format of Internet Message + Bodies", RFC 2045, November 1996. + + [RFC2119] Bradner, S., "Key words for use in RFCs to Indicate + Requirement Levels", BCP 14, RFC 2119, March 1997. + + [RFC2279] Yergeau, F., "UTF-8, a transformation format of ISO + 10646", RFC 2279, January 1998. + + + + + +Kennedy Informational [Page 14] + +RFC 3252 Binary Lexical Octet Ad-hoc Transport 1 April 2002 + + + [RFC2460] Deering, S. and R. Hinden, "Internet Protocol, Version 6 + (IPv6) Specification", RFC 2460, December 1998. + + [RFC3080] Rose, M., "The Blocks Extensible Exchange Protocol Core", + RFC 3080, March 2001. + + [SOAP] Box, D., Ehnebuske, D., Kakivaya, G., Layman, A., + Mendelsohn, N., Nielsen, H. F., Thatte, S. Winer, D., + "Simple Object Access Protocol (SOAP) 1.1" World Wide Web + Consortium Note, May 2000 http://www.w3.org/TR/SOAP/ + + [XML] Bray, T., Paoli, J., Sperberg-McQueen, C. M., "Extensible + Markup Language (XML)" World Wide Web Consortium + Recommendation REC- xml-19980210. + http://www.w3.org/TR/1998/REC-xml-19980210 + +10. Author's Address + + Hugh Kennedy + Mimezine + 1060 West Addison + Chicago, IL 60613 + USA + + EMail: kennedyh@engin.umich.edu + + + + + + + + + + + + + + + + + + + + + + + + + + +Kennedy Informational [Page 15] + +RFC 3252 Binary Lexical Octet Ad-hoc Transport 1 April 2002 + + +11. Full Copyright Statement + + Copyright (C) The Internet Society (2002). All Rights Reserved. + + This document and translations of it may be copied and furnished to + others, and derivative works that comment on or otherwise explain it + or assist in its implementation may be prepared, copied, published + and distributed, in whole or in part, without restriction of any + kind, provided that the above copyright notice and this paragraph are + included on all such copies and derivative works. However, this + document itself may not be modified in any way, such as by removing + the copyright notice or references to the Internet Society or other + Internet organizations, except as needed for the purpose of + developing Internet standards in which case the procedures for + copyrights defined in the Internet Standards process must be + followed, or as required to translate it into languages other than + English. + + The limited permissions granted above are perpetual and will not be + revoked by the Internet Society or its successors or assigns. + + This document and the information contained herein is provided on an + "AS IS" basis and THE INTERNET SOCIETY AND THE INTERNET ENGINEERING + TASK FORCE DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING + BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE INFORMATION + HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED WARRANTIES OF + MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. + +Acknowledgement + + Funding for the RFC Editor function is currently provided by the + Internet Society. + + + + + + + + + + + + + + + + + + + +Kennedy Informational [Page 16] + + + + + + + +Network Working Group H. Kennedy +Request for Comments: 3252 Mimezine +Category: Informational 1 April 2002 + + + Binary Lexical Octet Ad-hoc Transport + +Status of this Memo + + This memo provides information for the Internet community. It does + not specify an Internet standard of any kind. Distribution of this + memo is unlimited. + +Copyright Notice + + Copyright (C) The Internet Society (2002). All Rights Reserved. + +Abstract + + This document defines a reformulation of IP and two transport layer + protocols (TCP and UDP) as XML applications. + +1. Introduction + +1.1. Overview + + This document describes the Binary Lexical Octet Ad-hoc Transport + (BLOAT): a reformulation of a widely-deployed network-layer protocol + (IP [RFC791]), and two associated transport layer protocols (TCP + [RFC793] and UDP [RFC768]) as XML [XML] applications. It also + describes methods for transporting BLOAT over Ethernet and IEEE 802 + networks as well as encapsulating BLOAT in IP for gatewaying BLOAT + across the public Internet. + +1.2. Motivation + + The wild popularity of XML as a basis for application-level protocols + such as the Blocks Extensible Exchange Protocol [RFC3080], the Simple + Object Access Protocol [SOAP], and Jabber [JABBER] prompted + investigation into the possibility of extending the use of XML in the + protocol stack. Using XML at both the transport and network layer in + addition to the application layer would provide for an amazing amount + of power and flexibility while removing dependencies on proprietary + and hard-to-understand binary protocols. This protocol unification + would also allow applications to use a single XML parser for all + aspects of their operation, eliminating developer time spent figuring + out the intricacies of each new protocol, and moving the hard work of + + + + +Kennedy Informational [Page 1] + +RFC 3252 Binary Lexical Octet Ad-hoc Transport 1 April 2002 + + + parsing to the XML toolset. The use of XML also mitigates concerns + over "network vs. host" byte ordering which is at the root of many + network application bugs. + +1.3. Relation to Existing Protocols + + The reformulations specified in this RFC follow as closely as + possible the spirit of the RFCs on which they are based, and so MAY + contain elements or attributes that would not be needed in a pure + reworking (e.g. length attributes, which are implicit in XML.) + + The layering of network and transport protocols are maintained in + this RFC despite the optimizations that could be made if the line + were somewhat blurred (i.e. merging TCP and IP into a single, larger + element in the DTD) in order to foster future use of this protocol as + a basis for reformulating other protocols (such as ICMP.) + + Other than the encoding, the behavioral aspects of each of the + existing protocols remain unchanged. Routing, address spaces, TCP + congestion control, etc. behave as specified in the extant standards. + Adapting to new standards and experimental algorithm heuristics for + improving performance will become much easier once the move to BLOAT + has been completed. + +1.4. Requirement Levels + + The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", + "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this + document are to be interpreted as described in BCP 14, RFC 2119 + [RFC2119]. + +2. IPoXML + + This protocol MUST be implemented to be compliant with this RFC. + IPoXML is the root protocol REQUIRED for effective use of TCPoXML + (section 3.) and higher-level application protocols. + + The DTD for this document type can be found in section 7.1. + + The routing of IPoXML can be easily implemented on hosts with an XML + parser, as the regular structure lends itself handily to parsing and + validation of the document/datagram and then processing the + destination address, TTL, and checksum before sending it on to its + next-hop. + + The reformulation of IPv4 was chosen over IPv6 [RFC2460] due to the + wider deployment of IPv4 and the fact that implementing IPv6 as XML + would have exceeded the 1500 byte Ethernet MTU. + + + +Kennedy Informational [Page 2] + +RFC 3252 Binary Lexical Octet Ad-hoc Transport 1 April 2002 + + + All BLOAT implementations MUST use - and specify - the UTF-8 encoding + of RFC 2279 [RFC2279]. All BLOAT document/datagrams MUST be well- + formed and include the XMLDecl. + +2.1. IP Description + + A number of items have changed (for the better) from the original IP + specification. Bit-masks, where present have been converted into + human-readable values. IP addresses are listed in their dotted- + decimal notation [RFC1123]. Length and checksum values are present + as decimal integers. + + To calculate the length and checksum fields of the IP element, a + canonicalized form of the element MUST be used. The canonical form + SHALL have no whitespace (including newline characters) between + elements and only one space character between attributes. There + SHALL NOT be a space following the last attribute in an element. + + An iterative method SHOULD be used to calculate checksums, as the + length field will vary based on the size of the checksum. + + The payload element bears special attention. Due to the character + set restrictions of XML, the payload of IP datagrams (which MAY + contain arbitrary data) MUST be encoded for transport. This RFC + REQUIRES the contents of the payload to be encoded in the base-64 + encoding of RFC 2045 [RFC2045], but removes the requirement that the + encoded output MUST be wrapped on 76-character lines. + + + + + + + + + + + + + + + + + + + + + + + + +Kennedy Informational [Page 3] + +RFC 3252 Binary Lexical Octet Ad-hoc Transport 1 April 2002 + + +2.2. Example Datagram + + The following is an example IPoXML datagram with an empty payload: + + <?xml version="1.0" encoding="UTF-8"?> + <!DOCTYPE ip PUBLIC "-//IETF//DTD BLOAT 1.0 IP//EN" "bloat.dtd"> + <ip> + <header length="474"> + <version value="4"/> + <tos precedence="Routine" delay="Normal" throughput="Normal" + relibility="Normal" reserved="0"/> + <total.length value="461"/> + <id value="1"/> + <flags reserved="0" df="dont" mf="last"/> + <offset value="0"/> + <ttl value="255"/> + <protocol value="6"/> + <checksum value="8707"/> + <source address="10.0.0.22"/> + <destination address="10.0.0.1"/> + <options> + <end copied="0" class="0" number="0"/> + </options> + <padding pad="0"/> + </header> + <payload> + </payload> + </ip> + +3. TCPoXML + + This protocol MUST be implemented to be compliant with this RFC. The + DTD for this document type can be found in section 7.2. + +3.1. TCP Description + + A number of items have changed from the original TCP specification. + Bit-masks, where present have been converted into human-readable + values. Length and checksum and port values are present as decimal + integers. + + To calculate the length and checksum fields of the TCP element, a + canonicalized form of the element MUST be used as in section 2.1. + + An iterative method SHOULD be used to calculate checksums as in + section 2.1. + + The payload element MUST be encoded as in section 2.1. + + + +Kennedy Informational [Page 4] + +RFC 3252 Binary Lexical Octet Ad-hoc Transport 1 April 2002 + + + The TCP offset element was expanded to a maximum of 255 from 16 to + allow for the increased size of the header in XML. + + TCPoXML datagrams encapsulated by IPoXML MAY omit the <?xml?> header + as well as the <!DOCTYPE> declaration. + +3.2. Example Datagram + + The following is an example TCPoXML datagram with an empty payload: + + <?xml version="1.0" encoding="UTF-8"?> + <!DOCTYPE tcp PUBLIC "-//IETF//DTD BLOAT 1.0 TCP//EN" "bloat.dtd"> + <tcp> + <tcp.header> + <src port="31415"/> + <dest port="42424"/> + <sequence number="322622954"/> + <acknowledgement number="689715995"/> + <offset number=""/> + <reserved value="0"/> + <control syn="1" ack="1"/> + <window size="1"/> + <urgent pointer="0"/> + <checksum value="2988"/> + <tcp.options> + <tcp.end kind="0"/> + </tcp.options> + <padding pad="0"/> + </tcp.header> + <payload> + </payload> + </tcp> + +4. UDPoXML + + This protocol MUST be implemented to be compliant with this RFC. The + DTD for this document type can be found in section 7.3. + +4.1. UDP Description + + A number of items have changed from the original UDP specification. + Bit-masks, where present have been converted into human-readable + values. Length and checksum and port values are present as decimal + integers. + + + + + + + +Kennedy Informational [Page 5] + +RFC 3252 Binary Lexical Octet Ad-hoc Transport 1 April 2002 + + + To calculate the length and checksum fields of the UDP element, a + canonicalized form of the element MUST be used as in section 2.1. An + iterative method SHOULD be used to calculate checksums as in section + 2.1. + + The payload element MUST be encoded as in section 2.1. + + UDPoXML datagrams encapsulated by IPoXML MAY omit the <?xml?> header + as well as the <!DOCTYPE> declaration. + +4.2. Example Datagram + + The following is an example UDPoXML datagram with an empty payload: + + <?xml version="1.0" encoding="UTF-8"?> + <!DOCTYPE udp PUBLIC "-//IETF//DTD BLOAT 1.0 UDP//EN" "bloat.dtd"> + <udp> + <udp.header> + <src port="31415"/> + <dest port="42424"/> + <udp.length value="143"/> + <checksum value="2988"/> + </udp.header> + <payload> + </payload> + </udp> + +5. Network Transport + + This document provides for the transmission of BLOAT datagrams over + two common families of physical layer transport. Future RFCs will + address additional transports as routing vendors catch up to the + specification, and we begin to see BLOAT routed across the Internet + backbone. + +5.1. Ethernet + + BLOAT is encapsulated in Ethernet datagrams as in [RFC894] with the + exception that the type field of the Ethernet frame MUST contain the + value 0xBEEF. The first 5 octets of the Ethernet frame payload will + be 0x3c 3f 78 6d 6c ("<?xml".) + +5.2. IEEE 802 + + BLOAT is encapsulated in IEEE 802 Networks as in [RFC1042] except + that the protocol type code for IPoXML is 0xBEEF. + + + + + +Kennedy Informational [Page 6] + +RFC 3252 Binary Lexical Octet Ad-hoc Transport 1 April 2002 + + +6. Gatewaying over IP + + In order to facilitate the gradual introduction of BLOAT into the + public Internet, BLOAT MAY be encapsulated in IP as in [RFC2003] to + gateway between networks that run BLOAT natively on their LANs. + +7. DTDs + + The Transport DTDs (7.2. and 7.3.) build on the definitions in the + Network DTD (7.1.) + + The DTDs are referenced by their PubidLiteral and SystemLiteral (from + [XML]) although it is understood that most IPoXML implementations + will not need to pull down the DTD, as it will normally be embedded + in the implementation, and presents something of a catch-22 if you + need to load part of your network protocol over the network. + +7.1. IPoXML DTD + + <!-- + DTD for IP over XML. + Refer to this DTD as: + + <!DOCTYPE ip PUBLIC "-//IETF//DTD BLOAT 1.0 IP//EN" "bloat.dtd"> + --> + <!-- + DTD data types: + + Digits [0..9]+ + + Precedence "NetworkControl | InternetworkControl | + CRITIC | FlashOverride | Flash | Immediate | + Priority | Routine" + + IP4Addr "dotted-decimal" notation of [RFC1123] + + Class [0..3] + + Sec "Unclassified | Confidential | EFTO | MMMM | PROG | + Restricted | Secret | Top Secret | Reserved" + + Compartments [0..65535] + + Handling [0..65535] + + TCC [0..16777216] + + --> + + + +Kennedy Informational [Page 7] + +RFC 3252 Binary Lexical Octet Ad-hoc Transport 1 April 2002 + + + <!ENTITY % Digits "CDATA"> + <!ENTITY % Precedence "CDATA"> + <!ENTITY % IP4Addr "CDATA"> + <!ENTITY % Class "CDATA"> + <!ENTITY % Sec "CDATA"> + <!ENTITY % Compartments "CDATA"> + <!ENTITY % Handling "CDATA"> + <!ENTITY % TCC "CDATA"> + + <!ELEMENT ip (header, payload)> + + <!ELEMENT header (version, tos, total.length, id, flags, offset, ttl, + protocol, checksum, source, destination, options, + padding)> + <!-- length of header in 32-bit words --> + <!ATTLIST header + length %Digits; #REQUIRED> + + <!ELEMENT version EMPTY> + <!-- ip version. SHOULD be "4" --> + <!ATTLIST version + value %Digits; #REQUIRED> + + <!ELEMENT tos EMPTY> + <!ATTLIST tos + precedence %Precedence; #REQUIRED + delay (normal | low) #REQUIRED + throughput (normal | high) #REQUIRED + relibility (normal | high) #REQUIRED + reserved CDATA #FIXED "0"> + + <!ELEMENT total.length EMPTY> + <!-- + total length of datagram (header and payload) in octets, MUST be + less than 65,535 (and SHOULD be less than 1024 for IPoXML on local + ethernets). + --> + <!ATTLIST total.length + value %Digits; #REQUIRED> + + <!ELEMENT id EMPTY> + <!-- 0 <= id <= 65,535 --> + <!ATTLIST id + value %Digits; #REQUIRED> + + <!ELEMENT flags EMPTY> + <!-- df = don't fragment, mf = more fragments --> + <!ATTLIST flags + + + +Kennedy Informational [Page 8] + +RFC 3252 Binary Lexical Octet Ad-hoc Transport 1 April 2002 + + + reserved CDATA #FIXED "0" + df (may|dont) #REQUIRED + mf (last|more) #REQUIRED> + + <!ELEMENT offset EMPTY> + <!-- 0 <= offset <= 8192 measured in 8 octet (64-bit) chunks --> + <!ATTLIST offset + value %Digits; #REQUIRED> + + <!ELEMENT ttl EMPTY> + <!-- 0 <= ttl <= 255 --> + <!ATTLIST ttl + value %Digits; #REQUIRED> + + <!ELEMENT protocol EMPTY> + <!-- 0 <= protocol <= 255 (per IANA) --> + <!ATTLIST protocol + value %Digits; #REQUIRED> + + <!ELEMENT checksum EMPTY> + <!-- 0 <= checksum <= 65535 (over header only) --> + <!ATTLIST checksum + value %Digits; #REQUIRED> + + <!ELEMENT source EMPTY> + <!ATTLIST source + address %IP4Addr; #REQUIRED> + + <!ELEMENT destination EMPTY> + <!ATTLIST destination + address %IP4Addr; #REQUIRED> + + <!ELEMENT options ( end | noop | security | loose | strict | record + | stream | timestamp )*> + + <!ELEMENT end EMPTY> + <!ATTLIST end + copied (0|1) #REQUIRED + class CDATA #FIXED "0" + number CDATA #FIXED "0"> + + <!ELEMENT noop EMPTY> + <!ATTLIST noop + copied (0|1) #REQUIRED + class CDATA #FIXED "0" + number CDATA #FIXED "1"> + + <!ELEMENT security EMPTY> + + + +Kennedy Informational [Page 9] + +RFC 3252 Binary Lexical Octet Ad-hoc Transport 1 April 2002 + + + <!ATTLIST security + copied CDATA #FIXED "1" + class CDATA #FIXED "0" + number CDATA #FIXED "2" + length CDATA #FIXED "11" + security %Sec; #REQUIRED + compartments %Compartments; #REQUIRED + handling %Handling; #REQUIRED + tcc %TCC; #REQUIRED> + <!ELEMENT loose (hop)+> + <!ATTLIST loose + copied CDATA #FIXED "1" + class CDATA #FIXED "0" + number CDATA #FIXED "3" + length %Digits; #REQUIRED + pointer %Digits; #REQUIRED> + + <!ELEMENT hop EMPTY> + <!ATTLIST hop + address %IP4Addr; #REQUIRED> + + <!ELEMENT strict (hop)+> + <!ATTLIST strict + copied CDATA #FIXED "1" + class CDATA #FIXED "0" + number CDATA #FIXED "9" + length %Digits; #REQUIRED + pointer %Digits; #REQUIRED> + + <!ELEMENT record (hop)+> + <!ATTLIST record + copied CDATA #FIXED "0" + class CDATA #FIXED "0" + number CDATA #FIXED "7" + length %Digits; #REQUIRED + pointer %Digits; #REQUIRED> + + <!ELEMENT stream EMPTY> + <!-- 0 <= id <= 65,535 --> + <!ATTLIST stream + copied CDATA #FIXED "1" + class CDATA #FIXED "0" + number CDATA #FIXED "8" + length CDATA #FIXED "4" + id %Digits; #REQUIRED> + + <!ELEMENT timestamp (tstamp)+> + <!-- 0 <= oflw <=15 --> + + + +Kennedy Informational [Page 10] + +RFC 3252 Binary Lexical Octet Ad-hoc Transport 1 April 2002 + + + <!ATTLIST timestamp + copied CDATA #FIXED "0" + class CDATA #FIXED "2" + number CDATA #FIXED "4" + length %Digits; #REQUIRED + pointer %Digits; #REQUIRED + oflw %Digits; #REQUIRED + flag (0 | 1 | 3) #REQUIRED> + + <!ELEMENT tstamp EMPTY> + <!ATTLIST tstamp + time %Digits; #REQUIRED + address %IP4Addr; #IMPLIED> + <!-- + padding to bring header to 32-bit boundary. + pad MUST be "0"* + --> + <!ELEMENT padding EMPTY> + <!ATTLIST padding + pad CDATA #REQUIRED> + + <!-- payload MUST be encoded as base-64 [RFC2045], as modified + by section 2.1 of this RFC --> + <!ELEMENT payload (CDATA)> + +7.2. TCPoXML DTD + + <!-- + DTD for TCP over XML. + Refer to this DTD as: + + <!DOCTYPE tcp PUBLIC "-//IETF//DTD BLOAT 1.0 TCP//EN" "bloat.dtd"> + --> + + <!-- the pseudoheader is only included for checksum calculations --> + <!ELEMENT tcp (tcp.pseudoheader?, tcp.header, payload)> + + <!ELEMENT tcp.header (src, dest, sequence, acknowledgement, offset, + reserved, control, window, checksum, urgent, + tcp.options, padding)> + + <!ELEMENT src EMPTY> + <!-- 0 <= port <= 65,535 --> + <!ATTLIST src + port %Digits; #REQUIRED> + + <!ELEMENT dest EMPTY> + <!-- 0 <= port <= 65,535 --> + + + +Kennedy Informational [Page 11] + +RFC 3252 Binary Lexical Octet Ad-hoc Transport 1 April 2002 + + + <!ATTLIST dest + port %Digits; #REQUIRED> + + <!ELEMENT sequence EMPTY> + <!-- 0 <= number <= 4294967295 --> + <!ATTLIST sequence + number %Digits; #REQUIRED> + + <!ELEMENT acknowledgement EMPTY> + <!-- 0 <= number <= 4294967295 --> + <!ATTLIST acknowledgement + number %Digits; #REQUIRED> + + <!ELEMENT offset EMPTY> + <!-- 0 <= number <= 255 --> + <!ATTLIST offset + number %Digits; #REQUIRED> + + <!ELEMENT reserved EMPTY> + <!ATTLIST reserved + value CDATA #FIXED "0"> + + <!ELEMENT control EMPTY> + <!ATTLIST control + urg (0|1) #IMPLIED + ack (0|1) #IMPLIED + psh (0|1) #IMPLIED + rst (0|1) #IMPLIED + syn (0|1) #IMPLIED + fin (0|1) #IMPLIED> + + <!ELEMENT window EMPTY> + <!-- 0 <= size <= 65,535 --> + <!ATTLIST window + size %Digits; #REQUIRED> + + <!-- + checksum as in ip, but with + the following pseudo-header added into the tcp element: + --> + <!ELEMENT tcp.pseudoheader (source, destination, protocol, + tcp.length)> + + <!-- + tcp header + data length in octets. does not include the size of + + the pseudoheader. + --> + + + +Kennedy Informational [Page 12] + +RFC 3252 Binary Lexical Octet Ad-hoc Transport 1 April 2002 + + + <!ELEMENT tcp.length EMPTY> + <!ATTLIST tcp.length + value %Digits; #REQUIRED> + + <!ELEMENT urgent EMPTY> + <!-- 0 <= pointer <= 65,535 --> + <!ATTLIST urgent + pointer %Digits; #REQUIRED> + + <!ELEMENT tcp.options (tcp.end | tcp.noop | tcp.mss)+> + + <!ELEMENT tcp.end EMPTY> + <!ATTLIST tcp.end + kind CDATA #FIXED "0"> + + <!ELEMENT tcp.noop EMPTY> + <!ATTLIST tcp.noop + kind CDATA #FIXED "1"> + + <!ELEMENT tcp.mss EMPTY> + <!ATTLIST tcp.mss + kind CDATA #FIXED "2" + length CDATA #FIXED "4" + size %Digits; #REQUIRED> + +7.3. UDPoXML DTD + + <!-- + DTD for UDP over XML. + Refer to this DTD as: + + <!DOCTYPE udp PUBLIC "-//IETF//DTD BLOAT 1.0 UDP//EN" "bloat.dtd"> + --> + + <!ELEMENT udp (udp.pseudoheader?, udp.header, payload)> + + <!ELEMENT udp.header (src, dest, udp.length, checksum)> + + <!ELEMENT udp.pseudoheader (source, destination, protocol, + udp.length)> + + <!-- + udp header + data length in octets. does not include the size of + the pseudoheader. + --> + <!ELEMENT udp.length EMPTY> + <!ATTLIST udp.length + value %Digits; #REQUIRED> + + + +Kennedy Informational [Page 13] + +RFC 3252 Binary Lexical Octet Ad-hoc Transport 1 April 2002 + + +8. Security Considerations + + XML, as a subset of SGML, has the same security considerations as + specified in SGML Media Types [RFC1874]. Security considerations + that apply to IP, TCP and UDP also likely apply to BLOAT as it does + not attempt to correct for issues not related to message format. + +9. References + + [JABBER] Miller, J., "Jabber", draft-miller-jabber-00.txt, + February 2002. (Work in Progress) + + [RFC768] Postel, J., "User Datagram Protocol", STD 6, RFC 768, + August 1980. + + [RFC791] Postel, J., "Internet Protocol", STD 5, RFC 791, + September 1981. + + [RFC793] Postel, J., "Transmission Control Protocol", STD 7, RFC + 793, September 1981. + + [RFC894] Hornig, C., "Standard for the Transmission of IP + Datagrams over Ethernet Networks.", RFC 894, April 1984. + + [RFC1042] Postel, J. and J. Reynolds, "Standard for the + Transmission of IP Datagrams Over IEEE 802 Networks", STD + 43, RFC 1042, February 1988. + + [RFC1123] Braden, R., "Requirements for Internet Hosts - + Application and Support", RFC 1123, October 1989. + + [RFC1874] Levinson, E., "SGML Media Types", RFC 1874, December + 1995. + + [RFC2003] Perkins, C., "IP Encapsulation within IP", RFC 2003, + October 1996. + + [RFC2045] Freed, N. and N. Borenstein, "Multipurpose Internet Mail + Extensions (MIME) Part One: Format of Internet Message + Bodies", RFC 2045, November 1996. + + [RFC2119] Bradner, S., "Key words for use in RFCs to Indicate + Requirement Levels", BCP 14, RFC 2119, March 1997. + + [RFC2279] Yergeau, F., "UTF-8, a transformation format of ISO + 10646", RFC 2279, January 1998. + + + + + +Kennedy Informational [Page 14] + +RFC 3252 Binary Lexical Octet Ad-hoc Transport 1 April 2002 + + + [RFC2460] Deering, S. and R. Hinden, "Internet Protocol, Version 6 + (IPv6) Specification", RFC 2460, December 1998. + + [RFC3080] Rose, M., "The Blocks Extensible Exchange Protocol Core", + RFC 3080, March 2001. + + [SOAP] Box, D., Ehnebuske, D., Kakivaya, G., Layman, A., + Mendelsohn, N., Nielsen, H. F., Thatte, S. Winer, D., + "Simple Object Access Protocol (SOAP) 1.1" World Wide Web + Consortium Note, May 2000 http://www.w3.org/TR/SOAP/ + + [XML] Bray, T., Paoli, J., Sperberg-McQueen, C. M., "Extensible + Markup Language (XML)" World Wide Web Consortium + Recommendation REC- xml-19980210. + http://www.w3.org/TR/1998/REC-xml-19980210 + +10. Author's Address + + Hugh Kennedy + Mimezine + 1060 West Addison + Chicago, IL 60613 + USA + + EMail: kennedyh@engin.umich.edu + + + + + + + + + + + + + + + + + + + + + + + + + + +Kennedy Informational [Page 15] + +RFC 3252 Binary Lexical Octet Ad-hoc Transport 1 April 2002 + + +11. Full Copyright Statement + + Copyright (C) The Internet Society (2002). All Rights Reserved. + + This document and translations of it may be copied and furnished to + others, and derivative works that comment on or otherwise explain it + or assist in its implementation may be prepared, copied, published + and distributed, in whole or in part, without restriction of any + kind, provided that the above copyright notice and this paragraph are + included on all such copies and derivative works. However, this + document itself may not be modified in any way, such as by removing + the copyright notice or references to the Internet Society or other + Internet organizations, except as needed for the purpose of + developing Internet standards in which case the procedures for + copyrights defined in the Internet Standards process must be + followed, or as required to translate it into languages other than + English. + + The limited permissions granted above are perpetual and will not be + revoked by the Internet Society or its successors or assigns. + + This document and the information contained herein is provided on an + "AS IS" basis and THE INTERNET SOCIETY AND THE INTERNET ENGINEERING + TASK FORCE DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING + BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE INFORMATION + HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED WARRANTIES OF + MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. + +Acknowledgement + + Funding for the RFC Editor function is currently provided by the + Internet Society. + + + + + + + + + + + + + + + + + + + +Kennedy Informational [Page 16] + + + + + + + +Network Working Group H. Kennedy +Request for Comments: 3252 Mimezine +Category: Informational 1 April 2002 + + + Binary Lexical Octet Ad-hoc Transport + +Status of this Memo + + This memo provides information for the Internet community. It does + not specify an Internet standard of any kind. Distribution of this + memo is unlimited. + +Copyright Notice + + Copyright (C) The Internet Society (2002). All Rights Reserved. + +Abstract + + This document defines a reformulation of IP and two transport layer + protocols (TCP and UDP) as XML applications. + +1. Introduction + +1.1. Overview + + This document describes the Binary Lexical Octet Ad-hoc Transport + (BLOAT): a reformulation of a widely-deployed network-layer protocol + (IP [RFC791]), and two associated transport layer protocols (TCP + [RFC793] and UDP [RFC768]) as XML [XML] applications. It also + describes methods for transporting BLOAT over Ethernet and IEEE 802 + networks as well as encapsulating BLOAT in IP for gatewaying BLOAT + across the public Internet. + +1.2. Motivation + + The wild popularity of XML as a basis for application-level protocols + such as the Blocks Extensible Exchange Protocol [RFC3080], the Simple + Object Access Protocol [SOAP], and Jabber [JABBER] prompted + investigation into the possibility of extending the use of XML in the + protocol stack. Using XML at both the transport and network layer in + addition to the application layer would provide for an amazing amount + of power and flexibility while removing dependencies on proprietary + and hard-to-understand binary protocols. This protocol unification + would also allow applications to use a single XML parser for all + aspects of their operation, eliminating developer time spent figuring + out the intricacies of each new protocol, and moving the hard work of + + + + +Kennedy Informational [Page 1] + +RFC 3252 Binary Lexical Octet Ad-hoc Transport 1 April 2002 + + + parsing to the XML toolset. The use of XML also mitigates concerns + over "network vs. host" byte ordering which is at the root of many + network application bugs. + +1.3. Relation to Existing Protocols + + The reformulations specified in this RFC follow as closely as + possible the spirit of the RFCs on which they are based, and so MAY + contain elements or attributes that would not be needed in a pure + reworking (e.g. length attributes, which are implicit in XML.) + + The layering of network and transport protocols are maintained in + this RFC despite the optimizations that could be made if the line + were somewhat blurred (i.e. merging TCP and IP into a single, larger + element in the DTD) in order to foster future use of this protocol as + a basis for reformulating other protocols (such as ICMP.) + + Other than the encoding, the behavioral aspects of each of the + existing protocols remain unchanged. Routing, address spaces, TCP + congestion control, etc. behave as specified in the extant standards. + Adapting to new standards and experimental algorithm heuristics for + improving performance will become much easier once the move to BLOAT + has been completed. + +1.4. Requirement Levels + + The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", + "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this + document are to be interpreted as described in BCP 14, RFC 2119 + [RFC2119]. + +2. IPoXML + + This protocol MUST be implemented to be compliant with this RFC. + IPoXML is the root protocol REQUIRED for effective use of TCPoXML + (section 3.) and higher-level application protocols. + + The DTD for this document type can be found in section 7.1. + + The routing of IPoXML can be easily implemented on hosts with an XML + parser, as the regular structure lends itself handily to parsing and + validation of the document/datagram and then processing the + destination address, TTL, and checksum before sending it on to its + next-hop. + + The reformulation of IPv4 was chosen over IPv6 [RFC2460] due to the + wider deployment of IPv4 and the fact that implementing IPv6 as XML + would have exceeded the 1500 byte Ethernet MTU. + + + +Kennedy Informational [Page 2] + +RFC 3252 Binary Lexical Octet Ad-hoc Transport 1 April 2002 + + + All BLOAT implementations MUST use - and specify - the UTF-8 encoding + of RFC 2279 [RFC2279]. All BLOAT document/datagrams MUST be well- + formed and include the XMLDecl. + +2.1. IP Description + + A number of items have changed (for the better) from the original IP + specification. Bit-masks, where present have been converted into + human-readable values. IP addresses are listed in their dotted- + decimal notation [RFC1123]. Length and checksum values are present + as decimal integers. + + To calculate the length and checksum fields of the IP element, a + canonicalized form of the element MUST be used. The canonical form + SHALL have no whitespace (including newline characters) between + elements and only one space character between attributes. There + SHALL NOT be a space following the last attribute in an element. + + An iterative method SHOULD be used to calculate checksums, as the + length field will vary based on the size of the checksum. + + The payload element bears special attention. Due to the character + set restrictions of XML, the payload of IP datagrams (which MAY + contain arbitrary data) MUST be encoded for transport. This RFC + REQUIRES the contents of the payload to be encoded in the base-64 + encoding of RFC 2045 [RFC2045], but removes the requirement that the + encoded output MUST be wrapped on 76-character lines. + + + + + + + + + + + + + + + + + + + + + + + + +Kennedy Informational [Page 3] + +RFC 3252 Binary Lexical Octet Ad-hoc Transport 1 April 2002 + + +2.2. Example Datagram + + The following is an example IPoXML datagram with an empty payload: + + <?xml version="1.0" encoding="UTF-8"?> + <!DOCTYPE ip PUBLIC "-//IETF//DTD BLOAT 1.0 IP//EN" "bloat.dtd"> + <ip> + <header length="474"> + <version value="4"/> + <tos precedence="Routine" delay="Normal" throughput="Normal" + relibility="Normal" reserved="0"/> + <total.length value="461"/> + <id value="1"/> + <flags reserved="0" df="dont" mf="last"/> + <offset value="0"/> + <ttl value="255"/> + <protocol value="6"/> + <checksum value="8707"/> + <source address="10.0.0.22"/> + <destination address="10.0.0.1"/> + <options> + <end copied="0" class="0" number="0"/> + </options> + <padding pad="0"/> + </header> + <payload> + </payload> + </ip> + +3. TCPoXML + + This protocol MUST be implemented to be compliant with this RFC. The + DTD for this document type can be found in section 7.2. + +3.1. TCP Description + + A number of items have changed from the original TCP specification. + Bit-masks, where present have been converted into human-readable + values. Length and checksum and port values are present as decimal + integers. + + To calculate the length and checksum fields of the TCP element, a + canonicalized form of the element MUST be used as in section 2.1. + + An iterative method SHOULD be used to calculate checksums as in + section 2.1. + + The payload element MUST be encoded as in section 2.1. + + + +Kennedy Informational [Page 4] + +RFC 3252 Binary Lexical Octet Ad-hoc Transport 1 April 2002 + + + The TCP offset element was expanded to a maximum of 255 from 16 to + allow for the increased size of the header in XML. + + TCPoXML datagrams encapsulated by IPoXML MAY omit the <?xml?> header + as well as the <!DOCTYPE> declaration. + +3.2. Example Datagram + + The following is an example TCPoXML datagram with an empty payload: + + <?xml version="1.0" encoding="UTF-8"?> + <!DOCTYPE tcp PUBLIC "-//IETF//DTD BLOAT 1.0 TCP//EN" "bloat.dtd"> + <tcp> + <tcp.header> + <src port="31415"/> + <dest port="42424"/> + <sequence number="322622954"/> + <acknowledgement number="689715995"/> + <offset number=""/> + <reserved value="0"/> + <control syn="1" ack="1"/> + <window size="1"/> + <urgent pointer="0"/> + <checksum value="2988"/> + <tcp.options> + <tcp.end kind="0"/> + </tcp.options> + <padding pad="0"/> + </tcp.header> + <payload> + </payload> + </tcp> + +4. UDPoXML + + This protocol MUST be implemented to be compliant with this RFC. The + DTD for this document type can be found in section 7.3. + +4.1. UDP Description + + A number of items have changed from the original UDP specification. + Bit-masks, where present have been converted into human-readable + values. Length and checksum and port values are present as decimal + integers. + + + + + + + +Kennedy Informational [Page 5] + +RFC 3252 Binary Lexical Octet Ad-hoc Transport 1 April 2002 + + + To calculate the length and checksum fields of the UDP element, a + canonicalized form of the element MUST be used as in section 2.1. An + iterative method SHOULD be used to calculate checksums as in section + 2.1. + + The payload element MUST be encoded as in section 2.1. + + UDPoXML datagrams encapsulated by IPoXML MAY omit the <?xml?> header + as well as the <!DOCTYPE> declaration. + +4.2. Example Datagram + + The following is an example UDPoXML datagram with an empty payload: + + <?xml version="1.0" encoding="UTF-8"?> + <!DOCTYPE udp PUBLIC "-//IETF//DTD BLOAT 1.0 UDP//EN" "bloat.dtd"> + <udp> + <udp.header> + <src port="31415"/> + <dest port="42424"/> + <udp.length value="143"/> + <checksum value="2988"/> + </udp.header> + <payload> + </payload> + </udp> + +5. Network Transport + + This document provides for the transmission of BLOAT datagrams over + two common families of physical layer transport. Future RFCs will + address additional transports as routing vendors catch up to the + specification, and we begin to see BLOAT routed across the Internet + backbone. + +5.1. Ethernet + + BLOAT is encapsulated in Ethernet datagrams as in [RFC894] with the + exception that the type field of the Ethernet frame MUST contain the + value 0xBEEF. The first 5 octets of the Ethernet frame payload will + be 0x3c 3f 78 6d 6c ("<?xml".) + +5.2. IEEE 802 + + BLOAT is encapsulated in IEEE 802 Networks as in [RFC1042] except + that the protocol type code for IPoXML is 0xBEEF. + + + + + +Kennedy Informational [Page 6] + +RFC 3252 Binary Lexical Octet Ad-hoc Transport 1 April 2002 + + +6. Gatewaying over IP + + In order to facilitate the gradual introduction of BLOAT into the + public Internet, BLOAT MAY be encapsulated in IP as in [RFC2003] to + gateway between networks that run BLOAT natively on their LANs. + +7. DTDs + + The Transport DTDs (7.2. and 7.3.) build on the definitions in the + Network DTD (7.1.) + + The DTDs are referenced by their PubidLiteral and SystemLiteral (from + [XML]) although it is understood that most IPoXML implementations + will not need to pull down the DTD, as it will normally be embedded + in the implementation, and presents something of a catch-22 if you + need to load part of your network protocol over the network. + +7.1. IPoXML DTD + + <!-- + DTD for IP over XML. + Refer to this DTD as: + + <!DOCTYPE ip PUBLIC "-//IETF//DTD BLOAT 1.0 IP//EN" "bloat.dtd"> + --> + <!-- + DTD data types: + + Digits [0..9]+ + + Precedence "NetworkControl | InternetworkControl | + CRITIC | FlashOverride | Flash | Immediate | + Priority | Routine" + + IP4Addr "dotted-decimal" notation of [RFC1123] + + Class [0..3] + + Sec "Unclassified | Confidential | EFTO | MMMM | PROG | + Restricted | Secret | Top Secret | Reserved" + + Compartments [0..65535] + + Handling [0..65535] + + TCC [0..16777216] + + --> + + + +Kennedy Informational [Page 7] + +RFC 3252 Binary Lexical Octet Ad-hoc Transport 1 April 2002 + + + <!ENTITY % Digits "CDATA"> + <!ENTITY % Precedence "CDATA"> + <!ENTITY % IP4Addr "CDATA"> + <!ENTITY % Class "CDATA"> + <!ENTITY % Sec "CDATA"> + <!ENTITY % Compartments "CDATA"> + <!ENTITY % Handling "CDATA"> + <!ENTITY % TCC "CDATA"> + + <!ELEMENT ip (header, payload)> + + <!ELEMENT header (version, tos, total.length, id, flags, offset, ttl, + protocol, checksum, source, destination, options, + padding)> + <!-- length of header in 32-bit words --> + <!ATTLIST header + length %Digits; #REQUIRED> + + <!ELEMENT version EMPTY> + <!-- ip version. SHOULD be "4" --> + <!ATTLIST version + value %Digits; #REQUIRED> + + <!ELEMENT tos EMPTY> + <!ATTLIST tos + precedence %Precedence; #REQUIRED + delay (normal | low) #REQUIRED + throughput (normal | high) #REQUIRED + relibility (normal | high) #REQUIRED + reserved CDATA #FIXED "0"> + + <!ELEMENT total.length EMPTY> + <!-- + total length of datagram (header and payload) in octets, MUST be + less than 65,535 (and SHOULD be less than 1024 for IPoXML on local + ethernets). + --> + <!ATTLIST total.length + value %Digits; #REQUIRED> + + <!ELEMENT id EMPTY> + <!-- 0 <= id <= 65,535 --> + <!ATTLIST id + value %Digits; #REQUIRED> + + <!ELEMENT flags EMPTY> + <!-- df = don't fragment, mf = more fragments --> + <!ATTLIST flags + + + +Kennedy Informational [Page 8] + +RFC 3252 Binary Lexical Octet Ad-hoc Transport 1 April 2002 + + + reserved CDATA #FIXED "0" + df (may|dont) #REQUIRED + mf (last|more) #REQUIRED> + + <!ELEMENT offset EMPTY> + <!-- 0 <= offset <= 8192 measured in 8 octet (64-bit) chunks --> + <!ATTLIST offset + value %Digits; #REQUIRED> + + <!ELEMENT ttl EMPTY> + <!-- 0 <= ttl <= 255 --> + <!ATTLIST ttl + value %Digits; #REQUIRED> + + <!ELEMENT protocol EMPTY> + <!-- 0 <= protocol <= 255 (per IANA) --> + <!ATTLIST protocol + value %Digits; #REQUIRED> + + <!ELEMENT checksum EMPTY> + <!-- 0 <= checksum <= 65535 (over header only) --> + <!ATTLIST checksum + value %Digits; #REQUIRED> + + <!ELEMENT source EMPTY> + <!ATTLIST source + address %IP4Addr; #REQUIRED> + + <!ELEMENT destination EMPTY> + <!ATTLIST destination + address %IP4Addr; #REQUIRED> + + <!ELEMENT options ( end | noop | security | loose | strict | record + | stream | timestamp )*> + + <!ELEMENT end EMPTY> + <!ATTLIST end + copied (0|1) #REQUIRED + class CDATA #FIXED "0" + number CDATA #FIXED "0"> + + <!ELEMENT noop EMPTY> + <!ATTLIST noop + copied (0|1) #REQUIRED + class CDATA #FIXED "0" + number CDATA #FIXED "1"> + + <!ELEMENT security EMPTY> + + + +Kennedy Informational [Page 9] + +RFC 3252 Binary Lexical Octet Ad-hoc Transport 1 April 2002 + + + <!ATTLIST security + copied CDATA #FIXED "1" + class CDATA #FIXED "0" + number CDATA #FIXED "2" + length CDATA #FIXED "11" + security %Sec; #REQUIRED + compartments %Compartments; #REQUIRED + handling %Handling; #REQUIRED + tcc %TCC; #REQUIRED> + <!ELEMENT loose (hop)+> + <!ATTLIST loose + copied CDATA #FIXED "1" + class CDATA #FIXED "0" + number CDATA #FIXED "3" + length %Digits; #REQUIRED + pointer %Digits; #REQUIRED> + + <!ELEMENT hop EMPTY> + <!ATTLIST hop + address %IP4Addr; #REQUIRED> + + <!ELEMENT strict (hop)+> + <!ATTLIST strict + copied CDATA #FIXED "1" + class CDATA #FIXED "0" + number CDATA #FIXED "9" + length %Digits; #REQUIRED + pointer %Digits; #REQUIRED> + + <!ELEMENT record (hop)+> + <!ATTLIST record + copied CDATA #FIXED "0" + class CDATA #FIXED "0" + number CDATA #FIXED "7" + length %Digits; #REQUIRED + pointer %Digits; #REQUIRED> + + <!ELEMENT stream EMPTY> + <!-- 0 <= id <= 65,535 --> + <!ATTLIST stream + copied CDATA #FIXED "1" + class CDATA #FIXED "0" + number CDATA #FIXED "8" + length CDATA #FIXED "4" + id %Digits; #REQUIRED> + + <!ELEMENT timestamp (tstamp)+> + <!-- 0 <= oflw <=15 --> + + + +Kennedy Informational [Page 10] + +RFC 3252 Binary Lexical Octet Ad-hoc Transport 1 April 2002 + + + <!ATTLIST timestamp + copied CDATA #FIXED "0" + class CDATA #FIXED "2" + number CDATA #FIXED "4" + length %Digits; #REQUIRED + pointer %Digits; #REQUIRED + oflw %Digits; #REQUIRED + flag (0 | 1 | 3) #REQUIRED> + + <!ELEMENT tstamp EMPTY> + <!ATTLIST tstamp + time %Digits; #REQUIRED + address %IP4Addr; #IMPLIED> + <!-- + padding to bring header to 32-bit boundary. + pad MUST be "0"* + --> + <!ELEMENT padding EMPTY> + <!ATTLIST padding + pad CDATA #REQUIRED> + + <!-- payload MUST be encoded as base-64 [RFC2045], as modified + by section 2.1 of this RFC --> + <!ELEMENT payload (CDATA)> + +7.2. TCPoXML DTD + + <!-- + DTD for TCP over XML. + Refer to this DTD as: + + <!DOCTYPE tcp PUBLIC "-//IETF//DTD BLOAT 1.0 TCP//EN" "bloat.dtd"> + --> + + <!-- the pseudoheader is only included for checksum calculations --> + <!ELEMENT tcp (tcp.pseudoheader?, tcp.header, payload)> + + <!ELEMENT tcp.header (src, dest, sequence, acknowledgement, offset, + reserved, control, window, checksum, urgent, + tcp.options, padding)> + + <!ELEMENT src EMPTY> + <!-- 0 <= port <= 65,535 --> + <!ATTLIST src + port %Digits; #REQUIRED> + + <!ELEMENT dest EMPTY> + <!-- 0 <= port <= 65,535 --> + + + +Kennedy Informational [Page 11] + +RFC 3252 Binary Lexical Octet Ad-hoc Transport 1 April 2002 + + + <!ATTLIST dest + port %Digits; #REQUIRED> + + <!ELEMENT sequence EMPTY> + <!-- 0 <= number <= 4294967295 --> + <!ATTLIST sequence + number %Digits; #REQUIRED> + + <!ELEMENT acknowledgement EMPTY> + <!-- 0 <= number <= 4294967295 --> + <!ATTLIST acknowledgement + number %Digits; #REQUIRED> + + <!ELEMENT offset EMPTY> + <!-- 0 <= number <= 255 --> + <!ATTLIST offset + number %Digits; #REQUIRED> + + <!ELEMENT reserved EMPTY> + <!ATTLIST reserved + value CDATA #FIXED "0"> + + <!ELEMENT control EMPTY> + <!ATTLIST control + urg (0|1) #IMPLIED + ack (0|1) #IMPLIED + psh (0|1) #IMPLIED + rst (0|1) #IMPLIED + syn (0|1) #IMPLIED + fin (0|1) #IMPLIED> + + <!ELEMENT window EMPTY> + <!-- 0 <= size <= 65,535 --> + <!ATTLIST window + size %Digits; #REQUIRED> + + <!-- + checksum as in ip, but with + the following pseudo-header added into the tcp element: + --> + <!ELEMENT tcp.pseudoheader (source, destination, protocol, + tcp.length)> + + <!-- + tcp header + data length in octets. does not include the size of + + the pseudoheader. + --> + + + +Kennedy Informational [Page 12] + +RFC 3252 Binary Lexical Octet Ad-hoc Transport 1 April 2002 + + + <!ELEMENT tcp.length EMPTY> + <!ATTLIST tcp.length + value %Digits; #REQUIRED> + + <!ELEMENT urgent EMPTY> + <!-- 0 <= pointer <= 65,535 --> + <!ATTLIST urgent + pointer %Digits; #REQUIRED> + + <!ELEMENT tcp.options (tcp.end | tcp.noop | tcp.mss)+> + + <!ELEMENT tcp.end EMPTY> + <!ATTLIST tcp.end + kind CDATA #FIXED "0"> + + <!ELEMENT tcp.noop EMPTY> + <!ATTLIST tcp.noop + kind CDATA #FIXED "1"> + + <!ELEMENT tcp.mss EMPTY> + <!ATTLIST tcp.mss + kind CDATA #FIXED "2" + length CDATA #FIXED "4" + size %Digits; #REQUIRED> + +7.3. UDPoXML DTD + + <!-- + DTD for UDP over XML. + Refer to this DTD as: + + <!DOCTYPE udp PUBLIC "-//IETF//DTD BLOAT 1.0 UDP//EN" "bloat.dtd"> + --> + + <!ELEMENT udp (udp.pseudoheader?, udp.header, payload)> + + <!ELEMENT udp.header (src, dest, udp.length, checksum)> + + <!ELEMENT udp.pseudoheader (source, destination, protocol, + udp.length)> + + <!-- + udp header + data length in octets. does not include the size of + the pseudoheader. + --> + <!ELEMENT udp.length EMPTY> + <!ATTLIST udp.length + value %Digits; #REQUIRED> + + + +Kennedy Informational [Page 13] + +RFC 3252 Binary Lexical Octet Ad-hoc Transport 1 April 2002 + + +8. Security Considerations + + XML, as a subset of SGML, has the same security considerations as + specified in SGML Media Types [RFC1874]. Security considerations + that apply to IP, TCP and UDP also likely apply to BLOAT as it does + not attempt to correct for issues not related to message format. + +9. References + + [JABBER] Miller, J., "Jabber", draft-miller-jabber-00.txt, + February 2002. (Work in Progress) + + [RFC768] Postel, J., "User Datagram Protocol", STD 6, RFC 768, + August 1980. + + [RFC791] Postel, J., "Internet Protocol", STD 5, RFC 791, + September 1981. + + [RFC793] Postel, J., "Transmission Control Protocol", STD 7, RFC + 793, September 1981. + + [RFC894] Hornig, C., "Standard for the Transmission of IP + Datagrams over Ethernet Networks.", RFC 894, April 1984. + + [RFC1042] Postel, J. and J. Reynolds, "Standard for the + Transmission of IP Datagrams Over IEEE 802 Networks", STD + 43, RFC 1042, February 1988. + + [RFC1123] Braden, R., "Requirements for Internet Hosts - + Application and Support", RFC 1123, October 1989. + + [RFC1874] Levinson, E., "SGML Media Types", RFC 1874, December + 1995. + + [RFC2003] Perkins, C., "IP Encapsulation within IP", RFC 2003, + October 1996. + + [RFC2045] Freed, N. and N. Borenstein, "Multipurpose Internet Mail + Extensions (MIME) Part One: Format of Internet Message + Bodies", RFC 2045, November 1996. + + [RFC2119] Bradner, S., "Key words for use in RFCs to Indicate + Requirement Levels", BCP 14, RFC 2119, March 1997. + + [RFC2279] Yergeau, F., "UTF-8, a transformation format of ISO + 10646", RFC 2279, January 1998. + + + + + +Kennedy Informational [Page 14] + +RFC 3252 Binary Lexical Octet Ad-hoc Transport 1 April 2002 + + + [RFC2460] Deering, S. and R. Hinden, "Internet Protocol, Version 6 + (IPv6) Specification", RFC 2460, December 1998. + + [RFC3080] Rose, M., "The Blocks Extensible Exchange Protocol Core", + RFC 3080, March 2001. + + [SOAP] Box, D., Ehnebuske, D., Kakivaya, G., Layman, A., + Mendelsohn, N., Nielsen, H. F., Thatte, S. Winer, D., + "Simple Object Access Protocol (SOAP) 1.1" World Wide Web + Consortium Note, May 2000 http://www.w3.org/TR/SOAP/ + + [XML] Bray, T., Paoli, J., Sperberg-McQueen, C. M., "Extensible + Markup Language (XML)" World Wide Web Consortium + Recommendation REC- xml-19980210. + http://www.w3.org/TR/1998/REC-xml-19980210 + +10. Author's Address + + Hugh Kennedy + Mimezine + 1060 West Addison + Chicago, IL 60613 + USA + + EMail: kennedyh@engin.umich.edu + + + + + + + + + + + + + + + + + + + + + + + + + + +Kennedy Informational [Page 15] + +RFC 3252 Binary Lexical Octet Ad-hoc Transport 1 April 2002 + + +11. Full Copyright Statement + + Copyright (C) The Internet Society (2002). All Rights Reserved. + + This document and translations of it may be copied and furnished to + others, and derivative works that comment on or otherwise explain it + or assist in its implementation may be prepared, copied, published + and distributed, in whole or in part, without restriction of any + kind, provided that the above copyright notice and this paragraph are + included on all such copies and derivative works. However, this + document itself may not be modified in any way, such as by removing + the copyright notice or references to the Internet Society or other + Internet organizations, except as needed for the purpose of + developing Internet standards in which case the procedures for + copyrights defined in the Internet Standards process must be + followed, or as required to translate it into languages other than + English. + + The limited permissions granted above are perpetual and will not be + revoked by the Internet Society or its successors or assigns. + + This document and the information contained herein is provided on an + "AS IS" basis and THE INTERNET SOCIETY AND THE INTERNET ENGINEERING + TASK FORCE DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING + BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE INFORMATION + HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED WARRANTIES OF + MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. + +Acknowledgement + + Funding for the RFC Editor function is currently provided by the + Internet Society. + + + + + + + + + + + + + + + + + + + +Kennedy Informational [Page 16] + + + + + + + +Network Working Group H. Kennedy +Request for Comments: 3252 Mimezine +Category: Informational 1 April 2002 + + + Binary Lexical Octet Ad-hoc Transport + +Status of this Memo + + This memo provides information for the Internet community. It does + not specify an Internet standard of any kind. Distribution of this + memo is unlimited. + +Copyright Notice + + Copyright (C) The Internet Society (2002). All Rights Reserved. + +Abstract + + This document defines a reformulation of IP and two transport layer + protocols (TCP and UDP) as XML applications. + +1. Introduction + +1.1. Overview + + This document describes the Binary Lexical Octet Ad-hoc Transport + (BLOAT): a reformulation of a widely-deployed network-layer protocol + (IP [RFC791]), and two associated transport layer protocols (TCP + [RFC793] and UDP [RFC768]) as XML [XML] applications. It also + describes methods for transporting BLOAT over Ethernet and IEEE 802 + networks as well as encapsulating BLOAT in IP for gatewaying BLOAT + across the public Internet. + +1.2. Motivation + + The wild popularity of XML as a basis for application-level protocols + such as the Blocks Extensible Exchange Protocol [RFC3080], the Simple + Object Access Protocol [SOAP], and Jabber [JABBER] prompted + investigation into the possibility of extending the use of XML in the + protocol stack. Using XML at both the transport and network layer in + addition to the application layer would provide for an amazing amount + of power and flexibility while removing dependencies on proprietary + and hard-to-understand binary protocols. This protocol unification + would also allow applications to use a single XML parser for all + aspects of their operation, eliminating developer time spent figuring + out the intricacies of each new protocol, and moving the hard work of + + + + +Kennedy Informational [Page 1] + +RFC 3252 Binary Lexical Octet Ad-hoc Transport 1 April 2002 + + + parsing to the XML toolset. The use of XML also mitigates concerns + over "network vs. host" byte ordering which is at the root of many + network application bugs. + +1.3. Relation to Existing Protocols + + The reformulations specified in this RFC follow as closely as + possible the spirit of the RFCs on which they are based, and so MAY + contain elements or attributes that would not be needed in a pure + reworking (e.g. length attributes, which are implicit in XML.) + + The layering of network and transport protocols are maintained in + this RFC despite the optimizations that could be made if the line + were somewhat blurred (i.e. merging TCP and IP into a single, larger + element in the DTD) in order to foster future use of this protocol as + a basis for reformulating other protocols (such as ICMP.) + + Other than the encoding, the behavioral aspects of each of the + existing protocols remain unchanged. Routing, address spaces, TCP + congestion control, etc. behave as specified in the extant standards. + Adapting to new standards and experimental algorithm heuristics for + improving performance will become much easier once the move to BLOAT + has been completed. + +1.4. Requirement Levels + + The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", + "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this + document are to be interpreted as described in BCP 14, RFC 2119 + [RFC2119]. + +2. IPoXML + + This protocol MUST be implemented to be compliant with this RFC. + IPoXML is the root protocol REQUIRED for effective use of TCPoXML + (section 3.) and higher-level application protocols. + + The DTD for this document type can be found in section 7.1. + + The routing of IPoXML can be easily implemented on hosts with an XML + parser, as the regular structure lends itself handily to parsing and + validation of the document/datagram and then processing the + destination address, TTL, and checksum before sending it on to its + next-hop. + + The reformulation of IPv4 was chosen over IPv6 [RFC2460] due to the + wider deployment of IPv4 and the fact that implementing IPv6 as XML + would have exceeded the 1500 byte Ethernet MTU. + + + +Kennedy Informational [Page 2] + +RFC 3252 Binary Lexical Octet Ad-hoc Transport 1 April 2002 + + + All BLOAT implementations MUST use - and specify - the UTF-8 encoding + of RFC 2279 [RFC2279]. All BLOAT document/datagrams MUST be well- + formed and include the XMLDecl. + +2.1. IP Description + + A number of items have changed (for the better) from the original IP + specification. Bit-masks, where present have been converted into + human-readable values. IP addresses are listed in their dotted- + decimal notation [RFC1123]. Length and checksum values are present + as decimal integers. + + To calculate the length and checksum fields of the IP element, a + canonicalized form of the element MUST be used. The canonical form + SHALL have no whitespace (including newline characters) between + elements and only one space character between attributes. There + SHALL NOT be a space following the last attribute in an element. + + An iterative method SHOULD be used to calculate checksums, as the + length field will vary based on the size of the checksum. + + The payload element bears special attention. Due to the character + set restrictions of XML, the payload of IP datagrams (which MAY + contain arbitrary data) MUST be encoded for transport. This RFC + REQUIRES the contents of the payload to be encoded in the base-64 + encoding of RFC 2045 [RFC2045], but removes the requirement that the + encoded output MUST be wrapped on 76-character lines. + + + + + + + + + + + + + + + + + + + + + + + + +Kennedy Informational [Page 3] + +RFC 3252 Binary Lexical Octet Ad-hoc Transport 1 April 2002 + + +2.2. Example Datagram + + The following is an example IPoXML datagram with an empty payload: + + <?xml version="1.0" encoding="UTF-8"?> + <!DOCTYPE ip PUBLIC "-//IETF//DTD BLOAT 1.0 IP//EN" "bloat.dtd"> + <ip> + <header length="474"> + <version value="4"/> + <tos precedence="Routine" delay="Normal" throughput="Normal" + relibility="Normal" reserved="0"/> + <total.length value="461"/> + <id value="1"/> + <flags reserved="0" df="dont" mf="last"/> + <offset value="0"/> + <ttl value="255"/> + <protocol value="6"/> + <checksum value="8707"/> + <source address="10.0.0.22"/> + <destination address="10.0.0.1"/> + <options> + <end copied="0" class="0" number="0"/> + </options> + <padding pad="0"/> + </header> + <payload> + </payload> + </ip> + +3. TCPoXML + + This protocol MUST be implemented to be compliant with this RFC. The + DTD for this document type can be found in section 7.2. + +3.1. TCP Description + + A number of items have changed from the original TCP specification. + Bit-masks, where present have been converted into human-readable + values. Length and checksum and port values are present as decimal + integers. + + To calculate the length and checksum fields of the TCP element, a + canonicalized form of the element MUST be used as in section 2.1. + + An iterative method SHOULD be used to calculate checksums as in + section 2.1. + + The payload element MUST be encoded as in section 2.1. + + + +Kennedy Informational [Page 4] + +RFC 3252 Binary Lexical Octet Ad-hoc Transport 1 April 2002 + + + The TCP offset element was expanded to a maximum of 255 from 16 to + allow for the increased size of the header in XML. + + TCPoXML datagrams encapsulated by IPoXML MAY omit the <?xml?> header + as well as the <!DOCTYPE> declaration. + +3.2. Example Datagram + + The following is an example TCPoXML datagram with an empty payload: + + <?xml version="1.0" encoding="UTF-8"?> + <!DOCTYPE tcp PUBLIC "-//IETF//DTD BLOAT 1.0 TCP//EN" "bloat.dtd"> + <tcp> + <tcp.header> + <src port="31415"/> + <dest port="42424"/> + <sequence number="322622954"/> + <acknowledgement number="689715995"/> + <offset number=""/> + <reserved value="0"/> + <control syn="1" ack="1"/> + <window size="1"/> + <urgent pointer="0"/> + <checksum value="2988"/> + <tcp.options> + <tcp.end kind="0"/> + </tcp.options> + <padding pad="0"/> + </tcp.header> + <payload> + </payload> + </tcp> + +4. UDPoXML + + This protocol MUST be implemented to be compliant with this RFC. The + DTD for this document type can be found in section 7.3. + +4.1. UDP Description + + A number of items have changed from the original UDP specification. + Bit-masks, where present have been converted into human-readable + values. Length and checksum and port values are present as decimal + integers. + + + + + + + +Kennedy Informational [Page 5] + +RFC 3252 Binary Lexical Octet Ad-hoc Transport 1 April 2002 + + + To calculate the length and checksum fields of the UDP element, a + canonicalized form of the element MUST be used as in section 2.1. An + iterative method SHOULD be used to calculate checksums as in section + 2.1. + + The payload element MUST be encoded as in section 2.1. + + UDPoXML datagrams encapsulated by IPoXML MAY omit the <?xml?> header + as well as the <!DOCTYPE> declaration. + +4.2. Example Datagram + + The following is an example UDPoXML datagram with an empty payload: + + <?xml version="1.0" encoding="UTF-8"?> + <!DOCTYPE udp PUBLIC "-//IETF//DTD BLOAT 1.0 UDP//EN" "bloat.dtd"> + <udp> + <udp.header> + <src port="31415"/> + <dest port="42424"/> + <udp.length value="143"/> + <checksum value="2988"/> + </udp.header> + <payload> + </payload> + </udp> + +5. Network Transport + + This document provides for the transmission of BLOAT datagrams over + two common families of physical layer transport. Future RFCs will + address additional transports as routing vendors catch up to the + specification, and we begin to see BLOAT routed across the Internet + backbone. + +5.1. Ethernet + + BLOAT is encapsulated in Ethernet datagrams as in [RFC894] with the + exception that the type field of the Ethernet frame MUST contain the + value 0xBEEF. The first 5 octets of the Ethernet frame payload will + be 0x3c 3f 78 6d 6c ("<?xml".) + +5.2. IEEE 802 + + BLOAT is encapsulated in IEEE 802 Networks as in [RFC1042] except + that the protocol type code for IPoXML is 0xBEEF. + + + + + +Kennedy Informational [Page 6] + +RFC 3252 Binary Lexical Octet Ad-hoc Transport 1 April 2002 + + +6. Gatewaying over IP + + In order to facilitate the gradual introduction of BLOAT into the + public Internet, BLOAT MAY be encapsulated in IP as in [RFC2003] to + gateway between networks that run BLOAT natively on their LANs. + +7. DTDs + + The Transport DTDs (7.2. and 7.3.) build on the definitions in the + Network DTD (7.1.) + + The DTDs are referenced by their PubidLiteral and SystemLiteral (from + [XML]) although it is understood that most IPoXML implementations + will not need to pull down the DTD, as it will normally be embedded + in the implementation, and presents something of a catch-22 if you + need to load part of your network protocol over the network. + +7.1. IPoXML DTD + + <!-- + DTD for IP over XML. + Refer to this DTD as: + + <!DOCTYPE ip PUBLIC "-//IETF//DTD BLOAT 1.0 IP//EN" "bloat.dtd"> + --> + <!-- + DTD data types: + + Digits [0..9]+ + + Precedence "NetworkControl | InternetworkControl | + CRITIC | FlashOverride | Flash | Immediate | + Priority | Routine" + + IP4Addr "dotted-decimal" notation of [RFC1123] + + Class [0..3] + + Sec "Unclassified | Confidential | EFTO | MMMM | PROG | + Restricted | Secret | Top Secret | Reserved" + + Compartments [0..65535] + + Handling [0..65535] + + TCC [0..16777216] + + --> + + + +Kennedy Informational [Page 7] + +RFC 3252 Binary Lexical Octet Ad-hoc Transport 1 April 2002 + + + <!ENTITY % Digits "CDATA"> + <!ENTITY % Precedence "CDATA"> + <!ENTITY % IP4Addr "CDATA"> + <!ENTITY % Class "CDATA"> + <!ENTITY % Sec "CDATA"> + <!ENTITY % Compartments "CDATA"> + <!ENTITY % Handling "CDATA"> + <!ENTITY % TCC "CDATA"> + + <!ELEMENT ip (header, payload)> + + <!ELEMENT header (version, tos, total.length, id, flags, offset, ttl, + protocol, checksum, source, destination, options, + padding)> + <!-- length of header in 32-bit words --> + <!ATTLIST header + length %Digits; #REQUIRED> + + <!ELEMENT version EMPTY> + <!-- ip version. SHOULD be "4" --> + <!ATTLIST version + value %Digits; #REQUIRED> + + <!ELEMENT tos EMPTY> + <!ATTLIST tos + precedence %Precedence; #REQUIRED + delay (normal | low) #REQUIRED + throughput (normal | high) #REQUIRED + relibility (normal | high) #REQUIRED + reserved CDATA #FIXED "0"> + + <!ELEMENT total.length EMPTY> + <!-- + total length of datagram (header and payload) in octets, MUST be + less than 65,535 (and SHOULD be less than 1024 for IPoXML on local + ethernets). + --> + <!ATTLIST total.length + value %Digits; #REQUIRED> + + <!ELEMENT id EMPTY> + <!-- 0 <= id <= 65,535 --> + <!ATTLIST id + value %Digits; #REQUIRED> + + <!ELEMENT flags EMPTY> + <!-- df = don't fragment, mf = more fragments --> + <!ATTLIST flags + + + +Kennedy Informational [Page 8] + +RFC 3252 Binary Lexical Octet Ad-hoc Transport 1 April 2002 + + + reserved CDATA #FIXED "0" + df (may|dont) #REQUIRED + mf (last|more) #REQUIRED> + + <!ELEMENT offset EMPTY> + <!-- 0 <= offset <= 8192 measured in 8 octet (64-bit) chunks --> + <!ATTLIST offset + value %Digits; #REQUIRED> + + <!ELEMENT ttl EMPTY> + <!-- 0 <= ttl <= 255 --> + <!ATTLIST ttl + value %Digits; #REQUIRED> + + <!ELEMENT protocol EMPTY> + <!-- 0 <= protocol <= 255 (per IANA) --> + <!ATTLIST protocol + value %Digits; #REQUIRED> + + <!ELEMENT checksum EMPTY> + <!-- 0 <= checksum <= 65535 (over header only) --> + <!ATTLIST checksum + value %Digits; #REQUIRED> + + <!ELEMENT source EMPTY> + <!ATTLIST source + address %IP4Addr; #REQUIRED> + + <!ELEMENT destination EMPTY> + <!ATTLIST destination + address %IP4Addr; #REQUIRED> + + <!ELEMENT options ( end | noop | security | loose | strict | record + | stream | timestamp )*> + + <!ELEMENT end EMPTY> + <!ATTLIST end + copied (0|1) #REQUIRED + class CDATA #FIXED "0" + number CDATA #FIXED "0"> + + <!ELEMENT noop EMPTY> + <!ATTLIST noop + copied (0|1) #REQUIRED + class CDATA #FIXED "0" + number CDATA #FIXED "1"> + + <!ELEMENT security EMPTY> + + + +Kennedy Informational [Page 9] + +RFC 3252 Binary Lexical Octet Ad-hoc Transport 1 April 2002 + + + <!ATTLIST security + copied CDATA #FIXED "1" + class CDATA #FIXED "0" + number CDATA #FIXED "2" + length CDATA #FIXED "11" + security %Sec; #REQUIRED + compartments %Compartments; #REQUIRED + handling %Handling; #REQUIRED + tcc %TCC; #REQUIRED> + <!ELEMENT loose (hop)+> + <!ATTLIST loose + copied CDATA #FIXED "1" + class CDATA #FIXED "0" + number CDATA #FIXED "3" + length %Digits; #REQUIRED + pointer %Digits; #REQUIRED> + + <!ELEMENT hop EMPTY> + <!ATTLIST hop + address %IP4Addr; #REQUIRED> + + <!ELEMENT strict (hop)+> + <!ATTLIST strict + copied CDATA #FIXED "1" + class CDATA #FIXED "0" + number CDATA #FIXED "9" + length %Digits; #REQUIRED + pointer %Digits; #REQUIRED> + + <!ELEMENT record (hop)+> + <!ATTLIST record + copied CDATA #FIXED "0" + class CDATA #FIXED "0" + number CDATA #FIXED "7" + length %Digits; #REQUIRED + pointer %Digits; #REQUIRED> + + <!ELEMENT stream EMPTY> + <!-- 0 <= id <= 65,535 --> + <!ATTLIST stream + copied CDATA #FIXED "1" + class CDATA #FIXED "0" + number CDATA #FIXED "8" + length CDATA #FIXED "4" + id %Digits; #REQUIRED> + + <!ELEMENT timestamp (tstamp)+> + <!-- 0 <= oflw <=15 --> + + + +Kennedy Informational [Page 10] + +RFC 3252 Binary Lexical Octet Ad-hoc Transport 1 April 2002 + + + <!ATTLIST timestamp + copied CDATA #FIXED "0" + class CDATA #FIXED "2" + number CDATA #FIXED "4" + length %Digits; #REQUIRED + pointer %Digits; #REQUIRED + oflw %Digits; #REQUIRED + flag (0 | 1 | 3) #REQUIRED> + + <!ELEMENT tstamp EMPTY> + <!ATTLIST tstamp + time %Digits; #REQUIRED + address %IP4Addr; #IMPLIED> + <!-- + padding to bring header to 32-bit boundary. + pad MUST be "0"* + --> + <!ELEMENT padding EMPTY> + <!ATTLIST padding + pad CDATA #REQUIRED> + + <!-- payload MUST be encoded as base-64 [RFC2045], as modified + by section 2.1 of this RFC --> + <!ELEMENT payload (CDATA)> + +7.2. TCPoXML DTD + + <!-- + DTD for TCP over XML. + Refer to this DTD as: + + <!DOCTYPE tcp PUBLIC "-//IETF//DTD BLOAT 1.0 TCP//EN" "bloat.dtd"> + --> + + <!-- the pseudoheader is only included for checksum calculations --> + <!ELEMENT tcp (tcp.pseudoheader?, tcp.header, payload)> + + <!ELEMENT tcp.header (src, dest, sequence, acknowledgement, offset, + reserved, control, window, checksum, urgent, + tcp.options, padding)> + + <!ELEMENT src EMPTY> + <!-- 0 <= port <= 65,535 --> + <!ATTLIST src + port %Digits; #REQUIRED> + + <!ELEMENT dest EMPTY> + <!-- 0 <= port <= 65,535 --> + + + +Kennedy Informational [Page 11] + +RFC 3252 Binary Lexical Octet Ad-hoc Transport 1 April 2002 + + + <!ATTLIST dest + port %Digits; #REQUIRED> + + <!ELEMENT sequence EMPTY> + <!-- 0 <= number <= 4294967295 --> + <!ATTLIST sequence + number %Digits; #REQUIRED> + + <!ELEMENT acknowledgement EMPTY> + <!-- 0 <= number <= 4294967295 --> + <!ATTLIST acknowledgement + number %Digits; #REQUIRED> + + <!ELEMENT offset EMPTY> + <!-- 0 <= number <= 255 --> + <!ATTLIST offset + number %Digits; #REQUIRED> + + <!ELEMENT reserved EMPTY> + <!ATTLIST reserved + value CDATA #FIXED "0"> + + <!ELEMENT control EMPTY> + <!ATTLIST control + urg (0|1) #IMPLIED + ack (0|1) #IMPLIED + psh (0|1) #IMPLIED + rst (0|1) #IMPLIED + syn (0|1) #IMPLIED + fin (0|1) #IMPLIED> + + <!ELEMENT window EMPTY> + <!-- 0 <= size <= 65,535 --> + <!ATTLIST window + size %Digits; #REQUIRED> + + <!-- + checksum as in ip, but with + the following pseudo-header added into the tcp element: + --> + <!ELEMENT tcp.pseudoheader (source, destination, protocol, + tcp.length)> + + <!-- + tcp header + data length in octets. does not include the size of + + the pseudoheader. + --> + + + +Kennedy Informational [Page 12] + +RFC 3252 Binary Lexical Octet Ad-hoc Transport 1 April 2002 + + + <!ELEMENT tcp.length EMPTY> + <!ATTLIST tcp.length + value %Digits; #REQUIRED> + + <!ELEMENT urgent EMPTY> + <!-- 0 <= pointer <= 65,535 --> + <!ATTLIST urgent + pointer %Digits; #REQUIRED> + + <!ELEMENT tcp.options (tcp.end | tcp.noop | tcp.mss)+> + + <!ELEMENT tcp.end EMPTY> + <!ATTLIST tcp.end + kind CDATA #FIXED "0"> + + <!ELEMENT tcp.noop EMPTY> + <!ATTLIST tcp.noop + kind CDATA #FIXED "1"> + + <!ELEMENT tcp.mss EMPTY> + <!ATTLIST tcp.mss + kind CDATA #FIXED "2" + length CDATA #FIXED "4" + size %Digits; #REQUIRED> + +7.3. UDPoXML DTD + + <!-- + DTD for UDP over XML. + Refer to this DTD as: + + <!DOCTYPE udp PUBLIC "-//IETF//DTD BLOAT 1.0 UDP//EN" "bloat.dtd"> + --> + + <!ELEMENT udp (udp.pseudoheader?, udp.header, payload)> + + <!ELEMENT udp.header (src, dest, udp.length, checksum)> + + <!ELEMENT udp.pseudoheader (source, destination, protocol, + udp.length)> + + <!-- + udp header + data length in octets. does not include the size of + the pseudoheader. + --> + <!ELEMENT udp.length EMPTY> + <!ATTLIST udp.length + value %Digits; #REQUIRED> + + + +Kennedy Informational [Page 13] + +RFC 3252 Binary Lexical Octet Ad-hoc Transport 1 April 2002 + + +8. Security Considerations + + XML, as a subset of SGML, has the same security considerations as + specified in SGML Media Types [RFC1874]. Security considerations + that apply to IP, TCP and UDP also likely apply to BLOAT as it does + not attempt to correct for issues not related to message format. + +9. References + + [JABBER] Miller, J., "Jabber", draft-miller-jabber-00.txt, + February 2002. (Work in Progress) + + [RFC768] Postel, J., "User Datagram Protocol", STD 6, RFC 768, + August 1980. + + [RFC791] Postel, J., "Internet Protocol", STD 5, RFC 791, + September 1981. + + [RFC793] Postel, J., "Transmission Control Protocol", STD 7, RFC + 793, September 1981. + + [RFC894] Hornig, C., "Standard for the Transmission of IP + Datagrams over Ethernet Networks.", RFC 894, April 1984. + + [RFC1042] Postel, J. and J. Reynolds, "Standard for the + Transmission of IP Datagrams Over IEEE 802 Networks", STD + 43, RFC 1042, February 1988. + + [RFC1123] Braden, R., "Requirements for Internet Hosts - + Application and Support", RFC 1123, October 1989. + + [RFC1874] Levinson, E., "SGML Media Types", RFC 1874, December + 1995. + + [RFC2003] Perkins, C., "IP Encapsulation within IP", RFC 2003, + October 1996. + + [RFC2045] Freed, N. and N. Borenstein, "Multipurpose Internet Mail + Extensions (MIME) Part One: Format of Internet Message + Bodies", RFC 2045, November 1996. + + [RFC2119] Bradner, S., "Key words for use in RFCs to Indicate + Requirement Levels", BCP 14, RFC 2119, March 1997. + + [RFC2279] Yergeau, F., "UTF-8, a transformation format of ISO + 10646", RFC 2279, January 1998. + + + + + +Kennedy Informational [Page 14] + +RFC 3252 Binary Lexical Octet Ad-hoc Transport 1 April 2002 + + + [RFC2460] Deering, S. and R. Hinden, "Internet Protocol, Version 6 + (IPv6) Specification", RFC 2460, December 1998. + + [RFC3080] Rose, M., "The Blocks Extensible Exchange Protocol Core", + RFC 3080, March 2001. + + [SOAP] Box, D., Ehnebuske, D., Kakivaya, G., Layman, A., + Mendelsohn, N., Nielsen, H. F., Thatte, S. Winer, D., + "Simple Object Access Protocol (SOAP) 1.1" World Wide Web + Consortium Note, May 2000 http://www.w3.org/TR/SOAP/ + + [XML] Bray, T., Paoli, J., Sperberg-McQueen, C. M., "Extensible + Markup Language (XML)" World Wide Web Consortium + Recommendation REC- xml-19980210. + http://www.w3.org/TR/1998/REC-xml-19980210 + +10. Author's Address + + Hugh Kennedy + Mimezine + 1060 West Addison + Chicago, IL 60613 + USA + + EMail: kennedyh@engin.umich.edu + + + + + + + + + + + + + + + + + + + + + + + + + + +Kennedy Informational [Page 15] + +RFC 3252 Binary Lexical Octet Ad-hoc Transport 1 April 2002 + + +11. Full Copyright Statement + + Copyright (C) The Internet Society (2002). All Rights Reserved. + + This document and translations of it may be copied and furnished to + others, and derivative works that comment on or otherwise explain it + or assist in its implementation may be prepared, copied, published + and distributed, in whole or in part, without restriction of any + kind, provided that the above copyright notice and this paragraph are + included on all such copies and derivative works. However, this + document itself may not be modified in any way, such as by removing + the copyright notice or references to the Internet Society or other + Internet organizations, except as needed for the purpose of + developing Internet standards in which case the procedures for + copyrights defined in the Internet Standards process must be + followed, or as required to translate it into languages other than + English. + + The limited permissions granted above are perpetual and will not be + revoked by the Internet Society or its successors or assigns. + + This document and the information contained herein is provided on an + "AS IS" basis and THE INTERNET SOCIETY AND THE INTERNET ENGINEERING + TASK FORCE DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING + BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE INFORMATION + HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED WARRANTIES OF + MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. + +Acknowledgement + + Funding for the RFC Editor function is currently provided by the + Internet Society. + + + + + + + + + + + + + + + + + + + +Kennedy Informational [Page 16] + + + + + + + +Network Working Group H. Kennedy +Request for Comments: 3252 Mimezine +Category: Informational 1 April 2002 + + + Binary Lexical Octet Ad-hoc Transport + +Status of this Memo + + This memo provides information for the Internet community. It does + not specify an Internet standard of any kind. Distribution of this + memo is unlimited. + +Copyright Notice + + Copyright (C) The Internet Society (2002). All Rights Reserved. + +Abstract + + This document defines a reformulation of IP and two transport layer + protocols (TCP and UDP) as XML applications. + +1. Introduction + +1.1. Overview + + This document describes the Binary Lexical Octet Ad-hoc Transport + (BLOAT): a reformulation of a widely-deployed network-layer protocol + (IP [RFC791]), and two associated transport layer protocols (TCP + [RFC793] and UDP [RFC768]) as XML [XML] applications. It also + describes methods for transporting BLOAT over Ethernet and IEEE 802 + networks as well as encapsulating BLOAT in IP for gatewaying BLOAT + across the public Internet. + +1.2. Motivation + + The wild popularity of XML as a basis for application-level protocols + such as the Blocks Extensible Exchange Protocol [RFC3080], the Simple + Object Access Protocol [SOAP], and Jabber [JABBER] prompted + investigation into the possibility of extending the use of XML in the + protocol stack. Using XML at both the transport and network layer in + addition to the application layer would provide for an amazing amount + of power and flexibility while removing dependencies on proprietary + and hard-to-understand binary protocols. This protocol unification + would also allow applications to use a single XML parser for all + aspects of their operation, eliminating developer time spent figuring + out the intricacies of each new protocol, and moving the hard work of + + + + +Kennedy Informational [Page 1] + +RFC 3252 Binary Lexical Octet Ad-hoc Transport 1 April 2002 + + + parsing to the XML toolset. The use of XML also mitigates concerns + over "network vs. host" byte ordering which is at the root of many + network application bugs. + +1.3. Relation to Existing Protocols + + The reformulations specified in this RFC follow as closely as + possible the spirit of the RFCs on which they are based, and so MAY + contain elements or attributes that would not be needed in a pure + reworking (e.g. length attributes, which are implicit in XML.) + + The layering of network and transport protocols are maintained in + this RFC despite the optimizations that could be made if the line + were somewhat blurred (i.e. merging TCP and IP into a single, larger + element in the DTD) in order to foster future use of this protocol as + a basis for reformulating other protocols (such as ICMP.) + + Other than the encoding, the behavioral aspects of each of the + existing protocols remain unchanged. Routing, address spaces, TCP + congestion control, etc. behave as specified in the extant standards. + Adapting to new standards and experimental algorithm heuristics for + improving performance will become much easier once the move to BLOAT + has been completed. + +1.4. Requirement Levels + + The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", + "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this + document are to be interpreted as described in BCP 14, RFC 2119 + [RFC2119]. + +2. IPoXML + + This protocol MUST be implemented to be compliant with this RFC. + IPoXML is the root protocol REQUIRED for effective use of TCPoXML + (section 3.) and higher-level application protocols. + + The DTD for this document type can be found in section 7.1. + + The routing of IPoXML can be easily implemented on hosts with an XML + parser, as the regular structure lends itself handily to parsing and + validation of the document/datagram and then processing the + destination address, TTL, and checksum before sending it on to its + next-hop. + + The reformulation of IPv4 was chosen over IPv6 [RFC2460] due to the + wider deployment of IPv4 and the fact that implementing IPv6 as XML + would have exceeded the 1500 byte Ethernet MTU. + + + +Kennedy Informational [Page 2] + +RFC 3252 Binary Lexical Octet Ad-hoc Transport 1 April 2002 + + + All BLOAT implementations MUST use - and specify - the UTF-8 encoding + of RFC 2279 [RFC2279]. All BLOAT document/datagrams MUST be well- + formed and include the XMLDecl. + +2.1. IP Description + + A number of items have changed (for the better) from the original IP + specification. Bit-masks, where present have been converted into + human-readable values. IP addresses are listed in their dotted- + decimal notation [RFC1123]. Length and checksum values are present + as decimal integers. + + To calculate the length and checksum fields of the IP element, a + canonicalized form of the element MUST be used. The canonical form + SHALL have no whitespace (including newline characters) between + elements and only one space character between attributes. There + SHALL NOT be a space following the last attribute in an element. + + An iterative method SHOULD be used to calculate checksums, as the + length field will vary based on the size of the checksum. + + The payload element bears special attention. Due to the character + set restrictions of XML, the payload of IP datagrams (which MAY + contain arbitrary data) MUST be encoded for transport. This RFC + REQUIRES the contents of the payload to be encoded in the base-64 + encoding of RFC 2045 [RFC2045], but removes the requirement that the + encoded output MUST be wrapped on 76-character lines. + + + + + + + + + + + + + + + + + + + + + + + + +Kennedy Informational [Page 3] + +RFC 3252 Binary Lexical Octet Ad-hoc Transport 1 April 2002 + + +2.2. Example Datagram + + The following is an example IPoXML datagram with an empty payload: + + <?xml version="1.0" encoding="UTF-8"?> + <!DOCTYPE ip PUBLIC "-//IETF//DTD BLOAT 1.0 IP//EN" "bloat.dtd"> + <ip> + <header length="474"> + <version value="4"/> + <tos precedence="Routine" delay="Normal" throughput="Normal" + relibility="Normal" reserved="0"/> + <total.length value="461"/> + <id value="1"/> + <flags reserved="0" df="dont" mf="last"/> + <offset value="0"/> + <ttl value="255"/> + <protocol value="6"/> + <checksum value="8707"/> + <source address="10.0.0.22"/> + <destination address="10.0.0.1"/> + <options> + <end copied="0" class="0" number="0"/> + </options> + <padding pad="0"/> + </header> + <payload> + </payload> + </ip> + +3. TCPoXML + + This protocol MUST be implemented to be compliant with this RFC. The + DTD for this document type can be found in section 7.2. + +3.1. TCP Description + + A number of items have changed from the original TCP specification. + Bit-masks, where present have been converted into human-readable + values. Length and checksum and port values are present as decimal + integers. + + To calculate the length and checksum fields of the TCP element, a + canonicalized form of the element MUST be used as in section 2.1. + + An iterative method SHOULD be used to calculate checksums as in + section 2.1. + + The payload element MUST be encoded as in section 2.1. + + + +Kennedy Informational [Page 4] + +RFC 3252 Binary Lexical Octet Ad-hoc Transport 1 April 2002 + + + The TCP offset element was expanded to a maximum of 255 from 16 to + allow for the increased size of the header in XML. + + TCPoXML datagrams encapsulated by IPoXML MAY omit the <?xml?> header + as well as the <!DOCTYPE> declaration. + +3.2. Example Datagram + + The following is an example TCPoXML datagram with an empty payload: + + <?xml version="1.0" encoding="UTF-8"?> + <!DOCTYPE tcp PUBLIC "-//IETF//DTD BLOAT 1.0 TCP//EN" "bloat.dtd"> + <tcp> + <tcp.header> + <src port="31415"/> + <dest port="42424"/> + <sequence number="322622954"/> + <acknowledgement number="689715995"/> + <offset number=""/> + <reserved value="0"/> + <control syn="1" ack="1"/> + <window size="1"/> + <urgent pointer="0"/> + <checksum value="2988"/> + <tcp.options> + <tcp.end kind="0"/> + </tcp.options> + <padding pad="0"/> + </tcp.header> + <payload> + </payload> + </tcp> + +4. UDPoXML + + This protocol MUST be implemented to be compliant with this RFC. The + DTD for this document type can be found in section 7.3. + +4.1. UDP Description + + A number of items have changed from the original UDP specification. + Bit-masks, where present have been converted into human-readable + values. Length and checksum and port values are present as decimal + integers. + + + + + + + +Kennedy Informational [Page 5] + +RFC 3252 Binary Lexical Octet Ad-hoc Transport 1 April 2002 + + + To calculate the length and checksum fields of the UDP element, a + canonicalized form of the element MUST be used as in section 2.1. An + iterative method SHOULD be used to calculate checksums as in section + 2.1. + + The payload element MUST be encoded as in section 2.1. + + UDPoXML datagrams encapsulated by IPoXML MAY omit the <?xml?> header + as well as the <!DOCTYPE> declaration. + +4.2. Example Datagram + + The following is an example UDPoXML datagram with an empty payload: + + <?xml version="1.0" encoding="UTF-8"?> + <!DOCTYPE udp PUBLIC "-//IETF//DTD BLOAT 1.0 UDP//EN" "bloat.dtd"> + <udp> + <udp.header> + <src port="31415"/> + <dest port="42424"/> + <udp.length value="143"/> + <checksum value="2988"/> + </udp.header> + <payload> + </payload> + </udp> + +5. Network Transport + + This document provides for the transmission of BLOAT datagrams over + two common families of physical layer transport. Future RFCs will + address additional transports as routing vendors catch up to the + specification, and we begin to see BLOAT routed across the Internet + backbone. + +5.1. Ethernet + + BLOAT is encapsulated in Ethernet datagrams as in [RFC894] with the + exception that the type field of the Ethernet frame MUST contain the + value 0xBEEF. The first 5 octets of the Ethernet frame payload will + be 0x3c 3f 78 6d 6c ("<?xml".) + +5.2. IEEE 802 + + BLOAT is encapsulated in IEEE 802 Networks as in [RFC1042] except + that the protocol type code for IPoXML is 0xBEEF. + + + + + +Kennedy Informational [Page 6] + +RFC 3252 Binary Lexical Octet Ad-hoc Transport 1 April 2002 + + +6. Gatewaying over IP + + In order to facilitate the gradual introduction of BLOAT into the + public Internet, BLOAT MAY be encapsulated in IP as in [RFC2003] to + gateway between networks that run BLOAT natively on their LANs. + +7. DTDs + + The Transport DTDs (7.2. and 7.3.) build on the definitions in the + Network DTD (7.1.) + + The DTDs are referenced by their PubidLiteral and SystemLiteral (from + [XML]) although it is understood that most IPoXML implementations + will not need to pull down the DTD, as it will normally be embedded + in the implementation, and presents something of a catch-22 if you + need to load part of your network protocol over the network. + +7.1. IPoXML DTD + + <!-- + DTD for IP over XML. + Refer to this DTD as: + + <!DOCTYPE ip PUBLIC "-//IETF//DTD BLOAT 1.0 IP//EN" "bloat.dtd"> + --> + <!-- + DTD data types: + + Digits [0..9]+ + + Precedence "NetworkControl | InternetworkControl | + CRITIC | FlashOverride | Flash | Immediate | + Priority | Routine" + + IP4Addr "dotted-decimal" notation of [RFC1123] + + Class [0..3] + + Sec "Unclassified | Confidential | EFTO | MMMM | PROG | + Restricted | Secret | Top Secret | Reserved" + + Compartments [0..65535] + + Handling [0..65535] + + TCC [0..16777216] + + --> + + + +Kennedy Informational [Page 7] + +RFC 3252 Binary Lexical Octet Ad-hoc Transport 1 April 2002 + + + <!ENTITY % Digits "CDATA"> + <!ENTITY % Precedence "CDATA"> + <!ENTITY % IP4Addr "CDATA"> + <!ENTITY % Class "CDATA"> + <!ENTITY % Sec "CDATA"> + <!ENTITY % Compartments "CDATA"> + <!ENTITY % Handling "CDATA"> + <!ENTITY % TCC "CDATA"> + + <!ELEMENT ip (header, payload)> + + <!ELEMENT header (version, tos, total.length, id, flags, offset, ttl, + protocol, checksum, source, destination, options, + padding)> + <!-- length of header in 32-bit words --> + <!ATTLIST header + length %Digits; #REQUIRED> + + <!ELEMENT version EMPTY> + <!-- ip version. SHOULD be "4" --> + <!ATTLIST version + value %Digits; #REQUIRED> + + <!ELEMENT tos EMPTY> + <!ATTLIST tos + precedence %Precedence; #REQUIRED + delay (normal | low) #REQUIRED + throughput (normal | high) #REQUIRED + relibility (normal | high) #REQUIRED + reserved CDATA #FIXED "0"> + + <!ELEMENT total.length EMPTY> + <!-- + total length of datagram (header and payload) in octets, MUST be + less than 65,535 (and SHOULD be less than 1024 for IPoXML on local + ethernets). + --> + <!ATTLIST total.length + value %Digits; #REQUIRED> + + <!ELEMENT id EMPTY> + <!-- 0 <= id <= 65,535 --> + <!ATTLIST id + value %Digits; #REQUIRED> + + <!ELEMENT flags EMPTY> + <!-- df = don't fragment, mf = more fragments --> + <!ATTLIST flags + + + +Kennedy Informational [Page 8] + +RFC 3252 Binary Lexical Octet Ad-hoc Transport 1 April 2002 + + + reserved CDATA #FIXED "0" + df (may|dont) #REQUIRED + mf (last|more) #REQUIRED> + + <!ELEMENT offset EMPTY> + <!-- 0 <= offset <= 8192 measured in 8 octet (64-bit) chunks --> + <!ATTLIST offset + value %Digits; #REQUIRED> + + <!ELEMENT ttl EMPTY> + <!-- 0 <= ttl <= 255 --> + <!ATTLIST ttl + value %Digits; #REQUIRED> + + <!ELEMENT protocol EMPTY> + <!-- 0 <= protocol <= 255 (per IANA) --> + <!ATTLIST protocol + value %Digits; #REQUIRED> + + <!ELEMENT checksum EMPTY> + <!-- 0 <= checksum <= 65535 (over header only) --> + <!ATTLIST checksum + value %Digits; #REQUIRED> + + <!ELEMENT source EMPTY> + <!ATTLIST source + address %IP4Addr; #REQUIRED> + + <!ELEMENT destination EMPTY> + <!ATTLIST destination + address %IP4Addr; #REQUIRED> + + <!ELEMENT options ( end | noop | security | loose | strict | record + | stream | timestamp )*> + + <!ELEMENT end EMPTY> + <!ATTLIST end + copied (0|1) #REQUIRED + class CDATA #FIXED "0" + number CDATA #FIXED "0"> + + <!ELEMENT noop EMPTY> + <!ATTLIST noop + copied (0|1) #REQUIRED + class CDATA #FIXED "0" + number CDATA #FIXED "1"> + + <!ELEMENT security EMPTY> + + + +Kennedy Informational [Page 9] + +RFC 3252 Binary Lexical Octet Ad-hoc Transport 1 April 2002 + + + <!ATTLIST security + copied CDATA #FIXED "1" + class CDATA #FIXED "0" + number CDATA #FIXED "2" + length CDATA #FIXED "11" + security %Sec; #REQUIRED + compartments %Compartments; #REQUIRED + handling %Handling; #REQUIRED + tcc %TCC; #REQUIRED> + <!ELEMENT loose (hop)+> + <!ATTLIST loose + copied CDATA #FIXED "1" + class CDATA #FIXED "0" + number CDATA #FIXED "3" + length %Digits; #REQUIRED + pointer %Digits; #REQUIRED> + + <!ELEMENT hop EMPTY> + <!ATTLIST hop + address %IP4Addr; #REQUIRED> + + <!ELEMENT strict (hop)+> + <!ATTLIST strict + copied CDATA #FIXED "1" + class CDATA #FIXED "0" + number CDATA #FIXED "9" + length %Digits; #REQUIRED + pointer %Digits; #REQUIRED> + + <!ELEMENT record (hop)+> + <!ATTLIST record + copied CDATA #FIXED "0" + class CDATA #FIXED "0" + number CDATA #FIXED "7" + length %Digits; #REQUIRED + pointer %Digits; #REQUIRED> + + <!ELEMENT stream EMPTY> + <!-- 0 <= id <= 65,535 --> + <!ATTLIST stream + copied CDATA #FIXED "1" + class CDATA #FIXED "0" + number CDATA #FIXED "8" + length CDATA #FIXED "4" + id %Digits; #REQUIRED> + + <!ELEMENT timestamp (tstamp)+> + <!-- 0 <= oflw <=15 --> + + + +Kennedy Informational [Page 10] + +RFC 3252 Binary Lexical Octet Ad-hoc Transport 1 April 2002 + + + <!ATTLIST timestamp + copied CDATA #FIXED "0" + class CDATA #FIXED "2" + number CDATA #FIXED "4" + length %Digits; #REQUIRED + pointer %Digits; #REQUIRED + oflw %Digits; #REQUIRED + flag (0 | 1 | 3) #REQUIRED> + + <!ELEMENT tstamp EMPTY> + <!ATTLIST tstamp + time %Digits; #REQUIRED + address %IP4Addr; #IMPLIED> + <!-- + padding to bring header to 32-bit boundary. + pad MUST be "0"* + --> + <!ELEMENT padding EMPTY> + <!ATTLIST padding + pad CDATA #REQUIRED> + + <!-- payload MUST be encoded as base-64 [RFC2045], as modified + by section 2.1 of this RFC --> + <!ELEMENT payload (CDATA)> + +7.2. TCPoXML DTD + + <!-- + DTD for TCP over XML. + Refer to this DTD as: + + <!DOCTYPE tcp PUBLIC "-//IETF//DTD BLOAT 1.0 TCP//EN" "bloat.dtd"> + --> + + <!-- the pseudoheader is only included for checksum calculations --> + <!ELEMENT tcp (tcp.pseudoheader?, tcp.header, payload)> + + <!ELEMENT tcp.header (src, dest, sequence, acknowledgement, offset, + reserved, control, window, checksum, urgent, + tcp.options, padding)> + + <!ELEMENT src EMPTY> + <!-- 0 <= port <= 65,535 --> + <!ATTLIST src + port %Digits; #REQUIRED> + + <!ELEMENT dest EMPTY> + <!-- 0 <= port <= 65,535 --> + + + +Kennedy Informational [Page 11] + +RFC 3252 Binary Lexical Octet Ad-hoc Transport 1 April 2002 + + + <!ATTLIST dest + port %Digits; #REQUIRED> + + <!ELEMENT sequence EMPTY> + <!-- 0 <= number <= 4294967295 --> + <!ATTLIST sequence + number %Digits; #REQUIRED> + + <!ELEMENT acknowledgement EMPTY> + <!-- 0 <= number <= 4294967295 --> + <!ATTLIST acknowledgement + number %Digits; #REQUIRED> + + <!ELEMENT offset EMPTY> + <!-- 0 <= number <= 255 --> + <!ATTLIST offset + number %Digits; #REQUIRED> + + <!ELEMENT reserved EMPTY> + <!ATTLIST reserved + value CDATA #FIXED "0"> + + <!ELEMENT control EMPTY> + <!ATTLIST control + urg (0|1) #IMPLIED + ack (0|1) #IMPLIED + psh (0|1) #IMPLIED + rst (0|1) #IMPLIED + syn (0|1) #IMPLIED + fin (0|1) #IMPLIED> + + <!ELEMENT window EMPTY> + <!-- 0 <= size <= 65,535 --> + <!ATTLIST window + size %Digits; #REQUIRED> + + <!-- + checksum as in ip, but with + the following pseudo-header added into the tcp element: + --> + <!ELEMENT tcp.pseudoheader (source, destination, protocol, + tcp.length)> + + <!-- + tcp header + data length in octets. does not include the size of + + the pseudoheader. + --> + + + +Kennedy Informational [Page 12] + +RFC 3252 Binary Lexical Octet Ad-hoc Transport 1 April 2002 + + + <!ELEMENT tcp.length EMPTY> + <!ATTLIST tcp.length + value %Digits; #REQUIRED> + + <!ELEMENT urgent EMPTY> + <!-- 0 <= pointer <= 65,535 --> + <!ATTLIST urgent + pointer %Digits; #REQUIRED> + + <!ELEMENT tcp.options (tcp.end | tcp.noop | tcp.mss)+> + + <!ELEMENT tcp.end EMPTY> + <!ATTLIST tcp.end + kind CDATA #FIXED "0"> + + <!ELEMENT tcp.noop EMPTY> + <!ATTLIST tcp.noop + kind CDATA #FIXED "1"> + + <!ELEMENT tcp.mss EMPTY> + <!ATTLIST tcp.mss + kind CDATA #FIXED "2" + length CDATA #FIXED "4" + size %Digits; #REQUIRED> + +7.3. UDPoXML DTD + + <!-- + DTD for UDP over XML. + Refer to this DTD as: + + <!DOCTYPE udp PUBLIC "-//IETF//DTD BLOAT 1.0 UDP//EN" "bloat.dtd"> + --> + + <!ELEMENT udp (udp.pseudoheader?, udp.header, payload)> + + <!ELEMENT udp.header (src, dest, udp.length, checksum)> + + <!ELEMENT udp.pseudoheader (source, destination, protocol, + udp.length)> + + <!-- + udp header + data length in octets. does not include the size of + the pseudoheader. + --> + <!ELEMENT udp.length EMPTY> + <!ATTLIST udp.length + value %Digits; #REQUIRED> + + + +Kennedy Informational [Page 13] + +RFC 3252 Binary Lexical Octet Ad-hoc Transport 1 April 2002 + + +8. Security Considerations + + XML, as a subset of SGML, has the same security considerations as + specified in SGML Media Types [RFC1874]. Security considerations + that apply to IP, TCP and UDP also likely apply to BLOAT as it does + not attempt to correct for issues not related to message format. + +9. References + + [JABBER] Miller, J., "Jabber", draft-miller-jabber-00.txt, + February 2002. (Work in Progress) + + [RFC768] Postel, J., "User Datagram Protocol", STD 6, RFC 768, + August 1980. + + [RFC791] Postel, J., "Internet Protocol", STD 5, RFC 791, + September 1981. + + [RFC793] Postel, J., "Transmission Control Protocol", STD 7, RFC + 793, September 1981. + + [RFC894] Hornig, C., "Standard for the Transmission of IP + Datagrams over Ethernet Networks.", RFC 894, April 1984. + + [RFC1042] Postel, J. and J. Reynolds, "Standard for the + Transmission of IP Datagrams Over IEEE 802 Networks", STD + 43, RFC 1042, February 1988. + + [RFC1123] Braden, R., "Requirements for Internet Hosts - + Application and Support", RFC 1123, October 1989. + + [RFC1874] Levinson, E., "SGML Media Types", RFC 1874, December + 1995. + + [RFC2003] Perkins, C., "IP Encapsulation within IP", RFC 2003, + October 1996. + + [RFC2045] Freed, N. and N. Borenstein, "Multipurpose Internet Mail + Extensions (MIME) Part One: Format of Internet Message + Bodies", RFC 2045, November 1996. + + [RFC2119] Bradner, S., "Key words for use in RFCs to Indicate + Requirement Levels", BCP 14, RFC 2119, March 1997. + + [RFC2279] Yergeau, F., "UTF-8, a transformation format of ISO + 10646", RFC 2279, January 1998. + + + + + +Kennedy Informational [Page 14] + +RFC 3252 Binary Lexical Octet Ad-hoc Transport 1 April 2002 + + + [RFC2460] Deering, S. and R. Hinden, "Internet Protocol, Version 6 + (IPv6) Specification", RFC 2460, December 1998. + + [RFC3080] Rose, M., "The Blocks Extensible Exchange Protocol Core", + RFC 3080, March 2001. + + [SOAP] Box, D., Ehnebuske, D., Kakivaya, G., Layman, A., + Mendelsohn, N., Nielsen, H. F., Thatte, S. Winer, D., + "Simple Object Access Protocol (SOAP) 1.1" World Wide Web + Consortium Note, May 2000 http://www.w3.org/TR/SOAP/ + + [XML] Bray, T., Paoli, J., Sperberg-McQueen, C. M., "Extensible + Markup Language (XML)" World Wide Web Consortium + Recommendation REC- xml-19980210. + http://www.w3.org/TR/1998/REC-xml-19980210 + +10. Author's Address + + Hugh Kennedy + Mimezine + 1060 West Addison + Chicago, IL 60613 + USA + + EMail: kennedyh@engin.umich.edu + + + + + + + + + + + + + + + + + + + + + + + + + + +Kennedy Informational [Page 15] + +RFC 3252 Binary Lexical Octet Ad-hoc Transport 1 April 2002 + + +11. Full Copyright Statement + + Copyright (C) The Internet Society (2002). All Rights Reserved. + + This document and translations of it may be copied and furnished to + others, and derivative works that comment on or otherwise explain it + or assist in its implementation may be prepared, copied, published + and distributed, in whole or in part, without restriction of any + kind, provided that the above copyright notice and this paragraph are + included on all such copies and derivative works. However, this + document itself may not be modified in any way, such as by removing + the copyright notice or references to the Internet Society or other + Internet organizations, except as needed for the purpose of + developing Internet standards in which case the procedures for + copyrights defined in the Internet Standards process must be + followed, or as required to translate it into languages other than + English. + + The limited permissions granted above are perpetual and will not be + revoked by the Internet Society or its successors or assigns. + + This document and the information contained herein is provided on an + "AS IS" basis and THE INTERNET SOCIETY AND THE INTERNET ENGINEERING + TASK FORCE DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING + BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE INFORMATION + HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED WARRANTIES OF + MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. + +Acknowledgement + + Funding for the RFC Editor function is currently provided by the + Internet Society. + + + + + + + + + + + + + + + + + + + +Kennedy Informational [Page 16] + + + + + + + +Network Working Group H. Kennedy +Request for Comments: 3252 Mimezine +Category: Informational 1 April 2002 + + + Binary Lexical Octet Ad-hoc Transport + +Status of this Memo + + This memo provides information for the Internet community. It does + not specify an Internet standard of any kind. Distribution of this + memo is unlimited. + +Copyright Notice + + Copyright (C) The Internet Society (2002). All Rights Reserved. + +Abstract + + This document defines a reformulation of IP and two transport layer + protocols (TCP and UDP) as XML applications. + +1. Introduction + +1.1. Overview + + This document describes the Binary Lexical Octet Ad-hoc Transport + (BLOAT): a reformulation of a widely-deployed network-layer protocol + (IP [RFC791]), and two associated transport layer protocols (TCP + [RFC793] and UDP [RFC768]) as XML [XML] applications. It also + describes methods for transporting BLOAT over Ethernet and IEEE 802 + networks as well as encapsulating BLOAT in IP for gatewaying BLOAT + across the public Internet. + +1.2. Motivation + + The wild popularity of XML as a basis for application-level protocols + such as the Blocks Extensible Exchange Protocol [RFC3080], the Simple + Object Access Protocol [SOAP], and Jabber [JABBER] prompted + investigation into the possibility of extending the use of XML in the + protocol stack. Using XML at both the transport and network layer in + addition to the application layer would provide for an amazing amount + of power and flexibility while removing dependencies on proprietary + and hard-to-understand binary protocols. This protocol unification + would also allow applications to use a single XML parser for all + aspects of their operation, eliminating developer time spent figuring + out the intricacies of each new protocol, and moving the hard work of + + + + +Kennedy Informational [Page 1] + +RFC 3252 Binary Lexical Octet Ad-hoc Transport 1 April 2002 + + + parsing to the XML toolset. The use of XML also mitigates concerns + over "network vs. host" byte ordering which is at the root of many + network application bugs. + +1.3. Relation to Existing Protocols + + The reformulations specified in this RFC follow as closely as + possible the spirit of the RFCs on which they are based, and so MAY + contain elements or attributes that would not be needed in a pure + reworking (e.g. length attributes, which are implicit in XML.) + + The layering of network and transport protocols are maintained in + this RFC despite the optimizations that could be made if the line + were somewhat blurred (i.e. merging TCP and IP into a single, larger + element in the DTD) in order to foster future use of this protocol as + a basis for reformulating other protocols (such as ICMP.) + + Other than the encoding, the behavioral aspects of each of the + existing protocols remain unchanged. Routing, address spaces, TCP + congestion control, etc. behave as specified in the extant standards. + Adapting to new standards and experimental algorithm heuristics for + improving performance will become much easier once the move to BLOAT + has been completed. + +1.4. Requirement Levels + + The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", + "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this + document are to be interpreted as described in BCP 14, RFC 2119 + [RFC2119]. + +2. IPoXML + + This protocol MUST be implemented to be compliant with this RFC. + IPoXML is the root protocol REQUIRED for effective use of TCPoXML + (section 3.) and higher-level application protocols. + + The DTD for this document type can be found in section 7.1. + + The routing of IPoXML can be easily implemented on hosts with an XML + parser, as the regular structure lends itself handily to parsing and + validation of the document/datagram and then processing the + destination address, TTL, and checksum before sending it on to its + next-hop. + + The reformulation of IPv4 was chosen over IPv6 [RFC2460] due to the + wider deployment of IPv4 and the fact that implementing IPv6 as XML + would have exceeded the 1500 byte Ethernet MTU. + + + +Kennedy Informational [Page 2] + +RFC 3252 Binary Lexical Octet Ad-hoc Transport 1 April 2002 + + + All BLOAT implementations MUST use - and specify - the UTF-8 encoding + of RFC 2279 [RFC2279]. All BLOAT document/datagrams MUST be well- + formed and include the XMLDecl. + +2.1. IP Description + + A number of items have changed (for the better) from the original IP + specification. Bit-masks, where present have been converted into + human-readable values. IP addresses are listed in their dotted- + decimal notation [RFC1123]. Length and checksum values are present + as decimal integers. + + To calculate the length and checksum fields of the IP element, a + canonicalized form of the element MUST be used. The canonical form + SHALL have no whitespace (including newline characters) between + elements and only one space character between attributes. There + SHALL NOT be a space following the last attribute in an element. + + An iterative method SHOULD be used to calculate checksums, as the + length field will vary based on the size of the checksum. + + The payload element bears special attention. Due to the character + set restrictions of XML, the payload of IP datagrams (which MAY + contain arbitrary data) MUST be encoded for transport. This RFC + REQUIRES the contents of the payload to be encoded in the base-64 + encoding of RFC 2045 [RFC2045], but removes the requirement that the + encoded output MUST be wrapped on 76-character lines. + + + + + + + + + + + + + + + + + + + + + + + + +Kennedy Informational [Page 3] + +RFC 3252 Binary Lexical Octet Ad-hoc Transport 1 April 2002 + + +2.2. Example Datagram + + The following is an example IPoXML datagram with an empty payload: + + <?xml version="1.0" encoding="UTF-8"?> + <!DOCTYPE ip PUBLIC "-//IETF//DTD BLOAT 1.0 IP//EN" "bloat.dtd"> + <ip> + <header length="474"> + <version value="4"/> + <tos precedence="Routine" delay="Normal" throughput="Normal" + relibility="Normal" reserved="0"/> + <total.length value="461"/> + <id value="1"/> + <flags reserved="0" df="dont" mf="last"/> + <offset value="0"/> + <ttl value="255"/> + <protocol value="6"/> + <checksum value="8707"/> + <source address="10.0.0.22"/> + <destination address="10.0.0.1"/> + <options> + <end copied="0" class="0" number="0"/> + </options> + <padding pad="0"/> + </header> + <payload> + </payload> + </ip> + +3. TCPoXML + + This protocol MUST be implemented to be compliant with this RFC. The + DTD for this document type can be found in section 7.2. + +3.1. TCP Description + + A number of items have changed from the original TCP specification. + Bit-masks, where present have been converted into human-readable + values. Length and checksum and port values are present as decimal + integers. + + To calculate the length and checksum fields of the TCP element, a + canonicalized form of the element MUST be used as in section 2.1. + + An iterative method SHOULD be used to calculate checksums as in + section 2.1. + + The payload element MUST be encoded as in section 2.1. + + + +Kennedy Informational [Page 4] + +RFC 3252 Binary Lexical Octet Ad-hoc Transport 1 April 2002 + + + The TCP offset element was expanded to a maximum of 255 from 16 to + allow for the increased size of the header in XML. + + TCPoXML datagrams encapsulated by IPoXML MAY omit the <?xml?> header + as well as the <!DOCTYPE> declaration. + +3.2. Example Datagram + + The following is an example TCPoXML datagram with an empty payload: + + <?xml version="1.0" encoding="UTF-8"?> + <!DOCTYPE tcp PUBLIC "-//IETF//DTD BLOAT 1.0 TCP//EN" "bloat.dtd"> + <tcp> + <tcp.header> + <src port="31415"/> + <dest port="42424"/> + <sequence number="322622954"/> + <acknowledgement number="689715995"/> + <offset number=""/> + <reserved value="0"/> + <control syn="1" ack="1"/> + <window size="1"/> + <urgent pointer="0"/> + <checksum value="2988"/> + <tcp.options> + <tcp.end kind="0"/> + </tcp.options> + <padding pad="0"/> + </tcp.header> + <payload> + </payload> + </tcp> + +4. UDPoXML + + This protocol MUST be implemented to be compliant with this RFC. The + DTD for this document type can be found in section 7.3. + +4.1. UDP Description + + A number of items have changed from the original UDP specification. + Bit-masks, where present have been converted into human-readable + values. Length and checksum and port values are present as decimal + integers. + + + + + + + +Kennedy Informational [Page 5] + +RFC 3252 Binary Lexical Octet Ad-hoc Transport 1 April 2002 + + + To calculate the length and checksum fields of the UDP element, a + canonicalized form of the element MUST be used as in section 2.1. An + iterative method SHOULD be used to calculate checksums as in section + 2.1. + + The payload element MUST be encoded as in section 2.1. + + UDPoXML datagrams encapsulated by IPoXML MAY omit the <?xml?> header + as well as the <!DOCTYPE> declaration. + +4.2. Example Datagram + + The following is an example UDPoXML datagram with an empty payload: + + <?xml version="1.0" encoding="UTF-8"?> + <!DOCTYPE udp PUBLIC "-//IETF//DTD BLOAT 1.0 UDP//EN" "bloat.dtd"> + <udp> + <udp.header> + <src port="31415"/> + <dest port="42424"/> + <udp.length value="143"/> + <checksum value="2988"/> + </udp.header> + <payload> + </payload> + </udp> + +5. Network Transport + + This document provides for the transmission of BLOAT datagrams over + two common families of physical layer transport. Future RFCs will + address additional transports as routing vendors catch up to the + specification, and we begin to see BLOAT routed across the Internet + backbone. + +5.1. Ethernet + + BLOAT is encapsulated in Ethernet datagrams as in [RFC894] with the + exception that the type field of the Ethernet frame MUST contain the + value 0xBEEF. The first 5 octets of the Ethernet frame payload will + be 0x3c 3f 78 6d 6c ("<?xml".) + +5.2. IEEE 802 + + BLOAT is encapsulated in IEEE 802 Networks as in [RFC1042] except + that the protocol type code for IPoXML is 0xBEEF. + + + + + +Kennedy Informational [Page 6] + +RFC 3252 Binary Lexical Octet Ad-hoc Transport 1 April 2002 + + +6. Gatewaying over IP + + In order to facilitate the gradual introduction of BLOAT into the + public Internet, BLOAT MAY be encapsulated in IP as in [RFC2003] to + gateway between networks that run BLOAT natively on their LANs. + +7. DTDs + + The Transport DTDs (7.2. and 7.3.) build on the definitions in the + Network DTD (7.1.) + + The DTDs are referenced by their PubidLiteral and SystemLiteral (from + [XML]) although it is understood that most IPoXML implementations + will not need to pull down the DTD, as it will normally be embedded + in the implementation, and presents something of a catch-22 if you + need to load part of your network protocol over the network. + +7.1. IPoXML DTD + + <!-- + DTD for IP over XML. + Refer to this DTD as: + + <!DOCTYPE ip PUBLIC "-//IETF//DTD BLOAT 1.0 IP//EN" "bloat.dtd"> + --> + <!-- + DTD data types: + + Digits [0..9]+ + + Precedence "NetworkControl | InternetworkControl | + CRITIC | FlashOverride | Flash | Immediate | + Priority | Routine" + + IP4Addr "dotted-decimal" notation of [RFC1123] + + Class [0..3] + + Sec "Unclassified | Confidential | EFTO | MMMM | PROG | + Restricted | Secret | Top Secret | Reserved" + + Compartments [0..65535] + + Handling [0..65535] + + TCC [0..16777216] + + --> + + + +Kennedy Informational [Page 7] + +RFC 3252 Binary Lexical Octet Ad-hoc Transport 1 April 2002 + + + <!ENTITY % Digits "CDATA"> + <!ENTITY % Precedence "CDATA"> + <!ENTITY % IP4Addr "CDATA"> + <!ENTITY % Class "CDATA"> + <!ENTITY % Sec "CDATA"> + <!ENTITY % Compartments "CDATA"> + <!ENTITY % Handling "CDATA"> + <!ENTITY % TCC "CDATA"> + + <!ELEMENT ip (header, payload)> + + <!ELEMENT header (version, tos, total.length, id, flags, offset, ttl, + protocol, checksum, source, destination, options, + padding)> + <!-- length of header in 32-bit words --> + <!ATTLIST header + length %Digits; #REQUIRED> + + <!ELEMENT version EMPTY> + <!-- ip version. SHOULD be "4" --> + <!ATTLIST version + value %Digits; #REQUIRED> + + <!ELEMENT tos EMPTY> + <!ATTLIST tos + precedence %Precedence; #REQUIRED + delay (normal | low) #REQUIRED + throughput (normal | high) #REQUIRED + relibility (normal | high) #REQUIRED + reserved CDATA #FIXED "0"> + + <!ELEMENT total.length EMPTY> + <!-- + total length of datagram (header and payload) in octets, MUST be + less than 65,535 (and SHOULD be less than 1024 for IPoXML on local + ethernets). + --> + <!ATTLIST total.length + value %Digits; #REQUIRED> + + <!ELEMENT id EMPTY> + <!-- 0 <= id <= 65,535 --> + <!ATTLIST id + value %Digits; #REQUIRED> + + <!ELEMENT flags EMPTY> + <!-- df = don't fragment, mf = more fragments --> + <!ATTLIST flags + + + +Kennedy Informational [Page 8] + +RFC 3252 Binary Lexical Octet Ad-hoc Transport 1 April 2002 + + + reserved CDATA #FIXED "0" + df (may|dont) #REQUIRED + mf (last|more) #REQUIRED> + + <!ELEMENT offset EMPTY> + <!-- 0 <= offset <= 8192 measured in 8 octet (64-bit) chunks --> + <!ATTLIST offset + value %Digits; #REQUIRED> + + <!ELEMENT ttl EMPTY> + <!-- 0 <= ttl <= 255 --> + <!ATTLIST ttl + value %Digits; #REQUIRED> + + <!ELEMENT protocol EMPTY> + <!-- 0 <= protocol <= 255 (per IANA) --> + <!ATTLIST protocol + value %Digits; #REQUIRED> + + <!ELEMENT checksum EMPTY> + <!-- 0 <= checksum <= 65535 (over header only) --> + <!ATTLIST checksum + value %Digits; #REQUIRED> + + <!ELEMENT source EMPTY> + <!ATTLIST source + address %IP4Addr; #REQUIRED> + + <!ELEMENT destination EMPTY> + <!ATTLIST destination + address %IP4Addr; #REQUIRED> + + <!ELEMENT options ( end | noop | security | loose | strict | record + | stream | timestamp )*> + + <!ELEMENT end EMPTY> + <!ATTLIST end + copied (0|1) #REQUIRED + class CDATA #FIXED "0" + number CDATA #FIXED "0"> + + <!ELEMENT noop EMPTY> + <!ATTLIST noop + copied (0|1) #REQUIRED + class CDATA #FIXED "0" + number CDATA #FIXED "1"> + + <!ELEMENT security EMPTY> + + + +Kennedy Informational [Page 9] + +RFC 3252 Binary Lexical Octet Ad-hoc Transport 1 April 2002 + + + <!ATTLIST security + copied CDATA #FIXED "1" + class CDATA #FIXED "0" + number CDATA #FIXED "2" + length CDATA #FIXED "11" + security %Sec; #REQUIRED + compartments %Compartments; #REQUIRED + handling %Handling; #REQUIRED + tcc %TCC; #REQUIRED> + <!ELEMENT loose (hop)+> + <!ATTLIST loose + copied CDATA #FIXED "1" + class CDATA #FIXED "0" + number CDATA #FIXED "3" + length %Digits; #REQUIRED + pointer %Digits; #REQUIRED> + + <!ELEMENT hop EMPTY> + <!ATTLIST hop + address %IP4Addr; #REQUIRED> + + <!ELEMENT strict (hop)+> + <!ATTLIST strict + copied CDATA #FIXED "1" + class CDATA #FIXED "0" + number CDATA #FIXED "9" + length %Digits; #REQUIRED + pointer %Digits; #REQUIRED> + + <!ELEMENT record (hop)+> + <!ATTLIST record + copied CDATA #FIXED "0" + class CDATA #FIXED "0" + number CDATA #FIXED "7" + length %Digits; #REQUIRED + pointer %Digits; #REQUIRED> + + <!ELEMENT stream EMPTY> + <!-- 0 <= id <= 65,535 --> + <!ATTLIST stream + copied CDATA #FIXED "1" + class CDATA #FIXED "0" + number CDATA #FIXED "8" + length CDATA #FIXED "4" + id %Digits; #REQUIRED> + + <!ELEMENT timestamp (tstamp)+> + <!-- 0 <= oflw <=15 --> + + + +Kennedy Informational [Page 10] + +RFC 3252 Binary Lexical Octet Ad-hoc Transport 1 April 2002 + + + <!ATTLIST timestamp + copied CDATA #FIXED "0" + class CDATA #FIXED "2" + number CDATA #FIXED "4" + length %Digits; #REQUIRED + pointer %Digits; #REQUIRED + oflw %Digits; #REQUIRED + flag (0 | 1 | 3) #REQUIRED> + + <!ELEMENT tstamp EMPTY> + <!ATTLIST tstamp + time %Digits; #REQUIRED + address %IP4Addr; #IMPLIED> + <!-- + padding to bring header to 32-bit boundary. + pad MUST be "0"* + --> + <!ELEMENT padding EMPTY> + <!ATTLIST padding + pad CDATA #REQUIRED> + + <!-- payload MUST be encoded as base-64 [RFC2045], as modified + by section 2.1 of this RFC --> + <!ELEMENT payload (CDATA)> + +7.2. TCPoXML DTD + + <!-- + DTD for TCP over XML. + Refer to this DTD as: + + <!DOCTYPE tcp PUBLIC "-//IETF//DTD BLOAT 1.0 TCP//EN" "bloat.dtd"> + --> + + <!-- the pseudoheader is only included for checksum calculations --> + <!ELEMENT tcp (tcp.pseudoheader?, tcp.header, payload)> + + <!ELEMENT tcp.header (src, dest, sequence, acknowledgement, offset, + reserved, control, window, checksum, urgent, + tcp.options, padding)> + + <!ELEMENT src EMPTY> + <!-- 0 <= port <= 65,535 --> + <!ATTLIST src + port %Digits; #REQUIRED> + + <!ELEMENT dest EMPTY> + <!-- 0 <= port <= 65,535 --> + + + +Kennedy Informational [Page 11] + +RFC 3252 Binary Lexical Octet Ad-hoc Transport 1 April 2002 + + + <!ATTLIST dest + port %Digits; #REQUIRED> + + <!ELEMENT sequence EMPTY> + <!-- 0 <= number <= 4294967295 --> + <!ATTLIST sequence + number %Digits; #REQUIRED> + + <!ELEMENT acknowledgement EMPTY> + <!-- 0 <= number <= 4294967295 --> + <!ATTLIST acknowledgement + number %Digits; #REQUIRED> + + <!ELEMENT offset EMPTY> + <!-- 0 <= number <= 255 --> + <!ATTLIST offset + number %Digits; #REQUIRED> + + <!ELEMENT reserved EMPTY> + <!ATTLIST reserved + value CDATA #FIXED "0"> + + <!ELEMENT control EMPTY> + <!ATTLIST control + urg (0|1) #IMPLIED + ack (0|1) #IMPLIED + psh (0|1) #IMPLIED + rst (0|1) #IMPLIED + syn (0|1) #IMPLIED + fin (0|1) #IMPLIED> + + <!ELEMENT window EMPTY> + <!-- 0 <= size <= 65,535 --> + <!ATTLIST window + size %Digits; #REQUIRED> + + <!-- + checksum as in ip, but with + the following pseudo-header added into the tcp element: + --> + <!ELEMENT tcp.pseudoheader (source, destination, protocol, + tcp.length)> + + <!-- + tcp header + data length in octets. does not include the size of + + the pseudoheader. + --> + + + +Kennedy Informational [Page 12] + +RFC 3252 Binary Lexical Octet Ad-hoc Transport 1 April 2002 + + + <!ELEMENT tcp.length EMPTY> + <!ATTLIST tcp.length + value %Digits; #REQUIRED> + + <!ELEMENT urgent EMPTY> + <!-- 0 <= pointer <= 65,535 --> + <!ATTLIST urgent + pointer %Digits; #REQUIRED> + + <!ELEMENT tcp.options (tcp.end | tcp.noop | tcp.mss)+> + + <!ELEMENT tcp.end EMPTY> + <!ATTLIST tcp.end + kind CDATA #FIXED "0"> + + <!ELEMENT tcp.noop EMPTY> + <!ATTLIST tcp.noop + kind CDATA #FIXED "1"> + + <!ELEMENT tcp.mss EMPTY> + <!ATTLIST tcp.mss + kind CDATA #FIXED "2" + length CDATA #FIXED "4" + size %Digits; #REQUIRED> + +7.3. UDPoXML DTD + + <!-- + DTD for UDP over XML. + Refer to this DTD as: + + <!DOCTYPE udp PUBLIC "-//IETF//DTD BLOAT 1.0 UDP//EN" "bloat.dtd"> + --> + + <!ELEMENT udp (udp.pseudoheader?, udp.header, payload)> + + <!ELEMENT udp.header (src, dest, udp.length, checksum)> + + <!ELEMENT udp.pseudoheader (source, destination, protocol, + udp.length)> + + <!-- + udp header + data length in octets. does not include the size of + the pseudoheader. + --> + <!ELEMENT udp.length EMPTY> + <!ATTLIST udp.length + value %Digits; #REQUIRED> + + + +Kennedy Informational [Page 13] + +RFC 3252 Binary Lexical Octet Ad-hoc Transport 1 April 2002 + + +8. Security Considerations + + XML, as a subset of SGML, has the same security considerations as + specified in SGML Media Types [RFC1874]. Security considerations + that apply to IP, TCP and UDP also likely apply to BLOAT as it does + not attempt to correct for issues not related to message format. + +9. References + + [JABBER] Miller, J., "Jabber", draft-miller-jabber-00.txt, + February 2002. (Work in Progress) + + [RFC768] Postel, J., "User Datagram Protocol", STD 6, RFC 768, + August 1980. + + [RFC791] Postel, J., "Internet Protocol", STD 5, RFC 791, + September 1981. + + [RFC793] Postel, J., "Transmission Control Protocol", STD 7, RFC + 793, September 1981. + + [RFC894] Hornig, C., "Standard for the Transmission of IP + Datagrams over Ethernet Networks.", RFC 894, April 1984. + + [RFC1042] Postel, J. and J. Reynolds, "Standard for the + Transmission of IP Datagrams Over IEEE 802 Networks", STD + 43, RFC 1042, February 1988. + + [RFC1123] Braden, R., "Requirements for Internet Hosts - + Application and Support", RFC 1123, October 1989. + + [RFC1874] Levinson, E., "SGML Media Types", RFC 1874, December + 1995. + + [RFC2003] Perkins, C., "IP Encapsulation within IP", RFC 2003, + October 1996. + + [RFC2045] Freed, N. and N. Borenstein, "Multipurpose Internet Mail + Extensions (MIME) Part One: Format of Internet Message + Bodies", RFC 2045, November 1996. + + [RFC2119] Bradner, S., "Key words for use in RFCs to Indicate + Requirement Levels", BCP 14, RFC 2119, March 1997. + + [RFC2279] Yergeau, F., "UTF-8, a transformation format of ISO + 10646", RFC 2279, January 1998. + + + + + +Kennedy Informational [Page 14] + +RFC 3252 Binary Lexical Octet Ad-hoc Transport 1 April 2002 + + + [RFC2460] Deering, S. and R. Hinden, "Internet Protocol, Version 6 + (IPv6) Specification", RFC 2460, December 1998. + + [RFC3080] Rose, M., "The Blocks Extensible Exchange Protocol Core", + RFC 3080, March 2001. + + [SOAP] Box, D., Ehnebuske, D., Kakivaya, G., Layman, A., + Mendelsohn, N., Nielsen, H. F., Thatte, S. Winer, D., + "Simple Object Access Protocol (SOAP) 1.1" World Wide Web + Consortium Note, May 2000 http://www.w3.org/TR/SOAP/ + + [XML] Bray, T., Paoli, J., Sperberg-McQueen, C. M., "Extensible + Markup Language (XML)" World Wide Web Consortium + Recommendation REC- xml-19980210. + http://www.w3.org/TR/1998/REC-xml-19980210 + +10. Author's Address + + Hugh Kennedy + Mimezine + 1060 West Addison + Chicago, IL 60613 + USA + + EMail: kennedyh@engin.umich.edu + + + + + + + + + + + + + + + + + + + + + + + + + + +Kennedy Informational [Page 15] + +RFC 3252 Binary Lexical Octet Ad-hoc Transport 1 April 2002 + + +11. Full Copyright Statement + + Copyright (C) The Internet Society (2002). All Rights Reserved. + + This document and translations of it may be copied and furnished to + others, and derivative works that comment on or otherwise explain it + or assist in its implementation may be prepared, copied, published + and distributed, in whole or in part, without restriction of any + kind, provided that the above copyright notice and this paragraph are + included on all such copies and derivative works. However, this + document itself may not be modified in any way, such as by removing + the copyright notice or references to the Internet Society or other + Internet organizations, except as needed for the purpose of + developing Internet standards in which case the procedures for + copyrights defined in the Internet Standards process must be + followed, or as required to translate it into languages other than + English. + + The limited permissions granted above are perpetual and will not be + revoked by the Internet Society or its successors or assigns. + + This document and the information contained herein is provided on an + "AS IS" basis and THE INTERNET SOCIETY AND THE INTERNET ENGINEERING + TASK FORCE DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING + BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE INFORMATION + HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED WARRANTIES OF + MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. + +Acknowledgement + + Funding for the RFC Editor function is currently provided by the + Internet Society. + + + + + + + + + + + + + + + + + + + +Kennedy Informational [Page 16] + + + + + + + +Network Working Group H. Kennedy +Request for Comments: 3252 Mimezine +Category: Informational 1 April 2002 + + + Binary Lexical Octet Ad-hoc Transport + +Status of this Memo + + This memo provides information for the Internet community. It does + not specify an Internet standard of any kind. Distribution of this + memo is unlimited. + +Copyright Notice + + Copyright (C) The Internet Society (2002). All Rights Reserved. + +Abstract + + This document defines a reformulation of IP and two transport layer + protocols (TCP and UDP) as XML applications. + +1. Introduction + +1.1. Overview + + This document describes the Binary Lexical Octet Ad-hoc Transport + (BLOAT): a reformulation of a widely-deployed network-layer protocol + (IP [RFC791]), and two associated transport layer protocols (TCP + [RFC793] and UDP [RFC768]) as XML [XML] applications. It also + describes methods for transporting BLOAT over Ethernet and IEEE 802 + networks as well as encapsulating BLOAT in IP for gatewaying BLOAT + across the public Internet. + +1.2. Motivation + + The wild popularity of XML as a basis for application-level protocols + such as the Blocks Extensible Exchange Protocol [RFC3080], the Simple + Object Access Protocol [SOAP], and Jabber [JABBER] prompted + investigation into the possibility of extending the use of XML in the + protocol stack. Using XML at both the transport and network layer in + addition to the application layer would provide for an amazing amount + of power and flexibility while removing dependencies on proprietary + and hard-to-understand binary protocols. This protocol unification + would also allow applications to use a single XML parser for all + aspects of their operation, eliminating developer time spent figuring + out the intricacies of each new protocol, and moving the hard work of + + + + +Kennedy Informational [Page 1] + +RFC 3252 Binary Lexical Octet Ad-hoc Transport 1 April 2002 + + + parsing to the XML toolset. The use of XML also mitigates concerns + over "network vs. host" byte ordering which is at the root of many + network application bugs. + +1.3. Relation to Existing Protocols + + The reformulations specified in this RFC follow as closely as + possible the spirit of the RFCs on which they are based, and so MAY + contain elements or attributes that would not be needed in a pure + reworking (e.g. length attributes, which are implicit in XML.) + + The layering of network and transport protocols are maintained in + this RFC despite the optimizations that could be made if the line + were somewhat blurred (i.e. merging TCP and IP into a single, larger + element in the DTD) in order to foster future use of this protocol as + a basis for reformulating other protocols (such as ICMP.) + + Other than the encoding, the behavioral aspects of each of the + existing protocols remain unchanged. Routing, address spaces, TCP + congestion control, etc. behave as specified in the extant standards. + Adapting to new standards and experimental algorithm heuristics for + improving performance will become much easier once the move to BLOAT + has been completed. + +1.4. Requirement Levels + + The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", + "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this + document are to be interpreted as described in BCP 14, RFC 2119 + [RFC2119]. + +2. IPoXML + + This protocol MUST be implemented to be compliant with this RFC. + IPoXML is the root protocol REQUIRED for effective use of TCPoXML + (section 3.) and higher-level application protocols. + + The DTD for this document type can be found in section 7.1. + + The routing of IPoXML can be easily implemented on hosts with an XML + parser, as the regular structure lends itself handily to parsing and + validation of the document/datagram and then processing the + destination address, TTL, and checksum before sending it on to its + next-hop. + + The reformulation of IPv4 was chosen over IPv6 [RFC2460] due to the + wider deployment of IPv4 and the fact that implementing IPv6 as XML + would have exceeded the 1500 byte Ethernet MTU. + + + +Kennedy Informational [Page 2] + +RFC 3252 Binary Lexical Octet Ad-hoc Transport 1 April 2002 + + + All BLOAT implementations MUST use - and specify - the UTF-8 encoding + of RFC 2279 [RFC2279]. All BLOAT document/datagrams MUST be well- + formed and include the XMLDecl. + +2.1. IP Description + + A number of items have changed (for the better) from the original IP + specification. Bit-masks, where present have been converted into + human-readable values. IP addresses are listed in their dotted- + decimal notation [RFC1123]. Length and checksum values are present + as decimal integers. + + To calculate the length and checksum fields of the IP element, a + canonicalized form of the element MUST be used. The canonical form + SHALL have no whitespace (including newline characters) between + elements and only one space character between attributes. There + SHALL NOT be a space following the last attribute in an element. + + An iterative method SHOULD be used to calculate checksums, as the + length field will vary based on the size of the checksum. + + The payload element bears special attention. Due to the character + set restrictions of XML, the payload of IP datagrams (which MAY + contain arbitrary data) MUST be encoded for transport. This RFC + REQUIRES the contents of the payload to be encoded in the base-64 + encoding of RFC 2045 [RFC2045], but removes the requirement that the + encoded output MUST be wrapped on 76-character lines. + + + + + + + + + + + + + + + + + + + + + + + + +Kennedy Informational [Page 3] + +RFC 3252 Binary Lexical Octet Ad-hoc Transport 1 April 2002 + + +2.2. Example Datagram + + The following is an example IPoXML datagram with an empty payload: + + <?xml version="1.0" encoding="UTF-8"?> + <!DOCTYPE ip PUBLIC "-//IETF//DTD BLOAT 1.0 IP//EN" "bloat.dtd"> + <ip> + <header length="474"> + <version value="4"/> + <tos precedence="Routine" delay="Normal" throughput="Normal" + relibility="Normal" reserved="0"/> + <total.length value="461"/> + <id value="1"/> + <flags reserved="0" df="dont" mf="last"/> + <offset value="0"/> + <ttl value="255"/> + <protocol value="6"/> + <checksum value="8707"/> + <source address="10.0.0.22"/> + <destination address="10.0.0.1"/> + <options> + <end copied="0" class="0" number="0"/> + </options> + <padding pad="0"/> + </header> + <payload> + </payload> + </ip> + +3. TCPoXML + + This protocol MUST be implemented to be compliant with this RFC. The + DTD for this document type can be found in section 7.2. + +3.1. TCP Description + + A number of items have changed from the original TCP specification. + Bit-masks, where present have been converted into human-readable + values. Length and checksum and port values are present as decimal + integers. + + To calculate the length and checksum fields of the TCP element, a + canonicalized form of the element MUST be used as in section 2.1. + + An iterative method SHOULD be used to calculate checksums as in + section 2.1. + + The payload element MUST be encoded as in section 2.1. + + + +Kennedy Informational [Page 4] + +RFC 3252 Binary Lexical Octet Ad-hoc Transport 1 April 2002 + + + The TCP offset element was expanded to a maximum of 255 from 16 to + allow for the increased size of the header in XML. + + TCPoXML datagrams encapsulated by IPoXML MAY omit the <?xml?> header + as well as the <!DOCTYPE> declaration. + +3.2. Example Datagram + + The following is an example TCPoXML datagram with an empty payload: + + <?xml version="1.0" encoding="UTF-8"?> + <!DOCTYPE tcp PUBLIC "-//IETF//DTD BLOAT 1.0 TCP//EN" "bloat.dtd"> + <tcp> + <tcp.header> + <src port="31415"/> + <dest port="42424"/> + <sequence number="322622954"/> + <acknowledgement number="689715995"/> + <offset number=""/> + <reserved value="0"/> + <control syn="1" ack="1"/> + <window size="1"/> + <urgent pointer="0"/> + <checksum value="2988"/> + <tcp.options> + <tcp.end kind="0"/> + </tcp.options> + <padding pad="0"/> + </tcp.header> + <payload> + </payload> + </tcp> + +4. UDPoXML + + This protocol MUST be implemented to be compliant with this RFC. The + DTD for this document type can be found in section 7.3. + +4.1. UDP Description + + A number of items have changed from the original UDP specification. + Bit-masks, where present have been converted into human-readable + values. Length and checksum and port values are present as decimal + integers. + + + + + + + +Kennedy Informational [Page 5] + +RFC 3252 Binary Lexical Octet Ad-hoc Transport 1 April 2002 + + + To calculate the length and checksum fields of the UDP element, a + canonicalized form of the element MUST be used as in section 2.1. An + iterative method SHOULD be used to calculate checksums as in section + 2.1. + + The payload element MUST be encoded as in section 2.1. + + UDPoXML datagrams encapsulated by IPoXML MAY omit the <?xml?> header + as well as the <!DOCTYPE> declaration. + +4.2. Example Datagram + + The following is an example UDPoXML datagram with an empty payload: + + <?xml version="1.0" encoding="UTF-8"?> + <!DOCTYPE udp PUBLIC "-//IETF//DTD BLOAT 1.0 UDP//EN" "bloat.dtd"> + <udp> + <udp.header> + <src port="31415"/> + <dest port="42424"/> + <udp.length value="143"/> + <checksum value="2988"/> + </udp.header> + <payload> + </payload> + </udp> + +5. Network Transport + + This document provides for the transmission of BLOAT datagrams over + two common families of physical layer transport. Future RFCs will + address additional transports as routing vendors catch up to the + specification, and we begin to see BLOAT routed across the Internet + backbone. + +5.1. Ethernet + + BLOAT is encapsulated in Ethernet datagrams as in [RFC894] with the + exception that the type field of the Ethernet frame MUST contain the + value 0xBEEF. The first 5 octets of the Ethernet frame payload will + be 0x3c 3f 78 6d 6c ("<?xml".) + +5.2. IEEE 802 + + BLOAT is encapsulated in IEEE 802 Networks as in [RFC1042] except + that the protocol type code for IPoXML is 0xBEEF. + + + + + +Kennedy Informational [Page 6] + +RFC 3252 Binary Lexical Octet Ad-hoc Transport 1 April 2002 + + +6. Gatewaying over IP + + In order to facilitate the gradual introduction of BLOAT into the + public Internet, BLOAT MAY be encapsulated in IP as in [RFC2003] to + gateway between networks that run BLOAT natively on their LANs. + +7. DTDs + + The Transport DTDs (7.2. and 7.3.) build on the definitions in the + Network DTD (7.1.) + + The DTDs are referenced by their PubidLiteral and SystemLiteral (from + [XML]) although it is understood that most IPoXML implementations + will not need to pull down the DTD, as it will normally be embedded + in the implementation, and presents something of a catch-22 if you + need to load part of your network protocol over the network. + +7.1. IPoXML DTD + + <!-- + DTD for IP over XML. + Refer to this DTD as: + + <!DOCTYPE ip PUBLIC "-//IETF//DTD BLOAT 1.0 IP//EN" "bloat.dtd"> + --> + <!-- + DTD data types: + + Digits [0..9]+ + + Precedence "NetworkControl | InternetworkControl | + CRITIC | FlashOverride | Flash | Immediate | + Priority | Routine" + + IP4Addr "dotted-decimal" notation of [RFC1123] + + Class [0..3] + + Sec "Unclassified | Confidential | EFTO | MMMM | PROG | + Restricted | Secret | Top Secret | Reserved" + + Compartments [0..65535] + + Handling [0..65535] + + TCC [0..16777216] + + --> + + + +Kennedy Informational [Page 7] + +RFC 3252 Binary Lexical Octet Ad-hoc Transport 1 April 2002 + + + <!ENTITY % Digits "CDATA"> + <!ENTITY % Precedence "CDATA"> + <!ENTITY % IP4Addr "CDATA"> + <!ENTITY % Class "CDATA"> + <!ENTITY % Sec "CDATA"> + <!ENTITY % Compartments "CDATA"> + <!ENTITY % Handling "CDATA"> + <!ENTITY % TCC "CDATA"> + + <!ELEMENT ip (header, payload)> + + <!ELEMENT header (version, tos, total.length, id, flags, offset, ttl, + protocol, checksum, source, destination, options, + padding)> + <!-- length of header in 32-bit words --> + <!ATTLIST header + length %Digits; #REQUIRED> + + <!ELEMENT version EMPTY> + <!-- ip version. SHOULD be "4" --> + <!ATTLIST version + value %Digits; #REQUIRED> + + <!ELEMENT tos EMPTY> + <!ATTLIST tos + precedence %Precedence; #REQUIRED + delay (normal | low) #REQUIRED + throughput (normal | high) #REQUIRED + relibility (normal | high) #REQUIRED + reserved CDATA #FIXED "0"> + + <!ELEMENT total.length EMPTY> + <!-- + total length of datagram (header and payload) in octets, MUST be + less than 65,535 (and SHOULD be less than 1024 for IPoXML on local + ethernets). + --> + <!ATTLIST total.length + value %Digits; #REQUIRED> + + <!ELEMENT id EMPTY> + <!-- 0 <= id <= 65,535 --> + <!ATTLIST id + value %Digits; #REQUIRED> + + <!ELEMENT flags EMPTY> + <!-- df = don't fragment, mf = more fragments --> + <!ATTLIST flags + + + +Kennedy Informational [Page 8] + +RFC 3252 Binary Lexical Octet Ad-hoc Transport 1 April 2002 + + + reserved CDATA #FIXED "0" + df (may|dont) #REQUIRED + mf (last|more) #REQUIRED> + + <!ELEMENT offset EMPTY> + <!-- 0 <= offset <= 8192 measured in 8 octet (64-bit) chunks --> + <!ATTLIST offset + value %Digits; #REQUIRED> + + <!ELEMENT ttl EMPTY> + <!-- 0 <= ttl <= 255 --> + <!ATTLIST ttl + value %Digits; #REQUIRED> + + <!ELEMENT protocol EMPTY> + <!-- 0 <= protocol <= 255 (per IANA) --> + <!ATTLIST protocol + value %Digits; #REQUIRED> + + <!ELEMENT checksum EMPTY> + <!-- 0 <= checksum <= 65535 (over header only) --> + <!ATTLIST checksum + value %Digits; #REQUIRED> + + <!ELEMENT source EMPTY> + <!ATTLIST source + address %IP4Addr; #REQUIRED> + + <!ELEMENT destination EMPTY> + <!ATTLIST destination + address %IP4Addr; #REQUIRED> + + <!ELEMENT options ( end | noop | security | loose | strict | record + | stream | timestamp )*> + + <!ELEMENT end EMPTY> + <!ATTLIST end + copied (0|1) #REQUIRED + class CDATA #FIXED "0" + number CDATA #FIXED "0"> + + <!ELEMENT noop EMPTY> + <!ATTLIST noop + copied (0|1) #REQUIRED + class CDATA #FIXED "0" + number CDATA #FIXED "1"> + + <!ELEMENT security EMPTY> + + + +Kennedy Informational [Page 9] + +RFC 3252 Binary Lexical Octet Ad-hoc Transport 1 April 2002 + + + <!ATTLIST security + copied CDATA #FIXED "1" + class CDATA #FIXED "0" + number CDATA #FIXED "2" + length CDATA #FIXED "11" + security %Sec; #REQUIRED + compartments %Compartments; #REQUIRED + handling %Handling; #REQUIRED + tcc %TCC; #REQUIRED> + <!ELEMENT loose (hop)+> + <!ATTLIST loose + copied CDATA #FIXED "1" + class CDATA #FIXED "0" + number CDATA #FIXED "3" + length %Digits; #REQUIRED + pointer %Digits; #REQUIRED> + + <!ELEMENT hop EMPTY> + <!ATTLIST hop + address %IP4Addr; #REQUIRED> + + <!ELEMENT strict (hop)+> + <!ATTLIST strict + copied CDATA #FIXED "1" + class CDATA #FIXED "0" + number CDATA #FIXED "9" + length %Digits; #REQUIRED + pointer %Digits; #REQUIRED> + + <!ELEMENT record (hop)+> + <!ATTLIST record + copied CDATA #FIXED "0" + class CDATA #FIXED "0" + number CDATA #FIXED "7" + length %Digits; #REQUIRED + pointer %Digits; #REQUIRED> + + <!ELEMENT stream EMPTY> + <!-- 0 <= id <= 65,535 --> + <!ATTLIST stream + copied CDATA #FIXED "1" + class CDATA #FIXED "0" + number CDATA #FIXED "8" + length CDATA #FIXED "4" + id %Digits; #REQUIRED> + + <!ELEMENT timestamp (tstamp)+> + <!-- 0 <= oflw <=15 --> + + + +Kennedy Informational [Page 10] + +RFC 3252 Binary Lexical Octet Ad-hoc Transport 1 April 2002 + + + <!ATTLIST timestamp + copied CDATA #FIXED "0" + class CDATA #FIXED "2" + number CDATA #FIXED "4" + length %Digits; #REQUIRED + pointer %Digits; #REQUIRED + oflw %Digits; #REQUIRED + flag (0 | 1 | 3) #REQUIRED> + + <!ELEMENT tstamp EMPTY> + <!ATTLIST tstamp + time %Digits; #REQUIRED + address %IP4Addr; #IMPLIED> + <!-- + padding to bring header to 32-bit boundary. + pad MUST be "0"* + --> + <!ELEMENT padding EMPTY> + <!ATTLIST padding + pad CDATA #REQUIRED> + + <!-- payload MUST be encoded as base-64 [RFC2045], as modified + by section 2.1 of this RFC --> + <!ELEMENT payload (CDATA)> + +7.2. TCPoXML DTD + + <!-- + DTD for TCP over XML. + Refer to this DTD as: + + <!DOCTYPE tcp PUBLIC "-//IETF//DTD BLOAT 1.0 TCP//EN" "bloat.dtd"> + --> + + <!-- the pseudoheader is only included for checksum calculations --> + <!ELEMENT tcp (tcp.pseudoheader?, tcp.header, payload)> + + <!ELEMENT tcp.header (src, dest, sequence, acknowledgement, offset, + reserved, control, window, checksum, urgent, + tcp.options, padding)> + + <!ELEMENT src EMPTY> + <!-- 0 <= port <= 65,535 --> + <!ATTLIST src + port %Digits; #REQUIRED> + + <!ELEMENT dest EMPTY> + <!-- 0 <= port <= 65,535 --> + + + +Kennedy Informational [Page 11] + +RFC 3252 Binary Lexical Octet Ad-hoc Transport 1 April 2002 + + + <!ATTLIST dest + port %Digits; #REQUIRED> + + <!ELEMENT sequence EMPTY> + <!-- 0 <= number <= 4294967295 --> + <!ATTLIST sequence + number %Digits; #REQUIRED> + + <!ELEMENT acknowledgement EMPTY> + <!-- 0 <= number <= 4294967295 --> + <!ATTLIST acknowledgement + number %Digits; #REQUIRED> + + <!ELEMENT offset EMPTY> + <!-- 0 <= number <= 255 --> + <!ATTLIST offset + number %Digits; #REQUIRED> + + <!ELEMENT reserved EMPTY> + <!ATTLIST reserved + value CDATA #FIXED "0"> + + <!ELEMENT control EMPTY> + <!ATTLIST control + urg (0|1) #IMPLIED + ack (0|1) #IMPLIED + psh (0|1) #IMPLIED + rst (0|1) #IMPLIED + syn (0|1) #IMPLIED + fin (0|1) #IMPLIED> + + <!ELEMENT window EMPTY> + <!-- 0 <= size <= 65,535 --> + <!ATTLIST window + size %Digits; #REQUIRED> + + <!-- + checksum as in ip, but with + the following pseudo-header added into the tcp element: + --> + <!ELEMENT tcp.pseudoheader (source, destination, protocol, + tcp.length)> + + <!-- + tcp header + data length in octets. does not include the size of + + the pseudoheader. + --> + + + +Kennedy Informational [Page 12] + +RFC 3252 Binary Lexical Octet Ad-hoc Transport 1 April 2002 + + + <!ELEMENT tcp.length EMPTY> + <!ATTLIST tcp.length + value %Digits; #REQUIRED> + + <!ELEMENT urgent EMPTY> + <!-- 0 <= pointer <= 65,535 --> + <!ATTLIST urgent + pointer %Digits; #REQUIRED> + + <!ELEMENT tcp.options (tcp.end | tcp.noop | tcp.mss)+> + + <!ELEMENT tcp.end EMPTY> + <!ATTLIST tcp.end + kind CDATA #FIXED "0"> + + <!ELEMENT tcp.noop EMPTY> + <!ATTLIST tcp.noop + kind CDATA #FIXED "1"> + + <!ELEMENT tcp.mss EMPTY> + <!ATTLIST tcp.mss + kind CDATA #FIXED "2" + length CDATA #FIXED "4" + size %Digits; #REQUIRED> + +7.3. UDPoXML DTD + + <!-- + DTD for UDP over XML. + Refer to this DTD as: + + <!DOCTYPE udp PUBLIC "-//IETF//DTD BLOAT 1.0 UDP//EN" "bloat.dtd"> + --> + + <!ELEMENT udp (udp.pseudoheader?, udp.header, payload)> + + <!ELEMENT udp.header (src, dest, udp.length, checksum)> + + <!ELEMENT udp.pseudoheader (source, destination, protocol, + udp.length)> + + <!-- + udp header + data length in octets. does not include the size of + the pseudoheader. + --> + <!ELEMENT udp.length EMPTY> + <!ATTLIST udp.length + value %Digits; #REQUIRED> + + + +Kennedy Informational [Page 13] + +RFC 3252 Binary Lexical Octet Ad-hoc Transport 1 April 2002 + + +8. Security Considerations + + XML, as a subset of SGML, has the same security considerations as + specified in SGML Media Types [RFC1874]. Security considerations + that apply to IP, TCP and UDP also likely apply to BLOAT as it does + not attempt to correct for issues not related to message format. + +9. References + + [JABBER] Miller, J., "Jabber", draft-miller-jabber-00.txt, + February 2002. (Work in Progress) + + [RFC768] Postel, J., "User Datagram Protocol", STD 6, RFC 768, + August 1980. + + [RFC791] Postel, J., "Internet Protocol", STD 5, RFC 791, + September 1981. + + [RFC793] Postel, J., "Transmission Control Protocol", STD 7, RFC + 793, September 1981. + + [RFC894] Hornig, C., "Standard for the Transmission of IP + Datagrams over Ethernet Networks.", RFC 894, April 1984. + + [RFC1042] Postel, J. and J. Reynolds, "Standard for the + Transmission of IP Datagrams Over IEEE 802 Networks", STD + 43, RFC 1042, February 1988. + + [RFC1123] Braden, R., "Requirements for Internet Hosts - + Application and Support", RFC 1123, October 1989. + + [RFC1874] Levinson, E., "SGML Media Types", RFC 1874, December + 1995. + + [RFC2003] Perkins, C., "IP Encapsulation within IP", RFC 2003, + October 1996. + + [RFC2045] Freed, N. and N. Borenstein, "Multipurpose Internet Mail + Extensions (MIME) Part One: Format of Internet Message + Bodies", RFC 2045, November 1996. + + [RFC2119] Bradner, S., "Key words for use in RFCs to Indicate + Requirement Levels", BCP 14, RFC 2119, March 1997. + + [RFC2279] Yergeau, F., "UTF-8, a transformation format of ISO + 10646", RFC 2279, January 1998. + + + + + +Kennedy Informational [Page 14] + +RFC 3252 Binary Lexical Octet Ad-hoc Transport 1 April 2002 + + + [RFC2460] Deering, S. and R. Hinden, "Internet Protocol, Version 6 + (IPv6) Specification", RFC 2460, December 1998. + + [RFC3080] Rose, M., "The Blocks Extensible Exchange Protocol Core", + RFC 3080, March 2001. + + [SOAP] Box, D., Ehnebuske, D., Kakivaya, G., Layman, A., + Mendelsohn, N., Nielsen, H. F., Thatte, S. Winer, D., + "Simple Object Access Protocol (SOAP) 1.1" World Wide Web + Consortium Note, May 2000 http://www.w3.org/TR/SOAP/ + + [XML] Bray, T., Paoli, J., Sperberg-McQueen, C. M., "Extensible + Markup Language (XML)" World Wide Web Consortium + Recommendation REC- xml-19980210. + http://www.w3.org/TR/1998/REC-xml-19980210 + +10. Author's Address + + Hugh Kennedy + Mimezine + 1060 West Addison + Chicago, IL 60613 + USA + + EMail: kennedyh@engin.umich.edu + + + + + + + + + + + + + + + + + + + + + + + + + + +Kennedy Informational [Page 15] + +RFC 3252 Binary Lexical Octet Ad-hoc Transport 1 April 2002 + + +11. Full Copyright Statement + + Copyright (C) The Internet Society (2002). All Rights Reserved. + + This document and translations of it may be copied and furnished to + others, and derivative works that comment on or otherwise explain it + or assist in its implementation may be prepared, copied, published + and distributed, in whole or in part, without restriction of any + kind, provided that the above copyright notice and this paragraph are + included on all such copies and derivative works. However, this + document itself may not be modified in any way, such as by removing + the copyright notice or references to the Internet Society or other + Internet organizations, except as needed for the purpose of + developing Internet standards in which case the procedures for + copyrights defined in the Internet Standards process must be + followed, or as required to translate it into languages other than + English. + + The limited permissions granted above are perpetual and will not be + revoked by the Internet Society or its successors or assigns. + + This document and the information contained herein is provided on an + "AS IS" basis and THE INTERNET SOCIETY AND THE INTERNET ENGINEERING + TASK FORCE DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING + BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE INFORMATION + HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED WARRANTIES OF + MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. + +Acknowledgement + + Funding for the RFC Editor function is currently provided by the + Internet Society. + + + + + + + + + + + + + + + + + + + +Kennedy Informational [Page 16] + + + + + + + +Network Working Group H. Kennedy +Request for Comments: 3252 Mimezine +Category: Informational 1 April 2002 + + + Binary Lexical Octet Ad-hoc Transport + +Status of this Memo + + This memo provides information for the Internet community. It does + not specify an Internet standard of any kind. Distribution of this + memo is unlimited. + +Copyright Notice + + Copyright (C) The Internet Society (2002). All Rights Reserved. + +Abstract + + This document defines a reformulation of IP and two transport layer + protocols (TCP and UDP) as XML applications. + +1. Introduction + +1.1. Overview + + This document describes the Binary Lexical Octet Ad-hoc Transport + (BLOAT): a reformulation of a widely-deployed network-layer protocol + (IP [RFC791]), and two associated transport layer protocols (TCP + [RFC793] and UDP [RFC768]) as XML [XML] applications. It also + describes methods for transporting BLOAT over Ethernet and IEEE 802 + networks as well as encapsulating BLOAT in IP for gatewaying BLOAT + across the public Internet. + +1.2. Motivation + + The wild popularity of XML as a basis for application-level protocols + such as the Blocks Extensible Exchange Protocol [RFC3080], the Simple + Object Access Protocol [SOAP], and Jabber [JABBER] prompted + investigation into the possibility of extending the use of XML in the + protocol stack. Using XML at both the transport and network layer in + addition to the application layer would provide for an amazing amount + of power and flexibility while removing dependencies on proprietary + and hard-to-understand binary protocols. This protocol unification + would also allow applications to use a single XML parser for all + aspects of their operation, eliminating developer time spent figuring + out the intricacies of each new protocol, and moving the hard work of + + + + +Kennedy Informational [Page 1] + +RFC 3252 Binary Lexical Octet Ad-hoc Transport 1 April 2002 + + + parsing to the XML toolset. The use of XML also mitigates concerns + over "network vs. host" byte ordering which is at the root of many + network application bugs. + +1.3. Relation to Existing Protocols + + The reformulations specified in this RFC follow as closely as + possible the spirit of the RFCs on which they are based, and so MAY + contain elements or attributes that would not be needed in a pure + reworking (e.g. length attributes, which are implicit in XML.) + + The layering of network and transport protocols are maintained in + this RFC despite the optimizations that could be made if the line + were somewhat blurred (i.e. merging TCP and IP into a single, larger + element in the DTD) in order to foster future use of this protocol as + a basis for reformulating other protocols (such as ICMP.) + + Other than the encoding, the behavioral aspects of each of the + existing protocols remain unchanged. Routing, address spaces, TCP + congestion control, etc. behave as specified in the extant standards. + Adapting to new standards and experimental algorithm heuristics for + improving performance will become much easier once the move to BLOAT + has been completed. + +1.4. Requirement Levels + + The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", + "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this + document are to be interpreted as described in BCP 14, RFC 2119 + [RFC2119]. + +2. IPoXML + + This protocol MUST be implemented to be compliant with this RFC. + IPoXML is the root protocol REQUIRED for effective use of TCPoXML + (section 3.) and higher-level application protocols. + + The DTD for this document type can be found in section 7.1. + + The routing of IPoXML can be easily implemented on hosts with an XML + parser, as the regular structure lends itself handily to parsing and + validation of the document/datagram and then processing the + destination address, TTL, and checksum before sending it on to its + next-hop. + + The reformulation of IPv4 was chosen over IPv6 [RFC2460] due to the + wider deployment of IPv4 and the fact that implementing IPv6 as XML + would have exceeded the 1500 byte Ethernet MTU. + + + +Kennedy Informational [Page 2] + +RFC 3252 Binary Lexical Octet Ad-hoc Transport 1 April 2002 + + + All BLOAT implementations MUST use - and specify - the UTF-8 encoding + of RFC 2279 [RFC2279]. All BLOAT document/datagrams MUST be well- + formed and include the XMLDecl. + +2.1. IP Description + + A number of items have changed (for the better) from the original IP + specification. Bit-masks, where present have been converted into + human-readable values. IP addresses are listed in their dotted- + decimal notation [RFC1123]. Length and checksum values are present + as decimal integers. + + To calculate the length and checksum fields of the IP element, a + canonicalized form of the element MUST be used. The canonical form + SHALL have no whitespace (including newline characters) between + elements and only one space character between attributes. There + SHALL NOT be a space following the last attribute in an element. + + An iterative method SHOULD be used to calculate checksums, as the + length field will vary based on the size of the checksum. + + The payload element bears special attention. Due to the character + set restrictions of XML, the payload of IP datagrams (which MAY + contain arbitrary data) MUST be encoded for transport. This RFC + REQUIRES the contents of the payload to be encoded in the base-64 + encoding of RFC 2045 [RFC2045], but removes the requirement that the + encoded output MUST be wrapped on 76-character lines. + + + + + + + + + + + + + + + + + + + + + + + + +Kennedy Informational [Page 3] + +RFC 3252 Binary Lexical Octet Ad-hoc Transport 1 April 2002 + + +2.2. Example Datagram + + The following is an example IPoXML datagram with an empty payload: + + <?xml version="1.0" encoding="UTF-8"?> + <!DOCTYPE ip PUBLIC "-//IETF//DTD BLOAT 1.0 IP//EN" "bloat.dtd"> + <ip> + <header length="474"> + <version value="4"/> + <tos precedence="Routine" delay="Normal" throughput="Normal" + relibility="Normal" reserved="0"/> + <total.length value="461"/> + <id value="1"/> + <flags reserved="0" df="dont" mf="last"/> + <offset value="0"/> + <ttl value="255"/> + <protocol value="6"/> + <checksum value="8707"/> + <source address="10.0.0.22"/> + <destination address="10.0.0.1"/> + <options> + <end copied="0" class="0" number="0"/> + </options> + <padding pad="0"/> + </header> + <payload> + </payload> + </ip> + +3. TCPoXML + + This protocol MUST be implemented to be compliant with this RFC. The + DTD for this document type can be found in section 7.2. + +3.1. TCP Description + + A number of items have changed from the original TCP specification. + Bit-masks, where present have been converted into human-readable + values. Length and checksum and port values are present as decimal + integers. + + To calculate the length and checksum fields of the TCP element, a + canonicalized form of the element MUST be used as in section 2.1. + + An iterative method SHOULD be used to calculate checksums as in + section 2.1. + + The payload element MUST be encoded as in section 2.1. + + + +Kennedy Informational [Page 4] + +RFC 3252 Binary Lexical Octet Ad-hoc Transport 1 April 2002 + + + The TCP offset element was expanded to a maximum of 255 from 16 to + allow for the increased size of the header in XML. + + TCPoXML datagrams encapsulated by IPoXML MAY omit the <?xml?> header + as well as the <!DOCTYPE> declaration. + +3.2. Example Datagram + + The following is an example TCPoXML datagram with an empty payload: + + <?xml version="1.0" encoding="UTF-8"?> + <!DOCTYPE tcp PUBLIC "-//IETF//DTD BLOAT 1.0 TCP//EN" "bloat.dtd"> + <tcp> + <tcp.header> + <src port="31415"/> + <dest port="42424"/> + <sequence number="322622954"/> + <acknowledgement number="689715995"/> + <offset number=""/> + <reserved value="0"/> + <control syn="1" ack="1"/> + <window size="1"/> + <urgent pointer="0"/> + <checksum value="2988"/> + <tcp.options> + <tcp.end kind="0"/> + </tcp.options> + <padding pad="0"/> + </tcp.header> + <payload> + </payload> + </tcp> + +4. UDPoXML + + This protocol MUST be implemented to be compliant with this RFC. The + DTD for this document type can be found in section 7.3. + +4.1. UDP Description + + A number of items have changed from the original UDP specification. + Bit-masks, where present have been converted into human-readable + values. Length and checksum and port values are present as decimal + integers. + + + + + + + +Kennedy Informational [Page 5] + +RFC 3252 Binary Lexical Octet Ad-hoc Transport 1 April 2002 + + + To calculate the length and checksum fields of the UDP element, a + canonicalized form of the element MUST be used as in section 2.1. An + iterative method SHOULD be used to calculate checksums as in section + 2.1. + + The payload element MUST be encoded as in section 2.1. + + UDPoXML datagrams encapsulated by IPoXML MAY omit the <?xml?> header + as well as the <!DOCTYPE> declaration. + +4.2. Example Datagram + + The following is an example UDPoXML datagram with an empty payload: + + <?xml version="1.0" encoding="UTF-8"?> + <!DOCTYPE udp PUBLIC "-//IETF//DTD BLOAT 1.0 UDP//EN" "bloat.dtd"> + <udp> + <udp.header> + <src port="31415"/> + <dest port="42424"/> + <udp.length value="143"/> + <checksum value="2988"/> + </udp.header> + <payload> + </payload> + </udp> + +5. Network Transport + + This document provides for the transmission of BLOAT datagrams over + two common families of physical layer transport. Future RFCs will + address additional transports as routing vendors catch up to the + specification, and we begin to see BLOAT routed across the Internet + backbone. + +5.1. Ethernet + + BLOAT is encapsulated in Ethernet datagrams as in [RFC894] with the + exception that the type field of the Ethernet frame MUST contain the + value 0xBEEF. The first 5 octets of the Ethernet frame payload will + be 0x3c 3f 78 6d 6c ("<?xml".) + +5.2. IEEE 802 + + BLOAT is encapsulated in IEEE 802 Networks as in [RFC1042] except + that the protocol type code for IPoXML is 0xBEEF. + + + + + +Kennedy Informational [Page 6] + +RFC 3252 Binary Lexical Octet Ad-hoc Transport 1 April 2002 + + +6. Gatewaying over IP + + In order to facilitate the gradual introduction of BLOAT into the + public Internet, BLOAT MAY be encapsulated in IP as in [RFC2003] to + gateway between networks that run BLOAT natively on their LANs. + +7. DTDs + + The Transport DTDs (7.2. and 7.3.) build on the definitions in the + Network DTD (7.1.) + + The DTDs are referenced by their PubidLiteral and SystemLiteral (from + [XML]) although it is understood that most IPoXML implementations + will not need to pull down the DTD, as it will normally be embedded + in the implementation, and presents something of a catch-22 if you + need to load part of your network protocol over the network. + +7.1. IPoXML DTD + + <!-- + DTD for IP over XML. + Refer to this DTD as: + + <!DOCTYPE ip PUBLIC "-//IETF//DTD BLOAT 1.0 IP//EN" "bloat.dtd"> + --> + <!-- + DTD data types: + + Digits [0..9]+ + + Precedence "NetworkControl | InternetworkControl | + CRITIC | FlashOverride | Flash | Immediate | + Priority | Routine" + + IP4Addr "dotted-decimal" notation of [RFC1123] + + Class [0..3] + + Sec "Unclassified | Confidential | EFTO | MMMM | PROG | + Restricted | Secret | Top Secret | Reserved" + + Compartments [0..65535] + + Handling [0..65535] + + TCC [0..16777216] + + --> + + + +Kennedy Informational [Page 7] + +RFC 3252 Binary Lexical Octet Ad-hoc Transport 1 April 2002 + + + <!ENTITY % Digits "CDATA"> + <!ENTITY % Precedence "CDATA"> + <!ENTITY % IP4Addr "CDATA"> + <!ENTITY % Class "CDATA"> + <!ENTITY % Sec "CDATA"> + <!ENTITY % Compartments "CDATA"> + <!ENTITY % Handling "CDATA"> + <!ENTITY % TCC "CDATA"> + + <!ELEMENT ip (header, payload)> + + <!ELEMENT header (version, tos, total.length, id, flags, offset, ttl, + protocol, checksum, source, destination, options, + padding)> + <!-- length of header in 32-bit words --> + <!ATTLIST header + length %Digits; #REQUIRED> + + <!ELEMENT version EMPTY> + <!-- ip version. SHOULD be "4" --> + <!ATTLIST version + value %Digits; #REQUIRED> + + <!ELEMENT tos EMPTY> + <!ATTLIST tos + precedence %Precedence; #REQUIRED + delay (normal | low) #REQUIRED + throughput (normal | high) #REQUIRED + relibility (normal | high) #REQUIRED + reserved CDATA #FIXED "0"> + + <!ELEMENT total.length EMPTY> + <!-- + total length of datagram (header and payload) in octets, MUST be + less than 65,535 (and SHOULD be less than 1024 for IPoXML on local + ethernets). + --> + <!ATTLIST total.length + value %Digits; #REQUIRED> + + <!ELEMENT id EMPTY> + <!-- 0 <= id <= 65,535 --> + <!ATTLIST id + value %Digits; #REQUIRED> + + <!ELEMENT flags EMPTY> + <!-- df = don't fragment, mf = more fragments --> + <!ATTLIST flags + + + +Kennedy Informational [Page 8] + +RFC 3252 Binary Lexical Octet Ad-hoc Transport 1 April 2002 + + + reserved CDATA #FIXED "0" + df (may|dont) #REQUIRED + mf (last|more) #REQUIRED> + + <!ELEMENT offset EMPTY> + <!-- 0 <= offset <= 8192 measured in 8 octet (64-bit) chunks --> + <!ATTLIST offset + value %Digits; #REQUIRED> + + <!ELEMENT ttl EMPTY> + <!-- 0 <= ttl <= 255 --> + <!ATTLIST ttl + value %Digits; #REQUIRED> + + <!ELEMENT protocol EMPTY> + <!-- 0 <= protocol <= 255 (per IANA) --> + <!ATTLIST protocol + value %Digits; #REQUIRED> + + <!ELEMENT checksum EMPTY> + <!-- 0 <= checksum <= 65535 (over header only) --> + <!ATTLIST checksum + value %Digits; #REQUIRED> + + <!ELEMENT source EMPTY> + <!ATTLIST source + address %IP4Addr; #REQUIRED> + + <!ELEMENT destination EMPTY> + <!ATTLIST destination + address %IP4Addr; #REQUIRED> + + <!ELEMENT options ( end | noop | security | loose | strict | record + | stream | timestamp )*> + + <!ELEMENT end EMPTY> + <!ATTLIST end + copied (0|1) #REQUIRED + class CDATA #FIXED "0" + number CDATA #FIXED "0"> + + <!ELEMENT noop EMPTY> + <!ATTLIST noop + copied (0|1) #REQUIRED + class CDATA #FIXED "0" + number CDATA #FIXED "1"> + + <!ELEMENT security EMPTY> + + + +Kennedy Informational [Page 9] + +RFC 3252 Binary Lexical Octet Ad-hoc Transport 1 April 2002 + + + <!ATTLIST security + copied CDATA #FIXED "1" + class CDATA #FIXED "0" + number CDATA #FIXED "2" + length CDATA #FIXED "11" + security %Sec; #REQUIRED + compartments %Compartments; #REQUIRED + handling %Handling; #REQUIRED + tcc %TCC; #REQUIRED> + <!ELEMENT loose (hop)+> + <!ATTLIST loose + copied CDATA #FIXED "1" + class CDATA #FIXED "0" + number CDATA #FIXED "3" + length %Digits; #REQUIRED + pointer %Digits; #REQUIRED> + + <!ELEMENT hop EMPTY> + <!ATTLIST hop + address %IP4Addr; #REQUIRED> + + <!ELEMENT strict (hop)+> + <!ATTLIST strict + copied CDATA #FIXED "1" + class CDATA #FIXED "0" + number CDATA #FIXED "9" + length %Digits; #REQUIRED + pointer %Digits; #REQUIRED> + + <!ELEMENT record (hop)+> + <!ATTLIST record + copied CDATA #FIXED "0" + class CDATA #FIXED "0" + number CDATA #FIXED "7" + length %Digits; #REQUIRED + pointer %Digits; #REQUIRED> + + <!ELEMENT stream EMPTY> + <!-- 0 <= id <= 65,535 --> + <!ATTLIST stream + copied CDATA #FIXED "1" + class CDATA #FIXED "0" + number CDATA #FIXED "8" + length CDATA #FIXED "4" + id %Digits; #REQUIRED> + + <!ELEMENT timestamp (tstamp)+> + <!-- 0 <= oflw <=15 --> + + + +Kennedy Informational [Page 10] + +RFC 3252 Binary Lexical Octet Ad-hoc Transport 1 April 2002 + + + <!ATTLIST timestamp + copied CDATA #FIXED "0" + class CDATA #FIXED "2" + number CDATA #FIXED "4" + length %Digits; #REQUIRED + pointer %Digits; #REQUIRED + oflw %Digits; #REQUIRED + flag (0 | 1 | 3) #REQUIRED> + + <!ELEMENT tstamp EMPTY> + <!ATTLIST tstamp + time %Digits; #REQUIRED + address %IP4Addr; #IMPLIED> + <!-- + padding to bring header to 32-bit boundary. + pad MUST be "0"* + --> + <!ELEMENT padding EMPTY> + <!ATTLIST padding + pad CDATA #REQUIRED> + + <!-- payload MUST be encoded as base-64 [RFC2045], as modified + by section 2.1 of this RFC --> + <!ELEMENT payload (CDATA)> + +7.2. TCPoXML DTD + + <!-- + DTD for TCP over XML. + Refer to this DTD as: + + <!DOCTYPE tcp PUBLIC "-//IETF//DTD BLOAT 1.0 TCP//EN" "bloat.dtd"> + --> + + <!-- the pseudoheader is only included for checksum calculations --> + <!ELEMENT tcp (tcp.pseudoheader?, tcp.header, payload)> + + <!ELEMENT tcp.header (src, dest, sequence, acknowledgement, offset, + reserved, control, window, checksum, urgent, + tcp.options, padding)> + + <!ELEMENT src EMPTY> + <!-- 0 <= port <= 65,535 --> + <!ATTLIST src + port %Digits; #REQUIRED> + + <!ELEMENT dest EMPTY> + <!-- 0 <= port <= 65,535 --> + + + +Kennedy Informational [Page 11] + +RFC 3252 Binary Lexical Octet Ad-hoc Transport 1 April 2002 + + + <!ATTLIST dest + port %Digits; #REQUIRED> + + <!ELEMENT sequence EMPTY> + <!-- 0 <= number <= 4294967295 --> + <!ATTLIST sequence + number %Digits; #REQUIRED> + + <!ELEMENT acknowledgement EMPTY> + <!-- 0 <= number <= 4294967295 --> + <!ATTLIST acknowledgement + number %Digits; #REQUIRED> + + <!ELEMENT offset EMPTY> + <!-- 0 <= number <= 255 --> + <!ATTLIST offset + number %Digits; #REQUIRED> + + <!ELEMENT reserved EMPTY> + <!ATTLIST reserved + value CDATA #FIXED "0"> + + <!ELEMENT control EMPTY> + <!ATTLIST control + urg (0|1) #IMPLIED + ack (0|1) #IMPLIED + psh (0|1) #IMPLIED + rst (0|1) #IMPLIED + syn (0|1) #IMPLIED + fin (0|1) #IMPLIED> + + <!ELEMENT window EMPTY> + <!-- 0 <= size <= 65,535 --> + <!ATTLIST window + size %Digits; #REQUIRED> + + <!-- + checksum as in ip, but with + the following pseudo-header added into the tcp element: + --> + <!ELEMENT tcp.pseudoheader (source, destination, protocol, + tcp.length)> + + <!-- + tcp header + data length in octets. does not include the size of + + the pseudoheader. + --> + + + +Kennedy Informational [Page 12] + +RFC 3252 Binary Lexical Octet Ad-hoc Transport 1 April 2002 + + + <!ELEMENT tcp.length EMPTY> + <!ATTLIST tcp.length + value %Digits; #REQUIRED> + + <!ELEMENT urgent EMPTY> + <!-- 0 <= pointer <= 65,535 --> + <!ATTLIST urgent + pointer %Digits; #REQUIRED> + + <!ELEMENT tcp.options (tcp.end | tcp.noop | tcp.mss)+> + + <!ELEMENT tcp.end EMPTY> + <!ATTLIST tcp.end + kind CDATA #FIXED "0"> + + <!ELEMENT tcp.noop EMPTY> + <!ATTLIST tcp.noop + kind CDATA #FIXED "1"> + + <!ELEMENT tcp.mss EMPTY> + <!ATTLIST tcp.mss + kind CDATA #FIXED "2" + length CDATA #FIXED "4" + size %Digits; #REQUIRED> + +7.3. UDPoXML DTD + + <!-- + DTD for UDP over XML. + Refer to this DTD as: + + <!DOCTYPE udp PUBLIC "-//IETF//DTD BLOAT 1.0 UDP//EN" "bloat.dtd"> + --> + + <!ELEMENT udp (udp.pseudoheader?, udp.header, payload)> + + <!ELEMENT udp.header (src, dest, udp.length, checksum)> + + <!ELEMENT udp.pseudoheader (source, destination, protocol, + udp.length)> + + <!-- + udp header + data length in octets. does not include the size of + the pseudoheader. + --> + <!ELEMENT udp.length EMPTY> + <!ATTLIST udp.length + value %Digits; #REQUIRED> + + + +Kennedy Informational [Page 13] + +RFC 3252 Binary Lexical Octet Ad-hoc Transport 1 April 2002 + + +8. Security Considerations + + XML, as a subset of SGML, has the same security considerations as + specified in SGML Media Types [RFC1874]. Security considerations + that apply to IP, TCP and UDP also likely apply to BLOAT as it does + not attempt to correct for issues not related to message format. + +9. References + + [JABBER] Miller, J., "Jabber", draft-miller-jabber-00.txt, + February 2002. (Work in Progress) + + [RFC768] Postel, J., "User Datagram Protocol", STD 6, RFC 768, + August 1980. + + [RFC791] Postel, J., "Internet Protocol", STD 5, RFC 791, + September 1981. + + [RFC793] Postel, J., "Transmission Control Protocol", STD 7, RFC + 793, September 1981. + + [RFC894] Hornig, C., "Standard for the Transmission of IP + Datagrams over Ethernet Networks.", RFC 894, April 1984. + + [RFC1042] Postel, J. and J. Reynolds, "Standard for the + Transmission of IP Datagrams Over IEEE 802 Networks", STD + 43, RFC 1042, February 1988. + + [RFC1123] Braden, R., "Requirements for Internet Hosts - + Application and Support", RFC 1123, October 1989. + + [RFC1874] Levinson, E., "SGML Media Types", RFC 1874, December + 1995. + + [RFC2003] Perkins, C., "IP Encapsulation within IP", RFC 2003, + October 1996. + + [RFC2045] Freed, N. and N. Borenstein, "Multipurpose Internet Mail + Extensions (MIME) Part One: Format of Internet Message + Bodies", RFC 2045, November 1996. + + [RFC2119] Bradner, S., "Key words for use in RFCs to Indicate + Requirement Levels", BCP 14, RFC 2119, March 1997. + + [RFC2279] Yergeau, F., "UTF-8, a transformation format of ISO + 10646", RFC 2279, January 1998. + + + + + +Kennedy Informational [Page 14] + +RFC 3252 Binary Lexical Octet Ad-hoc Transport 1 April 2002 + + + [RFC2460] Deering, S. and R. Hinden, "Internet Protocol, Version 6 + (IPv6) Specification", RFC 2460, December 1998. + + [RFC3080] Rose, M., "The Blocks Extensible Exchange Protocol Core", + RFC 3080, March 2001. + + [SOAP] Box, D., Ehnebuske, D., Kakivaya, G., Layman, A., + Mendelsohn, N., Nielsen, H. F., Thatte, S. Winer, D., + "Simple Object Access Protocol (SOAP) 1.1" World Wide Web + Consortium Note, May 2000 http://www.w3.org/TR/SOAP/ + + [XML] Bray, T., Paoli, J., Sperberg-McQueen, C. M., "Extensible + Markup Language (XML)" World Wide Web Consortium + Recommendation REC- xml-19980210. + http://www.w3.org/TR/1998/REC-xml-19980210 + +10. Author's Address + + Hugh Kennedy + Mimezine + 1060 West Addison + Chicago, IL 60613 + USA + + EMail: kennedyh@engin.umich.edu + + + + + + + + + + + + + + + + + + + + + + + + + + +Kennedy Informational [Page 15] + +RFC 3252 Binary Lexical Octet Ad-hoc Transport 1 April 2002 + + +11. Full Copyright Statement + + Copyright (C) The Internet Society (2002). All Rights Reserved. + + This document and translations of it may be copied and furnished to + others, and derivative works that comment on or otherwise explain it + or assist in its implementation may be prepared, copied, published + and distributed, in whole or in part, without restriction of any + kind, provided that the above copyright notice and this paragraph are + included on all such copies and derivative works. However, this + document itself may not be modified in any way, such as by removing + the copyright notice or references to the Internet Society or other + Internet organizations, except as needed for the purpose of + developing Internet standards in which case the procedures for + copyrights defined in the Internet Standards process must be + followed, or as required to translate it into languages other than + English. + + The limited permissions granted above are perpetual and will not be + revoked by the Internet Society or its successors or assigns. + + This document and the information contained herein is provided on an + "AS IS" basis and THE INTERNET SOCIETY AND THE INTERNET ENGINEERING + TASK FORCE DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING + BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE INFORMATION + HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED WARRANTIES OF + MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. + +Acknowledgement + + Funding for the RFC Editor function is currently provided by the + Internet Society. + + + + + + + + + + + + + + + + + + + +Kennedy Informational [Page 16] + + + + + + + +Network Working Group H. Kennedy +Request for Comments: 3252 Mimezine +Category: Informational 1 April 2002 + + + Binary Lexical Octet Ad-hoc Transport + +Status of this Memo + + This memo provides information for the Internet community. It does + not specify an Internet standard of any kind. Distribution of this + memo is unlimited. + +Copyright Notice + + Copyright (C) The Internet Society (2002). All Rights Reserved. + +Abstract + + This document defines a reformulation of IP and two transport layer + protocols (TCP and UDP) as XML applications. + +1. Introduction + +1.1. Overview + + This document describes the Binary Lexical Octet Ad-hoc Transport + (BLOAT): a reformulation of a widely-deployed network-layer protocol + (IP [RFC791]), and two associated transport layer protocols (TCP + [RFC793] and UDP [RFC768]) as XML [XML] applications. It also + describes methods for transporting BLOAT over Ethernet and IEEE 802 + networks as well as encapsulating BLOAT in IP for gatewaying BLOAT + across the public Internet. + +1.2. Motivation + + The wild popularity of XML as a basis for application-level protocols + such as the Blocks Extensible Exchange Protocol [RFC3080], the Simple + Object Access Protocol [SOAP], and Jabber [JABBER] prompted + investigation into the possibility of extending the use of XML in the + protocol stack. Using XML at both the transport and network layer in + addition to the application layer would provide for an amazing amount + of power and flexibility while removing dependencies on proprietary + and hard-to-understand binary protocols. This protocol unification + would also allow applications to use a single XML parser for all + aspects of their operation, eliminating developer time spent figuring + out the intricacies of each new protocol, and moving the hard work of + + + + +Kennedy Informational [Page 1] + +RFC 3252 Binary Lexical Octet Ad-hoc Transport 1 April 2002 + + + parsing to the XML toolset. The use of XML also mitigates concerns + over "network vs. host" byte ordering which is at the root of many + network application bugs. + +1.3. Relation to Existing Protocols + + The reformulations specified in this RFC follow as closely as + possible the spirit of the RFCs on which they are based, and so MAY + contain elements or attributes that would not be needed in a pure + reworking (e.g. length attributes, which are implicit in XML.) + + The layering of network and transport protocols are maintained in + this RFC despite the optimizations that could be made if the line + were somewhat blurred (i.e. merging TCP and IP into a single, larger + element in the DTD) in order to foster future use of this protocol as + a basis for reformulating other protocols (such as ICMP.) + + Other than the encoding, the behavioral aspects of each of the + existing protocols remain unchanged. Routing, address spaces, TCP + congestion control, etc. behave as specified in the extant standards. + Adapting to new standards and experimental algorithm heuristics for + improving performance will become much easier once the move to BLOAT + has been completed. + +1.4. Requirement Levels + + The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", + "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this + document are to be interpreted as described in BCP 14, RFC 2119 + [RFC2119]. + +2. IPoXML + + This protocol MUST be implemented to be compliant with this RFC. + IPoXML is the root protocol REQUIRED for effective use of TCPoXML + (section 3.) and higher-level application protocols. + + The DTD for this document type can be found in section 7.1. + + The routing of IPoXML can be easily implemented on hosts with an XML + parser, as the regular structure lends itself handily to parsing and + validation of the document/datagram and then processing the + destination address, TTL, and checksum before sending it on to its + next-hop. + + The reformulation of IPv4 was chosen over IPv6 [RFC2460] due to the + wider deployment of IPv4 and the fact that implementing IPv6 as XML + would have exceeded the 1500 byte Ethernet MTU. + + + +Kennedy Informational [Page 2] + +RFC 3252 Binary Lexical Octet Ad-hoc Transport 1 April 2002 + + + All BLOAT implementations MUST use - and specify - the UTF-8 encoding + of RFC 2279 [RFC2279]. All BLOAT document/datagrams MUST be well- + formed and include the XMLDecl. + +2.1. IP Description + + A number of items have changed (for the better) from the original IP + specification. Bit-masks, where present have been converted into + human-readable values. IP addresses are listed in their dotted- + decimal notation [RFC1123]. Length and checksum values are present + as decimal integers. + + To calculate the length and checksum fields of the IP element, a + canonicalized form of the element MUST be used. The canonical form + SHALL have no whitespace (including newline characters) between + elements and only one space character between attributes. There + SHALL NOT be a space following the last attribute in an element. + + An iterative method SHOULD be used to calculate checksums, as the + length field will vary based on the size of the checksum. + + The payload element bears special attention. Due to the character + set restrictions of XML, the payload of IP datagrams (which MAY + contain arbitrary data) MUST be encoded for transport. This RFC + REQUIRES the contents of the payload to be encoded in the base-64 + encoding of RFC 2045 [RFC2045], but removes the requirement that the + encoded output MUST be wrapped on 76-character lines. + + + + + + + + + + + + + + + + + + + + + + + + +Kennedy Informational [Page 3] + +RFC 3252 Binary Lexical Octet Ad-hoc Transport 1 April 2002 + + +2.2. Example Datagram + + The following is an example IPoXML datagram with an empty payload: + + <?xml version="1.0" encoding="UTF-8"?> + <!DOCTYPE ip PUBLIC "-//IETF//DTD BLOAT 1.0 IP//EN" "bloat.dtd"> + <ip> + <header length="474"> + <version value="4"/> + <tos precedence="Routine" delay="Normal" throughput="Normal" + relibility="Normal" reserved="0"/> + <total.length value="461"/> + <id value="1"/> + <flags reserved="0" df="dont" mf="last"/> + <offset value="0"/> + <ttl value="255"/> + <protocol value="6"/> + <checksum value="8707"/> + <source address="10.0.0.22"/> + <destination address="10.0.0.1"/> + <options> + <end copied="0" class="0" number="0"/> + </options> + <padding pad="0"/> + </header> + <payload> + </payload> + </ip> + +3. TCPoXML + + This protocol MUST be implemented to be compliant with this RFC. The + DTD for this document type can be found in section 7.2. + +3.1. TCP Description + + A number of items have changed from the original TCP specification. + Bit-masks, where present have been converted into human-readable + values. Length and checksum and port values are present as decimal + integers. + + To calculate the length and checksum fields of the TCP element, a + canonicalized form of the element MUST be used as in section 2.1. + + An iterative method SHOULD be used to calculate checksums as in + section 2.1. + + The payload element MUST be encoded as in section 2.1. + + + +Kennedy Informational [Page 4] + +RFC 3252 Binary Lexical Octet Ad-hoc Transport 1 April 2002 + + + The TCP offset element was expanded to a maximum of 255 from 16 to + allow for the increased size of the header in XML. + + TCPoXML datagrams encapsulated by IPoXML MAY omit the <?xml?> header + as well as the <!DOCTYPE> declaration. + +3.2. Example Datagram + + The following is an example TCPoXML datagram with an empty payload: + + <?xml version="1.0" encoding="UTF-8"?> + <!DOCTYPE tcp PUBLIC "-//IETF//DTD BLOAT 1.0 TCP//EN" "bloat.dtd"> + <tcp> + <tcp.header> + <src port="31415"/> + <dest port="42424"/> + <sequence number="322622954"/> + <acknowledgement number="689715995"/> + <offset number=""/> + <reserved value="0"/> + <control syn="1" ack="1"/> + <window size="1"/> + <urgent pointer="0"/> + <checksum value="2988"/> + <tcp.options> + <tcp.end kind="0"/> + </tcp.options> + <padding pad="0"/> + </tcp.header> + <payload> + </payload> + </tcp> + +4. UDPoXML + + This protocol MUST be implemented to be compliant with this RFC. The + DTD for this document type can be found in section 7.3. + +4.1. UDP Description + + A number of items have changed from the original UDP specification. + Bit-masks, where present have been converted into human-readable + values. Length and checksum and port values are present as decimal + integers. + + + + + + + +Kennedy Informational [Page 5] + +RFC 3252 Binary Lexical Octet Ad-hoc Transport 1 April 2002 + + + To calculate the length and checksum fields of the UDP element, a + canonicalized form of the element MUST be used as in section 2.1. An + iterative method SHOULD be used to calculate checksums as in section + 2.1. + + The payload element MUST be encoded as in section 2.1. + + UDPoXML datagrams encapsulated by IPoXML MAY omit the <?xml?> header + as well as the <!DOCTYPE> declaration. + +4.2. Example Datagram + + The following is an example UDPoXML datagram with an empty payload: + + <?xml version="1.0" encoding="UTF-8"?> + <!DOCTYPE udp PUBLIC "-//IETF//DTD BLOAT 1.0 UDP//EN" "bloat.dtd"> + <udp> + <udp.header> + <src port="31415"/> + <dest port="42424"/> + <udp.length value="143"/> + <checksum value="2988"/> + </udp.header> + <payload> + </payload> + </udp> + +5. Network Transport + + This document provides for the transmission of BLOAT datagrams over + two common families of physical layer transport. Future RFCs will + address additional transports as routing vendors catch up to the + specification, and we begin to see BLOAT routed across the Internet + backbone. + +5.1. Ethernet + + BLOAT is encapsulated in Ethernet datagrams as in [RFC894] with the + exception that the type field of the Ethernet frame MUST contain the + value 0xBEEF. The first 5 octets of the Ethernet frame payload will + be 0x3c 3f 78 6d 6c ("<?xml".) + +5.2. IEEE 802 + + BLOAT is encapsulated in IEEE 802 Networks as in [RFC1042] except + that the protocol type code for IPoXML is 0xBEEF. + + + + + +Kennedy Informational [Page 6] + +RFC 3252 Binary Lexical Octet Ad-hoc Transport 1 April 2002 + + +6. Gatewaying over IP + + In order to facilitate the gradual introduction of BLOAT into the + public Internet, BLOAT MAY be encapsulated in IP as in [RFC2003] to + gateway between networks that run BLOAT natively on their LANs. + +7. DTDs + + The Transport DTDs (7.2. and 7.3.) build on the definitions in the + Network DTD (7.1.) + + The DTDs are referenced by their PubidLiteral and SystemLiteral (from + [XML]) although it is understood that most IPoXML implementations + will not need to pull down the DTD, as it will normally be embedded + in the implementation, and presents something of a catch-22 if you + need to load part of your network protocol over the network. + +7.1. IPoXML DTD + + <!-- + DTD for IP over XML. + Refer to this DTD as: + + <!DOCTYPE ip PUBLIC "-//IETF//DTD BLOAT 1.0 IP//EN" "bloat.dtd"> + --> + <!-- + DTD data types: + + Digits [0..9]+ + + Precedence "NetworkControl | InternetworkControl | + CRITIC | FlashOverride | Flash | Immediate | + Priority | Routine" + + IP4Addr "dotted-decimal" notation of [RFC1123] + + Class [0..3] + + Sec "Unclassified | Confidential | EFTO | MMMM | PROG | + Restricted | Secret | Top Secret | Reserved" + + Compartments [0..65535] + + Handling [0..65535] + + TCC [0..16777216] + + --> + + + +Kennedy Informational [Page 7] + +RFC 3252 Binary Lexical Octet Ad-hoc Transport 1 April 2002 + + + <!ENTITY % Digits "CDATA"> + <!ENTITY % Precedence "CDATA"> + <!ENTITY % IP4Addr "CDATA"> + <!ENTITY % Class "CDATA"> + <!ENTITY % Sec "CDATA"> + <!ENTITY % Compartments "CDATA"> + <!ENTITY % Handling "CDATA"> + <!ENTITY % TCC "CDATA"> + + <!ELEMENT ip (header, payload)> + + <!ELEMENT header (version, tos, total.length, id, flags, offset, ttl, + protocol, checksum, source, destination, options, + padding)> + <!-- length of header in 32-bit words --> + <!ATTLIST header + length %Digits; #REQUIRED> + + <!ELEMENT version EMPTY> + <!-- ip version. SHOULD be "4" --> + <!ATTLIST version + value %Digits; #REQUIRED> + + <!ELEMENT tos EMPTY> + <!ATTLIST tos + precedence %Precedence; #REQUIRED + delay (normal | low) #REQUIRED + throughput (normal | high) #REQUIRED + relibility (normal | high) #REQUIRED + reserved CDATA #FIXED "0"> + + <!ELEMENT total.length EMPTY> + <!-- + total length of datagram (header and payload) in octets, MUST be + less than 65,535 (and SHOULD be less than 1024 for IPoXML on local + ethernets). + --> + <!ATTLIST total.length + value %Digits; #REQUIRED> + + <!ELEMENT id EMPTY> + <!-- 0 <= id <= 65,535 --> + <!ATTLIST id + value %Digits; #REQUIRED> + + <!ELEMENT flags EMPTY> + <!-- df = don't fragment, mf = more fragments --> + <!ATTLIST flags + + + +Kennedy Informational [Page 8] + +RFC 3252 Binary Lexical Octet Ad-hoc Transport 1 April 2002 + + + reserved CDATA #FIXED "0" + df (may|dont) #REQUIRED + mf (last|more) #REQUIRED> + + <!ELEMENT offset EMPTY> + <!-- 0 <= offset <= 8192 measured in 8 octet (64-bit) chunks --> + <!ATTLIST offset + value %Digits; #REQUIRED> + + <!ELEMENT ttl EMPTY> + <!-- 0 <= ttl <= 255 --> + <!ATTLIST ttl + value %Digits; #REQUIRED> + + <!ELEMENT protocol EMPTY> + <!-- 0 <= protocol <= 255 (per IANA) --> + <!ATTLIST protocol + value %Digits; #REQUIRED> + + <!ELEMENT checksum EMPTY> + <!-- 0 <= checksum <= 65535 (over header only) --> + <!ATTLIST checksum + value %Digits; #REQUIRED> + + <!ELEMENT source EMPTY> + <!ATTLIST source + address %IP4Addr; #REQUIRED> + + <!ELEMENT destination EMPTY> + <!ATTLIST destination + address %IP4Addr; #REQUIRED> + + <!ELEMENT options ( end | noop | security | loose | strict | record + | stream | timestamp )*> + + <!ELEMENT end EMPTY> + <!ATTLIST end + copied (0|1) #REQUIRED + class CDATA #FIXED "0" + number CDATA #FIXED "0"> + + <!ELEMENT noop EMPTY> + <!ATTLIST noop + copied (0|1) #REQUIRED + class CDATA #FIXED "0" + number CDATA #FIXED "1"> + + <!ELEMENT security EMPTY> + + + +Kennedy Informational [Page 9] + +RFC 3252 Binary Lexical Octet Ad-hoc Transport 1 April 2002 + + + <!ATTLIST security + copied CDATA #FIXED "1" + class CDATA #FIXED "0" + number CDATA #FIXED "2" + length CDATA #FIXED "11" + security %Sec; #REQUIRED + compartments %Compartments; #REQUIRED + handling %Handling; #REQUIRED + tcc %TCC; #REQUIRED> + <!ELEMENT loose (hop)+> + <!ATTLIST loose + copied CDATA #FIXED "1" + class CDATA #FIXED "0" + number CDATA #FIXED "3" + length %Digits; #REQUIRED + pointer %Digits; #REQUIRED> + + <!ELEMENT hop EMPTY> + <!ATTLIST hop + address %IP4Addr; #REQUIRED> + + <!ELEMENT strict (hop)+> + <!ATTLIST strict + copied CDATA #FIXED "1" + class CDATA #FIXED "0" + number CDATA #FIXED "9" + length %Digits; #REQUIRED + pointer %Digits; #REQUIRED> + + <!ELEMENT record (hop)+> + <!ATTLIST record + copied CDATA #FIXED "0" + class CDATA #FIXED "0" + number CDATA #FIXED "7" + length %Digits; #REQUIRED + pointer %Digits; #REQUIRED> + + <!ELEMENT stream EMPTY> + <!-- 0 <= id <= 65,535 --> + <!ATTLIST stream + copied CDATA #FIXED "1" + class CDATA #FIXED "0" + number CDATA #FIXED "8" + length CDATA #FIXED "4" + id %Digits; #REQUIRED> + + <!ELEMENT timestamp (tstamp)+> + <!-- 0 <= oflw <=15 --> + + + +Kennedy Informational [Page 10] + +RFC 3252 Binary Lexical Octet Ad-hoc Transport 1 April 2002 + + + <!ATTLIST timestamp + copied CDATA #FIXED "0" + class CDATA #FIXED "2" + number CDATA #FIXED "4" + length %Digits; #REQUIRED + pointer %Digits; #REQUIRED + oflw %Digits; #REQUIRED + flag (0 | 1 | 3) #REQUIRED> + + <!ELEMENT tstamp EMPTY> + <!ATTLIST tstamp + time %Digits; #REQUIRED + address %IP4Addr; #IMPLIED> + <!-- + padding to bring header to 32-bit boundary. + pad MUST be "0"* + --> + <!ELEMENT padding EMPTY> + <!ATTLIST padding + pad CDATA #REQUIRED> + + <!-- payload MUST be encoded as base-64 [RFC2045], as modified + by section 2.1 of this RFC --> + <!ELEMENT payload (CDATA)> + +7.2. TCPoXML DTD + + <!-- + DTD for TCP over XML. + Refer to this DTD as: + + <!DOCTYPE tcp PUBLIC "-//IETF//DTD BLOAT 1.0 TCP//EN" "bloat.dtd"> + --> + + <!-- the pseudoheader is only included for checksum calculations --> + <!ELEMENT tcp (tcp.pseudoheader?, tcp.header, payload)> + + <!ELEMENT tcp.header (src, dest, sequence, acknowledgement, offset, + reserved, control, window, checksum, urgent, + tcp.options, padding)> + + <!ELEMENT src EMPTY> + <!-- 0 <= port <= 65,535 --> + <!ATTLIST src + port %Digits; #REQUIRED> + + <!ELEMENT dest EMPTY> + <!-- 0 <= port <= 65,535 --> + + + +Kennedy Informational [Page 11] + +RFC 3252 Binary Lexical Octet Ad-hoc Transport 1 April 2002 + + + <!ATTLIST dest + port %Digits; #REQUIRED> + + <!ELEMENT sequence EMPTY> + <!-- 0 <= number <= 4294967295 --> + <!ATTLIST sequence + number %Digits; #REQUIRED> + + <!ELEMENT acknowledgement EMPTY> + <!-- 0 <= number <= 4294967295 --> + <!ATTLIST acknowledgement + number %Digits; #REQUIRED> + + <!ELEMENT offset EMPTY> + <!-- 0 <= number <= 255 --> + <!ATTLIST offset + number %Digits; #REQUIRED> + + <!ELEMENT reserved EMPTY> + <!ATTLIST reserved + value CDATA #FIXED "0"> + + <!ELEMENT control EMPTY> + <!ATTLIST control + urg (0|1) #IMPLIED + ack (0|1) #IMPLIED + psh (0|1) #IMPLIED + rst (0|1) #IMPLIED + syn (0|1) #IMPLIED + fin (0|1) #IMPLIED> + + <!ELEMENT window EMPTY> + <!-- 0 <= size <= 65,535 --> + <!ATTLIST window + size %Digits; #REQUIRED> + + <!-- + checksum as in ip, but with + the following pseudo-header added into the tcp element: + --> + <!ELEMENT tcp.pseudoheader (source, destination, protocol, + tcp.length)> + + <!-- + tcp header + data length in octets. does not include the size of + + the pseudoheader. + --> + + + +Kennedy Informational [Page 12] + +RFC 3252 Binary Lexical Octet Ad-hoc Transport 1 April 2002 + + + <!ELEMENT tcp.length EMPTY> + <!ATTLIST tcp.length + value %Digits; #REQUIRED> + + <!ELEMENT urgent EMPTY> + <!-- 0 <= pointer <= 65,535 --> + <!ATTLIST urgent + pointer %Digits; #REQUIRED> + + <!ELEMENT tcp.options (tcp.end | tcp.noop | tcp.mss)+> + + <!ELEMENT tcp.end EMPTY> + <!ATTLIST tcp.end + kind CDATA #FIXED "0"> + + <!ELEMENT tcp.noop EMPTY> + <!ATTLIST tcp.noop + kind CDATA #FIXED "1"> + + <!ELEMENT tcp.mss EMPTY> + <!ATTLIST tcp.mss + kind CDATA #FIXED "2" + length CDATA #FIXED "4" + size %Digits; #REQUIRED> + +7.3. UDPoXML DTD + + <!-- + DTD for UDP over XML. + Refer to this DTD as: + + <!DOCTYPE udp PUBLIC "-//IETF//DTD BLOAT 1.0 UDP//EN" "bloat.dtd"> + --> + + <!ELEMENT udp (udp.pseudoheader?, udp.header, payload)> + + <!ELEMENT udp.header (src, dest, udp.length, checksum)> + + <!ELEMENT udp.pseudoheader (source, destination, protocol, + udp.length)> + + <!-- + udp header + data length in octets. does not include the size of + the pseudoheader. + --> + <!ELEMENT udp.length EMPTY> + <!ATTLIST udp.length + value %Digits; #REQUIRED> + + + +Kennedy Informational [Page 13] + +RFC 3252 Binary Lexical Octet Ad-hoc Transport 1 April 2002 + + +8. Security Considerations + + XML, as a subset of SGML, has the same security considerations as + specified in SGML Media Types [RFC1874]. Security considerations + that apply to IP, TCP and UDP also likely apply to BLOAT as it does + not attempt to correct for issues not related to message format. + +9. References + + [JABBER] Miller, J., "Jabber", draft-miller-jabber-00.txt, + February 2002. (Work in Progress) + + [RFC768] Postel, J., "User Datagram Protocol", STD 6, RFC 768, + August 1980. + + [RFC791] Postel, J., "Internet Protocol", STD 5, RFC 791, + September 1981. + + [RFC793] Postel, J., "Transmission Control Protocol", STD 7, RFC + 793, September 1981. + + [RFC894] Hornig, C., "Standard for the Transmission of IP + Datagrams over Ethernet Networks.", RFC 894, April 1984. + + [RFC1042] Postel, J. and J. Reynolds, "Standard for the + Transmission of IP Datagrams Over IEEE 802 Networks", STD + 43, RFC 1042, February 1988. + + [RFC1123] Braden, R., "Requirements for Internet Hosts - + Application and Support", RFC 1123, October 1989. + + [RFC1874] Levinson, E., "SGML Media Types", RFC 1874, December + 1995. + + [RFC2003] Perkins, C., "IP Encapsulation within IP", RFC 2003, + October 1996. + + [RFC2045] Freed, N. and N. Borenstein, "Multipurpose Internet Mail + Extensions (MIME) Part One: Format of Internet Message + Bodies", RFC 2045, November 1996. + + [RFC2119] Bradner, S., "Key words for use in RFCs to Indicate + Requirement Levels", BCP 14, RFC 2119, March 1997. + + [RFC2279] Yergeau, F., "UTF-8, a transformation format of ISO + 10646", RFC 2279, January 1998. + + + + + +Kennedy Informational [Page 14] + +RFC 3252 Binary Lexical Octet Ad-hoc Transport 1 April 2002 + + + [RFC2460] Deering, S. and R. Hinden, "Internet Protocol, Version 6 + (IPv6) Specification", RFC 2460, December 1998. + + [RFC3080] Rose, M., "The Blocks Extensible Exchange Protocol Core", + RFC 3080, March 2001. + + [SOAP] Box, D., Ehnebuske, D., Kakivaya, G., Layman, A., + Mendelsohn, N., Nielsen, H. F., Thatte, S. Winer, D., + "Simple Object Access Protocol (SOAP) 1.1" World Wide Web + Consortium Note, May 2000 http://www.w3.org/TR/SOAP/ + + [XML] Bray, T., Paoli, J., Sperberg-McQueen, C. M., "Extensible + Markup Language (XML)" World Wide Web Consortium + Recommendation REC- xml-19980210. + http://www.w3.org/TR/1998/REC-xml-19980210 + +10. Author's Address + + Hugh Kennedy + Mimezine + 1060 West Addison + Chicago, IL 60613 + USA + + EMail: kennedyh@engin.umich.edu + + + + + + + + + + + + + + + + + + + + + + + + + + +Kennedy Informational [Page 15] + +RFC 3252 Binary Lexical Octet Ad-hoc Transport 1 April 2002 + + +11. Full Copyright Statement + + Copyright (C) The Internet Society (2002). All Rights Reserved. + + This document and translations of it may be copied and furnished to + others, and derivative works that comment on or otherwise explain it + or assist in its implementation may be prepared, copied, published + and distributed, in whole or in part, without restriction of any + kind, provided that the above copyright notice and this paragraph are + included on all such copies and derivative works. However, this + document itself may not be modified in any way, such as by removing + the copyright notice or references to the Internet Society or other + Internet organizations, except as needed for the purpose of + developing Internet standards in which case the procedures for + copyrights defined in the Internet Standards process must be + followed, or as required to translate it into languages other than + English. + + The limited permissions granted above are perpetual and will not be + revoked by the Internet Society or its successors or assigns. + + This document and the information contained herein is provided on an + "AS IS" basis and THE INTERNET SOCIETY AND THE INTERNET ENGINEERING + TASK FORCE DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING + BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE INFORMATION + HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED WARRANTIES OF + MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. + +Acknowledgement + + Funding for the RFC Editor function is currently provided by the + Internet Society. + + + + + + + + + + + + + + + + + + + +Kennedy Informational [Page 16] + diff --git a/tests/auto/network/access/qnetworkreply/certs/aspiriniks.ca.crt b/tests/auto/network/access/qnetworkreply/certs/aspiriniks.ca.crt new file mode 100644 index 0000000000..36436b6248 --- /dev/null +++ b/tests/auto/network/access/qnetworkreply/certs/aspiriniks.ca.crt @@ -0,0 +1,22 @@ +-----BEGIN CERTIFICATE----- +MIIDnDCCAoQCCQDV3otC4hs2KTANBgkqhkiG9w0BAQUFADCBjzELMAkGA1UEBhMC +Tk8xDTALBgNVBAgTBE9zbG8xDTALBgNVBAcTBE9zbG8xDzANBgNVBAoTBlRUIEFT +QTEOMAwGA1UECxMFUVQgU1cxHDAaBgNVBAMTE2FzcGlyaW5pa3MudHJvbGwubm8x +IzAhBgkqhkiG9w0BCQEWFGFiYWJpY0B0cm9sbHRlY2guY29tMB4XDTA4MTEwMTA4 +NTcyOFoXDTA5MTEwMTA4NTcyOFowgY8xCzAJBgNVBAYTAk5PMQ0wCwYDVQQIEwRP +c2xvMQ0wCwYDVQQHEwRPc2xvMQ8wDQYDVQQKEwZUVCBBU0ExDjAMBgNVBAsTBVFU +IFNXMRwwGgYDVQQDExNhc3BpcmluaWtzLnRyb2xsLm5vMSMwIQYJKoZIhvcNAQkB +FhRhYmFiaWNAdHJvbGx0ZWNoLmNvbTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCC +AQoCggEBAMV2bMD1DN3DMgbxU3DXw2i7EWGDXcWjTDtdHvqgIb+9nHqo3MJSrzJy +qgEPoOsXqswMla9wDPZAsWv5gVAmVSqpy2lfEgfY7LaSHiGD75seF7zIy+CxREHW +DofHXpJGGJpBCZEKQt2HfHu3+yAYNPucN78tWNZAcPbUg5tfxMZeepRimAZNIxBI +93SDrl/f9Ka7hvPSzUQsnp8hfdpHlFPFznKfD6yPrjxgz2mT9efavJ4DhtyIa4m+ +paiX515CidDz4A8CFxKZbYvuqq1ilibF/si2so9VhALC77ZcAJP1IMuT8T+WUCxq +skJqiSCncl0Hgr+ba8MDGF9UQYowgjMCAwEAATANBgkqhkiG9w0BAQUFAAOCAQEA +KcJuNUHvjB8ok3cnTmQEeF0LPPkgj28Tqb5TFB8xpVfRI+wvTYsHsmGdOKCgYJ3a +7VflIsr63ojG8/rXK8H/cx2o2f2Hr3liJdi1UnoLDDRjBqGGz7JNuMreYokPvIbm +eP01mVyK4PO2iYRwHUIAw5eeB1vMWKX2z95MupD+HRLtmGyaLALg8aQxj5N84Ewl +eU2PQfhv8A1wj7aL17kfEUxDerQ1kUzlThJMV1J8Dl0l4C9N8evQkelROJU00i46 +oJikA8BW6EpgbnGyNyyj5Loy4wLPKew9nTS8MCJ5xPMQc0urbY/VzuOeUK7WQof7 +xOFSsRAVyQv+yqgmcZMCtg== +-----END CERTIFICATE----- diff --git a/tests/auto/network/access/qnetworkreply/certs/fluke.cert b/tests/auto/network/access/qnetworkreply/certs/fluke.cert new file mode 100644 index 0000000000..069fa6b341 --- /dev/null +++ b/tests/auto/network/access/qnetworkreply/certs/fluke.cert @@ -0,0 +1,75 @@ +Certificate: + Data: + Version: 3 (0x2) + Serial Number: 0 (0x0) + Signature Algorithm: sha1WithRSAEncryption + Issuer: C=NO, ST=Oslo, L=Nydalen, O=Nokia Corporation and/or its subsidiary(-ies), OU=Development, CN=fluke.troll.no/emailAddress=ahanssen@trolltech.com + Validity + Not Before: Dec 4 01:10:32 2007 GMT + Not After : Apr 21 01:10:32 2035 GMT + Subject: C=NO, ST=Oslo, O=Nokia Corporation and/or its subsidiary(-ies), OU=Development, CN=fluke.troll.no + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + RSA Public Key: (1024 bit) + Modulus (1024 bit): + 00:a7:c8:a0:4a:c4:19:05:1b:66:ba:32:e2:d2:f1: + 1c:6f:17:82:e4:39:2e:01:51:90:db:04:34:32:11: + 21:c2:0d:6f:59:d8:53:90:54:3f:83:8f:a9:d3:b3: + d5:ee:1a:9b:80:ae:c3:25:c9:5e:a5:af:4b:60:05: + aa:a0:d1:91:01:1f:ca:04:83:e3:58:1c:99:32:45: + 84:70:72:58:03:98:4a:63:8b:41:f5:08:49:d2:91: + 02:60:6b:e4:64:fe:dd:a0:aa:74:08:e9:34:4c:91: + 5f:12:3d:37:4d:54:2c:ad:7f:5b:98:60:36:02:8c: + 3b:f6:45:f3:27:6a:9b:94:9d + Exponent: 65537 (0x10001) + X509v3 extensions: + X509v3 Basic Constraints: + CA:FALSE + Netscape Comment: + OpenSSL Generated Certificate + X509v3 Subject Key Identifier: + 21:85:04:3D:23:01:66:E5:F7:9F:1A:84:24:8A:AF:0A:79:F4:E5:AC + X509v3 Authority Key Identifier: + DirName:/C=NO/ST=Oslo/L=Nydalen/O=Nokia Corporation and/or its subsidiary(-ies)/OU=Development/CN=fluke.troll.no/emailAddress=ahanssen@trolltech.com + serial:8E:A8:B4:E8:91:B7:54:2E + + Signature Algorithm: sha1WithRSAEncryption + 6d:57:5f:d1:05:43:f0:62:05:ec:2a:71:a5:dc:19:08:f2:c4: + a6:bd:bb:25:d9:ca:89:01:0e:e4:cf:1f:c1:8c:c8:24:18:35: + 53:59:7b:c0:43:b4:32:e6:98:b2:a6:ef:15:05:0b:48:5f:e1: + a0:0c:97:a9:a1:77:d8:35:18:30:bc:a9:8f:d3:b7:54:c7:f1: + a9:9e:5d:e6:19:bf:f6:3c:5b:2b:d8:e4:3e:62:18:88:8b:d3: + 24:e1:40:9b:0c:e6:29:16:62:ab:ea:05:24:70:36:aa:55:93: + ef:02:81:1b:23:10:a2:04:eb:56:95:75:fc:f8:94:b1:5d:42: + c5:3f:36:44:85:5d:3a:2e:90:46:8a:a2:b9:6f:87:ae:0c:15: + 40:19:31:90:fc:3b:25:bb:ae:f1:66:13:0d:85:90:d9:49:34: + 8f:f2:5d:f9:7a:db:4d:5d:27:f6:76:9d:35:8c:06:a6:4c:a3: + b1:b2:b6:6f:1d:d7:a3:00:fd:72:eb:9e:ea:44:a1:af:21:34: + 7d:c7:42:e2:49:91:19:8b:c0:ad:ba:82:80:a8:71:70:f4:35: + 31:91:63:84:20:95:e9:60:af:64:8b:cc:ff:3d:8a:76:74:3d: + c8:55:6d:e4:8e:c3:2b:1c:e8:42:18:ae:9f:e6:6b:9c:34:06: + ec:6a:f2:c3 +-----BEGIN CERTIFICATE----- +MIIEEzCCAvugAwIBAgIBADANBgkqhkiG9w0BAQUFADCBnDELMAkGA1UEBhMCTk8x +DTALBgNVBAgTBE9zbG8xEDAOBgNVBAcTB055ZGFsZW4xFjAUBgNVBAoTDVRyb2xs +dGVjaCBBU0ExFDASBgNVBAsTC0RldmVsb3BtZW50MRcwFQYDVQQDEw5mbHVrZS50 +cm9sbC5ubzElMCMGCSqGSIb3DQEJARYWYWhhbnNzZW5AdHJvbGx0ZWNoLmNvbTAe +Fw0wNzEyMDQwMTEwMzJaFw0zNTA0MjEwMTEwMzJaMGMxCzAJBgNVBAYTAk5PMQ0w +CwYDVQQIEwRPc2xvMRYwFAYDVQQKEw1Ucm9sbHRlY2ggQVNBMRQwEgYDVQQLEwtE +ZXZlbG9wbWVudDEXMBUGA1UEAxMOZmx1a2UudHJvbGwubm8wgZ8wDQYJKoZIhvcN +AQEBBQADgY0AMIGJAoGBAKfIoErEGQUbZroy4tLxHG8XguQ5LgFRkNsENDIRIcIN +b1nYU5BUP4OPqdOz1e4am4CuwyXJXqWvS2AFqqDRkQEfygSD41gcmTJFhHByWAOY +SmOLQfUISdKRAmBr5GT+3aCqdAjpNEyRXxI9N01ULK1/W5hgNgKMO/ZF8ydqm5Sd +AgMBAAGjggEaMIIBFjAJBgNVHRMEAjAAMCwGCWCGSAGG+EIBDQQfFh1PcGVuU1NM +IEdlbmVyYXRlZCBDZXJ0aWZpY2F0ZTAdBgNVHQ4EFgQUIYUEPSMBZuX3nxqEJIqv +Cnn05awwgbsGA1UdIwSBszCBsKGBoqSBnzCBnDELMAkGA1UEBhMCTk8xDTALBgNV +BAgTBE9zbG8xEDAOBgNVBAcTB055ZGFsZW4xFjAUBgNVBAoTDVRyb2xsdGVjaCBB +U0ExFDASBgNVBAsTC0RldmVsb3BtZW50MRcwFQYDVQQDEw5mbHVrZS50cm9sbC5u +bzElMCMGCSqGSIb3DQEJARYWYWhhbnNzZW5AdHJvbGx0ZWNoLmNvbYIJAI6otOiR +t1QuMA0GCSqGSIb3DQEBBQUAA4IBAQBtV1/RBUPwYgXsKnGl3BkI8sSmvbsl2cqJ +AQ7kzx/BjMgkGDVTWXvAQ7Qy5piypu8VBQtIX+GgDJepoXfYNRgwvKmP07dUx/Gp +nl3mGb/2PFsr2OQ+YhiIi9Mk4UCbDOYpFmKr6gUkcDaqVZPvAoEbIxCiBOtWlXX8 ++JSxXULFPzZEhV06LpBGiqK5b4euDBVAGTGQ/Dslu67xZhMNhZDZSTSP8l35ettN +XSf2dp01jAamTKOxsrZvHdejAP1y657qRKGvITR9x0LiSZEZi8CtuoKAqHFw9DUx +kWOEIJXpYK9ki8z/PYp2dD3IVW3kjsMrHOhCGK6f5mucNAbsavLD +-----END CERTIFICATE----- diff --git a/tests/auto/network/access/qnetworkreply/certs/fluke.key b/tests/auto/network/access/qnetworkreply/certs/fluke.key new file mode 100644 index 0000000000..9d1664d609 --- /dev/null +++ b/tests/auto/network/access/qnetworkreply/certs/fluke.key @@ -0,0 +1,15 @@ +-----BEGIN RSA PRIVATE KEY----- +MIICXAIBAAKBgQCnyKBKxBkFG2a6MuLS8RxvF4LkOS4BUZDbBDQyESHCDW9Z2FOQ +VD+Dj6nTs9XuGpuArsMlyV6lr0tgBaqg0ZEBH8oEg+NYHJkyRYRwclgDmEpji0H1 +CEnSkQJga+Rk/t2gqnQI6TRMkV8SPTdNVCytf1uYYDYCjDv2RfMnapuUnQIDAQAB +AoGANFzLkanTeSGNFM0uttBipFT9F4a00dqHz6JnO7zXAT26I5r8sU1pqQBb6uLz +/+Qz5Zwk8RUAQcsMRgJetuPQUb0JZjF6Duv24hNazqXBCu7AZzUenjafwmKC/8ri +KpX3fTwqzfzi//FKGgbXQ80yykSSliDL3kn/drATxsLCgQECQQDXhEFWLJ0vVZ1s +1Ekf+3NITE+DR16X+LQ4W6vyEHAjTbaNWtcTKdAWLA2l6N4WAAPYSi6awm+zMxx4 +VomVTsjdAkEAx0z+e7natLeFcrrq8pbU+wa6SAP1VfhQWKitxL1e7u/QO90NCpxE +oQYKzMkmmpOOFjQwEMAy1dvFMbm4LHlewQJAC/ksDBaUcQHHqjktCtrUb8rVjAyW +A8lscckeB2fEYyG5J6dJVaY4ClNOOs5yMDS2Afk1F6H/xKvtQ/5CzInA/QJATDub +K+BPU8jO9q+gpuIi3VIZdupssVGmCgObVCHLakG4uO04y9IyPhV9lA9tALtoIf4c +VIvv5fWGXBrZ48kZAQJBAJmVCdzQxd9LZI5vxijUCj5EI4e+x5DRqVUvyP8KCZrC +AiNyoDP85T+hBZaSXK3aYGpVwelyj3bvo1GrTNwNWLw= +-----END RSA PRIVATE KEY----- diff --git a/tests/auto/network/access/qnetworkreply/certs/qt-test-server-cacert.pem b/tests/auto/network/access/qnetworkreply/certs/qt-test-server-cacert.pem new file mode 100644 index 0000000000..25bd4046e8 --- /dev/null +++ b/tests/auto/network/access/qnetworkreply/certs/qt-test-server-cacert.pem @@ -0,0 +1,17 @@ +-----BEGIN CERTIFICATE----- +MIICrTCCAhYCCQCdDn5rci6VDjANBgkqhkiG9w0BAQQFADCBmjEOMAwGA1UEChMF +Tm9raWExFDASBgNVBAsTC1F0IFNvZnR3YXJlMSIwIAYJKoZIhvcNAQkBFhNub2Jv +ZHlAbm9kb21haW4ub3JnMQ0wCwYDVQQHEwRPc2xvMQ0wCwYDVQQIEwRPc2xvMQsw +CQYDVQQGEwJOTzEjMCEGA1UEAxMacXQtdGVzdC1zZXJ2ZXIucXQtdGVzdC1uZXQw +HhcNMDkwNzEwMDc0MTIzWhcNMTkwNzA4MDc0MTIzWjCBmjEOMAwGA1UEChMFTm9r +aWExFDASBgNVBAsTC1F0IFNvZnR3YXJlMSIwIAYJKoZIhvcNAQkBFhNub2JvZHlA +bm9kb21haW4ub3JnMQ0wCwYDVQQHEwRPc2xvMQ0wCwYDVQQIEwRPc2xvMQswCQYD +VQQGEwJOTzEjMCEGA1UEAxMacXQtdGVzdC1zZXJ2ZXIucXQtdGVzdC1uZXQwgZ8w +DQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBAM2q22/WNMmn8cC+5EEYGeICySLmp9W6 +Ay6eKHr0Xxp3X3epETuPfvAuxp7rOtkS18EMUegkUj8jw0IMEcbyHKFC/rTCaYOt +93CxGBXMIChiMPAsFeYzGa/D6xzAkfcRaJRQ+Ek3CDLXPnXfo7xpABXezYcPXAJr +gsgBfWrwHdxzAgMBAAEwDQYJKoZIhvcNAQEEBQADgYEAy7YOLCZABQy2Ygkchq1I ++TUpvMn+gLwAyW8TNErM1V4lNY2+K78RawzKx3SqM97ymCy4TD45EA3A2gmi32NI +xSKBNjFyzngUqsXBdcSasALiowlZCiJrGwlGX5qCkBlxXvJeUEbuJLPYVl5FBjXZ +6o00K4cSPCqtqUez7WSmDZU= +-----END CERTIFICATE----- diff --git a/tests/auto/network/access/qnetworkreply/certs/server.key b/tests/auto/network/access/qnetworkreply/certs/server.key new file mode 100644 index 0000000000..9d1664d609 --- /dev/null +++ b/tests/auto/network/access/qnetworkreply/certs/server.key @@ -0,0 +1,15 @@ +-----BEGIN RSA PRIVATE KEY----- +MIICXAIBAAKBgQCnyKBKxBkFG2a6MuLS8RxvF4LkOS4BUZDbBDQyESHCDW9Z2FOQ +VD+Dj6nTs9XuGpuArsMlyV6lr0tgBaqg0ZEBH8oEg+NYHJkyRYRwclgDmEpji0H1 +CEnSkQJga+Rk/t2gqnQI6TRMkV8SPTdNVCytf1uYYDYCjDv2RfMnapuUnQIDAQAB +AoGANFzLkanTeSGNFM0uttBipFT9F4a00dqHz6JnO7zXAT26I5r8sU1pqQBb6uLz +/+Qz5Zwk8RUAQcsMRgJetuPQUb0JZjF6Duv24hNazqXBCu7AZzUenjafwmKC/8ri +KpX3fTwqzfzi//FKGgbXQ80yykSSliDL3kn/drATxsLCgQECQQDXhEFWLJ0vVZ1s +1Ekf+3NITE+DR16X+LQ4W6vyEHAjTbaNWtcTKdAWLA2l6N4WAAPYSi6awm+zMxx4 +VomVTsjdAkEAx0z+e7natLeFcrrq8pbU+wa6SAP1VfhQWKitxL1e7u/QO90NCpxE +oQYKzMkmmpOOFjQwEMAy1dvFMbm4LHlewQJAC/ksDBaUcQHHqjktCtrUb8rVjAyW +A8lscckeB2fEYyG5J6dJVaY4ClNOOs5yMDS2Afk1F6H/xKvtQ/5CzInA/QJATDub +K+BPU8jO9q+gpuIi3VIZdupssVGmCgObVCHLakG4uO04y9IyPhV9lA9tALtoIf4c +VIvv5fWGXBrZ48kZAQJBAJmVCdzQxd9LZI5vxijUCj5EI4e+x5DRqVUvyP8KCZrC +AiNyoDP85T+hBZaSXK3aYGpVwelyj3bvo1GrTNwNWLw= +-----END RSA PRIVATE KEY----- diff --git a/tests/auto/network/access/qnetworkreply/certs/server.pem b/tests/auto/network/access/qnetworkreply/certs/server.pem new file mode 100644 index 0000000000..67eb495319 --- /dev/null +++ b/tests/auto/network/access/qnetworkreply/certs/server.pem @@ -0,0 +1,24 @@ +-----BEGIN CERTIFICATE----- +MIIEEzCCAvugAwIBAgIBADANBgkqhkiG9w0BAQUFADCBnDELMAkGA1UEBhMCTk8x +DTALBgNVBAgTBE9zbG8xEDAOBgNVBAcTB055ZGFsZW4xFjAUBgNVBAoTDVRyb2xs +dGVjaCBBU0ExFDASBgNVBAsTC0RldmVsb3BtZW50MRcwFQYDVQQDEw5mbHVrZS50 +cm9sbC5ubzElMCMGCSqGSIb3DQEJARYWYWhhbnNzZW5AdHJvbGx0ZWNoLmNvbTAe +Fw0wNzEyMDQwMTEwMzJaFw0zNTA0MjEwMTEwMzJaMGMxCzAJBgNVBAYTAk5PMQ0w +CwYDVQQIEwRPc2xvMRYwFAYDVQQKEw1Ucm9sbHRlY2ggQVNBMRQwEgYDVQQLEwtE +ZXZlbG9wbWVudDEXMBUGA1UEAxMOZmx1a2UudHJvbGwubm8wgZ8wDQYJKoZIhvcN +AQEBBQADgY0AMIGJAoGBAKfIoErEGQUbZroy4tLxHG8XguQ5LgFRkNsENDIRIcIN +b1nYU5BUP4OPqdOz1e4am4CuwyXJXqWvS2AFqqDRkQEfygSD41gcmTJFhHByWAOY +SmOLQfUISdKRAmBr5GT+3aCqdAjpNEyRXxI9N01ULK1/W5hgNgKMO/ZF8ydqm5Sd +AgMBAAGjggEaMIIBFjAJBgNVHRMEAjAAMCwGCWCGSAGG+EIBDQQfFh1PcGVuU1NM +IEdlbmVyYXRlZCBDZXJ0aWZpY2F0ZTAdBgNVHQ4EFgQUIYUEPSMBZuX3nxqEJIqv +Cnn05awwgbsGA1UdIwSBszCBsKGBoqSBnzCBnDELMAkGA1UEBhMCTk8xDTALBgNV +BAgTBE9zbG8xEDAOBgNVBAcTB055ZGFsZW4xFjAUBgNVBAoTDVRyb2xsdGVjaCBB +U0ExFDASBgNVBAsTC0RldmVsb3BtZW50MRcwFQYDVQQDEw5mbHVrZS50cm9sbC5u +bzElMCMGCSqGSIb3DQEJARYWYWhhbnNzZW5AdHJvbGx0ZWNoLmNvbYIJAI6otOiR +t1QuMA0GCSqGSIb3DQEBBQUAA4IBAQBtV1/RBUPwYgXsKnGl3BkI8sSmvbsl2cqJ +AQ7kzx/BjMgkGDVTWXvAQ7Qy5piypu8VBQtIX+GgDJepoXfYNRgwvKmP07dUx/Gp +nl3mGb/2PFsr2OQ+YhiIi9Mk4UCbDOYpFmKr6gUkcDaqVZPvAoEbIxCiBOtWlXX8 ++JSxXULFPzZEhV06LpBGiqK5b4euDBVAGTGQ/Dslu67xZhMNhZDZSTSP8l35ettN +XSf2dp01jAamTKOxsrZvHdejAP1y657qRKGvITR9x0LiSZEZi8CtuoKAqHFw9DUx +kWOEIJXpYK9ki8z/PYp2dD3IVW3kjsMrHOhCGK6f5mucNAbsavLD +-----END CERTIFICATE----- diff --git a/tests/auto/network/access/qnetworkreply/echo/echo.pro b/tests/auto/network/access/qnetworkreply/echo/echo.pro new file mode 100644 index 0000000000..74b0bfcab3 --- /dev/null +++ b/tests/auto/network/access/qnetworkreply/echo/echo.pro @@ -0,0 +1,6 @@ +SOURCES += main.cpp +QT = core +CONFIG -= app_bundle debug_and_release_target +CONFIG += console + +symbian:TARGET.CAPABILITY="ALL -TCB" diff --git a/tests/auto/network/access/qnetworkreply/echo/main.cpp b/tests/auto/network/access/qnetworkreply/echo/main.cpp new file mode 100644 index 0000000000..a4ddda171a --- /dev/null +++ b/tests/auto/network/access/qnetworkreply/echo/main.cpp @@ -0,0 +1,62 @@ +/**************************************************************************** +** +** 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 test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** 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. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + + +#include <QtCore> + +int main(int argc, char **) +{ + if (argc < 2) { + printf("usage: echo\n"); + printf("echos all its input to its output.\n"); + return 1; + } + + QFile file; + file.open(stdin, QFile::ReadWrite); + QByteArray data = file.readAll(); + file.close(); + + file.open(stdout, QFile::WriteOnly); + file.write(data); + file.close(); + return 0; +} diff --git a/tests/auto/network/access/qnetworkreply/empty b/tests/auto/network/access/qnetworkreply/empty new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/tests/auto/network/access/qnetworkreply/empty diff --git a/tests/auto/network/access/qnetworkreply/image1.jpg b/tests/auto/network/access/qnetworkreply/image1.jpg Binary files differnew file mode 100644 index 0000000000..dba31c1901 --- /dev/null +++ b/tests/auto/network/access/qnetworkreply/image1.jpg diff --git a/tests/auto/network/access/qnetworkreply/image2.jpg b/tests/auto/network/access/qnetworkreply/image2.jpg Binary files differnew file mode 100644 index 0000000000..72936e2de6 --- /dev/null +++ b/tests/auto/network/access/qnetworkreply/image2.jpg diff --git a/tests/auto/network/access/qnetworkreply/image3.jpg b/tests/auto/network/access/qnetworkreply/image3.jpg Binary files differnew file mode 100644 index 0000000000..cede519938 --- /dev/null +++ b/tests/auto/network/access/qnetworkreply/image3.jpg diff --git a/tests/auto/network/access/qnetworkreply/qnetworkreply.pro b/tests/auto/network/access/qnetworkreply/qnetworkreply.pro new file mode 100644 index 0000000000..86d3155c05 --- /dev/null +++ b/tests/auto/network/access/qnetworkreply/qnetworkreply.pro @@ -0,0 +1,7 @@ +TEMPLATE = subdirs +SUBDIRS = test + +requires(contains(QT_CONFIG,private_tests)) + +!wince*:SUBDIRS += echo +symbian: TARGET.CAPABILITY = NetworkServices diff --git a/tests/auto/network/access/qnetworkreply/qnetworkreply.qrc b/tests/auto/network/access/qnetworkreply/qnetworkreply.qrc new file mode 100644 index 0000000000..85ca6312af --- /dev/null +++ b/tests/auto/network/access/qnetworkreply/qnetworkreply.qrc @@ -0,0 +1,5 @@ +<!DOCTYPE RCC><RCC version="1.0"> +<qresource> + <file>resource</file> +</qresource> +</RCC> diff --git a/tests/auto/network/access/qnetworkreply/resource b/tests/auto/network/access/qnetworkreply/resource new file mode 100644 index 0000000000..e9b146042d --- /dev/null +++ b/tests/auto/network/access/qnetworkreply/resource @@ -0,0 +1,283 @@ + + + + + + +Network Working Group L. Masinter +Request for Comments: 2397 Xerox Corporation +Category: Standards Track August 1998 + + + The "data" URL scheme + +Status of this Memo + + This document specifies an Internet standards track protocol for the + Internet community, and requests discussion and suggestions for + improvements. Please refer to the current edition of the "Internet + Official Protocol Standards" (STD 1) for the standardization state + and status of this protocol. Distribution of this memo is unlimited. + +Copyright Notice + + Copyright (C) The Internet Society (1998). All Rights Reserved. + +1. Abstract + + A new URL scheme, "data", is defined. It allows inclusion of small + data items as "immediate" data, as if it had been included + externally. + +2. Description + + Some applications that use URLs also have a need to embed (small) + media type data directly inline. This document defines a new URL + scheme that would work like 'immediate addressing'. The URLs are of + the form: + + data:[<mediatype>][;base64],<data> + + The <mediatype> is an Internet media type specification (with + optional parameters.) The appearance of ";base64" means that the data + is encoded as base64. Without ";base64", the data (as a sequence of + octets) is represented using ASCII encoding for octets inside the + range of safe URL characters and using the standard %xx hex encoding + of URLs for octets outside that range. If <mediatype> is omitted, it + defaults to text/plain;charset=US-ASCII. As a shorthand, + "text/plain" can be omitted but the charset parameter supplied. + + The "data:" URL scheme is only useful for short values. Note that + some applications that use URLs may impose a length limit; for + example, URLs embedded within <A> anchors in HTML have a length limit + determined by the SGML declaration for HTML [RFC1866]. The LITLEN + (1024) limits the number of characters which can appear in a single + + + +Masinter Standards Track [Page 1] + +RFC 2397 The "data" URL scheme August 1998 + + + attribute value literal, the ATTSPLEN (2100) limits the sum of all + lengths of all attribute value specifications which appear in a tag, + and the TAGLEN (2100) limits the overall length of a tag. + + The "data" URL scheme has no relative URL forms. + +3. Syntax + + dataurl := "data:" [ mediatype ] [ ";base64" ] "," data + mediatype := [ type "/" subtype ] *( ";" parameter ) + data := *urlchar + parameter := attribute "=" value + + where "urlchar" is imported from [RFC2396], and "type", "subtype", + "attribute" and "value" are the corresponding tokens from [RFC2045], + represented using URL escaped encoding of [RFC2396] as necessary. + + Attribute values in [RFC2045] are allowed to be either represented as + tokens or as quoted strings. However, within a "data" URL, the + "quoted-string" representation would be awkward, since the quote mark + is itself not a valid urlchar. For this reason, parameter values + should use the URL Escaped encoding instead of quoted string if the + parameter values contain any "tspecial". + + The ";base64" extension is distinguishable from a content-type + parameter by the fact that it doesn't have a following "=" sign. + +4. Examples + + A data URL might be used for arbitrary types of data. The URL + + data:,A%20brief%20note + + encodes the text/plain string "A brief note", which might be useful + in a footnote link. + + The HTML fragment: + + <IMG + SRC="data:image/gif;base64,R0lGODdhMAAwAPAAAAAAAP///ywAAAAAMAAw + AAAC8IyPqcvt3wCcDkiLc7C0qwyGHhSWpjQu5yqmCYsapyuvUUlvONmOZtfzgFz + ByTB10QgxOR0TqBQejhRNzOfkVJ+5YiUqrXF5Y5lKh/DeuNcP5yLWGsEbtLiOSp + a/TPg7JpJHxyendzWTBfX0cxOnKPjgBzi4diinWGdkF8kjdfnycQZXZeYGejmJl + ZeGl9i2icVqaNVailT6F5iJ90m6mvuTS4OK05M0vDk0Q4XUtwvKOzrcd3iq9uis + F81M1OIcR7lEewwcLp7tuNNkM3uNna3F2JQFo97Vriy/Xl4/f1cf5VWzXyym7PH + hhx4dbgYKAAA7" + ALT="Larry"> + + + + +Masinter Standards Track [Page 2] + +RFC 2397 The "data" URL scheme August 1998 + + + could be used for a small inline image in a HTML document. (The + embedded image is probably near the limit of utility. For anything + else larger, data URLs are likely to be inappropriate.) + + A data URL scheme's media type specification can include other + parameters; for example, one might specify a charset parameter. + + data:text/plain;charset=iso-8859-7,%be%fg%be + + can be used for a short sequence of greek characters. + + Some applications may use the "data" URL scheme in order to provide + setup parameters for other kinds of networking applications. For + example, one might create a media type + application/vnd-xxx-query + + whose content consists of a query string and a database identifier + for the "xxx" vendor's databases. A URL of the form: + + data:application/vnd-xxx- + query,select_vcount,fcol_from_fieldtable/local + + could then be used in a local application to launch the "helper" for + application/vnd-xxx-query and give it the immediate data included. + +5. History + + This idea was originally proposed August 1995. Some versions of the + data URL scheme have been used in the definition of VRML, and a + version has appeared as part of a proposal for embedded data in HTML. + Various changes have been made, based on requests, to elide the media + type, pack the indication of the base64 encoding more tightly, and + eliminate "quoted printable" as an encoding since it would not easily + yield valid URLs without additional %xx encoding, which itself is + sufficient. The "data" URL scheme is in use in VRML, new applications + of HTML, and various commercial products. It is being used for object + parameters in Java and ActiveX applications. + +6. Security + + Interpretation of the data within a "data" URL has the same security + considerations as any implementation of the given media type. An + application should not interpret the contents of a data URL which is + marked with a media type that has been disallowed for processing by + the application's configuration. + + + + + + +Masinter Standards Track [Page 3] + +RFC 2397 The "data" URL scheme August 1998 + + + Sites which use firewall proxies to disallow the retrieval of certain + media types (such as application script languages or types with known + security problems) will find it difficult to screen against the + inclusion of such types using the "data" URL scheme. However, they + should be aware of the threat and take whatever precautions are + considered necessary within their domain. + + The effect of using long "data" URLs in applications is currently + unknown; some software packages may exhibit unreasonable behavior + when confronted with data that exceeds its allocated buffer size. + +7. References + + [RFC2396] Berners-Lee, T., Fielding, R., and L. Masinter, + "Uniform Resource Identifiers (URI): Generic Syntax", RFC + 2396, August 1998. + + [RFC1866] Berners-Lee, T., and D. Connolly, "Hypertext Markup + Language - 2.0.", RFC 1866, November 1995. + + [RFC2045] Freed N., and N. Borenstein., "Multipurpose Internet Mail + Extensions (MIME) Part One: Format of Internet Message + Bodies", RFC 2045, November 1996. + +Author contact information: + + Larry Masinter + Xerox Palo Alto Research Center + 3333 Coyote Hill Road + Palo Alto, CA 94304 + + EMail: masinter@parc.xerox.com + + + + + + + + + + + + + + + + + + + +Masinter Standards Track [Page 4] + +RFC 2397 The "data" URL scheme August 1998 + + +Full Copyright Statement + + Copyright (C) The Internet Society (1998). All Rights Reserved. + + This document and translations of it may be copied and furnished to + others, and derivative works that comment on or otherwise explain it + or assist in its implementation may be prepared, copied, published + and distributed, in whole or in part, without restriction of any + kind, provided that the above copyright notice and this paragraph are + included on all such copies and derivative works. However, this + document itself may not be modified in any way, such as by removing + the copyright notice or references to the Internet Society or other + Internet organizations, except as needed for the purpose of + developing Internet standards in which case the procedures for + copyrights defined in the Internet Standards process must be + followed, or as required to translate it into languages other than + English. + + The limited permissions granted above are perpetual and will not be + revoked by the Internet Society or its successors or assigns. + + This document and the information contained herein is provided on an + "AS IS" basis and THE INTERNET SOCIETY AND THE INTERNET ENGINEERING + TASK FORCE DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING + BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE INFORMATION + HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED WARRANTIES OF + MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. + + + + + + + + + + + + + + + + + + + + + + + + +Masinter Standards Track [Page 5] + diff --git a/tests/auto/network/access/qnetworkreply/rfc3252.txt b/tests/auto/network/access/qnetworkreply/rfc3252.txt new file mode 100644 index 0000000000..b80c61bf0a --- /dev/null +++ b/tests/auto/network/access/qnetworkreply/rfc3252.txt @@ -0,0 +1,899 @@ + + + + + + +Network Working Group H. Kennedy +Request for Comments: 3252 Mimezine +Category: Informational 1 April 2002 + + + Binary Lexical Octet Ad-hoc Transport + +Status of this Memo + + This memo provides information for the Internet community. It does + not specify an Internet standard of any kind. Distribution of this + memo is unlimited. + +Copyright Notice + + Copyright (C) The Internet Society (2002). All Rights Reserved. + +Abstract + + This document defines a reformulation of IP and two transport layer + protocols (TCP and UDP) as XML applications. + +1. Introduction + +1.1. Overview + + This document describes the Binary Lexical Octet Ad-hoc Transport + (BLOAT): a reformulation of a widely-deployed network-layer protocol + (IP [RFC791]), and two associated transport layer protocols (TCP + [RFC793] and UDP [RFC768]) as XML [XML] applications. It also + describes methods for transporting BLOAT over Ethernet and IEEE 802 + networks as well as encapsulating BLOAT in IP for gatewaying BLOAT + across the public Internet. + +1.2. Motivation + + The wild popularity of XML as a basis for application-level protocols + such as the Blocks Extensible Exchange Protocol [RFC3080], the Simple + Object Access Protocol [SOAP], and Jabber [JABBER] prompted + investigation into the possibility of extending the use of XML in the + protocol stack. Using XML at both the transport and network layer in + addition to the application layer would provide for an amazing amount + of power and flexibility while removing dependencies on proprietary + and hard-to-understand binary protocols. This protocol unification + would also allow applications to use a single XML parser for all + aspects of their operation, eliminating developer time spent figuring + out the intricacies of each new protocol, and moving the hard work of + + + + +Kennedy Informational [Page 1] + +RFC 3252 Binary Lexical Octet Ad-hoc Transport 1 April 2002 + + + parsing to the XML toolset. The use of XML also mitigates concerns + over "network vs. host" byte ordering which is at the root of many + network application bugs. + +1.3. Relation to Existing Protocols + + The reformulations specified in this RFC follow as closely as + possible the spirit of the RFCs on which they are based, and so MAY + contain elements or attributes that would not be needed in a pure + reworking (e.g. length attributes, which are implicit in XML.) + + The layering of network and transport protocols are maintained in + this RFC despite the optimizations that could be made if the line + were somewhat blurred (i.e. merging TCP and IP into a single, larger + element in the DTD) in order to foster future use of this protocol as + a basis for reformulating other protocols (such as ICMP.) + + Other than the encoding, the behavioral aspects of each of the + existing protocols remain unchanged. Routing, address spaces, TCP + congestion control, etc. behave as specified in the extant standards. + Adapting to new standards and experimental algorithm heuristics for + improving performance will become much easier once the move to BLOAT + has been completed. + +1.4. Requirement Levels + + The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", + "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this + document are to be interpreted as described in BCP 14, RFC 2119 + [RFC2119]. + +2. IPoXML + + This protocol MUST be implemented to be compliant with this RFC. + IPoXML is the root protocol REQUIRED for effective use of TCPoXML + (section 3.) and higher-level application protocols. + + The DTD for this document type can be found in section 7.1. + + The routing of IPoXML can be easily implemented on hosts with an XML + parser, as the regular structure lends itself handily to parsing and + validation of the document/datagram and then processing the + destination address, TTL, and checksum before sending it on to its + next-hop. + + The reformulation of IPv4 was chosen over IPv6 [RFC2460] due to the + wider deployment of IPv4 and the fact that implementing IPv6 as XML + would have exceeded the 1500 byte Ethernet MTU. + + + +Kennedy Informational [Page 2] + +RFC 3252 Binary Lexical Octet Ad-hoc Transport 1 April 2002 + + + All BLOAT implementations MUST use - and specify - the UTF-8 encoding + of RFC 2279 [RFC2279]. All BLOAT document/datagrams MUST be well- + formed and include the XMLDecl. + +2.1. IP Description + + A number of items have changed (for the better) from the original IP + specification. Bit-masks, where present have been converted into + human-readable values. IP addresses are listed in their dotted- + decimal notation [RFC1123]. Length and checksum values are present + as decimal integers. + + To calculate the length and checksum fields of the IP element, a + canonicalized form of the element MUST be used. The canonical form + SHALL have no whitespace (including newline characters) between + elements and only one space character between attributes. There + SHALL NOT be a space following the last attribute in an element. + + An iterative method SHOULD be used to calculate checksums, as the + length field will vary based on the size of the checksum. + + The payload element bears special attention. Due to the character + set restrictions of XML, the payload of IP datagrams (which MAY + contain arbitrary data) MUST be encoded for transport. This RFC + REQUIRES the contents of the payload to be encoded in the base-64 + encoding of RFC 2045 [RFC2045], but removes the requirement that the + encoded output MUST be wrapped on 76-character lines. + + + + + + + + + + + + + + + + + + + + + + + + +Kennedy Informational [Page 3] + +RFC 3252 Binary Lexical Octet Ad-hoc Transport 1 April 2002 + + +2.2. Example Datagram + + The following is an example IPoXML datagram with an empty payload: + + <?xml version="1.0" encoding="UTF-8"?> + <!DOCTYPE ip PUBLIC "-//IETF//DTD BLOAT 1.0 IP//EN" "bloat.dtd"> + <ip> + <header length="474"> + <version value="4"/> + <tos precedence="Routine" delay="Normal" throughput="Normal" + relibility="Normal" reserved="0"/> + <total.length value="461"/> + <id value="1"/> + <flags reserved="0" df="dont" mf="last"/> + <offset value="0"/> + <ttl value="255"/> + <protocol value="6"/> + <checksum value="8707"/> + <source address="10.0.0.22"/> + <destination address="10.0.0.1"/> + <options> + <end copied="0" class="0" number="0"/> + </options> + <padding pad="0"/> + </header> + <payload> + </payload> + </ip> + +3. TCPoXML + + This protocol MUST be implemented to be compliant with this RFC. The + DTD for this document type can be found in section 7.2. + +3.1. TCP Description + + A number of items have changed from the original TCP specification. + Bit-masks, where present have been converted into human-readable + values. Length and checksum and port values are present as decimal + integers. + + To calculate the length and checksum fields of the TCP element, a + canonicalized form of the element MUST be used as in section 2.1. + + An iterative method SHOULD be used to calculate checksums as in + section 2.1. + + The payload element MUST be encoded as in section 2.1. + + + +Kennedy Informational [Page 4] + +RFC 3252 Binary Lexical Octet Ad-hoc Transport 1 April 2002 + + + The TCP offset element was expanded to a maximum of 255 from 16 to + allow for the increased size of the header in XML. + + TCPoXML datagrams encapsulated by IPoXML MAY omit the <?xml?> header + as well as the <!DOCTYPE> declaration. + +3.2. Example Datagram + + The following is an example TCPoXML datagram with an empty payload: + + <?xml version="1.0" encoding="UTF-8"?> + <!DOCTYPE tcp PUBLIC "-//IETF//DTD BLOAT 1.0 TCP//EN" "bloat.dtd"> + <tcp> + <tcp.header> + <src port="31415"/> + <dest port="42424"/> + <sequence number="322622954"/> + <acknowledgement number="689715995"/> + <offset number=""/> + <reserved value="0"/> + <control syn="1" ack="1"/> + <window size="1"/> + <urgent pointer="0"/> + <checksum value="2988"/> + <tcp.options> + <tcp.end kind="0"/> + </tcp.options> + <padding pad="0"/> + </tcp.header> + <payload> + </payload> + </tcp> + +4. UDPoXML + + This protocol MUST be implemented to be compliant with this RFC. The + DTD for this document type can be found in section 7.3. + +4.1. UDP Description + + A number of items have changed from the original UDP specification. + Bit-masks, where present have been converted into human-readable + values. Length and checksum and port values are present as decimal + integers. + + + + + + + +Kennedy Informational [Page 5] + +RFC 3252 Binary Lexical Octet Ad-hoc Transport 1 April 2002 + + + To calculate the length and checksum fields of the UDP element, a + canonicalized form of the element MUST be used as in section 2.1. An + iterative method SHOULD be used to calculate checksums as in section + 2.1. + + The payload element MUST be encoded as in section 2.1. + + UDPoXML datagrams encapsulated by IPoXML MAY omit the <?xml?> header + as well as the <!DOCTYPE> declaration. + +4.2. Example Datagram + + The following is an example UDPoXML datagram with an empty payload: + + <?xml version="1.0" encoding="UTF-8"?> + <!DOCTYPE udp PUBLIC "-//IETF//DTD BLOAT 1.0 UDP//EN" "bloat.dtd"> + <udp> + <udp.header> + <src port="31415"/> + <dest port="42424"/> + <udp.length value="143"/> + <checksum value="2988"/> + </udp.header> + <payload> + </payload> + </udp> + +5. Network Transport + + This document provides for the transmission of BLOAT datagrams over + two common families of physical layer transport. Future RFCs will + address additional transports as routing vendors catch up to the + specification, and we begin to see BLOAT routed across the Internet + backbone. + +5.1. Ethernet + + BLOAT is encapsulated in Ethernet datagrams as in [RFC894] with the + exception that the type field of the Ethernet frame MUST contain the + value 0xBEEF. The first 5 octets of the Ethernet frame payload will + be 0x3c 3f 78 6d 6c ("<?xml".) + +5.2. IEEE 802 + + BLOAT is encapsulated in IEEE 802 Networks as in [RFC1042] except + that the protocol type code for IPoXML is 0xBEEF. + + + + + +Kennedy Informational [Page 6] + +RFC 3252 Binary Lexical Octet Ad-hoc Transport 1 April 2002 + + +6. Gatewaying over IP + + In order to facilitate the gradual introduction of BLOAT into the + public Internet, BLOAT MAY be encapsulated in IP as in [RFC2003] to + gateway between networks that run BLOAT natively on their LANs. + +7. DTDs + + The Transport DTDs (7.2. and 7.3.) build on the definitions in the + Network DTD (7.1.) + + The DTDs are referenced by their PubidLiteral and SystemLiteral (from + [XML]) although it is understood that most IPoXML implementations + will not need to pull down the DTD, as it will normally be embedded + in the implementation, and presents something of a catch-22 if you + need to load part of your network protocol over the network. + +7.1. IPoXML DTD + + <!-- + DTD for IP over XML. + Refer to this DTD as: + + <!DOCTYPE ip PUBLIC "-//IETF//DTD BLOAT 1.0 IP//EN" "bloat.dtd"> + --> + <!-- + DTD data types: + + Digits [0..9]+ + + Precedence "NetworkControl | InternetworkControl | + CRITIC | FlashOverride | Flash | Immediate | + Priority | Routine" + + IP4Addr "dotted-decimal" notation of [RFC1123] + + Class [0..3] + + Sec "Unclassified | Confidential | EFTO | MMMM | PROG | + Restricted | Secret | Top Secret | Reserved" + + Compartments [0..65535] + + Handling [0..65535] + + TCC [0..16777216] + + --> + + + +Kennedy Informational [Page 7] + +RFC 3252 Binary Lexical Octet Ad-hoc Transport 1 April 2002 + + + <!ENTITY % Digits "CDATA"> + <!ENTITY % Precedence "CDATA"> + <!ENTITY % IP4Addr "CDATA"> + <!ENTITY % Class "CDATA"> + <!ENTITY % Sec "CDATA"> + <!ENTITY % Compartments "CDATA"> + <!ENTITY % Handling "CDATA"> + <!ENTITY % TCC "CDATA"> + + <!ELEMENT ip (header, payload)> + + <!ELEMENT header (version, tos, total.length, id, flags, offset, ttl, + protocol, checksum, source, destination, options, + padding)> + <!-- length of header in 32-bit words --> + <!ATTLIST header + length %Digits; #REQUIRED> + + <!ELEMENT version EMPTY> + <!-- ip version. SHOULD be "4" --> + <!ATTLIST version + value %Digits; #REQUIRED> + + <!ELEMENT tos EMPTY> + <!ATTLIST tos + precedence %Precedence; #REQUIRED + delay (normal | low) #REQUIRED + throughput (normal | high) #REQUIRED + relibility (normal | high) #REQUIRED + reserved CDATA #FIXED "0"> + + <!ELEMENT total.length EMPTY> + <!-- + total length of datagram (header and payload) in octets, MUST be + less than 65,535 (and SHOULD be less than 1024 for IPoXML on local + ethernets). + --> + <!ATTLIST total.length + value %Digits; #REQUIRED> + + <!ELEMENT id EMPTY> + <!-- 0 <= id <= 65,535 --> + <!ATTLIST id + value %Digits; #REQUIRED> + + <!ELEMENT flags EMPTY> + <!-- df = don't fragment, mf = more fragments --> + <!ATTLIST flags + + + +Kennedy Informational [Page 8] + +RFC 3252 Binary Lexical Octet Ad-hoc Transport 1 April 2002 + + + reserved CDATA #FIXED "0" + df (may|dont) #REQUIRED + mf (last|more) #REQUIRED> + + <!ELEMENT offset EMPTY> + <!-- 0 <= offset <= 8192 measured in 8 octet (64-bit) chunks --> + <!ATTLIST offset + value %Digits; #REQUIRED> + + <!ELEMENT ttl EMPTY> + <!-- 0 <= ttl <= 255 --> + <!ATTLIST ttl + value %Digits; #REQUIRED> + + <!ELEMENT protocol EMPTY> + <!-- 0 <= protocol <= 255 (per IANA) --> + <!ATTLIST protocol + value %Digits; #REQUIRED> + + <!ELEMENT checksum EMPTY> + <!-- 0 <= checksum <= 65535 (over header only) --> + <!ATTLIST checksum + value %Digits; #REQUIRED> + + <!ELEMENT source EMPTY> + <!ATTLIST source + address %IP4Addr; #REQUIRED> + + <!ELEMENT destination EMPTY> + <!ATTLIST destination + address %IP4Addr; #REQUIRED> + + <!ELEMENT options ( end | noop | security | loose | strict | record + | stream | timestamp )*> + + <!ELEMENT end EMPTY> + <!ATTLIST end + copied (0|1) #REQUIRED + class CDATA #FIXED "0" + number CDATA #FIXED "0"> + + <!ELEMENT noop EMPTY> + <!ATTLIST noop + copied (0|1) #REQUIRED + class CDATA #FIXED "0" + number CDATA #FIXED "1"> + + <!ELEMENT security EMPTY> + + + +Kennedy Informational [Page 9] + +RFC 3252 Binary Lexical Octet Ad-hoc Transport 1 April 2002 + + + <!ATTLIST security + copied CDATA #FIXED "1" + class CDATA #FIXED "0" + number CDATA #FIXED "2" + length CDATA #FIXED "11" + security %Sec; #REQUIRED + compartments %Compartments; #REQUIRED + handling %Handling; #REQUIRED + tcc %TCC; #REQUIRED> + <!ELEMENT loose (hop)+> + <!ATTLIST loose + copied CDATA #FIXED "1" + class CDATA #FIXED "0" + number CDATA #FIXED "3" + length %Digits; #REQUIRED + pointer %Digits; #REQUIRED> + + <!ELEMENT hop EMPTY> + <!ATTLIST hop + address %IP4Addr; #REQUIRED> + + <!ELEMENT strict (hop)+> + <!ATTLIST strict + copied CDATA #FIXED "1" + class CDATA #FIXED "0" + number CDATA #FIXED "9" + length %Digits; #REQUIRED + pointer %Digits; #REQUIRED> + + <!ELEMENT record (hop)+> + <!ATTLIST record + copied CDATA #FIXED "0" + class CDATA #FIXED "0" + number CDATA #FIXED "7" + length %Digits; #REQUIRED + pointer %Digits; #REQUIRED> + + <!ELEMENT stream EMPTY> + <!-- 0 <= id <= 65,535 --> + <!ATTLIST stream + copied CDATA #FIXED "1" + class CDATA #FIXED "0" + number CDATA #FIXED "8" + length CDATA #FIXED "4" + id %Digits; #REQUIRED> + + <!ELEMENT timestamp (tstamp)+> + <!-- 0 <= oflw <=15 --> + + + +Kennedy Informational [Page 10] + +RFC 3252 Binary Lexical Octet Ad-hoc Transport 1 April 2002 + + + <!ATTLIST timestamp + copied CDATA #FIXED "0" + class CDATA #FIXED "2" + number CDATA #FIXED "4" + length %Digits; #REQUIRED + pointer %Digits; #REQUIRED + oflw %Digits; #REQUIRED + flag (0 | 1 | 3) #REQUIRED> + + <!ELEMENT tstamp EMPTY> + <!ATTLIST tstamp + time %Digits; #REQUIRED + address %IP4Addr; #IMPLIED> + <!-- + padding to bring header to 32-bit boundary. + pad MUST be "0"* + --> + <!ELEMENT padding EMPTY> + <!ATTLIST padding + pad CDATA #REQUIRED> + + <!-- payload MUST be encoded as base-64 [RFC2045], as modified + by section 2.1 of this RFC --> + <!ELEMENT payload (CDATA)> + +7.2. TCPoXML DTD + + <!-- + DTD for TCP over XML. + Refer to this DTD as: + + <!DOCTYPE tcp PUBLIC "-//IETF//DTD BLOAT 1.0 TCP//EN" "bloat.dtd"> + --> + + <!-- the pseudoheader is only included for checksum calculations --> + <!ELEMENT tcp (tcp.pseudoheader?, tcp.header, payload)> + + <!ELEMENT tcp.header (src, dest, sequence, acknowledgement, offset, + reserved, control, window, checksum, urgent, + tcp.options, padding)> + + <!ELEMENT src EMPTY> + <!-- 0 <= port <= 65,535 --> + <!ATTLIST src + port %Digits; #REQUIRED> + + <!ELEMENT dest EMPTY> + <!-- 0 <= port <= 65,535 --> + + + +Kennedy Informational [Page 11] + +RFC 3252 Binary Lexical Octet Ad-hoc Transport 1 April 2002 + + + <!ATTLIST dest + port %Digits; #REQUIRED> + + <!ELEMENT sequence EMPTY> + <!-- 0 <= number <= 4294967295 --> + <!ATTLIST sequence + number %Digits; #REQUIRED> + + <!ELEMENT acknowledgement EMPTY> + <!-- 0 <= number <= 4294967295 --> + <!ATTLIST acknowledgement + number %Digits; #REQUIRED> + + <!ELEMENT offset EMPTY> + <!-- 0 <= number <= 255 --> + <!ATTLIST offset + number %Digits; #REQUIRED> + + <!ELEMENT reserved EMPTY> + <!ATTLIST reserved + value CDATA #FIXED "0"> + + <!ELEMENT control EMPTY> + <!ATTLIST control + urg (0|1) #IMPLIED + ack (0|1) #IMPLIED + psh (0|1) #IMPLIED + rst (0|1) #IMPLIED + syn (0|1) #IMPLIED + fin (0|1) #IMPLIED> + + <!ELEMENT window EMPTY> + <!-- 0 <= size <= 65,535 --> + <!ATTLIST window + size %Digits; #REQUIRED> + + <!-- + checksum as in ip, but with + the following pseudo-header added into the tcp element: + --> + <!ELEMENT tcp.pseudoheader (source, destination, protocol, + tcp.length)> + + <!-- + tcp header + data length in octets. does not include the size of + + the pseudoheader. + --> + + + +Kennedy Informational [Page 12] + +RFC 3252 Binary Lexical Octet Ad-hoc Transport 1 April 2002 + + + <!ELEMENT tcp.length EMPTY> + <!ATTLIST tcp.length + value %Digits; #REQUIRED> + + <!ELEMENT urgent EMPTY> + <!-- 0 <= pointer <= 65,535 --> + <!ATTLIST urgent + pointer %Digits; #REQUIRED> + + <!ELEMENT tcp.options (tcp.end | tcp.noop | tcp.mss)+> + + <!ELEMENT tcp.end EMPTY> + <!ATTLIST tcp.end + kind CDATA #FIXED "0"> + + <!ELEMENT tcp.noop EMPTY> + <!ATTLIST tcp.noop + kind CDATA #FIXED "1"> + + <!ELEMENT tcp.mss EMPTY> + <!ATTLIST tcp.mss + kind CDATA #FIXED "2" + length CDATA #FIXED "4" + size %Digits; #REQUIRED> + +7.3. UDPoXML DTD + + <!-- + DTD for UDP over XML. + Refer to this DTD as: + + <!DOCTYPE udp PUBLIC "-//IETF//DTD BLOAT 1.0 UDP//EN" "bloat.dtd"> + --> + + <!ELEMENT udp (udp.pseudoheader?, udp.header, payload)> + + <!ELEMENT udp.header (src, dest, udp.length, checksum)> + + <!ELEMENT udp.pseudoheader (source, destination, protocol, + udp.length)> + + <!-- + udp header + data length in octets. does not include the size of + the pseudoheader. + --> + <!ELEMENT udp.length EMPTY> + <!ATTLIST udp.length + value %Digits; #REQUIRED> + + + +Kennedy Informational [Page 13] + +RFC 3252 Binary Lexical Octet Ad-hoc Transport 1 April 2002 + + +8. Security Considerations + + XML, as a subset of SGML, has the same security considerations as + specified in SGML Media Types [RFC1874]. Security considerations + that apply to IP, TCP and UDP also likely apply to BLOAT as it does + not attempt to correct for issues not related to message format. + +9. References + + [JABBER] Miller, J., "Jabber", draft-miller-jabber-00.txt, + February 2002. (Work in Progress) + + [RFC768] Postel, J., "User Datagram Protocol", STD 6, RFC 768, + August 1980. + + [RFC791] Postel, J., "Internet Protocol", STD 5, RFC 791, + September 1981. + + [RFC793] Postel, J., "Transmission Control Protocol", STD 7, RFC + 793, September 1981. + + [RFC894] Hornig, C., "Standard for the Transmission of IP + Datagrams over Ethernet Networks.", RFC 894, April 1984. + + [RFC1042] Postel, J. and J. Reynolds, "Standard for the + Transmission of IP Datagrams Over IEEE 802 Networks", STD + 43, RFC 1042, February 1988. + + [RFC1123] Braden, R., "Requirements for Internet Hosts - + Application and Support", RFC 1123, October 1989. + + [RFC1874] Levinson, E., "SGML Media Types", RFC 1874, December + 1995. + + [RFC2003] Perkins, C., "IP Encapsulation within IP", RFC 2003, + October 1996. + + [RFC2045] Freed, N. and N. Borenstein, "Multipurpose Internet Mail + Extensions (MIME) Part One: Format of Internet Message + Bodies", RFC 2045, November 1996. + + [RFC2119] Bradner, S., "Key words for use in RFCs to Indicate + Requirement Levels", BCP 14, RFC 2119, March 1997. + + [RFC2279] Yergeau, F., "UTF-8, a transformation format of ISO + 10646", RFC 2279, January 1998. + + + + + +Kennedy Informational [Page 14] + +RFC 3252 Binary Lexical Octet Ad-hoc Transport 1 April 2002 + + + [RFC2460] Deering, S. and R. Hinden, "Internet Protocol, Version 6 + (IPv6) Specification", RFC 2460, December 1998. + + [RFC3080] Rose, M., "The Blocks Extensible Exchange Protocol Core", + RFC 3080, March 2001. + + [SOAP] Box, D., Ehnebuske, D., Kakivaya, G., Layman, A., + Mendelsohn, N., Nielsen, H. F., Thatte, S. Winer, D., + "Simple Object Access Protocol (SOAP) 1.1" World Wide Web + Consortium Note, May 2000 http://www.w3.org/TR/SOAP/ + + [XML] Bray, T., Paoli, J., Sperberg-McQueen, C. M., "Extensible + Markup Language (XML)" World Wide Web Consortium + Recommendation REC- xml-19980210. + http://www.w3.org/TR/1998/REC-xml-19980210 + +10. Author's Address + + Hugh Kennedy + Mimezine + 1060 West Addison + Chicago, IL 60613 + USA + + EMail: kennedyh@engin.umich.edu + + + + + + + + + + + + + + + + + + + + + + + + + + +Kennedy Informational [Page 15] + +RFC 3252 Binary Lexical Octet Ad-hoc Transport 1 April 2002 + + +11. Full Copyright Statement + + Copyright (C) The Internet Society (2002). All Rights Reserved. + + This document and translations of it may be copied and furnished to + others, and derivative works that comment on or otherwise explain it + or assist in its implementation may be prepared, copied, published + and distributed, in whole or in part, without restriction of any + kind, provided that the above copyright notice and this paragraph are + included on all such copies and derivative works. However, this + document itself may not be modified in any way, such as by removing + the copyright notice or references to the Internet Society or other + Internet organizations, except as needed for the purpose of + developing Internet standards in which case the procedures for + copyrights defined in the Internet Standards process must be + followed, or as required to translate it into languages other than + English. + + The limited permissions granted above are perpetual and will not be + revoked by the Internet Society or its successors or assigns. + + This document and the information contained herein is provided on an + "AS IS" basis and THE INTERNET SOCIETY AND THE INTERNET ENGINEERING + TASK FORCE DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING + BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE INFORMATION + HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED WARRANTIES OF + MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. + +Acknowledgement + + Funding for the RFC Editor function is currently provided by the + Internet Society. + + + + + + + + + + + + + + + + + + + +Kennedy Informational [Page 16] + diff --git a/tests/auto/network/access/qnetworkreply/smb-file.txt b/tests/auto/network/access/qnetworkreply/smb-file.txt new file mode 100644 index 0000000000..73c3ac2c07 --- /dev/null +++ b/tests/auto/network/access/qnetworkreply/smb-file.txt @@ -0,0 +1 @@ +This is 34 bytes. Do not change...
\ No newline at end of file diff --git a/tests/auto/network/access/qnetworkreply/test/test.pro b/tests/auto/network/access/qnetworkreply/test/test.pro new file mode 100644 index 0000000000..dba1c69dbb --- /dev/null +++ b/tests/auto/network/access/qnetworkreply/test/test.pro @@ -0,0 +1,38 @@ +load(qttest_p4) +QT -= gui +SOURCES += ../tst_qnetworkreply.cpp +TARGET = ../tst_qnetworkreply + +qpa:contains(QT_CONFIG,xcb): CONFIG+=insignificant_test # unstable, QTBUG-21102 + +win32 { + CONFIG(debug, debug|release) { + TARGET = ../../debug/tst_qnetworkreply +} else { + TARGET = ../../release/tst_qnetworkreply + } +} + +!symbian:DEFINES += SRCDIR=\\\"$$PWD/..\\\" + +QT = core-private network-private +RESOURCES += ../qnetworkreply.qrc + +symbian|wince*:{ + # For cross compiled targets, reference data files need to be deployed + addFiles.files = ../empty ../rfc3252.txt ../resource ../bigfile ../*.jpg + addFiles.path = . + DEPLOYMENT += addFiles + + certFiles.files = ../certs + certFiles.path = . + DEPLOYMENT += certFiles +} + +symbian:{ + # Symbian toolchain does not support correct include semantics + INCLUDEPATH+=..\\..\\..\\..\\include\\QtNetwork\\private + # bigfile test case requires more heap + TARGET.EPOCHEAPSIZE="0x100 0x10000000" + TARGET.CAPABILITY="ALL -TCB" +} diff --git a/tests/auto/network/access/qnetworkreply/tst_qnetworkreply.cpp b/tests/auto/network/access/qnetworkreply/tst_qnetworkreply.cpp new file mode 100644 index 0000000000..dd9fe8ee82 --- /dev/null +++ b/tests/auto/network/access/qnetworkreply/tst_qnetworkreply.cpp @@ -0,0 +1,6342 @@ +/**************************************************************************** +** +** 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 test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** 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. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + + +#include <QtTest/QtTest> +#include <QtCore/QCryptographicHash> +#include <QtCore/QDataStream> +#include <QtCore/QUrl> +#include <QtCore/QEventLoop> +#include <QtCore/QFile> +#include <QtCore/QSharedPointer> +#include <QtCore/QScopedPointer> +#include <QtCore/QTemporaryFile> +#include <QtNetwork/QTcpServer> +#include <QtNetwork/QTcpSocket> +#include <QtNetwork/QLocalSocket> +#include <QtNetwork/QLocalServer> +#include <QtNetwork/QHostInfo> +#include <QtNetwork/QFtp> +#include <QtNetwork/QAbstractNetworkCache> +#include <QtNetwork/qauthenticator.h> +#include <QtNetwork/qnetworkaccessmanager.h> +#include <QtNetwork/qnetworkrequest.h> +#include <QtNetwork/qnetworkreply.h> +#include <QtNetwork/qnetworkcookie.h> +#include <QtNetwork/QHttpPart> +#include <QtNetwork/QHttpMultiPart> +#ifndef QT_NO_OPENSSL +#include <QtNetwork/qsslerror.h> +#include <QtNetwork/qsslconfiguration.h> +#endif +#ifndef QT_NO_BEARERMANAGEMENT +#include <QtNetwork/qnetworkconfigmanager.h> +#include <QtNetwork/qnetworkconfiguration.h> +#include <QtNetwork/qnetworksession.h> +#endif + +#include <time.h> + +#include "private/qnetworkaccessmanager_p.h" + +#ifdef Q_OS_SYMBIAN +#define SRCDIR "." +#endif + +#include "../../../network-settings.h" + +Q_DECLARE_METATYPE(QSharedPointer<char>) +Q_DECLARE_METATYPE(QNetworkReply*) +Q_DECLARE_METATYPE(QAuthenticator*) +Q_DECLARE_METATYPE(QNetworkProxy) +Q_DECLARE_METATYPE(QNetworkProxyQuery) +Q_DECLARE_METATYPE(QList<QNetworkProxy>) +Q_DECLARE_METATYPE(QNetworkReply::NetworkError) +Q_DECLARE_METATYPE(QBuffer*) +Q_DECLARE_METATYPE(QHttpMultiPart *) +Q_DECLARE_METATYPE(QList<QFile*>) // for multiparts +#ifndef QT_NO_OPENSSL +Q_DECLARE_METATYPE(QSslConfiguration) +#endif + +class QNetworkReplyPtr: public QSharedPointer<QNetworkReply> +{ +public: + inline QNetworkReplyPtr(QNetworkReply *ptr = 0) + : QSharedPointer<QNetworkReply>(ptr) + { } + + inline operator QNetworkReply *() const { return data(); } +}; + +class MyCookieJar; +class tst_QNetworkReply: public QObject +{ + Q_OBJECT + + struct ProxyData { + ProxyData(const QNetworkProxy &p, const QByteArray &t, bool auth) + : tag(t), proxy(p), requiresAuthentication(auth) + { } + QByteArray tag; + QNetworkProxy proxy; + bool requiresAuthentication; + }; + + static bool seedCreated; + static QString createUniqueExtension() { + if (!seedCreated) { + qsrand(QTime(0,0,0).msecsTo(QTime::currentTime()) + QCoreApplication::applicationPid()); + seedCreated = true; // not thread-safe, but who cares + } + QString s = QString("%1-%2-%3").arg(QTime(0,0,0).msecsTo(QTime::currentTime())).arg(QCoreApplication::applicationPid()).arg(qrand()); + return s; + }; + + QEventLoop *loop; + enum RunSimpleRequestReturn { Timeout = 0, Success, Failure }; + int returnCode; + QString testFileName; +#if !defined Q_OS_WIN + QString wronlyFileName; +#endif + QString uniqueExtension; + QList<ProxyData> proxies; + QNetworkAccessManager manager; + MyCookieJar *cookieJar; +#ifndef QT_NO_OPENSSL + QSslConfiguration storedSslConfiguration; + QList<QSslError> storedExpectedSslErrors; +#endif +#ifndef QT_NO_BEARERMANAGEMENT + QNetworkConfigurationManager *netConfMan; + QNetworkConfiguration networkConfiguration; + QScopedPointer<QNetworkSession> networkSession; +#endif + +public: + tst_QNetworkReply(); + ~tst_QNetworkReply(); + QString runSimpleRequest(QNetworkAccessManager::Operation op, const QNetworkRequest &request, + QNetworkReplyPtr &reply, const QByteArray &data = QByteArray()); + QString runMultipartRequest(const QNetworkRequest &request, QNetworkReplyPtr &reply, + QHttpMultiPart *multiPart, const QByteArray &verb); + + QString runCustomRequest(const QNetworkRequest &request, QNetworkReplyPtr &reply, + const QByteArray &verb, QIODevice *data); + +public Q_SLOTS: + void finished(); + void gotError(); + void authenticationRequired(QNetworkReply*,QAuthenticator*); + void proxyAuthenticationRequired(const QNetworkProxy &,QAuthenticator*); + +#ifndef QT_NO_OPENSSL + void sslErrors(QNetworkReply*,const QList<QSslError> &); + void storeSslConfiguration(); + void ignoreSslErrorListSlot(QNetworkReply *reply, const QList<QSslError> &); +#endif + +protected Q_SLOTS: + void nestedEventLoops_slot(); + +private Q_SLOTS: + void init(); + void cleanup(); + void initTestCase(); + void cleanupTestCase(); + + void stateChecking(); + void invalidProtocol(); + void getFromData_data(); + void getFromData(); + void getFromFile(); + void getFromFileSpecial_data(); + void getFromFileSpecial(); + void getFromFtp_data(); + void getFromFtp(); + void getFromHttp_data(); + void getFromHttp(); + void getErrors_data(); + void getErrors(); + void putToFile_data(); + void putToFile(); + void putToFtp_data(); + void putToFtp(); + void putToHttp_data(); + void putToHttp(); + void putToHttpSynchronous_data(); + void putToHttpSynchronous(); + void putToHttpMultipart_data(); + void putToHttpMultipart(); + void postToHttp_data(); + void postToHttp(); + void postToHttpSynchronous_data(); + void postToHttpSynchronous(); + void postToHttpMultipart_data(); + void postToHttpMultipart(); + void deleteFromHttp_data(); + void deleteFromHttp(); + void putGetDeleteGetFromHttp_data(); + void putGetDeleteGetFromHttp(); + void sendCustomRequestToHttp_data(); + void sendCustomRequestToHttp(); + void connectToIPv6Address_data(); + void connectToIPv6Address(); + + void ioGetFromData_data(); + void ioGetFromData(); + void ioGetFromFileSpecial_data(); + void ioGetFromFileSpecial(); + void ioGetFromFile_data(); + void ioGetFromFile(); + void ioGetFromFtp_data(); + void ioGetFromFtp(); + void ioGetFromFtpWithReuse(); + void ioGetFromHttp(); + + void ioGetFromBuiltinHttp_data(); + void ioGetFromBuiltinHttp(); + void ioGetFromHttpWithReuseParallel(); + void ioGetFromHttpWithReuseSequential(); + void ioGetFromHttpWithAuth_data(); + void ioGetFromHttpWithAuth(); + void ioGetFromHttpWithAuthSynchronous(); + void ioGetFromHttpWithProxyAuth(); + void ioGetFromHttpWithProxyAuthSynchronous(); + void ioGetFromHttpWithSocksProxy(); +#ifndef QT_NO_OPENSSL + void ioGetFromHttpsWithSslErrors(); + void ioGetFromHttpsWithIgnoreSslErrors(); + void ioGetFromHttpsWithSslHandshakeError(); +#endif + void ioGetFromHttpBrokenServer_data(); + void ioGetFromHttpBrokenServer(); + void ioGetFromHttpStatus100_data(); + void ioGetFromHttpStatus100(); + void ioGetFromHttpNoHeaders_data(); + void ioGetFromHttpNoHeaders(); + void ioGetFromHttpWithCache_data(); + void ioGetFromHttpWithCache(); + + void ioGetWithManyProxies_data(); + void ioGetWithManyProxies(); + + void ioPutToFileFromFile_data(); + void ioPutToFileFromFile(); + void ioPutToFileFromSocket_data(); + void ioPutToFileFromSocket(); + void ioPutToFileFromLocalSocket_data(); + void ioPutToFileFromLocalSocket(); + void ioPutToFileFromProcess_data(); + void ioPutToFileFromProcess(); + void ioPutToFtpFromFile_data(); + void ioPutToFtpFromFile(); + void ioPutToHttpFromFile_data(); + void ioPutToHttpFromFile(); + void ioPostToHttpFromFile_data(); + void ioPostToHttpFromFile(); + void ioPostToHttpFromSocket_data(); + void ioPostToHttpFromSocket(); + void ioPostToHttpFromSocketSynchronous(); + void ioPostToHttpFromSocketSynchronous_data(); + void ioPostToHttpFromMiddleOfFileToEnd(); + void ioPostToHttpFromMiddleOfFileFiveBytes(); + void ioPostToHttpFromMiddleOfQBufferFiveBytes(); + void ioPostToHttpNoBufferFlag(); + void ioPostToHttpUploadProgress(); + void ioPostToHttpEmptyUploadProgress(); + + void lastModifiedHeaderForFile(); + void lastModifiedHeaderForHttp(); + + void httpCanReadLine(); + + void rateControl_data(); + void rateControl(); + + void downloadProgress_data(); + void downloadProgress(); + void uploadProgress_data(); + void uploadProgress(); + + void chaining_data(); + void chaining(); + + void receiveCookiesFromHttp_data(); + void receiveCookiesFromHttp(); + void receiveCookiesFromHttpSynchronous_data(); + void receiveCookiesFromHttpSynchronous(); + void sendCookies_data(); + void sendCookies(); + void sendCookiesSynchronous_data(); + void sendCookiesSynchronous(); + + void nestedEventLoops(); + + void httpProxyCommands_data(); + void httpProxyCommands(); + void httpProxyCommandsSynchronous_data(); + void httpProxyCommandsSynchronous(); + void proxyChange(); + void authorizationError_data(); + void authorizationError(); + + void httpConnectionCount(); + + void httpReUsingConnectionSequential_data(); + void httpReUsingConnectionSequential(); + void httpReUsingConnectionFromFinishedSlot_data(); + void httpReUsingConnectionFromFinishedSlot(); + + void httpRecursiveCreation(); + +#ifndef QT_NO_OPENSSL + void ioPostToHttpsUploadProgress(); + void ignoreSslErrorsList_data(); + void ignoreSslErrorsList(); + void ignoreSslErrorsListWithSlot_data(); + void ignoreSslErrorsListWithSlot(); + void sslConfiguration_data(); + void sslConfiguration(); +#endif + + void getAndThenDeleteObject_data(); + void getAndThenDeleteObject(); + + void symbianOpenCDataUrlCrash(); + + void getFromHttpIntoBuffer_data(); + void getFromHttpIntoBuffer(); + void getFromHttpIntoBuffer2_data(); + void getFromHttpIntoBuffer2(); + void getFromHttpIntoBufferCanReadLine(); + + void ioGetFromHttpWithoutContentLength(); + + void ioGetFromHttpBrokenChunkedEncoding(); + void qtbug12908compressedHttpReply(); + void compressedHttpReplyBrokenGzip(); + + void getFromUnreachableIp(); + + void qtbug4121unknownAuthentication(); + + void qtbug13431replyThrottling(); + + void httpWithNoCredentialUsage(); + + void qtbug15311doubleContentLength(); + + void qtbug18232gzipContentLengthZero(); + + void synchronousRequest_data(); + void synchronousRequest(); +#ifndef QT_NO_OPENSSL + void synchronousRequestSslFailure(); +#endif + + void httpAbort(); + + void dontInsertPartialContentIntoTheCache(); + + void httpUserAgent(); + + // NOTE: This test must be last! + void parentingRepliesToTheApp(); +}; + +bool tst_QNetworkReply::seedCreated = false; + +QT_BEGIN_NAMESPACE + +namespace QTest { + template<> + char *toString(const QNetworkReply::NetworkError& code) + { + const QMetaObject *mo = &QNetworkReply::staticMetaObject; + int index = mo->indexOfEnumerator("NetworkError"); + if (index == -1) + return qstrdup(""); + + QMetaEnum qme = mo->enumerator(index); + return qstrdup(qme.valueToKey(code)); + } + + template<> + char *toString(const QNetworkCookie &cookie) + { + return qstrdup(cookie.toRawForm()); + } + + template<> + char *toString(const QList<QNetworkCookie> &list) + { + QString result = "QList("; + bool first = true; + foreach (QNetworkCookie cookie, list) { + if (!first) + result += ", "; + first = false; + result += QString::fromLatin1("QNetworkCookie(%1)").arg(QLatin1String(cookie.toRawForm())); + } + + return qstrdup(result.append(')').toLocal8Bit()); + } +} + +QT_END_NAMESPACE + +#define RUN_REQUEST(call) \ + do { \ + QString errorMsg = call; \ + if (!errorMsg.isEmpty()) \ + QFAIL(qPrintable(errorMsg)); \ + } while (0); + +#ifndef QT_NO_OPENSSL +static void setupSslServer(QSslSocket* serverSocket) +{ + serverSocket->setProtocol(QSsl::AnyProtocol); + serverSocket->setLocalCertificate(SRCDIR "/certs/server.pem"); + serverSocket->setPrivateKey(SRCDIR "/certs/server.key"); +} +#endif + +// Does not work for POST/PUT! +class MiniHttpServer: public QTcpServer +{ + Q_OBJECT +public: + QTcpSocket *client; // always the last one that was received + QByteArray dataToTransmit; + QByteArray receivedData; + QSemaphore ready; + bool doClose; + bool doSsl; + bool ipv6; + bool multiple; + int totalConnections; + + MiniHttpServer(const QByteArray &data, bool ssl = false, QThread *thread = 0, bool useipv6 = false) + : client(0), dataToTransmit(data), doClose(true), doSsl(ssl), ipv6(useipv6), + multiple(false), totalConnections(0) + { + if (useipv6) { + listen(QHostAddress::AnyIPv6); + } else { + listen(); + } + if (thread) { + connect(thread, SIGNAL(started()), this, SLOT(threadStartedSlot())); + moveToThread(thread); + thread->start(); + ready.acquire(); + } + } + +protected: + void incomingConnection(int socketDescriptor) + { + //qDebug() << "incomingConnection" << socketDescriptor << "doSsl:" << doSsl << "ipv6:" << ipv6; + if (!doSsl) { + client = new QTcpSocket; + client->setSocketDescriptor(socketDescriptor); + connectSocketSignals(); + } else { +#ifndef QT_NO_OPENSSL + QSslSocket *serverSocket = new QSslSocket; + serverSocket->setParent(this); + if (serverSocket->setSocketDescriptor(socketDescriptor)) { + connect(serverSocket, SIGNAL(sslErrors(QList<QSslError>)), this, SLOT(slotSslErrors(QList<QSslError>))); + setupSslServer(serverSocket); + serverSocket->startServerEncryption(); + client = serverSocket; + connectSocketSignals(); + } else { + delete serverSocket; + return; + } +#endif + } + client->setParent(this); + ++totalConnections; + } +private: + void connectSocketSignals() + { + //qDebug() << "connectSocketSignals" << client; + connect(client, SIGNAL(readyRead()), this, SLOT(readyReadSlot())); + connect(client, SIGNAL(bytesWritten(qint64)), this, SLOT(bytesWrittenSlot())); + connect(client, SIGNAL(error(QAbstractSocket::SocketError)), + this, SLOT(slotError(QAbstractSocket::SocketError))); + } + +private slots: +#ifndef QT_NO_OPENSSL + void slotSslErrors(const QList<QSslError>& errors) + { + qDebug() << "slotSslErrors" << client->errorString() << errors; + } +#endif + void slotError(QAbstractSocket::SocketError err) + { + qDebug() << "slotError" << err << client->errorString(); + } + +public slots: + void readyReadSlot() + { + receivedData += client->readAll(); + int doubleEndlPos = receivedData.indexOf("\r\n\r\n"); + + if (doubleEndlPos != -1) { + // multiple requests incoming. remove the bytes of the current one + if (multiple) + receivedData.remove(0, doubleEndlPos+4); + + // we need to emulate the bytesWrittenSlot call if the data is empty. + if (dataToTransmit.size() == 0) + QMetaObject::invokeMethod(this, "bytesWrittenSlot", Qt::QueuedConnection); + else + client->write(dataToTransmit); + } + } + + void bytesWrittenSlot() { + if (doClose && client->bytesToWrite() == 0) { + client->disconnectFromHost(); + disconnect(client, 0, this, 0); + } + } + + void threadStartedSlot() + { + ready.release(); + } +}; + +class MyCookieJar: public QNetworkCookieJar +{ +public: + inline QList<QNetworkCookie> allCookies() const + { return QNetworkCookieJar::allCookies(); } + inline void setAllCookies(const QList<QNetworkCookie> &cookieList) + { QNetworkCookieJar::setAllCookies(cookieList); } +}; + +class MyProxyFactory: public QNetworkProxyFactory +{ +public: + int callCount; + QList<QNetworkProxy> toReturn; + QNetworkProxyQuery lastQuery; + inline MyProxyFactory() { clear(); } + + inline void clear() + { + callCount = 0; + toReturn = QList<QNetworkProxy>() << QNetworkProxy::DefaultProxy; + lastQuery = QNetworkProxyQuery(); + } + + virtual QList<QNetworkProxy> queryProxy(const QNetworkProxyQuery &query) + { + lastQuery = query; + ++callCount; + return toReturn; + } +}; + +class MyMemoryCache: public QAbstractNetworkCache +{ +public: + typedef QPair<QNetworkCacheMetaData, QByteArray> CachedContent; + typedef QHash<QByteArray, CachedContent> CacheData; + CacheData cache; + + MyMemoryCache(QObject *parent) : QAbstractNetworkCache(parent) {} + + QNetworkCacheMetaData metaData(const QUrl &url) + { + return cache.value(url.toEncoded()).first; + } + + void updateMetaData(const QNetworkCacheMetaData &metaData) + { + cache[metaData.url().toEncoded()].first = metaData; + } + + QIODevice *data(const QUrl &url) + { + CacheData::ConstIterator it = cache.find(url.toEncoded()); + if (it == cache.constEnd()) + return 0; + QBuffer *io = new QBuffer(this); + io->setData(it->second); + io->open(QIODevice::ReadOnly); + io->seek(0); + return io; + } + + bool remove(const QUrl &url) + { + cache.remove(url.toEncoded()); + return true; + } + + qint64 cacheSize() const + { + qint64 total = 0; + foreach (const CachedContent &entry, cache) + total += entry.second.size(); + return total; + } + + QIODevice *prepare(const QNetworkCacheMetaData &) + { + qFatal("%s: Should not have tried to add to the cache", Q_FUNC_INFO); + return 0; + } + void insert(QIODevice *) + { + qFatal("%s: Should not have tried to add to the cache", Q_FUNC_INFO); + } + + void clear() { cache.clear(); } +}; +Q_DECLARE_METATYPE(MyMemoryCache::CachedContent) +Q_DECLARE_METATYPE(MyMemoryCache::CacheData) + +class MySpyMemoryCache: public QAbstractNetworkCache +{ +public: + MySpyMemoryCache(QObject *parent) : QAbstractNetworkCache(parent) {} + ~MySpyMemoryCache() + { + qDeleteAll(m_buffers); + m_buffers.clear(); + } + + QHash<QUrl, QIODevice*> m_buffers; + QList<QUrl> m_insertedUrls; + + QNetworkCacheMetaData metaData(const QUrl &) + { + return QNetworkCacheMetaData(); + } + + void updateMetaData(const QNetworkCacheMetaData &) + { + } + + QIODevice *data(const QUrl &) + { + return 0; + } + + bool remove(const QUrl &url) + { + delete m_buffers.take(url); + return m_insertedUrls.removeAll(url) > 0; + } + + qint64 cacheSize() const + { + return 0; + } + + QIODevice *prepare(const QNetworkCacheMetaData &metaData) + { + QBuffer* buffer = new QBuffer; + buffer->open(QIODevice::ReadWrite); + buffer->setProperty("url", metaData.url()); + m_buffers.insert(metaData.url(), buffer); + return buffer; + } + + void insert(QIODevice *buffer) + { + QUrl url = buffer->property("url").toUrl(); + m_insertedUrls << url; + delete m_buffers.take(url); + } + + void clear() { m_insertedUrls.clear(); } +}; + +class DataReader: public QObject +{ + Q_OBJECT +public: + qint64 totalBytes; + QByteArray data; + QIODevice *device; + bool accumulate; + DataReader(QIODevice *dev, bool acc = true) : totalBytes(0), device(dev), accumulate(acc) + { + connect(device, SIGNAL(readyRead()), SLOT(doRead())); + } + +public slots: + void doRead() + { + QByteArray buffer; + buffer.resize(device->bytesAvailable()); + qint64 bytesRead = device->read(buffer.data(), device->bytesAvailable()); + if (bytesRead == -1) { + QTestEventLoop::instance().exitLoop(); + return; + } + buffer.truncate(bytesRead); + totalBytes += bytesRead; + + if (accumulate) + data += buffer; + } +}; + + +class SocketPair: public QObject +{ + Q_OBJECT +public: + QIODevice *endPoints[2]; + + SocketPair(QObject *parent = 0) + : QObject(parent) + { + endPoints[0] = endPoints[1] = 0; + } + + bool create() + { + QTcpServer server; + server.listen(); + + QTcpSocket *active = new QTcpSocket(this); + active->connectToHost("127.0.0.1", server.serverPort()); +#ifndef Q_OS_SYMBIAN + // need more time as working with embedded + // device and testing from emualtor + // things tend to get slower + if (!active->waitForConnected(1000)) + return false; + + if (!server.waitForNewConnection(1000)) + return false; +#else + if (!active->waitForConnected(100)) + return false; + + if (!server.waitForNewConnection(100)) + return false; +#endif + QTcpSocket *passive = server.nextPendingConnection(); + passive->setParent(this); + + endPoints[0] = active; + endPoints[1] = passive; + return true; + } +}; + +// A blocking tcp server (must be used in a thread) which supports SSL. +class BlockingTcpServer : public QTcpServer +{ + Q_OBJECT +public: + BlockingTcpServer(bool ssl) : doSsl(ssl), sslSocket(0) {} + + QTcpSocket* waitForNextConnectionSocket() { + waitForNewConnection(-1); + if (doSsl) { + if (!sslSocket) + qFatal("%s: sslSocket should not be null after calling waitForNewConnection()", + Q_FUNC_INFO); + return sslSocket; + } else { + //qDebug() << "returning nextPendingConnection"; + return nextPendingConnection(); + } + } + virtual void incomingConnection(int socketDescriptor) + { +#ifndef QT_NO_OPENSSL + if (doSsl) { + QSslSocket *serverSocket = new QSslSocket; + serverSocket->setParent(this); + serverSocket->setSocketDescriptor(socketDescriptor); + connect(serverSocket, SIGNAL(sslErrors(QList<QSslError>)), this, SLOT(slotSslErrors(QList<QSslError>))); + setupSslServer(serverSocket); + serverSocket->startServerEncryption(); + sslSocket = serverSocket; + } else +#endif + { + QTcpServer::incomingConnection(socketDescriptor); + } + } +private slots: + +#ifndef QT_NO_OPENSSL + void slotSslErrors(const QList<QSslError>& errors) + { + qDebug() << "slotSslErrors" << sslSocket->errorString() << errors; + } +#endif + +private: + const bool doSsl; + QTcpSocket* sslSocket; +}; + +// This server tries to send data as fast as possible (like most servers) +// but it measures how fast it was able to send it, which shows at which +// rate the reader is processing the data. +class FastSender: public QThread +{ + Q_OBJECT + QSemaphore ready; + qint64 wantedSize; + int port; + enum Protocol { DebugPipe, ProvidedData }; + const Protocol protocol; + const bool doSsl; + const bool fillKernelBuffer; +public: + int transferRate; + QWaitCondition cond; + + QByteArray dataToTransmit; + int dataIndex; + + // a server that sends debugpipe data + FastSender(qint64 size) + : wantedSize(size), port(-1), protocol(DebugPipe), + doSsl(false), fillKernelBuffer(true), transferRate(-1), + dataIndex(0) + { + start(); + ready.acquire(); + } + + // a server that sends the data provided at construction time, useful for HTTP + FastSender(const QByteArray& data, bool https, bool fillBuffer) + : wantedSize(data.size()), port(-1), protocol(ProvidedData), + doSsl(https), fillKernelBuffer(fillBuffer), transferRate(-1), + dataToTransmit(data), dataIndex(0) + { + start(); + ready.acquire(); + } + + inline int serverPort() const { return port; } + + int writeNextData(QTcpSocket* socket, qint32 size) + { + if (protocol == DebugPipe) { + QByteArray data; + QDataStream stream(&data, QIODevice::WriteOnly); + stream << QVariantMap() << QByteArray(size, 'a'); + socket->write((char*)&size, sizeof size); + socket->write(data); + dataIndex += size; + return size; + } else { + const QByteArray data = dataToTransmit.mid(dataIndex, size); + socket->write(data); + dataIndex += data.size(); + //qDebug() << "wrote" << dataIndex << "/" << dataToTransmit.size(); + return data.size(); + } + } + void writeLastData(QTcpSocket* socket) + { + if (protocol == DebugPipe) { + QByteArray data; + QDataStream stream(&data, QIODevice::WriteOnly); + stream << QVariantMap() << QByteArray(); + const qint32 size = data.size(); + socket->write((char*)&size, sizeof size); + socket->write(data); + } + } + +protected: + void run() + { + BlockingTcpServer server(doSsl); + server.listen(); + port = server.serverPort(); + ready.release(); + + QTcpSocket *client = server.waitForNextConnectionSocket(); + + // get the "request" packet + if (!client->waitForReadyRead(2000)) { + qDebug() << "FastSender:" << client->error() << "waiting for \"request\" packet"; + return; + } + client->readAll(); // we're not interested in the actual contents (e.g. HTTP request) + + enum { BlockSize = 1024 }; + + if (fillKernelBuffer) { + + // write a bunch of bytes to fill up the buffers + bool done = false; + do { + if (writeNextData(client, BlockSize) < BlockSize) { + qDebug() << "ERROR: FastSender: not enough data to write in order to fill buffers; or client is reading too fast"; + return; + } + while (client->bytesToWrite() > 0) { + if (!client->waitForBytesWritten(0)) { + done = true; + break; + } + } + //qDebug() << "Filling kernel buffer: wrote" << dataIndex << "bytes"; + } while (!done); + + qDebug() << "FastSender: ok, kernel buffer is full after writing" << dataIndex << "bytes"; + } + + // Tell the client to start reading + emit dataReady(); + + // the kernel buffer is full + // clean up QAbstractSocket's residue: + while (client->bytesToWrite() > 0) { + qDebug() << "Still having" << client->bytesToWrite() << "bytes to write, doing that now"; + if (!client->waitForBytesWritten(2000)) { + qDebug() << "ERROR: FastSender:" << client->error() << "cleaning up residue"; + return; + } + } + + // now write in "blocking mode", this is where the rate measuring starts + QTime timer; + timer.start(); + //const qint64 writtenBefore = dataIndex; + //qint64 measuredTotalBytes = wantedSize - writtenBefore; + qint64 measuredSentBytes = 0; + while (dataIndex < wantedSize) { + const int remainingBytes = wantedSize - measuredSentBytes; + const int bytesToWrite = qMin(remainingBytes, static_cast<int>(BlockSize)); + if (bytesToWrite <= 0) + qFatal("%s: attempt to write %d bytes", Q_FUNC_INFO, bytesToWrite); + measuredSentBytes += writeNextData(client, bytesToWrite); + + while (client->bytesToWrite() > 0) { + if (!client->waitForBytesWritten(2000)) { + qDebug() << "ERROR: FastSender:" << client->error() << "during blocking write"; + return; + } + } + /*qDebug() << "FastSender:" << bytesToWrite << "bytes written now;" + << measuredSentBytes << "measured bytes" << measuredSentBytes + writtenBefore << "total (" + << measuredSentBytes*100/measuredTotalBytes << "% complete);" + << timer.elapsed() << "ms elapsed";*/ + } + + transferRate = measuredSentBytes * 1000 / timer.elapsed(); + qDebug() << "FastSender: flushed" << measuredSentBytes << "bytes in" << timer.elapsed() << "ms: rate =" << transferRate << "B/s"; + + // write a "close connection" packet, if the protocol needs it + writeLastData(client); + } +signals: + void dataReady(); +}; + +class RateControlledReader: public QObject +{ + Q_OBJECT + QIODevice *device; + int bytesToRead; + int interval; + int readBufferSize; +public: + QByteArray data; + qint64 totalBytesRead; + RateControlledReader(QObject& senderObj, QIODevice *dev, int kbPerSec, int maxBufferSize = 0) + : device(dev), readBufferSize(maxBufferSize), totalBytesRead(0) + { + // determine how often we have to wake up + int timesPerSecond; + if (readBufferSize == 0) { + // The requirement is simply "N KB per seconds" + timesPerSecond = 20; + bytesToRead = kbPerSec * 1024 / timesPerSecond; + } else { + // The requirement also includes "<readBufferSize> bytes at a time" + bytesToRead = readBufferSize; + timesPerSecond = kbPerSec * 1024 / readBufferSize; + } + interval = 1000 / timesPerSecond; // in ms + + qDebug() << "RateControlledReader: going to read" << bytesToRead + << "bytes every" << interval << "ms"; + qDebug() << "actual read rate will be" + << (bytesToRead * 1000 / interval) << "bytes/sec (wanted" + << kbPerSec * 1024 << "bytes/sec)"; + + // Wait for data to be readyRead + bool ok = connect(&senderObj, SIGNAL(dataReady()), this, SLOT(slotDataReady())); + if (!ok) + qFatal("%s: Cannot connect dataReady signal", Q_FUNC_INFO); + } + + void wrapUp() + { + QByteArray someData = device->read(device->bytesAvailable()); + data += someData; + totalBytesRead += someData.size(); + qDebug() << "wrapUp: found" << someData.size() << "bytes left. progress" << data.size(); + //qDebug() << "wrapUp: now bytesAvailable=" << device->bytesAvailable(); + } + +private slots: + void slotDataReady() + { + //qDebug() << "RateControlledReader: ready to go"; + startTimer(interval); + } + +protected: + void timerEvent(QTimerEvent *) + { + //qDebug() << "RateControlledReader: timerEvent bytesAvailable=" << device->bytesAvailable(); + if (readBufferSize > 0 && device->bytesAvailable() > readBufferSize) { + // This passes all the time, except in the final flush. + //qFatal("%s: Too many bytes available", Q_FUNC_INFO); + } + + qint64 bytesRead = 0; + QTime stopWatch; + stopWatch.start(); + do { + if (device->bytesAvailable() == 0) { + if (stopWatch.elapsed() > 20) { + qDebug() << "RateControlledReader: Not enough data available for reading, waited too much, timing out"; + break; + } + if (!device->waitForReadyRead(5)) { + qDebug() << "RateControlledReader: Not enough data available for reading, even after waiting 5ms, bailing out"; + break; + } + } + QByteArray someData = device->read(bytesToRead - bytesRead); + data += someData; + bytesRead += someData.size(); + //qDebug() << "RateControlledReader: successfully read" << someData.size() << "progress:" << data.size(); + } while (bytesRead < bytesToRead); + totalBytesRead += bytesRead; + + if (bytesRead < bytesToRead) + qWarning() << "RateControlledReader: WARNING:" << bytesToRead - bytesRead << "bytes not read"; + } +}; + + +tst_QNetworkReply::tst_QNetworkReply() +{ + qRegisterMetaType<QNetworkReply *>(); // for QSignalSpy + qRegisterMetaType<QAuthenticator *>(); + qRegisterMetaType<QNetworkProxy>(); +#ifndef QT_NO_OPENSSL + qRegisterMetaType<QList<QSslError> >(); +#endif + qRegisterMetaType<QNetworkReply::NetworkError>(); + + Q_SET_DEFAULT_IAP + + testFileName = QDir::currentPath() + "/testfile"; + uniqueExtension = createUniqueExtension(); + cookieJar = new MyCookieJar; + manager.setCookieJar(cookieJar); + + QHostInfo hostInfo = QHostInfo::fromName(QtNetworkSettings::serverName()); + + proxies << ProxyData(QNetworkProxy::NoProxy, "", false); + + if (hostInfo.error() == QHostInfo::NoError && !hostInfo.addresses().isEmpty()) { + QString proxyserver = hostInfo.addresses().first().toString(); + proxies << ProxyData(QNetworkProxy(QNetworkProxy::HttpProxy, proxyserver, 3128), "+proxy", false) + << ProxyData(QNetworkProxy(QNetworkProxy::HttpProxy, proxyserver, 3129), "+proxyauth", true) + // currently unsupported + // << ProxyData(QNetworkProxy(QNetworkProxy::HttpProxy, proxyserver, 3130), "+proxyauth-ntlm", true); + << ProxyData(QNetworkProxy(QNetworkProxy::Socks5Proxy, proxyserver, 1080), "+socks", false) + << ProxyData(QNetworkProxy(QNetworkProxy::Socks5Proxy, proxyserver, 1081), "+socksauth", true); + } else { + printf("==================================================================\n"); + printf("Proxy could not be looked up. No proxy will be used while testing!\n"); + printf("==================================================================\n"); + } +} + +tst_QNetworkReply::~tst_QNetworkReply() +{ +} + + +void tst_QNetworkReply::authenticationRequired(QNetworkReply*, QAuthenticator* auth) +{ + auth->setUser("httptest"); + auth->setPassword("httptest"); +} + +void tst_QNetworkReply::proxyAuthenticationRequired(const QNetworkProxy &, QAuthenticator* auth) +{ + auth->setUser("qsockstest"); + auth->setPassword("password"); +} + +#ifndef QT_NO_OPENSSL +void tst_QNetworkReply::sslErrors(QNetworkReply *reply, const QList<QSslError> &errors) +{ + reply->ignoreSslErrors(); + QVERIFY(!errors.isEmpty()); + QVERIFY(!reply->sslConfiguration().isNull()); +} + +void tst_QNetworkReply::storeSslConfiguration() +{ + storedSslConfiguration = QSslConfiguration(); + QNetworkReply *reply = qobject_cast<QNetworkReply *>(sender()); + if (reply) + storedSslConfiguration = reply->sslConfiguration(); +} +#endif + +QString tst_QNetworkReply::runMultipartRequest(const QNetworkRequest &request, + QNetworkReplyPtr &reply, + QHttpMultiPart *multiPart, + const QByteArray &verb) +{ + if (verb == "POST") + reply = manager.post(request, multiPart); + else + reply = manager.put(request, multiPart); + + // the code below is copied from tst_QNetworkReply::runSimpleRequest, see below + reply->setParent(this); + connect(reply, SIGNAL(finished()), SLOT(finished())); + connect(reply, SIGNAL(error(QNetworkReply::NetworkError)), SLOT(gotError())); + multiPart->setParent(reply); + + returnCode = Timeout; + loop = new QEventLoop; + QTimer::singleShot(25000, loop, SLOT(quit())); + int code = returnCode == Timeout ? loop->exec() : returnCode; + delete loop; + loop = 0; + + switch (code) { + case Failure: + return "Request failed: " + reply->errorString(); + case Timeout: + return "Network timeout"; + } + return QString(); +} + +QString tst_QNetworkReply::runSimpleRequest(QNetworkAccessManager::Operation op, + const QNetworkRequest &request, + QNetworkReplyPtr &reply, + const QByteArray &data) +{ + switch (op) { + case QNetworkAccessManager::HeadOperation: + reply = manager.head(request); + break; + + case QNetworkAccessManager::GetOperation: + reply = manager.get(request); + break; + + case QNetworkAccessManager::PutOperation: + reply = manager.put(request, data); + break; + + case QNetworkAccessManager::PostOperation: + reply = manager.post(request, data); + break; + + case QNetworkAccessManager::DeleteOperation: + reply = manager.deleteResource(request); + break; + + default: + qFatal("%s: Invalid/unknown operation requested", Q_FUNC_INFO); + } + reply->setParent(this); + + returnCode = Timeout; + int code = Success; + + if (request.attribute(QNetworkRequest::SynchronousRequestAttribute).toBool()) { + if (reply->isFinished()) + code = reply->error() != QNetworkReply::NoError ? Failure : Success; + else + code = Failure; + } else { + connect(reply, SIGNAL(finished()), SLOT(finished())); + connect(reply, SIGNAL(error(QNetworkReply::NetworkError)), SLOT(gotError())); + + loop = new QEventLoop; + QTimer::singleShot(20000, loop, SLOT(quit())); + code = returnCode == Timeout ? loop->exec() : returnCode; + delete loop; + loop = 0; + } + + switch (code) { + case Failure: + return "Request failed: " + reply->errorString(); + case Timeout: + return "Network timeout"; + } + return QString(); +} + +QString tst_QNetworkReply::runCustomRequest(const QNetworkRequest &request, + QNetworkReplyPtr &reply, + const QByteArray &verb, + QIODevice *data) +{ + reply = manager.sendCustomRequest(request, verb, data); + reply->setParent(this); + connect(reply, SIGNAL(finished()), SLOT(finished())); + connect(reply, SIGNAL(error(QNetworkReply::NetworkError)), SLOT(gotError())); + + returnCode = Timeout; + loop = new QEventLoop; + QTimer::singleShot(20000, loop, SLOT(quit())); + int code = returnCode == Timeout ? loop->exec() : returnCode; + delete loop; + loop = 0; + + switch (code) { + case Failure: + return "Request failed: " + reply->errorString(); + case Timeout: + return "Network timeout"; + } + return QString(); +} + +void tst_QNetworkReply::finished() +{ + loop->exit(returnCode = Success); +} + +void tst_QNetworkReply::gotError() +{ + loop->exit(returnCode = Failure); + disconnect(QObject::sender(), SIGNAL(finished()), this, 0); +} + +void tst_QNetworkReply::initTestCase() +{ +#if !defined Q_OS_WIN + wronlyFileName = QDir::currentPath() + "/write-only"; + QFile wr(wronlyFileName); + QVERIFY(wr.open(QIODevice::WriteOnly | QIODevice::Truncate)); + wr.setPermissions(QFile::WriteOwner | QFile::WriteUser); + wr.close(); +#endif + + QDir::setSearchPaths("srcdir", QStringList() << SRCDIR); +#ifndef QT_NO_OPENSSL + QSslSocket::defaultCaCertificates(); //preload certificates +#endif +#ifndef QT_NO_BEARERMANAGEMENT + netConfMan = new QNetworkConfigurationManager(this); + networkConfiguration = netConfMan->defaultConfiguration(); + networkSession.reset(new QNetworkSession(networkConfiguration)); + if (!networkSession->isOpen()) { + networkSession->open(); + QVERIFY(networkSession->waitForOpened(30000)); + } +#endif +} + +void tst_QNetworkReply::cleanupTestCase() +{ +#if !defined Q_OS_WIN + QFile::remove(wronlyFileName); +#endif + if (networkSession && networkSession->isOpen()) { + networkSession->close(); + } +} + +void tst_QNetworkReply::init() +{ + cleanup(); +} + +void tst_QNetworkReply::cleanup() +{ + QFile file(testFileName); + QVERIFY(!file.exists() || file.remove()); + + // clear the internal cache + manager.clearAccessCache(); + manager.setProxy(QNetworkProxy()); + manager.setCache(0); + + // clear cookies + cookieJar->setAllCookies(QList<QNetworkCookie>()); +} + +void tst_QNetworkReply::stateChecking() +{ + QUrl url = QUrl("file:///"); + QNetworkRequest req(url); // you can't open this file, I know + QNetworkReplyPtr reply = manager.get(req); + + QVERIFY(reply.data()); + QVERIFY(reply->isOpen()); + QVERIFY(reply->isReadable()); + QVERIFY(!reply->isWritable()); + + // both behaviours are OK since we might change underlying behaviour again + if (!reply->isFinished()) + QCOMPARE(reply->errorString(), QString("Unknown error")); + else + QVERIFY(!reply->errorString().isEmpty()); + + + QCOMPARE(reply->manager(), &manager); + QCOMPARE(reply->request(), req); + QCOMPARE(int(reply->operation()), int(QNetworkAccessManager::GetOperation)); + // error and not error are OK since we might change underlying behaviour again + if (!reply->isFinished()) + QCOMPARE(reply->error(), QNetworkReply::NoError); + QCOMPARE(reply->url(), url); + + reply->abort(); +} + +void tst_QNetworkReply::invalidProtocol() +{ + QUrl url = QUrl::fromEncoded("not-a-known-protocol://foo/bar"); + QNetworkRequest req(url); + QNetworkReplyPtr reply; + + QString errorMsg = "Request failed: Protocol \"not-a-known-protocol\" is unknown"; + QString result = runSimpleRequest(QNetworkAccessManager::GetOperation, req, reply); + QCOMPARE(result, errorMsg); + + QCOMPARE(reply->url(), url); + QCOMPARE(reply->error(), QNetworkReply::ProtocolUnknownError); +} + +void tst_QNetworkReply::getFromData_data() +{ + QTest::addColumn<QString>("request"); + QTest::addColumn<QByteArray>("expected"); + QTest::addColumn<QString>("mimeType"); + + const QString defaultMimeType("text/plain;charset=US-ASCII"); + + //QTest::newRow("empty") << "data:" << QByteArray() << defaultMimeType; + QTest::newRow("empty2") << "data:," << QByteArray() << defaultMimeType; + QTest::newRow("just-charset_1") << "data:charset=iso-8859-1," + << QByteArray() << "text/plain;charset=iso-8859-1"; + QTest::newRow("just-charset_2") << "data:charset = iso-8859-1 ," + << QByteArray() << "text/plain;charset = iso-8859-1"; + //QTest::newRow("just-media") << "data:text/xml" << QByteArray() << "text/xml"; + QTest::newRow("just-media2") << "data:text/xml," << QByteArray() << "text/xml"; + + QTest::newRow("plain_1") << "data:,foo" << QByteArray("foo") << defaultMimeType; + QTest::newRow("plain_2") << "data:text/html,Hello World" << QByteArray("Hello World") + << "text/html"; + QTest::newRow("plain_3") << "data:text/html;charset=utf-8,Hello World" + << QByteArray("Hello World") << "text/html;charset=utf-8"; + + QTest::newRow("pct_1") << "data:,%3Cbody%20contentEditable%3Dtrue%3E%0D%0A" + << QByteArray("<body contentEditable=true>\r\n") << defaultMimeType; + QTest::newRow("pct_2") << "data:text/html;charset=utf-8,%3Cbody%20contentEditable%3Dtrue%3E%0D%0A" + << QByteArray("<body contentEditable=true>\r\n") + << "text/html;charset=utf-8"; + + QTest::newRow("base64-empty_1") << "data:;base64," << QByteArray() << defaultMimeType; + QTest::newRow("base64-empty_2") << "data:charset=utf-8;base64," << QByteArray() + << "text/plain;charset=utf-8"; + QTest::newRow("base64-empty_3") << "data:text/html;charset=utf-8;base64," + << QByteArray() << "text/html;charset=utf-8"; + + QTest::newRow("base64_1") << "data:;base64,UXQgaXMgZ3JlYXQh" << QByteArray("Qt is great!") + << defaultMimeType; + QTest::newRow("base64_2") << "data:charset=utf-8;base64,UXQgaXMgZ3JlYXQh" + << QByteArray("Qt is great!") << "text/plain;charset=utf-8"; + QTest::newRow("base64_3") << "data:text/html;charset=utf-8;base64,UXQgaXMgZ3JlYXQh" + << QByteArray("Qt is great!") << "text/html;charset=utf-8"; + + QTest::newRow("pct-nul") << "data:,a%00g" << QByteArray("a\0g", 3) << defaultMimeType; + QTest::newRow("base64-nul") << "data:;base64,YQBn" << QByteArray("a\0g", 3) << defaultMimeType; + QTest::newRow("pct-nonutf8") << "data:,a%E1g" << QByteArray("a\xE1g", 3) << defaultMimeType; + + QTest::newRow("base64") + << QString::fromLatin1("data:application/xml;base64,PGUvPg==") + << QByteArray("<e/>") + << "application/xml"; + + QTest::newRow("base64, no media type") + << QString::fromLatin1("data:;base64,PGUvPg==") + << QByteArray("<e/>") + << defaultMimeType; + + QTest::newRow("Percent encoding") + << QString::fromLatin1("data:application/xml,%3Ce%2F%3E") + << QByteArray("<e/>") + << "application/xml"; + + QTest::newRow("Percent encoding, no media type") + << QString::fromLatin1("data:,%3Ce%2F%3E") + << QByteArray("<e/>") + << defaultMimeType; + + QTest::newRow("querychars") + << QString::fromLatin1("data:,foo?x=0&y=0") + << QByteArray("foo?x=0&y=0") + << defaultMimeType; + + QTest::newRow("css") << "data:text/css,div%20{%20border-right:%20solid;%20}" + << QByteArray("div { border-right: solid; }") + << "text/css"; +} + +void tst_QNetworkReply::getFromData() +{ + QFETCH(QString, request); + QFETCH(QByteArray, expected); + QFETCH(QString, mimeType); + + QUrl url = QUrl::fromEncoded(request.toLatin1()); + QNetworkRequest req(url); + QNetworkReplyPtr reply; + + RUN_REQUEST(runSimpleRequest(QNetworkAccessManager::GetOperation, req, reply)); + + QCOMPARE(reply->url(), url); + QCOMPARE(reply->error(), QNetworkReply::NoError); + + QCOMPARE(reply->header(QNetworkRequest::ContentTypeHeader).toString(), mimeType); + QCOMPARE(reply->header(QNetworkRequest::ContentLengthHeader).toLongLong(), qint64(expected.size())); + QCOMPARE(reply->readAll(), expected); +} + +void tst_QNetworkReply::getFromFile() +{ + // create the file: + QTemporaryFile file(QDir::currentPath() + "/temp-XXXXXX"); + file.setAutoRemove(true); + QVERIFY(file.open()); + + QNetworkRequest request(QUrl::fromLocalFile(file.fileName())); + QNetworkReplyPtr reply; + + static const char fileData[] = "This is some data that is in the file.\r\n"; + QByteArray data = QByteArray::fromRawData(fileData, sizeof fileData - 1); + QVERIFY(file.write(data) == data.size()); + file.flush(); + QCOMPARE(file.size(), qint64(data.size())); + + RUN_REQUEST(runSimpleRequest(QNetworkAccessManager::GetOperation, request, reply)); + + QCOMPARE(reply->url(), request.url()); + QCOMPARE(reply->error(), QNetworkReply::NoError); + + QCOMPARE(reply->header(QNetworkRequest::ContentLengthHeader).toLongLong(), file.size()); + QCOMPARE(reply->readAll(), data); + + // make the file bigger + file.resize(0); + const int multiply = (128 * 1024) / (sizeof fileData - 1); + for (int i = 0; i < multiply; ++i) + file.write(fileData, sizeof fileData - 1); + file.flush(); + + // run again + reply = 0; + + RUN_REQUEST(runSimpleRequest(QNetworkAccessManager::GetOperation, request, reply)); + QCOMPARE(reply->url(), request.url()); + QCOMPARE(reply->error(), QNetworkReply::NoError); + + QCOMPARE(reply->header(QNetworkRequest::ContentLengthHeader).toLongLong(), file.size()); + QCOMPARE(qint64(reply->readAll().size()), file.size()); +} + +void tst_QNetworkReply::getFromFileSpecial_data() +{ + QTest::addColumn<QString>("fileName"); + QTest::addColumn<QString>("url"); + + QTest::newRow("resource") << ":/resource" << "qrc:/resource"; + QTest::newRow("search-path") << "srcdir:/rfc3252.txt" << "srcdir:/rfc3252.txt"; + QTest::newRow("bigfile-path") << "srcdir:/bigfile" << "srcdir:/bigfile"; +#ifdef Q_OS_WIN + QTest::newRow("smb-path") << "srcdir:/smb-file.txt" << "file://" + QtNetworkSettings::winServerName() + "/testshare/test.pri"; +#endif +} + +void tst_QNetworkReply::getFromFileSpecial() +{ + QFETCH(QString, fileName); + QFETCH(QString, url); + + // open the resource so we can find out its size + QFile resource(fileName); + QVERIFY(resource.open(QIODevice::ReadOnly)); + + QNetworkRequest request; + QNetworkReplyPtr reply; + request.setUrl(url); + RUN_REQUEST(runSimpleRequest(QNetworkAccessManager::GetOperation, request, reply)); + + QCOMPARE(reply->url(), request.url()); + QCOMPARE(reply->error(), QNetworkReply::NoError); + + QCOMPARE(reply->header(QNetworkRequest::ContentLengthHeader).toLongLong(), resource.size()); + QCOMPARE(reply->readAll(), resource.readAll()); +} + +void tst_QNetworkReply::getFromFtp_data() +{ + QTest::addColumn<QString>("referenceName"); + QTest::addColumn<QString>("url"); + + QTest::newRow("rfc3252.txt") << SRCDIR "/rfc3252.txt" << "ftp://" + QtNetworkSettings::serverName() + "/qtest/rfc3252.txt"; + QTest::newRow("bigfile") << SRCDIR "/bigfile" << "ftp://" + QtNetworkSettings::serverName() + "/qtest/bigfile"; +} + +void tst_QNetworkReply::getFromFtp() +{ + QFETCH(QString, referenceName); + QFETCH(QString, url); + + QFile reference(referenceName); + QVERIFY(reference.open(QIODevice::ReadOnly)); + + QNetworkRequest request(url); + QNetworkReplyPtr reply; + RUN_REQUEST(runSimpleRequest(QNetworkAccessManager::GetOperation, request, reply)); + + QCOMPARE(reply->url(), request.url()); + QCOMPARE(reply->error(), QNetworkReply::NoError); + + QCOMPARE(reply->header(QNetworkRequest::ContentLengthHeader).toLongLong(), reference.size()); + QCOMPARE(reply->readAll(), reference.readAll()); +} + +void tst_QNetworkReply::getFromHttp_data() +{ + QTest::addColumn<QString>("referenceName"); + QTest::addColumn<QString>("url"); + + QTest::newRow("success-internal") << SRCDIR "/rfc3252.txt" << "http://" + QtNetworkSettings::serverName() + "/qtest/rfc3252.txt"; + QTest::newRow("success-external") << SRCDIR "/rfc3252.txt" << "http://www.ietf.org/rfc/rfc3252.txt"; + QTest::newRow("bigfile-internal") << SRCDIR "/bigfile" << "http://" + QtNetworkSettings::serverName() + "/qtest/bigfile"; +} + +void tst_QNetworkReply::getFromHttp() +{ + QFETCH(QString, referenceName); + QFETCH(QString, url); + + QFile reference(referenceName); + QVERIFY(reference.open(QIODevice::ReadOnly)); + + QNetworkRequest request(url); + QNetworkReplyPtr reply; + RUN_REQUEST(runSimpleRequest(QNetworkAccessManager::GetOperation, request, reply)); + + QCOMPARE(reply->url(), request.url()); + QCOMPARE(reply->error(), QNetworkReply::NoError); + QCOMPARE(reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(), 200); + QCOMPARE(reply->size(), reference.size()); + // only compare when the header is set. + if (reply->header(QNetworkRequest::ContentLengthHeader).isValid()) + QCOMPARE(reply->header(QNetworkRequest::ContentLengthHeader).toLongLong(), reference.size()); + + // We know our internal server is apache.. + if (qstrcmp(QTest::currentDataTag(), "success-internal") == 0) + QVERIFY(reply->header(QNetworkRequest::ServerHeader).toString().contains("Apache")); + + QCOMPARE(reply->readAll(), reference.readAll()); +} + +void tst_QNetworkReply::getErrors_data() +{ + QTest::addColumn<QString>("url"); + QTest::addColumn<int>("error"); + QTest::addColumn<int>("httpStatusCode"); + QTest::addColumn<bool>("dataIsEmpty"); + + // empties + QTest::newRow("empty-url") << QString() << int(QNetworkReply::ProtocolUnknownError) << 0 << true; + QTest::newRow("empty-scheme-host") << SRCDIR "/rfc3252.txt" << int(QNetworkReply::ProtocolUnknownError) << 0 << true; + QTest::newRow("empty-scheme") << "//" + QtNetworkSettings::winServerName() + "/testshare/test.pri" + << int(QNetworkReply::ProtocolUnknownError) << 0 << true; + + // file: errors + QTest::newRow("file-host") << "file://this-host-doesnt-exist.troll.no/foo.txt" +#if !defined Q_OS_WIN + << int(QNetworkReply::ProtocolInvalidOperationError) << 0 << true; +#else + << int(QNetworkReply::ContentNotFoundError) << 0 << true; +#endif + QTest::newRow("file-no-path") << "file://localhost" + << int(QNetworkReply::ContentOperationNotPermittedError) << 0 << true; + QTest::newRow("file-is-dir") << QUrl::fromLocalFile(QDir::currentPath()).toString() + << int(QNetworkReply::ContentOperationNotPermittedError) << 0 << true; + QTest::newRow("file-exist") << QUrl::fromLocalFile(QDir::currentPath() + "/this-file-doesnt-exist.txt").toString() + << int(QNetworkReply::ContentNotFoundError) << 0 << true; +#if !defined Q_OS_WIN && !defined(Q_OS_SYMBIAN) + QTest::newRow("file-is-wronly") << QUrl::fromLocalFile(wronlyFileName).toString() + << int(QNetworkReply::ContentAccessDenied) << 0 << true; +#endif + if (QFile::exists("/etc/shadow")) + QTest::newRow("file-permissions") << "file:/etc/shadow" + << int(QNetworkReply::ContentAccessDenied) << 0 << true; + + // ftp: errors + QTest::newRow("ftp-host") << "ftp://this-host-doesnt-exist.troll.no/foo.txt" + << int(QNetworkReply::HostNotFoundError) << 0 << true; + QTest::newRow("ftp-no-path") << "ftp://" + QtNetworkSettings::serverName() + << int(QNetworkReply::ContentOperationNotPermittedError) << 0 << true; + QTest::newRow("ftp-is-dir") << "ftp://" + QtNetworkSettings::serverName() + "/qtest" + << int(QNetworkReply::ContentOperationNotPermittedError) << 0 << true; + QTest::newRow("ftp-dir-not-readable") << "ftp://" + QtNetworkSettings::serverName() + "/pub/dir-not-readable/foo.txt" + << int(QNetworkReply::ContentAccessDenied) << 0 << true; + QTest::newRow("ftp-file-not-readable") << "ftp://" + QtNetworkSettings::serverName() + "/pub/file-not-readable.txt" + << int(QNetworkReply::ContentAccessDenied) << 0 << true; + QTest::newRow("ftp-exist") << "ftp://" + QtNetworkSettings::serverName() + "/pub/this-file-doesnt-exist.txt" + << int(QNetworkReply::ContentNotFoundError) << 0 << true; + + // http: errors + QTest::newRow("http-host") << "http://this-host-will-never-exist.troll.no/" + << int(QNetworkReply::HostNotFoundError) << 0 << true; + QTest::newRow("http-exist") << "http://" + QtNetworkSettings::serverName() + "/this-file-doesnt-exist.txt" + << int(QNetworkReply::ContentNotFoundError) << 404 << false; + QTest::newRow("http-authentication") << "http://" + QtNetworkSettings::serverName() + "/qtest/rfcs-auth" + << int(QNetworkReply::AuthenticationRequiredError) << 401 << false; +} + +void tst_QNetworkReply::getErrors() +{ + QFETCH(QString, url); + QNetworkRequest request(url); + + QNetworkReplyPtr reply = manager.get(request); + reply->setParent(this); // we have expect-fails + + if (!reply->isFinished()) + QCOMPARE(reply->error(), QNetworkReply::NoError); + + // now run the request: + connect(reply, SIGNAL(finished()), + &QTestEventLoop::instance(), SLOT(exitLoop())); + QTestEventLoop::instance().enterLoop(10); + QVERIFY(!QTestEventLoop::instance().timeout()); + //qDebug() << reply->errorString(); + + QFETCH(int, error); + QEXPECT_FAIL("ftp-is-dir", "QFtp cannot provide enough detail", Abort); + // the line below is not necessary + QEXPECT_FAIL("ftp-dir-not-readable", "QFtp cannot provide enough detail", Abort); + QCOMPARE(reply->error(), QNetworkReply::NetworkError(error)); + + QTEST(reply->readAll().isEmpty(), "dataIsEmpty"); + + QVERIFY(reply->isFinished()); + QVERIFY(!reply->isRunning()); + + QFETCH(int, httpStatusCode); + if (httpStatusCode != 0) { + QCOMPARE(reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(), httpStatusCode); + } +} + +static inline QByteArray md5sum(const QByteArray &data) +{ + return QCryptographicHash::hash(data, QCryptographicHash::Md5); +} + +void tst_QNetworkReply::putToFile_data() +{ + QTest::addColumn<QByteArray>("data"); + QTest::addColumn<QByteArray>("md5sum"); + + QByteArray data; + data = ""; + QTest::newRow("empty") << data << md5sum(data); + + data = "This is a normal message."; + QTest::newRow("generic") << data << md5sum(data); + + data = "This is a message to show that Qt rocks!\r\n\n"; + QTest::newRow("small") << data << md5sum(data); + + data = QByteArray("abcd\0\1\2\abcd",12); + QTest::newRow("with-nul") << data << md5sum(data); + + data = QByteArray(4097, '\4'); + QTest::newRow("4k+1") << data << md5sum(data); + + data = QByteArray(128*1024+1, '\177'); + QTest::newRow("128k+1") << data << md5sum(data); + + data = QByteArray(2*1024*1024+1, '\177'); + QTest::newRow("2MB+1") << data << md5sum(data); +} + +void tst_QNetworkReply::putToFile() +{ + QFile file(testFileName); + + QUrl url = QUrl::fromLocalFile(file.fileName()); + QNetworkRequest request(url); + QNetworkReplyPtr reply; + + QFETCH(QByteArray, data); + + RUN_REQUEST(runSimpleRequest(QNetworkAccessManager::PutOperation, request, reply, data)); + + QCOMPARE(reply->url(), url); + QCOMPARE(reply->error(), QNetworkReply::NoError); + QCOMPARE(reply->header(QNetworkRequest::ContentLengthHeader).toLongLong(), Q_INT64_C(0)); + QVERIFY(reply->readAll().isEmpty()); + + QVERIFY(file.open(QIODevice::ReadOnly)); + QCOMPARE(file.size(), qint64(data.size())); + QByteArray contents = file.readAll(); + QCOMPARE(contents, data); +} + +void tst_QNetworkReply::putToFtp_data() +{ + putToFile_data(); +} + +void tst_QNetworkReply::putToFtp() +{ + QUrl url("ftp://" + QtNetworkSettings::serverName()); + url.setPath(QString("/qtest/upload/qnetworkaccess-putToFtp-%1-%2") + .arg(QTest::currentDataTag()) + .arg(uniqueExtension)); + + QNetworkRequest request(url); + QNetworkReplyPtr reply; + + QFETCH(QByteArray, data); + + RUN_REQUEST(runSimpleRequest(QNetworkAccessManager::PutOperation, request, reply, data)); + + QCOMPARE(reply->url(), url); + QCOMPARE(reply->error(), QNetworkReply::NoError); + QCOMPARE(reply->header(QNetworkRequest::ContentLengthHeader).toLongLong(), Q_INT64_C(0)); + QVERIFY(reply->readAll().isEmpty()); + + // download the file again from FTP to make sure it was uploaded + // correctly + QFtp ftp; + ftp.connectToHost(url.host()); + ftp.login(); + ftp.get(url.path()); + + QObject::connect(&ftp, SIGNAL(done(bool)), &QTestEventLoop::instance(), SLOT(exitLoop())); + QTestEventLoop::instance().enterLoop(10); + QObject::disconnect(&ftp, SIGNAL(done(bool)), &QTestEventLoop::instance(), SLOT(exitLoop())); + + QByteArray uploaded = ftp.readAll(); + QCOMPARE(uploaded.size(), data.size()); + QCOMPARE(uploaded, data); + + ftp.close(); + QObject::connect(&ftp, SIGNAL(done(bool)), &QTestEventLoop::instance(), SLOT(exitLoop())); + QTestEventLoop::instance().enterLoop(10); + QObject::disconnect(&ftp, SIGNAL(done(bool)), &QTestEventLoop::instance(), SLOT(exitLoop())); +} + +void tst_QNetworkReply::putToHttp_data() +{ + putToFile_data(); +} + +void tst_QNetworkReply::putToHttp() +{ + QUrl url("http://" + QtNetworkSettings::serverName()); + url.setPath(QString("/dav/qnetworkaccess-putToHttp-%1-%2") + .arg(QTest::currentDataTag()) + .arg(uniqueExtension)); + + QNetworkRequest request(url); + QNetworkReplyPtr reply; + + QFETCH(QByteArray, data); + + RUN_REQUEST(runSimpleRequest(QNetworkAccessManager::PutOperation, request, reply, data)); + + QCOMPARE(reply->url(), url); + QCOMPARE(reply->error(), QNetworkReply::NoError); + + QCOMPARE(reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(), 201); // 201 Created + + // download the file again from HTTP to make sure it was uploaded + // correctly. HTTP/0.9 is enough + QTcpSocket socket; + socket.connectToHost(QtNetworkSettings::serverName(), 80); + socket.write("GET " + url.toEncoded(QUrl::RemoveScheme | QUrl::RemoveAuthority) + "\r\n"); + if (!socket.waitForDisconnected(10000)) + QFAIL("Network timeout"); + + QByteArray uploadedData = socket.readAll(); + QCOMPARE(uploadedData, data); +} + +void tst_QNetworkReply::putToHttpSynchronous_data() +{ + uniqueExtension = createUniqueExtension(); + putToFile_data(); +} + +void tst_QNetworkReply::putToHttpSynchronous() +{ + QUrl url("http://" + QtNetworkSettings::serverName()); + url.setPath(QString("/dav/qnetworkaccess-putToHttp-%1-%2") + .arg(QTest::currentDataTag()) + .arg(uniqueExtension)); + + QNetworkRequest request(url); + QNetworkReplyPtr reply; + + QFETCH(QByteArray, data); + + request.setAttribute( + QNetworkRequest::SynchronousRequestAttribute, + true); + + RUN_REQUEST(runSimpleRequest(QNetworkAccessManager::PutOperation, request, reply, data)); + + QCOMPARE(reply->url(), url); + QCOMPARE(reply->error(), QNetworkReply::NoError); + + QCOMPARE(reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(), 201); // 201 Created + + // download the file again from HTTP to make sure it was uploaded + // correctly. HTTP/0.9 is enough + QTcpSocket socket; + socket.connectToHost(QtNetworkSettings::serverName(), 80); + socket.write("GET " + url.toEncoded(QUrl::RemoveScheme | QUrl::RemoveAuthority) + "\r\n"); + if (!socket.waitForDisconnected(10000)) + QFAIL("Network timeout"); + + QByteArray uploadedData = socket.readAll(); + QCOMPARE(uploadedData, data); +} + +void tst_QNetworkReply::postToHttp_data() +{ + putToFile_data(); +} + +void tst_QNetworkReply::postToHttp() +{ + QUrl url("http://" + QtNetworkSettings::serverName() + "/qtest/cgi-bin/md5sum.cgi"); + + QNetworkRequest request(url); + request.setRawHeader("Content-Type", "application/octet-stream"); + QNetworkReplyPtr reply; + + QFETCH(QByteArray, data); + + RUN_REQUEST(runSimpleRequest(QNetworkAccessManager::PostOperation, request, reply, data)); + + QCOMPARE(reply->url(), url); + QCOMPARE(reply->error(), QNetworkReply::NoError); + + QCOMPARE(reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(), 200); // 200 Ok + + QFETCH(QByteArray, md5sum); + QByteArray uploadedData = reply->readAll().trimmed(); + QCOMPARE(uploadedData, md5sum.toHex()); +} + +void tst_QNetworkReply::postToHttpSynchronous_data() +{ + putToFile_data(); +} + +void tst_QNetworkReply::postToHttpSynchronous() +{ + QUrl url("http://" + QtNetworkSettings::serverName() + "/qtest/cgi-bin/md5sum.cgi"); + + QNetworkRequest request(url); + request.setRawHeader("Content-Type", "application/octet-stream"); + + request.setAttribute( + QNetworkRequest::SynchronousRequestAttribute, + true); + + QNetworkReplyPtr reply; + + QFETCH(QByteArray, data); + + RUN_REQUEST(runSimpleRequest(QNetworkAccessManager::PostOperation, request, reply, data)); + + QCOMPARE(reply->url(), url); + QCOMPARE(reply->error(), QNetworkReply::NoError); + + QCOMPARE(reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(), 200); // 200 Ok + + QFETCH(QByteArray, md5sum); + QByteArray uploadedData = reply->readAll().trimmed(); + QCOMPARE(uploadedData, md5sum.toHex()); +} + +void tst_QNetworkReply::postToHttpMultipart_data() +{ + QTest::addColumn<QUrl>("url"); + QTest::addColumn<QHttpMultiPart *>("multiPart"); + QTest::addColumn<QByteArray>("expectedReplyData"); + QTest::addColumn<QByteArray>("contentType"); + + QUrl url("http://" + QtNetworkSettings::serverName() + "/qtest/cgi-bin/multipart.cgi"); + QByteArray expectedData; + + + // empty parts + + QHttpMultiPart *emptyMultiPart = new QHttpMultiPart; + QTest::newRow("empty") << url << emptyMultiPart << expectedData << QByteArray("mixed"); + + QHttpMultiPart *emptyRelatedMultiPart = new QHttpMultiPart; + emptyRelatedMultiPart->setContentType(QHttpMultiPart::RelatedType); + QTest::newRow("empty-related") << url << emptyRelatedMultiPart << expectedData << QByteArray("related"); + + QHttpMultiPart *emptyAlternativeMultiPart = new QHttpMultiPart; + emptyAlternativeMultiPart->setContentType(QHttpMultiPart::AlternativeType); + QTest::newRow("empty-alternative") << url << emptyAlternativeMultiPart << expectedData << QByteArray("alternative"); + + + // text-only parts + + QHttpPart textPart; + textPart.setHeader(QNetworkRequest::ContentTypeHeader, QVariant("text/plain")); + textPart.setHeader(QNetworkRequest::ContentDispositionHeader, QVariant("form-data; name=\"text\"")); + textPart.setBody("7 bytes"); + QHttpMultiPart *multiPart1 = new QHttpMultiPart; + multiPart1->setContentType(QHttpMultiPart::FormDataType); + multiPart1->append(textPart); + expectedData = "key: text, value: 7 bytes\n"; + QTest::newRow("text") << url << multiPart1 << expectedData << QByteArray("form-data"); + + QHttpMultiPart *customMultiPart = new QHttpMultiPart; + customMultiPart->append(textPart); + expectedData = "header: Content-Type, value: 'text/plain'\n" + "header: Content-Disposition, value: 'form-data; name=\"text\"'\n" + "content: 7 bytes\n" + "\n"; + QTest::newRow("text-custom") << url << customMultiPart << expectedData << QByteArray("custom"); + + QHttpPart textPart2; + textPart2.setHeader(QNetworkRequest::ContentTypeHeader, QVariant("text/plain")); + textPart2.setRawHeader("myRawHeader", "myValue"); + textPart2.setHeader(QNetworkRequest::ContentDispositionHeader, QVariant("form-data; name=\"text2\"")); + textPart2.setBody("some more bytes"); + textPart2.setBodyDevice((QIODevice *) 1); // test whether setting and unsetting of the device works + textPart2.setBodyDevice(0); + QHttpMultiPart *multiPart2 = new QHttpMultiPart; + multiPart2->setContentType(QHttpMultiPart::FormDataType); + multiPart2->append(textPart); + multiPart2->append(textPart2); + expectedData = "key: text2, value: some more bytes\n" + "key: text, value: 7 bytes\n"; + QTest::newRow("text-text") << url << multiPart2 << expectedData << QByteArray("form-data"); + + + QHttpPart textPart3; + textPart3.setHeader(QNetworkRequest::ContentTypeHeader, QVariant("text/plain")); + textPart3.setHeader(QNetworkRequest::ContentDispositionHeader, QVariant("form-data; name=\"text3\"")); + textPart3.setRawHeader("Content-Location", "http://my.test.location.tld"); + textPart3.setBody("even more bytes"); + QHttpMultiPart *multiPart3 = new QHttpMultiPart; + multiPart3->setContentType(QHttpMultiPart::AlternativeType); + multiPart3->append(textPart); + multiPart3->append(textPart2); + multiPart3->append(textPart3); + expectedData = "header: Content-Type, value: 'text/plain'\n" + "header: Content-Disposition, value: 'form-data; name=\"text\"'\n" + "content: 7 bytes\n" + "\n" + "header: Content-Type, value: 'text/plain'\n" + "header: myRawHeader, value: 'myValue'\n" + "header: Content-Disposition, value: 'form-data; name=\"text2\"'\n" + "content: some more bytes\n" + "\n" + "header: Content-Type, value: 'text/plain'\n" + "header: Content-Disposition, value: 'form-data; name=\"text3\"'\n" + "header: Content-Location, value: 'http://my.test.location.tld'\n" + "content: even more bytes\n\n"; + QTest::newRow("text-text-text") << url << multiPart3 << expectedData << QByteArray("alternative"); + + + + // text and image parts + + QHttpPart imagePart11; + imagePart11.setHeader(QNetworkRequest::ContentTypeHeader, QVariant("image/jpeg")); + imagePart11.setHeader(QNetworkRequest::ContentDispositionHeader, QVariant("form-data; name=\"testImage\"")); + imagePart11.setRawHeader("Content-Location", "http://my.test.location.tld"); + imagePart11.setRawHeader("Content-ID", "my@id.tld"); + QFile *file11 = new QFile(SRCDIR "/image1.jpg"); + file11->open(QIODevice::ReadOnly); + imagePart11.setBodyDevice(file11); + QHttpMultiPart *imageMultiPart1 = new QHttpMultiPart(QHttpMultiPart::FormDataType); + imageMultiPart1->append(imagePart11); + file11->setParent(imageMultiPart1); + expectedData = "key: testImage, value: 87ef3bb319b004ba9e5e9c9fa713776e\n"; // md5 sum of file + QTest::newRow("image") << url << imageMultiPart1 << expectedData << QByteArray("form-data"); + + QHttpPart imagePart21; + imagePart21.setHeader(QNetworkRequest::ContentTypeHeader, QVariant("image/jpeg")); + imagePart21.setHeader(QNetworkRequest::ContentDispositionHeader, QVariant("form-data; name=\"testImage1\"")); + imagePart21.setRawHeader("Content-Location", "http://my.test.location.tld"); + imagePart21.setRawHeader("Content-ID", "my@id.tld"); + QFile *file21 = new QFile(SRCDIR "/image1.jpg"); + file21->open(QIODevice::ReadOnly); + imagePart21.setBodyDevice(file21); + QHttpMultiPart *imageMultiPart2 = new QHttpMultiPart(); + imageMultiPart2->setContentType(QHttpMultiPart::FormDataType); + imageMultiPart2->append(textPart); + imageMultiPart2->append(imagePart21); + file21->setParent(imageMultiPart2); + QHttpPart imagePart22; + imagePart22.setHeader(QNetworkRequest::ContentTypeHeader, QVariant("image/jpeg")); + imagePart22.setHeader(QNetworkRequest::ContentDispositionHeader, QVariant("form-data; name=\"testImage2\"")); + QFile *file22 = new QFile(SRCDIR "/image2.jpg"); + file22->open(QIODevice::ReadOnly); + imagePart22.setBodyDevice(file22); + imageMultiPart2->append(imagePart22); + file22->setParent(imageMultiPart2); + expectedData = "key: testImage1, value: 87ef3bb319b004ba9e5e9c9fa713776e\n" + "key: text, value: 7 bytes\n" + "key: testImage2, value: 483761b893f7fb1bd2414344cd1f3dfb\n"; + QTest::newRow("text-image-image") << url << imageMultiPart2 << expectedData << QByteArray("form-data"); + + + QHttpPart imagePart31; + imagePart31.setHeader(QNetworkRequest::ContentTypeHeader, QVariant("image/jpeg")); + imagePart31.setHeader(QNetworkRequest::ContentDispositionHeader, QVariant("form-data; name=\"testImage1\"")); + imagePart31.setRawHeader("Content-Location", "http://my.test.location.tld"); + imagePart31.setRawHeader("Content-ID", "my@id.tld"); + QFile *file31 = new QFile(SRCDIR "/image1.jpg"); + file31->open(QIODevice::ReadOnly); + imagePart31.setBodyDevice(file31); + QHttpMultiPart *imageMultiPart3 = new QHttpMultiPart(QHttpMultiPart::FormDataType); + imageMultiPart3->append(imagePart31); + file31->setParent(imageMultiPart3); + QHttpPart imagePart32; + imagePart32.setHeader(QNetworkRequest::ContentTypeHeader, QVariant("image/jpeg")); + imagePart32.setHeader(QNetworkRequest::ContentDispositionHeader, QVariant("form-data; name=\"testImage2\"")); + QFile *file32 = new QFile(SRCDIR "/image2.jpg"); + file32->open(QIODevice::ReadOnly); + imagePart32.setBodyDevice(file31); // check that resetting works + imagePart32.setBodyDevice(file32); + imageMultiPart3->append(imagePart32); + file32->setParent(imageMultiPart3); + QHttpPart imagePart33; + imagePart33.setHeader(QNetworkRequest::ContentTypeHeader, QVariant("image/jpeg")); + imagePart33.setHeader(QNetworkRequest::ContentDispositionHeader, QVariant("form-data; name=\"testImage3\"")); + QFile *file33 = new QFile(SRCDIR "/image3.jpg"); + file33->open(QIODevice::ReadOnly); + imagePart33.setBodyDevice(file33); + imageMultiPart3->append(imagePart33); + file33->setParent(imageMultiPart3); + expectedData = "key: testImage1, value: 87ef3bb319b004ba9e5e9c9fa713776e\n" + "key: testImage2, value: 483761b893f7fb1bd2414344cd1f3dfb\n" + "key: testImage3, value: ab0eb6fd4fcf8b4436254870b4513033\n"; + QTest::newRow("3-images") << url << imageMultiPart3 << expectedData << QByteArray("form-data"); + + + // note: nesting multiparts is not working currently; for that, the outputDevice would need to be public + +// QHttpPart imagePart41; +// imagePart41.setHeader(QNetworkRequest::ContentTypeHeader, QVariant("image/jpeg")); +// QFile *file41 = new QFile(SRCDIR "/image1.jpg"); +// file41->open(QIODevice::ReadOnly); +// imagePart41.setBodyDevice(file41); +// +// QHttpMultiPart *innerMultiPart = new QHttpMultiPart(); +// innerMultiPart->setContentType(QHttpMultiPart::FormDataType); +// textPart.setHeader(QNetworkRequest::ContentDispositionHeader, QVariant()); +// innerMultiPart->append(textPart); +// innerMultiPart->append(imagePart41); +// textPart2.setHeader(QNetworkRequest::ContentDispositionHeader, QVariant()); +// innerMultiPart->append(textPart2); +// +// QHttpPart nestedPart; +// nestedPart.setHeader(QNetworkRequest::ContentDispositionHeader, QVariant("form-data; name=\"nestedMessage")); +// nestedPart.setHeader(QNetworkRequest::ContentTypeHeader, QVariant("multipart/alternative; boundary=\"" + innerMultiPart->boundary() + "\"")); +// innerMultiPart->outputDevice()->open(QIODevice::ReadOnly); +// nestedPart.setBodyDevice(innerMultiPart->outputDevice()); +// +// QHttpMultiPart *outerMultiPart = new QHttpMultiPart; +// outerMultiPart->setContentType(QHttpMultiPart::FormDataType); +// outerMultiPart->append(textPart); +// outerMultiPart->append(nestedPart); +// outerMultiPart->append(textPart2); +// expectedData = "nothing"; // the CGI.pm module running on the test server does not understand nested multiparts +// openFiles.clear(); +// openFiles << file41; +// QTest::newRow("nested") << url << outerMultiPart << expectedData << openFiles; + + + // test setting large chunks of content with a byte array instead of a device (DISCOURAGED because of high memory consumption, + // but we need to test that the behavior is correct) + QHttpPart imagePart51; + imagePart51.setHeader(QNetworkRequest::ContentTypeHeader, QVariant("image/jpeg")); + imagePart51.setHeader(QNetworkRequest::ContentDispositionHeader, QVariant("form-data; name=\"testImage\"")); + QFile *file51 = new QFile(SRCDIR "/image1.jpg"); + file51->open(QIODevice::ReadOnly); + QByteArray imageData = file51->readAll(); + file51->close(); + delete file51; + imagePart51.setBody("7 bytes"); // check that resetting works + imagePart51.setBody(imageData); + QHttpMultiPart *imageMultiPart5 = new QHttpMultiPart; + imageMultiPart5->setContentType(QHttpMultiPart::FormDataType); + imageMultiPart5->append(imagePart51); + expectedData = "key: testImage, value: 87ef3bb319b004ba9e5e9c9fa713776e\n"; // md5 sum of file + QTest::newRow("image-as-content") << url << imageMultiPart5 << expectedData << QByteArray("form-data"); +} + +void tst_QNetworkReply::postToHttpMultipart() +{ + QFETCH(QUrl, url); + + static QSet<QByteArray> boundaries; + + QNetworkRequest request(url); + QNetworkReplyPtr reply; + + QFETCH(QHttpMultiPart *, multiPart); + QFETCH(QByteArray, expectedReplyData); + QFETCH(QByteArray, contentType); + + // hack for testing the setting of the content-type header by hand: + if (contentType == "custom") { + QByteArray contentType("multipart/custom; boundary=\"" + multiPart->boundary() + "\""); + request.setHeader(QNetworkRequest::ContentTypeHeader, contentType); + } + + QVERIFY2(! boundaries.contains(multiPart->boundary()), "boundary '" + multiPart->boundary() + "' has been created twice"); + boundaries.insert(multiPart->boundary()); + + RUN_REQUEST(runMultipartRequest(request, reply, multiPart, "POST")); + multiPart->deleteLater(); + + QCOMPARE(reply->url(), url); + QCOMPARE(reply->error(), QNetworkReply::NoError); + + QCOMPARE(reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(), 200); // 200 Ok + + QVERIFY(multiPart->boundary().count() > 20); // check that there is randomness after the "boundary_.oOo._" string + QVERIFY(multiPart->boundary().count() < 70); + QByteArray replyData = reply->readAll(); + + expectedReplyData.prepend("content type: multipart/" + contentType + "; boundary=\"" + multiPart->boundary() + "\"\n"); +// QEXPECT_FAIL("nested", "the server does not understand nested multipart messages", Continue); // see above + QCOMPARE(replyData, expectedReplyData); +} + +void tst_QNetworkReply::putToHttpMultipart_data() +{ + postToHttpMultipart_data(); +} + +void tst_QNetworkReply::putToHttpMultipart() +{ + QSKIP("test server script cannot handle PUT data yet", SkipAll); + QFETCH(QUrl, url); + + static QSet<QByteArray> boundaries; + + QNetworkRequest request(url); + QNetworkReplyPtr reply; + + QFETCH(QHttpMultiPart *, multiPart); + QFETCH(QByteArray, expectedReplyData); + QFETCH(QByteArray, contentType); + + // hack for testing the setting of the content-type header by hand: + if (contentType == "custom") { + QByteArray contentType("multipart/custom; boundary=\"" + multiPart->boundary() + "\""); + request.setHeader(QNetworkRequest::ContentTypeHeader, contentType); + } + + QVERIFY2(! boundaries.contains(multiPart->boundary()), "boundary '" + multiPart->boundary() + "' has been created twice"); + boundaries.insert(multiPart->boundary()); + + RUN_REQUEST(runMultipartRequest(request, reply, multiPart, "PUT")); + multiPart->deleteLater(); + + QCOMPARE(reply->url(), url); + QCOMPARE(reply->error(), QNetworkReply::NoError); + + QCOMPARE(reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(), 200); // 200 Ok + + QVERIFY(multiPart->boundary().count() > 20); // check that there is randomness after the "boundary_.oOo._" string + QVERIFY(multiPart->boundary().count() < 70); + QByteArray replyData = reply->readAll(); + + expectedReplyData.prepend("content type: multipart/" + contentType + "; boundary=\"" + multiPart->boundary() + "\"\n"); +// QEXPECT_FAIL("nested", "the server does not understand nested multipart messages", Continue); // see above + QCOMPARE(replyData, expectedReplyData); +} + +void tst_QNetworkReply::deleteFromHttp_data() +{ + QTest::addColumn<QUrl>("url"); + QTest::addColumn<int>("resultCode"); + QTest::addColumn<QNetworkReply::NetworkError>("error"); + + // for status codes to expect, see http://www.w3.org/Protocols/rfc2616/rfc2616-sec9.html + + QTest::newRow("405-method-not-allowed") << QUrl("http://" + QtNetworkSettings::serverName() + "/index.html") << 405 << QNetworkReply::ContentOperationNotPermittedError; + QTest::newRow("200-ok") << QUrl("http://" + QtNetworkSettings::serverName() + "/qtest/cgi-bin/http-delete.cgi?200-ok") << 200 << QNetworkReply::NoError; + QTest::newRow("202-accepted") << QUrl("http://" + QtNetworkSettings::serverName() + "/qtest/cgi-bin/http-delete.cgi?202-accepted") << 202 << QNetworkReply::NoError; + QTest::newRow("204-no-content") << QUrl("http://" + QtNetworkSettings::serverName() + "/qtest/cgi-bin/http-delete.cgi?204-no-content") << 204 << QNetworkReply::NoError; + QTest::newRow("404-not-found") << QUrl("http://" + QtNetworkSettings::serverName() + "/qtest/cgi-bin/http-delete.cgi?404-not-found") << 404 << QNetworkReply::ContentNotFoundError; +} + +void tst_QNetworkReply::deleteFromHttp() +{ + QFETCH(QUrl, url); + QFETCH(int, resultCode); + QFETCH(QNetworkReply::NetworkError, error); + QNetworkRequest request(url); + QNetworkReplyPtr reply; + runSimpleRequest(QNetworkAccessManager::DeleteOperation, request, reply, 0); + QCOMPARE(reply->url(), url); + QCOMPARE(reply->error(), error); + QCOMPARE(reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(), resultCode); +} + +void tst_QNetworkReply::putGetDeleteGetFromHttp_data() +{ + QTest::addColumn<QUrl>("putUrl"); + QTest::addColumn<int>("putResultCode"); + QTest::addColumn<QNetworkReply::NetworkError>("putError"); + QTest::addColumn<QUrl>("deleteUrl"); + QTest::addColumn<int>("deleteResultCode"); + QTest::addColumn<QNetworkReply::NetworkError>("deleteError"); + QTest::addColumn<QUrl>("get2Url"); + QTest::addColumn<int>("get2ResultCode"); + QTest::addColumn<QNetworkReply::NetworkError>("get2Error"); + + QUrl url("http://" + QtNetworkSettings::serverName()); + url.setPath(QString("/dav/qnetworkaccess-putToHttp-%1-%2") + .arg(QTest::currentDataTag()) + .arg(uniqueExtension)); + + // first use case: put, get (to check it is there), delete, get (to check it is not there anymore) + QTest::newRow("success") << url << 201 << QNetworkReply::NoError << url << 204 << QNetworkReply::NoError << url << 404 << QNetworkReply::ContentNotFoundError; + + QUrl wrongUrl("http://" + QtNetworkSettings::serverName()); + wrongUrl.setPath(QString("/dav/qnetworkaccess-thisURLisNotAvailable")); + + // second use case: put, get (to check it is there), delete wrong URL, get (to check it is still there) + QTest::newRow("delete-error") << url << 201 << QNetworkReply::NoError << wrongUrl << 404 << QNetworkReply::ContentNotFoundError << url << 200 << QNetworkReply::NoError; + +} + +void tst_QNetworkReply::putGetDeleteGetFromHttp() +{ + QFETCH(QUrl, putUrl); + QFETCH(int, putResultCode); + QFETCH(QNetworkReply::NetworkError, putError); + QFETCH(QUrl, deleteUrl); + QFETCH(int, deleteResultCode); + QFETCH(QNetworkReply::NetworkError, deleteError); + QFETCH(QUrl, get2Url); + QFETCH(int, get2ResultCode); + QFETCH(QNetworkReply::NetworkError, get2Error); + + QNetworkRequest putRequest(putUrl); + QNetworkRequest deleteRequest(deleteUrl); + QNetworkRequest get2Request(get2Url); + QNetworkReplyPtr reply; + + RUN_REQUEST(runSimpleRequest(QNetworkAccessManager::PutOperation, putRequest, reply, 0)); + QCOMPARE(reply->error(), putError); + QCOMPARE(reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(), putResultCode); + + runSimpleRequest(QNetworkAccessManager::GetOperation, putRequest, reply, 0); + QCOMPARE(reply->error(), QNetworkReply::NoError); + QCOMPARE(reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(), 200); + + runSimpleRequest(QNetworkAccessManager::DeleteOperation, deleteRequest, reply, 0); + QCOMPARE(reply->error(), deleteError); + QCOMPARE(reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(), deleteResultCode); + + runSimpleRequest(QNetworkAccessManager::GetOperation, get2Request, reply, 0); + QCOMPARE(reply->error(), get2Error); + QCOMPARE(reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(), get2ResultCode); + +} + +void tst_QNetworkReply::connectToIPv6Address_data() +{ + QTest::addColumn<QUrl>("url"); + QTest::addColumn<QNetworkReply::NetworkError>("error"); + QTest::addColumn<QByteArray>("dataToSend"); + QTest::addColumn<QByteArray>("hostfield"); + QTest::newRow("localhost") << QUrl(QByteArray("http://[::1]")) << QNetworkReply::NoError<< QByteArray("localhost") << QByteArray("[::1]"); + //QTest::newRow("ipv4localhost") << QUrl(QByteArray("http://127.0.0.1")) << QNetworkReply::NoError<< QByteArray("ipv4localhost") << QByteArray("127.0.0.1"); + //to add more test data here +} + +void tst_QNetworkReply::connectToIPv6Address() +{ + QFETCH(QUrl, url); + QFETCH(QNetworkReply::NetworkError, error); + QFETCH(QByteArray, dataToSend); + QFETCH(QByteArray, hostfield); + + QByteArray httpResponse = QByteArray("HTTP/1.0 200 OK\r\nContent-Length: "); + httpResponse += QByteArray::number(dataToSend.size()); + httpResponse += "\r\n\r\n"; + httpResponse += dataToSend; + + MiniHttpServer server(httpResponse, false, NULL/*thread*/, true/*useipv6*/); + server.doClose = true; + + url.setPort(server.serverPort()); + QNetworkRequest request(url); + + QNetworkReplyPtr reply = manager.get(request); + connect(reply, SIGNAL(finished()), &QTestEventLoop::instance(), SLOT(exitLoop())); + QTestEventLoop::instance().enterLoop(10); + QVERIFY(!QTestEventLoop::instance().timeout()); + QByteArray content = reply->readAll(); + //qDebug() << server.receivedData; + QByteArray hostinfo = "\r\nHost: " + hostfield + ":" + QByteArray::number(server.serverPort()) + "\r\n"; + QVERIFY(server.receivedData.contains(hostinfo)); + QVERIFY(content == dataToSend); + QCOMPARE(reply->url(), request.url()); + QVERIFY(reply->error() == error); +} + +void tst_QNetworkReply::sendCustomRequestToHttp_data() +{ + QTest::addColumn<QUrl>("url"); + QTest::addColumn<QByteArray>("verb"); + QTest::addColumn<QBuffer *>("device"); + QTest::addColumn<int>("resultCode"); + QTest::addColumn<QNetworkReply::NetworkError>("error"); + QTest::addColumn<QByteArray>("expectedContent"); + + QTest::newRow("options") << QUrl("http://" + QtNetworkSettings::serverName()) << + QByteArray("OPTIONS") << (QBuffer *) 0 << 200 << QNetworkReply::NoError << QByteArray(); + QTest::newRow("trace") << QUrl("http://" + QtNetworkSettings::serverName()) << + QByteArray("TRACE") << (QBuffer *) 0 << 200 << QNetworkReply::NoError << QByteArray(); + QTest::newRow("connect") << QUrl("http://" + QtNetworkSettings::serverName()) << + QByteArray("CONNECT") << (QBuffer *) 0 << 400 << QNetworkReply::UnknownContentError << QByteArray(); // 400 = Bad Request + QTest::newRow("nonsense") << QUrl("http://" + QtNetworkSettings::serverName()) << + QByteArray("NONSENSE") << (QBuffer *) 0 << 501 << QNetworkReply::ProtocolUnknownError << QByteArray(); // 501 = Method Not Implemented + + QByteArray ba("test"); + QBuffer *buffer = new QBuffer; + buffer->setData(ba); + buffer->open(QIODevice::ReadOnly); + QTest::newRow("post") << QUrl("http://" + QtNetworkSettings::serverName() + "/qtest/cgi-bin/md5sum.cgi") << QByteArray("POST") + << buffer << 200 << QNetworkReply::NoError << QByteArray("098f6bcd4621d373cade4e832627b4f6\n"); + + QByteArray ba2("test"); + QBuffer *buffer2 = new QBuffer; + buffer2->setData(ba2); + buffer2->open(QIODevice::ReadOnly); + QTest::newRow("put") << QUrl("http://" + QtNetworkSettings::serverName() + "/qtest/cgi-bin/md5sum.cgi") << QByteArray("PUT") + << buffer2 << 200 << QNetworkReply::NoError << QByteArray("098f6bcd4621d373cade4e832627b4f6\n"); +} + +void tst_QNetworkReply::sendCustomRequestToHttp() +{ + QFETCH(QUrl, url); + QNetworkRequest request(url); + QNetworkReplyPtr reply; + QFETCH(QByteArray, verb); + QFETCH(QBuffer *, device); + runCustomRequest(request, reply, verb, device); + QCOMPARE(reply->url(), url); + QFETCH(QNetworkReply::NetworkError, error); + QCOMPARE(reply->error(), error); + QFETCH(int, resultCode); + QCOMPARE(reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(), resultCode); + QFETCH(QByteArray, expectedContent); + if (! expectedContent.isEmpty()) + QCOMPARE(reply->readAll(), expectedContent); +} + +void tst_QNetworkReply::ioGetFromData_data() +{ + QTest::addColumn<QString>("urlStr"); + QTest::addColumn<QByteArray>("data"); + + QTest::newRow("data-empty") << "data:," << QByteArray(); + QTest::newRow("data-literal") << "data:,foo" << QByteArray("foo"); + QTest::newRow("data-pct") << "data:,%3Cbody%20contentEditable%3Dtrue%3E%0D%0A" + << QByteArray("<body contentEditable=true>\r\n"); + QTest::newRow("data-base64") << "data:;base64,UXQgaXMgZ3JlYXQh" << QByteArray("Qt is great!"); +} + +void tst_QNetworkReply::ioGetFromData() +{ + QFETCH(QString, urlStr); + + QUrl url = QUrl::fromEncoded(urlStr.toLatin1()); + QNetworkRequest request(url); + + QNetworkReplyPtr reply = manager.get(request); + DataReader reader(reply); + + connect(reply, SIGNAL(finished()), + &QTestEventLoop::instance(), SLOT(exitLoop())); + QTestEventLoop::instance().enterLoop(10); + QVERIFY(!QTestEventLoop::instance().timeout()); + + QCOMPARE(reply->url(), request.url()); + QCOMPARE(reply->error(), QNetworkReply::NoError); + + QFETCH(QByteArray, data); + QCOMPARE(reply->header(QNetworkRequest::ContentLengthHeader).toInt(), data.size()); + QCOMPARE(reader.data.size(), data.size()); + QCOMPARE(reader.data, data); +} + +void tst_QNetworkReply::ioGetFromFileSpecial_data() +{ + getFromFileSpecial_data(); +} + +void tst_QNetworkReply::ioGetFromFileSpecial() +{ + QFETCH(QString, fileName); + QFETCH(QString, url); + + QFile resource(fileName); + QVERIFY(resource.open(QIODevice::ReadOnly)); + + QNetworkRequest request; + request.setUrl(url); + QNetworkReplyPtr reply = manager.get(request); + DataReader reader(reply); + + connect(reply, SIGNAL(finished()), &QTestEventLoop::instance(), SLOT(exitLoop())); + QTestEventLoop::instance().enterLoop(10); + QVERIFY(!QTestEventLoop::instance().timeout()); + + QCOMPARE(reply->url(), request.url()); + QCOMPARE(reply->error(), QNetworkReply::NoError); + + QCOMPARE(reply->header(QNetworkRequest::ContentLengthHeader).toLongLong(), resource.size()); + QCOMPARE(qint64(reader.data.size()), resource.size()); + QCOMPARE(reader.data, resource.readAll()); +} + +void tst_QNetworkReply::ioGetFromFile_data() +{ + putToFile_data(); +} + +void tst_QNetworkReply::ioGetFromFile() +{ + QTemporaryFile file(QDir::currentPath() + "/temp-XXXXXX"); + file.setAutoRemove(true); + QVERIFY(file.open()); + + QFETCH(QByteArray, data); + QVERIFY(file.write(data) == data.size()); + file.flush(); + QCOMPARE(file.size(), qint64(data.size())); + + QNetworkRequest request(QUrl::fromLocalFile(file.fileName())); + QNetworkReplyPtr reply = manager.get(request); + QVERIFY(reply->isFinished()); // a file should immediately be done + DataReader reader(reply); + + connect(reply, SIGNAL(finished()), &QTestEventLoop::instance(), SLOT(exitLoop())); + QTestEventLoop::instance().enterLoop(10); + QVERIFY(!QTestEventLoop::instance().timeout()); + + QCOMPARE(reply->url(), request.url()); + QCOMPARE(reply->error(), QNetworkReply::NoError); + + QCOMPARE(reply->header(QNetworkRequest::ContentLengthHeader).toLongLong(), file.size()); + QCOMPARE(qint64(reader.data.size()), file.size()); + QCOMPARE(reader.data, data); +} + +void tst_QNetworkReply::ioGetFromFtp_data() +{ + QTest::addColumn<QString>("fileName"); + QTest::addColumn<qint64>("expectedSize"); + + QTest::newRow("bigfile") << "bigfile" << Q_INT64_C(519240); + + QFile file(SRCDIR "/rfc3252.txt"); + QTest::newRow("rfc3252.txt") << "rfc3252.txt" << file.size(); +} + +void tst_QNetworkReply::ioGetFromFtp() +{ + QFETCH(QString, fileName); + QFile reference(fileName); + reference.open(QIODevice::ReadOnly); // will fail for bigfile + + QNetworkRequest request("ftp://" + QtNetworkSettings::serverName() + "/qtest/" + fileName); + QNetworkReplyPtr reply = manager.get(request); + DataReader reader(reply); + + connect(reply, SIGNAL(finished()), &QTestEventLoop::instance(), SLOT(exitLoop())); + QTestEventLoop::instance().enterLoop(10); + QVERIFY(!QTestEventLoop::instance().timeout()); + + QCOMPARE(reply->url(), request.url()); + QCOMPARE(reply->error(), QNetworkReply::NoError); + + QFETCH(qint64, expectedSize); + QCOMPARE(reply->header(QNetworkRequest::ContentLengthHeader).toLongLong(), expectedSize); + QCOMPARE(qint64(reader.data.size()), expectedSize); + + if (reference.isOpen()) + QCOMPARE(reader.data, reference.readAll()); +} + +void tst_QNetworkReply::ioGetFromFtpWithReuse() +{ + QString fileName = SRCDIR "/rfc3252.txt"; + QFile reference(fileName); + reference.open(QIODevice::ReadOnly); + + QNetworkRequest request(QUrl("ftp://" + QtNetworkSettings::serverName() + "/qtest/rfc3252.txt")); + + // two concurrent (actually, consecutive) gets: + QNetworkReplyPtr reply1 = manager.get(request); + DataReader reader1(reply1); + QNetworkReplyPtr reply2 = manager.get(request); + DataReader reader2(reply2); + QSignalSpy spy(reply1, SIGNAL(finished())); + + connect(reply2, SIGNAL(finished()), &QTestEventLoop::instance(), SLOT(exitLoop())); + QTestEventLoop::instance().enterLoop(10); + QVERIFY(!QTestEventLoop::instance().timeout()); + if (spy.count() == 0) { + connect(reply1, SIGNAL(finished()), &QTestEventLoop::instance(), SLOT(exitLoop())); + QTestEventLoop::instance().enterLoop(10); + QVERIFY(!QTestEventLoop::instance().timeout()); + } + + QCOMPARE(reply1->url(), request.url()); + QCOMPARE(reply2->url(), request.url()); + QCOMPARE(reply1->error(), QNetworkReply::NoError); + QCOMPARE(reply2->error(), QNetworkReply::NoError); + + QCOMPARE(qint64(reader1.data.size()), reference.size()); + QCOMPARE(qint64(reader2.data.size()), reference.size()); + QCOMPARE(reply1->header(QNetworkRequest::ContentLengthHeader).toLongLong(), reference.size()); + QCOMPARE(reply2->header(QNetworkRequest::ContentLengthHeader).toLongLong(), reference.size()); + + QByteArray referenceData = reference.readAll(); + QCOMPARE(reader1.data, referenceData); + QCOMPARE(reader2.data, referenceData); +} + +void tst_QNetworkReply::ioGetFromHttp() +{ + QFile reference(SRCDIR "/rfc3252.txt"); + QVERIFY(reference.open(QIODevice::ReadOnly)); + + QNetworkRequest request(QUrl("http://" + QtNetworkSettings::serverName() + "/qtest/rfc3252.txt")); + QNetworkReplyPtr reply = manager.get(request); + DataReader reader(reply); + + connect(reply, SIGNAL(finished()), &QTestEventLoop::instance(), SLOT(exitLoop())); + QTestEventLoop::instance().enterLoop(10); + QVERIFY(!QTestEventLoop::instance().timeout()); + + QCOMPARE(reply->url(), request.url()); + QCOMPARE(reply->error(), QNetworkReply::NoError); + QCOMPARE(reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(), 200); + + QCOMPARE(reply->header(QNetworkRequest::ContentLengthHeader).toLongLong(), reference.size()); + QCOMPARE(qint64(reader.data.size()), reference.size()); + + QCOMPARE(reader.data, reference.readAll()); +} + +void tst_QNetworkReply::ioGetFromHttpWithReuseParallel() +{ + QFile reference(SRCDIR "/rfc3252.txt"); + QVERIFY(reference.open(QIODevice::ReadOnly)); + + QNetworkRequest request(QUrl("http://" + QtNetworkSettings::serverName() + "/qtest/rfc3252.txt")); + QNetworkReplyPtr reply1 = manager.get(request); + QNetworkReplyPtr reply2 = manager.get(request); + DataReader reader1(reply1); + DataReader reader2(reply2); + QSignalSpy spy(reply1, SIGNAL(finished())); + + connect(reply2, SIGNAL(finished()), &QTestEventLoop::instance(), SLOT(exitLoop())); + QTestEventLoop::instance().enterLoop(10); + QVERIFY(!QTestEventLoop::instance().timeout()); + if (spy.count() == 0) { + connect(reply1, SIGNAL(finished()), &QTestEventLoop::instance(), SLOT(exitLoop())); + QTestEventLoop::instance().enterLoop(10); + QVERIFY(!QTestEventLoop::instance().timeout()); + } + + QCOMPARE(reply1->url(), request.url()); + QCOMPARE(reply2->url(), request.url()); + QCOMPARE(reply1->error(), QNetworkReply::NoError); + QCOMPARE(reply2->error(), QNetworkReply::NoError); + QCOMPARE(reply1->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(), 200); + QCOMPARE(reply2->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(), 200); + + QCOMPARE(reply1->header(QNetworkRequest::ContentLengthHeader).toLongLong(), reference.size()); + QCOMPARE(reply2->header(QNetworkRequest::ContentLengthHeader).toLongLong(), reference.size()); + QCOMPARE(qint64(reader1.data.size()), reference.size()); + QCOMPARE(qint64(reader2.data.size()), reference.size()); + + QByteArray referenceData = reference.readAll(); + QCOMPARE(reader1.data, referenceData); + QCOMPARE(reader2.data, referenceData); +} + +void tst_QNetworkReply::ioGetFromHttpWithReuseSequential() +{ + QFile reference(SRCDIR "/rfc3252.txt"); + QVERIFY(reference.open(QIODevice::ReadOnly)); + + QNetworkRequest request(QUrl("http://" + QtNetworkSettings::serverName() + "/qtest/rfc3252.txt")); + { + QNetworkReplyPtr reply = manager.get(request); + DataReader reader(reply); + + connect(reply, SIGNAL(finished()), &QTestEventLoop::instance(), SLOT(exitLoop())); + QTestEventLoop::instance().enterLoop(10); + QVERIFY(!QTestEventLoop::instance().timeout()); + + QCOMPARE(reply->url(), request.url()); + QCOMPARE(reply->error(), QNetworkReply::NoError); + QCOMPARE(reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(), 200); + + QCOMPARE(reply->header(QNetworkRequest::ContentLengthHeader).toLongLong(), reference.size()); + QCOMPARE(qint64(reader.data.size()), reference.size()); + + QCOMPARE(reader.data, reference.readAll()); + } + + reference.seek(0); + // rinse and repeat: + { + QNetworkReplyPtr reply = manager.get(request); + DataReader reader(reply); + + connect(reply, SIGNAL(finished()), &QTestEventLoop::instance(), SLOT(exitLoop())); + QTestEventLoop::instance().enterLoop(10); + QVERIFY(!QTestEventLoop::instance().timeout()); + + QCOMPARE(reply->url(), request.url()); + QCOMPARE(reply->error(), QNetworkReply::NoError); + QCOMPARE(reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(), 200); + + QCOMPARE(reply->header(QNetworkRequest::ContentLengthHeader).toLongLong(), reference.size()); + QCOMPARE(qint64(reader.data.size()), reference.size()); + + QCOMPARE(reader.data, reference.readAll()); + } +} + +void tst_QNetworkReply::ioGetFromHttpWithAuth_data() +{ + QTest::addColumn<QUrl>("url"); + QTest::addColumn<QByteArray>("expectedData"); + + QFile reference(SRCDIR "/rfc3252.txt"); + reference.open(QIODevice::ReadOnly); + QByteArray referenceData = reference.readAll(); + QTest::newRow("basic") << QUrl("http://" + QtNetworkSettings::serverName() + "/qtest/rfcs-auth/rfc3252.txt") << referenceData; + QTest::newRow("digest") << QUrl("http://" + QtNetworkSettings::serverName() + "/qtest/auth-digest/") << QByteArray("digest authentication successful\n"); +} + +void tst_QNetworkReply::ioGetFromHttpWithAuth() +{ + // This test sends three requests + // The first two in parallel + // The third after the first two finished + + QFETCH(QUrl, url); + QFETCH(QByteArray, expectedData); + QNetworkRequest request(url); + { + QNetworkReplyPtr reply1 = manager.get(request); + QNetworkReplyPtr reply2 = manager.get(request); + DataReader reader1(reply1); + DataReader reader2(reply2); + QSignalSpy finishedspy(reply1, SIGNAL(finished())); + + QSignalSpy authspy(&manager, SIGNAL(authenticationRequired(QNetworkReply*,QAuthenticator*))); + connect(&manager, SIGNAL(authenticationRequired(QNetworkReply*,QAuthenticator*)), + SLOT(authenticationRequired(QNetworkReply*,QAuthenticator*))); + + connect(reply2, SIGNAL(finished()), &QTestEventLoop::instance(), SLOT(exitLoop())); + QTestEventLoop::instance().enterLoop(10); + QVERIFY(!QTestEventLoop::instance().timeout()); + if (finishedspy.count() == 0) { + connect(reply1, SIGNAL(finished()), &QTestEventLoop::instance(), SLOT(exitLoop())); + QTestEventLoop::instance().enterLoop(10); + QVERIFY(!QTestEventLoop::instance().timeout()); + } + manager.disconnect(SIGNAL(authenticationRequired(QNetworkReply*,QAuthenticator*)), + this, SLOT(authenticationRequired(QNetworkReply*,QAuthenticator*))); + + QCOMPARE(reply1->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(), 200); + QCOMPARE(reply2->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(), 200); + QCOMPARE(reader1.data, expectedData); + QCOMPARE(reader2.data, expectedData); + + QCOMPARE(authspy.count(), 1); + } + + // rinse and repeat: + { + QNetworkReplyPtr reply = manager.get(request); + DataReader reader(reply); + + QSignalSpy authspy(&manager, SIGNAL(authenticationRequired(QNetworkReply*,QAuthenticator*))); + connect(&manager, SIGNAL(authenticationRequired(QNetworkReply*,QAuthenticator*)), + SLOT(authenticationRequired(QNetworkReply*,QAuthenticator*))); + connect(reply, SIGNAL(finished()), &QTestEventLoop::instance(), SLOT(exitLoop())); + QTestEventLoop::instance().enterLoop(10); + QVERIFY(!QTestEventLoop::instance().timeout()); + manager.disconnect(SIGNAL(authenticationRequired(QNetworkReply*,QAuthenticator*)), + this, SLOT(authenticationRequired(QNetworkReply*,QAuthenticator*))); + + QCOMPARE(reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(), 200); + QCOMPARE(reader.data, expectedData); + + QCOMPARE(authspy.count(), 0); + } + + // now check with synchronous calls: + { + request.setAttribute( + QNetworkRequest::SynchronousRequestAttribute, + true); + + QSignalSpy authspy(&manager, SIGNAL(authenticationRequired(QNetworkReply*,QAuthenticator*))); + QNetworkReplyPtr replySync = manager.get(request); + QVERIFY(replySync->isFinished()); // synchronous + QCOMPARE(authspy.count(), 0); + + // we cannot use a data reader here, since that connects to the readyRead signal, + // just use readAll() + + // the only thing we check here is that the auth cache was used when using synchronous requests + QCOMPARE(replySync->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(), 200); + QCOMPARE(replySync->readAll(), expectedData); + } +} + +void tst_QNetworkReply::ioGetFromHttpWithAuthSynchronous() +{ + // verify that we do not enter an endless loop with synchronous calls and wrong credentials + // the case when we succeed with the login is tested in ioGetFromHttpWithAuth() + + QNetworkRequest request(QUrl("http://" + QtNetworkSettings::serverName() + "/qtest/rfcs-auth/rfc3252.txt")); + request.setAttribute( + QNetworkRequest::SynchronousRequestAttribute, + true); + + QSignalSpy authspy(&manager, SIGNAL(authenticationRequired(QNetworkReply*,QAuthenticator*))); + QNetworkReplyPtr replySync = manager.get(request); + QVERIFY(replySync->isFinished()); // synchronous + QCOMPARE(replySync->error(), QNetworkReply::AuthenticationRequiredError); + QCOMPARE(authspy.count(), 0); + QCOMPARE(replySync->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(), 401); +} + +void tst_QNetworkReply::ioGetFromHttpWithProxyAuth() +{ + qRegisterMetaType<QNetworkProxy>(); // for QSignalSpy + qRegisterMetaType<QAuthenticator *>(); + + // This test sends three requests + // The first two in parallel + // The third after the first two finished + QFile reference(SRCDIR "/rfc3252.txt"); + QVERIFY(reference.open(QIODevice::ReadOnly)); + + QNetworkProxy proxy(QNetworkProxy::HttpCachingProxy, QtNetworkSettings::serverName(), 3129); + QNetworkRequest request(QUrl("http://" + QtNetworkSettings::serverName() + "/qtest/rfc3252.txt")); + { + manager.setProxy(proxy); + QNetworkReplyPtr reply1 = manager.get(request); + QNetworkReplyPtr reply2 = manager.get(request); + manager.setProxy(QNetworkProxy()); + + DataReader reader1(reply1); + DataReader reader2(reply2); + QSignalSpy finishedspy(reply1, SIGNAL(finished())); + + QSignalSpy authspy(&manager, SIGNAL(proxyAuthenticationRequired(QNetworkProxy,QAuthenticator*))); + connect(&manager, SIGNAL(proxyAuthenticationRequired(QNetworkProxy,QAuthenticator*)), + SLOT(proxyAuthenticationRequired(QNetworkProxy,QAuthenticator*))); + + connect(reply2, SIGNAL(finished()), &QTestEventLoop::instance(), SLOT(exitLoop())); + QTestEventLoop::instance().enterLoop(10); + QVERIFY(!QTestEventLoop::instance().timeout()); + if (finishedspy.count() == 0) { + connect(reply1, SIGNAL(finished()), &QTestEventLoop::instance(), SLOT(exitLoop())); + QTestEventLoop::instance().enterLoop(10); + QVERIFY(!QTestEventLoop::instance().timeout()); + } + manager.disconnect(SIGNAL(proxyAuthenticationRequired(QNetworkProxy,QAuthenticator*)), + this, SLOT(proxyAuthenticationRequired(QNetworkProxy,QAuthenticator*))); + + QCOMPARE(reply1->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(), 200); + QCOMPARE(reply2->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(), 200); + QByteArray referenceData = reference.readAll(); + QCOMPARE(reader1.data, referenceData); + QCOMPARE(reader2.data, referenceData); + + QCOMPARE(authspy.count(), 1); + } + + reference.seek(0); + // rinse and repeat: + { + manager.setProxy(proxy); + QNetworkReplyPtr reply = manager.get(request); + DataReader reader(reply); + manager.setProxy(QNetworkProxy()); + + QSignalSpy authspy(&manager, SIGNAL(proxyAuthenticationRequired(QNetworkProxy,QAuthenticator*))); + connect(&manager, SIGNAL(proxyAuthenticationRequired(QNetworkProxy,QAuthenticator*)), + SLOT(proxyAuthenticationRequired(QNetworkProxy,QAuthenticator*))); + connect(reply, SIGNAL(finished()), &QTestEventLoop::instance(), SLOT(exitLoop())); + QTestEventLoop::instance().enterLoop(10); + QVERIFY(!QTestEventLoop::instance().timeout()); + manager.disconnect(SIGNAL(proxyAuthenticationRequired(QNetworkProxy,QAuthenticator*)), + this, SLOT(proxyAuthenticationRequired(QNetworkProxy,QAuthenticator*))); + + QCOMPARE(reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(), 200); + QCOMPARE(reader.data, reference.readAll()); + + QCOMPARE(authspy.count(), 0); + } + + // now check with synchronous calls: + reference.seek(0); + { + request.setAttribute( + QNetworkRequest::SynchronousRequestAttribute, + true); + + QSignalSpy authspy(&manager, SIGNAL(proxyAuthenticationRequired(QNetworkProxy,QAuthenticator*))); + QNetworkReplyPtr replySync = manager.get(request); + QVERIFY(replySync->isFinished()); // synchronous + QCOMPARE(authspy.count(), 0); + + // we cannot use a data reader here, since that connects to the readyRead signal, + // just use readAll() + + // the only thing we check here is that the proxy auth cache was used when using synchronous requests + QCOMPARE(replySync->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(), 200); + QCOMPARE(replySync->readAll(), reference.readAll()); + } +} + +void tst_QNetworkReply::ioGetFromHttpWithProxyAuthSynchronous() +{ + // verify that we do not enter an endless loop with synchronous calls and wrong credentials + // the case when we succeed with the login is tested in ioGetFromHttpWithAuth() + + QNetworkProxy proxy(QNetworkProxy::HttpCachingProxy, QtNetworkSettings::serverName(), 3129); + QNetworkRequest request(QUrl("http://" + QtNetworkSettings::serverName() + "/qtest/rfc3252.txt")); + manager.setProxy(proxy); + request.setAttribute( + QNetworkRequest::SynchronousRequestAttribute, + true); + + QSignalSpy authspy(&manager, SIGNAL(proxyAuthenticationRequired(QNetworkProxy,QAuthenticator*))); + QNetworkReplyPtr replySync = manager.get(request); + manager.setProxy(QNetworkProxy()); // reset + QVERIFY(replySync->isFinished()); // synchronous + QCOMPARE(replySync->error(), QNetworkReply::ProxyAuthenticationRequiredError); + QCOMPARE(authspy.count(), 0); + QCOMPARE(replySync->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(), 407); +} + +void tst_QNetworkReply::ioGetFromHttpWithSocksProxy() +{ + // HTTP caching proxies are tested by the above function + // test SOCKSv5 proxies too + + qRegisterMetaType<QNetworkProxy>(); // for QSignalSpy + qRegisterMetaType<QAuthenticator *>(); + + QFile reference(SRCDIR "/rfc3252.txt"); + QVERIFY(reference.open(QIODevice::ReadOnly)); + + QNetworkProxy proxy(QNetworkProxy::Socks5Proxy, QtNetworkSettings::serverName(), 1080); + QNetworkRequest request(QUrl("http://" + QtNetworkSettings::serverName() + "/qtest/rfc3252.txt")); + { + manager.setProxy(proxy); + QNetworkReplyPtr reply = manager.get(request); + DataReader reader(reply); + manager.setProxy(QNetworkProxy()); + + QSignalSpy authspy(&manager, SIGNAL(proxyAuthenticationRequired(QNetworkProxy,QAuthenticator*))); + connect(&manager, SIGNAL(proxyAuthenticationRequired(QNetworkProxy,QAuthenticator*)), + SLOT(proxyAuthenticationRequired(QNetworkProxy,QAuthenticator*))); + connect(reply, SIGNAL(finished()), &QTestEventLoop::instance(), SLOT(exitLoop())); + QTestEventLoop::instance().enterLoop(10); + QVERIFY(!QTestEventLoop::instance().timeout()); + manager.disconnect(SIGNAL(proxyAuthenticationRequired(QNetworkProxy,QAuthenticator*)), + this, SLOT(proxyAuthenticationRequired(QNetworkProxy,QAuthenticator*))); + + QCOMPARE(reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(), 200); + QCOMPARE(reader.data, reference.readAll()); + + QCOMPARE(authspy.count(), 0); + } + + // set an invalid proxy just to make sure that we can't load + proxy = QNetworkProxy(QNetworkProxy::Socks5Proxy, QtNetworkSettings::serverName(), 1079); + { + manager.setProxy(proxy); + QNetworkReplyPtr reply = manager.get(request); + DataReader reader(reply); + manager.setProxy(QNetworkProxy()); + + QSignalSpy authspy(&manager, SIGNAL(proxyAuthenticationRequired(QNetworkProxy,QAuthenticator*))); + connect(&manager, SIGNAL(proxyAuthenticationRequired(QNetworkProxy,QAuthenticator*)), + SLOT(proxyAuthenticationRequired(QNetworkProxy,QAuthenticator*))); + connect(reply, SIGNAL(finished()), &QTestEventLoop::instance(), SLOT(exitLoop())); + QTestEventLoop::instance().enterLoop(10); + QVERIFY(!QTestEventLoop::instance().timeout()); + manager.disconnect(SIGNAL(proxyAuthenticationRequired(QNetworkProxy,QAuthenticator*)), + this, SLOT(proxyAuthenticationRequired(QNetworkProxy,QAuthenticator*))); + + QVERIFY(!reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).isValid()); + QVERIFY(reader.data.isEmpty()); + + QVERIFY(int(reply->error()) > 0); + QEXPECT_FAIL("", "QTcpSocket doesn't return enough information yet", Continue); + QCOMPARE(int(reply->error()), int(QNetworkReply::ProxyConnectionRefusedError)); + + QCOMPARE(authspy.count(), 0); + } +} + +#ifndef QT_NO_OPENSSL +void tst_QNetworkReply::ioGetFromHttpsWithSslErrors() +{ + qRegisterMetaType<QNetworkReply*>(); // for QSignalSpy + qRegisterMetaType<QList<QSslError> >(); + + QFile reference(SRCDIR "/rfc3252.txt"); + QVERIFY(reference.open(QIODevice::ReadOnly)); + + QNetworkRequest request(QUrl("https://" + QtNetworkSettings::serverName() + "/qtest/rfc3252.txt")); + QNetworkReplyPtr reply = manager.get(request); + DataReader reader(reply); + + QSignalSpy sslspy(&manager, SIGNAL(sslErrors(QNetworkReply*,QList<QSslError>))); + connect(&manager, SIGNAL(sslErrors(QNetworkReply*,QList<QSslError>)), + SLOT(sslErrors(QNetworkReply*,QList<QSslError>))); + connect(reply, SIGNAL(metaDataChanged()), SLOT(storeSslConfiguration())); + + connect(reply, SIGNAL(finished()), &QTestEventLoop::instance(), SLOT(exitLoop())); + QTestEventLoop::instance().enterLoop(10); + QVERIFY(!QTestEventLoop::instance().timeout()); + manager.disconnect(SIGNAL(sslErrors(QNetworkReply*,QList<QSslError>)), + this, SLOT(sslErrors(QNetworkReply*,QList<QSslError>))); + + QCOMPARE(reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(), 200); + QCOMPARE(reader.data, reference.readAll()); + + QCOMPARE(sslspy.count(), 1); + + QVERIFY(!storedSslConfiguration.isNull()); + QVERIFY(!reply->sslConfiguration().isNull()); +} + +void tst_QNetworkReply::ioGetFromHttpsWithIgnoreSslErrors() +{ + // same as above, except that we call ignoreSslErrors and don't connect + // to the sslErrors() signal (which is *still* emitted) + + qRegisterMetaType<QNetworkReply*>(); // for QSignalSpy + qRegisterMetaType<QList<QSslError> >(); + + QFile reference(SRCDIR "/rfc3252.txt"); + QVERIFY(reference.open(QIODevice::ReadOnly)); + + QNetworkRequest request(QUrl("https://" + QtNetworkSettings::serverName() + "/qtest/rfc3252.txt")); + + QNetworkReplyPtr reply = manager.get(request); + reply->ignoreSslErrors(); + DataReader reader(reply); + + QSignalSpy sslspy(&manager, SIGNAL(sslErrors(QNetworkReply*,QList<QSslError>))); + connect(reply, SIGNAL(metaDataChanged()), SLOT(storeSslConfiguration())); + connect(reply, SIGNAL(finished()), &QTestEventLoop::instance(), SLOT(exitLoop())); + QTestEventLoop::instance().enterLoop(10); + QVERIFY(!QTestEventLoop::instance().timeout()); + + QCOMPARE(reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(), 200); + QCOMPARE(reader.data, reference.readAll()); + + QCOMPARE(sslspy.count(), 1); + + QVERIFY(!storedSslConfiguration.isNull()); + QVERIFY(!reply->sslConfiguration().isNull()); +} + +void tst_QNetworkReply::ioGetFromHttpsWithSslHandshakeError() +{ + qRegisterMetaType<QNetworkReply*>(); // for QSignalSpy + qRegisterMetaType<QList<QSslError> >(); + + QFile reference(SRCDIR "/rfc3252.txt"); + QVERIFY(reference.open(QIODevice::ReadOnly)); + + QNetworkRequest request(QUrl("https://" + QtNetworkSettings::serverName() + ":80")); + + QNetworkReplyPtr reply = manager.get(request); + reply->ignoreSslErrors(); + DataReader reader(reply); + + QSignalSpy sslspy(&manager, SIGNAL(sslErrors(QNetworkReply*,QList<QSslError>))); + connect(reply, SIGNAL(metaDataChanged()), SLOT(storeSslConfiguration())); + connect(reply, SIGNAL(finished()), &QTestEventLoop::instance(), SLOT(exitLoop())); + QTestEventLoop::instance().enterLoop(10); + QVERIFY(!QTestEventLoop::instance().timeout()); + + QCOMPARE(reply->error(), QNetworkReply::SslHandshakeFailedError); + QCOMPARE(sslspy.count(), 0); +} +#endif + +void tst_QNetworkReply::ioGetFromHttpBrokenServer_data() +{ + QTest::addColumn<QByteArray>("dataToSend"); + QTest::addColumn<bool>("doDisconnect"); + + QTest::newRow("no-newline") << QByteArray("Hello World") << false; + + // these are OK now, we just eat the lonely newlines + //QTest::newRow("just-newline") << QByteArray("\r\n") << false; + //QTest::newRow("just-2newline") << QByteArray("\r\n\r\n") << false; + + QTest::newRow("with-newlines") << QByteArray("Long first line\r\nLong second line") << false; + QTest::newRow("with-newlines2") << QByteArray("\r\nSecond line") << false; + QTest::newRow("with-newlines3") << QByteArray("ICY\r\nSecond line") << false; + QTest::newRow("invalid-version") << QByteArray("HTTP/123 200 \r\n") << false; + QTest::newRow("invalid-version2") << QByteArray("HTTP/a.\033 200 \r\n") << false; + QTest::newRow("invalid-reply-code") << QByteArray("HTTP/1.0 fuu \r\n") << false; + + QTest::newRow("empty+disconnect") << QByteArray() << true; + + QTest::newRow("no-newline+disconnect") << QByteArray("Hello World") << true; + QTest::newRow("just-newline+disconnect") << QByteArray("\r\n") << true; + QTest::newRow("just-2newline+disconnect") << QByteArray("\r\n\r\n") << true; + QTest::newRow("with-newlines+disconnect") << QByteArray("Long first line\r\nLong second line") << true; + QTest::newRow("with-newlines2+disconnect") << QByteArray("\r\nSecond line") << true; + QTest::newRow("with-newlines3+disconnect") << QByteArray("ICY\r\nSecond line") << true; + + QTest::newRow("invalid-version+disconnect") << QByteArray("HTTP/123 200 ") << true; + QTest::newRow("invalid-version2+disconnect") << QByteArray("HTTP/a.\033 200 ") << true; + QTest::newRow("invalid-reply-code+disconnect") << QByteArray("HTTP/1.0 fuu ") << true; + + QTest::newRow("immediate disconnect") << QByteArray("") << true; + QTest::newRow("justHalfStatus+disconnect") << QByteArray("HTTP/1.1") << true; + QTest::newRow("justStatus+disconnect") << QByteArray("HTTP/1.1 200 OK\r\n") << true; + QTest::newRow("justStatusAndHalfHeaders+disconnect") << QByteArray("HTTP/1.1 200 OK\r\nContent-L") << true; + + QTest::newRow("halfContent+disconnect") << QByteArray("HTTP/1.1 200 OK\r\nContent-Length: 4\r\n\r\nAB") << true; + +} + +void tst_QNetworkReply::ioGetFromHttpBrokenServer() +{ + QFETCH(QByteArray, dataToSend); + QFETCH(bool, doDisconnect); + MiniHttpServer server(dataToSend); + server.doClose = doDisconnect; + + QNetworkRequest request(QUrl("http://localhost:" + QString::number(server.serverPort()))); + QNetworkReplyPtr reply = manager.get(request); + QSignalSpy spy(reply, SIGNAL(error(QNetworkReply::NetworkError))); + + + connect(reply, SIGNAL(finished()), &QTestEventLoop::instance(), SLOT(exitLoop())); + QTestEventLoop::instance().enterLoop(10); + QVERIFY(!QTestEventLoop::instance().timeout()); + + QCOMPARE(reply->url(), request.url()); + QCOMPARE(spy.count(), 1); + QVERIFY(reply->error() != QNetworkReply::NoError); +} + +void tst_QNetworkReply::ioGetFromHttpStatus100_data() +{ + QTest::addColumn<QByteArray>("dataToSend"); + QTest::addColumn<int>("statusCode"); + QTest::newRow("normal") << QByteArray("HTTP/1.1 100 Continue\r\n\r\nHTTP/1.1 200 OK\r\nContent-Length: 0\r\n\r\n") << 200; + QTest::newRow("minimal") << QByteArray("HTTP/1.1 100 Continue\n\nHTTP/1.1 200 OK\r\nContent-Length: 0\r\n\r\n") << 200; + QTest::newRow("minimal2") << QByteArray("HTTP/1.1 100 Continue\n\nHTTP/1.0 200 OK\r\n\r\n") << 200; + QTest::newRow("minimal3") << QByteArray("HTTP/1.1 100 Continue\n\nHTTP/1.0 200 OK\n\n") << 200; + QTest::newRow("minimal+404") << QByteArray("HTTP/1.1 100 Continue\n\nHTTP/1.0 204 No Content\r\n\r\n") << 204; + QTest::newRow("with_headers") << QByteArray("HTTP/1.1 100 Continue\r\nBla: x\r\n\r\nHTTP/1.1 200 OK\r\nContent-Length: 0\r\n\r\n") << 200; + QTest::newRow("with_headers2") << QByteArray("HTTP/1.1 100 Continue\nBla: x\n\nHTTP/1.1 200 OK\r\nContent-Length: 0\r\n\r\n") << 200; +} + +void tst_QNetworkReply::ioGetFromHttpStatus100() +{ + QFETCH(QByteArray, dataToSend); + QFETCH(int, statusCode); + MiniHttpServer server(dataToSend); + server.doClose = true; + + QNetworkRequest request(QUrl("http://localhost:" + QString::number(server.serverPort()))); + QNetworkReplyPtr reply = manager.get(request); + + connect(reply, SIGNAL(finished()), &QTestEventLoop::instance(), SLOT(exitLoop())); + QTestEventLoop::instance().enterLoop(10); + QVERIFY(!QTestEventLoop::instance().timeout()); + + QCOMPARE(reply->url(), request.url()); + QCOMPARE(reply->error(), QNetworkReply::NoError); + QCOMPARE(reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(), statusCode); + QVERIFY(reply->rawHeader("bla").isNull()); +} + +void tst_QNetworkReply::ioGetFromHttpNoHeaders_data() +{ + QTest::addColumn<QByteArray>("dataToSend"); + QTest::newRow("justStatus+noheaders+disconnect") << QByteArray("HTTP/1.0 200 OK\r\n\r\n"); +} + +void tst_QNetworkReply::ioGetFromHttpNoHeaders() +{ + QFETCH(QByteArray, dataToSend); + MiniHttpServer server(dataToSend); + server.doClose = true; + + QNetworkRequest request(QUrl("http://localhost:" + QString::number(server.serverPort()))); + QNetworkReplyPtr reply = manager.get(request); + + connect(reply, SIGNAL(finished()), &QTestEventLoop::instance(), SLOT(exitLoop())); + QTestEventLoop::instance().enterLoop(10); + QVERIFY(!QTestEventLoop::instance().timeout()); + + QCOMPARE(reply->url(), request.url()); + QCOMPARE(reply->error(), QNetworkReply::NoError); + QCOMPARE(reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(), 200); +} + +void tst_QNetworkReply::ioGetFromHttpWithCache_data() +{ + qRegisterMetaType<MyMemoryCache::CachedContent>(); + QTest::addColumn<QByteArray>("dataToSend"); + QTest::addColumn<QString>("body"); + QTest::addColumn<MyMemoryCache::CachedContent>("cachedReply"); + QTest::addColumn<int>("cacheMode"); + QTest::addColumn<QStringList>("extraHttpHeaders"); + QTest::addColumn<bool>("loadedFromCache"); + QTest::addColumn<bool>("networkUsed"); + + QByteArray reply200 = + "HTTP/1.0 200\r\n" + "Connection: keep-alive\r\n" + "Content-Type: text/plain\r\n" + "Cache-control: no-cache\r\n" + "Content-length: 8\r\n" + "\r\n" + "Reloaded"; + QByteArray reply304 = + "HTTP/1.0 304 Use Cache\r\n" + "Connection: keep-alive\r\n" + "\r\n"; + + QTest::newRow("not-cached,always-network") + << reply200 << "Reloaded" << MyMemoryCache::CachedContent() << int(QNetworkRequest::AlwaysNetwork) << QStringList() << false << true; + QTest::newRow("not-cached,prefer-network") + << reply200 << "Reloaded" << MyMemoryCache::CachedContent() << int(QNetworkRequest::PreferNetwork) << QStringList() << false << true; + QTest::newRow("not-cached,prefer-cache") + << reply200 << "Reloaded" << MyMemoryCache::CachedContent() << int(QNetworkRequest::PreferCache) << QStringList() << false << true; + + QDateTime present = QDateTime::currentDateTime().toUTC(); + QDateTime past = present.addSecs(-3600); + QDateTime future = present.addSecs(3600); + static const char dateFormat[] = "ddd, dd MMM yyyy hh:mm:ss 'GMT'"; + + QNetworkCacheMetaData::RawHeaderList rawHeaders; + MyMemoryCache::CachedContent content; + content.second = "Not-reloaded"; + content.first.setLastModified(past); + + // + // Set to expired + // + rawHeaders.clear(); + rawHeaders << QNetworkCacheMetaData::RawHeader("Date", QLocale::c().toString(past, dateFormat).toLatin1()) + << QNetworkCacheMetaData::RawHeader("Cache-control", "max-age=0"); // isn't used in cache loading + content.first.setRawHeaders(rawHeaders); + content.first.setLastModified(past); + + QTest::newRow("expired,200,prefer-network") + << reply200 << "Reloaded" << content << int(QNetworkRequest::PreferNetwork) << QStringList() << false << true; + QTest::newRow("expired,200,prefer-cache") + << reply200 << "Reloaded" << content << int(QNetworkRequest::PreferCache) << QStringList() << false << true; + + QTest::newRow("expired,304,prefer-network") + << reply304 << "Not-reloaded" << content << int(QNetworkRequest::PreferNetwork) << QStringList() << true << true; + QTest::newRow("expired,304,prefer-cache") + << reply304 << "Not-reloaded" << content << int(QNetworkRequest::PreferCache) << QStringList() << true << true; + + // + // Set to not-expired + // + rawHeaders.clear(); + rawHeaders << QNetworkCacheMetaData::RawHeader("Date", QLocale::c().toString(past, dateFormat).toLatin1()) + << QNetworkCacheMetaData::RawHeader("Cache-control", "max-age=7200"); // isn't used in cache loading + content.first.setRawHeaders(rawHeaders); + content.first.setExpirationDate(future); + + QTest::newRow("not-expired,200,always-network") + << reply200 << "Reloaded" << content << int(QNetworkRequest::AlwaysNetwork) << QStringList() << false << true; + QTest::newRow("not-expired,200,prefer-network") + << reply200 << "Not-reloaded" << content << int(QNetworkRequest::PreferNetwork) << QStringList() << true << false; + QTest::newRow("not-expired,200,prefer-cache") + << reply200 << "Not-reloaded" << content << int(QNetworkRequest::PreferCache) << QStringList() << true << false; + QTest::newRow("not-expired,200,always-cache") + << reply200 << "Not-reloaded" << content << int(QNetworkRequest::AlwaysCache) << QStringList() << true << false; + + QTest::newRow("not-expired,304,prefer-network") + << reply304 << "Not-reloaded" << content << int(QNetworkRequest::PreferNetwork) << QStringList() << true << false; + QTest::newRow("not-expired,304,prefer-cache") + << reply304 << "Not-reloaded" << content << int(QNetworkRequest::PreferCache) << QStringList() << true << false; + QTest::newRow("not-expired,304,always-cache") + << reply304 << "Not-reloaded" << content << int(QNetworkRequest::AlwaysCache) << QStringList() << true << false; + + // + // Set must-revalidate now + // + rawHeaders.clear(); + rawHeaders << QNetworkCacheMetaData::RawHeader("Date", QLocale::c().toString(past, dateFormat).toLatin1()) + << QNetworkCacheMetaData::RawHeader("Cache-control", "max-age=7200, must-revalidate"); // must-revalidate is used + content.first.setRawHeaders(rawHeaders); + + QTest::newRow("must-revalidate,200,always-network") + << reply200 << "Reloaded" << content << int(QNetworkRequest::AlwaysNetwork) << QStringList() << false << true; + QTest::newRow("must-revalidate,200,prefer-network") + << reply200 << "Reloaded" << content << int(QNetworkRequest::PreferNetwork) << QStringList() << false << true; + QTest::newRow("must-revalidate,200,prefer-cache") + << reply200 << "Reloaded" << content << int(QNetworkRequest::PreferCache) << QStringList() << false << true; + QTest::newRow("must-revalidate,200,always-cache") + << reply200 << "" << content << int(QNetworkRequest::AlwaysCache) << QStringList() << false << false; + + QTest::newRow("must-revalidate,304,prefer-network") + << reply304 << "Not-reloaded" << content << int(QNetworkRequest::PreferNetwork) << QStringList() << true << true; + QTest::newRow("must-revalidate,304,prefer-cache") + << reply304 << "Not-reloaded" << content << int(QNetworkRequest::PreferCache) << QStringList() << true << true; + QTest::newRow("must-revalidate,304,always-cache") + << reply304 << "" << content << int(QNetworkRequest::AlwaysCache) << QStringList() << false << false; + + // + // Partial content + // + rawHeaders.clear(); + rawHeaders << QNetworkCacheMetaData::RawHeader("Date", QLocale::c().toString(past, dateFormat).toLatin1()) + << QNetworkCacheMetaData::RawHeader("Cache-control", "max-age=7200"); // isn't used in cache loading + content.first.setRawHeaders(rawHeaders); + content.first.setExpirationDate(future); + + QByteArray reply206 = + "HTTP/1.0 206\r\n" + "Connection: keep-alive\r\n" + "Content-Type: text/plain\r\n" + "Cache-control: no-cache\r\n" + "Content-Range: bytes 2-6/8\r\n" + "Content-length: 4\r\n" + "\r\n" + "load"; + + QTest::newRow("partial,dontuse-cache") + << reply206 << "load" << content << int(QNetworkRequest::PreferCache) << (QStringList() << "Range" << "bytes=2-6") << false << true; +} + +void tst_QNetworkReply::ioGetFromHttpWithCache() +{ + QFETCH(QByteArray, dataToSend); + MiniHttpServer server(dataToSend); + server.doClose = false; + + MyMemoryCache *memoryCache = new MyMemoryCache(&manager); + manager.setCache(memoryCache); + + QFETCH(MyMemoryCache::CachedContent, cachedReply); + QUrl url = "http://localhost:" + QString::number(server.serverPort()); + cachedReply.first.setUrl(url); + if (!cachedReply.second.isNull()) + memoryCache->cache.insert(url.toEncoded(), cachedReply); + + QFETCH(int, cacheMode); + QNetworkRequest request(url); + request.setAttribute(QNetworkRequest::CacheLoadControlAttribute, cacheMode); + request.setAttribute(QNetworkRequest::CacheSaveControlAttribute, false); + + QFETCH(QStringList, extraHttpHeaders); + QStringListIterator it(extraHttpHeaders); + while (it.hasNext()) { + QString header = it.next(); + QString value = it.next(); + request.setRawHeader(header.toLatin1(), value.toLatin1()); // To latin1? Deal with it! + } + + QNetworkReplyPtr reply = manager.get(request); + + connect(reply, SIGNAL(finished()), &QTestEventLoop::instance(), SLOT(exitLoop())); + QTestEventLoop::instance().enterLoop(10); + QVERIFY(!QTestEventLoop::instance().timeout()); + + QTEST(reply->attribute(QNetworkRequest::SourceIsFromCacheAttribute).toBool(), "loadedFromCache"); + QTEST(server.totalConnections > 0, "networkUsed"); + QFETCH(QString, body); + QCOMPARE(reply->readAll().constData(), qPrintable(body)); +} + +void tst_QNetworkReply::ioGetWithManyProxies_data() +{ + QTest::addColumn<QList<QNetworkProxy> >("proxyList"); + QTest::addColumn<QNetworkProxy>("proxyUsed"); + QTest::addColumn<QString>("url"); + QTest::addColumn<QNetworkReply::NetworkError>("expectedError"); + + QList<QNetworkProxy> proxyList; + + // All of the other functions test DefaultProxy + // So let's test something else + + // Simple tests that work: + + // HTTP request with HTTP caching proxy + proxyList << QNetworkProxy(QNetworkProxy::HttpCachingProxy, QtNetworkSettings::serverName(), 3129); + QTest::newRow("http-on-http") + << proxyList << proxyList.at(0) + << "http://" + QtNetworkSettings::serverName() + "/qtest/rfc3252.txt" + << QNetworkReply::NoError; + + // HTTP request with HTTP transparent proxy + proxyList.clear(); + proxyList << QNetworkProxy(QNetworkProxy::HttpProxy, QtNetworkSettings::serverName(), 3129); + QTest::newRow("http-on-http2") + << proxyList << proxyList.at(0) + << "http://" + QtNetworkSettings::serverName() + "/qtest/rfc3252.txt" + << QNetworkReply::NoError; + + // HTTP request with SOCKS transparent proxy + proxyList.clear(); + proxyList << QNetworkProxy(QNetworkProxy::Socks5Proxy, QtNetworkSettings::serverName(), 1081); + QTest::newRow("http-on-socks") + << proxyList << proxyList.at(0) + << "http://" + QtNetworkSettings::serverName() + "/qtest/rfc3252.txt" + << QNetworkReply::NoError; + + // FTP request with FTP caching proxy + proxyList.clear(); + proxyList << QNetworkProxy(QNetworkProxy::FtpCachingProxy, QtNetworkSettings::serverName(), 2121); + QTest::newRow("ftp-on-ftp") + << proxyList << proxyList.at(0) + << "ftp://" + QtNetworkSettings::serverName() + "/qtest/rfc3252.txt" + << QNetworkReply::NoError; + + // The following test doesn't work because QFtp is too limited + // It can only talk to its own kind of proxies + + // FTP request with SOCKSv5 transparent proxy + proxyList.clear(); + proxyList << QNetworkProxy(QNetworkProxy::Socks5Proxy, QtNetworkSettings::serverName(), 1081); + QTest::newRow("ftp-on-socks") + << proxyList << proxyList.at(0) + << "ftp://" + QtNetworkSettings::serverName() + "/qtest/rfc3252.txt" + << QNetworkReply::NoError; + +#ifndef QT_NO_OPENSSL + // HTTPS with HTTP transparent proxy + proxyList.clear(); + proxyList << QNetworkProxy(QNetworkProxy::HttpProxy, QtNetworkSettings::serverName(), 3129); + QTest::newRow("https-on-http") + << proxyList << proxyList.at(0) + << "https://" + QtNetworkSettings::serverName() + "/qtest/rfc3252.txt" + << QNetworkReply::NoError; + + // HTTPS request with SOCKS transparent proxy + proxyList.clear(); + proxyList << QNetworkProxy(QNetworkProxy::Socks5Proxy, QtNetworkSettings::serverName(), 1081); + QTest::newRow("https-on-socks") + << proxyList << proxyList.at(0) + << "https://" + QtNetworkSettings::serverName() + "/qtest/rfc3252.txt" + << QNetworkReply::NoError; +#endif + + // Tests that fail: + + // HTTP request with FTP caching proxy + proxyList.clear(); + proxyList << QNetworkProxy(QNetworkProxy::FtpCachingProxy, QtNetworkSettings::serverName(), 2121); + QTest::newRow("http-on-ftp") + << proxyList << QNetworkProxy() + << "http://" + QtNetworkSettings::serverName() + "/qtest/rfc3252.txt" + << QNetworkReply::ProxyNotFoundError; + + // FTP request with HTTP caching proxy + proxyList.clear(); + proxyList << QNetworkProxy(QNetworkProxy::HttpCachingProxy, QtNetworkSettings::serverName(), 3129); + QTest::newRow("ftp-on-http") + << proxyList << QNetworkProxy() + << "ftp://" + QtNetworkSettings::serverName() + "/qtest/rfc3252.txt" + << QNetworkReply::ProxyNotFoundError; + + // FTP request with HTTP caching proxies + proxyList.clear(); + proxyList << QNetworkProxy(QNetworkProxy::HttpCachingProxy, QtNetworkSettings::serverName(), 3129) + << QNetworkProxy(QNetworkProxy::HttpCachingProxy, QtNetworkSettings::serverName(), 3130); + QTest::newRow("ftp-on-multiple-http") + << proxyList << QNetworkProxy() + << "ftp://" + QtNetworkSettings::serverName() + "/qtest/rfc3252.txt" + << QNetworkReply::ProxyNotFoundError; + +#ifndef QT_NO_OPENSSL + // HTTPS with HTTP caching proxy + proxyList.clear(); + proxyList << QNetworkProxy(QNetworkProxy::HttpCachingProxy, QtNetworkSettings::serverName(), 3129); + QTest::newRow("https-on-httptransparent") + << proxyList << QNetworkProxy() + << "https://" + QtNetworkSettings::serverName() + "/qtest/rfc3252.txt" + << QNetworkReply::ProxyNotFoundError; + + // HTTPS with FTP caching proxy + proxyList.clear(); + proxyList << QNetworkProxy(QNetworkProxy::FtpCachingProxy, QtNetworkSettings::serverName(), 2121); + QTest::newRow("https-on-ftp") + << proxyList << QNetworkProxy() + << "https://" + QtNetworkSettings::serverName() + "/qtest/rfc3252.txt" + << QNetworkReply::ProxyNotFoundError; +#endif + + // Complex requests: + + // HTTP request with more than one HTTP proxy + proxyList.clear(); + proxyList << QNetworkProxy(QNetworkProxy::HttpCachingProxy, QtNetworkSettings::serverName(), 3129) + << QNetworkProxy(QNetworkProxy::HttpCachingProxy, QtNetworkSettings::serverName(), 3130); + QTest::newRow("http-on-multiple-http") + << proxyList << proxyList.at(0) + << "http://" + QtNetworkSettings::serverName() + "/qtest/rfc3252.txt" + << QNetworkReply::NoError; + + // HTTP request with HTTP + SOCKS + proxyList.clear(); + proxyList << QNetworkProxy(QNetworkProxy::HttpCachingProxy, QtNetworkSettings::serverName(), 3129) + << QNetworkProxy(QNetworkProxy::Socks5Proxy, QtNetworkSettings::serverName(), 1081); + QTest::newRow("http-on-http+socks") + << proxyList << proxyList.at(0) + << "http://" + QtNetworkSettings::serverName() + "/qtest/rfc3252.txt" + << QNetworkReply::NoError; + + // HTTP request with FTP + HTTP + SOCKS + proxyList.clear(); + proxyList << QNetworkProxy(QNetworkProxy::FtpCachingProxy, QtNetworkSettings::serverName(), 2121) + << QNetworkProxy(QNetworkProxy::HttpCachingProxy, QtNetworkSettings::serverName(), 3129) + << QNetworkProxy(QNetworkProxy::Socks5Proxy, QtNetworkSettings::serverName(), 1081); + QTest::newRow("http-on-ftp+http+socks") + << proxyList << proxyList.at(1) // second proxy should be used + << "http://" + QtNetworkSettings::serverName() + "/qtest/rfc3252.txt" + << QNetworkReply::NoError; + + // HTTP request with NoProxy + HTTP + proxyList.clear(); + proxyList << QNetworkProxy(QNetworkProxy::NoProxy) + << QNetworkProxy(QNetworkProxy::HttpCachingProxy, QtNetworkSettings::serverName(), 3129); + QTest::newRow("http-on-noproxy+http") + << proxyList << proxyList.at(0) + << "http://" + QtNetworkSettings::serverName() + "/qtest/rfc3252.txt" + << QNetworkReply::NoError; + + // HTTP request with FTP + NoProxy + proxyList.clear(); + proxyList << QNetworkProxy(QNetworkProxy::FtpCachingProxy, QtNetworkSettings::serverName(), 2121) + << QNetworkProxy(QNetworkProxy::NoProxy); + QTest::newRow("http-on-ftp+noproxy") + << proxyList << proxyList.at(1) // second proxy should be used + << "http://" + QtNetworkSettings::serverName() + "/qtest/rfc3252.txt" + << QNetworkReply::NoError; + + // FTP request with HTTP Caching + FTP + proxyList.clear(); + proxyList << QNetworkProxy(QNetworkProxy::HttpCachingProxy, QtNetworkSettings::serverName(), 3129) + << QNetworkProxy(QNetworkProxy::FtpCachingProxy, QtNetworkSettings::serverName(), 2121); + QTest::newRow("ftp-on-http+ftp") + << proxyList << proxyList.at(1) // second proxy should be used + << "ftp://" + QtNetworkSettings::serverName() + "/qtest/rfc3252.txt" + << QNetworkReply::NoError; + +#ifndef QT_NO_OPENSSL + // HTTPS request with HTTP Caching + HTTP transparent + proxyList.clear(); + proxyList << QNetworkProxy(QNetworkProxy::HttpCachingProxy, QtNetworkSettings::serverName(), 3129) + << QNetworkProxy(QNetworkProxy::HttpProxy, QtNetworkSettings::serverName(), 3129); + QTest::newRow("https-on-httpcaching+http") + << proxyList << proxyList.at(1) // second proxy should be used + << "https://" + QtNetworkSettings::serverName() + "/qtest/rfc3252.txt" + << QNetworkReply::NoError; + + // HTTPS request with FTP + HTTP C + HTTP T + proxyList.clear(); + proxyList << QNetworkProxy(QNetworkProxy::FtpCachingProxy, QtNetworkSettings::serverName(), 2121) + << QNetworkProxy(QNetworkProxy::HttpCachingProxy, QtNetworkSettings::serverName(), 3129) + << QNetworkProxy(QNetworkProxy::HttpProxy, QtNetworkSettings::serverName(), 3129); + QTest::newRow("https-on-ftp+httpcaching+http") + << proxyList << proxyList.at(2) // skip the first two + << "https://" + QtNetworkSettings::serverName() + "/qtest/rfc3252.txt" + << QNetworkReply::NoError; +#endif +} + +void tst_QNetworkReply::ioGetWithManyProxies() +{ + // Test proxy factories + + qRegisterMetaType<QNetworkProxy>(); // for QSignalSpy + qRegisterMetaType<QAuthenticator *>(); + + QFile reference(SRCDIR "/rfc3252.txt"); + QVERIFY(reference.open(QIODevice::ReadOnly)); + + // set the proxy factory: + QFETCH(QList<QNetworkProxy>, proxyList); + MyProxyFactory *proxyFactory = new MyProxyFactory; + proxyFactory->toReturn = proxyList; + manager.setProxyFactory(proxyFactory); + + QFETCH(QString, url); + QUrl theUrl(url); + QNetworkRequest request(theUrl); + QNetworkReplyPtr reply = manager.get(request); + DataReader reader(reply); + + QSignalSpy authspy(&manager, SIGNAL(proxyAuthenticationRequired(QNetworkProxy,QAuthenticator*))); + connect(&manager, SIGNAL(proxyAuthenticationRequired(QNetworkProxy,QAuthenticator*)), + SLOT(proxyAuthenticationRequired(QNetworkProxy,QAuthenticator*))); + connect(reply, SIGNAL(finished()), &QTestEventLoop::instance(), SLOT(exitLoop())); +#ifndef QT_NO_OPENSSL + connect(&manager, SIGNAL(sslErrors(QNetworkReply*,QList<QSslError>)), + SLOT(sslErrors(QNetworkReply*,QList<QSslError>))); +#endif + QTestEventLoop::instance().enterLoop(15); + QVERIFY(!QTestEventLoop::instance().timeout()); + + manager.disconnect(SIGNAL(proxyAuthenticationRequired(QNetworkProxy,QAuthenticator*)), + this, SLOT(proxyAuthenticationRequired(QNetworkProxy,QAuthenticator*))); +#ifndef QT_NO_OPENSSL + manager.disconnect(SIGNAL(sslErrors(QNetworkReply*,QList<QSslError>)), + this, SLOT(sslErrors(QNetworkReply*,QList<QSslError>))); +#endif + + QFETCH(QNetworkReply::NetworkError, expectedError); + QEXPECT_FAIL("ftp-on-socks", "QFtp is too limited and won't accept non-FTP proxies", Abort); + QCOMPARE(reply->error(), expectedError); + + // Verify that the factory was called properly + QCOMPARE(proxyFactory->callCount, 1); + QCOMPARE(proxyFactory->lastQuery, QNetworkProxyQuery(theUrl)); + + if (expectedError == QNetworkReply::NoError) { + // request succeeded + QCOMPARE(reader.data, reference.readAll()); + + // now verify that the proxies worked: + QFETCH(QNetworkProxy, proxyUsed); + if (proxyUsed.type() == QNetworkProxy::NoProxy) { + QCOMPARE(authspy.count(), 0); + } else { + if (QByteArray(QTest::currentDataTag()).startsWith("ftp-")) + return; // No authentication with current FTP or with FTP proxies + QCOMPARE(authspy.count(), 1); + QCOMPARE(qvariant_cast<QNetworkProxy>(authspy.at(0).at(0)), proxyUsed); + } + } else { + // request failed + QCOMPARE(authspy.count(), 0); + } +} + +void tst_QNetworkReply::ioPutToFileFromFile_data() +{ + QTest::addColumn<QString>("fileName"); + + QTest::newRow("empty") << SRCDIR "/empty"; + QTest::newRow("real-file") << SRCDIR "/rfc3252.txt"; + QTest::newRow("resource") << ":/resource"; + QTest::newRow("search-path") << "srcdir:/rfc3252.txt"; +} + +void tst_QNetworkReply::ioPutToFileFromFile() +{ + QFETCH(QString, fileName); + QFile sourceFile(fileName); + QFile targetFile(testFileName); + + QVERIFY(sourceFile.open(QIODevice::ReadOnly)); + + QUrl url = QUrl::fromLocalFile(targetFile.fileName()); + QNetworkRequest request(url); + QNetworkReplyPtr reply = manager.put(request, &sourceFile); + + connect(reply, SIGNAL(finished()), &QTestEventLoop::instance(), SLOT(exitLoop())); + QTestEventLoop::instance().enterLoop(10); + QVERIFY(!QTestEventLoop::instance().timeout()); + + QCOMPARE(reply->url(), url); + QCOMPARE(reply->error(), QNetworkReply::NoError); + QCOMPARE(reply->header(QNetworkRequest::ContentLengthHeader).toLongLong(), Q_INT64_C(0)); + QVERIFY(reply->readAll().isEmpty()); + + QVERIFY(sourceFile.atEnd()); + sourceFile.seek(0); // reset it to the beginning + + QVERIFY(targetFile.open(QIODevice::ReadOnly)); + QCOMPARE(targetFile.size(), sourceFile.size()); + QCOMPARE(targetFile.readAll(), sourceFile.readAll()); +} + +void tst_QNetworkReply::ioPutToFileFromSocket_data() +{ + putToFile_data(); +} + +void tst_QNetworkReply::ioPutToFileFromSocket() +{ + QFile file(testFileName); + + QUrl url = QUrl::fromLocalFile(file.fileName()); + QNetworkRequest request(url); + + QFETCH(QByteArray, data); + SocketPair socketpair; + socketpair.create(); + QVERIFY(socketpair.endPoints[0] && socketpair.endPoints[1]); + + socketpair.endPoints[0]->write(data); + QNetworkReplyPtr reply = manager.put(QNetworkRequest(url), socketpair.endPoints[1]); + socketpair.endPoints[0]->close(); + + connect(reply, SIGNAL(finished()), &QTestEventLoop::instance(), SLOT(exitLoop())); + QTestEventLoop::instance().enterLoop(10); + QCOMPARE(reply->error(), QNetworkReply::NoError); + QVERIFY(!QTestEventLoop::instance().timeout()); + + QCOMPARE(reply->url(), url); + QCOMPARE(reply->error(), QNetworkReply::NoError); + QCOMPARE(reply->header(QNetworkRequest::ContentLengthHeader).toLongLong(), Q_INT64_C(0)); + QVERIFY(reply->readAll().isEmpty()); + + QVERIFY(file.open(QIODevice::ReadOnly)); + QCOMPARE(file.size(), qint64(data.size())); + QByteArray contents = file.readAll(); + QCOMPARE(contents, data); +} + +void tst_QNetworkReply::ioPutToFileFromLocalSocket_data() +{ + putToFile_data(); +} + +void tst_QNetworkReply::ioPutToFileFromLocalSocket() +{ + QString socketname = "networkreplytest"; + QLocalServer server; + if (!server.listen(socketname)) { + QLocalServer::removeServer(socketname); + QVERIFY(server.listen(socketname)); + } + QLocalSocket active; + active.connectToServer(socketname); + QVERIFY2(server.waitForNewConnection(10), server.errorString().toLatin1().constData()); + QVERIFY2(active.waitForConnected(10), active.errorString().toLatin1().constData()); + QVERIFY2(server.hasPendingConnections(), server.errorString().toLatin1().constData()); + QLocalSocket *passive = server.nextPendingConnection(); + + QFile file(testFileName); + QUrl url = QUrl::fromLocalFile(file.fileName()); + QNetworkRequest request(url); + + QFETCH(QByteArray, data); + active.write(data); + active.close(); + QNetworkReplyPtr reply = manager.put(QNetworkRequest(url), passive); + passive->setParent(reply); + + connect(reply, SIGNAL(finished()), &QTestEventLoop::instance(), SLOT(exitLoop())); + QTestEventLoop::instance().enterLoop(10); + QCOMPARE(reply->error(), QNetworkReply::NoError); + QVERIFY(!QTestEventLoop::instance().timeout()); + + QCOMPARE(reply->url(), url); + QCOMPARE(reply->error(), QNetworkReply::NoError); + QCOMPARE(reply->header(QNetworkRequest::ContentLengthHeader).toLongLong(), Q_INT64_C(0)); + QVERIFY(reply->readAll().isEmpty()); + + QVERIFY(file.open(QIODevice::ReadOnly)); + QCOMPARE(file.size(), qint64(data.size())); + QByteArray contents = file.readAll(); + QCOMPARE(contents, data); +} + +void tst_QNetworkReply::ioPutToFileFromProcess_data() +{ + putToFile_data(); +} + +void tst_QNetworkReply::ioPutToFileFromProcess() +{ +#if defined(Q_OS_WINCE) || defined (Q_OS_SYMBIAN) + QSKIP("Currently no stdin/out supported for Windows CE / Symbian OS", SkipAll); +#else + +#ifdef Q_OS_WIN + if (qstrcmp(QTest::currentDataTag(), "small") == 0) + QSKIP("When passing a CR-LF-LF sequence through Windows stdio, it gets converted, " + "so this test fails. Disabled on Windows", SkipSingle); +#endif + +#if defined(QT_NO_PROCESS) + QSKIP("Qt was compiled with QT_NO_PROCESS", SkipAll); +#else + QFile file(testFileName); + + QUrl url = QUrl::fromLocalFile(file.fileName()); + QNetworkRequest request(url); + + QFETCH(QByteArray, data); + QProcess process; + process.start("echo/echo all"); + process.write(data); + process.closeWriteChannel(); + + QNetworkReplyPtr reply = manager.put(QNetworkRequest(url), &process); + + connect(reply, SIGNAL(finished()), &QTestEventLoop::instance(), SLOT(exitLoop())); + QTestEventLoop::instance().enterLoop(10); + QVERIFY(!QTestEventLoop::instance().timeout()); + + QCOMPARE(reply->url(), url); + QCOMPARE(reply->error(), QNetworkReply::NoError); + QCOMPARE(reply->header(QNetworkRequest::ContentLengthHeader).toLongLong(), Q_INT64_C(0)); + QVERIFY(reply->readAll().isEmpty()); + + QVERIFY(file.open(QIODevice::ReadOnly)); + QCOMPARE(file.size(), qint64(data.size())); + QByteArray contents = file.readAll(); + QCOMPARE(contents, data); +#endif +#endif +} + +void tst_QNetworkReply::ioPutToFtpFromFile_data() +{ + ioPutToFileFromFile_data(); +} + +void tst_QNetworkReply::ioPutToFtpFromFile() +{ + QFETCH(QString, fileName); + QFile sourceFile(fileName); + QVERIFY(sourceFile.open(QIODevice::ReadOnly)); + + QUrl url("ftp://" + QtNetworkSettings::serverName()); + url.setPath(QString("/qtest/upload/qnetworkaccess-ioPutToFtpFromFile-%1-%2") + .arg(QTest::currentDataTag()) + .arg(uniqueExtension)); + + QNetworkRequest request(url); + QNetworkReplyPtr reply = manager.put(request, &sourceFile); + + connect(reply, SIGNAL(finished()), &QTestEventLoop::instance(), SLOT(exitLoop())); + QTestEventLoop::instance().enterLoop(10); + QVERIFY(!QTestEventLoop::instance().timeout()); + + QCOMPARE(reply->url(), url); + QCOMPARE(reply->error(), QNetworkReply::NoError); + QCOMPARE(reply->header(QNetworkRequest::ContentLengthHeader).toLongLong(), Q_INT64_C(0)); + QVERIFY(reply->readAll().isEmpty()); + + QVERIFY(sourceFile.atEnd()); + sourceFile.seek(0); // reset it to the beginning + + // download the file again from FTP to make sure it was uploaded + // correctly + QFtp ftp; + ftp.connectToHost(url.host()); + ftp.login(); + ftp.get(url.path()); + + QObject::connect(&ftp, SIGNAL(done(bool)), &QTestEventLoop::instance(), SLOT(exitLoop())); + QTestEventLoop::instance().enterLoop(3); + QObject::disconnect(&ftp, SIGNAL(done(bool)), &QTestEventLoop::instance(), SLOT(exitLoop())); + + QByteArray uploaded = ftp.readAll(); + QCOMPARE(qint64(uploaded.size()), sourceFile.size()); + QCOMPARE(uploaded, sourceFile.readAll()); + + ftp.close(); + QObject::connect(&ftp, SIGNAL(done(bool)), &QTestEventLoop::instance(), SLOT(exitLoop())); + QTestEventLoop::instance().enterLoop(10); + QObject::disconnect(&ftp, SIGNAL(done(bool)), &QTestEventLoop::instance(), SLOT(exitLoop())); +} + +void tst_QNetworkReply::ioPutToHttpFromFile_data() +{ + ioPutToFileFromFile_data(); +} + +void tst_QNetworkReply::ioPutToHttpFromFile() +{ + QFETCH(QString, fileName); + QFile sourceFile(fileName); + QVERIFY(sourceFile.open(QIODevice::ReadOnly)); + + QUrl url("http://" + QtNetworkSettings::serverName()); + url.setPath(QString("/dav/qnetworkaccess-ioPutToHttpFromFile-%1-%2") + .arg(QTest::currentDataTag()) + .arg(uniqueExtension)); + + QNetworkRequest request(url); + QNetworkReplyPtr reply = manager.put(request, &sourceFile); + + connect(reply, SIGNAL(finished()), &QTestEventLoop::instance(), SLOT(exitLoop())); + QTestEventLoop::instance().enterLoop(10); + QVERIFY(!QTestEventLoop::instance().timeout()); + + QCOMPARE(reply->url(), url); + QCOMPARE(reply->error(), QNetworkReply::NoError); + + // verify that the HTTP status code is 201 Created + QCOMPARE(reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(), 201); + + QVERIFY(sourceFile.atEnd()); + sourceFile.seek(0); // reset it to the beginning + + // download the file again from HTTP to make sure it was uploaded + // correctly + reply = manager.get(request); + connect(reply, SIGNAL(finished()), &QTestEventLoop::instance(), SLOT(exitLoop())); + QTestEventLoop::instance().enterLoop(10); + QVERIFY(!QTestEventLoop::instance().timeout()); + + QCOMPARE(reply->url(), url); + QCOMPARE(reply->error(), QNetworkReply::NoError); + QCOMPARE(reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(), 200); // 200 Ok + + QCOMPARE(reply->readAll(), sourceFile.readAll()); +} + +void tst_QNetworkReply::ioPostToHttpFromFile_data() +{ + ioPutToFileFromFile_data(); +} + +void tst_QNetworkReply::ioPostToHttpFromFile() +{ + QFETCH(QString, fileName); + QFile sourceFile(fileName); + QVERIFY(sourceFile.open(QIODevice::ReadOnly)); + + QUrl url("http://" + QtNetworkSettings::serverName() + "/qtest/cgi-bin/md5sum.cgi"); + QNetworkRequest request(url); + request.setRawHeader("Content-Type", "application/octet-stream"); + + QNetworkReplyPtr reply = manager.post(request, &sourceFile); + + connect(reply, SIGNAL(finished()), &QTestEventLoop::instance(), SLOT(exitLoop())); + QTestEventLoop::instance().enterLoop(10); + QVERIFY(!QTestEventLoop::instance().timeout()); + + QCOMPARE(reply->url(), url); + QCOMPARE(reply->error(), QNetworkReply::NoError); + + // verify that the HTTP status code is 200 Ok + QCOMPARE(reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(), 200); + + QVERIFY(sourceFile.atEnd()); + sourceFile.seek(0); // reset it to the beginning + + QCOMPARE(reply->readAll().trimmed(), md5sum(sourceFile.readAll()).toHex()); +} + +void tst_QNetworkReply::ioPostToHttpFromSocket_data() +{ + QTest::addColumn<QByteArray>("data"); + QTest::addColumn<QByteArray>("md5sum"); + QTest::addColumn<QUrl>("url"); + QTest::addColumn<QNetworkProxy>("proxy"); + QTest::addColumn<int>("authenticationRequiredCount"); + QTest::addColumn<int>("proxyAuthenticationRequiredCount"); + + for (int i = 0; i < proxies.count(); ++i) + for (int auth = 0; auth < 2; ++auth) { + QUrl url; + if (auth) + url = "http://" + QtNetworkSettings::serverName() + "/qtest/protected/cgi-bin/md5sum.cgi"; + else + url = "http://" + QtNetworkSettings::serverName() + "/qtest/cgi-bin/md5sum.cgi"; + + QNetworkProxy proxy = proxies.at(i).proxy; + QByteArray testsuffix = QByteArray(auth ? "+auth" : "") + proxies.at(i).tag; + int proxyauthcount = proxies.at(i).requiresAuthentication; + + QByteArray data; + data = ""; + QTest::newRow("empty" + testsuffix) << data << md5sum(data) << url << proxy << auth << proxyauthcount; + + data = "This is a normal message."; + QTest::newRow("generic" + testsuffix) << data << md5sum(data) << url << proxy << auth << proxyauthcount; + + data = "This is a message to show that Qt rocks!\r\n\n"; + QTest::newRow("small" + testsuffix) << data << md5sum(data) << url << proxy << auth << proxyauthcount; + + data = QByteArray("abcd\0\1\2\abcd",12); + QTest::newRow("with-nul" + testsuffix) << data << md5sum(data) << url << proxy << auth << proxyauthcount; + + data = QByteArray(4097, '\4'); + QTest::newRow("4k+1" + testsuffix) << data << md5sum(data) << url << proxy << auth << proxyauthcount; + + data = QByteArray(128*1024+1, '\177'); + QTest::newRow("128k+1" + testsuffix) << data << md5sum(data) << url << proxy << auth << proxyauthcount; + } +} + +void tst_QNetworkReply::ioPostToHttpFromSocket() +{ + qRegisterMetaType<QNetworkProxy>(); // for QSignalSpy + qRegisterMetaType<QAuthenticator *>(); + qRegisterMetaType<QNetworkReply *>(); + + QFETCH(QByteArray, data); + QFETCH(QUrl, url); + QFETCH(QNetworkProxy, proxy); + SocketPair socketpair; + socketpair.create(); + QVERIFY(socketpair.endPoints[0] && socketpair.endPoints[1]); + + socketpair.endPoints[0]->write(data); + + QNetworkRequest request(url); + request.setRawHeader("Content-Type", "application/octet-stream"); + + manager.setProxy(proxy); + QNetworkReplyPtr reply = manager.post(request, socketpair.endPoints[1]); + socketpair.endPoints[0]->close(); + + connect(reply, SIGNAL(finished()), &QTestEventLoop::instance(), SLOT(exitLoop())); + connect(&manager, SIGNAL(proxyAuthenticationRequired(QNetworkProxy,QAuthenticator*)), + SLOT(proxyAuthenticationRequired(QNetworkProxy,QAuthenticator*))); + connect(&manager, SIGNAL(authenticationRequired(QNetworkReply*,QAuthenticator*)), + SLOT(authenticationRequired(QNetworkReply*,QAuthenticator*))); + + QSignalSpy authenticationRequiredSpy(&manager, SIGNAL(authenticationRequired(QNetworkReply*,QAuthenticator*))); + QSignalSpy proxyAuthenticationRequiredSpy(&manager, SIGNAL(proxyAuthenticationRequired(QNetworkProxy,QAuthenticator*))); + + QTestEventLoop::instance().enterLoop(12); + disconnect(&manager, SIGNAL(proxyAuthenticationRequired(QNetworkProxy,QAuthenticator*)), + this, SLOT(proxyAuthenticationRequired(QNetworkProxy,QAuthenticator*))); + disconnect(&manager, SIGNAL(authenticationRequired(QNetworkReply*,QAuthenticator*)), + this, SLOT(authenticationRequired(QNetworkReply*,QAuthenticator*))); + QCOMPARE(reply->error(), QNetworkReply::NoError); + QVERIFY(!QTestEventLoop::instance().timeout()); + + QCOMPARE(reply->url(), url); + QCOMPARE(reply->error(), QNetworkReply::NoError); + // verify that the HTTP status code is 200 Ok + QCOMPARE(reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(), 200); + + QCOMPARE(reply->readAll().trimmed(), md5sum(data).toHex()); + + QTEST(authenticationRequiredSpy.count(), "authenticationRequiredCount"); + QTEST(proxyAuthenticationRequiredSpy.count(), "proxyAuthenticationRequiredCount"); +} + +void tst_QNetworkReply::ioPostToHttpFromSocketSynchronous_data() +{ + QTest::addColumn<QByteArray>("data"); + QTest::addColumn<QByteArray>("md5sum"); + + QByteArray data; + data = ""; + QTest::newRow("empty") << data << md5sum(data); + + data = "This is a normal message."; + QTest::newRow("generic") << data << md5sum(data); + + data = "This is a message to show that Qt rocks!\r\n\n"; + QTest::newRow("small") << data << md5sum(data); + + data = QByteArray("abcd\0\1\2\abcd",12); + QTest::newRow("with-nul") << data << md5sum(data); + + data = QByteArray(4097, '\4'); + QTest::newRow("4k+1") << data << md5sum(data); + + data = QByteArray(128*1024+1, '\177'); + QTest::newRow("128k+1") << data << md5sum(data); + + data = QByteArray(2*1024*1024+1, '\177'); + QTest::newRow("2MB+1") << data << md5sum(data); +} + +void tst_QNetworkReply::ioPostToHttpFromSocketSynchronous() +{ + QFETCH(QByteArray, data); + + SocketPair socketpair; + QVERIFY(socketpair.create()); + QVERIFY(socketpair.endPoints[0] && socketpair.endPoints[1]); + socketpair.endPoints[0]->write(data); + socketpair.endPoints[0]->waitForBytesWritten(5000); + // ### for 4.8: make the socket pair unbuffered, to not read everything in one go in QNetworkReplyImplPrivate::setup() + QTestEventLoop::instance().enterLoop(3); + + QUrl url("http://" + QtNetworkSettings::serverName() + "/qtest/cgi-bin/md5sum.cgi"); + QNetworkRequest request(url); + request.setRawHeader("Content-Type", "application/octet-stream"); + request.setAttribute( + QNetworkRequest::SynchronousRequestAttribute, + true); + + QNetworkReplyPtr reply = manager.post(request, socketpair.endPoints[1]); + QVERIFY(reply->isFinished()); + socketpair.endPoints[0]->close(); + + QCOMPARE(reply->error(), QNetworkReply::NoError); + + QCOMPARE(reply->url(), url); + QCOMPARE(reply->error(), QNetworkReply::NoError); + // verify that the HTTP status code is 200 Ok + QCOMPARE(reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(), 200); + + QCOMPARE(reply->readAll().trimmed(), md5sum(data).toHex()); +} + +// this tests checks if rewinding the POST-data to some place in the middle +// worked. +void tst_QNetworkReply::ioPostToHttpFromMiddleOfFileToEnd() +{ + QFile sourceFile(SRCDIR "/rfc3252.txt"); + QVERIFY(sourceFile.open(QIODevice::ReadOnly)); + // seeking to the middle + sourceFile.seek(sourceFile.size() / 2); + + QUrl url = "http://" + QtNetworkSettings::serverName() + "/qtest/protected/cgi-bin/md5sum.cgi"; + QNetworkRequest request(url); + request.setRawHeader("Content-Type", "application/octet-stream"); + QNetworkReplyPtr reply = manager.post(request, &sourceFile); + + connect(reply, SIGNAL(finished()), &QTestEventLoop::instance(), SLOT(exitLoop())); + connect(&manager, SIGNAL(authenticationRequired(QNetworkReply*,QAuthenticator*)), + SLOT(authenticationRequired(QNetworkReply*,QAuthenticator*))); + + QTestEventLoop::instance().enterLoop(2); + disconnect(&manager, SIGNAL(authenticationRequired(QNetworkReply*,QAuthenticator*)), + this, SLOT(authenticationRequired(QNetworkReply*,QAuthenticator*))); + QVERIFY(!QTestEventLoop::instance().timeout()); + + // compare half data + sourceFile.seek(sourceFile.size() / 2); + QByteArray data = sourceFile.readAll(); + QCOMPARE(reply->readAll().trimmed(), md5sum(data).toHex()); +} + +void tst_QNetworkReply::ioPostToHttpFromMiddleOfFileFiveBytes() +{ + QFile sourceFile(SRCDIR "/rfc3252.txt"); + QVERIFY(sourceFile.open(QIODevice::ReadOnly)); + // seeking to the middle + sourceFile.seek(sourceFile.size() / 2); + + QUrl url = "http://" + QtNetworkSettings::serverName() + "/qtest/protected/cgi-bin/md5sum.cgi"; + QNetworkRequest request(url); + request.setRawHeader("Content-Type", "application/octet-stream"); + // only send 5 bytes + request.setHeader(QNetworkRequest::ContentLengthHeader, 5); + QVERIFY(request.header(QNetworkRequest::ContentLengthHeader).isValid()); + QNetworkReplyPtr reply = manager.post(request, &sourceFile); + + connect(reply, SIGNAL(finished()), &QTestEventLoop::instance(), SLOT(exitLoop())); + connect(&manager, SIGNAL(authenticationRequired(QNetworkReply*,QAuthenticator*)), + SLOT(authenticationRequired(QNetworkReply*,QAuthenticator*))); + + QTestEventLoop::instance().enterLoop(2); + disconnect(&manager, SIGNAL(authenticationRequired(QNetworkReply*,QAuthenticator*)), + this, SLOT(authenticationRequired(QNetworkReply*,QAuthenticator*))); + QVERIFY(!QTestEventLoop::instance().timeout()); + + // compare half data + sourceFile.seek(sourceFile.size() / 2); + QByteArray data = sourceFile.read(5); + QCOMPARE(reply->readAll().trimmed(), md5sum(data).toHex()); +} + +void tst_QNetworkReply::ioPostToHttpFromMiddleOfQBufferFiveBytes() +{ + // test needed since a QBuffer goes with a different codepath than the QFile + // tested in ioPostToHttpFromMiddleOfFileFiveBytes + QBuffer uploadBuffer; + uploadBuffer.open(QIODevice::ReadWrite); + uploadBuffer.write("1234567890"); + uploadBuffer.seek(5); + + QUrl url = "http://" + QtNetworkSettings::serverName() + "/qtest/protected/cgi-bin/md5sum.cgi"; + QNetworkRequest request(url); + request.setRawHeader("Content-Type", "application/octet-stream"); + QNetworkReplyPtr reply = manager.post(request, &uploadBuffer); + + connect(reply, SIGNAL(finished()), &QTestEventLoop::instance(), SLOT(exitLoop())); + connect(&manager, SIGNAL(authenticationRequired(QNetworkReply*,QAuthenticator*)), + SLOT(authenticationRequired(QNetworkReply*,QAuthenticator*))); + + QTestEventLoop::instance().enterLoop(2); + disconnect(&manager, SIGNAL(authenticationRequired(QNetworkReply*,QAuthenticator*)), + this, SLOT(authenticationRequired(QNetworkReply*,QAuthenticator*))); + QVERIFY(!QTestEventLoop::instance().timeout()); + + // compare half data + uploadBuffer.seek(5); + QByteArray data = uploadBuffer.read(5); + QCOMPARE(reply->readAll().trimmed(), md5sum(data).toHex()); +} + + +void tst_QNetworkReply::ioPostToHttpNoBufferFlag() +{ + QByteArray data = QByteArray("daaaaaaataaaaaaa"); + // create a sequential QIODevice by feeding the data into a local TCP server + SocketPair socketpair; + socketpair.create(); + QVERIFY(socketpair.endPoints[0] && socketpair.endPoints[1]); + socketpair.endPoints[0]->write(data); + + QUrl url = "http://" + QtNetworkSettings::serverName() + "/qtest/protected/cgi-bin/md5sum.cgi"; + QNetworkRequest request(url); + request.setRawHeader("Content-Type", "application/octet-stream"); + // disallow buffering + request.setAttribute(QNetworkRequest::DoNotBufferUploadDataAttribute, true); + request.setHeader(QNetworkRequest::ContentLengthHeader, data.size()); + QNetworkReplyPtr reply = manager.post(request, socketpair.endPoints[1]); + socketpair.endPoints[0]->close(); + + connect(reply, SIGNAL(finished()), &QTestEventLoop::instance(), SLOT(exitLoop())); + connect(&manager, SIGNAL(authenticationRequired(QNetworkReply*,QAuthenticator*)), + SLOT(authenticationRequired(QNetworkReply*,QAuthenticator*))); + + QTestEventLoop::instance().enterLoop(2); + disconnect(&manager, SIGNAL(authenticationRequired(QNetworkReply*,QAuthenticator*)), + this, SLOT(authenticationRequired(QNetworkReply*,QAuthenticator*))); + + // verify: error code is QNetworkReply::ContentReSendError + QCOMPARE(reply->error(), QNetworkReply::ContentReSendError); +} + +#ifndef QT_NO_OPENSSL +class SslServer : public QTcpServer { + Q_OBJECT +public: + SslServer() : socket(0) {}; + void incomingConnection(int socketDescriptor) { + QSslSocket *serverSocket = new QSslSocket; + serverSocket->setParent(this); + + if (serverSocket->setSocketDescriptor(socketDescriptor)) { + connect(serverSocket, SIGNAL(encrypted()), this, SLOT(encryptedSlot())); + connect(serverSocket, SIGNAL(readyRead()), this, SLOT(readyReadSlot())); + serverSocket->setProtocol(QSsl::AnyProtocol); + connect(serverSocket, SIGNAL(sslErrors(const QList<QSslError>&)), serverSocket, SLOT(ignoreSslErrors())); + serverSocket->setLocalCertificate(SRCDIR "/certs/server.pem"); + serverSocket->setPrivateKey(SRCDIR "/certs/server.key"); + serverSocket->startServerEncryption(); + } else { + delete serverSocket; + } + } +signals: + void newEncryptedConnection(); +public slots: + void encryptedSlot() { + socket = (QSslSocket*) sender(); + emit newEncryptedConnection(); + } + void readyReadSlot() { + // for the incoming sockets, not the server socket + //qDebug() << static_cast<QSslSocket*>(sender())->bytesAvailable() << static_cast<QSslSocket*>(sender())->encryptedBytesAvailable(); + } + +public: + QSslSocket *socket; +}; + +// very similar to ioPostToHttpUploadProgress but for SSL +void tst_QNetworkReply::ioPostToHttpsUploadProgress() +{ + //QFile sourceFile(SRCDIR "/bigfile"); + //QVERIFY(sourceFile.open(QIODevice::ReadOnly)); + qint64 wantedSize = 2*1024*1024; // 2 MB + QByteArray sourceFile; + // And in the case of SSL, the compression can fool us and let the + // server send the data much faster than expected. + // So better provide random data that cannot be compressed. + for (int i = 0; i < wantedSize; ++i) + sourceFile += (char)qrand(); + + // emulate a minimal https server + SslServer server; + server.listen(QHostAddress(QHostAddress::LocalHost), 0); + + // create the request + QUrl url = QUrl(QString("https://127.0.0.1:%1/").arg(server.serverPort())); + QNetworkRequest request(url); + + request.setRawHeader("Content-Type", "application/octet-stream"); + QNetworkReplyPtr reply = manager.post(request, sourceFile); + + QSignalSpy spy(reply, SIGNAL(uploadProgress(qint64,qint64))); + connect(&server, SIGNAL(newEncryptedConnection()), &QTestEventLoop::instance(), SLOT(exitLoop())); + connect(reply, SIGNAL(sslErrors(const QList<QSslError>&)), reply, SLOT(ignoreSslErrors())); + + // get the request started and the incoming socket connected + QTestEventLoop::instance().enterLoop(10); + QVERIFY(!QTestEventLoop::instance().timeout()); + QTcpSocket *incomingSocket = server.socket; + QVERIFY(incomingSocket); + disconnect(&server, SIGNAL(newEncryptedConnection()), &QTestEventLoop::instance(), SLOT(exitLoop())); + + + incomingSocket->setReadBufferSize(1*1024); + QTestEventLoop::instance().enterLoop(2); + // some progress should have been made + QVERIFY(!spy.isEmpty()); + QList<QVariant> args = spy.last(); + QVERIFY(args.at(0).toLongLong() > 0); + // but not everything! + QVERIFY(args.at(0).toLongLong() != sourceFile.size()); + + // set the read buffer to unlimited + incomingSocket->setReadBufferSize(0); + QTestEventLoop::instance().enterLoop(10); + // progress should be finished + QVERIFY(!spy.isEmpty()); + QList<QVariant> args3 = spy.last(); + QCOMPARE(args3.at(0).toLongLong(), args3.at(1).toLongLong()); + QCOMPARE(args3.at(0).toLongLong(), qint64(sourceFile.size())); + + // after sending this, the QNAM should emit finished() + connect(reply, SIGNAL(finished()), &QTestEventLoop::instance(), SLOT(exitLoop())); + incomingSocket->write("HTTP/1.0 200 OK\r\n"); + incomingSocket->write("Content-Length: 0\r\n"); + incomingSocket->write("\r\n"); + QTestEventLoop::instance().enterLoop(10); + // not timeouted -> finished() was emitted + QVERIFY(!QTestEventLoop::instance().timeout()); + + incomingSocket->close(); + server.close(); +} +#endif + +void tst_QNetworkReply::ioGetFromBuiltinHttp_data() +{ + QTest::addColumn<bool>("https"); + QTest::addColumn<int>("bufferSize"); + QTest::newRow("http+unlimited") << false << 0; + QTest::newRow("http+limited") << false << 4096; +#ifndef QT_NO_OPENSSL + QTest::newRow("https+unlimited") << true << 0; + QTest::newRow("https+limited") << true << 4096; +#endif +} + +void tst_QNetworkReply::ioGetFromBuiltinHttp() +{ + QSKIP("Limiting is broken right now, check QTBUG-15065", SkipAll); + QFETCH(bool, https); + QFETCH(int, bufferSize); + + QByteArray testData; + // Make the data big enough so that it can fill the kernel buffer + // (which seems to hold 202 KB here) + const int wantedSize = 1200 * 1000; + testData.reserve(wantedSize); + // And in the case of SSL, the compression can fool us and let the + // server send the data much faster than expected. + // So better provide random data that cannot be compressed. + for (int i = 0; i < wantedSize; ++i) + testData += (char)qrand(); + + QByteArray httpResponse = QByteArray("HTTP/1.0 200 OK\r\nContent-Length: "); + httpResponse += QByteArray::number(testData.size()); + httpResponse += "\r\n\r\n"; + httpResponse += testData; + + qDebug() << "Server will send" << (httpResponse.size()-testData.size()) << "bytes of header and" + << testData.size() << "bytes of data"; + + const bool fillKernelBuffer = bufferSize > 0; + FastSender server(httpResponse, https, fillKernelBuffer); + + QUrl url(QString("%1://127.0.0.1:%2/qtest/rfc3252.txt") + .arg(https?"https":"http") + .arg(server.serverPort())); + QNetworkRequest request(url); + QNetworkReplyPtr reply = manager.get(request); + reply->setReadBufferSize(bufferSize); + reply->ignoreSslErrors(); + const int rate = 200; // in kB per sec + RateControlledReader reader(server, reply, rate, bufferSize); + + connect(reply, SIGNAL(finished()), &QTestEventLoop::instance(), SLOT(exitLoop())); + QTime loopTime; + loopTime.start(); + QTestEventLoop::instance().enterLoop(30); + const int elapsedTime = loopTime.elapsed(); + server.wait(); + reader.wrapUp(); + + qDebug() << "send rate:" << server.transferRate << "B/s"; + qDebug() << "receive rate:" << reader.totalBytesRead * 1000 / elapsedTime + << "(it received" << reader.totalBytesRead << "bytes in" << elapsedTime << "ms)"; + + QVERIFY(!QTestEventLoop::instance().timeout()); + + QCOMPARE(reply->url(), request.url()); + QCOMPARE(reply->error(), QNetworkReply::NoError); + QCOMPARE(reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(), 200); + + QCOMPARE(reply->header(QNetworkRequest::ContentLengthHeader).toLongLong(), (qint64)testData.size()); + if (reader.data.size() < testData.size()) { // oops? + QCOMPARE(reader.data, testData.mid(0, reader.data.size())); + qDebug() << "The data is incomplete, the last" << testData.size() - reader.data.size() << "bytes are missing"; + QEXPECT_FAIL("http+limited", "Limiting is broken right now, check QTBUG-15065", Abort); + QEXPECT_FAIL("https+limited", "Limiting is broken right now, check QTBUG-15065", Abort); + } + QCOMPARE(reader.data.size(), testData.size()); + QCOMPARE(reader.data, testData); + + // OK we got the file alright, but did setReadBufferSize work? + QVERIFY(server.transferRate != -1); + if (bufferSize > 0) { + const int allowedDeviation = 16; // TODO find out why the send rate is 13% faster currently + const int minRate = rate * 1024 * (100-allowedDeviation) / 100; + const int maxRate = rate * 1024 * (100+allowedDeviation) / 100; + qDebug() << minRate << "<="<< server.transferRate << "<=" << maxRate << "?"; + QEXPECT_FAIL("http+limited", "Limiting is broken right now, check QTBUG-15065", Continue); + QEXPECT_FAIL("https+limited", "Limiting is broken right now, check QTBUG-15065", Continue); + QVERIFY(server.transferRate >= minRate && server.transferRate <= maxRate); + } +} + +void tst_QNetworkReply::ioPostToHttpUploadProgress() +{ + QFile sourceFile(SRCDIR "/bigfile"); + QVERIFY(sourceFile.open(QIODevice::ReadOnly)); + + // emulate a minimal http server + QTcpServer server; + server.listen(QHostAddress(QHostAddress::LocalHost), 0); + + // create the request + QUrl url = QUrl(QString("http://127.0.0.1:%1/").arg(server.serverPort())); + QNetworkRequest request(url); + request.setRawHeader("Content-Type", "application/octet-stream"); + QNetworkReplyPtr reply = manager.post(request, &sourceFile); + QSignalSpy spy(reply, SIGNAL(uploadProgress(qint64,qint64))); + connect(&server, SIGNAL(newConnection()), &QTestEventLoop::instance(), SLOT(exitLoop())); + + // get the request started and the incoming socket connected + QTestEventLoop::instance().enterLoop(10); + QVERIFY(!QTestEventLoop::instance().timeout()); + QTcpSocket *incomingSocket = server.nextPendingConnection(); + QVERIFY(incomingSocket); + disconnect(&server, SIGNAL(newConnection()), &QTestEventLoop::instance(), SLOT(exitLoop())); + + incomingSocket->setReadBufferSize(1*1024); + QTestEventLoop::instance().enterLoop(5); + // some progress should have been made + QList<QVariant> args = spy.last(); + QVERIFY(!args.isEmpty()); + QVERIFY(args.at(0).toLongLong() > 0); + // but not everything! + QVERIFY(args.at(0).toLongLong() != sourceFile.size()); + + // set the read buffer to unlimited + incomingSocket->setReadBufferSize(0); + QTestEventLoop::instance().enterLoop(10); + // progress should be finished + QList<QVariant> args3 = spy.last(); + QVERIFY(!args3.isEmpty()); + // More progress than before + QVERIFY(args3.at(0).toLongLong() > args.at(0).toLongLong()); + QCOMPARE(args3.at(0).toLongLong(), args3.at(1).toLongLong()); + // And actually finished.. + QCOMPARE(args3.at(0).toLongLong(), sourceFile.size()); + + // after sending this, the QNAM should emit finished() + connect(reply, SIGNAL(finished()), &QTestEventLoop::instance(), SLOT(exitLoop())); + incomingSocket->write("HTTP/1.0 200 OK\r\n"); + incomingSocket->write("Content-Length: 0\r\n"); + incomingSocket->write("\r\n"); + QTestEventLoop::instance().enterLoop(10); + // not timeouted -> finished() was emitted + QVERIFY(!QTestEventLoop::instance().timeout()); + + incomingSocket->close(); + server.close(); +} + +void tst_QNetworkReply::ioPostToHttpEmptyUploadProgress() +{ + QByteArray ba; + ba.resize(0); + QBuffer buffer(&ba,0); + QVERIFY(buffer.open(QIODevice::ReadOnly)); + + // emulate a minimal http server + QTcpServer server; + server.listen(QHostAddress(QHostAddress::LocalHost), 0); + + // create the request + QUrl url = QUrl(QString("http://127.0.0.1:%1/").arg(server.serverPort())); + QNetworkRequest request(url); + request.setRawHeader("Content-Type", "application/octet-stream"); + QNetworkReplyPtr reply = manager.post(request, &buffer); + QSignalSpy spy(reply, SIGNAL(uploadProgress(qint64,qint64))); + connect(&server, SIGNAL(newConnection()), &QTestEventLoop::instance(), SLOT(exitLoop())); + + + // get the request started and the incoming socket connected + QTestEventLoop::instance().enterLoop(10); + QVERIFY(!QTestEventLoop::instance().timeout()); + QTcpSocket *incomingSocket = server.nextPendingConnection(); + QVERIFY(incomingSocket); + + // after sending this, the QNAM should emit finished() + connect(reply, SIGNAL(finished()), &QTestEventLoop::instance(), SLOT(exitLoop())); + incomingSocket->write("HTTP/1.0 200 OK\r\n"); + incomingSocket->write("Content-Length: 0\r\n"); + incomingSocket->write("\r\n"); + incomingSocket->flush(); + QTestEventLoop::instance().enterLoop(10); + // not timeouted -> finished() was emitted + QVERIFY(!QTestEventLoop::instance().timeout()); + + // final check: only 1 uploadProgress has been emitted + QVERIFY(spy.length() == 1); + QList<QVariant> args = spy.last(); + QVERIFY(!args.isEmpty()); + QCOMPARE(args.at(0).toLongLong(), buffer.size()); + QCOMPARE(args.at(0).toLongLong(), buffer.size()); + + incomingSocket->close(); + server.close(); +} + +void tst_QNetworkReply::lastModifiedHeaderForFile() +{ + QFileInfo fileInfo(SRCDIR "/bigfile"); + QVERIFY(fileInfo.exists()); + + QUrl url = QUrl::fromLocalFile(fileInfo.filePath()); + + QNetworkRequest request(url); + QNetworkReplyPtr reply = manager.head(request); + connect(reply, SIGNAL(finished()), &QTestEventLoop::instance(), SLOT(exitLoop())); + QTestEventLoop::instance().enterLoop(10); + QVERIFY(!QTestEventLoop::instance().timeout()); + + QDateTime header = reply->header(QNetworkRequest::LastModifiedHeader).toDateTime(); + QCOMPARE(header, fileInfo.lastModified()); +} + +void tst_QNetworkReply::lastModifiedHeaderForHttp() +{ + // Tue, 22 May 2007 12:04:57 GMT according to webserver + QUrl url = "http://" + QtNetworkSettings::serverName() + "/qtest/fluke.gif"; + + QNetworkRequest request(url); + QNetworkReplyPtr reply = manager.head(request); + connect(reply, SIGNAL(finished()), &QTestEventLoop::instance(), SLOT(exitLoop())); + QTestEventLoop::instance().enterLoop(10); + QVERIFY(!QTestEventLoop::instance().timeout()); + + QDateTime header = reply->header(QNetworkRequest::LastModifiedHeader).toDateTime(); + QDateTime realDate = QDateTime::fromString("2007-05-22T12:04:57", Qt::ISODate); + realDate.setTimeSpec(Qt::UTC); + + QCOMPARE(header, realDate); +} + +void tst_QNetworkReply::httpCanReadLine() +{ + QNetworkRequest request(QUrl("http://" + QtNetworkSettings::serverName() + "/qtest/rfc3252.txt")); + QNetworkReplyPtr reply = manager.get(request); + + connect(reply, SIGNAL(finished()), &QTestEventLoop::instance(), SLOT(exitLoop())); + QTestEventLoop::instance().enterLoop(10); + QVERIFY(!QTestEventLoop::instance().timeout()); + QCOMPARE(reply->error(), QNetworkReply::NoError); + + QVERIFY(reply->canReadLine()); + QVERIFY(!reply->readAll().isEmpty()); + QVERIFY(!reply->canReadLine()); +} + +void tst_QNetworkReply::rateControl_data() +{ + QTest::addColumn<int>("rate"); + + QTest::newRow("15") << 15; + QTest::newRow("40") << 40; + QTest::newRow("73") << 73; + QTest::newRow("80") << 80; + QTest::newRow("125") << 125; + QTest::newRow("250") << 250; + QTest::newRow("1024") << 1024; +} + +void tst_QNetworkReply::rateControl() +{ + QSKIP("Test disabled -- only for manual purposes", SkipAll); + // this function tests that we aren't reading from the network + // faster than the data is being consumed. + QFETCH(int, rate); + + // ask for 20 seconds worth of data + FastSender sender(20 * rate * 1024); + + QNetworkRequest request("debugpipe://localhost:" + QString::number(sender.serverPort())); + QNetworkReplyPtr reply = manager.get(request); + reply->setReadBufferSize(32768); + connect(reply, SIGNAL(finished()), &QTestEventLoop::instance(), SLOT(exitLoop())); + qRegisterMetaType<QNetworkReply::NetworkError>("QNetworkReply::NetworkError"); + QSignalSpy errorSpy(reply, SIGNAL(error(QNetworkReply::NetworkError))); + + RateControlledReader reader(sender, reply, rate, 20); + + // this test is designed to run for 25 seconds at most + QTime loopTime; + loopTime.start(); + QTestEventLoop::instance().enterLoop(40); + int elapsedTime = loopTime.elapsed(); + + if (!errorSpy.isEmpty()) { + qDebug() << "ERROR!" << errorSpy[0][0] << reply->errorString(); + } + + qDebug() << "tst_QNetworkReply::rateControl" << "send rate:" << sender.transferRate; + qDebug() << "tst_QNetworkReply::rateControl" << "receive rate:" << reader.totalBytesRead * 1000 / elapsedTime + << "(it received" << reader.totalBytesRead << "bytes in" << elapsedTime << "ms)"; + + sender.wait(); + QVERIFY(!QTestEventLoop::instance().timeout()); + + QCOMPARE(reply->url(), request.url()); + QCOMPARE(reply->error(), QNetworkReply::NoError); + + QVERIFY(sender.transferRate != -1); + int minRate = rate * 1024 * 9 / 10; + int maxRate = rate * 1024 * 11 / 10; + QVERIFY(sender.transferRate >= minRate); + QVERIFY(sender.transferRate <= maxRate); +} + +void tst_QNetworkReply::downloadProgress_data() +{ + QTest::addColumn<int>("loopCount"); + + QTest::newRow("empty") << 0; + QTest::newRow("small") << 4; +#ifndef Q_OS_SYMBIAN + QTest::newRow("big") << 4096; +#else + // it can run even with 4096 + // but it takes lot time + //especially on emulator + QTest::newRow("big") << 1024; +#endif +} + +void tst_QNetworkReply::downloadProgress() +{ + QTcpServer server; + QVERIFY(server.listen()); + + QNetworkRequest request("debugpipe://127.0.0.1:" + QString::number(server.serverPort()) + "/?bare=1"); + QNetworkReplyPtr reply = manager.get(request); + QSignalSpy spy(reply, SIGNAL(downloadProgress(qint64,qint64))); + connect(reply, SIGNAL(downloadProgress(qint64,qint64)), + &QTestEventLoop::instance(), SLOT(exitLoop())); + QVERIFY(spy.isValid()); + QVERIFY(!reply->isFinished()); + QVERIFY(reply->isRunning()); + + QCoreApplication::instance()->processEvents(); + if (!server.hasPendingConnections()) + server.waitForNewConnection(1000); + QVERIFY(server.hasPendingConnections()); + QCOMPARE(spy.count(), 0); + + QByteArray data(128, 'a'); + QTcpSocket *sender = server.nextPendingConnection(); + QVERIFY(sender); + + QFETCH(int, loopCount); + for (int i = 1; i <= loopCount; ++i) { + sender->write(data); + QVERIFY2(sender->waitForBytesWritten(2000), "Network timeout"); + + spy.clear(); + QTestEventLoop::instance().enterLoop(2); + QVERIFY(!QTestEventLoop::instance().timeout()); + QVERIFY(spy.count() > 0); + QVERIFY(!reply->isFinished()); + QVERIFY(reply->isRunning()); + + QList<QVariant> args = spy.last(); + QCOMPARE(args.at(0).toInt(), i*data.size()); + QCOMPARE(args.at(1).toInt(), -1); + } + + // close the connection: + delete sender; + + spy.clear(); + QTestEventLoop::instance().enterLoop(2); + QCOMPARE(reply->error(), QNetworkReply::NoError); + QVERIFY(!QTestEventLoop::instance().timeout()); + QVERIFY(spy.count() > 0); + QVERIFY(!reply->isRunning()); + QVERIFY(reply->isFinished()); + + QList<QVariant> args = spy.last(); + QCOMPARE(args.at(0).toInt(), loopCount * data.size()); + QCOMPARE(args.at(1).toInt(), loopCount * data.size()); +} + +void tst_QNetworkReply::uploadProgress_data() +{ + putToFile_data(); +} + +void tst_QNetworkReply::uploadProgress() +{ + QFETCH(QByteArray, data); + QTcpServer server; + QVERIFY(server.listen()); + + QNetworkRequest request("debugpipe://127.0.0.1:" + QString::number(server.serverPort()) + "/?bare=1"); + QNetworkReplyPtr reply = manager.put(request, data); + QSignalSpy spy(reply, SIGNAL(uploadProgress(qint64,qint64))); + QSignalSpy finished(reply, SIGNAL(finished())); + QVERIFY(spy.isValid()); + QVERIFY(finished.isValid()); + + QCoreApplication::instance()->processEvents(); + if (!server.hasPendingConnections()) + server.waitForNewConnection(1000); + QVERIFY(server.hasPendingConnections()); + + QTcpSocket *receiver = server.nextPendingConnection(); + if (finished.count() == 0) { + // it's not finished yet, so wait for it to be + connect(reply, SIGNAL(finished()), &QTestEventLoop::instance(), SLOT(exitLoop())); + QTestEventLoop::instance().enterLoop(2); + QVERIFY(!QTestEventLoop::instance().timeout()); + } + delete receiver; + + QVERIFY(finished.count() > 0); + QVERIFY(spy.count() > 0); + + QList<QVariant> args = spy.last(); + QCOMPARE(args.at(0).toInt(), data.size()); + QCOMPARE(args.at(1).toInt(), data.size()); +} + +void tst_QNetworkReply::chaining_data() +{ + putToFile_data(); +} + +void tst_QNetworkReply::chaining() +{ + QTemporaryFile sourceFile(QDir::currentPath() + "/temp-XXXXXX"); + sourceFile.setAutoRemove(true); + QVERIFY(sourceFile.open()); + + QFETCH(QByteArray, data); + QVERIFY(sourceFile.write(data) == data.size()); + sourceFile.flush(); + QCOMPARE(sourceFile.size(), qint64(data.size())); + + QNetworkRequest request(QUrl::fromLocalFile(sourceFile.fileName())); + QNetworkReplyPtr getReply = manager.get(request); + + QFile targetFile(testFileName); + QUrl url = QUrl::fromLocalFile(targetFile.fileName()); + request.setUrl(url); + QNetworkReplyPtr putReply = manager.put(request, getReply); + + connect(putReply, SIGNAL(finished()), &QTestEventLoop::instance(), SLOT(exitLoop())); + QTestEventLoop::instance().enterLoop(10); + QVERIFY(!QTestEventLoop::instance().timeout()); + + QCOMPARE(getReply->url(), QUrl::fromLocalFile(sourceFile.fileName())); + QCOMPARE(getReply->error(), QNetworkReply::NoError); + QCOMPARE(getReply->header(QNetworkRequest::ContentLengthHeader).toLongLong(), sourceFile.size()); + + QCOMPARE(putReply->url(), url); + QCOMPARE(putReply->error(), QNetworkReply::NoError); + QCOMPARE(putReply->header(QNetworkRequest::ContentLengthHeader).toLongLong(), Q_INT64_C(0)); + QVERIFY(putReply->readAll().isEmpty()); + + QVERIFY(sourceFile.atEnd()); + sourceFile.seek(0); // reset it to the beginning + + QVERIFY(targetFile.open(QIODevice::ReadOnly)); + QCOMPARE(targetFile.size(), sourceFile.size()); + QCOMPARE(targetFile.readAll(), sourceFile.readAll()); +} + +void tst_QNetworkReply::receiveCookiesFromHttp_data() +{ + QTest::addColumn<QString>("cookieString"); + QTest::addColumn<QList<QNetworkCookie> >("expectedCookiesFromHttp"); + QTest::addColumn<QList<QNetworkCookie> >("expectedCookiesInJar"); + + QTest::newRow("empty") << "" << QList<QNetworkCookie>() << QList<QNetworkCookie>(); + + QList<QNetworkCookie> header, jar; + QNetworkCookie cookie("a", "b"); + header << cookie; + cookie.setDomain(QtNetworkSettings::serverName()); + cookie.setPath("/qtest/cgi-bin/"); + jar << cookie; + QTest::newRow("simple-cookie") << "a=b" << header << jar; + + header << QNetworkCookie("c", "d"); + cookie.setName("c"); + cookie.setValue("d"); + jar << cookie; + QTest::newRow("two-cookies") << "a=b, c=d" << header << jar; + QTest::newRow("two-cookies-2") << "a=b\nc=d" << header << jar; + + header.clear(); + jar.clear(); + cookie = QNetworkCookie("a", "b"); + cookie.setPath("/not/part-of-path"); + header << cookie; + cookie.setDomain(QtNetworkSettings::serverName()); + jar << cookie; + QTest::newRow("invalid-cookie-path") << "a=b; path=/not/part-of-path" << header << jar; + + jar.clear(); + cookie = QNetworkCookie("a", "b"); + cookie.setDomain(".example.com"); + header.clear(); + header << cookie; + QTest::newRow("invalid-cookie-domain") << "a=b; domain=.example.com" << header << jar; +} + +void tst_QNetworkReply::receiveCookiesFromHttp() +{ + QFETCH(QString, cookieString); + + QByteArray data = cookieString.toLatin1() + '\n'; + QUrl url("http://" + QtNetworkSettings::serverName() + "/qtest/cgi-bin/set-cookie.cgi"); + QNetworkRequest request(url); + request.setRawHeader("Content-Type", "application/octet-stream"); + QNetworkReplyPtr reply; + RUN_REQUEST(runSimpleRequest(QNetworkAccessManager::PostOperation, request, reply, data)); + + QCOMPARE(reply->url(), url); + QCOMPARE(reply->error(), QNetworkReply::NoError); + + QCOMPARE(reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(), 200); // 200 Ok + + QList<QNetworkCookie> setCookies = + qvariant_cast<QList<QNetworkCookie> >(reply->header(QNetworkRequest::SetCookieHeader)); + QTEST(setCookies, "expectedCookiesFromHttp"); + QTEST(cookieJar->allCookies(), "expectedCookiesInJar"); +} + +void tst_QNetworkReply::receiveCookiesFromHttpSynchronous_data() +{ + tst_QNetworkReply::receiveCookiesFromHttp_data(); +} + +void tst_QNetworkReply::receiveCookiesFromHttpSynchronous() +{ + QFETCH(QString, cookieString); + + QByteArray data = cookieString.toLatin1() + '\n'; + QUrl url("http://" + QtNetworkSettings::serverName() + "/qtest/cgi-bin/set-cookie.cgi"); + + QNetworkRequest request(url); + request.setRawHeader("Content-Type", "application/octet-stream"); + request.setAttribute( + QNetworkRequest::SynchronousRequestAttribute, + true); + + QNetworkReplyPtr reply; + RUN_REQUEST(runSimpleRequest(QNetworkAccessManager::PostOperation, request, reply, data)); + + QCOMPARE(reply->url(), url); + QCOMPARE(reply->error(), QNetworkReply::NoError); + + QCOMPARE(reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(), 200); // 200 Ok + + QList<QNetworkCookie> setCookies = + qvariant_cast<QList<QNetworkCookie> >(reply->header(QNetworkRequest::SetCookieHeader)); + QTEST(setCookies, "expectedCookiesFromHttp"); + QTEST(cookieJar->allCookies(), "expectedCookiesInJar"); +} + +void tst_QNetworkReply::sendCookies_data() +{ + QTest::addColumn<QList<QNetworkCookie> >("cookiesToSet"); + QTest::addColumn<QString>("expectedCookieString"); + + QList<QNetworkCookie> list; + QTest::newRow("empty") << list << ""; + + QNetworkCookie cookie("a", "b"); + cookie.setPath("/"); + cookie.setDomain("example.com"); + list << cookie; + QTest::newRow("no-match-domain") << list << ""; + + cookie.setDomain(QtNetworkSettings::serverName()); + cookie.setPath("/something/else"); + list << cookie; + QTest::newRow("no-match-path") << list << ""; + + cookie.setPath("/"); + list << cookie; + QTest::newRow("simple-cookie") << list << "a=b"; + + cookie.setPath("/qtest"); + cookie.setValue("longer"); + list << cookie; + QTest::newRow("two-cookies") << list << "a=longer; a=b"; + + list.clear(); + cookie = QNetworkCookie("a", "b"); + cookie.setPath("/"); + cookie.setDomain("." + QtNetworkSettings::serverDomainName()); + list << cookie; + QTest::newRow("domain-match") << list << "a=b"; + + // but it shouldn't match this: + cookie.setDomain(QtNetworkSettings::serverDomainName()); + list << cookie; + QTest::newRow("domain-match-2") << list << "a=b"; +} + +void tst_QNetworkReply::sendCookies() +{ + QFETCH(QString, expectedCookieString); + QFETCH(QList<QNetworkCookie>, cookiesToSet); + cookieJar->setAllCookies(cookiesToSet); + + QUrl url("http://" + QtNetworkSettings::serverName() + "/qtest/cgi-bin/get-cookie.cgi"); + QNetworkRequest request(url); + QNetworkReplyPtr reply; + RUN_REQUEST(runSimpleRequest(QNetworkAccessManager::GetOperation, request, reply)); + + QCOMPARE(reply->url(), url); + QCOMPARE(reply->error(), QNetworkReply::NoError); + + QCOMPARE(reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(), 200); // 200 Ok + + QCOMPARE(QString::fromLatin1(reply->readAll()).trimmed(), expectedCookieString); +} + +void tst_QNetworkReply::sendCookiesSynchronous_data() +{ + tst_QNetworkReply::sendCookies_data(); +} + +void tst_QNetworkReply::sendCookiesSynchronous() +{ + QFETCH(QString, expectedCookieString); + QFETCH(QList<QNetworkCookie>, cookiesToSet); + cookieJar->setAllCookies(cookiesToSet); + + QUrl url("http://" + QtNetworkSettings::serverName() + "/qtest/cgi-bin/get-cookie.cgi"); + QNetworkRequest request(url); + + request.setAttribute( + QNetworkRequest::SynchronousRequestAttribute, + true); + + QNetworkReplyPtr reply; + RUN_REQUEST(runSimpleRequest(QNetworkAccessManager::GetOperation, request, reply)); + + QCOMPARE(reply->url(), url); + QCOMPARE(reply->error(), QNetworkReply::NoError); + + QCOMPARE(reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(), 200); // 200 Ok + + QCOMPARE(QString::fromLatin1(reply->readAll()).trimmed(), expectedCookieString); +} + +void tst_QNetworkReply::nestedEventLoops_slot() +{ + QEventLoop subloop; + + // 16 seconds: fluke times out in 15 seconds, which triggers a QTcpSocket error + QTimer::singleShot(16000, &subloop, SLOT(quit())); + subloop.exec(); + + QTestEventLoop::instance().exitLoop(); +} + +void tst_QNetworkReply::nestedEventLoops() +{ + // Slightly fragile test, it may not be testing anything + // This is certifying that we're not running into the same issue + // that QHttp had (task 200432): the QTcpSocket connection is + // closed by the remote end because of the kept-alive HTTP + // connection timed out. + // + // The exact time required for this to happen is not exactly + // defined. Our server (Apache httpd) times out after 15 + // seconds. (see above) + + qDebug("Takes 16 seconds to run, please wait"); + qRegisterMetaType<QNetworkReply::NetworkError>(); + + QUrl url("http://" + QtNetworkSettings::serverName()); + QNetworkRequest request(url); + QNetworkReplyPtr reply = manager.get(request); + + QSignalSpy finishedspy(reply, SIGNAL(finished())); + QSignalSpy errorspy(reply, SIGNAL(error(QNetworkReply::NetworkError))); + + connect(reply, SIGNAL(finished()), SLOT(nestedEventLoops_slot())); + QTestEventLoop::instance().enterLoop(20); + QVERIFY2(!QTestEventLoop::instance().timeout(), "Network timeout"); + + QCOMPARE(finishedspy.count(), 1); + QCOMPARE(errorspy.count(), 0); +} + +void tst_QNetworkReply::httpProxyCommands_data() +{ + QTest::addColumn<QUrl>("url"); + QTest::addColumn<QByteArray>("responseToSend"); + QTest::addColumn<QString>("expectedCommand"); + + QTest::newRow("http") + << QUrl("http://0.0.0.0:4443/http-request") + << QByteArray("HTTP/1.0 200 OK\r\nProxy-Connection: close\r\nContent-Length: 1\r\n\r\n1") + << "GET http://0.0.0.0:4443/http-request HTTP/1."; +#ifndef QT_NO_OPENSSL + QTest::newRow("https") + << QUrl("https://0.0.0.0:4443/https-request") + << QByteArray("HTTP/1.0 200 Connection Established\r\n\r\n") + << "CONNECT 0.0.0.0:4443 HTTP/1."; +#endif +} + +void tst_QNetworkReply::httpProxyCommands() +{ + QFETCH(QUrl, url); + QFETCH(QByteArray, responseToSend); + QFETCH(QString, expectedCommand); + + MiniHttpServer proxyServer(responseToSend); + QNetworkProxy proxy(QNetworkProxy::HttpProxy, "127.0.0.1", proxyServer.serverPort()); + + manager.setProxy(proxy); + QNetworkRequest request(url); + request.setRawHeader("User-Agent", "QNetworkReplyAutoTest/1.0"); + QNetworkReplyPtr reply = manager.get(request); + //clearing the proxy here causes the test to fail. + //the proxy isn't used until after the bearer has been started + //which is correct in general, because system proxy isn't known until that time. + //removing this line is safe, as the proxy is also reset by the cleanup() function + //manager.setProxy(QNetworkProxy()); + + // wait for the finished signal + connect(reply, SIGNAL(finished()), &QTestEventLoop::instance(), SLOT(exitLoop())); + + QTestEventLoop::instance().enterLoop(15); + + QVERIFY(!QTestEventLoop::instance().timeout()); + + //qDebug() << reply->error() << reply->errorString(); + //qDebug() << proxyServer.receivedData; + + // we don't really care if the request succeeded + // especially since it won't succeed in the HTTPS case + // so just check that the command was correct + + QString receivedHeader = proxyServer.receivedData.left(expectedCommand.length()); + QCOMPARE(receivedHeader, expectedCommand); + + //QTBUG-17223 - make sure the user agent from the request is sent to proxy server even for CONNECT + int uapos = proxyServer.receivedData.indexOf("User-Agent"); + int uaend = proxyServer.receivedData.indexOf("\r\n", uapos); + QByteArray uaheader = proxyServer.receivedData.mid(uapos, uaend - uapos); + QCOMPARE(uaheader, QByteArray("User-Agent: QNetworkReplyAutoTest/1.0")); +} + +class ProxyChangeHelper : public QObject { + Q_OBJECT +public: + ProxyChangeHelper() : QObject(), signalCount(0) {}; +public slots: + void finishedSlot() { + signalCount++; + if (signalCount == 2) + QMetaObject::invokeMethod(&QTestEventLoop::instance(), "exitLoop", Qt::QueuedConnection); + } +private: + int signalCount; +}; + +void tst_QNetworkReply::httpProxyCommandsSynchronous_data() +{ + httpProxyCommands_data(); +} + +struct QThreadCleanup +{ + static inline void cleanup(QThread *thread) + { + thread->quit(); + if (thread->wait(3000)) + delete thread; + else + qWarning("thread hung, leaking memory so test can finish"); + } +}; + +struct QDeleteLaterCleanup +{ + static inline void cleanup(QObject *o) + { + o->deleteLater(); + } +}; + +void tst_QNetworkReply::httpProxyCommandsSynchronous() +{ + QFETCH(QUrl, url); + QFETCH(QByteArray, responseToSend); + QFETCH(QString, expectedCommand); + + // when using synchronous commands, we need a different event loop for + // the server thread, because the client is never returning to the + // event loop + QScopedPointer<QThread, QThreadCleanup> serverThread(new QThread); + QScopedPointer<MiniHttpServer, QDeleteLaterCleanup> proxyServer(new MiniHttpServer(responseToSend, false, serverThread.data())); + QNetworkProxy proxy(QNetworkProxy::HttpProxy, "127.0.0.1", proxyServer->serverPort()); + + manager.setProxy(proxy); + QNetworkRequest request(url); + + // send synchronous request + request.setAttribute( + QNetworkRequest::SynchronousRequestAttribute, + true); + + QNetworkReplyPtr reply = manager.get(request); + QVERIFY(reply->isFinished()); // synchronous + manager.setProxy(QNetworkProxy()); + + //qDebug() << reply->error() << reply->errorString(); + + // we don't really care if the request succeeded + // especially since it won't succeed in the HTTPS case + // so just check that the command was correct + + QString receivedHeader = proxyServer->receivedData.left(expectedCommand.length()); + QCOMPARE(receivedHeader, expectedCommand); +} + +void tst_QNetworkReply::proxyChange() +{ + ProxyChangeHelper helper; + MiniHttpServer proxyServer( + "HTTP/1.0 200 OK\r\nProxy-Connection: keep-alive\r\n" + "Content-Length: 1\r\n\r\n1"); + QNetworkProxy dummyProxy(QNetworkProxy::HttpProxy, "127.0.0.1", proxyServer.serverPort()); + QNetworkRequest req(QUrl("http://" + QtNetworkSettings::serverName())); + proxyServer.doClose = false; + + manager.setProxy(dummyProxy); + QNetworkReplyPtr reply1 = manager.get(req); + connect(reply1, SIGNAL(finished()), &helper, SLOT(finishedSlot())); + + manager.setProxy(QNetworkProxy()); + QNetworkReplyPtr reply2 = manager.get(req); + connect(reply2, SIGNAL(finished()), &helper, SLOT(finishedSlot())); + + QTestEventLoop::instance().enterLoop(20); + QVERIFY(!QTestEventLoop::instance().timeout()); + + // verify that the replies succeeded + QCOMPARE(reply1->error(), QNetworkReply::NoError); + QCOMPARE(reply1->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(), 200); + QVERIFY(reply1->size() == 1); + + QCOMPARE(reply2->error(), QNetworkReply::NoError); + QCOMPARE(reply2->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(), 200); + QVERIFY(reply2->size() > 1); + + // now try again and get an error + // this verifies that we reuse the already-open connection + + proxyServer.doClose = true; + proxyServer.dataToTransmit = + "HTTP/1.0 403 Forbidden\r\nProxy-Connection: close\r\n" + "Content-Length: 1\r\n\r\n1"; + + manager.setProxy(dummyProxy); + QNetworkReplyPtr reply3 = manager.get(req); + connect(reply3, SIGNAL(finished()), &QTestEventLoop::instance(), SLOT(exitLoop())); + QTestEventLoop::instance().enterLoop(5); + QVERIFY(!QTestEventLoop::instance().timeout()); + + QVERIFY(int(reply3->error()) > 0); +} + +void tst_QNetworkReply::authorizationError_data() +{ + + QTest::addColumn<QString>("url"); + QTest::addColumn<int>("errorSignalCount"); + QTest::addColumn<int>("finishedSignalCount"); + QTest::addColumn<int>("error"); + QTest::addColumn<int>("httpStatusCode"); + QTest::addColumn<QString>("httpBody"); + + QTest::newRow("unknown-authorization-method") << "http://" + QtNetworkSettings::serverName() + + "/qtest/cgi-bin/http-unknown-authentication-method.cgi?401-authorization-required" << 1 << 1 + << int(QNetworkReply::AuthenticationRequiredError) << 401 << "authorization required"; + QTest::newRow("unknown-proxy-authorization-method") << "http://" + QtNetworkSettings::serverName() + + "/qtest/cgi-bin/http-unknown-authentication-method.cgi?407-proxy-authorization-required" << 1 << 1 + << int(QNetworkReply::ProxyAuthenticationRequiredError) << 407 + << "authorization required"; +} + +void tst_QNetworkReply::authorizationError() +{ + QFETCH(QString, url); + QNetworkRequest request(url); + QNetworkReplyPtr reply = manager.get(request); + + QCOMPARE(reply->error(), QNetworkReply::NoError); + + qRegisterMetaType<QNetworkReply::NetworkError>("QNetworkReply::NetworkError"); + QSignalSpy errorSpy(reply, SIGNAL(error(QNetworkReply::NetworkError))); + QSignalSpy finishedSpy(reply, SIGNAL(finished())); + // now run the request: + connect(reply, SIGNAL(finished()), + &QTestEventLoop::instance(), SLOT(exitLoop())); + QTestEventLoop::instance().enterLoop(10); + QVERIFY(!QTestEventLoop::instance().timeout()); + + QFETCH(int, errorSignalCount); + QCOMPARE(errorSpy.count(), errorSignalCount); + QFETCH(int, finishedSignalCount); + QCOMPARE(finishedSpy.count(), finishedSignalCount); + QFETCH(int, error); + QCOMPARE(reply->error(), QNetworkReply::NetworkError(error)); + + QFETCH(int, httpStatusCode); + QCOMPARE(reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(), httpStatusCode); + + QFETCH(QString, httpBody); + QCOMPARE(qint64(reply->size()), qint64(httpBody.size())); + QCOMPARE(QString(reply->readAll()), httpBody); +} + +void tst_QNetworkReply::httpConnectionCount() +{ + QTcpServer server; + QVERIFY(server.listen()); + QCoreApplication::instance()->processEvents(); + + for (int i = 0; i < 10; i++) { + QNetworkRequest request (QUrl("http://127.0.0.1:" + QString::number(server.serverPort()) + "/" + QString::number(i))); + QNetworkReply* reply = manager.get(request); + reply->setParent(&server); + } + + int pendingConnectionCount = 0; + QTime time; + time.start(); + + while(pendingConnectionCount <= 20) { + QTestEventLoop::instance().enterLoop(1); + QTcpSocket *socket = server.nextPendingConnection(); + while (socket != 0) { + pendingConnectionCount++; + socket->setParent(&server); + socket = server.nextPendingConnection(); + } + + // at max. wait 10 sec + if (time.elapsed() > 10000) + break; + } + +#ifdef Q_OS_SYMBIAN + // see in qhttpnetworkconnection.cpp + // hardcoded defaultChannelCount = 3 + QCOMPARE(pendingConnectionCount, 3); +#else + QCOMPARE(pendingConnectionCount, 6); +#endif +} + +void tst_QNetworkReply::httpReUsingConnectionSequential_data() +{ + QTest::addColumn<bool>("doDeleteLater"); + QTest::newRow("deleteLater") << true; + QTest::newRow("noDeleteLater") << false; +} + +void tst_QNetworkReply::httpReUsingConnectionSequential() +{ + QFETCH(bool, doDeleteLater); + + QByteArray response("HTTP/1.1 200 OK\r\nContent-Length: 0\r\n\r\n"); + MiniHttpServer server(response); + server.multiple = true; + server.doClose = false; + + QUrl url; + url.setScheme("http"); + url.setPort(server.serverPort()); + url.setHost("127.0.0.1"); + // first request + QNetworkReply* reply1 = manager.get(QNetworkRequest(url)); + connect(reply1, SIGNAL(finished()), &QTestEventLoop::instance(), SLOT(exitLoop())); + QTestEventLoop::instance().enterLoop(2); + QVERIFY(!QTestEventLoop::instance().timeout()); + QVERIFY(!reply1->error()); + int reply1port = server.client->peerPort(); + + if (doDeleteLater) + reply1->deleteLater(); + + // finished received, send the next one + QNetworkReply*reply2 = manager.get(QNetworkRequest(url)); + connect(reply2, SIGNAL(finished()), &QTestEventLoop::instance(), SLOT(exitLoop())); + QTestEventLoop::instance().enterLoop(2); + QVERIFY(!QTestEventLoop::instance().timeout()); + QVERIFY(!reply2->error()); + int reply2port = server.client->peerPort(); // should still be the same object + + QVERIFY(reply1port > 0); + QCOMPARE(server.totalConnections, 1); + QCOMPARE(reply2port, reply1port); + + if (!doDeleteLater) + reply1->deleteLater(); // only do it if it was not done earlier + reply2->deleteLater(); +} + +class HttpReUsingConnectionFromFinishedSlot : public QObject { + Q_OBJECT +public: + QNetworkReply* reply1; + QNetworkReply* reply2; + QUrl url; + QNetworkAccessManager manager; +public slots: + void finishedSlot() { + QVERIFY(!reply1->error()); + + QFETCH(bool, doDeleteLater); + if (doDeleteLater) { + reply1->deleteLater(); + reply1 = 0; + } + + // kick off 2nd request and exit the loop when it is done + reply2 = manager.get(QNetworkRequest(url)); + reply2->setParent(this); + connect(reply2, SIGNAL(finished()), &QTestEventLoop::instance(), SLOT(exitLoop())); + } +}; + +void tst_QNetworkReply::httpReUsingConnectionFromFinishedSlot_data() +{ + httpReUsingConnectionSequential_data(); +} + +void tst_QNetworkReply::httpReUsingConnectionFromFinishedSlot() +{ + QByteArray response("HTTP/1.1 200 OK\r\nContent-Length: 0\r\n\r\n"); + MiniHttpServer server(response); + server.multiple = true; + server.doClose = false; + + HttpReUsingConnectionFromFinishedSlot helper; + helper.reply1 = 0; + helper.reply2 = 0; + helper.url.setScheme("http"); + helper.url.setPort(server.serverPort()); + helper.url.setHost("127.0.0.1"); + + // first request + helper.reply1 = helper.manager.get(QNetworkRequest(helper.url)); + helper.reply1->setParent(&helper); + connect(helper.reply1, SIGNAL(finished()), &helper, SLOT(finishedSlot())); + QTestEventLoop::instance().enterLoop(4); + QVERIFY(!QTestEventLoop::instance().timeout()); + + QVERIFY(helper.reply2); + QVERIFY(!helper.reply2->error()); + + QCOMPARE(server.totalConnections, 1); +} + +class HttpRecursiveCreationHelper : public QObject { + Q_OBJECT +public: + + HttpRecursiveCreationHelper(): + QObject(0), + requestsStartedCount_finished(0), + requestsStartedCount_readyRead(0), + requestsFinishedCount(0) + { + } + QNetworkAccessManager manager; + int requestsStartedCount_finished; + int requestsStartedCount_readyRead; + int requestsFinishedCount; +public slots: + void finishedSlot() { + requestsFinishedCount++; + + QNetworkReply *reply = qobject_cast<QNetworkReply*>(sender()); + QVERIFY(!reply->error()); + QVERIFY(reply->bytesAvailable() == 27906); + + if (requestsFinishedCount == 60) { + QTestEventLoop::instance().exitLoop(); + return; + } + + if (requestsStartedCount_finished < 30) { + startOne(); + requestsStartedCount_finished++; + } + + reply->deleteLater(); + } + void readyReadSlot() { + QNetworkReply *reply = qobject_cast<QNetworkReply*>(sender()); + QVERIFY(!reply->error()); + + if (requestsStartedCount_readyRead < 30 && reply->bytesAvailable() > 27906/2) { + startOne(); + requestsStartedCount_readyRead++; + } + } + void startOne() { + QUrl url = "http://" + QtNetworkSettings::serverName() + "/qtest/fluke.gif"; + QNetworkRequest request(url); + QNetworkReply *reply = manager.get(request); + reply->setParent(this); + connect(reply, SIGNAL(finished()), this, SLOT(finishedSlot())); + connect(reply, SIGNAL(readyRead()), this, SLOT(readyReadSlot())); + } +}; + +void tst_QNetworkReply::httpRecursiveCreation() +{ + // this test checks if creation of new requests to the same host properly works + // from readyRead() and finished() signals + HttpRecursiveCreationHelper helper; + helper.startOne(); + QTestEventLoop::instance().enterLoop(30); + QVERIFY(!QTestEventLoop::instance().timeout()); +} + +#ifndef QT_NO_OPENSSL +void tst_QNetworkReply::ignoreSslErrorsList_data() +{ + QTest::addColumn<QString>("url"); + QTest::addColumn<QList<QSslError> >("expectedSslErrors"); + QTest::addColumn<QNetworkReply::NetworkError>("expectedNetworkError"); + + QList<QSslError> expectedSslErrors; + // apparently, because of some weird behaviour of SRCDIR, the file name below needs to start with a slash + QList<QSslCertificate> certs = QSslCertificate::fromPath(QLatin1String(SRCDIR "/certs/qt-test-server-cacert.pem")); + QSslError rightError(QSslError::SelfSignedCertificate, certs.at(0)); + QSslError wrongError(QSslError::SelfSignedCertificate); + + QTest::newRow("SSL-failure-empty-list") << "https://" + QtNetworkSettings::serverName() + "/index.html" << expectedSslErrors << QNetworkReply::SslHandshakeFailedError; + expectedSslErrors.append(wrongError); + QTest::newRow("SSL-failure-wrong-error") << "https://" + QtNetworkSettings::serverName() + "/index.html" << expectedSslErrors << QNetworkReply::SslHandshakeFailedError; + expectedSslErrors.append(rightError); + QTest::newRow("allErrorsInExpectedList1") << "https://" + QtNetworkSettings::serverName() + "/index.html" << expectedSslErrors << QNetworkReply::NoError; + expectedSslErrors.removeAll(wrongError); + QTest::newRow("allErrorsInExpectedList2") << "https://" + QtNetworkSettings::serverName() + "/index.html" << expectedSslErrors << QNetworkReply::NoError; + expectedSslErrors.removeAll(rightError); + QTest::newRow("SSL-failure-empty-list-again") << "https://" + QtNetworkSettings::serverName() + "/index.html" << expectedSslErrors << QNetworkReply::SslHandshakeFailedError; +} + +void tst_QNetworkReply::ignoreSslErrorsList() +{ + QFETCH(QString, url); + QNetworkRequest request(url); + QNetworkReplyPtr reply = manager.get(request); + + QFETCH(QList<QSslError>, expectedSslErrors); + reply->ignoreSslErrors(expectedSslErrors); + + connect(reply, SIGNAL(finished()), &QTestEventLoop::instance(), SLOT(exitLoop())); + QTestEventLoop::instance().enterLoop(10); + QVERIFY(!QTestEventLoop::instance().timeout()); + + QFETCH(QNetworkReply::NetworkError, expectedNetworkError); + QCOMPARE(reply->error(), expectedNetworkError); +} + +void tst_QNetworkReply::ignoreSslErrorsListWithSlot_data() +{ + ignoreSslErrorsList_data(); +} + +// this is not a test, just a slot called in the test below +void tst_QNetworkReply::ignoreSslErrorListSlot(QNetworkReply *reply, const QList<QSslError> &) +{ + reply->ignoreSslErrors(storedExpectedSslErrors); +} + +// do the same as in ignoreSslErrorsList, but ignore the errors in the slot +void tst_QNetworkReply::ignoreSslErrorsListWithSlot() +{ + QFETCH(QString, url); + QNetworkRequest request(url); + QNetworkReplyPtr reply = manager.get(request); + + QFETCH(QList<QSslError>, expectedSslErrors); + // store the errors to ignore them later in the slot connected below + storedExpectedSslErrors = expectedSslErrors; + connect(&manager, SIGNAL(sslErrors(QNetworkReply *, const QList<QSslError> &)), + this, SLOT(ignoreSslErrorListSlot(QNetworkReply *, const QList<QSslError> &))); + + + connect(reply, SIGNAL(finished()), &QTestEventLoop::instance(), SLOT(exitLoop())); + QTestEventLoop::instance().enterLoop(10); + QVERIFY(!QTestEventLoop::instance().timeout()); + + QFETCH(QNetworkReply::NetworkError, expectedNetworkError); + QCOMPARE(reply->error(), expectedNetworkError); +} + +void tst_QNetworkReply::sslConfiguration_data() +{ + QTest::addColumn<QSslConfiguration>("configuration"); + QTest::addColumn<bool>("works"); + + QTest::newRow("empty") << QSslConfiguration() << false; + QSslConfiguration conf = QSslConfiguration::defaultConfiguration(); + QTest::newRow("default") << conf << false; // does not contain test server cert + QList<QSslCertificate> testServerCert = QSslCertificate::fromPath(SRCDIR "/certs/qt-test-server-cacert.pem"); + conf.setCaCertificates(testServerCert); + QTest::newRow("set-root-cert") << conf << true; + conf.setProtocol(QSsl::SecureProtocols); + QTest::newRow("secure") << conf << true; +} + +void tst_QNetworkReply::sslConfiguration() +{ + QNetworkRequest request(QUrl("https://" + QtNetworkSettings::serverName() + "/index.html")); + QFETCH(QSslConfiguration, configuration); + request.setSslConfiguration(configuration); + QNetworkReplyPtr reply = manager.get(request); + + connect(reply, SIGNAL(finished()), &QTestEventLoop::instance(), SLOT(exitLoop())); + QTestEventLoop::instance().enterLoop(10); + QVERIFY(!QTestEventLoop::instance().timeout()); + + QFETCH(bool, works); + QNetworkReply::NetworkError expectedError = works ? QNetworkReply::NoError : QNetworkReply::SslHandshakeFailedError; + QCOMPARE(reply->error(), expectedError); +} + +#endif // QT_NO_OPENSSL + +void tst_QNetworkReply::getAndThenDeleteObject_data() +{ + QTest::addColumn<bool>("replyFirst"); + + QTest::newRow("delete-reply-first") << true; + QTest::newRow("delete-qnam-first") << false; +} + +void tst_QNetworkReply::getAndThenDeleteObject() +{ + // yes, this will leak if the testcase fails. I don't care. It must not fail then :P + QNetworkAccessManager *manager = new QNetworkAccessManager(); + QNetworkRequest request("http://" + QtNetworkSettings::serverName() + "/qtest/bigfile"); + QNetworkReply *reply = manager->get(request); + reply->setReadBufferSize(1); + reply->setParent((QObject*)0); // must be 0 because else it is the manager + + QTime stopWatch; + stopWatch.start(); + forever { + QCoreApplication::instance()->processEvents(); + if (reply->bytesAvailable()) + break; + if (stopWatch.elapsed() >= 30000) + break; + } + + QVERIFY(reply->bytesAvailable()); + QCOMPARE(reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(), 200); + QVERIFY(!reply->isFinished()); // must not be finished + + QFETCH(bool, replyFirst); + + if (replyFirst) { + delete reply; + delete manager; + } else { + delete manager; + delete reply; + } +} + +// see https://bugs.webkit.org/show_bug.cgi?id=38935 +void tst_QNetworkReply::symbianOpenCDataUrlCrash() +{ + QString requestUrl("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABkAAAAWCAYAAAA1vze2AAAAB3RJTUUH2AUSEgolrgBvVQAAAAlwSFlzAAALEwAACxMBAJqcGAAAAARnQU1BAACxjwv8YQUAAAHlSURBVHja5VbNShxBEK6ZaXtnHTebQPA1gngNmfaeq+QNPIlIXkC9iQdJxJNvEHLN3VkxhxxE8gTmEhAVddXZ6Z3f9Ndriz89/sHmkBQUVVT1fB9d9c3uOERUKTunIdn3HzstxGpYBDS4wZk7TAJj/wlJ90J+jnuygqs8svSj+/rGHBos3rE18XBvfU3no7NzlJfUaY/5whAwl8Lr/WDUv4ODxTMb+P5xLExe5LmO559WqTX/MQR4WZYEAtSePS4pE0qSnuhnRUcBU5Gm2k9XljU4Z26I3NRxBrd80rj2fh+KNE0FY4xevRgTjREvPFpasAK8Xli6MUbbuKw3afAGgSBXozo5u4hkmncAlkl5wx8iMGbdyQjnCFEiEwGiosj1UQA/x2rVddiVoi+l4IxE0PTDnx+mrQBvvnx9cFz3krhVvuhzFn579/aq/n5rW8fbtTqiWhIQZEo17YBvbkxOXNVndnYpTvod7AtiuN2re0+siwcB9oH8VxxrNwQQAhzyRs30n7wTI2HIN2g2QtQwjjhJIQatOq7E8bIVCLwzpl83Lvtvl+NohWWlE8UZTWEMAGCcR77fHKhPnZF5tYie6dfdxCphACmLPM+j8bYfmTryg64kV9Vh3mV8jP0b/4wO/YUPiT/8i0MLf55lSQAAAABJRU5ErkJggg=="); + QUrl url = QUrl::fromEncoded(requestUrl.toLatin1()); + QNetworkRequest req(url); + QNetworkReplyPtr reply; + + RUN_REQUEST(runSimpleRequest(QNetworkAccessManager::GetOperation, req, reply)); + + QCOMPARE(reply->url(), url); + QCOMPARE(reply->error(), QNetworkReply::NoError); + + QCOMPARE(reply->header(QNetworkRequest::ContentLengthHeader).toLongLong(), qint64(598)); +} + +void tst_QNetworkReply::getFromHttpIntoBuffer_data() +{ + QTest::addColumn<QUrl>("url"); + + QTest::newRow("rfc-internal") << QUrl("http://" + QtNetworkSettings::serverName() + "/qtest/rfc3252.txt"); +} + +// Please note that the whole "zero copy" download buffer API is private right now. Do not use it. +void tst_QNetworkReply::getFromHttpIntoBuffer() +{ + QFETCH(QUrl, url); + QNetworkRequest request(url); + request.setAttribute(QNetworkRequest::MaximumDownloadBufferSizeAttribute, 1024*128); // 128 kB + + QNetworkAccessManager manager; + QNetworkReply *reply = manager.get(request); + connect(reply, SIGNAL(finished()), &QTestEventLoop::instance(), SLOT(exitLoop())); + + QTestEventLoop::instance().enterLoop(10); + QVERIFY(!QTestEventLoop::instance().timeout()); + QVERIFY(reply->isFinished()); + + QFile reference(SRCDIR "/rfc3252.txt"); + QVERIFY(reference.open(QIODevice::ReadOnly)); + + QCOMPARE(reference.bytesAvailable(), reply->bytesAvailable()); + QCOMPARE(reference.size(), reply->size()); + + // Compare the memory buffer + QVariant downloadBufferAttribute = reply->attribute(QNetworkRequest::DownloadBufferAttribute); + QVERIFY(downloadBufferAttribute.isValid()); + QSharedPointer<char> sharedPointer = downloadBufferAttribute.value<QSharedPointer<char> >(); + bool memoryComparison = + (0 == memcmp(static_cast<void*>(reference.readAll().data()), + sharedPointer.data(), reference.size())); + QVERIFY(memoryComparison); + + // Make sure the normal reading works + reference.seek(0); + QCOMPARE(reply->read(42), reference.read(42)); + QCOMPARE(reply->getChar(0), reference.getChar(0)); + QCOMPARE(reply->peek(23), reference.peek(23)); + QCOMPARE(reply->readLine(), reference.readLine()); + QCOMPARE(reference.bytesAvailable(), reply->bytesAvailable()); + QCOMPARE(reply->readAll(), reference.readAll()); + QVERIFY(reply->atEnd()); +} + +// FIXME we really need to consolidate all those server implementations +class GetFromHttpIntoBuffer2Server : QObject { + Q_OBJECT + qint64 dataSize; + qint64 dataSent; + QTcpServer server; + QTcpSocket *client; + bool serverSendsContentLength; + bool chunkedEncoding; + +public: + GetFromHttpIntoBuffer2Server (qint64 ds, bool sscl, bool ce) : dataSize(ds), dataSent(0), + client(0), serverSendsContentLength(sscl), chunkedEncoding(ce) { + server.listen(); + connect(&server, SIGNAL(newConnection()), this, SLOT(newConnectionSlot())); + } + + int serverPort() { + return server.serverPort(); + } + +public slots: + + void newConnectionSlot() { + client = server.nextPendingConnection(); + client->setParent(this); + connect(client, SIGNAL(readyRead()), this, SLOT(readyReadSlot())); + connect(client, SIGNAL(bytesWritten(qint64)), this, SLOT(bytesWrittenSlot(qint64))); + } + + void readyReadSlot() { + client->readAll(); + client->write("HTTP/1.0 200 OK\n"); + if (serverSendsContentLength) + client->write(QString("Content-Length: " + QString::number(dataSize) + "\n").toAscii()); + if (chunkedEncoding) + client->write(QString("Transfer-Encoding: chunked\n").toAscii()); + client->write("Connection: close\n\n"); + } + + void bytesWrittenSlot(qint64 amount) { + Q_UNUSED(amount); + if (dataSent == dataSize && client) { + // close eventually + + // chunked encoding: we have to send a last "empty" chunk + if (chunkedEncoding) + client->write(QString("0\r\n\r\n").toAscii()); + + client->disconnectFromHost(); + server.close(); + client = 0; + return; + } + + // send data + if (client && client->bytesToWrite() < 100*1024 && dataSent < dataSize) { + qint64 amount = qMin(qint64(16*1024), dataSize - dataSent); + QByteArray data(amount, '@'); + + if (chunkedEncoding) { + client->write(QString(QString("%1").arg(amount,0,16).toUpper() + "\r\n").toAscii()); + client->write(data.constData(), amount); + client->write(QString("\r\n").toAscii()); + } else { + client->write(data.constData(), amount); + } + + dataSent += amount; + } + } +}; + +class GetFromHttpIntoBuffer2Client : QObject { + Q_OBJECT +private: + bool useDownloadBuffer; + QNetworkReply *reply; + qint64 uploadSize; + QList<qint64> bytesAvailableList; +public: + GetFromHttpIntoBuffer2Client (QNetworkReply *reply, bool useDownloadBuffer, qint64 uploadSize) + : useDownloadBuffer(useDownloadBuffer), reply(reply), uploadSize(uploadSize) + { + connect(reply, SIGNAL(metaDataChanged()), this, SLOT(metaDataChangedSlot())); + connect(reply, SIGNAL(readyRead()), this, SLOT(readyReadSlot())); + connect(reply, SIGNAL(finished()), this, SLOT(finishedSlot())); + } + + public slots: + void metaDataChangedSlot() { + if (useDownloadBuffer) { + QSharedPointer<char> sharedPointer = qvariant_cast<QSharedPointer<char> >(reply->attribute(QNetworkRequest::DownloadBufferAttribute)); + QVERIFY(!sharedPointer.isNull()); // It will be 0 if it failed + } + + // metaDataChanged needs to come before everything else + QVERIFY(bytesAvailableList.isEmpty()); + } + + void readyReadSlot() { + QVERIFY(!reply->isFinished()); + + qint64 bytesAvailable = reply->bytesAvailable(); + + // bytesAvailable must never be 0 + QVERIFY(bytesAvailable != 0); + + if (bytesAvailableList.length() < 5) { + // We assume that the first few times the bytes available must be less than the complete size, e.g. + // the bytesAvailable() function works correctly in case of a downloadBuffer. + QVERIFY(bytesAvailable < uploadSize); + } + if (!bytesAvailableList.isEmpty()) { + // Also check that the same bytesAvailable is not coming twice in a row + QVERIFY(bytesAvailableList.last() != bytesAvailable); + } + + bytesAvailableList.append(bytesAvailable); + // Add bytesAvailable to a list an parse + } + + void finishedSlot() { + // We should have already received all readyRead + QVERIFY(!bytesAvailableList.isEmpty()); + QVERIFY(bytesAvailableList.last() == uploadSize); + } +}; + +void tst_QNetworkReply::getFromHttpIntoBuffer2_data() +{ + QTest::addColumn<bool>("useDownloadBuffer"); + + QTest::newRow("use-download-buffer") << true; + QTest::newRow("do-not-use-download-buffer") << false; +} + +// This test checks mostly that signal emissions are in correct order +// Please note that the whole "zero copy" download buffer API is private right now. Do not use it. +void tst_QNetworkReply::getFromHttpIntoBuffer2() +{ + QFETCH(bool, useDownloadBuffer); + + // On my Linux Desktop the results are already visible with 128 kB, however we use this to have good results. +#if defined(Q_OS_SYMBIAN) || defined(Q_WS_WINCE_WM) + // Show some mercy to non-desktop platform/s + enum {UploadSize = 4*1024*1024}; // 4 MB +#else + enum {UploadSize = 32*1024*1024}; // 32 MB +#endif + + GetFromHttpIntoBuffer2Server server(UploadSize, true, false); + + QNetworkRequest request(QUrl("http://127.0.0.1:" + QString::number(server.serverPort()) + "/?bare=1")); + if (useDownloadBuffer) + request.setAttribute(QNetworkRequest::MaximumDownloadBufferSizeAttribute, 1024*1024*128); // 128 MB is max allowed + + QNetworkAccessManager manager; + QNetworkReplyPtr reply = manager.get(request); + + GetFromHttpIntoBuffer2Client client(reply, useDownloadBuffer, UploadSize); + + connect(reply, SIGNAL(finished()), &QTestEventLoop::instance(), SLOT(exitLoop()), Qt::QueuedConnection); + QTestEventLoop::instance().enterLoop(40); + QCOMPARE(reply->error(), QNetworkReply::NoError); + QVERIFY(!QTestEventLoop::instance().timeout()); +} + + +void tst_QNetworkReply::getFromHttpIntoBufferCanReadLine() +{ + QString header("HTTP/1.0 200 OK\r\nContent-Length: 7\r\n\r\nxxx\nxxx"); + + MiniHttpServer server(header.toAscii()); + server.doClose = true; + + QNetworkRequest request(QUrl("http://localhost:" + QString::number(server.serverPort()))); + request.setAttribute(QNetworkRequest::MaximumDownloadBufferSizeAttribute, 1024*1024*128); // 128 MB is max allowed + QNetworkReplyPtr reply = manager.get(request); + + connect(reply, SIGNAL(finished()), &QTestEventLoop::instance(), SLOT(exitLoop())); + QTestEventLoop::instance().enterLoop(10); + QVERIFY(!QTestEventLoop::instance().timeout()); + + QCOMPARE(reply->error(), QNetworkReply::NoError); + QVERIFY(reply->canReadLine()); + QCOMPARE(reply->read(1), QByteArray("x")); + QVERIFY(reply->canReadLine()); + QCOMPARE(reply->read(3), QByteArray("xx\n")); + QVERIFY(!reply->canReadLine()); + QCOMPARE(reply->readAll(), QByteArray("xxx")); + QVERIFY(!reply->canReadLine()); +} + + + +// Is handled somewhere else too, introduced this special test to have it more accessible +void tst_QNetworkReply::ioGetFromHttpWithoutContentLength() +{ + QByteArray dataToSend("HTTP/1.0 200 OK\r\n\r\nHALLO! 123!"); + MiniHttpServer server(dataToSend); + server.doClose = true; + + QNetworkRequest request(QUrl("http://localhost:" + QString::number(server.serverPort()))); + QNetworkReplyPtr reply = manager.get(request); + + connect(reply, SIGNAL(finished()), &QTestEventLoop::instance(), SLOT(exitLoop())); + QTestEventLoop::instance().enterLoop(10); + QVERIFY(!QTestEventLoop::instance().timeout()); + + QCOMPARE(reply->url(), request.url()); + QVERIFY(reply->isFinished()); + QVERIFY(reply->error() == QNetworkReply::NoError); +} + +// Is handled somewhere else too, introduced this special test to have it more accessible +void tst_QNetworkReply::ioGetFromHttpBrokenChunkedEncoding() +{ + // This is wrong chunked encoding because of the X. What actually has to follow is \r\n + // and then the declaration of the final 0 chunk + QByteArray dataToSend("HTTP/1.0 200 OK\r\nTransfer-Encoding: chunked\r\n\r\n3\r\nABCX"); + MiniHttpServer server(dataToSend); + server.doClose = false; // FIXME + + QNetworkRequest request(QUrl("http://localhost:" + QString::number(server.serverPort()))); + QNetworkReplyPtr reply = manager.get(request); + + connect(reply, SIGNAL(finished()), &QTestEventLoop::instance(), SLOT(exitLoop())); + QTestEventLoop::instance().enterLoop(10); + + QEXPECT_FAIL(0, "We should close the socket and not just do nothing", Continue); + QVERIFY(!QTestEventLoop::instance().timeout()); + QEXPECT_FAIL(0, "We should close the socket and not just do nothing", Continue); + QVERIFY(reply->isFinished()); + QCOMPARE(reply->error(), QNetworkReply::NoError); +} + +// TODO: +// Prepare a gzip that has one chunk that expands to the size mentioned in the bugreport. +// Then have a custom HTTP server that waits after this chunk so the returning gets +// triggered. +void tst_QNetworkReply::qtbug12908compressedHttpReply() +{ + QString header("HTTP/1.0 200 OK\r\nContent-Encoding: gzip\r\nContent-Length: 63\r\n\r\n"); + + // dd if=/dev/zero of=qtbug-12908 bs=16384 count=1 && gzip qtbug-12908 && base64 -w 0 qtbug-12908.gz + QString encodedFile("H4sICDdDaUwAA3F0YnVnLTEyOTA4AO3BMQEAAADCoPVPbQwfoAAAAAAAAAAAAAAAAAAAAIC3AYbSVKsAQAAA"); + QByteArray decodedFile = QByteArray::fromBase64(encodedFile.toAscii()); + QCOMPARE(decodedFile.size(), 63); + + MiniHttpServer server(header.toAscii() + decodedFile); + server.doClose = true; + + QNetworkRequest request(QUrl("http://localhost:" + QString::number(server.serverPort()))); + QNetworkReplyPtr reply = manager.get(request); + + connect(reply, SIGNAL(finished()), &QTestEventLoop::instance(), SLOT(exitLoop())); + QTestEventLoop::instance().enterLoop(10); + QVERIFY(!QTestEventLoop::instance().timeout()); + + QCOMPARE(reply->error(), QNetworkReply::NoError); + QCOMPARE(reply->size(), qint64(16384)); + QCOMPARE(reply->readAll(), QByteArray(16384, '\0')); +} + +void tst_QNetworkReply::compressedHttpReplyBrokenGzip() +{ + QString header("HTTP/1.0 200 OK\r\nContent-Encoding: gzip\r\nContent-Length: 63\r\n\r\n"); + + // dd if=/dev/zero of=qtbug-12908 bs=16384 count=1 && gzip qtbug-12908 && base64 -w 0 qtbug-12908.gz + // Then change "BMQ" to "BMX" + QString encodedFile("H4sICDdDaUwAA3F0YnVnLTEyOTA4AO3BMXEAAADCoPVPbQwfoAAAAAAAAAAAAAAAAAAAAIC3AYbSVKsAQAAA"); + QByteArray decodedFile = QByteArray::fromBase64(encodedFile.toAscii()); + QCOMPARE(decodedFile.size(), 63); + + MiniHttpServer server(header.toAscii() + decodedFile); + server.doClose = true; + + QNetworkRequest request(QUrl("http://localhost:" + QString::number(server.serverPort()))); + QNetworkReplyPtr reply = manager.get(request); + + connect(reply, SIGNAL(finished()), &QTestEventLoop::instance(), SLOT(exitLoop())); + QTestEventLoop::instance().enterLoop(10); + QVERIFY(!QTestEventLoop::instance().timeout()); + + QCOMPARE(reply->error(), QNetworkReply::ProtocolFailure); +} + +// TODO add similar test for FTP +void tst_QNetworkReply::getFromUnreachableIp() +{ + QNetworkAccessManager manager; + + QNetworkRequest request(QUrl("http://255.255.255.255/42/23/narf/narf/narf")); + QNetworkReplyPtr reply = manager.get(request); + + connect(reply, SIGNAL(finished()), &QTestEventLoop::instance(), SLOT(exitLoop())); + QTestEventLoop::instance().enterLoop(10); + QVERIFY(!QTestEventLoop::instance().timeout()); + + QVERIFY(reply->error() != QNetworkReply::NoError); +} + +void tst_QNetworkReply::qtbug4121unknownAuthentication() +{ + MiniHttpServer server(QByteArray("HTTP/1.1 401 bla\r\nWWW-Authenticate: crap\r\nContent-Length: 0\r\n\r\n")); + server.doClose = false; + + QNetworkRequest request(QUrl("http://localhost:" + QString::number(server.serverPort()))); + QNetworkAccessManager manager; + QNetworkReplyPtr reply = manager.get(request); + + qRegisterMetaType<QNetworkReply*>("QNetworkReply*"); + qRegisterMetaType<QAuthenticator*>("QAuthenticator*"); + QSignalSpy authSpy(&manager, SIGNAL(authenticationRequired(QNetworkReply*,QAuthenticator*))); + QSignalSpy finishedSpy(&manager, SIGNAL(finished(QNetworkReply*))); + qRegisterMetaType<QNetworkReply::NetworkError>("QNetworkReply::NetworkError"); + QSignalSpy errorSpy(reply, SIGNAL(error(QNetworkReply::NetworkError))); + + connect(reply, SIGNAL(finished()), &QTestEventLoop::instance(), SLOT(exitLoop()), Qt::QueuedConnection); + QTestEventLoop::instance().enterLoop(10); + QVERIFY(!QTestEventLoop::instance().timeout()); + + QCOMPARE(authSpy.count(), 0); + QCOMPARE(finishedSpy.count(), 1); + QCOMPARE(errorSpy.count(), 1); + + QCOMPARE(reply->error(), QNetworkReply::AuthenticationRequiredError); +} + +class QtBug13431Helper : public QObject { + Q_OBJECT +public: + QNetworkReply* m_reply; + QTimer m_dlTimer; +public slots: + void replyFinished(QNetworkReply*) { + QTestEventLoop::instance().exitLoop(); + } + + void onReadAndReschedule() { + const qint64 bytesReceived = m_reply->bytesAvailable(); + if (bytesReceived && m_reply->readBufferSize()) { + QByteArray data = m_reply->read(bytesReceived); + // reschedule read + const int millisecDelay = static_cast<int>(bytesReceived * 1000 / m_reply->readBufferSize()); + m_dlTimer.start(millisecDelay); + } + else { + // reschedule read + m_dlTimer.start(200); + } + } +}; + +void tst_QNetworkReply::qtbug13431replyThrottling() +{ + QtBug13431Helper helper; + + QNetworkAccessManager nam; + connect(&nam, SIGNAL(finished(QNetworkReply*)), &helper, SLOT(replyFinished(QNetworkReply*))); + + // Download a bigger file + QNetworkRequest netRequest(QUrl("http://" + QtNetworkSettings::serverName() + "/qtest/bigfile")); + helper.m_reply = nam.get(netRequest); + // Set the throttle + helper.m_reply->setReadBufferSize(36000); + + // Schedule a timer that tries to read + + connect(&helper.m_dlTimer, SIGNAL(timeout()), &helper, SLOT(onReadAndReschedule())); + helper.m_dlTimer.setSingleShot(true); + helper.m_dlTimer.start(0); + + QTestEventLoop::instance().enterLoop(30); + QVERIFY(!QTestEventLoop::instance().timeout()); + QVERIFY(helper.m_reply->isFinished()); + QCOMPARE(helper.m_reply->error(), QNetworkReply::NoError); +} + +void tst_QNetworkReply::httpWithNoCredentialUsage() +{ + QNetworkRequest request(QUrl("http://httptest:httptest@" + QtNetworkSettings::serverName() + "/qtest/protected/cgi-bin/md5sum.cgi")); + // Do not use credentials + request.setAttribute(QNetworkRequest::AuthenticationReuseAttribute, QNetworkRequest::Manual); + QNetworkAccessManager manager; + QNetworkReplyPtr reply = manager.get(request); + + qRegisterMetaType<QNetworkReply*>("QNetworkReply*"); + qRegisterMetaType<QAuthenticator*>("QAuthenticator*"); + QSignalSpy authSpy(&manager, SIGNAL(authenticationRequired(QNetworkReply*,QAuthenticator*))); + QSignalSpy finishedSpy(&manager, SIGNAL(finished(QNetworkReply*))); + qRegisterMetaType<QNetworkReply::NetworkError>("QNetworkReply::NetworkError"); + QSignalSpy errorSpy(reply, SIGNAL(error(QNetworkReply::NetworkError))); + + connect(reply, SIGNAL(finished()), &QTestEventLoop::instance(), SLOT(exitLoop()), Qt::QueuedConnection); + QTestEventLoop::instance().enterLoop(10); + QVERIFY(!QTestEventLoop::instance().timeout()); + + // We check if authenticationRequired was emitted, however we do not anything in it so it should be 401 + QCOMPARE(authSpy.count(), 1); + QCOMPARE(finishedSpy.count(), 1); + QCOMPARE(errorSpy.count(), 1); + + QCOMPARE(reply->error(), QNetworkReply::AuthenticationRequiredError); +} + +void tst_QNetworkReply::qtbug15311doubleContentLength() +{ + QByteArray response("HTTP/1.0 200 OK\r\nContent-Length: 3\r\nServer: bogus\r\nContent-Length: 3\r\n\r\nABC"); + MiniHttpServer server(response); + server.doClose = true; + + QNetworkRequest request(QUrl("http://localhost:" + QString::number(server.serverPort()))); + QNetworkReplyPtr reply = manager.get(request); + + connect(reply, SIGNAL(finished()), &QTestEventLoop::instance(), SLOT(exitLoop())); + QTestEventLoop::instance().enterLoop(10); + QVERIFY(!QTestEventLoop::instance().timeout()); + QVERIFY(reply->isFinished()); + QCOMPARE(reply->error(), QNetworkReply::NoError); + QCOMPARE(reply->size(), qint64(3)); + QCOMPARE(reply->header(QNetworkRequest::ContentLengthHeader).toLongLong(), qint64(3)); + QCOMPARE(reply->rawHeader("Content-length"), QByteArray("3, 3")); + QCOMPARE(reply->readAll(), QByteArray("ABC")); +} + +void tst_QNetworkReply::qtbug18232gzipContentLengthZero() +{ + QByteArray response("HTTP/1.0 200 OK\r\nContent-Encoding: gzip\r\nContent-Length: 0\r\n\r\n"); + MiniHttpServer server(response); + server.doClose = true; + + QNetworkRequest request(QUrl("http://localhost:" + QString::number(server.serverPort()))); + QNetworkReplyPtr reply = manager.get(request); + + connect(reply, SIGNAL(finished()), &QTestEventLoop::instance(), SLOT(exitLoop())); + QTestEventLoop::instance().enterLoop(10); + QVERIFY(!QTestEventLoop::instance().timeout()); + QVERIFY(reply->isFinished()); + QCOMPARE(reply->error(), QNetworkReply::NoError); + QCOMPARE(reply->size(), qint64(0)); + QCOMPARE(reply->header(QNetworkRequest::ContentLengthHeader).toLongLong(), qint64(0)); + QCOMPARE(reply->readAll(), QByteArray()); +} + +void tst_QNetworkReply::synchronousRequest_data() +{ + QTest::addColumn<QUrl>("url"); + QTest::addColumn<QString>("expected"); + QTest::addColumn<bool>("checkContentLength"); + QTest::addColumn<QString>("mimeType"); + + // ### cache, auth, proxies + + QTest::newRow("http") + << QUrl("http://" + QtNetworkSettings::serverName() + "/qtest/rfc3252.txt") + << QString("file:" SRCDIR "/rfc3252.txt") + << true + << QString("text/plain"); + + QTest::newRow("http-gzip") + << QUrl("http://" + QtNetworkSettings::serverName() + "/qtest/deflate/rfc3252.txt") + << QString("file:" SRCDIR "/rfc3252.txt") + << false // don't check content length, because it's gzip encoded + // ### we would need to enflate (un-deflate) the file content and compare the sizes + << QString("text/plain"); + +#ifndef QT_NO_OPENSSL + QTest::newRow("https") + << QUrl("https://" + QtNetworkSettings::serverName() + "/qtest/rfc3252.txt") + << QString("file:" SRCDIR "/rfc3252.txt") + << true + << QString("text/plain"); +#endif + + QTest::newRow("data") + << QUrl(QString::fromLatin1("data:text/plain,hello world")) + << QString("data:hello world") + << true // check content length + << QString("text/plain"); + + QTest::newRow("simple-file") + << QUrl::fromLocalFile(SRCDIR "/rfc3252.txt") + << QString("file:" SRCDIR "/rfc3252.txt") + << true + << QString(); +} + +// FIXME add testcase for failing network etc +void tst_QNetworkReply::synchronousRequest() +{ + QFETCH(QUrl, url); + QFETCH(QString, expected); + QFETCH(bool, checkContentLength); + QFETCH(QString, mimeType); + + QNetworkRequest request(url); + +#ifndef QT_NO_OPENSSL + // workaround for HTTPS requests: add self-signed server cert to list of CA certs, + // since we cannot react to the sslErrors() signal + // to fix this properly we would need to have an ignoreSslErrors() method in the + // QNetworkRequest, see http://bugreports.qt.nokia.com/browse/QTBUG-14774 + if (url.scheme() == "https") { + QSslConfiguration sslConf; + QList<QSslCertificate> certs = QSslCertificate::fromPath(SRCDIR "/certs/qt-test-server-cacert.pem"); + sslConf.setCaCertificates(certs); + request.setSslConfiguration(sslConf); + } +#endif + + request.setAttribute( + QNetworkRequest::SynchronousRequestAttribute, + true); + + QNetworkReplyPtr reply; + QSignalSpy finishedSpy(&manager, SIGNAL(finished(QNetworkReply*))); + QSignalSpy sslErrorsSpy(&manager, SIGNAL(sslErrors(QNetworkReply*,QList<QSslError>))); + RUN_REQUEST(runSimpleRequest(QNetworkAccessManager::GetOperation, request, reply, 0)); + QVERIFY(reply->isFinished()); + QCOMPARE(finishedSpy.count(), 0); + QCOMPARE(sslErrorsSpy.count(), 0); + + QCOMPARE(reply->header(QNetworkRequest::ContentTypeHeader).toString(), mimeType); + + QByteArray expectedContent; + + if (expected.startsWith("file:")) { + QString path = expected.mid(5); + QFile file(path); + file.open(QIODevice::ReadOnly); + expectedContent = file.readAll(); + } else if (expected.startsWith("data:")) { + expectedContent = expected.mid(5).toUtf8(); + } + + if (checkContentLength) + QCOMPARE(reply->header(QNetworkRequest::ContentLengthHeader).toLongLong(), qint64(expectedContent.size())); + QCOMPARE(reply->readAll(), expectedContent); + + reply->deleteLater(); +} + +#ifndef QT_NO_OPENSSL +void tst_QNetworkReply::synchronousRequestSslFailure() +{ + // test that SSL won't be accepted with self-signed certificate, + // and that we do not emit the sslError signal (in the manager that is, + // in the reply we don't care) + + QUrl url("https://" + QtNetworkSettings::serverName() + "/qtest/rfc3252.txt"); + QNetworkRequest request(url); + request.setAttribute( + QNetworkRequest::SynchronousRequestAttribute, + true); + QNetworkReplyPtr reply; + QSignalSpy sslErrorsSpy(&manager, SIGNAL(sslErrors(QNetworkReply *, const QList<QSslError> &))); + runSimpleRequest(QNetworkAccessManager::GetOperation, request, reply, 0); + QVERIFY(reply->isFinished()); + QCOMPARE(reply->error(), QNetworkReply::SslHandshakeFailedError); + QCOMPARE(sslErrorsSpy.count(), 0); +} +#endif + +class HttpAbortHelper : public QObject +{ + Q_OBJECT +public: + HttpAbortHelper(QNetworkReply *parent) + : QObject(parent) + { + mReply = parent; + connect(parent, SIGNAL(readyRead()), this, SLOT(readyRead())); + } + + ~HttpAbortHelper() + { + } + +public slots: + void readyRead() + { + mReply->abort(); + QMetaObject::invokeMethod(&QTestEventLoop::instance(), "exitLoop", Qt::QueuedConnection); + } + +private: + QNetworkReply *mReply; +}; + +void tst_QNetworkReply::httpAbort() +{ + // FIXME Also implement one where we do a big upload and then abort(). + // It must not crash either. + + // Abort after the first readyRead() + QNetworkRequest request("http://" + QtNetworkSettings::serverName() + "/qtest/bigfile"); + QNetworkReplyPtr reply; + reply = manager.get(request); + HttpAbortHelper replyHolder(reply); + QTestEventLoop::instance().enterLoop(10); + QVERIFY(!QTestEventLoop::instance().timeout()); + QCOMPARE(reply->error(), QNetworkReply::OperationCanceledError); + QVERIFY(reply->isFinished()); + + // Abort immediately after the get() + QNetworkReplyPtr reply2 = manager.get(request); + connect(reply2, SIGNAL(finished()), &QTestEventLoop::instance(), SLOT(exitLoop())); + reply2->abort(); + QCOMPARE(reply2->error(), QNetworkReply::OperationCanceledError); + QVERIFY(reply2->isFinished()); + + // Abort after the finished() + QNetworkRequest request3("http://" + QtNetworkSettings::serverName() + "/qtest/rfc3252.txt"); + QNetworkReplyPtr reply3 = manager.get(request3); + connect(reply3, SIGNAL(finished()), &QTestEventLoop::instance(), SLOT(exitLoop())); + QTestEventLoop::instance().enterLoop(10); + QVERIFY(reply3->isFinished()); + reply3->abort(); + QCOMPARE(reply3->error(), QNetworkReply::NoError); +} + +void tst_QNetworkReply::dontInsertPartialContentIntoTheCache() +{ + QByteArray reply206 = + "HTTP/1.0 206\r\n" + "Connection: keep-alive\r\n" + "Content-Type: text/plain\r\n" + "Cache-control: no-cache\r\n" + "Content-Range: bytes 2-6/8\r\n" + "Content-length: 4\r\n" + "\r\n" + "load"; + + MiniHttpServer server(reply206); + server.doClose = false; + + MySpyMemoryCache *memoryCache = new MySpyMemoryCache(&manager); + manager.setCache(memoryCache); + + QUrl url = "http://localhost:" + QString::number(server.serverPort()); + QNetworkRequest request(url); + request.setRawHeader("Range", "bytes=2-6"); + + QNetworkReplyPtr reply = manager.get(request); + + connect(reply, SIGNAL(finished()), &QTestEventLoop::instance(), SLOT(exitLoop())); + QTestEventLoop::instance().enterLoop(10); + QVERIFY(!QTestEventLoop::instance().timeout()); + + QVERIFY(server.totalConnections > 0); + QCOMPARE(reply->readAll().constData(), "load"); + QCOMPARE(memoryCache->m_insertedUrls.count(), 0); +} + +void tst_QNetworkReply::httpUserAgent() +{ + QByteArray response("HTTP/1.0 200 OK\r\n\r\n"); + MiniHttpServer server(response); + server.doClose = true; + + QNetworkRequest request(QUrl("http://localhost:" + QString::number(server.serverPort()))); + request.setHeader(QNetworkRequest::UserAgentHeader, "abcDEFghi"); + QNetworkReplyPtr reply = manager.get(request); + + connect(reply, SIGNAL(finished()), &QTestEventLoop::instance(), SLOT(exitLoop())); + QTestEventLoop::instance().enterLoop(10); + QVERIFY(!QTestEventLoop::instance().timeout()); + QVERIFY(reply->isFinished()); + QCOMPARE(reply->error(), QNetworkReply::NoError); + QVERIFY(server.receivedData.contains("\r\nUser-Agent: abcDEFghi\r\n")); +} + + +// NOTE: This test must be last testcase in tst_qnetworkreply! +void tst_QNetworkReply::parentingRepliesToTheApp() +{ + QNetworkRequest request (QUrl("http://" + QtNetworkSettings::serverName())); + manager.get(request)->setParent(this); // parent to this object + manager.get(request)->setParent(qApp); // parent to the app +} + +QTEST_MAIN(tst_QNetworkReply) + +#include "tst_qnetworkreply.moc" diff --git a/tests/auto/network/access/qnetworkrequest/.gitignore b/tests/auto/network/access/qnetworkrequest/.gitignore new file mode 100644 index 0000000000..c814099c96 --- /dev/null +++ b/tests/auto/network/access/qnetworkrequest/.gitignore @@ -0,0 +1 @@ +tst_qnetworkrequest diff --git a/tests/auto/network/access/qnetworkrequest/qnetworkrequest.pro b/tests/auto/network/access/qnetworkrequest/qnetworkrequest.pro new file mode 100644 index 0000000000..f96fd3bb02 --- /dev/null +++ b/tests/auto/network/access/qnetworkrequest/qnetworkrequest.pro @@ -0,0 +1,5 @@ +load(qttest_p4) +SOURCES += tst_qnetworkrequest.cpp + +QT = core network +symbian: TARGET.CAPABILITY = NetworkServices diff --git a/tests/auto/network/access/qnetworkrequest/tst_qnetworkrequest.cpp b/tests/auto/network/access/qnetworkrequest/tst_qnetworkrequest.cpp new file mode 100644 index 0000000000..90527163e2 --- /dev/null +++ b/tests/auto/network/access/qnetworkrequest/tst_qnetworkrequest.cpp @@ -0,0 +1,496 @@ +/**************************************************************************** +** +** 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 test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** 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. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + + +#include <QtTest/QtTest> +#include <QtCore/QUrl> +#include <QtNetwork/QNetworkRequest> +#include <QtNetwork/QNetworkCookie> + +Q_DECLARE_METATYPE(QList<QByteArray>) +Q_DECLARE_METATYPE(QNetworkRequest::KnownHeaders) +Q_DECLARE_METATYPE(QVariant) + +class tst_QNetworkRequest: public QObject +{ + Q_OBJECT + +private slots: + void ctor_data(); + void ctor(); + void setUrl_data(); + void setUrl(); + void setRawHeader_data(); + void setRawHeader(); + void rawHeaderList_data(); + void rawHeaderList(); + void setHeader_data(); + void setHeader(); + void rawHeaderParsing_data(); + void rawHeaderParsing(); + void originatingObject(); + + void removeHeader(); +}; + +QT_BEGIN_NAMESPACE + +namespace QTest { + template<> + char *toString(const QNetworkCookie &cookie) + { + return qstrdup(cookie.toRawForm()); + } + + template<> + char *toString(const QList<QNetworkCookie> &list) + { + QString result = "QList("; + bool first = true; + foreach (QNetworkCookie cookie, list) { + if (!first) + result += ", "; + first = false; + result += QString::fromLatin1("QNetworkCookie(%1)").arg(QLatin1String(cookie.toRawForm())); + } + + return qstrdup(result.append(')').toLocal8Bit()); + } +} + +QT_END_NAMESPACE + +void tst_QNetworkRequest::ctor_data() +{ + QTest::addColumn<QUrl>("url"); + + QTest::newRow("nothing") << QUrl(); + QTest::newRow("empty") << QUrl(); + QTest::newRow("http") << QUrl("http://qt.nokia.com"); +} + +void tst_QNetworkRequest::ctor() +{ + QFETCH(QUrl, url); + + if (qstrcmp(QTest::currentDataTag(), "nothing") == 0) { + QNetworkRequest request; + QCOMPARE(request.url(), url); + } else { + QNetworkRequest request(url); + QCOMPARE(request.url(), url); + } +} + +void tst_QNetworkRequest::setUrl_data() +{ + ctor_data(); +} + +void tst_QNetworkRequest::setUrl() +{ + QFETCH(QUrl, url); + QNetworkRequest request; + + if (qstrcmp(QTest::currentDataTag(), "nothing") != 0) + request.setUrl(url); + + QCOMPARE(request.url(), url); +} + +void tst_QNetworkRequest::setRawHeader_data() +{ + QTest::addColumn<QByteArray>("header"); + QTest::addColumn<QByteArray>("value"); + QTest::addColumn<QByteArray>("headerToGet"); + QTest::addColumn<QByteArray>("expectedValue"); + QTest::addColumn<bool>("hasHeader"); + + QTest::newRow("null-header") << QByteArray() << QByteArray("abc") + << QByteArray() << QByteArray() << false; + QTest::newRow("empty-header") << QByteArray("") << QByteArray("abc") + << QByteArray("") << QByteArray() << false; + QTest::newRow("null-value") << QByteArray("foo") << QByteArray() + << QByteArray("foo") << QByteArray() << false; + QTest::newRow("empty-value") << QByteArray("foo") << QByteArray("") + << QByteArray("foo") << QByteArray("") << true; + QTest::newRow("empty-value-vs-null") << QByteArray("foo") << QByteArray("") + << QByteArray("foo") << QByteArray() << true; + + QTest::newRow("UPPER-UPPER") << QByteArray("FOO") << QByteArray("abc") + << QByteArray("FOO") << QByteArray("abc") << true; + QTest::newRow("UPPER-Mixed") << QByteArray("FOO") << QByteArray("abc") + << QByteArray("Foo") << QByteArray("abc") << true; + QTest::newRow("UPPER-lower") << QByteArray("FOO") << QByteArray("abc") + << QByteArray("foo") << QByteArray("abc") << true; + QTest::newRow("Mixed-UPPER") << QByteArray("Foo") << QByteArray("abc") + << QByteArray("FOO") << QByteArray("abc") << true; + QTest::newRow("Mixed-Mixed") << QByteArray("Foo") << QByteArray("abc") + << QByteArray("Foo") << QByteArray("abc") << true; + QTest::newRow("Mixed-lower") << QByteArray("Foo") << QByteArray("abc") + << QByteArray("foo") << QByteArray("abc") << true; + QTest::newRow("lower-UPPER") << QByteArray("foo") << QByteArray("abc") + << QByteArray("FOO") << QByteArray("abc") << true; + QTest::newRow("lower-Mixed") << QByteArray("foo") << QByteArray("abc") + << QByteArray("Foo") << QByteArray("abc") << true; + QTest::newRow("lower-lower") << QByteArray("foo") << QByteArray("abc") + << QByteArray("foo") << QByteArray("abc") << true; +} + +void tst_QNetworkRequest::setRawHeader() +{ + QFETCH(QByteArray, header); + QFETCH(QByteArray, value); + QFETCH(QByteArray, headerToGet); + QFETCH(QByteArray, expectedValue); + QFETCH(bool, hasHeader); + + QNetworkRequest request; + request.setRawHeader(header, value); + + QCOMPARE(request.hasRawHeader(headerToGet), hasHeader); + QCOMPARE(request.rawHeader(headerToGet), expectedValue); +} + +void tst_QNetworkRequest::rawHeaderList_data() +{ + QTest::addColumn<QList<QByteArray> >("set"); + QTest::addColumn<QList<QByteArray> >("expected"); + + QTest::newRow("empty") << QList<QByteArray>() << QList<QByteArray>(); + + QList<QByteArray> set; + QList<QByteArray> expected; + + set << "foo"; + expected = set; + QTest::newRow("one") << set << expected; + + set << "bar"; + expected = set; + QTest::newRow("two") << set << expected; + + set.clear(); + expected.clear(); + set << "foo" << "foo"; + expected << "foo"; + QTest::newRow("repeated") << set << expected; + + set.clear(); + expected.clear(); + set << "foo" << "bar" << "foo"; + expected << "bar" << "foo"; + QTest::newRow("repeated-interleaved") << set << expected; +} + +void tst_QNetworkRequest::rawHeaderList() +{ + QFETCH(QList<QByteArray>, set); + QFETCH(QList<QByteArray>, expected); + + QNetworkRequest request; + foreach (QByteArray header, set) + request.setRawHeader(header, "a value"); + + QList<QByteArray> got = request.rawHeaderList(); + QCOMPARE(got.size(), expected.size()); + for (int i = 0; i < got.size(); ++i) + QCOMPARE(got.at(i), expected.at(i)); +} + +void tst_QNetworkRequest::setHeader_data() +{ + QTest::addColumn<QNetworkRequest::KnownHeaders>("cookedHeader"); + QTest::addColumn<QVariant>("cookedValue"); + QTest::addColumn<bool>("success"); + QTest::addColumn<QString>("rawHeader"); + QTest::addColumn<QString>("rawValue"); + + QTest::newRow("Content-Type-Null") << QNetworkRequest::ContentTypeHeader << QVariant() + << false << "Content-Type" << ""; + QTest::newRow("Content-Type-String") << QNetworkRequest::ContentTypeHeader << QVariant("text/html") + << true + << "Content-Type" << "text/html"; + QTest::newRow("Content-Type-ByteArray") << QNetworkRequest::ContentTypeHeader + << QVariant("text/html") << true + << "Content-Type" << "text/html"; + + QTest::newRow("Content-Length-Int") << QNetworkRequest::ContentLengthHeader << QVariant(1) + << true << "Content-Length" << "1"; + QTest::newRow("Content-Length-Int64") << QNetworkRequest::ContentLengthHeader << QVariant(qint64(1)) + << true << "Content-Length" << "1"; + + QTest::newRow("Location-String") << QNetworkRequest::LocationHeader << QVariant("http://foo/with space") + << true << "Location" << "http://foo/with space"; + QTest::newRow("Location-ByteArray") << QNetworkRequest::LocationHeader + << QVariant("http://foo/with space") + << true << "Location" << "http://foo/with space"; + QTest::newRow("Location-Url") << QNetworkRequest::LocationHeader + << QVariant(QUrl("http://foo/with space")) + << true << "Location" << "http://foo/with%20space"; + + QTest::newRow("Last-Modified-Date") << QNetworkRequest::LastModifiedHeader + << QVariant(QDate(2007, 11, 01)) + << true << "Last-Modified" + << "Thu, 01 Nov 2007 00:00:00 GMT"; + QTest::newRow("Last-Modified-DateTime") << QNetworkRequest::LastModifiedHeader + << QVariant(QDateTime(QDate(2007, 11, 01), + QTime(18, 8, 30), + Qt::UTC)) + << true << "Last-Modified" + << "Thu, 01 Nov 2007 18:08:30 GMT"; + + QNetworkCookie cookie; + cookie.setName("a"); + cookie.setValue("b"); + QTest::newRow("Cookie-1") << QNetworkRequest::CookieHeader + << qVariantFromValue(QList<QNetworkCookie>() << cookie) + << true << "Cookie" + << "a=b"; + QTest::newRow("SetCookie-1") << QNetworkRequest::SetCookieHeader + << qVariantFromValue(QList<QNetworkCookie>() << cookie) + << true << "Set-Cookie" + << "a=b"; + + cookie.setPath("/"); + QTest::newRow("Cookie-2") << QNetworkRequest::CookieHeader + << qVariantFromValue(QList<QNetworkCookie>() << cookie) + << true << "Cookie" + << "a=b"; + QTest::newRow("SetCookie-2") << QNetworkRequest::SetCookieHeader + << qVariantFromValue(QList<QNetworkCookie>() << cookie) + << true << "Set-Cookie" + << "a=b; path=/"; + + QNetworkCookie cookie2; + cookie2.setName("c"); + cookie2.setValue("d"); + QTest::newRow("Cookie-3") << QNetworkRequest::CookieHeader + << qVariantFromValue(QList<QNetworkCookie>() << cookie << cookie2) + << true << "Cookie" + << "a=b; c=d"; + QTest::newRow("SetCookie-3") << QNetworkRequest::SetCookieHeader + << qVariantFromValue(QList<QNetworkCookie>() << cookie << cookie2) + << true << "Set-Cookie" + << "a=b; path=/, c=d"; +} + +void tst_QNetworkRequest::setHeader() +{ + QFETCH(QNetworkRequest::KnownHeaders, cookedHeader); + QFETCH(QVariant, cookedValue); + QFETCH(bool, success); + QFETCH(QString, rawHeader); + QFETCH(QString, rawValue); + + QNetworkRequest request; + request.setHeader(cookedHeader, cookedValue); + + QCOMPARE(request.header(cookedHeader).isNull(), !success); + QCOMPARE(request.hasRawHeader(rawHeader.toLatin1()), success); + QCOMPARE(request.rawHeader(rawHeader.toLatin1()).isEmpty(), !success); + + if (success) { + QCOMPARE(request.header(cookedHeader), cookedValue); + QCOMPARE(QString(request.rawHeader(rawHeader.toLatin1())), rawValue); + } +} + +void tst_QNetworkRequest::rawHeaderParsing_data() +{ + QTest::addColumn<QNetworkRequest::KnownHeaders>("cookedHeader"); + QTest::addColumn<QVariant>("cookedValue"); + QTest::addColumn<bool>("success"); + QTest::addColumn<QString>("rawHeader"); + QTest::addColumn<QString>("rawValue"); + + QTest::newRow("Content-Type") << QNetworkRequest::ContentTypeHeader << QVariant("text/html") + << true + << "Content-Type" << "text/html"; + QTest::newRow("Content-Length") << QNetworkRequest::ContentLengthHeader << QVariant(qint64(1)) + << true << "Content-Length" << " 1 "; + QTest::newRow("Location") << QNetworkRequest::LocationHeader + << QVariant(QUrl("http://foo/with space")) + << true << "Location" << "http://foo/with%20space"; + QTest::newRow("Last-Modified-RFC1123") << QNetworkRequest::LastModifiedHeader + << QVariant(QDateTime(QDate(1994, 11, 06), + QTime(8, 49, 37), + Qt::UTC)) + << true << "Last-Modified" + << "Sun, 06 Nov 1994 08:49:37 GMT"; + QTest::newRow("Last-Modified-RFC850") << QNetworkRequest::LastModifiedHeader + << QVariant(QDateTime(QDate(1994, 11, 06), + QTime(8, 49, 37), + Qt::UTC)) + << true << "Last-Modified" + << "Sunday, 06-Nov-94 08:49:37 GMT"; + QTest::newRow("Last-Modified-asctime") << QNetworkRequest::LastModifiedHeader + << QVariant(QDateTime(QDate(1994, 11, 06), + QTime(8, 49, 37), + Qt::UTC)) + << true << "Last-Modified" + << "Sun Nov 6 08:49:37 1994"; + + QTest::newRow("Content-Length-invalid1") << QNetworkRequest::ContentLengthHeader << QVariant() + << false << "Content-Length" << "1a"; + QTest::newRow("Content-Length-invalid2") << QNetworkRequest::ContentLengthHeader << QVariant() + << false << "Content-Length" << "a"; + + + QTest::newRow("Location-invalid1") << QNetworkRequest::LocationHeader << QVariant() << false + << "Location" << "abc"; + QTest::newRow("Location-invalid2") << QNetworkRequest::LocationHeader << QVariant() << false + << "Location" << "1http://foo"; + QTest::newRow("Location-invalid3") << QNetworkRequest::LocationHeader << QVariant() << false + << "Location" << "http://foo/%gg"; + + // don't test for invalid dates because we may want to support broken servers in the future + + QNetworkCookie cookie; + cookie.setName("a"); + cookie.setValue("b"); + QTest::newRow("Cookie-1") << QNetworkRequest::CookieHeader + << qVariantFromValue(QList<QNetworkCookie>() << cookie) + << true << "Cookie" + << "a=b"; + QTest::newRow("SetCookie-1") << QNetworkRequest::SetCookieHeader + << qVariantFromValue(QList<QNetworkCookie>() << cookie) + << true << "Set-Cookie" + << "a=b"; + + cookie.setPath("/"); + QTest::newRow("SetCookie-2") << QNetworkRequest::SetCookieHeader + << qVariantFromValue(QList<QNetworkCookie>() << cookie) + << true << "Set-Cookie" + << "a=b; path=/"; + + QNetworkCookie cookie2; + cookie.setPath(""); + cookie2.setName("c"); + cookie2.setValue("d"); + QTest::newRow("Cookie-3") << QNetworkRequest::CookieHeader + << qVariantFromValue(QList<QNetworkCookie>() << cookie << cookie2) + << true << "Cookie" + << "a=b; c=d"; + cookie.setPath("/"); + QTest::newRow("SetCookie-3") << QNetworkRequest::SetCookieHeader + << qVariantFromValue(QList<QNetworkCookie>() << cookie << cookie2) + << true << "Set-Cookie" + << "a=b; path=/, c=d"; +} + +void tst_QNetworkRequest::rawHeaderParsing() +{ + QFETCH(QNetworkRequest::KnownHeaders, cookedHeader); + QFETCH(QVariant, cookedValue); + QFETCH(bool, success); + QFETCH(QString, rawHeader); + QFETCH(QString, rawValue); + + QNetworkRequest request; + request.setRawHeader(rawHeader.toLatin1(), rawValue.toLatin1()); + + // even if it doesn't parse, it's as a raw header + QVERIFY(request.hasRawHeader(rawHeader.toLatin1())); + QVERIFY(request.hasRawHeader(rawHeader.toLower().toLatin1())); + QCOMPARE(QString(request.rawHeader(rawHeader.toLatin1())), rawValue); + + QCOMPARE(request.header(cookedHeader).isNull(), !success); + if (cookedValue.type() != QVariant::UserType) + QCOMPARE(request.header(cookedHeader), cookedValue); + else if (cookedValue.userType() == qMetaTypeId<QList<QNetworkCookie> >()) + QCOMPARE(qvariant_cast<QList<QNetworkCookie> >(request.header(cookedHeader)), + qvariant_cast<QList<QNetworkCookie> >(cookedValue)); +} + +void tst_QNetworkRequest::removeHeader() +{ + QNetworkRequest request; + + request.setRawHeader("Foo", "1"); + QVERIFY(request.hasRawHeader("Foo")); + QVERIFY(request.hasRawHeader("foo")); + request.setRawHeader("Foo", QByteArray()); + QVERIFY(!request.hasRawHeader("Foo")); + + // same, but remove with different capitalisation + request.setRawHeader("Foo", "1"); + QVERIFY(request.hasRawHeader("Foo")); + QVERIFY(request.hasRawHeader("foo")); + request.setRawHeader("foo", QByteArray()); + QVERIFY(!request.hasRawHeader("Foo")); + + // same, but not the first + request.setRawHeader("Bar", "2"); + request.setRawHeader("Foo", "1"); + QVERIFY(request.hasRawHeader("Foo")); + QVERIFY(request.hasRawHeader("foo")); + request.setRawHeader("foo", QByteArray()); + QVERIFY(!request.hasRawHeader("Foo")); + QVERIFY(request.hasRawHeader("bar")); + + // same, but not the first nor last + request.setRawHeader("Foo", "1"); + request.setRawHeader("Bar", "3"); + QVERIFY(request.hasRawHeader("Foo")); + QVERIFY(request.hasRawHeader("foo")); + request.setRawHeader("foo", QByteArray()); + QVERIFY(!request.hasRawHeader("Foo")); + QVERIFY(request.hasRawHeader("bar")); +} + +void tst_QNetworkRequest::originatingObject() +{ + QNetworkRequest request; + + QVERIFY(!request.originatingObject()); + + { + QObject dummy; + request.setOriginatingObject(&dummy); + QCOMPARE(request.originatingObject(), &dummy); + } + + QVERIFY(!request.originatingObject()); +} + +QTEST_MAIN(tst_QNetworkRequest) +#include "tst_qnetworkrequest.moc" |