@harperfast/harper 5.0.0-alpha.10 → 5.0.0-beta.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/bin/BinObjects.js +17 -0
- package/bin/cliOperations.js +157 -0
- package/bin/copyDb.ts +280 -0
- package/bin/harper.js +156 -0
- package/bin/install.js +15 -0
- package/bin/lite.js +5 -0
- package/bin/restart.js +201 -0
- package/bin/run.js +409 -0
- package/bin/status.js +65 -0
- package/bin/stop.js +22 -0
- package/bin/upgrade.js +134 -0
- package/components/Application.ts +646 -0
- package/components/ApplicationScope.ts +49 -0
- package/components/Component.ts +53 -0
- package/components/ComponentV1.ts +342 -0
- package/components/DEFAULT_CONFIG.ts +18 -0
- package/components/EntryHandler.ts +227 -0
- package/components/Logger.ts +14 -0
- package/components/OptionsWatcher.ts +354 -0
- package/components/PluginModule.ts +6 -0
- package/components/Scope.ts +329 -0
- package/components/componentLoader.ts +529 -0
- package/components/deriveCommonPatternBase.ts +31 -0
- package/components/deriveGlobOptions.ts +44 -0
- package/components/deriveURLPath.ts +57 -0
- package/components/operations.js +658 -0
- package/components/operationsValidation.js +246 -0
- package/components/packageComponent.ts +39 -0
- package/components/requestRestart.ts +26 -0
- package/components/resolveBaseURLPath.ts +38 -0
- package/components/status/ComponentStatus.ts +110 -0
- package/components/status/ComponentStatusRegistry.ts +251 -0
- package/components/status/api.ts +153 -0
- package/components/status/crossThread.ts +405 -0
- package/components/status/errors.ts +152 -0
- package/components/status/index.ts +44 -0
- package/components/status/internal.ts +65 -0
- package/components/status/registry.ts +12 -0
- package/components/status/types.ts +96 -0
- package/config/RootConfigWatcher.ts +59 -0
- package/config/configHelpers.ts +11 -0
- package/config/configUtils.js +967 -0
- package/config/harperConfigEnvVars.ts +641 -0
- package/dataLayer/CreateAttributeObject.js +25 -0
- package/dataLayer/CreateTableObject.js +11 -0
- package/dataLayer/DataLayerObjects.js +43 -0
- package/dataLayer/DeleteBeforeObject.js +22 -0
- package/dataLayer/DeleteObject.js +25 -0
- package/dataLayer/DropAttributeObject.js +11 -0
- package/dataLayer/GetBackupObject.js +22 -0
- package/dataLayer/InsertObject.js +24 -0
- package/dataLayer/ReadAuditLogObject.js +24 -0
- package/dataLayer/SQLSearch.js +1335 -0
- package/dataLayer/SearchByConditionsObject.js +61 -0
- package/dataLayer/SearchByHashObject.js +21 -0
- package/dataLayer/SearchObject.js +45 -0
- package/dataLayer/SqlSearchObject.js +14 -0
- package/dataLayer/UpdateObject.js +23 -0
- package/dataLayer/UpsertObject.js +23 -0
- package/dataLayer/bulkLoad.js +813 -0
- package/dataLayer/dataObjects/BulkLoadObjects.js +27 -0
- package/dataLayer/dataObjects/UpsertObject.js +23 -0
- package/dataLayer/delete.js +164 -0
- package/dataLayer/export.js +381 -0
- package/dataLayer/getBackup.js +40 -0
- package/dataLayer/harperBridge/BridgeMethods.js +81 -0
- package/dataLayer/harperBridge/ResourceBridge.ts +633 -0
- package/dataLayer/harperBridge/bridgeUtility/insertUpdateReturnObj.js +28 -0
- package/dataLayer/harperBridge/bridgeUtility/insertUpdateValidate.js +88 -0
- package/dataLayer/harperBridge/harperBridge.js +21 -0
- package/dataLayer/harperBridge/lmdbBridge/LMDBBridge.js +119 -0
- package/dataLayer/harperBridge/lmdbBridge/lmdbMethods/DeleteAuditLogsBeforeResults.js +19 -0
- package/dataLayer/harperBridge/lmdbBridge/lmdbMethods/lmdbCreateAttribute.js +112 -0
- package/dataLayer/harperBridge/lmdbBridge/lmdbMethods/lmdbCreateRecords.js +67 -0
- package/dataLayer/harperBridge/lmdbBridge/lmdbMethods/lmdbCreateSchema.js +31 -0
- package/dataLayer/harperBridge/lmdbBridge/lmdbMethods/lmdbCreateTable.js +94 -0
- package/dataLayer/harperBridge/lmdbBridge/lmdbMethods/lmdbDeleteAuditLogsBefore.js +98 -0
- package/dataLayer/harperBridge/lmdbBridge/lmdbMethods/lmdbDeleteRecords.js +89 -0
- package/dataLayer/harperBridge/lmdbBridge/lmdbMethods/lmdbDropAttribute.js +109 -0
- package/dataLayer/harperBridge/lmdbBridge/lmdbMethods/lmdbDropSchema.js +107 -0
- package/dataLayer/harperBridge/lmdbBridge/lmdbMethods/lmdbDropTable.js +137 -0
- package/dataLayer/harperBridge/lmdbBridge/lmdbMethods/lmdbFlush.js +35 -0
- package/dataLayer/harperBridge/lmdbBridge/lmdbMethods/lmdbGetBackup.js +111 -0
- package/dataLayer/harperBridge/lmdbBridge/lmdbMethods/lmdbGetDataByHash.js +28 -0
- package/dataLayer/harperBridge/lmdbBridge/lmdbMethods/lmdbGetDataByValue.js +29 -0
- package/dataLayer/harperBridge/lmdbBridge/lmdbMethods/lmdbReadAuditLog.js +207 -0
- package/dataLayer/harperBridge/lmdbBridge/lmdbMethods/lmdbSearchByConditions.js +156 -0
- package/dataLayer/harperBridge/lmdbBridge/lmdbMethods/lmdbSearchByHash.js +21 -0
- package/dataLayer/harperBridge/lmdbBridge/lmdbMethods/lmdbSearchByValue.js +30 -0
- package/dataLayer/harperBridge/lmdbBridge/lmdbMethods/lmdbTransaction.js +19 -0
- package/dataLayer/harperBridge/lmdbBridge/lmdbMethods/lmdbUpdateRecords.js +64 -0
- package/dataLayer/harperBridge/lmdbBridge/lmdbMethods/lmdbUpsertRecords.js +70 -0
- package/dataLayer/harperBridge/lmdbBridge/lmdbUtility/LMDBCreateAttributeObject.js +22 -0
- package/dataLayer/harperBridge/lmdbBridge/lmdbUtility/LMDBDeleteTransactionObject.js +23 -0
- package/dataLayer/harperBridge/lmdbBridge/lmdbUtility/LMDBInsertTransactionObject.js +22 -0
- package/dataLayer/harperBridge/lmdbBridge/lmdbUtility/LMDBTransactionObject.js +23 -0
- package/dataLayer/harperBridge/lmdbBridge/lmdbUtility/LMDBUpdateTransactionObject.js +24 -0
- package/dataLayer/harperBridge/lmdbBridge/lmdbUtility/LMDBUpsertTransactionObject.js +24 -0
- package/dataLayer/harperBridge/lmdbBridge/lmdbUtility/TableSizeObject.js +25 -0
- package/dataLayer/harperBridge/lmdbBridge/lmdbUtility/initializeHashSearch.js +21 -0
- package/dataLayer/harperBridge/lmdbBridge/lmdbUtility/initializePaths.js +157 -0
- package/dataLayer/harperBridge/lmdbBridge/lmdbUtility/lmdbCheckForNewAttributes.js +94 -0
- package/dataLayer/harperBridge/lmdbBridge/lmdbUtility/lmdbCreateTransactionsAuditEnvironment.js +39 -0
- package/dataLayer/harperBridge/lmdbBridge/lmdbUtility/lmdbGetTableSize.js +34 -0
- package/dataLayer/harperBridge/lmdbBridge/lmdbUtility/lmdbProcessRows.js +100 -0
- package/dataLayer/harperBridge/lmdbBridge/lmdbUtility/lmdbSearch.js +371 -0
- package/dataLayer/harperBridge/lmdbBridge/lmdbUtility/lmdbWriteTransaction.js +109 -0
- package/dataLayer/hdbInfoController.js +254 -0
- package/dataLayer/insert.js +266 -0
- package/dataLayer/readAuditLog.js +59 -0
- package/dataLayer/schema.js +366 -0
- package/dataLayer/schemaDescribe.js +289 -0
- package/dataLayer/search.js +60 -0
- package/dataLayer/transaction.js +17 -0
- package/dataLayer/update.js +124 -0
- package/dist/components/Logger.d.ts +12 -0
- package/dist/components/Logger.js +3 -0
- package/dist/components/Logger.js.map +1 -0
- package/dist/components/Scope.d.ts +14 -4
- package/dist/components/Scope.js +18 -10
- package/dist/components/Scope.js.map +1 -1
- package/dist/components/componentLoader.js +16 -9
- package/dist/components/componentLoader.js.map +1 -1
- package/dist/components/operations.js +2 -2
- package/dist/components/operations.js.map +1 -1
- package/dist/config/configUtils.d.ts +1 -1
- package/dist/config/configUtils.js +1 -1
- package/dist/config/configUtils.js.map +1 -1
- package/dist/dataLayer/CreateTableObject.d.ts +2 -2
- package/dist/dataLayer/CreateTableObject.js +2 -2
- package/dist/dataLayer/CreateTableObject.js.map +1 -1
- package/dist/dataLayer/delete.d.ts +1 -1
- package/dist/dataLayer/schema.js +6 -5
- package/dist/dataLayer/schema.js.map +1 -1
- package/dist/dataLayer/schemaDescribe.js +1 -1
- package/dist/dataLayer/schemaDescribe.js.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +2 -0
- package/dist/index.js.map +1 -1
- package/dist/resources/DatabaseTransaction.d.ts +1 -1
- package/dist/resources/IterableEventQueue.d.ts +1 -1
- package/dist/resources/LMDBTransaction.d.ts +5 -1
- package/dist/resources/Resource.d.ts +1 -1
- package/dist/resources/RocksIndexStore.d.ts +3 -3
- package/dist/resources/RocksTransactionLogStore.d.ts +6 -3
- package/dist/resources/Table.d.ts +15 -6
- package/dist/resources/Table.js +4 -1
- package/dist/resources/Table.js.map +1 -1
- package/dist/resources/analytics/read.js +32 -22
- package/dist/resources/analytics/read.js.map +1 -1
- package/dist/resources/analytics/write.js +3 -6
- package/dist/resources/analytics/write.js.map +1 -1
- package/dist/resources/auditStore.d.ts +3 -3
- package/dist/resources/blob.d.ts +25 -2
- package/dist/resources/databases.d.ts +12 -2
- package/dist/resources/databases.js +22 -19
- package/dist/resources/databases.js.map +1 -1
- package/dist/resources/search.js +11 -5
- package/dist/resources/search.js.map +1 -1
- package/dist/resources/transaction.d.ts +2 -1
- package/dist/security/auth.js +1 -1
- package/dist/security/auth.js.map +1 -1
- package/dist/security/cryptoHash.d.ts +2 -2
- package/dist/security/jsLoader.js +243 -66
- package/dist/security/jsLoader.js.map +1 -1
- package/dist/security/keys.js +4 -5
- package/dist/security/keys.js.map +1 -1
- package/dist/security/user.js +3 -3
- package/dist/security/user.js.map +1 -1
- package/dist/server/REST.js +16 -2
- package/dist/server/REST.js.map +1 -1
- package/dist/server/Server.d.ts +2 -1
- package/dist/server/Server.js.map +1 -1
- package/dist/server/fastifyRoutes/plugins/hdbCore.d.ts +6 -1
- package/dist/server/fastifyRoutes.js +2 -0
- package/dist/server/fastifyRoutes.js.map +1 -1
- package/dist/server/http.js +12 -6
- package/dist/server/http.js.map +1 -1
- package/dist/server/jobs/JobObject.d.ts +3 -3
- package/dist/server/loadRootComponents.js +1 -0
- package/dist/server/loadRootComponents.js.map +1 -1
- package/dist/server/operationsServer.js +3 -1
- package/dist/server/operationsServer.js.map +1 -1
- package/dist/server/serverHelpers/JSONStream.d.ts +3 -3
- package/dist/server/serverHelpers/Request.d.ts +5 -5
- package/dist/server/serverHelpers/requestTimePlugin.d.ts +1 -1
- package/dist/server/threads/manageThreads.d.ts +2 -2
- package/dist/server/threads/manageThreads.js +50 -35
- package/dist/server/threads/manageThreads.js.map +1 -1
- package/dist/server/threads/socketRouter.d.ts +1 -1
- package/dist/sqlTranslator/deleteTranslator.d.ts +1 -1
- package/dist/utility/AWS/AWSConnector.d.ts +3 -2
- package/dist/utility/common_utils.d.ts +3 -3
- package/dist/utility/environment/systemInformation.d.ts +1 -0
- package/dist/utility/functions/date/dateFunctions.d.ts +11 -11
- package/dist/utility/globalSchema.d.ts +1 -1
- package/dist/utility/hdbTerms.d.ts +3 -0
- package/dist/utility/hdbTerms.js +3 -0
- package/dist/utility/hdbTerms.js.map +1 -1
- package/dist/utility/installation.d.ts +2 -4
- package/dist/utility/installation.js.map +1 -1
- package/dist/utility/lmdb/commonUtility.d.ts +1 -0
- package/dist/utility/lmdb/deleteUtility.d.ts +1 -0
- package/dist/utility/lmdb/environmentUtility.d.ts +1 -0
- package/dist/utility/lmdb/searchUtility.d.ts +2 -1
- package/dist/utility/lmdb/writeUtility.d.ts +1 -0
- package/dist/utility/logging/harper_logger.d.ts +6 -6
- package/dist/utility/processManagement/processManagement.d.ts +1 -1
- package/dist/utility/processManagement/servicesConfig.d.ts +12 -6
- package/dist/validation/common_validators.d.ts +4 -3
- package/dist/validation/configValidator.d.ts +3 -2
- package/index.d.ts +56 -0
- package/index.js +41 -0
- package/json/systemSchema.json +373 -0
- package/launchServiceScripts/launchHarperDB.js +3 -0
- package/launchServiceScripts/utility/checkNodeVersion.js +15 -0
- package/package.json +21 -3
- package/resources/DatabaseTransaction.ts +378 -0
- package/resources/ErrorResource.ts +57 -0
- package/resources/IterableEventQueue.ts +94 -0
- package/resources/LMDBTransaction.ts +349 -0
- package/resources/RecordEncoder.ts +702 -0
- package/resources/RequestTarget.ts +134 -0
- package/resources/Resource.ts +789 -0
- package/resources/ResourceInterface.ts +221 -0
- package/resources/ResourceInterfaceV2.ts +53 -0
- package/resources/ResourceV2.ts +67 -0
- package/resources/Resources.ts +162 -0
- package/resources/RocksIndexStore.ts +70 -0
- package/resources/RocksTransactionLogStore.ts +352 -0
- package/resources/Table.ts +4527 -0
- package/resources/analytics/hostnames.ts +72 -0
- package/resources/analytics/metadata.ts +10 -0
- package/resources/analytics/read.ts +252 -0
- package/resources/analytics/write.ts +803 -0
- package/resources/auditStore.ts +556 -0
- package/resources/blob.ts +1268 -0
- package/resources/crdt.ts +125 -0
- package/resources/dataLoader.ts +527 -0
- package/resources/databases.ts +1290 -0
- package/resources/graphql.ts +221 -0
- package/resources/indexes/HierarchicalNavigableSmallWorld.ts +638 -0
- package/resources/indexes/customIndexes.ts +7 -0
- package/resources/indexes/vector.ts +38 -0
- package/resources/jsResource.ts +86 -0
- package/resources/loadEnv.ts +22 -0
- package/resources/login.ts +18 -0
- package/resources/openApi.ts +409 -0
- package/resources/registrationDeprecated.ts +8 -0
- package/resources/replayLogs.ts +136 -0
- package/resources/roles.ts +98 -0
- package/resources/search.ts +1301 -0
- package/resources/tracked.ts +584 -0
- package/resources/transaction.ts +89 -0
- package/resources/transactionBroadcast.ts +258 -0
- package/security/auth.ts +376 -0
- package/security/certificateVerification/certificateVerificationSource.ts +84 -0
- package/security/certificateVerification/configValidation.ts +107 -0
- package/security/certificateVerification/crlVerification.ts +623 -0
- package/security/certificateVerification/index.ts +121 -0
- package/security/certificateVerification/ocspVerification.ts +148 -0
- package/security/certificateVerification/pkijs-ed25519-patch.ts +188 -0
- package/security/certificateVerification/types.ts +128 -0
- package/security/certificateVerification/verificationConfig.ts +138 -0
- package/security/certificateVerification/verificationUtils.ts +447 -0
- package/security/cryptoHash.js +42 -0
- package/security/data_objects/PermissionAttributeResponseObject.js +15 -0
- package/security/data_objects/PermissionResponseObject.js +115 -0
- package/security/data_objects/PermissionTableResponseObject.js +20 -0
- package/security/fastifyAuth.js +169 -0
- package/security/impersonation.ts +160 -0
- package/security/jsLoader.ts +716 -0
- package/security/keys.js +948 -0
- package/security/permissionsTranslator.js +300 -0
- package/security/role.js +218 -0
- package/security/tokenAuthentication.ts +228 -0
- package/security/user.ts +449 -0
- package/server/DurableSubscriptionsSession.ts +503 -0
- package/server/REST.ts +407 -0
- package/server/Server.ts +89 -0
- package/server/fastifyRoutes/helpers/getCORSOptions.js +36 -0
- package/server/fastifyRoutes/helpers/getHeaderTimeoutConfig.js +15 -0
- package/server/fastifyRoutes/helpers/getServerOptions.js +33 -0
- package/server/fastifyRoutes/plugins/hdbCore.js +39 -0
- package/server/fastifyRoutes.ts +205 -0
- package/server/graphqlQuerying.ts +700 -0
- package/server/http.ts +640 -0
- package/server/itc/serverHandlers.js +161 -0
- package/server/itc/utility/ITCEventObject.js +10 -0
- package/server/jobs/JobObject.js +24 -0
- package/server/jobs/jobProcess.js +69 -0
- package/server/jobs/jobRunner.js +162 -0
- package/server/jobs/jobs.js +304 -0
- package/server/loadRootComponents.js +44 -0
- package/server/mqtt.ts +485 -0
- package/server/nodeName.ts +75 -0
- package/server/operationsServer.ts +313 -0
- package/server/serverHelpers/Headers.ts +108 -0
- package/server/serverHelpers/JSONStream.ts +269 -0
- package/server/serverHelpers/OperationFunctionObject.ts +13 -0
- package/server/serverHelpers/Request.ts +158 -0
- package/server/serverHelpers/contentTypes.ts +637 -0
- package/server/serverHelpers/requestTimePlugin.js +57 -0
- package/server/serverHelpers/serverHandlers.js +148 -0
- package/server/serverHelpers/serverUtilities.ts +473 -0
- package/server/serverRegistry.ts +8 -0
- package/server/static.ts +187 -0
- package/server/status/definitions.ts +37 -0
- package/server/status/index.ts +125 -0
- package/server/storageReclamation.ts +93 -0
- package/server/threads/itc.js +89 -0
- package/server/threads/manageThreads.js +594 -0
- package/server/threads/socketRouter.ts +360 -0
- package/server/threads/threadServer.js +279 -0
- package/server/throttle.ts +73 -0
- package/sqlTranslator/SelectValidator.js +330 -0
- package/sqlTranslator/alasqlFunctionImporter.js +62 -0
- package/sqlTranslator/deleteTranslator.js +67 -0
- package/sqlTranslator/index.js +242 -0
- package/sqlTranslator/sql_statement_bucket.js +472 -0
- package/static/defaultConfig.yaml +3 -0
- package/studio/web/HDBDogOnly.svg +78 -0
- package/studio/web/assets/PPRadioGrotesk-Bold-DDaUYG8E.woff +0 -0
- package/studio/web/assets/fa-brands-400-CEJbCg16.woff +0 -0
- package/studio/web/assets/fa-brands-400-CSYNqBb_.ttf +0 -0
- package/studio/web/assets/fa-brands-400-DnkPfk3o.eot +0 -0
- package/studio/web/assets/fa-brands-400-UxlILjvJ.woff2 +0 -0
- package/studio/web/assets/fa-brands-400-cH1MgKbP.svg +3717 -0
- package/studio/web/assets/fa-regular-400-BhTwtT8w.eot +0 -0
- package/studio/web/assets/fa-regular-400-D1vz6WBx.ttf +0 -0
- package/studio/web/assets/fa-regular-400-DFnMcJPd.woff +0 -0
- package/studio/web/assets/fa-regular-400-DGzu1beS.woff2 +0 -0
- package/studio/web/assets/fa-regular-400-gwj8Pxq-.svg +801 -0
- package/studio/web/assets/fa-solid-900-B4ZZ7kfP.svg +5034 -0
- package/studio/web/assets/fa-solid-900-B6Axprfb.eot +0 -0
- package/studio/web/assets/fa-solid-900-BUswJgRo.woff2 +0 -0
- package/studio/web/assets/fa-solid-900-DOXgCApm.woff +0 -0
- package/studio/web/assets/fa-solid-900-mxuxnBEa.ttf +0 -0
- package/studio/web/assets/index-BTgXJX9d.js +235 -0
- package/studio/web/assets/index-BTgXJX9d.js.map +1 -0
- package/studio/web/assets/index-C-GXfcup.js +37 -0
- package/studio/web/assets/index-C-GXfcup.js.map +1 -0
- package/studio/web/assets/index-PFlNdimM.js +2 -0
- package/studio/web/assets/index-PFlNdimM.js.map +1 -0
- package/studio/web/assets/index-Y2g_iFpU.css +1 -0
- package/studio/web/assets/index-jiPwkrsB.css +1 -0
- package/studio/web/assets/index.lazy-C3TJZJ4o.js +266 -0
- package/studio/web/assets/index.lazy-C3TJZJ4o.js.map +1 -0
- package/studio/web/assets/profiler-DotzgiCJ.js +2 -0
- package/studio/web/assets/profiler-DotzgiCJ.js.map +1 -0
- package/studio/web/assets/react-redux-VxUEx_mU.js +6 -0
- package/studio/web/assets/react-redux-VxUEx_mU.js.map +1 -0
- package/studio/web/assets/startRecording-B_9J9Csd.js +3 -0
- package/studio/web/assets/startRecording-B_9J9Csd.js.map +1 -0
- package/studio/web/fabric-signup-background.webp +0 -0
- package/studio/web/fabric-signup-text.png +0 -0
- package/studio/web/favicon_purple.png +0 -0
- package/studio/web/github-icon.svg +15 -0
- package/studio/web/harper-fabric_black.png +0 -0
- package/studio/web/harper-fabric_white.png +0 -0
- package/studio/web/harper-studio_white.png +0 -0
- package/studio/web/index.html +16 -0
- package/studio/web/running.css +148 -0
- package/studio/web/running.html +147 -0
- package/studio/web/running.js +111 -0
- package/upgrade/UpgradeObjects.js +13 -0
- package/upgrade/directives/directivesController.js +90 -0
- package/upgrade/directivesManager.js +139 -0
- package/upgrade/upgradePrompt.js +124 -0
- package/upgrade/upgradeUtilities.js +28 -0
- package/utility/AWS/AWSConnector.js +29 -0
- package/utility/OperationFunctionCaller.js +63 -0
- package/utility/assignCmdEnvVariables.js +62 -0
- package/utility/common_utils.js +867 -0
- package/utility/environment/environmentManager.js +208 -0
- package/utility/environment/systemInformation.js +355 -0
- package/utility/errors/commonErrors.js +267 -0
- package/utility/errors/hdbError.js +146 -0
- package/utility/functions/date/dateFunctions.js +65 -0
- package/utility/functions/geo.js +355 -0
- package/utility/functions/sql/alaSQLExtension.js +104 -0
- package/utility/globalSchema.js +35 -0
- package/utility/hdbTerms.ts +819 -0
- package/utility/install/checkJWTTokensExist.js +62 -0
- package/utility/install/harperdb.conf +15 -0
- package/utility/install/harperdb.service +14 -0
- package/utility/install/installer.js +635 -0
- package/utility/installation.ts +30 -0
- package/utility/lmdb/DBIDefinition.js +20 -0
- package/utility/lmdb/DeleteRecordsResponseObject.js +25 -0
- package/utility/lmdb/InsertRecordsResponseObject.js +22 -0
- package/utility/lmdb/OpenDBIObject.js +31 -0
- package/utility/lmdb/OpenEnvironmentObject.js +41 -0
- package/utility/lmdb/UpdateRecordsResponseObject.js +25 -0
- package/utility/lmdb/UpsertRecordsResponseObject.js +22 -0
- package/utility/lmdb/cleanLMDBMap.js +65 -0
- package/utility/lmdb/commonUtility.js +119 -0
- package/utility/lmdb/deleteUtility.js +128 -0
- package/utility/lmdb/environmentUtility.js +477 -0
- package/utility/lmdb/searchCursorFunctions.js +187 -0
- package/utility/lmdb/searchUtility.js +918 -0
- package/utility/lmdb/terms.js +57 -0
- package/utility/lmdb/writeUtility.js +407 -0
- package/utility/logging/harper_logger.js +876 -0
- package/utility/logging/logRotator.js +157 -0
- package/utility/logging/logger.ts +24 -0
- package/utility/logging/readLog.js +355 -0
- package/utility/logging/transactionLog.js +57 -0
- package/utility/mount_hdb.js +59 -0
- package/utility/npmUtilities.js +102 -0
- package/utility/operationPermissions.ts +112 -0
- package/utility/operation_authorization.js +836 -0
- package/utility/packageUtils.js +55 -0
- package/utility/password.ts +99 -0
- package/utility/processManagement/processManagement.js +187 -0
- package/utility/processManagement/servicesConfig.js +56 -0
- package/utility/scripts/restartHdb.js +24 -0
- package/utility/scripts/user_data.sh +13 -0
- package/utility/signalling.js +36 -0
- package/utility/terms/certificates.js +81 -0
- package/utility/when.ts +20 -0
- package/v1.d.ts +39 -0
- package/v1.js +41 -0
- package/v2.d.ts +39 -0
- package/v2.js +41 -0
- package/validation/bulkDeleteValidator.js +24 -0
- package/validation/check_permissions.js +19 -0
- package/validation/common_validators.js +95 -0
- package/validation/configValidator.js +331 -0
- package/validation/deleteValidator.js +15 -0
- package/validation/fileLoadValidator.js +153 -0
- package/validation/insertValidator.js +40 -0
- package/validation/installValidator.js +37 -0
- package/validation/readLogValidator.js +64 -0
- package/validation/role_validation.js +320 -0
- package/validation/schemaMetadataValidator.js +42 -0
- package/validation/searchValidator.js +166 -0
- package/validation/statusValidator.ts +66 -0
- package/validation/transactionLogValidator.js +33 -0
- package/validation/user_validation.js +55 -0
- package/validation/validationWrapper.js +105 -0
- package/dist/resources/analytics/profile.d.ts +0 -2
- package/dist/resources/analytics/profile.js +0 -144
- package/dist/resources/analytics/profile.js.map +0 -1
package/server/http.ts
ADDED
|
@@ -0,0 +1,640 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* This module represents the HTTP component for Harper, and receives the HTTP options and uses them to configure
|
|
3
|
+
* HTTP servers
|
|
4
|
+
*/
|
|
5
|
+
import { Scope } from '../components/Scope.ts';
|
|
6
|
+
import { Socket } from 'node:net';
|
|
7
|
+
import harperLogger from '../utility/logging/harper_logger.js';
|
|
8
|
+
import { parentPort } from 'node:worker_threads';
|
|
9
|
+
import env from '../utility/environment/environmentManager.js';
|
|
10
|
+
import * as terms from '../utility/hdbTerms.ts';
|
|
11
|
+
import { resolvePath } from '../config/configUtils.js';
|
|
12
|
+
import { getTicketKeys } from './threads/manageThreads.js';
|
|
13
|
+
import { createTLSSelector } from '../security/keys.js';
|
|
14
|
+
import { createSecureServer } from 'node:http2';
|
|
15
|
+
import { createServer as createSecureServerHttp1 } from 'node:https';
|
|
16
|
+
import { createServer, IncomingMessage } from 'node:http';
|
|
17
|
+
import { Request } from './serverHelpers/Request.ts';
|
|
18
|
+
import { appendHeader, Headers } from './serverHelpers/Headers.ts';
|
|
19
|
+
import { Blob } from '../resources/blob.ts';
|
|
20
|
+
import { recordAction, recordActionBinary } from '../resources/analytics/write.ts';
|
|
21
|
+
import { Readable } from 'node:stream';
|
|
22
|
+
import { server, type ServerOptions, type HttpOptions } from './Server.ts';
|
|
23
|
+
import { setPortServerMap, SERVERS } from './serverRegistry.ts';
|
|
24
|
+
import { getComponentName } from '../components/componentLoader.ts';
|
|
25
|
+
import { throttle } from './throttle.ts';
|
|
26
|
+
import { WebSocketServer } from 'ws';
|
|
27
|
+
|
|
28
|
+
const { errorToString } = harperLogger;
|
|
29
|
+
server.http = httpServer;
|
|
30
|
+
server.request = onRequest;
|
|
31
|
+
server.ws = onWebSocket;
|
|
32
|
+
server.upgrade = onUpgrade;
|
|
33
|
+
const websocketServers = {};
|
|
34
|
+
const httpServers = {},
|
|
35
|
+
httpChain = {},
|
|
36
|
+
httpResponders = [];
|
|
37
|
+
let httpOptions: HttpOptions = {};
|
|
38
|
+
|
|
39
|
+
export function handleApplication(scope: Scope) {
|
|
40
|
+
httpOptions = scope.options.getAll() as HttpOptions;
|
|
41
|
+
scope.options.on('change', (_key) => {
|
|
42
|
+
// TODO: Check to see if the key is something we can or can't handle
|
|
43
|
+
httpOptions = scope.options.getAll() as HttpOptions;
|
|
44
|
+
});
|
|
45
|
+
}
|
|
46
|
+
export function getHttpOptions() {
|
|
47
|
+
return httpOptions;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
export function deliverSocket(fdOrSocket, port, data) {
|
|
51
|
+
// Create a socket and deliver it to the HTTP server
|
|
52
|
+
// HTTP server likes to allow half open sockets
|
|
53
|
+
const socket = fdOrSocket?.read
|
|
54
|
+
? fdOrSocket
|
|
55
|
+
: new Socket({ fd: fdOrSocket, readable: true, writable: true, allowHalfOpen: true });
|
|
56
|
+
// for each socket, deliver the connection to the HTTP server handler/parser
|
|
57
|
+
const server = SERVERS[port];
|
|
58
|
+
if (server.isSecure) {
|
|
59
|
+
socket.startTime = performance.now();
|
|
60
|
+
}
|
|
61
|
+
if (server) {
|
|
62
|
+
if (typeof server === 'function') server(socket);
|
|
63
|
+
else server.emit('connection', socket);
|
|
64
|
+
if (data) socket.emit('data', data);
|
|
65
|
+
} else {
|
|
66
|
+
const retry = (retries) => {
|
|
67
|
+
// in case the server hasn't registered itself yet
|
|
68
|
+
setTimeout(() => {
|
|
69
|
+
const server = SERVERS[port];
|
|
70
|
+
if (server) {
|
|
71
|
+
if (typeof server === 'function') server(socket);
|
|
72
|
+
else server.emit('connection', socket);
|
|
73
|
+
if (data) socket.emit('data', data);
|
|
74
|
+
} else if (retries < 5) retry(retries + 1);
|
|
75
|
+
else {
|
|
76
|
+
harperLogger.error(`Server on port ${port} was not registered`);
|
|
77
|
+
socket.destroy();
|
|
78
|
+
}
|
|
79
|
+
}, 1000);
|
|
80
|
+
};
|
|
81
|
+
retry(1);
|
|
82
|
+
}
|
|
83
|
+
return socket;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
const requestMap = new Map();
|
|
87
|
+
export function proxyRequest(message) {
|
|
88
|
+
const { port, event, data, requestId } = message;
|
|
89
|
+
let socket;
|
|
90
|
+
socket = requestMap.get(requestId);
|
|
91
|
+
switch (event) {
|
|
92
|
+
case 'connection':
|
|
93
|
+
socket = deliverSocket(undefined, port);
|
|
94
|
+
requestMap.set(requestId, socket);
|
|
95
|
+
socket.write = (data, encoding, callback) => {
|
|
96
|
+
parentPort.postMessage({
|
|
97
|
+
requestId,
|
|
98
|
+
event: 'data',
|
|
99
|
+
data: data.toString('latin1'),
|
|
100
|
+
});
|
|
101
|
+
if (callback) callback();
|
|
102
|
+
return true;
|
|
103
|
+
};
|
|
104
|
+
socket.end = (data, encoding, callback) => {
|
|
105
|
+
parentPort.postMessage({
|
|
106
|
+
requestId,
|
|
107
|
+
event: 'end',
|
|
108
|
+
data: data?.toString('latin1'),
|
|
109
|
+
});
|
|
110
|
+
if (callback) callback();
|
|
111
|
+
return true;
|
|
112
|
+
};
|
|
113
|
+
const originalDestroy = socket.destroy;
|
|
114
|
+
socket.destroy = () => {
|
|
115
|
+
originalDestroy.call(socket);
|
|
116
|
+
parentPort.postMessage({
|
|
117
|
+
requestId,
|
|
118
|
+
event: 'destroy',
|
|
119
|
+
});
|
|
120
|
+
};
|
|
121
|
+
break;
|
|
122
|
+
case 'data':
|
|
123
|
+
if (!socket._readableState.destroyed) socket.emit('data', Buffer.from(data, 'latin1'));
|
|
124
|
+
break;
|
|
125
|
+
case 'drain':
|
|
126
|
+
if (!socket._readableState.destroyed) socket.emit('drain', {});
|
|
127
|
+
break;
|
|
128
|
+
case 'end':
|
|
129
|
+
if (!socket._readableState.destroyed) socket.emit('end', {});
|
|
130
|
+
break;
|
|
131
|
+
case 'error':
|
|
132
|
+
if (!socket._readableState.destroyed) socket.emit('error', {});
|
|
133
|
+
break;
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
export function registerServer(server, port, checkPort = true) {
|
|
138
|
+
if (!port) {
|
|
139
|
+
// if no port is provided, default to custom functions port
|
|
140
|
+
port = env.get(terms.CONFIG_PARAMS.HTTP_PORT);
|
|
141
|
+
}
|
|
142
|
+
const existingServer = SERVERS[port];
|
|
143
|
+
if (existingServer) {
|
|
144
|
+
// if there is an existing server on this port, we create a cascading delegation to try the request with one
|
|
145
|
+
// server and if doesn't handle the request, cascade to next server (until finally we 404)
|
|
146
|
+
const lastServer = existingServer.lastServer || existingServer;
|
|
147
|
+
if (lastServer === server) throw new Error(`Can not register the same server twice for the same port ${port}`);
|
|
148
|
+
if (checkPort && Boolean(lastServer.sessionIdContext) !== Boolean(server.sessionIdContext) && +port)
|
|
149
|
+
throw new Error(`Can not mix secure HTTPS and insecure HTTP on the same port ${port}`);
|
|
150
|
+
lastServer.off('unhandled', defaultNotFound);
|
|
151
|
+
lastServer.on('unhandled', (request, response) => {
|
|
152
|
+
// fastify can't clean up properly, and as soon as we have received a fastify request, must mark our mode
|
|
153
|
+
// as such
|
|
154
|
+
if (server.cantCleanupProperly) existingServer.cantCleanupProperly = true;
|
|
155
|
+
server.emit('request', request, response);
|
|
156
|
+
});
|
|
157
|
+
existingServer.lastServer = server;
|
|
158
|
+
} else {
|
|
159
|
+
SERVERS[port] = server;
|
|
160
|
+
}
|
|
161
|
+
server.on('unhandled', defaultNotFound);
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
function getPorts(options) {
|
|
165
|
+
let ports = [];
|
|
166
|
+
let port = options?.securePort;
|
|
167
|
+
if (port) ports.push({ port, secure: true });
|
|
168
|
+
port = options?.port;
|
|
169
|
+
if (port) ports.push({ port, secure: false });
|
|
170
|
+
if (ports.length === 0) {
|
|
171
|
+
// if no port is provided, default to http port
|
|
172
|
+
ports = [];
|
|
173
|
+
if (env.get(terms.CONFIG_PARAMS.HTTP_PORT) != null)
|
|
174
|
+
ports.push({
|
|
175
|
+
port: env.get(terms.CONFIG_PARAMS.HTTP_PORT),
|
|
176
|
+
secure: env.get(terms.CONFIG_PARAMS.CUSTOMFUNCTIONS_NETWORK_HTTPS),
|
|
177
|
+
});
|
|
178
|
+
if (env.get(terms.CONFIG_PARAMS.HTTP_SECUREPORT) != null)
|
|
179
|
+
ports.push({ port: env.get(terms.CONFIG_PARAMS.HTTP_SECUREPORT), secure: true });
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
if (options?.usageType === 'operations-api' && env.get(terms.CONFIG_PARAMS.OPERATIONSAPI_NETWORK_DOMAINSOCKET)) {
|
|
183
|
+
ports.push({
|
|
184
|
+
port: resolvePath(env.get(terms.CONFIG_PARAMS.OPERATIONSAPI_NETWORK_DOMAINSOCKET)),
|
|
185
|
+
secure: false,
|
|
186
|
+
});
|
|
187
|
+
}
|
|
188
|
+
return ports;
|
|
189
|
+
}
|
|
190
|
+
export function httpServer(listener, options) {
|
|
191
|
+
const servers = [];
|
|
192
|
+
|
|
193
|
+
for (const { port, secure } of getPorts(options)) {
|
|
194
|
+
servers.push(getHTTPServer(port, secure, options));
|
|
195
|
+
if (typeof listener === 'function') {
|
|
196
|
+
httpResponders[options?.runFirst ? 'unshift' : 'push']({ listener, port: options?.port || port });
|
|
197
|
+
} else {
|
|
198
|
+
listener.isSecure = secure;
|
|
199
|
+
registerServer(listener, port, false);
|
|
200
|
+
}
|
|
201
|
+
httpChain[port] = makeCallbackChain(httpResponders, port);
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
return servers;
|
|
205
|
+
}
|
|
206
|
+
function getHTTPServer(port: number, secure: boolean, options: ServerOptions) {
|
|
207
|
+
const { mtls: isMtls, usageType } = options || {};
|
|
208
|
+
const isOperationsServer = usageType === 'operations-api';
|
|
209
|
+
setPortServerMap(port, { protocol_name: secure ? 'HTTPS' : 'HTTP', name: getComponentName() });
|
|
210
|
+
if (!httpServers[port]) {
|
|
211
|
+
// TODO: These should all come from httpOptions or operationsApiOptions
|
|
212
|
+
const serverPrefix = isOperationsServer ? 'operationsApi_network' : 'http';
|
|
213
|
+
const keepAliveTimeout = env.get(serverPrefix + '_keepAliveTimeout');
|
|
214
|
+
const requestTimeout = env.get(serverPrefix + '_timeout');
|
|
215
|
+
const headersTimeout = env.get(serverPrefix + '_headersTimeout');
|
|
216
|
+
const options = {
|
|
217
|
+
keepAliveTimeout,
|
|
218
|
+
headersTimeout,
|
|
219
|
+
requestTimeout,
|
|
220
|
+
// we set this higher (2x times the default in v22, 8x times the default in v20) because it can help with
|
|
221
|
+
// performance
|
|
222
|
+
highWaterMark: 128 * 1024,
|
|
223
|
+
noDelay: true, // don't delay for Nagle's algorithm, it is a relic of the past that slows things down: https://brooker.co.za/blog/2024/05/09/nagle.html
|
|
224
|
+
keepAlive: true,
|
|
225
|
+
keepAliveInitialDelay: 600, // lower the initial delay to 10 minutes, we want to be proactive about closing unused connections
|
|
226
|
+
maxHeaderSize: env.get(terms.CONFIG_PARAMS.HTTP_MAXHEADERSIZE),
|
|
227
|
+
};
|
|
228
|
+
const mtls = env.get(serverPrefix + '_mtls');
|
|
229
|
+
const mtlsRequired = env.get(serverPrefix + '_mtls_required');
|
|
230
|
+
let http2;
|
|
231
|
+
|
|
232
|
+
if (secure) {
|
|
233
|
+
const tlsConfig = env.get('tls');
|
|
234
|
+
// check if we want to enable HTTP/2; operations server doesn't use HTTP/2 because it doesn't allow the
|
|
235
|
+
// ALPNCallback to work with our custom protocol for replication
|
|
236
|
+
http2 = env.get(serverPrefix + '_http2');
|
|
237
|
+
// If we are in secure mode, we use HTTP/2 (createSecureServer from http2), with back-compat support
|
|
238
|
+
// HTTP/1. We do not use HTTP/2 for insecure mode for a few reasons: browsers do not support insecure
|
|
239
|
+
// HTTP/2. We have seen slower performance with HTTP/2, when used for directly benchmarking. We have
|
|
240
|
+
// also seen problems with insecure HTTP/2 clients negotiating properly (Java HttpClient).
|
|
241
|
+
// TODO: Add an option to not accept the root certificates, and only use the CA
|
|
242
|
+
Object.assign(options, {
|
|
243
|
+
allowHTTP1: true,
|
|
244
|
+
rejectUnauthorized: Boolean(mtlsRequired),
|
|
245
|
+
requestCert: Boolean(mtls || isMtls),
|
|
246
|
+
ticketKeys: getTicketKeys(),
|
|
247
|
+
SNICallback: createTLSSelector(usageType ?? 'server', mtls),
|
|
248
|
+
ciphers: tlsConfig.ciphers ?? tlsConfig[0]?.ciphers,
|
|
249
|
+
});
|
|
250
|
+
}
|
|
251
|
+
const requestHandler = async (nodeRequest: IncomingMessage, nodeResponse: any) => {
|
|
252
|
+
const startTime = performance.now();
|
|
253
|
+
let requestId = 0;
|
|
254
|
+
try {
|
|
255
|
+
const request = new Request(nodeRequest, nodeResponse);
|
|
256
|
+
if (isOperationsServer) request.isOperationsServer = true;
|
|
257
|
+
if (httpOptions.logging?.id) request.requestId = requestId = getRequestId();
|
|
258
|
+
// assign a more WHATWG compliant headers object, this is our real standard interface
|
|
259
|
+
let response = await httpChain[port](request);
|
|
260
|
+
if (!response) {
|
|
261
|
+
// this means that the request was completely handled, presumably through the
|
|
262
|
+
// nodeResponse and we are actually just done
|
|
263
|
+
if (request._nodeResponse.statusCode) {
|
|
264
|
+
logRequest(nodeRequest, request._nodeResponse.statusCode, requestId, performance.now() - startTime);
|
|
265
|
+
return;
|
|
266
|
+
}
|
|
267
|
+
response = unhandled(request);
|
|
268
|
+
}
|
|
269
|
+
if (!response.headers?.set) {
|
|
270
|
+
response.headers = new Headers(response.headers);
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
if (response.status === -1) {
|
|
274
|
+
// This means the HDB stack didn't handle the request, and we can then cascade the request
|
|
275
|
+
// to the server-level handler, forming the bridge to the slower legacy fastify framework that expects
|
|
276
|
+
// to interact with a node HTTP server object.
|
|
277
|
+
for (const headerPair of response.headers || []) {
|
|
278
|
+
nodeResponse.setHeader(headerPair[0], headerPair[1]);
|
|
279
|
+
}
|
|
280
|
+
nodeRequest.baseRequest = request;
|
|
281
|
+
nodeResponse.baseResponse = response;
|
|
282
|
+
return httpServers[port].emit('unhandled', nodeRequest, nodeResponse);
|
|
283
|
+
}
|
|
284
|
+
const status = response.status || 200;
|
|
285
|
+
nodeResponse.statusCode = status;
|
|
286
|
+
const endTime = performance.now();
|
|
287
|
+
const executionTime = endTime - startTime;
|
|
288
|
+
let body = response.body;
|
|
289
|
+
let sentBody;
|
|
290
|
+
let deferWriteHead = false;
|
|
291
|
+
if (!response.handlesHeaders) {
|
|
292
|
+
const headers = response.headers || new Headers();
|
|
293
|
+
if (!body) {
|
|
294
|
+
if (request.method !== 'HEAD') {
|
|
295
|
+
headers.set('Content-Length', '0');
|
|
296
|
+
}
|
|
297
|
+
sentBody = true;
|
|
298
|
+
} else if (body.length >= 0) {
|
|
299
|
+
if (typeof body === 'string') headers.set('Content-Length', Buffer.byteLength(body));
|
|
300
|
+
else headers.set('Content-Length', body.length);
|
|
301
|
+
sentBody = true;
|
|
302
|
+
} else if (body instanceof Blob) {
|
|
303
|
+
// if the size is available now, immediately set it
|
|
304
|
+
if (body.size) headers.set('Content-Length', body.size);
|
|
305
|
+
else if (body.on) {
|
|
306
|
+
deferWriteHead = true;
|
|
307
|
+
body.on('size', (size) => {
|
|
308
|
+
// we can also try to set the Content-Length once the header is read and
|
|
309
|
+
// the size available. but if writeHead is called, this will have no effect. So we
|
|
310
|
+
// need to defer writeHead if we are going to set this
|
|
311
|
+
if (!nodeResponse.headersSent) nodeResponse.setHeader('Content-Length', size);
|
|
312
|
+
});
|
|
313
|
+
}
|
|
314
|
+
body = body.stream();
|
|
315
|
+
}
|
|
316
|
+
let serverTiming = `hdb;dur=${executionTime.toFixed(2)}`;
|
|
317
|
+
if (response.wasCacheMiss) {
|
|
318
|
+
serverTiming += ', miss';
|
|
319
|
+
}
|
|
320
|
+
appendHeader(headers, 'Server-Timing', serverTiming, true);
|
|
321
|
+
if (!nodeResponse.headersSent) {
|
|
322
|
+
if (deferWriteHead) {
|
|
323
|
+
// if we are deferring, we need to set the statusCode and headers, let any other headers be set later
|
|
324
|
+
// until the first write
|
|
325
|
+
|
|
326
|
+
if (headers) {
|
|
327
|
+
if (headers[Symbol.iterator]) {
|
|
328
|
+
for (const [name, value] of headers) {
|
|
329
|
+
nodeResponse.setHeader(name, value);
|
|
330
|
+
}
|
|
331
|
+
} else {
|
|
332
|
+
for (const name in headers) {
|
|
333
|
+
nodeResponse.setHeader(name, headers[name]);
|
|
334
|
+
}
|
|
335
|
+
}
|
|
336
|
+
}
|
|
337
|
+
} // else the fast path, if we don't have to defer
|
|
338
|
+
else nodeResponse.writeHead(status, headers && (headers[Symbol.iterator] ? Array.from(headers) : headers));
|
|
339
|
+
}
|
|
340
|
+
if (sentBody) nodeResponse.end(body);
|
|
341
|
+
}
|
|
342
|
+
const handlerPath = request.handlerPath;
|
|
343
|
+
const method = request.method;
|
|
344
|
+
recordAction(
|
|
345
|
+
executionTime,
|
|
346
|
+
'duration',
|
|
347
|
+
handlerPath,
|
|
348
|
+
method,
|
|
349
|
+
response.wasCacheMiss == undefined ? undefined : response.wasCacheMiss ? 'cache-miss' : 'cache-hit'
|
|
350
|
+
);
|
|
351
|
+
recordActionBinary(status < 400, 'success', handlerPath, method);
|
|
352
|
+
recordActionBinary(1, 'response_' + status, handlerPath, method);
|
|
353
|
+
logRequest(nodeRequest, status, requestId, executionTime);
|
|
354
|
+
if (!sentBody) {
|
|
355
|
+
if (body instanceof ReadableStream) body = Readable.fromWeb(body);
|
|
356
|
+
if (body[Symbol.iterator] || body[Symbol.asyncIterator]) body = Readable.from(body);
|
|
357
|
+
|
|
358
|
+
// if it is a stream, pipe it
|
|
359
|
+
if (body?.pipe) {
|
|
360
|
+
body.pipe(nodeResponse);
|
|
361
|
+
if (body.destroy)
|
|
362
|
+
nodeResponse.on('close', () => {
|
|
363
|
+
body.destroy();
|
|
364
|
+
});
|
|
365
|
+
let bytesSent = 0;
|
|
366
|
+
body.on('data', (data) => {
|
|
367
|
+
bytesSent += data.length;
|
|
368
|
+
});
|
|
369
|
+
body.on('end', () => {
|
|
370
|
+
recordAction(performance.now() - endTime, 'transfer', handlerPath, method);
|
|
371
|
+
recordAction(bytesSent, 'bytes-sent', handlerPath, method);
|
|
372
|
+
});
|
|
373
|
+
}
|
|
374
|
+
// else just send the buffer/string
|
|
375
|
+
else if (body?.then)
|
|
376
|
+
body.then((body) => {
|
|
377
|
+
nodeResponse.end(body);
|
|
378
|
+
}, onError);
|
|
379
|
+
else nodeResponse.end(body);
|
|
380
|
+
}
|
|
381
|
+
} catch (error) {
|
|
382
|
+
onError(error);
|
|
383
|
+
}
|
|
384
|
+
function onError(error) {
|
|
385
|
+
const headers = error.headers;
|
|
386
|
+
const status = error.statusCode || 500;
|
|
387
|
+
try {
|
|
388
|
+
nodeResponse.writeHead(status, headers && (headers[Symbol.iterator] ? Array.from(headers) : headers));
|
|
389
|
+
} catch {} // silently ignore errors writing headers, because they may have been set already
|
|
390
|
+
nodeResponse.end(errorToString(error));
|
|
391
|
+
logRequest(nodeRequest, status, requestId, performance.now() - startTime);
|
|
392
|
+
// a status code is interpreted as an expected error, so just info or warn, otherwise log as error
|
|
393
|
+
if (error.statusCode) {
|
|
394
|
+
if (error.statusCode === 500) harperLogger.warn(error);
|
|
395
|
+
else harperLogger.info(error);
|
|
396
|
+
} else harperLogger.error(error);
|
|
397
|
+
}
|
|
398
|
+
};
|
|
399
|
+
// create a throttled version of the request handler, so we can throttle POST requests
|
|
400
|
+
const throttledRequestHandler = throttle(
|
|
401
|
+
requestHandler,
|
|
402
|
+
(nodeRequest: IncomingMessage, nodeResponse: any) => {
|
|
403
|
+
// if the request queue is taking too long, we want to return an error
|
|
404
|
+
nodeResponse.statusCode = 503;
|
|
405
|
+
nodeResponse.end('Service unavailable, exceeded request queue limit');
|
|
406
|
+
recordAction(true, 'service-unavailable', port);
|
|
407
|
+
},
|
|
408
|
+
env.get(serverPrefix + '_requestQueueLimit')
|
|
409
|
+
);
|
|
410
|
+
const server = (httpServers[port] = (
|
|
411
|
+
secure ? (http2 ? createSecureServer : createSecureServerHttp1) : createServer
|
|
412
|
+
)(options, (nodeRequest: IncomingMessage, nodeResponse: any) => {
|
|
413
|
+
// throttle the requests that can make data modifications because they are more likely to be slow and we don't
|
|
414
|
+
// want to block or slow down other activity
|
|
415
|
+
const method = nodeRequest.method;
|
|
416
|
+
if (method === 'GET' || method === 'OPTIONS' || method === 'HEAD') requestHandler(nodeRequest, nodeResponse);
|
|
417
|
+
else throttledRequestHandler(nodeRequest, nodeResponse);
|
|
418
|
+
}));
|
|
419
|
+
|
|
420
|
+
// Node v16 and earlier required setting this as a property; but carefully, we must only set if it is actually a
|
|
421
|
+
// number or it will actually crash the server
|
|
422
|
+
if (keepAliveTimeout >= 0) server.keepAliveTimeout = keepAliveTimeout;
|
|
423
|
+
if (headersTimeout >= 0) server.headersTimeout = headersTimeout;
|
|
424
|
+
|
|
425
|
+
/* Should we use HTTP2 on upgrade?:
|
|
426
|
+
httpServers[port].on('upgrade', function upgrade(request, socket, head) {
|
|
427
|
+
wss.handleUpgrade(request, socket, head, function done(ws) {
|
|
428
|
+
wss.emit('connection', ws, request);
|
|
429
|
+
});
|
|
430
|
+
});*/
|
|
431
|
+
if (secure) {
|
|
432
|
+
if (!server.ports) server.ports = [];
|
|
433
|
+
server.ports.push(port);
|
|
434
|
+
options.SNICallback.initialize(server);
|
|
435
|
+
if (mtls) server.mtlsConfig = mtls;
|
|
436
|
+
server.on('secureConnection', (socket) => {
|
|
437
|
+
if (socket._parent.startTime) recordAction(performance.now() - socket._parent.startTime, 'tls-handshake', port);
|
|
438
|
+
recordAction(socket.isSessionReused(), 'tls-reused', port);
|
|
439
|
+
});
|
|
440
|
+
server.isSecure = true;
|
|
441
|
+
}
|
|
442
|
+
registerServer(server, port);
|
|
443
|
+
}
|
|
444
|
+
return httpServers[port];
|
|
445
|
+
}
|
|
446
|
+
|
|
447
|
+
function makeCallbackChain(responders, portNum) {
|
|
448
|
+
let nextCallback = unhandled;
|
|
449
|
+
// go through the listeners in reverse order so each callback can be passed to the one before
|
|
450
|
+
// and then each middleware layer can call the next middleware layer
|
|
451
|
+
for (let i = responders.length; i > 0; ) {
|
|
452
|
+
const { listener, port } = responders[--i];
|
|
453
|
+
if (port === portNum || port === 'all') {
|
|
454
|
+
const callback = nextCallback;
|
|
455
|
+
nextCallback = (...args) => {
|
|
456
|
+
// for listener only layers, the response through
|
|
457
|
+
return listener(...args, callback);
|
|
458
|
+
};
|
|
459
|
+
}
|
|
460
|
+
}
|
|
461
|
+
return nextCallback;
|
|
462
|
+
}
|
|
463
|
+
function unhandled(request) {
|
|
464
|
+
if (request.user) {
|
|
465
|
+
// pass on authentication information to the next server
|
|
466
|
+
request._nodeRequest.user = request.user;
|
|
467
|
+
}
|
|
468
|
+
return {
|
|
469
|
+
status: -1,
|
|
470
|
+
body: 'Not found',
|
|
471
|
+
headers: new Headers(),
|
|
472
|
+
};
|
|
473
|
+
}
|
|
474
|
+
function onRequest(listener, options) {
|
|
475
|
+
httpServer(listener, { requestOnly: true, ...options });
|
|
476
|
+
}
|
|
477
|
+
// workaround for inability to defer upgrade from https://github.com/nodejs/node/issues/6339#issuecomment-570511836
|
|
478
|
+
Object.defineProperty(IncomingMessage.prototype, 'upgrade', {
|
|
479
|
+
get() {
|
|
480
|
+
return (
|
|
481
|
+
'connection' in this.headers &&
|
|
482
|
+
'upgrade' in this.headers &&
|
|
483
|
+
this.headers.connection.toLowerCase().includes('upgrade') &&
|
|
484
|
+
this.headers.upgrade.toLowerCase() == 'websocket'
|
|
485
|
+
);
|
|
486
|
+
},
|
|
487
|
+
set(_v) {},
|
|
488
|
+
});
|
|
489
|
+
|
|
490
|
+
type OnUpgradeOptions = {
|
|
491
|
+
port?: number;
|
|
492
|
+
securePort?: number;
|
|
493
|
+
runFirst?: boolean;
|
|
494
|
+
};
|
|
495
|
+
|
|
496
|
+
/**
|
|
497
|
+
* @typedef {(request: unknown, next: Listener) => void | Promise<void>} Listener
|
|
498
|
+
*/
|
|
499
|
+
|
|
500
|
+
const upgradeListeners = [],
|
|
501
|
+
upgradeChains = {};
|
|
502
|
+
|
|
503
|
+
/**
|
|
504
|
+
*
|
|
505
|
+
* @param {Listener} listener
|
|
506
|
+
* @param {OnUpgradeOptions} options
|
|
507
|
+
* @returns
|
|
508
|
+
*/
|
|
509
|
+
function onUpgrade(
|
|
510
|
+
listener: (request: Request, next: (request: Request) => Response) => void,
|
|
511
|
+
options: OnUpgradeOptions
|
|
512
|
+
) {
|
|
513
|
+
for (const { port } of getPorts(options)) {
|
|
514
|
+
upgradeListeners[options?.runFirst ? 'unshift' : 'push']({ listener, port });
|
|
515
|
+
upgradeChains[port] = makeCallbackChain(upgradeListeners, port);
|
|
516
|
+
}
|
|
517
|
+
}
|
|
518
|
+
|
|
519
|
+
type OnWebSocketOptions = {
|
|
520
|
+
port?: number;
|
|
521
|
+
securePort?: number;
|
|
522
|
+
maxPayload?: number;
|
|
523
|
+
usageType?: string;
|
|
524
|
+
mtls?: boolean;
|
|
525
|
+
};
|
|
526
|
+
const websocketListeners = [],
|
|
527
|
+
websocketChains = {};
|
|
528
|
+
/**
|
|
529
|
+
*
|
|
530
|
+
* @param {Listener} listener
|
|
531
|
+
* @param {OnWebSocketOptions} options
|
|
532
|
+
* @returns
|
|
533
|
+
*/
|
|
534
|
+
function onWebSocket(listener: (ws: WebSocket) => void, options: OnWebSocketOptions) {
|
|
535
|
+
const servers = [];
|
|
536
|
+
|
|
537
|
+
for (const { port, secure } of getPorts(options)) {
|
|
538
|
+
setPortServerMap(port, {
|
|
539
|
+
protocol_name: secure ? 'WSS' : 'WS',
|
|
540
|
+
name: getComponentName(),
|
|
541
|
+
});
|
|
542
|
+
|
|
543
|
+
const server = getHTTPServer(port, secure, options);
|
|
544
|
+
|
|
545
|
+
if (!websocketServers[port]) {
|
|
546
|
+
websocketServers[port] = new WebSocketServer({
|
|
547
|
+
noServer: true,
|
|
548
|
+
// TODO: this should be a global config and not per ws listener
|
|
549
|
+
maxPayload: options.maxPayload ?? 100 * 1024 * 1024, // The ws library has a default of 100MB
|
|
550
|
+
});
|
|
551
|
+
|
|
552
|
+
websocketServers[port].on('connection', (ws, incomingMessage) => {
|
|
553
|
+
try {
|
|
554
|
+
const request = new Request(incomingMessage);
|
|
555
|
+
request.isWebSocket = true;
|
|
556
|
+
const chainCompletion = httpChain[port](request);
|
|
557
|
+
harperLogger.debug('Received WS connection, calling listeners', websocketListeners);
|
|
558
|
+
websocketChains[port](ws, request, chainCompletion);
|
|
559
|
+
} catch (error) {
|
|
560
|
+
harperLogger.warn('Error in handling WS connection', error);
|
|
561
|
+
}
|
|
562
|
+
});
|
|
563
|
+
|
|
564
|
+
// Add the default upgrade handler if it doesn't exist.
|
|
565
|
+
onUpgrade(
|
|
566
|
+
(request, socket, head, next) => {
|
|
567
|
+
// If the request has already been upgraded, continue without upgrading
|
|
568
|
+
if (request.__harperdbRequestUpgraded) {
|
|
569
|
+
return next(request, socket, head);
|
|
570
|
+
}
|
|
571
|
+
|
|
572
|
+
// Otherwise, upgrade the socket and then continue
|
|
573
|
+
return websocketServers[port].handleUpgrade(request, socket, head, (ws) => {
|
|
574
|
+
request.__harperdbRequestUpgraded = true;
|
|
575
|
+
next(request, socket, head);
|
|
576
|
+
websocketServers[port].emit('connection', ws, request);
|
|
577
|
+
});
|
|
578
|
+
},
|
|
579
|
+
{ port }
|
|
580
|
+
);
|
|
581
|
+
|
|
582
|
+
// Call the upgrade middleware chain
|
|
583
|
+
server.on('upgrade', (request, socket, head) => {
|
|
584
|
+
if (upgradeChains[port]) {
|
|
585
|
+
upgradeChains[port](request, socket, head);
|
|
586
|
+
}
|
|
587
|
+
});
|
|
588
|
+
}
|
|
589
|
+
|
|
590
|
+
servers.push(server);
|
|
591
|
+
|
|
592
|
+
websocketListeners[options?.runFirst ? 'unshift' : 'push']({ listener, port });
|
|
593
|
+
websocketChains[port] = makeCallbackChain(websocketListeners, port);
|
|
594
|
+
|
|
595
|
+
// mqtt doesn't invoke the http handler so this needs to be here to load up the http chains.
|
|
596
|
+
httpChain[port] = makeCallbackChain(httpResponders, port);
|
|
597
|
+
}
|
|
598
|
+
|
|
599
|
+
return servers;
|
|
600
|
+
}
|
|
601
|
+
|
|
602
|
+
function defaultNotFound(request, response) {
|
|
603
|
+
if (response.headersSent || response.writableEnded) return;
|
|
604
|
+
response.writeHead(404);
|
|
605
|
+
response.end('Not found\n');
|
|
606
|
+
logRequest(request, 404, 0, request.requestId);
|
|
607
|
+
}
|
|
608
|
+
let httpLogger: any;
|
|
609
|
+
|
|
610
|
+
export function logRequest(nodeRequest: IncomingMessage, status: number, requestId: number, executionTime?: number) {
|
|
611
|
+
const logging = httpOptions.logging;
|
|
612
|
+
if (logging) {
|
|
613
|
+
if (!httpLogger) {
|
|
614
|
+
httpLogger = harperLogger.forComponent('http');
|
|
615
|
+
}
|
|
616
|
+
const level = status < 400 ? 'info' : status === 500 ? 'error' : 'warn';
|
|
617
|
+
httpLogger[level]?.(
|
|
618
|
+
`${nodeRequest.method} ${nodeRequest.url} ${nodeRequest.socket.encrypted ? 'HTTPS' : 'HTTP'}/${nodeRequest.httpVersion}${
|
|
619
|
+
logging.headers ? ' ' + headersToString(nodeRequest.headers) : ''
|
|
620
|
+
} ${status}${logging.timing && executionTime ? ' ' + executionTime.toFixed(2) + 'ms' : ''}${requestId ? ' id: ' + requestId : ''}`
|
|
621
|
+
);
|
|
622
|
+
}
|
|
623
|
+
}
|
|
624
|
+
function headersToString(headers: any) {
|
|
625
|
+
const result: string[] = [];
|
|
626
|
+
for (const name in headers) {
|
|
627
|
+
result.push(`${name}: ${headers[name]}`);
|
|
628
|
+
}
|
|
629
|
+
return result.join(', ');
|
|
630
|
+
}
|
|
631
|
+
let nextRequestId: BigInt64Array;
|
|
632
|
+
export function getRequestId() {
|
|
633
|
+
if (!nextRequestId) {
|
|
634
|
+
nextRequestId = new BigInt64Array([1n]);
|
|
635
|
+
nextRequestId = new BigInt64Array(
|
|
636
|
+
databases.system.hdb_analytics.primaryStore.getUserSharedBuffer('next-request-id', nextRequestId.buffer)
|
|
637
|
+
);
|
|
638
|
+
}
|
|
639
|
+
return Number(Atomics.add(nextRequestId, 0, 1n));
|
|
640
|
+
}
|