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

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

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