Ticket #12710: 0001-BPackageInfo-Parser-Validate-URL-strings-10jun2016-1855.patch

File 0001-BPackageInfo-Parser-Validate-URL-strings-10jun2016-1855.patch, 29.2 KB (added by apl-haiku, 8 years ago)
  • .gitignore

    From 1491967525418d362bf19fc20747afde468ea183 Mon Sep 17 00:00:00 2001
    From: Andrew Lindesay <apl@lindesay.co.nz>
    Date: Sat, 9 Apr 2016 18:49:29 +1200
    Subject: [PATCH] BPackageInfo::Parser: Validate URL strings.
    
    ---
     .gitignore                                       |   3 +
     build/jam/BuildSetup                             |   4 +-
     docs/develop/build/libgnuregex.md                |  12 +
     headers/os/net/Url.h                             |  25 ++-
     src/bin/Jamfile                                  |   7 +-
     src/build/libbe/Jamfile                          |   4 +
     src/build/libbe/network/Jamfile                  |  15 ++
     src/build/libgnuregex/Jamfile                    |   6 +-
     src/build/libpackage/Jamfile                     |   2 +
     src/build/libshared/Jamfile                      |   7 +
     src/kits/network/libnetapi/Url.cpp               | 102 ++++++---
     src/kits/package/Jamfile                         |   2 +
     src/kits/package/PackageInfoParser.cpp           |  39 +++-
     src/kits/package/PackageInfoParser.h             |  19 +-
     src/tests/kits/net/libnetapi/Jamfile             |   1 +
     src/tests/kits/net/libnetapi/NetAPITestAddon.cpp |   2 +
     src/tests/kits/net/libnetapi/NetworkUrlTest.cpp  | 272 +++++++++++++++++++++++
     src/tests/kits/net/libnetapi/NetworkUrlTest.h    |  42 ++++
     18 files changed, 509 insertions(+), 55 deletions(-)
     create mode 100644 docs/develop/build/libgnuregex.md
     create mode 100644 src/build/libbe/network/Jamfile
     create mode 100644 src/tests/kits/net/libnetapi/NetworkUrlTest.cpp
     create mode 100644 src/tests/kits/net/libnetapi/NetworkUrlTest.h
    
    diff --git a/.gitignore b/.gitignore
    index 9e9420d..96542f4 100644
    a b conf.sh  
    1212# compiled/optimized Python
    1313*.pyc
    1414*.pyo
     15
     16# MacOS-X directory attributes
     17.DS_Store
  • build/jam/BuildSetup

    diff --git a/build/jam/BuildSetup b/build/jam/BuildSetup
    index d13922a..801c27f 100644
    a b if $(HOST_PLATFORM_BEOS_COMPATIBLE) {  
    496496        HOST_LIBROOT += /usr/lib/libgnuregex.so ;
    497497        HOST_STATIC_LIBROOT += /usr/lib/libgnuregex.so ;
    498498    } else if $(HOST_PLATFORM) = darwin {
    499         HOST_LIBROOT += libgnuregex_build.a ;
    500         HOST_STATIC_LIBROOT += libgnuregex_build.a ;
     499        HOST_LIBROOT += libgnuregex_build.so ;
     500        HOST_STATIC_LIBROOT += libgnuregex_build.so ;
    501501    }
    502502
    503503    # The BeOS compilers define __INTEL__ respectively __POWERPC__. On the
  • new file docs/develop/build/libgnuregex.md

    diff --git a/docs/develop/build/libgnuregex.md b/docs/develop/build/libgnuregex.md
    new file mode 100644
    index 0000000..7dadd29
    - +  
     1# libgnuregex
     2
     3This library exists because some systems don't have a flavor of regex library
     4built-in which supports groups.  This variant does include group-support.  An
     5example of where this comes into play is with the `BUrl` class where URLs are
     6parsed, in part, using regular expressions.
     7
     8## Use with MacOS-X
     9
     10In the case of MacOS-X, the dynamic-library build product
     11`libgnuregex_build.so` can be configured for use by configuring the
     12`DYLD_INSERT_LIBRARIES` environment variable.
  • headers/os/net/Url.h

    diff --git a/headers/os/net/Url.h b/headers/os/net/Url.h
    index da241cc..560e08b 100644
    a b  
    11/*
    2  * Copyright 2010 Haiku Inc. All rights reserved.
     2 * Copyright 2010-2016 Haiku Inc. All rights reserved.
    33 * Distributed under the terms of the MIT License.
    44 */
    55#ifndef _B_URL_H_
    public:  
    3333            BUrl&               SetPath(const BString& path);
    3434            BUrl&               SetRequest(const BString& request);
    3535            BUrl&               SetFragment(const BString& fragment);
    36            
     36
    3737    // URL fields access
    3838            const BString&      UrlString() const;
    3939            const BString&      Protocol() const;
    public:  
    4646            const BString&      Path() const;
    4747            const BString&      Request() const;
    4848            const BString&      Fragment() const;
    49            
     49
    5050    // URL fields tests
    5151            bool                IsValid() const;
    5252            bool                HasProtocol() const;
    public:  
    6464            void                UrlEncode(bool strict = false);
    6565            void                UrlDecode(bool strict = false);
    6666
     67#ifdef HAIKU_TARGET_PLATFORM_HAIKU
    6768            status_t            IDNAToAscii();
    6869            status_t            IDNAToUnicode();
     70#endif
    6971
    7072    // Url encoding/decoding of strings
    71     static  BString             UrlEncode(const BString& url, 
    72                                     bool strict = false, 
     73    static  BString             UrlEncode(const BString& url,
     74                                    bool strict = false,
    7375                                    bool directory = false);
    74     static  BString             UrlDecode(const BString& url, 
     76    static  BString             UrlDecode(const BString& url,
    7577                                    bool strict = false);
    7678
     79#ifdef HAIKU_TARGET_PLATFORM_HAIKU
    7780    // utility functionality
    7881            bool                HasPreferredApplication() const;
    7982            BString             PreferredApplication() const;
    8083            status_t            OpenWithPreferredApplication(
    8184                                    bool onProblemAskUser = true) const;
     85#endif
    8286
    8387    // BArchivable members
    8488    virtual status_t            Archive(BMessage* into,
    public:  
    9397            const BUrl&         operator=(const BUrl& other);
    9498            const BUrl&         operator=(const BString& string);
    9599            const BUrl&         operator=(const char* string);
    96            
     100
    97101    // URL to string conversion
    98102                                operator const char*() const;
    99103
    100104private:
    101105            void                _ResetFields();
     106            bool                _ContainsDelimiter(const BString& url);
    102107            void                _ExplodeUrlString(const BString& urlString);
    103108            BString             _MergePath(const BString& relative) const;
    104109            void                _SetPathUnsafe(const BString& path);
    105110
    106     static  BString             _DoUrlEncodeChunk(const BString& chunk, 
     111    static  BString             _DoUrlEncodeChunk(const BString& chunk,
    107112                                    bool strict, bool directory = false);
    108     static  BString             _DoUrlDecodeChunk(const BString& chunk, 
     113    static  BString             _DoUrlDecodeChunk(const BString& chunk,
    109114                                    bool strict);
    110115
    111116            bool                _IsProtocolValid();
    private:  
    128133            BString             fPath;
    129134            BString             fRequest;
    130135            BString             fFragment;
    131            
     136
    132137    mutable bool                fUrlStringValid : 1;
    133138    mutable bool                fAuthorityValid : 1;
    134139    mutable bool                fUserInfoValid : 1;
  • src/bin/Jamfile

    diff --git a/src/bin/Jamfile b/src/bin/Jamfile
    index de947dc..8b20291 100644
    a b StdBinCommands  
    134134    ramdisk.cpp
    135135    : shared be [ TargetLibsupc++ ] : $(haiku-utils_rsrc) ;
    136136
    137 # standard commands that need libbe.so, libbnetapi.solibsupc++.so
     137# standard commands that need libbe.so, libbnetapi.so
     138StdBinCommands
     139    package.cpp
     140    : be bnetapi : $(haiku-utils_rsrc) ;
     141
     142# standard commands that need libbe.so, libbnetapi.so, libsupc++.so
    138143StdBinCommands
    139144    open.cpp
    140145    urlwrapper.cpp
  • src/build/libbe/Jamfile

    diff --git a/src/build/libbe/Jamfile b/src/build/libbe/Jamfile
    index 70f487e..0429a29 100644
    a b BuildPlatformSharedLibrary libbe_build.so :  
    1111    <libbe_build>app_kit.o
    1212    <libbe_build>icon_kit.o
    1313    <libbe_build>interface_kit.o
     14    <libbe_build>network_kit.o
    1415    <libbe_build>storage_kit.o
    1516    <libbe_build>support_kit.o
    1617
     18    libshared_build.a
     19
    1720    z $(HOST_LIBSUPC++) $(HOST_LIBSTDC++)
    1821;
    1922
    2023SubInclude HAIKU_TOP src build libbe app ;
    2124SubInclude HAIKU_TOP src build libbe icon ;
    2225SubInclude HAIKU_TOP src build libbe interface ;
     26SubInclude HAIKU_TOP src build libbe network ;
    2327SubInclude HAIKU_TOP src build libbe storage ;
    2428SubInclude HAIKU_TOP src build libbe support ;
  • new file src/build/libbe/network/Jamfile

    diff --git a/src/build/libbe/network/Jamfile b/src/build/libbe/network/Jamfile
    new file mode 100644
    index 0000000..c824cec
    - +  
     1SubDir HAIKU_TOP src build libbe network;
     2
     3UseHeaders [ FDirName $(HAIKU_TOP) headers build ] : true ;
     4UseHeaders [ FDirName $(HAIKU_TOP) headers os net ] : true ;
     5UseHeaders [ FDirName $(HAIKU_TOP) headers private shared ] : true ;
     6
     7UsePrivateBuildHeaders app interface shared network ;
     8
     9USES_BE_API on <libbe_build>network_kit.o = true ;
     10
     11SEARCH_SOURCE += [ FDirName $(HAIKU_TOP) src kits network libnetapi ] ;
     12
     13BuildPlatformMergeObjectPIC <libbe_build>network_kit.o :
     14    Url.cpp
     15;
  • src/build/libgnuregex/Jamfile

    diff --git a/src/build/libgnuregex/Jamfile b/src/build/libgnuregex/Jamfile
    index 6f3d05b..cfcc8ef 100644
    a b  
    11SubDir HAIKU_TOP src build libgnuregex ;
    22
    3 BuildPlatformStaticLibrary libgnuregex_build.a : regex.c ;
     3BuildPlatformSharedLibrary libgnuregex_build.so :
     4    regex.c
     5    :
     6    # no linked libraries here
     7;
  • src/build/libpackage/Jamfile

    diff --git a/src/build/libpackage/Jamfile b/src/build/libpackage/Jamfile
    index fa1b4e2..83cfa8b 100644
    a b SubDir HAIKU_TOP src build libpackage ;  
    22
    33UsePrivateBuildHeaders kernel package shared storage support ;
    44
     5UseHeaders [ FDirName $(HAIKU_TOP) headers os net ] : true ;
     6
    57SEARCH_SOURCE += [ FDirName $(HAIKU_TOP) src kits package ] ;
    68SEARCH_SOURCE += [ FDirName $(HAIKU_TOP) src kits package hpkg ] ;
    79SEARCH_SOURCE += [ FDirName $(HAIKU_TOP) src kits package hpkg v1 ] ;
  • src/build/libshared/Jamfile

    diff --git a/src/build/libshared/Jamfile b/src/build/libshared/Jamfile
    index 44984b7..3999b00 100644
    a b SubDir HAIKU_TOP src build libshared ;  
    22
    33USES_BE_API on libshared_build.a = true ;
    44
     5UseHeaders [ FDirName $(HAIKU_TOP) headers private shared ] : true ;
     6
    57UsePrivateBuildHeaders shared ;
    68
    79SEARCH_SOURCE += [ FDirName $(HAIKU_TOP) src kits shared ] ;
    BuildPlatformStaticLibraryPIC libshared_build.a :  
    1012    Keymap.cpp
    1113    NaturalCompare.cpp
    1214    SHA256.cpp
     15    RegExp.cpp
     16   
     17    :
     18   
     19    # no shared libs, but will require 'libgnuregex' dynamic library on Darwin
    1320;
  • src/kits/network/libnetapi/Url.cpp

    diff --git a/src/kits/network/libnetapi/Url.cpp b/src/kits/network/libnetapi/Url.cpp
    index e68b535..d24f026 100644
    a b  
    11/*
    2  * Copyright 2010 Haiku Inc. All rights reserved.
     2 * Copyright 2010-2016 Haiku Inc. All rights reserved.
    33 * Distributed under the terms of the MIT License.
    44 *
    55 * Authors:
    66 *      Christophe Huriaux, c.huriaux@gmail.com
     7 *      Andrew Lindesay, apl@lindesay.co.nz
    78 */
    89
    910
     
    1718#include <MimeType.h>
    1819#include <Roster.h>
    1920
    20 #include <ICUWrapper.h>
     21#ifdef HAIKU_TARGET_PLATFORM_HAIKU
     22    #include <ICUWrapper.h>
     23#endif
    2124#include <RegExp.h>
    2225
    23 #include <unicode/idna.h>
    24 #include <unicode/stringpiece.h>
     26#ifdef HAIKU_TARGET_PLATFORM_HAIKU
     27    #include <unicode/idna.h>
     28    #include <unicode/stringpiece.h>
     29#endif
    2530
    2631
    2732static const char* kArchivedUrl = "be:url string";
    BUrl::Fragment() const  
    498503bool
    499504BUrl::IsValid() const
    500505{
     506    if (!fHasProtocol)
     507        return false;
     508
     509    if (fProtocol == "http" || fProtocol == "https" || fProtocol == "ftp")
     510        return fHasHost;
     511
    501512    // TODO: Implement for real!
    502     return fHasProtocol && (fHasHost || fHasPath);
     513    return fHasHost || fHasPath;
    503514}
    504515
    505516
    BUrl::UrlDecode(bool strict)  
    598609}
    599610
    600611
     612#ifdef HAIKU_TARGET_PLATFORM_HAIKU
    601613status_t
    602614BUrl::IDNAToAscii()
    603615{
    BUrl::IDNAToAscii()  
    618630    fHost = result;
    619631    return B_OK;
    620632}
     633#endif
    621634
    622635
     636#ifdef HAIKU_TARGET_PLATFORM_HAIKU
    623637status_t
    624638BUrl::IDNAToUnicode()
    625639{
    BUrl::IDNAToUnicode()  
    640654    fHost = result;
    641655    return B_OK;
    642656}
     657#endif
    643658
    644659
    645660// #pragma mark - utility functionality
    646661
    647662
     663#ifdef HAIKU_TARGET_PLATFORM_HAIKU
    648664bool
    649665BUrl::HasPreferredApplication() const
    650666{
    BUrl::HasPreferredApplication() const  
    657673
    658674    return false;
    659675}
     676#endif
    660677
    661678
     679#ifdef HAIKU_TARGET_PLATFORM_HAIKU
    662680BString
    663681BUrl::PreferredApplication() const
    664682{
    BUrl::PreferredApplication() const  
    669687
    670688    return BString(appSignature);
    671689}
     690#endif
    672691
    673692
     693#ifdef HAIKU_TARGET_PLATFORM_HAIKU
    674694status_t
    675695BUrl::OpenWithPreferredApplication(bool onProblemAskUser) const
    676696{
    BUrl::OpenWithPreferredApplication(bool onProblemAskUser) const  
    710730
    711731    return status;
    712732}
     733#endif
    713734
    714735
    715736// #pragma mark Url encoding/decoding of string
    BUrl::_ResetFields()  
    866887}
    867888
    868889
     890bool
     891BUrl::_ContainsDelimiter(const BString& url)
     892{
     893    int32 len = url.Length();
     894
     895    for (int32 i = 0; i < len; i++) {
     896        switch (url[i]) {
     897            case ' ':
     898            case '\n':
     899            case '\t':
     900            case '\r':
     901            case '<':
     902            case '>':
     903            case '"':
     904                return true;
     905        }
     906    }
     907
     908    return false;
     909}
     910
     911
    869912void
    870913BUrl::_ExplodeUrlString(const BString& url)
    871914{
    BUrl::_ExplodeUrlString(const BString& url)  
    875918
    876919    _ResetFields();
    877920
     921    // RFC3986, Appendix C; the URL should not contain whitespace or delimiters
     922    // by this point.
     923    if (_ContainsDelimiter(url))
     924        return; // TODO error handing
     925
    878926    RegExp::MatchResult match = urlMatcher.Match(url.String());
    879927
    880928    if (!match.HasMatched())
    BUrl::_ExplodeUrlString(const BString& url)  
    883931    // Scheme/Protocol
    884932    url.CopyInto(fProtocol, match.GroupStartOffsetAt(1),
    885933        match.GroupEndOffsetAt(1) - match.GroupStartOffsetAt(1));
     934
    886935    if (!_IsProtocolValid()) {
    887936        fHasProtocol = false;
    888937        fProtocol.Truncate(0);
    BUrl::SetAuthority(const BString& authority)  
    9811030        return;
    9821031
    9831032    int32 userInfoEnd = fAuthority.FindFirst('@');
     1033    int16 hostAndPortStart = 0;
    9841034
    9851035    // URL contains userinfo field
    9861036    if (userInfoEnd != -1) {
    BUrl::SetAuthority(const BString& authority)  
    10001050        } else {
    10011051            SetUserName(fUser);
    10021052        }
    1003     }
    1004 
    10051053
    1006     // Extract the host part
    1007     int16 hostEnd = fAuthority.FindFirst(':', userInfoEnd);
    1008     userInfoEnd++;
    1009 
    1010     if (hostEnd < 0) {
    1011         // no ':' found, the host extends to the end of the URL
    1012         hostEnd = fAuthority.Length() + 1;
     1054        hostAndPortStart = userInfoEnd + 1;
    10131055    }
    10141056
    1015     // The host is likely to be present if an authority is
    1016     // defined, but in some weird cases, it's not.
    1017     if (hostEnd != userInfoEnd) {
    1018         fAuthority.CopyInto(fHost, userInfoEnd, hostEnd - userInfoEnd);
    1019         SetHost(fHost);
    1020     }
     1057    int16 hostEnd = fAuthority.FindFirst(':', hostAndPortStart);
    10211058
    1022     // Extract the port part
    1023     fPort = 0;
    1024     if (fAuthority.ByteAt(hostEnd) == ':') {
    1025         hostEnd++;
    1026         int16 portEnd = fAuthority.Length();
    1027 
    1028         BString portString;
    1029         fAuthority.CopyInto(portString, hostEnd, portEnd - hostEnd);
    1030         fPort = atoi(portString.String());
    1031 
    1032         //  Even if the port is invalid, the URL is considered to
    1033         // have a port.
    1034         fHasPort = portString.Length() > 0;
     1059    if (hostEnd != B_ERROR) {
     1060        if (hostEnd < fAuthority.Length()-1) {
     1061             fPort = atoi(&(fAuthority.String())[hostEnd+1]);
     1062             fHasPort = true;
     1063        }
    10351064    }
     1065    else
     1066        hostEnd = fAuthority.Length();
     1067
     1068    fAuthority.CopyInto(fHost, hostAndPortStart, hostEnd - hostAndPortStart);
     1069    SetHost(fHost);
    10361070}
    10371071
    10381072
    BUrl::_DoUrlDecodeChunk(const BString& chunk, bool strict)  
    10881122                result << decoded;
    10891123            } else
    10901124                result << chunk[i];
    1091         } 
     1125        }
    10921126    }
    10931127    return result;
    10941128}
  • src/kits/package/Jamfile

    diff --git a/src/kits/package/Jamfile b/src/kits/package/Jamfile
    index 013c9ee..7d221f2 100644
    a b for architectureObject in [ MultiArchSubDirSetup ] {  
    129129            SolverResult.cpp
    130130            :
    131131            shared
     132            bnetapi
    132133            be
    133134            [ BuildFeatureAttribute curl : library ]
    134135            [ TargetLibstdc++ ]
     136            $(TARGET_NETWORK_LIBS)
    135137            ;
    136138    }
    137139}
  • src/kits/package/PackageInfoParser.cpp

    diff --git a/src/kits/package/PackageInfoParser.cpp b/src/kits/package/PackageInfoParser.cpp
    index f684815..3de3a7c 100644
    a b  
    11/*
    22 * Copyright 2011, Oliver Tappe <zooey@hirschkaefer.de>
     3 * Copyright 2016, Andrew Lindesay <apl@lindesay.co.nz>
    34 * Distributed under the terms of the MIT License.
    45 */
    56
     
    1314#include <algorithm>
    1415#include <string>
    1516
     17#include <Url.h>
    1618
    1719namespace BPackageKit {
    1820
    BPackageInfo::Parser::_ParseList(ListElementParser& elementParser,  
    508510
    509511void
    510512BPackageInfo::Parser::_ParseStringList(BStringList* value,
    511     bool requireResolvableName, bool convertToLowerCase)
     513    bool requireResolvableName, bool convertToLowerCase,
     514    StringValidator* stringValidator)
    512515{
    513516    struct StringParser : public ListElementParser {
    514517        BStringList* value;
    515518        bool requireResolvableName;
    516519        bool convertToLowerCase;
     520        StringValidator* stringValidator;
    517521
    518522        StringParser(BStringList* value, bool requireResolvableName,
    519             bool convertToLowerCase)
     523            bool convertToLowerCase, StringValidator* stringValidator)
    520524            :
    521525            value(value),
    522526            requireResolvableName(requireResolvableName),
    523             convertToLowerCase(convertToLowerCase)
     527            convertToLowerCase(convertToLowerCase),
     528            stringValidator(stringValidator)
    524529        {
    525530        }
    526531
    BPackageInfo::Parser::_ParseStringList(BStringList* value,  
    541546            if (convertToLowerCase)
    542547                element.ToLower();
    543548
     549            if (stringValidator != NULL)
     550                stringValidator->Validate(element, token.pos);
     551
    544552            value->Add(element);
    545553        }
    546     } stringParser(value, requireResolvableName, convertToLowerCase);
     554    } stringParser(value, requireResolvableName, convertToLowerCase,
     555        stringValidator);
    547556
    548557    _ParseList(stringParser, true);
    549558}
    BPackageInfo::Parser::_Parse(BPackageInfo* packageInfo)  
    10081017                break;
    10091018
    10101019            case B_PACKAGE_INFO_URLS:
    1011                 _ParseStringList(&packageInfo->fURLList);
     1020            {
     1021                UrlStringValidator stringValidator;
     1022                _ParseStringList(&packageInfo->fURLList,
     1023                    false, false, &stringValidator);
     1024            }
    10121025                break;
    10131026
    10141027            case B_PACKAGE_INFO_SOURCE_URLS:
    1015                 _ParseStringList(&packageInfo->fSourceURLList);
     1028            {
     1029                UrlStringValidator stringValidator;
     1030                _ParseStringList(&packageInfo->fSourceURLList,
     1031                    false, false, &stringValidator);
     1032            }
    10161033                break;
    10171034
    10181035            case B_PACKAGE_INFO_GLOBAL_WRITABLE_FILES:
    BPackageInfo::Parser::_IsValidResolvableName(const char* string,  
    11451162    return true;
    11461163}
    11471164
     1165void
     1166BPackageInfo::Parser::UrlStringValidator::Validate(const BString& urlString,
     1167    const char* pos)
     1168{
     1169    BUrl url(urlString);
     1170
     1171    if (!url.IsValid())
     1172        throw ParseError("invalid url", pos);
     1173}
     1174
    11481175
    11491176} // namespace BPackageKit
  • src/kits/package/PackageInfoParser.h

    diff --git a/src/kits/package/PackageInfoParser.h b/src/kits/package/PackageInfoParser.h
    index 6824b9e..5319558 100644
    a b  
    11/*
    22 * Copyright 2011, Oliver Tappe <zooey@hirschkaefer.de>
     3 * Copyright 2016, Andrew Lindesay <apl@lindesay.co.nz>
    34 * Distributed under the terms of the MIT License.
    45 */
    56#ifndef PACKAGE_INFO_PARSER_H
    public:  
    3132                                    BPackageResolvableExpression& _expression);
    3233
    3334private:
     35            struct UrlStringValidator;
     36            struct StringValidator;
    3437            struct ParseError;
    3538            struct Token;
    3639            struct ListElementParser;
    private:  
    7477                                    bool allowSingleNonListElement);
    7578            void                _ParseStringList(BStringList* value,
    7679                                    bool requireResolvableName = false,
    77                                     bool convertToLowerCase = false);
     80                                    bool convertToLowerCase = false,
     81                                    StringValidator* stringValidator = NULL);
    7882            void                _ParseResolvableList(
    7983                                    BObjectList<BPackageResolvable>* value);
    8084            void                _ParseResolvableExprList(
    struct BPackageInfo::Parser::ListElementParser {  
    152156};
    153157
    154158
     159struct BPackageInfo::Parser::StringValidator {
     160public:
     161    virtual void Validate(const BString &string, const char *pos) = 0;
     162};
     163
     164
     165struct BPackageInfo::Parser::UrlStringValidator
     166    : public BPackageInfo::Parser::StringValidator {
     167public:
     168    virtual void                Validate(const BString &string, const char* pos);
     169};
     170
     171
    155172} // namespace BPackageKit
    156173
    157174
  • src/tests/kits/net/libnetapi/Jamfile

    diff --git a/src/tests/kits/net/libnetapi/Jamfile b/src/tests/kits/net/libnetapi/Jamfile
    index b2e34ce..6a7d8fa 100644
    a b UnitTestLib libnetapitest.so :  
    55
    66    NetworkAddressTest.cpp
    77    NetworkInterfaceTest.cpp
     8    NetworkUrlTest.cpp
    89
    910    : be bnetapi network [ TargetLibstdc++ ] [ TargetLibsupc++ ]
    1011;
  • src/tests/kits/net/libnetapi/NetAPITestAddon.cpp

    diff --git a/src/tests/kits/net/libnetapi/NetAPITestAddon.cpp b/src/tests/kits/net/libnetapi/NetAPITestAddon.cpp
    index 593ab4a..fd9e398 100644
    a b  
    99
    1010#include "NetworkAddressTest.h"
    1111#include "NetworkInterfaceTest.h"
     12#include "NetworkUrlTest.h"
    1213
    1314
    1415BTestSuite*
    getTestSuite()  
    1819
    1920    NetworkAddressTest::AddTests(*suite);
    2021    NetworkInterfaceTest::AddTests(*suite);
     22    NetworkUrlTest::AddTests(*suite);
    2123
    2224    return suite;
    2325}
  • new file src/tests/kits/net/libnetapi/NetworkUrlTest.cpp

    diff --git a/src/tests/kits/net/libnetapi/NetworkUrlTest.cpp b/src/tests/kits/net/libnetapi/NetworkUrlTest.cpp
    new file mode 100644
    index 0000000..23feb96
    - +  
     1/*
     2 * Copyright 2016, Andrew Lindesay, apl@lindesay.co.nz.
     3 * Distributed under the terms of the MIT License.
     4 */
     5
     6
     7#include "NetworkUrlTest.h"
     8
     9#include <Url.h>
     10
     11#include <cppunit/TestCaller.h>
     12#include <cppunit/TestSuite.h>
     13
     14
     15NetworkUrlTest::NetworkUrlTest()
     16{
     17}
     18
     19
     20NetworkUrlTest::~NetworkUrlTest()
     21{
     22}
     23
     24
     25void
     26NetworkUrlTest::setUp()
     27{
     28}
     29
     30
     31void
     32NetworkUrlTest::tearDown()
     33{
     34}
     35
     36
     37// General Tests ---------------------------------------------------------------
     38
     39/*
     40This is the "happy days" tests that checks that a URL featuring all of the
     41parsed elements successfully processes and the elements are present.
     42*/
     43
     44void NetworkUrlTest::TestValidFullUrl()
     45{
     46    BUrl url("http://ewe:pea@www.something.co.nz:8888/some/path?key1=value1#fragment");
     47    CPPUNIT_ASSERT(url.IsValid());
     48    CPPUNIT_ASSERT(url.Protocol() == "http");
     49    CPPUNIT_ASSERT(url.HasProtocol());
     50    CPPUNIT_ASSERT(url.UserName() == "ewe");
     51    CPPUNIT_ASSERT(url.HasUserName());
     52    CPPUNIT_ASSERT(url.Password() == "pea");
     53    CPPUNIT_ASSERT(url.HasPassword());
     54    CPPUNIT_ASSERT(url.Host() == "www.something.co.nz");
     55    CPPUNIT_ASSERT(url.HasHost());
     56    CPPUNIT_ASSERT(url.Port() == 8888);
     57    CPPUNIT_ASSERT(url.HasPort());
     58    CPPUNIT_ASSERT(url.Path() == "/some/path");
     59    CPPUNIT_ASSERT(url.HasPath());
     60    CPPUNIT_ASSERT(url.Request() == "key1=value1");
     61    CPPUNIT_ASSERT(url.HasRequest());
     62    CPPUNIT_ASSERT(url.Fragment() == "fragment");
     63    CPPUNIT_ASSERT(url.HasFragment());
     64}
     65
     66
     67void NetworkUrlTest::TestFileUrl()
     68{
     69    BUrl url("file:///northisland/wellington/brooklyn/windturbine");
     70    CPPUNIT_ASSERT(url.IsValid());
     71    CPPUNIT_ASSERT(url.Protocol() == "file");
     72    CPPUNIT_ASSERT(url.HasProtocol());
     73    CPPUNIT_ASSERT(!url.HasUserName());
     74    CPPUNIT_ASSERT(!url.HasPassword());
     75    CPPUNIT_ASSERT(url.Host() == "");
     76    CPPUNIT_ASSERT(url.HasHost());
     77    CPPUNIT_ASSERT(!url.HasPort());
     78    CPPUNIT_ASSERT(url.Path() == "/northisland/wellington/brooklyn/windturbine");
     79    CPPUNIT_ASSERT(url.HasPath());
     80    CPPUNIT_ASSERT(!url.HasRequest());
     81    CPPUNIT_ASSERT(!url.HasFragment());
     82}
     83
     84
     85// Authority Tests (UserName, Password, Host, Port) ----------------------------
     86
     87
     88void NetworkUrlTest::TestWithUserNameAndPasswordNoHostAndPort()
     89{
     90    BUrl url("wierd://tea:tree@/x");
     91    CPPUNIT_ASSERT(url.IsValid());
     92    CPPUNIT_ASSERT(url.Protocol() == "wierd");
     93    CPPUNIT_ASSERT(url.HasProtocol());
     94    CPPUNIT_ASSERT(url.UserName() == "tea");
     95    CPPUNIT_ASSERT(url.HasUserName());
     96    CPPUNIT_ASSERT(url.Password() == "tree");
     97    CPPUNIT_ASSERT(url.HasPassword());
     98    CPPUNIT_ASSERT(url.Host() == "");
     99    CPPUNIT_ASSERT(!url.HasHost());
     100    CPPUNIT_ASSERT(!url.HasPort());
     101    CPPUNIT_ASSERT(url.Path() == "/x");
     102    CPPUNIT_ASSERT(url.HasPath());
     103    CPPUNIT_ASSERT(!url.HasRequest());
     104    CPPUNIT_ASSERT(!url.HasFragment());
     105}
     106
     107
     108void NetworkUrlTest::TestHostAndPortWithNoUserNameAndPassword()
     109{
     110    BUrl url("https://www.something.co.nz:443/z");
     111    CPPUNIT_ASSERT(url.IsValid());
     112    CPPUNIT_ASSERT(url.Protocol() == "https");
     113    CPPUNIT_ASSERT(url.HasProtocol());
     114    CPPUNIT_ASSERT(!url.HasUserName());
     115    CPPUNIT_ASSERT(!url.HasPassword());
     116    CPPUNIT_ASSERT(url.Port() == 443);
     117    CPPUNIT_ASSERT(url.HasPort());
     118    CPPUNIT_ASSERT(url.Host() == "www.something.co.nz");
     119    CPPUNIT_ASSERT(url.HasHost());
     120    CPPUNIT_ASSERT(url.Path() == "/z");
     121    CPPUNIT_ASSERT(url.HasPath());
     122    CPPUNIT_ASSERT(!url.HasRequest());
     123    CPPUNIT_ASSERT(!url.HasFragment());
     124}
     125
     126
     127void NetworkUrlTest::TestHostWithNoPortOrUserNameAndPassword()
     128{
     129    BUrl url("https://www.something.co.nz/z");
     130    CPPUNIT_ASSERT(url.IsValid());
     131    CPPUNIT_ASSERT(url.Protocol() == "https");
     132    CPPUNIT_ASSERT(url.HasProtocol());
     133    CPPUNIT_ASSERT(!url.HasUserName());
     134    CPPUNIT_ASSERT(!url.HasPassword());
     135    CPPUNIT_ASSERT(url.Host() == "www.something.co.nz");
     136    CPPUNIT_ASSERT(url.HasHost());
     137    CPPUNIT_ASSERT(!url.HasPort());
     138    CPPUNIT_ASSERT(url.Path() == "/z");
     139    CPPUNIT_ASSERT(url.HasPath());
     140    CPPUNIT_ASSERT(!url.HasRequest());
     141    CPPUNIT_ASSERT(!url.HasFragment());
     142}
     143
     144
     145void NetworkUrlTest::TestHostWithNoPortNoPath()
     146{
     147    BUrl url("https://www.something.co.nz");
     148    CPPUNIT_ASSERT(url.IsValid());
     149    CPPUNIT_ASSERT(url.Protocol() == "https");
     150    CPPUNIT_ASSERT(url.HasProtocol());
     151    CPPUNIT_ASSERT(!url.HasUserName());
     152    CPPUNIT_ASSERT(!url.HasPassword());
     153    CPPUNIT_ASSERT(url.Host() == "www.something.co.nz");
     154    CPPUNIT_ASSERT(url.HasHost());
     155    CPPUNIT_ASSERT(!url.HasPort());
     156    CPPUNIT_ASSERT(!url.HasPath());
     157    CPPUNIT_ASSERT(!url.HasRequest());
     158    CPPUNIT_ASSERT(!url.HasFragment());
     159}
     160
     161
     162void NetworkUrlTest::TestHostWithPortNoPath()
     163{
     164    BUrl url("https://www.something.co.nz:1234");
     165    CPPUNIT_ASSERT(url.IsValid());
     166    CPPUNIT_ASSERT(url.Protocol() == "https");
     167    CPPUNIT_ASSERT(url.HasProtocol());
     168    CPPUNIT_ASSERT(!url.HasUserName());
     169    CPPUNIT_ASSERT(!url.HasPassword());
     170    CPPUNIT_ASSERT(url.Host() == "www.something.co.nz");
     171    CPPUNIT_ASSERT(url.HasHost());
     172    CPPUNIT_ASSERT(url.Port() == 1234);
     173    CPPUNIT_ASSERT(url.HasPort());
     174    CPPUNIT_ASSERT(!url.HasPath());
     175    CPPUNIT_ASSERT(!url.HasRequest());
     176    CPPUNIT_ASSERT(!url.HasFragment());
     177}
     178
     179
     180void NetworkUrlTest::TestHostWithEmptyPort()
     181{
     182    BUrl url("https://www.something.co.nz:");
     183    CPPUNIT_ASSERT(url.IsValid());
     184    CPPUNIT_ASSERT(url.Protocol() == "https");
     185    CPPUNIT_ASSERT(url.HasProtocol());
     186    CPPUNIT_ASSERT(!url.HasUserName());
     187    CPPUNIT_ASSERT(!url.HasPassword());
     188    CPPUNIT_ASSERT(url.Host() == "www.something.co.nz");
     189    CPPUNIT_ASSERT(url.HasHost());
     190    CPPUNIT_ASSERT(!url.HasPort());
     191    CPPUNIT_ASSERT(!url.HasPath());
     192    CPPUNIT_ASSERT(!url.HasRequest());
     193    CPPUNIT_ASSERT(!url.HasFragment());
     194}
     195
     196
     197// Invalid Forms ---------------------------------------------------------------
     198
     199
     200void NetworkUrlTest::TestWhitespaceBefore()
     201{
     202    BUrl url("   https://www.something.co.nz/z");
     203    CPPUNIT_ASSERT(!url.IsValid());
     204}
     205
     206
     207void NetworkUrlTest::TestWhitespaceAfter()
     208{
     209    BUrl url("https://www.something.co.nz/z\t\t ");
     210    CPPUNIT_ASSERT(!url.IsValid());
     211}
     212
     213
     214void NetworkUrlTest::TestWhitespaceMiddle()
     215{
     216    BUrl url("https://www.  something.co.nz/z");
     217    CPPUNIT_ASSERT(!url.IsValid());
     218}
     219
     220
     221void NetworkUrlTest::TestHttpNoHost()
     222{
     223    BUrl url("https:///z");
     224    CPPUNIT_ASSERT(!url.IsValid());
     225}
     226
     227
     228// Control ---------------------------------------------------------------------
     229
     230
     231/*static*/ void
     232NetworkUrlTest::AddTests(BTestSuite& parent)
     233{
     234    CppUnit::TestSuite& suite = *new CppUnit::TestSuite("NetworkUrlTest");
     235
     236    suite.addTest(new CppUnit::TestCaller<NetworkUrlTest>(
     237        "NetworkUrlTest::TestHostAndPortWithNoUserNameAndPassword",
     238        &NetworkUrlTest::TestHostAndPortWithNoUserNameAndPassword));
     239    suite.addTest(new CppUnit::TestCaller<NetworkUrlTest>(
     240        "NetworkUrlTest::TestWithUserNameAndPasswordNoHostAndPort",
     241        &NetworkUrlTest::TestWithUserNameAndPasswordNoHostAndPort));
     242    suite.addTest(new CppUnit::TestCaller<NetworkUrlTest>(
     243        "NetworkUrlTest::TestHostWithNoPortOrUserNameAndPassword",
     244        &NetworkUrlTest::TestHostWithNoPortOrUserNameAndPassword));
     245    suite.addTest(new CppUnit::TestCaller<NetworkUrlTest>(
     246        "NetworkUrlTest::TestHostWithNoPortNoPath",
     247        &NetworkUrlTest::TestHostWithNoPortNoPath));
     248    suite.addTest(new CppUnit::TestCaller<NetworkUrlTest>(
     249        "NetworkUrlTest::TestHostWithPortNoPath",
     250        &NetworkUrlTest::TestHostWithPortNoPath));
     251    suite.addTest(new CppUnit::TestCaller<NetworkUrlTest>(
     252        "NetworkUrlTest::TestHostWithEmptyPort",
     253        &NetworkUrlTest::TestHostWithEmptyPort));
     254
     255    suite.addTest(new CppUnit::TestCaller<NetworkUrlTest>(
     256        "NetworkUrlTest::TestWhitespaceBefore",
     257        &NetworkUrlTest::TestWhitespaceBefore));
     258    suite.addTest(new CppUnit::TestCaller<NetworkUrlTest>(
     259        "NetworkUrlTest::TestWhitespaceAfter",
     260        &NetworkUrlTest::TestWhitespaceAfter));
     261    suite.addTest(new CppUnit::TestCaller<NetworkUrlTest>(
     262        "NetworkUrlTest::TestWhitespaceMiddle",
     263        &NetworkUrlTest::TestWhitespaceMiddle));
     264
     265    suite.addTest(new CppUnit::TestCaller<NetworkUrlTest>(
     266        "NetworkUrlTest::TestFileUrl",
     267        &NetworkUrlTest::TestFileUrl));
     268    suite.addTest(new CppUnit::TestCaller<NetworkUrlTest>(
     269        "NetworkUrlTest::TestValidFullUrl", &NetworkUrlTest::TestValidFullUrl));
     270
     271    parent.addTest("NetworkUrlTest", &suite);
     272}
  • new file src/tests/kits/net/libnetapi/NetworkUrlTest.h

    diff --git a/src/tests/kits/net/libnetapi/NetworkUrlTest.h b/src/tests/kits/net/libnetapi/NetworkUrlTest.h
    new file mode 100644
    index 0000000..6b8b7e4
    - +  
     1/*
     2 * Copyright 2016, Andrew Lindesay, apl@lindesay.co.nz
     3 * Distributed under the terms of the MIT License.
     4 */
     5#ifndef NETWORK_URL_TEST_H
     6#define NETWORK_URL_TEST_H
     7
     8
     9#include <TestCase.h>
     10#include <TestSuite.h>
     11
     12
     13class NetworkUrlTest : public CppUnit::TestCase {
     14public:
     15                                NetworkUrlTest();
     16    virtual                     ~NetworkUrlTest();
     17
     18    virtual void                setUp();
     19    virtual void                tearDown();
     20
     21            void                TestValidFullUrl();
     22
     23            void                TestFileUrl();
     24
     25            void                TestWithUserNameAndPasswordNoHostAndPort();
     26            void                TestHostAndPortWithNoUserNameAndPassword();
     27            void                TestHostWithNoPortOrUserNameAndPassword();
     28            void                TestHostWithNoPortNoPath();
     29            void                TestHostWithPortNoPath();
     30            void                TestHostWithEmptyPort();
     31
     32            void                TestWhitespaceBefore();
     33            void                TestWhitespaceAfter();
     34            void                TestWhitespaceMiddle();
     35            void                TestHttpNoHost();
     36
     37    static  void                AddTests(BTestSuite& suite);
     38
     39};
     40
     41
     42#endif  // NETWORK_URL_TEST_H