client-connection-http.c revision 6e15d56df69d5b8e80768779c3c769e429aaa530
/* Copyright (c) 2010-2016 Dovecot authors, see the included COPYING file */
#include "lib.h"
#include "compat.h"
#include "lib-signals.h"
#include "base64.h"
#include "ioloop.h"
#include "str.h"
#include "istream.h"
#include "ostream.h"
#include "strescape.h"
#include "settings-parser.h"
#include "iostream-ssl.h"
#include "iostream-temp.h"
#include "istream-seekable.h"
#include "master-service.h"
#include "master-service-ssl.h"
#include "master-service-settings.h"
#include "mail-storage-service.h"
#include "http-server.h"
#include "http-request.h"
#include "http-response.h"
#include "http-url.h"
#include "doveadm-util.h"
#include "doveadm-server.h"
#include "doveadm-mail.h"
#include "doveadm-print.h"
#include "doveadm-settings.h"
#include "client-connection-private.h"
#include "json-parser.h"
#include <unistd.h>
#include <ctype.h>
struct client_connection_http {
struct client_connection client;
struct http_server_connection *http_client;
struct http_server_request *http_server_request;
const struct http_request *http_request;
struct http_server_response *http_response;
struct json_parser *json_parser;
const struct doveadm_cmd_ver2 *cmd;
struct doveadm_cmd_param *cmd_param;
int method_err;
char *method_id;
bool first_row;
bool value_is_array;
enum {
} json_state;
};
struct doveadm_http_server_mount {
const char *verb;
const char *path;
bool auth;
};
static struct http_server *doveadm_http_server;
static const struct http_server_callbacks doveadm_http_callbacks = {
};
static void doveadm_http_server_options_handler(struct client_connection_http *);
static void doveadm_http_server_print_mounts(struct client_connection_http *);
static void doveadm_http_server_send_api_v1(struct client_connection_http *);
static void doveadm_http_server_read_request_v1(struct client_connection_http *);
static struct doveadm_http_server_mount doveadm_http_server_mounts[] = {
{ .verb = "POST", .path = "/doveadm/v1", .handler = doveadm_http_server_read_request_v1, .auth = TRUE }
};
static void doveadm_http_server_send_response(void *context);
struct client_connection *
{
struct client_connection_http *conn;
return NULL;
}
static void
{
}
static void
{
struct http_server_response *resp =
const char *agent;
const char *url;
int status;
const char *reason;
url,
agent);
}
const char *error ATTR_UNUSED;
// we've already failed, ignore error
}
}
{
str_truncate(escaped,0);
str_truncate(escaped,0);
}
}
{
}
}
{
i_stream_skip(conn->cmd_param->value.v_istream, i_stream_get_data_size(conn->cmd_param->value.v_istream));
return 0;
i_error("read(%s) failed: %s",
return -1;
}
return 1;
}
/**
* this is to ensure we can handle arrays and other special parameter types
*/
static int doveadm_http_server_json_parse_next(struct client_connection_http *conn, enum json_type *type, const char **value)
{
int rc;
const char *tmp;
/* reading through parameters in an array */
if (*type == JSON_TYPE_ARRAY_END)
break;
if (*type != JSON_TYPE_STRING)
return -2;
}
if (rc <= 0)
return rc;
conn->cmd_param->value.v_istream = i_stream_create_seekable_path(is, IO_BLOCK_SIZE, "/tmp/doveadm.");
i_stream_unref(&is[0]);
}
if (*type == JSON_TYPE_ARRAY) {
/* start of array */
}
if (*type != JSON_TYPE_STRING) {
/* FIXME: should handle other than string too */
return -2;
}
} else {
case CMD_PARAM_BOOL:
case CMD_PARAM_INT64:
}
break;
case CMD_PARAM_IP:
}
break;
case CMD_PARAM_STR:
default:
break;
}
}
}
}
static void
{
struct doveadm_cmd_context cctx;
/* final preflight check */
if (conn->method_err != 0) {
} else {
}
return;
}
const char *user;
// create iostream
/* then call it */
ioloop = io_loop_create();
doveadm_exit_code = 0;
else
if (o_stream_nfinish(doveadm_print_ostream)<0) {
i_info("Error writing output in command %s: %s",
}
} else {
}
if (doveadm_exit_code != 0) {
} else {
}
i_stream_unref(&is);
}
static void
{
const struct doveadm_cmd_ver2 *ccmd;
struct doveadm_cmd_param *par;
int rc;
bool found;
if (type != JSON_TYPE_ARRAY) break;
if (type == JSON_TYPE_ARRAY_END) {
continue;
}
if (type != JSON_TYPE_ARRAY) break;
conn->method_err = 0;
if (type != JSON_TYPE_STRING) break;
/* see if we can find it */
break;
}
}
if (!found) {
} else {
struct doveadm_cmd_param *param;
/* initialize pargv */
}
}
if (type == JSON_TYPE_OBJECT_END) {
continue;
}
if (type != JSON_TYPE_OBJECT) break;
if (type == JSON_TYPE_OBJECT_END) {
continue;
}
// can happen...
/* go hunting */
/* it's already set, cannot have same key twice in json */
break;
}
}
/* skip parameters if error has already occured */
} else {
// FIXME: should be returned as error to client, not logged
i_info("Parameter %s already set",
break;
}
}
if (type != JSON_TYPE_STRING) break;
/* should be end of array */
if (type != JSON_TYPE_ARRAY_END) break;
// FIXME: should be returned as error to client, not logged
i_info("Got unexpected elements in JSON data");
continue;
}
}
return;
/* this will happen if the parser above runs into unexpected element, but JSON is OK */
// FIXME: should be returned as error to client, not logged
i_info("unexpected element");
return;
}
i_info("read(client) failed: %s",
return;
}
// istream JSON parsing failures do not count as errors
// FIXME: should be returned as error to client, not logged
return;
}
}
{
size_t i,k;
i++;
}
str_truncate(value, k);
}
static void
{
size_t i,k;
const struct doveadm_cmd_ver2 *cmd;
const struct doveadm_cmd_param *par;
bool sent;
for(i = 0; i < array_count(&doveadm_cmds_ver2); i++) {
str_truncate(tmp, 0);
continue;
if (sent)
else
case CMD_PARAM_BOOL:
break;
case CMD_PARAM_INT64:
break;
case CMD_PARAM_ARRAY:
break;
case CMD_PARAM_IP:
case CMD_PARAM_ISTREAM:
case CMD_PARAM_STR:
}
}
str_truncate(tmp, 0);
}
}
static void
{
"Access-Control-Allow-Origin", "*");
"Access-Control-Allow-Methods", "GET, POST, OPTIONS");
"Access-Control-Allow-Request-Headers",
"Content-Type, X-API-Key, Authorization");
"Access-Control-Allow-Headers",
"Content-Type, WWW-Authenticate");
}
static void
{
if (i>0)
else
else
}
}
static bool
{
struct http_auth_credentials creds;
/* no authentication specified */
i_error("No authentication defined in configuration. Add API key or password");
return FALSE;
}
/* see if the mech is supported */
else i_error("Invalid authencition attempt to HTTP API");
}
else if (strcasecmp(creds.scheme, "X-Doveadm-API") == 0 && doveadm_settings->doveadm_api_key[0] != '\0') {
base64_encode(doveadm_settings->doveadm_api_key, strlen(doveadm_settings->doveadm_api_key), b64_value);
else i_error("Invalid authencition attempt to HTTP API");
}
else i_error("Unsupported authentication scheme to HTTP API");
}
conn->http_response = http_server_response_create(conn->http_server_request, 401, "Authentication required");
"WWW-Authenticate", "X-Dovecot-API Realm=\"doveadm\""
);
"WWW-Authenticate", "Basic Realm=\"doveadm\""
);
}
return auth;
}
static void
{
ep = &doveadm_http_server_mounts[i];
break;
}
}
}
return;
}
return;
}
"application/json; charset=utf-8");
/* handle request */
} else {
}
}
static void doveadm_http_server_send_response(void *context)
{
i_info("error writing output: %s",
} else {
// send the payload response
i_stream_unref(&is);
}
}
// submit response
}
static const struct http_server_settings http_server_set = {
.max_client_idle_time_msecs = 5000,
};
void doveadm_http_server_init(void)
{
}
void doveadm_http_server_deinit(void)
{
}