#include <ngx_core.h>
#include <ngx_http.h>
#include "ngx_js.h"
+#include "ngx_js_http.h"
#include "ngx_js_modules.h"
#include "ngx_js_form.h"
return NJS_DECLINED;
}
+ if (setval != NULL
+ && ngx_js_check_header_name(name.start, name.length) != NGX_OK)
+ {
+ njs_vm_type_error(vm, "%s",
+ ngx_js_headers_error(NGX_JS_HEADERS_INVALID_NAME));
+ return NJS_ERROR;
+ }
+
if (r->header_sent && setval != NULL) {
ngx_log_error(NGX_LOG_WARN, r->connection->log, 0,
"ignored setting of response header \"%V\" because"
setval = njs_vm_array_prop(vm, setval, length - 1, &lvalue);
}
- if (ngx_js_string(vm, setval, &s) != NGX_OK) {
+ if (ngx_js_header_value(vm, setval, &s) != NGX_OK) {
return NJS_ERROR;
}
setval = njs_vm_array_prop(vm, array, i, &lvalue);
}
- if (ngx_js_string(vm, setval, &s) != NGX_OK) {
+ if (ngx_js_header_value(vm, setval, &s) != NGX_OK) {
return NJS_ERROR;
}
setval = njs_vm_array_prop(vm, array, i, &lvalue);
}
- if (ngx_js_string(vm, setval, &s) != NGX_OK) {
+ if (ngx_js_header_value(vm, setval, &s) != NGX_OK) {
return NJS_ERROR;
}
setval = njs_vm_array_prop(vm, setval, length - 1, &lvalue);
}
- if (ngx_js_string(vm, setval, &s) != NGX_OK) {
+ if (ngx_js_header_value(vm, setval, &s) != NGX_OK) {
return NJS_ERROR;
}
setval = njs_vm_array_prop(vm, setval, length - 1, &lvalue);
}
- if (ngx_js_string(vm, setval, &s) != NGX_OK) {
+ if (ngx_js_header_value(vm, setval, &s) != NGX_OK) {
return NJS_ERROR;
}
}
}
- rc = ngx_qjs_string(cx, r->pool, v, &s);
+ rc = ngx_qjs_header_value(cx, r->pool, v, &s);
if (qjs_is_array(cx, *value)) {
JS_FreeValue(cx, v);
setval = JS_UNDEFINED;
}
- rc = ngx_qjs_string(cx, r->pool, setval, &s);
+ rc = ngx_qjs_header_value(cx, r->pool, setval, &s);
if (value != NULL && qjs_is_array(cx, *value)) {
JS_FreeValue(cx, setval);
setval = *value;
}
- rc = ngx_qjs_string(cx, r->pool, setval, &s);
+ rc = ngx_qjs_header_value(cx, r->pool, setval, &s);
if (qjs_is_array(cx, *value)) {
JS_FreeValue(cx, setval);
name.len = ngx_strlen(name.data);
+ if (ngx_js_check_header_name(name.data, name.len) != NGX_OK) {
+ JS_FreeCString(cx, (char *) name.data);
+ (void) JS_ThrowTypeError(cx, "%s",
+ ngx_js_headers_error(NGX_JS_HEADERS_INVALID_NAME));
+ return -1;
+ }
+
if (r->header_sent) {
ngx_log_error(NGX_LOG_WARN, r->connection->log, 0,
"ignored setting of response header \"%V\" because"
}
+ngx_int_t
+ngx_qjs_header_value(JSContext *cx, ngx_pool_t *pool, JSValueConst val,
+ ngx_str_t *dst)
+{
+ if (ngx_qjs_string(cx, pool, val, dst) != NGX_OK) {
+ return NGX_ERROR;
+ }
+
+ if (ngx_js_check_header_value(dst->data, dst->len) != NGX_OK) {
+ (void) JS_ThrowTypeError(cx, "%s",
+ ngx_js_headers_error(NGX_JS_HEADERS_INVALID_VALUE));
+ return NGX_ERROR;
+ }
+
+ return NGX_OK;
+}
+
+
static void
ngx_qjs_timer_handler(ngx_event_t *ev)
{
}
+ngx_int_t
+ngx_js_header_value(njs_vm_t *vm, njs_value_t *value, njs_str_t *str)
+{
+ if (ngx_js_string(vm, value, str) != NGX_OK) {
+ return NGX_ERROR;
+ }
+
+ if (ngx_js_check_header_value(str->start, str->length) != NGX_OK) {
+ njs_vm_type_error(vm, "%s",
+ ngx_js_headers_error(NGX_JS_HEADERS_INVALID_VALUE));
+ return NGX_ERROR;
+ }
+
+ return NGX_OK;
+}
+
+
static njs_int_t
njs_function_bind(njs_vm_t *vm, const njs_str_t *name,
njs_function_native_t native, njs_bool_t ctor)
ngx_int_t ngx_qjs_integer(JSContext *cx, JSValueConst val, ngx_int_t *n);
ngx_int_t ngx_qjs_string(JSContext *cx, ngx_pool_t *pool, JSValueConst val,
ngx_str_t *dst);
+ngx_int_t ngx_qjs_header_value(JSContext *cx, ngx_pool_t *pool,
+ JSValueConst val, ngx_str_t *dst);
JSValue ngx_qjs_ext_fetch(JSContext *cx, JSValueConst this_val, int argc,
JSValueConst *argv);
ngx_int_t ngx_js_string(njs_vm_t *vm, njs_value_t *value, njs_str_t *str);
ngx_int_t ngx_js_ngx_string(njs_vm_t *vm, njs_value_t *value, ngx_str_t *str);
+ngx_int_t ngx_js_header_value(njs_vm_t *vm, njs_value_t *value,
+ njs_str_t *str);
ngx_int_t ngx_js_integer(njs_vm_t *vm, njs_value_t *value, ngx_int_t *n);
const char *ngx_js_errno_string(int errnum);
js_content test.hdr_out_array;
}
+ location /hdr_out_invalid {
+ js_content test.hdr_out_invalid;
+ }
+
+ location /hdr_out_valid {
+ js_content test.hdr_out_valid;
+ }
+
location /hdr_out_set_cookie {
js_content test.hdr_out_set_cookie;
}
r.return(200, `B:\${r.headersOut.foo}`);
}
+ function hdr_out_invalid(r) {
+ var v = 'a\\r\\nInjected: 1';
+
+ try {
+ if (r.args.h == 'arr') {
+ r.headersOut['Foo'] = ['good', v];
+
+ } else if (r.args.h == 'name') {
+ r.headersOut['X\\r\\nInjected: 1'] = 'val';
+
+ } else {
+ r.headersOut[r.args.h] = v;
+ }
+
+ r.return(200, 'no_error');
+
+ } catch (e) {
+ r.return(500, `\${e.constructor.name}:\${e.message}`);
+ }
+ }
+
+ function hdr_out_valid(r) {
+ r.headersOut['Foo'] = 'a\\tb\\u00e9';
+ r.return(200, 'ok');
+ }
+
function hdr_out_single(r) {
r.headersOut.ETag = ['a', 'b'];
r.return(200, `B:\${r.headersOut.etag}`);
content_encoding, content_encoding_arr, headers_list,
hdr_in, raw_hdr_in, hdr_sorted_keys, foo_in, ifoo_in,
hdr_out, raw_hdr_out, hdr_out_array, hdr_out_single,
+ hdr_out_invalid, hdr_out_valid,
hdr_out_set_cookie, ihdr_out, hdr_out_special_set,
copy_subrequest_hdrs, subrequest, date, last_modified,
location, location_sr, server, in_lowkey};
EOF
-$t->try_run('no njs')->plan(53);
+$t->try_run('no njs')->plan(61);
###############################################################################
'r.headersOut single');
like(http_get('/hdr_out_single'), qr/B:a/,
'r.headersOut single get');
+like(http_get('/hdr_out_invalid?h=Foo'),
+ qr/500.*TypeError:invalid header value/s, 'r.headersOut invalid value');
+like(http_get('/hdr_out_invalid?h=Location'),
+ qr/500.*TypeError:invalid header value/s,
+ 'r.headersOut invalid special value');
+like(http_get('/hdr_out_invalid?h=Content-Type'),
+ qr/500.*TypeError:invalid header value/s,
+ 'r.headersOut invalid Content-Type value');
+like(http_get('/hdr_out_invalid?h=arr'),
+ qr/500.*TypeError:invalid header value/s,
+ 'r.headersOut invalid value in array');
+like(http_get('/hdr_out_invalid?h=name'),
+ qr/500.*TypeError:invalid header name/s, 'r.headersOut invalid name');
+unlike(http_get('/hdr_out_invalid?h=Foo'), qr/^Injected/m,
+ 'r.headersOut no response splitting');
+unlike(http_get('/hdr_out_invalid?h=name'), qr/^Injected/m,
+ 'r.headersOut no response splitting by name');
+like(http_get('/hdr_out_valid'), qr/Foo: a\tb\xc3\xa9/,
+ 'r.headersOut obs-text value');
+
like(http_get('/hdr_out_set_cookie'), qr/Set-Cookie: c\r\nSet-Cookie: d/,
'set_cookie');
like(http_get('/hdr_out_set_cookie'), qr/B:c,d,f true/,