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

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

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