1/* ====================================================================
2 *    Licensed to the Apache Software Foundation (ASF) under one
3 *    or more contributor license agreements.  See the NOTICE file
4 *    distributed with this work for additional information
5 *    regarding copyright ownership.  The ASF licenses this file
6 *    to you under the Apache License, Version 2.0 (the
7 *    "License"); you may not use this file except in compliance
8 *    with the License.  You may obtain a copy of the License at
9 *
10 *      http://www.apache.org/licenses/LICENSE-2.0
11 *
12 *    Unless required by applicable law or agreed to in writing,
13 *    software distributed under the License is distributed on an
14 *    "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15 *    KIND, either express or implied.  See the License for the
16 *    specific language governing permissions and limitations
17 *    under the License.
18 * ====================================================================
19 */
20
21#include <apr_pools.h>
22#include <apr_poll.h>
23#include <apr_version.h>
24#include <apr_portable.h>
25
26#include "serf.h"
27#include "serf_bucket_util.h"
28
29#include "serf_private.h"
30
31/* cleanup for sockets */
32static apr_status_t clean_skt(void *data)
33{
34    serf_connection_t *conn = data;
35    apr_status_t status = APR_SUCCESS;
36
37    if (conn->skt) {
38        serf__log_skt(SOCK_VERBOSE, __FILE__, conn->skt, "cleanup - ");
39        status = apr_socket_close(conn->skt);
40        conn->skt = NULL;
41        serf__log_nopref(SOCK_VERBOSE, "closed socket, status %d\n", status);
42    }
43
44    return status;
45}
46
47static apr_status_t clean_resp(void *data)
48{
49    serf_request_t *request = data;
50
51    /* The request's RESPOOL is being cleared.  */
52
53    /* If the response has allocated some buckets, then destroy them (since
54       the bucket may hold resources other than memory in RESPOOL). Also
55       make sure to set their fields to NULL so connection closure does
56       not attempt to free them again.  */
57    if (request->resp_bkt) {
58        serf_bucket_destroy(request->resp_bkt);
59        request->resp_bkt = NULL;
60    }
61    if (request->req_bkt) {
62        serf_bucket_destroy(request->req_bkt);
63        request->req_bkt = NULL;
64    }
65
66    /* ### should we worry about debug stuff, like that performed in
67       ### destroy_request()? should we worry about calling req->handler
68       ### to notify this "cancellation" due to pool clearing?  */
69
70    /* This pool just got cleared/destroyed. Don't try to destroy the pool
71       (again) when the request is canceled.  */
72    request->respool = NULL;
73
74    return APR_SUCCESS;
75}
76
77/* cleanup for conns */
78static apr_status_t clean_conn(void *data)
79{
80    serf_connection_t *conn = data;
81
82    serf__log(CONN_VERBOSE, __FILE__, "cleaning up connection 0x%x\n",
83              conn);
84    serf_connection_close(conn);
85
86    return APR_SUCCESS;
87}
88
89/* Check if there is data waiting to be sent over the socket. This can happen
90   in two situations:
91   - The connection queue has atleast one request with unwritten data.
92   - All requests are written and the ssl layer wrote some data while reading
93     the response. This can happen when the server triggers a renegotiation,
94     e.g. after the first and only request on that connection was received.
95   Returns 1 if data is pending on CONN, NULL if not.
96   If NEXT_REQ is not NULL, it will be filled in with the next available request
97   with unwritten data. */
98static int
99request_or_data_pending(serf_request_t **next_req, serf_connection_t *conn)
100{
101    serf_request_t *request = conn->requests;
102
103    while (request != NULL && request->req_bkt == NULL &&
104           request->writing_started)
105        request = request->next;
106
107    if (next_req)
108        *next_req = request;
109
110    if (request != NULL) {
111        return 1;
112    } else if (conn->ostream_head) {
113        const char *dummy;
114        apr_size_t len;
115        apr_status_t status;
116
117        status = serf_bucket_peek(conn->ostream_head, &dummy,
118                                  &len);
119        if (!SERF_BUCKET_READ_ERROR(status) && len) {
120            serf__log_skt(CONN_VERBOSE, __FILE__, conn->skt,
121                          "All requests written but still data pending.\n");
122            return 1;
123        }
124    }
125
126    return 0;
127}
128
129/* Update the pollset for this connection. We tweak the pollset based on
130 * whether we want to read and/or write, given conditions within the
131 * connection. If the connection is not (yet) in the pollset, then it
132 * will be added.
133 */
134apr_status_t serf__conn_update_pollset(serf_connection_t *conn)
135{
136    serf_context_t *ctx = conn->ctx;
137    apr_status_t status;
138    apr_pollfd_t desc = { 0 };
139
140    if (!conn->skt) {
141        return APR_SUCCESS;
142    }
143
144    /* Remove the socket from the poll set. */
145    desc.desc_type = APR_POLL_SOCKET;
146    desc.desc.s = conn->skt;
147    desc.reqevents = conn->reqevents;
148
149    status = ctx->pollset_rm(ctx->pollset_baton,
150                             &desc, &conn->baton);
151    if (status && !APR_STATUS_IS_NOTFOUND(status))
152        return status;
153
154    /* Now put it back in with the correct read/write values. */
155    desc.reqevents = APR_POLLHUP | APR_POLLERR;
156    if (conn->requests &&
157        conn->state != SERF_CONN_INIT) {
158        /* If there are any outstanding events, then we want to read. */
159        /* ### not true. we only want to read IF we have sent some data */
160        desc.reqevents |= APR_POLLIN;
161
162        /* Don't write if OpenSSL told us that it needs to read data first. */
163        if (conn->stop_writing != 1) {
164
165            /* If the connection is not closing down and
166             *   has unwritten data or
167             *   there are any requests that still have buckets to write out,
168             *     then we want to write.
169             */
170            if (conn->vec_len &&
171                conn->state != SERF_CONN_CLOSING)
172                desc.reqevents |= APR_POLLOUT;
173            else {
174
175                if ((conn->probable_keepalive_limit &&
176                     conn->completed_requests > conn->probable_keepalive_limit) ||
177                    (conn->max_outstanding_requests &&
178                     conn->completed_requests - conn->completed_responses >=
179                     conn->max_outstanding_requests)) {
180                        /* we wouldn't try to write any way right now. */
181                }
182                else if (request_or_data_pending(NULL, conn)) {
183                    desc.reqevents |= APR_POLLOUT;
184                }
185            }
186        }
187    }
188
189    /* If we can have async responses, always look for something to read. */
190    if (conn->async_responses) {
191        desc.reqevents |= APR_POLLIN;
192    }
193
194    /* save our reqevents, so we can pass it in to remove later. */
195    conn->reqevents = desc.reqevents;
196
197    /* Note: even if we don't want to read/write this socket, we still
198     * want to poll it for hangups and errors.
199     */
200    return ctx->pollset_add(ctx->pollset_baton,
201                            &desc, &conn->baton);
202}
203
204#ifdef SERF_DEBUG_BUCKET_USE
205
206/* Make sure all response buckets were drained. */
207static void check_buckets_drained(serf_connection_t *conn)
208{
209    serf_request_t *request = conn->requests;
210
211    for ( ; request ; request = request->next ) {
212        if (request->resp_bkt != NULL) {
213            /* ### crap. can't do this. this allocator may have un-drained
214             * ### REQUEST buckets.
215             */
216            /* serf_debug__entered_loop(request->resp_bkt->allocator); */
217            /* ### for now, pretend we closed the conn (resets the tracking) */
218            serf_debug__closed_conn(request->resp_bkt->allocator);
219        }
220    }
221}
222
223#endif
224
225static void destroy_ostream(serf_connection_t *conn)
226{
227    if (conn->ostream_head != NULL) {
228        serf_bucket_destroy(conn->ostream_head);
229        conn->ostream_head = NULL;
230        conn->ostream_tail = NULL;
231    }
232}
233
234static apr_status_t detect_eof(void *baton, serf_bucket_t *aggregate_bucket)
235{
236    serf_connection_t *conn = baton;
237    conn->hit_eof = 1;
238    return APR_EAGAIN;
239}
240
241static apr_status_t do_conn_setup(serf_connection_t *conn)
242{
243    apr_status_t status;
244    serf_bucket_t *ostream;
245
246    if (conn->ostream_head == NULL) {
247        conn->ostream_head = serf_bucket_aggregate_create(conn->allocator);
248    }
249
250    if (conn->ostream_tail == NULL) {
251        conn->ostream_tail = serf__bucket_stream_create(conn->allocator,
252                                                        detect_eof,
253                                                        conn);
254    }
255
256    ostream = conn->ostream_tail;
257
258    status = (*conn->setup)(conn->skt,
259                            &conn->stream,
260                            &ostream,
261                            conn->setup_baton,
262                            conn->pool);
263    if (status) {
264        /* extra destroy here since it wasn't added to the head bucket yet. */
265        serf_bucket_destroy(conn->ostream_tail);
266        destroy_ostream(conn);
267        return status;
268    }
269
270    serf_bucket_aggregate_append(conn->ostream_head,
271                                 ostream);
272
273    return status;
274}
275
276/* Set up the input and output stream buckets.
277 When a tunnel over an http proxy is needed, create a socket bucket and
278 empty aggregate bucket for sending and receiving unencrypted requests
279 over the socket.
280
281 After the tunnel is there, or no tunnel was needed, ask the application
282 to create the input and output buckets, which should take care of the
283 [en/de]cryption.
284 */
285
286static apr_status_t prepare_conn_streams(serf_connection_t *conn,
287                                         serf_bucket_t **istream,
288                                         serf_bucket_t **ostreamt,
289                                         serf_bucket_t **ostreamh)
290{
291    apr_status_t status;
292
293    if (conn->stream == NULL) {
294        conn->latency = apr_time_now() - conn->connect_time;
295    }
296
297    /* Do we need a SSL tunnel first? */
298    if (conn->state == SERF_CONN_CONNECTED) {
299        /* If the connection does not have an associated bucket, then
300         * call the setup callback to get one.
301         */
302        if (conn->stream == NULL) {
303            status = do_conn_setup(conn);
304            if (status) {
305                return status;
306            }
307        }
308        *ostreamt = conn->ostream_tail;
309        *ostreamh = conn->ostream_head;
310        *istream = conn->stream;
311    } else {
312        /* SSL tunnel needed and not set up yet, get a direct unencrypted
313         stream for this socket */
314        if (conn->stream == NULL) {
315            *istream = serf_bucket_socket_create(conn->skt,
316                                                 conn->allocator);
317        }
318        /* Don't create the ostream bucket chain including the ssl_encrypt
319         bucket yet. This ensure the CONNECT request is sent unencrypted
320         to the proxy. */
321        *ostreamt = *ostreamh = conn->ssltunnel_ostream;
322    }
323
324    return APR_SUCCESS;
325}
326
327/* Create and connect sockets for any connections which don't have them
328 * yet. This is the core of our lazy-connect behavior.
329 */
330apr_status_t serf__open_connections(serf_context_t *ctx)
331{
332    int i;
333
334    for (i = ctx->conns->nelts; i--; ) {
335        serf_connection_t *conn = GET_CONN(ctx, i);
336        serf__authn_info_t *authn_info;
337        apr_status_t status;
338        apr_socket_t *skt;
339
340        conn->seen_in_pollset = 0;
341
342        if (conn->skt != NULL) {
343#ifdef SERF_DEBUG_BUCKET_USE
344            check_buckets_drained(conn);
345#endif
346            continue;
347        }
348
349        /* Delay opening until we have something to deliver! */
350        if (conn->requests == NULL) {
351            continue;
352        }
353
354        apr_pool_clear(conn->skt_pool);
355        apr_pool_cleanup_register(conn->skt_pool, conn, clean_skt, clean_skt);
356
357        status = apr_socket_create(&skt, conn->address->family,
358                                   SOCK_STREAM,
359#if APR_MAJOR_VERSION > 0
360                                   APR_PROTO_TCP,
361#endif
362                                   conn->skt_pool);
363        serf__log(SOCK_VERBOSE, __FILE__,
364                  "created socket for conn 0x%x, status %d\n", conn, status);
365        if (status != APR_SUCCESS)
366            return status;
367
368        /* Set the socket to be non-blocking */
369        if ((status = apr_socket_timeout_set(skt, 0)) != APR_SUCCESS)
370            return status;
371
372        /* Disable Nagle's algorithm */
373        if ((status = apr_socket_opt_set(skt,
374                                         APR_TCP_NODELAY, 1)) != APR_SUCCESS)
375            return status;
376
377        /* Configured. Store it into the connection now. */
378        conn->skt = skt;
379
380        /* Remember time when we started connecting to server to calculate
381           network latency. */
382        conn->connect_time = apr_time_now();
383
384        /* Now that the socket is set up, let's connect it. This should
385         * return immediately.
386         */
387        status = apr_socket_connect(skt, conn->address);
388        serf__log_skt(SOCK_VERBOSE, __FILE__, skt,
389                      "connected socket for conn 0x%x, status %d\n",
390                      conn, status);
391        if (status != APR_SUCCESS) {
392            if (!APR_STATUS_IS_EINPROGRESS(status))
393                return status;
394        }
395
396        /* Flag our pollset as dirty now that we have a new socket. */
397        conn->dirty_conn = 1;
398        ctx->dirty_pollset = 1;
399
400        /* If the authentication was already started on another connection,
401           prepare this connection (it might be possible to skip some
402           part of the handshaking). */
403        if (ctx->proxy_address) {
404            authn_info = &ctx->proxy_authn_info;
405            if (authn_info->scheme) {
406                authn_info->scheme->init_conn_func(authn_info->scheme, 407,
407                                                   conn, conn->pool);
408            }
409        }
410
411        authn_info = serf__get_authn_info_for_server(conn);
412        if (authn_info->scheme) {
413            authn_info->scheme->init_conn_func(authn_info->scheme, 401,
414                                               conn, conn->pool);
415        }
416
417        /* Does this connection require a SSL tunnel over the proxy? */
418        if (ctx->proxy_address && strcmp(conn->host_info.scheme, "https") == 0)
419            serf__ssltunnel_connect(conn);
420        else {
421            serf_bucket_t *dummy1, *dummy2;
422
423            conn->state = SERF_CONN_CONNECTED;
424
425            status = prepare_conn_streams(conn, &conn->stream,
426                                          &dummy1, &dummy2);
427            if (status) {
428                return status;
429            }
430        }
431    }
432
433    return APR_SUCCESS;
434}
435
436static apr_status_t no_more_writes(serf_connection_t *conn)
437{
438    /* Note that we should hold new requests until we open our new socket. */
439    conn->state = SERF_CONN_CLOSING;
440    serf__log_skt(CONN_VERBOSE, __FILE__, conn->skt,
441                  "stop writing on conn 0x%x\n", conn);
442
443    /* Clear our iovec. */
444    conn->vec_len = 0;
445
446    /* Update the pollset to know we don't want to write on this socket any
447     * more.
448     */
449    conn->dirty_conn = 1;
450    conn->ctx->dirty_pollset = 1;
451    return APR_SUCCESS;
452}
453
454/* Read the 'Connection' header from the response. Return SERF_ERROR_CLOSING if
455 * the header contains value 'close' indicating the server is closing the
456 * connection right after this response.
457 * Otherwise returns APR_SUCCESS.
458 */
459static apr_status_t is_conn_closing(serf_bucket_t *response)
460{
461    serf_bucket_t *hdrs;
462    const char *val;
463
464    hdrs = serf_bucket_response_get_headers(response);
465    val = serf_bucket_headers_get(hdrs, "Connection");
466    if (val && strcasecmp("close", val) == 0)
467        {
468            return SERF_ERROR_CLOSING;
469        }
470
471    return APR_SUCCESS;
472}
473
474static void link_requests(serf_request_t **list, serf_request_t **tail,
475                          serf_request_t *request)
476{
477    if (*list == NULL) {
478        *list = request;
479        *tail = request;
480    }
481    else {
482        (*tail)->next = request;
483        *tail = request;
484    }
485}
486
487static apr_status_t destroy_request(serf_request_t *request)
488{
489    serf_connection_t *conn = request->conn;
490
491    /* The request and response buckets are no longer needed,
492       nor is the request's pool.  */
493    if (request->resp_bkt) {
494        serf_debug__closed_conn(request->resp_bkt->allocator);
495        serf_bucket_destroy(request->resp_bkt);
496        request->resp_bkt = NULL;
497    }
498    if (request->req_bkt) {
499        serf_debug__closed_conn(request->req_bkt->allocator);
500        serf_bucket_destroy(request->req_bkt);
501        request->req_bkt = NULL;
502    }
503
504    serf_debug__bucket_alloc_check(request->allocator);
505    if (request->respool) {
506        /* ### unregister the pool cleanup for self?  */
507        apr_pool_destroy(request->respool);
508    }
509
510    serf_bucket_mem_free(conn->allocator, request);
511
512    return APR_SUCCESS;
513}
514
515static apr_status_t cancel_request(serf_request_t *request,
516                                   serf_request_t **list,
517                                   int notify_request)
518{
519    /* If we haven't run setup, then we won't have a handler to call. */
520    if (request->handler && notify_request) {
521        /* We actually don't care what the handler returns.
522         * We have bigger matters at hand.
523         */
524        (*request->handler)(request, NULL, request->handler_baton,
525                            request->respool);
526    }
527
528    if (*list == request) {
529        *list = request->next;
530    }
531    else {
532        serf_request_t *scan = *list;
533
534        while (scan->next && scan->next != request)
535            scan = scan->next;
536
537        if (scan->next) {
538            scan->next = scan->next->next;
539        }
540    }
541
542    return destroy_request(request);
543}
544
545static apr_status_t remove_connection(serf_context_t *ctx,
546                                      serf_connection_t *conn)
547{
548    apr_pollfd_t desc = { 0 };
549
550    desc.desc_type = APR_POLL_SOCKET;
551    desc.desc.s = conn->skt;
552    desc.reqevents = conn->reqevents;
553
554    return ctx->pollset_rm(ctx->pollset_baton,
555                           &desc, &conn->baton);
556}
557
558/* A socket was closed, inform the application. */
559static void handle_conn_closed(serf_connection_t *conn, apr_status_t status)
560{
561    (*conn->closed)(conn, conn->closed_baton, status,
562                    conn->pool);
563}
564
565static apr_status_t reset_connection(serf_connection_t *conn,
566                                     int requeue_requests)
567{
568    serf_context_t *ctx = conn->ctx;
569    apr_status_t status;
570    serf_request_t *old_reqs;
571
572    conn->probable_keepalive_limit = conn->completed_responses;
573    conn->completed_requests = 0;
574    conn->completed_responses = 0;
575
576    old_reqs = conn->requests;
577
578    conn->requests = NULL;
579    conn->requests_tail = NULL;
580
581    /* Handle all outstanding requests. These have either not been written yet,
582       or have been written but the expected reply wasn't received yet. */
583    while (old_reqs) {
584        /* If we haven't started to write the connection, bring it over
585         * unchanged to our new socket.
586         * Do not copy a CONNECT request to the new connection, the ssl tunnel
587         * setup code will create a new CONNECT request already.
588         */
589        if (requeue_requests && !old_reqs->writing_started &&
590            !old_reqs->ssltunnel) {
591
592            serf_request_t *req = old_reqs;
593            old_reqs = old_reqs->next;
594            req->next = NULL;
595            link_requests(&conn->requests, &conn->requests_tail, req);
596        }
597        else {
598            /* Request has been consumed, or we don't want to requeue the
599               request. Either way, inform the application that the request
600               is cancelled. */
601            cancel_request(old_reqs, &old_reqs, requeue_requests);
602        }
603    }
604
605    /* Requests queue has been prepared for a new socket, close the old one. */
606    if (conn->skt != NULL) {
607        remove_connection(ctx, conn);
608        status = apr_socket_close(conn->skt);
609        serf__log_skt(SOCK_VERBOSE, __FILE__, conn->skt,
610                      "closed socket, status %d\n", status);
611        if (conn->closed != NULL) {
612            handle_conn_closed(conn, status);
613        }
614        conn->skt = NULL;
615    }
616
617    if (conn->stream != NULL) {
618        serf_bucket_destroy(conn->stream);
619        conn->stream = NULL;
620    }
621
622    destroy_ostream(conn);
623
624    /* Don't try to resume any writes */
625    conn->vec_len = 0;
626
627    conn->dirty_conn = 1;
628    conn->ctx->dirty_pollset = 1;
629    conn->state = SERF_CONN_INIT;
630
631    conn->hit_eof = 0;
632    conn->connect_time = 0;
633    conn->latency = -1;
634    conn->stop_writing = 0;
635
636    serf__log(CONN_VERBOSE, __FILE__, "reset connection 0x%x\n", conn);
637
638    conn->status = APR_SUCCESS;
639
640    /* Let our context know that we've 'reset' the socket already. */
641    conn->seen_in_pollset |= APR_POLLHUP;
642
643    /* Found the connection. Closed it. All done. */
644    return APR_SUCCESS;
645}
646
647static apr_status_t socket_writev(serf_connection_t *conn)
648{
649    apr_size_t written;
650    apr_status_t status;
651
652    status = apr_socket_sendv(conn->skt, conn->vec,
653                              conn->vec_len, &written);
654    if (status && !APR_STATUS_IS_EAGAIN(status))
655        serf__log_skt(SOCK_VERBOSE, __FILE__, conn->skt,
656                      "socket_sendv error %d\n", status);
657
658    /* did we write everything? */
659    if (written) {
660        apr_size_t len = 0;
661        int i;
662
663        serf__log_skt(SOCK_MSG_VERBOSE, __FILE__, conn->skt,
664                      "--- socket_sendv:\n");
665
666        for (i = 0; i < conn->vec_len; i++) {
667            len += conn->vec[i].iov_len;
668            if (written < len) {
669                serf__log_nopref(SOCK_MSG_VERBOSE, "%.*s",
670                                   conn->vec[i].iov_len - (len - written),
671                                   conn->vec[i].iov_base);
672                if (i) {
673                    memmove(conn->vec, &conn->vec[i],
674                            sizeof(struct iovec) * (conn->vec_len - i));
675                    conn->vec_len -= i;
676                }
677                conn->vec[0].iov_base = (char *)conn->vec[0].iov_base + (conn->vec[0].iov_len - (len - written));
678                conn->vec[0].iov_len = len - written;
679                break;
680            } else {
681                serf__log_nopref(SOCK_MSG_VERBOSE, "%.*s",
682                                   conn->vec[i].iov_len, conn->vec[i].iov_base);
683            }
684        }
685        if (len == written) {
686            conn->vec_len = 0;
687        }
688        serf__log_nopref(SOCK_MSG_VERBOSE, "-(%d)-\n", written);
689
690        /* Log progress information */
691        serf__context_progress_delta(conn->ctx, 0, written);
692    }
693
694    return status;
695}
696
697static apr_status_t setup_request(serf_request_t *request)
698{
699    serf_connection_t *conn = request->conn;
700    apr_status_t status;
701
702    /* Now that we are about to serve the request, allocate a pool. */
703    apr_pool_create(&request->respool, conn->pool);
704    request->allocator = serf_bucket_allocator_create(request->respool,
705                                                      NULL, NULL);
706    apr_pool_cleanup_register(request->respool, request,
707                              clean_resp, clean_resp);
708
709    /* Fill in the rest of the values for the request. */
710    status = request->setup(request, request->setup_baton,
711                            &request->req_bkt,
712                            &request->acceptor,
713                            &request->acceptor_baton,
714                            &request->handler,
715                            &request->handler_baton,
716                            request->respool);
717    return status;
718}
719
720/* write data out to the connection */
721static apr_status_t write_to_connection(serf_connection_t *conn)
722{
723    if (conn->probable_keepalive_limit &&
724        conn->completed_requests > conn->probable_keepalive_limit) {
725
726        conn->dirty_conn = 1;
727        conn->ctx->dirty_pollset = 1;
728
729        /* backoff for now. */
730        return APR_SUCCESS;
731    }
732
733    /* Keep reading and sending until we run out of stuff to read, or
734     * writing would block.
735     */
736    while (1) {
737        serf_request_t *request;
738        int stop_reading = 0;
739        apr_status_t status;
740        apr_status_t read_status;
741        serf_bucket_t *ostreamt;
742        serf_bucket_t *ostreamh;
743        int max_outstanding_requests = conn->max_outstanding_requests;
744
745        /* If we're setting up an ssl tunnel, we can't send real requests
746           at yet, as they need to be encrypted and our encrypt buckets
747           aren't created yet as we still need to read the unencrypted
748           response of the CONNECT request. */
749        if (conn->state != SERF_CONN_CONNECTED)
750            max_outstanding_requests = 1;
751
752        if (max_outstanding_requests &&
753            conn->completed_requests -
754                conn->completed_responses >= max_outstanding_requests) {
755            /* backoff for now. */
756            return APR_SUCCESS;
757        }
758
759        /* If we have unwritten data, then write what we can. */
760        while (conn->vec_len) {
761            status = socket_writev(conn);
762
763            /* If the write would have blocked, then we're done. Don't try
764             * to write anything else to the socket.
765             */
766            if (APR_STATUS_IS_EAGAIN(status))
767                return APR_SUCCESS;
768            if (APR_STATUS_IS_EPIPE(status) ||
769                APR_STATUS_IS_ECONNRESET(status) ||
770                APR_STATUS_IS_ECONNABORTED(status))
771                return no_more_writes(conn);
772            if (status)
773                return status;
774        }
775        /* ### can we have a short write, yet no EAGAIN? a short write
776           ### would imply unwritten_len > 0 ... */
777        /* assert: unwritten_len == 0. */
778
779        /* We may need to move forward to a request which has something
780         * to write.
781         */
782        if (!request_or_data_pending(&request, conn)) {
783            /* No more requests (with data) are registered with the
784             * connection, and no data is pending on the outgoing stream.
785             * Let's update the pollset so that we don't try to write to this
786             * socket again.
787             */
788            conn->dirty_conn = 1;
789            conn->ctx->dirty_pollset = 1;
790            return APR_SUCCESS;
791        }
792
793        status = prepare_conn_streams(conn, &conn->stream, &ostreamt, &ostreamh);
794        if (status) {
795            return status;
796        }
797
798        if (request) {
799            if (request->req_bkt == NULL) {
800                read_status = setup_request(request);
801                if (read_status) {
802                    /* Something bad happened. Propagate any errors. */
803                    return read_status;
804                }
805            }
806
807            if (!request->writing_started) {
808                request->writing_started = 1;
809                serf_bucket_aggregate_append(ostreamt, request->req_bkt);
810            }
811        }
812
813        /* ### optimize at some point by using read_for_sendfile */
814        /* TODO: now that read_iovec will effectively try to return as much
815           data as available, we probably don't want to read ALL_AVAIL, but
816           a lower number, like the size of one or a few TCP packets, the
817           available TCP buffer size ... */
818        read_status = serf_bucket_read_iovec(ostreamh,
819                                             SERF_READ_ALL_AVAIL,
820                                             IOV_MAX,
821                                             conn->vec,
822                                             &conn->vec_len);
823
824        if (!conn->hit_eof) {
825            if (APR_STATUS_IS_EAGAIN(read_status)) {
826                /* We read some stuff, but should not try to read again. */
827                stop_reading = 1;
828            }
829            else if (read_status == SERF_ERROR_WAIT_CONN) {
830                /* The bucket told us that it can't provide more data until
831                   more data is read from the socket. This normally happens
832                   during a SSL handshake.
833
834                   We should avoid looking for writability for a while so
835                   that (hopefully) something will appear in the bucket so
836                   we can actually write something. otherwise, we could
837                   end up in a CPU spin: socket wants something, but we
838                   don't have anything (and keep returning EAGAIN)
839                 */
840                conn->stop_writing = 1;
841                conn->dirty_conn = 1;
842                conn->ctx->dirty_pollset = 1;
843            }
844            else if (read_status && !APR_STATUS_IS_EOF(read_status)) {
845                /* Something bad happened. Propagate any errors. */
846                return read_status;
847            }
848        }
849
850        /* If we got some data, then deliver it. */
851        /* ### what to do if we got no data?? is that a problem? */
852        if (conn->vec_len > 0) {
853            status = socket_writev(conn);
854
855            /* If we can't write any more, or an error occurred, then
856             * we're done here.
857             */
858            if (APR_STATUS_IS_EAGAIN(status))
859                return APR_SUCCESS;
860            if (APR_STATUS_IS_EPIPE(status))
861                return no_more_writes(conn);
862            if (APR_STATUS_IS_ECONNRESET(status) ||
863                APR_STATUS_IS_ECONNABORTED(status)) {
864                return no_more_writes(conn);
865            }
866            if (status)
867                return status;
868        }
869
870        if (read_status == SERF_ERROR_WAIT_CONN) {
871            stop_reading = 1;
872            conn->stop_writing = 1;
873            conn->dirty_conn = 1;
874            conn->ctx->dirty_pollset = 1;
875        }
876        else if (request && read_status && conn->hit_eof &&
877                 conn->vec_len == 0) {
878            /* If we hit the end of the request bucket and all of its data has
879             * been written, then clear it out to signify that we're done
880             * sending the request. On the next iteration through this loop:
881             * - if there are remaining bytes they will be written, and as the
882             * request bucket will be completely read it will be destroyed then.
883             * - we'll see if there are other requests that need to be sent
884             * ("pipelining").
885             */
886            conn->hit_eof = 0;
887            serf_bucket_destroy(request->req_bkt);
888            request->req_bkt = NULL;
889
890            /* If our connection has async responses enabled, we're not
891             * going to get a reply back, so kill the request.
892             */
893            if (conn->async_responses) {
894                conn->requests = request->next;
895                destroy_request(request);
896            }
897
898            conn->completed_requests++;
899
900            if (conn->probable_keepalive_limit &&
901                conn->completed_requests > conn->probable_keepalive_limit) {
902                /* backoff for now. */
903                stop_reading = 1;
904            }
905        }
906
907        if (stop_reading) {
908            return APR_SUCCESS;
909        }
910    }
911    /* NOTREACHED */
912}
913
914/* A response message was received from the server, so call
915   the handler as specified on the original request. */
916static apr_status_t handle_response(serf_request_t *request,
917                                    apr_pool_t *pool)
918{
919    apr_status_t status = APR_SUCCESS;
920    int consumed_response = 0;
921
922    /* Only enable the new authentication framework if the program has
923     * registered an authentication credential callback.
924     *
925     * This permits older Serf apps to still handle authentication
926     * themselves by not registering credential callbacks.
927     */
928    if (request->conn->ctx->cred_cb) {
929      status = serf__handle_auth_response(&consumed_response,
930                                          request,
931                                          request->resp_bkt,
932                                          request->handler_baton,
933                                          pool);
934
935      /* If there was an error reading the response (maybe there wasn't
936         enough data available), don't bother passing the response to the
937         application.
938
939         If the authentication was tried, but failed, pass the response
940         to the application, maybe it can do better. */
941      if (status) {
942          return status;
943      }
944    }
945
946    if (!consumed_response) {
947        return (*request->handler)(request,
948                                   request->resp_bkt,
949                                   request->handler_baton,
950                                   pool);
951    }
952
953    return status;
954}
955
956/* An async response message was received from the server. */
957static apr_status_t handle_async_response(serf_connection_t *conn,
958                                          apr_pool_t *pool)
959{
960    apr_status_t status;
961
962    if (conn->current_async_response == NULL) {
963        conn->current_async_response =
964            (*conn->async_acceptor)(NULL, conn->stream,
965                                    conn->async_acceptor_baton, pool);
966    }
967
968    status = (*conn->async_handler)(NULL, conn->current_async_response,
969                                    conn->async_handler_baton, pool);
970
971    if (APR_STATUS_IS_EOF(status)) {
972        serf_bucket_destroy(conn->current_async_response);
973        conn->current_async_response = NULL;
974        status = APR_SUCCESS;
975    }
976
977    return status;
978}
979
980
981apr_status_t
982serf__provide_credentials(serf_context_t *ctx,
983                          char **username,
984                          char **password,
985                          serf_request_t *request, void *baton,
986                          int code, const char *authn_type,
987                          const char *realm,
988                          apr_pool_t *pool)
989{
990    serf_connection_t *conn = request->conn;
991    serf_request_t *authn_req = request;
992    apr_status_t status;
993
994    if (request->ssltunnel == 1 &&
995        conn->state == SERF_CONN_SETUP_SSLTUNNEL) {
996        /* This is a CONNECT request to set up an SSL tunnel over a proxy.
997           This request is created by serf, so if the proxy requires
998           authentication, we can't ask the application for credentials with
999           this request.
1000
1001           Solution: setup the first request created by the application on
1002           this connection, and use that request and its handler_baton to
1003           call back to the application. */
1004
1005        authn_req = request->next;
1006        /* assert: app_request != NULL */
1007        if (!authn_req)
1008            return APR_EGENERAL;
1009
1010        if (!authn_req->req_bkt) {
1011            apr_status_t status;
1012
1013            status = setup_request(authn_req);
1014            /* If we can't setup a request, don't bother setting up the
1015               ssl tunnel. */
1016            if (status)
1017                return status;
1018        }
1019    }
1020
1021    /* Ask the application. */
1022    status = (*ctx->cred_cb)(username, password,
1023                             authn_req, authn_req->handler_baton,
1024                             code, authn_type, realm, pool);
1025    if (status)
1026        return status;
1027
1028    return APR_SUCCESS;
1029}
1030
1031/* read data from the connection */
1032static apr_status_t read_from_connection(serf_connection_t *conn)
1033{
1034    apr_status_t status;
1035    apr_pool_t *tmppool;
1036    int close_connection = FALSE;
1037
1038    /* Whatever is coming in on the socket corresponds to the first request
1039     * on our chain.
1040     */
1041    serf_request_t *request = conn->requests;
1042
1043    /* If the stop_writing flag was set on the connection, reset it now because
1044       there is some data to read. */
1045    if (conn->stop_writing) {
1046        conn->stop_writing = 0;
1047        conn->dirty_conn = 1;
1048        conn->ctx->dirty_pollset = 1;
1049    }
1050
1051    /* assert: request != NULL */
1052
1053    if ((status = apr_pool_create(&tmppool, conn->pool)) != APR_SUCCESS)
1054        goto error;
1055
1056    /* Invoke response handlers until we have no more work. */
1057    while (1) {
1058        serf_bucket_t *dummy1, *dummy2;
1059
1060        apr_pool_clear(tmppool);
1061
1062        /* Only interested in the input stream here. */
1063        status = prepare_conn_streams(conn, &conn->stream, &dummy1, &dummy2);
1064        if (status) {
1065            goto error;
1066        }
1067
1068        /* We have a different codepath when we can have async responses. */
1069        if (conn->async_responses) {
1070            /* TODO What about socket errors? */
1071            status = handle_async_response(conn, tmppool);
1072            if (APR_STATUS_IS_EAGAIN(status)) {
1073                status = APR_SUCCESS;
1074                goto error;
1075            }
1076            if (status) {
1077                goto error;
1078            }
1079            continue;
1080        }
1081
1082        /* We are reading a response for a request we haven't
1083         * written yet!
1084         *
1085         * This shouldn't normally happen EXCEPT:
1086         *
1087         * 1) when the other end has closed the socket and we're
1088         *    pending an EOF return.
1089         * 2) Doing the initial SSL handshake - we'll get EAGAIN
1090         *    as the SSL buckets will hide the handshake from us
1091         *    but not return any data.
1092         * 3) When the server sends us an SSL alert.
1093         *
1094         * In these cases, we should not receive any actual user data.
1095         *
1096         * 4) When the server sends a error response, like 408 Request timeout.
1097         *    This response should be passed to the application.
1098         *
1099         * If we see an EOF (due to either an expired timeout or the server
1100         * sending the SSL 'close notify' shutdown alert), we'll reset the
1101         * connection and open a new one.
1102         */
1103        if (request->req_bkt || !request->writing_started) {
1104            const char *data;
1105            apr_size_t len;
1106
1107            status = serf_bucket_peek(conn->stream, &data, &len);
1108
1109            if (APR_STATUS_IS_EOF(status)) {
1110                reset_connection(conn, 1);
1111                status = APR_SUCCESS;
1112                goto error;
1113            }
1114            else if (APR_STATUS_IS_EAGAIN(status) && !len) {
1115                status = APR_SUCCESS;
1116                goto error;
1117            } else if (status && !APR_STATUS_IS_EAGAIN(status)) {
1118                /* Read error */
1119                goto error;
1120            }
1121
1122            /* Unexpected response from the server */
1123
1124        }
1125
1126        /* If the request doesn't have a response bucket, then call the
1127         * acceptor to get one created.
1128         */
1129        if (request->resp_bkt == NULL) {
1130            request->resp_bkt = (*request->acceptor)(request, conn->stream,
1131                                                     request->acceptor_baton,
1132                                                     tmppool);
1133            apr_pool_clear(tmppool);
1134        }
1135
1136        status = handle_response(request, tmppool);
1137
1138        /* Some systems will not generate a HUP poll event so we have to
1139         * handle the ECONNRESET issue and ECONNABORT here.
1140         */
1141        if (APR_STATUS_IS_ECONNRESET(status) ||
1142            APR_STATUS_IS_ECONNABORTED(status) ||
1143            status == SERF_ERROR_REQUEST_LOST) {
1144            /* If the connection had ever been good, be optimistic & try again.
1145             * If it has never tried again (incl. a retry), fail.
1146             */
1147            if (conn->completed_responses) {
1148                reset_connection(conn, 1);
1149                status = APR_SUCCESS;
1150            }
1151            else if (status == SERF_ERROR_REQUEST_LOST) {
1152                status = SERF_ERROR_ABORTED_CONNECTION;
1153            }
1154            goto error;
1155        }
1156
1157        /* If our response handler says it can't do anything more, we now
1158         * treat that as a success.
1159         */
1160        if (APR_STATUS_IS_EAGAIN(status)) {
1161            /* It is possible that while reading the response, the ssl layer
1162               has prepared some data to send. If this was the last request,
1163               serf will not check for socket writability, so force this here.
1164             */
1165            if (request_or_data_pending(&request, conn) && !request) {
1166                conn->dirty_conn = 1;
1167                conn->ctx->dirty_pollset = 1;
1168            }
1169            status = APR_SUCCESS;
1170            goto error;
1171        }
1172
1173        /* If we received APR_SUCCESS, run this loop again. */
1174        if (!status) {
1175            continue;
1176        }
1177
1178        close_connection = is_conn_closing(request->resp_bkt);
1179
1180        if (!APR_STATUS_IS_EOF(status) &&
1181            close_connection != SERF_ERROR_CLOSING) {
1182            /* Whether success, or an error, there is no more to do unless
1183             * this request has been completed.
1184             */
1185            goto error;
1186        }
1187
1188        /* The response has been fully-read, so that means the request has
1189         * either been fully-delivered (most likely), or that we don't need to
1190         * write the rest of it anymore, e.g. when a 408 Request timeout was
1191         $ received.
1192         * Remove it from our queue and loop to read another response.
1193         */
1194        conn->requests = request->next;
1195
1196        destroy_request(request);
1197
1198        request = conn->requests;
1199
1200        /* If we're truly empty, update our tail. */
1201        if (request == NULL) {
1202            conn->requests_tail = NULL;
1203        }
1204
1205        conn->completed_responses++;
1206
1207        /* We've to rebuild pollset since completed_responses is changed. */
1208        conn->dirty_conn = 1;
1209        conn->ctx->dirty_pollset = 1;
1210
1211        /* This means that we're being advised that the connection is done. */
1212        if (close_connection == SERF_ERROR_CLOSING) {
1213            reset_connection(conn, 1);
1214            if (APR_STATUS_IS_EOF(status))
1215                status = APR_SUCCESS;
1216            goto error;
1217        }
1218
1219        /* The server is suddenly deciding to serve more responses than we've
1220         * seen before.
1221         *
1222         * Let our requests go.
1223         */
1224        if (conn->probable_keepalive_limit &&
1225            conn->completed_responses > conn->probable_keepalive_limit) {
1226            conn->probable_keepalive_limit = 0;
1227        }
1228
1229        /* If we just ran out of requests or have unwritten requests, then
1230         * update the pollset. We don't want to read from this socket any
1231         * more. We are definitely done with this loop, too.
1232         */
1233        if (request == NULL || !request->writing_started) {
1234            conn->dirty_conn = 1;
1235            conn->ctx->dirty_pollset = 1;
1236            status = APR_SUCCESS;
1237            goto error;
1238        }
1239    }
1240
1241error:
1242    apr_pool_destroy(tmppool);
1243    return status;
1244}
1245
1246/* process all events on the connection */
1247apr_status_t serf__process_connection(serf_connection_t *conn,
1248                                      apr_int16_t events)
1249{
1250    apr_status_t status;
1251
1252    /* POLLHUP/ERR should come after POLLIN so if there's an error message or
1253     * the like sitting on the connection, we give the app a chance to read
1254     * it before we trigger a reset condition.
1255     */
1256    if ((events & APR_POLLIN) != 0) {
1257        if ((status = read_from_connection(conn)) != APR_SUCCESS)
1258            return status;
1259
1260        /* If we decided to reset our connection, return now as we don't
1261         * want to write.
1262         */
1263        if ((conn->seen_in_pollset & APR_POLLHUP) != 0) {
1264            return APR_SUCCESS;
1265        }
1266    }
1267    if ((events & APR_POLLHUP) != 0) {
1268        /* The connection got reset by the server. On Windows this can happen
1269           when all data is read, so just cleanup the connection and open
1270           a new one.
1271           If we haven't had any successful responses on this connection,
1272           then error out as it is likely a server issue. */
1273        if (conn->completed_responses) {
1274            return reset_connection(conn, 1);
1275        }
1276        return SERF_ERROR_ABORTED_CONNECTION;
1277    }
1278    if ((events & APR_POLLERR) != 0) {
1279        /* We might be talking to a buggy HTTP server that doesn't
1280         * do lingering-close.  (httpd < 2.1.8 does this.)
1281         *
1282         * See:
1283         *
1284         * http://issues.apache.org/bugzilla/show_bug.cgi?id=35292
1285         */
1286        if (conn->completed_requests && !conn->probable_keepalive_limit) {
1287            return reset_connection(conn, 1);
1288        }
1289#ifdef SO_ERROR
1290        /* If possible, get the error from the platform's socket layer and
1291           convert it to an APR status code. */
1292        {
1293            apr_os_sock_t osskt;
1294            if (!apr_os_sock_get(&osskt, conn->skt)) {
1295                int error;
1296                apr_socklen_t l = sizeof(error);
1297
1298                if (!getsockopt(osskt, SOL_SOCKET, SO_ERROR, (char*)&error,
1299                                &l)) {
1300                    status = APR_FROM_OS_ERROR(error);
1301
1302                    /* Handle fallback for multi-homed servers.
1303
1304                       ### Improve algorithm to find better than just 'next'?
1305
1306                       Current Windows versions already handle re-ordering for
1307                       api users by using statistics on the recently failed
1308                       connections to order the list of addresses. */
1309                    if (conn->completed_requests == 0
1310                        && conn->address->next != NULL
1311                        && (APR_STATUS_IS_ECONNREFUSED(status)
1312                            || APR_STATUS_IS_TIMEUP(status)
1313                            || APR_STATUS_IS_ENETUNREACH(status))) {
1314
1315                        conn->address = conn->address->next;
1316                        return reset_connection(conn, 1);
1317                    }
1318
1319                    return status;
1320                  }
1321            }
1322        }
1323#endif
1324        return APR_EGENERAL;
1325    }
1326    if ((events & APR_POLLOUT) != 0) {
1327        if ((status = write_to_connection(conn)) != APR_SUCCESS)
1328            return status;
1329    }
1330    return APR_SUCCESS;
1331}
1332
1333serf_connection_t *serf_connection_create(
1334    serf_context_t *ctx,
1335    apr_sockaddr_t *address,
1336    serf_connection_setup_t setup,
1337    void *setup_baton,
1338    serf_connection_closed_t closed,
1339    void *closed_baton,
1340    apr_pool_t *pool)
1341{
1342    serf_connection_t *conn = apr_pcalloc(pool, sizeof(*conn));
1343
1344    conn->ctx = ctx;
1345    conn->status = APR_SUCCESS;
1346    /* Ignore server address if proxy was specified. */
1347    conn->address = ctx->proxy_address ? ctx->proxy_address : address;
1348    conn->setup = setup;
1349    conn->setup_baton = setup_baton;
1350    conn->closed = closed;
1351    conn->closed_baton = closed_baton;
1352    conn->pool = pool;
1353    conn->allocator = serf_bucket_allocator_create(pool, NULL, NULL);
1354    conn->stream = NULL;
1355    conn->ostream_head = NULL;
1356    conn->ostream_tail = NULL;
1357    conn->baton.type = SERF_IO_CONN;
1358    conn->baton.u.conn = conn;
1359    conn->hit_eof = 0;
1360    conn->state = SERF_CONN_INIT;
1361    conn->latency = -1; /* unknown */
1362
1363    /* Create a subpool for our connection. */
1364    apr_pool_create(&conn->skt_pool, conn->pool);
1365
1366    /* register a cleanup */
1367    apr_pool_cleanup_register(conn->pool, conn, clean_conn,
1368                              apr_pool_cleanup_null);
1369
1370    /* Add the connection to the context. */
1371    *(serf_connection_t **)apr_array_push(ctx->conns) = conn;
1372
1373    serf__log(CONN_VERBOSE, __FILE__, "created connection 0x%x\n",
1374              conn);
1375
1376    return conn;
1377}
1378
1379apr_status_t serf_connection_create2(
1380    serf_connection_t **conn,
1381    serf_context_t *ctx,
1382    apr_uri_t host_info,
1383    serf_connection_setup_t setup,
1384    void *setup_baton,
1385    serf_connection_closed_t closed,
1386    void *closed_baton,
1387    apr_pool_t *pool)
1388{
1389    apr_status_t status = APR_SUCCESS;
1390    serf_connection_t *c;
1391    apr_sockaddr_t *host_address = NULL;
1392
1393    /* Set the port number explicitly, needed to create the socket later. */
1394    if (!host_info.port) {
1395        host_info.port = apr_uri_port_of_scheme(host_info.scheme);
1396    }
1397
1398    /* Only lookup the address of the server if no proxy server was
1399       configured. */
1400    if (!ctx->proxy_address) {
1401        status = apr_sockaddr_info_get(&host_address,
1402                                       host_info.hostname,
1403                                       APR_UNSPEC, host_info.port, 0, pool);
1404        if (status)
1405            return status;
1406    }
1407
1408    c = serf_connection_create(ctx, host_address, setup, setup_baton,
1409                               closed, closed_baton, pool);
1410
1411    /* We're not interested in the path following the hostname. */
1412    c->host_url = apr_uri_unparse(c->pool,
1413                                  &host_info,
1414                                  APR_URI_UNP_OMITPATHINFO |
1415                                  APR_URI_UNP_OMITUSERINFO);
1416
1417    /* Store the host info without the path on the connection. */
1418    (void)apr_uri_parse(c->pool, c->host_url, &(c->host_info));
1419    if (!c->host_info.port) {
1420        c->host_info.port = apr_uri_port_of_scheme(c->host_info.scheme);
1421    }
1422
1423    *conn = c;
1424
1425    return status;
1426}
1427
1428apr_status_t serf_connection_reset(
1429    serf_connection_t *conn)
1430{
1431    return reset_connection(conn, 0);
1432}
1433
1434
1435apr_status_t serf_connection_close(
1436    serf_connection_t *conn)
1437{
1438    int i;
1439    serf_context_t *ctx = conn->ctx;
1440    apr_status_t status;
1441
1442    for (i = ctx->conns->nelts; i--; ) {
1443        serf_connection_t *conn_seq = GET_CONN(ctx, i);
1444
1445        if (conn_seq == conn) {
1446            while (conn->requests) {
1447                serf_request_cancel(conn->requests);
1448            }
1449            if (conn->skt != NULL) {
1450                remove_connection(ctx, conn);
1451                status = apr_socket_close(conn->skt);
1452                serf__log_skt(SOCK_VERBOSE, __FILE__, conn->skt,
1453                              "closed socket, status %d\n",
1454                              status);
1455                if (conn->closed != NULL) {
1456                    handle_conn_closed(conn, status);
1457                }
1458                conn->skt = NULL;
1459            }
1460            if (conn->stream != NULL) {
1461                serf_bucket_destroy(conn->stream);
1462                conn->stream = NULL;
1463            }
1464
1465            destroy_ostream(conn);
1466
1467            /* Remove the connection from the context. We don't want to
1468             * deal with it any more.
1469             */
1470            if (i < ctx->conns->nelts - 1) {
1471                /* move later connections over this one. */
1472                memmove(
1473                    &GET_CONN(ctx, i),
1474                    &GET_CONN(ctx, i + 1),
1475                    (ctx->conns->nelts - i - 1) * sizeof(serf_connection_t *));
1476            }
1477            --ctx->conns->nelts;
1478
1479            serf__log(CONN_VERBOSE, __FILE__, "closed connection 0x%x\n",
1480                      conn);
1481
1482            /* Found the connection. Closed it. All done. */
1483            return APR_SUCCESS;
1484        }
1485    }
1486
1487    /* We didn't find the specified connection. */
1488    /* ### doc talks about this w.r.t poll structures. use something else? */
1489    return APR_NOTFOUND;
1490}
1491
1492
1493void serf_connection_set_max_outstanding_requests(
1494    serf_connection_t *conn,
1495    unsigned int max_requests)
1496{
1497    if (max_requests == 0)
1498        serf__log_skt(CONN_VERBOSE, __FILE__, conn->skt,
1499                      "Set max. nr. of outstanding requests for this "
1500                      "connection to unlimited.\n");
1501    else
1502        serf__log_skt(CONN_VERBOSE, __FILE__, conn->skt,
1503                      "Limit max. nr. of outstanding requests for this "
1504                      "connection to %u.\n", max_requests);
1505
1506    conn->max_outstanding_requests = max_requests;
1507}
1508
1509
1510void serf_connection_set_async_responses(
1511    serf_connection_t *conn,
1512    serf_response_acceptor_t acceptor,
1513    void *acceptor_baton,
1514    serf_response_handler_t handler,
1515    void *handler_baton)
1516{
1517    conn->async_responses = 1;
1518    conn->async_acceptor = acceptor;
1519    conn->async_acceptor_baton = acceptor_baton;
1520    conn->async_handler = handler;
1521    conn->async_handler_baton = handler_baton;
1522}
1523
1524static serf_request_t *
1525create_request(serf_connection_t *conn,
1526               serf_request_setup_t setup,
1527               void *setup_baton,
1528               int priority,
1529               int ssltunnel)
1530{
1531    serf_request_t *request;
1532
1533    request = serf_bucket_mem_alloc(conn->allocator, sizeof(*request));
1534    request->conn = conn;
1535    request->setup = setup;
1536    request->setup_baton = setup_baton;
1537    request->handler = NULL;
1538    request->respool = NULL;
1539    request->req_bkt = NULL;
1540    request->resp_bkt = NULL;
1541    request->priority = priority;
1542    request->writing_started = 0;
1543    request->ssltunnel = ssltunnel;
1544    request->next = NULL;
1545    request->auth_baton = NULL;
1546
1547    return request;
1548}
1549
1550serf_request_t *serf_connection_request_create(
1551    serf_connection_t *conn,
1552    serf_request_setup_t setup,
1553    void *setup_baton)
1554{
1555    serf_request_t *request;
1556
1557    request = create_request(conn, setup, setup_baton,
1558                             0, /* priority */
1559                             0  /* ssl tunnel */);
1560
1561    /* Link the request to the end of the request chain. */
1562    link_requests(&conn->requests, &conn->requests_tail, request);
1563
1564    /* Ensure our pollset becomes writable in context run */
1565    conn->ctx->dirty_pollset = 1;
1566    conn->dirty_conn = 1;
1567
1568    return request;
1569}
1570
1571static serf_request_t *
1572priority_request_create(serf_connection_t *conn,
1573                        int ssltunnelreq,
1574                        serf_request_setup_t setup,
1575                        void *setup_baton)
1576{
1577    serf_request_t *request;
1578    serf_request_t *iter, *prev;
1579
1580    request = create_request(conn, setup, setup_baton,
1581                             1, /* priority */
1582                             ssltunnelreq);
1583
1584    /* Link the new request after the last written request. */
1585    iter = conn->requests;
1586    prev = NULL;
1587
1588    /* Find a request that has data which needs to be delivered. */
1589    while (iter != NULL && iter->req_bkt == NULL && iter->writing_started) {
1590        prev = iter;
1591        iter = iter->next;
1592    }
1593
1594    /* A CONNECT request to setup an ssltunnel has absolute priority over all
1595       other requests on the connection, so:
1596       a. add it first to the queue
1597       b. ensure that other priority requests are added after the CONNECT
1598          request */
1599    if (!request->ssltunnel) {
1600        /* Advance to next non priority request */
1601        while (iter != NULL && iter->priority) {
1602            prev = iter;
1603            iter = iter->next;
1604        }
1605    }
1606
1607    if (prev) {
1608        request->next = iter;
1609        prev->next = request;
1610    } else {
1611        request->next = iter;
1612        conn->requests = request;
1613    }
1614
1615    /* Ensure our pollset becomes writable in context run */
1616    conn->ctx->dirty_pollset = 1;
1617    conn->dirty_conn = 1;
1618
1619    return request;
1620}
1621
1622serf_request_t *serf_connection_priority_request_create(
1623    serf_connection_t *conn,
1624    serf_request_setup_t setup,
1625    void *setup_baton)
1626{
1627    return priority_request_create(conn,
1628                                   0, /* not a ssltunnel CONNECT request */
1629                                   setup, setup_baton);
1630}
1631
1632serf_request_t *serf__ssltunnel_request_create(serf_connection_t *conn,
1633                                               serf_request_setup_t setup,
1634                                               void *setup_baton)
1635{
1636    return priority_request_create(conn,
1637                                   1, /* This is a ssltunnel CONNECT request */
1638                                   setup, setup_baton);
1639}
1640
1641apr_status_t serf_request_cancel(serf_request_t *request)
1642{
1643    return cancel_request(request, &request->conn->requests, 0);
1644}
1645
1646apr_status_t serf_request_is_written(serf_request_t *request)
1647{
1648    if (request->writing_started && !request->req_bkt)
1649        return APR_SUCCESS;
1650
1651    return APR_EBUSY;
1652}
1653
1654apr_pool_t *serf_request_get_pool(const serf_request_t *request)
1655{
1656    return request->respool;
1657}
1658
1659
1660serf_bucket_alloc_t *serf_request_get_alloc(
1661    const serf_request_t *request)
1662{
1663    return request->allocator;
1664}
1665
1666
1667serf_connection_t *serf_request_get_conn(
1668    const serf_request_t *request)
1669{
1670    return request->conn;
1671}
1672
1673
1674void serf_request_set_handler(
1675    serf_request_t *request,
1676    const serf_response_handler_t handler,
1677    const void **handler_baton)
1678{
1679    request->handler = handler;
1680    request->handler_baton = handler_baton;
1681}
1682
1683
1684serf_bucket_t *serf_request_bucket_request_create(
1685    serf_request_t *request,
1686    const char *method,
1687    const char *uri,
1688    serf_bucket_t *body,
1689    serf_bucket_alloc_t *allocator)
1690{
1691    serf_bucket_t *req_bkt, *hdrs_bkt;
1692    serf_connection_t *conn = request->conn;
1693    serf_context_t *ctx = conn->ctx;
1694    int ssltunnel;
1695
1696    ssltunnel = ctx->proxy_address &&
1697                (strcmp(conn->host_info.scheme, "https") == 0);
1698
1699    req_bkt = serf_bucket_request_create(method, uri, body, allocator);
1700    hdrs_bkt = serf_bucket_request_get_headers(req_bkt);
1701
1702    /* Use absolute uri's in requests to a proxy. USe relative uri's in
1703       requests directly to a server or sent through an SSL tunnel. */
1704    if (ctx->proxy_address && conn->host_url &&
1705        !(ssltunnel && !request->ssltunnel)) {
1706
1707        serf_bucket_request_set_root(req_bkt, conn->host_url);
1708    }
1709
1710    if (conn->host_info.hostinfo)
1711        serf_bucket_headers_setn(hdrs_bkt, "Host",
1712                                 conn->host_info.hostinfo);
1713
1714    /* Setup server authorization headers, unless this is a CONNECT request. */
1715    if (!request->ssltunnel) {
1716        serf__authn_info_t *authn_info;
1717        authn_info = serf__get_authn_info_for_server(conn);
1718        if (authn_info->scheme)
1719            authn_info->scheme->setup_request_func(HOST, 0, conn, request,
1720                                                   method, uri,
1721                                                   hdrs_bkt);
1722    }
1723
1724    /* Setup proxy authorization headers.
1725       Don't set these headers on the requests to the server if we're using
1726       an SSL tunnel, only on the CONNECT request to setup the tunnel. */
1727    if (ctx->proxy_authn_info.scheme) {
1728        if (strcmp(conn->host_info.scheme, "https") == 0) {
1729            if (request->ssltunnel)
1730                ctx->proxy_authn_info.scheme->setup_request_func(PROXY, 0, conn,
1731                                                                 request,
1732                                                                 method, uri,
1733                                                                 hdrs_bkt);
1734        } else {
1735            ctx->proxy_authn_info.scheme->setup_request_func(PROXY, 0, conn,
1736                                                             request,
1737                                                             method, uri,
1738                                                             hdrs_bkt);
1739        }
1740    }
1741
1742    return req_bkt;
1743}
1744
1745apr_interval_time_t serf_connection_get_latency(serf_connection_t *conn)
1746{
1747    if (conn->ctx->proxy_address) {
1748        /* Detecting network latency for proxied connection is not implemented
1749           yet. */
1750        return -1;
1751    }
1752
1753    return conn->latency;
1754}
1755