Commit 83fe5a17 authored by Deomid Ryabkov's avatar Deomid Ryabkov Committed by Cesanta Bot

Make mg_connect_{http,ws} use mg_parse_uri

Remove the specialized URI parser, clean up code a bit.

Fix parsing of URIs with IPv6 hosts (http://[2001:2:3::4]:567/)

PUBLISHED_FROM=968ad97585d928123106ce3828920ee073113f83
parent 49bbfaf1
...@@ -11,6 +11,7 @@ items: ...@@ -11,6 +11,7 @@ items:
- { name: mg_send_websocket_handshake.md } - { name: mg_send_websocket_handshake.md }
- { name: mg_send_websocket_handshake2.md } - { name: mg_send_websocket_handshake2.md }
- { name: mg_send_websocket_handshake3.md } - { name: mg_send_websocket_handshake3.md }
- { name: mg_send_websocket_handshake3v.md }
- { name: mg_set_protocol_http_websocket.md } - { name: mg_set_protocol_http_websocket.md }
- { name: mg_url_decode.md } - { name: mg_url_decode.md }
- { name: struct_http_message.md } - { name: struct_http_message.md }
......
...@@ -9,5 +9,6 @@ signature: | ...@@ -9,5 +9,6 @@ signature: |
Sends multiple websocket frames. Sends multiple websocket frames.
Like `mg_send_websocket_frame()`, but composes a frame from multiple buffers. Like `mg_send_websocket_frame()`, but composes a frame from multiple
*buffers.
---
title: "mg_send_websocket_handshake3v()"
decl_name: "mg_send_websocket_handshake3v"
symbol_kind: "func"
signature: |
void mg_send_websocket_handshake3v(struct mg_connection *nc,
const struct mg_str path,
const struct mg_str host,
const struct mg_str protocol,
const struct mg_str extra_headers,
const struct mg_str user,
const struct mg_str pass);
---
Same as mg_send_websocket_handshake3 but with strings not necessarily
NUL-temrinated
...@@ -13,6 +13,7 @@ Source string is specified by (`src`, `src_len`), and destination is ...@@ -13,6 +13,7 @@ Source string is specified by (`src`, `src_len`), and destination is
(`dst`, `dst_len`). If `is_form_url_encoded` is non-zero, then (`dst`, `dst_len`). If `is_form_url_encoded` is non-zero, then
`+` character is decoded as a blank space character. This function `+` character is decoded as a blank space character. This function
guarantees to NUL-terminate the destination. If destination is too small, guarantees to NUL-terminate the destination. If destination is too small,
then the source string is partially decoded and `-1` is returned. Otherwise, then the source string is partially decoded and `-1` is returned.
*Otherwise,
a length of the decoded string is returned, not counting final NUL. a length of the decoded string is returned, not counting final NUL.
...@@ -3,7 +3,7 @@ title: "mg_parse_uri()" ...@@ -3,7 +3,7 @@ title: "mg_parse_uri()"
decl_name: "mg_parse_uri" decl_name: "mg_parse_uri"
symbol_kind: "func" symbol_kind: "func"
signature: | signature: |
int mg_parse_uri(struct mg_str uri, struct mg_str *scheme, int mg_parse_uri(const struct mg_str uri, struct mg_str *scheme,
struct mg_str *user_info, struct mg_str *host, struct mg_str *user_info, struct mg_str *host,
unsigned int *port, struct mg_str *path, struct mg_str *query, unsigned int *port, struct mg_str *path, struct mg_str *query,
struct mg_str *fragment); struct mg_str *fragment);
......
...@@ -3,7 +3,8 @@ title: "mg_basic_auth_header()" ...@@ -3,7 +3,8 @@ title: "mg_basic_auth_header()"
decl_name: "mg_basic_auth_header" decl_name: "mg_basic_auth_header"
symbol_kind: "func" symbol_kind: "func"
signature: | signature: |
void mg_basic_auth_header(const char *user, const char *pass, struct mbuf *buf); void mg_basic_auth_header(const struct mg_str user, const struct mg_str pass,
struct mbuf *buf);
--- ---
Generate a Basic Auth header and appends it to buf. Generate a Basic Auth header and appends it to buf.
......
...@@ -97,11 +97,6 @@ MG_INTERNAL size_t mg_handle_chunked(struct mg_connection *nc, ...@@ -97,11 +97,6 @@ MG_INTERNAL size_t mg_handle_chunked(struct mg_connection *nc,
struct http_message *hm, char *buf, struct http_message *hm, char *buf,
size_t blen); size_t blen);
MG_INTERNAL int mg_http_common_url_parse(const char *url, const char *schema,
const char *schema_tls, int *use_ssl,
char **user, char **pass, char **addr,
int *port_i, const char **path);
#if MG_ENABLE_FILESYSTEM #if MG_ENABLE_FILESYSTEM
MG_INTERNAL int mg_uri_to_local_path(struct http_message *hm, MG_INTERNAL int mg_uri_to_local_path(struct http_message *hm,
const struct mg_serve_http_opts *opts, const struct mg_serve_http_opts *opts,
...@@ -153,11 +148,6 @@ MG_INTERNAL int mg_get_errno(void); ...@@ -153,11 +148,6 @@ MG_INTERNAL int mg_get_errno(void);
MG_INTERNAL void mg_close_conn(struct mg_connection *conn); MG_INTERNAL void mg_close_conn(struct mg_connection *conn);
MG_INTERNAL int mg_http_common_url_parse(const char *url, const char *schema,
const char *schema_tls, int *use_ssl,
char **user, char **pass, char **addr,
int *port_i, const char **path);
#if MG_ENABLE_SNTP #if MG_ENABLE_SNTP
MG_INTERNAL int mg_sntp_parse_reply(const char *buf, int len, MG_INTERNAL int mg_sntp_parse_reply(const char *buf, int len,
struct mg_sntp_message *msg); struct mg_sntp_message *msg);
...@@ -4853,7 +4843,7 @@ static void parse_uri_component(const char **p, const char *end, char sep, ...@@ -4853,7 +4843,7 @@ static void parse_uri_component(const char **p, const char *end, char sep,
if (*p < end) (*p)++; if (*p < end) (*p)++;
} }
int mg_parse_uri(struct mg_str uri, struct mg_str *scheme, int mg_parse_uri(const struct mg_str uri, struct mg_str *scheme,
struct mg_str *user_info, struct mg_str *host, struct mg_str *user_info, struct mg_str *host,
unsigned int *port, struct mg_str *path, struct mg_str *query, unsigned int *port, struct mg_str *path, struct mg_str *query,
struct mg_str *fragment) { struct mg_str *fragment) {
...@@ -4877,8 +4867,13 @@ int mg_parse_uri(struct mg_str uri, struct mg_str *scheme, ...@@ -4877,8 +4867,13 @@ int mg_parse_uri(struct mg_str uri, struct mg_str *scheme,
* expecting on of: * expecting on of:
* - `scheme://xxxx` * - `scheme://xxxx`
* - `xxxx:port` * - `xxxx:port`
* - `[a:b:c]:port`
* - `xxxx/path` * - `xxxx/path`
*/ */
if (*p == '[') {
state = P_HOST;
break;
}
for (; p < end; p++) { for (; p < end; p++) {
if (*p == ':') { if (*p == ':') {
state = P_SCHEME_OR_PORT; state = P_SCHEME_OR_PORT;
...@@ -4898,7 +4893,7 @@ int mg_parse_uri(struct mg_str uri, struct mg_str *scheme, ...@@ -4898,7 +4893,7 @@ int mg_parse_uri(struct mg_str uri, struct mg_str *scheme,
rscheme.p = uri.p; rscheme.p = uri.p;
rscheme.len = p - uri.p; rscheme.len = p - uri.p;
state = P_USER_INFO; state = P_USER_INFO;
p += 2; /* point to last separator char */ p += 3;
} else { } else {
rhost.p = uri.p; rhost.p = uri.p;
rhost.len = p - uri.p; rhost.len = p - uri.p;
...@@ -4906,27 +4901,35 @@ int mg_parse_uri(struct mg_str uri, struct mg_str *scheme, ...@@ -4906,27 +4901,35 @@ int mg_parse_uri(struct mg_str uri, struct mg_str *scheme,
} }
break; break;
case P_USER_INFO: case P_USER_INFO:
p++;
ruser_info.p = p; ruser_info.p = p;
for (; p < end; p++) { for (; p < end; p++) {
if (*p == '@') { if (*p == '@' || *p == '[') {
state = P_HOST;
break;
} else if (*p == '/') {
break; break;
} }
} }
if (p == end || *p == '/') { if (p == end || *p == '/' || *p == '[') {
/* backtrack and parse as host */ /* backtrack and parse as host */
state = P_HOST;
p = ruser_info.p; p = ruser_info.p;
} }
ruser_info.len = p - ruser_info.p; ruser_info.len = p - ruser_info.p;
state = P_HOST;
break; break;
case P_HOST: case P_HOST:
if (*p == '@') p++; if (*p == '@') p++;
rhost.p = p; rhost.p = p;
for (; p < end; p++) { if (*p == '[') {
int found = 0;
for (; !found && p < end; p++) {
found = (*p == ']');
}
if (!found) return -1;
} else {
for (; p < end; p++) {
if (*p == ':' || *p == '/') break;
}
}
rhost.len = p - rhost.p;
if (p < end) {
if (*p == ':') { if (*p == ':') {
state = P_PORT; state = P_PORT;
break; break;
...@@ -4935,7 +4938,6 @@ int mg_parse_uri(struct mg_str uri, struct mg_str *scheme, ...@@ -4935,7 +4938,6 @@ int mg_parse_uri(struct mg_str uri, struct mg_str *scheme,
break; break;
} }
} }
rhost.len = p - rhost.p;
break; break;
case P_PORT: case P_PORT:
p++; p++;
...@@ -5095,7 +5097,8 @@ static void mg_http_conn_destructor(void *proto_data); ...@@ -5095,7 +5097,8 @@ static void mg_http_conn_destructor(void *proto_data);
struct mg_connection *mg_connect_http_base( struct mg_connection *mg_connect_http_base(
struct mg_mgr *mgr, MG_CB(mg_event_handler_t ev_handler, void *user_data), struct mg_mgr *mgr, MG_CB(mg_event_handler_t ev_handler, void *user_data),
struct mg_connect_opts opts, const char *schema, const char *schema_ssl, struct mg_connect_opts opts, const char *schema, const char *schema_ssl,
const char *url, const char **path, char **user, char **pass, char **addr); const char *url, struct mg_str *path, struct mg_str *user_info,
struct mg_str *host);
static struct mg_http_proto_data *mg_http_get_proto_data( static struct mg_http_proto_data *mg_http_get_proto_data(
struct mg_connection *c) { struct mg_connection *c) {
...@@ -7089,20 +7092,19 @@ void mg_http_reverse_proxy(struct mg_connection *nc, ...@@ -7089,20 +7092,19 @@ void mg_http_reverse_proxy(struct mg_connection *nc,
struct mg_str upstream) { struct mg_str upstream) {
struct mg_connection *be; struct mg_connection *be;
char burl[256], *purl = burl; char burl[256], *purl = burl;
char *addr = NULL;
const char *path = NULL;
int i; int i;
const char *error; const char *error;
struct mg_connect_opts opts; struct mg_connect_opts opts;
struct mg_str path = MG_NULL_STR, user_info = MG_NULL_STR, host = MG_NULL_STR;
memset(&opts, 0, sizeof(opts)); memset(&opts, 0, sizeof(opts));
opts.error_string = &error; opts.error_string = &error;
mg_asprintf(&purl, sizeof(burl), "%.*s%.*s", (int) upstream.len, upstream.p, mg_asprintf(&purl, sizeof(burl), "%.*s%.*s", (int) upstream.len, upstream.p,
(int) (hm->uri.len - mount.len), hm->uri.p + mount.len); (int) (hm->uri.len - mount.len), hm->uri.p + mount.len);
be = mg_connect_http_base(nc->mgr, MG_CB(mg_reverse_proxy_handler, NULL), be =
opts, "http://", "https://", purl, &path, mg_connect_http_base(nc->mgr, MG_CB(mg_reverse_proxy_handler, NULL), opts,
NULL /* user */, NULL /* pass */, &addr); "http", "https", purl, &path, &user_info, &host);
LOG(LL_DEBUG, ("Proxying %.*s to %s (rule: %.*s)", (int) hm->uri.len, LOG(LL_DEBUG, ("Proxying %.*s to %s (rule: %.*s)", (int) hm->uri.len,
hm->uri.p, purl, (int) mount.len, mount.p)); hm->uri.p, purl, (int) mount.len, mount.p));
...@@ -7117,10 +7119,10 @@ void mg_http_reverse_proxy(struct mg_connection *nc, ...@@ -7117,10 +7119,10 @@ void mg_http_reverse_proxy(struct mg_connection *nc,
mg_http_get_proto_data(nc)->reverse_proxy_data.linked_conn = be; mg_http_get_proto_data(nc)->reverse_proxy_data.linked_conn = be;
/* send request upstream */ /* send request upstream */
mg_printf(be, "%.*s %s HTTP/1.1\r\n", (int) hm->method.len, hm->method.p, mg_printf(be, "%.*s %.*s HTTP/1.1\r\n", (int) hm->method.len, hm->method.p,
path); (int) path.len, path.p);
mg_printf(be, "Host: %s\r\n", addr); mg_printf(be, "Host: %.*s\r\n", (int) host.len, host.p);
for (i = 0; i < MG_MAX_HTTP_HEADERS && hm->header_names[i].len > 0; i++) { for (i = 0; i < MG_MAX_HTTP_HEADERS && hm->header_names[i].len > 0; i++) {
struct mg_str hn = hm->header_names[i]; struct mg_str hn = hm->header_names[i];
struct mg_str hv = hm->header_values[i]; struct mg_str hv = hm->header_values[i];
...@@ -7704,103 +7706,39 @@ void mg_file_upload_handler(struct mg_connection *nc, int ev, void *ev_data, ...@@ -7704,103 +7706,39 @@ void mg_file_upload_handler(struct mg_connection *nc, int ev, void *ev_data,
#endif /* MG_ENABLE_HTTP_STREAMING_MULTIPART */ #endif /* MG_ENABLE_HTTP_STREAMING_MULTIPART */
#endif /* MG_ENABLE_FILESYSTEM */ #endif /* MG_ENABLE_FILESYSTEM */
/* returns 0 on success, -1 on error */
MG_INTERNAL int mg_http_common_url_parse(const char *url, const char *schema,
const char *schema_tls, int *use_ssl,
char **user, char **pass, char **addr,
int *port_i, const char **path) {
int addr_len = 0;
int auth_sep_pos = -1;
int user_sep_pos = -1;
int port_pos = -1;
(void) user;
(void) pass;
if (strncmp(url, schema, strlen(schema)) == 0) {
url += strlen(schema);
} else if (strncmp(url, schema_tls, strlen(schema_tls)) == 0) {
url += strlen(schema_tls);
*use_ssl = 1;
#if !MG_ENABLE_SSL
return -1; /* SSL is not enabled, cannot do HTTPS URLs */
#endif
}
while (*url != '\0') {
*addr = (char *) MG_REALLOC(*addr, addr_len + 6 /* space for port too. */);
if (*addr == NULL) {
DBG(("OOM"));
return -1;
}
if (*url == '/') {
break;
}
if (*url == '@') {
auth_sep_pos = addr_len;
user_sep_pos = port_pos;
port_pos = -1;
}
if (*url == ':') port_pos = addr_len;
(*addr)[addr_len++] = *url;
(*addr)[addr_len] = '\0';
url++;
}
if (addr_len == 0) goto cleanup;
if (port_pos < 0) {
*port_i = addr_len;
addr_len += sprintf(*addr + addr_len, ":%d", *use_ssl ? 443 : 80);
} else {
*port_i = -1;
}
if (*path == NULL) *path = url;
if (**path == '\0') *path = "/";
if (user != NULL && pass != NULL) {
if (auth_sep_pos == -1) {
*user = NULL;
*pass = NULL;
} else {
/* user is from 0 to user_sep_pos */
*user = (char *) MG_MALLOC(user_sep_pos + 1);
memcpy(*user, *addr, user_sep_pos);
(*user)[user_sep_pos] = '\0';
/* pass is from user_sep_pos + 1 to auth_sep_pos */
*pass = (char *) MG_MALLOC(auth_sep_pos - user_sep_pos - 1 + 1);
memcpy(*pass, *addr + user_sep_pos + 1, auth_sep_pos - user_sep_pos - 1);
(*pass)[auth_sep_pos - user_sep_pos - 1] = '\0';
/* move address proper to the front */
memmove(*addr, *addr + auth_sep_pos + 1, addr_len - auth_sep_pos);
}
}
DBG(("%s %s", *addr, *path));
return 0;
cleanup:
MG_FREE(*addr);
return -1;
}
struct mg_connection *mg_connect_http_base( struct mg_connection *mg_connect_http_base(
struct mg_mgr *mgr, MG_CB(mg_event_handler_t ev_handler, void *user_data), struct mg_mgr *mgr, MG_CB(mg_event_handler_t ev_handler, void *user_data),
struct mg_connect_opts opts, const char *schema, const char *schema_ssl, struct mg_connect_opts opts, const char *schema, const char *schema_ssl,
const char *url, const char **path, char **user, char **pass, char **addr) { const char *url, struct mg_str *path, struct mg_str *user_info,
struct mg_str *host) {
struct mg_connection *nc = NULL; struct mg_connection *nc = NULL;
int port_i = -1; unsigned int port_i = 0;
int use_ssl = 0; int use_ssl = 0;
struct mg_str scheme, query, fragment;
char conn_addr_buf[2];
char *conn_addr = conn_addr_buf;
if (mg_http_common_url_parse(url, schema, schema_ssl, &use_ssl, user, pass, if (mg_parse_uri(mg_mk_str(url), &scheme, user_info, host, &port_i, path,
addr, &port_i, path) < 0) { &query, &fragment) != 0) {
MG_SET_PTRPTR(opts.error_string, "cannot parse url"); MG_SET_PTRPTR(opts.error_string, "cannot parse url");
return NULL; goto out;
} }
LOG(LL_DEBUG, ("%s use_ssl? %d", url, use_ssl)); if (mg_vcmp(&scheme, schema) == 0) {
use_ssl = 0;
if (port_i == 0) port_i = 80;
} else if (mg_vcmp(&scheme, schema_ssl) == 0) {
use_ssl = 1;
if (port_i == 0) port_i = 443;
} else {
goto out;
}
mg_asprintf(&conn_addr, sizeof(conn_addr_buf), "tcp://%.*s:%u",
(int) host->len, host->p, port_i);
if (conn_addr == NULL) goto out;
LOG(LL_DEBUG, ("%s use_ssl? %d %s", url, use_ssl, conn_addr));
if (use_ssl) { if (use_ssl) {
#if MG_ENABLE_SSL #if MG_ENABLE_SSL
/* /*
...@@ -7813,20 +7751,17 @@ struct mg_connection *mg_connect_http_base( ...@@ -7813,20 +7751,17 @@ struct mg_connection *mg_connect_http_base(
} }
#else #else
MG_SET_PTRPTR(opts.error_string, "ssl is disabled"); MG_SET_PTRPTR(opts.error_string, "ssl is disabled");
if (user != NULL) MG_FREE(*user); goto out;
if (pass != NULL) MG_FREE(*pass);
MG_FREE(*addr);
return NULL;
#endif #endif
} }
if ((nc = mg_connect_opt(mgr, *addr, MG_CB(ev_handler, user_data), opts)) != if ((nc = mg_connect_opt(mgr, conn_addr, MG_CB(ev_handler, user_data),
NULL) { opts)) != NULL) {
mg_set_protocol_http_websocket(nc); mg_set_protocol_http_websocket(nc);
/* If the port was addred by us, restore the original host. */
if (port_i >= 0) (*addr)[port_i] = '\0';
} }
out:
if (conn_addr != NULL && conn_addr != conn_addr_buf) MG_FREE(conn_addr);
return nc; return nc;
} }
...@@ -7834,35 +7769,33 @@ struct mg_connection *mg_connect_http_opt( ...@@ -7834,35 +7769,33 @@ struct mg_connection *mg_connect_http_opt(
struct mg_mgr *mgr, MG_CB(mg_event_handler_t ev_handler, void *user_data), struct mg_mgr *mgr, MG_CB(mg_event_handler_t ev_handler, void *user_data),
struct mg_connect_opts opts, const char *url, const char *extra_headers, struct mg_connect_opts opts, const char *url, const char *extra_headers,
const char *post_data) { const char *post_data) {
char *user = NULL, *pass = NULL, *addr = NULL; struct mg_str user = MG_NULL_STR, null_str = MG_NULL_STR;
const char *path = NULL; struct mg_str host = MG_NULL_STR, path = MG_NULL_STR;
struct mbuf auth; struct mbuf auth;
struct mg_connection *nc = struct mg_connection *nc =
mg_connect_http_base(mgr, MG_CB(ev_handler, user_data), opts, "http://", mg_connect_http_base(mgr, MG_CB(ev_handler, user_data), opts, "http",
"https://", url, &path, &user, &pass, &addr); "https", url, &path, &user, &host);
if (nc == NULL) { if (nc == NULL) {
return NULL; return NULL;
} }
mbuf_init(&auth, 0); mbuf_init(&auth, 0);
if (user != NULL) { if (user.len > 0) {
mg_basic_auth_header(user, pass, &auth); mg_basic_auth_header(user, null_str, &auth);
} }
if (post_data == NULL) post_data = ""; if (post_data == NULL) post_data = "";
if (extra_headers == NULL) extra_headers = ""; if (extra_headers == NULL) extra_headers = "";
if (path.len == 0) path = mg_mk_str("/");
mg_printf(nc, "%s %s HTTP/1.1\r\nHost: %s\r\nContent-Length: %" SIZE_T_FMT mg_printf(nc, "%s %.*s HTTP/1.1\r\nHost: %.*s\r\nContent-Length: %" SIZE_T_FMT
"\r\n%.*s%s\r\n%s", "\r\n%.*s%s\r\n%s",
post_data[0] == '\0' ? "GET" : "POST", path, addr, (post_data[0] == '\0' ? "GET" : "POST"), (int) path.len, path.p,
strlen(post_data), (int) auth.len, (int) host.len, host.p, strlen(post_data), (int) auth.len,
(auth.buf == NULL ? "" : auth.buf), extra_headers, post_data); (auth.buf == NULL ? "" : auth.buf), extra_headers, post_data);
mbuf_free(&auth); mbuf_free(&auth);
MG_FREE(user);
MG_FREE(pass);
MG_FREE(addr);
return nc; return nc;
} }
...@@ -8974,8 +8907,6 @@ MG_INTERNAL void mg_handle_put(struct mg_connection *nc, const char *path, ...@@ -8974,8 +8907,6 @@ MG_INTERNAL void mg_handle_put(struct mg_connection *nc, const char *path,
#define MG_WEBSOCKET_PING_INTERVAL_SECONDS 5 #define MG_WEBSOCKET_PING_INTERVAL_SECONDS 5
#endif #endif
#define MG_WS_NO_HOST_HEADER_MAGIC ((char *) 0x1)
static int mg_is_ws_fragment(unsigned char flags) { static int mg_is_ws_fragment(unsigned char flags) {
return (flags & 0x80) == 0 || (flags & 0x0f) == 0; return (flags & 0x80) == 0 || (flags & 0x0f) == 0;
} }
...@@ -9283,6 +9214,18 @@ void mg_send_websocket_handshake3(struct mg_connection *nc, const char *path, ...@@ -9283,6 +9214,18 @@ void mg_send_websocket_handshake3(struct mg_connection *nc, const char *path,
const char *host, const char *protocol, const char *host, const char *protocol,
const char *extra_headers, const char *user, const char *extra_headers, const char *user,
const char *pass) { const char *pass) {
mg_send_websocket_handshake3v(nc, mg_mk_str(path), mg_mk_str(host),
mg_mk_str(protocol), mg_mk_str(extra_headers),
mg_mk_str(user), mg_mk_str(pass));
}
void mg_send_websocket_handshake3v(struct mg_connection *nc,
const struct mg_str path,
const struct mg_str host,
const struct mg_str protocol,
const struct mg_str extra_headers,
const struct mg_str user,
const struct mg_str pass) {
struct mbuf auth; struct mbuf auth;
char key[25]; char key[25];
uint32_t nonce[4]; uint32_t nonce[4];
...@@ -9293,7 +9236,7 @@ void mg_send_websocket_handshake3(struct mg_connection *nc, const char *path, ...@@ -9293,7 +9236,7 @@ void mg_send_websocket_handshake3(struct mg_connection *nc, const char *path,
mg_base64_encode((unsigned char *) &nonce, sizeof(nonce), key); mg_base64_encode((unsigned char *) &nonce, sizeof(nonce), key);
mbuf_init(&auth, 0); mbuf_init(&auth, 0);
if (user != NULL) { if (user.len > 0) {
mg_basic_auth_header(user, pass, &auth); mg_basic_auth_header(user, pass, &auth);
} }
...@@ -9304,23 +9247,25 @@ void mg_send_websocket_handshake3(struct mg_connection *nc, const char *path, ...@@ -9304,23 +9247,25 @@ void mg_send_websocket_handshake3(struct mg_connection *nc, const char *path,
* because it handles NULL specially (and incorrectly). * because it handles NULL specially (and incorrectly).
*/ */
mg_printf(nc, mg_printf(nc,
"GET %s HTTP/1.1\r\n" "GET %.*s HTTP/1.1\r\n"
"Upgrade: websocket\r\n" "Upgrade: websocket\r\n"
"Connection: Upgrade\r\n" "Connection: Upgrade\r\n"
"%.*s" "%.*s"
"Sec-WebSocket-Version: 13\r\n" "Sec-WebSocket-Version: 13\r\n"
"Sec-WebSocket-Key: %s\r\n", "Sec-WebSocket-Key: %s\r\n",
path, (int) auth.len, (auth.buf == NULL ? "" : auth.buf), key); (int) path.len, path.p, (int) auth.len,
(auth.buf == NULL ? "" : auth.buf), key);
/* TODO(mkm): take default hostname from http proto data if host == NULL */ /* TODO(mkm): take default hostname from http proto data if host == NULL */
if (host != MG_WS_NO_HOST_HEADER_MAGIC) { if (host.len > 0) {
mg_printf(nc, "Host: %s\r\n", host); mg_printf(nc, "Host: %.*s\r\n", (int) host.len, host.p);
} }
if (protocol != NULL) { if (protocol.len > 0) {
mg_printf(nc, "Sec-WebSocket-Protocol: %s\r\n", protocol); mg_printf(nc, "Sec-WebSocket-Protocol: %.*s\r\n", (int) protocol.len,
protocol.p);
} }
if (extra_headers != NULL) { if (extra_headers.len > 0) {
mg_printf(nc, "%s", extra_headers); mg_printf(nc, "%.*s", (int) extra_headers.len, extra_headers.p);
} }
mg_printf(nc, "\r\n"); mg_printf(nc, "\r\n");
...@@ -9329,28 +9274,26 @@ void mg_send_websocket_handshake3(struct mg_connection *nc, const char *path, ...@@ -9329,28 +9274,26 @@ void mg_send_websocket_handshake3(struct mg_connection *nc, const char *path,
void mg_send_websocket_handshake(struct mg_connection *nc, const char *path, void mg_send_websocket_handshake(struct mg_connection *nc, const char *path,
const char *extra_headers) { const char *extra_headers) {
mg_send_websocket_handshake2(nc, path, MG_WS_NO_HOST_HEADER_MAGIC, NULL, struct mg_str null_str = MG_NULL_STR;
extra_headers); mg_send_websocket_handshake3v(
nc, mg_mk_str(path), null_str /* host */, null_str /* protocol */,
mg_mk_str(extra_headers), null_str /* user */, null_str /* pass */);
} }
struct mg_connection *mg_connect_ws_opt( struct mg_connection *mg_connect_ws_opt(
struct mg_mgr *mgr, MG_CB(mg_event_handler_t ev_handler, void *user_data), struct mg_mgr *mgr, MG_CB(mg_event_handler_t ev_handler, void *user_data),
struct mg_connect_opts opts, const char *url, const char *protocol, struct mg_connect_opts opts, const char *url, const char *protocol,
const char *extra_headers) { const char *extra_headers) {
char *user = NULL, *pass = NULL, *addr = NULL; struct mg_str null_str = MG_NULL_STR;
const char *path = NULL; struct mg_str host = MG_NULL_STR, path = MG_NULL_STR, user_info = MG_NULL_STR;
struct mg_connection *nc = struct mg_connection *nc =
mg_connect_http_base(mgr, MG_CB(ev_handler, user_data), opts, "ws://", mg_connect_http_base(mgr, MG_CB(ev_handler, user_data), opts, "ws", "wss",
"wss://", url, &path, &user, &pass, &addr); url, &path, &user_info, &host);
if (nc != NULL) { if (nc != NULL) {
mg_send_websocket_handshake3(nc, path, addr, protocol, extra_headers, user, mg_send_websocket_handshake3v(nc, path, host, mg_mk_str(protocol),
pass); mg_mk_str(extra_headers), user_info,
null_str);
} }
MG_FREE(addr);
MG_FREE(user);
MG_FREE(pass);
return nc; return nc;
} }
...@@ -9749,7 +9692,7 @@ void mg_mbuf_append_base64(struct mbuf *mbuf, const void *data, size_t len) { ...@@ -9749,7 +9692,7 @@ void mg_mbuf_append_base64(struct mbuf *mbuf, const void *data, size_t len) {
cs_base64_finish(&ctx); cs_base64_finish(&ctx);
} }
void mg_basic_auth_header(const char *user, const char *pass, void mg_basic_auth_header(const struct mg_str user, const struct mg_str pass,
struct mbuf *buf) { struct mbuf *buf) {
const char *header_prefix = "Authorization: Basic "; const char *header_prefix = "Authorization: Basic ";
const char *header_suffix = "\r\n"; const char *header_suffix = "\r\n";
...@@ -9759,10 +9702,10 @@ void mg_basic_auth_header(const char *user, const char *pass, ...@@ -9759,10 +9702,10 @@ void mg_basic_auth_header(const char *user, const char *pass,
mbuf_append(buf, header_prefix, strlen(header_prefix)); mbuf_append(buf, header_prefix, strlen(header_prefix));
cs_base64_update(&ctx, user, strlen(user)); cs_base64_update(&ctx, user.p, user.len);
if (pass != NULL) { if (pass.len > 0) {
cs_base64_update(&ctx, ":", 1); cs_base64_update(&ctx, ":", 1);
cs_base64_update(&ctx, pass, strlen(pass)); cs_base64_update(&ctx, pass.p, pass.len);
} }
cs_base64_finish(&ctx); cs_base64_finish(&ctx);
mbuf_append(buf, header_suffix, strlen(header_suffix)); mbuf_append(buf, header_suffix, strlen(header_suffix));
......
...@@ -1774,6 +1774,8 @@ struct mg_str mg_mk_str_n(const char *s, size_t len); ...@@ -1774,6 +1774,8 @@ struct mg_str mg_mk_str_n(const char *s, size_t len);
/* Macro for initializing mg_str. */ /* Macro for initializing mg_str. */
#define MG_MK_STR(str_literal) \ #define MG_MK_STR(str_literal) \
{ str_literal, sizeof(str_literal) - 1 } { str_literal, sizeof(str_literal) - 1 }
#define MG_NULL_STR \
{ NULL, 0 }
/* /*
* Cross-platform version of `strcmp()` where where first string is * Cross-platform version of `strcmp()` where where first string is
...@@ -3828,7 +3830,7 @@ extern "C" { ...@@ -3828,7 +3830,7 @@ extern "C" {
* *
* Returns 0 on success, -1 on error. * Returns 0 on success, -1 on error.
*/ */
int mg_parse_uri(struct mg_str uri, struct mg_str *scheme, int mg_parse_uri(const struct mg_str uri, struct mg_str *scheme,
struct mg_str *user_info, struct mg_str *host, struct mg_str *user_info, struct mg_str *host,
unsigned int *port, struct mg_str *path, struct mg_str *query, unsigned int *port, struct mg_str *path, struct mg_str *query,
struct mg_str *fragment); struct mg_str *fragment);
...@@ -4056,7 +4058,8 @@ void mg_mbuf_append_base64(struct mbuf *mbuf, const void *data, size_t len); ...@@ -4056,7 +4058,8 @@ void mg_mbuf_append_base64(struct mbuf *mbuf, const void *data, size_t len);
* If pass is NULL, then user is expected to contain the credentials pair * If pass is NULL, then user is expected to contain the credentials pair
* already encoded as `user:pass`. * already encoded as `user:pass`.
*/ */
void mg_basic_auth_header(const char *user, const char *pass, struct mbuf *buf); void mg_basic_auth_header(const struct mg_str user, const struct mg_str pass,
struct mbuf *buf);
#ifdef __cplusplus #ifdef __cplusplus
} }
...@@ -4280,6 +4283,17 @@ void mg_send_websocket_handshake3(struct mg_connection *nc, const char *path, ...@@ -4280,6 +4283,17 @@ void mg_send_websocket_handshake3(struct mg_connection *nc, const char *path,
const char *host, const char *protocol, const char *host, const char *protocol,
const char *extra_headers, const char *user, const char *extra_headers, const char *user,
const char *pass); const char *pass);
/* Same as mg_send_websocket_handshake3 but with strings not necessarily
* NUL-temrinated */
void mg_send_websocket_handshake3v(struct mg_connection *nc,
const struct mg_str path,
const struct mg_str host,
const struct mg_str protocol,
const struct mg_str extra_headers,
const struct mg_str user,
const struct mg_str pass);
/* /*
* Helper function that creates an outbound WebSocket connection. * Helper function that creates an outbound WebSocket connection.
* *
...@@ -4341,7 +4355,8 @@ void mg_send_websocket_frame(struct mg_connection *nc, int op_and_flags, ...@@ -4341,7 +4355,8 @@ void mg_send_websocket_frame(struct mg_connection *nc, int op_and_flags,
/* /*
* Sends multiple websocket frames. * Sends multiple websocket frames.
* *
* Like `mg_send_websocket_frame()`, but composes a frame from multiple buffers. * Like `mg_send_websocket_frame()`, but composes a frame from multiple
*buffers.
*/ */
void mg_send_websocket_framev(struct mg_connection *nc, int op_and_flags, void mg_send_websocket_framev(struct mg_connection *nc, int op_and_flags,
const struct mg_str *strings, int num_strings); const struct mg_str *strings, int num_strings);
...@@ -4386,7 +4401,8 @@ void mg_printf_websocket_frame(struct mg_connection *nc, int op_and_flags, ...@@ -4386,7 +4401,8 @@ void mg_printf_websocket_frame(struct mg_connection *nc, int op_and_flags,
* (`dst`, `dst_len`). If `is_form_url_encoded` is non-zero, then * (`dst`, `dst_len`). If `is_form_url_encoded` is non-zero, then
* `+` character is decoded as a blank space character. This function * `+` character is decoded as a blank space character. This function
* guarantees to NUL-terminate the destination. If destination is too small, * guarantees to NUL-terminate the destination. If destination is too small,
* then the source string is partially decoded and `-1` is returned. Otherwise, * then the source string is partially decoded and `-1` is returned.
*Otherwise,
* a length of the decoded string is returned, not counting final NUL. * a length of the decoded string is returned, not counting final NUL.
*/ */
int mg_url_decode(const char *src, int src_len, char *dst, int dst_len, int mg_url_decode(const char *src, int src_len, char *dst, int dst_len,
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment