outgoing.c revision 253895
1251877Speter/* Copyright 2002-2004 Justin Erenkrantz and Greg Stein
2251877Speter *
3251877Speter * Licensed under the Apache License, Version 2.0 (the "License");
4251877Speter * you may not use this file except in compliance with the License.
5251877Speter * You may obtain a copy of the License at
6251877Speter *
7251877Speter *     http://www.apache.org/licenses/LICENSE-2.0
8251877Speter *
9251877Speter * Unless required by applicable law or agreed to in writing, software
10251877Speter * distributed under the License is distributed on an "AS IS" BASIS,
11251877Speter * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12251877Speter * See the License for the specific language governing permissions and
13251877Speter * limitations under the License.
14251877Speter */
15251877Speter
16251877Speter#include <apr_pools.h>
17251877Speter#include <apr_poll.h>
18251877Speter#include <apr_version.h>
19253895Speter#include <apr_portable.h>
20251877Speter
21251877Speter#include "serf.h"
22251877Speter#include "serf_bucket_util.h"
23251877Speter
24251877Speter#include "serf_private.h"
25251877Speter
26251877Speter/* cleanup for sockets */
27251877Speterstatic apr_status_t clean_skt(void *data)
28251877Speter{
29251877Speter    serf_connection_t *conn = data;
30251877Speter    apr_status_t status = APR_SUCCESS;
31251877Speter
32251877Speter    if (conn->skt) {
33251877Speter        serf__log_skt(SOCK_VERBOSE, __FILE__, conn->skt, "cleanup - ");
34251877Speter        status = apr_socket_close(conn->skt);
35251877Speter        conn->skt = NULL;
36251877Speter        serf__log_nopref(SOCK_VERBOSE, "closed socket, status %d\n", status);
37251877Speter    }
38251877Speter
39251877Speter    return status;
40251877Speter}
41251877Speter
42251877Speterstatic apr_status_t clean_resp(void *data)
43251877Speter{
44251877Speter    serf_request_t *request = data;
45251877Speter
46251877Speter    /* The request's RESPOOL is being cleared.  */
47251877Speter
48251877Speter    /* If the response has allocated some buckets, then destroy them (since
49251877Speter       the bucket may hold resources other than memory in RESPOOL). Also
50251877Speter       make sure to set their fields to NULL so connection closure does
51251877Speter       not attempt to free them again.  */
52251877Speter    if (request->resp_bkt) {
53251877Speter        serf_bucket_destroy(request->resp_bkt);
54251877Speter        request->resp_bkt = NULL;
55251877Speter    }
56251877Speter    if (request->req_bkt) {
57251877Speter        serf_bucket_destroy(request->req_bkt);
58251877Speter        request->req_bkt = NULL;
59251877Speter    }
60251877Speter
61251877Speter    /* ### should we worry about debug stuff, like that performed in
62251877Speter       ### destroy_request()? should we worry about calling req->handler
63251877Speter       ### to notify this "cancellation" due to pool clearing?  */
64251877Speter
65251877Speter    /* This pool just got cleared/destroyed. Don't try to destroy the pool
66251877Speter       (again) when the request is canceled.  */
67251877Speter    request->respool = NULL;
68251877Speter
69251877Speter    return APR_SUCCESS;
70251877Speter}
71251877Speter
72251877Speter/* cleanup for conns */
73251877Speterstatic apr_status_t clean_conn(void *data)
74251877Speter{
75251877Speter    serf_connection_t *conn = data;
76251877Speter
77251877Speter    serf__log(CONN_VERBOSE, __FILE__, "cleaning up connection 0x%x\n",
78251877Speter              conn);
79251877Speter    serf_connection_close(conn);
80251877Speter
81251877Speter    return APR_SUCCESS;
82251877Speter}
83251877Speter
84251877Speter/* Update the pollset for this connection. We tweak the pollset based on
85251877Speter * whether we want to read and/or write, given conditions within the
86251877Speter * connection. If the connection is not (yet) in the pollset, then it
87251877Speter * will be added.
88251877Speter */
89251877Speterapr_status_t serf__conn_update_pollset(serf_connection_t *conn)
90251877Speter{
91251877Speter    serf_context_t *ctx = conn->ctx;
92251877Speter    apr_status_t status;
93251877Speter    apr_pollfd_t desc = { 0 };
94251877Speter
95251877Speter    if (!conn->skt) {
96251877Speter        return APR_SUCCESS;
97251877Speter    }
98251877Speter
99251877Speter    /* Remove the socket from the poll set. */
100251877Speter    desc.desc_type = APR_POLL_SOCKET;
101251877Speter    desc.desc.s = conn->skt;
102251877Speter    desc.reqevents = conn->reqevents;
103251877Speter
104251877Speter    status = ctx->pollset_rm(ctx->pollset_baton,
105251877Speter                             &desc, conn);
106251877Speter    if (status && !APR_STATUS_IS_NOTFOUND(status))
107251877Speter        return status;
108251877Speter
109251877Speter    /* Now put it back in with the correct read/write values. */
110251877Speter    desc.reqevents = APR_POLLHUP | APR_POLLERR;
111251877Speter    if (conn->requests &&
112251877Speter        conn->state != SERF_CONN_INIT) {
113251877Speter        /* If there are any outstanding events, then we want to read. */
114251877Speter        /* ### not true. we only want to read IF we have sent some data */
115251877Speter        desc.reqevents |= APR_POLLIN;
116251877Speter
117253895Speter        /* Don't write if OpenSSL told us that it needs to read data first. */
118253895Speter        if (conn->stop_writing != 1) {
119251877Speter
120253895Speter            /* If the connection is not closing down and
121253895Speter             *   has unwritten data or
122253895Speter             *   there are any requests that still have buckets to write out,
123253895Speter             *     then we want to write.
124253895Speter             */
125253895Speter            if (conn->vec_len &&
126253895Speter                conn->state != SERF_CONN_CLOSING)
127253895Speter                desc.reqevents |= APR_POLLOUT;
128253895Speter            else {
129253895Speter                serf_request_t *request = conn->requests;
130253895Speter
131253895Speter                if ((conn->probable_keepalive_limit &&
132253895Speter                     conn->completed_requests > conn->probable_keepalive_limit) ||
133253895Speter                    (conn->max_outstanding_requests &&
134253895Speter                     conn->completed_requests - conn->completed_responses >=
135251877Speter                     conn->max_outstanding_requests)) {
136253895Speter                        /* we wouldn't try to write any way right now. */
137253895Speter                    }
138253895Speter                else {
139253895Speter                    while (request != NULL && request->req_bkt == NULL &&
140253895Speter                           request->written)
141253895Speter                        request = request->next;
142253895Speter                    if (request != NULL)
143253895Speter                        desc.reqevents |= APR_POLLOUT;
144253895Speter                }
145251877Speter            }
146251877Speter        }
147251877Speter    }
148251877Speter
149251877Speter    /* If we can have async responses, always look for something to read. */
150251877Speter    if (conn->async_responses) {
151251877Speter        desc.reqevents |= APR_POLLIN;
152251877Speter    }
153251877Speter
154251877Speter    /* save our reqevents, so we can pass it in to remove later. */
155251877Speter    conn->reqevents = desc.reqevents;
156251877Speter
157251877Speter    /* Note: even if we don't want to read/write this socket, we still
158251877Speter     * want to poll it for hangups and errors.
159251877Speter     */
160251877Speter    return ctx->pollset_add(ctx->pollset_baton,
161251877Speter                            &desc, &conn->baton);
162251877Speter}
163251877Speter
164251877Speter#ifdef SERF_DEBUG_BUCKET_USE
165251877Speter
166251877Speter/* Make sure all response buckets were drained. */
167251877Speterstatic void check_buckets_drained(serf_connection_t *conn)
168251877Speter{
169251877Speter    serf_request_t *request = conn->requests;
170251877Speter
171251877Speter    for ( ; request ; request = request->next ) {
172251877Speter        if (request->resp_bkt != NULL) {
173251877Speter            /* ### crap. can't do this. this allocator may have un-drained
174251877Speter             * ### REQUEST buckets.
175251877Speter             */
176251877Speter            /* serf_debug__entered_loop(request->resp_bkt->allocator); */
177251877Speter            /* ### for now, pretend we closed the conn (resets the tracking) */
178251877Speter            serf_debug__closed_conn(request->resp_bkt->allocator);
179251877Speter        }
180251877Speter    }
181251877Speter}
182251877Speter
183251877Speter#endif
184251877Speter
185253895Speterstatic void destroy_ostream(serf_connection_t *conn)
186253895Speter{
187253895Speter    if (conn->ostream_head != NULL) {
188253895Speter        serf_bucket_destroy(conn->ostream_head);
189253895Speter        conn->ostream_head = NULL;
190253895Speter        conn->ostream_tail = NULL;
191253895Speter    }
192253895Speter}
193253895Speter
194253895Speterstatic apr_status_t detect_eof(void *baton, serf_bucket_t *aggregate_bucket)
195253895Speter{
196253895Speter    serf_connection_t *conn = baton;
197253895Speter    conn->hit_eof = 1;
198253895Speter    return APR_EAGAIN;
199253895Speter}
200253895Speter
201253895Speterstatic apr_status_t do_conn_setup(serf_connection_t *conn)
202253895Speter{
203253895Speter    apr_status_t status;
204253895Speter    serf_bucket_t *ostream;
205253895Speter
206253895Speter    if (conn->ostream_head == NULL) {
207253895Speter        conn->ostream_head = serf_bucket_aggregate_create(conn->allocator);
208253895Speter    }
209253895Speter
210253895Speter    if (conn->ostream_tail == NULL) {
211253895Speter        conn->ostream_tail = serf__bucket_stream_create(conn->allocator,
212253895Speter                                                        detect_eof,
213253895Speter                                                        conn);
214253895Speter    }
215253895Speter
216253895Speter    ostream = conn->ostream_tail;
217253895Speter
218253895Speter    status = (*conn->setup)(conn->skt,
219253895Speter                            &conn->stream,
220253895Speter                            &ostream,
221253895Speter                            conn->setup_baton,
222253895Speter                            conn->pool);
223253895Speter    if (status) {
224253895Speter        /* extra destroy here since it wasn't added to the head bucket yet. */
225253895Speter        serf_bucket_destroy(conn->ostream_tail);
226253895Speter        destroy_ostream(conn);
227253895Speter        return status;
228253895Speter    }
229253895Speter
230253895Speter    serf_bucket_aggregate_append(conn->ostream_head,
231253895Speter                                 ostream);
232253895Speter
233253895Speter    return status;
234253895Speter}
235253895Speter
236253895Speter/* Set up the input and output stream buckets.
237253895Speter When a tunnel over an http proxy is needed, create a socket bucket and
238253895Speter empty aggregate bucket for sending and receiving unencrypted requests
239253895Speter over the socket.
240253895Speter
241253895Speter After the tunnel is there, or no tunnel was needed, ask the application
242253895Speter to create the input and output buckets, which should take care of the
243253895Speter [en/de]cryption.
244253895Speter */
245253895Speter
246253895Speterstatic apr_status_t prepare_conn_streams(serf_connection_t *conn,
247253895Speter                                         serf_bucket_t **istream,
248253895Speter                                         serf_bucket_t **ostreamt,
249253895Speter                                         serf_bucket_t **ostreamh)
250253895Speter{
251253895Speter    apr_status_t status;
252253895Speter
253253895Speter    if (conn->stream == NULL) {
254253895Speter        conn->latency = apr_time_now() - conn->connect_time;
255253895Speter    }
256253895Speter
257253895Speter    /* Do we need a SSL tunnel first? */
258253895Speter    if (conn->state == SERF_CONN_CONNECTED) {
259253895Speter        /* If the connection does not have an associated bucket, then
260253895Speter         * call the setup callback to get one.
261253895Speter         */
262253895Speter        if (conn->stream == NULL) {
263253895Speter            status = do_conn_setup(conn);
264253895Speter            if (status) {
265253895Speter                return status;
266253895Speter            }
267253895Speter        }
268253895Speter        *ostreamt = conn->ostream_tail;
269253895Speter        *ostreamh = conn->ostream_head;
270253895Speter        *istream = conn->stream;
271253895Speter    } else {
272253895Speter        /* SSL tunnel needed and not set up yet, get a direct unencrypted
273253895Speter         stream for this socket */
274253895Speter        if (conn->stream == NULL) {
275253895Speter            *istream = serf_bucket_socket_create(conn->skt,
276253895Speter                                                 conn->allocator);
277253895Speter        }
278253895Speter        /* Don't create the ostream bucket chain including the ssl_encrypt
279253895Speter         bucket yet. This ensure the CONNECT request is sent unencrypted
280253895Speter         to the proxy. */
281253895Speter        *ostreamt = *ostreamh = conn->ssltunnel_ostream;
282253895Speter    }
283253895Speter
284253895Speter    return APR_SUCCESS;
285253895Speter}
286253895Speter
287251877Speter/* Create and connect sockets for any connections which don't have them
288251877Speter * yet. This is the core of our lazy-connect behavior.
289251877Speter */
290251877Speterapr_status_t serf__open_connections(serf_context_t *ctx)
291251877Speter{
292251877Speter    int i;
293251877Speter
294251877Speter    for (i = ctx->conns->nelts; i--; ) {
295251877Speter        serf_connection_t *conn = GET_CONN(ctx, i);
296253895Speter        serf__authn_info_t *authn_info;
297251877Speter        apr_status_t status;
298251877Speter        apr_socket_t *skt;
299251877Speter
300251877Speter        conn->seen_in_pollset = 0;
301251877Speter
302251877Speter        if (conn->skt != NULL) {
303251877Speter#ifdef SERF_DEBUG_BUCKET_USE
304251877Speter            check_buckets_drained(conn);
305251877Speter#endif
306251877Speter            continue;
307251877Speter        }
308251877Speter
309251877Speter        /* Delay opening until we have something to deliver! */
310251877Speter        if (conn->requests == NULL) {
311251877Speter            continue;
312251877Speter        }
313251877Speter
314251877Speter        apr_pool_clear(conn->skt_pool);
315251877Speter        apr_pool_cleanup_register(conn->skt_pool, conn, clean_skt, clean_skt);
316251877Speter
317251877Speter        status = apr_socket_create(&skt, conn->address->family,
318251877Speter                                   SOCK_STREAM,
319251877Speter#if APR_MAJOR_VERSION > 0
320251877Speter                                   APR_PROTO_TCP,
321251877Speter#endif
322251877Speter                                   conn->skt_pool);
323251877Speter        serf__log(SOCK_VERBOSE, __FILE__,
324251877Speter                  "created socket for conn 0x%x, status %d\n", conn, status);
325251877Speter        if (status != APR_SUCCESS)
326251877Speter            return status;
327251877Speter
328251877Speter        /* Set the socket to be non-blocking */
329251877Speter        if ((status = apr_socket_timeout_set(skt, 0)) != APR_SUCCESS)
330251877Speter            return status;
331251877Speter
332251877Speter        /* Disable Nagle's algorithm */
333251877Speter        if ((status = apr_socket_opt_set(skt,
334251877Speter                                         APR_TCP_NODELAY, 1)) != APR_SUCCESS)
335251877Speter            return status;
336251877Speter
337251877Speter        /* Configured. Store it into the connection now. */
338251877Speter        conn->skt = skt;
339251877Speter
340251877Speter        /* Remember time when we started connecting to server to calculate
341251877Speter           network latency. */
342251877Speter        conn->connect_time = apr_time_now();
343251877Speter
344251877Speter        /* Now that the socket is set up, let's connect it. This should
345251877Speter         * return immediately.
346251877Speter         */
347251877Speter        status = apr_socket_connect(skt, conn->address);
348251877Speter        serf__log_skt(SOCK_VERBOSE, __FILE__, skt,
349251877Speter                      "connected socket for conn 0x%x, status %d\n",
350251877Speter                      conn, status);
351253895Speter        if (status != APR_SUCCESS) {
352251877Speter            if (!APR_STATUS_IS_EINPROGRESS(status))
353251877Speter                return status;
354251877Speter        }
355251877Speter
356251877Speter        /* Flag our pollset as dirty now that we have a new socket. */
357251877Speter        conn->dirty_conn = 1;
358251877Speter        ctx->dirty_pollset = 1;
359251877Speter
360251877Speter        /* If the authentication was already started on another connection,
361251877Speter           prepare this connection (it might be possible to skip some
362251877Speter           part of the handshaking). */
363251877Speter        if (ctx->proxy_address) {
364253895Speter            authn_info = &ctx->proxy_authn_info;
365253895Speter            if (authn_info->scheme) {
366253895Speter                authn_info->scheme->init_conn_func(authn_info->scheme, 407,
367253895Speter                                                   conn, conn->pool);
368253895Speter            }
369251877Speter        }
370251877Speter
371253895Speter        authn_info = serf__get_authn_info_for_server(conn);
372253895Speter        if (authn_info->scheme) {
373253895Speter            authn_info->scheme->init_conn_func(authn_info->scheme, 401,
374253895Speter                                               conn, conn->pool);
375253895Speter        }
376251877Speter
377251877Speter        /* Does this connection require a SSL tunnel over the proxy? */
378251877Speter        if (ctx->proxy_address && strcmp(conn->host_info.scheme, "https") == 0)
379251877Speter            serf__ssltunnel_connect(conn);
380253895Speter        else {
381253895Speter            serf_bucket_t *dummy1, *dummy2;
382253895Speter
383251877Speter            conn->state = SERF_CONN_CONNECTED;
384251877Speter
385253895Speter            status = prepare_conn_streams(conn, &conn->stream,
386253895Speter                                          &dummy1, &dummy2);
387253895Speter            if (status) {
388253895Speter                return status;
389253895Speter            }
390253895Speter        }
391251877Speter    }
392251877Speter
393251877Speter    return APR_SUCCESS;
394251877Speter}
395251877Speter
396251877Speterstatic apr_status_t no_more_writes(serf_connection_t *conn,
397251877Speter                                   serf_request_t *request)
398251877Speter{
399251877Speter    /* Note that we should hold new requests until we open our new socket. */
400251877Speter    conn->state = SERF_CONN_CLOSING;
401251877Speter    serf__log(CONN_VERBOSE, __FILE__, "stop writing on conn 0x%x\n",
402251877Speter              conn);
403251877Speter
404251877Speter    /* Clear our iovec. */
405251877Speter    conn->vec_len = 0;
406251877Speter
407251877Speter    /* Update the pollset to know we don't want to write on this socket any
408251877Speter     * more.
409251877Speter     */
410251877Speter    conn->dirty_conn = 1;
411251877Speter    conn->ctx->dirty_pollset = 1;
412251877Speter    return APR_SUCCESS;
413251877Speter}
414251877Speter
415251877Speter/* Read the 'Connection' header from the response. Return SERF_ERROR_CLOSING if
416251877Speter * the header contains value 'close' indicating the server is closing the
417251877Speter * connection right after this response.
418251877Speter * Otherwise returns APR_SUCCESS.
419251877Speter */
420251877Speterstatic apr_status_t is_conn_closing(serf_bucket_t *response)
421251877Speter{
422251877Speter    serf_bucket_t *hdrs;
423251877Speter    const char *val;
424251877Speter
425251877Speter    hdrs = serf_bucket_response_get_headers(response);
426251877Speter    val = serf_bucket_headers_get(hdrs, "Connection");
427251877Speter    if (val && strcasecmp("close", val) == 0)
428251877Speter        {
429251877Speter            return SERF_ERROR_CLOSING;
430251877Speter        }
431251877Speter
432251877Speter    return APR_SUCCESS;
433251877Speter}
434251877Speter
435251877Speterstatic void link_requests(serf_request_t **list, serf_request_t **tail,
436251877Speter                          serf_request_t *request)
437251877Speter{
438251877Speter    if (*list == NULL) {
439251877Speter        *list = request;
440251877Speter        *tail = request;
441251877Speter    }
442251877Speter    else {
443251877Speter        (*tail)->next = request;
444251877Speter        *tail = request;
445251877Speter    }
446251877Speter}
447251877Speter
448251877Speterstatic apr_status_t destroy_request(serf_request_t *request)
449251877Speter{
450251877Speter    serf_connection_t *conn = request->conn;
451251877Speter
452251877Speter    /* The request and response buckets are no longer needed,
453251877Speter       nor is the request's pool.  */
454251877Speter    if (request->resp_bkt) {
455251877Speter        serf_debug__closed_conn(request->resp_bkt->allocator);
456251877Speter        serf_bucket_destroy(request->resp_bkt);
457251877Speter        request->resp_bkt = NULL;
458251877Speter    }
459251877Speter    if (request->req_bkt) {
460251877Speter        serf_debug__closed_conn(request->req_bkt->allocator);
461251877Speter        serf_bucket_destroy(request->req_bkt);
462251877Speter        request->req_bkt = NULL;
463251877Speter    }
464251877Speter
465251877Speter    serf_debug__bucket_alloc_check(request->allocator);
466251877Speter    if (request->respool) {
467251877Speter        /* ### unregister the pool cleanup for self?  */
468251877Speter        apr_pool_destroy(request->respool);
469251877Speter    }
470251877Speter
471251877Speter    serf_bucket_mem_free(conn->allocator, request);
472251877Speter
473251877Speter    return APR_SUCCESS;
474251877Speter}
475251877Speter
476251877Speterstatic apr_status_t cancel_request(serf_request_t *request,
477251877Speter                                   serf_request_t **list,
478251877Speter                                   int notify_request)
479251877Speter{
480251877Speter    /* If we haven't run setup, then we won't have a handler to call. */
481251877Speter    if (request->handler && notify_request) {
482251877Speter        /* We actually don't care what the handler returns.
483251877Speter         * We have bigger matters at hand.
484251877Speter         */
485251877Speter        (*request->handler)(request, NULL, request->handler_baton,
486251877Speter                            request->respool);
487251877Speter    }
488251877Speter
489251877Speter    if (*list == request) {
490251877Speter        *list = request->next;
491251877Speter    }
492251877Speter    else {
493251877Speter        serf_request_t *scan = *list;
494251877Speter
495251877Speter        while (scan->next && scan->next != request)
496251877Speter            scan = scan->next;
497251877Speter
498251877Speter        if (scan->next) {
499251877Speter            scan->next = scan->next->next;
500251877Speter        }
501251877Speter    }
502251877Speter
503251877Speter    return destroy_request(request);
504251877Speter}
505251877Speter
506251877Speterstatic apr_status_t remove_connection(serf_context_t *ctx,
507251877Speter                                      serf_connection_t *conn)
508251877Speter{
509251877Speter    apr_pollfd_t desc = { 0 };
510251877Speter
511251877Speter    desc.desc_type = APR_POLL_SOCKET;
512251877Speter    desc.desc.s = conn->skt;
513251877Speter    desc.reqevents = conn->reqevents;
514251877Speter
515251877Speter    return ctx->pollset_rm(ctx->pollset_baton,
516251877Speter                           &desc, conn);
517251877Speter}
518251877Speter
519251877Speter/* A socket was closed, inform the application. */
520251877Speterstatic void handle_conn_closed(serf_connection_t *conn, apr_status_t status)
521251877Speter{
522251877Speter    (*conn->closed)(conn, conn->closed_baton, status,
523251877Speter                    conn->pool);
524251877Speter}
525251877Speter
526251877Speterstatic apr_status_t reset_connection(serf_connection_t *conn,
527251877Speter                                     int requeue_requests)
528251877Speter{
529251877Speter    serf_context_t *ctx = conn->ctx;
530251877Speter    apr_status_t status;
531251877Speter    serf_request_t *old_reqs;
532251877Speter
533251877Speter    conn->probable_keepalive_limit = conn->completed_responses;
534251877Speter    conn->completed_requests = 0;
535251877Speter    conn->completed_responses = 0;
536251877Speter
537251877Speter    old_reqs = conn->requests;
538251877Speter
539251877Speter    conn->requests = NULL;
540251877Speter    conn->requests_tail = NULL;
541251877Speter
542251877Speter    /* Handle all outstanding requests. These have either not been written yet,
543251877Speter       or have been written but the expected reply wasn't received yet. */
544251877Speter    while (old_reqs) {
545251877Speter        /* If we haven't started to write the connection, bring it over
546251877Speter         * unchanged to our new socket.
547251877Speter         */
548251877Speter        if (requeue_requests && !old_reqs->written) {
549251877Speter            serf_request_t *req = old_reqs;
550251877Speter            old_reqs = old_reqs->next;
551251877Speter            req->next = NULL;
552251877Speter            link_requests(&conn->requests, &conn->requests_tail, req);
553251877Speter        }
554251877Speter        else {
555251877Speter            /* Request has been consumed, or we don't want to requeue the
556251877Speter               request. Either way, inform the application that the request
557251877Speter               is cancelled. */
558251877Speter            cancel_request(old_reqs, &old_reqs, requeue_requests);
559251877Speter        }
560251877Speter    }
561251877Speter
562251877Speter    /* Requests queue has been prepared for a new socket, close the old one. */
563251877Speter    if (conn->skt != NULL) {
564251877Speter        remove_connection(ctx, conn);
565251877Speter        status = apr_socket_close(conn->skt);
566251877Speter        serf__log_skt(SOCK_VERBOSE, __FILE__, conn->skt,
567251877Speter                      "closed socket, status %d\n", status);
568251877Speter        if (conn->closed != NULL) {
569251877Speter            handle_conn_closed(conn, status);
570251877Speter        }
571251877Speter        conn->skt = NULL;
572251877Speter    }
573251877Speter
574251877Speter    if (conn->stream != NULL) {
575251877Speter        serf_bucket_destroy(conn->stream);
576251877Speter        conn->stream = NULL;
577251877Speter    }
578251877Speter
579251877Speter    destroy_ostream(conn);
580251877Speter
581251877Speter    /* Don't try to resume any writes */
582251877Speter    conn->vec_len = 0;
583251877Speter
584251877Speter    conn->dirty_conn = 1;
585251877Speter    conn->ctx->dirty_pollset = 1;
586251877Speter    conn->state = SERF_CONN_INIT;
587251877Speter
588251877Speter    serf__log(CONN_VERBOSE, __FILE__, "reset connection 0x%x\n", conn);
589251877Speter
590251877Speter    conn->status = APR_SUCCESS;
591251877Speter
592251877Speter    /* Let our context know that we've 'reset' the socket already. */
593251877Speter    conn->seen_in_pollset |= APR_POLLHUP;
594251877Speter
595251877Speter    /* Found the connection. Closed it. All done. */
596251877Speter    return APR_SUCCESS;
597251877Speter}
598251877Speter
599251877Speterstatic apr_status_t socket_writev(serf_connection_t *conn)
600251877Speter{
601251877Speter    apr_size_t written;
602251877Speter    apr_status_t status;
603251877Speter
604251877Speter    status = apr_socket_sendv(conn->skt, conn->vec,
605251877Speter                              conn->vec_len, &written);
606253895Speter    if (status && !APR_STATUS_IS_EAGAIN(status))
607251877Speter        serf__log_skt(SOCK_VERBOSE, __FILE__, conn->skt,
608251877Speter                      "socket_sendv error %d\n", status);
609251877Speter
610251877Speter    /* did we write everything? */
611251877Speter    if (written) {
612251877Speter        apr_size_t len = 0;
613251877Speter        int i;
614251877Speter
615251877Speter        serf__log_skt(SOCK_MSG_VERBOSE, __FILE__, conn->skt,
616251877Speter                      "--- socket_sendv:\n");
617251877Speter
618251877Speter        for (i = 0; i < conn->vec_len; i++) {
619251877Speter            len += conn->vec[i].iov_len;
620251877Speter            if (written < len) {
621251877Speter                serf__log_nopref(SOCK_MSG_VERBOSE, "%.*s",
622251877Speter                                   conn->vec[i].iov_len - (len - written),
623251877Speter                                   conn->vec[i].iov_base);
624251877Speter                if (i) {
625251877Speter                    memmove(conn->vec, &conn->vec[i],
626251877Speter                            sizeof(struct iovec) * (conn->vec_len - i));
627251877Speter                    conn->vec_len -= i;
628251877Speter                }
629251877Speter                conn->vec[0].iov_base = (char *)conn->vec[0].iov_base + (conn->vec[0].iov_len - (len - written));
630251877Speter                conn->vec[0].iov_len = len - written;
631251877Speter                break;
632251877Speter            } else {
633251877Speter                serf__log_nopref(SOCK_MSG_VERBOSE, "%.*s",
634251877Speter                                   conn->vec[i].iov_len, conn->vec[i].iov_base);
635251877Speter            }
636251877Speter        }
637251877Speter        if (len == written) {
638251877Speter            conn->vec_len = 0;
639251877Speter        }
640251877Speter        serf__log_nopref(SOCK_MSG_VERBOSE, "-(%d)-\n", written);
641251877Speter
642251877Speter        /* Log progress information */
643251877Speter        serf__context_progress_delta(conn->ctx, 0, written);
644251877Speter    }
645251877Speter
646251877Speter    return status;
647251877Speter}
648251877Speter
649253895Speterstatic apr_status_t setup_request(serf_request_t *request)
650251877Speter{
651253895Speter    serf_connection_t *conn = request->conn;
652251877Speter    apr_status_t status;
653251877Speter
654253895Speter    /* Now that we are about to serve the request, allocate a pool. */
655253895Speter    apr_pool_create(&request->respool, conn->pool);
656253895Speter    request->allocator = serf_bucket_allocator_create(request->respool,
657253895Speter                                                      NULL, NULL);
658253895Speter    apr_pool_cleanup_register(request->respool, request,
659253895Speter                              clean_resp, clean_resp);
660251877Speter
661253895Speter    /* Fill in the rest of the values for the request. */
662253895Speter    status = request->setup(request, request->setup_baton,
663253895Speter                            &request->req_bkt,
664253895Speter                            &request->acceptor,
665253895Speter                            &request->acceptor_baton,
666253895Speter                            &request->handler,
667253895Speter                            &request->handler_baton,
668253895Speter                            request->respool);
669251877Speter    return status;
670251877Speter}
671251877Speter
672251877Speter/* write data out to the connection */
673251877Speterstatic apr_status_t write_to_connection(serf_connection_t *conn)
674251877Speter{
675251877Speter    serf_request_t *request = conn->requests;
676251877Speter
677251877Speter    if (conn->probable_keepalive_limit &&
678251877Speter        conn->completed_requests > conn->probable_keepalive_limit) {
679251877Speter
680251877Speter        conn->dirty_conn = 1;
681251877Speter        conn->ctx->dirty_pollset = 1;
682251877Speter
683251877Speter        /* backoff for now. */
684251877Speter        return APR_SUCCESS;
685251877Speter    }
686251877Speter
687251877Speter    /* Find a request that has data which needs to be delivered. */
688251877Speter    while (request != NULL &&
689251877Speter           request->req_bkt == NULL && request->written)
690251877Speter        request = request->next;
691251877Speter
692251877Speter    /* assert: request != NULL || conn->vec_len */
693251877Speter
694251877Speter    /* Keep reading and sending until we run out of stuff to read, or
695251877Speter     * writing would block.
696251877Speter     */
697251877Speter    while (1) {
698251877Speter        int stop_reading = 0;
699251877Speter        apr_status_t status;
700251877Speter        apr_status_t read_status;
701251877Speter        serf_bucket_t *ostreamt, *ostreamh;
702251877Speter        int max_outstanding_requests = conn->max_outstanding_requests;
703251877Speter
704251877Speter        /* If we're setting up an ssl tunnel, we can't send real requests
705251877Speter           at yet, as they need to be encrypted and our encrypt buckets
706251877Speter           aren't created yet as we still need to read the unencrypted
707251877Speter           response of the CONNECT request. */
708251877Speter        if (conn->state != SERF_CONN_CONNECTED)
709251877Speter            max_outstanding_requests = 1;
710251877Speter
711251877Speter        if (max_outstanding_requests &&
712251877Speter            conn->completed_requests -
713251877Speter                conn->completed_responses >= max_outstanding_requests) {
714251877Speter            /* backoff for now. */
715251877Speter            return APR_SUCCESS;
716251877Speter        }
717251877Speter
718251877Speter        /* If we have unwritten data, then write what we can. */
719251877Speter        while (conn->vec_len) {
720251877Speter            status = socket_writev(conn);
721251877Speter
722251877Speter            /* If the write would have blocked, then we're done. Don't try
723251877Speter             * to write anything else to the socket.
724251877Speter             */
725251877Speter            if (APR_STATUS_IS_EAGAIN(status))
726251877Speter                return APR_SUCCESS;
727251877Speter            if (APR_STATUS_IS_EPIPE(status) ||
728251877Speter                APR_STATUS_IS_ECONNRESET(status) ||
729251877Speter                APR_STATUS_IS_ECONNABORTED(status))
730251877Speter                return no_more_writes(conn, request);
731251877Speter            if (status)
732251877Speter                return status;
733251877Speter        }
734251877Speter        /* ### can we have a short write, yet no EAGAIN? a short write
735251877Speter           ### would imply unwritten_len > 0 ... */
736251877Speter        /* assert: unwritten_len == 0. */
737251877Speter
738251877Speter        /* We may need to move forward to a request which has something
739251877Speter         * to write.
740251877Speter         */
741251877Speter        while (request != NULL &&
742251877Speter               request->req_bkt == NULL && request->written)
743251877Speter            request = request->next;
744251877Speter
745251877Speter        if (request == NULL) {
746251877Speter            /* No more requests (with data) are registered with the
747251877Speter             * connection. Let's update the pollset so that we don't
748251877Speter             * try to write to this socket again.
749251877Speter             */
750251877Speter            conn->dirty_conn = 1;
751251877Speter            conn->ctx->dirty_pollset = 1;
752251877Speter            return APR_SUCCESS;
753251877Speter        }
754251877Speter
755251877Speter        status = prepare_conn_streams(conn, &conn->stream, &ostreamt, &ostreamh);
756251877Speter        if (status) {
757251877Speter            return status;
758251877Speter        }
759251877Speter
760251877Speter        if (request->req_bkt == NULL) {
761253895Speter            read_status = setup_request(request);
762251877Speter            if (read_status) {
763251877Speter                /* Something bad happened. Propagate any errors. */
764251877Speter                return read_status;
765251877Speter            }
766253895Speter        }
767251877Speter
768253895Speter        if (!request->written) {
769251877Speter            request->written = 1;
770251877Speter            serf_bucket_aggregate_append(ostreamt, request->req_bkt);
771251877Speter        }
772251877Speter
773251877Speter        /* ### optimize at some point by using read_for_sendfile */
774253895Speter        /* TODO: now that read_iovec will effectively try to return as much
775253895Speter           data as available, we probably don't want to read ALL_AVAIL, but
776253895Speter           a lower number, like the size of one or a few TCP packets, the
777253895Speter           available TCP buffer size ... */
778251877Speter        read_status = serf_bucket_read_iovec(ostreamh,
779251877Speter                                             SERF_READ_ALL_AVAIL,
780251877Speter                                             IOV_MAX,
781251877Speter                                             conn->vec,
782251877Speter                                             &conn->vec_len);
783251877Speter
784251877Speter        if (!conn->hit_eof) {
785253895Speter            if (APR_STATUS_IS_EAGAIN(read_status)) {
786251877Speter                /* We read some stuff, but should not try to read again. */
787251877Speter                stop_reading = 1;
788253895Speter            }
789253895Speter            else if (read_status == SERF_ERROR_WAIT_CONN) {
790253895Speter                /* The bucket told us that it can't provide more data until
791253895Speter                   more data is read from the socket. This normally happens
792253895Speter                   during a SSL handshake.
793251877Speter
794253895Speter                   We should avoid looking for writability for a while so
795253895Speter                   that (hopefully) something will appear in the bucket so
796253895Speter                   we can actually write something. otherwise, we could
797253895Speter                   end up in a CPU spin: socket wants something, but we
798253895Speter                   don't have anything (and keep returning EAGAIN)
799253895Speter                 */
800253895Speter                conn->stop_writing = 1;
801253895Speter                conn->dirty_conn = 1;
802253895Speter                conn->ctx->dirty_pollset = 1;
803251877Speter            }
804251877Speter            else if (read_status && !APR_STATUS_IS_EOF(read_status)) {
805251877Speter                /* Something bad happened. Propagate any errors. */
806251877Speter                return read_status;
807251877Speter            }
808251877Speter        }
809251877Speter
810251877Speter        /* If we got some data, then deliver it. */
811251877Speter        /* ### what to do if we got no data?? is that a problem? */
812251877Speter        if (conn->vec_len > 0) {
813251877Speter            status = socket_writev(conn);
814251877Speter
815251877Speter            /* If we can't write any more, or an error occurred, then
816251877Speter             * we're done here.
817251877Speter             */
818251877Speter            if (APR_STATUS_IS_EAGAIN(status))
819251877Speter                return APR_SUCCESS;
820251877Speter            if (APR_STATUS_IS_EPIPE(status))
821251877Speter                return no_more_writes(conn, request);
822251877Speter            if (APR_STATUS_IS_ECONNRESET(status) ||
823251877Speter                APR_STATUS_IS_ECONNABORTED(status)) {
824251877Speter                return no_more_writes(conn, request);
825251877Speter            }
826251877Speter            if (status)
827251877Speter                return status;
828251877Speter        }
829251877Speter
830251877Speter        if (read_status == SERF_ERROR_WAIT_CONN) {
831251877Speter            stop_reading = 1;
832253895Speter            conn->stop_writing = 1;
833253895Speter            conn->dirty_conn = 1;
834253895Speter            conn->ctx->dirty_pollset = 1;
835251877Speter        }
836251877Speter        else if (read_status && conn->hit_eof && conn->vec_len == 0) {
837251877Speter            /* If we hit the end of the request bucket and all of its data has
838251877Speter             * been written, then clear it out to signify that we're done
839251877Speter             * sending the request. On the next iteration through this loop:
840251877Speter             * - if there are remaining bytes they will be written, and as the
841251877Speter             * request bucket will be completely read it will be destroyed then.
842251877Speter             * - we'll see if there are other requests that need to be sent
843251877Speter             * ("pipelining").
844251877Speter             */
845251877Speter            conn->hit_eof = 0;
846251877Speter            serf_bucket_destroy(request->req_bkt);
847251877Speter            request->req_bkt = NULL;
848251877Speter
849251877Speter            /* If our connection has async responses enabled, we're not
850251877Speter             * going to get a reply back, so kill the request.
851251877Speter             */
852251877Speter            if (conn->async_responses) {
853251877Speter                conn->requests = request->next;
854251877Speter                destroy_request(request);
855251877Speter            }
856251877Speter
857251877Speter            conn->completed_requests++;
858251877Speter
859251877Speter            if (conn->probable_keepalive_limit &&
860251877Speter                conn->completed_requests > conn->probable_keepalive_limit) {
861251877Speter                /* backoff for now. */
862251877Speter                stop_reading = 1;
863251877Speter            }
864251877Speter        }
865251877Speter
866251877Speter        if (stop_reading) {
867251877Speter            return APR_SUCCESS;
868251877Speter        }
869251877Speter    }
870251877Speter    /* NOTREACHED */
871251877Speter}
872251877Speter
873251877Speter/* A response message was received from the server, so call
874251877Speter   the handler as specified on the original request. */
875251877Speterstatic apr_status_t handle_response(serf_request_t *request,
876251877Speter                                    apr_pool_t *pool)
877251877Speter{
878251877Speter    apr_status_t status = APR_SUCCESS;
879251877Speter    int consumed_response = 0;
880251877Speter
881251877Speter    /* Only enable the new authentication framework if the program has
882251877Speter     * registered an authentication credential callback.
883251877Speter     *
884251877Speter     * This permits older Serf apps to still handle authentication
885251877Speter     * themselves by not registering credential callbacks.
886251877Speter     */
887251877Speter    if (request->conn->ctx->cred_cb) {
888251877Speter      status = serf__handle_auth_response(&consumed_response,
889251877Speter                                          request,
890251877Speter                                          request->resp_bkt,
891251877Speter                                          request->handler_baton,
892251877Speter                                          pool);
893251877Speter
894251877Speter      /* If there was an error reading the response (maybe there wasn't
895251877Speter         enough data available), don't bother passing the response to the
896251877Speter         application.
897251877Speter
898251877Speter         If the authentication was tried, but failed, pass the response
899251877Speter         to the application, maybe it can do better. */
900251877Speter      if (APR_STATUS_IS_EOF(status) ||
901251877Speter          APR_STATUS_IS_EAGAIN(status)) {
902251877Speter          return status;
903251877Speter      }
904251877Speter    }
905251877Speter
906251877Speter    if (!consumed_response) {
907251877Speter        return (*request->handler)(request,
908251877Speter                                   request->resp_bkt,
909251877Speter                                   request->handler_baton,
910251877Speter                                   pool);
911251877Speter    }
912251877Speter
913251877Speter    return status;
914251877Speter}
915251877Speter
916251877Speter/* An async response message was received from the server. */
917251877Speterstatic apr_status_t handle_async_response(serf_connection_t *conn,
918251877Speter                                          apr_pool_t *pool)
919251877Speter{
920251877Speter    apr_status_t status;
921251877Speter
922251877Speter    if (conn->current_async_response == NULL) {
923251877Speter        conn->current_async_response =
924251877Speter            (*conn->async_acceptor)(NULL, conn->stream,
925251877Speter                                    conn->async_acceptor_baton, pool);
926251877Speter    }
927251877Speter
928251877Speter    status = (*conn->async_handler)(NULL, conn->current_async_response,
929251877Speter                                    conn->async_handler_baton, pool);
930251877Speter
931251877Speter    if (APR_STATUS_IS_EOF(status)) {
932251877Speter        serf_bucket_destroy(conn->current_async_response);
933251877Speter        conn->current_async_response = NULL;
934251877Speter        status = APR_SUCCESS;
935251877Speter    }
936251877Speter
937251877Speter    return status;
938251877Speter}
939251877Speter
940253895Speter
941253895Speterapr_status_t
942253895Speterserf__provide_credentials(serf_context_t *ctx,
943253895Speter                          char **username,
944253895Speter                          char **password,
945253895Speter                          serf_request_t *request, void *baton,
946253895Speter                          int code, const char *authn_type,
947253895Speter                          const char *realm,
948253895Speter                          apr_pool_t *pool)
949253895Speter{
950253895Speter    serf_connection_t *conn = request->conn;
951253895Speter    serf_request_t *authn_req = request;
952253895Speter    apr_status_t status;
953253895Speter
954253895Speter    if (request->ssltunnel == 1 &&
955253895Speter        conn->state == SERF_CONN_SETUP_SSLTUNNEL) {
956253895Speter        /* This is a CONNECT request to set up an SSL tunnel over a proxy.
957253895Speter           This request is created by serf, so if the proxy requires
958253895Speter           authentication, we can't ask the application for credentials with
959253895Speter           this request.
960253895Speter
961253895Speter           Solution: setup the first request created by the application on
962253895Speter           this connection, and use that request and its handler_baton to
963253895Speter           call back to the application. */
964253895Speter
965253895Speter        authn_req = request->next;
966253895Speter        /* assert: app_request != NULL */
967253895Speter        if (!authn_req)
968253895Speter            return APR_EGENERAL;
969253895Speter
970253895Speter        if (!authn_req->req_bkt) {
971253895Speter            apr_status_t status;
972253895Speter
973253895Speter            status = setup_request(authn_req);
974253895Speter            /* If we can't setup a request, don't bother setting up the
975253895Speter               ssl tunnel. */
976253895Speter            if (status)
977253895Speter                return status;
978253895Speter        }
979253895Speter    }
980253895Speter
981253895Speter    /* Ask the application. */
982253895Speter    status = (*ctx->cred_cb)(username, password,
983253895Speter                             authn_req, authn_req->handler_baton,
984253895Speter                             code, authn_type, realm, pool);
985253895Speter    if (status)
986253895Speter        return status;
987253895Speter
988253895Speter    return APR_SUCCESS;
989253895Speter}
990253895Speter
991251877Speter/* read data from the connection */
992251877Speterstatic apr_status_t read_from_connection(serf_connection_t *conn)
993251877Speter{
994251877Speter    apr_status_t status;
995251877Speter    apr_pool_t *tmppool;
996251877Speter    int close_connection = FALSE;
997251877Speter
998251877Speter    /* Whatever is coming in on the socket corresponds to the first request
999251877Speter     * on our chain.
1000251877Speter     */
1001251877Speter    serf_request_t *request = conn->requests;
1002251877Speter
1003253895Speter    /* If the stop_writing flag was set on the connection, reset it now because
1004253895Speter       there is some data to read. */
1005253895Speter    if (conn->stop_writing) {
1006253895Speter        conn->stop_writing = 0;
1007253895Speter        conn->dirty_conn = 1;
1008253895Speter        conn->ctx->dirty_pollset = 1;
1009253895Speter    }
1010253895Speter
1011251877Speter    /* assert: request != NULL */
1012251877Speter
1013251877Speter    if ((status = apr_pool_create(&tmppool, conn->pool)) != APR_SUCCESS)
1014251877Speter        goto error;
1015251877Speter
1016251877Speter    /* Invoke response handlers until we have no more work. */
1017251877Speter    while (1) {
1018251877Speter        serf_bucket_t *dummy1, *dummy2;
1019251877Speter
1020251877Speter        apr_pool_clear(tmppool);
1021251877Speter
1022251877Speter        /* Only interested in the input stream here. */
1023251877Speter        status = prepare_conn_streams(conn, &conn->stream, &dummy1, &dummy2);
1024251877Speter        if (status) {
1025251877Speter            goto error;
1026251877Speter        }
1027251877Speter
1028251877Speter        /* We have a different codepath when we can have async responses. */
1029251877Speter        if (conn->async_responses) {
1030251877Speter            /* TODO What about socket errors? */
1031251877Speter            status = handle_async_response(conn, tmppool);
1032251877Speter            if (APR_STATUS_IS_EAGAIN(status)) {
1033251877Speter                status = APR_SUCCESS;
1034251877Speter                goto error;
1035251877Speter            }
1036251877Speter            if (status) {
1037251877Speter                goto error;
1038251877Speter            }
1039251877Speter            continue;
1040251877Speter        }
1041251877Speter
1042251877Speter        /* We are reading a response for a request we haven't
1043251877Speter         * written yet!
1044251877Speter         *
1045251877Speter         * This shouldn't normally happen EXCEPT:
1046251877Speter         *
1047251877Speter         * 1) when the other end has closed the socket and we're
1048251877Speter         *    pending an EOF return.
1049251877Speter         * 2) Doing the initial SSL handshake - we'll get EAGAIN
1050251877Speter         *    as the SSL buckets will hide the handshake from us
1051251877Speter         *    but not return any data.
1052251877Speter         * 3) When the server sends us an SSL alert.
1053251877Speter         *
1054251877Speter         * In these cases, we should not receive any actual user data.
1055251877Speter         *
1056251877Speter         * 4) When the server sends a error response, like 408 Request timeout.
1057251877Speter         *    This response should be passed to the application.
1058251877Speter         *
1059251877Speter         * If we see an EOF (due to either an expired timeout or the server
1060251877Speter         * sending the SSL 'close notify' shutdown alert), we'll reset the
1061251877Speter         * connection and open a new one.
1062251877Speter         */
1063251877Speter        if (request->req_bkt || !request->written) {
1064251877Speter            const char *data;
1065251877Speter            apr_size_t len;
1066251877Speter
1067251877Speter            status = serf_bucket_peek(conn->stream, &data, &len);
1068251877Speter
1069251877Speter            if (APR_STATUS_IS_EOF(status)) {
1070251877Speter                reset_connection(conn, 1);
1071251877Speter                status = APR_SUCCESS;
1072251877Speter                goto error;
1073251877Speter            }
1074251877Speter            else if (APR_STATUS_IS_EAGAIN(status) && !len) {
1075251877Speter                status = APR_SUCCESS;
1076251877Speter                goto error;
1077251877Speter            } else if (status && !APR_STATUS_IS_EAGAIN(status)) {
1078251877Speter                /* Read error */
1079251877Speter                goto error;
1080251877Speter            }
1081251877Speter
1082251877Speter            /* Unexpected response from the server */
1083251877Speter
1084251877Speter        }
1085251877Speter
1086251877Speter        /* If the request doesn't have a response bucket, then call the
1087251877Speter         * acceptor to get one created.
1088251877Speter         */
1089251877Speter        if (request->resp_bkt == NULL) {
1090251877Speter            request->resp_bkt = (*request->acceptor)(request, conn->stream,
1091251877Speter                                                     request->acceptor_baton,
1092251877Speter                                                     tmppool);
1093251877Speter            apr_pool_clear(tmppool);
1094251877Speter        }
1095251877Speter
1096251877Speter        status = handle_response(request, tmppool);
1097251877Speter
1098251877Speter        /* Some systems will not generate a HUP poll event so we have to
1099251877Speter         * handle the ECONNRESET issue and ECONNABORT here.
1100251877Speter         */
1101251877Speter        if (APR_STATUS_IS_ECONNRESET(status) ||
1102251877Speter            APR_STATUS_IS_ECONNABORTED(status) ||
1103251877Speter            status == SERF_ERROR_REQUEST_LOST) {
1104251877Speter            /* If the connection had ever been good, be optimistic & try again.
1105251877Speter             * If it has never tried again (incl. a retry), fail.
1106251877Speter             */
1107251877Speter            if (conn->completed_responses) {
1108251877Speter                reset_connection(conn, 1);
1109251877Speter                status = APR_SUCCESS;
1110251877Speter            }
1111251877Speter            else if (status == SERF_ERROR_REQUEST_LOST) {
1112251877Speter                status = SERF_ERROR_ABORTED_CONNECTION;
1113251877Speter            }
1114251877Speter            goto error;
1115251877Speter        }
1116251877Speter
1117251877Speter        /* If our response handler says it can't do anything more, we now
1118251877Speter         * treat that as a success.
1119251877Speter         */
1120251877Speter        if (APR_STATUS_IS_EAGAIN(status)) {
1121251877Speter            status = APR_SUCCESS;
1122251877Speter            goto error;
1123251877Speter        }
1124251877Speter
1125251877Speter        /* If we received APR_SUCCESS, run this loop again. */
1126251877Speter        if (!status) {
1127251877Speter            continue;
1128251877Speter        }
1129251877Speter
1130251877Speter        close_connection = is_conn_closing(request->resp_bkt);
1131251877Speter
1132251877Speter        if (!APR_STATUS_IS_EOF(status) &&
1133251877Speter            close_connection != SERF_ERROR_CLOSING) {
1134251877Speter            /* Whether success, or an error, there is no more to do unless
1135251877Speter             * this request has been completed.
1136251877Speter             */
1137251877Speter            goto error;
1138251877Speter        }
1139251877Speter
1140251877Speter        /* The response has been fully-read, so that means the request has
1141251877Speter         * either been fully-delivered (most likely), or that we don't need to
1142251877Speter         * write the rest of it anymore, e.g. when a 408 Request timeout was
1143251877Speter         $ received.
1144251877Speter         * Remove it from our queue and loop to read another response.
1145251877Speter         */
1146251877Speter        conn->requests = request->next;
1147251877Speter
1148251877Speter        destroy_request(request);
1149251877Speter
1150251877Speter        request = conn->requests;
1151251877Speter
1152251877Speter        /* If we're truly empty, update our tail. */
1153251877Speter        if (request == NULL) {
1154251877Speter            conn->requests_tail = NULL;
1155251877Speter        }
1156251877Speter
1157251877Speter        conn->completed_responses++;
1158251877Speter
1159251877Speter        /* We've to rebuild pollset since completed_responses is changed. */
1160251877Speter        conn->dirty_conn = 1;
1161251877Speter        conn->ctx->dirty_pollset = 1;
1162251877Speter
1163251877Speter        /* This means that we're being advised that the connection is done. */
1164251877Speter        if (close_connection == SERF_ERROR_CLOSING) {
1165251877Speter            reset_connection(conn, 1);
1166251877Speter            if (APR_STATUS_IS_EOF(status))
1167251877Speter                status = APR_SUCCESS;
1168251877Speter            goto error;
1169251877Speter        }
1170251877Speter
1171251877Speter        /* The server is suddenly deciding to serve more responses than we've
1172251877Speter         * seen before.
1173251877Speter         *
1174251877Speter         * Let our requests go.
1175251877Speter         */
1176251877Speter        if (conn->probable_keepalive_limit &&
1177251877Speter            conn->completed_responses > conn->probable_keepalive_limit) {
1178251877Speter            conn->probable_keepalive_limit = 0;
1179251877Speter        }
1180251877Speter
1181251877Speter        /* If we just ran out of requests or have unwritten requests, then
1182251877Speter         * update the pollset. We don't want to read from this socket any
1183251877Speter         * more. We are definitely done with this loop, too.
1184251877Speter         */
1185251877Speter        if (request == NULL || !request->written) {
1186251877Speter            conn->dirty_conn = 1;
1187251877Speter            conn->ctx->dirty_pollset = 1;
1188251877Speter            status = APR_SUCCESS;
1189251877Speter            goto error;
1190251877Speter        }
1191251877Speter    }
1192251877Speter
1193251877Spetererror:
1194251877Speter    apr_pool_destroy(tmppool);
1195251877Speter    return status;
1196251877Speter}
1197251877Speter
1198251877Speter/* process all events on the connection */
1199251877Speterapr_status_t serf__process_connection(serf_connection_t *conn,
1200251877Speter                                      apr_int16_t events)
1201251877Speter{
1202251877Speter    apr_status_t status;
1203251877Speter
1204251877Speter    /* POLLHUP/ERR should come after POLLIN so if there's an error message or
1205251877Speter     * the like sitting on the connection, we give the app a chance to read
1206251877Speter     * it before we trigger a reset condition.
1207251877Speter     */
1208251877Speter    if ((events & APR_POLLIN) != 0) {
1209251877Speter        if ((status = read_from_connection(conn)) != APR_SUCCESS)
1210251877Speter            return status;
1211251877Speter
1212251877Speter        /* If we decided to reset our connection, return now as we don't
1213251877Speter         * want to write.
1214251877Speter         */
1215251877Speter        if ((conn->seen_in_pollset & APR_POLLHUP) != 0) {
1216251877Speter            return APR_SUCCESS;
1217251877Speter        }
1218251877Speter    }
1219251877Speter    if ((events & APR_POLLHUP) != 0) {
1220251877Speter        /* The connection got reset by the server. On Windows this can happen
1221251877Speter           when all data is read, so just cleanup the connection and open
1222251877Speter           a new one.
1223251877Speter           If we haven't had any successful responses on this connection,
1224251877Speter           then error out as it is likely a server issue. */
1225251877Speter        if (conn->completed_responses) {
1226251877Speter            return reset_connection(conn, 1);
1227251877Speter        }
1228251877Speter        return SERF_ERROR_ABORTED_CONNECTION;
1229251877Speter    }
1230251877Speter    if ((events & APR_POLLERR) != 0) {
1231251877Speter        /* We might be talking to a buggy HTTP server that doesn't
1232251877Speter         * do lingering-close.  (httpd < 2.1.8 does this.)
1233251877Speter         *
1234251877Speter         * See:
1235251877Speter         *
1236251877Speter         * http://issues.apache.org/bugzilla/show_bug.cgi?id=35292
1237251877Speter         */
1238251877Speter        if (conn->completed_requests && !conn->probable_keepalive_limit) {
1239251877Speter            return reset_connection(conn, 1);
1240251877Speter        }
1241253895Speter#ifdef SO_ERROR
1242253895Speter        /* If possible, get the error from the platform's socket layer and
1243253895Speter           convert it to an APR status code. */
1244253895Speter        {
1245253895Speter            apr_os_sock_t osskt;
1246253895Speter            if (!apr_os_sock_get(&osskt, conn->skt)) {
1247253895Speter                int error;
1248253895Speter                apr_socklen_t l = sizeof(error);
1249253895Speter
1250253895Speter                if (!getsockopt(osskt, SOL_SOCKET, SO_ERROR, (char*)&error, &l))
1251253895Speter                    return APR_FROM_OS_ERROR(error);
1252253895Speter            }
1253253895Speter        }
1254253895Speter#endif
1255251877Speter        return APR_EGENERAL;
1256251877Speter    }
1257251877Speter    if ((events & APR_POLLOUT) != 0) {
1258251877Speter        if ((status = write_to_connection(conn)) != APR_SUCCESS)
1259251877Speter            return status;
1260251877Speter    }
1261251877Speter    return APR_SUCCESS;
1262251877Speter}
1263251877Speter
1264251877Speterserf_connection_t *serf_connection_create(
1265251877Speter    serf_context_t *ctx,
1266251877Speter    apr_sockaddr_t *address,
1267251877Speter    serf_connection_setup_t setup,
1268251877Speter    void *setup_baton,
1269251877Speter    serf_connection_closed_t closed,
1270251877Speter    void *closed_baton,
1271251877Speter    apr_pool_t *pool)
1272251877Speter{
1273251877Speter    serf_connection_t *conn = apr_pcalloc(pool, sizeof(*conn));
1274251877Speter
1275251877Speter    conn->ctx = ctx;
1276251877Speter    conn->status = APR_SUCCESS;
1277251877Speter    /* Ignore server address if proxy was specified. */
1278251877Speter    conn->address = ctx->proxy_address ? ctx->proxy_address : address;
1279251877Speter    conn->setup = setup;
1280251877Speter    conn->setup_baton = setup_baton;
1281251877Speter    conn->closed = closed;
1282251877Speter    conn->closed_baton = closed_baton;
1283251877Speter    conn->pool = pool;
1284251877Speter    conn->allocator = serf_bucket_allocator_create(pool, NULL, NULL);
1285251877Speter    conn->stream = NULL;
1286251877Speter    conn->ostream_head = NULL;
1287251877Speter    conn->ostream_tail = NULL;
1288251877Speter    conn->baton.type = SERF_IO_CONN;
1289251877Speter    conn->baton.u.conn = conn;
1290251877Speter    conn->hit_eof = 0;
1291251877Speter    conn->state = SERF_CONN_INIT;
1292251877Speter    conn->latency = -1; /* unknown */
1293251877Speter
1294251877Speter    /* Create a subpool for our connection. */
1295251877Speter    apr_pool_create(&conn->skt_pool, conn->pool);
1296251877Speter
1297251877Speter    /* register a cleanup */
1298253895Speter    apr_pool_cleanup_register(conn->pool, conn, clean_conn,
1299253895Speter                              apr_pool_cleanup_null);
1300251877Speter
1301251877Speter    /* Add the connection to the context. */
1302251877Speter    *(serf_connection_t **)apr_array_push(ctx->conns) = conn;
1303251877Speter
1304251877Speter    serf__log(CONN_VERBOSE, __FILE__, "created connection 0x%x\n",
1305251877Speter              conn);
1306251877Speter
1307251877Speter    return conn;
1308251877Speter}
1309251877Speter
1310251877Speterapr_status_t serf_connection_create2(
1311251877Speter    serf_connection_t **conn,
1312251877Speter    serf_context_t *ctx,
1313251877Speter    apr_uri_t host_info,
1314251877Speter    serf_connection_setup_t setup,
1315251877Speter    void *setup_baton,
1316251877Speter    serf_connection_closed_t closed,
1317251877Speter    void *closed_baton,
1318251877Speter    apr_pool_t *pool)
1319251877Speter{
1320251877Speter    apr_status_t status = APR_SUCCESS;
1321251877Speter    serf_connection_t *c;
1322251877Speter    apr_sockaddr_t *host_address = NULL;
1323251877Speter
1324251877Speter    /* Set the port number explicitly, needed to create the socket later. */
1325251877Speter    if (!host_info.port) {
1326251877Speter        host_info.port = apr_uri_port_of_scheme(host_info.scheme);
1327251877Speter    }
1328251877Speter
1329251877Speter    /* Only lookup the address of the server if no proxy server was
1330251877Speter       configured. */
1331251877Speter    if (!ctx->proxy_address) {
1332251877Speter        status = apr_sockaddr_info_get(&host_address,
1333251877Speter                                       host_info.hostname,
1334251877Speter                                       APR_UNSPEC, host_info.port, 0, pool);
1335251877Speter        if (status)
1336251877Speter            return status;
1337251877Speter    }
1338251877Speter
1339251877Speter    c = serf_connection_create(ctx, host_address, setup, setup_baton,
1340251877Speter                               closed, closed_baton, pool);
1341251877Speter
1342251877Speter    /* We're not interested in the path following the hostname. */
1343251877Speter    c->host_url = apr_uri_unparse(c->pool,
1344251877Speter                                  &host_info,
1345251877Speter                                  APR_URI_UNP_OMITPATHINFO);
1346251877Speter
1347253895Speter    /* Store the host info without the path on the connection. */
1348253895Speter    (void)apr_uri_parse(c->pool, c->host_url, &(c->host_info));
1349253895Speter    if (!c->host_info.port) {
1350253895Speter        c->host_info.port = apr_uri_port_of_scheme(c->host_info.scheme);
1351253895Speter    }
1352253895Speter
1353251877Speter    *conn = c;
1354251877Speter
1355251877Speter    return status;
1356251877Speter}
1357251877Speter
1358251877Speterapr_status_t serf_connection_reset(
1359251877Speter    serf_connection_t *conn)
1360251877Speter{
1361251877Speter    return reset_connection(conn, 0);
1362251877Speter}
1363251877Speter
1364251877Speter
1365251877Speterapr_status_t serf_connection_close(
1366251877Speter    serf_connection_t *conn)
1367251877Speter{
1368251877Speter    int i;
1369251877Speter    serf_context_t *ctx = conn->ctx;
1370251877Speter    apr_status_t status;
1371251877Speter
1372251877Speter    for (i = ctx->conns->nelts; i--; ) {
1373251877Speter        serf_connection_t *conn_seq = GET_CONN(ctx, i);
1374251877Speter
1375251877Speter        if (conn_seq == conn) {
1376251877Speter            while (conn->requests) {
1377251877Speter                serf_request_cancel(conn->requests);
1378251877Speter            }
1379251877Speter            if (conn->skt != NULL) {
1380251877Speter                remove_connection(ctx, conn);
1381251877Speter                status = apr_socket_close(conn->skt);
1382251877Speter                serf__log_skt(SOCK_VERBOSE, __FILE__, conn->skt,
1383251877Speter                              "closed socket, status %d\n",
1384251877Speter                              status);
1385251877Speter                if (conn->closed != NULL) {
1386251877Speter                    handle_conn_closed(conn, status);
1387251877Speter                }
1388251877Speter                conn->skt = NULL;
1389251877Speter            }
1390251877Speter            if (conn->stream != NULL) {
1391251877Speter                serf_bucket_destroy(conn->stream);
1392251877Speter                conn->stream = NULL;
1393251877Speter            }
1394251877Speter
1395251877Speter            destroy_ostream(conn);
1396251877Speter
1397251877Speter            /* Remove the connection from the context. We don't want to
1398251877Speter             * deal with it any more.
1399251877Speter             */
1400251877Speter            if (i < ctx->conns->nelts - 1) {
1401251877Speter                /* move later connections over this one. */
1402251877Speter                memmove(
1403251877Speter                    &GET_CONN(ctx, i),
1404251877Speter                    &GET_CONN(ctx, i + 1),
1405251877Speter                    (ctx->conns->nelts - i - 1) * sizeof(serf_connection_t *));
1406251877Speter            }
1407251877Speter            --ctx->conns->nelts;
1408251877Speter
1409251877Speter            serf__log(CONN_VERBOSE, __FILE__, "closed connection 0x%x\n",
1410251877Speter                      conn);
1411251877Speter
1412251877Speter            /* Found the connection. Closed it. All done. */
1413251877Speter            return APR_SUCCESS;
1414251877Speter        }
1415251877Speter    }
1416251877Speter
1417251877Speter    /* We didn't find the specified connection. */
1418251877Speter    /* ### doc talks about this w.r.t poll structures. use something else? */
1419251877Speter    return APR_NOTFOUND;
1420251877Speter}
1421251877Speter
1422251877Speter
1423251877Spetervoid serf_connection_set_max_outstanding_requests(
1424251877Speter    serf_connection_t *conn,
1425251877Speter    unsigned int max_requests)
1426251877Speter{
1427251877Speter    if (max_requests == 0)
1428251877Speter        serf__log_skt(CONN_VERBOSE, __FILE__, conn->skt,
1429251877Speter                      "Set max. nr. of outstanding requests for this "
1430251877Speter                      "connection to unlimited.\n");
1431251877Speter    else
1432251877Speter        serf__log_skt(CONN_VERBOSE, __FILE__, conn->skt,
1433251877Speter                      "Limit max. nr. of outstanding requests for this "
1434251877Speter                      "connection to %u.\n", max_requests);
1435251877Speter
1436251877Speter    conn->max_outstanding_requests = max_requests;
1437251877Speter}
1438251877Speter
1439251877Speter
1440251877Spetervoid serf_connection_set_async_responses(
1441251877Speter    serf_connection_t *conn,
1442251877Speter    serf_response_acceptor_t acceptor,
1443251877Speter    void *acceptor_baton,
1444251877Speter    serf_response_handler_t handler,
1445251877Speter    void *handler_baton)
1446251877Speter{
1447251877Speter    conn->async_responses = 1;
1448251877Speter    conn->async_acceptor = acceptor;
1449251877Speter    conn->async_acceptor_baton = acceptor_baton;
1450251877Speter    conn->async_handler = handler;
1451251877Speter    conn->async_handler_baton = handler_baton;
1452251877Speter}
1453251877Speter
1454253895Speterstatic serf_request_t *
1455253895Spetercreate_request(serf_connection_t *conn,
1456253895Speter               serf_request_setup_t setup,
1457253895Speter               void *setup_baton,
1458253895Speter               int priority,
1459253895Speter               int ssltunnel)
1460251877Speter{
1461251877Speter    serf_request_t *request;
1462251877Speter
1463251877Speter    request = serf_bucket_mem_alloc(conn->allocator, sizeof(*request));
1464251877Speter    request->conn = conn;
1465251877Speter    request->setup = setup;
1466251877Speter    request->setup_baton = setup_baton;
1467251877Speter    request->handler = NULL;
1468251877Speter    request->respool = NULL;
1469251877Speter    request->req_bkt = NULL;
1470251877Speter    request->resp_bkt = NULL;
1471253895Speter    request->priority = priority;
1472251877Speter    request->written = 0;
1473253895Speter    request->ssltunnel = ssltunnel;
1474251877Speter    request->next = NULL;
1475251877Speter
1476253895Speter    return request;
1477253895Speter}
1478253895Speter
1479253895Speterserf_request_t *serf_connection_request_create(
1480253895Speter    serf_connection_t *conn,
1481253895Speter    serf_request_setup_t setup,
1482253895Speter    void *setup_baton)
1483253895Speter{
1484253895Speter    serf_request_t *request;
1485253895Speter
1486253895Speter    request = create_request(conn, setup, setup_baton,
1487253895Speter                             0, /* priority */
1488253895Speter                             0  /* ssl tunnel */);
1489253895Speter
1490251877Speter    /* Link the request to the end of the request chain. */
1491251877Speter    link_requests(&conn->requests, &conn->requests_tail, request);
1492251877Speter
1493251877Speter    /* Ensure our pollset becomes writable in context run */
1494251877Speter    conn->ctx->dirty_pollset = 1;
1495251877Speter    conn->dirty_conn = 1;
1496251877Speter
1497251877Speter    return request;
1498251877Speter}
1499251877Speter
1500253895Speterstatic serf_request_t *
1501253895Speterpriority_request_create(serf_connection_t *conn,
1502253895Speter                        int ssltunnelreq,
1503253895Speter                        serf_request_setup_t setup,
1504253895Speter                        void *setup_baton)
1505251877Speter{
1506251877Speter    serf_request_t *request;
1507251877Speter    serf_request_t *iter, *prev;
1508251877Speter
1509253895Speter    request = create_request(conn, setup, setup_baton,
1510253895Speter                             1, /* priority */
1511253895Speter                             ssltunnelreq);
1512251877Speter
1513251877Speter    /* Link the new request after the last written request. */
1514251877Speter    iter = conn->requests;
1515251877Speter    prev = NULL;
1516251877Speter
1517251877Speter    /* Find a request that has data which needs to be delivered. */
1518251877Speter    while (iter != NULL && iter->req_bkt == NULL && iter->written) {
1519251877Speter        prev = iter;
1520251877Speter        iter = iter->next;
1521251877Speter    }
1522251877Speter
1523253895Speter    /* A CONNECT request to setup an ssltunnel has absolute priority over all
1524253895Speter       other requests on the connection, so:
1525253895Speter       a. add it first to the queue
1526253895Speter       b. ensure that other priority requests are added after the CONNECT
1527253895Speter          request */
1528253895Speter    if (!request->ssltunnel) {
1529253895Speter        /* Advance to next non priority request */
1530253895Speter        while (iter != NULL && iter->priority) {
1531253895Speter            prev = iter;
1532253895Speter            iter = iter->next;
1533253895Speter        }
1534251877Speter    }
1535251877Speter
1536251877Speter    if (prev) {
1537251877Speter        request->next = iter;
1538251877Speter        prev->next = request;
1539251877Speter    } else {
1540251877Speter        request->next = iter;
1541251877Speter        conn->requests = request;
1542251877Speter    }
1543251877Speter
1544251877Speter    /* Ensure our pollset becomes writable in context run */
1545251877Speter    conn->ctx->dirty_pollset = 1;
1546251877Speter    conn->dirty_conn = 1;
1547251877Speter
1548251877Speter    return request;
1549251877Speter}
1550251877Speter
1551253895Speterserf_request_t *serf_connection_priority_request_create(
1552253895Speter    serf_connection_t *conn,
1553253895Speter    serf_request_setup_t setup,
1554253895Speter    void *setup_baton)
1555253895Speter{
1556253895Speter    return priority_request_create(conn,
1557253895Speter                                   0, /* not a ssltunnel CONNECT request */
1558253895Speter                                   setup, setup_baton);
1559253895Speter}
1560251877Speter
1561253895Speterserf_request_t *serf__ssltunnel_request_create(serf_connection_t *conn,
1562253895Speter                                               serf_request_setup_t setup,
1563253895Speter                                               void *setup_baton)
1564253895Speter{
1565253895Speter    return priority_request_create(conn,
1566253895Speter                                   1, /* This is a ssltunnel CONNECT request */
1567253895Speter                                   setup, setup_baton);
1568253895Speter}
1569253895Speter
1570251877Speterapr_status_t serf_request_cancel(serf_request_t *request)
1571251877Speter{
1572251877Speter    return cancel_request(request, &request->conn->requests, 0);
1573251877Speter}
1574251877Speter
1575251877Speterapr_status_t serf_request_is_written(serf_request_t *request)
1576251877Speter{
1577251877Speter    if (request->written && !request->req_bkt)
1578251877Speter        return APR_SUCCESS;
1579251877Speter
1580251877Speter    return APR_EBUSY;
1581251877Speter}
1582251877Speter
1583251877Speterapr_pool_t *serf_request_get_pool(const serf_request_t *request)
1584251877Speter{
1585251877Speter    return request->respool;
1586251877Speter}
1587251877Speter
1588251877Speter
1589251877Speterserf_bucket_alloc_t *serf_request_get_alloc(
1590251877Speter    const serf_request_t *request)
1591251877Speter{
1592251877Speter    return request->allocator;
1593251877Speter}
1594251877Speter
1595251877Speter
1596251877Speterserf_connection_t *serf_request_get_conn(
1597251877Speter    const serf_request_t *request)
1598251877Speter{
1599251877Speter    return request->conn;
1600251877Speter}
1601251877Speter
1602251877Speter
1603251877Spetervoid serf_request_set_handler(
1604251877Speter    serf_request_t *request,
1605251877Speter    const serf_response_handler_t handler,
1606251877Speter    const void **handler_baton)
1607251877Speter{
1608251877Speter    request->handler = handler;
1609251877Speter    request->handler_baton = handler_baton;
1610251877Speter}
1611251877Speter
1612251877Speter
1613251877Speterserf_bucket_t *serf_request_bucket_request_create(
1614251877Speter    serf_request_t *request,
1615251877Speter    const char *method,
1616251877Speter    const char *uri,
1617251877Speter    serf_bucket_t *body,
1618251877Speter    serf_bucket_alloc_t *allocator)
1619251877Speter{
1620251877Speter    serf_bucket_t *req_bkt, *hdrs_bkt;
1621251877Speter    serf_connection_t *conn = request->conn;
1622251877Speter    serf_context_t *ctx = conn->ctx;
1623253895Speter    int ssltunnel;
1624251877Speter
1625253895Speter    ssltunnel = ctx->proxy_address &&
1626253895Speter                (strcmp(conn->host_info.scheme, "https") == 0);
1627253895Speter
1628251877Speter    req_bkt = serf_bucket_request_create(method, uri, body, allocator);
1629251877Speter    hdrs_bkt = serf_bucket_request_get_headers(req_bkt);
1630251877Speter
1631253895Speter    /* Use absolute uri's in requests to a proxy. USe relative uri's in
1632253895Speter       requests directly to a server or sent through an SSL tunnel. */
1633253895Speter    if (ctx->proxy_address && conn->host_url &&
1634253895Speter        !(ssltunnel && !request->ssltunnel)) {
1635253895Speter
1636251877Speter        serf_bucket_request_set_root(req_bkt, conn->host_url);
1637253895Speter    }
1638251877Speter
1639251877Speter    if (conn->host_info.hostinfo)
1640251877Speter        serf_bucket_headers_setn(hdrs_bkt, "Host",
1641251877Speter                                 conn->host_info.hostinfo);
1642251877Speter
1643253895Speter    /* Setup server authorization headers, unless this is a CONNECT request. */
1644253895Speter    if (!request->ssltunnel) {
1645253895Speter        serf__authn_info_t *authn_info;
1646253895Speter        authn_info = serf__get_authn_info_for_server(conn);
1647253895Speter        if (authn_info->scheme)
1648253895Speter            authn_info->scheme->setup_request_func(HOST, 0, conn, request,
1649251877Speter                                                   method, uri,
1650251877Speter                                                   hdrs_bkt);
1651253895Speter    }
1652251877Speter
1653253895Speter    /* Setup proxy authorization headers.
1654253895Speter       Don't set these headers on the requests to the server if we're using
1655253895Speter       an SSL tunnel, only on the CONNECT request to setup the tunnel. */
1656253895Speter    if (ctx->proxy_authn_info.scheme) {
1657253895Speter        if (strcmp(conn->host_info.scheme, "https") == 0) {
1658253895Speter            if (request->ssltunnel)
1659253895Speter                ctx->proxy_authn_info.scheme->setup_request_func(PROXY, 0, conn,
1660253895Speter                                                                 request,
1661253895Speter                                                                 method, uri,
1662253895Speter                                                                 hdrs_bkt);
1663253895Speter        } else {
1664253895Speter            ctx->proxy_authn_info.scheme->setup_request_func(PROXY, 0, conn,
1665253895Speter                                                             request,
1666253895Speter                                                             method, uri,
1667253895Speter                                                             hdrs_bkt);
1668253895Speter        }
1669253895Speter    }
1670251877Speter
1671251877Speter    return req_bkt;
1672251877Speter}
1673251877Speter
1674251877Speterapr_interval_time_t serf_connection_get_latency(serf_connection_t *conn)
1675251877Speter{
1676251877Speter    if (conn->ctx->proxy_address) {
1677251877Speter        /* Detecting network latency for proxied connection is not implemented
1678251877Speter           yet. */
1679251877Speter        return -1;
1680251877Speter    }
1681251877Speter
1682251877Speter    return conn->latency;
1683251877Speter}
1684