files.com 1.1.813 → 1.1.815

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.
Files changed (465) hide show
  1. checksums.yaml +4 -4
  2. data/_VERSION +1 -1
  3. data/doc/Files/APIConnectionError.html +1 -1
  4. data/doc/Files/APIError.html +1 -1
  5. data/doc/Files/AccountAlreadyExistsError.html +1 -1
  6. data/doc/Files/AccountLineItem.html +1 -1
  7. data/doc/Files/AccountOverdueError.html +1 -1
  8. data/doc/Files/Action.html +1 -1
  9. data/doc/Files/ActionLog.html +1 -1
  10. data/doc/Files/ActionNotificationExport.html +1 -1
  11. data/doc/Files/ActionNotificationExportResult.html +1 -1
  12. data/doc/Files/AdditionalAuthenticationRequiredError.html +1 -1
  13. data/doc/Files/AgentNode.html +1 -1
  14. data/doc/Files/AgentNodeConnection.html +1 -1
  15. data/doc/Files/AgentNodeInstance.html +1 -1
  16. data/doc/Files/AgentPushUpdate.html +1 -1
  17. data/doc/Files/AgentPushUpdateBlockedError.html +1 -1
  18. data/doc/Files/AgentUnavailableError.html +1 -1
  19. data/doc/Files/AgentUpgradeRequiredError.html +1 -1
  20. data/doc/Files/AiAssistantPersonality.html +1 -1
  21. data/doc/Files/AiTask.html +1 -1
  22. data/doc/Files/AiTaskCannotBeRunManuallyError.html +1 -1
  23. data/doc/Files/AlreadyCompletedError.html +1 -1
  24. data/doc/Files/Api.html +20 -13
  25. data/doc/Files/ApiClient/RequestLogContext.html +29 -29
  26. data/doc/Files/ApiClient/TransferSettings.html +721 -0
  27. data/doc/Files/ApiClient.html +756 -204
  28. data/doc/Files/ApiKey.html +1 -1
  29. data/doc/Files/ApiKeyIsDisabledError.html +1 -1
  30. data/doc/Files/ApiKeyIsPathRestrictedError.html +1 -1
  31. data/doc/Files/ApiKeyNotFoundError.html +1 -1
  32. data/doc/Files/ApiKeyOnlyForDesktopAppError.html +1 -1
  33. data/doc/Files/ApiKeyOnlyForFileOperationsError.html +1 -1
  34. data/doc/Files/ApiKeyOnlyForMobileAppError.html +1 -1
  35. data/doc/Files/ApiKeyOnlyForOfficeIntegrationError.html +1 -1
  36. data/doc/Files/ApiKeySessionsNotSupportedError.html +1 -1
  37. data/doc/Files/ApiRequestLog.html +1 -1
  38. data/doc/Files/App.html +1 -1
  39. data/doc/Files/As2IncomingMessage.html +1 -1
  40. data/doc/Files/As2OutgoingMessage.html +1 -1
  41. data/doc/Files/As2Partner.html +1 -1
  42. data/doc/Files/As2Station.html +1 -1
  43. data/doc/Files/AttachmentTooLargeError.html +1 -1
  44. data/doc/Files/AuthenticationError.html +1 -1
  45. data/doc/Files/AuthenticationRequiredError.html +1 -1
  46. data/doc/Files/Auto.html +1 -1
  47. data/doc/Files/Automation.html +1 -1
  48. data/doc/Files/AutomationAuthoringSchema.html +1 -1
  49. data/doc/Files/AutomationCannotBeRunManuallyError.html +1 -1
  50. data/doc/Files/AutomationExecutionNode.html +1 -1
  51. data/doc/Files/AutomationLog.html +1 -1
  52. data/doc/Files/AutomationRun.html +1 -1
  53. data/doc/Files/AutomationsUnavailableError.html +1 -1
  54. data/doc/Files/BadRequestError.html +1 -1
  55. data/doc/Files/BandwidthSnapshot.html +1 -1
  56. data/doc/Files/Behavior.html +1 -1
  57. data/doc/Files/BehaviorNotAllowedOnRemoteServerError.html +1 -1
  58. data/doc/Files/BillingInformationHiddenError.html +1 -1
  59. data/doc/Files/BillingPermissionRequiredError.html +1 -1
  60. data/doc/Files/BufferedUploadDisabledForThisDestinationError.html +1 -1
  61. data/doc/Files/Bundle.html +1 -1
  62. data/doc/Files/BundleAction.html +1 -1
  63. data/doc/Files/BundleDownload.html +1 -1
  64. data/doc/Files/BundleMaximumUsesReachedError.html +1 -1
  65. data/doc/Files/BundleNotification.html +1 -1
  66. data/doc/Files/BundleOnlyAllowsPreviewsError.html +1 -1
  67. data/doc/Files/BundleOperationRequiresSubfolderError.html +1 -1
  68. data/doc/Files/BundlePath.html +1 -1
  69. data/doc/Files/BundlePathNotFoundError.html +1 -1
  70. data/doc/Files/BundlePermissionRequiredError.html +1 -1
  71. data/doc/Files/BundleRecipient.html +1 -1
  72. data/doc/Files/BundleRegistration.html +1 -1
  73. data/doc/Files/BundleRegistrationCodeFailedError.html +1 -1
  74. data/doc/Files/BundleRegistrationNotFoundError.html +1 -1
  75. data/doc/Files/CannotAdministerHigherLevelUserError.html +1 -1
  76. data/doc/Files/CannotDownloadDirectoryError.html +1 -1
  77. data/doc/Files/CannotLoginWhileUsingKeyError.html +1 -1
  78. data/doc/Files/CantActForOtherUserError.html +1 -1
  79. data/doc/Files/CantMoveWithMultipleLocationsError.html +1 -1
  80. data/doc/Files/ChatMessage.html +1 -1
  81. data/doc/Files/ChatSession.html +1 -1
  82. data/doc/Files/ChildSiteManagementPolicy.html +1 -1
  83. data/doc/Files/Clickwrap.html +1 -1
  84. data/doc/Files/CodeNotFoundError.html +1 -1
  85. data/doc/Files/ConfigurationLockedPathError.html +1 -1
  86. data/doc/Files/ContactAdminForPasswordChangeHelpError.html +1 -1
  87. data/doc/Files/CouldNotCreateParentError.html +1 -1
  88. data/doc/Files/CustomDomain.html +1 -1
  89. data/doc/Files/DatetimeParseError.html +1 -1
  90. data/doc/Files/DesktopConfigurationProfile.html +1 -1
  91. data/doc/Files/DestinationExistsError.html +1 -1
  92. data/doc/Files/DestinationFolderLimitedError.html +1 -1
  93. data/doc/Files/DestinationParentConflictError.html +1 -1
  94. data/doc/Files/DestinationParentDoesNotExistError.html +1 -1
  95. data/doc/Files/DestinationSameError.html +1 -1
  96. data/doc/Files/DestinationSiteMismatchError.html +1 -1
  97. data/doc/Files/DirectConnectionInfo.html +1 -1
  98. data/doc/Files/DnsRecord.html +1 -1
  99. data/doc/Files/DoesNotSupportSortingError.html +1 -1
  100. data/doc/Files/DuplicateShareRecipientError.html +1 -1
  101. data/doc/Files/EmailIncomingMessage.html +1 -1
  102. data/doc/Files/EmailLog.html +1 -1
  103. data/doc/Files/Error.html +2 -2
  104. data/doc/Files/Errors.html +1 -1
  105. data/doc/Files/EventChannel.html +1 -1
  106. data/doc/Files/EventDeliveryAttempt.html +1 -1
  107. data/doc/Files/EventRecord.html +1 -1
  108. data/doc/Files/EventSubscription.html +1 -1
  109. data/doc/Files/EventTarget.html +1 -1
  110. data/doc/Files/ExavaultApiRequestLog.html +1 -1
  111. data/doc/Files/ExceededRuntimeLimitError.html +1 -1
  112. data/doc/Files/Expectation.html +1 -1
  113. data/doc/Files/ExpectationAlreadyHasOpenWindowError.html +1 -1
  114. data/doc/Files/ExpectationEvaluation.html +1 -1
  115. data/doc/Files/ExpectationIncident.html +1 -1
  116. data/doc/Files/ExpectationNotManualTriggerError.html +1 -1
  117. data/doc/Files/ExpiredPrivateKeyError.html +1 -1
  118. data/doc/Files/ExpiredPublicKeyError.html +1 -1
  119. data/doc/Files/ExportFailureError.html +1 -1
  120. data/doc/Files/ExportNotReadyError.html +1 -1
  121. data/doc/Files/ExternalEvent.html +1 -1
  122. data/doc/Files/FailedToChangePasswordError.html +1 -1
  123. data/doc/Files/File.html +2019 -1515
  124. data/doc/Files/FileAction.html +1 -1
  125. data/doc/Files/FileActionError.html +1 -1
  126. data/doc/Files/FileComment.html +1 -1
  127. data/doc/Files/FileCommentReaction.html +1 -1
  128. data/doc/Files/FileLockedError.html +1 -1
  129. data/doc/Files/FileMigration.html +1 -1
  130. data/doc/Files/FileMigrationLog.html +1 -1
  131. data/doc/Files/FileNotFoundError.html +1 -1
  132. data/doc/Files/FileNotUploadedError.html +1 -1
  133. data/doc/Files/FilePendingProcessingError.html +1 -1
  134. data/doc/Files/FileProcessingErrorError.html +1 -1
  135. data/doc/Files/FileTooBigToDecryptError.html +1 -1
  136. data/doc/Files/FileTooBigToEncryptError.html +1 -1
  137. data/doc/Files/FileUploadNotFoundError.html +1 -1
  138. data/doc/Files/FileUploadPart.html +1 -1
  139. data/doc/Files/FileUploadedToWrongRegionError.html +1 -1
  140. data/doc/Files/FileUtils.html +1 -1
  141. data/doc/Files/FilenameTooLongError.html +1 -1
  142. data/doc/Files/FilesAgentFailedAuthorizationError.html +1 -1
  143. data/doc/Files/FilesNativeStorageOverloadedError.html +1 -1
  144. data/doc/Files/Folder.html +1 -1
  145. data/doc/Files/FolderAdminOrBillingPermissionRequiredError.html +1 -1
  146. data/doc/Files/FolderAdminPermissionRequiredError.html +1 -1
  147. data/doc/Files/FolderLockedError.html +1 -1
  148. data/doc/Files/FolderMustNotBeAFileError.html +1 -1
  149. data/doc/Files/FolderNotEmptyError.html +1 -1
  150. data/doc/Files/FoldersNotAllowedError.html +1 -1
  151. data/doc/Files/FormField.html +1 -1
  152. data/doc/Files/FormFieldSet.html +1 -1
  153. data/doc/Files/FtpActionLog.html +1 -1
  154. data/doc/Files/FullPermissionRequiredError.html +1 -1
  155. data/doc/Files/GpgKey.html +1 -1
  156. data/doc/Files/Group.html +1 -1
  157. data/doc/Files/GroupNotFoundError.html +1 -1
  158. data/doc/Files/GroupUser.html +1 -1
  159. data/doc/Files/History.html +1 -1
  160. data/doc/Files/HistoryExport.html +1 -1
  161. data/doc/Files/HistoryExportResult.html +1 -1
  162. data/doc/Files/HistoryPermissionRequiredError.html +1 -1
  163. data/doc/Files/HistoryUnavailableError.html +1 -1
  164. data/doc/Files/HolidayCalendar.html +1 -1
  165. data/doc/Files/HolidayRegion.html +1 -1
  166. data/doc/Files/Image.html +1 -1
  167. data/doc/Files/InAppAiAssistantUnavailableError.html +1 -1
  168. data/doc/Files/InboundS3Log.html +1 -1
  169. data/doc/Files/InboxNotFoundError.html +1 -1
  170. data/doc/Files/InboxRecipient.html +1 -1
  171. data/doc/Files/InboxRegistration.html +1 -1
  172. data/doc/Files/InboxRegistrationCodeFailedError.html +1 -1
  173. data/doc/Files/InboxUpload.html +1 -1
  174. data/doc/Files/InsufficientPermissionForParamsError.html +1 -1
  175. data/doc/Files/InsufficientPermissionForSiteError.html +1 -1
  176. data/doc/Files/IntegrationCentricProfile.html +1 -1
  177. data/doc/Files/InternalGeneralErrorError.html +1 -1
  178. data/doc/Files/InvalidBodyError.html +1 -1
  179. data/doc/Files/InvalidBundleCodeError.html +1 -1
  180. data/doc/Files/InvalidCredentialsError.html +1 -1
  181. data/doc/Files/InvalidCursorError.html +1 -1
  182. data/doc/Files/InvalidCursorTypeForSortError.html +1 -1
  183. data/doc/Files/InvalidEtagsError.html +1 -1
  184. data/doc/Files/InvalidFileTypeError.html +1 -1
  185. data/doc/Files/InvalidFilenameError.html +1 -1
  186. data/doc/Files/InvalidFilterAliasCombinationError.html +1 -1
  187. data/doc/Files/InvalidFilterFieldError.html +1 -1
  188. data/doc/Files/InvalidFilterParamError.html +1 -1
  189. data/doc/Files/InvalidFilterParamFormatError.html +1 -1
  190. data/doc/Files/InvalidFilterParamValueError.html +1 -1
  191. data/doc/Files/InvalidInputEncodingError.html +1 -1
  192. data/doc/Files/InvalidInterfaceError.html +1 -1
  193. data/doc/Files/InvalidOauthError.html +1 -1
  194. data/doc/Files/InvalidOauthProviderError.html +1 -1
  195. data/doc/Files/InvalidOrExpiredCodeError.html +1 -1
  196. data/doc/Files/InvalidParameterError.html +5 -1
  197. data/doc/Files/InvalidPathError.html +1 -1
  198. data/doc/Files/InvalidPriorityColorError.html +1 -1
  199. data/doc/Files/InvalidRangeError.html +1 -1
  200. data/doc/Files/InvalidReturnToUrlError.html +1 -1
  201. data/doc/Files/InvalidSearchQueryError.html +1 -1
  202. data/doc/Files/InvalidSessionError.html +1 -1
  203. data/doc/Files/InvalidSiteError.html +1 -1
  204. data/doc/Files/InvalidSortFieldError.html +1 -1
  205. data/doc/Files/InvalidSortFilterCombinationError.html +1 -1
  206. data/doc/Files/InvalidUploadOffsetError.html +1 -1
  207. data/doc/Files/InvalidUploadPartGapError.html +1 -1
  208. data/doc/Files/InvalidUploadPartSizeError.html +1 -1
  209. data/doc/Files/InvalidUsernameOrPasswordError.html +1 -1
  210. data/doc/Files/InvalidWorkspaceIdHeaderError.html +1 -1
  211. data/doc/Files/InvalidZipFileError.html +1 -1
  212. data/doc/Files/Invoice.html +1 -1
  213. data/doc/Files/InvoiceLineItem.html +1 -1
  214. data/doc/Files/IpAddress.html +1 -1
  215. data/doc/Files/KeyLifecycleRule.html +1 -1
  216. data/doc/Files/List.html +1 -1
  217. data/doc/Files/Lock.html +1 -1
  218. data/doc/Files/LockOperationBusyError.html +1 -1
  219. data/doc/Files/LockedOutError.html +1 -1
  220. data/doc/Files/LockoutRegionMismatchError.html +1 -1
  221. data/doc/Files/MetadataCategory.html +1 -1
  222. data/doc/Files/MetadataNotSupportedOnRemotesError.html +1 -1
  223. data/doc/Files/MethodNotAllowedError.html +1 -1
  224. data/doc/Files/MigrationInProgressError.html +1 -1
  225. data/doc/Files/MissingParameterError.html +1 -1
  226. data/doc/Files/ModelSaveErrorError.html +1 -1
  227. data/doc/Files/MoverAccessDeniedError.html +1 -1
  228. data/doc/Files/MoverPackageRequiredError.html +1 -1
  229. data/doc/Files/MultipleProcessingErrorsError.html +1 -1
  230. data/doc/Files/MultipleSortParamsNotAllowedError.html +1 -1
  231. data/doc/Files/MustAuthenticateWithApiKeyError.html +1 -1
  232. data/doc/Files/NeedAdminPermissionForInboxError.html +1 -1
  233. data/doc/Files/NestedNotFoundError.html +1 -1
  234. data/doc/Files/NoAccountForSiteError.html +1 -1
  235. data/doc/Files/NoValidInputParamsError.html +1 -1
  236. data/doc/Files/NonAdminsMustQueryByFolderOrPathError.html +1 -1
  237. data/doc/Files/NotAllowedToCreateBundleError.html +1 -1
  238. data/doc/Files/NotAuthenticatedError.html +1 -1
  239. data/doc/Files/NotAuthorizedError.html +1 -1
  240. data/doc/Files/NotEnqueuableSyncError.html +1 -1
  241. data/doc/Files/NotFoundError.html +1 -1
  242. data/doc/Files/NotImplementedError.html +1 -1
  243. data/doc/Files/Notification.html +1 -1
  244. data/doc/Files/OffsetUploadNotAllowedWithMalwareScanningError.html +1 -1
  245. data/doc/Files/OneTimePasswordIncorrectError.html +1 -1
  246. data/doc/Files/OutboundConnectionLog.html +1 -1
  247. data/doc/Files/PartNumberTooLargeError.html +1 -1
  248. data/doc/Files/Partner.html +1 -1
  249. data/doc/Files/PartnerChannel.html +1 -1
  250. data/doc/Files/PartnerChannelTemplate.html +1 -1
  251. data/doc/Files/PartnerConnection.html +1 -1
  252. data/doc/Files/PartnerSite.html +1 -1
  253. data/doc/Files/PartnerSiteRequest.html +1 -1
  254. data/doc/Files/PasswordChangeNotRequiredError.html +1 -1
  255. data/doc/Files/PasswordChangeRequiredError.html +1 -1
  256. data/doc/Files/PathCannotHaveTrailingWhitespaceError.html +1 -1
  257. data/doc/Files/PathTooLongError.html +1 -1
  258. data/doc/Files/PathUtil.html +1 -1
  259. data/doc/Files/Payment.html +1 -1
  260. data/doc/Files/PaymentLineItem.html +1 -1
  261. data/doc/Files/PaymentMethodErrorError.html +1 -1
  262. data/doc/Files/PendingWorkEvent.html +1 -1
  263. data/doc/Files/Permission.html +1 -1
  264. data/doc/Files/PlanNotFoundError.html +1 -1
  265. data/doc/Files/Preview.html +1 -1
  266. data/doc/Files/PreviewOnlyPermissionCannotDownloadError.html +1 -1
  267. data/doc/Files/ProcessingFailureError.html +1 -1
  268. data/doc/Files/PublicHostingRequestLog.html +1 -1
  269. data/doc/Files/PublicIpAddress.html +1 -1
  270. data/doc/Files/PublicKey.html +1 -1
  271. data/doc/Files/RateLimitedError.html +1 -1
  272. data/doc/Files/ReadOnlySessionError.html +1 -1
  273. data/doc/Files/ReadPermissionRequiredError.html +1 -1
  274. data/doc/Files/ReauthenticationFailedError.html +1 -1
  275. data/doc/Files/ReauthenticationFailedFinalError.html +1 -1
  276. data/doc/Files/ReauthenticationNeededActionError.html +1 -1
  277. data/doc/Files/ReauthenticationNeededFieldsError.html +1 -1
  278. data/doc/Files/ReauthenticationRateLimitedError.html +1 -1
  279. data/doc/Files/RecaptchaFailedError.html +1 -1
  280. data/doc/Files/RecipientAlreadySharedError.html +1 -1
  281. data/doc/Files/RemoteBandwidthSnapshot.html +1 -1
  282. data/doc/Files/RemoteDesktopDebugLoggingDisabledError.html +1 -1
  283. data/doc/Files/RemoteEntryReadOnlyError.html +1 -1
  284. data/doc/Files/RemoteMountBackend.html +1 -1
  285. data/doc/Files/RemoteServer.html +1 -1
  286. data/doc/Files/RemoteServerConfigurationFile.html +1 -1
  287. data/doc/Files/RemoteServerCredential.html +1 -1
  288. data/doc/Files/RemoteServerErrorError.html +1 -1
  289. data/doc/Files/Request.html +1 -1
  290. data/doc/Files/RequestBodyTooLargeError.html +1 -1
  291. data/doc/Files/RequestParamsContainInvalidCharacterError.html +1 -1
  292. data/doc/Files/RequestParamsInvalidError.html +1 -1
  293. data/doc/Files/RequestParamsRequiredError.html +1 -1
  294. data/doc/Files/ResourceBelongsToParentSiteError.html +1 -1
  295. data/doc/Files/ResourceLockedError.html +1 -1
  296. data/doc/Files/Response.html +1 -1
  297. data/doc/Files/Restore.html +1 -1
  298. data/doc/Files/RootFolderBehaviorSiteAdminRequiredError.html +1 -1
  299. data/doc/Files/RootFolderBehaviorSkipSiteAdminRequiredError.html +1 -1
  300. data/doc/Files/Schedule.html +1 -1
  301. data/doc/Files/ScheduledExport.html +1 -1
  302. data/doc/Files/ScimLog.html +1 -1
  303. data/doc/Files/SearchAllOnChildPathError.html +1 -1
  304. data/doc/Files/SearchUnavailableError.html +1 -1
  305. data/doc/Files/Secret.html +1 -1
  306. data/doc/Files/SelfManagedRequiredError.html +1 -1
  307. data/doc/Files/ServiceUnavailableError.html +1 -1
  308. data/doc/Files/Session.html +1 -1
  309. data/doc/Files/SettingsChange.html +1 -1
  310. data/doc/Files/SftpActionLog.html +1 -1
  311. data/doc/Files/SftpHostKey.html +1 -1
  312. data/doc/Files/ShareGroup.html +1 -1
  313. data/doc/Files/ShareGroupMember.html +1 -1
  314. data/doc/Files/SiemHttpDestination.html +1 -1
  315. data/doc/Files/SiemHttpDestinationEvent.html +1 -1
  316. data/doc/Files/Site.html +911 -731
  317. data/doc/Files/SiteAdminOrPartnerAdminPermissionRequiredError.html +1 -1
  318. data/doc/Files/SiteAdminOrWorkspaceAdminOrFolderAdminPermissionRequiredError.html +1 -1
  319. data/doc/Files/SiteAdminOrWorkspaceAdminOrPartnerAdminOrFolderAdminPermissionRequiredError.html +1 -1
  320. data/doc/Files/SiteAdminOrWorkspaceAdminOrPartnerAdminPermissionRequiredError.html +1 -1
  321. data/doc/Files/SiteAdminOrWorkspaceAdminPermissionRequiredError.html +1 -1
  322. data/doc/Files/SiteAdminRequiredError.html +1 -1
  323. data/doc/Files/SiteConfigurationError.html +1 -1
  324. data/doc/Files/SiteDisabledError.html +1 -1
  325. data/doc/Files/SiteFilesAreImmutableError.html +1 -1
  326. data/doc/Files/SiteNotFoundError.html +1 -1
  327. data/doc/Files/SiteSubdomainRedirect.html +1 -1
  328. data/doc/Files/SiteWasRemovedError.html +1 -1
  329. data/doc/Files/SizableIO.html +1 -1
  330. data/doc/Files/Snapshot.html +1 -1
  331. data/doc/Files/SsoEvent.html +1 -1
  332. data/doc/Files/SsoStrategy.html +1 -1
  333. data/doc/Files/Status.html +1 -1
  334. data/doc/Files/Style.html +1 -1
  335. data/doc/Files/SubfolderLockedError.html +1 -1
  336. data/doc/Files/Sync.html +1 -1
  337. data/doc/Files/SyncInProgressError.html +1 -1
  338. data/doc/Files/SyncLog.html +1 -1
  339. data/doc/Files/SyncRun.html +1 -1
  340. data/doc/Files/SyncRunLiveTransfer.html +1 -1
  341. data/doc/Files/SystemProfiler.html +1 -1
  342. data/doc/Files/TooManyConcurrentLoginsError.html +1 -1
  343. data/doc/Files/TooManyConcurrentRequestsError.html +1 -1
  344. data/doc/Files/TooManyLoginAttemptsError.html +1 -1
  345. data/doc/Files/TooManyRequestsError.html +1 -1
  346. data/doc/Files/TooManySharesError.html +1 -1
  347. data/doc/Files/Transfer/BufferLimitError.html +175 -0
  348. data/doc/Files/Transfer/ByteBudget/Reservation.html +301 -0
  349. data/doc/Files/Transfer/ByteBudget.html +748 -0
  350. data/doc/Files/Transfer/CancelledError.html +235 -0
  351. data/doc/Files/Transfer/Checkpoint.html +1371 -0
  352. data/doc/Files/Transfer/CheckpointError.html +173 -0
  353. data/doc/Files/Transfer/ClientTransport/ClientResponse.html +661 -0
  354. data/doc/Files/Transfer/ClientTransport/Reader.html +530 -0
  355. data/doc/Files/Transfer/ClientTransport.html +675 -0
  356. data/doc/Files/Transfer/Clock.html +189 -0
  357. data/doc/Files/Transfer/Control.html +667 -0
  358. data/doc/Files/Transfer/Controller/Attempt.html +465 -0
  359. data/doc/Files/Transfer/Controller.html +1166 -0
  360. data/doc/Files/Transfer/Coordinator/Timing.html +568 -0
  361. data/doc/Files/Transfer/Coordinator.html +534 -0
  362. data/doc/Files/Transfer/DownloadCoordinator/FileSink.html +976 -0
  363. data/doc/Files/Transfer/DownloadCoordinator/IoSink.html +1168 -0
  364. data/doc/Files/Transfer/DownloadCoordinator/Piece.html +875 -0
  365. data/doc/Files/Transfer/DownloadCoordinator.html +728 -0
  366. data/doc/Files/Transfer/FileSlots.html +480 -0
  367. data/doc/Files/Transfer/FrontendResponseError.html +235 -0
  368. data/doc/Files/Transfer/Holds.html +505 -0
  369. data/doc/Files/Transfer/HttpTransport.html +579 -0
  370. data/doc/Files/Transfer/Job.html +2338 -0
  371. data/doc/Files/Transfer/Options.html +924 -0
  372. data/doc/Files/Transfer/PausedError.html +319 -0
  373. data/doc/Files/Transfer/Policy.html +1642 -0
  374. data/doc/Files/Transfer/RequestPermits.html +160 -0
  375. data/doc/Files/Transfer/SourceChangedError.html +235 -0
  376. data/doc/Files/Transfer/StorageResponse.html +546 -0
  377. data/doc/Files/Transfer/StorageRetry.html +1098 -0
  378. data/doc/Files/Transfer/UploadCoordinator/Grant.html +1048 -0
  379. data/doc/Files/Transfer/UploadCoordinator/Part.html +1048 -0
  380. data/doc/Files/Transfer/UploadCoordinator/Region.html +295 -0
  381. data/doc/Files/Transfer/UploadCoordinator/Segments.html +299 -0
  382. data/doc/Files/Transfer/UploadCoordinator/Source.html +725 -0
  383. data/doc/Files/Transfer/UploadCoordinator/StreamSource.html +664 -0
  384. data/doc/Files/Transfer/UploadCoordinator.html +546 -0
  385. data/doc/Files/Transfer/UploadPlan.html +522 -0
  386. data/doc/Files/Transfer/VersionChangedError.html +235 -0
  387. data/doc/Files/Transfer.html +134 -0
  388. data/doc/Files/TrialExpiredError.html +1 -1
  389. data/doc/Files/TrialLockedError.html +1 -1
  390. data/doc/Files/TwoFactorAuthenticationCodeAlreadySentError.html +1 -1
  391. data/doc/Files/TwoFactorAuthenticationCountryBlacklistedError.html +1 -1
  392. data/doc/Files/TwoFactorAuthenticationErrorError.html +1 -1
  393. data/doc/Files/TwoFactorAuthenticationGeneralErrorError.html +1 -1
  394. data/doc/Files/TwoFactorAuthenticationMethodUnsupportedErrorError.html +1 -1
  395. data/doc/Files/TwoFactorAuthenticationRequiredError.html +1 -1
  396. data/doc/Files/TwoFactorAuthenticationSetupExpiredError.html +1 -1
  397. data/doc/Files/TwoFactorAuthenticationUnsubscribedRecipientError.html +1 -1
  398. data/doc/Files/URI.html +1 -1
  399. data/doc/Files/UnrecognizedSortIndexError.html +1 -1
  400. data/doc/Files/UnsupportedCurrencyError.html +1 -1
  401. data/doc/Files/UnsupportedHttpResponseFormatError.html +1 -1
  402. data/doc/Files/UnsupportedMediaTypeError.html +1 -1
  403. data/doc/Files/UpdatesNotAllowedForRemotesError.html +1 -1
  404. data/doc/Files/UploadsUnavailableError.html +1 -1
  405. data/doc/Files/UsageByTopLevelDir.html +1 -1
  406. data/doc/Files/UsageDailySnapshot.html +1 -1
  407. data/doc/Files/UsageSnapshot.html +1 -1
  408. data/doc/Files/User.html +597 -386
  409. data/doc/Files/UserAdditionalEmailRecipient.html +1 -1
  410. data/doc/Files/UserCipherUse.html +1 -1
  411. data/doc/Files/UserIdInvalidError.html +1 -1
  412. data/doc/Files/UserIdOnUserEndpointError.html +1 -1
  413. data/doc/Files/UserIdWithoutSiteAdminError.html +1 -1
  414. data/doc/Files/UserLifecycleRule.html +1 -1
  415. data/doc/Files/UserNotFoundError.html +1 -1
  416. data/doc/Files/UserRequest.html +1 -1
  417. data/doc/Files/UserRequestsEnabledRequiredError.html +1 -1
  418. data/doc/Files/UserRequiredError.html +1 -1
  419. data/doc/Files/UserSecurityEvent.html +1 -1
  420. data/doc/Files/UserSftpClientUse.html +1 -1
  421. data/doc/Files/Util/LogSettings.html +1 -1
  422. data/doc/Files/Util.html +1 -1
  423. data/doc/Files/WebDavActionLog.html +1 -1
  424. data/doc/Files/WebhookTest.html +1 -1
  425. data/doc/Files/Workspace.html +1 -1
  426. data/doc/Files/WriteAndBundlePermissionRequiredError.html +1 -1
  427. data/doc/Files/WritePermissionRequiredError.html +1 -1
  428. data/doc/Files/ZipListEntry.html +1 -1
  429. data/doc/Files.html +116 -116
  430. data/doc/_index.html +314 -4
  431. data/doc/class_list.html +1 -1
  432. data/doc/file.README.html +1 -1
  433. data/doc/index.html +1 -1
  434. data/doc/method_list.html +5368 -3048
  435. data/doc/top-level-namespace.html +1 -1
  436. data/docs/file.md +346 -0
  437. data/docs/site.md +10 -0
  438. data/docs/user.md +8 -0
  439. data/lib/files.com/api.rb +6 -1
  440. data/lib/files.com/api_client.rb +220 -32
  441. data/lib/files.com/models/file.rb +124 -17
  442. data/lib/files.com/models/site.rb +16 -0
  443. data/lib/files.com/models/user.rb +19 -0
  444. data/lib/files.com/transfer/budgets.rb +123 -0
  445. data/lib/files.com/transfer/checkpoint.rb +113 -0
  446. data/lib/files.com/transfer/clock.rb +14 -0
  447. data/lib/files.com/transfer/controller.rb +549 -0
  448. data/lib/files.com/transfer/download_coordinator.rb +906 -0
  449. data/lib/files.com/transfer/errors.rb +100 -0
  450. data/lib/files.com/transfer/http_transport.rb +337 -0
  451. data/lib/files.com/transfer/job.rb +778 -0
  452. data/lib/files.com/transfer/options.rb +126 -0
  453. data/lib/files.com/transfer/policy.rb +91 -0
  454. data/lib/files.com/transfer/storage_retry.rb +169 -0
  455. data/lib/files.com/transfer/upload_coordinator.rb +657 -0
  456. data/lib/files.com/transfer/upload_plan.rb +157 -0
  457. data/lib/files.com.rb +13 -0
  458. data/spec/lib/api_client_spec.rb +125 -3
  459. data/spec/models/file_transfer_spec.rb +53 -4
  460. data/spec/support/transfer_server.rb +113 -14
  461. data/spec/transfer/adaptive_download_spec.rb +1102 -0
  462. data/spec/transfer/adaptive_upload_spec.rb +1602 -0
  463. data/spec/transfer/concurrency_controller_spec.rb +382 -0
  464. data/spec/workspace_id_spec.rb +19 -14
  465. metadata +59 -1
@@ -76,6 +76,7 @@ module Files
76
76
  end
77
77
 
78
78
  def self.build_default_conn(force_net_http: false)
79
+ proxy = Files.proxy
79
80
  conn = Faraday.new do |builder|
80
81
  if Gem::Version.new(Faraday::VERSION) < Gem::Version.new("2.0.0") && defined?(Faraday::Request::Multipart)
81
82
  begin
@@ -98,12 +99,120 @@ module Files
98
99
  end
99
100
  end
100
101
 
101
- conn.proxy = Files.proxy if Files.proxy
102
+ conn.proxy = proxy if proxy
102
103
  conn.ssl.verify = true
104
+ # How it was made, and with which proxy, so unchanged_default_conn? can tell whether anything about it has changed
105
+ # since.
106
+ conn.instance_variable_set(:@files_sdk_configuration, [ connection_configuration(conn), proxy_identity(proxy) ].freeze)
103
107
 
104
108
  conn
105
109
  end
106
110
 
111
+ # Whether conn is a connection build_default_conn made with proxy, as proxy_identity gives it (nil when it was given
112
+ # none, so it follows the proxy environment variables), with nothing about it changed since: the same middleware and
113
+ # adapter (the same objects, so neither another adapter nor one with a configuration block of its own), and the same
114
+ # TLS, request and proxy options, default headers and default parameters. An adaptive transfer sends over its own
115
+ # connections, made with its own proxy, in place of only such a connection with that same proxy; through any other,
116
+ # such as one with a minimum TLS version or another proxy, it sends as that connection does.
117
+ def self.unchanged_default_conn?(conn, proxy)
118
+ return false unless conn.is_a?(Faraday::Connection)
119
+
120
+ conn.instance_variable_get(:@files_sdk_configuration) == [ connection_configuration(conn), proxy ]
121
+ end
122
+
123
+ # A Files.proxy value, a URL or a Hash of its uri, user and password, as one frozen [URL, user, password], its user
124
+ # and password included, or nil for none.
125
+ def self.proxy_identity(proxy)
126
+ options = proxy && Faraday::ProxyOptions.from(proxy)
127
+ options&.uri && [ options.uri.to_s, options.user, options.password ].freeze
128
+ end
129
+
130
+ private_class_method def self.connection_configuration(conn)
131
+ [ conn.builder.handlers.map(&:object_id), conn.builder.adapter&.object_id, conn.ssl.to_hash, conn.options.to_hash,
132
+ conn.headers.to_h { |name, value| [ name.dup, value.dup ] }, conn.params.to_h { |name, value| [ name.dup, value.dup ] }, conn.proxy&.to_hash ].freeze
133
+ end
134
+
135
+ # Runs the block with each transfer request this thread sends through remote_request sent once: a failure is
136
+ # logged as usual but neither retried nor converted, so Faraday's own error, with any response it got, reaches
137
+ # the caller. An adaptive transfer sends its content requests through a caller's client this way, since it
138
+ # schedules and counts every retry itself.
139
+ def self.single_attempt
140
+ previous = Thread.current[:files_api_client_single_attempt]
141
+ Thread.current[:files_api_client_single_attempt] = true
142
+ yield
143
+ ensure
144
+ Thread.current[:files_api_client_single_attempt] = previous
145
+ end
146
+
147
+ # What an adaptive transfer's API requests use in place of the library-wide settings, fixed on the caller's thread
148
+ # as the transfer begins (transfer_settings) and passed as their request_settings option.
149
+ TransferSettings = Struct.new(:default_headers, :language, :app_info, :open_timeout, :read_timeout, :region_policy, :region_handler, keyword_init: true)
150
+
151
+ # The library-wide settings as they are now: frozen copies of Files.default_headers (a Proc is kept as it is, and
152
+ # still called for each request), Files.language and Files.app_info, the timeouts, Files.region_policy, and
153
+ # Files.region_handler, kept as it is. A request given them uses them instead of the library-wide ones, and never
154
+ # falls back to Files.api_key or Files.session_id: a credential it was not given stays absent.
155
+ def self.transfer_settings
156
+ TransferSettings.new(default_headers: settings_copy(Files.default_headers), language: settings_copy(Files.language), app_info: settings_copy(Files.app_info),
157
+ open_timeout: Files.open_timeout, read_timeout: Files.read_timeout, region_policy: Files.region_policy,
158
+ region_handler: Files.region_handler
159
+ ).freeze
160
+ end
161
+
162
+ # A frozen copy of value's Hashes, Arrays and Strings, all the way down; anything else, such as a Proc, as it is.
163
+ private_class_method def self.settings_copy(value)
164
+ case value
165
+ when Hash then value.to_h { |key, item| [ settings_copy(key), settings_copy(item) ] }.freeze
166
+ when Array then value.map { |item| settings_copy(item) }.freeze
167
+ when String then value.dup.freeze
168
+ else value
169
+ end
170
+ end
171
+
172
+ # The comment the SDK's own User-Agent ends with, and the most bytes that comment and the whole User-Agent may take.
173
+ USER_AGENT_METADATA_MARKER = "files-sdk-meta/1"
174
+ MAX_USER_AGENT_BYTES = 190
175
+ MAX_USER_AGENT_METADATA_BYTES = 128
176
+ private_constant :USER_AGENT_METADATA_MARKER, :MAX_USER_AGENT_BYTES, :MAX_USER_AGENT_METADATA_BYTES
177
+
178
+ # The User-Agent the SDK sends with its own API requests: identity, the SDK's name and version and any app info,
179
+ # followed by one comment naming the coarse family of the operating system host_os (RbConfig's) names and the Ruby
180
+ # runtime, with ruby_version for CRuby, such as "Files.com Ruby SDK v1.2.3 (files-sdk-meta/1; os=linux;
181
+ # runtime=ruby/3.4.4)". The comment carries nothing else: no host or user name, path, architecture or build. A
182
+ # version it cannot carry as given is left out rather than changed. When the whole User-Agent would be longer than
183
+ # 190 bytes, the version is left out first and then the whole comment, so identity is always sent as it is; an
184
+ # identity that is not printable ASCII, such as one whose app info is not, gets no comment. A User-Agent from
185
+ # Files.default_headers or a request's own headers is sent instead, exactly as given, and a transfer request
186
+ # (remote_request) sends only the headers it is given.
187
+ def self.user_agent_with_metadata(identity, host_os: RbConfig::CONFIG["host_os"], ruby_engine: RUBY_ENGINE, ruby_version: RUBY_VERSION)
188
+ return identity unless identity.is_a?(String) && identity.ascii_only? && identity.match?(/\A[\x20-\x7e]+\z/)
189
+
190
+ carried = ruby_engine == "ruby" && ruby_version.is_a?(String) && ruby_version.ascii_only? && ruby_version.match?(/\A[0-9][A-Za-z0-9.+_-]{0,47}\z/)
191
+ runtimes = carried ? [ "ruby/#{ruby_version}", "ruby" ] : [ "ruby" ]
192
+ os = user_agent_os(host_os)
193
+ runtimes.each do |runtime|
194
+ metadata = " (#{USER_AGENT_METADATA_MARKER}; os=#{os}; runtime=#{runtime})"
195
+ return "#{identity}#{metadata}" if metadata.bytesize <= MAX_USER_AGENT_METADATA_BYTES && identity.bytesize + metadata.bytesize <= MAX_USER_AGENT_BYTES
196
+ end
197
+ identity
198
+ end
199
+
200
+ # The coarse family of the operating system RbConfig's host_os names: "unknown" for none, and "other" for one the
201
+ # User-Agent's comment does not name.
202
+ private_class_method def self.user_agent_os(host_os)
203
+ return "unknown" unless host_os.is_a?(String) && !host_os.empty?
204
+ return "other" unless host_os.ascii_only?
205
+
206
+ case host_os
207
+ when /mswin|mingw|cygwin/i then "windows"
208
+ when /darwin/i then "macos"
209
+ when /android/i then "android"
210
+ when /linux/i then "linux"
211
+ when /freebsd/i then "freebsd"
212
+ else "other"
213
+ end
214
+ end
215
+
107
216
  def self.should_retry?(error, num_retries)
108
217
  return false if num_retries >= Files.max_network_retries
109
218
  return true if error.is_a?(Faraday::TimeoutError)
@@ -144,13 +253,15 @@ module Files
144
253
  end
145
254
 
146
255
  # Returns the response and the API key and session ID the request used. +region_http_pairs+, such as the pairs a
147
- # returned record keeps, is used instead of this client's. The block, if given, receives the request's context once
148
- # its response has arrived: the regional origin a lockout region mismatch moved it to, or nil, and the frozen
149
- # region_http_pairs it used.
150
- def execute_request(method, path, base_url: nil, api_key: nil, session_id: nil, workspace_id: nil, region_http_pairs: nil, headers: {}, params: {}, &on_request_context)
256
+ # returned record keeps, is used instead of this client's. +settings+, an adaptive transfer's TransferSettings, is
257
+ # used instead of the library-wide default headers, language, app info, timeouts and region policy and handler, and
258
+ # with it a credential the request was not given is not looked up in Files.api_key or Files.session_id. The block,
259
+ # if given, receives the request's context once its response has arrived: the regional origin a lockout region
260
+ # mismatch moved it to, or nil, and the frozen region_http_pairs it used.
261
+ def execute_request(method, path, base_url: nil, api_key: nil, session_id: nil, workspace_id: nil, region_http_pairs: nil, settings: nil, headers: {}, params: {}, &on_request_context)
151
262
  base_url ||= Files.base_url
152
263
  if api_key.nil?
153
- session_id ||= Files.session_id
264
+ session_id ||= Files.session_id unless settings
154
265
  else
155
266
  session_id = nil
156
267
  end
@@ -159,7 +270,7 @@ module Files
159
270
  if session_id and session_id != ""
160
271
  check_session_id!(session_id)
161
272
  elsif path !~ /^\/sessions/ # TODO: automate this to refer to any unauthenticated endpoint
162
- api_key ||= Files.api_key
273
+ api_key ||= Files.api_key unless settings
163
274
  check_api_key!(api_key)
164
275
  end
165
276
 
@@ -172,7 +283,7 @@ module Files
172
283
  body = params
173
284
  end
174
285
 
175
- headers = request_headers(api_key, session_id, method, workspace_id).update(headers)
286
+ headers = request_headers(api_key, session_id, method, workspace_id, settings).update(headers)
176
287
  url = api_url(path, base_url)
177
288
 
178
289
  context = RequestLogContext.new
@@ -188,15 +299,15 @@ module Files
188
299
  # Fixed before the request starts, so later changes to the caller's or the library-wide pairs cannot affect it.
189
300
  http_pairs = region_http_pairs.nil? ? self.region_http_pairs : Util.checked_region_http_pairs(region_http_pairs)
190
301
  relocate = lambda do |error_response|
191
- regional_base_url = region_continuation_base_url(error_response, base_url, body, http_pairs)
302
+ regional_base_url = region_continuation_base_url(error_response, base_url, body, http_pairs, settings)
192
303
  url = api_url(path, regional_base_url) if regional_base_url
193
304
  regional_base_url
194
305
  end
195
306
 
196
307
  http_resp = execute_request_with_rescues(base_url, context, relocate: relocate) do
197
308
  conn.run_request(method, url, body, headers) do |req|
198
- req.options.open_timeout = Files.open_timeout
199
- req.options.timeout = Files.read_timeout
309
+ req.options.open_timeout = setting(settings, :open_timeout)
310
+ req.options.timeout = setting(settings, :read_timeout)
200
311
  req.params = query_params unless query_params.nil?
201
312
  end
202
313
  end
@@ -212,26 +323,59 @@ module Files
212
323
  [ resp, api_key, session_id ]
213
324
  end
214
325
 
326
+ # Whether this client sends transfer requests just as the SDK's own default client does: an ApiClient itself, not
327
+ # a subclass or an object with methods of its own, with no logger or log level of its own. Only then may an
328
+ # adaptive transfer send its content requests over its own connections instead of through remote_request.
329
+ def default_transfer_behavior?
330
+ instance_of?(ApiClient) && singleton_methods.empty? && @logger.equal?(USE_GLOBAL) && @log_level.equal?(USE_GLOBAL)
331
+ end
332
+
333
+ # The workspace_id option that names, for every later request, the workspace this client's requests name now when
334
+ # their own workspace_id is nil: its own, or Files.workspace_id, and "" for none. An adaptive upload fixes it as it
335
+ # begins, so a later change to Files.workspace_id cannot move it.
336
+ def resolved_workspace_id
337
+ workspace_id = default_workspace_id
338
+ workspace_id.nil? ? "" : workspace_id
339
+ end
340
+
341
+ # Sends a request to a transfer URL, such as a signed storage URL, through this client's connection, with its
342
+ # middleware, adapter, settings and logging. The URL's query reaches the adapter as URI parses it (SignedQuery): the
343
+ # request's params, the connection's default ones included, are not added to it, unlike an API request's. URI keeps
344
+ # its order, its percent escapes and the characters a signed URL's query uses, so such a query arrives exactly as
345
+ # given, as its signature needs; it escapes others, such as a space, and drops tabs and line breaks. A URL URI cannot
346
+ # parse, as one with %zz in its query or a character outside ASCII, is left to Faraday as it is, which refuses it
347
+ # or sends its query decoded and encoded again, as it does any params.
215
348
  def remote_request(method, url, headers = {}, body = nil)
216
349
  context = RequestLogContext.new
217
350
  context.method = method
218
351
  context.path = "[transfer]"
219
352
  Util.log_debug("Transfer request", method: method, url: url)
353
+ query = transfer_query(url)
220
354
 
221
355
  execute_request_with_rescues(Files.base_url, context, skip_body_logging: true, is_transfer: true) do
222
356
  conn.run_request(method, url, body, headers) do |req|
223
357
  req.options.open_timeout = Files.open_timeout
224
358
  req.options.timeout = Files.read_timeout
359
+ req.options.params_encoder = SignedQuery.new(query, req.options.params_encoder || Faraday::Utils.default_params_encoder) if query
225
360
  yield(req) if block_given?
226
361
  end
227
362
  end
228
363
  end
229
364
 
365
+ # The query a request to a transfer URL carries to the adapter (SignedQuery): the one URI parses from the URL, ""
366
+ # for none, or nil when URI cannot parse it.
367
+ private def transfer_query(url)
368
+ ::URI.parse(url.to_s).query || ""
369
+ rescue ::URI::InvalidURIError
370
+ nil
371
+ end
372
+
230
373
  def stream_download(uri, io, range)
231
374
  if conn.adapter == Faraday::Adapter::NetHttp
232
375
  stream_download_with_net_http(URI(uri), io, range)
233
376
  else
234
377
  response = remote_request(:get, uri)
378
+ reject_frontend_response(response.headers.key?(Transfer::StorageRetry::FRONTEND_HEADER), io)
235
379
  io.fulfill_content_length(response.content_length) if io.respond_to?(:fulfill_content_length)
236
380
  io.write(response.body)
237
381
  end
@@ -261,6 +405,7 @@ module Files
261
405
 
262
406
  private def write_download_body(response, io)
263
407
  reject_unsuccessful_download(response, io)
408
+ reject_frontend_response(response.key?(Transfer::StorageRetry::FRONTEND_HEADER), io)
264
409
  io.fulfill_content_length(response.content_length) if io.respond_to?(:fulfill_content_length)
265
410
 
266
411
  expected_bytes = expected_download_bytes(response)
@@ -298,6 +443,16 @@ module Files
298
443
  raise
299
444
  end
300
445
 
446
+ # A response carrying X-Files-Frontend-App came from the Files.com web app, such as a sign-in page, not from file
447
+ # storage. It is refused before anything of it is written, and closes the destination as a refused transfer does.
448
+ private def reject_frontend_response(frontend, io)
449
+ return unless frontend
450
+
451
+ error = Transfer::FrontendResponseError.new
452
+ close_destination_after_failure(io, error)
453
+ raise error
454
+ end
455
+
301
456
  private def write_download_chunk(io, chunk)
302
457
  io << chunk
303
458
  rescue StandardError => e
@@ -344,9 +499,10 @@ module Files
344
499
  # with that error, naming the site's own origin in data.host or X-Files-Host, when the site is pinned to another
345
500
  # region or to a custom domain. Only the configured HTTPS origin, reached over this client's verified connection, may send the
346
501
  # credentials elsewhere, apart from an http:// origin to the destination +http_pairs+ pairs it with.
347
- private def region_continuation_base_url(error_response, base_url, body, http_pairs)
348
- return if Files.region_policy == :disabled
502
+ private def region_continuation_base_url(error_response, base_url, body, http_pairs, settings = nil)
503
+ return if setting(settings, :region_policy) == :disabled
349
504
 
505
+ handler = setting(settings, :region_handler)
350
506
  error_object = error_response.data
351
507
  return unless error_response.http_status == 403 && error_object[:type] == "not-authenticated/lockout-region-mismatch"
352
508
  return unless replayable?(body)
@@ -356,7 +512,7 @@ module Files
356
512
 
357
513
  host = data && data[:host]
358
514
  host = Faraday::Utils::Headers.new(error_response.http_headers || {})["X-Files-Host"] if host.nil? || host == ""
359
- return http_pair_origin(base_url, host, http_pairs) unless verified_https_connection?(base_url)
515
+ return http_pair_origin(base_url, host, http_pairs, handler) unless verified_https_connection?(base_url)
360
516
 
361
517
  configured = Addressable::URI.parse(base_url)
362
518
  original_origin = https_origin(configured.normalized_host, configured.inferred_port)
@@ -364,8 +520,8 @@ module Files
364
520
  # A mismatch that names the origin it came from cannot be resolved by moving, so the handler is not asked.
365
521
  return if target_origin.nil? || target_origin == original_origin
366
522
 
367
- if Files.region_handler
368
- target_origin = approved_region_origin(original_origin, target_origin, approval_required) { |decision| region_target(decision)&.first }
523
+ if handler
524
+ target_origin = approved_region_origin(handler, original_origin, target_origin, approval_required) { |decision| region_target(decision)&.first }
369
525
  elsif approval_required
370
526
  return
371
527
  end
@@ -375,12 +531,13 @@ module Files
375
531
  target_origin
376
532
  end
377
533
 
378
- # The origin Files.region_handler approves: the target for true, or another origin it returns that the block gives
379
- # back unchanged, as the canonical form of an origin the request may move to. nil when it declines. The handler
380
- # gets frozen copies, so it cannot change the origins used here.
381
- private def approved_region_origin(original_origin, target_origin, approval_required)
534
+ # The origin the region handler (Files.region_handler, or the one an adaptive transfer began with) approves: the
535
+ # target for true, or another origin it returns that the block gives back unchanged, as the canonical form of an
536
+ # origin the request may move to. nil when it declines. The handler gets frozen copies, so it cannot change the
537
+ # origins used here.
538
+ private def approved_region_origin(handler, original_origin, target_origin, approval_required)
382
539
  event = { reason: :lockout_region_mismatch, original_origin: original_origin.dup.freeze, target_origin: target_origin.dup.freeze, approval_required: approval_required }.freeze
383
- decision = Files.region_handler.call(event)
540
+ decision = handler.call(event)
384
541
  return target_origin if decision == true
385
542
  return unless decision.is_a?(String)
386
543
 
@@ -393,13 +550,13 @@ module Files
393
550
  # continue. Within it a bare host means that host over plain HTTP, on port 80 unless it names another port. The
394
551
  # region handler may still decline, or choose another destination paired with the same source; the request then
395
552
  # continues at that pair's own frozen destination, not at the String the handler returned.
396
- private def http_pair_origin(base_url, host, http_pairs)
553
+ private def http_pair_origin(base_url, host, http_pairs, handler)
397
554
  original_origin = Util.http_origin(base_url)
398
555
  target_origin = Util.http_origin(host.is_a?(String) && !host.include?("://") ? "http://#{host}" : host)
399
556
  return unless original_origin && target_origin != original_origin && http_pairs.include?([ original_origin, target_origin ])
400
557
 
401
- if Files.region_handler
402
- target_origin = approved_region_origin(original_origin, target_origin, false) do |decision|
558
+ if handler
559
+ target_origin = approved_region_origin(handler, original_origin, target_origin, false) do |decision|
403
560
  http_pairs.find { |source, destination| source == original_origin && destination == decision }&.last
404
561
  end
405
562
  end
@@ -499,13 +656,15 @@ module Files
499
656
  log_response_error(error_context, request_start, e)
500
657
  end
501
658
 
502
- if self.class.should_retry?(e, num_retries)
659
+ single_attempt = is_transfer && Thread.current[:files_api_client_single_attempt]
660
+ if !single_attempt && self.class.should_retry?(e, num_retries)
503
661
  num_retries += 1
504
662
  wait_seconds = self.class.sleep_time(num_retries)
505
663
  log_retry(context, num_retries, e, wait_seconds) unless is_transfer
506
664
  sleep wait_seconds
507
665
  retry
508
666
  end
667
+ raise if single_attempt
509
668
 
510
669
  Util.log_debug("Transfer error details", error_message: e.message) if is_transfer
511
670
 
@@ -692,25 +851,33 @@ module Files
692
851
  raise APIConnectionError, message
693
852
  end
694
853
 
695
- private def request_headers(api_key, session_id, method, workspace_id)
854
+ # The library-wide setting name, or, for an adaptive transfer's request, what its TransferSettings hold for it.
855
+ private def setting(settings, name)
856
+ settings ? settings[name] : Files.public_send(name)
857
+ end
858
+
859
+ private def request_headers(api_key, session_id, method, workspace_id, settings = nil)
860
+ app_info = setting(settings, :app_info)
696
861
  user_agent = "Files.com Ruby SDK v#{Files::VERSION}"
697
- user_agent += " #{format_app_info(Files.app_info)}" unless Files.app_info.nil?
862
+ user_agent += " #{format_app_info(app_info)}" unless app_info.nil?
698
863
 
699
- headers = { "User-Agent" => user_agent }
864
+ headers = { "User-Agent" => self.class.user_agent_with_metadata(user_agent) }
700
865
  # A request body gets its Content-Type from the multipart and URL-encoding middleware, which choose
701
866
  # multipart/form-data when the body holds a file part and application/x-www-form-urlencoded otherwise.
702
867
  headers["Content-Type"] = "application/x-www-form-urlencoded" if QUERY_METHODS.include?(method.to_s.downcase.to_sym)
703
868
 
704
- if Files.default_headers.is_a?(Proc)
705
- proc_headers = Files.default_headers.call
869
+ default_headers = setting(settings, :default_headers)
870
+ if default_headers.is_a?(Proc)
871
+ proc_headers = default_headers.call
706
872
  headers.merge!(proc_headers) if proc_headers.is_a?(Hash)
707
873
  end
708
874
 
709
- headers.merge!(Files.default_headers) if Files.default_headers.is_a?(Hash)
875
+ headers.merge!(default_headers) if default_headers.is_a?(Hash)
710
876
 
877
+ language = setting(settings, :language)
711
878
  headers["X-FilesAPI-Key"] = api_key if api_key
712
879
  headers["X-FilesAPI-Auth"] = session_id if session_id
713
- headers["Accept-Language"] = Files.language if Files.language
880
+ headers["Accept-Language"] = language if language
714
881
  workspace_id = workspace_id.to_s
715
882
  headers["X-Files-Workspace-Id"] = workspace_id unless workspace_id.empty?
716
883
 
@@ -761,5 +928,26 @@ module Files
761
928
  class RequestLogContext
762
929
  attr_accessor :body, :api_key, :headers, :method, :path, :query_params, :session_id
763
930
  end
931
+
932
+ # The params encoder of one transfer request (remote_request). Faraday decodes a URL's query into the request's
933
+ # params and encodes them again as it builds the adapter's URL, sorted and escaped its own way, with the
934
+ # connection's default params among them. This encoder gives back the query remote_request read from the URL
935
+ # instead, character for character, whatever the params hold. Decoding, as an adapter may do to read the query
936
+ # back, is left to the encoder the request had.
937
+ class SignedQuery
938
+ def initialize(query, decoder)
939
+ @query = query
940
+ @decoder = decoder
941
+ end
942
+
943
+ def encode(_params)
944
+ @query
945
+ end
946
+
947
+ def decode(query)
948
+ @decoder.decode(query)
949
+ end
950
+ end
951
+ private_constant :SignedQuery
764
952
  end
765
953
  end