/**
 * Copy data from the JVM to the browser.
 */
static int
send_data(stream_t *s, request_rec *r)
{
  int code = -1;
  char buf[8193];
  char key[8193];
  char value[8193];
  int i;
  int channel;
    
  if (cse_fill_buffer(s) < 0) {
    return -1;
  }
    
  while (1) {
    int len;

    code = cse_read_byte(s);

    LOG(("%s:%d:send_data(): r-code %c\n", __FILE__, __LINE__, code));
    
    switch (code) {
    case HMUX_CHANNEL:
      channel = hmux_read_len(s);
      LOG(("%s:%d:send_data(): r-channel %d\n", __FILE__, __LINE__, channel));
      break;
      
    case HMUX_ACK:
      channel = hmux_read_len(s);
      LOG(("%s:%d:send_data(): r-ack %d\n", __FILE__, __LINE__, channel));
      return code;
      
    case HMUX_STATUS:
      len = hmux_read_len(s);
      cse_read_limit(s, buf, sizeof(buf), len);

      for (i = 0; buf[i] && buf[i] != ' '; i++) {
      }
      i++;
      r->status = atoi(buf);
      r->status_line = apr_pstrdup(r->pool, buf);
      break;

    case HMUX_HEADER:
      len = hmux_read_len(s);
      cse_read_limit(s, key, sizeof(key), len);
      cse_read_string(s, value, sizeof(value));
      
      if (! strcasecmp(key, "content-type")) {
	r->content_type = apr_pstrdup(r->pool, value);
	apr_table_set(r->headers_out, key, value);
      }
      else
	apr_table_add(r->headers_out, key, value);
      break;
      
    case HMUX_META_HEADER:
      len = hmux_read_len(s);
      cse_read_limit(s, key, sizeof(key), len);
      cse_read_string(s, value, sizeof(value));
      break;

    case HMUX_DATA:
      len = hmux_read_len(s);
      if (cse_write_response(s, len, r) < 0)
	return HMUX_EXIT;
      break;

    case HMUX_FLUSH:
      len = hmux_read_len(s);
      ap_rflush(r);
      break;

    case CSE_SEND_HEADER:
      len = hmux_read_len(s);
      break;

    case HMUX_QUIT:
    case HMUX_EXIT:
      return code;

    default:
      if (code < 0) {
	return code;
      }
      
      len = hmux_read_len(s);
      cse_skip(s, len);
      break;
    }
  }
}
/**
 * Copy data from the JVM to the browser.
 */
static int
send_data(stream_t *s, request_rec *r, int ack, int *keepalive)
{
  int code = HMUX_QUIT;
  char buf[8193];
  char key[8193];
  char value[8193];
  int channel;
  int i;

  /* ap_reset_timeout(r); */
    
  if (cse_fill_buffer(s) < 0)
    return -1;

  /*
  code = cse_read_byte(s);
  if (code != HMUX_CHANNEL) {
    r->status = 500;
    r->status_line = "Protocol error";

    cse_close(s, "bad protocol");
    return -1;
  }
  channel = hmux_read_len(s);
  */
    
  do {
    int len;

    /* ap_reset_timeout(r); */
    
    code = cse_read_byte(s);

    if (s->socket < 0)
      return -1;

    switch (code) {
    case HMUX_CHANNEL:
      channel = hmux_read_len(s);
      LOG(("channel %d\n", channel));
      break;
      
    case HMUX_ACK:
      channel = hmux_read_len(s);
      LOG(("ack %d\n", channel));
      break;
      
    case HMUX_STATUS:
      len = hmux_read_len(s);
      cse_read_limit(s, buf, sizeof(buf), len);
      for (i = 0; buf[i] && buf[i] != ' '; i++) {
      }
      buf[i] = 0;
      r->status = atoi(buf);
      buf[i] = ' ';
      i++;
      r->status_line = ap_pstrdup(r->pool, buf);
      break;

    case HMUX_HEADER:
      len = hmux_read_len(s);
      cse_read_limit(s, key, sizeof(key), len);
      cse_read_string(s, value, sizeof(value));
      if (! strcasecmp(key, "content-type"))
	r->content_type = ap_pstrdup(r->pool, value);
      else
	ap_table_add(r->headers_out, key, value);
      break;
      
    case HMUX_META_HEADER:
      len = hmux_read_len(s);
      cse_read_limit(s, key, sizeof(key), len);
      cse_read_string(s, value, sizeof(value));
      break;

    case HMUX_DATA:
      len = hmux_read_len(s);
      if (cse_write_response(s, len, r) < 0)
	return -1;
      break;

    case HMUX_FLUSH:
      len = hmux_read_len(s);
      ap_rflush(r);
      break;

    case CSE_KEEPALIVE:
      len = hmux_read_len(s);
      *keepalive = 1;
      break;

    case CSE_SEND_HEADER:
      len = hmux_read_len(s);
      ap_send_http_header(r);
      break;

    case -1:
      break;

    case HMUX_QUIT:
    case HMUX_EXIT:
      break;
      
    default:
      len = hmux_read_len(s);
      cse_skip(s, len);
      break;
    }
  } while (code > 0 && code != HMUX_QUIT && code != HMUX_EXIT && code != ack);

  return code;
}