blob: ef5594817538b55a20e897cee0a5f4b7d186f05b [file] [log] [blame]
#ifndef QUICHE_HTTP2_ADAPTER_HEADER_VALIDATOR_H_
#define QUICHE_HTTP2_ADAPTER_HEADER_VALIDATOR_H_
#include <bitset>
#include <optional>
#include <string>
#include <vector>
#include "absl/strings/string_view.h"
#include "quiche/http2/adapter/header_validator_base.h"
#include "quiche/common/platform/api/quiche_export.h"
namespace http2 {
namespace adapter {
class QUICHE_EXPORT HeaderValidator : public HeaderValidatorBase {
public:
HeaderValidator() = default;
void StartHeaderBlock() override;
HeaderStatus ValidateSingleHeader(absl::string_view key,
absl::string_view value) override;
// Returns true if all required pseudoheaders and no extra pseudoheaders are
// present for the given header type.
bool FinishHeaderBlock(HeaderType type) override;
// Returns whether `name` is valid according to RFC 9110 Section 5.1.
// ':' is an invalid character, therefore HTTP/2 pseudo-headers must be
// validated with the leading colon removed.
static bool IsValidHeaderName(absl::string_view name);
// Returns whether `value` is valid according to RFC 9110 Section 5.5 and
// RFC 9113 Section 8.2.1.
static bool IsValidHeaderValue(absl::string_view value,
ObsTextOption ops_text_option);
// Returns whether `authority` is valid according to RFC 3986 Section 3.2.
static bool IsValidAuthority(absl::string_view authority);
// Returns whether `path` is valid according to RFC 3986 Section 3.3. May
// contain the query part of a URI.
static bool IsValidPath(absl::string_view path, bool allow_fragment);
private:
enum ContentLengthStatus {
CONTENT_LENGTH_OK,
CONTENT_LENGTH_SKIP, // Used to handle duplicate content length values.
CONTENT_LENGTH_ERROR,
};
ContentLengthStatus HandleContentLength(absl::string_view value);
bool ValidateAndSetAuthority(absl::string_view authority);
enum PseudoHeaderTag {
TAG_AUTHORITY = 0,
TAG_METHOD,
TAG_PATH,
TAG_PROTOCOL,
TAG_SCHEME,
TAG_STATUS,
TAG_UNKNOWN_EXTRA,
TAG_ENUM_SIZE,
};
void RecordPseudoHeader(PseudoHeaderTag tag);
using PseudoHeaderTagSet = std::bitset<TAG_ENUM_SIZE>;
enum PseudoHeaderState {
STATE_AUTHORITY_IS_NONEMPTY,
STATE_METHOD_IS_OPTIONS,
STATE_METHOD_IS_CONNECT,
STATE_PATH_IS_EMPTY,
STATE_PATH_IS_STAR,
STATE_PATH_INITIAL_SLASH,
STATE_ENUM_SIZE,
};
using PseudoHeaderStateSet = std::bitset<STATE_ENUM_SIZE>;
static bool ValidateRequestHeaders(
const PseudoHeaderTagSet& pseudo_headers,
const PseudoHeaderStateSet& pseudo_header_state,
bool allow_extended_connect);
static bool ValidateRequestTrailers(const PseudoHeaderTagSet& pseudo_headers);
static bool ValidateResponseHeaders(const PseudoHeaderTagSet& pseudo_headers);
static bool ValidateResponseTrailers(
const PseudoHeaderTagSet& pseudo_headers);
PseudoHeaderTagSet pseudo_headers_;
PseudoHeaderStateSet pseudo_header_state_;
std::string authority_;
};
} // namespace adapter
} // namespace http2
#endif // QUICHE_HTTP2_ADAPTER_HEADER_VALIDATOR_H_