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