mirror of
https://github.com/esphome/esphome.git
synced 2025-08-06 18:37:47 +00:00
cleanup
This commit is contained in:
parent
f26bec1a5a
commit
f94703360b
@ -0,0 +1,52 @@
|
||||
[17:53:09][D][sensor:104]: 'Lambda Sensor 15': Sending state 15.00000 with 1 decimals of accuracy
|
||||
[17:53:09][D][sensor:104]: 'Lambda Sensor 34': Sending state 34.00000 with 1 decimals of accuracy
|
||||
[17:53:10][D][sensor:104]: 'Lambda Sensor 16': Sending state 16.00000 with 1 decimals of accuracy
|
||||
[17:53:10][D][sensor:104]: 'Lambda Sensor 7': Sending state 7.00000 with 1 decimals of accuracy
|
||||
[17:53:12][D][esp-idf:000]: W (92465) httpd_txrx: httpd_sock_err: error in send : 9
|
||||
[17:53:12]Guru Meditation Error: Core 0 panic'ed (LoadProhibited). Exception was unhandled.
|
||||
|
||||
[17:53:12]Core 0 register dump:
|
||||
[17:53:12]PC : 0x401a369f PS : 0x00060530 A0 : 0x801705f8 A1 : 0x3ffcc9d0
|
||||
WARNING Decoded 0x401a369f: std::local_Rb_tree_increment(std::_Rb_tree_node_base*) at /Users/brnomac003/.gitlab-runner/builds/qR2TxTby/0/idf/crosstool-NG/.build/xtensa-esp-elf/src/gcc/libstdc++-v3/src/c++98/tree.cc:65
|
||||
[17:53:12]A2 : 0x02000241 A3 : 0x3ffcc9c8 A4 : 0x00000008 A5 : 0x3ffe8b84
|
||||
[17:53:12]A6 : 0x30303030 A7 : 0x63383030 A8 : 0x3ffe8778 A9 : 0x02000241
|
||||
[17:53:12]A10 : 0xfffffffe A11 : 0x0000003b A12 : 0x3ffe8b7c A13 : 0x00000098
|
||||
[17:53:12]A14 : 0x00000000 A15 : 0x3ffe36c4 SAR : 0x00000017 EXCCAUSE: 0x0000001c
|
||||
[17:53:12]EXCVADDR: 0x02000249 LBEG : 0x40082b85 LEND : 0x40082b8d LCOUNT : 0x00000027
|
||||
|
||||
|
||||
[17:53:12]Backtrace: 0x401a369c:0x3ffcc9d0 0x401705f5:0x3ffcc9f0 0x4010062e:0x3ffcca10 0x400f793a:0x3ffcca30 0x400f08c1:0x3ffcca50 0x400f094d:0x3ffcca80 0x401a03ad:0x3ffccac0 0x401a0461:0x3ffccae0 0x40101566:0x3ffccb00 0x4010586a:0x3ffccb30 0x400e6f76:0x3ffccb50
|
||||
WARNING Found stack trace! Trying to decode it
|
||||
WARNING Decoded 0x401a369c: std::local_Rb_tree_increment(std::_Rb_tree_node_base*) at /Users/brnomac003/.gitlab-runner/builds/qR2TxTby/0/idf/crosstool-NG/.build/xtensa-esp-elf/src/gcc/libstdc++-v3/src/c++98/tree.cc:62
|
||||
WARNING Decoded 0x401705f5: std::_Rb_tree_increment(std::_Rb_tree_node_base const*) at /Users/brnomac003/.gitlab-runner/builds/qR2TxTby/0/idf/crosstool-NG/.build/xtensa-esp-elf/src/gcc/libstdc++-v3/src/c++98/tree.cc:89
|
||||
WARNING Decoded 0x4010062e: std::_Rb_tree_const_iterator<esphome::web_server_idf::AsyncEventSourceResponse*>::operator++() at /Users/bdraco/.platformio/packages/toolchain-xtensa-esp-elf/xtensa-esp-elf/include/c++/13.2.0/bits/stl_tree.h:368
|
||||
(inlined by) esphome::web_server_idf::AsyncEventSource::try_send_nodefer(char const*, char const*, unsigned long, unsigned long) at /Users/bdraco/esphome/.esphome/build/ol/src/esphome/components/web_server_idf/web_server_idf.cpp:516
|
||||
WARNING Decoded 0x400f793a: std::_Function_handler<void (unsigned char, char const*, char const*), esphome::web_server::WebServer::setup()::{lambda(int, char const*, char const*)#1}>::_M_invoke(std::_Any_data const&, unsigned char&&, char const*&&, char const*&&) at /Users/bdraco/esphome/.esphome/build/ol/src/esphome/components/web_server/web_server.cpp:247 (discriminator 1)
|
||||
(inlined by) __invoke_impl<void, esphome::web_server::WebServer::setup()::<lambda(int, char const*, char const*)>&, unsigned char, char const*, char const*> at /Users/bdraco/.platformio/packages/toolchain-xtensa-esp-elf/xtensa-esp-elf/include/c++/13.2.0/bits/invoke.h:61 (discriminator 1)
|
||||
(inlined by) __invoke_r<void, esphome::web_server::WebServer::setup()::<lambda(int, char const*, char const*)>&, unsigned char, char const*, char const*> at /Users/bdraco/.platformio/packages/toolchain-xtensa-esp-elf/xtensa-esp-elf/include/c++/13.2.0/bits/invoke.h:111 (discriminator 1)
|
||||
(inlined by) _M_invoke at /Users/bdraco/.platformio/packages/toolchain-xtensa-esp-elf/xtensa-esp-elf/include/c++/13.2.0/bits/std_function.h:290 (discriminator 1)
|
||||
WARNING Decoded 0x400f08c1: std::function<void (unsigned char, char const*, char const*)>::operator()(unsigned char, char const*, char const*) const at /Users/bdraco/.platformio/packages/toolchain-xtensa-esp-elf/xtensa-esp-elf/include/c++/13.2.0/bits/std_function.h:591
|
||||
(inlined by) esphome::CallbackManager<void (unsigned char, char const*, char const*)>::call(unsigned char, char const*, char const*) at /Users/bdraco/esphome/.esphome/build/ol/src/esphome/core/helpers.h:431
|
||||
WARNING Decoded 0x400f094d: esphome::logger::Logger::loop() at /Users/bdraco/esphome/.esphome/build/ol/src/esphome/components/logger/logger.cpp:188
|
||||
(inlined by) esphome::logger::Logger::loop() at /Users/bdraco/esphome/.esphome/build/ol/src/esphome/components/logger/logger.cpp:155
|
||||
WARNING Decoded 0x401a03ad: esphome::Component::call_loop() at /Users/bdraco/esphome/.esphome/build/ol/src/esphome/core/component.cpp:84
|
||||
WARNING Decoded 0x401a0461: esphome::Component::call() at /Users/bdraco/esphome/.esphome/build/ol/src/esphome/core/component.cpp:112
|
||||
WARNING Decoded 0x40101566: esphome::Application::loop() at /Users/bdraco/esphome/.esphome/build/ol/src/esphome/core/application.cpp:128
|
||||
WARNING Decoded 0x4010586a: loop() at /Users/bdraco/esphome/.esphome/build/ol/ol.yaml:1345
|
||||
WARNING Decoded 0x400e6f76: esphome::loop_task(void*) at /Users/bdraco/esphome/.esphome/build/ol/src/esphome/components/esp32/core.cpp:86 (discriminator 1)
|
||||
|
||||
|
||||
|
||||
|
||||
[17:53:14]ELF file SHA256: 009865893
|
||||
|
||||
[17:53:14]Rebooting...
|
||||
[17:53:14]ets Jul 29 2019 12:21:46
|
||||
|
||||
[17:53:14]rst:0xc (SW_CPU_RESET),boot:0x1b (SPI_FAST_FLASH_BOOT)
|
||||
[17:53:14]configsip: 0, SPIWP:0xee
|
||||
[17:53:14]clk_drv:0x00,q_drv:0x00,d_drv:0x00,cs0_drv:0x00,hd_drv:0x00,wp_drv:0x00
|
||||
[17:53:14]mode:DIO, clock div:2
|
||||
[17:53:14]load:0x3fff0030,len:6072
|
||||
[17:53:14]load:0x40078000,len:14960
|
||||
[17:53:14]load:0x40080400,len:4
|
@ -1,12 +1,140 @@
|
||||
#include "esphome/core/defines.h"
|
||||
#if defined(USE_ESP_IDF) && defined(USE_WEBSERVER_OTA)
|
||||
#include "multipart_parser_utils.h"
|
||||
#include "multipart.h"
|
||||
#include "parser_utils.h"
|
||||
#include "esphome/core/log.h"
|
||||
#include <cstring>
|
||||
#include "multipart_parser.h"
|
||||
|
||||
namespace esphome {
|
||||
namespace web_server_idf {
|
||||
|
||||
static const char *const TAG = "multipart";
|
||||
|
||||
// ========== MultipartReader Implementation ==========
|
||||
|
||||
MultipartReader::MultipartReader(const std::string &boundary) {
|
||||
// Initialize settings with callbacks
|
||||
memset(&settings_, 0, sizeof(settings_));
|
||||
settings_.on_header_field = on_header_field;
|
||||
settings_.on_header_value = on_header_value;
|
||||
settings_.on_part_data_begin = on_part_data_begin;
|
||||
settings_.on_part_data = on_part_data;
|
||||
settings_.on_part_data_end = on_part_data_end;
|
||||
settings_.on_headers_complete = on_headers_complete;
|
||||
|
||||
ESP_LOGV(TAG, "Initializing multipart parser with boundary: '%s' (len: %zu)", boundary.c_str(), boundary.length());
|
||||
|
||||
// Create parser with boundary
|
||||
parser_ = multipart_parser_init(boundary.c_str(), &settings_);
|
||||
if (parser_) {
|
||||
multipart_parser_set_data(parser_, this);
|
||||
} else {
|
||||
ESP_LOGE(TAG, "Failed to initialize multipart parser");
|
||||
}
|
||||
}
|
||||
|
||||
MultipartReader::~MultipartReader() {
|
||||
if (parser_) {
|
||||
multipart_parser_free(parser_);
|
||||
}
|
||||
}
|
||||
|
||||
size_t MultipartReader::parse(const char *data, size_t len) {
|
||||
if (!parser_) {
|
||||
ESP_LOGE(TAG, "Parser not initialized");
|
||||
return 0;
|
||||
}
|
||||
|
||||
size_t parsed = multipart_parser_execute(parser_, data, len);
|
||||
|
||||
if (parsed != len) {
|
||||
ESP_LOGW(TAG, "Parser consumed %zu of %zu bytes - possible error", parsed, len);
|
||||
}
|
||||
|
||||
return parsed;
|
||||
}
|
||||
|
||||
void MultipartReader::process_header_(const std::string &value) {
|
||||
// Process the completed header (field + value pair)
|
||||
if (str_startswith_case_insensitive(current_header_field_, "content-disposition")) {
|
||||
// Parse name and filename from Content-Disposition
|
||||
current_part_.name = extract_header_param(value, "name");
|
||||
current_part_.filename = extract_header_param(value, "filename");
|
||||
} else if (str_startswith_case_insensitive(current_header_field_, "content-type")) {
|
||||
current_part_.content_type = str_trim(value);
|
||||
}
|
||||
|
||||
// Clear field for next header
|
||||
current_header_field_.clear();
|
||||
}
|
||||
|
||||
int MultipartReader::on_header_field(multipart_parser *parser, const char *at, size_t length) {
|
||||
MultipartReader *reader = static_cast<MultipartReader *>(multipart_parser_get_data(parser));
|
||||
|
||||
// Store the header field name
|
||||
reader->current_header_field_.assign(at, length);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int MultipartReader::on_header_value(multipart_parser *parser, const char *at, size_t length) {
|
||||
MultipartReader *reader = static_cast<MultipartReader *>(multipart_parser_get_data(parser));
|
||||
|
||||
// Process the header immediately with the value
|
||||
std::string value(at, length);
|
||||
reader->process_header_(value);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int MultipartReader::on_headers_complete(multipart_parser *parser) {
|
||||
MultipartReader *reader = static_cast<MultipartReader *>(multipart_parser_get_data(parser));
|
||||
|
||||
ESP_LOGV(TAG, "Part headers complete: name='%s', filename='%s', content_type='%s'",
|
||||
reader->current_part_.name.c_str(), reader->current_part_.filename.c_str(),
|
||||
reader->current_part_.content_type.c_str());
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int MultipartReader::on_part_data_begin(multipart_parser *parser) {
|
||||
MultipartReader *reader = static_cast<MultipartReader *>(multipart_parser_get_data(parser));
|
||||
ESP_LOGV(TAG, "Part data begin");
|
||||
return 0;
|
||||
}
|
||||
|
||||
int MultipartReader::on_part_data(multipart_parser *parser, const char *at, size_t length) {
|
||||
MultipartReader *reader = static_cast<MultipartReader *>(multipart_parser_get_data(parser));
|
||||
|
||||
// Only process file uploads
|
||||
if (reader->has_file() && reader->data_callback_) {
|
||||
// IMPORTANT: The 'at' pointer points to data within the parser's input buffer.
|
||||
// This data is only valid during this callback. The callback handler MUST
|
||||
// process or copy the data immediately - it cannot store the pointer for
|
||||
// later use as the buffer will be overwritten.
|
||||
reader->data_callback_(reinterpret_cast<const uint8_t *>(at), length);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int MultipartReader::on_part_data_end(multipart_parser *parser) {
|
||||
MultipartReader *reader = static_cast<MultipartReader *>(multipart_parser_get_data(parser));
|
||||
|
||||
ESP_LOGV(TAG, "Part data end");
|
||||
|
||||
if (reader->part_complete_callback_) {
|
||||
reader->part_complete_callback_();
|
||||
}
|
||||
|
||||
// Clear part info for next part
|
||||
reader->current_part_ = Part{};
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// ========== Utility Functions ==========
|
||||
|
||||
// Case-insensitive string prefix check
|
||||
bool str_startswith_case_insensitive(const std::string &str, const std::string &prefix) {
|
||||
if (str.length() < prefix.length()) {
|
||||
@ -171,4 +299,4 @@ std::string str_trim(const std::string &str) {
|
||||
|
||||
} // namespace web_server_idf
|
||||
} // namespace esphome
|
||||
#endif // defined(USE_ESP_IDF) && defined(USE_WEBSERVER_OTA)
|
||||
#endif // defined(USE_ESP_IDF) && defined(USE_WEBSERVER_OTA)
|
@ -6,6 +6,8 @@
|
||||
#include <multipart_parser.h>
|
||||
#include <string>
|
||||
#include <functional>
|
||||
#include <cctype>
|
||||
#include <cstring>
|
||||
|
||||
namespace esphome {
|
||||
namespace web_server_idf {
|
||||
@ -63,6 +65,26 @@ class MultipartReader {
|
||||
void process_header_(const std::string &value);
|
||||
};
|
||||
|
||||
// ========== Utility Functions ==========
|
||||
|
||||
// Case-insensitive string prefix check
|
||||
bool str_startswith_case_insensitive(const std::string &str, const std::string &prefix);
|
||||
|
||||
// Find a substring case-insensitively
|
||||
size_t str_find_case_insensitive(const std::string &haystack, const std::string &needle, size_t pos = 0);
|
||||
|
||||
// Extract a parameter value from a header line
|
||||
// Handles both quoted and unquoted values
|
||||
std::string extract_header_param(const std::string &header, const std::string ¶m);
|
||||
|
||||
// Parse boundary from Content-Type header
|
||||
// Returns true if boundary found, false otherwise
|
||||
// boundary_start and boundary_len will point to the boundary value
|
||||
bool parse_multipart_boundary(const char *content_type, const char **boundary_start, size_t *boundary_len);
|
||||
|
||||
// Trim whitespace from both ends of a string
|
||||
std::string str_trim(const std::string &str);
|
||||
|
||||
} // namespace web_server_idf
|
||||
} // namespace esphome
|
||||
#endif // defined(USE_ESP_IDF) && defined(USE_WEBSERVER_OTA)
|
||||
#endif // defined(USE_ESP_IDF) && defined(USE_WEBSERVER_OTA)
|
@ -1,32 +0,0 @@
|
||||
#pragma once
|
||||
#include "esphome/core/defines.h"
|
||||
#if defined(USE_ESP_IDF) && defined(USE_WEBSERVER_OTA)
|
||||
|
||||
#include <string>
|
||||
#include <cctype>
|
||||
#include <cstring>
|
||||
|
||||
namespace esphome {
|
||||
namespace web_server_idf {
|
||||
|
||||
// Case-insensitive string prefix check
|
||||
bool str_startswith_case_insensitive(const std::string &str, const std::string &prefix);
|
||||
|
||||
// Find a substring case-insensitively
|
||||
size_t str_find_case_insensitive(const std::string &haystack, const std::string &needle, size_t pos = 0);
|
||||
|
||||
// Extract a parameter value from a header line
|
||||
// Handles both quoted and unquoted values
|
||||
std::string extract_header_param(const std::string &header, const std::string ¶m);
|
||||
|
||||
// Parse boundary from Content-Type header
|
||||
// Returns true if boundary found, false otherwise
|
||||
// boundary_start and boundary_len will point to the boundary value
|
||||
bool parse_multipart_boundary(const char *content_type, const char **boundary_start, size_t *boundary_len);
|
||||
|
||||
// Trim whitespace from both ends of a string
|
||||
std::string str_trim(const std::string &str);
|
||||
|
||||
} // namespace web_server_idf
|
||||
} // namespace esphome
|
||||
#endif // defined(USE_ESP_IDF) && defined(USE_WEBSERVER_OTA)
|
@ -1,136 +0,0 @@
|
||||
#include "esphome/core/defines.h"
|
||||
#if defined(USE_ESP_IDF) && defined(USE_WEBSERVER_OTA)
|
||||
#include "multipart_reader.h"
|
||||
#include "multipart_parser_utils.h"
|
||||
#include "esphome/core/log.h"
|
||||
#include <cstring>
|
||||
#include "multipart_parser.h"
|
||||
|
||||
namespace esphome {
|
||||
namespace web_server_idf {
|
||||
|
||||
static const char *const TAG = "multipart_reader";
|
||||
|
||||
MultipartReader::MultipartReader(const std::string &boundary) {
|
||||
// Initialize settings with callbacks
|
||||
memset(&settings_, 0, sizeof(settings_));
|
||||
settings_.on_header_field = on_header_field;
|
||||
settings_.on_header_value = on_header_value;
|
||||
settings_.on_part_data_begin = on_part_data_begin;
|
||||
settings_.on_part_data = on_part_data;
|
||||
settings_.on_part_data_end = on_part_data_end;
|
||||
settings_.on_headers_complete = on_headers_complete;
|
||||
|
||||
ESP_LOGV(TAG, "Initializing multipart parser with boundary: '%s' (len: %zu)", boundary.c_str(), boundary.length());
|
||||
|
||||
// Create parser with boundary
|
||||
parser_ = multipart_parser_init(boundary.c_str(), &settings_);
|
||||
if (parser_) {
|
||||
multipart_parser_set_data(parser_, this);
|
||||
} else {
|
||||
ESP_LOGE(TAG, "Failed to initialize multipart parser");
|
||||
}
|
||||
}
|
||||
|
||||
MultipartReader::~MultipartReader() {
|
||||
if (parser_) {
|
||||
multipart_parser_free(parser_);
|
||||
}
|
||||
}
|
||||
|
||||
size_t MultipartReader::parse(const char *data, size_t len) {
|
||||
if (!parser_) {
|
||||
ESP_LOGE(TAG, "Parser not initialized");
|
||||
return 0;
|
||||
}
|
||||
|
||||
size_t parsed = multipart_parser_execute(parser_, data, len);
|
||||
|
||||
if (parsed != len) {
|
||||
ESP_LOGW(TAG, "Parser consumed %zu of %zu bytes - possible error", parsed, len);
|
||||
}
|
||||
|
||||
return parsed;
|
||||
}
|
||||
|
||||
void MultipartReader::process_header_(const std::string &value) {
|
||||
// Process the completed header (field + value pair)
|
||||
if (str_startswith_case_insensitive(current_header_field_, "content-disposition")) {
|
||||
// Parse name and filename from Content-Disposition
|
||||
current_part_.name = extract_header_param(value, "name");
|
||||
current_part_.filename = extract_header_param(value, "filename");
|
||||
} else if (str_startswith_case_insensitive(current_header_field_, "content-type")) {
|
||||
current_part_.content_type = str_trim(value);
|
||||
}
|
||||
|
||||
// Clear field for next header
|
||||
current_header_field_.clear();
|
||||
}
|
||||
|
||||
int MultipartReader::on_header_field(multipart_parser *parser, const char *at, size_t length) {
|
||||
MultipartReader *reader = static_cast<MultipartReader *>(multipart_parser_get_data(parser));
|
||||
|
||||
// Store the header field name
|
||||
reader->current_header_field_.assign(at, length);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int MultipartReader::on_header_value(multipart_parser *parser, const char *at, size_t length) {
|
||||
MultipartReader *reader = static_cast<MultipartReader *>(multipart_parser_get_data(parser));
|
||||
|
||||
// Process the header immediately with the value
|
||||
std::string value(at, length);
|
||||
reader->process_header_(value);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int MultipartReader::on_headers_complete(multipart_parser *parser) {
|
||||
MultipartReader *reader = static_cast<MultipartReader *>(multipart_parser_get_data(parser));
|
||||
|
||||
ESP_LOGV(TAG, "Part headers complete: name='%s', filename='%s', content_type='%s'",
|
||||
reader->current_part_.name.c_str(), reader->current_part_.filename.c_str(),
|
||||
reader->current_part_.content_type.c_str());
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int MultipartReader::on_part_data_begin(multipart_parser *parser) {
|
||||
MultipartReader *reader = static_cast<MultipartReader *>(multipart_parser_get_data(parser));
|
||||
ESP_LOGV(TAG, "Part data begin");
|
||||
return 0;
|
||||
}
|
||||
|
||||
int MultipartReader::on_part_data(multipart_parser *parser, const char *at, size_t length) {
|
||||
MultipartReader *reader = static_cast<MultipartReader *>(multipart_parser_get_data(parser));
|
||||
|
||||
// Only process file uploads
|
||||
if (reader->has_file() && reader->data_callback_) {
|
||||
// IMPORTANT: The 'at' pointer points to data within the parser's input buffer.
|
||||
// This data is only valid during this callback. The callback handler MUST
|
||||
// process or copy the data immediately - it cannot store the pointer for
|
||||
// later use as the buffer will be overwritten.
|
||||
reader->data_callback_(reinterpret_cast<const uint8_t *>(at), length);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int MultipartReader::on_part_data_end(multipart_parser *parser) {
|
||||
MultipartReader *reader = static_cast<MultipartReader *>(multipart_parser_get_data(parser));
|
||||
|
||||
ESP_LOGV(TAG, "Part data end");
|
||||
|
||||
if (reader->part_complete_callback_) {
|
||||
reader->part_complete_callback_();
|
||||
}
|
||||
|
||||
// Clear part info for next part
|
||||
reader->current_part_ = Part{};
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
} // namespace web_server_idf
|
||||
} // namespace esphome
|
||||
#endif // defined(USE_ESP_IDF) && defined(USE_WEBSERVER_OTA)
|
@ -17,8 +17,7 @@
|
||||
#include "parser_utils.h"
|
||||
|
||||
#ifdef USE_WEBSERVER_OTA
|
||||
#include "multipart_reader.h"
|
||||
#include "multipart_parser_utils.h"
|
||||
#include "multipart.h"
|
||||
#endif
|
||||
|
||||
#ifdef USE_WEBSERVER
|
||||
|
Loading…
x
Reference in New Issue
Block a user