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

1.1       misho       1: #include "response.h"
                      2: #include "keyvalue.h"
                      3: #include "log.h"
                      4: #include "stat_cache.h"
                      5: #include "chunk.h"
                      6: 
                      7: #include "configfile.h"
                      8: #include "connections.h"
                      9: 
                     10: #include "plugin.h"
                     11: 
                     12: #include <sys/types.h>
                     13: #include <sys/stat.h>
                     14: 
                     15: #include <limits.h>
                     16: #include <errno.h>
                     17: #include <fcntl.h>
                     18: #include <stdlib.h>
                     19: #include <string.h>
                     20: #include <time.h>
                     21: #include <unistd.h>
                     22: #include <ctype.h>
                     23: #include <assert.h>
                     24: 
                     25: #include <stdio.h>
                     26: 
                     27: #include "sys-socket.h"
                     28: #include "version.h"
                     29: 
                     30: int http_response_write_header(server *srv, connection *con) {
                     31:        buffer *b;
                     32:        size_t i;
                     33:        int have_date = 0;
                     34:        int have_server = 0;
                     35: 
                     36:        b = chunkqueue_get_prepend_buffer(con->write_queue);
                     37: 
                     38:        if (con->request.http_version == HTTP_VERSION_1_1) {
                     39:                buffer_copy_string_len(b, CONST_STR_LEN("HTTP/1.1 "));
                     40:        } else {
                     41:                buffer_copy_string_len(b, CONST_STR_LEN("HTTP/1.0 "));
                     42:        }
                     43:        buffer_append_long(b, con->http_status);
                     44:        buffer_append_string_len(b, CONST_STR_LEN(" "));
                     45:        buffer_append_string(b, get_http_status_name(con->http_status));
                     46: 
                     47:        /* disable keep-alive if requested */
                     48:        if (con->request_count > con->conf.max_keep_alive_requests || 0 == con->conf.max_keep_alive_idle) {
                     49:                con->keep_alive = 0;
                     50:        } else {
                     51:                con->keep_alive_idle = con->conf.max_keep_alive_idle;
                     52:        }
                     53: 
                     54:        if (con->request.http_version != HTTP_VERSION_1_1 || con->keep_alive == 0) {
                     55:                if (con->keep_alive) {
                     56:                        response_header_overwrite(srv, con, CONST_STR_LEN("Connection"), CONST_STR_LEN("keep-alive"));
                     57:                } else {
                     58:                        response_header_overwrite(srv, con, CONST_STR_LEN("Connection"), CONST_STR_LEN("close"));
                     59:                }
                     60:        }
                     61: 
                     62:        if (con->response.transfer_encoding & HTTP_TRANSFER_ENCODING_CHUNKED) {
                     63:                response_header_overwrite(srv, con, CONST_STR_LEN("Transfer-Encoding"), CONST_STR_LEN("chunked"));
                     64:        }
                     65: 
                     66: 
                     67:        /* add all headers */
                     68:        for (i = 0; i < con->response.headers->used; i++) {
                     69:                data_string *ds;
                     70: 
                     71:                ds = (data_string *)con->response.headers->data[i];
                     72: 
                     73:                if (ds->value->used && ds->key->used &&
                     74:                    0 != strncasecmp(ds->key->ptr, CONST_STR_LEN("X-LIGHTTPD-")) &&
                     75:                        0 != strncasecmp(ds->key->ptr, CONST_STR_LEN("X-Sendfile"))) {
                     76:                        if (0 == strcasecmp(ds->key->ptr, "Date")) have_date = 1;
                     77:                        if (0 == strcasecmp(ds->key->ptr, "Server")) have_server = 1;
                     78:                        if (0 == strcasecmp(ds->key->ptr, "Content-Encoding") && 304 == con->http_status) continue;
                     79: 
                     80:                        buffer_append_string_len(b, CONST_STR_LEN("\r\n"));
                     81:                        buffer_append_string_buffer(b, ds->key);
                     82:                        buffer_append_string_len(b, CONST_STR_LEN(": "));
                     83: #if 0
                     84:                        /** 
                     85:                         * the value might contain newlines, encode them with at least one white-space
                     86:                         */
                     87:                        buffer_append_string_encoded(b, CONST_BUF_LEN(ds->value), ENCODING_HTTP_HEADER);
                     88: #else
                     89:                        buffer_append_string_buffer(b, ds->value);
                     90: #endif
                     91:                }
                     92:        }
                     93: 
                     94:        if (!have_date) {
                     95:                /* HTTP/1.1 requires a Date: header */
                     96:                buffer_append_string_len(b, CONST_STR_LEN("\r\nDate: "));
                     97: 
                     98:                /* cache the generated timestamp */
                     99:                if (srv->cur_ts != srv->last_generated_date_ts) {
                    100:                        buffer_prepare_copy(srv->ts_date_str, 255);
                    101: 
                    102:                        strftime(srv->ts_date_str->ptr, srv->ts_date_str->size - 1,
                    103:                                 "%a, %d %b %Y %H:%M:%S GMT", gmtime(&(srv->cur_ts)));
                    104: 
                    105:                        srv->ts_date_str->used = strlen(srv->ts_date_str->ptr) + 1;
                    106: 
                    107:                        srv->last_generated_date_ts = srv->cur_ts;
                    108:                }
                    109: 
                    110:                buffer_append_string_buffer(b, srv->ts_date_str);
                    111:        }
                    112: 
                    113:        if (!have_server) {
                    114:                if (buffer_is_empty(con->conf.server_tag)) {
                    115:                        buffer_append_string_len(b, CONST_STR_LEN("\r\nServer: " PACKAGE_DESC));
                    116:                } else if (con->conf.server_tag->used > 1) {
                    117:                        buffer_append_string_len(b, CONST_STR_LEN("\r\nServer: "));
                    118:                        buffer_append_string_encoded(b, CONST_BUF_LEN(con->conf.server_tag), ENCODING_HTTP_HEADER);
                    119:                }
                    120:        }
                    121: 
                    122:        buffer_append_string_len(b, CONST_STR_LEN("\r\n\r\n"));
                    123: 
                    124: 
                    125:        con->bytes_header = b->used - 1;
                    126: 
                    127:        if (con->conf.log_response_header) {
                    128:                log_error_write(srv, __FILE__, __LINE__, "sSb", "Response-Header:", "\n", b);
                    129:        }
                    130: 
                    131:        return 0;
                    132: }
                    133: 
                    134: #ifdef USE_OPENSSL
                    135: static void https_add_ssl_entries(connection *con) {
                    136:        X509 *xs;
                    137:        X509_NAME *xn;
                    138:        X509_NAME_ENTRY *xe;
                    139:        int i, nentries;
                    140: 
                    141:        if (
                    142:                SSL_get_verify_result(con->ssl) != X509_V_OK
                    143:                || !(xs = SSL_get_peer_certificate(con->ssl))
                    144:        ) {
                    145:                return;
                    146:        }
                    147: 
                    148:        xn = X509_get_subject_name(xs);
                    149:        for (i = 0, nentries = X509_NAME_entry_count(xn); i < nentries; ++i) {
                    150:                int xobjnid;
                    151:                const char * xobjsn;
                    152:                data_string *envds;
                    153: 
                    154:                if (!(xe = X509_NAME_get_entry(xn, i))) {
                    155:                        continue;
                    156:                }
                    157:                xobjnid = OBJ_obj2nid((ASN1_OBJECT*)X509_NAME_ENTRY_get_object(xe));
                    158:                xobjsn = OBJ_nid2sn(xobjnid);
                    159:                if (!xobjsn) {
                    160:                        continue;
                    161:                }
                    162: 
                    163:                if (NULL == (envds = (data_string *)array_get_unused_element(con->environment, TYPE_STRING))) {
                    164:                        envds = data_string_init();
                    165:                }
                    166:                buffer_copy_string_len(envds->key, CONST_STR_LEN("SSL_CLIENT_S_DN_"));
                    167:                buffer_append_string(envds->key, xobjsn);
                    168:                buffer_copy_string_len(
                    169:                        envds->value,
                    170:                        (const char *)xe->value->data, xe->value->length
                    171:                );
                    172:                /* pick one of the exported values as "REMOTE_USER", for example
                    173:                 * ssl.verifyclient.username   = "SSL_CLIENT_S_DN_UID" or "SSL_CLIENT_S_DN_emailAddress"
                    174:                 */
                    175:                if (buffer_is_equal(con->conf.ssl_verifyclient_username, envds->key)) {
                    176:                        data_string *ds;
                    177:                        if (NULL == (ds = (data_string *)array_get_element(con->environment, "REMOTE_USER"))) {
                    178:                                if (NULL == (ds = (data_string *)array_get_unused_element(con->environment, TYPE_STRING))) {
                    179:                                        ds = data_string_init();
                    180:                                }
                    181:                                buffer_copy_string(ds->key, "REMOTE_USER");
                    182:                                array_insert_unique(con->environment, (data_unset *)ds);
                    183:                        }
                    184:                        buffer_copy_string_buffer(ds->value, envds->value);
                    185:                }
                    186:                array_insert_unique(con->environment, (data_unset *)envds);
                    187:        }
                    188:        if (con->conf.ssl_verifyclient_export_cert) {
                    189:                BIO *bio;
                    190:                if (NULL != (bio = BIO_new(BIO_s_mem()))) {
                    191:                        data_string *envds;
                    192:                        int n;
                    193: 
                    194:                        PEM_write_bio_X509(bio, xs);
                    195:                        n = BIO_pending(bio);
                    196: 
                    197:                        if (NULL == (envds = (data_string *)array_get_unused_element(con->environment, TYPE_STRING))) {
                    198:                                envds = data_string_init();
                    199:                        }
                    200: 
                    201:                        buffer_copy_string_len(envds->key, CONST_STR_LEN("SSL_CLIENT_CERT"));
                    202:                        buffer_prepare_copy(envds->value, n+1);
                    203:                        BIO_read(bio, envds->value->ptr, n);
                    204:                        BIO_free(bio);
                    205:                        envds->value->ptr[n] = '\0';
                    206:                        envds->value->used = n+1;
                    207:                        array_insert_unique(con->environment, (data_unset *)envds);
                    208:                }
                    209:        }
                    210:        X509_free(xs);
                    211: }
                    212: #endif
                    213: 
                    214: 
                    215: handler_t http_response_prepare(server *srv, connection *con) {
                    216:        handler_t r;
                    217: 
                    218:        /* looks like someone has already done a decision */
                    219:        if (con->mode == DIRECT &&
                    220:            (con->http_status != 0 && con->http_status != 200)) {
                    221:                /* remove a packets in the queue */
                    222:                if (con->file_finished == 0) {
                    223:                        chunkqueue_reset(con->write_queue);
                    224:                }
                    225: 
                    226:                return HANDLER_FINISHED;
                    227:        }
                    228: 
                    229:        /* no decision yet, build conf->filename */
                    230:        if (con->mode == DIRECT && con->physical.path->used == 0) {
                    231:                char *qstr;
                    232: 
                    233:                /* we only come here when we have the parse the full request again
                    234:                 *
                    235:                 * a HANDLER_COMEBACK from mod_rewrite and mod_fastcgi might be a
                    236:                 * problem here as mod_setenv might get called multiple times
                    237:                 *
                    238:                 * fastcgi-auth might lead to a COMEBACK too
                    239:                 * fastcgi again dead server too
                    240:                 *
                    241:                 * mod_compress might add headers twice too
                    242:                 *
                    243:                 *  */
                    244: 
                    245:                config_cond_cache_reset(srv, con);
                    246:                config_setup_connection(srv, con); /* Perhaps this could be removed at other places. */
                    247: 
                    248:                if (con->conf.log_condition_handling) {
                    249:                        log_error_write(srv, __FILE__, __LINE__,  "s",  "run condition");
                    250:                }
                    251:                config_patch_connection(srv, con, COMP_SERVER_SOCKET); /* SERVERsocket */
                    252: 
                    253:                /**
                    254:                 * prepare strings
                    255:                 *
                    256:                 * - uri.path_raw
                    257:                 * - uri.path (secure)
                    258:                 * - uri.query
                    259:                 *
                    260:                 */
                    261: 
                    262:                /**
                    263:                 * Name according to RFC 2396
                    264:                 *
                    265:                 * - scheme
                    266:                 * - authority
                    267:                 * - path
                    268:                 * - query
                    269:                 *
                    270:                 * (scheme)://(authority)(path)?(query)#fragment
                    271:                 *
                    272:                 *
                    273:                 */
                    274: 
                    275:                /* initial scheme value. can be overwritten for example by mod_extforward later */
                    276:                if (con->srv_socket->is_ssl) {
                    277:                        buffer_copy_string_len(con->uri.scheme, CONST_STR_LEN("https"));
                    278:                } else {
                    279:                        buffer_copy_string_len(con->uri.scheme, CONST_STR_LEN("http"));
                    280:                }
                    281:                buffer_copy_string_buffer(con->uri.authority, con->request.http_host);
                    282:                buffer_to_lower(con->uri.authority);
                    283: 
                    284:                config_patch_connection(srv, con, COMP_HTTP_SCHEME);    /* Scheme:      */
                    285:                config_patch_connection(srv, con, COMP_HTTP_HOST);      /* Host:        */
                    286:                config_patch_connection(srv, con, COMP_HTTP_REMOTE_IP); /* Client-IP */
                    287:                config_patch_connection(srv, con, COMP_HTTP_REFERER);   /* Referer:     */
                    288:                config_patch_connection(srv, con, COMP_HTTP_USER_AGENT);/* User-Agent:  */
                    289:                config_patch_connection(srv, con, COMP_HTTP_LANGUAGE);  /* Accept-Language:  */
                    290:                config_patch_connection(srv, con, COMP_HTTP_COOKIE);    /* Cookie:  */
                    291:                config_patch_connection(srv, con, COMP_HTTP_REQUEST_METHOD); /* REQUEST_METHOD */
                    292: 
                    293:                /** their might be a fragment which has to be cut away */
                    294:                if (NULL != (qstr = strchr(con->request.uri->ptr, '#'))) {
                    295:                        con->request.uri->used = qstr - con->request.uri->ptr;
                    296:                        con->request.uri->ptr[con->request.uri->used++] = '\0';
                    297:                }
                    298: 
                    299:                /** extract query string from request.uri */
                    300:                if (NULL != (qstr = strchr(con->request.uri->ptr, '?'))) {
                    301:                        buffer_copy_string    (con->uri.query, qstr + 1);
                    302:                        buffer_copy_string_len(con->uri.path_raw, con->request.uri->ptr, qstr - con->request.uri->ptr);
                    303:                } else {
                    304:                        buffer_reset     (con->uri.query);
                    305:                        buffer_copy_string_buffer(con->uri.path_raw, con->request.uri);
                    306:                }
                    307: 
1.1.1.2 ! misho     308:                /* decode url to path
        !           309:                 *
        !           310:                 * - decode url-encodings  (e.g. %20 -> ' ')
        !           311:                 * - remove path-modifiers (e.g. /../)
        !           312:                 */
        !           313: 
        !           314:                if (con->request.http_method == HTTP_METHOD_OPTIONS &&
        !           315:                    con->uri.path_raw->ptr[0] == '*' && con->uri.path_raw->ptr[1] == '\0') {
        !           316:                        /* OPTIONS * ... */
        !           317:                        buffer_copy_string_buffer(con->uri.path, con->uri.path_raw);
        !           318:                } else {
        !           319:                        buffer_copy_string_buffer(srv->tmp_buf, con->uri.path_raw);
        !           320:                        buffer_urldecode_path(srv->tmp_buf);
        !           321:                        buffer_path_simplify(con->uri.path, srv->tmp_buf);
        !           322:                }
        !           323: 
        !           324:                config_patch_connection(srv, con, COMP_HTTP_URL); /* HTTPurl */
        !           325:                config_patch_connection(srv, con, COMP_HTTP_QUERY_STRING); /* HTTPqs */
        !           326: 
        !           327: #ifdef USE_OPENSSL
        !           328:                if (con->srv_socket->is_ssl && con->conf.ssl_verifyclient) {
        !           329:                        https_add_ssl_entries(con);
        !           330:                }
        !           331: #endif
        !           332: 
        !           333:                /* do we have to downgrade to 1.0 ? */
        !           334:                if (!con->conf.allow_http11) {
        !           335:                        con->request.http_version = HTTP_VERSION_1_0;
        !           336:                }
        !           337: 
1.1       misho     338:                if (con->conf.log_request_handling) {
                    339:                        log_error_write(srv, __FILE__, __LINE__,  "s",  "-- splitting Request-URI");
1.1.1.2 ! misho     340:                        log_error_write(srv, __FILE__, __LINE__,  "sb", "Request-URI     : ", con->request.uri);
        !           341:                        log_error_write(srv, __FILE__, __LINE__,  "sb", "URI-scheme      : ", con->uri.scheme);
        !           342:                        log_error_write(srv, __FILE__, __LINE__,  "sb", "URI-authority   : ", con->uri.authority);
        !           343:                        log_error_write(srv, __FILE__, __LINE__,  "sb", "URI-path (raw)  : ", con->uri.path_raw);
        !           344:                        log_error_write(srv, __FILE__, __LINE__,  "sb", "URI-path (clean): ", con->uri.path);
        !           345:                        log_error_write(srv, __FILE__, __LINE__,  "sb", "URI-query       : ", con->uri.query);
1.1       misho     346:                }
                    347: 
                    348: 
                    349:                /**
                    350:                 *
                    351:                 * call plugins
                    352:                 *
                    353:                 * - based on the raw URL
                    354:                 *
                    355:                 */
                    356: 
                    357:                switch(r = plugins_call_handle_uri_raw(srv, con)) {
                    358:                case HANDLER_GO_ON:
                    359:                        break;
                    360:                case HANDLER_FINISHED:
                    361:                case HANDLER_COMEBACK:
                    362:                case HANDLER_WAIT_FOR_EVENT:
                    363:                case HANDLER_ERROR:
                    364:                        return r;
                    365:                default:
                    366:                        log_error_write(srv, __FILE__, __LINE__, "sd", "handle_uri_raw: unknown return value", r);
                    367:                        break;
                    368:                }
                    369: 
                    370:                /**
                    371:                 *
                    372:                 * call plugins
                    373:                 *
                    374:                 * - based on the clean URL
                    375:                 *
                    376:                 */
                    377: 
                    378:                switch(r = plugins_call_handle_uri_clean(srv, con)) {
                    379:                case HANDLER_GO_ON:
                    380:                        break;
                    381:                case HANDLER_FINISHED:
                    382:                case HANDLER_COMEBACK:
                    383:                case HANDLER_WAIT_FOR_EVENT:
                    384:                case HANDLER_ERROR:
                    385:                        return r;
                    386:                default:
                    387:                        log_error_write(srv, __FILE__, __LINE__, "");
                    388:                        break;
                    389:                }
                    390: 
                    391:                if (con->request.http_method == HTTP_METHOD_OPTIONS &&
                    392:                    con->uri.path->ptr[0] == '*' && con->uri.path_raw->ptr[1] == '\0') {
                    393:                        /* option requests are handled directly without checking of the path */
                    394: 
                    395:                        response_header_insert(srv, con, CONST_STR_LEN("Allow"), CONST_STR_LEN("OPTIONS, GET, HEAD, POST"));
                    396: 
                    397:                        con->http_status = 200;
                    398:                        con->file_finished = 1;
                    399: 
                    400:                        return HANDLER_FINISHED;
                    401:                }
                    402: 
                    403:                /***
                    404:                 *
                    405:                 * border
                    406:                 *
                    407:                 * logical filename (URI) becomes a physical filename here
                    408:                 *
                    409:                 *
                    410:                 *
                    411:                 */
                    412: 
                    413: 
                    414: 
                    415: 
                    416:                /* 1. stat()
                    417:                 * ... ISREG() -> ok, go on
                    418:                 * ... ISDIR() -> index-file -> redirect
                    419:                 *
                    420:                 * 2. pathinfo()
                    421:                 * ... ISREG()
                    422:                 *
                    423:                 * 3. -> 404
                    424:                 *
                    425:                 */
                    426: 
                    427:                /*
                    428:                 * SEARCH DOCUMENT ROOT
                    429:                 */
                    430: 
                    431:                /* set a default */
                    432: 
                    433:                buffer_copy_string_buffer(con->physical.doc_root, con->conf.document_root);
                    434:                buffer_copy_string_buffer(con->physical.rel_path, con->uri.path);
                    435: 
                    436: #if defined(__WIN32) || defined(__CYGWIN__)
                    437:                /* strip dots from the end and spaces
                    438:                 *
                    439:                 * windows/dos handle those filenames as the same file
                    440:                 *
                    441:                 * foo == foo. == foo..... == "foo...   " == "foo..  ./"
                    442:                 *
                    443:                 * This will affect in some cases PATHINFO
                    444:                 *
                    445:                 * on native windows we could prepend the filename with \\?\ to circumvent
                    446:                 * this behaviour. I have no idea how to push this through cygwin
                    447:                 *
                    448:                 * */
                    449: 
                    450:                if (con->physical.rel_path->used > 1) {
                    451:                        buffer *b = con->physical.rel_path;
                    452:                        size_t i;
                    453: 
                    454:                        if (b->used > 2 &&
                    455:                            b->ptr[b->used-2] == '/' &&
                    456:                            (b->ptr[b->used-3] == ' ' ||
                    457:                             b->ptr[b->used-3] == '.')) {
                    458:                                b->ptr[b->used--] = '\0';
                    459:                        }
                    460: 
                    461:                        for (i = b->used - 2; b->used > 1; i--) {
                    462:                                if (b->ptr[i] == ' ' ||
                    463:                                    b->ptr[i] == '.') {
                    464:                                        b->ptr[b->used--] = '\0';
                    465:                                } else {
                    466:                                        break;
                    467:                                }
                    468:                        }
                    469:                }
                    470: #endif
                    471: 
                    472:                if (con->conf.log_request_handling) {
                    473:                        log_error_write(srv, __FILE__, __LINE__,  "s",  "-- before doc_root");
                    474:                        log_error_write(srv, __FILE__, __LINE__,  "sb", "Doc-Root     :", con->physical.doc_root);
                    475:                        log_error_write(srv, __FILE__, __LINE__,  "sb", "Rel-Path     :", con->physical.rel_path);
                    476:                        log_error_write(srv, __FILE__, __LINE__,  "sb", "Path         :", con->physical.path);
                    477:                }
                    478:                /* the docroot plugin should set the doc_root and might also set the physical.path
                    479:                 * for us (all vhost-plugins are supposed to set the doc_root)
                    480:                 * */
                    481:                switch(r = plugins_call_handle_docroot(srv, con)) {
                    482:                case HANDLER_GO_ON:
                    483:                        break;
                    484:                case HANDLER_FINISHED:
                    485:                case HANDLER_COMEBACK:
                    486:                case HANDLER_WAIT_FOR_EVENT:
                    487:                case HANDLER_ERROR:
                    488:                        return r;
                    489:                default:
                    490:                        log_error_write(srv, __FILE__, __LINE__, "");
                    491:                        break;
                    492:                }
                    493: 
                    494:                /* MacOS X and Windows can't distiguish between upper and lower-case
                    495:                 *
                    496:                 * convert to lower-case
                    497:                 */
                    498:                if (con->conf.force_lowercase_filenames) {
                    499:                        buffer_to_lower(con->physical.rel_path);
                    500:                }
                    501: 
                    502:                /* the docroot plugins might set the servername, if they don't we take http-host */
                    503:                if (buffer_is_empty(con->server_name)) {
                    504:                        buffer_copy_string_buffer(con->server_name, con->uri.authority);
                    505:                }
                    506: 
                    507:                /**
                    508:                 * create physical filename
                    509:                 * -> physical.path = docroot + rel_path
                    510:                 *
                    511:                 */
                    512: 
1.1.1.2 ! misho     513:                buffer_copy_string_buffer(con->physical.basedir, con->physical.doc_root);
1.1       misho     514:                buffer_copy_string_buffer(con->physical.path, con->physical.doc_root);
                    515:                BUFFER_APPEND_SLASH(con->physical.path);
                    516:                if (con->physical.rel_path->used &&
                    517:                    con->physical.rel_path->ptr[0] == '/') {
                    518:                        buffer_append_string_len(con->physical.path, con->physical.rel_path->ptr + 1, con->physical.rel_path->used - 2);
                    519:                } else {
                    520:                        buffer_append_string_buffer(con->physical.path, con->physical.rel_path);
                    521:                }
                    522: 
                    523:                if (con->conf.log_request_handling) {
                    524:                        log_error_write(srv, __FILE__, __LINE__,  "s",  "-- after doc_root");
                    525:                        log_error_write(srv, __FILE__, __LINE__,  "sb", "Doc-Root     :", con->physical.doc_root);
                    526:                        log_error_write(srv, __FILE__, __LINE__,  "sb", "Rel-Path     :", con->physical.rel_path);
                    527:                        log_error_write(srv, __FILE__, __LINE__,  "sb", "Path         :", con->physical.path);
                    528:                }
                    529: 
                    530:                switch(r = plugins_call_handle_physical(srv, con)) {
                    531:                case HANDLER_GO_ON:
                    532:                        break;
                    533:                case HANDLER_FINISHED:
                    534:                case HANDLER_COMEBACK:
                    535:                case HANDLER_WAIT_FOR_EVENT:
                    536:                case HANDLER_ERROR:
                    537:                        return r;
                    538:                default:
                    539:                        log_error_write(srv, __FILE__, __LINE__, "");
                    540:                        break;
                    541:                }
                    542: 
                    543:                if (con->conf.log_request_handling) {
                    544:                        log_error_write(srv, __FILE__, __LINE__,  "s",  "-- logical -> physical");
                    545:                        log_error_write(srv, __FILE__, __LINE__,  "sb", "Doc-Root     :", con->physical.doc_root);
1.1.1.2 ! misho     546:                        log_error_write(srv, __FILE__, __LINE__,  "sb", "Basedir      :", con->physical.basedir);
1.1       misho     547:                        log_error_write(srv, __FILE__, __LINE__,  "sb", "Rel-Path     :", con->physical.rel_path);
                    548:                        log_error_write(srv, __FILE__, __LINE__,  "sb", "Path         :", con->physical.path);
                    549:                }
                    550:        }
                    551: 
                    552:        /*
                    553:         * Noone catched away the file from normal path of execution yet (like mod_access)
                    554:         *
                    555:         * Go on and check of the file exists at all
                    556:         */
                    557: 
                    558:        if (con->mode == DIRECT) {
                    559:                char *slash = NULL;
                    560:                char *pathinfo = NULL;
                    561:                int found = 0;
                    562:                stat_cache_entry *sce = NULL;
                    563: 
                    564:                if (con->conf.log_request_handling) {
                    565:                        log_error_write(srv, __FILE__, __LINE__,  "s",  "-- handling physical path");
                    566:                        log_error_write(srv, __FILE__, __LINE__,  "sb", "Path         :", con->physical.path);
                    567:                }
                    568: 
                    569:                if (HANDLER_ERROR != stat_cache_get_entry(srv, con, con->physical.path, &sce)) {
                    570:                        /* file exists */
                    571: 
                    572:                        if (con->conf.log_request_handling) {
                    573:                                log_error_write(srv, __FILE__, __LINE__,  "s",  "-- file found");
                    574:                                log_error_write(srv, __FILE__, __LINE__,  "sb", "Path         :", con->physical.path);
                    575:                        }
                    576: #ifdef HAVE_LSTAT
                    577:                        if ((sce->is_symlink != 0) && !con->conf.follow_symlink) {
                    578:                                con->http_status = 403;
                    579: 
                    580:                                if (con->conf.log_request_handling) {
                    581:                                        log_error_write(srv, __FILE__, __LINE__,  "s",  "-- access denied due symlink restriction");
                    582:                                        log_error_write(srv, __FILE__, __LINE__,  "sb", "Path         :", con->physical.path);
                    583:                                }
                    584: 
                    585:                                buffer_reset(con->physical.path);
                    586:                                return HANDLER_FINISHED;
                    587:                        };
                    588: #endif
                    589:                        if (S_ISDIR(sce->st.st_mode)) {
                    590:                                if (con->uri.path->ptr[con->uri.path->used - 2] != '/') {
                    591:                                        /* redirect to .../ */
                    592: 
                    593:                                        http_response_redirect_to_directory(srv, con);
                    594: 
                    595:                                        return HANDLER_FINISHED;
                    596:                                }
                    597: #ifdef HAVE_LSTAT
                    598:                        } else if (!S_ISREG(sce->st.st_mode) && !sce->is_symlink) {
                    599: #else
                    600:                        } else if (!S_ISREG(sce->st.st_mode)) {
                    601: #endif
                    602:                                /* any special handling of non-reg files ?*/
                    603: 
                    604: 
                    605:                        }
                    606:                } else {
                    607:                        switch (errno) {
                    608:                        case EACCES:
                    609:                                con->http_status = 403;
                    610: 
                    611:                                if (con->conf.log_request_handling) {
                    612:                                        log_error_write(srv, __FILE__, __LINE__,  "s",  "-- access denied");
                    613:                                        log_error_write(srv, __FILE__, __LINE__,  "sb", "Path         :", con->physical.path);
                    614:                                }
                    615: 
                    616:                                buffer_reset(con->physical.path);
                    617:                                return HANDLER_FINISHED;
                    618:                        case ENAMETOOLONG:
                    619:                                /* file name to be read was too long. return 404 */
                    620:                        case ENOENT:
                    621:                                con->http_status = 404;
                    622: 
                    623:                                if (con->conf.log_request_handling) {
                    624:                                        log_error_write(srv, __FILE__, __LINE__,  "s",  "-- file not found");
                    625:                                        log_error_write(srv, __FILE__, __LINE__,  "sb", "Path         :", con->physical.path);
                    626:                                }
                    627: 
                    628:                                buffer_reset(con->physical.path);
                    629:                                return HANDLER_FINISHED;
                    630:                        case ENOTDIR:
                    631:                                /* PATH_INFO ! :) */
                    632:                                break;
                    633:                        default:
                    634:                                /* we have no idea what happend. let's tell the user so. */
                    635:                                con->http_status = 500;
                    636:                                buffer_reset(con->physical.path);
                    637: 
                    638:                                log_error_write(srv, __FILE__, __LINE__, "ssbsb",
                    639:                                                "file not found ... or so: ", strerror(errno),
                    640:                                                con->uri.path,
                    641:                                                "->", con->physical.path);
                    642: 
                    643:                                return HANDLER_FINISHED;
                    644:                        }
                    645: 
                    646:                        /* not found, perhaps PATHINFO */
                    647: 
                    648:                        buffer_copy_string_buffer(srv->tmp_buf, con->physical.path);
                    649: 
                    650:                        do {
                    651:                                if (slash) {
                    652:                                        buffer_copy_string_len(con->physical.path, srv->tmp_buf->ptr, slash - srv->tmp_buf->ptr);
                    653:                                } else {
                    654:                                        buffer_copy_string_buffer(con->physical.path, srv->tmp_buf);
                    655:                                }
                    656: 
                    657:                                if (HANDLER_ERROR != stat_cache_get_entry(srv, con, con->physical.path, &sce)) {
                    658:                                        found = S_ISREG(sce->st.st_mode);
                    659:                                        break;
                    660:                                }
                    661: 
                    662:                                if (pathinfo != NULL) {
                    663:                                        *pathinfo = '\0';
                    664:                                }
                    665:                                slash = strrchr(srv->tmp_buf->ptr, '/');
                    666: 
                    667:                                if (pathinfo != NULL) {
                    668:                                        /* restore '/' */
                    669:                                        *pathinfo = '/';
                    670:                                }
                    671: 
                    672:                                if (slash) pathinfo = slash;
                    673:                        } while ((found == 0) && (slash != NULL) && ((size_t)(slash - srv->tmp_buf->ptr) > (con->physical.basedir->used - 2)));
                    674: 
                    675:                        if (found == 0) {
                    676:                                /* no it really doesn't exists */
                    677:                                con->http_status = 404;
                    678: 
                    679:                                if (con->conf.log_file_not_found) {
                    680:                                        log_error_write(srv, __FILE__, __LINE__, "sbsb",
                    681:                                                        "file not found:", con->uri.path,
                    682:                                                        "->", con->physical.path);
                    683:                                }
                    684: 
                    685:                                buffer_reset(con->physical.path);
                    686: 
                    687:                                return HANDLER_FINISHED;
                    688:                        }
                    689: 
                    690: #ifdef HAVE_LSTAT
                    691:                        if ((sce->is_symlink != 0) && !con->conf.follow_symlink) {
                    692:                                con->http_status = 403;
                    693: 
                    694:                                if (con->conf.log_request_handling) {
                    695:                                        log_error_write(srv, __FILE__, __LINE__,  "s",  "-- access denied due symlink restriction");
                    696:                                        log_error_write(srv, __FILE__, __LINE__,  "sb", "Path         :", con->physical.path);
                    697:                                }
                    698: 
                    699:                                buffer_reset(con->physical.path);
                    700:                                return HANDLER_FINISHED;
                    701:                        };
                    702: #endif
                    703: 
                    704:                        /* we have a PATHINFO */
                    705:                        if (pathinfo) {
                    706:                                buffer_copy_string(con->request.pathinfo, pathinfo);
                    707: 
                    708:                                /*
                    709:                                 * shorten uri.path
                    710:                                 */
                    711: 
                    712:                                con->uri.path->used -= strlen(pathinfo);
                    713:                                con->uri.path->ptr[con->uri.path->used - 1] = '\0';
                    714:                        }
                    715: 
                    716:                        if (con->conf.log_request_handling) {
                    717:                                log_error_write(srv, __FILE__, __LINE__,  "s",  "-- after pathinfo check");
                    718:                                log_error_write(srv, __FILE__, __LINE__,  "sb", "Path         :", con->physical.path);
                    719:                                log_error_write(srv, __FILE__, __LINE__,  "sb", "URI          :", con->uri.path);
                    720:                                log_error_write(srv, __FILE__, __LINE__,  "sb", "Pathinfo     :", con->request.pathinfo);
                    721:                        }
                    722:                }
                    723: 
                    724:                if (con->conf.log_request_handling) {
                    725:                        log_error_write(srv, __FILE__, __LINE__,  "s",  "-- handling subrequest");
                    726:                        log_error_write(srv, __FILE__, __LINE__,  "sb", "Path         :", con->physical.path);
                    727:                }
                    728: 
                    729:                /* call the handlers */
                    730:                switch(r = plugins_call_handle_subrequest_start(srv, con)) {
                    731:                case HANDLER_GO_ON:
                    732:                        /* request was not handled */
                    733:                        break;
                    734:                case HANDLER_FINISHED:
                    735:                default:
                    736:                        if (con->conf.log_request_handling) {
                    737:                                log_error_write(srv, __FILE__, __LINE__,  "s",  "-- subrequest finished");
                    738:                        }
                    739: 
                    740:                        /* something strange happend */
                    741:                        return r;
                    742:                }
                    743: 
                    744:                /* if we are still here, no one wanted the file, status 403 is ok I think */
                    745: 
                    746:                if (con->mode == DIRECT && con->http_status == 0) {
                    747:                        switch (con->request.http_method) {
                    748:                        case HTTP_METHOD_OPTIONS:
                    749:                                con->http_status = 200;
                    750:                                break;
                    751:                        default:
                    752:                                con->http_status = 403;
                    753:                        }
                    754: 
                    755:                        return HANDLER_FINISHED;
                    756:                }
                    757: 
                    758:        }
                    759: 
                    760:        switch(r = plugins_call_handle_subrequest(srv, con)) {
                    761:        case HANDLER_GO_ON:
                    762:                /* request was not handled, looks like we are done */
                    763:                return HANDLER_FINISHED;
                    764:        case HANDLER_FINISHED:
                    765:                /* request is finished */
                    766:        default:
                    767:                /* something strange happend */
                    768:                return r;
                    769:        }
                    770: 
                    771:        /* can't happen */
                    772:        return HANDLER_COMEBACK;
                    773: }
                    774: 
                    775: 
                    776: 

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