summaryrefslogtreecommitdiffhomepage
path: root/src
diff options
context:
space:
mode:
authorDan Callahan <d.callahan@f5.com>2024-02-27 15:15:42 +0000
committerDan Callahan <d.callahan@f5.com>2024-02-27 15:15:42 +0000
commitd76761901c4084bcdbc5a449e9bbb47d56b7093c (patch)
treeb4b7b4e3d588b73a2adcc0094cab466d9194c679 /src
parentc43629880472bba8d389dfb0b7ae6d883b0ba499 (diff)
parent088117008c9e8f397a58cc8d8070ce047beff12f (diff)
downloadunit-d76761901c4084bcdbc5a449e9bbb47d56b7093c.tar.gz
unit-d76761901c4084bcdbc5a449e9bbb47d56b7093c.tar.bz2
Merge tag '1.32.0' into branches/packaging1.32.0-1
Unit 1.32.0 release.
Diffstat (limited to 'src')
-rw-r--r--src/java/nginx/unit/websocket/DigestAuthenticator.java4
-rw-r--r--src/java/nginx/unit/websocket/Util.java2
-rw-r--r--src/java/nginx/unit/websocket/server/WsSessionListener.java2
-rw-r--r--src/nodejs/unit-http/http.js4
-rw-r--r--src/nodejs/unit-http/http_server.js13
-rw-r--r--src/nodejs/unit-http/loader.js2
-rw-r--r--src/nodejs/unit-http/loader.mjs2
-rw-r--r--src/nodejs/unit-http/unit.cpp8
-rw-r--r--src/nodejs/unit-http/websocket_connection.js8
-rw-r--r--src/nodejs/unit-http/websocket_request.js8
-rw-r--r--src/nxt_application.c3
-rw-r--r--src/nxt_application.h9
-rw-r--r--src/nxt_atomic.h4
-rw-r--r--src/nxt_clone.c14
-rw-r--r--src/nxt_clone.h8
-rw-r--r--src/nxt_conf.c11
-rw-r--r--src/nxt_conf.h3
-rw-r--r--src/nxt_conf_validation.c150
-rw-r--r--src/nxt_conn_write.c7
-rw-r--r--src/nxt_credential.c7
-rw-r--r--src/nxt_file.c82
-rw-r--r--src/nxt_file.h2
-rw-r--r--src/nxt_http_js.c49
-rw-r--r--src/nxt_http_request.c69
-rw-r--r--src/nxt_http_static.c11
-rw-r--r--src/nxt_http_variables.c50
-rw-r--r--src/nxt_isolation.c6
-rw-r--r--src/nxt_js.c64
-rw-r--r--src/nxt_listen_socket.c14
-rw-r--r--src/nxt_main_process.c15
-rw-r--r--src/nxt_openssl.c2
-rw-r--r--src/nxt_php_sapi.c2
-rw-r--r--src/nxt_router.c26
-rw-r--r--src/nxt_router.h2
-rw-r--r--src/nxt_router_access_log.c25
-rw-r--r--src/nxt_runtime.c55
-rw-r--r--src/nxt_runtime.h6
-rw-r--r--src/nxt_socket.c8
-rw-r--r--src/nxt_unit.h38
-rw-r--r--src/nxt_var.c74
-rw-r--r--src/nxt_var.h6
-rw-r--r--src/python/nxt_python_asgi_http.c31
-rw-r--r--src/python/nxt_python_wsgi.c33
-rw-r--r--src/ruby/nxt_ruby.c77
-rw-r--r--src/test/nxt_rbtree1.c2
-rw-r--r--src/test/nxt_rbtree1.h2
-rw-r--r--src/wasm-wasi-component/.gitignore1
-rw-r--r--src/wasm-wasi-component/Cargo.lock2293
-rw-r--r--src/wasm-wasi-component/Cargo.toml30
-rw-r--r--src/wasm-wasi-component/build.rs33
-rw-r--r--src/wasm-wasi-component/src/lib.rs611
-rw-r--r--src/wasm-wasi-component/wrapper.h5
52 files changed, 3726 insertions, 267 deletions
diff --git a/src/java/nginx/unit/websocket/DigestAuthenticator.java b/src/java/nginx/unit/websocket/DigestAuthenticator.java
index 9530c303..eb91a9b4 100644
--- a/src/java/nginx/unit/websocket/DigestAuthenticator.java
+++ b/src/java/nginx/unit/websocket/DigestAuthenticator.java
@@ -22,7 +22,7 @@ import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.util.Map;
-import org.apache.tomcat.util.security.MD5Encoder;
+import org.apache.tomcat.util.buf.HexUtils;
/**
* Authenticator supporting the DIGEST auth method.
@@ -140,7 +140,7 @@ public class DigestAuthenticator extends Authenticator {
MessageDigest md = MessageDigest.getInstance("MD5");
byte[] thedigest = md.digest(bytesOfMessage);
- return MD5Encoder.encode(thedigest);
+ return HexUtils.toHexString(thedigest);
}
@Override
diff --git a/src/java/nginx/unit/websocket/Util.java b/src/java/nginx/unit/websocket/Util.java
index 6acf3ade..5388431f 100644
--- a/src/java/nginx/unit/websocket/Util.java
+++ b/src/java/nginx/unit/websocket/Util.java
@@ -332,7 +332,7 @@ public class Util {
public static List<DecoderEntry> getDecoders(
List<Class<? extends Decoder>> decoderClazzes)
- throws DeploymentException{
+ throws DeploymentException {
List<DecoderEntry> result = new ArrayList<>();
if (decoderClazzes != null) {
diff --git a/src/java/nginx/unit/websocket/server/WsSessionListener.java b/src/java/nginx/unit/websocket/server/WsSessionListener.java
index fc2bc9c5..2921bd45 100644
--- a/src/java/nginx/unit/websocket/server/WsSessionListener.java
+++ b/src/java/nginx/unit/websocket/server/WsSessionListener.java
@@ -19,7 +19,7 @@ package nginx.unit.websocket.server;
import javax.servlet.http.HttpSessionEvent;
import javax.servlet.http.HttpSessionListener;
-public class WsSessionListener implements HttpSessionListener{
+public class WsSessionListener implements HttpSessionListener {
private final WsServerContainer wsServerContainer;
diff --git a/src/nodejs/unit-http/http.js b/src/nodejs/unit-http/http.js
index d298a35f..60b8004f 100644
--- a/src/nodejs/unit-http/http.js
+++ b/src/nodejs/unit-http/http.js
@@ -11,8 +11,8 @@ const {
ServerResponse,
} = require('./http_server');
-function createServer (requestHandler) {
- return new Server(requestHandler);
+function createServer (options, requestHandler) {
+ return new Server(options, requestHandler);
}
const http = require("http")
diff --git a/src/nodejs/unit-http/http_server.js b/src/nodejs/unit-http/http_server.js
index 0f00b47f..4e1c190e 100644
--- a/src/nodejs/unit-http/http_server.js
+++ b/src/nodejs/unit-http/http_server.js
@@ -138,6 +138,10 @@ ServerResponse.prototype.removeHeader = function removeHeader(name) {
}
};
+ServerResponse.prototype.flushHeaders = function flushHeaders() {
+ this._sendHeaders();
+};
+
ServerResponse.prototype._removeHeader = function _removeHeader(lc_name) {
let entry = this.headers[lc_name];
let name_len = Buffer.byteLength(entry[0] + "", 'latin1');
@@ -409,7 +413,14 @@ ServerRequest.prototype._read = function _read(n) {
};
-function Server(requestListener) {
+function Server(options, requestListener) {
+ if (typeof options === 'function') {
+ requestListener = options;
+ options = {};
+ } else {
+ console.warn("http.Server constructor was called with unsupported options, using default settings");
+ }
+
EventEmitter.call(this);
this.unit = new unit_lib.Unit();
diff --git a/src/nodejs/unit-http/loader.js b/src/nodejs/unit-http/loader.js
index e5aa3558..849df3d1 100644
--- a/src/nodejs/unit-http/loader.js
+++ b/src/nodejs/unit-http/loader.js
@@ -11,10 +11,12 @@ if (module.parent && module.parent.id === "internal/preload") {
Module.prototype.require = function (id) {
switch(id) {
case "http":
+ case "node:http":
case "unit-http":
return http
case "websocket":
+ case "node:websocket":
case "unit-http/websocket":
return websocket
}
diff --git a/src/nodejs/unit-http/loader.mjs b/src/nodejs/unit-http/loader.mjs
index 83985b0f..01fa2920 100644
--- a/src/nodejs/unit-http/loader.mjs
+++ b/src/nodejs/unit-http/loader.mjs
@@ -2,6 +2,7 @@
export async function resolve(specifier, context, defaultResolver) {
switch (specifier) {
case "websocket":
+ case "node:websocket":
return {
url: new URL("./websocket.js", import.meta.url).href,
format: "commonjs",
@@ -9,6 +10,7 @@ export async function resolve(specifier, context, defaultResolver) {
}
case "http":
+ case "node:http":
return {
url: new URL("./http.js", import.meta.url).href,
format: "commonjs",
diff --git a/src/nodejs/unit-http/unit.cpp b/src/nodejs/unit-http/unit.cpp
index 7912d0ac..7d9395bb 100644
--- a/src/nodejs/unit-http/unit.cpp
+++ b/src/nodejs/unit-http/unit.cpp
@@ -581,6 +581,7 @@ Unit::get_server_object()
void
Unit::create_headers(nxt_unit_request_info_t *req, napi_value request)
{
+ char *p;
uint32_t i;
napi_value headers, raw_headers;
napi_status status;
@@ -602,7 +603,12 @@ Unit::create_headers(nxt_unit_request_info_t *req, napi_value request)
set_named_property(request, "headers", headers);
set_named_property(request, "rawHeaders", raw_headers);
- set_named_property(request, "httpVersion", r->version, r->version_length);
+
+ // trim the "HTTP/" protocol prefix
+ p = (char *) nxt_unit_sptr_get(&r->version);
+ p += 5;
+
+ set_named_property(request, "httpVersion", create_string_latin1(p, 3));
set_named_property(request, "method", r->method, r->method_length);
set_named_property(request, "url", r->target, r->target_length);
diff --git a/src/nodejs/unit-http/websocket_connection.js b/src/nodejs/unit-http/websocket_connection.js
index 4eccf6bf..c04075d7 100644
--- a/src/nodejs/unit-http/websocket_connection.js
+++ b/src/nodejs/unit-http/websocket_connection.js
@@ -36,11 +36,11 @@ var idCounter = 0;
function WebSocketConnection(socket, extensions, protocol, maskOutgoingPackets, config) {
this._debug = utils.BufferingLogger('websocket:connection', ++idCounter);
this._debug('constructor');
-
+
if (this._debug.enabled) {
instrumentSocketForDebugging(this, socket);
}
-
+
// Superclass Constructor
EventEmitter.call(this);
@@ -432,8 +432,8 @@ WebSocketConnection.prototype.processFrame = function(frame) {
// logic to emit the ping frame: this is only done when a listener is known to exist
// Expose a function allowing the user to override the default ping() behavior
var cancelled = false;
- var cancel = function() {
- cancelled = true;
+ var cancel = function() {
+ cancelled = true;
};
this.emit('ping', cancel, frame.binaryPayload);
diff --git a/src/nodejs/unit-http/websocket_request.js b/src/nodejs/unit-http/websocket_request.js
index d84e428b..450ab629 100644
--- a/src/nodejs/unit-http/websocket_request.js
+++ b/src/nodejs/unit-http/websocket_request.js
@@ -247,7 +247,7 @@ WebSocketRequest.prototype.parseCookies = function(str) {
WebSocketRequest.prototype.accept = function(acceptedProtocol, allowedOrigin, cookies) {
this._verifyResolution();
-
+
// TODO: Handle extensions
var protocolFullCase;
@@ -418,7 +418,7 @@ WebSocketRequest.prototype.accept = function(acceptedProtocol, allowedOrigin, co
// if (negotiatedExtensions) {
// response += 'Sec-WebSocket-Extensions: ' + negotiatedExtensions.join(', ') + '\r\n';
// }
-
+
// Mark the request resolved now so that the user can't call accept or
// reject a second time.
this._resolved = true;
@@ -447,12 +447,12 @@ WebSocketRequest.prototype.accept = function(acceptedProtocol, allowedOrigin, co
WebSocketRequest.prototype.reject = function(status, reason, extraHeaders) {
this._verifyResolution();
-
+
// Mark the request resolved now so that the user can't call accept or
// reject a second time.
this._resolved = true;
this.emit('requestResolved', this);
-
+
if (typeof(status) !== 'number') {
status = 403;
}
diff --git a/src/nxt_application.c b/src/nxt_application.c
index 872e387a..e0247bf0 100644
--- a/src/nxt_application.c
+++ b/src/nxt_application.c
@@ -1100,6 +1100,9 @@ nxt_app_parse_type(u_char *p, size_t length)
} else if (nxt_str_eq(&str, "java", 4)) {
return NXT_APP_JAVA;
+ } else if (nxt_str_eq(&str, "wasm-wasi-component", 19)) {
+ return NXT_APP_WASM_WC;
+
} else if (nxt_str_eq(&str, "wasm", 4)) {
return NXT_APP_WASM;
}
diff --git a/src/nxt_application.h b/src/nxt_application.h
index 64866db6..f5d7a9df 100644
--- a/src/nxt_application.h
+++ b/src/nxt_application.h
@@ -22,6 +22,7 @@ typedef enum {
NXT_APP_RUBY,
NXT_APP_JAVA,
NXT_APP_WASM,
+ NXT_APP_WASM_WC,
NXT_APP_UNKNOWN,
} nxt_app_type_t;
@@ -104,6 +105,13 @@ typedef struct {
} nxt_wasm_app_conf_t;
+typedef struct {
+ const char *component;
+
+ nxt_conf_value_t *access;
+} nxt_wasm_wc_app_conf_t;
+
+
struct nxt_common_app_conf_s {
nxt_str_t name;
nxt_str_t type;
@@ -133,6 +141,7 @@ struct nxt_common_app_conf_s {
nxt_ruby_app_conf_t ruby;
nxt_java_app_conf_t java;
nxt_wasm_app_conf_t wasm;
+ nxt_wasm_wc_app_conf_t wasm_wc;
} u;
nxt_conf_value_t *self;
diff --git a/src/nxt_atomic.h b/src/nxt_atomic.h
index cd2e7253..dae999a9 100644
--- a/src/nxt_atomic.h
+++ b/src/nxt_atomic.h
@@ -58,6 +58,10 @@ typedef volatile nxt_atomic_uint_t nxt_atomic_t;
#define nxt_cpu_pause() \
__asm__ ("pause")
+#elif (__aarch64__ || __arm64__)
+#define nxt_cpu_pause() \
+ __asm__ ("isb")
+
#else
#define nxt_cpu_pause()
#endif
diff --git a/src/nxt_clone.c b/src/nxt_clone.c
index 1cd70f6c..e78a7822 100644
--- a/src/nxt_clone.c
+++ b/src/nxt_clone.c
@@ -143,7 +143,7 @@ nxt_clone_credential_map_set(nxt_task_t *task, const char* mapfile, pid_t pid,
end = mapinfo + len;
for (i = 0; i < map->size; i++) {
- p = nxt_sprintf(p, end, "%d %d %d", map->map[i].container,
+ p = nxt_sprintf(p, end, "%L %L %L", map->map[i].container,
map->map[i].host, map->map[i].size);
if (nxt_slow_path(p == end)) {
@@ -152,7 +152,7 @@ nxt_clone_credential_map_set(nxt_task_t *task, const char* mapfile, pid_t pid,
return NXT_ERROR;
}
- if (i+1 < map->size) {
+ if (i + 1 < map->size) {
*p++ = '\n';
} else {
@@ -332,7 +332,7 @@ nxt_clone_vldt_credential_gidmap(nxt_task_t *task,
if (nxt_slow_path((nxt_gid_t) m.host != nxt_egid)) {
nxt_log(task, NXT_LOG_ERR, "\"gidmap\" field has an entry for "
- "host gid %d but unprivileged unit can only map itself "
+ "host gid %L but unprivileged unit can only map itself "
"(gid %d) into child namespaces.", m.host, nxt_egid);
return NXT_ERROR;
@@ -340,7 +340,7 @@ nxt_clone_vldt_credential_gidmap(nxt_task_t *task,
if (nxt_slow_path(m.size > 1)) {
nxt_log(task, NXT_LOG_ERR, "\"gidmap\" field has an entry with "
- "\"size\": %d, but for unprivileged unit it must be 1.",
+ "\"size\": %L, but for unprivileged unit it must be 1.",
m.size);
return NXT_ERROR;
@@ -382,13 +382,13 @@ nxt_clone_vldt_credential_gidmap(nxt_task_t *task,
m = map->map[j];
if (!base_ok && creds->base_gid >= (nxt_gid_t) m.container
- && creds->base_gid < (nxt_gid_t) (m.container+m.size))
+ && creds->base_gid < (nxt_gid_t) (m.container + m.size))
{
base_ok = 1;
}
if (creds->gids[i] >= (nxt_gid_t) m.container
- && creds->gids[i] < (nxt_gid_t) (m.container+m.size))
+ && creds->gids[i] < (nxt_gid_t) (m.container + m.size))
{
gid_ok = 1;
break;
@@ -405,7 +405,7 @@ nxt_clone_vldt_credential_gidmap(nxt_task_t *task,
m = map->map[i];
if (creds->base_gid >= (nxt_gid_t) m.container
- && creds->base_gid < (nxt_gid_t) (m.container+m.size))
+ && creds->base_gid < (nxt_gid_t) (m.container + m.size))
{
base_ok = 1;
break;
diff --git a/src/nxt_clone.h b/src/nxt_clone.h
index 6cea1bd7..bf28322f 100644
--- a/src/nxt_clone.h
+++ b/src/nxt_clone.h
@@ -9,10 +9,12 @@
#if (NXT_HAVE_CLONE_NEWUSER)
+typedef int64_t nxt_cred_t;
+
typedef struct {
- nxt_int_t container;
- nxt_int_t host;
- nxt_int_t size;
+ nxt_cred_t container;
+ nxt_cred_t host;
+ nxt_cred_t size;
} nxt_clone_map_entry_t;
typedef struct {
diff --git a/src/nxt_conf.c b/src/nxt_conf.c
index 664b5468..008cb968 100644
--- a/src/nxt_conf.c
+++ b/src/nxt_conf.c
@@ -3,6 +3,7 @@
* Copyright (C) Igor Sysoev
* Copyright (C) Valentin V. Bartenev
* Copyright (C) NGINX, Inc.
+ * Copyright 2024, Alejandro Colomar <alx@kernel.org>
*/
#include <nxt_main.h>
@@ -174,6 +175,16 @@ nxt_conf_get_string(nxt_conf_value_t *value, nxt_str_t *str)
}
+nxt_str_t *
+nxt_conf_get_string_dup(nxt_conf_value_t *value, nxt_mp_t *mp, nxt_str_t *str)
+{
+ nxt_str_t s;
+
+ nxt_conf_get_string(value, &s);
+ return nxt_str_dup(mp, str, &s);
+}
+
+
void
nxt_conf_set_string(nxt_conf_value_t *value, nxt_str_t *str)
{
diff --git a/src/nxt_conf.h b/src/nxt_conf.h
index 1b13f5ae..626b6d4d 100644
--- a/src/nxt_conf.h
+++ b/src/nxt_conf.h
@@ -3,6 +3,7 @@
* Copyright (C) Igor Sysoev
* Copyright (C) Valentin V. Bartenev
* Copyright (C) NGINX, Inc.
+ * Copyright 2024, Alejandro Colomar <alx@kernel.org>
*/
#ifndef _NXT_CONF_INCLUDED_
@@ -116,6 +117,8 @@ void nxt_conf_json_position(u_char *start, const u_char *pos, nxt_uint_t *line,
nxt_int_t nxt_conf_validate(nxt_conf_validation_t *vldt);
NXT_EXPORT void nxt_conf_get_string(nxt_conf_value_t *value, nxt_str_t *str);
+NXT_EXPORT nxt_str_t *nxt_conf_get_string_dup(nxt_conf_value_t *value,
+ nxt_mp_t *mp, nxt_str_t *str);
NXT_EXPORT void nxt_conf_set_string(nxt_conf_value_t *value, nxt_str_t *str);
NXT_EXPORT nxt_int_t nxt_conf_set_string_dup(nxt_conf_value_t *value,
nxt_mp_t *mp, const nxt_str_t *str);
diff --git a/src/nxt_conf_validation.c b/src/nxt_conf_validation.c
index f00b28b8..2099f887 100644
--- a/src/nxt_conf_validation.c
+++ b/src/nxt_conf_validation.c
@@ -2,6 +2,7 @@
/*
* Copyright (C) Valentin V. Bartenev
* Copyright (C) NGINX, Inc.
+ * Copyright 2024, Alejandro Colomar <alx@kernel.org>
*/
#include <nxt_main.h>
@@ -77,6 +78,8 @@ static nxt_int_t nxt_conf_vldt_error(nxt_conf_validation_t *vldt,
const char *fmt, ...);
static nxt_int_t nxt_conf_vldt_var(nxt_conf_validation_t *vldt, nxt_str_t *name,
nxt_str_t *value);
+static nxt_int_t nxt_conf_vldt_if(nxt_conf_validation_t *vldt,
+ nxt_conf_value_t *value, void *data);
nxt_inline nxt_int_t nxt_conf_vldt_unsupported(nxt_conf_validation_t *vldt,
nxt_conf_value_t *value, void *data)
NXT_MAYBE_UNUSED;
@@ -216,8 +219,6 @@ static nxt_int_t nxt_conf_vldt_clone_namespaces(nxt_conf_validation_t *vldt,
nxt_conf_value_t *value, void *data);
#if (NXT_HAVE_CLONE_NEWUSER)
-static nxt_int_t nxt_conf_vldt_clone_procmap(nxt_conf_validation_t *vldt,
- const char* mapfile, nxt_conf_value_t *value);
static nxt_int_t nxt_conf_vldt_clone_uidmap(nxt_conf_validation_t *vldt,
nxt_conf_value_t *value);
static nxt_int_t nxt_conf_vldt_clone_gidmap(nxt_conf_validation_t *vldt,
@@ -690,6 +691,7 @@ static nxt_conf_vldt_object_t nxt_conf_vldt_action_common_members[] = {
{
.name = nxt_string("rewrite"),
.type = NXT_CONF_VLDT_STRING,
+ .flags = NXT_CONF_VLDT_TSTR,
},
{
.name = nxt_string("response_headers"),
@@ -1093,6 +1095,22 @@ static nxt_conf_vldt_object_t nxt_conf_vldt_wasm_members[] = {
};
+static nxt_conf_vldt_object_t nxt_conf_vldt_wasm_wc_members[] = {
+ {
+ .name = nxt_string("component"),
+ .type = NXT_CONF_VLDT_STRING,
+ .flags = NXT_CONF_VLDT_REQUIRED,
+ }, {
+ .name = nxt_string("access"),
+ .type = NXT_CONF_VLDT_OBJECT,
+ .validator = nxt_conf_vldt_object,
+ .u.members = nxt_conf_vldt_wasm_access_members,
+ },
+
+ NXT_CONF_VLDT_NEXT(nxt_conf_vldt_common_members)
+};
+
+
static nxt_conf_vldt_object_t nxt_conf_vldt_wasm_access_members[] = {
{
.name = nxt_string("filesystem"),
@@ -1324,12 +1342,15 @@ static nxt_conf_vldt_object_t nxt_conf_vldt_app_procmap_members[] = {
{
.name = nxt_string("container"),
.type = NXT_CONF_VLDT_INTEGER,
+ .flags = NXT_CONF_VLDT_REQUIRED,
}, {
.name = nxt_string("host"),
.type = NXT_CONF_VLDT_INTEGER,
+ .flags = NXT_CONF_VLDT_REQUIRED,
}, {
.name = nxt_string("size"),
.type = NXT_CONF_VLDT_INTEGER,
+ .flags = NXT_CONF_VLDT_REQUIRED,
},
NXT_CONF_VLDT_END
@@ -1368,6 +1389,10 @@ static nxt_conf_vldt_object_t nxt_conf_vldt_access_log_members[] = {
}, {
.name = nxt_string("format"),
.type = NXT_CONF_VLDT_STRING,
+ }, {
+ .name = nxt_string("if"),
+ .type = NXT_CONF_VLDT_STRING,
+ .validator = nxt_conf_vldt_if,
},
NXT_CONF_VLDT_END
@@ -1537,6 +1562,37 @@ nxt_conf_vldt_var(nxt_conf_validation_t *vldt, nxt_str_t *name,
}
+static nxt_int_t
+nxt_conf_vldt_if(nxt_conf_validation_t *vldt, nxt_conf_value_t *value,
+ void *data)
+{
+ nxt_str_t str;
+
+ static nxt_str_t if_str = nxt_string("if");
+
+ if (nxt_conf_type(value) != NXT_CONF_STRING) {
+ return nxt_conf_vldt_error(vldt, "The \"if\" must be a string");
+ }
+
+ nxt_conf_get_string(value, &str);
+
+ if (str.length == 0) {
+ return NXT_OK;
+ }
+
+ if (str.start[0] == '!') {
+ str.start++;
+ str.length--;
+ }
+
+ if (nxt_is_tstr(&str)) {
+ return nxt_conf_vldt_var(vldt, &if_str, &str);
+ }
+
+ return NXT_OK;
+}
+
+
typedef struct {
nxt_mp_t *pool;
nxt_str_t *type;
@@ -1897,10 +1953,13 @@ static nxt_int_t
nxt_conf_vldt_proxy(nxt_conf_validation_t *vldt, nxt_conf_value_t *value,
void *data)
{
- nxt_str_t name;
+ nxt_str_t name, *ret;
nxt_sockaddr_t *sa;
- nxt_conf_get_string(value, &name);
+ ret = nxt_conf_get_string_dup(value, vldt->pool, &name);
+ if (nxt_slow_path(ret == NULL)) {
+ return NXT_ERROR;
+ }
if (nxt_str_start(&name, "http://", 7)) {
name.length -= 7;
@@ -2617,6 +2676,7 @@ nxt_conf_vldt_app(nxt_conf_validation_t *vldt, nxt_str_t *name,
{ nxt_conf_vldt_object, nxt_conf_vldt_ruby_members },
{ nxt_conf_vldt_object, nxt_conf_vldt_java_members },
{ nxt_conf_vldt_object, nxt_conf_vldt_wasm_members },
+ { nxt_conf_vldt_object, nxt_conf_vldt_wasm_wc_members },
};
ret = nxt_conf_vldt_type(vldt, name, value, NXT_CONF_VLDT_OBJECT);
@@ -2787,7 +2847,7 @@ nxt_conf_vldt_processes(nxt_conf_validation_t *vldt, nxt_conf_value_t *value,
nxt_int_t ret;
nxt_conf_vldt_processes_conf_t proc;
- if (nxt_conf_type(value) == NXT_CONF_NUMBER) {
+ if (nxt_conf_type(value) == NXT_CONF_INTEGER) {
int_value = nxt_conf_get_number(value);
if (int_value < 1) {
@@ -2874,13 +2934,11 @@ nxt_conf_vldt_object_iterator(nxt_conf_validation_t *vldt,
for ( ;; ) {
member = nxt_conf_next_object_member(value, &name, &index);
-
if (member == NULL) {
return NXT_OK;
}
ret = validator(vldt, &name, member);
-
if (ret != NXT_OK) {
return ret;
}
@@ -3050,73 +3108,6 @@ nxt_conf_vldt_isolation(nxt_conf_validation_t *vldt, nxt_conf_value_t *value,
#if (NXT_HAVE_CLONE_NEWUSER)
-typedef struct {
- nxt_int_t container;
- nxt_int_t host;
- nxt_int_t size;
-} nxt_conf_vldt_clone_procmap_conf_t;
-
-
-static nxt_conf_map_t nxt_conf_vldt_clone_procmap_conf_map[] = {
- {
- nxt_string("container"),
- NXT_CONF_MAP_INT32,
- offsetof(nxt_conf_vldt_clone_procmap_conf_t, container),
- },
-
- {
- nxt_string("host"),
- NXT_CONF_MAP_INT32,
- offsetof(nxt_conf_vldt_clone_procmap_conf_t, host),
- },
-
- {
- nxt_string("size"),
- NXT_CONF_MAP_INT32,
- offsetof(nxt_conf_vldt_clone_procmap_conf_t, size),
- },
-
-};
-
-
-static nxt_int_t
-nxt_conf_vldt_clone_procmap(nxt_conf_validation_t *vldt, const char *mapfile,
- nxt_conf_value_t *value)
-{
- nxt_int_t ret;
- nxt_conf_vldt_clone_procmap_conf_t procmap;
-
- procmap.container = -1;
- procmap.host = -1;
- procmap.size = -1;
-
- ret = nxt_conf_map_object(vldt->pool, value,
- nxt_conf_vldt_clone_procmap_conf_map,
- nxt_nitems(nxt_conf_vldt_clone_procmap_conf_map),
- &procmap);
- if (ret != NXT_OK) {
- return ret;
- }
-
- if (procmap.container == -1) {
- return nxt_conf_vldt_error(vldt, "The %s requires the "
- "\"container\" field set.", mapfile);
- }
-
- if (procmap.host == -1) {
- return nxt_conf_vldt_error(vldt, "The %s requires the "
- "\"host\" field set.", mapfile);
- }
-
- if (procmap.size == -1) {
- return nxt_conf_vldt_error(vldt, "The %s requires the "
- "\"size\" field set.", mapfile);
- }
-
- return NXT_OK;
-}
-
-
static nxt_int_t
nxt_conf_vldt_clone_uidmap(nxt_conf_validation_t *vldt, nxt_conf_value_t *value)
{
@@ -3133,7 +3124,7 @@ nxt_conf_vldt_clone_uidmap(nxt_conf_validation_t *vldt, nxt_conf_value_t *value)
return ret;
}
- return nxt_conf_vldt_clone_procmap(vldt, "uid_map", value);
+ return NXT_OK;
}
@@ -3153,7 +3144,7 @@ nxt_conf_vldt_clone_gidmap(nxt_conf_validation_t *vldt, nxt_conf_value_t *value)
return ret;
}
- return nxt_conf_vldt_clone_procmap(vldt, "gid_map", value);
+ return NXT_OK;
}
#endif
@@ -3296,16 +3287,19 @@ nxt_conf_vldt_server(nxt_conf_validation_t *vldt, nxt_str_t *name,
nxt_conf_value_t *value)
{
nxt_int_t ret;
+ nxt_str_t str;
nxt_sockaddr_t *sa;
ret = nxt_conf_vldt_type(vldt, name, value, NXT_CONF_VLDT_OBJECT);
-
if (ret != NXT_OK) {
return ret;
}
- sa = nxt_sockaddr_parse(vldt->pool, name);
+ if (nxt_slow_path(nxt_str_dup(vldt->pool, &str, name) == NULL)) {
+ return NXT_ERROR;
+ }
+ sa = nxt_sockaddr_parse(vldt->pool, &str);
if (sa == NULL) {
return nxt_conf_vldt_error(vldt, "The \"%V\" is not valid "
"server address.", name);
diff --git a/src/nxt_conn_write.c b/src/nxt_conn_write.c
index 714a3e15..7d0a579f 100644
--- a/src/nxt_conn_write.c
+++ b/src/nxt_conn_write.c
@@ -172,6 +172,13 @@ nxt_conn_io_sendbuf(nxt_task_t *task, nxt_sendbuf_t *sb)
return 0;
}
+ /*
+ * XXX Temporary fix for <https://github.com/nginx/unit/issues/1125>
+ */
+ if (niov == 0 && sb->buf == NULL) {
+ return 0;
+ }
+
if (niov == 0 && nxt_buf_is_file(sb->buf)) {
return nxt_conn_io_sendfile(task, sb);
}
diff --git a/src/nxt_credential.c b/src/nxt_credential.c
index bda97024..1c9fa9a7 100644
--- a/src/nxt_credential.c
+++ b/src/nxt_credential.c
@@ -74,8 +74,11 @@ nxt_credential_get(nxt_task_t *task, nxt_mp_t *mp, nxt_credential_t *uc,
end = msg + NXT_MAX_ERROR_STR;
for (i = 0; i < uc->ngroups; i++) {
- p = nxt_sprintf(p, end, "%d%c", uc->gids[i],
- i+1 < uc->ngroups ? ',' : '\0');
+ p = nxt_sprintf(p, end, "%d,", uc->gids[i]);
+ }
+
+ if (uc->ngroups > 0) {
+ p--;
}
nxt_debug(task, "user \"%s\" has gids:%*s", uc->user, p - msg, msg);
diff --git a/src/nxt_file.c b/src/nxt_file.c
index 6f1a93e4..4047d9d7 100644
--- a/src/nxt_file.c
+++ b/src/nxt_file.c
@@ -326,6 +326,88 @@ nxt_file_set_access(nxt_file_name_t *name, nxt_file_access_t access)
nxt_int_t
+nxt_file_chown(nxt_file_name_t *name, const char *owner, const char *group)
+{
+ int err;
+ char *buf;
+ long bufsize;
+ gid_t gid = ~0;
+ uid_t uid = ~0;
+
+ if (owner == NULL && group == NULL) {
+ return NXT_OK;
+ }
+
+ if (owner != NULL) {
+ struct passwd pwd, *result;
+
+ bufsize = sysconf(_SC_GETPW_R_SIZE_MAX);
+ if (bufsize == -1) {
+ bufsize = 32768;
+ }
+
+ buf = nxt_malloc(bufsize);
+ if (buf == NULL) {
+ return NXT_ERROR;
+ }
+
+ err = getpwnam_r(owner, &pwd, buf, bufsize, &result);
+ if (result == NULL) {
+ nxt_thread_log_alert("getpwnam_r(\"%s\", ...) failed %E %s",
+ owner, nxt_errno,
+ err == 0 ? "(User not found)" : "");
+ goto out_err_free;
+ }
+
+ uid = pwd.pw_uid;
+
+ nxt_free(buf);
+ }
+
+ if (group != NULL) {
+ struct group grp, *result;
+
+ bufsize = sysconf(_SC_GETGR_R_SIZE_MAX);
+ if (bufsize == -1) {
+ bufsize = 32768;
+ }
+
+ buf = nxt_malloc(bufsize);
+ if (buf == NULL) {
+ return NXT_ERROR;
+ }
+
+ err = getgrnam_r(group, &grp, buf, bufsize, &result);
+ if (result == NULL) {
+ nxt_thread_log_alert("getgrnam_r(\"%s\", ...) failed %E %s",
+ group, nxt_errno,
+ err == 0 ? "(Group not found)" : "");
+ goto out_err_free;
+ }
+
+ gid = grp.gr_gid;
+
+ nxt_free(buf);
+ }
+
+ if (nxt_fast_path(chown((const char *) name, uid, gid) == 0)) {
+ return NXT_OK;
+ }
+
+ nxt_thread_log_alert("chown(\"%FN\", %l, %l) failed %E", name,
+ owner != NULL ? (long) uid : -1,
+ group != NULL ? (long) gid : -1, nxt_errno);
+
+ return NXT_ERROR;
+
+out_err_free:
+ nxt_free(buf);
+
+ return NXT_ERROR;
+}
+
+
+nxt_int_t
nxt_file_rename(nxt_file_name_t *old_name, nxt_file_name_t *new_name)
{
int ret;
diff --git a/src/nxt_file.h b/src/nxt_file.h
index 97636db6..0c03a5f9 100644
--- a/src/nxt_file.h
+++ b/src/nxt_file.h
@@ -177,6 +177,8 @@ NXT_EXPORT nxt_int_t nxt_file_info(nxt_file_t *file, nxt_file_info_t *fi);
NXT_EXPORT nxt_int_t nxt_file_delete(nxt_file_name_t *name);
NXT_EXPORT nxt_int_t nxt_file_set_access(nxt_file_name_t *name,
nxt_file_access_t access);
+NXT_EXPORT nxt_int_t nxt_file_chown(nxt_file_name_t *name, const char *owner,
+ const char *group);
NXT_EXPORT nxt_int_t nxt_file_rename(nxt_file_name_t *old_name,
nxt_file_name_t *new_name);
diff --git a/src/nxt_http_js.c b/src/nxt_http_js.c
index 72ba761f..e3beb8b4 100644
--- a/src/nxt_http_js.c
+++ b/src/nxt_http_js.c
@@ -28,6 +28,8 @@ static njs_int_t nxt_http_js_ext_get_cookie(njs_vm_t *vm,
njs_value_t *retval);
static njs_int_t nxt_http_js_ext_keys_cookie(njs_vm_t *vm, njs_value_t *value,
njs_value_t *keys);
+static njs_int_t nxt_http_js_ext_get_var(njs_vm_t *vm, njs_object_prop_t *prop,
+ njs_value_t *value, njs_value_t *setval, njs_value_t *retval);
static njs_external_t nxt_http_js_proto[] = {
@@ -88,6 +90,14 @@ static njs_external_t nxt_http_js_proto[] = {
.keys = nxt_http_js_ext_keys_cookie,
}
},
+
+ {
+ .flags = NJS_EXTERN_OBJECT,
+ .name.string = njs_str("vars"),
+ .u.object = {
+ .prop_handler = nxt_http_js_ext_get_var,
+ }
+ },
};
@@ -338,3 +348,42 @@ nxt_http_js_ext_keys_cookie(njs_vm_t *vm, njs_value_t *value, njs_value_t *keys)
return NJS_OK;
}
+
+
+static njs_int_t
+nxt_http_js_ext_get_var(njs_vm_t *vm, njs_object_prop_t *prop,
+ njs_value_t *value, njs_value_t *setval, njs_value_t *retval)
+{
+ njs_int_t rc;
+ njs_str_t key;
+ nxt_str_t name, *vv;
+ nxt_router_conf_t *rtcf;
+ nxt_http_request_t *r;
+
+ r = njs_vm_external(vm, nxt_js_proto_id, value);
+ if (r == NULL) {
+ njs_value_undefined_set(retval);
+ return NJS_DECLINED;
+ }
+
+ rc = njs_vm_prop_name(vm, prop, &key);
+ if (rc != NJS_OK) {
+ njs_value_undefined_set(retval);
+ return NJS_DECLINED;
+ }
+
+ rtcf = r->conf->socket_conf->router_conf;
+
+ name.start = key.start;
+ name.length = key.length;
+
+ vv = nxt_var_get(&r->task, rtcf->tstr_state, &r->tstr_cache.var, &name, r);
+
+ if (vv != NULL) {
+ return njs_vm_value_string_set(vm, retval, vv->start, vv->length);
+ }
+
+ njs_value_undefined_set(retval);
+
+ return NJS_DECLINED;
+}
diff --git a/src/nxt_http_request.c b/src/nxt_http_request.c
index e532baff..f8d8d887 100644
--- a/src/nxt_http_request.c
+++ b/src/nxt_http_request.c
@@ -24,6 +24,8 @@ static void nxt_http_request_proto_info(nxt_task_t *task,
static void nxt_http_request_mem_buf_completion(nxt_task_t *task, void *obj,
void *data);
static void nxt_http_request_done(nxt_task_t *task, void *obj, void *data);
+static nxt_int_t nxt_http_request_access_log(nxt_task_t *task,
+ nxt_http_request_t *r, nxt_router_conf_t *rtcf);
static u_char *nxt_http_date_cache_handler(u_char *buf, nxt_realtime_t *now,
struct tm *tm, size_t size, const char *format);
@@ -816,27 +818,27 @@ nxt_http_request_error_handler(nxt_task_t *task, void *obj, void *data)
void
nxt_http_request_close_handler(nxt_task_t *task, void *obj, void *data)
{
- nxt_tstr_t *log_format;
+ nxt_int_t ret;
nxt_http_proto_t proto;
+ nxt_router_conf_t *rtcf;
nxt_http_request_t *r;
nxt_http_protocol_t protocol;
nxt_socket_conf_joint_t *conf;
- nxt_router_access_log_t *access_log;
r = obj;
proto.any = data;
conf = r->conf;
+ rtcf = conf->socket_conf->router_conf;
if (!r->logged) {
r->logged = 1;
- access_log = conf->socket_conf->router_conf->access_log;
- log_format = conf->socket_conf->router_conf->log_format;
-
- if (access_log != NULL) {
- access_log->handler(task, r, access_log, log_format);
- return;
+ if (rtcf->access_log != NULL) {
+ ret = nxt_http_request_access_log(task, r, rtcf);
+ if (ret == NXT_OK) {
+ return;
+ }
}
}
@@ -866,6 +868,57 @@ nxt_http_request_close_handler(nxt_task_t *task, void *obj, void *data)
}
+static nxt_int_t
+nxt_http_request_access_log(nxt_task_t *task, nxt_http_request_t *r,
+ nxt_router_conf_t *rtcf)
+{
+ nxt_int_t ret;
+ nxt_str_t str;
+ nxt_bool_t expr;
+ nxt_router_access_log_t *access_log;
+
+ access_log = rtcf->access_log;
+
+ expr = 1;
+
+ if (rtcf->log_expr != NULL) {
+
+ if (nxt_tstr_is_const(rtcf->log_expr)) {
+ nxt_tstr_str(rtcf->log_expr, &str);
+
+ } else {
+ ret = nxt_tstr_query_init(&r->tstr_query, rtcf->tstr_state,
+ &r->tstr_cache, r, r->mem_pool);
+ if (nxt_slow_path(ret != NXT_OK)) {
+ return NXT_DECLINED;
+ }
+
+ nxt_tstr_query(task, r->tstr_query, rtcf->log_expr, &str);
+
+ if (nxt_slow_path(nxt_tstr_query_failed(r->tstr_query))) {
+ return NXT_DECLINED;
+ }
+ }
+
+ if (str.length == 0
+ || nxt_str_eq(&str, "0", 1)
+ || nxt_str_eq(&str, "false", 5)
+ || nxt_str_eq(&str, "null", 4)
+ || nxt_str_eq(&str, "undefined", 9))
+ {
+ expr = 0;
+ }
+ }
+
+ if (rtcf->log_negate ^ expr) {
+ access_log->handler(task, r, access_log, rtcf->log_format);
+ return NXT_OK;
+ }
+
+ return NXT_DECLINED;
+}
+
+
static u_char *
nxt_http_date_cache_handler(u_char *buf, nxt_realtime_t *now, struct tm *tm,
size_t size, const char *format)
diff --git a/src/nxt_http_static.c b/src/nxt_http_static.c
index e51ba6b0..ee25015e 100644
--- a/src/nxt_http_static.c
+++ b/src/nxt_http_static.c
@@ -117,9 +117,7 @@ nxt_http_static_init(nxt_task_t *task, nxt_router_temp_conf_t *tmcf,
nxt_str_set(&conf->index, "index.html");
} else {
- nxt_conf_get_string(acf->index, &str);
-
- ret = nxt_str_dup(mp, &conf->index, &str);
+ ret = nxt_conf_get_string_dup(acf->index, mp, &conf->index);
if (nxt_slow_path(ret == NULL)) {
return NXT_ERROR;
}
@@ -879,12 +877,7 @@ complete_buf:
n = nxt_file_read(fb->file, b->mem.start, size, fb->file_pos);
- if (n != size) {
- if (n >= 0) {
- nxt_log(task, NXT_LOG_ERR, "file \"%FN\" has changed "
- "while sending response to a client", fb->file->name);
- }
-
+ if (nxt_slow_path(n == NXT_ERROR)) {
nxt_http_request_error_handler(task, r, r->proto.any);
goto clean;
}
diff --git a/src/nxt_http_variables.c b/src/nxt_http_variables.c
index 46594a6b..85ae6004 100644
--- a/src/nxt_http_variables.c
+++ b/src/nxt_http_variables.c
@@ -28,6 +28,8 @@ static u_char *nxt_http_log_date(u_char *buf, nxt_realtime_t *now,
struct tm *tm, size_t size, const char *format);
static nxt_int_t nxt_http_var_request_line(nxt_task_t *task, nxt_str_t *str,
void *ctx, void *data);
+static nxt_int_t nxt_http_var_request_id(nxt_task_t *task, nxt_str_t *str,
+ void *ctx, void *data);
static nxt_int_t nxt_http_var_status(nxt_task_t *task, nxt_str_t *str,
void *ctx, void *data);
static nxt_int_t nxt_http_var_body_bytes_sent(nxt_task_t *task, nxt_str_t *str,
@@ -90,6 +92,10 @@ static nxt_var_decl_t nxt_http_vars[] = {
.handler = nxt_http_var_request_line,
.cacheable = 1,
}, {
+ .name = nxt_string("request_id"),
+ .handler = nxt_http_var_request_id,
+ .cacheable = 1,
+ }, {
.name = nxt_string("status"),
.handler = nxt_http_var_status,
.cacheable = 1,
@@ -129,8 +135,7 @@ nxt_http_register_variables(void)
nxt_int_t
-nxt_http_unknown_var_ref(nxt_tstr_state_t *state, nxt_var_ref_t *ref,
- nxt_str_t *name)
+nxt_http_unknown_var_ref(nxt_mp_t *mp, nxt_var_ref_t *ref, nxt_str_t *name)
{
int64_t hash;
nxt_str_t str, *lower;
@@ -146,7 +151,7 @@ nxt_http_unknown_var_ref(nxt_tstr_state_t *state, nxt_var_ref_t *ref,
return NXT_ERROR;
}
- lower = nxt_str_alloc(state->pool, str.length);
+ lower = nxt_str_alloc(mp, str.length);
if (nxt_slow_path(lower == NULL)) {
return NXT_ERROR;
}
@@ -169,7 +174,7 @@ nxt_http_unknown_var_ref(nxt_tstr_state_t *state, nxt_var_ref_t *ref,
return NXT_ERROR;
}
- hash = nxt_http_header_hash(state->pool, &str);
+ hash = nxt_http_header_hash(mp, &str);
if (nxt_slow_path(hash == -1)) {
return NXT_ERROR;
}
@@ -185,7 +190,7 @@ nxt_http_unknown_var_ref(nxt_tstr_state_t *state, nxt_var_ref_t *ref,
return NXT_ERROR;
}
- hash = nxt_http_argument_hash(state->pool, &str);
+ hash = nxt_http_argument_hash(mp, &str);
if (nxt_slow_path(hash == -1)) {
return NXT_ERROR;
}
@@ -201,7 +206,7 @@ nxt_http_unknown_var_ref(nxt_tstr_state_t *state, nxt_var_ref_t *ref,
return NXT_ERROR;
}
- hash = nxt_http_cookie_hash(state->pool, &str);
+ hash = nxt_http_cookie_hash(mp, &str);
if (nxt_slow_path(hash == -1)) {
return NXT_ERROR;
}
@@ -210,7 +215,7 @@ nxt_http_unknown_var_ref(nxt_tstr_state_t *state, nxt_var_ref_t *ref,
return NXT_ERROR;
}
- ref->data = nxt_var_field_new(state->pool, &str, (uint32_t) hash);
+ ref->data = nxt_var_field_new(mp, &str, (uint32_t) hash);
if (nxt_slow_path(ref->data == NULL)) {
return NXT_ERROR;
}
@@ -396,6 +401,32 @@ nxt_http_var_request_line(nxt_task_t *task, nxt_str_t *str, void *ctx,
static nxt_int_t
+nxt_http_var_request_id(nxt_task_t *task, nxt_str_t *str, void *ctx,
+ void *data)
+{
+ nxt_random_t *rand;
+ nxt_http_request_t *r;
+
+ r = ctx;
+
+ str->start = nxt_mp_nget(r->mem_pool, 32);
+ if (nxt_slow_path(str->start == NULL)) {
+ return NXT_ERROR;
+ }
+
+ str->length = 32;
+
+ rand = &task->thread->random;
+
+ (void) nxt_sprintf(str->start, str->start + 32, "%08xD%08xD%08xD%08xD",
+ nxt_random(rand), nxt_random(rand),
+ nxt_random(rand), nxt_random(rand));
+
+ return NXT_OK;
+}
+
+
+static nxt_int_t
nxt_http_var_body_bytes_sent(nxt_task_t *task, nxt_str_t *str, void *ctx,
void *data)
{
@@ -423,7 +454,6 @@ nxt_http_var_body_bytes_sent(nxt_task_t *task, nxt_str_t *str, void *ctx,
static nxt_int_t
nxt_http_var_status(nxt_task_t *task, nxt_str_t *str, void *ctx, void *data)
{
- u_char *p;
nxt_http_request_t *r;
r = ctx;
@@ -433,9 +463,9 @@ nxt_http_var_status(nxt_task_t *task, nxt_str_t *str, void *ctx, void *data)
return NXT_ERROR;
}
- p = nxt_sprintf(str->start, str->start + 3, "%03d", r->status);
+ (void) nxt_sprintf(str->start, str->start + 3, "%03d", r->status);
- str->length = p - str->start;
+ str->length = 3;
return NXT_OK;
}
diff --git a/src/nxt_isolation.c b/src/nxt_isolation.c
index cfa494a8..ed5e0d76 100644
--- a/src/nxt_isolation.c
+++ b/src/nxt_isolation.c
@@ -326,19 +326,19 @@ nxt_isolation_credential_map(nxt_task_t *task, nxt_mp_t *mp,
static nxt_conf_map_t nxt_clone_map_entry_conf[] = {
{
nxt_string("container"),
- NXT_CONF_MAP_INT,
+ NXT_CONF_MAP_INT64,
offsetof(nxt_clone_map_entry_t, container),
},
{
nxt_string("host"),
- NXT_CONF_MAP_INT,
+ NXT_CONF_MAP_INT64,
offsetof(nxt_clone_map_entry_t, host),
},
{
nxt_string("size"),
- NXT_CONF_MAP_INT,
+ NXT_CONF_MAP_INT64,
offsetof(nxt_clone_map_entry_t, size),
},
};
diff --git a/src/nxt_js.c b/src/nxt_js.c
index 74663660..6885afb7 100644
--- a/src/nxt_js.c
+++ b/src/nxt_js.c
@@ -240,7 +240,7 @@ nxt_js_add_tpl(nxt_js_conf_t *jcf, nxt_str_t *str, nxt_bool_t strz)
nxt_str_t *func;
static nxt_str_t func_str = nxt_string("function(uri, host, remoteAddr, "
- "args, headers, cookies) {"
+ "args, headers, cookies, vars) {"
" return ");
/*
@@ -388,16 +388,20 @@ nxt_js_call(nxt_task_t *task, nxt_js_conf_t *jcf, nxt_js_cache_t *cache,
njs_vm_t *vm;
njs_int_t ret;
njs_str_t res;
+ njs_uint_t i, n;
njs_value_t *value;
njs_function_t *func;
- njs_opaque_value_t retval, opaque_value, arguments[6];
-
- static const njs_str_t uri_str = njs_str("uri");
- static const njs_str_t host_str = njs_str("host");
- static const njs_str_t remote_addr_str = njs_str("remoteAddr");
- static const njs_str_t args_str = njs_str("args");
- static const njs_str_t headers_str = njs_str("headers");
- static const njs_str_t cookies_str = njs_str("cookies");
+ njs_opaque_value_t retval, opaque_value, arguments[7];
+
+ static const njs_str_t js_args[] = {
+ njs_str("uri"),
+ njs_str("host"),
+ njs_str("remoteAddr"),
+ njs_str("args"),
+ njs_str("headers"),
+ njs_str("cookies"),
+ njs_str("vars"),
+ };
vm = cache->vm;
@@ -424,43 +428,17 @@ nxt_js_call(nxt_task_t *task, nxt_js_conf_t *jcf, nxt_js_cache_t *cache,
return NXT_ERROR;
}
- value = njs_vm_object_prop(vm, njs_value_arg(&opaque_value), &uri_str,
- &arguments[0]);
- if (nxt_slow_path(value == NULL)) {
- return NXT_ERROR;
- }
-
- value = njs_vm_object_prop(vm, njs_value_arg(&opaque_value), &host_str,
- &arguments[1]);
- if (nxt_slow_path(value == NULL)) {
- return NXT_ERROR;
- }
-
- value = njs_vm_object_prop(vm, njs_value_arg(&opaque_value),
- &remote_addr_str, &arguments[2]);
- if (nxt_slow_path(value == NULL)) {
- return NXT_ERROR;
- }
+ n = nxt_nitems(js_args);
- value = njs_vm_object_prop(vm, njs_value_arg(&opaque_value), &args_str,
- &arguments[3]);
- if (nxt_slow_path(value == NULL)) {
- return NXT_ERROR;
- }
-
- value = njs_vm_object_prop(vm, njs_value_arg(&opaque_value), &headers_str,
- &arguments[4]);
- if (nxt_slow_path(value == NULL)) {
- return NXT_ERROR;
- }
-
- value = njs_vm_object_prop(vm, njs_value_arg(&opaque_value), &cookies_str,
- &arguments[5]);
- if (nxt_slow_path(value == NULL)) {
- return NXT_ERROR;
+ for (i = 0; i < n; i++) {
+ value = njs_vm_object_prop(vm, njs_value_arg(&opaque_value),
+ &js_args[i], &arguments[i]);
+ if (nxt_slow_path(value == NULL)) {
+ return NXT_ERROR;
+ }
}
- ret = njs_vm_invoke(vm, func, njs_value_arg(&arguments), 6,
+ ret = njs_vm_invoke(vm, func, njs_value_arg(&arguments), n,
njs_value_arg(&retval));
if (ret != NJS_OK) {
diff --git a/src/nxt_listen_socket.c b/src/nxt_listen_socket.c
index d477eef1..047c1ef9 100644
--- a/src/nxt_listen_socket.c
+++ b/src/nxt_listen_socket.c
@@ -127,13 +127,23 @@ nxt_listen_socket_create(nxt_task_t *task, nxt_mp_t *mp,
#if (NXT_HAVE_UNIX_DOMAIN)
if (family == AF_UNIX) {
- name = (nxt_file_name_t *) sa->u.sockaddr_un.sun_path;
+ const char *user;
+ const char *group;
+ nxt_runtime_t *rt = thr->runtime;
- access = (S_IRUSR | S_IWUSR);
+ name = (nxt_file_name_t *) sa->u.sockaddr_un.sun_path;
+ access = rt->control_mode > 0 ? rt->control_mode : S_IRUSR | S_IWUSR;
if (nxt_file_set_access(name, access) != NXT_OK) {
goto listen_fail;
}
+
+ user = rt->control_user;
+ group = rt->control_group;
+
+ if (nxt_file_chown(name, user, group) != NXT_OK) {
+ goto listen_fail;
+ }
}
#endif
diff --git a/src/nxt_main_process.c b/src/nxt_main_process.c
index 3f317d5e..060ead41 100644
--- a/src/nxt_main_process.c
+++ b/src/nxt_main_process.c
@@ -377,6 +377,20 @@ static nxt_conf_map_t nxt_wasm_app_conf[] = {
};
+static nxt_conf_map_t nxt_wasm_wc_app_conf[] = {
+ {
+ nxt_string("component"),
+ NXT_CONF_MAP_CSTRZ,
+ offsetof(nxt_common_app_conf_t, u.wasm_wc.component),
+ },
+ {
+ nxt_string("access"),
+ NXT_CONF_MAP_PTR,
+ offsetof(nxt_common_app_conf_t, u.wasm_wc.access),
+ },
+};
+
+
static nxt_conf_app_map_t nxt_app_maps[] = {
{ nxt_nitems(nxt_external_app_conf), nxt_external_app_conf },
{ nxt_nitems(nxt_python_app_conf), nxt_python_app_conf },
@@ -385,6 +399,7 @@ static nxt_conf_app_map_t nxt_app_maps[] = {
{ nxt_nitems(nxt_ruby_app_conf), nxt_ruby_app_conf },
{ nxt_nitems(nxt_java_app_conf), nxt_java_app_conf },
{ nxt_nitems(nxt_wasm_app_conf), nxt_wasm_app_conf },
+ { nxt_nitems(nxt_wasm_wc_app_conf), nxt_wasm_wc_app_conf },
};
diff --git a/src/nxt_openssl.c b/src/nxt_openssl.c
index f56135f3..8f66f45b 100644
--- a/src/nxt_openssl.c
+++ b/src/nxt_openssl.c
@@ -73,7 +73,7 @@ static nxt_int_t nxt_ssl_conf_commands(nxt_task_t *task, SSL_CTX *ctx,
static nxt_int_t nxt_tls_ticket_keys(nxt_task_t *task, SSL_CTX *ctx,
nxt_tls_init_t *tls_init, nxt_mp_t *mp);
static int nxt_tls_ticket_key_callback(SSL *s, unsigned char *name,
- unsigned char *iv, EVP_CIPHER_CTX *ectx,HMAC_CTX *hctx, int enc);
+ unsigned char *iv, EVP_CIPHER_CTX *ectx, HMAC_CTX *hctx, int enc);
#endif
static void nxt_ssl_session_cache(SSL_CTX *ctx, size_t cache_size,
time_t timeout);
diff --git a/src/nxt_php_sapi.c b/src/nxt_php_sapi.c
index ba000fc0..77117533 100644
--- a/src/nxt_php_sapi.c
+++ b/src/nxt_php_sapi.c
@@ -1225,6 +1225,8 @@ nxt_php_execute(nxt_php_run_ctx_t *ctx, nxt_unit_request_t *r)
nxt_unit_req_debug(ctx->req, "php_request_startup() failed");
nxt_unit_request_done(ctx->req, NXT_UNIT_ERROR);
+ fclose(fp);
+
return;
}
diff --git a/src/nxt_router.c b/src/nxt_router.c
index 4e3cb303..1a1aca2b 100644
--- a/src/nxt_router.c
+++ b/src/nxt_router.c
@@ -281,6 +281,7 @@ static const nxt_str_t *nxt_app_msg_prefix[] = {
[NXT_APP_RUBY] = &http_prefix,
[NXT_APP_JAVA] = &empty_prefix,
[NXT_APP_WASM] = &empty_prefix,
+ [NXT_APP_WASM_WC] = &empty_prefix,
};
@@ -2275,7 +2276,7 @@ nxt_router_conf_process_static(nxt_task_t *task, nxt_router_conf_t *rtcf,
{
uint32_t next, i;
nxt_mp_t *mp;
- nxt_str_t *type, exten, str;
+ nxt_str_t *type, exten, str, *s;
nxt_int_t ret;
nxt_uint_t exts;
nxt_conf_value_t *mtypes_conf, *ext_conf, *value;
@@ -2311,9 +2312,8 @@ nxt_router_conf_process_static(nxt_task_t *task, nxt_router_conf_t *rtcf,
}
if (nxt_conf_type(ext_conf) == NXT_CONF_STRING) {
- nxt_conf_get_string(ext_conf, &str);
-
- if (nxt_slow_path(nxt_str_dup(mp, &exten, &str) == NULL)) {
+ s = nxt_conf_get_string_dup(ext_conf, mp, &exten);
+ if (nxt_slow_path(s == NULL)) {
return NXT_ERROR;
}
@@ -2331,9 +2331,8 @@ nxt_router_conf_process_static(nxt_task_t *task, nxt_router_conf_t *rtcf,
for (i = 0; i < exts; i++) {
value = nxt_conf_get_array_element(ext_conf, i);
- nxt_conf_get_string(value, &str);
-
- if (nxt_slow_path(nxt_str_dup(mp, &exten, &str) == NULL)) {
+ s = nxt_conf_get_string_dup(value, mp, &exten);
+ if (nxt_slow_path(s == NULL)) {
return NXT_ERROR;
}
@@ -2425,14 +2424,11 @@ static nxt_int_t
nxt_router_conf_forward_header(nxt_mp_t *mp, nxt_conf_value_t *conf,
nxt_http_forward_header_t *fh)
{
- char c;
- size_t i;
- uint32_t hash;
- nxt_str_t header;
-
- nxt_conf_get_string(conf, &header);
+ char c;
+ size_t i;
+ uint32_t hash;
- fh->header = nxt_str_dup(mp, NULL, &header);
+ fh->header = nxt_conf_get_string_dup(conf, mp, NULL);
if (nxt_slow_path(fh->header == NULL)) {
return NXT_ERROR;
}
@@ -2971,7 +2967,7 @@ nxt_router_tls_rpc_handler(nxt_task_t *task, nxt_port_recv_msg_t *msg,
mp = tmcf->router_conf->mem_pool;
- if (tls->socket_conf->tls == NULL){
+ if (tls->socket_conf->tls == NULL) {
tlscf = nxt_mp_zget(mp, sizeof(nxt_tls_conf_t));
if (nxt_slow_path(tlscf == NULL)) {
goto fail;
diff --git a/src/nxt_router.h b/src/nxt_router.h
index b14f8410..3e523001 100644
--- a/src/nxt_router.h
+++ b/src/nxt_router.h
@@ -54,6 +54,8 @@ typedef struct {
nxt_router_access_log_t *access_log;
nxt_tstr_t *log_format;
+ nxt_tstr_t *log_expr;
+ uint8_t log_negate; /* 1 bit */
} nxt_router_conf_t;
diff --git a/src/nxt_router_access_log.c b/src/nxt_router_access_log.c
index ccbddb96..7fc59972 100644
--- a/src/nxt_router_access_log.c
+++ b/src/nxt_router_access_log.c
@@ -13,6 +13,7 @@
typedef struct {
nxt_str_t path;
nxt_str_t format;
+ nxt_conf_value_t *expr;
} nxt_router_access_log_conf_t;
@@ -53,6 +54,12 @@ static nxt_conf_map_t nxt_router_access_log_conf[] = {
NXT_CONF_MAP_STR,
offsetof(nxt_router_access_log_conf_t, format),
},
+
+ {
+ nxt_string("if"),
+ NXT_CONF_MAP_PTR,
+ offsetof(nxt_router_access_log_conf_t, expr),
+ },
};
@@ -72,6 +79,8 @@ nxt_router_access_log_create(nxt_task_t *task, nxt_router_conf_t *rtcf,
"[$time_local] \"$request_line\" $status $body_bytes_sent "
"\"$header_referer\" \"$header_user_agent\"");
+ nxt_memzero(&alcf, sizeof(nxt_router_access_log_conf_t));
+
alcf.format = log_format_str;
if (nxt_conf_type(value) == NXT_CONF_STRING) {
@@ -133,6 +142,22 @@ nxt_router_access_log_create(nxt_task_t *task, nxt_router_conf_t *rtcf,
rtcf->access_log = access_log;
rtcf->log_format = format;
+ if (alcf.expr != NULL) {
+ nxt_conf_get_string(alcf.expr, &str);
+
+ if (str.length > 0 && str.start[0] == '!') {
+ rtcf->log_negate = 1;
+
+ str.start++;
+ str.length--;
+ }
+
+ rtcf->log_expr = nxt_tstr_compile(rtcf->tstr_state, &str, 0);
+ if (nxt_slow_path(rtcf->log_expr == NULL)) {
+ return NXT_ERROR;
+ }
+ }
+
return NXT_OK;
}
diff --git a/src/nxt_runtime.c b/src/nxt_runtime.c
index 9bfabc75..0e7f879e 100644
--- a/src/nxt_runtime.c
+++ b/src/nxt_runtime.c
@@ -956,6 +956,12 @@ nxt_runtime_conf_read_cmd(nxt_task_t *task, nxt_runtime_t *rt)
static const char no_control[] =
"option \"--control\" requires socket address\n";
+ static const char no_control_mode[] =
+ "option \"--control-mode\" requires a mode\n";
+ static const char no_control_user[] =
+ "option \"--control-user\" requires a username\n";
+ static const char no_control_group[] =
+ "option \"--control-group\" requires a group name\n";
static const char no_user[] = "option \"--user\" requires username\n";
static const char no_group[] = "option \"--group\" requires group name\n";
static const char no_pid[] = "option \"--pid\" requires filename\n";
@@ -984,6 +990,13 @@ nxt_runtime_conf_read_cmd(nxt_task_t *task, nxt_runtime_t *rt)
" --control ADDRESS set address of control API socket\n"
" default: \"" NXT_CONTROL_SOCK "\"\n"
"\n"
+ " --control-mode MODE set mode of the control API socket\n"
+ " default: 0600\n"
+ "\n"
+ " --control-user USER set the owner of the control API socket\n"
+ "\n"
+ " --control-group GROUP set the group of the control API socket\n"
+ "\n"
" --pid FILE set pid filename\n"
" default: \"" NXT_PID "\"\n"
"\n"
@@ -1032,6 +1045,48 @@ nxt_runtime_conf_read_cmd(nxt_task_t *task, nxt_runtime_t *rt)
continue;
}
+ if (nxt_strcmp(p, "--control-mode") == 0) {
+ if (*argv == NULL) {
+ write(STDERR_FILENO, no_control_mode,
+ nxt_length(no_control_mode));
+ return NXT_ERROR;
+ }
+
+ p = *argv++;
+
+ rt->control_mode = strtoul(p, NULL, 8);
+
+ continue;
+ }
+
+ if (nxt_strcmp(p, "--control-user") == 0) {
+ if (*argv == NULL) {
+ write(STDERR_FILENO, no_control_user,
+ nxt_length(no_control_user));
+ return NXT_ERROR;
+ }
+
+ p = *argv++;
+
+ rt->control_user = p;
+
+ continue;
+ }
+
+ if (nxt_strcmp(p, "--control-group") == 0) {
+ if (*argv == NULL) {
+ write(STDERR_FILENO, no_control_group,
+ nxt_length(no_control_group));
+ return NXT_ERROR;
+ }
+
+ p = *argv++;
+
+ rt->control_group = p;
+
+ continue;
+ }
+
if (nxt_strcmp(p, "--user") == 0) {
if (*argv == NULL) {
write(STDERR_FILENO, no_user, nxt_length(no_user));
diff --git a/src/nxt_runtime.h b/src/nxt_runtime.h
index 66ec0106..7bd490d7 100644
--- a/src/nxt_runtime.h
+++ b/src/nxt_runtime.h
@@ -70,8 +70,12 @@ struct nxt_runtime_s {
const char *ver_tmp;
const char *conf;
const char *conf_tmp;
- const char *control;
const char *tmp;
+ const char *control;
+
+ mode_t control_mode;
+ const char *control_user;
+ const char *control_group;
nxt_str_t certs;
nxt_str_t scripts;
diff --git a/src/nxt_socket.c b/src/nxt_socket.c
index a8e0d514..9ac8ecd2 100644
--- a/src/nxt_socket.c
+++ b/src/nxt_socket.c
@@ -322,15 +322,15 @@ nxt_socket_error(nxt_socket_t s)
err = 0;
len = sizeof(int);
- /*
- * Linux and BSDs return 0 and store a pending error in the err argument;
+ /*
+ * Linux and BSDs return 0 and store a pending error in the err argument;
* Solaris returns -1 and sets the errno.
- */
+ */
ret = getsockopt(s, SOL_SOCKET, SO_ERROR, (void *) &err, &len);
if (nxt_slow_path(ret == -1)) {
err = nxt_errno;
- }
+ }
return err;
}
diff --git a/src/nxt_unit.h b/src/nxt_unit.h
index 35f9fa55..a50046a5 100644
--- a/src/nxt_unit.h
+++ b/src/nxt_unit.h
@@ -40,7 +40,7 @@ enum {
/*
* Mostly opaque structure with library state.
*
- * Only user defined 'data' pointer exposed here. The rest is unit
+ * Only the user defined 'data' pointer is exposed here. The rest is unit
* implementation specific and hidden.
*/
struct nxt_unit_s {
@@ -51,8 +51,8 @@ struct nxt_unit_s {
* Thread context.
*
* First (main) context is provided 'for free'. To receive and process
- * requests in other thread, one need to allocate context and use it
- * further in this thread.
+ * requests in other threads, one needs to allocate a new context and use it
+ * further in that thread.
*/
struct nxt_unit_ctx_s {
void *data; /* User context-specific data. */
@@ -72,7 +72,7 @@ struct nxt_unit_port_id_s {
};
/*
- * unit provides port storage which is able to store and find the following
+ * Unit provides port storage which is able to store and find the following
* data structures.
*/
struct nxt_unit_port_s {
@@ -114,13 +114,13 @@ struct nxt_unit_request_info_s {
/*
- * Set of application-specific callbacks. Application may leave all optional
- * callbacks as NULL.
+ * Set of application-specific callbacks. The application may leave all
+ * optional callbacks as NULL.
*/
struct nxt_unit_callbacks_s {
/*
- * Process request. Unlike all other callback, this callback
- * need to be defined by application.
+ * Process request. Unlike all other callbacks, this callback is required
+ * and needs to be defined by the application.
*/
void (*request_handler)(nxt_unit_request_info_t *req);
@@ -201,15 +201,15 @@ struct nxt_unit_read_info_s {
nxt_unit_ctx_t *nxt_unit_init(nxt_unit_init_t *);
/*
- * Main function useful in case when application does not have it's own
- * event loop. nxt_unit_run() starts infinite message wait and process loop.
+ * Main function, useful in case the application does not have its own event
+ * loop. nxt_unit_run() starts an infinite message wait and process loop.
*
* for (;;) {
* app_lib->port_recv(...);
* nxt_unit_process_msg(...);
* }
*
- * The normally function returns when QUIT message received from Unit.
+ * The function returns normally when a QUIT message is received from Unit.
*/
int nxt_unit_run(nxt_unit_ctx_t *);
@@ -220,10 +220,10 @@ int nxt_unit_run_shared(nxt_unit_ctx_t *ctx);
nxt_unit_request_info_t *nxt_unit_dequeue_request(nxt_unit_ctx_t *ctx);
/*
- * Receive and process one message, invoke configured callbacks.
+ * Receive and process one message, and invoke configured callbacks.
*
- * If application implements it's own event loop, each datagram received
- * from port socket should be initially processed by unit. This function
+ * If the application implements its own event loop, each datagram received
+ * from the port socket should be initially processed by unit. This function
* may invoke other application-defined callback for message processing.
*/
int nxt_unit_run_once(nxt_unit_ctx_t *ctx);
@@ -234,8 +234,8 @@ int nxt_unit_process_port_msg(nxt_unit_ctx_t *ctx, nxt_unit_port_t *port);
void nxt_unit_done(nxt_unit_ctx_t *);
/*
- * Allocate and initialize new execution context with new listen port to
- * process requests in other thread.
+ * Allocate and initialize a new execution context with a new listen port to
+ * process requests in another thread.
*/
nxt_unit_ctx_t *nxt_unit_ctx_alloc(nxt_unit_ctx_t *, void *);
@@ -253,7 +253,7 @@ void nxt_unit_split_host(char *host_start, uint32_t host_length,
void nxt_unit_request_group_dup_fields(nxt_unit_request_info_t *req);
/*
- * Allocate response structure capable to store limited numer of fields.
+ * Allocate response structure capable of storing a limited number of fields.
* The structure may be accessed directly via req->response pointer or
* filled step-by-step using functions add_field and add_content.
*/
@@ -273,8 +273,8 @@ int nxt_unit_response_add_content(nxt_unit_request_info_t *req,
const void* src, uint32_t size);
/*
- * Send prepared response to Unit server. Response structure destroyed during
- * this call.
+ * Send the prepared response to the Unit server. The Response structure is
+ * destroyed during this call.
*/
int nxt_unit_response_send(nxt_unit_request_info_t *req);
diff --git a/src/nxt_var.c b/src/nxt_var.c
index 729de788..2600371b 100644
--- a/src/nxt_var.c
+++ b/src/nxt_var.c
@@ -50,11 +50,12 @@ struct nxt_var_query_s {
static nxt_int_t nxt_var_hash_test(nxt_lvlhsh_query_t *lhq, void *data);
static nxt_var_decl_t *nxt_var_hash_find(nxt_str_t *name);
-static nxt_var_ref_t *nxt_var_ref_get(nxt_tstr_state_t *state, nxt_str_t *name);
+static nxt_var_ref_t *nxt_var_ref_get(nxt_tstr_state_t *state, nxt_str_t *name,
+ nxt_mp_t *mp);
static nxt_int_t nxt_var_cache_test(nxt_lvlhsh_query_t *lhq, void *data);
static nxt_str_t *nxt_var_cache_value(nxt_task_t *task, nxt_tstr_state_t *state,
- nxt_var_cache_t *cache, uint32_t index, void *ctx);
+ nxt_var_cache_t *cache, nxt_var_ref_t *ref, void *ctx);
static u_char *nxt_var_next_part(u_char *start, u_char *end, nxt_str_t *part);
@@ -109,7 +110,7 @@ nxt_var_hash_find(nxt_str_t *name)
static nxt_var_ref_t *
-nxt_var_ref_get(nxt_tstr_state_t *state, nxt_str_t *name)
+nxt_var_ref_get(nxt_tstr_state_t *state, nxt_str_t *name, nxt_mp_t *mp)
{
nxt_int_t ret;
nxt_uint_t i;
@@ -125,16 +126,21 @@ nxt_var_ref_get(nxt_tstr_state_t *state, nxt_str_t *name)
}
}
- ref = nxt_array_add(state->var_refs);
- if (nxt_slow_path(ref == NULL)) {
- return NULL;
- }
+ if (mp != NULL) {
+ ref = nxt_mp_alloc(mp, sizeof(nxt_var_ref_t));
+ if (nxt_slow_path(ref == NULL)) {
+ return NULL;
+ }
- ref->index = state->var_refs->nelts - 1;
+ } else {
+ ref = nxt_array_add(state->var_refs);
+ if (nxt_slow_path(ref == NULL)) {
+ return NULL;
+ }
- ref->name = nxt_str_dup(state->pool, NULL, name);
- if (nxt_slow_path(ref->name == NULL)) {
- return NULL;
+ ref->index = state->var_refs->nelts - 1;
+
+ mp = state->pool;
}
decl = nxt_var_hash_find(name);
@@ -143,14 +149,21 @@ nxt_var_ref_get(nxt_tstr_state_t *state, nxt_str_t *name)
ref->handler = decl->handler;
ref->cacheable = decl->cacheable;
- return ref;
+ goto done;
}
- ret = nxt_http_unknown_var_ref(state, ref, name);
+ ret = nxt_http_unknown_var_ref(mp, ref, name);
if (nxt_slow_path(ret != NXT_OK)) {
return NULL;
}
+done:
+
+ ref->name = nxt_str_dup(mp, NULL, name);
+ if (nxt_slow_path(ref->name == NULL)) {
+ return NULL;
+ }
+
return ref;
}
@@ -203,16 +216,12 @@ nxt_var_cache_test(nxt_lvlhsh_query_t *lhq, void *data)
static nxt_str_t *
nxt_var_cache_value(nxt_task_t *task, nxt_tstr_state_t *state,
- nxt_var_cache_t *cache, uint32_t index, void *ctx)
+ nxt_var_cache_t *cache, nxt_var_ref_t *ref, void *ctx)
{
nxt_int_t ret;
nxt_str_t *value;
- nxt_var_ref_t *ref;
nxt_lvlhsh_query_t lhq;
- ref = state->var_refs->elts;
- ref = &ref[index];
-
value = cache->spare;
if (value == NULL) {
@@ -228,10 +237,10 @@ nxt_var_cache_value(nxt_task_t *task, nxt_tstr_state_t *state,
goto not_cached;
}
- lhq.key_hash = nxt_murmur_hash2_uint32(&index);
+ lhq.key_hash = nxt_murmur_hash2_uint32(&ref->index);
lhq.replace = 0;
lhq.key.length = sizeof(uint32_t);
- lhq.key.start = (u_char *) &index;
+ lhq.key.start = (u_char *) &ref->index;
lhq.value = value;
lhq.proto = &nxt_var_cache_proto;
lhq.pool = cache->pool;
@@ -357,7 +366,7 @@ nxt_var_compile(nxt_tstr_state_t *state, nxt_str_t *str)
next = nxt_var_next_part(p, end, &part);
if (part.start != NULL) {
- ref = nxt_var_ref_get(state, &part);
+ ref = nxt_var_ref_get(state, &part, NULL);
if (nxt_slow_path(ref == NULL)) {
return NULL;
}
@@ -397,7 +406,7 @@ nxt_var_test(nxt_tstr_state_t *state, nxt_str_t *str, u_char *error)
}
if (part.start != NULL) {
- ref = nxt_var_ref_get(state, &part);
+ ref = nxt_var_ref_get(state, &part, NULL);
if (ref == NULL) {
nxt_sprintf(error, error + NXT_MAX_ERROR_STR,
@@ -491,20 +500,24 @@ nxt_var_interpreter(nxt_task_t *task, nxt_tstr_state_t *state,
{
u_char *p, *src;
size_t length, last, next;
+ uint32_t index;
nxt_str_t *value, **part;
nxt_uint_t i;
nxt_array_t parts;
+ nxt_var_ref_t *ref;
nxt_var_sub_t *subs;
nxt_memzero(&parts, sizeof(nxt_array_t));
nxt_array_init(&parts, cache->pool, sizeof(nxt_str_t *));
+ ref = state->var_refs->elts;
subs = nxt_var_subs(var);
length = var->length;
for (i = 0; i < var->vars; i++) {
- value = nxt_var_cache_value(task, state, cache, subs[i].index, ctx);
+ index = subs[i].index;
+ value = nxt_var_cache_value(task, state, cache, &ref[index], ctx);
if (nxt_slow_path(value == NULL)) {
return NXT_ERROR;
}
@@ -558,3 +571,18 @@ nxt_var_interpreter(nxt_task_t *task, nxt_tstr_state_t *state,
return NXT_OK;
}
+
+
+nxt_str_t *
+nxt_var_get(nxt_task_t *task, nxt_tstr_state_t *state, nxt_var_cache_t *cache,
+ nxt_str_t *name, void *ctx)
+{
+ nxt_var_ref_t *ref;
+
+ ref = nxt_var_ref_get(state, name, cache->pool);
+ if (nxt_slow_path(ref == NULL)) {
+ return NULL;
+ }
+
+ return nxt_var_cache_value(task, state, cache, ref, ctx);
+}
diff --git a/src/nxt_var.h b/src/nxt_var.h
index fde64f1e..08a92c08 100644
--- a/src/nxt_var.h
+++ b/src/nxt_var.h
@@ -59,10 +59,10 @@ nxt_int_t nxt_var_test(nxt_tstr_state_t *state, nxt_str_t *str, u_char *error);
nxt_int_t nxt_var_interpreter(nxt_task_t *task, nxt_tstr_state_t *state,
nxt_var_cache_t *cache, nxt_var_t *var, nxt_str_t *str, void *ctx,
nxt_bool_t logging);
-nxt_str_t *nxt_var_get(nxt_task_t *task, nxt_var_cache_t *cache,
- nxt_str_t *name, void *ctx);
+nxt_str_t *nxt_var_get(nxt_task_t *task, nxt_tstr_state_t *state,
+ nxt_var_cache_t *cache, nxt_str_t *name, void *ctx);
-nxt_int_t nxt_http_unknown_var_ref(nxt_tstr_state_t *state, nxt_var_ref_t *ref,
+nxt_int_t nxt_http_unknown_var_ref(nxt_mp_t *mp, nxt_var_ref_t *ref,
nxt_str_t *name);
diff --git a/src/python/nxt_python_asgi_http.c b/src/python/nxt_python_asgi_http.c
index 05c0da4f..cdd6357e 100644
--- a/src/python/nxt_python_asgi_http.c
+++ b/src/python/nxt_python_asgi_http.c
@@ -362,16 +362,6 @@ nxt_py_asgi_http_response_body(nxt_py_asgi_http_t *http, PyObject *dict)
Py_ssize_t body_len, body_off;
nxt_py_asgi_ctx_data_t *ctx_data;
- body = PyDict_GetItem(dict, nxt_py_body_str);
- if (nxt_slow_path(body != NULL && !PyBytes_Check(body))) {
- return PyErr_Format(PyExc_TypeError, "'body' is not a byte string");
- }
-
- more_body = PyDict_GetItem(dict, nxt_py_more_body_str);
- if (nxt_slow_path(more_body != NULL && !PyBool_Check(more_body))) {
- return PyErr_Format(PyExc_TypeError, "'more_body' is not a bool");
- }
-
if (nxt_slow_path(http->complete)) {
return PyErr_Format(PyExc_RuntimeError,
"Unexpected ASGI message 'http.response.body' "
@@ -382,9 +372,26 @@ nxt_py_asgi_http_response_body(nxt_py_asgi_http_t *http, PyObject *dict)
return PyErr_Format(PyExc_RuntimeError, "Concurrent send");
}
+ more_body = PyDict_GetItem(dict, nxt_py_more_body_str);
+ if (nxt_slow_path(more_body != NULL && !PyBool_Check(more_body))) {
+ return PyErr_Format(PyExc_TypeError, "'more_body' is not a bool");
+ }
+
+ body = PyDict_GetItem(dict, nxt_py_body_str);
+
if (body != NULL) {
- body_str = PyBytes_AS_STRING(body);
- body_len = PyBytes_GET_SIZE(body);
+ if (PyBytes_Check(body)) {
+ body_str = PyBytes_AS_STRING(body);
+ body_len = PyBytes_GET_SIZE(body);
+
+ } else if (PyByteArray_Check(body)) {
+ body_str = PyByteArray_AS_STRING(body);
+ body_len = PyByteArray_GET_SIZE(body);
+
+ } else {
+ return PyErr_Format(PyExc_TypeError,
+ "'body' is not a byte string or bytearray");
+ }
nxt_unit_req_debug(http->req, "asgi_http_response_body: %d, %d",
(int) body_len, (more_body == Py_True) );
diff --git a/src/python/nxt_python_wsgi.c b/src/python/nxt_python_wsgi.c
index dfb31509..c621097e 100644
--- a/src/python/nxt_python_wsgi.c
+++ b/src/python/nxt_python_wsgi.c
@@ -863,11 +863,38 @@ nxt_python_field_value(nxt_unit_field_t *f, int n, uint32_t vl)
char *p, *src;
PyObject *res;
+ src = nxt_unit_sptr_get(&f->value);
+
#if PY_MAJOR_VERSION == 3
- res = PyUnicode_New(vl, 255);
+ if (nxt_slow_path(n > 1)) {
+ char *ptr;
+
+ p = nxt_unit_malloc(NULL, vl + 1);
+ if (nxt_slow_path(p == NULL)) {
+ return NULL;
+ }
+
+ ptr = p;
+ p = nxt_cpymem(p, src, f->value_length);
+
+ for (i = 1; i < n; i++) {
+ p = nxt_cpymem(p, ", ", 2);
+
+ src = nxt_unit_sptr_get(&f[i].value);
+ p = nxt_cpymem(p, src, f[i].value_length);
+ }
+ *p = '\0';
+
+ src = ptr;
+ }
+
+ res = PyUnicode_DecodeCharmap(src, vl, NULL, NULL);
+
+ if (nxt_slow_path(n > 1)) {
+ nxt_unit_free(NULL, src);
+ }
#else
res = PyString_FromStringAndSize(NULL, vl);
-#endif
if (nxt_slow_path(res == NULL)) {
return NULL;
@@ -875,7 +902,6 @@ nxt_python_field_value(nxt_unit_field_t *f, int n, uint32_t vl)
p = PyString_AS_STRING(res);
- src = nxt_unit_sptr_get(&f->value);
p = nxt_cpymem(p, src, f->value_length);
for (i = 1; i < n; i++) {
@@ -884,6 +910,7 @@ nxt_python_field_value(nxt_unit_field_t *f, int n, uint32_t vl)
src = nxt_unit_sptr_get(&f[i].value);
p = nxt_cpymem(p, src, f[i].value_length);
}
+#endif
return res;
}
diff --git a/src/ruby/nxt_ruby.c b/src/ruby/nxt_ruby.c
index bcb48f6b..27b868fe 100644
--- a/src/ruby/nxt_ruby.c
+++ b/src/ruby/nxt_ruby.c
@@ -889,13 +889,41 @@ nxt_ruby_hash_info(VALUE r_key, VALUE r_value, VALUE arg)
goto fail;
}
- if (nxt_slow_path(TYPE(r_value) != T_STRING)) {
+ if (nxt_slow_path(TYPE(r_value) != T_STRING && TYPE(r_value) != T_ARRAY)) {
nxt_unit_req_error(headers_info->req,
"Ruby: Wrong header entry 'value' from application");
goto fail;
}
+ if (TYPE(r_value) == T_ARRAY) {
+ int i;
+ int arr_len = RARRAY_LEN(r_value);
+ VALUE item;
+ size_t len = 0;
+
+ for (i = 0; i < arr_len; i++) {
+ item = rb_ary_entry(r_value, i);
+ if (TYPE(item) != T_STRING) {
+ nxt_unit_req_error(headers_info->req,
+ "Ruby: Wrong header entry in 'value' array "
+ "from application");
+ goto fail;
+ }
+
+ len += RSTRING_LEN(item) + 2; /* +2 for '; ' */
+ }
+
+ if (arr_len > 0) {
+ len -= 2;
+ }
+
+ headers_info->fields++;
+ headers_info->size += RSTRING_LEN(r_key) + len;
+
+ return ST_CONTINUE;
+ }
+
value = RSTRING_PTR(r_value);
value_end = value + RSTRING_LEN(r_value);
@@ -941,11 +969,54 @@ nxt_ruby_hash_add(VALUE r_key, VALUE r_value, VALUE arg)
headers_info = (void *) (uintptr_t) arg;
rc = &headers_info->rc;
+ key_len = RSTRING_LEN(r_key);
+
+ if (TYPE(r_value) == T_ARRAY) {
+ int i;
+ int arr_len = RARRAY_LEN(r_value);
+ char *field, *p;
+ VALUE item;
+ size_t len = 0;
+
+ for (i = 0; i < arr_len; i++) {
+ item = rb_ary_entry(r_value, i);
+
+ len += RSTRING_LEN(item) + 2; /* +2 for '; ' */
+ }
+
+ field = nxt_unit_malloc(NULL, len);
+ if (field == NULL) {
+ goto fail;
+ }
+
+ p = field;
+
+ for (i = 0; i < arr_len; i++) {
+ item = rb_ary_entry(r_value, i);
+
+ p = nxt_cpymem(p, RSTRING_PTR(item), RSTRING_LEN(item));
+ p = nxt_cpymem(p, "; ", 2);
+ }
+
+ if (arr_len > 0) {
+ len -= 2;
+ }
+
+ *rc = nxt_unit_response_add_field(headers_info->req,
+ RSTRING_PTR(r_key), key_len,
+ field, len);
+ nxt_unit_free(NULL, field);
+
+ if (nxt_slow_path(*rc != NXT_UNIT_OK)) {
+ goto fail;
+ }
+
+ return ST_CONTINUE;
+ }
+
value = RSTRING_PTR(r_value);
value_end = value + RSTRING_LEN(r_value);
- key_len = RSTRING_LEN(r_key);
-
pos = value;
for ( ;; ) {
diff --git a/src/test/nxt_rbtree1.c b/src/test/nxt_rbtree1.c
index 1ae059ab..ec024858 100644
--- a/src/test/nxt_rbtree1.c
+++ b/src/test/nxt_rbtree1.c
@@ -1,7 +1,7 @@
/*
* Copyright (C) Igor Sysoev
- * Copyright (C) Nginx, Inc.
+ * Copyright (C) NGINX, Inc.
*/
diff --git a/src/test/nxt_rbtree1.h b/src/test/nxt_rbtree1.h
index 60048dad..d6230ab0 100644
--- a/src/test/nxt_rbtree1.h
+++ b/src/test/nxt_rbtree1.h
@@ -1,7 +1,7 @@
/*
* Copyright (C) Igor Sysoev
- * Copyright (C) Nginx, Inc.
+ * Copyright (C) NGINX, Inc.
*/
diff --git a/src/wasm-wasi-component/.gitignore b/src/wasm-wasi-component/.gitignore
new file mode 100644
index 00000000..eb5a316c
--- /dev/null
+++ b/src/wasm-wasi-component/.gitignore
@@ -0,0 +1 @@
+target
diff --git a/src/wasm-wasi-component/Cargo.lock b/src/wasm-wasi-component/Cargo.lock
new file mode 100644
index 00000000..bc09e96a
--- /dev/null
+++ b/src/wasm-wasi-component/Cargo.lock
@@ -0,0 +1,2293 @@
+# This file is automatically @generated by Cargo.
+# It is not intended for manual editing.
+version = 3
+
+[[package]]
+name = "addr2line"
+version = "0.21.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8a30b2e23b9e17a9f90641c7ab1549cd9b44f296d3ccbf309d2863cfe398a0cb"
+dependencies = [
+ "gimli",
+]
+
+[[package]]
+name = "adler"
+version = "1.0.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe"
+
+[[package]]
+name = "ahash"
+version = "0.8.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "77c3a9648d43b9cd48db467b3f87fdd6e146bcc88ab0180006cef2179fe11d01"
+dependencies = [
+ "cfg-if",
+ "once_cell",
+ "version_check",
+ "zerocopy",
+]
+
+[[package]]
+name = "aho-corasick"
+version = "1.1.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b2969dcb958b36655471fc61f7e416fa76033bdd4bfed0678d8fee1e2d07a1f0"
+dependencies = [
+ "memchr",
+]
+
+[[package]]
+name = "ambient-authority"
+version = "0.0.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e9d4ee0d472d1cd2e28c97dfa124b3d8d992e10eb0a035f33f5d12e3a177ba3b"
+
+[[package]]
+name = "android_system_properties"
+version = "0.1.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "819e7219dbd41043ac279b19830f2efc897156490d7fd6ea916720117ee66311"
+dependencies = [
+ "libc",
+]
+
+[[package]]
+name = "anyhow"
+version = "1.0.79"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "080e9890a082662b09c1ad45f567faeeb47f22b5fb23895fbe1e651e718e25ca"
+
+[[package]]
+name = "arbitrary"
+version = "1.3.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7d5a26814d8dcb93b0e5a0ff3c6d80a8843bafb21b39e8e18a6f05471870e110"
+
+[[package]]
+name = "async-trait"
+version = "0.1.77"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c980ee35e870bd1a4d2c8294d4c04d0499e67bca1e4b5cefcc693c2fa00caea9"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn",
+]
+
+[[package]]
+name = "autocfg"
+version = "1.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa"
+
+[[package]]
+name = "backtrace"
+version = "0.3.69"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2089b7e3f35b9dd2d0ed921ead4f6d318c27680d4a5bd167b3ee120edb105837"
+dependencies = [
+ "addr2line",
+ "cc",
+ "cfg-if",
+ "libc",
+ "miniz_oxide",
+ "object",
+ "rustc-demangle",
+]
+
+[[package]]
+name = "bincode"
+version = "1.3.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b1f45e9417d87227c7a56d22e471c6206462cba514c7590c09aff4cf6d1ddcad"
+dependencies = [
+ "serde",
+]
+
+[[package]]
+name = "bindgen"
+version = "0.68.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "726e4313eb6ec35d2730258ad4e15b547ee75d6afaa1361a922e78e59b7d8078"
+dependencies = [
+ "bitflags 2.4.2",
+ "cexpr",
+ "clang-sys",
+ "lazy_static",
+ "lazycell",
+ "log",
+ "peeking_take_while",
+ "prettyplease",
+ "proc-macro2",
+ "quote",
+ "regex",
+ "rustc-hash",
+ "shlex",
+ "syn",
+ "which",
+]
+
+[[package]]
+name = "bitflags"
+version = "1.3.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
+
+[[package]]
+name = "bitflags"
+version = "2.4.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ed570934406eb16438a4e976b1b4500774099c13b8cb96eec99f620f05090ddf"
+
+[[package]]
+name = "bumpalo"
+version = "3.14.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7f30e7476521f6f8af1a1c4c0b8cc94f0bee37d91763d0ca2665f299b6cd8aec"
+
+[[package]]
+name = "bytes"
+version = "1.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a2bd12c1caf447e69cd4528f47f94d203fd2582878ecb9e9465484c4148a8223"
+
+[[package]]
+name = "cap-fs-ext"
+version = "2.0.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "88e341d15ac1029aadce600be764a1a1edafe40e03cde23285bc1d261b3a4866"
+dependencies = [
+ "cap-primitives",
+ "cap-std",
+ "io-lifetimes",
+ "windows-sys 0.52.0",
+]
+
+[[package]]
+name = "cap-net-ext"
+version = "2.0.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "434168fe6533055f0f4204039abe3ff6d7db338ef46872a5fa39e9d5ad5ab7a9"
+dependencies = [
+ "cap-primitives",
+ "cap-std",
+ "rustix",
+ "smallvec",
+]
+
+[[package]]
+name = "cap-primitives"
+version = "2.0.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "fe16767ed8eee6d3f1f00d6a7576b81c226ab917eb54b96e5f77a5216ef67abb"
+dependencies = [
+ "ambient-authority",
+ "fs-set-times",
+ "io-extras",
+ "io-lifetimes",
+ "ipnet",
+ "maybe-owned",
+ "rustix",
+ "windows-sys 0.52.0",
+ "winx",
+]
+
+[[package]]
+name = "cap-rand"
+version = "2.0.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "20e5695565f0cd7106bc3c7170323597540e772bb73e0be2cd2c662a0f8fa4ca"
+dependencies = [
+ "ambient-authority",
+ "rand",
+]
+
+[[package]]
+name = "cap-std"
+version = "2.0.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "593db20e4c51f62d3284bae7ee718849c3214f93a3b94ea1899ad85ba119d330"
+dependencies = [
+ "cap-primitives",
+ "io-extras",
+ "io-lifetimes",
+ "rustix",
+]
+
+[[package]]
+name = "cap-time-ext"
+version = "2.0.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "03261630f291f425430a36f38c847828265bc928f517cdd2004c56f4b02f002b"
+dependencies = [
+ "ambient-authority",
+ "cap-primitives",
+ "iana-time-zone",
+ "once_cell",
+ "rustix",
+ "winx",
+]
+
+[[package]]
+name = "cc"
+version = "1.0.83"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f1174fb0b6ec23863f8b971027804a42614e347eafb0a95bf0b12cdae21fc4d0"
+dependencies = [
+ "libc",
+]
+
+[[package]]
+name = "cexpr"
+version = "0.6.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6fac387a98bb7c37292057cffc56d62ecb629900026402633ae9160df93a8766"
+dependencies = [
+ "nom",
+]
+
+[[package]]
+name = "cfg-if"
+version = "1.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
+
+[[package]]
+name = "clang-sys"
+version = "1.7.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "67523a3b4be3ce1989d607a828d036249522dd9c1c8de7f4dd2dae43a37369d1"
+dependencies = [
+ "glob",
+ "libc",
+ "libloading",
+]
+
+[[package]]
+name = "core-foundation-sys"
+version = "0.8.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "06ea2b9bc92be3c2baa9334a323ebca2d6f074ff852cd1d7b11064035cd3868f"
+
+[[package]]
+name = "cranelift-bforest"
+version = "0.104.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d819feeda4c420a18f1e28236ca0ce1177b22bf7c8a44ddee92dfe40de15bcf0"
+dependencies = [
+ "cranelift-entity",
+]
+
+[[package]]
+name = "cranelift-codegen"
+version = "0.104.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e9b8d03d5bdbca7e5f72b0e0a0f69933ed1f09e24be6c075aa6fe3f802b0cc0c"
+dependencies = [
+ "bumpalo",
+ "cranelift-bforest",
+ "cranelift-codegen-meta",
+ "cranelift-codegen-shared",
+ "cranelift-control",
+ "cranelift-entity",
+ "cranelift-isle",
+ "gimli",
+ "hashbrown 0.14.3",
+ "log",
+ "regalloc2",
+ "smallvec",
+ "target-lexicon",
+]
+
+[[package]]
+name = "cranelift-codegen-meta"
+version = "0.104.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a3fd3664e38e51649b17dc30cfdd561273fe2f590dcd013fb75d9eabc6272dfb"
+dependencies = [
+ "cranelift-codegen-shared",
+]
+
+[[package]]
+name = "cranelift-codegen-shared"
+version = "0.104.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4b031ec5e605828975952622b5a77d49126f20ffe88d33719a0af66b23a0fc36"
+
+[[package]]
+name = "cranelift-control"
+version = "0.104.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "fada054d017cf2ed8f7ed2336e0517fc1b19e6825be1790de9eb00c94788362b"
+dependencies = [
+ "arbitrary",
+]
+
+[[package]]
+name = "cranelift-entity"
+version = "0.104.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "177b6f94ae8de6348eb45bf977c79ab9e3c40fc3ac8cb7ed8109560ea39bee7d"
+dependencies = [
+ "serde",
+ "serde_derive",
+]
+
+[[package]]
+name = "cranelift-frontend"
+version = "0.104.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ebebd23a69a23e3ddea78e98ff3a2de222e88c8e045d81ef4a72f042e0d79dbd"
+dependencies = [
+ "cranelift-codegen",
+ "log",
+ "smallvec",
+ "target-lexicon",
+]
+
+[[package]]
+name = "cranelift-isle"
+version = "0.104.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1571bfc14df8966d12c6121b5325026591a4b4009e22fea0fe3765ab7cd33b96"
+
+[[package]]
+name = "cranelift-native"
+version = "0.104.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "35a69c37e0c10b46fe5527f2397ac821046efbf5f7ec112c8b84df25712f465b"
+dependencies = [
+ "cranelift-codegen",
+ "libc",
+ "target-lexicon",
+]
+
+[[package]]
+name = "cranelift-wasm"
+version = "0.104.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9b3fef8bbceb8cb56d3f1778b0418d75c5cf12ec571a35fc01eb41abb0227a25"
+dependencies = [
+ "cranelift-codegen",
+ "cranelift-entity",
+ "cranelift-frontend",
+ "itertools",
+ "log",
+ "smallvec",
+ "wasmparser 0.118.1",
+ "wasmtime-types",
+]
+
+[[package]]
+name = "crc32fast"
+version = "1.3.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b540bd8bc810d3885c6ea91e2018302f68baba2129ab3e88f32389ee9370880d"
+dependencies = [
+ "cfg-if",
+]
+
+[[package]]
+name = "dirs"
+version = "4.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ca3aa72a6f96ea37bbc5aa912f6788242832f75369bdfdadcb0e38423f100059"
+dependencies = [
+ "dirs-sys",
+]
+
+[[package]]
+name = "dirs-sys"
+version = "0.3.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1b1d1d91c932ef41c0f2663aa8b0ca0342d444d842c06914aa0a7e352d0bada6"
+dependencies = [
+ "libc",
+ "redox_users",
+ "winapi",
+]
+
+[[package]]
+name = "either"
+version = "1.9.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a26ae43d7bcc3b814de94796a5e736d4029efb0ee900c12e2d54c993ad1a1e07"
+
+[[package]]
+name = "encoding_rs"
+version = "0.8.33"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7268b386296a025e474d5140678f75d6de9493ae55a5d709eeb9dd08149945e1"
+dependencies = [
+ "cfg-if",
+]
+
+[[package]]
+name = "equivalent"
+version = "1.0.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5"
+
+[[package]]
+name = "errno"
+version = "0.3.8"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a258e46cdc063eb8519c00b9fc845fc47bcfca4130e2f08e88665ceda8474245"
+dependencies = [
+ "libc",
+ "windows-sys 0.52.0",
+]
+
+[[package]]
+name = "fallible-iterator"
+version = "0.3.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2acce4a10f12dc2fb14a218589d4f1f62ef011b2d0cc4b3cb1bba8e94da14649"
+
+[[package]]
+name = "fd-lock"
+version = "4.0.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7e5768da2206272c81ef0b5e951a41862938a6070da63bcea197899942d3b947"
+dependencies = [
+ "cfg-if",
+ "rustix",
+ "windows-sys 0.52.0",
+]
+
+[[package]]
+name = "fnv"
+version = "1.0.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1"
+
+[[package]]
+name = "form_urlencoded"
+version = "1.2.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e13624c2627564efccf4934284bdd98cbaa14e79b0b5a141218e507b3a823456"
+dependencies = [
+ "percent-encoding",
+]
+
+[[package]]
+name = "fs-set-times"
+version = "0.20.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "033b337d725b97690d86893f9de22b67b80dcc4e9ad815f348254c38119db8fb"
+dependencies = [
+ "io-lifetimes",
+ "rustix",
+ "windows-sys 0.52.0",
+]
+
+[[package]]
+name = "futures"
+version = "0.3.30"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "645c6916888f6cb6350d2550b80fb63e734897a8498abe35cfb732b6487804b0"
+dependencies = [
+ "futures-channel",
+ "futures-core",
+ "futures-io",
+ "futures-sink",
+ "futures-task",
+ "futures-util",
+]
+
+[[package]]
+name = "futures-channel"
+version = "0.3.30"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "eac8f7d7865dcb88bd4373ab671c8cf4508703796caa2b1985a9ca867b3fcb78"
+dependencies = [
+ "futures-core",
+ "futures-sink",
+]
+
+[[package]]
+name = "futures-core"
+version = "0.3.30"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "dfc6580bb841c5a68e9ef15c77ccc837b40a7504914d52e47b8b0e9bbda25a1d"
+
+[[package]]
+name = "futures-io"
+version = "0.3.30"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a44623e20b9681a318efdd71c299b6b222ed6f231972bfe2f224ebad6311f0c1"
+
+[[package]]
+name = "futures-sink"
+version = "0.3.30"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9fb8e00e87438d937621c1c6269e53f536c14d3fbd6a042bb24879e57d474fb5"
+
+[[package]]
+name = "futures-task"
+version = "0.3.30"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "38d84fa142264698cdce1a9f9172cf383a0c82de1bddcf3092901442c4097004"
+
+[[package]]
+name = "futures-util"
+version = "0.3.30"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3d6401deb83407ab3da39eba7e33987a73c3df0c82b4bb5813ee871c19c41d48"
+dependencies = [
+ "futures-core",
+ "futures-sink",
+ "futures-task",
+ "pin-project-lite",
+ "pin-utils",
+]
+
+[[package]]
+name = "getrandom"
+version = "0.2.12"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "190092ea657667030ac6a35e305e62fc4dd69fd98ac98631e5d3a2b1575a12b5"
+dependencies = [
+ "cfg-if",
+ "libc",
+ "wasi",
+]
+
+[[package]]
+name = "gimli"
+version = "0.28.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4271d37baee1b8c7e4b708028c57d816cf9d2434acb33a549475f78c181f6253"
+dependencies = [
+ "fallible-iterator",
+ "indexmap",
+ "stable_deref_trait",
+]
+
+[[package]]
+name = "glob"
+version = "0.3.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d2fabcfbdc87f4758337ca535fb41a6d701b65693ce38287d856d1674551ec9b"
+
+[[package]]
+name = "h2"
+version = "0.4.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "31d030e59af851932b72ceebadf4a2b5986dba4c3b99dd2493f8273a0f151943"
+dependencies = [
+ "bytes",
+ "fnv",
+ "futures-core",
+ "futures-sink",
+ "futures-util",
+ "http",
+ "indexmap",
+ "slab",
+ "tokio",
+ "tokio-util",
+ "tracing",
+]
+
+[[package]]
+name = "hashbrown"
+version = "0.13.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "43a3c133739dddd0d2990f9a4bdf8eb4b21ef50e4851ca85ab661199821d510e"
+dependencies = [
+ "ahash",
+]
+
+[[package]]
+name = "hashbrown"
+version = "0.14.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "290f1a1d9242c78d09ce40a5e87e7554ee637af1351968159f4952f028f75604"
+dependencies = [
+ "ahash",
+]
+
+[[package]]
+name = "heck"
+version = "0.4.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8"
+
+[[package]]
+name = "hermit-abi"
+version = "0.3.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d0c62115964e08cb8039170eb33c1d0e2388a256930279edca206fff675f82c3"
+
+[[package]]
+name = "home"
+version = "0.5.9"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e3d1354bf6b7235cb4a0576c2619fd4ed18183f689b12b006a0ee7329eeff9a5"
+dependencies = [
+ "windows-sys 0.52.0",
+]
+
+[[package]]
+name = "http"
+version = "1.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b32afd38673a8016f7c9ae69e5af41a58f81b1d31689040f2f1959594ce194ea"
+dependencies = [
+ "bytes",
+ "fnv",
+ "itoa",
+]
+
+[[package]]
+name = "http-body"
+version = "1.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1cac85db508abc24a2e48553ba12a996e87244a0395ce011e62b37158745d643"
+dependencies = [
+ "bytes",
+ "http",
+]
+
+[[package]]
+name = "http-body-util"
+version = "0.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "41cb79eb393015dadd30fc252023adb0b2400a0caee0fa2a077e6e21a551e840"
+dependencies = [
+ "bytes",
+ "futures-util",
+ "http",
+ "http-body",
+ "pin-project-lite",
+]
+
+[[package]]
+name = "httparse"
+version = "1.8.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d897f394bad6a705d5f4104762e116a75639e470d80901eed05a860a95cb1904"
+
+[[package]]
+name = "httpdate"
+version = "1.0.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9"
+
+[[package]]
+name = "hyper"
+version = "1.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "fb5aa53871fc917b1a9ed87b683a5d86db645e23acb32c2e0785a353e522fb75"
+dependencies = [
+ "bytes",
+ "futures-channel",
+ "futures-util",
+ "h2",
+ "http",
+ "http-body",
+ "httparse",
+ "httpdate",
+ "itoa",
+ "pin-project-lite",
+ "tokio",
+ "want",
+]
+
+[[package]]
+name = "iana-time-zone"
+version = "0.1.60"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e7ffbb5a1b541ea2561f8c41c087286cc091e21e556a4f09a8f6cbf17b69b141"
+dependencies = [
+ "android_system_properties",
+ "core-foundation-sys",
+ "iana-time-zone-haiku",
+ "js-sys",
+ "wasm-bindgen",
+ "windows-core",
+]
+
+[[package]]
+name = "iana-time-zone-haiku"
+version = "0.1.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f31827a206f56af32e590ba56d5d2d085f558508192593743f16b2306495269f"
+dependencies = [
+ "cc",
+]
+
+[[package]]
+name = "id-arena"
+version = "2.2.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "25a2bc672d1148e28034f176e01fffebb08b35768468cc954630da77a1449005"
+
+[[package]]
+name = "idna"
+version = "0.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "634d9b1461af396cad843f47fdba5597a4f9e6ddd4bfb6ff5d85028c25cb12f6"
+dependencies = [
+ "unicode-bidi",
+ "unicode-normalization",
+]
+
+[[package]]
+name = "indexmap"
+version = "2.2.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "824b2ae422412366ba479e8111fd301f7b5faece8149317bb81925979a53f520"
+dependencies = [
+ "equivalent",
+ "hashbrown 0.14.3",
+ "serde",
+]
+
+[[package]]
+name = "io-extras"
+version = "0.18.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c301e73fb90e8a29e600a9f402d095765f74310d582916a952f618836a1bd1ed"
+dependencies = [
+ "io-lifetimes",
+ "windows-sys 0.52.0",
+]
+
+[[package]]
+name = "io-lifetimes"
+version = "2.0.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5a611371471e98973dbcab4e0ec66c31a10bc356eeb4d54a0e05eac8158fe38c"
+
+[[package]]
+name = "ipnet"
+version = "2.9.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8f518f335dce6725a761382244631d86cf0ccb2863413590b31338feb467f9c3"
+
+[[package]]
+name = "itertools"
+version = "0.10.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b0fd2260e829bddf4cb6ea802289de2f86d6a7a690192fbe91b3f46e0f2c8473"
+dependencies = [
+ "either",
+]
+
+[[package]]
+name = "itoa"
+version = "1.0.10"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b1a46d1a171d865aa5f83f92695765caa047a9b4cbae2cbf37dbd613a793fd4c"
+
+[[package]]
+name = "js-sys"
+version = "0.3.67"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9a1d36f1235bc969acba30b7f5990b864423a6068a10f7c90ae8f0112e3a59d1"
+dependencies = [
+ "wasm-bindgen",
+]
+
+[[package]]
+name = "lazy_static"
+version = "1.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
+
+[[package]]
+name = "lazycell"
+version = "1.3.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "830d08ce1d1d941e6b30645f1a0eb5643013d835ce3779a5fc208261dbe10f55"
+
+[[package]]
+name = "leb128"
+version = "0.2.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "884e2677b40cc8c339eaefcb701c32ef1fd2493d71118dc0ca4b6a736c93bd67"
+
+[[package]]
+name = "libc"
+version = "0.2.153"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9c198f91728a82281a64e1f4f9eeb25d82cb32a5de251c6bd1b5154d63a8e7bd"
+
+[[package]]
+name = "libloading"
+version = "0.8.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c571b676ddfc9a8c12f1f3d3085a7b163966a8fd8098a90640953ce5f6170161"
+dependencies = [
+ "cfg-if",
+ "windows-sys 0.48.0",
+]
+
+[[package]]
+name = "libredox"
+version = "0.0.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "85c833ca1e66078851dba29046874e38f08b2c883700aa29a03ddd3b23814ee8"
+dependencies = [
+ "bitflags 2.4.2",
+ "libc",
+ "redox_syscall",
+]
+
+[[package]]
+name = "linux-raw-sys"
+version = "0.4.13"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "01cda141df6706de531b6c46c3a33ecca755538219bd484262fa09410c13539c"
+
+[[package]]
+name = "log"
+version = "0.4.20"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b5e6163cb8c49088c2c36f57875e58ccd8c87c7427f7fbd50ea6710b2f3f2e8f"
+
+[[package]]
+name = "mach"
+version = "0.3.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b823e83b2affd8f40a9ee8c29dbc56404c1e34cd2710921f2801e2cf29527afa"
+dependencies = [
+ "libc",
+]
+
+[[package]]
+name = "maybe-owned"
+version = "0.3.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4facc753ae494aeb6e3c22f839b158aebd4f9270f55cd3c79906c45476c47ab4"
+
+[[package]]
+name = "memchr"
+version = "2.7.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "523dc4f511e55ab87b694dc30d0f820d60906ef06413f93d4d7a1385599cc149"
+
+[[package]]
+name = "memfd"
+version = "0.6.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b2cffa4ad52c6f791f4f8b15f0c05f9824b2ced1160e88cc393d64fff9a8ac64"
+dependencies = [
+ "rustix",
+]
+
+[[package]]
+name = "memoffset"
+version = "0.9.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5a634b1c61a95585bd15607c6ab0c4e5b226e695ff2800ba0cdccddf208c406c"
+dependencies = [
+ "autocfg",
+]
+
+[[package]]
+name = "minimal-lexical"
+version = "0.2.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a"
+
+[[package]]
+name = "miniz_oxide"
+version = "0.7.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9d811f3e15f28568be3407c8e7fdb6514c1cda3cb30683f15b6a1a1dc4ea14a7"
+dependencies = [
+ "adler",
+]
+
+[[package]]
+name = "mio"
+version = "0.8.10"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8f3d0b296e374a4e6f3c7b0a1f5a51d748a0d34c85e7dc48fc3fa9a87657fe09"
+dependencies = [
+ "libc",
+ "wasi",
+ "windows-sys 0.48.0",
+]
+
+[[package]]
+name = "nom"
+version = "7.1.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d273983c5a657a70a3e8f2a01329822f3b8c8172b73826411a55751e404a0a4a"
+dependencies = [
+ "memchr",
+ "minimal-lexical",
+]
+
+[[package]]
+name = "num_cpus"
+version = "1.16.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4161fcb6d602d4d2081af7c3a45852d875a03dd337a6bfdd6e06407b61342a43"
+dependencies = [
+ "hermit-abi",
+ "libc",
+]
+
+[[package]]
+name = "object"
+version = "0.32.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a6a622008b6e321afc04970976f62ee297fdbaa6f95318ca343e3eebb9648441"
+dependencies = [
+ "crc32fast",
+ "hashbrown 0.14.3",
+ "indexmap",
+ "memchr",
+]
+
+[[package]]
+name = "once_cell"
+version = "1.19.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92"
+
+[[package]]
+name = "paste"
+version = "1.0.14"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "de3145af08024dea9fa9914f381a17b8fc6034dfb00f3a84013f7ff43f29ed4c"
+
+[[package]]
+name = "peeking_take_while"
+version = "0.1.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "19b17cddbe7ec3f8bc800887bab5e717348c95ea2ca0b1bf0837fb964dc67099"
+
+[[package]]
+name = "percent-encoding"
+version = "2.3.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e"
+
+[[package]]
+name = "pin-project-lite"
+version = "0.2.13"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8afb450f006bf6385ca15ef45d71d2288452bc3683ce2e2cacc0d18e4be60b58"
+
+[[package]]
+name = "pin-utils"
+version = "0.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184"
+
+[[package]]
+name = "ppv-lite86"
+version = "0.2.17"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de"
+
+[[package]]
+name = "prettyplease"
+version = "0.2.16"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a41cf62165e97c7f814d2221421dbb9afcbcdb0a88068e5ea206e19951c2cbb5"
+dependencies = [
+ "proc-macro2",
+ "syn",
+]
+
+[[package]]
+name = "proc-macro2"
+version = "1.0.78"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e2422ad645d89c99f8f3e6b88a9fdeca7fabeac836b1002371c4367c8f984aae"
+dependencies = [
+ "unicode-ident",
+]
+
+[[package]]
+name = "psm"
+version = "0.1.21"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5787f7cda34e3033a72192c018bc5883100330f362ef279a8cbccfce8bb4e874"
+dependencies = [
+ "cc",
+]
+
+[[package]]
+name = "quote"
+version = "1.0.35"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "291ec9ab5efd934aaf503a6466c5d5251535d108ee747472c3977cc5acc868ef"
+dependencies = [
+ "proc-macro2",
+]
+
+[[package]]
+name = "rand"
+version = "0.8.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404"
+dependencies = [
+ "libc",
+ "rand_chacha",
+ "rand_core",
+]
+
+[[package]]
+name = "rand_chacha"
+version = "0.3.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88"
+dependencies = [
+ "ppv-lite86",
+ "rand_core",
+]
+
+[[package]]
+name = "rand_core"
+version = "0.6.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c"
+dependencies = [
+ "getrandom",
+]
+
+[[package]]
+name = "redox_syscall"
+version = "0.4.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4722d768eff46b75989dd134e5c353f0d6296e5aaa3132e776cbdb56be7731aa"
+dependencies = [
+ "bitflags 1.3.2",
+]
+
+[[package]]
+name = "redox_users"
+version = "0.4.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a18479200779601e498ada4e8c1e1f50e3ee19deb0259c25825a98b5603b2cb4"
+dependencies = [
+ "getrandom",
+ "libredox",
+ "thiserror",
+]
+
+[[package]]
+name = "regalloc2"
+version = "0.9.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ad156d539c879b7a24a363a2016d77961786e71f48f2e2fc8302a92abd2429a6"
+dependencies = [
+ "hashbrown 0.13.2",
+ "log",
+ "rustc-hash",
+ "slice-group-by",
+ "smallvec",
+]
+
+[[package]]
+name = "regex"
+version = "1.10.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b62dbe01f0b06f9d8dc7d49e05a0785f153b00b2c227856282f671e0318c9b15"
+dependencies = [
+ "aho-corasick",
+ "memchr",
+ "regex-automata",
+ "regex-syntax",
+]
+
+[[package]]
+name = "regex-automata"
+version = "0.4.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5bb987efffd3c6d0d8f5f89510bb458559eab11e4f869acb20bf845e016259cd"
+dependencies = [
+ "aho-corasick",
+ "memchr",
+ "regex-syntax",
+]
+
+[[package]]
+name = "regex-syntax"
+version = "0.8.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c08c74e62047bb2de4ff487b251e4a92e24f48745648451635cec7d591162d9f"
+
+[[package]]
+name = "ring"
+version = "0.17.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "688c63d65483050968b2a8937f7995f443e27041a0f7700aa59b0822aedebb74"
+dependencies = [
+ "cc",
+ "getrandom",
+ "libc",
+ "spin",
+ "untrusted",
+ "windows-sys 0.48.0",
+]
+
+[[package]]
+name = "rustc-demangle"
+version = "0.1.23"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d626bb9dae77e28219937af045c257c28bfd3f69333c512553507f5f9798cb76"
+
+[[package]]
+name = "rustc-hash"
+version = "1.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2"
+
+[[package]]
+name = "rustix"
+version = "0.38.31"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6ea3e1a662af26cd7a3ba09c0297a31af215563ecf42817c98df621387f4e949"
+dependencies = [
+ "bitflags 2.4.2",
+ "errno",
+ "itoa",
+ "libc",
+ "linux-raw-sys",
+ "once_cell",
+ "windows-sys 0.52.0",
+]
+
+[[package]]
+name = "rustls"
+version = "0.21.10"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f9d5a6813c0759e4609cd494e8e725babae6a2ca7b62a5536a13daaec6fcb7ba"
+dependencies = [
+ "log",
+ "ring",
+ "rustls-webpki",
+ "sct",
+]
+
+[[package]]
+name = "rustls-webpki"
+version = "0.101.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8b6275d1ee7a1cd780b64aca7726599a1dbc893b1e64144529e55c3c2f745765"
+dependencies = [
+ "ring",
+ "untrusted",
+]
+
+[[package]]
+name = "ryu"
+version = "1.0.16"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f98d2aa92eebf49b69786be48e4477826b256916e84a57ff2a4f21923b48eb4c"
+
+[[package]]
+name = "sct"
+version = "0.7.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "da046153aa2352493d6cb7da4b6e5c0c057d8a1d0a9aa8560baffdd945acd414"
+dependencies = [
+ "ring",
+ "untrusted",
+]
+
+[[package]]
+name = "semver"
+version = "1.0.21"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b97ed7a9823b74f99c7742f5336af7be5ecd3eeafcb1507d1fa93347b1d589b0"
+
+[[package]]
+name = "serde"
+version = "1.0.196"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "870026e60fa08c69f064aa766c10f10b1d62db9ccd4d0abb206472bee0ce3b32"
+dependencies = [
+ "serde_derive",
+]
+
+[[package]]
+name = "serde_derive"
+version = "1.0.196"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "33c85360c95e7d137454dc81d9a4ed2b8efd8fbe19cee57357b32b9771fccb67"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn",
+]
+
+[[package]]
+name = "serde_json"
+version = "1.0.113"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "69801b70b1c3dac963ecb03a364ba0ceda9cf60c71cfe475e99864759c8b8a79"
+dependencies = [
+ "itoa",
+ "ryu",
+ "serde",
+]
+
+[[package]]
+name = "shellexpand"
+version = "2.1.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7ccc8076840c4da029af4f87e4e8daeb0fca6b87bbb02e10cb60b791450e11e4"
+dependencies = [
+ "dirs",
+]
+
+[[package]]
+name = "shlex"
+version = "1.3.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64"
+
+[[package]]
+name = "slab"
+version = "0.4.9"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8f92a496fb766b417c996b9c5e57daf2f7ad3b0bebe1ccfca4856390e3d3bb67"
+dependencies = [
+ "autocfg",
+]
+
+[[package]]
+name = "slice-group-by"
+version = "0.3.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "826167069c09b99d56f31e9ae5c99049e932a98c9dc2dac47645b08dbbf76ba7"
+
+[[package]]
+name = "smallvec"
+version = "1.13.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e6ecd384b10a64542d77071bd64bd7b231f4ed5940fba55e98c3de13824cf3d7"
+
+[[package]]
+name = "socket2"
+version = "0.5.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7b5fac59a5cb5dd637972e5fca70daf0523c9067fcdc4842f053dae04a18f8e9"
+dependencies = [
+ "libc",
+ "windows-sys 0.48.0",
+]
+
+[[package]]
+name = "spin"
+version = "0.9.8"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67"
+
+[[package]]
+name = "sptr"
+version = "0.3.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3b9b39299b249ad65f3b7e96443bad61c02ca5cd3589f46cb6d610a0fd6c0d6a"
+
+[[package]]
+name = "stable_deref_trait"
+version = "1.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3"
+
+[[package]]
+name = "syn"
+version = "2.0.48"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0f3531638e407dfc0814761abb7c00a5b54992b849452a0646b7f65c9f770f3f"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "unicode-ident",
+]
+
+[[package]]
+name = "system-interface"
+version = "0.26.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0682e006dd35771e392a6623ac180999a9a854b1d4a6c12fb2e804941c2b1f58"
+dependencies = [
+ "bitflags 2.4.2",
+ "cap-fs-ext",
+ "cap-std",
+ "fd-lock",
+ "io-lifetimes",
+ "rustix",
+ "windows-sys 0.52.0",
+ "winx",
+]
+
+[[package]]
+name = "target-lexicon"
+version = "0.12.13"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "69758bda2e78f098e4ccb393021a0963bb3442eac05f135c30f61b7370bbafae"
+
+[[package]]
+name = "thiserror"
+version = "1.0.56"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d54378c645627613241d077a3a79db965db602882668f9136ac42af9ecb730ad"
+dependencies = [
+ "thiserror-impl",
+]
+
+[[package]]
+name = "thiserror-impl"
+version = "1.0.56"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "fa0faa943b50f3db30a20aa7e265dbc66076993efed8463e8de414e5d06d3471"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn",
+]
+
+[[package]]
+name = "tinyvec"
+version = "1.6.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "87cc5ceb3875bb20c2890005a4e226a4651264a5c75edb2421b52861a0a0cb50"
+dependencies = [
+ "tinyvec_macros",
+]
+
+[[package]]
+name = "tinyvec_macros"
+version = "0.1.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20"
+
+[[package]]
+name = "tokio"
+version = "1.36.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "61285f6515fa018fb2d1e46eb21223fff441ee8db5d0f1435e8ab4f5cdb80931"
+dependencies = [
+ "backtrace",
+ "bytes",
+ "libc",
+ "mio",
+ "num_cpus",
+ "pin-project-lite",
+ "socket2",
+ "windows-sys 0.48.0",
+]
+
+[[package]]
+name = "tokio-rustls"
+version = "0.24.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c28327cf380ac148141087fbfb9de9d7bd4e84ab5d2c28fbc911d753de8a7081"
+dependencies = [
+ "rustls",
+ "tokio",
+]
+
+[[package]]
+name = "tokio-util"
+version = "0.7.10"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5419f34732d9eb6ee4c3578b7989078579b7f039cbbb9ca2c4da015749371e15"
+dependencies = [
+ "bytes",
+ "futures-core",
+ "futures-sink",
+ "pin-project-lite",
+ "tokio",
+ "tracing",
+]
+
+[[package]]
+name = "tracing"
+version = "0.1.40"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c3523ab5a71916ccf420eebdf5521fcef02141234bbc0b8a49f2fdc4544364ef"
+dependencies = [
+ "log",
+ "pin-project-lite",
+ "tracing-attributes",
+ "tracing-core",
+]
+
+[[package]]
+name = "tracing-attributes"
+version = "0.1.27"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn",
+]
+
+[[package]]
+name = "tracing-core"
+version = "0.1.32"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c06d3da6113f116aaee68e4d601191614c9053067f9ab7f6edbcb161237daa54"
+dependencies = [
+ "once_cell",
+]
+
+[[package]]
+name = "try-lock"
+version = "0.2.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b"
+
+[[package]]
+name = "unicode-bidi"
+version = "0.3.15"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "08f95100a766bf4f8f28f90d77e0a5461bbdb219042e7679bebe79004fed8d75"
+
+[[package]]
+name = "unicode-ident"
+version = "1.0.12"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b"
+
+[[package]]
+name = "unicode-normalization"
+version = "0.1.22"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5c5713f0fc4b5db668a2ac63cdb7bb4469d8c9fed047b1d0292cc7b0ce2ba921"
+dependencies = [
+ "tinyvec",
+]
+
+[[package]]
+name = "unicode-xid"
+version = "0.2.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f962df74c8c05a667b5ee8bcf162993134c104e96440b663c8daa176dc772d8c"
+
+[[package]]
+name = "untrusted"
+version = "0.9.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1"
+
+[[package]]
+name = "url"
+version = "2.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "31e6302e3bb753d46e83516cae55ae196fc0c309407cf11ab35cc51a4c2a4633"
+dependencies = [
+ "form_urlencoded",
+ "idna",
+ "percent-encoding",
+]
+
+[[package]]
+name = "version_check"
+version = "0.9.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f"
+
+[[package]]
+name = "want"
+version = "0.3.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "bfa7760aed19e106de2c7c0b581b509f2f25d3dacaf737cb82ac61bc6d760b0e"
+dependencies = [
+ "try-lock",
+]
+
+[[package]]
+name = "wasi"
+version = "0.11.0+wasi-snapshot-preview1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423"
+
+[[package]]
+name = "wasi-cap-std-sync"
+version = "17.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "db014d2ced91f17d1f1a8f2b76d6ea8d731bc1dbc8c2bbaec689d6a242568e5d"
+dependencies = [
+ "anyhow",
+ "async-trait",
+ "cap-fs-ext",
+ "cap-rand",
+ "cap-std",
+ "cap-time-ext",
+ "fs-set-times",
+ "io-extras",
+ "io-lifetimes",
+ "once_cell",
+ "rustix",
+ "system-interface",
+ "tracing",
+ "wasi-common",
+ "windows-sys 0.52.0",
+]
+
+[[package]]
+name = "wasi-common"
+version = "17.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "449d17849e3c83a931374442fe2deee4d6bd1ebf469719ef44192e9e82e19c89"
+dependencies = [
+ "anyhow",
+ "bitflags 2.4.2",
+ "cap-rand",
+ "cap-std",
+ "io-extras",
+ "log",
+ "rustix",
+ "thiserror",
+ "tracing",
+ "wasmtime",
+ "wiggle",
+ "windows-sys 0.52.0",
+]
+
+[[package]]
+name = "wasm-bindgen"
+version = "0.2.90"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b1223296a201415c7fad14792dbefaace9bd52b62d33453ade1c5b5f07555406"
+dependencies = [
+ "cfg-if",
+ "wasm-bindgen-macro",
+]
+
+[[package]]
+name = "wasm-bindgen-backend"
+version = "0.2.90"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "fcdc935b63408d58a32f8cc9738a0bffd8f05cc7c002086c6ef20b7312ad9dcd"
+dependencies = [
+ "bumpalo",
+ "log",
+ "once_cell",
+ "proc-macro2",
+ "quote",
+ "syn",
+ "wasm-bindgen-shared",
+]
+
+[[package]]
+name = "wasm-bindgen-macro"
+version = "0.2.90"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3e4c238561b2d428924c49815533a8b9121c664599558a5d9ec51f8a1740a999"
+dependencies = [
+ "quote",
+ "wasm-bindgen-macro-support",
+]
+
+[[package]]
+name = "wasm-bindgen-macro-support"
+version = "0.2.90"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "bae1abb6806dc1ad9e560ed242107c0f6c84335f1749dd4e8ddb012ebd5e25a7"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn",
+ "wasm-bindgen-backend",
+ "wasm-bindgen-shared",
+]
+
+[[package]]
+name = "wasm-bindgen-shared"
+version = "0.2.90"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4d91413b1c31d7539ba5ef2451af3f0b833a005eb27a631cec32bc0635a8602b"
+
+[[package]]
+name = "wasm-encoder"
+version = "0.38.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0ad2b51884de9c7f4fe2fd1043fccb8dcad4b1e29558146ee57a144d15779f3f"
+dependencies = [
+ "leb128",
+]
+
+[[package]]
+name = "wasm-wasi-component"
+version = "0.1.0"
+dependencies = [
+ "anyhow",
+ "bindgen",
+ "bytes",
+ "cc",
+ "futures-util",
+ "http",
+ "http-body",
+ "http-body-util",
+ "tokio",
+ "wasmtime",
+ "wasmtime-wasi",
+ "wasmtime-wasi-http",
+]
+
+[[package]]
+name = "wasmparser"
+version = "0.118.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "95ee9723b928e735d53000dec9eae7b07a60e490c85ab54abb66659fc61bfcd9"
+dependencies = [
+ "indexmap",
+ "semver",
+]
+
+[[package]]
+name = "wasmparser"
+version = "0.121.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "953cf6a7606ab31382cb1caa5ae403e77ba70c7f8e12eeda167e7040d42bfda8"
+dependencies = [
+ "bitflags 2.4.2",
+ "indexmap",
+ "semver",
+]
+
+[[package]]
+name = "wasmprinter"
+version = "0.2.78"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "05e32c13c59fdc64d3f6998a1d52eb1d362b6904a88b754190ccb85661ad577a"
+dependencies = [
+ "anyhow",
+ "wasmparser 0.121.0",
+]
+
+[[package]]
+name = "wasmtime"
+version = "17.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "910fabce77e660f0e0e41cfd5f69fc8bf020a025f059718846e918db7177f469"
+dependencies = [
+ "anyhow",
+ "async-trait",
+ "bincode",
+ "bumpalo",
+ "cfg-if",
+ "encoding_rs",
+ "indexmap",
+ "libc",
+ "log",
+ "object",
+ "once_cell",
+ "paste",
+ "serde",
+ "serde_derive",
+ "serde_json",
+ "target-lexicon",
+ "wasmparser 0.118.1",
+ "wasmtime-component-macro",
+ "wasmtime-component-util",
+ "wasmtime-cranelift",
+ "wasmtime-environ",
+ "wasmtime-fiber",
+ "wasmtime-jit",
+ "wasmtime-runtime",
+ "wasmtime-winch",
+ "windows-sys 0.52.0",
+]
+
+[[package]]
+name = "wasmtime-asm-macros"
+version = "17.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "37288142e9b4a61655a3bcbdc7316c2e4bb9e776b10ce3dd758f8186b4469572"
+dependencies = [
+ "cfg-if",
+]
+
+[[package]]
+name = "wasmtime-component-macro"
+version = "17.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ad63de18eb42e586386b6091f787c82707cbd5ac5e9343216dba1976190cd03a"
+dependencies = [
+ "anyhow",
+ "proc-macro2",
+ "quote",
+ "syn",
+ "wasmtime-component-util",
+ "wasmtime-wit-bindgen",
+ "wit-parser",
+]
+
+[[package]]
+name = "wasmtime-component-util"
+version = "17.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7e0a160c0c44369aa4bee6d311a8e4366943bab1651040cc8b0fcec2c9eb8906"
+
+[[package]]
+name = "wasmtime-cranelift"
+version = "17.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3734cc01b7cd37bc62fdbcd9529ca9547440052d4b3886cfdec3b8081a5d3647"
+dependencies = [
+ "anyhow",
+ "cfg-if",
+ "cranelift-codegen",
+ "cranelift-control",
+ "cranelift-entity",
+ "cranelift-frontend",
+ "cranelift-native",
+ "cranelift-wasm",
+ "gimli",
+ "log",
+ "object",
+ "target-lexicon",
+ "thiserror",
+ "wasmparser 0.118.1",
+ "wasmtime-cranelift-shared",
+ "wasmtime-environ",
+ "wasmtime-versioned-export-macros",
+]
+
+[[package]]
+name = "wasmtime-cranelift-shared"
+version = "17.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e0eb33cd30c47844aa228d4d0030587e65c1108343f311fe9f7248b5bd9cb65c"
+dependencies = [
+ "anyhow",
+ "cranelift-codegen",
+ "cranelift-control",
+ "cranelift-native",
+ "gimli",
+ "object",
+ "target-lexicon",
+ "wasmtime-environ",
+]
+
+[[package]]
+name = "wasmtime-environ"
+version = "17.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9a3a056b041fdea604f0972e2fae97958e7748d629a55180228348baefdfc217"
+dependencies = [
+ "anyhow",
+ "cranelift-entity",
+ "gimli",
+ "indexmap",
+ "log",
+ "object",
+ "serde",
+ "serde_derive",
+ "target-lexicon",
+ "thiserror",
+ "wasm-encoder",
+ "wasmparser 0.118.1",
+ "wasmprinter",
+ "wasmtime-component-util",
+ "wasmtime-types",
+]
+
+[[package]]
+name = "wasmtime-fiber"
+version = "17.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "43987d0977c07f15c3608c2f255870c127ffd19e35eeedb1ac1dccedf9932a42"
+dependencies = [
+ "anyhow",
+ "cc",
+ "cfg-if",
+ "rustix",
+ "wasmtime-asm-macros",
+ "wasmtime-versioned-export-macros",
+ "windows-sys 0.52.0",
+]
+
+[[package]]
+name = "wasmtime-jit"
+version = "17.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9b3e48395ac672b386ed588d97a9612aa13a345008f26466f0dfb2a91628aa9f"
+dependencies = [
+ "anyhow",
+ "bincode",
+ "cfg-if",
+ "gimli",
+ "log",
+ "object",
+ "rustix",
+ "serde",
+ "serde_derive",
+ "target-lexicon",
+ "wasmtime-environ",
+ "wasmtime-jit-icache-coherence",
+ "wasmtime-runtime",
+ "windows-sys 0.52.0",
+]
+
+[[package]]
+name = "wasmtime-jit-icache-coherence"
+version = "17.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "bdc26415bb89e9ccd3bdc498fef63aabf665c4c0dd710c107691deb9694955da"
+dependencies = [
+ "cfg-if",
+ "libc",
+ "windows-sys 0.52.0",
+]
+
+[[package]]
+name = "wasmtime-runtime"
+version = "17.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0abddaf17912aabaf39be0802d5eba9a002e956e902d1ebd438a2fe1c88769a2"
+dependencies = [
+ "anyhow",
+ "cc",
+ "cfg-if",
+ "encoding_rs",
+ "indexmap",
+ "libc",
+ "log",
+ "mach",
+ "memfd",
+ "memoffset",
+ "paste",
+ "psm",
+ "rustix",
+ "sptr",
+ "wasm-encoder",
+ "wasmtime-asm-macros",
+ "wasmtime-environ",
+ "wasmtime-fiber",
+ "wasmtime-versioned-export-macros",
+ "wasmtime-wmemcheck",
+ "windows-sys 0.52.0",
+]
+
+[[package]]
+name = "wasmtime-types"
+version = "17.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b35a95cdc1433729085beab42c0a5c742b431f25b17c40d7718e46df63d5ffc7"
+dependencies = [
+ "cranelift-entity",
+ "serde",
+ "serde_derive",
+ "thiserror",
+ "wasmparser 0.118.1",
+]
+
+[[package]]
+name = "wasmtime-versioned-export-macros"
+version = "17.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "fad322733fe67e45743784d8b1df452bcb54f581572a4f1a646a4332deecbcc2"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn",
+]
+
+[[package]]
+name = "wasmtime-wasi"
+version = "17.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "902cc299b73655c36679b77efdfce4bb5971992f1a4a8a436dd3809a6848ff0e"
+dependencies = [
+ "anyhow",
+ "async-trait",
+ "bitflags 2.4.2",
+ "bytes",
+ "cap-fs-ext",
+ "cap-net-ext",
+ "cap-rand",
+ "cap-std",
+ "cap-time-ext",
+ "fs-set-times",
+ "futures",
+ "io-extras",
+ "io-lifetimes",
+ "libc",
+ "log",
+ "once_cell",
+ "rustix",
+ "system-interface",
+ "thiserror",
+ "tokio",
+ "tracing",
+ "url",
+ "wasi-cap-std-sync",
+ "wasi-common",
+ "wasmtime",
+ "wiggle",
+ "windows-sys 0.52.0",
+]
+
+[[package]]
+name = "wasmtime-wasi-http"
+version = "17.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "151fc711fad35034b8a6df00a5bcd5a7b1acb89ca12c2407f564a36ebd382e26"
+dependencies = [
+ "anyhow",
+ "async-trait",
+ "bytes",
+ "futures",
+ "http",
+ "http-body",
+ "http-body-util",
+ "hyper",
+ "rustls",
+ "tokio",
+ "tokio-rustls",
+ "tracing",
+ "wasmtime",
+ "wasmtime-wasi",
+ "webpki-roots",
+]
+
+[[package]]
+name = "wasmtime-winch"
+version = "17.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9e63aeca929f84560eec52c5af43bf5d623b92683b0195d9fb06da8ed860e092"
+dependencies = [
+ "anyhow",
+ "cranelift-codegen",
+ "gimli",
+ "object",
+ "target-lexicon",
+ "wasmparser 0.118.1",
+ "wasmtime-cranelift-shared",
+ "wasmtime-environ",
+ "winch-codegen",
+]
+
+[[package]]
+name = "wasmtime-wit-bindgen"
+version = "17.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "41e5675998fdc74495afdd90ad2bd221206a258075b23048af0535a969b07893"
+dependencies = [
+ "anyhow",
+ "heck",
+ "indexmap",
+ "wit-parser",
+]
+
+[[package]]
+name = "wasmtime-wmemcheck"
+version = "17.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b20a19e10d8cb50b45412fb21192982b7ce85c0122dc33bb71f1813e25dc6e52"
+
+[[package]]
+name = "wast"
+version = "35.0.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2ef140f1b49946586078353a453a1d28ba90adfc54dde75710bc1931de204d68"
+dependencies = [
+ "leb128",
+]
+
+[[package]]
+name = "webpki-roots"
+version = "0.25.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5f20c57d8d7db6d3b86154206ae5d8fba62dd39573114de97c2cb0578251f8e1"
+
+[[package]]
+name = "which"
+version = "4.4.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "87ba24419a2078cd2b0f2ede2691b6c66d8e47836da3b6db8265ebad47afbfc7"
+dependencies = [
+ "either",
+ "home",
+ "once_cell",
+ "rustix",
+]
+
+[[package]]
+name = "wiggle"
+version = "17.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "737728db69a7657a5f6a7bac445c02d8564d603d62c46c95edf928554e67d072"
+dependencies = [
+ "anyhow",
+ "async-trait",
+ "bitflags 2.4.2",
+ "thiserror",
+ "tracing",
+ "wasmtime",
+ "wiggle-macro",
+]
+
+[[package]]
+name = "wiggle-generate"
+version = "17.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2460c7163b79ffefd9a564eaeab0a5b0e84bb91afdfeeb84d36f304ddbe08982"
+dependencies = [
+ "anyhow",
+ "heck",
+ "proc-macro2",
+ "quote",
+ "shellexpand",
+ "syn",
+ "witx",
+]
+
+[[package]]
+name = "wiggle-macro"
+version = "17.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "fa8d8412375ba8325d61fbae56dead51dabfaec85d620ce36427922fb9cece83"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn",
+ "wiggle-generate",
+]
+
+[[package]]
+name = "winapi"
+version = "0.3.9"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419"
+dependencies = [
+ "winapi-i686-pc-windows-gnu",
+ "winapi-x86_64-pc-windows-gnu",
+]
+
+[[package]]
+name = "winapi-i686-pc-windows-gnu"
+version = "0.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
+
+[[package]]
+name = "winapi-x86_64-pc-windows-gnu"
+version = "0.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
+
+[[package]]
+name = "winch-codegen"
+version = "0.15.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9d2b346bad5397b219b4ff0a8fa7230936061ff07c61f05d589d8d81e06fb7b2"
+dependencies = [
+ "anyhow",
+ "cranelift-codegen",
+ "gimli",
+ "regalloc2",
+ "smallvec",
+ "target-lexicon",
+ "wasmparser 0.118.1",
+ "wasmtime-environ",
+]
+
+[[package]]
+name = "windows-core"
+version = "0.52.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "33ab640c8d7e35bf8ba19b884ba838ceb4fba93a4e8c65a9059d08afcfc683d9"
+dependencies = [
+ "windows-targets 0.52.0",
+]
+
+[[package]]
+name = "windows-sys"
+version = "0.48.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9"
+dependencies = [
+ "windows-targets 0.48.5",
+]
+
+[[package]]
+name = "windows-sys"
+version = "0.52.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d"
+dependencies = [
+ "windows-targets 0.52.0",
+]
+
+[[package]]
+name = "windows-targets"
+version = "0.48.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c"
+dependencies = [
+ "windows_aarch64_gnullvm 0.48.5",
+ "windows_aarch64_msvc 0.48.5",
+ "windows_i686_gnu 0.48.5",
+ "windows_i686_msvc 0.48.5",
+ "windows_x86_64_gnu 0.48.5",
+ "windows_x86_64_gnullvm 0.48.5",
+ "windows_x86_64_msvc 0.48.5",
+]
+
+[[package]]
+name = "windows-targets"
+version = "0.52.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8a18201040b24831fbb9e4eb208f8892e1f50a37feb53cc7ff887feb8f50e7cd"
+dependencies = [
+ "windows_aarch64_gnullvm 0.52.0",
+ "windows_aarch64_msvc 0.52.0",
+ "windows_i686_gnu 0.52.0",
+ "windows_i686_msvc 0.52.0",
+ "windows_x86_64_gnu 0.52.0",
+ "windows_x86_64_gnullvm 0.52.0",
+ "windows_x86_64_msvc 0.52.0",
+]
+
+[[package]]
+name = "windows_aarch64_gnullvm"
+version = "0.48.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8"
+
+[[package]]
+name = "windows_aarch64_gnullvm"
+version = "0.52.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "cb7764e35d4db8a7921e09562a0304bf2f93e0a51bfccee0bd0bb0b666b015ea"
+
+[[package]]
+name = "windows_aarch64_msvc"
+version = "0.48.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc"
+
+[[package]]
+name = "windows_aarch64_msvc"
+version = "0.52.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "bbaa0368d4f1d2aaefc55b6fcfee13f41544ddf36801e793edbbfd7d7df075ef"
+
+[[package]]
+name = "windows_i686_gnu"
+version = "0.48.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e"
+
+[[package]]
+name = "windows_i686_gnu"
+version = "0.52.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a28637cb1fa3560a16915793afb20081aba2c92ee8af57b4d5f28e4b3e7df313"
+
+[[package]]
+name = "windows_i686_msvc"
+version = "0.48.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406"
+
+[[package]]
+name = "windows_i686_msvc"
+version = "0.52.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ffe5e8e31046ce6230cc7215707b816e339ff4d4d67c65dffa206fd0f7aa7b9a"
+
+[[package]]
+name = "windows_x86_64_gnu"
+version = "0.48.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e"
+
+[[package]]
+name = "windows_x86_64_gnu"
+version = "0.52.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3d6fa32db2bc4a2f5abeacf2b69f7992cd09dca97498da74a151a3132c26befd"
+
+[[package]]
+name = "windows_x86_64_gnullvm"
+version = "0.48.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc"
+
+[[package]]
+name = "windows_x86_64_gnullvm"
+version = "0.52.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1a657e1e9d3f514745a572a6846d3c7aa7dbe1658c056ed9c3344c4109a6949e"
+
+[[package]]
+name = "windows_x86_64_msvc"
+version = "0.48.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538"
+
+[[package]]
+name = "windows_x86_64_msvc"
+version = "0.52.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "dff9641d1cd4be8d1a070daf9e3773c5f67e78b4d9d42263020c057706765c04"
+
+[[package]]
+name = "winx"
+version = "0.36.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f9643b83820c0cd246ecabe5fa454dd04ba4fa67996369466d0747472d337346"
+dependencies = [
+ "bitflags 2.4.2",
+ "windows-sys 0.52.0",
+]
+
+[[package]]
+name = "wit-parser"
+version = "0.13.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "df4913a2219096373fd6512adead1fb77ecdaa59d7fc517972a7d30b12f625be"
+dependencies = [
+ "anyhow",
+ "id-arena",
+ "indexmap",
+ "log",
+ "semver",
+ "serde",
+ "serde_derive",
+ "serde_json",
+ "unicode-xid",
+]
+
+[[package]]
+name = "witx"
+version = "0.9.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e366f27a5cabcddb2706a78296a40b8fcc451e1a6aba2fc1d94b4a01bdaaef4b"
+dependencies = [
+ "anyhow",
+ "log",
+ "thiserror",
+ "wast",
+]
+
+[[package]]
+name = "zerocopy"
+version = "0.7.32"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "74d4d3961e53fa4c9a25a8637fc2bfaf2595b3d3ae34875568a5cf64787716be"
+dependencies = [
+ "zerocopy-derive",
+]
+
+[[package]]
+name = "zerocopy-derive"
+version = "0.7.32"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9ce1b18ccd8e73a9321186f97e46f9f04b778851177567b1975109d26a08d2a6"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn",
+]
diff --git a/src/wasm-wasi-component/Cargo.toml b/src/wasm-wasi-component/Cargo.toml
new file mode 100644
index 00000000..feb7f53c
--- /dev/null
+++ b/src/wasm-wasi-component/Cargo.toml
@@ -0,0 +1,30 @@
+[package]
+name = "wasm-wasi-component"
+version = "0.1.0"
+edition = "2021"
+publish = false
+
+[lib]
+crate-type = ["cdylib"]
+
+[dependencies]
+anyhow = "1.0.75"
+bytes = "1.5.0"
+futures-util = { version = "0.3.29", default-features = false }
+http = "1.0.0"
+http-body = { version = "1.0.0", default-features = false }
+http-body-util = "0.1.0"
+tokio = { version = "1.33.0", default-features = false }
+wasmtime = { version = "17.0.0", default-features = false, features = ['component-model', 'cranelift'] }
+wasmtime-wasi = "17.0.0"
+wasmtime-wasi-http = "17.0.0"
+
+[build-dependencies]
+bindgen = "0.68.1"
+cc = "1.0.83"
+
+[profile.dev]
+panic = 'abort'
+
+[profile.release]
+panic = 'abort'
diff --git a/src/wasm-wasi-component/build.rs b/src/wasm-wasi-component/build.rs
new file mode 100644
index 00000000..5ea74f17
--- /dev/null
+++ b/src/wasm-wasi-component/build.rs
@@ -0,0 +1,33 @@
+use std::env;
+use std::path::PathBuf;
+
+fn main() {
+ // Tell cargo to invalidate the built crate whenever the wrapper changes
+ println!("cargo:rerun-if-changed=wrapper.h");
+
+ let bindings = bindgen::Builder::default()
+ .clang_args(["-I", "../"])
+ .clang_args(["-I", "../../build/include"])
+ .header("./wrapper.h")
+ // only generate bindings for `nxt_*` header files
+ .allowlist_file(".*nxt_.*.h")
+ // generates an "improper_ctypes" warning and we don't need it anyway
+ .blocklist_function("nxt_vsprintf")
+ // Tell cargo to invalidate the built crate whenever any of the
+ // included header files changed.
+ .parse_callbacks(Box::new(bindgen::CargoCallbacks))
+ // disable some features which aren't necessary
+ .layout_tests(false)
+ .derive_debug(false)
+ .generate()
+ .expect("Unable to generate bindings");
+
+ cc::Build::new()
+ .object("../../build/src/nxt_unit.o")
+ .compile("nxt-unit");
+
+ let out_path = PathBuf::from(env::var("OUT_DIR").unwrap());
+ bindings
+ .write_to_file(out_path.join("bindings.rs"))
+ .expect("Couldn't write bindings!");
+}
diff --git a/src/wasm-wasi-component/src/lib.rs b/src/wasm-wasi-component/src/lib.rs
new file mode 100644
index 00000000..3ee40c4f
--- /dev/null
+++ b/src/wasm-wasi-component/src/lib.rs
@@ -0,0 +1,611 @@
+use anyhow::{bail, Context, Result};
+use bytes::{Bytes, BytesMut};
+use http_body_util::combinators::BoxBody;
+use http_body_util::{BodyExt, Full};
+use std::ffi::{CStr, CString};
+use std::mem::MaybeUninit;
+use std::ptr;
+use std::sync::OnceLock;
+use tokio::sync::mpsc;
+use wasmtime::component::{Component, InstancePre, Linker, ResourceTable};
+use wasmtime::{Config, Engine, Store};
+use wasmtime_wasi::preview2::{
+ DirPerms, FilePerms, WasiCtx, WasiCtxBuilder, WasiView,
+};
+use wasmtime_wasi::{ambient_authority, Dir};
+use wasmtime_wasi_http::bindings::http::types::ErrorCode;
+use wasmtime_wasi_http::{WasiHttpCtx, WasiHttpView};
+
+#[allow(
+ non_camel_case_types,
+ non_upper_case_globals,
+ non_snake_case,
+ dead_code
+)]
+mod bindings {
+ include!(concat!(env!("OUT_DIR"), "/bindings.rs"));
+
+ pub const fn nxt_string(s: &'static str) -> nxt_str_t {
+ nxt_str_t {
+ start: s.as_ptr().cast_mut(),
+ length: s.len(),
+ }
+ }
+
+ pub unsafe fn nxt_unit_sptr_get(sptr: &nxt_unit_sptr_t) -> *const u8 {
+ sptr.base.as_ptr().offset(sptr.offset as isize)
+ }
+}
+
+#[no_mangle]
+pub static mut nxt_app_module: bindings::nxt_app_module_t = {
+ const COMPAT: [u32; 2] = [bindings::NXT_VERNUM, bindings::NXT_DEBUG];
+ let version = "0.1\0";
+ bindings::nxt_app_module_t {
+ compat: COMPAT.as_ptr().cast_mut(),
+ compat_length: COMPAT.len() * 4,
+ mounts: ptr::null(),
+ nmounts: 0,
+ type_: bindings::nxt_string("wasm-wasi-component"),
+ version: version.as_ptr().cast(),
+ setup: Some(setup),
+ start: Some(start),
+ }
+};
+
+static GLOBAL_CONFIG: OnceLock<GlobalConfig> = OnceLock::new();
+static GLOBAL_STATE: OnceLock<GlobalState> = OnceLock::new();
+
+unsafe extern "C" fn setup(
+ task: *mut bindings::nxt_task_t,
+ // TODO: should this get used?
+ _process: *mut bindings::nxt_process_t,
+ conf: *mut bindings::nxt_common_app_conf_t,
+) -> bindings::nxt_int_t {
+ handle_result(task, || {
+ let wasm_conf = &(*conf).u.wasm_wc;
+ let component = CStr::from_ptr(wasm_conf.component).to_str()?;
+ let mut dirs = Vec::new();
+ if !wasm_conf.access.is_null() {
+ let dirs_ptr = bindings::nxt_conf_get_object_member(
+ wasm_conf.access,
+ &mut bindings::nxt_string("filesystem"),
+ ptr::null_mut(),
+ );
+ for i in 0..bindings::nxt_conf_object_members_count(dirs_ptr) {
+ let value = bindings::nxt_conf_get_array_element(
+ dirs_ptr,
+ i.try_into().unwrap(),
+ );
+ let mut s = bindings::nxt_string("");
+ bindings::nxt_conf_get_string(value, &mut s);
+ dirs.push(
+ std::str::from_utf8(std::slice::from_raw_parts(
+ s.start, s.length,
+ ))?
+ .to_string(),
+ );
+ }
+ }
+
+ let result = GLOBAL_CONFIG.set(GlobalConfig {
+ component: component.to_string(),
+ dirs,
+ });
+ assert!(result.is_ok());
+ Ok(())
+ })
+}
+
+unsafe extern "C" fn start(
+ task: *mut bindings::nxt_task_t,
+ data: *mut bindings::nxt_process_data_t,
+) -> bindings::nxt_int_t {
+ handle_result(task, || {
+ let config = GLOBAL_CONFIG.get().unwrap();
+ let state = GlobalState::new(&config)
+ .context("failed to create initial state")?;
+ let res = GLOBAL_STATE.set(state);
+ assert!(res.is_ok());
+
+ let conf = (*data).app;
+ let mut wasm_init = MaybeUninit::uninit();
+ let ret =
+ bindings::nxt_unit_default_init(task, wasm_init.as_mut_ptr(), conf);
+ if ret != bindings::NXT_OK as bindings::nxt_int_t {
+ bail!("nxt_unit_default_init() failed");
+ }
+ let mut wasm_init = wasm_init.assume_init();
+ wasm_init.callbacks.request_handler = Some(request_handler);
+
+ let unit_ctx = bindings::nxt_unit_init(&mut wasm_init);
+ if unit_ctx.is_null() {
+ bail!("nxt_unit_init() failed");
+ }
+
+ bindings::nxt_unit_run(unit_ctx);
+ bindings::nxt_unit_done(unit_ctx);
+
+ Ok(())
+ })
+}
+
+unsafe fn handle_result(
+ task: *mut bindings::nxt_task_t,
+ func: impl FnOnce() -> Result<()>,
+) -> bindings::nxt_int_t {
+ let rc = match func() {
+ Ok(()) => bindings::NXT_OK as bindings::nxt_int_t,
+ Err(e) => {
+ alert(task, &format!("{e:?}"));
+ bindings::NXT_ERROR as bindings::nxt_int_t
+ }
+ };
+ return rc;
+
+ unsafe fn alert(task: *mut bindings::nxt_task_t, msg: &str) {
+ let log = (*task).log;
+ let msg = CString::new(msg).unwrap();
+ ((*log).handler).unwrap()(
+ bindings::NXT_LOG_ALERT as bindings::nxt_uint_t,
+ log,
+ "%s\0".as_ptr().cast(),
+ msg.as_ptr(),
+ );
+ }
+}
+
+unsafe extern "C" fn request_handler(
+ info: *mut bindings::nxt_unit_request_info_t,
+) {
+ // Enqueue this request to get processed by the Tokio event loop, and
+ // otherwise immediately return.
+ let state = GLOBAL_STATE.get().unwrap();
+ state.sender.blocking_send(NxtRequestInfo { info }).unwrap();
+}
+
+struct GlobalConfig {
+ component: String,
+ dirs: Vec<String>,
+}
+
+struct GlobalState {
+ engine: Engine,
+ component: InstancePre<StoreState>,
+ global_config: &'static GlobalConfig,
+ sender: mpsc::Sender<NxtRequestInfo>,
+}
+
+impl GlobalState {
+ fn new(global_config: &'static GlobalConfig) -> Result<GlobalState> {
+ // Configure Wasmtime, e.g. the component model and async support are
+ // enabled here. Other configuration can include:
+ //
+ // * Epochs/fuel - enables async yielding to prevent any one request
+ // starving others.
+ // * Pooling allocator - accelerates instantiation at the cost of a
+ // large virtual memory reservation.
+ // * Memory limits/etc.
+ let mut config = Config::new();
+ config.wasm_component_model(true);
+ config.async_support(true);
+ let engine = Engine::new(&config)?;
+
+ // Compile the binary component on disk in Wasmtime. This is then
+ // pre-instantiated with host APIs defined by WASI. The result of
+ // this is a "pre-instantiated instance" which can be used to
+ // repeatedly instantiate later on. This will frontload
+ // compilation/linking/type-checking/etc to happen once rather than on
+ // each request.
+ let component = Component::from_file(&engine, &global_config.component)
+ .context("failed to compile component")?;
+ let mut linker = Linker::<StoreState>::new(&engine);
+ wasmtime_wasi::preview2::command::add_to_linker(&mut linker)?;
+ wasmtime_wasi_http::proxy::add_only_http_to_linker(&mut linker)?;
+ let component = linker
+ .instantiate_pre(&component)
+ .context("failed to pre-instantiate the provided component")?;
+
+ // Spin up the Tokio async runtime in a separate thread with a
+ // communication channel into it. This thread will send requests to
+ // Tokio and the results will be calculated there.
+ let (sender, receiver) = mpsc::channel(10);
+ std::thread::spawn(|| GlobalState::run(receiver));
+
+ Ok(GlobalState {
+ engine,
+ component,
+ sender,
+ global_config,
+ })
+ }
+
+ /// Worker thread that executes the Tokio runtime, infinitely receiving
+ /// messages from the provided `receiver` and handling those requests.
+ ///
+ /// Each request is handled in a separate subtask so processing can all
+ /// happen concurrently.
+ fn run(mut receiver: mpsc::Receiver<NxtRequestInfo>) {
+ let rt = tokio::runtime::Runtime::new().unwrap();
+ rt.block_on(async {
+ while let Some(msg) = receiver.recv().await {
+ let state = GLOBAL_STATE.get().unwrap();
+ tokio::task::spawn(async move {
+ state.handle(msg).await.expect("failed to handle request")
+ });
+ }
+ });
+ }
+
+ async fn handle(&'static self, mut info: NxtRequestInfo) -> Result<()> {
+ // Create a "Store" which is the unit of per-request isolation in
+ // Wasmtime.
+ let data = StoreState {
+ ctx: {
+ let mut cx = WasiCtxBuilder::new();
+ // NB: while useful for debugging untrusted code probably
+ // shouldn't get raw access to stdout/stderr.
+ cx.inherit_stdout();
+ cx.inherit_stderr();
+ for dir in self.global_config.dirs.iter() {
+ let fd = Dir::open_ambient_dir(dir, ambient_authority())
+ .with_context(|| {
+ format!("failed to open directory '{dir}'")
+ })?;
+ cx.preopened_dir(
+ fd,
+ DirPerms::all(),
+ FilePerms::all(),
+ dir,
+ );
+ }
+ cx.build()
+ },
+ table: ResourceTable::default(),
+ http: WasiHttpCtx,
+ };
+ let mut store = Store::new(&self.engine, data);
+
+ // Convert the `nxt_*` representation into the representation required
+ // by Wasmtime's `wasi-http` implementation using the Rust `http`
+ // crate.
+ let request = self.to_request_builder(&info)?;
+ let body = self.to_request_body(&mut info);
+ let request = request.body(body)?;
+
+ let (sender, receiver) = tokio::sync::oneshot::channel();
+
+ // Instantiate the WebAssembly component and invoke its `handle`
+ // function which receives a request and where to put a response.
+ //
+ // Note that this is done in a sub-task to work concurrently with
+ // writing the response when it's available. This enables wasm to
+ // generate headers, write those below, and then compute the body
+ // afterwards.
+ let task = tokio::spawn(async move {
+ let (proxy, _) = wasmtime_wasi_http::proxy::Proxy::instantiate_pre(
+ &mut store,
+ &self.component,
+ )
+ .await
+ .context("failed to instantiate")?;
+ let req = store.data_mut().new_incoming_request(request)?;
+ let out = store.data_mut().new_response_outparam(sender)?;
+ proxy
+ .wasi_http_incoming_handler()
+ .call_handle(&mut store, req, out)
+ .await
+ .context("failed to invoke wasm `handle`")?;
+ Ok::<_, anyhow::Error>(())
+ });
+
+ // Wait for the wasm to produce the initial response. If this succeeds
+ // then propagate that failure. If this fails then wait for the above
+ // task to complete to see if it failed, otherwise panic since that's
+ // unexpected.
+ let response = match receiver.await {
+ Ok(response) => response.context("response generation failed")?,
+ Err(_) => {
+ task.await.unwrap()?;
+ panic!("sender of response disappeared");
+ }
+ };
+
+ // Send the headers/status which will extract the body for the next
+ // phase.
+ let body = self.send_response(&mut info, response);
+
+ // Send the body, a blocking operation, over time as it becomes
+ // available.
+ self.send_response_body(&mut info, body)
+ .await
+ .context("failed to write response body")?;
+
+ // Join on completion of the wasm task which should be done by this
+ // point.
+ task.await.unwrap()?;
+
+ // And finally signal that we're done.
+ info.request_done();
+
+ Ok(())
+ }
+
+ fn to_request_builder(
+ &self,
+ info: &NxtRequestInfo,
+ ) -> Result<http::request::Builder> {
+ let mut request = http::Request::builder();
+
+ request = request.method(info.method());
+ request = match info.version() {
+ "HTTP/0.9" => request.version(http::Version::HTTP_09),
+ "HTTP/1.0" => request.version(http::Version::HTTP_10),
+ "HTTP/1.1" => request.version(http::Version::HTTP_11),
+ "HTTP/2.0" => request.version(http::Version::HTTP_2),
+ "HTTP/3.0" => request.version(http::Version::HTTP_3),
+ version => {
+ println!("unknown version: {version}");
+ request
+ }
+ };
+
+ let uri = http::Uri::builder()
+ .scheme(if info.tls() { "https" } else { "http" })
+ .authority(info.server_name())
+ .path_and_query(info.target())
+ .build()
+ .context("failed to build URI")?;
+ request = request.uri(uri);
+
+ for (name, value) in info.fields() {
+ request = request.header(name, value);
+ }
+ Ok(request)
+ }
+
+ fn to_request_body(
+ &self,
+ info: &mut NxtRequestInfo,
+ ) -> BoxBody<Bytes, ErrorCode> {
+ // TODO: should convert the body into a form of `Stream` to become an
+ // async stream of frames. The return value can represent that here
+ // but for now this slurps up the entire body into memory and puts it
+ // all in a single `BytesMut` which is then converted to `Bytes`.
+ let mut body =
+ BytesMut::with_capacity(info.content_length().try_into().unwrap());
+
+ // TODO: can this perform a partial read?
+ // TODO: how to make this async at the nxt level?
+ info.request_read(&mut body);
+
+ Full::new(body.freeze()).map_err(|e| match e {}).boxed()
+ }
+
+ fn send_response<T>(
+ &self,
+ info: &mut NxtRequestInfo,
+ response: http::Response<T>,
+ ) -> T {
+ info.init_response(
+ response.status().as_u16(),
+ response.headers().len().try_into().unwrap(),
+ response
+ .headers()
+ .iter()
+ .map(|(k, v)| k.as_str().len() + v.len())
+ .sum::<usize>()
+ .try_into()
+ .unwrap(),
+ );
+ for (k, v) in response.headers() {
+ info.add_field(k.as_str().as_bytes(), v.as_bytes());
+ }
+ info.send_response();
+
+ response.into_body()
+ }
+
+ async fn send_response_body(
+ &self,
+ info: &mut NxtRequestInfo,
+ mut body: BoxBody<Bytes, ErrorCode>,
+ ) -> Result<()> {
+ loop {
+ // Acquire the next frame, and because nothing is actually async
+ // at the moment this should never block meaning that the
+ // `Pending` case should not happen.
+ let frame = match body.frame().await {
+ Some(Ok(frame)) => frame,
+ Some(Err(e)) => break Err(e.into()),
+ None => break Ok(()),
+ };
+ match frame.data_ref() {
+ Some(data) => {
+ info.response_write(&data);
+ }
+ None => {
+ // TODO: what to do with trailers?
+ }
+ }
+ }
+ }
+}
+
+struct NxtRequestInfo {
+ info: *mut bindings::nxt_unit_request_info_t,
+}
+
+// TODO: is this actually safe?
+unsafe impl Send for NxtRequestInfo {}
+unsafe impl Sync for NxtRequestInfo {}
+
+impl NxtRequestInfo {
+ fn method(&self) -> &str {
+ unsafe {
+ let raw = (*self.info).request;
+ self.get_str(&(*raw).method, (*raw).method_length.into())
+ }
+ }
+
+ fn tls(&self) -> bool {
+ unsafe { (*(*self.info).request).tls != 0 }
+ }
+
+ fn version(&self) -> &str {
+ unsafe {
+ let raw = (*self.info).request;
+ self.get_str(&(*raw).version, (*raw).version_length.into())
+ }
+ }
+
+ fn server_name(&self) -> &str {
+ unsafe {
+ let raw = (*self.info).request;
+ self.get_str(&(*raw).server_name, (*raw).server_name_length.into())
+ }
+ }
+
+ fn target(&self) -> &str {
+ unsafe {
+ let raw = (*self.info).request;
+ self.get_str(&(*raw).target, (*raw).target_length.into())
+ }
+ }
+
+ fn content_length(&self) -> u64 {
+ unsafe {
+ let raw_request = (*self.info).request;
+ (*raw_request).content_length
+ }
+ }
+
+ fn fields(&self) -> impl Iterator<Item = (&str, &str)> {
+ unsafe {
+ let raw = (*self.info).request;
+ (0..(*raw).fields_count).map(move |i| {
+ let field = (*raw).fields.as_ptr().add(i as usize);
+ let name =
+ self.get_str(&(*field).name, (*field).name_length.into());
+ let value =
+ self.get_str(&(*field).value, (*field).value_length.into());
+ (name, value)
+ })
+ }
+ }
+
+ fn request_read(&mut self, dst: &mut BytesMut) {
+ unsafe {
+ let rest = dst.spare_capacity_mut();
+ let mut total_bytes_read = 0;
+ loop {
+ let amt = bindings::nxt_unit_request_read(
+ self.info,
+ rest.as_mut_ptr().wrapping_add(total_bytes_read).cast(),
+ 32 * 1024 * 1024,
+ );
+ total_bytes_read += amt as usize;
+ if total_bytes_read >= rest.len() {
+ break;
+ }
+ }
+ // TODO: handle failure when `amt` is negative
+ let total_bytes_read: usize = total_bytes_read.try_into().unwrap();
+ dst.set_len(dst.len() + total_bytes_read);
+ }
+ }
+
+ fn response_write(&mut self, data: &[u8]) {
+ unsafe {
+ let rc = bindings::nxt_unit_response_write(
+ self.info,
+ data.as_ptr().cast(),
+ data.len(),
+ );
+ assert_eq!(rc, 0);
+ }
+ }
+
+ fn init_response(&mut self, status: u16, headers: u32, headers_size: u32) {
+ unsafe {
+ let rc = bindings::nxt_unit_response_init(
+ self.info,
+ status,
+ headers,
+ headers_size,
+ );
+ assert_eq!(rc, 0);
+ }
+ }
+
+ fn add_field(&mut self, key: &[u8], val: &[u8]) {
+ unsafe {
+ let rc = bindings::nxt_unit_response_add_field(
+ self.info,
+ key.as_ptr().cast(),
+ key.len().try_into().unwrap(),
+ val.as_ptr().cast(),
+ val.len().try_into().unwrap(),
+ );
+ assert_eq!(rc, 0);
+ }
+ }
+
+ fn send_response(&mut self) {
+ unsafe {
+ let rc = bindings::nxt_unit_response_send(self.info);
+ assert_eq!(rc, 0);
+ }
+ }
+
+ fn request_done(self) {
+ unsafe {
+ bindings::nxt_unit_request_done(
+ self.info,
+ bindings::NXT_UNIT_OK as i32,
+ );
+ }
+ }
+
+ unsafe fn get_str(
+ &self,
+ ptr: &bindings::nxt_unit_sptr_t,
+ len: u32,
+ ) -> &str {
+ let ptr = bindings::nxt_unit_sptr_get(ptr);
+ let slice = std::slice::from_raw_parts(ptr, len.try_into().unwrap());
+ std::str::from_utf8(slice).unwrap()
+ }
+}
+
+struct StoreState {
+ ctx: WasiCtx,
+ http: WasiHttpCtx,
+ table: ResourceTable,
+}
+
+impl WasiView for StoreState {
+ fn table(&self) -> &ResourceTable {
+ &self.table
+ }
+ fn table_mut(&mut self) -> &mut ResourceTable {
+ &mut self.table
+ }
+ fn ctx(&self) -> &WasiCtx {
+ &self.ctx
+ }
+ fn ctx_mut(&mut self) -> &mut WasiCtx {
+ &mut self.ctx
+ }
+}
+
+impl WasiHttpView for StoreState {
+ fn ctx(&mut self) -> &mut WasiHttpCtx {
+ &mut self.http
+ }
+ fn table(&mut self) -> &mut ResourceTable {
+ &mut self.table
+ }
+}
+
+impl StoreState {}
diff --git a/src/wasm-wasi-component/wrapper.h b/src/wasm-wasi-component/wrapper.h
new file mode 100644
index 00000000..93f3014a
--- /dev/null
+++ b/src/wasm-wasi-component/wrapper.h
@@ -0,0 +1,5 @@
+#include <nxt_main.h>
+#include <nxt_unit.h>
+#include <nxt_unit_request.h>
+#include <nxt_unit_typedefs.h>
+#include <nxt_application.h>