Search code examples
httpswebserveresp-idf

accepting Uri between 2 numbers


I'm working on the ESP-idf via Visual Studio Code. Currently I'm working on a Webserver implementation and i would like to accept the following url:

IPADDRESS/command/on/5(number between 1 and 32)

The easiest(but not very efficient) solution would be, to initialize every single uri like this

static const httpd_uri_t postCommandOn = {
    .uri       = "/command/on/1",
    .method    = HTTP_POST,
    .handler   = on_command_handler

};
static const httpd_uri_t postCommandOn = {
    .uri       = "/command/on/2",
    .method    = HTTP_POST,
    .handler   = on_command_handler

};

etc..

But shouldn't there be an easier method? Thanks in advance!

greetings

Edit: Well I don't know how it happened but my complete project is gone now.

I try to redo my steps but facing a new problem which I'm pretty sure didn't exist the last time.

When i try to add this line:

    conf.uri_match_fn = httpd_uri_match_wildcard;

i get the following Error message:

error: 'httpd_ssl_config_t' {aka 'struct httpd_ssl_config'} has no member named 'uri_to_match'
conf.uri_to_match = httpd_uri_match_wildcard;

I dont know why it appears all of the sudden, but I don't really know what i did different to the last time i inserted this line.

my main.c file now looks like this:


   This example code is in the Public Domain (or CC0 licensed, at your option.)

   Unless required by applicable law or agreed to in writing, this
   software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
   CONDITIONS OF ANY KIND, either express or implied.
*/

#include <esp_wifi.h>
#include <esp_event.h>
#include <esp_log.h>
#include <esp_system.h>
#include <nvs_flash.h>
#include <sys/param.h>
#include "esp_netif.h"
#include "esp_eth.h"
#include "protocol_examples_common.h"

#include <esp_https_server.h>

/* A simple example that demonstrates how to create GET and POST
 * handlers and start an HTTPS server.
*/

static const char *TAG = "example";


/* An HTTP GET handler */
static esp_err_t root_get_handler(httpd_req_t *req)
{
    httpd_resp_set_type(req, "text/html");
    httpd_resp_send(req, "<h1>Hello Secure World!</h1>", HTTPD_RESP_USE_STRLEN);

    return ESP_OK;
}

static esp_err_t status_get_handler(httpd_req_t *req)
{
    httpd_resp_set_type(req, "text/html");
    httpd_resp_send(req, "<h1>Hello Secure World!</h1>", HTTPD_RESP_USE_STRLEN);

    return ESP_OK;

}

static esp_err_t command_on_post_handler(httpd_req_t *req)
{
    httpd_resp_set_type(req, "text/html");
    httpd_resp_send(req, "<h1>Hello Secure World!</h1>", HTTPD_RESP_USE_STRLEN);

    return ESP_OK;

}

static esp_err_t command_off_post_handler(httpd_req_t *req)
{
    httpd_resp_set_type(req, "text/html");
    httpd_resp_send(req, "<h1>Hello Secure World!</h1>", HTTPD_RESP_USE_STRLEN);

    return ESP_OK;

}

static const httpd_uri_t getStatus = {
    .uri       = "/status",
    .method    = HTTP_GET,
    .handler   = status_get_handler
};

static const httpd_uri_t postCommandOn = {
    .uri       = "/command/on/*",
    .method    = HTTP_POST,
    .handler   = command_on_post_handler
};

static const httpd_uri_t postCommandOff = {
    .uri       = "/command/off/*",
    .method    = HTTP_POST,
    .handler   = command_off_post_handler
};

static const httpd_uri_t root = {
    .uri       = "/",
    .method    = HTTP_GET,
    .handler   = root_get_handler
};


static httpd_handle_t start_webserver(void)
{
    httpd_handle_t server = NULL;

    // Start the httpd server
    ESP_LOGI(TAG, "Starting server");

    httpd_ssl_config_t conf = HTTPD_SSL_CONFIG_DEFAULT();

    extern const unsigned char cacert_pem_start[] asm("_binary_cacert_pem_start");
    extern const unsigned char cacert_pem_end[]   asm("_binary_cacert_pem_end");
    conf.cacert_pem = cacert_pem_start;
    conf.cacert_len = cacert_pem_end - cacert_pem_start;

    extern const unsigned char prvtkey_pem_start[] asm("_binary_prvtkey_pem_start");
    extern const unsigned char prvtkey_pem_end[]   asm("_binary_prvtkey_pem_end");
    conf.prvtkey_pem = prvtkey_pem_start;
    conf.prvtkey_len = prvtkey_pem_end - prvtkey_pem_start;

    //////////////////////////////////////////////////////////
    //////////this line causes the problem///////////////////
    conf.uri_match_fn = httpd_uri_match_wildcard;

    esp_err_t ret = httpd_ssl_start(&server, &conf);
    if (ESP_OK != ret) {
        ESP_LOGI(TAG, "Error starting server!");
        return NULL;
    }

    // Set URI handlers
    ESP_LOGI(TAG, "Registering URI handlers");
    httpd_register_uri_handler(server, &root);
    httpd_register_uri_handler(server, &getStatus);
    httpd_register_uri_handler(server, &postCommandOff);
    httpd_register_uri_handler(server, &postCommandOn);
    return server;
}

static void stop_webserver(httpd_handle_t server)
{
    // Stop the httpd server
    httpd_ssl_stop(server);
}

static void disconnect_handler(void* arg, esp_event_base_t event_base,
                               int32_t event_id, void* event_data)
{
    httpd_handle_t* server = (httpd_handle_t*) arg;
    if (*server) {
        stop_webserver(*server);
        *server = NULL;
    }
}

static void connect_handler(void* arg, esp_event_base_t event_base,
                            int32_t event_id, void* event_data)
{
    httpd_handle_t* server = (httpd_handle_t*) arg;
    if (*server == NULL) {
        *server = start_webserver();
    }
}

void app_main(void)
{
    static httpd_handle_t server = NULL;

    ESP_ERROR_CHECK(nvs_flash_init());
    ESP_ERROR_CHECK(esp_netif_init());
    ESP_ERROR_CHECK(esp_event_loop_create_default());

    /* Register event handlers to start server when Wi-Fi or Ethernet is connected,
     * and stop server when disconnection happens.
     */

#ifdef CONFIG_EXAMPLE_CONNECT_WIFI
    ESP_ERROR_CHECK(esp_event_handler_register(IP_EVENT, IP_EVENT_STA_GOT_IP, &connect_handler, &server));
    ESP_ERROR_CHECK(esp_event_handler_register(WIFI_EVENT, WIFI_EVENT_STA_DISCONNECTED, &disconnect_handler, &server));
#endif // CONFIG_EXAMPLE_CONNECT_WIFI
#ifdef CONFIG_EXAMPLE_CONNECT_ETHERNET
    ESP_ERROR_CHECK(esp_event_handler_register(IP_EVENT, IP_EVENT_ETH_GOT_IP, &connect_handler, &server));
    ESP_ERROR_CHECK(esp_event_handler_register(ETH_EVENT, ETHERNET_EVENT_DISCONNECTED, &disconnect_handler, &server));
#endif // CONFIG_EXAMPLE_CONNECT_ETHERNET

    /* This helper function configures Wi-Fi or Ethernet, as selected in menuconfig.
     * Read "Establishing Wi-Fi or Ethernet Connection" section in
     * examples/protocols/README.md for more information about this function.
     */
    ESP_ERROR_CHECK(example_connect());
}

EDIT2:

I tried the following: in the header esp_https_server.h conf is defined as the following =

    .httpd = {                                    \
        .task_priority      = tskIDLE_PRIORITY+5, \
        .stack_size         = 10240,              \
        .core_id            = tskNO_AFFINITY,     \
        .server_port        = 0,                  \
        .ctrl_port          = 32768,              \
        .max_open_sockets   = 4,                  \
        .max_uri_handlers   = 8,                  \
        .max_resp_headers   = 8,                  \
        .backlog_conn       = 5,                  \
        .lru_purge_enable   = true,               \
        .recv_wait_timeout  = 5,                  \
        .send_wait_timeout  = 5,                  \
        .global_user_ctx = NULL,                  \
        .global_user_ctx_free_fn = NULL,          \
        .global_transport_ctx = NULL,             \
        .global_transport_ctx_free_fn = NULL,     \
        .open_fn = NULL,                          \
        .close_fn = NULL,                         \
        .uri_match_fn = NULL                      \ //this is the part which is "no member"
    },                                            \
    .cacert_pem = NULL,                           \
    .cacert_len = 0,                              \
    .client_verify_cert_pem = NULL,               \
    .client_verify_cert_len = 0,                  \
    .prvtkey_pem = NULL,                          \
    .prvtkey_len = 0,                             \
    .transport_mode = HTTPD_SSL_TRANSPORT_SECURE, \
    .port_secure = 443,                           \
    .port_insecure = 80,                          \
}

you can clearly see, that .uri_match_fn is set NULL(so it is a Member of that struct). If I set .uri_match_fn = httpd_uri_match_wildcard \ within the header it does work, but i dont want to change the default setting function. I could add another function which implement a uri wildcard, but i think the problem is somewhere else.

someone might have an Idea why it is like that?


Solution

  • After a search I found an example that shows how it is used:

    You have to set the URI matcher to a wild card match.

    config.uri_match_fn = httpd_uri_match_wildcard;
    
    static esp_err_t on_command_handler(httpd_req_t *req)
    {
        // req->uri is character array with request uri
        // find the number after /on/ and validate
        // and call httpd_resp_send_404(req)
        return ESP_OK;
    }
    
    static const httpd_uri_t postCommandOn = {
        .uri       = "/command/on/*",
        .method    = HTTP_POST,
        .handler   = on_command_handler
    };
    
    httpd_register_uri_handler(server_handle, &postCommandOn);