[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:
parent
f9cd50b782
commit
38c8735850
165
src/buffer.c
165
src/buffer.c
|
@ -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 */
|
||||
|
|
11
src/buffer.h
11
src/buffer.h
|
@ -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))
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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)) {
|
||||
|
|
Loading…
Reference in New Issue