ngx_int_t nchan_msg_buf_open_fd_if_needed(ngx_buf_t *buf, ngx_file_t *file, ngx_http_request_t *r) { if(buf->in_file) { //open file fd if necessary if(!file) { if(r) { if((file = ngx_pcalloc(r->pool, sizeof(*file))) == NULL) { ERR("couldn't allocate memory for file struct while responding with msg"); return NGX_ERROR; } } else { //no file given, can't allocate from NULL pool return NGX_ERROR; } } ngx_memcpy(file, buf->file, sizeof(*file)); if(file->fd == NGX_INVALID_FILE) { file->fd = nchan_fdcache_get(&file->name); if(file->fd == NGX_INVALID_FILE) { ERR("can't create output chain, file in buffer won't open"); return NGX_ERROR; } } buf->file = file; } return NGX_OK; }
static ngx_int_t es_respond_message(subscriber_t *sub, nchan_msg_t *msg) { static ngx_str_t terminal_newlines=ngx_string("\n\n"); full_subscriber_t *fsub = (full_subscriber_t *)sub; u_char *cur = NULL, *last = NULL; ngx_buf_t *msg_buf = msg->buf; ngx_buf_t databuf; ngx_pool_t *pool; nchan_buf_and_chain_t *bc; size_t len; ngx_chain_t *first_link = NULL, *last_link = NULL; ngx_file_t *msg_file; ngx_int_t rc; nchan_request_ctx_t *ctx = ngx_http_get_module_ctx(fsub->sub.request, nchan_module); ctx->prev_msg_id = fsub->sub.last_msgid; update_subscriber_last_msg_id(sub, msg); ctx->msg_id = fsub->sub.last_msgid; es_ensure_headers_sent(fsub); DBG("%p output msg to subscriber", sub); pool = ngx_create_pool(NGX_DEFAULT_LINEBREAK_POOL_SIZE, ngx_cycle->log); assert(pool); ngx_memcpy(&databuf, msg_buf, sizeof(*msg_buf)); databuf.last_buf = 0; if(!databuf.in_file) { cur = msg_buf->start; last = msg_buf->end; do { databuf.start = cur; databuf.pos = cur; databuf.end = last; databuf.last = last; cur = ngx_strlchr(cur, last, '\n'); if(cur == NULL) { //sweet, no newlines! //let's get out of this hellish loop databuf.end = last; databuf.last = last; cur = last + 1; } else { cur++; //include the newline databuf.end = cur; databuf.last = cur; } create_dataline_bufchain(pool, &first_link, &last_link, &databuf); } while(cur <= last); } else { //great, we've gotta scan this whole damn file for line breaks. //EventStream really isn't designed for large chunks of data off_t fcur, flast; ngx_fd_t fd; int chr_int; FILE *stream; msg_file = ngx_palloc(pool, sizeof(*msg_file)); databuf.file = msg_file; ngx_memcpy(msg_file, msg_buf->file, sizeof(*msg_file)); if(msg_file->fd == NGX_INVALID_FILE) { msg_file->fd = nchan_fdcache_get(&msg_file->name); } fd = msg_file->fd; stream = fdopen(dup(fd), "r"); fcur = databuf.file_pos; flast = databuf.file_last; fseek(stream, fcur, SEEK_SET); do { databuf.file_pos = fcur; databuf.file_last = flast; //getc that shit for(;;) { chr_int = getc(stream); if(chr_int == EOF) { break; } else if(chr_int == (int )'\n') { fcur++; break; } fcur++; } databuf.file_last = fcur; create_dataline_bufchain(pool, &first_link, &last_link, &databuf); } while(fcur < flast); fclose(stream); } //now 2 newlines at the end if(last_link) { bc = ngx_palloc(pool, sizeof(*bc)); last_link->next=&bc->chain; ngx_init_set_membuf(&bc->buf, terminal_newlines.data, terminal_newlines.data + terminal_newlines.len); bc->buf.flush = 1; bc->buf.last_buf = 0; bc->chain.next = NULL; bc->chain.buf = &bc->buf; last_link = &bc->chain; } //okay, this crazy data chain is finished. now how about the mesage tag? len = 10 + 2*NGX_INT_T_LEN; bc = ngx_palloc(pool, sizeof(*bc) + len); ngx_memzero(&bc->buf, sizeof(bc->buf)); cur = (u_char *)&bc[1]; ngx_init_set_membuf(&bc->buf, cur, ngx_snprintf(cur, len, "id: %V\n", msgid_to_str(&sub->last_msgid))); bc->chain.buf = &bc->buf; bc->chain.next = first_link; first_link=&bc->chain; rc = nchan_output_filter(fsub->sub.request, first_link); ngx_destroy_pool(pool); return rc; }