Support for Private Asterisk HTTP Servers. More...
#include "asterisk/config.h"
#include "asterisk/tcptls.h"
#include "asterisk/linkedlists.h"
Go to the source code of this file.
Data Structures | |
struct | ast_http_uri |
Definition of a URI handler. More... | |
Typedefs | |
typedef int(* | ast_http_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) |
HTTP Callbacks. | |
Enumerations | |
enum | ast_http_method { AST_HTTP_UNKNOWN = -1, AST_HTTP_GET = 0, AST_HTTP_POST, AST_HTTP_HEAD, AST_HTTP_PUT } |
HTTP Request methods known by Asterisk. More... | |
Functions | |
const char * | ast_get_http_method (enum ast_http_method method) attribute_pure |
Return http method name string. | |
void | ast_http_auth (struct ast_tcptls_session_instance *ser, const char *realm, const unsigned long nonce, const unsigned long opaque, int stale, const char *text) |
Send http "401 Unauthorized" response and close socket. | |
void | ast_http_error (struct ast_tcptls_session_instance *ser, int status, const char *title, const char *text) |
Send HTTP error message and close socket. | |
const char * | ast_http_ftype2mtype (const char *ftype) attribute_pure |
Return mime type based on extension. | |
struct ast_variable * | ast_http_get_cookies (struct ast_variable *headers) |
Get cookie from Request headers. | |
struct ast_variable * | ast_http_get_post_vars (struct ast_tcptls_session_instance *ser, struct ast_variable *headers) |
Get post variables from client Request Entity-Body, if content type is application/x-www-form-urlencoded. | |
uint32_t | ast_http_manid_from_vars (struct ast_variable *headers) attribute_pure |
Return manager id, if exist, from request headers. | |
void | ast_http_prefix (char *buf, int len) |
Return the current prefix. | |
void | ast_http_send (struct ast_tcptls_session_instance *ser, enum ast_http_method method, int status_code, const char *status_title, struct ast_str *http_header, struct ast_str *out, const int fd, unsigned int static_content) |
Generic function for sending http/1.1 response. | |
int | ast_http_uri_link (struct ast_http_uri *urihandler) |
Register a URI handler. | |
void | ast_http_uri_unlink (struct ast_http_uri *urihandler) |
Unregister a URI handler. | |
void | ast_http_uri_unlink_all_with_key (const char *key) |
Unregister all handlers with matching key. |
Support for Private Asterisk HTTP Servers.
Definition in file http.h.
typedef int(* ast_http_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) |
HTTP Callbacks.
Status and status text should be sent as arguments to the ast_http_send() function to reflect the status of the request (200 or 304, for example). Content length is calculated by ast_http_send() automatically.
Static content may be indicated to the ast_http_send() function, to indicate that it may be cached.
* The return value may include additional headers at the front and MUST * include a blank line with \r\n to provide separation between user headers * and content (even if no content is specified) *
For an error response, the ast_http_error() function may be used.
enum ast_http_method |
HTTP Request methods known by Asterisk.
AST_HTTP_UNKNOWN |
Unknown response |
AST_HTTP_GET | |
AST_HTTP_POST | |
AST_HTTP_HEAD | |
AST_HTTP_PUT |
Not supported in Asterisk |
Definition at line 56 of file http.h.
00056 { 00057 AST_HTTP_UNKNOWN = -1, /*!< Unknown response */ 00058 AST_HTTP_GET = 0, 00059 AST_HTTP_POST, 00060 AST_HTTP_HEAD, 00061 AST_HTTP_PUT, /*!< Not supported in Asterisk */ 00062 };
const char* ast_get_http_method | ( | enum ast_http_method | method | ) |
Return http method name string.
Definition at line 153 of file http.c.
References ARRAY_LEN, ast_http_methods_text, and ast_cfhttp_methods_text::text.
Referenced by auth_http_callback().
00154 { 00155 int x; 00156 00157 for (x = 0; x < ARRAY_LEN(ast_http_methods_text); x++) { 00158 if (ast_http_methods_text[x].method == method) { 00159 return ast_http_methods_text[x].text; 00160 } 00161 } 00162 00163 return NULL; 00164 }
void ast_http_auth | ( | struct ast_tcptls_session_instance * | ser, | |
const char * | realm, | |||
const unsigned long | nonce, | |||
const unsigned long | opaque, | |||
int | stale, | |||
const char * | text | |||
) |
Send http "401 Unauthorized" response and close socket.
Definition at line 468 of file http.c.
References ast_free, ast_http_send(), AST_HTTP_UNKNOWN, ast_str_create(), and ast_str_set().
Referenced by auth_http_callback().
00471 { 00472 struct ast_str *http_headers = ast_str_create(128); 00473 struct ast_str *out = ast_str_create(512); 00474 00475 if (!http_headers || !out) { 00476 ast_free(http_headers); 00477 ast_free(out); 00478 return; 00479 } 00480 00481 ast_str_set(&http_headers, 0, 00482 "WWW-authenticate: Digest algorithm=MD5, realm=\"%s\", nonce=\"%08lx\", qop=\"auth\", opaque=\"%08lx\"%s\r\n" 00483 "Content-type: text/html\r\n", 00484 realm ? realm : "Asterisk", 00485 nonce, 00486 opaque, 00487 stale ? ", stale=true" : ""); 00488 00489 ast_str_set(&out, 0, 00490 "<!DOCTYPE HTML PUBLIC \"-//IETF//DTD HTML 2.0//EN\">\r\n" 00491 "<html><head>\r\n" 00492 "<title>401 Unauthorized</title>\r\n" 00493 "</head><body>\r\n" 00494 "<h1>401 Unauthorized</h1>\r\n" 00495 "<p>%s</p>\r\n" 00496 "<hr />\r\n" 00497 "<address>Asterisk Server</address>\r\n" 00498 "</body></html>\r\n", 00499 text ? text : ""); 00500 00501 ast_http_send(ser, AST_HTTP_UNKNOWN, 401, "Unauthorized", http_headers, out, 0, 0); 00502 return; 00503 }
void ast_http_error | ( | struct ast_tcptls_session_instance * | ser, | |
int | status, | |||
const char * | title, | |||
const char * | text | |||
) |
Send HTTP error message and close socket.
Definition at line 506 of file http.c.
References ast_free, ast_http_send(), AST_HTTP_UNKNOWN, ast_str_create(), and ast_str_set().
Referenced by auth_http_callback(), generic_http_callback(), handle_uri(), http_post_callback(), httpd_helper_thread(), httpstatus_callback(), phoneprov_callback(), and static_callback().
00507 { 00508 struct ast_str *http_headers = ast_str_create(40); 00509 struct ast_str *out = ast_str_create(256); 00510 00511 if (!http_headers || !out) { 00512 ast_free(http_headers); 00513 ast_free(out); 00514 return; 00515 } 00516 00517 ast_str_set(&http_headers, 0, "Content-type: text/html\r\n"); 00518 00519 ast_str_set(&out, 0, 00520 "<!DOCTYPE HTML PUBLIC \"-//IETF//DTD HTML 2.0//EN\">\r\n" 00521 "<html><head>\r\n" 00522 "<title>%d %s</title>\r\n" 00523 "</head><body>\r\n" 00524 "<h1>%s</h1>\r\n" 00525 "<p>%s</p>\r\n" 00526 "<hr />\r\n" 00527 "<address>Asterisk Server</address>\r\n" 00528 "</body></html>\r\n", 00529 status_code, status_title, status_title, text); 00530 00531 ast_http_send(ser, AST_HTTP_UNKNOWN, status_code, status_title, http_headers, out, 0, 0); 00532 return; 00533 }
const char* ast_http_ftype2mtype | ( | const char * | ftype | ) |
Return mime type based on extension.
ftype | filename extension |
Definition at line 166 of file http.c.
References ARRAY_LEN, ext, and mimetypes.
Referenced by build_profile(), and static_callback().
struct ast_variable* ast_http_get_cookies | ( | struct ast_variable * | headers | ) | [read] |
Get cookie from Request headers.
Definition at line 862 of file http.c.
References ast_variables_destroy(), ast_variable::name, ast_variable::next, parse_cookies(), and ast_variable::value.
Referenced by ast_http_manid_from_vars(), generic_http_callback(), http_post_callback(), and httpstatus_callback().
00863 { 00864 struct ast_variable *v, *cookies = NULL; 00865 00866 for (v = headers; v; v = v->next) { 00867 if (!strcasecmp(v->name, "Cookie")) { 00868 ast_variables_destroy(cookies); 00869 cookies = parse_cookies(v->value); 00870 } 00871 } 00872 return cookies; 00873 }
struct ast_variable* ast_http_get_post_vars | ( | struct ast_tcptls_session_instance * | ser, | |
struct ast_variable * | headers | |||
) | [read] |
Get post variables from client Request Entity-Body, if content type is application/x-www-form-urlencoded.
ser | TCP/TLS session object | |
headers | List of HTTP headers |
Definition at line 624 of file http.c.
References ast_free, AST_HTTP_POST, ast_http_send(), ast_log(), ast_malloc, ast_variable_new(), ast_tcptls_session_instance::f, http_decode(), LOG_WARNING, MAX_POST_CONTENT, ast_variable::name, ast_variable::next, ast_variable::value, and var.
Referenced by auth_http_callback(), and generic_http_callback().
00626 { 00627 int content_length = 0; 00628 struct ast_variable *v, *post_vars=NULL, *prev = NULL; 00629 char *buf, *var, *val; 00630 int res; 00631 00632 for (v = headers; v; v = v->next) { 00633 if (!strcasecmp(v->name, "Content-Type")) { 00634 if (strcasecmp(v->value, "application/x-www-form-urlencoded")) { 00635 return NULL; 00636 } 00637 break; 00638 } 00639 } 00640 00641 for (v = headers; v; v = v->next) { 00642 if (!strcasecmp(v->name, "Content-Length")) { 00643 content_length = atoi(v->value); 00644 break; 00645 } 00646 } 00647 00648 if (content_length <= 0) { 00649 return NULL; 00650 } 00651 00652 if (content_length > MAX_POST_CONTENT - 1) { 00653 ast_log(LOG_WARNING, "Excessively long HTTP content. %d is greater than our max of %d\n", 00654 content_length, MAX_POST_CONTENT); 00655 ast_http_send(ser, AST_HTTP_POST, 413, "Request Entity Too Large", NULL, NULL, 0, 0); 00656 return NULL; 00657 } 00658 00659 buf = ast_malloc(content_length + 1); 00660 if (!buf) { 00661 return NULL; 00662 } 00663 00664 res = fread(buf, 1, content_length, ser->f); 00665 if (res < content_length) { 00666 /* Error, distinguishable by ferror() or feof(), but neither 00667 * is good. */ 00668 goto done; 00669 } 00670 buf[content_length] = '\0'; 00671 00672 while ((val = strsep(&buf, "&"))) { 00673 var = strsep(&val, "="); 00674 if (val) { 00675 http_decode(val); 00676 } else { 00677 val = ""; 00678 } 00679 http_decode(var); 00680 if ((v = ast_variable_new(var, val, ""))) { 00681 if (post_vars) { 00682 prev->next = v; 00683 } else { 00684 post_vars = v; 00685 } 00686 prev = v; 00687 } 00688 } 00689 00690 done: 00691 ast_free(buf); 00692 return post_vars; 00693 }
uint32_t ast_http_manid_from_vars | ( | struct ast_variable * | headers | ) |
Return manager id, if exist, from request headers.
headers | List of HTTP headers |
Definition at line 180 of file http.c.
References ast_http_get_cookies(), ast_variables_destroy(), ast_variable::name, ast_variable::next, and ast_variable::value.
Referenced by http_post_callback(), and static_callback().
00181 { 00182 uint32_t mngid = 0; 00183 struct ast_variable *v, *cookies; 00184 00185 cookies = ast_http_get_cookies(headers); 00186 for (v = cookies; v; v = v->next) { 00187 if (!strcasecmp(v->name, "mansession_id")) { 00188 sscanf(v->value, "%30x", &mngid); 00189 break; 00190 } 00191 } 00192 ast_variables_destroy(cookies); 00193 return mngid; 00194 }
void ast_http_prefix | ( | char * | buf, | |
int | len | |||
) |
Return the current prefix.
[out] | buf | destination buffer for previous |
[in] | len | length of prefix to copy |
Definition at line 196 of file http.c.
References ast_copy_string().
00197 { 00198 if (buf) { 00199 ast_copy_string(buf, prefix, len); 00200 } 00201 }
void ast_http_send | ( | struct ast_tcptls_session_instance * | ser, | |
enum ast_http_method | method, | |||
int | status_code, | |||
const char * | status_title, | |||
struct ast_str * | http_header, | |||
struct ast_str * | out, | |||
const int | fd, | |||
unsigned int | static_content | |||
) |
Generic function for sending http/1.1 response.
ser | TCP/TLS session object | |
method | GET/POST/HEAD | |
status_code | HTTP response code (200/401/403/404/500) | |
status_title | English equivalent to the status_code parameter | |
http_header | An ast_str object containing all headers | |
out | An ast_str object containing the body of the response | |
fd | If out is NULL, a file descriptor where the body of the response is held (otherwise -1) | |
static_content | Zero if the content is dynamically generated and should not be cached; nonzero otherwise |
Extra HTTP headers MUST be present only in the http_header argument. The argument "out" should contain only content of the response (no headers!).
HTTP content can be constructed from the argument "out", if it is not NULL; otherwise, the function will read content from FD.
This function calculates the content-length http header itself.
Both the http_header and out arguments will be freed by this function; however, if FD is open, it will remain open.
Definition at line 393 of file http.c.
References ast_free, ast_get_version(), AST_HTTP_HEAD, ast_localtime(), ast_log(), ast_str_buffer(), ast_str_strlen(), ast_strftime(), ast_tcptls_close_session_file(), ast_tvnow(), errno, ast_tcptls_session_instance::f, len(), LOG_ERROR, and LOG_WARNING.
Referenced by ast_http_auth(), ast_http_error(), ast_http_get_post_vars(), auth_http_callback(), generic_http_callback(), handle_uri(), httpstatus_callback(), phoneprov_callback(), and static_callback().
00397 { 00398 struct timeval now = ast_tvnow(); 00399 struct ast_tm tm; 00400 char timebuf[80]; 00401 int content_length = 0; 00402 00403 if (!ser || 0 == ser->f) { 00404 return; 00405 } 00406 00407 ast_strftime(timebuf, sizeof(timebuf), "%a, %d %b %Y %H:%M:%S GMT", ast_localtime(&now, &tm, "GMT")); 00408 00409 /* calc content length */ 00410 if (out) { 00411 content_length += ast_str_strlen(out); 00412 } 00413 00414 if (fd) { 00415 content_length += lseek(fd, 0, SEEK_END); 00416 lseek(fd, 0, SEEK_SET); 00417 } 00418 00419 /* send http header */ 00420 fprintf(ser->f, "HTTP/1.1 %d %s\r\n" 00421 "Server: Asterisk/%s\r\n" 00422 "Date: %s\r\n" 00423 "Connection: close\r\n" 00424 "%s" 00425 "Content-Length: %d\r\n" 00426 "%s" 00427 "\r\n", 00428 status_code, status_title ? status_title : "OK", 00429 ast_get_version(), 00430 timebuf, 00431 static_content ? "" : "Cache-Control: no-cache, no-store\r\n", 00432 content_length, 00433 http_header ? ast_str_buffer(http_header) : "" 00434 ); 00435 00436 /* send content */ 00437 if (method != AST_HTTP_HEAD || status_code >= 400) { 00438 if (out && ast_str_strlen(out)) { 00439 if (fwrite(ast_str_buffer(out), ast_str_strlen(out), 1, ser->f) != 1) { 00440 ast_log(LOG_ERROR, "fwrite() failed: %s\n", strerror(errno)); 00441 } 00442 } 00443 00444 if (fd) { 00445 char buf[256]; 00446 int len; 00447 while ((len = read(fd, buf, sizeof(buf))) > 0) { 00448 if (fwrite(buf, len, 1, ser->f) != 1) { 00449 ast_log(LOG_WARNING, "fwrite() failed: %s\n", strerror(errno)); 00450 break; 00451 } 00452 } 00453 } 00454 } 00455 00456 if (http_header) { 00457 ast_free(http_header); 00458 } 00459 if (out) { 00460 ast_free(out); 00461 } 00462 00463 ast_tcptls_close_session_file(ser); 00464 return; 00465 }
int ast_http_uri_link | ( | struct ast_http_uri * | urih | ) |
Register a URI handler.
Register a URI handler.
They are sorted by length of the string, not alphabetically. Duplicate entries are not replaced, but the insertion order (using <= and not just <) makes sure that more recent insertions hide older ones. On a lookup, we just scan the list and stop at the first matching entry.
Definition at line 544 of file http.c.
References AST_RWLIST_EMPTY, AST_RWLIST_FIRST, AST_RWLIST_INSERT_AFTER, AST_RWLIST_INSERT_HEAD, AST_RWLIST_INSERT_TAIL, AST_RWLIST_NEXT, AST_RWLIST_TRAVERSE, AST_RWLIST_UNLOCK, AST_RWLIST_WRLOCK, http_uri_redirect::entry, len(), and ast_http_uri::uri.
Referenced by __ast_http_post_load(), __init_manager(), ast_http_init(), and load_module().
00545 { 00546 struct ast_http_uri *uri; 00547 int len = strlen(urih->uri); 00548 00549 AST_RWLIST_WRLOCK(&uris); 00550 00551 if ( AST_RWLIST_EMPTY(&uris) || strlen(AST_RWLIST_FIRST(&uris)->uri) <= len ) { 00552 AST_RWLIST_INSERT_HEAD(&uris, urih, entry); 00553 AST_RWLIST_UNLOCK(&uris); 00554 return 0; 00555 } 00556 00557 AST_RWLIST_TRAVERSE(&uris, uri, entry) { 00558 if (AST_RWLIST_NEXT(uri, entry) && 00559 strlen(AST_RWLIST_NEXT(uri, entry)->uri) <= len) { 00560 AST_RWLIST_INSERT_AFTER(&uris, uri, urih, entry); 00561 AST_RWLIST_UNLOCK(&uris); 00562 00563 return 0; 00564 } 00565 } 00566 00567 AST_RWLIST_INSERT_TAIL(&uris, urih, entry); 00568 00569 AST_RWLIST_UNLOCK(&uris); 00570 00571 return 0; 00572 }
void ast_http_uri_unlink | ( | struct ast_http_uri * | urihandler | ) |
Unregister a URI handler.
Definition at line 574 of file http.c.
References AST_RWLIST_REMOVE, AST_RWLIST_UNLOCK, AST_RWLIST_WRLOCK, and http_uri_redirect::entry.
Referenced by __init_manager(), http_shutdown(), and unload_module().
00575 { 00576 AST_RWLIST_WRLOCK(&uris); 00577 AST_RWLIST_REMOVE(&uris, urih, entry); 00578 AST_RWLIST_UNLOCK(&uris); 00579 }
void ast_http_uri_unlink_all_with_key | ( | const char * | key | ) |
Unregister all handlers with matching key.
Definition at line 581 of file http.c.
References ast_free, AST_RWLIST_REMOVE_CURRENT, AST_RWLIST_TRAVERSE_SAFE_BEGIN, AST_RWLIST_TRAVERSE_SAFE_END, AST_RWLIST_UNLOCK, AST_RWLIST_WRLOCK, ast_http_uri::data, ast_http_uri::dmallocd, http_uri_redirect::entry, ast_http_uri::key, and ast_http_uri::mallocd.
Referenced by __ast_http_post_load(), and unload_module().
00582 { 00583 struct ast_http_uri *urih; 00584 AST_RWLIST_WRLOCK(&uris); 00585 AST_RWLIST_TRAVERSE_SAFE_BEGIN(&uris, urih, entry) { 00586 if (!strcmp(urih->key, key)) { 00587 AST_RWLIST_REMOVE_CURRENT(entry); 00588 if (urih->dmallocd) { 00589 ast_free(urih->data); 00590 } 00591 if (urih->mallocd) { 00592 ast_free(urih); 00593 } 00594 } 00595 } 00596 AST_RWLIST_TRAVERSE_SAFE_END; 00597 AST_RWLIST_UNLOCK(&uris); 00598 }