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 */
clean_skt(void * data)32 static 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
clean_resp(void * data)47 static 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 */
clean_conn(void * data)78 static 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. */
98 static int
request_or_data_pending(serf_request_t ** next_req,serf_connection_t * conn)99 request_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 */
serf__conn_update_pollset(serf_connection_t * conn)134 apr_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. */
check_buckets_drained(serf_connection_t * conn)207 static 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
destroy_ostream(serf_connection_t * conn)225 static 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
detect_eof(void * baton,serf_bucket_t * aggregate_bucket)234 static 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
do_conn_setup(serf_connection_t * conn)241 static 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
prepare_conn_streams(serf_connection_t * conn,serf_bucket_t ** istream,serf_bucket_t ** ostreamt,serf_bucket_t ** ostreamh)286 static 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 */
serf__open_connections(serf_context_t * ctx)330 apr_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
no_more_writes(serf_connection_t * conn)436 static 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 */
is_conn_closing(serf_bucket_t * response)459 static 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
link_requests(serf_request_t ** list,serf_request_t ** tail,serf_request_t * request)474 static 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
destroy_request(serf_request_t * request)487 static 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
cancel_request(serf_request_t * request,serf_request_t ** list,int notify_request)515 static 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
remove_connection(serf_context_t * ctx,serf_connection_t * conn)545 static 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. */
handle_conn_closed(serf_connection_t * conn,apr_status_t status)559 static 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
reset_connection(serf_connection_t * conn,int requeue_requests)565 static 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
socket_writev(serf_connection_t * conn)647 static 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
setup_request(serf_request_t * request)697 static 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 */
write_to_connection(serf_connection_t * conn)721 static 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. */
handle_response(serf_request_t * request,apr_pool_t * pool)916 static 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. */
handle_async_response(serf_connection_t * conn,apr_pool_t * pool)957 static 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
981 apr_status_t
serf__provide_credentials(serf_context_t * ctx,char ** username,char ** password,serf_request_t * request,void * baton,int code,const char * authn_type,const char * realm,apr_pool_t * pool)982 serf__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 */
read_from_connection(serf_connection_t * conn)1032 static 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
1241 error:
1242 apr_pool_destroy(tmppool);
1243 return status;
1244 }
1245
1246 /* process all events on the connection */
serf__process_connection(serf_connection_t * conn,apr_int16_t events)1247 apr_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
serf_connection_create(serf_context_t * ctx,apr_sockaddr_t * address,serf_connection_setup_t setup,void * setup_baton,serf_connection_closed_t closed,void * closed_baton,apr_pool_t * pool)1333 serf_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
serf_connection_create2(serf_connection_t ** conn,serf_context_t * ctx,apr_uri_t host_info,serf_connection_setup_t setup,void * setup_baton,serf_connection_closed_t closed,void * closed_baton,apr_pool_t * pool)1379 apr_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
serf_connection_reset(serf_connection_t * conn)1428 apr_status_t serf_connection_reset(
1429 serf_connection_t *conn)
1430 {
1431 return reset_connection(conn, 0);
1432 }
1433
1434
serf_connection_close(serf_connection_t * conn)1435 apr_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
serf_connection_set_max_outstanding_requests(serf_connection_t * conn,unsigned int max_requests)1493 void 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
serf_connection_set_async_responses(serf_connection_t * conn,serf_response_acceptor_t acceptor,void * acceptor_baton,serf_response_handler_t handler,void * handler_baton)1510 void 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
1524 static serf_request_t *
create_request(serf_connection_t * conn,serf_request_setup_t setup,void * setup_baton,int priority,int ssltunnel)1525 create_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
serf_connection_request_create(serf_connection_t * conn,serf_request_setup_t setup,void * setup_baton)1550 serf_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
1571 static serf_request_t *
priority_request_create(serf_connection_t * conn,int ssltunnelreq,serf_request_setup_t setup,void * setup_baton)1572 priority_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
serf_connection_priority_request_create(serf_connection_t * conn,serf_request_setup_t setup,void * setup_baton)1622 serf_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
serf__ssltunnel_request_create(serf_connection_t * conn,serf_request_setup_t setup,void * setup_baton)1632 serf_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
serf_request_cancel(serf_request_t * request)1641 apr_status_t serf_request_cancel(serf_request_t *request)
1642 {
1643 return cancel_request(request, &request->conn->requests, 0);
1644 }
1645
serf_request_is_written(serf_request_t * request)1646 apr_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
serf_request_get_pool(const serf_request_t * request)1654 apr_pool_t *serf_request_get_pool(const serf_request_t *request)
1655 {
1656 return request->respool;
1657 }
1658
1659
serf_request_get_alloc(const serf_request_t * request)1660 serf_bucket_alloc_t *serf_request_get_alloc(
1661 const serf_request_t *request)
1662 {
1663 return request->allocator;
1664 }
1665
1666
serf_request_get_conn(const serf_request_t * request)1667 serf_connection_t *serf_request_get_conn(
1668 const serf_request_t *request)
1669 {
1670 return request->conn;
1671 }
1672
1673
serf_request_set_handler(serf_request_t * request,const serf_response_handler_t handler,const void ** handler_baton)1674 void 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
serf_request_bucket_request_create(serf_request_t * request,const char * method,const char * uri,serf_bucket_t * body,serf_bucket_alloc_t * allocator)1684 serf_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
serf_connection_get_latency(serf_connection_t * conn)1745 apr_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