BUG/MEDIUM: h1: ensure the chunk size parser can deal with full buffers
The HTTP/1 code always has the reserve left available so the buffer is
never full there. But with HTTP/2 we have to deal with full buffers,
and it happens that the chunk size parser cannot tell the difference
between a full buffer and an empty one since it compares the start and
the stop pointer.
Let's change this to instead deal with the number of bytes left to process.
As a side effect, this code ends up being about 10% faster than the previous
one, even on HTTP/1.
diff --git a/include/proto/h1.h b/include/proto/h1.h
index ef405c4..ada7d03 100644
--- a/include/proto/h1.h
+++ b/include/proto/h1.h
@@ -192,16 +192,18 @@
const char *ptr = b_ptr(buf, start);
const char *ptr_old = ptr;
const char *end = buf->data + buf->size;
- const char *ptr_stop = b_ptr(buf, stop);
unsigned int chunk = 0;
+ stop -= start; // bytes left
+ start = stop; // bytes to transfer
+
/* The chunk size is in the following form, though we are only
* interested in the size and CRLF :
* 1*HEXDIGIT *WSP *[ ';' extensions ] CRLF
*/
while (1) {
int c;
- if (ptr == ptr_stop)
+ if (!stop)
return 0;
c = hex2i(*ptr);
if (c < 0) /* not a hex digit anymore */
@@ -211,6 +213,7 @@
if (unlikely(chunk & 0xF8000000)) /* integer overflow will occur if result >= 2GB */
goto error;
chunk = (chunk << 4) + c;
+ stop--;
}
/* empty size not allowed */
@@ -220,7 +223,7 @@
while (HTTP_IS_SPHT(*ptr)) {
if (++ptr >= end)
ptr = buf->data;
- if (unlikely(ptr == ptr_stop))
+ if (--stop == 0)
return 0;
}
@@ -233,14 +236,15 @@
if (likely(*ptr == '\r')) {
if (++ptr >= end)
ptr = buf->data;
- if (ptr == ptr_stop)
+ if (--stop == 0)
return 0;
}
- if (unlikely(*ptr != '\n'))
+ if (*ptr != '\n')
goto error;
if (++ptr >= end)
ptr = buf->data;
+ --stop;
/* done */
break;
}
@@ -248,13 +252,13 @@
/* chunk extension, ends at next CRLF */
if (++ptr >= end)
ptr = buf->data;
- if (ptr == ptr_stop)
+ if (--stop == 0)
return 0;
while (!HTTP_IS_CRLF(*ptr)) {
if (++ptr >= end)
ptr = buf->data;
- if (ptr == ptr_stop)
+ if (--stop == 0)
return 0;
}
/* we have a CRLF now, loop above */
@@ -268,10 +272,10 @@
* or may not be present. Let's return the number of bytes parsed.
*/
*res = chunk;
- return (ptr - ptr_old) >= 0 ? (ptr - ptr_old) : (ptr - ptr_old + buf->size);
+ return start - stop;
error:
*res = 0; // just to stop gcc's -Wuninitialized warning :-(
- return -buffer_count(buf, ptr, ptr_stop);
+ return -stop;
}
/* initializes an H1 message */