static ngx_int_t ngx_http_push_store_delete_channel(ngx_http_push_channel_t *channel, ngx_http_request_t *r) {
  ngx_http_push_msg_t            *msg, *sentinel;
  ngx_shmtx_lock(&ngx_http_push_shpool->mutex);
  sentinel = channel->message_queue; 
  msg = sentinel;
        
  while((msg=(ngx_http_push_msg_t *)ngx_queue_next(&msg->queue))!=sentinel) {
    //force-delete all the messages
    ngx_http_push_force_delete_message_locked(NULL, msg, ngx_http_push_shpool);
  }
  channel->messages=0;
  
  //410 gone
  ngx_shmtx_unlock(&ngx_http_push_shpool->mutex);
  
  ngx_http_push_store_publish(channel, NULL, NGX_HTTP_GONE, &NGX_HTTP_PUSH_HTTP_STATUS_410, r->connection->log);
  
  ngx_shmtx_lock(&ngx_http_push_shpool->mutex);
  ngx_http_push_delete_channel_locked(channel);
  ngx_shmtx_unlock(&ngx_http_push_shpool->mutex);
  return NGX_OK;
}
static void ngx_http_push_publisher_body_handler(ngx_http_request_t * r) { 
	ngx_str_t                      *id;
	ngx_http_push_loc_conf_t       *cf = ngx_http_get_module_loc_conf(r, ngx_http_push_module);
	ngx_slab_pool_t                *shpool = (ngx_slab_pool_t *) ngx_http_push_shm_zone->shm.addr;
	ngx_buf_t                      *buf = NULL, *buf_copy;
	ngx_http_push_channel_t        *channel;
	ngx_uint_t                      method = r->method;
	
	time_t                          last_seen = 0;
	ngx_uint_t                      subscribers = 0;
	ngx_uint_t                      messages = 0;
	
	if((id = ngx_http_push_get_channel_id(r, cf))==NULL) {
		ngx_http_finalize_request(r, r->headers_out.status ? NGX_OK : NGX_HTTP_INTERNAL_SERVER_ERROR);
		return;
	}
	
	ngx_shmtx_lock(&shpool->mutex);
	//POST requests will need a channel created if it doesn't yet exist.
	if(method==NGX_HTTP_POST || method==NGX_HTTP_PUT) {
		channel = ngx_http_push_get_channel(id, &((ngx_http_push_shm_data_t *) ngx_http_push_shm_zone->data)->tree, shpool, r->connection->log);
		NGX_HTTP_PUSH_PUBLISHER_CHECK_LOCKED(channel, NULL, r, "push module: unable to allocate memory for new channel", shpool);
	}
	//no other request method needs that.
	else{
		//just find the channel. if it's not there, NULL.
		channel = ngx_http_push_find_channel(id, &((ngx_http_push_shm_data_t *) ngx_http_push_shm_zone->data)->tree, shpool, r->connection->log);
	}
	
	if(channel!=NULL) {
		subscribers = channel->subscribers;
		last_seen = channel->last_seen;
		messages  = channel->messages;
	}
	else {
		//404!
		ngx_shmtx_unlock(&shpool->mutex);
		r->headers_out.status=NGX_HTTP_NOT_FOUND;
		
		//just the headers, please. we don't care to describe the situation or
		//respond with an html page
		r->headers_out.content_length_n=0;
		r->header_only = 1;
		
		ngx_http_finalize_request(r, ngx_http_send_header(r));
		return;
	}
	ngx_shmtx_unlock(&shpool->mutex);
	
	switch(method) {
		ngx_http_push_msg_t        *msg, *previous_msg;
		size_t                      content_type_len;
		ngx_uint_t                  received;
		ngx_http_push_msg_t        *sentinel;
		
		case NGX_HTTP_POST:
			//first off, we'll want to extract the body buffer
		
			//note: this works mostly because of r->request_body_in_single_buf = 1; 
			//which, i suppose, makes this module a little slower than it could be.
			//this block is a little hacky. might be a thorn for forward-compatibility.
			if(r->headers_in.content_length_n == -1 || r->headers_in.content_length_n == 0) {
				buf = ngx_create_temp_buf(r->pool, 0);
				//this buffer will get copied to shared memory in a few lines, 
				//so it does't matter what pool we make it in.
			}
			else if(r->request_body->temp_file==NULL) { //everything in the first buffer, please
				//no file
				buf=r->request_body->bufs->buf;
			}
			else { //(r->request_body->bufs->next!=NULL)
				//there's probably a file
				buf=r->request_body->bufs->next->buf;
			}
			
			NGX_HTTP_PUSH_PUBLISHER_CHECK(buf, NULL, r, "push module: can't find or allocate publisher request body buffer");
					
			content_type_len = (r->headers_in.content_type!=NULL ? r->headers_in.content_type->value.len : 0);
			
			ngx_shmtx_lock(&shpool->mutex);
			
			//create a buffer copy in shared mem
			msg = ngx_slab_alloc_locked(shpool, sizeof(*msg) + content_type_len);
			NGX_HTTP_PUSH_PUBLISHER_CHECK_LOCKED(msg, NULL, r, "push module: unable to allocate message in shared memory", shpool);
			previous_msg=ngx_http_push_get_latest_message_locked(channel); //need this for entity-tags generation
			NGX_HTTP_PUSH_CREATE_BUF_COPY(buf, buf_copy, shpool, ngx_slab_alloc_locked);
			NGX_HTTP_PUSH_PUBLISHER_CHECK_LOCKED(buf_copy, NULL, r, "push module: unable to allocate buffer in shared memory", shpool);
			msg->buf=buf_copy;
			
			if(cf->store_messages) {
				ngx_queue_insert_tail(&channel->message_queue->queue, &msg->queue);
				channel->messages++;
			}
			
			//Stamp the new message with entity tags
			msg->message_time=ngx_time(); //ESSENTIAL TODO: make sure this ends up producing GMT time
			msg->message_tag=(previous_msg!=NULL && msg->message_time == previous_msg->message_time) ? (previous_msg->message_tag + 1) : 0;		
			
			//store the content-type
			if(content_type_len>0) {
				msg->content_type.len=r->headers_in.content_type->value.len;
				msg->content_type.data=(u_char *) (msg+1); //we had reserved a contiguous chunk, myes?
				ngx_memcpy(msg->content_type.data, r->headers_in.content_type->value.data, msg->content_type.len);
			}
			else {
				msg->content_type.len=0;
				msg->content_type.data=NULL;
			}
			
			//set message expiration time
			time_t                  message_timeout = cf->buffer_timeout;
			msg->expires = (message_timeout==0 ? 0 : (ngx_time() + message_timeout));
			
			//FMI (For My Information): shm is still locked.
			switch(ngx_http_push_broadcast_message_locked(channel, msg, r->connection->log, shpool)) {
				
				case NGX_HTTP_PUSH_MESSAGE_QUEUED:
					//message was queued successfully, but there were no 
					//subscribers to receive it.
					r->headers_out.status = NGX_HTTP_ACCEPTED;
					r->headers_out.status_line.len =sizeof("202 Accepted")- 1;
					r->headers_out.status_line.data=(u_char *) "202 Accepted";
					break;
					
				case NGX_HTTP_PUSH_MESSAGE_RECEIVED:
					//message was queued successfully, and it was already sent
					//to at least one subscriber
					r->headers_out.status = NGX_HTTP_CREATED;
					r->headers_out.status_line.len =sizeof("201 Created")- 1;
					r->headers_out.status_line.data=(u_char *) "201 Created";
					
					//update the number of times the message was received.
					//in the interest of premature optimization, I assume all
					//current subscribers have received the message successfully.
					received = msg->received;					
					//nasty overflow check
					msg->received = (received + subscribers < received) ? NGX_MAX_UINT32_VALUE : (received + subscribers);
					break;
					
				case NGX_ERROR:
					//WTF?
					ngx_shmtx_unlock(&shpool->mutex);
					ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "push module: error broadcasting message to workers");
					ngx_http_finalize_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR);
					return;
					
				default: 
					//for debugging, mostly. I don't expect this branch to be
					//hit during regular operation
					ngx_shmtx_unlock(&shpool->mutex);
					ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "push module: TOTALLY UNEXPECTED error broadcasting message to workers");
					ngx_http_finalize_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR);
					return;
			}
			//shm is still locked I hope.
			
			if(buf->file!=NULL) {
				//future subscribers won't be able to use this file descriptor --
				//it will be closed once the publisher request is finalized. 
				//(That's about to happen a handful of lines below.)
				msg->buf->file->fd=NGX_INVALID_FILE;
			}
			
			//now see if the queue is too big
			if(channel->messages > (ngx_uint_t) cf->max_messages) {
				//exceeeds max queue size. force-delete oldest message
				ngx_http_push_force_delete_message_locked(channel, ngx_http_push_get_oldest_message_locked(channel), shpool);
			}
			if(channel->messages > (ngx_uint_t) cf->min_messages) {
				//exceeeds min queue size. maybe delete the oldest message
				ngx_http_push_msg_t    *oldest_msg = ngx_http_push_get_oldest_message_locked(channel);
				NGX_HTTP_PUSH_PUBLISHER_CHECK_LOCKED(oldest_msg, NULL, r, "push module: oldest message not found", shpool);
				if(oldest_msg->received >= (ngx_uint_t) cf->min_message_recipients) {
					//received more than min_message_recipients times
					ngx_http_push_delete_message_locked(channel, oldest_msg, shpool);
				}
			}
			messages = channel->messages;
			
			ngx_shmtx_unlock(&shpool->mutex);
			ngx_http_finalize_request(r, ngx_http_push_channel_info(r, messages, subscribers, last_seen));
			return;
			
		case NGX_HTTP_PUT:
		case NGX_HTTP_GET: 
			r->headers_out.status = NGX_HTTP_OK;
			ngx_http_finalize_request(r, ngx_http_push_channel_info(r, messages, subscribers, last_seen));
			return;
			
		case NGX_HTTP_DELETE:
			ngx_shmtx_lock(&shpool->mutex);
			sentinel = channel->message_queue; 
			msg = sentinel;
						
			while((msg=(ngx_http_push_msg_t *)ngx_queue_next(&msg->queue))!=sentinel) {
				//force-delete all the messages
				ngx_http_push_force_delete_message_locked(NULL, msg, shpool);
			}
			channel->messages=0;
			
			//410 gone
			NGX_HTTP_PUSH_PUBLISHER_CHECK_LOCKED(ngx_http_push_broadcast_status_locked(channel, NGX_HTTP_GONE, &NGX_HTTP_PUSH_HTTP_STATUS_410, r->connection->log, shpool), NGX_ERROR, r, "push module: unable to send current subscribers a 410 Gone response", shpool);
			ngx_http_push_delete_node_locked(&((ngx_http_push_shm_data_t *) ngx_http_push_shm_zone->data)->tree, (ngx_rbtree_node_t *) channel, shpool);
			ngx_shmtx_unlock(&shpool->mutex);
			//done.
			r->headers_out.status=NGX_HTTP_OK;
			ngx_http_finalize_request(r, ngx_http_push_channel_info(r, messages, subscribers, last_seen));
			return;
			
		default: 
			//some other weird request method
			ngx_http_push_add_response_header(r, &NGX_HTTP_PUSH_HEADER_ALLOW, &NGX_HTTP_PUSH_ALLOW_GET_POST_PUT_DELETE);
			ngx_http_finalize_request(r, NGX_HTTP_NOT_ALLOWED);
			return;
	}
}