Компонент HTTP Server предоставляет возможность запуска облегченного web-сервера на ESP32. Ниже приведены подробные инструкции по использованию API, предоставляемого HTTP-сервером:
httpd_start(): создает экземпляр HTTP-сервера, выделяет ему память/ресурсы в зависимости от заданной конфигурации и выдаёт дескриптор экземпляру сервера. На сервере имеется прослушивающий сокет (TCP) для HTTP-трафика и управляющий сокет (UDP) для управляющих сигналов, которые выбираются циклически (по алгоритму round robin) в цикле задач сервера (server task loop). Приоритет задачи сервера и размер её стека конфигурируются во время создания экземпляра сервера путем передачи структуры httpd_config_t в вызов httpd_start(). TCP-трафик обрабатывается как HTTP-запросы, и, в зависимости от запрошенного URI, вызываются зарегистрированные пользователем обработчики, которые должны отправлять HTTP-пакеты ответов.
httpd_stop(): остановит сервер по предоставленному дескриптору и освободит любые выделенные для него ресурсы и память. Это блокирующая функция, которая сначала сигнализирует halt для задачи сервера, и затем ждет завершения этой задачи. При остановке задача закрывает все открытые соединения, удаляет зарегистрированные обработчики URI и сбрасывает все данные контекста сеанса в пустое состояние.
httpd_register_uri_handler(): обработчик URI регистрируется передачей объекта типа структуры httpd_uri_t, в которой заполнены поля имя ссылки (uri name), тип метода (method type, например HTTP_GET/HTTP_POST/HTTP_PUT и т. п.), указатель на функцию типа esp_err_t *handler (httpd_req_t *req) и указатель user_ctx на пользовательские контекстные данные.
Для ESP HTTP-сервера URI это путь и параметры, которые определяют, какой обработчик должен выполниться.
Примеры URI для регистрации обработчиков:
// Обработчик для главной страницы URI: "/" Метод: GET
// Обработчик для получения данных датчика URI: "/api/temperature" Метод: GET
// Обработчик для отправки команд URI: "/api/control" Метод: POST
// Обработчик для статических файлов URI: "/images/*" Метод: GET
Структура URI:
https://example.com:8080/api/v1/users?id=123#section ┌────────────────────┬─────────────────────────┬────────────────┐ │ Часть │ Пример │ Роль | ├────────────────────┼─────────────────────────┼────────────────┤ │ Схема │ https:// │ Протокол │ │ Домен │ example.com │ Сервер │ │ Порт │ :8080 │ Порт сервера │ │ Путь (Path) │ /api/v1/users │ ✅ Это то, что │ │ │ │ обрабатывает │ │ │ │ ваш сервер! │ │ Параметры (Query) │ ?id=123 │ Доп. данные │ │ Фрагмент │ #section │ Якорь | └────────────────────┴─────────────────────────┴────────────────┘
Когда на ESP HTTP-сервере регистрируют URI-обработчики (handlers), тем самым говорят серверу:
> "Когда приходит HTTP-запрос с методом GET на путь `/api/data` — вызови вот эту мою функцию-обработчик"
URI в этом контексте это путь запроса, который определяет, какой код должен выполниться для обработки конкретного запроса. Т. е. URI — это "адрес" в вашем приложении, который определяет, какая логика должна выполниться.
[Примеры приложений]
Пример protocols/http_server/simple демонстрирует, как обрабатывать произвольные длины контента, читать заголовки запроса и параметры запроса URL, и устанавливать заголовки ответа.
Persistent Connections. HTTP-сервер поддерживает постоянные соединения (persistent connections), позволяющие повторно использовать одно и то же соединение (сессию) для нескольких транзакций, сохраняя при этом контекстно-зависимые данные сессии. Данные контекста могут быть выделены динамически обработчиком, и в этом случае может потребоваться указать специальную пользовательскую функцию для освобождения этих данных, когда соединение/сессия закрывается.
Пример Persistent Connections:
/* Пользовательская функция для освобождения контекста */ voidfree_ctx_func(void*ctx)
{ /* Какие-нибудь дополнительные действия, которые могут потребоваться для освобождения ресурсов */ free(ctx);
}
esp_err_tadder_post_handler(httpd_req_t*req)
{ /* Создание контекста сессии, если он еще недоступен */ if(!req->sess_ctx){ req->sess_ctx=malloc(sizeof(ANY_DATA_TYPE));/*!< Указатель на данные контекста */ req->free_ctx=free_ctx_func;/*!< Функция для освобождения данных контекста */ }
/* Доступ к данным контекста */ ANY_DATA_TYPE*ctx_data=(ANY_DATA_TYPE*)req->sess_ctx;
/* Ответ */ ............... ............... ...............
returnESP_OK;
}
См. пример в каталоге protocols/http_server/persistent_sockets. Этот пример демонстрирует, как настроить и использовать HTTP-сервер для persistent sockets, позволяя получить независимые сессии или контексты для каждого отдельного клиента.
WebSocket Server. Компонент HTTP-сервера предоставляет поддержку WebSocket. Фича WebSocket может быть разрешена в menuconfig с помощью опции CONFIG_HTTPD_WS_SUPPORT.
Пример protocols/http_server/ws_echo_server демонстрирует, как создать WebSocket echo-сервер, используя HTTP-сервер, который запускается в локальной сети и требует для взаимодействия клиента WebSocket, отправляя обратно в виде эха принятые кадры WebSocket.
Обработка ошибок. У ESP HTTP-сервера есть различные события, для которых библиотека Event Loop [2] может запустить обработчик при возникновении определённого события. Обработчик должен быть зарегистрирован с помощью esp_event_handler_register(). В перечислении esp_http_server_event_id_t обозначены все события, которые могут произойти для ESP HTTP-сервера.
/** * @brief Идентификаторы событий HTTP-сервера */ typedefenum{ HTTP_SERVER_EVENT_ERROR=0,/*!< Любая ошибка во время выполнения */ HTTP_SERVER_EVENT_START,/*!< При старте HTTP-сервера */ HTTP_SERVER_EVENT_ON_CONNECTED,/*!< Подключение клиента, без выполнения обмена данными */ HTTP_SERVER_EVENT_ON_HEADER,/*!< При получении каждого заголовка, отправленного клиентом */ HTTP_SERVER_EVENT_HEADERS_SENT,/*!< После отправки всех заголовков клиенту */ HTTP_SERVER_EVENT_ON_DATA,/*!< Когда приняты данные от клиента */ HTTP_SERVER_EVENT_SENT_DATA,/*!< Когда завершается сессия */ HTTP_SERVER_EVENT_DISCONNECTED,/*!< При разрыве соединения */ HTTP_SERVER_EVENT_STOP,/*!< При остановке HTTP-сервера */
}esp_http_server_event_id_t;
Ожидаемые типы данных для различных событий ESP HTTP-сервера, обрабатываемых в event loop:
HTTP_SERVER_EVENT_ERROR: httpd_err_code_t HTTP_SERVER_EVENT_START: NULL HTTP_SERVER_EVENT_ON_CONNECTED: int HTTP_SERVER_EVENT_ON_HEADER: int HTTP_SERVER_EVENT_HEADERS_SENT: int HTTP_SERVER_EVENT_ON_DATA: esp_http_server_event_data HTTP_SERVER_EVENT_SENT_DATA: esp_http_server_event_data HTTP_SERVER_EVENT_DISCONNECTED: int HTTP_SERVER_EVENT_STOP: NULL
Обслуживание файлов. Пример protocols/http_server/file_serving демонстрирует, как создать простой файловый сервер HTTP, с возможностью как выгрузки (upload), так и загрузки (download) файлов.
Captive Portal. Пример protocols/http_server/captive_portal демонстрирует два метода для создания портала захвата (captive portal), который направляет пользователей на страницу аутентификации перед посещением других страниц, используя либо DNS-запросы и перенаправление HTTP-запросов, либо современный метод, включающий поле в предложении DHCP.
Асинхронные обработчики. Пример protocols/http_server/async_handlers демонстрирует, как обрабатывать несколько долго выполняющихся запросов к HTTP-серверу, использующих разные URI для асинхронных запросов (asynchronous requests), быстрых запросов (quick requests) и главной страницы (index page).
RESTful API. Пример protocols/http_server/restful_server демонстрирует, как реализовать RESTful API сервер и HTTP-сервер с пользовательским интерфейсом браузера (frontend browser UI), а также разрабатывает несколько API для извлечения ресурсов, используя mDNS для парсинга доменного имени и развертывания web-страницы на хосте разработки (host PC) с помощью технологии семихостинга, или на SPI flash, или на карте SD.
URI-обработчики. HTTP-сервер позволяет вам регистрировать URI-обработчики для обработки разных HTTP-запросов. Каждый обработчик (URI handler) привязывается к определенному URI и HTTP-методу (GET, POST, и т. п.). Функция обработчика вызывается всякий раз, когда поступает запрос, соответствующий URI и методу.
Функция обработчика должна вернуть значение esp_err_t.
esp_err_tmy_uri_handler(httpd_req_t*req)
{ // Обработка запроса // ... // Возврат ESP_OK, если запрос был успешно обработан returnESP_OK;
// Возврат кода ошибки, чтобы закрыть соединение // return ESP_FAIL;
}
В этом примере функция-обработчик my_uri_handler обрабатывает запросы для URI /my_uri. Если обработчик вернул ESP_OK, то соединение остается открытым. Если обработчик возвратит любое другое значение, то соединение закрывается. Это поведение позволит приложению обслуживать закрытие соединения, основываясь на определенных событиях или условиях.
Этот файл заголовка может быть подключен директивой:
#include"esp_http_server.h"
Этот заголовочный файл является частью API, предоставляемого компонентом esp_http_server. Для декларации, что ваш компонент (а приложение это тоже компонент) зависит от esp_http_server, добавьте в свой CMakeLists.txt:
// Если сервер не запустился, то дескриптор server будет равен NULL returnserver;
}
Параметры:
config -- [in] Конфигурация для нового экземпляра сервера. handle -- [out] Дескриптор для нового созданного экземпляра сервера. == NULL в случае ошибки.
Возвращаемые значения:
ESP_OK: экземпляр сервера успешно создан ESP_ERR_INVALID_ARG: недопустимые аргументы (NULL в параметре config?) ESP_ERR_HTTPD_ALLOC_MEM: не получилось выделить память для экземпляра сервера ESP_ERR_HTTPD_TASK: не получилось запустить задачу сервера
Остановит web-сервер. Освобождается память/ресурсы, используемые экземпляром HTTP-сервера, и этот экземпляр удаляется. После удаления, дескриптор удаленного сервера больше не может использоваться для доступа к этому экземпляру.
Пример использования:
// Функция для остановки web-сервера voidstop_webserver(httpd_handle_tserver)
{ // Проверка, что дескриптор не NULL if(server!=NULL){ // Остановка httpd сервера httpd_stop(server); }
}
Переопределит функцию приема веб-сервера (по FD, файловому дескриптору сессии). Эта же функция используется для чтения пакетов HTTP-запросов.
Замечание: эта API-функция предполагается для вызова либо из контекста http-сессии, либо из API, где sockfd является допустимым параметром, либо из обработчика URI, где sockfd получен вызовом httpd_req_to_sockfd().
Параметры:
hd -- [in] дескриптор экземпляра сервера HTTPD. sockfd -- [in] Session socket FD (файловый дескриптор сокета сессии). recv_func -- [in] функция приема для установки в этой сессии.
Возвращаемые значения:
ESP_OK: замена успешно зарегистрирована. ESP_ERR_INVALID_ARG: Null-аргументы.
Переопределит функцию передачи web-сервера (по FD, файловому дескриптору сессии). Эта же функция используется для отправки ответа на любой HTTP-запрос.
Замечание: подразумевается, что эта API-функция вызывается либо из контекста http-сессии, либо из API, где sockfd является допустимым параметром, либо из обработчика URI, где sockfd получен вызовом httpd_req_to_sockfd().
Параметры:
hd -- [in] дескриптор экземпляра сервера HTTPD. sockfd -- [in] Session socket FD (файловый дескриптор сокета сессии). send_func -- [in] функция отправки для установки в этой сессии.
Возвращаемые значения:
ESP_OK: замена успешно зарегистрирована. ESP_ERR_INVALID_ARG: Null-аргументы.
Переопределение функции ожидания веб-сервера (по сеансовому FD). Эта функция переопределяет функцию ожидания веб-сервера. Используется для проверки наличия ожидающих байтов в сокете.
Замечание: эта API-функция подразумевается для вызова либо из контекста http-сессии, либо из API, где sockfd является допустимым параметром, либо из URI-обработчика, где sockfd получен вызовом httpd_req_to_sockfd().
Параметры:
hd -- [in] дескриптор экземпляра сервера HTTPD. sockfd -- [in] Session socket FD (файловый дескриптор сокета сессии). pending_func -- [in] функция ожидания для установки в этой сессии.
Возвращаемые значения:
ESP_OK: замена успешно зарегистрирована. ESP_ERR_INVALID_ARG: Null-аргументы.
Запустит асинхронный запрос. Эта функция может быть вызвана в обработчике запроса, чтобы получить копию запроса, которая может использоваться в асинхронном потоке (async thread).
Пометит асинхронный запрос как завершенный. Этот вызов:
● Освободит память запроса. ● Отказывается от владения нижележащим сокетом, чтобы его можно было использовать повторно. ● Позволит http-серверу закрыть наш сокет при необходимости (lru_purge_enable).
Замечание: если асинхронные запросы не помечаются как завершенные, то иногда сервер не сможет принимать входящие соединения. В этом случае сервер будет выводить в лог сообщение об ошибке "httpd_accept_conn: error in accept (23)".
Параметры:
r -- [in] Запрос пометки асинхронной работы как завершенной.
Возвращаемое значение ESP_OK: асинхронный запрос был помечен как завершенный.
Получение дескриптора сокета (Socket Descriptor) из HTTP-запроса.
Эта API-функция возвратит дескриптор сокета сессии, для которой был выполнен URI-обработчик на приеме HTTP-запроса. Это полезно, когда пользователь хочет вызвать функции, которые требуют файловый дескриптор сессии (socket fd) сессии, из URI-обработчика, например: httpd_sess_get_ctx(), httpd_sess_trigger_close(), httpd_sess_update_lru_counter().
Замечание: предполагается, что эта API-функция вызывается только из контекста URI-обработчика, где httpd_req_t* допустимый указатель запроса.
Параметры:
r -- [in] Запрос, дескриптор сокета которого необходимо найти.
Возвращаемые значения:
Дескриптор сокета: socket descriptor для этого запроса. -1: недопустимый/NULL указатель запроса.
API для чтения данных содержимого из HTTP-запроса.
Эта функция прочитает данные содержимого запроса (HTTP content data) в предоставленный буфер buf. Используйте поле content_len структуры httpd_req_t, чтобы узнать длину извлекаемых данных. Если content_len слишком большое для буфера, то пользователь может сделать несколько вызов этой функции, каждый раз извлекая buf_len байт, при этом указатель на данные содержимого внутренне инкрементируется на это же значение.
Замечания:
● Предполагается, что эта API-функция вызывается только из контекста URI-обработчика, где httpd_req_t* является допустимым указателем запроса. ● Если возвращается ошибка, обработчик URI должен далее вернуть ошибку. Это гарантирует, что ошибочный сокет будет закрыт и очищен веб-сервером. ● В настоящее время Chunked Encoding не поддерживается (см. врезку ниже).
Параметры:
r -- [in] Запрос, на который формируется ответ. buf -- [in] Указатель на буфер, куда должны быть прочитаны данные. buf_len -- [in] Длина предоставленного буфера.
Возвращаемые значения:
N: количество байт, успешно прочитанных в буфер. 0: параметр длины буфера 0, или соединение закрыто на удаленной стороне. HTTPD_SOCK_ERR_INVALID: недопустимые аргументы. HTTPD_SOCK_ERR_TIMEOUT: таймаут/прервано при вызове socket recv(). HTTPD_SOCK_ERR_FAIL: не восстановимая ошибка при вызове socket recv().
"В настоящее время Chunked Encoding не поддерживается" означает, что в настоящее время HTTP-сервер не поддерживает механизм передачи данных по частям (chunked encoding).
[Что такое Chunked Encoding]
Chunked Transfer Encoding — метод передачи HTTP-данных, при котором тело ответа или запроса разбивается на отдельные "чанки" (куски). Каждый чанк имеет свой размер и передается отдельно.
[Как работает Chunked Encoding]
Обычная передача:
Content-Length: 245 [все 245 байт данных сразу]
Chunked Encoding:
Transfer-Encoding: chunked
5 Hello 6 World 0
- `5` — размер первого чанка (5 байт) - `Hello` — данные первого чанка - `6` — размер второго чанка (6 байт) - ` World` — данные второго чанка - `0` — маркер окончания передачи
[Что это значит для ESP HTTP-сервера]
Ограничения:
1. Только фиксированный размер: сервер ожидает, что клиент укажет точный размер данных в заголовке `Content-Length`. 2. Нет потоковой передачи: нельзя передавать данные по частям без знания общего размера. 3. Все данные сразу: необходимо знать полный размер данных до начала передачи.
Пример проблемы:
// Если клиент отправит запрос с Transfer-Encoding: chunked // httpd_req_recv() не сможет его корректно обработать
esp_err_tmy_handler(httpd_req_t*req)
{ charbuf[100]; intret=httpd_req_recv(req,buf,sizeof(buf)); // При chunked encoding это может работать некорректно
}
[Практические последствия]
Что МОЖЕТ ESP HTTP сервер: - Принимать запросы с заголовком `Content-Length` - Читать данные известного размера через `httpd_req_recv()` - Обрабатывать статические файлы известного размера
Что НЕ МОЖЕТ ESP HTTP сервер: - Принимать данные в потоковом режиме (например, видеостриминг) - Обрабатывать запросы, где размер данных неизвестен заранее - Работать с некоторыми типами прокси и клиентов, использующих chunked encoding
[Обходные пути]
Если нужно передавать данные неизвестного размера, можно:
1. Использовать другой протокол: WebSockets, MQTT 2. Буферизировать данные: сначала собрать все данные, потом отправить с `Content-Length` 3. Использовать multipart/form-data: для загрузки файлов
[Почему это важно]
Если клиент отправит запрос с `Transfer-Encoding: chunked`, то ESP HTTP-сервер:
- Не поймет формат данных - Вернет ошибку при чтении - Закроет соединение (как рекомендует документация)
Поиск поля в заголовках запроса и возврат длины строки его значения.
Замечания:
● Предполагается, что эта API-функция вызывается только из контекста URI-обработчика, где httpd_req_t* это допустимый указатель запроса. ● Как только была вызвана API-функция httpd_resp_send(), все заголовки запроса выпиливаются, так что они должны быть копированы в отдельные буфера, если их данные могут потребоваться позже.
Параметры:
r -- [in] Запрос, на который формируется ответ. field -- [in] Полез заголовка, которое ищется в запросе.
Возвращаемые значения:
Длина: если поле найдено в URL запроса. 0: поле не найдено / недопустимый запрос / Null-аргументы.
Получение значения строки поля из заголовков запроса.
Замечания:
● Предполагается, что эта API-функция вызывается только из контекста URI-обработчика, где httpd_req_t* это допустимый указатель запроса. ● Как только была вызвана API-функция httpd_resp_send(), все заголовки запроса выпиливаются, так что они должны быть копированы в отдельные буфера, если их данные могут потребоваться позже. ● Если размер выходных данных больше, чем входной буфер, то значение обрезается с сопровождением кода ошибки обрезки в возвращаемом значении. ● Используйте httpd_req_get_hdr_value_len(), чтобы узнать правильную длину буфера.
Параметры:
r -- [in] Запрос, на который формируется ответ. field -- [in] Поле, которое ищется в заголовке. val -- [out] Указатель на буфер, куда копируется значение поля, если это поле найдено. val_size -- [in] Размер пользовательского буфера "val".
Возвращаемые значения:
ESP_OK: поле найдено в заголовке запроса, и его значение было скопировано в буфер val. ESP_ERR_NOT_FOUND: поле не найдено. ESP_ERR_INVALID_ARG: Null-аргументы. ESP_ERR_HTTPD_INVALID_REQ: недопустимый указатель HTTP-запроса. ESP_ERR_HTTPD_RESULT_TRUNC: строка значения была обрезана.
● В настоящее время пользователь может извлечь полную строку запроса URL, но её декодирование он должен выполнить самостоятельно. Заголовки запроса можно прочитать с помощью httpd_req_get_hdr_value_str(), чтобы узнать 'Content-Type' (например Content-Type: application/x-www-form-urlencoded), тогда нужно применить подходящий алгоритм декодирования. ● Подразумевается, что эта API-функция вызывается только из контекста URI-обработчика, где указатель запроса httpd_req_t* достоверный. ● Если выходной размер больше входного буфера, то значение строки обрезается, сопровождаясь соответствующим кодом ошибки в возвращаемом значении. ● Перед вызовом этой функции можно сделать вызов httpd_req_get_url_query_len(), чтобы предварительно узнать длину строки запроса, и по этой длине выделить буфер правильного размера (обычно этот размер равен длине строки запроса + 1 для байта null-терминатора) для сохранения строки запроса.
Параметры:
r -- [in] Запрос, на который формируется ответ. buf -- [out] Указатель на буфер, куда будет копироваться строка запроса (если она найдена). buf_len -- [in] Длина выходного буфера.
Возвращаемые значения:
ESP_OK: запрос найден в URL-адресе запроса и скопирован в буфер. ESP_FAIL: uri пуст. ESP_ERR_NOT_FOUND: запрос не найден. ESP_ERR_INVALID_ARG: Null-аргументы. ESP_ERR_HTTPD_INVALID_REQ: недопустимый указатель HTTP-запроса. ESP_ERR_HTTPD_RESULT_TRUNC: строка запроса обрезана.
Вспомогательная функция для получения тега URL-запроса из строки запроса типа param1=val1¶m2=val2.
Замечания:
● Компоненты строки запроса (ключи и значения) не декодированы (not URLdecoded). Пользователь должен проверить поле 'Content-Type' в заголовках запроса, и затем в зависимости от указанного кодирования (URLencoded или что-то другое) применить подходящий алгоритм декодирования. ● Если фактическая длина значения больше, чем val_size, то значение будет обрезано, сопровождаясь соответствующим кодом ошибки возвращаемого значения.
Параметры:
qry -- [in] Указатель на строку запроса. key -- [in] Ключ, который ищется в строке запроса. val -- [out] Указатель на буфер, в который должно быть помещено значение, если ключ key найден. val_size -- [in] Размер буфера пользователя val.
Возвращаемые значения:
ESP_OK: ключ найден в строке URL-запроса, и его значение было скопировано в буфер. ESP_ERR_NOT_FOUND: ключ не найден. ESP_ERR_INVALID_ARG: Null-аргументы. ESP_ERR_HTTPD_RESULT_TRUNC: строка значения была обрезана.
Получит строку значения cookie-файла из заголовков запроса «Cookie» по имени cookie.
Параметры:
req -- [in] Указатель на HTTP-запрос. cookie_name -- [in] Имя cookie, которое ищется в запросе. val -- [out] Указатель на буфер, в который значение cookie будет копироваться, если cookie найден. val_size -- [inout] Указатель на размер буфера пользователя val. Эта переменная будет содержать длину cookie, если возвращаемое значение ESP_OK, и требуемую длину буфера, если возвращаемое значение ESP_ERR_HTTPD_RESULT_TRUNC.
Возвращаемые значения:
ESP_OK: ключ найден в строке cookie, и значение скопировано в буфер. ESP_ERR_NOT_FOUND: ключ не найден. ESP_ERR_INVALID_ARG: Null-аргументы. ESP_ERR_HTTPD_RESULT_TRUNC: значение строки обрезано. ESP_ERR_NO_MEM: ошибка выделения памяти.
Проверка, соответствует ли URI предоставленному шаблону wildcard.
Шаблон может оканчиваться на '?' чтобы сделать предыдущий символ опциональным (обычно слеш), '*' для совпадения wildcard, и '?*' чтобы сделать предыдущий символ опциональным, и обеспечить совпадение, если что-то идет дальше.
Примеры:
* совпадет с любым значением. /api/? совпадет с /api и /api/ /api/* (без backslash) совпадет с /api/ и /api/status, но не с /api или /ap /api/?* или /api/*? (без backslash) совпадет с /api/, /api/status, а также /api, но не с /apix или /ap
Специальные символы '?' и '*' в любом месте шаблона будут восприниматься буквально.
Параметры:
uri_template -- [in] URI template (шаблон) uri_to_match -- [in] URI для проверки на совпадение match_upto -- [in] сколько символов в буфере URI проверять (может быть завершающая строка запроса, и т. п.)
Возвращаемое значение: true если было обнаружено совпадение.
Отправит данные в качестве HTTP-ответа на запрос. Подразумевается, что вы подготовили полный готовый запрос в одном буфере. Если вы хотите послать ответ последовательными кусками, то используйте вместо этого httpd_resp_send_chunk().
Если код статуса и тип содержимого не были заданы, по умолчанию будет отправлен код статуса 200 OK и тип содержимого как text/html. Вы можете вызвать следующие функции перед этим API для настройки заголовков ответа: httpd_resp_set_status() — для установки строки статуса HTTP, httpd_resp_set_type() — для установки типа содержимого, httpd_resp_set_hdr() — для добавления любых дополнительных значений полей в заголовок ответа.
Замечания:
● Подразумевается, что эта API-функция вызывается только из контекста URI-обработчика, где указатель запроса httpd_req_t* достоверный. ● После вызова этой API-функции на запрос выдается ответ. ● Никаких дополнительных данных не может быть отправлено для запроса. ● После вызова этой API-функции все заголовки запроса выпиливаются, так что необходимо их предварительно копировать в отдельные буферы, если они позже могут понадобиться.
Параметры:
r -- [in] Запрос, на который посылается ответ. buf -- [in] Буфер, из которого извлекается содержимое. buf_len -- [in] Длина буфера, HTTPD_RESP_USE_STRLEN для использования strlen().
Возвращаемые значения:
ESP_OK: пакет ответа успешно отправлен. ESP_ERR_INVALID_ARG: Null в указателе на запрос. ESP_ERR_HTTPD_RESP_HDR: необходимые заголовки слишком велики для внутреннего буфера. ESP_ERR_HTTPD_RESP_SEND: ошибка при отправке необработанных данных. ESP_ERR_HTTPD_INVALID_REQ: недопустимый запрос.
Эта API-функция отправит данные в качестве HTTP-ответа на запрос. Будет использоваться кодирование по частям и отправка ответа в виде фрагментов. Если весь ответ находится в одном буфере, используйте вместо этого функцию httpd_resp_send().
Если код статуса и тип контента не заданы, по умолчанию будут отправлены код статуса 200 OK и тип контента в формате text/html. Для настройки заголовков ответа перед этим API можно вызвать следующие функции: httpd_resp_set_status() — для установки строки статуса HTTP, httpd_resp_set_type() — для установки типа контента, httpd_resp_set_hdr() — для добавления любых дополнительных значений полей в заголовок ответа.
Замечания:
● Подразумевается, что эта API-функция вызывается только из контекста URI-обработчика, где указатель запроса httpd_req_t* достоверный. ● Когда вы завершили отправку всех ваших фрагментов ответа на запрос, то необходимо вызвать эту функцию, где в параметре buf_len указан 0. ● После вызова этой API-функции все заголовки запроса выпиливаются, так что необходимо их предварительно копировать в отдельные буферы, если они позже могут понадобиться.
Параметры:
r -- [in] Запрос, на который посылается ответ. buf -- [in] Указатель на буфер, где сохранены данные. buf_len -- [in] Длина буфера, HTTPD_RESP_USE_STRLEN для использования strlen().
Возвращаемые значения:
ESP_OK: был успешно отправлен фрагмент ответа. ESP_ERR_INVALID_ARG: Null в указателе на запрос. ESP_ERR_HTTPD_RESP_HDR: необходимые заголовки слишком велики для внутреннего буфера. ESP_ERR_HTTPD_RESP_SEND: ошибка при отправке необработанных данных. ESP_ERR_HTTPD_INVALID_REQ: недопустимый запрос.
API для отправки строки в качестве фрагмента HTTP-ответа.
Эта API-функция просто вызовет httpd_resp_send_chunk с длиной буфера, установленной на длину строки. Подразумевается, что строка в буфере содержит байт null-терминатора.
Параметры:
r -- [in] Запрос, на который посылается ответ. str -- [in] Строка для отправки в теле ответа (NULL для завершения пакета ответа).
Возвращаемые значения:
ESP_OK: при успешной отправке пакета ответа. ESP_ERR_INVALID_ARG: Null в указателе на запрос. ESP_ERR_HTTPD_RESP_HDR: необходимые заголовки слишком велики для внутреннего буфера. ESP_ERR_HTTPD_RESP_SEND: ошибка при отправке необработанных данных. ESP_ERR_HTTPD_INVALID_REQ: недопустимый запрос.
Эта API-функция установит статус HTTP-ответа в указанное значение. По умолчанию посылается '200 OK' в качестве ответа.
Замечания:
● Подразумевается, что эта API-функция вызывается только из контекста URI-обработчика, где указатель запроса httpd_req_t* достоверный. ● Эта функция только устанавливает статус в указанное значение. Этот статус не будет отправлен, пока не будет выполнена API-функция отправки. ● Обеспечьте достоверность буфера status до возврата из функции отправки.
Параметры:
r -- [in] Запрос, на который формируется ответ. status -- [in] Код статуса HTTP для ответа.
Возвращаемые значения:
ESP_OK: при успехе. ESP_ERR_INVALID_ARG: Null-аргументы. ESP_ERR_HTTPD_INVALID_REQ: недопустимый указатель на запрос.
API для установки типа контента (HTTP content type).
Эта API-функция установит поле 'Content Type' ответа на запрос. По умолчанию content type 'text/html'.
Замечания:
● Подразумевается, что эта API-функция вызывается только из контекста URI-обработчика, где указатель запроса httpd_req_t* достоверный. ● Эта функция только устанавливает тип контента в указанное значение. Этот статус не будет отправлен, пока не будет выполнена API-функция отправки. ● Обеспечьте достоверность буфера строки type до возврата из функции отправки.
Параметры:
r -- [in] Запрос, на который формируется ответ. type -- [in] Content Type ответа.
Возвращаемые значения:
ESP_OK: при успехе. ESP_ERR_INVALID_ARG: Null-аргументы. ESP_ERR_HTTPD_INVALID_REQ: недопустимый указатель на запрос.
API для добавления любых дополнительных заголовков.
Эта API-функция установит поля дополнительного заголовка, который необходимо послать в ответе на запрос.
Замечания:
● Подразумевается, что эта API-функция вызывается только из контекста URI-обработчика, где указатель запроса httpd_req_t* достоверный. ● Заголовок не будет отправлен, пока не будет выполнена API-функция отправки. ● Максимальное допустимое количество дополнительных заголовков ограничвается значением max_resp_headers в структуре config. ● Обеспечьте достоверность буфера строк field и value до возврата из функции отправки.
Параметры:
r -- [in] Запрос, на который формируется ответ. field -- [in] Имя поля в заголовке HTTP. value -- [in] Значение этого заголовка HTTP.
Возвращаемые значения:
ESP_OK: успешно присоединен новый заголовок. ESP_ERR_INVALID_ARG: Null-аргументы. ESP_ERR_HTTPD_RESP_HDR: общее количество дополнительных заголовков превысило допустимое значение. ESP_ERR_HTTPD_INVALID_REQ: недопустимый указатель на запрос.
Функция для отправки кода ошибки в ответе на HTTP-запрос.
Замечания:
● Подразумевается, что эта API-функция вызывается только из контекста URI-обработчика, где указатель запроса httpd_req_t* достоверный. ● Как только вызвана эта API-функция, все заголовки запроса выпиливаются, так что они должны быть скопированы в отдельный буфер, если понадобятся впоследствии. ● Если вы хотите послать дополнительные данные в теле ответа, то напрямую используйте низкоуровневые функции.
Параметры:
req -- [in] Указатель на HTTP-запрос, для которого надо послать ответ. error -- [in] Тип отправляемой ошибки. msg -- [in] Строка сообщения об ошибке (передайте NULL для отправки сообщения по умолчанию).
Возвращаемые значения:
ESP_OK: был успешно отправлен пакет ответа. ESP_ERR_INVALID_ARG: Null-аргументы. ESP_ERR_HTTPD_RESP_SEND: ошибка при отправке необработанных данных. ESP_ERR_HTTPD_INVALID_REQ: недопустимый запрос.
API-функция для отправки пользовательского кода ошибки в ответ на HTTP-запрос.
Замечания:
● Подразумевается, что эта API-функция вызывается только из контекста URI-обработчика, где указатель запроса httpd_req_t* достоверный. ● Как только вызвана эта API-функция, все заголовки запроса выпиливаются, так что они должны быть скопированы в отдельный буфер, если понадобятся впоследствии. ● Если вы хотите послать дополнительные данные в теле ответа, то напрямую используйте низкоуровневые функции.
Параметры:
req -- [in] Указатель на HTTP-запрос, для которого надо послать ответ. status -- [in] Статус ошибки для отправки. msg -- [in] Строка сообщения об ошибке.
Возвращаемые значения:
ESP_OK: был успешно отправлен пакет ответа. ESP_ERR_INVALID_ARG: Null-аргументы. ESP_ERR_HTTPD_RESP_SEND: ошибка при отправке необработанных данных. ESP_ERR_HTTPD_INVALID_REQ: недопустимый запрос.
Отправит сообщение об ошибке HTTP 404. Если вы хотите послать дополнительные данные в теле ответа, то напрямую используйте низкоуровневые функции.
Замечания:
● Подразумевается, что эта API-функция вызывается только из контекста URI-обработчика, где указатель запроса httpd_req_t* достоверный. ● Как только вызвана эта API-функция, все заголовки запроса выпиливаются, так что они должны быть скопированы в отдельный буфер, если понадобятся впоследствии.
Параметры:
r -- [in] Указатель на HTTP-запрос, для которого надо послать ответ.
Возвращаемые значения:
ESP_OK: был успешно отправлен пакет ответа. ESP_ERR_INVALID_ARG: Null-аргументы. ESP_ERR_HTTPD_RESP_SEND: ошибка при отправке необработанных данных. ESP_ERR_HTTPD_INVALID_REQ: недопустимый запрос.
Отправит сообщение об ошибке HTTP 408. Если вы хотите послать дополнительные данные в теле ответа, то напрямую используйте низкоуровневые функции.
Замечания:
● Подразумевается, что эта API-функция вызывается только из контекста URI-обработчика, где указатель запроса httpd_req_t* достоверный. ● Как только вызвана эта API-функция, все заголовки запроса выпиливаются, так что они должны быть скопированы в отдельный буфер, если понадобятся впоследствии.
Параметры:
r -- [in] Указатель на HTTP-запрос, для которого надо послать ответ.
Возвращаемые значения:
ESP_OK: был успешно отправлен пакет ответа. ESP_ERR_INVALID_ARG: Null-аргументы. ESP_ERR_HTTPD_RESP_SEND: ошибка при отправке необработанных данных. ESP_ERR_HTTPD_INVALID_REQ: недопустимый запрос.
Отправит сообщение об ошибке HTTP 500. Если вы хотите послать дополнительные данные в теле ответа, то напрямую используйте низкоуровневые функции.
Замечания:
● Подразумевается, что эта API-функция вызывается только из контекста URI-обработчика, где указатель запроса httpd_req_t* достоверный. ● Как только вызвана эта API-функция, все заголовки запроса выпиливаются, так что они должны быть скопированы в отдельный буфер, если понадобятся впоследствии.
Параметры:
r -- [in] Указатель на HTTP-запрос, для которого надо послать ответ.
Возвращаемые значения:
ESP_OK: был успешно отправлен пакет ответа. ESP_ERR_INVALID_ARG: Null-аргументы. ESP_ERR_HTTPD_RESP_SEND: ошибка при отправке необработанных данных. ESP_ERR_HTTPD_INVALID_REQ: недопустимый запрос.
Вызовите эту API-функцию, если хотите сами сконструировать свой пакет ответа. При использовании этого метода все основные заголовки, например HTTP version, Status Code, Content Type и Length, Encoding, и т. д. придется создавать вручную, а разделители HTTP (CRLF) необходимо будет правильно разместить для разделения подразделов пакета ответа HTTP.
Если установлена функция переопределения отправки, то в конечном итоге будет вызвана эта функция для отправки данных.
Замечания:
● Подразумевается, что эта API-функция вызывается только из контекста URI-обработчика, где указатель запроса httpd_req_t* достоверный. ● Если ответ не имеет корректной HTTP-структуры (что теперь в зоне ответственности пользователя), то нет гарантии, что он будет распознан клиентом. В большинстве случаев вам не придётся вызывать этот API, так что лучше использовать один из следующих методов: httpd_resp_send() или httpd_resp_send_chunk().
Параметры:
r -- [in] Запрос, на который формируется ответ. buf -- [in] Буфер, откуда вычитывается полный пакет, сконструированный пользователем. buf_len -- [in] Длина буфера.
Возвращаемые значения:
Bytes: количество успешно отправленных байт. HTTPD_SOCK_ERR_INVALID: недопустимые аргументы. HTTPD_SOCK_ERR_TIMEOUT: таймаут/прервано при вызове socket send(). HTTPD_SOCK_ERR_FAIL: невосстановимая ошибка при вызове socket send().
Низкоуровневый API для отправки данных на предоставленном сокете.
Эта функция внутренне вызывает функцию отправки по умолчанию, или функцию, зарегистрированную httpd_sess_set_send_override().
Замечание: не рекомендуется использовать это API в любом обработчике запроса. Эта API-функция предназначена для особых продвинутых случаев, когда некоторые асинхронные данные необходимо передать через сокет.
Параметры:
hd -- [in] экземпляр сервера. sockfd -- [in] файловый дескриптор сокета сессии. buf -- [in] буфер с байтами для отправки. buf_len -- [in] размер отправляемых данных. flags -- [in] флаги для функции send().
Возвращаемые значения:
Bytes: количество успешно отправленных байт. HTTPD_SOCK_ERR_INVALID: недопустимые аргументы. HTTPD_SOCK_ERR_TIMEOUT: таймаут/прервано при вызове socket send(). HTTPD_SOCK_ERR_FAIL: невосстановимая ошибка при вызове socket send().
Низкоуровневый API для приема данных из предоставленного сокета.
Эта функция внутренне вызывает функцию приема по умолчанию, или функцию, зарегистрированную httpd_sess_set_recv_override().
Замечание: не рекомендуется использовать это API в любом обработчике запроса. Эта API-функция предназначена для особых продвинутых случаев, когда требуется некая асинхронная коммуникация.
Параметры:
hd -- [in] экземпляр сервера. sockfd -- [in] файловый дескиптор сокета сессии. buf -- [in] буфер для приема данных. buf_len -- [in] размер буфера. flags -- [in] флаги для функции recv().
Возвращаемые значения:
Bytes: количество успешно принятых байт. 0: нулевой параметр длины буфера или соединение закрыто на удаленной стороне. HTTPD_SOCK_ERR_INVALID: недопустимые аргументы. HTTPD_SOCK_ERR_TIMEOUT: таймаут/прервано при вызове socket recv(). HTTPD_SOCK_ERR_FAIL: невосстановимая ошибка при вызове socket recv().
Функция для регистрации обработчиков ошибок (HTTP error handlers).
Эта функция привязывает функцию обработчика к любому поддерживаемому коду ошибки httpd_err_code_t. См. далее описание прототипа функции httpd_err_handler_func_t.
Параметры:
handle -- [in] дескриптор сервера HTTP. error -- [in] тип ошибки. handler_fn -- [in] реализованная пользователем функция обработчика (передайте здесь NULL для снятия ранее установленного обработчика).
Возвращаемые значения:
ESP_OK: обработчик был успешно зарегистрирован. ESP_ERR_INVALID_ARG: недопустимый код ошибки или дескриптор сервера.
Замечание: вызов httpd_ws_recv_frame() с max_len == 0 выдаст фактический размер кадра в pkt->len. Пользователь может динамически выделить пространство для pkt->payload на эту длину, и еще раз вызвать httpd_ws_recv_frame() для получения реальных данных. См. соответствующий пример для использования.
Параметры:
req -- [in] текущий запрос. pkt -- [out] пакет WebSocket. max_len -- [in] максимальная длина для приема.
Возвращаемые значения:
ESP_OK: при успехе. ESP_FAIL: произошли ошибки сокета. ESP_ERR_INVALID_STATE: рукопожатие уже было сделано заранее. ESP_ERR_INVALID_ARG: недопустимый аргумент (null или non-WebSocket).
ESP_OK: при успехе. ESP_FAIL: произошли ошибки сокета. ESP_ERR_INVALID_STATE: рукопожатие уже было сделано заранее. ESP_ERR_INVALID_ARG: недопустимый аргумент (null или non-WebSocket).
Низкоуровневая отправка кадра WebSocket вне области текущего запроса с использованием внутренне настроенной функции отправки httpd.
Этот API редко следует вызывать напрямую, за исключением асинхронной отправки с использованием httpd_queue_work.
Параметры:
hd -- [in] данные экземпляра сервера. fd -- [in] дескриптор сокета для отправки данных. frame -- [in] кадр WebSocket.
Возвращаемые значения:
ESP_OK: при успехе. ESP_FAIL: произошли ошибки сокета. ESP_ERR_INVALID_STATE: рукопожатие уже было сделано заранее. ESP_ERR_INVALID_ARG: недопустимый аргумент (null или non-WebSocket).
Проверяет предоставленный дескриптор сокета, принадлежит ли он какому-либо активному клиенту данного экземпляра сервера и активен ли протокол websoket.
Параметры:
hd -- [in] данные экземпляра сервера. fd -- [in] дескриптор сокета.
Возвращаемые значения:
HTTPD_WS_CLIENT_INVALID: этот fd не клиент этого httpd. HTTPD_WS_CLIENT_HTTP: этот fd активный клиент, протокол не WS. HTTPD_WS_CLIENT_WEBSOCKET: этот fd активный клиент, протокол WS.
Регистрирует URI-обработчик. Пример использования:
esp_err_tmy_uri_handler(httpd_req_t*req)
{ // Прием, обработка и отправка .... .... ....
// Обработка ситуации ошибки if(....){ // Возврат ошибки для закрытия сессии returnESP_FAIL; }
// При успехе returnESP_OK;
}
// Структура URI-обработчика
httpd_uri_tmy_uri{ .uri="/my_uri/path/xyz", .method=HTTP_GET, .handler=my_uri_handler, .user_ctx=NULL
};
// Регистрация обработчика if(httpd_register_uri_handler(server_handle,&my_uri)!=ESP_OK){ // Если произошла ошибка регистрации обработчика ....
}
Замечание: URI-обработчики могут быть зарегистрированы во время выполнения (real time) пока достоверен дескриптор сервера.
Параметры:
handle -- [in] дескриптор экземпляра сервера HTTPD. uri_handler -- [in] указатель на обработчик, который должен быть зарегистрирован.
Возвращаемые значения:
ESP_OK: обработчик успешно зарегистрирован. ESP_ERR_INVALID_ARG: Null-аргументы. ESP_ERR_HTTPD_HANDLERS_FULL: если не осталось слотов для нового обработчика. ESP_ERR_HTTPD_HANDLER_EXISTS: если у обработчика такой же URI и метод уже зарегистрирован.
Отменит все URI-обработчики с указанной строкой uri.
Параметры:
handle -- [in] дескриптор экземпляра сервера HTTPD. uri -- [in] строка URI, указывающая все обработчики, которые должны быть дерегистрированы.
Возвращаемые значения:
ESP_OK: были успешно дерегистрированы все такие обработчики. ESP_ERR_INVALID_ARG: Null-аргументы. ESP_ERR_NOT_FOUND: нет обработчиков, зарегистрированных с указанной строкой uri.
Постановка в очередь функции на выполнение в контексте HTTPD.
Эта API-функция ставит в очередь функцию work для асинхронного выполнения.
Замечание: некоторые протоколы требуют, чтобы web-сервер генерировал некие асинхронные данные и посылал их на постоянно открытое соединение. Эта фича как раз для использования с такими протоколами.
Параметры:
handle -- [in] дескриптор сервера, возвращенный из httpd_start. work -- [in] указатель на функцию для выполнения в контексте HTTPD. arg -- [in] указатель на аргументы, которые должны быть переданы в эту функцию.
Возвращаемые значения:
ESP_OK: функция work успешно поставлена в очередь. ESP_FAIL: ошибка в ctrl socket. ESP_ERR_INVALID_ARG: Null-аргументы.
Обычно если контекст сессии создан, он доступен для URI-обработчиков через структуру httpd_req_t. Однако бывают случаи, когда send/receive функции web-сервера могут требовать контекст (например, для доступа к ключевой информации и т. п.). Поскольку функция send/receive располагает только дескриптором сокета, этот API предоставляет им возможность получить контекст сессии.
Параметры:
handle -- [in] дескриптор сервера, возвращенный из httpd_start. sockfd -- [in] дескриптор сокета, для которого должен быть извлечен контекст.
Возвращаемые значения:
void*: указатель на контекст, связанный с этой сессией. NULL: пустой контекст / недопустимый handle / недопустимый fd сокета.
handle -- [in] дескриптор сервера, возвращенный из httpd_start. sockfd -- [in] дескриптор сокета, для которого должен быть установлен контекст. ctx -- [in] объект контекста для назначения сессии. free_fn -- [in] функция, которая должна быть вызвана для освобождения контекста.
Установит контекст 'transport' по дескриптору сокета.
Параметры:
handle -- [in] дескриптор сервера, возвращенный из httpd_start. sockfd -- [in] дескриптор сокета, для которого должен быть установлен контекст. ctx -- [in] объект контекста транспорта для назначения сессии. free_fn -- [in] функция, которая должна быть вызвана для освобождения контекста транспорта.
Замечание: вызов этой API-функции требуется только в специальных случаях, когда какое-то приложение требует асинхронно закрыть сессию клиента httpd.
Параметры:
handle -- [in] дескриптор сервера, возвращенный из httpd_start. sockfd -- [in] дескриптор сокета, сессия которого закрывается.
Возвращаемые значения:
ESP_OK: успешно инициированное закрытие. ESP_FAIL: сбой при постановке в очередь. ESP_ERR_NOT_FOUND: fd сокета не найден. ESP_ERR_INVALID_ARG: Null-аргументы.
Обновит счетчик LRU для указанного сокета. LRU расшифровывается как Least Recently Used, т. е. "последний использованный".
Счетчики LRU, внутренне связанные с каждой сессией, предназначены для мониторинга, как часто проходит трафик через сессию. Когда разрешена очистка этих счетчиков (LRU purge), если клиент запрашивает соединение, но достигнут максимум сокетов/сессий, то сессия, у которой самый ранний счетчик LRU, закроется автоматически.
Обновление счетчика LRU вручную предотвращает очистку сокета логикой LRU, даже когда на нем некоторое время не было трафика. Это полезно, когда все открытые сокеты/сессии часто обмениваются трафиком, но пользователь специально хочет, чтобы одна из сессий оставалась открытой, независимо от того, когда через неё последний раз передавался пакет.
Замечание: вызов этой API-функции необходим только когда разрешена опция LRU Purge Enable.
Параметры:
handle -- [in] дескриптор сервера, возвращенный из httpd_start. sockfd -- [in] дескриптор сокета для сессии, у которой должен быть обновлен счетчик LRU.
Возвращаемое значение:
ESP_OK: сокет найден и счетчик LRU его сессии обновлен. ESP_ERR_NOT_FOUND: сокет не найден. ESP_ERR_INVALID_ARG: Null-аргументы.
Возвратит список текущих дескрипторов сокетов активных сессий.
Замечание: размер предоставленного массива должен быть равен или больше количества открытых сокетов, сконфигурированных полем max_open_sockets в структуре httpd_config_t structure при инициализации сервера.
Параметры:
handle -- [in] дескриптор сервера, возвращенный из httpd_start. fds -- [inout] In: размер предоставленного массива client_fds. Out: количество допустимых fds клиента, возвращенных в client_fds. client_fds -- [out] массив fds клиентов.
Возвращаемые значения:
ESP_OK: успешно получен список сессий. ESP_ERR_INVALID_ARG: неправильные аргументы или список больше, чем предоставленный массив.
/** Структура аргумента для событий HTTP_SERVER_EVENT_ON_DATA и HTTP_SERVER_EVENT_SENT_DATA event */ typedefstruct{ intfd;/*!< файловый дескриптор сокета сессии */ intdata_len;/*!< длина данных */
}esp_http_server_event_data;
/** * @brief Структура конфигурации HTTP-сервера * * @note Используйте HTTPD_DEFAULT_CONFIG() для инициализации конфигурации * в значения по умолчанию, и затем по необходимости модифицируйте * только те поля, которые специально влияют на ваш сценарий использования. */ typedefstructhttpd_config{ unsignedtask_priority;/*!< Приоритет задачи FreeRTOS в которой работает сервер */ size_tstack_size;/*!< Максимальный размер стека задачи сервера */ BaseType_tcore_id;/*!< Идентификатор ядра сервера HTTP, который будет запущен */ uint32_ttask_caps;/*!< Особенности памяти для использования при выделении пространства стека задачи HTTP-сервера */
/** * Номер TCP-порта для приема и передачи трафика HTTP */ uint16_tserver_port;
/** * Номер UDP-порта для асинхронного обмена сигналами управления между различными * компонентами сервера. */ uint16_tctrl_port; uint16_tmax_open_sockets;/*!< Максимальное количество сокетов/клиентов, открытых в любое время (3 сокета резервируются для внутренней работы сервера HTTP) */ uint16_tmax_uri_handlers;/*!< Максимальное количество обработчиков URI */ uint16_tmax_resp_headers;/*!< Максимально допустимое количество дополнительных заголовков в HTTP-ответе */ uint16_tbacklog_conn;/*!< Количество backlog-соединений (см. примечание (1)) */ boollru_purge_enable;/*!< Разрешить закрывать "Least Recently Used" соединение */ uint16_trecv_wait_timeout;/*!< Таймаут для функции приема (в секундах)*/ uint16_tsend_wait_timeout;/*!< Таймаут для функции отправки (в секундах)*/
/** * Глобальный контекст пользователя. * * Это поле может использоваться для сохранения произвольных данных пользователя * в контексте сервера. Это значение может быть получено через дескриптор сервера * как доступное в структуре httpd_req_t struct. * * При выключении сервер освободит контекст пользователя вызовом free() * на поле global_user_ctx field. Если вы хотите использовать пользовательскую * функцию для освобождения глобального контекста пользователя, то * укажите её в поле global_user_ctx_free_fn. */ void*global_user_ctx;
/** * Функция для освобождения глобального контекста пользователя. */ httpd_free_ctx_fn_tglobal_user_ctx_free_fn;
/** * Глобальный контекст транспорта. * * Это данные подобны global_user_ctx, но они используются для кодирования * или шифрования сессии (например, для хранения контекста SSL). * Они будут освобождены вызовом free(), если не была специально предоставлена * пользовательская функция global_transport_ctx_free_fn. */ void*global_transport_ctx;
/** * Функция освобождения глобального контекста транспорта. */ httpd_free_ctx_fn_tglobal_transport_ctx_free_fn; boolenable_so_linger;/*!< разрешение/запрет linger (см. примечание (2)) */ intlinger_timeout;/*!< таймаут linger (в секундах) */ boolkeep_alive_enable;/*!< Разрешит keep-alive таймаут */ intkeep_alive_idle;/*!< Keep-alive время ожидания. По умолчанию 5 (секунд) */ intkeep_alive_interval;/*!< Keep-alive время интервала. По умолчанию 5 (секунд) */ intkeep_alive_count;/*!< Keep-alive счетчик повторов отправки пакета. По умолчанию 3 */
/** * Пользовательский callback открытия сессии. * * Вызывается на новом сокете сессии сразу после accept(), но перед чтением любых данных. * * Это возможность настроить, например, SSL-шифрование с помощью global_transport_ctx * и переопределения сеансов send/recv/pending. * * Если контекст нуждается в поддержке между этими функциями, сохраните его в сессии, * используя httpd_sess_set_transport_ctx(), и извлекайте контекст позже вызовом * httpd_sess_get_transport_ctx(). * * Возврат значения, отличающегося от ESP_OK, приведет к немедленному закрытию нового сокета. */ httpd_open_func_topen_fn;
/** * Пользовательский callback закрытия сессии. * * Вызывается, когда сессия удаляется, перед освобождением контекстов пользователя * и транспорта, и перед закрытием сокета. Это то место, куда помещают пользовательский * de-init код, общий для всех сокетов. * * Сервер закроет сокет только в том случае, если не установлен пользовательский callback * закрытия сессии. Если используется пользовательский callback, то в нем должна быть * вызвана close(sockfd) для большинства случаев. * * Если здесь освобождаются контексты пользователя или транспорта, то установите * их указатели в NULL, тогда сервер не будет их освобождать повторно. * * Эта функция вызывается для всех прерванных сессий, включая те, у которых сокет был * закрыт сетевым стеком, то есть дескриптор файла может быть больше недействительным. */httpd_close_func_tclose_fn;
/** * Функция совпадения URI. * * Вызывается, когда происходит поиск соответствия URI: * 1) обработчик запросов которого должен быть выполнен сразу * после успешного анализа HTTP-запроса * 2) для предотвращения дублирования при регистрации нового * обработчика URI с помощью httpd_register_uri_handler() * * Доступны опции: * 1) NULL: внутренне выполняемая базовая проверка на совпадение * с помощью strncmp() * 2) httpd_uri_match_wildcard(): используется URI wildcard matcher * * Пользователи могут реализовать свои собственные функции проверки * совпадения (см. описание прототипа функции httpd_uri_match_func_t). */ httpd_uri_match_func_turi_match_fn;
}httpd_config_t;
Примечание (1): Backlog-соединения (также называемые "очередью ожидающих соединений") - это максимальное количество TCP-соединений, которые могут находиться в состоянии ожидания принятия сервером, когда он уже обрабатывает максимальное количество активных соединений.
Как это работает:
1. Сервер слушает на определенном порту. 2. Клиенты устанавливают соединение через трехстороннее рукопожатие TCP. 3. Соединение переходит в состояние `SYN_RECEIVED` и помещается в очередь backlog. 4. Сервер принимает соединение из backlog-очереди, когда готов его обработать.
На практике:
- Когда сервер занят обработкой существующих соединений, новые входящие соединения попадают в backlog-очередь. - Если очередь заполнена, новые соединения будут отклоняться. - Размер backlog влияет на устойчивость сервера к пиковым нагрузкам.
Пример настройки в ESP-IDF:
httpd_config_tconfig=HTTPD_DEFAULT_CONFIG();
config.backlog_conn=10;// Очередь из 10 ожидающих соединений
// Если приходит 11-е соединение, когда сервер занят и очередь полна, // оно будет немедленно отклонено
Типичные значения:
- Маленькие значения (3-10) - для устройств с ограниченными ресурсами. - Средние значения (10-50) - для большинства встраиваемых систем. - Большие значения (50+) - для серверов, ожидающих высокие нагрузки.
В контексте HTTP-сервера на ESP32 параметр backlog_conn помогает справляться с кратковременными всплесками запросов, не теряя соединения.
Примечание (2): Linger (задержка) это опция сокета, которая определяет поведение при закрытии TCP-сокета, когда в буфере остаются не переданные данные.
Без linger (enable_so_linger = false):
- При вызове close() система немедленно возвращает управление - ОС в фоне пытается отправить оставшиеся данные - Соединение закрывается, даже если данные не доставлены
При разрешенном linger (enable_so_linger = true):
- При вызове close() система блокирует выполнение на linger_timeout секунд - ОС пытается отправить все данные из буфера - Если данные отправлены до истечения таймаута - соединение закрывается корректно - Если таймаут истек - соединение принудительно разрывается
Практический пример:
httpd_config_tconfig=HTTPD_DEFAULT_CONFIG();
config.enable_so_linger=true;
config.linger_timeout=5;// Ждать до 5 секунд
// При закрытии соединения: // 1. Система попытается отправить все оставшиеся HTTP-данные // 2. Если за 5 секунд не успеет - соединение будет принудительно закрыто
Когда использовать:
✅ Включить linger: - Важные HTTP-ответы, которые должны быть доставлены - Критичные данные, которые нельзя потерять - Когда клиент должен получить полный ответ
❌ Выключить linger: - Высоконагруженные серверы (помогает избегать блокировок) - Реaltime-приложения, где важна скорость - Когда потеря части данных допустима
В контексте HTTP-сервера Linger помогает гарантировать, что клиент получит полный HTTP-ответ перед закрытием соединения, особенно при медленных сетях или больших объемах данных.
/** * @brief Структура данных запроса HTTP */ typedefstructhttpd_req{ httpd_handle_thandle;/*!< дескриптор экземпляра сервера */ intmethod;/*!< Тип HTTP-запроса, -1 если не поддерживаемый метод, HTTP_ANY для wildcard-метода универсальной поддержки */ constcharuri[HTTPD_MAX_URI_LEN+1];/*!< URI этого запроса (1 доп. байт для null-терминатора) */ size_tcontent_len;/*!< длина тела запроса */ void*aux;/*!< внутренне используемые данные */
/** * Указатель на контекст пользователя, переданный при регистрации URI. */ void*user_ctx;
/** * Указатель на контекст сессии (Session Context Pointer) * * Контекст сессии. Контексты сохраняются между 'сессиями' для указанного открытого * TCP-соединения. В одной сессии может быть несколько запросов и ответов. * Web-сервер обеспечит постоянный контекст между всеми этими запросами и ответами. * * По умолчанию это NULL. URI-обработчики могут установить это поле в осмысленное значение. * * Если нижележащий сокет закрывается, и этот указатель не NULL, то web-сервер освободит * контекст вызовом free(), если не была установлена функция free_ctx. */ void*sess_ctx;
/** * Указатель на хук освобождения контекста. * * Функция для освобождения контекста сессии. * * Если сокет web-сервера закрывается, он освободит контекст сессии вызовом free() * на поле sess_ctx. Если вы хотите иметь пользовательскую функцию для освобождения * контекста, то укажите её в этом месте. */ httpd_free_ctx_fn_tfree_ctx;
/** * Флаг, показывающий, должны ли быть игнорированы изменения контекста сессии. * * По умолчанию, если вы меняете sess_ctx в каком-то URI-обработчике, то http-сервер * будет внутренне освобождать предыдущий контекст (если он не NULL) после возврата * из URI-обработчика. Если вы хотите сами управлять выделением / изменением * выделения / освобождением sess_ctx, то установите этот флаг в true, тогда * сервер не будет выполнять соответствующие проверки контекста. Контекст будет * очищен сервером (вызовом free_ctx или free()) только если сокет закрывается. */ boolignore_sess_ctx_changes;
}httpd_req_t;
/** * @brief Структура для URI-обработчика */ typedefstructhttpd_uri{ constchar*uri;/*!< URI для обработки */ httpd_method_tmethod;/*!< Метод, поддерживаемый URI, HTTP_ANY для универсального wildcard-метода */
/** * Обработчик для вызова поддерживаемого метода запроса. Он должен возвратить * ESP_OK, или иначе нижележащий сокет будет закрыт. */ esp_err_t(*handler)(httpd_req_t*r);
/** * Указатель на данные контекста пользователя, которые будут доступны для обработчика */ void*user_ctx;
#ifdef CONFIG_HTTPD_WS_SUPPORT /** * Флаг, показывающий конечную точку WebSocket. * Если этот флаг true, то метод должен быть HTTP_GET. Иначе handshake не будет обработан. */ boolis_websocket;
/** * Флаг, показывающий, что кадры управления (PING, PONG, CLOSE) также переданы в обработчик. * Это используется, если необходима пользовательская обработка кадров управления. */ boolhandle_ws_control_frames;
/** * Указатель на суб-протокол, поддерживаемый URI */ constchar*supported_subprotocol; #endif
}httpd_uri_t;
/** * @brief Формат кадра WebSocket */ typedefstructhttpd_ws_frame{ boolfinal;/*!< Конечный кадр: Для принятых кадров это поле показывает, был ли установлен флаг `FIN`. Для передаваемых кадров это поле используется только если также установлена опция `fragmented`. Если `fragmented` == false, то по умолчанию флаг `FIN` устанавливается, делая ws_frame кадром полного/не фрагментированного сообщения (esp_http_server не делает автоматическую фрагментацию сообщений) */ boolfragmented;/*!< Показывает, что кадр, выделенный для передачи, это фрагмент сообщения, так что флаг `FIN` устанавливается вручную в соответствии с опцией `final`. Этот флаг никогда не устанавливается для принятых сообщений */ httpd_ws_type_ttype;/*!< Тип кадра WebSocket */ uint8_t*payload;/*!< Предварительно выделенный буфер данных */ size_tlen;/*!< Длина данных WebSocket */
}httpd_ws_frame_t;
[Используемые макросы (esp_http_server.h)]
HTTP_ANY
HTTPD_SOCK_ERR_FAIL
HTTPD_SOCK_ERR_INVALID
HTTPD_SOCK_ERR_TIMEOUT
HTTPD_200 HTTP Response 200
HTTPD_204 HTTP Response 204
HTTPD_207 HTTP Response 207
HTTPD_400 HTTP Response 400
HTTPD_404 HTTP Response 404
HTTPD_408 HTTP Response 408
HTTPD_500 HTTP Response 500
HTTPD_TYPE_JSON HTTP Content type JSON
HTTPD_TYPE_TEXT HTTP Content type text/HTML
HTTPD_TYPE_OCTET HTTP Content type octext-stream
ESP_HTTPD_DEF_CTRL_PORT HTTP Server control socket port
HTTPD_DEFAULT_CONFIG()
ESP_ERR_HTTPD_BASE Начальное значение кодов ошибок HTTPD
ESP_ERR_HTTPD_HANDLERS_FULL Задействован все слоты зарегистрированных URI-обработчиков.
ESP_ERR_HTTPD_HANDLER_EXISTS URI-обработчик с таким же методом и целевым URI уже зарегистрирован.
ESP_ERR_HTTPD_RESP_HDR Поле заголовка ответа больше, чем поддерживается.
ESP_ERR_HTTPD_RESP_SEND Произошла ошибка при отправке пакета ответа.
ESP_ERR_HTTPD_ALLOC_MEM Не получилось динамически выделить память для ресурса.
ESP_ERR_HTTPD_TASK Не получилось запустить задачу/поток сервера.
HTTPD_RESP_USE_STRLEN
[Используемые определения типа]
typedef void *httpd_handle_t Дескриптор HTTP-сервера. У каждого экземпляра сервера будет уникальный дескриптор.
typedef enum http_method httpd_method_t Обертка типа метода HTTP над перечислением http_method, доступным в библиотеке http_parser.
typedef void (*httpd_free_ctx_fn_t)(void *ctx) Прототип функции для освобождения данных контекста (если она присутствует). Параметр ctx [in] указывает на освобождаемый объект.
typedef esp_err_t (*httpd_open_func_t)(httpd_handle_t hd, int sockfd) Прототип функции для открытия сессии. Вызывается немедленно после того, как сокет был открыт, для установки функций send/recv и других параметров сокета.
Возвращаемое значение: ESP_OK: при успехе. Любое другое значение сигнализирует, что сервер немедленно закроет сокет.
typedef void (*httpd_close_func_t)(httpd_handle_t hd, int sockfd) Прототип функции для закрытия сессии.
Замечание: существует возможность, что в этой точке дескриптор сокета недопустимый, эта функция вызывается для всех завершенных сессий. Обеспечьте правильную обработку кодов возврата.
Параметры: reference_uri: [in] образцовый URI/шаблон, на соответствие которому проверяется другой URI. uri_to_match: [in] URI/шаблон, совпадающий с образцовым URI/шаблоном. match_upto: [in] для указания реальной длины uri_to_match по которому применяется алгоритм проверки соответствия (максимальное значение это strlen(uri_to_match), независимо от длины reference_uri)
Возвращаемое значение: true при обнаруженном совпадении.
typedef struct httpd_config httpd_config_t Структура конфигурации HTTP-сервера.
Замечание: используйте HTTPD_DEFAULT_CONFIG() для инициализации конфигурации в состояние по умолчанию, и затем модифицируйте те поля, которые специально нужны для вашего случая применения.
typedef int (*httpd_send_func_t)(httpd_handle_t hd, int sockfd, const char *buf, size_t buf_len, int flags) Прототип для низкоуровневой функции отправки HTTPD.
Замечание: предоставленная пользователем функция должна внутри себя обрабатывать ошибки, в зависимости от установленного значения errno, и возвращать специальные коды HTTPD_SOCK_ERR_ codes, которые в конечном итоге будут переданы как возвращаемые значения функции httpd_send().
Параметры: hd: [in] экземпляр сервера sockfd: [in] файловый дескриптор сокета сессии buf: [in] буфер для отправляемых байт buf_len: [in] размер данных flags: [in] флаги для функции send()
Возвращаемые значения: Bytes: количество успешно отправленных байт. HTTPD_SOCK_ERR_INVALID: недопустимые аргументы. HTTPD_SOCK_ERR_TIMEOUT: таймаут/прервано при вызове socket send(). HTTPD_SOCK_ERR_FAIL: невосстановимая ошибка при вызове socket send().
typedef int (*httpd_recv_func_t)(httpd_handle_t hd, int sockfd, char *buf, size_t buf_len, int flags) Прототип для низкоуровневой функции приема HTTPD.
Замечание: предоставленная пользователем функция должна внутри себя обрабатывать ошибки, в зависимости от установленного значения errno, и возвращать специальные коды HTTPD_SOCK_ERR_ codes, которые в конечном итоге будут переданы как возвращаемые значения функции httpd_req_recv().
Параметры: hd: [in] экземпляр сервера sockfd: [in] файловый дескриптор сокета сессии buf: [in] буфер для принимаемых байт buf_len: [in] размер данных flags: [in] флаги для функции recv()
Возвращаемые значения: Bytes: количество успешно принятых байт. 0: длина параметра длины буфера 0 / соединение закрыто на удаленной стороне. HTTPD_SOCK_ERR_INVALID: недопустимые аргументы. HTTPD_SOCK_ERR_TIMEOUT: таймаут/прервано при вызове socket recv(). HTTPD_SOCK_ERR_FAIL: невосстановимая ошибка при вызове socket recv().
typedef int (*httpd_pending_func_t)(httpd_handle_t hd, int sockfd) Прототип для низкоуровневой функции HTTPD "get pending bytes" (получение ожидающих байт).
Замечание: предоставленная пользователем функция должна внутри себя обрабатывать ошибки, в зависимости от установленного значения errno, и возвращать специальные коды HTTPD_SOCK_ERR_ codes, которые будут соответственно обрабатываться в задаче сервера.
Возвращаемые значения: Bytes: количество байт, ожидающих приема HTTPD_SOCK_ERR_INVALID: недопустимые аргументы. HTTPD_SOCK_ERR_TIMEOUT: таймаут/прервано при вызове socket pending(). HTTPD_SOCK_ERR_FAIL: невосстановимая ошибка при вызове socket pending().
typedef esp_err_t (*httpd_err_handler_func_t)(httpd_req_t *req, httpd_err_code_t error) Прототип функции для обработки ошибок HTTP.
Эта функция вызывается при ошибках HTTP, генерируемых при внутренней обработке HTTP-запроса. Это используется для переопределения поведения по умолчанию для ошибки, при котором посылаются ответы HTTP error и закрывается нижележащий сокет.
Замечания:
● Если функция реализована, то сервер не будет автоматически посылать коды ответа HTTP error, так что httpd_resp_send_err() должна вызываться внутри этой функции, если пользователю нужно генерировать ответы HTTP error. ● При вызове не гарантируется достоверность полей uri, method, content_len и user_ctx параметра httpd_req_t, поскольку HTTP-запрос может быть частично получен/проанализирован. ● Эта функция должна возвратить ESP_OK, если нижележащий сокет должен сохраняться открытым. Любое другое значение будет гарантировать закрытие сокета. Возвращаемое значение игнорируется, когда ошибка типа HTTPD_500_INTERNAL_SERVER_ERROR и сокет все равно закрыт.
Параметры: req: [in] HTTP-запрос, для которого должна быть обработана ошибка error: [in] тип ошибки
Возвращаемые значения: ESP_OK: ошибка была успешно обработана ESP_FAIL: сбой, показывающий что нижележащий сокет должен быть закрыт.
typedef void (*transfer_complete_cb)(esp_err_t err, int socket, void *arg) Функция обратного вызова (callback) завершения транзакции.
typedef struct httpd_req httpd_req_t Структура данных запроса HTTP.
typedef struct httpd_uri httpd_uri_t Структура для URI-обработчика.
typedef void (*httpd_work_fn_t)(void *arg) Прототип рабочей функции сервера (HTTPD work). Подробности см. в описании функции httpd_queue_work() []. Параметр arg: [in] задает аргументы для этой work-функции.
/** * @brief Коды ошибки, отправляемые как HTTP-ответ в случае ошибок, * возникающих при обработке HTTP-запроса */ typedefenum{ /* Код для любых неожиданных ошибок во время парсинга, наподобие неожиданных * переходов между состояниями или необработанных ошибок. */ HTTPD_500_INTERNAL_SERVER_ERROR=0,
/* Для методов, не поддерживаемых http_parser. В настоящее время * http_parser останавливает парсинг, когда встречаются такие методы, * и тогда сервер отвечает вместо этого ошибкой 400 Bad Request. */ HTTPD_501_METHOD_NOT_IMPLEMENTED,
/* Когда HTTP-версия не 1.1 или 1.0 */ HTTPD_505_VERSION_NOT_SUPPORTED,
/* Возвращается, когда http_parser остановил парсинг из-за некорректного * синтаксиса запроса, не поддерживаемого метода в URI запроса или * из-за фрагментированного encoding / upgrade поля, присутствующего * в заголовках */ HTTPD_400_BAD_REQUEST,
/* Этот ответ означает, что клиент должен себя аутентифицировать, чтобы * получить ответ на запрос. */ HTTPD_401_UNAUTHORIZED,
/* Клиент не имеет прав для доступа к содержимому, так что сервер * отказался от предоставления запрошенного ресурса. В отличие * от ошибки 401, сервер идентифицировал клиента. */ HTTPD_403_FORBIDDEN,
/* Когда запрошенный URI не найден */ HTTPD_404_NOT_FOUND,
/* Когда URI найден, но запрошен метод без обработчика */ HTTPD_405_METHOD_NOT_ALLOWED,
/* Предназначен для таймаута приема. В нестоящее время также посылается * и для других ошибок приема. Клиент должен подразумевать, что сервер * немедленно закроет соединение после ответа этим кодом. */ HTTPD_408_REQ_TIMEOUT,
/* Предназначено для ответа на фрагментарное кодирование, которое * в настоящий момент не поддерживается. Хотя необработанный http_parser * callback возвратит в ответ на фрагментированный запрос ошибку * "400 Bad Request". */ HTTPD_411_LENGTH_REQUIRED,
/* Пришедшая полезная нагрузка слишком велика */ HTTPD_413_CONTENT_TOO_LARGE,
/* Длина URI больше, чем CONFIG_HTTPD_MAX_URI_LEN */ HTTPD_414_URI_TOO_LONG,
/* Секция заголовков больше, чем CONFIG_HTTPD_MAX_REQ_HDR_LEN */ HTTPD_431_REQ_HDR_FIELDS_TOO_LARGE,
/* Используется внутренне для получения общего количества кодов ошибок */ HTTPD_ERR_CODE_MAX
}httpd_err_code_t;
/** * @brief Перечисление для описания информации клиента */ typedefenum{ HTTPD_WS_CLIENT_INVALID=0x0, HTTPD_WS_CLIENT_HTTP=0x1, HTTPD_WS_CLIENT_WEBSOCKET=0x2,
}httpd_ws_client_info_t;
/** * @brief Идентификаторы событий HTTP-сервера */ typedefenum{ HTTP_SERVER_EVENT_ERROR=0,/*!< Возникает при любой ошибке во время выполнения */ HTTP_SERVER_EVENT_START,/*!< При старте HTTP-сервера */ HTTP_SERVER_EVENT_ON_CONNECTED,/*!< Клиент соединился с HTTP-сервером, передачи данных еще не было */ HTTP_SERVER_EVENT_ON_HEADER,/*!< При получении каждого заголовка, отправленного клиентом */ HTTP_SERVER_EVENT_HEADERS_SENT,/*!< После отправки всех заголовков клиенту */ HTTP_SERVER_EVENT_ON_DATA,/*!< При получении данных от клиента */ HTTP_SERVER_EVENT_SENT_DATA,/*!< При завершении сесии ESP HTTP-сервера */ HTTP_SERVER_EVENT_DISCONNECTED,/*!< При разрыве соединения */ HTTP_SERVER_EVENT_STOP,/*!< При остановке HTTP-сервера */
}esp_http_server_event_id_t;