[Libwebsockets] serving compressed http response from a zip archive

Andy Green andy at warmcat.com
Wed Mar 1 02:04:00 CET 2017

On March 1, 2017 9:06:53 AM GMT+09:00, Per Bothner <per at bothner.com> wrote:
>If you want to include zip archive (or gzip file) support in
>I think the code in DomTerm is clean enough that it can be used with
>modest changes.
>The source is in the directory:
>- The files junzip.h and junzip.c handle the
>actual parsing and seeking in the zip archive.
>For simplicity and performance, it assumes the zip
>archive is in memory. DomTerm mmaps the file in,
>but it would be a trivial change to handle a literal data buffer,
>as created by xxd --include.
>The jzReadData function decompresses a file entry; it is not called
>if the response can be compressed.
>- The io.c file provides the "fops" wrapper.  It determines
>if the data can be sent uncompressed as-is: If so,
>it copies it out of the zip file; otherwise it calls jzReadData.
>- The file http.c is http-server part of DomTerm.
>It just adds a "domterm:" prefix to the path.
>It seems that rather than keying off a "domterm:" prefix
>we should be using a struct lws_http_mount.  I haven't tried that.
>It seems what is missing is a pointer from a lws_http_mount instance
>to either a lws_plat_file_ops or at least a mount-specific open method.
>Would it make sense to add a field in struct lws_http_mount to
>either a lws_plat_file_op table or just an open function? Or is
>there a better way to do it?

The value of the mounts is not just the serving automation but also they enforce not being able to "go behind" the .origin mapping.

So if some vhost has a file:// mount with the origin at /var/www/html, he should not be able to break out of that and come back to / by any variation of ../ or %2e%2e etc.  So they strictly segregate access to bits of the filesystem.

The new fops stuff holds the active fops in the "fop_fd" after .open()... the idea is you can either select the fops before open(), or in your fops[0].open() treat the fops as the start of an array of fops structs with a NULL .open sentinel at the end, and choose the right operations, calling through to his .open and he will store his fops pointer into the fop_fd, so it will be his read(), close() etc that is called on that fd subsequently.

To help that I pushed a patch adding a const char *path_prefix; member in the fops... you can set this to the left part of the filesystem namespace that fops is to be used with.

So, eg, if your mount says URL namespace "/user-manual" has a filesystem origin of "/zipped/user-manual", your fops[0].open can match it on, say, fops[2].path_prefix, which is "/zipped".  fops[2] open/read/close are then used for that fop_fd.

Possibly some of this is better done in lws rather than your fops.open()... feel free to suggest it if it starts to feel like that.


More information about the Libwebsockets mailing list