http-client-connection.c revision f21b0af073359dfc5560a6187a0257b3000b39dc
/* 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
static inline void
const char *format, ...)
{
i_debug("http-client: conn %s: %s",
}
}
static inline void
const char *format, ...)
{
i_error("http-client: conn %s: %s",
}
/*
* Connection
*/
{
}
{
}
static void
{
struct http_client_request **req;
}
}
static void
{
struct http_client_request **req;
"Server explicitly closed connection");
}
}
static void
{
}
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;
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
{
/* wrap the stream to capture the destroy event without destroying the
actual payload stream. */
conn);
/* the callback may add its own I/O, so we need to remove
our one before calling it */
}
// FIXME: conn may be freed at this point..
/* 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 */
}
#ifdef HTTP_BUILD_SSL
static int http_client_connection_ssl_handshaked(void *context)
{
/* skip certificate checks */
return 0;
} else {
}
} else {
"SSL certificate doesn't match host name");
} else {
return 0;
}
}
return -1;
}
static int
{
struct ssl_iostream_settings ssl_set;
const char *source;
return -1;
}
}
return -1;
}
return -1;
}
return 0;
}
#endif
static void
{
struct http_client_connection *conn =
(struct http_client_connection *)_conn;
if (!success) {
} else {
#ifdef HTTP_BUILD_SSL
if (http_client_connection_ssl_init(conn) < 0)
return;
}
#endif
}
}
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
}
{
return -1;
}
}
return 0;
}
struct http_client_connection *
{
struct http_client_connection *conn;
static unsigned int id = 0;
if (http_client_connection_connect(conn) < 0) {
return NULL;
}
"Connection created (%d parallel connections exist)",
return conn;
}
{
}
{
struct http_client_connection *const *conn_idx;
struct http_client_request **req;
return;
#ifdef HTTP_BUILD_SSL
#endif
/* abort all pending requests */
"Aborting");
}
/* remove this connection from the list */
break;
}
}
}
{
}