Annotation of embedaddon/nginx/src/http/modules/ngx_http_autoindex_module.c, revision 1.1

1.1     ! misho       1: 
        !             2: /*
        !             3:  * Copyright (C) Igor Sysoev
        !             4:  * Copyright (C) Nginx, Inc.
        !             5:  */
        !             6: 
        !             7: 
        !             8: #include <ngx_config.h>
        !             9: #include <ngx_core.h>
        !            10: #include <ngx_http.h>
        !            11: 
        !            12: 
        !            13: #if 0
        !            14: 
        !            15: typedef struct {
        !            16:     ngx_buf_t     *buf;
        !            17:     size_t         size;
        !            18:     ngx_pool_t    *pool;
        !            19:     size_t         alloc_size;
        !            20:     ngx_chain_t  **last_out;
        !            21: } ngx_http_autoindex_ctx_t;
        !            22: 
        !            23: #endif
        !            24: 
        !            25: 
        !            26: typedef struct {
        !            27:     ngx_str_t      name;
        !            28:     size_t         utf_len;
        !            29:     size_t         escape;
        !            30:     size_t         escape_html;
        !            31: 
        !            32:     unsigned       dir:1;
        !            33: 
        !            34:     time_t         mtime;
        !            35:     off_t          size;
        !            36: } ngx_http_autoindex_entry_t;
        !            37: 
        !            38: 
        !            39: typedef struct {
        !            40:     ngx_flag_t     enable;
        !            41:     ngx_flag_t     localtime;
        !            42:     ngx_flag_t     exact_size;
        !            43: } ngx_http_autoindex_loc_conf_t;
        !            44: 
        !            45: 
        !            46: #define NGX_HTTP_AUTOINDEX_PREALLOCATE  50
        !            47: 
        !            48: #define NGX_HTTP_AUTOINDEX_NAME_LEN     50
        !            49: 
        !            50: 
        !            51: static int ngx_libc_cdecl ngx_http_autoindex_cmp_entries(const void *one,
        !            52:     const void *two);
        !            53: static ngx_int_t ngx_http_autoindex_error(ngx_http_request_t *r,
        !            54:     ngx_dir_t *dir, ngx_str_t *name);
        !            55: static ngx_int_t ngx_http_autoindex_init(ngx_conf_t *cf);
        !            56: static void *ngx_http_autoindex_create_loc_conf(ngx_conf_t *cf);
        !            57: static char *ngx_http_autoindex_merge_loc_conf(ngx_conf_t *cf,
        !            58:     void *parent, void *child);
        !            59: 
        !            60: 
        !            61: static ngx_command_t  ngx_http_autoindex_commands[] = {
        !            62: 
        !            63:     { ngx_string("autoindex"),
        !            64:       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG,
        !            65:       ngx_conf_set_flag_slot,
        !            66:       NGX_HTTP_LOC_CONF_OFFSET,
        !            67:       offsetof(ngx_http_autoindex_loc_conf_t, enable),
        !            68:       NULL },
        !            69: 
        !            70:     { ngx_string("autoindex_localtime"),
        !            71:       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG,
        !            72:       ngx_conf_set_flag_slot,
        !            73:       NGX_HTTP_LOC_CONF_OFFSET,
        !            74:       offsetof(ngx_http_autoindex_loc_conf_t, localtime),
        !            75:       NULL },
        !            76: 
        !            77:     { ngx_string("autoindex_exact_size"),
        !            78:       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG,
        !            79:       ngx_conf_set_flag_slot,
        !            80:       NGX_HTTP_LOC_CONF_OFFSET,
        !            81:       offsetof(ngx_http_autoindex_loc_conf_t, exact_size),
        !            82:       NULL },
        !            83: 
        !            84:       ngx_null_command
        !            85: };
        !            86: 
        !            87: 
        !            88: static ngx_http_module_t  ngx_http_autoindex_module_ctx = {
        !            89:     NULL,                                  /* preconfiguration */
        !            90:     ngx_http_autoindex_init,               /* postconfiguration */
        !            91: 
        !            92:     NULL,                                  /* create main configuration */
        !            93:     NULL,                                  /* init main configuration */
        !            94: 
        !            95:     NULL,                                  /* create server configuration */
        !            96:     NULL,                                  /* merge server configuration */
        !            97: 
        !            98:     ngx_http_autoindex_create_loc_conf,    /* create location configuration */
        !            99:     ngx_http_autoindex_merge_loc_conf      /* merge location configuration */
        !           100: };
        !           101: 
        !           102: 
        !           103: ngx_module_t  ngx_http_autoindex_module = {
        !           104:     NGX_MODULE_V1,
        !           105:     &ngx_http_autoindex_module_ctx,        /* module context */
        !           106:     ngx_http_autoindex_commands,           /* module directives */
        !           107:     NGX_HTTP_MODULE,                       /* module type */
        !           108:     NULL,                                  /* init master */
        !           109:     NULL,                                  /* init module */
        !           110:     NULL,                                  /* init process */
        !           111:     NULL,                                  /* init thread */
        !           112:     NULL,                                  /* exit thread */
        !           113:     NULL,                                  /* exit process */
        !           114:     NULL,                                  /* exit master */
        !           115:     NGX_MODULE_V1_PADDING
        !           116: };
        !           117: 
        !           118: 
        !           119: static u_char title[] =
        !           120: "<html>" CRLF
        !           121: "<head><title>Index of "
        !           122: ;
        !           123: 
        !           124: 
        !           125: static u_char header[] =
        !           126: "</title></head>" CRLF
        !           127: "<body bgcolor=\"white\">" CRLF
        !           128: "<h1>Index of "
        !           129: ;
        !           130: 
        !           131: static u_char tail[] =
        !           132: "</body>" CRLF
        !           133: "</html>" CRLF
        !           134: ;
        !           135: 
        !           136: 
        !           137: static ngx_int_t
        !           138: ngx_http_autoindex_handler(ngx_http_request_t *r)
        !           139: {
        !           140:     u_char                         *last, *filename, scale;
        !           141:     off_t                           length;
        !           142:     size_t                          len, char_len, escape_html, allocated, root;
        !           143:     ngx_tm_t                        tm;
        !           144:     ngx_err_t                       err;
        !           145:     ngx_buf_t                      *b;
        !           146:     ngx_int_t                       rc, size;
        !           147:     ngx_str_t                       path;
        !           148:     ngx_dir_t                       dir;
        !           149:     ngx_uint_t                      i, level, utf8;
        !           150:     ngx_pool_t                     *pool;
        !           151:     ngx_time_t                     *tp;
        !           152:     ngx_chain_t                     out;
        !           153:     ngx_array_t                     entries;
        !           154:     ngx_http_autoindex_entry_t     *entry;
        !           155:     ngx_http_autoindex_loc_conf_t  *alcf;
        !           156: 
        !           157:     static char  *months[] = { "Jan", "Feb", "Mar", "Apr", "May", "Jun",
        !           158:                                "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" };
        !           159: 
        !           160:     if (r->uri.data[r->uri.len - 1] != '/') {
        !           161:         return NGX_DECLINED;
        !           162:     }
        !           163: 
        !           164:     if (!(r->method & (NGX_HTTP_GET|NGX_HTTP_HEAD))) {
        !           165:         return NGX_DECLINED;
        !           166:     }
        !           167: 
        !           168:     alcf = ngx_http_get_module_loc_conf(r, ngx_http_autoindex_module);
        !           169: 
        !           170:     if (!alcf->enable) {
        !           171:         return NGX_DECLINED;
        !           172:     }
        !           173: 
        !           174:     /* NGX_DIR_MASK_LEN is lesser than NGX_HTTP_AUTOINDEX_PREALLOCATE */
        !           175: 
        !           176:     last = ngx_http_map_uri_to_path(r, &path, &root,
        !           177:                                     NGX_HTTP_AUTOINDEX_PREALLOCATE);
        !           178:     if (last == NULL) {
        !           179:         return NGX_HTTP_INTERNAL_SERVER_ERROR;
        !           180:     }
        !           181: 
        !           182:     allocated = path.len;
        !           183:     path.len = last - path.data;
        !           184:     if (path.len > 1) {
        !           185:         path.len--;
        !           186:     }
        !           187:     path.data[path.len] = '\0';
        !           188: 
        !           189:     ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
        !           190:                    "http autoindex: \"%s\"", path.data);
        !           191: 
        !           192:     if (ngx_open_dir(&path, &dir) == NGX_ERROR) {
        !           193:         err = ngx_errno;
        !           194: 
        !           195:         if (err == NGX_ENOENT
        !           196:             || err == NGX_ENOTDIR
        !           197:             || err == NGX_ENAMETOOLONG)
        !           198:         {
        !           199:             level = NGX_LOG_ERR;
        !           200:             rc = NGX_HTTP_NOT_FOUND;
        !           201: 
        !           202:         } else if (err == NGX_EACCES) {
        !           203:             level = NGX_LOG_ERR;
        !           204:             rc = NGX_HTTP_FORBIDDEN;
        !           205: 
        !           206:         } else {
        !           207:             level = NGX_LOG_CRIT;
        !           208:             rc = NGX_HTTP_INTERNAL_SERVER_ERROR;
        !           209:         }
        !           210: 
        !           211:         ngx_log_error(level, r->connection->log, err,
        !           212:                       ngx_open_dir_n " \"%s\" failed", path.data);
        !           213: 
        !           214:         return rc;
        !           215:     }
        !           216: 
        !           217: #if (NGX_SUPPRESS_WARN)
        !           218: 
        !           219:     /* MSVC thinks 'entries' may be used without having been initialized */
        !           220:     ngx_memzero(&entries, sizeof(ngx_array_t));
        !           221: 
        !           222: #endif
        !           223: 
        !           224:     /* TODO: pool should be temporary pool */
        !           225:     pool = r->pool;
        !           226: 
        !           227:     if (ngx_array_init(&entries, pool, 40, sizeof(ngx_http_autoindex_entry_t))
        !           228:         != NGX_OK)
        !           229:     {
        !           230:         return ngx_http_autoindex_error(r, &dir, &path);
        !           231:     }
        !           232: 
        !           233:     r->headers_out.status = NGX_HTTP_OK;
        !           234:     r->headers_out.content_type_len = sizeof("text/html") - 1;
        !           235:     ngx_str_set(&r->headers_out.content_type, "text/html");
        !           236: 
        !           237:     rc = ngx_http_send_header(r);
        !           238: 
        !           239:     if (rc == NGX_ERROR || rc > NGX_OK || r->header_only) {
        !           240:         if (ngx_close_dir(&dir) == NGX_ERROR) {
        !           241:             ngx_log_error(NGX_LOG_ALERT, r->connection->log, ngx_errno,
        !           242:                           ngx_close_dir_n " \"%V\" failed", &path);
        !           243:         }
        !           244: 
        !           245:         return rc;
        !           246:     }
        !           247: 
        !           248:     filename = path.data;
        !           249:     filename[path.len] = '/';
        !           250: 
        !           251:     if (r->headers_out.charset.len == 5
        !           252:         && ngx_strncasecmp(r->headers_out.charset.data, (u_char *) "utf-8", 5)
        !           253:            == 0)
        !           254:     {
        !           255:         utf8 = 1;
        !           256: 
        !           257:     } else {
        !           258:         utf8 = 0;
        !           259:     }
        !           260: 
        !           261:     for ( ;; ) {
        !           262:         ngx_set_errno(0);
        !           263: 
        !           264:         if (ngx_read_dir(&dir) == NGX_ERROR) {
        !           265:             err = ngx_errno;
        !           266: 
        !           267:             if (err != NGX_ENOMOREFILES) {
        !           268:                 ngx_log_error(NGX_LOG_CRIT, r->connection->log, err,
        !           269:                               ngx_read_dir_n " \"%V\" failed", &path);
        !           270:                 return ngx_http_autoindex_error(r, &dir, &path);
        !           271:             }
        !           272: 
        !           273:             break;
        !           274:         }
        !           275: 
        !           276:         ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
        !           277:                        "http autoindex file: \"%s\"", ngx_de_name(&dir));
        !           278: 
        !           279:         len = ngx_de_namelen(&dir);
        !           280: 
        !           281:         if (ngx_de_name(&dir)[0] == '.') {
        !           282:             continue;
        !           283:         }
        !           284: 
        !           285:         if (!dir.valid_info) {
        !           286: 
        !           287:             /* 1 byte for '/' and 1 byte for terminating '\0' */
        !           288: 
        !           289:             if (path.len + 1 + len + 1 > allocated) {
        !           290:                 allocated = path.len + 1 + len + 1
        !           291:                                      + NGX_HTTP_AUTOINDEX_PREALLOCATE;
        !           292: 
        !           293:                 filename = ngx_pnalloc(pool, allocated);
        !           294:                 if (filename == NULL) {
        !           295:                     return ngx_http_autoindex_error(r, &dir, &path);
        !           296:                 }
        !           297: 
        !           298:                 last = ngx_cpystrn(filename, path.data, path.len + 1);
        !           299:                 *last++ = '/';
        !           300:             }
        !           301: 
        !           302:             ngx_cpystrn(last, ngx_de_name(&dir), len + 1);
        !           303: 
        !           304:             if (ngx_de_info(filename, &dir) == NGX_FILE_ERROR) {
        !           305:                 err = ngx_errno;
        !           306: 
        !           307:                 if (err != NGX_ENOENT && err != NGX_ELOOP) {
        !           308:                     ngx_log_error(NGX_LOG_CRIT, r->connection->log, err,
        !           309:                                   ngx_de_info_n " \"%s\" failed", filename);
        !           310: 
        !           311:                     if (err == NGX_EACCES) {
        !           312:                         continue;
        !           313:                     }
        !           314: 
        !           315:                     return ngx_http_autoindex_error(r, &dir, &path);
        !           316:                 }
        !           317: 
        !           318:                 if (ngx_de_link_info(filename, &dir) == NGX_FILE_ERROR) {
        !           319:                     ngx_log_error(NGX_LOG_CRIT, r->connection->log, ngx_errno,
        !           320:                                   ngx_de_link_info_n " \"%s\" failed",
        !           321:                                   filename);
        !           322:                     return ngx_http_autoindex_error(r, &dir, &path);
        !           323:                 }
        !           324:             }
        !           325:         }
        !           326: 
        !           327:         entry = ngx_array_push(&entries);
        !           328:         if (entry == NULL) {
        !           329:             return ngx_http_autoindex_error(r, &dir, &path);
        !           330:         }
        !           331: 
        !           332:         entry->name.len = len;
        !           333: 
        !           334:         entry->name.data = ngx_pnalloc(pool, len + 1);
        !           335:         if (entry->name.data == NULL) {
        !           336:             return ngx_http_autoindex_error(r, &dir, &path);
        !           337:         }
        !           338: 
        !           339:         ngx_cpystrn(entry->name.data, ngx_de_name(&dir), len + 1);
        !           340: 
        !           341:         entry->escape = 2 * ngx_escape_uri(NULL, ngx_de_name(&dir), len,
        !           342:                                            NGX_ESCAPE_URI_COMPONENT);
        !           343: 
        !           344:         entry->escape_html = ngx_escape_html(NULL, entry->name.data,
        !           345:                                              entry->name.len);
        !           346: 
        !           347:         if (utf8) {
        !           348:             entry->utf_len = ngx_utf8_length(entry->name.data, entry->name.len);
        !           349:         } else {
        !           350:             entry->utf_len = len;
        !           351:         }
        !           352: 
        !           353:         entry->dir = ngx_de_is_dir(&dir);
        !           354:         entry->mtime = ngx_de_mtime(&dir);
        !           355:         entry->size = ngx_de_size(&dir);
        !           356:     }
        !           357: 
        !           358:     if (ngx_close_dir(&dir) == NGX_ERROR) {
        !           359:         ngx_log_error(NGX_LOG_ALERT, r->connection->log, ngx_errno,
        !           360:                       ngx_close_dir_n " \"%s\" failed", &path);
        !           361:     }
        !           362: 
        !           363:     escape_html = ngx_escape_html(NULL, r->uri.data, r->uri.len);
        !           364: 
        !           365:     len = sizeof(title) - 1
        !           366:           + r->uri.len + escape_html
        !           367:           + sizeof(header) - 1
        !           368:           + r->uri.len + escape_html
        !           369:           + sizeof("</h1>") - 1
        !           370:           + sizeof("<hr><pre><a href=\"../\">../</a>" CRLF) - 1
        !           371:           + sizeof("</pre><hr>") - 1
        !           372:           + sizeof(tail) - 1;
        !           373: 
        !           374:     entry = entries.elts;
        !           375:     for (i = 0; i < entries.nelts; i++) {
        !           376:         len += sizeof("<a href=\"") - 1
        !           377:             + entry[i].name.len + entry[i].escape
        !           378:             + 1                                          /* 1 is for "/" */
        !           379:             + sizeof("\">") - 1
        !           380:             + entry[i].name.len - entry[i].utf_len
        !           381:             + entry[i].escape_html
        !           382:             + NGX_HTTP_AUTOINDEX_NAME_LEN + sizeof("&gt;") - 2
        !           383:             + sizeof("</a>") - 1
        !           384:             + sizeof(" 28-Sep-1970 12:00 ") - 1
        !           385:             + 20                                         /* the file size */
        !           386:             + 2;
        !           387:     }
        !           388: 
        !           389:     b = ngx_create_temp_buf(r->pool, len);
        !           390:     if (b == NULL) {
        !           391:         return NGX_ERROR;
        !           392:     }
        !           393: 
        !           394:     if (entries.nelts > 1) {
        !           395:         ngx_qsort(entry, (size_t) entries.nelts,
        !           396:                   sizeof(ngx_http_autoindex_entry_t),
        !           397:                   ngx_http_autoindex_cmp_entries);
        !           398:     }
        !           399: 
        !           400:     b->last = ngx_cpymem(b->last, title, sizeof(title) - 1);
        !           401: 
        !           402:     if (escape_html) {
        !           403:         b->last = (u_char *) ngx_escape_html(b->last, r->uri.data, r->uri.len);
        !           404:         b->last = ngx_cpymem(b->last, header, sizeof(header) - 1);
        !           405:         b->last = (u_char *) ngx_escape_html(b->last, r->uri.data, r->uri.len);
        !           406: 
        !           407:     } else {
        !           408:         b->last = ngx_cpymem(b->last, r->uri.data, r->uri.len);
        !           409:         b->last = ngx_cpymem(b->last, header, sizeof(header) - 1);
        !           410:         b->last = ngx_cpymem(b->last, r->uri.data, r->uri.len);
        !           411:     }
        !           412: 
        !           413:     b->last = ngx_cpymem(b->last, "</h1>", sizeof("</h1>") - 1);
        !           414: 
        !           415:     b->last = ngx_cpymem(b->last, "<hr><pre><a href=\"../\">../</a>" CRLF,
        !           416:                          sizeof("<hr><pre><a href=\"../\">../</a>" CRLF) - 1);
        !           417: 
        !           418:     tp = ngx_timeofday();
        !           419: 
        !           420:     for (i = 0; i < entries.nelts; i++) {
        !           421:         b->last = ngx_cpymem(b->last, "<a href=\"", sizeof("<a href=\"") - 1);
        !           422: 
        !           423:         if (entry[i].escape) {
        !           424:             ngx_escape_uri(b->last, entry[i].name.data, entry[i].name.len,
        !           425:                            NGX_ESCAPE_URI_COMPONENT);
        !           426: 
        !           427:             b->last += entry[i].name.len + entry[i].escape;
        !           428: 
        !           429:         } else {
        !           430:             b->last = ngx_cpymem(b->last, entry[i].name.data,
        !           431:                                  entry[i].name.len);
        !           432:         }
        !           433: 
        !           434:         if (entry[i].dir) {
        !           435:             *b->last++ = '/';
        !           436:         }
        !           437: 
        !           438:         *b->last++ = '"';
        !           439:         *b->last++ = '>';
        !           440: 
        !           441:         len = entry[i].utf_len;
        !           442: 
        !           443:         if (entry[i].name.len != len) {
        !           444:             if (len > NGX_HTTP_AUTOINDEX_NAME_LEN) {
        !           445:                 char_len = NGX_HTTP_AUTOINDEX_NAME_LEN - 3 + 1;
        !           446: 
        !           447:             } else {
        !           448:                 char_len = NGX_HTTP_AUTOINDEX_NAME_LEN + 1;
        !           449:             }
        !           450: 
        !           451:             last = b->last;
        !           452:             b->last = ngx_utf8_cpystrn(b->last, entry[i].name.data,
        !           453:                                        char_len, entry[i].name.len + 1);
        !           454: 
        !           455:             if (entry[i].escape_html) {
        !           456:                 b->last = (u_char *) ngx_escape_html(last, entry[i].name.data,
        !           457:                                                      b->last - last);
        !           458:             }
        !           459: 
        !           460:             last = b->last;
        !           461: 
        !           462:         } else {
        !           463:             if (entry[i].escape_html) {
        !           464:                 if (len > NGX_HTTP_AUTOINDEX_NAME_LEN) {
        !           465:                     char_len = NGX_HTTP_AUTOINDEX_NAME_LEN - 3;
        !           466: 
        !           467:                 } else {
        !           468:                     char_len = len;
        !           469:                 }
        !           470: 
        !           471:                 b->last = (u_char *) ngx_escape_html(b->last,
        !           472:                                                   entry[i].name.data, char_len);
        !           473:                 last = b->last;
        !           474: 
        !           475:             } else {
        !           476:                 b->last = ngx_cpystrn(b->last, entry[i].name.data,
        !           477:                                       NGX_HTTP_AUTOINDEX_NAME_LEN + 1);
        !           478:                 last = b->last - 3;
        !           479:             }
        !           480:         }
        !           481: 
        !           482:         if (len > NGX_HTTP_AUTOINDEX_NAME_LEN) {
        !           483:             b->last = ngx_cpymem(last, "..&gt;</a>", sizeof("..&gt;</a>") - 1);
        !           484: 
        !           485:         } else {
        !           486:             if (entry[i].dir && NGX_HTTP_AUTOINDEX_NAME_LEN - len > 0) {
        !           487:                 *b->last++ = '/';
        !           488:                 len++;
        !           489:             }
        !           490: 
        !           491:             b->last = ngx_cpymem(b->last, "</a>", sizeof("</a>") - 1);
        !           492: 
        !           493:             if (NGX_HTTP_AUTOINDEX_NAME_LEN - len > 0) {
        !           494:                 ngx_memset(b->last, ' ', NGX_HTTP_AUTOINDEX_NAME_LEN - len);
        !           495:                 b->last += NGX_HTTP_AUTOINDEX_NAME_LEN - len;
        !           496:             }
        !           497:         }
        !           498: 
        !           499:         *b->last++ = ' ';
        !           500: 
        !           501:         ngx_gmtime(entry[i].mtime + tp->gmtoff * 60 * alcf->localtime, &tm);
        !           502: 
        !           503:         b->last = ngx_sprintf(b->last, "%02d-%s-%d %02d:%02d ",
        !           504:                               tm.ngx_tm_mday,
        !           505:                               months[tm.ngx_tm_mon - 1],
        !           506:                               tm.ngx_tm_year,
        !           507:                               tm.ngx_tm_hour,
        !           508:                               tm.ngx_tm_min);
        !           509: 
        !           510:         if (alcf->exact_size) {
        !           511:             if (entry[i].dir) {
        !           512:                 b->last = ngx_cpymem(b->last,  "                  -",
        !           513:                                      sizeof("                  -") - 1);
        !           514:             } else {
        !           515:                 b->last = ngx_sprintf(b->last, "%19O", entry[i].size);
        !           516:             }
        !           517: 
        !           518:         } else {
        !           519:             if (entry[i].dir) {
        !           520:                 b->last = ngx_cpymem(b->last,  "      -",
        !           521:                                      sizeof("      -") - 1);
        !           522: 
        !           523:             } else {
        !           524:                 length = entry[i].size;
        !           525: 
        !           526:                 if (length > 1024 * 1024 * 1024 - 1) {
        !           527:                     size = (ngx_int_t) (length / (1024 * 1024 * 1024));
        !           528:                     if ((length % (1024 * 1024 * 1024))
        !           529:                                                 > (1024 * 1024 * 1024 / 2 - 1))
        !           530:                     {
        !           531:                         size++;
        !           532:                     }
        !           533:                     scale = 'G';
        !           534: 
        !           535:                 } else if (length > 1024 * 1024 - 1) {
        !           536:                     size = (ngx_int_t) (length / (1024 * 1024));
        !           537:                     if ((length % (1024 * 1024)) > (1024 * 1024 / 2 - 1)) {
        !           538:                         size++;
        !           539:                     }
        !           540:                     scale = 'M';
        !           541: 
        !           542:                 } else if (length > 9999) {
        !           543:                     size = (ngx_int_t) (length / 1024);
        !           544:                     if (length % 1024 > 511) {
        !           545:                         size++;
        !           546:                     }
        !           547:                     scale = 'K';
        !           548: 
        !           549:                 } else {
        !           550:                     size = (ngx_int_t) length;
        !           551:                     scale = '\0';
        !           552:                 }
        !           553: 
        !           554:                 if (scale) {
        !           555:                     b->last = ngx_sprintf(b->last, "%6i%c", size, scale);
        !           556: 
        !           557:                 } else {
        !           558:                     b->last = ngx_sprintf(b->last, " %6i", size);
        !           559:                 }
        !           560:             }
        !           561:         }
        !           562: 
        !           563:         *b->last++ = CR;
        !           564:         *b->last++ = LF;
        !           565:     }
        !           566: 
        !           567:     /* TODO: free temporary pool */
        !           568: 
        !           569:     b->last = ngx_cpymem(b->last, "</pre><hr>", sizeof("</pre><hr>") - 1);
        !           570: 
        !           571:     b->last = ngx_cpymem(b->last, tail, sizeof(tail) - 1);
        !           572: 
        !           573:     if (r == r->main) {
        !           574:         b->last_buf = 1;
        !           575:     }
        !           576: 
        !           577:     b->last_in_chain = 1;
        !           578: 
        !           579:     out.buf = b;
        !           580:     out.next = NULL;
        !           581: 
        !           582:     return ngx_http_output_filter(r, &out);
        !           583: }
        !           584: 
        !           585: 
        !           586: static int ngx_libc_cdecl
        !           587: ngx_http_autoindex_cmp_entries(const void *one, const void *two)
        !           588: {
        !           589:     ngx_http_autoindex_entry_t *first = (ngx_http_autoindex_entry_t *) one;
        !           590:     ngx_http_autoindex_entry_t *second = (ngx_http_autoindex_entry_t *) two;
        !           591: 
        !           592:     if (first->dir && !second->dir) {
        !           593:         /* move the directories to the start */
        !           594:         return -1;
        !           595:     }
        !           596: 
        !           597:     if (!first->dir && second->dir) {
        !           598:         /* move the directories to the start */
        !           599:         return 1;
        !           600:     }
        !           601: 
        !           602:     return (int) ngx_strcmp(first->name.data, second->name.data);
        !           603: }
        !           604: 
        !           605: 
        !           606: #if 0
        !           607: 
        !           608: static ngx_buf_t *
        !           609: ngx_http_autoindex_alloc(ngx_http_autoindex_ctx_t *ctx, size_t size)
        !           610: {
        !           611:     ngx_chain_t  *cl;
        !           612: 
        !           613:     if (ctx->buf) {
        !           614: 
        !           615:         if ((size_t) (ctx->buf->end - ctx->buf->last) >= size) {
        !           616:             return ctx->buf;
        !           617:         }
        !           618: 
        !           619:         ctx->size += ctx->buf->last - ctx->buf->pos;
        !           620:     }
        !           621: 
        !           622:     ctx->buf = ngx_create_temp_buf(ctx->pool, ctx->alloc_size);
        !           623:     if (ctx->buf == NULL) {
        !           624:         return NULL;
        !           625:     }
        !           626: 
        !           627:     cl = ngx_alloc_chain_link(ctx->pool);
        !           628:     if (cl == NULL) {
        !           629:         return NULL;
        !           630:     }
        !           631: 
        !           632:     cl->buf = ctx->buf;
        !           633:     cl->next = NULL;
        !           634: 
        !           635:     *ctx->last_out = cl;
        !           636:     ctx->last_out = &cl->next;
        !           637: 
        !           638:     return ctx->buf;
        !           639: }
        !           640: 
        !           641: #endif
        !           642: 
        !           643: 
        !           644: static ngx_int_t
        !           645: ngx_http_autoindex_error(ngx_http_request_t *r, ngx_dir_t *dir, ngx_str_t *name)
        !           646: {
        !           647:     if (ngx_close_dir(dir) == NGX_ERROR) {
        !           648:         ngx_log_error(NGX_LOG_ALERT, r->connection->log, ngx_errno,
        !           649:                       ngx_close_dir_n " \"%V\" failed", name);
        !           650:     }
        !           651: 
        !           652:     return r->header_sent ? NGX_ERROR : NGX_HTTP_INTERNAL_SERVER_ERROR;
        !           653: }
        !           654: 
        !           655: 
        !           656: static void *
        !           657: ngx_http_autoindex_create_loc_conf(ngx_conf_t *cf)
        !           658: {
        !           659:     ngx_http_autoindex_loc_conf_t  *conf;
        !           660: 
        !           661:     conf = ngx_palloc(cf->pool, sizeof(ngx_http_autoindex_loc_conf_t));
        !           662:     if (conf == NULL) {
        !           663:         return NULL;
        !           664:     }
        !           665: 
        !           666:     conf->enable = NGX_CONF_UNSET;
        !           667:     conf->localtime = NGX_CONF_UNSET;
        !           668:     conf->exact_size = NGX_CONF_UNSET;
        !           669: 
        !           670:     return conf;
        !           671: }
        !           672: 
        !           673: 
        !           674: static char *
        !           675: ngx_http_autoindex_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child)
        !           676: {
        !           677:     ngx_http_autoindex_loc_conf_t *prev = parent;
        !           678:     ngx_http_autoindex_loc_conf_t *conf = child;
        !           679: 
        !           680:     ngx_conf_merge_value(conf->enable, prev->enable, 0);
        !           681:     ngx_conf_merge_value(conf->localtime, prev->localtime, 0);
        !           682:     ngx_conf_merge_value(conf->exact_size, prev->exact_size, 1);
        !           683: 
        !           684:     return NGX_CONF_OK;
        !           685: }
        !           686: 
        !           687: 
        !           688: static ngx_int_t
        !           689: ngx_http_autoindex_init(ngx_conf_t *cf)
        !           690: {
        !           691:     ngx_http_handler_pt        *h;
        !           692:     ngx_http_core_main_conf_t  *cmcf;
        !           693: 
        !           694:     cmcf = ngx_http_conf_get_module_main_conf(cf, ngx_http_core_module);
        !           695: 
        !           696:     h = ngx_array_push(&cmcf->phases[NGX_HTTP_CONTENT_PHASE].handlers);
        !           697:     if (h == NULL) {
        !           698:         return NGX_ERROR;
        !           699:     }
        !           700: 
        !           701:     *h = ngx_http_autoindex_handler;
        !           702: 
        !           703:     return NGX_OK;
        !           704: }

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