Exemplo n.º 1
0
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;
}
Exemplo n.º 2
0
static ngx_int_t longpoll_respond_message(subscriber_t *self, nchan_msg_t *msg) {
  full_subscriber_t  *fsub = (full_subscriber_t  *)self;
  ngx_int_t                  rc;
  char                      *err = NULL;
  ngx_http_request_t        *r = fsub->sub.request;
  nchan_request_ctx_t       *ctx = ngx_http_get_module_ctx(r, nchan_module);
  nchan_loc_conf_t          *cf = fsub->sub.cf;
  
  DBG("%p respond req %p msg %p", self, r, msg);
  
  ctx->prev_msg_id = self->last_msgid;
  update_subscriber_last_msg_id(self, msg);
  ctx->msg_id = self->last_msgid;
  
  //disable abort handler
  fsub->data.cln->handler = empty_handler;

  //verify_unique_response(&fsub->data.request->uri, &self->last_msgid, msg, self);
  
  if(!cf->longpoll_multimsg) {
    assert(fsub->data.already_responded != 1);
    fsub->data.already_responded = 1;
    if(ctx->request_origin_header.len > 0) {
      nchan_add_response_header(r, &NCHAN_HEADER_ALLOW_ORIGIN, &cf->allow_origin);
    }
    if((rc = nchan_respond_msg(r, msg, &self->last_msgid, 0, &err)) != NGX_OK) {
      return abort_response(self, err);
    }
  }
  else {
    if((rc = longpoll_multimsg_add(fsub, msg, &err)) != NGX_OK) {
      return abort_response(self, err);
    }
  }
  dequeue_maybe(self);
  return rc;
}
Exemplo n.º 3
0
static ngx_int_t longpoll_respond_message(subscriber_t *self, nchan_msg_t *msg) {
  full_subscriber_t  *fsub = (full_subscriber_t  *)self;
  ngx_int_t                  rc;
  char                      *err = NULL;
  ngx_http_request_t        *r = fsub->sub.request;
  nchan_request_ctx_t       *ctx = ngx_http_get_module_ctx(r, ngx_nchan_module);
  nchan_loc_conf_t          *cf = fsub->sub.cf;
  
  DBG("%p respond req %p msg %p", self, r, msg);
  
  ctx->prev_msg_id = self->last_msgid;
  update_subscriber_last_msg_id(self, msg);
  ctx->msg_id = self->last_msgid;

  //verify_unique_response(&fsub->data.request->uri, &self->last_msgid, msg, self);
  if(fsub->data.timeout_ev.timer_set) {
    ngx_del_timer(&fsub->data.timeout_ev);
  }
  if(!cf->longpoll_multimsg) {
    //disable abort handler
    fsub->data.cln->handler = empty_handler;
    
    assert(fsub->data.already_responded != 1);
    fsub->data.already_responded = 1;
    if((rc = nchan_respond_msg(r, msg, &self->last_msgid, 0, &err)) != NGX_OK) {
      return abort_response(self, err);
    }
  }
  else {
    if((rc = longpoll_multipart_add(fsub, msg, &err)) != NGX_OK) {
      return abort_response(self, err);
    }
  }
  dequeue_maybe(self);
  return rc;
}
Exemplo n.º 4
0
static ngx_int_t multipart_respond_message(subscriber_t *sub,  nchan_msg_t *msg) {
  
  full_subscriber_t      *fsub = (full_subscriber_t  *)sub;
  ngx_buf_t              *buf, *msg_buf = msg->buf, *msgid_buf;
  ngx_int_t               rc;
  nchan_loc_conf_t       *cf = ngx_http_get_module_loc_conf(fsub->sub.request, nchan_module);
  nchan_request_ctx_t    *ctx = ngx_http_get_module_ctx(fsub->sub.request, nchan_module);
  ngx_int_t               n;
  nchan_buf_and_chain_t  *bc;
  ngx_chain_t            *chain;
  ngx_file_t             *file_copy;
  multipart_privdata_t   *mpd = (multipart_privdata_t *)fsub->privdata;
  
  headerbuf_t            *headerbuf = nchan_reuse_queue_push(ctx->output_str_queue);
  u_char                 *cur = headerbuf->charbuf;
  
  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);
  }
  
  //generate the headers
  if(!cf->msg_in_etag_only) {
    //msgtime
    cur = ngx_cpymem(cur, "\r\nLast-Modified: ", sizeof("\r\nLast-Modified: ") - 1);
    cur = ngx_http_time(cur, msg->id.time);
    *cur++ = CR; *cur++ = LF;
    //msgtag
    cur = ngx_cpymem(cur, "Etag: ", sizeof("Etag: ") - 1);
    cur += msgtag_to_strptr(&msg->id, (char *)cur);
    *cur++ = CR; *cur++ = LF;
  }
  else {
    ngx_str_t   *tmp_etag = msgid_to_str(&msg->id);
    cur = ngx_snprintf(cur, 58 + 10*NCHAN_FIXED_MULTITAG_MAX, "\r\nEtag: %V\r\n", tmp_etag);
  }
  
  n=4;
  if(msg->content_type.len == 0) {
    //don't need content_type buf'n'chain
    n--;
  }
  if(ngx_buf_size(msg_buf) == 0) {
    //don't need msgbuf
    n --;
  }
  if((bc = nchan_bufchain_pool_reserve(ctx->bcp, n)) == NULL) {
    ERR("cant allocate buf-and-chains for multipart/mixed client output");
    return NGX_ERROR;
  }
  
  chain = &bc->chain;
  msgid_buf = chain->buf;
  
  //message id
  ngx_memzero(chain->buf, sizeof(ngx_buf_t));
  chain->buf->memory = 1;
  chain->buf->start = headerbuf->charbuf;
  chain->buf->pos = headerbuf->charbuf;
  
  //content_type maybe
  if(msg->content_type.len > 0) {
    chain = chain->next;
    buf = chain->buf;
    
    msgid_buf->last = cur;
    msgid_buf->end = cur;
    
    ngx_memzero(buf, sizeof(ngx_buf_t));
    buf->memory = 1;
    buf->start = cur;
    buf->pos = cur;
    buf->last = ngx_snprintf(cur, 255, "Content-Type: %V\r\n\r\n", &msg->content_type);
    buf->end = buf->last;
  }
  else {
    *cur++ = CR; *cur++ = LF;
    msgid_buf->last = cur;
    msgid_buf->end = cur;
  }
  
  chain = chain->next;
  buf = chain->buf;
  //msgbuf
  if(ngx_buf_size(msg_buf) > 0) {
    ngx_memcpy(buf, msg_buf, sizeof(*msg_buf));
    if(msg_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;
  }
  
  chain = chain->next;
  buf = chain->buf;
  ngx_memzero(buf, sizeof(ngx_buf_t));
  buf->start = &mpd->boundary[0];
  buf->pos = buf->start;
  buf->end = mpd->boundary_end;
  buf->last = buf->end;
  buf->memory = 1;
  buf->last_buf = 0;
  buf->last_in_chain = 1;
  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;
  
  multipart_ensure_headers_sent(fsub);
  
  DBG("%p output msg to subscriber", sub);
  
  rc = nchan_output_msg_filter(fsub->sub.request, msg, &bc->chain);
  
  return rc;
}
Exemplo n.º 5
0
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;
}
Exemplo n.º 6
0
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;
}