diff --git a/lib/client.c b/lib/client.c index 19a819d9..2b9a943c 100755 --- a/lib/client.c +++ b/lib/client.c @@ -411,7 +411,7 @@ int lws_client_socket_service(struct libwebsocket_context *context, return 0; } - if (libwebsocket_parse(wsi, c)) { + if (libwebsocket_parse(context, wsi, c)) { lwsl_warn("problems parsing header\n"); goto bail3; } diff --git a/lib/context.c b/lib/context.c index 2c283d76..f2f30ade 100644 --- a/lib/context.c +++ b/lib/context.c @@ -116,6 +116,7 @@ libwebsocket_create_context(struct lws_context_creation_info *info) context->listen_service_extraseen = 0; context->protocols = info->protocols; + context->token_limits = info->token_limits; context->listen_port = info->port; context->http_proxy_port = 0; context->http_proxy_address[0] = '\0'; diff --git a/lib/libwebsockets.h b/lib/libwebsockets.h index 47ae4df3..dd0bd372 100644 --- a/lib/libwebsockets.h +++ b/lib/libwebsockets.h @@ -341,6 +341,10 @@ enum lws_token_indexes { WSI_INIT_TOKEN_MUXURL, }; +struct lws_token_limits { + unsigned short token_limit[WSI_TOKEN_COUNT]; +}; + /* * From RFC 6455 1000 @@ -947,6 +951,7 @@ struct lws_context_creation_info { const char *iface; struct libwebsocket_protocols *protocols; struct libwebsocket_extension *extensions; + struct lws_token_limits *token_limits; const char *ssl_cert_filepath; const char *ssl_private_key_filepath; const char *ssl_ca_filepath; diff --git a/lib/parsers.c b/lib/parsers.c index 68a7e5d3..07c55001 100644 --- a/lib/parsers.c +++ b/lib/parsers.c @@ -165,12 +165,22 @@ static char char_to_hex(const char c) return -1; } -static int issue_char(struct libwebsocket *wsi, unsigned char c) +static int issue_char( + struct libwebsocket_context *context, + struct libwebsocket *wsi, unsigned char c) { if (wsi->u.hdr.ah->pos == sizeof(wsi->u.hdr.ah->data)) { lwsl_warn("excessive header content\n"); return -1; } + + if( context->token_limits && + (wsi->u.hdr.ah->frags[wsi->u.hdr.ah->next_frag_index].len >= + context->token_limits->token_limit[wsi->u.hdr.parser_state]) ) { + lwsl_warn("header %i exceeds limit\n", wsi->u.hdr.parser_state); + return 1; + }; + wsi->u.hdr.ah->data[wsi->u.hdr.ah->pos++] = c; if (c) wsi->u.hdr.ah->frags[wsi->u.hdr.ah->next_frag_index].len++; @@ -178,7 +188,9 @@ static int issue_char(struct libwebsocket *wsi, unsigned char c) return 0; } -int libwebsocket_parse(struct libwebsocket *wsi, unsigned char c) +int libwebsocket_parse( + struct libwebsocket_context *context, + struct libwebsocket *wsi, unsigned char c) { int n; @@ -234,7 +246,7 @@ int libwebsocket_parse(struct libwebsocket *wsi, unsigned char c) if (c == ' ') { /* enforce starting with / */ if (!wsi->u.hdr.ah->frags[wsi->u.hdr.ah->next_frag_index].len) - if (issue_char(wsi, '/') < 0) + if (issue_char(context, wsi, '/') < 0) return -1; c = '\0'; wsi->u.hdr.parser_state = WSI_TOKEN_SKIPPING; @@ -253,7 +265,7 @@ int libwebsocket_parse(struct libwebsocket *wsi, unsigned char c) case URIES_SEEN_PERCENT: if (char_to_hex(c) < 0) { /* regurgitate */ - if (issue_char(wsi, '%') < 0) + if (issue_char(context, wsi, '%') < 0) return -1; wsi->u.hdr.ues = URIES_IDLE; /* continue on to assess c */ @@ -266,10 +278,10 @@ int libwebsocket_parse(struct libwebsocket *wsi, unsigned char c) case URIES_SEEN_PERCENT_H1: if (char_to_hex(c) < 0) { /* regurgitate */ - issue_char(wsi, '%'); + issue_char(context, wsi, '%'); wsi->u.hdr.ues = URIES_IDLE; /* regurgitate + assess */ - if (libwebsocket_parse(wsi, wsi->u.hdr.esc_stash) < 0) + if (libwebsocket_parse(context, wsi, wsi->u.hdr.esc_stash) < 0) return -1; /* continue on to assess c */ break; @@ -332,7 +344,7 @@ int libwebsocket_parse(struct libwebsocket *wsi, unsigned char c) } /* it was like /.dir ... regurgitate the . */ wsi->u.hdr.ups = URIPS_IDLE; - issue_char(wsi, '.'); + issue_char(context, wsi, '.'); break; case URIPS_SEEN_SLASH_DOT_DOT: @@ -383,8 +395,15 @@ check_eol: } spill: - if (issue_char(wsi, c) < 0) - return -1; + { + int issue_result = issue_char(context, wsi, c); + if (issue_result < 0) { + return -1; + } + else if(issue_result > 0) { + wsi->u.hdr.parser_state = WSI_TOKEN_SKIPPING; + }; + }; swallow: /* per-protocol end of headers management */ diff --git a/lib/private-libwebsockets.h b/lib/private-libwebsockets.h index d05c48f2..281bd7f4 100755 --- a/lib/private-libwebsockets.h +++ b/lib/private-libwebsockets.h @@ -432,6 +432,7 @@ struct libwebsocket_context { #ifndef LWS_NO_EXTENSIONS struct libwebsocket_extension *extensions; #endif + struct lws_token_limits *token_limits; void *user_space; }; @@ -645,7 +646,8 @@ LWS_EXTERN int libwebsocket_client_rx_sm(struct libwebsocket *wsi, unsigned char c); LWS_EXTERN int -libwebsocket_parse(struct libwebsocket *wsi, unsigned char c); +libwebsocket_parse(struct libwebsocket_context *context, + struct libwebsocket *wsi, unsigned char c); LWS_EXTERN int lws_b64_selftest(void); diff --git a/lib/server.c b/lib/server.c index 37ce6a17..1e851864 100644 --- a/lib/server.c +++ b/lib/server.c @@ -179,7 +179,7 @@ int lws_handshake_server(struct libwebsocket_context *context, /* LWS_CONNMODE_WS_SERVING */ while (len--) { - if (libwebsocket_parse(wsi, *(*buf)++)) { + if (libwebsocket_parse(context, wsi, *(*buf)++)) { lwsl_info("libwebsocket_parse failed\n"); goto bail_nuke_ah; }