subscriber_t *http_multipart_subscriber_create(ngx_http_request_t *r, nchan_msg_id_t *msg_id) {
  subscriber_t         *sub = longpoll_subscriber_create(r, msg_id);
  full_subscriber_t    *fsub = (full_subscriber_t *)sub;
  multipart_privdata_t *multipart_data;
  nchan_request_ctx_t  *ctx = ngx_http_get_module_ctx(fsub->sub.request, nchan_module);
  
  if(multipart_fn == NULL) {
    multipart_fn = &multipart_fn_data;
    *multipart_fn = *sub->fn;
    multipart_fn->enqueue = multipart_enqueue;
    multipart_fn->respond_message = multipart_respond_message;
    multipart_fn->respond_status = multipart_respond_status;
  }
  
  fsub->data.shook_hands = 0;
  
  fsub->privdata = ngx_palloc(sub->request->pool, sizeof(multipart_privdata_t));
  multipart_data = (multipart_privdata_t *)fsub->privdata;
  multipart_data->boundary_end = ngx_snprintf(multipart_data->boundary, 50, "\r\n--%V", nchan_request_multipart_boundary(fsub->sub.request, ctx));
  
  //header bufs -- unique per response
  ctx->output_str_queue = ngx_palloc(r->pool, sizeof(*ctx->output_str_queue));
  nchan_reuse_queue_init(ctx->output_str_queue, offsetof(headerbuf_t, prev), offsetof(headerbuf_t, next), headerbuf_alloc, NULL, sub->request->pool);
  
  ctx->bcp = ngx_palloc(r->pool, sizeof(nchan_bufchain_pool_t));
  nchan_bufchain_pool_init(ctx->bcp, r->pool);
  
  nchan_subscriber_common_setup(sub, HTTP_MULTIPART, &sub_name, multipart_fn, 0);
  return sub;
}
Example #2
0
subscriber_t *http_chunked_subscriber_create(ngx_http_request_t *r, nchan_msg_id_t *msg_id) {
  subscriber_t         *sub;
  full_subscriber_t    *fsub;
  nchan_request_ctx_t  *ctx = ngx_http_get_module_ctx(r, nchan_module);
  sub = longpoll_subscriber_create(r, msg_id);
  
  if(chunked_fn == NULL) {
    chunked_fn = &chunked_fn_data;
    *chunked_fn = *sub->fn;
    chunked_fn->enqueue = chunked_enqueue;
    chunked_fn->respond_message = chunked_respond_message;
    chunked_fn->respond_status = chunked_respond_status;
  }
  
  fsub = (full_subscriber_t *)sub;
  
  sub->fn = chunked_fn;
  sub->name = &sub_name;
  sub->type = HTTP_CHUNKED;
  
  sub->dequeue_after_response = 0;
  
  fsub->data.shook_hands = 0;
  
  DBG("%p create subscriber", sub);
  
  if(ctx) {
    ctx->subscriber_type = sub->name;
  }
  return sub;
}
Example #3
0
subscriber_t *eventsource_subscriber_create(ngx_http_request_t *r, nchan_msg_id_t *msg_id) {
  subscriber_t         *sub;
  full_subscriber_t    *fsub;
  nchan_request_ctx_t  *ctx = ngx_http_get_module_ctx(r, nchan_module);
  sub = longpoll_subscriber_create(r, msg_id);
  
  if(eventsource_fn == NULL) {
    eventsource_fn = &eventsource_fn_data;
    *eventsource_fn = *sub->fn;
    eventsource_fn->enqueue = es_enqueue;
    eventsource_fn->respond_message= es_respond_message;
    eventsource_fn->respond_status = es_respond_status;
  }
  
  fsub = (full_subscriber_t *)sub;
  
  sub->fn = eventsource_fn;
  sub->name = &sub_name;
  sub->type = EVENTSOURCE;
  
  sub->dequeue_after_response = 0;
  
  fsub->data.shook_hands = 0;
  
  DBG("%p create subscriber", sub);
  
  if(ctx) {
    ctx->subscriber_type = sub->name;
  }
  return sub;
}
Example #4
0
subscriber_t *http_chunked_subscriber_create(ngx_http_request_t *r, nchan_msg_id_t *msg_id) {
  subscriber_t         *sub = longpoll_subscriber_create(r, msg_id);
  
  if(chunked_fn == NULL) {
    chunked_fn = &chunked_fn_data;
    *chunked_fn = *sub->fn;
    chunked_fn->enqueue = chunked_enqueue;
    chunked_fn->respond_message = chunked_respond_message;
    chunked_fn->respond_status = chunked_respond_status;
  }
  
  ((full_subscriber_t *)sub)->data.shook_hands = 0;
  
  nchan_subscriber_common_setup(sub, HTTP_CHUNKED, &sub_name, chunked_fn, 0);
  return sub;
}
Example #5
0
subscriber_t *http_raw_stream_subscriber_create(ngx_http_request_t *r, nchan_msg_id_t *msg_id) {
  subscriber_t         *sub = longpoll_subscriber_create(r, msg_id);
  full_subscriber_t    *fsub = (full_subscriber_t *)sub;
  nchan_request_ctx_t  *ctx = ngx_http_get_module_ctx(fsub->sub.request, ngx_nchan_module);
  
  if(rawstream_fn == NULL) {
    rawstream_fn = &rawstream_fn_data;
    *rawstream_fn = *sub->fn;
    rawstream_fn->enqueue = rawstream_enqueue;
    rawstream_fn->respond_message = rawstream_respond_message;
    rawstream_fn->respond_status = rawstream_respond_status;
  }
  
  fsub->data.shook_hands = 0;
  r->keepalive=0;
  
  ctx->bcp = ngx_palloc(r->pool, sizeof(nchan_bufchain_pool_t));
  nchan_bufchain_pool_init(ctx->bcp, r->pool);
  
  nchan_subscriber_common_setup(sub, HTTP_RAW_STREAM, &sub_name, rawstream_fn, 0);
  return sub;
}
Example #6
0
subscriber_t *http_chunked_subscriber_create(ngx_http_request_t *r, nchan_msg_id_t *msg_id) {
  subscriber_t         *sub = longpoll_subscriber_create(r, msg_id);
  full_subscriber_t    *fsub = (full_subscriber_t *)sub;
  nchan_request_ctx_t  *ctx = ngx_http_get_module_ctx(sub->request, ngx_nchan_module);
  if(chunked_fn == NULL) {
    chunked_fn = &chunked_fn_data;
    *chunked_fn = *sub->fn;
    chunked_fn->enqueue = chunked_enqueue;
    chunked_fn->respond_message = chunked_respond_message;
    chunked_fn->respond_status = chunked_respond_status;
  }
  
  fsub->data.shook_hands = 0;
  
  ctx->output_str_queue = ngx_palloc(r->pool, sizeof(*ctx->output_str_queue));
  nchan_reuse_queue_init(ctx->output_str_queue, offsetof(chunksizebuf_t, prev), offsetof(chunksizebuf_t, next), chunksizebuf_alloc, NULL, r->pool);
  
  ctx->bcp = ngx_palloc(r->pool, sizeof(nchan_bufchain_pool_t));
  nchan_bufchain_pool_init(ctx->bcp, r->pool);
  
  nchan_subscriber_common_setup(sub, HTTP_CHUNKED, &sub_name, chunked_fn, 1, 0);
  return sub;
}
Example #7
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;
}