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

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: 
                    308:                if (con->conf.log_request_handling) {
                    309:                        log_error_write(srv, __FILE__, __LINE__,  "s",  "-- splitting Request-URI");
                    310:                        log_error_write(srv, __FILE__, __LINE__,  "sb", "Request-URI  : ", con->request.uri);
                    311:                        log_error_write(srv, __FILE__, __LINE__,  "sb", "URI-scheme   : ", con->uri.scheme);
                    312:                        log_error_write(srv, __FILE__, __LINE__,  "sb", "URI-authority: ", con->uri.authority);
                    313:                        log_error_write(srv, __FILE__, __LINE__,  "sb", "URI-path     : ", con->uri.path_raw);
                    314:                        log_error_write(srv, __FILE__, __LINE__,  "sb", "URI-query    : ", con->uri.query);
                    315:                }
                    316: 
                    317: 
                    318:                /**
                    319:                 *
                    320:                 * call plugins
                    321:                 *
                    322:                 * - based on the raw URL
                    323:                 *
                    324:                 */
                    325: 
                    326:                switch(r = plugins_call_handle_uri_raw(srv, con)) {
                    327:                case HANDLER_GO_ON:
                    328:                        break;
                    329:                case HANDLER_FINISHED:
                    330:                case HANDLER_COMEBACK:
                    331:                case HANDLER_WAIT_FOR_EVENT:
                    332:                case HANDLER_ERROR:
                    333:                        return r;
                    334:                default:
                    335:                        log_error_write(srv, __FILE__, __LINE__, "sd", "handle_uri_raw: unknown return value", r);
                    336:                        break;
                    337:                }
                    338: 
                    339:                /* build filename
                    340:                 *
                    341:                 * - decode url-encodings  (e.g. %20 -> ' ')
                    342:                 * - remove path-modifiers (e.g. /../)
                    343:                 */
                    344: 
                    345: 
                    346: 
                    347:                if (con->request.http_method == HTTP_METHOD_OPTIONS &&
                    348:                    con->uri.path_raw->ptr[0] == '*' && con->uri.path_raw->ptr[1] == '\0') {
                    349:                        /* OPTIONS * ... */
                    350:                        buffer_copy_string_buffer(con->uri.path, con->uri.path_raw);
                    351:                } else {
                    352:                        buffer_copy_string_buffer(srv->tmp_buf, con->uri.path_raw);
                    353:                        buffer_urldecode_path(srv->tmp_buf);
                    354:                        buffer_path_simplify(con->uri.path, srv->tmp_buf);
                    355:                }
                    356: 
                    357:                if (con->conf.log_request_handling) {
                    358:                        log_error_write(srv, __FILE__, __LINE__,  "s",  "-- sanatising URI");
                    359:                        log_error_write(srv, __FILE__, __LINE__,  "sb", "URI-path     : ", con->uri.path);
                    360:                }
                    361: 
                    362: #ifdef USE_OPENSSL
                    363:                if (con->srv_socket->is_ssl && con->conf.ssl_verifyclient) {
                    364:                        https_add_ssl_entries(con);
                    365:                }
                    366: #endif
                    367: 
                    368:                /**
                    369:                 *
                    370:                 * call plugins
                    371:                 *
                    372:                 * - based on the clean URL
                    373:                 *
                    374:                 */
                    375: 
                    376:                config_patch_connection(srv, con, COMP_HTTP_URL); /* HTTPurl */
                    377:                config_patch_connection(srv, con, COMP_HTTP_QUERY_STRING); /* HTTPqs */
                    378: 
                    379:                /* do we have to downgrade to 1.0 ? */
                    380:                if (!con->conf.allow_http11) {
                    381:                        con->request.http_version = HTTP_VERSION_1_0;
                    382:                }
                    383: 
                    384:                switch(r = plugins_call_handle_uri_clean(srv, con)) {
                    385:                case HANDLER_GO_ON:
                    386:                        break;
                    387:                case HANDLER_FINISHED:
                    388:                case HANDLER_COMEBACK:
                    389:                case HANDLER_WAIT_FOR_EVENT:
                    390:                case HANDLER_ERROR:
                    391:                        return r;
                    392:                default:
                    393:                        log_error_write(srv, __FILE__, __LINE__, "");
                    394:                        break;
                    395:                }
                    396: 
                    397:                if (con->request.http_method == HTTP_METHOD_OPTIONS &&
                    398:                    con->uri.path->ptr[0] == '*' && con->uri.path_raw->ptr[1] == '\0') {
                    399:                        /* option requests are handled directly without checking of the path */
                    400: 
                    401:                        response_header_insert(srv, con, CONST_STR_LEN("Allow"), CONST_STR_LEN("OPTIONS, GET, HEAD, POST"));
                    402: 
                    403:                        con->http_status = 200;
                    404:                        con->file_finished = 1;
                    405: 
                    406:                        return HANDLER_FINISHED;
                    407:                }
                    408: 
                    409:                /***
                    410:                 *
                    411:                 * border
                    412:                 *
                    413:                 * logical filename (URI) becomes a physical filename here
                    414:                 *
                    415:                 *
                    416:                 *
                    417:                 */
                    418: 
                    419: 
                    420: 
                    421: 
                    422:                /* 1. stat()
                    423:                 * ... ISREG() -> ok, go on
                    424:                 * ... ISDIR() -> index-file -> redirect
                    425:                 *
                    426:                 * 2. pathinfo()
                    427:                 * ... ISREG()
                    428:                 *
                    429:                 * 3. -> 404
                    430:                 *
                    431:                 */
                    432: 
                    433:                /*
                    434:                 * SEARCH DOCUMENT ROOT
                    435:                 */
                    436: 
                    437:                /* set a default */
                    438: 
                    439:                buffer_copy_string_buffer(con->physical.doc_root, con->conf.document_root);
                    440:                buffer_copy_string_buffer(con->physical.rel_path, con->uri.path);
                    441: 
                    442: #if defined(__WIN32) || defined(__CYGWIN__)
                    443:                /* strip dots from the end and spaces
                    444:                 *
                    445:                 * windows/dos handle those filenames as the same file
                    446:                 *
                    447:                 * foo == foo. == foo..... == "foo...   " == "foo..  ./"
                    448:                 *
                    449:                 * This will affect in some cases PATHINFO
                    450:                 *
                    451:                 * on native windows we could prepend the filename with \\?\ to circumvent
                    452:                 * this behaviour. I have no idea how to push this through cygwin
                    453:                 *
                    454:                 * */
                    455: 
                    456:                if (con->physical.rel_path->used > 1) {
                    457:                        buffer *b = con->physical.rel_path;
                    458:                        size_t i;
                    459: 
                    460:                        if (b->used > 2 &&
                    461:                            b->ptr[b->used-2] == '/' &&
                    462:                            (b->ptr[b->used-3] == ' ' ||
                    463:                             b->ptr[b->used-3] == '.')) {
                    464:                                b->ptr[b->used--] = '\0';
                    465:                        }
                    466: 
                    467:                        for (i = b->used - 2; b->used > 1; i--) {
                    468:                                if (b->ptr[i] == ' ' ||
                    469:                                    b->ptr[i] == '.') {
                    470:                                        b->ptr[b->used--] = '\0';
                    471:                                } else {
                    472:                                        break;
                    473:                                }
                    474:                        }
                    475:                }
                    476: #endif
                    477: 
                    478:                if (con->conf.log_request_handling) {
                    479:                        log_error_write(srv, __FILE__, __LINE__,  "s",  "-- before doc_root");
                    480:                        log_error_write(srv, __FILE__, __LINE__,  "sb", "Doc-Root     :", con->physical.doc_root);
                    481:                        log_error_write(srv, __FILE__, __LINE__,  "sb", "Rel-Path     :", con->physical.rel_path);
                    482:                        log_error_write(srv, __FILE__, __LINE__,  "sb", "Path         :", con->physical.path);
                    483:                }
                    484:                /* the docroot plugin should set the doc_root and might also set the physical.path
                    485:                 * for us (all vhost-plugins are supposed to set the doc_root)
                    486:                 * */
                    487:                switch(r = plugins_call_handle_docroot(srv, con)) {
                    488:                case HANDLER_GO_ON:
                    489:                        break;
                    490:                case HANDLER_FINISHED:
                    491:                case HANDLER_COMEBACK:
                    492:                case HANDLER_WAIT_FOR_EVENT:
                    493:                case HANDLER_ERROR:
                    494:                        return r;
                    495:                default:
                    496:                        log_error_write(srv, __FILE__, __LINE__, "");
                    497:                        break;
                    498:                }
                    499: 
                    500:                /* MacOS X and Windows can't distiguish between upper and lower-case
                    501:                 *
                    502:                 * convert to lower-case
                    503:                 */
                    504:                if (con->conf.force_lowercase_filenames) {
                    505:                        buffer_to_lower(con->physical.rel_path);
                    506:                }
                    507: 
                    508:                /* the docroot plugins might set the servername, if they don't we take http-host */
                    509:                if (buffer_is_empty(con->server_name)) {
                    510:                        buffer_copy_string_buffer(con->server_name, con->uri.authority);
                    511:                }
                    512: 
                    513:                /**
                    514:                 * create physical filename
                    515:                 * -> physical.path = docroot + rel_path
                    516:                 *
                    517:                 */
                    518: 
                    519:                buffer_copy_string_buffer(con->physical.path, con->physical.doc_root);
                    520:                buffer_copy_string_buffer(con->physical.basedir, con->physical.path);
                    521:                BUFFER_APPEND_SLASH(con->physical.path);
                    522:                if (con->physical.rel_path->used &&
                    523:                    con->physical.rel_path->ptr[0] == '/') {
                    524:                        buffer_append_string_len(con->physical.path, con->physical.rel_path->ptr + 1, con->physical.rel_path->used - 2);
                    525:                } else {
                    526:                        buffer_append_string_buffer(con->physical.path, con->physical.rel_path);
                    527:                }
                    528: 
                    529:                if (con->conf.log_request_handling) {
                    530:                        log_error_write(srv, __FILE__, __LINE__,  "s",  "-- after doc_root");
                    531:                        log_error_write(srv, __FILE__, __LINE__,  "sb", "Doc-Root     :", con->physical.doc_root);
                    532:                        log_error_write(srv, __FILE__, __LINE__,  "sb", "Rel-Path     :", con->physical.rel_path);
                    533:                        log_error_write(srv, __FILE__, __LINE__,  "sb", "Path         :", con->physical.path);
                    534:                }
                    535: 
                    536:                switch(r = plugins_call_handle_physical(srv, con)) {
                    537:                case HANDLER_GO_ON:
                    538:                        break;
                    539:                case HANDLER_FINISHED:
                    540:                case HANDLER_COMEBACK:
                    541:                case HANDLER_WAIT_FOR_EVENT:
                    542:                case HANDLER_ERROR:
                    543:                        return r;
                    544:                default:
                    545:                        log_error_write(srv, __FILE__, __LINE__, "");
                    546:                        break;
                    547:                }
                    548: 
                    549:                if (con->conf.log_request_handling) {
                    550:                        log_error_write(srv, __FILE__, __LINE__,  "s",  "-- logical -> physical");
                    551:                        log_error_write(srv, __FILE__, __LINE__,  "sb", "Doc-Root     :", con->physical.doc_root);
                    552:                        log_error_write(srv, __FILE__, __LINE__,  "sb", "Rel-Path     :", con->physical.rel_path);
                    553:                        log_error_write(srv, __FILE__, __LINE__,  "sb", "Path         :", con->physical.path);
                    554:                }
                    555:        }
                    556: 
                    557:        /*
                    558:         * Noone catched away the file from normal path of execution yet (like mod_access)
                    559:         *
                    560:         * Go on and check of the file exists at all
                    561:         */
                    562: 
                    563:        if (con->mode == DIRECT) {
                    564:                char *slash = NULL;
                    565:                char *pathinfo = NULL;
                    566:                int found = 0;
                    567:                stat_cache_entry *sce = NULL;
                    568: 
                    569:                if (con->conf.log_request_handling) {
                    570:                        log_error_write(srv, __FILE__, __LINE__,  "s",  "-- handling physical path");
                    571:                        log_error_write(srv, __FILE__, __LINE__,  "sb", "Path         :", con->physical.path);
                    572:                }
                    573: 
                    574:                if (HANDLER_ERROR != stat_cache_get_entry(srv, con, con->physical.path, &sce)) {
                    575:                        /* file exists */
                    576: 
                    577:                        if (con->conf.log_request_handling) {
                    578:                                log_error_write(srv, __FILE__, __LINE__,  "s",  "-- file found");
                    579:                                log_error_write(srv, __FILE__, __LINE__,  "sb", "Path         :", con->physical.path);
                    580:                        }
                    581: #ifdef HAVE_LSTAT
                    582:                        if ((sce->is_symlink != 0) && !con->conf.follow_symlink) {
                    583:                                con->http_status = 403;
                    584: 
                    585:                                if (con->conf.log_request_handling) {
                    586:                                        log_error_write(srv, __FILE__, __LINE__,  "s",  "-- access denied due symlink restriction");
                    587:                                        log_error_write(srv, __FILE__, __LINE__,  "sb", "Path         :", con->physical.path);
                    588:                                }
                    589: 
                    590:                                buffer_reset(con->physical.path);
                    591:                                return HANDLER_FINISHED;
                    592:                        };
                    593: #endif
                    594:                        if (S_ISDIR(sce->st.st_mode)) {
                    595:                                if (con->uri.path->ptr[con->uri.path->used - 2] != '/') {
                    596:                                        /* redirect to .../ */
                    597: 
                    598:                                        http_response_redirect_to_directory(srv, con);
                    599: 
                    600:                                        return HANDLER_FINISHED;
                    601:                                }
                    602: #ifdef HAVE_LSTAT
                    603:                        } else if (!S_ISREG(sce->st.st_mode) && !sce->is_symlink) {
                    604: #else
                    605:                        } else if (!S_ISREG(sce->st.st_mode)) {
                    606: #endif
                    607:                                /* any special handling of non-reg files ?*/
                    608: 
                    609: 
                    610:                        }
                    611:                } else {
                    612:                        switch (errno) {
                    613:                        case EACCES:
                    614:                                con->http_status = 403;
                    615: 
                    616:                                if (con->conf.log_request_handling) {
                    617:                                        log_error_write(srv, __FILE__, __LINE__,  "s",  "-- access denied");
                    618:                                        log_error_write(srv, __FILE__, __LINE__,  "sb", "Path         :", con->physical.path);
                    619:                                }
                    620: 
                    621:                                buffer_reset(con->physical.path);
                    622:                                return HANDLER_FINISHED;
                    623:                        case ENAMETOOLONG:
                    624:                                /* file name to be read was too long. return 404 */
                    625:                        case ENOENT:
                    626:                                con->http_status = 404;
                    627: 
                    628:                                if (con->conf.log_request_handling) {
                    629:                                        log_error_write(srv, __FILE__, __LINE__,  "s",  "-- file not found");
                    630:                                        log_error_write(srv, __FILE__, __LINE__,  "sb", "Path         :", con->physical.path);
                    631:                                }
                    632: 
                    633:                                buffer_reset(con->physical.path);
                    634:                                return HANDLER_FINISHED;
                    635:                        case ENOTDIR:
                    636:                                /* PATH_INFO ! :) */
                    637:                                break;
                    638:                        default:
                    639:                                /* we have no idea what happend. let's tell the user so. */
                    640:                                con->http_status = 500;
                    641:                                buffer_reset(con->physical.path);
                    642: 
                    643:                                log_error_write(srv, __FILE__, __LINE__, "ssbsb",
                    644:                                                "file not found ... or so: ", strerror(errno),
                    645:                                                con->uri.path,
                    646:                                                "->", con->physical.path);
                    647: 
                    648:                                return HANDLER_FINISHED;
                    649:                        }
                    650: 
                    651:                        /* not found, perhaps PATHINFO */
                    652: 
                    653:                        buffer_copy_string_buffer(srv->tmp_buf, con->physical.path);
                    654: 
                    655:                        do {
                    656:                                if (slash) {
                    657:                                        buffer_copy_string_len(con->physical.path, srv->tmp_buf->ptr, slash - srv->tmp_buf->ptr);
                    658:                                } else {
                    659:                                        buffer_copy_string_buffer(con->physical.path, srv->tmp_buf);
                    660:                                }
                    661: 
                    662:                                if (HANDLER_ERROR != stat_cache_get_entry(srv, con, con->physical.path, &sce)) {
                    663:                                        found = S_ISREG(sce->st.st_mode);
                    664:                                        break;
                    665:                                }
                    666: 
                    667:                                if (pathinfo != NULL) {
                    668:                                        *pathinfo = '\0';
                    669:                                }
                    670:                                slash = strrchr(srv->tmp_buf->ptr, '/');
                    671: 
                    672:                                if (pathinfo != NULL) {
                    673:                                        /* restore '/' */
                    674:                                        *pathinfo = '/';
                    675:                                }
                    676: 
                    677:                                if (slash) pathinfo = slash;
                    678:                        } while ((found == 0) && (slash != NULL) && ((size_t)(slash - srv->tmp_buf->ptr) > (con->physical.basedir->used - 2)));
                    679: 
                    680:                        if (found == 0) {
                    681:                                /* no it really doesn't exists */
                    682:                                con->http_status = 404;
                    683: 
                    684:                                if (con->conf.log_file_not_found) {
                    685:                                        log_error_write(srv, __FILE__, __LINE__, "sbsb",
                    686:                                                        "file not found:", con->uri.path,
                    687:                                                        "->", con->physical.path);
                    688:                                }
                    689: 
                    690:                                buffer_reset(con->physical.path);
                    691: 
                    692:                                return HANDLER_FINISHED;
                    693:                        }
                    694: 
                    695: #ifdef HAVE_LSTAT
                    696:                        if ((sce->is_symlink != 0) && !con->conf.follow_symlink) {
                    697:                                con->http_status = 403;
                    698: 
                    699:                                if (con->conf.log_request_handling) {
                    700:                                        log_error_write(srv, __FILE__, __LINE__,  "s",  "-- access denied due symlink restriction");
                    701:                                        log_error_write(srv, __FILE__, __LINE__,  "sb", "Path         :", con->physical.path);
                    702:                                }
                    703: 
                    704:                                buffer_reset(con->physical.path);
                    705:                                return HANDLER_FINISHED;
                    706:                        };
                    707: #endif
                    708: 
                    709:                        /* we have a PATHINFO */
                    710:                        if (pathinfo) {
                    711:                                buffer_copy_string(con->request.pathinfo, pathinfo);
                    712: 
                    713:                                /*
                    714:                                 * shorten uri.path
                    715:                                 */
                    716: 
                    717:                                con->uri.path->used -= strlen(pathinfo);
                    718:                                con->uri.path->ptr[con->uri.path->used - 1] = '\0';
                    719:                        }
                    720: 
                    721:                        if (con->conf.log_request_handling) {
                    722:                                log_error_write(srv, __FILE__, __LINE__,  "s",  "-- after pathinfo check");
                    723:                                log_error_write(srv, __FILE__, __LINE__,  "sb", "Path         :", con->physical.path);
                    724:                                log_error_write(srv, __FILE__, __LINE__,  "sb", "URI          :", con->uri.path);
                    725:                                log_error_write(srv, __FILE__, __LINE__,  "sb", "Pathinfo     :", con->request.pathinfo);
                    726:                        }
                    727:                }
                    728: 
                    729:                if (con->conf.log_request_handling) {
                    730:                        log_error_write(srv, __FILE__, __LINE__,  "s",  "-- handling subrequest");
                    731:                        log_error_write(srv, __FILE__, __LINE__,  "sb", "Path         :", con->physical.path);
                    732:                }
                    733: 
                    734:                /* call the handlers */
                    735:                switch(r = plugins_call_handle_subrequest_start(srv, con)) {
                    736:                case HANDLER_GO_ON:
                    737:                        /* request was not handled */
                    738:                        break;
                    739:                case HANDLER_FINISHED:
                    740:                default:
                    741:                        if (con->conf.log_request_handling) {
                    742:                                log_error_write(srv, __FILE__, __LINE__,  "s",  "-- subrequest finished");
                    743:                        }
                    744: 
                    745:                        /* something strange happend */
                    746:                        return r;
                    747:                }
                    748: 
                    749:                /* if we are still here, no one wanted the file, status 403 is ok I think */
                    750: 
                    751:                if (con->mode == DIRECT && con->http_status == 0) {
                    752:                        switch (con->request.http_method) {
                    753:                        case HTTP_METHOD_OPTIONS:
                    754:                                con->http_status = 200;
                    755:                                break;
                    756:                        default:
                    757:                                con->http_status = 403;
                    758:                        }
                    759: 
                    760:                        return HANDLER_FINISHED;
                    761:                }
                    762: 
                    763:        }
                    764: 
                    765:        switch(r = plugins_call_handle_subrequest(srv, con)) {
                    766:        case HANDLER_GO_ON:
                    767:                /* request was not handled, looks like we are done */
                    768:                return HANDLER_FINISHED;
                    769:        case HANDLER_FINISHED:
                    770:                /* request is finished */
                    771:        default:
                    772:                /* something strange happend */
                    773:                return r;
                    774:        }
                    775: 
                    776:        /* can't happen */
                    777:        return HANDLER_COMEBACK;
                    778: }
                    779: 
                    780: 
                    781: 

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