http_server_handlers.c 37 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148
  1. /*
  2. Copyright (c) 2017-2021 Sebastien L
  3. */
  4. #include "http_server_handlers.h"
  5. #include "esp_http_server.h"
  6. #include "cmd_system.h"
  7. #include <inttypes.h>
  8. #include "squeezelite-ota.h"
  9. #include "nvs_utilities.h"
  10. #include <stdio.h>
  11. #include <stdlib.h>
  12. #include "cJSON.h"
  13. #include "esp_system.h"
  14. #include "freertos/FreeRTOS.h"
  15. #include "freertos/task.h"
  16. #include "platform_config.h"
  17. #include "sys/param.h"
  18. #include "esp_vfs.h"
  19. #include "messaging.h"
  20. #include "platform_esp32.h"
  21. #include "trace.h"
  22. #include "esp_console.h"
  23. #include "argtable3/argtable3.h"
  24. #include "platform_console.h"
  25. #include "accessors.h"
  26. #include "webapp/webpack.h"
  27. #include "network_wifi.h"
  28. #include "network_status.h"
  29. #include "globdefs.h"
  30. #define HTTP_STACK_SIZE (5*1024)
  31. const char str_na[]="N/A";
  32. #define STR_OR_NA(s) s?s:str_na
  33. /* @brief tag used for ESP serial console messages */
  34. static const char TAG[] = "httpd_handlers";
  35. /* @brief task handle for the http server */
  36. SemaphoreHandle_t http_server_config_mutex = NULL;
  37. extern RingbufHandle_t messaging;
  38. #define AUTH_TOKEN_SIZE 50
  39. typedef struct session_context {
  40. char * auth_token;
  41. bool authenticated;
  42. char * sess_ip_address;
  43. u16_t port;
  44. } session_context_t;
  45. union sockaddr_aligned {
  46. struct sockaddr sa;
  47. struct sockaddr_storage st;
  48. struct sockaddr_in sin;
  49. struct sockaddr_in6 sin6;
  50. } aligned_sockaddr_t;
  51. esp_err_t post_handler_buff_receive(httpd_req_t * req);
  52. static const char redirect_payload1[]="<html><head><title>Redirecting to Captive Portal</title><meta http-equiv='refresh' content='0; url=";
  53. static const char redirect_payload2[]="'></head><body><p>Please wait, refreshing. If page does not refresh, click <a href='";
  54. static const char redirect_payload3[]="'>here</a> to login.</p></body></html>";
  55. /**
  56. * @brief embedded binary data.
  57. * @see file "component.mk"
  58. * @see https://docs.espressif.com/projects/esp-idf/en/latest/api-guides/build-system.html#embedding-binary-data
  59. */
  60. esp_err_t redirect_processor(httpd_req_t *req, httpd_err_code_t error);
  61. char * alloc_get_http_header(httpd_req_t * req, const char * key){
  62. char* buf = NULL;
  63. size_t buf_len;
  64. /* Get header value string length and allocate memory for length + 1,
  65. * extra byte for null termination */
  66. buf_len = httpd_req_get_hdr_value_len(req, key) + 1;
  67. if (buf_len > 1) {
  68. buf = malloc_init_external(buf_len);
  69. /* Copy null terminated value string into buffer */
  70. if (httpd_req_get_hdr_value_str(req, "Host", buf, buf_len) == ESP_OK) {
  71. ESP_LOGD_LOC(TAG, "Found header => %s: %s",key, buf);
  72. }
  73. }
  74. return buf;
  75. }
  76. char * http_alloc_get_socket_address(httpd_req_t *req, u8_t local, in_port_t * portl) {
  77. socklen_t len;
  78. union sockaddr_aligned addr;
  79. len = sizeof(addr);
  80. ip_addr_t * ip_addr=NULL;
  81. char * ipstr = malloc_init_external(INET6_ADDRSTRLEN);
  82. typedef int (*getaddrname_fn_t)(int s, struct sockaddr *name, socklen_t *namelen);
  83. getaddrname_fn_t get_addr = NULL;
  84. int s = httpd_req_to_sockfd(req);
  85. if(s == -1) {
  86. free(ipstr);
  87. return strdup_psram("httpd_req_to_sockfd error");
  88. }
  89. ESP_LOGV_LOC(TAG,"httpd socket descriptor: %u", s);
  90. get_addr = local?&lwip_getsockname:&lwip_getpeername;
  91. if(get_addr(s, (struct sockaddr *)&addr, &len) <0){
  92. ESP_LOGE_LOC(TAG,"Failed to retrieve socket address");
  93. sprintf(ipstr,"N/A (0.0.0.%u)",local);
  94. }
  95. else {
  96. if (addr.sin.sin_family!= AF_INET) {
  97. ip_addr = (ip_addr_t *)&(addr.sin6.sin6_addr);
  98. inet_ntop(addr.sa.sa_family, ip_addr, ipstr, INET6_ADDRSTRLEN);
  99. ESP_LOGV_LOC(TAG,"Processing an IPV6 address : %s", ipstr);
  100. *portl = addr.sin6.sin6_port;
  101. unmap_ipv4_mapped_ipv6(ip_2_ip4(ip_addr), ip_2_ip6(ip_addr));
  102. }
  103. else {
  104. ip_addr = (ip_addr_t *)&(addr.sin.sin_addr);
  105. inet_ntop(addr.sa.sa_family, ip_addr, ipstr, INET6_ADDRSTRLEN);
  106. ESP_LOGV_LOC(TAG,"Processing an IPV6 address : %s", ipstr);
  107. *portl = addr.sin.sin_port;
  108. }
  109. inet_ntop(AF_INET, ip_addr, ipstr, INET6_ADDRSTRLEN);
  110. ESP_LOGV_LOC(TAG,"Retrieved ip address:port = %s:%u",ipstr, *portl);
  111. }
  112. return ipstr;
  113. }
  114. bool is_captive_portal_host_name(httpd_req_t *req){
  115. const char * host_name=NULL;
  116. const char * ap_host_name=NULL;
  117. char * ap_ip_address=NULL;
  118. bool request_contains_hostname = false;
  119. esp_err_t hn_err =ESP_OK, err=ESP_OK;
  120. ESP_LOGD_LOC(TAG, "Getting adapter host name");
  121. if((err = tcpip_adapter_get_hostname(TCPIP_ADAPTER_IF_STA, &host_name )) !=ESP_OK) {
  122. ESP_LOGE_LOC(TAG, "Unable to get host name. Error: %s",esp_err_to_name(err));
  123. }
  124. else {
  125. ESP_LOGD_LOC(TAG, "Host name is %s",host_name);
  126. }
  127. ESP_LOGD_LOC(TAG, "Getting host name from request");
  128. char *req_host = alloc_get_http_header(req, "Host");
  129. if(tcpip_adapter_is_netif_up(TCPIP_ADAPTER_IF_AP)){
  130. ESP_LOGD_LOC(TAG, "Soft AP is enabled. getting ip info");
  131. // Access point is up and running. Get the current IP address
  132. tcpip_adapter_ip_info_t ip_info;
  133. esp_err_t ap_ip_err = tcpip_adapter_get_ip_info(TCPIP_ADAPTER_IF_AP, &ip_info);
  134. if(ap_ip_err != ESP_OK){
  135. ESP_LOGE_LOC(TAG, "Unable to get local AP ip address. Error: %s",esp_err_to_name(ap_ip_err));
  136. }
  137. else {
  138. ESP_LOGD_LOC(TAG, "getting host name for TCPIP_ADAPTER_IF_AP");
  139. if((hn_err = tcpip_adapter_get_hostname(TCPIP_ADAPTER_IF_AP, &ap_host_name )) !=ESP_OK) {
  140. ESP_LOGE_LOC(TAG, "Unable to get host name. Error: %s",esp_err_to_name(hn_err));
  141. err=err==ESP_OK?hn_err:err;
  142. }
  143. else {
  144. ESP_LOGD_LOC(TAG, "Soft AP Host name is %s",ap_host_name);
  145. }
  146. ap_ip_address = malloc_init_external(IP4ADDR_STRLEN_MAX);
  147. memset(ap_ip_address, 0x00, IP4ADDR_STRLEN_MAX);
  148. if(ap_ip_address){
  149. ESP_LOGD_LOC(TAG, "Converting soft ip address to string");
  150. ip4addr_ntoa_r(&ip_info.ip, ap_ip_address, IP4ADDR_STRLEN_MAX);
  151. ESP_LOGD_LOC(TAG,"TCPIP_ADAPTER_IF_AP is up and has ip address %s ", ap_ip_address);
  152. }
  153. }
  154. }
  155. if((request_contains_hostname = (host_name!=NULL) && (req_host!=NULL) && strcasestr(req_host,host_name)) == true){
  156. ESP_LOGD_LOC(TAG,"http request host = system host name %s", req_host);
  157. }
  158. else if((request_contains_hostname = (ap_host_name!=NULL) && (req_host!=NULL) && strcasestr(req_host,ap_host_name)) == true){
  159. ESP_LOGD_LOC(TAG,"http request host = AP system host name %s", req_host);
  160. }
  161. FREE_AND_NULL(ap_ip_address);
  162. FREE_AND_NULL(req_host);
  163. return request_contains_hostname;
  164. }
  165. /* Custom function to free context */
  166. void free_ctx_func(void *ctx)
  167. {
  168. session_context_t * context = (session_context_t *)ctx;
  169. if(context){
  170. ESP_LOGD(TAG, "Freeing up socket context");
  171. FREE_AND_NULL(context->auth_token);
  172. FREE_AND_NULL(context->sess_ip_address);
  173. free(context);
  174. }
  175. }
  176. session_context_t* get_session_context(httpd_req_t *req){
  177. bool newConnection=false;
  178. if (! req->sess_ctx) {
  179. ESP_LOGD(TAG,"New connection context. Allocating session buffer");
  180. req->sess_ctx = malloc_init_external(sizeof(session_context_t));
  181. req->free_ctx = free_ctx_func;
  182. newConnection = true;
  183. // get the remote IP address only once per session
  184. }
  185. session_context_t *ctx_data = (session_context_t*)req->sess_ctx;
  186. FREE_AND_NULL(ctx_data->sess_ip_address);
  187. ctx_data->sess_ip_address = http_alloc_get_socket_address(req, 0, &ctx_data->port);
  188. if(newConnection){
  189. ESP_LOGI(TAG, "serving %s to peer %s port %u", req->uri, ctx_data->sess_ip_address , ctx_data->port);
  190. }
  191. return (session_context_t *)req->sess_ctx;
  192. }
  193. bool is_user_authenticated(httpd_req_t *req){
  194. session_context_t *ctx_data = get_session_context(req);
  195. if(ctx_data->authenticated){
  196. ESP_LOGD_LOC(TAG,"User is authenticated.");
  197. return true;
  198. }
  199. ESP_LOGD(TAG, "Heap internal:%zu (min:%zu) external:%zu (min:%zu) dma:%zu (min:%zu)",
  200. heap_caps_get_free_size(MALLOC_CAP_INTERNAL),
  201. heap_caps_get_minimum_free_size(MALLOC_CAP_INTERNAL),
  202. heap_caps_get_free_size(MALLOC_CAP_SPIRAM),
  203. heap_caps_get_minimum_free_size(MALLOC_CAP_SPIRAM),
  204. heap_caps_get_free_size(MALLOC_CAP_DMA),
  205. heap_caps_get_minimum_free_size(MALLOC_CAP_DMA));
  206. // todo: ask for user to authenticate
  207. return false;
  208. }
  209. /* Copies the full path into destination buffer and returns
  210. * pointer to requested file name */
  211. static const char* get_path_from_uri(char *dest, const char *uri, size_t destsize)
  212. {
  213. size_t pathlen = strlen(uri);
  214. memset(dest,0x0,destsize);
  215. const char *quest = strchr(uri, '?');
  216. if (quest) {
  217. pathlen = MIN(pathlen, quest - uri);
  218. }
  219. const char *hash = strchr(uri, '#');
  220. if (hash) {
  221. pathlen = MIN(pathlen, hash - uri);
  222. }
  223. if ( pathlen + 1 > destsize) {
  224. /* Full path string won't fit into destination buffer */
  225. return NULL;
  226. }
  227. strlcpy(dest , uri, pathlen + 1);
  228. // strip trailing blanks
  229. char * sr = dest+pathlen;
  230. while(*sr== ' ') *sr-- = '\0';
  231. char * last_fs = strchr(dest,'/');
  232. if(!last_fs) ESP_LOGD_LOC(TAG,"no / found in %s", dest);
  233. char * p=last_fs;
  234. while(p && *(++p)!='\0'){
  235. if(*p == '/') {
  236. last_fs=p;
  237. }
  238. }
  239. /* Return pointer to path, skipping the base */
  240. return last_fs? ++last_fs: dest;
  241. }
  242. #define IS_FILE_EXT(filename, ext) \
  243. (strcasecmp(&filename[strlen(filename) - sizeof(ext) + 1], ext) == 0)
  244. /* Set HTTP response content type according to file extension */
  245. static esp_err_t set_content_type_from_file(httpd_req_t *req, const char *filename)
  246. {
  247. if(strlen(filename) ==0){
  248. // for root page, etc.
  249. return httpd_resp_set_type(req, HTTPD_TYPE_TEXT);
  250. } else if (IS_FILE_EXT(filename, ".pdf")) {
  251. return httpd_resp_set_type(req, "application/pdf");
  252. } else if (IS_FILE_EXT(filename, ".html")) {
  253. return httpd_resp_set_type(req, HTTPD_TYPE_TEXT);
  254. } else if (IS_FILE_EXT(filename, ".jpeg")) {
  255. return httpd_resp_set_type(req, "image/jpeg");
  256. } else if (IS_FILE_EXT(filename, ".png")) {
  257. return httpd_resp_set_type(req, "image/png");
  258. } else if (IS_FILE_EXT(filename, ".ico")) {
  259. return httpd_resp_set_type(req, "image/x-icon");
  260. } else if (IS_FILE_EXT(filename, ".css")) {
  261. return httpd_resp_set_type(req, "text/css");
  262. } else if (IS_FILE_EXT(filename, ".js")) {
  263. return httpd_resp_set_type(req, "text/javascript");
  264. } else if (IS_FILE_EXT(filename, ".json")) {
  265. return httpd_resp_set_type(req, HTTPD_TYPE_JSON);
  266. }
  267. /* This is a limited set only */
  268. /* For any other type always set as plain text */
  269. return httpd_resp_set_type(req, "text/plain");
  270. }
  271. static esp_err_t set_content_type_from_req(httpd_req_t *req)
  272. {
  273. char filepath[FILE_PATH_MAX];
  274. const char *filename = get_path_from_uri(filepath, req->uri, sizeof(filepath));
  275. if (!filename) {
  276. ESP_LOGE_LOC(TAG, "Filename is too long");
  277. /* Respond with 500 Internal Server Error */
  278. httpd_resp_send_err(req, HTTPD_500_INTERNAL_SERVER_ERROR, "Filename too long");
  279. return ESP_FAIL;
  280. }
  281. /* If name has trailing '/', respond with directory contents */
  282. if (filename[strlen(filename) - 1] == '/' && strlen(filename)>1) {
  283. httpd_resp_send_err(req, HTTPD_400_BAD_REQUEST, "Browsing files forbidden.");
  284. return ESP_FAIL;
  285. }
  286. set_content_type_from_file(req, filename);
  287. return ESP_OK;
  288. }
  289. int resource_get_index(const char * fileName){
  290. for(int i=0;resource_lookups[i][0]!='\0';i++){
  291. if(strstr(resource_lookups[i], fileName)){
  292. return i;
  293. }
  294. }
  295. return -1;
  296. }
  297. esp_err_t root_get_handler(httpd_req_t *req){
  298. esp_err_t err = ESP_OK;
  299. ESP_LOGD_LOC(TAG, "serving [%s]", req->uri);
  300. httpd_resp_set_hdr(req, "Access-Control-Allow-Origin", "*");
  301. httpd_resp_set_hdr(req, "Accept-Encoding", "identity");
  302. if(!is_user_authenticated(req)){
  303. // todo: send password entry page and return
  304. }
  305. int idx=-1;
  306. if((idx=resource_get_index("index.html"))>=0){
  307. const size_t file_size = (resource_map_end[idx] - resource_map_start[idx]);
  308. httpd_resp_set_hdr(req, "Content-Encoding", "gzip");
  309. err = set_content_type_from_req(req);
  310. if(err == ESP_OK){
  311. httpd_resp_send(req, (const char *)resource_map_start[idx], file_size);
  312. }
  313. }
  314. else{
  315. httpd_resp_send_err(req, HTTPD_500_INTERNAL_SERVER_ERROR, "index.html not found");
  316. return ESP_FAIL;
  317. }
  318. ESP_LOGD_LOC(TAG, "done serving [%s]", req->uri);
  319. return err;
  320. }
  321. esp_err_t resource_filehandler(httpd_req_t *req){
  322. char filepath[FILE_PATH_MAX];
  323. ESP_LOGD_LOC(TAG, "serving [%s]", req->uri);
  324. const char *filename = get_path_from_uri(filepath, req->uri, sizeof(filepath));
  325. if (!filename) {
  326. ESP_LOGE_LOC(TAG, "Filename is too long");
  327. /* Respond with 500 Internal Server Error */
  328. httpd_resp_send_err(req, HTTPD_500_INTERNAL_SERVER_ERROR, "Filename too long");
  329. return ESP_FAIL;
  330. }
  331. /* If name has trailing '/', respond with directory contents */
  332. if (filename[strlen(filename) - 1] == '/') {
  333. httpd_resp_send_err(req, HTTPD_400_BAD_REQUEST, "Browsing files forbidden.");
  334. return ESP_FAIL;
  335. }
  336. int idx=-1;
  337. if((idx=resource_get_index(filename))>=0){
  338. set_content_type_from_file(req, filename);
  339. if(strstr(resource_lookups[idx], ".gz")) {
  340. httpd_resp_set_hdr(req, "Content-Encoding", "gzip");
  341. }
  342. const size_t file_size = (resource_map_end[idx] - resource_map_start[idx]);
  343. httpd_resp_send(req, (const char *)resource_map_start[idx], file_size);
  344. }
  345. else {
  346. ESP_LOGE_LOC(TAG, "Unknown resource [%s] from path [%s] ", filename,filepath);
  347. /* Respond with 404 Not Found */
  348. httpd_resp_send_err(req, HTTPD_404_NOT_FOUND, "File does not exist");
  349. return ESP_FAIL;
  350. }
  351. ESP_LOGD_LOC(TAG, "Resource sending complete");
  352. return ESP_OK;
  353. }
  354. esp_err_t ap_scan_handler(httpd_req_t *req){
  355. const char empty[] = "{}";
  356. ESP_LOGD_LOC(TAG, "serving [%s]", req->uri);
  357. if(!is_user_authenticated(req)){
  358. // todo: redirect to login page
  359. // return ESP_OK;
  360. }
  361. network_async_scan();
  362. esp_err_t err = set_content_type_from_req(req);
  363. if(err == ESP_OK){
  364. httpd_resp_send(req, (const char *)empty, HTTPD_RESP_USE_STRLEN);
  365. }
  366. return err;
  367. }
  368. esp_err_t console_cmd_get_handler(httpd_req_t *req){
  369. ESP_LOGD_LOC(TAG, "serving [%s]", req->uri);
  370. if(!is_user_authenticated(req)){
  371. // todo: redirect to login page
  372. // return ESP_OK;
  373. }
  374. /* if we can get the mutex, write the last version of the AP list */
  375. esp_err_t err = set_content_type_from_req(req);
  376. cJSON * cmdlist = get_cmd_list();
  377. char * json_buffer = cJSON_Print(cmdlist);
  378. if(json_buffer){
  379. httpd_resp_send(req, (const char *)json_buffer, HTTPD_RESP_USE_STRLEN);
  380. free(json_buffer);
  381. }
  382. else{
  383. ESP_LOGD_LOC(TAG, "Error retrieving command json string. ");
  384. httpd_resp_send_err(req, HTTPD_500_INTERNAL_SERVER_ERROR, "Unable to format command");
  385. }
  386. cJSON_Delete(cmdlist);
  387. ESP_LOGD_LOC(TAG, "done serving [%s]", req->uri);
  388. return err;
  389. }
  390. esp_err_t console_cmd_post_handler(httpd_req_t *req){
  391. char success[]="{\"Result\" : \"Success\" }";
  392. char failed[]="{\"Result\" : \"Failed\" }";
  393. ESP_LOGD_LOC(TAG, "serving [%s]", req->uri);
  394. //bool bOTA=false;
  395. //char * otaURL=NULL;
  396. esp_err_t err = post_handler_buff_receive(req);
  397. if(err!=ESP_OK){
  398. return err;
  399. }
  400. if(!is_user_authenticated(req)){
  401. // todo: redirect to login page
  402. // return ESP_OK;
  403. }
  404. err = set_content_type_from_req(req);
  405. if(err != ESP_OK){
  406. return err;
  407. }
  408. char *command= ((rest_server_context_t *)(req->user_ctx))->scratch;
  409. cJSON *root = cJSON_Parse(command);
  410. if(root == NULL){
  411. ESP_LOGE_LOC(TAG, "Parsing command. Received content was: %s",command);
  412. httpd_resp_send_err(req, HTTPD_400_BAD_REQUEST, "Malformed command json. Unable to parse content.");
  413. return ESP_FAIL;
  414. }
  415. char * root_str = cJSON_Print(root);
  416. if(root_str!=NULL){
  417. ESP_LOGD(TAG, "Processing command item: \n%s", root_str);
  418. free(root_str);
  419. }
  420. cJSON *item=cJSON_GetObjectItemCaseSensitive(root, "command");
  421. if(!item){
  422. ESP_LOGE_LOC(TAG, "Command not found. Received content was: %s",command);
  423. httpd_resp_send_err(req, HTTPD_400_BAD_REQUEST, "Malformed command json. Unable to parse content.");
  424. err = ESP_FAIL;
  425. }
  426. else{
  427. // navigate to the first child of the config structure
  428. if(run_command(cJSON_GetStringValue(item))!=ESP_OK){
  429. httpd_resp_send(req, (const char *)failed, strlen(failed));
  430. }
  431. else {
  432. httpd_resp_send(req, (const char *)success, strlen(success));
  433. }
  434. }
  435. ESP_LOGD_LOC(TAG, "done serving [%s]", req->uri);
  436. return err;
  437. }
  438. esp_err_t ap_get_handler(httpd_req_t *req){
  439. ESP_LOGD_LOC(TAG, "serving [%s]", req->uri);
  440. if(!is_user_authenticated(req)){
  441. // todo: redirect to login page
  442. // return ESP_OK;
  443. }
  444. /* if we can get the mutex, write the last version of the AP list */
  445. esp_err_t err = set_content_type_from_req(req);
  446. if( err == ESP_OK && network_status_lock_json_buffer(( TickType_t ) 200/portTICK_PERIOD_MS)){
  447. char *buff = network_status_alloc_get_ap_list_json();
  448. network_status_unlock_json_buffer();
  449. if(buff!=NULL){
  450. httpd_resp_send(req, (const char *)buff, HTTPD_RESP_USE_STRLEN);
  451. free(buff);
  452. }
  453. else {
  454. ESP_LOGD_LOC(TAG, "Error retrieving ap list json string. ");
  455. httpd_resp_send_err(req, HTTPD_500_INTERNAL_SERVER_ERROR, "Unable to retrieve AP list");
  456. }
  457. }
  458. else {
  459. httpd_resp_send_err(req, HTTPD_500_INTERNAL_SERVER_ERROR, "AP list unavailable");
  460. ESP_LOGE_LOC(TAG, "GET /ap.json failed to obtain mutex");
  461. }
  462. ESP_LOGD_LOC(TAG, "done serving [%s]", req->uri);
  463. return err;
  464. }
  465. esp_err_t config_get_handler(httpd_req_t *req){
  466. ESP_LOGD_LOC(TAG, "serving [%s]", req->uri);
  467. if(!is_user_authenticated(req)){
  468. // todo: redirect to login page
  469. // return ESP_OK;
  470. }
  471. esp_err_t err = set_content_type_from_req(req);
  472. if(err == ESP_OK){
  473. char * json = config_alloc_get_json(false);
  474. if(json==NULL){
  475. ESP_LOGD_LOC(TAG, "Error retrieving config json string. ");
  476. httpd_resp_send_err(req, HTTPD_500_INTERNAL_SERVER_ERROR, "Error retrieving configuration object");
  477. err=ESP_FAIL;
  478. }
  479. else {
  480. ESP_LOGD_LOC(TAG, "config json : %s",json );
  481. cJSON * gplist=get_gpio_list(false);
  482. char * gpliststr=cJSON_PrintUnformatted(gplist);
  483. httpd_resp_sendstr_chunk(req,"{ \"gpio\":");
  484. httpd_resp_sendstr_chunk(req,gpliststr);
  485. httpd_resp_sendstr_chunk(req,", \"config\":");
  486. httpd_resp_sendstr_chunk(req, (const char *)json);
  487. httpd_resp_sendstr_chunk(req,"}");
  488. httpd_resp_sendstr_chunk(req,NULL);
  489. free(gpliststr);
  490. free(json);
  491. }
  492. }
  493. return err;
  494. }
  495. esp_err_t post_handler_buff_receive(httpd_req_t * req){
  496. esp_err_t err = ESP_OK;
  497. int total_len = req->content_len;
  498. int cur_len = 0;
  499. char *buf = ((rest_server_context_t *)(req->user_ctx))->scratch;
  500. int received = 0;
  501. if (total_len >= SCRATCH_BUFSIZE) {
  502. /* Respond with 500 Internal Server Error */
  503. ESP_LOGE_LOC(TAG,"Received content was too long. ");
  504. httpd_resp_send_err(req, HTTPD_500_INTERNAL_SERVER_ERROR , "Content too long");
  505. err = ESP_FAIL;
  506. }
  507. while (err == ESP_OK && cur_len < total_len) {
  508. received = httpd_req_recv(req, buf + cur_len, total_len);
  509. if (received <= 0) {
  510. /* Respond with 500 Internal Server Error */
  511. ESP_LOGE_LOC(TAG,"Not all data was received. ");
  512. httpd_resp_send_err(req, HTTPD_500_INTERNAL_SERVER_ERROR , "Not all data was received");
  513. err = ESP_FAIL;
  514. }
  515. else {
  516. cur_len += received;
  517. }
  518. }
  519. if(err == ESP_OK) {
  520. buf[total_len] = '\0';
  521. }
  522. return err;
  523. }
  524. esp_err_t config_post_handler(httpd_req_t *req){
  525. ESP_LOGD_LOC(TAG, "serving [%s]", req->uri);
  526. bool bOTA=false;
  527. char * otaURL=NULL;
  528. esp_err_t err = post_handler_buff_receive(req);
  529. if(err!=ESP_OK){
  530. return err;
  531. }
  532. if(!is_user_authenticated(req)){
  533. // todo: redirect to login page
  534. // return ESP_OK;
  535. }
  536. err = set_content_type_from_req(req);
  537. if(err != ESP_OK){
  538. return err;
  539. }
  540. char *buf = ((rest_server_context_t *)(req->user_ctx))->scratch;
  541. cJSON *root = cJSON_Parse(buf);
  542. if(root == NULL){
  543. ESP_LOGE_LOC(TAG, "Parsing config json failed. Received content was: %s",buf);
  544. httpd_resp_send_err(req, HTTPD_400_BAD_REQUEST, "Malformed config json. Unable to parse content.");
  545. return ESP_FAIL;
  546. }
  547. char * root_str = cJSON_Print(root);
  548. if(root_str!=NULL){
  549. ESP_LOGD(TAG, "Processing config item: \n%s", root_str);
  550. free(root_str);
  551. }
  552. cJSON *item=cJSON_GetObjectItemCaseSensitive(root, "config");
  553. if(!item){
  554. ESP_LOGE_LOC(TAG, "Parsing config json failed. Received content was: %s",buf);
  555. httpd_resp_send_err(req, HTTPD_400_BAD_REQUEST, "Malformed config json. Unable to parse content.");
  556. err = ESP_FAIL;
  557. }
  558. else{
  559. // navigate to the first child of the config structure
  560. if(item->child) item=item->child;
  561. }
  562. while (item && err == ESP_OK)
  563. {
  564. cJSON *prev_item = item;
  565. item=item->next;
  566. char * entry_str = cJSON_Print(prev_item);
  567. if(entry_str!=NULL){
  568. ESP_LOGD_LOC(TAG, "Processing config item: \n%s", entry_str);
  569. free(entry_str);
  570. }
  571. if(prev_item->string==NULL) {
  572. ESP_LOGD_LOC(TAG,"Config value does not have a name");
  573. httpd_resp_send_err(req, HTTPD_400_BAD_REQUEST, "Malformed config json. Value does not have a name.");
  574. err = ESP_FAIL;
  575. }
  576. if(err == ESP_OK){
  577. ESP_LOGD_LOC(TAG,"Found config value name [%s]", prev_item->string);
  578. nvs_type_t item_type= config_get_item_type(prev_item);
  579. if(item_type!=0){
  580. void * val = config_safe_alloc_get_entry_value(item_type, prev_item);
  581. if(val!=NULL){
  582. if(strcmp(prev_item->string, "fwurl")==0) {
  583. if(item_type!=NVS_TYPE_STR){
  584. ESP_LOGE_LOC(TAG,"Firmware url should be type %d. Found type %d instead.",NVS_TYPE_STR,item_type );
  585. httpd_resp_send_err(req, HTTPD_400_BAD_REQUEST, "Malformed config json. Wrong type for firmware URL.");
  586. err = ESP_FAIL;
  587. }
  588. else {
  589. // we're getting a request to do an OTA from that URL
  590. ESP_LOGW_LOC(TAG, "Found OTA request!");
  591. otaURL=strdup_psram(val);
  592. bOTA=true;
  593. }
  594. }
  595. else {
  596. if(config_set_value(item_type, prev_item->string , val) != ESP_OK){
  597. ESP_LOGE_LOC(TAG,"Unable to store value for [%s]", prev_item->string);
  598. httpd_resp_send_err(req, HTTPD_500_INTERNAL_SERVER_ERROR , "Unable to store config value");
  599. err = ESP_FAIL;
  600. }
  601. else {
  602. ESP_LOGD_LOC(TAG,"Successfully set value for [%s]",prev_item->string);
  603. }
  604. }
  605. free(val);
  606. }
  607. else {
  608. char messageBuffer[101]={};
  609. ESP_LOGE_LOC(TAG,"Value not found for [%s]", prev_item->string);
  610. snprintf(messageBuffer,sizeof(messageBuffer),"Malformed config json. Missing value for entry %s.",prev_item->string);
  611. httpd_resp_send_err(req, HTTPD_400_BAD_REQUEST, messageBuffer);
  612. err = ESP_FAIL;
  613. }
  614. }
  615. else {
  616. ESP_LOGE_LOC(TAG,"Unable to determine the type of config value [%s]", prev_item->string);
  617. httpd_resp_send_err(req, HTTPD_400_BAD_REQUEST, "Malformed config json. Missing value for entry.");
  618. err = ESP_FAIL;
  619. }
  620. }
  621. }
  622. if(err==ESP_OK){
  623. httpd_resp_sendstr(req, "{ \"result\" : \"OK\" }");
  624. messaging_post_message(MESSAGING_INFO,MESSAGING_CLASS_SYSTEM,"Save Success");
  625. }
  626. cJSON_Delete(root);
  627. if(bOTA) {
  628. if(is_recovery_running){
  629. ESP_LOGW_LOC(TAG, "Starting process OTA for url %s",otaURL);
  630. }
  631. else {
  632. ESP_LOGW_LOC(TAG, "Restarting system to process OTA for url %s",otaURL);
  633. }
  634. network_reboot_ota(otaURL);
  635. free(otaURL);
  636. }
  637. return err;
  638. }
  639. esp_err_t connect_post_handler(httpd_req_t *req){
  640. ESP_LOGD_LOC(TAG, "serving [%s]", req->uri);
  641. char success[]="{}";
  642. char * ssid=NULL;
  643. char * password=NULL;
  644. char * host_name=NULL;
  645. esp_err_t err = post_handler_buff_receive(req);
  646. if(err!=ESP_OK){
  647. return err;
  648. }
  649. err = set_content_type_from_req(req);
  650. if(err != ESP_OK){
  651. return err;
  652. }
  653. char *buf = ((rest_server_context_t *)(req->user_ctx))->scratch;
  654. if(!is_user_authenticated(req)){
  655. // todo: redirect to login page
  656. // return ESP_OK;
  657. }
  658. cJSON *root = cJSON_Parse(buf);
  659. if(root==NULL){
  660. httpd_resp_send_err(req, HTTPD_500_INTERNAL_SERVER_ERROR , "JSON parsing error.");
  661. return ESP_FAIL;
  662. }
  663. cJSON * ssid_object = cJSON_GetObjectItem(root, "ssid");
  664. if(ssid_object !=NULL){
  665. ssid = strdup_psram(ssid_object->valuestring);
  666. }
  667. cJSON * password_object = cJSON_GetObjectItem(root, "pwd");
  668. if(password_object !=NULL){
  669. password = strdup_psram(password_object->valuestring);
  670. }
  671. cJSON * host_name_object = cJSON_GetObjectItem(root, "host_name");
  672. if(host_name_object !=NULL){
  673. host_name = strdup_psram(host_name_object->valuestring);
  674. }
  675. cJSON_Delete(root);
  676. if(host_name!=NULL){
  677. if(config_set_value(NVS_TYPE_STR, "host_name", host_name) != ESP_OK){
  678. ESP_LOGW_LOC(TAG, "Unable to save host name configuration");
  679. }
  680. }
  681. if(ssid !=NULL && strlen(ssid) <= MAX_SSID_SIZE && strlen(password) <= MAX_PASSWORD_SIZE ){
  682. network_async_connect(ssid, password);
  683. httpd_resp_send(req, (const char *)success, strlen(success));
  684. }
  685. else {
  686. httpd_resp_send_err(req, HTTPD_400_BAD_REQUEST, "Malformed json. Missing or invalid ssid/password.");
  687. err = ESP_FAIL;
  688. }
  689. FREE_AND_NULL(ssid);
  690. FREE_AND_NULL(password);
  691. FREE_AND_NULL(host_name);
  692. return err;
  693. }
  694. esp_err_t connect_delete_handler(httpd_req_t *req){
  695. char success[]="{}";
  696. ESP_LOGD_LOC(TAG, "serving [%s]", req->uri);
  697. if(!is_user_authenticated(req)){
  698. // todo: redirect to login page
  699. // return ESP_OK;
  700. }
  701. esp_err_t err = set_content_type_from_req(req);
  702. if(err != ESP_OK){
  703. return err;
  704. }
  705. httpd_resp_send(req, (const char *)success, strlen(success));
  706. network_async_delete();
  707. return ESP_OK;
  708. }
  709. esp_err_t reboot_ota_post_handler(httpd_req_t *req){
  710. char success[]="{}";
  711. ESP_LOGD_LOC(TAG, "serving [%s]", req->uri);
  712. if(!is_user_authenticated(req)){
  713. // todo: redirect to login page
  714. // return ESP_OK;
  715. }
  716. esp_err_t err = set_content_type_from_req(req);
  717. if(err != ESP_OK){
  718. return err;
  719. }
  720. httpd_resp_send(req, (const char *)success, strlen(success));
  721. network_async_reboot(OTA);
  722. return ESP_OK;
  723. }
  724. esp_err_t reboot_post_handler(httpd_req_t *req){
  725. ESP_LOGD_LOC(TAG, "serving [%s]", req->uri);
  726. char success[]="{}";
  727. if(!is_user_authenticated(req)){
  728. // todo: redirect to login page
  729. // return ESP_OK;
  730. }
  731. esp_err_t err = set_content_type_from_req(req);
  732. if(err != ESP_OK){
  733. return err;
  734. }
  735. httpd_resp_send(req, (const char *)success, strlen(success));
  736. network_async_reboot(RESTART);
  737. return ESP_OK;
  738. }
  739. esp_err_t recovery_post_handler(httpd_req_t *req){
  740. ESP_LOGD_LOC(TAG, "serving [%s]", req->uri);
  741. char success[]="{}";
  742. if(!is_user_authenticated(req)){
  743. // todo: redirect to login page
  744. // return ESP_OK;
  745. }
  746. esp_err_t err = set_content_type_from_req(req);
  747. if(err != ESP_OK){
  748. return err;
  749. }
  750. httpd_resp_send(req, (const char *)success, strlen(success));
  751. network_async_reboot(RECOVERY);
  752. return ESP_OK;
  753. }
  754. esp_err_t flash_post_handler(httpd_req_t *req){
  755. esp_err_t err =ESP_OK;
  756. if(is_recovery_running){
  757. ESP_LOGD_LOC(TAG, "serving [%s]", req->uri);
  758. char success[]="File uploaded. Flashing started.";
  759. if(!is_user_authenticated(req)){
  760. // todo: redirect to login page
  761. // return ESP_OK;
  762. }
  763. err = httpd_resp_set_type(req, HTTPD_TYPE_TEXT);
  764. if(err != ESP_OK){
  765. return err;
  766. }
  767. char * binary_buffer = malloc_init_external(req->content_len);
  768. if(binary_buffer == NULL){
  769. ESP_LOGE(TAG, "File too large : %d bytes", req->content_len);
  770. /* Respond with 400 Bad Request */
  771. httpd_resp_send_err(req, HTTPD_400_BAD_REQUEST,
  772. "Binary file too large. Unable to allocate memory!");
  773. return ESP_FAIL;
  774. }
  775. ESP_LOGI(TAG, "Receiving ota binary file");
  776. /* Retrieve the pointer to scratch buffer for temporary storage */
  777. char *buf = ((rest_server_context_t *)(req->user_ctx))->scratch;
  778. char *head=binary_buffer;
  779. int received;
  780. /* Content length of the request gives
  781. * the size of the file being uploaded */
  782. int remaining = req->content_len;
  783. while (remaining > 0) {
  784. ESP_LOGI(TAG, "Remaining size : %d", remaining);
  785. /* Receive the file part by part into a buffer */
  786. if ((received = httpd_req_recv(req, buf, MIN(remaining, SCRATCH_BUFSIZE))) <= 0) {
  787. if (received == HTTPD_SOCK_ERR_TIMEOUT) {
  788. /* Retry if timeout occurred */
  789. continue;
  790. }
  791. FREE_RESET(binary_buffer);
  792. ESP_LOGE(TAG, "File reception failed!");
  793. /* Respond with 500 Internal Server Error */
  794. httpd_resp_send_err(req, HTTPD_500_INTERNAL_SERVER_ERROR, "Failed to receive file");
  795. err = ESP_FAIL;
  796. goto bail_out;
  797. }
  798. /* Write buffer content to file on storage */
  799. if (received ) {
  800. memcpy(head,buf,received );
  801. head+=received;
  802. }
  803. /* Keep track of remaining size of
  804. * the file left to be uploaded */
  805. remaining -= received;
  806. }
  807. /* Close file upon upload completion */
  808. ESP_LOGI(TAG, "File reception complete. Invoking OTA process.");
  809. err = start_ota(NULL, binary_buffer, req->content_len);
  810. if(err!=ESP_OK){
  811. httpd_resp_send_err(req, HTTPD_500_INTERNAL_SERVER_ERROR, "OTA processing failed");
  812. goto bail_out;
  813. }
  814. //todo: handle this in ajax. For now, just send the root page
  815. httpd_resp_send(req, (const char *)success, strlen(success));
  816. }
  817. bail_out:
  818. return err;
  819. }
  820. char * get_ap_ip_address(){
  821. static char ap_ip_address[IP4ADDR_STRLEN_MAX]={};
  822. tcpip_adapter_ip_info_t ip_info;
  823. esp_err_t err=ESP_OK;
  824. memset(ap_ip_address, 0x00, sizeof(ap_ip_address));
  825. ESP_LOGD_LOC(TAG, "checking if soft AP is enabled");
  826. if(tcpip_adapter_is_netif_up(TCPIP_ADAPTER_IF_AP)){
  827. ESP_LOGD_LOC(TAG, "Soft AP is enabled. getting ip info");
  828. // Access point is up and running. Get the current IP address
  829. err = tcpip_adapter_get_ip_info(TCPIP_ADAPTER_IF_AP, &ip_info);
  830. if(err != ESP_OK){
  831. ESP_LOGE_LOC(TAG, "Unable to get local AP ip address. Error: %s",esp_err_to_name(err));
  832. }
  833. else {
  834. ESP_LOGV_LOC(TAG, "Converting soft ip address to string");
  835. ip4addr_ntoa_r(&ip_info.ip, ap_ip_address, IP4ADDR_STRLEN_MAX);
  836. ESP_LOGD_LOC(TAG,"TCPIP_ADAPTER_IF_AP is up and has ip address %s ", ap_ip_address);
  837. }
  838. }
  839. else{
  840. ESP_LOGD_LOC(TAG,"AP Is not enabled. Returning blank string");
  841. }
  842. return ap_ip_address;
  843. }
  844. esp_err_t process_redirect(httpd_req_t *req, const char * status){
  845. const char location_prefix[] = "http://";
  846. char * ap_ip_address=get_ap_ip_address();
  847. char * remote_ip=NULL;
  848. in_port_t port=0;
  849. char *redirect_url = NULL;
  850. ESP_LOGD_LOC(TAG, "Getting remote socket address");
  851. remote_ip = http_alloc_get_socket_address(req,0, &port);
  852. size_t buf_size = strlen(redirect_payload1) +strlen(redirect_payload2) + strlen(redirect_payload3) +2*(strlen(location_prefix)+strlen(ap_ip_address))+1;
  853. char * redirect=malloc_init_external(buf_size);
  854. if(strcasestr(status,"302")){
  855. size_t url_buf_size = strlen(location_prefix) + strlen(ap_ip_address)+1;
  856. redirect_url = malloc_init_external(url_buf_size);
  857. memset(redirect_url,0x00,url_buf_size);
  858. snprintf(redirect_url, buf_size,"%s%s/",location_prefix, ap_ip_address);
  859. ESP_LOGW_LOC(TAG, "Redirecting host [%s] to %s (from uri %s)",remote_ip, redirect_url,req->uri);
  860. httpd_resp_set_hdr(req,"Location",redirect_url);
  861. snprintf(redirect, buf_size,"OK");
  862. }
  863. else {
  864. snprintf(redirect, buf_size,"%s%s%s%s%s%s%s",redirect_payload1, location_prefix, ap_ip_address,redirect_payload2, location_prefix, ap_ip_address,redirect_payload3);
  865. ESP_LOGW_LOC(TAG, "Responding to host [%s] (from uri %s) with redirect html page %s",remote_ip, req->uri,redirect);
  866. }
  867. httpd_resp_set_type(req, HTTPD_TYPE_TEXT);
  868. httpd_resp_set_hdr(req,"Cache-Control","no-cache");
  869. httpd_resp_set_status(req, status);
  870. httpd_resp_send(req, redirect, HTTPD_RESP_USE_STRLEN);
  871. FREE_AND_NULL(redirect);
  872. FREE_AND_NULL(redirect_url);
  873. FREE_AND_NULL(remote_ip);
  874. return ESP_OK;
  875. }
  876. esp_err_t redirect_200_ev_handler(httpd_req_t *req){
  877. ESP_LOGD_LOC(TAG,"Processing known redirect url %s",req->uri);
  878. process_redirect(req,"200 OK");
  879. return ESP_OK;
  880. }
  881. esp_err_t redirect_processor(httpd_req_t *req, httpd_err_code_t error){
  882. esp_err_t err=ESP_OK;
  883. const char * host_name=NULL;
  884. const char * ap_host_name=NULL;
  885. char * user_agent=NULL;
  886. char * remote_ip=NULL;
  887. char * sta_ip_address=NULL;
  888. char * ap_ip_address=get_ap_ip_address();
  889. char * socket_local_address=NULL;
  890. bool request_contains_hostname = false;
  891. bool request_contains_ap_ip_address = false;
  892. bool request_is_sta_ip_address = false;
  893. bool connected_to_ap_ip_interface = false;
  894. bool connected_to_sta_ip_interface = false;
  895. bool useragentiscaptivenetwork = false;
  896. in_port_t port=0;
  897. ESP_LOGV_LOC(TAG, "Getting remote socket address");
  898. remote_ip = http_alloc_get_socket_address(req,0, &port);
  899. ESP_LOGW_LOC(TAG, "%s requested invalid URL: [%s]",remote_ip, req->uri);
  900. if(network_status_lock_sta_ip_string(portMAX_DELAY)){
  901. sta_ip_address = strdup_psram(network_status_get_sta_ip_string());
  902. network_status_unlock_sta_ip_string();
  903. }
  904. else {
  905. ESP_LOGE(TAG,"Unable to obtain local IP address from WiFi Manager.");
  906. httpd_resp_send_err(req, HTTPD_500_INTERNAL_SERVER_ERROR , NULL);
  907. }
  908. ESP_LOGV_LOC(TAG, "Getting host name from request");
  909. char *req_host = alloc_get_http_header(req, "Host");
  910. user_agent = alloc_get_http_header(req,"User-Agent");
  911. if((useragentiscaptivenetwork = (user_agent!=NULL && strcasestr(user_agent,"CaptiveNetworkSupport"))==true)){
  912. ESP_LOGW_LOC(TAG,"Found user agent that supports captive networks! [%s]",user_agent);
  913. }
  914. esp_err_t hn_err = ESP_OK;
  915. ESP_LOGV_LOC(TAG, "Getting adapter host name");
  916. if((hn_err = tcpip_adapter_get_hostname(TCPIP_ADAPTER_IF_STA, &host_name )) !=ESP_OK) {
  917. ESP_LOGE_LOC(TAG, "Unable to get host name. Error: %s",esp_err_to_name(hn_err));
  918. err=err==ESP_OK?hn_err:err;
  919. }
  920. else {
  921. ESP_LOGV_LOC(TAG, "Host name is %s",host_name);
  922. }
  923. in_port_t loc_port=0;
  924. ESP_LOGV_LOC(TAG, "Getting local socket address");
  925. socket_local_address= http_alloc_get_socket_address(req,1, &loc_port);
  926. ESP_LOGD_LOC(TAG, "Peer IP: %s [port %u], System AP IP address: %s, System host: %s. Requested Host: [%s], uri [%s]",STR_OR_NA(remote_ip), port, STR_OR_NA(ap_ip_address), STR_OR_NA(host_name), STR_OR_NA(req_host), req->uri);
  927. /* captive portal functionality: redirect to access point IP for HOST that are not the access point IP OR the STA IP */
  928. /* determine if Host is from the STA IP address */
  929. if((request_contains_hostname = (host_name!=NULL) && (req_host!=NULL) && strcasestr(req_host,host_name)) == true){
  930. ESP_LOGD_LOC(TAG,"http request host = system host name %s", req_host);
  931. }
  932. else if((request_contains_hostname = (ap_host_name!=NULL) && (req_host!=NULL) && strcasestr(req_host,ap_host_name)) == true){
  933. ESP_LOGD_LOC(TAG,"http request host = AP system host name %s", req_host);
  934. }
  935. if((request_contains_ap_ip_address = (ap_ip_address!=NULL) && (req_host!=NULL) && strcasestr(req_host,ap_ip_address))== true){
  936. ESP_LOGD_LOC(TAG,"http request host is access point ip address %s", req_host);
  937. }
  938. if((connected_to_ap_ip_interface = (ap_ip_address!=NULL) && (socket_local_address!=NULL) && strcasestr(socket_local_address,ap_ip_address))==true){
  939. ESP_LOGD_LOC(TAG,"http request is connected to access point interface IP %s", ap_ip_address);
  940. }
  941. if((request_is_sta_ip_address = (sta_ip_address!=NULL) && (req_host!=NULL) && strcasestr(req_host,sta_ip_address))==true){
  942. ESP_LOGD_LOC(TAG,"http request host is WiFi client ip address %s", req_host);
  943. }
  944. if((connected_to_sta_ip_interface = (sta_ip_address!=NULL) && (socket_local_address!=NULL) && strcasestr(sta_ip_address,socket_local_address))==true){
  945. ESP_LOGD_LOC(TAG,"http request is connected to WiFi client ip address %s", sta_ip_address);
  946. }
  947. if((error == 0) || (error == HTTPD_404_NOT_FOUND && connected_to_ap_ip_interface && !(request_contains_ap_ip_address || request_contains_hostname ))) {
  948. process_redirect(req,"302 Found");
  949. }
  950. else {
  951. ESP_LOGD_LOC(TAG,"URL not found, and not processing captive portal so throw regular 404 error");
  952. httpd_resp_send_err(req, error, NULL);
  953. }
  954. FREE_AND_NULL(socket_local_address);
  955. FREE_AND_NULL(req_host);
  956. FREE_AND_NULL(user_agent);
  957. FREE_AND_NULL(sta_ip_address);
  958. FREE_AND_NULL(remote_ip);
  959. return err;
  960. }
  961. esp_err_t redirect_ev_handler(httpd_req_t *req){
  962. return redirect_processor(req,0);
  963. }
  964. esp_err_t messages_get_handler(httpd_req_t *req){
  965. ESP_LOGD_LOC(TAG, "serving [%s]", req->uri);
  966. if(!is_user_authenticated(req)){
  967. // todo: redirect to login page
  968. // return ESP_OK;
  969. }
  970. esp_err_t err = set_content_type_from_req(req);
  971. if(err != ESP_OK){
  972. return err;
  973. }
  974. cJSON * json_messages= messaging_retrieve_messages(messaging);
  975. if(json_messages!=NULL){
  976. char * json_text= cJSON_Print(json_messages);
  977. httpd_resp_send(req, (const char *)json_text, strlen(json_text));
  978. free(json_text);
  979. cJSON_Delete(json_messages);
  980. }
  981. else {
  982. httpd_resp_send_err(req, HTTPD_500_INTERNAL_SERVER_ERROR , "Unable to retrieve messages");
  983. }
  984. return ESP_OK;
  985. }
  986. esp_err_t status_get_handler(httpd_req_t *req){
  987. ESP_LOGD_LOC(TAG, "serving [%s]", req->uri);
  988. if(!is_user_authenticated(req)){
  989. // todo: redirect to login page
  990. // return ESP_OK;
  991. }
  992. esp_err_t err = set_content_type_from_req(req);
  993. if(err != ESP_OK){
  994. return err;
  995. }
  996. if(network_status_lock_json_buffer(( TickType_t ) 200/portTICK_PERIOD_MS)) {
  997. char *buff = network_status_alloc_get_ip_info_json();
  998. network_status_unlock_json_buffer();
  999. if(buff) {
  1000. httpd_resp_send(req, (const char *)buff, strlen(buff));
  1001. free(buff);
  1002. }
  1003. else {
  1004. httpd_resp_send_err(req, HTTPD_500_INTERNAL_SERVER_ERROR , "Empty status object");
  1005. }
  1006. }
  1007. else {
  1008. httpd_resp_send_err(req, HTTPD_500_INTERNAL_SERVER_ERROR , "Error retrieving status object");
  1009. }
  1010. // update status for next status call
  1011. network_async_update_status();
  1012. return ESP_OK;
  1013. }
  1014. esp_err_t err_handler(httpd_req_t *req, httpd_err_code_t error){
  1015. esp_err_t err = ESP_OK;
  1016. if(error != HTTPD_404_NOT_FOUND){
  1017. err = httpd_resp_send_err(req, error, NULL);
  1018. }
  1019. else {
  1020. err = redirect_processor(req,error);
  1021. }
  1022. return err;
  1023. }