Overview

This tutorial shows an example of how to embed all the web files in a packed filesystem that is linked into the server binary; forming a read-only file system. This makes it possible to serve files on devices with no filesystem. Even on devices with a filesystem, packing some files like the Web UI can be beneficial, providing resiliency to filesystem errors.

Embedded filesystem

All the static files of a web server can be compiled into its binary, maintaining the directory structure.

This is done with a utility present in the Mongoose Library tree: pack.c. This utility can be compiled at build time by the Makefile and called passing it the path to the web root directory. The output of this utility is then a C file that can be compiled and linked into the binary file.

packed filesystem

At run time, a file system virtualization layer in Mongoose extracts the requested file contents from this packed directory, as the handler is conveniently passed the proper options:

In order for Mongoose to include the proper code, we need to set the MG_ENABLE_PACKED_FS macro. This is usually done by adding proper compiler flags in the Makefile, e.g.: -DMG_ENABLE_PACKED_FS=1.

Mongoose can automatically serve gzipped versions of the files, that is, when there is a request for file.extension and that file is not present but file.extension.gz is, Mongoose will serve the gzipped file with the original file Content-Type header, but adding a proper Content-Encoding header so the browser is able to gunzip the file itself.

You can use all the usual Mongoose functions, though remember that this is a read-only file system.

Build and try

  • If you've not already done so, clone the Mongoose Library repo
    $ git clone https://github.com/cesanta/mongoose
    
  • Build the example, this will also start Mongoose:
    $ cd mongoose/examples/embedded-filesystem
    $ make clean all
    
  • Start your browser on http://localhost:8000, a simple "About Cesanta" page is loaded
  • Observe the size of the generated binary, you can make it even smaller by gzipping its contents:
    $ make clean gzipped
    
  • To make again but with regular files, just run
    $ make clean plain
    

Create and use an embedded filesystem

Some of these steps, as you may have seen while trying this out, are done under the hood by the Makefile. Here we will detail them in case you can't use a Makefile or want to do things differently.

In order to create the embedded (or packed) filesystem, do the following:

  1. Build the pack tool from test/pack.c:
    $ cc -o pack pack.c
    
  2. If your files should be gzipped, do it now
  3. Convert a list of files into a single .c file; e.g: packed_fs.c:
    $ ./pack web_root/index.html web_root/style.css > packed_fs.c
    
  4. In your application, besides referring to the root folder as usual, declare the filesystem type as mg_fs_packed:
  5. Build your application with the packed filesystem file (packed_fs.c), and enable packed filesystem support in Mongoose by defining MG_ENABLE_PACKED_FS=1:
    $ cc mongoose.c app.c packed_fs.c -DMG_ENABLE_PACKED_FS=1
    

Browse latest code