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> Defaults to an empty \ref BUrl </td>
|
||||
</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>
|
||||
<td> \ref Method() </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
|
||||
\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)
|
||||
\brief Set the \a method for this request.
|
||||
|
@ -23,6 +23,9 @@ namespace BPrivate {
|
||||
namespace Network {
|
||||
|
||||
|
||||
class BHttpFields;
|
||||
|
||||
|
||||
class BHttpMethod {
|
||||
public:
|
||||
// Constants for default methods in RFC 7230 section 4.2
|
||||
@ -92,11 +95,13 @@ public:
|
||||
|
||||
// Access
|
||||
bool IsEmpty() const noexcept;
|
||||
const BHttpFields& Fields() const noexcept;
|
||||
const BHttpMethod& Method() const noexcept;
|
||||
const BHttpRedirectOptions& Redirect() const noexcept;
|
||||
const BUrl& Url() const noexcept;
|
||||
|
||||
// Named Setters
|
||||
void SetFields(const BHttpFields& fields);
|
||||
void SetMethod(const BHttpMethod& method);
|
||||
void SetRedirect(const BHttpRedirectOptions& redirectOptions);
|
||||
void SetUrl(const BUrl& url);
|
||||
|
@ -157,12 +157,13 @@ BHttpMethod::Method() const noexcept
|
||||
static const BUrl kDefaultUrl = BUrl();
|
||||
static const BHttpMethod kDefaultMethod = BHttpMethod::Get;
|
||||
static const BHttpRedirectOptions kDefaultRedirectOptions = BHttpRedirectOptions();
|
||||
|
||||
static const BHttpFields kDefaultOptionalFields = BHttpFields();
|
||||
|
||||
struct BHttpRequest::Data {
|
||||
BUrl url = kDefaultUrl;
|
||||
BHttpMethod method = kDefaultMethod;
|
||||
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&
|
||||
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
|
||||
BHttpRequest::SetMethod(const BHttpMethod& method)
|
||||
{
|
||||
@ -326,6 +362,11 @@ BHttpRequest::SerializeHeaderTo(BDataIO* target) const
|
||||
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);
|
||||
return bytesWritten;
|
||||
}
|
||||
|
@ -276,12 +276,13 @@ HttpProtocolTest::HttpMethodTest()
|
||||
}
|
||||
|
||||
|
||||
constexpr std::string_view kHaikuGetRequestText =
|
||||
constexpr std::string_view kExpectedRequestText =
|
||||
"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";
|
||||
"Connection: close\r\n"
|
||||
"Api-Key: 01234567890abcdef\r\n\r\n";
|
||||
|
||||
|
||||
void
|
||||
@ -294,9 +295,22 @@ HttpProtocolTest::HttpRequestTest()
|
||||
request.SetUrl(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
|
||||
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
|
||||
HttpProtocolTest::HttpRequestStreamTest()
|
||||
{
|
||||
@ -336,11 +358,11 @@ HttpProtocolTest::HttpRequestStreamTest()
|
||||
|
||||
// Test streaming the request
|
||||
BHttpRequestStream requestStream(request);
|
||||
RequestStreamTestIO testIO(kHaikuGetRequestText.data());
|
||||
RequestStreamTestIO testIO(kExpectedStreamText.data());
|
||||
bool finished = false;
|
||||
ssize_t expectedBytesWritten = 8;
|
||||
ssize_t expectedTotalBytesWritten = 8;
|
||||
const ssize_t expectedTotalSize = kHaikuGetRequestText.size();
|
||||
const ssize_t expectedTotalSize = kExpectedStreamText.size();
|
||||
if (expectedTotalSize < 8) {
|
||||
expectedBytesWritten = expectedTotalSize;
|
||||
expectedTotalBytesWritten = expectedTotalSize;
|
||||
|
Loading…
Reference in New Issue
Block a user