[security]: potential vulnerability
shu7734 opened this issue · comments
当我发起一个非标准的Pub请求的时候,100%导致进程挂掉,提示段错误,应该是内存溢出或指针错误,可能会导致安全漏洞,至少可以用于拒绝服务攻击,Debug日志如下
`
2023-12-28 18:47:23 [411] DEBUG /root/nanomq/nng/src/sp/protocol/mqtt/mqtt_parser.c:611 conn_handler: remain len 89 max len 91 prop len 0 pos 12
2023-12-28 18:47:23 [411] DEBUG /root/nanomq/nng/src/sp/protocol/mqtt/nmq_mqtt.c:674 nano_pipe_start: client connected! addr [121.35.41.145 port [49502]
2023-12-28 18:47:23 [411] DEBUG /root/nanomq/nanomq/apps/broker.c:253 server_cb: RECV ^^^^ ctx1 ^^^^
2023-12-28 18:47:23 [411] DEBUG /root/nanomq/nanomq/pub_handler.c:1494 decode_pub_message: cmd: 3, retain: 0, qos: 0, dup: 0, remaining length: 201
2023-12-28 18:47:23 [411] DEBUG /root/nanomq/nanomq/pub_handler.c:1542 decode_pub_message: topic: [$SYS/brokers/connected], len: [22], qos: 0
2023-12-28 18:47:23 [411] DEBUG /root/nanomq/nanomq/pub_handler.c:1585 decode_pub_message: used pos: [24]
2023-12-28 18:47:23 [411] DEBUG /root/nanomq/nanomq/pub_handler.c:1596 decode_pub_message: payload: [], len = 177
2023-12-28 18:47:23 [411] DEBUG /root/nanomq/nanomq/pub_handler.c:1182 handle_pub: pipe_info size: [0]
2023-12-28 18:47:23 [411] DEBUG /root/nanomq/nanomq/apps/broker.c:497 server_cb: WAIT ^^^^ ctx1 ^^^^
2023-12-28 18:47:23 [411] DEBUG /root/nanomq/nanomq/pub_handler.c:1278 free_pub_packet: free topic
2023-12-28 18:47:23 [411] DEBUG /root/nanomq/nanomq/pub_handler.c:1294 free_pub_packet: free payload
2023-12-28 18:47:23 [411] DEBUG /root/nanomq/nanomq/pub_handler.c:1300 free_pub_packet: free pub_packet
2023-12-28 18:47:23 [411] DEBUG /root/nanomq/nanomq/pub_handler.c:84 init_pipe_content: pub_handler: init pipe_info
2023-12-28 18:47:23 [410] DEBUG /root/nanomq/nanomq/apps/broker.c:253 server_cb: RECV ^^^^ ctx2 ^^^^
2023-12-28 18:47:23 [410] DEBUG /root/nanomq/nanomq/sub_handler.c:65 decode_sub_msg: remainLen: [29] packetid : [23]
2023-12-28 18:47:23 [413] DEBUG /root/nanomq/nanomq/apps/broker.c:253 server_cb: RECV ^^^^ ctx3 ^^^^
2023-12-28 18:47:23 [410] INFO /root/nanomq/nanomq/sub_handler.c:86 decode_sub_msg: topic: [devtype1/mqttx_0f8aaefa] len: [23] pid [23]
2023-12-28 18:47:23 [413] DEBUG /root/nanomq/nanomq/pub_handler.c:1494 decode_pub_message: cmd: 3, retain: 0, qos: 1, dup: 0, remaining length: 33
2023-12-28 18:47:23 [410] DEBUG /root/nanomq/nanomq/sub_handler.c:248 sub_ctx_handle: topicLen: [23] body: [devtype1/mqttx_0f8aaefa]
2023-12-28 18:47:23 [410] INFO /root/nanomq/nanomq/sub_handler.c:269 sub_ctx_handle: acl allow
2023-12-28 18:47:23 [410] DEBUG /root/nanomq/nng/src/supplemental/nanolib/mqtt_db.c:385 dbtree_node_new: New node: [devtype1]
2023-12-28 18:47:23 [410] DEBUG /root/nanomq/nng/src/supplemental/nanolib/mqtt_db.c:385 dbtree_node_new: New node: [mqttx_0f8aaefa]
2023-12-28 18:47:23 [413] DEBUG /root/nanomq/nanomq/pub_handler.c:1542 decode_pub_message: topic: [devtype1/mqttx_0f8aaefa], len: [23], qos: 1
2023-12-28 18:47:23 [413] DEBUG /root/nanomq/nanomq/pub_handler.c:1551 decode_pub_message: identifier: [24]
2023-12-28 18:47:23 [413] DEBUG /root/nanomq/nanomq/pub_handler.c:1562 decode_pub_message: property len: 0
2023-12-28 18:47:23 [413] DEBUG /root/nanomq/nanomq/pub_handler.c:1585 decode_pub_message: used pos: [28]
2023-12-28 18:47:23 [413] DEBUG /root/nanomq/nanomq/pub_handler.c:1596 decode_pub_message: payload: [hello], len = 5
2023-12-28 18:47:23 [410] DEBUG /root/nanomq/nanomq/sub_handler.c:339 sub_ctx_handle: end of sub ctx handle.
2023-12-28 18:47:23 [413] INFO /root/nanomq/nanomq/pub_handler.c:1164 handle_pub: acl allow
2023-12-28 18:47:23 [413] DEBUG /root/nanomq/nng/src/supplemental/nanolib/mqtt_db.c:734 collect_clients: Searching client: devtype1
2023-12-28 18:47:23 [410] DEBUG /root/nanomq/nanomq/sub_handler.c:188 encode_suback_msg: reason_code: [2]
2023-12-28 18:47:23 [413] DEBUG /root/nanomq/nng/src/supplemental/nanolib/mqtt_db.c:754 collect_clients: Searching client: devtype1
2023-12-28 18:47:23 [413] DEBUG /root/nanomq/nng/src/supplemental/nanolib/mqtt_db.c:756 collect_clients: add node_t: devtype1
2023-12-28 18:47:23 [413] DEBUG /root/nanomq/nng/src/supplemental/nanolib/mqtt_db.c:734 collect_clients: Searching client: mqttx_0f8aaefa
2023-12-28 18:47:23 [410] DEBUG /root/nanomq/nanomq/sub_handler.c:214 encode_suback_msg: remain: [4] varint: [4 0 0 0] len: [1] packetid: [0 17]
2023-12-28 18:47:23 [413] DEBUG /root/nanomq/nng/src/supplemental/nanolib/mqtt_db.c:737 collect_clients: Searching client: mqttx_0f8aaefa
2023-12-28 18:47:23 [413] DEBUG /root/nanomq/nanomq/pub_handler.c:1182 handle_pub: pipe_info size: [1]
2023-12-28 18:47:23 [413] DEBUG /root/nanomq/nanomq/apps/broker.c:574 server_cb: SEND ^^^^ ctx2 ^^^^
2023-12-28 18:47:23 [410] DEBUG /root/nanomq/nanomq/apps/broker.c:497 server_cb: WAIT ^^^^ ctx3 ^^^^
2023-12-28 18:47:23 [410] DEBUG /root/nanomq/nanomq/pub_handler.c:1343 encode_pub_message: start encode message
2023-12-28 18:47:23 [410] DEBUG /root/nanomq/nanomq/pub_handler.c:1380 encode_pub_message: after topic and id len in msg already [27]
2023-12-28 18:47:23 [410] DEBUG /root/nanomq/nanomq/pub_handler.c:1403 encode_pub_message: after payload len in msg already [33]
2023-12-28 18:47:23 [410] DEBUG /root/nanomq/nanomq/pub_handler.c:1413 encode_pub_message: header len [2] remain len [33]
2023-12-28 18:47:23 [410] DEBUG /root/nanomq/nanomq/pub_handler.c:1465 encode_pub_message: end encode message
ERROR: packet id duplicates in nano_qos_db
2023-12-28 18:47:23 [410] DEBUG /root/nanomq/nanomq/pub_handler.c:1278 free_pub_packet: free topic
2023-12-28 18:47:23 [410] DEBUG /root/nanomq/nanomq/pub_handler.c:1294 free_pub_packet: free payload
2023-12-28 18:47:23 [410] DEBUG /root/nanomq/nanomq/pub_handler.c:1300 free_pub_packet: free pub_packet
2023-12-28 18:47:23 [410] DEBUG /root/nanomq/nanomq/pub_handler.c:84 init_pipe_content: pub_handler: init pipe_info
段错误
`
Thanks for spotting security issue, plz provide your data sample so that we can fix it
感谢你帮忙发现潜在的安全风险,请提供你的测试数据集以便我们尽快修复。
以下是我的Demo代码
#define MG_ARCH MG_ARCH_WIN32
#define MG_TLS MG_TLS_MBED
#include <iostream>
#include "mongoose.h"
#ifndef _LIBPATH_
#define _LIBPATH_(p,f) p##f
#endif
#ifdef _WIN32
#ifdef _WIN64 //x64
#pragma comment(lib,"lib\\x64\\mbedTLS.lib")
#else
#pragma comment(lib,"lib\\x86\\mbedTLS.lib")
#endif // _WIN64
#endif // _WIN32
/*************************************
* 为了兼容nanomq的websocket协议,需在mg_ws_connect函数的HTTP头添加
*"Sec-WebSocket-Extensions: permessage-deflate; client_max_window_bits\r\n"
*"Sec-WebSocket-Protocol: mqtt\r\n"
* 否则无法完成握手
**************************************/
//以下为自签CA根证书
static const char* s_ca =
"-----BEGIN CERTIFICATE-----\n"
"MIIC6jCCAdICCQCbea5Ea6i87DANBgkqhkiG9w0BAQsFADA2MTQwMgYDVQQKDCtU\n"
"TFMgUHJxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxR5MCAXDTIx\n"
"MTEyNxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxDCtUTFMgUHJv\n"
"amVjdCBNaWtlWmhvbmcgQ2VydGlmaWNhdGUgQXV0aG9yaXR5MIIBIjANBgkqhkiG\n"
"9w0BAQEFAAOCAQ8AMIIBCgKCAQEAzWP5+VG3l8Kg1sTZCKpbj3AkpSGYKZITz3wT\n"
"ZoNfcFNnwlf5l37PbHZ4QjRoA1CW00YbAWzVBpyhQhVtpXtV/ozEzN3+qCPR/3+S\n"
"n802TFoHbaRl7rA6LpEDv1IJGgO8PMAsxrP0KQ6aTCZdFudVQeYtJUtk4f2IIt4K\n"
"oeGkX3GNWQjpR2x/w1rNHrBUUGM++lzeEOR/m5GdaP6o7kyNIG03GhGqVPH5Jntx\n"
"2UvZvE2w+3lpHy0GU8mD/6YdHd5J1tI/2y8klv3Q+ZtQ+5yOW2+HAJaCdYD+k2uu\n"
"MtkKHL4y12qFIpye//AozFVJAJBQ4eaY3l1FuE/no74c5xHp8QIDAQABMA0GCSqG\n"
"SIb3DQEBCwUAA4IBAQCmAbjezu1nBVWbfGqo8jVOMPUryDoAekNDL31jrKPYYLHX\n"
"bTxC6RESpm3YuCyiOyGhK3u5L6pzTPPAPidVJzIzyDSCvamHj0mEQ6J08csl8TAR\n"
"bpRj6ud/ogmnhbpD8UU3Ic28v3ZhmSBteS20WnFQQdSmc9Fp0LDH0RggRrOsGc+j\n"
"mUyzJhtMlkUjEH3ef8wl/jPZkH6JnTDUPS9a6C6sBNJ2ggR+G3qcDIgnqqh/yetD\n"
"fz1ON32qDmE4r0DcpdA8iecdgJ9xvuZ7JCJ6NTzAA+VN748yPU8ziEWTY4DASR0u\n"
"h+r+5S6PINcOU+f++lBJsvFCtcw2FtWsqy/gNjxA\n"
"-----END CERTIFICATE-----\n"
"\n";
static const char* s_topic = "devtype1/mqttx_0f8aaefa";
static const char* s_mqtt_url = "wss://mqtt.xxxx.com/mqtt";
static struct mg_connection* s_mqttconn;
static bool mqtt_stop = false;
// Print websocket response and signal that we're done
static void fn(struct mg_connection* c, int ev, void* ev_data, void* fn_data) {
if (ev == MG_EV_ERROR) {
// On error, log error message
MG_ERROR(("%p %s", c->fd, (char*)ev_data));
}
else if (ev == MG_EV_CONNECT) {
if (mg_url_is_ssl(s_mqtt_url)) {
struct mg_tls_opts opts = {
.ca = mg_str(s_ca), .name = mg_url_host(s_mqtt_url)
};
mg_tls_init(c, &opts);
}
}
else if (ev == MG_EV_WS_OPEN) {
// WS connection established. Perform MQTT login
MG_INFO(("Connected to WS. Logging in to MQTT..."));
struct mg_mqtt_opts opts = {
.user = mg_str("user01"),
.pass = mg_str("xxxxxxxxxxxxxxx"),
.client_id = mg_str("mqttx_0f8aaefa"),
.topic = mg_str(s_topic),
.message = mg_str("goodbye"),
.qos = 1,
.version = 5,
.keepalive=300
};
size_t len = c->send.len;
mg_mqtt_login(c, &opts);
mg_ws_wrap(c, c->send.len - len, WEBSOCKET_OP_BINARY);
c->is_hexdumping = 1;
}
else if (ev == MG_EV_WS_MSG) {
struct mg_mqtt_message mm;
struct mg_ws_message* wm = (struct mg_ws_message*)ev_data;
uint8_t version = c->is_mqtt5 ? 5 : 4;
MG_INFO(("GOT %d bytes WS msg", (int)wm->data.len));
while ((mg_mqtt_parse((uint8_t*)wm->data.ptr,
wm->data.len,
version,
&mm)) == MQTT_OK) {
switch (mm.cmd) {
case MQTT_CMD_CONNACK:
mg_call(c, MG_EV_MQTT_OPEN, &mm.ack);
if (mm.ack == 0) {
struct mg_str topic = mg_str(s_topic), data = mg_str("hello");
size_t len = c->send.len;
MG_INFO(("CONNECTED to %s", s_mqtt_url));
struct mg_mqtt_opts sub_opts;
memset(&sub_opts, 0, sizeof(sub_opts));
//sub_opts.user = mg_str("user01");
//sub_opts.pass = mg_str("xxxxxxxxxxxxxxxx");
//sub_opts.client_id = mg_str("mqttx_0f8aaefa");
sub_opts.topic = topic;
sub_opts.qos = 1;
mg_mqtt_sub(c, &sub_opts);
len = mg_ws_wrap(c, c->send.len - len, WEBSOCKET_OP_BINARY);
MG_INFO(("SUBSCRIBED to %.*s", (int)topic.len, topic.ptr));
struct mg_mqtt_opts pub_opts;
memset(&pub_opts, 0, sizeof(pub_opts));
pub_opts.topic = topic;
pub_opts.message = data;
pub_opts.qos = 1, pub_opts.retain = false;
mg_mqtt_pub(c, &pub_opts);
MG_INFO(("PUBLISHED %.*s -> %.*s", (int)data.len, data.ptr,
(int)topic.len, topic.ptr));
len = mg_ws_wrap(c, c->send.len - len, WEBSOCKET_OP_BINARY);
}
else {
MG_ERROR(("%lu MQTT auth failed, code %d", c->id, mm.ack));
c->is_draining = 1;
}
break;
case MQTT_CMD_PUBLISH: {
MG_DEBUG(("%lu [%.*s] -> [%.*s]", c->id, (int)mm.topic.len,
mm.topic.ptr, (int)mm.data.len, mm.data.ptr));
MG_INFO(("RECEIVED %.*s <- %.*s", (int)mm.data.len, mm.data.ptr,
(int)mm.topic.len, mm.topic.ptr));
//c->is_draining = 1;
break;
}
}
wm->data.ptr += mm.dgram.len;
wm->data.len -= mm.dgram.len;
}
}
if (ev == MG_EV_ERROR || ev == MG_EV_CLOSE) {
MG_ERROR(("%p %s", c->fd, (char*)ev_data));
c->is_closing = 1;
s_mqttconn = NULL;
}
}
static void mqtt_timer_fn(void* arg) {
struct mg_mgr* mgr = (struct mg_mgr*)arg;
if (s_mqttconn == NULL)
{
s_mqttconn = mg_ws_connect(mgr, s_mqtt_url, fn, NULL, NULL);
//以下请求是当时调试时写错了,却必然引发服务端出错挂掉,服务端不太好变更,只有wss端口开放出来,未测试ws是否也会出现
size_t len = s_mqttconn->send.len;
struct mg_str topic = mg_str(s_topic), data = mg_str("test111");
struct mg_mqtt_opts pub_opts;
memset(&pub_opts, 0, sizeof(pub_opts));
pub_opts.topic = topic;
pub_opts.message = data;
pub_opts.qos = 1, pub_opts.retain = false;
mg_mqtt_pub(s_mqttconn, &pub_opts);
MG_INFO(("PUBLISHED %.*s -> %.*s", (int)data.len, data.ptr,
(int)topic.len, topic.ptr));
len = mg_ws_wrap(s_mqttconn, s_mqttconn->send.len, WEBSOCKET_OP_BINARY);
}
}
int main()
{
struct mg_mgr mgr; // Event manager
bool done = false; // Event handler flips it to true
struct mg_connection* c; // Client connection
mg_mgr_init(&mgr); // Initialise event manager
mg_log_set(MG_LL_DEBUG); // Set log level
mg_timer_add(&mgr, 5000, MG_TIMER_REPEAT, mqtt_timer_fn, &mgr);
while (mqtt_stop == false) mg_mgr_poll(&mgr, 1000);
mg_mgr_free(&mgr); // Deallocate resources
}
好的 websocket确实并没有做过安全加固
Hello @shu7734
我参考你的demo进行了测试,似乎并没有触发NanoMQ的任何问题。以下是我的编译命令与日志。
make CFLAGS_EXTRA="-DMG_TLS=MG_TLS_MBED -lmbedtls -lmbedcrypto -lmbedx509"
./example
141eaf3 3 net.c:177:mg_connect 1 -1 wss://192.168.192.2:8086/mqtt
141eaf3 3 sock.c:388:mg_connect_resolve 1 4 -> 192.168.192.2:8086 pend
141eaf3 3 mqtt.c:326:mg_mqtt_pub 1 [devtype1/mqttx_0f8aaefa] -> [test111]
141eaf3 2 main.c:166:mqtt_timer_fn PUBLISHED test111 -> devtype1/mqttx_0f8aaefa
141eaf3 2 main.c:63:fn Connected to WS. Logging in to MQTT...
141eaf3 3 tls_mbed.c:107:mg_tls_init 1 Setting TLS
141eb11 3 tls_mbed.c:80:mg_tls_handshak 1 success
141eb11 3 sock.c:299:read_conn 1 0x4 snd 200/2048 rcv 0/2048 n=-2 err=115
141eb11 3 sock.c:310:write_conn 1 4 snd 200/2048 rcv 0/2048 n=200 err=0
141eb11 3 sock.c:299:read_conn 1 0x4 snd 0/2048 rcv 0/2048 n=-1 err=115
141eb11 1 main.c:145:fn 0x4
141eb11 3 net.c:151:mg_close_conn 1 4 closed
141f2e3 3 net.c:177:mg_connect 2 -1 wss://192.168.192.2:8086/mqtt
141f2e3 3 sock.c:388:mg_connect_resolve 2 4 -> 192.168.192.2:8086 pend
141f2e3 3 mqtt.c:326:mg_mqtt_pub 2 [devtype1/mqttx_0f8aaefa] -> [test111]
141f2e3 2 main.c:166:mqtt_timer_fn PUBLISHED test111 -> devtype1/mqttx_0f8aaefa
141f2e3 2 main.c:63:fn Connected to WS. Logging in to MQTT...
141f2e3 3 tls_mbed.c:107:mg_tls_init 2 Setting TLS
141f301 3 tls_mbed.c:80:mg_tls_handshak 2 success
141f301 3 sock.c:299:read_conn 2 0x4 snd 200/2048 rcv 0/2048 n=-2 err=115
141f301 3 sock.c:310:write_conn 2 4 snd 200/2048 rcv 0/2048 n=200 err=0
141f301 3 sock.c:299:read_conn 2 0x4 snd 0/2048 rcv 0/2048 n=-1 err=115
141f301 1 main.c:145:fn 0x4
141f301 3 net.c:151:mg_close_conn 2 4 closed
我注意到上述过程中,MQTT连接并没有成功连接,想请问一下,Demo这边是否需要进行修改,还是我的上述的配置或者编译过程有问题。
此外,想请问一下您使用的NanoMQ的版本或者commitid是?能否提供更多NanoMQ的Backtrace信息(NanoMQ编译时开启cmake .. -DDEBUG=ON -DASAN=ON)
没有连接成功请参考我文件前几行的注释代码,需要修改Mongoose的代码的,因为你们有两个特殊的MQTT header
具体版本我就不记得了,就是当天从master签出来的版本,目前为了进度已换成其它的MQTT Server
nanomq遵循标准mqtt协议,并没有特殊的mqtt header开头。
若是从master直接使用可能会遇到开发未完成版本和submodule不匹配的情况,还请使用release tag.
那么我将这个issue标为 invalid,有需要请reopen 并提供可复现的client或log。
没有连接成功请参考我文件前几行的注释代码,需要修改Mongoose的代码的,因为你们有两个特殊的MQTT header
具体版本我就不记得了,就是当天从master签出来的版本,目前为了进度已换成其它的MQTT Server
像这样吗?
s_mqttconn = mg_ws_connect(mgr, s_mqtt_url, fn, NULL, "Sec-WebSocket-Extensions: permessage-deflate; client_max_window_bits\r\n", "Sec-WebSocket-Protocol: mqtt\r\n");
是的,这样应该也是可以的,Demo还是没连上吗?
我是直接改Mongoose代码实现的
是的,还是无法连接。
不过好消息是,Mongoose官方的Demo可以运行。
以下是我的修改。
--- a/examples/mqtt-over-ws-client/main.c
+++ b/examples/mqtt-over-ws-client/main.c
@@ -13,7 +13,7 @@
static const char *s_url =
#if MG_TLS
- "wss://broker.hivemq.com:8884/mqtt";
+ "wss://192.168.192.2:8086/mqtt";
#else
"ws://broker.hivemq.com:8000/mqtt";
#endif
@@ -26,7 +26,7 @@ static void fn(struct mg_connection *c, int ev, void *ev_data, void *fn_data) {
MG_ERROR(("%p %s", c->fd, (char *) ev_data));
} else if (ev == MG_EV_CONNECT) {
if (mg_url_is_ssl(s_url)) {
- struct mg_tls_opts opts = {.ca = mg_unpacked("/certs/ca.pem"),
+ struct mg_tls_opts opts = {.ca = mg_unpacked("/home/wangha/Documents/nanomq/etc/certs/cacert.pem"),
.name = mg_url_host(s_url)};
mg_tls_init(c, &opts);
}
@@ -98,7 +98,7 @@ int main(void) {
bool done = false; // Event handler flips it to true when done
mg_mgr_init(&mgr); // Initialise event manager
mg_log_set(MG_LL_DEBUG); // Set log level
- mg_ws_connect(&mgr, s_url, fn, &done, NULL); // Create client connection
+ mg_ws_connect(&mgr, s_url, fn, &done, "Sec-WebSocket-Protocol: mqtt\r\n"); // Create client connection
while (done == false) mg_mgr_poll(&mgr, 1000); // Event loop
mg_mgr_free(&mgr); // Finished, cleanup
return 0;
我是直接改这里的
struct mg_connection *mg_ws_connect(struct mg_mgr *mgr, const char *url,
mg_event_handler_t fn, void *fn_data,
const char *fmt, ...) {
struct mg_connection *c = mg_connect(mgr, url, fn, fn_data);
if (c != NULL) {
char nonce[16], key[30];
struct mg_str host = mg_url_host(url);
mg_random(nonce, sizeof(nonce));
mg_base64_encode((unsigned char *) nonce, sizeof(nonce), key, sizeof(key));
mg_xprintf(mg_pfn_iobuf, &c->send,
"GET %s HTTP/1.1\r\n"
"Upgrade: websocket\r\n"
"Host: %.*s\r\n"
"Connection: Upgrade\r\n"
"Sec-WebSocket-Extensions: permessage-deflate; client_max_window_bits\r\n"
"Sec-WebSocket-Protocol: mqtt\r\n"
"Sec-WebSocket-Version: 13\r\n"
"Sec-WebSocket-Key: %s\r\n",
mg_url_uri(url), (int) host.len, host.ptr, key);