This commit is contained in:
Andy Green 2017-03-03 12:38:10 +08:00
parent 2f4dfa4ea7
commit 19cc7acb24
21 changed files with 1180 additions and 490 deletions

View file

@ -655,7 +655,7 @@ endif()
if (LWS_WITH_ZIP_FOPS)
list(APPEND SOURCES
lib/junzip.c)
lib/fops-zip.c)
endif()
# Add helper files for Windows.
@ -1174,6 +1174,7 @@ if (NOT LWS_WITHOUT_TESTAPPS)
set(TEST_SERVER_DATA
"${PROJECT_SOURCE_DIR}/test-server/favicon.ico"
"${PROJECT_SOURCE_DIR}/test-server/leaf.jpg"
"${PROJECT_SOURCE_DIR}/test-server/candide.zip"
"${PROJECT_SOURCE_DIR}/test-server/libwebsockets.org-logo.png"
"${PROJECT_SOURCE_DIR}/test-server/lws-common.js"
"${PROJECT_SOURCE_DIR}/test-server/test.html")

View file

@ -120,6 +120,34 @@ the send pipe on the connection is choked but no ack will ever come, so the
dead connection will never become writeable. To cover that, you can use TCP
keepalives (see later in this document) or pings.
@section gzip Serving from inside a zip file
Lws now supports serving gzipped files from inside a zip container. Thanks to
Per Bothner for contributing the code.
This has the advtantage that if the client can accept GZIP encoding, lws can
simply send the gzip-compressed file from inside the zip file with no further
processing, saving time and bandwidth.
In the case the client can't understand gzip compression, lws automatically
decompressed the file and sends it normally.
Clients with limited storage and RAM will find this useful; the memory needed
for the inflate case is constrained so that only one input buffer at a time
is ever in memory.
To use this feature, ensure LWS_WITH_ZIP_FOPS is enabled at CMake (it is by
default).
`libwebsockets-test-server-v2.0` includes a mount using this technology
already, run that test server and navigate to http://localhost:7681/ziptest/candide.html
This will serve the book Candide in html, together with two jpgs, all from
inside a .zip file in /usr/[local/]share-libwebsockets-test-server/candide.zip
Usage is otherwise automatic, if you arrange a mount that points to the zipfile,
eg, "/ziptest" -> "mypath/test.zip", then URLs like `/ziptest/index.html` will be
servied from `index.html` inside `mypath/test.zip`
@section frags Fragmented messages
@ -347,30 +375,51 @@ and then can use helpers to also leverage these platform-independent
file handling apis
```
static inline lws_fop_fd_t
lws_fop_fd_t
`lws_plat_file_open`(struct lws_plat_file_ops *fops, const char *filename,
lws_filepos_t *filelen, lws_fop_flags_t *flags)
static inline int
lws_fop_flags_t *flags)
int
`lws_plat_file_close`(lws_fop_fd_t fop_fd)
static inline unsigned long
unsigned long
`lws_plat_file_seek_cur`(lws_fop_fd_t fop_fd, lws_fileofs_t offset)
static inline int
int
`lws_plat_file_read`(lws_fop_fd_t fop_fd, lws_filepos_t *amount,
uint8_t *buf, lws_filepos_t len)
static inline int
int
`lws_plat_file_write`(lws_fop_fd_t fop_fd, lws_filepos_t *amount,
uint8_t *buf, lws_filepos_t len )
```
Generic helpers are provided which provide access to generic fops information or
call through to the above fops
```
lws_filepos_t
lws_vfs_tell(lws_fop_fd_t fop_fd);
lws_filepos_t
lws_vfs_get_length(lws_fop_fd_t fop_fd);
uint32_t
lws_vfs_get_mod_time(lws_fop_fd_t fop_fd);
lws_fileofs_t
lws_vfs_file_seek_set(lws_fop_fd_t fop_fd, lws_fileofs_t offset);
lws_fileofs_t
lws_vfs_file_seek_end(lws_fop_fd_t fop_fd, lws_fileofs_t offset);
```
The user code can also override or subclass the file operations, to either
wrap or replace them. An example is shown in test server.
### Changes from v2.1 and before fops
There are three changes:
There are several changes:
1) Pre-2.2 fops directly used platform file descriptors. Current fops returns and accepts a wrapper type lws_fop_fd_t which is a pointer to a malloc'd struct containing information specific to the filesystem implementation.
@ -378,6 +427,19 @@ There are three changes:
3) Everything is wrapped in typedefs. See lws-plat-unix.c for examples of how to implement.
4) Position in the file, File Length, and a copy of Flags left after open are now generically held in the fop_fd.
VFS implementation must set and manage this generic information now. See the implementations in lws-plat-unix.c for
examples.
5) The file length is no longer set at a pointer provided by the open() fop. The api `lws_vfs_get_length()` is provided to
get the file length after open.
6) If your file namespace is virtual, ie, is not reachable by platform fops directly, you must set LWS_FOP_FLAG_VIRTUAL
on the flags during open.
7) There is an optional `mod_time` uint32_t member in the generic fop_fd. If you are able to set it during open, you
should indicate it by setting `LWS_FOP_FLAG_MOD_TIME_VALID` on the flags.
@section ecdh ECDH Support
ECDH Certs are now supported. Enable the CMake option

View file

@ -150,7 +150,8 @@ lws_protocol_init(struct lws_context *context)
for (n = 0; n < vh->count_protocols; n++) {
wsi.protocol = &vh->protocols[n];
if (!vh->protocols[n].name)
continue;
pvo = lws_vhost_protocol_options(vh,
vh->protocols[n].name);
if (pvo) {
@ -403,7 +404,11 @@ lws_create_vhost(struct lws_context *context,
}
#endif
if (info->options & LWS_SERVER_OPTION_EXPLICIT_VHOSTS)
if (
#ifdef LWS_WITH_PLUGINS
(context->plugin_list) ||
#endif
info->options & LWS_SERVER_OPTION_EXPLICIT_VHOSTS)
vh->protocols = lwsp;
else {
vh->protocols = info->protocols;
@ -571,6 +576,7 @@ LWS_VISIBLE struct lws_context *
lws_create_context(struct lws_context_creation_info *info)
{
struct lws_context *context = NULL;
struct lws_plat_file_ops *prev;
#ifndef LWS_NO_DAEMONIZE
int pid_daemon = get_daemonize_pid();
#endif
@ -621,20 +627,34 @@ lws_create_context(struct lws_context_creation_info *info)
/* default to just the platform fops implementation */
context->fops_default[0].open = _lws_plat_file_open;
context->fops_default[0].close = _lws_plat_file_close;
context->fops_default[0].seek_cur = _lws_plat_file_seek_cur;
context->fops_default[0].read = _lws_plat_file_read;
context->fops_default[0].write = _lws_plat_file_write;
context->fops_default[0].path_prefix = "/";
context->fops_platform.open = _lws_plat_file_open;
context->fops_platform.close = _lws_plat_file_close;
context->fops_platform.seek_cur = _lws_plat_file_seek_cur;
context->fops_platform.read = _lws_plat_file_read;
context->fops_platform.write = _lws_plat_file_write;
context->fops_platform.fi[0].sig = NULL;
// context->fops_default[1].open is already NULL from zalloc
/*
* arrange a linear linked-list of fops starting from context->fops
*
* platform fops
* [ -> fops_zip (copied into context so .next settable) ]
* [ -> info->fops ]
*/
/* it can be overridden from context creation info */
context->fops = &context->fops_platform;
prev = (struct lws_plat_file_ops *)context->fops;
#if defined(LWS_WITH_ZIP_FOPS)
/* make a soft copy so we can set .next */
context->fops_zip = fops_zip;
prev->next = &context->fops_zip;
prev = (struct lws_plat_file_ops *)prev->next;
#endif
/* if user provided fops, tack them on the end of the list */
if (info->fops)
context->fops = info->fops;
else
context->fops = &context->fops_default[0];
prev->next = info->fops;
context->reject_service_keywords = info->reject_service_keywords;
if (info->external_baggage_free_on_destroy)

667
lib/fops-zip.c Normal file
View file

@ -0,0 +1,667 @@
/*
* libwebsockets - small server side websockets and web server implementation
*
* Original code used in this source file:
*
* https://github.com/PerBothner/DomTerm.git @912add15f3d0aec
*
* ./lws-term/io.c
* ./lws-term/junzip.c
*
* Copyright (C) 2017 Per Bothner <per@bothner.com>
*
* MIT License
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* ( copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*
*
* lws rewrite:
*
* Copyright (C) 2017 Andy Green <andy@warmcat.com>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation:
* version 2.1 of the License.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
* MA 02110-1301 USA
*/
#include "private-libwebsockets.h"
#include <zlib.h>
/*
* This code works with zip format containers which may have files compressed
* with gzip deflate (type 8) or store uncompressed (type 0).
*
* Linux zip produces such zipfiles by default, eg
*
* $ zip ../myzip.zip file1 file2 file3
*/
#define ZIP_COMPRESSION_METHOD_STORE 0
#define ZIP_COMPRESSION_METHOD_DEFLATE 8
typedef struct {
lws_filepos_t filename_start;
uint32_t crc32;
uint32_t comp_size;
uint32_t uncomp_size;
uint32_t offset;
uint32_t mod_time;
uint16_t filename_len;
uint16_t extra;
uint16_t method;
uint16_t file_com_len;
} lws_fops_zip_hdr_t;
typedef struct {
struct lws_fop_fd fop_fd; /* MUST BE FIRST logical fop_fd into
* file inside zip: fops_zip fops */
lws_fop_fd_t zip_fop_fd; /* logical fop fd on to zip file
* itself: using platform fops */
lws_fops_zip_hdr_t hdr;
z_stream inflate;
lws_filepos_t content_start;
lws_filepos_t exp_uncomp_pos;
union {
uint8_t trailer8[8];
uint32_t trailer32[2];
} u;
uint8_t rbuf[128]; /* decompression chunk size */
int entry_count;
unsigned int decompress:1; /* 0 = direct from file */
unsigned int add_gzip_container:1;
} *lws_fops_zip_t;
struct lws_plat_file_ops fops_zip;
#define fop_fd_to_priv(FD) ((lws_fops_zip_t)(FD))
static const uint8_t hd[] = { 31, 139, 8, 0, 0, 0, 0, 0, 0, 3 };
enum {
ZC_SIGNATURE = 0,
ZC_VERSION_MADE_BY = 4,
ZC_VERSION_NEEDED_TO_EXTRACT = 6,
ZC_GENERAL_PURPOSE_BIT_FLAG = 8,
ZC_COMPRESSION_METHOD = 10,
ZC_LAST_MOD_FILE_TIME = 12,
ZC_LAST_MOD_FILE_DATE = 14,
ZC_CRC32 = 16,
ZC_COMPRESSED_SIZE = 20,
ZC_UNCOMPRESSED_SIZE = 24,
ZC_FILE_NAME_LENGTH = 28,
ZC_EXTRA_FIELD_LENGTH = 30,
ZC_FILE_COMMENT_LENGTH = 32,
ZC_DISK_NUMBER_START = 34,
ZC_INTERNAL_FILE_ATTRIBUTES = 36,
ZC_EXTERNAL_FILE_ATTRIBUTES = 38,
ZC_REL_OFFSET_LOCAL_HEADER = 42,
ZC_DIRECTORY_LENGTH = 46,
ZE_SIGNATURE_OFFSET = 0,
ZE_DESK_NUMBER = 4,
ZE_CENTRAL_DIRECTORY_DISK_NUMBER = 6,
ZE_NUM_ENTRIES_THIS_DISK = 8,
ZE_NUM_ENTRIES = 10,
ZE_CENTRAL_DIRECTORY_SIZE = 12,
ZE_CENTRAL_DIR_OFFSET = 16,
ZE_ZIP_COMMENT_LENGTH = 20,
ZE_DIRECTORY_LENGTH = 22,
ZL_REL_OFFSET_CONTENT = 28,
ZL_HEADER_LENGTH = 30,
LWS_FZ_ERR_SEEK_END_RECORD = 1,
LWS_FZ_ERR_READ_END_RECORD,
LWS_FZ_ERR_END_RECORD_MAGIC,
LWS_FZ_ERR_END_RECORD_SANITY,
LWS_FZ_ERR_CENTRAL_SEEK,
LWS_FZ_ERR_CENTRAL_READ,
LWS_FZ_ERR_CENTRAL_SANITY,
LWS_FZ_ERR_NAME_TOO_LONG,
LWS_FZ_ERR_NAME_READ,
LWS_FZ_ERR_CONTENT_SANITY,
LWS_FZ_ERR_CONTENT_SEEK,
LWS_FZ_ERR_SCAN_SEEK,
LWS_FZ_ERR_NOT_FOUND,
LWS_FZ_ERR_ZLIB_INIT,
LWS_FZ_ERR_READ_CONTENT,
LWS_FZ_ERR_SEEK_COMPRESSED,
};
static uint16_t
get_u16(void *p)
{
const uint8_t *c = (const uint8_t *)p;
return (uint16_t)((c[0] | (c[1] << 8)));
}
static uint32_t
get_u32(void *p)
{
const uint8_t *c = (const uint8_t *)p;
return (uint32_t)((c[0] | (c[1] << 8) | (c[2] << 16) | (c[3] << 24)));
}
int
lws_fops_zip_scan(lws_fops_zip_t priv, const char *name, int len)
{
lws_filepos_t amount;
uint8_t buf[64];
int i;
if (lws_vfs_file_seek_end(priv->zip_fop_fd, -ZE_DIRECTORY_LENGTH) < 0)
return LWS_FZ_ERR_SEEK_END_RECORD;
if (lws_vfs_file_read(priv->zip_fop_fd, &amount, buf,
ZE_DIRECTORY_LENGTH))
return LWS_FZ_ERR_READ_END_RECORD;
if (amount != ZE_DIRECTORY_LENGTH)
return LWS_FZ_ERR_READ_END_RECORD;
/*
* We require the zip to have the last record right at the end
* Linux zip always does this if no zip comment.
*/
if (buf[0] != 'P' || buf[1] != 'K' || buf[2] != 5 || buf[3] != 6)
return LWS_FZ_ERR_END_RECORD_MAGIC;
i = get_u16(buf + ZE_NUM_ENTRIES);
if (get_u16(buf + ZE_DESK_NUMBER) ||
get_u16(buf + ZE_CENTRAL_DIRECTORY_DISK_NUMBER) ||
i != get_u16(buf + ZE_NUM_ENTRIES_THIS_DISK))
return LWS_FZ_ERR_END_RECORD_SANITY;
/* end record is OK... look for our file in the central dir */
if (lws_vfs_file_seek_set(priv->zip_fop_fd,
get_u32(buf + ZE_CENTRAL_DIR_OFFSET)) < 0)
return LWS_FZ_ERR_CENTRAL_SEEK;
while (i--) {
priv->content_start = lws_vfs_tell(priv->zip_fop_fd);
if (lws_vfs_file_read(priv->zip_fop_fd, &amount, buf,
ZC_DIRECTORY_LENGTH))
return LWS_FZ_ERR_CENTRAL_READ;
if (amount != ZC_DIRECTORY_LENGTH)
return LWS_FZ_ERR_CENTRAL_READ;
if (get_u32(buf + ZC_SIGNATURE) != 0x02014B50)
return LWS_FZ_ERR_CENTRAL_SANITY;
lwsl_debug("cstart 0x%lx\n", priv->content_start);
priv->hdr.filename_len = get_u16(buf + ZC_FILE_NAME_LENGTH);
priv->hdr.extra = get_u16(buf + ZC_EXTRA_FIELD_LENGTH);
priv->hdr.filename_start = lws_vfs_tell(priv->zip_fop_fd);
priv->hdr.method = get_u16(buf + ZC_COMPRESSION_METHOD);
priv->hdr.crc32 = get_u32(buf + ZC_CRC32);
priv->hdr.comp_size = get_u32(buf + ZC_COMPRESSED_SIZE);
priv->hdr.uncomp_size = get_u32(buf + ZC_UNCOMPRESSED_SIZE);
priv->hdr.offset = get_u32(buf + ZC_REL_OFFSET_LOCAL_HEADER);
priv->hdr.mod_time = get_u32(buf + ZC_LAST_MOD_FILE_TIME);
priv->hdr.file_com_len = get_u16(buf + ZC_FILE_COMMENT_LENGTH);
if (priv->hdr.filename_len != len)
goto next;
if (len >= sizeof(buf) - 1)
return LWS_FZ_ERR_NAME_TOO_LONG;
if (priv->zip_fop_fd->fops->LWS_FOP_READ(priv->zip_fop_fd,
&amount, buf, len))
return LWS_FZ_ERR_NAME_READ;
if (amount != len)
return LWS_FZ_ERR_NAME_READ;
buf[len] = '\0';
lwsl_debug("check %s vs %s\n", buf, name);
if (strcmp((const char *)buf, name))
goto next;
/* we found a match */
lws_vfs_file_seek_set(priv->zip_fop_fd, priv->hdr.offset);
if (priv->zip_fop_fd->fops->LWS_FOP_READ(priv->zip_fop_fd,
&amount, buf,
ZL_HEADER_LENGTH))
return LWS_FZ_ERR_NAME_READ;
if (amount != ZL_HEADER_LENGTH)
return LWS_FZ_ERR_NAME_READ;
priv->content_start = priv->hdr.offset +
ZL_HEADER_LENGTH +
priv->hdr.filename_len +
get_u16(buf + ZL_REL_OFFSET_CONTENT);
lwsl_debug("content supposed to start at 0x%lx\n",
priv->content_start);
if (priv->content_start > priv->zip_fop_fd->len)
return LWS_FZ_ERR_CONTENT_SANITY;
if (lws_vfs_file_seek_set(priv->zip_fop_fd,
priv->content_start) < 0)
return LWS_FZ_ERR_CONTENT_SEEK;
/* we are aligned at the start of the content */
priv->exp_uncomp_pos = 0;
return 0;
next:
if (i && lws_vfs_file_seek_set(priv->zip_fop_fd,
priv->content_start +
ZC_DIRECTORY_LENGTH +
priv->hdr.filename_len +
priv->hdr.extra +
priv->hdr.file_com_len) < 0)
return LWS_FZ_ERR_SCAN_SEEK;
}
return LWS_FZ_ERR_NOT_FOUND;
}
static int
lws_fops_zip_reset_inflate(lws_fops_zip_t priv)
{
if (priv->decompress)
inflateEnd(&priv->inflate);
priv->inflate.zalloc = Z_NULL;
priv->inflate.zfree = Z_NULL;
priv->inflate.opaque = Z_NULL;
priv->inflate.avail_in = 0;
priv->inflate.next_in = Z_NULL;
if (inflateInit2(&priv->inflate, -MAX_WBITS) != Z_OK) {
lwsl_err("inflate init failed\n");
return LWS_FZ_ERR_ZLIB_INIT;
}
if (lws_vfs_file_seek_set(priv->zip_fop_fd, priv->content_start) < 0)
return LWS_FZ_ERR_CONTENT_SEEK;
priv->exp_uncomp_pos = 0;
return 0;
}
static lws_fop_fd_t
lws_fops_zip_open(const struct lws_plat_file_ops *fops, const char *vfs_path,
const char *vpath, lws_fop_flags_t *flags)
{
lws_fop_flags_t local_flags = 0;
lws_fops_zip_t priv;
char rp[192];
int m;
/*
* vpath points at the / after the fops signature in vfs_path, eg
* with a vfs_path "/var/www/docs/manual.zip/index.html", vpath
* will come pointing at "/index.html"
*/
priv = lws_zalloc(sizeof(*priv));
if (!priv)
return NULL;
priv->fop_fd.fops = &fops_zip;
m = sizeof(rp) - 1;
if ((vpath - vfs_path - 1) < m)
m = vpath - vfs_path - 1;
strncpy(rp, vfs_path, m);
rp[m] = '\0';
/* open the zip file itself using the incoming fops, not fops_zip */
priv->zip_fop_fd = fops->LWS_FOP_OPEN(fops, rp, NULL, &local_flags);
if (!priv->zip_fop_fd) {
lwsl_err("unable to open zip %s\n", rp);
goto bail1;
}
if (*vpath == '/')
vpath++;
m = lws_fops_zip_scan(priv, vpath, strlen(vpath));
if (m) {
lwsl_err("unable to find record matching '%s' %d\n", vpath, m);
goto bail2;
}
/* the directory metadata tells us modification time, so pass it on */
priv->fop_fd.mod_time = priv->hdr.mod_time;
*flags |= LWS_FOP_FLAG_MOD_TIME_VALID | LWS_FOP_FLAG_VIRTUAL;
priv->fop_fd.flags = *flags;
/* The zip fop_fd is left pointing at the start of the content.
*
* 1) Content could be uncompressed (STORE), and we can always serve
* that directly
*
* 2) Content could be compressed (GZIP), and the client can handle
* receiving GZIP... we can wrap it in a GZIP header and trailer
* and serve the content part directly. The flag indicating we
* are providing GZIP directly is set so lws will send the right
* headers.
*
* 3) Content could be compressed (GZIP) but the client can't handle
* receiving GZIP... we can decompress it and serve as it is
* inflated piecemeal.
*
* 4) Content may be compressed some unknown way... fail
*
*/
if (priv->hdr.method == ZIP_COMPRESSION_METHOD_STORE) {
/*
* it is stored uncompressed, leave it indicated as
* uncompressed, and just serve it from inside the
* zip with no gzip container;
*/
lwsl_info("direct zip serving (stored)\n");
priv->fop_fd.len = priv->hdr.uncomp_size;
return &priv->fop_fd;
}
if ((*flags & LWS_FOP_FLAG_COMPR_ACCEPTABLE_GZIP) &&
priv->hdr.method == ZIP_COMPRESSION_METHOD_DEFLATE) {
/*
* We can serve the gzipped file contents directly as gzip
* from inside the zip container; client says it is OK.
*
* To convert to standalone gzip, we have to add a 10-byte
* constant header and a variable 8-byte trailer around the
* content.
*
* The 8-byte trailer is prepared now and held in the priv.
*/
lwsl_info("direct zip serving (gzipped)\n");
priv->fop_fd.len = sizeof(hd) + priv->hdr.comp_size +
sizeof(priv->u);
if (lws_is_be()) {
uint8_t *p = priv->u.trailer8;
*p++ = (uint8_t)priv->hdr.crc32;
*p++ = (uint8_t)(priv->hdr.crc32 >> 8);
*p++ = (uint8_t)(priv->hdr.crc32 >> 16);
*p++ = (uint8_t)(priv->hdr.crc32 >> 24);
*p++ = (uint8_t)priv->hdr.uncomp_size;
*p++ = (uint8_t)(priv->hdr.uncomp_size >> 8);
*p++ = (uint8_t)(priv->hdr.uncomp_size >> 16);
*p = (uint8_t)(priv->hdr.uncomp_size >> 24);
} else {
priv->u.trailer32[0] = priv->hdr.crc32;
priv->u.trailer32[1] = priv->hdr.uncomp_size;
}
*flags |= LWS_FOP_FLAG_COMPR_IS_GZIP;
priv->fop_fd.flags = *flags;
priv->add_gzip_container = 1;
return &priv->fop_fd;
}
if (priv->hdr.method == ZIP_COMPRESSION_METHOD_DEFLATE) {
/* we must decompress it to serve it */
lwsl_info("decompressed zip serving\n");
priv->fop_fd.len = priv->hdr.uncomp_size;
if (lws_fops_zip_reset_inflate(priv)) {
lwsl_err("inflate init failed\n");
goto bail2;
}
priv->decompress = 1;
return &priv->fop_fd;
}
/* we can't handle it ... */
lwsl_err("zipped file %s compressed in unknown way (%d)\n", vfs_path,
priv->hdr.method);
bail2:
lws_vfs_file_close(&priv->zip_fop_fd);
bail1:
free(priv);
return NULL;
}
/* ie, we are closing the fop_fd for the file inside the gzip */
static int
lws_fops_zip_close(lws_fop_fd_t *fd)
{
lws_fops_zip_t priv = fop_fd_to_priv(*fd);
if (priv->decompress)
inflateEnd(&priv->inflate);
lws_vfs_file_close(&priv->zip_fop_fd); /* close the gzip fop_fd */
free(priv);
*fd = NULL;
return 0;
}
static lws_fileofs_t
lws_fops_zip_seek_cur(lws_fop_fd_t fd, lws_fileofs_t offset_from_cur_pos)
{
fd->pos += offset_from_cur_pos;
return fd->pos;
}
static int
lws_fops_zip_read(lws_fop_fd_t fd, lws_filepos_t *amount, uint8_t *buf,
lws_filepos_t len)
{
lws_fops_zip_t priv = fop_fd_to_priv(fd);
lws_filepos_t ramount, rlen, cur = lws_vfs_tell(fd);
int ret;
if (priv->decompress) {
if (priv->exp_uncomp_pos != fd->pos) {
/*
* there has been a seek in the uncompressed fop_fd
* we have to restart the decompression and loop eating
* the decompressed data up to the seek point
*/
lwsl_info("seek in decompressed\n");
lws_fops_zip_reset_inflate(priv);
while (priv->exp_uncomp_pos != fd->pos) {
rlen = len;
if (rlen > fd->pos - priv->exp_uncomp_pos)
rlen = fd->pos - priv->exp_uncomp_pos;
if (lws_fops_zip_read(fd, amount, buf, rlen))
return LWS_FZ_ERR_SEEK_COMPRESSED;
}
*amount = 0;
}
priv->inflate.avail_out = len;
priv->inflate.next_out = buf;
spin:
if (!priv->inflate.avail_in) {
rlen = sizeof(priv->rbuf);
if (rlen > priv->hdr.comp_size -
(cur - priv->content_start))
rlen = priv->hdr.comp_size -
(priv->hdr.comp_size -
priv->content_start);
if (priv->zip_fop_fd->fops->LWS_FOP_READ(
priv->zip_fop_fd, &ramount, priv->rbuf,
rlen))
return LWS_FZ_ERR_READ_CONTENT;
cur += ramount;
priv->inflate.avail_in = ramount;
priv->inflate.next_in = priv->rbuf;
}
ret = inflate(&priv->inflate, Z_NO_FLUSH);
if (ret == Z_STREAM_ERROR)
return ret;
switch (ret) {
case Z_NEED_DICT:
ret = Z_DATA_ERROR;
/* and fall through */
case Z_DATA_ERROR:
case Z_MEM_ERROR:
return ret;
}
if (!priv->inflate.avail_in && priv->inflate.avail_out &&
cur != priv->content_start + priv->hdr.comp_size)
goto spin;
*amount = len - priv->inflate.avail_out;
priv->exp_uncomp_pos += *amount;
fd->pos += *amount;
return 0;
}
if (priv->add_gzip_container) {
lwsl_info("%s: gzip + container\n", __func__);
*amount = 0;
/* place the canned header at the start */
if (len && fd->pos < sizeof(hd)) {
rlen = sizeof(hd) - fd->pos;
if (rlen > len)
rlen = len;
/* provide stuff from canned header */
memcpy(buf, hd + fd->pos, rlen);
fd->pos += rlen;
buf += rlen;
len -= rlen;
*amount += rlen;
}
/* serve gzipped data direct from zipfile */
if (len && fd->pos >= sizeof(hd) &&
fd->pos < priv->hdr.comp_size + sizeof(hd)) {
rlen = priv->hdr.comp_size - (priv->zip_fop_fd->pos -
priv->content_start);
if (rlen > len)
rlen = len;
if (rlen &&
priv->zip_fop_fd->pos < (priv->hdr.comp_size +
priv->content_start)) {
if (lws_vfs_file_read(priv->zip_fop_fd,
&ramount, buf, rlen))
return LWS_FZ_ERR_READ_CONTENT;
*amount += ramount;
fd->pos += ramount; // virtual pos
buf += ramount;
len -= ramount;
}
}
/* place the prepared trailer at the end */
if (len && fd->pos >= priv->hdr.comp_size + sizeof(hd) &&
fd->pos < priv->hdr.comp_size + sizeof(hd) +
sizeof(priv->u)) {
cur = fd->pos - priv->hdr.comp_size - sizeof(hd);
rlen = sizeof(priv->u) - cur;
if (rlen > len)
rlen = len;
memcpy(buf, priv->u.trailer8 + cur, rlen);
*amount += rlen;
fd->pos += rlen;
}
return 0;
}
lwsl_info("%s: store\n", __func__);
if (len > priv->hdr.uncomp_size - (cur - priv->content_start))
len = priv->hdr.comp_size - (priv->hdr.comp_size -
priv->content_start);
if (priv->zip_fop_fd->fops->LWS_FOP_READ(priv->zip_fop_fd,
amount, buf, len))
return LWS_FZ_ERR_READ_CONTENT;
return 0;
}
struct lws_plat_file_ops fops_zip = {
lws_fops_zip_open,
lws_fops_zip_close,
lws_fops_zip_seek_cur,
lws_fops_zip_read,
NULL,
{ { ".zip/", 5 }, { ".jar/", 5 }, { ".war/", 5 } },
NULL,
};

View file

@ -1,267 +0,0 @@
// Unzip library by Per Bothner and Joonas Pihlajamaa.
// See junzip.h for license and details.
#include <stdlib.h>
#include <string.h>
#include <zlib.h>
#include "private-libwebsockets.h"
enum {
ZC_SIGNATURE = 0,
ZC_VERSION_MADE_BY = 4,
ZC_VERSION_NEEDED_TO_EXTRACT = 6,
ZC_GENERAL_PURPOSE_BIT_FLAG = 8,
ZC_COMPRESSION_METHOD = 10,
ZC_LAST_MOD_FILE_TIME = 12,
ZC_LAST_MOD_FILE_DATE = 14,
ZC_CRC32 = 16,
ZC_COMPRESSED_SIZE = 20,
ZC_UNCOMPRESSED_SIZE = 24,
ZC_FILE_NAME_LENGTH = 28,
ZC_EXTRA_FIELD_LENGTH = 30,
ZC_FILE_COMMENT_LENGTH = 32,
ZC_DISK_NUMBER_START = 34,
ZC_INTERNAL_FILE_ATTRIBUTES = 36,
ZC_EXTERNAL_FILE_ATTRIBUTES = 38,
ZC_RELATIVE_OFFSET_OF_LOCAL_HEADER = 42,
ZC_DIRECTORY_LENGTH = 46,
ZE_SIGNATURE_OFFSET = 0,
ZE_DESK_NUMBER = 4,
ZE_CENTRAL_DIRECTORY_DISK_NUMBER = 6,
ZE_NUM_ENTRIES_THIS_DISK = 8,
ZE_NUM_ENTRIES = 10,
ZE_CENTRAL_DIRECTORY_SIZE = 12,
ZE_CENTRAL_DIRECTORY_OFFSET = 16,
ZE_ZIP_COMMENT_LENGTH = 20,
ZE_DIRECTORY_LENGTH = 22,
};
static uint16_t
get_u16(void *p)
{
const uint8_t *c = (const uint8_t *)p;
return (uint16_t)((c[0] | (c[1] << 8)));
}
static uint32_t
get_u32(void *p)
{
const uint8_t *c = (const uint8_t *)p;
return (uint32_t)((c[0] | (c[1] << 8) | (c[2] << 16) | (c[3] << 24)));
}
static int
zf_seek_set(jzfile_t *zfile, size_t offset)
{
int new_position = offset;
if (new_position < 0 || new_position > zfile->length)
return -1;
zfile->position = new_position;
return 0;
}
static int
zf_seek_cur(jzfile_t *zfile, size_t offset)
{
int new_position = zfile->position + offset;
if (new_position < 0 || new_position > zfile->length)
return -1;
zfile->position = new_position;
return 0;
}
static int
zf_seek_end(jzfile_t *zfile, size_t offset)
{
int new_position = zfile->length + offset;
if (new_position < 0 || new_position > zfile->length)
return -1;
zfile->position = new_position;
return 0;
}
size_t
zf_read(jzfile_t *zfile, void *buf, size_t size)
{
size_t avail = zfile->length - zfile->position;
if (size > avail)
size = avail;
memcpy(buf, zfile->start + zfile->position, size);
zfile->position += size;
return size;
}
/* Read ZIP file end record. Will move within file. */
int
jzReadEndRecord(jzfile_t *zip)
{
unsigned char *ptr = zf_current(zip);
if (zf_seek_end(zip, -ZE_DIRECTORY_LENGTH))
return Z_ERRNO;
while (ptr[0] != 0x50 || ptr[1] != 0x4B || ptr[2] != 5 || ptr[3] != 6)
if (ptr-- == zip->start)
return Z_ERRNO;
zip->numEntries = get_u16(ptr + ZE_NUM_ENTRIES);
zip->centralDirectoryOffset= get_u32(ptr + ZE_CENTRAL_DIRECTORY_OFFSET);
if (get_u16(ptr + ZE_DESK_NUMBER) ||
get_u16(ptr + ZE_CENTRAL_DIRECTORY_DISK_NUMBER) ||
zip->numEntries != get_u16(ptr + ZE_NUM_ENTRIES_THIS_DISK))
return Z_ERRNO;
return Z_OK;
}
/* Read ZIP file global directory. Will move within file. */
int
jzReadCentralDirectory(jzfile_t *zip, jzcb_t callback)
{
jzfile_hdr_t h;
int i;
if (zf_seek_set(zip, zip->centralDirectoryOffset))
return Z_ERRNO;
for (i = 0; i < zip->numEntries; i++) {
unsigned char *ptr = zf_current(zip);
if (zf_available(zip) < ZC_DIRECTORY_LENGTH)
return Z_ERRNO;
zf_seek_cur(zip, ZC_DIRECTORY_LENGTH);
if (get_u32(ptr + ZC_SIGNATURE) != 0x02014B50)
return Z_ERRNO;
// Construct jzfile_hdr_t from global file h
h.compressionMethod = get_u16(ptr + ZC_COMPRESSION_METHOD);
h.crc32 = get_u32(ptr + ZC_CRC32);
h.compressedSize = get_u32(ptr + ZC_COMPRESSED_SIZE);
h.uncompressedSize = get_u32(ptr + ZC_UNCOMPRESSED_SIZE);
h.fileNameLength = get_u16(ptr + ZC_FILE_NAME_LENGTH);
h.extraFieldLength = get_u16(ptr + ZC_EXTRA_FIELD_LENGTH);
h.offset = get_u32(ptr + ZC_RELATIVE_OFFSET_OF_LOCAL_HEADER);
h.fileNameStart = zf_tell(zip);
if (zf_seek_cur(zip, h.fileNameLength + h.extraFieldLength +
get_u16(ptr + ZC_FILE_COMMENT_LENGTH)))
return Z_ERRNO;
if (!callback(zip, i, &h))
break; // end if callback returns zero
}
return Z_OK;
}
int jzSeekData(jzfile_t *zip, jzfile_hdr_t *entry)
{
size_t offset = entry->offset;
offset += ZIP_LOCAL_FILE_HEADER_LENGTH;
offset += entry->fileNameLength + entry->extraFieldLength;
if (offset < 0 || offset > zip->length)
return Z_STREAM_END;
zip->position = offset;
return Z_OK;
}
/* Read data from file stream, described by h, to preallocated buffer */
int
jzReadData(jzfile_t *zip, jzfile_hdr_t *h, void *buffer)
{
unsigned char *bytes = (unsigned char *)buffer;
long compressedLeft, uncompressedLeft;
z_stream strm;
int ret;
switch (h->compressionMethod) {
case 0: /* Store - just read it */
if (zf_read(zip, buffer, h->uncompressedSize) <
h->uncompressedSize)
return Z_ERRNO;
break;
case 8: /* Deflate - using zlib */
strm.zalloc = Z_NULL;
strm.zfree = Z_NULL;
strm.opaque = Z_NULL;
strm.avail_in = 0;
strm.next_in = Z_NULL;
/*
* Use inflateInit2 with negative window bits to
* indicate raw data
*/
if ((ret = inflateInit2(&strm, -MAX_WBITS)) != Z_OK)
return ret; /* Zlib errors are negative */
/* Inflate compressed data */
for (compressedLeft = h->compressedSize,
uncompressedLeft = h->uncompressedSize;
compressedLeft && uncompressedLeft && ret != Z_STREAM_END;
compressedLeft -= strm.avail_in) {
/* Read next chunk */
unsigned char *ptr = zf_current(zip);
strm.avail_in = compressedLeft;
zf_seek_cur(zip, compressedLeft);
if (strm.avail_in == 0) {
inflateEnd(&strm);
return Z_ERRNO;
}
strm.next_in = ptr;
strm.avail_out = uncompressedLeft;
strm.next_out = bytes;
compressedLeft -= strm.avail_in;
/* inflate will change avail_in */
ret = inflate(&strm, Z_NO_FLUSH);
if (ret == Z_STREAM_ERROR)
return ret;
switch (ret) {
case Z_NEED_DICT:
ret = Z_DATA_ERROR;
/* and fall through */
case Z_DATA_ERROR: case Z_MEM_ERROR:
(void)inflateEnd(&strm);
return ret;
}
/* bytes uncompressed */
bytes += uncompressedLeft - strm.avail_out;
uncompressedLeft = strm.avail_out;
}
inflateEnd(&strm);
break;
default:
return Z_ERRNO;
}
return Z_OK;
}

View file

@ -455,7 +455,8 @@ lejp_vhosts_cb(struct lejp_ctx *ctx, char reason)
"cgi://",
">http://",
">https://",
"callback://"
"callback://",
"gzip://",
};
if (!a->fresh_mount)

View file

@ -170,7 +170,7 @@ lws_libev_accept(struct lws *new_wsi, lws_sock_file_fd_type desc)
if (!LWS_LIBEV_ENABLED(context))
return;
if (wsi->mode == LWSCM_RAW_FILEDESC)
if (new_wsi->mode == LWSCM_RAW_FILEDESC)
fd = desc.filefd;
else
fd = desc.sockfd;

View file

@ -220,9 +220,7 @@ lws_close_free_wsi(struct lws *wsi, enum lws_close_status reason)
wsi->protocol->callback(wsi,
LWS_CALLBACK_RAW_CLOSE_FILE,
wsi->user_space, NULL, 0);
lws_free_wsi(wsi);
return;
goto async_close;
}
#ifdef LWS_WITH_CGI
@ -264,8 +262,7 @@ lws_close_free_wsi(struct lws *wsi, enum lws_close_status reason)
if (wsi->mode == LWSCM_HTTP_SERVING_ACCEPTED &&
wsi->u.http.fop_fd != NULL) {
lws_vfs_file_close(wsi->u.http.fop_fd);
wsi->u.http.fop_fd = NULL;
lws_vfs_file_close(&wsi->u.http.fop_fd);
wsi->vhost->protocols->callback(wsi,
LWS_CALLBACK_CLOSED_HTTP, wsi->user_space, NULL, 0);
wsi->told_user_closed = 1;
@ -606,6 +603,7 @@ just_kill_connection:
LWS_EXT_CB_DESTROY_ANY_WSI_CLOSING, NULL, 0) < 0)
lwsl_warn("ext destroy wsi failed\n");
async_close:
wsi->socket_is_permanently_unusable = 1;
#ifdef LWS_USE_LIBUV
@ -971,32 +969,105 @@ lws_callback_vhost_protocols(struct lws *wsi, int reason, void *in, int len)
LWS_VISIBLE LWS_EXTERN void
lws_set_fops(struct lws_context *context, struct lws_plat_file_ops *fops)
{
memcpy(&context->fops_default, fops, sizeof *fops);
memcpy(&context->fops, fops, sizeof *fops);
}
LWS_VISIBLE LWS_EXTERN const struct lws_plat_file_ops *
lws_select_fops_by_vfs_path(const struct lws_context *context, const char *vfs_path)
LWS_VISIBLE LWS_EXTERN lws_filepos_t
lws_vfs_tell(lws_fop_fd_t fop_fd)
{
const struct lws_plat_file_ops *fops = context->fops;
int hit = -1, n = 0, matchlen = 0, len;
return fop_fd->pos;
}
while (fops->open) {
len = strlen(fops->path_prefix);
LWS_VISIBLE LWS_EXTERN lws_filepos_t
lws_vfs_get_length(lws_fop_fd_t fop_fd)
{
return fop_fd->len;
}
if (!strncmp(vfs_path, fops->path_prefix, len))
if (len > matchlen) {
hit = n;
matchlen = len;
LWS_VISIBLE LWS_EXTERN uint32_t
lws_vfs_get_mod_time(lws_fop_fd_t fop_fd)
{
return fop_fd->mod_time;
}
LWS_VISIBLE lws_fileofs_t
lws_vfs_file_seek_set(lws_fop_fd_t fop_fd, lws_fileofs_t offset)
{
lws_fileofs_t ofs;
lwsl_debug("%s: seeking to %ld, len %ld\n", __func__, offset, fop_fd->len);
ofs = fop_fd->fops->LWS_FOP_SEEK_CUR(fop_fd, offset - fop_fd->pos);
lwsl_debug("%s: result %ld, fop_fd pos %ld\n", __func__, ofs, fop_fd->pos);
return ofs;
}
LWS_VISIBLE lws_fileofs_t
lws_vfs_file_seek_end(lws_fop_fd_t fop_fd, lws_fileofs_t offset)
{
return fop_fd->fops->LWS_FOP_SEEK_CUR(fop_fd, fop_fd->len + fop_fd->pos + offset);
}
const struct lws_plat_file_ops *
lws_vfs_select_fops(const struct lws_plat_file_ops *fops, const char *vfs_path,
const char **vpath)
{
const struct lws_plat_file_ops *pf;
const char *p = vfs_path;
int n;
*vpath = NULL;
/* no non-platform fops, just use that */
if (!fops->next)
return fops;
/*
* scan the vfs path looking for indications we are to be
* handled by a specific fops
*/
while (*p) {
if (*p != '/') {
p++;
continue;
}
/* the first one is always platform fops, so skip */
pf = fops->next;
while (pf) {
n = 0;
while (n < ARRAY_SIZE(pf->fi) && pf->fi[n].sig) {
if (p >= vfs_path + pf->fi[n].len)
if (!strncmp(p - (pf->fi[n].len - 1),
pf->fi[n].sig,
pf->fi[n].len - 1)) {
*vpath = p + 1;
return pf;
}
n++;
}
fops++;
pf = pf->next;
}
p++;
}
if (hit < 0)
return context->fops_default;
return &context->fops[hit];
return fops;
}
LWS_VISIBLE LWS_EXTERN lws_fop_fd_t LWS_WARN_UNUSED_RESULT
lws_vfs_file_open(const struct lws_plat_file_ops *fops, const char *vfs_path,
lws_fop_flags_t *flags)
{
const char *vpath;
const struct lws_plat_file_ops *selected = lws_vfs_select_fops(
fops, vfs_path, &vpath);
return selected->LWS_FOP_OPEN(fops, vfs_path, vpath, flags);
}
/**
* lws_now_secs() - seconds since 1970-1-1
*
@ -1396,7 +1467,7 @@ lws_union_transition(struct lws *wsi, enum connection_mode mode)
LWS_VISIBLE struct lws_plat_file_ops *
lws_get_fops(struct lws_context *context)
{
return &context->fops_default[0];
return (struct lws_plat_file_ops *)context->fops;
}
LWS_VISIBLE LWS_EXTERN struct lws_context *

View file

@ -33,6 +33,12 @@ extern "C" {
#include <stdarg.h>
#endif
static inline int lws_is_be(void) {
const int probe = ~0xff;
return *(const char *)&probe;
}
#if defined(LWS_WITH_ESP8266)
struct sockaddr_in;
#define LWS_POSIX 0
@ -1816,9 +1822,7 @@ struct lws_context_creation_info {
* by a sentinel with NULL .open.
*
* If NULL, lws provides just the platform file operations struct for
* backwards compatibility. If set to point to an array of fops
* structs, lws_select_fops_by_vfs_path() will select the best match
* comparing the left of vfs_path to each fops .path_prefix.
* backwards compatibility.
*/
/* Add new things just above here ---^
@ -2559,6 +2563,7 @@ lws_get_mimetype(const char *file, const struct lws_http_mount *m);
LWS_VISIBLE LWS_EXTERN int
lws_serve_http_file(struct lws *wsi, const char *file, const char *content_type,
const char *other_headers, int other_headers_len);
LWS_VISIBLE LWS_EXTERN int
lws_serve_http_file_fragment(struct lws *wsi);
//@}
@ -4268,29 +4273,27 @@ lws_cgi_kill(struct lws *wsi);
#if defined(LWS_WITH_ESP32)
/* sdk preprocessor defs? compiler issue? gets confused with member names */
#define LWS_FOP_OPEN _open
#define LWS_FOP_CLOSE _close
#define LWS_FOP_SEEK_CUR _seek_cur
#define LWS_FOP_READ _read
#define LWS_FOP_WRITE _write
#define LWS_FOP_OPEN _open
#define LWS_FOP_CLOSE _close
#define LWS_FOP_SEEK_CUR _seek_cur
#define LWS_FOP_READ _read
#define LWS_FOP_WRITE _write
#else
#define LWS_FOP_OPEN open
#define LWS_FOP_CLOSE close
#define LWS_FOP_SEEK_CUR seek_cur
#define LWS_FOP_READ read
#define LWS_FOP_WRITE write
#define LWS_FOP_OPEN open
#define LWS_FOP_CLOSE close
#define LWS_FOP_SEEK_CUR seek_cur
#define LWS_FOP_READ read
#define LWS_FOP_WRITE write
#endif
#define LWS_FOP_FLAGS_MASK ((1 << 23) - 1)
#define LWS_FOP_FLAG_COMPR_ACCEPTABLE_GZIP (1 << 24)
#define LWS_FOP_FLAG_COMPR_IS_GZIP (1 << 25)
#define LWS_FOP_FLAG_MOD_TIME_VALID (1 << 26)
#define LWS_FOP_FLAG_VIRTUAL (1 << 27)
struct lws_plat_file_ops;
struct lws_fop_fd {
lws_filefd_type fd;
const struct lws_plat_file_ops *fops;
void *filesystem_priv;
};
#if defined(WIN32) || defined(_WIN32)
/* ... */
#if !defined(ssize_t)
@ -4313,26 +4316,49 @@ typedef unsigned char uint8_t;
#endif
#endif
typedef struct lws_fop_fd *lws_fop_fd_t;
typedef size_t lws_filepos_t;
typedef ssize_t lws_fileofs_t;
typedef uint32_t lws_fop_flags_t;
struct lws_fop_fd {
lws_filefd_type fd;
/**< real file descriptor related to the file... */
const struct lws_plat_file_ops *fops;
/**< fops that apply to this fop_fd */
void *filesystem_priv;
/**< ignored by lws; owned by the fops handlers */
lws_filepos_t pos;
/**< generic "position in file" */
lws_filepos_t len;
/**< generic "length of file" */
lws_fop_flags_t flags;
/**< copy of the returned flags */
uint32_t mod_time;
/**< optional "modification time of file", only valid if .open()
* set the LWS_FOP_FLAG_MOD_TIME_VALID flag */
};
typedef struct lws_fop_fd *lws_fop_fd_t;
struct lws_fops_index {
const char *sig; /* NULL or vfs signature, eg, ".zip/" */
uint8_t len; /* length of above string */
};
struct lws_plat_file_ops {
lws_fop_fd_t (*LWS_FOP_OPEN)(const struct lws_plat_file_ops *fops,
const char *filename,
lws_filepos_t *filelen,
const char *filename, const char *vpath,
lws_fop_flags_t *flags);
/**< Open file (always binary access if plat supports it)
* filelen is filled on exit to be the length of the file
* vpath may be NULL, or if the fops understands it, the point at which
* the filename's virtual part starts.
* *flags & LWS_FOP_FLAGS_MASK should be set to O_RDONLY or O_RDWR.
* If the file may be gzip-compressed,
* LWS_FOP_FLAG_COMPR_ACCEPTABLE_GZIP is set. If it actually is
* gzip-compressed, then the open handler should OR
* LWS_FOP_FLAG_COMPR_IS_GZIP on to *flags before returning.
*/
int (*LWS_FOP_CLOSE)(lws_fop_fd_t fop_fd);
/**< close file */
int (*LWS_FOP_CLOSE)(lws_fop_fd_t *fop_fd);
/**< close file AND set the pointer to NULL */
lws_fileofs_t (*LWS_FOP_SEEK_CUR)(lws_fop_fd_t fop_fd,
lws_fileofs_t offset_from_cur_pos);
/**< seek from current position */
@ -4342,8 +4368,12 @@ struct lws_plat_file_ops {
int (*LWS_FOP_WRITE)(lws_fop_fd_t fop_fd, lws_filepos_t *amount,
uint8_t *buf, lws_filepos_t len);
/**< Write to file, on exit *amount is set to amount actually written */
const char *path_prefix;
/**< Optional, NULL or filesystem namespace prefix matching this fops */
struct lws_fops_index fi[3];
/**< vfs path signatures implying use of this fops */
const struct lws_plat_file_ops *next;
/**< NULL or next fops in list */
/* Add new things just above here ---^
* This is part of the ABI, don't needlessly break compatibility */
@ -4358,24 +4388,63 @@ LWS_VISIBLE LWS_EXTERN struct lws_plat_file_ops * LWS_WARN_UNUSED_RESULT
lws_get_fops(struct lws_context *context);
LWS_VISIBLE LWS_EXTERN void
lws_set_fops(struct lws_context *context, struct lws_plat_file_ops *fops);
LWS_VISIBLE LWS_EXTERN const struct lws_plat_file_ops * LWS_WARN_UNUSED_RESULT
lws_select_fops_by_vfs_path(const struct lws_context *context, const char *vfs_path);
/**
* lws_plat_file_open() - file open operations
* lws_vfs_tell() - get current file position
*
* \param fop_fd: fop_fd we are asking about
*/
LWS_VISIBLE LWS_EXTERN lws_filepos_t LWS_WARN_UNUSED_RESULT
lws_vfs_tell(lws_fop_fd_t fop_fd);
/**
* lws_vfs_get_length() - get current file total length in bytes
*
* \param fop_fd: fop_fd we are asking about
*/
LWS_VISIBLE LWS_EXTERN lws_filepos_t LWS_WARN_UNUSED_RESULT
lws_vfs_get_length(lws_fop_fd_t fop_fd);
/**
* lws_vfs_get_mod_time() - get time file last modified
*
* \param fop_fd: fop_fd we are asking about
*/
LWS_VISIBLE LWS_EXTERN uint32_t LWS_WARN_UNUSED_RESULT
lws_vfs_get_mod_time(lws_fop_fd_t fop_fd);
/**
* lws_vfs_file_seek_set() - seek relative to start of file
*
* \param fop_fd: fop_fd we are seeking in
* \param offset: offset from start of file
*/
LWS_VISIBLE LWS_EXTERN lws_fileofs_t
lws_vfs_file_seek_set(lws_fop_fd_t fop_fd, lws_fileofs_t offset);
/**
* lws_vfs_file_seek_end() - seek relative to end of file
*
* \param fop_fd: fop_fd we are seeking in
* \param offset: offset from start of file
*/
LWS_VISIBLE LWS_EXTERN lws_fileofs_t
lws_vfs_file_seek_end(lws_fop_fd_t fop_fd, lws_fileofs_t offset);
LWS_VISIBLE LWS_EXTERN struct lws_plat_file_ops fops_zip;
/**
* lws_plat_file_open() - open vfs filepath
*
* \param fops: file ops struct that applies to this descriptor
* \param filename: filename to open
* \param filelen: length of file (filled in by call)
* \param vfs_path: filename to open
* \param flags: pointer to open flags
*
* The vfs_path is scanned for known fops signatures, and the open directed
* to any matching fops open.
*
* User code should use this api to perform vfs opens.
*
* returns semi-opaque handle
*/
static LWS_INLINE lws_fop_fd_t LWS_WARN_UNUSED_RESULT
lws_vfs_file_open(const struct lws_plat_file_ops *fops, const char *filename,
lws_filepos_t *filelen, lws_fop_flags_t *flags)
{
return fops->LWS_FOP_OPEN(fops, filename, filelen, flags);
}
LWS_VISIBLE LWS_EXTERN lws_fop_fd_t LWS_WARN_UNUSED_RESULT
lws_vfs_file_open(const struct lws_plat_file_ops *fops, const char *vfs_path,
lws_fop_flags_t *flags);
/**
* lws_plat_file_close() - close file
@ -4383,9 +4452,9 @@ lws_vfs_file_open(const struct lws_plat_file_ops *fops, const char *filename,
* \param fop_fd: file handle to close
*/
static LWS_INLINE int
lws_vfs_file_close(lws_fop_fd_t fop_fd)
lws_vfs_file_close(lws_fop_fd_t *fop_fd)
{
return fop_fd->fops->LWS_FOP_CLOSE(fop_fd);
return (*fop_fd)->fops->LWS_FOP_CLOSE(fop_fd);
}
/**
@ -4429,15 +4498,15 @@ lws_vfs_file_write(lws_fop_fd_t fop_fd, lws_filepos_t *amount,
return fop_fd->fops->LWS_FOP_WRITE(fop_fd, amount, buf, len);
}
/* these are the flatform file operations implmenetations... they can
/* these are the platform file operations implementations... they can
* be called directly and used in fops arrays
*/
LWS_VISIBLE LWS_EXTERN lws_fop_fd_t
_lws_plat_file_open(const struct lws_plat_file_ops *fops, const char *filename,
lws_filepos_t *filelen, lws_fop_flags_t *flags);
const char *vpath, lws_fop_flags_t *flags);
LWS_VISIBLE LWS_EXTERN int
_lws_plat_file_close(lws_fop_fd_t fop_fd);
_lws_plat_file_close(lws_fop_fd_t *fop_fd);
LWS_VISIBLE LWS_EXTERN lws_fileofs_t
_lws_plat_file_seek_cur(lws_fop_fd_t fop_fd, lws_fileofs_t offset);
LWS_VISIBLE LWS_EXTERN int

View file

@ -397,7 +397,7 @@ lws_plat_inet_ntop(int af, const void *src, char *dst, int cnt)
LWS_VISIBLE lws_fop_fd_t
_lws_plat_file_open(struct lws_plat_file_ops *fops, const char *filename,
lws_filepos_t *filelen, lws_fop_flags_t *flags)
const char *vpath, lws_fop_flags_t *flags)
{
struct stat stat_buf;
lws_fop_fd_t fop_fd;
@ -414,9 +414,10 @@ _lws_plat_file_open(struct lws_plat_file_ops *fops, const char *filename,
fop_fd->fops = fops;
fop_fd->fd = ret;
fop_fd->flags = *flags;
fop_fd->filesystem_priv = NULL; /* we don't use it */
*filelen = stat_buf.st_size;
fop_fd->pos = 0;
fop_fd->len = stat_buf.st_size;
return fop_fd;
@ -427,11 +428,12 @@ bail:
}
LWS_VISIBLE int
_lws_plat_file_close(lws_fop_fd_t fops_fd)
_lws_plat_file_close(lws_fop_fd_t *fops_fd)
{
int fd = fops_fd->fd;
int fd = (*fops_fd)->fd;
free(fd);
free(*fops_fd);
*fops_fd = NULL;
return close(fd);
}
@ -453,7 +455,7 @@ _lws_plat_file_read(lws_fop_fd_t fops_fd, lws_filepos_t *amount,
*amount = 0;
return -1;
}
fop_fd->pos += n;
*amount = n;
return 0;
@ -470,7 +472,7 @@ _lws_plat_file_write(lws_fop_fd_t fops_fd, lws_filepos_t *amount,
*amount = 0;
return -1;
}
fop_fd->pos += n;
*amount = n;
return 0;

View file

@ -263,14 +263,13 @@ lws_plat_inet_ntop(int af, const void *src, char *dst, int cnt)
LWS_VISIBLE lws_fop_fd_t
_lws_plat_file_open(lws_plat_file_open(struct lws_plat_file_ops *fops,
const char *filename, lws_filepos_t *filelen,
lws_fop_flags_t *flags)
const char *filename, lws_fop_flags_t *flags)
{
return NULL;
}
LWS_VISIBLE int
_lws_plat_file_close(lws_fop_fd_t fop_fd)
_lws_plat_file_close(lws_fop_fd_t *fop_fd)
{
return 0;
}

View file

@ -611,7 +611,7 @@ lws_plat_inet_ntop(int af, const void *src, char *dst, int cnt)
LWS_VISIBLE lws_fop_fd_t
_lws_plat_file_open(const struct lws_plat_file_ops *fops, const char *filename,
lws_filepos_t *filelen, lws_fop_flags_t *flags)
const char *vpath, lws_fop_flags_t *flags)
{
struct stat stat_buf;
int ret = open(filename, (*flags) & LWS_FOP_FLAGS_MASK, 0664);
@ -628,9 +628,11 @@ _lws_plat_file_open(const struct lws_plat_file_ops *fops, const char *filename,
goto bail;
fop_fd->fops = fops;
fop_fd->flags = *flags;
fop_fd->fd = ret;
fop_fd->filesystem_priv = NULL; /* we don't use it */
*filelen = stat_buf.st_size;
fop_fd->len = stat_buf.st_size;
fop_fd->pos = 0;
return fop_fd;
@ -640,18 +642,36 @@ bail:
}
LWS_VISIBLE int
_lws_plat_file_close(lws_fop_fd_t fop_fd)
_lws_plat_file_close(lws_fop_fd_t *fop_fd)
{
int fd = fop_fd->fd;
int fd = (*fop_fd)->fd;
free(*fop_fd);
*fop_fd = NULL;
free(fop_fd);
return close(fd);
}
LWS_VISIBLE lws_fileofs_t
_lws_plat_file_seek_cur(lws_fop_fd_t fop_fd, lws_fileofs_t offset)
{
return lseek(fop_fd->fd, offset, SEEK_CUR);
lws_fileofs_t r;
if (offset > 0 && offset > fop_fd->len - fop_fd->pos)
offset = fop_fd->len - fop_fd->pos;
if ((lws_fileofs_t)fop_fd->pos + offset < 0)
offset = -fop_fd->pos;
r = lseek(fop_fd->fd, offset, SEEK_CUR);
if (r >= 0)
fop_fd->pos = r;
else
lwsl_err("error seeking from cur %ld, offset %ld\n",
fop_fd->pos, offset);
return r;
}
LWS_VISIBLE int
@ -665,7 +685,9 @@ _lws_plat_file_read(lws_fop_fd_t fop_fd, lws_filepos_t *amount,
*amount = 0;
return -1;
}
fop_fd->pos += n;
lwsl_debug("%s: read %ld of req %ld, pos %ld, len %ld\n", __func__, n,
(long)len, fop_fd->pos, fop_fd->len);
*amount = n;
return 0;
@ -683,6 +705,7 @@ _lws_plat_file_write(lws_fop_fd_t fop_fd, lws_filepos_t *amount,
return -1;
}
fop_fd->pos += n;
*amount = n;
return 0;

View file

@ -523,7 +523,7 @@ lws_plat_inet_ntop(int af, const void *src, char *dst, int cnt)
LWS_VISIBLE lws_fop_fd_t
_lws_plat_file_open(struct lws_plat_file_ops *fops, const char *filename,
lws_filepos_t *filelen, lws_fop_flags_t *flags)
const char *vpath, lws_fop_flags_t *flags)
{
HANDLE ret;
WCHAR buf[MAX_PATH];
@ -548,22 +548,23 @@ _lws_plat_file_open(struct lws_plat_file_ops *fops, const char *filename,
fop_fd->fops = fops;
fop_fd->fd = ret;
fop_fd->filesystem_priv = NULL; /* we don't use it */
*filelen = GetFileSize(ret, NULL);
fop_fd->flags = *flags;
fop_fd->len = GetFileSize(ret, NULL);
fop_fd->pos = 0;
return fop_fd;
bail:
*filelen = 0;
return NULL;
}
LWS_VISIBLE int
_lws_plat_file_close(lws_fop_fd_t fop_fd)
_lws_plat_file_close(lws_fop_fd_t *fop_fd)
{
HANDLE fd = fop_fd->fd;
HANDLE fd = (*fop_fd)->fd;
free(fop_fd);
free(*fop_fd);
*fop_fd = NULL;
CloseHandle((HANDLE)fd);
@ -588,6 +589,7 @@ _lws_plat_file_read(lws_fop_fd_t fop_fd, lws_filepos_t *amount,
return 1;
}
fop_fd->pos += _amount;
*amount = (unsigned long)_amount;
return 0;
@ -602,6 +604,8 @@ _lws_plat_file_write(lws_fop_fd_t fop_fd, lws_filepos_t *amount,
(void)buf;
(void)len;
fop_fd->pos += len;
lwsl_err("%s: not implemented yet on this platform\n", __func__);
return -1;

View file

@ -574,7 +574,7 @@ LWS_VISIBLE int lws_serve_http_file_fragment(struct lws *wsi)
wsi->trunc_offset,
wsi->trunc_len) < 0) {
lwsl_info("%s: closing\n", __func__);
return -1;
goto file_had_it;
}
continue;
}
@ -594,7 +594,7 @@ LWS_VISIBLE int lws_serve_http_file_fragment(struct lws *wsi)
if ((long)lws_vfs_file_seek_cur(wsi->u.http.fop_fd,
wsi->u.http.range.start -
wsi->u.http.filepos) < 0)
return -1;
goto file_had_it;
wsi->u.http.filepos = wsi->u.http.range.start;
@ -634,7 +634,7 @@ LWS_VISIBLE int lws_serve_http_file_fragment(struct lws *wsi)
}
if (lws_vfs_file_read(wsi->u.http.fop_fd, &amount, p, poss) < 0)
return -1; /* caller will close */
goto file_had_it; /* caller will close */
//lwsl_notice("amount %ld\n", amount);
@ -656,7 +656,7 @@ LWS_VISIBLE int lws_serve_http_file_fragment(struct lws *wsi)
wsi->vhost->protocols[(int)wsi->protocol_interpret_idx].callback, wsi,
LWS_CALLBACK_PROCESS_HTML,
wsi->user_space, &args, 0) < 0)
return -1;
goto file_had_it;
n = args.len;
p = (unsigned char *)args.p;
} else
@ -678,7 +678,7 @@ LWS_VISIBLE int lws_serve_http_file_fragment(struct lws *wsi)
LWS_WRITE_HTTP
);
if (m < 0)
return -1;
goto file_had_it;
wsi->u.http.filepos += amount;
@ -703,7 +703,7 @@ LWS_VISIBLE int lws_serve_http_file_fragment(struct lws *wsi)
if (lws_vfs_file_seek_cur(wsi->u.http.fop_fd,
m - n) ==
(unsigned long)-1)
return -1;
goto file_had_it;
}
}
all_sent:
@ -716,8 +716,7 @@ all_sent:
{
wsi->state = LWSS_HTTP;
/* we might be in keepalive, so close it off here */
lws_vfs_file_close(wsi->u.http.fop_fd);
wsi->u.http.fop_fd = NULL;
lws_vfs_file_close(&wsi->u.http.fop_fd);
lwsl_debug("file completed\n");
@ -736,6 +735,11 @@ all_sent:
lws_callback_on_writable(wsi);
return 0; /* indicates further processing must be done */
file_had_it:
lws_vfs_file_close(&wsi->u.http.fop_fd);
return -1;
}
#if LWS_POSIX

View file

@ -439,57 +439,6 @@ extern "C" {
#define SYSTEM_RANDOM_FILEPATH "/dev/urandom"
#endif
/**
* Unzip library by Per Bothner.
* Loosely based on Joonas Pihlajamaa's JUnzip.
* Released into public domain. https://github.com/jokkebk/JUnzip
* ------->
*/
typedef struct jzfile {
unsigned char *start;
off_t length;
long position;
int numEntries;
uint32_t centralDirectoryOffset;
} jzfile_t;
#define zf_tell(ZF) ((ZF)->position)
#define zf_available(ZF) ((ZF)->length - (ZF)->position)
#define zf_current(ZF) ((ZF)->start + (ZF)->position)
#define ZIP_LOCAL_FILE_HEADER_LENGTH 30
typedef struct {
uint16_t compressionMethod;
uint32_t crc32;
uint32_t compressedSize;
uint32_t uncompressedSize;
long fileNameStart;
uint16_t fileNameLength;
uint16_t extraFieldLength; // unsupported
uint32_t offset;
} jzfile_hdr_t;
// Callback prototype for central and local file record reading functions
typedef int (*jzcb_t)(jzfile_t *zip, int index, jzfile_hdr_t *header);
// Read ZIP file end record. Will move within file.
int jzReadEndRecord(jzfile_t *zip);
// Read ZIP file global directory. Will move within file.
// Callback is called for each record, until callback returns zero
int jzReadCentralDirectory(jzfile_t *zip, jzcb_t callback);
// See to the start of the actual data of the given entry.
int jzSeekData(jzfile_t *zip, jzfile_hdr_t *header);
// Read data from file stream, described by header, to preallocated buffer
// Return value is zlib coded, e.g. Z_OK, or error code
int jzReadData(jzfile_t *zip, jzfile_hdr_t *header, void *buffer);
/* <------ */
enum lws_websocket_opcodes_07 {
LWSWSOPC_CONTINUATION = 0,
LWSWSOPC_TEXT_FRAME = 1,
@ -860,7 +809,10 @@ struct lws_context {
time_t last_ws_ping_pong_check_s;
time_t time_up;
const struct lws_plat_file_ops *fops;
struct lws_plat_file_ops fops_default[2];
struct lws_plat_file_ops fops_platform;
#if defined(LWS_WITH_ZIP_FOPS)
struct lws_plat_file_ops fops_zip;
#endif
struct lws_context_per_thread pt[LWS_MAX_SMP];
struct lws_conn_stats conn_stats;
#ifdef _WIN32
@ -947,6 +899,7 @@ struct lws_context {
short server_string_len;
unsigned short ws_ping_pong_interval;
unsigned short deprecation_pending_listen_close_count;
uint8_t max_fi;
};
#define lws_get_context_protocol(ctx, x) ctx->vhost_list->protocols[x]
@ -2005,6 +1958,10 @@ void lws_free(void *p);
#define lws_free_set_NULL(P) do { lws_realloc(P, 0); (P) = NULL; } while(0)
#endif
const struct lws_plat_file_ops *
lws_vfs_select_fops(const struct lws_plat_file_ops *fops, const char *vfs_path,
const char **vpath);
/* lws_plat_ */
LWS_EXTERN void
lws_plat_delete_socket_from_fds(struct lws_context *context,

View file

@ -312,6 +312,22 @@ lws_get_mimetype(const char *file, const struct lws_http_mount *m)
return NULL;
}
static lws_fop_flags_t
lws_vfs_prepare_flags(struct lws *wsi)
{
lws_fop_flags_t f = 0;
if (!lws_hdr_total_length(wsi, WSI_TOKEN_HTTP_ACCEPT_ENCODING))
return f;
if (strstr(lws_hdr_simple_ptr(wsi, WSI_TOKEN_HTTP_ACCEPT_ENCODING),
"gzip")) {
lwsl_info("client indicates GZIP is acceptable\n");
f |= LWS_FOP_FLAG_COMPR_ACCEPTABLE_GZIP;
}
return f;
}
static int
lws_http_serve(struct lws *wsi, char *uri, const char *origin,
@ -319,8 +335,11 @@ lws_http_serve(struct lws *wsi, char *uri, const char *origin,
{
const struct lws_protocol_vhost_options *pvo = m->interpret;
struct lws_process_html_args args;
const char *mimetype;
#if !defined(_WIN32_WCE) && !defined(LWS_WITH_ESP8266) && !defined(LWS_WITH_ESP32)
const char *mimetype, *vpath;
#if !defined(_WIN32_WCE) && !defined(LWS_WITH_ESP8266) && \
!defined(LWS_WITH_ESP32)
const struct lws_plat_file_ops *fops;
lws_fop_flags_t fflags = LWS_O_RDONLY;
struct stat st;
int spin = 0;
#endif
@ -334,15 +353,37 @@ lws_http_serve(struct lws *wsi, char *uri, const char *origin,
lws_snprintf(path, sizeof(path) - 1, "%s/%s", origin, uri);
#if !defined(_WIN32_WCE) && !defined(LWS_WITH_ESP8266) && !defined(LWS_WITH_ESP32)
fflags |= lws_vfs_prepare_flags(wsi);
#if !defined(_WIN32_WCE) && !defined(LWS_WITH_ESP8266) && \
!defined(LWS_WITH_ESP32)
do {
spin++;
fops = lws_vfs_select_fops(wsi->context->fops, path, &vpath);
if (stat(path, &st)) {
if (wsi->u.http.fop_fd)
lws_vfs_file_close(&wsi->u.http.fop_fd);
wsi->u.http.fop_fd = fops->LWS_FOP_OPEN(wsi->context->fops,
path, vpath, &fflags);
if (!wsi->u.http.fop_fd) {
lwsl_err("Unable to open '%s'\n", path);
return -1;
}
/* if it can't be statted, don't try */
if (fflags & LWS_FOP_FLAG_VIRTUAL)
break;
if (fstat(wsi->u.http.fop_fd->fd, &st)) {
lwsl_info("unable to stat %s\n", path);
goto bail;
}
wsi->u.http.fop_fd->mod_time = (uint32_t)st.st_mtime;
fflags |= LWS_FOP_FLAG_MOD_TIME_VALID;
lwsl_debug(" %s mode %d\n", path, S_IFMT & st.st_mode);
#if !defined(WIN32) && LWS_POSIX
if ((S_IFMT & st.st_mode) == S_IFLNK) {
@ -367,8 +408,9 @@ lws_http_serve(struct lws *wsi, char *uri, const char *origin,
if (spin == 5)
lwsl_err("symlink loop %s \n", path);
n = sprintf(sym, "%08lX%08lX", (unsigned long)st.st_size,
(unsigned long)st.st_mtime);
n = sprintf(sym, "%08lX%08lX",
(unsigned long)lws_vfs_get_length(wsi->u.http.fop_fd),
(unsigned long)lws_vfs_get_mod_time(wsi->u.http.fop_fd));
/* disable ranges if IF_RANGE token invalid */
@ -382,7 +424,8 @@ lws_http_serve(struct lws *wsi, char *uri, const char *origin,
* he thinks he has some version of it already,
* check if the tag matches
*/
if (!strcmp(sym, lws_hdr_simple_ptr(wsi, WSI_TOKEN_HTTP_IF_NONE_MATCH))) {
if (!strcmp(sym, lws_hdr_simple_ptr(wsi,
WSI_TOKEN_HTTP_IF_NONE_MATCH))) {
lwsl_debug("%s: ETAG match %s %s\n", __func__,
uri, origin);
@ -407,6 +450,8 @@ lws_http_serve(struct lws *wsi, char *uri, const char *origin,
return -1;
}
lws_vfs_file_close(&wsi->u.http.fop_fd);
return lws_http_transaction_completed(wsi);
}
}
@ -2060,7 +2105,7 @@ lws_server_socket_service(struct lws_context *context, struct lws *wsi,
len = lws_ssl_capable_read(wsi, pt->serv_buf,
context->pt_serv_buf_size);
lwsl_notice("%s: wsi %p read %d\r\n", __func__, wsi, len);
// lwsl_notice("%s: wsi %p read %d\r\n", __func__, wsi, len);
switch (len) {
case 0:
lwsl_info("%s: read 0 len\n", __func__);
@ -2228,39 +2273,33 @@ lws_serve_http_file(struct lws *wsi, const char *file, const char *content_type,
unsigned char *end = p + context->pt_serv_buf_size - LWS_PRE;
unsigned long computed_total_content_length;
int ret = 0, cclen = 8, n = HTTP_STATUS_OK;
lws_fop_flags_t fflags = O_RDONLY;
lws_fop_flags_t fflags = LWS_O_RDONLY;
#if defined(LWS_WITH_RANGES)
int ranges;
#endif
const struct lws_plat_file_ops *fops;
const char *vpath;
if (lws_hdr_total_length(wsi, WSI_TOKEN_HTTP_ACCEPT_ENCODING))
if (strstr("gzip", lws_hdr_simple_ptr(wsi, WSI_TOKEN_HTTP_ACCEPT_ENCODING)) &&
strstr("deflate", lws_hdr_simple_ptr(wsi, WSI_TOKEN_HTTP_ACCEPT_ENCODING))) {
lwsl_debug("client indicates GZIP is acceptable\n");
fflags |= LWS_FOP_FLAG_COMPR_ACCEPTABLE_GZIP;
}
wsi->u.http.fop_fd = lws_vfs_file_open(lws_select_fops_by_vfs_path(
wsi->context, file), file,
&wsi->u.http.filelen,
&fflags);
/*
* We either call the platform fops .open with first arg platform fops,
* or we call fops_zip .open with first arg platform fops, and fops_zip
* open will decide whether to switch to fops_zip or stay with fops_def.
*
* If wsi->u.http.fop_fd is already set, the caller already opened it
*/
if (!wsi->u.http.fop_fd) {
lwsl_err("Unable to open '%s'\n", file);
fops = lws_vfs_select_fops(wsi->context->fops, file, &vpath);
fflags |= lws_vfs_prepare_flags(wsi);
wsi->u.http.fop_fd = fops->LWS_FOP_OPEN(wsi->context->fops,
file, vpath, &fflags);
if (!wsi->u.http.fop_fd) {
lwsl_err("Unable to open '%s'\n", file);
return -1;
}
computed_total_content_length = wsi->u.http.filelen;
if ((fflags & (LWS_FOP_FLAG_COMPR_ACCEPTABLE_GZIP |
LWS_FOP_FLAG_COMPR_IS_GZIP)) ==
(LWS_FOP_FLAG_COMPR_ACCEPTABLE_GZIP | LWS_FOP_FLAG_COMPR_IS_GZIP)) {
if (lws_add_http_header_by_token(wsi,
WSI_TOKEN_HTTP_CONTENT_ENCODING,
(unsigned char *)"gzip, deflate", 13, &p, end))
return -1;
lwsl_debug("file is being provided in gzip\n");
}
}
wsi->u.http.filelen = lws_vfs_get_length(wsi->u.http.fop_fd);
computed_total_content_length = wsi->u.http.filelen;
#if defined(LWS_WITH_RANGES)
ranges = lws_ranges_init(wsi, rp, wsi->u.http.filelen);
@ -2279,6 +2318,8 @@ lws_serve_http_file(struct lws *wsi, const char *file, const char *content_type,
if (lws_http_transaction_completed(wsi))
return -1; /* <0 means just hang up */
lws_vfs_file_close(&wsi->u.http.fop_fd);
return 0; /* == 0 means we dealt with the transaction complete */
}
if (ranges)
@ -2288,6 +2329,16 @@ lws_serve_http_file(struct lws *wsi, const char *file, const char *content_type,
if (lws_add_http_header_status(wsi, n, &p, end))
return -1;
if ((wsi->u.http.fop_fd->flags & (LWS_FOP_FLAG_COMPR_ACCEPTABLE_GZIP |
LWS_FOP_FLAG_COMPR_IS_GZIP)) ==
(LWS_FOP_FLAG_COMPR_ACCEPTABLE_GZIP | LWS_FOP_FLAG_COMPR_IS_GZIP)) {
if (lws_add_http_header_by_token(wsi,
WSI_TOKEN_HTTP_CONTENT_ENCODING,
(unsigned char *)"gzip", 4, &p, end))
return -1;
lwsl_info("file is being provided in gzip\n");
}
#if defined(LWS_WITH_RANGES)
if (ranges < 2 && content_type && content_type[0])
if (lws_add_http_header_by_token(wsi, WSI_TOKEN_HTTP_CONTENT_TYPE,

BIN
test-server/candide.zip Normal file

Binary file not shown.

View file

@ -292,13 +292,14 @@ int callback_http(struct lws *wsi, enum lws_callback_reasons reason, void *user,
p = buffer + LWS_PRE;
end = p + sizeof(buffer) - LWS_PRE;
pss->fop_fd = lws_vfs_file_open(lws_get_fops(lws_get_context(wsi)),
leaf_path, &file_len, &flags);
pss->fop_fd = lws_vfs_file_open(
lws_get_fops(lws_get_context(wsi)),
leaf_path, &flags);
if (!pss->fop_fd) {
lwsl_err("failed to open file %s\n", leaf_path);
return -1;
}
file_len = lws_vfs_get_length(pss->fop_fd);
/*
* we will send a big jpeg file, but it could be
@ -346,7 +347,7 @@ int callback_http(struct lws *wsi, enum lws_callback_reasons reason, void *user,
p - (buffer + LWS_PRE),
LWS_WRITE_HTTP_HEADERS);
if (n < 0) {
lws_vfs_file_close(pss->fop_fd);
lws_vfs_file_close(&pss->fop_fd);
return -1;
}
/*
@ -588,12 +589,12 @@ later:
lws_callback_on_writable(wsi);
break;
penultimate:
lws_vfs_file_close(pss->fop_fd);
lws_vfs_file_close(&pss->fop_fd);
pss->fop_fd = NULL;
goto try_to_reuse;
bail:
lws_vfs_file_close(pss->fop_fd);
lws_vfs_file_close(&pss->fop_fd);
return -1;

View file

@ -150,16 +150,16 @@ static const struct lws_extension exts[] = {
* compressed files without decompressing the whole archive)
*/
static lws_fop_fd_t
test_server_fops_open(struct lws_plat_file_ops *fops, const char *filename,
lws_filepos_t *filelen, lws_fop_flags_t *flags)
test_server_fops_open(const struct lws_plat_file_ops *fops,
const char *vfs_path, const char *vpath,
lws_fop_flags_t *flags)
{
lws_fop_fd_t n;
/* call through to original platform implementation */
n = fops_plat.open(fops, filename, filelen, flags);
n = fops_plat.open(fops, vfs_path, vpath, flags);
lwsl_notice("%s: opening %s, ret %p, len %lu\n", __func__, filename,
n, *filelen);
lwsl_notice("%s: opening %s, ret %p\n", __func__, vfs_path, n);
return n;
}

View file

@ -67,11 +67,33 @@ static const struct lws_extension exts[] = {
};
/*
* mount a handler for a section of the URL space
* mount handlers for sections of the URL space
*/
static const struct lws_http_mount mount_ziptest = {
NULL, /* linked-list pointer to next*/
"/ziptest", /* mountpoint in URL namespace on this vhost */
LOCAL_RESOURCE_PATH"/candide.zip", /* handler */
NULL, /* default filename if none given */
NULL,
NULL,
NULL,
NULL,
0,
0,
0,
0,
0,
0,
LWSMPRO_FILE, /* origin points to a callback */
8, /* strlen("/ziptest"), ie length of the mountpoint */
NULL,
{ NULL, NULL } // sentinel
};
static const struct lws_http_mount mount_post = {
NULL, /* linked-list pointer to next*/
(struct lws_http_mount *)&mount_ziptest, /* linked-list pointer to next*/
"/formtest", /* mountpoint in URL namespace on this vhost */
"protocol-post-demo", /* handler */
NULL, /* default filename if none given */

View file

@ -122,17 +122,20 @@ static struct lws_protocols protocols[] = {
*/
static lws_fop_fd_t
test_server_fops_open(const struct lws_plat_file_ops *fops,
const char *filename,
lws_filepos_t *filelen,
const char *vfs_path, const char *vpath,
lws_fop_flags_t *flags)
{
lws_fop_fd_t fop_fd;
/* call through to original platform implementation */
fop_fd = fops_plat.open(fops, filename, filelen, flags);
fop_fd = fops_plat.open(fops, vfs_path, vpath, flags);
lwsl_info("%s: opening %s, ret %p, len %lu\n", __func__, filename,
fop_fd, (long)*filelen);
if (fop_fd)
lwsl_info("%s: opening %s, ret %p, len %lu\n", __func__,
vfs_path, fop_fd,
(long)lws_vfs_get_length(fop_fd));
else
lwsl_info("%s: open %s failed\n", __func__, vfs_path);
return fop_fd;
}