add protocol plugin for post demo
Signed-off-by: Andy Green <andy@warmcat.com>
This commit is contained in:
parent
4010694d04
commit
b24aaeb822
11 changed files with 323 additions and 22 deletions
|
@ -1216,6 +1216,8 @@ if (NOT LWS_WITHOUT_TESTAPPS)
|
|||
"plugins/protocol_lws_mirror.c")
|
||||
create_plugin(protocol_lws_status
|
||||
"plugins/protocol_lws_status.c")
|
||||
create_plugin(protocol_post_demo
|
||||
"plugins/protocol_post_demo.c")
|
||||
if (LWS_WITH_SERVER_STATUS)
|
||||
create_plugin(protocol_lws_server_status
|
||||
"plugins/protocol_lws_server_status.c")
|
||||
|
|
|
@ -542,11 +542,64 @@ enum {
|
|||
LWSMPRO_CGI,
|
||||
LWSMPRO_REDIR_HTTP,
|
||||
LWSMPRO_REDIR_HTTPS,
|
||||
LWSMPRO_CALLBACK,
|
||||
};
|
||||
```
|
||||
|
||||
LWSMPRO_FILE is used for mapping url namespace to a filesystem directory and
|
||||
serve it automatically.
|
||||
|
||||
LWSMPRO_CGI associates the url namespace with the given CGI executable, which
|
||||
runs when the URL is accessed and the output provided to the client.
|
||||
|
||||
LWSMPRO_REDIR_HTTP and LWSMPRO_REDIR_HTTPS auto-redirect clients to the given
|
||||
origin URL.
|
||||
|
||||
LWSMPRO_CALLBACK causes the http connection to attach to the callback
|
||||
associated with the named protocol (which may be a plugin).
|
||||
|
||||
|
||||
Operation of LWSMPRO_CALLBACK mounts
|
||||
------------------------------------
|
||||
|
||||
The feature provided by CALLBACK type mounts is binding a part of the URL
|
||||
namespace to a named protocol callback handler.
|
||||
|
||||
This allows protocol plugins to handle areas of the URL namespace. For example
|
||||
in test-server-v2.0.c, the URL area "/formtest" is associated with the plugin
|
||||
providing "protocol-post-demo" like this
|
||||
|
||||
```
|
||||
static const struct lws_http_mount mount_post = {
|
||||
NULL, /* linked-list pointer to next*/
|
||||
"/formtest", /* mountpoint in URL namespace on this vhost */
|
||||
"protocol-post-demo", /* handler */
|
||||
NULL, /* default filename if none given */
|
||||
NULL,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
LWSMPRO_CALLBACK, /* origin points to a callback */
|
||||
9, /* strlen("/formtest"), ie length of the mountpoint */
|
||||
};
|
||||
```
|
||||
|
||||
Client access to /formtest[anything] will be passed to the callback registered
|
||||
with the named protocol, which in this case is provided by a protocol plugin.
|
||||
|
||||
Access by all methods, eg, GET and POST are handled by the callback.
|
||||
|
||||
protocol-post-demo deals with accepting and responding to the html form that
|
||||
is in the test server HTML.
|
||||
|
||||
When a connection accesses a URL related to a CALLBACK type mount, the
|
||||
connection protocol is changed until the next access on the connection to a
|
||||
URL outside the same CALLBACK mount area. User space on the connection is
|
||||
arranged to be the size of the new protocol user space allocation as given in
|
||||
the protocol struct.
|
||||
|
||||
This allocation is only deleted / replaced when the connection accesses a
|
||||
URL region with a different protocol (or the default protocols[0] if no
|
||||
CALLBACK area matches it).
|
||||
|
|
|
@ -256,7 +256,25 @@ Other mount options
|
|||
"cgi-timeout": "30"
|
||||
```
|
||||
|
||||
3) Cache policy of the files in the mount can also be set. If no
|
||||
3) `callback://` protocol may be used when defining a mount to associate a
|
||||
named protocol callback with the URL namespace area. For example
|
||||
|
||||
```
|
||||
{
|
||||
"mountpoint": "/formtest",
|
||||
"origin": "callback://protocol-post-demo"
|
||||
}
|
||||
```
|
||||
|
||||
All handling of client access to /formtest[anything] will be passed to the
|
||||
callback registered to the protocol "protocol-post-demo".
|
||||
|
||||
This is useful for handling POST http body content or general non-cgi http
|
||||
payload generation inside a plugin.
|
||||
|
||||
See the related notes in README.coding.md
|
||||
|
||||
4) Cache policy of the files in the mount can also be set. If no
|
||||
options are given, the content is marked uncacheable.
|
||||
|
||||
{
|
||||
|
|
|
@ -47,6 +47,7 @@ static const char * const mount_protocols[] = {
|
|||
"cgi://",
|
||||
">http://",
|
||||
">https://",
|
||||
"callback://"
|
||||
};
|
||||
|
||||
LWS_VISIBLE void *
|
||||
|
|
|
@ -2368,6 +2368,7 @@ lws_json_dump_vhost(const struct lws_vhost *vh, char *buf, int len)
|
|||
"cgi://",
|
||||
">http://",
|
||||
">https://",
|
||||
"callback://"
|
||||
};
|
||||
char *orig = buf, *end = buf + len - 1, first = 1;
|
||||
int n = 0;
|
||||
|
|
|
@ -1600,12 +1600,13 @@ struct lws_client_connect_info {
|
|||
};
|
||||
|
||||
enum {
|
||||
LWSMPRO_HTTP,
|
||||
LWSMPRO_HTTPS,
|
||||
LWSMPRO_FILE,
|
||||
LWSMPRO_CGI,
|
||||
LWSMPRO_REDIR_HTTP,
|
||||
LWSMPRO_REDIR_HTTPS,
|
||||
LWSMPRO_HTTP = 0,
|
||||
LWSMPRO_HTTPS = 1,
|
||||
LWSMPRO_FILE = 2,
|
||||
LWSMPRO_CGI = 3,
|
||||
LWSMPRO_REDIR_HTTP = 4,
|
||||
LWSMPRO_REDIR_HTTPS = 5,
|
||||
LWSMPRO_CALLBACK = 6,
|
||||
};
|
||||
|
||||
LWS_EXTERN int
|
||||
|
|
|
@ -82,7 +82,7 @@ lws_header_table_reset(struct lws *wsi, int autoservice)
|
|||
ah->rxlen = 0;
|
||||
|
||||
/* since we will restart the ah, our new headers are not completed */
|
||||
wsi->hdr_parsing_completed = 0;
|
||||
// wsi->hdr_parsing_completed = 0;
|
||||
|
||||
/*
|
||||
* if we inherited pending rx (from socket adoption deferred
|
||||
|
|
72
lib/server.c
72
lib/server.c
|
@ -579,9 +579,10 @@ lws_http_action(struct lws *wsi)
|
|||
uri_ptr[hm->mountpoint_len] == '/' ||
|
||||
hm->mountpoint_len == 1)
|
||||
) {
|
||||
if ((hm->origin_protocol == LWSMPRO_CGI ||
|
||||
if (hm->origin_protocol == LWSMPRO_CALLBACK ||
|
||||
((hm->origin_protocol == LWSMPRO_CGI ||
|
||||
lws_hdr_total_length(wsi, WSI_TOKEN_GET_URI)) &&
|
||||
hm->mountpoint_len > best) {
|
||||
hm->mountpoint_len > best)) {
|
||||
best = hm->mountpoint_len;
|
||||
hit = hm;
|
||||
}
|
||||
|
@ -609,9 +610,13 @@ lws_http_action(struct lws *wsi)
|
|||
* / at the end, we must redirect to add it so the browser
|
||||
* understands he is one "directory level" down.
|
||||
*/
|
||||
if ((hit->mountpoint_len > 1 || (hit->origin_protocol & 4)) &&
|
||||
(*s != '/' || (hit->origin_protocol & 4)) &&
|
||||
(hit->origin_protocol != LWSMPRO_CGI)) {
|
||||
if ((hit->mountpoint_len > 1 ||
|
||||
(hit->origin_protocol == LWSMPRO_REDIR_HTTP ||
|
||||
hit->origin_protocol == LWSMPRO_REDIR_HTTPS)) &&
|
||||
(*s != '/' ||
|
||||
(hit->origin_protocol == LWSMPRO_REDIR_HTTP ||
|
||||
hit->origin_protocol == LWSMPRO_REDIR_HTTPS)) &&
|
||||
(hit->origin_protocol != LWSMPRO_CGI && hit->origin_protocol != LWSMPRO_CALLBACK)) {
|
||||
unsigned char *start = pt->serv_buf + LWS_PRE,
|
||||
*p = start, *end = p + 512;
|
||||
static const char *oprot[] = {
|
||||
|
@ -642,6 +647,50 @@ lws_http_action(struct lws *wsi)
|
|||
return lws_http_transaction_completed(wsi);
|
||||
}
|
||||
|
||||
/*
|
||||
* A particular protocol callback is mounted here?
|
||||
*
|
||||
* For the duration of this http transaction, bind us to the
|
||||
* associated protocol
|
||||
*/
|
||||
if (hit->origin_protocol == LWSMPRO_CALLBACK) {
|
||||
|
||||
for (n = 0; n < wsi->vhost->count_protocols; n++)
|
||||
if (!strcmp(wsi->vhost->protocols[n].name,
|
||||
hit->origin)) {
|
||||
|
||||
if (wsi->protocol != &wsi->vhost->protocols[n])
|
||||
if (!wsi->user_space_externally_allocated)
|
||||
lws_free_set_NULL(wsi->user_space);
|
||||
wsi->protocol = &wsi->vhost->protocols[n];
|
||||
if (lws_ensure_user_space(wsi)) {
|
||||
lwsl_err("Unable to allocate user space\n");
|
||||
|
||||
return 1;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
if (n == wsi->vhost->count_protocols) {
|
||||
n = -1;
|
||||
lwsl_err("Unable to find plugin '%s'\n",
|
||||
hit->origin);
|
||||
}
|
||||
|
||||
n = wsi->protocol->callback(wsi, LWS_CALLBACK_HTTP,
|
||||
wsi->user_space, uri_ptr, uri_len);
|
||||
|
||||
goto after;
|
||||
}
|
||||
|
||||
/* deferred cleanup and reset to protocols[0] */
|
||||
|
||||
if (wsi->protocol != &wsi->vhost->protocols[0])
|
||||
if (!wsi->user_space_externally_allocated)
|
||||
lws_free_set_NULL(wsi->user_space);
|
||||
|
||||
wsi->protocol = &wsi->vhost->protocols[0];
|
||||
|
||||
#ifdef LWS_WITH_CGI
|
||||
/* did we hit something with a cgi:// origin? */
|
||||
if (hit->origin_protocol == LWSMPRO_CGI) {
|
||||
|
@ -699,10 +748,18 @@ lws_http_action(struct lws *wsi)
|
|||
n = wsi->protocol->callback(wsi, LWS_CALLBACK_HTTP,
|
||||
wsi->user_space, uri_ptr, uri_len);
|
||||
}
|
||||
} else
|
||||
} else {
|
||||
/* deferred cleanup and reset to protocols[0] */
|
||||
|
||||
if (wsi->protocol != &wsi->vhost->protocols[0])
|
||||
if (!wsi->user_space_externally_allocated)
|
||||
lws_free_set_NULL(wsi->user_space);
|
||||
wsi->protocol = &wsi->vhost->protocols[0];
|
||||
|
||||
n = wsi->protocol->callback(wsi, LWS_CALLBACK_HTTP,
|
||||
wsi->user_space, uri_ptr, uri_len);
|
||||
|
||||
}
|
||||
after:
|
||||
if (n) {
|
||||
lwsl_info("LWS_CALLBACK_HTTP closing\n");
|
||||
|
||||
|
@ -1185,6 +1242,7 @@ lws_http_transaction_completed(struct lws *wsi)
|
|||
/* otherwise set ourselves up ready to go again */
|
||||
wsi->state = LWSS_HTTP;
|
||||
wsi->mode = LWSCM_HTTP_SERVING;
|
||||
/* reset of non [0] protocols (and freeing of user_space) is deferred */
|
||||
wsi->u.http.content_length = 0;
|
||||
wsi->hdr_parsing_completed = 0;
|
||||
#ifdef LWS_WITH_ACCESS_LOG
|
||||
|
|
|
@ -277,6 +277,7 @@ lejp_vhosts_cb(struct lejp_ctx *ctx, char reason)
|
|||
"cgi://",
|
||||
">http://",
|
||||
">https://",
|
||||
"callback://"
|
||||
};
|
||||
|
||||
if (!a->m.mountpoint || !a->m.origin) {
|
||||
|
|
144
plugins/protocol_post_demo.c
Normal file
144
plugins/protocol_post_demo.c
Normal file
|
@ -0,0 +1,144 @@
|
|||
/*
|
||||
* ws protocol handler plugin for "dumb increment"
|
||||
*
|
||||
* Copyright (C) 2010-2016 Andy Green <andy@warmcat.com>
|
||||
*
|
||||
* This file is made available under the Creative Commons CC0 1.0
|
||||
* Universal Public Domain Dedication.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* These test plugins are intended to be adapted for use in your code, which
|
||||
* may be proprietary. So unlike the library itself, they are licensed
|
||||
* Public Domain.
|
||||
*/
|
||||
#include "../lib/libwebsockets.h"
|
||||
#include <string.h>
|
||||
|
||||
struct per_session_data__post_demo {
|
||||
char post_string[256];
|
||||
char result[500 + LWS_PRE];
|
||||
int result_len;
|
||||
};
|
||||
|
||||
static int
|
||||
callback_post_demo(struct lws *wsi, enum lws_callback_reasons reason,
|
||||
void *user, void *in, size_t len)
|
||||
{
|
||||
struct per_session_data__post_demo *pss =
|
||||
(struct per_session_data__post_demo *)user;
|
||||
unsigned char buffer[LWS_PRE + 512];
|
||||
unsigned char *p, *start, *end;
|
||||
int n;
|
||||
|
||||
switch (reason) {
|
||||
case LWS_CALLBACK_HTTP:
|
||||
lwsl_debug("LWS_CALLBACK_HTTP\n");
|
||||
if (lws_hdr_total_length(wsi, WSI_TOKEN_POST_URI))
|
||||
return 0;
|
||||
break;
|
||||
|
||||
case LWS_CALLBACK_HTTP_BODY:
|
||||
lwsl_debug("LWS_CALLBACK_HTTP_BODY: len %d\n", (int)len);
|
||||
strncpy(pss->post_string, in, sizeof (pss->post_string) -1);
|
||||
pss->post_string[sizeof(pss->post_string) - 1] = '\0';
|
||||
|
||||
if (len < sizeof(pss->post_string) - 1)
|
||||
pss->post_string[len] = '\0';
|
||||
break;
|
||||
|
||||
case LWS_CALLBACK_HTTP_WRITEABLE:
|
||||
lwsl_debug("LWS_CALLBACK_HTTP_WRITEABLE: sending %d\n", pss->result_len);
|
||||
n = lws_write(wsi, (unsigned char *)pss->result + LWS_PRE,
|
||||
pss->result_len, LWS_WRITE_HTTP);
|
||||
if (n < 0)
|
||||
return 1;
|
||||
goto try_to_reuse;
|
||||
|
||||
case LWS_CALLBACK_HTTP_BODY_COMPLETION:
|
||||
lwsl_debug("LWS_CALLBACK_HTTP_BODY_COMPLETION\n");
|
||||
/*
|
||||
* the whole of the sent body arrived,
|
||||
* respond to the client with a redirect to show the
|
||||
* results
|
||||
*/
|
||||
pss->result_len = sprintf((char *)pss->result + LWS_PRE,
|
||||
"<html><body><h1>Form results</h1>'%s'<br>"
|
||||
"</body></html>", pss->post_string);
|
||||
|
||||
p = buffer + LWS_PRE;
|
||||
start = p;
|
||||
end = p + sizeof(buffer) - LWS_PRE;
|
||||
|
||||
if (lws_add_http_header_status(wsi, 200, &p, end))
|
||||
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;
|
||||
|
||||
/*
|
||||
* send the payload next time, in case would block after
|
||||
* headers
|
||||
*/
|
||||
lws_callback_on_writable(wsi);
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
try_to_reuse:
|
||||
if (lws_http_transaction_completed(wsi))
|
||||
return -1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct lws_protocols protocols[] = {
|
||||
{
|
||||
"protocol-post-demo",
|
||||
callback_post_demo,
|
||||
sizeof(struct per_session_data__post_demo),
|
||||
1024,
|
||||
},
|
||||
};
|
||||
|
||||
LWS_VISIBLE int
|
||||
init_protocol_post_demo(struct lws_context *context,
|
||||
struct lws_plugin_capability *c)
|
||||
{
|
||||
if (c->api_magic != LWS_PLUGIN_API_MAGIC) {
|
||||
lwsl_err("Plugin API %d, library API %d", LWS_PLUGIN_API_MAGIC,
|
||||
c->api_magic);
|
||||
return 1;
|
||||
}
|
||||
|
||||
c->protocols = protocols;
|
||||
c->count_protocols = ARRAY_SIZE(protocols);
|
||||
c->extensions = NULL;
|
||||
c->count_extensions = 0;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
LWS_VISIBLE int
|
||||
destroy_protocol_post_demo(struct lws_context *context)
|
||||
{
|
||||
return 0;
|
||||
}
|
|
@ -69,6 +69,25 @@ static const struct lws_extension exts[] = {
|
|||
{ NULL, NULL, NULL /* terminator */ }
|
||||
};
|
||||
|
||||
/*
|
||||
* mount a handler for a section of the URL space
|
||||
*/
|
||||
|
||||
static const struct lws_http_mount mount_post = {
|
||||
NULL, /* linked-list pointer to next*/
|
||||
"/formtest", /* mountpoint in URL namespace on this vhost */
|
||||
"protocol-post-demo", /* handler */
|
||||
NULL, /* default filename if none given */
|
||||
NULL,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
LWSMPRO_CALLBACK, /* origin points to a callback */
|
||||
9, /* strlen("/formtest"), ie length of the mountpoint */
|
||||
};
|
||||
|
||||
/*
|
||||
* mount a filesystem directory into the URL space at /
|
||||
* point it to our /usr/share directory with our assets in
|
||||
|
@ -76,7 +95,7 @@ static const struct lws_extension exts[] = {
|
|||
*/
|
||||
|
||||
static const struct lws_http_mount mount = {
|
||||
NULL, /* linked-list pointer to next, but we only have one */
|
||||
(struct lws_http_mount *)&mount_post, /* linked-list pointer to next*/
|
||||
"/", /* mountpoint in URL namespace on this vhost */
|
||||
LOCAL_RESOURCE_PATH, /* where to go on the filesystem for that */
|
||||
"test.html", /* default filename if none given */
|
||||
|
@ -108,9 +127,16 @@ static const struct lws_protocol_vhost_options pvo_opt = {
|
|||
* linked-list. We can also give the plugin per-vhost options here.
|
||||
*/
|
||||
|
||||
static const struct lws_protocol_vhost_options pvo_2 = {
|
||||
static const struct lws_protocol_vhost_options pvo_3 = {
|
||||
NULL,
|
||||
NULL,
|
||||
"protocol-post-demo",
|
||||
"" /* ignored, just matches the protocol name above */
|
||||
};
|
||||
|
||||
static const struct lws_protocol_vhost_options pvo_2 = {
|
||||
&pvo_3,
|
||||
NULL,
|
||||
"lws-status",
|
||||
"" /* ignored, just matches the protocol name above */
|
||||
};
|
||||
|
@ -160,7 +186,6 @@ static const struct option options[] = {
|
|||
{ "ssl-crl", required_argument, NULL, 'R' },
|
||||
#endif
|
||||
#endif
|
||||
{ "libev", no_argument, NULL, 'e' },
|
||||
#ifndef LWS_NO_DAEMONIZE
|
||||
{ "daemonize", no_argument, NULL, 'D' },
|
||||
#endif
|
||||
|
@ -200,13 +225,10 @@ int main(int argc, char **argv)
|
|||
info.port = 7681;
|
||||
|
||||
while (n >= 0) {
|
||||
n = getopt_long(argc, argv, "ei:hsap:d:Dr:C:K:A:R:vu:g:", options, NULL);
|
||||
n = getopt_long(argc, argv, "i:hsap:d:Dr:C:K:A:R:vu:g:", options, NULL);
|
||||
if (n < 0)
|
||||
continue;
|
||||
switch (n) {
|
||||
case 'e':
|
||||
opts |= LWS_SERVER_OPTION_LIBEV;
|
||||
break;
|
||||
#ifndef LWS_NO_DAEMONIZE
|
||||
case 'D':
|
||||
daemonize = 1;
|
||||
|
|
Loading…
Add table
Reference in a new issue