111 lines
3.6 KiB
C++
111 lines
3.6 KiB
C++
#include "http_server.h"
|
|
#include <ESPmDNS.h>
|
|
|
|
HTTPServer::HTTPServer(Player* p, Controller* c) {
|
|
_player = p;
|
|
_controller = c;
|
|
_server = new AsyncWebServer(80);
|
|
ws = new AsyncWebSocket("/ws");
|
|
_server->addHandler(ws);
|
|
ws->onEvent([&](AsyncWebSocket * server, AsyncWebSocketClient * client, AwsEventType type, void * arg, uint8_t *data, size_t len){this->_onEvent(server, client, type, arg, data, len);});
|
|
_server->on("/", [&](AsyncWebServerRequest* req) {_handle_index(req);});
|
|
_server->begin();
|
|
MDNS.addService("http", "tcp", 80);
|
|
}
|
|
|
|
void HTTPServer::_handle_upload(AsyncWebServerRequest* request, String filename, size_t index, uint8_t* data, size_t len, bool final) {
|
|
// https://www.gnu.org/software/tar/manual/html_node/Standard.html
|
|
// https://www.mkssoftware.com/docs/man4/tar.4.asp
|
|
|
|
if (index == 0) { // Starting upload
|
|
_chunk = new uint8_t[512];
|
|
_chunk_length = 0;
|
|
_upload_position = 0;
|
|
_file_size = 0;
|
|
_file_size_done = 0;
|
|
_need_header = true;
|
|
}
|
|
|
|
uint32_t upload_offset = 0;
|
|
while (upload_offset < len) {
|
|
// Load a chunk
|
|
if (_chunk_length < 512 && len > upload_offset) {
|
|
uint16_t needed = 512 - _chunk_length;
|
|
if (needed > len - upload_offset) needed = len - upload_offset;
|
|
memcpy(_chunk + _chunk_length, data + upload_offset, needed);
|
|
_chunk_length += needed;
|
|
upload_offset += needed;
|
|
_upload_position += needed;
|
|
|
|
if (_chunk_length == 512) {
|
|
// Process chunk
|
|
DEBUG("Chunk.\n");
|
|
if (_need_header) {
|
|
if (_chunk[257]=='u'&&_chunk[258]=='s'&&_chunk[259]=='t'&&_chunk[260]=='a'&&_chunk[261]=='r') {
|
|
DEBUG("It is a valid header, starting at 0x%X!\n", _upload_position-512);
|
|
char filename[200];
|
|
strncpy(filename, (char*)_chunk, 100);
|
|
DEBUG("filename: %s\n", filename);
|
|
_file_size = 0;
|
|
_file_size_done = 0;
|
|
for (int i=0; i<11; i++) {
|
|
//Serial.print(_header_buffer[124 + i]);
|
|
_file_size = (_file_size<<3) + (_chunk[124 + i] - '0');
|
|
}
|
|
DEBUG("filesize: %d\n", _file_size);
|
|
uint8_t type = _chunk[156] - '0';
|
|
if (type==0) {
|
|
DEBUG("Is a file.\n");
|
|
} else if (type==5) {
|
|
DEBUG("Is a directory.\n");
|
|
} else {
|
|
ERROR("Unknown file type %d\n", type);
|
|
}
|
|
_need_header = (type==5 || _file_size==0); // No chunks needed for directories.
|
|
} else {
|
|
bool byte_found = false;
|
|
for (int i=0; i<512; i++) byte_found = byte_found || _chunk[i]>0;
|
|
if (!byte_found) {
|
|
DEBUG("Empty chunk while looking for header -> ignoring.\n");
|
|
} else {
|
|
ERROR("Invalid tar header: %c %c %c %c %c. Looking at header start offset 0x%X.\n", _chunk[257], _chunk[258], _chunk[259], _chunk[260], _chunk[261], _upload_position-512);
|
|
}
|
|
}
|
|
} else {
|
|
uint16_t bytes_to_write = _file_size - _file_size_done;
|
|
if (bytes_to_write > 512) bytes_to_write=512;
|
|
// Write bytes...
|
|
_file_size_done += bytes_to_write;
|
|
if (_file_size_done >= _file_size) _need_header = true;
|
|
}
|
|
|
|
_chunk_length = 0;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (final == true) {
|
|
// Close the file
|
|
delete _chunk;
|
|
return;
|
|
}
|
|
}
|
|
|
|
void HTTPServer::_onEvent(AsyncWebSocket * server, AsyncWebSocketClient * client, AwsEventType type, void * arg, uint8_t *data, size_t len) {
|
|
if (type==WS_EVT_CONNECT) {
|
|
_controller->inform_new_client(client);
|
|
} else if (type==WS_EVT_DATA) {
|
|
AwsFrameInfo* info = (AwsFrameInfo*) arg;
|
|
if (info->final && info->index==0 && info->len==len && info->opcode==WS_TEXT) {
|
|
DEBUG("Received ws message: %s\n", (char*)data);
|
|
_controller->queue_command((char*)data);
|
|
}
|
|
}
|
|
}
|
|
|
|
void HTTPServer::_handle_index(AsyncWebServerRequest* r) {
|
|
|
|
#include "index.html"
|
|
|
|
r->send(200, "text/html", html);
|
|
} |