Rocket.Chat.ReactNative/ios/Pods/Flipper-RSocket/rsocket/framing/Frame.h

440 lines
13 KiB
C++

// Copyright (c) Facebook, Inc. and its affiliates.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#pragma once
#include <array>
#include <iosfwd>
#include <limits>
#include <folly/io/IOBuf.h>
#include <folly/io/IOBufQueue.h>
#include "rsocket/Payload.h"
#include "rsocket/framing/ErrorCode.h"
#include "rsocket/framing/FrameFlags.h"
#include "rsocket/framing/FrameHeader.h"
#include "rsocket/framing/FrameType.h"
#include "rsocket/framing/ProtocolVersion.h"
#include "rsocket/framing/ResumeIdentificationToken.h"
namespace folly {
template <typename V>
class Optional;
namespace io {
class Cursor;
class QueueAppender;
} // namespace io
} // namespace folly
namespace rsocket {
namespace detail {
FrameFlags getFlags(const Payload&);
void checkFlags(const Payload&, FrameFlags);
} // namespace detail
using ResumePosition = int64_t;
constexpr ResumePosition kUnspecifiedResumePosition = -1;
/// Frames do not form hierarchy, as we never perform type erasure on a frame.
/// We use inheritance only to save code duplication.
///
/// Since frames are only meaningful for stream automata on both ends of a
/// stream, intermediate layers that are frame-type-agnostic pass around
/// serialized frame.
class Frame_REQUEST_N {
public:
/*
* Maximum value for ReactiveSocket Subscription::request.
* Value is a signed int, however negative values are not allowed.
*
* n.b. this is less than size_t because of the Frame encoding restrictions.
*/
static constexpr int64_t kMaxRequestN = std::numeric_limits<int32_t>::max();
Frame_REQUEST_N() = default;
Frame_REQUEST_N(StreamId streamId, uint32_t requestN)
: header_(FrameType::REQUEST_N, FrameFlags::EMPTY_, streamId),
requestN_(requestN) {
DCHECK(requestN_ > 0);
DCHECK(requestN_ <= kMaxRequestN);
}
FrameHeader header_;
uint32_t requestN_{};
};
std::ostream& operator<<(std::ostream&, const Frame_REQUEST_N&);
class Frame_REQUEST_Base {
public:
Frame_REQUEST_Base() = default;
Frame_REQUEST_Base(
FrameType frameType,
StreamId streamId,
FrameFlags flags,
uint32_t requestN,
Payload payload)
: header_(frameType, flags | detail::getFlags(payload), streamId),
requestN_(requestN),
payload_(std::move(payload)) {
detail::checkFlags(payload_, header_.flags);
// TODO: DCHECK(requestN_ > 0);
DCHECK(requestN_ <= Frame_REQUEST_N::kMaxRequestN);
}
/// For compatibility with other data-carrying frames.
Frame_REQUEST_Base(
FrameType frameType,
StreamId streamId,
FrameFlags flags,
Payload payload)
: Frame_REQUEST_Base(frameType, streamId, flags, 0, std::move(payload)) {}
FrameHeader header_;
uint32_t requestN_{};
Payload payload_;
};
std::ostream& operator<<(std::ostream&, const Frame_REQUEST_Base&);
class Frame_REQUEST_STREAM : public Frame_REQUEST_Base {
public:
constexpr static const FrameFlags AllowedFlags =
FrameFlags::METADATA | FrameFlags::FOLLOWS;
Frame_REQUEST_STREAM() = default;
Frame_REQUEST_STREAM(
StreamId streamId,
FrameFlags flags,
uint32_t requestN,
Payload payload)
: Frame_REQUEST_Base(
FrameType::REQUEST_STREAM,
streamId,
flags,
requestN,
std::move(payload)) {}
/// For compatibility with other data-carrying frames.
Frame_REQUEST_STREAM(StreamId streamId, FrameFlags flags, Payload payload)
: Frame_REQUEST_STREAM(
streamId,
flags & AllowedFlags,
0,
std::move(payload)) {}
};
std::ostream& operator<<(std::ostream& os, const Frame_REQUEST_STREAM& frame);
class Frame_REQUEST_CHANNEL : public Frame_REQUEST_Base {
public:
constexpr static const FrameFlags AllowedFlags =
FrameFlags::METADATA | FrameFlags::FOLLOWS | FrameFlags::COMPLETE;
Frame_REQUEST_CHANNEL() = default;
Frame_REQUEST_CHANNEL(
StreamId streamId,
FrameFlags flags,
uint32_t requestN,
Payload payload)
: Frame_REQUEST_Base(
FrameType::REQUEST_CHANNEL,
streamId,
flags,
requestN,
std::move(payload)) {}
/// For compatibility with other data-carrying frames.
Frame_REQUEST_CHANNEL(StreamId streamId, FrameFlags flags, Payload payload)
: Frame_REQUEST_CHANNEL(
streamId,
flags & AllowedFlags,
0,
std::move(payload)) {}
};
std::ostream& operator<<(std::ostream&, const Frame_REQUEST_CHANNEL&);
class Frame_REQUEST_RESPONSE {
public:
constexpr static const FrameFlags AllowedFlags =
FrameFlags::METADATA | FrameFlags::FOLLOWS;
Frame_REQUEST_RESPONSE() = default;
Frame_REQUEST_RESPONSE(StreamId streamId, FrameFlags flags, Payload payload)
: header_(
FrameType::REQUEST_RESPONSE,
(flags & AllowedFlags) | detail::getFlags(payload),
streamId),
payload_(std::move(payload)) {
detail::checkFlags(payload_, header_.flags);
}
FrameHeader header_;
Payload payload_;
};
std::ostream& operator<<(std::ostream&, const Frame_REQUEST_RESPONSE&);
class Frame_REQUEST_FNF {
public:
constexpr static const FrameFlags AllowedFlags =
FrameFlags::METADATA | FrameFlags::FOLLOWS;
Frame_REQUEST_FNF() = default;
Frame_REQUEST_FNF(StreamId streamId, FrameFlags flags, Payload payload)
: header_(
FrameType::REQUEST_FNF,
(flags & AllowedFlags) | detail::getFlags(payload),
streamId),
payload_(std::move(payload)) {
detail::checkFlags(payload_, header_.flags);
}
FrameHeader header_;
Payload payload_;
};
std::ostream& operator<<(std::ostream&, const Frame_REQUEST_FNF&);
class Frame_METADATA_PUSH {
public:
Frame_METADATA_PUSH() {}
explicit Frame_METADATA_PUSH(std::unique_ptr<folly::IOBuf> metadata)
: header_(FrameType::METADATA_PUSH, FrameFlags::METADATA, 0),
metadata_(std::move(metadata)) {
CHECK(metadata_);
}
FrameHeader header_;
std::unique_ptr<folly::IOBuf> metadata_;
};
std::ostream& operator<<(std::ostream&, const Frame_METADATA_PUSH&);
class Frame_CANCEL {
public:
Frame_CANCEL() = default;
explicit Frame_CANCEL(StreamId streamId)
: header_(FrameType::CANCEL, FrameFlags::EMPTY_, streamId) {}
FrameHeader header_;
};
std::ostream& operator<<(std::ostream&, const Frame_CANCEL&);
class Frame_PAYLOAD {
public:
constexpr static const FrameFlags AllowedFlags = FrameFlags::METADATA |
FrameFlags::FOLLOWS | FrameFlags::COMPLETE | FrameFlags::NEXT;
Frame_PAYLOAD() = default;
Frame_PAYLOAD(StreamId streamId, FrameFlags flags, Payload payload)
: header_(
FrameType::PAYLOAD,
(flags & AllowedFlags) | detail::getFlags(payload),
streamId),
payload_(std::move(payload)) {
detail::checkFlags(payload_, header_.flags);
}
static Frame_PAYLOAD complete(StreamId streamId);
FrameHeader header_;
Payload payload_;
};
std::ostream& operator<<(std::ostream&, const Frame_PAYLOAD&);
class Frame_ERROR {
public:
constexpr static const FrameFlags AllowedFlags = FrameFlags::METADATA;
Frame_ERROR() = default;
Frame_ERROR(StreamId streamId, ErrorCode errorCode, Payload payload)
: header_(FrameType::ERROR, detail::getFlags(payload), streamId),
errorCode_(errorCode),
payload_(std::move(payload)) {}
// Connection errors.
static Frame_ERROR invalidSetup(folly::StringPiece);
static Frame_ERROR unsupportedSetup(folly::StringPiece);
static Frame_ERROR rejectedSetup(folly::StringPiece);
static Frame_ERROR rejectedResume(folly::StringPiece);
static Frame_ERROR connectionError(folly::StringPiece);
// Stream errors.
static Frame_ERROR applicationError(StreamId, folly::StringPiece);
static Frame_ERROR applicationError(StreamId, Payload&&);
static Frame_ERROR rejected(StreamId, folly::StringPiece);
static Frame_ERROR canceled(StreamId, folly::StringPiece);
static Frame_ERROR invalid(StreamId, folly::StringPiece);
private:
static Frame_ERROR connectionErr(ErrorCode, folly::StringPiece);
static Frame_ERROR streamErr(ErrorCode, folly::StringPiece, StreamId);
public:
FrameHeader header_;
ErrorCode errorCode_{};
Payload payload_;
};
std::ostream& operator<<(std::ostream&, const Frame_ERROR&);
class Frame_KEEPALIVE {
public:
constexpr static const FrameFlags AllowedFlags =
FrameFlags::KEEPALIVE_RESPOND;
Frame_KEEPALIVE() = default;
Frame_KEEPALIVE(
FrameFlags flags,
ResumePosition position,
std::unique_ptr<folly::IOBuf> data)
: header_(FrameType::KEEPALIVE, flags & AllowedFlags, 0),
position_(position),
data_(std::move(data)) {}
FrameHeader header_;
ResumePosition position_{};
std::unique_ptr<folly::IOBuf> data_;
};
std::ostream& operator<<(std::ostream&, const Frame_KEEPALIVE&);
class SetupParameters;
class Frame_SETUP {
public:
constexpr static const FrameFlags AllowedFlags =
FrameFlags::METADATA | FrameFlags::RESUME_ENABLE | FrameFlags::LEASE;
constexpr static const uint32_t kMaxKeepaliveTime =
std::numeric_limits<int32_t>::max();
constexpr static const uint32_t kMaxLifetime =
std::numeric_limits<int32_t>::max();
Frame_SETUP() = default;
Frame_SETUP(
FrameFlags flags,
uint16_t versionMajor,
uint16_t versionMinor,
uint32_t keepaliveTime,
uint32_t maxLifetime,
const ResumeIdentificationToken& token,
std::string metadataMimeType,
std::string dataMimeType,
Payload payload)
: header_(
FrameType::SETUP,
(flags & AllowedFlags) | detail::getFlags(payload),
0),
versionMajor_(versionMajor),
versionMinor_(versionMinor),
keepaliveTime_(keepaliveTime),
maxLifetime_(maxLifetime),
token_(token),
metadataMimeType_(metadataMimeType),
dataMimeType_(dataMimeType),
payload_(std::move(payload)) {
detail::checkFlags(payload_, header_.flags);
DCHECK(keepaliveTime_ > 0);
DCHECK(maxLifetime_ > 0);
DCHECK(keepaliveTime_ <= kMaxKeepaliveTime);
DCHECK(maxLifetime_ <= kMaxLifetime);
}
void moveToSetupPayload(SetupParameters& setupPayload);
FrameHeader header_;
uint16_t versionMajor_{};
uint16_t versionMinor_{};
uint32_t keepaliveTime_{};
uint32_t maxLifetime_{};
ResumeIdentificationToken token_;
std::string metadataMimeType_;
std::string dataMimeType_;
Payload payload_;
};
std::ostream& operator<<(std::ostream&, const Frame_SETUP&);
/// @}
class Frame_LEASE {
public:
constexpr static const FrameFlags AllowedFlags = FrameFlags::METADATA;
constexpr static const uint32_t kMaxTtl = std::numeric_limits<int32_t>::max();
constexpr static const uint32_t kMaxNumRequests =
std::numeric_limits<int32_t>::max();
Frame_LEASE() = default;
Frame_LEASE(
uint32_t ttl,
uint32_t numberOfRequests,
std::unique_ptr<folly::IOBuf> metadata = std::unique_ptr<folly::IOBuf>())
: header_(
FrameType::LEASE,
metadata ? FrameFlags::METADATA : FrameFlags::EMPTY_,
0),
ttl_(ttl),
numberOfRequests_(numberOfRequests),
metadata_(std::move(metadata)) {
DCHECK(ttl_ > 0);
DCHECK(numberOfRequests_ > 0);
DCHECK(ttl_ <= kMaxTtl);
DCHECK(numberOfRequests_ <= kMaxNumRequests);
}
FrameHeader header_;
uint32_t ttl_{};
uint32_t numberOfRequests_{};
std::unique_ptr<folly::IOBuf> metadata_;
};
std::ostream& operator<<(std::ostream&, const Frame_LEASE&);
/// @}
class Frame_RESUME {
public:
Frame_RESUME() = default;
Frame_RESUME(
const ResumeIdentificationToken& token,
ResumePosition lastReceivedServerPosition,
ResumePosition clientPosition,
ProtocolVersion protocolVersion)
: header_(FrameType::RESUME, FrameFlags::EMPTY_, 0),
versionMajor_(protocolVersion.major),
versionMinor_(protocolVersion.minor),
token_(token),
lastReceivedServerPosition_(lastReceivedServerPosition),
clientPosition_(clientPosition) {}
FrameHeader header_;
uint16_t versionMajor_{};
uint16_t versionMinor_{};
ResumeIdentificationToken token_;
ResumePosition lastReceivedServerPosition_{};
ResumePosition clientPosition_{};
};
std::ostream& operator<<(std::ostream&, const Frame_RESUME&);
/// @}
class Frame_RESUME_OK {
public:
Frame_RESUME_OK() = default;
explicit Frame_RESUME_OK(ResumePosition position)
: header_(FrameType::RESUME_OK, FrameFlags::EMPTY_, 0),
position_(position) {}
FrameHeader header_;
ResumePosition position_{};
};
std::ostream& operator<<(std::ostream&, const Frame_RESUME_OK&);
} // namespace rsocket