[multiple] optimize primitives, buffer_extend()

optimize buffer_* primitives

Other than buffer_string_set_length(), reallocate with one power-2 step
in size (or use the requested size, if larger).  This replaces the fixed
BUFFER_PIECE_SIZE round-up of only 64 bytes extension each reallocation,
which could lead to excessive reallocations in some scenarios.

buffer_extend() convenience routine to prep for batch append
(combines buffer_string_prepare_append() and buffer_commit())

mod_fastcgi, mod_scgi, mod_proxy and others now leverage buffer_extend()

mod_scgi directly performs little-endian encoding of short ints

http_response_write_header() optimizes writing response header,
leveraging buffer_extend()

modify mod_proxy to append line ends
similar to how it is done in http_response_write_header()
(removes one call to buffer_append_string_len())
This commit is contained in:
Glenn Strauss 2021-03-16 01:05:47 -04:00
parent f9cd50b782
commit 38c8735850
9 changed files with 161 additions and 190 deletions

View File

@ -64,7 +64,9 @@ void buffer_move(buffer * restrict b, buffer * restrict src) {
/* make sure buffer is at least "size" big + 1 for '\0'. keep old data */
__attribute_cold__
static void buffer_realloc(buffer * const b, const size_t len) {
__attribute_noinline__
__attribute_returns_nonnull__
static char* buffer_realloc(buffer * const restrict b, const size_t len) {
#define BUFFER_PIECE_SIZE 64uL /*(must be power-of-2)*/
const size_t sz = (len + 1 + BUFFER_PIECE_SIZE-1) & ~(BUFFER_PIECE_SIZE-1);
force_assert(sz > len);
@ -73,60 +75,80 @@ static void buffer_realloc(buffer * const b, const size_t len) {
b->ptr = realloc(b->ptr, sz);
force_assert(NULL != b->ptr);
}
__attribute_cold__
__attribute_noinline__
static void buffer_alloc_replace(buffer * const b, const size_t size) {
force_assert(NULL != b);
/*(discard old data so realloc() does not copy)*/
if (NULL != b->ptr) {
free(b->ptr);
b->ptr = NULL;
}
buffer_realloc(b, size);
}
char* buffer_string_prepare_copy(buffer * const b, const size_t size) {
if (NULL == b->ptr || size >= b->size) buffer_alloc_replace(b, size);
b->used = 0;
return b->ptr;
return b->ptr;
}
__attribute_cold__
__attribute_noinline__
__attribute_returns_nonnull__
static char* buffer_string_prepare_append_resize(buffer * const b, const size_t size) {
force_assert(NULL != b);
if (buffer_string_is_empty(b)) {
return buffer_string_prepare_copy(b, size);
} else {
/* not empty, b->used already includes a terminating 0 */
size_t req_size = b->used + size;
static char* buffer_alloc_replace(buffer * const restrict b, const size_t size) {
/*(discard old data so realloc() does not copy)*/
if (NULL != b->ptr) {
free(b->ptr);
b->ptr = NULL;
}
/*(note: if size larger than one lshift, use size instead of power-2)*/
return buffer_realloc(b, (b->size << 1) > size ? (b->size << 1)-1 : size);
}
/* check for overflow: unsigned overflow is defined to wrap around */
force_assert(req_size >= b->used);
char* buffer_string_prepare_copy(buffer * const b, const size_t size) {
b->used = 0;
return (size < b->size)
? b->ptr
: buffer_alloc_replace(b, size);
}
buffer_realloc(b, req_size);
__attribute_cold__
__attribute_noinline__
__attribute_returns_nonnull__
static char* buffer_string_prepare_append_resize(buffer * const restrict b, const size_t size) {
if (b->used < 2) /* buffer_string_is_empty(b) */
return buffer_string_prepare_copy(b, size);
return b->ptr + b->used - 1;
}
/* not empty, b->used already includes a terminating 0 */
/*(note: if size larger than one lshift, use size instead of power-2)*/
const size_t req_size = ((b->size << 1) - b->used > size)
? (b->size << 1)-1
: b->used + size;
/* check for overflow: unsigned overflow is defined to wrap around */
force_assert(req_size >= b->used);
return buffer_realloc(b, req_size) + b->used - 1;
}
char* buffer_string_prepare_append(buffer * const b, const size_t size) {
return (NULL != b->ptr && size < b->size - b->used)
? b->ptr + b->used - (0 != b->used)
const uint32_t len = b->used ? b->used-1 : 0;
return (b->size - len >= size + 1)
? b->ptr + len
: buffer_string_prepare_append_resize(b, size);
}
/*(prefer smaller code than inlining buffer_extend in many places in buffer.c)*/
__attribute_noinline__
char*
buffer_extend (buffer * const b, const size_t x)
{
/* extend buffer to append x (reallocate by power-2 (or larger), if needed)
* (combine buffer_string_prepare_append() and buffer_commit())
* (future: might make buffer.h static inline func for HTTP/1.1 performance)
* pre-sets '\0' byte and b->used (unlike buffer_string_prepare_append())*/
const uint32_t len = b->used ? b->used-1 : 0;
char * const s = (b->size - len >= x + 1)
? b->ptr + len
: buffer_string_prepare_append_resize(b, x);
b->used = len+x+1;
s[x] = '\0';
return s;
}
void buffer_string_set_length(buffer *b, uint32_t len) {
force_assert(NULL != b);
if (len >= b->size) buffer_realloc(b, len);
b->used = len + 1;
b->ptr[len] = '\0';
/*(intended for string truncate; prefer buffer_extend() to extend string)*/
/*(unlike others routines, this routine potentially extends string
* extra len + (up to) BUFFER_PIECE_SIZE without power-2 reallocation,
* but does not optimize realloc of empty string)*/
b->used = len + 1; /*(not resizing for power-2)*/
(len < b->size ? b->ptr : buffer_realloc(b, len))[len] = '\0';
}
void buffer_commit(buffer *b, size_t size)
@ -151,12 +173,13 @@ void buffer_copy_string(buffer * restrict b, const char * restrict s) {
buffer_copy_string_len(b, s, NULL != s ? strlen(s) : 0);
}
void buffer_copy_string_len(buffer * const restrict b, const char * const restrict s, const size_t s_len) {
if (NULL == b->ptr || s_len >= b->size) buffer_alloc_replace(b, s_len);
b->used = s_len + 1;
b->ptr[s_len] = '\0';
if (0 != s_len) memcpy(b->ptr, s, s_len); /*(s might be NULL)*/
void buffer_copy_string_len(buffer * const restrict b, const char * const restrict s, const size_t len) {
b->used = len + 1;
char * const restrict d = (len < b->size)
? b->ptr
: buffer_alloc_replace(b, len);
d[len] = '\0';
memcpy(d, s, len);
}
void buffer_append_string(buffer * restrict b, const char * restrict s) {
@ -174,28 +197,29 @@ void buffer_append_string(buffer * restrict b, const char * restrict s) {
* @param s_len size of the string (without the terminating \0)
*/
void buffer_append_string_len(buffer * const restrict b, const char * const restrict s, const size_t s_len) {
char * const target_buf = buffer_string_prepare_append(b, s_len);
b->used += s_len + (0 == b->used); /*(must include '\0' for append)*/
target_buf[s_len] = '\0';
/*(s might be NULL if 0 == s_len)*/
if (s_len) memcpy(target_buf, s, s_len);
void buffer_append_string_len(buffer * const restrict b, const char * const restrict s, const size_t len) {
memcpy(buffer_extend(b, len), s, len);
}
void buffer_append_path_len(buffer * restrict b, const char * restrict a, size_t alen) {
size_t blen = buffer_string_length(b);
int aslash = (alen && a[0] == '/');
buffer_string_prepare_append(b, alen+2); /*(+ '/' and + '\0' if 0 == blen)*/
if (blen && b->ptr[blen-1] == '/') {
if (aslash) --b->used;
char * restrict s = buffer_string_prepare_append(b, alen+1);
const int aslash = (alen && a[0] == '/');
if (b->used > 1 && s[-1] == '/') {
if (aslash) {
++a;
--alen;
}
}
else {
if (!b->used) ++b->used;
if (!aslash) b->ptr[++b->used - 2] = '/';
if (0 == b->used) b->used = 1;
if (!aslash) {
*s++ = '/';
++b->used;
}
}
memcpy(b->ptr+b->used-1, a, alen);
b->ptr[(b->used += alen)-1] = '\0';
b->used += alen;
s[alen] = '\0';
memcpy(s, a, alen);
}
void buffer_append_uint_hex_lc(buffer *b, uintmax_t value) {
@ -210,8 +234,7 @@ void buffer_append_uint_hex_lc(buffer *b, uintmax_t value) {
} while (0 != copy);
}
buf = buffer_string_prepare_append(b, shift >> 2); /*nibbles (4 bits)*/
buffer_commit(b, shift >> 2); /* will fill below */
buf = buffer_extend(b, shift >> 2); /*nibbles (4 bits)*/
while (shift > 0) {
shift -= 4;
@ -425,9 +448,7 @@ void buffer_substr_replace (buffer * const restrict b, const size_t offset,
void buffer_append_string_encoded_hex_lc(buffer * const restrict b, const char * const restrict s, size_t len) {
unsigned char * const p =
(unsigned char*) buffer_string_prepare_append(b, len*2);
buffer_commit(b, len*2); /* fill below */
unsigned char * const p = (unsigned char *)buffer_extend(b, len*2);
for (size_t i = 0; i < len; ++i) {
p[(i<<1)] = hex_chars_lc[(s[i] >> 4) & 0x0F];
p[(i<<1)+1] = hex_chars_lc[(s[i]) & 0x0F];
@ -435,9 +456,7 @@ void buffer_append_string_encoded_hex_lc(buffer * const restrict b, const char *
}
void buffer_append_string_encoded_hex_uc(buffer * const restrict b, const char * const restrict s, size_t len) {
unsigned char * const p =
(unsigned char*) buffer_string_prepare_append(b, len*2);
buffer_commit(b, len*2); /* fill below */
unsigned char * const p = (unsigned char *)buffer_extend(b, len*2);
for (size_t i = 0; i < len; ++i) {
p[(i<<1)] = hex_chars_uc[(s[i] >> 4) & 0x0F];
p[(i<<1)+1] = hex_chars_uc[(s[i]) & 0x0F];
@ -581,8 +600,7 @@ void buffer_append_string_encoded(buffer * const restrict b, const char * const
}
}
d = (unsigned char*) buffer_string_prepare_append(b, d_len);
buffer_commit(b, d_len); /* fill below */
d = (unsigned char*) buffer_extend(b, d_len);
for (ds = (unsigned char *)s, d_len = 0, ndx = 0; ndx < s_len; ds++, ndx++) {
if (map[*ds & 0xFF]) {
@ -636,8 +654,7 @@ void buffer_append_string_c_escaped(buffer * const restrict b, const char * cons
}
}
d = (unsigned char*) buffer_string_prepare_append(b, d_len);
buffer_commit(b, d_len); /* fill below */
d = (unsigned char*) buffer_extend(b, d_len);
for (ds = (unsigned char *)s, d_len = 0, ndx = 0; ndx < s_len; ds++, ndx++) {
if ((*ds < 0x20) /* control character */

View File

@ -62,6 +62,13 @@ char* buffer_string_prepare_copy(buffer *b, size_t size);
__attribute_returns_nonnull__
char* buffer_string_prepare_append(buffer *b, size_t size);
/* extend and modify buffer for immediate addition of x bytes (differs from
* buffer_string_prepare_append() which only ensures space is available)
* returns pointer to which callers should immediately write x bytes
*/
__attribute_returns_nonnull__
char* buffer_extend(buffer * const restrict b, size_t x);
/* use after prepare_(copy,append) when you have written data to the buffer
* to increase the buffer length by size. also sets the terminating zero.
* requires enough space is present for the terminating zero (prepare with the
@ -99,11 +106,11 @@ __attribute_cold__
void buffer_free_ptr(buffer *b);
void buffer_copy_string(buffer * restrict b, const char * restrict s);
void buffer_copy_string_len(buffer * restrict b, const char * restrict s, size_t s_len);
void buffer_copy_string_len(buffer * restrict b, const char * restrict s, size_t len);
static inline void buffer_copy_buffer(buffer * restrict b, const buffer * restrict src);
void buffer_append_string(buffer * restrict b, const char * restrict s);
void buffer_append_string_len(buffer * restrict b, const char * restrict s, size_t s_len);
void buffer_append_string_len(buffer * restrict b, const char * restrict s, size_t len);
static inline void buffer_append_string_buffer(buffer * restrict b, const buffer * restrict src);
#define buffer_append_uint_hex(b,len) buffer_append_uint_hex_lc((b),(len))

View File

@ -152,8 +152,8 @@ log_buffer_vprintf (buffer * const b,
va_end(aptry);
if (n >= bsp) {
buffer_string_prepare_append(b, n); /*(must re-read s after realloc)*/
vsnprintf((s = b->ptr + blen), buffer_string_space(b)+1, fmt, ap);
s = buffer_extend(b, n);
vsnprintf(s, n+1, fmt, ap);
}
size_t i;

View File

@ -409,12 +409,10 @@ static void mod_authn_append_ldap_dn_escape(buffer * const filter, const buffer
else {
/* escape NUL ('\0') (and all UTF-8 chars with high bit set) */
char *f;
buffer_string_prepare_append(filter, 3);
f = filter->ptr + buffer_string_length(filter);
f = buffer_extend(filter, 3);
f[0] = '\\';
f[1] = "0123456789abcdef"[(((unsigned char *)b)[i] >> 4) & 0xf];
f[2] = "0123456789abcdef"[(((unsigned char *)b)[i] ) & 0xf];
buffer_commit(filter, 3);
}
}
@ -481,12 +479,10 @@ static void mod_authn_append_ldap_filter_escape(buffer * const filter, const buf
}
/* escape * ( ) \ NUL ('\0') (and all UTF-8 chars with high bit set) */
buffer_string_prepare_append(filter, 3);
f = filter->ptr + buffer_string_length(filter);
f = buffer_extend(filter, 3);
f[0] = '\\';
f[1] = "0123456789abcdef"[(((unsigned char *)b)[i] >> 4) & 0xf];
f[2] = "0123456789abcdef"[(((unsigned char *)b)[i] ) & 0xf];
buffer_commit(filter, 3);
}
}

View File

@ -137,25 +137,11 @@ SETDEFAULTS_FUNC(mod_fastcgi_set_defaults) {
static int fcgi_env_add(void *venv, const char *key, size_t key_len, const char *val, size_t val_len) {
buffer *env = venv;
size_t len;
char len_enc[8];
size_t len_enc_len = 0;
char *dst;
if (!key || (!val && val_len)) return -1;
len = key_len + val_len;
len += key_len > 127 ? 4 : 1;
len += val_len > 127 ? 4 : 1;
if (buffer_string_length(env) + len >= FCGI_MAX_LENGTH + sizeof(FCGI_BeginRequestRecord) + sizeof(FCGI_Header)) {
/**
* we can't append more headers, ignore it
*/
return -1;
}
/**
* field length can be 31bit max
*
@ -164,35 +150,31 @@ static int fcgi_env_add(void *venv, const char *key, size_t key_len, const char
force_assert(key_len < 0x7fffffffu);
force_assert(val_len < 0x7fffffffu);
if (buffer_string_space(env) < len) {
size_t extend = env->size * 2 - buffer_string_length(env);
extend = extend > len ? extend : len + 4095;
buffer_string_prepare_append(env, extend);
}
if (key_len > 127) {
len_enc[len_enc_len++] = ((key_len >> 24) & 0xff) | 0x80;
len_enc[len_enc_len++] = (key_len >> 16) & 0xff;
len_enc[len_enc_len++] = (key_len >> 8) & 0xff;
len_enc[len_enc_len++] = (key_len >> 0) & 0xff;
} else {
len_enc[len_enc_len++] = (key_len >> 0) & 0xff;
len_enc[0] = ((key_len >> 24) & 0xff) | 0x80;
len_enc[1] = (key_len >> 16) & 0xff;
len_enc[2] = (key_len >> 8) & 0xff;
len_enc_len += 3;
}
len_enc[len_enc_len++] = key_len & 0xff;
if (val_len > 127) {
len_enc[len_enc_len++] = ((val_len >> 24) & 0xff) | 0x80;
len_enc[len_enc_len++] = (val_len >> 16) & 0xff;
len_enc[len_enc_len++] = (val_len >> 8) & 0xff;
len_enc[len_enc_len++] = (val_len >> 0) & 0xff;
} else {
len_enc[len_enc_len++] = (val_len >> 0) & 0xff;
}
len_enc[len_enc_len++] = val_len & 0xff;
dst = buffer_string_prepare_append(env, len);
const size_t len = len_enc_len + key_len + val_len;
const size_t fmax =
FCGI_MAX_LENGTH + sizeof(FCGI_BeginRequestRecord) + sizeof(FCGI_Header);
if (buffer_string_length(env) + len >= fmax)
return -1; /* we can't append more headers, ignore it */
char * const dst = buffer_extend(env, len);
memcpy(dst, len_enc, len_enc_len);
memcpy(dst + len_enc_len, key, key_len);
if (val_len) memcpy(dst + len_enc_len + key_len, val, val_len);
buffer_commit(env, len);
return 0;
}

View File

@ -869,26 +869,24 @@ static handler_t proxy_create_env(gw_handler_ctx *gwhctx) {
http_header_remap_uri(b, buffer_string_length(b) - buffer_string_length(&r->target), &hctx->conf.header, 1);
if (!hctx->conf.header.force_http10)
buffer_append_string_len(b, CONST_STR_LEN(" HTTP/1.1\r\n"));
buffer_append_string_len(b, CONST_STR_LEN(" HTTP/1.1"));
else
buffer_append_string_len(b, CONST_STR_LEN(" HTTP/1.0\r\n"));
buffer_append_string_len(b, CONST_STR_LEN(" HTTP/1.0"));
if (hctx->conf.replace_http_host && !buffer_string_is_empty(hctx->gw.host->id)) {
if (hctx->gw.conf.debug > 1) {
log_error(r->conf.errh, __FILE__, __LINE__,
"proxy - using \"%s\" as HTTP Host", hctx->gw.host->id->ptr);
}
buffer_append_string_len(b, CONST_STR_LEN("Host: "));
buffer_append_string_len(b, CONST_STR_LEN("\r\nHost: "));
buffer_append_string_buffer(b, hctx->gw.host->id);
buffer_append_string_len(b, CONST_STR_LEN("\r\n"));
} else if (!buffer_string_is_empty(r->http_host)) {
buffer_append_string_len(b, CONST_STR_LEN("Host: "));
buffer_append_string_len(b, CONST_STR_LEN("\r\nHost: "));
buffer_append_string_buffer(b, r->http_host);
if (remap_headers) {
size_t alen = buffer_string_length(r->http_host);
http_header_remap_host(b, buffer_string_length(b) - alen, &hctx->conf.header, 1, alen);
}
buffer_append_string_len(b, CONST_STR_LEN("\r\n"));
}
/* "Forwarded" and legacy X- headers */
@ -911,7 +909,7 @@ static handler_t proxy_create_env(gw_handler_ctx *gwhctx) {
&& (r->conf.stream_request_body
& (FDEVENT_STREAM_REQUEST | FDEVENT_STREAM_REQUEST_BUFMIN))) {
hctx->gw.stdin_append = proxy_stdin_append; /* stream chunked body */
buffer_append_string_len(b, CONST_STR_LEN("Transfer-Encoding: chunked\r\n"));
buffer_append_string_len(b, CONST_STR_LEN("\r\nTransfer-Encoding: chunked"));
}
/* request header */
@ -957,17 +955,14 @@ static handler_t proxy_create_env(gw_handler_ctx *gwhctx) {
const uint32_t klen = buffer_string_length(&ds->key);
const uint32_t vlen = buffer_string_length(&ds->value);
if (0 == klen || 0 == vlen) continue;
if (buffer_string_space(b) < klen + vlen + 4) {
size_t extend = b->size * 2 - buffer_string_length(b);
extend = extend > klen + vlen + 4 ? extend : klen + vlen + 4 + 4095;
buffer_string_prepare_append(b, extend);
}
buffer_append_string_len(b, ds->key.ptr, klen);
buffer_append_string_len(b, CONST_STR_LEN(": "));
buffer_append_string_len(b, ds->value.ptr, vlen);
buffer_append_string_len(b, CONST_STR_LEN("\r\n"));
char * restrict s = buffer_extend(b, klen+vlen+4);
s[0] = '\r';
s[1] = '\n';
memcpy(s+2, ds->key.ptr, klen);
s += 2+klen;
s[0] = ':';
s[1] = ' ';
memcpy(s+2, ds->value.ptr, vlen);
if (!remap_headers) continue;
@ -994,13 +989,13 @@ static handler_t proxy_create_env(gw_handler_ctx *gwhctx) {
continue;
}
http_header_remap_uri(b, buffer_string_length(b) - vlen - 2, &hctx->conf.header, 1);
http_header_remap_uri(b, buffer_string_length(b) - vlen, &hctx->conf.header, 1);
}
if (connhdr && !hctx->conf.header.force_http10 && r->http_version >= HTTP_VERSION_1_1
&& !buffer_eq_icase_slen(connhdr, CONST_STR_LEN("close"))) {
/* mod_proxy always sends Connection: close to backend */
buffer_append_string_len(b, CONST_STR_LEN("Connection: close"));
buffer_append_string_len(b, CONST_STR_LEN("\r\nConnection: close"));
/* (future: might be pedantic and also check Connection header for each
* token using http_header_str_contains_token() */
if (!buffer_string_is_empty(te))
@ -1010,7 +1005,7 @@ static handler_t proxy_create_env(gw_handler_ctx *gwhctx) {
buffer_append_string_len(b, CONST_STR_LEN("\r\n\r\n"));
}
else /* mod_proxy always sends Connection: close to backend */
buffer_append_string_len(b, CONST_STR_LEN("Connection: close\r\n\r\n"));
buffer_append_string_len(b, CONST_STR_LEN("\r\nConnection: close\r\n\r\n"));
hctx->gw.wb_reqlen = buffer_string_length(b);
chunkqueue_prepend_buffer_commit(&hctx->gw.wb);

View File

@ -16,8 +16,6 @@ typedef gw_handler_ctx handler_ctx;
#include "log.h"
#include "status_counter.h"
#include "sys-endian.h"
enum { LI_PROTOCOL_SCGI, LI_PROTOCOL_UWSGI };
static void mod_scgi_merge_config_cpv(plugin_config * const pconf, const config_plugin_value_t * const cpv) {
@ -147,62 +145,35 @@ SETDEFAULTS_FUNC(mod_scgi_set_defaults) {
static int scgi_env_add_scgi(void *venv, const char *key, size_t key_len, const char *val, size_t val_len) {
buffer *env = venv;
char *dst;
size_t len;
if (!key || (!val && val_len)) return -1;
len = key_len + val_len + 2;
if (buffer_string_space(env) < len) {
size_t extend = env->size * 2 - buffer_string_length(env);
extend = extend > len ? extend : len + 4095;
buffer_string_prepare_append(env, extend);
}
dst = buffer_string_prepare_append(env, len);
char *dst = buffer_extend(env, len);
memcpy(dst, key, key_len);
dst[key_len] = '\0';
memcpy(dst + key_len + 1, val, val_len);
dst[key_len + 1 + val_len] = '\0';
buffer_commit(env, len);
dst += key_len + 1;
memcpy(dst, val, val_len);
dst[val_len] = '\0';
return 0;
}
#ifdef __LITTLE_ENDIAN__
#define uwsgi_htole16(x) (x)
#else /* __BIG_ENDIAN__ */
#define uwsgi_htole16(x) ((uint16_t) (((x) & 0xff) << 8 | ((x) & 0xff00) >> 8))
#endif
static int scgi_env_add_uwsgi(void *venv, const char *key, size_t key_len, const char *val, size_t val_len) {
buffer *env = venv;
char *dst;
size_t len;
uint16_t uwlen;
if (!key || (!val && val_len)) return -1;
if (key_len > USHRT_MAX || val_len > USHRT_MAX) return -1;
len = 2 + key_len + 2 + val_len;
if (buffer_string_space(env) < len) {
size_t extend = env->size * 2 - buffer_string_length(env);
extend = extend > len ? extend : len + 4095;
buffer_string_prepare_append(env, extend);
}
dst = buffer_string_prepare_append(env, len);
uwlen = uwsgi_htole16((uint16_t)key_len);
memcpy(dst, (char *)&uwlen, 2);
char *dst = buffer_extend(venv, 2 + key_len + 2 + val_len);
dst[0] = key_len & 0xff; /* little-endian */
dst[1] = (key_len >> 8) & 0xff;
memcpy(dst + 2, key, key_len);
uwlen = uwsgi_htole16((uint16_t)val_len);
memcpy(dst + 2 + key_len, (char *)&uwlen, 2);
memcpy(dst + 2 + key_len + 2, val, val_len);
buffer_commit(env, len);
dst += 2+key_len;
dst[0] = val_len & 0xff; /* little-endian */
dst[1] = (val_len >> 8) & 0xff;
memcpy(dst + 2, val, val_len);
return 0;
}
@ -246,7 +217,6 @@ static handler_t scgi_create_env(handler_ctx *hctx) {
} else { /* LI_PROTOCOL_UWSGI */
/* http://uwsgi-docs.readthedocs.io/en/latest/Protocol.html */
size_t len = buffer_string_length(b)-10;
uint32_t uwsgi_header;
if (len > USHRT_MAX) {
r->http_status = 431; /* Request Header Fields Too Large */
r->handler_module = NULL;
@ -255,8 +225,10 @@ static handler_t scgi_create_env(handler_ctx *hctx) {
return HANDLER_FINISHED;
}
offset = 10 - 4;
uwsgi_header = ((uint32_t)uwsgi_htole16((uint16_t)len)) << 8;
memcpy(b->ptr+offset, (char *)&uwsgi_header, 4);
b->ptr[offset] = 0;
b->ptr[offset+1] = len & 0xff; /* little-endian */
b->ptr[offset+2] = (len >> 8) & 0xff;
b->ptr[offset+3] = 0;
}
hctx->wb_reqlen = buffer_string_length(b) - offset;

View File

@ -242,12 +242,10 @@ static void mod_authn_append_ldap_filter_escape(buffer * const filter, const buf
}
/* escape * ( ) \ NUL ('\0') (and all UTF-8 chars with high bit set) */
buffer_string_prepare_append(filter, 3);
f = filter->ptr + buffer_string_length(filter);
f = buffer_extend(filter, 3);
f[0] = '\\';
f[1] = "0123456789abcdef"[(((unsigned char *)b)[i] >> 4) & 0xf];
f[2] = "0123456789abcdef"[(((unsigned char *)b)[i] ) & 0xf];
buffer_commit(filter, 3);
}
}

View File

@ -118,16 +118,20 @@ http_response_write_header (request_st * const r)
/* add all headers */
for (size_t i = 0; i < r->resp_headers.used; ++i) {
const data_string * const ds = (data_string *)r->resp_headers.data[i];
if (buffer_string_is_empty(&ds->value)) continue;
if (buffer_string_is_empty(&ds->key)) continue;
const uint32_t klen = buffer_string_length(&ds->key);
const uint32_t vlen = buffer_string_length(&ds->value);
if (0 == klen || 0 == vlen)
continue;
if ((ds->key.ptr[0] & 0xdf) == 'X' && http_response_omit_header(r, ds))
continue;
buffer_append_string_len(b, CONST_STR_LEN("\r\n"));
buffer_append_string_buffer(b, &ds->key);
buffer_append_string_len(b, CONST_STR_LEN(": "));
buffer_append_string_buffer(b, &ds->value);
char * restrict s = buffer_extend(b, klen+vlen+4);
s[0] = '\r';
s[1] = '\n';
memcpy(s+2, ds->key.ptr, klen);
s += 2+klen;
s[0] = ':';
s[1] = ' ';
memcpy(s+2, ds->value.ptr, vlen);
}
if (!light_btst(r->resp_htags, HTTP_HEADER_DATE)) {