Njs: How to change response header ?

Created on 1 Dec 2018  路  14Comments  路  Source: nginx/njs

Hi buddies:

I set response header.

function version(r) {
    r.headersOut['Content-Type'] = 'text/html';
    r.return(200, njs.version);
}

But I got two Content-Type header (another comes from default_type).

I try to delete it, but it doesn't work either. (crash)

function version(r) {
    delete r.headersOut['Content-Type'];
    r.headersOut['Content-Type'] = 'text/html';
    r.return(200, njs.version);
}
bug

Most helpful comment

Hi @nishant-dani

r.response property was removed after 0.2.8 (26 Feb 2019) version.

To change Content-Type header:

r.headersOut['Content-Type'] = 'application/json';

All 14 comments

Hi @Runrioter,

1) The issue with 'Content-Type' (as well as other often used headers) is that it is treated in a special way by nginx (by a custom field)
(https://github.com/nginx/nginx/blob/master/src/http/ngx_http_request.h#L277)

You can set contentType now by
r.contentType ='text/html'

In the future, I am planning to get rid of special setters (like r.contentType).
It will be possible to set Content-Type simply by
r.headersOut['Content-Type'] = 'text/html'

2) the delete issue
Thank you for reporting it. Will be fixed.

Is related to #43

@xeioex Thanks for your quick reply. I like the njs module. Hope that it will become better.

Hi @Runrioter ,

Could you please report the njs version.

I am trying to reproduce the delete issue (using 0.2.6).

function version(r) {
    delete r.headersOut['Content-Type'];
    r.headersOut['Content-Type'] = 'text/html';
    r.return(200, njs.version);
}
2018/12/03 14:56:10 [error] 22597#22597: *2 js exception: TypeError: Cannot delete property 'Content-Type' of external
    at version (:82)
    at main (native)

Yes. I use 0.2.6, too.

2018/12/03 13:12:52 [error] 91#91: *83 js exception: TypeError: Cannot delete property 'Content-Type' of external
    at version (:1)
    at main (native)

So, how can I reproduce the crash?

Sorry, I mean the crash is the js exception. Is this js exception TypeError reasonable ? Need I try catch this exception ?

external means what ?

delete operator can't throw TypeError. Refer to here https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/delete

external means what ?

It is a special value type (a thin, zero-copy wrapper around nginx C-structures). externals is a way to introduce native nginx object into the engine.

For example r - nginx request is external.
Currently, externals behave like semi-Objects. You can do some js operations on them.

In C-code, you have to define some C level functions to support the operations (like iterations, property get, property set..) (https://github.com/nginx/njs/blob/master/nginx/ngx_http_js_module.c#L478). In the future, I hope to get rid of the externals, but it is not easy.

Currently, there is no C-level function which implements delete operation for r.headersOut object.

Is this js exception TypeError reasonable ?

njs aims to implement strict mode only. In the strict mode, you get TypeError exception (according to ES5.1 https://www.ecma-international.org/ecma-262/5.1/#sec-11.4.1) if delete operator fails (njs treats absence of C-level delete function as a configure:false).

@xeioex Thank you. I learnt a lot. You can close this issue at any time.

Hi! I'm having the problem when trying to change the content type.

Using r.headersOut['Content-Type'] = 'text/plain', the header is not changed, but added in addition to the original:

HTTP/1.1 200 OK
Server: nginx/1.15.8
Date: Thu, 17 Jan 2019 07:47:24 GMT
Content-Type: application/octet-stream
Content-Length: 0
Connection: close
Content-Type: text/plain     <-- here

When using the proposed r.contentType = 'text/plain', I get the following error:

2019/01/17 07:38:21 [error] 2263#2263: *376 js exception: TypeError: Cannot assign to read-only property 'contentType' of external
    at jsLogBasicAuth (:17)
    at main (native)
, client: 1.2.3.4, server: foo.bar, request: "GET /test/basic-auth/ HTTP/1.1", host: "foo.bar"

Any solution on this? I would prefer if the content type 'text/plain' was default, which would make more sense IMO when doing a simple r.return(200, "Hello, World\n").

Awesome project btw! Very helpful for doing security testing.

EDIT: Seems that the following code works:

r.status = 200;
r.headersOut['Content-Type'] = 'text/plain';
r.sendHeader();
r.finish();

Which returns the following correct response:

HTTP/1.1 200 OK
Server: nginx/1.15.8
Date: Thu, 17 Jan 2019 08:06:55 GMT
Connection: close
Content-Type: text/plain
Content-Length: 0

Hi @mfaerevaag,

The issue with some special headers still persists (the reason for that is explaned here).

As a workaround:
You can set special headers using nginx directives:
default_type for Content-Type header. add_header for other headers.

or the following code (r.response object is deprecated, and will be removed in the future):

r.response.contentType = 'text/plain';  // <- modifies resulting content_type header in-place.                                                                              
r.return(200, "Hello world\n");

Alright, thanks!

When I try to set
r.response.contentType = 'application/json';
req.return (reply.status, reply.responseBody)

nginx.1 | 2020/01/08 08:10:27 [error] 59#59: *138 js exception: TypeError: property set on primitive undefined type

Hi @nishant-dani

r.response property was removed after 0.2.8 (26 Feb 2019) version.

To change Content-Type header:

r.headersOut['Content-Type'] = 'application/json';
Was this page helpful?
0 / 5 - 0 ratings

Related issues

xeioex picture xeioex  路  3Comments

drsm picture drsm  路  3Comments

xbb123 picture xbb123  路  4Comments

xeioex picture xeioex  路  3Comments

laith-leo picture laith-leo  路  5Comments