You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

199 lines
4.8 KiB

/*
* ws protocol handler plugin for "client_loopback_test"
*
* Written in 2010-2019 by 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.
*/
#define LWS_DLL
#define LWS_INTERNAL
#include <libwebsockets.h>
#include <string.h>
struct per_session_data__client_loopback_test {
struct lws *wsi;
};
/*
* This is a bit fiddly...
*
* 0) If you want the wss:// test to work, make sure the vhost is marked with
* enable-client-ssl if using lwsws, or call lws_init_vhost_client_ssl() on
* the vhost if you're doing it by hand.
*
* 1) enable the protocol on a vhost
*
* "ws-protocols": [{
* "client-loopback-test": {
* "status": "ok"
* }, ...
*
* the vhost should listen on 80 (ws://) or 443 (wss://)
*
* 2) mount the http part of the test one level down on the same vhost, eg
* {
* "mountpoint": "/c",
* "origin": "callback://client-loopback-test"
* }
*
* 3) Use a browser to visit the mountpoint with a URI attached for looping
* back, eg, if testing on localhost
*
* http://localhost/c/ws://localhost
* https://localhost/c/wss://localhost
*
* 4) The HTTP part of this test protocol will try to do the requested
* ws client connection, to the same test protocol on the same
* server.
*/
static int
callback_client_loopback_test(struct lws *wsi, enum lws_callback_reasons reason,
void *user, void *in, size_t len)
{
struct lws_client_connect_info i;
struct per_session_data__client_loopback_test *pss =
(struct per_session_data__client_loopback_test *)user;
const char *p = (const char *)in;
char buf[100];
int n;
switch (reason) {
/* HTTP part */
case LWS_CALLBACK_HTTP:
if (len < 10)
return -1;
p++;
while (*p && *p != '/')
p++;
if (!*p) {
lws_return_http_status(wsi, 400, "Arg needs to be in format ws://xxx or wss://xxx");
return -1;
}
p++;
memset(&i, 0, sizeof(i));
i.context = lws_get_context(wsi);
// stacked /// get resolved to /
if (strncmp(p, "ws:/", 4) == 0) {
i.ssl_connection = 0;
i.port = 80;
p += 4;
} else
if (strncmp(p, "wss:/", 5) == 0) {
i.port = 443;
i.ssl_connection = 1;
p += 5;
} else {
sprintf(buf, "Arg %s is not in format ws://xxx or wss://xxx\n", p);
lws_return_http_status(wsi, 400, buf);
return -1;
}
i.address = p;
i.path = "";
i.host = p;
i.origin = p;
i.ietf_version_or_minus_one = -1;
i.protocol = "client-loopback-test";
pss->wsi = lws_client_connect_via_info(&i);
if (!pss->wsi)
lws_return_http_status(wsi, 401, "client-loopback-test: connect failed\n");
else {
lwsl_notice("client connection to %s:%d with ssl: %d started\n",
i.address, i.port, i.ssl_connection);
lws_return_http_status(wsi, 200, "OK");
}
/* either way, close the triggering http link */
return -1;
case LWS_CALLBACK_CLOSED_HTTP:
lwsl_notice("Http part closed\n");
break;
/* server part */
case LWS_CALLBACK_ESTABLISHED:
lwsl_notice("server part: LWS_CALLBACK_ESTABLISHED\n");
strcpy(buf + LWS_PRE, "Made it");
n = lws_write(wsi, (unsigned char *)buf + LWS_PRE,
7, LWS_WRITE_TEXT);
if (n < 7)
return -1;
break;
/* client part */
case LWS_CALLBACK_CLIENT_ESTABLISHED:
lwsl_notice("Client connection established\n");
break;
case LWS_CALLBACK_CLIENT_RECEIVE:
lws_strncpy(buf, in, sizeof(buf));
lwsl_notice("Client connection received %ld from server '%s'\n",
(long)len, buf);
/* OK we are done with the client connection */
return -1;
default:
break;
}
return 0;
}
static const struct lws_protocols protocols[] = {
{
"client-loopback-test",
callback_client_loopback_test,
sizeof(struct per_session_data__client_loopback_test),
1024, /* rx buf size must be >= permessage-deflate rx size */
},
};
LWS_VISIBLE int
init_protocol_client_loopback_test(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 = LWS_ARRAY_SIZE(protocols);
c->extensions = NULL;
c->count_extensions = 0;
return 0;
}
LWS_VISIBLE int
destroy_protocol_client_loopback_test(struct lws_context *context)
{
return 0;
}