[njs] HTTP: reading r.requestText or r.requestBuffer from a temp file.

noreply at nginx.com noreply at nginx.com
Sat Feb 1 01:57:02 UTC 2025


details:   https://github.com/nginx/njs/commit/2d97e80486d7d2554e58cdaca4f2389b836600c8
branches:  master
commit:    2d97e80486d7d2554e58cdaca4f2389b836600c8
user:      Dmitry Volyntsev <xeioex at nginx.com>
date:      Tue, 28 Jan 2025 19:11:48 -0800
description:
HTTP: reading r.requestText or r.requestBuffer from a temp file.

Previously, an exception was thrown when accessing r.requestText or
r.requestBuffer if a client request body size exceeded
client_body_buffer_size.

---
 nginx/ngx_http_js_module.c | 60 +++++++++++++++++++++++++++++++++++++++-------
 nginx/t/js_request_body.t  | 29 +++++++++++++++++++---
 2 files changed, 77 insertions(+), 12 deletions(-)

diff --git a/nginx/ngx_http_js_module.c b/nginx/ngx_http_js_module.c
index 04d06fb2..66cb97c0 100644
--- a/nginx/ngx_http_js_module.c
+++ b/nginx/ngx_http_js_module.c
@@ -2916,6 +2916,7 @@ ngx_http_js_ext_get_request_body(njs_vm_t *vm, njs_object_prop_t *prop,
 {
     u_char              *p, *body;
     size_t               len;
+    ssize_t              n;
     uint32_t             buffer_type;
     ngx_buf_t           *buf;
     njs_int_t            ret;
@@ -2948,14 +2949,35 @@ ngx_http_js_ext_get_request_body(njs_vm_t *vm, njs_object_prop_t *prop,
         return NJS_DECLINED;
     }
 
-    if (r->request_body->temp_file) {
-        njs_vm_error(vm, "request body is in a file");
-        return NJS_ERROR;
-    }
-
     cl = r->request_body->bufs;
     buf = cl->buf;
 
+    if (r->request_body->temp_file) {
+        ngx_log_error(NGX_LOG_WARN, r->connection->log, 0,
+                      "http js reading request body from a temporary file");
+
+        if (buf == NULL || !buf->in_file) {
+            njs_vm_internal_error(vm, "cannot find request body");
+            return NJS_ERROR;
+        }
+
+        len = buf->file_last - buf->file_pos;
+
+        body = ngx_pnalloc(r->pool, len);
+        if (body == NULL) {
+            njs_vm_memory_error(vm);
+            return NJS_ERROR;
+        }
+
+        n = ngx_read_file(buf->file, body, len, buf->file_pos);
+        if (n != (ssize_t) len) {
+            njs_vm_internal_error(vm, "failed to read request body");
+            return NJS_ERROR;
+        }
+
+        goto done;
+    }
+
     if (cl->next == NULL) {
         len = buf->last - buf->pos;
         body = buf->pos;
@@ -5259,6 +5281,7 @@ ngx_http_qjs_ext_request_body(JSContext *cx, JSValueConst this_val, int type)
 {
     u_char                  *p, *data;
     size_t                   len;
+    ssize_t                  n;
     JSValue                  body;
     uint32_t                 buffer_type;
     ngx_buf_t               *buf;
@@ -5287,13 +5310,32 @@ ngx_http_qjs_ext_request_body(JSContext *cx, JSValueConst this_val, int type)
         return JS_UNDEFINED;
     }
 
-    if (r->request_body->temp_file) {
-        return JS_ThrowTypeError(cx, "request body is in a file");
-    }
-
     cl = r->request_body->bufs;
     buf = cl->buf;
 
+    if (r->request_body->temp_file) {
+        ngx_log_error(NGX_LOG_WARN, r->connection->log, 0,
+                      "http js reading request body from a temporary file");
+
+        if (buf == NULL || !buf->in_file) {
+            return JS_ThrowInternalError(cx, "cannot find body file");
+        }
+
+        len = buf->file_last - buf->file_pos;
+
+        data = ngx_pnalloc(r->pool, len);
+        if (data == NULL) {
+            return JS_ThrowOutOfMemory(cx);
+        }
+
+        n = ngx_read_file(buf->file, data, len, buf->file_pos);
+        if (n != (ssize_t) len) {
+            return JS_ThrowInternalError(cx, "failed to read request body");
+        }
+
+        goto done;
+    }
+
     if (cl->next == NULL) {
         len = buf->last - buf->pos;
         data = buf->pos;
diff --git a/nginx/t/js_request_body.t b/nginx/t/js_request_body.t
index 360e4565..3980ea73 100644
--- a/nginx/t/js_request_body.t
+++ b/nginx/t/js_request_body.t
@@ -47,11 +47,25 @@ http {
             js_content test.body;
         }
 
+        location /body_4k {
+            client_body_buffer_size 4k;
+            js_content test.body;
+        }
+
         location /in_file {
+            js_content test.body;
+        }
+
+        location /in_file_on {
             client_body_in_file_only on;
             js_content test.body;
         }
 
+        location /in_file_clean {
+            client_body_in_file_only clean;
+            js_content test.body;
+        }
+
         location /read_body_from_temp_file {
             client_body_in_file_only clean;
             js_content test.read_body_from_temp_file;
@@ -93,20 +107,29 @@ $t->write_file('test.js', <<EOF);
 
 EOF
 
-$t->try_run('no njs request body')->plan(5);
+$t->try_run('no njs request body')->plan(9);
 
 ###############################################################################
 
 like(http_post('/body'), qr/REQ-BODY/, 'request body');
-like(http_post('/in_file'), qr/request body is in a file/,
-	'request body in file');
+like(http_post('/in_file'), qr/REQ-BODY/, 'request body in a file');
+like(http_post('/in_file_on'), qr/REQ-BODY/, 'request body in a file on');
+like(http_post('/in_file_clean'), qr/REQ-BODY/, 'request body in a file clean');
 like(http_post_big('/body'), qr/200.*^(1234567890){1024}$/ms,
 		'request body big');
+like(http_post_big('/body_4k'), qr/200.*^(1234567890){1024}$/ms,
+		'request body big with 4k buffer');
 like(http_post_big('/read_body_from_temp_file'),
 	qr/200.*^(1234567890){1024}$/ms, 'request body big from temp file');
 like(http_post('/request_body_cache'),
 	qr/requestText:string requestBuffer:buffer$/s, 'request body cache');
 
+$t->stop();
+
+ok(index($t->read_file('error.log'),
+	'http js reading request body from a temporary file') > 0,
+	'http request body is in a file warning');
+
 ###############################################################################
 
 sub http_post {


More information about the nginx-devel mailing list