netservices: add BHttpHeader class and BHttpHeaderMap skeleton
Change-Id: I36a7c757a6909604d749355ecb1a9d42d05d7306
This commit is contained in:
parent
892cbe10b6
commit
34522da9e3
332
docs/user/netservices/HttpHeaders.dox
Executable file
332
docs/user/netservices/HttpHeaders.dox
Executable file
@ -0,0 +1,332 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2021 Haiku, Inc. All rights reserved.
|
||||||
|
* Distributed under the terms of the MIT License.
|
||||||
|
*
|
||||||
|
* Authors:
|
||||||
|
* Niels Sascha Reedijk, niels.reedijk@gmail.com
|
||||||
|
*
|
||||||
|
* Corresponds to:
|
||||||
|
* headers/private/netservices2/HttpHeaders.h hrev?????
|
||||||
|
* src/kits/network/libnetservices2/HttpHeaders.cpp hrev?????
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
#if __cplusplus >= 201703L
|
||||||
|
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\file HttpHeaders.h
|
||||||
|
\ingroup netservices
|
||||||
|
\brief Provides the BHttpHeader and BHttpHeaderMap classes.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace BPrivate {
|
||||||
|
|
||||||
|
namespace Network {
|
||||||
|
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\class BHttpHeader
|
||||||
|
\ingroup netservices
|
||||||
|
\brief Represent a HTTP header name and value pair.
|
||||||
|
|
||||||
|
\since Haiku R1
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\class BHttpHeader::InvalidInput
|
||||||
|
\ingroup netservices
|
||||||
|
\brief Error that represents when a string input contains characters that are incompatible with
|
||||||
|
the HTTP specification.
|
||||||
|
|
||||||
|
\since Haiku R1
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\var BString BHttpHeader::InvalidInput::input
|
||||||
|
\brief The input that contains the invalid contents.
|
||||||
|
|
||||||
|
\since Haiku R1
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\fn BHttpHeader::InvalidInput::InvalidInput(const char *origin, BString input)
|
||||||
|
\brief Constructor that sets the \a origin and the invalid \a input.
|
||||||
|
|
||||||
|
\since Haiku R1
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\fn virtual BString BHttpHeader::InvalidInput::DebugMessage() const override
|
||||||
|
\brief Retrieve a debug message that contains all info in this error.
|
||||||
|
|
||||||
|
The output will be along the lines of:
|
||||||
|
\code
|
||||||
|
[Origin] Invalid format or unsupported characters in input [input]
|
||||||
|
\endcode
|
||||||
|
|
||||||
|
\exception std::bad_alloc In the future this method may throw this
|
||||||
|
exception when the memory for the debug message cannot be allocated.
|
||||||
|
|
||||||
|
\return A \ref BString object that contains the debug message.
|
||||||
|
|
||||||
|
\since Haiku R1
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\fn virtual const char* BHttpHeader::InvalidInput::Message() const noexcept override
|
||||||
|
\brief Get a pointer to the message describing the error.
|
||||||
|
|
||||||
|
\since Haiku R1
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\class BHttpHeader::EmptyHeader
|
||||||
|
\ingroup netservices
|
||||||
|
\brief Error that is raised when the HTTP header has an empty name or value when it is
|
||||||
|
serialized to and from text.
|
||||||
|
|
||||||
|
\since Haiku R1
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\fn BHttpHeader::EmptyHeader::EmptyHeader(const char *origin)
|
||||||
|
\copydoc BError::BError()
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\fn virtual const char* BHttpHeader::EmptyHeader::Message() const noexcept override
|
||||||
|
\brief Get a pointer to the message describing the error.
|
||||||
|
|
||||||
|
\since Haiku R1
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\class BHttpHeader::HeaderName
|
||||||
|
\ingroup netservices
|
||||||
|
\brief Representation of a HTTP header name.
|
||||||
|
|
||||||
|
As per the HTTP specification, header fields have a name. There are limitations to which
|
||||||
|
characters are supported. As per the specification, header field names are case insensitive.
|
||||||
|
This means that the \c content-encoding is equal to \c Content-Encoding or even
|
||||||
|
\c COnTenT-ENcOdING.
|
||||||
|
|
||||||
|
This particular object can be empty. Headers with empty names can still be used in the
|
||||||
|
\ref BHttpHeaderMap object, though as soon as you try to serialize them to a string, the
|
||||||
|
\ref BHttpHeader::EmptyHeader exception will be raised.
|
||||||
|
|
||||||
|
\since Haiku R1
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\fn bool BHttpHeader::HeaderName::IsEmpty() const noexcept
|
||||||
|
\brief Check if the header name has a value set.
|
||||||
|
|
||||||
|
\retval true This object is empty, meaning it is set to an empty string.
|
||||||
|
\retval false This object has a valid header name.
|
||||||
|
|
||||||
|
\since Haiku R1
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\fn BHttpHeader::HeaderName::operator BString() const
|
||||||
|
\brief Return a copy of the header name as a string.
|
||||||
|
|
||||||
|
\return The header name as a \ref BString object.
|
||||||
|
|
||||||
|
\since Haiku R1
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\fn BHttpHeader::HeaderName::operator std::string_view() const
|
||||||
|
\brief Return a \c std::string_view over the header name.
|
||||||
|
|
||||||
|
\return A \c std::string_view object over the header name.
|
||||||
|
|
||||||
|
\since Haiku R1
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\fn bool BHttpHeader::HeaderName::operator==(const BString &other) const noexcept
|
||||||
|
\brief Compare the header name to a string.
|
||||||
|
|
||||||
|
\param other The \c other string to compare it to.
|
||||||
|
|
||||||
|
The comparison is case-insensitive. So if this header name is set to \c Content-Encoding,
|
||||||
|
comparing it to \c content-encoding will return \c true.
|
||||||
|
|
||||||
|
\retval true The current header name is equal to the \a other name.
|
||||||
|
\retval false The current header name is different from the \a other name.
|
||||||
|
|
||||||
|
\since Haiku R1
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\fn bool BHttpHeader::HeaderName::operator==(const std::string_view other) const noexcept
|
||||||
|
\copydoc BHttpHeader::HeaderName::operator==(const BString &other) const noexcept
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\fn BHttpHeader::BHttpHeader()
|
||||||
|
\brief Construct an empty HTTP Header Field.
|
||||||
|
|
||||||
|
The name and the value of the field will both be empty.
|
||||||
|
|
||||||
|
\since Haiku R1
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\fn BHttpHeader::BHttpHeader(BHttpHeader &&other) noexcept
|
||||||
|
\brief Move constructor.
|
||||||
|
|
||||||
|
The name and value from the \a other header object will be moved to this object. The \a other
|
||||||
|
object will be empty, meaning it no longer has a name or value.
|
||||||
|
|
||||||
|
\since Haiku R1
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\fn BHttpHeader::BHttpHeader(const BHttpHeader &other)
|
||||||
|
\brief Copy constructor.
|
||||||
|
|
||||||
|
\since Haiku R1
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\fn BHttpHeader::BHttpHeader(std::string_view name, std::string_view value)
|
||||||
|
\brief Constructor to create a header from a \a name and a \a value.
|
||||||
|
|
||||||
|
The parameters are checked whether they only contain characters that are allowed by the HTTP
|
||||||
|
specification.
|
||||||
|
|
||||||
|
\param name The name of the header field.
|
||||||
|
\param value The value of the header field.
|
||||||
|
|
||||||
|
\exception BHttpHeader::InvalidInput This error indicates that the \a name or the \a value
|
||||||
|
contains invalid characters.
|
||||||
|
|
||||||
|
\since Haiku R1
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\fn BHttpHeader::~BHttpHeader() noexcept
|
||||||
|
\brief Destructor.
|
||||||
|
|
||||||
|
\since Haiku R1
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\fn bool BHttpHeader::IsEmpty() noexcept
|
||||||
|
\brief Check if the name or the value are empty.
|
||||||
|
|
||||||
|
A header is considered empty when it does not have a name or a value, or neither of them. An
|
||||||
|
empty header cannot be serialized to a string.
|
||||||
|
|
||||||
|
\retval true The name or value are empty.
|
||||||
|
\retval false The name and value contain valid data.
|
||||||
|
|
||||||
|
\since Haiku R1
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\fn const HeaderName& BHttpHeader::Name() noexcept
|
||||||
|
\brief Get the header name.
|
||||||
|
|
||||||
|
\return A reference to the header name object.
|
||||||
|
|
||||||
|
\since Haiku R1
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\fn std::string_view BHttpHeader::Value() noexcept
|
||||||
|
\brief Get the header value.
|
||||||
|
|
||||||
|
\return A \c std::string_view to the header value.
|
||||||
|
|
||||||
|
\since Haiku R1
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\fn BHttpHeader& BHttpHeader::operator=(BHttpHeader &&other) noexcept
|
||||||
|
\brief Move assignment operator.
|
||||||
|
|
||||||
|
Moves the name and value from the \a other header to this object. The \a other object will be
|
||||||
|
empty.
|
||||||
|
|
||||||
|
\since Haiku R1
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\fn BHttpHeader& BHttpHeader::operator=(const BHttpHeader &other)
|
||||||
|
\brief Copy assignment operator.
|
||||||
|
|
||||||
|
Make a new header object with a copy of the name and value of the \a other header.
|
||||||
|
|
||||||
|
\since Haiku R1
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\fn void BHttpHeader::SetName(std::string_view name)
|
||||||
|
\brief Set the name of the header to a \a name.
|
||||||
|
|
||||||
|
\param name A header name with characters supported by the HTTP specification.
|
||||||
|
|
||||||
|
\exception BHttpHeader::InvalidInput This error indicates that the \a name contains invalid
|
||||||
|
characters.
|
||||||
|
|
||||||
|
\since Haiku R1
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\fn void BHttpHeader::SetValue(std::string_view value)
|
||||||
|
\brief Set the value of the header to a \a value.
|
||||||
|
|
||||||
|
\param value A header value with characters supported by the HTTP specification.
|
||||||
|
|
||||||
|
\exception BHttpHeader::InvalidInput This error indicates that the \a value contains invalid
|
||||||
|
characters.
|
||||||
|
|
||||||
|
\since Haiku R1
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\class BHttpHeaderMap
|
||||||
|
\ingroup netservices
|
||||||
|
\brief Represent set of HTTP headers.
|
||||||
|
|
||||||
|
\since Haiku R1
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
} // namespace Network
|
||||||
|
|
||||||
|
} // namespace BPrivate
|
||||||
|
|
||||||
|
#endif
|
94
headers/private/netservices2/HttpHeaders.h
Executable file
94
headers/private/netservices2/HttpHeaders.h
Executable file
@ -0,0 +1,94 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2021 Haiku Inc. All rights reserved.
|
||||||
|
* Distributed under the terms of the MIT License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _B_HTTP_HEADERS_H_
|
||||||
|
#define _B_HTTP_HEADERS_H_
|
||||||
|
|
||||||
|
#include <string_view>
|
||||||
|
|
||||||
|
#include <ErrorsExt.h>
|
||||||
|
#include <String.h>
|
||||||
|
|
||||||
|
|
||||||
|
namespace BPrivate {
|
||||||
|
|
||||||
|
namespace Network {
|
||||||
|
|
||||||
|
|
||||||
|
class BHttpHeader {
|
||||||
|
public:
|
||||||
|
// Exceptions
|
||||||
|
class InvalidInput : public BError {
|
||||||
|
public:
|
||||||
|
InvalidInput(const char* origin, BString input);
|
||||||
|
|
||||||
|
virtual const char* Message() const noexcept override;
|
||||||
|
virtual BString DebugMessage() const override;
|
||||||
|
|
||||||
|
BString input;
|
||||||
|
};
|
||||||
|
|
||||||
|
class EmptyHeader : public BError {
|
||||||
|
public:
|
||||||
|
EmptyHeader(const char* origin);
|
||||||
|
|
||||||
|
virtual const char* Message() const noexcept override;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Wrapper Types
|
||||||
|
class HeaderName {
|
||||||
|
public:
|
||||||
|
bool IsEmpty() const noexcept { return fName.IsEmpty(); }
|
||||||
|
|
||||||
|
// Comparison
|
||||||
|
bool operator==(const BString& other) const noexcept;
|
||||||
|
bool operator==(const std::string_view other) const noexcept;
|
||||||
|
|
||||||
|
// Conversion
|
||||||
|
operator BString() const;
|
||||||
|
operator std::string_view() const;
|
||||||
|
private:
|
||||||
|
friend class BHttpHeader;
|
||||||
|
HeaderName(std::string_view name);
|
||||||
|
BString fName;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Constructors & Destructor
|
||||||
|
BHttpHeader();
|
||||||
|
BHttpHeader(std::string_view name, std::string_view value);
|
||||||
|
BHttpHeader(const BHttpHeader& other);
|
||||||
|
BHttpHeader(BHttpHeader&& other) noexcept;
|
||||||
|
~BHttpHeader() noexcept;
|
||||||
|
|
||||||
|
// Assignment operators
|
||||||
|
BHttpHeader& operator=(const BHttpHeader& other);
|
||||||
|
BHttpHeader& operator=(BHttpHeader&& other) noexcept;
|
||||||
|
|
||||||
|
// Header data modification
|
||||||
|
void SetName(std::string_view name);
|
||||||
|
void SetValue(std::string_view value);
|
||||||
|
|
||||||
|
// Access Data
|
||||||
|
const HeaderName& Name() noexcept;
|
||||||
|
std::string_view Value() noexcept;
|
||||||
|
bool IsEmpty() noexcept;
|
||||||
|
|
||||||
|
private:
|
||||||
|
HeaderName fName;
|
||||||
|
BString fValue;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
// Placeholder for a HashMap that represents HTTP Headers
|
||||||
|
class BHttpHeaderMap {
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
} // namespace Network
|
||||||
|
|
||||||
|
} // namespace BPrivate
|
||||||
|
|
||||||
|
#endif // _B_HTTP_HEADERS_H_
|
225
src/kits/network/libnetservices2/HttpHeaders.cpp
Executable file
225
src/kits/network/libnetservices2/HttpHeaders.cpp
Executable file
@ -0,0 +1,225 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2021 Haiku Inc. All rights reserved.
|
||||||
|
* Distributed under the terms of the MIT License.
|
||||||
|
*
|
||||||
|
* Authors:
|
||||||
|
* Niels Sascha Reedijk, niels.reedijk@gmail.com
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <HttpHeaders.h>
|
||||||
|
|
||||||
|
#include <ctype.h>
|
||||||
|
#include <utility>
|
||||||
|
|
||||||
|
using namespace BPrivate::Network;
|
||||||
|
|
||||||
|
|
||||||
|
// #pragma mark -- utilities
|
||||||
|
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\brief Validate whether the string conforms to a HTTP token value
|
||||||
|
|
||||||
|
RFC 7230 section 3.2.6 determines that valid tokens for the header name are:
|
||||||
|
!#$%&'*+=.^_`|~, any digits or alpha.
|
||||||
|
|
||||||
|
\returns \c true if the string is valid, or \c false if it is not.
|
||||||
|
*/
|
||||||
|
static inline bool
|
||||||
|
validate_token_string(std::string_view string)
|
||||||
|
{
|
||||||
|
for (auto it = string.cbegin(); it < string.cend(); it++) {
|
||||||
|
if (*it <= 31 || *it == 127 || *it == '(' || *it == ')' || *it == '<' || *it == '>'
|
||||||
|
|| *it == '@' || *it == ',' || *it == ';' || *it == '\\' || *it == '"'
|
||||||
|
|| *it == '/' || *it == '[' || *it == ']' || *it == '?' || *it == '='
|
||||||
|
|| *it == '{' || *it == '}' || *it == ' ')
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\brief Validate whether the string is a valid HTTP header value
|
||||||
|
|
||||||
|
RFC 7230 section 3.2.6 determines that valid tokens for the header are:
|
||||||
|
HTAB ('\t'), SP (32), all visible ASCII characters (33-126), and all characters that
|
||||||
|
not control characters (in the case of a char, any value < 0)
|
||||||
|
|
||||||
|
\note When printing out the HTTP header, sometimes the string needs to be quoted and some
|
||||||
|
characters need to be escaped. This function is not checking for whether the string can
|
||||||
|
be transmitted as is.
|
||||||
|
|
||||||
|
\returns \c true if the string is valid, or \c false if it is not.
|
||||||
|
*/
|
||||||
|
static inline bool
|
||||||
|
validate_value_string(std::string_view string)
|
||||||
|
{
|
||||||
|
for (auto it = string.cbegin(); it < string.cend(); it++) {
|
||||||
|
if ((*it >= 0 && *it < 32) || *it == 127 || *it == '\t')
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// #pragma mark -- BHttpHeader::InvalidHeader
|
||||||
|
|
||||||
|
|
||||||
|
BHttpHeader::InvalidInput::InvalidInput(const char* origin, BString input)
|
||||||
|
:
|
||||||
|
BError(origin),
|
||||||
|
input(std::move(input))
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
const char*
|
||||||
|
BHttpHeader::InvalidInput::Message() const noexcept
|
||||||
|
{
|
||||||
|
return "Invalid format or unsupported characters in input";
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
BString
|
||||||
|
BHttpHeader::InvalidInput::DebugMessage() const
|
||||||
|
{
|
||||||
|
BString output = BError::DebugMessage();
|
||||||
|
output << "\t " << input << "\n";
|
||||||
|
return output;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// #pragma mark -- BHttpHeader::EmptyHeader
|
||||||
|
|
||||||
|
|
||||||
|
BHttpHeader::EmptyHeader::EmptyHeader(const char* origin)
|
||||||
|
:
|
||||||
|
BError(origin)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
const char*
|
||||||
|
BHttpHeader::EmptyHeader::Message() const noexcept
|
||||||
|
{
|
||||||
|
return "Cannot convert this object into a HTTP header string: the name or value is empty";
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// #pragma mark -- BHttpHeader::HeaderName
|
||||||
|
|
||||||
|
|
||||||
|
BHttpHeader::HeaderName::HeaderName(std::string_view name)
|
||||||
|
{
|
||||||
|
if (name.empty()) {
|
||||||
|
// ignore an empty name
|
||||||
|
} else if (!validate_token_string(name)) {
|
||||||
|
throw InvalidInput(__PRETTY_FUNCTION__, BString(name.data(), name.size()));
|
||||||
|
} else {
|
||||||
|
fName.SetTo(name.data(), name.length());
|
||||||
|
fName.CapitalizeEachWord();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool
|
||||||
|
BHttpHeader::HeaderName::operator==(const BString& other) const noexcept
|
||||||
|
{
|
||||||
|
return fName.ICompare(other) == 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool
|
||||||
|
BHttpHeader::HeaderName::operator==(const std::string_view other) const noexcept
|
||||||
|
{
|
||||||
|
return fName.ICompare(other.data(), other.size()) == 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
BHttpHeader::HeaderName::operator BString() const
|
||||||
|
{
|
||||||
|
return fName;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
BHttpHeader::HeaderName::operator std::string_view() const
|
||||||
|
{
|
||||||
|
return std::string_view(fName.String());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// #pragma mark -- BHttpHeader
|
||||||
|
|
||||||
|
|
||||||
|
BHttpHeader::BHttpHeader()
|
||||||
|
: fName(std::string_view())
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
BHttpHeader::BHttpHeader(std::string_view name, std::string_view value)
|
||||||
|
: fName(name)
|
||||||
|
{
|
||||||
|
SetValue(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
BHttpHeader::BHttpHeader(const BHttpHeader& other) = default;
|
||||||
|
|
||||||
|
|
||||||
|
BHttpHeader::BHttpHeader(BHttpHeader&& other) noexcept = default;
|
||||||
|
|
||||||
|
|
||||||
|
BHttpHeader::~BHttpHeader() noexcept
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
BHttpHeader&
|
||||||
|
BHttpHeader::operator=(const BHttpHeader& other) = default;
|
||||||
|
|
||||||
|
|
||||||
|
BHttpHeader&
|
||||||
|
BHttpHeader::operator=(BHttpHeader&& other) noexcept = default;
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
BHttpHeader::SetName(std::string_view name)
|
||||||
|
{
|
||||||
|
fName = BHttpHeader::HeaderName(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
BHttpHeader::SetValue(std::string_view value)
|
||||||
|
{
|
||||||
|
if (!validate_value_string(value))
|
||||||
|
throw InvalidInput(__PRETTY_FUNCTION__, BString(value.data(), value.length()));
|
||||||
|
fValue.SetTo(value.data(), value.length());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
const BHttpHeader::HeaderName&
|
||||||
|
BHttpHeader::Name() noexcept
|
||||||
|
{
|
||||||
|
return fName;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
std::string_view
|
||||||
|
BHttpHeader::Value() noexcept
|
||||||
|
{
|
||||||
|
return std::string_view(fValue.String());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool
|
||||||
|
BHttpHeader::IsEmpty() noexcept
|
||||||
|
{
|
||||||
|
return fName.IsEmpty() || fValue.IsEmpty();
|
||||||
|
}
|
@ -12,8 +12,11 @@ for architectureObject in [ MultiArchSubDirSetup ] {
|
|||||||
continue ;
|
continue ;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
SubDirC++Flags -std=gnu++17 ;
|
||||||
|
|
||||||
StaticLibrary [ MultiArchDefaultGristFiles libnetservices2.a ] :
|
StaticLibrary [ MultiArchDefaultGristFiles libnetservices2.a ] :
|
||||||
ErrorsExt.cpp
|
ErrorsExt.cpp
|
||||||
|
HttpHeaders.cpp
|
||||||
HttpSession.cpp
|
HttpSession.cpp
|
||||||
NetServicesMisc.cpp
|
NetServicesMisc.cpp
|
||||||
;
|
;
|
||||||
|
91
src/tests/kits/net/netservices2/HttpProtocolTest.cpp
Normal file
91
src/tests/kits/net/netservices2/HttpProtocolTest.cpp
Normal file
@ -0,0 +1,91 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2021 Haiku Inc. All rights reserved.
|
||||||
|
* Distributed under the terms of the MIT License.
|
||||||
|
*
|
||||||
|
* Authors:
|
||||||
|
* Niels Sascha Reedijk, niels.reedijk@gmail.com
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "HttpProtocolTest.h"
|
||||||
|
|
||||||
|
#include <cppunit/TestAssert.h>
|
||||||
|
#include <cppunit/TestCaller.h>
|
||||||
|
#include <cppunit/TestSuite.h>
|
||||||
|
|
||||||
|
#include <HttpHeaders.h>
|
||||||
|
|
||||||
|
using BPrivate::Network::BHttpHeader;
|
||||||
|
using BPrivate::Network::BHttpSession;
|
||||||
|
|
||||||
|
|
||||||
|
HttpProtocolTest::HttpProtocolTest()
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
HttpProtocolTest::HttpHeaderTest()
|
||||||
|
{
|
||||||
|
using namespace std::literals;
|
||||||
|
|
||||||
|
// Header field name validation (ignore value validation)
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
auto validFieldName = "Content-Encoding"sv;
|
||||||
|
auto header = BHttpHeader{validFieldName, ""sv};
|
||||||
|
} catch (...) {
|
||||||
|
CPPUNIT_FAIL("Unexpected exception when passing valid field name");
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
auto invalidFieldName = "Cóntênt_Éncõdìng";
|
||||||
|
auto header = BHttpHeader{invalidFieldName, ""sv};
|
||||||
|
CPPUNIT_FAIL("Creating a header with an invalid name did not raise an exception");
|
||||||
|
} catch (const BHttpHeader::InvalidInput& e) {
|
||||||
|
// success
|
||||||
|
} catch (...) {
|
||||||
|
CPPUNIT_FAIL("Unexpected exception when creating a header with an invalid name");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Header field value validation (ignore name validation)
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
auto validFieldValue = "VálìdF|êldValue"sv;
|
||||||
|
auto header = BHttpHeader{""sv, validFieldValue};
|
||||||
|
} catch (...) {
|
||||||
|
CPPUNIT_FAIL("Unexpected exception when passing valid field value");
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
auto invalidFieldValue = "Invalid\tField\0Value";
|
||||||
|
auto header = BHttpHeader{""sv, invalidFieldValue};
|
||||||
|
CPPUNIT_FAIL("Creating a header with an invalid value did not raise an exception");
|
||||||
|
} catch (const BHttpHeader::InvalidInput& e) {
|
||||||
|
// success
|
||||||
|
} catch (...) {
|
||||||
|
CPPUNIT_FAIL("Unexpected exception when creating a header with an invalid value");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Header field name case insensitive comparison
|
||||||
|
{
|
||||||
|
BHttpHeader header = BHttpHeader{"content-type"sv, ""sv};
|
||||||
|
CPPUNIT_ASSERT(header.Name() == "content-type"sv);
|
||||||
|
CPPUNIT_ASSERT(header.Name() == "Content-Type"sv);
|
||||||
|
CPPUNIT_ASSERT(header.Name() == "cOnTeNt-TyPe"sv);
|
||||||
|
CPPUNIT_ASSERT(header.Name() != "content_type"sv);
|
||||||
|
CPPUNIT_ASSERT(header.Name() == BString{"Content-Type"});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* static */ void
|
||||||
|
HttpProtocolTest::AddTests(BTestSuite& parent)
|
||||||
|
{
|
||||||
|
CppUnit::TestSuite& suite = *new CppUnit::TestSuite("HttpProtocolTest");
|
||||||
|
|
||||||
|
suite.addTest(new CppUnit::TestCaller<HttpProtocolTest>(
|
||||||
|
"HttpProtocolTest::HttpHeaderTest", &HttpProtocolTest::HttpHeaderTest));
|
||||||
|
|
||||||
|
// leak for now
|
||||||
|
parent.addTest("HttpProtocolTest", &suite);
|
||||||
|
}
|
@ -13,9 +13,11 @@
|
|||||||
using BPrivate::Network::BHttpSession;
|
using BPrivate::Network::BHttpSession;
|
||||||
|
|
||||||
|
|
||||||
class HttpTest: public BTestCase {
|
class HttpProtocolTest: public BTestCase {
|
||||||
public:
|
public:
|
||||||
HttpTest(BHttpSession& session);
|
HttpProtocolTest();
|
||||||
|
|
||||||
|
void HttpHeaderTest();
|
||||||
|
|
||||||
static void AddTests(BTestSuite& suite);
|
static void AddTests(BTestSuite& suite);
|
||||||
|
|
@ -1,33 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2021 Haiku Inc. All rights reserved.
|
|
||||||
* Distributed under the terms of the MIT License.
|
|
||||||
*
|
|
||||||
* Authors:
|
|
||||||
* Niels Sascha Reedijk, niels.reedijk@gmail.com
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "HttpTest.h"
|
|
||||||
|
|
||||||
#include <cppunit/TestSuite.h>
|
|
||||||
|
|
||||||
using BPrivate::Network::BHttpSession;
|
|
||||||
|
|
||||||
|
|
||||||
HttpTest::HttpTest(BHttpSession& session)
|
|
||||||
:fSession(session)
|
|
||||||
{
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/* static */ void
|
|
||||||
HttpTest::AddTests(BTestSuite& parent)
|
|
||||||
{
|
|
||||||
CppUnit::TestSuite& suite = *new CppUnit::TestSuite("HttpTest");
|
|
||||||
|
|
||||||
BHttpSession session;
|
|
||||||
|
|
||||||
HttpTest* httpTest = new HttpTest(session);
|
|
||||||
// leak for now
|
|
||||||
parent.addTest("HttpTest", &suite);
|
|
||||||
}
|
|
@ -4,10 +4,12 @@ if $(TARGET_PACKAGING_ARCH) != x86_gcc2 {
|
|||||||
# do not target the legacy platform
|
# do not target the legacy platform
|
||||||
UsePrivateHeaders netservices2 ;
|
UsePrivateHeaders netservices2 ;
|
||||||
|
|
||||||
|
SubDirC++Flags -std=gnu++17 ;
|
||||||
|
|
||||||
UnitTestLib netservicekit2test.so :
|
UnitTestLib netservicekit2test.so :
|
||||||
ServicesKitTestAddon.cpp
|
ServicesKitTestAddon.cpp
|
||||||
|
|
||||||
HttpTest.cpp
|
HttpProtocolTest.cpp
|
||||||
|
|
||||||
: be libnetservices2.a $(TARGET_NETWORK_LIBS) $(HAIKU_NETAPI_LIB)
|
: be libnetservices2.a $(TARGET_NETWORK_LIBS) $(HAIKU_NETAPI_LIB)
|
||||||
[ TargetLibstdc++ ]
|
[ TargetLibstdc++ ]
|
||||||
|
@ -7,7 +7,7 @@
|
|||||||
#include <TestSuite.h>
|
#include <TestSuite.h>
|
||||||
#include <TestSuiteAddon.h>
|
#include <TestSuiteAddon.h>
|
||||||
|
|
||||||
#include "HttpTest.h"
|
#include "HttpProtocolTest.h"
|
||||||
|
|
||||||
|
|
||||||
BTestSuite*
|
BTestSuite*
|
||||||
@ -15,7 +15,7 @@ getTestSuite()
|
|||||||
{
|
{
|
||||||
BTestSuite* suite = new BTestSuite("NetServices2Kit");
|
BTestSuite* suite = new BTestSuite("NetServices2Kit");
|
||||||
|
|
||||||
HttpTest::AddTests(*suite);
|
HttpProtocolTest::AddTests(*suite);
|
||||||
|
|
||||||
return suite;
|
return suite;
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user