lwsws redirect and correct vhost selection before accept

Signed-off-by: Andy Green <andy@warmcat.com>
This commit is contained in:
Andy Green 2016-04-08 18:30:45 +08:00
parent 37098ae2a2
commit d459a6fadc
5 changed files with 100 additions and 31 deletions

View file

@ -44,7 +44,9 @@ static const char * const mount_protocols[] = {
"http://", "http://",
"https://", "https://",
"file://", "file://",
"cgi://" "cgi://",
">http://",
">https://",
}; };
LWS_VISIBLE LWS_EXTERN int LWS_VISIBLE LWS_EXTERN int
@ -70,6 +72,7 @@ lws_write_http_mount(struct lws_http_mount *next, struct lws_http_mount **res,
m->mount_next = NULL; m->mount_next = NULL;
if (next) if (next)
next->mount_next = m; next->mount_next = m;
for (n = 0; n < ARRAY_SIZE(mount_protocols); n++) for (n = 0; n < ARRAY_SIZE(mount_protocols); n++)
if (!strncmp(origin, mount_protocols[n], if (!strncmp(origin, mount_protocols[n],
strlen(mount_protocols[n]))) { strlen(mount_protocols[n]))) {

View file

@ -191,6 +191,12 @@ static const char * get_mimetype(const char *file)
if (!strcmp(&file[n - 4], ".ico")) if (!strcmp(&file[n - 4], ".ico"))
return "image/x-icon"; return "image/x-icon";
if (!strcmp(&file[n - 4], ".gif"))
return "image/gif";
if (!strcmp(&file[n - 3], ".js"))
return "text/javascript";
if (!strcmp(&file[n - 4], ".png")) if (!strcmp(&file[n - 4], ".png"))
return "image/png"; return "image/png";
@ -203,6 +209,9 @@ static const char * get_mimetype(const char *file)
if (!strcmp(&file[n - 4], ".css")) if (!strcmp(&file[n - 4], ".css"))
return "text/css"; return "text/css";
if (!strcmp(&file[n - 4], ".ttf"))
return "application/x-font-ttf";
return NULL; return NULL;
} }
@ -233,9 +242,7 @@ int lws_http_serve(struct lws *wsi, char *uri, const char *origin)
int int
lws_http_action(struct lws *wsi) lws_http_action(struct lws *wsi)
{ {
#ifdef LWS_OPENSSL_SUPPORT
struct lws_context_per_thread *pt = &wsi->context->pt[(int)wsi->tsi]; struct lws_context_per_thread *pt = &wsi->context->pt[(int)wsi->tsi];
#endif
enum http_connection_type connection_type; enum http_connection_type connection_type;
enum http_version request_version; enum http_version request_version;
char content_length_str[32]; char content_length_str[32];
@ -395,7 +402,6 @@ lws_http_action(struct lws *wsi)
hm = wsi->vhost->mount_list; hm = wsi->vhost->mount_list;
while (hm) { while (hm) {
lwsl_err("a %p\n", hm);
if (uri_len >= hm->mountpoint_len && if (uri_len >= hm->mountpoint_len &&
!strncmp(uri_ptr, hm->mountpoint, hm->mountpoint_len)) { !strncmp(uri_ptr, hm->mountpoint, hm->mountpoint_len)) {
if (hm->mountpoint_len > best) { if (hm->mountpoint_len > best) {
@ -405,23 +411,75 @@ lws_http_action(struct lws *wsi)
} }
hm = hm->mount_next; hm = hm->mount_next;
} }
lwsl_err("x\n");
if (hit) { if (hit) {
char *s = uri_ptr + hit->mountpoint_len; char *s = uri_ptr + hit->mountpoint_len;
if (s[0] == '\0') lwsl_err("*** hit %d %d %s\n", hit->mountpoint_len, hit->origin_protocol , hit->origin);
/*
* if we have a mountpoint like https://xxx.com/yyy
* there is an implied / at the end for our purposes since
* we can only mount on a "directory".
*
* But if we just go with that, the browser cannot understand
* that he is actually looking down one "directory level", so
* even though we give him /yyy/abc.html he acts like the
* current directory level is /. So relative urls like "x.png"
* wrongly look outside the mountpoint.
*
* Therefore if we didn't come in on a url with an explicit
* / at the end, we must redirect to add it so the browser
* understands he is one "directory level" down.
*/
if (hit->mountpoint_len > 1 || (hit->origin_protocol & 4))
if (*s != '/' || (hit->origin_protocol & 4)) {
unsigned char *start = pt->serv_buf + LWS_PRE,
*p = start, *end = p + 512;
static const char *oprot[] = {
"http://", "https://"
};
if (!lws_hdr_total_length(wsi, WSI_TOKEN_HOST))
goto bail_nuke_ah;
if (lws_add_http_header_status(wsi, 301, &p, end))
goto bail_nuke_ah;
lwsl_err("**** %s", hit->origin);
/* > at start indicates deal with by redirect */
if (hit->origin_protocol & 4)
n = snprintf((char *)end, 256, "%s%s",
oprot[hit->origin_protocol & 1],
hit->origin);
else
n = snprintf((char *)end, 256,
"https://%s/%s/",
lws_hdr_simple_ptr(wsi, WSI_TOKEN_HOST),
uri_ptr);
if (lws_add_http_header_by_token(wsi,
WSI_TOKEN_HTTP_LOCATION,
end, n, &p, end))
goto bail_nuke_ah;
if (lws_finalize_http_header(wsi, &p, end))
goto bail_nuke_ah;
n = lws_write(wsi, start, p - start,
LWS_WRITE_HTTP_HEADERS);
if ((int)n < 0)
goto bail_nuke_ah;
return lws_http_transaction_completed(wsi);
}
if (s[0] == '\0' || (s[0] == '/' && s[1] == '\0'))
s = (char *)hit->def; s = (char *)hit->def;
if (!s) if (!s)
s = "index.html"; s = "index.html";
lwsl_err("b\n");
n = lws_http_serve(wsi, s, hit->origin); n = lws_http_serve(wsi, s, hit->origin);
} else { } else
lwsl_err("c\n");
n = wsi->protocol->callback(wsi, LWS_CALLBACK_HTTP, n = wsi->protocol->callback(wsi, LWS_CALLBACK_HTTP,
wsi->user_space, uri_ptr, uri_len); wsi->user_space, uri_ptr, uri_len);
}
if (n) { if (n) {
lwsl_info("LWS_CALLBACK_HTTP closing\n"); lwsl_info("LWS_CALLBACK_HTTP closing\n");
@ -895,22 +953,11 @@ lws_http_transaction_completed(struct lws *wsi)
return 0; return 0;
} }
/** static struct lws *
* lws_adopt_socket() - adopt foreign socket as if listen socket accepted it lws_adopt_socket_vhost(struct lws_vhost *vh, lws_sockfd_type accept_fd)
* @context: lws context
* @accept_fd: fd of already-accepted socket to adopt
*
* Either returns new wsi bound to accept_fd, or closes accept_fd and
* returns NULL, having cleaned up any new wsi pieces.
*
* LWS adopts the socket in http serving mode, it's ready to accept an upgrade
* to ws or just serve http.
*/
LWS_VISIBLE struct lws *
lws_adopt_socket(struct lws_context *context, lws_sockfd_type accept_fd)
{ {
struct lws *new_wsi = lws_create_new_server_wsi(context->vhost_list); struct lws_context *context = vh->context;
struct lws *new_wsi = lws_create_new_server_wsi(vh);
if (!new_wsi) { if (!new_wsi) {
compatible_close(accept_fd); compatible_close(accept_fd);
@ -962,6 +1009,25 @@ fail:
return NULL; return NULL;
} }
/**
* lws_adopt_socket() - adopt foreign socket as if listen socket accepted it
* @context: lws context
* @accept_fd: fd of already-accepted socket to adopt
*
* Either returns new wsi bound to accept_fd, or closes accept_fd and
* returns NULL, having cleaned up any new wsi pieces.
*
* LWS adopts the socket in http serving mode, it's ready to accept an upgrade
* to ws or just serve http.
*/
LWS_VISIBLE struct lws *
lws_adopt_socket(struct lws_context *context, lws_sockfd_type accept_fd)
{
return lws_adopt_socket_vhost(context->vhost_list, accept_fd);
}
/** /**
* lws_adopt_socket_readbuf() - adopt foreign socket and first rx as if listen socket accepted it * lws_adopt_socket_readbuf() - adopt foreign socket and first rx as if listen socket accepted it
* @context: lws context * @context: lws context
@ -1273,7 +1339,7 @@ try_pollout:
break; break;
} }
if (!lws_adopt_socket(context, accept_fd)) if (!lws_adopt_socket_vhost(wsi->vhost, accept_fd))
/* already closed cleanly as necessary */ /* already closed cleanly as necessary */
return 1; return 1;

View file

@ -178,7 +178,7 @@ lws_ssl_server_name_cb(SSL *ssl, int *ad, void *arg)
if (servername) { if (servername) {
vhost = lws_select_vhost(context, port, servername); vhost = lws_select_vhost(context, port, servername);
if (vhost) { if (vhost) {
lwsl_info("SNI: Found: %s\n", servername); lwsl_notice("SNI: Found: %s (port %d)\n", servername, port);
SSL_set_SSL_CTX(ssl, vhost->ssl_ctx); SSL_set_SSL_CTX(ssl, vhost->ssl_ctx);
return SSL_TLSEXT_ERR_OK; return SSL_TLSEXT_ERR_OK;
} }

View file

@ -50,7 +50,7 @@ static const char * const paths_vhosts[] = {
"vhosts[].mounts[].default", "vhosts[].mounts[].default",
"vhosts[].ws-protocols[].*.*", "vhosts[].ws-protocols[].*.*",
"vhosts[].ws-protocols[].*", "vhosts[].ws-protocols[].*",
"vhosts[].ws-protocols[]" "vhosts[].ws-protocols[]",
}; };
enum lejp_vhost_paths { enum lejp_vhost_paths {

View file

@ -87,7 +87,7 @@
<tr> <tr>
<td valign=middle align=center> <td valign=middle align=center>
<a href="https://libwebsockets.org"> <a href="https://libwebsockets.org">
<img src="/libwebsockets.org-logo.png"></a></td><td> <img src="libwebsockets.org-logo.png"></a></td><td>
<section class="browser">Detected Browser: <section class="browser">Detected Browser:
<div id=brow>...</div></section> <div id=brow>...</div></section>
</td> </td>
@ -96,7 +96,7 @@
</table> </table>
</td></tr> </td></tr>
<tr><td colspan=2 align=center> <tr><td colspan=2 align=center>
Click <a href="/leaf.jpg" target="_blank">Here</a> to Click <a href="leaf.jpg" target="_blank">Here</a> to
have the test server send a big picture by http. have the test server send a big picture by http.
</td></tr> </td></tr>
<tr><td colspan=2> <tr><td colspan=2>