Ejemplo n.º 1
0
static void nchan_publisher_body_handler(ngx_http_request_t *r) {
  ngx_str_t                      *channel_id;
  nchan_loc_conf_t               *cf = ngx_http_get_module_loc_conf(r, ngx_nchan_module);
  ngx_table_elt_t                *content_length_elt;
  ngx_http_complex_value_t       *authorize_request_url_ccv = cf->authorize_request_url;
  
  if((channel_id = nchan_get_channel_id(r, PUB, 1))==NULL) {
    nchan_http_finalize_request(r, r->headers_out.status ? NGX_OK : NGX_HTTP_INTERNAL_SERVER_ERROR);
    return;
  }
  
  if(!authorize_request_url_ccv) {
    nchan_publisher_body_handler_continued(r, channel_id, cf);
  }
  else {
    nchan_pub_subrequest_stuff_t   *psr_stuff;
    
    if((psr_stuff = ngx_palloc(r->pool, sizeof(*psr_stuff))) == NULL) {
      nchan_log_request_error(r, "can't allocate memory for publisher auth subrequest");
      nchan_http_finalize_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR);
      return;
    }
    
    ngx_http_post_subrequest_t    *psr = &psr_stuff->psr;
    nchan_pub_subrequest_data_t   *psrd = &psr_stuff->psr_data;
    ngx_http_request_t            *sr;
    ngx_str_t                      auth_request_url;
    
    ngx_http_complex_value(r, authorize_request_url_ccv, &auth_request_url);
    
    psr->handler = nchan_publisher_body_authorize_handler;
    psr->data = psrd;
    
    psrd->ch_id = channel_id;
    
    ngx_http_subrequest(r, &auth_request_url, NULL, &sr, psr, 0);
    
    if((sr->request_body = ngx_pcalloc(r->pool, sizeof(ngx_http_request_body_t))) == NULL) {
      nchan_log_request_error(r, "can't allocate memory for publisher auth subrequest body");
      nchan_http_finalize_request(r, r->headers_out.status ? NGX_OK : NGX_HTTP_INTERNAL_SERVER_ERROR);
      return;
    }
    if((content_length_elt = ngx_palloc(r->pool, sizeof(*content_length_elt))) == NULL) {
      nchan_log_request_error(r, "can't allocate memory for publisher auth subrequest content-length header");
      nchan_http_finalize_request(r, r->headers_out.status ? NGX_OK : NGX_HTTP_INTERNAL_SERVER_ERROR);
      return;
    }
    
    if(sr->headers_in.content_length) {
      *content_length_elt = *sr->headers_in.content_length;
      content_length_elt->value.len=1;
      content_length_elt->value.data=(u_char *)"0";
      sr->headers_in.content_length = content_length_elt;
    }
    
    sr->headers_in.content_length_n = 0;
    sr->args = r->args;
    sr->header_only = 1;
  }
}
Ejemplo n.º 2
0
ngx_int_t nchan_pubsub_handler(ngx_http_request_t *r) {
  nchan_loc_conf_t       *cf = ngx_http_get_module_loc_conf(r, nchan_module);
  ngx_str_t              *channel_id;
  subscriber_t           *sub;
  nchan_msg_id_t         *msg_id;
  ngx_int_t               rc = NGX_DONE;
  nchan_request_ctx_t    *ctx;
  ngx_str_t              *origin_header;
  
#if NCHAN_BENCHMARK
  struct timeval          tv;
  ngx_gettimeofday(&tv);
#endif
  
  if((ctx = ngx_pcalloc(r->pool, sizeof(nchan_request_ctx_t))) == NULL) {
    return NGX_HTTP_INTERNAL_SERVER_ERROR;
  }
  ngx_http_set_ctx(r, ctx, nchan_module);

#if NCHAN_BENCHMARK
  ctx->start_tv = tv;
#endif
  
  if((origin_header = nchan_get_header_value(r, NCHAN_HEADER_ORIGIN)) != NULL) {
    ctx->request_origin_header = *origin_header;
    if(!(cf->allow_origin.len == 1 && cf->allow_origin.data[0] == '*')) {
      if(!(origin_header->len == cf->allow_origin.len && ngx_strnstr(origin_header->data, (char *)cf->allow_origin.data, origin_header->len) != NULL)) {
        //CORS origin match failed! return a 403 forbidden
        goto forbidden;
      }
    }
  }
  else {
    ctx->request_origin_header.len=0;
    ctx->request_origin_header.data=NULL;
  }
  
  if((channel_id = nchan_get_channel_id(r, SUB, 1)) == NULL) {
    //just get the subscriber_channel_id for now. the publisher one is handled elsewhere
    return r->headers_out.status ? NGX_OK : NGX_HTTP_INTERNAL_SERVER_ERROR;
  }

  if(nchan_detect_websocket_request(r)) {
    //want websocket?
    if(cf->sub.websocket) {
      //we prefer to subscribe
#if FAKESHARD
      memstore_sub_debug_start();
#endif
      if((msg_id = nchan_subscriber_get_msg_id(r)) == NULL) {
        goto bad_msgid;
      }
      if((sub = websocket_subscriber_create(r, msg_id)) == NULL) {
        ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "unable to create websocket subscriber");
        return NGX_HTTP_INTERNAL_SERVER_ERROR;
      }
      sub->fn->subscribe(sub, channel_id);
#if FAKESHARD      
      memstore_sub_debug_end();
#endif
    }
    else if(cf->pub.websocket) {
      //no need to subscribe, but keep a connection open for publishing
      //not yet implemented
      nchan_create_websocket_publisher(r);
    }
    else goto forbidden;
    return NGX_DONE;
  }
  else {
    subscriber_t *(*sub_create)(ngx_http_request_t *r, nchan_msg_id_t *msg_id) = NULL;
    
    switch(r->method) {
      case NGX_HTTP_GET:
        if(cf->sub.eventsource && nchan_detect_eventsource_request(r)) {
          sub_create = eventsource_subscriber_create;
        }
        else if(cf->sub.http_chunked && nchan_detect_chunked_subscriber_request(r)) {
          sub_create = http_chunked_subscriber_create;
        }
        else if(cf->sub.http_multipart && nchan_detect_multipart_subscriber_request(r)) {
          sub_create = http_multipart_subscriber_create;
        }
        else if(cf->sub.poll) {
          sub_create = intervalpoll_subscriber_create;
        }
        else if(cf->sub.longpoll) {
          sub_create = longpoll_subscriber_create;
        }
        else if(cf->pub.http) {
          nchan_http_publisher_handler(r);
        }
        else {
          goto forbidden;
        }
        
        if(sub_create) {
#if FAKESHARD
          memstore_sub_debug_start();
#endif
          if((msg_id = nchan_subscriber_get_msg_id(r)) == NULL) {
            goto bad_msgid;
          }
          if((sub = sub_create(r, msg_id)) == NULL) {
            ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "unable to create subscriber");
            return NGX_HTTP_INTERNAL_SERVER_ERROR;
          }
          
          sub->fn->subscribe(sub, channel_id);
#if FAKESHARD
          memstore_sub_debug_end();
#endif
        }
        
        break;
      
      case NGX_HTTP_POST:
      case NGX_HTTP_PUT:
        if(cf->pub.http) {
          nchan_http_publisher_handler(r);
        }
        else goto forbidden;
        break;
      
      case NGX_HTTP_DELETE:
        if(cf->pub.http) {
          nchan_http_publisher_handler(r);
        }
        else goto forbidden;
        break;
      
      case NGX_HTTP_OPTIONS:
        if(cf->pub.http) {
          nchan_OPTIONS_respond(r, &cf->allow_origin, &NCHAN_ACCESS_CONTROL_ALLOWED_PUBLISHER_HEADERS, &NCHAN_ALLOW_GET_POST_PUT_DELETE);
        }
        else if(cf->sub.poll || cf->sub.longpoll || cf->sub.eventsource || cf->sub.websocket) {
          nchan_OPTIONS_respond(r, &cf->allow_origin, &NCHAN_ACCESS_CONTROL_ALLOWED_SUBSCRIBER_HEADERS, &NCHAN_ALLOW_GET);
        }
        else goto forbidden;
        break;
    }
  }
  
  return rc;
  
forbidden:
  nchan_respond_status(r, NGX_HTTP_FORBIDDEN, NULL, 0);
  return NGX_OK;

bad_msgid:
  nchan_respond_cstring(r, NGX_HTTP_BAD_REQUEST, &NCHAN_CONTENT_TYPE_TEXT_PLAIN, "Message ID invalid", 0);
  return NGX_OK;
  
}
Ejemplo n.º 3
0
subscriber_t *websocket_subscriber_create(ngx_http_request_t *r, nchan_msg_id_t *msg_id) {
  nchan_request_ctx_t  *ctx = ngx_http_get_module_ctx(r, ngx_nchan_module);
  
  DBG("create for req %p", r);
  full_subscriber_t  *fsub;
  if((fsub = ngx_alloc(sizeof(*fsub), ngx_cycle->log)) == NULL) {
    ERR("Unable to allocate");
    return NULL;
  }
  
  nchan_subscriber_init(&fsub->sub, &new_websocket_sub, r, msg_id);
  fsub->cln = NULL;
  fsub->ctx = ctx;
  fsub->ws_meta_subprotocol = 0;
  fsub->finalize_request = 0;
  fsub->holding = 0;
  fsub->shook_hands = 0;
  fsub->connected = 0;
  fsub->pinging = 0;
  fsub->closing = 0;
  ngx_memzero(&fsub->ping_ev, sizeof(fsub->ping_ev));
  nchan_subscriber_init_timeout_timer(&fsub->sub, &fsub->timeout_ev);
  fsub->dequeue_handler = empty_handler;
  fsub->dequeue_handler_data = NULL;
  fsub->awaiting_destruction = 0;
  
  ngx_memzero(&fsub->closing_ev, sizeof(fsub->closing_ev));
#if nginx_version >= 1008000  
  fsub->closing_ev.cancelable = 1;
#endif
  
  //what should the buffers look like?
  
  /*
  //mesage buf
  b->last_buf = 1;
  b->last_in_chain = 1;
  b->flush = 1;
  b->memory = 1;
  b->temporary = 0;
  */
  
  if(fsub->sub.cf->pub.websocket) {
    fsub->publish_channel_id = nchan_get_channel_id(r, PUB, 0);
  }
  
  fsub->upstream_stuff = NULL;
  
  websocket_init_frame(&fsub->frame);
  
  //http request sudden close cleanup
  if((fsub->cln = ngx_http_cleanup_add(r, 0)) == NULL) {
    ERR("Unable to add request cleanup for websocket subscriber");
    return NULL;
  }
  fsub->cln->data = fsub;
  fsub->cln->handler = (ngx_http_cleanup_pt )sudden_abort_handler;
  DBG("%p created for request %p", &fsub->sub, r);
  
  assert(ctx != NULL);
  ctx->sub = &fsub->sub; //gonna need this for recv
  ctx->subscriber_type = fsub->sub.name;
  
  #if NCHAN_SUBSCRIBER_LEAK_DEBUG
    subscriber_debug_add(&fsub->sub);
  #endif

  //send-frame buffer
  ctx->output_str_queue = ngx_palloc(r->pool, sizeof(*ctx->output_str_queue));
  nchan_reuse_queue_init(ctx->output_str_queue, offsetof(framebuf_t, prev), offsetof(framebuf_t, next), framebuf_alloc, NULL, r->pool);
  
  //bufchain pool
  ctx->bcp = ngx_palloc(r->pool, sizeof(nchan_bufchain_pool_t));
  nchan_bufchain_pool_init(ctx->bcp, r->pool);
  
  return &fsub->sub;
}
Ejemplo n.º 4
0
ngx_int_t nchan_pubsub_handler(ngx_http_request_t *r) {
  nchan_loc_conf_t       *cf = ngx_http_get_module_loc_conf(r, ngx_nchan_module);
  ngx_str_t              *channel_id;
  subscriber_t           *sub;
  nchan_msg_id_t         *msg_id;
  ngx_int_t               rc = NGX_DONE;
  nchan_request_ctx_t    *ctx;
  nchan_group_limits_t    group_limits;
  
#if NCHAN_BENCHMARK
  struct timeval          tv;
  ngx_gettimeofday(&tv);
#endif
  
  if(r->connection && (r->connection->read->eof || r->connection->read->pending_eof)) {
    ngx_http_finalize_request(r, NGX_HTTP_CLIENT_CLOSED_REQUEST);
    return NGX_ERROR;
  }  
  
  if((ctx = ngx_pcalloc(r->pool, sizeof(nchan_request_ctx_t))) == NULL) {
    return NGX_HTTP_INTERNAL_SERVER_ERROR;
  }
  ngx_http_set_ctx(r, ctx, ngx_nchan_module);

#if NCHAN_BENCHMARK
  ctx->start_tv = tv;
#endif
  
  //X-Accel-Redirected requests get their method mangled to GET. De-mangle it if necessary
  if(r->upstream && r->upstream->headers_in.x_accel_redirect) {
    //yep, we got x-accel-redirected. what was the original method?...
    nchan_recover_x_accel_redirected_request_method(r);
  }
  
  if(!nchan_match_origin_header(r, cf, ctx)) {
    goto forbidden;
  }
  
  if((channel_id = nchan_get_channel_id(r, SUB, 1)) == NULL) {
    //just get the subscriber_channel_id for now. the publisher one is handled elsewhere
    return r->headers_out.status ? NGX_OK : NGX_HTTP_INTERNAL_SERVER_ERROR;
  }
  
  if((msg_id = nchan_subscriber_get_msg_id(r)) == NULL) {
    goto bad_msgid;
  }
  
  if(parse_group_limits(r, cf, &group_limits) == NGX_OK) {
    // unless the group already exists, these limits may only be set after this incoming request.
    // TODO: fix this, although that will lead to even gnarlier control flow.
    cf->storage_engine->set_group_limits(nchan_get_group_name(r, cf, ctx), cf, &group_limits, NULL, NULL);
  }
  else {
    // there waas an error parsing group limit strings, and it has already been sent in the response. 
    // just quit.
    return NGX_OK;
  }
  
  if(cf->pub.websocket || cf->pub.http) {
    char *err;
    if(!nchan_parse_message_buffer_config(r, cf, &err)) {
      if(err) {
        nchan_respond_cstring(r, NGX_HTTP_FORBIDDEN, &NCHAN_CONTENT_TYPE_TEXT_PLAIN, err, 0);
        return NGX_OK;
      }
      else {
        nchan_respond_status(r, NGX_HTTP_INTERNAL_SERVER_ERROR, NULL, 0);
        return NGX_OK;
      }
    }
  }
  
  if(nchan_detect_websocket_request(r)) {
    //want websocket?
    if(cf->sub.websocket) {
      //we prefer to subscribe
#if FAKESHARD
      memstore_sub_debug_start();
#endif
      if((msg_id = nchan_subscriber_get_msg_id(r)) == NULL) {
        goto bad_msgid;
      }
      if((sub = websocket_subscriber_create(r, msg_id)) == NULL) {
        nchan_log_request_error(r, "unable to create websocket subscriber");
        return NGX_HTTP_INTERNAL_SERVER_ERROR;
      }
      sub->fn->subscribe(sub, channel_id);
#if FAKESHARD      
      memstore_sub_debug_end();
#endif
    }
    else if(cf->pub.websocket) {
      //no need to subscribe, but keep a connection open for publishing
      nchan_create_websocket_publisher(r);
    }
    else goto forbidden;
    return NGX_DONE;
  }
  else {
    subscriber_t *(*sub_create)(ngx_http_request_t *r, nchan_msg_id_t *msg_id) = NULL;
    
    switch(r->method) {
      case NGX_HTTP_GET:
        if(cf->sub.eventsource && nchan_detect_eventsource_request(r)) {
          sub_create = eventsource_subscriber_create;
        }
        else if(cf->sub.http_chunked && nchan_detect_chunked_subscriber_request(r)) {
          sub_create = http_chunked_subscriber_create;
        }
        else if(cf->sub.http_multipart && nchan_detect_multipart_subscriber_request(r)) {
          sub_create = http_multipart_subscriber_create;
        }
        else if(cf->sub.poll) {
          sub_create = intervalpoll_subscriber_create;
        }
        else if(cf->sub.http_raw_stream) {
          sub_create = http_raw_stream_subscriber_create;
        }
        else if(cf->sub.longpoll) {
          sub_create = longpoll_subscriber_create;
        }
        else if(cf->pub.http) {
          nchan_http_publisher_handler(r);
        }
        else {
          goto forbidden;
        }
        
        if(sub_create) {
#if FAKESHARD
          memstore_sub_debug_start();
#endif
          if((msg_id = nchan_subscriber_get_msg_id(r)) == NULL) {
            goto bad_msgid;
          }
          
          if((sub = sub_create(r, msg_id)) == NULL) {
            nchan_log_request_error(r, "unable to create subscriber");
            return NGX_HTTP_INTERNAL_SERVER_ERROR;
          }
          
          sub->fn->subscribe(sub, channel_id);
#if FAKESHARD
          memstore_sub_debug_end();
#endif
        }
        
        break;
      
      case NGX_HTTP_POST:
      case NGX_HTTP_PUT:
        if(cf->pub.http) {
          nchan_http_publisher_handler(r);
        }
        else goto forbidden;
        break;
      
      case NGX_HTTP_DELETE:
        if(cf->pub.http) {
          nchan_http_publisher_handler(r);
        }
        else goto forbidden;
        break;
      
      case NGX_HTTP_OPTIONS:
        if(cf->pub.http) {
          nchan_OPTIONS_respond(r, &NCHAN_ACCESS_CONTROL_ALLOWED_PUBLISHER_HEADERS, &NCHAN_ALLOW_GET_POST_PUT_DELETE);
        }
        else if(cf->sub.poll || cf->sub.longpoll || cf->sub.eventsource || cf->sub.websocket) {
          nchan_OPTIONS_respond(r, &NCHAN_ACCESS_CONTROL_ALLOWED_SUBSCRIBER_HEADERS, &NCHAN_ALLOW_GET);
        }
        else goto forbidden;
        break;
    }
  }
  ctx->request_ran_content_handler = 1;
  return rc;
  
forbidden:
  nchan_respond_status(r, NGX_HTTP_FORBIDDEN, NULL, 0);
  ctx->request_ran_content_handler = 1;
  return NGX_OK;

bad_msgid:
  nchan_respond_cstring(r, NGX_HTTP_BAD_REQUEST, &NCHAN_CONTENT_TYPE_TEXT_PLAIN, "Message ID invalid", 0);
  ctx->request_ran_content_handler = 1;
  return NGX_OK;
  
}
Ejemplo n.º 5
0
static void nchan_publisher_body_handler(ngx_http_request_t * r) {
  ngx_str_t                      *channel_id;
  nchan_loc_conf_t               *cf = ngx_http_get_module_loc_conf(r, nchan_module);
  ngx_buf_t                      *buf;
  size_t                          content_type_len;
  nchan_msg_t                    *msg;
  struct timeval                  tv;
  
  if((channel_id = nchan_get_channel_id(r, PUB, 1))==NULL) {
    ngx_http_finalize_request(r, r->headers_out.status ? NGX_OK : NGX_HTTP_INTERNAL_SERVER_ERROR);
    return;
  }
  
  switch(r->method) {
    case NGX_HTTP_GET:
      cf->storage_engine->find_channel(channel_id, (callback_pt) &channel_info_callback, (void *)r);
      break;
    
    case NGX_HTTP_PUT:
    case NGX_HTTP_POST:
      memstore_pub_debug_start();
      
      msg = ngx_pcalloc(r->pool, sizeof(*msg));
      msg->shared = 0;
      NGX_REQUEST_VAL_CHECK(msg, NULL, r, "nchan: can't allocate msg in request pool");
      //buf = ngx_create_temp_buf(r->pool, 0);
      //NGX_REQUEST_VAL_CHECK(buf, NULL, r, "nchan: can't allocate buf in request pool");
      
      //content type
      content_type_len = (r->headers_in.content_type!=NULL ? r->headers_in.content_type->value.len : 0);
      if(content_type_len > 0) {
        msg->content_type.len = content_type_len;
        msg->content_type.data = r->headers_in.content_type->value.data;
      }
      
      if(r->headers_in.content_length_n == -1 || r->headers_in.content_length_n == 0) {
        buf = ngx_create_temp_buf(r->pool, 0);
      }
      else if(r->request_body->bufs!=NULL) {
        buf = nchan_request_body_to_single_buffer(r);
      }
      else {
        ngx_log_error(NGX_LOG_ERR, (r)->connection->log, 0, "nchan: unexpected publisher message request body buffer location. please report this to the nchan developers.");
        ngx_http_finalize_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR);
        return;
      }
      
      ngx_gettimeofday(&tv);
      msg->id.time = tv.tv_sec;
      msg->id.tag[0] = 0;
      msg->id.tagactive = 0;
      msg->id.tagcount = 1;
      
      msg->buf = buf;
#if NCHAN_MSG_LEAK_DEBUG
      msg->lbl = r->uri;
#endif      
      cf->storage_engine->publish(channel_id, msg, cf, (callback_pt) &publish_callback, r);
      
      memstore_pub_debug_end();
      break;
      
    case NGX_HTTP_DELETE:
      cf->storage_engine->delete_channel(channel_id, (callback_pt) &channel_info_callback, (void *)r);
      break;
      
    default: 
      nchan_respond_status(r, NGX_HTTP_FORBIDDEN, NULL, 0);
  }
}
Ejemplo n.º 6
0
ngx_int_t nchan_pubsub_handler(ngx_http_request_t *r) {
  nchan_loc_conf_t       *cf = ngx_http_get_module_loc_conf(r, nchan_module);
  ngx_str_t              *channel_id;
  subscriber_t           *sub;
  nchan_msg_id_t          msg_id = {0}; //memzeroed for debugging
  ngx_int_t               rc = NGX_DONE;
  
  nchan_request_ctx_t    *ctx;
  if((ctx = ngx_pcalloc(r->pool, sizeof(nchan_request_ctx_t))) == NULL) {
    return NGX_HTTP_INTERNAL_SERVER_ERROR;
  }
  ngx_http_set_ctx(r, ctx, nchan_module);
  
  if((channel_id = nchan_get_channel_id(r, SUB, 1)) == NULL) {
    //just get the subscriber_channel_id for now. the publisher one is handled elsewhere
    return r->headers_out.status ? NGX_OK : NGX_HTTP_INTERNAL_SERVER_ERROR;
  }

  if(nchan_detect_websocket_handshake(r)) {
    //want websocket?
    if(cf->sub.websocket) {
      //we prefer to subscribe
      memstore_sub_debug_start();
      nchan_subscriber_get_msg_id(r, &msg_id);
      if((sub = websocket_subscriber_create(r, &msg_id)) == NULL) {
        ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "unable to create websocket subscriber");
        return NGX_HTTP_INTERNAL_SERVER_ERROR;
      }
      cf->storage_engine->subscribe(channel_id, sub, (callback_pt )&subscribe_websocket_callback, (void *)r);
      
      memstore_sub_debug_end();
    }
    else if(cf->pub.websocket) {
      //no need to subscribe, but keep a connection open for publishing
      //not yet implemented
      nchan_create_websocket_publisher(r);
    }
    else goto forbidden;
    return NGX_DONE;
  }
  else {
    switch(r->method) {
      case NGX_HTTP_GET:
        if(cf->sub.eventsource && nchan_detect_eventsource_request(r)) {
          memstore_sub_debug_start();
          
          nchan_subscriber_get_msg_id(r, &msg_id);
          if((sub = eventsource_subscriber_create(r, &msg_id)) == NULL) {
            ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "unable to create longpoll subscriber");
            return NGX_HTTP_INTERNAL_SERVER_ERROR;
          }
          cf->storage_engine->subscribe(channel_id, sub, (callback_pt )&subscribe_eventsource_callback, (void *)r);
          
          memstore_sub_debug_end();
        }
        else if(cf->sub.poll) {
          memstore_sub_debug_start();
          
          nchan_subscriber_get_msg_id(r, &msg_id);
          assert(msg_id.tagcount == 1);
          
          r->main->count++;
          cf->storage_engine->get_message(channel_id, &msg_id, (callback_pt )&subscribe_intervalpoll_callback, (void *)r);
          memstore_sub_debug_end();
        }
        else if(cf->sub.longpoll) {
          memstore_sub_debug_start();
          
          nchan_subscriber_get_msg_id(r, &msg_id);
          if((sub = longpoll_subscriber_create(r, &msg_id)) == NULL) {
            ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "unable to create longpoll subscriber");
            return NGX_HTTP_INTERNAL_SERVER_ERROR;
          }
          cf->storage_engine->subscribe(channel_id, sub, (callback_pt )&subscribe_longpoll_callback, (void *)r);
          
          memstore_sub_debug_end();
        }
        else if(cf->pub.http) {
          nchan_http_publisher_handler(r);
        }
        else goto forbidden;
        break;
      
      case NGX_HTTP_POST:
      case NGX_HTTP_PUT:
        if(cf->pub.http) {
          nchan_http_publisher_handler(r);
        }
        else goto forbidden;
        break;
      
      case NGX_HTTP_DELETE:
        if(cf->pub.http) {
          nchan_http_publisher_handler(r);
        }
        else goto forbidden;
        break;
      
      case NGX_HTTP_OPTIONS:
        if(cf->pub.http) {
          nchan_OPTIONS_respond(r, &NCHAN_ANYSTRING, &NCHAN_ACCESS_CONTROL_ALLOWED_PUBLISHER_HEADERS, &NCHAN_ALLOW_GET_POST_PUT_DELETE_OPTIONS);
        }
        else if(cf->sub.poll || cf->sub.longpoll || cf->sub.eventsource || cf->sub.websocket) {
          nchan_OPTIONS_respond(r, &NCHAN_ANYSTRING, &NCHAN_ACCESS_CONTROL_ALLOWED_SUBSCRIBER_HEADERS, &NCHAN_ALLOW_GET_OPTIONS);
        }
        else goto forbidden;
        break;
    }
  }
  
  return rc;
  
forbidden:
  nchan_respond_status(r, NGX_HTTP_FORBIDDEN, NULL, 0);
  return NGX_OK;
}
Ejemplo n.º 7
0
subscriber_t *websocket_subscriber_create(ngx_http_request_t *r, nchan_msg_id_t *msg_id) {
  ngx_buf_t            *b;
  nchan_loc_conf_t     *cf = ngx_http_get_module_loc_conf(r, nchan_module);
  DBG("create for req %p", r);
  full_subscriber_t  *fsub;
  if((fsub = ngx_alloc(sizeof(*fsub), ngx_cycle->log)) == NULL) {
    ERR("Unable to allocate");
    return NULL;
  }
  ngx_memcpy(&fsub->sub, &new_websocket_sub, sizeof(new_websocket_sub));
  fsub->request = r;
  fsub->cln = NULL;
  fsub->finalize_request = 0;
  fsub->holding = 0;
  fsub->shook_hands = 0;
  fsub->sub.cf = ngx_http_get_module_loc_conf(r, nchan_module);
  
  if(msg_id) {
    fsub->sub.last_msg_id.time = msg_id->time;
    fsub->sub.last_msg_id.tag = msg_id->tag;
  }
  
  ngx_memzero(&fsub->timeout_ev, sizeof(fsub->timeout_ev));
  fsub->timeout_handler = empty_handler;
  fsub->timeout_handler_data = NULL;
  fsub->dequeue_handler = empty_handler;
  fsub->dequeue_handler_data = NULL;
  fsub->already_enqueued = 0;
  fsub->awaiting_destruction = 0;
  fsub->reserved = 0;
  
  //initialize reusable chains and bufs
  ngx_memzero(&fsub->hdr_buf, sizeof(fsub->hdr_buf));
  ngx_memzero(&fsub->msg_buf, sizeof(fsub->msg_buf));
  //space for frame header
  fsub->hdr_buf.start = ngx_pcalloc(r->pool, WEBSOCKET_FRAME_HEADER_MAX_LENGTH);
  
  fsub->hdr_chain.buf = &fsub->hdr_buf;
  fsub->hdr_chain.next = &fsub->msg_chain;
  
  fsub->msg_chain.buf = &fsub->msg_buf;
  fsub->msg_chain.next = NULL;
  
  //what should the buffers look like?
  b = &fsub->msg_buf;
  b->last_buf = 1;
  b->last_in_chain = 1;
  b->flush = 1;
  b->memory = 1;
  b->temporary = 0;

  if(cf->pub.websocket) {
    fsub->publish_channel_id = nchan_get_channel_id(r, PUB, 0);
  }
  
  websocket_init_frame(&fsub->frame);
  
  fsub->owner = memstore_slot();
  
  //http request sudden close cleanup
  if((fsub->cln = ngx_http_cleanup_add(r, 0)) == NULL) {
    ERR("Unable to add request cleanup for websocket subscriber");
    return NULL;
  }
  fsub->cln->data = fsub;
  fsub->cln->handler = (ngx_http_cleanup_pt )sudden_abort_handler;
  DBG("%p created for request %p", &fsub->sub, r);
  
  ngx_http_set_ctx(r, fsub, nchan_module); //gonna need this for recv
  
  return &fsub->sub;
}