Fri, 17 May 2019 15:39:05 +0200
Fixed css path in chart.html. Show errors in console when writing logfiles.json. Upgraded esp-idf.
0 | 1 | /** |
2 | * @file task_http.c | |
3 | * @brief HTTP and Websocket server functions. | |
4 | * This uses some ESP32 Websocket code written by Blake Felt - blake.w.felt@gmail.com | |
5 | */ | |
6 | #include "config.h" | |
7 | #include "mbedtls/base64.h" | |
8 | #include "mbedtls/sha1.h" | |
41
7639cfa6aec0
Websocket interface is working for the main screen and manual mode.
Michiel Broek <mbroek@mbse.eu>
parents:
38
diff
changeset
|
9 | #include "cJSON.h" |
0 | 10 | |
11 | ||
1
ad2c8b13eb88
Updated lots of doxygen comments
Michiel Broek <mbroek@mbse.eu>
parents:
0
diff
changeset
|
12 | static const char *TAG = "task_http"; |
0 | 13 | static QueueHandle_t client_queue; |
14 | const static int client_queue_size = 10; | |
15 | static TaskHandle_t xTaskHTTP = NULL; | |
16 | static TaskHandle_t xTaskQueue = NULL; | |
17 | ||
41
7639cfa6aec0
Websocket interface is working for the main screen and manual mode.
Michiel Broek <mbroek@mbse.eu>
parents:
38
diff
changeset
|
18 | cJSON *root = NULL; |
7639cfa6aec0
Websocket interface is working for the main screen and manual mode.
Michiel Broek <mbroek@mbse.eu>
parents:
38
diff
changeset
|
19 | cJSON *touch = NULL; |
0 | 20 | |
21 | ||
1
ad2c8b13eb88
Updated lots of doxygen comments
Michiel Broek <mbroek@mbse.eu>
parents:
0
diff
changeset
|
22 | /** |
ad2c8b13eb88
Updated lots of doxygen comments
Michiel Broek <mbroek@mbse.eu>
parents:
0
diff
changeset
|
23 | * @brief Debug dump buffer |
ad2c8b13eb88
Updated lots of doxygen comments
Michiel Broek <mbroek@mbse.eu>
parents:
0
diff
changeset
|
24 | * @param buf The buffer |
ad2c8b13eb88
Updated lots of doxygen comments
Michiel Broek <mbroek@mbse.eu>
parents:
0
diff
changeset
|
25 | * @param buflen Length of the buffer |
ad2c8b13eb88
Updated lots of doxygen comments
Michiel Broek <mbroek@mbse.eu>
parents:
0
diff
changeset
|
26 | */ |
41
7639cfa6aec0
Websocket interface is working for the main screen and manual mode.
Michiel Broek <mbroek@mbse.eu>
parents:
38
diff
changeset
|
27 | #if 0 |
0 | 28 | void dump_buf(char *buf, uint16_t buflen); |
41
7639cfa6aec0
Websocket interface is working for the main screen and manual mode.
Michiel Broek <mbroek@mbse.eu>
parents:
38
diff
changeset
|
29 | #endif |
0 | 30 | |
1
ad2c8b13eb88
Updated lots of doxygen comments
Michiel Broek <mbroek@mbse.eu>
parents:
0
diff
changeset
|
31 | |
0 | 32 | /** |
33 | * @brief Send HTTP error and message | |
34 | * @param conn The socket to send to. | |
35 | * @param error The HTTP error code. | |
36 | * @param message Yhe human readable explanation. | |
37 | * @paeam body The human readable explanation. | |
38 | */ | |
39 | static void http_error(struct netconn *conn, int error, char *message, char *body) | |
40 | { | |
41 | char *tmp = malloc(200); | |
42 | ||
43 | ESP_LOGI(TAG, "Http response %d - %s", error, message); | |
44 | if (strlen(body)) { | |
45 | snprintf(tmp, 199, "HTTP/1.1 %d %s\r\nContent-type: text/plain\r\n\r\n%s\n", error, message, body); | |
46 | } else { | |
47 | snprintf(tmp, 199, "HTTP/1.1 %d %s\r\n\r\n", error, message); | |
48 | } | |
49 | netconn_write(conn, tmp, strlen(tmp), NETCONN_NOCOPY); | |
50 | free(tmp); | |
51 | } | |
52 | ||
53 | ||
54 | ||
55 | /** | |
56 | * @brief Send HTTP file from the filesystem. | |
57 | * @param conn The network connection. | |
58 | * @param url The requested url. | |
59 | * @param mod_since The date/time of the file, or NULL. | |
60 | * @param ipstr The IP address of the remote. | |
61 | */ | |
62 | static void http_sendfile(struct netconn *conn, char *url, char *mod_since, char *ipstr) | |
63 | { | |
64 | char temp_url[128], temp_url_gz[128], header[128], c_type[32]; | |
65 | struct stat st; | |
66 | off_t filesize; | |
67 | size_t sentsize; | |
68 | char strftime_buf[64]; | |
69 | err_t err; | |
70 | bool send_gz; | |
71 | FILE *f; | |
72 | ||
73 | if (url[strlen(url) - 1] == '/') { | |
74 | // If no filename given, use index.html | |
75 | sprintf(temp_url, "/spiffs/w%sindex.html", url); | |
76 | } else if (strncmp(url, "/log/", 5) == 0) { | |
77 | // Logfiles are on the SD card. | |
78 | sprintf(temp_url, "/sdcard/w%s", url); | |
79 | } else { | |
80 | sprintf(temp_url, "/spiffs/w%s", url); | |
81 | for (int i = 0; i < 127; i++) { | |
82 | if (temp_url[i] == '?') | |
83 | temp_url[i] = '\0'; | |
84 | if (temp_url[i] == '\0') | |
85 | break; | |
86 | } | |
87 | } | |
88 | sprintf(temp_url_gz, "%s.gz", temp_url); | |
89 | ||
90 | /* | |
91 | * Get filesize and date for the response headers. | |
92 | * Note that the /spiffs filesystem doesn't support file timestamps | |
93 | * and returns the epoch for each file. Therefore we cannot use | |
94 | * the cache based on timestamps. | |
95 | */ | |
96 | filesize = 0; | |
97 | strftime_buf[0] = '\0'; | |
98 | send_gz = false; | |
99 | if (stat(temp_url_gz, &st) == 0) { | |
100 | filesize = st.st_size; | |
101 | strftime(strftime_buf, sizeof(strftime_buf), "%a, %d %b %Y %T %z", localtime(&(st.st_mtime))); | |
102 | send_gz = true; | |
103 | } else if (stat(temp_url, &st) == 0) { | |
104 | filesize = st.st_size; | |
105 | strftime(strftime_buf, sizeof(strftime_buf), "%a, %d %b %Y %T %z", localtime(&(st.st_mtime))); | |
106 | } | |
107 | ||
108 | /* | |
109 | * If we have a If-Modified-Since parameter, compare that with the current | |
110 | * filedate on disk. If It's the same send a 304 response. | |
111 | * Cannot work on /spiffs. | |
112 | */ | |
113 | #if 0 | |
114 | time_t Now; | |
115 | struct tm timeInfo; | |
116 | if (mod_since && strlen(strftime_buf)) { | |
117 | time(&Now); | |
118 | localtime_r(&Now, &timeInfo); | |
119 | strftime(strftime_buf, sizeof(strftime_buf), "%a, %d %b %Y %T %z", &timeInfo); | |
120 | sprintf(header, "HTTP/1.1 304 Not Modified\r\nDate: %s\r\n\r\n", strftime_buf); | |
121 | netconn_write(conn, header, strlen(header), NETCONN_NOCOPY); | |
122 | ESP_LOGI(TAG, "http_sendfile %s Not Modified, ok", temp_url); | |
123 | return; | |
124 | } | |
125 | #endif | |
126 | ||
127 | if (send_gz) { | |
128 | f = fopen(temp_url_gz, "r"); | |
129 | } else { | |
130 | f = fopen(temp_url, "r"); | |
131 | } | |
132 | if (f == NULL) { | |
133 | ESP_LOGI(TAG, "%s url \'%s\' file \'%s\' not found", ipstr, url, temp_url); | |
134 | http_error(conn, 404, "Not found", "Not found"); | |
135 | return; | |
136 | } | |
137 | ||
138 | if (strcmp(".html", &temp_url[strlen(temp_url) - 5]) == 0) { | |
139 | sprintf(c_type, "text/html"); | |
140 | } else if (strcmp(".css", &temp_url[strlen(temp_url) - 4]) == 0) { | |
141 | sprintf(c_type, "text/css"); | |
142 | } else if (strcmp(".js", &temp_url[strlen(temp_url) - 3]) == 0) { | |
143 | sprintf(c_type, "text/javascript"); | |
144 | } else if (strcmp(".json", &temp_url[strlen(temp_url) - 5]) == 0) { | |
145 | sprintf(c_type, "text/json"); | |
146 | } else if (strcmp(".gz", &temp_url[strlen(temp_url) - 3]) == 0) { | |
147 | sprintf(c_type, "application/x-gzip"); | |
148 | } else if (strcmp(".png", &temp_url[strlen(temp_url) - 4]) == 0) { | |
149 | sprintf(c_type, "image/png"); | |
150 | } else if (strcmp(".svg", &temp_url[strlen(temp_url) - 4]) == 0) { | |
151 | sprintf(c_type, "image/svg+xml"); | |
152 | } else if (strcmp(".oga", &temp_url[strlen(temp_url) - 4]) == 0) { | |
153 | sprintf(c_type, "audio/ogg"); | |
154 | } else if (strcmp(".ico", &temp_url[strlen(temp_url) - 4]) == 0) { | |
155 | sprintf(c_type, "image/x-icon"); | |
156 | } else if (strcmp(".xml", &temp_url[strlen(temp_url) - 4]) == 0) { | |
157 | sprintf(c_type, "text/xml"); | |
158 | } else { | |
159 | sprintf(c_type, "application/octet-stream"); | |
160 | printf("Unknown content type for %s\n", temp_url); | |
161 | } | |
162 | ||
163 | vTaskDelay(2 / portTICK_PERIOD_MS); | |
164 | // httpdHeader(connData, "Cache-Control", "max-age=3600, must-revalidate"); | |
165 | if (filesize) { | |
166 | sprintf(header, "HTTP/1.1 200 OK\r\nLast-Modified: %s\r\nContent-Length: %ld\r\nContent-type: %s\r\n", strftime_buf, filesize, c_type); | |
167 | } else { | |
168 | sprintf(header, "HTTP/1.1 200 OK\r\nContent-type: %s\r\n", c_type); | |
169 | } | |
170 | if (send_gz) { | |
171 | sprintf(header, "%sContent-Encoding: gzip\r\n", header); | |
172 | } | |
173 | sprintf(header, "%s\r\n", header); // Add last empty line. | |
174 | err = netconn_write(conn, header, strlen(header), NETCONN_NOCOPY); | |
175 | if (err != ERR_OK) { | |
176 | ESP_LOGE(TAG, "%s sendfile %s%s err=%d on header write", ipstr, temp_url, (send_gz) ? ".gz":"", err); | |
177 | fclose(f); | |
178 | return; | |
179 | } | |
180 | // if (strstr(acceptEncodingBuffer, "gzip") == NULL) | |
181 | // http_error(conn, 501, "Not implemented", "Your browser does not accept gzip-compressed data."); | |
182 | ||
183 | sentsize = 0; | |
184 | uint8_t *buff = malloc(1024); | |
185 | size_t bytes; | |
186 | int pause = 0; | |
187 | ||
188 | for (;;) { | |
189 | bytes = fread(buff, 1, 1024, f); | |
190 | if (bytes == 0) | |
191 | break; | |
192 | ||
193 | err = netconn_write(conn, buff, bytes, NETCONN_NOCOPY); | |
194 | if (err != ERR_OK) { | |
195 | ESP_LOGE(TAG, "%s sendfile %s%s err=%d send %u bytes of %ld bytes", ipstr, temp_url, (send_gz) ? ".gz":"", err, sentsize, filesize); | |
196 | break; | |
197 | } | |
198 | vTaskDelay(2 / portTICK_PERIOD_MS); | |
199 | sentsize += bytes; | |
200 | pause++; | |
201 | if (pause > 50) { // 50 K | |
202 | pause = 0; | |
203 | vTaskDelay(50 / portTICK_PERIOD_MS); | |
204 | } | |
205 | } | |
206 | fclose(f); | |
207 | free(buff); | |
208 | ||
209 | if (sentsize == filesize) { | |
210 | ESP_LOGI(TAG, "%s sendfile %s%s sent %u bytes, ok (%s)", ipstr, temp_url, (send_gz) ? ".gz":"", sentsize, url); | |
211 | } | |
212 | } | |
213 | ||
214 | ||
215 | ||
216 | /** | |
217 | * @brief Handle web ui websocket events. | |
218 | */ | |
219 | void websock_callback(uint8_t num, WEBSOCKET_TYPE_t type, char* msg, uint64_t len) | |
220 | { | |
41
7639cfa6aec0
Websocket interface is working for the main screen and manual mode.
Michiel Broek <mbroek@mbse.eu>
parents:
38
diff
changeset
|
221 | char jbuf[128]; |
7639cfa6aec0
Websocket interface is working for the main screen and manual mode.
Michiel Broek <mbroek@mbse.eu>
parents:
38
diff
changeset
|
222 | |
0 | 223 | switch(type) { |
224 | case WEBSOCKET_CONNECT: | |
225 | ESP_LOGI(TAG,"Websocket client %i connected!",num); | |
226 | break; | |
227 | ||
228 | case WEBSOCKET_DISCONNECT_EXTERNAL: | |
229 | ESP_LOGI(TAG,"Websocket client %i sent a disconnect message",num); | |
230 | break; | |
231 | ||
232 | case WEBSOCKET_DISCONNECT_INTERNAL: | |
233 | ESP_LOGI(TAG,"Websocket client %i was disconnected",num); | |
234 | break; | |
235 | ||
236 | case WEBSOCKET_DISCONNECT_ERROR: | |
237 | ESP_LOGI(TAG,"Websocket client %i was disconnected due to an error",num); | |
238 | break; | |
239 | ||
240 | case WEBSOCKET_TEXT: | |
41
7639cfa6aec0
Websocket interface is working for the main screen and manual mode.
Michiel Broek <mbroek@mbse.eu>
parents:
38
diff
changeset
|
241 | /* |
7639cfa6aec0
Websocket interface is working for the main screen and manual mode.
Michiel Broek <mbroek@mbse.eu>
parents:
38
diff
changeset
|
242 | * Handle json actions from the web clients, like button presses. |
7639cfa6aec0
Websocket interface is working for the main screen and manual mode.
Michiel Broek <mbroek@mbse.eu>
parents:
38
diff
changeset
|
243 | */ |
7639cfa6aec0
Websocket interface is working for the main screen and manual mode.
Michiel Broek <mbroek@mbse.eu>
parents:
38
diff
changeset
|
244 | if (len < 128) { // Safety, messages are small. |
7639cfa6aec0
Websocket interface is working for the main screen and manual mode.
Michiel Broek <mbroek@mbse.eu>
parents:
38
diff
changeset
|
245 | memcpy(jbuf, msg, len); |
7639cfa6aec0
Websocket interface is working for the main screen and manual mode.
Michiel Broek <mbroek@mbse.eu>
parents:
38
diff
changeset
|
246 | jbuf[len] = '\0'; |
7639cfa6aec0
Websocket interface is working for the main screen and manual mode.
Michiel Broek <mbroek@mbse.eu>
parents:
38
diff
changeset
|
247 | if ((root = cJSON_Parse(jbuf))) { |
7639cfa6aec0
Websocket interface is working for the main screen and manual mode.
Michiel Broek <mbroek@mbse.eu>
parents:
38
diff
changeset
|
248 | if ((touch = cJSON_GetObjectItem(root,"touch"))) { |
7639cfa6aec0
Websocket interface is working for the main screen and manual mode.
Michiel Broek <mbroek@mbse.eu>
parents:
38
diff
changeset
|
249 | int x = cJSON_GetObjectItem(touch, "x")->valueint; |
7639cfa6aec0
Websocket interface is working for the main screen and manual mode.
Michiel Broek <mbroek@mbse.eu>
parents:
38
diff
changeset
|
250 | int y = cJSON_GetObjectItem(touch, "y")->valueint; |
7639cfa6aec0
Websocket interface is working for the main screen and manual mode.
Michiel Broek <mbroek@mbse.eu>
parents:
38
diff
changeset
|
251 | WS_touched(x, y); |
7639cfa6aec0
Websocket interface is working for the main screen and manual mode.
Michiel Broek <mbroek@mbse.eu>
parents:
38
diff
changeset
|
252 | break; |
7639cfa6aec0
Websocket interface is working for the main screen and manual mode.
Michiel Broek <mbroek@mbse.eu>
parents:
38
diff
changeset
|
253 | } else { |
7639cfa6aec0
Websocket interface is working for the main screen and manual mode.
Michiel Broek <mbroek@mbse.eu>
parents:
38
diff
changeset
|
254 | ESP_LOGI(TAG,"not json touch"); |
7639cfa6aec0
Websocket interface is working for the main screen and manual mode.
Michiel Broek <mbroek@mbse.eu>
parents:
38
diff
changeset
|
255 | } |
7639cfa6aec0
Websocket interface is working for the main screen and manual mode.
Michiel Broek <mbroek@mbse.eu>
parents:
38
diff
changeset
|
256 | cJSON_Delete(root); |
7639cfa6aec0
Websocket interface is working for the main screen and manual mode.
Michiel Broek <mbroek@mbse.eu>
parents:
38
diff
changeset
|
257 | } else { |
7639cfa6aec0
Websocket interface is working for the main screen and manual mode.
Michiel Broek <mbroek@mbse.eu>
parents:
38
diff
changeset
|
258 | ESP_LOGI(TAG,"not json"); |
7639cfa6aec0
Websocket interface is working for the main screen and manual mode.
Michiel Broek <mbroek@mbse.eu>
parents:
38
diff
changeset
|
259 | } |
7639cfa6aec0
Websocket interface is working for the main screen and manual mode.
Michiel Broek <mbroek@mbse.eu>
parents:
38
diff
changeset
|
260 | } |
7639cfa6aec0
Websocket interface is working for the main screen and manual mode.
Michiel Broek <mbroek@mbse.eu>
parents:
38
diff
changeset
|
261 | // Log if the message in not processed. |
0 | 262 | ESP_LOGI(TAG,"Websocket client %i sent text message of size %i:\n%s",num,(uint32_t)len,msg); |
263 | break; | |
264 | ||
265 | case WEBSOCKET_BIN: | |
266 | ESP_LOGI(TAG,"Websocket client %i sent bin message of size %i:\n",num,(uint32_t)len); | |
267 | break; | |
268 | ||
269 | case WEBSOCKET_PING: | |
270 | ESP_LOGI(TAG,"client %i pinged us with message of size %i:\n%s",num,(uint32_t)len,msg); | |
271 | break; | |
272 | ||
273 | case WEBSOCKET_PONG: | |
274 | ESP_LOGI(TAG,"client %i responded to the ping",num); | |
275 | break; | |
276 | } | |
277 | } | |
278 | ||
279 | ||
280 | ||
41
7639cfa6aec0
Websocket interface is working for the main screen and manual mode.
Michiel Broek <mbroek@mbse.eu>
parents:
38
diff
changeset
|
281 | #if 0 |
0 | 282 | void dump_buf(char *buf, uint16_t buflen) |
283 | { | |
284 | int i = 0, l = 1; | |
285 | ||
286 | printf("request length %d\n00: ", buflen); | |
287 | for (;;) { | |
288 | if (i >= buflen) | |
289 | break; | |
290 | if ((buf[i] < ' ') || (buf[i] > 126)) { | |
291 | if (buf[i] == '\n') { | |
292 | printf("\\n\n%02d: ", l); | |
293 | l++; | |
294 | } else if (buf[i] == '\r') { | |
295 | printf("\\r"); | |
296 | } else { | |
297 | printf("\\%02x", buf[i]); | |
298 | } | |
299 | } else { | |
300 | printf("%c", buf[i]); | |
301 | } | |
302 | i++; | |
303 | } | |
304 | printf("\n"); | |
305 | } | |
41
7639cfa6aec0
Websocket interface is working for the main screen and manual mode.
Michiel Broek <mbroek@mbse.eu>
parents:
38
diff
changeset
|
306 | #endif |
0 | 307 | |
308 | ||
309 | ||
310 | /** | |
311 | * @brief Serve any client. | |
312 | * @param http_client_sock The socket on which the client is connected. | |
313 | */ | |
314 | static void http_serve(struct netconn *conn) | |
315 | { | |
316 | char ipstr[IPADDR_STRLEN_MAX]; | |
317 | struct netbuf *inbuf; | |
318 | static char *buf; | |
319 | static uint16_t buflen; | |
320 | static err_t err; | |
321 | char url[128], *p, *mod_since = NULL; | |
322 | ip_addr_t remote_addr; | |
323 | uint16_t remote_port; | |
324 | ||
325 | if (netconn_getaddr(conn, &remote_addr, &remote_port, 0) == ERR_OK) { | |
326 | strcpy(ipstr, ip4addr_ntoa(ip_2_ip4(&remote_addr))); | |
327 | } else { | |
328 | ipstr[0] = '\0'; | |
329 | } | |
330 | ||
331 | netconn_set_recvtimeout(conn,1000); // allow a connection timeout of 1 second | |
332 | err = netconn_recv(conn, &inbuf); | |
333 | ||
334 | if (err != ERR_OK) { | |
335 | if (err != ERR_TIMEOUT) { // Ignore timeout | |
336 | ESP_LOGI(TAG,"%s error %d on read", ipstr, err); | |
337 | } | |
338 | netconn_close(conn); | |
339 | netconn_delete(conn); | |
340 | netbuf_delete(inbuf); | |
341 | return; | |
342 | } | |
343 | ||
344 | netbuf_data(inbuf, (void**)&buf, &buflen); | |
345 | ||
346 | if (buf) { | |
347 | /* | |
348 | * Build url string from the data buffer. | |
349 | * It looks like: GET /app/localization.js HTTP/1.1 | |
350 | */ | |
351 | for (int i = 0; i < 10; i++) { | |
352 | if (buf[i] == ' ') { | |
353 | i++; | |
354 | for (int j = i; j < 128; j++) { | |
355 | url[j-i] = buf[j]; | |
356 | if (url[j-i] == ' ') { | |
357 | url[j-i] = '\0'; | |
358 | break; | |
359 | } | |
360 | } | |
361 | break; | |
362 | } | |
363 | } | |
364 | ||
365 | if (strstr(buf, "GET /logfiles.json")) { | |
366 | char temp[64]; | |
367 | FILE *dest = fopen("/spiffs/w/logfiles.json", "w"); | |
368 | if (dest) { | |
369 | fprintf(dest, "{\"Dir\":[{\"Folder\":\"/log\",\"Files\":["); | |
370 | DIR *dir = opendir("/sdcard/w/log"); | |
371 | if (dir) { | |
372 | struct dirent* de = readdir(dir); | |
373 | struct stat st; | |
374 | bool comma = false; | |
375 | while (de) { | |
376 | sprintf(temp, "/sdcard/w/log/%s", de->d_name); | |
377 | if (stat(temp, &st) == ESP_OK) { | |
378 | fprintf(dest, "%s{\"File\":\"%s\",\"Size\":%ld,\"Date\":%ld}", (comma)?",":"", de->d_name, st.st_size, st.st_mtime); | |
379 | comma = true; | |
380 | } | |
381 | de = readdir(dir); | |
382 | vTaskDelay(5 / portTICK_PERIOD_MS); | |
383 | } | |
384 | closedir(dir); | |
47
2aab3b5af4b5
Fixed css path in chart.html. Show errors in console when writing logfiles.json. Upgraded esp-idf.
Michiel Broek <mbroek@mbse.eu>
parents:
41
diff
changeset
|
385 | } else { |
2aab3b5af4b5
Fixed css path in chart.html. Show errors in console when writing logfiles.json. Upgraded esp-idf.
Michiel Broek <mbroek@mbse.eu>
parents:
41
diff
changeset
|
386 | ESP_LOGE(TAG, "Error %d open directory /sdcard/w/log", errno); |
2aab3b5af4b5
Fixed css path in chart.html. Show errors in console when writing logfiles.json. Upgraded esp-idf.
Michiel Broek <mbroek@mbse.eu>
parents:
41
diff
changeset
|
387 | } |
0 | 388 | fprintf(dest, "]}]}"); |
389 | fclose(dest); | |
47
2aab3b5af4b5
Fixed css path in chart.html. Show errors in console when writing logfiles.json. Upgraded esp-idf.
Michiel Broek <mbroek@mbse.eu>
parents:
41
diff
changeset
|
390 | } else { |
2aab3b5af4b5
Fixed css path in chart.html. Show errors in console when writing logfiles.json. Upgraded esp-idf.
Michiel Broek <mbroek@mbse.eu>
parents:
41
diff
changeset
|
391 | ESP_LOGE(TAG, "Error %d write /spiffs/w/logfiles.json", errno); |
0 | 392 | } |
393 | http_sendfile(conn, "/logfiles.json", NULL, ipstr); | |
394 | netconn_close(conn); | |
395 | netconn_delete(conn); | |
396 | netbuf_delete(inbuf); | |
397 | unlink("/spiffs/w/logfiles.json"); | |
398 | return; | |
399 | } | |
400 | ||
401 | // http requests | |
402 | if (! strstr(buf,"Upgrade: websocket")) { // Not websocket | |
403 | p = strstr(buf, "If-Modified-Since:"); // May be cached | |
404 | if (p) { | |
405 | size_t mod_len = strcspn(p, " "); | |
406 | p += (int)(mod_len + 1); | |
407 | mod_len = strcspn(p, "\r\n"); | |
408 | mod_since = malloc(mod_len + 2); | |
409 | memcpy(mod_since, p, mod_len); | |
410 | mod_since[mod_len] = '\0'; | |
411 | } | |
412 | http_sendfile(conn, url, mod_since, ipstr); | |
413 | if (mod_since) | |
414 | free(mod_since); | |
415 | mod_since = NULL; | |
416 | netconn_close(conn); | |
417 | netconn_delete(conn); | |
418 | netbuf_delete(inbuf); | |
419 | return; | |
420 | } | |
421 | ||
422 | // websocket for web UI. | |
423 | if ((strstr(buf,"GET /ws ") && strstr(buf,"Upgrade: websocket"))) { | |
424 | int nr = ws_server_add_client_protocol(conn, buf, buflen, "/ws", "binary", websock_callback); | |
425 | ESP_LOGI(TAG, "%s new websocket on /ws client: %d", ipstr, nr); | |
426 | netbuf_delete(inbuf); | |
427 | TFTstartWS(nr); | |
428 | // Startup something? Init webscreen? | |
429 | return; | |
430 | } | |
431 | ||
41
7639cfa6aec0
Websocket interface is working for the main screen and manual mode.
Michiel Broek <mbroek@mbse.eu>
parents:
38
diff
changeset
|
432 | #if 0 |
0 | 433 | dump_buf(buf, buflen); |
41
7639cfa6aec0
Websocket interface is working for the main screen and manual mode.
Michiel Broek <mbroek@mbse.eu>
parents:
38
diff
changeset
|
434 | #endif |
0 | 435 | |
436 | if (strstr(buf, "GET /")) { | |
437 | ESP_LOGI(TAG, "%s request: %s", ipstr, buf); | |
438 | http_error(conn, 404, "Not found", "Not found"); | |
439 | } else { | |
440 | http_error(conn, 405, "Invalid method", "Invalid method"); | |
441 | } | |
442 | } | |
443 | ||
444 | netconn_close(conn); | |
445 | netconn_delete(conn); | |
446 | netbuf_delete(inbuf); | |
447 | } | |
448 | ||
449 | ||
450 | ||
451 | /** | |
452 | * @brief Handles clients when they first connect. passes to a queue | |
453 | */ | |
454 | static void task_HTTPserver(void* pvParameters) | |
455 | { | |
456 | struct netconn *conn, *newconn; | |
457 | static err_t err; | |
458 | ||
459 | ESP_LOGI(TAG, "Starting http server_task"); | |
460 | client_queue = xQueueCreate(client_queue_size,sizeof(struct netconn*)); | |
461 | ||
462 | conn = netconn_new(NETCONN_TCP); | |
463 | netconn_bind(conn,NULL,80); | |
464 | netconn_listen(conn); | |
465 | ||
466 | do { | |
467 | err = netconn_accept(conn, &newconn); | |
468 | if (err == ERR_OK) { | |
469 | if (xQueueSendToBack(client_queue,&newconn,portMAX_DELAY) != pdTRUE) { | |
470 | ESP_LOGE(TAG, "xQueueSendToBack() queue full"); | |
471 | }; | |
472 | } | |
473 | vTaskDelay(5 / portTICK_PERIOD_MS); | |
474 | } while (err == ERR_OK); | |
475 | ||
476 | ESP_LOGE(TAG, "Stopping http server_task"); | |
477 | netconn_close(conn); | |
478 | netconn_delete(conn); | |
479 | vTaskDelete(NULL); | |
480 | } | |
481 | ||
482 | ||
483 | ||
484 | /** | |
485 | * @brief Receives clients from queue and handle them. | |
486 | */ | |
487 | static void task_Queue(void* pvParameters) | |
488 | { | |
489 | struct netconn* conn; | |
490 | ||
491 | ESP_LOGI(TAG, "Starting Queue task"); | |
492 | for(;;) { | |
493 | xQueueReceive(client_queue, &conn, portMAX_DELAY); | |
494 | if (!conn) | |
495 | continue; | |
496 | http_serve(conn); | |
497 | vTaskDelay(2 / portTICK_PERIOD_MS); | |
498 | } | |
499 | ESP_LOGE(TAG, "Stopping Queue task"); | |
500 | vTaskDelete(NULL); | |
501 | } | |
502 | ||
503 | ||
504 | ||
505 | void start_http_websocket(void) | |
506 | { | |
507 | ESP_LOGI(TAG, "Starting HTTP/Websocket server"); | |
508 | ||
509 | ws_server_start(); | |
510 | xTaskCreate(&task_HTTPserver, "HTTPserver", 3000, NULL, 9, &xTaskHTTP); | |
511 | xTaskCreate(&task_Queue, "Queue", 4000, NULL, 6, &xTaskQueue); | |
512 | } | |
513 |