1
0
Fork 0
mirror of https://github.com/warmcat/libwebsockets.git synced 2025-03-09 00:00:04 +01:00

lws_plat_fd implement platform default handlers

This is a rewrite of the patch from Soapyman here

https://github.com/warmcat/libwebsockets/pull/363

The main changes compared to Soapyman's original patch are

 - There's no new stuff in the info struct user code does any overrides
   it may want to do explicitly after lws_context_create returns

 - User overrides for file ops can call through (subclass) to the original
   platform implementation using lws_get_fops_plat()

 - A typedef is provided for plat-specific fd type

 - Public helpers are provided to allow user code to be platform-independent
   about file access, using the lws platform file operations underneath:

static inline lws_filefd_type
lws_plat_file_open(struct lws_plat_file_ops *fops, const char *filename,
		   unsigned long *filelen, int flags)

static inline int
lws_plat_file_close(struct lws_plat_file_ops *fops, lws_filefd_type fd)

static inline unsigned long
lws_plat_file_seek_cur(struct lws_plat_file_ops *fops, lws_filefd_type fd,
		       long offset_from_cur_pos)

static inline int
lws_plat_file_read(struct lws_plat_file_ops *fops, lws_filefd_type fd,
		   unsigned long *amount, unsigned char *buf, unsigned long len)

static inline int
lws_plat_file_write(struct lws_plat_file_ops *fops, lws_filefd_type fd,
		    unsigned long *amount, unsigned char *buf, unsigned long len)

There's example documentation and implementation in the test server.

Signed-off-by: Andy Green <andy.green@linaro.org>
This commit is contained in:
Andy Green 2015-12-10 07:58:58 +08:00
parent 11260dac18
commit 4e442b7743
13 changed files with 483 additions and 179 deletions

View file

@ -276,3 +276,43 @@ After attempting the connection and getting back a non-`NULL` `wsi` you should
loop calling `lws_service()` until one of the above callbacks occurs.
As usual, see [test-client.c](test-server/test-client.c) for example code.
Lws platform-independent file access apis
-----------------------------------------
lws now exposes his internal platform file abstraction in a way that can be
both used by user code to make it platform-agnostic, and be overridden or
subclassed by user code. This allows things like handling the URI "directory
space" as a virtual filesystem that may or may not be backed by a regular
filesystem. One example use is serving files from inside large compressed
archive storage without having to unpack anything except the file being
requested.
The test server shows how to use it, basically the platform-specific part of
lws prepares a file operations structure that lives in the lws context.
The user code can get a pointer to the file operations struct
LWS_VISIBLE LWS_EXTERN struct lws_plat_file_ops *
`lws_get_fops`(struct lws_context *context);
and then can use it with helpers to also leverage these platform-independent
file handling apis
static inline lws_filefd_type
`lws_plat_file_open`(struct lws_plat_file_ops *fops, const char *filename, unsigned long *filelen, int flags)
static inline int
`lws_plat_file_close`(struct lws_plat_file_ops *fops, lws_filefd_type fd)
static inline unsigned long
`lws_plat_file_seek_cur`(struct lws_plat_file_ops *fops, lws_filefd_type fd, long offset_from_cur_pos)
static inline int
`lws_plat_file_read`(struct lws_plat_file_ops *fops, lws_filefd_type fd, unsigned long *amount, unsigned char *buf, unsigned long len)
static inline int
`lws_plat_file_write`(struct lws_plat_file_ops *fops, lws_filefd_type fd, unsigned long *amount, unsigned char *buf, unsigned long len)
The user code can also override or subclass the file operations, to either
wrap or replace them. An example is shown in test server.

View file

@ -1,6 +1,51 @@
Changelog
---------
User api additions
------------------
lws now exposes his internal platform file abstraction in a way that can be
both used by user code to make it platform-agnostic, and be overridden or
subclassed by user code. This allows things like handling the URI "directory
space" as a virtual filesystem that may or may not be backed by a regular
filesystem. One example use is serving files from inside large compressed
archive storage without having to unpack anything except the file being
requested.
The test server shows how to use it, basically the platform-specific part of
lws prepares a file operations structure that lives in the lws context.
The user code can get a pointer to the file operations struct
LWS_VISIBLE LWS_EXTERN struct lws_plat_file_ops *
lws_get_fops(struct lws_context *context);
and then can use it with helpers to also leverage these platform-independent
file handling apis
static inline lws_filefd_type
lws_plat_file_open(struct lws_plat_file_ops *fops, const char *filename,
unsigned long *filelen, int flags)
static inline int
lws_plat_file_close(struct lws_plat_file_ops *fops, lws_filefd_type fd)
static inline unsigned long
lws_plat_file_seek_cur(struct lws_plat_file_ops *fops, lws_filefd_type fd,
long offset_from_cur_pos)
static inline int
lws_plat_file_read(struct lws_plat_file_ops *fops, lws_filefd_type fd,
unsigned long *amount, unsigned char *buf, unsigned long len)
static inline int
lws_plat_file_write(struct lws_plat_file_ops *fops, lws_filefd_type fd,
unsigned long *amount, unsigned char *buf, unsigned long len)
The user code can also override or subclass the file operations, to either
wrap or replace them. An example is shown in test server.
User api changes
----------------

View file

@ -73,7 +73,7 @@ lws_close_and_free_session(struct lws_context *context,
if (wsi->mode == LWS_CONNMODE_HTTP_SERVING_ACCEPTED &&
wsi->u.http.fd != LWS_INVALID_FILE) {
lwsl_debug("closing http file\n");
compatible_file_close(wsi->u.http.fd);
lws_plat_file_close(&context->fops, wsi->u.http.fd);
wsi->u.http.fd = LWS_INVALID_FILE;
context->protocols[0].callback(context, wsi,
LWS_CALLBACK_CLOSED_HTTP, wsi->user_space, NULL, 0);
@ -929,6 +929,11 @@ lws_union_transition(struct lws *wsi, enum connection_mode mode)
wsi->mode = mode;
}
LWS_VISIBLE struct lws_plat_file_ops *
lws_get_fops(struct lws_context *context)
{
return &context->fops;
}
#ifdef LWS_WITH_OLD_API_WRAPPERS

View file

@ -177,9 +177,13 @@ extern "C" {
#else
#define LWS_EXTERN
#endif
#define LWS_INVALID_FILE INVALID_HANDLE_VALUE
#else /* NOT WIN32 */
#include <unistd.h>
#define LWS_INVALID_FILE -1
#ifndef MBED_OPERATORS
#include <poll.h>
@ -296,6 +300,9 @@ LWS_VISIBLE LWS_EXTERN void lwsl_hexdump(void *buf, size_t len);
/* extra parameter introduced in 917f43ab821 */
#define LWS_FEATURE_SERVE_HTTP_FILE_HAS_OTHER_HEADERS_LEN
/* File operations stuff exists */
#define LWS_FEATURE_FOPS
/*
* NOTE: These public enums are part of the abi. If you want to add one,
* add it at where specified so existing users are unaffected.
@ -1626,6 +1633,55 @@ LWS_VISIBLE LWS_EXTERN int
lws_hdr_copy(struct lws *wsi, char *dest, int len,
enum lws_token_indexes h);
/* get the active file operations struct */
LWS_VISIBLE LWS_EXTERN struct lws_plat_file_ops *
lws_get_fops(struct lws_context *context);
/*
* File Operations access helpers
*
* usually the first argument will be lws_get_fops(context)
* If so, then it calls the platform handler or user overrides where present
* (as defined in info->fops)
*
* The advantage from all this is user code can be portable for file operations
* without having to deal with differences between platforms.
*/
static inline lws_filefd_type
lws_plat_file_open(struct lws_plat_file_ops *fops, const char *filename,
unsigned long *filelen, int flags)
{
return fops->open(filename, filelen, flags);
}
static inline int
lws_plat_file_close(struct lws_plat_file_ops *fops, lws_filefd_type fd)
{
return fops->close(fd);
}
static inline unsigned long
lws_plat_file_seek_cur(struct lws_plat_file_ops *fops, lws_filefd_type fd,
long offset_from_cur_pos)
{
return fops->seek_cur(fd, offset_from_cur_pos);
}
static inline int
lws_plat_file_read(struct lws_plat_file_ops *fops, lws_filefd_type fd,
unsigned long *amount, unsigned char *buf, unsigned long len)
{
return fops->read(fd, amount, buf, len);
}
static inline int
lws_plat_file_write(struct lws_plat_file_ops *fops, lws_filefd_type fd,
unsigned long *amount, unsigned char *buf, unsigned long len)
{
return fops->write(fd, amount, buf, len);
}
/*
* Note: this is not normally needed as a user api. It's provided in case it is
* useful when integrating with other app poll loop service code.

View file

@ -105,14 +105,6 @@ lws_plat_drop_app_privileges(struct lws_context_creation_info *info)
(void)info;
}
LWS_VISIBLE int
lws_plat_init(struct lws_context *context,
struct lws_context_creation_info *info)
{
return 0;
}
LWS_VISIBLE int
lws_plat_context_early_init(void)
{
@ -138,14 +130,6 @@ lws_plat_service_periodic(struct lws_context *context)
(void)context;
}
LWS_VISIBLE int
lws_plat_open_file(const char* filename, unsigned long* filelen)
{
(void)filename;
(void)filelen;
return LWS_INVALID_FILE;
}
LWS_VISIBLE const char *
lws_plat_inet_ntop(int af, const void *src, char *dst, int cnt)
{
@ -172,4 +156,66 @@ delete_from_fd(struct lws_context *context, lws_sockfd_type fd)
(void)fd;
return 1;
}
}
static lws_filefd_type
_lws_plat_file_open(const char *filename, unsigned long *filelen, int flags)
{
(void)filename;
(void)filelen;
(void)flags;
return -1;
}
static int
_lws_plat_file_close(lws_filefd_type fd)
{
(void)fd;
return -1;
}
unsigned long
_lws_plat_file_seek_cur(lws_filefd_type fd, long offset)
{
(void)fd;
(void)offset;
return -1;
}
static int
_lws_plat_file_read(lws_filefd_type fd, unsigned long *amount,
unsigned char* buf, unsigned long* len)
{
(void)amount;
(void)fd;
(void)buf;
(void)len;
return -1;
}
static int
_lws_plat_file_write(lws_filefd_type fd, unsigned long *amount,
unsigned char* buf, unsigned long len)
{
(void)amount;
(void)fd;
(void)buf;
(void)len;
return -1;
}
LWS_VISIBLE int
lws_plat_init(struct lws_context *context,
struct lws_context_creation_info *info)
{
context->fops.open = _lws_plat_file_open;
context->fops.close = _lws_plat_file_close;
context->fops.seek_cur = _lws_plat_file_seek_cur;
context->fops.read = _lws_plat_file_read;
context->fops.write = _lws_plat_file_write;
return 0;
}

View file

@ -271,43 +271,6 @@ lws_plat_drop_app_privileges(struct lws_context_creation_info *info)
}
LWS_VISIBLE int
lws_plat_init(struct lws_context *context,
struct lws_context_creation_info *info)
{
context->lws_lookup = lws_zalloc(sizeof(struct lws *) * context->max_fds);
if (context->lws_lookup == NULL) {
lwsl_err(
"Unable to allocate lws_lookup array for %d connections\n",
context->max_fds);
return 1;
}
context->fd_random = open(SYSTEM_RANDOM_FILEPATH, O_RDONLY);
if (context->fd_random < 0) {
lwsl_err("Unable to open random device %s %d\n",
SYSTEM_RANDOM_FILEPATH, context->fd_random);
return 1;
}
if (lws_libev_init_fd_table(context))
/* libev handled it instead */
return 0;
if (pipe(context->dummy_pipe_fds)) {
lwsl_err("Unable to create pipe\n");
return 1;
}
/* use the read end of pipe as first item */
context->fds[0].fd = context->dummy_pipe_fds[0];
context->fds[0].events = LWS_POLLIN;
context->fds[0].revents = 0;
context->fds_count = 1;
return 0;
}
static void sigpipe_handler(int x)
{
}
@ -446,11 +409,17 @@ lws_plat_change_pollfd(struct lws_context *context,
return 0;
}
LWS_VISIBLE int
lws_plat_open_file(const char* filename, unsigned long* filelen)
LWS_VISIBLE const char *
lws_plat_inet_ntop(int af, const void *src, char *dst, int cnt)
{
return inet_ntop(af, src, dst, cnt);
}
static lws_filefd_type
_lws_plat_file_open(const char *filename, unsigned long *filelen, int flags)
{
struct stat stat_buf;
int ret = open(filename, O_RDONLY);
int ret = open(filename, flags, 0664);
if (ret < 0)
return LWS_INVALID_FILE;
@ -463,8 +432,91 @@ lws_plat_open_file(const char* filename, unsigned long* filelen)
return ret;
}
LWS_VISIBLE const char *
lws_plat_inet_ntop(int af, const void *src, char *dst, int cnt)
static int
_lws_plat_file_close(lws_filefd_type fd)
{
return inet_ntop(af, src, dst, cnt);
return close(fd);
}
unsigned long
_lws_plat_file_seek_cur(lws_filefd_type fd, long offset)
{
return lseek(fd, offset, SEEK_CUR);
}
static int
_lws_plat_file_read(lws_filefd_type fd, unsigned long *amount,
unsigned char *buf, unsigned long len)
{
long n;
n = read((int)fd, buf, len);
if (n == -1) {
*amount = 0;
return -1;
}
*amount = n;
return 0;
}
static int
_lws_plat_file_write(lws_filefd_type fd, unsigned long *amount,
unsigned char *buf, unsigned long len)
{
long n;
n = write((int)fd, buf, len);
if (n == -1) {
*amount = 0;
return -1;
}
*amount = n;
return 0;
}
LWS_VISIBLE int
lws_plat_init(struct lws_context *context,
struct lws_context_creation_info *info)
{
context->lws_lookup = lws_zalloc(sizeof(struct lws *) * context->max_fds);
if (context->lws_lookup == NULL) {
lwsl_err(
"Unable to allocate lws_lookup array for %d connections\n",
context->max_fds);
return 1;
}
context->fd_random = open(SYSTEM_RANDOM_FILEPATH, O_RDONLY);
if (context->fd_random < 0) {
lwsl_err("Unable to open random device %s %d\n",
SYSTEM_RANDOM_FILEPATH, context->fd_random);
return 1;
}
if (lws_libev_init_fd_table(context))
/* libev handled it instead */
return 0;
if (pipe(context->dummy_pipe_fds)) {
lwsl_err("Unable to create pipe\n");
return 1;
}
/* use the read end of pipe as first item */
context->fds[0].fd = context->dummy_pipe_fds[0];
context->fds[0].events = LWS_POLLIN;
context->fds[0].revents = 0;
context->fds_count = 1;
context->fops.open = _lws_plat_file_open;
context->fops.close = _lws_plat_file_close;
context->fops.seek_cur = _lws_plat_file_seek_cur;
context->fops.read = _lws_plat_file_read;
context->fops.write = _lws_plat_file_write;
return 0;
}

View file

@ -256,35 +256,6 @@ lws_plat_drop_app_privileges(struct lws_context_creation_info *info)
{
}
LWS_VISIBLE int
lws_plat_init(struct lws_context *context,
struct lws_context_creation_info *info)
{
int i;
for (i = 0; i < FD_HASHTABLE_MODULUS; i++) {
context->fd_hashtable[i].wsi = lws_zalloc(sizeof(struct lws*) * context->max_fds);
if (!context->fd_hashtable[i].wsi) {
return -1;
}
}
context->events = lws_malloc(sizeof(WSAEVENT) * (context->max_fds + 1));
if (context->events == NULL) {
lwsl_err("Unable to allocate events array for %d connections\n",
context->max_fds);
return 1;
}
context->fds_count = 0;
context->events[0] = WSACreateEvent();
context->fd_random = 0;
return 0;
}
LWS_VISIBLE int
lws_plat_context_early_init(void)
{
@ -393,23 +364,6 @@ lws_plat_change_pollfd(struct lws_context *context,
return 1;
}
LWS_VISIBLE HANDLE
lws_plat_open_file(const char* filename, unsigned long* filelen)
{
HANDLE ret;
WCHAR buffer[MAX_PATH];
MultiByteToWideChar(CP_UTF8, 0, filename, -1, buffer,
sizeof(buffer) / sizeof(buffer[0]));
ret = CreateFileW(buffer, GENERIC_READ, FILE_SHARE_READ,
NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
if (ret != LWS_INVALID_FILE)
*filelen = GetFileSize(ret, NULL);
return ret;
}
LWS_VISIBLE const char *
lws_plat_inet_ntop(int af, const void *src, char *dst, int cnt)
{
@ -455,3 +409,100 @@ lws_plat_inet_ntop(int af, const void *src, char *dst, int cnt)
lws_free(buffer);
return ok ? dst : NULL;
}
static lws_filefd_type
_lws_plat_file_open(const char *filename, unsigned long *filelen, int flags)
{
HANDLE ret;
WCHAR buf[MAX_PATH];
MultiByteToWideChar(CP_UTF8, 0, filename, -1, buf, ARRAY_SIZE(buf));
if (flags & O_RDONLY) {
ret = CreateFileW(buf, GENERIC_READ, FILE_SHARE_READ,
NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
} else {
lwsl_err("%s: open for write not implemented\n", __func__);
*filelen = 0;
return LWS_INVALID_FILE;
}
if (ret != LWS_INVALID_FILE)
*filelen = GetFileSize(ret, NULL);
return ret;
}
static int
_lws_plat_file_close(lws_filefd_type fd)
{
CloseHandle((HANDLE)fd);
return 0;
}
static unsigned long
_lws_plat_file_seek_cur(lws_filefd_type fd, long offset)
{
return SetFilePointer((HANDLE)fd, offset, NULL, FILE_CURRENT);
}
static int
_lws_plat_file_read(lws_filefd_type fd, unsigned long *amount,
unsigned char* buf, unsigned long len)
{
DWORD _amount;
if (!ReadFile((HANDLE)fd, buf, (DWORD)len, &_amount, NULL)) {
*amount = 0;
return 1;
}
*amount = (unsigned long)_amount;
return 0;
}
static int
_lws_plat_file_write(lws_filefd_type fd, unsigned long *amount,
unsigned char* buf, unsigned long len)
{
lwsl_err("%s: not implemented on this platform\n", __func__);
return -1;
}
LWS_VISIBLE int
lws_plat_init(struct lws_context *context,
struct lws_context_creation_info *info)
{
int i;
for (i = 0; i < FD_HASHTABLE_MODULUS; i++) {
context->fd_hashtable[i].wsi =
lws_zalloc(sizeof(struct lws*) * context->max_fds);
if (!context->fd_hashtable[i].wsi)
return -1;
}
context->events = lws_malloc(sizeof(WSAEVENT) * (context->max_fds + 1));
if (context->events == NULL) {
lwsl_err("Unable to allocate events array for %d connections\n",
context->max_fds);
return 1;
}
context->fds_count = 0;
context->events[0] = WSACreateEvent();
context->fd_random = 0;
context->fops.open = _lws_plat_file_open;
context->fops.close = _lws_plat_file_close;
context->fops.seek_cur = _lws_plat_file_seek_cur;
context->fops.read = _lws_plat_file_read;
context->fops.write = _lws_plat_file_write;
return 0;
}

View file

@ -509,8 +509,8 @@ send_raw:
LWS_VISIBLE int lws_serve_http_file_fragment(struct lws_context *context,
struct lws *wsi)
{
int n;
int m;
unsigned long amount;
int n, m;
while (!lws_send_pipe_choked(wsi)) {
@ -518,7 +518,7 @@ LWS_VISIBLE int lws_serve_http_file_fragment(struct lws_context *context,
if (lws_issue_raw(wsi, wsi->truncated_send_malloc +
wsi->truncated_send_offset,
wsi->truncated_send_len) < 0) {
lwsl_info("closing from lws_serve_http_file_fragment\n");
lwsl_info("%s: closing\n", __func__);
return -1;
}
continue;
@ -527,10 +527,12 @@ LWS_VISIBLE int lws_serve_http_file_fragment(struct lws_context *context,
if (wsi->u.http.filepos == wsi->u.http.filelen)
goto all_sent;
compatible_file_read(n, wsi->u.http.fd, context->service_buffer,
sizeof(context->service_buffer));
if (n < 0)
if (lws_plat_file_read(&context->fops, wsi->u.http.fd, &amount,
context->service_buffer,
sizeof(context->service_buffer)) < 0)
return -1; /* caller will close */
n = (int)amount;
if (n) {
lws_set_timeout(wsi, PENDING_TIMEOUT_HTTP_CONTENT,
AWAITING_TIMEOUT);
@ -543,7 +545,9 @@ LWS_VISIBLE int lws_serve_http_file_fragment(struct lws_context *context,
if (m != n)
/* adjust for what was not sent */
if (compatible_file_seek_cur(wsi->u.http.fd, m - n) < 0)
if (lws_plat_file_seek_cur(&context->fops,
wsi->u.http.fd,
m - n) < 0)
return -1;
}
all_sent:
@ -552,7 +556,7 @@ all_sent:
wsi->state = WSI_STATE_HTTP;
/* we might be in keepalive, so close it off here */
compatible_file_close(wsi->u.http.fd);
lws_plat_file_close(&context->fops, wsi->u.http.fd);
wsi->u.http.fd = LWS_INVALID_FILE;
if (wsi->protocol->callback)

View file

@ -62,16 +62,6 @@
#define SOL_TCP IPPROTO_TCP
#define compatible_close(fd) closesocket(fd)
#define compatible_file_close(fd) CloseHandle(fd)
#define compatible_file_seek_cur(fd, offset) \
SetFilePointer(fd, offset, NULL, FILE_CURRENT)
#define compatible_file_read(amount, fd, buf, len) {\
DWORD _amount; \
if (!ReadFile(fd, buf, len, &_amount, NULL)) \
amount = -1; \
else \
amount = _amount; \
}
#define lws_set_blocking_send(wsi) wsi->sock_send_blocking = TRUE
#define lws_socket_is_valid(x) (!!x)
#define LWS_SOCK_INVALID 0
@ -91,7 +81,6 @@
#define vsnprintf _vsnprintf
#endif
#define LWS_INVALID_FILE INVALID_HANDLE_VALUE
#else /* not windows --> */
#include <fcntl.h>
@ -144,15 +133,10 @@
#define LWS_EINTR EINTR
#define LWS_EISCONN EISCONN
#define LWS_EWOULDBLOCK EWOULDBLOCK
#define LWS_INVALID_FILE -1
#define LWS_POLLHUP (POLLHUP|POLLERR)
#define LWS_POLLIN (POLLIN)
#define LWS_POLLOUT (POLLOUT)
#define compatible_close(fd) close(fd)
#define compatible_file_close(fd) close(fd)
#define compatible_file_seek_cur(fd, offset) lseek(fd, offset, SEEK_CUR)
#define compatible_file_read(amount, fd, buf, len) \
amount = read(fd, buf, len);
#define lws_set_blocking_send(wsi)
#ifdef MBED_OPERATORS
@ -546,8 +530,10 @@ struct lws_context {
#ifndef LWS_NO_EXTENSIONS
struct lws_extension *extensions;
#endif
struct lws_token_limits *token_limits;
struct lws_token_limits *token_limits;
void *user_space;
struct lws_plat_file_ops fops;
};
enum {
@ -644,11 +630,7 @@ struct allocated_headers {
struct _lws_http_mode_related {
/* MUST be first in struct */
struct allocated_headers *ah; /* mirroring _lws_header_related */
#if defined(WIN32) || defined(_WIN32)
HANDLE fd;
#else
int fd;
#endif
lws_filefd_type fd;
unsigned long filepos;
unsigned long filelen;
@ -1142,12 +1124,6 @@ interface_to_sa(struct lws_context *context, const char *ifname,
#endif
LWS_EXTERN void lwsl_emit_stderr(int level, const char *line);
#ifdef _WIN32
LWS_EXTERN HANDLE lws_plat_open_file(const char* filename, unsigned long* filelen);
#else
LWS_EXTERN int lws_plat_open_file(const char* filename, unsigned long* filelen);
#endif
enum lws_ssl_capable_status {
LWS_SSL_CAPABLE_ERROR = -1,
LWS_SSL_CAPABLE_MORE_SERVICE = -2,

View file

@ -914,7 +914,8 @@ LWS_VISIBLE int lws_serve_http_file(struct lws_context *context,
LWS_SEND_BUFFER_PRE_PADDING;
int ret = 0;
wsi->u.http.fd = lws_plat_open_file(file, &wsi->u.http.filelen);
wsi->u.http.fd = lws_plat_file_open(&context->fops, file,
&wsi->u.http.filelen, O_RDONLY);
if (wsi->u.http.fd == LWS_INVALID_FILE) {
lwsl_err("Unable to open '%s'\n", file);
@ -948,8 +949,7 @@ LWS_VISIBLE int lws_serve_http_file(struct lws_context *context,
if (lws_finalize_http_header(context, wsi, &p, end))
return -1;
ret = lws_write(wsi, response,
p - response, LWS_WRITE_HTTP_HEADERS);
ret = lws_write(wsi, response, p - response, LWS_WRITE_HTTP_HEADERS);
if (ret != (p - response)) {
lwsl_err("_write returned %d from %d\n", ret, (p - response));
return -1;

View file

@ -117,7 +117,7 @@ int callback_http(struct lws_context *context, struct lws *wsi,
struct per_session_data__http *pss =
(struct per_session_data__http *)user;
static unsigned char buffer[4096];
struct stat stat_buf;
unsigned long amount, file_len;
char leaf_path[1024];
const char *mimetype;
char *other_headers;
@ -165,16 +165,12 @@ int callback_http(struct lws_context *context, struct lws *wsi,
p = buffer + LWS_SEND_BUFFER_PRE_PADDING;
end = p + sizeof(buffer) - LWS_SEND_BUFFER_PRE_PADDING;
#ifdef _WIN32
pss->fd = open(leaf_path, O_RDONLY | _O_BINARY);
#else
pss->fd = open(leaf_path, O_RDONLY);
#endif
if (pss->fd < 0)
return -1;
pss->fd = lws_plat_file_open(lws_get_fops(context),
leaf_path, &file_len,
O_RDONLY);
if (fstat(pss->fd, &stat_buf) < 0)
if (pss->fd == LWS_INVALID_FILE)
return -1;
/*
@ -200,7 +196,8 @@ int callback_http(struct lws_context *context, struct lws *wsi,
10, &p, end))
return 1;
if (lws_add_http_header_content_length(context, wsi,
stat_buf.st_size, &p, end))
file_len, &p,
end))
return 1;
if (lws_finalize_http_header(context, wsi, &p, end))
return 1;
@ -216,13 +213,13 @@ int callback_http(struct lws_context *context, struct lws *wsi,
* this is mandated by changes in HTTP2
*/
n = lws_write(wsi,
buffer + LWS_SEND_BUFFER_PRE_PADDING,
p - (buffer + LWS_SEND_BUFFER_PRE_PADDING),
LWS_WRITE_HTTP_HEADERS);
n = lws_write(wsi, buffer + LWS_SEND_BUFFER_PRE_PADDING,
p - (buffer + LWS_SEND_BUFFER_PRE_PADDING),
LWS_WRITE_HTTP_HEADERS);
if (n < 0) {
close(pss->fd);
lws_plat_file_close(lws_get_fops(context),
pss->fd);
return -1;
}
/*
@ -328,11 +325,13 @@ int callback_http(struct lws_context *context, struct lws *wsi,
/* he couldn't handle that much */
n = m;
n = read(pss->fd, buffer + LWS_SEND_BUFFER_PRE_PADDING,
n);
n = lws_plat_file_read(lws_get_fops(context), pss->fd,
&amount, buffer +
LWS_SEND_BUFFER_PRE_PADDING, n);
/* problem reading, close conn */
if (n < 0)
goto bail;
n = (int)amount;
/* sent it all, close conn */
if (n == 0)
goto flush_bail;
@ -354,7 +353,8 @@ int callback_http(struct lws_context *context, struct lws *wsi,
*/
if (m != n)
/* partial write, adjust */
if (lseek(pss->fd, m - n, SEEK_CUR) < 0)
if (lws_plat_file_seek_cur(lws_get_fops(context),
pss->fd, m - n) < 0)
goto bail;
if (m) /* while still active, extend timeout */
@ -377,11 +377,11 @@ flush_bail:
lws_callback_on_writable(context, wsi);
break;
}
close(pss->fd);
lws_plat_file_close(lws_get_fops(context), pss->fd);
goto try_to_reuse;
bail:
close(pss->fd);
lws_plat_file_close(lws_get_fops(context), pss->fd);
return -1;
/*

View file

@ -31,6 +31,7 @@ int count_pollfds;
#endif
volatile int force_exit = 0;
struct lws_context *context;
struct lws_plat_file_ops fops_plat;
/* http server gets files from this path */
#define LOCAL_RESOURCE_PATH INSTALL_DATADIR"/libwebsockets-test-server"
@ -97,6 +98,25 @@ static struct lws_protocols protocols[] = {
{ NULL, NULL, 0, 0 } /* terminator */
};
/* this shows how to override the lws file operations. You don't need
* to do any of this unless you have a reason (eg, want to serve
* compressed files without decompressing the whole archive)
*/
static lws_filefd_type
test_server_fops_open(const char *filename, unsigned long *filelen, int flags)
{
int n;
/* call through to original platform implementation */
n = fops_plat.open(filename, filelen, flags);
lwsl_notice("%s: opening %s, ret %d, len %lu\n", __func__, filename,
n, *filelen);
return n;
}
void sighandler(int sig)
{
force_exit = 1;
@ -271,6 +291,15 @@ int main(int argc, char **argv)
return -1;
}
/* this shows how to override the lws file operations. You don't need
* to do any of this unless you have a reason (eg, want to serve
* compressed files without decompressing the whole archive)
*/
/* stash original platform fops */
fops_plat = *(lws_get_fops(context));
/* override the active fops */
lws_get_fops(context)->open = test_server_fops_open;
n = 0;
while (n >= 0 && !force_exit) {
struct timeval tv;

View file

@ -43,7 +43,7 @@ extern void test_server_unlock(int care);
#endif
struct per_session_data__http {
int fd;
lws_filefd_type fd;
};
/*
@ -63,18 +63,18 @@ struct per_session_data__lws_mirror {
int ringbuffer_tail;
};
extern int callback_http(struct lws_context *context,
struct lws *wsi,
enum lws_callback_reasons reason,
void *user, void *in, size_t len);
extern int callback_lws_mirror(struct lws_context *context,
struct lws *wsi,
enum lws_callback_reasons reason,
void *user, void *in, size_t len);
extern int callback_dumb_increment(struct lws_context *context,
struct lws *wsi,
enum lws_callback_reasons reason,
void *user, void *in, size_t len);
extern int
callback_http(struct lws_context *context, struct lws *wsi,
enum lws_callback_reasons reason, void *user, void *in,
size_t len);
extern int
callback_lws_mirror(struct lws_context *context, struct lws *wsi,
enum lws_callback_reasons reason, void *user, void *in,
size_t len);
extern int
callback_dumb_increment(struct lws_context *context, struct lws *wsi,
enum lws_callback_reasons reason, void *user, void *in,
size_t len);
extern void
dump_handshake_info(struct lws *wsi);