/**
 * handles a client request
 */
static int
write_request(stream_t *s, request_rec *r,
	      config_t *config, cluster_t *cluster, int *keepalive,
              int session_index, int backup_index,
              char *ip, char *session_id)
{
  int len;
  int code;
  int write_length;
  time_t new_time;
  time_t start_time = r->request_time;

  hmux_start_channel(s, 1);
  write_env(s, r, session_id);
  write_headers(s, r);
  write_added_headers(s, r);

  /* read post data */
  if (ap_should_client_block(r)) {
    char buf[BUF_LENGTH];
    int ack_size = s->cluster_srun->srun->send_buffer_size;
    int send_length = 0;

    while ((len = ap_get_client_block(r, buf, BUF_LENGTH)) > 0) {
      /* ap_reset_timeout(r); */
      cse_write_packet(s, HMUX_DATA, buf, len);

      send_length += len;
      
      if (ack_size <= send_length) {
	send_length = 0;
	cse_write_byte(s, HMUX_YIELD);
        code = send_data(s, r, HMUX_ACK, keepalive);
        if (code < 0 || code == HMUX_QUIT || code == HMUX_EXIT)
          break;
      }
    }
  }

  cse_write_byte(s, HMUX_QUIT);

  code = send_data(s, r, HMUX_QUIT, keepalive);

  if (code >= 0 || s->sent_data)
    return code;
  
  write_length = s->write_length; 
  if (cse_open_connection(s, cluster, session_index, backup_index,
                          r->request_time, r->pool)) {
    s->write_length = write_length;
    LOG(("retry connection %d\n", s->socket));
    
    return send_data(s, r, HMUX_QUIT, keepalive);
  }
  else {
    return HTTP_SERVICE_UNAVAILABLE;
  }
}
/**
 * Handle a request.
 */
static int
caucho_request(request_rec *r, config_t *config, resin_host_t *host,
	       unsigned int now)
{
  stream_t s;
  int retval;
  int code = -1;
  int session_index;
  int backup_index = 0;
  char *ip;
  srun_t *srun;

  if ((retval = ap_setup_client_block(r, REQUEST_CHUNKED_DECHUNK)))
    return retval;

  session_index = get_session_index(config, r, &backup_index);
  ip = r->connection->REMOTE_IP;

  if (host) {
  }
  else if (config->manual_host) {
    host = config->manual_host;
  }
  else {
    host = cse_match_host(config,
			  ap_get_server_name(r),
			  ap_get_server_port(r),
			  now);
  }
    
  LOG(("%s:%d:caucho_request(): session index: %d\n",
       __FILE__, __LINE__, session_index));
  
  if (! host) {
    ERR(("%s:%d:caucho_request(): no host: %p\n",
	 __FILE__, __LINE__, host));
    
    return HTTP_SERVICE_UNAVAILABLE;
  }
  else if (! cse_open_connection(&s, &host->cluster,
				 session_index, backup_index,
				 now, r->pool)) {
    ERR(("%s:%d:caucho_request(): no connection: cluster(%p)\n",
	 __FILE__, __LINE__, &host->cluster));
    
    return HTTP_SERVICE_UNAVAILABLE;
  }

  srun = s.cluster_srun->srun;

  apr_thread_mutex_lock(srun->lock);
  srun->active_sockets++;
  apr_thread_mutex_unlock(srun->lock);
  
  code = write_request(&s, r, config, session_index, backup_index);

  apr_thread_mutex_lock(srun->lock);
  srun->active_sockets--;
  apr_thread_mutex_unlock(srun->lock);
  
  /* on failure, do not failover but simply fail */
  if (code == HMUX_QUIT)
    cse_free_idle(&s, now);
  else
    cse_close(&s, "no reuse");

  if (code != HMUX_QUIT && code != HMUX_EXIT) {
    ERR(("%s:%d:caucho_request(): protocol failure code:%d\n",
	 __FILE__, __LINE__, code));

    return HTTP_SERVICE_UNAVAILABLE;
  }
  else if (r->status == HTTP_SERVICE_UNAVAILABLE) {
    cse_close(&s, "close from 503");
    cse_srun_unavail(srun, now);

    return HTTP_SERVICE_UNAVAILABLE;
  }
  else {
    /*
     * See pages like jms/index.xtp
    int status = r->status;
    r->status = HTTP_OK;

    return status;
    */
    return OK;
  }
}
/**
 * Handle a request.
 */
static int
caucho_request(request_rec *r)
{
  config_t *config = cse_get_module_config(r);
  resin_host_t *host = 0;
  stream_t s;
  int retval;
  int keepalive = 0;
  int reuse;
  int session_index;
  int backup_index;
  char *ip;
  time_t now = r->request_time;
  char *session_id = 0;

  if (! config)
    return HTTP_SERVICE_UNAVAILABLE;
  
  if ((retval = ap_setup_client_block(r, REQUEST_CHUNKED_DECHUNK)))
    return retval;

  /* ap_soft_timeout("servlet request", r); */
  
  if (r->request_config && ! *config->alt_session_url_prefix &&
      ((session_id = ap_get_module_config(r->request_config, &caucho_module)) ||
       r->prev &&
       (session_id = ap_get_module_config(r->prev->request_config, &caucho_module)))) {
    /* *session_id = *config->session_url_prefix; */
  }

  session_index = get_session_index(config, r, &backup_index);
  ip = r->connection->remote_ip;
  
  if (host) {
  }
  else if (config->manual_host)
    host = config->manual_host;
  else {
    host = cse_match_host(config,
			  ap_get_server_name(r),
			  ap_get_server_port(r),
			  now);
  }

  if (! host ||
      ! cse_open_connection(&s, &host->cluster, session_index, backup_index,
                            now, r->pool)) {
    return HTTP_SERVICE_UNAVAILABLE;
  }

  reuse = write_request(&s, r, config, &host->cluster, &keepalive,
                        session_index, backup_index,
                        ip, session_id);
  /*
  ap_kill_timeout(r);
  */
  ap_rflush(r);

  if (reuse == HMUX_QUIT)
    cse_recycle(&s, now);
  else
    cse_close(&s, "no reuse");

  if (reuse == HTTP_SERVICE_UNAVAILABLE)
    return reuse;
  else
    return OK;
}