BPackageInfo::Parser: Validate URL strings.

Fixes #12710.

Signed-off-by: Augustin Cavalier <waddlesplash@gmail.com>
I fixed the modifications to the Jamfiles in src/bin, they were all wrong
in the patch.
This commit is contained in:
Andrew Lindesay 2016-04-09 18:49:29 +12:00 committed by Augustin Cavalier
parent a4f86e7f78
commit fa2dd9c45f
18 changed files with 502 additions and 56 deletions

View File

@ -496,8 +496,8 @@ if $(HOST_PLATFORM_BEOS_COMPATIBLE) {
HOST_LIBROOT += /usr/lib/libgnuregex.so ;
HOST_STATIC_LIBROOT += /usr/lib/libgnuregex.so ;
} else if $(HOST_PLATFORM) = darwin {
HOST_LIBROOT += libgnuregex_build.a ;
HOST_STATIC_LIBROOT += libgnuregex_build.a ;
HOST_LIBROOT += libgnuregex_build.so ;
HOST_STATIC_LIBROOT += libgnuregex_build.so ;
}
# The BeOS compilers define __INTEL__ respectively __POWERPC__. On the

View File

@ -0,0 +1,12 @@
# libgnuregex
This library exists because some systems don't have a flavor of regex library
built-in which supports groups. This variant does include group-support. An
example of where this comes into play is with the `BUrl` class where URLs are
parsed, in part, using regular expressions.
## Use with MacOS-X
In the case of MacOS-X, the dynamic-library build product
`libgnuregex_build.so` can be configured for use by configuring the
`DYLD_INSERT_LIBRARIES` environment variable.

View File

@ -1,5 +1,5 @@
/*
* Copyright 2010 Haiku Inc. All rights reserved.
* Copyright 2010-2016 Haiku Inc. All rights reserved.
* Distributed under the terms of the MIT License.
*/
#ifndef _B_URL_H_
@ -33,7 +33,7 @@ public:
BUrl& SetPath(const BString& path);
BUrl& SetRequest(const BString& request);
BUrl& SetFragment(const BString& fragment);
// URL fields access
const BString& UrlString() const;
const BString& Protocol() const;
@ -46,7 +46,7 @@ public:
const BString& Path() const;
const BString& Request() const;
const BString& Fragment() const;
// URL fields tests
bool IsValid() const;
bool HasProtocol() const;
@ -64,21 +64,25 @@ public:
void UrlEncode(bool strict = false);
void UrlDecode(bool strict = false);
#ifdef HAIKU_TARGET_PLATFORM_HAIKU
status_t IDNAToAscii();
status_t IDNAToUnicode();
#endif
// Url encoding/decoding of strings
static BString UrlEncode(const BString& url,
bool strict = false,
static BString UrlEncode(const BString& url,
bool strict = false,
bool directory = false);
static BString UrlDecode(const BString& url,
static BString UrlDecode(const BString& url,
bool strict = false);
#ifdef HAIKU_TARGET_PLATFORM_HAIKU
// utility functionality
bool HasPreferredApplication() const;
BString PreferredApplication() const;
status_t OpenWithPreferredApplication(
bool onProblemAskUser = true) const;
#endif
// BArchivable members
virtual status_t Archive(BMessage* into,
@ -93,19 +97,20 @@ public:
const BUrl& operator=(const BUrl& other);
const BUrl& operator=(const BString& string);
const BUrl& operator=(const char* string);
// URL to string conversion
operator const char*() const;
private:
void _ResetFields();
bool _ContainsDelimiter(const BString& url);
void _ExplodeUrlString(const BString& urlString);
BString _MergePath(const BString& relative) const;
void _SetPathUnsafe(const BString& path);
static BString _DoUrlEncodeChunk(const BString& chunk,
static BString _DoUrlEncodeChunk(const BString& chunk,
bool strict, bool directory = false);
static BString _DoUrlDecodeChunk(const BString& chunk,
static BString _DoUrlDecodeChunk(const BString& chunk,
bool strict);
bool _IsProtocolValid();
@ -128,7 +133,7 @@ private:
BString fPath;
BString fRequest;
BString fFragment;
mutable bool fUrlStringValid : 1;
mutable bool fAuthorityValid : 1;
mutable bool fUserInfoValid : 1;

View File

@ -134,7 +134,7 @@ StdBinCommands
ramdisk.cpp
: shared be [ TargetLibsupc++ ] : $(haiku-utils_rsrc) ;
# standard commands that need libbe.so, libbnetapi.solibsupc++.so
# standard commands that need libbe.so, libbnetapi.so, libsupc++.so
StdBinCommands
open.cpp
urlwrapper.cpp

View File

@ -15,6 +15,6 @@ BinCommand package :
PackageWriterListener.cpp
PackageWritingUtils.cpp
:
package be
package be bnetapi
[ TargetLibsupc++ ]
;

View File

@ -11,14 +11,18 @@ BuildPlatformSharedLibrary libbe_build.so :
<libbe_build>app_kit.o
<libbe_build>icon_kit.o
<libbe_build>interface_kit.o
<libbe_build>network_kit.o
<libbe_build>storage_kit.o
<libbe_build>support_kit.o
libshared_build.a
z $(HOST_LIBSUPC++) $(HOST_LIBSTDC++)
;
SubInclude HAIKU_TOP src build libbe app ;
SubInclude HAIKU_TOP src build libbe icon ;
SubInclude HAIKU_TOP src build libbe interface ;
SubInclude HAIKU_TOP src build libbe network ;
SubInclude HAIKU_TOP src build libbe storage ;
SubInclude HAIKU_TOP src build libbe support ;

View File

@ -0,0 +1,15 @@
SubDir HAIKU_TOP src build libbe network;
UseHeaders [ FDirName $(HAIKU_TOP) headers build ] : true ;
UseHeaders [ FDirName $(HAIKU_TOP) headers os net ] : true ;
UseHeaders [ FDirName $(HAIKU_TOP) headers private shared ] : true ;
UsePrivateBuildHeaders app interface shared network ;
USES_BE_API on <libbe_build>network_kit.o = true ;
SEARCH_SOURCE += [ FDirName $(HAIKU_TOP) src kits network libnetapi ] ;
BuildPlatformMergeObjectPIC <libbe_build>network_kit.o :
Url.cpp
;

View File

@ -1,3 +1,7 @@
SubDir HAIKU_TOP src build libgnuregex ;
BuildPlatformStaticLibrary libgnuregex_build.a : regex.c ;
BuildPlatformSharedLibrary libgnuregex_build.so :
regex.c
:
# no linked libraries here
;

View File

@ -2,6 +2,8 @@ SubDir HAIKU_TOP src build libpackage ;
UsePrivateBuildHeaders kernel package shared storage support ;
UseHeaders [ FDirName $(HAIKU_TOP) headers os net ] : true ;
SEARCH_SOURCE += [ FDirName $(HAIKU_TOP) src kits package ] ;
SEARCH_SOURCE += [ FDirName $(HAIKU_TOP) src kits package hpkg ] ;
SEARCH_SOURCE += [ FDirName $(HAIKU_TOP) src kits package hpkg v1 ] ;

View File

@ -2,6 +2,8 @@ SubDir HAIKU_TOP src build libshared ;
USES_BE_API on libshared_build.a = true ;
UseHeaders [ FDirName $(HAIKU_TOP) headers private shared ] : true ;
UsePrivateBuildHeaders shared ;
SEARCH_SOURCE += [ FDirName $(HAIKU_TOP) src kits shared ] ;
@ -10,4 +12,9 @@ BuildPlatformStaticLibraryPIC libshared_build.a :
Keymap.cpp
NaturalCompare.cpp
SHA256.cpp
RegExp.cpp
:
# no shared libs, but will require 'libgnuregex' dynamic library on Darwin
;

View File

@ -1,9 +1,10 @@
/*
* Copyright 2010 Haiku Inc. All rights reserved.
* Copyright 2010-2016 Haiku Inc. All rights reserved.
* Distributed under the terms of the MIT License.
*
* Authors:
* Christophe Huriaux, c.huriaux@gmail.com
* Andrew Lindesay, apl@lindesay.co.nz
*/
@ -17,11 +18,15 @@
#include <MimeType.h>
#include <Roster.h>
#include <ICUWrapper.h>
#ifdef HAIKU_TARGET_PLATFORM_HAIKU
#include <ICUWrapper.h>
#endif
#include <RegExp.h>
#include <unicode/idna.h>
#include <unicode/stringpiece.h>
#ifdef HAIKU_TARGET_PLATFORM_HAIKU
#include <unicode/idna.h>
#include <unicode/stringpiece.h>
#endif
static const char* kArchivedUrl = "be:url string";
@ -498,8 +503,14 @@ BUrl::Fragment() const
bool
BUrl::IsValid() const
{
if (!fHasProtocol)
return false;
if (fProtocol == "http" || fProtocol == "https" || fProtocol == "ftp")
return fHasHost;
// TODO: Implement for real!
return fHasProtocol && (fHasHost || fHasPath);
return fHasHost || fHasPath;
}
@ -598,6 +609,7 @@ BUrl::UrlDecode(bool strict)
}
#ifdef HAIKU_TARGET_PLATFORM_HAIKU
status_t
BUrl::IDNAToAscii()
{
@ -618,8 +630,10 @@ BUrl::IDNAToAscii()
fHost = result;
return B_OK;
}
#endif
#ifdef HAIKU_TARGET_PLATFORM_HAIKU
status_t
BUrl::IDNAToUnicode()
{
@ -640,11 +654,13 @@ BUrl::IDNAToUnicode()
fHost = result;
return B_OK;
}
#endif
// #pragma mark - utility functionality
#ifdef HAIKU_TARGET_PLATFORM_HAIKU
bool
BUrl::HasPreferredApplication() const
{
@ -657,8 +673,10 @@ BUrl::HasPreferredApplication() const
return false;
}
#endif
#ifdef HAIKU_TARGET_PLATFORM_HAIKU
BString
BUrl::PreferredApplication() const
{
@ -669,8 +687,10 @@ BUrl::PreferredApplication() const
return BString(appSignature);
}
#endif
#ifdef HAIKU_TARGET_PLATFORM_HAIKU
status_t
BUrl::OpenWithPreferredApplication(bool onProblemAskUser) const
{
@ -710,6 +730,7 @@ BUrl::OpenWithPreferredApplication(bool onProblemAskUser) const
return status;
}
#endif
// #pragma mark Url encoding/decoding of string
@ -866,6 +887,28 @@ BUrl::_ResetFields()
}
bool
BUrl::_ContainsDelimiter(const BString& url)
{
int32 len = url.Length();
for (int32 i = 0; i < len; i++) {
switch (url[i]) {
case ' ':
case '\n':
case '\t':
case '\r':
case '<':
case '>':
case '"':
return true;
}
}
return false;
}
void
BUrl::_ExplodeUrlString(const BString& url)
{
@ -875,6 +918,11 @@ BUrl::_ExplodeUrlString(const BString& url)
_ResetFields();
// RFC3986, Appendix C; the URL should not contain whitespace or delimiters
// by this point.
if (_ContainsDelimiter(url))
return; // TODO error handing
RegExp::MatchResult match = urlMatcher.Match(url.String());
if (!match.HasMatched())
@ -883,6 +931,7 @@ BUrl::_ExplodeUrlString(const BString& url)
// Scheme/Protocol
url.CopyInto(fProtocol, match.GroupStartOffsetAt(1),
match.GroupEndOffsetAt(1) - match.GroupStartOffsetAt(1));
if (!_IsProtocolValid()) {
fHasProtocol = false;
fProtocol.Truncate(0);
@ -981,6 +1030,7 @@ BUrl::SetAuthority(const BString& authority)
return;
int32 userInfoEnd = fAuthority.FindFirst('@');
int16 hostAndPortStart = 0;
// URL contains userinfo field
if (userInfoEnd != -1) {
@ -1000,39 +1050,23 @@ BUrl::SetAuthority(const BString& authority)
} else {
SetUserName(fUser);
}
hostAndPortStart = userInfoEnd + 1;
}
int16 hostEnd = fAuthority.FindFirst(':', hostAndPortStart);
// Extract the host part
int16 hostEnd = fAuthority.FindFirst(':', userInfoEnd);
userInfoEnd++;
if (hostEnd < 0) {
// no ':' found, the host extends to the end of the URL
hostEnd = fAuthority.Length() + 1;
if (hostEnd != B_ERROR) {
if (hostEnd < fAuthority.Length()-1) {
fPort = atoi(&(fAuthority.String())[hostEnd+1]);
fHasPort = true;
}
}
else
hostEnd = fAuthority.Length();
// The host is likely to be present if an authority is
// defined, but in some weird cases, it's not.
if (hostEnd != userInfoEnd) {
fAuthority.CopyInto(fHost, userInfoEnd, hostEnd - userInfoEnd);
SetHost(fHost);
}
// Extract the port part
fPort = 0;
if (fAuthority.ByteAt(hostEnd) == ':') {
hostEnd++;
int16 portEnd = fAuthority.Length();
BString portString;
fAuthority.CopyInto(portString, hostEnd, portEnd - hostEnd);
fPort = atoi(portString.String());
// Even if the port is invalid, the URL is considered to
// have a port.
fHasPort = portString.Length() > 0;
}
fAuthority.CopyInto(fHost, hostAndPortStart, hostEnd - hostAndPortStart);
SetHost(fHost);
}
@ -1088,7 +1122,7 @@ BUrl::_DoUrlDecodeChunk(const BString& chunk, bool strict)
result << decoded;
} else
result << chunk[i];
}
}
}
return result;
}

View File

@ -129,9 +129,11 @@ for architectureObject in [ MultiArchSubDirSetup ] {
SolverResult.cpp
:
shared
bnetapi
be
[ BuildFeatureAttribute curl : library ]
[ TargetLibstdc++ ]
$(TARGET_NETWORK_LIBS)
;
}
}

View File

@ -1,5 +1,6 @@
/*
* Copyright 2011, Oliver Tappe <zooey@hirschkaefer.de>
* Copyright 2016, Andrew Lindesay <apl@lindesay.co.nz>
* Distributed under the terms of the MIT License.
*/
@ -13,6 +14,7 @@
#include <algorithm>
#include <string>
#include <Url.h>
namespace BPackageKit {
@ -508,19 +510,22 @@ BPackageInfo::Parser::_ParseList(ListElementParser& elementParser,
void
BPackageInfo::Parser::_ParseStringList(BStringList* value,
bool requireResolvableName, bool convertToLowerCase)
bool requireResolvableName, bool convertToLowerCase,
StringValidator* stringValidator)
{
struct StringParser : public ListElementParser {
BStringList* value;
bool requireResolvableName;
bool convertToLowerCase;
StringValidator* stringValidator;
StringParser(BStringList* value, bool requireResolvableName,
bool convertToLowerCase)
bool convertToLowerCase, StringValidator* stringValidator)
:
value(value),
requireResolvableName(requireResolvableName),
convertToLowerCase(convertToLowerCase)
convertToLowerCase(convertToLowerCase),
stringValidator(stringValidator)
{
}
@ -541,9 +546,13 @@ BPackageInfo::Parser::_ParseStringList(BStringList* value,
if (convertToLowerCase)
element.ToLower();
if (stringValidator != NULL)
stringValidator->Validate(element, token.pos);
value->Add(element);
}
} stringParser(value, requireResolvableName, convertToLowerCase);
} stringParser(value, requireResolvableName, convertToLowerCase,
stringValidator);
_ParseList(stringParser, true);
}
@ -1008,11 +1017,19 @@ BPackageInfo::Parser::_Parse(BPackageInfo* packageInfo)
break;
case B_PACKAGE_INFO_URLS:
_ParseStringList(&packageInfo->fURLList);
{
UrlStringValidator stringValidator;
_ParseStringList(&packageInfo->fURLList,
false, false, &stringValidator);
}
break;
case B_PACKAGE_INFO_SOURCE_URLS:
_ParseStringList(&packageInfo->fSourceURLList);
{
UrlStringValidator stringValidator;
_ParseStringList(&packageInfo->fSourceURLList,
false, false, &stringValidator);
}
break;
case B_PACKAGE_INFO_GLOBAL_WRITABLE_FILES:
@ -1145,5 +1162,15 @@ BPackageInfo::Parser::_IsValidResolvableName(const char* string,
return true;
}
void
BPackageInfo::Parser::UrlStringValidator::Validate(const BString& urlString,
const char* pos)
{
BUrl url(urlString);
if (!url.IsValid())
throw ParseError("invalid url", pos);
}
} // namespace BPackageKit

View File

@ -1,5 +1,6 @@
/*
* Copyright 2011, Oliver Tappe <zooey@hirschkaefer.de>
* Copyright 2016, Andrew Lindesay <apl@lindesay.co.nz>
* Distributed under the terms of the MIT License.
*/
#ifndef PACKAGE_INFO_PARSER_H
@ -31,6 +32,8 @@ public:
BPackageResolvableExpression& _expression);
private:
struct UrlStringValidator;
struct StringValidator;
struct ParseError;
struct Token;
struct ListElementParser;
@ -74,7 +77,8 @@ private:
bool allowSingleNonListElement);
void _ParseStringList(BStringList* value,
bool requireResolvableName = false,
bool convertToLowerCase = false);
bool convertToLowerCase = false,
StringValidator* stringValidator = NULL);
void _ParseResolvableList(
BObjectList<BPackageResolvable>* value);
void _ParseResolvableExprList(
@ -152,6 +156,19 @@ struct BPackageInfo::Parser::ListElementParser {
};
struct BPackageInfo::Parser::StringValidator {
public:
virtual void Validate(const BString &string, const char *pos) = 0;
};
struct BPackageInfo::Parser::UrlStringValidator
: public BPackageInfo::Parser::StringValidator {
public:
virtual void Validate(const BString &string, const char* pos);
};
} // namespace BPackageKit

View File

@ -5,6 +5,7 @@ UnitTestLib libnetapitest.so :
NetworkAddressTest.cpp
NetworkInterfaceTest.cpp
NetworkUrlTest.cpp
: be bnetapi network [ TargetLibstdc++ ] [ TargetLibsupc++ ]
;

View File

@ -9,6 +9,7 @@
#include "NetworkAddressTest.h"
#include "NetworkInterfaceTest.h"
#include "NetworkUrlTest.h"
BTestSuite*
@ -18,6 +19,7 @@ getTestSuite()
NetworkAddressTest::AddTests(*suite);
NetworkInterfaceTest::AddTests(*suite);
NetworkUrlTest::AddTests(*suite);
return suite;
}

View File

@ -0,0 +1,272 @@
/*
* Copyright 2016, Andrew Lindesay, apl@lindesay.co.nz.
* Distributed under the terms of the MIT License.
*/
#include "NetworkUrlTest.h"
#include <Url.h>
#include <cppunit/TestCaller.h>
#include <cppunit/TestSuite.h>
NetworkUrlTest::NetworkUrlTest()
{
}
NetworkUrlTest::~NetworkUrlTest()
{
}
void
NetworkUrlTest::setUp()
{
}
void
NetworkUrlTest::tearDown()
{
}
// General Tests ---------------------------------------------------------------
/*
This is the "happy days" tests that checks that a URL featuring all of the
parsed elements successfully processes and the elements are present.
*/
void NetworkUrlTest::TestValidFullUrl()
{
BUrl url("http://ewe:pea@www.something.co.nz:8888/some/path?key1=value1#fragment");
CPPUNIT_ASSERT(url.IsValid());
CPPUNIT_ASSERT(url.Protocol() == "http");
CPPUNIT_ASSERT(url.HasProtocol());
CPPUNIT_ASSERT(url.UserName() == "ewe");
CPPUNIT_ASSERT(url.HasUserName());
CPPUNIT_ASSERT(url.Password() == "pea");
CPPUNIT_ASSERT(url.HasPassword());
CPPUNIT_ASSERT(url.Host() == "www.something.co.nz");
CPPUNIT_ASSERT(url.HasHost());
CPPUNIT_ASSERT(url.Port() == 8888);
CPPUNIT_ASSERT(url.HasPort());
CPPUNIT_ASSERT(url.Path() == "/some/path");
CPPUNIT_ASSERT(url.HasPath());
CPPUNIT_ASSERT(url.Request() == "key1=value1");
CPPUNIT_ASSERT(url.HasRequest());
CPPUNIT_ASSERT(url.Fragment() == "fragment");
CPPUNIT_ASSERT(url.HasFragment());
}
void NetworkUrlTest::TestFileUrl()
{
BUrl url("file:///northisland/wellington/brooklyn/windturbine");
CPPUNIT_ASSERT(url.IsValid());
CPPUNIT_ASSERT(url.Protocol() == "file");
CPPUNIT_ASSERT(url.HasProtocol());
CPPUNIT_ASSERT(!url.HasUserName());
CPPUNIT_ASSERT(!url.HasPassword());
CPPUNIT_ASSERT(url.Host() == "");
CPPUNIT_ASSERT(url.HasHost());
CPPUNIT_ASSERT(!url.HasPort());
CPPUNIT_ASSERT(url.Path() == "/northisland/wellington/brooklyn/windturbine");
CPPUNIT_ASSERT(url.HasPath());
CPPUNIT_ASSERT(!url.HasRequest());
CPPUNIT_ASSERT(!url.HasFragment());
}
// Authority Tests (UserName, Password, Host, Port) ----------------------------
void NetworkUrlTest::TestWithUserNameAndPasswordNoHostAndPort()
{
BUrl url("wierd://tea:tree@/x");
CPPUNIT_ASSERT(url.IsValid());
CPPUNIT_ASSERT(url.Protocol() == "wierd");
CPPUNIT_ASSERT(url.HasProtocol());
CPPUNIT_ASSERT(url.UserName() == "tea");
CPPUNIT_ASSERT(url.HasUserName());
CPPUNIT_ASSERT(url.Password() == "tree");
CPPUNIT_ASSERT(url.HasPassword());
CPPUNIT_ASSERT(url.Host() == "");
CPPUNIT_ASSERT(!url.HasHost());
CPPUNIT_ASSERT(!url.HasPort());
CPPUNIT_ASSERT(url.Path() == "/x");
CPPUNIT_ASSERT(url.HasPath());
CPPUNIT_ASSERT(!url.HasRequest());
CPPUNIT_ASSERT(!url.HasFragment());
}
void NetworkUrlTest::TestHostAndPortWithNoUserNameAndPassword()
{
BUrl url("https://www.something.co.nz:443/z");
CPPUNIT_ASSERT(url.IsValid());
CPPUNIT_ASSERT(url.Protocol() == "https");
CPPUNIT_ASSERT(url.HasProtocol());
CPPUNIT_ASSERT(!url.HasUserName());
CPPUNIT_ASSERT(!url.HasPassword());
CPPUNIT_ASSERT(url.Port() == 443);
CPPUNIT_ASSERT(url.HasPort());
CPPUNIT_ASSERT(url.Host() == "www.something.co.nz");
CPPUNIT_ASSERT(url.HasHost());
CPPUNIT_ASSERT(url.Path() == "/z");
CPPUNIT_ASSERT(url.HasPath());
CPPUNIT_ASSERT(!url.HasRequest());
CPPUNIT_ASSERT(!url.HasFragment());
}
void NetworkUrlTest::TestHostWithNoPortOrUserNameAndPassword()
{
BUrl url("https://www.something.co.nz/z");
CPPUNIT_ASSERT(url.IsValid());
CPPUNIT_ASSERT(url.Protocol() == "https");
CPPUNIT_ASSERT(url.HasProtocol());
CPPUNIT_ASSERT(!url.HasUserName());
CPPUNIT_ASSERT(!url.HasPassword());
CPPUNIT_ASSERT(url.Host() == "www.something.co.nz");
CPPUNIT_ASSERT(url.HasHost());
CPPUNIT_ASSERT(!url.HasPort());
CPPUNIT_ASSERT(url.Path() == "/z");
CPPUNIT_ASSERT(url.HasPath());
CPPUNIT_ASSERT(!url.HasRequest());
CPPUNIT_ASSERT(!url.HasFragment());
}
void NetworkUrlTest::TestHostWithNoPortNoPath()
{
BUrl url("https://www.something.co.nz");
CPPUNIT_ASSERT(url.IsValid());
CPPUNIT_ASSERT(url.Protocol() == "https");
CPPUNIT_ASSERT(url.HasProtocol());
CPPUNIT_ASSERT(!url.HasUserName());
CPPUNIT_ASSERT(!url.HasPassword());
CPPUNIT_ASSERT(url.Host() == "www.something.co.nz");
CPPUNIT_ASSERT(url.HasHost());
CPPUNIT_ASSERT(!url.HasPort());
CPPUNIT_ASSERT(!url.HasPath());
CPPUNIT_ASSERT(!url.HasRequest());
CPPUNIT_ASSERT(!url.HasFragment());
}
void NetworkUrlTest::TestHostWithPortNoPath()
{
BUrl url("https://www.something.co.nz:1234");
CPPUNIT_ASSERT(url.IsValid());
CPPUNIT_ASSERT(url.Protocol() == "https");
CPPUNIT_ASSERT(url.HasProtocol());
CPPUNIT_ASSERT(!url.HasUserName());
CPPUNIT_ASSERT(!url.HasPassword());
CPPUNIT_ASSERT(url.Host() == "www.something.co.nz");
CPPUNIT_ASSERT(url.HasHost());
CPPUNIT_ASSERT(url.Port() == 1234);
CPPUNIT_ASSERT(url.HasPort());
CPPUNIT_ASSERT(!url.HasPath());
CPPUNIT_ASSERT(!url.HasRequest());
CPPUNIT_ASSERT(!url.HasFragment());
}
void NetworkUrlTest::TestHostWithEmptyPort()
{
BUrl url("https://www.something.co.nz:");
CPPUNIT_ASSERT(url.IsValid());
CPPUNIT_ASSERT(url.Protocol() == "https");
CPPUNIT_ASSERT(url.HasProtocol());
CPPUNIT_ASSERT(!url.HasUserName());
CPPUNIT_ASSERT(!url.HasPassword());
CPPUNIT_ASSERT(url.Host() == "www.something.co.nz");
CPPUNIT_ASSERT(url.HasHost());
CPPUNIT_ASSERT(!url.HasPort());
CPPUNIT_ASSERT(!url.HasPath());
CPPUNIT_ASSERT(!url.HasRequest());
CPPUNIT_ASSERT(!url.HasFragment());
}
// Invalid Forms ---------------------------------------------------------------
void NetworkUrlTest::TestWhitespaceBefore()
{
BUrl url(" https://www.something.co.nz/z");
CPPUNIT_ASSERT(!url.IsValid());
}
void NetworkUrlTest::TestWhitespaceAfter()
{
BUrl url("https://www.something.co.nz/z\t\t ");
CPPUNIT_ASSERT(!url.IsValid());
}
void NetworkUrlTest::TestWhitespaceMiddle()
{
BUrl url("https://www. something.co.nz/z");
CPPUNIT_ASSERT(!url.IsValid());
}
void NetworkUrlTest::TestHttpNoHost()
{
BUrl url("https:///z");
CPPUNIT_ASSERT(!url.IsValid());
}
// Control ---------------------------------------------------------------------
/*static*/ void
NetworkUrlTest::AddTests(BTestSuite& parent)
{
CppUnit::TestSuite& suite = *new CppUnit::TestSuite("NetworkUrlTest");
suite.addTest(new CppUnit::TestCaller<NetworkUrlTest>(
"NetworkUrlTest::TestHostAndPortWithNoUserNameAndPassword",
&NetworkUrlTest::TestHostAndPortWithNoUserNameAndPassword));
suite.addTest(new CppUnit::TestCaller<NetworkUrlTest>(
"NetworkUrlTest::TestWithUserNameAndPasswordNoHostAndPort",
&NetworkUrlTest::TestWithUserNameAndPasswordNoHostAndPort));
suite.addTest(new CppUnit::TestCaller<NetworkUrlTest>(
"NetworkUrlTest::TestHostWithNoPortOrUserNameAndPassword",
&NetworkUrlTest::TestHostWithNoPortOrUserNameAndPassword));
suite.addTest(new CppUnit::TestCaller<NetworkUrlTest>(
"NetworkUrlTest::TestHostWithNoPortNoPath",
&NetworkUrlTest::TestHostWithNoPortNoPath));
suite.addTest(new CppUnit::TestCaller<NetworkUrlTest>(
"NetworkUrlTest::TestHostWithPortNoPath",
&NetworkUrlTest::TestHostWithPortNoPath));
suite.addTest(new CppUnit::TestCaller<NetworkUrlTest>(
"NetworkUrlTest::TestHostWithEmptyPort",
&NetworkUrlTest::TestHostWithEmptyPort));
suite.addTest(new CppUnit::TestCaller<NetworkUrlTest>(
"NetworkUrlTest::TestWhitespaceBefore",
&NetworkUrlTest::TestWhitespaceBefore));
suite.addTest(new CppUnit::TestCaller<NetworkUrlTest>(
"NetworkUrlTest::TestWhitespaceAfter",
&NetworkUrlTest::TestWhitespaceAfter));
suite.addTest(new CppUnit::TestCaller<NetworkUrlTest>(
"NetworkUrlTest::TestWhitespaceMiddle",
&NetworkUrlTest::TestWhitespaceMiddle));
suite.addTest(new CppUnit::TestCaller<NetworkUrlTest>(
"NetworkUrlTest::TestFileUrl",
&NetworkUrlTest::TestFileUrl));
suite.addTest(new CppUnit::TestCaller<NetworkUrlTest>(
"NetworkUrlTest::TestValidFullUrl", &NetworkUrlTest::TestValidFullUrl));
parent.addTest("NetworkUrlTest", &suite);
}

View File

@ -0,0 +1,42 @@
/*
* Copyright 2016, Andrew Lindesay, apl@lindesay.co.nz
* Distributed under the terms of the MIT License.
*/
#ifndef NETWORK_URL_TEST_H
#define NETWORK_URL_TEST_H
#include <TestCase.h>
#include <TestSuite.h>
class NetworkUrlTest : public CppUnit::TestCase {
public:
NetworkUrlTest();
virtual ~NetworkUrlTest();
virtual void setUp();
virtual void tearDown();
void TestValidFullUrl();
void TestFileUrl();
void TestWithUserNameAndPasswordNoHostAndPort();
void TestHostAndPortWithNoUserNameAndPassword();
void TestHostWithNoPortOrUserNameAndPassword();
void TestHostWithNoPortNoPath();
void TestHostWithPortNoPath();
void TestHostWithEmptyPort();
void TestWhitespaceBefore();
void TestWhitespaceAfter();
void TestWhitespaceMiddle();
void TestHttpNoHost();
static void AddTests(BTestSuite& suite);
};
#endif // NETWORK_URL_TEST_H