static ngx_int_t chunked_respond_message(subscriber_t *sub, nchan_msg_t *msg) { static u_char chunk_start[15]; //that's enough static u_char *chunk_end=(u_char *)"\r\n"; full_subscriber_t *fsub = (full_subscriber_t *)sub; ngx_buf_t *msg_buf = msg->buf; ngx_int_t rc; nchan_request_ctx_t *ctx = ngx_http_get_module_ctx(fsub->sub.request, nchan_module); if (ngx_buf_size(msg_buf) == 0) { //empty messages are skipped, because a zero-length chunk finalizes the request return NGX_OK; } nchan_buf_and_chain_t bc[3]; bc[0].chain.buf = &bc[0].buf; bc[0].chain.next = &bc[1].chain; ngx_memzero(&bc[0].buf, sizeof(ngx_buf_t)); bc[0].buf.memory = 1; bc[0].buf.start = chunk_start; bc[0].buf.pos = chunk_start; bc[0].buf.end = ngx_snprintf(chunk_start, 15, "%xi\r\n", ngx_buf_size(msg_buf)); bc[0].buf.last = bc[0].buf.end; bc[1].chain.buf = &bc[1].buf; bc[1].chain.next = &bc[2].chain; ngx_memcpy(&bc[1].buf, msg_buf, sizeof(*msg_buf)); bc[1].buf.last_buf = 0; bc[1].buf.last_in_chain = 0; bc[1].buf.flush = 0; bc[2].chain.buf = &bc[2].buf; bc[2].chain.next = NULL; ngx_memzero(&bc[2].buf, sizeof(ngx_buf_t)); bc[2].buf.start = chunk_end; bc[2].buf.pos = chunk_end; bc[2].buf.end = chunk_end + 2; bc[2].buf.last = bc[2].buf.end; bc[2].buf.memory = 1; bc[2].buf.last_buf = 0; bc[2].buf.last_in_chain = 1; bc[2].buf.flush = 1; ctx->prev_msg_id = fsub->sub.last_msgid; update_subscriber_last_msg_id(sub, msg); ctx->msg_id = fsub->sub.last_msgid; chunked_ensure_headers_sent(fsub); DBG("%p output msg to subscriber", sub); rc = nchan_output_filter(fsub->sub.request, &bc[0].chain); return rc; }
static ngx_int_t chunked_enqueue(subscriber_t *sub) { ngx_int_t rc; full_subscriber_t *fsub = (full_subscriber_t *)sub; DBG("%p output status to subscriber", sub); rc = longpoll_enqueue(sub); fsub->data.finalize_request = 0; chunked_ensure_headers_sent(fsub); sub->enqueued = 1; return rc; }
static ngx_int_t chunked_respond_status(subscriber_t *sub, ngx_int_t status_code, const ngx_str_t *status_line){ nchan_buf_and_chain_t bc; ngx_chain_t *chain = NULL; full_subscriber_t *fsub = (full_subscriber_t *)sub; if(chain == NULL) { bc.chain.buf=&bc.buf; bc.chain.next=NULL; ngx_memzero(&bc.buf, sizeof(ngx_buf_t)); bc.buf.last_buf = 1; bc.buf.last_in_chain = 1; bc.buf.flush = 1; bc.buf.memory = 1; chain = &bc.chain; } bc.buf.start = (u_char *)"0\r\n\r\n"; bc.buf.end = bc.buf.start + 5; bc.buf.pos = bc.buf.start; bc.buf.last = bc.buf.end; if(status_code == NGX_HTTP_NO_CONTENT || status_code == NGX_HTTP_NOT_MODIFIED) { //ignore return NGX_OK; } if(fsub->data.shook_hands == 0 && status_code >= 400 && status_code <600) { nchan_respond_status(sub->request, status_code, status_line, 1); return NGX_OK; } chunked_ensure_headers_sent(fsub); nchan_output_filter(fsub->sub.request, chain); if(status_code >=400 && status_code <599) { fsub->data.cln->handler = (ngx_http_cleanup_pt )empty_handler; fsub->sub.request->keepalive=0; fsub->data.finalize_request=1; sub->fn->dequeue(sub); } return NGX_OK; }
static ngx_int_t chunked_respond_status(subscriber_t *sub, ngx_int_t status_code, const ngx_str_t *status_line){ nchan_buf_and_chain_t bc; ngx_chain_t *chain = NULL; full_subscriber_t *fsub = (full_subscriber_t *)sub; if(chain == NULL) { bc.chain.buf=&bc.buf; bc.chain.next=NULL; ngx_memzero(&bc.buf, sizeof(ngx_buf_t)); bc.buf.last_buf = 1; bc.buf.last_in_chain = 1; bc.buf.flush = 1; bc.buf.memory = 1; chain = &bc.chain; } bc.buf.start = (u_char *)"0\r\n\r\n"; bc.buf.end = bc.buf.start + 5; bc.buf.pos = bc.buf.start; bc.buf.last = bc.buf.end; if(status_code == NGX_HTTP_NO_CONTENT || (status_code == NGX_HTTP_NOT_MODIFIED && !status_line)) { //ignore return NGX_OK; } if(fsub->data.shook_hands == 0 && status_code >= 400 && status_code < 600) { nchan_respond_status(sub->request, status_code, status_line, 1); return NGX_OK; } chunked_ensure_headers_sent(fsub); nchan_output_filter(fsub->sub.request, chain); subscriber_maybe_dequeue_after_status_response(fsub, status_code); return NGX_OK; }
static ngx_int_t chunked_respond_message(subscriber_t *sub, nchan_msg_t *msg) { full_subscriber_t *fsub = (full_subscriber_t *)sub; nchan_request_ctx_t *ctx = ngx_http_get_module_ctx(fsub->sub.request, ngx_nchan_module); chunksizebuf_t *chunksizebuf = nchan_reuse_queue_push(ctx->output_str_queue); u_char *chunk_start = &chunksizebuf->chr[0]; static u_char *chunk_end=(u_char *)"\r\n"; ngx_file_t *file_copy; nchan_buf_and_chain_t *bc = nchan_bufchain_pool_reserve(ctx->bcp, 3); ngx_chain_t *chain; ngx_buf_t *buf, *msg_buf = &msg->buf; ngx_int_t rc; if(fsub->data.timeout_ev.timer_set) { ngx_del_timer(&fsub->data.timeout_ev); ngx_add_timer(&fsub->data.timeout_ev, sub->cf->subscriber_timeout * 1000); } ctx->prev_msg_id = fsub->sub.last_msgid; update_subscriber_last_msg_id(sub, msg); ctx->msg_id = fsub->sub.last_msgid; if (ngx_buf_size(msg_buf) == 0) { //empty messages are skipped, because a zero-length chunk finalizes the request return NGX_OK; } //chunk size chain = &bc->chain; buf = chain->buf; ngx_memzero(buf, sizeof(*buf)); buf->memory = 1; buf->start = chunk_start; buf->pos = chunk_start; buf->end = ngx_snprintf(chunk_start, 15, "%xi\r\n", ngx_buf_size(msg_buf)); buf->last = buf->end; //message chain = chain->next; buf = chain->buf; *buf = *msg_buf; if(buf->file) { file_copy = nchan_bufchain_pool_reserve_file(ctx->bcp); nchan_msg_buf_open_fd_if_needed(buf, file_copy, NULL); } buf->last_buf = 0; buf->last_in_chain = 0; buf->flush = 0; //trailing newlines chain = chain->next; buf = chain->buf; ngx_memzero(buf, sizeof(*buf)); buf->start = chunk_end; buf->pos = chunk_end; buf->end = chunk_end + 2; buf->last = buf->end; buf->memory = 1; buf->last_buf = 0; buf->last_in_chain = 1; buf->flush = 1; chunked_ensure_headers_sent(fsub); DBG("%p output msg to subscriber", sub); rc = nchan_output_msg_filter(fsub->sub.request, msg, &bc->chain); return rc; }