diff options
author | Ippolitov Igor <iippolitov@nginx.com> | 2023-10-19 12:50:39 +0100 |
---|---|---|
committer | Ippolitov Igor <iippolitov@nginx.com> | 2023-10-19 12:50:39 +0100 |
commit | c43629880472bba8d389dfb0b7ae6d883b0ba499 (patch) | |
tree | acecdcb36cfb85fac3d8cdbfbe473c26ac2e2686 | |
parent | 8c4425ccb9a413e8d0506e0254f0e84bd89a32a6 (diff) | |
parent | fb33ec86a3b6ca6a844dfa6980bb9e083094abec (diff) | |
download | unit-1.31.1-1.tar.gz unit-1.31.1-1.tar.bz2 |
Merged with the default branch.1.31.1-1
45 files changed, 675 insertions, 113 deletions
@@ -73,3 +73,4 @@ e7b7f2bb04e8c6f4cbe6374fd6960d4465654215 1.29.1-1 8a0b4338a15648792bcad47edb53f1b1c0badeb4 1.30.0-1 3a9046dca2a6c51ee2df2cabdf69cb9a83e7a1e6 1.31.0 ef8ddca63f2c1a3e1758968740837b921dd953dc 1.31.0-1 +25aafe2ff61e0424b3245f4e3d40eb1fa7611063 1.31.1 @@ -1,4 +1,31 @@ +Changes with Unit 1.31.1 19 Oct 2023 + + *) Feature: allow to set the HTTP response status in Wasm module. + + *) Feature: allow uploads larger than 4GiB in Wasm module. + + *) Bugfix: application process could crash while rewriting URLs with + query strings. + + *) Bugfix: requests larger than about 64MiB could cause error in Wasm + module. + + *) Bugfix: when using many headers in Java module some of them could be + corrupted due to memory realocation issue. + + *) Bugfix: ServerRequest.destroy() implemented in Node.js module to make + it compatible with some frameworks that might use it. + + *) Bugfix: chunk argument of ServerResponse.write() can now be a + Uint8Array to improve compatibility with Node.js 15.0.0 and above. + + *) Bugfix: Node.JS unit-http NPM module now has appropriate default + paths for macOS/arm64 systems. + + *) Bugfix: build on musl libc with clang. + + Changes with Unit 1.31.0 31 Aug 2023 *) Change: if building with njs, version 0.8.0 or later is now required. diff --git a/auto/modules/java b/auto/modules/java index 7c39eb37..53f99f7e 100644 --- a/auto/modules/java +++ b/auto/modules/java @@ -238,7 +238,7 @@ cat << END > $NXT_JAVA_JARS static const char *nxt_java_system_jars[] = { END -NXT_TOMCAT_VERSION=9.0.75 +NXT_TOMCAT_VERSION=9.0.82 NXT_JAR_VERSION=$NXT_TOMCAT_VERSION @@ -284,7 +284,7 @@ static const char *nxt_java_unit_jars[] = { "$NXT_UNIT_JAR", END -NXT_JAR_VERSION=9.4.51.v20230217 +NXT_JAR_VERSION=9.4.53.v20231009 NXT_JAR_NAMESPACE=org/eclipse/jetty/ NXT_JAR_NAME=jetty-util @@ -297,7 +297,7 @@ NXT_JAR_NAME=jetty-http . auto/modules/java_get_jar NXT_JAR_NAME=classgraph -NXT_JAR_VERSION=4.8.158 +NXT_JAR_VERSION=4.8.162 NXT_JAR_NAMESPACE=io/github/classgraph/ . auto/modules/java_get_jar diff --git a/auto/modules/java_jar.sha512 b/auto/modules/java_jar.sha512 index da08f786..e0a648af 100644 --- a/auto/modules/java_jar.sha512 +++ b/auto/modules/java_jar.sha512 @@ -1,14 +1,14 @@ -00dc1aedae7cb6600b4b27ac7ec0234981a23a8c6f03dc1881304b7d999d94f0fdaa51e0008288740d9890b34f41462e8ed82c76f36a18bd45eabbb8084ec8d4 classgraph-4.8.158.jar +a117092f4ab77ef89b3b83a45b9e33c0360cb18098df17da77e5d765a6b5cea1fae6190399217236c0d970f2b3603bc8f408c2471cf8854de1282dba7525c335 classgraph-4.8.162.jar ab441acf5551a7dc81c353eaccb3b3df9e89a48987294d19e39acdb83a5b640fcdff7414cee29f5b96eaa8826647f1d5323e185018fe33a64c402d69c73c9158 ecj-3.26.0.jar -606d0446a948c7a349cba5415d079bd054e43a8a09727c8300865f38678c5101642ecafa777d5f979bde1bd520543a4cf83348fcd9a444e6681cf773eb3c5824 jetty-http-9.4.51.v20230217.jar -e9d3f7104214a16435d077eb53d943130b3a85bf9e8a48b9e40a7ad063ca3cca69324e03f21202e66fc5fd864c3cb09cd1857eff8d682c69398b4d75c1a430c6 jetty-server-9.4.51.v20230217.jar -12725e106000d6ef672c474e467d7c976c3913b2d39a92e7304cc30d0e0d1f92575227d2c2201b97ca50f39cba81ac8b79bccb2b32b63d758ac4e192173c3f62 jetty-util-9.4.51.v20230217.jar -b802b595d796285653c3c1b3d870295767afc6d4f857d439d579b7261dc8d015c948cd900e93ebc0ad706d1c74600645d3a18caef4f040a7085ff0e9f6cb4e44 tomcat-api-9.0.75.jar -90cc3c2847782b6854bc0549e7bdfda2e92feac726285718aa4083baef597e472e7f3712257790107fa9306263f645fcc17344a8209415d10a75f4f4cfa30b04 tomcat-el-api-9.0.75.jar -c23a0db30c5d77a518c7cd0afebe6c59600b45e03651409788acb91fa652752960f6e21ac15a233b433dbe290028d00ac72c4cd2856880f4d4ba9ef227692d7a tomcat-jasper-9.0.75.jar -06fb8c0d49945437900be1cc8fd8d8123a7bf6599e7755aa6c7963a65d46aea444661de532ce0e6c0573ecd12def2d5d1e7942ecace9c7c3a39e232373f3fd6b tomcat-jasper-el-9.0.75.jar -7dbaacd7f0490c8f0062eb12cd244acc9c51ee72d1c60ad841ac61905cd46b5d477b01c97019ba6e93a6b27de3e3438c620fb156cec3d6ece36f37918a6ee5bd tomcat-jsp-api-9.0.75.jar -05c15c5c6877b39aed4457e5ea7992819c28dc148a2442a149a8d5ee294a62042eebd2f3846acdd70b08d531d95cdcc8cfcd7b64fb8b046aa5639e7901505131 tomcat-juli-9.0.75.jar -92a44f8970746976a63351d45f84c7963127bd21db0af834a7d38dcfb3c29450398cb4b466636dfb3d8e764093c612eb2938af22ac2098171bac201ad6bcc320 tomcat-servlet-api-9.0.75.jar -6794c0d6d5780ca09fdbaf801c1475f227b799c809a46195c0fd1f9792303fb6d0aa6e49ac049337863bdb512c390334470210294364b7af25d86355f7fd0605 tomcat-util-9.0.75.jar -e97c90c857a5c814518f3da10d8c09c900417421d81ad500ad338ac10c6b7dc8338b486d2338f5cebea6fa33c9803fd2c06cf35c44b1b5b720331943f2e22de3 tomcat-util-scan-9.0.75.jar +867afb0e69ab225a3d57c0eda4e773ca2f41dcc6eb294e14aef4d69441314bee88221081f9edc6289b9e4a99184804b60c32f4443c8ff96eb34d6508b348b755 jetty-http-9.4.53.v20231009.jar +aca14debabc0cc40e154d4de4de404c383c4611e9f2482911e17d9072f0941cef8a88511d5d49d70946e65872e1bc8d395b9401b2ec91132553d782d99140ce3 jetty-server-9.4.53.v20231009.jar +429b269e21c6e7bf86ba8a8b71569e3abf61b06ace9dd064a9c80af4282227e910a8d20be86ef6581895ff283a5aa4711bbb238de45dc7628f494624879c4d49 jetty-util-9.4.53.v20231009.jar +ee33bc0020ce5be2fbdb52352fb9b2846dc5898b2190e46b2a8efdfdb16a33a83538731a6d7eeeb91c7b81e8d1e022b15924fa30ee1e9770a9f9adf96989ffd7 tomcat-api-9.0.82.jar +dfb4a37dddf4bc4e9a41a1381544c81e3962a63833f024236d1ed28eabe8daae77cd79466881177ce9f729efad2f5169e9cf8a9e45c820b775c3a9223d258e6f tomcat-el-api-9.0.82.jar +db764d29d882458d8cc2aeded7b25b6129eeeb7d9ec5b77d380ca14add659a8c12f233802a5e8dfa287a1c1b9dbfd6a12fa053ec506443bde0dce9fb36081782 tomcat-jasper-9.0.82.jar +bcc9ffc0f4d50defb0fdb12c2f9a8bd89fd8758f768c2495baa9c0e77a0ae08f3e610f6893ecd30843cfda6021120d9886aab3e377309ded68cd83f3d32b654a tomcat-jasper-el-9.0.82.jar +d2d9154b622b18ef190146631984188d6353ad2cb3c6ec1922387c76ae4d279a511d76680271f29b861ee18b444894ed66e5e41030e0beb265bf47eecc1a3a81 tomcat-jsp-api-9.0.82.jar +e1c92251e2e1cd5fc99d304399fbb13af50b7d86e56ffca59edb85934474df2b8dd6b4ea3d949cc1d7cc21e673094a044b22d05bc45e540c9a0a211974ebee5c tomcat-juli-9.0.82.jar +7d30076e306403c243ed4d802fca6de7e827e7f6cef8827353fff4514bee484ff71abc61597fd92b63470c6477bb26c398d4cd9b293f059e0ff94156f0210106 tomcat-servlet-api-9.0.82.jar +b06b112011526911b08849093d61a4d4337283f4a54dee2d4f8f4ce55687eabdf5df97b9326e1430fe7cd4d043a16076e86c1354cc2661c19e87918c4635e3d1 tomcat-util-9.0.82.jar +dfe0beac3b4b8466454fb790e9dd7a17b97e62edb0f5caaaedab0360b32a0536b7d788f3d5511eb47ea3abca4f5751ab32c814c73dbf465529898d78b69fb8d6 tomcat-util-scan-9.0.82.jar diff --git a/docs/changes.xml b/docs/changes.xml index fca9ebcd..60f259ad 100644 --- a/docs/changes.xml +++ b/docs/changes.xml @@ -16,6 +16,95 @@ unit-jsc14 unit-jsc15 unit-jsc16 unit-jsc17 unit-jsc18 unit-jsc19 unit-jsc20 unit-wasm" + ver="1.31.1" rev="1" + date="2023-10-19" time="18:00:00 +0300" + packager="Nginx Packaging <nginx-packaging@f5.com>"> + +<change> +<para> +NGINX Unit updated to 1.31.1. +</para> +</change> + +</changes> + + +<changes apply="unit" ver="1.31.1" rev="1" + date="2023-10-19" time="18:00:00 +0300" + packager="Nginx Packaging <nginx-packaging@f5.com>"> + +<change type="feature"> +<para> +allow to set the HTTP response status in Wasm module. +</para> +</change> + +<change type="feature"> +<para> +allow uploads larger than 4GiB in Wasm module. +</para> +</change> + +<change type="bugfix"> +<para> +application process could crash while rewriting URLs with query strings. +</para> +</change> + +<change type="bugfix"> +<para> +requests larger than about 64MiB could cause error in Wasm module. +</para> +</change> + +<change type="bugfix"> +<para> +when using many headers in Java module some of them could be +corrupted due to memory realocation issue. +</para> +</change> + +<change type="bugfix"> +<para> +ServerRequest.destroy() implemented in Node.js module to make it compatible +with some frameworks that might use it. +</para> +</change> + +<change type="bugfix"> +<para> +chunk argument of ServerResponse.write() can now be a Uint8Array to improve +compatibility with Node.js 15.0.0 and above. +</para> +</change> + +<change type="bugfix"> +<para> +Node.JS unit-http NPM module now has appropriate default paths for +macOS/arm64 systems. +</para> +</change> + +<change type="bugfix"> +<para> +build on musl libc with clang. +</para> +</change> + +</changes> + + +<changes apply="unit-php + unit-python unit-python2.7 + unit-python3.4 unit-python3.5 unit-python3.6 unit-python3.7 + unit-python3.8 unit-python3.9 unit-python3.10 unit-python3.11 + unit-go + unit-perl + unit-ruby + unit-jsc-common unit-jsc8 unit-jsc10 unit-jsc11 unit-jsc13 + unit-jsc14 unit-jsc15 unit-jsc16 unit-jsc17 unit-jsc18 + unit-jsc19 unit-jsc20 + unit-wasm" ver="1.31.0" rev="1" date="2023-08-31" time="18:00:00 +0300" packager="Nginx Packaging <nginx-packaging@f5.com>"> diff --git a/docs/unit-openapi.yaml b/docs/unit-openapi.yaml index 0301326d..4ce26fa0 100644 --- a/docs/unit-openapi.yaml +++ b/docs/unit-openapi.yaml @@ -1,6 +1,6 @@ openapi: 3.0.0 info: - title: "NGINX Unit 1.30.0" + title: "NGINX Unit 1.31.1" description: "NGINX Unit is a lightweight and versatile application runtime that provides the essential components for your web application as a single open-source server: running application code, serving static assets, @@ -5887,6 +5887,7 @@ components: description: "An object whose options define a step's action." oneOf: - $ref: "#/components/schemas/configRouteStepActionPass" + - $ref: "#/components/schemas/configRouteStepActionProxy" - $ref: "#/components/schemas/configRouteStepActionReturn" - $ref: "#/components/schemas/configRouteStepActionShare" @@ -5903,6 +5904,32 @@ components: description: "Destination to which the action passes incoming requests." + rewrite: + $ref: "#/components/schemas/configRouteStepActionRewrite" + + response_headers: + $ref: "#/components/schemas/configRouteStepActionResponseHeaders" + + #/config/routes/{stepIndex}/action/proxy + #/config/routes/{routeName}/{stepIndex}/action/proxy + configRouteStepActionProxy: + type: object + description: "An object whose single option defines a step's proxy + action." + required: + - proxy + properties: + proxy: + type: string + description: "Socket address of an HTTP server to where the request + is proxied." + + rewrite: + $ref: "#/components/schemas/configRouteStepActionRewrite" + + response_headers: + $ref: "#/components/schemas/configRouteStepActionResponseHeaders" + #/config/routes/{stepIndex}/action/return #/config/routes/{routeName}/{stepIndex}/action/return configRouteStepActionReturn: @@ -5922,6 +5949,12 @@ components: type: string description: "URI; used if the return value implies redirection." + rewrite: + $ref: "#/components/schemas/configRouteStepActionRewrite" + + response_headers: + $ref: "#/components/schemas/configRouteStepActionResponseHeaders" + #/config/routes/{stepIndex}/action/share #/config/routes/{routeName}/{stepIndex}/action/share configRouteStepActionShare: @@ -5964,6 +5997,28 @@ components: description: "Turns on and off mount point resolution." default: true + rewrite: + $ref: "#/components/schemas/configRouteStepActionRewrite" + + response_headers: + $ref: "#/components/schemas/configRouteStepActionResponseHeaders" + + #/config/routes/{stepIndex}/action/rewrite + #/config/routes/{routeName}/{stepIndex}/action/rewrite + configRouteStepActionRewrite: + type: string + description: "Updates the URI of the incoming request before the action + is applied." + + #/config/routes/{stepIndex}/action/response_headers + #/config/routes/{routeName}/{stepIndex}/action/response_headers + configRouteStepActionResponseHeaders: + type: object + description: "Updates the header fields of Unit’s response before the + action is taken." + additionalProperties: + type: string + # /config/listeners/ configListeners: type: object diff --git a/pkg/contrib/src/njs/SHA512SUMS b/pkg/contrib/src/njs/SHA512SUMS index ad8e180c..3c3ce210 100644 --- a/pkg/contrib/src/njs/SHA512SUMS +++ b/pkg/contrib/src/njs/SHA512SUMS @@ -1 +1 @@ -200f3ae1e1909f0d8086e2fbfbd6b8654e596f3ad2e4cf4d863e201cfcb2f86a419fa9061067cbededf6a8c792c1a5ecf60c3a4c983af044c179bb9fe619eea5 njs-0.8.0.tar.gz +5038b4cd9e18de89c9cf7fe7b25a0a8a03c51cfb20b6ee5085e68f885113b104092baf5ac8fe80e9d1611b2f75e47448753e6b327bef2e706ea46f2d6299f927 njs-0.8.1.tar.gz diff --git a/pkg/contrib/src/njs/version b/pkg/contrib/src/njs/version index 8c9ee6ba..73c524fb 100644 --- a/pkg/contrib/src/njs/version +++ b/pkg/contrib/src/njs/version @@ -1 +1 @@ -NJS_VERSION := 0.8.0 +NJS_VERSION := 0.8.1 diff --git a/pkg/docker/Dockerfile.go1.20 b/pkg/docker/Dockerfile.go1.20 index 98f6d92f..53379dd1 100644 --- a/pkg/docker/Dockerfile.go1.20 +++ b/pkg/docker/Dockerfile.go1.20 @@ -6,7 +6,7 @@ LABEL org.opencontainers.image.url="https://unit.nginx.org" LABEL org.opencontainers.image.source="https://github.com/nginx/unit" LABEL org.opencontainers.image.documentation="https://unit.nginx.org/installation/#docker-images" LABEL org.opencontainers.image.vendor="NGINX Docker Maintainers <docker-maint@nginx.com>" -LABEL org.opencontainers.image.version="1.31.0" +LABEL org.opencontainers.image.version="1.31.1" RUN set -ex \ && savedAptMark="$(apt-mark showmanual)" \ @@ -15,7 +15,7 @@ RUN set -ex \ && mkdir -p /usr/lib/unit/modules /usr/lib/unit/debug-modules \ && mkdir -p /usr/src/unit \ && cd /usr/src/unit \ - && hg clone -u 1.31.0-1 https://hg.nginx.org/unit \ + && hg clone -u 1.31.1-1 https://hg.nginx.org/unit \ && cd unit \ && NCPU="$(getconf _NPROCESSORS_ONLN)" \ && DEB_HOST_MULTIARCH="$(dpkg-architecture -q DEB_HOST_MULTIARCH)" \ diff --git a/pkg/docker/Dockerfile.go1.21 b/pkg/docker/Dockerfile.go1.21 index 18d3cc7b..a90dc115 100644 --- a/pkg/docker/Dockerfile.go1.21 +++ b/pkg/docker/Dockerfile.go1.21 @@ -6,7 +6,7 @@ LABEL org.opencontainers.image.url="https://unit.nginx.org" LABEL org.opencontainers.image.source="https://github.com/nginx/unit" LABEL org.opencontainers.image.documentation="https://unit.nginx.org/installation/#docker-images" LABEL org.opencontainers.image.vendor="NGINX Docker Maintainers <docker-maint@nginx.com>" -LABEL org.opencontainers.image.version="1.31.0" +LABEL org.opencontainers.image.version="1.31.1" RUN set -ex \ && savedAptMark="$(apt-mark showmanual)" \ @@ -15,7 +15,7 @@ RUN set -ex \ && mkdir -p /usr/lib/unit/modules /usr/lib/unit/debug-modules \ && mkdir -p /usr/src/unit \ && cd /usr/src/unit \ - && hg clone -u 1.31.0-1 https://hg.nginx.org/unit \ + && hg clone -u 1.31.1-1 https://hg.nginx.org/unit \ && cd unit \ && NCPU="$(getconf _NPROCESSORS_ONLN)" \ && DEB_HOST_MULTIARCH="$(dpkg-architecture -q DEB_HOST_MULTIARCH)" \ diff --git a/pkg/docker/Dockerfile.jsc11 b/pkg/docker/Dockerfile.jsc11 index e7a057bd..2844c813 100644 --- a/pkg/docker/Dockerfile.jsc11 +++ b/pkg/docker/Dockerfile.jsc11 @@ -6,7 +6,7 @@ LABEL org.opencontainers.image.url="https://unit.nginx.org" LABEL org.opencontainers.image.source="https://github.com/nginx/unit" LABEL org.opencontainers.image.documentation="https://unit.nginx.org/installation/#docker-images" LABEL org.opencontainers.image.vendor="NGINX Docker Maintainers <docker-maint@nginx.com>" -LABEL org.opencontainers.image.version="1.31.0" +LABEL org.opencontainers.image.version="1.31.1" RUN set -ex \ && savedAptMark="$(apt-mark showmanual)" \ @@ -15,7 +15,7 @@ RUN set -ex \ && mkdir -p /usr/lib/unit/modules /usr/lib/unit/debug-modules \ && mkdir -p /usr/src/unit \ && cd /usr/src/unit \ - && hg clone -u 1.31.0-1 https://hg.nginx.org/unit \ + && hg clone -u 1.31.1-1 https://hg.nginx.org/unit \ && cd unit \ && NCPU="$(getconf _NPROCESSORS_ONLN)" \ && DEB_HOST_MULTIARCH="$(dpkg-architecture -q DEB_HOST_MULTIARCH)" \ diff --git a/pkg/docker/Dockerfile.minimal b/pkg/docker/Dockerfile.minimal index 8c5ce0d5..4b585480 100644 --- a/pkg/docker/Dockerfile.minimal +++ b/pkg/docker/Dockerfile.minimal @@ -6,7 +6,7 @@ LABEL org.opencontainers.image.url="https://unit.nginx.org" LABEL org.opencontainers.image.source="https://github.com/nginx/unit" LABEL org.opencontainers.image.documentation="https://unit.nginx.org/installation/#docker-images" LABEL org.opencontainers.image.vendor="NGINX Docker Maintainers <docker-maint@nginx.com>" -LABEL org.opencontainers.image.version="1.31.0" +LABEL org.opencontainers.image.version="1.31.1" RUN set -ex \ && savedAptMark="$(apt-mark showmanual)" \ @@ -15,7 +15,7 @@ RUN set -ex \ && mkdir -p /usr/lib/unit/modules /usr/lib/unit/debug-modules \ && mkdir -p /usr/src/unit \ && cd /usr/src/unit \ - && hg clone -u 1.31.0-1 https://hg.nginx.org/unit \ + && hg clone -u 1.31.1-1 https://hg.nginx.org/unit \ && cd unit \ && NCPU="$(getconf _NPROCESSORS_ONLN)" \ && DEB_HOST_MULTIARCH="$(dpkg-architecture -q DEB_HOST_MULTIARCH)" \ diff --git a/pkg/docker/Dockerfile.node18 b/pkg/docker/Dockerfile.node18 index 735342dd..4ac18847 100644 --- a/pkg/docker/Dockerfile.node18 +++ b/pkg/docker/Dockerfile.node18 @@ -6,7 +6,7 @@ LABEL org.opencontainers.image.url="https://unit.nginx.org" LABEL org.opencontainers.image.source="https://github.com/nginx/unit" LABEL org.opencontainers.image.documentation="https://unit.nginx.org/installation/#docker-images" LABEL org.opencontainers.image.vendor="NGINX Docker Maintainers <docker-maint@nginx.com>" -LABEL org.opencontainers.image.version="1.31.0" +LABEL org.opencontainers.image.version="1.31.1" RUN set -ex \ && savedAptMark="$(apt-mark showmanual)" \ @@ -15,7 +15,7 @@ RUN set -ex \ && mkdir -p /usr/lib/unit/modules /usr/lib/unit/debug-modules \ && mkdir -p /usr/src/unit \ && cd /usr/src/unit \ - && hg clone -u 1.31.0-1 https://hg.nginx.org/unit \ + && hg clone -u 1.31.1-1 https://hg.nginx.org/unit \ && cd unit \ && NCPU="$(getconf _NPROCESSORS_ONLN)" \ && DEB_HOST_MULTIARCH="$(dpkg-architecture -q DEB_HOST_MULTIARCH)" \ diff --git a/pkg/docker/Dockerfile.node20 b/pkg/docker/Dockerfile.node20 index f291ccfc..f783ba72 100644 --- a/pkg/docker/Dockerfile.node20 +++ b/pkg/docker/Dockerfile.node20 @@ -6,7 +6,7 @@ LABEL org.opencontainers.image.url="https://unit.nginx.org" LABEL org.opencontainers.image.source="https://github.com/nginx/unit" LABEL org.opencontainers.image.documentation="https://unit.nginx.org/installation/#docker-images" LABEL org.opencontainers.image.vendor="NGINX Docker Maintainers <docker-maint@nginx.com>" -LABEL org.opencontainers.image.version="1.31.0" +LABEL org.opencontainers.image.version="1.31.1" RUN set -ex \ && savedAptMark="$(apt-mark showmanual)" \ @@ -15,7 +15,7 @@ RUN set -ex \ && mkdir -p /usr/lib/unit/modules /usr/lib/unit/debug-modules \ && mkdir -p /usr/src/unit \ && cd /usr/src/unit \ - && hg clone -u 1.31.0-1 https://hg.nginx.org/unit \ + && hg clone -u 1.31.1-1 https://hg.nginx.org/unit \ && cd unit \ && NCPU="$(getconf _NPROCESSORS_ONLN)" \ && DEB_HOST_MULTIARCH="$(dpkg-architecture -q DEB_HOST_MULTIARCH)" \ diff --git a/pkg/docker/Dockerfile.perl5.36 b/pkg/docker/Dockerfile.perl5.36 index 2db7506d..8cc5d9e2 100644 --- a/pkg/docker/Dockerfile.perl5.36 +++ b/pkg/docker/Dockerfile.perl5.36 @@ -6,7 +6,7 @@ LABEL org.opencontainers.image.url="https://unit.nginx.org" LABEL org.opencontainers.image.source="https://github.com/nginx/unit" LABEL org.opencontainers.image.documentation="https://unit.nginx.org/installation/#docker-images" LABEL org.opencontainers.image.vendor="NGINX Docker Maintainers <docker-maint@nginx.com>" -LABEL org.opencontainers.image.version="1.31.0" +LABEL org.opencontainers.image.version="1.31.1" RUN set -ex \ && savedAptMark="$(apt-mark showmanual)" \ @@ -15,7 +15,7 @@ RUN set -ex \ && mkdir -p /usr/lib/unit/modules /usr/lib/unit/debug-modules \ && mkdir -p /usr/src/unit \ && cd /usr/src/unit \ - && hg clone -u 1.31.0-1 https://hg.nginx.org/unit \ + && hg clone -u 1.31.1-1 https://hg.nginx.org/unit \ && cd unit \ && NCPU="$(getconf _NPROCESSORS_ONLN)" \ && DEB_HOST_MULTIARCH="$(dpkg-architecture -q DEB_HOST_MULTIARCH)" \ diff --git a/pkg/docker/Dockerfile.perl5.38 b/pkg/docker/Dockerfile.perl5.38 index bd653cb1..531188fe 100644 --- a/pkg/docker/Dockerfile.perl5.38 +++ b/pkg/docker/Dockerfile.perl5.38 @@ -6,7 +6,7 @@ LABEL org.opencontainers.image.url="https://unit.nginx.org" LABEL org.opencontainers.image.source="https://github.com/nginx/unit" LABEL org.opencontainers.image.documentation="https://unit.nginx.org/installation/#docker-images" LABEL org.opencontainers.image.vendor="NGINX Docker Maintainers <docker-maint@nginx.com>" -LABEL org.opencontainers.image.version="1.31.0" +LABEL org.opencontainers.image.version="1.31.1" RUN set -ex \ && savedAptMark="$(apt-mark showmanual)" \ @@ -15,7 +15,7 @@ RUN set -ex \ && mkdir -p /usr/lib/unit/modules /usr/lib/unit/debug-modules \ && mkdir -p /usr/src/unit \ && cd /usr/src/unit \ - && hg clone -u 1.31.0-1 https://hg.nginx.org/unit \ + && hg clone -u 1.31.1-1 https://hg.nginx.org/unit \ && cd unit \ && NCPU="$(getconf _NPROCESSORS_ONLN)" \ && DEB_HOST_MULTIARCH="$(dpkg-architecture -q DEB_HOST_MULTIARCH)" \ diff --git a/pkg/docker/Dockerfile.php8.2 b/pkg/docker/Dockerfile.php8.2 index bd27a4dd..5783bf6c 100644 --- a/pkg/docker/Dockerfile.php8.2 +++ b/pkg/docker/Dockerfile.php8.2 @@ -6,7 +6,7 @@ LABEL org.opencontainers.image.url="https://unit.nginx.org" LABEL org.opencontainers.image.source="https://github.com/nginx/unit" LABEL org.opencontainers.image.documentation="https://unit.nginx.org/installation/#docker-images" LABEL org.opencontainers.image.vendor="NGINX Docker Maintainers <docker-maint@nginx.com>" -LABEL org.opencontainers.image.version="1.31.0" +LABEL org.opencontainers.image.version="1.31.1" RUN set -ex \ && savedAptMark="$(apt-mark showmanual)" \ @@ -15,7 +15,7 @@ RUN set -ex \ && mkdir -p /usr/lib/unit/modules /usr/lib/unit/debug-modules \ && mkdir -p /usr/src/unit \ && cd /usr/src/unit \ - && hg clone -u 1.31.0-1 https://hg.nginx.org/unit \ + && hg clone -u 1.31.1-1 https://hg.nginx.org/unit \ && cd unit \ && NCPU="$(getconf _NPROCESSORS_ONLN)" \ && DEB_HOST_MULTIARCH="$(dpkg-architecture -q DEB_HOST_MULTIARCH)" \ diff --git a/pkg/docker/Dockerfile.python3.11 b/pkg/docker/Dockerfile.python3.11 index cdc96434..b5e81b6c 100644 --- a/pkg/docker/Dockerfile.python3.11 +++ b/pkg/docker/Dockerfile.python3.11 @@ -6,7 +6,7 @@ LABEL org.opencontainers.image.url="https://unit.nginx.org" LABEL org.opencontainers.image.source="https://github.com/nginx/unit" LABEL org.opencontainers.image.documentation="https://unit.nginx.org/installation/#docker-images" LABEL org.opencontainers.image.vendor="NGINX Docker Maintainers <docker-maint@nginx.com>" -LABEL org.opencontainers.image.version="1.31.0" +LABEL org.opencontainers.image.version="1.31.1" RUN set -ex \ && savedAptMark="$(apt-mark showmanual)" \ @@ -15,7 +15,7 @@ RUN set -ex \ && mkdir -p /usr/lib/unit/modules /usr/lib/unit/debug-modules \ && mkdir -p /usr/src/unit \ && cd /usr/src/unit \ - && hg clone -u 1.31.0-1 https://hg.nginx.org/unit \ + && hg clone -u 1.31.1-1 https://hg.nginx.org/unit \ && cd unit \ && NCPU="$(getconf _NPROCESSORS_ONLN)" \ && DEB_HOST_MULTIARCH="$(dpkg-architecture -q DEB_HOST_MULTIARCH)" \ diff --git a/pkg/docker/Dockerfile.ruby3.2 b/pkg/docker/Dockerfile.ruby3.2 index 8b870756..c417a327 100644 --- a/pkg/docker/Dockerfile.ruby3.2 +++ b/pkg/docker/Dockerfile.ruby3.2 @@ -6,7 +6,7 @@ LABEL org.opencontainers.image.url="https://unit.nginx.org" LABEL org.opencontainers.image.source="https://github.com/nginx/unit" LABEL org.opencontainers.image.documentation="https://unit.nginx.org/installation/#docker-images" LABEL org.opencontainers.image.vendor="NGINX Docker Maintainers <docker-maint@nginx.com>" -LABEL org.opencontainers.image.version="1.31.0" +LABEL org.opencontainers.image.version="1.31.1" RUN set -ex \ && savedAptMark="$(apt-mark showmanual)" \ @@ -15,7 +15,7 @@ RUN set -ex \ && mkdir -p /usr/lib/unit/modules /usr/lib/unit/debug-modules \ && mkdir -p /usr/src/unit \ && cd /usr/src/unit \ - && hg clone -u 1.31.0-1 https://hg.nginx.org/unit \ + && hg clone -u 1.31.1-1 https://hg.nginx.org/unit \ && cd unit \ && NCPU="$(getconf _NPROCESSORS_ONLN)" \ && DEB_HOST_MULTIARCH="$(dpkg-architecture -q DEB_HOST_MULTIARCH)" \ diff --git a/pkg/docker/Dockerfile.wasm b/pkg/docker/Dockerfile.wasm index 852bc5d0..e45f020f 100644 --- a/pkg/docker/Dockerfile.wasm +++ b/pkg/docker/Dockerfile.wasm @@ -6,7 +6,7 @@ LABEL org.opencontainers.image.url="https://unit.nginx.org" LABEL org.opencontainers.image.source="https://github.com/nginx/unit" LABEL org.opencontainers.image.documentation="https://unit.nginx.org/installation/#docker-images" LABEL org.opencontainers.image.vendor="NGINX Docker Maintainers <docker-maint@nginx.com>" -LABEL org.opencontainers.image.version="1.31.0" +LABEL org.opencontainers.image.version="1.31.1" RUN set -ex \ && savedAptMark="$(apt-mark showmanual)" \ @@ -15,7 +15,7 @@ RUN set -ex \ && mkdir -p /usr/lib/unit/modules /usr/lib/unit/debug-modules \ && mkdir -p /usr/src/unit \ && cd /usr/src/unit \ - && hg clone -u 1.31.0-1 https://hg.nginx.org/unit \ + && hg clone -u 1.31.1-1 https://hg.nginx.org/unit \ && cd unit \ && NCPU="$(getconf _NPROCESSORS_ONLN)" \ && DEB_HOST_MULTIARCH="$(dpkg-architecture -q DEB_HOST_MULTIARCH)" \ diff --git a/pkg/docker/welcome.html b/pkg/docker/welcome.html index 9c4f8281..89de39e1 100644 --- a/pkg/docker/welcome.html +++ b/pkg/docker/welcome.html @@ -35,7 +35,7 @@ on the <a href="https://en.wikipedia.org/wiki/Unix_domain_socket">Unix socket</a> at <b>/var/run/control.unit.sock</b> inside the container.<br> To see the current configuration run:</p> - <pre>docker exec -ti <containerID> curl --unix-socket /var/run/control.unit.sock http://localhost/config</pre> + <pre>docker exec -ti <containerID> curl --unix-socket /var/run/control.unit.sock http://localhost/config</pre> </div> <hr> diff --git a/src/java/nxt_jni_Response.c b/src/java/nxt_jni_Response.c index 2ccfd854..fa698ee8 100644 --- a/src/java/nxt_jni_Response.c +++ b/src/java/nxt_jni_Response.c @@ -334,7 +334,8 @@ nxt_java_get_response_info(jlong req_info_ptr, uint32_t extra_fields, - req->response->fields_count || extra_data > (uint32_t) (buf->end - buf->free)) { - p = buf->start + req->response_max_fields * sizeof(nxt_unit_field_t); + p = buf->start + sizeof(nxt_unit_response_t) + + req->response_max_fields * sizeof(nxt_unit_field_t); max_size = 2 * (buf->end - p); if (max_size > nxt_unit_buf_max()) { @@ -936,8 +937,8 @@ nxt_java_Response_reset(JNIEnv *env, jclass cls, jlong req_info_ptr) buf = req->response_buf; - buf->free = buf->start + req->response_max_fields - * sizeof(nxt_unit_field_t); + buf->free = buf->start + sizeof(nxt_unit_response_t) + + req->response_max_fields * sizeof(nxt_unit_field_t); } } diff --git a/src/nodejs/unit-http/binding_pub.gyp b/src/nodejs/unit-http/binding_pub.gyp index 3c39933a..3dadf4a5 100644 --- a/src/nodejs/unit-http/binding_pub.gyp +++ b/src/nodejs/unit-http/binding_pub.gyp @@ -7,9 +7,28 @@ ['OS=="mac"', { 'xcode_settings': { 'GCC_ENABLE_CPP_EXCEPTIONS': 'YES' - } - }] - ], + }, + 'conditions': [ + [ 'target_arch=="arm64"', { + 'include_dirs': [ + '/opt/homebrew/include' + ], + 'libraries' : [ + '-L/opt/homebrew/lib', + '-lunit' + ], + }], + ['target_arch=="x64"', { + 'include_dirs': [ + '/usr/local/include', + ], + 'libraries' : [ + '-L/usr/local/lib', + '-lunit' + ], + }] + ]} + ]], 'sources': ["unit.cpp", "addon.cpp"], 'libraries': ["-lunit"] }] diff --git a/src/nodejs/unit-http/http_server.js b/src/nodejs/unit-http/http_server.js index 89964ec3..0f00b47f 100644 --- a/src/nodejs/unit-http/http_server.js +++ b/src/nodejs/unit-http/http_server.js @@ -33,8 +33,17 @@ ServerResponse.prototype.statusMessage = undefined; ServerResponse.prototype.headers_len = 0; ServerResponse.prototype.headers_count = 0; ServerResponse.prototype.headersSent = false; +ServerResponse.prototype.destroyed = false; ServerResponse.prototype.finished = false; +ServerResponse.prototype.destroy = function destroy(error) { + if (!this.destroyed) { + this.destroyed = true; + } + + return this; +}; + ServerResponse.prototype._finish = function _finish() { this.headers = {}; this.headers_len = 0; @@ -243,8 +252,11 @@ ServerResponse.prototype._writeBody = function(chunk, encoding, callback) { } if (chunk) { - if (typeof chunk !== 'string' && !(chunk instanceof Buffer)) { - throw new TypeError('First argument must be a string or Buffer'); + if (typeof chunk !== 'string' && !(chunk instanceof Buffer || + chunk instanceof Uint8Array)) { + throw new TypeError( + 'First argument must be a string, Buffer, ' + + 'or Uint8Array'); } if (typeof chunk === 'string') { diff --git a/src/nxt_conn_write.c b/src/nxt_conn_write.c index bcf9e8fa..714a3e15 100644 --- a/src/nxt_conn_write.c +++ b/src/nxt_conn_write.c @@ -97,7 +97,7 @@ nxt_conn_io_write(nxt_task_t *task, void *obj, void *data) if (sb.limit == 0) { /* * Postpone writing until next event poll to allow to - * process other recevied events and to get new events. + * process other received events and to get new events. */ c->write_timer.handler = nxt_conn_write_timer_handler; nxt_timer_add(engine, &c->write_timer, 0); diff --git a/src/nxt_controller.c b/src/nxt_controller.c index 4e2e3749..eb814321 100644 --- a/src/nxt_controller.c +++ b/src/nxt_controller.c @@ -510,8 +510,9 @@ nxt_controller_conf_default(void) nxt_mp_t *mp; nxt_conf_value_t *conf; - static const nxt_str_t json - = nxt_string("{ \"listeners\": {}, \"applications\": {} }"); + static const nxt_str_t json = nxt_string( + "{ \"listeners\": {}, \"routes\": [], \"applications\": {} }" + ); mp = nxt_mp_create(1024, 128, 256, 32); diff --git a/src/nxt_http_rewrite.c b/src/nxt_http_rewrite.c index ae5c865a..fb216eeb 100644 --- a/src/nxt_http_rewrite.c +++ b/src/nxt_http_rewrite.c @@ -93,6 +93,7 @@ nxt_http_rewrite(nxt_task_t *task, nxt_http_request_t *r) nxt_memcpy(p, r->args->start, r->args->length); r->target = target; + r->args->start = p; } r->path = nxt_mp_alloc(r->mem_pool, sizeof(nxt_str_t)); diff --git a/src/nxt_main_process.c b/src/nxt_main_process.c index 6622f67e..3f317d5e 100644 --- a/src/nxt_main_process.c +++ b/src/nxt_main_process.c @@ -856,7 +856,7 @@ nxt_main_process_sigusr1_handler(nxt_task_t *task, void *obj, void *data) nxt_array_t *new_files; nxt_runtime_t *rt; - nxt_log(task, NXT_LOG_NOTICE, "signal %d (%s) recevied, %s", + nxt_log(task, NXT_LOG_NOTICE, "signal %d (%s) received, %s", (int) (uintptr_t) obj, data, "log files rotation"); rt = task->thread->runtime; @@ -1073,7 +1073,7 @@ nxt_main_process_sigchld_handler(nxt_task_t *task, void *obj, void *data) static void nxt_main_process_signal_handler(nxt_task_t *task, void *obj, void *data) { - nxt_trace(task, "signal signo:%d (%s) recevied, ignored", + nxt_trace(task, "signal signo:%d (%s) received, ignored", (int) (uintptr_t) obj, data); } diff --git a/src/nxt_signal_handlers.c b/src/nxt_signal_handlers.c index 69ae2bc4..63b38fab 100644 --- a/src/nxt_signal_handlers.c +++ b/src/nxt_signal_handlers.c @@ -31,7 +31,7 @@ const nxt_sig_event_t nxt_process_signals[] = { static void nxt_signal_handler(nxt_task_t *task, void *obj, void *data) { - nxt_trace(task, "signal signo:%d (%s) recevied, ignored", + nxt_trace(task, "signal signo:%d (%s) received, ignored", (int) (uintptr_t) obj, data); } diff --git a/src/nxt_socket_msg.h b/src/nxt_socket_msg.h index 04de1761..81617bd6 100644 --- a/src/nxt_socket_msg.h +++ b/src/nxt_socket_msg.h @@ -69,6 +69,20 @@ NXT_EXPORT ssize_t nxt_recvmsg(nxt_socket_t s, nxt_iobuf_t *iob, nxt_uint_t niob, nxt_recv_oob_t *oob); +nxt_inline struct cmsghdr * +NXT_CMSG_NXTHDR(struct msghdr *msgh, struct cmsghdr *cmsg) +{ +#if !defined(__GLIBC__) && defined(__clang__) +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wsign-compare" +#endif + return CMSG_NXTHDR(msgh, cmsg); +#if !defined(__GLIBC__) && defined(__clang__) +#pragma clang diagnostic pop +#endif +} + + nxt_inline void nxt_socket_msg_oob_init(nxt_send_oob_t *oob, int *fds) { @@ -135,7 +149,7 @@ nxt_socket_msg_oob_get_fds(nxt_recv_oob_t *oob, nxt_fd_t *fd) for (cmsg = CMSG_FIRSTHDR(&msg); cmsg != NULL; - cmsg = CMSG_NXTHDR(&msg, cmsg)) + cmsg = NXT_CMSG_NXTHDR(&msg, cmsg)) { size = cmsg->cmsg_len - CMSG_LEN(0); @@ -174,7 +188,7 @@ nxt_socket_msg_oob_get(nxt_recv_oob_t *oob, nxt_fd_t *fd, nxt_pid_t *pid) for (cmsg = CMSG_FIRSTHDR(&msg); cmsg != NULL; - cmsg = CMSG_NXTHDR(&msg, cmsg)) + cmsg = NXT_CMSG_NXTHDR(&msg, cmsg)) { size = cmsg->cmsg_len - CMSG_LEN(0); diff --git a/src/nxt_sprintf.c b/src/nxt_sprintf.c index 9c8e27ed..875f43a5 100644 --- a/src/nxt_sprintf.c +++ b/src/nxt_sprintf.c @@ -156,7 +156,8 @@ nxt_vsprintf(u_char *buf, u_char *end, const char *fmt, va_list args) p = va_arg(args, const u_char *); if (nxt_slow_path(p == NULL)) { - goto copy; + buf = nxt_cpymem(buf, null, nxt_length(null)); + continue; } while (*p != '\0' && buf < end) { @@ -174,6 +175,11 @@ nxt_vsprintf(u_char *buf, u_char *end, const char *fmt, va_list args) fmt++; p = va_arg(args, const u_char *); + if (nxt_slow_path(p == NULL)) { + buf = nxt_cpymem(buf, null, nxt_length(null)); + continue; + } + goto copy; } @@ -556,14 +562,7 @@ nxt_vsprintf(u_char *buf, u_char *end, const char *fmt, va_list args) copy: - if (nxt_slow_path(p == NULL)) { - p = null; - length = nxt_length(null); - - } else { - length = nxt_min((size_t) (end - buf), length); - } - + length = nxt_min((size_t) (end - buf), length); buf = nxt_cpymem(buf, p, length); continue; } diff --git a/src/nxt_unit.c b/src/nxt_unit.c index e1b1897a..b6291b2d 100644 --- a/src/nxt_unit.c +++ b/src/nxt_unit.c @@ -2148,7 +2148,8 @@ nxt_unit_response_realloc(nxt_unit_request_info_t *req, resp->status = req->response->status; resp->content_length = req->response->content_length; - p = buf->start + max_fields_count * sizeof(nxt_unit_field_t); + p = buf->start + sizeof(nxt_unit_response_t) + + max_fields_count * sizeof(nxt_unit_field_t); f = resp->fields; for (i = 0; i < req->response->fields_count; i++) { diff --git a/src/wasm/nxt_rt_wasmtime.c b/src/wasm/nxt_rt_wasmtime.c index 99786b89..bf0b0a0f 100644 --- a/src/wasm/nxt_rt_wasmtime.c +++ b/src/wasm/nxt_rt_wasmtime.c @@ -102,6 +102,19 @@ nxt_wasm_send_headers(void *env, wasmtime_caller_t *caller, } +static wasm_trap_t * +nxt_wasm_set_resp_status(void *env, wasmtime_caller_t *caller, + const wasmtime_val_t *args, size_t nargs, + wasmtime_val_t *results, size_t nresults) +{ + nxt_wasm_ctx_t *ctx = env; + + ctx->status = args[0].of.i32; + + return NULL; +} + + static void nxt_wasmtime_execute_hook(const nxt_wasm_ctx_t *ctx, nxt_wasm_fh_t hook) { @@ -123,7 +136,7 @@ nxt_wasmtime_execute_hook(const nxt_wasm_ctx_t *ctx, nxt_wasm_fh_t hook) } -static void +static int nxt_wasmtime_execute_request(const nxt_wasm_ctx_t *ctx) { int i = 0; @@ -142,7 +155,10 @@ nxt_wasmtime_execute_request(const nxt_wasm_ctx_t *ctx) nxt_wasmtime_err_msg(error, trap, "failed to call function [->wasm_request_handler]" ); + return -1; } + + return results[0].of.i32; } @@ -183,6 +199,11 @@ nxt_wasmtime_set_function_imports(nxt_wasm_ctx_t *ctx) .func = nxt_wasm_send_headers, .params = { WASM_I32 }, .ft = NXT_WASM_FT_1_0 + }, { + .func_name = "nxt_wasm_set_resp_status", + .func = nxt_wasm_set_resp_status, + .params = { WASM_I32 }, + .ft = NXT_WASM_FT_1_0 }, { } diff --git a/src/wasm/nxt_wasm.c b/src/wasm/nxt_wasm.c index 45a40b4b..92ed57ab 100644 --- a/src/wasm/nxt_wasm.c +++ b/src/wasm/nxt_wasm.c @@ -24,6 +24,11 @@ static nxt_wasm_ctx_t nxt_wasm_ctx; static const nxt_wasm_operations_t *nxt_wops; +enum { + NXT_WASM_HTTP_OK = 200, + NXT_WASM_HTTP_ERROR = 500 +}; + void nxt_wasm_do_response_end(nxt_wasm_ctx_t *ctx) @@ -48,7 +53,7 @@ nxt_wasm_do_send_headers(nxt_wasm_ctx_t *ctx, uint32_t offset) fields_len += rh->fields[i].name_len + rh->fields[i].value_len; } - nxt_unit_response_init(ctx->req, 200, rh->nfields, fields_len); + nxt_unit_response_init(ctx->req, ctx->status, rh->nfields, fields_len); for (i = 0; i < rh->nfields; i++) { const char *name; @@ -72,7 +77,7 @@ nxt_wasm_do_send_response(nxt_wasm_ctx_t *ctx, uint32_t offset) nxt_unit_request_info_t *req = ctx->req; if (!nxt_unit_response_is_init(req)) { - nxt_unit_response_init(req, 200, 0, 0); + nxt_unit_response_init(req, ctx->status, 0, 0); } resp = (nxt_wasm_response_t *)(nxt_wasm_ctx.baddr + offset); @@ -84,6 +89,7 @@ nxt_wasm_do_send_response(nxt_wasm_ctx_t *ctx, uint32_t offset) static void nxt_wasm_request_handler(nxt_unit_request_info_t *req) { + int err; size_t offset, read_bytes, content_sent, content_len; ssize_t bytes_read; nxt_unit_field_t *sf, *sf_end; @@ -149,15 +155,18 @@ nxt_wasm_request_handler(nxt_unit_request_info_t *req) wr->request_size = offset + bytes_read; + nxt_wasm_ctx.status = NXT_WASM_HTTP_OK; nxt_wasm_ctx.req = req; - nxt_wops->exec_request(&nxt_wasm_ctx); + err = nxt_wops->exec_request(&nxt_wasm_ctx); + if (err) { + goto out_err_500; + } if (content_len == content_sent) { goto request_done; } - wr->nfields = 0; - wr->content_off = offset = sizeof(nxt_wasm_request_t); + offset = sizeof(nxt_wasm_request_t); do { read_bytes = nxt_min(content_len - content_sent, NXT_WASM_MEM_SIZE - offset); @@ -167,10 +176,20 @@ nxt_wasm_request_handler(nxt_unit_request_info_t *req) content_sent += bytes_read; wr->request_size = wr->content_sent = bytes_read; wr->total_content_sent = content_sent; + wr->content_off = offset; - nxt_wops->exec_request(&nxt_wasm_ctx); + err = nxt_wops->exec_request(&nxt_wasm_ctx); + if (err) { + goto out_err_500; + } } while (content_sent < content_len); + goto request_done; + +out_err_500: + nxt_unit_response_init(req, NXT_WASM_HTTP_ERROR, 0, 0); + nxt_unit_request_done(req, NXT_UNIT_OK); + request_done: NXT_WASM_DO_HOOK(NXT_WASM_FH_REQUEST_END); } diff --git a/src/wasm/nxt_wasm.h b/src/wasm/nxt_wasm.h index cb9dbdfe..6bc3ae35 100644 --- a/src/wasm/nxt_wasm.h +++ b/src/wasm/nxt_wasm.h @@ -59,10 +59,10 @@ struct nxt_wasm_request_s { uint32_t server_name_off; uint32_t server_name_len; - uint32_t content_off; - uint32_t content_len; + uint64_t content_len; + uint64_t total_content_sent; uint32_t content_sent; - uint32_t total_content_sent; + uint32_t content_off; uint32_t request_size; @@ -70,6 +70,8 @@ struct nxt_wasm_request_s { uint32_t tls; + char __pad[4]; + nxt_wasm_http_field_t fields[]; }; @@ -118,12 +120,14 @@ struct nxt_wasm_ctx_s { size_t baddr_off; size_t response_off; + + uint16_t status; }; struct nxt_wasm_operations_s { int (*init)(nxt_wasm_ctx_t *ctx); void (*destroy)(const nxt_wasm_ctx_t *ctx); - void (*exec_request)(const nxt_wasm_ctx_t *ctx); + int (*exec_request)(const nxt_wasm_ctx_t *ctx); void (*exec_hook)(const nxt_wasm_ctx_t *ctx, nxt_wasm_fh_t hook); }; diff --git a/test/node/write_array/app.js b/test/node/write_array/app.js new file mode 100644 index 00000000..b7abb3fc --- /dev/null +++ b/test/node/write_array/app.js @@ -0,0 +1,4 @@ +require('http').createServer(function (req, res) { + res.writeHead(200, {'Content-Length': 5, 'Content-Type': 'text/plain'}) + .end(new Uint8Array(Buffer.from('array', 'utf8'))); +}).listen(7080); diff --git a/test/node/write_buffer/app.js b/test/node/write_buffer/app.js index 506e8613..72e9c600 100644 --- a/test/node/write_buffer/app.js +++ b/test/node/write_buffer/app.js @@ -1,5 +1,5 @@ require('http').createServer(function (req, res) { res.writeHead(200, {'Content-Type': 'text/plain'}) - .end(new Buffer([0x62, 0x75, 0x66, 0x66, 0x65, 0x72])); + .end(Buffer.from('buffer', 'utf8')); }).listen(7080); diff --git a/test/test_java_application.py b/test/test_java_application.py index a8814583..eefc5c79 100644 --- a/test/test_java_application.py +++ b/test/test_java_application.py @@ -875,6 +875,23 @@ def test_java_application_get_headers(): assert headers['X-Reply-0'] == 'blah', 'get headers' assert headers['X-Reply-1'] == 'blah', 'get headers 2' +def test_java_application_many_headers(): + client.load('get_headers') + + value = '0123456789' * 10 + + headers = client.get( + headers={ + 'X-Header': [value] * 100, + 'Content-Type': 'text/html', + 'Host': 'localhost', + 'Connection': 'close', + } + )['headers'] + + for i in range(0, 99): + assert headers[f'X-Reply-{i}'] == value, 'many headers' + def test_java_application_get_headers_empty(): client.load('get_headers') diff --git a/test/test_node_application.py b/test/test_node_application.py index e4226535..ab8aa8f8 100644 --- a/test/test_node_application.py +++ b/test/test_node_application.py @@ -149,6 +149,10 @@ def test_node_application_write_buffer(): assert client.get()['body'] == 'buffer', 'write buffer' +def test_node_application_write_array(): + client.load('write_array') + + assert client.get()['body'] == 'array', 'write array' def test_node_application_write_callback(temp_dir): client.load('write_callback') diff --git a/test/test_php_application.py b/test/test_php_application.py index 6c1f227b..17440909 100644 --- a/test/test_php_application.py +++ b/test/test_php_application.py @@ -171,6 +171,36 @@ def test_php_application_query_string_empty(): assert resp['headers']['Query-String'] == '', 'query string empty' +def test_php_application_query_string_rewrite(): + assert 'success' in client.conf( + { + "listeners": {"*:7080": {"pass": "routes"}}, + "routes": [ + { + "action": { + "rewrite": "/new", + "pass": "applications/query_string", + }, + }, + ], + "applications": { + "query_string": { + "type": client.get_application_type(), + "processes": {"spare": 0}, + "root": f"{option.test_dir}/php/query_string", + "script": "index.php", + } + }, + }, + ) + + assert client.get(url='/old')['status'] == 200 + + resp = client.get(url='/old?arg=val') + assert resp['status'] == 200 + assert resp['headers']['Query-String'] == 'arg=val' + + def test_php_application_fastcgi_finish_request(findall, unit_pid): client.load('fastcgi_finish_request') diff --git a/test/test_response_headers.py b/test/test_response_headers.py new file mode 100644 index 00000000..50f47d9a --- /dev/null +++ b/test/test_response_headers.py @@ -0,0 +1,173 @@ +from pathlib import Path + +import pytest +from unit.applications.proto import ApplicationProto +from unit.applications.lang.python import ApplicationPython +from unit.option import option + +client = ApplicationProto() +client_python = ApplicationPython() + + +@pytest.fixture(autouse=True) +def setup_method_fixture(temp_dir): + path = Path(f'{temp_dir}/index.html') + path.write_text('0123456789') + + assert 'success' in client.conf( + { + "listeners": { + "*:7080": {"pass": "routes"}, + }, + "routes": [ + { + "action": { + "share": str(path), + "response_headers": { + "X-Foo": "foo", + }, + } + } + ], + } + ) + + +def action_update(conf): + assert 'success' in client.conf(conf, 'routes/0/action') + + +def test_response_headers(temp_dir): + resp = client.get() + assert resp['status'] == 200, 'status 200' + assert resp['headers']['X-Foo'] == 'foo', 'header 200' + + assert 'success' in client.conf(f'"{temp_dir}"', 'routes/0/action/share') + + resp = client.get() + assert resp['status'] == 301, 'status 301' + assert resp['headers']['X-Foo'] == 'foo', 'header 301' + + assert 'success' in client.conf('"/blah"', 'routes/0/action/share') + + resp = client.get() + assert resp['status'] == 404, 'status 404' + assert 'X-Foo' not in client.get()['headers'], 'header 404' + + +def test_response_last_action(): + assert 'success' in client.conf( + { + "listeners": { + "*:7080": {"pass": "routes/first"}, + }, + "routes": { + "first": [ + { + "action": { + "pass": "routes/second", + "response_headers": { + "X-Foo": "foo", + }, + } + } + ], + "second": [ + { + "action": {"return": 200}, + } + ], + }, + "applications": {}, + } + ) + + assert 'X-Foo' not in client.get()['headers'] + + +def test_response_pass(require): + require({'modules': {'python': 'any'}}) + + assert 'success' in client_python.conf( + { + "listeners": { + "*:7080": {"pass": "routes"}, + }, + "routes": [ + { + "action": { + "pass": "applications/empty", + "response_headers": { + "X-Foo": "foo", + }, + } + }, + ], + "applications": { + "empty": { + "type": client_python.get_application_type(), + "processes": {"spare": 0}, + "path": f'{option.test_dir}/python/empty', + "working_directory": f'{option.test_dir}/python/empty', + "module": "wsgi", + } + }, + } + ) + + assert client.get()['headers']['X-Foo'] == 'foo' + + +def test_response_fallback(): + assert 'success' in client.conf( + { + "listeners": {"*:7080": {"pass": "routes"}}, + "routes": [ + { + "action": { + "share": "/blah", + "fallback": { + "return": 200, + "response_headers": { + "X-Foo": "foo", + }, + }, + } + } + ], + } + ) + + assert client.get()['headers']['X-Foo'] == 'foo' + + +def test_response_headers_var(): + assert 'success' in client.conf( + { + "X-Foo": "$uri", + }, + 'routes/0/action/response_headers', + ) + + assert client.get()['headers']['X-Foo'] == '/' + + +def test_response_headers_remove(): + assert 'success' in client.conf( + {"etag": None}, + 'routes/0/action/response_headers', + ) + + assert 'ETag' not in client.get()['headers'] + + +def test_response_headers_invalid(skip_alert): + skip_alert(r'failed to apply new conf') + + def check_invalid(conf): + assert 'error' in client.conf( + conf, + 'routes/0/action/response_headers', + ) + + check_invalid({"X-Foo": "$u"}) diff --git a/test/unit/applications/lang/java.py b/test/unit/applications/lang/java.py index a253aea5..dc6d2bfc 100644 --- a/test/unit/applications/lang/java.py +++ b/test/unit/applications/lang/java.py @@ -53,7 +53,7 @@ class ApplicationJava(ApplicationProto): os.makedirs(classes_path) classpath = ( - f'{option.current_dir}/build/tomcat-servlet-api-9.0.75.jar' + f'{option.current_dir}/build/tomcat-servlet-api-9.0.82.jar' ) ws_jars = glob.glob( diff --git a/tools/README.md b/tools/README.md index 1a631e10..883bc107 100644 --- a/tools/README.md +++ b/tools/README.md @@ -37,12 +37,16 @@ web page with NGINX Unit. | _HTTP method_ | It is usually not required to specify a HTTP method. `GET` is used to read the configuration. `PUT` is used when making configuration changes unless a specific method is provided. | `edit` | Opens **URI** in the default editor for interactive configuration. The [jq](https://stedolan.github.io/jq/) tool is required for this option. | `INSERT` | A _virtual_ HTTP method that prepends data when the URI specifies an existing array. The [jq](https://stedolan.github.io/jq/) tool is required for this option. +| `-f` \| `--format YAML` | Convert configuration data to/from YAML format. The [yq](https://github.com/mikefarah/yq) tool is required for this option. | `-q` \| `--quiet` | No output to stdout. Options are case insensitive and can appear in any order. For example, a redundant part of the configuration can be identified by its URI, and followed by `delete` in a subsequent command. +Options may be combined. For example, `edit -f yaml` will open the +configuration URI in a text editor, in YAML format. + ### Local Configuration For local instances of Unit, the control socket is automatically detected. The error log is monitored; when changes occur, new log entries are shown. @@ -51,10 +55,9 @@ The error log is monitored; when changes occur, new log entries are shown. |---------|-| | `-l` \| `--nolog` | Do not monitor the error log after configuration changes. -#### Examples +#### Local Examples ```shell unitc /config -unitc /control/applications/my_app/restart unitc /config < unitconf.json echo '{"*:8080": {"pass": "routes"}}' | unitc /config/listeners unitc /config/applications/my_app DELETE @@ -64,10 +67,12 @@ unitc /certificates/bundle cert.pem key.pem ### Remote Configuration For remote instances of NGINX Unit, the control socket on the remote host can be set with the `$UNIT_CTRL` environment variable. The remote control socket -can be accessed over TCP or SSH, depending on the type of control socket: +can be accessed over TCP, SSH, or Docker containers on the host, depending on +the type of control socket: * `ssh://[user@]remote_host[:ssh_port]/path/to/control.socket` * `http://remote_host:unit_control_port` + * `docker://container_ID[/path/to/control.socket]` > **Note:** SSH is recommended for remote confguration. Consider the > [security implications](https://unit.nginx.org/howto/security/#secure-socket-and-state) @@ -77,8 +82,9 @@ can be accessed over TCP or SSH, depending on the type of control socket: |---------|-| | `ssh://…` | Specify the remote Unix control socket on the command line. | `http://…`*URI* | For remote TCP control sockets, the URI may include the protocol, hostname, and port. +| `docker://…` | Specify the local container ID/name. The default Unix control socket can be overridden. -#### Examples +#### Remote Examples ```shell unitc http://192.168.0.1:8080/status UNIT_CTRL=http://192.168.0.1:8080 unitc /status @@ -89,4 +95,12 @@ cat catchall_route.json | unitc POST /config/routes echo '{"match":{"uri":"/wp-admin/*"},"action":{"return":403}}' | unitc INSERT /config/routes ``` +#### Docker Examples +```shell +unitc docker://d43251184c54 /config +echo '{"http": {"log_route": true}}' | unitc docker://d43251184c54 /settings +unitc docker://f4f3d9e918e6/root/unit.sock /control/applications/my_app/restart +UNIT_CTRL=docker://4d0431488982 unitc /status/requests/total +``` + --- diff --git a/tools/unitc b/tools/unitc index 877e11d4..4ab5f663 100755 --- a/tools/unitc +++ b/tools/unitc @@ -10,14 +10,39 @@ REMOTE=0 SHOW_LOG=1 NOLOG=0 QUIET=0 +CONVERT=0 URI="" -SSH_CMD="" +RPC_CMD="" METHOD=PUT CONF_FILES=() while [ $# -gt 0 ]; do OPTION=$(echo $1 | tr '[a-z]' '[A-Z]') case $OPTION in + "-F" | "--FORMAT") + case $(echo $2 | tr '[a-z]' '[A-Z]') in + "YAML") + CONVERT=1 + if hash yq 2> /dev/null; then + CONVERT_TO_JSON="yq eval -P --output-format=json" + CONVERT_FROM_JSON="yq eval -P --output-format=yaml" + else + echo "${0##*/}: ERROR: yq(1) is required to use YAML format; install at <https://github.com/mikefarah/yq#install>" + exit 1 + fi + ;; + "") + echo "${0##*/}: ERROR: Must specify configuration format" + exit 1 + ;; + *) + echo "${0##*/}: ERROR: Invalid format ($2)" + exit 1 + ;; + esac + shift; shift + ;; + "-H" | "--HELP") shift ;; @@ -45,15 +70,25 @@ while [ $# -gt 0 ]; do *) if [ -f $1 ] && [ -r $1 ]; then CONF_FILES+=($1) + if [ "${1##*.}" = "yaml" ]; then + echo "${0##*/}: INFO: converting $1 to JSON" + shift; set -- "--format" "yaml" "$@" # Apply the command line option + else + shift + fi elif [ "${1:0:1}" = "/" ] || [ "${1:0:4}" = "http" ] && [ "$URI" = "" ]; then URI=$1 + shift elif [ "${1:0:6}" = "ssh://" ]; then UNIT_CTRL=$1 + shift + elif [ "${1:0:9}" = "docker://" ]; then + UNIT_CTRL=$1 + shift else echo "${0##*/}: ERROR: Invalid option ($1)" exit 1 fi - shift ;; esac done @@ -67,23 +102,26 @@ USAGE: ${0##*/} [options] URI • URI is for Unit's control API target, e.g. /config • A local Unit control socket is detected unless a remote one is specified. • Configuration data is read from stdin. +• All options are case-insensitive (excluding filenames and URIs). General options - filename … # Read configuration data from files instead of stdin - HTTP method # Default=GET, or PUT with config data (case-insensitive) - EDIT # Opens the URI contents in \$EDITOR - INSERT # Virtual HTTP method to prepend data to an existing array - -q | --quiet # No output to stdout + filename … # Read configuration data from files instead of stdin + HTTP method # Default=GET, or PUT when config data is present + EDIT # Opens the URI contents in \$EDITOR + INSERT # Virtual HTTP method; prepend data to an array + -f | --format YAML # Convert configuration data to/from YAML format + -q | --quiet # No output to stdout Local options - -l | --nolog # Do not monitor the error log after applying config changes + -l | --nolog # Do not monitor the Unit log file after config changes Remote options ssh://[user@]remote_host[:port]/path/to/control.socket # Remote Unix socket http://remote_host:port/URI # Remote TCP socket + docker://container_ID[/non-default/control.socket] # Container on host - A remote Unit control socket may also be defined with the \$UNIT_CTRL - environment variable as http://remote_host:port -OR- ssh://… (as above) + A remote Unit instance may also be defined with the \$UNIT_CTRL environment + variable as http://remote_host:port or ssh://… or docker://… (as above). __EOF__ exit 1 @@ -99,8 +137,16 @@ if [ "$UNIT_CTRL" = "" ]; then fi elif [ "${UNIT_CTRL:0:6}" = "ssh://" ]; then REMOTE=1 - SSH_CMD="ssh $(echo $UNIT_CTRL | cut -f1-3 -d/)" + RPC_CMD="ssh $(echo $UNIT_CTRL | cut -f1-3 -d/)" UNIT_CTRL="--unix-socket /$(echo $UNIT_CTRL | cut -f4- -d/) _" +elif [ "${UNIT_CTRL:0:9}" = "docker://" ]; then + RPC_CMD="docker exec -i $(echo $UNIT_CTRL | cut -f3 -d/)" + DOCKSOCK=/$(echo "$UNIT_CTRL" | cut -f4- -d/) + if [ "$DOCKSOCK" = "/" ]; then + DOCKSOCK="/var/run/control.unit.sock" # Use default location if no path + fi + UNIT_CTRL="--unix-socket $DOCKSOCK _" + REMOTE=1 elif [ "${URI:0:1}" = "/" ]; then REMOTE=1 fi @@ -186,7 +232,9 @@ fi # Choose presentation style # if [ $QUIET -eq 1 ]; then - OUTPUT="head -c 0" # Equivalent to >/dev/null + OUTPUT="tail -c 0" # Equivalent to >/dev/null +elif [ $CONVERT -eq 1 ]; then + OUTPUT=$CONVERT_FROM_JSON elif hash jq 2> /dev/null; then OUTPUT="jq" else @@ -205,11 +253,11 @@ fi # if [ -t 0 ] && [ ${#CONF_FILES[@]} -eq 0 ]; then if [ "$METHOD" = "DELETE" ]; then - $SSH_CMD curl -X $METHOD $UNIT_CTRL$URI 2> /tmp/${0##*/}.$$ | $OUTPUT + $RPC_CMD curl -X $METHOD $UNIT_CTRL$URI 2> /tmp/${0##*/}.$$ | $OUTPUT elif [ "$METHOD" = "EDIT" ]; then EDITOR=$(test "$EDITOR" && printf '%s' "$EDITOR" || command -v editor || command -v vim || echo vi) EDIT_FILENAME=/tmp/${0##*/}.$$${URI//\//_} - $SSH_CMD curl -fsS $UNIT_CTRL$URI > $EDIT_FILENAME || exit 2 + $RPC_CMD curl -fsS $UNIT_CTRL$URI > $EDIT_FILENAME || exit 2 if [ "${URI:0:12}" = "/js_modules/" ]; then if ! hash jq 2> /dev/null; then echo "${0##*/}: ERROR: jq(1) is required to edit JavaScript modules; install at <https://stedolan.github.io/jq/>" @@ -219,19 +267,23 @@ if [ -t 0 ] && [ ${#CONF_FILES[@]} -eq 0 ]; then EDIT_FILE=$EDIT_FILENAME.js $EDITOR $EDIT_FILENAME.js || exit 2 # Remove the references, delete old config, push new config+reference - $SSH_CMD curl -fsS $UNIT_CTRL/config/settings/js_module > /tmp/${0##*/}.$$_js_module && \ - $SSH_CMD curl -X DELETE $UNIT_CTRL/config/settings/js_module && \ - $SSH_CMD curl -fsSX DELETE $UNIT_CTRL$URI 2> /tmp/${0##*/}.$$ && \ - printf "%s" "$(< $EDIT_FILENAME.js)" | $SSH_CMD curl -fX PUT --data-binary @- $UNIT_CTRL$URI 2> /tmp/${0##*/}.$$ && \ - $SSH_CMD curl -X PUT --data-binary @/tmp/${0##*/}.$$_js_module $UNIT_CTRL/config/settings/js_module 2> /tmp/${0##*/}.$$ + $RPC_CMD curl -fsS $UNIT_CTRL/config/settings/js_module > /tmp/${0##*/}.$$_js_module && \ + $RPC_CMD curl -X DELETE $UNIT_CTRL/config/settings/js_module && \ + $RPC_CMD curl -fsSX DELETE $UNIT_CTRL$URI 2> /tmp/${0##*/}.$$ && \ + printf "%s" "$(< $EDIT_FILENAME.js)" | $RPC_CMD curl -fX PUT --data-binary @- $UNIT_CTRL$URI 2> /tmp/${0##*/}.$$ && \ + cat /tmp/${0##*/}.$$_js_module | $RPC_CMD curl -X PUT --data-binary @- $UNIT_CTRL/config/settings/js_module 2> /tmp/${0##*/}.$$ + elif [ $CONVERT -eq 1 ]; then + $CONVERT_FROM_JSON < $EDIT_FILENAME > $EDIT_FILENAME.yaml + $EDITOR $EDIT_FILENAME.yaml || exit 2 + $CONVERT_TO_JSON < $EDIT_FILENAME.yaml | $RPC_CMD curl -X PUT --data-binary @- $UNIT_CTRL$URI 2> /tmp/${0##*/}.$$ | $OUTPUT else tr -d '\r' < $EDIT_FILENAME > $EDIT_FILENAME.json # Remove carriage-return from newlines $EDITOR $EDIT_FILENAME.json || exit 2 - $SSH_CMD curl -X PUT --data-binary @$EDIT_FILENAME.json $UNIT_CTRL$URI 2> /tmp/${0##*/}.$$ | $OUTPUT + cat $EDIT_FILENAME.json | $RPC_CMD curl -X PUT --data-binary @- $UNIT_CTRL$URI 2> /tmp/${0##*/}.$$ | $OUTPUT fi else SHOW_LOG=$(echo $URI | grep -c ^/control/) - $SSH_CMD curl $UNIT_CTRL$URI 2> /tmp/${0##*/}.$$ | $OUTPUT + $RPC_CMD curl $UNIT_CTRL$URI 2> /tmp/${0##*/}.$$ | $OUTPUT fi else if [ "$METHOD" = "INSERT" ]; then @@ -241,15 +293,19 @@ else fi NEW_ELEMENT=$(cat ${CONF_FILES[@]}) echo $NEW_ELEMENT | jq > /dev/null || exit $? # Test the input is valid JSON before proceeding - OLD_ARRAY=$($SSH_CMD curl -s $UNIT_CTRL$URI) + OLD_ARRAY=$($RPC_CMD curl -s $UNIT_CTRL$URI) if [ "$(echo $OLD_ARRAY | jq -r type)" = "array" ]; then - echo $OLD_ARRAY | jq ". |= [$NEW_ELEMENT] + ." | $SSH_CMD curl -X PUT --data-binary @- $UNIT_CTRL$URI 2> /tmp/${0##*/}.$$ | $OUTPUT + echo $OLD_ARRAY | jq ". |= [$NEW_ELEMENT] + ." | $RPC_CMD curl -X PUT --data-binary @- $UNIT_CTRL$URI 2> /tmp/${0##*/}.$$ | $OUTPUT else echo "${0##*/}: ERROR: the INSERT method expects an array" exit 3 fi else - cat ${CONF_FILES[@]} | $SSH_CMD curl -X $METHOD --data-binary @- $UNIT_CTRL$URI 2> /tmp/${0##*/}.$$ | $OUTPUT + if [ $CONVERT -eq 1 ]; then + cat ${CONF_FILES[@]} | $CONVERT_TO_JSON > /tmp/${0##*/}.$$_json + CONF_FILES=(/tmp/${0##*/}.$$_json) + fi + cat ${CONF_FILES[@]} | $RPC_CMD curl -X $METHOD --data-binary @- $UNIT_CTRL$URI 2> /tmp/${0##*/}.$$ | $OUTPUT fi fi @@ -1,5 +1,5 @@ # Copyright (C) NGINX, Inc. -NXT_VERSION=1.31.0 -NXT_VERNUM=13100 +NXT_VERSION=1.31.1 +NXT_VERNUM=13101 |