ngx_js_headers_append(njs_vm_t *vm, ngx_js_headers_t *headers,
u_char *name, size_t len, u_char *value, size_t vlen)
{
- u_char *p, *end;
ngx_int_t ret;
ngx_uint_t i;
ngx_js_tb_elt_t *h, **ph;
ngx_list_part_t *part;
- ngx_js_http_trim(&value, &vlen, 0);
+ ngx_js_http_trim_ows(&value, &vlen);
ret = ngx_js_check_header_name(name, len);
if (ret != NGX_OK) {
return NJS_ERROR;
}
- p = value;
- end = p + vlen;
-
- while (p < end) {
- if (*p == '\0') {
- njs_vm_error(vm, "invalid header value");
- return NJS_ERROR;
- }
-
- p++;
+ ret = ngx_js_check_header_value(value, vlen);
+ if (ret != NGX_OK) {
+ njs_vm_error(vm, "invalid header value");
+ return NJS_ERROR;
}
if (headers->guard == GUARD_IMMUTABLE) {
}
+void
+ngx_js_http_trim_ows(u_char **value, size_t *len)
+{
+ u_char *start, *end;
+
+ start = *value;
+ end = start + *len;
+
+ while (start < end && (*start == ' ' || *start == '\t')) {
+ start++;
+ }
+
+ while (start < end) {
+ end--;
+
+ if (*end != ' ' && *end != '\t') {
+ end++;
+ break;
+ }
+ }
+
+ *value = start;
+ *len = end - start;
+}
+
+
static const uint32_t token_map[] = {
0x00000000, /* 0000 0000 0000 0000 0000 0000 0000 0000 */
}
+ngx_int_t
+ngx_js_check_header_value(u_char *value, size_t len)
+{
+ u_char *p, *end;
+
+ p = value;
+ end = p + len;
+
+ while (p < end) {
+ if (*p <= 0x08 || (*p >= 0x0a && *p <= 0x1f) || *p == 0x7f) {
+ return NGX_ERROR;
+ }
+
+ p++;
+ }
+
+ return NGX_OK;
+}
+
+
static ngx_int_t
ngx_js_http_get_keepalive_connection(ngx_js_http_t *http)
{
void ngx_js_http_close_peer(ngx_js_http_t *http);
void ngx_js_http_trim(u_char **value, size_t *len,
int trim_c0_control_or_space);
+void ngx_js_http_trim_ows(u_char **value, size_t *len);
ngx_int_t ngx_js_check_header_name(u_char *name, size_t len);
+ngx_int_t ngx_js_check_header_value(u_char *value, size_t len);
ngx_buf_t *ngx_js_chain_to_buf(ngx_pool_t *pool, njs_chb_t *chain);
ngx_qjs_headers_append(JSContext *cx, ngx_js_headers_t *headers,
u_char *name, size_t len, u_char *value, size_t vlen)
{
- u_char *p, *end;
ngx_int_t ret;
ngx_uint_t i;
ngx_list_part_t *part;
ngx_js_tb_elt_t *h, **ph;
- ngx_js_http_trim(&value, &vlen, 0);
+ ngx_js_http_trim_ows(&value, &vlen);
ret = ngx_js_check_header_name(name, len);
if (ret != NGX_OK) {
return NGX_ERROR;
}
- p = value;
- end = p + vlen;
-
- while (p < end) {
- if (*p == '\0') {
- JS_ThrowInternalError(cx, "invalid header value");
- return NGX_ERROR;
- }
-
- p++;
+ ret = ngx_js_check_header_value(value, vlen);
+ if (ret != NGX_OK) {
+ JS_ThrowInternalError(cx, "invalid header value");
+ return NGX_ERROR;
}
if (headers->guard == GUARD_IMMUTABLE) {
}, 'OK'],
['invalid header value', () => {
- var h = new Headers({A: 'aa\x00a'});
- }, 'invalid header value'],
+ const invalid = [0, 1, 8, 10, 13, 31, 127];
+
+ for (var i = 0; i < invalid.length; i++) {
+ var c = String.fromCharCode(invalid[i]);
+ var values = [
+ c, c + 'aa', 'aa' + c, 'aa' + c + 'a'
+ ];
+
+ for (var j = 0; j < values.length; j++) {
+ try {
+ new Headers({A: values[j]});
+ throw new Error('no error');
+
+ } catch (e) {
+ if (e.message != 'invalid header value') {
+ throw e;
+ }
+ }
+ }
+ }
+
+ return 'OK';
+
+ }, 'OK'],
+ ['valid header value', () => {
+ var obs = String.fromCharCode(0x80, 0xff);
+ var h = new Headers({A: '\t a\tb \t'});
+
+ h.append('A', obs);
+
+ if (h.get('a') != 'a\tb, ' + obs) {
+ throw new Error('invalid header value normalization');
+ }
+
+ return 'OK';
+ }, 'OK'],
['combine', () => {
var h = new Headers({a: 'X', A: 'Z'});
return h.get('a');