VirtualBox

Changeset 87032 in vbox for trunk/src/VBox/Runtime/tools


Ignore:
Timestamp:
Dec 2, 2020 4:33:29 PM (4 years ago)
Author:
vboxsync
svn:sync-xref-src-repo-rev:
141673
Message:

Shared Clipboard/Transfers: Added initial directory listing support via WebDAV (needs RTHTTP_WITH_WEBDAV, experimental). bugref:9874

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/VBox/Runtime/tools/RTHttpServer.cpp

    r87018 r87032  
    4949#include <iprt/getopt.h>
    5050#include <iprt/initterm.h>
     51#define LOG_GROUP RTLOGGROUP_HTTP
     52#include <iprt/log.h>
    5153#include <iprt/mem.h>
    5254#include <iprt/message.h>
     
    286288                    continue;
    287289            }
    288             else if (rc != VERR_NO_MORE_FILES)
     290            else
    289291                break;
    290292        }
     
    309311}
    310312
    311 static int dirEntryWrite(char *pszBuf, size_t cbBuf,
    312                          const char *pszEntry, const PRTFSOBJINFO pObjInfo, size_t *pcbWritten)
    313 {
     313#ifdef RTHTTP_WITH_WEBDAV
     314static int dirEntryWriteDAV(char *pszBuf, size_t cbBuf,
     315                            const char *pszEntry, const PRTFSOBJINFO pObjInfo, size_t *pcbWritten)
     316{
     317    char szBirthTime[32];
     318    if (RTTimeSpecToString(&pObjInfo->BirthTime, szBirthTime, sizeof(szBirthTime)) == NULL)
     319        return VERR_BUFFER_UNDERFLOW;
     320
    314321    char szModTime[32];
    315322    if (RTTimeSpecToString(&pObjInfo->ModificationTime, szModTime, sizeof(szModTime)) == NULL)
     
    318325    int rc = VINF_SUCCESS;
    319326
    320     ssize_t cch = RTStrPrintf2(pszBuf, cbBuf, "201: %s %RU64 %s %s\r\n",
    321                                pszEntry, pObjInfo->cbObject, szModTime,
    322                                /** @todo Very crude; only files and directories are supported for now. */
    323                                RTFS_IS_FILE(pObjInfo->Attr.fMode) ? "FILE" : "DIRECTORY");
     327    /**
     328     * !!! HACK ALERT !!!
     329     ** @todo Build up and use a real XML DOM here. Works with Gnome / Gvfs-compatible apps though.
     330     */
     331    ssize_t cch = RTStrPrintf(pszBuf, cbBuf,
     332"<d:response>"
     333"<d:href>%s</d:href>"
     334"<d:propstat>"
     335"<d:status>HTTP/1.1 200 OK</d:status>"
     336"<d:prop>"
     337"<d:displayname>%s</d:displayname>"
     338"<d:getcontentlength>%RU64</d:getcontentlength>"
     339"<d:getcontenttype>%s</d:getcontenttype>"
     340"<d:creationdate>%s</d:creationdate>"
     341"<d:getlastmodified>%s</d:getlastmodified>"
     342"<d:getetag/>"
     343"<d:resourcetype><d:collection/></d:resourcetype>"
     344"</d:prop>"
     345"</d:propstat>"
     346"</d:response>",
     347                        pszEntry, pszEntry, pObjInfo->cbObject, "application/octet-stream", szBirthTime, szModTime);
     348
    324349    if (cch <= 0)
    325350        rc = VERR_BUFFER_OVERFLOW;
     351
     352    *pcbWritten = cch;
     353
     354    return rc;
     355}
     356#endif /* RTHTTP_WITH_WEBDAV */
     357
     358static int dirEntryWrite(RTHTTPMETHOD enmMethod, char *pszBuf, size_t cbBuf,
     359                         const char *pszEntry, const PRTFSOBJINFO pObjInfo, size_t *pcbWritten)
     360{
     361    char szModTime[32];
     362    if (RTTimeSpecToString(&pObjInfo->ModificationTime, szModTime, sizeof(szModTime)) == NULL)
     363        return VERR_BUFFER_UNDERFLOW;
     364
     365    int rc = VINF_SUCCESS;
     366
     367    ssize_t cch = 0;
     368
     369    if (enmMethod == RTHTTPMETHOD_GET)
     370    {
     371        cch = RTStrPrintf2(pszBuf, cbBuf, "201: %s %RU64 %s %s\r\n",
     372                           pszEntry, pObjInfo->cbObject, szModTime,
     373                           /** @todo Very crude; only files and directories are supported for now. */
     374                           RTFS_IS_FILE(pObjInfo->Attr.fMode) ? "FILE" : "DIRECTORY");
     375        if (cch <= 0)
     376            rc = VERR_BUFFER_OVERFLOW;
     377    }
     378#ifdef RTHTTP_WITH_WEBDAV
     379    else if (enmMethod == RTHTTPMETHOD_PROPFIND)
     380    {
     381        char szBuf[RTPATH_MAX + _4K]; /** @todo Just a rough guesstimate. */
     382        rc = dirEntryWriteDAV(szBuf, sizeof(szBuf), pszEntry, pObjInfo, (size_t *)&cch);
     383        if (RT_SUCCESS(rc))
     384            rc = RTStrCat(pszBuf, cbBuf, szBuf);
     385        AssertRC(rc);
     386    }
     387#endif /* RTHTTP_WITH_WEBDAV */
     388    else
     389        rc = VERR_NOT_SUPPORTED;
    326390
    327391    if (RT_SUCCESS(rc))
     
    361425}
    362426
    363 DECLCALLBACK(int) onOpen(PRTHTTPCALLBACKDATA pData, const char *pszUrl, void **ppvHandle)
     427DECLCALLBACK(int) onOpen(PRTHTTPCALLBACKDATA pData, PRTHTTPSERVERREQ pReq, void **ppvHandle)
    364428{
    365429    PHTTPSERVERDATA pThis = (PHTTPSERVERDATA)pData->pvUser;
     
    367431
    368432    char *pszPathAbs = NULL;
    369     int rc = pathResolve(pThis, pszUrl, &pszPathAbs);
     433    int rc = pathResolve(pThis, pReq->pszUrl, &pszPathAbs);
    370434    if (RT_SUCCESS(rc))
    371435    {
     
    395459        RTStrFree(pszPathAbs);
    396460    }
     461
     462    LogFlowFuncLeaveRC(rc);
    397463    return rc;
    398464}
     
    404470
    405471    AssertReturn(*(uint64_t *)pvHandle == 42 /** @todo Fudge. */, VERR_NOT_FOUND);
     472
     473    int rc;
    406474
    407475    if (RTFS_IS_DIRECTORY(pThis->fMode))
     
    416484        *pcbRead = cbToCopy;
    417485
    418         return VINF_SUCCESS;
     486        rc = VINF_SUCCESS;
    419487    }
    420488    else if (RTFS_IS_FILE(pThis->fMode))
    421         return RTFileRead(pThis->h.File, pvBuf, cbBuf, pcbRead);
    422 
    423     return VERR_NOT_IMPLEMENTED; /* Never reached. */
     489    {
     490        rc = RTFileRead(pThis->h.File, pvBuf, cbBuf, pcbRead);
     491    }
     492    else
     493        rc = VERR_NOT_SUPPORTED;
     494
     495    LogFlowFuncLeaveRC(rc);
     496    return rc;
    424497}
    425498
     
    445518    pvHandle = NULL;
    446519
     520    LogFlowFuncLeaveRC(rc);
    447521    return rc;
    448522}
    449523
    450524DECLCALLBACK(int) onQueryInfo(PRTHTTPCALLBACKDATA pData,
    451                               const char *pszUrl, PRTFSOBJINFO pObjInfo, char **ppszMIMEHint)
     525                              PRTHTTPSERVERREQ pReq, PRTFSOBJINFO pObjInfo, char **ppszMIMEHint)
    452526{
    453527    PHTTPSERVERDATA pThis = (PHTTPSERVERDATA)pData->pvUser;
    454528    Assert(pData->cbUser == sizeof(HTTPSERVERDATA));
    455529
     530    /** !!!! WARNING !!!
     531     **
     532     ** Not production-ready code below!
     533     ** @todo Use something like bodyAdd() instead of the RTStrPrintf2() hacks.
     534     **
     535     ** !!!! WARNING !!! */
     536
    456537    char *pszPathAbs = NULL;
    457     int rc = pathResolve(pThis, pszUrl, &pszPathAbs);
     538    int rc = pathResolve(pThis, pReq->pszUrl, &pszPathAbs);
    458539    if (RT_SUCCESS(rc))
    459540    {
     
    471552                {
    472553                    RTHttpServerResponseDestroy(pResp);
    473                     RTHttpServerResponseInitEx(pResp, _4K);
     554                    RTHttpServerResponseInitEx(pResp, _64K); /** @todo Make this more dynamic. */
     555
     556                    char  *pszBody    = (char *)pResp->pvBody;
     557                    size_t cbBodyLeft = pResp->cbBodyAlloc;
    474558
    475559                    /*
    476560                     * Write body header.
    477561                     */
    478                     ssize_t cch = RTStrPrintf2((char *)pResp->pvBody, pResp->cbBodyAlloc,
    479                                                "300: file://%s\r\n"
    480                                                "200: filename content-length last-modified file-type\r\n",
    481                                                pszUrl);
    482                     RT_NOREF(cch);
    483                     Assert(cch);
    484 
    485                     pResp->cbBodyUsed = strlen((char *)pResp->pvBody);
    486 
     562                    if (pReq->enmMethod == RTHTTPMETHOD_GET)
     563                    {
     564                        ssize_t cch = RTStrPrintf2(pszBody, cbBodyLeft,
     565                                                   "300: file://%s\r\n"
     566                                                   "200: filename content-length last-modified file-type\r\n",
     567                                                   pReq->pszUrl);
     568                        Assert(cch);
     569                        pszBody    += cch;
     570                        cbBodyLeft -= cch;
     571                    }
     572#ifdef RTHTTP_WITH_WEBDAV
     573                    else if (pReq->enmMethod == RTHTTPMETHOD_PROPFIND)
     574                    {
     575                        ssize_t cch = RTStrPrintf2(pszBody, cbBodyLeft, "<?xml version=\"1.0\" encoding=\"utf-8\"?>\r\n");
     576                        Assert(cch);
     577                        pszBody    += cch;
     578                        cbBodyLeft -= cch;
     579
     580                        cch = RTStrPrintf2(pszBody, cbBodyLeft, "<d:multistatus xmlns:d=\"DAV:\">\r\n");
     581                        Assert(cch);
     582                        pszBody    += cch;
     583                        cbBodyLeft -= cch;
     584
     585                        rc = dirEntryWriteDAV(pszBody, cbBodyLeft, "/", &objInfo, (size_t *)&cch);
     586                        AssertRC(rc);
     587                        pszBody    += cch;
     588                        cbBodyLeft -= cch;
     589                    }
     590#endif /* RTHTTP_WITH_WEBDAV */
    487591                    /*
    488592                     * Write body entries.
     
    492596                    while (RT_SUCCESS(rc = dirRead(hVfsDir, &pszEntry, &fsObjInfo)))
    493597                    {
    494                         char *pszBody = (char *)pResp->pvBody;
    495 
    496                         size_t cbWritten;
    497                         rc = dirEntryWrite(&pszBody[pResp->cbBodyUsed], pResp->cbBodyAlloc - pResp->cbBodyUsed, pszEntry, &fsObjInfo, &cbWritten);
     598                        size_t cbWritten = 0;
     599                        rc = dirEntryWrite(pReq->enmMethod, pszBody, cbBodyLeft, pszEntry, &fsObjInfo, &cbWritten);
    498600                        if (rc == VERR_BUFFER_OVERFLOW)
    499601                        {
    500                             pResp->cbBodyAlloc *= 2; /** @todo Improve this. */
     602                            pResp->cbBodyAlloc += _4K; /** @todo Improve this. */
    501603                            pResp->pvBody       = RTMemRealloc(pResp->pvBody, pResp->cbBodyAlloc);
    502604                            AssertPtrBreakStmt(pResp->pvBody, rc = VERR_NO_MEMORY);
    503605
    504606                            pszBody = (char *)pResp->pvBody;
    505 
    506                             rc = dirEntryWrite(&pszBody[pResp->cbBodyUsed], pResp->cbBodyAlloc - pResp->cbBodyUsed, pszEntry, &fsObjInfo, &cbWritten);
     607                            cbBodyLeft += _4K; /** @todo Ditto. */
     608
     609                            rc = dirEntryWrite(pReq->enmMethod, pszBody, cbBodyLeft, pszEntry, &fsObjInfo, &cbWritten);
    507610                        }
    508611
    509                         if (RT_SUCCESS(rc))
    510                             pResp->cbBodyUsed += cbWritten;
     612                        if (   RT_SUCCESS(rc)
     613                            && cbWritten)
     614                        {
     615                            pszBody    += cbWritten;
     616                            Assert(cbBodyLeft > cbWritten);
     617                            cbBodyLeft -= cbWritten;
     618                        }
    511619
    512620                        RTStrFree(pszEntry);
     
    521629                    dirClose(hVfsDir);
    522630
     631                    /*
     632                     * Write footers, if any.
     633                     */
    523634                    if (RT_SUCCESS(rc))
    524635                    {
    525                         rc = RTStrAPrintf(ppszMIMEHint, "text/plain");
    526                         if (RT_SUCCESS(rc))
    527                             pObjInfo->cbObject = pResp->cbBodyUsed;
     636                        if (pReq->enmMethod == RTHTTPMETHOD_GET)
     637                        {
     638                            if (ppszMIMEHint)
     639                                rc = RTStrAPrintf(ppszMIMEHint, "text/plain");
     640                        }
     641#ifdef RTHTTP_WITH_WEBDAV
     642                        else if (pReq->enmMethod == RTHTTPMETHOD_PROPFIND)
     643                        {
     644                            /**
     645                             * !!! HACK ALERT !!!
     646                             ** @todo Build up and use a real XML DOM here. Works with Gnome / Gvfs-compatible apps though.
     647                             */
     648                            ssize_t cch = RTStrPrintf2(pszBody, cbBodyLeft, "</d:multistatus>\r\n");
     649                            Assert(cch);
     650                            RT_NOREF(cch);
     651                        }
     652#endif /* RTHTTP_WITH_WEBDAV */
     653
     654                        pResp->cbBodyUsed = strlen((char *)pResp->pvBody);
     655
     656                        pObjInfo->cbObject = pResp->cbBodyUsed;
    528657                    }
    529658                }
     
    541670                }
    542671            }
     672            else
     673                rc = VERR_NOT_SUPPORTED;
    543674        }
    544675
     
    546677    }
    547678
     679    LogFlowFuncLeaveRC(rc);
    548680    return rc;
     681}
     682
     683DECLCALLBACK(int) onDestroy(PRTHTTPCALLBACKDATA pData)
     684{
     685    PHTTPSERVERDATA pThis = (PHTTPSERVERDATA)pData->pvUser;
     686    Assert(pData->cbUser == sizeof(HTTPSERVERDATA));
     687
     688    RTHttpServerResponseDestroy(&pThis->Resp);
     689
     690    return VINF_SUCCESS;
    549691}
    550692
     
    650792        Callbacks.pfnClose         = onClose;
    651793        Callbacks.pfnQueryInfo     = onQueryInfo;
     794        Callbacks.pfnDestroy       = onDestroy;
    652795
    653796        g_HttpServerData.h.File = NIL_RTFILE;
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