fops-zip
This commit is contained in:
parent
2f4dfa4ea7
commit
19cc7acb24
21 changed files with 1180 additions and 490 deletions
|
@ -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")
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
667
lib/fops-zip.c
Normal 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,
|
||||
};
|
267
lib/junzip.c
267
lib/junzip.c
|
@ -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;
|
||||
}
|
|
@ -455,7 +455,8 @@ lejp_vhosts_cb(struct lejp_ctx *ctx, char reason)
|
|||
"cgi://",
|
||||
">http://",
|
||||
">https://",
|
||||
"callback://"
|
||||
"callback://",
|
||||
"gzip://",
|
||||
};
|
||||
|
||||
if (!a->fresh_mount)
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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 *
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
20
lib/output.c
20
lib/output.c
|
@ -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
|
||||
|
|
|
@ -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,
|
||||
|
|
117
lib/server.c
117
lib/server.c
|
@ -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
BIN
test-server/candide.zip
Normal file
Binary file not shown.
|
@ -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;
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue