mirror of
				https://github.com/esphome/esphome.git
				synced 2025-10-31 07:03:55 +00:00 
			
		
		
		
	cleanup
This commit is contained in:
		| @@ -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" | #include "esphome/core/defines.h" | ||||||
| #if defined(USE_ESP_IDF) && defined(USE_WEBSERVER_OTA) | #if defined(USE_ESP_IDF) && defined(USE_WEBSERVER_OTA) | ||||||
| #include "multipart_parser_utils.h" | #include "multipart.h" | ||||||
| #include "parser_utils.h" | #include "parser_utils.h" | ||||||
| #include "esphome/core/log.h" | #include "esphome/core/log.h" | ||||||
|  | #include <cstring> | ||||||
|  | #include "multipart_parser.h" | ||||||
| 
 | 
 | ||||||
| namespace esphome { | namespace esphome { | ||||||
| namespace web_server_idf { | 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
 | // Case-insensitive string prefix check
 | ||||||
| bool str_startswith_case_insensitive(const std::string &str, const std::string &prefix) { | bool str_startswith_case_insensitive(const std::string &str, const std::string &prefix) { | ||||||
|   if (str.length() < prefix.length()) { |   if (str.length() < prefix.length()) { | ||||||
| @@ -6,6 +6,8 @@ | |||||||
| #include <multipart_parser.h> | #include <multipart_parser.h> | ||||||
| #include <string> | #include <string> | ||||||
| #include <functional> | #include <functional> | ||||||
|  | #include <cctype> | ||||||
|  | #include <cstring> | ||||||
| 
 | 
 | ||||||
| namespace esphome { | namespace esphome { | ||||||
| namespace web_server_idf { | namespace web_server_idf { | ||||||
| @@ -63,6 +65,26 @@ class MultipartReader { | |||||||
|   void process_header_(const std::string &value); |   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 web_server_idf
 | ||||||
| }  // namespace esphome
 | }  // 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" | #include "parser_utils.h" | ||||||
|  |  | ||||||
| #ifdef USE_WEBSERVER_OTA | #ifdef USE_WEBSERVER_OTA | ||||||
| #include "multipart_reader.h" | #include "multipart.h" | ||||||
| #include "multipart_parser_utils.h" |  | ||||||
| #endif | #endif | ||||||
|  |  | ||||||
| #ifdef USE_WEBSERVER | #ifdef USE_WEBSERVER | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user