Mongoose esp32 with mg_http_serve_dir

  1. My goal is: to set up a mongoose webserver on the esp32 in c++ with direcory listening

  2. My actions are:

     if (ev == MG_EV_HTTP_MSG) {
         struct mg_http_message *hm = (struct mg_http_message *) ev_data;
         if (mg_http_match_uri(hm, "/api/config/get")) {
             ESP_LOGD(LOG_TAG, "api/config/get");
             char *s = stringify_config(&s_config);
             mg_printf(c, "HTTP/1.1 200 OK\r\nContent-Length: %d\r\n\r\n%s\n",
                       (int) strlen(s) + 1, s);
             free(s);
         } else if (mg_http_match_uri(hm, "/api/config/set")) {
             ESP_LOGD(LOG_TAG, "/api/config/set");
             if (update_config(hm, &s_config)) notify_config_change((struct mg_mgr*) fn_data);
             mg_printf(c, "HTTP/1.1 200 OK\r\nContent-Length: 0\r\n\r\n");
         } else if (mg_http_match_uri(hm, "/api/config/watch")) {
             ESP_LOGD(LOG_TAG, "/api/config/watch");
             c->label[0] = 'W';  // Mark ourselves as a config watcher
             mg_printf(c, "HTTP/1.1 200 OK\r\nTransfer-Encoding: chunked\r\n\r\n");
         } else {
             ESP_LOGD(LOG_TAG, "else");
             struct mg_http_serve_opts opts = {.root_dir = "/www"};
    
             //mg_http_serve_file(c, (struct mg_http_message*) ev_data, "/www/index.html", "text/html", "AA: bb\r\nCC: dd\r\n");
             mg_http_serve_dir(c,  (struct mg_http_message*) ev_data, &opts);
         }
     }
    

I serve a web directory (www) but the files are not available in the mongoose context.
To be sure the files are available I did the following:

    FileSystem *file = new FileSystem();
std::vector<File> test = file->getDirectoryContents("/www");

for(int i = 0; i < test.size(); i++) {
    cout << test[i].getName();
}
  1. The result I see is: The output returns all filename, so they are available at the filesystem.
    I tried to do this with mg_http_serve_dir but it didn’t work.

  2. My expectation & question is: Whats going wrong and why can’t mongoose find the files on the server? Can someone help me?

Mongoose uses ISO C API to serve files, and uses realpath() call to normalise paths.
In other words, when you serve a directory, Mongoose will:

  1. Construct a file name from the URI, for example for / uri, it is A = root_dir + / + index.html
  2. Call B = realpath(A), make sure B is within root_dir
  3. Call fopen(B)

Therefore, on your system, please double-check that realpath() and fopen() work as expected.
You can mg_set_log_level("3,http=4") to increase log verbosity and see what exactly fails.

Thanks for your fast response. I checked if fopen() and realpath() works as expected. It did.

I did the following to check the functions:

  char buf[PATH_MAX];
  char *res = realpath("/www/web/index.html", buf);
  printf("%s", buf);

The output is:

/www/web/index.html

After this I did the following:

        FILE* fp = std::fopen(buf, "r");
        if(!fp) {
            std::perror("File opening failed");
        }

        int c; // note: int, not char, required to handle EOF
        while ((c = std::fgetc(fp)) != EOF) { // standard C I/O file reading loop
            std::putchar(c);
        }

        if (std::ferror(fp))
            std::puts("I/O error when reading");
        else if (std::feof(fp))
            std::puts("End of file reached successfully");

        std::fclose(fp);

The output shows the content of the index.html file.

Then I used the url for the root dir again:

struct mg_http_serve_opts opts = {.root_dir = "/www/web"};
mg_http_serve_dir(c,  (struct mg_http_message*) ev_data, &opts);

The response is a kernel panic.

The mg_set_log_level("3,http=4") doesn’t work.
Do you have an idea, what I can do to solve the problem?

Please update mongoose source tree.
The ESP32 example there was updated and now works with FS.
Note: the FS is SPIFFS, mounted on /spiffs.

1 Like