http.c 34 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319
  1. /*
  2. * Asterisk -- An open source telephony toolkit.
  3. *
  4. * Copyright (C) 1999 - 2006, Digium, Inc.
  5. *
  6. * Mark Spencer <markster@digium.com>
  7. *
  8. * See http://www.asterisk.org for more information about
  9. * the Asterisk project. Please do not directly contact
  10. * any of the maintainers of this project for assistance;
  11. * the project provides a web site, mailing lists and IRC
  12. * channels for your use.
  13. *
  14. * This program is free software, distributed under the terms of
  15. * the GNU General Public License Version 2. See the LICENSE file
  16. * at the top of the source tree.
  17. */
  18. /*!
  19. * \file
  20. * \brief http server for AMI access
  21. *
  22. * \author Mark Spencer <markster@digium.com>
  23. *
  24. * This program implements a tiny http server
  25. * and was inspired by micro-httpd by Jef Poskanzer
  26. *
  27. * \extref GMime http://spruce.sourceforge.net/gmime/
  28. *
  29. * \ref AstHTTP - AMI over the http protocol
  30. */
  31. /*** MODULEINFO
  32. <support_level>core</support_level>
  33. ***/
  34. #include "asterisk.h"
  35. ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
  36. #include <time.h>
  37. #include <sys/time.h>
  38. #include <sys/stat.h>
  39. #include <sys/signal.h>
  40. #include <fcntl.h>
  41. #include "asterisk/paths.h" /* use ast_config_AST_DATA_DIR */
  42. #include "asterisk/cli.h"
  43. #include "asterisk/tcptls.h"
  44. #include "asterisk/http.h"
  45. #include "asterisk/utils.h"
  46. #include "asterisk/strings.h"
  47. #include "asterisk/config.h"
  48. #include "asterisk/stringfields.h"
  49. #include "asterisk/ast_version.h"
  50. #include "asterisk/manager.h"
  51. #include "asterisk/_private.h"
  52. #include "asterisk/astobj2.h"
  53. #include "asterisk/netsock2.h"
  54. #define MAX_PREFIX 80
  55. #define DEFAULT_PORT 8088
  56. #define DEFAULT_TLS_PORT 8089
  57. #define DEFAULT_SESSION_LIMIT 100
  58. #define DEFAULT_SESSION_INACTIVITY 30000 /* (ms) Idle time waiting for data. */
  59. /* See http.h for more information about the SSL implementation */
  60. #if defined(HAVE_OPENSSL) && (defined(HAVE_FUNOPEN) || defined(HAVE_FOPENCOOKIE))
  61. #define DO_SSL /* comment in/out if you want to support ssl */
  62. #endif
  63. static int session_limit = DEFAULT_SESSION_LIMIT;
  64. static int session_inactivity = DEFAULT_SESSION_INACTIVITY;
  65. static int session_count = 0;
  66. static struct ast_tls_config http_tls_cfg;
  67. static void *httpd_helper_thread(void *arg);
  68. /*!
  69. * we have up to two accepting threads, one for http, one for https
  70. */
  71. static struct ast_tcptls_session_args http_desc = {
  72. .accept_fd = -1,
  73. .master = AST_PTHREADT_NULL,
  74. .tls_cfg = NULL,
  75. .poll_timeout = -1,
  76. .name = "http server",
  77. .accept_fn = ast_tcptls_server_root,
  78. .worker_fn = httpd_helper_thread,
  79. };
  80. static struct ast_tcptls_session_args https_desc = {
  81. .accept_fd = -1,
  82. .master = AST_PTHREADT_NULL,
  83. .tls_cfg = &http_tls_cfg,
  84. .poll_timeout = -1,
  85. .name = "https server",
  86. .accept_fn = ast_tcptls_server_root,
  87. .worker_fn = httpd_helper_thread,
  88. };
  89. static AST_RWLIST_HEAD_STATIC(uris, ast_http_uri); /*!< list of supported handlers */
  90. /* all valid URIs must be prepended by the string in prefix. */
  91. static char prefix[MAX_PREFIX];
  92. static int enablestatic;
  93. /*! \brief Limit the kinds of files we're willing to serve up */
  94. static struct {
  95. const char *ext;
  96. const char *mtype;
  97. } mimetypes[] = {
  98. { "png", "image/png" },
  99. { "xml", "text/xml" },
  100. { "jpg", "image/jpeg" },
  101. { "js", "application/x-javascript" },
  102. { "wav", "audio/x-wav" },
  103. { "mp3", "audio/mpeg" },
  104. { "svg", "image/svg+xml" },
  105. { "svgz", "image/svg+xml" },
  106. { "gif", "image/gif" },
  107. { "html", "text/html" },
  108. { "htm", "text/html" },
  109. { "css", "text/css" },
  110. { "cnf", "text/plain" },
  111. { "cfg", "text/plain" },
  112. { "bin", "application/octet-stream" },
  113. { "sbn", "application/octet-stream" },
  114. { "ld", "application/octet-stream" },
  115. };
  116. struct http_uri_redirect {
  117. AST_LIST_ENTRY(http_uri_redirect) entry;
  118. char *dest;
  119. char target[0];
  120. };
  121. static AST_RWLIST_HEAD_STATIC(uri_redirects, http_uri_redirect);
  122. static const struct ast_cfhttp_methods_text {
  123. enum ast_http_method method;
  124. const char *text;
  125. } ast_http_methods_text[] = {
  126. { AST_HTTP_UNKNOWN, "UNKNOWN" },
  127. { AST_HTTP_GET, "GET" },
  128. { AST_HTTP_POST, "POST" },
  129. { AST_HTTP_HEAD, "HEAD" },
  130. { AST_HTTP_PUT, "PUT" },
  131. };
  132. const char *ast_get_http_method(enum ast_http_method method)
  133. {
  134. int x;
  135. for (x = 0; x < ARRAY_LEN(ast_http_methods_text); x++) {
  136. if (ast_http_methods_text[x].method == method) {
  137. return ast_http_methods_text[x].text;
  138. }
  139. }
  140. return NULL;
  141. }
  142. const char *ast_http_ftype2mtype(const char *ftype)
  143. {
  144. int x;
  145. if (ftype) {
  146. for (x = 0; x < ARRAY_LEN(mimetypes); x++) {
  147. if (!strcasecmp(ftype, mimetypes[x].ext)) {
  148. return mimetypes[x].mtype;
  149. }
  150. }
  151. }
  152. return NULL;
  153. }
  154. uint32_t ast_http_manid_from_vars(struct ast_variable *headers)
  155. {
  156. uint32_t mngid = 0;
  157. struct ast_variable *v, *cookies;
  158. cookies = ast_http_get_cookies(headers);
  159. for (v = cookies; v; v = v->next) {
  160. if (!strcasecmp(v->name, "mansession_id")) {
  161. sscanf(v->value, "%30x", &mngid);
  162. break;
  163. }
  164. }
  165. ast_variables_destroy(cookies);
  166. return mngid;
  167. }
  168. void ast_http_prefix(char *buf, int len)
  169. {
  170. if (buf) {
  171. ast_copy_string(buf, prefix, len);
  172. }
  173. }
  174. static int static_callback(struct ast_tcptls_session_instance *ser,
  175. const struct ast_http_uri *urih, const char *uri,
  176. enum ast_http_method method, struct ast_variable *get_vars,
  177. struct ast_variable *headers)
  178. {
  179. char *path;
  180. const char *ftype;
  181. const char *mtype;
  182. char wkspace[80];
  183. struct stat st;
  184. int len;
  185. int fd;
  186. struct ast_str *http_header;
  187. struct timeval tv;
  188. struct ast_tm tm;
  189. char timebuf[80], etag[23];
  190. struct ast_variable *v;
  191. int not_modified = 0;
  192. if (method != AST_HTTP_GET && method != AST_HTTP_HEAD) {
  193. ast_http_error(ser, 501, "Not Implemented", "Attempt to use unimplemented / unsupported method");
  194. return -1;
  195. }
  196. /* Yuck. I'm not really sold on this, but if you don't deliver static content it makes your configuration
  197. substantially more challenging, but this seems like a rather irritating feature creep on Asterisk. */
  198. if (!enablestatic || ast_strlen_zero(uri)) {
  199. goto out403;
  200. }
  201. /* Disallow any funny filenames at all (checking first character only??) */
  202. if ((uri[0] < 33) || strchr("./|~@#$%^&*() \t", uri[0])) {
  203. goto out403;
  204. }
  205. if (strstr(uri, "/..")) {
  206. goto out403;
  207. }
  208. if ((ftype = strrchr(uri, '.'))) {
  209. ftype++;
  210. }
  211. if (!(mtype = ast_http_ftype2mtype(ftype))) {
  212. snprintf(wkspace, sizeof(wkspace), "text/%s", S_OR(ftype, "plain"));
  213. mtype = wkspace;
  214. }
  215. /* Cap maximum length */
  216. if ((len = strlen(uri) + strlen(ast_config_AST_DATA_DIR) + strlen("/static-http/") + 5) > 1024) {
  217. goto out403;
  218. }
  219. path = ast_alloca(len);
  220. sprintf(path, "%s/static-http/%s", ast_config_AST_DATA_DIR, uri);
  221. if (stat(path, &st)) {
  222. goto out404;
  223. }
  224. if (S_ISDIR(st.st_mode)) {
  225. goto out404;
  226. }
  227. if (strstr(path, "/private/") && !astman_is_authed(ast_http_manid_from_vars(headers))) {
  228. goto out403;
  229. }
  230. fd = open(path, O_RDONLY);
  231. if (fd < 0) {
  232. goto out403;
  233. }
  234. /* make "Etag:" http header value */
  235. snprintf(etag, sizeof(etag), "\"%ld\"", (long)st.st_mtime);
  236. /* make "Last-Modified:" http header value */
  237. tv.tv_sec = st.st_mtime;
  238. tv.tv_usec = 0;
  239. ast_strftime(timebuf, sizeof(timebuf), "%a, %d %b %Y %H:%M:%S GMT", ast_localtime(&tv, &tm, "GMT"));
  240. /* check received "If-None-Match" request header and Etag value for file */
  241. for (v = headers; v; v = v->next) {
  242. if (!strcasecmp(v->name, "If-None-Match")) {
  243. if (!strcasecmp(v->value, etag)) {
  244. not_modified = 1;
  245. }
  246. break;
  247. }
  248. }
  249. if ( (http_header = ast_str_create(255)) == NULL) {
  250. close(fd);
  251. return -1;
  252. }
  253. ast_str_set(&http_header, 0, "Content-type: %s\r\n"
  254. "ETag: %s\r\n"
  255. "Last-Modified: %s\r\n",
  256. mtype,
  257. etag,
  258. timebuf);
  259. /* ast_http_send() frees http_header, so we don't need to do it before returning */
  260. if (not_modified) {
  261. ast_http_send(ser, method, 304, "Not Modified", http_header, NULL, 0, 1);
  262. } else {
  263. ast_http_send(ser, method, 200, NULL, http_header, NULL, fd, 1); /* static content flag is set */
  264. }
  265. close(fd);
  266. return 0;
  267. out404:
  268. ast_http_error(ser, 404, "Not Found", "The requested URL was not found on this server.");
  269. return -1;
  270. out403:
  271. ast_http_error(ser, 403, "Access Denied", "You do not have permission to access the requested URL.");
  272. return -1;
  273. }
  274. static int httpstatus_callback(struct ast_tcptls_session_instance *ser,
  275. const struct ast_http_uri *urih, const char *uri,
  276. enum ast_http_method method, struct ast_variable *get_vars,
  277. struct ast_variable *headers)
  278. {
  279. struct ast_str *out;
  280. struct ast_variable *v, *cookies = NULL;
  281. if (method != AST_HTTP_GET && method != AST_HTTP_HEAD) {
  282. ast_http_error(ser, 501, "Not Implemented", "Attempt to use unimplemented / unsupported method");
  283. return -1;
  284. }
  285. if ( (out = ast_str_create(512)) == NULL) {
  286. return -1;
  287. }
  288. ast_str_append(&out, 0,
  289. "<html><title>Asterisk HTTP Status</title>\r\n"
  290. "<body bgcolor=\"#ffffff\">\r\n"
  291. "<table bgcolor=\"#f1f1f1\" align=\"center\"><tr><td bgcolor=\"#e0e0ff\" colspan=\"2\" width=\"500\">\r\n"
  292. "<h2>&nbsp;&nbsp;Asterisk&trade; HTTP Status</h2></td></tr>\r\n");
  293. ast_str_append(&out, 0, "<tr><td><i>Prefix</i></td><td><b>%s</b></td></tr>\r\n", prefix);
  294. ast_str_append(&out, 0, "<tr><td><i>Bind Address</i></td><td><b>%s</b></td></tr>\r\n",
  295. ast_sockaddr_stringify_addr(&http_desc.old_address));
  296. ast_str_append(&out, 0, "<tr><td><i>Bind Port</i></td><td><b>%s</b></td></tr>\r\n",
  297. ast_sockaddr_stringify_port(&http_desc.old_address));
  298. if (http_tls_cfg.enabled) {
  299. ast_str_append(&out, 0, "<tr><td><i>SSL Bind Port</i></td><td><b>%s</b></td></tr>\r\n",
  300. ast_sockaddr_stringify_port(&https_desc.old_address));
  301. }
  302. ast_str_append(&out, 0, "<tr><td colspan=\"2\"><hr></td></tr>\r\n");
  303. for (v = get_vars; v; v = v->next) {
  304. ast_str_append(&out, 0, "<tr><td><i>Submitted GET Variable '%s'</i></td><td>%s</td></tr>\r\n", v->name, v->value);
  305. }
  306. ast_str_append(&out, 0, "<tr><td colspan=\"2\"><hr></td></tr>\r\n");
  307. cookies = ast_http_get_cookies(headers);
  308. for (v = cookies; v; v = v->next) {
  309. ast_str_append(&out, 0, "<tr><td><i>Cookie '%s'</i></td><td>%s</td></tr>\r\n", v->name, v->value);
  310. }
  311. ast_variables_destroy(cookies);
  312. ast_str_append(&out, 0, "</table><center><font size=\"-1\"><i>Asterisk and Digium are registered trademarks of Digium, Inc.</i></font></center></body></html>\r\n");
  313. ast_http_send(ser, method, 200, NULL, NULL, out, 0, 0);
  314. return 0;
  315. }
  316. static struct ast_http_uri statusuri = {
  317. .callback = httpstatus_callback,
  318. .description = "Asterisk HTTP General Status",
  319. .uri = "httpstatus",
  320. .has_subtree = 0,
  321. .data = NULL,
  322. .key = __FILE__,
  323. };
  324. static struct ast_http_uri staticuri = {
  325. .callback = static_callback,
  326. .description = "Asterisk HTTP Static Delivery",
  327. .uri = "static",
  328. .has_subtree = 1,
  329. .data = NULL,
  330. .key= __FILE__,
  331. };
  332. /* send http/1.1 response */
  333. /* free content variable and close socket*/
  334. void ast_http_send(struct ast_tcptls_session_instance *ser,
  335. enum ast_http_method method, int status_code, const char *status_title,
  336. struct ast_str *http_header, struct ast_str *out, const int fd,
  337. unsigned int static_content)
  338. {
  339. struct timeval now = ast_tvnow();
  340. struct ast_tm tm;
  341. char timebuf[80];
  342. int content_length = 0;
  343. if (!ser || 0 == ser->f) {
  344. return;
  345. }
  346. ast_strftime(timebuf, sizeof(timebuf), "%a, %d %b %Y %H:%M:%S GMT", ast_localtime(&now, &tm, "GMT"));
  347. /* calc content length */
  348. if (out) {
  349. content_length += ast_str_strlen(out);
  350. }
  351. if (fd) {
  352. content_length += lseek(fd, 0, SEEK_END);
  353. lseek(fd, 0, SEEK_SET);
  354. }
  355. /* send http header */
  356. fprintf(ser->f, "HTTP/1.1 %d %s\r\n"
  357. "Server: Asterisk/%s\r\n"
  358. "Date: %s\r\n"
  359. "Connection: close\r\n"
  360. "%s"
  361. "Content-Length: %d\r\n"
  362. "%s"
  363. "\r\n",
  364. status_code, status_title ? status_title : "OK",
  365. ast_get_version(),
  366. timebuf,
  367. static_content ? "" : "Cache-Control: no-cache, no-store\r\n",
  368. content_length,
  369. http_header ? ast_str_buffer(http_header) : ""
  370. );
  371. /* send content */
  372. if (method != AST_HTTP_HEAD || status_code >= 400) {
  373. if (out && ast_str_strlen(out)) {
  374. if (fwrite(ast_str_buffer(out), ast_str_strlen(out), 1, ser->f) != 1) {
  375. ast_log(LOG_ERROR, "fwrite() failed: %s\n", strerror(errno));
  376. }
  377. }
  378. if (fd) {
  379. char buf[256];
  380. int len;
  381. while ((len = read(fd, buf, sizeof(buf))) > 0) {
  382. if (fwrite(buf, len, 1, ser->f) != 1) {
  383. ast_log(LOG_WARNING, "fwrite() failed: %s\n", strerror(errno));
  384. break;
  385. }
  386. }
  387. }
  388. }
  389. if (http_header) {
  390. ast_free(http_header);
  391. }
  392. if (out) {
  393. ast_free(out);
  394. }
  395. ast_tcptls_close_session_file(ser);
  396. return;
  397. }
  398. /* Send http "401 Unauthorized" responce and close socket*/
  399. void ast_http_auth(struct ast_tcptls_session_instance *ser, const char *realm,
  400. const unsigned long nonce, const unsigned long opaque, int stale,
  401. const char *text)
  402. {
  403. struct ast_str *http_headers = ast_str_create(128);
  404. struct ast_str *out = ast_str_create(512);
  405. if (!http_headers || !out) {
  406. ast_free(http_headers);
  407. ast_free(out);
  408. return;
  409. }
  410. ast_str_set(&http_headers, 0,
  411. "WWW-authenticate: Digest algorithm=MD5, realm=\"%s\", nonce=\"%08lx\", qop=\"auth\", opaque=\"%08lx\"%s\r\n"
  412. "Content-type: text/html\r\n",
  413. realm ? realm : "Asterisk",
  414. nonce,
  415. opaque,
  416. stale ? ", stale=true" : "");
  417. ast_str_set(&out, 0,
  418. "<!DOCTYPE HTML PUBLIC \"-//IETF//DTD HTML 2.0//EN\">\r\n"
  419. "<html><head>\r\n"
  420. "<title>401 Unauthorized</title>\r\n"
  421. "</head><body>\r\n"
  422. "<h1>401 Unauthorized</h1>\r\n"
  423. "<p>%s</p>\r\n"
  424. "<hr />\r\n"
  425. "<address>Asterisk Server</address>\r\n"
  426. "</body></html>\r\n",
  427. text ? text : "");
  428. ast_http_send(ser, AST_HTTP_UNKNOWN, 401, "Unauthorized", http_headers, out, 0, 0);
  429. return;
  430. }
  431. /* send http error response and close socket*/
  432. void ast_http_error(struct ast_tcptls_session_instance *ser, int status_code, const char *status_title, const char *text)
  433. {
  434. struct ast_str *http_headers = ast_str_create(40);
  435. struct ast_str *out = ast_str_create(256);
  436. if (!http_headers || !out) {
  437. ast_free(http_headers);
  438. ast_free(out);
  439. return;
  440. }
  441. ast_str_set(&http_headers, 0, "Content-type: text/html\r\n");
  442. ast_str_set(&out, 0,
  443. "<!DOCTYPE HTML PUBLIC \"-//IETF//DTD HTML 2.0//EN\">\r\n"
  444. "<html><head>\r\n"
  445. "<title>%d %s</title>\r\n"
  446. "</head><body>\r\n"
  447. "<h1>%s</h1>\r\n"
  448. "<p>%s</p>\r\n"
  449. "<hr />\r\n"
  450. "<address>Asterisk Server</address>\r\n"
  451. "</body></html>\r\n",
  452. status_code, status_title, status_title, text);
  453. ast_http_send(ser, AST_HTTP_UNKNOWN, status_code, status_title, http_headers, out, 0, 0);
  454. return;
  455. }
  456. /*! \brief
  457. * Link the new uri into the list.
  458. *
  459. * They are sorted by length of
  460. * the string, not alphabetically. Duplicate entries are not replaced,
  461. * but the insertion order (using <= and not just <) makes sure that
  462. * more recent insertions hide older ones.
  463. * On a lookup, we just scan the list and stop at the first matching entry.
  464. */
  465. int ast_http_uri_link(struct ast_http_uri *urih)
  466. {
  467. struct ast_http_uri *uri;
  468. int len = strlen(urih->uri);
  469. AST_RWLIST_WRLOCK(&uris);
  470. if ( AST_RWLIST_EMPTY(&uris) || strlen(AST_RWLIST_FIRST(&uris)->uri) <= len ) {
  471. AST_RWLIST_INSERT_HEAD(&uris, urih, entry);
  472. AST_RWLIST_UNLOCK(&uris);
  473. return 0;
  474. }
  475. AST_RWLIST_TRAVERSE(&uris, uri, entry) {
  476. if (AST_RWLIST_NEXT(uri, entry) &&
  477. strlen(AST_RWLIST_NEXT(uri, entry)->uri) <= len) {
  478. AST_RWLIST_INSERT_AFTER(&uris, uri, urih, entry);
  479. AST_RWLIST_UNLOCK(&uris);
  480. return 0;
  481. }
  482. }
  483. AST_RWLIST_INSERT_TAIL(&uris, urih, entry);
  484. AST_RWLIST_UNLOCK(&uris);
  485. return 0;
  486. }
  487. void ast_http_uri_unlink(struct ast_http_uri *urih)
  488. {
  489. AST_RWLIST_WRLOCK(&uris);
  490. AST_RWLIST_REMOVE(&uris, urih, entry);
  491. AST_RWLIST_UNLOCK(&uris);
  492. }
  493. void ast_http_uri_unlink_all_with_key(const char *key)
  494. {
  495. struct ast_http_uri *urih;
  496. AST_RWLIST_WRLOCK(&uris);
  497. AST_RWLIST_TRAVERSE_SAFE_BEGIN(&uris, urih, entry) {
  498. if (!strcmp(urih->key, key)) {
  499. AST_RWLIST_REMOVE_CURRENT(entry);
  500. if (urih->dmallocd) {
  501. ast_free(urih->data);
  502. }
  503. if (urih->mallocd) {
  504. ast_free(urih);
  505. }
  506. }
  507. }
  508. AST_RWLIST_TRAVERSE_SAFE_END;
  509. AST_RWLIST_UNLOCK(&uris);
  510. }
  511. #define MAX_POST_CONTENT 1025
  512. /*
  513. * get post variables from client Request Entity-Body, if content type is
  514. * application/x-www-form-urlencoded
  515. */
  516. struct ast_variable *ast_http_get_post_vars(
  517. struct ast_tcptls_session_instance *ser, struct ast_variable *headers)
  518. {
  519. int content_length = 0;
  520. struct ast_variable *v, *post_vars=NULL, *prev = NULL;
  521. char *buf, *var, *val;
  522. int res;
  523. for (v = headers; v; v = v->next) {
  524. if (!strcasecmp(v->name, "Content-Type")) {
  525. if (strcasecmp(v->value, "application/x-www-form-urlencoded")) {
  526. return NULL;
  527. }
  528. break;
  529. }
  530. }
  531. for (v = headers; v; v = v->next) {
  532. if (!strcasecmp(v->name, "Content-Length")) {
  533. content_length = atoi(v->value);
  534. break;
  535. }
  536. }
  537. if (content_length <= 0) {
  538. return NULL;
  539. }
  540. if (content_length > MAX_POST_CONTENT - 1) {
  541. ast_log(LOG_WARNING, "Excessively long HTTP content. %d is greater than our max of %d\n",
  542. content_length, MAX_POST_CONTENT);
  543. ast_http_send(ser, AST_HTTP_POST, 413, "Request Entity Too Large", NULL, NULL, 0, 0);
  544. return NULL;
  545. }
  546. buf = ast_malloc(content_length + 1);
  547. if (!buf) {
  548. return NULL;
  549. }
  550. res = fread(buf, 1, content_length, ser->f);
  551. if (res < content_length) {
  552. /* Error, distinguishable by ferror() or feof(), but neither
  553. * is good. */
  554. goto done;
  555. }
  556. buf[content_length] = '\0';
  557. while ((val = strsep(&buf, "&"))) {
  558. var = strsep(&val, "=");
  559. if (val) {
  560. ast_uri_decode(val, ast_uri_http_legacy);
  561. } else {
  562. val = "";
  563. }
  564. ast_uri_decode(var, ast_uri_http_legacy);
  565. if ((v = ast_variable_new(var, val, ""))) {
  566. if (post_vars) {
  567. prev->next = v;
  568. } else {
  569. post_vars = v;
  570. }
  571. prev = v;
  572. }
  573. }
  574. done:
  575. ast_free(buf);
  576. return post_vars;
  577. }
  578. static int handle_uri(struct ast_tcptls_session_instance *ser, char *uri,
  579. enum ast_http_method method, struct ast_variable *headers)
  580. {
  581. char *c;
  582. int res = -1;
  583. char *params = uri;
  584. struct ast_http_uri *urih = NULL;
  585. int l;
  586. struct ast_variable *get_vars = NULL, *v, *prev = NULL;
  587. struct http_uri_redirect *redirect;
  588. ast_debug(2, "HTTP Request URI is %s \n", uri);
  589. strsep(&params, "?");
  590. /* Extract arguments from the request and store them in variables. */
  591. if (params) {
  592. char *var, *val;
  593. while ((val = strsep(&params, "&"))) {
  594. var = strsep(&val, "=");
  595. if (val) {
  596. ast_uri_decode(val, ast_uri_http_legacy);
  597. } else {
  598. val = "";
  599. }
  600. ast_uri_decode(var, ast_uri_http_legacy);
  601. if ((v = ast_variable_new(var, val, ""))) {
  602. if (get_vars) {
  603. prev->next = v;
  604. } else {
  605. get_vars = v;
  606. }
  607. prev = v;
  608. }
  609. }
  610. }
  611. ast_uri_decode(uri, ast_uri_http_legacy);
  612. AST_RWLIST_RDLOCK(&uri_redirects);
  613. AST_RWLIST_TRAVERSE(&uri_redirects, redirect, entry) {
  614. if (!strcasecmp(uri, redirect->target)) {
  615. struct ast_str *http_header = ast_str_create(128);
  616. ast_str_set(&http_header, 0, "Location: %s\r\n", redirect->dest);
  617. ast_http_send(ser, method, 302, "Moved Temporarily", http_header, NULL, 0, 0);
  618. break;
  619. }
  620. }
  621. AST_RWLIST_UNLOCK(&uri_redirects);
  622. if (redirect) {
  623. goto cleanup;
  624. }
  625. /* We want requests to start with the (optional) prefix and '/' */
  626. l = strlen(prefix);
  627. if (!strncasecmp(uri, prefix, l) && uri[l] == '/') {
  628. uri += l + 1;
  629. /* scan registered uris to see if we match one. */
  630. AST_RWLIST_RDLOCK(&uris);
  631. AST_RWLIST_TRAVERSE(&uris, urih, entry) {
  632. ast_debug(2, "match request [%s] with handler [%s] len %d\n", uri, urih->uri, l);
  633. l = strlen(urih->uri);
  634. c = uri + l; /* candidate */
  635. if (strncasecmp(urih->uri, uri, l) /* no match */
  636. || (*c && *c != '/')) { /* substring */
  637. continue;
  638. }
  639. if (*c == '/') {
  640. c++;
  641. }
  642. if (!*c || urih->has_subtree) {
  643. uri = c;
  644. break;
  645. }
  646. }
  647. AST_RWLIST_UNLOCK(&uris);
  648. }
  649. if (urih) {
  650. res = urih->callback(ser, urih, uri, method, get_vars, headers);
  651. } else {
  652. ast_http_error(ser, 404, "Not Found", "The requested URL was not found on this server.");
  653. }
  654. cleanup:
  655. ast_variables_destroy(get_vars);
  656. return res;
  657. }
  658. #ifdef DO_SSL
  659. #if defined(HAVE_FUNOPEN)
  660. #define HOOK_T int
  661. #define LEN_T int
  662. #else
  663. #define HOOK_T ssize_t
  664. #define LEN_T size_t
  665. #endif
  666. /*!
  667. * replacement read/write functions for SSL support.
  668. * We use wrappers rather than SSL_read/SSL_write directly so
  669. * we can put in some debugging.
  670. */
  671. /*static HOOK_T ssl_read(void *cookie, char *buf, LEN_T len)
  672. {
  673. int i = SSL_read(cookie, buf, len-1);
  674. #if 0
  675. if (i >= 0)
  676. buf[i] = '\0';
  677. ast_verbose("ssl read size %d returns %d <%s>\n", (int)len, i, buf);
  678. #endif
  679. return i;
  680. }
  681. static HOOK_T ssl_write(void *cookie, const char *buf, LEN_T len)
  682. {
  683. #if 0
  684. char *s = ast_alloca(len+1);
  685. strncpy(s, buf, len);
  686. s[len] = '\0';
  687. ast_verbose("ssl write size %d <%s>\n", (int)len, s);
  688. #endif
  689. return SSL_write(cookie, buf, len);
  690. }
  691. static int ssl_close(void *cookie)
  692. {
  693. close(SSL_get_fd(cookie));
  694. SSL_shutdown(cookie);
  695. SSL_free(cookie);
  696. return 0;
  697. }*/
  698. #endif /* DO_SSL */
  699. static struct ast_variable *parse_cookies(const char *cookies)
  700. {
  701. char *parse = ast_strdupa(cookies);
  702. char *cur;
  703. struct ast_variable *vars = NULL, *var;
  704. while ((cur = strsep(&parse, ";"))) {
  705. char *name, *val;
  706. name = val = cur;
  707. strsep(&val, "=");
  708. if (ast_strlen_zero(name) || ast_strlen_zero(val)) {
  709. continue;
  710. }
  711. name = ast_strip(name);
  712. val = ast_strip_quoted(val, "\"", "\"");
  713. if (ast_strlen_zero(name) || ast_strlen_zero(val)) {
  714. continue;
  715. }
  716. ast_debug(1, "HTTP Cookie, Name: '%s' Value: '%s'\n", name, val);
  717. var = ast_variable_new(name, val, __FILE__);
  718. var->next = vars;
  719. vars = var;
  720. }
  721. return vars;
  722. }
  723. /* get cookie from Request headers */
  724. struct ast_variable *ast_http_get_cookies(struct ast_variable *headers)
  725. {
  726. struct ast_variable *v, *cookies = NULL;
  727. for (v = headers; v; v = v->next) {
  728. if (!strcasecmp(v->name, "Cookie")) {
  729. ast_variables_destroy(cookies);
  730. cookies = parse_cookies(v->value);
  731. }
  732. }
  733. return cookies;
  734. }
  735. /*! Limit the number of request headers in case the sender is being ridiculous. */
  736. #define MAX_HTTP_REQUEST_HEADERS 100
  737. static void *httpd_helper_thread(void *data)
  738. {
  739. char buf[4096];
  740. char header_line[4096];
  741. struct ast_tcptls_session_instance *ser = data;
  742. struct ast_variable *headers = NULL;
  743. struct ast_variable *tail = headers;
  744. char *uri, *method;
  745. enum ast_http_method http_method = AST_HTTP_UNKNOWN;
  746. int remaining_headers;
  747. int flags;
  748. struct protoent *p;
  749. if (ast_atomic_fetchadd_int(&session_count, +1) >= session_limit) {
  750. goto done;
  751. }
  752. /* here we set TCP_NODELAY on the socket to disable Nagle's algorithm.
  753. * This is necessary to prevent delays (caused by buffering) as we
  754. * write to the socket in bits and pieces. */
  755. p = getprotobyname("tcp");
  756. if (p) {
  757. int arg = 1;
  758. if( setsockopt(ser->fd, p->p_proto, TCP_NODELAY, (char *)&arg, sizeof(arg) ) < 0 ) {
  759. ast_log(LOG_WARNING, "Failed to set TCP_NODELAY on HTTP connection: %s\n", strerror(errno));
  760. ast_log(LOG_WARNING, "Some HTTP requests may be slow to respond.\n");
  761. }
  762. } else {
  763. ast_log(LOG_WARNING, "Failed to set TCP_NODELAY on HTTP connection, getprotobyname(\"tcp\") failed\n");
  764. ast_log(LOG_WARNING, "Some HTTP requests may be slow to respond.\n");
  765. }
  766. /* make sure socket is non-blocking */
  767. flags = fcntl(ser->fd, F_GETFL);
  768. flags |= O_NONBLOCK;
  769. fcntl(ser->fd, F_SETFL, flags);
  770. /* We can let the stream wait for data to arrive. */
  771. ast_tcptls_stream_set_exclusive_input(ser->stream_cookie, 1);
  772. ast_tcptls_stream_set_timeout_inactivity(ser->stream_cookie, session_inactivity);
  773. if (!fgets(buf, sizeof(buf), ser->f) || feof(ser->f)) {
  774. goto done;
  775. }
  776. /* Get method */
  777. method = ast_skip_blanks(buf);
  778. uri = ast_skip_nonblanks(method);
  779. if (*uri) {
  780. *uri++ = '\0';
  781. }
  782. if (!strcasecmp(method,"GET")) {
  783. http_method = AST_HTTP_GET;
  784. } else if (!strcasecmp(method,"POST")) {
  785. http_method = AST_HTTP_POST;
  786. } else if (!strcasecmp(method,"HEAD")) {
  787. http_method = AST_HTTP_HEAD;
  788. } else if (!strcasecmp(method,"PUT")) {
  789. http_method = AST_HTTP_PUT;
  790. }
  791. uri = ast_skip_blanks(uri); /* Skip white space */
  792. if (*uri) { /* terminate at the first blank */
  793. char *c = ast_skip_nonblanks(uri);
  794. if (*c) {
  795. *c = '\0';
  796. }
  797. } else {
  798. ast_http_error(ser, 400, "Bad Request", "Invalid Request");
  799. goto done;
  800. }
  801. /* process "Request Headers" lines */
  802. remaining_headers = MAX_HTTP_REQUEST_HEADERS;
  803. for (;;) {
  804. char *name;
  805. char *value;
  806. if (!fgets(header_line, sizeof(header_line), ser->f) || feof(ser->f)) {
  807. ast_http_error(ser, 400, "Bad Request", "Timeout");
  808. goto done;
  809. }
  810. /* Trim trailing characters */
  811. ast_trim_blanks(header_line);
  812. if (ast_strlen_zero(header_line)) {
  813. /* A blank line ends the request header section. */
  814. break;
  815. }
  816. value = header_line;
  817. name = strsep(&value, ":");
  818. if (!value) {
  819. continue;
  820. }
  821. value = ast_skip_blanks(value);
  822. if (ast_strlen_zero(value) || ast_strlen_zero(name)) {
  823. continue;
  824. }
  825. ast_trim_blanks(name);
  826. if (!remaining_headers--) {
  827. /* Too many headers. */
  828. ast_http_error(ser, 413, "Request Entity Too Large", "Too many headers");
  829. goto done;
  830. }
  831. if (!headers) {
  832. headers = ast_variable_new(name, value, __FILE__);
  833. tail = headers;
  834. } else {
  835. tail->next = ast_variable_new(name, value, __FILE__);
  836. tail = tail->next;
  837. }
  838. if (!tail) {
  839. /*
  840. * Variable allocation failure.
  841. * Try to make some room.
  842. */
  843. ast_variables_destroy(headers);
  844. headers = NULL;
  845. ast_http_error(ser, 500, "Server Error", "Out of memory");
  846. goto done;
  847. }
  848. }
  849. handle_uri(ser, uri, http_method, headers);
  850. done:
  851. ast_atomic_fetchadd_int(&session_count, -1);
  852. /* clean up all the header information */
  853. ast_variables_destroy(headers);
  854. if (ser->f) {
  855. ast_tcptls_close_session_file(ser);
  856. }
  857. ao2_ref(ser, -1);
  858. ser = NULL;
  859. return NULL;
  860. }
  861. /*!
  862. * \brief Add a new URI redirect
  863. * The entries in the redirect list are sorted by length, just like the list
  864. * of URI handlers.
  865. */
  866. static void add_redirect(const char *value)
  867. {
  868. char *target, *dest;
  869. struct http_uri_redirect *redirect, *cur;
  870. unsigned int target_len;
  871. unsigned int total_len;
  872. dest = ast_strdupa(value);
  873. dest = ast_skip_blanks(dest);
  874. target = strsep(&dest, " ");
  875. target = ast_skip_blanks(target);
  876. target = strsep(&target, " "); /* trim trailing whitespace */
  877. if (!dest) {
  878. ast_log(LOG_WARNING, "Invalid redirect '%s'\n", value);
  879. return;
  880. }
  881. target_len = strlen(target) + 1;
  882. total_len = sizeof(*redirect) + target_len + strlen(dest) + 1;
  883. if (!(redirect = ast_calloc(1, total_len))) {
  884. return;
  885. }
  886. redirect->dest = redirect->target + target_len;
  887. strcpy(redirect->target, target);
  888. strcpy(redirect->dest, dest);
  889. AST_RWLIST_WRLOCK(&uri_redirects);
  890. target_len--; /* So we can compare directly with strlen() */
  891. if (AST_RWLIST_EMPTY(&uri_redirects)
  892. || strlen(AST_RWLIST_FIRST(&uri_redirects)->target) <= target_len ) {
  893. AST_RWLIST_INSERT_HEAD(&uri_redirects, redirect, entry);
  894. AST_RWLIST_UNLOCK(&uri_redirects);
  895. return;
  896. }
  897. AST_RWLIST_TRAVERSE(&uri_redirects, cur, entry) {
  898. if (AST_RWLIST_NEXT(cur, entry)
  899. && strlen(AST_RWLIST_NEXT(cur, entry)->target) <= target_len ) {
  900. AST_RWLIST_INSERT_AFTER(&uri_redirects, cur, redirect, entry);
  901. AST_RWLIST_UNLOCK(&uri_redirects);
  902. return;
  903. }
  904. }
  905. AST_RWLIST_INSERT_TAIL(&uri_redirects, redirect, entry);
  906. AST_RWLIST_UNLOCK(&uri_redirects);
  907. }
  908. static int __ast_http_load(int reload)
  909. {
  910. struct ast_config *cfg;
  911. struct ast_variable *v;
  912. int enabled=0;
  913. int newenablestatic=0;
  914. char newprefix[MAX_PREFIX] = "";
  915. struct http_uri_redirect *redirect;
  916. struct ast_flags config_flags = { reload ? CONFIG_FLAG_FILEUNCHANGED : 0 };
  917. uint32_t bindport = DEFAULT_PORT;
  918. RAII_VAR(struct ast_sockaddr *, addrs, NULL, ast_free);
  919. int num_addrs = 0;
  920. int http_tls_was_enabled = 0;
  921. cfg = ast_config_load2("http.conf", "http", config_flags);
  922. if (cfg == CONFIG_STATUS_FILEMISSING || cfg == CONFIG_STATUS_FILEUNCHANGED || cfg == CONFIG_STATUS_FILEINVALID) {
  923. return 0;
  924. }
  925. http_tls_was_enabled = (reload && http_tls_cfg.enabled);
  926. http_tls_cfg.enabled = 0;
  927. if (http_tls_cfg.certfile) {
  928. ast_free(http_tls_cfg.certfile);
  929. }
  930. http_tls_cfg.certfile = ast_strdup(AST_CERTFILE);
  931. if (http_tls_cfg.pvtfile) {
  932. ast_free(http_tls_cfg.pvtfile);
  933. }
  934. http_tls_cfg.pvtfile = ast_strdup("");
  935. if (http_tls_cfg.cipher) {
  936. ast_free(http_tls_cfg.cipher);
  937. }
  938. http_tls_cfg.cipher = ast_strdup("");
  939. AST_RWLIST_WRLOCK(&uri_redirects);
  940. while ((redirect = AST_RWLIST_REMOVE_HEAD(&uri_redirects, entry))) {
  941. ast_free(redirect);
  942. }
  943. AST_RWLIST_UNLOCK(&uri_redirects);
  944. ast_sockaddr_setnull(&https_desc.local_address);
  945. session_limit = DEFAULT_SESSION_LIMIT;
  946. session_inactivity = DEFAULT_SESSION_INACTIVITY;
  947. if (cfg) {
  948. v = ast_variable_browse(cfg, "general");
  949. for (; v; v = v->next) {
  950. /* read tls config options while preventing unsupported options from being set */
  951. if (strcasecmp(v->name, "tlscafile")
  952. && strcasecmp(v->name, "tlscapath")
  953. && strcasecmp(v->name, "tlscadir")
  954. && strcasecmp(v->name, "tlsverifyclient")
  955. && strcasecmp(v->name, "tlsdontverifyserver")
  956. && strcasecmp(v->name, "tlsclientmethod")
  957. && strcasecmp(v->name, "sslclientmethod")
  958. && strcasecmp(v->name, "tlscipher")
  959. && strcasecmp(v->name, "sslcipher")
  960. && !ast_tls_read_conf(&http_tls_cfg, &https_desc, v->name, v->value)) {
  961. continue;
  962. }
  963. if (!strcasecmp(v->name, "enabled")) {
  964. enabled = ast_true(v->value);
  965. } else if (!strcasecmp(v->name, "enablestatic")) {
  966. newenablestatic = ast_true(v->value);
  967. } else if (!strcasecmp(v->name, "bindport")) {
  968. if (ast_parse_arg(v->value, PARSE_UINT32 | PARSE_IN_RANGE | PARSE_DEFAULT, &bindport, DEFAULT_PORT, 0, 65535)) {
  969. ast_log(LOG_WARNING, "Invalid port %s specified. Using default port %"PRId32, v->value, DEFAULT_PORT);
  970. }
  971. } else if (!strcasecmp(v->name, "bindaddr")) {
  972. if (!(num_addrs = ast_sockaddr_resolve(&addrs, v->value, 0, AST_AF_UNSPEC))) {
  973. ast_log(LOG_WARNING, "Invalid bind address %s\n", v->value);
  974. }
  975. } else if (!strcasecmp(v->name, "prefix")) {
  976. if (!ast_strlen_zero(v->value)) {
  977. newprefix[0] = '/';
  978. ast_copy_string(newprefix + 1, v->value, sizeof(newprefix) - 1);
  979. } else {
  980. newprefix[0] = '\0';
  981. }
  982. } else if (!strcasecmp(v->name, "redirect")) {
  983. add_redirect(v->value);
  984. } else if (!strcasecmp(v->name, "sessionlimit")) {
  985. if (ast_parse_arg(v->value, PARSE_INT32|PARSE_DEFAULT|PARSE_IN_RANGE,
  986. &session_limit, DEFAULT_SESSION_LIMIT, 1, INT_MAX)) {
  987. ast_log(LOG_WARNING, "Invalid %s '%s' at line %d of http.conf\n",
  988. v->name, v->value, v->lineno);
  989. }
  990. } else if (!strcasecmp(v->name, "session_inactivity")) {
  991. if (ast_parse_arg(v->value, PARSE_INT32 |PARSE_DEFAULT | PARSE_IN_RANGE,
  992. &session_inactivity, DEFAULT_SESSION_INACTIVITY, 1, INT_MAX)) {
  993. ast_log(LOG_WARNING, "Invalid %s '%s' at line %d of http.conf\n",
  994. v->name, v->value, v->lineno);
  995. }
  996. } else {
  997. ast_log(LOG_WARNING, "Ignoring unknown option '%s' in http.conf\n", v->name);
  998. }
  999. }
  1000. ast_config_destroy(cfg);
  1001. }
  1002. if (strcmp(prefix, newprefix)) {
  1003. ast_copy_string(prefix, newprefix, sizeof(prefix));
  1004. }
  1005. enablestatic = newenablestatic;
  1006. if (num_addrs && enabled) {
  1007. int i;
  1008. for (i = 0; i < num_addrs; ++i) {
  1009. ast_sockaddr_copy(&http_desc.local_address, &addrs[i]);
  1010. if (!ast_sockaddr_port(&http_desc.local_address)) {
  1011. ast_sockaddr_set_port(&http_desc.local_address, bindport);
  1012. }
  1013. ast_tcptls_server_start(&http_desc);
  1014. if (http_desc.accept_fd == -1) {
  1015. ast_log(LOG_WARNING, "Failed to start HTTP server for address %s\n", ast_sockaddr_stringify(&addrs[i]));
  1016. ast_sockaddr_setnull(&http_desc.local_address);
  1017. } else {
  1018. ast_verb(1, "Bound HTTP server to address %s\n", ast_sockaddr_stringify(&addrs[i]));
  1019. break;
  1020. }
  1021. }
  1022. /* When no specific TLS bindaddr is specified, we just use
  1023. * the non-TLS bindaddress here.
  1024. */
  1025. if (ast_sockaddr_isnull(&https_desc.local_address) && http_desc.accept_fd != -1) {
  1026. ast_sockaddr_copy(&https_desc.local_address, &https_desc.local_address);
  1027. /* Of course, we can't use the same port though.
  1028. * Since no bind address was specified, we just use the
  1029. * default TLS port
  1030. */
  1031. ast_sockaddr_set_port(&https_desc.local_address, DEFAULT_TLS_PORT);
  1032. }
  1033. }
  1034. if (http_tls_was_enabled && !http_tls_cfg.enabled) {
  1035. ast_tcptls_server_stop(&https_desc);
  1036. } else if (http_tls_cfg.enabled && !ast_sockaddr_isnull(&https_desc.local_address)) {
  1037. /* We can get here either because a TLS-specific address was specified
  1038. * or because we copied the non-TLS address here. In the case where
  1039. * we read an explicit address from the config, there may have been
  1040. * no port specified, so we'll just use the default TLS port.
  1041. */
  1042. if (!ast_sockaddr_port(&https_desc.local_address)) {
  1043. ast_sockaddr_set_port(&https_desc.local_address, DEFAULT_TLS_PORT);
  1044. }
  1045. if (ast_ssl_setup(https_desc.tls_cfg)) {
  1046. ast_tcptls_server_start(&https_desc);
  1047. }
  1048. }
  1049. return 0;
  1050. }
  1051. static char *handle_show_http(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
  1052. {
  1053. struct ast_http_uri *urih;
  1054. struct http_uri_redirect *redirect;
  1055. switch (cmd) {
  1056. case CLI_INIT:
  1057. e->command = "http show status";
  1058. e->usage =
  1059. "Usage: http show status\n"
  1060. " Lists status of internal HTTP engine\n";
  1061. return NULL;
  1062. case CLI_GENERATE:
  1063. return NULL;
  1064. }
  1065. if (a->argc != 3) {
  1066. return CLI_SHOWUSAGE;
  1067. }
  1068. ast_cli(a->fd, "HTTP Server Status:\n");
  1069. ast_cli(a->fd, "Prefix: %s\n", prefix);
  1070. if (ast_sockaddr_isnull(&http_desc.old_address)) {
  1071. ast_cli(a->fd, "Server Disabled\n\n");
  1072. } else {
  1073. ast_cli(a->fd, "Server Enabled and Bound to %s\n\n",
  1074. ast_sockaddr_stringify(&http_desc.old_address));
  1075. if (http_tls_cfg.enabled) {
  1076. ast_cli(a->fd, "HTTPS Server Enabled and Bound to %s\n\n",
  1077. ast_sockaddr_stringify(&https_desc.old_address));
  1078. }
  1079. }
  1080. ast_cli(a->fd, "Enabled URI's:\n");
  1081. AST_RWLIST_RDLOCK(&uris);
  1082. if (AST_RWLIST_EMPTY(&uris)) {
  1083. ast_cli(a->fd, "None.\n");
  1084. } else {
  1085. AST_RWLIST_TRAVERSE(&uris, urih, entry)
  1086. ast_cli(a->fd, "%s/%s%s => %s\n", prefix, urih->uri, (urih->has_subtree ? "/..." : "" ), urih->description);
  1087. }
  1088. AST_RWLIST_UNLOCK(&uris);
  1089. ast_cli(a->fd, "\nEnabled Redirects:\n");
  1090. AST_RWLIST_RDLOCK(&uri_redirects);
  1091. AST_RWLIST_TRAVERSE(&uri_redirects, redirect, entry)
  1092. ast_cli(a->fd, " %s => %s\n", redirect->target, redirect->dest);
  1093. if (AST_RWLIST_EMPTY(&uri_redirects)) {
  1094. ast_cli(a->fd, " None.\n");
  1095. }
  1096. AST_RWLIST_UNLOCK(&uri_redirects);
  1097. return CLI_SUCCESS;
  1098. }
  1099. int ast_http_reload(void)
  1100. {
  1101. return __ast_http_load(1);
  1102. }
  1103. static struct ast_cli_entry cli_http[] = {
  1104. AST_CLI_DEFINE(handle_show_http, "Display HTTP server status"),
  1105. };
  1106. static void http_shutdown(void)
  1107. {
  1108. struct http_uri_redirect *redirect;
  1109. ast_cli_unregister_multiple(cli_http, ARRAY_LEN(cli_http));
  1110. ast_tcptls_server_stop(&http_desc);
  1111. if (http_tls_cfg.enabled) {
  1112. ast_tcptls_server_stop(&https_desc);
  1113. }
  1114. ast_free(http_tls_cfg.certfile);
  1115. ast_free(http_tls_cfg.pvtfile);
  1116. ast_free(http_tls_cfg.cipher);
  1117. ast_http_uri_unlink(&statusuri);
  1118. ast_http_uri_unlink(&staticuri);
  1119. AST_RWLIST_WRLOCK(&uri_redirects);
  1120. while ((redirect = AST_RWLIST_REMOVE_HEAD(&uri_redirects, entry))) {
  1121. ast_free(redirect);
  1122. }
  1123. AST_RWLIST_UNLOCK(&uri_redirects);
  1124. }
  1125. int ast_http_init(void)
  1126. {
  1127. ast_http_uri_link(&statusuri);
  1128. ast_http_uri_link(&staticuri);
  1129. ast_cli_register_multiple(cli_http, ARRAY_LEN(cli_http));
  1130. ast_register_cleanup(http_shutdown);
  1131. return __ast_http_load(0);
  1132. }