VirtualBox

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

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

Shared Clipboard: Unified root list entry code to also use the generic list entry code, a lot of updates for the cross OS transfer handling code, more updates for HTTP server transfer handling.

This also changed the handling of how that transfers are being initiated, as we needed to have this for X11: Before, transfers were initiated as soon as on side announced the URI list format -- now we postpone initiating the transfer until the receiving side requests the data as URI list.

bugref:9437

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 10.2 KB
Line 
1/* $Id: tstClipboardHttpServer.cpp 100204 2023-06-19 09:11:37Z 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 RTTEST_CHECK(hTest, ShClTransferHttpServerIsRunning(&HttpSrv) == false);
179 if (uPort)
180 rc = ShClTransferHttpServerStartEx(&HttpSrv, uPort);
181 else
182 rc = ShClTransferHttpServerStart(&HttpSrv, 32 /* cMaxAttempts */, &uPort);
183 RTTEST_CHECK_RC_OK(hTest, rc);
184 RTTEST_CHECK(hTest, ShClTransferHttpServerGetTransfer(&HttpSrv, 0) == false);
185 RTTEST_CHECK(hTest, ShClTransferHttpServerGetTransfer(&HttpSrv, 42) == false);
186
187 char *pszSrvAddr = ShClTransferHttpServerGetAddressA(&HttpSrv);
188 RTTEST_CHECK(hTest, pszSrvAddr != NULL);
189 RTTestPrintf(hTest, RTTESTLVL_ALWAYS, "HTTP server running: %s (for %RU32ms) ...\n", pszSrvAddr, g_msRuntime);
190 RTMemFree(pszSrvAddr);
191 pszSrvAddr = NULL;
192
193 SHCLTRANSFERCTX TxCtx;
194 RTTEST_CHECK_RC_OK(hTest, ShClTransferCtxInit(&TxCtx));
195
196 /* Parse options again, but this time we only fetch all files we want to serve.
197 * Only can be done after we initialized the HTTP server above. */
198 RT_ZERO(GetState);
199 rc = RTGetOptInit(&GetState, argc, argv, aOpts, RT_ELEMENTS(aOpts), 1 /*idxFirst*/, 0 /*fFlags - must not sort! */);
200 AssertRCReturn(rc, RTEXITCODE_INIT);
201 while ((ch = RTGetOpt(&GetState, &ValueUnion)) != 0)
202 {
203 switch (ch)
204 {
205 case VINF_GETOPT_NOT_OPTION:
206 {
207 PSHCLTRANSFER pTx;
208 RTTEST_CHECK_RC_OK(hTest, ShClTransferCreate(&pTx));
209 RTTEST_CHECK_RC_OK(hTest, ShClTransferInit(pTx, SHCLTRANSFERDIR_TO_REMOTE, SHCLSOURCE_LOCAL));
210 RTTEST_CHECK_RC_OK(hTest, ShClTransferRootsInitFromFile(pTx, ValueUnion.psz));
211 RTTEST_CHECK_RC_OK(hTest, ShClTransferCtxTransferRegister(&TxCtx, pTx, NULL));
212 RTTEST_CHECK_RC_OK(hTest, ShClTransferHttpServerRegisterTransfer(&HttpSrv, pTx));
213 break;
214 }
215
216 default:
217 continue;
218 }
219 }
220
221 uint32_t const cTx = ShClTransferCtxGetTotalTransfers(&TxCtx);
222 if (!cTx)
223 return RTMsgErrorExit(RTEXITCODE_SYNTAX, "No files to serve specified!\n");
224
225 /* Create thread for our HTTP server. */
226 RTTHREAD hThread;
227 rc = RTThreadCreate(&hThread, tstSrvWorker, NULL, 0, RTTHREADTYPE_DEFAULT, RTTHREADFLAGS_WAITABLE,
228 "tstClpHttpSrv");
229 RTTEST_CHECK_RC_OK(hTest, rc);
230 if (RT_SUCCESS(rc))
231 {
232 rc = RTThreadUserWait(hThread, RT_MS_30SEC);
233 RTTEST_CHECK_RC_OK(hTest, rc);
234 }
235
236
237 if (RT_SUCCESS(rc))
238 {
239 if (g_fManual)
240 {
241 for (uint32_t i = 0; i < cTx; i++)
242 {
243 PSHCLTRANSFER pTx = ShClTransferCtxGetTransferByIndex(&TxCtx, i);
244
245 uint16_t const uID = ShClTransferGetID(pTx);
246 char *pszURL = ShClTransferHttpServerGetUrlA(&HttpSrv, uID);
247 RTTEST_CHECK(hTest, pszURL != NULL);
248 RTTestPrintf(hTest, RTTESTLVL_ALWAYS, "URL #%02RU32: %s\n", i, pszURL);
249 RTStrFree(pszURL);
250 }
251 }
252 else /* Download all files to a temp file using our HTTP client. */
253 {
254 RTHTTP hClient;
255 rc = RTHttpCreate(&hClient);
256 if (RT_SUCCESS(rc))
257 {
258 char szFileTemp[RTPATH_MAX];
259 RTTEST_CHECK_RC_OK(hTest, RTPathTemp(szFileTemp, sizeof(szFileTemp)));
260 RTTEST_CHECK_RC_OK(hTest, RTPathAppend(szFileTemp, sizeof(szFileTemp), "tstClipboardHttpServer-XXXXXX"));
261 RTTEST_CHECK_RC_OK(hTest, RTFileCreateTemp(szFileTemp, 0600));
262
263 for (unsigned a = 0; a < 3; a++) /* Repeat downloads to stress things. */
264 {
265 for (uint32_t i = 0; i < cTx; i++)
266 {
267 PSHCLTRANSFER pTx = ShClTransferCtxGetTransferByIndex(&TxCtx, i);
268
269 uint16_t const uID = ShClTransferGetID(pTx);
270 char *pszURL = ShClTransferHttpServerGetUrlA(&HttpSrv, uID);
271 RTTEST_CHECK(hTest, pszURL != NULL);
272 RTTestPrintf(hTest, RTTESTLVL_ALWAYS, "Downloading: %s -> %s\n", pszURL, szFileTemp);
273 RTTEST_CHECK_RC_BREAK(hTest, RTHttpGetFile(hClient, pszURL, szFileTemp), VINF_SUCCESS);
274 RTStrFree(pszURL);
275 }
276 }
277
278 RTTEST_CHECK_RC_OK(hTest, RTFileDelete(szFileTemp));
279 RTTEST_CHECK_RC_OK(hTest, RTHttpDestroy(hClient));
280 }
281
282 /* This is supposed to run unattended, so shutdown automatically. */
283 ASMAtomicXchgBool(&g_fShutdown, true); /* Set shutdown indicator. */
284 }
285 }
286
287 int rcThread;
288 RTTEST_CHECK_RC_OK(hTest, RTThreadWait(hThread, g_msRuntime, &rcThread));
289 RTTEST_CHECK_RC_OK(hTest, rcThread);
290
291 RTTEST_CHECK_RC_OK(hTest, ShClTransferHttpServerDestroy(&HttpSrv));
292 ShClTransferCtxDestroy(&TxCtx);
293
294 /*
295 * Summary
296 */
297 return RTTestSummaryAndDestroy(hTest);
298}
299
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