VirtualBox

Changeset 102141 in vbox for trunk/src


Ignore:
Timestamp:
Nov 17, 2023 3:27:32 PM (17 months ago)
Author:
vboxsync
svn:sync-xref-src-repo-rev:
160266
Message:

Shared Clipboard/Transfers: Implemented support for percent-encoded URLs for HTTP downloads. Extended testcase. bugref:9437

Location:
trunk/src/VBox/GuestHost/SharedClipboard
Files:
2 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/VBox/GuestHost/SharedClipboard/clipboard-transfers-http.cpp

    r102115 r102141  
    8686    SHCLOBJHANDLE       hObj;
    8787    /** The virtual path of the HTTP server's root directory for this transfer.
    88      *  Always has to start with a "/". */
     88     *  Always has to start with a "/". Unescaped. */
    8989    char                szPathVirtual[RTPATH_MAX];
    9090} SHCLHTTPSERVERTRANSFER;
     
    170170
    171171/**
     172 * Creates an URL from a given path, extended version.
     173 *
     174 * @returns VBox status code.
     175 * @retval  VERR_INVALID_PARAMETER if the path is not valid.
     176 * @param   pszPath             Path to create URL for.
     177 * @param   ppszURL             Where to return the allocated URL on success.
     178 * @param   pchScheme           Where to return the size of the full HTTP scheme including "://". Optional and can be NULL.
     179 *                              Right now this always is sizeof("http://").
     180 *
     181 * @note    The path is not checked on file system level.
     182 */
     183static int shClTransferHttpURLCreateFromPathEx(const char *pszPath, char **ppszURL, size_t *pchScheme)
     184{
     185    AssertRCReturn(ShClTransferValidatePath(pszPath, false /* fMustExist */), VERR_INVALID_PARAMETER);
     186
     187    int rc = VINF_SUCCESS;
     188
     189    const char   szScheme[] = "http://"; /** @todo For now we only support HTTP. */
     190    const size_t cchScheme  = strlen(szScheme);
     191
     192    char *pszURL = RTStrAPrintf2("%s%s", szScheme, pszPath);
     193    if (pszURL)
     194    {
     195        AssertReturn(strlen(pszURL) > cchScheme, VERR_INVALID_PARAMETER);
     196
     197        *ppszURL = pszURL;
     198        if (pchScheme)
     199            *pchScheme = cchScheme;
     200    }
     201    else
     202        rc = VERR_NO_MEMORY;
     203
     204    return rc;
     205}
     206
     207/**
     208 * Creates an URL from a given path.
     209 *
     210 * @returns VBox status code.
     211 * @retval  VERR_INVALID_PARAMETER if the path is not valid.
     212 * @param   pszPath             Path to create URL for.
     213 * @param   ppszURL             Where to return the allocated URL on success.
     214 *
     215 * @note    The path is not checked on file system level.
     216 */
     217static int shClTransferHttpURLCreateFromPath(const char *pszPath, char **ppszURL)
     218{
     219    return shClTransferHttpURLCreateFromPathEx(pszPath, ppszURL, NULL /* pchScheme */);
     220}
     221
     222/**
    172223 * Return the HTTP server transfer for a specific transfer ID.
    173224 *
     
    403454    AssertReturn(RTStrIsValidEncoding(pReq->pszUrl), VERR_INVALID_PARAMETER);
    404455
    405     size_t const cchUrl  = strlen(pReq->pszUrl);
    406     AssertReturn(cchUrl, VERR_INVALID_PARAMETER);
    407 
    408     int rc;
    409 
    410     /* For now we only know the transfer -- now we need to figure out the entry we want to serve. */
    411     PSHCLHTTPSERVERTRANSFER pSrvTx = (PSHCLHTTPSERVERTRANSFER)pReq->pvUser;
    412     if (pSrvTx)
    413     {
    414         size_t const cchBase = strlen(pSrvTx->szPathVirtual) + 1 /* Skip slash separating the base from the rest */;
    415         AssertReturn(cchUrl >= cchBase, VERR_INVALID_PARAMETER);
    416 
    417         SHCLOBJOPENCREATEPARMS openParms;
    418         rc = ShClTransferObjOpenParmsInit(&openParms);
    419         if (RT_SUCCESS(rc))
     456    LogRel2(("Shared Clipboard: HTTP query for '%s' ...\n", pReq->pszUrl));
     457
     458    char *pszUrl;
     459    int rc = shClTransferHttpURLCreateFromPath(pReq->pszUrl, &pszUrl);
     460    AssertRCReturn(rc, rc);
     461
     462    RTURIPARSED Parsed;
     463    rc = RTUriParse(pszUrl, &Parsed);
     464    if (RT_SUCCESS(rc))
     465    {
     466        char        *pszPath = RTUriParsedPath(pszUrl, &Parsed);
     467        size_t const cchPath = strlen(pszPath);
     468
     469        /* For now we only know the transfer -- now we need to figure out the entry we want to serve. */
     470        PSHCLHTTPSERVERTRANSFER pSrvTx = (PSHCLHTTPSERVERTRANSFER)pReq->pvUser;
     471        if (pSrvTx)
    420472        {
    421             openParms.fCreate = SHCL_OBJ_CF_ACCESS_READ
    422                               | SHCL_OBJ_CF_ACCESS_DENYWRITE;
    423 
    424             PSHCLTRANSFER pTx = pSrvTx->pTransfer;
    425             AssertPtr(pTx);
    426 
    427             rc = VERR_NOT_FOUND; /* Must find the matching root entry first. */
    428 
    429             uint64_t const cRoots = ShClTransferRootsCount(pTx);
    430             for (uint32_t i = 0; i < cRoots; i++)
     473            size_t const cchBase = strlen(pSrvTx->szPathVirtual) + 1 /* Skip slash separating the base from the rest */;
     474            AssertReturn(cchPath >= cchBase, VERR_INVALID_PARAMETER);
     475
     476            SHCLOBJOPENCREATEPARMS openParms;
     477            rc = ShClTransferObjOpenParmsInit(&openParms);
     478            if (RT_SUCCESS(rc))
    431479            {
    432                 PCSHCLLISTENTRY pEntry = ShClTransferRootsEntryGet(pTx, i);
    433                 AssertPtrBreakStmt(pEntry, rc = VERR_NOT_FOUND);
    434 
    435                 const char *pszName = pReq->pszUrl + cchBase;
    436 
    437                 Log3Func(("pReqUrl=%s -> pszName=%s vs. pEntry=%s\n", pReq->pszUrl, pszName, pEntry->pszName));
    438 
    439                 if (RTStrCmp(pEntry->pszName, pszName)) /* Case-sensitive! */
    440                     continue;
    441 
    442                 LogRel2(("Shared Clipboard: Querying HTTP transfer information for '%s' ...\n", pEntry->pszName));
    443 
    444                 rc = RTStrCopy(openParms.pszPath, openParms.cbPath, pEntry->pszName);
    445                 if (RT_SUCCESS(rc))
     480                openParms.fCreate = SHCL_OBJ_CF_ACCESS_READ
     481                                  | SHCL_OBJ_CF_ACCESS_DENYWRITE;
     482
     483                PSHCLTRANSFER pTx = pSrvTx->pTransfer;
     484                AssertPtr(pTx);
     485
     486                rc = VERR_NOT_FOUND; /* Must find the matching root entry first. */
     487
     488                uint64_t const cRoots = ShClTransferRootsCount(pTx);
     489                for (uint32_t i = 0; i < cRoots; i++)
    446490                {
    447                     rc = ShClTransferObjOpen(pTx, &openParms, &pSrvTx->hObj);
     491                    PCSHCLLISTENTRY pEntry = ShClTransferRootsEntryGet(pTx, i);
     492                    AssertPtrBreakStmt(pEntry, rc = VERR_NOT_FOUND);
     493
     494                    Log3Func(("pszPath=%s vs. pEntry=%s\n", pszPath, pEntry->pszName));
     495
     496                    if (RTStrCmp(pEntry->pszName, pszPath + cchBase)) /* Case-sensitive! */
     497                        continue;
     498
     499                    rc = RTStrCopy(openParms.pszPath, openParms.cbPath, pEntry->pszName);
    448500                    if (RT_SUCCESS(rc))
    449501                    {
    450                         rc = VERR_NOT_SUPPORTED; /* Play safe by default. */
    451 
    452                         if (   pEntry->fInfo & VBOX_SHCL_INFO_F_FSOBJINFO
    453                             && pEntry->cbInfo == sizeof(SHCLFSOBJINFO))
     502                        rc = ShClTransferObjOpen(pTx, &openParms, &pSrvTx->hObj);
     503                        if (RT_SUCCESS(rc))
    454504                        {
    455                             PCSHCLFSOBJINFO pSrcObjInfo = (PSHCLFSOBJINFO)pEntry->pvInfo;
    456 
    457                             LogFlowFunc(("pszName=%s, cbInfo=%RU32, fMode=%#x (type %#x)\n",
    458                                          pEntry->pszName, pEntry->cbInfo, pSrcObjInfo->Attr.fMode, (pSrcObjInfo->Attr.fMode & RTFS_TYPE_MASK)));
    459 
    460                             if (RTFS_IS_FILE(pSrcObjInfo->Attr.fMode))
     505                            rc = VERR_NOT_SUPPORTED; /* Play safe by default. */
     506
     507                            if (   pEntry->fInfo & VBOX_SHCL_INFO_F_FSOBJINFO
     508                                && pEntry->cbInfo == sizeof(SHCLFSOBJINFO))
    461509                            {
    462                                 memcpy(pObjInfo, pSrcObjInfo, sizeof(SHCLFSOBJINFO));
    463                                 rc = VINF_SUCCESS;
     510                                PCSHCLFSOBJINFO pSrcObjInfo = (PSHCLFSOBJINFO)pEntry->pvInfo;
     511
     512                                LogFlowFunc(("pszName=%s, cbInfo=%RU32, fMode=%#x (type %#x)\n",
     513                                             pEntry->pszName, pEntry->cbInfo, pSrcObjInfo->Attr.fMode, (pSrcObjInfo->Attr.fMode & RTFS_TYPE_MASK)));
     514
     515                                LogRel2(("Shared Clipboard: HTTP object info: fMode=%#x, cbObject=%zu\n", pSrcObjInfo->Attr.fMode, pSrcObjInfo->cbObject));
     516
     517                                if (RTFS_IS_FILE(pSrcObjInfo->Attr.fMode))
     518                                {
     519                                    memcpy(pObjInfo, pSrcObjInfo, sizeof(SHCLFSOBJINFO));
     520                                    rc = VINF_SUCCESS;
     521                                }
    464522                            }
     523                            else
     524                                LogRel2(("Shared Clipboard: Supplied entry information for '%s' not supported (fInfo=%#x, cbInfo=%RU32\n",
     525                                         pEntry->pszName, pEntry->fInfo, pEntry->cbInfo));
    465526                        }
    466                         else
    467                             LogRel2(("Shared Clipboard: Supplied entry information for '%s' not supported (fInfo=%#x, cbInfo=%RU32\n",
    468                                      pEntry->pszName, pEntry->fInfo, pEntry->cbInfo));
    469527                    }
     528
     529                    break;
    470530                }
    471531
    472                 break;
     532                ShClTransferObjOpenParmsDestroy(&openParms);
    473533            }
    474 
    475             ShClTransferObjOpenParmsDestroy(&openParms);
    476534        }
    477     }
    478     else
    479         rc = VERR_NOT_FOUND;
     535        else
     536            rc = VERR_NOT_FOUND;
     537    }
     538
     539    RTStrFree(pszUrl);
    480540
    481541    if (RT_FAILURE(rc))
     
    899959#ifdef VBOX_SHCL_DEBUG_HTTPSERVER
    900960# ifdef DEBUG_andy /** Too lazy to specify a different transfer ID for debugging. */
    901             ssize_t cch = RTStrAPrintf(&pszPath, "//transfer");
     961            ssize_t cch = RTStrAPrintf(&pszPath, "/transfer");
    902962# else
    903             ssize_t cch = RTStrAPrintf(&pszPath, "//transfer%RU16", pTransfer->State.uID);
     963            ssize_t cch = RTStrAPrintf(&pszPath, "/transfer%RU16", pTransfer->State.uID);
    904964# endif
    905965#else /* Release mode */
    906             ssize_t cch = RTStrAPrintf(&pszPath, "//%s/%s", SHCL_HTTPT_URL_NAMESPACE, szUuid);
     966            ssize_t cch = RTStrAPrintf(&pszPath, "/%s/%s", SHCL_HTTPT_URL_NAMESPACE, szUuid);
    907967#endif
    908968            AssertReturn(cch, VERR_NO_MEMORY);
    909969
    910             const char   szScheme[] = "http"; /** @todo For now we only support HTTP. */
    911             const size_t cchScheme  = strlen(szScheme) + 3 /* "://" */;
    912 
    913             char *pszURI = RTUriCreate(szScheme, NULL /* pszAuthority */, pszPath, NULL /* pszQuery */, NULL /* pszFragment */);
    914             if (pszURI)
     970            char  *pszURI;
     971            size_t cchScheme;
     972            rc = shClTransferHttpURLCreateFromPathEx(pszPath, &pszURI, &cchScheme);
     973            if (RT_SUCCESS(rc))
    915974            {
    916                 if (strlen(pszURI) >= cchScheme)
    917                 {
    918                     /* For the virtual path we only keep everything after the full scheme (e.g. "http://").
    919                      * The virtual path always has to start with a "/". */
    920                     if (RTStrPrintf2(pSrvTx->szPathVirtual, sizeof(pSrvTx->szPathVirtual), "/%s", pszURI + cchScheme) <= 0)
    921                         rc = VERR_BUFFER_OVERFLOW;
    922                 }
    923                 else
    924                     rc = VERR_INVALID_PARAMETER;
     975                /* For the virtual path we only keep everything after the full scheme (e.g. "http://").
     976                 * The virtual path always has to start with a "/". */
     977                if (RTStrPrintf2(pSrvTx->szPathVirtual, sizeof(pSrvTx->szPathVirtual), "%s", pszURI + cchScheme) <= 0)
     978                    rc = VERR_BUFFER_OVERFLOW;
    925979
    926980                RTStrFree(pszURI);
     
    11441198 * @param   idTransfer          Transfer ID to return the URL for.
    11451199 * @param   idxEntry            Index of transfer entry to return URL for.
     1200 *                              Specify UINT64_MAX to only return the base URL.
    11461201 */
    11471202char *ShClTransferHttpServerGetUrlA(PSHCLHTTPSERVER pSrv, SHCLTRANSFERID idTransfer, uint64_t idxEntry)
     
    11651220    char *pszUrl = NULL;
    11661221
    1167     /* For now this only supports root entries. */
    1168     PCSHCLLISTENTRY pEntry = ShClTransferRootsEntryGet(pTx, idxEntry);
    1169     if (pEntry)
    1170     {
    1171         AssertReturn(RTStrNLen(pSrvTx->szPathVirtual, RTPATH_MAX), NULL);
    1172         pszUrl = RTStrAPrintf2("%s:%RU16%s/%s", shClTransferHttpServerGetHost(pSrv), pSrv->uPort, pSrvTx->szPathVirtual, pEntry->pszName);
    1173         AssertPtr(pszUrl);
    1174     }
     1222    if (RT_LIKELY(idxEntry != UINT64_MAX))
     1223    {
     1224        /* For now this only supports root entries. */
     1225        PCSHCLLISTENTRY pEntry = ShClTransferRootsEntryGet(pTx, idxEntry);
     1226        if (pEntry)
     1227        {
     1228            AssertReturn(RTStrNLen(pSrvTx->szPathVirtual, RTPATH_MAX), NULL);
     1229            pszUrl = RTStrAPrintf2("%s:%RU16%s/%s", shClTransferHttpServerGetHost(pSrv), pSrv->uPort, pSrvTx->szPathVirtual, pEntry->pszName);
     1230        }
     1231    }
     1232    else /* Only return the base. */
     1233        pszUrl = RTStrAPrintf2("%s:%RU16%s", shClTransferHttpServerGetHost(pSrv), pSrv->uPort, pSrvTx->szPathVirtual);
    11751234
    11761235    shClTransferHttpServerUnlock(pSrv);
  • trunk/src/VBox/GuestHost/SharedClipboard/testcase/tstClipboardHttpServer.cpp

    r100679 r102141  
    5151static bool         g_fManual       = false;
    5252
     53/** Test files to handle + download.
     54 *  All files reside in a common temporary directory. */
     55static struct
     56{
     57    /** File name to serve via HTTP server. */
     58    const char *pszFileName;
     59    /** URL to use for downloading the file via RTHttp APIs. */
     60    const char *pszUrl;
     61    /** File allocation size.
     62     *  Specify UINT64_MAX for random size. */
     63    size_t      cbSize;
     64    /** Expected test result. */
     65    int         rc;
     66} g_aTests[] =
     67{
     68    "file1.txt",                          "file1.txt",                 UINT64_MAX, VINF_SUCCESS,
     69    /* Note: For RTHttpGetFile() the URL needs to be percent-encoded. */
     70    "file2 with spaces.txt",              "file2%20with%20spaces.txt", UINT64_MAX, VINF_SUCCESS,
     71    "bigfile.bin",                        "bigfile.bin",               _1G,        VINF_SUCCESS
     72};
    5373
    5474/* Worker thread for the HTTP server. */
     
    233253    }
    234254
    235     char szRandomTestFile[RTPATH_MAX] = { 0 };
    236 
    237     uint32_t const cTx = ShClTransferCtxGetTotalTransfers(&TxCtx);
    238     if (!cTx)
    239     {
    240         RTTEST_CHECK_RC_OK(hTest, RTPathTemp(szRandomTestFile, sizeof(szRandomTestFile)));
    241         RTTEST_CHECK_RC_OK(hTest, RTPathAppend(szRandomTestFile, sizeof(szRandomTestFile), "tstClipboardHttpServer-XXXXXX"));
    242         RTTEST_CHECK_RC_OK(hTest, RTFileCreateTemp(szRandomTestFile, 0600));
    243 
    244         size_t cbExist = RTRandU32Ex(0, _256M);
    245 
    246         RTTestPrintf(hTest, RTTESTLVL_ALWAYS, "Random test file (%zu bytes): %s\n", cbExist, szRandomTestFile);
    247 
    248         RTFILE hFile;
    249         rc = RTFileOpen(&hFile, szRandomTestFile, RTFILE_O_WRITE | RTFILE_O_CREATE_REPLACE | RTFILE_O_DENY_NONE);
     255    char szTempDir[RTPATH_MAX];
     256    RTTEST_CHECK_RC_OK(hTest, RTPathTemp(szTempDir, sizeof(szTempDir)));
     257    RTTEST_CHECK_RC_OK(hTest, RTPathAppend(szTempDir, sizeof(szTempDir), "tstClipboardHttpServer-XXXXXX"));
     258    RTTEST_CHECK_RC_OK(hTest, RTDirCreateTemp(szTempDir, 0700));
     259
     260    if (!g_fManual)
     261    {
     262        char szFilePath[RTPATH_MAX];
     263        for (size_t i = 0; i < RT_ELEMENTS(g_aTests); i++)
     264        {
     265            RTTEST_CHECK      (hTest, RTStrPrintf(szFilePath, sizeof(szFilePath),  szTempDir));
     266            RTTEST_CHECK_RC_OK(hTest, RTPathAppend(szFilePath, sizeof(szFilePath), g_aTests[i].pszFileName));
     267
     268            size_t cbSize =  g_aTests[i].cbSize == UINT64_MAX ? RTRandU32Ex(0, _256M) : g_aTests[i].cbSize;
     269
     270            RTTestPrintf(hTest, RTTESTLVL_ALWAYS, "Random test file (%zu bytes): %s\n", cbSize, szFilePath);
     271
     272            RTFILE hFile;
     273            rc = RTFileOpen(&hFile, szFilePath, RTFILE_O_WRITE | RTFILE_O_CREATE_REPLACE | RTFILE_O_DENY_NONE);
     274            if (RT_SUCCESS(rc))
     275            {
     276                uint8_t abBuf[_64K] = { 42 };
     277
     278                while (cbSize > 0)
     279                {
     280                    size_t cbToWrite = sizeof(abBuf);
     281                    if (cbToWrite > cbSize)
     282                        cbToWrite = cbSize;
     283                    rc = RTFileWrite(hFile, abBuf, cbToWrite, NULL);
     284                    if (RT_FAILURE(rc))
     285                    {
     286                        RTTestIFailed("RTFileWrite(%#x) -> %Rrc\n", cbToWrite, rc);
     287                        break;
     288                    }
     289                    cbSize -= cbToWrite;
     290                }
     291
     292                RTTESTI_CHECK_RC(RTFileClose(hFile), VINF_SUCCESS);
     293
     294                if (RT_SUCCESS(rc))
     295                    tstCreateTransferSingle(hTest, &TxCtx, &HttpSrv, szFilePath, &Provider);
     296            }
     297            else
     298                RTTestIFailed("RTFileOpen(%s) -> %Rrc\n", szFilePath, rc);
     299        }
     300    }
     301
     302    /* Don't bail out here to prevent cleaning up after ourselves on failure. */
     303    if (RTTestErrorCount(hTest) == 0)
     304    {
     305        /* Create  thread for our HTTP server. */
     306        RTTHREAD hThread;
     307        rc = RTThreadCreate(&hThread, tstSrvWorker, NULL, 0, RTTHREADTYPE_DEFAULT, RTTHREADFLAGS_WAITABLE,
     308                            "tstClpHttpSrv");
     309        RTTEST_CHECK_RC_OK(hTest, rc);
    250310        if (RT_SUCCESS(rc))
    251311        {
    252             uint8_t abBuf[_64K] = { 42 };
    253 
    254             while (cbExist > 0)
    255             {
    256                 size_t cbToWrite = sizeof(abBuf);
    257                 if (cbToWrite > cbExist)
    258                     cbToWrite = cbExist;
    259                 rc = RTFileWrite(hFile, abBuf, cbToWrite, NULL);
    260                 if (RT_FAILURE(rc))
     312            rc = RTThreadUserWait(hThread, RT_MS_30SEC);
     313            RTTEST_CHECK_RC_OK(hTest, rc);
     314        }
     315
     316        if (RT_SUCCESS(rc))
     317        {
     318            if (g_fManual)
     319            {
     320                uint32_t const cTx = ShClTransferCtxGetTotalTransfers(&TxCtx);
     321                for (uint32_t i = 0; i < cTx; i++)
    261322                {
    262                     RTTestIFailed("RTFileWrite(%#x) -> %Rrc\n", cbToWrite, rc);
    263                     break;
     323                    PSHCLTRANSFER pTx = ShClTransferCtxGetTransferByIndex(&TxCtx, i);
     324
     325                    uint16_t const uID    = ShClTransferGetID(pTx);
     326                    char          *pszURL = ShClTransferHttpServerGetUrlA(&HttpSrv, uID, 0 /* Entry index */);
     327                    RTTEST_CHECK(hTest, pszURL != NULL);
     328                    RTTestPrintf(hTest, RTTESTLVL_ALWAYS, "URL #%02RU32: %s\n", i, pszURL);
     329                    RTStrFree(pszURL);
    264330                }
    265                 cbExist -= cbToWrite;
    266             }
    267 
    268             RTTESTI_CHECK_RC(RTFileClose(hFile), VINF_SUCCESS);
    269 
    270             if (RT_SUCCESS(rc))
    271             {
    272                 tstCreateTransferSingle(hTest, &TxCtx, &HttpSrv, szRandomTestFile, &Provider);
    273             }
    274         }
    275         else
    276             RTTestIFailed("RTFileOpen(%s) -> %Rrc\n", szRandomTestFile, rc);
    277     }
    278 
    279     if (RTTestErrorCount(hTest))
    280         return RTTestSummaryAndDestroy(hTest);
    281 
    282     /* Create  thread for our HTTP server. */
    283     RTTHREAD hThread;
    284     rc = RTThreadCreate(&hThread, tstSrvWorker, NULL, 0, RTTHREADTYPE_DEFAULT, RTTHREADFLAGS_WAITABLE,
    285                         "tstClpHttpSrv");
    286     RTTEST_CHECK_RC_OK(hTest, rc);
    287     if (RT_SUCCESS(rc))
    288     {
    289         rc = RTThreadUserWait(hThread, RT_MS_30SEC);
    290         RTTEST_CHECK_RC_OK(hTest, rc);
    291     }
    292 
    293     if (RT_SUCCESS(rc))
    294     {
    295         if (g_fManual)
    296         {
    297             for (uint32_t i = 0; i < cTx; i++)
    298             {
    299                 PSHCLTRANSFER pTx = ShClTransferCtxGetTransferByIndex(&TxCtx, i);
    300 
    301                 uint16_t const uID    = ShClTransferGetID(pTx);
    302                 char          *pszURL = ShClTransferHttpServerGetUrlA(&HttpSrv, uID, 0 /* Entry index */);
    303                 RTTEST_CHECK(hTest, pszURL != NULL);
    304                 RTTestPrintf(hTest, RTTESTLVL_ALWAYS, "URL #%02RU32: %s\n", i, pszURL);
    305                 RTStrFree(pszURL);
    306             }
    307         }
    308         else /* Download all files to a temp file using our HTTP client. */
    309         {
    310             RTHTTP hClient;
    311             rc = RTHttpCreate(&hClient);
    312             if (RT_SUCCESS(rc))
    313             {
    314                 char szFileTemp[RTPATH_MAX];
    315                 RTTEST_CHECK_RC_OK(hTest, RTPathTemp(szFileTemp, sizeof(szFileTemp)));
    316                 RTTEST_CHECK_RC_OK(hTest, RTPathAppend(szFileTemp, sizeof(szFileTemp), "tstClipboardHttpServer-XXXXXX"));
    317                 RTTEST_CHECK_RC_OK(hTest, RTFileCreateTemp(szFileTemp, 0600));
    318 
    319                 for (unsigned a = 0; a < 3; a++) /* Repeat downloads to stress things. */
     331            }
     332            else /* Download all files to a temp file using our HTTP client. */
     333            {
     334                RTHTTP hClient;
     335                rc = RTHttpCreate(&hClient);
     336                if (RT_SUCCESS(rc))
    320337                {
    321                     for (uint32_t i = 0; i < ShClTransferCtxGetTotalTransfers(&TxCtx); i++)
     338                    char szURL[RTPATH_MAX];
     339                    for (size_t i = 0; i < RT_ELEMENTS(g_aTests); i++)
    322340                    {
    323341                        PSHCLTRANSFER pTx = ShClTransferCtxGetTransferByIndex(&TxCtx, i);
    324 
    325                         uint16_t const uID    = ShClTransferGetID(pTx);
    326                         char          *pszURL = ShClTransferHttpServerGetUrlA(&HttpSrv, uID, 0 /* Entry index */);
    327                         RTTEST_CHECK(hTest, pszURL != NULL);
    328                         RTTestPrintf(hTest, RTTESTLVL_ALWAYS, "Downloading: %s -> %s\n", pszURL, szFileTemp);
    329                         RTTEST_CHECK_RC_BREAK(hTest, RTHttpGetFile(hClient, pszURL, szFileTemp), VINF_SUCCESS);
    330                         RTStrFree(pszURL);
     342                        char *pszUrlBase  = ShClTransferHttpServerGetUrlA(&HttpSrv, ShClTransferGetID(pTx), UINT64_MAX);
     343
     344                        RTTEST_CHECK(hTest, RTStrPrintf2(szURL, sizeof(szURL), "%s/%s", pszUrlBase, g_aTests[i].pszUrl));
     345
     346                        RTStrFree(pszUrlBase);
     347
     348                        char szTempFile[RTPATH_MAX];
     349                        RTTEST_CHECK_RC_OK(hTest, RTPathTemp(szTempFile, sizeof(szTempFile)));
     350                        RTTEST_CHECK_RC_OK(hTest, RTPathAppend(szTempFile, sizeof(szTempFile), "tstClipboardHttpServer-XXXXXX"));
     351                        RTTEST_CHECK_RC_OK(hTest, RTFileCreateTemp(szTempFile, 0600));
     352
     353                        RTTestPrintf(hTest, RTTESTLVL_ALWAYS, "Downloading '%s' -> '%s'\n", szURL, szTempFile);
     354
     355                        RTTEST_CHECK_RC_OK(hTest, RTHttpGetFile(hClient, szURL, szTempFile));
     356
     357                        RTTEST_CHECK_RC_OK(hTest, RTFileDelete(szTempFile));
    331358                    }
     359
     360                    RTTEST_CHECK_RC_OK(hTest, RTHttpDestroy(hClient));
    332361                }
    333362
    334                 RTTEST_CHECK_RC_OK(hTest, RTFileDelete(szFileTemp));
    335                 RTTEST_CHECK_RC_OK(hTest, RTHttpDestroy(hClient));
    336             }
    337 
    338             /* This is supposed to run unattended, so shutdown automatically. */
    339             ASMAtomicXchgBool(&g_fShutdown, true); /* Set shutdown indicator. */
    340         }
    341     }
    342 
    343     int rcThread;
    344     RTTEST_CHECK_RC_OK(hTest, RTThreadWait(hThread, g_msRuntime, &rcThread));
    345     RTTEST_CHECK_RC_OK(hTest, rcThread);
    346 
    347     RTTEST_CHECK_RC_OK(hTest, ShClTransferHttpServerDestroy(&HttpSrv));
    348     ShClTransferCtxDestroy(&TxCtx);
    349 
    350     if (strlen(szRandomTestFile))
    351         RTTEST_CHECK_RC_OK(hTest, RTFileDelete(szRandomTestFile));
     363                /* This is supposed to run unattended, so shutdown automatically. */
     364                ASMAtomicXchgBool(&g_fShutdown, true); /* Set shutdown indicator. */
     365            }
     366        }
     367
     368        int rcThread;
     369        RTTEST_CHECK_RC_OK(hTest, RTThreadWait(hThread, g_msRuntime, &rcThread));
     370        RTTEST_CHECK_RC_OK(hTest, rcThread);
     371
     372        RTTEST_CHECK_RC_OK(hTest, ShClTransferHttpServerDestroy(&HttpSrv));
     373        ShClTransferCtxDestroy(&TxCtx);
     374    }
     375
     376    /*
     377     * Cleanup
     378     */
     379    char szFilePath[RTPATH_MAX];
     380    for (size_t i = 0; i < RT_ELEMENTS(g_aTests); i++)
     381    {
     382        RTTEST_CHECK      (hTest, RTStrPrintf(szFilePath, sizeof(szFilePath), szTempDir));
     383        RTTEST_CHECK_RC_OK(hTest, RTPathAppend(szFilePath, sizeof(szFilePath), g_aTests[i].pszFileName));
     384        RTTEST_CHECK_RC_OK(hTest, RTFileDelete(szFilePath));
     385    }
     386    RTTEST_CHECK_RC_OK(hTest, RTDirRemove(szTempDir));
    352387
    353388    /*
Note: See TracChangeset for help on using the changeset viewer.

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