http-client-connection.c revision 52ccd525937de3e914cc0c54f46de98414dd979d
/* Copyright (c) 2013 Dovecot authors, see the included COPYING file */
#include "lib.h"
#include "net.h"
#include "str.h"
#include "hash.h"
#include "array.h"
#include "ioloop.h"
#include "istream.h"
#include "ostream.h"
#include "iostream-rawlog.h"
#include "iostream-ssl.h"
#include "http-response-parser.h"
#include "http-client-private.h"
/*
* Logging
*/
static inline void
static inline void
const char *format, ...)
{
i_debug("http-client: conn %s: %s",
}
}
/*
* Connection
*/
{
!conn->close_indicated &&
}
{
}
static void
{
struct http_client_request **req;
}
}
static void
{
struct http_client_request **req;
"Server explicitly closed connection");
}
}
static void
{
const char *sslerr;
}
}
}
static void
{
struct http_client_request **req;
}
}
static void
{
}
static void
{
/* timeout already set */
return;
}
/* set timeout for this connection */
/* instant death for (urgent) connections above limit */
timeout = 0;
} else {
/* kill duplicate connections quicker;
linearly based on the number of connections */
}
"No more requests queued; going idle (timeout = %u msecs)",
timeout);
} else {
/* there should be no idle timeout */
}
}
static void
{
struct http_client_request *const *req_idx;
struct http_client_request *req;
const char *error;
"Expected 100-continue response timed out; sending payload anyway");
}
}
{
const char *error;
bool have_pending_requests;
if (!http_client_connection_is_ready(conn)) {
return FALSE;
}
/* claim request, but no urgent request can be second in line */
return FALSE;
}
return FALSE;
}
Section 6.1.2.1:
Because of the presence of older implementations, the protocol allows
ambiguous situations in which a client might send "Expect: 100-continue"
without receiving either a 417 (Expectation Failed) or a 100 (Continue)
status code. Therefore, when a client sends this header field to an
origin server (possibly via a proxy) from which it has never seen a 100
(Continue) status code, the client SHOULD NOT wait for an indefinite
period before sending the payload body.
*/
if (req->payload_sync) {
}
return TRUE;
}
{
struct http_client_connection *conn =
(struct http_client_connection *)_conn;
const char *error;
switch (_conn->disconnect_reason) {
break;
/* retry pending requests if possible */
t_strdup_printf("Connection lost: %s",
default:
break;
}
}
{
}
static void
{
if (conn->close_indicated) {
return;
}
}
{
/* caller is allowed to change the socket fd to blocking while reading
the payload. make sure here that it's switched back. */
/* input stream may have pending input. make sure input handler
gets called (but don't do it directly, since we get get here
somewhere from the API user's code, which we can't really know what
state it is in). this call also triggers sending a new request if
necessary. */
}
static bool
{
bool retrying;
/* wrap the stream to capture the destroy event without destroying the
actual payload stream. */
req);
/* the callback may add its own I/O, so we need to remove
our one before calling it */
}
/* the callback managed to get this connection destroyed */
if (!retrying)
return FALSE;
}
if (retrying) {
/* retrying, don't destroy the request */
}
return TRUE;
}
/* already finished reading the payload */
}
} else {
}
return TRUE;
}
return FALSE;
}
{
struct http_client_connection *conn =
(struct http_client_connection *)_conn;
struct http_response *response;
struct http_client_request *const *req_idx;
const char *error;
bool no_payload = FALSE;
/* We came here from a timeout added by
http_client_payload_destroyed(). The IO couldn't be added
back immediately in there, because the HTTP API user may
still have had its own IO pointed to the same fd. It should
be removed by now, so we can add it back. */
finished++;
}
/* get first waiting request */
Section 3.3.2:
A server MAY send a Content-Length header field in a response to a
HEAD request [...]
*/
}
// FIXME: handle somehow if server replies before request->input is at EOF
while ((ret=http_response_parse_next
bool aborted;
/* server sent response without any requests in the wait list */
return;
}
/* Got some response; cancel response timeout */
Section 7.2:
A client MUST be prepared to accept one or more 1xx status responses
prior to a regular response, even if the client does not expect a 100
(Continue) status message. Unexpected 1xx status responses MAY be
ignored by a user agent.
*/
"Got expected 100-continue response");
}
return;
/* ignore them for now */
/* restart timeout */
continue;
}
"Got %u response for request %s",
/* remove request from queue */
if (!aborted) {
/* drop Expect: continue */
return;
/* redirect */
} else {
/* response for application */
return;
}
finished++;
}
/* server closing connection? */
if (conn->close_indicated) {
return;
}
/* get next waiting request */
} else {
no_payload = FALSE;
}
}
if (ret <= 0 &&
t_strdup_printf("Connection lost: read(%s) failed: %s",
stream_errno != 0 ?
return;
}
if (ret < 0) {
return;
}
if (finished > 0) {
/* room for new requests */
}
}
{
const char *error;
int ret;
if (ret < 0) {
t_strdup_printf("Connection lost: write(%s) failed: %m",
}
return ret;
}
return -1;
}
if (!conn->output_locked) {
/* room for new requests */
}
}
}
return 1;
}
static void
{
}
/* we never pipeline before the first response */
}
static int
{
/* skip certificate checks */
return 0;
*error_r = "SSL certificate not received";
else
*error_r = "Received invalid SSL certificate";
} else {
return 0;
}
"SSL certificate doesn't match expected host name %s", host);
}
return -1;
}
static int
const char **error_r)
{
struct ssl_iostream_settings ssl_set;
}
"Couldn't initialize SSL client for %s: %s",
return -1;
}
return -1;
}
return 0;
}
static void
{
struct http_client_connection *conn =
(struct http_client_connection *)_conn;
const char *error;
if (!success) {
} else {
}
return;
}
}
}
static const struct connection_settings http_client_connection_set = {
};
static const struct connection_vfuncs http_client_connection_vfuncs = {
};
struct connection_list *
{
return connection_list_init
}
static void
{
}
{
}
}
struct http_client_connection *
{
struct http_client_connection *conn;
static unsigned int id = 0;
"Connection created (%d parallel connections exist)",
return conn;
}
{
}
{
struct http_client_connection *const *conn_idx;
struct http_client_request **req;
return;
/* abort all pending requests */
"Aborting");
}
/* remove this connection from the list */
break;
}
}
}
{
}