Make that in batch

This commit is contained in:
uNetworkingAB
2022-10-30 21:10:01 +01:00
committed by GitHub
parent c613a4cb9a
commit fc51d2b4d6
+36 -8
View File
@@ -203,17 +203,43 @@ private:
((x > 96) & (x < '{'));
}
static inline bool hasLess(uint64_t word) {
return (word - ~0UL / 255 * 32) & ~word & ~0UL / 255 * 128;
static inline uint64_t hasLess(uint64_t x, uint64_t n) {
return (((x)-~0UL/255*(n))&~(x)&~0UL/255*128);
}
static inline uint64_t hasMore(uint64_t x, uint64_t n) {
return (((x)+~0UL/255*(127-(n))|(x))&~0UL/255*128);
}
static inline uint64_t hasBetween(uint64_t x, uint64_t m, uint64_t n) {
return ((~0UL/255*(127+(n))-((x)&~0UL/255*127)&~(x)&((x)&~0UL/255*127)+~0UL/255*(127-(m)))&~0UL/255*128);
}
static inline bool notFieldNameWord(uint64_t x) {
return hasLess(x, '-') |
hasBetween(x, '-', '0') |
hasBetween(x, '9', 'A') |
hasBetween(x, 'Z', 'a') |
hasMore(x, 'z');
}
static inline void *consumeFieldName(char *p) {
for (; true; p += 8) {
if (notFieldNameWord(*(uint64_t *)p)) {
while (isFieldNameByte(*(unsigned char *)p)) p++;
return (void *)p;
}
(*(uint64_t *)p) |= 0x2020202020202020ull;
}
}
/* RFC 9110: 5.5 Field Values (TLDR; anything above 31 is allowed; htab (9) is also allowed)
* Field values are usually constrained to the range of US-ASCII characters [...]
* Field values containing CR, LF, or NUL characters are invalid and dangerous [...]
* Field values containing other CTL characters are also invalid. */
static inline void *find_less(char *p, char */*end*/) {
static inline void *tryConsumeFieldValue(char *p) {
for (; true; p += 8) {
if (hasLess(*(uint64_t *)p)) {
if (hasLess(*(uint64_t *)p), 32) {
while (*(unsigned char *)p > 31) p++;
return (void *)p;
}
@@ -250,9 +276,11 @@ private:
* which is then removed, and our counters to flip due to overflow and we end up with a crash */
for (unsigned int i = 0; i < HttpRequest::MAX_HEADERS - 1; i++) {
/* Lower case and short scan until ':', or stop at \r (from previous scan) */
for (preliminaryKey = postPaddedBuffer; isFieldNameByte(*postPaddedBuffer); *(postPaddedBuffer++) |= 32);
/* Lower case and consume the field name */
preliminaryKey = postPaddedBuffer;
postPaddedBuffer = (char *) consumeFieldName(postPaddedBuffer);
headers->key = std::string_view(preliminaryKey, (size_t) (postPaddedBuffer - preliminaryKey));
/* Assume colon, space follows (this is fine as we have at least 2 bytes past) */
if (postPaddedBuffer[0] == ':' && postPaddedBuffer[1] == ' ') {
postPaddedBuffer += 2;
@@ -265,9 +293,9 @@ private:
for (; (*postPaddedBuffer == ':' || *(unsigned char *)postPaddedBuffer < 33) && *postPaddedBuffer != '\r'; postPaddedBuffer++);
}
preliminaryValue = postPaddedBuffer;
/* The goal of this call is to find next "\r\n", fast */
/* The goal of this call is to find next "\r\n", or any invalid field value chars, fast */
retry:
postPaddedBuffer = (char *) find_less(postPaddedBuffer, end);
postPaddedBuffer = (char *) tryConsumeFieldValue(postPaddedBuffer);
/* If this is not CR then we caught some stinky invalid char on the way */
if (postPaddedBuffer[0] != '\r') {
/* If TAB then keep searching */