Mercurial > dovecot > core-2.2
view src/lib-http/http-client-private.h @ 19841:0101120789fb
lib-http: client: Gave request, connect and dns timeouts defaults that make more sense.
author | Stephan Bosch <stephan@rename-it.nl> |
---|---|
date | Fri, 26 Feb 2016 00:15:17 +0200 |
parents | 4487e5892f41 |
children | 3f6a74b9ce54 |
line wrap: on
line source
#ifndef HTTP_CLIENT_PRIVATE_H #define HTTP_CLIENT_PRIVATE_H #include "connection.h" #include "http-url.h" #include "http-client.h" #define HTTP_DEFAULT_PORT 80 #define HTTPS_DEFAULT_PORT 443 #define HTTP_CLIENT_CONTINUE_TIMEOUT_MSECS (1000*2) #define HTTP_CLIENT_DEFAULT_REQUEST_TIMEOUT_MSECS (1000*60*1) #define HTTP_CLIENT_DEFAULT_DNS_LOOKUP_TIMEOUT_MSECS (1000*10) #define HTTP_CLIENT_DEFAULT_BACKOFF_TIME_MSECS (100) #define HTTP_CLIENT_DEFAULT_BACKOFF_MAX_TIME_MSECS (1000*60) enum http_response_payload_type; struct http_client_host; struct http_client_queue; struct http_client_peer; struct http_client_connection; ARRAY_DEFINE_TYPE(http_client_host, struct http_client_host *); ARRAY_DEFINE_TYPE(http_client_queue, struct http_client_queue *); ARRAY_DEFINE_TYPE(http_client_peer, struct http_client_peer *); ARRAY_DEFINE_TYPE(http_client_connection, struct http_client_connection *); ARRAY_DEFINE_TYPE(http_client_request, struct http_client_request *); HASH_TABLE_DEFINE_TYPE(http_client_host, const char *, struct http_client_host *); HASH_TABLE_DEFINE_TYPE(http_client_peer, const struct http_client_peer_addr *, struct http_client_peer *); enum http_client_peer_addr_type { HTTP_CLIENT_PEER_ADDR_HTTP = 0, HTTP_CLIENT_PEER_ADDR_HTTPS, HTTP_CLIENT_PEER_ADDR_HTTPS_TUNNEL, HTTP_CLIENT_PEER_ADDR_RAW, HTTP_CLIENT_PEER_ADDR_UNIX, }; struct http_client_peer_addr { enum http_client_peer_addr_type type; union { struct { const char *https_name; /* TLS SNI */ struct ip_addr ip; in_port_t port; } tcp; struct { const char *path; } un; } a; }; struct http_client_request { pool_t pool; unsigned int refcount; const char *label; unsigned int id; struct http_client_request *prev, *next; const char *method, *target; struct http_url origin_url; const char *username, *password; const char *host_socket; const struct http_url *host_url; const char *authority; struct http_client *client; struct http_client_host *host; struct http_client_queue *queue; struct http_client_peer *peer; struct http_client_connection *conn; string_t *headers; time_t date; struct istream *payload_input; uoff_t payload_size, payload_offset; struct ostream *payload_output; struct timeval release_time; struct timeval submit_time; struct timeval sent_time; struct timeval response_time; struct timeval timeout_time; unsigned int timeout_msecs; unsigned int attempts; unsigned int redirects; unsigned int delayed_error_status; const char *delayed_error; http_client_request_callback_t *callback; void *context; void (*destroy_callback)(void *); void *destroy_context; enum http_request_state state; unsigned int have_hdr_authorization:1; unsigned int have_hdr_body_spec:1; unsigned int have_hdr_connection:1; unsigned int have_hdr_date:1; unsigned int have_hdr_expect:1; unsigned int have_hdr_host:1; unsigned int have_hdr_user_agent:1; unsigned int payload_sync:1; unsigned int payload_sync_continue:1; unsigned int payload_chunked:1; unsigned int payload_wait:1; unsigned int urgent:1; unsigned int submitted:1; unsigned int connect_tunnel:1; unsigned int connect_direct:1; unsigned int ssl_tunnel:1; }; struct http_client_connection { struct connection conn; struct http_client_peer *peer; struct http_client *client; unsigned int refcount; const char *label; unsigned int id; // DEBUG: identify parallel connections int connect_errno; struct timeval connect_start_timestamp; struct timeval connected_timestamp; struct http_client_request *connect_request; struct ssl_iostream *ssl_iostream; struct http_response_parser *http_parser; struct timeout *to_connect, *to_input, *to_idle, *to_response; struct timeout *to_requests; struct http_client_request *pending_request; struct istream *incoming_payload; struct io *io_req_payload; struct ioloop *last_ioloop; /* requests that have been sent, waiting for response */ ARRAY_TYPE(http_client_request) request_wait_list; unsigned int connected:1; /* connection is connected */ unsigned int tunneling:1; /* last sent request turns this connection into tunnel */ unsigned int connect_initialized:1; /* connection was initialized */ unsigned int connect_succeeded:1; unsigned int closing:1; unsigned int close_indicated:1; unsigned int output_locked:1; /* output is locked; no pipelining */ unsigned int output_broken:1; /* output is broken; no more requests */ unsigned int in_req_callback:1; /* performin request callback (busy) */ }; struct http_client_peer { struct http_client_peer_addr addr; char *addr_name; struct http_client *client; struct http_client_peer *prev, *next; /* queues using this peer */ ARRAY_TYPE(http_client_queue) queues; /* active connections to this peer */ ARRAY_TYPE(http_client_connection) conns; /* zero time-out for consolidating request handling */ struct timeout *to_req_handling; /* connection retry */ struct timeval last_failure; struct timeout *to_backoff; unsigned int backoff_time_msecs; unsigned int destroyed:1; /* peer is being destroyed */ unsigned int no_payload_sync:1; /* expect: 100-continue failed before */ unsigned int seen_100_response:1;/* expect: 100-continue succeeded before */ unsigned int allows_pipelining:1;/* peer is known to allow persistent connections */ unsigned int handling_requests:1;/* currently running request handler */ }; struct http_client_queue { struct http_client *client; struct http_client_host *host; char *name; struct http_client_peer_addr addr; char *addr_name; /* current index in host->ips */ unsigned int ips_connect_idx; /* the first IP that started the current round of connection attempts. initially 0, and later set to the ip index of the last successful connected IP */ unsigned int ips_connect_start_idx; unsigned int connect_attempts; /* peers we are trying to connect to; this can be more than one when soft connect timeouts are enabled */ ARRAY_TYPE(http_client_peer) pending_peers; /* all requests associated to this queue (ordered by earliest timeout first) */ ARRAY_TYPE(http_client_request) requests; /* delayed requests waiting to be released after delay */ ARRAY_TYPE(http_client_request) delayed_requests; /* requests pending in queue to be picked up by connections */ ARRAY_TYPE(http_client_request) queued_requests, queued_urgent_requests; struct timeout *to_connect, *to_request, *to_delayed; }; struct http_client_host { struct http_client_host *prev, *next; struct http_client *client; char *name; /* the ip addresses DNS returned for this host */ unsigned int ips_count; struct ip_addr *ips; /* requests are managed on a per-port basis */ ARRAY_TYPE(http_client_queue) queues; /* active DNS lookup */ struct dns_lookup *dns_lookup; unsigned int unix_local:1; }; struct http_client { pool_t pool; struct http_client_settings set; struct ioloop *ioloop; struct ssl_iostream_context *ssl_ctx; /* list of failed requests that are waiting for ioloop */ ARRAY(struct http_client_request *) delayed_failing_requests; struct timeout *to_failing_requests; struct connection_list *conn_list; HASH_TABLE_TYPE(http_client_host) hosts; struct http_client_host *unix_host; struct http_client_host *hosts_list; HASH_TABLE_TYPE(http_client_peer) peers; struct http_client_peer *peers_list; struct http_client_request *requests_list; unsigned int requests_count; }; int http_client_init_ssl_ctx(struct http_client *client, const char **error_r); void http_client_request_ref(struct http_client_request *req); /* Returns FALSE if unrefing destroyed the request entirely */ bool http_client_request_unref(struct http_client_request **_req); void http_client_request_destroy(struct http_client_request **_req); int http_client_request_delay_from_response(struct http_client_request *req, const struct http_response *response); void http_client_request_get_peer_addr(const struct http_client_request *req, struct http_client_peer_addr *addr); enum http_response_payload_type http_client_request_get_payload_type(struct http_client_request *req); int http_client_request_send(struct http_client_request *req, const char **error_r); int http_client_request_send_more(struct http_client_request *req, const char **error_r); bool http_client_request_callback(struct http_client_request *req, struct http_response *response); void http_client_request_connect_callback(struct http_client_request *req, const struct http_client_tunnel *tunnel, struct http_response *response); void http_client_request_resubmit(struct http_client_request *req); void http_client_request_retry(struct http_client_request *req, unsigned int status, const char *error); void http_client_request_error_delayed(struct http_client_request **_req); void http_client_request_error(struct http_client_request *req, unsigned int status, const char *error); void http_client_request_redirect(struct http_client_request *req, unsigned int status, const char *location); void http_client_request_finish(struct http_client_request *req); struct connection_list *http_client_connection_list_init(void); struct http_client_connection * http_client_connection_create(struct http_client_peer *peer); void http_client_connection_ref(struct http_client_connection *conn); /* Returns FALSE if unrefing destroyed the connection entirely */ bool http_client_connection_unref(struct http_client_connection **_conn); void http_client_connection_close(struct http_client_connection **_conn); int http_client_connection_output(struct http_client_connection *conn); void http_client_connection_start_request_timeout( struct http_client_connection *conn); void http_client_connection_reset_request_timeout( struct http_client_connection *conn); void http_client_connection_stop_request_timeout( struct http_client_connection *conn); unsigned int http_client_connection_count_pending(struct http_client_connection *conn); bool http_client_connection_is_ready(struct http_client_connection *conn); bool http_client_connection_is_idle(struct http_client_connection *conn); int http_client_connection_next_request(struct http_client_connection *conn); void http_client_connection_check_idle(struct http_client_connection *conn); void http_client_connection_switch_ioloop(struct http_client_connection *conn); void http_client_connection_start_tunnel(struct http_client_connection **_conn, struct http_client_tunnel *tunnel); unsigned int http_client_peer_addr_hash (const struct http_client_peer_addr *peer) ATTR_PURE; int http_client_peer_addr_cmp (const struct http_client_peer_addr *peer1, const struct http_client_peer_addr *peer2) ATTR_PURE; struct http_client_peer * http_client_peer_get(struct http_client *client, const struct http_client_peer_addr *addr); void http_client_peer_free(struct http_client_peer **_peer); bool http_client_peer_have_queue(struct http_client_peer *peer, struct http_client_queue *queue); void http_client_peer_link_queue(struct http_client_peer *peer, struct http_client_queue *queue); void http_client_peer_unlink_queue(struct http_client_peer *peer, struct http_client_queue *queue); struct http_client_request * http_client_peer_claim_request(struct http_client_peer *peer, bool no_urgent); void http_client_peer_trigger_request_handler(struct http_client_peer *peer); void http_client_peer_connection_success(struct http_client_peer *peer); void http_client_peer_connection_failure(struct http_client_peer *peer, const char *reason); void http_client_peer_connection_lost(struct http_client_peer *peer); bool http_client_peer_is_connected(struct http_client_peer *peer); unsigned int http_client_peer_idle_connections(struct http_client_peer *peer); unsigned int http_client_peer_pending_connections(struct http_client_peer *peer); void http_client_peer_switch_ioloop(struct http_client_peer *peer); struct http_client_queue * http_client_queue_create(struct http_client_host *host, const struct http_client_peer_addr *addr); void http_client_queue_free(struct http_client_queue *queue); void http_client_queue_fail(struct http_client_queue *queue, unsigned int status, const char *error); void http_client_queue_connection_setup(struct http_client_queue *queue); void http_client_queue_submit_request(struct http_client_queue *queue, struct http_client_request *req); void http_client_queue_drop_request(struct http_client_queue *queue, struct http_client_request *req); struct http_client_request * http_client_queue_claim_request(struct http_client_queue *queue, const struct http_client_peer_addr *addr, bool no_urgent); unsigned int http_client_queue_requests_pending(struct http_client_queue *queue, unsigned int *num_urgent_r) ATTR_NULL(2); void http_client_queue_connection_success(struct http_client_queue *queue, const struct http_client_peer_addr *addr); void http_client_queue_connection_failure(struct http_client_queue *queue, const struct http_client_peer_addr *addr, const char *reason); void http_client_queue_switch_ioloop(struct http_client_queue *queue); struct http_client_host * http_client_host_get(struct http_client *client, const struct http_url *host_url); void http_client_host_free(struct http_client_host **_host); void http_client_host_submit_request(struct http_client_host *host, struct http_client_request *req); void http_client_host_switch_ioloop(struct http_client_host *host); void http_client_delay_request_error(struct http_client *client, struct http_client_request *req); void http_client_remove_request_error(struct http_client *client, struct http_client_request *req); static inline bool http_client_peer_addr_is_https(const struct http_client_peer_addr *addr) { switch (addr->type) { case HTTP_CLIENT_PEER_ADDR_HTTPS: case HTTP_CLIENT_PEER_ADDR_HTTPS_TUNNEL: return TRUE; default: break; } return FALSE; } static inline const char * http_client_peer_addr_get_https_name(const struct http_client_peer_addr *addr) { switch (addr->type) { case HTTP_CLIENT_PEER_ADDR_HTTPS: case HTTP_CLIENT_PEER_ADDR_HTTPS_TUNNEL: return addr->a.tcp.https_name; default: break; } return NULL; } static inline const char * http_client_peer_addr2str(const struct http_client_peer_addr *addr) { switch (addr->type) { case HTTP_CLIENT_PEER_ADDR_HTTP: case HTTP_CLIENT_PEER_ADDR_HTTPS: case HTTP_CLIENT_PEER_ADDR_HTTPS_TUNNEL: case HTTP_CLIENT_PEER_ADDR_RAW: if (addr->a.tcp.ip.family == AF_INET6) { return t_strdup_printf("[%s]:%u", net_ip2addr(&addr->a.tcp.ip), addr->a.tcp.port); } return t_strdup_printf("%s:%u", net_ip2addr(&addr->a.tcp.ip), addr->a.tcp.port); case HTTP_CLIENT_PEER_ADDR_UNIX: return t_strdup_printf("unix:%s", addr->a.un.path); default: break; } i_unreached(); return ""; } static inline const char * http_client_request_label(struct http_client_request *req) { if (req->label == NULL) { return t_strdup_printf("[Req%u: %s %s%s]", req->id, req->method, http_url_create(&req->origin_url), req->target); } return req->label; } static inline bool http_client_request_to_proxy(const struct http_client_request *req) { return (req->host_url != &req->origin_url); } static inline const char * http_client_connection_label(struct http_client_connection *conn) { return t_strdup_printf("%s%s [%d]", http_client_peer_addr2str(&conn->peer->addr), (conn->peer->addr.type == HTTP_CLIENT_PEER_ADDR_HTTPS_TUNNEL ? " (tunnel)" : ""), conn->id); } static inline const char * http_client_peer_label(struct http_client_peer *peer) { if (peer->addr.type == HTTP_CLIENT_PEER_ADDR_HTTPS_TUNNEL) { return t_strconcat (http_client_peer_addr2str(&peer->addr), " (tunnel)", NULL); } return http_client_peer_addr2str(&peer->addr); } static inline unsigned int http_client_host_get_ip_idx(struct http_client_host *host, const struct ip_addr *ip) { unsigned int i; for (i = 0; i < host->ips_count; i++) { if (net_ip_compare(&host->ips[i], ip)) return i; } i_unreached(); } #endif