Annotation of embedaddon/lighttpd/src/request.c, revision 1.1.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>