2015-11-19 13:55:47 +08:00
|
|
|
/*
|
|
|
|
* libwebsockets-test-server - libwebsockets test implementation
|
|
|
|
*
|
2016-02-08 08:44:21 +08:00
|
|
|
* Copyright (C) 2010-2016 Andy Green <andy@warmcat.com>
|
2015-11-19 13:55:47 +08:00
|
|
|
*
|
2016-02-08 08:44:21 +08:00
|
|
|
* This file is made available under the Creative Commons CC0 1.0
|
|
|
|
* Universal Public Domain Dedication.
|
2015-11-19 13:55:47 +08:00
|
|
|
*
|
2016-02-08 08:44:21 +08:00
|
|
|
* The person who associated a work with this deed has dedicated
|
|
|
|
* the work to the public domain by waiving all of his or her rights
|
|
|
|
* to the work worldwide under copyright law, including all related
|
|
|
|
* and neighboring rights, to the extent allowed by law. You can copy,
|
|
|
|
* modify, distribute and perform the work, even for commercial purposes,
|
|
|
|
* all without asking permission.
|
2015-11-19 13:55:47 +08:00
|
|
|
*
|
2016-02-08 08:44:21 +08:00
|
|
|
* The test apps are intended to be adapted for use in your code, which
|
|
|
|
* may be proprietary. So unlike the library itself, they are licensed
|
|
|
|
* Public Domain.
|
2015-11-19 13:55:47 +08:00
|
|
|
*/
|
|
|
|
#include "test-server.h"
|
|
|
|
|
|
|
|
/*
|
|
|
|
* This demo server shows how to use libwebsockets for one or more
|
|
|
|
* websocket protocols in the same server
|
|
|
|
*
|
|
|
|
* It defines the following websocket protocols:
|
|
|
|
*
|
|
|
|
* dumb-increment-protocol: once the socket is opened, an incrementing
|
|
|
|
* ascii string is sent down it every 50ms.
|
|
|
|
* If you send "reset\n" on the websocket, then
|
|
|
|
* the incrementing number is reset to 0.
|
|
|
|
*
|
|
|
|
* lws-mirror-protocol: copies any received packet to every connection also
|
|
|
|
* using this protocol, including the sender
|
|
|
|
*/
|
|
|
|
|
2016-04-13 22:17:05 +02:00
|
|
|
#if defined(LWS_OPENSSL_SUPPORT) && defined(LWS_HAVE_SSL_CTX_set1_param)
|
|
|
|
/* location of the certificate revocation list */
|
2016-04-17 11:28:43 +08:00
|
|
|
extern char crl_path[1024];
|
|
|
|
#endif
|
2016-04-13 22:17:05 +02:00
|
|
|
|
2016-01-26 20:56:56 +08:00
|
|
|
extern int debug_level;
|
|
|
|
|
2015-11-19 13:55:47 +08:00
|
|
|
enum demo_protocols {
|
|
|
|
/* always first */
|
|
|
|
PROTOCOL_HTTP = 0,
|
|
|
|
|
|
|
|
PROTOCOL_DUMB_INCREMENT,
|
|
|
|
PROTOCOL_LWS_MIRROR,
|
|
|
|
|
|
|
|
/* always last */
|
|
|
|
DEMO_PROTOCOL_COUNT
|
|
|
|
};
|
|
|
|
|
|
|
|
/*
|
|
|
|
* We take a strict whitelist approach to stop ../ attacks
|
|
|
|
*/
|
|
|
|
struct serveable {
|
|
|
|
const char *urlpath;
|
|
|
|
const char *mimetype;
|
2015-12-14 08:52:03 +08:00
|
|
|
};
|
2015-11-19 13:55:47 +08:00
|
|
|
|
|
|
|
/*
|
|
|
|
* this is just an example of parsing handshake headers, you don't need this
|
|
|
|
* in your code unless you will filter allowing connections by the header
|
|
|
|
* content
|
|
|
|
*/
|
|
|
|
void
|
2015-12-04 11:08:32 +08:00
|
|
|
dump_handshake_info(struct lws *wsi)
|
2015-11-19 13:55:47 +08:00
|
|
|
{
|
2016-01-19 22:20:18 +08:00
|
|
|
int n = 0, len;
|
2015-11-19 13:55:47 +08:00
|
|
|
char buf[256];
|
|
|
|
const unsigned char *c;
|
|
|
|
|
|
|
|
do {
|
|
|
|
c = lws_token_to_string(n);
|
|
|
|
if (!c) {
|
|
|
|
n++;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2016-01-19 22:20:18 +08:00
|
|
|
len = lws_hdr_total_length(wsi, n);
|
|
|
|
if (!len || len > sizeof(buf) - 1) {
|
2015-11-19 13:55:47 +08:00
|
|
|
n++;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
lws_hdr_copy(wsi, buf, sizeof buf, n);
|
2016-01-19 22:20:18 +08:00
|
|
|
buf[sizeof(buf) - 1] = '\0';
|
2015-11-19 13:55:47 +08:00
|
|
|
|
|
|
|
fprintf(stderr, " %s = %s\n", (char *)c, buf);
|
|
|
|
n++;
|
|
|
|
} while (c);
|
|
|
|
}
|
|
|
|
|
|
|
|
const char * get_mimetype(const char *file)
|
|
|
|
{
|
|
|
|
int n = strlen(file);
|
|
|
|
|
|
|
|
if (n < 5)
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
if (!strcmp(&file[n - 4], ".ico"))
|
|
|
|
return "image/x-icon";
|
|
|
|
|
|
|
|
if (!strcmp(&file[n - 4], ".png"))
|
|
|
|
return "image/png";
|
|
|
|
|
|
|
|
if (!strcmp(&file[n - 5], ".html"))
|
|
|
|
return "text/html";
|
|
|
|
|
2016-03-20 11:55:25 +08:00
|
|
|
if (!strcmp(&file[n - 4], ".css"))
|
|
|
|
return "text/css";
|
|
|
|
|
2016-07-13 08:45:22 +08:00
|
|
|
if (!strcmp(&file[n - 3], ".js"))
|
|
|
|
return "text/javascript";
|
|
|
|
|
2015-11-19 13:55:47 +08:00
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2016-06-08 10:07:02 +08:00
|
|
|
|
|
|
|
static const char * const param_names[] = {
|
|
|
|
"text",
|
|
|
|
"send",
|
|
|
|
"file",
|
|
|
|
"upload",
|
|
|
|
};
|
|
|
|
|
|
|
|
enum enum_param_names {
|
|
|
|
EPN_TEXT,
|
|
|
|
EPN_SEND,
|
|
|
|
EPN_FILE,
|
|
|
|
EPN_UPLOAD,
|
|
|
|
};
|
|
|
|
|
|
|
|
static int
|
|
|
|
file_upload_cb(void *data, const char *name, const char *filename,
|
|
|
|
char *buf, int len, enum lws_spa_fileupload_states state)
|
|
|
|
{
|
|
|
|
struct per_session_data__http *pss =
|
|
|
|
(struct per_session_data__http *)data;
|
|
|
|
int n;
|
|
|
|
|
2017-06-13 16:55:07 +03:00
|
|
|
(void)n;
|
|
|
|
|
2016-06-08 10:07:02 +08:00
|
|
|
switch (state) {
|
|
|
|
case LWS_UFS_OPEN:
|
|
|
|
strncpy(pss->filename, filename, sizeof(pss->filename) - 1);
|
|
|
|
/* we get the original filename in @filename arg, but for
|
|
|
|
* simple demo use a fixed name so we don't have to deal with
|
|
|
|
* attacks */
|
2017-04-28 11:54:27 +08:00
|
|
|
pss->post_fd = (lws_filefd_type)open("/tmp/post-file",
|
2016-06-08 10:07:02 +08:00
|
|
|
O_CREAT | O_TRUNC | O_RDWR, 0600);
|
|
|
|
break;
|
|
|
|
case LWS_UFS_FINAL_CONTENT:
|
|
|
|
case LWS_UFS_CONTENT:
|
|
|
|
if (len) {
|
|
|
|
pss->file_length += len;
|
|
|
|
|
|
|
|
/* if the file length is too big, drop it */
|
|
|
|
if (pss->file_length > 100000)
|
|
|
|
return 1;
|
|
|
|
|
2017-04-28 11:54:27 +08:00
|
|
|
n = write((int)pss->post_fd, buf, len);
|
2016-06-08 10:07:02 +08:00
|
|
|
lwsl_notice("%s: write %d says %d\n", __func__, len, n);
|
|
|
|
}
|
|
|
|
if (state == LWS_UFS_CONTENT)
|
|
|
|
break;
|
2017-04-28 11:54:27 +08:00
|
|
|
close((int)pss->post_fd);
|
2016-06-08 10:07:02 +08:00
|
|
|
pss->post_fd = LWS_INVALID_FILE;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2015-11-19 13:55:47 +08:00
|
|
|
/* this protocol server (always the first one) handles HTTP,
|
2015-12-14 08:52:03 +08:00
|
|
|
*
|
2015-11-19 13:55:47 +08:00
|
|
|
* Some misc callbacks that aren't associated with a protocol also turn up only
|
|
|
|
* here on the first protocol server.
|
|
|
|
*/
|
|
|
|
|
2015-12-17 07:54:44 +08:00
|
|
|
int callback_http(struct lws *wsi, enum lws_callback_reasons reason, void *user,
|
2015-12-04 11:08:32 +08:00
|
|
|
void *in, size_t len)
|
2015-11-19 13:55:47 +08:00
|
|
|
{
|
|
|
|
struct per_session_data__http *pss =
|
2016-03-20 11:55:25 +08:00
|
|
|
(struct per_session_data__http *)user;
|
2016-01-26 20:56:56 +08:00
|
|
|
unsigned char buffer[4096 + LWS_PRE];
|
2017-03-09 18:52:10 +08:00
|
|
|
lws_filepos_t amount, file_len, sent;
|
2015-11-19 13:55:47 +08:00
|
|
|
char leaf_path[1024];
|
|
|
|
const char *mimetype;
|
|
|
|
char *other_headers;
|
2016-04-25 10:04:49 +08:00
|
|
|
unsigned char *end, *start;
|
2015-11-19 13:55:47 +08:00
|
|
|
struct timeval tv;
|
|
|
|
unsigned char *p;
|
2016-03-20 11:55:25 +08:00
|
|
|
#ifndef LWS_NO_CLIENT
|
|
|
|
struct per_session_data__http *pss1;
|
2016-03-20 11:59:53 +08:00
|
|
|
struct lws *wsi1;
|
2016-03-20 11:55:25 +08:00
|
|
|
#endif
|
2015-11-19 13:55:47 +08:00
|
|
|
char buf[256];
|
|
|
|
char b64[64];
|
|
|
|
int n, m;
|
|
|
|
#ifdef EXTERNAL_POLL
|
2015-12-04 11:08:32 +08:00
|
|
|
struct lws_pollargs *pa = (struct lws_pollargs *)in;
|
2015-11-19 13:55:47 +08:00
|
|
|
#endif
|
|
|
|
|
2016-04-07 10:08:35 +08:00
|
|
|
|
2015-11-19 13:55:47 +08:00
|
|
|
switch (reason) {
|
|
|
|
case LWS_CALLBACK_HTTP:
|
|
|
|
|
2017-02-05 22:07:34 +08:00
|
|
|
lwsl_info("lws_http_serve: %s\n", (const char *)in);
|
2016-04-07 10:08:35 +08:00
|
|
|
|
2016-01-26 20:56:56 +08:00
|
|
|
if (debug_level & LLL_INFO) {
|
|
|
|
dump_handshake_info(wsi);
|
2015-11-19 13:55:47 +08:00
|
|
|
|
2016-01-26 20:56:56 +08:00
|
|
|
/* dump the individual URI Arg parameters */
|
|
|
|
n = 0;
|
|
|
|
while (lws_hdr_copy_fragment(wsi, buf, sizeof(buf),
|
|
|
|
WSI_TOKEN_HTTP_URI_ARGS, n) > 0) {
|
ah http1.1 deal with pipelined headers properly
Connections must hold an ah for the whole time they are
processing one header set, even if eg, the headers are
fragmented and it involves network roundtrip times.
However on http1.1 / keepalive, it must drop the ah when
there are no more header sets to deal with, and reacquire
the ah later when more data appears. It's because the
time between header sets / http1.1 requests is unbounded
and the ah would be tied up forever.
But in the case that we got pipelined http1.1 requests,
even partial already buffered, we must keep the ah,
resetting it instead of dropping it. Because we store
the rx data conveniently in a per-tsi buffer since it only
does one thing at a time per thread, we cannot go back to
the event loop to await a new ah inside one service action.
But no problem since we definitely already have an ah,
let's just reuse it at http completion time if more rx is
already buffered.
NB: attack.sh makes request with echo | nc, this
accidentally sends a trailing '\n' from the echo showing
this problem. With this patch attack.sh can complete well.
Signed-off-by: Andy Green <andy.green@linaro.org>
2016-01-30 11:43:10 +08:00
|
|
|
lwsl_notice("URI Arg %d: %s\n", ++n, buf);
|
2016-01-26 20:56:56 +08:00
|
|
|
}
|
2015-12-15 22:57:19 +08:00
|
|
|
}
|
2016-02-25 15:06:37 +08:00
|
|
|
|
|
|
|
{
|
2016-06-30 10:11:59 +08:00
|
|
|
lws_get_peer_simple(wsi, buf, sizeof(buf));
|
|
|
|
lwsl_info("HTTP connect from %s\n", buf);
|
2016-02-25 15:06:37 +08:00
|
|
|
}
|
|
|
|
|
2015-11-19 13:55:47 +08:00
|
|
|
if (len < 1) {
|
2015-12-16 18:19:08 +08:00
|
|
|
lws_return_http_status(wsi,
|
2015-11-19 13:55:47 +08:00
|
|
|
HTTP_STATUS_BAD_REQUEST, NULL);
|
|
|
|
goto try_to_reuse;
|
|
|
|
}
|
|
|
|
|
2017-06-12 13:36:24 +08:00
|
|
|
#if !defined(LWS_NO_CLIENT) && defined(LWS_OPENSSL_SUPPORT)
|
2016-03-20 11:59:53 +08:00
|
|
|
if (!strncmp(in, "/proxytest", 10)) {
|
2016-03-01 07:19:01 +08:00
|
|
|
struct lws_client_connect_info i;
|
2017-06-12 13:36:24 +08:00
|
|
|
char *rootpath = "/git/";
|
2016-03-20 11:59:53 +08:00
|
|
|
const char *p = (const char *)in;
|
2016-03-01 07:19:01 +08:00
|
|
|
|
|
|
|
if (lws_get_child(wsi))
|
|
|
|
break;
|
|
|
|
|
|
|
|
pss->client_finished = 0;
|
2017-06-12 13:36:24 +08:00
|
|
|
memset(&i, 0, sizeof(i));
|
2016-03-01 07:19:01 +08:00
|
|
|
i.context = lws_get_context(wsi);
|
2017-06-12 13:36:24 +08:00
|
|
|
i.address = "libwebsockets.org";
|
|
|
|
i.port = 443;
|
|
|
|
i.ssl_connection = 1;
|
2016-03-20 11:59:53 +08:00
|
|
|
if (p[10])
|
2016-03-20 11:55:25 +08:00
|
|
|
i.path = (char *)in + 10;
|
2016-03-20 11:59:53 +08:00
|
|
|
else
|
|
|
|
i.path = rootpath;
|
2017-06-12 13:36:24 +08:00
|
|
|
i.host = i.address;
|
2016-03-01 07:19:01 +08:00
|
|
|
i.origin = NULL;
|
|
|
|
i.method = "GET";
|
|
|
|
i.parent_wsi = wsi;
|
2017-06-12 13:36:24 +08:00
|
|
|
i.uri_replace_from = "libwebsockets.org/git/";
|
2016-03-20 11:59:53 +08:00
|
|
|
i.uri_replace_to = "/proxytest/";
|
2017-06-12 13:36:24 +08:00
|
|
|
|
2016-03-01 07:19:01 +08:00
|
|
|
if (!lws_client_connect_via_info(&i)) {
|
|
|
|
lwsl_err("proxy connect fail\n");
|
|
|
|
break;
|
|
|
|
}
|
2016-03-20 11:59:53 +08:00
|
|
|
|
2016-03-01 07:19:01 +08:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2016-03-20 11:55:25 +08:00
|
|
|
#if 1
|
2016-03-20 11:59:53 +08:00
|
|
|
/* this example server has no concept of directories */
|
|
|
|
if (strchr((const char *)in + 1, '/')) {
|
2016-04-07 10:08:35 +08:00
|
|
|
lws_return_http_status(wsi, HTTP_STATUS_NOT_ACCEPTABLE, NULL);
|
2016-03-20 11:59:53 +08:00
|
|
|
goto try_to_reuse;
|
|
|
|
}
|
2016-03-20 11:55:25 +08:00
|
|
|
#endif
|
2016-03-20 11:59:53 +08:00
|
|
|
|
2015-11-19 13:55:47 +08:00
|
|
|
/* if a legal POST URL, let it continue and accept data */
|
|
|
|
if (lws_hdr_total_length(wsi, WSI_TOKEN_POST_URI))
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
/* check for the "send a big file by hand" example case */
|
|
|
|
|
|
|
|
if (!strcmp((const char *)in, "/leaf.jpg")) {
|
2017-02-25 12:42:45 +08:00
|
|
|
lws_fop_flags_t flags = LWS_O_RDONLY;
|
|
|
|
|
2015-11-19 13:55:47 +08:00
|
|
|
if (strlen(resource_path) > sizeof(leaf_path) - 10)
|
|
|
|
return -1;
|
|
|
|
sprintf(leaf_path, "%s/leaf.jpg", resource_path);
|
|
|
|
|
|
|
|
/* well, let's demonstrate how to send the hard way */
|
|
|
|
|
2016-01-11 11:34:01 +08:00
|
|
|
p = buffer + LWS_PRE;
|
|
|
|
end = p + sizeof(buffer) - LWS_PRE;
|
2015-11-19 13:55:47 +08:00
|
|
|
|
2017-03-03 12:38:10 +08:00
|
|
|
pss->fop_fd = lws_vfs_file_open(
|
|
|
|
lws_get_fops(lws_get_context(wsi)),
|
|
|
|
leaf_path, &flags);
|
2017-02-25 12:42:45 +08:00
|
|
|
if (!pss->fop_fd) {
|
2016-10-02 02:21:03 +03:00
|
|
|
lwsl_err("failed to open file %s\n", leaf_path);
|
2015-11-19 13:55:47 +08:00
|
|
|
return -1;
|
2016-01-26 20:56:56 +08:00
|
|
|
}
|
2017-03-03 12:38:10 +08:00
|
|
|
file_len = lws_vfs_get_length(pss->fop_fd);
|
2015-11-19 13:55:47 +08:00
|
|
|
|
|
|
|
/*
|
|
|
|
* we will send a big jpeg file, but it could be
|
|
|
|
* anything. Set the Content-Type: appropriately
|
|
|
|
* so the browser knows what to do with it.
|
2015-12-14 08:52:03 +08:00
|
|
|
*
|
2015-11-19 13:55:47 +08:00
|
|
|
* Notice we use the APIs to build the header, which
|
|
|
|
* will do the right thing for HTTP 1/1.1 and HTTP2
|
|
|
|
* depending on what connection it happens to be working
|
|
|
|
* on
|
|
|
|
*/
|
2017-03-08 07:51:47 +08:00
|
|
|
if (lws_add_http_header_status(wsi, HTTP_STATUS_OK, &p, end))
|
2015-11-19 13:55:47 +08:00
|
|
|
return 1;
|
2015-12-16 18:19:08 +08:00
|
|
|
if (lws_add_http_header_by_token(wsi, WSI_TOKEN_HTTP_SERVER,
|
2015-11-19 13:55:47 +08:00
|
|
|
(unsigned char *)"libwebsockets",
|
|
|
|
13, &p, end))
|
|
|
|
return 1;
|
2015-12-16 18:19:08 +08:00
|
|
|
if (lws_add_http_header_by_token(wsi,
|
2015-11-19 13:55:47 +08:00
|
|
|
WSI_TOKEN_HTTP_CONTENT_TYPE,
|
|
|
|
(unsigned char *)"image/jpeg",
|
|
|
|
10, &p, end))
|
|
|
|
return 1;
|
2015-12-16 18:19:08 +08:00
|
|
|
if (lws_add_http_header_content_length(wsi,
|
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>
2015-12-10 07:58:58 +08:00
|
|
|
file_len, &p,
|
|
|
|
end))
|
2015-11-19 13:55:47 +08:00
|
|
|
return 1;
|
2015-12-16 18:19:08 +08:00
|
|
|
if (lws_finalize_http_header(wsi, &p, end))
|
2015-11-19 13:55:47 +08:00
|
|
|
return 1;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* send the http headers...
|
|
|
|
* this won't block since it's the first payload sent
|
|
|
|
* on the connection since it was established
|
|
|
|
* (too small for partial)
|
2015-12-14 08:52:03 +08:00
|
|
|
*
|
2015-11-19 13:55:47 +08:00
|
|
|
* Notice they are sent using LWS_WRITE_HTTP_HEADERS
|
|
|
|
* which also means you can't send body too in one step,
|
|
|
|
* this is mandated by changes in HTTP2
|
|
|
|
*/
|
|
|
|
|
2016-01-26 20:56:56 +08:00
|
|
|
*p = '\0';
|
|
|
|
lwsl_info("%s\n", buffer + LWS_PRE);
|
|
|
|
|
2016-02-21 21:25:48 +08:00
|
|
|
n = lws_write(wsi, buffer + LWS_PRE,
|
|
|
|
p - (buffer + LWS_PRE),
|
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>
2015-12-10 07:58:58 +08:00
|
|
|
LWS_WRITE_HTTP_HEADERS);
|
2015-11-19 13:55:47 +08:00
|
|
|
if (n < 0) {
|
2017-03-03 12:38:10 +08:00
|
|
|
lws_vfs_file_close(&pss->fop_fd);
|
2015-11-19 13:55:47 +08:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
/*
|
|
|
|
* book us a LWS_CALLBACK_HTTP_WRITEABLE callback
|
|
|
|
*/
|
2015-12-16 18:19:08 +08:00
|
|
|
lws_callback_on_writable(wsi);
|
2015-11-19 13:55:47 +08:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* if not, send a file the easy way */
|
2016-03-20 11:55:25 +08:00
|
|
|
if (!strncmp(in, "/cgit-data/", 11)) {
|
|
|
|
in = (char *)in + 11;
|
|
|
|
strcpy(buf, "/usr/share/cgit");
|
|
|
|
} else
|
|
|
|
strcpy(buf, resource_path);
|
|
|
|
|
2015-11-19 13:55:47 +08:00
|
|
|
if (strcmp(in, "/")) {
|
|
|
|
if (*((const char *)in) != '/')
|
|
|
|
strcat(buf, "/");
|
2016-03-20 11:55:25 +08:00
|
|
|
strncat(buf, in, sizeof(buf) - strlen(buf) - 1);
|
2015-11-19 13:55:47 +08:00
|
|
|
} else /* default file to serve */
|
|
|
|
strcat(buf, "/test.html");
|
|
|
|
buf[sizeof(buf) - 1] = '\0';
|
|
|
|
|
|
|
|
/* refuse to serve files we don't understand */
|
|
|
|
mimetype = get_mimetype(buf);
|
|
|
|
if (!mimetype) {
|
|
|
|
lwsl_err("Unknown mimetype for %s\n", buf);
|
2015-12-16 18:19:08 +08:00
|
|
|
lws_return_http_status(wsi,
|
2017-06-29 11:26:22 +08:00
|
|
|
HTTP_STATUS_UNSUPPORTED_MEDIA_TYPE, "Unknown Mimetype");
|
2015-11-19 13:55:47 +08:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2015-12-16 18:19:08 +08:00
|
|
|
/* demonstrates how to set a cookie on / */
|
2015-11-19 13:55:47 +08:00
|
|
|
|
2016-02-18 20:36:40 +08:00
|
|
|
other_headers = leaf_path;
|
|
|
|
p = (unsigned char *)leaf_path;
|
2015-11-19 13:55:47 +08:00
|
|
|
if (!strcmp((const char *)in, "/") &&
|
|
|
|
!lws_hdr_total_length(wsi, WSI_TOKEN_HTTP_COOKIE)) {
|
|
|
|
/* this isn't very unguessable but it'll do for us */
|
|
|
|
gettimeofday(&tv, NULL);
|
|
|
|
n = sprintf(b64, "test=LWS_%u_%u_COOKIE;Max-Age=360000",
|
|
|
|
(unsigned int)tv.tv_sec,
|
|
|
|
(unsigned int)tv.tv_usec);
|
|
|
|
|
2015-12-16 18:19:08 +08:00
|
|
|
if (lws_add_http_header_by_name(wsi,
|
2015-12-14 08:52:03 +08:00
|
|
|
(unsigned char *)"set-cookie:",
|
2015-11-19 13:55:47 +08:00
|
|
|
(unsigned char *)b64, n, &p,
|
|
|
|
(unsigned char *)leaf_path + sizeof(leaf_path)))
|
|
|
|
return 1;
|
|
|
|
}
|
2016-02-18 20:36:40 +08:00
|
|
|
if (lws_is_ssl(wsi) && lws_add_http_header_by_name(wsi,
|
|
|
|
(unsigned char *)
|
|
|
|
"Strict-Transport-Security:",
|
|
|
|
(unsigned char *)
|
|
|
|
"max-age=15768000 ; "
|
|
|
|
"includeSubDomains", 36, &p,
|
|
|
|
(unsigned char *)leaf_path +
|
|
|
|
sizeof(leaf_path)))
|
|
|
|
return 1;
|
|
|
|
n = (char *)p - leaf_path;
|
2015-11-19 13:55:47 +08:00
|
|
|
|
2015-12-16 18:19:08 +08:00
|
|
|
n = lws_serve_http_file(wsi, buf, mimetype, other_headers, n);
|
2017-06-28 09:57:15 +08:00
|
|
|
if (n < 0)
|
|
|
|
return -1; /* error*/
|
2015-11-19 13:55:47 +08:00
|
|
|
|
|
|
|
/*
|
|
|
|
* notice that the sending of the file completes asynchronously,
|
|
|
|
* we'll get a LWS_CALLBACK_HTTP_FILE_COMPLETION callback when
|
2017-06-28 09:57:15 +08:00
|
|
|
* it's done. That's the case even if we just completed the
|
|
|
|
* send, so wait for that.
|
2015-11-19 13:55:47 +08:00
|
|
|
*/
|
|
|
|
break;
|
|
|
|
|
2017-06-12 13:36:24 +08:00
|
|
|
case LWS_CALLBACK_CLIENT_RECEIVE:
|
|
|
|
((char *)in)[len] = '\0';
|
|
|
|
lwsl_info("rx %d '%s'\n", (int)len, (char *)in);
|
|
|
|
break;
|
|
|
|
|
2015-11-19 13:55:47 +08:00
|
|
|
case LWS_CALLBACK_HTTP_BODY:
|
2016-06-08 10:07:02 +08:00
|
|
|
/* create the POST argument parser if not already existing */
|
|
|
|
if (!pss->spa) {
|
|
|
|
pss->spa = lws_spa_create(wsi, param_names,
|
|
|
|
ARRAY_SIZE(param_names), 1024,
|
|
|
|
file_upload_cb, pss);
|
|
|
|
if (!pss->spa)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
pss->filename[0] = '\0';
|
|
|
|
pss->file_length = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* let it parse the POST data */
|
|
|
|
if (lws_spa_process(pss->spa, in, len))
|
|
|
|
return -1;
|
2015-11-19 13:55:47 +08:00
|
|
|
break;
|
|
|
|
|
|
|
|
case LWS_CALLBACK_HTTP_BODY_COMPLETION:
|
2016-06-08 10:07:02 +08:00
|
|
|
lwsl_debug("LWS_CALLBACK_HTTP_BODY_COMPLETION\n");
|
2016-04-25 10:04:49 +08:00
|
|
|
/*
|
|
|
|
* the whole of the sent body arrived,
|
|
|
|
* respond to the client with a redirect to show the
|
|
|
|
* results
|
|
|
|
*/
|
2016-06-08 10:07:02 +08:00
|
|
|
|
|
|
|
/* call to inform no more payload data coming */
|
|
|
|
lws_spa_finalize(pss->spa);
|
|
|
|
|
|
|
|
p = (unsigned char *)pss->result + LWS_PRE;
|
|
|
|
end = p + sizeof(pss->result) - LWS_PRE - 1;
|
|
|
|
p += sprintf((char *)p,
|
|
|
|
"<html><body><h1>Form results (after urldecoding)</h1>"
|
|
|
|
"<table><tr><td>Name</td><td>Length</td><td>Value</td></tr>");
|
|
|
|
|
|
|
|
for (n = 0; n < ARRAY_SIZE(param_names); n++)
|
2016-09-15 02:22:57 +08:00
|
|
|
p += lws_snprintf((char *)p, end - p,
|
2016-06-08 10:07:02 +08:00
|
|
|
"<tr><td><b>%s</b></td><td>%d</td><td>%s</td></tr>",
|
|
|
|
param_names[n],
|
|
|
|
lws_spa_get_length(pss->spa, n),
|
|
|
|
lws_spa_get_string(pss->spa, n));
|
|
|
|
|
2016-09-15 02:22:57 +08:00
|
|
|
p += lws_snprintf((char *)p, end - p, "</table><br><b>filename:</b> %s, <b>length</b> %ld",
|
2016-06-08 10:07:02 +08:00
|
|
|
pss->filename, pss->file_length);
|
|
|
|
|
2016-09-15 02:22:57 +08:00
|
|
|
p += lws_snprintf((char *)p, end - p, "</body></html>");
|
2016-06-08 10:07:02 +08:00
|
|
|
pss->result_len = p - (unsigned char *)(pss->result + LWS_PRE);
|
|
|
|
|
|
|
|
p = buffer + LWS_PRE;
|
|
|
|
start = p;
|
|
|
|
end = p + sizeof(buffer) - LWS_PRE;
|
|
|
|
|
2017-03-08 07:51:47 +08:00
|
|
|
if (lws_add_http_header_status(wsi, HTTP_STATUS_OK, &p, end))
|
2016-06-08 10:07:02 +08:00
|
|
|
return 1;
|
|
|
|
|
|
|
|
if (lws_add_http_header_by_token(wsi, WSI_TOKEN_HTTP_CONTENT_TYPE,
|
|
|
|
(unsigned char *)"text/html", 9, &p, end))
|
|
|
|
return 1;
|
|
|
|
if (lws_add_http_header_content_length(wsi, pss->result_len, &p, end))
|
|
|
|
return 1;
|
|
|
|
if (lws_finalize_http_header(wsi, &p, end))
|
|
|
|
return 1;
|
|
|
|
|
|
|
|
n = lws_write(wsi, start, p - start, LWS_WRITE_HTTP_HEADERS);
|
|
|
|
if (n < 0)
|
|
|
|
return 1;
|
|
|
|
|
|
|
|
n = lws_write(wsi, (unsigned char *)pss->result + LWS_PRE,
|
|
|
|
pss->result_len, LWS_WRITE_HTTP);
|
|
|
|
if (n < 0)
|
|
|
|
return 1;
|
2015-11-19 13:55:47 +08:00
|
|
|
goto try_to_reuse;
|
2016-06-18 09:00:04 +08:00
|
|
|
case LWS_CALLBACK_HTTP_DROP_PROTOCOL:
|
2016-06-30 10:11:59 +08:00
|
|
|
lwsl_debug("LWS_CALLBACK_HTTP_DROP_PROTOCOL\n");
|
2015-11-19 13:55:47 +08:00
|
|
|
|
2016-06-18 09:00:04 +08:00
|
|
|
/* called when our wsi user_space is going to be destroyed */
|
|
|
|
if (pss->spa) {
|
|
|
|
lws_spa_destroy(pss->spa);
|
|
|
|
pss->spa = NULL;
|
|
|
|
}
|
|
|
|
break;
|
2015-11-19 13:55:47 +08:00
|
|
|
case LWS_CALLBACK_HTTP_FILE_COMPLETION:
|
|
|
|
goto try_to_reuse;
|
|
|
|
|
|
|
|
case LWS_CALLBACK_HTTP_WRITEABLE:
|
2016-01-26 20:56:56 +08:00
|
|
|
lwsl_info("LWS_CALLBACK_HTTP_WRITEABLE\n");
|
|
|
|
|
2016-03-01 07:19:01 +08:00
|
|
|
if (pss->client_finished)
|
|
|
|
return -1;
|
|
|
|
|
2017-06-12 13:36:24 +08:00
|
|
|
if (!lws_get_child(wsi) && !pss->fop_fd) {
|
|
|
|
lwsl_notice("fop_fd NULL\n");
|
2016-01-26 20:56:56 +08:00
|
|
|
goto try_to_reuse;
|
2017-06-12 13:36:24 +08:00
|
|
|
}
|
2016-03-09 07:41:59 +08:00
|
|
|
|
2016-03-20 11:59:53 +08:00
|
|
|
#ifndef LWS_NO_CLIENT
|
2017-08-26 12:15:40 +08:00
|
|
|
if (pss->reason_bf & LWS_CB_REASON_AUX_BF__PROXY) {
|
2016-03-20 11:59:53 +08:00
|
|
|
char *px = buf + LWS_PRE;
|
|
|
|
int lenx = sizeof(buf) - LWS_PRE;
|
|
|
|
/*
|
|
|
|
* our sink is writeable and our source has something
|
|
|
|
* to read. So read a lump of source material of
|
|
|
|
* suitable size to send or what's available, whichever
|
|
|
|
* is the smaller.
|
|
|
|
*/
|
2017-06-12 13:36:24 +08:00
|
|
|
|
|
|
|
|
2017-08-26 12:15:40 +08:00
|
|
|
pss->reason_bf &= ~LWS_CB_REASON_AUX_BF__PROXY;
|
2016-03-20 11:59:53 +08:00
|
|
|
wsi1 = lws_get_child(wsi);
|
|
|
|
if (!wsi1)
|
|
|
|
break;
|
|
|
|
if (lws_http_client_read(wsi1, &px, &lenx) < 0)
|
2017-06-12 13:36:24 +08:00
|
|
|
return -1;
|
2016-03-20 11:59:53 +08:00
|
|
|
|
|
|
|
if (pss->client_finished)
|
|
|
|
return -1;
|
2017-06-12 13:36:24 +08:00
|
|
|
|
2016-02-21 21:25:48 +08:00
|
|
|
break;
|
|
|
|
}
|
2017-06-12 13:36:24 +08:00
|
|
|
|
|
|
|
if (lws_get_child(wsi))
|
|
|
|
break;
|
|
|
|
|
2016-02-21 21:25:48 +08:00
|
|
|
#endif
|
2015-11-19 13:55:47 +08:00
|
|
|
/*
|
|
|
|
* we can send more of whatever it is we were sending
|
|
|
|
*/
|
2016-01-26 20:56:56 +08:00
|
|
|
sent = 0;
|
2015-11-19 13:55:47 +08:00
|
|
|
do {
|
|
|
|
/* we'd like the send this much */
|
2016-01-11 11:34:01 +08:00
|
|
|
n = sizeof(buffer) - LWS_PRE;
|
2015-12-14 08:52:03 +08:00
|
|
|
|
2015-11-19 13:55:47 +08:00
|
|
|
/* but if the peer told us he wants less, we can adapt */
|
|
|
|
m = lws_get_peer_write_allowance(wsi);
|
|
|
|
|
|
|
|
/* -1 means not using a protocol that has this info */
|
|
|
|
if (m == 0)
|
|
|
|
/* right now, peer can't handle anything */
|
|
|
|
goto later;
|
|
|
|
|
|
|
|
if (m != -1 && m < n)
|
|
|
|
/* he couldn't handle that much */
|
|
|
|
n = m;
|
2015-12-14 08:52:03 +08:00
|
|
|
|
2017-03-01 14:28:56 +08:00
|
|
|
n = lws_vfs_file_read(pss->fop_fd,
|
2016-01-26 20:56:56 +08:00
|
|
|
&amount, buffer + LWS_PRE, n);
|
2015-11-19 13:55:47 +08:00
|
|
|
/* problem reading, close conn */
|
2016-01-26 20:56:56 +08:00
|
|
|
if (n < 0) {
|
|
|
|
lwsl_err("problem reading file\n");
|
2015-11-19 13:55:47 +08:00
|
|
|
goto bail;
|
2016-01-26 20:56:56 +08: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>
2015-12-10 07:58:58 +08:00
|
|
|
n = (int)amount;
|
2015-11-19 13:55:47 +08:00
|
|
|
/* sent it all, close conn */
|
|
|
|
if (n == 0)
|
2016-01-26 20:56:56 +08:00
|
|
|
goto penultimate;
|
2015-11-19 13:55:47 +08:00
|
|
|
/*
|
|
|
|
* To support HTTP2, must take care about preamble space
|
2015-12-14 08:52:03 +08:00
|
|
|
*
|
2015-11-19 13:55:47 +08:00
|
|
|
* identification of when we send the last payload frame
|
|
|
|
* is handled by the library itself if you sent a
|
|
|
|
* content-length header
|
|
|
|
*/
|
2016-01-26 20:56:56 +08:00
|
|
|
m = lws_write(wsi, buffer + LWS_PRE, n, LWS_WRITE_HTTP);
|
|
|
|
if (m < 0) {
|
|
|
|
lwsl_err("write failed\n");
|
2015-11-19 13:55:47 +08:00
|
|
|
/* write failed, close conn */
|
|
|
|
goto bail;
|
2016-01-26 20:56:56 +08:00
|
|
|
}
|
2015-11-19 13:55:47 +08:00
|
|
|
if (m) /* while still active, extend timeout */
|
2016-01-26 20:56:56 +08:00
|
|
|
lws_set_timeout(wsi, PENDING_TIMEOUT_HTTP_CONTENT, 5);
|
|
|
|
sent += m;
|
2015-11-19 13:55:47 +08:00
|
|
|
|
2016-01-26 20:56:56 +08:00
|
|
|
} while (!lws_send_pipe_choked(wsi) && (sent < 1024 * 1024));
|
2015-11-19 13:55:47 +08:00
|
|
|
later:
|
2015-12-16 18:19:08 +08:00
|
|
|
lws_callback_on_writable(wsi);
|
2015-11-19 13:55:47 +08:00
|
|
|
break;
|
2016-01-26 20:56:56 +08:00
|
|
|
penultimate:
|
2017-03-03 12:38:10 +08:00
|
|
|
lws_vfs_file_close(&pss->fop_fd);
|
2017-02-25 12:42:45 +08:00
|
|
|
pss->fop_fd = NULL;
|
2015-11-19 13:55:47 +08:00
|
|
|
goto try_to_reuse;
|
|
|
|
|
|
|
|
bail:
|
2017-03-03 12:38:10 +08:00
|
|
|
lws_vfs_file_close(&pss->fop_fd);
|
2016-01-26 20:56:56 +08:00
|
|
|
|
2015-11-19 13:55:47 +08:00
|
|
|
return -1;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* callback for confirming to continue with client IP appear in
|
|
|
|
* protocol 0 callback since no websocket protocol has been agreed
|
|
|
|
* yet. You can just ignore this if you won't filter on client IP
|
2016-03-20 11:59:53 +08:00
|
|
|
* since the default unhandled callback return is 0 meaning let the
|
2015-11-19 13:55:47 +08:00
|
|
|
* connection continue.
|
|
|
|
*/
|
|
|
|
case LWS_CALLBACK_FILTER_NETWORK_CONNECTION:
|
|
|
|
/* if we returned non-zero from here, we kill the connection */
|
|
|
|
break;
|
|
|
|
|
2016-03-20 11:55:25 +08:00
|
|
|
#ifndef LWS_NO_CLIENT
|
2016-03-20 11:59:53 +08:00
|
|
|
case LWS_CALLBACK_ESTABLISHED_CLIENT_HTTP: {
|
|
|
|
char ctype[64], ctlen = 0;
|
|
|
|
lwsl_err("LWS_CALLBACK_ESTABLISHED_CLIENT_HTTP\n");
|
2016-03-01 07:19:01 +08:00
|
|
|
p = buffer + LWS_PRE;
|
|
|
|
end = p + sizeof(buffer) - LWS_PRE;
|
2017-03-08 07:51:47 +08:00
|
|
|
if (lws_add_http_header_status(lws_get_parent(wsi), HTTP_STATUS_OK, &p, end))
|
2016-03-01 07:19:01 +08:00
|
|
|
return 1;
|
|
|
|
if (lws_add_http_header_by_token(lws_get_parent(wsi),
|
|
|
|
WSI_TOKEN_HTTP_SERVER,
|
|
|
|
(unsigned char *)"libwebsockets",
|
|
|
|
13, &p, end))
|
|
|
|
return 1;
|
2016-03-20 11:59:53 +08:00
|
|
|
|
|
|
|
ctlen = lws_hdr_copy(wsi, ctype, sizeof(ctype), WSI_TOKEN_HTTP_CONTENT_TYPE);
|
|
|
|
if (ctlen > 0) {
|
|
|
|
if (lws_add_http_header_by_token(lws_get_parent(wsi),
|
2016-03-01 07:19:01 +08:00
|
|
|
WSI_TOKEN_HTTP_CONTENT_TYPE,
|
2016-03-20 11:59:53 +08:00
|
|
|
(unsigned char *)ctype, ctlen, &p, end))
|
|
|
|
return 1;
|
|
|
|
}
|
2016-03-01 07:19:01 +08:00
|
|
|
#if 0
|
|
|
|
if (lws_add_http_header_content_length(lws_get_parent(wsi),
|
2016-03-20 11:59:53 +08:00
|
|
|
file_len, &p, end))
|
2016-03-01 07:19:01 +08:00
|
|
|
return 1;
|
|
|
|
#endif
|
|
|
|
if (lws_finalize_http_header(lws_get_parent(wsi), &p, end))
|
|
|
|
return 1;
|
|
|
|
|
|
|
|
*p = '\0';
|
|
|
|
lwsl_info("%s\n", buffer + LWS_PRE);
|
|
|
|
|
|
|
|
n = lws_write(lws_get_parent(wsi), buffer + LWS_PRE,
|
|
|
|
p - (buffer + LWS_PRE),
|
|
|
|
LWS_WRITE_HTTP_HEADERS);
|
|
|
|
if (n < 0)
|
|
|
|
return -1;
|
|
|
|
|
2016-03-20 11:59:53 +08:00
|
|
|
break; }
|
2016-03-01 07:19:01 +08:00
|
|
|
case LWS_CALLBACK_CLOSED_CLIENT_HTTP:
|
2016-03-20 11:59:53 +08:00
|
|
|
//lwsl_err("LWS_CALLBACK_CLOSED_CLIENT_HTTP\n");
|
2016-03-01 07:19:01 +08:00
|
|
|
return -1;
|
|
|
|
break;
|
|
|
|
case LWS_CALLBACK_RECEIVE_CLIENT_HTTP:
|
2016-03-20 11:59:53 +08:00
|
|
|
//lwsl_err("LWS_CALLBACK_RECEIVE_CLIENT_HTTP: wsi %p\n", wsi);
|
|
|
|
assert(lws_get_parent(wsi));
|
|
|
|
if (!lws_get_parent(wsi))
|
|
|
|
break;
|
|
|
|
pss1 = lws_wsi_user(lws_get_parent(wsi));
|
2017-08-26 12:15:40 +08:00
|
|
|
pss1->reason_bf |= LWS_CB_REASON_AUX_BF__PROXY;
|
2016-03-20 11:59:53 +08:00
|
|
|
lws_callback_on_writable(lws_get_parent(wsi));
|
|
|
|
break;
|
|
|
|
case LWS_CALLBACK_RECEIVE_CLIENT_HTTP_READ:
|
2017-06-12 13:36:24 +08:00
|
|
|
//lwsl_err("LWS_CALLBACK_RECEIVE_CLIENT_HTTP_READ len %d\n", (int)len);
|
2016-03-20 11:59:53 +08:00
|
|
|
assert(lws_get_parent(wsi));
|
|
|
|
m = lws_write(lws_get_parent(wsi), (unsigned char *)in,
|
|
|
|
len, LWS_WRITE_HTTP);
|
2016-03-01 07:19:01 +08:00
|
|
|
if (m < 0)
|
2016-03-20 11:59:53 +08:00
|
|
|
return -1;
|
2016-03-01 07:19:01 +08:00
|
|
|
break;
|
|
|
|
case LWS_CALLBACK_COMPLETED_CLIENT_HTTP:
|
2016-03-20 11:59:53 +08:00
|
|
|
//lwsl_err("LWS_CALLBACK_COMPLETED_CLIENT_HTTP\n");
|
|
|
|
assert(lws_get_parent(wsi));
|
|
|
|
if (!lws_get_parent(wsi))
|
|
|
|
break;
|
2016-03-01 07:19:01 +08:00
|
|
|
pss1 = lws_wsi_user(lws_get_parent(wsi));
|
|
|
|
pss1->client_finished = 1;
|
|
|
|
break;
|
|
|
|
#endif
|
|
|
|
|
2015-11-19 13:55:47 +08:00
|
|
|
/*
|
|
|
|
* callbacks for managing the external poll() array appear in
|
|
|
|
* protocol 0 callback
|
|
|
|
*/
|
|
|
|
|
|
|
|
case LWS_CALLBACK_LOCK_POLL:
|
|
|
|
/*
|
|
|
|
* lock mutex to protect pollfd state
|
|
|
|
* called before any other POLL related callback
|
2015-11-20 09:33:02 +08:00
|
|
|
* if protecting wsi lifecycle change, len == 1
|
2015-11-19 13:55:47 +08:00
|
|
|
*/
|
2015-11-20 09:33:02 +08:00
|
|
|
test_server_lock(len);
|
2015-11-19 13:55:47 +08:00
|
|
|
break;
|
|
|
|
|
|
|
|
case LWS_CALLBACK_UNLOCK_POLL:
|
|
|
|
/*
|
|
|
|
* unlock mutex to protect pollfd state when
|
|
|
|
* called after any other POLL related callback
|
2015-11-20 09:33:02 +08:00
|
|
|
* if protecting wsi lifecycle change, len == 1
|
2015-11-19 13:55:47 +08:00
|
|
|
*/
|
2015-11-20 09:33:02 +08:00
|
|
|
test_server_unlock(len);
|
2015-11-19 13:55:47 +08:00
|
|
|
break;
|
|
|
|
|
2015-11-20 09:33:02 +08:00
|
|
|
#ifdef EXTERNAL_POLL
|
2015-11-19 13:55:47 +08:00
|
|
|
case LWS_CALLBACK_ADD_POLL_FD:
|
|
|
|
|
|
|
|
if (count_pollfds >= max_poll_elements) {
|
|
|
|
lwsl_err("LWS_CALLBACK_ADD_POLL_FD: too many sockets to track\n");
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
fd_lookup[pa->fd] = count_pollfds;
|
|
|
|
pollfds[count_pollfds].fd = pa->fd;
|
|
|
|
pollfds[count_pollfds].events = pa->events;
|
|
|
|
pollfds[count_pollfds++].revents = 0;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case LWS_CALLBACK_DEL_POLL_FD:
|
|
|
|
if (!--count_pollfds)
|
|
|
|
break;
|
|
|
|
m = fd_lookup[pa->fd];
|
|
|
|
/* have the last guy take up the vacant slot */
|
|
|
|
pollfds[m] = pollfds[count_pollfds];
|
|
|
|
fd_lookup[pollfds[count_pollfds].fd] = m;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case LWS_CALLBACK_CHANGE_MODE_POLL_FD:
|
|
|
|
pollfds[fd_lookup[pa->fd]].events = pa->events;
|
|
|
|
break;
|
|
|
|
#endif
|
|
|
|
|
|
|
|
case LWS_CALLBACK_GET_THREAD_ID:
|
|
|
|
/*
|
2015-12-04 08:43:54 +08:00
|
|
|
* if you will call "lws_callback_on_writable"
|
2015-11-19 13:55:47 +08:00
|
|
|
* from a different thread, return the caller thread ID
|
|
|
|
* here so lws can use this information to work out if it
|
|
|
|
* should signal the poll() loop to exit and restart early
|
|
|
|
*/
|
|
|
|
|
|
|
|
/* return pthread_getthreadid_np(); */
|
|
|
|
|
|
|
|
break;
|
|
|
|
|
2016-04-13 22:17:05 +02:00
|
|
|
#if defined(LWS_OPENSSL_SUPPORT)
|
|
|
|
case LWS_CALLBACK_OPENSSL_PERFORM_CLIENT_CERT_VERIFICATION:
|
|
|
|
/* Verify the client certificate */
|
|
|
|
if (!len || (SSL_get_verify_result((SSL*)in) != X509_V_OK)) {
|
|
|
|
int err = X509_STORE_CTX_get_error((X509_STORE_CTX*)user);
|
|
|
|
int depth = X509_STORE_CTX_get_error_depth((X509_STORE_CTX*)user);
|
|
|
|
const char* msg = X509_verify_cert_error_string(err);
|
|
|
|
lwsl_err("LWS_CALLBACK_OPENSSL_PERFORM_CLIENT_CERT_VERIFICATION: SSL error: %s (%d), depth: %d\n", msg, err, depth);
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
#if defined(LWS_HAVE_SSL_CTX_set1_param)
|
|
|
|
case LWS_CALLBACK_OPENSSL_LOAD_EXTRA_SERVER_VERIFY_CERTS:
|
|
|
|
if (crl_path[0]) {
|
|
|
|
/* Enable CRL checking */
|
|
|
|
X509_VERIFY_PARAM *param = X509_VERIFY_PARAM_new();
|
|
|
|
X509_VERIFY_PARAM_set_flags(param, X509_V_FLAG_CRL_CHECK);
|
|
|
|
SSL_CTX_set1_param((SSL_CTX*)user, param);
|
|
|
|
X509_STORE *store = SSL_CTX_get_cert_store((SSL_CTX*)user);
|
|
|
|
X509_LOOKUP *lookup = X509_STORE_add_lookup(store, X509_LOOKUP_file());
|
|
|
|
n = X509_load_cert_crl_file(lookup, crl_path, X509_FILETYPE_PEM);
|
|
|
|
X509_VERIFY_PARAM_free(param);
|
|
|
|
if (n != 1) {
|
|
|
|
char errbuf[256];
|
|
|
|
n = ERR_get_error();
|
|
|
|
lwsl_err("LWS_CALLBACK_OPENSSL_LOAD_EXTRA_SERVER_VERIFY_CERTS: SSL error: %s (%d)\n", ERR_error_string(n, errbuf), n);
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
#endif
|
|
|
|
#endif
|
|
|
|
|
2015-11-19 13:55:47 +08:00
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
/* if we're on HTTP1.1 or 2.0, will keep the idle connection alive */
|
|
|
|
try_to_reuse:
|
|
|
|
if (lws_http_transaction_completed(wsi))
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|