Update Files
This commit is contained in:
209
Kinc/Sources/kinc/libs/core/server/access-log.c
Normal file
209
Kinc/Sources/kinc/libs/core/server/access-log.c
Normal file
@ -0,0 +1,209 @@
|
||||
/*
|
||||
* libwebsockets - small server side websockets and web server implementation
|
||||
*
|
||||
* Copyright (C) 2010 - 2019 Andy Green <andy@warmcat.com>
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#include "private-lib-core.h"
|
||||
|
||||
/*
|
||||
* Produce Apache-compatible log string for wsi, like this:
|
||||
*
|
||||
* 2.31.234.19 - - [27/Mar/2016:03:22:44 +0800]
|
||||
* "GET /aep-screen.png HTTP/1.1"
|
||||
* 200 152987 "https://libwebsockets.org/index.html"
|
||||
* "Mozilla/5.0 (Macint... Chrome/49.0.2623.87 Safari/537.36"
|
||||
*
|
||||
*/
|
||||
|
||||
extern const char * const method_names[];
|
||||
|
||||
static const char * const hver[] = {
|
||||
"HTTP/1.0", "HTTP/1.1", "HTTP/2"
|
||||
};
|
||||
|
||||
void
|
||||
lws_prepare_access_log_info(struct lws *wsi, char *uri_ptr, int uri_len, int meth)
|
||||
{
|
||||
char da[64], uri[256], ta[64];
|
||||
time_t t = time(NULL);
|
||||
struct lws *nwsi;
|
||||
const char *me;
|
||||
int l = 256, m;
|
||||
struct tm *ptm = NULL;
|
||||
#if defined(LWS_HAVE_LOCALTIME_R)
|
||||
struct tm tm;
|
||||
#endif
|
||||
|
||||
if (!wsi->a.vhost)
|
||||
return;
|
||||
|
||||
/* only worry about preparing it if we store it */
|
||||
if (wsi->a.vhost->log_fd == (int)LWS_INVALID_FILE)
|
||||
return;
|
||||
|
||||
if (wsi->access_log_pending)
|
||||
lws_access_log(wsi);
|
||||
|
||||
wsi->http.access_log.header_log = lws_malloc((unsigned int)l, "access log");
|
||||
if (!wsi->http.access_log.header_log)
|
||||
return;
|
||||
|
||||
#if defined(LWS_HAVE_LOCALTIME_R)
|
||||
ptm = localtime_r(&t, &tm);
|
||||
#else
|
||||
ptm = localtime(&t);
|
||||
#endif
|
||||
if (ptm)
|
||||
strftime(da, sizeof(da), "%d/%b/%Y:%H:%M:%S %z", ptm);
|
||||
else
|
||||
strcpy(da, "01/Jan/1970:00:00:00 +0000");
|
||||
|
||||
#if defined(LWS_ROLE_H2)
|
||||
if (wsi->mux_substream)
|
||||
me = lws_hdr_simple_ptr(wsi, WSI_TOKEN_HTTP_COLON_METHOD);
|
||||
else
|
||||
#endif
|
||||
me = method_names[meth];
|
||||
|
||||
if (!me)
|
||||
me = "(null)";
|
||||
|
||||
m = uri_len;
|
||||
if (m > (int)sizeof(uri) - 1)
|
||||
m = sizeof(uri) - 1;
|
||||
|
||||
strncpy(uri, uri_ptr, (unsigned int)m);
|
||||
uri[m] = '\0';
|
||||
|
||||
nwsi = lws_get_network_wsi(wsi);
|
||||
|
||||
if (nwsi->sa46_peer.sa4.sin_family)
|
||||
lws_sa46_write_numeric_address(&nwsi->sa46_peer, ta, sizeof(ta));
|
||||
else
|
||||
strncpy(ta, "unknown", sizeof(ta));
|
||||
|
||||
lws_snprintf(wsi->http.access_log.header_log, (size_t)l,
|
||||
"%s - - [%s] \"%s %s %s\"",
|
||||
ta, da, me, uri, hver[wsi->http.request_version]);
|
||||
|
||||
//lwsl_notice("%s\n", wsi->http.access_log.header_log);
|
||||
|
||||
l = lws_hdr_total_length(wsi, WSI_TOKEN_HTTP_USER_AGENT);
|
||||
if (l) {
|
||||
wsi->http.access_log.user_agent =
|
||||
lws_malloc((unsigned int)l + 5, "access log");
|
||||
if (!wsi->http.access_log.user_agent) {
|
||||
lwsl_err("OOM getting user agent\n");
|
||||
lws_free_set_NULL(wsi->http.access_log.header_log);
|
||||
return;
|
||||
}
|
||||
wsi->http.access_log.user_agent[0] = '\0';
|
||||
|
||||
if (lws_hdr_copy(wsi, wsi->http.access_log.user_agent, l + 4,
|
||||
WSI_TOKEN_HTTP_USER_AGENT) >= 0)
|
||||
for (m = 0; m < l; m++)
|
||||
if (wsi->http.access_log.user_agent[m] == '\"')
|
||||
wsi->http.access_log.user_agent[m] = '\'';
|
||||
}
|
||||
l = lws_hdr_total_length(wsi, WSI_TOKEN_HTTP_REFERER);
|
||||
if (l) {
|
||||
wsi->http.access_log.referrer = lws_malloc((unsigned int)l + 5, "referrer");
|
||||
if (!wsi->http.access_log.referrer) {
|
||||
lwsl_err("OOM getting referrer\n");
|
||||
lws_free_set_NULL(wsi->http.access_log.user_agent);
|
||||
lws_free_set_NULL(wsi->http.access_log.header_log);
|
||||
return;
|
||||
}
|
||||
wsi->http.access_log.referrer[0] = '\0';
|
||||
if (lws_hdr_copy(wsi, wsi->http.access_log.referrer,
|
||||
l + 4, WSI_TOKEN_HTTP_REFERER) >= 0)
|
||||
|
||||
for (m = 0; m < l; m++)
|
||||
if (wsi->http.access_log.referrer[m] == '\"')
|
||||
wsi->http.access_log.referrer[m] = '\'';
|
||||
}
|
||||
wsi->access_log_pending = 1;
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
lws_access_log(struct lws *wsi)
|
||||
{
|
||||
char *p = wsi->http.access_log.user_agent, ass[512],
|
||||
*p1 = wsi->http.access_log.referrer;
|
||||
int l;
|
||||
|
||||
if (!wsi->a.vhost)
|
||||
return 0;
|
||||
|
||||
if (wsi->a.vhost->log_fd == (int)LWS_INVALID_FILE)
|
||||
return 0;
|
||||
|
||||
if (!wsi->access_log_pending)
|
||||
return 0;
|
||||
|
||||
if (!wsi->http.access_log.header_log)
|
||||
return 0;
|
||||
|
||||
if (!p)
|
||||
p = "";
|
||||
|
||||
if (!p1)
|
||||
p1 = "";
|
||||
|
||||
/*
|
||||
* We do this in two parts to restrict an oversize referrer such that
|
||||
* we will always have space left to append an empty useragent, while
|
||||
* maintaining the structure of the log text
|
||||
*/
|
||||
l = lws_snprintf(ass, sizeof(ass) - 7, "%s %d %lu \"%s",
|
||||
wsi->http.access_log.header_log,
|
||||
wsi->http.access_log.response,
|
||||
wsi->http.access_log.sent, p1);
|
||||
if (strlen(p) > sizeof(ass) - 6 - (unsigned int)l) {
|
||||
p[sizeof(ass) - 6 - (unsigned int)l] = '\0';
|
||||
l--;
|
||||
}
|
||||
l += lws_snprintf(ass + (unsigned int)l, sizeof(ass) - 1 - (unsigned int)l, "\" \"%s\"\n", p);
|
||||
|
||||
ass[sizeof(ass) - 1] = '\0';
|
||||
|
||||
if ((int)write(wsi->a.vhost->log_fd, ass, (size_t)l) != l)
|
||||
lwsl_err("Failed to write log\n");
|
||||
|
||||
if (wsi->http.access_log.header_log) {
|
||||
lws_free(wsi->http.access_log.header_log);
|
||||
wsi->http.access_log.header_log = NULL;
|
||||
}
|
||||
if (wsi->http.access_log.user_agent) {
|
||||
lws_free(wsi->http.access_log.user_agent);
|
||||
wsi->http.access_log.user_agent = NULL;
|
||||
}
|
||||
if (wsi->http.access_log.referrer) {
|
||||
lws_free(wsi->http.access_log.referrer);
|
||||
wsi->http.access_log.referrer = NULL;
|
||||
}
|
||||
wsi->access_log_pending = 0;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
657
Kinc/Sources/kinc/libs/core/server/fops-zip.c
Normal file
657
Kinc/Sources/kinc/libs/core/server/fops-zip.c
Normal file
@ -0,0 +1,657 @@
|
||||
/*
|
||||
* 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.
|
||||
*
|
||||
* Somewhat rewritten by AG
|
||||
*/
|
||||
|
||||
#include "private-lib-core.h"
|
||||
|
||||
#if defined(LWS_WITH_MINIZ)
|
||||
#include <miniz.h>
|
||||
#else
|
||||
#include <zlib.h>
|
||||
#endif
|
||||
|
||||
/*
|
||||
* 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_SEEK,
|
||||
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,
|
||||
};
|
||||
|
||||
#define eff_size(_priv) (_priv->hdr.method == ZIP_COMPRESSION_METHOD_STORE ? \
|
||||
_priv->hdr.uncomp_size : _priv->hdr.comp_size)
|
||||
|
||||
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[96];
|
||||
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", (unsigned long)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 >= (int)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, (unsigned int)len))
|
||||
return LWS_FZ_ERR_NAME_READ;
|
||||
if ((int)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 */
|
||||
if (lws_vfs_file_seek_set(priv->zip_fop_fd, priv->hdr.offset) < 0)
|
||||
return LWS_FZ_ERR_NAME_SEEK;
|
||||
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",
|
||||
(unsigned long)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,
|
||||
(lws_fileofs_t)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,
|
||||
(lws_fileofs_t)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, (lws_fileofs_t)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_own,
|
||||
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), "fops_zip priv");
|
||||
if (!priv)
|
||||
return NULL;
|
||||
|
||||
priv->fop_fd.fops = &fops_zip;
|
||||
|
||||
m = sizeof(rp) - 1;
|
||||
if ((vpath - vfs_path - 1) < m)
|
||||
m = lws_ptr_diff(vpath, vfs_path) - 1;
|
||||
lws_strncpy(rp, vfs_path, (unsigned int)m + 1);
|
||||
|
||||
/* open the zip file itself using the incoming fops, not fops_zip */
|
||||
|
||||
priv->zip_fop_fd = fops->LWS_FOP_OPEN(fops_own, fops, rp, NULL, &local_flags);
|
||||
if (!priv->zip_fop_fd) {
|
||||
lwsl_err("%s: unable to open zip %s\n", __func__, rp);
|
||||
goto bail1;
|
||||
}
|
||||
|
||||
if (*vpath == '/')
|
||||
vpath++;
|
||||
|
||||
m = lws_fops_zip_scan(priv, vpath, (int)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 = (lws_filepos_t)((lws_fileofs_t)fd->pos + offset_from_cur_pos);
|
||||
|
||||
return (lws_fileofs_t)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 = (unsigned int)len;
|
||||
priv->inflate.next_out = buf;
|
||||
|
||||
spin:
|
||||
if (!priv->inflate.avail_in) {
|
||||
rlen = sizeof(priv->rbuf);
|
||||
if (rlen > eff_size(priv) - (cur - priv->content_start))
|
||||
rlen = eff_size(priv) - (cur - 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 = (unsigned int)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;
|
||||
/* fallthru */
|
||||
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, (size_t)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, (size_t)rlen);
|
||||
|
||||
*amount += rlen;
|
||||
fd->pos += rlen;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
lwsl_info("%s: store\n", __func__);
|
||||
|
||||
if (len > eff_size(priv) - cur)
|
||||
len = eff_size(priv) - cur;
|
||||
|
||||
if (priv->zip_fop_fd->fops->LWS_FOP_READ(priv->zip_fop_fd,
|
||||
amount, buf, len))
|
||||
return LWS_FZ_ERR_READ_CONTENT;
|
||||
|
||||
fd->pos += *amount;
|
||||
|
||||
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,
|
||||
NULL,
|
||||
};
|
1112
Kinc/Sources/kinc/libs/core/server/lejp-conf.c
Normal file
1112
Kinc/Sources/kinc/libs/core/server/lejp-conf.c
Normal file
File diff suppressed because it is too large
Load Diff
725
Kinc/Sources/kinc/libs/core/server/lws-spa.c
Normal file
725
Kinc/Sources/kinc/libs/core/server/lws-spa.c
Normal file
@ -0,0 +1,725 @@
|
||||
/*
|
||||
* libwebsockets - small server side websockets and web server implementation
|
||||
*
|
||||
* Copyright (C) 2010 - 2021 Andy Green <andy@warmcat.com>
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#include "private-lib-core.h"
|
||||
|
||||
#define LWS_MAX_ELEM_NAME 32
|
||||
|
||||
enum urldecode_stateful {
|
||||
US_NAME,
|
||||
US_IDLE,
|
||||
US_PC1,
|
||||
US_PC2,
|
||||
|
||||
MT_LOOK_BOUND_IN,
|
||||
MT_HNAME,
|
||||
MT_DISP,
|
||||
MT_TYPE,
|
||||
MT_IGNORE1,
|
||||
MT_IGNORE2,
|
||||
MT_IGNORE3,
|
||||
MT_COMPLETED,
|
||||
};
|
||||
|
||||
static struct mp_hdr {
|
||||
const char * const hdr;
|
||||
uint8_t hdr_len;
|
||||
} mp_hdrs[] = {
|
||||
{ "content-disposition: ", 21 },
|
||||
{ "content-type: ", 14 },
|
||||
{ "\x0d\x0a", 2 }
|
||||
};
|
||||
|
||||
struct lws_spa;
|
||||
|
||||
typedef int (*lws_urldecode_stateful_cb)(struct lws_spa *spa,
|
||||
const char *name, char **buf, int len, int final);
|
||||
|
||||
struct lws_urldecode_stateful {
|
||||
char *out;
|
||||
struct lws_spa *data;
|
||||
struct lws *wsi;
|
||||
char name[LWS_MAX_ELEM_NAME];
|
||||
char temp[LWS_MAX_ELEM_NAME];
|
||||
char content_type[32];
|
||||
char content_disp[32];
|
||||
char content_disp_filename[256];
|
||||
char mime_boundary[128];
|
||||
int out_len;
|
||||
int pos;
|
||||
int hdr_idx;
|
||||
int mp;
|
||||
int sum;
|
||||
|
||||
uint8_t matchable;
|
||||
|
||||
uint8_t multipart_form_data:1;
|
||||
uint8_t inside_quote:1;
|
||||
uint8_t subname:1;
|
||||
uint8_t boundary_real_crlf:1;
|
||||
|
||||
enum urldecode_stateful state;
|
||||
|
||||
lws_urldecode_stateful_cb output;
|
||||
};
|
||||
|
||||
struct lws_spa {
|
||||
struct lws_urldecode_stateful *s;
|
||||
lws_spa_create_info_t i;
|
||||
int *param_length;
|
||||
char finalized;
|
||||
char **params;
|
||||
char *storage;
|
||||
char *end;
|
||||
};
|
||||
|
||||
static struct lws_urldecode_stateful *
|
||||
lws_urldecode_s_create(struct lws_spa *spa, struct lws *wsi, char *out,
|
||||
int out_len, lws_urldecode_stateful_cb output)
|
||||
{
|
||||
struct lws_urldecode_stateful *s;
|
||||
char buf[205], *p;
|
||||
int m = 0;
|
||||
|
||||
if (spa->i.ac)
|
||||
s = lwsac_use_zero(spa->i.ac, sizeof(*s), spa->i.ac_chunk_size);
|
||||
else
|
||||
s = lws_zalloc(sizeof(*s), "stateful urldecode");
|
||||
|
||||
if (!s)
|
||||
return NULL;
|
||||
|
||||
s->out = out;
|
||||
s->out_len = out_len;
|
||||
s->output = output;
|
||||
s->pos = 0;
|
||||
s->sum = 0;
|
||||
s->mp = 0;
|
||||
s->state = US_NAME;
|
||||
s->name[0] = '\0';
|
||||
s->data = spa;
|
||||
s->wsi = wsi;
|
||||
|
||||
if (lws_hdr_copy(wsi, buf, sizeof(buf),
|
||||
WSI_TOKEN_HTTP_CONTENT_TYPE) > 0) {
|
||||
/* multipart/form-data;
|
||||
* boundary=----WebKitFormBoundarycc7YgAPEIHvgE9Bf */
|
||||
|
||||
if (!strncmp(buf, "multipart/form-data", 19) ||
|
||||
!strncmp(buf, "multipart/related", 17)) {
|
||||
s->multipart_form_data = 1;
|
||||
s->state = MT_LOOK_BOUND_IN;
|
||||
s->mp = 2;
|
||||
p = strstr(buf, "boundary=");
|
||||
if (p) {
|
||||
p += 9;
|
||||
s->mime_boundary[m++] = '\x0d';
|
||||
s->mime_boundary[m++] = '\x0a';
|
||||
s->mime_boundary[m++] = '-';
|
||||
s->mime_boundary[m++] = '-';
|
||||
if (*p == '\"')
|
||||
p++;
|
||||
while (m < (int)sizeof(s->mime_boundary) - 1 &&
|
||||
*p && *p != ' ' && *p != ';' && *p != '\"')
|
||||
s->mime_boundary[m++] = *p++;
|
||||
s->mime_boundary[m] = '\0';
|
||||
|
||||
// lwsl_notice("boundary '%s'\n", s->mime_boundary);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
static int
|
||||
lws_urldecode_s_process(struct lws_urldecode_stateful *s, const char *in,
|
||||
int len)
|
||||
{
|
||||
int n, hit;
|
||||
char c;
|
||||
|
||||
while (len--) {
|
||||
if (s->pos == s->out_len - s->mp - 1) {
|
||||
if (s->output(s->data, s->name, &s->out, s->pos,
|
||||
LWS_UFS_CONTENT))
|
||||
return -1;
|
||||
|
||||
s->pos = 0;
|
||||
}
|
||||
|
||||
switch (s->state) {
|
||||
|
||||
/* states for url arg style */
|
||||
|
||||
case US_NAME:
|
||||
s->inside_quote = 0;
|
||||
if (*in == '=') {
|
||||
s->name[s->pos] = '\0';
|
||||
s->pos = 0;
|
||||
s->state = US_IDLE;
|
||||
in++;
|
||||
continue;
|
||||
}
|
||||
if (*in == '&') {
|
||||
s->name[s->pos] = '\0';
|
||||
if (s->output(s->data, s->name, &s->out,
|
||||
s->pos, LWS_UFS_FINAL_CONTENT))
|
||||
return -1;
|
||||
s->pos = 0;
|
||||
s->state = US_IDLE;
|
||||
in++;
|
||||
continue;
|
||||
}
|
||||
if (s->pos >= (int)sizeof(s->name) - 1) {
|
||||
lwsl_hexdump_notice(s->name, (size_t)s->pos);
|
||||
lwsl_notice("Name too long...\n");
|
||||
return -1;
|
||||
}
|
||||
s->name[s->pos++] = *in++;
|
||||
break;
|
||||
case US_IDLE:
|
||||
if (*in == '%') {
|
||||
s->state++;
|
||||
in++;
|
||||
continue;
|
||||
}
|
||||
if (*in == '&') {
|
||||
s->out[s->pos] = '\0';
|
||||
if (s->output(s->data, s->name, &s->out,
|
||||
s->pos, LWS_UFS_FINAL_CONTENT))
|
||||
return -1;
|
||||
s->pos = 0;
|
||||
s->state = US_NAME;
|
||||
in++;
|
||||
continue;
|
||||
}
|
||||
if (*in == '+') {
|
||||
in++;
|
||||
s->out[s->pos++] = ' ';
|
||||
continue;
|
||||
}
|
||||
s->out[s->pos++] = *in++;
|
||||
break;
|
||||
case US_PC1:
|
||||
n = char_to_hex(*in);
|
||||
if (n < 0)
|
||||
return -1;
|
||||
|
||||
in++;
|
||||
s->sum = n << 4;
|
||||
s->state++;
|
||||
break;
|
||||
|
||||
case US_PC2:
|
||||
n = char_to_hex(*in);
|
||||
if (n < 0)
|
||||
return -1;
|
||||
|
||||
in++;
|
||||
s->out[s->pos++] = (char)(s->sum | n);
|
||||
s->state = US_IDLE;
|
||||
break;
|
||||
|
||||
|
||||
/* states for multipart / mime style */
|
||||
|
||||
case MT_LOOK_BOUND_IN:
|
||||
retry_as_first:
|
||||
if (*in == s->mime_boundary[s->mp] &&
|
||||
s->mime_boundary[s->mp]) {
|
||||
in++;
|
||||
s->mp++;
|
||||
if (!s->mime_boundary[s->mp]) {
|
||||
s->mp = 0;
|
||||
s->state = MT_IGNORE1;
|
||||
|
||||
if (s->output(s->data, s->name,
|
||||
&s->out, s->pos,
|
||||
LWS_UFS_FINAL_CONTENT))
|
||||
return -1;
|
||||
|
||||
s->pos = 0;
|
||||
|
||||
s->content_disp[0] = '\0';
|
||||
s->name[0] = '\0';
|
||||
s->content_disp_filename[0] = '\0';
|
||||
s->boundary_real_crlf = 1;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
if (s->mp) {
|
||||
n = 0;
|
||||
if (!s->boundary_real_crlf)
|
||||
n = 2;
|
||||
if (s->mp >= n) {
|
||||
memcpy(s->out + s->pos,
|
||||
s->mime_boundary + n,
|
||||
(unsigned int)(s->mp - n));
|
||||
s->pos += s->mp;
|
||||
s->mp = 0;
|
||||
goto retry_as_first;
|
||||
}
|
||||
}
|
||||
|
||||
s->out[s->pos++] = *in;
|
||||
in++;
|
||||
s->mp = 0;
|
||||
break;
|
||||
|
||||
case MT_HNAME:
|
||||
c =*in;
|
||||
if (c >= 'A' && c <= 'Z')
|
||||
c = (char)(c + 'a' - 'A');
|
||||
if (!s->mp)
|
||||
/* initially, any of them might match */
|
||||
s->matchable = (1 << LWS_ARRAY_SIZE(mp_hdrs)) - 1;
|
||||
|
||||
hit = -1;
|
||||
for (n = 0; n < (int)LWS_ARRAY_SIZE(mp_hdrs); n++) {
|
||||
|
||||
if (!(s->matchable & (1 << n)))
|
||||
continue;
|
||||
/* this guy is still in contention... */
|
||||
|
||||
if (s->mp >= mp_hdrs[n].hdr_len) {
|
||||
/* he went past the end of it */
|
||||
s->matchable &= (uint8_t)~(1 << n);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (c != mp_hdrs[n].hdr[s->mp]) {
|
||||
/* mismatched a char */
|
||||
s->matchable &= (uint8_t)~(1 << n);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (s->mp + 1 == mp_hdrs[n].hdr_len) {
|
||||
/* we have a winner... */
|
||||
hit = n;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
in++;
|
||||
if (hit == -1 && !s->matchable) {
|
||||
/* We ruled them all out */
|
||||
s->state = MT_IGNORE1;
|
||||
s->mp = 0;
|
||||
continue;
|
||||
}
|
||||
|
||||
s->mp++;
|
||||
if (hit < 0)
|
||||
continue;
|
||||
|
||||
/* we matched the one in hit */
|
||||
|
||||
s->mp = 0;
|
||||
s->temp[0] = '\0';
|
||||
s->subname = 0;
|
||||
|
||||
if (hit == 2)
|
||||
s->state = MT_LOOK_BOUND_IN;
|
||||
else
|
||||
s->state += (unsigned int)hit + 1u;
|
||||
break;
|
||||
|
||||
case MT_DISP:
|
||||
/* form-data; name="file"; filename="t.txt" */
|
||||
|
||||
if (*in == '\x0d') {
|
||||
if (s->content_disp_filename[0])
|
||||
if (s->output(s->data, s->name,
|
||||
&s->out, s->pos,
|
||||
LWS_UFS_OPEN))
|
||||
return -1;
|
||||
s->state = MT_IGNORE2;
|
||||
goto done;
|
||||
}
|
||||
if (*in == ';') {
|
||||
s->subname = 1;
|
||||
s->temp[0] = '\0';
|
||||
s->mp = 0;
|
||||
goto done;
|
||||
}
|
||||
|
||||
if (*in == '\"') {
|
||||
s->inside_quote = !!((s->inside_quote ^ 1) & 1);
|
||||
goto done;
|
||||
}
|
||||
|
||||
if (s->subname) {
|
||||
if (*in == '=') {
|
||||
s->temp[s->mp] = '\0';
|
||||
s->subname = 0;
|
||||
s->mp = 0;
|
||||
goto done;
|
||||
}
|
||||
if (s->mp < (int)sizeof(s->temp) - 1 &&
|
||||
(*in != ' ' || s->inside_quote))
|
||||
s->temp[s->mp++] = *in;
|
||||
goto done;
|
||||
}
|
||||
|
||||
if (!s->temp[0]) {
|
||||
if (s->mp < (int)sizeof(s->content_disp) - 1)
|
||||
s->content_disp[s->mp++] = *in;
|
||||
if (s->mp < (int)sizeof(s->content_disp))
|
||||
s->content_disp[s->mp] = '\0';
|
||||
goto done;
|
||||
}
|
||||
|
||||
if (!strcmp(s->temp, "name")) {
|
||||
if (s->mp < (int)sizeof(s->name) - 1)
|
||||
s->name[s->mp++] = *in;
|
||||
else
|
||||
s->mp = (int)sizeof(s->name) - 1;
|
||||
s->name[s->mp] = '\0';
|
||||
goto done;
|
||||
}
|
||||
|
||||
if (!strcmp(s->temp, "filename")) {
|
||||
if (s->mp < (int)sizeof(s->content_disp_filename) - 1)
|
||||
s->content_disp_filename[s->mp++] = *in;
|
||||
s->content_disp_filename[s->mp] = '\0';
|
||||
goto done;
|
||||
}
|
||||
done:
|
||||
in++;
|
||||
break;
|
||||
|
||||
case MT_TYPE:
|
||||
if (*in == '\x0d')
|
||||
s->state = MT_IGNORE2;
|
||||
else {
|
||||
if (s->mp < (int)sizeof(s->content_type) - 1)
|
||||
s->content_type[s->mp++] = *in;
|
||||
s->content_type[s->mp] = '\0';
|
||||
}
|
||||
in++;
|
||||
break;
|
||||
|
||||
case MT_IGNORE1:
|
||||
if (*in == '\x0d')
|
||||
s->state = MT_IGNORE2;
|
||||
if (*in == '-')
|
||||
s->state = MT_IGNORE3;
|
||||
in++;
|
||||
break;
|
||||
|
||||
case MT_IGNORE2:
|
||||
s->mp = 0;
|
||||
if (*in == '\x0a')
|
||||
s->state = MT_HNAME;
|
||||
in++;
|
||||
break;
|
||||
|
||||
case MT_IGNORE3:
|
||||
if (*in == '\x0d')
|
||||
s->state = MT_IGNORE2;
|
||||
if (*in == '-') {
|
||||
s->state = MT_COMPLETED;
|
||||
s->wsi->http.rx_content_remain = 0;
|
||||
}
|
||||
in++;
|
||||
break;
|
||||
case MT_COMPLETED:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
lws_urldecode_s_destroy(struct lws_spa *spa, struct lws_urldecode_stateful *s)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
if (s->state != US_IDLE)
|
||||
ret = -1;
|
||||
|
||||
if (!ret)
|
||||
if (s->output(s->data, s->name, &s->out, s->pos,
|
||||
LWS_UFS_FINAL_CONTENT))
|
||||
ret = -1;
|
||||
|
||||
if (s->output(s->data, s->name, NULL, 0, LWS_UFS_CLOSE))
|
||||
return -1;
|
||||
|
||||
if (!spa->i.ac)
|
||||
lws_free(s);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int
|
||||
lws_urldecode_spa_lookup(struct lws_spa *spa, const char *name)
|
||||
{
|
||||
const char * const *pp = spa->i.param_names;
|
||||
int n;
|
||||
|
||||
for (n = 0; n < spa->i.count_params; n++) {
|
||||
if (!*pp && !spa->i.param_names_stride && spa->i.ac) {
|
||||
unsigned int len = (unsigned int)strlen(name);
|
||||
char **ptr = (char**)spa->i.param_names;
|
||||
|
||||
/* Use NULLs at end of list to dynamically create
|
||||
* unknown entries */
|
||||
|
||||
ptr[n] = lwsac_use(spa->i.ac, len + 1, spa->i.ac_chunk_size);
|
||||
if (!ptr[n])
|
||||
return -1;
|
||||
|
||||
memcpy(ptr[n], name, len);
|
||||
ptr[n][len] = '\0';
|
||||
|
||||
return n;
|
||||
}
|
||||
if (*pp && !strcmp(*pp, name))
|
||||
return n;
|
||||
|
||||
if (spa->i.param_names_stride)
|
||||
pp = (const char * const *)(((char *)pp) + spa->i.param_names_stride);
|
||||
else
|
||||
pp++;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int
|
||||
lws_urldecode_spa_cb(struct lws_spa *spa, const char *name, char **buf, int len,
|
||||
int final)
|
||||
{
|
||||
int n;
|
||||
|
||||
if (final == LWS_UFS_CLOSE || spa->s->content_disp_filename[0]) {
|
||||
if (spa->i.opt_cb) {
|
||||
n = spa->i.opt_cb(spa->i.opt_data, name,
|
||||
spa->s->content_disp_filename,
|
||||
buf ? *buf : NULL, len, (enum lws_spa_fileupload_states)final);
|
||||
|
||||
if (n < 0)
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
n = lws_urldecode_spa_lookup(spa, name);
|
||||
if (n == -1 || !len) /* unrecognized */
|
||||
return 0;
|
||||
|
||||
if (!spa->i.ac) {
|
||||
if (!spa->params[n])
|
||||
spa->params[n] = *buf;
|
||||
|
||||
if ((*buf) + len >= spa->end) {
|
||||
lwsl_info("%s: exceeded storage\n", __func__);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* move it on inside storage */
|
||||
(*buf) += len;
|
||||
*((*buf)++) = '\0';
|
||||
|
||||
spa->s->out_len -= len + 1;
|
||||
} else {
|
||||
spa->params[n] = lwsac_use(spa->i.ac, (unsigned int)len + 1,
|
||||
spa->i.ac_chunk_size);
|
||||
if (!spa->params[n])
|
||||
return -1;
|
||||
|
||||
memcpy(spa->params[n], *buf, (unsigned int)len);
|
||||
spa->params[n][len] = '\0';
|
||||
}
|
||||
|
||||
spa->param_length[n] += len;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct lws_spa *
|
||||
lws_spa_create_via_info(struct lws *wsi, const lws_spa_create_info_t *i)
|
||||
{
|
||||
struct lws_spa *spa;
|
||||
|
||||
if (i->ac)
|
||||
spa = lwsac_use_zero(i->ac, sizeof(*spa), i->ac_chunk_size);
|
||||
else
|
||||
spa = lws_zalloc(sizeof(*spa), "spa");
|
||||
|
||||
if (!spa)
|
||||
return NULL;
|
||||
|
||||
spa->i = *i;
|
||||
if (!spa->i.max_storage)
|
||||
spa->i.max_storage = 512;
|
||||
|
||||
if (i->ac)
|
||||
spa->storage = lwsac_use(i->ac, (unsigned int)spa->i.max_storage,
|
||||
i->ac_chunk_size);
|
||||
else
|
||||
spa->storage = lws_malloc((unsigned int)spa->i.max_storage, "spa");
|
||||
|
||||
if (!spa->storage)
|
||||
goto bail2;
|
||||
|
||||
spa->end = spa->storage + spa->i.max_storage - 1;
|
||||
|
||||
if (i->count_params) {
|
||||
if (i->ac)
|
||||
spa->params = lwsac_use_zero(i->ac,
|
||||
sizeof(char *) * (unsigned int)i->count_params, i->ac_chunk_size);
|
||||
else
|
||||
spa->params = lws_zalloc(sizeof(char *) * (unsigned int)i->count_params,
|
||||
"spa params");
|
||||
if (!spa->params)
|
||||
goto bail3;
|
||||
}
|
||||
|
||||
spa->s = lws_urldecode_s_create(spa, wsi, spa->storage, spa->i.max_storage,
|
||||
lws_urldecode_spa_cb);
|
||||
if (!spa->s)
|
||||
goto bail4;
|
||||
|
||||
if (i->count_params) {
|
||||
if (i->ac)
|
||||
spa->param_length = lwsac_use_zero(i->ac,
|
||||
sizeof(int) * (unsigned int)i->count_params, i->ac_chunk_size);
|
||||
else
|
||||
spa->param_length = lws_zalloc(sizeof(int) * (unsigned int)i->count_params,
|
||||
"spa param len");
|
||||
if (!spa->param_length)
|
||||
goto bail5;
|
||||
}
|
||||
|
||||
// lwsl_notice("%s: Created SPA %p\n", __func__, spa);
|
||||
|
||||
return spa;
|
||||
|
||||
bail5:
|
||||
lws_urldecode_s_destroy(spa, spa->s);
|
||||
bail4:
|
||||
if (!i->ac)
|
||||
lws_free(spa->params);
|
||||
bail3:
|
||||
if (!i->ac)
|
||||
lws_free(spa->storage);
|
||||
bail2:
|
||||
if (!i->ac)
|
||||
lws_free(spa);
|
||||
|
||||
if (i->ac)
|
||||
lwsac_free(i->ac);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct lws_spa *
|
||||
lws_spa_create(struct lws *wsi, const char * const *param_names,
|
||||
int count_params, int max_storage,
|
||||
lws_spa_fileupload_cb opt_cb, void *opt_data)
|
||||
{
|
||||
lws_spa_create_info_t i;
|
||||
|
||||
memset(&i, 0, sizeof(i));
|
||||
i.count_params = count_params;
|
||||
i.max_storage = max_storage;
|
||||
i.opt_cb = opt_cb;
|
||||
i.opt_data = opt_data;
|
||||
i.param_names = param_names;
|
||||
|
||||
return lws_spa_create_via_info(wsi, &i);
|
||||
}
|
||||
|
||||
int
|
||||
lws_spa_process(struct lws_spa *spa, const char *in, int len)
|
||||
{
|
||||
if (!spa) {
|
||||
lwsl_err("%s: NULL spa\n", __func__);
|
||||
return -1;
|
||||
}
|
||||
/* we reject any junk after the last part arrived and we finalized */
|
||||
if (spa->finalized)
|
||||
return 0;
|
||||
|
||||
return lws_urldecode_s_process(spa->s, in, len);
|
||||
}
|
||||
|
||||
int
|
||||
lws_spa_get_length(struct lws_spa *spa, int n)
|
||||
{
|
||||
if (n >= spa->i.count_params)
|
||||
return 0;
|
||||
|
||||
return spa->param_length[n];
|
||||
}
|
||||
|
||||
const char *
|
||||
lws_spa_get_string(struct lws_spa *spa, int n)
|
||||
{
|
||||
if (n >= spa->i.count_params)
|
||||
return NULL;
|
||||
|
||||
return spa->params[n];
|
||||
}
|
||||
|
||||
int
|
||||
lws_spa_finalize(struct lws_spa *spa)
|
||||
{
|
||||
if (!spa)
|
||||
return 0;
|
||||
|
||||
if (spa->s) {
|
||||
lws_urldecode_s_destroy(spa, spa->s);
|
||||
spa->s = NULL;
|
||||
}
|
||||
|
||||
spa->finalized = 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
lws_spa_destroy(struct lws_spa *spa)
|
||||
{
|
||||
int n = 0;
|
||||
|
||||
lwsl_info("%s: destroy spa %p\n", __func__, spa);
|
||||
|
||||
if (spa->s)
|
||||
lws_urldecode_s_destroy(spa, spa->s);
|
||||
|
||||
if (spa->i.ac)
|
||||
lwsac_free(spa->i.ac);
|
||||
else {
|
||||
lws_free(spa->param_length);
|
||||
lws_free(spa->params);
|
||||
lws_free(spa->storage);
|
||||
lws_free(spa);
|
||||
}
|
||||
|
||||
return n;
|
||||
}
|
214
Kinc/Sources/kinc/libs/core/server/ranges.c
Normal file
214
Kinc/Sources/kinc/libs/core/server/ranges.c
Normal file
@ -0,0 +1,214 @@
|
||||
/*
|
||||
* libwebsockets - small server side websockets and web server implementation
|
||||
*
|
||||
* Copyright (C) 2010 - 2019 Andy Green <andy@warmcat.com>
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#include "private-lib-core.h"
|
||||
|
||||
/*
|
||||
* RFC7233 examples
|
||||
*
|
||||
* o The first 500 bytes (byte offsets 0-499, inclusive):
|
||||
*
|
||||
* bytes=0-499
|
||||
*
|
||||
* o The second 500 bytes (byte offsets 500-999, inclusive):
|
||||
*
|
||||
* bytes=500-999
|
||||
*
|
||||
* o The final 500 bytes (byte offsets 9500-9999, inclusive):
|
||||
*
|
||||
* bytes=-500
|
||||
*
|
||||
* Or:
|
||||
*
|
||||
* bytes=9500-
|
||||
*
|
||||
* o The first and last bytes only (bytes 0 and 9999):
|
||||
*
|
||||
* bytes=0-0,-1
|
||||
*
|
||||
* o Other valid (but not canonical) specifications of the second 500
|
||||
* bytes (byte offsets 500-999, inclusive):
|
||||
*
|
||||
* bytes=500-600,601-999
|
||||
* bytes=500-700,601-999
|
||||
*/
|
||||
|
||||
/*
|
||||
* returns 1 if the range struct represents a usable range
|
||||
* if no ranges header, you get one of these for the whole
|
||||
* file. Otherwise you get one for each valid range in the
|
||||
* header.
|
||||
*
|
||||
* returns 0 if no further valid range forthcoming; rp->state
|
||||
* may be LWSRS_SYNTAX or LWSRS_COMPLETED
|
||||
*/
|
||||
|
||||
int
|
||||
lws_ranges_next(struct lws_range_parsing *rp)
|
||||
{
|
||||
static const char * const beq = "bytes=";
|
||||
|
||||
while (1) {
|
||||
|
||||
char c = rp->buf[rp->pos];
|
||||
|
||||
switch (rp->state) {
|
||||
case LWSRS_SYNTAX:
|
||||
case LWSRS_COMPLETED:
|
||||
return 0;
|
||||
|
||||
case LWSRS_NO_ACTIVE_RANGE:
|
||||
rp->state = LWSRS_COMPLETED;
|
||||
return 0;
|
||||
|
||||
case LWSRS_BYTES_EQ: // looking for "bytes="
|
||||
if (c != beq[rp->pos]) {
|
||||
rp->state = LWSRS_SYNTAX;
|
||||
return -1;
|
||||
}
|
||||
if (rp->pos == 5)
|
||||
rp->state = LWSRS_FIRST;
|
||||
break;
|
||||
|
||||
case LWSRS_FIRST:
|
||||
rp->start = 0;
|
||||
rp->end = 0;
|
||||
rp->start_valid = 0;
|
||||
rp->end_valid = 0;
|
||||
|
||||
rp->state = LWSRS_STARTING;
|
||||
|
||||
// fallthru
|
||||
|
||||
case LWSRS_STARTING:
|
||||
if (c == '-') {
|
||||
rp->state = LWSRS_ENDING;
|
||||
break;
|
||||
}
|
||||
|
||||
if (!(c >= '0' && c <= '9')) {
|
||||
rp->state = LWSRS_SYNTAX;
|
||||
return 0;
|
||||
}
|
||||
rp->start = (unsigned long long)(((unsigned long long)rp->start * 10) + (unsigned long long)(c - '0'));
|
||||
rp->start_valid = 1;
|
||||
break;
|
||||
|
||||
case LWSRS_ENDING:
|
||||
if (c == ',' || c == '\0') {
|
||||
rp->state = LWSRS_FIRST;
|
||||
if (c == ',')
|
||||
rp->pos++;
|
||||
|
||||
/*
|
||||
* By the end of this, start and end are
|
||||
* always valid if the range still is
|
||||
*/
|
||||
|
||||
if (!rp->start_valid) { /* eg, -500 */
|
||||
if (rp->end > rp->extent)
|
||||
rp->end = rp->extent;
|
||||
|
||||
rp->start = rp->extent - rp->end;
|
||||
rp->end = rp->extent - 1;
|
||||
} else
|
||||
if (!rp->end_valid)
|
||||
rp->end = rp->extent - 1;
|
||||
|
||||
rp->did_try = 1;
|
||||
|
||||
/* end must be >= start or ignore it */
|
||||
if (rp->end < rp->start) {
|
||||
if (c == ',')
|
||||
break;
|
||||
rp->state = LWSRS_COMPLETED;
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1; /* issue range */
|
||||
}
|
||||
|
||||
if (!(c >= '0' && c <= '9')) {
|
||||
rp->state = LWSRS_SYNTAX;
|
||||
return 0;
|
||||
}
|
||||
rp->end = (unsigned long long)(((unsigned long long)rp->end * 10) + (unsigned long long)(c - '0'));
|
||||
rp->end_valid = 1;
|
||||
break;
|
||||
}
|
||||
|
||||
rp->pos++;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
lws_ranges_reset(struct lws_range_parsing *rp)
|
||||
{
|
||||
rp->pos = 0;
|
||||
rp->ctr = 0;
|
||||
rp->start = 0;
|
||||
rp->end = 0;
|
||||
rp->start_valid = 0;
|
||||
rp->end_valid = 0;
|
||||
rp->state = LWSRS_BYTES_EQ;
|
||||
}
|
||||
|
||||
/*
|
||||
* returns count of valid ranges
|
||||
*/
|
||||
int
|
||||
lws_ranges_init(struct lws *wsi, struct lws_range_parsing *rp,
|
||||
unsigned long long extent)
|
||||
{
|
||||
rp->agg = 0;
|
||||
rp->send_ctr = 0;
|
||||
rp->inside = 0;
|
||||
rp->count_ranges = 0;
|
||||
rp->did_try = 0;
|
||||
lws_ranges_reset(rp);
|
||||
rp->state = LWSRS_COMPLETED;
|
||||
|
||||
rp->extent = extent;
|
||||
|
||||
if (lws_hdr_copy(wsi, (char *)rp->buf, sizeof(rp->buf),
|
||||
WSI_TOKEN_HTTP_RANGE) <= 0)
|
||||
return 0;
|
||||
|
||||
rp->state = LWSRS_BYTES_EQ;
|
||||
|
||||
while (lws_ranges_next(rp)) {
|
||||
rp->count_ranges++;
|
||||
rp->agg += rp->end - rp->start + 1;
|
||||
}
|
||||
|
||||
lwsl_debug("%s: count %d\n", __func__, rp->count_ranges);
|
||||
lws_ranges_reset(rp);
|
||||
|
||||
if (rp->did_try && !rp->count_ranges)
|
||||
return -1; /* "not satisfiable */
|
||||
|
||||
lws_ranges_next(rp);
|
||||
|
||||
return rp->count_ranges;
|
||||
}
|
55
Kinc/Sources/kinc/libs/core/server/rewrite.c
Normal file
55
Kinc/Sources/kinc/libs/core/server/rewrite.c
Normal file
@ -0,0 +1,55 @@
|
||||
#include "private-lib-core.h"
|
||||
|
||||
#if defined(LWS_WITH_HUBBUB)
|
||||
|
||||
struct lws_rewrite *
|
||||
lws_rewrite_create(struct lws *wsi, hubbub_callback_t cb, const char *from,
|
||||
const char *to)
|
||||
{
|
||||
struct lws_rewrite *r = lws_malloc(sizeof(*r), "rewrite");
|
||||
|
||||
if (!r) {
|
||||
lwsl_err("OOM\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (hubbub_parser_create("UTF-8", false, &r->parser) != HUBBUB_OK) {
|
||||
lws_free(r);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
r->from = from;
|
||||
r->from_len = strlen(from);
|
||||
r->to = to;
|
||||
r->to_len = strlen(to);
|
||||
r->params.token_handler.handler = cb;
|
||||
r->wsi = wsi;
|
||||
r->params.token_handler.pw = (void *)r;
|
||||
if (hubbub_parser_setopt(r->parser, HUBBUB_PARSER_TOKEN_HANDLER,
|
||||
&r->params) != HUBBUB_OK) {
|
||||
lws_free(r);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
int
|
||||
lws_rewrite_parse(struct lws_rewrite *r,
|
||||
const unsigned char *in, int in_len)
|
||||
{
|
||||
if (r && hubbub_parser_parse_chunk(r->parser, in, in_len) != HUBBUB_OK)
|
||||
return -1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void
|
||||
lws_rewrite_destroy(struct lws_rewrite *r)
|
||||
{
|
||||
hubbub_parser_destroy(r->parser);
|
||||
lws_free(r);
|
||||
}
|
||||
|
||||
#endif
|
3511
Kinc/Sources/kinc/libs/core/server/server.c
Normal file
3511
Kinc/Sources/kinc/libs/core/server/server.c
Normal file
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user