VirtualBox

source: vbox/trunk/src/VBox/GuestHost/SharedClipboard/testcase/tstClipboardHttpServer.cpp@ 100436

Last change on this file since 100436 was 100393, checked in by vboxsync, 21 months ago

Shared Clipboard: Made setting the transfer callbacks part of ShClTransferCreate(), otherwise the pfnOnCreated callback won't be called. ​​bugref:9437

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 10.6 KB
Line 
1/* $Id: tstClipboardHttpServer.cpp 100393 2023-07-05 16:18:02Z vboxsync $ */
2/** @file
3 * Shared Clipboard HTTP server test case.
4 */
5
6/*
7 * Copyright (C) 2023 Oracle and/or its affiliates.
8 *
9 * This file is part of VirtualBox base platform packages, as
10 * available from https://www.virtualbox.org.
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation, in version 3 of the
15 * License.
16 *
17 * This program is distributed in the hope that it will be useful, but
18 * WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20 * General Public License for more details.
21 *
22 * You should have received a copy of the GNU General Public License
23 * along with this program; if not, see <https://www.gnu.org/licenses>.
24 *
25 * SPDX-License-Identifier: GPL-3.0-only
26 */
27
28#include <iprt/assert.h>
29#include <iprt/dir.h>
30#include <iprt/file.h>
31#include <iprt/getopt.h>
32#include <iprt/http.h>
33#include <iprt/message.h>
34#include <iprt/path.h>
35#include <iprt/string.h>
36#include <iprt/test.h>
37
38#include <VBox/GuestHost/SharedClipboard-transfers.h>
39
40
41/** The release logger. */
42static PRTLOGGER g_pRelLogger;
43/** The current logging verbosity level. */
44static unsigned g_uVerbosity = 0;
45/** Maximum HTTP server runtime (in ms). */
46static RTMSINTERVAL g_msRuntime = RT_MS_30SEC;
47/** Shutdown indicator. */
48static bool g_fShutdown = false;
49/** Manual mode indicator; allows manual testing w/ other HTTP clients. */
50static bool g_fManual = false;
51
52
53/* Worker thread for the HTTP server. */
54static DECLCALLBACK(int) tstSrvWorker(RTTHREAD hThread, void *pvUser)
55{
56 RT_NOREF(pvUser);
57
58 int rc = RTThreadUserSignal(hThread);
59 AssertRCReturn(rc, rc);
60
61 uint32_t const msStartTS = RTTimeMilliTS();
62 while (RTTimeMilliTS() - msStartTS < g_msRuntime)
63 {
64 if (g_fShutdown)
65 break;
66 RTThreadSleep(100); /* Wait a little. */
67 }
68
69 return RTTimeMilliTS() - msStartTS <= g_msRuntime ? VINF_SUCCESS : VERR_TIMEOUT;
70}
71
72int main(int argc, char *argv[])
73{
74 /*
75 * Init the runtime, test and say hello.
76 */
77 RTTEST hTest;
78 RTEXITCODE rcExit = RTTestInitAndCreate("tstClipboardHttpServer", &hTest);
79 if (rcExit != RTEXITCODE_SUCCESS)
80 return rcExit;
81 RTTestBanner(hTest);
82
83 /*
84 * Process options.
85 */
86 static const RTGETOPTDEF aOpts[] =
87 {
88 { "--port", 'p', RTGETOPT_REQ_UINT16 },
89 { "--manual", 'm', RTGETOPT_REQ_NOTHING },
90 { "--max-time", 't', RTGETOPT_REQ_UINT32 },
91 { "--verbose", 'v', RTGETOPT_REQ_NOTHING }
92 };
93
94 RTGETOPTSTATE GetState;
95 int rc = RTGetOptInit(&GetState, argc, argv, aOpts, RT_ELEMENTS(aOpts), 1 /*idxFirst*/, 0 /*fFlags - must not sort! */);
96 AssertRCReturn(rc, RTEXITCODE_INIT);
97
98 uint16_t uPort = 0;
99
100 int ch;
101 RTGETOPTUNION ValueUnion;
102 while ((ch = RTGetOpt(&GetState, &ValueUnion)) != 0)
103 {
104 switch (ch)
105 {
106 case 'p':
107 uPort = ValueUnion.u16;
108 break;
109
110 case 't':
111 g_msRuntime = ValueUnion.u32 * RT_MS_1SEC; /* Convert s to ms. */
112 break;
113
114 case 'm':
115 g_fManual = true;
116 break;
117
118 case 'v':
119 g_uVerbosity++;
120 break;
121
122 case VINF_GETOPT_NOT_OPTION:
123 continue;
124
125 default:
126 return RTGetOptPrintError(ch, &ValueUnion);
127 }
128 }
129
130 /*
131 * Configure release logging to go to stdout.
132 */
133 RTUINT fFlags = RTLOGFLAGS_PREFIX_THREAD | RTLOGFLAGS_PREFIX_TIME_PROG;
134#if defined(RT_OS_WINDOWS) || defined(RT_OS_OS2)
135 fFlags |= RTLOGFLAGS_USECRLF;
136#endif
137 static const char * const s_apszLogGroups[] = VBOX_LOGGROUP_NAMES;
138 rc = RTLogCreate(&g_pRelLogger, fFlags, "all.e.l", "TST_CLIPBOARDR_HTTPSERVER_RELEASE_LOG",
139 RT_ELEMENTS(s_apszLogGroups), s_apszLogGroups, RTLOGDEST_STDOUT, NULL /*"vkat-release.log"*/);
140 if (RT_SUCCESS(rc))
141 {
142 RTLogSetDefaultInstance(g_pRelLogger);
143 if (g_uVerbosity)
144 {
145 RTMsgInfo("Setting verbosity logging to level %u\n", g_uVerbosity);
146 switch (g_uVerbosity) /* Not very elegant, but has to do it for now. */
147 {
148 case 1:
149 rc = RTLogGroupSettings(g_pRelLogger, "shared_clipboard.e.l+http.e.l");
150 break;
151
152 case 2:
153 rc = RTLogGroupSettings(g_pRelLogger, "shared_clipboard.e.l.l2+http.e.l.l2");
154 break;
155
156 case 3:
157 rc = RTLogGroupSettings(g_pRelLogger, "shared_clipboard.e.l.l2.l3+http.e.l.l2.l3");
158 break;
159
160 case 4:
161 RT_FALL_THROUGH();
162 default:
163 rc = RTLogGroupSettings(g_pRelLogger, "shared_clipboard.e.l.l2.l3.l4+http.e.l.l2.l3.l4");
164 break;
165 }
166 if (RT_FAILURE(rc))
167 RTMsgError("Setting debug logging failed, rc=%Rrc\n", rc);
168 }
169 }
170 else
171 RTMsgWarning("Failed to create release logger: %Rrc", rc);
172
173 /*
174 * Create HTTP server.
175 */
176 SHCLHTTPSERVER HttpSrv;
177 ShClTransferHttpServerInit(&HttpSrv);
178 ShClTransferHttpServerStop(&HttpSrv); /* Try to stop a non-running server twice. */
179 ShClTransferHttpServerStop(&HttpSrv);
180 RTTEST_CHECK(hTest, ShClTransferHttpServerIsRunning(&HttpSrv) == false);
181 if (uPort)
182 rc = ShClTransferHttpServerStartEx(&HttpSrv, uPort);
183 else
184 rc = ShClTransferHttpServerStart(&HttpSrv, 32 /* cMaxAttempts */, &uPort);
185 RTTEST_CHECK_RC_OK(hTest, rc);
186 RTTEST_CHECK(hTest, ShClTransferHttpServerGetTransfer(&HttpSrv, 0) == false);
187 RTTEST_CHECK(hTest, ShClTransferHttpServerGetTransfer(&HttpSrv, 42) == false);
188
189 char *pszSrvAddr = ShClTransferHttpServerGetAddressA(&HttpSrv);
190 RTTEST_CHECK(hTest, pszSrvAddr != NULL);
191 RTTestPrintf(hTest, RTTESTLVL_ALWAYS, "HTTP server running: %s (for %RU32ms) ...\n", pszSrvAddr, g_msRuntime);
192 RTMemFree(pszSrvAddr);
193 pszSrvAddr = NULL;
194
195 SHCLTRANSFERCTX TxCtx;
196 RTTEST_CHECK_RC_OK(hTest, ShClTransferCtxInit(&TxCtx));
197
198 /* Query the local transfer provider. */
199 SHCLTXPROVIDER Provider;
200 RTTESTI_CHECK(ShClTransferProviderLocalQueryInterface(&Provider) != NULL);
201
202 /* Parse options again, but this time we only fetch all files we want to serve.
203 * Only can be done after we initialized the HTTP server above. */
204 RT_ZERO(GetState);
205 rc = RTGetOptInit(&GetState, argc, argv, aOpts, RT_ELEMENTS(aOpts), 1 /*idxFirst*/, 0 /*fFlags - must not sort! */);
206 AssertRCReturn(rc, RTEXITCODE_INIT);
207 while ((ch = RTGetOpt(&GetState, &ValueUnion)) != 0)
208 {
209 switch (ch)
210 {
211 case VINF_GETOPT_NOT_OPTION:
212 {
213 PSHCLTRANSFER pTx;
214 RTTEST_CHECK_RC_OK(hTest, ShClTransferCreate(SHCLTRANSFERDIR_TO_REMOTE, SHCLSOURCE_LOCAL, NULL /* Callbacks */, &pTx));
215 RTTEST_CHECK_RC_OK(hTest, ShClTransferSetProvider(pTx, &Provider));
216 RTTEST_CHECK_RC_OK(hTest, ShClTransferInit(pTx));
217 RTTEST_CHECK_RC_OK(hTest, ShClTransferRootsInitFromFile(pTx, ValueUnion.psz));
218 RTTEST_CHECK_RC_OK(hTest, ShClTransferCtxRegister(&TxCtx, pTx, NULL));
219 RTTEST_CHECK_RC_OK(hTest, ShClTransferHttpServerRegisterTransfer(&HttpSrv, pTx));
220 break;
221 }
222
223 default:
224 continue;
225 }
226 }
227
228 uint32_t const cTx = ShClTransferCtxGetTotalTransfers(&TxCtx);
229 if (!cTx)
230 return RTMsgErrorExit(RTEXITCODE_SYNTAX, "No files to serve specified!\n");
231
232 /* Create thread for our HTTP server. */
233 RTTHREAD hThread;
234 rc = RTThreadCreate(&hThread, tstSrvWorker, NULL, 0, RTTHREADTYPE_DEFAULT, RTTHREADFLAGS_WAITABLE,
235 "tstClpHttpSrv");
236 RTTEST_CHECK_RC_OK(hTest, rc);
237 if (RT_SUCCESS(rc))
238 {
239 rc = RTThreadUserWait(hThread, RT_MS_30SEC);
240 RTTEST_CHECK_RC_OK(hTest, rc);
241 }
242
243
244 if (RT_SUCCESS(rc))
245 {
246 if (g_fManual)
247 {
248 for (uint32_t i = 0; i < cTx; i++)
249 {
250 PSHCLTRANSFER pTx = ShClTransferCtxGetTransferByIndex(&TxCtx, i);
251
252 uint16_t const uID = ShClTransferGetID(pTx);
253 char *pszURL = ShClTransferHttpServerGetUrlA(&HttpSrv, uID);
254 RTTEST_CHECK(hTest, pszURL != NULL);
255 RTTestPrintf(hTest, RTTESTLVL_ALWAYS, "URL #%02RU32: %s\n", i, pszURL);
256 RTStrFree(pszURL);
257 }
258 }
259 else /* Download all files to a temp file using our HTTP client. */
260 {
261 RTHTTP hClient;
262 rc = RTHttpCreate(&hClient);
263 if (RT_SUCCESS(rc))
264 {
265 char szFileTemp[RTPATH_MAX];
266 RTTEST_CHECK_RC_OK(hTest, RTPathTemp(szFileTemp, sizeof(szFileTemp)));
267 RTTEST_CHECK_RC_OK(hTest, RTPathAppend(szFileTemp, sizeof(szFileTemp), "tstClipboardHttpServer-XXXXXX"));
268 RTTEST_CHECK_RC_OK(hTest, RTFileCreateTemp(szFileTemp, 0600));
269
270 for (unsigned a = 0; a < 3; a++) /* Repeat downloads to stress things. */
271 {
272 for (uint32_t i = 0; i < cTx; i++)
273 {
274 PSHCLTRANSFER pTx = ShClTransferCtxGetTransferByIndex(&TxCtx, i);
275
276 uint16_t const uID = ShClTransferGetID(pTx);
277 char *pszURL = ShClTransferHttpServerGetUrlA(&HttpSrv, uID);
278 RTTEST_CHECK(hTest, pszURL != NULL);
279 RTTestPrintf(hTest, RTTESTLVL_ALWAYS, "Downloading: %s -> %s\n", pszURL, szFileTemp);
280 RTTEST_CHECK_RC_BREAK(hTest, RTHttpGetFile(hClient, pszURL, szFileTemp), VINF_SUCCESS);
281 RTStrFree(pszURL);
282 }
283 }
284
285 RTTEST_CHECK_RC_OK(hTest, RTFileDelete(szFileTemp));
286 RTTEST_CHECK_RC_OK(hTest, RTHttpDestroy(hClient));
287 }
288
289 /* This is supposed to run unattended, so shutdown automatically. */
290 ASMAtomicXchgBool(&g_fShutdown, true); /* Set shutdown indicator. */
291 }
292 }
293
294 int rcThread;
295 RTTEST_CHECK_RC_OK(hTest, RTThreadWait(hThread, g_msRuntime, &rcThread));
296 RTTEST_CHECK_RC_OK(hTest, rcThread);
297
298 RTTEST_CHECK_RC_OK(hTest, ShClTransferHttpServerDestroy(&HttpSrv));
299 ShClTransferCtxDestroy(&TxCtx);
300
301 /*
302 * Summary
303 */
304 return RTTestSummaryAndDestroy(hTest);
305}
306
Note: See TracBrowser for help on using the repository browser.

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette