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,
196 bool methodFound =
false;
197 const char *
headerName[] = {
":authority",
":scheme",
":path"};
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) {
221 if (headerFound[
j]) {
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)
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)
qsizetype size() const
Returns the number of characters in this string.
bool operator==(const BitPattern &lhs, const BitPattern &rhs)
std::vector< HeaderField > HttpHeader
HeaderSize header_size(const HttpHeader &header)
HeaderSize entry_size(QByteArrayView name, QByteArrayView value)
QPair< bool, quint32 > HeaderSize
Combined button and popup list for selecting options.
static QString header(const QString &name)
EGLOutputLayerEXT EGLint EGLAttrib value
[5]
static QByteArray headerName(QNetworkRequest::KnownHeaders header)
GLenum GLuint GLintptr GLsizeiptr size
[1]