outgoing.c   outgoing.c 
skipping to change at line 32 skipping to change at line 32
#include "serf_private.h" #include "serf_private.h"
/* cleanup for sockets */ /* cleanup for sockets */
static apr_status_t clean_skt(void *data) static apr_status_t clean_skt(void *data)
{ {
serf_connection_t *conn = data; serf_connection_t *conn = data;
apr_status_t status = APR_SUCCESS; apr_status_t status = APR_SUCCESS;
if (conn->skt) { if (conn->skt) {
serf__log_skt(SOCK_VERBOSE, __FILE__, conn->skt, "cleanup - ");
status = apr_socket_close(conn->skt); status = apr_socket_close(conn->skt);
conn->skt = NULL; conn->skt = NULL;
serf__log_nopref(SOCK_VERBOSE, "closed socket, status %d\n", status );
} }
return status; return status;
} }
static apr_status_t clean_resp(void *data) static apr_status_t clean_resp(void *data)
{ {
serf_request_t *request = data; serf_request_t *request = data;
/* The request's RESPOOL is being cleared. */ /* The request's RESPOOL is being cleared. */
skipping to change at line 74 skipping to change at line 76
request->respool = NULL; request->respool = NULL;
return APR_SUCCESS; return APR_SUCCESS;
} }
/* cleanup for conns */ /* cleanup for conns */
static apr_status_t clean_conn(void *data) static apr_status_t clean_conn(void *data)
{ {
serf_connection_t *conn = data; serf_connection_t *conn = data;
serf__log(CONN_VERBOSE, __FILE__, "cleaning up connection 0x%x\n",
conn);
serf_connection_close(conn); serf_connection_close(conn);
return APR_SUCCESS; return APR_SUCCESS;
} }
/* Update the pollset for this connection. We tweak the pollset based on /* Update the pollset for this connection. We tweak the pollset based on
* whether we want to read and/or write, given conditions within the * whether we want to read and/or write, given conditions within the
* connection. If the connection is not (yet) in the pollset, then it * connection. If the connection is not (yet) in the pollset, then it
* will be added. * will be added.
*/ */
skipping to change at line 187 skipping to change at line 191
* yet. This is the core of our lazy-connect behavior. * yet. This is the core of our lazy-connect behavior.
*/ */
apr_status_t serf__open_connections(serf_context_t *ctx) apr_status_t serf__open_connections(serf_context_t *ctx)
{ {
int i; int i;
for (i = ctx->conns->nelts; i--; ) { for (i = ctx->conns->nelts; i--; ) {
serf_connection_t *conn = GET_CONN(ctx, i); serf_connection_t *conn = GET_CONN(ctx, i);
apr_status_t status; apr_status_t status;
apr_socket_t *skt; apr_socket_t *skt;
apr_sockaddr_t *serv_addr;
conn->seen_in_pollset = 0; conn->seen_in_pollset = 0;
if (conn->skt != NULL) { if (conn->skt != NULL) {
#ifdef SERF_DEBUG_BUCKET_USE #ifdef SERF_DEBUG_BUCKET_USE
check_buckets_drained(conn); check_buckets_drained(conn);
#endif #endif
continue; continue;
} }
/* Delay opening until we have something to deliver! */ /* Delay opening until we have something to deliver! */
if (conn->requests == NULL) { if (conn->requests == NULL) {
continue; continue;
} }
apr_pool_clear(conn->skt_pool); apr_pool_clear(conn->skt_pool);
apr_pool_cleanup_register(conn->skt_pool, conn, clean_skt, clean_sk t); apr_pool_cleanup_register(conn->skt_pool, conn, clean_skt, clean_sk t);
/* Do we have to connect to a proxy server? */ status = apr_socket_create(&skt, conn->address->family,
if (ctx->proxy_address) SOCK_STREAM,
serv_addr = ctx->proxy_address;
else
serv_addr = conn->address;
if ((status = apr_socket_create(&skt, serv_addr->family,
SOCK_STREAM,
#if APR_MAJOR_VERSION > 0 #if APR_MAJOR_VERSION > 0
APR_PROTO_TCP, APR_PROTO_TCP,
#endif #endif
conn->skt_pool)) != APR_SUCCESS) conn->skt_pool);
serf__log(SOCK_VERBOSE, __FILE__,
"created socket for conn 0x%x, status %d\n", conn, status
);
if (status != APR_SUCCESS)
return status; return status;
/* Set the socket to be non-blocking */ /* Set the socket to be non-blocking */
if ((status = apr_socket_timeout_set(skt, 0)) != APR_SUCCESS) if ((status = apr_socket_timeout_set(skt, 0)) != APR_SUCCESS)
return status; return status;
/* Disable Nagle's algorithm */ /* Disable Nagle's algorithm */
if ((status = apr_socket_opt_set(skt, if ((status = apr_socket_opt_set(skt,
APR_TCP_NODELAY, 1)) != APR_SUCCES S) APR_TCP_NODELAY, 1)) != APR_SUCCES S)
return status; return status;
/* Configured. Store it into the connection now. */ /* Configured. Store it into the connection now. */
conn->skt = skt; conn->skt = skt;
/* Remember time when we started connecting to server to calculate
network latency. */
conn->connect_time = apr_time_now();
/* Now that the socket is set up, let's connect it. This should /* Now that the socket is set up, let's connect it. This should
* return immediately. * return immediately.
*/ */
if ((status = apr_socket_connect(skt, status = apr_socket_connect(skt, conn->address);
serv_addr)) != APR_SUCCESS) { serf__log_skt(SOCK_VERBOSE, __FILE__, skt,
"connected socket for conn 0x%x, status %d\n",
conn, status);
if (status != APR_SUCCESS) {
if (!APR_STATUS_IS_EINPROGRESS(status)) if (!APR_STATUS_IS_EINPROGRESS(status))
return status; return status;
} }
/* Flag our pollset as dirty now that we have a new socket. */ /* Flag our pollset as dirty now that we have a new socket. */
conn->dirty_conn = 1; conn->dirty_conn = 1;
ctx->dirty_pollset = 1; ctx->dirty_pollset = 1;
/* If the authentication was already started on another connection, /* If the authentication was already started on another connection,
prepare this connection (it might be possible to skip some prepare this connection (it might be possible to skip some
skipping to change at line 274 skipping to change at line 281
} }
return APR_SUCCESS; return APR_SUCCESS;
} }
static apr_status_t no_more_writes(serf_connection_t *conn, static apr_status_t no_more_writes(serf_connection_t *conn,
serf_request_t *request) serf_request_t *request)
{ {
/* Note that we should hold new requests until we open our new socket. */ /* Note that we should hold new requests until we open our new socket. */
conn->state = SERF_CONN_CLOSING; conn->state = SERF_CONN_CLOSING;
serf__log(CONN_VERBOSE, __FILE__, "stop writing on conn 0x%x\n",
conn);
/* Clear our iovec. */ /* Clear our iovec. */
conn->vec_len = 0; conn->vec_len = 0;
/* Update the pollset to know we don't want to write on this socket any /* Update the pollset to know we don't want to write on this socket any
* more. * more.
*/ */
conn->dirty_conn = 1; conn->dirty_conn = 1;
conn->ctx->dirty_pollset = 1; conn->ctx->dirty_pollset = 1;
return APR_SUCCESS; return APR_SUCCESS;
skipping to change at line 422 skipping to change at line 431
conn->probable_keepalive_limit = conn->completed_responses; conn->probable_keepalive_limit = conn->completed_responses;
conn->completed_requests = 0; conn->completed_requests = 0;
conn->completed_responses = 0; conn->completed_responses = 0;
old_reqs = conn->requests; old_reqs = conn->requests;
conn->requests = NULL; conn->requests = NULL;
conn->requests_tail = NULL; conn->requests_tail = NULL;
/* Handle all outstanding requests. These have either not been written
yet,
or have been written but the expected reply wasn't received yet. */
while (old_reqs) { while (old_reqs) {
/* If we haven't started to write the connection, bring it over /* If we haven't started to write the connection, bring it over
* unchanged to our new socket. Otherwise, call the cancel functio n. * unchanged to our new socket.
*/ */
if (requeue_requests && !old_reqs->written) { if (requeue_requests && !old_reqs->written) {
serf_request_t *req = old_reqs; serf_request_t *req = old_reqs;
old_reqs = old_reqs->next; old_reqs = old_reqs->next;
req->next = NULL; req->next = NULL;
link_requests(&conn->requests, &conn->requests_tail, req); link_requests(&conn->requests, &conn->requests_tail, req);
} }
else { else {
/* Request has been consumed, or we don't want to requeue the
request. Either way, inform the application that the request
is cancelled. */
cancel_request(old_reqs, &old_reqs, requeue_requests); cancel_request(old_reqs, &old_reqs, requeue_requests);
} }
} }
/* Requests queue has been prepared for a new socket, close the old one . */
if (conn->skt != NULL) { if (conn->skt != NULL) {
remove_connection(ctx, conn); remove_connection(ctx, conn);
status = apr_socket_close(conn->skt); status = apr_socket_close(conn->skt);
serf__log_skt(SOCK_VERBOSE, __FILE__, conn->skt,
"closed socket, status %d\n", status);
if (conn->closed != NULL) { if (conn->closed != NULL) {
handle_conn_closed(conn, status); handle_conn_closed(conn, status);
} }
conn->skt = NULL; conn->skt = NULL;
} }
if (conn->stream != NULL) { if (conn->stream != NULL) {
serf_bucket_destroy(conn->stream); serf_bucket_destroy(conn->stream);
conn->stream = NULL; conn->stream = NULL;
} }
destroy_ostream(conn); destroy_ostream(conn);
/* Don't try to resume any writes */ /* Don't try to resume any writes */
conn->vec_len = 0; conn->vec_len = 0;
conn->dirty_conn = 1; conn->dirty_conn = 1;
conn->ctx->dirty_pollset = 1; conn->ctx->dirty_pollset = 1;
conn->state = SERF_CONN_INIT; conn->state = SERF_CONN_INIT;
serf__log(CONN_VERBOSE, __FILE__, "reset connection 0x%x\n", conn);
conn->status = APR_SUCCESS; conn->status = APR_SUCCESS;
/* Let our context know that we've 'reset' the socket already. */ /* Let our context know that we've 'reset' the socket already. */
conn->seen_in_pollset |= APR_POLLHUP; conn->seen_in_pollset |= APR_POLLHUP;
/* Found the connection. Closed it. All done. */ /* Found the connection. Closed it. All done. */
return APR_SUCCESS; return APR_SUCCESS;
} }
static apr_status_t socket_writev(serf_connection_t *conn) static apr_status_t socket_writev(serf_connection_t *conn)
{ {
apr_size_t written; apr_size_t written;
apr_status_t status; apr_status_t status;
status = apr_socket_sendv(conn->skt, conn->vec, status = apr_socket_sendv(conn->skt, conn->vec,
conn->vec_len, &written); conn->vec_len, &written);
if (status && !APR_STATUS_IS_EAGAIN(status))
serf__log_skt(SOCK_VERBOSE, __FILE__, conn->skt,
"socket_sendv error %d\n", status);
/* did we write everything? */ /* did we write everything? */
if (written) { if (written) {
apr_size_t len = 0; apr_size_t len = 0;
int i; int i;
serf__log_skt(SOCK_MSG_VERBOSE, __FILE__, conn->skt,
"--- socket_sendv:\n");
for (i = 0; i < conn->vec_len; i++) { for (i = 0; i < conn->vec_len; i++) {
len += conn->vec[i].iov_len; len += conn->vec[i].iov_len;
if (written < len) { if (written < len) {
serf__log_nopref(SOCK_MSG_VERBOSE, "%.*s",
conn->vec[i].iov_len - (len - written),
conn->vec[i].iov_base);
if (i) { if (i) {
memmove(conn->vec, &conn->vec[i], memmove(conn->vec, &conn->vec[i],
sizeof(struct iovec) * (conn->vec_len - i)); sizeof(struct iovec) * (conn->vec_len - i));
conn->vec_len -= i; conn->vec_len -= i;
} }
conn->vec[0].iov_base = (char *)conn->vec[0].iov_base + (co nn->vec[0].iov_len - (len - written)); conn->vec[0].iov_base = (char *)conn->vec[0].iov_base + (co nn->vec[0].iov_len - (len - written));
conn->vec[0].iov_len = len - written; conn->vec[0].iov_len = len - written;
break; break;
} else {
serf__log_nopref(SOCK_MSG_VERBOSE, "%.*s",
conn->vec[i].iov_len, conn->vec[i].iov_b
ase);
} }
} }
if (len == written) { if (len == written) {
conn->vec_len = 0; conn->vec_len = 0;
} }
serf__log_nopref(SOCK_MSG_VERBOSE, "-(%d)-\n", written);
/* Log progress information */ /* Log progress information */
serf__context_progress_delta(conn->ctx, 0, written); serf__context_progress_delta(conn->ctx, 0, written);
} }
return status; return status;
} }
static apr_status_t detect_eof(void *baton, serf_bucket_t *aggregate_bucket ) static apr_status_t detect_eof(void *baton, serf_bucket_t *aggregate_bucket )
{ {
skipping to change at line 565 skipping to change at line 597
[en/de]cryption. [en/de]cryption.
*/ */
static apr_status_t prepare_conn_streams(serf_connection_t *conn, static apr_status_t prepare_conn_streams(serf_connection_t *conn,
serf_bucket_t **istream, serf_bucket_t **istream,
serf_bucket_t **ostreamt, serf_bucket_t **ostreamt,
serf_bucket_t **ostreamh) serf_bucket_t **ostreamh)
{ {
apr_status_t status; apr_status_t status;
if (conn->stream == NULL) {
conn->latency = apr_time_now() - conn->connect_time;
}
/* Do we need a SSL tunnel first? */ /* Do we need a SSL tunnel first? */
if (conn->state == SERF_CONN_CONNECTED) { if (conn->state == SERF_CONN_CONNECTED) {
/* If the connection does not have an associated bucket, then /* If the connection does not have an associated bucket, then
* call the setup callback to get one. * call the setup callback to get one.
*/ */
if (conn->stream == NULL) { if (conn->stream == NULL) {
status = do_conn_setup(conn); status = do_conn_setup(conn);
if (status) { if (status) {
return status; return status;
} }
skipping to change at line 919 skipping to change at line 955
* *
* 1) when the other end has closed the socket and we're * 1) when the other end has closed the socket and we're
* pending an EOF return. * pending an EOF return.
* 2) Doing the initial SSL handshake - we'll get EAGAIN * 2) Doing the initial SSL handshake - we'll get EAGAIN
* as the SSL buckets will hide the handshake from us * as the SSL buckets will hide the handshake from us
* but not return any data. * but not return any data.
* 3) When the server sends us an SSL alert. * 3) When the server sends us an SSL alert.
* *
* In these cases, we should not receive any actual user data. * In these cases, we should not receive any actual user data.
* *
* If we see an EOF (due to either an expired timeout or the serer * 4) When the server sends a error response, like 408 Request time
out.
* This response should be passed to the application.
*
* If we see an EOF (due to either an expired timeout or the server
* sending the SSL 'close notify' shutdown alert), we'll reset the * sending the SSL 'close notify' shutdown alert), we'll reset the
* connection and open a new one. * connection and open a new one.
*/ */
if (request->req_bkt || !request->written) { if (request->req_bkt || !request->written) {
const char *data; const char *data;
apr_size_t len; apr_size_t len;
status = serf_bucket_read(conn->stream, SERF_READ_ALL_AVAIL, status = serf_bucket_peek(conn->stream, &data, &len);
&data, &len);
if (!status && len) { if (APR_STATUS_IS_EOF(status)) {
status = APR_EGENERAL;
}
else if (APR_STATUS_IS_EOF(status)) {
reset_connection(conn, 1); reset_connection(conn, 1);
status = APR_SUCCESS; status = APR_SUCCESS;
goto error;
} }
else if (APR_STATUS_IS_EAGAIN(status)) { else if (APR_STATUS_IS_EAGAIN(status) && !len) {
status = APR_SUCCESS; status = APR_SUCCESS;
goto error;
} else if (status && !APR_STATUS_IS_EAGAIN(status)) {
/* Read error */
goto error;
} }
goto error; /* Unexpected response from the server */
} }
/* If the request doesn't have a response bucket, then call the /* If the request doesn't have a response bucket, then call the
* acceptor to get one created. * acceptor to get one created.
*/ */
if (request->resp_bkt == NULL) { if (request->resp_bkt == NULL) {
request->resp_bkt = (*request->acceptor)(request, conn->stream, request->resp_bkt = (*request->acceptor)(request, conn->stream,
request->acceptor_bato n, request->acceptor_bato n,
tmppool); tmppool);
apr_pool_clear(tmppool); apr_pool_clear(tmppool);
} }
status = handle_response(request, tmppool); status = handle_response(request, tmppool);
/* Some systems will not generate a HUP poll event so we have to /* Some systems will not generate a HUP poll event so we have to
* handle the ECONNRESET issue and ECONNABORT here. * handle the ECONNRESET issue and ECONNABORT here.
*/ */
if (APR_STATUS_IS_ECONNRESET(status) || if (APR_STATUS_IS_ECONNRESET(status) ||
APR_STATUS_IS_ECONNABORTED(status) || APR_STATUS_IS_ECONNABORTED(status) ||
status == SERF_ERROR_REQUEST_LOST) { status == SERF_ERROR_REQUEST_LOST) {
reset_connection(conn, 1); /* If the connection had ever been good, be optimistic & try ag
status = APR_SUCCESS; ain.
* If it has never tried again (incl. a retry), fail.
*/
if (conn->completed_responses) {
reset_connection(conn, 1);
status = APR_SUCCESS;
}
else if (status == SERF_ERROR_REQUEST_LOST) {
status = SERF_ERROR_ABORTED_CONNECTION;
}
goto error; goto error;
} }
/* If our response handler says it can't do anything more, we now /* If our response handler says it can't do anything more, we now
* treat that as a success. * treat that as a success.
*/ */
if (APR_STATUS_IS_EAGAIN(status)) { if (APR_STATUS_IS_EAGAIN(status)) {
status = APR_SUCCESS; status = APR_SUCCESS;
goto error; goto error;
} }
skipping to change at line 990 skipping to change at line 1039
close_connection = is_conn_closing(request->resp_bkt); close_connection = is_conn_closing(request->resp_bkt);
if (!APR_STATUS_IS_EOF(status) && if (!APR_STATUS_IS_EOF(status) &&
close_connection != SERF_ERROR_CLOSING) { close_connection != SERF_ERROR_CLOSING) {
/* Whether success, or an error, there is no more to do unless /* Whether success, or an error, there is no more to do unless
* this request has been completed. * this request has been completed.
*/ */
goto error; goto error;
} }
/* The request has been fully-delivered, and the response has /* The response has been fully-read, so that means the request has
* been fully-read. Remove it from our queue and loop to read * either been fully-delivered (most likely), or that we don't need
* another response. to
* write the rest of it anymore, e.g. when a 408 Request timeout wa
s
$ received.
* Remove it from our queue and loop to read another response.
*/ */
conn->requests = request->next; conn->requests = request->next;
destroy_request(request); destroy_request(request);
request = conn->requests; request = conn->requests;
/* If we're truly empty, update our tail. */ /* If we're truly empty, update our tail. */
if (request == NULL) { if (request == NULL) {
conn->requests_tail = NULL; conn->requests_tail = NULL;
skipping to change at line 1070 skipping to change at line 1121
/* If we decided to reset our connection, return now as we don't /* If we decided to reset our connection, return now as we don't
* want to write. * want to write.
*/ */
if ((conn->seen_in_pollset & APR_POLLHUP) != 0) { if ((conn->seen_in_pollset & APR_POLLHUP) != 0) {
return APR_SUCCESS; return APR_SUCCESS;
} }
} }
if ((events & APR_POLLHUP) != 0) { if ((events & APR_POLLHUP) != 0) {
/* The connection got reset by the server. On Windows this can happ en /* The connection got reset by the server. On Windows this can happ en
when all data is read, so just cleanup the connection and open when all data is read, so just cleanup the connection and open
a new one. */ a new one.
return reset_connection(conn, 1); If we haven't had any successful responses on this connection,
then error out as it is likely a server issue. */
if (conn->completed_responses) {
return reset_connection(conn, 1);
}
return SERF_ERROR_ABORTED_CONNECTION;
} }
if ((events & APR_POLLERR) != 0) { if ((events & APR_POLLERR) != 0) {
/* We might be talking to a buggy HTTP server that doesn't /* We might be talking to a buggy HTTP server that doesn't
* do lingering-close. (httpd < 2.1.8 does this.) * do lingering-close. (httpd < 2.1.8 does this.)
* *
* See: * See:
* *
* http://issues.apache.org/bugzilla/show_bug.cgi?id=35292 * http://issues.apache.org/bugzilla/show_bug.cgi?id=35292
*/ */
if (conn->completed_requests && !conn->probable_keepalive_limit) { if (conn->completed_requests && !conn->probable_keepalive_limit) {
skipping to change at line 1106 skipping to change at line 1162
serf_connection_setup_t setup, serf_connection_setup_t setup,
void *setup_baton, void *setup_baton,
serf_connection_closed_t closed, serf_connection_closed_t closed,
void *closed_baton, void *closed_baton,
apr_pool_t *pool) apr_pool_t *pool)
{ {
serf_connection_t *conn = apr_pcalloc(pool, sizeof(*conn)); serf_connection_t *conn = apr_pcalloc(pool, sizeof(*conn));
conn->ctx = ctx; conn->ctx = ctx;
conn->status = APR_SUCCESS; conn->status = APR_SUCCESS;
conn->address = address; /* Ignore server address if proxy was specified. */
conn->address = ctx->proxy_address ? ctx->proxy_address : address;
conn->setup = setup; conn->setup = setup;
conn->setup_baton = setup_baton; conn->setup_baton = setup_baton;
conn->closed = closed; conn->closed = closed;
conn->closed_baton = closed_baton; conn->closed_baton = closed_baton;
conn->pool = pool; conn->pool = pool;
conn->allocator = serf_bucket_allocator_create(pool, NULL, NULL); conn->allocator = serf_bucket_allocator_create(pool, NULL, NULL);
conn->stream = NULL; conn->stream = NULL;
conn->ostream_head = NULL; conn->ostream_head = NULL;
conn->ostream_tail = NULL; conn->ostream_tail = NULL;
conn->baton.type = SERF_IO_CONN; conn->baton.type = SERF_IO_CONN;
conn->baton.u.conn = conn; conn->baton.u.conn = conn;
conn->hit_eof = 0; conn->hit_eof = 0;
conn->state = SERF_CONN_INIT; conn->state = SERF_CONN_INIT;
conn->latency = -1; /* unknown */
/* Create a subpool for our connection. */ /* Create a subpool for our connection. */
apr_pool_create(&conn->skt_pool, conn->pool); apr_pool_create(&conn->skt_pool, conn->pool);
/* register a cleanup */ /* register a cleanup */
apr_pool_cleanup_register(conn->pool, conn, clean_conn, apr_pool_cleanu p_null); apr_pool_cleanup_register(conn->pool, conn, clean_conn, apr_pool_cleanu p_null);
/* Add the connection to the context. */ /* Add the connection to the context. */
*(serf_connection_t **)apr_array_push(ctx->conns) = conn; *(serf_connection_t **)apr_array_push(ctx->conns) = conn;
serf__log(CONN_VERBOSE, __FILE__, "created connection 0x%x\n",
conn);
return conn; return conn;
} }
apr_status_t serf_connection_create2( apr_status_t serf_connection_create2(
serf_connection_t **conn, serf_connection_t **conn,
serf_context_t *ctx, serf_context_t *ctx,
apr_uri_t host_info, apr_uri_t host_info,
serf_connection_setup_t setup, serf_connection_setup_t setup,
void *setup_baton, void *setup_baton,
serf_connection_closed_t closed, serf_connection_closed_t closed,
void *closed_baton, void *closed_baton,
apr_pool_t *pool) apr_pool_t *pool)
{ {
apr_status_t status; apr_status_t status = APR_SUCCESS;
serf_connection_t *c; serf_connection_t *c;
apr_sockaddr_t *host_address; apr_sockaddr_t *host_address = NULL;
/* Parse the url, store the address of the server. */ /* Set the port number explicitly, needed to create the socket later. *
status = apr_sockaddr_info_get(&host_address, /
host_info.hostname, if (!host_info.port) {
APR_UNSPEC, host_info.port, 0, pool); host_info.port = apr_uri_port_of_scheme(host_info.scheme);
if (status) }
return status;
/* Only lookup the address of the server if no proxy server was
configured. */
if (!ctx->proxy_address) {
status = apr_sockaddr_info_get(&host_address,
host_info.hostname,
APR_UNSPEC, host_info.port, 0, pool)
;
if (status)
return status;
}
c = serf_connection_create(ctx, host_address, setup, setup_baton, c = serf_connection_create(ctx, host_address, setup, setup_baton,
closed, closed_baton, pool); closed, closed_baton, pool);
/* We're not interested in the path following the hostname. */ /* We're not interested in the path following the hostname. */
c->host_url = apr_uri_unparse(c->pool, c->host_url = apr_uri_unparse(c->pool,
&host_info, &host_info,
APR_URI_UNP_OMITPATHINFO); APR_URI_UNP_OMITPATHINFO);
c->host_info = host_info; c->host_info = host_info;
skipping to change at line 1191 skipping to change at line 1260
for (i = ctx->conns->nelts; i--; ) { for (i = ctx->conns->nelts; i--; ) {
serf_connection_t *conn_seq = GET_CONN(ctx, i); serf_connection_t *conn_seq = GET_CONN(ctx, i);
if (conn_seq == conn) { if (conn_seq == conn) {
while (conn->requests) { while (conn->requests) {
serf_request_cancel(conn->requests); serf_request_cancel(conn->requests);
} }
if (conn->skt != NULL) { if (conn->skt != NULL) {
remove_connection(ctx, conn); remove_connection(ctx, conn);
status = apr_socket_close(conn->skt); status = apr_socket_close(conn->skt);
serf__log_skt(SOCK_VERBOSE, __FILE__, conn->skt,
"closed socket, status %d\n",
status);
if (conn->closed != NULL) { if (conn->closed != NULL) {
handle_conn_closed(conn, status); handle_conn_closed(conn, status);
} }
conn->skt = NULL; conn->skt = NULL;
} }
if (conn->stream != NULL) { if (conn->stream != NULL) {
serf_bucket_destroy(conn->stream); serf_bucket_destroy(conn->stream);
conn->stream = NULL; conn->stream = NULL;
} }
skipping to change at line 1215 skipping to change at line 1287
*/ */
if (i < ctx->conns->nelts - 1) { if (i < ctx->conns->nelts - 1) {
/* move later connections over this one. */ /* move later connections over this one. */
memmove( memmove(
&GET_CONN(ctx, i), &GET_CONN(ctx, i),
&GET_CONN(ctx, i + 1), &GET_CONN(ctx, i + 1),
(ctx->conns->nelts - i - 1) * sizeof(serf_connection_t *)); (ctx->conns->nelts - i - 1) * sizeof(serf_connection_t *));
} }
--ctx->conns->nelts; --ctx->conns->nelts;
serf__log(CONN_VERBOSE, __FILE__, "closed connection 0x%x\n",
conn);
/* Found the connection. Closed it. All done. */ /* Found the connection. Closed it. All done. */
return APR_SUCCESS; return APR_SUCCESS;
} }
} }
/* We didn't find the specified connection. */ /* We didn't find the specified connection. */
/* ### doc talks about this w.r.t poll structures. use something else? */ /* ### doc talks about this w.r.t poll structures. use something else? */
return APR_NOTFOUND; return APR_NOTFOUND;
} }
void serf_connection_set_max_outstanding_requests( void serf_connection_set_max_outstanding_requests(
serf_connection_t *conn, serf_connection_t *conn,
unsigned int max_requests) unsigned int max_requests)
{ {
if (max_requests == 0)
serf__log_skt(CONN_VERBOSE, __FILE__, conn->skt,
"Set max. nr. of outstanding requests for this "
"connection to unlimited.\n");
else
serf__log_skt(CONN_VERBOSE, __FILE__, conn->skt,
"Limit max. nr. of outstanding requests for this "
"connection to %u.\n", max_requests);
conn->max_outstanding_requests = max_requests; conn->max_outstanding_requests = max_requests;
} }
void serf_connection_set_async_responses( void serf_connection_set_async_responses(
serf_connection_t *conn, serf_connection_t *conn,
serf_response_acceptor_t acceptor, serf_response_acceptor_t acceptor,
void *acceptor_baton, void *acceptor_baton,
serf_response_handler_t handler, serf_response_handler_t handler,
void *handler_baton) void *handler_baton)
{ {
skipping to change at line 1331 skipping to change at line 1415
conn->dirty_conn = 1; conn->dirty_conn = 1;
return request; return request;
} }
apr_status_t serf_request_cancel(serf_request_t *request) apr_status_t serf_request_cancel(serf_request_t *request)
{ {
return cancel_request(request, &request->conn->requests, 0); return cancel_request(request, &request->conn->requests, 0);
} }
apr_status_t serf_request_is_written(serf_request_t *request)
{
if (request->written && !request->req_bkt)
return APR_SUCCESS;
return APR_EBUSY;
}
apr_pool_t *serf_request_get_pool(const serf_request_t *request) apr_pool_t *serf_request_get_pool(const serf_request_t *request)
{ {
return request->respool; return request->respool;
} }
serf_bucket_alloc_t *serf_request_get_alloc( serf_bucket_alloc_t *serf_request_get_alloc(
const serf_request_t *request) const serf_request_t *request)
{ {
return request->allocator; return request->allocator;
} }
skipping to change at line 1381 skipping to change at line 1473
/* Proxy? */ /* Proxy? */
if (ctx->proxy_address && conn->host_url) if (ctx->proxy_address && conn->host_url)
serf_bucket_request_set_root(req_bkt, conn->host_url); serf_bucket_request_set_root(req_bkt, conn->host_url);
if (conn->host_info.hostinfo) if (conn->host_info.hostinfo)
serf_bucket_headers_setn(hdrs_bkt, "Host", serf_bucket_headers_setn(hdrs_bkt, "Host",
conn->host_info.hostinfo); conn->host_info.hostinfo);
/* Setup server authorization headers */ /* Setup server authorization headers */
if (ctx->authn_info.scheme) if (ctx->authn_info.scheme)
ctx->authn_info.scheme->setup_request_func(401, conn, method, uri, ctx->authn_info.scheme->setup_request_func(HOST, 0, conn, method, u ri,
hdrs_bkt); hdrs_bkt);
/* Setup proxy authorization headers */ /* Setup proxy authorization headers */
if (ctx->proxy_authn_info.scheme) if (ctx->proxy_authn_info.scheme)
ctx->proxy_authn_info.scheme->setup_request_func(407, conn, method, ctx->proxy_authn_info.scheme->setup_request_func(PROXY, 0, conn,
uri, hdrs_bkt); method, uri, hdrs_
bkt);
return req_bkt; return req_bkt;
} }
apr_interval_time_t serf_connection_get_latency(serf_connection_t *conn)
{
if (conn->ctx->proxy_address) {
/* Detecting network latency for proxied connection is not implemen
ted
yet. */
return -1;
}
return conn->latency;
}
 End of changes. 45 change blocks. 
42 lines changed or deleted 144 lines changed or added

This html diff was produced by rfcdiff 1.41. The latest version is available from http://tools.ietf.org/tools/rfcdiff/