Annotation of embedaddon/lighttpd/src/request.c, revision 1.1

1.1     ! misho       1: #include "request.h"
        !             2: #include "keyvalue.h"
        !             3: #include "log.h"
        !             4: 
        !             5: #include <sys/stat.h>
        !             6: 
        !             7: #include <limits.h>
        !             8: #include <stdlib.h>
        !             9: #include <string.h>
        !            10: #include <stdio.h>
        !            11: #include <ctype.h>
        !            12: 
        !            13: static int request_check_hostname(server *srv, connection *con, buffer *host) {
        !            14:        enum { DOMAINLABEL, TOPLABEL } stage = TOPLABEL;
        !            15:        size_t i;
        !            16:        int label_len = 0;
        !            17:        size_t host_len;
        !            18:        char *colon;
        !            19:        int is_ip = -1; /* -1 don't know yet, 0 no, 1 yes */
        !            20:        int level = 0;
        !            21: 
        !            22:        UNUSED(srv);
        !            23:        UNUSED(con);
        !            24: 
        !            25:        /*
        !            26:         *       hostport      = host [ ":" port ]
        !            27:         *       host          = hostname | IPv4address | IPv6address
        !            28:         *       hostname      = *( domainlabel "." ) toplabel [ "." ]
        !            29:         *       domainlabel   = alphanum | alphanum *( alphanum | "-" ) alphanum
        !            30:         *       toplabel      = alpha | alpha *( alphanum | "-" ) alphanum
        !            31:         *       IPv4address   = 1*digit "." 1*digit "." 1*digit "." 1*digit
        !            32:         *       IPv6address   = "[" ... "]"
        !            33:         *       port          = *digit
        !            34:         */
        !            35: 
        !            36:        /* no Host: */
        !            37:        if (!host || host->used == 0) return 0;
        !            38: 
        !            39:        host_len = host->used - 1;
        !            40: 
        !            41:        /* IPv6 adress */
        !            42:        if (host->ptr[0] == '[') {
        !            43:                char *c = host->ptr + 1;
        !            44:                int colon_cnt = 0;
        !            45: 
        !            46:                /* check portnumber */
        !            47:                for (; *c && *c != ']'; c++) {
        !            48:                        if (*c == ':') {
        !            49:                                if (++colon_cnt > 7) {
        !            50:                                        return -1;
        !            51:                                }
        !            52:                        } else if (!light_isxdigit(*c) && '.' != *c) {
        !            53:                                return -1;
        !            54:                        }
        !            55:                }
        !            56: 
        !            57:                /* missing ] */
        !            58:                if (!*c) {
        !            59:                        return -1;
        !            60:                }
        !            61: 
        !            62:                /* check port */
        !            63:                if (*(c+1) == ':') {
        !            64:                        for (c += 2; *c; c++) {
        !            65:                                if (!light_isdigit(*c)) {
        !            66:                                        return -1;
        !            67:                                }
        !            68:                        }
        !            69:                }
        !            70:                return 0;
        !            71:        }
        !            72: 
        !            73:        if (NULL != (colon = memchr(host->ptr, ':', host_len))) {
        !            74:                char *c = colon + 1;
        !            75: 
        !            76:                /* check portnumber */
        !            77:                for (; *c; c++) {
        !            78:                        if (!light_isdigit(*c)) return -1;
        !            79:                }
        !            80: 
        !            81:                /* remove the port from the host-len */
        !            82:                host_len = colon - host->ptr;
        !            83:        }
        !            84: 
        !            85:        /* Host is empty */
        !            86:        if (host_len == 0) return -1;
        !            87: 
        !            88:        /* if the hostname ends in a "." strip it */
        !            89:        if (host->ptr[host_len-1] == '.') {
        !            90:                /* shift port info one left */
        !            91:                if (NULL != colon) memmove(colon-1, colon, host->used - host_len);
        !            92:                else host->ptr[host_len-1] = '\0';
        !            93:                host_len -= 1;
        !            94:                host->used -= 1;
        !            95:        }
        !            96: 
        !            97:        if (host_len == 0) return -1;
        !            98: 
        !            99:        /* scan from the right and skip the \0 */
        !           100:        for (i = host_len; i-- > 0; ) {
        !           101:                const char c = host->ptr[i];
        !           102: 
        !           103:                switch (stage) {
        !           104:                case TOPLABEL:
        !           105:                        if (c == '.') {
        !           106:                                /* only switch stage, if this is not the last character */
        !           107:                                if (i != host_len - 1) {
        !           108:                                        if (label_len == 0) {
        !           109:                                                return -1;
        !           110:                                        }
        !           111: 
        !           112:                                        /* check the first character at right of the dot */
        !           113:                                        if (is_ip == 0) {
        !           114:                                                if (!light_isalnum(host->ptr[i+1])) {
        !           115:                                                        return -1;
        !           116:                                                }
        !           117:                                        } else if (!light_isdigit(host->ptr[i+1])) {
        !           118:                                                is_ip = 0;
        !           119:                                        } else if ('-' == host->ptr[i+1]) {
        !           120:                                                return -1;
        !           121:                                        } else {
        !           122:                                                /* just digits */
        !           123:                                                is_ip = 1;
        !           124:                                        }
        !           125: 
        !           126:                                        stage = DOMAINLABEL;
        !           127: 
        !           128:                                        label_len = 0;
        !           129:                                        level++;
        !           130:                                } else if (i == 0) {
        !           131:                                        /* just a dot and nothing else is evil */
        !           132:                                        return -1;
        !           133:                                }
        !           134:                        } else if (i == 0) {
        !           135:                                /* the first character of the hostname */
        !           136:                                if (!light_isalnum(c)) {
        !           137:                                        return -1;
        !           138:                                }
        !           139:                                label_len++;
        !           140:                        } else {
        !           141:                                if (c != '-' && !light_isalnum(c)) {
        !           142:                                        return -1;
        !           143:                                }
        !           144:                                if (is_ip == -1) {
        !           145:                                        if (!light_isdigit(c)) is_ip = 0;
        !           146:                                }
        !           147:                                label_len++;
        !           148:                        }
        !           149: 
        !           150:                        break;
        !           151:                case DOMAINLABEL:
        !           152:                        if (is_ip == 1) {
        !           153:                                if (c == '.') {
        !           154:                                        if (label_len == 0) {
        !           155:                                                return -1;
        !           156:                                        }
        !           157: 
        !           158:                                        label_len = 0;
        !           159:                                        level++;
        !           160:                                } else if (!light_isdigit(c)) {
        !           161:                                        return -1;
        !           162:                                } else {
        !           163:                                        label_len++;
        !           164:                                }
        !           165:                        } else {
        !           166:                                if (c == '.') {
        !           167:                                        if (label_len == 0) {
        !           168:                                                return -1;
        !           169:                                        }
        !           170: 
        !           171:                                        /* c is either - or alphanum here */
        !           172:                                        if ('-' == host->ptr[i+1]) {
        !           173:                                                return -1;
        !           174:                                        }
        !           175: 
        !           176:                                        label_len = 0;
        !           177:                                        level++;
        !           178:                                } else if (i == 0) {
        !           179:                                        if (!light_isalnum(c)) {
        !           180:                                                return -1;
        !           181:                                        }
        !           182:                                        label_len++;
        !           183:                                } else {
        !           184:                                        if (c != '-' && !light_isalnum(c)) {
        !           185:                                                return -1;
        !           186:                                        }
        !           187:                                        label_len++;
        !           188:                                }
        !           189:                        }
        !           190: 
        !           191:                        break;
        !           192:                }
        !           193:        }
        !           194: 
        !           195:        /* a IP has to consist of 4 parts */
        !           196:        if (is_ip == 1 && level != 3) {
        !           197:                return -1;
        !           198:        }
        !           199: 
        !           200:        if (label_len == 0) {
        !           201:                return -1;
        !           202:        }
        !           203: 
        !           204:        return 0;
        !           205: }
        !           206: 
        !           207: #if 0
        !           208: #define DUMP_HEADER
        !           209: #endif
        !           210: 
        !           211: static int http_request_split_value(array *vals, buffer *b) {
        !           212:        size_t i;
        !           213:        int state = 0;
        !           214: 
        !           215:        const char *current;
        !           216:        const char *token_start = NULL, *token_end = NULL;
        !           217:        /*
        !           218:         * parse
        !           219:         *
        !           220:         * val1, val2, val3, val4
        !           221:         *
        !           222:         * into a array (more or less a explode() incl. striping of whitespaces
        !           223:         */
        !           224: 
        !           225:        if (b->used == 0) return 0;
        !           226: 
        !           227:        current = b->ptr;
        !           228:        for (i =  0; i < b->used; ++i, ++current) {
        !           229:                data_string *ds;
        !           230: 
        !           231:                switch (state) {
        !           232:                case 0: /* find start of a token */
        !           233:                        switch (*current) {
        !           234:                        case ' ':
        !           235:                        case '\t': /* skip white space */
        !           236:                        case ',': /* skip empty token */
        !           237:                                break;
        !           238:                        case '\0': /* end of string */
        !           239:                                return 0;
        !           240:                        default:
        !           241:                                /* found real data, switch to state 1 to find the end of the token */
        !           242:                                token_start = token_end = current;
        !           243:                                state = 1;
        !           244:                                break;
        !           245:                        }
        !           246:                        break;
        !           247:                case 1: /* find end of token and last non white space character */
        !           248:                        switch (*current) {
        !           249:                        case ' ':
        !           250:                        case '\t':
        !           251:                                /* space - don't update token_end */
        !           252:                                break;
        !           253:                        case ',':
        !           254:                        case '\0': /* end of string also marks the end of a token */
        !           255:                                if (NULL == (ds = (data_string *)array_get_unused_element(vals, TYPE_STRING))) {
        !           256:                                        ds = data_string_init();
        !           257:                                }
        !           258: 
        !           259:                                buffer_copy_string_len(ds->value, token_start, token_end-token_start+1);
        !           260:                                array_insert_unique(vals, (data_unset *)ds);
        !           261: 
        !           262:                                state = 0;
        !           263:                                break;
        !           264:                        default:
        !           265:                                /* no white space, update token_end to include current character */
        !           266:                                token_end = current;
        !           267:                                break;
        !           268:                        }
        !           269:                        break;
        !           270:                }
        !           271:        }
        !           272: 
        !           273:        return 0;
        !           274: }
        !           275: 
        !           276: static int request_uri_is_valid_char(unsigned char c) {
        !           277:        if (c <= 32) return 0;
        !           278:        if (c == 127) return 0;
        !           279:        if (c == 255) return 0;
        !           280: 
        !           281:        return 1;
        !           282: }
        !           283: 
        !           284: int http_request_parse(server *srv, connection *con) {
        !           285:        char *uri = NULL, *proto = NULL, *method = NULL, con_length_set;
        !           286:        int is_key = 1, key_len = 0, is_ws_after_key = 0, in_folding;
        !           287:        char *value = NULL, *key = NULL;
        !           288:        char *reqline_host = NULL;
        !           289:        int reqline_hostlen = 0;
        !           290: 
        !           291:        enum { HTTP_CONNECTION_UNSET, HTTP_CONNECTION_KEEPALIVE, HTTP_CONNECTION_CLOSE } keep_alive_set = HTTP_CONNECTION_UNSET;
        !           292: 
        !           293:        int line = 0;
        !           294: 
        !           295:        int request_line_stage = 0;
        !           296:        size_t i, first;
        !           297: 
        !           298:        int done = 0;
        !           299: 
        !           300:        /*
        !           301:         * Request: "^(GET|POST|HEAD) ([^ ]+(\\?[^ ]+|)) (HTTP/1\\.[01])$"
        !           302:         * Option : "^([-a-zA-Z]+): (.+)$"
        !           303:         * End    : "^$"
        !           304:         */
        !           305: 
        !           306:        if (con->conf.log_request_header) {
        !           307:                log_error_write(srv, __FILE__, __LINE__, "sdsdSb",
        !           308:                                "fd:", con->fd,
        !           309:                                "request-len:", con->request.request->used,
        !           310:                                "\n", con->request.request);
        !           311:        }
        !           312: 
        !           313:        if (con->request_count > 1 &&
        !           314:            con->request.request->ptr[0] == '\r' &&
        !           315:            con->request.request->ptr[1] == '\n') {
        !           316:                /* we are in keep-alive and might get \r\n after a previous POST request.*/
        !           317: 
        !           318:                buffer_copy_string_len(con->parse_request, con->request.request->ptr + 2, con->request.request->used - 1 - 2);
        !           319:        } else {
        !           320:                /* fill the local request buffer */
        !           321:                buffer_copy_string_buffer(con->parse_request, con->request.request);
        !           322:        }
        !           323: 
        !           324:        keep_alive_set = 0;
        !           325:        con_length_set = 0;
        !           326: 
        !           327:        /* parse the first line of the request
        !           328:         *
        !           329:         * should be:
        !           330:         *
        !           331:         * <method> <uri> <protocol>\r\n
        !           332:         * */
        !           333:        for (i = 0, first = 0; i < con->parse_request->used && line == 0; i++) {
        !           334:                char *cur = con->parse_request->ptr + i;
        !           335: 
        !           336:                switch(*cur) {
        !           337:                case '\r':
        !           338:                        if (con->parse_request->ptr[i+1] == '\n') {
        !           339:                                http_method_t r;
        !           340:                                char *nuri = NULL;
        !           341:                                size_t j;
        !           342: 
        !           343:                                /* \r\n -> \0\0 */
        !           344:                                con->parse_request->ptr[i] = '\0';
        !           345:                                con->parse_request->ptr[i+1] = '\0';
        !           346: 
        !           347:                                buffer_copy_string_len(con->request.request_line, con->parse_request->ptr, i);
        !           348: 
        !           349:                                if (request_line_stage != 2) {
        !           350:                                        con->http_status = 400;
        !           351:                                        con->response.keep_alive = 0;
        !           352:                                        con->keep_alive = 0;
        !           353: 
        !           354:                                        if (srv->srvconf.log_request_header_on_error) {
        !           355:                                                log_error_write(srv, __FILE__, __LINE__, "s", "incomplete request line -> 400");
        !           356:                                                log_error_write(srv, __FILE__, __LINE__, "Sb",
        !           357:                                                                "request-header:\n",
        !           358:                                                                con->request.request);
        !           359:                                        }
        !           360:                                        return 0;
        !           361:                                }
        !           362: 
        !           363:                                proto = con->parse_request->ptr + first;
        !           364: 
        !           365:                                *(uri - 1) = '\0';
        !           366:                                *(proto - 1) = '\0';
        !           367: 
        !           368:                                /* we got the first one :) */
        !           369:                                if (HTTP_METHOD_UNSET == (r = get_http_method_key(method))) {
        !           370:                                        con->http_status = 501;
        !           371:                                        con->response.keep_alive = 0;
        !           372:                                        con->keep_alive = 0;
        !           373: 
        !           374:                                        if (srv->srvconf.log_request_header_on_error) {
        !           375:                                                log_error_write(srv, __FILE__, __LINE__, "s", "unknown http-method -> 501");
        !           376:                                                log_error_write(srv, __FILE__, __LINE__, "Sb",
        !           377:                                                                "request-header:\n",
        !           378:                                                                con->request.request);
        !           379:                                        }
        !           380: 
        !           381:                                        return 0;
        !           382:                                }
        !           383: 
        !           384:                                con->request.http_method = r;
        !           385: 
        !           386:                                /*
        !           387:                                 * RFC2616 says:
        !           388:                                 *
        !           389:                                 * HTTP-Version   = "HTTP" "/" 1*DIGIT "." 1*DIGIT
        !           390:                                 *
        !           391:                                 * */
        !           392:                                if (0 == strncmp(proto, "HTTP/", sizeof("HTTP/") - 1)) {
        !           393:                                        char * major = proto + sizeof("HTTP/") - 1;
        !           394:                                        char * minor = strchr(major, '.');
        !           395:                                        char *err = NULL;
        !           396:                                        int major_num = 0, minor_num = 0;
        !           397: 
        !           398:                                        int invalid_version = 0;
        !           399: 
        !           400:                                        if (NULL == minor || /* no dot */
        !           401:                                            minor == major || /* no major */
        !           402:                                            *(minor + 1) == '\0' /* no minor */) {
        !           403:                                                invalid_version = 1;
        !           404:                                        } else {
        !           405:                                                *minor = '\0';
        !           406:                                                major_num = strtol(major, &err, 10);
        !           407: 
        !           408:                                                if (*err != '\0') invalid_version = 1;
        !           409: 
        !           410:                                                *minor++ = '.';
        !           411:                                                minor_num = strtol(minor, &err, 10);
        !           412: 
        !           413:                                                if (*err != '\0') invalid_version = 1;
        !           414:                                        }
        !           415: 
        !           416:                                        if (invalid_version) {
        !           417:                                                con->http_status = 400;
        !           418:                                                con->keep_alive = 0;
        !           419: 
        !           420:                                                if (srv->srvconf.log_request_header_on_error) {
        !           421:                                                        log_error_write(srv, __FILE__, __LINE__, "s", "unknown protocol -> 400");
        !           422:                                                        log_error_write(srv, __FILE__, __LINE__, "Sb",
        !           423:                                                                        "request-header:\n",
        !           424:                                                                        con->request.request);
        !           425:                                                }
        !           426:                                                return 0;
        !           427:                                        }
        !           428: 
        !           429:                                        if (major_num == 1 && minor_num == 1) {
        !           430:                                                con->request.http_version = con->conf.allow_http11 ? HTTP_VERSION_1_1 : HTTP_VERSION_1_0;
        !           431:                                        } else if (major_num == 1 && minor_num == 0) {
        !           432:                                                con->request.http_version = HTTP_VERSION_1_0;
        !           433:                                        } else {
        !           434:                                                con->http_status = 505;
        !           435: 
        !           436:                                                if (srv->srvconf.log_request_header_on_error) {
        !           437:                                                        log_error_write(srv, __FILE__, __LINE__, "s", "unknown HTTP version -> 505");
        !           438:                                                        log_error_write(srv, __FILE__, __LINE__, "Sb",
        !           439:                                                                        "request-header:\n",
        !           440:                                                                        con->request.request);
        !           441:                                                }
        !           442:                                                return 0;
        !           443:                                        }
        !           444:                                } else {
        !           445:                                        con->http_status = 400;
        !           446:                                        con->keep_alive = 0;
        !           447: 
        !           448:                                        if (srv->srvconf.log_request_header_on_error) {
        !           449:                                                log_error_write(srv, __FILE__, __LINE__, "s", "unknown protocol -> 400");
        !           450:                                                log_error_write(srv, __FILE__, __LINE__, "Sb",
        !           451:                                                                "request-header:\n",
        !           452:                                                                con->request.request);
        !           453:                                        }
        !           454:                                        return 0;
        !           455:                                }
        !           456: 
        !           457:                                if (0 == strncmp(uri, "http://", 7) &&
        !           458:                                    NULL != (nuri = strchr(uri + 7, '/'))) {
        !           459:                                        reqline_host = uri + 7;
        !           460:                                        reqline_hostlen = nuri - reqline_host;
        !           461: 
        !           462:                                        buffer_copy_string_len(con->request.uri, nuri, proto - nuri - 1);
        !           463:                                } else if (0 == strncmp(uri, "https://", 8) &&
        !           464:                                    NULL != (nuri = strchr(uri + 8, '/'))) {
        !           465:                                        reqline_host = uri + 8;
        !           466:                                        reqline_hostlen = nuri - reqline_host;
        !           467: 
        !           468:                                        buffer_copy_string_len(con->request.uri, nuri, proto - nuri - 1);
        !           469:                                } else {
        !           470:                                        /* everything looks good so far */
        !           471:                                        buffer_copy_string_len(con->request.uri, uri, proto - uri - 1);
        !           472:                                }
        !           473: 
        !           474:                                /* check uri for invalid characters */
        !           475:                                for (j = 0; j < con->request.uri->used - 1; j++) {
        !           476:                                        if (!request_uri_is_valid_char(con->request.uri->ptr[j])) {
        !           477:                                                unsigned char buf[2];
        !           478:                                                con->http_status = 400;
        !           479:                                                con->keep_alive = 0;
        !           480: 
        !           481:                                                if (srv->srvconf.log_request_header_on_error) {
        !           482:                                                        buf[0] = con->request.uri->ptr[j];
        !           483:                                                        buf[1] = '\0';
        !           484: 
        !           485:                                                        if (con->request.uri->ptr[j] > 32 &&
        !           486:                                                            con->request.uri->ptr[j] != 127) {
        !           487:                                                                /* the character is printable -> print it */
        !           488:                                                                log_error_write(srv, __FILE__, __LINE__, "ss",
        !           489:                                                                                "invalid character in URI -> 400",
        !           490:                                                                                buf);
        !           491:                                                        } else {
        !           492:                                                                /* a control-character, print ascii-code */
        !           493:                                                                log_error_write(srv, __FILE__, __LINE__, "sd",
        !           494:                                                                                "invalid character in URI -> 400",
        !           495:                                                                                con->request.uri->ptr[j]);
        !           496:                                                        }
        !           497: 
        !           498:                                                        log_error_write(srv, __FILE__, __LINE__, "Sb",
        !           499:                                                                        "request-header:\n",
        !           500:                                                                        con->request.request);
        !           501:                                                }
        !           502: 
        !           503:                                                return 0;
        !           504:                                        }
        !           505:                                }
        !           506: 
        !           507:                                buffer_copy_string_buffer(con->request.orig_uri, con->request.uri);
        !           508: 
        !           509:                                con->http_status = 0;
        !           510: 
        !           511:                                i++;
        !           512:                                line++;
        !           513:                                first = i+1;
        !           514:                        }
        !           515:                        break;
        !           516:                case ' ':
        !           517:                        switch(request_line_stage) {
        !           518:                        case 0:
        !           519:                                /* GET|POST|... */
        !           520:                                method = con->parse_request->ptr + first;
        !           521:                                first = i + 1;
        !           522:                                break;
        !           523:                        case 1:
        !           524:                                /* /foobar/... */
        !           525:                                uri = con->parse_request->ptr + first;
        !           526:                                first = i + 1;
        !           527:                                break;
        !           528:                        default:
        !           529:                                /* ERROR, one space to much */
        !           530:                                con->http_status = 400;
        !           531:                                con->response.keep_alive = 0;
        !           532:                                con->keep_alive = 0;
        !           533: 
        !           534:                                if (srv->srvconf.log_request_header_on_error) {
        !           535:                                        log_error_write(srv, __FILE__, __LINE__, "s", "overlong request line -> 400");
        !           536:                                        log_error_write(srv, __FILE__, __LINE__, "Sb",
        !           537:                                                        "request-header:\n",
        !           538:                                                        con->request.request);
        !           539:                                }
        !           540:                                return 0;
        !           541:                        }
        !           542: 
        !           543:                        request_line_stage++;
        !           544:                        break;
        !           545:                }
        !           546:        }
        !           547: 
        !           548:        in_folding = 0;
        !           549: 
        !           550:        if (con->request.uri->used == 1) {
        !           551:                con->http_status = 400;
        !           552:                con->response.keep_alive = 0;
        !           553:                con->keep_alive = 0;
        !           554: 
        !           555:                if (srv->srvconf.log_request_header_on_error) {
        !           556:                        log_error_write(srv, __FILE__, __LINE__, "s", "no uri specified -> 400");
        !           557:                        log_error_write(srv, __FILE__, __LINE__, "Sb",
        !           558:                                                        "request-header:\n",
        !           559:                                                        con->request.request);
        !           560:                }
        !           561:                return 0;
        !           562:        }
        !           563: 
        !           564:        if (reqline_host) {
        !           565:                /* Insert as host header */
        !           566:                data_string *ds;
        !           567: 
        !           568:                if (NULL == (ds = (data_string *)array_get_unused_element(con->request.headers, TYPE_STRING))) {
        !           569:                        ds = data_string_init();
        !           570:                }
        !           571: 
        !           572:                buffer_copy_string_len(ds->key, CONST_STR_LEN("Host"));
        !           573:                buffer_copy_string_len(ds->value, reqline_host, reqline_hostlen);
        !           574:                array_insert_unique(con->request.headers, (data_unset *)ds);
        !           575:                con->request.http_host = ds->value;
        !           576:        }
        !           577: 
        !           578:        for (; i < con->parse_request->used && !done; i++) {
        !           579:                char *cur = con->parse_request->ptr + i;
        !           580: 
        !           581:                if (is_key) {
        !           582:                        size_t j;
        !           583:                        int got_colon = 0;
        !           584: 
        !           585:                        /**
        !           586:                         * 1*<any CHAR except CTLs or separators>
        !           587:                         * CTLs == 0-31 + 127, CHAR = 7-bit ascii (0..127)
        !           588:                         *
        !           589:                         */
        !           590:                        switch(*cur) {
        !           591:                        case ':':
        !           592:                                is_key = 0;
        !           593: 
        !           594:                                value = cur + 1;
        !           595: 
        !           596:                                if (is_ws_after_key == 0) {
        !           597:                                        key_len = i - first;
        !           598:                                }
        !           599:                                is_ws_after_key = 0;
        !           600: 
        !           601:                                break;
        !           602:                        case '(':
        !           603:                        case ')':
        !           604:                        case '<':
        !           605:                        case '>':
        !           606:                        case '@':
        !           607:                        case ',':
        !           608:                        case ';':
        !           609:                        case '\\':
        !           610:                        case '\"':
        !           611:                        case '/':
        !           612:                        case '[':
        !           613:                        case ']':
        !           614:                        case '?':
        !           615:                        case '=':
        !           616:                        case '{':
        !           617:                        case '}':
        !           618:                                con->http_status = 400;
        !           619:                                con->keep_alive = 0;
        !           620:                                con->response.keep_alive = 0;
        !           621: 
        !           622:                                if (srv->srvconf.log_request_header_on_error) {
        !           623:                                        log_error_write(srv, __FILE__, __LINE__, "sbsds",
        !           624:                                                "invalid character in key", con->request.request, cur, *cur, "-> 400");
        !           625: 
        !           626:                                        log_error_write(srv, __FILE__, __LINE__, "Sb",
        !           627:                                                "request-header:\n",
        !           628:                                                con->request.request);
        !           629:                                }
        !           630:                                return 0;
        !           631:                        case ' ':
        !           632:                        case '\t':
        !           633:                                if (i == first) {
        !           634:                                        is_key = 0;
        !           635:                                        in_folding = 1;
        !           636:                                        value = cur;
        !           637: 
        !           638:                                        break;
        !           639:                                }
        !           640: 
        !           641: 
        !           642:                                key_len = i - first;
        !           643: 
        !           644:                                /* skip every thing up to the : */
        !           645:                                for (j = 1; !got_colon; j++) {
        !           646:                                        switch(con->parse_request->ptr[j + i]) {
        !           647:                                        case ' ':
        !           648:                                        case '\t':
        !           649:                                                /* skip WS */
        !           650:                                                continue;
        !           651:                                        case ':':
        !           652:                                                /* ok, done; handle the colon the usual way */
        !           653: 
        !           654:                                                i += j - 1;
        !           655:                                                got_colon = 1;
        !           656:                                                is_ws_after_key = 1; /* we already know the key length */
        !           657: 
        !           658:                                                break;
        !           659:                                        default:
        !           660:                                                /* error */
        !           661: 
        !           662:                                                if (srv->srvconf.log_request_header_on_error) {
        !           663:                                                        log_error_write(srv, __FILE__, __LINE__, "s", "WS character in key -> 400");
        !           664:                                                        log_error_write(srv, __FILE__, __LINE__, "Sb",
        !           665:                                                                "request-header:\n",
        !           666:                                                                con->request.request);
        !           667:                                                }
        !           668: 
        !           669:                                                con->http_status = 400;
        !           670:                                                con->response.keep_alive = 0;
        !           671:                                                con->keep_alive = 0;
        !           672: 
        !           673:                                                return 0;
        !           674:                                        }
        !           675:                                }
        !           676: 
        !           677:                                break;
        !           678:                        case '\r':
        !           679:                                if (con->parse_request->ptr[i+1] == '\n' && i == first) {
        !           680:                                        /* End of Header */
        !           681:                                        con->parse_request->ptr[i] = '\0';
        !           682:                                        con->parse_request->ptr[i+1] = '\0';
        !           683: 
        !           684:                                        i++;
        !           685: 
        !           686:                                        done = 1;
        !           687:                                } else {
        !           688:                                        if (srv->srvconf.log_request_header_on_error) {
        !           689:                                                log_error_write(srv, __FILE__, __LINE__, "s", "CR without LF -> 400");
        !           690:                                                log_error_write(srv, __FILE__, __LINE__, "Sb",
        !           691:                                                        "request-header:\n",
        !           692:                                                        con->request.request);
        !           693:                                        }
        !           694: 
        !           695:                                        con->http_status = 400;
        !           696:                                        con->keep_alive = 0;
        !           697:                                        con->response.keep_alive = 0;
        !           698:                                        return 0;
        !           699:                                }
        !           700:                                break;
        !           701:                        default:
        !           702:                                if (*cur < 32 || ((unsigned char)*cur) >= 127) {
        !           703:                                        con->http_status = 400;
        !           704:                                        con->keep_alive = 0;
        !           705:                                        con->response.keep_alive = 0;
        !           706: 
        !           707:                                        if (srv->srvconf.log_request_header_on_error) {
        !           708:                                                log_error_write(srv, __FILE__, __LINE__, "sbsds",
        !           709:                                                        "invalid character in key", con->request.request, cur, *cur, "-> 400");
        !           710: 
        !           711:                                                log_error_write(srv, __FILE__, __LINE__, "Sb",
        !           712:                                                        "request-header:\n",
        !           713:                                                        con->request.request);
        !           714:                                        }
        !           715: 
        !           716:                                        return 0;
        !           717:                                }
        !           718:                                /* ok */
        !           719:                                break;
        !           720:                        }
        !           721:                } else {
        !           722:                        switch(*cur) {
        !           723:                        case '\r':
        !           724:                                if (con->parse_request->ptr[i+1] == '\n') {
        !           725:                                        data_string *ds = NULL;
        !           726: 
        !           727:                                        /* End of Headerline */
        !           728:                                        con->parse_request->ptr[i] = '\0';
        !           729:                                        con->parse_request->ptr[i+1] = '\0';
        !           730: 
        !           731:                                        if (in_folding) {
        !           732:                                                buffer *key_b;
        !           733:                                                /**
        !           734:                                                 * we use a evil hack to handle the line-folding
        !           735:                                                 * 
        !           736:                                                 * As array_insert_unique() deletes 'ds' in the case of a duplicate
        !           737:                                                 * ds points somewhere and we get a evil crash. As a solution we keep the old
        !           738:                                                 * "key" and get the current value from the hash and append us
        !           739:                                                 *
        !           740:                                                 * */
        !           741: 
        !           742:                                                if (!key || !key_len) {
        !           743:                                                        /* 400 */
        !           744: 
        !           745:                                                        if (srv->srvconf.log_request_header_on_error) {
        !           746:                                                                log_error_write(srv, __FILE__, __LINE__, "s", "WS at the start of first line -> 400");
        !           747: 
        !           748:                                                                log_error_write(srv, __FILE__, __LINE__, "Sb",
        !           749:                                                                        "request-header:\n",
        !           750:                                                                        con->request.request);
        !           751:                                                        }
        !           752: 
        !           753: 
        !           754:                                                        con->http_status = 400;
        !           755:                                                        con->keep_alive = 0;
        !           756:                                                        con->response.keep_alive = 0;
        !           757:                                                        return 0;
        !           758:                                                }
        !           759: 
        !           760:                                                key_b = buffer_init();
        !           761:                                                buffer_copy_string_len(key_b, key, key_len);
        !           762: 
        !           763:                                                if (NULL != (ds = (data_string *)array_get_element(con->request.headers, key_b->ptr))) {
        !           764:                                                        buffer_append_string(ds->value, value);
        !           765:                                                }
        !           766: 
        !           767:                                                buffer_free(key_b);
        !           768:                                        } else {
        !           769:                                                int s_len;
        !           770:                                                key = con->parse_request->ptr + first;
        !           771: 
        !           772:                                                s_len = cur - value;
        !           773: 
        !           774:                                                /* strip trailing white-spaces */
        !           775:                                                for (; s_len > 0 && 
        !           776:                                                                (value[s_len - 1] == ' ' || 
        !           777:                                                                 value[s_len - 1] == '\t'); s_len--);
        !           778: 
        !           779:                                                value[s_len] = '\0';
        !           780: 
        !           781:                                                if (s_len > 0) {
        !           782:                                                        int cmp = 0;
        !           783:                                                        if (NULL == (ds = (data_string *)array_get_unused_element(con->request.headers, TYPE_STRING))) {
        !           784:                                                                ds = data_string_init();
        !           785:                                                        }
        !           786:                                                        buffer_copy_string_len(ds->key, key, key_len);
        !           787:                                                        buffer_copy_string_len(ds->value, value, s_len);
        !           788: 
        !           789:                                                        /* retreive values
        !           790:                                                         *
        !           791:                                                         *
        !           792:                                                         * the list of options is sorted to simplify the search
        !           793:                                                         */
        !           794: 
        !           795:                                                        if (0 == (cmp = buffer_caseless_compare(CONST_BUF_LEN(ds->key), CONST_STR_LEN("Connection")))) {
        !           796:                                                                array *vals;
        !           797:                                                                size_t vi;
        !           798: 
        !           799:                                                                /* split on , */
        !           800: 
        !           801:                                                                vals = srv->split_vals;
        !           802: 
        !           803:                                                                array_reset(vals);
        !           804: 
        !           805:                                                                http_request_split_value(vals, ds->value);
        !           806: 
        !           807:                                                                for (vi = 0; vi < vals->used; vi++) {
        !           808:                                                                        data_string *dsv = (data_string *)vals->data[vi];
        !           809: 
        !           810:                                                                        if (0 == buffer_caseless_compare(CONST_BUF_LEN(dsv->value), CONST_STR_LEN("keep-alive"))) {
        !           811:                                                                                keep_alive_set = HTTP_CONNECTION_KEEPALIVE;
        !           812: 
        !           813:                                                                                break;
        !           814:                                                                        } else if (0 == buffer_caseless_compare(CONST_BUF_LEN(dsv->value), CONST_STR_LEN("close"))) {
        !           815:                                                                                keep_alive_set = HTTP_CONNECTION_CLOSE;
        !           816: 
        !           817:                                                                                break;
        !           818:                                                                        }
        !           819:                                                                }
        !           820: 
        !           821:                                                        } else if (cmp > 0 && 0 == (cmp = buffer_caseless_compare(CONST_BUF_LEN(ds->key), CONST_STR_LEN("Content-Length")))) {
        !           822:                                                                char *err;
        !           823:                                                                unsigned long int r;
        !           824:                                                                size_t j;
        !           825: 
        !           826:                                                                if (con_length_set) {
        !           827:                                                                        con->http_status = 400;
        !           828:                                                                        con->keep_alive = 0;
        !           829: 
        !           830:                                                                        if (srv->srvconf.log_request_header_on_error) {
        !           831:                                                                                log_error_write(srv, __FILE__, __LINE__, "s",
        !           832:                                                                                                "duplicate Content-Length-header -> 400");
        !           833:                                                                                log_error_write(srv, __FILE__, __LINE__, "Sb",
        !           834:                                                                                                "request-header:\n",
        !           835:                                                                                                con->request.request);
        !           836:                                                                        }
        !           837:                                                                        array_insert_unique(con->request.headers, (data_unset *)ds);
        !           838:                                                                        return 0;
        !           839:                                                                }
        !           840: 
        !           841:                                                                if (ds->value->used == 0) SEGFAULT();
        !           842: 
        !           843:                                                                for (j = 0; j < ds->value->used - 1; j++) {
        !           844:                                                                        char c = ds->value->ptr[j];
        !           845:                                                                        if (!isdigit((unsigned char)c)) {
        !           846:                                                                                log_error_write(srv, __FILE__, __LINE__, "sbs",
        !           847:                                                                                                "content-length broken:", ds->value, "-> 400");
        !           848: 
        !           849:                                                                                con->http_status = 400;
        !           850:                                                                                con->keep_alive = 0;
        !           851: 
        !           852:                                                                                array_insert_unique(con->request.headers, (data_unset *)ds);
        !           853:                                                                                return 0;
        !           854:                                                                        }
        !           855:                                                                }
        !           856: 
        !           857:                                                                r = strtoul(ds->value->ptr, &err, 10);
        !           858: 
        !           859:                                                                if (*err == '\0') {
        !           860:                                                                        con_length_set = 1;
        !           861:                                                                        con->request.content_length = r;
        !           862:                                                                } else {
        !           863:                                                                        log_error_write(srv, __FILE__, __LINE__, "sbs",
        !           864:                                                                                        "content-length broken:", ds->value, "-> 400");
        !           865: 
        !           866:                                                                        con->http_status = 400;
        !           867:                                                                        con->keep_alive = 0;
        !           868: 
        !           869:                                                                        array_insert_unique(con->request.headers, (data_unset *)ds);
        !           870:                                                                        return 0;
        !           871:                                                                }
        !           872:                                                        } else if (cmp > 0 && 0 == (cmp = buffer_caseless_compare(CONST_BUF_LEN(ds->key), CONST_STR_LEN("Content-Type")))) {
        !           873:                                                                /* if dup, only the first one will survive */
        !           874:                                                                if (!con->request.http_content_type) {
        !           875:                                                                        con->request.http_content_type = ds->value->ptr;
        !           876:                                                                } else {
        !           877:                                                                        con->http_status = 400;
        !           878:                                                                        con->keep_alive = 0;
        !           879: 
        !           880:                                                                        if (srv->srvconf.log_request_header_on_error) {
        !           881:                                                                                log_error_write(srv, __FILE__, __LINE__, "s",
        !           882:                                                                                                "duplicate Content-Type-header -> 400");
        !           883:                                                                                log_error_write(srv, __FILE__, __LINE__, "Sb",
        !           884:                                                                                                "request-header:\n",
        !           885:                                                                                                con->request.request);
        !           886:                                                                        }
        !           887:                                                                        array_insert_unique(con->request.headers, (data_unset *)ds);
        !           888:                                                                        return 0;
        !           889:                                                                }
        !           890:                                                        } else if (cmp > 0 && 0 == (cmp = buffer_caseless_compare(CONST_BUF_LEN(ds->key), CONST_STR_LEN("Expect")))) {
        !           891:                                                                /* HTTP 2616 8.2.3
        !           892:                                                                 * Expect: 100-continue
        !           893:                                                                 *
        !           894:                                                                 *   -> (10.1.1)  100 (read content, process request, send final status-code)
        !           895:                                                                 *   -> (10.4.18) 417 (close)
        !           896:                                                                 *
        !           897:                                                                 * (not handled at all yet, we always send 417 here)
        !           898:                                                                 *
        !           899:                                                                 * What has to be added ?
        !           900:                                                                 * 1. handling of chunked request body
        !           901:                                                                 * 2. out-of-order sending from the HTTP/1.1 100 Continue
        !           902:                                                                 *    header
        !           903:                                                                 *
        !           904:                                                                 */
        !           905: 
        !           906:                                                                if (srv->srvconf.reject_expect_100_with_417 && 0 == buffer_caseless_compare(CONST_BUF_LEN(ds->value), CONST_STR_LEN("100-continue"))) {
        !           907:                                                                        con->http_status = 417;
        !           908:                                                                        con->keep_alive = 0;
        !           909:                                                                        array_insert_unique(con->request.headers, (data_unset *)ds);
        !           910:                                                                        return 0;
        !           911:                                                                }
        !           912:                                                        } else if (cmp > 0 && 0 == (cmp = buffer_caseless_compare(CONST_BUF_LEN(ds->key), CONST_STR_LEN("Host")))) {
        !           913:                                                                if (reqline_host) {
        !           914:                                                                        /* ignore all host: headers as we got the host in the request line */
        !           915:                                                                        ds->free((data_unset*) ds);
        !           916:                                                                        ds = NULL;
        !           917:                                                                } else if (!con->request.http_host) {
        !           918:                                                                        con->request.http_host = ds->value;
        !           919:                                                                } else {
        !           920:                                                                        con->http_status = 400;
        !           921:                                                                        con->keep_alive = 0;
        !           922: 
        !           923:                                                                        if (srv->srvconf.log_request_header_on_error) {
        !           924:                                                                                log_error_write(srv, __FILE__, __LINE__, "s",
        !           925:                                                                                                "duplicate Host-header -> 400");
        !           926:                                                                                log_error_write(srv, __FILE__, __LINE__, "Sb",
        !           927:                                                                                                "request-header:\n",
        !           928:                                                                                                con->request.request);
        !           929:                                                                        }
        !           930:                                                                        array_insert_unique(con->request.headers, (data_unset *)ds);
        !           931:                                                                        return 0;
        !           932:                                                                }
        !           933:                                                        } else if (cmp > 0 && 0 == (cmp = buffer_caseless_compare(CONST_BUF_LEN(ds->key), CONST_STR_LEN("If-Modified-Since")))) {
        !           934:                                                                /* Proxies sometimes send dup headers
        !           935:                                                                 * if they are the same we ignore the second
        !           936:                                                                 * if not, we raise an error */
        !           937:                                                                if (!con->request.http_if_modified_since) {
        !           938:                                                                        con->request.http_if_modified_since = ds->value->ptr;
        !           939:                                                                } else if (0 == strcasecmp(con->request.http_if_modified_since,
        !           940:                                                                                        ds->value->ptr)) {
        !           941:                                                                        /* ignore it if they are the same */
        !           942: 
        !           943:                                                                        ds->free((data_unset *)ds);
        !           944:                                                                        ds = NULL;
        !           945:                                                                } else {
        !           946:                                                                        con->http_status = 400;
        !           947:                                                                        con->keep_alive = 0;
        !           948: 
        !           949:                                                                        if (srv->srvconf.log_request_header_on_error) {
        !           950:                                                                                log_error_write(srv, __FILE__, __LINE__, "s",
        !           951:                                                                                                "duplicate If-Modified-Since header -> 400");
        !           952:                                                                                log_error_write(srv, __FILE__, __LINE__, "Sb",
        !           953:                                                                                                "request-header:\n",
        !           954:                                                                                                con->request.request);
        !           955:                                                                        }
        !           956:                                                                        array_insert_unique(con->request.headers, (data_unset *)ds);
        !           957:                                                                        return 0;
        !           958:                                                                }
        !           959:                                                        } else if (cmp > 0 && 0 == (cmp = buffer_caseless_compare(CONST_BUF_LEN(ds->key), CONST_STR_LEN("If-None-Match")))) {
        !           960:                                                                /* if dup, only the first one will survive */
        !           961:                                                                if (!con->request.http_if_none_match) {
        !           962:                                                                        con->request.http_if_none_match = ds->value->ptr;
        !           963:                                                                } else {
        !           964:                                                                        ds->free((data_unset*) ds);
        !           965:                                                                        ds = NULL;
        !           966:                                                                }
        !           967:                                                        } else if (cmp > 0 && 0 == (cmp = buffer_caseless_compare(CONST_BUF_LEN(ds->key), CONST_STR_LEN("Range")))) {
        !           968:                                                                if (!con->request.http_range) {
        !           969:                                                                        /* bytes=.*-.* */
        !           970: 
        !           971:                                                                        if (0 == strncasecmp(ds->value->ptr, "bytes=", 6) &&
        !           972:                                                                            NULL != strchr(ds->value->ptr+6, '-')) {
        !           973: 
        !           974:                                                                                /* if dup, only the first one will survive */
        !           975:                                                                                con->request.http_range = ds->value->ptr + 6;
        !           976:                                                                        }
        !           977:                                                                } else {
        !           978:                                                                        con->http_status = 400;
        !           979:                                                                        con->keep_alive = 0;
        !           980: 
        !           981:                                                                        if (srv->srvconf.log_request_header_on_error) {
        !           982:                                                                                log_error_write(srv, __FILE__, __LINE__, "s",
        !           983:                                                                                                "duplicate Range-header -> 400");
        !           984:                                                                                log_error_write(srv, __FILE__, __LINE__, "Sb",
        !           985:                                                                                                "request-header:\n",
        !           986:                                                                                                con->request.request);
        !           987:                                                                        }
        !           988:                                                                        array_insert_unique(con->request.headers, (data_unset *)ds);
        !           989:                                                                        return 0;
        !           990:                                                                }
        !           991:                                                        }
        !           992: 
        !           993:                                                        if (ds) array_insert_unique(con->request.headers, (data_unset *)ds);
        !           994:                                                } else {
        !           995:                                                        /* empty header-fields are not allowed by HTTP-RFC, we just ignore them */
        !           996:                                                }
        !           997:                                        }
        !           998: 
        !           999:                                        i++;
        !          1000:                                        first = i+1;
        !          1001:                                        is_key = 1;
        !          1002:                                        value = NULL;
        !          1003: #if 0
        !          1004:                                        /**
        !          1005:                                         * for Bug 1230 keep the key_len a live
        !          1006:                                         */
        !          1007:                                        key_len = 0; 
        !          1008: #endif
        !          1009:                                        in_folding = 0;
        !          1010:                                } else {
        !          1011:                                        if (srv->srvconf.log_request_header_on_error) {
        !          1012:                                                log_error_write(srv, __FILE__, __LINE__, "sbs",
        !          1013:                                                                "CR without LF", con->request.request, "-> 400");
        !          1014:                                        }
        !          1015: 
        !          1016:                                        con->http_status = 400;
        !          1017:                                        con->keep_alive = 0;
        !          1018:                                        con->response.keep_alive = 0;
        !          1019:                                        return 0;
        !          1020:                                }
        !          1021:                                break;
        !          1022:                        case ' ':
        !          1023:                        case '\t':
        !          1024:                                /* strip leading WS */
        !          1025:                                if (value == cur) value = cur+1;
        !          1026:                        default:
        !          1027:                                if (*cur >= 0 && *cur < 32 && *cur != '\t') {
        !          1028:                                        if (srv->srvconf.log_request_header_on_error) {
        !          1029:                                                log_error_write(srv, __FILE__, __LINE__, "sds",
        !          1030:                                                                "invalid char in header", (int)*cur, "-> 400");
        !          1031:                                        }
        !          1032: 
        !          1033:                                        con->http_status = 400;
        !          1034:                                        con->keep_alive = 0;
        !          1035: 
        !          1036:                                        return 0;
        !          1037:                                }
        !          1038:                                break;
        !          1039:                        }
        !          1040:                }
        !          1041:        }
        !          1042: 
        !          1043:        con->header_len = i;
        !          1044: 
        !          1045:        /* do some post-processing */
        !          1046: 
        !          1047:        if (con->request.http_version == HTTP_VERSION_1_1) {
        !          1048:                if (keep_alive_set != HTTP_CONNECTION_CLOSE) {
        !          1049:                        /* no Connection-Header sent */
        !          1050: 
        !          1051:                        /* HTTP/1.1 -> keep-alive default TRUE */
        !          1052:                        con->keep_alive = 1;
        !          1053:                } else {
        !          1054:                        con->keep_alive = 0;
        !          1055:                }
        !          1056: 
        !          1057:                /* RFC 2616, 14.23 */
        !          1058:                if (con->request.http_host == NULL ||
        !          1059:                    buffer_is_empty(con->request.http_host)) {
        !          1060:                        con->http_status = 400;
        !          1061:                        con->response.keep_alive = 0;
        !          1062:                        con->keep_alive = 0;
        !          1063: 
        !          1064:                        if (srv->srvconf.log_request_header_on_error) {
        !          1065:                                log_error_write(srv, __FILE__, __LINE__, "s", "HTTP/1.1 but Host missing -> 400");
        !          1066:                                log_error_write(srv, __FILE__, __LINE__, "Sb",
        !          1067:                                                "request-header:\n",
        !          1068:                                                con->request.request);
        !          1069:                        }
        !          1070:                        return 0;
        !          1071:                }
        !          1072:        } else {
        !          1073:                if (keep_alive_set == HTTP_CONNECTION_KEEPALIVE) {
        !          1074:                        /* no Connection-Header sent */
        !          1075: 
        !          1076:                        /* HTTP/1.0 -> keep-alive default FALSE  */
        !          1077:                        con->keep_alive = 1;
        !          1078:                } else {
        !          1079:                        con->keep_alive = 0;
        !          1080:                }
        !          1081:        }
        !          1082: 
        !          1083:        /* check hostname field if it is set */
        !          1084:        if (NULL != con->request.http_host &&
        !          1085:            0 != request_check_hostname(srv, con, con->request.http_host)) {
        !          1086: 
        !          1087:                if (srv->srvconf.log_request_header_on_error) {
        !          1088:                        log_error_write(srv, __FILE__, __LINE__, "s",
        !          1089:                                        "Invalid Hostname -> 400");
        !          1090:                        log_error_write(srv, __FILE__, __LINE__, "Sb",
        !          1091:                                        "request-header:\n",
        !          1092:                                        con->request.request);
        !          1093:                }
        !          1094: 
        !          1095:                con->http_status = 400;
        !          1096:                con->response.keep_alive = 0;
        !          1097:                con->keep_alive = 0;
        !          1098: 
        !          1099:                return 0;
        !          1100:        }
        !          1101: 
        !          1102:        switch(con->request.http_method) {
        !          1103:        case HTTP_METHOD_GET:
        !          1104:        case HTTP_METHOD_HEAD:
        !          1105:                /* content-length is forbidden for those */
        !          1106:                if (con_length_set && con->request.content_length != 0) {
        !          1107:                        /* content-length is missing */
        !          1108:                        log_error_write(srv, __FILE__, __LINE__, "s",
        !          1109:                                        "GET/HEAD with content-length -> 400");
        !          1110: 
        !          1111:                        con->keep_alive = 0;
        !          1112:                        con->http_status = 400;
        !          1113:                        return 0;
        !          1114:                }
        !          1115:                break;
        !          1116:        case HTTP_METHOD_POST:
        !          1117:                /* content-length is required for them */
        !          1118:                if (!con_length_set) {
        !          1119:                        /* content-length is missing */
        !          1120:                        log_error_write(srv, __FILE__, __LINE__, "s",
        !          1121:                                        "POST-request, but content-length missing -> 411");
        !          1122: 
        !          1123:                        con->keep_alive = 0;
        !          1124:                        con->http_status = 411;
        !          1125:                        return 0;
        !          1126: 
        !          1127:                }
        !          1128:                break;
        !          1129:        default:
        !          1130:                /* the may have a content-length */
        !          1131:                break;
        !          1132:        }
        !          1133: 
        !          1134: 
        !          1135:        /* check if we have read post data */
        !          1136:        if (con_length_set) {
        !          1137:                /* don't handle more the SSIZE_MAX bytes in content-length */
        !          1138:                if (con->request.content_length > SSIZE_MAX) {
        !          1139:                        con->http_status = 413;
        !          1140:                        con->keep_alive = 0;
        !          1141: 
        !          1142:                        log_error_write(srv, __FILE__, __LINE__, "sos",
        !          1143:                                        "request-size too long:", (off_t) con->request.content_length, "-> 413");
        !          1144:                        return 0;
        !          1145:                }
        !          1146: 
        !          1147:                /* divide by 1024 as srvconf.max_request_size is in kBytes */
        !          1148:                if (srv->srvconf.max_request_size != 0 &&
        !          1149:                    (con->request.content_length >> 10) > srv->srvconf.max_request_size) {
        !          1150:                        /* the request body itself is larger then
        !          1151:                         * our our max_request_size
        !          1152:                         */
        !          1153: 
        !          1154:                        con->http_status = 413;
        !          1155:                        con->keep_alive = 0;
        !          1156: 
        !          1157:                        log_error_write(srv, __FILE__, __LINE__, "sos",
        !          1158:                                        "request-size too long:", (off_t) con->request.content_length, "-> 413");
        !          1159:                        return 0;
        !          1160:                }
        !          1161: 
        !          1162: 
        !          1163:                /* we have content */
        !          1164:                if (con->request.content_length != 0) {
        !          1165:                        return 1;
        !          1166:                }
        !          1167:        }
        !          1168: 
        !          1169:        return 0;
        !          1170: }
        !          1171: 
        !          1172: int http_request_header_finished(server *srv, connection *con) {
        !          1173:        UNUSED(srv);
        !          1174: 
        !          1175:        if (con->request.request->used < 5) return 0;
        !          1176: 
        !          1177:        if (0 == memcmp(con->request.request->ptr + con->request.request->used - 5, "\r\n\r\n", 4)) return 1;
        !          1178:        if (NULL != strstr(con->request.request->ptr, "\r\n\r\n")) return 1;
        !          1179: 
        !          1180:        return 0;
        !          1181: }

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>