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