1362181Sdim/* ==================================================================== 2362181Sdim * Licensed to the Apache Software Foundation (ASF) under one 3362181Sdim * or more contributor license agreements. See the NOTICE file 4362181Sdim * distributed with this work for additional information 5362181Sdim * regarding copyright ownership. The ASF licenses this file 6362181Sdim * to you under the Apache License, Version 2.0 (the 7362181Sdim * "License"); you may not use this file except in compliance 8362181Sdim * with the License. You may obtain a copy of the License at 9251877Speter * 10362181Sdim * http://www.apache.org/licenses/LICENSE-2.0 11251877Speter * 12362181Sdim * Unless required by applicable law or agreed to in writing, 13362181Sdim * software distributed under the License is distributed on an 14362181Sdim * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 15362181Sdim * KIND, either express or implied. See the License for the 16362181Sdim * specific language governing permissions and limitations 17362181Sdim * under the License. 18362181Sdim * ==================================================================== 19251877Speter */ 20251877Speter 21251877Speter#include <apr_pools.h> 22251877Speter#include <apr_poll.h> 23251877Speter#include <apr_version.h> 24253895Speter#include <apr_portable.h> 25251877Speter 26251877Speter#include "serf.h" 27251877Speter#include "serf_bucket_util.h" 28251877Speter 29251877Speter#include "serf_private.h" 30251877Speter 31251877Speter/* cleanup for sockets */ 32251877Speterstatic apr_status_t clean_skt(void *data) 33251877Speter{ 34251877Speter serf_connection_t *conn = data; 35251877Speter apr_status_t status = APR_SUCCESS; 36251877Speter 37251877Speter if (conn->skt) { 38251877Speter serf__log_skt(SOCK_VERBOSE, __FILE__, conn->skt, "cleanup - "); 39251877Speter status = apr_socket_close(conn->skt); 40251877Speter conn->skt = NULL; 41251877Speter serf__log_nopref(SOCK_VERBOSE, "closed socket, status %d\n", status); 42251877Speter } 43251877Speter 44251877Speter return status; 45251877Speter} 46251877Speter 47251877Speterstatic apr_status_t clean_resp(void *data) 48251877Speter{ 49251877Speter serf_request_t *request = data; 50251877Speter 51251877Speter /* The request's RESPOOL is being cleared. */ 52251877Speter 53251877Speter /* If the response has allocated some buckets, then destroy them (since 54251877Speter the bucket may hold resources other than memory in RESPOOL). Also 55251877Speter make sure to set their fields to NULL so connection closure does 56251877Speter not attempt to free them again. */ 57251877Speter if (request->resp_bkt) { 58251877Speter serf_bucket_destroy(request->resp_bkt); 59251877Speter request->resp_bkt = NULL; 60251877Speter } 61251877Speter if (request->req_bkt) { 62251877Speter serf_bucket_destroy(request->req_bkt); 63251877Speter request->req_bkt = NULL; 64251877Speter } 65251877Speter 66251877Speter /* ### should we worry about debug stuff, like that performed in 67251877Speter ### destroy_request()? should we worry about calling req->handler 68251877Speter ### to notify this "cancellation" due to pool clearing? */ 69251877Speter 70251877Speter /* This pool just got cleared/destroyed. Don't try to destroy the pool 71251877Speter (again) when the request is canceled. */ 72251877Speter request->respool = NULL; 73251877Speter 74251877Speter return APR_SUCCESS; 75251877Speter} 76251877Speter 77251877Speter/* cleanup for conns */ 78251877Speterstatic apr_status_t clean_conn(void *data) 79251877Speter{ 80251877Speter serf_connection_t *conn = data; 81251877Speter 82251877Speter serf__log(CONN_VERBOSE, __FILE__, "cleaning up connection 0x%x\n", 83251877Speter conn); 84251877Speter serf_connection_close(conn); 85251877Speter 86251877Speter return APR_SUCCESS; 87251877Speter} 88251877Speter 89262324Speter/* Check if there is data waiting to be sent over the socket. This can happen 90262324Speter in two situations: 91262324Speter - The connection queue has atleast one request with unwritten data. 92262324Speter - All requests are written and the ssl layer wrote some data while reading 93262324Speter the response. This can happen when the server triggers a renegotiation, 94262324Speter e.g. after the first and only request on that connection was received. 95262324Speter Returns 1 if data is pending on CONN, NULL if not. 96262324Speter If NEXT_REQ is not NULL, it will be filled in with the next available request 97262324Speter with unwritten data. */ 98262324Speterstatic int 99262324Speterrequest_or_data_pending(serf_request_t **next_req, serf_connection_t *conn) 100262324Speter{ 101262324Speter serf_request_t *request = conn->requests; 102262324Speter 103262324Speter while (request != NULL && request->req_bkt == NULL && 104262324Speter request->writing_started) 105262324Speter request = request->next; 106262324Speter 107262324Speter if (next_req) 108262324Speter *next_req = request; 109262324Speter 110262324Speter if (request != NULL) { 111262324Speter return 1; 112262324Speter } else if (conn->ostream_head) { 113262324Speter const char *dummy; 114262324Speter apr_size_t len; 115262324Speter apr_status_t status; 116262324Speter 117262324Speter status = serf_bucket_peek(conn->ostream_head, &dummy, 118262324Speter &len); 119262324Speter if (!SERF_BUCKET_READ_ERROR(status) && len) { 120262324Speter serf__log_skt(CONN_VERBOSE, __FILE__, conn->skt, 121262324Speter "All requests written but still data pending.\n"); 122262324Speter return 1; 123262324Speter } 124262324Speter } 125262324Speter 126262324Speter return 0; 127262324Speter} 128262324Speter 129251877Speter/* Update the pollset for this connection. We tweak the pollset based on 130251877Speter * whether we want to read and/or write, given conditions within the 131251877Speter * connection. If the connection is not (yet) in the pollset, then it 132251877Speter * will be added. 133251877Speter */ 134251877Speterapr_status_t serf__conn_update_pollset(serf_connection_t *conn) 135251877Speter{ 136251877Speter serf_context_t *ctx = conn->ctx; 137251877Speter apr_status_t status; 138251877Speter apr_pollfd_t desc = { 0 }; 139251877Speter 140251877Speter if (!conn->skt) { 141251877Speter return APR_SUCCESS; 142251877Speter } 143251877Speter 144251877Speter /* Remove the socket from the poll set. */ 145251877Speter desc.desc_type = APR_POLL_SOCKET; 146251877Speter desc.desc.s = conn->skt; 147251877Speter desc.reqevents = conn->reqevents; 148251877Speter 149251877Speter status = ctx->pollset_rm(ctx->pollset_baton, 150362181Sdim &desc, &conn->baton); 151251877Speter if (status && !APR_STATUS_IS_NOTFOUND(status)) 152251877Speter return status; 153251877Speter 154251877Speter /* Now put it back in with the correct read/write values. */ 155251877Speter desc.reqevents = APR_POLLHUP | APR_POLLERR; 156251877Speter if (conn->requests && 157251877Speter conn->state != SERF_CONN_INIT) { 158251877Speter /* If there are any outstanding events, then we want to read. */ 159251877Speter /* ### not true. we only want to read IF we have sent some data */ 160251877Speter desc.reqevents |= APR_POLLIN; 161251877Speter 162253895Speter /* Don't write if OpenSSL told us that it needs to read data first. */ 163253895Speter if (conn->stop_writing != 1) { 164251877Speter 165253895Speter /* If the connection is not closing down and 166253895Speter * has unwritten data or 167253895Speter * there are any requests that still have buckets to write out, 168253895Speter * then we want to write. 169253895Speter */ 170253895Speter if (conn->vec_len && 171253895Speter conn->state != SERF_CONN_CLOSING) 172253895Speter desc.reqevents |= APR_POLLOUT; 173253895Speter else { 174253895Speter 175253895Speter if ((conn->probable_keepalive_limit && 176253895Speter conn->completed_requests > conn->probable_keepalive_limit) || 177253895Speter (conn->max_outstanding_requests && 178253895Speter conn->completed_requests - conn->completed_responses >= 179251877Speter conn->max_outstanding_requests)) { 180253895Speter /* we wouldn't try to write any way right now. */ 181253895Speter } 182262324Speter else if (request_or_data_pending(NULL, conn)) { 183262324Speter desc.reqevents |= APR_POLLOUT; 184262324Speter } 185251877Speter } 186251877Speter } 187251877Speter } 188251877Speter 189251877Speter /* If we can have async responses, always look for something to read. */ 190251877Speter if (conn->async_responses) { 191251877Speter desc.reqevents |= APR_POLLIN; 192251877Speter } 193251877Speter 194251877Speter /* save our reqevents, so we can pass it in to remove later. */ 195251877Speter conn->reqevents = desc.reqevents; 196251877Speter 197251877Speter /* Note: even if we don't want to read/write this socket, we still 198251877Speter * want to poll it for hangups and errors. 199251877Speter */ 200251877Speter return ctx->pollset_add(ctx->pollset_baton, 201251877Speter &desc, &conn->baton); 202251877Speter} 203251877Speter 204251877Speter#ifdef SERF_DEBUG_BUCKET_USE 205251877Speter 206251877Speter/* Make sure all response buckets were drained. */ 207251877Speterstatic void check_buckets_drained(serf_connection_t *conn) 208251877Speter{ 209251877Speter serf_request_t *request = conn->requests; 210251877Speter 211251877Speter for ( ; request ; request = request->next ) { 212251877Speter if (request->resp_bkt != NULL) { 213251877Speter /* ### crap. can't do this. this allocator may have un-drained 214251877Speter * ### REQUEST buckets. 215251877Speter */ 216251877Speter /* serf_debug__entered_loop(request->resp_bkt->allocator); */ 217251877Speter /* ### for now, pretend we closed the conn (resets the tracking) */ 218251877Speter serf_debug__closed_conn(request->resp_bkt->allocator); 219251877Speter } 220251877Speter } 221251877Speter} 222251877Speter 223251877Speter#endif 224251877Speter 225253895Speterstatic void destroy_ostream(serf_connection_t *conn) 226253895Speter{ 227253895Speter if (conn->ostream_head != NULL) { 228253895Speter serf_bucket_destroy(conn->ostream_head); 229253895Speter conn->ostream_head = NULL; 230253895Speter conn->ostream_tail = NULL; 231253895Speter } 232253895Speter} 233253895Speter 234253895Speterstatic apr_status_t detect_eof(void *baton, serf_bucket_t *aggregate_bucket) 235253895Speter{ 236253895Speter serf_connection_t *conn = baton; 237253895Speter conn->hit_eof = 1; 238253895Speter return APR_EAGAIN; 239253895Speter} 240253895Speter 241253895Speterstatic apr_status_t do_conn_setup(serf_connection_t *conn) 242253895Speter{ 243253895Speter apr_status_t status; 244253895Speter serf_bucket_t *ostream; 245253895Speter 246253895Speter if (conn->ostream_head == NULL) { 247253895Speter conn->ostream_head = serf_bucket_aggregate_create(conn->allocator); 248253895Speter } 249253895Speter 250253895Speter if (conn->ostream_tail == NULL) { 251253895Speter conn->ostream_tail = serf__bucket_stream_create(conn->allocator, 252253895Speter detect_eof, 253253895Speter conn); 254253895Speter } 255253895Speter 256253895Speter ostream = conn->ostream_tail; 257253895Speter 258253895Speter status = (*conn->setup)(conn->skt, 259253895Speter &conn->stream, 260253895Speter &ostream, 261253895Speter conn->setup_baton, 262253895Speter conn->pool); 263253895Speter if (status) { 264253895Speter /* extra destroy here since it wasn't added to the head bucket yet. */ 265253895Speter serf_bucket_destroy(conn->ostream_tail); 266253895Speter destroy_ostream(conn); 267253895Speter return status; 268253895Speter } 269253895Speter 270253895Speter serf_bucket_aggregate_append(conn->ostream_head, 271253895Speter ostream); 272253895Speter 273253895Speter return status; 274253895Speter} 275253895Speter 276253895Speter/* Set up the input and output stream buckets. 277253895Speter When a tunnel over an http proxy is needed, create a socket bucket and 278253895Speter empty aggregate bucket for sending and receiving unencrypted requests 279253895Speter over the socket. 280253895Speter 281253895Speter After the tunnel is there, or no tunnel was needed, ask the application 282253895Speter to create the input and output buckets, which should take care of the 283253895Speter [en/de]cryption. 284253895Speter */ 285253895Speter 286253895Speterstatic apr_status_t prepare_conn_streams(serf_connection_t *conn, 287253895Speter serf_bucket_t **istream, 288253895Speter serf_bucket_t **ostreamt, 289253895Speter serf_bucket_t **ostreamh) 290253895Speter{ 291253895Speter apr_status_t status; 292253895Speter 293253895Speter if (conn->stream == NULL) { 294253895Speter conn->latency = apr_time_now() - conn->connect_time; 295253895Speter } 296253895Speter 297253895Speter /* Do we need a SSL tunnel first? */ 298253895Speter if (conn->state == SERF_CONN_CONNECTED) { 299253895Speter /* If the connection does not have an associated bucket, then 300253895Speter * call the setup callback to get one. 301253895Speter */ 302253895Speter if (conn->stream == NULL) { 303253895Speter status = do_conn_setup(conn); 304253895Speter if (status) { 305253895Speter return status; 306253895Speter } 307253895Speter } 308253895Speter *ostreamt = conn->ostream_tail; 309253895Speter *ostreamh = conn->ostream_head; 310253895Speter *istream = conn->stream; 311253895Speter } else { 312253895Speter /* SSL tunnel needed and not set up yet, get a direct unencrypted 313253895Speter stream for this socket */ 314253895Speter if (conn->stream == NULL) { 315253895Speter *istream = serf_bucket_socket_create(conn->skt, 316253895Speter conn->allocator); 317253895Speter } 318253895Speter /* Don't create the ostream bucket chain including the ssl_encrypt 319253895Speter bucket yet. This ensure the CONNECT request is sent unencrypted 320253895Speter to the proxy. */ 321253895Speter *ostreamt = *ostreamh = conn->ssltunnel_ostream; 322253895Speter } 323253895Speter 324253895Speter return APR_SUCCESS; 325253895Speter} 326253895Speter 327251877Speter/* Create and connect sockets for any connections which don't have them 328251877Speter * yet. This is the core of our lazy-connect behavior. 329251877Speter */ 330251877Speterapr_status_t serf__open_connections(serf_context_t *ctx) 331251877Speter{ 332251877Speter int i; 333251877Speter 334251877Speter for (i = ctx->conns->nelts; i--; ) { 335251877Speter serf_connection_t *conn = GET_CONN(ctx, i); 336253895Speter serf__authn_info_t *authn_info; 337251877Speter apr_status_t status; 338251877Speter apr_socket_t *skt; 339251877Speter 340251877Speter conn->seen_in_pollset = 0; 341251877Speter 342251877Speter if (conn->skt != NULL) { 343251877Speter#ifdef SERF_DEBUG_BUCKET_USE 344251877Speter check_buckets_drained(conn); 345251877Speter#endif 346251877Speter continue; 347251877Speter } 348251877Speter 349251877Speter /* Delay opening until we have something to deliver! */ 350251877Speter if (conn->requests == NULL) { 351251877Speter continue; 352251877Speter } 353251877Speter 354251877Speter apr_pool_clear(conn->skt_pool); 355251877Speter apr_pool_cleanup_register(conn->skt_pool, conn, clean_skt, clean_skt); 356251877Speter 357251877Speter status = apr_socket_create(&skt, conn->address->family, 358251877Speter SOCK_STREAM, 359251877Speter#if APR_MAJOR_VERSION > 0 360251877Speter APR_PROTO_TCP, 361251877Speter#endif 362251877Speter conn->skt_pool); 363251877Speter serf__log(SOCK_VERBOSE, __FILE__, 364251877Speter "created socket for conn 0x%x, status %d\n", conn, status); 365251877Speter if (status != APR_SUCCESS) 366251877Speter return status; 367251877Speter 368251877Speter /* Set the socket to be non-blocking */ 369251877Speter if ((status = apr_socket_timeout_set(skt, 0)) != APR_SUCCESS) 370251877Speter return status; 371251877Speter 372251877Speter /* Disable Nagle's algorithm */ 373251877Speter if ((status = apr_socket_opt_set(skt, 374251877Speter APR_TCP_NODELAY, 1)) != APR_SUCCESS) 375251877Speter return status; 376251877Speter 377251877Speter /* Configured. Store it into the connection now. */ 378251877Speter conn->skt = skt; 379251877Speter 380251877Speter /* Remember time when we started connecting to server to calculate 381251877Speter network latency. */ 382251877Speter conn->connect_time = apr_time_now(); 383251877Speter 384251877Speter /* Now that the socket is set up, let's connect it. This should 385251877Speter * return immediately. 386251877Speter */ 387251877Speter status = apr_socket_connect(skt, conn->address); 388251877Speter serf__log_skt(SOCK_VERBOSE, __FILE__, skt, 389251877Speter "connected socket for conn 0x%x, status %d\n", 390251877Speter conn, status); 391253895Speter if (status != APR_SUCCESS) { 392251877Speter if (!APR_STATUS_IS_EINPROGRESS(status)) 393251877Speter return status; 394251877Speter } 395251877Speter 396251877Speter /* Flag our pollset as dirty now that we have a new socket. */ 397251877Speter conn->dirty_conn = 1; 398251877Speter ctx->dirty_pollset = 1; 399251877Speter 400251877Speter /* If the authentication was already started on another connection, 401251877Speter prepare this connection (it might be possible to skip some 402251877Speter part of the handshaking). */ 403251877Speter if (ctx->proxy_address) { 404253895Speter authn_info = &ctx->proxy_authn_info; 405253895Speter if (authn_info->scheme) { 406253895Speter authn_info->scheme->init_conn_func(authn_info->scheme, 407, 407253895Speter conn, conn->pool); 408253895Speter } 409251877Speter } 410251877Speter 411253895Speter authn_info = serf__get_authn_info_for_server(conn); 412253895Speter if (authn_info->scheme) { 413253895Speter authn_info->scheme->init_conn_func(authn_info->scheme, 401, 414253895Speter conn, conn->pool); 415253895Speter } 416251877Speter 417251877Speter /* Does this connection require a SSL tunnel over the proxy? */ 418251877Speter if (ctx->proxy_address && strcmp(conn->host_info.scheme, "https") == 0) 419251877Speter serf__ssltunnel_connect(conn); 420253895Speter else { 421253895Speter serf_bucket_t *dummy1, *dummy2; 422253895Speter 423251877Speter conn->state = SERF_CONN_CONNECTED; 424251877Speter 425253895Speter status = prepare_conn_streams(conn, &conn->stream, 426253895Speter &dummy1, &dummy2); 427253895Speter if (status) { 428253895Speter return status; 429253895Speter } 430253895Speter } 431251877Speter } 432251877Speter 433251877Speter return APR_SUCCESS; 434251877Speter} 435251877Speter 436262324Speterstatic apr_status_t no_more_writes(serf_connection_t *conn) 437251877Speter{ 438251877Speter /* Note that we should hold new requests until we open our new socket. */ 439251877Speter conn->state = SERF_CONN_CLOSING; 440262324Speter serf__log_skt(CONN_VERBOSE, __FILE__, conn->skt, 441262324Speter "stop writing on conn 0x%x\n", conn); 442251877Speter 443251877Speter /* Clear our iovec. */ 444251877Speter conn->vec_len = 0; 445251877Speter 446251877Speter /* Update the pollset to know we don't want to write on this socket any 447251877Speter * more. 448251877Speter */ 449251877Speter conn->dirty_conn = 1; 450251877Speter conn->ctx->dirty_pollset = 1; 451251877Speter return APR_SUCCESS; 452251877Speter} 453251877Speter 454251877Speter/* Read the 'Connection' header from the response. Return SERF_ERROR_CLOSING if 455251877Speter * the header contains value 'close' indicating the server is closing the 456251877Speter * connection right after this response. 457251877Speter * Otherwise returns APR_SUCCESS. 458251877Speter */ 459251877Speterstatic apr_status_t is_conn_closing(serf_bucket_t *response) 460251877Speter{ 461251877Speter serf_bucket_t *hdrs; 462251877Speter const char *val; 463251877Speter 464251877Speter hdrs = serf_bucket_response_get_headers(response); 465251877Speter val = serf_bucket_headers_get(hdrs, "Connection"); 466251877Speter if (val && strcasecmp("close", val) == 0) 467251877Speter { 468251877Speter return SERF_ERROR_CLOSING; 469251877Speter } 470251877Speter 471251877Speter return APR_SUCCESS; 472251877Speter} 473251877Speter 474251877Speterstatic void link_requests(serf_request_t **list, serf_request_t **tail, 475251877Speter serf_request_t *request) 476251877Speter{ 477251877Speter if (*list == NULL) { 478251877Speter *list = request; 479251877Speter *tail = request; 480251877Speter } 481251877Speter else { 482251877Speter (*tail)->next = request; 483251877Speter *tail = request; 484251877Speter } 485251877Speter} 486251877Speter 487251877Speterstatic apr_status_t destroy_request(serf_request_t *request) 488251877Speter{ 489251877Speter serf_connection_t *conn = request->conn; 490251877Speter 491251877Speter /* The request and response buckets are no longer needed, 492251877Speter nor is the request's pool. */ 493251877Speter if (request->resp_bkt) { 494251877Speter serf_debug__closed_conn(request->resp_bkt->allocator); 495251877Speter serf_bucket_destroy(request->resp_bkt); 496251877Speter request->resp_bkt = NULL; 497251877Speter } 498251877Speter if (request->req_bkt) { 499251877Speter serf_debug__closed_conn(request->req_bkt->allocator); 500251877Speter serf_bucket_destroy(request->req_bkt); 501251877Speter request->req_bkt = NULL; 502251877Speter } 503251877Speter 504251877Speter serf_debug__bucket_alloc_check(request->allocator); 505251877Speter if (request->respool) { 506251877Speter /* ### unregister the pool cleanup for self? */ 507251877Speter apr_pool_destroy(request->respool); 508251877Speter } 509251877Speter 510251877Speter serf_bucket_mem_free(conn->allocator, request); 511251877Speter 512251877Speter return APR_SUCCESS; 513251877Speter} 514251877Speter 515251877Speterstatic apr_status_t cancel_request(serf_request_t *request, 516251877Speter serf_request_t **list, 517251877Speter int notify_request) 518251877Speter{ 519251877Speter /* If we haven't run setup, then we won't have a handler to call. */ 520251877Speter if (request->handler && notify_request) { 521251877Speter /* We actually don't care what the handler returns. 522251877Speter * We have bigger matters at hand. 523251877Speter */ 524251877Speter (*request->handler)(request, NULL, request->handler_baton, 525251877Speter request->respool); 526251877Speter } 527251877Speter 528251877Speter if (*list == request) { 529251877Speter *list = request->next; 530251877Speter } 531251877Speter else { 532251877Speter serf_request_t *scan = *list; 533251877Speter 534251877Speter while (scan->next && scan->next != request) 535251877Speter scan = scan->next; 536251877Speter 537251877Speter if (scan->next) { 538251877Speter scan->next = scan->next->next; 539251877Speter } 540251877Speter } 541251877Speter 542251877Speter return destroy_request(request); 543251877Speter} 544251877Speter 545251877Speterstatic apr_status_t remove_connection(serf_context_t *ctx, 546251877Speter serf_connection_t *conn) 547251877Speter{ 548251877Speter apr_pollfd_t desc = { 0 }; 549251877Speter 550251877Speter desc.desc_type = APR_POLL_SOCKET; 551251877Speter desc.desc.s = conn->skt; 552251877Speter desc.reqevents = conn->reqevents; 553251877Speter 554251877Speter return ctx->pollset_rm(ctx->pollset_baton, 555362181Sdim &desc, &conn->baton); 556251877Speter} 557251877Speter 558251877Speter/* A socket was closed, inform the application. */ 559251877Speterstatic void handle_conn_closed(serf_connection_t *conn, apr_status_t status) 560251877Speter{ 561251877Speter (*conn->closed)(conn, conn->closed_baton, status, 562251877Speter conn->pool); 563251877Speter} 564251877Speter 565251877Speterstatic apr_status_t reset_connection(serf_connection_t *conn, 566251877Speter int requeue_requests) 567251877Speter{ 568251877Speter serf_context_t *ctx = conn->ctx; 569251877Speter apr_status_t status; 570251877Speter serf_request_t *old_reqs; 571251877Speter 572251877Speter conn->probable_keepalive_limit = conn->completed_responses; 573251877Speter conn->completed_requests = 0; 574251877Speter conn->completed_responses = 0; 575251877Speter 576251877Speter old_reqs = conn->requests; 577251877Speter 578251877Speter conn->requests = NULL; 579251877Speter conn->requests_tail = NULL; 580251877Speter 581251877Speter /* Handle all outstanding requests. These have either not been written yet, 582251877Speter or have been written but the expected reply wasn't received yet. */ 583251877Speter while (old_reqs) { 584251877Speter /* If we haven't started to write the connection, bring it over 585251877Speter * unchanged to our new socket. 586262324Speter * Do not copy a CONNECT request to the new connection, the ssl tunnel 587262324Speter * setup code will create a new CONNECT request already. 588251877Speter */ 589262324Speter if (requeue_requests && !old_reqs->writing_started && 590262324Speter !old_reqs->ssltunnel) { 591262324Speter 592251877Speter serf_request_t *req = old_reqs; 593251877Speter old_reqs = old_reqs->next; 594251877Speter req->next = NULL; 595251877Speter link_requests(&conn->requests, &conn->requests_tail, req); 596251877Speter } 597251877Speter else { 598251877Speter /* Request has been consumed, or we don't want to requeue the 599251877Speter request. Either way, inform the application that the request 600251877Speter is cancelled. */ 601251877Speter cancel_request(old_reqs, &old_reqs, requeue_requests); 602251877Speter } 603251877Speter } 604251877Speter 605251877Speter /* Requests queue has been prepared for a new socket, close the old one. */ 606251877Speter if (conn->skt != NULL) { 607251877Speter remove_connection(ctx, conn); 608251877Speter status = apr_socket_close(conn->skt); 609251877Speter serf__log_skt(SOCK_VERBOSE, __FILE__, conn->skt, 610251877Speter "closed socket, status %d\n", status); 611251877Speter if (conn->closed != NULL) { 612251877Speter handle_conn_closed(conn, status); 613251877Speter } 614251877Speter conn->skt = NULL; 615251877Speter } 616251877Speter 617251877Speter if (conn->stream != NULL) { 618251877Speter serf_bucket_destroy(conn->stream); 619251877Speter conn->stream = NULL; 620251877Speter } 621251877Speter 622251877Speter destroy_ostream(conn); 623251877Speter 624251877Speter /* Don't try to resume any writes */ 625251877Speter conn->vec_len = 0; 626251877Speter 627251877Speter conn->dirty_conn = 1; 628251877Speter conn->ctx->dirty_pollset = 1; 629251877Speter conn->state = SERF_CONN_INIT; 630251877Speter 631362181Sdim conn->hit_eof = 0; 632362181Sdim conn->connect_time = 0; 633362181Sdim conn->latency = -1; 634362181Sdim conn->stop_writing = 0; 635362181Sdim 636251877Speter serf__log(CONN_VERBOSE, __FILE__, "reset connection 0x%x\n", conn); 637251877Speter 638251877Speter conn->status = APR_SUCCESS; 639251877Speter 640251877Speter /* Let our context know that we've 'reset' the socket already. */ 641251877Speter conn->seen_in_pollset |= APR_POLLHUP; 642251877Speter 643251877Speter /* Found the connection. Closed it. All done. */ 644251877Speter return APR_SUCCESS; 645251877Speter} 646251877Speter 647251877Speterstatic apr_status_t socket_writev(serf_connection_t *conn) 648251877Speter{ 649251877Speter apr_size_t written; 650251877Speter apr_status_t status; 651251877Speter 652251877Speter status = apr_socket_sendv(conn->skt, conn->vec, 653251877Speter conn->vec_len, &written); 654253895Speter if (status && !APR_STATUS_IS_EAGAIN(status)) 655251877Speter serf__log_skt(SOCK_VERBOSE, __FILE__, conn->skt, 656251877Speter "socket_sendv error %d\n", status); 657251877Speter 658251877Speter /* did we write everything? */ 659251877Speter if (written) { 660251877Speter apr_size_t len = 0; 661251877Speter int i; 662251877Speter 663251877Speter serf__log_skt(SOCK_MSG_VERBOSE, __FILE__, conn->skt, 664251877Speter "--- socket_sendv:\n"); 665251877Speter 666251877Speter for (i = 0; i < conn->vec_len; i++) { 667251877Speter len += conn->vec[i].iov_len; 668251877Speter if (written < len) { 669251877Speter serf__log_nopref(SOCK_MSG_VERBOSE, "%.*s", 670251877Speter conn->vec[i].iov_len - (len - written), 671251877Speter conn->vec[i].iov_base); 672251877Speter if (i) { 673251877Speter memmove(conn->vec, &conn->vec[i], 674251877Speter sizeof(struct iovec) * (conn->vec_len - i)); 675251877Speter conn->vec_len -= i; 676251877Speter } 677251877Speter conn->vec[0].iov_base = (char *)conn->vec[0].iov_base + (conn->vec[0].iov_len - (len - written)); 678251877Speter conn->vec[0].iov_len = len - written; 679251877Speter break; 680251877Speter } else { 681251877Speter serf__log_nopref(SOCK_MSG_VERBOSE, "%.*s", 682251877Speter conn->vec[i].iov_len, conn->vec[i].iov_base); 683251877Speter } 684251877Speter } 685251877Speter if (len == written) { 686251877Speter conn->vec_len = 0; 687251877Speter } 688251877Speter serf__log_nopref(SOCK_MSG_VERBOSE, "-(%d)-\n", written); 689251877Speter 690251877Speter /* Log progress information */ 691251877Speter serf__context_progress_delta(conn->ctx, 0, written); 692251877Speter } 693251877Speter 694251877Speter return status; 695251877Speter} 696251877Speter 697253895Speterstatic apr_status_t setup_request(serf_request_t *request) 698251877Speter{ 699253895Speter serf_connection_t *conn = request->conn; 700251877Speter apr_status_t status; 701251877Speter 702253895Speter /* Now that we are about to serve the request, allocate a pool. */ 703253895Speter apr_pool_create(&request->respool, conn->pool); 704253895Speter request->allocator = serf_bucket_allocator_create(request->respool, 705253895Speter NULL, NULL); 706253895Speter apr_pool_cleanup_register(request->respool, request, 707253895Speter clean_resp, clean_resp); 708251877Speter 709253895Speter /* Fill in the rest of the values for the request. */ 710253895Speter status = request->setup(request, request->setup_baton, 711253895Speter &request->req_bkt, 712253895Speter &request->acceptor, 713253895Speter &request->acceptor_baton, 714253895Speter &request->handler, 715253895Speter &request->handler_baton, 716253895Speter request->respool); 717251877Speter return status; 718251877Speter} 719251877Speter 720251877Speter/* write data out to the connection */ 721251877Speterstatic apr_status_t write_to_connection(serf_connection_t *conn) 722251877Speter{ 723251877Speter if (conn->probable_keepalive_limit && 724251877Speter conn->completed_requests > conn->probable_keepalive_limit) { 725251877Speter 726251877Speter conn->dirty_conn = 1; 727251877Speter conn->ctx->dirty_pollset = 1; 728251877Speter 729251877Speter /* backoff for now. */ 730251877Speter return APR_SUCCESS; 731251877Speter } 732251877Speter 733251877Speter /* Keep reading and sending until we run out of stuff to read, or 734251877Speter * writing would block. 735251877Speter */ 736251877Speter while (1) { 737262324Speter serf_request_t *request; 738251877Speter int stop_reading = 0; 739251877Speter apr_status_t status; 740251877Speter apr_status_t read_status; 741262324Speter serf_bucket_t *ostreamt; 742262324Speter serf_bucket_t *ostreamh; 743251877Speter int max_outstanding_requests = conn->max_outstanding_requests; 744251877Speter 745251877Speter /* If we're setting up an ssl tunnel, we can't send real requests 746251877Speter at yet, as they need to be encrypted and our encrypt buckets 747251877Speter aren't created yet as we still need to read the unencrypted 748251877Speter response of the CONNECT request. */ 749251877Speter if (conn->state != SERF_CONN_CONNECTED) 750251877Speter max_outstanding_requests = 1; 751251877Speter 752251877Speter if (max_outstanding_requests && 753251877Speter conn->completed_requests - 754251877Speter conn->completed_responses >= max_outstanding_requests) { 755251877Speter /* backoff for now. */ 756251877Speter return APR_SUCCESS; 757251877Speter } 758251877Speter 759251877Speter /* If we have unwritten data, then write what we can. */ 760251877Speter while (conn->vec_len) { 761251877Speter status = socket_writev(conn); 762251877Speter 763251877Speter /* If the write would have blocked, then we're done. Don't try 764251877Speter * to write anything else to the socket. 765251877Speter */ 766251877Speter if (APR_STATUS_IS_EAGAIN(status)) 767251877Speter return APR_SUCCESS; 768251877Speter if (APR_STATUS_IS_EPIPE(status) || 769251877Speter APR_STATUS_IS_ECONNRESET(status) || 770251877Speter APR_STATUS_IS_ECONNABORTED(status)) 771262324Speter return no_more_writes(conn); 772251877Speter if (status) 773251877Speter return status; 774251877Speter } 775251877Speter /* ### can we have a short write, yet no EAGAIN? a short write 776251877Speter ### would imply unwritten_len > 0 ... */ 777251877Speter /* assert: unwritten_len == 0. */ 778251877Speter 779251877Speter /* We may need to move forward to a request which has something 780251877Speter * to write. 781251877Speter */ 782262324Speter if (!request_or_data_pending(&request, conn)) { 783251877Speter /* No more requests (with data) are registered with the 784262324Speter * connection, and no data is pending on the outgoing stream. 785262324Speter * Let's update the pollset so that we don't try to write to this 786262324Speter * socket again. 787251877Speter */ 788251877Speter conn->dirty_conn = 1; 789251877Speter conn->ctx->dirty_pollset = 1; 790251877Speter return APR_SUCCESS; 791251877Speter } 792251877Speter 793251877Speter status = prepare_conn_streams(conn, &conn->stream, &ostreamt, &ostreamh); 794251877Speter if (status) { 795251877Speter return status; 796251877Speter } 797251877Speter 798262324Speter if (request) { 799262324Speter if (request->req_bkt == NULL) { 800262324Speter read_status = setup_request(request); 801262324Speter if (read_status) { 802262324Speter /* Something bad happened. Propagate any errors. */ 803262324Speter return read_status; 804262324Speter } 805251877Speter } 806251877Speter 807262324Speter if (!request->writing_started) { 808262324Speter request->writing_started = 1; 809262324Speter serf_bucket_aggregate_append(ostreamt, request->req_bkt); 810262324Speter } 811251877Speter } 812251877Speter 813251877Speter /* ### optimize at some point by using read_for_sendfile */ 814253895Speter /* TODO: now that read_iovec will effectively try to return as much 815253895Speter data as available, we probably don't want to read ALL_AVAIL, but 816253895Speter a lower number, like the size of one or a few TCP packets, the 817253895Speter available TCP buffer size ... */ 818251877Speter read_status = serf_bucket_read_iovec(ostreamh, 819251877Speter SERF_READ_ALL_AVAIL, 820251877Speter IOV_MAX, 821251877Speter conn->vec, 822251877Speter &conn->vec_len); 823251877Speter 824251877Speter if (!conn->hit_eof) { 825253895Speter if (APR_STATUS_IS_EAGAIN(read_status)) { 826251877Speter /* We read some stuff, but should not try to read again. */ 827251877Speter stop_reading = 1; 828253895Speter } 829253895Speter else if (read_status == SERF_ERROR_WAIT_CONN) { 830253895Speter /* The bucket told us that it can't provide more data until 831253895Speter more data is read from the socket. This normally happens 832253895Speter during a SSL handshake. 833251877Speter 834253895Speter We should avoid looking for writability for a while so 835253895Speter that (hopefully) something will appear in the bucket so 836253895Speter we can actually write something. otherwise, we could 837253895Speter end up in a CPU spin: socket wants something, but we 838253895Speter don't have anything (and keep returning EAGAIN) 839253895Speter */ 840253895Speter conn->stop_writing = 1; 841253895Speter conn->dirty_conn = 1; 842253895Speter conn->ctx->dirty_pollset = 1; 843251877Speter } 844251877Speter else if (read_status && !APR_STATUS_IS_EOF(read_status)) { 845251877Speter /* Something bad happened. Propagate any errors. */ 846251877Speter return read_status; 847251877Speter } 848251877Speter } 849251877Speter 850251877Speter /* If we got some data, then deliver it. */ 851251877Speter /* ### what to do if we got no data?? is that a problem? */ 852251877Speter if (conn->vec_len > 0) { 853251877Speter status = socket_writev(conn); 854251877Speter 855251877Speter /* If we can't write any more, or an error occurred, then 856251877Speter * we're done here. 857251877Speter */ 858251877Speter if (APR_STATUS_IS_EAGAIN(status)) 859251877Speter return APR_SUCCESS; 860251877Speter if (APR_STATUS_IS_EPIPE(status)) 861262324Speter return no_more_writes(conn); 862251877Speter if (APR_STATUS_IS_ECONNRESET(status) || 863251877Speter APR_STATUS_IS_ECONNABORTED(status)) { 864262324Speter return no_more_writes(conn); 865251877Speter } 866251877Speter if (status) 867251877Speter return status; 868251877Speter } 869251877Speter 870251877Speter if (read_status == SERF_ERROR_WAIT_CONN) { 871251877Speter stop_reading = 1; 872253895Speter conn->stop_writing = 1; 873253895Speter conn->dirty_conn = 1; 874253895Speter conn->ctx->dirty_pollset = 1; 875251877Speter } 876262324Speter else if (request && read_status && conn->hit_eof && 877262324Speter conn->vec_len == 0) { 878251877Speter /* If we hit the end of the request bucket and all of its data has 879251877Speter * been written, then clear it out to signify that we're done 880251877Speter * sending the request. On the next iteration through this loop: 881251877Speter * - if there are remaining bytes they will be written, and as the 882251877Speter * request bucket will be completely read it will be destroyed then. 883251877Speter * - we'll see if there are other requests that need to be sent 884251877Speter * ("pipelining"). 885251877Speter */ 886251877Speter conn->hit_eof = 0; 887251877Speter serf_bucket_destroy(request->req_bkt); 888251877Speter request->req_bkt = NULL; 889251877Speter 890251877Speter /* If our connection has async responses enabled, we're not 891251877Speter * going to get a reply back, so kill the request. 892251877Speter */ 893251877Speter if (conn->async_responses) { 894251877Speter conn->requests = request->next; 895251877Speter destroy_request(request); 896251877Speter } 897251877Speter 898251877Speter conn->completed_requests++; 899251877Speter 900251877Speter if (conn->probable_keepalive_limit && 901251877Speter conn->completed_requests > conn->probable_keepalive_limit) { 902251877Speter /* backoff for now. */ 903251877Speter stop_reading = 1; 904251877Speter } 905251877Speter } 906251877Speter 907251877Speter if (stop_reading) { 908251877Speter return APR_SUCCESS; 909251877Speter } 910251877Speter } 911251877Speter /* NOTREACHED */ 912251877Speter} 913251877Speter 914251877Speter/* A response message was received from the server, so call 915251877Speter the handler as specified on the original request. */ 916251877Speterstatic apr_status_t handle_response(serf_request_t *request, 917251877Speter apr_pool_t *pool) 918251877Speter{ 919251877Speter apr_status_t status = APR_SUCCESS; 920251877Speter int consumed_response = 0; 921251877Speter 922251877Speter /* Only enable the new authentication framework if the program has 923251877Speter * registered an authentication credential callback. 924251877Speter * 925251877Speter * This permits older Serf apps to still handle authentication 926251877Speter * themselves by not registering credential callbacks. 927251877Speter */ 928251877Speter if (request->conn->ctx->cred_cb) { 929268960Speter status = serf__handle_auth_response(&consumed_response, 930268960Speter request, 931268960Speter request->resp_bkt, 932268960Speter request->handler_baton, 933268960Speter pool); 934251877Speter 935268960Speter /* If there was an error reading the response (maybe there wasn't 936268960Speter enough data available), don't bother passing the response to the 937268960Speter application. 938251877Speter 939268960Speter If the authentication was tried, but failed, pass the response 940268960Speter to the application, maybe it can do better. */ 941268960Speter if (status) { 942268960Speter return status; 943268960Speter } 944251877Speter } 945251877Speter 946251877Speter if (!consumed_response) { 947251877Speter return (*request->handler)(request, 948251877Speter request->resp_bkt, 949251877Speter request->handler_baton, 950251877Speter pool); 951251877Speter } 952251877Speter 953251877Speter return status; 954251877Speter} 955251877Speter 956251877Speter/* An async response message was received from the server. */ 957251877Speterstatic apr_status_t handle_async_response(serf_connection_t *conn, 958251877Speter apr_pool_t *pool) 959251877Speter{ 960251877Speter apr_status_t status; 961251877Speter 962251877Speter if (conn->current_async_response == NULL) { 963251877Speter conn->current_async_response = 964251877Speter (*conn->async_acceptor)(NULL, conn->stream, 965251877Speter conn->async_acceptor_baton, pool); 966251877Speter } 967251877Speter 968251877Speter status = (*conn->async_handler)(NULL, conn->current_async_response, 969251877Speter conn->async_handler_baton, pool); 970251877Speter 971251877Speter if (APR_STATUS_IS_EOF(status)) { 972251877Speter serf_bucket_destroy(conn->current_async_response); 973251877Speter conn->current_async_response = NULL; 974251877Speter status = APR_SUCCESS; 975251877Speter } 976251877Speter 977251877Speter return status; 978251877Speter} 979251877Speter 980253895Speter 981253895Speterapr_status_t 982253895Speterserf__provide_credentials(serf_context_t *ctx, 983253895Speter char **username, 984253895Speter char **password, 985253895Speter serf_request_t *request, void *baton, 986253895Speter int code, const char *authn_type, 987253895Speter const char *realm, 988253895Speter apr_pool_t *pool) 989253895Speter{ 990253895Speter serf_connection_t *conn = request->conn; 991253895Speter serf_request_t *authn_req = request; 992253895Speter apr_status_t status; 993253895Speter 994253895Speter if (request->ssltunnel == 1 && 995253895Speter conn->state == SERF_CONN_SETUP_SSLTUNNEL) { 996253895Speter /* This is a CONNECT request to set up an SSL tunnel over a proxy. 997253895Speter This request is created by serf, so if the proxy requires 998253895Speter authentication, we can't ask the application for credentials with 999253895Speter this request. 1000253895Speter 1001253895Speter Solution: setup the first request created by the application on 1002253895Speter this connection, and use that request and its handler_baton to 1003253895Speter call back to the application. */ 1004253895Speter 1005253895Speter authn_req = request->next; 1006253895Speter /* assert: app_request != NULL */ 1007253895Speter if (!authn_req) 1008253895Speter return APR_EGENERAL; 1009253895Speter 1010253895Speter if (!authn_req->req_bkt) { 1011253895Speter apr_status_t status; 1012253895Speter 1013253895Speter status = setup_request(authn_req); 1014253895Speter /* If we can't setup a request, don't bother setting up the 1015253895Speter ssl tunnel. */ 1016253895Speter if (status) 1017253895Speter return status; 1018253895Speter } 1019253895Speter } 1020253895Speter 1021253895Speter /* Ask the application. */ 1022253895Speter status = (*ctx->cred_cb)(username, password, 1023253895Speter authn_req, authn_req->handler_baton, 1024253895Speter code, authn_type, realm, pool); 1025253895Speter if (status) 1026253895Speter return status; 1027253895Speter 1028253895Speter return APR_SUCCESS; 1029253895Speter} 1030253895Speter 1031251877Speter/* read data from the connection */ 1032251877Speterstatic apr_status_t read_from_connection(serf_connection_t *conn) 1033251877Speter{ 1034251877Speter apr_status_t status; 1035251877Speter apr_pool_t *tmppool; 1036251877Speter int close_connection = FALSE; 1037251877Speter 1038251877Speter /* Whatever is coming in on the socket corresponds to the first request 1039251877Speter * on our chain. 1040251877Speter */ 1041251877Speter serf_request_t *request = conn->requests; 1042251877Speter 1043253895Speter /* If the stop_writing flag was set on the connection, reset it now because 1044253895Speter there is some data to read. */ 1045253895Speter if (conn->stop_writing) { 1046253895Speter conn->stop_writing = 0; 1047253895Speter conn->dirty_conn = 1; 1048253895Speter conn->ctx->dirty_pollset = 1; 1049253895Speter } 1050253895Speter 1051251877Speter /* assert: request != NULL */ 1052251877Speter 1053251877Speter if ((status = apr_pool_create(&tmppool, conn->pool)) != APR_SUCCESS) 1054251877Speter goto error; 1055251877Speter 1056251877Speter /* Invoke response handlers until we have no more work. */ 1057251877Speter while (1) { 1058251877Speter serf_bucket_t *dummy1, *dummy2; 1059251877Speter 1060251877Speter apr_pool_clear(tmppool); 1061251877Speter 1062251877Speter /* Only interested in the input stream here. */ 1063251877Speter status = prepare_conn_streams(conn, &conn->stream, &dummy1, &dummy2); 1064251877Speter if (status) { 1065251877Speter goto error; 1066251877Speter } 1067251877Speter 1068251877Speter /* We have a different codepath when we can have async responses. */ 1069251877Speter if (conn->async_responses) { 1070251877Speter /* TODO What about socket errors? */ 1071251877Speter status = handle_async_response(conn, tmppool); 1072251877Speter if (APR_STATUS_IS_EAGAIN(status)) { 1073251877Speter status = APR_SUCCESS; 1074251877Speter goto error; 1075251877Speter } 1076251877Speter if (status) { 1077251877Speter goto error; 1078251877Speter } 1079251877Speter continue; 1080251877Speter } 1081251877Speter 1082251877Speter /* We are reading a response for a request we haven't 1083251877Speter * written yet! 1084251877Speter * 1085251877Speter * This shouldn't normally happen EXCEPT: 1086251877Speter * 1087251877Speter * 1) when the other end has closed the socket and we're 1088251877Speter * pending an EOF return. 1089251877Speter * 2) Doing the initial SSL handshake - we'll get EAGAIN 1090251877Speter * as the SSL buckets will hide the handshake from us 1091251877Speter * but not return any data. 1092251877Speter * 3) When the server sends us an SSL alert. 1093251877Speter * 1094251877Speter * In these cases, we should not receive any actual user data. 1095251877Speter * 1096251877Speter * 4) When the server sends a error response, like 408 Request timeout. 1097251877Speter * This response should be passed to the application. 1098251877Speter * 1099251877Speter * If we see an EOF (due to either an expired timeout or the server 1100251877Speter * sending the SSL 'close notify' shutdown alert), we'll reset the 1101251877Speter * connection and open a new one. 1102251877Speter */ 1103262324Speter if (request->req_bkt || !request->writing_started) { 1104251877Speter const char *data; 1105251877Speter apr_size_t len; 1106251877Speter 1107251877Speter status = serf_bucket_peek(conn->stream, &data, &len); 1108251877Speter 1109251877Speter if (APR_STATUS_IS_EOF(status)) { 1110251877Speter reset_connection(conn, 1); 1111251877Speter status = APR_SUCCESS; 1112251877Speter goto error; 1113251877Speter } 1114251877Speter else if (APR_STATUS_IS_EAGAIN(status) && !len) { 1115251877Speter status = APR_SUCCESS; 1116251877Speter goto error; 1117251877Speter } else if (status && !APR_STATUS_IS_EAGAIN(status)) { 1118251877Speter /* Read error */ 1119251877Speter goto error; 1120251877Speter } 1121251877Speter 1122251877Speter /* Unexpected response from the server */ 1123251877Speter 1124251877Speter } 1125251877Speter 1126251877Speter /* If the request doesn't have a response bucket, then call the 1127251877Speter * acceptor to get one created. 1128251877Speter */ 1129251877Speter if (request->resp_bkt == NULL) { 1130251877Speter request->resp_bkt = (*request->acceptor)(request, conn->stream, 1131251877Speter request->acceptor_baton, 1132251877Speter tmppool); 1133251877Speter apr_pool_clear(tmppool); 1134251877Speter } 1135251877Speter 1136251877Speter status = handle_response(request, tmppool); 1137251877Speter 1138251877Speter /* Some systems will not generate a HUP poll event so we have to 1139251877Speter * handle the ECONNRESET issue and ECONNABORT here. 1140251877Speter */ 1141251877Speter if (APR_STATUS_IS_ECONNRESET(status) || 1142251877Speter APR_STATUS_IS_ECONNABORTED(status) || 1143251877Speter status == SERF_ERROR_REQUEST_LOST) { 1144251877Speter /* If the connection had ever been good, be optimistic & try again. 1145251877Speter * If it has never tried again (incl. a retry), fail. 1146251877Speter */ 1147251877Speter if (conn->completed_responses) { 1148251877Speter reset_connection(conn, 1); 1149251877Speter status = APR_SUCCESS; 1150251877Speter } 1151251877Speter else if (status == SERF_ERROR_REQUEST_LOST) { 1152251877Speter status = SERF_ERROR_ABORTED_CONNECTION; 1153251877Speter } 1154251877Speter goto error; 1155251877Speter } 1156251877Speter 1157251877Speter /* If our response handler says it can't do anything more, we now 1158251877Speter * treat that as a success. 1159251877Speter */ 1160251877Speter if (APR_STATUS_IS_EAGAIN(status)) { 1161262324Speter /* It is possible that while reading the response, the ssl layer 1162262324Speter has prepared some data to send. If this was the last request, 1163262324Speter serf will not check for socket writability, so force this here. 1164262324Speter */ 1165262324Speter if (request_or_data_pending(&request, conn) && !request) { 1166262324Speter conn->dirty_conn = 1; 1167262324Speter conn->ctx->dirty_pollset = 1; 1168262324Speter } 1169251877Speter status = APR_SUCCESS; 1170251877Speter goto error; 1171251877Speter } 1172251877Speter 1173251877Speter /* If we received APR_SUCCESS, run this loop again. */ 1174251877Speter if (!status) { 1175251877Speter continue; 1176251877Speter } 1177251877Speter 1178251877Speter close_connection = is_conn_closing(request->resp_bkt); 1179251877Speter 1180251877Speter if (!APR_STATUS_IS_EOF(status) && 1181251877Speter close_connection != SERF_ERROR_CLOSING) { 1182251877Speter /* Whether success, or an error, there is no more to do unless 1183251877Speter * this request has been completed. 1184251877Speter */ 1185251877Speter goto error; 1186251877Speter } 1187251877Speter 1188251877Speter /* The response has been fully-read, so that means the request has 1189251877Speter * either been fully-delivered (most likely), or that we don't need to 1190251877Speter * write the rest of it anymore, e.g. when a 408 Request timeout was 1191251877Speter $ received. 1192251877Speter * Remove it from our queue and loop to read another response. 1193251877Speter */ 1194251877Speter conn->requests = request->next; 1195251877Speter 1196251877Speter destroy_request(request); 1197251877Speter 1198251877Speter request = conn->requests; 1199251877Speter 1200251877Speter /* If we're truly empty, update our tail. */ 1201251877Speter if (request == NULL) { 1202251877Speter conn->requests_tail = NULL; 1203251877Speter } 1204251877Speter 1205251877Speter conn->completed_responses++; 1206251877Speter 1207251877Speter /* We've to rebuild pollset since completed_responses is changed. */ 1208251877Speter conn->dirty_conn = 1; 1209251877Speter conn->ctx->dirty_pollset = 1; 1210251877Speter 1211251877Speter /* This means that we're being advised that the connection is done. */ 1212251877Speter if (close_connection == SERF_ERROR_CLOSING) { 1213251877Speter reset_connection(conn, 1); 1214251877Speter if (APR_STATUS_IS_EOF(status)) 1215251877Speter status = APR_SUCCESS; 1216251877Speter goto error; 1217251877Speter } 1218251877Speter 1219251877Speter /* The server is suddenly deciding to serve more responses than we've 1220251877Speter * seen before. 1221251877Speter * 1222251877Speter * Let our requests go. 1223251877Speter */ 1224251877Speter if (conn->probable_keepalive_limit && 1225251877Speter conn->completed_responses > conn->probable_keepalive_limit) { 1226251877Speter conn->probable_keepalive_limit = 0; 1227251877Speter } 1228251877Speter 1229251877Speter /* If we just ran out of requests or have unwritten requests, then 1230251877Speter * update the pollset. We don't want to read from this socket any 1231251877Speter * more. We are definitely done with this loop, too. 1232251877Speter */ 1233262324Speter if (request == NULL || !request->writing_started) { 1234251877Speter conn->dirty_conn = 1; 1235251877Speter conn->ctx->dirty_pollset = 1; 1236251877Speter status = APR_SUCCESS; 1237251877Speter goto error; 1238251877Speter } 1239251877Speter } 1240251877Speter 1241251877Spetererror: 1242251877Speter apr_pool_destroy(tmppool); 1243251877Speter return status; 1244251877Speter} 1245251877Speter 1246251877Speter/* process all events on the connection */ 1247251877Speterapr_status_t serf__process_connection(serf_connection_t *conn, 1248251877Speter apr_int16_t events) 1249251877Speter{ 1250251877Speter apr_status_t status; 1251251877Speter 1252251877Speter /* POLLHUP/ERR should come after POLLIN so if there's an error message or 1253251877Speter * the like sitting on the connection, we give the app a chance to read 1254251877Speter * it before we trigger a reset condition. 1255251877Speter */ 1256251877Speter if ((events & APR_POLLIN) != 0) { 1257251877Speter if ((status = read_from_connection(conn)) != APR_SUCCESS) 1258251877Speter return status; 1259251877Speter 1260251877Speter /* If we decided to reset our connection, return now as we don't 1261251877Speter * want to write. 1262251877Speter */ 1263251877Speter if ((conn->seen_in_pollset & APR_POLLHUP) != 0) { 1264251877Speter return APR_SUCCESS; 1265251877Speter } 1266251877Speter } 1267251877Speter if ((events & APR_POLLHUP) != 0) { 1268251877Speter /* The connection got reset by the server. On Windows this can happen 1269251877Speter when all data is read, so just cleanup the connection and open 1270251877Speter a new one. 1271251877Speter If we haven't had any successful responses on this connection, 1272251877Speter then error out as it is likely a server issue. */ 1273251877Speter if (conn->completed_responses) { 1274251877Speter return reset_connection(conn, 1); 1275251877Speter } 1276251877Speter return SERF_ERROR_ABORTED_CONNECTION; 1277251877Speter } 1278251877Speter if ((events & APR_POLLERR) != 0) { 1279251877Speter /* We might be talking to a buggy HTTP server that doesn't 1280251877Speter * do lingering-close. (httpd < 2.1.8 does this.) 1281251877Speter * 1282251877Speter * See: 1283251877Speter * 1284251877Speter * http://issues.apache.org/bugzilla/show_bug.cgi?id=35292 1285251877Speter */ 1286251877Speter if (conn->completed_requests && !conn->probable_keepalive_limit) { 1287251877Speter return reset_connection(conn, 1); 1288251877Speter } 1289253895Speter#ifdef SO_ERROR 1290253895Speter /* If possible, get the error from the platform's socket layer and 1291253895Speter convert it to an APR status code. */ 1292253895Speter { 1293253895Speter apr_os_sock_t osskt; 1294253895Speter if (!apr_os_sock_get(&osskt, conn->skt)) { 1295253895Speter int error; 1296253895Speter apr_socklen_t l = sizeof(error); 1297253895Speter 1298262324Speter if (!getsockopt(osskt, SOL_SOCKET, SO_ERROR, (char*)&error, 1299262324Speter &l)) { 1300262324Speter status = APR_FROM_OS_ERROR(error); 1301262324Speter 1302262324Speter /* Handle fallback for multi-homed servers. 1303262324Speter 1304262324Speter ### Improve algorithm to find better than just 'next'? 1305262324Speter 1306262324Speter Current Windows versions already handle re-ordering for 1307262324Speter api users by using statistics on the recently failed 1308262324Speter connections to order the list of addresses. */ 1309262324Speter if (conn->completed_requests == 0 1310262324Speter && conn->address->next != NULL 1311262324Speter && (APR_STATUS_IS_ECONNREFUSED(status) 1312262324Speter || APR_STATUS_IS_TIMEUP(status) 1313262324Speter || APR_STATUS_IS_ENETUNREACH(status))) { 1314262324Speter 1315262324Speter conn->address = conn->address->next; 1316262324Speter return reset_connection(conn, 1); 1317262324Speter } 1318262324Speter 1319262324Speter return status; 1320262324Speter } 1321253895Speter } 1322253895Speter } 1323253895Speter#endif 1324251877Speter return APR_EGENERAL; 1325251877Speter } 1326251877Speter if ((events & APR_POLLOUT) != 0) { 1327251877Speter if ((status = write_to_connection(conn)) != APR_SUCCESS) 1328251877Speter return status; 1329251877Speter } 1330251877Speter return APR_SUCCESS; 1331251877Speter} 1332251877Speter 1333251877Speterserf_connection_t *serf_connection_create( 1334251877Speter serf_context_t *ctx, 1335251877Speter apr_sockaddr_t *address, 1336251877Speter serf_connection_setup_t setup, 1337251877Speter void *setup_baton, 1338251877Speter serf_connection_closed_t closed, 1339251877Speter void *closed_baton, 1340251877Speter apr_pool_t *pool) 1341251877Speter{ 1342251877Speter serf_connection_t *conn = apr_pcalloc(pool, sizeof(*conn)); 1343251877Speter 1344251877Speter conn->ctx = ctx; 1345251877Speter conn->status = APR_SUCCESS; 1346251877Speter /* Ignore server address if proxy was specified. */ 1347251877Speter conn->address = ctx->proxy_address ? ctx->proxy_address : address; 1348251877Speter conn->setup = setup; 1349251877Speter conn->setup_baton = setup_baton; 1350251877Speter conn->closed = closed; 1351251877Speter conn->closed_baton = closed_baton; 1352251877Speter conn->pool = pool; 1353251877Speter conn->allocator = serf_bucket_allocator_create(pool, NULL, NULL); 1354251877Speter conn->stream = NULL; 1355251877Speter conn->ostream_head = NULL; 1356251877Speter conn->ostream_tail = NULL; 1357251877Speter conn->baton.type = SERF_IO_CONN; 1358251877Speter conn->baton.u.conn = conn; 1359251877Speter conn->hit_eof = 0; 1360251877Speter conn->state = SERF_CONN_INIT; 1361251877Speter conn->latency = -1; /* unknown */ 1362251877Speter 1363251877Speter /* Create a subpool for our connection. */ 1364251877Speter apr_pool_create(&conn->skt_pool, conn->pool); 1365251877Speter 1366251877Speter /* register a cleanup */ 1367253895Speter apr_pool_cleanup_register(conn->pool, conn, clean_conn, 1368253895Speter apr_pool_cleanup_null); 1369251877Speter 1370251877Speter /* Add the connection to the context. */ 1371251877Speter *(serf_connection_t **)apr_array_push(ctx->conns) = conn; 1372251877Speter 1373251877Speter serf__log(CONN_VERBOSE, __FILE__, "created connection 0x%x\n", 1374251877Speter conn); 1375251877Speter 1376251877Speter return conn; 1377251877Speter} 1378251877Speter 1379251877Speterapr_status_t serf_connection_create2( 1380251877Speter serf_connection_t **conn, 1381251877Speter serf_context_t *ctx, 1382251877Speter apr_uri_t host_info, 1383251877Speter serf_connection_setup_t setup, 1384251877Speter void *setup_baton, 1385251877Speter serf_connection_closed_t closed, 1386251877Speter void *closed_baton, 1387251877Speter apr_pool_t *pool) 1388251877Speter{ 1389251877Speter apr_status_t status = APR_SUCCESS; 1390251877Speter serf_connection_t *c; 1391251877Speter apr_sockaddr_t *host_address = NULL; 1392251877Speter 1393251877Speter /* Set the port number explicitly, needed to create the socket later. */ 1394251877Speter if (!host_info.port) { 1395251877Speter host_info.port = apr_uri_port_of_scheme(host_info.scheme); 1396251877Speter } 1397251877Speter 1398251877Speter /* Only lookup the address of the server if no proxy server was 1399251877Speter configured. */ 1400251877Speter if (!ctx->proxy_address) { 1401251877Speter status = apr_sockaddr_info_get(&host_address, 1402251877Speter host_info.hostname, 1403251877Speter APR_UNSPEC, host_info.port, 0, pool); 1404251877Speter if (status) 1405251877Speter return status; 1406251877Speter } 1407251877Speter 1408251877Speter c = serf_connection_create(ctx, host_address, setup, setup_baton, 1409251877Speter closed, closed_baton, pool); 1410251877Speter 1411251877Speter /* We're not interested in the path following the hostname. */ 1412251877Speter c->host_url = apr_uri_unparse(c->pool, 1413251877Speter &host_info, 1414262324Speter APR_URI_UNP_OMITPATHINFO | 1415262324Speter APR_URI_UNP_OMITUSERINFO); 1416251877Speter 1417253895Speter /* Store the host info without the path on the connection. */ 1418253895Speter (void)apr_uri_parse(c->pool, c->host_url, &(c->host_info)); 1419253895Speter if (!c->host_info.port) { 1420253895Speter c->host_info.port = apr_uri_port_of_scheme(c->host_info.scheme); 1421253895Speter } 1422253895Speter 1423251877Speter *conn = c; 1424251877Speter 1425251877Speter return status; 1426251877Speter} 1427251877Speter 1428251877Speterapr_status_t serf_connection_reset( 1429251877Speter serf_connection_t *conn) 1430251877Speter{ 1431251877Speter return reset_connection(conn, 0); 1432251877Speter} 1433251877Speter 1434251877Speter 1435251877Speterapr_status_t serf_connection_close( 1436251877Speter serf_connection_t *conn) 1437251877Speter{ 1438251877Speter int i; 1439251877Speter serf_context_t *ctx = conn->ctx; 1440251877Speter apr_status_t status; 1441251877Speter 1442251877Speter for (i = ctx->conns->nelts; i--; ) { 1443251877Speter serf_connection_t *conn_seq = GET_CONN(ctx, i); 1444251877Speter 1445251877Speter if (conn_seq == conn) { 1446251877Speter while (conn->requests) { 1447251877Speter serf_request_cancel(conn->requests); 1448251877Speter } 1449251877Speter if (conn->skt != NULL) { 1450251877Speter remove_connection(ctx, conn); 1451251877Speter status = apr_socket_close(conn->skt); 1452251877Speter serf__log_skt(SOCK_VERBOSE, __FILE__, conn->skt, 1453251877Speter "closed socket, status %d\n", 1454251877Speter status); 1455251877Speter if (conn->closed != NULL) { 1456251877Speter handle_conn_closed(conn, status); 1457251877Speter } 1458251877Speter conn->skt = NULL; 1459251877Speter } 1460251877Speter if (conn->stream != NULL) { 1461251877Speter serf_bucket_destroy(conn->stream); 1462251877Speter conn->stream = NULL; 1463251877Speter } 1464251877Speter 1465251877Speter destroy_ostream(conn); 1466251877Speter 1467251877Speter /* Remove the connection from the context. We don't want to 1468251877Speter * deal with it any more. 1469251877Speter */ 1470251877Speter if (i < ctx->conns->nelts - 1) { 1471251877Speter /* move later connections over this one. */ 1472251877Speter memmove( 1473251877Speter &GET_CONN(ctx, i), 1474251877Speter &GET_CONN(ctx, i + 1), 1475251877Speter (ctx->conns->nelts - i - 1) * sizeof(serf_connection_t *)); 1476251877Speter } 1477251877Speter --ctx->conns->nelts; 1478251877Speter 1479251877Speter serf__log(CONN_VERBOSE, __FILE__, "closed connection 0x%x\n", 1480251877Speter conn); 1481251877Speter 1482251877Speter /* Found the connection. Closed it. All done. */ 1483251877Speter return APR_SUCCESS; 1484251877Speter } 1485251877Speter } 1486251877Speter 1487251877Speter /* We didn't find the specified connection. */ 1488251877Speter /* ### doc talks about this w.r.t poll structures. use something else? */ 1489251877Speter return APR_NOTFOUND; 1490251877Speter} 1491251877Speter 1492251877Speter 1493251877Spetervoid serf_connection_set_max_outstanding_requests( 1494251877Speter serf_connection_t *conn, 1495251877Speter unsigned int max_requests) 1496251877Speter{ 1497251877Speter if (max_requests == 0) 1498251877Speter serf__log_skt(CONN_VERBOSE, __FILE__, conn->skt, 1499251877Speter "Set max. nr. of outstanding requests for this " 1500251877Speter "connection to unlimited.\n"); 1501251877Speter else 1502251877Speter serf__log_skt(CONN_VERBOSE, __FILE__, conn->skt, 1503251877Speter "Limit max. nr. of outstanding requests for this " 1504251877Speter "connection to %u.\n", max_requests); 1505251877Speter 1506251877Speter conn->max_outstanding_requests = max_requests; 1507251877Speter} 1508251877Speter 1509251877Speter 1510251877Spetervoid serf_connection_set_async_responses( 1511251877Speter serf_connection_t *conn, 1512251877Speter serf_response_acceptor_t acceptor, 1513251877Speter void *acceptor_baton, 1514251877Speter serf_response_handler_t handler, 1515251877Speter void *handler_baton) 1516251877Speter{ 1517251877Speter conn->async_responses = 1; 1518251877Speter conn->async_acceptor = acceptor; 1519251877Speter conn->async_acceptor_baton = acceptor_baton; 1520251877Speter conn->async_handler = handler; 1521251877Speter conn->async_handler_baton = handler_baton; 1522251877Speter} 1523251877Speter 1524253895Speterstatic serf_request_t * 1525253895Spetercreate_request(serf_connection_t *conn, 1526253895Speter serf_request_setup_t setup, 1527253895Speter void *setup_baton, 1528253895Speter int priority, 1529253895Speter int ssltunnel) 1530251877Speter{ 1531251877Speter serf_request_t *request; 1532251877Speter 1533251877Speter request = serf_bucket_mem_alloc(conn->allocator, sizeof(*request)); 1534251877Speter request->conn = conn; 1535251877Speter request->setup = setup; 1536251877Speter request->setup_baton = setup_baton; 1537251877Speter request->handler = NULL; 1538251877Speter request->respool = NULL; 1539251877Speter request->req_bkt = NULL; 1540251877Speter request->resp_bkt = NULL; 1541253895Speter request->priority = priority; 1542262324Speter request->writing_started = 0; 1543253895Speter request->ssltunnel = ssltunnel; 1544251877Speter request->next = NULL; 1545262324Speter request->auth_baton = NULL; 1546251877Speter 1547253895Speter return request; 1548253895Speter} 1549253895Speter 1550253895Speterserf_request_t *serf_connection_request_create( 1551253895Speter serf_connection_t *conn, 1552253895Speter serf_request_setup_t setup, 1553253895Speter void *setup_baton) 1554253895Speter{ 1555253895Speter serf_request_t *request; 1556253895Speter 1557253895Speter request = create_request(conn, setup, setup_baton, 1558253895Speter 0, /* priority */ 1559253895Speter 0 /* ssl tunnel */); 1560253895Speter 1561251877Speter /* Link the request to the end of the request chain. */ 1562251877Speter link_requests(&conn->requests, &conn->requests_tail, request); 1563251877Speter 1564251877Speter /* Ensure our pollset becomes writable in context run */ 1565251877Speter conn->ctx->dirty_pollset = 1; 1566251877Speter conn->dirty_conn = 1; 1567251877Speter 1568251877Speter return request; 1569251877Speter} 1570251877Speter 1571253895Speterstatic serf_request_t * 1572253895Speterpriority_request_create(serf_connection_t *conn, 1573253895Speter int ssltunnelreq, 1574253895Speter serf_request_setup_t setup, 1575253895Speter void *setup_baton) 1576251877Speter{ 1577251877Speter serf_request_t *request; 1578251877Speter serf_request_t *iter, *prev; 1579251877Speter 1580253895Speter request = create_request(conn, setup, setup_baton, 1581253895Speter 1, /* priority */ 1582253895Speter ssltunnelreq); 1583251877Speter 1584251877Speter /* Link the new request after the last written request. */ 1585251877Speter iter = conn->requests; 1586251877Speter prev = NULL; 1587251877Speter 1588251877Speter /* Find a request that has data which needs to be delivered. */ 1589262324Speter while (iter != NULL && iter->req_bkt == NULL && iter->writing_started) { 1590251877Speter prev = iter; 1591251877Speter iter = iter->next; 1592251877Speter } 1593251877Speter 1594253895Speter /* A CONNECT request to setup an ssltunnel has absolute priority over all 1595253895Speter other requests on the connection, so: 1596253895Speter a. add it first to the queue 1597253895Speter b. ensure that other priority requests are added after the CONNECT 1598253895Speter request */ 1599253895Speter if (!request->ssltunnel) { 1600253895Speter /* Advance to next non priority request */ 1601253895Speter while (iter != NULL && iter->priority) { 1602253895Speter prev = iter; 1603253895Speter iter = iter->next; 1604253895Speter } 1605251877Speter } 1606251877Speter 1607251877Speter if (prev) { 1608251877Speter request->next = iter; 1609251877Speter prev->next = request; 1610251877Speter } else { 1611251877Speter request->next = iter; 1612251877Speter conn->requests = request; 1613251877Speter } 1614251877Speter 1615251877Speter /* Ensure our pollset becomes writable in context run */ 1616251877Speter conn->ctx->dirty_pollset = 1; 1617251877Speter conn->dirty_conn = 1; 1618251877Speter 1619251877Speter return request; 1620251877Speter} 1621251877Speter 1622253895Speterserf_request_t *serf_connection_priority_request_create( 1623253895Speter serf_connection_t *conn, 1624253895Speter serf_request_setup_t setup, 1625253895Speter void *setup_baton) 1626253895Speter{ 1627253895Speter return priority_request_create(conn, 1628253895Speter 0, /* not a ssltunnel CONNECT request */ 1629253895Speter setup, setup_baton); 1630253895Speter} 1631251877Speter 1632253895Speterserf_request_t *serf__ssltunnel_request_create(serf_connection_t *conn, 1633253895Speter serf_request_setup_t setup, 1634253895Speter void *setup_baton) 1635253895Speter{ 1636253895Speter return priority_request_create(conn, 1637253895Speter 1, /* This is a ssltunnel CONNECT request */ 1638253895Speter setup, setup_baton); 1639253895Speter} 1640253895Speter 1641251877Speterapr_status_t serf_request_cancel(serf_request_t *request) 1642251877Speter{ 1643251877Speter return cancel_request(request, &request->conn->requests, 0); 1644251877Speter} 1645251877Speter 1646251877Speterapr_status_t serf_request_is_written(serf_request_t *request) 1647251877Speter{ 1648262324Speter if (request->writing_started && !request->req_bkt) 1649251877Speter return APR_SUCCESS; 1650251877Speter 1651251877Speter return APR_EBUSY; 1652251877Speter} 1653251877Speter 1654251877Speterapr_pool_t *serf_request_get_pool(const serf_request_t *request) 1655251877Speter{ 1656251877Speter return request->respool; 1657251877Speter} 1658251877Speter 1659251877Speter 1660251877Speterserf_bucket_alloc_t *serf_request_get_alloc( 1661251877Speter const serf_request_t *request) 1662251877Speter{ 1663251877Speter return request->allocator; 1664251877Speter} 1665251877Speter 1666251877Speter 1667251877Speterserf_connection_t *serf_request_get_conn( 1668251877Speter const serf_request_t *request) 1669251877Speter{ 1670251877Speter return request->conn; 1671251877Speter} 1672251877Speter 1673251877Speter 1674251877Spetervoid serf_request_set_handler( 1675251877Speter serf_request_t *request, 1676251877Speter const serf_response_handler_t handler, 1677251877Speter const void **handler_baton) 1678251877Speter{ 1679251877Speter request->handler = handler; 1680251877Speter request->handler_baton = handler_baton; 1681251877Speter} 1682251877Speter 1683251877Speter 1684251877Speterserf_bucket_t *serf_request_bucket_request_create( 1685251877Speter serf_request_t *request, 1686251877Speter const char *method, 1687251877Speter const char *uri, 1688251877Speter serf_bucket_t *body, 1689251877Speter serf_bucket_alloc_t *allocator) 1690251877Speter{ 1691251877Speter serf_bucket_t *req_bkt, *hdrs_bkt; 1692251877Speter serf_connection_t *conn = request->conn; 1693251877Speter serf_context_t *ctx = conn->ctx; 1694253895Speter int ssltunnel; 1695251877Speter 1696253895Speter ssltunnel = ctx->proxy_address && 1697253895Speter (strcmp(conn->host_info.scheme, "https") == 0); 1698253895Speter 1699251877Speter req_bkt = serf_bucket_request_create(method, uri, body, allocator); 1700251877Speter hdrs_bkt = serf_bucket_request_get_headers(req_bkt); 1701251877Speter 1702253895Speter /* Use absolute uri's in requests to a proxy. USe relative uri's in 1703253895Speter requests directly to a server or sent through an SSL tunnel. */ 1704253895Speter if (ctx->proxy_address && conn->host_url && 1705253895Speter !(ssltunnel && !request->ssltunnel)) { 1706253895Speter 1707251877Speter serf_bucket_request_set_root(req_bkt, conn->host_url); 1708253895Speter } 1709251877Speter 1710251877Speter if (conn->host_info.hostinfo) 1711251877Speter serf_bucket_headers_setn(hdrs_bkt, "Host", 1712251877Speter conn->host_info.hostinfo); 1713251877Speter 1714253895Speter /* Setup server authorization headers, unless this is a CONNECT request. */ 1715253895Speter if (!request->ssltunnel) { 1716253895Speter serf__authn_info_t *authn_info; 1717253895Speter authn_info = serf__get_authn_info_for_server(conn); 1718253895Speter if (authn_info->scheme) 1719253895Speter authn_info->scheme->setup_request_func(HOST, 0, conn, request, 1720251877Speter method, uri, 1721251877Speter hdrs_bkt); 1722253895Speter } 1723251877Speter 1724253895Speter /* Setup proxy authorization headers. 1725253895Speter Don't set these headers on the requests to the server if we're using 1726253895Speter an SSL tunnel, only on the CONNECT request to setup the tunnel. */ 1727253895Speter if (ctx->proxy_authn_info.scheme) { 1728253895Speter if (strcmp(conn->host_info.scheme, "https") == 0) { 1729253895Speter if (request->ssltunnel) 1730253895Speter ctx->proxy_authn_info.scheme->setup_request_func(PROXY, 0, conn, 1731253895Speter request, 1732253895Speter method, uri, 1733253895Speter hdrs_bkt); 1734253895Speter } else { 1735253895Speter ctx->proxy_authn_info.scheme->setup_request_func(PROXY, 0, conn, 1736253895Speter request, 1737253895Speter method, uri, 1738253895Speter hdrs_bkt); 1739253895Speter } 1740253895Speter } 1741251877Speter 1742251877Speter return req_bkt; 1743251877Speter} 1744251877Speter 1745251877Speterapr_interval_time_t serf_connection_get_latency(serf_connection_t *conn) 1746251877Speter{ 1747251877Speter if (conn->ctx->proxy_address) { 1748251877Speter /* Detecting network latency for proxied connection is not implemented 1749251877Speter yet. */ 1750251877Speter return -1; 1751251877Speter } 1752251877Speter 1753251877Speter return conn->latency; 1754251877Speter} 1755