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

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

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