8 #include "protocolhttp2.h" 9 #include "serverengine.h" 15 #define INT_MASK(bits) ((1 << (bits)) - 1) 21 hpackDecodeString(
unsigned char *src,
unsigned char *src_end,
QByteArray &value,
int len)
24 const HPackPrivate::HuffDecode *entry =
nullptr;
31 entry = HPackPrivate::huff_decode_table[state] + (*src >> 4);
33 if (entry->flags & HPackPrivate::HUFF_FAIL) {
38 if (entry->flags & HPackPrivate::HUFF_SYM) {
39 value.
append(
char(entry->sym));
42 entry = HPackPrivate::huff_decode_table[entry->state] + (*src & 0x0f);
44 if (entry->flags & HPackPrivate::HUFF_FAIL) {
49 if ((entry->flags & HPackPrivate::HUFF_SYM) != 0) {
50 value.
append(
char(entry->sym));
53 }
while (++src < src_end);
58 if ((entry->flags & HPackPrivate::HUFF_ACCEPTED) == 0) {
72 decodeUInt16(
unsigned char *src,
const unsigned char *src_end, quint16 &dst, quint8 mask)
80 if (++src >= src_end) {
85 dst += (*src & 0x7f) << M;
87 }
while (*src & 0x80);
93 void encodeUInt16(
QByteArray &buf,
int I, quint8 mask)
103 buf.
append(
char((I & 0x7f) | 0x80));
112 encodeUInt16(buf, key.
length(), INT_MASK(7));
113 for (
auto keyIt : key) {
114 if (keyIt.isLetter()) {
115 buf.
append(keyIt.toLower().toLatin1());
116 }
else if (keyIt == u
'_') {
119 buf.
append(keyIt.toLatin1());
124 unsigned char *parse_string(
QByteArray &dst,
unsigned char *buf,
const quint8 *itEnd)
128 bool huffmanDecode = *buf & 0x80;
130 buf = decodeUInt16(buf, itEnd, str_len, INT_MASK(7));
136 buf = hpackDecodeString(buf, buf + str_len, dst, str_len);
141 if (buf + str_len <= itEnd) {
142 dst =
QByteArray(reinterpret_cast<const char *>(buf), str_len);
151 unsigned char *parse_string_key(
QByteArray &dst, quint8 *buf,
const quint8 *itEnd)
154 bool huffmanDecode = *buf & 0x80;
156 buf = decodeUInt16(buf, itEnd, str_len, INT_MASK(7));
162 buf = hpackDecodeString(buf, buf + str_len, dst, str_len);
167 if (buf + str_len <= itEnd) {
168 itEnd = buf + str_len;
170 while (buf < itEnd) {
175 dst += char(*(buf++));
189 if (!stream->gotPath && !v.
isEmpty()) {
190 int leadingSlash = 0;
191 while (leadingSlash < v.
size() && v.
at(leadingSlash) == u
'/') {
204 stream->gotPath =
true;
207 }
else if (k.
compare(
":method") == 0) {
212 }
else if (k.
compare(
":authority") == 0) {
215 }
else if (k.
compare(
":scheme") == 0) {
216 if (stream->scheme.
isEmpty()) {
232 if (k.
compare(
"content-length") == 0) {
239 HPack::HPack(
int maxTableSize)
240 : m_currentMaxDynamicTableSize(maxTableSize)
241 , m_maxTableSize(maxTableSize)
253 }
else if (status == 204) {
255 }
else if (status == 206) {
257 }
else if (status == 304) {
259 }
else if (status == 400) {
261 }
else if (status == 404) {
263 }
else if (status == 500) {
269 encodeUInt16(buf, statusStr.
length(), INT_MASK(4));
273 bool hasDate =
false;
274 const auto headersData = headers.
data();
275 for (
const auto &[key, value] : headersData) {
280 auto staticIt = HPackPrivate::hpackStaticHeadersCode.constFind(key);
281 if (staticIt != HPackPrivate::hpackStaticHeadersCode.constEnd()) {
282 buf.
append(staticIt.value(), 2);
284 encodeUInt16(buf, value.
length(), INT_MASK(7));
290 encodeUInt16(buf, value.
length(), INT_MASK(7));
297 if (date.
length() != 29) {
304 buf.
append(
"\x0f\x12\x1d", 3);
311 ErrorProtocolError = 0x1,
312 ErrorInternalError = 0x2,
313 ErrorFlowControlError = 0x3,
314 ErrorSettingsTimeout = 0x4,
315 ErrorStreamClosed = 0x5,
316 ErrorFrameSizeError = 0x6,
317 ErrorRefusedStream = 0x7,
319 ErrorCompressionError = 0x9,
320 ErrorConnectError = 0xA,
321 ErrorEnhanceYourCalm = 0xB,
322 ErrorInadequateSecurity = 0xC,
323 ErrorHttp11Required = 0xD
326 int HPack::decode(
unsigned char *it,
const unsigned char *itEnd,
H2Stream *stream)
328 bool pseudoHeadersAllowed =
true;
329 bool allowedToUpdate =
true;
333 it = decodeUInt16(it, itEnd, intValue, INT_MASK(7));
336 if (!it || intValue == 0) {
337 return ErrorCompressionError;
346 if (intValue < qint64(m_dynamicTable.size())) {
347 const auto h = m_dynamicTable[intValue];
351 return ErrorCompressionError;
354 const auto h = HPackPrivate::hpackStaticHeaders[intValue];
361 if (!pseudoHeadersAllowed || !validPseudoHeader(key, value, stream)) {
362 return ErrorProtocolError;
365 if (!validHeader(key, value)) {
366 return ErrorProtocolError;
368 pseudoHeadersAllowed =
false;
369 consumeHeader(key, value, stream);
373 bool addToDynamicTable =
false;
376 it = decodeUInt16(it, itEnd, intValue, INT_MASK(6));
378 return ErrorCompressionError;
380 addToDynamicTable =
true;
383 }
else if (*it & 0x20) {
384 it = decodeUInt16(it, itEnd, intValue, INT_MASK(5));
388 if (!it || intValue > m_maxTableSize || !allowedToUpdate) {
389 return ErrorCompressionError;
392 m_currentMaxDynamicTableSize = intValue;
393 while (m_dynamicTableSize > m_currentMaxDynamicTableSize &&
394 !m_dynamicTable.empty()) {
395 auto header = m_dynamicTable.takeLast();
396 m_dynamicTableSize -= header.key.length() + header.value.length() + 32;
403 it = decodeUInt16(it, itEnd, intValue, INT_MASK(4));
405 return ErrorCompressionError;
411 if (addToDynamicTable) {
414 if (intValue - 62 < qint64(m_dynamicTable.size())) {
415 const auto h = m_dynamicTable[intValue - 62];
418 return ErrorCompressionError;
421 return ErrorCompressionError;
423 }
else if (intValue != 0) {
424 const auto h = HPackPrivate::hpackStaticHeaders[intValue];
427 it = parse_string_key(key, it, itEnd);
429 return ErrorProtocolError;
434 it = parse_string(value, it, itEnd);
436 return ErrorCompressionError;
440 if (!pseudoHeadersAllowed || !validPseudoHeader(key, value, stream)) {
441 return ErrorProtocolError;
444 if (!validHeader(key, value)) {
445 return ErrorProtocolError;
447 pseudoHeadersAllowed =
false;
448 consumeHeader(key, value, stream);
452 if (addToDynamicTable) {
454 while (size + m_dynamicTableSize > m_currentMaxDynamicTableSize &&
455 !m_dynamicTable.empty()) {
457 m_dynamicTableSize -= entry.key.
length() + entry.value.
length() + 32;
460 if (size + m_dynamicTableSize <= m_currentMaxDynamicTableSize) {
461 m_dynamicTable.prepend({key, value});
462 m_dynamicTableSize += size;
469 allowedToUpdate =
false;
473 return ErrorProtocolError;
bool isUpper(char32_t ucs4)
void reserve(qsizetype size)
char at(qsizetype i) const const
void setPath(char *rawPath, int len)
bool isEmpty() const const
bool startsWith(QByteArrayView bv) const const
qsizetype length() const const
int compare(QByteArrayView bv, Qt::CaseSensitivity cs) const const
qsizetype indexOf(QByteArrayView bv, qsizetype from) const const
QByteArray number(double n, char format, int precision)
The Cutelyst namespace holds all public Cutelyst API.
QByteArray mid(qsizetype pos, qsizetype len) const const
QByteArray & append(QByteArrayView data)
qlonglong toLongLong(bool *ok, int base) const const
QString fromLatin1(QByteArrayView str)
qsizetype length() const const
qsizetype size() const const