NetServices: add optional fields to BHttpRequest
Change-Id: I6228419a55c81203ce2c26827d17ff6a402d86c5
This commit is contained in:
parent
46b7da1f4f
commit
f751534257
@ -329,6 +329,12 @@ namespace Network {
|
|||||||
<td> The URL. This must start with http or https. </td>
|
<td> The URL. This must start with http or https. </td>
|
||||||
<td> Defaults to an empty \ref BUrl </td>
|
<td> Defaults to an empty \ref BUrl </td>
|
||||||
</tr>
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td> \ref Fields() </td>
|
||||||
|
<td> \ref SetFields() </td>
|
||||||
|
<td> Additional fields set in the request header. </td>
|
||||||
|
<td> Defaults with no additional fields </td>
|
||||||
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td> \ref Method() </td>
|
<td> \ref Method() </td>
|
||||||
<td> \ref SetMethod() </td>
|
<td> \ref SetMethod() </td>
|
||||||
@ -472,6 +478,16 @@ namespace Network {
|
|||||||
//! @{
|
//! @{
|
||||||
|
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\fn const BHttpFields& BHttpRequest::Fields() const noexcept
|
||||||
|
\brief Get the additional header fields set for the request.
|
||||||
|
|
||||||
|
The returned header fields may be empty if no additional header fields were set.
|
||||||
|
|
||||||
|
\since Haiku R1
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
\fn const BHttpMethod& BHttpRequest::Method() const noexcept
|
\fn const BHttpMethod& BHttpRequest::Method() const noexcept
|
||||||
\brief Get the current method for the request.
|
\brief Get the current method for the request.
|
||||||
@ -515,6 +531,26 @@ namespace Network {
|
|||||||
//! @{
|
//! @{
|
||||||
|
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\fn void BHttpRequest::SetFields(const BHttpFields &fields)
|
||||||
|
\brief Set additional header \a fields for this request.
|
||||||
|
|
||||||
|
There are a few reserved fields, which cannot be set as optional fields. These currently are:
|
||||||
|
* \c Host
|
||||||
|
* \c Accept
|
||||||
|
* \c Accept-Encoding
|
||||||
|
* \c Connection
|
||||||
|
|
||||||
|
\param fields Additional fields for the header of the request.
|
||||||
|
|
||||||
|
\exception std::bad_alloc This exception may be raised if it is impossible to allocate memory.
|
||||||
|
\exception BHttpFields::InvalidData This exception is raised when the \a fields contain
|
||||||
|
reserved fields.
|
||||||
|
|
||||||
|
\since Haiku R1
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
\fn void BHttpRequest::SetMethod(const BHttpMethod &method)
|
\fn void BHttpRequest::SetMethod(const BHttpMethod &method)
|
||||||
\brief Set the \a method for this request.
|
\brief Set the \a method for this request.
|
||||||
|
@ -23,6 +23,9 @@ namespace BPrivate {
|
|||||||
namespace Network {
|
namespace Network {
|
||||||
|
|
||||||
|
|
||||||
|
class BHttpFields;
|
||||||
|
|
||||||
|
|
||||||
class BHttpMethod {
|
class BHttpMethod {
|
||||||
public:
|
public:
|
||||||
// Constants for default methods in RFC 7230 section 4.2
|
// Constants for default methods in RFC 7230 section 4.2
|
||||||
@ -92,11 +95,13 @@ public:
|
|||||||
|
|
||||||
// Access
|
// Access
|
||||||
bool IsEmpty() const noexcept;
|
bool IsEmpty() const noexcept;
|
||||||
|
const BHttpFields& Fields() const noexcept;
|
||||||
const BHttpMethod& Method() const noexcept;
|
const BHttpMethod& Method() const noexcept;
|
||||||
const BHttpRedirectOptions& Redirect() const noexcept;
|
const BHttpRedirectOptions& Redirect() const noexcept;
|
||||||
const BUrl& Url() const noexcept;
|
const BUrl& Url() const noexcept;
|
||||||
|
|
||||||
// Named Setters
|
// Named Setters
|
||||||
|
void SetFields(const BHttpFields& fields);
|
||||||
void SetMethod(const BHttpMethod& method);
|
void SetMethod(const BHttpMethod& method);
|
||||||
void SetRedirect(const BHttpRedirectOptions& redirectOptions);
|
void SetRedirect(const BHttpRedirectOptions& redirectOptions);
|
||||||
void SetUrl(const BUrl& url);
|
void SetUrl(const BUrl& url);
|
||||||
|
@ -157,12 +157,13 @@ BHttpMethod::Method() const noexcept
|
|||||||
static const BUrl kDefaultUrl = BUrl();
|
static const BUrl kDefaultUrl = BUrl();
|
||||||
static const BHttpMethod kDefaultMethod = BHttpMethod::Get;
|
static const BHttpMethod kDefaultMethod = BHttpMethod::Get;
|
||||||
static const BHttpRedirectOptions kDefaultRedirectOptions = BHttpRedirectOptions();
|
static const BHttpRedirectOptions kDefaultRedirectOptions = BHttpRedirectOptions();
|
||||||
|
static const BHttpFields kDefaultOptionalFields = BHttpFields();
|
||||||
|
|
||||||
struct BHttpRequest::Data {
|
struct BHttpRequest::Data {
|
||||||
BUrl url = kDefaultUrl;
|
BUrl url = kDefaultUrl;
|
||||||
BHttpMethod method = kDefaultMethod;
|
BHttpMethod method = kDefaultMethod;
|
||||||
BHttpRedirectOptions redirectOptions;
|
BHttpRedirectOptions redirectOptions;
|
||||||
|
BHttpFields optionalFields;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
@ -200,6 +201,15 @@ BHttpRequest::IsEmpty() const noexcept
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
const BHttpFields&
|
||||||
|
BHttpRequest::Fields() const noexcept
|
||||||
|
{
|
||||||
|
if (!fData)
|
||||||
|
return kDefaultOptionalFields;
|
||||||
|
return fData->optionalFields;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
const BHttpMethod&
|
const BHttpMethod&
|
||||||
BHttpRequest::Method() const noexcept
|
BHttpRequest::Method() const noexcept
|
||||||
{
|
{
|
||||||
@ -227,6 +237,32 @@ BHttpRequest::Url() const noexcept
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static constexpr std::array<std::string_view, 4> fReservedOptionalFieldNames = {
|
||||||
|
"Host"sv,
|
||||||
|
"Accept"sv,
|
||||||
|
"Accept-Encoding"sv,
|
||||||
|
"Connection"sv
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
BHttpRequest::SetFields(const BHttpFields& fields)
|
||||||
|
{
|
||||||
|
if (!fData)
|
||||||
|
fData = std::make_unique<Data>();
|
||||||
|
|
||||||
|
for (auto& field: fields) {
|
||||||
|
if (std::find(fReservedOptionalFieldNames.begin(), fReservedOptionalFieldNames.end(),
|
||||||
|
field.Name()) != fReservedOptionalFieldNames.end())
|
||||||
|
{
|
||||||
|
std::string_view fieldName = field.Name();
|
||||||
|
throw BHttpFields::InvalidInput(__PRETTY_FUNCTION__, BString(fieldName.data(), fieldName.size()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fData->optionalFields = fields;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void
|
void
|
||||||
BHttpRequest::SetMethod(const BHttpMethod& method)
|
BHttpRequest::SetMethod(const BHttpMethod& method)
|
||||||
{
|
{
|
||||||
@ -326,6 +362,11 @@ BHttpRequest::SerializeHeaderTo(BDataIO* target) const
|
|||||||
bytesWritten += _write_to_dataio(target, "\r\n"sv);
|
bytesWritten += _write_to_dataio(target, "\r\n"sv);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for (const auto& field: fData->optionalFields) {
|
||||||
|
bytesWritten += _write_to_dataio(target, field.RawField());
|
||||||
|
bytesWritten += _write_to_dataio(target, "\r\n"sv);
|
||||||
|
}
|
||||||
|
|
||||||
bytesWritten += _write_to_dataio(target, "\r\n"sv);
|
bytesWritten += _write_to_dataio(target, "\r\n"sv);
|
||||||
return bytesWritten;
|
return bytesWritten;
|
||||||
}
|
}
|
||||||
|
@ -276,12 +276,13 @@ HttpProtocolTest::HttpMethodTest()
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
constexpr std::string_view kHaikuGetRequestText =
|
constexpr std::string_view kExpectedRequestText =
|
||||||
"GET / HTTP/1.1\r\n"
|
"GET / HTTP/1.1\r\n"
|
||||||
"Host: www.haiku-os.org\r\n"
|
"Host: www.haiku-os.org\r\n"
|
||||||
"Accept: *\r\n"
|
"Accept: *\r\n"
|
||||||
"Accept-Encoding: gzip\r\n"
|
"Accept-Encoding: gzip\r\n"
|
||||||
"Connection: close\r\n\r\n";
|
"Connection: close\r\n"
|
||||||
|
"Api-Key: 01234567890abcdef\r\n\r\n";
|
||||||
|
|
||||||
|
|
||||||
void
|
void
|
||||||
@ -294,9 +295,22 @@ HttpProtocolTest::HttpRequestTest()
|
|||||||
request.SetUrl(url);
|
request.SetUrl(url);
|
||||||
CPPUNIT_ASSERT(request.Url() == url);
|
CPPUNIT_ASSERT(request.Url() == url);
|
||||||
|
|
||||||
|
// Add Invalid HTTP fields (should throw)
|
||||||
|
try {
|
||||||
|
BHttpFields invalidField = {{"Host"sv, "haiku-os.org"sv}};
|
||||||
|
request.SetFields(invalidField);
|
||||||
|
CPPUNIT_FAIL("Should not be able to add the invalid \"Host\" field to a request");
|
||||||
|
} catch (BHttpFields::InvalidInput& e) {
|
||||||
|
// Correct; do nothing
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add valid HTTP field
|
||||||
|
BHttpFields validField = {{"Api-Key"sv, "01234567890abcdef"}};
|
||||||
|
request.SetFields(validField);
|
||||||
|
|
||||||
// Validate header serialization
|
// Validate header serialization
|
||||||
BString header = request.HeaderToString();
|
BString header = request.HeaderToString();
|
||||||
CPPUNIT_ASSERT(header.Compare(kHaikuGetRequestText.data(), kHaikuGetRequestText.size()) == 0);
|
CPPUNIT_ASSERT(header.Compare(kExpectedRequestText.data(), kExpectedRequestText.size()) == 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -326,6 +340,14 @@ private:
|
|||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
constexpr std::string_view kExpectedStreamText =
|
||||||
|
"GET / HTTP/1.1\r\n"
|
||||||
|
"Host: www.haiku-os.org\r\n"
|
||||||
|
"Accept: *\r\n"
|
||||||
|
"Accept-Encoding: gzip\r\n"
|
||||||
|
"Connection: close\r\n\r\n";
|
||||||
|
|
||||||
|
|
||||||
void
|
void
|
||||||
HttpProtocolTest::HttpRequestStreamTest()
|
HttpProtocolTest::HttpRequestStreamTest()
|
||||||
{
|
{
|
||||||
@ -336,11 +358,11 @@ HttpProtocolTest::HttpRequestStreamTest()
|
|||||||
|
|
||||||
// Test streaming the request
|
// Test streaming the request
|
||||||
BHttpRequestStream requestStream(request);
|
BHttpRequestStream requestStream(request);
|
||||||
RequestStreamTestIO testIO(kHaikuGetRequestText.data());
|
RequestStreamTestIO testIO(kExpectedStreamText.data());
|
||||||
bool finished = false;
|
bool finished = false;
|
||||||
ssize_t expectedBytesWritten = 8;
|
ssize_t expectedBytesWritten = 8;
|
||||||
ssize_t expectedTotalBytesWritten = 8;
|
ssize_t expectedTotalBytesWritten = 8;
|
||||||
const ssize_t expectedTotalSize = kHaikuGetRequestText.size();
|
const ssize_t expectedTotalSize = kExpectedStreamText.size();
|
||||||
if (expectedTotalSize < 8) {
|
if (expectedTotalSize < 8) {
|
||||||
expectedBytesWritten = expectedTotalSize;
|
expectedBytesWritten = expectedTotalSize;
|
||||||
expectedTotalBytesWritten = expectedTotalSize;
|
expectedTotalBytesWritten = expectedTotalSize;
|
||||||
|
Loading…
Reference in New Issue
Block a user