static ngx_int_t
ngx_file_info_wrapper(ngx_str_t *name, ngx_open_file_info_t *of,
    ngx_file_info_t *fi, ngx_log_t *log)
{
    ngx_int_t  rc;

#if !(NGX_HAVE_OPENAT)

    rc = ngx_file_info(name->data, fi);

    if (rc == NGX_FILE_ERROR) {
        of->err = ngx_errno;
        of->failed = ngx_file_info_n;
        return NGX_FILE_ERROR;
    }

    return rc;

#else

    ngx_fd_t  fd;

    if (of->disable_symlinks == NGX_DISABLE_SYMLINKS_OFF) {

        rc = ngx_file_info(name->data, fi);

        if (rc == NGX_FILE_ERROR) {
            of->err = ngx_errno;
            of->failed = ngx_file_info_n;
            return NGX_FILE_ERROR;
        }

        return rc;
    }

    fd = ngx_open_file_wrapper(name, of, NGX_FILE_RDONLY|NGX_FILE_NONBLOCK,
                               NGX_FILE_OPEN, 0, log);

    if (fd == NGX_INVALID_FILE) {
        return NGX_FILE_ERROR;
    }

    rc = ngx_fd_info(fd, fi);

    if (rc == NGX_FILE_ERROR) {
        of->err = ngx_errno;
        of->failed = ngx_fd_info_n;
    }

    if (ngx_close_file(fd) == NGX_FILE_ERROR) {
        ngx_log_error(NGX_LOG_ALERT, log, ngx_errno,
                      ngx_close_file_n " \"%V\" failed", name);
    }

    return rc;
#endif
}
Example #2
0
static void
ngx_pipe_create_subdirs(char *filename, ngx_cycle_t *cycle)
{
    ngx_file_info_t stat_buf;
    char            dirname[1024];
    char           *p;

    for (p = filename; (p = strchr(p, '/')); p++)
    {
        if (p == filename) {
            continue;       // Don't bother with the root directory
        }

        ngx_memcpy(dirname, filename, p - filename);
        dirname[p-filename] = '\0';

        if (ngx_file_info(dirname, &stat_buf) < 0) {
            if (errno != ENOENT) {
                ngx_log_error(NGX_LOG_EMERG, cycle->log, ngx_errno,
                              "stat [%s] failed", dirname);
                exit(2);

            } else {
                if ((ngx_create_dir(dirname, NGX_PIPE_DIR_ACCESS) < 0) && (errno != EEXIST)) {
                    ngx_log_error(NGX_LOG_EMERG, cycle->log, ngx_errno,
                                  "mkdir [%s] failed", dirname);
                    exit(2);
                }
            }
        }
    }
}
Example #3
0
void ngx_pipe_get_last_rollback_time(ngx_pipe_rollback_conf_t *rbcf)
{
    int             fd;
    struct flock    lock;
    int             ret;

    struct stat     sb;

    fd = ngx_open_file(rbcf->logname, NGX_FILE_RDWR, NGX_FILE_OPEN, 0);
    if (fd < 0) {
        //open lock file failed just use now
        rbcf->last_open_time = rbcf->time_now;
        return;
    }

    lock.l_type     = F_WRLCK;
    lock.l_whence   = SEEK_SET;
    lock.l_start    = 0;
    lock.l_len      = 0;

    ret = fcntl(fd, F_SETLKW, &lock);
    if (ret < 0) {
        close(fd);
        //lock failed just use now
        rbcf->last_open_time = rbcf->time_now;
        return;
    }

    //check time
    if (rbcf->interval > 0) {
        if (ngx_file_info(rbcf->backup[0], &sb) == -1) {
            //no backup file ,so need rollback just set 1
            rbcf->last_open_time = 1;
        } else if (sb.st_ctime / rbcf->interval < ngx_time() / rbcf->interval) {
            //need rollback just set 1
            rbcf->last_open_time = 1;
        } else {
            //just no need rollback
            rbcf->last_open_time = rbcf->time_now;
        }
    } else {
        rbcf->last_open_time = rbcf->time_now;
    }

    close(fd);
}
static ngx_int_t
ngx_http_url_encoding_convert_handler(ngx_http_request_t *r)
{
    u_char                                      *last;
    size_t                                      root;
    ngx_int_t                                   rc;
    ngx_str_t                                   path;
    ngx_file_info_t                             of;
    ngx_http_url_encoding_convert_loc_conf_t    *ulcf;

    ulcf = ngx_http_get_module_loc_conf(r, ngx_http_url_encoding_convert_module);

    if (!ulcf->enable) {
         return NGX_DECLINED;
    }

    /* before rewrite */
    if (r->phase_handler == NGX_HTTP_POST_READ_PHASE && ulcf->phase == NGX_HTTP_PREACCESS_PHASE) {
         return NGX_DECLINED;
    }

    /* after rewrite */
    if (r->phase_handler > NGX_HTTP_POST_READ_PHASE && ulcf->phase == NGX_HTTP_POST_READ_PHASE) {
         return NGX_DECLINED;
    }

    last = ngx_http_map_uri_to_path(r, &path, &root, 0);
    if (last == NULL) {
        return NGX_DECLINED;
    }

    path.len = last - path.data;

    if (ngx_file_info(path.data, &of) == NGX_FILE_ERROR) {
        rc = ngx_http_url_encoding_convert_iconv(r, (const char *)ulcf->from_encode.data, (const char *)ulcf->to_encode.data);

        if (rc == NGX_OK) {
            return rc;
        }
    }

    return NGX_DECLINED;
}
    static ngx_int_t
ngx_http_fsutil_create_dir_if_not_found( ngx_log_t *log, char *path )
{

    ngx_file_info_t fi;
    ngx_int_t rc;

    if ( ngx_file_info( path, &fi ) == NGX_FILE_ERROR ) {
        rc = ngx_create_dir( path, 0700 );
        if ( 0 != rc ) {
            ngx_log_error(NGX_LOG_ERR, log, 0,
                    "creating dir failed:%s", path);
            /* TODO elaborate error */
            return rc;
        }
    }
    else {
        if ( ! ngx_is_dir( &fi ) ) {
            return NGX_ENOTDIR;
        }
        /*
         * if ( ngx_is_dir( &fi ) ) {
         *     return NGX_OK;
         * }
         * else if ( ngx_is_file( &fi ) || ngx_is_link( &fi ) ) {
         *     ngx_log_error(NGX_LOG_ERR, log, 0,
         *             "Normal file or link as path element:%s", path);
         *     [> TODO elaborate error <]
         *     return NGX_ENOTDIR;
         * }
         * else {
         *     [> TODO elaborate error <]
         *     return NGX_ENOTDIR;
         * }
         */
    }

    return NGX_OK;

}
static ngx_inline ngx_str_t
get_readme_path(ngx_http_request_t *r, const ngx_str_t *path)
{
    u_char *last;
    ngx_file_info_t info;
    ngx_str_t fullpath = ngx_null_string;
    ngx_http_fancyindex_loc_conf_t *alcf =
        ngx_http_get_module_loc_conf(r, ngx_http_fancyindex_module);

    if (alcf->readme.len == 0) /* Readme files are disabled */
        return fullpath;

    fullpath.len  = path->len + 2 + alcf->readme.len;
    fullpath.data = ngx_palloc(r->pool, fullpath.len);

    last = ngx_cpymem_str(fullpath.data, *path); *last++ = '/';
    last = ngx_cpymem_str(last, alcf->readme); *last++ = '\0';

    /* File does not exists, or cannot be accessed */
    if (ngx_file_info(fullpath.data, &info) != 0)
        fullpath.len = 0;

    return fullpath;
}
Example #7
0
ngx_int_t
ngx_open_cached_file(ngx_open_file_cache_t *cache, ngx_str_t *name,
    ngx_open_file_info_t *of, ngx_pool_t *pool)
{
    time_t                          now;
    uint32_t                        hash;
    ngx_int_t                       rc;
    ngx_file_info_t                 fi;
    ngx_pool_cleanup_t             *cln;
    ngx_cached_open_file_t         *file;
    ngx_pool_cleanup_file_t        *clnf;
    ngx_open_file_cache_cleanup_t  *ofcln;

    of->fd = NGX_INVALID_FILE;
    of->err = 0;

    if (cache == NULL) {

        if (of->test_only) {

            if (ngx_file_info(name->data, &fi) == NGX_FILE_ERROR) {
                of->err = ngx_errno;
                of->failed = ngx_file_info_n;
                return NGX_ERROR;
            }

            of->uniq = ngx_file_uniq(&fi);
            of->mtime = ngx_file_mtime(&fi);
            of->size = ngx_file_size(&fi);
            of->fs_size = ngx_file_fs_size(&fi);
            of->is_dir = ngx_is_dir(&fi);
            of->is_file = ngx_is_file(&fi);
            of->is_link = ngx_is_link(&fi);
            of->is_exec = ngx_is_exec(&fi);

            return NGX_OK;
        }

        cln = ngx_pool_cleanup_add(pool, sizeof(ngx_pool_cleanup_file_t));
        if (cln == NULL) {
            return NGX_ERROR;
        }

        rc = ngx_open_and_stat_file(name->data, of, pool->log);

        if (rc == NGX_OK && !of->is_dir) {
            cln->handler = ngx_pool_cleanup_file;
            clnf = cln->data;

            clnf->fd = of->fd;
            clnf->name = name->data;
            clnf->log = pool->log;
        }

        return rc;
    }

    cln = ngx_pool_cleanup_add(pool, sizeof(ngx_open_file_cache_cleanup_t));
    if (cln == NULL) {
        return NGX_ERROR;
    }

    now = ngx_time();

    hash = ngx_crc32_long(name->data, name->len);

    file = ngx_open_file_lookup(cache, name, hash);

    if (file) {

        file->uses++;

        ngx_queue_remove(&file->queue);

        if (file->fd == NGX_INVALID_FILE && file->err == 0 && !file->is_dir) {

            /* file was not used often enough to keep open */

            rc = ngx_open_and_stat_file(name->data, of, pool->log);

            if (rc != NGX_OK && (of->err == 0 || !of->errors)) {
                goto failed;
            }

            goto add_event;
        }

        if (file->use_event
            || (file->event == NULL
                && (of->uniq == 0 || of->uniq == file->uniq)
                && now - file->created < of->valid))
        {
            if (file->err == 0) {

                of->fd = file->fd;
                of->uniq = file->uniq;
                of->mtime = file->mtime;
                of->size = file->size;

                of->is_dir = file->is_dir;
                of->is_file = file->is_file;
                of->is_link = file->is_link;
                of->is_exec = file->is_exec;
                of->is_directio = file->is_directio;

                if (!file->is_dir) {
                    file->count++;
                    ngx_open_file_add_event(cache, file, of, pool->log);
                }

            } else {
                of->err = file->err;
                of->failed = ngx_open_file_n;
            }

            goto found;
        }

        ngx_log_debug4(NGX_LOG_DEBUG_CORE, pool->log, 0,
                       "retest open file: %s, fd:%d, c:%d, e:%d",
                       file->name, file->fd, file->count, file->err);

        if (file->is_dir) {

            /*
             * chances that directory became file are very small
             * so test_dir flag allows to use a single syscall
             * in ngx_file_info() instead of three syscalls
             */

            of->test_dir = 1;
        }

        of->fd = file->fd;
        of->uniq = file->uniq;

        rc = ngx_open_and_stat_file(name->data, of, pool->log);

        if (rc != NGX_OK && (of->err == 0 || !of->errors)) {
            goto failed;
        }

        if (of->is_dir) {

            if (file->is_dir || file->err) {
                goto update;
            }

            /* file became directory */

        } else if (of->err == 0) {  /* file */

            if (file->is_dir || file->err) {
                goto add_event;
            }

            if (of->uniq == file->uniq) {

                if (file->event) {
                    file->use_event = 1;
                }

                of->is_directio = file->is_directio;

                goto update;
            }

            /* file was changed */

        } else { /* error to cache */

            if (file->err || file->is_dir) {
                goto update;
            }

            /* file was removed, etc. */
        }

        if (file->count == 0) {

            ngx_open_file_del_event(file);

            if (ngx_close_file(file->fd) == NGX_FILE_ERROR) {
                ngx_log_error(NGX_LOG_ALERT, pool->log, ngx_errno,
                              ngx_close_file_n " \"%s\" failed",
                              name->data);
            }

            goto add_event;
        }

        ngx_rbtree_delete(&cache->rbtree, &file->node);

        cache->current--;

        file->close = 1;

        goto create;
    }

    /* not found */

    rc = ngx_open_and_stat_file(name->data, of, pool->log);

    if (rc != NGX_OK && (of->err == 0 || !of->errors)) {
        goto failed;
    }

create:

    if (cache->current >= cache->max) {
        ngx_expire_old_cached_files(cache, 0, pool->log);
    }

    file = ngx_alloc(sizeof(ngx_cached_open_file_t), pool->log);

    if (file == NULL) {
        goto failed;
    }

    file->name = ngx_alloc(name->len + 1, pool->log);

    if (file->name == NULL) {
        ngx_free(file);
        file = NULL;
        goto failed;
    }

    ngx_cpystrn(file->name, name->data, name->len + 1);

    file->node.key = hash;

    ngx_rbtree_insert(&cache->rbtree, &file->node);

    cache->current++;

    file->uses = 1;
    file->count = 0;
    file->use_event = 0;
    file->event = NULL;

add_event:

    ngx_open_file_add_event(cache, file, of, pool->log);

update:

    file->fd = of->fd;
    file->err = of->err;

    if (of->err == 0) {
        file->uniq = of->uniq;
        file->mtime = of->mtime;
        file->size = of->size;

        file->close = 0;

        file->is_dir = of->is_dir;
        file->is_file = of->is_file;
        file->is_link = of->is_link;
        file->is_exec = of->is_exec;
        file->is_directio = of->is_directio;

        if (!of->is_dir) {
            file->count++;
        }
    }

    file->created = now;

found:

    file->accessed = now;

    ngx_queue_insert_head(&cache->expire_queue, &file->queue);

    ngx_log_debug5(NGX_LOG_DEBUG_CORE, pool->log, 0,
                   "cached open file: %s, fd:%d, c:%d, e:%d, u:%d",
                   file->name, file->fd, file->count, file->err, file->uses);

    if (of->err == 0) {

        if (!of->is_dir) {
            cln->handler = ngx_open_file_cleanup;
            ofcln = cln->data;

            ofcln->cache = cache;
            ofcln->file = file;
            ofcln->min_uses = of->min_uses;
            ofcln->log = pool->log;
        }

        return NGX_OK;
    }

    return NGX_ERROR;

failed:

    if (file) {
        ngx_rbtree_delete(&cache->rbtree, &file->node);

        cache->current--;

        if (file->count == 0) {

            if (file->fd != NGX_INVALID_FILE) {
                if (ngx_close_file(file->fd) == NGX_FILE_ERROR) {
                    ngx_log_error(NGX_LOG_ALERT, pool->log, ngx_errno,
                                  ngx_close_file_n " \"%s\" failed",
                                  file->name);
                }
            }

            ngx_free(file->name);
            ngx_free(file);

        } else {
            file->close = 1;
        }
    }

    if (of->fd != NGX_INVALID_FILE) {
        if (ngx_close_file(of->fd) == NGX_FILE_ERROR) {
            ngx_log_error(NGX_LOG_ALERT, pool->log, ngx_errno,
                          ngx_close_file_n " \"%s\" failed", name->data);
        }
    }

    return NGX_ERROR;
}
static ngx_int_t
ngx_http_lookup_and_send_cache_file(ngx_http_request_t *r,ngx_chain_t *out)
{
    u_char buf[128];
    u_char file_name[128] = "/tmp/image_cache/";
    ngx_buf_t *b;
    ngx_pool_cleanup_t *cln;
    size_t name_len;
    u_char *uri_file_name;
    
    memset(buf,0,128);
    name_len = r->uri_end - r->uri_start;
    memcpy(buf,r->uri_start,name_len);
    uri_file_name = buf + 12;

    strncat((char*)file_name,(char *)uri_file_name,128);

    if(access((char *)file_name,F_OK) == 0) {

        b = ngx_palloc(r->pool, sizeof(ngx_buf_t));
        ngx_memzero(b,sizeof(ngx_buf_t));
        b->in_file = 1;
        b->file = ngx_palloc(r->pool, sizeof(ngx_file_t));
        ngx_memzero(b->file,sizeof(ngx_file_t));
        b->file->fd = ngx_open_file(file_name,NGX_FILE_RDONLY|NGX_FILE_NONBLOCK, NGX_FILE_OPEN, 0);

        b->file->log = r->connection->log;
    
        if(b->file->fd <= 0){
            return NGX_HTTP_NOT_FOUND;
        }

        if(ngx_file_info(file_name,&b->file->info) == NGX_FILE_ERROR){
            ngx_http_finalize_request(r,NGX_HTTP_INTERNAL_SERVER_ERROR);
        }

        if(b->file->info.st_size < 128)
            return NGX_HTTP_NOT_FOUND;
        //r->connection->buffered &= ~NGX_HTTP_IMAGE_BUFFERED;
        r->headers_out.content_length_n = b->file->info.st_size;
        if (r->headers_out.content_length) {
            r->headers_out.content_length->hash = 0;
        }

        r->headers_out.content_length = NULL;

        b->file_pos = 0;
        b->file_last = b->file->info.st_size;
        b->last_buf = 1;

        out->buf = b;
        out->next = NULL;
    
        cln = ngx_pool_cleanup_add(r->pool, sizeof(ngx_pool_cleanup_file_t));
        if(cln == NULL){
            ngx_http_finalize_request(r,NGX_ERROR);
        }
        cln->handler = ngx_pool_cleanup_file;
        ngx_pool_cleanup_file_t *clnf = cln->data;

        clnf->fd = b->file->fd;
        clnf->log = r->pool->log;

        return NGX_OK; 
    }

    return NGX_HTTP_NOT_FOUND;
}
char *
ngx_xconf_include_uri(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
{
    ngx_str_t          *arg, uri, filename, scheme_name;
    ngx_xconf_ctx_t     ctx;
    ngx_flag_t          is_last_elt;
    ngx_uint_t          i;
    ngx_str_t          *cmd_name;
    u_char              need_next;
    ngx_str_t           ofilename_prefix = ngx_string("$file"),
                        ofilename_suffix = ngx_string("l$line.conf"),
                        ofilename_suffix2 = ngx_string("conf");
    char               *rv;
    u_char             *s; /* 用于临时分配内存用 */;
    lua_State          *L;
    ngx_xconf_scheme_t *scheme;


    arg = cf->args->elts;
    cmd_name = &arg[0];

    scheme = ngx_xconf_schemes;
    if ((scheme == NULL) || (scheme->name.len == 0)) {
        ngx_log_error(NGX_LOG_ERR, cf->log, 0,
                "%V: no scheme define.",
                cmd_name);

        return NGX_CONF_ERROR;
    }

    /* 参数说明见 README */

    uri.len = 0;        /* 如果没设定报错 */
    filename.len = 0;   /* 如果没设定就默认给一个 */
    ctx.evaluri = 1;    /* 默认 eval uri */
    ctx.keep_error_cachefile = 0;   /* 默认删除解析出错的 cachefile */
    ctx.pre_usecache = -1;   /* 默认不使用 cachefile */
    ctx.fail_usecache = -1;   /* 默认不使用 cachefile */

    ctx.fetch_content = NULL;
    ctx.do_cachefile = 0;

    need_next = 0;
    is_last_elt = 0;

    /* 解析参数 {{{ */
    for (i = 1; i < cf->args->nelts; i++) {
        if (! (arg[i].len)) {
            continue;
        }

        is_last_elt = i == cf->args->nelts - 1;

        if (need_next) {
            switch(need_next) {
                case 'o':
                    filename.data = arg[i].data;
                    filename.len = arg[i].len;
                    break;
                case 'O':
                    filename.len = ofilename_prefix.len + arg[i].len + ofilename_suffix.len + sizeof("..") - 1;
                    filename.data = ngx_palloc(cf->pool, filename.len + 1);
                    ngx_snprintf(filename.data, filename.len,
                            "%V.%V.%V",
                            &ofilename_prefix, &arg[i], &ofilename_suffix);
                    break;
                case 'I':
                    filename.len = ofilename_prefix.len + arg[i].len + ofilename_suffix2.len + sizeof("..") - 1;
                    filename.data = ngx_palloc(cf->pool, filename.len + 1);
                    ngx_snprintf(filename.data, filename.len,
                            "%V.%V.%V",
                            &ofilename_prefix, &arg[i], &ofilename_suffix2);
                    break;
                case 't':
                    ctx.timeout = ngx_parse_time(&arg[i], 1);
                    if (ctx.timeout == NGX_ERROR) {
                        ngx_log_error(NGX_LOG_ERR, cf->log, 0,
                                "%V: option [-t %V] value error.",
                                cmd_name, &arg[i]);

                        return NGX_CONF_ERROR;
                    }
                    break;
                case 'c':
                    if (arg[i].len == 2 && arg[i].data[0] == '-' && arg[i].data[1] == '1') {
                        ctx.pre_usecache = -1 * (arg[i].data[1] - '0');
                    } else {
                        ctx.pre_usecache = ngx_parse_time(&arg[i], 1);
                        if (ctx.pre_usecache == NGX_ERROR) {
                            ngx_log_error(NGX_LOG_ERR, cf->log, 0,
                                    "%V: option [-c %V] value error.",
                                    cmd_name, &arg[i]);

                            return NGX_CONF_ERROR;
                        }
                    }
                    break;
                case 'C':
                    if (arg[i].len == 2 && arg[i].data[0] == '-' &&
                            (arg[i].data[1] >= '1' && arg[i].data[1] <= '2')) {
                        ctx.fail_usecache = -1 * (arg[i].data[1] - '0');
                    } else {
                        ctx.fail_usecache = ngx_parse_time(&arg[i], 1);
                        if (ctx.fail_usecache == NGX_ERROR) {
                            ngx_log_error(NGX_LOG_ERR, cf->log, 0,
                                    "%V: option [-C %V] value error.",
                                    cmd_name, &arg[i]);

                            return NGX_CONF_ERROR;
                        }
                    }
                    break;
                default:
                    /* 通常不会到这里 */
                    ngx_log_error(NGX_LOG_ERR, cf->log, 0,
                            "%V: unknown option [%c] .",
                            cmd_name, need_next);

                    return NGX_CONF_ERROR;
            }

            need_next = 0;
            continue;
        } else {
            if (arg[i].data[0] == '-') {
                /* 现在只支持 -x */
                if (arg[i].len != 2) {
                    goto unknow_opt;
                }
                switch(arg[i].data[1]) {
                    case 'K':
                        ctx.keep_error_cachefile = 1;
                        break;
                    case 'n':
                        ctx.evaluri = 0;
                        break;
                    case 'c':
                    case 'C':
                    case 'o':
                    case 'I':
                    case 'O':
                    case 't':
                        need_next = arg[i].data[1];

                        if (is_last_elt) {
                            ngx_log_error(NGX_LOG_ERR, cf->log, 0,
                                    "%V: option [-%c] need a value.",
                                    cmd_name, need_next);

                            return NGX_CONF_ERROR;
                        }

                        break;
                    default:
                        goto unknow_opt;
                }

                continue;
            } else { /* this will be the uri */
                uri.data = arg[i].data;
                uri.len = arg[i].len;

                continue;
            }
        }

        goto unknow_opt;
    }
    /* }}} */

    /* 因为上面不需要用到 lua 的功能,所有此刻才初始化 lua vm {{{ */
    L = luaL_newstate();

    if (L == NULL) {
        ngx_log_error(NGX_LOG_ERR, cf->log, 0,
                "%V: create lua vm fail.",
                cmd_name);

        return NGX_CONF_ERROR;
    }

    /* XXX 从这以下如果出错,需要 goto error; 因为要 close lua vm */

    ctx.lua = L;

    luaL_openlibs(L);
    {
        int         rc;
        ngx_str_t   msg;

        rc = luaL_loadbuffer(L, (const char*) xconf_util_lua, sizeof(xconf_util_lua), "ngx_xconf_util.lua(embed)");
        if (rc != 0) {
            msg.data = (u_char *) lua_tolstring(L, -1, &msg.len);

            if (msg.data == NULL) {
                msg.data = (u_char *) "unknown reason";
                msg.len = sizeof("unknown reason") - 1;
            }

            ngx_log_error(NGX_LOG_ERR, cf->log, 0,
                    "xconf load lua code error: %V.",
                    &msg);

            lua_pop(L, 1);

            rv = NULL;
            goto error;
        }
    }
    /* 这个 lua 文件会创建 若干个 全局函数,如: format */

    if (ngx_xconf_util_lua_pcall(cf, L, 0, 0, 0, 0) != NGX_OK) {
        rv = NULL;
        goto error;
    }
    /* }}} */

    /* 创建变量 table 到 lua vm (var_ctx) 里,用于变量插值 {{{ */
    lua_createtable(L, /* i */0, /* key */10); /* var_ctx */
    lua_pushlstring(L, (char *)cf->conf_file->file.name.data, cf->conf_file->file.name.len);
    lua_setfield(L, -2, "file");
    lua_pushnumber(L, cf->conf_file->line);
    lua_setfield(L, -2, "line");
    lua_pushlstring(L, (char *)cf->cycle->prefix.data, cf->cycle->prefix.len);
    lua_setfield(L, -2, "prefix");
    lua_pushlstring(L, (char *)cf->cycle->conf_prefix.data, cf->cycle->conf_prefix.len);
    lua_setfield(L, -2, "conf_prefix");
    lua_pushnumber(L, (int) ngx_pid);
    lua_setfield(L, -2, "pid");
    lua_pushlstring(L, (char *)cf->cycle->hostname.data, cf->cycle->hostname.len);
    lua_setfield(L, -2, "hostname");
    {
        ngx_time_t *tp = ngx_timeofday();

        lua_pushnumber(L, (int) (tp->sec));
        lua_setfield(L, -2, "time"); /* var_ctx */
    }

    lua_setfield(L, LUA_GLOBALSINDEX, "var_ctx");
    /* }}} */

    /* 对 uri 进行变量插值 {{{ */
    if (ctx.evaluri) {
        lua_getfield(L, LUA_GLOBALSINDEX, "format"); /* got the format function */
        lua_pushlstring(L, (char *) uri.data, uri.len);
        if (ngx_xconf_util_lua_pcall(cf, L, 1, 1, 0, 0) != NGX_OK) {
            rv = NULL;
            goto error;
        }
        uri.data = (u_char *) lua_tolstring(L, -1, &uri.len);
        s = ngx_palloc(cf->pool, uri.len);
        ngx_memcpy(s, uri.data, uri.len);
        uri.data = s;
        s = NULL;
        lua_pop(L, 1);
    }

    if (! (uri.len)) {
        ngx_log_error(NGX_LOG_ERR, cf->log, 0,
                "%V: must give us uri.",
                cmd_name);

        rv = NULL;
        goto error;
    }

    ctx.uri.len = uri.len;
    ctx.uri.data = uri.data;
    /* }}} */

    /* 计算 uri 的 scheme_name {{{ */
    /* 如果以 '//' 开头 认为是 http: */
    if (uri.len > 2 && uri.data[0] == '/' && uri.data[1] == '/') {
        ctx.noscheme_uri.data = uri.data;
        ctx.noscheme_uri.len = uri.len;

        scheme_name.len = sizeof("http") - 1;
        scheme_name.data = ngx_palloc(cf->pool, scheme_name.len + 1);
        ngx_cpystrn(scheme_name.data, (u_char *)"http", scheme_name.len + 1);
    /* 如果以 '/' 或 './' 开头 认为是 file: */
    } else if (uri.data[0] == '/'
            || (uri.len > 2 && uri.data[0] == '.' && uri.data[1] == '/')) {

        size_t is_abs = uri.data[0] == '/';
        u_char *data = uri.data + (is_abs ? 0 : 2);
        size_t len = uri.len - (is_abs ? 0 : 2);

        ctx.noscheme_uri.len = len + 2;
        ctx.noscheme_uri.data = ngx_palloc(cf->pool, len + 2 + 1);
        ctx.noscheme_uri.data[0] = '/';
        ctx.noscheme_uri.data[1] = '/';
        ngx_cpystrn(ctx.noscheme_uri.data + 2, data, len + 1);

        scheme_name.len = sizeof("file") - 1;
        scheme_name.data = ngx_palloc(cf->pool, scheme_name.len + 1);
        ngx_cpystrn(scheme_name.data, (u_char *)"file", scheme_name.len + 1);
    } else {
        u_char      c;
        ngx_str_t   tmp_scheme;
        size_t      i, maxi, found;

        /* find scheme: [a-z_][a-z_0-9+.-]: , max_scheme_len */
        tmp_scheme.data = ngx_palloc(cf->pool, max_scheme_len);
        tmp_scheme.len = 0;
        i = 0;
        maxi = uri.len - 1;
        found = 0;

        while (i < max_scheme_len && i <= maxi) {
            c = uri.data[i];

            if (c == ':') {
                found = 1;
                break;
            }

            tmp_scheme.data[i] = c;
            tmp_scheme.len++;
            if ((c >= 'a' && c <= 'z')
                    || (c >= 'A' && c <= 'Z')
                    || (c >= '0' && c <= '9')
                    || c == '+' || c == '-' || c == '.') {
            } else {
                ngx_log_error(NGX_LOG_ERR, cf->log, 0,
                        "%V: uri (%V...) have no valid scheme name.",
                        cmd_name, &tmp_scheme);

                rv = NULL;
                goto error;
            }

            /* XXX important */
            i++;
        }

        if (! (found && tmp_scheme.len)) {
            ngx_log_error(NGX_LOG_ERR, cf->log, 0,
                    "%V: uri (%V) have no valid scheme name.",
                    cmd_name, &uri);

            rv = NULL;
            goto error;
        }

        scheme_name.len = tmp_scheme.len;
        scheme_name.data = tmp_scheme.data;
        scheme_name.data[tmp_scheme.len] = '\0';

        /* 1 -> the ':' after scheme name */
        ctx.noscheme_uri.len = uri.len - tmp_scheme.len - 1;
        ctx.noscheme_uri.data = uri.data + tmp_scheme.len + 1;
    }
    /* }}} */

    /* 查找当前 scheme {{{ */
    for ( /* void */ ; scheme->name.len; scheme++) {
        if (scheme_name.len == scheme->name.len &&
                ngx_strcmp(scheme_name.data, scheme->name.data) == 0) {
            break;
        }
    }

    if (! scheme->name.len) {
        ngx_log_error(NGX_LOG_ERR, cf->log, 0,
                "%V: no scheme found for \"%V\".",
                cmd_name, &ctx.scheme);

        rv = NULL;
        goto error;
    }
    /* }}} */

    ctx.scheme = scheme;

    /* 如果 scheme usecache 则计算 filename 并 判断 pre_usecache {{{ */
    if (scheme->usecache) {
        /* filename 计算, 插值, 展开 {{{ */
        if (! (filename.len)) {
            filename.len = ofilename_prefix.len + ofilename_suffix.len + sizeof(".") - 1;
            filename.data = ngx_palloc(cf->pool, filename.len + 1);
            ngx_snprintf(filename.data, filename.len,
                    "%V.%V",
                    &ofilename_prefix, &ofilename_suffix);
        }

        /* FIXME filename.data 是否需要 free ?? */
        lua_getfield(L, LUA_GLOBALSINDEX, "format"); /* got the format function */
        lua_pushlstring(L, (char *) filename.data, filename.len);
        if (ngx_xconf_util_lua_pcall(cf, L, 1, 1, 0, 0) != NGX_OK) {
            rv = NULL;
            goto error;
        }
        filename.data = (u_char *) lua_tolstring(L, -1, &filename.len);
        s = ngx_palloc(cf->pool, filename.len + 1);
        ngx_cpystrn(s, filename.data, filename.len + 1); /* 让 ngx_cpystrn 帮忙添加个 \0 */
        filename.data = s;
        s = NULL;
        lua_pop(L, 1);

        if (ngx_conf_full_name(cf->cycle, &filename, 1) != NGX_OK) {
            rv = NULL;
            goto error;
        }
        /* }}} */

        ctx.cachefile = ngx_palloc(cf->pool, sizeof(ngx_file_t));
        if (ctx.cachefile == NULL) {
            ngx_log_error(NGX_LOG_ERR, cf->log, 0,
                    "%V: alloc cachefile error.",
                    cmd_name);

            rv = NULL;
            goto error;
        }
        ngx_memzero(ctx.cachefile, sizeof(ngx_file_t));

        ctx.cachefile->name = filename;
        ctx.cachefile->log = cf->log;

        dd("pre-usecache: %d, %d", (int)ctx.scheme->pre_usecache, (int)ctx.pre_usecache);
        if (ctx.scheme->pre_usecache && ctx.pre_usecache > -1) {
            ngx_file_t  *file;

            file = ctx.cachefile;

            /* 获取文件信息 FAIL */
            if (ngx_file_info(file->name.data, &file->info) == -1) {
                /* 如果文件不存在则忽略,否则报错 */
                if (errno != ENOENT) {
                    ngx_log_error(NGX_LOG_ERR, cf->log, 0,
                            "%V: get file \"%V\" info error: %s.",
                            cmd_name, file->name, strerror(errno));

                    rv = NULL;
                    goto error;
                }
            /* 获取文件信息 OK, 有没可能是个 目录 ?? ,如果谁这么配置 !!! */
            } else {
                int     now;

                /* 只要文件存在就用 */
                if (ctx.pre_usecache == 0) {
                    goto do_cachefile;
                }

                ngx_time_update();
                now = (int)ngx_time();

                dd("pre-usecache now: %d, mtime: %d, diff: %d, pref: %d.",
                        now, (int)file->info.st_mtime, now - (int)file->info.st_mtime, (int)ctx.pre_usecache);

                if (now - file->info.st_mtime <= ctx.pre_usecache) {
                    goto do_cachefile;
                }
            }
        }
    }
    /* }}} */

    ngx_log_error(NGX_LOG_INFO, cf->log, 0,
            "\n- - - - - - - -\ncmd_name: %V\nfileneme: %V\nuri: %V\npre_usecache: %d\nfail_usecache: %d\nevaluri: %d\nscheme: %V\nnoscheme_uri: %V\n- - - - - - - -",
            cmd_name, &filename, &uri, ctx.pre_usecache, ctx.fail_usecache, ctx.evaluri, &ctx.scheme->name, &ctx.noscheme_uri);

    /* 执行具体 scheme {{{ */
    rv = scheme->handler(cf, cmd, conf, &ctx);

    if (rv == NGX_CONF_OK) {
        goto done;
    } else if (rv == NGX_XCONF_FETCH_ERROR) {
        /* do fail_usecache */
        if (scheme->usecache) {
            goto fetch_fail;
        } else {
            /* 不可能 */
            ngx_log_error(NGX_LOG_ERR, cf->log, 0,
                    "if you see this error, please report it to author with \"%V\".",
                    &scheme->name);

            rv = NULL;
            goto error;
        }
    } else if (rv == NGX_XCONF_FETCH_OK) {
        if (scheme->usecache) {
            if (ctx.fetch_content != NULL) {
                goto save_cachefile;
            } else if (ctx.do_cachefile) {
                goto do_cachefile;
            }
        }

        goto done;
    } else {
        goto error;
    }
    /* }}} */

    goto done;

fetch_fail:
    dd("fail-usecache: %d, %d", (int)ctx.scheme->fail_usecache, (int)ctx.fail_usecache);

    if (ctx.scheme->fail_usecache && ctx.fail_usecache != -1) {
        /* 删除 */
        if (ctx.fail_usecache != -2) {
            ngx_delete_file(ctx.cachefile->name.data);

            rv = NULL;
            goto error;

        } else if (ctx.fail_usecache >= 0) {
            ngx_file_t  *file;

            file = ctx.cachefile;

            /* 获取文件信息 FAIL */
            if (ngx_file_info(file->name.data, &file->info) == -1) {
                ngx_log_error(NGX_LOG_ERR, cf->log, 0,
                        "%V: get file \"%V\" info in fetch_fail error: %s.",
                        cmd_name, file->name, strerror(errno));

                rv = NULL;
                goto error;
            /* 获取文件信息 OK, 有没可能是个 目录 ?? ,如果谁这么配置 !!! */
            } else {
                int     now;

                /* 只要文件存在就用 */
                if (ctx.fail_usecache == 0) {
                    goto do_cachefile;
                }

                ngx_time_update();
                now = (int)ngx_time();

                dd("fail-usecache now: %d, mtime: %d, diff: %d, pref: %d.",
                        now, (int)file->info.st_mtime, now - (int)file->info.st_mtime, (int)ctx.fail_usecache);

                if (now - file->info.st_mtime <= ctx.fail_usecache) {
                    goto do_cachefile;
                }
            }
        } else {
            /* 不可能 */

            rv = NULL;
            goto error;
        }
    }

    rv = NULL;
    goto error;

save_cachefile:
    {
        int rc;

        ctx.cachefile->fd = ngx_open_file(ctx.cachefile->name.data, O_WRONLY, O_CREAT | O_TRUNC , S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH);

        if (ctx.cachefile->fd == NGX_INVALID_FILE) {
            ngx_log_error(NGX_LOG_ERR, cf->log, 0,
                    "%V: open (%V) error: \"%s\".",
                    cmd_name, &ctx.cachefile->name, strerror(errno));

            rv = NULL;
            goto error;
        }

        dd("open cachefd: %s, %d", (char *)ctx.cachefile->name.data, ctx.cachefile->fd);

        rc = ngx_write_fd(ctx.cachefile->fd, ctx.fetch_content->data, ctx.fetch_content->len);
        if (rc == NGX_FILE_ERROR) {
            ngx_log_error(NGX_LOG_ERR, cf->log, 0,
                    "%V: write data to (%V) error: \"%s\".",
                    cmd_name, ctx.cachefile->name, strerror(errno));

            rv = NULL;
            goto error;
        } else if ((size_t)rc != ctx.fetch_content->len) {
            ngx_log_error(NGX_LOG_ERR, cf->log, 0,
                    "%V: write data to (%V) incomplete: %z of %uz.",
                    cmd_name, ctx.cachefile->name, rc, ctx.fetch_content->len);

            rv = NULL;
            goto error;
        }

        if (ngx_close_file(ctx.cachefile->fd) == NGX_FILE_ERROR) {
            ngx_log_error(NGX_LOG_ERR, cf->log, 0,
                    "%: close cachefile error.",
                    cmd_name);

            rv = NULL;
            goto error;
        }

        goto do_cachefile;
    }

do_cachefile:
    if (! scheme->usecache) {
        ngx_log_error(NGX_LOG_ERR, cf->log, 0,
                "%V: current scheme \"%V\" can not usecache.",
                cmd_name, &scheme->name);

        rv = NULL;
        goto error;
    }

    dd("do cachefile");
    rv = ngx_conf_parse(cf, &ctx.cachefile->name);

    if (rv != NGX_CONF_OK) {
        ngx_log_error(NGX_LOG_WARN, cf->log, 0,
                "%V: do cachefile \"%V\" error.",
                cmd_name, &ctx.cachefile->name);

        /* 删除解析出错的 cachefile */
        if (! ctx.keep_error_cachefile) {
            if (ngx_delete_file(ctx.cachefile->name.data) == NGX_FILE_ERROR) {
                    ngx_log_error(NGX_LOG_WARN, cf->log, 0,
                            "%V: delete cachefile \"%V\" error.",
                            cmd_name, &ctx.cachefile->name);
            }
        }

        goto error;
    }

    goto done;

done:
    lua_close(L);

    return NGX_CONF_OK;

unknow_opt:
    ngx_log_error(NGX_LOG_ERR, cf->log, 0,
            "%V: unknown option [%V].",
            cmd_name, &arg[i]);

    return NGX_CONF_ERROR;

error:
    lua_close(L);

    return rv == NULL ? NGX_CONF_ERROR : rv;
}
static ngx_int_t
ngx_rtmp_dash_ensure_directory(ngx_rtmp_session_t *s)
{
    size_t                     len;
    ngx_file_info_t            fi;
    ngx_rtmp_dash_ctx_t       *ctx;
    ngx_rtmp_dash_app_conf_t  *dacf;

    static u_char              path[NGX_MAX_PATH + 1];

    dacf = ngx_rtmp_get_module_app_conf(s, ngx_rtmp_dash_module);

    *ngx_snprintf(path, sizeof(path) - 1, "%V", &dacf->path) = 0;

    if (ngx_file_info(path, &fi) == NGX_FILE_ERROR) {

        if (ngx_errno != NGX_ENOENT) {
            ngx_log_error(NGX_LOG_ERR, s->connection->log, ngx_errno,
                          "dash: " ngx_file_info_n " failed on '%V'",
                          &dacf->path);
            return NGX_ERROR;
        }

        /* ENOENT */

        if (ngx_create_dir(path, NGX_RTMP_DASH_DIR_ACCESS) == NGX_FILE_ERROR) {
            ngx_log_error(NGX_LOG_ERR, s->connection->log, ngx_errno,
                          "dash: " ngx_create_dir_n " failed on '%V'",
                          &dacf->path);
            return NGX_ERROR;
        }

        ngx_log_debug1(NGX_LOG_DEBUG_RTMP, s->connection->log, 0,
                       "dash: directory '%V' created", &dacf->path);

    } else {

        if (!ngx_is_dir(&fi)) {
            ngx_log_error(NGX_LOG_ERR, s->connection->log, 0,
                          "dash: '%V' exists and is not a directory",
                          &dacf->path);
            return  NGX_ERROR;
        }

        ngx_log_debug1(NGX_LOG_DEBUG_RTMP, s->connection->log, 0,
                       "dash: directory '%V' exists", &dacf->path);
    }

    if (!dacf->nested) {
        return NGX_OK;
    }

    ctx = ngx_rtmp_get_module_ctx(s, ngx_rtmp_dash_module);

    len = dacf->path.len;
    if (dacf->path.data[len - 1] == '/') {
        len--;
    }

    *ngx_snprintf(path, sizeof(path) - 1, "%*s/%V", len, dacf->path.data,
                  &ctx->name) = 0;

    if (ngx_file_info(path, &fi) != NGX_FILE_ERROR) {

        if (ngx_is_dir(&fi)) {
            ngx_log_debug1(NGX_LOG_DEBUG_RTMP, s->connection->log, 0,
                           "dash: directory '%s' exists", path);
            return NGX_OK;
        }

        ngx_log_error(NGX_LOG_ERR, s->connection->log, 0,
                      "dash: '%s' exists and is not a directory", path);

        return  NGX_ERROR;
    }

    if (ngx_errno != NGX_ENOENT) {
        ngx_log_error(NGX_LOG_ERR, s->connection->log, ngx_errno,
                      "dash: " ngx_file_info_n " failed on '%s'", path);
        return NGX_ERROR;
    }

    /* NGX_ENOENT */

    if (ngx_create_dir(path, NGX_RTMP_DASH_DIR_ACCESS) == NGX_FILE_ERROR) {
        ngx_log_error(NGX_LOG_ERR, s->connection->log, ngx_errno,
                      "dash: " ngx_create_dir_n " failed on '%s'", path);
        return NGX_ERROR;
    }

    ngx_log_debug1(NGX_LOG_DEBUG_RTMP, s->connection->log, 0,
                   "dash: directory '%s' created", path);

    return NGX_OK;
}
static void
ngx_rtmp_auto_push_reconnect(ngx_event_t *ev)
{
    ngx_rtmp_session_t             *s = ev->data;

    ngx_rtmp_auto_push_conf_t      *apcf;
    ngx_rtmp_auto_push_ctx_t       *ctx;
    ngx_int_t                      *slot;
    ngx_int_t                       n;
    ngx_rtmp_relay_target_t         at;
    u_char                          path[sizeof("unix:") + NGX_MAX_PATH];
    u_char                          flash_ver[sizeof("APSH ,") +
                                              NGX_INT_T_LEN * 2];
    u_char                          play_path[NGX_RTMP_MAX_NAME];
    ngx_str_t                       name;
    u_char                         *p;
    ngx_str_t                      *u;
    ngx_pid_t                       pid;
    ngx_int_t                       npushed;
    ngx_core_conf_t                *ccf;
    ngx_file_info_t                 fi;

    ngx_log_debug0(NGX_LOG_DEBUG_RTMP, s->connection->log, 0,
                   "auto_push: reconnect");

    apcf = (ngx_rtmp_auto_push_conf_t *) ngx_get_conf(ngx_cycle->conf_ctx,
                                                    ngx_rtmp_auto_push_module);
    ctx = ngx_rtmp_get_module_ctx(s, ngx_rtmp_auto_push_module);
    if (ctx == NULL) {
        return;
    }

    name.data = ctx->name;
    name.len = ngx_strlen(name.data);

    ngx_memzero(&at, sizeof(at));
    ngx_str_set(&at.page_url, "nginx-auto-push");
    at.tag = &ngx_rtmp_auto_push_module;

    if (ctx->args[0]) {
        at.play_path.data = play_path;
        at.play_path.len = ngx_snprintf(play_path, sizeof(play_path),
                                        "%s?%s", ctx->name, ctx->args) -
                           play_path;
    }

    slot = ctx->slots;
    npushed = 0;

    for (n = 0; n < NGX_MAX_PROCESSES; ++n, ++slot) {
        if (n == ngx_process_slot) {
            continue;
        }

        pid = ngx_processes[n].pid;
        if (pid == 0 || pid == NGX_INVALID_PID) {
            continue;
        }

        if (*slot) {
            npushed++;
            continue;
        }

        at.data = &ngx_processes[n];

        ngx_memzero(&at.url, sizeof(at.url));
        u = &at.url.url;
        p = ngx_snprintf(path, sizeof(path) - 1,
                         "unix:%V/" NGX_RTMP_AUTO_PUSH_SOCKNAME ".%i",
                         &apcf->socket_dir, n);
        *p = 0;

        if (ngx_file_info(path + sizeof("unix:") - 1, &fi) != NGX_OK) {
            ngx_log_debug5(NGX_LOG_DEBUG_RTMP, s->connection->log, 0,
                           "auto_push: " ngx_file_info_n " failed: "
                           "slot=%i pid=%P socket='%s'" "url='%V' name='%s'",
                           n, pid, path, u, ctx->name);
            continue;
        }

        u->data = path;
        u->len = p - path;
        if (ngx_parse_url(s->connection->pool, &at.url) != NGX_OK) {
            ngx_log_error(NGX_LOG_ERR, s->connection->log, 0,
                          "auto_push: auto-push parse_url failed "
                          "url='%V' name='%s'",
                          u, ctx->name);
            continue;
        }

        p = ngx_snprintf(flash_ver, sizeof(flash_ver) - 1, "APSH %i,%i",
                         (ngx_int_t) ngx_process_slot, (ngx_int_t) ngx_pid);
        at.flash_ver.data = flash_ver;
        at.flash_ver.len = p - flash_ver;

        ngx_log_debug4(NGX_LOG_DEBUG_RTMP, s->connection->log, 0,
                       "auto_push: connect slot=%i pid=%P socket='%s' name='%s'",
                       n, pid, path, ctx->name);

        if (ngx_rtmp_relay_push(s, &name, &at) == NGX_OK) {
            *slot = 1;
            npushed++;
            continue;
        }

        ngx_log_debug5(NGX_LOG_DEBUG_RTMP, s->connection->log, 0,
                      "auto_push: connect failed: slot=%i pid=%P socket='%s'"
                      "url='%V' name='%s'",
                      n, pid, path, u, ctx->name);
    }

    ccf = (ngx_core_conf_t *) ngx_get_conf(ngx_cycle->conf_ctx,
                                           ngx_core_module);

    ngx_log_debug3(NGX_LOG_DEBUG_RTMP, s->connection->log, 0,
                   "auto_push: pushed=%i total=%i failed=%i",
                   npushed, ccf->worker_processes,
                   ccf->worker_processes - 1 - npushed);

    if (ccf->worker_processes == npushed + 1) {
        return;
    }

    /* several workers failed */

    slot = ctx->slots;

    for (n = 0; n < NGX_MAX_PROCESSES; ++n, ++slot) {
        pid = ngx_processes[n].pid;

        if (n == ngx_process_slot || *slot == 1 ||
            pid == 0 || pid == NGX_INVALID_PID)
        {
            continue;
        }

        ngx_log_error(NGX_LOG_ERR, s->connection->log, 0,
                      "auto_push: connect failed: slot=%i pid=%P name='%s'",
                      n, pid, ctx->name);
    }

    if (!ctx->push_evt.timer_set) {
        ngx_add_timer(&ctx->push_evt, apcf->push_reconnect);
    }
}
static ngx_int_t
ngx_http_dav_copy_move_handler(ngx_http_request_t *r)
{
    u_char                   *p, *host, *last, ch;
    size_t                    len, root;
    ngx_err_t                 err;
    ngx_int_t                 rc, depth;
    ngx_uint_t                overwrite, slash, dir;
    ngx_str_t                 path, uri;
    ngx_tree_ctx_t            tree;
    ngx_copy_file_t           cf;
    ngx_file_info_t           fi;
    ngx_table_elt_t          *dest, *over;
    ngx_ext_rename_file_t     ext;
    ngx_http_dav_copy_ctx_t   copy;
    ngx_http_dav_loc_conf_t  *dlcf;

    if (r->headers_in.content_length_n > 0) {
        return NGX_HTTP_UNSUPPORTED_MEDIA_TYPE;
    }

    dest = r->headers_in.destination;

    if (dest == NULL) {
        ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
                      "client sent no \"Destination\" header");
        return NGX_HTTP_BAD_REQUEST;
    }

    len = r->headers_in.server.len;

    if (len == 0) {
        ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
                      "client sent no \"Host\" header");
        return NGX_HTTP_BAD_REQUEST;
    }

#if (NGX_HTTP_SSL)

    if (r->connection->ssl) {
        if (ngx_strncmp(dest->value.data, "https://", sizeof("https://") - 1)
            != 0)
        {
            goto invalid_destination;
        }

        host = dest->value.data + sizeof("https://") - 1;

    } else
#endif
    {
        if (ngx_strncmp(dest->value.data, "http://", sizeof("http://") - 1)
            != 0)
        {
            goto invalid_destination;
        }

        host = dest->value.data + sizeof("http://") - 1;
    }

    if (ngx_strncmp(host, r->headers_in.server.data, len) != 0) {
        ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
                      "\"Destination\" URI \"%V\" is handled by "
                      "different repository than the source URI",
                      &dest->value);
        return NGX_HTTP_BAD_REQUEST;
    }

    last = dest->value.data + dest->value.len;

    for (p = host + len; p < last; p++) {
        if (*p == '/') {
            goto destination_done;
        }
    }

invalid_destination:

    ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
                  "client sent invalid \"Destination\" header: \"%V\"",
                  &dest->value);
    return NGX_HTTP_BAD_REQUEST;

destination_done:

    if ((r->uri.data[r->uri.len - 1] == '/' && *(last - 1) != '/')
        || (r->uri.data[r->uri.len - 1] != '/' && *(last - 1) == '/'))
    {
         ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
                       "both URI \"%V\" and \"Destination\" URI \"%V\" "
                       "should be either collections or non-collections",
                       &r->uri, &dest->value);
         return NGX_HTTP_CONFLICT;
    }

    depth = ngx_http_dav_depth(r, NGX_HTTP_DAV_INFINITY_DEPTH);

    if (depth != NGX_HTTP_DAV_INFINITY_DEPTH) {

        if (r->method == NGX_HTTP_COPY) {
            if (depth != 0) {
                ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
                              "\"Depth\" header must be 0 or infinity");
                return NGX_HTTP_BAD_REQUEST;
            }

        } else {
            ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
                          "\"Depth\" header must be infinity");
            return NGX_HTTP_BAD_REQUEST;
        }
    }

    over = r->headers_in.overwrite;

    if (over) {
        if (over->value.len == 1) {
            ch = over->value.data[0];

            if (ch == 'T' || ch == 't') {
                overwrite = 1;
                goto overwrite_done;
            }

            if (ch == 'F' || ch == 'f') {
                overwrite = 0;
                goto overwrite_done;
            }

        }

        ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
                      "client sent invalid \"Overwrite\" header: \"%V\"",
                      &over->value);
        return NGX_HTTP_BAD_REQUEST;
    }

    overwrite = 1;

overwrite_done:

    ngx_http_map_uri_to_path(r, &path, &root, 0);

    ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
                   "http copy from: \"%s\"", path.data);

    uri = r->uri;

    r->uri.len = last - p;
    r->uri.data = p;

    ngx_http_map_uri_to_path(r, &copy.path, &root, 0);

    r->uri = uri;

    copy.path.len--;  /* omit "\0" */

    if (copy.path.data[copy.path.len - 1] == '/') {
        slash = 1;
        copy.path.len--;
        copy.path.data[copy.path.len] = '\0';

    } else {
        slash = 0;
    }

    ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
                   "http copy to: \"%s\"", copy.path.data);

    if (ngx_file_info(copy.path.data, &fi) == NGX_FILE_ERROR) {
        err = ngx_errno;

        if (err != NGX_ENOENT) {
            return ngx_http_dav_error(r->connection->log, err,
                                      NGX_HTTP_NOT_FOUND, ngx_file_info_n,
                                      copy.path.data);
        }

        /* destination does not exist */

        overwrite = 0;
        dir = 0;

    } else {

        /* destination exists */

        if (ngx_is_dir(&fi) && !slash) {
            ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
                          "\"%V\" could not be %Ved to collection \"%V\"",
                          &r->uri, &r->method_name, &dest->value);
            return NGX_HTTP_CONFLICT;
        }

        if (!overwrite) {
            ngx_log_error(NGX_LOG_ERR, r->connection->log, NGX_EEXIST,
                          "\"%s\" could not be created", copy.path.data);
            return NGX_HTTP_PRECONDITION_FAILED;
        }

        dir = ngx_is_dir(&fi);
    }

    if (ngx_file_info(path.data, &fi) == NGX_FILE_ERROR) {
        return ngx_http_dav_error(r->connection->log, ngx_errno,
                                  NGX_HTTP_NOT_FOUND, ngx_file_info_n,
                                  path.data);
    }

    if (ngx_is_dir(&fi)) {

        if (r->uri.data[r->uri.len - 1] != '/') {
            ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
                          "\"%V\" is collection", &r->uri);
            return NGX_HTTP_BAD_REQUEST;
        }

        if (overwrite) {
            ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
                           "http delete: \"%s\"", copy.path.data);

            rc = ngx_http_dav_delete_path(r, &copy.path, dir);

            if (rc != NGX_OK) {
                return rc;
            }
        }
    }

    if (ngx_is_dir(&fi)) {

        path.len -= 2;  /* omit "/\0" */

        if (r->method == NGX_HTTP_MOVE) {
            if (ngx_rename_file(path.data, copy.path.data) != NGX_FILE_ERROR) {
                return NGX_HTTP_CREATED;
            }
        }

        if (ngx_create_dir(copy.path.data, ngx_file_access(&fi))
            == NGX_FILE_ERROR)
        {
            return ngx_http_dav_error(r->connection->log, ngx_errno,
                                      NGX_HTTP_NOT_FOUND,
                                      ngx_create_dir_n, copy.path.data);
        }

        copy.len = path.len;

        tree.init_handler = NULL;
        tree.file_handler = ngx_http_dav_copy_tree_file;
        tree.pre_tree_handler = ngx_http_dav_copy_dir;
        tree.post_tree_handler = ngx_http_dav_copy_dir_time;
        tree.spec_handler = ngx_http_dav_noop;
        tree.data = &copy;
        tree.alloc = 0;
        tree.log = r->connection->log;

        if (ngx_walk_tree(&tree, &path) == NGX_OK) {

            if (r->method == NGX_HTTP_MOVE) {
                rc = ngx_http_dav_delete_path(r, &path, 1);

                if (rc != NGX_OK) {
                    return rc;
                }
            }

            return NGX_HTTP_CREATED;
        }

    } else {

        if (r->method == NGX_HTTP_MOVE) {

            dlcf = ngx_http_get_module_loc_conf(r, ngx_http_dav_module);

            ext.access = 0;
            ext.path_access = dlcf->access;
            ext.time = -1;
            ext.create_path = 1;
            ext.delete_file = 0;
            ext.log = r->connection->log;

            if (ngx_ext_rename_file(&path, &copy.path, &ext) == NGX_OK) {
                return NGX_HTTP_NO_CONTENT;
            }

            return NGX_HTTP_INTERNAL_SERVER_ERROR;
        }

        dlcf = ngx_http_get_module_loc_conf(r, ngx_http_dav_module);

        cf.size = ngx_file_size(&fi);
        cf.buf_size = 0;
        cf.access = dlcf->access;
        cf.time = ngx_file_mtime(&fi);
        cf.log = r->connection->log;

        if (ngx_copy_file(path.data, copy.path.data, &cf) == NGX_OK) {
            return NGX_HTTP_NO_CONTENT;
        }
    }

    return NGX_HTTP_INTERNAL_SERVER_ERROR;
}
static ngx_int_t ngx_hls_handler(ngx_http_request_t *r)
{
    //ngx_log_t *log = r->connection->log;
	
	if(!(r->method & (NGX_HTTP_GET|NGX_HTTP_HEAD))){
		return NGX_HTTP_NOT_ALLOWED;
	}
	ngx_http_hls_loc_conf_t *elcf = ngx_http_get_module_loc_conf(r,ngx_http_hls_module);

	char* media_type = ngx_http_hls_convert_string(elcf->media_type);
	char* media_path = ngx_http_hls_convert_string(elcf->media_path);
	//char *media_type = (char*)elcf->media_type.data;
	//char *media_path = (char*)elcf->media_path.data;
	ngx_int_t rc = ngx_http_discard_request_body(r);
	if(rc != NGX_OK){
		return rc;
	}

	if(strcmp(media_type,"live") == 0){
		//TODO:Live media.
	}
	else{
		ngx_str_t media_file;
		ngx_str_t media_start;
		ngx_str_t media_end;
		ngx_http_arg(r, (u_char *)"media", 5, &media_file);

		rc = ngx_http_arg(r,(u_char *)"start",5,&media_start);

		ngx_http_arg(r, (u_char *)"end", 3 , &media_end);

		if(rc == NGX_DECLINED || media_start.len == 0){
			char filename[512];
			bzero(filename,512);
			ngx_str_t type = ngx_string("application/x-mpegURL");//m3u8文件的content type
			ngx_snprintf((u_char*)filename,1024,"%s%V.m3u8",media_path,&media_file);
			
			//M3U8文件不存在,目前采用直接返回错误的方式,后期采用根据TS文件创建新的M3U8
			if(access((char*)filename,F_OK) == -1){
				ngx_log_error(NGX_LOG_CRIT,r->connection->log,0,"File[%s] is not exist!media_path = %s,media_file=%V",filename,media_path,&media_file);
				//r->headers_out.status = NGX_HTTP_NOT_FOUND;
				//rc = ngx_http_send_header(r);
				return NGX_HTTP_NOT_FOUND;	
			}
			else{
				ngx_chain_t *out = ngx_pcalloc(r->pool,sizeof(ngx_chain_t));
				ngx_buf_t *b;
				//b = ngx_create_temp_buf(r->pool,sizeof(ngx_buf_t));
				b = ngx_pcalloc(r->pool,sizeof(ngx_buf_t));
				if(b == NULL){
					return NGX_HTTP_INTERNAL_SERVER_ERROR;
				}
				b->in_file = 1;
				b->file = ngx_pcalloc(r->pool,sizeof(ngx_file_t));
				b->file->fd = ngx_open_file(filename,NGX_FILE_RDONLY|NGX_FILE_NONBLOCK, NGX_FILE_OPEN, 0);
				if(b->file->fd == -1){
					return NGX_HTTP_INTERNAL_SERVER_ERROR;
				}
				b->file->name.data = (u_char*)filename;
				b->file->name.len = sizeof(filename) -1;
				if(ngx_file_info(filename,&b->file->info) == NGX_FILE_ERROR){
					return NGX_HTTP_INTERNAL_SERVER_ERROR;
				}
				
				r->headers_out.status = NGX_HTTP_OK;
				r->headers_out.content_length_n = b->file->info.st_size;
				r->headers_out.content_type = type;
				b->file_pos = 0;
				b->file_last = b->file->info.st_size;
				b->last_in_chain = 1;
				b->file->log = r->connection->log;
				b->last_buf = 1;
				

				//清理文件句柄
				/*
				ngx_pool_cleanup_t *cln = ngx_pool_cleanup_add(r->pool,sizeof(ngx_pool_cleanup_file_t));
				if(cln == NULL){
					return NGX_ERROR;
				}
				cln->handler = ngx_pool_cleanup_file;
				ngx_pool_cleanup_file_t *clnf = cln->data;
				clnf->fd = b->file->fd;
				clnf->name = b->file->name.data;
				clnf->log = r->pool->log;
				*/
				
				out->buf = b;
				out->next = NULL;
				rc = ngx_http_send_header(r);
				if(rc == NGX_ERROR || rc > NGX_OK || r->header_only)
				{
					return rc;
				}
				
				return ngx_http_output_filter(r,out);
			
			}
		}
		else{
			ngx_str_t type = ngx_string("video/mp2t");	//ts文件的content type
			//ngx_str_t type = ngx_string("application/octet-stream");
			char filename[512];
			bzero(filename,512);
			ngx_snprintf((u_char*)filename,512,"%s%V.ts",media_path,&media_file);
			ngx_log_error(NGX_LOG_CRIT,r->connection->log,0,"File[%s] is not exist!media_path = %s,media_file=%V",filename,media_path,&media_file);
			r->allow_ranges = 1; //开启range选项
			char *start = ngx_http_hls_convert_string(media_start);
			char *end = ngx_http_hls_convert_string(media_end);
			ngx_log_error(NGX_LOG_CRIT,r->connection->log,0,"start=%s;end=%s",start,end);
			ngx_chain_t *out = ngx_pcalloc(r->pool,sizeof(ngx_chain_t));
			ngx_buf_t *b = ngx_pcalloc(r->pool,sizeof(ngx_buf_t));
			if(b == NULL){
				return NGX_HTTP_INTERNAL_SERVER_ERROR;
			}
			b->in_file = 1;
			b->file = ngx_pcalloc(r->pool,sizeof(ngx_file_t));
			b->file->fd = ngx_open_file(filename,NGX_FILE_RDONLY|NGX_FILE_NONBLOCK, NGX_FILE_OPEN,0);
			if(b->file->fd == -1){
				return NGX_HTTP_INTERNAL_SERVER_ERROR;
			}
			b->file->name.data = (u_char*)filename;
			b->file->name.len = sizeof(filename)-1;
		
			r->headers_out.status = NGX_HTTP_OK;
			r->headers_out.content_length_n = atol(end)-atol(start);
			 ngx_log_error(NGX_LOG_CRIT,r->connection->log,0,"%d",r->headers_out.content_length_n);
			r->headers_out.content_type = type;
			b->file_pos = atol(start);
			b->file_last= atol(end);
			b->last_in_chain = 1;
			b->file->log = r->connection->log;
			b->last_buf = 1;
			out->buf = b;
			out->next = NULL;

			rc = ngx_http_send_header(r);
			if(rc == NGX_ERROR || rc > NGX_OK || r->header_only)
			{
				return rc;
			}
			
			return ngx_http_output_filter(r,out);
			
		}	
	
	}
	return NGX_OK;
}
static ngx_int_t
ngx_open_and_stat_file(u_char *name, ngx_open_file_info_t *of, ngx_log_t *log)
{
    ngx_fd_t         fd;
    ngx_file_info_t  fi;

    of->fd = NGX_INVALID_FILE;

    if (of->test_dir) {

        if (ngx_file_info(name, &fi) == -1) {
            of->err = ngx_errno;

            return NGX_ERROR;
        }

        of->uniq = ngx_file_uniq(&fi);
        of->mtime = ngx_file_mtime(&fi);
        of->size = ngx_file_size(&fi);
        of->is_dir = ngx_is_dir(&fi);
        of->is_file = ngx_is_file(&fi);
        of->is_link = ngx_is_link(&fi);
        of->is_exec = ngx_is_exec(&fi);

        if (of->is_dir) {
            return NGX_OK;
        }
    }

    fd = ngx_open_file(name, NGX_FILE_RDONLY, NGX_FILE_OPEN, 0);

    if (fd == NGX_INVALID_FILE) {
        of->err = ngx_errno;
        return NGX_ERROR;
    }

    if (ngx_fd_info(fd, &fi) == NGX_FILE_ERROR) {
        ngx_log_error(NGX_LOG_CRIT, log, ngx_errno,
                      ngx_fd_info_n " \"%s\" failed", name);

        if (ngx_close_file(fd) == NGX_FILE_ERROR) {
            ngx_log_error(NGX_LOG_ALERT, log, ngx_errno,
                          ngx_close_file_n " \"%s\" failed", name);
        }

        return NGX_ERROR;
    }

    if (ngx_is_dir(&fi)) {
        if (ngx_close_file(fd) == NGX_FILE_ERROR) {
            ngx_log_error(NGX_LOG_ALERT, log, ngx_errno,
                          ngx_close_file_n " \"%s\" failed", name);
        }

        fd = NGX_INVALID_FILE;
    }

    of->fd = fd;
    of->uniq = ngx_file_uniq(&fi);
    of->mtime = ngx_file_mtime(&fi);
    of->size = ngx_file_size(&fi);
    of->is_dir = ngx_is_dir(&fi);
    of->is_file = ngx_is_file(&fi);
    of->is_link = ngx_is_link(&fi);
    of->is_exec = ngx_is_exec(&fi);

    return NGX_OK;
}
static ngx_int_t ngx_http_filetransfer_handler2(ngx_http_request_t *r)  
{  
    //必须是GET或者HEAD方法,否则返回405 Not Allowed  
    if (!(r->method & (NGX_HTTP_GET|NGX_HTTP_HEAD))) {  
        return NGX_HTTP_NOT_ALLOWED;  
    }  

    //丢弃请求中的包体  
    ngx_int_t rc = ngx_http_discard_request_body(r);  
    if (rc != NGX_OK) {  
        return rc;  
    }  
 

    ngx_str_t type = ngx_string("text/html");  
    //返回的包体内容  

    //设置返回状态码  
    r->headers_out.status = NGX_HTTP_OK;  
    //响应包是有包体内容的,需要设置Content-Length长度  

    //设置Content-Type  
    r->headers_out.content_type = type;  
 
    //发送HTTP头部  
    rc = ngx_http_send_header(r);  
    if (rc == NGX_ERROR || rc > NGX_OK || r->header_only) {  
        return rc;  
    }  
 



    ngx_buf_t *b; 
    b = ngx_palloc(r->pool, sizeof(ngx_buf_t)); 
    b->in_file=1;
    u_char* filename = (u_char*)"/usr/local/nginx/html/Google.html";  
    b->file = ngx_pcalloc(r->pool, sizeof(ngx_file_t));  
    b->file->fd = ngx_open_file(filename, NGX_FILE_RDONLY|NGX_FILE_NONBLOCK, NGX_FILE_OPEN, 0);  
    b->file->log = r->connection->log;  
    b->file->name.data = filename;  
    b->file->name.len = sizeof(filename)-1;  
	if (b->file->fd <= 0)  
	{  
	    return NGX_HTTP_NOT_FOUND;  
	} 
    
    if (ngx_file_info(filename, &b->file->info) == NGX_FILE_ERROR) 
    {  
        return NGX_HTTP_INTERNAL_SERVER_ERROR;  
    } 

    r->headers_out.content_length_n = b->file->info.st_size; 
    b->file_pos = 0;  
    b->file_last = b->file->info.st_size; 
   
    ngx_pool_cleanup_t* cln = ngx_pool_cleanup_add(r->pool, sizeof(ngx_pool_cleanup_file_t));  
    if (cln == NULL) {  
    return NGX_ERROR;  
    }  
     
    cln->handler = ngx_pool_cleanup_file;  
    ngx_pool_cleanup_file_t  *clnclnf = cln->data;  
 
    clnclnf->fd = b->file->fd;  
    clnclnf->name = b->file->name.data;  
    clnclnf->log = r->pool->log; 


    //构造发送时的ngx_chain_t结构体  
    ngx_chain_t out;  
    //赋值ngx_buf_t  
    out.buf = b;  
    //设置next为NULL  
    out.next = NULL;  
 
     
    return ngx_http_output_filter(r, &out);  
} 
static ngx_int_t
ngx_http_store_plusplus_add_path(ngx_http_request_t *r, ngx_conhash_t *conhash, ngx_chain_t *out)
{
    ngx_str_t                            value;
    size_t                               len;
    ngx_int_t                            rc;
    ngx_buf_t                           *b;
    u_char                              *p, *path_name;
    ngx_file_info_t                      fi;
    ngx_err_t                            err;
    
    rc = ngx_http_arg(r, (u_char *) STORE_VALUE_STR, sizeof(STORE_VALUE_STR) - 1, &value);
    if (rc != NGX_OK) {
        return rc;
    }
    
    b = ngx_create_temp_buf(r->pool, 1024);
    if (b == NULL) {
        return NGX_HTTP_INTERNAL_SERVER_ERROR;
    }
    
    if (value.data[0] != '/') {
        b->last = ngx_sprintf(b->last, "ERROR: must be an absolute path." CRLF);
        rc = NGX_OK;
        goto done;
    }
    
    if (value.data[value.len - 1] == '/') {
        value.len--;
    }
    
    //  check whether the store path is existent.
    len = value.len + 1 + sizeof(NGX_STORE_PLUSPLUS_TMP_PATH) - 1;
    path_name = ngx_pcalloc(r->pool, len + 1);
    if (path_name == NULL) {
        return NGX_ERROR;
    }
    
    p = ngx_cpymem(path_name, value.data, value.len);
    *p = '\0';
    
    rc = ngx_file_info(path_name, &fi);
    if (rc == NGX_FILE_ERROR) {
        err = ngx_errno;
        b->last = ngx_strerror(err, b->last, b->end - b->last);
        *b->last++ = CR;
        *b->last++ = LF;
        rc = NGX_OK;
        goto done;
    }
    
    //  create temp_path in this store path
    p = ngx_cpymem(path_name, value.data, value.len);
    *p++ = '/';
    p = ngx_cpymem(p, NGX_STORE_PLUSPLUS_TMP_PATH, sizeof(NGX_STORE_PLUSPLUS_TMP_PATH) - 1);
    *p++ = '\0';

    if (ngx_create_dir(path_name, ngx_dir_access(NGX_FILE_OWNER_ACCESS)) 
        == NGX_FILE_ERROR) 
    {
        err = ngx_errno;
        if (err != NGX_EEXIST) {
            b->last = ngx_strerror(err, b->last, b->end - b->last);
            *b->last++ = CR;
            *b->last++ = LF;
            rc = NGX_OK;
            goto done;
        }
    }
    
    rc = ngx_conhash_add_node(conhash, value.data, value.len, NULL);
    if (rc == NGX_OK) {
        b->last = ngx_sprintf(b->last, "Add node successfully!" CRLF);
    }
    
    if (rc == NGX_DECLINED) {
        b->last = ngx_sprintf(b->last, "The node already exists!" CRLF);
        rc = NGX_OK;
    }
    
    if (rc == NGX_AGAIN) {
        b->last = ngx_sprintf(b->last, "The conhash space is not enough!" CRLF);
        rc = NGX_OK;
    }

done:
    b->last_buf = 1;
    out->buf = b;
    
    return rc;
}
Example #17
0
void
ngx_reopen_files(ngx_cycle_t *cycle, ngx_uid_t user)
{
    ssize_t           n, len;
    ngx_fd_t          fd;
    ngx_uint_t        i;
    ngx_list_part_t  *part;
    ngx_open_file_t  *file;

    part = &cycle->open_files.part;
    file = part->elts;

    for (i = 0; /* void */ ; i++) {
        if (i >= part->nelts) {//大于等于总文件数
            if (part->next == NULL) {
                break;//如果没有了,就返回
            }
            part = part->next;//如果还有,标记i = 0,重新来
            file = part->elts;
            i = 0;
        }
        if (file[i].name.len == 0) {
            continue;
        }
        len = file[i].pos - file[i].buffer;
        if (file[i].buffer && len != 0) {//要写进去吗,确认?
            n = ngx_write_fd(file[i].fd, file[i].buffer, len);
            if (n == NGX_FILE_ERROR) {
                ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno, ngx_write_fd_n " to \"%s\" failed", file[i].name.data);
            } else if (n != len) {
                ngx_log_error(NGX_LOG_ALERT, cycle->log, 0, ngx_write_fd_n " to \"%s\" was incomplete: %z of %uz", file[i].name.data, n, len);
            }

            file[i].pos = file[i].buffer;
        }
//再次打开以下这个文件
        fd = ngx_open_file(file[i].name.data, NGX_FILE_APPEND, NGX_FILE_CREATE_OR_OPEN, NGX_FILE_DEFAULT_ACCESS);
        ngx_log_debug3(NGX_LOG_DEBUG_EVENT, cycle->log, 0, "reopen file \"%s\", old:%d new:%d", file[i].name.data, file[i].fd, fd);
        if (fd == NGX_INVALID_FILE) {
            ngx_log_error(NGX_LOG_EMERG, cycle->log, ngx_errno,  ngx_open_file_n " \"%s\" failed", file[i].name.data);
            continue;
        }

#if !(NGX_WIN32)//如果是unix系的操作系统,需要设置文件拥有者啥的
        if (user != (ngx_uid_t) NGX_CONF_UNSET_UINT) {
            ngx_file_info_t  fi;
//得到文件的信息
            if (ngx_file_info((const char *) file[i].name.data, &fi) == NGX_FILE_ERROR) {
                ngx_log_error(NGX_LOG_EMERG, cycle->log, ngx_errno, ngx_file_info_n " \"%s\" failed",  file[i].name.data);
                if (ngx_close_file(fd) == NGX_FILE_ERROR) {
                    ngx_log_error(NGX_LOG_EMERG, cycle->log, ngx_errno, ngx_close_file_n " \"%s\" failed", file[i].name.data);
                }
            }
//修改文件所有者
            if (fi.st_uid != user) {
                if (chown((const char *) file[i].name.data, user, -1) == -1) {
                    ngx_log_error(NGX_LOG_EMERG, cycle->log, ngx_errno, "chown(\"%s\", %d) failed", file[i].name.data, user);
                    if (ngx_close_file(fd) == NGX_FILE_ERROR) {
                        ngx_log_error(NGX_LOG_EMERG, cycle->log, ngx_errno, ngx_close_file_n " \"%s\" failed", file[i].name.data);
                    }
                }
            }
//修改文件权限
            if ((fi.st_mode & (S_IRUSR|S_IWUSR)) != (S_IRUSR|S_IWUSR)) { fi.st_mode |= (S_IRUSR|S_IWUSR);
                if (chmod((const char *) file[i].name.data, fi.st_mode) == -1) {
                    ngx_log_error(NGX_LOG_EMERG, cycle->log, ngx_errno, "chmod() \"%s\" failed", file[i].name.data);
                    if (ngx_close_file(fd) == NGX_FILE_ERROR) {
                        ngx_log_error(NGX_LOG_EMERG, cycle->log, ngx_errno, ngx_close_file_n " \"%s\" failed",  file[i].name.data);
                    }
                }
            }
        }

        if (fcntl(fd, F_SETFD, FD_CLOEXEC) == -1) {
            ngx_log_error(NGX_LOG_EMERG, cycle->log, ngx_errno, "fcntl(FD_CLOEXEC) \"%s\" failed", file[i].name.data);
            if (ngx_close_file(fd) == NGX_FILE_ERROR) {
                ngx_log_error(NGX_LOG_EMERG, cycle->log, ngx_errno, ngx_close_file_n " \"%s\" failed", file[i].name.data);
            }
            continue;
        }
#endif
        if (ngx_close_file(file[i].fd) == NGX_FILE_ERROR) {//关闭掉老的文件句柄
            ngx_log_error(NGX_LOG_EMERG, cycle->log, ngx_errno, ngx_close_file_n " \"%s\" failed",file[i].name.data);
        }
//赋值为新的文件句柄。放心吧,没有别的地方使用这个fd的,就我一个进程,多线程版本不在此
        file[i].fd = fd;
    }

#if !(NGX_WIN32)
    if (cycle->log->file->fd != STDERR_FILENO) {//int dup2(int oldfd, int newfd);
        if (dup2(cycle->log->file->fd, STDERR_FILENO) == -1) {//标准错误输出也设置为日志.那程序的fprint(stderr,)将输出到日志文件
            ngx_log_error(NGX_LOG_EMERG, cycle->log, ngx_errno,"dup2(STDERR) failed");
        }
    }
#endif
}
Example #18
0
void
ngx_pipe_do_rollback(ngx_cycle_t *cycle, ngx_pipe_rollback_conf_t *rbcf)
{
    int             fd;
    struct flock    lock;
    int             ret;
    ngx_int_t       i;
    ngx_file_info_t sb;
    ngx_int_t       need_do = 0;

    fd = ngx_open_file(rbcf->logname, NGX_FILE_RDWR, NGX_FILE_OPEN, 0);
    if (fd < 0) {
        //open lock file failed just no need rollback
        return;
    }

    lock.l_type     = F_WRLCK;
    lock.l_whence   = SEEK_SET;
    lock.l_start    = 0;
    lock.l_len      = 0;

    ret = fcntl(fd, F_SETLKW, &lock);
    if (ret < 0) {
        ngx_close_file(fd);
        //lock failed just no need rollback
        return;
    }

    //check time
    if (rbcf->interval >= 0) {
        if (ngx_file_info(rbcf->backup[0], &sb) == -1) {
            need_do = 1;
            ngx_log_error(NGX_LOG_INFO, cycle->log, 0,
                          "need rollback [%s]: cannot open backup", rbcf->logname);

        } else if (sb.st_ctime / rbcf->interval < ngx_time() / rbcf->interval) {
            need_do = 1;
            ngx_log_error(NGX_LOG_INFO, cycle->log, 0,
                          "need rollback [%s]: time on [%d] [%d]",
                          rbcf->logname, sb.st_ctime, rbcf->time_now);

        } else {
            ngx_log_error(NGX_LOG_INFO, cycle->log, 0,
                          "no need rollback [%s]: time not on [%d] [%d]",
                          rbcf->logname, sb.st_ctime, rbcf->time_now);
        }

    } else {
        ngx_log_error(NGX_LOG_INFO, cycle->log, 0,
                      "no need check rollback [%s] time: no interval", rbcf->logname);
    }

    //check size
    if (rbcf->log_max_size > 0) {
        if (ngx_file_info(rbcf->logname, &sb) == 0 && (sb.st_size >= rbcf->log_max_size)) {
            need_do = 1;
            ngx_log_error(NGX_LOG_INFO, cycle->log, 0,
                          "need rollback [%s]: size on [%d]", rbcf->logname, sb.st_size);

        } else {
            ngx_log_error(NGX_LOG_INFO, cycle->log, 0,
                          "no need rollback [%s]: size not on", rbcf->logname);
        }

    } else {
        ngx_log_error(NGX_LOG_INFO, cycle->log, 0,
                      "no need check rollback [%s] size: no max size", rbcf->logname);
    }

    if (need_do) {
        for (i = 1; i < rbcf->backup_num; i++) {
            ngx_rename_file(rbcf->backup[rbcf->backup_num - i - 1],
                   rbcf->backup[rbcf->backup_num - i]);
        }
        if (ngx_rename_file(rbcf->logname, rbcf->backup[0]) < 0) {
            ngx_log_error(NGX_LOG_EMERG, cycle->log, ngx_errno,
                          "rname %s to %s failed", rbcf->logname, rbcf->backup[0]);
        } else {
            ngx_log_error(NGX_LOG_WARN, cycle->log, 0,
                          "rollback [%s] success", rbcf->logname);
        }
    }
    ngx_close_file(fd);
}
Example #19
0
static ngx_int_t
ngx_open_and_stat_file(u_char *name, ngx_open_file_info_t *of, ngx_log_t *log)
{
    int              mode;
    ngx_fd_t         fd;
    ngx_file_info_t  fi;

    if (of->fd != NGX_INVALID_FILE) {

        if (ngx_file_info(name, &fi) == NGX_FILE_ERROR) {
            of->failed = ngx_file_info_n;
            goto failed;
        }

        if (of->uniq == ngx_file_uniq(&fi)) {
            goto done;
        }

    } else if (of->test_dir) {

        if (ngx_file_info(name, &fi) == NGX_FILE_ERROR) {
            of->failed = ngx_file_info_n;
            goto failed;
        }

        if (ngx_is_dir(&fi)) {
            goto done;
        }
    }

    if (!of->log) {

        /*
         * Use non-blocking open() not to hang on FIFO files, etc.
         * This flag has no effect on a regular files.
         */

        mode = NGX_FILE_RDONLY|NGX_FILE_NONBLOCK;

#if (NGX_WIN32 && NGX_HAVE_FILE_AIO)
        if (ngx_event_flags & NGX_USE_IOCP_EVENT && of->aio) {
            mode |= NGX_FILE_OVERLAPPED;
        }
#endif

        fd = ngx_open_file(name, mode, NGX_FILE_OPEN, 0);

    } else {
        fd = ngx_open_file(name, NGX_FILE_APPEND, NGX_FILE_CREATE_OR_OPEN,
                           NGX_FILE_DEFAULT_ACCESS);
    }

    if (fd == NGX_INVALID_FILE) {
        of->failed = ngx_open_file_n;
        goto failed;
    }

    if (ngx_fd_info(fd, &fi) == NGX_FILE_ERROR) {
        ngx_log_error(NGX_LOG_CRIT, log, ngx_errno,
                      ngx_fd_info_n " \"%s\" failed", name);

        if (ngx_close_file(fd) == NGX_FILE_ERROR) {
            ngx_log_error(NGX_LOG_ALERT, log, ngx_errno,
                          ngx_close_file_n " \"%s\" failed", name);
        }

        of->fd = NGX_INVALID_FILE;

        return NGX_ERROR;
    }

    if (ngx_is_dir(&fi)) {
        if (ngx_close_file(fd) == NGX_FILE_ERROR) {
            ngx_log_error(NGX_LOG_ALERT, log, ngx_errno,
                          ngx_close_file_n " \"%s\" failed", name);
        }

        of->fd = NGX_INVALID_FILE;

    } else {
        of->fd = fd;

        if (of->read_ahead && ngx_file_size(&fi) > NGX_MIN_READ_AHEAD) {
            if (ngx_read_ahead(fd, of->read_ahead) == NGX_ERROR) {
                ngx_log_error(NGX_LOG_ALERT, log, ngx_errno,
                              ngx_read_ahead_n " \"%s\" failed", name);
            }
        }

        if (of->directio <= ngx_file_size(&fi)) {
            if (ngx_directio_on(fd) == NGX_FILE_ERROR) {
                ngx_log_error(NGX_LOG_ALERT, log, ngx_errno,
                              ngx_directio_on_n " \"%s\" failed", name);

            } else {
                of->is_directio = 1;
            }
        }
    }

done:

    of->uniq = ngx_file_uniq(&fi);
    of->mtime = ngx_file_mtime(&fi);
    of->size = ngx_file_size(&fi);
    of->fs_size = ngx_file_fs_size(&fi);
    of->is_dir = ngx_is_dir(&fi);
    of->is_file = ngx_is_file(&fi);
    of->is_link = ngx_is_link(&fi);
    of->is_exec = ngx_is_exec(&fi);

    return NGX_OK;

failed:

    of->fd = NGX_INVALID_FILE;
    of->err = ngx_errno;

    return NGX_ERROR;
}
Example #20
0
void
ngx_reopen_files(ngx_cycle_t *cycle, ngx_uid_t user)
{
    ssize_t           n, len;
    ngx_fd_t          fd;
    ngx_uint_t        i;
    ngx_list_part_t  *part;
    ngx_open_file_t  *file;

    part = &cycle->open_files.part;
    file = part->elts;

    for (i = 0; /* void */ ; i++) {

        if (i >= part->nelts) {
            if (part->next == NULL) {
                break;
            }
            part = part->next;
            file = part->elts;
            i = 0;
        }

        if (file[i].name.data == NULL) {
            continue;
        }

        len = file[i].pos - file[i].buffer;

        if (file[i].buffer && len != 0) {

            n = ngx_write_fd(file[i].fd, file[i].buffer, len);

            if (n == NGX_FILE_ERROR) {
                ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno,
                              ngx_write_fd_n " to \"%s\" failed",
                              file[i].name.data);

            } else if (n != len) {
                ngx_log_error(NGX_LOG_ALERT, cycle->log, 0,
                          ngx_write_fd_n " to \"%s\" was incomplete: %z of %uz",
                          file[i].name.data, n, len);
            }

            file[i].pos = file[i].buffer;
        }

        fd = ngx_open_file(file[i].name.data, NGX_FILE_RDWR,
                           NGX_FILE_CREATE_OR_OPEN|NGX_FILE_APPEND,
                           NGX_FILE_DEFAULT_ACCESS);

        ngx_log_debug3(NGX_LOG_DEBUG_EVENT, cycle->log, 0,
                       "reopen file \"%s\", old:%d new:%d",
                       file[i].name.data, file[i].fd, fd);

        if (fd == NGX_INVALID_FILE) {
            ngx_log_error(NGX_LOG_EMERG, cycle->log, ngx_errno,
                          ngx_open_file_n " \"%s\" failed", file[i].name.data);
            continue;
        }

#if (NGX_WIN32)
        if (ngx_file_append_mode(fd) == NGX_ERROR) {
            ngx_log_error(NGX_LOG_EMERG, cycle->log, ngx_errno,
                          ngx_file_append_mode_n " \"%s\" failed",
                          file[i].name.data);

            if (ngx_close_file(fd) == NGX_FILE_ERROR) {
                ngx_log_error(NGX_LOG_EMERG, cycle->log, ngx_errno,
                              ngx_close_file_n " \"%s\" failed",
                              file[i].name.data);
            }

            continue;
        }
#else
        if (user != (ngx_uid_t) NGX_CONF_UNSET_UINT) {
            ngx_file_info_t  fi;

            if (ngx_file_info((const char *) file[i].name.data, &fi) == -1) {
                ngx_log_error(NGX_LOG_EMERG, cycle->log, ngx_errno,
                              ngx_file_info_n " \"%s\" failed",
                              file[i].name.data);

                if (ngx_close_file(fd) == NGX_FILE_ERROR) {
                    ngx_log_error(NGX_LOG_EMERG, cycle->log, ngx_errno,
                                  ngx_close_file_n " \"%s\" failed",
                                  file[i].name.data);
                }
            }

            if (fi.st_uid != user) {
                if (chown((const char *) file[i].name.data, user, -1) == -1) {
                    ngx_log_error(NGX_LOG_EMERG, cycle->log, ngx_errno,
                                  "chown(\"%s\", %d) failed",
                                  file[i].name.data, user);

                    if (ngx_close_file(fd) == NGX_FILE_ERROR) {
                        ngx_log_error(NGX_LOG_EMERG, cycle->log, ngx_errno,
                                      ngx_close_file_n " \"%s\" failed",
                                      file[i].name.data);
                    }
                }
            }

            if ((fi.st_mode & (S_IRUSR|S_IWUSR)) != (S_IRUSR|S_IWUSR)) {

                fi.st_mode |= (S_IRUSR|S_IWUSR);

                if (chmod((const char *) file[i].name.data, fi.st_mode) == -1) {
                    ngx_log_error(NGX_LOG_EMERG, cycle->log, ngx_errno,
                                  "chmod() \"%s\" failed", file[i].name.data);

                    if (ngx_close_file(fd) == NGX_FILE_ERROR) {
                        ngx_log_error(NGX_LOG_EMERG, cycle->log, ngx_errno,
                                      ngx_close_file_n " \"%s\" failed",
                                      file[i].name.data);
                    }
                }
            }
        }

        if (fcntl(fd, F_SETFD, FD_CLOEXEC) == -1) {
            ngx_log_error(NGX_LOG_EMERG, cycle->log, ngx_errno,
                          "fcntl(FD_CLOEXEC) \"%s\" failed",
                          file[i].name.data);

            if (ngx_close_file(fd) == NGX_FILE_ERROR) {
                ngx_log_error(NGX_LOG_EMERG, cycle->log, ngx_errno,
                              ngx_close_file_n " \"%s\" failed",
                              file[i].name.data);
            }

            continue;
        }
#endif

        if (ngx_close_file(file[i].fd) == NGX_FILE_ERROR) {
            ngx_log_error(NGX_LOG_EMERG, cycle->log, ngx_errno,
                          ngx_close_file_n " \"%s\" failed",
                          file[i].name.data);
        }

        file[i].fd = fd;
    }

#if !(NGX_WIN32)

    if (cycle->log->file->fd != STDERR_FILENO) {
        if (dup2(cycle->log->file->fd, STDERR_FILENO) == -1) {
            ngx_log_error(NGX_LOG_EMERG, cycle->log, ngx_errno,
                          "dup2(STDERR) failed");
        }
    }

#endif
}
static ngx_int_t
ngx_http_dav_delete_handler(ngx_http_request_t *r)
{
    size_t                    root;
    ngx_err_t                 err;
    ngx_int_t                 rc, depth;
    ngx_uint_t                i, d, dir;
    ngx_str_t                 path;
    ngx_file_info_t           fi;
    ngx_http_dav_loc_conf_t  *dlcf;

    if (r->headers_in.content_length_n > 0) {
        ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
                      "DELETE with body is unsupported");
        return NGX_HTTP_UNSUPPORTED_MEDIA_TYPE;
    }

    dlcf = ngx_http_get_module_loc_conf(r, ngx_http_dav_module);

    if (dlcf->min_delete_depth) {
        d = 0;

        for (i = 0; i < r->uri.len; /* void */) {
            if (r->uri.data[i++] == '/') {
                if (++d >= dlcf->min_delete_depth && i < r->uri.len) {
                    goto ok;
                }
            }
        }

        ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
                      "insufficient URI depth:%i to DELETE", d);
        return NGX_HTTP_CONFLICT;
    }

ok:

    ngx_http_map_uri_to_path(r, &path, &root, 0);

    ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
                   "http delete filename: \"%s\"", path.data);

    if (ngx_file_info(path.data, &fi) == NGX_FILE_ERROR) {
        err = ngx_errno;

        rc = (err == NGX_ENOTDIR) ? NGX_HTTP_CONFLICT : NGX_HTTP_NOT_FOUND;

        return ngx_http_dav_error(r->connection->log, err,
                                  rc, ngx_file_info_n, path.data);
    }

    if (ngx_is_dir(&fi)) {

        if (r->uri.data[r->uri.len - 1] != '/') {
            ngx_log_error(NGX_LOG_ERR, r->connection->log, NGX_EISDIR,
                          "DELETE \"%s\" failed", path.data);
            return NGX_HTTP_CONFLICT;
        }

        depth = ngx_http_dav_depth(r, NGX_HTTP_DAV_INFINITY_DEPTH);

        if (depth != NGX_HTTP_DAV_INFINITY_DEPTH) {
            ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
                          "\"Depth\" header must be infinity");
            return NGX_HTTP_BAD_REQUEST;
        }

        path.len -= 2;  /* omit "/\0" */

        dir = 1;

    } else {

        /*
         * we do not need to test (r->uri.data[r->uri.len - 1] == '/')
         * because ngx_file_info("/file/") returned NGX_ENOTDIR above
         */

        depth = ngx_http_dav_depth(r, 0);

        if (depth != 0 && depth != NGX_HTTP_DAV_INFINITY_DEPTH) {
            ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
                          "\"Depth\" header must be 0 or infinity");
            return NGX_HTTP_BAD_REQUEST;
        }

        dir = 0;
    }

    rc = ngx_http_dav_delete_path(r, &path, dir);

    if (rc == NGX_OK) {
        return NGX_HTTP_NO_CONTENT;
    }

    return rc;
}
Example #22
0
void
ngx_reopen_files(ngx_cycle_t *cycle, ngx_uid_t user)
{
    ngx_fd_t          fd;
    ngx_uint_t        i;
    ngx_list_part_t  *part;
    ngx_open_file_t  *file;

    part = &cycle->open_files.part;
    file = part->elts;

    for (i = 0; /* void */ ; i++) {

        if (i >= part->nelts) {
            if (part->next == NULL) {
                break;
            }
            part = part->next;
            file = part->elts;
            i = 0;
        }

        if (file[i].name.len == 0) {
            continue;
        }

        if (file[i].flush) {
            file[i].flush(&file[i], cycle->log);
        }

        fd = ngx_open_file(file[i].name.data, NGX_FILE_APPEND,
                           NGX_FILE_CREATE_OR_OPEN, NGX_FILE_DEFAULT_ACCESS);

        ngx_log_debug3(NGX_LOG_DEBUG_EVENT, cycle->log, 0,
                       "reopen file \"%s\", old:%d new:%d",
                       file[i].name.data, file[i].fd, fd);

        if (fd == NGX_INVALID_FILE) {
            ngx_log_error(NGX_LOG_EMERG, cycle->log, ngx_errno,
                          ngx_open_file_n " \"%s\" failed", file[i].name.data);
            continue;
        }

#if !(NGX_WIN32)
        if (user != (ngx_uid_t) NGX_CONF_UNSET_UINT) {
            ngx_file_info_t  fi;

            if (ngx_file_info((const char *) file[i].name.data, &fi)
                == NGX_FILE_ERROR)
            {
                ngx_log_error(NGX_LOG_EMERG, cycle->log, ngx_errno,
                              ngx_file_info_n " \"%s\" failed",
                              file[i].name.data);

                if (ngx_close_file(fd) == NGX_FILE_ERROR) {
                    ngx_log_error(NGX_LOG_EMERG, cycle->log, ngx_errno,
                                  ngx_close_file_n " \"%s\" failed",
                                  file[i].name.data);
                }
            }

            if (fi.st_uid != user) {
                if (chown((const char *) file[i].name.data, user, -1) == -1) {
                    ngx_log_error(NGX_LOG_EMERG, cycle->log, ngx_errno,
                                  "chown(\"%s\", %d) failed",
                                  file[i].name.data, user);

                    if (ngx_close_file(fd) == NGX_FILE_ERROR) {
                        ngx_log_error(NGX_LOG_EMERG, cycle->log, ngx_errno,
                                      ngx_close_file_n " \"%s\" failed",
                                      file[i].name.data);
                    }
                }
            }

            if ((fi.st_mode & (S_IRUSR|S_IWUSR)) != (S_IRUSR|S_IWUSR)) {

                fi.st_mode |= (S_IRUSR|S_IWUSR);

                if (chmod((const char *) file[i].name.data, fi.st_mode) == -1) {
                    ngx_log_error(NGX_LOG_EMERG, cycle->log, ngx_errno,
                                  "chmod() \"%s\" failed", file[i].name.data);

                    if (ngx_close_file(fd) == NGX_FILE_ERROR) {
                        ngx_log_error(NGX_LOG_EMERG, cycle->log, ngx_errno,
                                      ngx_close_file_n " \"%s\" failed",
                                      file[i].name.data);
                    }
                }
            }
        }

        if (fcntl(fd, F_SETFD, FD_CLOEXEC) == -1) {
            ngx_log_error(NGX_LOG_EMERG, cycle->log, ngx_errno,
                          "fcntl(FD_CLOEXEC) \"%s\" failed",
                          file[i].name.data);

            if (ngx_close_file(fd) == NGX_FILE_ERROR) {
                ngx_log_error(NGX_LOG_EMERG, cycle->log, ngx_errno,
                              ngx_close_file_n " \"%s\" failed",
                              file[i].name.data);
            }

            continue;
        }
#endif

        if (ngx_close_file(file[i].fd) == NGX_FILE_ERROR) {
            ngx_log_error(NGX_LOG_EMERG, cycle->log, ngx_errno,
                          ngx_close_file_n " \"%s\" failed",
                          file[i].name.data);
        }

        file[i].fd = fd;
    }

    (void) ngx_log_redirect_stderr(cycle);
}
static ngx_int_t
ngx_rtmp_auto_push_init_process(ngx_cycle_t *cycle)
{
#if (NGX_HAVE_UNIX_DOMAIN)
    ngx_rtmp_auto_push_conf_t  *apcf;
    ngx_listening_t            *ls, *lss;
    struct sockaddr_un         *saun;
    int                         reuseaddr;
    ngx_socket_t                s;
    size_t                      n;
    ngx_file_info_t             fi;

    if (ngx_process != NGX_PROCESS_WORKER) {
        return NGX_OK;
    }

    ngx_rtmp_auto_push_module.ctx_index = ngx_rtmp_core_module.ctx_index;

    apcf = (ngx_rtmp_auto_push_conf_t *) ngx_get_conf(cycle->conf_ctx,
                                                    ngx_rtmp_auto_push_module);
    if (apcf->auto_push == 0) {
        return NGX_OK;
    }

    next_publish = ngx_rtmp_publish;
    ngx_rtmp_publish = ngx_rtmp_auto_push_publish;

    next_delete_stream = ngx_rtmp_delete_stream;
    ngx_rtmp_delete_stream = ngx_rtmp_auto_push_delete_stream;

    reuseaddr = 1;
    s = (ngx_socket_t) -1;

    ngx_log_debug0(NGX_LOG_DEBUG_RTMP, cycle->log, 0,
            "auto_push: creating sockets");

    /*TODO: clone all RTMP listenings? */
    ls = cycle->listening.elts;
    lss = NULL;
    for (n = 0; n < cycle->listening.nelts; ++n, ++ls) {
        if (ls->handler == ngx_stream_init_connection) {
            lss = ls;
            break;
        }
    }

    if (lss == NULL) {
        return NGX_OK;
    }

    ls = ngx_array_push(&cycle->listening);
    if (ls == NULL) {
        return NGX_ERROR;
    }

    *ls = *lss;

    /* Disable unix socket client address extraction
     * from accept call
     * Nginx generates bad addr_text with this enabled */
    ls->addr_ntop = 0;

    ls->socklen = sizeof(struct sockaddr_un);
    saun = ngx_pcalloc(cycle->pool, ls->socklen);
    ls->sockaddr = (struct sockaddr *) saun;
    if (ls->sockaddr == NULL) {
        return NGX_ERROR;
    }
    saun->sun_family = AF_UNIX;
    *ngx_snprintf((u_char *) saun->sun_path, sizeof(saun->sun_path),
                  "%V/" NGX_RTMP_AUTO_PUSH_SOCKNAME ".%i",
                  &apcf->socket_dir, ngx_process_slot)
        = 0;

    ngx_log_debug1(NGX_LOG_DEBUG_RTMP, cycle->log, 0,
                   "auto_push: create socket '%s'",
                   saun->sun_path);

    if (ngx_file_info(saun->sun_path, &fi) != ENOENT) {
        ngx_log_debug1(NGX_LOG_DEBUG_RTMP, cycle->log, 0,
                       "auto_push: delete existing socket '%s'",
                       saun->sun_path);
        ngx_delete_file(saun->sun_path);
    }

    ngx_str_set(&ls->addr_text, "worker_socket");

    s = ngx_socket(AF_UNIX, SOCK_STREAM, 0);
    if (s == -1) {
        ngx_log_error(NGX_LOG_EMERG, cycle->log, ngx_socket_errno,
                      ngx_socket_n " worker_socket failed");
        return NGX_ERROR;
    }

    if (setsockopt(s, SOL_SOCKET, SO_REUSEADDR,
                   (const void *) &reuseaddr, sizeof(int))
        == -1)
    {
        ngx_log_error(NGX_LOG_EMERG, cycle->log, ngx_socket_errno,
                "setsockopt(SO_REUSEADDR) worker_socket failed");
        goto sock_error;
    }

    if (!(ngx_event_flags & NGX_USE_AIO_EVENT)) {
        if (ngx_nonblocking(s) == -1) {
            ngx_log_error(NGX_LOG_EMERG, cycle->log, ngx_socket_errno,
                          ngx_nonblocking_n " worker_socket failed");
            return NGX_ERROR;
        }
    }

    if (bind(s, (struct sockaddr *) saun, sizeof(*saun)) == -1) {
        ngx_log_error(NGX_LOG_EMERG, cycle->log, ngx_socket_errno,
                      ngx_nonblocking_n " worker_socket bind failed");
        goto sock_error;
    }

    if (listen(s, NGX_LISTEN_BACKLOG) == -1) {
        ngx_log_error(NGX_LOG_EMERG, cycle->log, ngx_socket_errno,
                      "listen() to worker_socket, backlog %d failed",
                      NGX_LISTEN_BACKLOG);
        goto sock_error;
    }

    ls->fd = s;
    ls->listen = 1;

    return NGX_OK;

sock_error:
    if (s != (ngx_socket_t) -1 && ngx_close_socket(s) == -1) {
        ngx_log_error(NGX_LOG_EMERG, cycle->log, ngx_socket_errno,
                ngx_close_socket_n " worker_socket failed");
    }
    ngx_delete_file(saun->sun_path);

    return NGX_ERROR;

#else  /* NGX_HAVE_UNIX_DOMAIN */

    return NGX_OK;

#endif /* NGX_HAVE_UNIX_DOMAIN */
}
Example #24
0
static ngx_int_t ngx_http_static_handler(ngx_http_request_t *r)
{
  u_char                      *last;
  ngx_fd_t                     fd;
  ngx_int_t                    rc;
  ngx_uint_t                   level;
  ngx_str_t                    name, location;
  ngx_err_t                    err;
  ngx_log_t                   *log;
  ngx_buf_t                   *b;
  ngx_chain_t                  out;
  ngx_file_info_t              fi;
  ngx_http_cleanup_t          *file_cleanup, *redirect_cleanup;
  ngx_http_log_ctx_t          *ctx;
  ngx_http_core_loc_conf_t    *clcf;
  ngx_http_static_loc_conf_t  *slcf;
#if (NGX_HTTP_CACHE)
  uint32_t                     file_crc, redirect_crc;
  ngx_http_cache_t            *file, *redirect;
#endif

  if (r->uri.data[r->uri.len - 1] == '/') {
    return NGX_DECLINED;
  }

  if (r->method != NGX_HTTP_GET && r->method != NGX_HTTP_HEAD) {
    return NGX_HTTP_NOT_ALLOWED;
  }

  rc = ngx_http_discard_body(r);

  if (rc != NGX_OK && rc != NGX_AGAIN) {
    return rc;
  }

#if (NGX_HTTP_CACHE)

  /*
   * there is a valid cached open file, i.e by the index handler,
   * and it should be already registered in r->cleanup
   */

  if (r->cache && !r->cache->expired) {
    return ngx_http_send_cached(r);
  }

#endif

  log = r->connection->log;

  clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);

  /*
   * make a file name, reserve 2 bytes for a trailing '/'
   * in a possible redirect and for the last '\0'
   */

  if (clcf->alias) {
    name.data = ngx_palloc(r->pool, clcf->root.len + r->uri.len + 2
                    - clcf->name.len);
    if (name.data == NULL) {
      return NGX_HTTP_INTERNAL_SERVER_ERROR;
    }

    last = ngx_cpymem(name.data, clcf->root.data, clcf->root.len);
    last = ngx_cpystrn(last, r->uri.data + clcf->name.len,
               r->uri.len + 1 - clcf->name.len);

    name.len = last - name.data;

    location.data = ngx_palloc(r->pool, r->uri.len + 2);
    if (location.data == NULL) {
      return NGX_HTTP_INTERNAL_SERVER_ERROR;
    }

    last = ngx_cpystrn(location.data, r->uri.data, r->uri.len + 1);

#if 0
    /*
     * aliases usually have trailling "/",
     * set it in the start of the possible redirect
     */

    if (*location.data != '/') {
      location.data--;
    }
#endif

    location.len = last - location.data + 1;

  } else {
    name.data = ngx_palloc(r->pool, clcf->root.len + r->uri.len + 2);
    if (name.data == NULL) {
      return NGX_HTTP_INTERNAL_SERVER_ERROR;
    }

    location.data = ngx_cpymem(name.data, clcf->root.data, clcf->root.len);
    last = ngx_cpystrn(location.data, r->uri.data, r->uri.len + 1);

    name.len = last - name.data;
    location.len = last - location.data + 1;
  }

  ngx_log_debug1(NGX_LOG_DEBUG_HTTP, log, 0,
           "http filename: \"%s\"", name.data);


  /* allocate cleanups */

  if (!(file_cleanup = ngx_push_array(&r->cleanup))) {
    return NGX_HTTP_INTERNAL_SERVER_ERROR;
  }
  file_cleanup->valid = 0;

  slcf = ngx_http_get_module_loc_conf(r, ngx_http_static_module);
  if (slcf->redirect_cache) {
    if (!(redirect_cleanup = ngx_push_array(&r->cleanup))) {
      return NGX_HTTP_INTERNAL_SERVER_ERROR;
    }
    redirect_cleanup->valid = 0;

  } else {
    redirect_cleanup = NULL;
  }

#if (NGX_HTTP_CACHE)

  /* look up an open files cache */

  if (clcf->open_files) {
    file = ngx_http_cache_get(clcf->open_files, file_cleanup,
                  &name, &file_crc);

    ngx_log_debug1(NGX_LOG_DEBUG_HTTP, log, 0,
             "http open file cache get: " PTR_FMT, file);

    if (file && !file->expired) {
      r->cache = file;
      return ngx_http_send_cached(r);
    }

  } else {
    file = NULL;
  }


  /* look up an redirect cache */

  if (slcf->redirect_cache) {
    redirect = ngx_http_cache_get(slcf->redirect_cache, redirect_cleanup,
                    &name, &redirect_crc);

    ngx_log_debug1(NGX_LOG_DEBUG_HTTP, log, 0,
             "http redirect cache get: " PTR_FMT, redirect);

    if (redirect && !redirect->expired) {

      /*
       * We do not copy a cached value so the cache entry is locked
       * until the end of the request.  In a single threaded model
       * the redirected request should complete before other event
       * will be processed.  In a multithreaded model this locking
       * should keep more popular redirects in cache.
       */

      if (!(r->headers_out.location =
           ngx_http_add_header(&r->headers_out, ngx_http_headers_out)))
      {
        return NGX_HTTP_INTERNAL_SERVER_ERROR;
      }

      r->headers_out.location->value = redirect->data.value;

      return NGX_HTTP_MOVED_PERMANENTLY;
    }

  } else {
    redirect = NULL;
  }

#endif

  /* open file */

#if (WIN9X)

  /* TODO: redirect cache */

  if (ngx_win32_version < NGX_WIN_NT) {

    /*
     * there is no way to open a file or a directory in Win9X with
     * one syscall because Win9X has no FILE_FLAG_BACKUP_SEMANTICS flag
     * so we need to check its type before the opening
     */

    if (ngx_file_info(name.data, &fi) == NGX_FILE_ERROR) {
      err = ngx_errno;
      ngx_log_error(NGX_LOG_ERR, log, err,
              ngx_file_info_n " \"%s\" failed", name.data);

      if (err == NGX_ENOENT || err == NGX_ENOTDIR) {
        return NGX_HTTP_NOT_FOUND;

      } else if (err == NGX_EACCES) {
        return NGX_HTTP_FORBIDDEN;

      } else {
        return NGX_HTTP_INTERNAL_SERVER_ERROR;
      }
    }

    if (ngx_is_dir(&fi)) {
      ngx_log_debug(log, "HTTP DIR: '%s'" _ name.data);

      if (!(r->headers_out.location =
           ngx_http_add_header(&r->headers_out, ngx_http_headers_out)))
      {
        return NGX_HTTP_INTERNAL_SERVER_ERROR;
      }

      *last++ = '/';
      *last = '\0';
      r->headers_out.location->value.len = last - location;
      r->headers_out.location->value.data = location;

      return NGX_HTTP_MOVED_PERMANENTLY;
    }
  }

#endif


  fd = ngx_open_file(name.data, NGX_FILE_RDONLY, NGX_FILE_OPEN);

  if (fd == NGX_INVALID_FILE) {
    err = ngx_errno;

    if (err == NGX_ENOENT || err == NGX_ENOTDIR) {
      level = NGX_LOG_ERR;
      rc = NGX_HTTP_NOT_FOUND;

    } else if (err == NGX_EACCES) {
      level = NGX_LOG_ERR;
      rc = NGX_HTTP_FORBIDDEN;

    } else {
      level = NGX_LOG_CRIT;
      rc = NGX_HTTP_INTERNAL_SERVER_ERROR;
    }

    ngx_log_error(level, log, err,
            ngx_open_file_n " \"%s\" failed", name.data);

    return rc;
  }

  ngx_log_debug1(NGX_LOG_DEBUG_HTTP, log, 0, "http static fd: %d", fd);

  if (ngx_fd_info(fd, &fi) == NGX_FILE_ERROR) {
    ngx_log_error(NGX_LOG_CRIT, log, ngx_errno,
            ngx_fd_info_n " \"%s\" failed", name.data);

    if (ngx_close_file(fd) == NGX_FILE_ERROR) {
      ngx_log_error(NGX_LOG_ALERT, log, ngx_errno,
              ngx_close_file_n " \"%s\" failed", name.data);
    }

    return NGX_HTTP_INTERNAL_SERVER_ERROR;
  }

  if (ngx_is_dir(&fi)) {

    ngx_log_debug0(NGX_LOG_DEBUG_HTTP, log, 0, "http dir");

    if (ngx_close_file(fd) == NGX_FILE_ERROR) {
      ngx_log_error(NGX_LOG_ALERT, log, ngx_errno,
              ngx_close_file_n " \"%s\" failed", name.data);
    }

    *last++ = '/';
    *last = '\0';

    r->headers_out.location = ngx_list_push(&r->headers_out.headers);
    if (r->headers_out.location == NULL) {
      return NGX_HTTP_INTERNAL_SERVER_ERROR;
    }

    r->headers_out.location->value = location;

#if (NGX_HTTP_CACHE)

    if (slcf->redirect_cache) {
      if (redirect) {
        if (location.len == redirect->data.value.len
          && ngx_memcmp(redirect->data.value.data, location.data,
                              location.len) == 0)
        {
          redirect->accessed = ngx_cached_time;
          redirect->updated = ngx_cached_time;

          /*
           * we can unlock the cache entry because
           * we have the local copy anyway
           */

          ngx_http_cache_unlock(slcf->redirect_cache, redirect, log);
          redirect_cleanup->valid = 0;

          return NGX_HTTP_MOVED_PERMANENTLY;
        }
      }

      location.len++;
      redirect = ngx_http_cache_alloc(slcf->redirect_cache, redirect,
                      redirect_cleanup,
                      &name, redirect_crc,
                      &location, log);
      location.len--;

      ngx_log_debug1(NGX_LOG_DEBUG_HTTP, log, 0,
               "http redirect cache alloc: " PTR_FMT, redirect);

      if (redirect) {
        redirect->fd = NGX_INVALID_FILE;
        redirect->accessed = ngx_cached_time;
        redirect->last_modified = 0;
        redirect->updated = ngx_cached_time;
        redirect->memory = 1;
        ngx_http_cache_unlock(slcf->redirect_cache, redirect, log);
        redirect_cleanup->valid = 0;
      }

    }

#endif

    return NGX_HTTP_MOVED_PERMANENTLY;
  }

#if !(WIN32) /* the not regular files are probably Unix specific */

  if (!ngx_is_file(&fi)) {
    ngx_log_error(NGX_LOG_CRIT, log, ngx_errno,
            "%s is not a regular file", name.data);

    if (ngx_close_file(fd) == NGX_FILE_ERROR) {
      ngx_log_error(NGX_LOG_ALERT, log, ngx_errno,
              ngx_close_file_n " \"%s\" failed", name.data);
    }

    return NGX_HTTP_NOT_FOUND;
  }

#endif


#if (NGX_HTTP_CACHE)

  if (clcf->open_files) {

#if (NGX_USE_HTTP_FILE_CACHE_UNIQ)

    if (file && file->uniq == ngx_file_uniq(&fi)) {
      if (ngx_close_file(fd) == NGX_FILE_ERROR) {
        ngx_log_error(NGX_LOG_ALERT, log, ngx_errno,
                ngx_close_file_n " \"%s\" failed", name.data);
      }
      file->accessed = ngx_cached_time;
      file->updated = ngx_cached_time;
      file->expired = 0;
      r->cache = file;

      return ngx_http_send_cached(r);

    } else {
      if (file) {
        ngx_http_cache_unlock(clcf->open_files, file, log);
        file = NULL;
      }

      file = ngx_http_cache_alloc(clcf->open_files, file,
                    file_cleanup,
                    &name, file_crc, NULL, log);
      if (file) {
        file->uniq = ngx_file_uniq(&fi);
      }
    }

#else
    file = ngx_http_cache_alloc(clcf->open_files, file,
                  file_cleanup,
                  &name, file_crc, NULL, log);
#endif

    ngx_log_debug1(NGX_LOG_DEBUG_HTTP, log, 0,
             "http open file cache alloc: " PTR_FMT, file);

    if (file) {
      file->fd = fd;
      file->data.size = ngx_file_size(&fi);
      file->accessed = ngx_cached_time;
      file->last_modified = ngx_file_mtime(&fi);
      file->updated = ngx_cached_time;
      r->cache = file;
    }

    return ngx_http_send_cached(r);
  }

#endif

  ctx = log->data;
  ctx->action = "sending response to client";

  file_cleanup->data.file.fd = fd;
  file_cleanup->data.file.name = name.data;
  file_cleanup->valid = 1;
  file_cleanup->cache = 0;

  r->headers_out.status = NGX_HTTP_OK;
  r->headers_out.content_length_n = ngx_file_size(&fi);
  r->headers_out.last_modified_time = ngx_file_mtime(&fi);

  if (r->headers_out.content_length_n == 0) {
    r->header_only = 1;
  }

  if (ngx_http_set_content_type(r) != NGX_OK) {
    return NGX_HTTP_INTERNAL_SERVER_ERROR;
  }

#if (NGX_SUPPRESS_WARN)
  b = NULL;
#endif

  if (!r->header_only) {
    /* we need to allocate all before the header would be sent */

    if (!(b = ngx_pcalloc(r->pool, sizeof(ngx_buf_t)))) {
      return NGX_HTTP_INTERNAL_SERVER_ERROR;
    }

    if (!(b->file = ngx_pcalloc(r->pool, sizeof(ngx_file_t)))) {
      return NGX_HTTP_INTERNAL_SERVER_ERROR;
    }

    r->filter_allow_ranges = 1;
  }

  rc = ngx_http_send_header(r);

  if (rc == NGX_ERROR || rc > NGX_OK || r->header_only) {
    return rc;
  }

  b->in_file = 1;

  if (!r->main) {
    b->last_buf = 1;
  }

  b->file_pos = 0;
  b->file_last = ngx_file_size(&fi);

  b->file->fd = fd;
  b->file->log = log;

  out.buf = b;
  out.next = NULL;

  return ngx_http_output_filter(r, &out);
}
ngx_int_t ngx_http_small_light_imlib2_process(ngx_http_request_t *r, ngx_http_small_light_ctx_t *ctx)
{
    ngx_http_small_light_imlib2_ctx_t *ictx;
    ngx_http_small_light_image_size_t sz;
    Imlib_Image image_org, image_dst, image_tmp;
    Imlib_Load_Error err;
    ngx_file_info_t fi;
    ngx_fd_t fd;
    char *filename, *sharpen, *blur, *of, *buf;
    void *data;
    int w, h, radius, orientation;
    double iw, ih, q;
    ngx_int_t type;
    const char *ext;
    ssize_t size;

    ictx = (ngx_http_small_light_imlib2_ctx_t *)ctx->ictx;

    filename = (char *)ictx->tf->file.name.data;

    /* adjust image size */
    ngx_http_small_light_calc_image_size(r, ctx, &sz, 10000.0, 10000.0);

    if (sz.jpeghint_flg != 0) {
        if (ngx_http_small_light_load_jpeg((void**)&data, &w, &h, r, filename, sz.dw, sz.dh) != NGX_OK) {
            image_org = imlib_load_image_immediately_without_cache(filename);
            if (image_org == NULL) {
                ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
                              "failed to load image %s:%d",
                              __FUNCTION__,
                              __LINE__);
                return NGX_ERROR;
            }
        } else {
            image_org = imlib_create_image_using_data(w, h, data);
        }
    } else {
        image_org = imlib_load_image_immediately_without_cache(filename);
        if (image_org == NULL) {
            ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
                          "failed to load image %s:%d",
                          __FUNCTION__,
                          __LINE__);
            return NGX_ERROR;
        }
    }

    /* rotate. */
    if (sz.angle) {
        orientation = 0;
        switch (sz.angle) {
        case 90:
            orientation = 1;
            break;
        case 180:
            orientation = 2;
            break;
        case 270:
            orientation = 3;
            break;
        default:
            ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
                          "image not rotated. 'angle'(%d) must be 90 or 180 or 270. %s:%d",
                          sz.angle,
                          __FUNCTION__,
                          __LINE__);
            break;
        }

        imlib_context_set_image(image_org);
        imlib_image_orientate(orientation);
    }

    /* calc size. */
    imlib_context_set_image(image_org);
    iw = (double)imlib_image_get_width();
    ih = (double)imlib_image_get_height();
    ngx_http_small_light_calc_image_size(r, ctx, &sz, iw, ih);

    /* pass through. */
    if (sz.pt_flg != 0) {
        ctx->of = ctx->inf;
        return NGX_OK;
    }

    /* crop, scale. */
    if (sz.scale_flg != 0) {
        image_dst = imlib_create_cropped_scaled_image((int)sz.sx, (int)sz.sy, (int)sz.sw, (int)sz.sh, (int)sz.dw, (int)sz.dh);
        imlib_context_set_image(image_org);
        imlib_free_image();
    } else {
        image_dst = image_org;
    }

    if (image_dst == NULL) {
        ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
                      "imlib_create_cropped_scaled_image failed. %s:%d",
                      __FUNCTION__,
                      __LINE__);
        return NGX_ERROR;
    }

    /* create canvas then draw image to the canvas. */
    if (sz.cw > 0.0 && sz.ch > 0.0) {
        image_tmp = imlib_create_image(sz.cw, sz.ch);
        if (image_tmp == NULL) {
            imlib_context_set_image(image_dst);
            imlib_free_image();
            return NGX_ERROR;
        }
        imlib_context_set_image(image_tmp);
        imlib_context_set_color(sz.cc.r, sz.cc.g, sz.cc.b, sz.cc.a);
        imlib_image_fill_rectangle(0, 0, sz.cw, sz.ch);
        imlib_blend_image_onto_image(image_dst, 255, 0, 0,
                                     (int)sz.dw, (int)sz.dh, (int)sz.dx, (int)sz.dy, (int)sz.dw, (int)sz.dh);
        imlib_context_set_image(image_dst);
        imlib_free_image();
        image_dst = image_tmp;
    }

    /* effects. */
    sharpen = NGX_HTTP_SMALL_LIGHT_PARAM_GET_LIT(&ctx->hash, "sharpen");
    if (sharpen) {
        radius = ngx_http_small_light_parse_int(sharpen);
        if (radius > 0) {
            imlib_context_set_image(image_dst);
            imlib_image_sharpen(radius);
        }
    }

    blur = NGX_HTTP_SMALL_LIGHT_PARAM_GET_LIT(&ctx->hash, "blur");
    if (blur) {
        radius = ngx_http_small_light_parse_int(blur);
        if (radius > 0) {
            imlib_context_set_image(image_dst);
            imlib_image_blur(radius);
        }
    }

    /* border. */
    if (sz.bw > 0.0 || sz.bh > 0.0) {
        imlib_context_set_color(sz.bc.r, sz.bc.g, sz.bc.b, sz.bc.a);
        imlib_context_set_image(image_dst);
        if (sz.cw > 0.0 && sz.ch > 0.0) {
            imlib_image_fill_rectangle(0, 0, sz.cw, sz.bh);
            imlib_image_fill_rectangle(0, 0, sz.bw, sz.ch);
            imlib_image_fill_rectangle(0, sz.ch - sz.bh, sz.cw, sz.bh);
            imlib_image_fill_rectangle(sz.cw - sz.bw, 0, sz.bw, sz.ch);
        } else {
            imlib_image_fill_rectangle(0, 0, sz.dw, sz.bh);
            imlib_image_fill_rectangle(0, 0, sz.bw, sz.ch);
            imlib_image_fill_rectangle(0, sz.dh - sz.bh, sz.dw, sz.bh);
            imlib_image_fill_rectangle(sz.dw - sz.bw, 0, sz.bw, sz.dh);
        }
    }

    /* set params. */
    imlib_context_set_image(image_dst);
    q = ngx_http_small_light_parse_double(NGX_HTTP_SMALL_LIGHT_PARAM_GET_LIT(&ctx->hash, "q"));
    if (q > 0.0) {
        imlib_image_attach_data_value("quality", NULL, q, NULL);
    }

    of = NGX_HTTP_SMALL_LIGHT_PARAM_GET_LIT(&ctx->hash, "of");
    if (ngx_strlen(of) > 0) {
        type = ngx_http_small_light_type(of);
        if (type == NGX_HTTP_SMALL_LIGHT_IMAGE_NONE) {
            ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
                          "of is invalid(%s) %s:%d",
                          of,
                          __FUNCTION__,
                          __LINE__);
            of = (char *)ngx_http_small_light_image_exts[ictx->type - 1];
        } else if (type == NGX_HTTP_SMALL_LIGHT_IMAGE_WEBP) {
            ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
                          "WebP is not supported %s:%d",
                          __FUNCTION__,
                          __LINE__);
            of = (char *)ngx_http_small_light_image_exts[ictx->type - 1];
        } else {
            ictx->type = type;
        }
        imlib_image_set_format(of);
        ctx->of = ngx_http_small_light_image_types[ictx->type - 1];
    } else {
        ext = ngx_http_small_light_image_exts[ictx->type - 1];
        imlib_image_set_format(ext);
        ctx->of = ctx->inf;
    }

    /* save image. */
    imlib_save_image_with_error_return(filename, &err);
    imlib_free_image();

    /* check error. */
    if (err != IMLIB_LOAD_ERROR_NONE) {
        ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
                      "failed to imlib_save_error %s:%d",
                      __FUNCTION__,
                      __LINE__);
        return NGX_ERROR;
    }

    if (ngx_file_info(filename, &fi) == NGX_FILE_ERROR) {
        ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
                      "failed to ngx_file_info %s:%d",
                      __FUNCTION__,
                      __LINE__);
        return NGX_ERROR;
    }

    fd = ngx_open_file(filename, NGX_FILE_RDONLY, NGX_FILE_OPEN, 0);
    if (fd == NGX_INVALID_FILE) {
        ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
                      "failed to open fd %s:%d",
                      __FUNCTION__,
                      __LINE__);
        return NGX_ERROR;
    }

    if (ngx_fd_info(fd, &fi) == NGX_FILE_ERROR) {
        ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
                      "failed to ngx_fd_info %s:%d",
                      __FUNCTION__,
                      __LINE__);
        ngx_close_file(fd);
        return NGX_ERROR;
    } 

    buf = ngx_palloc(r->pool, ngx_file_size(&fi));
    if (buf == NULL) {
        ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
                      "failed to allocate memory from r->pool %s:%d",
                      __FUNCTION__,
                      __LINE__);
        ngx_close_file(fd);
        return NGX_ERROR;
    }
    size = ngx_read_fd(fd, buf, ngx_file_size(&fi));
    if (size == -1) {
        ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
                      "failed to ngx_read_fd %s:%d",
                      __FUNCTION__,
                      __LINE__);
        ngx_close_file(fd);
        return NGX_ERROR;
    }

    if ((size_t)size > ctx->content_length) {
        ctx->content = ngx_palloc(r->pool, size);
        if (ctx->content == NULL) {
            ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
                          "failed to allocate memory from r->pool %s:%d",
                          __FUNCTION__,
                          __LINE__);
            ngx_close_file(fd);
            return NGX_ERROR;
        }
    }

    ngx_memcpy(ctx->content, buf, size);

    ngx_close_file(fd);

    ctx->content_length = size;

    return NGX_OK;
}
Example #26
0
/*重新打开所有文件cycle->open_files*/
void
ngx_reopen_files(ngx_cycle_t *cycle, ngx_uid_t user)
{
    ngx_fd_t          fd;
    ngx_uint_t        i;
    ngx_list_part_t  *part;
    ngx_open_file_t  *file;

    part = &cycle->open_files.part;
    file = part->elts;

    for (i = 0; /* void */ ; i++) {

        if (i >= part->nelts) {
            if (part->next == NULL) {
                break;
            }
            part = part->next;
            file = part->elts;
            i = 0;
        }

        if (file[i].name.len == 0) {
            continue;
        }

        /*原有文件内容下盘*/
        if (file[i].flush) {
            file[i].flush(&file[i], cycle->log);
        }

        /*以追加方式打开文件*/
        fd = ngx_open_file(file[i].name.data, NGX_FILE_APPEND,
                           NGX_FILE_CREATE_OR_OPEN, NGX_FILE_DEFAULT_ACCESS);

        ngx_log_debug3(NGX_LOG_DEBUG_EVENT, cycle->log, 0,
                       "reopen file \"%s\", old:%d new:%d",
                       file[i].name.data, file[i].fd, fd);

        if (fd == NGX_INVALID_FILE) {
            ngx_log_error(NGX_LOG_EMERG, cycle->log, ngx_errno,
                          ngx_open_file_n " \"%s\" failed", file[i].name.data);
            continue;
        }

#if !(NGX_WIN32)
        if (user != (ngx_uid_t) NGX_CONF_UNSET_UINT) {
            ngx_file_info_t  fi;

            /*获取文件信息,如所有者,权限等*/
            if (ngx_file_info((const char *) file[i].name.data, &fi)
                == NGX_FILE_ERROR)
            {
                ngx_log_error(NGX_LOG_EMERG, cycle->log, ngx_errno,
                              ngx_file_info_n " \"%s\" failed",
                              file[i].name.data);

                if (ngx_close_file(fd) == NGX_FILE_ERROR) {
                    ngx_log_error(NGX_LOG_EMERG, cycle->log, ngx_errno,
                                  ngx_close_file_n " \"%s\" failed",
                                  file[i].name.data);
                }

                continue;
            }

            /*修改文件所有者*/
            if (fi.st_uid != user) {
                if (chown((const char *) file[i].name.data, user, -1) == -1) {
                    ngx_log_error(NGX_LOG_EMERG, cycle->log, ngx_errno,
                                  "chown(\"%s\", %d) failed",
                                  file[i].name.data, user);

                    if (ngx_close_file(fd) == NGX_FILE_ERROR) {
                        ngx_log_error(NGX_LOG_EMERG, cycle->log, ngx_errno,
                                      ngx_close_file_n " \"%s\" failed",
                                      file[i].name.data);
                    }

                    continue;
                }
            }

            /*修改文件权限*/
            if ((fi.st_mode & (S_IRUSR|S_IWUSR)) != (S_IRUSR|S_IWUSR)) {

                fi.st_mode |= (S_IRUSR|S_IWUSR);

                if (chmod((const char *) file[i].name.data, fi.st_mode) == -1) {
                    ngx_log_error(NGX_LOG_EMERG, cycle->log, ngx_errno,
                                  "chmod() \"%s\" failed", file[i].name.data);

                    if (ngx_close_file(fd) == NGX_FILE_ERROR) {
                        ngx_log_error(NGX_LOG_EMERG, cycle->log, ngx_errno,
                                      ngx_close_file_n " \"%s\" failed",
                                      file[i].name.data);
                    }

                    continue;
                }
            }
        }

        /*F_SETFD 设置close-on-exec 旗标。该旗标以参数arg 的FD_CLOEXEC位决定。*/
        /*
         * lose_on_exec 是一个进程所有文件描述符(文件句柄)的位图标志,每个比特位代表一个打开的文件描述符,
         * 用于确定在调用系统调用execve()时需要关闭的文件句柄
         */
        if (fcntl(fd, F_SETFD, FD_CLOEXEC) == -1) {
            ngx_log_error(NGX_LOG_EMERG, cycle->log, ngx_errno,
                          "fcntl(FD_CLOEXEC) \"%s\" failed",
                          file[i].name.data);

            if (ngx_close_file(fd) == NGX_FILE_ERROR) {
                ngx_log_error(NGX_LOG_EMERG, cycle->log, ngx_errno,
                              ngx_close_file_n " \"%s\" failed",
                              file[i].name.data);
            }

            continue;
        }
#endif

        /*关闭文件*/
        if (ngx_close_file(file[i].fd) == NGX_FILE_ERROR) {
            ngx_log_error(NGX_LOG_EMERG, cycle->log, ngx_errno,
                          ngx_close_file_n " \"%s\" failed",
                          file[i].name.data);
        }

        file[i].fd = fd;
    }

    /*重定向标准错误输出*/
    (void) ngx_log_redirect_stderr(cycle);
}
Example #27
0
ngx_int_t
ngx_create_paths(ngx_cycle_t *cycle, ngx_uid_t user)
{
    ngx_err_t         err;
    ngx_uint_t        i;
    ngx_path_t      **path;

    path = cycle->paths.elts;
    for (i = 0; i < cycle->paths.nelts; i++) {

        if (ngx_create_dir(path[i]->name.data, 0700) == NGX_FILE_ERROR) {
            err = ngx_errno;
            if (err != NGX_EEXIST) {
                ngx_log_error(NGX_LOG_EMERG, cycle->log, err,
                              ngx_create_dir_n " \"%s\" failed",
                              path[i]->name.data);
                return NGX_ERROR;
            }
        }

        if (user == (ngx_uid_t) NGX_CONF_UNSET_UINT) {
            continue;
        }

#if !(NGX_WIN32)
        {
        ngx_file_info_t   fi;

        if (ngx_file_info((const char *) path[i]->name.data, &fi)
            == NGX_FILE_ERROR)
        {
            ngx_log_error(NGX_LOG_EMERG, cycle->log, ngx_errno,
                          ngx_file_info_n " \"%s\" failed", path[i]->name.data);
            return NGX_ERROR;
        }

        if (fi.st_uid != user) {
            if (chown((const char *) path[i]->name.data, user, -1) == -1) {
                ngx_log_error(NGX_LOG_EMERG, cycle->log, ngx_errno,
                              "chown(\"%s\", %d) failed",
                              path[i]->name.data, user);
                return NGX_ERROR;
            }
        }

        if ((fi.st_mode & (S_IRUSR|S_IWUSR|S_IXUSR))
                                                  != (S_IRUSR|S_IWUSR|S_IXUSR))
        {
            fi.st_mode |= (S_IRUSR|S_IWUSR|S_IXUSR);

            if (chmod((const char *) path[i]->name.data, fi.st_mode) == -1) {
                ngx_log_error(NGX_LOG_EMERG, cycle->log, ngx_errno,
                              "chmod() \"%s\" failed", path[i]->name.data);
                return NGX_ERROR;
            }
        }
        }
#endif
    }

    return NGX_OK;
}
static ngx_int_t
ngx_rtmp_dash_cleanup_dir(ngx_str_t *ppath, ngx_msec_t playlen)
{
    time_t           mtime, max_age;
    u_char          *p;
    u_char           path[NGX_MAX_PATH + 1], mpd_path[NGX_MAX_PATH + 1];
    ngx_dir_t        dir;
    ngx_err_t        err;
    ngx_str_t        name, spath, mpd;
    ngx_int_t        nentries, nerased;
    ngx_file_info_t  fi;

    ngx_log_debug2(NGX_LOG_DEBUG_RTMP, ngx_cycle->log, 0,
                   "dash: cleanup path='%V' playlen=%M", ppath, playlen);

    if (ngx_open_dir(ppath, &dir) != NGX_OK) {
        ngx_log_debug1(NGX_LOG_DEBUG_RTMP, ngx_cycle->log, ngx_errno,
                       "dash: cleanup open dir failed '%V'", ppath);
        return NGX_ERROR;
    }

    nentries = 0;
    nerased = 0;

    for ( ;; ) {
        ngx_set_errno(0);

        if (ngx_read_dir(&dir) == NGX_ERROR) {
            err = ngx_errno;

            if (ngx_close_dir(&dir) == NGX_ERROR) {
                ngx_log_error(NGX_LOG_CRIT, ngx_cycle->log, ngx_errno,
                              "dash: cleanup " ngx_close_dir_n " \"%V\" failed",
                              ppath);
            }

            if (err == NGX_ENOMOREFILES) {
                return nentries - nerased;
            }

            ngx_log_error(NGX_LOG_CRIT, ngx_cycle->log, err,
                          "dash: cleanup " ngx_read_dir_n
                          " '%V' failed", ppath);
            return NGX_ERROR;
        }

        name.data = ngx_de_name(&dir);
        if (name.data[0] == '.') {
            continue;
        }

        name.len = ngx_de_namelen(&dir);

        p = ngx_snprintf(path, sizeof(path) - 1, "%V/%V", ppath, &name);
        *p = 0;

        spath.data = path;
        spath.len = p - path;

        nentries++;

        if (!dir.valid_info && ngx_de_info(path, &dir) == NGX_FILE_ERROR) {
            ngx_log_error(NGX_LOG_CRIT, ngx_cycle->log, ngx_errno,
                          "dash: cleanup " ngx_de_info_n " \"%V\" failed",
                          &spath);

            continue;
        }

        if (ngx_de_is_dir(&dir)) {

            if (ngx_rtmp_dash_cleanup_dir(&spath, playlen) == 0) {
                ngx_log_debug1(NGX_LOG_DEBUG_RTMP, ngx_cycle->log, 0,
                               "dash: cleanup dir '%V'", &name);

                /*
                 * null-termination gets spoiled in win32
                 * version of ngx_open_dir
                 */

                *p = 0;

                if (ngx_delete_dir(path) == NGX_FILE_ERROR) {
                    ngx_log_error(NGX_LOG_ERR, ngx_cycle->log, ngx_errno,
                                  "dash: cleanup " ngx_delete_dir_n
                                  " failed on '%V'", &spath);
                } else {
                    nerased++;
                }
            }

            continue;
        }

        if (!ngx_de_is_file(&dir)) {
            continue;
        }

        if (name.len >= 8 && name.data[name.len - 8] == 'i' &&
                             name.data[name.len - 7] == 'n' &&
                             name.data[name.len - 6] == 'i' &&
                             name.data[name.len - 5] == 't' &&
                             name.data[name.len - 4] == '.' &&
                             name.data[name.len - 3] == 'm' &&
                             name.data[name.len - 2] == '4')
        {
            if (name.len == 8) {
                ngx_str_set(&mpd, "index");
            } else {
                mpd.data = name.data;
                mpd.len = name.len - 9;
            }

            p = ngx_snprintf(mpd_path, sizeof(mpd_path) - 1, "%V/%V.mpd",
                             ppath, &mpd);
            *p = 0;

            if (ngx_file_info(mpd_path, &fi) != NGX_FILE_ERROR) {
                ngx_log_debug2(NGX_LOG_DEBUG_RTMP, ngx_cycle->log, 0,
                               "dash: cleanup '%V' delayed, mpd exists '%s'",
                               &name, mpd_path);
                continue;
            }

            ngx_log_debug2(NGX_LOG_DEBUG_RTMP, ngx_cycle->log, 0,
                           "dash: cleanup '%V' allowed, mpd missing '%s'",
                           &name, mpd_path);

            max_age = 0;

        } else if (name.len >= 4 && name.data[name.len - 4] == '.' &&
                                    name.data[name.len - 3] == 'm' &&
                                    name.data[name.len - 2] == '4' &&
                                    name.data[name.len - 1] == 'v')
        {
            max_age = playlen / 500;

        } else if (name.len >= 4 && name.data[name.len - 4] == '.' &&
                                    name.data[name.len - 3] == 'm' &&
                                    name.data[name.len - 2] == '4' &&
                                    name.data[name.len - 1] == 'a')
        {
            max_age = playlen / 500;

        } else if (name.len >= 4 && name.data[name.len - 4] == '.' &&
                                    name.data[name.len - 3] == 'm' &&
                                    name.data[name.len - 2] == 'p' &&
                                    name.data[name.len - 1] == 'd')
        {
            max_age = playlen / 500;

        } else if (name.len >= 4 && name.data[name.len - 4] == '.' &&
                                    name.data[name.len - 3] == 'r' &&
                                    name.data[name.len - 2] == 'a' &&
                                    name.data[name.len - 1] == 'w')
        {
            max_age = playlen / 1000;

        } else {
            ngx_log_debug1(NGX_LOG_DEBUG_RTMP, ngx_cycle->log, 0,
                           "dash: cleanup skip unknown file type '%V'", &name);
            continue;
        }

        mtime = ngx_de_mtime(&dir);
        if (mtime + max_age > ngx_cached_time->sec) {
            continue;
        }

        ngx_log_debug3(NGX_LOG_DEBUG_RTMP, ngx_cycle->log, 0,
                       "dash: cleanup '%V' mtime=%T age=%T",
                       &name, mtime, ngx_cached_time->sec - mtime);

        if (ngx_delete_file(path) == NGX_FILE_ERROR) {
            ngx_log_error(NGX_LOG_ERR, ngx_cycle->log, ngx_errno,
                          "dash: cleanup " ngx_delete_file_n " failed on '%V'",
                          &spath);
            continue;
        }

        nerased++;
    }
}
Example #29
0
static void
ngx_http_dav_put_handler(ngx_http_request_t *r)
{
    size_t                    root;
    time_t                    date;
    ngx_str_t                *temp, path;
    ngx_uint_t                status;
    ngx_file_info_t           fi;
    ngx_ext_rename_file_t     ext;
    ngx_http_dav_loc_conf_t  *dlcf;

    if (r->request_body == NULL || r->request_body->temp_file == NULL) {
        ngx_http_finalize_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR);
        return;
    }

    ngx_http_map_uri_to_path(r, &path, &root, 0);

    path.len--;

    ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
                   "http put filename: \"%s\"", path.data);

    temp = &r->request_body->temp_file->file.name;

    if (ngx_file_info(path.data, &fi) == NGX_FILE_ERROR) {
        status = NGX_HTTP_CREATED;

    } else {
        status = NGX_HTTP_NO_CONTENT;

        if (ngx_is_dir(&fi)) {
            ngx_log_error(NGX_LOG_ERR, r->connection->log, NGX_EISDIR,
                          "\"%s\" could not be created", path.data);

            if (ngx_delete_file(temp->data) == NGX_FILE_ERROR) {
                ngx_log_error(NGX_LOG_CRIT, r->connection->log, ngx_errno,
                              ngx_delete_file_n " \"%s\" failed",
                              temp->data);
            }

            ngx_http_finalize_request(r, NGX_HTTP_CONFLICT);
            return;
        }
    }

    dlcf = ngx_http_get_module_loc_conf(r, ngx_http_dav_module);

    ext.access = dlcf->access;
    ext.path_access = dlcf->access;
    ext.time = -1;
    ext.create_path = dlcf->create_full_put_path;
    ext.delete_file = 1;
    ext.log = r->connection->log;

    if (r->headers_in.date) {
        date = ngx_http_parse_time(r->headers_in.date->value.data,
                                   r->headers_in.date->value.len);

        if (date != NGX_ERROR) {
            ext.time = date;
            ext.fd = r->request_body->temp_file->file.fd;
        }
    }

    if (ngx_ext_rename_file(temp, &path, &ext) != NGX_OK) {
        ngx_http_finalize_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR);
        return;
    }

    if (status == NGX_HTTP_CREATED) {
        if (ngx_http_dav_location(r, path.data) != NGX_OK) {
            ngx_http_finalize_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR);
            return;
        }

        r->headers_out.content_length_n = 0;
    }

    r->headers_out.status = status;
    r->header_only = 1;

    ngx_http_finalize_request(r, ngx_http_send_header(r));
    return;
}
Example #30
0
static ngx_int_t
ngx_rtmp_record_ensure_directory(ngx_rtmp_session_t *s, ngx_str_t *path)
{
    size_t                    len;
    ngx_file_info_t           fi;
    ngx_rtmp_record_ctx_t       *ctx;
    ngx_rtmp_record_app_conf_t  *hacf;

    static u_char  zpath[NGX_MAX_PATH + 1] = {0};

    hacf = ngx_rtmp_get_module_app_conf(s, ngx_rtmp_record_module);

    if (path->len + 1 > sizeof(zpath)) {
        ngx_log_error(NGX_LOG_ERR, s->connection->log, 0, "record: too long path");
        return NGX_ERROR;
    }

    ngx_snprintf(zpath, sizeof(zpath), "%V%Z", path);

    if (ngx_file_info(zpath, &fi) == NGX_FILE_ERROR) {

        if (ngx_errno != NGX_ENOENT) {
            ngx_log_error(NGX_LOG_ERR, s->connection->log, ngx_errno,
                          "record: " ngx_file_info_n " failed on '%V'", path);
            return NGX_ERROR;
        }

        /* ENOENT */

        if (ngx_create_full_path(zpath, NGX_RTMP_RECORD_DIR_ACCESS) == NGX_FILE_ERROR) {
            ngx_log_error(NGX_LOG_ERR, s->connection->log, ngx_errno,
                          "record: " ngx_create_dir_n " failed on '%V'", path);
            return NGX_ERROR;
        }

        ngx_log_debug1(NGX_LOG_DEBUG_RTMP, s->connection->log, 0,
                       "record: directory '%V' created", path);

    } else {

        if (!ngx_is_dir(&fi)) {
            ngx_log_error(NGX_LOG_ERR, s->connection->log, 0,
                          "record: '%V' exists and is not a directory", path);
            return  NGX_ERROR;
        }

        ngx_log_debug1(NGX_LOG_DEBUG_RTMP, s->connection->log, 0,
                       "record: directory '%V' exists", path);
    }

    ctx = ngx_rtmp_get_module_ctx(s, ngx_rtmp_record_module);

    len = path->len;
    if (path->data[len - 1] == '/') {
        len--;
    }

    if (len + 1 + ngx_strlen(ctx->name) + 1 > sizeof(zpath)) {
        ngx_log_error(NGX_LOG_ERR, s->connection->log, 0, "record: too long path");
        return NGX_ERROR;
    }

    ngx_snprintf(zpath, sizeof(zpath) - 1, "%*s/%s%Z", len, path->data,
                 ctx->name);

    if (ngx_file_info(zpath, &fi) != NGX_FILE_ERROR) {

        if (ngx_is_dir(&fi)) {
            ngx_log_debug1(NGX_LOG_DEBUG_RTMP, s->connection->log, 0,
                           "record: directory '%s' exists", zpath);
            return NGX_OK;
        }

        ngx_log_error(NGX_LOG_ERR, s->connection->log, 0,
                      "record: '%s' exists and is not a directory", zpath);

        return  NGX_ERROR;
    }

    if (ngx_errno != NGX_ENOENT) {
        ngx_log_error(NGX_LOG_ERR, s->connection->log, ngx_errno,
                      "record: " ngx_file_info_n " failed on '%s'", zpath);
        return NGX_ERROR;
    }

    /* NGX_ENOENT */

    if (ngx_create_full_path(zpath, NGX_RTMP_RECORD_DIR_ACCESS) == NGX_FILE_ERROR) {
        ngx_log_error(NGX_LOG_ERR, s->connection->log, ngx_errno,
                      "record: " ngx_create_dir_n " failed on '%s'", zpath);
        return NGX_ERROR;
    }

    ngx_log_debug1(NGX_LOG_DEBUG_RTMP, s->connection->log, 0,
                   "record: directory '%s' created", zpath);

    return NGX_OK;
}