VirtualBox

Changeset 87032 in vbox


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

Location:
trunk
Files:
6 edited

Legend:

Unmodified
Added
Removed
  • trunk/include/iprt/http-common.h

    r87010 r87032  
    4848    RTHTTPMETHOD_OPTIONS,
    4949    RTHTTPMETHOD_TRACE,
     50#ifdef RTHTTP_WITH_WEBDAV
     51    RTHTTPMETHOD_PROPFIND,
     52#endif
    5053    RTHTTPMETHOD_END,
    5154    RTHTTPMETHOD_32BIT_HACK = 0x7fffffff
  • trunk/include/iprt/http-server.h

    r87016 r87032  
    125125     * @returns VBox status code.
    126126     * @param   pData           Pointer to HTTP callback data.
    127      * @param   pszUrl          URL to handle.
     127     * @param   pReq            Pointer to request to handle.
    128128     * @param   ppvHandle       Where to return the pointer to the opaque handle used for object identification.
    129129     */
    130     DECLCALLBACKMEMBER(int, pfnOpen,(PRTHTTPCALLBACKDATA pData, const char *pszUrl, void **ppvHandle));
     130    DECLCALLBACKMEMBER(int, pfnOpen,(PRTHTTPCALLBACKDATA pData, PRTHTTPSERVERREQ pReq, void **ppvHandle));
    131131    /**
    132132     * Called when a given URL will be retrieved by the GET method.
     
    137137     * @returns VBox status code.
    138138     * @param   pData           Pointer to HTTP callback data.
     139     * @param   pvHandle        Opaque handle for object identification.
     140     * @param   pvBuf           Pointer to buffer where to store the read data.
     141     * @param   cbBuf           Size (in bytes) of the buffer where to store the read data.
     142     * @param   pcbRead         Where to return the amount (in bytes) of read data. Optional and can be NULL.
     143     */
     144    DECLCALLBACKMEMBER(int, pfnRead,(PRTHTTPCALLBACKDATA pData, void *pvHandle, void *pvBuf, size_t cbBuf, size_t *pcbRead));
     145    /**
     146     * Called when a given URL is done retrieving by the GET method.
     147     *
     148     * Note: High level function, not being called when pfnOnGetRequest is implemented.
     149     *
     150     * @returns VBox status code.
     151     * @param   pData           Pointer to HTTP callback data.
    139152     * @param   pszUrl          URL to handle.
    140153     * @param   pvHandle        Opaque handle for object identification.
    141154     */
    142     DECLCALLBACKMEMBER(int, pfnRead,(PRTHTTPCALLBACKDATA pData, void *pvHandle, void *pvBuf, size_t cbBuf, size_t *pcbRead));
    143     /**
    144      * Called when a given URL is done retrieving by the GET method.
    145      *
    146      * Note: High level function, not being called when pfnOnGetRequest is implemented.
    147      *
    148      * @returns VBox status code.
    149      * @param   pData           Pointer to HTTP callback data.
    150      * @param   pszUrl          URL to handle.
    151      * @param   pvHandle        Opaque handle for object identification.
    152      */
    153155    DECLCALLBACKMEMBER(int, pfnClose,(PRTHTTPCALLBACKDATA pData, void *pvHandle));
    154156    /**
     
    159161     * @returns VBox status code.
    160162     * @param   pData           Pointer to HTTP callback data.
    161      * @param   pszUrl          URL to query information for.
     163     * @param   pReq            Pointer to request to handle.
    162164     * @param   pObjInfo        Where to store the queried file information on success.
    163165     * @param   ppszMIMEHint    Where to return an allocated MIME type hint on success.
    164166     *                          Must be free'd by the caller using RTStrFree().
    165167     */
    166     DECLCALLBACKMEMBER(int, pfnQueryInfo,(PRTHTTPCALLBACKDATA pData, const char *pszUrl, PRTFSOBJINFO pObjInfo, char **ppszMIMEHint));
     168    DECLCALLBACKMEMBER(int, pfnQueryInfo,(PRTHTTPCALLBACKDATA pData, PRTHTTPSERVERREQ pReq, PRTFSOBJINFO pObjInfo, char **ppszMIMEHint));
    167169    /**
    168170     * Low-level handler for a GET method request.
     
    181183     */
    182184    DECLCALLBACKMEMBER(int, pfnOnHeadRequest,(PRTHTTPCALLBACKDATA pData, PRTHTTPSERVERREQ pReq));
     185    /**
     186     * Called before the HTTP server will be destroyed.
     187     *
     188     * @returns VBox status code.
     189     * @param   pData           Pointer to HTTP callback data.
     190     */
     191    DECLCALLBACKMEMBER(int, pfnDestroy,(PRTHTTPCALLBACKDATA pData));
    183192} RTHTTPSERVERCALLBACKS;
    184193/** Pointer to a HTTP server callback data table. */
    185194typedef RTHTTPSERVERCALLBACKS *PRTHTTPSERVERCALLBACKS;
    186195
    187 /** Maximum length (in bytes) a client request can have. */
     196/** Maximum length (in bytes) a single client request can have. */
    188197#define RTHTTPSERVER_MAX_REQ_LEN        _8K
    189198
  • trunk/src/VBox/Runtime/generic/http-curl.cpp

    r87004 r87032  
    23962396        case RTHTTPMETHOD_OPTIONS:  pszMethodSp = "options "; break;
    23972397        case RTHTTPMETHOD_TRACE:    pszMethodSp = "trace "; break;
     2398#ifdef RTHTTP_WITH_WEBDAV
     2399        case RTHTTPMETHOD_PROPFIND: pszMethodSp = "propfind "; break;
     2400#endif
    23982401        /* no default! */
    23992402        case RTHTTPMETHOD_INVALID:
     
    37343737                rcCurl = curl_easy_setopt(pThis->pCurl, CURLOPT_CUSTOMREQUEST, "TRACE");
    37353738                break;
     3739#ifdef RTHTTP_WITH_WEBDAV
     3740            case RTHTTPMETHOD_PROPFIND:
     3741                RT_FALL_THROUGH();
     3742#endif
    37363743            case RTHTTPMETHOD_END:
    37373744            case RTHTTPMETHOD_INVALID:
  • trunk/src/VBox/Runtime/generic/http.cpp

    r87010 r87032  
    104104        case RTHTTPMETHOD_OPTIONS:  return "OPTIONS";
    105105        case RTHTTPMETHOD_TRACE:    return "TRACE";
    106 
     106#ifdef RTHTTP_WITH_WEBDAV
     107        case RTHTTPMETHOD_PROPFIND: return "PROPFIND";
     108#endif
    107109        case RTHTTPMETHOD_END:
    108110            RT_FALL_THROUGH();
  • trunk/src/VBox/Runtime/r3/http-server.cpp

    r87029 r87032  
    1414 * - No IPv6 support.
    1515 * - No multi-threading.
     16 *
     17 * For WebDAV (optional via RTHTTP_WITH_WEBDAV):
     18 * - Only OPTIONS + PROPLIST methods are implemented (e.g. simple read-only support).
     19 * - No pagination support for directory listings.
    1620 */
    1721
     
    132136            rc = pCallbacks->a_Name(&Data); \
    133137        } \
    134         else \
    135             rc = VERR_NOT_IMPLEMENTED; \
    136138    } while (0)
    137139
     
    146148            rc = pCallbacks->a_Name(&Data, __VA_ARGS__); \
    147149        } \
    148         else \
    149             rc = VERR_NOT_IMPLEMENTED; \
    150150    } while (0)
    151151
     
    256256 * @{
    257257 */
    258 static FNRTHTTPSERVERMETHOD rtHttpServerHandleGET;
    259 static FNRTHTTPSERVERMETHOD rtHttpServerHandleHEAD;
     258static FNRTHTTPSERVERMETHOD  rtHttpServerHandleGET;
     259static FNRTHTTPSERVERMETHOD  rtHttpServerHandleHEAD;
     260#ifdef RTHTTP_WITH_WEBDAV
     261 static FNRTHTTPSERVERMETHOD rtHttpServerHandleOPTIONS;
     262 static FNRTHTTPSERVERMETHOD rtHttpServerHandlePROPFIND;
     263#endif
    260264/** @} */
    261265
     
    283287static const RTHTTPSERVERMETHOD_ENTRY g_aMethodMap[] =
    284288{
    285     { RTHTTPMETHOD_GET,  rtHttpServerHandleGET },
    286     { RTHTTPMETHOD_HEAD, rtHttpServerHandleHEAD },
     289    { RTHTTPMETHOD_GET,      rtHttpServerHandleGET },
     290    { RTHTTPMETHOD_HEAD,     rtHttpServerHandleHEAD },
     291#ifdef RTHTTP_WITH_WEBDAV
     292    { RTHTTPMETHOD_OPTIONS,  rtHttpServerHandleOPTIONS },
     293    { RTHTTPMETHOD_PROPFIND, rtHttpServerHandlePROPFIND },
     294#endif
    287295    { RTHTTPMETHOD_END,  NULL }
    288296};
     
    518526    AssertRCReturn(rc, rc);
    519527
     528#ifdef RTHTTP_WITH_WEBDAV
     529    rc = RTHttpHeaderListAdd(HdrLst, "Allow", "GET, HEAD, PROPFIND", strlen("GET, HEAD, PROPFIND"), RTHTTPHEADERLISTADD_F_BACK);
     530    AssertRCReturn(rc, rc);
     531    rc = RTHttpHeaderListAdd(HdrLst, "DAV", "1", strlen("1"), RTHTTPHEADERLISTADD_F_BACK); /* Note: v1 is sufficient for read-only access. */
     532    AssertRCReturn(rc, rc);
     533#endif
     534
    520535    char *pszHdr = NULL;
    521536
     
    621636        case VERR_INVALID_POINTER:      return RTHTTPSTATUS_BADREQUEST;
    622637        case VERR_NOT_IMPLEMENTED:      return RTHTTPSTATUS_NOTIMPLEMENTED;
     638        case VERR_NOT_SUPPORTED:        return RTHTTPSTATUS_NOTIMPLEMENTED;
    623639        case VERR_PATH_NOT_FOUND:       return RTHTTPSTATUS_NOTFOUND;
    624640        case VERR_FILE_NOT_FOUND:       return RTHTTPSTATUS_NOTFOUND;
     
    649665    LogFlowFuncEnter();
    650666
    651     int rc;
     667    int rc = VINF_SUCCESS;
    652668
    653669    /* If a low-level GET request handler is defined, call it and return. */
     
    659675    char *pszMIMEHint = NULL;
    660676
    661     RTHTTPSERVER_HANDLE_CALLBACK_VA(pfnQueryInfo, pReq->pszUrl, &fsObj, &pszMIMEHint);
     677    RTHTTPSERVER_HANDLE_CALLBACK_VA(pfnQueryInfo, pReq, &fsObj, &pszMIMEHint);
    662678    if (RT_FAILURE(rc))
    663679        return rc;
    664680
    665681    void *pvHandle = NULL;
    666     RTHTTPSERVER_HANDLE_CALLBACK_VA(pfnOpen, pReq->pszUrl, &pvHandle);
     682    RTHTTPSERVER_HANDLE_CALLBACK_VA(pfnOpen, pReq, &pvHandle);
    667683
    668684    if (RT_SUCCESS(rc))
     
    761777    RTHTTPSERVER_HANDLE_CALLBACK_VA_RET(pfnOnHeadRequest, pReq);
    762778
    763     int rc;
     779    int rc = VINF_SUCCESS;
    764780
    765781    RTFSOBJINFO fsObj;
    766782    RT_ZERO(fsObj); /* Shut up MSVC. */
    767783
    768     char *pszMIMEHint = NULL;
    769 
    770     RTHTTPSERVER_HANDLE_CALLBACK_VA(pfnQueryInfo, pReq->pszUrl, &fsObj, &pszMIMEHint);
     784    RTHTTPSERVER_HANDLE_CALLBACK_VA(pfnQueryInfo, pReq, &fsObj, NULL /* pszMIMEHint */);
    771785    if (RT_SUCCESS(rc))
    772786    {
     
    805819    return rc;
    806820}
     821
     822#ifdef RTHTTP_WITH_WEBDAV
     823/**
     824 * Handler for the OPTIONS method.
     825 *
     826 * @returns VBox status code.
     827 * @param   pClient             Client to handle OPTIONS method for.
     828 * @param   pReq                Client request to handle.
     829 */
     830static DECLCALLBACK(int) rtHttpServerHandleOPTIONS(PRTHTTPSERVERCLIENT pClient, PRTHTTPSERVERREQ pReq)
     831{
     832    LogFlowFuncEnter();
     833
     834    RT_NOREF(pReq);
     835
     836    int rc = rtHttpServerSendResponseEx(pClient, RTHTTPSTATUS_OK, NULL /* pHdrLst */);
     837
     838    LogFlowFuncLeaveRC(rc);
     839    return rc;
     840}
     841
     842/**
     843 * Handler for the PROPFIND (WebDAV) method.
     844 *
     845 * @returns VBox status code.
     846 * @param   pClient             Client to handle PROPFIND method for.
     847 * @param   pReq                Client request to handle.
     848 */
     849static DECLCALLBACK(int) rtHttpServerHandlePROPFIND(PRTHTTPSERVERCLIENT pClient, PRTHTTPSERVERREQ pReq)
     850{
     851    LogFlowFuncEnter();
     852
     853    int rc = VINF_SUCCESS;
     854
     855    /* If a low-level GET request handler is defined, call it and return. */
     856    RTHTTPSERVER_HANDLE_CALLBACK_VA_RET(pfnOnGetRequest, pReq);
     857
     858    RTFSOBJINFO fsObj;
     859    RT_ZERO(fsObj); /* Shut up MSVC. */
     860
     861    RTHTTPSERVER_HANDLE_CALLBACK_VA(pfnQueryInfo, pReq, &fsObj, NULL /* pszMIMEHint */);
     862    if (RT_FAILURE(rc))
     863        return rc;
     864
     865    void *pvHandle = NULL;
     866    RTHTTPSERVER_HANDLE_CALLBACK_VA(pfnOpen, pReq, &pvHandle);
     867
     868    if (RT_SUCCESS(rc))
     869    {
     870        size_t cbBuf = _64K;
     871        void  *pvBuf = RTMemAlloc(cbBuf);
     872        AssertPtrReturn(pvBuf, VERR_NO_MEMORY);
     873
     874        for (;;)
     875        {
     876            RTHTTPHEADERLIST HdrLst;
     877            rc = RTHttpHeaderListInit(&HdrLst);
     878            AssertRCReturn(rc, rc);
     879
     880            char szVal[16];
     881
     882            rc = RTHttpHeaderListAdd(HdrLst, "Content-Type", "text/xml; charset=utf-8", strlen("text/xml; charset=utf-8"), RTHTTPHEADERLISTADD_F_BACK);
     883            AssertRCBreak(rc);
     884
     885            /* Note: For directories fsObj.cbObject contains the actual size (in bytes)
     886             *       of the body data for the directory listing. */
     887
     888            ssize_t cch = RTStrPrintf2(szVal, sizeof(szVal), "%RU64", fsObj.cbObject);
     889            AssertBreakStmt(cch, VERR_BUFFER_OVERFLOW);
     890            rc = RTHttpHeaderListAdd(HdrLst, "Content-Length", szVal, strlen(szVal), RTHTTPHEADERLISTADD_F_BACK);
     891            AssertRCBreak(rc);
     892
     893            rc = rtHttpServerSendResponseEx(pClient, RTHTTPSTATUS_MULTISTATUS, &HdrLst);
     894            AssertRCReturn(rc, rc);
     895
     896            RTHttpHeaderListDestroy(HdrLst);
     897
     898            size_t cbToRead  = fsObj.cbObject;
     899            size_t cbRead    = 0; /* Shut up GCC. */
     900            size_t cbWritten = 0; /* Ditto. */
     901            while (cbToRead)
     902            {
     903                RTHTTPSERVER_HANDLE_CALLBACK_VA(pfnRead, pvHandle, pvBuf, RT_MIN(cbBuf, cbToRead), &cbRead);
     904                if (RT_FAILURE(rc))
     905                    break;
     906                rtHttpServerLogProto(pClient, true /* fWrite */, (const char *)pvBuf);
     907                rc = rtHttpServerSendResponseBody(pClient, pvBuf, cbRead, &cbWritten);
     908                AssertBreak(cbToRead >= cbWritten);
     909                cbToRead -= cbWritten;
     910                if (rc == VERR_NET_CONNECTION_RESET_BY_PEER) /* Clients often apruptly abort the connection when done. */
     911                {
     912                    rc = VINF_SUCCESS;
     913                    break;
     914                }
     915                AssertRCBreak(rc);
     916            }
     917
     918            break;
     919        } /* for (;;) */
     920
     921        RTMemFree(pvBuf);
     922
     923        int rc2 = rc; /* Save rc. */
     924
     925        RTHTTPSERVER_HANDLE_CALLBACK_VA(pfnClose, pvHandle);
     926
     927        if (RT_FAILURE(rc2)) /* Restore original rc on failure. */
     928            rc = rc2;
     929    }
     930
     931    LogFlowFuncLeaveRC(rc);
     932    return rc;
     933}
     934#endif /* RTHTTP_WITH_WEBDAV */
    807935
    808936/**
     
    9121040
    9131041    /* Note: Method names are case sensitive. */
    914     if      (!RTStrCmp(pszReq, "GET"))  pReq->enmMethod = RTHTTPMETHOD_GET;
    915     else if (!RTStrCmp(pszReq, "HEAD")) pReq->enmMethod = RTHTTPMETHOD_HEAD;
     1042    if      (!RTStrCmp(pszReq, "GET"))      pReq->enmMethod = RTHTTPMETHOD_GET;
     1043    else if (!RTStrCmp(pszReq, "HEAD"))     pReq->enmMethod = RTHTTPMETHOD_HEAD;
     1044#ifdef RTHTTP_WITH_WEBDAV
     1045    else if (!RTStrCmp(pszReq, "OPTIONS"))  pReq->enmMethod = RTHTTPMETHOD_OPTIONS;
     1046    else if (!RTStrCmp(pszReq, "PROPFIND")) pReq->enmMethod = RTHTTPMETHOD_PROPFIND;
     1047#endif
    9161048    else
    9171049        return VERR_NOT_SUPPORTED;
     
    11221254    AssertPtr(pThis->pTCPServer);
    11231255
    1124     int rc = RTTcpServerDestroy(pThis->pTCPServer);
     1256    int rc = VINF_SUCCESS;
     1257
     1258    PRTHTTPSERVERCALLBACKS pCallbacks = &pThis->Callbacks;
     1259    if (pCallbacks->pfnDestroy)
     1260    {
     1261        RTHTTPCALLBACKDATA Data = { NULL /* pClient */, pThis->pvUser, pThis->cbUser };
     1262        rc = pCallbacks->pfnDestroy(&Data);
     1263    }
     1264
    11251265    if (RT_SUCCESS(rc))
    11261266    {
    1127         pThis->u32Magic = RTHTTPSERVER_MAGIC_DEAD;
    1128 
    1129         RTMemFree(pThis);
    1130     }
    1131 
    1132     return rc;
    1133 }
     1267        rc = RTTcpServerDestroy(pThis->pTCPServer);
     1268        if (RT_SUCCESS(rc))
     1269        {
     1270            pThis->u32Magic = RTHTTPSERVER_MAGIC_DEAD;
     1271
     1272            RTMemFree(pThis);
     1273        }
     1274    }
     1275
     1276    return rc;
     1277}
  • 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