http-server-connection.c revision ee2633056e67353157bfbce4d9e0d1c3ceaa627a
/* Copyright (c) 2013-2016 Dovecot authors, see the included COPYING file */
#include "lib.h"
#include "llist.h"
#include "array.h"
#include "str.h"
#include "ioloop.h"
#include "istream.h"
#include "ostream.h"
#include "connection.h"
#include "iostream-rawlog.h"
#include "iostream-ssl.h"
#include "master-service.h"
#include "master-service-ssl.h"
#include "http-date.h"
#include "http-request-parser.h"
#include "http-server-private.h"
static void
const char *reason);
/*
* Logging
*/
static inline void
static inline void
const char *format, ...)
{
i_debug("http-server: conn %s: %s",
}
}
static inline void
static inline void
const char *format, ...)
{
i_error("http-server: conn %s: %s",
}
static inline void
static inline void
const char *format, ...)
{
i_info("http-server: conn %s: %s",
}
/*
* Connection
*/
static void
{
}
const struct http_server_stats *
{
}
static void
{
}
static void
{
!conn->in_req_callback) {
}
}
static void
{
}
static void
{
}
static void
{
}
}
static void
{
}
{
}
}
{
struct http_server_connection *conn =
(struct http_server_connection *)_conn;
}
{
}
static void
{
}
{
int stream_errno;
/* caller is allowed to change the socket fd to blocking while reading
the payload. make sure here that it's switched back. */
/* handle errors in transfer stream */
switch (stream_errno) {
case EMSGSIZE:
"Client sent excessively large request");
return;
case EIO:
"Client sent invalid request payload");
return;
default:
break;
}
}
/* resource stopped reading payload; update state */
/* finished reading request */
break;
/* no response submitted yet */
break;
/* response submitted, but not all payload is necessarily read */
break;
/* nothing to do */
break;
default:
i_unreached();
}
/* 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 the next response if
necessary. */
}
}
static void http_server_connection_request_callback(
{
/* CONNECT method */
return;
}
return;
}
/* other methods */
} else {
return;
}
}
}
static bool
struct http_server_request *req)
{
return TRUE;
}
/* wrap the stream to capture the destroy event without destroying the
actual payload stream. */
} else {
i_stream_create_from_data("", 0);
}
/* the callback may add its own I/O, so we need to remove
our one before calling it */
return FALSE;
}
/* send 100 Continue when appropriate */
}
/* delegate payload handling to request handler */
/* already finished reading the payload */
}
}
/* finished reading request */
}
return TRUE;
}
/* Request payload is still being uploaded by the client */
return FALSE;
}
static int
{
const char *error;
return -1;
}
return -1;
}
return 0;
}
static bool
{
int stream_errno;
return FALSE;
/* connection input broken; output may still be intact */
stream_errno != ECONNRESET) {
"Connection lost: read(%s) failed: %s",
} else {
"Connection lost: Remote disconnected");
/* no pending requests; close */
"Remote closed connection");
/* unfinished request; close */
"Remote closed connection unexpectedly");
} else {
/* a request is still processing; only drop input io for now.
the other end may only have shutdown one direction */
}
}
return FALSE;
}
return TRUE;
}
{
struct http_server_connection *conn =
(struct http_server_connection *)_conn;
const char *error;
bool cont;
int ret;
if (http_server_connection_ssl_init(conn) < 0) {
/* ssl failed */
return;
}
}
/* We came here from a timeout added by
http_server_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. */
}
/* create request object if none was created already */
if (conn->request_queue_count >
/* pipeline full */
return;
}
/* continue last unfinished request*/
} else {
if (conn->request_queue_count >=
/* pipeline full */
return;
}
/* start new request */
}
/* parse requests */
ret = 1;
if (pending_request != NULL) {
/* previous request is now fully read and ready to respond */
}
T_BEGIN {
} T_END;
if (!cont) {
/* connection closed or request body not read yet.
the request may be destroyed now. */
if (req->destroy_pending)
else
return;
}
if (req->destroy_pending)
else
/* connection got closed in destroy callback */
break;
}
if (conn->close_indicated) {
/* client indicated it will close after this request; stop trying
to read more. */
break;
}
if (conn->request_queue_count >=
/* pipeline full */
return;
}
/* start new request */
}
/* connection got closed */
return;
}
if (ret <= 0 &&
return;
if (ret < 0) {
"Client sent invalid request: %s", error);
switch (error_code) {
/* fall through */
break;
/* fall through */
break;
break;
break;
break;
default:
i_unreached();
}
/* connection got closed */
return;
}
}
return;
}
/* previous request is now fully read and ready to respond */
}
}
}
static void
{
const char *error;
int ret = 0;
if (ret <= 0 &&
return;
}
if (ret < 0) {
"Client sent invalid request: %s", error);
switch (error_code) {
413, "Payload Too Large");
break;
default:
i_unreached();
}
return;
}
if (ret > 0)
}
struct http_server_connection *conn)
{
/* destroy payload wrapper early to advance state */
}
/* finish reading payload from the parser */
(conn->http_parser)) {
"Discarding remaining incoming payload");
} else {
"No remaining incoming payload");
}
/* check whether connection is still viable */
return -1;
return 0;
}
const char *error)
{
return;
"Connection lost: %s", error);
} else {
"Connection lost: Remote disconnected");
"Remote closed connection unexpectedly");
}
}
static bool
{
struct http_server_request *req;
int ret;
if (conn->output_locked)
return FALSE;
/* no requests pending */
return FALSE;
}
/* server is causing idle time */
} else {
/* client is causing idle time */
}
/* send 100 Continue if appropriate */
&& !req->sent_100_continue) {
static const char *response = "HTTP/1.1 100 Continue\r\n\r\n";
}
return FALSE;
}
}
return FALSE;
}
if (ret < 0) {
return FALSE;
}
return TRUE;
}
static int http_server_connection_send_responses(
struct http_server_connection *conn)
{
/* send more responses until no more responses remain, the output
blocks again, or the connection is closed */
return -1;
/* accept more requests if possible */
return 1;
}
return 0;
}
{
int ret;
if (ret < 0) {
}
}
return -1;
}
return 0;
}
{
if (http_server_connection_flush(conn) < 0)
return -1;
if (!conn->output_locked) {
if (http_server_connection_send_responses(conn) < 0)
return -1;
return -1;
}
if (!conn->output_locked) {
/* room for more responses */
if (http_server_connection_send_responses(conn) < 0)
return -1;
/* server is causing idle time */
} else {
/* client is causing idle time */
}
}
return 1;
}
struct http_server_connection *conn)
{
}
bool
{
}
static struct connection_settings http_server_connection_set = {
};
static const struct connection_vfuncs http_server_connection_vfuncs = {
};
struct connection_list *
{
return connection_list_init
}
struct http_server_connection *
{
struct http_server_connection *conn;
static unsigned int id = 0;
const char *name;
/* get a name for this connection */
} else {
struct net_unix_cred cred;
} else {
}
} else {
}
}
if (!ssl)
return conn;
}
{
}
static void
const char *reason)
{
return;
reason = "Connection closed";
/* preserve statistics */
/* drop all requests before connection is closed */
}
}
/* the stream is still accessed by lib-http caller. */
}
}
{
return;
} T_END;
}
const char *reason)
{
}
{
struct http_server_tunnel tunnel;
/* preserve statistics */
}
{
}