urldecode forbid malformed
authorAndy Green <andy@warmcat.com>
Thu, 7 Apr 2016 02:08:35 +0000 (10:08 +0800)
committerAndy Green <andy@warmcat.com>
Thu, 7 Apr 2016 02:08:35 +0000 (10:08 +0800)
And update attack.sh to confirm the new test cases

Signed-off-by: Andy Green <andy@warmcat.com>
lib/parsers.c
lib/server.c
test-server/attack.sh
test-server/test-server-http.c

index 879db99..cfacace 100644 (file)
@@ -586,6 +586,23 @@ lws_parse(struct lws *wsi, unsigned char c)
                                if (issue_char(wsi, '/') < 0)
                                        return -1;
 
+                       if (wsi->u.hdr.ups == URIPS_SEEN_SLASH_DOT_DOT) {
+                               /*
+                                * back up one dir level if possible
+                                * safe against header fragmentation because
+                                * the method URI can only be in 1 fragment
+                                */
+                               if (ah->frags[ah->nfrag].len > 2) {
+                                       ah->pos--;
+                                       ah->frags[ah->nfrag].len--;
+                                       do {
+                                               ah->pos--;
+                                               ah->frags[ah->nfrag].len--;
+                                       } while (ah->frags[ah->nfrag].len > 1 &&
+                                                ah->data[ah->pos] != '/');
+                               }
+                       }
+
                        /* begin parsing HTTP version: */
                        if (issue_char(wsi, '\0') < 0)
                                return -1;
@@ -593,7 +610,10 @@ lws_parse(struct lws *wsi, unsigned char c)
                        goto start_fragment;
                }
 
-               /* special URI processing... convert %xx */
+               /*
+                * PRIORITY 1
+                * special URI processing... convert %xx
+                */
 
                switch (wsi->u.hdr.ues) {
                case URIES_IDLE:
@@ -603,30 +623,19 @@ lws_parse(struct lws *wsi, unsigned char c)
                        }
                        break;
                case URIES_SEEN_PERCENT:
-                       if (char_to_hex(c) < 0) {
-                               /* regurgitate */
-                               if (issue_char(wsi, '%') < 0)
-                                       return -1;
-                               wsi->u.hdr.ues = URIES_IDLE;
-                               /* continue on to assess c */
-                               break;
-                       }
+                       if (char_to_hex(c) < 0)
+                               /* illegal post-% char */
+                               goto forbid;
+
                        wsi->u.hdr.esc_stash = c;
                        wsi->u.hdr.ues = URIES_SEEN_PERCENT_H1;
                        goto swallow;
 
                case URIES_SEEN_PERCENT_H1:
-                       if (char_to_hex(c) < 0) {
-                               /* regurgitate */
-                               if (issue_char(wsi, '%') < 0)
-                                       return -1;
-                               wsi->u.hdr.ues = URIES_IDLE;
-                               /* regurgitate + assess */
-                               if (lws_parse(wsi, wsi->u.hdr.esc_stash) < 0)
-                                       return -1;
-                               /* continue on to assess c */
-                               break;
-                       }
+                       if (char_to_hex(c) < 0)
+                               /* illegal post-% char */
+                               goto forbid;
+
                        c = (char_to_hex(wsi->u.hdr.esc_stash) << 4) |
                                        char_to_hex(c);
                        enc = 1;
@@ -635,6 +644,7 @@ lws_parse(struct lws *wsi, unsigned char c)
                }
 
                /*
+                * PRIORITY 2
                 * special URI processing...
                 *  convert /.. or /... or /../ etc to /
                 *  convert /./ to /
@@ -693,6 +703,24 @@ lws_parse(struct lws *wsi, unsigned char c)
                case URIPS_SEEN_SLASH_DOT:
                        /* swallow second . */
                        if (c == '.') {
+                               wsi->u.hdr.ups = URIPS_SEEN_SLASH_DOT_DOT;
+                               goto swallow;
+                       }
+                       /* change /./ to / */
+                       if (c == '/') {
+                               wsi->u.hdr.ups = URIPS_SEEN_SLASH;
+                               goto swallow;
+                       }
+                       /* it was like /.dir ... regurgitate the . */
+                       wsi->u.hdr.ups = URIPS_IDLE;
+                       if (issue_char(wsi, '.') < 0)
+                               return -1;
+                       break;
+
+               case URIPS_SEEN_SLASH_DOT_DOT:
+
+                       /* /../ or /..[End of URI] --> backup to last / */
+                       if (c == '/' || c == '?') {
                                /*
                                 * back up one dir level if possible
                                 * safe against header fragmentation because
@@ -707,34 +735,27 @@ lws_parse(struct lws *wsi, unsigned char c)
                                        } while (ah->frags[ah->nfrag].len > 1 &&
                                                 ah->data[ah->pos] != '/');
                                }
-                               wsi->u.hdr.ups = URIPS_SEEN_SLASH_DOT_DOT;
-                               goto swallow;
-                       }
-                       /* change /./ to / */
-                       if (c == '/') {
                                wsi->u.hdr.ups = URIPS_SEEN_SLASH;
+                               if (ah->frags[ah->nfrag].len > 1)
+                                       break;
                                goto swallow;
                        }
-                       /* it was like /.dir ... regurgitate the . */
-                       wsi->u.hdr.ups = URIPS_IDLE;
+
+                       /*  /..[^/] ... regurgitate and allow */
+
                        if (issue_char(wsi, '.') < 0)
                                return -1;
-                       break;
-
-               case URIPS_SEEN_SLASH_DOT_DOT:
-                       /* swallow prior .. chars and any subsequent . */
-                       if (c == '.')
-                               goto swallow;
-                       /* last issued was /, so another / == // */
-                       if (c == '/')
-                               goto swallow;
-                       /* last we issued was / so SEEN_SLASH */
-                       wsi->u.hdr.ups = URIPS_SEEN_SLASH;
+                       if (issue_char(wsi, '.') < 0)
+                               return -1;
+                       wsi->u.hdr.ups = URIPS_IDLE;
                        break;
                }
 
                if (c == '?' && !enc &&
                    !ah->frag_index[WSI_TOKEN_HTTP_URI_ARGS]) { /* start of URI arguments */
+                       if (wsi->u.hdr.ues != URIES_IDLE)
+                               goto forbid;
+
                        /* seal off uri header */
                        if (issue_char(wsi, '\0') < 0)
                                return -1;
@@ -754,10 +775,12 @@ lws_parse(struct lws *wsi, unsigned char c)
                }
 
 check_eol:
-
                /* bail at EOL */
                if (wsi->u.hdr.parser_state != WSI_TOKEN_CHALLENGE &&
                    c == '\x0d') {
+                       if (wsi->u.hdr.ues != URIES_IDLE)
+                               goto forbid;
+
                        c = '\0';
                        wsi->u.hdr.parser_state = WSI_TOKEN_SKIPPING_SAW_CR;
                        lwsl_parser("*\n");
@@ -803,7 +826,7 @@ swallow:
                         */
                        if (m == ARRAY_SIZE(methods)) {
                                lwsl_info("Unknown method - dropping\n");
-                               return -1;
+                               goto forbid;
                        }
                        break;
                }
@@ -891,6 +914,8 @@ excessive:
 
        case WSI_TOKEN_SKIPPING_SAW_CR:
                lwsl_parser("WSI_TOKEN_SKIPPING_SAW_CR '%c'\n", c);
+               if (wsi->u.hdr.ues != URIES_IDLE)
+                       goto forbid;
                if (c == '\x0a') {
                        wsi->u.hdr.parser_state = WSI_TOKEN_NAME_PART;
                        wsi->u.hdr.lextable_pos = 0;
@@ -907,7 +932,8 @@ excessive:
        return 0;
 
 set_parsing_complete:
-
+       if (wsi->u.hdr.ues != URIES_IDLE)
+               goto forbid;
        if (lws_hdr_total_length(wsi, WSI_TOKEN_UPGRADE)) {
                if (lws_hdr_total_length(wsi, WSI_TOKEN_VERSION))
                        wsi->ietf_spec_revision =
@@ -919,6 +945,11 @@ set_parsing_complete:
        wsi->hdr_parsing_completed = 1;
 
        return 0;
+
+forbid:
+       lwsl_notice(" forbidding on uri sanitation\n");
+       lws_return_http_status(wsi, HTTP_STATUS_FORBIDDEN, NULL);
+       return -1;
 }
 
 
index 3103256..5a3ec79 100644 (file)
@@ -376,7 +376,7 @@ lws_http_action(struct lws *wsi)
                        goto bail_nuke_ah;
                if (lws_add_http_header_status(wsi, 301, &p, end))
                        goto bail_nuke_ah;
-               n = sprintf((char *)end, "htt   struct lws_http_mount *hm;ps://%s/",
+               n = sprintf((char *)end, "https://%s/",
                            lws_hdr_simple_ptr(wsi, WSI_TOKEN_HOST));
                if (lws_add_http_header_by_token(wsi, WSI_TOKEN_HTTP_LOCATION,
                                end, n, &p, end))
index f1a4e1b..7fe3d84 100755 (executable)
@@ -35,6 +35,14 @@ function check {
                fi
        fi
 
+       if [ "$1" = "rejected" ] ; then
+               if [ -z "`grep '<h1>406</h1>' /tmp/lwscap`" ] ; then
+                       echo "FAIL: should have told forbidden (test server has no dirs)"
+                       exit 1
+               fi
+       fi
+
+
        if [ "$1" = "media" ] ; then
                if [ -z "`grep '<h1>415</h1>' /tmp/lwscap`" ] ; then
                        echo "FAIL: should have told unknown media type"
@@ -73,7 +81,7 @@ function check {
 
 rm -rf $LOG
 killall libwebsockets-test-server 2>/dev/null
-libwebsockets-test-server -d31 2>> $LOG &
+libwebsockets-test-server -d15 2>> $LOG &
 CPID=$!
 
 while [ -z "`grep Listening $LOG`" ] ; do
@@ -233,7 +241,7 @@ echo
 echo "---- directory attack 1 (/../../../../etc/passwd should be /etc/passswd)"
 rm -f /tmp/lwscap
 echo -e "GET /../../../../etc/passwd HTTP/1.1\x0d\x0a\x0d\x0a" | nc $SERVER $PORT | sed '1,/^\r$/d'> /tmp/lwscap
-check forbidden
+check rejected
 check
 
 echo
@@ -275,14 +283,14 @@ echo
 echo "---- directory attack 7 (/%2e%2e%2f../../../etc/passwd should be /etc/passswd)"
 rm -f /tmp/lwscap
 echo -e "GET /%2e%2e%2f../../../etc/passwd HTTP/1.1\x0d\x0a\x0d\x0a" | nc $SERVER $PORT | sed '1,/^\r$/d'> /tmp/lwscap
-check forbidden
+check rejected
 check
 
 echo
 echo "---- directory attack 8 (%2f%2e%2e%2f%2e./.%2e/.%2e%2fetc/passwd should be /etc/passswd)"
 rm -f /tmp/lwscap
 echo -e "GET %2f%2e%2e%2f%2e./.%2e/.%2e%2fetc/passwd HTTP/1.1\x0d\x0a\x0d\x0a" | nc $SERVER $PORT | sed '1,/^\r$/d'> /tmp/lwscap
-check forbidden
+check rejected
 check
 
 echo
@@ -296,6 +304,449 @@ if [ "$good" != "`md5sum /tmp/lwsdump | cut -d' ' -f 1`" ] ; then
 fi
 
 echo
+echo "---- mass testing uri variations"
+
+rm -f /tmp/results
+
+for i in \
+/..../ \
+/.../. \
+/...// \
+/.../a \
+/.../w \
+/.../? \
+/.../% \
+/../.. \
+/.././ \
+/../.a \
+/../.w \
+/../.. \
+/../.% \
+/..//. \
+/../// \
+/..//a \
+/..//w \
+/..//? \
+/..//% \
+/../a. \
+/../a/ \
+/../aa \
+/../aw \
+/../a? \
+/../a% \
+/../w. \
+/../w/ \
+/../wa \
+/../ww \
+/../w? \
+/../w% \
+/../?. \
+/../?/ \
+/../?a \
+/../?w \
+/../?? \
+/../?% \
+/../%. \
+/../%/ \
+/../%a \
+/../%w \
+/../%? \
+/../%% \
+/./... \
+/./../ \
+/./..a \
+/./..w \
+/./..? \
+/./..% \
+/.//.. \
+/.a../ \
+/.a/.. \
+/.w../ \
+/.w/.. \
+/.?../ \
+/../.. \
+/.%../ \
+/.%/.. \
+//.... \
+//.../ \
+//...a \
+//...w \
+//...? \
+//...% \
+//../. \
+//..// \
+//../a \
+//../w \
+//../? \
+//../% \
+//..a. \
+//..a/ \
+//..aa \
+//..aw \
+//..a? \
+//..a% \
+//..w. \
+//..w/ \
+//..wa \
+//..ww \
+//..w? \
+//..w% \
+//..?. \
+//..?/ \
+//..?a \
+//..?w \
+//..?? \
+//..?% \
+//..%. \
+//..%/ \
+//..%a \
+//..%w \
+//..%? \
+//..%% \
+//./.. \
+///... \
+///../ \
+///..a \
+///..w \
+///..? \
+///..% \
+////.. \
+//a../ \
+//a/.. \
+//w../ \
+//w/.. \
+//?../ \
+//?/.. \
+//%../ \
+//%/.. \
+/a.../ \
+/a../. \
+/a..// \
+/a../a \
+/a../w \
+/a../? \
+/a../% \
+/a./.. \
+/a/... \
+/a/../ \
+/a/..a \
+/a/..w \
+/a/..? \
+/a/..% \
+/a//.. \
+/aa../ \
+/aa/.. \
+/aw../ \
+/aw/.. \
+/a?../ \
+/a?/.. \
+/a%../ \
+/a%/.. \
+/w.../ \
+/w../. \
+/w..// \
+/w../a \
+/w../w \
+/w../? \
+/w../% \
+/w./.. \
+/w/... \
+/w/../ \
+/w/..a \
+/w/..w \
+/w/..? \
+/w/..% \
+/w//.. \
+/wa../ \
+/wa/.. \
+/ww../ \
+/ww/.. \
+/w?../ \
+/w?/.. \
+/w%../ \
+/w%/.. \
+/?.../ \
+/?../. \
+/?..// \
+/?../a \
+/?../w \
+/?../? \
+/?../% \
+/?./.. \
+/?/... \
+/?/../ \
+/?/..a \
+/?/..w \
+/?/..? \
+/?/..% \
+/?//.. \
+/?a../ \
+/?a/.. \
+/?w../ \
+/?w/.. \
+/??../ \
+/??/.. \
+/?%../ \
+/?%/.. \
+/%.../ \
+/%../. \
+/%..// \
+/%../a \
+/%../w \
+/%../? \
+/%../% \
+/%./.. \
+/%/... \
+/%/../ \
+/%/..a \
+/%/..w \
+/%/..? \
+/%/..% \
+/%//.. \
+/%a../ \
+/%a/.. \
+/%w../ \
+/%w/.. \
+/%?../ \
+/%?/.. \
+/%%../ \
+/%%/.. \
+/a/w/../a \
+/path/to/dir/../other/dir \
+; do
+
+R=`rm -f /tmp/lwscap ; echo -n -e "GET $i HTTP/1.0\r\n\r\n" | nc localhost 7681 2>/dev/null >/tmp/lwscap; head -n1 /tmp/lwscap| cut -d' ' -f2`
+
+cat /tmp/lwscap | head -n1
+echo ==== $R
+
+
+if [ "$R" != "403" ]; then
+       U=`cat $LOG | grep lws_http_serve | tail -n 1 | cut -d':' -f3 | cut -d' ' -f2`
+       echo $U
+       echo "- \"$i\" -> $R \"$U\"" >>/tmp/results
+else
+       echo "- \"$i\" -> $R" >>/tmp/results
+fi
+done
+
+cat <<EOF >/tmp/lwsresult1
+- "/..../" -> 406 "/..../"
+- "/.../." -> 406 "/.../"
+- "/...//" -> 406 "/.../"
+- "/.../a" -> 406 "/.../a"
+- "/.../w" -> 406 "/.../w"
+- "/.../?" -> 406 "/.../"
+- "/.../%" -> 403
+- "/../.." -> 200 "/"
+- "/.././" -> 200 "/"
+- "/../.a" -> 415 "/.a"
+- "/../.w" -> 415 "/.w"
+- "/../.." -> 200 "/"
+- "/../.%" -> 403
+- "/..//." -> 200 "/"
+- "/..///" -> 200 "/"
+- "/..//a" -> 415 "/a"
+- "/..//w" -> 415 "/w"
+- "/..//?" -> 200 "/"
+- "/..//%" -> 403
+- "/../a." -> 415 "/a."
+- "/../a/" -> 406 "/a/"
+- "/../aa" -> 415 "/aa"
+- "/../aw" -> 415 "/aw"
+- "/../a?" -> 415 "/a"
+- "/../a%" -> 403
+- "/../w." -> 415 "/w."
+- "/../w/" -> 406 "/w/"
+- "/../wa" -> 415 "/wa"
+- "/../ww" -> 415 "/ww"
+- "/../w?" -> 415 "/w"
+- "/../w%" -> 403
+- "/../?." -> 200 "/"
+- "/../?/" -> 200 "/"
+- "/../?a" -> 200 "/"
+- "/../?w" -> 200 "/"
+- "/../??" -> 200 "/"
+- "/../?%" -> 403
+- "/../%." -> 403
+- "/../%/" -> 403
+- "/../%a" -> 403
+- "/../%w" -> 403
+- "/../%?" -> 403
+- "/../%%" -> 403
+- "/./..." -> 415 "/..."
+- "/./../" -> 200 "/"
+- "/./..a" -> 415 "/..a"
+- "/./..w" -> 415 "/..w"
+- "/./..?" -> 200 "/"
+- "/./..%" -> 403
+- "/.//.." -> 200 "/"
+- "/.a../" -> 406 "/.a../"
+- "/.a/.." -> 200 "/"
+- "/.w../" -> 406 "/.w../"
+- "/.w/.." -> 200 "/"
+- "/.?../" -> 415 "/."
+- "/../.." -> 200 "/"
+- "/.%../" -> 403
+- "/.%/.." -> 403
+- "//...." -> 415 "/...."
+- "//.../" -> 406 "/.../"
+- "//...a" -> 415 "/...a"
+- "//...w" -> 415 "/...w"
+- "//...?" -> 415 "/..."
+- "//...%" -> 403
+- "//../." -> 200 "/"
+- "//..//" -> 200 "/"
+- "//../a" -> 415 "/a"
+- "//../w" -> 415 "/w"
+- "//../?" -> 200 "/"
+- "//../%" -> 403
+- "//..a." -> 415 "/..a."
+- "//..a/" -> 406 "/..a/"
+- "//..aa" -> 415 "/..aa"
+- "//..aw" -> 415 "/..aw"
+- "//..a?" -> 415 "/..a"
+- "//..a%" -> 403
+- "//..w." -> 415 "/..w."
+- "//..w/" -> 406 "/..w/"
+- "//..wa" -> 415 "/..wa"
+- "//..ww" -> 415 "/..ww"
+- "//..w?" -> 415 "/..w"
+- "//..w%" -> 403
+- "//..?." -> 200 "/"
+- "//..?/" -> 200 "/"
+- "//..?a" -> 415 "/a"
+- "//..?w" -> 415 "/w"
+- "//..??" -> 200 "/"
+- "//..?%" -> 403
+- "//..%." -> 403
+- "//..%/" -> 403
+- "//..%a" -> 403
+- "//..%w" -> 403
+- "//..%?" -> 403
+- "//..%%" -> 403
+- "//./.." -> 200 "/"
+- "///..." -> 415 "/..."
+- "///../" -> 200 "/"
+- "///..a" -> 415 "/..a"
+- "///..w" -> 415 "/..w"
+- "///..?" -> 200 "/"
+- "///..%" -> 403
+- "////.." -> 200 "/"
+- "//a../" -> 406 "/a../"
+- "//a/.." -> 200 "/"
+- "//w../" -> 406 "/w../"
+- "//w/.." -> 200 "/"
+- "//?../" -> 200 "/"
+- "//?/.." -> 200 "/"
+- "//%../" -> 403
+- "//%/.." -> 403
+- "/a.../" -> 406 "/a.../"
+- "/a../." -> 406 "/a../"
+- "/a..//" -> 406 "/a../"
+- "/a../a" -> 406 "/a../a"
+- "/a../w" -> 406 "/a../w"
+- "/a../?" -> 406 "/a../"
+- "/a../%" -> 403
+- "/a./.." -> 200 "/"
+- "/a/..." -> 406 "/a/..."
+- "/a/../" -> 200 "/"
+- "/a/..a" -> 406 "/a/..a"
+- "/a/..w" -> 406 "/a/..w"
+- "/a/..?" -> 200 "/"
+- "/a/..%" -> 403
+- "/a//.." -> 200 "/"
+- "/aa../" -> 406 "/aa../"
+- "/aa/.." -> 200 "/"
+- "/aw../" -> 406 "/aw../"
+- "/aw/.." -> 200 "/"
+- "/a?../" -> 415 "/a"
+- "/a?/.." -> 415 "/a"
+- "/a%../" -> 403
+- "/a%/.." -> 403
+- "/w.../" -> 406 "/w.../"
+- "/w../." -> 406 "/w../"
+- "/w..//" -> 406 "/w../"
+- "/w../a" -> 406 "/w../a"
+- "/w../w" -> 406 "/w../w"
+- "/w../?" -> 406 "/w../"
+- "/w../%" -> 403
+- "/w./.." -> 200 "/"
+- "/w/..." -> 406 "/w/..."
+- "/w/../" -> 200 "/"
+- "/w/..a" -> 406 "/w/..a"
+- "/w/..w" -> 406 "/w/..w"
+- "/w/..?" -> 200 "/"
+- "/w/..%" -> 403
+- "/w//.." -> 200 "/"
+- "/wa../" -> 406 "/wa../"
+- "/wa/.." -> 200 "/"
+- "/ww../" -> 406 "/ww../"
+- "/ww/.." -> 200 "/"
+- "/w?../" -> 415 "/w"
+- "/w?/.." -> 415 "/w"
+- "/w%../" -> 403
+- "/w%/.." -> 403
+- "/?.../" -> 200 "/"
+- "/?../." -> 200 "/"
+- "/?..//" -> 200 "/"
+- "/?../a" -> 200 "/"
+- "/?../w" -> 200 "/"
+- "/?../?" -> 200 "/"
+- "/?../%" -> 403
+- "/?./.." -> 200 "/"
+- "/?/..." -> 200 "/"
+- "/?/../" -> 200 "/"
+- "/?/..a" -> 200 "/"
+- "/?/..w" -> 200 "/"
+- "/?/..?" -> 200 "/"
+- "/?/..%" -> 403
+- "/?//.." -> 200 "/"
+- "/?a../" -> 200 "/"
+- "/?a/.." -> 200 "/"
+- "/?w../" -> 200 "/"
+- "/?w/.." -> 200 "/"
+- "/??../" -> 200 "/"
+- "/??/.." -> 200 "/"
+- "/?%../" -> 403
+- "/?%/.." -> 403
+- "/%.../" -> 403
+- "/%../." -> 403
+- "/%..//" -> 403
+- "/%../a" -> 403
+- "/%../w" -> 403
+- "/%../?" -> 403
+- "/%../%" -> 403
+- "/%./.." -> 403
+- "/%/..." -> 403
+- "/%/../" -> 403
+- "/%/..a" -> 403
+- "/%/..w" -> 403
+- "/%/..?" -> 403
+- "/%/..%" -> 403
+- "/%//.." -> 403
+- "/%a../" -> 403
+- "/%a/.." -> 403
+- "/%w../" -> 403
+- "/%w/.." -> 403
+- "/%?../" -> 403
+- "/%?/.." -> 403
+- "/%%../" -> 403
+- "/%%/.." -> 403
+- "/a/w/../a" -> 406 "/a/a"
+- "/path/to/dir/../other/dir" -> 406 "/path/to/other/dir"
+EOF
+
+if [ "`md5sum /tmp/results | cut -d' ' -f 1`" != "`md5sum /tmp/lwsresult1 | cut -d' ' -f1`" ] ; then
+       echo "Differences..."
+       diff -urN /tmp/results /tmp/lwsresult1
+       exit 1
+else
+       echo "OK"
+fi
+
+
+echo
 echo "--- survived OK ---"
 kill -2 $CPID
 
index a142b70..902e945 100644 (file)
@@ -140,9 +140,12 @@ int callback_http(struct lws *wsi, enum lws_callback_reasons reason, void *user,
        struct lws_pollargs *pa = (struct lws_pollargs *)in;
 #endif
 
+
        switch (reason) {
        case LWS_CALLBACK_HTTP:
 
+               lwsl_notice("lws_http_serve: %s\n",in);
+
                if (debug_level & LLL_INFO) {
                        dump_handshake_info(wsi);
 
@@ -207,7 +210,7 @@ int callback_http(struct lws *wsi, enum lws_callback_reasons reason, void *user,
 #if 1
                /* this example server has no concept of directories */
                if (strchr((const char *)in + 1, '/')) {
-                       lws_return_http_status(wsi, HTTP_STATUS_FORBIDDEN, NULL);
+                       lws_return_http_status(wsi, HTTP_STATUS_NOT_ACCEPTABLE, NULL);
                        goto try_to_reuse;
                }
 #endif