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); }
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; }
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; }
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; }
/*! * \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; }