xref: /aosp_15_r20/external/libwebsockets/plugins/protocol_client_loopback_test.c (revision 1c60b9aca93fdbc9b5f19b2d2194c91294b22281)
1*1c60b9acSAndroid Build Coastguard Worker /*
2*1c60b9acSAndroid Build Coastguard Worker  * ws protocol handler plugin for "client_loopback_test"
3*1c60b9acSAndroid Build Coastguard Worker  *
4*1c60b9acSAndroid Build Coastguard Worker  * Written in 2010-2019 by Andy Green <[email protected]>
5*1c60b9acSAndroid Build Coastguard Worker  *
6*1c60b9acSAndroid Build Coastguard Worker  * This file is made available under the Creative Commons CC0 1.0
7*1c60b9acSAndroid Build Coastguard Worker  * Universal Public Domain Dedication.
8*1c60b9acSAndroid Build Coastguard Worker  *
9*1c60b9acSAndroid Build Coastguard Worker  * The person who associated a work with this deed has dedicated
10*1c60b9acSAndroid Build Coastguard Worker  * the work to the public domain by waiving all of his or her rights
11*1c60b9acSAndroid Build Coastguard Worker  * to the work worldwide under copyright law, including all related
12*1c60b9acSAndroid Build Coastguard Worker  * and neighboring rights, to the extent allowed by law. You can copy,
13*1c60b9acSAndroid Build Coastguard Worker  * modify, distribute and perform the work, even for commercial purposes,
14*1c60b9acSAndroid Build Coastguard Worker  * all without asking permission.
15*1c60b9acSAndroid Build Coastguard Worker  *
16*1c60b9acSAndroid Build Coastguard Worker  * These test plugins are intended to be adapted for use in your code, which
17*1c60b9acSAndroid Build Coastguard Worker  * may be proprietary.  So unlike the library itself, they are licensed
18*1c60b9acSAndroid Build Coastguard Worker  * Public Domain.
19*1c60b9acSAndroid Build Coastguard Worker  */
20*1c60b9acSAndroid Build Coastguard Worker 
21*1c60b9acSAndroid Build Coastguard Worker #if !defined(LWS_DLL)
22*1c60b9acSAndroid Build Coastguard Worker #define LWS_DLL
23*1c60b9acSAndroid Build Coastguard Worker #endif
24*1c60b9acSAndroid Build Coastguard Worker #if !defined(LWS_INTERNAL)
25*1c60b9acSAndroid Build Coastguard Worker #define LWS_INTERNAL
26*1c60b9acSAndroid Build Coastguard Worker #endif
27*1c60b9acSAndroid Build Coastguard Worker #include <libwebsockets.h>
28*1c60b9acSAndroid Build Coastguard Worker #include <string.h>
29*1c60b9acSAndroid Build Coastguard Worker 
30*1c60b9acSAndroid Build Coastguard Worker struct per_session_data__client_loopback_test {
31*1c60b9acSAndroid Build Coastguard Worker 	struct lws *wsi;
32*1c60b9acSAndroid Build Coastguard Worker };
33*1c60b9acSAndroid Build Coastguard Worker 
34*1c60b9acSAndroid Build Coastguard Worker /*
35*1c60b9acSAndroid Build Coastguard Worker  * This is a bit fiddly...
36*1c60b9acSAndroid Build Coastguard Worker  *
37*1c60b9acSAndroid Build Coastguard Worker  * 0) If you want the wss:// test to work, make sure the vhost is marked with
38*1c60b9acSAndroid Build Coastguard Worker  *    enable-client-ssl if using lwsws, or call lws_init_vhost_client_ssl() on
39*1c60b9acSAndroid Build Coastguard Worker  *    the vhost if you're doing it by hand.
40*1c60b9acSAndroid Build Coastguard Worker  *
41*1c60b9acSAndroid Build Coastguard Worker  * 1) enable the protocol on a vhost
42*1c60b9acSAndroid Build Coastguard Worker  *
43*1c60b9acSAndroid Build Coastguard Worker  *      "ws-protocols": [{
44*1c60b9acSAndroid Build Coastguard Worker  *     "client-loopback-test": {
45*1c60b9acSAndroid Build Coastguard Worker  *      "status": "ok"
46*1c60b9acSAndroid Build Coastguard Worker  *     },  ...
47*1c60b9acSAndroid Build Coastguard Worker  *
48*1c60b9acSAndroid Build Coastguard Worker  *     the vhost should listen on 80 (ws://) or 443 (wss://)
49*1c60b9acSAndroid Build Coastguard Worker  *
50*1c60b9acSAndroid Build Coastguard Worker  * 2) mount the http part of the test one level down on the same vhost, eg
51*1c60b9acSAndroid Build Coastguard Worker  *   {
52*1c60b9acSAndroid Build Coastguard Worker  *      "mountpoint": "/c",
53*1c60b9acSAndroid Build Coastguard Worker  *      "origin": "callback://client-loopback-test"
54*1c60b9acSAndroid Build Coastguard Worker  *   }
55*1c60b9acSAndroid Build Coastguard Worker  *
56*1c60b9acSAndroid Build Coastguard Worker  * 3) Use a browser to visit the mountpoint with a URI attached for looping
57*1c60b9acSAndroid Build Coastguard Worker  *    back, eg, if testing on localhost
58*1c60b9acSAndroid Build Coastguard Worker  *
59*1c60b9acSAndroid Build Coastguard Worker  *    http://localhost/c/ws://localhost
60*1c60b9acSAndroid Build Coastguard Worker  *    https://localhost/c/wss://localhost
61*1c60b9acSAndroid Build Coastguard Worker  *
62*1c60b9acSAndroid Build Coastguard Worker  * 4) The HTTP part of this test protocol will try to do the requested
63*1c60b9acSAndroid Build Coastguard Worker  *    ws client connection, to the same test protocol on the same
64*1c60b9acSAndroid Build Coastguard Worker  *    server.
65*1c60b9acSAndroid Build Coastguard Worker  */
66*1c60b9acSAndroid Build Coastguard Worker 
67*1c60b9acSAndroid Build Coastguard Worker static int
callback_client_loopback_test(struct lws * wsi,enum lws_callback_reasons reason,void * user,void * in,size_t len)68*1c60b9acSAndroid Build Coastguard Worker callback_client_loopback_test(struct lws *wsi, enum lws_callback_reasons reason,
69*1c60b9acSAndroid Build Coastguard Worker 			void *user, void *in, size_t len)
70*1c60b9acSAndroid Build Coastguard Worker {
71*1c60b9acSAndroid Build Coastguard Worker 	struct lws_client_connect_info i;
72*1c60b9acSAndroid Build Coastguard Worker 	struct per_session_data__client_loopback_test *pss =
73*1c60b9acSAndroid Build Coastguard Worker 			(struct per_session_data__client_loopback_test *)user;
74*1c60b9acSAndroid Build Coastguard Worker 	const char *p = (const char *)in;
75*1c60b9acSAndroid Build Coastguard Worker 	char buf[100];
76*1c60b9acSAndroid Build Coastguard Worker 	int n;
77*1c60b9acSAndroid Build Coastguard Worker 
78*1c60b9acSAndroid Build Coastguard Worker 	switch (reason) {
79*1c60b9acSAndroid Build Coastguard Worker 
80*1c60b9acSAndroid Build Coastguard Worker 	/* HTTP part */
81*1c60b9acSAndroid Build Coastguard Worker 
82*1c60b9acSAndroid Build Coastguard Worker 	case LWS_CALLBACK_HTTP:
83*1c60b9acSAndroid Build Coastguard Worker 		if (len < 10)
84*1c60b9acSAndroid Build Coastguard Worker 			return -1;
85*1c60b9acSAndroid Build Coastguard Worker 
86*1c60b9acSAndroid Build Coastguard Worker 		p++;
87*1c60b9acSAndroid Build Coastguard Worker 		while (*p && *p != '/')
88*1c60b9acSAndroid Build Coastguard Worker 			p++;
89*1c60b9acSAndroid Build Coastguard Worker 		if (!*p) {
90*1c60b9acSAndroid Build Coastguard Worker 			lws_return_http_status(wsi, 400, "Arg needs to be in format ws://xxx or wss://xxx");
91*1c60b9acSAndroid Build Coastguard Worker 			return -1;
92*1c60b9acSAndroid Build Coastguard Worker 		}
93*1c60b9acSAndroid Build Coastguard Worker 		p++;
94*1c60b9acSAndroid Build Coastguard Worker 
95*1c60b9acSAndroid Build Coastguard Worker 		memset(&i, 0, sizeof(i));
96*1c60b9acSAndroid Build Coastguard Worker 		i.context = lws_get_context(wsi);
97*1c60b9acSAndroid Build Coastguard Worker 
98*1c60b9acSAndroid Build Coastguard Worker 		// stacked /// get resolved to /
99*1c60b9acSAndroid Build Coastguard Worker 
100*1c60b9acSAndroid Build Coastguard Worker 		if (strncmp(p, "ws:/", 4) == 0) {
101*1c60b9acSAndroid Build Coastguard Worker 			i.ssl_connection = 0;
102*1c60b9acSAndroid Build Coastguard Worker 			i.port = 80;
103*1c60b9acSAndroid Build Coastguard Worker 			p += 4;
104*1c60b9acSAndroid Build Coastguard Worker 		} else
105*1c60b9acSAndroid Build Coastguard Worker 			if (strncmp(p, "wss:/", 5) == 0) {
106*1c60b9acSAndroid Build Coastguard Worker 				i.port = 443;
107*1c60b9acSAndroid Build Coastguard Worker 				i.ssl_connection = 1;
108*1c60b9acSAndroid Build Coastguard Worker 				p += 5;
109*1c60b9acSAndroid Build Coastguard Worker 			} else {
110*1c60b9acSAndroid Build Coastguard Worker 				sprintf(buf, "Arg %s is not in format ws://xxx or wss://xxx\n", p);
111*1c60b9acSAndroid Build Coastguard Worker 				lws_return_http_status(wsi, 400, buf);
112*1c60b9acSAndroid Build Coastguard Worker 				return -1;
113*1c60b9acSAndroid Build Coastguard Worker 			}
114*1c60b9acSAndroid Build Coastguard Worker 
115*1c60b9acSAndroid Build Coastguard Worker 		i.address = p;
116*1c60b9acSAndroid Build Coastguard Worker 		i.path = "";
117*1c60b9acSAndroid Build Coastguard Worker 		i.host = p;
118*1c60b9acSAndroid Build Coastguard Worker 		i.origin = p;
119*1c60b9acSAndroid Build Coastguard Worker 		i.ietf_version_or_minus_one = -1;
120*1c60b9acSAndroid Build Coastguard Worker 		i.protocol = "client-loopback-test";
121*1c60b9acSAndroid Build Coastguard Worker 
122*1c60b9acSAndroid Build Coastguard Worker 		pss->wsi = lws_client_connect_via_info(&i);
123*1c60b9acSAndroid Build Coastguard Worker 		if (!pss->wsi)
124*1c60b9acSAndroid Build Coastguard Worker 			lws_return_http_status(wsi, 401, "client-loopback-test: connect failed\n");
125*1c60b9acSAndroid Build Coastguard Worker 		else {
126*1c60b9acSAndroid Build Coastguard Worker 			lwsl_notice("client connection to %s:%d with ssl: %d started\n",
127*1c60b9acSAndroid Build Coastguard Worker 				    i.address, i.port, i.ssl_connection);
128*1c60b9acSAndroid Build Coastguard Worker 			lws_return_http_status(wsi, 200, "OK");
129*1c60b9acSAndroid Build Coastguard Worker 		}
130*1c60b9acSAndroid Build Coastguard Worker 
131*1c60b9acSAndroid Build Coastguard Worker 		/* either way, close the triggering http link */
132*1c60b9acSAndroid Build Coastguard Worker 
133*1c60b9acSAndroid Build Coastguard Worker 		return -1;
134*1c60b9acSAndroid Build Coastguard Worker 
135*1c60b9acSAndroid Build Coastguard Worker 	case LWS_CALLBACK_CLOSED_HTTP:
136*1c60b9acSAndroid Build Coastguard Worker 		lwsl_notice("Http part closed\n");
137*1c60b9acSAndroid Build Coastguard Worker 		break;
138*1c60b9acSAndroid Build Coastguard Worker 
139*1c60b9acSAndroid Build Coastguard Worker 	/* server part */
140*1c60b9acSAndroid Build Coastguard Worker 
141*1c60b9acSAndroid Build Coastguard Worker 	case LWS_CALLBACK_ESTABLISHED:
142*1c60b9acSAndroid Build Coastguard Worker 		lwsl_notice("server part: LWS_CALLBACK_ESTABLISHED\n");
143*1c60b9acSAndroid Build Coastguard Worker 		strcpy(buf + LWS_PRE, "Made it");
144*1c60b9acSAndroid Build Coastguard Worker 		n = lws_write(wsi, (unsigned char *)buf + LWS_PRE,
145*1c60b9acSAndroid Build Coastguard Worker 			      7, LWS_WRITE_TEXT);
146*1c60b9acSAndroid Build Coastguard Worker 		if (n < 7)
147*1c60b9acSAndroid Build Coastguard Worker 			return -1;
148*1c60b9acSAndroid Build Coastguard Worker 		break;
149*1c60b9acSAndroid Build Coastguard Worker 
150*1c60b9acSAndroid Build Coastguard Worker 	/* client part */
151*1c60b9acSAndroid Build Coastguard Worker 
152*1c60b9acSAndroid Build Coastguard Worker 	case LWS_CALLBACK_CLIENT_ESTABLISHED:
153*1c60b9acSAndroid Build Coastguard Worker 		lwsl_notice("Client connection established\n");
154*1c60b9acSAndroid Build Coastguard Worker 		break;
155*1c60b9acSAndroid Build Coastguard Worker 
156*1c60b9acSAndroid Build Coastguard Worker 	case LWS_CALLBACK_CLIENT_RECEIVE:
157*1c60b9acSAndroid Build Coastguard Worker 		lws_strncpy(buf, in, sizeof(buf));
158*1c60b9acSAndroid Build Coastguard Worker 		lwsl_notice("Client connection received %ld from server '%s'\n",
159*1c60b9acSAndroid Build Coastguard Worker 			    (long)len, buf);
160*1c60b9acSAndroid Build Coastguard Worker 
161*1c60b9acSAndroid Build Coastguard Worker 		/* OK we are done with the client connection */
162*1c60b9acSAndroid Build Coastguard Worker 		return -1;
163*1c60b9acSAndroid Build Coastguard Worker 
164*1c60b9acSAndroid Build Coastguard Worker 	default:
165*1c60b9acSAndroid Build Coastguard Worker 		break;
166*1c60b9acSAndroid Build Coastguard Worker 	}
167*1c60b9acSAndroid Build Coastguard Worker 
168*1c60b9acSAndroid Build Coastguard Worker 	return 0;
169*1c60b9acSAndroid Build Coastguard Worker }
170*1c60b9acSAndroid Build Coastguard Worker 
171*1c60b9acSAndroid Build Coastguard Worker LWS_VISIBLE const struct lws_protocols client_loopback_test_protocols[] = {
172*1c60b9acSAndroid Build Coastguard Worker 	{
173*1c60b9acSAndroid Build Coastguard Worker 		"client-loopback-test",
174*1c60b9acSAndroid Build Coastguard Worker 		callback_client_loopback_test,
175*1c60b9acSAndroid Build Coastguard Worker 		sizeof(struct per_session_data__client_loopback_test),
176*1c60b9acSAndroid Build Coastguard Worker 		1024, /* rx buf size must be >= permessage-deflate rx size */
177*1c60b9acSAndroid Build Coastguard Worker 		0, NULL, 0
178*1c60b9acSAndroid Build Coastguard Worker 	},
179*1c60b9acSAndroid Build Coastguard Worker };
180*1c60b9acSAndroid Build Coastguard Worker 
181*1c60b9acSAndroid Build Coastguard Worker LWS_VISIBLE const lws_plugin_protocol_t client_loopback_test = {
182*1c60b9acSAndroid Build Coastguard Worker 	.hdr = {
183*1c60b9acSAndroid Build Coastguard Worker 		"client loopback test",
184*1c60b9acSAndroid Build Coastguard Worker 		"lws_protocol_plugin",
185*1c60b9acSAndroid Build Coastguard Worker 		LWS_BUILD_HASH,
186*1c60b9acSAndroid Build Coastguard Worker 		LWS_PLUGIN_API_MAGIC
187*1c60b9acSAndroid Build Coastguard Worker 	},
188*1c60b9acSAndroid Build Coastguard Worker 
189*1c60b9acSAndroid Build Coastguard Worker 	.protocols = client_loopback_test_protocols,
190*1c60b9acSAndroid Build Coastguard Worker 	.count_protocols = LWS_ARRAY_SIZE(client_loopback_test_protocols),
191*1c60b9acSAndroid Build Coastguard Worker 	.extensions = NULL,
192*1c60b9acSAndroid Build Coastguard Worker 	.count_extensions = 0,
193*1c60b9acSAndroid Build Coastguard Worker };
194