Changeset 87016 in vbox for trunk/src/VBox
- Timestamp:
- Nov 30, 2020 4:45:54 PM (4 years ago)
- svn:sync-xref-src-repo-rev:
- 141597
- Location:
- trunk/src/VBox/Runtime
- Files:
-
- 2 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/Runtime/r3/http-server.cpp
r87013 r87016 160 160 return pCallbacks->a_Name(&Data, __VA_ARGS__); \ 161 161 } \ 162 return VERR_NOT_IMPLEMENTED; \163 162 } while (0) 164 163 … … 355 354 } 356 355 356 /** 357 * Initializes a HTTP server response with an allocated body size. 358 * 359 * @returns VBox status code. 360 * @param pResp HTTP server response to initialize. 361 * @param cbBody Body size (in bytes) to allocate. 362 */ 363 RTR3DECL(int) RTHttpServerResponseInitEx(PRTHTTPSERVERRESP pResp, size_t cbBody) 364 { 365 pResp->enmSts = RTHTTPSTATUS_INTERNAL_NOT_SET; 366 367 int rc = RTHttpHeaderListInit(&pResp->hHdrLst); 368 AssertRCReturn(rc, rc); 369 370 if (cbBody) 371 { 372 pResp->pvBody = RTMemAlloc(cbBody); 373 AssertPtrReturn(pResp->pvBody, VERR_NO_MEMORY); 374 pResp->cbBodyAlloc = cbBody; 375 } 376 else 377 { 378 pResp->cbBodyAlloc = 0; 379 } 380 381 pResp->cbBodyUsed = 0; 382 383 return rc; 384 } 385 386 /** 387 * Initializes a HTTP server response. 388 * 389 * @returns VBox status code. 390 * @param pResp HTTP server response to initialize. 391 */ 392 RTR3DECL(int) RTHttpServerResponseInit(PRTHTTPSERVERRESP pResp) 393 { 394 return RTHttpServerResponseInitEx(pResp, 0 /* cbBody */); 395 } 396 397 /** 398 * Destroys a formerly initialized HTTP server response. 399 * 400 * @param pResp Pointer to HTTP server response to destroy. 401 */ 402 RTR3DECL(void) RTHttpServerResponseDestroy(PRTHTTPSERVERRESP pResp) 403 { 404 if (!pResp) 405 return; 406 407 pResp->enmSts = RTHTTPSTATUS_INTERNAL_NOT_SET; 408 409 RTHttpHeaderListDestroy(pResp->hHdrLst); 410 411 if (pResp->pvBody) 412 { 413 Assert(pResp->cbBodyAlloc); 414 415 RTMemFree(pResp->pvBody); 416 pResp->pvBody = NULL; 417 } 418 419 pResp->cbBodyAlloc = 0; 420 pResp->cbBodyUsed = 0; 421 } 422 357 423 358 424 /********************************************************************************************************************************* … … 522 588 int rc; 523 589 590 /* If a low-level GET request handler is defined, call it and return. */ 591 RTHTTPSERVER_HANDLE_CALLBACK_VA_RET(pfnOnGetRequest, pReq); 592 524 593 RTFSOBJINFO fsObj; 525 594 RT_ZERO(fsObj); /* Shut up MSVC. */ 526 RTHTTPSERVER_HANDLE_CALLBACK_VA(pfnQueryInfo, pReq->pszUrl, &fsObj); 595 596 char *pszMIMEHint = NULL; 597 598 RTHTTPSERVER_HANDLE_CALLBACK_VA(pfnQueryInfo, pReq->pszUrl, &fsObj, &pszMIMEHint); 527 599 if (RT_FAILURE(rc)) 528 600 return rc; 529 601 530 uint64_t uID = 0; /* Ditto. */531 RTHTTPSERVER_HANDLE_CALLBACK_VA(pfnOpen, pReq->pszUrl, & uID);602 void *pvHandle; 603 RTHTTPSERVER_HANDLE_CALLBACK_VA(pfnOpen, pReq->pszUrl, &pvHandle); 532 604 533 605 if (RT_SUCCESS(rc)) … … 545 617 char szVal[16]; 546 618 619 /* Note: For directories fsObj.cbObject contains the actual size (in bytes) 620 * of the body data for the directory listing. */ 621 547 622 ssize_t cch = RTStrPrintf2(szVal, sizeof(szVal), "%RU64", fsObj.cbObject); 548 623 AssertBreakStmt(cch, VERR_BUFFER_OVERFLOW); … … 555 630 AssertRCBreak(rc); 556 631 557 const char *pszMIME = rtHttpServerGuessMIMEType(RTPathSuffix(pReq->pszUrl)); 558 rc = RTHttpHeaderListAdd(HdrLst, "Content-Type", pszMIME, strlen(pszMIME), RTHTTPHEADERLISTADD_F_BACK); 632 if (pszMIMEHint == NULL) 633 { 634 const char *pszMIME = rtHttpServerGuessMIMEType(RTPathSuffix(pReq->pszUrl)); 635 rc = RTHttpHeaderListAdd(HdrLst, "Content-Type", pszMIME, strlen(pszMIME), RTHTTPHEADERLISTADD_F_BACK); 636 } 637 else 638 { 639 rc = RTHttpHeaderListAdd(HdrLst, "Content-Type", pszMIMEHint, strlen(pszMIMEHint), RTHTTPHEADERLISTADD_F_BACK); 640 RTStrFree(pszMIMEHint); 641 pszMIMEHint = NULL; 642 } 559 643 AssertRCReturn(rc, rc); 560 644 … … 569 653 while (cbToRead) 570 654 { 571 RTHTTPSERVER_HANDLE_CALLBACK_VA(pfnRead, uID, pvBuf, RT_MIN(cbBuf, cbToRead), &cbRead);655 RTHTTPSERVER_HANDLE_CALLBACK_VA(pfnRead, pvHandle, pvBuf, RT_MIN(cbBuf, cbToRead), &cbRead); 572 656 if (RT_FAILURE(rc)) 573 657 break; … … 590 674 int rc2 = rc; /* Save rc. */ 591 675 592 RTHTTPSERVER_HANDLE_CALLBACK_VA(pfnClose, uID);676 RTHTTPSERVER_HANDLE_CALLBACK_VA(pfnClose, pvHandle); 593 677 594 678 if (RT_FAILURE(rc2)) /* Restore original rc on failure. */ … … 611 695 LogFlowFuncEnter(); 612 696 697 /* If a low-level HEAD request handler is defined, call it and return. */ 698 RTHTTPSERVER_HANDLE_CALLBACK_VA_RET(pfnOnHeadRequest, pReq); 699 613 700 int rc; 614 701 615 702 RTFSOBJINFO fsObj; 616 703 RT_ZERO(fsObj); /* Shut up MSVC. */ 617 RTHTTPSERVER_HANDLE_CALLBACK_VA(pfnQueryInfo, pReq->pszUrl, &fsObj); 704 705 char *pszMIMEHint = NULL; 706 707 RTHTTPSERVER_HANDLE_CALLBACK_VA(pfnQueryInfo, pReq->pszUrl, &fsObj, &pszMIMEHint); 618 708 if (RT_SUCCESS(rc)) 619 709 { -
trunk/src/VBox/Runtime/tools/RTHttpServer.cpp
r87004 r87016 69 69 /** The absolute path of the HTTP server's root directory. */ 70 70 char szPathRootAbs[RTPATH_MAX]; 71 /** The relative current working directory (CWD) to szRootDir. */ 72 char szCWD[RTPATH_MAX]; 71 RTFMODE fMode; 73 72 union 74 73 { 75 RTFILE File;76 RT DIR Dir;74 RTFILE File; 75 RTVFSDIR Dir; 77 76 } h; 77 /** Cached response data. */ 78 RTHTTPSERVERRESP Resp; 78 79 } HTTPSERVERDATA; 79 80 typedef HTTPSERVERDATA *PHTTPSERVERDATA; … … 289 290 } 290 291 292 /* Skip dot directories. */ 293 if (RTDirEntryExIsStdDotLink(pDirEntry)) 294 continue; 295 291 296 *ppszEntry = RTStrDup(pDirEntry->szName); 292 297 AssertPtrReturn(*ppszEntry, VERR_NO_MEMORY); … … 305 310 306 311 static int dirEntryWrite(char *pszBuf, size_t cbBuf, 307 const char *pszEntry, const PRTFSOBJINFO pInfo, size_t *pcbWritten) 308 { 309 RT_NOREF(pInfo); 310 311 ssize_t cch = RTStrPrintf2(pszBuf, cbBuf, "201: %s\r\n", pszEntry); 312 const char *pszEntry, const PRTFSOBJINFO pObjInfo, size_t *pcbWritten) 313 { 314 char szModTime[32]; 315 if (RTTimeSpecToString(&pObjInfo->ModificationTime, szModTime, sizeof(szModTime)) == NULL) 316 return VERR_BUFFER_UNDERFLOW; 317 318 int rc = VINF_SUCCESS; 319 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"); 312 324 if (cch <= 0) 313 return VERR_BUFFER_OVERFLOW; 314 315 /* 316 Content-type: 317 Last-Modified: 318 Content-Length: 319 */ 320 321 *pcbWritten = (size_t)cch; 322 323 return VINF_SUCCESS; 324 } 325 326 static DECLCALLBACK(int) onGetRequest(PRTHTTPCALLBACKDATA pData, PRTHTTPSERVERREQ pReq) 327 { 328 PHTTPSERVERDATA pThis = (PHTTPSERVERDATA)pData->pvUser; 329 Assert(pData->cbUser == sizeof(HTTPSERVERDATA)); 330 331 /* Construct absolute path. */ 332 char *pszPathAbs = NULL; 333 if (RTStrAPrintf(&pszPathAbs, "%s/%s", pThis->szPathRootAbs, pReq->pszUrl) <= 0) 334 return VERR_NO_MEMORY; 335 336 RTVFSDIR hVfsDir; 337 int rc = dirOpen(pszPathAbs, &hVfsDir); 325 rc = VERR_BUFFER_OVERFLOW; 326 338 327 if (RT_SUCCESS(rc)) 339 328 { 340 pReq->pvBody = RTMemAlloc(_4K); 341 AssertPtrReturn(pReq->pvBody, VERR_NO_MEMORY); /** @todo Leaks stuff. */ 342 pReq->cbBodyAlloc = _4K; 343 pReq->cbBodyUsed = 0; 344 345 char *pszEntry = NULL; 346 RTFSOBJINFO fsObjInfo; 347 348 while (RT_SUCCESS(rc = dirRead(hVfsDir, &pszEntry, &fsObjInfo))) 349 { 350 char *pszBody = (char *)pReq->pvBody; 351 352 size_t cbWritten; 353 rc = dirEntryWrite(&pszBody[pReq->cbBodyUsed], pReq->cbBodyAlloc - pReq->cbBodyUsed, pszEntry, &fsObjInfo, &cbWritten); 354 if (rc == VERR_BUFFER_OVERFLOW) 355 { 356 pReq->cbBodyAlloc *= 2; /** @todo Improve this. */ 357 pReq->pvBody = RTMemRealloc(pReq->pvBody, pReq->cbBodyAlloc); 358 AssertPtrBreakStmt(pReq->pvBody, rc = VERR_NO_MEMORY); 359 360 pszBody = (char *)pReq->pvBody; 361 362 rc = dirEntryWrite(&pszBody[pReq->cbBodyUsed], pReq->cbBodyAlloc - pReq->cbBodyUsed, pszEntry, &fsObjInfo, &cbWritten); 363 } 364 365 if (RT_SUCCESS(rc)) 366 pReq->cbBodyUsed += cbWritten; 367 368 RTStrFree(pszEntry); 369 370 if (RT_FAILURE(rc)) 371 break; 372 } 373 374 if (rc == VERR_NO_MORE_FILES) /* All entries consumed? */ 375 rc = VINF_SUCCESS; 376 377 dirClose(hVfsDir); 378 } 379 380 RTStrFree(pszPathAbs); 329 *pcbWritten = (size_t)cch; 330 } 331 381 332 return rc; 382 333 } 383 334 384 static DECLCALLBACK(int) onHeadRequest(PRTHTTPCALLBACKDATA pData, PRTHTTPSERVERREQ pReq) 385 { 386 RT_NOREF(pData, pReq); 387 388 return VINF_SUCCESS; 389 } 390 391 DECLCALLBACK(int) onOpen(PRTHTTPCALLBACKDATA pData, const char *pszUrl, uint64_t *pidObj) 392 { 393 PHTTPSERVERDATA pThis = (PHTTPSERVERDATA)pData->pvUser; 394 Assert(pData->cbUser == sizeof(HTTPSERVERDATA)); 395 335 /** 336 * Resolves (and validates) a given URL to an absolute (local) path. 337 * 338 * @returns VBox status code. 339 * @param pThis HTTP server instance data. 340 * @param pszUrl URL to resolve. 341 * @param ppszPathAbs Where to store the resolved absolute path on success. 342 * Needs to be free'd with RTStrFree(). 343 */ 344 static int pathResolve(PHTTPSERVERDATA pThis, const char *pszUrl, char **ppszPathAbs) 345 { 396 346 /* Construct absolute path. */ 397 347 char *pszPathAbs = NULL; … … 399 349 return VERR_NO_MEMORY; 400 350 401 int rc = RTFileOpen(&pThis->h.File, pszPathAbs, 402 RTFILE_O_READ | RTFILE_O_OPEN | RTFILE_O_DENY_WRITE); 403 if (RT_SUCCESS(rc)) 404 *pidObj = 42; 405 406 RTStrFree(pszPathAbs); 407 return rc; 408 } 409 410 DECLCALLBACK(int) onRead(PRTHTTPCALLBACKDATA pData, uint64_t idObj, void *pvBuf, size_t cbBuf, size_t *pcbRead) 351 #ifdef VBOX_STRICT 352 RTFSOBJINFO objInfo; 353 int rc2 = RTPathQueryInfo(pszPathAbs, &objInfo, RTFSOBJATTRADD_NOTHING); 354 AssertRCReturn(rc, rc); 355 AssertReturn(!RTFS_IS_SYMLINK(objInfo.Attr.fMode), VERR_NOT_SUPPORTED); 356 #endif 357 358 *ppszPathAbs = pszPathAbs; 359 360 return VINF_SUCCESS; 361 } 362 363 DECLCALLBACK(int) onOpen(PRTHTTPCALLBACKDATA pData, const char *pszUrl, void **ppvHandle) 411 364 { 412 365 PHTTPSERVERDATA pThis = (PHTTPSERVERDATA)pData->pvUser; 413 366 Assert(pData->cbUser == sizeof(HTTPSERVERDATA)); 414 367 415 AssertReturn(idObj == 42, VERR_NOT_FOUND); 416 417 return RTFileRead(pThis->h.File, pvBuf, cbBuf, pcbRead); 418 } 419 420 DECLCALLBACK(int) onClose(PRTHTTPCALLBACKDATA pData, uint64_t idObj) 368 char *pszPathAbs = NULL; 369 int rc = pathResolve(pThis, pszUrl, &pszPathAbs); 370 if (RT_SUCCESS(rc)) 371 { 372 RTFSOBJINFO objInfo; 373 rc = RTPathQueryInfo(pszPathAbs, &objInfo, RTFSOBJATTRADD_NOTHING); 374 AssertRCReturn(rc, rc); 375 if (RTFS_IS_DIRECTORY(objInfo.Attr.fMode)) 376 { 377 /* Nothing to do here; 378 * The directory listing has been cached already in onQueryInfo(). */ 379 } 380 else if (RTFS_IS_FILE(objInfo.Attr.fMode)) 381 { 382 rc = RTFileOpen(&pThis->h.File, pszPathAbs, 383 RTFILE_O_READ | RTFILE_O_OPEN | RTFILE_O_DENY_WRITE); 384 } 385 386 if (RT_SUCCESS(rc)) 387 { 388 pThis->fMode = objInfo.Attr.fMode; 389 390 uint64_t *puHandle = (uint64_t *)RTMemAlloc(sizeof(uint64_t)); 391 *puHandle = 42; /** @todo Fudge. */ 392 *ppvHandle = puHandle; 393 } 394 395 RTStrFree(pszPathAbs); 396 } 397 return rc; 398 } 399 400 DECLCALLBACK(int) onRead(PRTHTTPCALLBACKDATA pData, void *pvHandle, void *pvBuf, size_t cbBuf, size_t *pcbRead) 421 401 { 422 402 PHTTPSERVERDATA pThis = (PHTTPSERVERDATA)pData->pvUser; 423 403 Assert(pData->cbUser == sizeof(HTTPSERVERDATA)); 424 404 425 AssertReturn(idObj == 42, VERR_NOT_FOUND); 426 427 int rc = RTFileClose(pThis->h.File); 428 if (RT_SUCCESS(rc)) 429 pThis->h.File = NIL_RTFILE; 430 431 return rc; 432 } 433 434 DECLCALLBACK(int) onQueryInfo(PRTHTTPCALLBACKDATA pData, const char *pszUrl, PRTFSOBJINFO pObjInfo) 405 AssertReturn(*(uint64_t *)pvHandle == 42 /** @todo Fudge. */, VERR_NOT_FOUND); 406 407 if (RTFS_IS_DIRECTORY(pThis->fMode)) 408 { 409 PRTHTTPSERVERRESP pResp = &pThis->Resp; 410 411 const size_t cbToCopy = RT_MIN(cbBuf, pResp->cbBodyUsed); 412 memcpy(pvBuf, pResp->pvBody, cbToCopy); 413 Assert(pResp->cbBodyUsed >= cbToCopy); 414 pResp->cbBodyUsed -= cbToCopy; 415 416 *pcbRead = cbToCopy; 417 418 return VINF_SUCCESS; 419 } 420 else if (RTFS_IS_FILE(pThis->fMode)) 421 return RTFileRead(pThis->h.File, pvBuf, cbBuf, pcbRead); 422 423 return VERR_NOT_IMPLEMENTED; /* Never reached. */ 424 } 425 426 DECLCALLBACK(int) onClose(PRTHTTPCALLBACKDATA pData, void *pvHandle) 435 427 { 436 428 PHTTPSERVERDATA pThis = (PHTTPSERVERDATA)pData->pvUser; 437 429 Assert(pData->cbUser == sizeof(HTTPSERVERDATA)); 438 430 439 /* Construct absolute path. */ 431 AssertReturn(*(uint64_t *)pvHandle == 42 /** @todo Fudge. */, VERR_NOT_FOUND); 432 433 int rc; 434 435 if (RTFS_IS_FILE(pThis->fMode)) 436 { 437 rc = RTFileClose(pThis->h.File); 438 if (RT_SUCCESS(rc)) 439 pThis->h.File = NIL_RTFILE; 440 } 441 else 442 rc = VINF_SUCCESS; 443 444 RTMemFree(pvHandle); 445 pvHandle = NULL; 446 447 return rc; 448 } 449 450 DECLCALLBACK(int) onQueryInfo(PRTHTTPCALLBACKDATA pData, 451 const char *pszUrl, PRTFSOBJINFO pObjInfo, char **ppszMIMEHint) 452 { 453 PHTTPSERVERDATA pThis = (PHTTPSERVERDATA)pData->pvUser; 454 Assert(pData->cbUser == sizeof(HTTPSERVERDATA)); 455 440 456 char *pszPathAbs = NULL; 441 if (RTStrAPrintf(&pszPathAbs, "%s/%s", pThis->szPathRootAbs, pszUrl) <= 0) 442 return VERR_NO_MEMORY; 443 444 RTFILE hFile; 445 int rc = RTFileOpen(&hFile, pszPathAbs, 446 RTFILE_O_READ | RTFILE_O_OPEN | RTFILE_O_DENY_WRITE); 457 int rc = pathResolve(pThis, pszUrl, &pszPathAbs); 447 458 if (RT_SUCCESS(rc)) 448 459 { 449 rc = RTFileQueryInfo(hFile, pObjInfo, RTFSOBJATTRADD_NOTHING); 450 451 RTFileClose(hFile); 460 RTFSOBJINFO objInfo; 461 rc = RTPathQueryInfo(pszPathAbs, &objInfo, RTFSOBJATTRADD_NOTHING); 462 if (RT_SUCCESS(rc)) 463 { 464 if (RTFS_IS_DIRECTORY(objInfo.Attr.fMode)) 465 { 466 PRTHTTPSERVERRESP pResp = &pThis->Resp; 467 468 RTVFSDIR hVfsDir; 469 rc = dirOpen(pszPathAbs, &hVfsDir); 470 if (RT_SUCCESS(rc)) 471 { 472 RTHttpServerResponseDestroy(pResp); 473 RTHttpServerResponseInitEx(pResp, _4K); 474 475 /* 476 * Write body header. 477 */ 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 Assert(cch); 483 484 pResp->cbBodyUsed = strlen((char *)pResp->pvBody); 485 486 /* 487 * Write body entries. 488 */ 489 char *pszEntry = NULL; 490 RTFSOBJINFO fsObjInfo; 491 while (RT_SUCCESS(rc = dirRead(hVfsDir, &pszEntry, &fsObjInfo))) 492 { 493 char *pszBody = (char *)pResp->pvBody; 494 495 size_t cbWritten; 496 rc = dirEntryWrite(&pszBody[pResp->cbBodyUsed], pResp->cbBodyAlloc - pResp->cbBodyUsed, pszEntry, &fsObjInfo, &cbWritten); 497 if (rc == VERR_BUFFER_OVERFLOW) 498 { 499 pResp->cbBodyAlloc *= 2; /** @todo Improve this. */ 500 pResp->pvBody = RTMemRealloc(pResp->pvBody, pResp->cbBodyAlloc); 501 AssertPtrBreakStmt(pResp->pvBody, rc = VERR_NO_MEMORY); 502 503 pszBody = (char *)pResp->pvBody; 504 505 rc = dirEntryWrite(&pszBody[pResp->cbBodyUsed], pResp->cbBodyAlloc - pResp->cbBodyUsed, pszEntry, &fsObjInfo, &cbWritten); 506 } 507 508 if (RT_SUCCESS(rc)) 509 pResp->cbBodyUsed += cbWritten; 510 511 RTStrFree(pszEntry); 512 513 if (RT_FAILURE(rc)) 514 break; 515 } 516 517 if (rc == VERR_NO_MORE_FILES) /* All entries consumed? */ 518 rc = VINF_SUCCESS; 519 520 dirClose(hVfsDir); 521 522 if (RT_SUCCESS(rc)) 523 { 524 rc = RTStrAPrintf(ppszMIMEHint, "text/plain"); 525 if (RT_SUCCESS(rc)) 526 pObjInfo->cbObject = pResp->cbBodyUsed; 527 } 528 } 529 } 530 else if (RTFS_IS_FILE(objInfo.Attr.fMode)) 531 { 532 RTFILE hFile; 533 rc = RTFileOpen(&hFile, pszPathAbs, 534 RTFILE_O_READ | RTFILE_O_OPEN | RTFILE_O_DENY_WRITE); 535 if (RT_SUCCESS(rc)) 536 { 537 rc = RTFileQueryInfo(hFile, pObjInfo, RTFSOBJATTRADD_NOTHING); 538 539 RTFileClose(hFile); 540 } 541 } 542 } 543 544 RTStrFree(pszPathAbs); 452 545 } 453 546 … … 542 635 } 543 636 544 /* Initialize CWD. */545 RTStrPrintf2(g_HttpServerData.szCWD, sizeof(g_HttpServerData.szCWD), "/");546 547 637 /* Install signal handler. */ 548 638 rc = signalHandlerInstall(); … … 559 649 Callbacks.pfnClose = onClose; 560 650 Callbacks.pfnQueryInfo = onQueryInfo; 561 Callbacks.pfnOnGetRequest = onGetRequest;562 Callbacks.pfnOnHeadRequest = onHeadRequest;563 651 564 652 g_HttpServerData.h.File = NIL_RTFILE; 565 g_HttpServerData.h.Dir = NIL_RTDIR; 653 g_HttpServerData.h.Dir = NIL_RTVFSDIR; 654 655 rc = RTHttpServerResponseInit(&g_HttpServerData.Resp); 656 AssertRC(rc); 566 657 567 658 RTHTTPSERVER hHTTPServer;
Note:
See TracChangeset
for help on using the changeset viewer.