Beispiel #1
0
bud_client_error_t bud_client_backend_out(bud_client_t* client) {
  int read;
  int err;
  size_t avail;
  char* out;
  bud_client_error_t cerr;

  /* If buffer is full - stop reading */
  cerr = bud_client_throttle(client,
                             &client->backend,
                             &client->backend.output);
  if (cerr.err.code == kBudErrClientThrottle)
    return bud_client_ok(&client->frontend);
  else if (!bud_is_ok(cerr.err))
    return cerr;

  do {
    avail = 0;
    out = ringbuffer_write_ptr(&client->backend.output, &avail);
    read = SSL_read(client->ssl, out, avail);
    DBG(&client->frontend, "SSL_read() => %d", read);
    if (read > 0) {
      ringbuffer_write_append(&client->backend.output, read);
      if (client->selected_backend->xforward &&
          !bud_client_xforward_done(client)) {
        cerr = bud_client_prepend_xforward(client);
        if (!bud_is_ok(cerr.err))
          return cerr;
      }

      cerr = bud_client_send(client, &client->backend);
      if (!bud_is_ok(cerr.err))
        return cerr;
    }

    /* info_cb() has closed front-end */
    if (client->close != kBudProgressNone)
      return bud_client_ok(&client->frontend);
  } while (read > 0);

  if (read > 0)
    goto success;

  err = SSL_get_error(client->ssl, read);
  if (err == SSL_ERROR_WANT_READ || err == SSL_ERROR_WANT_WRITE)
    goto success;

  /* Close-notify, most likely */
  if (err == SSL_ERROR_ZERO_RETURN)
    return bud_client_shutdown(client, &client->backend);

  return bud_client_error(bud_error_num(kBudErrClientSSLRead, err),
                          &client->frontend);

success:
  return bud_client_ok(&client->backend);
}
Beispiel #2
0
bud_client_error_t bud_client_http_xforward(bud_client_t* client) {
  char* out;
  size_t avail;
  size_t off;
  char xforward[256];
  int r;

  out = ringbuffer_read_next(&client->backend.output, &avail);

  /* Not enough data yet */
  if (avail <= client->xforward.skip)
    goto done;

  /* Find first CRLF */
  for (off = client->xforward.skip; off < avail; off++) {
    static char* crlf = "\r\n";
    char cur;

    cur = out[off];

    /* Reset on mismatch */
    if (cur != crlf[client->xforward.crlf]) {
      client->xforward.crlf = 0;
      continue;
    }

    /* Move forward */
    if (++client->xforward.crlf == 2) {
      off++;
      break;
    }
  }
  client->xforward.skip = off;
  if (!bud_client_xforward_done(client))
    goto done;

  /* Format header */
  r = snprintf(xforward,
               sizeof(xforward),
               "X-Forwarded-For: %s\r\n",
               client->host);

  /* Shift data and insert xforward header */
  r = ringbuffer_insert(&client->backend.output,
                        client->xforward.skip,
                        xforward,
                        (size_t) r);
  if (r != 0) {
    return bud_client_error(bud_error(kBudErrClientXForwardInsert),
                            &client->backend);
  }

done:
  return bud_client_ok(&client->backend);
}
Beispiel #3
0
bud_client_error_t bud_client_backend_out(bud_client_t* client) {
  int read;
  int err;
  size_t avail;
  char* out;
  bud_client_error_t cerr;

  /* If buffer is full - stop reading */
  cerr = bud_client_throttle(client,
                             &client->backend,
                             &client->backend.output);
  if (cerr.err.code == kBudErrClientThrottle)
    return bud_client_ok(&client->frontend);
  else if (!bud_is_ok(cerr.err))
    return cerr;

  do {
    avail = 0;
    int init_trigger;

    init_trigger = SSL_is_init_finished(client->ssl);
    out = ringbuffer_write_ptr(&client->backend.output, &avail);
    read = SSL_read(client->ssl, out, avail);
    init_trigger ^= SSL_is_init_finished(client->ssl);

    DBG(&client->frontend, "SSL_read() => %d", read);
    if (read > 0)
      ringbuffer_write_append(&client->backend.output, read);

    /* Send proxyline once the handshake will end */
    if (init_trigger != 0) {
      cerr = bud_client_prepend_proxyline(client);
      if (!bud_is_ok(cerr.err))
        return cerr;
    }

    /* If there is any new data - try to append x-forwarded-for */
    if (read > 0 &&
        client->selected_backend->xforward &&
        !bud_client_xforward_done(client)) {
      cerr = bud_client_prepend_xforward(client);
      if (!bud_is_ok(cerr.err))
        return cerr;
    }

    /* Either proxyline or incoming data - need to send stuff to the client */
    if (init_trigger != 0 || read > 0) {
      cerr = bud_client_send(client, &client->backend);
      if (!bud_is_ok(cerr.err))
        return cerr;
    }

    /* info_cb() has closed front-end */
    if (client->close != kBudProgressNone)
      return bud_client_ok(&client->frontend);
  } while (read > 0);

  if (read > 0)
    goto success;

  err = SSL_get_error(client->ssl, read);
  if (err == SSL_ERROR_WANT_READ ||
      err == SSL_ERROR_WANT_WRITE ||
      err == SSL_ERROR_WANT_X509_LOOKUP) {
    goto success;
  }

  /* Close-notify, most likely */
  if (err == SSL_ERROR_ZERO_RETURN)
    return bud_client_shutdown(client, &client->backend);

  return bud_client_error(bud_error_num(kBudErrClientSSLRead, err),
                          &client->frontend);

success:
  return bud_client_ok(&client->backend);
}