Пример #1
0
static ngx_int_t
ngx_http_srcache_set_content_length_header(ngx_http_request_t *r, off_t len)
{
    ngx_table_elt_t                 *h, *header;
    u_char                          *p;
    ngx_list_part_t                 *part;
    ngx_http_request_t              *pr;
    ngx_uint_t                       i;

    r->headers_in.content_length_n = len;

    if (ngx_list_init(&r->headers_in.headers, r->pool, 20,
                      sizeof(ngx_table_elt_t))
        != NGX_OK)
    {
        return NGX_ERROR;
    }

    h = ngx_list_push(&r->headers_in.headers);
    if (h == NULL) {
        return NGX_ERROR;
    }

    h->key = ngx_http_srcache_content_length_header_key;
    h->lowcase_key = ngx_pnalloc(r->pool, h->key.len);
    if (h->lowcase_key == NULL) {
        return NGX_ERROR;
    }

    ngx_strlow(h->lowcase_key, h->key.data, h->key.len);

    r->headers_in.content_length = h;

    p = ngx_palloc(r->pool, NGX_OFF_T_LEN);
    if (p == NULL) {
        return NGX_ERROR;
    }

    h->value.data = p;

    h->value.len = ngx_sprintf(h->value.data, "%O", len) - h->value.data;

    h->hash = ngx_hash(ngx_hash(ngx_hash(ngx_hash(ngx_hash(ngx_hash(ngx_hash(
            ngx_hash(ngx_hash(ngx_hash(ngx_hash(ngx_hash(
            ngx_hash('c', 'o'), 'n'), 't'), 'e'), 'n'), 't'), '-'), 'l'), 'e'),
            'n'), 'g'), 't'), 'h');

    dd("r content length: %.*s",
       (int)r->headers_in.content_length->value.len,
       r->headers_in.content_length->value.data);

    pr = r->parent;

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

    /* forward the parent request's all other request headers */

    part = &pr->headers_in.headers.part;
    header = part->elts;

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

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

            part = part->next;
            header = part->elts;
            i = 0;
        }

        if (header[i].key.len == sizeof("Content-Length") - 1
            && ngx_strncasecmp(header[i].key.data,
                               (u_char *) "Content-Length",
                               sizeof("Content-Length") - 1) == 0)
        {
            continue;
        }

        h = ngx_list_push(&r->headers_in.headers);
        if (h == NULL) {
            return NGX_ERROR;
        }

        *h = header[i];
    }

    /* XXX maybe we should set those built-in header slot in
     * ngx_http_headers_in_t too? */

    return NGX_OK;
}
static ngx_int_t
ngx_http_push_stream_send_response_all_channels_info_detailed(ngx_http_request_t *r, ngx_str_t *prefix) {
    ngx_int_t                                 rc, content_len = 0;
    ngx_chain_t                              *chain, *first = NULL, *last = NULL;
    ngx_str_t                                *currenttime, *hostname, *text, *header_response;
    ngx_queue_t                               queue_channel_info;
    ngx_queue_t                              *cur, *next;
    ngx_http_push_stream_shm_data_t          *data = (ngx_http_push_stream_shm_data_t *) ngx_http_push_stream_shm_zone->data;
    ngx_slab_pool_t                          *shpool = (ngx_slab_pool_t *) ngx_http_push_stream_shm_zone->shm.addr;
    ngx_http_push_stream_content_subtype_t   *subtype = ngx_http_push_stream_match_channel_info_format_and_content_type(r, 1);
    ngx_pool_t                               *temp_pool = ngx_http_push_stream_get_temp_pool(r);

    const ngx_str_t *format;
    const ngx_str_t *head = subtype->format_group_head;
    const ngx_str_t *tail = subtype->format_group_tail;

    ngx_queue_init(&queue_channel_info);

    ngx_shmtx_lock(&shpool->mutex);
    ngx_http_push_stream_rbtree_walker_channel_info_locked(&data->tree, temp_pool, data->tree.root, &queue_channel_info, prefix);
    ngx_shmtx_unlock(&shpool->mutex);

    // format content body
    cur = ngx_queue_head(&queue_channel_info);
    while (cur != &queue_channel_info) {
        next = ngx_queue_next(cur);
        ngx_http_push_stream_channel_info_t *channel_info = (ngx_http_push_stream_channel_info_t *) cur;
        if ((chain = ngx_http_push_stream_get_buf(r)) == NULL) {
            ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "push stream module: unable to allocate memory for response channels info");
            return NGX_HTTP_INTERNAL_SERVER_ERROR;
        }

        format = (next != &queue_channel_info) ? subtype->format_group_item : subtype->format_group_last_item;
        if ((text = ngx_http_push_stream_channel_info_formatted(temp_pool, format, &channel_info->id, channel_info->published_messages, channel_info->stored_messages, channel_info->subscribers)) == NULL) {
            ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "push stream module: unable to allocate memory to format channel info");
            return NGX_HTTP_INTERNAL_SERVER_ERROR;
        }

        chain->buf->last_buf = 0;
        chain->buf->memory = 1;
        chain->buf->pos = text->data;
        chain->buf->last = text->data + text->len;
        chain->buf->start = chain->buf->pos;
        chain->buf->end = chain->buf->last;

        content_len += text->len;

        if (first == NULL) {
            first = chain;
        }

        if (last != NULL) {
            last->next = chain;
        }

        last = chain;
        cur = next;
    }

    // get formatted current time
    currenttime = ngx_http_push_stream_get_formatted_current_time(temp_pool);

    // get formatted hostname
    hostname = ngx_http_push_stream_get_formatted_hostname(temp_pool);

    // format content header
    if ((header_response = ngx_http_push_stream_create_str(temp_pool, head->len + hostname->len + currenttime->len + NGX_INT_T_LEN)) == NULL) {
        ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "push stream module: unable to allocate memory for response channels info");
        return NGX_HTTP_INTERNAL_SERVER_ERROR;
    }

    ngx_sprintf(header_response->data, (char *) head->data, hostname->data, currenttime->data, data->channels, data->broadcast_channels, ngx_time() - data->startup);
    header_response->len = ngx_strlen(header_response->data);

    content_len += header_response->len + tail->len;

    r->headers_out.content_type.len = subtype->content_type->len;
    r->headers_out.content_type.data = subtype->content_type->data;
    r->headers_out.content_length_n = content_len;
    r->headers_out.status = NGX_HTTP_OK;

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

    // send content header
    ngx_http_push_stream_send_response_text(r, header_response->data, header_response->len,0);
    // send content body
    if (first != NULL) {
        ngx_http_push_stream_output_filter(r, first);
    }
    // send content footer
    return ngx_http_push_stream_send_response_text(r, tail->data, tail->len, 1);
}
Пример #3
0
ngx_pid_t
ngx_exec_new_binary(ngx_cycle_t *cycle, char *const *argv)
{
	char             **env, *var;
	u_char            *p;
	ngx_uint_t         i, n;
	ngx_pid_t          pid;
	ngx_exec_ctx_t     ctx;
	ngx_core_conf_t   *ccf;
	ngx_listening_t   *ls;

	ngx_memzero(&ctx, sizeof(ngx_exec_ctx_t));

	ctx.path = argv[0];
	ctx.name = "new binary process";
	ctx.argv = argv;

	n = 2;
	env = ngx_set_environment(cycle, &n);
	if (env == NULL) {
		return NGX_INVALID_PID;
	}

	var = ngx_alloc(sizeof(NGINX_VAR)
			+ cycle->listening.nelts * (NGX_INT32_LEN + 1) + 2,
			cycle->log);
	if (var == NULL) {
		ngx_free(env);
		return NGX_INVALID_PID;
	}

	p = ngx_cpymem(var, NGINX_VAR "=", sizeof(NGINX_VAR));

	ls = cycle->listening.elts;
	for (i = 0; i < cycle->listening.nelts; i++) {
		p = ngx_sprintf(p, "%ud;", ls[i].fd);
	}

	*p = '\0';

	env[n++] = var;

#if (NGX_SETPROCTITLE_USES_ENV)

	/* allocate the spare 300 bytes for the new binary process title */

	env[n++] = "SPARE=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"
		"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"
		"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"
		"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"
		"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX";

#endif

	env[n] = NULL;

#if (NGX_DEBUG)
	{
		char  **e;
		for (e = env; *e; e++) {
			ngx_log_debug1(NGX_LOG_DEBUG_CORE, cycle->log, 0, "env: %s", *e);
		}
	}
#endif

	ctx.envp = (char *const *) env;

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

	if (ngx_rename_file(ccf->pid.data, ccf->oldpid.data) == NGX_FILE_ERROR) {
		ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno,
			      ngx_rename_file_n " %s to %s failed "
			      "before executing new binary process \"%s\"",
			      ccf->pid.data, ccf->oldpid.data, argv[0]);

		ngx_free(env);
		ngx_free(var);

		return NGX_INVALID_PID;
	}

	pid = ngx_execute(cycle, &ctx);

	if (pid == NGX_INVALID_PID) {
		if (ngx_rename_file(ccf->oldpid.data, ccf->pid.data)
		    == NGX_FILE_ERROR)
		{
			ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno,
				      ngx_rename_file_n " %s back to %s failed after "
				      "an attempt to execute new binary process \"%s\"",
				      ccf->oldpid.data, ccf->pid.data, argv[0]);
		}
	}

	ngx_free(env);
	ngx_free(var);

	return pid;
}
Пример #4
0
static int
ngx_http_lua_ngx_req_body_finish(lua_State *L)
{
    ngx_http_request_t          *r;
    int                          n;
    ngx_http_request_body_t     *rb;
    ngx_buf_t                   *b;
    size_t                      size;
    ngx_str_t                   value;
    ngx_str_t                   key;
    ngx_int_t                   rc;

    n = lua_gettop(L);

    if (n != 0) {
        return luaL_error(L, "expecting 0 argument but seen %d", n);
    }

    r = ngx_http_lua_get_req(L);
    if (r == NULL) {
        return luaL_error(L, "no request found");
    }

    ngx_http_lua_check_fake_request(L, r);

    if (r->request_body == NULL
        || r->request_body->buf == NULL
        || r->request_body->bufs == NULL)
    {
        return luaL_error(L, "request_body not initalized");
    }

    rb = r->request_body;

    if (rb->temp_file) {

        /* save the last part */

        if (ngx_http_lua_write_request_body(r, rb->bufs) != NGX_OK) {
            return luaL_error(L, "fail to write file");
        }

        b = ngx_calloc_buf(r->pool);
        if (b == NULL) {
            return luaL_error(L, "no memory");
        }

        b->in_file = 1;
        b->file_pos = 0;
        b->file_last = rb->temp_file->file.offset;
        b->file = &rb->temp_file->file;

        if (rb->bufs->next) {
            rb->bufs->next->buf = b;

        } else {
            rb->bufs->buf = b;
        }
    }

    /* override input header Content-Length (value must be null terminated) */

    value.data = ngx_palloc(r->pool, NGX_SIZE_T_LEN + 1);
    if (value.data == NULL) {
        return luaL_error(L, "no memory");
    }

    size = (size_t) r->headers_in.content_length_n;

    value.len = ngx_sprintf(value.data, "%uz", size) - value.data;
    value.data[value.len] = '\0';

    dd("setting request Content-Length to %.*s (%d)", (int) value.len,
       value.data, (int) size);

    if (r->headers_in.content_length) {
        r->headers_in.content_length->value.data = value.data;
        r->headers_in.content_length->value.len = value.len;

    } else {

        ngx_str_set(&key, "Content-Length");

        rc = ngx_http_lua_set_input_header(r, key, value, 1 /* override */);
        if (rc != NGX_OK) {
            return luaL_error(L, "failed to reset the Content-Length "
                              "input header");
        }
    }

    return 0;

}
static char *
ngx_http_eval_block(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
{
    ngx_http_eval_loc_conf_t  *ecf, *pecf = conf;

    char                      *rv;
    void                      *mconf;
    ngx_str_t                  name;
    ngx_uint_t                 i;
    ngx_conf_t                 save;
    ngx_http_module_t         *module;
    ngx_http_conf_ctx_t       *ctx, *pctx;
    ngx_http_core_loc_conf_t  *clcf, *pclcf, *rclcf;
    ngx_http_core_srv_conf_t  *cscf;

    ctx = ngx_pcalloc(cf->pool, sizeof(ngx_http_conf_ctx_t));
    if (ctx == NULL) {
        return NGX_CONF_ERROR;
    }

    pctx = cf->ctx;
    ctx->main_conf = pctx->main_conf;
    ctx->srv_conf = pctx->srv_conf;

    ctx->loc_conf = ngx_pcalloc(cf->pool, sizeof(void *) * ngx_http_max_module);
    if (ctx->loc_conf == NULL) {
        return NGX_CONF_ERROR;
    }

    for (i = 0; ngx_modules[i]; i++) {
        if (ngx_modules[i]->type != NGX_HTTP_MODULE) {
            continue;
        }

        module = ngx_modules[i]->ctx;

        if (module->create_loc_conf) {

            mconf = module->create_loc_conf(cf);
            if (mconf == NULL) {
                 return NGX_CONF_ERROR;
            }

            ctx->loc_conf[ngx_modules[i]->ctx_index] = mconf;
        }
    }

    ecf = ctx->loc_conf[ngx_http_eval_module.ctx_index];

    pclcf = pctx->loc_conf[ngx_http_core_module.ctx_index];

    clcf = ctx->loc_conf[ngx_http_core_module.ctx_index];

    name.len = sizeof("/eval_") - 1 + NGX_OFF_T_LEN;

    name.data = ngx_palloc(cf->pool, name.len);

    if(name.data == NULL) {
        return NGX_CONF_ERROR;
    }

    name.len = ngx_sprintf(name.data, "/eval_%O", (off_t)(uintptr_t)clcf) - name.data;

    clcf->loc_conf = ctx->loc_conf;
    clcf->name = name;
    clcf->exact_match = 0;
    clcf->noname = 0;
    clcf->internal = 1;
    clcf->noregex = 1;

    cscf = ngx_http_conf_get_module_srv_conf(cf, ngx_http_core_module);

    rclcf = cscf->ctx->loc_conf[ngx_http_core_module.ctx_index];

    if (ngx_http_add_location(cf, &rclcf->locations, clcf) != NGX_OK) {
        return NGX_CONF_ERROR;
    }

    if(ngx_http_eval_add_block(cf, pecf, &clcf->name) != NGX_OK) {
        return NGX_CONF_ERROR;
    }

    save = *cf;
    cf->ctx = ctx;
    cf->cmd_type = NGX_HTTP_LOC_CONF;

    rv = ngx_conf_parse(cf, NULL);

    *cf = save;

    return rv;
}
Пример #6
0
ngx_int_t
ngx_ext_rename_file(ngx_str_t *src, ngx_str_t *to, ngx_ext_rename_file_t *ext)
{
    u_char           *name;
    ngx_err_t         err;
    ngx_copy_file_t   cf;

#if !(NGX_WIN32)

    if (ext->access) {
        if (ngx_change_file_access(src->data, ext->access) == NGX_FILE_ERROR) {
            ngx_log_error(NGX_LOG_CRIT, ext->log, ngx_errno,
                          ngx_change_file_access_n " \"%s\" failed", src->data);
            err = 0;
            goto failed;
        }
    }

#endif

    if (ext->time != -1) {
        if (ngx_set_file_time(src->data, ext->fd, ext->time) != NGX_OK) {
            ngx_log_error(NGX_LOG_CRIT, ext->log, ngx_errno,
                          ngx_set_file_time_n " \"%s\" failed", src->data);
            err = 0;
            goto failed;
        }
    }

    if (ngx_rename_file(src->data, to->data) != NGX_FILE_ERROR) {
        return NGX_OK;
    }

    err = ngx_errno;

    if (err == NGX_ENOPATH) {

        if (!ext->create_path) {
            goto failed;
        }

        err = ngx_create_full_path(to->data, ngx_dir_access(ext->path_access));

        if (err) {
            ngx_log_error(NGX_LOG_CRIT, ext->log, err,
                          ngx_create_dir_n " \"%s\" failed", to->data);
            err = 0;
            goto failed;
        }

        if (ngx_rename_file(src->data, to->data) != NGX_FILE_ERROR) {
            return NGX_OK;
        }

        err = ngx_errno;
    }

#if (NGX_WIN32)

    if (err == NGX_EEXIST) {
        err = ngx_win32_rename_file(src, to, ext->log);

        if (err == 0) {
            return NGX_OK;
        }
    }

#endif

    if (err == NGX_EXDEV) {

        cf.size = -1;
        cf.buf_size = 0;
        cf.access = ext->access;
        cf.time = ext->time;
        cf.log = ext->log;

        name = ngx_alloc(to->len + 1 + 10 + 1, ext->log);
        if (name == NULL) {
            return NGX_ERROR;
        }

        (void) ngx_sprintf(name, "%*s.%010uD%Z", to->len, to->data,
                           (uint32_t) ngx_next_temp_number(0));

        if (ngx_copy_file(src->data, name, &cf) == NGX_OK) {

            if (ngx_rename_file(name, to->data) != NGX_FILE_ERROR) {
                ngx_free(name);

                if (ngx_delete_file(src->data) == NGX_FILE_ERROR) {
                    ngx_log_error(NGX_LOG_CRIT, ext->log, ngx_errno,
                                  ngx_delete_file_n " \"%s\" failed",
                                  src->data);
                    return NGX_ERROR;
                }

                return NGX_OK;
            }

            ngx_log_error(NGX_LOG_CRIT, ext->log, ngx_errno,
                          ngx_rename_file_n " \"%s\" to \"%s\" failed",
                          name, to->data);

            if (ngx_delete_file(name) == NGX_FILE_ERROR) {
                ngx_log_error(NGX_LOG_CRIT, ext->log, ngx_errno,
                              ngx_delete_file_n " \"%s\" failed", name);

            }
        }

        ngx_free(name);

        err = 0;
    }

failed:

    if (ext->delete_file) {
        if (ngx_delete_file(src->data) == NGX_FILE_ERROR) {
            ngx_log_error(NGX_LOG_CRIT, ext->log, ngx_errno,
                          ngx_delete_file_n " \"%s\" failed", src->data);
        }
    }

    if (err) {
        ngx_log_error(NGX_LOG_CRIT, ext->log, err,
                      ngx_rename_file_n " \"%s\" to \"%s\" failed",
                      src->data, to->data);
    }

    return NGX_ERROR;
}
u_char *
ngx_http_req_stat_request_length(ngx_http_request_t *r, u_char *buf,
    ngx_http_req_stat_op_t *op)
{
    return ngx_sprintf(buf, "%O", r->request_length);
}
void
ngx_log_error_coreall(ngx_uint_t level, ngx_log_t *log, const char* filename, int lineno, ngx_err_t err,
    const char *fmt, va_list args)

#endif

{
#if (NGX_HAVE_VARIADIC_MACROS)
    va_list      args;
#endif
    u_char      *p, *last, *msg;
    ssize_t      n;
    ngx_uint_t   wrote_stderr, debug_connection;
    u_char       errstr[NGX_MAX_ERROR_STR];
    char filebuf[52];

    last = errstr + NGX_MAX_ERROR_STR;
    
    p = ngx_cpymem(errstr, ngx_cached_err_log_time.data,
                   ngx_cached_err_log_time.len);

    snprintf(filebuf, sizeof(filebuf), "[%35s, %5d][yangyazhou @@@ test]", filename, lineno);

    p = ngx_slprintf(p, last, "%s ", filebuf);  
    
    p = ngx_slprintf(p, last, " [%V] ", &err_levels[level]);

    /* pid#tid */
    p = ngx_slprintf(p, last, "%P#" NGX_TID_T_FMT ": ", ngx_log_pid, ngx_log_tid); //进程ID和线程ID(在开启线程池的时候线程ID和进程ID不同)
    
    if (log->connection) {
        p = ngx_slprintf(p, last, "*%uA ", log->connection);
    }

    msg = p;

#if (NGX_HAVE_VARIADIC_MACROS)

    va_start(args, fmt);
    p = ngx_vslprintf(p, last, fmt, args);
    va_end(args);

#else

    p = ngx_vslprintf(p, last, fmt, args);

#endif

    if (err) {
        p = ngx_log_errno(p, last, err);
    }

    if (level != NGX_LOG_DEBUG && log->handler) {
        p = log->handler(log, p, last - p);
    }

    if (p > last - NGX_LINEFEED_SIZE) {
        p = last - NGX_LINEFEED_SIZE;
    }

    ngx_linefeed(p);

    wrote_stderr = 0;
    debug_connection = (log->log_level & NGX_LOG_DEBUG_CONNECTION) != 0;

    while (log) {

        if (log->writer) {
            log->writer(log, level, errstr, p - errstr);
            goto next;
        }

        if (ngx_time() == log->disk_full_time) {

            /*
             * on FreeBSD writing to a full filesystem with enabled softupdates
             * may block process for much longer time than writing to non-full
             * filesystem, so we skip writing to a log for one second
             */

            goto next;
        }

        n = ngx_write_fd(log->file->fd, errstr, p - errstr); //写到log文件中

        if (n == -1 && ngx_errno == NGX_ENOSPC) {
            log->disk_full_time = ngx_time();
        }

        if (log->file->fd == ngx_stderr) {
            wrote_stderr = 1;
        }

    next:

        log = log->next;
    }

    if (!ngx_use_stderr
        || level > NGX_LOG_WARN
        || wrote_stderr) /* 如果满足这些条件,则不会输出打印到前台,只会写到errlog文件中 */
    {
        return;
    }

    msg -= (7 + err_levels[level].len + 3);

    (void) ngx_sprintf(msg, "nginx: [%V] ", &err_levels[level]);
    (void) ngx_write_console(ngx_stderr, msg, p - msg);
}
ngx_int_t
ngx_http_upstream_create_round_robin_peer(ngx_http_request_t *r,
    ngx_http_upstream_resolved_t *ur)
{
    u_char                            *p;
    size_t                             len;
    ngx_uint_t                         i, n;
    struct sockaddr_in                *sin;
    ngx_http_upstream_rr_peers_t      *peers;
    ngx_http_upstream_rr_peer_data_t  *rrp;

    rrp = r->upstream->peer.data;

    if (rrp == NULL) {
        rrp = ngx_palloc(r->pool, sizeof(ngx_http_upstream_rr_peer_data_t));
        if (rrp == NULL) {
            return NGX_ERROR;
        }

        r->upstream->peer.data = rrp;
    }

    peers = ngx_pcalloc(r->pool, sizeof(ngx_http_upstream_rr_peers_t)
                     + sizeof(ngx_http_upstream_rr_peer_t) * (ur->naddrs - 1));
    if (peers == NULL) {
        return NGX_ERROR;
    }

    peers->single = (ur->naddrs == 1);
    peers->number = ur->naddrs;
    peers->name = &ur->host;

    for (i = 0; i < ur->naddrs; i++) {

        len = NGX_INET_ADDRSTRLEN + sizeof(":65536") - 1;

        p = ngx_pnalloc(r->pool, len);
        if (p == NULL) {
            return NGX_ERROR;
        }

        len = ngx_inet_ntop(AF_INET, &ur->addrs[i], p, NGX_INET_ADDRSTRLEN);
        len = ngx_sprintf(&p[len], ":%d", ur->port) - p;

        sin = ngx_pcalloc(r->pool, sizeof(struct sockaddr_in));
        if (sin == NULL) {
            return NGX_ERROR;
        }

        sin->sin_family = AF_INET;
        sin->sin_port = htons(ur->port);
        sin->sin_addr.s_addr = ur->addrs[i];

        peers->peer[i].sockaddr = (struct sockaddr *) sin;
        peers->peer[i].socklen = sizeof(struct sockaddr_in);
        peers->peer[i].name.len = len;
        peers->peer[i].name.data = p;
        peers->peer[i].weight = 1;
        peers->peer[i].current_weight = 1;
        peers->peer[i].max_fails = 1;
        peers->peer[i].fail_timeout = 10;
    }

    rrp->peers = peers;
    rrp->current = 0;

    if (rrp->peers->number <= 8 * sizeof(uintptr_t)) {
        rrp->tried = &rrp->data;
        rrp->data = 0;

    } else {
        n = (rrp->peers->number + (8 * sizeof(uintptr_t) - 1))
                / (8 * sizeof(uintptr_t));

        rrp->tried = ngx_pcalloc(r->pool, n * sizeof(uintptr_t));
        if (rrp->tried == NULL) {
            return NGX_ERROR;
        }
    }

    r->upstream->peer.get = ngx_http_upstream_get_round_robin_peer;
    r->upstream->peer.free = ngx_http_upstream_free_round_robin_peer;
    r->upstream->peer.tries = rrp->peers->number;
#if (NGX_HTTP_SSL)
    r->upstream->peer.set_session =
                               ngx_http_upstream_set_round_robin_peer_session;
    r->upstream->peer.save_session =
                               ngx_http_upstream_save_round_robin_peer_session;
#endif

    return NGX_OK;
}
static void
ngx_http_upstream_dynamic_handler(ngx_resolver_ctx_t *ctx)
{
    ngx_http_request_t     *r;
    ngx_http_upstream_t    *u;
    ngx_peer_connection_t  *pc;
    struct sockaddr_in     *sin, *csin;
    in_port_t               port;
    ngx_str_t              *addr;
    u_char                 *p;

    size_t                                 len;
    ngx_http_upstream_srv_conf_t          *us;
    ngx_http_upstream_dynamic_srv_conf_t  *dscf;

    r = ctx->data;

    u = r->upstream;
    us = u->conf->upstream;
    pc = &u->peer;

    dscf = ngx_http_conf_upstream_srv_conf(us, ngx_http_upstream_dynamic_module);

    if (ctx->state) {

        ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
                      "%V could not be resolved (%i: %s)",
                      &ctx->name, ctx->state,
                      ngx_resolver_strerror(ctx->state));

        dscf->fail_check = ngx_time();

        pc->resolved = NGX_HTTP_UPSTREAM_DR_FAILED;

    } else {
        /* dns query ok */
        dscf->fail_check = 0;

        sin = ngx_pcalloc(r->pool, sizeof(struct sockaddr_in));
        if (sin == NULL) {
            ngx_http_upstream_finalize_request(r, u,
                                               NGX_HTTP_INTERNAL_SERVER_ERROR);
            return;
        }

        ngx_memcpy(sin, pc->sockaddr, pc->socklen);

        /* only the first IP addr is used in version 1 */

        csin = (struct sockaddr_in *) ctx->addrs[0].sockaddr;
        if (sin->sin_addr.s_addr == csin->sin_addr.s_addr) {

            pc->resolved = NGX_HTTP_UPSTREAM_DR_OK;

            goto out;
        }

        sin->sin_addr.s_addr = csin->sin_addr.s_addr;

        len = NGX_INET_ADDRSTRLEN + sizeof(":65535") - 1;

        p = ngx_pnalloc(r->pool, len);
        if (p == NULL) {
            ngx_http_upstream_finalize_request(r, u,
                                               NGX_HTTP_INTERNAL_SERVER_ERROR);
            return;
        }

        port = ntohs(sin->sin_port);
        len = ngx_inet_ntop(AF_INET, &sin->sin_addr.s_addr,
                            p, NGX_INET_ADDRSTRLEN);
        len = ngx_sprintf(&p[len], ":%d", port) - p;

        addr = ngx_palloc(r->pool, sizeof(ngx_str_t));
        if (addr == NULL) {
            ngx_http_upstream_finalize_request(r, u,
                                               NGX_HTTP_INTERNAL_SERVER_ERROR);
            return;
        }

        addr->data = p;
        addr->len = len;

        pc->sockaddr = (struct sockaddr *) sin;
        pc->socklen = sizeof(struct sockaddr_in);
        pc->name = addr;

        ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
                "name was resolved to %V", pc->name);

        pc->resolved = NGX_HTTP_UPSTREAM_DR_OK;
    }

out:
    ngx_resolve_name_done(ctx);
    u->dyn_resolve_ctx = NULL;

    ngx_http_upstream_connect(r, u);
}
Пример #11
0
static u_char *
ngx_http_log_connection(ngx_http_request_t *r, u_char *buf,
    ngx_http_log_op_t *op)
{
    return ngx_sprintf(buf, "%ui", r->connection->number);
}
Пример #12
0
static ngx_int_t
ngx_status_ex_init_zone(ngx_shm_zone_t *shm_zone, void *data)
{
    ngx_status_ex_host_ctx_t       *octx = data;

    size_t                      	 len;
    ngx_slab_pool_t                  *shpool;
    ngx_rbtree_node_t                *sentinel;
    ngx_status_ex_host_ctx_t  	 	 *ctx;

    ctx = shm_zone->data;
	
    if (octx) {
        ctx->rbtree = octx->rbtree;
		
		status_ex_shm_zone = shm_zone;
        return NGX_OK;
    }

    shpool = (ngx_slab_pool_t *) shm_zone->shm.addr;

    if (shm_zone->shm.exists) {
        ctx->rbtree = shpool->data;
		
		status_ex_shm_zone = shm_zone;
        return NGX_OK;
    }

    ctx->rbtree = ngx_slab_alloc(shpool, sizeof(ngx_rbtree_t));
    if (ctx->rbtree == NULL) {
        return NGX_ERROR;
    }

    shpool->data = ctx->rbtree;

    sentinel = ngx_slab_alloc(shpool, sizeof(ngx_rbtree_node_t));
    if (sentinel == NULL) {
        return NGX_ERROR;
    }

	statu_io_info = ngx_slab_alloc(shpool, sizeof(ngx_tcp_io));
	if (statu_io_info == NULL)
		return NGX_ERROR;

	statu_url_io_array = ngx_slab_alloc(shpool, sizeof(statu_url_io_array)+ sizeof(ngx_tcp_io*) * STATU_MONITOR_DOMAINS);
	if (statu_url_io_array == NULL)
			return NGX_ERROR;
	
	statu_url_io_array->number = 0;
	ngx_rbtree_init(ctx->rbtree, sentinel,
                    ngx_status_ex_host_rbtree_insert_value);

    len = sizeof(" in status_ex zone \"\"") + shm_zone->shm.name.len;

    shpool->log_ctx = ngx_slab_alloc(shpool, len);
    if (shpool->log_ctx == NULL) {
        return NGX_ERROR;
    }

    ngx_sprintf(shpool->log_ctx, " in status_ex zone \"%V\"%Z",
                &shm_zone->shm.name);

	status_ex_shm_zone = shm_zone;
    return NGX_OK;
}
static ngx_int_t
ngx_http_mogilefs_put_handler(ngx_http_request_t *r)
{
    ngx_http_mogilefs_put_ctx_t        *ctx;
    ngx_str_t                           args; 
    ngx_uint_t                          flags;
    ngx_http_request_t                 *sr; 
    ngx_str_t                           spare_location = ngx_null_string, uri, value;
    ngx_int_t                           rc;
    u_char                             *p;
    ngx_http_core_loc_conf_t           *clcf;
    ngx_http_mogilefs_loc_conf_t       *mgcf;

    ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
                   "mogilefs put handler");

    clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);
    mgcf = ngx_http_get_module_loc_conf(r, ngx_http_mogilefs_module);

    if (clcf->handler != ngx_http_mogilefs_handler ||
        (mgcf->location_type == NGX_MOGILEFS_MAIN && !(r->method & mgcf->methods)))
    {
        return NGX_DECLINED;
    }

    ctx = ngx_http_get_module_ctx(r, ngx_http_mogilefs_module);

    if(ctx == NULL) {
        ctx = ngx_palloc(r->pool, sizeof(ngx_http_mogilefs_put_ctx_t));
        if (ctx == NULL) {
            return NGX_ERROR;
        }

        ctx->psr = NULL;
        ctx->state = START;
        ctx->status = 0;
        ctx->create_open_ctx = NULL;

        if(ngx_http_mogilefs_eval_key(r, &ctx->key) != NGX_OK) {
            return NGX_HTTP_INTERNAL_SERVER_ERROR;
        }

        ngx_http_set_ctx(r, ctx, ngx_http_mogilefs_module);
    }

    if(ctx->psr == NULL) {
        ctx->psr = ngx_palloc(r->pool, sizeof(ngx_http_post_subrequest_t));
        if (ctx->psr == NULL) {
            return NGX_ERROR;
        }
    }

    if(r->request_body == NULL) {
        rc = ngx_http_read_client_request_body(r, ngx_http_mogilefs_body_handler);

        if (rc >= NGX_HTTP_SPECIAL_RESPONSE) {
            return rc;
        }

        return NGX_DONE;
    }

    // Still receiving body?
    if(r->request_body->rest) {
        return NGX_DONE;
    }

    ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
                   "mogilefs put handler state: %ui, status: %i", ctx->state, ctx->status);

    if(ctx->state == CREATE_OPEN || ctx->state == FETCH || ctx->state == CREATE_CLOSE) {
        if(ctx->status != NGX_OK && ctx->status != NGX_HTTP_CREATED && ctx->status != NGX_HTTP_NO_CONTENT) {
            return (ctx->status >= NGX_HTTP_SPECIAL_RESPONSE) ?
                ctx->status : NGX_HTTP_INTERNAL_SERVER_ERROR;
        }
    }

    switch(ctx->state) {
        case START:
            spare_location = mgcf->create_open_spare_location;
            ctx->state = CREATE_OPEN;
            break;
        case CREATE_OPEN:
            spare_location = mgcf->fetch_location;
            ctx->state = FETCH;
            break;
        case FETCH:
            spare_location = mgcf->create_close_spare_location;
            ctx->state = CREATE_CLOSE;
            break;
        case CREATE_CLOSE:
            r->headers_out.content_length_n = 0;
            r->headers_out.status = NGX_HTTP_CREATED;

            r->header_only = 1;

            return ngx_http_send_header(r);
    }

    uri.len = spare_location.len + ctx->key.len;

    uri.data = ngx_palloc(r->pool, uri.len);

    p = ngx_cpymem(uri.data, spare_location.data, spare_location.len);

    p = ngx_cpymem(p, ctx->key.data, ctx->key.len);

    args.len = 0;
    args.data = NULL;
    flags = 0;

    if (ngx_http_parse_unsafe_uri(r, &uri, &args, &flags) != NGX_OK) {
        return NGX_ERROR;
    }

    ctx->psr->handler = ngx_http_mogilefs_finish_phase_handler;
    ctx->psr->data = ctx;

    flags |= NGX_HTTP_SUBREQUEST_WAITED;

    if(ctx->state == FETCH) {
        flags |= NGX_HTTP_SUBREQUEST_IN_MEMORY;
    }

    rc = ngx_http_subrequest(r, &uri, &args, &sr, ctx->psr, flags);

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

    if(ctx->state == CREATE_CLOSE) {
        ngx_http_set_ctx(sr, ctx->create_open_ctx, ngx_http_mogilefs_module);

        value.data = ngx_palloc(r->pool, NGX_OFF_T_LEN);

        if(value.data == NULL) {
            return NGX_ERROR;
        }

        value.len = ngx_sprintf(value.data, "%O", r->headers_in.content_length_n)
            - value.data;

        if(ngx_http_mogilefs_add_aux_param(sr, &ngx_http_mogilefs_size, &value) != NGX_OK) {
            return NGX_ERROR;
        }
    }

    /*
     * Nginx closes temporary file with buffered body
     * whenever it starts sending reponse from upstream
     * and it is not doing subrequest in memory.
     *
     * Since the request body in create_open subrequest is
     * inherited from main request, it is necessary to prevent
     * nginx from closing the temporary file with request body,
     * before it could be passed to the storage node on fetch/store
     * stage.
     *
     * We do it by "hiding" the request body from nginx internals.
     */
    if(ctx->state == CREATE_OPEN) {
        sr->request_body = NULL;
    }

    sr->method = NGX_HTTP_PUT;
    sr->method_name = ngx_http_mogilefs_put_method;

    /*
     * Wait for subrequest to complete
     */
    return NGX_DONE;
}
Пример #14
0
ngx_int_t
ngx_http_srcache_store_response_header(ngx_http_request_t *r,
    ngx_http_srcache_ctx_t *ctx)
{
    ngx_chain_t             *cl;
    size_t                   len;
    ngx_buf_t               *b;
    ngx_uint_t               status;
    ngx_uint_t               i;
    ngx_str_t               *status_line;
    ngx_list_part_t         *part;
    ngx_table_elt_t         *header;

    u_char                   buf[sizeof("Mon, 28 Sep 1970 06:00:00 GMT") - 1];

    ngx_http_srcache_loc_conf_t    *conf;

    conf = ngx_http_get_module_loc_conf(r, ngx_http_srcache_filter_module);

    dd("request: %p, uri: %.*s", r, (int) r->uri.len, r->uri.data);

    len = sizeof("HTTP/1.x ") - 1 + sizeof(CRLF) - 1
          /* the end of the header */
          + sizeof(CRLF) - 1;

    if (r->headers_out.status_line.len) {
        dd("status line defined");
        len += r->headers_out.status_line.len;
        status_line = &r->headers_out.status_line;
        status = 0;

    } else {
        dd("status line not defined");

        status = r->headers_out.status;

        if (status >= NGX_HTTP_OK
            && status < NGX_HTTP_LAST_LEVEL_200)
        {
            /* 2XX */

            status -= NGX_HTTP_OK;
            dd("status: %d", (int) status);
            status_line = &ngx_http_status_lines[status];
            len += ngx_http_status_lines[status].len;

        } else if (status >= NGX_HTTP_MOVED_PERMANENTLY
                   && status < NGX_HTTP_LAST_LEVEL_300)
        {
            /* 3XX */

            if (status == NGX_HTTP_NOT_MODIFIED) {
                r->header_only = 1;
            }

            status = status - NGX_HTTP_MOVED_PERMANENTLY + NGX_HTTP_LEVEL_200;
            status_line = &ngx_http_status_lines[status];
            len += ngx_http_status_lines[status].len;

        } else if (status >= NGX_HTTP_BAD_REQUEST
                   && status < NGX_HTTP_LAST_LEVEL_400)
        {
            /* 4XX */
            status = status - NGX_HTTP_BAD_REQUEST
                            + NGX_HTTP_LEVEL_200
                            + NGX_HTTP_LEVEL_300;

            status_line = &ngx_http_status_lines[status];
            len += ngx_http_status_lines[status].len;

        } else if (status >= NGX_HTTP_INTERNAL_SERVER_ERROR
                   && status < NGX_HTTP_LAST_LEVEL_500)
        {
            /* 5XX */
            status = status - NGX_HTTP_INTERNAL_SERVER_ERROR
                            + NGX_HTTP_LEVEL_200
                            + NGX_HTTP_LEVEL_300
                            + NGX_HTTP_LEVEL_400;

            status_line = &ngx_http_status_lines[status];
            len += ngx_http_status_lines[status].len;

        } else {
            len += NGX_INT_T_LEN;
            status_line = NULL;
        }
    }

    if (!conf->hide_content_type && r->headers_out.content_type.len) {
        len += sizeof("Content-Type: ") - 1
               + r->headers_out.content_type.len + 2;

        if (r->headers_out.content_type_len == r->headers_out.content_type.len
            && r->headers_out.charset.len)
        {
            len += sizeof("; charset=") - 1 + r->headers_out.charset.len;
        }
    }

    if (!conf->hide_last_modified) {
        if (r->headers_out.last_modified_time != -1) {
            if (r->headers_out.status != NGX_HTTP_OK
                && r->headers_out.status != NGX_HTTP_PARTIAL_CONTENT
                && r->headers_out.status != NGX_HTTP_NOT_MODIFIED
                && r->headers_out.status != NGX_HTTP_NO_CONTENT)
            {
                r->headers_out.last_modified_time = -1;
                r->headers_out.last_modified = NULL;
            }
        }

        dd("last modified time: %d", (int) r->headers_out.last_modified_time);

        if (r->headers_out.last_modified == NULL
            && r->headers_out.last_modified_time != -1)
        {
            (void) ngx_http_time(buf, r->headers_out.last_modified_time);

            len += sizeof("Last-Modified: ") - 1 + sizeof(buf) + 2;
        }
    }

    if (r->allow_ranges) {
        len += sizeof("X-SRCache-Allow-Ranges: 1") - 1 + 2;
    }

    part = &r->headers_out.headers.part;
    header = part->elts;

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

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

            part = part->next;
            header = part->elts;
            i = 0;
        }

        if (header[i].hash == 0) {
            continue;
        }

        if (ngx_hash_find(&conf->hide_headers_hash, header[i].hash,
                          header[i].lowcase_key, header[i].key.len))
        {
            continue;
        }

        len += header[i].key.len + sizeof(": ") - 1 + header[i].value.len
               + sizeof(CRLF) - 1;
    }

    b = ngx_create_temp_buf(r->pool, len);
    if (b == NULL) {
        return NGX_ERROR;
    }

    /* "HTTP/1.x " */
    b->last = ngx_cpymem(b->last, "HTTP/1.1 ", sizeof("HTTP/1.x ") - 1);

    /* status line */
    if (status_line) {
        b->last = ngx_copy(b->last, status_line->data, status_line->len);

    } else {
        b->last = ngx_sprintf(b->last, "%ui", status);
    }
    *b->last++ = CR; *b->last++ = LF;

    if (!conf->hide_content_type && r->headers_out.content_type.len) {
        b->last = ngx_cpymem(b->last, "Content-Type: ",
                             sizeof("Content-Type: ") - 1);
        b->last = ngx_copy(b->last, r->headers_out.content_type.data,
                           r->headers_out.content_type.len);

        if (r->headers_out.content_type_len == r->headers_out.content_type.len
            && r->headers_out.charset.len)
        {
            b->last = ngx_cpymem(b->last, "; charset=",
                                 sizeof("; charset=") - 1);
            b->last = ngx_copy(b->last, r->headers_out.charset.data,
                               r->headers_out.charset.len);
        }

        *b->last++ = CR; *b->last++ = LF;
    }

    if (!conf->hide_last_modified
        && r->headers_out.last_modified == NULL
        && r->headers_out.last_modified_time != -1)
    {
        b->last = ngx_cpymem(b->last, "Last-Modified: ",
                             sizeof("Last-Modified: ") - 1);

        b->last = ngx_cpymem(b->last, buf, sizeof(buf));

        *b->last++ = CR; *b->last++ = LF;
    }

    if (r->allow_ranges) {
        b->last = ngx_cpymem(b->last, "X-SRCache-Allow-Ranges: 1\r\n",
                             sizeof("X-SRCache-Allow-Ranges: 1\r\n") - 1);
    }

    part = &r->headers_out.headers.part;
    header = part->elts;

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

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

            part = part->next;
            header = part->elts;
            i = 0;
        }

        if (header[i].hash == 0) {
            continue;
        }

        dd("header hash: %lu, hash lc: %lu", (unsigned long) header[i].hash,
           (unsigned long) ngx_hash_key_lc(header[i].key.data,
           header[i].key.len));

        if (ngx_hash_find(&conf->hide_headers_hash, header[i].hash,
                          header[i].lowcase_key, header[i].key.len))
        {
            dd("skipped header key: %.*s", (int) header[i].key.len,
               header[i].key.data);
            continue;
        }

        dd("header not skipped");

        b->last = ngx_copy(b->last, header[i].key.data, header[i].key.len);
        *b->last++ = ':'; *b->last++ = ' ';

        b->last = ngx_copy(b->last, header[i].value.data, header[i].value.len);
        *b->last++ = CR; *b->last++ = LF;
    }

    ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
                   "srcache store header %*s", (size_t) (b->last - b->pos),
                   b->pos);

    /* the end of HTTP header */
    *b->last++ = CR; *b->last++ = LF;

    if (b->last != b->end) {
        ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
                      "srcache_fetch: buffer error when serializing the "
                      "response header: %O left", (off_t) (b->last - b->end));

        return NGX_ERROR;
    }

    cl = ngx_alloc_chain_link(r->pool);
    if (cl == NULL) {
        return NGX_ERROR;
    }

    cl->buf = b;
    cl->next = NULL;

    ctx->body_to_cache = cl;

    ctx->response_length += len;

    return NGX_OK;
}
static void
ngx_rtmp_dash_close_fragment(ngx_rtmp_session_t *s, ngx_rtmp_dash_track_t *t)
{
    u_char                    *pos, *pos1;
    size_t                     left;
    ssize_t                    n;
    ngx_fd_t                   fd;
    ngx_buf_t                  b;
    ngx_rtmp_dash_ctx_t       *ctx;
    ngx_rtmp_dash_frag_t      *f;

    static u_char              buffer[NGX_RTMP_DASH_BUFSIZE];

    if (!t->opened) {
        return;
    }

    ngx_log_debug3(NGX_LOG_DEBUG_RTMP, s->connection->log, 0,
                   "dash: close fragment id=%ui, type=%c, pts=%uD",
                   t->id, t->type, t->earliest_pres_time);

    ctx = ngx_rtmp_get_module_ctx(s, ngx_rtmp_dash_module);

    b.start = buffer;
    b.end = buffer + sizeof(buffer);
    b.pos = b.last = b.start;

    ngx_rtmp_mp4_write_styp(&b);

    pos = b.last;
    b.last += 44; /* leave room for sidx */

    ngx_rtmp_mp4_write_moof(&b, t->earliest_pres_time, t->sample_count,
                            t->samples, t->sample_mask, t->id);
    pos1 = b.last;
    b.last = pos;

    ngx_rtmp_mp4_write_sidx(&b, t->mdat_size + 8 + (pos1 - (pos + 44)),
                            t->earliest_pres_time, t->latest_pres_time);
    b.last = pos1;
    ngx_rtmp_mp4_write_mdat(&b, t->mdat_size + 8);

    /* move the data down to make room for the headers */

    f = ngx_rtmp_dash_get_frag(s, ctx->nfrags);

    *ngx_sprintf(ctx->stream.data + ctx->stream.len, "%uD.m4%c",
                 f->timestamp, t->type) = 0;

    fd = ngx_open_file(ctx->stream.data, NGX_FILE_RDWR,
                       NGX_FILE_TRUNCATE, NGX_FILE_DEFAULT_ACCESS);

    if (fd == NGX_INVALID_FILE) {
        ngx_log_error(NGX_LOG_ERR, s->connection->log, ngx_errno,
                      "dash: error creating dash temp video file");
        goto done;
    }

    if (ngx_write_fd(fd, b.pos, (size_t) (b.last - b.pos)) == NGX_ERROR) {
        goto done;
    }

    left = (size_t) t->mdat_size;

#if (NGX_WIN32)
    if (SetFilePointer(t->fd, 0, 0, FILE_BEGIN) == INVALID_SET_FILE_POINTER) {
        ngx_log_error(NGX_LOG_ERR, s->connection->log, 0,
                      "dash: SetFilePointer error");
        goto done;
    }
#else
    if (lseek(t->fd, 0, SEEK_SET) == -1) {
        ngx_log_error(NGX_LOG_ERR, s->connection->log, ngx_errno,
                      "dash: lseek error");
        goto done;
    }
#endif

    while (left > 0) {

        n = ngx_read_fd(t->fd, buffer, ngx_min(sizeof(buffer), left));
        if (n == NGX_ERROR) {
            break;
        }

        n = ngx_write_fd(fd, buffer, (size_t) n);
        if (n == NGX_ERROR) {
            break;
        }

        left -= n;
    }

done:

    if (fd != NGX_INVALID_FILE) {
        ngx_close_file(fd);
    }

    ngx_close_file(t->fd);

    t->fd = NGX_INVALID_FILE;
    t->opened = 0;
}
static ngx_int_t
ngx_http_limit_zone_init_zone(ngx_shm_zone_t *shm_zone, void *data)
{
    ngx_http_limit_zone_ctx_t  *octx = data;

    size_t                      len;
    ngx_slab_pool_t            *shpool;
    ngx_rbtree_node_t          *sentinel;
    ngx_http_limit_zone_ctx_t  *ctx;

    ctx = shm_zone->data;

    if (octx) {
        if (ngx_strcmp(ctx->var.data, octx->var.data) != 0) {
            ngx_log_error(NGX_LOG_EMERG, shm_zone->shm.log, 0,
                          "limit_zone \"%V\" uses the \"%V\" variable "
                          "while previously it used the \"%V\" variable",
                          &shm_zone->shm.name, &ctx->var, &octx->var);
            return NGX_ERROR;
        }

        ctx->rbtree = octx->rbtree;

        return NGX_OK;
    }

    shpool = (ngx_slab_pool_t *) shm_zone->shm.addr;

    if (shm_zone->shm.exists) {
        ctx->rbtree = shpool->data;

        return NGX_OK;
    }

    ctx->rbtree = ngx_slab_alloc(shpool, sizeof(ngx_rbtree_t));
    if (ctx->rbtree == NULL) {
        return NGX_ERROR;
    }

    shpool->data = ctx->rbtree;

    sentinel = ngx_slab_alloc(shpool, sizeof(ngx_rbtree_node_t));
    if (sentinel == NULL) {
        return NGX_ERROR;
    }

    ngx_rbtree_init(ctx->rbtree, sentinel,
                    ngx_http_limit_zone_rbtree_insert_value);

    len = sizeof(" in limit_zone \"\"") + shm_zone->shm.name.len;

    shpool->log_ctx = ngx_slab_alloc(shpool, len);
    if (shpool->log_ctx == NULL) {
        return NGX_ERROR;
    }

    ngx_sprintf(shpool->log_ctx, " in limit_zone \"%V\"%Z",
                &shm_zone->shm.name);

    return NGX_OK;
}
Пример #17
0
ngx_int_t
ngx_create_temp_file(ngx_file_t *file, ngx_path_t *path, ngx_pool_t *pool,
    ngx_uint_t persistent, ngx_uint_t clean, ngx_uint_t access)
{
    uint32_t                  n;
    ngx_err_t                 err;
    ngx_pool_cleanup_t       *cln;
    ngx_pool_cleanup_file_t  *clnf;

    file->name.len = path->name.len + 1 + path->len + 10;

    file->name.data = ngx_pnalloc(pool, file->name.len + 1);
    if (file->name.data == NULL) {
        return NGX_ERROR;
    }

#if 0
    for (i = 0; i < file->name.len; i++) {
         file->name.data[i] = 'X';
    }
#endif

    ngx_memcpy(file->name.data, path->name.data, path->name.len);

    n = (uint32_t) ngx_next_temp_number(0);

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

    for ( ;; ) {
        (void) ngx_sprintf(file->name.data + path->name.len + 1 + path->len,
                           "%010uD%Z", n);

        ngx_create_hashed_filename(path, file->name.data, file->name.len);

        ngx_log_debug1(NGX_LOG_DEBUG_CORE, file->log, 0,
                       "hashed path: %s", file->name.data);

        file->fd = ngx_open_tempfile(file->name.data, persistent, access);

        ngx_log_debug1(NGX_LOG_DEBUG_CORE, file->log, 0,
                       "temp fd:%d", file->fd);

        if (file->fd != NGX_INVALID_FILE) {

            cln->handler = clean ? ngx_pool_delete_file : ngx_pool_cleanup_file;
            clnf = cln->data;

            clnf->fd = file->fd;
            clnf->name = file->name.data;
            clnf->log = pool->log;

            return NGX_OK;
        }

        err = ngx_errno;

        if (err == NGX_EEXIST) {
            n = (uint32_t) ngx_next_temp_number(1);
            continue;
        }

        if ((path->level[0] == 0) || (err != NGX_ENOPATH)) {
            ngx_log_error(NGX_LOG_CRIT, file->log, err,
                          ngx_open_tempfile_n " \"%s\" failed",
                          file->name.data);
            return NGX_ERROR;
        }

        if (ngx_create_path(file, path) == NGX_ERROR) {
            return NGX_ERROR;
        }
    }
}
static ngx_int_t
ngx_http_chunked_body_filter(ngx_http_request_t *r, ngx_chain_t *in)
{
    u_char                         *chunk;
    off_t                           size;
    ngx_int_t                       rc;
    ngx_buf_t                      *b;
    ngx_chain_t                    *out, *cl, *tl, **ll;
    ngx_http_chunked_filter_ctx_t  *ctx;

    if (in == NULL || !r->chunked || r->header_only) {
        return ngx_http_next_body_filter(r, in);
    }

    ctx = ngx_http_get_module_ctx(r, ngx_http_chunked_filter_module);

    out = NULL;
    ll = &out;

    size = 0;
    cl = in;

    for ( ;; ) {
        ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
                       "http chunk: %d", ngx_buf_size(cl->buf));

        size += ngx_buf_size(cl->buf);

        if (cl->buf->flush
            || cl->buf->sync
            || ngx_buf_in_memory(cl->buf)
            || cl->buf->in_file)
        {
            tl = ngx_alloc_chain_link(r->pool);
            if (tl == NULL) {
                return NGX_ERROR;
            }

            tl->buf = cl->buf;
            *ll = tl;
            ll = &tl->next;
        }

        if (cl->next == NULL) {
            break;
        }

        cl = cl->next;
    }

    if (size) {
        tl = ngx_chain_get_free_buf(r->pool, &ctx->free);
        if (tl == NULL) {
            return NGX_ERROR;
        }

        b = tl->buf;
        chunk = b->start;

        if (chunk == NULL) {
            /* the "0000000000000000" is 64-bit hexadecimal string */

            chunk = ngx_palloc(r->pool, sizeof("0000000000000000" CRLF) - 1);
            if (chunk == NULL) {
                return NGX_ERROR;
            }

            b->start = chunk;
            b->end = chunk + sizeof("0000000000000000" CRLF) - 1;
        }

        b->tag = (ngx_buf_tag_t) &ngx_http_chunked_filter_module;
        b->memory = 0;
        b->temporary = 1;
        b->pos = chunk;
        b->last = ngx_sprintf(chunk, "%xO" CRLF, size);

        tl->next = out;
        out = tl;
    }

    if (cl->buf->last_buf) {
        tl = ngx_chain_get_free_buf(r->pool, &ctx->free);
        if (tl == NULL) {
            return NGX_ERROR;
        }

        b = tl->buf;

        b->tag = (ngx_buf_tag_t) &ngx_http_chunked_filter_module;
        b->temporary = 0;
        b->memory = 1;
        b->last_buf = 1;
        b->pos = (u_char *) CRLF "0" CRLF CRLF;
        b->last = b->pos + 7;

        cl->buf->last_buf = 0;

        *ll = tl;

        if (size == 0) {
            b->pos += 2;
        }

    } else if (size > 0) {
        tl = ngx_chain_get_free_buf(r->pool, &ctx->free);
        if (tl == NULL) {
            return NGX_ERROR;
        }

        b = tl->buf;

        b->tag = (ngx_buf_tag_t) &ngx_http_chunked_filter_module;
        b->temporary = 0;
        b->memory = 1;
        b->pos = (u_char *) CRLF;
        b->last = b->pos + 2;

        *ll = tl;

    } else {
        *ll = NULL;
    }

    ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
                   "send chunked data: %d", size);

    rc = ngx_http_next_body_filter(r, out);

    ngx_chain_update_chains(r->pool, &ctx->free, &ctx->busy, &out,
                            (ngx_buf_tag_t) &ngx_http_chunked_filter_module);

    return rc;
}
Пример #19
0
u_char *
ngx_http_req_stat_bytes_sent(ngx_http_request_t *r, u_char *buf,
    ngx_http_req_stat_op_t *op)
{
    return ngx_sprintf(buf, "%O", r->connection->sent);
}
static ngx_int_t
ngx_http_limit_req2_init_zone(ngx_shm_zone_t *shm_zone, void *data)
{
    ngx_http_limit_req2_ctx_t  *octx = data;

    size_t                          len;
    ngx_uint_t                      i, j;
    ngx_http_limit_req2_ctx_t      *ctx;
    ngx_http_limit_req2_variable_t *v1, *v2;

    ctx = shm_zone->data;
    v1 = ctx->limit_vars->elts;

    if (octx) {
        v2 = octx->limit_vars->elts;
        if (ctx->limit_vars->nelts != octx->limit_vars->nelts) {
            ngx_log_error(NGX_LOG_EMERG, shm_zone->shm.log, 0,
                          "limit_req2 \"%V\" uses the \"%V\" variable "
                          "while previously it used the \"%V\" variable",
                          &shm_zone->shm.name, &v1[0].var, &v2[0].var);
            return NGX_ERROR;
        }

        for (i = 0, j = 0;
             i < ctx->limit_vars->nelts && j < octx->limit_vars->nelts;
             i++, j++)
        {
            if (ngx_strcmp(v1[i].var.data, v2[j].var.data) != 0) {
                ngx_log_error(NGX_LOG_EMERG, shm_zone->shm.log, 0,
                              "limit_req2 \"%V\" uses the \"%V\" variable "
                              "while previously it used the \"%V\" variable",
                              &shm_zone->shm.name, &v1[i].var,
                              &v2[j].var);
                return NGX_ERROR;
            }
        }

        ctx->sh = octx->sh;
        ctx->shpool = octx->shpool;

        return NGX_OK;
    }

    ctx->shpool = (ngx_slab_pool_t *) shm_zone->shm.addr;

    if (shm_zone->shm.exists) {
        ctx->sh = ctx->shpool->data;

        return NGX_OK;
    }

    ctx->sh = ngx_slab_alloc(ctx->shpool, sizeof(ngx_http_limit_req2_shctx_t));
    if (ctx->sh == NULL) {
        return NGX_ERROR;
    }

    ctx->shpool->data = ctx->sh;

    ngx_rbtree_init(&ctx->sh->rbtree, &ctx->sh->sentinel,
                    ngx_http_limit_req2_rbtree_insert_value);

    ngx_queue_init(&ctx->sh->queue);

    len = sizeof(" in limit_req2 zone \"\"") + shm_zone->shm.name.len;

    ctx->shpool->log_ctx = ngx_slab_alloc(ctx->shpool, len);
    if (ctx->shpool->log_ctx == NULL) {
        return NGX_ERROR;
    }

    ngx_sprintf(ctx->shpool->log_ctx, " in limit_req2 zone \"%V\"%Z",
                &shm_zone->shm.name);

    return NGX_OK;
}
Пример #21
0
static int
ngx_http_lua_ngx_req_set_body_data(lua_State *L)
{
    ngx_http_request_t          *r;
    int                          n;
    ngx_http_request_body_t     *rb;
    ngx_temp_file_t             *tf;
    ngx_buf_t                   *b;
    ngx_str_t                    body, key, value;
#if 1
    ngx_int_t                    rc;
#endif
    ngx_chain_t                 *cl;
    ngx_buf_tag_t                tag;

    n = lua_gettop(L);

    if (n != 1) {
        return luaL_error(L, "expecting 1 arguments but seen %d", n);
    }

    body.data = (u_char *) luaL_checklstring(L, 1, &body.len);

    r = ngx_http_lua_get_req(L);
    if (r == NULL) {
        return luaL_error(L, "request object not found");
    }

    ngx_http_lua_check_fake_request(L, r);

    if (r->discard_body) {
        return luaL_error(L, "request body already discarded asynchronously");
    }

    if (r->request_body == NULL) {
        return luaL_error(L, "request body not read yet");
    }

    rb = r->request_body;

    tag = (ngx_buf_tag_t) &ngx_http_lua_module;

    tf = rb->temp_file;

    if (tf) {
        if (tf->file.fd != NGX_INVALID_FILE) {

            dd("cleaning temp file %.*s", (int) tf->file.name.len,
               tf->file.name.data);

            ngx_http_lua_pool_cleanup_file(r->pool, tf->file.fd);
            tf->file.fd = NGX_INVALID_FILE;

            dd("temp file cleaned: %.*s", (int) tf->file.name.len,
               tf->file.name.data);
        }

        rb->temp_file = NULL;
    }

    if (body.len == 0) {

        if (rb->bufs) {

            for (cl = rb->bufs; cl; cl = cl->next) {
                if (cl->buf->tag == tag && cl->buf->temporary) {

                    dd("free old request body buffer: size:%d",
                       (int) ngx_buf_size(cl->buf));

                    ngx_pfree(r->pool, cl->buf->start);
                    cl->buf->tag = (ngx_buf_tag_t) NULL;
                    cl->buf->temporary = 0;
                }
            }
        }

        rb->bufs = NULL;
        rb->buf = NULL;

        dd("request body is set to empty string");
        goto set_header;
    }

    if (rb->bufs) {

        for (cl = rb->bufs; cl; cl = cl->next) {
            if (cl->buf->tag == tag && cl->buf->temporary) {
                dd("free old request body buffer: size:%d",
                   (int) ngx_buf_size(cl->buf));

                ngx_pfree(r->pool, cl->buf->start);
                cl->buf->tag = (ngx_buf_tag_t) NULL;
                cl->buf->temporary = 0;
            }
        }

        rb->bufs->next = NULL;

        b = rb->bufs->buf;

        ngx_memzero(b, sizeof(ngx_buf_t));

        b->temporary = 1;
        b->tag = tag;

        b->start = ngx_palloc(r->pool, body.len);
        if (b->start == NULL) {
            return luaL_error(L, "no memory");
        }
        b->end = b->start + body.len;

        b->pos = b->start;
        b->last = ngx_copy(b->pos, body.data, body.len);

    } else {

        rb->bufs = ngx_alloc_chain_link(r->pool);
        if (rb->bufs == NULL) {
            return luaL_error(L, "no memory");
        }
        rb->bufs->next = NULL;

        b = ngx_create_temp_buf(r->pool, body.len);
        if (b == NULL) {
            return luaL_error(L, "no memory");
        }

        b->tag = tag;
        b->last = ngx_copy(b->pos, body.data, body.len);

        rb->bufs->buf = b;
        rb->buf = b;
    }

set_header:

    /* override input header Content-Length (value must be null terminated) */

    value.data = ngx_palloc(r->pool, NGX_SIZE_T_LEN + 1);
    if (value.data == NULL) {
        return luaL_error(L, "no memory");
    }

    value.len = ngx_sprintf(value.data, "%uz", body.len) - value.data;
    value.data[value.len] = '\0';

    dd("setting request Content-Length to %.*s (%d)",
       (int) value.len, value.data, (int) body.len);

    r->headers_in.content_length_n = body.len;

    if (r->headers_in.content_length) {
        r->headers_in.content_length->value.data = value.data;
        r->headers_in.content_length->value.len = value.len;

    } else {

        ngx_str_set(&key, "Content-Length");

        rc = ngx_http_lua_set_input_header(r, key, value, 1 /* override */);
        if (rc != NGX_OK) {
            return luaL_error(L, "failed to reset the Content-Length "
                              "input header");
        }
    }

    return 0;
}
static ngx_int_t
ngx_secure_token_cht_get_var(
	ngx_http_request_t *r,
	ngx_http_variable_value_t *v,
	uintptr_t data)
{
	ngx_secure_token_cht_token_t* token = (void*)data;
	ngx_str_t expires_str;
	ngx_str_t md5hash_str;
	ngx_str_t token_str;
	ngx_str_t acl;
	ngx_md5_t md5;
	u_char end_time_buf[NGX_INT32_LEN];
	u_char md5hash_buf[MD5_DIGEST_LENGTH];
	u_char token_buf[ngx_base64_encoded_length(MD5_DIGEST_LENGTH)];
	time_t end_time;
	size_t result_size;
	u_char* p;
	ngx_int_t rc;

	// get the acl
	rc = ngx_http_secure_token_get_acl(r, token->acl, &acl);
	if (rc != NGX_OK)
	{
		return rc;
	}

	// get the end time
	end_time = token->end.val;
	if (token->end.type == NGX_HTTP_SECURE_TOKEN_TIME_RELATIVE)
	{
		end_time += ngx_time();
	}
	expires_str.data = end_time_buf;
	expires_str.len = ngx_sprintf(end_time_buf, "%uD", (uint32_t)end_time) - end_time_buf;
	
	// calculate the signature
	ngx_md5_init(&md5);
	ngx_md5_update(&md5, acl.data, acl.len);
	ngx_md5_update(&md5, token->key.data, token->key.len);
	ngx_md5_update(&md5, expires_str.data, expires_str.len);
	ngx_md5_final(md5hash_buf, &md5);

	md5hash_str.data = md5hash_buf;
	md5hash_str.len = sizeof(md5hash_buf);

	token_str.data = token_buf;
	ngx_encode_base64url(&token_str, &md5hash_str);

	// get the result size
	result_size = sizeof(TOKEN_PART1) + token_str.len + sizeof(TOKEN_PART2) + expires_str.len;

	// allocate the result
	p = ngx_pnalloc(r->pool, result_size);
	if (p == NULL)
	{
		return NGX_ERROR;
	}

	v->data = p;

	// build the result
	p = ngx_copy(p, TOKEN_PART1, sizeof(TOKEN_PART1) - 1);
	p = ngx_copy(p, token_str.data, token_str.len);
	p = ngx_copy(p, TOKEN_PART2, sizeof(TOKEN_PART2) - 1);
	p = ngx_copy(p, expires_str.data, expires_str.len);
	*p = '\0';

	v->len = p - v->data;
	v->valid = 1;
	v->no_cacheable = 0;
	v->not_found = 0;

	return NGX_OK;
}
Пример #23
0
static int
ngx_http_lua_ngx_req_set_body_file(lua_State *L)
{
    u_char                      *p;
    ngx_http_request_t          *r;
    int                          n;
    ngx_http_request_body_t     *rb;
    ngx_temp_file_t             *tf;
    ngx_buf_t                   *b;
    ngx_str_t                    name;
    ngx_int_t                    rc;
    int                          clean;
    ngx_open_file_info_t         of;
    ngx_str_t                    key, value;
    ngx_pool_cleanup_t          *cln;
    ngx_pool_cleanup_file_t     *clnf;
    ngx_err_t                    err;
    ngx_chain_t                 *cl;
    ngx_buf_tag_t                tag;

    n = lua_gettop(L);

    if (n != 1 && n != 2) {
        return luaL_error(L, "expecting 1 or 2 arguments but seen %d", n);
    }

    p = (u_char *) luaL_checklstring(L, 1, &name.len);

    r = ngx_http_lua_get_req(L);
    if (r == NULL) {
        return luaL_error(L, "no request found");
    }

    ngx_http_lua_check_fake_request(L, r);

    if (r->discard_body) {
        return luaL_error(L, "request body already discarded asynchronously");
    }

    if (r->request_body == NULL) {
        return luaL_error(L, "request body not read yet");
    }

    name.data = ngx_palloc(r->pool, name.len + 1);
    if (name.data == NULL) {
        return luaL_error(L, "no memory");
    }

    ngx_memcpy(name.data, p, name.len);
    name.data[name.len] = '\0';

    if (n == 2) {
        luaL_checktype(L, 2, LUA_TBOOLEAN);
        clean = lua_toboolean(L, 2);

    } else {
        clean = 0;
    }

    dd("clean: %d", (int) clean);

    rb = r->request_body;

    /* clean up existing r->request_body->bufs (if any) */

    tag = (ngx_buf_tag_t) &ngx_http_lua_module;

    if (rb->bufs) {
        dd("XXX reusing buf");

        for (cl = rb->bufs; cl; cl = cl->next) {
            if (cl->buf->tag == tag && cl->buf->temporary) {
                dd("free old request body buffer: size:%d",
                   (int) ngx_buf_size(cl->buf));

                ngx_pfree(r->pool, cl->buf->start);
                cl->buf->tag = (ngx_buf_tag_t) NULL;
                cl->buf->temporary = 0;
            }
        }

        rb->bufs->next = NULL;
        b = rb->bufs->buf;

        ngx_memzero(b, sizeof(ngx_buf_t));

        b->tag = tag;
        rb->buf = NULL;

    } else {

        dd("XXX creating new buf");

        rb->bufs = ngx_alloc_chain_link(r->pool);
        if (rb->bufs == NULL) {
            return luaL_error(L, "no memory");
        }
        rb->bufs->next = NULL;

        b = ngx_calloc_buf(r->pool);
        if (b == NULL) {
            return luaL_error(L, "no memory");
        }

        b->tag = tag;

        rb->bufs->buf = b;
        rb->buf = NULL;
    }

    b->last_in_chain = 1;

    /* just make r->request_body->temp_file a bare stub */

    tf = rb->temp_file;

    if (tf) {
        if (tf->file.fd != NGX_INVALID_FILE) {

            dd("cleaning temp file %.*s", (int) tf->file.name.len,
               tf->file.name.data);

            ngx_http_lua_pool_cleanup_file(r->pool, tf->file.fd);

            ngx_memzero(tf, sizeof(ngx_temp_file_t));

            tf->file.fd = NGX_INVALID_FILE;

            dd("temp file cleaned: %.*s", (int) tf->file.name.len,
               tf->file.name.data);
        }

    } else {

        tf = ngx_pcalloc(r->pool, sizeof(ngx_temp_file_t));
        if (tf == NULL) {
            return luaL_error(L, "no memory");
        }

        tf->file.fd = NGX_INVALID_FILE;
        rb->temp_file = tf;
    }

    /* read the file info and construct an in-file buf */

    ngx_memzero(&of, sizeof(ngx_open_file_info_t));

    of.directio = NGX_OPEN_FILE_DIRECTIO_OFF;

    if (ngx_http_lua_open_and_stat_file(name.data, &of, r->connection->log)
        != NGX_OK)
    {
        return luaL_error(L, "%s \"%s\" failed", of.failed, name.data);
    }

    dd("XXX new body file fd: %d", of.fd);

    tf->file.fd = of.fd;
    tf->file.name = name;
    tf->file.log = r->connection->log;
    tf->file.directio = 0;

    if (of.size == 0) {
        if (clean) {
            if (ngx_delete_file(name.data) == NGX_FILE_ERROR) {
                err = ngx_errno;

                if (err != NGX_ENOENT) {
                    ngx_log_error(NGX_LOG_CRIT, r->connection->log, err,
                                  ngx_delete_file_n " \"%s\" failed",
                                  name.data);
                }
            }
        }

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

        r->request_body->bufs = NULL;
        r->request_body->buf = NULL;

        goto set_header;
    }

    /* register file cleanup hook */

    cln = ngx_pool_cleanup_add(r->pool,
                               sizeof(ngx_pool_cleanup_file_t));

    if (cln == NULL) {
        return luaL_error(L, "no memory");
    }

    cln->handler = clean ? ngx_pool_delete_file : ngx_pool_cleanup_file;
    clnf = cln->data;

    clnf->fd = of.fd;
    clnf->name = name.data;
    clnf->log = r->pool->log;

    b->file = &tf->file;
    if (b->file == NULL) {
        return NGX_HTTP_INTERNAL_SERVER_ERROR;
    }

    dd("XXX file size: %d", (int) of.size);

    b->file_pos = 0;
    b->file_last = of.size;

    b->in_file = 1;

    dd("buf file: %p, f:%u", b->file, b->in_file);

set_header:

    /* override input header Content-Length (value must be null terminated) */

    value.data = ngx_palloc(r->pool, NGX_OFF_T_LEN + 1);
    if (value.data == NULL) {
        return luaL_error(L, "no memory");
    }

    value.len = ngx_sprintf(value.data, "%O", of.size) - value.data;
    value.data[value.len] = '\0';

    r->headers_in.content_length_n = of.size;

    if (r->headers_in.content_length) {
        r->headers_in.content_length->value.data = value.data;
        r->headers_in.content_length->value.len = value.len;

    } else {

        ngx_str_set(&key, "Content-Length");

        rc = ngx_http_lua_set_input_header(r, key, value, 1 /* override */);
        if (rc != NGX_OK) {
            return luaL_error(L, "failed to reset the Content-Length "
                              "input header");
        }
    }

    return 0;
}
static ngx_int_t
ngx_http_range_multipart_header(ngx_http_request_t *r,
    ngx_http_range_filter_ctx_t *ctx)
{
    size_t              len;
    ngx_uint_t          i;
    ngx_http_range_t   *range;
    ngx_atomic_uint_t   boundary;

    len = sizeof(CRLF "--") - 1 + NGX_ATOMIC_T_LEN
          + sizeof(CRLF "Content-Type: ") - 1
          + r->headers_out.content_type.len
          + sizeof(CRLF "Content-Range: bytes ") - 1;

    if (r->headers_out.content_type_len == r->headers_out.content_type.len
        && r->headers_out.charset.len)
    {
        len += sizeof("; charset=") - 1 + r->headers_out.charset.len;
    }

    ctx->boundary_header.data = ngx_pnalloc(r->pool, len);
    if (ctx->boundary_header.data == NULL) {
        return NGX_ERROR;
    }

    boundary = ngx_next_temp_number(0);

    /*
     * The boundary header of the range:
     * CRLF
     * "--0123456789" CRLF
     * "Content-Type: image/jpeg" CRLF
     * "Content-Range: bytes "
     */

    if (r->headers_out.content_type_len == r->headers_out.content_type.len
        && r->headers_out.charset.len)
    {
        ctx->boundary_header.len = ngx_sprintf(ctx->boundary_header.data,
                                           CRLF "--%0muA" CRLF
                                           "Content-Type: %V; charset=%V" CRLF
                                           "Content-Range: bytes ",
                                           boundary,
                                           &r->headers_out.content_type,
                                           &r->headers_out.charset)
                                   - ctx->boundary_header.data;

    } else if (r->headers_out.content_type.len) {
        ctx->boundary_header.len = ngx_sprintf(ctx->boundary_header.data,
                                           CRLF "--%0muA" CRLF
                                           "Content-Type: %V" CRLF
                                           "Content-Range: bytes ",
                                           boundary,
                                           &r->headers_out.content_type)
                                   - ctx->boundary_header.data;

    } else {
        ctx->boundary_header.len = ngx_sprintf(ctx->boundary_header.data,
                                           CRLF "--%0muA" CRLF
                                           "Content-Range: bytes ",
                                           boundary)
                                   - ctx->boundary_header.data;
    }

    r->headers_out.content_type.data =
        ngx_pnalloc(r->pool,
                    sizeof("Content-Type: multipart/byteranges; boundary=") - 1
                    + NGX_ATOMIC_T_LEN);

    if (r->headers_out.content_type.data == NULL) {
        return NGX_ERROR;
    }

    r->headers_out.content_type_lowcase = NULL;

    /* "Content-Type: multipart/byteranges; boundary=0123456789" */

    r->headers_out.content_type.len =
                           ngx_sprintf(r->headers_out.content_type.data,
                                       "multipart/byteranges; boundary=%0muA",
                                       boundary)
                           - r->headers_out.content_type.data;

    r->headers_out.content_type_len = r->headers_out.content_type.len;

    r->headers_out.charset.len = 0;

    /* the size of the last boundary CRLF "--0123456789--" CRLF */

    len = sizeof(CRLF "--") - 1 + NGX_ATOMIC_T_LEN + sizeof("--" CRLF) - 1;

    range = ctx->ranges.elts;
    for (i = 0; i < ctx->ranges.nelts; i++) {

        /* the size of the range: "SSSS-EEEE/TTTT" CRLF CRLF */

        range[i].content_range.data =
                               ngx_pnalloc(r->pool, 3 * NGX_OFF_T_LEN + 2 + 4);

        if (range[i].content_range.data == NULL) {
            return NGX_ERROR;
        }

        range[i].content_range.len = ngx_sprintf(range[i].content_range.data,
                                               "%O-%O/%O" CRLF CRLF,
                                               range[i].start, range[i].end - 1,
                                               r->headers_out.content_length_n)
                                     - range[i].content_range.data;

        len += ctx->boundary_header.len + range[i].content_range.len
                                    + (size_t) (range[i].end - range[i].start);
    }

    r->headers_out.content_length_n = len;

    if (r->headers_out.content_length) {
        r->headers_out.content_length->hash = 0;
        r->headers_out.content_length = NULL;
    }

    return ngx_http_next_header_filter(r);
}
Пример #25
0
ngx_int_t
ngx_http_redis2_build_query(ngx_http_request_t *r, ngx_array_t *queries,
    ngx_buf_t **b)
{
    ngx_uint_t                       i, j;
    ngx_uint_t                       n;
    ngx_str_t                       *arg;
    ngx_array_t                     *args;
    size_t                           len;
    ngx_array_t                    **query_args;
    ngx_http_complex_value_t       **complex_arg;
    u_char                          *p;
    ngx_http_redis2_loc_conf_t      *rlcf;

    rlcf = ngx_http_get_module_loc_conf(r, ngx_http_redis2_module);

    query_args = rlcf->queries->elts;

    n = 0;
    for (i = 0; i < rlcf->queries->nelts; i++) {
        for (j = 0; j < query_args[i]->nelts; j++) {
            n++;
        }
    }

    args = ngx_array_create(r->pool, n, sizeof(ngx_str_t));

    if (args == NULL) {
        return NGX_ERROR;
    }

    len = 0;
    n = 0;

    for (i = 0; i < rlcf->queries->nelts; i++) {
        complex_arg = query_args[i]->elts;

        len += sizeof("*") - 1
             + ngx_get_num_size(query_args[i]->nelts)
             + sizeof("\r\n") - 1
             ;

        for (j = 0; j < query_args[i]->nelts; j++) {
            n++;

            arg = ngx_array_push(args);
            if (arg == NULL) {
                return NGX_ERROR;
            }

            if (ngx_http_complex_value(r, complex_arg[j], arg) != NGX_OK) {
                return NGX_ERROR;
            }

            len += sizeof("$") - 1
                 + ngx_get_num_size(arg->len)
                 + sizeof("\r\n") - 1
                 + arg->len
                 + sizeof("\r\n") - 1
                 ;
        }
    }

    *b = ngx_create_temp_buf(r->pool, len);
    if (*b == NULL) {
        return NGX_ERROR;
    }

    p = (*b)->last;

    arg = args->elts;

    n = 0;
    for (i = 0; i < rlcf->queries->nelts; i++) {
        *p++ = '*';
        p = ngx_sprintf(p, "%uz", query_args[i]->nelts);
        *p++ = '\r'; *p++ = '\n';

        for (j = 0; j < query_args[i]->nelts; j++) {
            *p++ = '$';
            p = ngx_sprintf(p, "%uz", arg[n].len);
            *p++ = '\r'; *p++ = '\n';
            p = ngx_copy(p, arg[n].data, arg[n].len);
            *p++ = '\r'; *p++ = '\n';

            n++;
        }
    }

    dd("query: %.*s", (int) (p - (*b)->pos), (*b)->pos);

    if (p - (*b)->pos != (ssize_t) len) {
        ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
                "redis2: redis2_query buffer error %uz != %uz",
                (size_t) (p - (*b)->pos), len);

        return NGX_ERROR;
    }

    (*b)->last = p;

    return NGX_OK;
}
static ngx_int_t
ngx_rtmp_dash_write_playlist(ngx_rtmp_session_t *s)
{
    char                      *sep;
    u_char                    *p, *last;
    ssize_t                    n;
    ngx_fd_t                   fd;
    struct tm                  tm;
    ngx_str_t                  noname, *name;
    ngx_uint_t                 i, frame_rate_num, frame_rate_denom;
    ngx_rtmp_dash_ctx_t       *ctx;
    ngx_rtmp_codec_ctx_t      *codec_ctx;
    ngx_rtmp_dash_frag_t      *f;
    ngx_rtmp_dash_app_conf_t  *dacf;

    static u_char              buffer[NGX_RTMP_DASH_BUFSIZE];
    static u_char              start_time[sizeof("1970-09-28T12:00:00+06:00")];
    static u_char              end_time[sizeof("1970-09-28T12:00:00+06:00")];
    static u_char              frame_rate[(NGX_INT_T_LEN * 2) + 2];

    dacf = ngx_rtmp_get_module_app_conf(s, ngx_rtmp_dash_module);
    ctx = ngx_rtmp_get_module_ctx(s, ngx_rtmp_dash_module);
    codec_ctx = ngx_rtmp_get_module_ctx(s, ngx_rtmp_codec_module);

    if (dacf == NULL || ctx == NULL || codec_ctx == NULL) {
        return NGX_ERROR;
    }

    if (ctx->id == 0) {
        ngx_rtmp_dash_write_init_segments(s);
    }

    fd = ngx_open_file(ctx->playlist_bak.data, NGX_FILE_WRONLY,
                       NGX_FILE_TRUNCATE, NGX_FILE_DEFAULT_ACCESS);

    if (fd == NGX_INVALID_FILE) {
        ngx_log_error(NGX_LOG_ERR, s->connection->log, ngx_errno,
                      "dash: open failed: '%V'", &ctx->playlist_bak);
        return NGX_ERROR;
    }


#define NGX_RTMP_DASH_MANIFEST_HEADER                                          \
    "<?xml version=\"1.0\"?>\n"                                                \
    "<MPD\n"                                                                   \
    "    type=\"dynamic\"\n"                                                   \
    "    xmlns=\"urn:mpeg:dash:schema:mpd:2011\"\n"                            \
    "    availabilityStartTime=\"%s\"\n"                                       \
    "    availabilityEndTime=\"%s\"\n"                                         \
    "    minimumUpdatePeriod=\"PT%uiS\"\n"                                     \
    "    minBufferTime=\"PT%uiS\"\n"                                           \
    "    timeShiftBufferDepth=\"PT0H0M0.00S\"\n"                               \
    "    suggestedPresentationDelay=\"PT%uiS\"\n"                              \
    "    profiles=\"urn:hbbtv:dash:profile:isoff-live:2012,"                   \
                   "urn:mpeg:dash:profile:isoff-live:2011\"\n"                 \
    "    xmlns:xsi=\"http://www.w3.org/2011/XMLSchema-instance\"\n"            \
    "    xsi:schemaLocation=\"urn:mpeg:DASH:schema:MPD:2011 DASH-MPD.xsd\">\n" \
    "  <Period start=\"PT0S\" id=\"dash\">\n"


#define NGX_RTMP_DASH_MANIFEST_VIDEO                                           \
    "    <AdaptationSet\n"                                                     \
    "        id=\"1\"\n"                                                       \
    "        segmentAlignment=\"true\"\n"                                      \
    "        maxWidth=\"%ui\"\n"                                               \
    "        maxHeight=\"%ui\"\n"                                              \
    "        maxFrameRate=\"%s\">\n"                                           \
    "      <Representation\n"                                                  \
    "          id=\"%V_H264\"\n"                                               \
    "          mimeType=\"video/mp4\"\n"                                       \
    "          codecs=\"avc1.%02uxi%02uxi%02uxi\"\n"                           \
    "          width=\"%ui\"\n"                                                \
    "          height=\"%ui\"\n"                                               \
    "          frameRate=\"%s\"\n"                                             \
    "          sar=\"1:1\"\n"                                                  \
    "          startWithSAP=\"1\"\n"                                           \
    "          bandwidth=\"%ui\">\n"                                           \
    "        <SegmentTemplate\n"                                               \
    "            presentationTimeOffset=\"0\"\n"                               \
    "            timescale=\"1000\"\n"                                         \
    "            media=\"%V%s$Time$.m4v\"\n"                                   \
    "            initialization=\"%V%sinit.m4v\">\n"                           \
    "          <SegmentTimeline>\n"


#define NGX_RTMP_DASH_MANIFEST_VIDEO_FOOTER                                    \
    "          </SegmentTimeline>\n"                                           \
    "        </SegmentTemplate>\n"                                             \
    "      </Representation>\n"                                                \
    "    </AdaptationSet>\n"


#define NGX_RTMP_DASH_MANIFEST_TIME                                            \
    "             <S t=\"%uD\" d=\"%uD\"/>\n"


#define NGX_RTMP_DASH_MANIFEST_AUDIO                                           \
    "    <AdaptationSet\n"                                                     \
    "        id=\"2\"\n"                                                       \
    "        segmentAlignment=\"true\">\n"                                     \
    "      <AudioChannelConfiguration\n"                                       \
    "          schemeIdUri=\"urn:mpeg:dash:"                                   \
                                "23003:3:audio_channel_configuration:2011\"\n" \
    "          value=\"1\"/>\n"                                                \
    "      <Representation\n"                                                  \
    "          id=\"%V_AAC\"\n"                                                \
    "          mimeType=\"audio/mp4\"\n"                                       \
    "          codecs=\"mp4a.%s\"\n"                                           \
    "          audioSamplingRate=\"%ui\"\n"                                    \
    "          startWithSAP=\"1\"\n"                                           \
    "          bandwidth=\"%ui\">\n"                                           \
    "        <SegmentTemplate\n"                                               \
    "            presentationTimeOffset=\"0\"\n"                               \
    "            timescale=\"1000\"\n"                                         \
    "            media=\"%V%s$Time$.m4a\"\n"                                   \
    "            initialization=\"%V%sinit.m4a\">\n"                           \
    "          <SegmentTimeline>\n"


#define NGX_RTMP_DASH_MANIFEST_AUDIO_FOOTER                                    \
    "          </SegmentTimeline>\n"                                           \
    "        </SegmentTemplate>\n"                                             \
    "      </Representation>\n"                                                \
    "    </AdaptationSet>\n"


#define NGX_RTMP_DASH_MANIFEST_FOOTER                                          \
    "  </Period>\n"                                                            \
    "</MPD>\n"

    ngx_libc_localtime(ctx->start_time.sec +
                       ngx_rtmp_dash_get_frag(s, 0)->timestamp / 1000, &tm);

    *ngx_sprintf(start_time, "%4d-%02d-%02dT%02d:%02d:%02d%c%02d:%02d",
                 tm.tm_year + 1900, tm.tm_mon + 1,
                 tm.tm_mday, tm.tm_hour,
                 tm.tm_min, tm.tm_sec,
                 ctx->start_time.gmtoff < 0 ? '-' : '+',
                 ngx_abs(ctx->start_time.gmtoff / 60),
                 ngx_abs(ctx->start_time.gmtoff % 60)) = 0;

    ngx_libc_localtime(ctx->start_time.sec +
                       (ngx_rtmp_dash_get_frag(s, ctx->nfrags - 1)->timestamp +
                        ngx_rtmp_dash_get_frag(s, ctx->nfrags - 1)->duration) /
                       1000, &tm);

    *ngx_sprintf(end_time, "%4d-%02d-%02dT%02d:%02d:%02d%c%02d:%02d",
                 tm.tm_year + 1900, tm.tm_mon + 1,
                 tm.tm_mday, tm.tm_hour,
                 tm.tm_min, tm.tm_sec,
                 ctx->start_time.gmtoff < 0 ? '-' : '+',
                 ngx_abs(ctx->start_time.gmtoff / 60),
                 ngx_abs(ctx->start_time.gmtoff % 60)) = 0;

    last = buffer + sizeof(buffer);

    p = ngx_slprintf(buffer, last, NGX_RTMP_DASH_MANIFEST_HEADER,
                     start_time,
                     end_time,
                     (ngx_uint_t) (dacf->fraglen / 1000),
                     (ngx_uint_t) (dacf->fraglen / 1000),
                     (ngx_uint_t) (dacf->fraglen / 500));

    n = ngx_write_fd(fd, buffer, p - buffer);

    ngx_str_null(&noname);

    name = (dacf->nested ? &noname : &ctx->name);
    sep = (dacf->nested ? "" : "-");

    if (ctx->has_video) {
        frame_rate_num = (ngx_uint_t) (codec_ctx->frame_rate * 1000.);

        if (frame_rate_num % 1000 == 0) {
            *ngx_sprintf(frame_rate, "%ui", frame_rate_num / 1000) = 0;
        } else {
            frame_rate_denom = 1000;
            switch (frame_rate_num) {
                case 23976:
                    frame_rate_num = 24000;
                    frame_rate_denom = 1001;
                    break;
                case 29970:
                    frame_rate_num = 30000;
                    frame_rate_denom = 1001;
                    break;
                case 59940:
                    frame_rate_num = 60000;
                    frame_rate_denom = 1001;
                    break;
            }

            *ngx_sprintf(frame_rate, "%ui/%ui", frame_rate_num, frame_rate_denom) = 0;
        }

        p = ngx_slprintf(buffer, last, NGX_RTMP_DASH_MANIFEST_VIDEO,
                         codec_ctx->width,
                         codec_ctx->height,
                         frame_rate,
                         &ctx->name,
                         codec_ctx->avc_profile,
                         codec_ctx->avc_compat,
                         codec_ctx->avc_level,
                         codec_ctx->width,
                         codec_ctx->height,
                         frame_rate,
                         (ngx_uint_t) (codec_ctx->video_data_rate * 1000),
                         name, sep,
                         name, sep);

        for (i = 0; i < ctx->nfrags; i++) {
            f = ngx_rtmp_dash_get_frag(s, i);
            p = ngx_slprintf(p, last, NGX_RTMP_DASH_MANIFEST_TIME,
                             f->timestamp, f->duration);
        }

        p = ngx_slprintf(p, last, NGX_RTMP_DASH_MANIFEST_VIDEO_FOOTER);

        n = ngx_write_fd(fd, buffer, p - buffer);
    }

    if (ctx->has_audio) {
        p = ngx_slprintf(buffer, last, NGX_RTMP_DASH_MANIFEST_AUDIO,
                         &ctx->name,
                         codec_ctx->audio_codec_id == NGX_RTMP_AUDIO_AAC ?
                         (codec_ctx->aac_sbr ? "40.5" : "40.2") : "6b",
                         codec_ctx->sample_rate,
                         (ngx_uint_t) (codec_ctx->audio_data_rate * 1000),
                         name, sep,
                         name, sep);

        for (i = 0; i < ctx->nfrags; i++) {
            f = ngx_rtmp_dash_get_frag(s, i);
            p = ngx_slprintf(p, last, NGX_RTMP_DASH_MANIFEST_TIME,
                             f->timestamp, f->duration);
        }

        p = ngx_slprintf(p, last, NGX_RTMP_DASH_MANIFEST_AUDIO_FOOTER);

        n = ngx_write_fd(fd, buffer, p - buffer);
    }

    p = ngx_slprintf(buffer, last, NGX_RTMP_DASH_MANIFEST_FOOTER);
    n = ngx_write_fd(fd, buffer, p - buffer);

    if (n < 0) {
        ngx_log_error(NGX_LOG_ERR, s->connection->log, ngx_errno,
                      "dash: write failed: '%V'", &ctx->playlist_bak);
        ngx_close_file(fd);
        return NGX_ERROR;
    }

    ngx_close_file(fd);

    if (ngx_rtmp_dash_rename_file(ctx->playlist_bak.data, ctx->playlist.data)
        == NGX_FILE_ERROR)
    {
        ngx_log_error(NGX_LOG_ERR, s->connection->log, ngx_errno,
                      "dash: rename failed: '%V'->'%V'",
                      &ctx->playlist_bak, &ctx->playlist);
        return NGX_ERROR;
    }

    return NGX_OK;
}
static ngx_int_t
ngx_http_set_expires(ngx_http_request_t *r, ngx_http_headers_conf_t *conf)
{
    size_t            len;
    time_t            now, expires_time, max_age;
    ngx_uint_t        i;
    ngx_table_elt_t  *expires, *cc, **ccp;

    expires = r->headers_out.expires;

    if (expires == NULL) {

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

        r->headers_out.expires = expires;

        expires->hash = 1;
        ngx_str_set(&expires->key, "Expires");
    }

    len = sizeof("Mon, 28 Sep 1970 06:00:00 GMT");
    expires->value.len = len - 1;

    ccp = r->headers_out.cache_control.elts;

    if (ccp == NULL) {

        if (ngx_array_init(&r->headers_out.cache_control, r->pool,
                           1, sizeof(ngx_table_elt_t *))
                != NGX_OK)
        {
            return NGX_ERROR;
        }

        ccp = ngx_array_push(&r->headers_out.cache_control);
        if (ccp == NULL) {
            return NGX_ERROR;
        }

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

        cc->hash = 1;
        ngx_str_set(&cc->key, "Cache-Control");
        *ccp = cc;

    } else {
        for (i = 1; i < r->headers_out.cache_control.nelts; i++) {
            ccp[i]->hash = 0;
        }

        cc = ccp[0];
    }

    if (conf->expires == NGX_HTTP_EXPIRES_EPOCH) {
        expires->value.data = (u_char *) "Thu, 01 Jan 1970 00:00:01 GMT";
        ngx_str_set(&cc->value, "no-cache");
        return NGX_OK;
    }

    if (conf->expires == NGX_HTTP_EXPIRES_MAX) {
        expires->value.data = (u_char *) "Thu, 31 Dec 2037 23:55:55 GMT";
        /* 10 years */
        ngx_str_set(&cc->value, "max-age=315360000");
        return NGX_OK;
    }

    expires->value.data = ngx_pnalloc(r->pool, len);
    if (expires->value.data == NULL) {
        return NGX_ERROR;
    }

    if (conf->expires_time == 0 && conf->expires != NGX_HTTP_EXPIRES_DAILY) {
        ngx_memcpy(expires->value.data, ngx_cached_http_time.data,
                   ngx_cached_http_time.len + 1);
        ngx_str_set(&cc->value, "max-age=0");
        return NGX_OK;
    }

    now = ngx_time();

    if (conf->expires == NGX_HTTP_EXPIRES_DAILY) {
        expires_time = ngx_next_time(conf->expires_time);
        max_age = expires_time - now;

    } else if (conf->expires == NGX_HTTP_EXPIRES_ACCESS
               || r->headers_out.last_modified_time == -1)
    {
        expires_time = now + conf->expires_time;
        max_age = conf->expires_time;

    } else {
        expires_time = r->headers_out.last_modified_time + conf->expires_time;
        max_age = expires_time - now;
    }

    ngx_http_time(expires->value.data, expires_time);

    if (conf->expires_time < 0 || max_age < 0) {
        ngx_str_set(&cc->value, "no-cache");
        return NGX_OK;
    }

    cc->value.data = ngx_pnalloc(r->pool,
                                 sizeof("max-age=") + NGX_TIME_T_LEN + 1);
    if (cc->value.data == NULL) {
        return NGX_ERROR;
    }

    cc->value.len = ngx_sprintf(cc->value.data, "max-age=%T", max_age)
                    - cc->value.data;

    return NGX_OK;
}
static ngx_int_t
ngx_rtmp_dash_write_init_segments(ngx_rtmp_session_t *s)
{
    ngx_fd_t               fd;
    ngx_int_t              rc;
    ngx_buf_t              b;
    ngx_rtmp_dash_ctx_t   *ctx;
    ngx_rtmp_codec_ctx_t  *codec_ctx;

    static u_char          buffer[NGX_RTMP_DASH_BUFSIZE];

    ctx = ngx_rtmp_get_module_ctx(s, ngx_rtmp_dash_module);
    codec_ctx = ngx_rtmp_get_module_ctx(s, ngx_rtmp_codec_module);

    if (ctx == NULL || codec_ctx == NULL) {
        return NGX_ERROR;
    }

    /* init video */

    *ngx_sprintf(ctx->stream.data + ctx->stream.len, "init.m4v") = 0;

    fd = ngx_open_file(ctx->stream.data, NGX_FILE_RDWR, NGX_FILE_TRUNCATE,
                       NGX_FILE_DEFAULT_ACCESS);

    if (fd == NGX_INVALID_FILE) {
        ngx_log_error(NGX_LOG_ERR, s->connection->log, ngx_errno,
                      "dash: error creating video init file");
        return NGX_ERROR;
    }

    b.start = buffer;
    b.end = b.start + sizeof(buffer);
    b.pos = b.last = b.start;

    ngx_rtmp_mp4_write_ftyp(&b);
    ngx_rtmp_mp4_write_moov(s, &b, NGX_RTMP_MP4_VIDEO_TRACK);

    rc = ngx_write_fd(fd, b.start, (size_t) (b.last - b.start));
    if (rc == NGX_ERROR) {
        ngx_log_error(NGX_LOG_ERR, s->connection->log, ngx_errno,
                      "dash: writing video init failed");
    }

    ngx_close_file(fd);

    /* init audio */

    *ngx_sprintf(ctx->stream.data + ctx->stream.len, "init.m4a") = 0;

    fd = ngx_open_file(ctx->stream.data, NGX_FILE_RDWR, NGX_FILE_TRUNCATE,
                       NGX_FILE_DEFAULT_ACCESS);

    if (fd == NGX_INVALID_FILE) {
        ngx_log_error(NGX_LOG_ERR, s->connection->log, ngx_errno,
                      "dash: error creating dash audio init file");
        return NGX_ERROR;
    }

    b.pos = b.last = b.start;

    ngx_rtmp_mp4_write_ftyp(&b);
    ngx_rtmp_mp4_write_moov(s, &b, NGX_RTMP_MP4_AUDIO_TRACK);

    rc = ngx_write_fd(fd, b.start, (size_t) (b.last - b.start));
    if (rc == NGX_ERROR) {
        ngx_log_error(NGX_LOG_ERR, s->connection->log, ngx_errno,
                      "dash: writing audio init failed");
    }

    ngx_close_file(fd);

    return NGX_OK;
}
Пример #29
0
static void
ngx_mail_proxy_imap_handler(ngx_event_t *rev)
{
    u_char                 *p;
    ngx_int_t               rc;
    ngx_str_t               line;
    ngx_connection_t       *c;
    ngx_mail_session_t     *s;
    ngx_mail_proxy_conf_t  *pcf;

    ngx_log_debug0(NGX_LOG_DEBUG_MAIL, rev->log, 0,
                   "mail proxy imap auth handler");

    c = rev->data;
    s = c->data;

    if (rev->timedout) {
        ngx_log_error(NGX_LOG_INFO, c->log, NGX_ETIMEDOUT,
                      "upstream timed out");
        c->timedout = 1;
        ngx_mail_proxy_internal_server_error(s);
        return;
    }

    rc = ngx_mail_proxy_read_response(s, s->mail_state);

    if (rc == NGX_AGAIN) {
        return;
    }

    if (rc == NGX_ERROR) {
        ngx_mail_proxy_upstream_error(s);
        return;
    }

    switch (s->mail_state) {

    case ngx_imap_start:
        ngx_log_debug0(NGX_LOG_DEBUG_MAIL, rev->log, 0,
                       "mail proxy send login");

        s->connection->log->action = "sending LOGIN command to upstream";

        line.len = s->tag.len + sizeof("LOGIN ") - 1
                   + 1 + NGX_SIZE_T_LEN + 1 + 2;
        line.data = ngx_pnalloc(c->pool, line.len);
        if (line.data == NULL) {
            ngx_mail_proxy_internal_server_error(s);
            return;
        }

        line.len = ngx_sprintf(line.data, "%VLOGIN {%uz}" CRLF,
                               &s->tag, s->login.len)
                   - line.data;

        s->mail_state = ngx_imap_login;
        break;

    case ngx_imap_login:
        ngx_log_debug0(NGX_LOG_DEBUG_MAIL, rev->log, 0, "mail proxy send user");

        s->connection->log->action = "sending user name to upstream";

        line.len = s->login.len + 1 + 1 + NGX_SIZE_T_LEN + 1 + 2;
        line.data = ngx_pnalloc(c->pool, line.len);
        if (line.data == NULL) {
            ngx_mail_proxy_internal_server_error(s);
            return;
        }

        line.len = ngx_sprintf(line.data, "%V {%uz}" CRLF,
                               &s->login, s->passwd.len)
                   - line.data;

        s->mail_state = ngx_imap_user;
        break;

    case ngx_imap_user:
        ngx_log_debug0(NGX_LOG_DEBUG_MAIL, rev->log, 0,
                       "mail proxy send passwd");

        s->connection->log->action = "sending password to upstream";

        line.len = s->passwd.len + 2;
        line.data = ngx_pnalloc(c->pool, line.len);
        if (line.data == NULL) {
            ngx_mail_proxy_internal_server_error(s);
            return;
        }

        p = ngx_cpymem(line.data, s->passwd.data, s->passwd.len);
        *p++ = CR; *p = LF;

        s->mail_state = ngx_imap_passwd;
        break;

    case ngx_imap_passwd:
        s->connection->read->handler = ngx_mail_proxy_handler;
        s->connection->write->handler = ngx_mail_proxy_handler;
        rev->handler = ngx_mail_proxy_handler;
        c->write->handler = ngx_mail_proxy_handler;

        pcf = ngx_mail_get_module_srv_conf(s, ngx_mail_proxy_module);
        ngx_add_timer(s->connection->read, pcf->timeout);
        ngx_del_timer(c->read);

        c->log->action = NULL;
        ngx_log_error(NGX_LOG_INFO, c->log, 0, "client logged in");

        ngx_mail_proxy_handler(s->connection->write);

        return;

    default:
#if (NGX_SUPPRESS_WARN)
        ngx_str_null(&line);
#endif
        break;
    }

    if (c->send(c, line.data, line.len) < (ssize_t) line.len) {
        /*
         * we treat the incomplete sending as NGX_ERROR
         * because it is very strange here
         */
        ngx_mail_proxy_internal_server_error(s);
        return;
    }

    s->proxy->buffer->pos = s->proxy->buffer->start;
    s->proxy->buffer->last = s->proxy->buffer->start;
}
Пример #30
0
static ngx_int_t ngx_http_gridfs_handler(ngx_http_request_t* request) {
    ngx_http_gridfs_loc_conf_t* gridfs_conf;
    ngx_http_core_loc_conf_t* core_conf;
    ngx_buf_t* buffer;
    ngx_chain_t out;
    ngx_str_t location_name;
    ngx_str_t full_uri;
    char* value;
    ngx_http_mongo_connection_t *mongo_conn;
    gridfs gfs;
    gridfile gfile;
    gridfs_offset length;
    ngx_uint_t numchunks;
    char* contenttype;
    char* md5;
    bson_date_t last_modified;

    volatile ngx_uint_t i;
    ngx_int_t rc = NGX_OK;
    bson query;
    bson_oid_t oid;
    mongo_cursor ** cursors;
    gridfs_offset chunk_len;
    const char * chunk_data;
    bson_iterator it;
    bson chunk;
    ngx_pool_cleanup_t* gridfs_cln;
    ngx_http_gridfs_cleanup_t* gridfs_clndata;
    int status;
    volatile ngx_uint_t e = FALSE;
    volatile ngx_uint_t ecounter = 0;
    uint64_t range_start = 0;
    uint64_t range_end   = 0;
    uint64_t current_buf_pos = 0;

    gridfs_conf = ngx_http_get_module_loc_conf(request, ngx_http_gridfs_module);
    core_conf = ngx_http_get_module_loc_conf(request, ngx_http_core_module);

    // ---------- ENSURE MONGO CONNECTION ---------- //

    mongo_conn = ngx_http_get_mongo_connection( gridfs_conf->mongo );
    if (mongo_conn == NULL) {
        ngx_log_error(NGX_LOG_ERR, request->connection->log, 0,
                      "Mongo Connection not found: \"%V\"", &gridfs_conf->mongo);
        return NGX_HTTP_INTERNAL_SERVER_ERROR;
    }

    if (mongo_conn->conn.connected == 0) {
        if (ngx_http_mongo_reconnect(request->connection->log, mongo_conn) == NGX_ERROR) {
            ngx_log_error(NGX_LOG_ERR, request->connection->log, 0,
                          "Could not connect to mongo: \"%V\"", &gridfs_conf->mongo);
            if(mongo_conn->conn.connected) { mongo_disconnect(&mongo_conn->conn); }
            return NGX_HTTP_SERVICE_UNAVAILABLE;
        }
        if (ngx_http_mongo_reauth(request->connection->log, mongo_conn) == NGX_ERROR) {
            ngx_log_error(NGX_LOG_ERR, request->connection->log, 0,
                          "Failed to reauth to mongo: \"%V\"", &gridfs_conf->mongo);
            if(mongo_conn->conn.connected) { mongo_disconnect(&mongo_conn->conn); }
            return NGX_HTTP_SERVICE_UNAVAILABLE;
        }
    }

    // ---------- RETRIEVE KEY ---------- //

    location_name = core_conf->name;
    full_uri = request->uri;

    if (full_uri.len < location_name.len) {
        ngx_log_error(NGX_LOG_ERR, request->connection->log, 0,
                      "Invalid location name or uri.");
        return NGX_HTTP_INTERNAL_SERVER_ERROR;
    }

    value = (char*)malloc(sizeof(char) * (full_uri.len - location_name.len + 1));
    if (value == NULL) {
        ngx_log_error(NGX_LOG_ERR, request->connection->log, 0,
                      "Failed to allocate memory for value buffer.");
        return NGX_HTTP_INTERNAL_SERVER_ERROR;
    }
    memcpy(value, full_uri.data + location_name.len, full_uri.len - location_name.len);
    value[full_uri.len - location_name.len] = '\0';

    if (!url_decode(value)) {
        ngx_log_error(NGX_LOG_ERR, request->connection->log, 0,
                      "Malformed request.");
        free(value);
        return NGX_HTTP_BAD_REQUEST;
    }

    // ---------- RETRIEVE GRIDFILE ---------- //

    bson_init(&query);
    switch (gridfs_conf->type) {
    case  BSON_OID:
        bson_oid_from_string(&oid, value);
        bson_append_oid(&query, (char*)gridfs_conf->field.data, &oid);
        break;
    case BSON_INT:
      bson_append_int(&query, (char*)gridfs_conf->field.data, ngx_atoi((u_char*)value, strlen(value)));
        break;
    case BSON_STRING:
        bson_append_string(&query, (char*)gridfs_conf->field.data, value);
        break;
    }
    bson_finish(&query);

    do {
        e = FALSE;
        if (gridfs_init(&mongo_conn->conn,
                        (const char*)gridfs_conf->db.data,
                        (const char*)gridfs_conf->root_collection.data,
                        &gfs) != MONGO_OK
            || (status = gridfs_find_query(&gfs, &query, &gfile) == MONGO_ERROR)) {
            e = TRUE; ecounter++;
            if (ecounter > MONGO_MAX_RETRIES_PER_REQUEST
                || ngx_http_mongo_reconnect(request->connection->log, mongo_conn) == NGX_ERROR
                || ngx_http_mongo_reauth(request->connection->log, mongo_conn) == NGX_ERROR) {
                ngx_log_error(NGX_LOG_ERR, request->connection->log, 0,
                              "Mongo connection dropped, could not reconnect");
                if(&mongo_conn->conn.connected) { mongo_disconnect(&mongo_conn->conn); }
                bson_destroy(&query);
                free(value);
                return NGX_HTTP_SERVICE_UNAVAILABLE;
            }
        }
    } while (e);

    bson_destroy(&query);
    free(value);

    /* Get information about the file */
    length = gridfile_get_contentlength(&gfile);
    numchunks = gridfile_get_numchunks(&gfile);

    // NaN workaround
    if (numchunks > INT_MAX)
    {
        gridfile_destroy(&gfile);
        gridfs_destroy(&gfs);
        return NGX_HTTP_NOT_FOUND;
    }

    contenttype = (char*)gridfile_get_contenttype(&gfile);

    md5 = (char*)gridfile_get_md5(&gfile);
    last_modified = gridfile_get_uploaddate(&gfile);

    // ---------- Partial Range
    // set follow-fork-mode child
    // attach (pid)
    // break ngx_http_gridfs_module.c:959

    if (request->headers_in.range) {
        gridfs_parse_range(request, &request->headers_in.range->value, &range_start, &range_end, length);
    }

    // ---------- SEND THE HEADERS ---------- //

    if (range_start == 0 && range_end == 0) {
        request->headers_out.status = NGX_HTTP_OK;
        request->headers_out.content_length_n = length;
    } else {
        request->headers_out.status = NGX_HTTP_PARTIAL_CONTENT;
        request->headers_out.content_length_n = length;
        //request->headers_out.content_range = range_end - range_start + 1;

        ngx_table_elt_t   *content_range;

        content_range = ngx_list_push(&request->headers_out.headers);
        if (content_range == NULL) {
            return NGX_ERROR;
        }

        request->headers_out.content_range = content_range;

        content_range->hash = 1;
        ngx_str_set(&content_range->key, "Content-Range");

        content_range->value.data = ngx_pnalloc(request->pool,sizeof("bytes -/") - 1 + 3 * NGX_OFF_T_LEN);
        if (content_range->value.data == NULL) {
            return NGX_ERROR;
        }

        /* "Content-Range: bytes SSSS-EEEE/TTTT" header */
        content_range->value.len = ngx_sprintf(content_range->value.data,
                                               "bytes %O-%O/%O",
                                               range_start, range_end,
                                               request->headers_out.content_length_n)
            - content_range->value.data;

        request->headers_out.content_length_n = range_end - range_start + 1;
    }
    if (contenttype != NULL) {
        request->headers_out.content_type.len = strlen(contenttype);
        request->headers_out.content_type.data = (u_char*)contenttype;
    }
    else ngx_http_set_content_type(request);

    // use md5 field as ETag if possible
    if (md5 != NULL) {
        request->headers_out.etag = ngx_list_push(&request->headers_out.headers);
        request->headers_out.etag->hash = 1;
        request->headers_out.etag->key.len = sizeof("ETag") - 1;
        request->headers_out.etag->key.data = (u_char*)"ETag";

        ngx_buf_t *b;
        b = ngx_create_temp_buf(request->pool, strlen(md5) + 2);
        b->last = ngx_sprintf(b->last, "\"%s\"", md5);
        request->headers_out.etag->value.len = strlen(md5) + 2;
        request->headers_out.etag->value.data = b->start;
    }

    // use uploadDate field as last_modified if possible
    if (last_modified) {
        request->headers_out.last_modified_time = (time_t)(last_modified/1000);
    }

    /* Determine if content is gzipped, set headers accordingly */
    if ( gridfile_get_boolean(&gfile,"gzipped") ) {
        ngx_log_error(NGX_LOG_ERR, request->connection->log, 0, gridfile_get_field(&gfile,"gzipped") );
        request->headers_out.content_encoding = ngx_list_push(&request->headers_out.headers);
        if (request->headers_out.content_encoding == NULL) {
            gridfile_destroy(&gfile);
            gridfs_destroy(&gfs);
            return NGX_ERROR;
        }
        request->headers_out.content_encoding->hash = 1;
        request->headers_out.content_encoding->key.len = sizeof("Content-Encoding") - 1;
        request->headers_out.content_encoding->key.data = (u_char *) "Content-Encoding";
        request->headers_out.content_encoding->value.len = sizeof("gzip") - 1;
        request->headers_out.content_encoding->value.data = (u_char *) "gzip";
    }

    ngx_http_send_header(request);

    // ---------- SEND THE BODY ---------- //

    /* Empty file */
    if (numchunks == 0) {
        /* Allocate space for the response buffer */
        buffer = ngx_pcalloc(request->pool, sizeof(ngx_buf_t));
        if (buffer == NULL) {
            ngx_log_error(NGX_LOG_ERR, request->connection->log, 0,
                          "Failed to allocate response buffer");
            gridfile_destroy(&gfile);
            gridfs_destroy(&gfs);
            return NGX_HTTP_INTERNAL_SERVER_ERROR;
        }

        buffer->pos = NULL;
        buffer->last = NULL;
        buffer->memory = 1;
        buffer->last_buf = 1;
        out.buf = buffer;
        out.next = NULL;

        gridfile_destroy(&gfile);
        gridfs_destroy(&gfs);

        return ngx_http_output_filter(request, &out);
    }

    cursors = (mongo_cursor **)ngx_pcalloc(request->pool, sizeof(mongo_cursor *) * numchunks);
    if (cursors == NULL) {
      gridfile_destroy(&gfile);
      gridfs_destroy(&gfs);
      return NGX_HTTP_INTERNAL_SERVER_ERROR;
    }

    ngx_memzero( cursors, sizeof(mongo_cursor *) * numchunks);

    /* Hook in the cleanup function */
    gridfs_cln = ngx_pool_cleanup_add(request->pool, sizeof(ngx_http_gridfs_cleanup_t));
    if (gridfs_cln == NULL) {
      gridfile_destroy(&gfile);
      gridfs_destroy(&gfs);
      return NGX_HTTP_INTERNAL_SERVER_ERROR;
    }
    gridfs_cln->handler = ngx_http_gridfs_cleanup;
    gridfs_clndata = gridfs_cln->data;
    gridfs_clndata->cursors = cursors;
    gridfs_clndata->numchunks = numchunks;

    /* Read and serve chunk by chunk */
    for (i = 0; i < numchunks; i++) {

        /* Allocate space for the response buffer */
        buffer = ngx_pcalloc(request->pool, sizeof(ngx_buf_t));
        if (buffer == NULL) {
            ngx_log_error(NGX_LOG_ERR, request->connection->log, 0,
                          "Failed to allocate response buffer");
            gridfile_destroy(&gfile);
            gridfs_destroy(&gfs);
            return NGX_HTTP_INTERNAL_SERVER_ERROR;
        }

        /* Fetch the chunk from mongo */
        do {
            e = FALSE;
            cursors[i] = gridfile_get_chunks(&gfile, i, 1);
            if (!(cursors[i] && mongo_cursor_next(cursors[i]) == MONGO_OK)) {
                e = TRUE; ecounter++;
                if (ecounter > MONGO_MAX_RETRIES_PER_REQUEST
                    || ngx_http_mongo_reconnect(request->connection->log, mongo_conn) == NGX_ERROR
                    || ngx_http_mongo_reauth(request->connection->log, mongo_conn) == NGX_ERROR) {
                    ngx_log_error(NGX_LOG_ERR, request->connection->log, 0,
                                  "Mongo connection dropped, could not reconnect");
                    if(mongo_conn->conn.connected) { mongo_disconnect(&mongo_conn->conn); }
                    gridfile_destroy(&gfile);
                    gridfs_destroy(&gfs);
                    return NGX_HTTP_SERVICE_UNAVAILABLE;
                }
            }
        } while (e);

        chunk = cursors[i]->current;
        bson_find(&it, &chunk, "data");
        chunk_len = bson_iterator_bin_len( &it ); // break ngx_http_gridfs_module.c:1099
        chunk_data = bson_iterator_bin_data( &it );

        if (range_start == 0 && range_end == 0) {
            /* <<no range request>> */
            /* Set up the buffer chain */
            buffer->pos = (u_char*)chunk_data;
            buffer->last = (u_char*)chunk_data + chunk_len;
            buffer->memory = 1;
            buffer->last_buf = (i == numchunks-1);
            out.buf = buffer;
            out.next = NULL;

            /* Serve the Chunk */
            rc = ngx_http_output_filter(request, &out);
        } else {
            /* <<range request>> */
            if ( range_start >= (current_buf_pos+chunk_len) ||
                 range_end <= current_buf_pos) {
                /* no output */
                ngx_pfree(request->pool, buffer);
            } else {
                if (range_start <= current_buf_pos) {
                    buffer->pos = (u_char*)chunk_data;
                } else {
                    buffer->pos = (u_char*)chunk_data + (range_start - current_buf_pos);
                }
                if (range_end < (current_buf_pos+chunk_len)) {
                    buffer->last = (u_char*)chunk_data + (range_end - current_buf_pos + 1);
                } else {
                    buffer->last = (u_char*)chunk_data + chunk_len;
                }
                if (buffer->pos == buffer->last) {
                    ngx_log_error(NGX_LOG_ALERT, request->connection->log, 0,
                                  "zero size buf in writer "
                                  "range_start:%d range_end:%d "
                                  "current_buf_pos:%d chunk_len:%d i:%d numchunk:%d",
                                  range_start,range_end,
                                  current_buf_pos, chunk_len,
                                  i,numchunks);
                }
                buffer->memory = 1;
                buffer->last_buf = (i == numchunks-1) || (range_end < (current_buf_pos+chunk_len));
                out.buf = buffer;
                out.next = NULL;

                /* Serve the Chunk */
                rc = ngx_http_output_filter(request, &out);
            }
        }

        current_buf_pos += chunk_len;

        /* TODO: More Codes to Catch? */
        if (rc == NGX_ERROR) {
            gridfile_destroy(&gfile);
            gridfs_destroy(&gfs);
            return NGX_ERROR;
        }
    }

    gridfile_destroy(&gfile);
    gridfs_destroy(&gfs);

    return rc;
}