|
@@ -2912,7 +2912,6 @@ struct mg_connection {
|
|
* mg_get_connection_info_impl */
|
|
* mg_get_connection_info_impl */
|
|
#endif
|
|
#endif
|
|
|
|
|
|
- const char *host; /* Host (HTTP/1.1 header or SNI) */
|
|
|
|
SSL *ssl; /* SSL descriptor */
|
|
SSL *ssl; /* SSL descriptor */
|
|
struct socket client; /* Connected client */
|
|
struct socket client; /* Connected client */
|
|
time_t conn_birth_time; /* Time (wall clock) when connection was
|
|
time_t conn_birth_time; /* Time (wall clock) when connection was
|
|
@@ -4147,9 +4146,17 @@ mg_get_request_link(const struct mg_connection *conn, char *buf, size_t buflen)
|
|
&truncated,
|
|
&truncated,
|
|
buf,
|
|
buf,
|
|
buflen,
|
|
buflen,
|
|
|
|
+#if defined(USE_IPV6)
|
|
|
|
+ "%s://%s%s%s%s%s",
|
|
|
|
+ proto,
|
|
|
|
+ (is_ipv6 && (server_domain == server_ip)) ? "[" : "",
|
|
|
|
+ server_domain,
|
|
|
|
+ (is_ipv6 && (server_domain == server_ip)) ? "]" : "",
|
|
|
|
+#else
|
|
"%s://%s%s%s",
|
|
"%s://%s%s%s",
|
|
proto,
|
|
proto,
|
|
server_domain,
|
|
server_domain,
|
|
|
|
+#endif
|
|
portstr,
|
|
portstr,
|
|
ri->local_uri);
|
|
ri->local_uri);
|
|
if (truncated) {
|
|
if (truncated) {
|
|
@@ -13615,68 +13622,76 @@ get_first_ssl_listener_index(const struct mg_context *ctx)
|
|
|
|
|
|
|
|
|
|
/* Return host (without port) */
|
|
/* Return host (without port) */
|
|
-/* Use mg_free to free the result */
|
|
|
|
-static const char *
|
|
|
|
-alloc_get_host(struct mg_connection *conn)
|
|
|
|
|
|
+static void
|
|
|
|
+get_host_from_request_info(struct vec *host, const struct mg_request_info *ri)
|
|
{
|
|
{
|
|
- char buf[1025];
|
|
|
|
- size_t buflen = sizeof(buf);
|
|
|
|
- const char *host_header = get_header(conn->request_info.http_headers,
|
|
|
|
- conn->request_info.num_headers,
|
|
|
|
- "Host");
|
|
|
|
- char *host;
|
|
|
|
|
|
+ const char *host_header =
|
|
|
|
+ get_header(ri->http_headers, ri->num_headers, "Host");
|
|
|
|
+
|
|
|
|
+ host->ptr = NULL;
|
|
|
|
+ host->len = 0;
|
|
|
|
|
|
if (host_header != NULL) {
|
|
if (host_header != NULL) {
|
|
char *pos;
|
|
char *pos;
|
|
|
|
|
|
- /* Create a local copy of the "Host" header, since it might be
|
|
|
|
- * modified here. */
|
|
|
|
- mg_strlcpy(buf, host_header, buflen);
|
|
|
|
- buf[buflen - 1] = '\0';
|
|
|
|
- host = buf;
|
|
|
|
- while (isspace((unsigned char)*host)) {
|
|
|
|
- host++;
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
/* If the "Host" is an IPv6 address, like [::1], parse until ]
|
|
/* If the "Host" is an IPv6 address, like [::1], parse until ]
|
|
* is found. */
|
|
* is found. */
|
|
- if (*host == '[') {
|
|
|
|
- pos = strchr(host, ']');
|
|
|
|
|
|
+ if (*host_header == '[') {
|
|
|
|
+ pos = strchr(host_header, ']');
|
|
if (!pos) {
|
|
if (!pos) {
|
|
/* Malformed hostname starts with '[', but no ']' found */
|
|
/* Malformed hostname starts with '[', but no ']' found */
|
|
DEBUG_TRACE("%s", "Host name format error '[' without ']'");
|
|
DEBUG_TRACE("%s", "Host name format error '[' without ']'");
|
|
- return NULL;
|
|
|
|
|
|
+ return;
|
|
}
|
|
}
|
|
/* terminate after ']' */
|
|
/* terminate after ']' */
|
|
- pos[1] = 0;
|
|
|
|
|
|
+ host->ptr = host_header;
|
|
|
|
+ host->len = (size_t)(pos + 1 - host_header);
|
|
} else {
|
|
} else {
|
|
/* Otherwise, a ':' separates hostname and port number */
|
|
/* Otherwise, a ':' separates hostname and port number */
|
|
- pos = strchr(host, ':');
|
|
|
|
|
|
+ pos = strchr(host_header, ':');
|
|
if (pos != NULL) {
|
|
if (pos != NULL) {
|
|
- *pos = '\0';
|
|
|
|
|
|
+ host->len = (size_t)(pos - host_header);
|
|
|
|
+ } else {
|
|
|
|
+ host->len = strlen(host_header);
|
|
}
|
|
}
|
|
|
|
+ host->ptr = host_header;
|
|
}
|
|
}
|
|
|
|
+ }
|
|
|
|
+}
|
|
|
|
|
|
|
|
+
|
|
|
|
+static int
|
|
|
|
+switch_domain_context(struct mg_connection *conn)
|
|
|
|
+{
|
|
|
|
+ struct vec host;
|
|
|
|
+
|
|
|
|
+ get_host_from_request_info(&host, &conn->request_info);
|
|
|
|
+
|
|
|
|
+ if (host.ptr) {
|
|
if (conn->ssl) {
|
|
if (conn->ssl) {
|
|
/* This is a HTTPS connection, maybe we have a hostname
|
|
/* This is a HTTPS connection, maybe we have a hostname
|
|
* from SNI (set in ssl_servername_callback). */
|
|
* from SNI (set in ssl_servername_callback). */
|
|
const char *sslhost = conn->dom_ctx->config[AUTHENTICATION_DOMAIN];
|
|
const char *sslhost = conn->dom_ctx->config[AUTHENTICATION_DOMAIN];
|
|
if (sslhost && (conn->dom_ctx != &(conn->phys_ctx->dd))) {
|
|
if (sslhost && (conn->dom_ctx != &(conn->phys_ctx->dd))) {
|
|
/* We are not using the default domain */
|
|
/* We are not using the default domain */
|
|
- if (mg_strcasecmp(host, sslhost)) {
|
|
|
|
|
|
+ if ((strlen(sslhost) != host.len)
|
|
|
|
+ || mg_strncasecmp(host.ptr, sslhost, host.len)) {
|
|
/* Mismatch between SNI domain and HTTP domain */
|
|
/* Mismatch between SNI domain and HTTP domain */
|
|
- DEBUG_TRACE("Host mismatch: SNI: %s, HTTPS: %s",
|
|
|
|
|
|
+ DEBUG_TRACE("Host mismatch: SNI: %s, HTTPS: %.*s",
|
|
sslhost,
|
|
sslhost,
|
|
- host);
|
|
|
|
- return NULL;
|
|
|
|
|
|
+ (int)host.len,
|
|
|
|
+ host.ptr);
|
|
|
|
+ return 0;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
- DEBUG_TRACE("HTTPS Host: %s", host);
|
|
|
|
|
|
|
|
} else {
|
|
} else {
|
|
struct mg_domain_context *dom = &(conn->phys_ctx->dd);
|
|
struct mg_domain_context *dom = &(conn->phys_ctx->dd);
|
|
while (dom) {
|
|
while (dom) {
|
|
- if (!mg_strcasecmp(host, dom->config[AUTHENTICATION_DOMAIN])) {
|
|
|
|
|
|
+ if ((strlen(dom->config[AUTHENTICATION_DOMAIN]) == host.len)
|
|
|
|
+ && !mg_strncasecmp(host.ptr,
|
|
|
|
+ dom->config[AUTHENTICATION_DOMAIN],
|
|
|
|
+ host.len)) {
|
|
|
|
|
|
/* Found matching domain */
|
|
/* Found matching domain */
|
|
DEBUG_TRACE("HTTP domain %s found",
|
|
DEBUG_TRACE("HTTP domain %s found",
|
|
@@ -13690,31 +13705,33 @@ alloc_get_host(struct mg_connection *conn)
|
|
dom = dom->next;
|
|
dom = dom->next;
|
|
mg_unlock_context(conn->phys_ctx);
|
|
mg_unlock_context(conn->phys_ctx);
|
|
}
|
|
}
|
|
-
|
|
|
|
- DEBUG_TRACE("HTTP Host: %s", host);
|
|
|
|
}
|
|
}
|
|
|
|
|
|
} else {
|
|
} else {
|
|
- sockaddr_to_string(buf, buflen, &conn->client.lsa);
|
|
|
|
- host = buf;
|
|
|
|
-
|
|
|
|
- DEBUG_TRACE("IP: %s", host);
|
|
|
|
|
|
+ DEBUG_TRACE("HTTP%s Host is not set", conn->ssl ? "S" : "");
|
|
|
|
+ return 1;
|
|
}
|
|
}
|
|
|
|
|
|
- return mg_strdup_ctx(host, conn->phys_ctx);
|
|
|
|
|
|
+ DEBUG_TRACE("HTTP%s Host: %.*s",
|
|
|
|
+ conn->ssl ? "S" : "",
|
|
|
|
+ (int)host.len,
|
|
|
|
+ host.ptr);
|
|
|
|
+ return 1;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
static void
|
|
redirect_to_https_port(struct mg_connection *conn, int ssl_index)
|
|
redirect_to_https_port(struct mg_connection *conn, int ssl_index)
|
|
{
|
|
{
|
|
|
|
+ struct vec host;
|
|
char target_url[MG_BUF_LEN];
|
|
char target_url[MG_BUF_LEN];
|
|
int truncated = 0;
|
|
int truncated = 0;
|
|
|
|
|
|
conn->must_close = 1;
|
|
conn->must_close = 1;
|
|
|
|
|
|
/* Send host, port, uri and (if it exists) ?query_string */
|
|
/* Send host, port, uri and (if it exists) ?query_string */
|
|
- if (conn->host) {
|
|
|
|
|
|
+ get_host_from_request_info(&host, &conn->request_info);
|
|
|
|
+ if (host.ptr) {
|
|
|
|
|
|
/* Use "308 Permanent Redirect" */
|
|
/* Use "308 Permanent Redirect" */
|
|
int redirect_code = 308;
|
|
int redirect_code = 308;
|
|
@@ -13725,9 +13742,10 @@ redirect_to_https_port(struct mg_connection *conn, int ssl_index)
|
|
&truncated,
|
|
&truncated,
|
|
target_url,
|
|
target_url,
|
|
sizeof(target_url),
|
|
sizeof(target_url),
|
|
- "https://%s:%d%s%s%s",
|
|
|
|
|
|
+ "https://%.*s:%d%s%s%s",
|
|
|
|
|
|
- conn->host,
|
|
|
|
|
|
+ (int)host.len,
|
|
|
|
+ host.ptr,
|
|
#if defined(USE_IPV6)
|
|
#if defined(USE_IPV6)
|
|
(conn->phys_ctx->listening_sockets[ssl_index].lsa.sa.sa_family
|
|
(conn->phys_ctx->listening_sockets[ssl_index].lsa.sa.sa_family
|
|
== AF_INET6)
|
|
== AF_INET6)
|
|
@@ -13752,6 +13770,8 @@ redirect_to_https_port(struct mg_connection *conn, int ssl_index)
|
|
|
|
|
|
/* Use redirect helper function */
|
|
/* Use redirect helper function */
|
|
mg_send_http_redirect(conn, target_url, redirect_code);
|
|
mg_send_http_redirect(conn, target_url, redirect_code);
|
|
|
|
+ } else {
|
|
|
|
+ mg_send_http_error(conn, 400, "%s", "Bad Request");
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
@@ -17059,11 +17079,6 @@ close_connection(struct mg_connection *conn)
|
|
conn->client.sock = INVALID_SOCKET;
|
|
conn->client.sock = INVALID_SOCKET;
|
|
}
|
|
}
|
|
|
|
|
|
- if (conn->host) {
|
|
|
|
- mg_free((void *)conn->host);
|
|
|
|
- conn->host = NULL;
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
mg_unlock_connection(conn);
|
|
mg_unlock_connection(conn);
|
|
|
|
|
|
#if defined(USE_SERVER_STATS)
|
|
#if defined(USE_SERVER_STATS)
|
|
@@ -17770,12 +17785,7 @@ get_request(struct mg_connection *conn, char *ebuf, size_t ebuf_len, int *err)
|
|
|
|
|
|
/* Message is a valid request */
|
|
/* Message is a valid request */
|
|
|
|
|
|
- /* Is there a "host" ? */
|
|
|
|
- if (conn->host != NULL) {
|
|
|
|
- mg_free((void *)conn->host);
|
|
|
|
- }
|
|
|
|
- conn->host = alloc_get_host(conn);
|
|
|
|
- if (!conn->host) {
|
|
|
|
|
|
+ if (!switch_domain_context(conn)) {
|
|
mg_snprintf(conn,
|
|
mg_snprintf(conn,
|
|
NULL, /* No truncation check for ebuf */
|
|
NULL, /* No truncation check for ebuf */
|
|
ebuf,
|
|
ebuf,
|
|
@@ -18779,7 +18789,6 @@ worker_thread_run(struct mg_connection *conn)
|
|
conn->buf_size = (int)ctx->max_request_size;
|
|
conn->buf_size = (int)ctx->max_request_size;
|
|
|
|
|
|
conn->dom_ctx = &(ctx->dd); /* Use default domain and default host */
|
|
conn->dom_ctx = &(ctx->dd); /* Use default domain and default host */
|
|
- conn->host = NULL; /* until we have more information. */
|
|
|
|
|
|
|
|
conn->tls_user_ptr = tls.user_ptr; /* store ptr for quick access */
|
|
conn->tls_user_ptr = tls.user_ptr; /* store ptr for quick access */
|
|
|
|
|