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); }
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; }
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; }
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); }
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); }
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; }
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; }
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; }
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; }
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; }
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); }
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; }
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; }
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; }