handle same vh protocol reinsert
[platform/upstream/libwebsockets.git] / plugins / protocol_client_loopback_test.c
1 /*
2  * ws protocol handler plugin for "client_loopback_test"
3  *
4  * Copyright (C) 2010-2016 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 "../lib/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
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                 strncpy(buf, in, sizeof(buf) - 1);
154                 lwsl_notice("Client connection received %ld from server '%s'\n", (long)len, buf);
155
156                 /* OK we are done with the client connection */
157                 return -1;
158
159         default:
160                 break;
161         }
162
163         return 0;
164 }
165
166 static const struct lws_protocols protocols[] = {
167         {
168                 "client-loopback-test",
169                 callback_client_loopback_test,
170                 sizeof(struct per_session_data__client_loopback_test),
171                 1024, /* rx buf size must be >= permessage-deflate rx size */
172         },
173 };
174
175 LWS_EXTERN LWS_VISIBLE int
176 init_protocol_client_loopback_test(struct lws_context *context,
177                                    struct lws_plugin_capability *c)
178 {
179         if (c->api_magic != LWS_PLUGIN_API_MAGIC) {
180                 lwsl_err("Plugin API %d, library API %d", LWS_PLUGIN_API_MAGIC,
181                          c->api_magic);
182                 return 1;
183         }
184
185         c->protocols = protocols;
186         c->count_protocols = ARRAY_SIZE(protocols);
187         c->extensions = NULL;
188         c->count_extensions = 0;
189
190         return 0;
191 }
192
193 LWS_EXTERN LWS_VISIBLE int
194 destroy_protocol_client_loopback_test(struct lws_context *context)
195 {
196         return 0;
197 }