xref: /aosp_15_r20/external/curl/tests/http/clients/ws-data.c (revision 6236dae45794135f37c4eb022389c904c8b0090d)
1*6236dae4SAndroid Build Coastguard Worker /***************************************************************************
2*6236dae4SAndroid Build Coastguard Worker  *                                  _   _ ____  _
3*6236dae4SAndroid Build Coastguard Worker  *  Project                     ___| | | |  _ \| |
4*6236dae4SAndroid Build Coastguard Worker  *                             / __| | | | |_) | |
5*6236dae4SAndroid Build Coastguard Worker  *                            | (__| |_| |  _ <| |___
6*6236dae4SAndroid Build Coastguard Worker  *                             \___|\___/|_| \_\_____|
7*6236dae4SAndroid Build Coastguard Worker  *
8*6236dae4SAndroid Build Coastguard Worker  * Copyright (C) Daniel Stenberg, <[email protected]>, et al.
9*6236dae4SAndroid Build Coastguard Worker  *
10*6236dae4SAndroid Build Coastguard Worker  * This software is licensed as described in the file COPYING, which
11*6236dae4SAndroid Build Coastguard Worker  * you should have received as part of this distribution. The terms
12*6236dae4SAndroid Build Coastguard Worker  * are also available at https://curl.se/docs/copyright.html.
13*6236dae4SAndroid Build Coastguard Worker  *
14*6236dae4SAndroid Build Coastguard Worker  * You may opt to use, copy, modify, merge, publish, distribute and/or sell
15*6236dae4SAndroid Build Coastguard Worker  * copies of the Software, and permit persons to whom the Software is
16*6236dae4SAndroid Build Coastguard Worker  * furnished to do so, under the terms of the COPYING file.
17*6236dae4SAndroid Build Coastguard Worker  *
18*6236dae4SAndroid Build Coastguard Worker  * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
19*6236dae4SAndroid Build Coastguard Worker  * KIND, either express or implied.
20*6236dae4SAndroid Build Coastguard Worker  *
21*6236dae4SAndroid Build Coastguard Worker  * SPDX-License-Identifier: curl
22*6236dae4SAndroid Build Coastguard Worker  *
23*6236dae4SAndroid Build Coastguard Worker  ***************************************************************************/
24*6236dae4SAndroid Build Coastguard Worker /* <DESC>
25*6236dae4SAndroid Build Coastguard Worker  * WebSockets data echos
26*6236dae4SAndroid Build Coastguard Worker  * </DESC>
27*6236dae4SAndroid Build Coastguard Worker  */
28*6236dae4SAndroid Build Coastguard Worker /* curl stuff */
29*6236dae4SAndroid Build Coastguard Worker #include "curl_setup.h"
30*6236dae4SAndroid Build Coastguard Worker #include <curl/curl.h>
31*6236dae4SAndroid Build Coastguard Worker 
32*6236dae4SAndroid Build Coastguard Worker #include <stdio.h>
33*6236dae4SAndroid Build Coastguard Worker #include <stdlib.h>
34*6236dae4SAndroid Build Coastguard Worker #include <string.h>
35*6236dae4SAndroid Build Coastguard Worker 
36*6236dae4SAndroid Build Coastguard Worker #ifndef CURL_DISABLE_WEBSOCKETS
37*6236dae4SAndroid Build Coastguard Worker 
38*6236dae4SAndroid Build Coastguard Worker #ifdef _WIN32
39*6236dae4SAndroid Build Coastguard Worker #ifndef WIN32_LEAN_AND_MEAN
40*6236dae4SAndroid Build Coastguard Worker #define WIN32_LEAN_AND_MEAN
41*6236dae4SAndroid Build Coastguard Worker #endif
42*6236dae4SAndroid Build Coastguard Worker #include <windows.h>
43*6236dae4SAndroid Build Coastguard Worker #else
44*6236dae4SAndroid Build Coastguard Worker #include <sys/time.h>
45*6236dae4SAndroid Build Coastguard Worker #endif
46*6236dae4SAndroid Build Coastguard Worker 
47*6236dae4SAndroid Build Coastguard Worker static
dump(const char * text,unsigned char * ptr,size_t size,char nohex)48*6236dae4SAndroid Build Coastguard Worker void dump(const char *text, unsigned char *ptr, size_t size,
49*6236dae4SAndroid Build Coastguard Worker           char nohex)
50*6236dae4SAndroid Build Coastguard Worker {
51*6236dae4SAndroid Build Coastguard Worker   size_t i;
52*6236dae4SAndroid Build Coastguard Worker   size_t c;
53*6236dae4SAndroid Build Coastguard Worker 
54*6236dae4SAndroid Build Coastguard Worker   unsigned int width = 0x10;
55*6236dae4SAndroid Build Coastguard Worker 
56*6236dae4SAndroid Build Coastguard Worker   if(nohex)
57*6236dae4SAndroid Build Coastguard Worker     /* without the hex output, we can fit more on screen */
58*6236dae4SAndroid Build Coastguard Worker     width = 0x40;
59*6236dae4SAndroid Build Coastguard Worker 
60*6236dae4SAndroid Build Coastguard Worker   fprintf(stderr, "%s, %lu bytes (0x%lx)\n",
61*6236dae4SAndroid Build Coastguard Worker           text, (unsigned long)size, (unsigned long)size);
62*6236dae4SAndroid Build Coastguard Worker 
63*6236dae4SAndroid Build Coastguard Worker   for(i = 0; i < size; i += width) {
64*6236dae4SAndroid Build Coastguard Worker 
65*6236dae4SAndroid Build Coastguard Worker     fprintf(stderr, "%4.4lx: ", (unsigned long)i);
66*6236dae4SAndroid Build Coastguard Worker 
67*6236dae4SAndroid Build Coastguard Worker     if(!nohex) {
68*6236dae4SAndroid Build Coastguard Worker       /* hex not disabled, show it */
69*6236dae4SAndroid Build Coastguard Worker       for(c = 0; c < width; c++)
70*6236dae4SAndroid Build Coastguard Worker         if(i + c < size)
71*6236dae4SAndroid Build Coastguard Worker           fprintf(stderr, "%02x ", ptr[i + c]);
72*6236dae4SAndroid Build Coastguard Worker         else
73*6236dae4SAndroid Build Coastguard Worker           fputs("   ", stderr);
74*6236dae4SAndroid Build Coastguard Worker     }
75*6236dae4SAndroid Build Coastguard Worker 
76*6236dae4SAndroid Build Coastguard Worker     for(c = 0; (c < width) && (i + c < size); c++) {
77*6236dae4SAndroid Build Coastguard Worker       /* check for 0D0A; if found, skip past and start a new line of output */
78*6236dae4SAndroid Build Coastguard Worker       if(nohex && (i + c + 1 < size) && ptr[i + c] == 0x0D &&
79*6236dae4SAndroid Build Coastguard Worker          ptr[i + c + 1] == 0x0A) {
80*6236dae4SAndroid Build Coastguard Worker         i += (c + 2 - width);
81*6236dae4SAndroid Build Coastguard Worker         break;
82*6236dae4SAndroid Build Coastguard Worker       }
83*6236dae4SAndroid Build Coastguard Worker       fprintf(stderr, "%c",
84*6236dae4SAndroid Build Coastguard Worker               (ptr[i + c] >= 0x20) && (ptr[i + c] < 0x80) ? ptr[i + c] : '.');
85*6236dae4SAndroid Build Coastguard Worker       /* check again for 0D0A, to avoid an extra \n if it's at width */
86*6236dae4SAndroid Build Coastguard Worker       if(nohex && (i + c + 2 < size) && ptr[i + c + 1] == 0x0D &&
87*6236dae4SAndroid Build Coastguard Worker          ptr[i + c + 2] == 0x0A) {
88*6236dae4SAndroid Build Coastguard Worker         i += (c + 3 - width);
89*6236dae4SAndroid Build Coastguard Worker         break;
90*6236dae4SAndroid Build Coastguard Worker       }
91*6236dae4SAndroid Build Coastguard Worker     }
92*6236dae4SAndroid Build Coastguard Worker     fputc('\n', stderr); /* newline */
93*6236dae4SAndroid Build Coastguard Worker   }
94*6236dae4SAndroid Build Coastguard Worker }
95*6236dae4SAndroid Build Coastguard Worker 
send_binary(CURL * curl,char * buf,size_t buflen)96*6236dae4SAndroid Build Coastguard Worker static CURLcode send_binary(CURL *curl, char *buf, size_t buflen)
97*6236dae4SAndroid Build Coastguard Worker {
98*6236dae4SAndroid Build Coastguard Worker   size_t nwritten;
99*6236dae4SAndroid Build Coastguard Worker   CURLcode result =
100*6236dae4SAndroid Build Coastguard Worker     curl_ws_send(curl, buf, buflen, &nwritten, 0, CURLWS_BINARY);
101*6236dae4SAndroid Build Coastguard Worker   fprintf(stderr, "ws: send_binary(len=%ld) -> %d, %ld\n",
102*6236dae4SAndroid Build Coastguard Worker           (long)buflen, result, (long)nwritten);
103*6236dae4SAndroid Build Coastguard Worker   return result;
104*6236dae4SAndroid Build Coastguard Worker }
105*6236dae4SAndroid Build Coastguard Worker 
recv_binary(CURL * curl,char * exp_data,size_t exp_len)106*6236dae4SAndroid Build Coastguard Worker static CURLcode recv_binary(CURL *curl, char *exp_data, size_t exp_len)
107*6236dae4SAndroid Build Coastguard Worker {
108*6236dae4SAndroid Build Coastguard Worker   const struct curl_ws_frame *frame;
109*6236dae4SAndroid Build Coastguard Worker   char recvbuf[256];
110*6236dae4SAndroid Build Coastguard Worker   size_t r_offset, nread;
111*6236dae4SAndroid Build Coastguard Worker   CURLcode result;
112*6236dae4SAndroid Build Coastguard Worker 
113*6236dae4SAndroid Build Coastguard Worker   fprintf(stderr, "recv_binary: expected payload %ld bytes\n", (long)exp_len);
114*6236dae4SAndroid Build Coastguard Worker   r_offset = 0;
115*6236dae4SAndroid Build Coastguard Worker   while(1) {
116*6236dae4SAndroid Build Coastguard Worker     result = curl_ws_recv(curl, recvbuf, sizeof(recvbuf), &nread, &frame);
117*6236dae4SAndroid Build Coastguard Worker     if(result == CURLE_AGAIN) {
118*6236dae4SAndroid Build Coastguard Worker       fprintf(stderr, "EAGAIN, sleep, try again\n");
119*6236dae4SAndroid Build Coastguard Worker #ifdef _WIN32
120*6236dae4SAndroid Build Coastguard Worker       Sleep(100);
121*6236dae4SAndroid Build Coastguard Worker #else
122*6236dae4SAndroid Build Coastguard Worker       usleep(100*1000);
123*6236dae4SAndroid Build Coastguard Worker #endif
124*6236dae4SAndroid Build Coastguard Worker       continue;
125*6236dae4SAndroid Build Coastguard Worker     }
126*6236dae4SAndroid Build Coastguard Worker     fprintf(stderr, "ws: curl_ws_recv(offset=%ld, len=%ld) -> %d, %ld\n",
127*6236dae4SAndroid Build Coastguard Worker             (long)r_offset, (long)sizeof(recvbuf), result, (long)nread);
128*6236dae4SAndroid Build Coastguard Worker     if(result) {
129*6236dae4SAndroid Build Coastguard Worker       return result;
130*6236dae4SAndroid Build Coastguard Worker     }
131*6236dae4SAndroid Build Coastguard Worker     if(!(frame->flags & CURLWS_BINARY)) {
132*6236dae4SAndroid Build Coastguard Worker       fprintf(stderr, "recv_data: wrong frame, got %ld bytes rflags %x\n",
133*6236dae4SAndroid Build Coastguard Worker               (long)nread, frame->flags);
134*6236dae4SAndroid Build Coastguard Worker       return CURLE_RECV_ERROR;
135*6236dae4SAndroid Build Coastguard Worker     }
136*6236dae4SAndroid Build Coastguard Worker     if(frame->offset != (curl_off_t)r_offset) {
137*6236dae4SAndroid Build Coastguard Worker       fprintf(stderr, "recv_data: frame offset, expected %ld, got %ld\n",
138*6236dae4SAndroid Build Coastguard Worker               (long)r_offset, (long)frame->offset);
139*6236dae4SAndroid Build Coastguard Worker       return CURLE_RECV_ERROR;
140*6236dae4SAndroid Build Coastguard Worker     }
141*6236dae4SAndroid Build Coastguard Worker     if(frame->bytesleft != (curl_off_t)(exp_len - r_offset - nread)) {
142*6236dae4SAndroid Build Coastguard Worker       fprintf(stderr, "recv_data: frame bytesleft, expected %ld, got %ld\n",
143*6236dae4SAndroid Build Coastguard Worker               (long)(exp_len - r_offset - nread), (long)frame->bytesleft);
144*6236dae4SAndroid Build Coastguard Worker       return CURLE_RECV_ERROR;
145*6236dae4SAndroid Build Coastguard Worker     }
146*6236dae4SAndroid Build Coastguard Worker     if(r_offset + nread > exp_len) {
147*6236dae4SAndroid Build Coastguard Worker       fprintf(stderr, "recv_data: data length, expected %ld, now at %ld\n",
148*6236dae4SAndroid Build Coastguard Worker               (long)exp_len, (long)(r_offset + nread));
149*6236dae4SAndroid Build Coastguard Worker       return CURLE_RECV_ERROR;
150*6236dae4SAndroid Build Coastguard Worker     }
151*6236dae4SAndroid Build Coastguard Worker     if(memcmp(exp_data + r_offset, recvbuf, nread)) {
152*6236dae4SAndroid Build Coastguard Worker       fprintf(stderr, "recv_data: data differs, offset=%ld, len=%ld\n",
153*6236dae4SAndroid Build Coastguard Worker               (long)r_offset, (long)nread);
154*6236dae4SAndroid Build Coastguard Worker       dump("expected:", (unsigned char *)exp_data + r_offset, nread, 0);
155*6236dae4SAndroid Build Coastguard Worker       dump("received:", (unsigned char *)recvbuf, nread, 0);
156*6236dae4SAndroid Build Coastguard Worker       return CURLE_RECV_ERROR;
157*6236dae4SAndroid Build Coastguard Worker     }
158*6236dae4SAndroid Build Coastguard Worker     r_offset += nread;
159*6236dae4SAndroid Build Coastguard Worker     if(r_offset >= exp_len) {
160*6236dae4SAndroid Build Coastguard Worker       fprintf(stderr, "recv_data: frame complete\n");
161*6236dae4SAndroid Build Coastguard Worker       break;
162*6236dae4SAndroid Build Coastguard Worker     }
163*6236dae4SAndroid Build Coastguard Worker   }
164*6236dae4SAndroid Build Coastguard Worker   return CURLE_OK;
165*6236dae4SAndroid Build Coastguard Worker }
166*6236dae4SAndroid Build Coastguard Worker 
167*6236dae4SAndroid Build Coastguard Worker /* just close the connection */
websocket_close(CURL * curl)168*6236dae4SAndroid Build Coastguard Worker static void websocket_close(CURL *curl)
169*6236dae4SAndroid Build Coastguard Worker {
170*6236dae4SAndroid Build Coastguard Worker   size_t sent;
171*6236dae4SAndroid Build Coastguard Worker   CURLcode result =
172*6236dae4SAndroid Build Coastguard Worker     curl_ws_send(curl, "", 0, &sent, 0, CURLWS_CLOSE);
173*6236dae4SAndroid Build Coastguard Worker   fprintf(stderr,
174*6236dae4SAndroid Build Coastguard Worker           "ws: curl_ws_send returned %u, sent %u\n", (int)result, (int)sent);
175*6236dae4SAndroid Build Coastguard Worker }
176*6236dae4SAndroid Build Coastguard Worker 
data_echo(CURL * curl,size_t plen_min,size_t plen_max)177*6236dae4SAndroid Build Coastguard Worker static CURLcode data_echo(CURL *curl, size_t plen_min, size_t plen_max)
178*6236dae4SAndroid Build Coastguard Worker {
179*6236dae4SAndroid Build Coastguard Worker   CURLcode res = CURLE_OK;
180*6236dae4SAndroid Build Coastguard Worker   size_t len;
181*6236dae4SAndroid Build Coastguard Worker   char *send_buf;
182*6236dae4SAndroid Build Coastguard Worker   size_t i;
183*6236dae4SAndroid Build Coastguard Worker 
184*6236dae4SAndroid Build Coastguard Worker   send_buf = calloc(1, plen_max);
185*6236dae4SAndroid Build Coastguard Worker   if(!send_buf)
186*6236dae4SAndroid Build Coastguard Worker     return CURLE_OUT_OF_MEMORY;
187*6236dae4SAndroid Build Coastguard Worker   for(i = 0; i < plen_max; ++i) {
188*6236dae4SAndroid Build Coastguard Worker     send_buf[i] = (char)('0' + ((int)i % 10));
189*6236dae4SAndroid Build Coastguard Worker   }
190*6236dae4SAndroid Build Coastguard Worker 
191*6236dae4SAndroid Build Coastguard Worker   for(len = plen_min; len <= plen_max; ++len) {
192*6236dae4SAndroid Build Coastguard Worker     res = send_binary(curl, send_buf, len);
193*6236dae4SAndroid Build Coastguard Worker     if(res)
194*6236dae4SAndroid Build Coastguard Worker       goto out;
195*6236dae4SAndroid Build Coastguard Worker     res = recv_binary(curl, send_buf, len);
196*6236dae4SAndroid Build Coastguard Worker     if(res) {
197*6236dae4SAndroid Build Coastguard Worker       fprintf(stderr, "recv_data(len=%ld) -> %d\n", (long)len, res);
198*6236dae4SAndroid Build Coastguard Worker       goto out;
199*6236dae4SAndroid Build Coastguard Worker     }
200*6236dae4SAndroid Build Coastguard Worker   }
201*6236dae4SAndroid Build Coastguard Worker 
202*6236dae4SAndroid Build Coastguard Worker out:
203*6236dae4SAndroid Build Coastguard Worker   if(!res)
204*6236dae4SAndroid Build Coastguard Worker     websocket_close(curl);
205*6236dae4SAndroid Build Coastguard Worker   free(send_buf);
206*6236dae4SAndroid Build Coastguard Worker   return res;
207*6236dae4SAndroid Build Coastguard Worker }
208*6236dae4SAndroid Build Coastguard Worker 
209*6236dae4SAndroid Build Coastguard Worker #endif
210*6236dae4SAndroid Build Coastguard Worker 
main(int argc,char * argv[])211*6236dae4SAndroid Build Coastguard Worker int main(int argc, char *argv[])
212*6236dae4SAndroid Build Coastguard Worker {
213*6236dae4SAndroid Build Coastguard Worker #ifndef CURL_DISABLE_WEBSOCKETS
214*6236dae4SAndroid Build Coastguard Worker   CURL *curl;
215*6236dae4SAndroid Build Coastguard Worker   CURLcode res = CURLE_OK;
216*6236dae4SAndroid Build Coastguard Worker   const char *url;
217*6236dae4SAndroid Build Coastguard Worker   long l1, l2;
218*6236dae4SAndroid Build Coastguard Worker   size_t plen_min, plen_max;
219*6236dae4SAndroid Build Coastguard Worker 
220*6236dae4SAndroid Build Coastguard Worker 
221*6236dae4SAndroid Build Coastguard Worker   if(argc != 4) {
222*6236dae4SAndroid Build Coastguard Worker     fprintf(stderr, "usage: ws-data url minlen maxlen\n");
223*6236dae4SAndroid Build Coastguard Worker     return 2;
224*6236dae4SAndroid Build Coastguard Worker   }
225*6236dae4SAndroid Build Coastguard Worker   url = argv[1];
226*6236dae4SAndroid Build Coastguard Worker   l1 = strtol(argv[2], NULL, 10);
227*6236dae4SAndroid Build Coastguard Worker   if(l1 < 0) {
228*6236dae4SAndroid Build Coastguard Worker     fprintf(stderr, "minlen must be >= 0, got %ld\n", l1);
229*6236dae4SAndroid Build Coastguard Worker     return 2;
230*6236dae4SAndroid Build Coastguard Worker   }
231*6236dae4SAndroid Build Coastguard Worker   l2 = strtol(argv[3], NULL, 10);
232*6236dae4SAndroid Build Coastguard Worker   if(l2 < 0) {
233*6236dae4SAndroid Build Coastguard Worker     fprintf(stderr, "maxlen must be >= 0, got %ld\n", l2);
234*6236dae4SAndroid Build Coastguard Worker     return 2;
235*6236dae4SAndroid Build Coastguard Worker   }
236*6236dae4SAndroid Build Coastguard Worker   plen_min = l1;
237*6236dae4SAndroid Build Coastguard Worker   plen_max = l2;
238*6236dae4SAndroid Build Coastguard Worker   if(plen_max < plen_min) {
239*6236dae4SAndroid Build Coastguard Worker     fprintf(stderr, "maxlen must be >= minlen, got %ld-%ld\n",
240*6236dae4SAndroid Build Coastguard Worker             (long)plen_min, (long)plen_max);
241*6236dae4SAndroid Build Coastguard Worker     return 2;
242*6236dae4SAndroid Build Coastguard Worker   }
243*6236dae4SAndroid Build Coastguard Worker 
244*6236dae4SAndroid Build Coastguard Worker   curl_global_init(CURL_GLOBAL_ALL);
245*6236dae4SAndroid Build Coastguard Worker 
246*6236dae4SAndroid Build Coastguard Worker   curl = curl_easy_init();
247*6236dae4SAndroid Build Coastguard Worker   if(curl) {
248*6236dae4SAndroid Build Coastguard Worker     curl_easy_setopt(curl, CURLOPT_URL, url);
249*6236dae4SAndroid Build Coastguard Worker 
250*6236dae4SAndroid Build Coastguard Worker     /* use the callback style */
251*6236dae4SAndroid Build Coastguard Worker     curl_easy_setopt(curl, CURLOPT_USERAGENT, "ws-data");
252*6236dae4SAndroid Build Coastguard Worker     curl_easy_setopt(curl, CURLOPT_VERBOSE, 1L);
253*6236dae4SAndroid Build Coastguard Worker     curl_easy_setopt(curl, CURLOPT_CONNECT_ONLY, 2L); /* websocket style */
254*6236dae4SAndroid Build Coastguard Worker     res = curl_easy_perform(curl);
255*6236dae4SAndroid Build Coastguard Worker     fprintf(stderr, "curl_easy_perform() returned %u\n", (int)res);
256*6236dae4SAndroid Build Coastguard Worker     if(res == CURLE_OK)
257*6236dae4SAndroid Build Coastguard Worker       res = data_echo(curl, plen_min, plen_max);
258*6236dae4SAndroid Build Coastguard Worker 
259*6236dae4SAndroid Build Coastguard Worker     /* always cleanup */
260*6236dae4SAndroid Build Coastguard Worker     curl_easy_cleanup(curl);
261*6236dae4SAndroid Build Coastguard Worker   }
262*6236dae4SAndroid Build Coastguard Worker   curl_global_cleanup();
263*6236dae4SAndroid Build Coastguard Worker   return (int)res;
264*6236dae4SAndroid Build Coastguard Worker 
265*6236dae4SAndroid Build Coastguard Worker #else /* !CURL_DISABLE_WEBSOCKETS */
266*6236dae4SAndroid Build Coastguard Worker   (void)argc;
267*6236dae4SAndroid Build Coastguard Worker   (void)argv;
268*6236dae4SAndroid Build Coastguard Worker   fprintf(stderr, "WebSockets not enabled in libcurl\n");
269*6236dae4SAndroid Build Coastguard Worker   return 1;
270*6236dae4SAndroid Build Coastguard Worker #endif /* CURL_DISABLE_WEBSOCKETS */
271*6236dae4SAndroid Build Coastguard Worker }
272