Added optional per-header length limits:
authorAndrew Canaday <andrew.canaday@nytimes.com>
Sun, 29 Jun 2014 04:25:19 +0000 (00:25 -0400)
committerAndy Green <andy.green@linaro.org>
Sun, 6 Jul 2014 01:33:40 +0000 (09:33 +0800)
 - libwebsockets.h:
 - * added struct lws_token_limits
   * added token limits pointer to lws_context_creation_info
 - private-libwebsockets.h: added token limits pointer to lws_context_creation_info
 - context.c: copy token limits in create_context
 - client.c / server.c: pass context when invoking libwebsocket_parse
 - parsers.c:
 - * libwebsocket_parse takes context pointer
   * issue_char takes context pointer and checks header length against context limits, if defined
   * issue_char returns 1 (not -1/0) for header too long, and spill: sets the state to WSI_TOKEN_SKIPPING

lib/client.c
lib/context.c
lib/libwebsockets.h
lib/parsers.c
lib/private-libwebsockets.h
lib/server.c

index 19a819d..2b9a943 100755 (executable)
@@ -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;
                        }
index 2c283d7..f2f30ad 100644 (file)
@@ -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';
index 47ae4df..dd0bd37 100644 (file)
@@ -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;
index 68a7e5d..07c5500 100644 (file)
@@ -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 */
 
index d05c48f..281bd7f 100755 (executable)
@@ -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);
index 37ce6a1..1e85186 100644 (file)
@@ -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;
                }