nginx uses bitwise operations for HTTP method parsing
As in every HTTP server, method parsing is a pretty “hot” code path. That’s why it seems to be highly optimized:
#if (NGX_HAVE_LITTLE_ENDIAN && NGX_HAVE_NONALIGNED)
#define ngx_str3_cmp(m, c0, c1, c2, c3) \
*(uint32_t *) m == ((c3 << 24) | (c2 << 16) | (c1 << 8) | c0)
#define ngx_str3Ocmp(m, c0, c1, c2, c3) \
*(uint32_t *) m == ((c3 << 24) | (c2 << 16) | (c1 << 8) | c0)
#define ngx_str4cmp(m, c0, c1, c2, c3) \
*(uint32_t *) m == ((c3 << 24) | (c2 << 16) | (c1 << 8) | c0)
#define ngx_str5cmp(m, c0, c1, c2, c3, c4) \
*(uint32_t *) m == ((c3 << 24) | (c2 << 16) | (c1 << 8) | c0) \
&& m[4] == c4
#define ngx_str6cmp(m, c0, c1, c2, c3, c4, c5) \
*(uint32_t *) m == ((c3 << 24) | (c2 << 16) | (c1 << 8) | c0) \
&& (((uint32_t *) m)[1] & 0xffff) == ((c5 << 8) | c4)
#define ngx_str7_cmp(m, c0, c1, c2, c3, c4, c5, c6, c7) \
*(uint32_t *) m == ((c3 << 24) | (c2 << 16) | (c1 << 8) | c0) \
&& ((uint32_t *) m)[1] == ((c7 << 24) | (c6 << 16) | (c5 << 8) | c4)
#define ngx_str8cmp(m, c0, c1, c2, c3, c4, c5, c6, c7) \
*(uint32_t *) m == ((c3 << 24) | (c2 << 16) | (c1 << 8) | c0) \
&& ((uint32_t *) m)[1] == ((c7 << 24) | (c6 << 16) | (c5 << 8) | c4)
#define ngx_str9cmp(m, c0, c1, c2, c3, c4, c5, c6, c7, c8) \
*(uint32_t *) m == ((c3 << 24) | (c2 << 16) | (c1 << 8) | c0) \
&& ((uint32_t *) m)[1] == ((c7 << 24) | (c6 << 16) | (c5 << 8) | c4) \
&& m[8] == c8
#else /* !(NGX_HAVE_LITTLE_ENDIAN && NGX_HAVE_NONALIGNED) */
Instead of comparing 4 individual bytes, these macros “glue” them together in a 32-bit number and compare it to the (appropriately casted) string.
Wonder why there is ngx_str3Ocmp
? The non-optimized version of it (in the “else”) skips the second character:
#define ngx_str3Ocmp(m, c0, c1, c2, c3) \
m[0] == c0 && m[2] == c2 && m[3] == c3
And later it’s used to skip duplicate checks for all methods with an “O” in second position:
if (m[1] == 'O') {
if (ngx_str3Ocmp(m, 'P', 'O', 'S', 'T')) {
r->method = NGX_HTTP_POST;
break;
}
if (ngx_str3Ocmp(m, 'C', 'O', 'P', 'Y')) {
r->method = NGX_HTTP_COPY;
break;
}
if (ngx_str3Ocmp(m, 'M', 'O', 'V', 'E')) {
r->method = NGX_HTTP_MOVE;
break;
}
if (ngx_str3Ocmp(m, 'L', 'O', 'C', 'K')) {
r->method = NGX_HTTP_LOCK;
break;
}
}
You can take a look here. That’s some pretty impressive level of optimization!