7#include <QtCore/qbytearray.h>
8#include <QtCore/qdebug.h>
24 if (std::numeric_limits<quint32>::max() -
size.second < delta.second)
26 size.second += delta.second;
57const BitPattern Indexed = {1, 1};
58const BitPattern LiteralIncrementalIndexing = {1, 2};
59const BitPattern LiteralNoIndexing = {0, 4};
60const BitPattern LiteralNeverIndexing = {1, 4};
61const BitPattern SizeUpdate = {1, 3};
63bool is_literal_field(
const BitPattern &
pattern)
65 return pattern == LiteralIncrementalIndexing
67 ||
pattern == LiteralNeverIndexing;
70void write_bit_pattern(
const BitPattern &
pattern, BitOStream &outputStream)
75bool read_bit_pattern(
const BitPattern &
pattern, BitIStream &inputStream)
79 const quint32 bitsRead = inputStream.peekBits(inputStream.streamOffset(),
81 if (bitsRead !=
pattern.bitLength)
85 chunk >>= (8 - bitsRead);
89 inputStream.skipBits(
pattern.bitLength);
96 return name ==
":method" ||
name ==
":scheme" ||
97 name ==
":authority" ||
name ==
":path";
103 : lookupTable(
size, true ),
104 compressStrings(compress)
120 if (!encodeRequestPseudoHeaders(outputStream,
header))
123 for (
const auto &field :
header) {
124 if (is_request_pseudo_header(field.name))
127 if (!encodeHeaderField(outputStream, field))
141 if (!encodeResponsePseudoHeaders(outputStream,
header))
144 for (
const auto &field :
header) {
145 if (field.name ==
":status")
148 if (!encodeHeaderField(outputStream, field))
158 qDebug(
"failed to update own table size");
162 write_bit_pattern(SizeUpdate, outputStream);
163 outputStream.
write(newSize);
177 compressStrings = compress;
180bool Encoder::encodeRequestPseudoHeaders(
BitOStream &outputStream,
194 using size_type =
decltype(
header.size());
196 bool methodFound =
false;
197 constexpr QByteArrayView headerName[] = {
":authority",
":scheme",
":path"};
198 constexpr size_type nHeaders = std::size(headerName);
199 bool headerFound[nHeaders] = {};
201 for (
const auto &field :
header) {
202 if (field.name ==
":status") {
203 qCritical(
"invalid pseudo-header (:status) in a request");
207 if (field.name ==
":method") {
209 qCritical(
"only one :method pseudo-header is allowed");
213 if (!encodeMethod(outputStream, field))
216 }
else if (field.name ==
"cookie") {
219 for (size_type
j = 0;
j < nHeaders; ++
j) {
220 if (field.name == headerName[
j]) {
221 if (headerFound[
j]) {
222 qCritical() <<
"only one" << headerName[
j] <<
"pseudo-header is allowed";
225 if (!encodeHeaderField(outputStream, field))
227 headerFound[
j] =
true;
235 qCritical(
"mandatory :method pseudo-header not found");
240 for (size_type
i = 1;
i < nHeaders; ++
i) {
241 if (!headerFound[
i]) {
243 <<
"pseudo-header not found";
251bool Encoder::encodeHeaderField(BitOStream &outputStream,
const HeaderField &field)
259 if (
const auto index = lookupTable.
indexOf(field.name, field.value))
260 return encodeIndexedField(outputStream,
index);
262 if (
const auto index = lookupTable.
indexOf(field.name)) {
263 return encodeLiteralField(outputStream, LiteralIncrementalIndexing,
264 index, field.value, compressStrings);
267 return encodeLiteralField(outputStream, LiteralIncrementalIndexing,
268 field.name, field.value, compressStrings);
271bool Encoder::encodeMethod(BitOStream &outputStream,
const HeaderField &field)
276 return encodeIndexedField(outputStream,
index);
280 return encodeLiteralField(outputStream, LiteralIncrementalIndexing,
281 index, field.value, compressStrings);
284bool Encoder::encodeResponsePseudoHeaders(BitOStream &outputStream,
const HttpHeader &
header)
286 bool statusFound =
false;
287 for (
const auto &field :
header) {
288 if (is_request_pseudo_header(field.name)) {
289 qCritical() <<
"invalid pseudo-header" << field.name <<
"in http response";
293 if (field.name ==
":status") {
295 qDebug(
"only one :status pseudo-header is allowed");
298 if (!encodeHeaderField(outputStream, field))
301 }
else if (field.name ==
"cookie") {
307 qCritical(
"mandatory :status pseudo-header not found");
312bool Encoder::encodeIndexedField(BitOStream &outputStream,
quint32 index)
const
316 write_bit_pattern(Indexed, outputStream);
317 outputStream.write(
index);
322bool Encoder::encodeLiteralField(BitOStream &outputStream,
const BitPattern &fieldType,
324 bool withCompression)
326 Q_ASSERT(is_literal_field(fieldType));
331 if (outputStream.bitLength() % 8) {
336 if (fieldType == LiteralIncrementalIndexing) {
338 qDebug(
"failed to prepend a new field");
341 write_bit_pattern(fieldType, outputStream);
343 outputStream.write(0);
344 outputStream.write(
name, withCompression);
345 outputStream.write(
value, withCompression);
350bool Encoder::encodeLiteralField(BitOStream &outputStream,
const BitPattern &fieldType,
352 bool withCompression)
354 Q_ASSERT(is_literal_field(fieldType));
361 if (fieldType == LiteralIncrementalIndexing) {
363 qDebug(
"failed to prepend a new field");
366 write_bit_pattern(fieldType, outputStream);
367 outputStream.write(nameIndex);
368 outputStream.write(
value, withCompression);
382 if (read_bit_pattern(Indexed, inputStream)) {
383 if (!decodeIndexedField(inputStream))
385 }
else if (read_bit_pattern(LiteralIncrementalIndexing, inputStream)) {
386 if (!decodeLiteralField(LiteralIncrementalIndexing, inputStream))
388 }
else if (read_bit_pattern(LiteralNoIndexing, inputStream)) {
389 if (!decodeLiteralField(LiteralNoIndexing, inputStream))
391 }
else if (read_bit_pattern(LiteralNeverIndexing, inputStream)) {
392 if (!decodeLiteralField(LiteralNeverIndexing, inputStream))
394 }
else if (read_bit_pattern(SizeUpdate, inputStream)) {
395 if (!decodeSizeUpdate(inputStream))
417bool Decoder::decodeIndexedField(
BitIStream &inputStream)
431 return processDecodedField(Indexed,
name,
value);
433 handleStreamError(inputStream);
439bool Decoder::decodeSizeUpdate(BitIStream &inputStream)
443 if (inputStream.read(&maxSize)) {
450 handleStreamError(inputStream);
454bool Decoder::decodeLiteralField(
const BitPattern &fieldType, BitIStream &inputStream)
461 if (inputStream.read(&
index)) {
465 if (!inputStream.read(&
name)) {
466 handleStreamError(inputStream);
475 if (inputStream.read(&
value))
476 return processDecodedField(fieldType,
name,
value);
479 handleStreamError(inputStream);
484bool Decoder::processDecodedField(
const BitPattern &fieldType,
488 if (fieldType == LiteralIncrementalIndexing) {
493 header.push_back(HeaderField(
name,
value));
497void Decoder::handleStreamError(BitIStream &inputStream)
499 const auto errorCode(inputStream.error());
500 if (errorCode == StreamError::NoError)
510 enum PseudoHeaderEnum
517 std::array<std::optional<QByteArrayView>, std::size(
names)> pseudoHeaders{};
518 for (
const auto &field : requestHeader) {
521 const auto index = std::distance(std::begin(
names),
it);
522 if (field.value.isEmpty() || pseudoHeaders.at(
index).has_value())
524 pseudoHeaders[
index] = field.value;
528 auto optionalIsSet = [](
const auto &
x) {
return x.has_value(); };
529 if (!std::all_of(pseudoHeaders.begin(), pseudoHeaders.end(), optionalIsSet)) {
quint64 bitLength() const
quint64 streamOffset() const
bool read(quint32 *dstPtr)
quint32 dynamicTableSize() const
void setMaxDynamicTableSize(quint32 size)
bool decodeHeaderFields(class BitIStream &inputStream)
quint32 dynamicTableSize() const
void setCompressStrings(bool compress)
void setMaxDynamicTableSize(quint32 size)
bool encodeResponse(BitOStream &outputStream, const HttpHeader &header)
bool encodeRequest(class BitOStream &outputStream, const HttpHeader &header)
bool encodeSizeUpdate(BitOStream &outputStream, quint32 newSize)
Encoder(quint32 maxTableSize, bool compressStrings)
bool fieldName(quint32 index, QByteArray *dst) const
void setMaxDynamicTableSize(quint32 size)
bool updateDynamicTableSize(quint32 size)
quint32 indexOf(const QByteArray &name, const QByteArray &value) const
bool indexIsValid(quint32 index) const
bool field(quint32 index, QByteArray *name, QByteArray *value) const
quint32 dynamicDataSize() const
bool prependField(const QByteArray &name, const QByteArray &value)
bool isValid() const
Returns true if the URL is non-empty and valid; otherwise returns false.
void setScheme(const QString &scheme)
Sets the scheme of the URL to scheme.
void setAuthority(const QString &authority, ParsingMode mode=TolerantMode)
Sets the authority of the URL to authority.
void setPath(const QString &path, ParsingMode mode=DecodedMode)
Sets the path of the URL to path.
QSet< QString >::iterator it
bool operator==(const BitPattern &lhs, const BitPattern &rhs)
QPair< bool, quint32 > HeaderSize
std::vector< HeaderField > HttpHeader
HeaderSize header_size(const HttpHeader &header)
std::optional< QUrl > makePromiseKeyUrl(const HttpHeader &requestHeader)
HeaderSize entry_size(QByteArrayView name, QByteArrayView value)
Combined button and popup list for selecting options.
DBusConnection const char DBusError DBusBusType DBusError return DBusConnection DBusHandleMessageFunction void DBusFreeFunction return DBusConnection return DBusConnection return const char DBusError return DBusConnection DBusMessage dbus_uint32_t return DBusConnection dbus_bool_t DBusConnection DBusAddWatchFunction DBusRemoveWatchFunction DBusWatchToggledFunction void DBusFreeFunction return DBusConnection DBusDispatchStatusFunction void DBusFreeFunction DBusTimeout return DBusTimeout return DBusWatch return DBusWatch unsigned int return DBusError const DBusError return const DBusMessage return DBusMessage return DBusMessage return DBusMessage return DBusMessage return DBusMessage return DBusMessageIter int const void return DBusMessageIter DBusMessageIter return DBusMessageIter void DBusMessageIter void int return DBusMessage DBusMessageIter return DBusMessageIter return DBusMessageIter DBusMessageIter const char const char const char const char * method
static QString header(const QString &name)
EGLOutputLayerEXT EGLint EGLAttrib value
[5]
GLint GLint GLint GLint GLint x
[0]
GLenum GLuint GLintptr GLsizeiptr size
[1]
QUrl url("example.com")
[constructor-url-reference]