diff options
author | Dan Callahan <d.callahan@f5.com> | 2024-02-27 15:15:42 +0000 |
---|---|---|
committer | Dan Callahan <d.callahan@f5.com> | 2024-02-27 15:15:42 +0000 |
commit | d76761901c4084bcdbc5a449e9bbb47d56b7093c (patch) | |
tree | b4b7b4e3d588b73a2adcc0094cab466d9194c679 /src | |
parent | c43629880472bba8d389dfb0b7ae6d883b0ba499 (diff) | |
parent | 088117008c9e8f397a58cc8d8070ce047beff12f (diff) | |
download | unit-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')
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> |