int ast_http_init(void)
{
	ast_http_uri_link(&statusuri);
	ast_http_uri_link(&staticuri);
	ast_cli_register_multiple(http_cli, sizeof(http_cli) / sizeof(http_cli[0]));
	return __ast_http_load(0);
}
int ast_http_init(void)
{
	ast_http_uri_link(&statusuri);
	ast_http_uri_link(&staticuri);
	ast_cli_register_multiple(cli_http, sizeof(cli_http) / sizeof(struct ast_cli_entry));

	return __ast_http_load(0);
}
Exemple #3
0
static int __ast_http_post_load(int reload)
{
	struct ast_config *cfg;
	struct ast_variable *v;
	struct ast_flags config_flags = { reload ? CONFIG_FLAG_FILEUNCHANGED : 0 };

	cfg = ast_config_load2("http.conf", "http", config_flags);
	if (cfg == CONFIG_STATUS_FILEMISSING || cfg == CONFIG_STATUS_FILEUNCHANGED || cfg == CONFIG_STATUS_FILEINVALID) {
		return 0;
	}

	if (reload) {
		ast_http_uri_unlink_all_with_key(__FILE__);
	}

	if (cfg) {
		for (v = ast_variable_browse(cfg, "general"); v; v = v->next) {
			if (!strcasecmp(v->name, "prefix")) {
				ast_copy_string(prefix, v->value, sizeof(prefix));
				if (prefix[strlen(prefix)] == '/') {
					prefix[strlen(prefix)] = '\0';
				}
			}
		}

		for (v = ast_variable_browse(cfg, "post_mappings"); v; v = v->next) {
			struct ast_http_uri *urih;
			struct ast_str *ds;

			if (!(urih = ast_calloc(sizeof(*urih), 1))) {
				ast_config_destroy(cfg);
				return -1;
			}

			if (!(ds = ast_str_create(32))) {
				ast_free(urih);
				ast_config_destroy(cfg);
				return -1;
			}

			urih->description = ast_strdup("HTTP POST mapping");
			urih->uri = ast_strdup(v->name);
			ast_str_set(&ds, 0, "%s", v->value);
			urih->data = ds;
			urih->has_subtree = 0;
			urih->supports_get = 0;
			urih->supports_post = 1;
			urih->callback = http_post_callback;
			urih->key = __FILE__;
			urih->mallocd = urih->dmallocd = 1;

			ast_http_uri_link(urih);
		}

		ast_config_destroy(cfg);
	}
	return 0;
}
Exemple #4
0
static int reload_module(void)
{
    char was_enabled = is_enabled();

    if (ast_ari_config_reload() != 0) {
        return AST_MODULE_LOAD_DECLINE;
    }

    if (was_enabled && !is_enabled()) {
        ast_debug(3, "Disabling ARI\n");
        ast_http_uri_unlink(&http_uri);
    } else if (!was_enabled && is_enabled()) {
        ast_debug(3, "Enabling ARI\n");
        ast_http_uri_link(&http_uri);
    }

    return AST_MODULE_LOAD_SUCCESS;
}
Exemple #5
0
static int load_module(void)
{
    ast_mutex_init(&root_handler_lock);

    /* root_handler may have been built during a declined load */
    if (!root_handler) {
        root_handler = root_handler_create();
    }
    if (!root_handler) {
        return AST_MODULE_LOAD_FAILURE;
    }

    /* oom_json may have been built during a declined load */
    if (!oom_json) {
        oom_json = ast_json_pack(
                       "{s: s}", "error", "Allocation failed");
    }
    if (!oom_json) {
        /* Ironic */
        return AST_MODULE_LOAD_FAILURE;
    }

    if (ast_ari_config_init() != 0) {
        return AST_MODULE_LOAD_DECLINE;
    }

    if (is_enabled()) {
        ast_debug(3, "ARI enabled\n");
        ast_http_uri_link(&http_uri);
    } else {
        ast_debug(3, "ARI disabled\n");
    }

    if (ast_ari_cli_register() != 0) {
        return AST_MODULE_LOAD_FAILURE;
    }

    return AST_MODULE_LOAD_SUCCESS;
}
static int load_module(void)
{
	if (process_config(0)) {
		return AST_MODULE_LOAD_DECLINE;
	}

	if (ast_http_uri_link(&test_uri)) {
		return AST_MODULE_LOAD_DECLINE;
	}

	AST_TEST_REGISTER(create_nominal);

	AST_TEST_REGISTER(retrieve_nominal);
	AST_TEST_REGISTER(retrieve_etag);
	AST_TEST_REGISTER(retrieve_expires);
	AST_TEST_REGISTER(retrieve_etag_expired);
	AST_TEST_REGISTER(retrieve_cache_control_age);
	AST_TEST_REGISTER(retrieve_cache_control_directives);

	ast_test_register_init(CATEGORY, pre_test_cb);

	return AST_MODULE_LOAD_SUCCESS;
}
Exemple #7
0
/*!
 * \internal
 * \brief ARI HTTP handler.
 *
 * This handler takes the HTTP request and turns it into the appropriate
 * RESTful request (conversion to JSON, routing, etc.)
 *
 * \param ser TCP session.
 * \param urih URI handler.
 * \param uri URI requested.
 * \param method HTTP method.
 * \param get_params HTTP \c GET params.
 * \param headers HTTP headers.
 */
static int ast_ari_callback(struct ast_tcptls_session_instance *ser,
				const struct ast_http_uri *urih,
				const char *uri,
				enum ast_http_method method,
				struct ast_variable *get_params,
				struct ast_variable *headers)
{
	RAII_VAR(struct ast_ari_conf *, conf, NULL, ao2_cleanup);
	RAII_VAR(struct ast_str *, response_body, ast_str_create(256), ast_free);
	RAII_VAR(struct ast_ari_conf_user *, user, NULL, ao2_cleanup);
	struct ast_ari_response response = { .fd = -1, 0 };
	RAII_VAR(struct ast_variable *, post_vars, NULL, ast_variables_destroy);

	if (!response_body) {
		ast_http_request_close_on_completion(ser);
		ast_http_error(ser, 500, "Server Error", "Out of memory");
		return 0;
	}

	response.headers = ast_str_create(40);
	if (!response.headers) {
		ast_http_request_close_on_completion(ser);
		ast_http_error(ser, 500, "Server Error", "Out of memory");
		return 0;
	}

	conf = ast_ari_config_get();
	if (!conf || !conf->general) {
		ast_free(response.headers);
		ast_http_request_close_on_completion(ser);
		ast_http_error(ser, 500, "Server Error", "URI handler config missing");
		return 0;
	}

	process_cors_request(headers, &response);

	/* Process form data from a POST. It could be mixed with query
	 * parameters, which seems a bit odd. But it's allowed, so that's okay
	 * with us.
	 */
	post_vars = ast_http_get_post_vars(ser, headers);
	if (!post_vars) {
		switch (errno) {
		case EFBIG:
			ast_ari_response_error(&response, 413,
				"Request Entity Too Large",
				"Request body too large");
			goto request_failed;
		case ENOMEM:
			ast_http_request_close_on_completion(ser);
			ast_ari_response_error(&response, 500,
				"Internal Server Error",
				"Out of memory");
			goto request_failed;
		case EIO:
			ast_ari_response_error(&response, 400,
				"Bad Request", "Error parsing request body");
			goto request_failed;
		}
	}
	if (get_params == NULL) {
		get_params = post_vars;
	} else if (get_params && post_vars) {
		/* Has both post_vars and get_params */
		struct ast_variable *last_var = post_vars;
		while (last_var->next) {
			last_var = last_var->next;
		}
		/* The duped get_params will get freed when post_vars gets
		 * ast_variables_destroyed.
		 */
		last_var->next = ast_variables_dup(get_params);
		get_params = post_vars;
	}

	user = authenticate_user(get_params, headers);
	if (response.response_code > 0) {
		/* POST parameter processing error. Do nothing. */
	} else if (!user) {
		/* Per RFC 2617, section 1.2: The 401 (Unauthorized) response
		 * message is used by an origin server to challenge the
		 * authorization of a user agent. This response MUST include a
		 * WWW-Authenticate header field containing at least one
		 * challenge applicable to the requested resource.
		 */
		ast_ari_response_error(&response, 401, "Unauthorized", "Authentication required");

		/* Section 1.2:
		 *   realm       = "realm" "=" realm-value
		 *   realm-value = quoted-string
		 * Section 2:
		 *   challenge   = "Basic" realm
		 */
		ast_str_append(&response.headers, 0,
			"WWW-Authenticate: Basic realm=\"%s\"\r\n",
			conf->general->auth_realm);
	} else if (!ast_fully_booted) {
		ast_http_request_close_on_completion(ser);
		ast_ari_response_error(&response, 503, "Service Unavailable", "Asterisk not booted");
	} else if (user->read_only && method != AST_HTTP_GET && method != AST_HTTP_OPTIONS) {
		ast_ari_response_error(&response, 403, "Forbidden", "Write access denied");
	} else if (ast_ends_with(uri, "/")) {
		remove_trailing_slash(uri, &response);
	} else if (ast_begins_with(uri, "api-docs/")) {
		/* Serving up API docs */
		if (method != AST_HTTP_GET) {
			ast_ari_response_error(&response, 405, "Method Not Allowed", "Unsupported method");
		} else {
			/* Skip the api-docs prefix */
			ast_ari_get_docs(strchr(uri, '/') + 1, urih->prefix, headers, &response);
		}
	} else {
		/* Other RESTful resources */
		ast_ari_invoke(ser, uri, method, get_params, headers,
			&response);
	}

	if (response.no_response) {
		/* The handler indicates no further response is necessary.
		 * Probably because it already handled it */
		ast_free(response.headers);
		return 0;
	}

request_failed:
	/* If you explicitly want to have no content, set message to
	 * ast_json_null().
	 */
	ast_assert(response.message != NULL);
	ast_assert(response.response_code > 0);

	/* response.message could be NULL, in which case the empty response_body
	 * is correct
	 */
	if (response.message && !ast_json_is_null(response.message)) {
		ast_str_append(&response.headers, 0,
			       "Content-type: application/json\r\n");
		if (ast_json_dump_str_format(response.message, &response_body,
				conf->general->format) != 0) {
			/* Error encoding response */
			response.response_code = 500;
			response.response_text = "Internal Server Error";
			ast_str_set(&response_body, 0, "%s", "");
			ast_str_set(&response.headers, 0, "%s", "");
		}
	}

	ast_debug(3, "Examining ARI response:\n%d %s\n%s\n%s\n", response.response_code,
		response.response_text, ast_str_buffer(response.headers), ast_str_buffer(response_body));
	ast_http_send(ser, method, response.response_code,
		      response.response_text, response.headers, response_body,
		      response.fd != -1 ? response.fd : 0, 0);
	/* ast_http_send takes ownership, so we don't have to free them */
	response_body = NULL;

	ast_json_unref(response.message);
	if (response.fd >= 0) {
		close(response.fd);
	}
	return 0;
}

static struct ast_http_uri http_uri = {
	.callback = ast_ari_callback,
	.description = "Asterisk RESTful API",
	.uri = "ari",
	.has_subtree = 1,
	.data = NULL,
	.key = __FILE__,
	.no_decode_uri = 1,
};

static int load_module(void)
{
	ast_mutex_init(&root_handler_lock);

	/* root_handler may have been built during a declined load */
	if (!root_handler) {
		root_handler = root_handler_create();
	}
	if (!root_handler) {
		return AST_MODULE_LOAD_FAILURE;
	}

	/* oom_json may have been built during a declined load */
	if (!oom_json) {
		oom_json = ast_json_pack(
			"{s: s}", "error", "Allocation failed");
	}
	if (!oom_json) {
		/* Ironic */
		return AST_MODULE_LOAD_FAILURE;
	}

	if (ast_ari_config_init() != 0) {
		return AST_MODULE_LOAD_DECLINE;
	}

	if (is_enabled()) {
		ast_debug(3, "ARI enabled\n");
		ast_http_uri_link(&http_uri);
	} else {
		ast_debug(3, "ARI disabled\n");
	}

	if (ast_ari_cli_register() != 0) {
		return AST_MODULE_LOAD_FAILURE;
	}

	return AST_MODULE_LOAD_SUCCESS;
}

static int unload_module(void)
{
	ast_ari_cli_unregister();

	if (is_enabled()) {
		ast_debug(3, "Disabling ARI\n");
		ast_http_uri_unlink(&http_uri);
	}

	ast_ari_config_destroy();

	ao2_cleanup(root_handler);
	root_handler = NULL;
	ast_mutex_destroy(&root_handler_lock);

	ast_json_unref(oom_json);
	oom_json = NULL;

	return 0;
}