diff --git a/src/WebAsyncWrapper.cls b/src/WebAsyncWrapper.cls index ded42076..fcd7eb53 100644 --- a/src/WebAsyncWrapper.cls +++ b/src/WebAsyncWrapper.cls @@ -13,7 +13,7 @@ Attribute VB_Exposed = True ' ' Wrapper WebClient and WebRequest that enables callback-style async requests ' -' _Note_ Windows-only and requires reference to "Microsoft WinHTTP Services, version 5.1" +' _Note_ Windows-only and Excel-only and requires reference to "Microsoft WinHTTP Services, version 5.1" ' ' Errors: ' 11050 / 80042b2a / -2147210454 - Client should not be changed @@ -163,11 +163,13 @@ End Sub '' Public Sub TimedOut() Dim web_Response As New WebResponse + + web_StopTimeoutTimer + WebHelpers.LogDebug "Timed out", "WebAsyncWrapper.TimedOut" + + ' Callback web_Response.StatusCode = WebStatusCode.RequestTimeout web_Response.StatusDescription = "Request Timeout" - - ' Callback - WebHelpers.LogDebug "Timed out", "WebAsyncWrapper.TimedOut" web_RunCallback web_Response End Sub @@ -210,12 +212,27 @@ End Sub ' Start timeout timer Private Sub web_StartTimeoutTimer() - WebHelpers.StartTimeoutTimer Me, Me.Client.TimeoutMs + Dim web_TimeoutS As Long + + If WebHelpers.AsyncRequests Is Nothing Then: Set WebHelpers.AsyncRequests = New Dictionary + + ' Round ms to seconds with minimum of 1 second if ms > 0 + web_TimeoutS = Round(Me.Client.TimeoutMs / 1000, 0) + If Me.Client.TimeoutMs > 0 And web_TimeoutS = 0 Then + web_TimeoutS = 1 + End If + + WebHelpers.AsyncRequests.Add Me.Request.Id, Me + Application.OnTime Now + TimeValue("00:00:" & web_TimeoutS), "'WebHelpers.OnTimeoutTimerExpired """ & Me.Request.Id & """'" End Sub ' Stop timeout timer Private Sub web_StopTimeoutTimer() - WebHelpers.StopTimeoutTimer Me + If Not WebHelpers.AsyncRequests Is Nothing And Not Me.Request Is Nothing Then + If WebHelpers.AsyncRequests.Exists(Me.Request.Id) Then + WebHelpers.AsyncRequests.Remove Me.Request.Id + End If + End If End Sub ' Process asynchronous requests diff --git a/src/WebClient.cls b/src/WebClient.cls index b4515b1e..6b0d58db 100644 --- a/src/WebClient.cls +++ b/src/WebClient.cls @@ -11,7 +11,26 @@ Attribute VB_Exposed = True ' WebClient v4.0.3 ' (c) Tim Hall - https://github.com/VBA-tools/VBA-Web ' -' Execute requests and handle responses +' `WebClient` executes requests and handles response and is responsible for functionality shared between requests, +' such as authentication, proxy configuration, and security. +' +' Usage: +' +' ```VB.net +' Dim Client As New WebClient +' Client.BaseUrl = "https://www.example.com/api/" +' +' Dim Auth As New HttpBasicAuthenticator +' Auth.Setup Username, Password +' Set Client.Authenticator = Auth +' +' Dim Request As New WebRequest +' Dim Response As WebResponse +' ' Setup WebRequest... +' +' Set Response = Client.Execute(Request) +' ' -> Uses Http Basic authentication and appends Request.Resource to BaseUrl +' ``` ' ' Errors: ' 11010 / 80042b02 / -2147210494 - cURL error in Execute @@ -146,7 +165,7 @@ Public ProxyUsername As String Public ProxyPassword As String '' -' Load proxy server and bypass list automatically. +' Load proxy server and bypass list automatically (`False` by default). ' ' @property EnableAutoProxy ' @type Boolean @@ -155,7 +174,8 @@ Public ProxyPassword As String Public EnableAutoProxy As Boolean '' -' Turn off SSL validation. +' Turn off SSL validation (`False` by default). +' Useful for self-signed certificates and should only be used with trusted servers. ' ' @property Insecure ' @type Boolean diff --git a/src/WebHelpers.bas b/src/WebHelpers.bas index a0b8497b..36726030 100644 --- a/src/WebHelpers.bas +++ b/src/WebHelpers.bas @@ -3,7 +3,17 @@ Attribute VB_Name = "WebHelpers" ' WebHelpers v4.0.3 ' (c) Tim Hall - https://github.com/VBA-tools/VBA-Web ' -' Common helpers VBA-Web +' Contains general-purpose helpers that are used throughout VBA-Web. Includes: +' +' - Logging +' - Converters and encoding +' - Url handling +' - Object/Dictionary/Collection/Array helpers +' - Request preparation / handling +' - Timing +' - Mac +' - Cryptography +' - Converters (JSON, XML, Url-Encoded) ' ' Errors: ' 11000 - Error during parsing @@ -213,11 +223,10 @@ End Type Private web_pDocumentHelper As Object Private web_pElHelper As Object -Private web_pAsyncRequests As Dictionary Private web_pConverters As Dictionary ' --------------------------------------------- ' -' Types +' Types and Properties ' --------------------------------------------- ' '' @@ -308,7 +317,26 @@ End Enum ' ' @example ' ```VB.net +' Dim Client As New WebClient +' Client.BaseUrl = "https://api.example.com/v1/" ' +' Dim RequestWithTypo As New WebRequest +' RequestWithTypo.Resource = "peeple/{id}" +' RequestWithType.AddUrlSegment "idd", 123 +' +' ' Enable logging before the request is executed +' WebHelpers.EnableLogging = True +' +' Dim Response As WebResponse +' Set Response = Client.Execute(Request) +' +' ' Immediate window: +' ' --> Request - (Time) +' ' GET https://api.example.com/v1/peeple/{id} +' ' Headers... +' ' +' ' <-- Response - (Time) +' ' 404 ... ' ``` ' ' @property EnableLogging @@ -317,6 +345,14 @@ End Enum '' Public EnableLogging As Boolean +'' +' Store currently running async requests +' +' @property AsyncRequests +' @type Dictionary +'' +Public AsyncRequests As Dictionary + ' ============================================= ' ' 1. Logging ' ============================================= ' @@ -489,7 +525,7 @@ End Function ' ' @method ParseJson ' @param {String} Json JSON value to parse -' @return {Object} +' @return {Dictionary|Collection} ' ' (Implemented in VBA-JSON embedded below) @@ -497,7 +533,7 @@ End Function ' Convert `Dictionary`, `Collection`, or `Array` to JSON string. ' ' @method ConvertToJson -' @param {Dictionary|Collection|Variant} Obj +' @param {Dictionary|Collection|Array} Obj ' @return {String} ' ' (Implemented in VBA-JSON embedded below) @@ -1220,7 +1256,7 @@ End Function ' ' @method FindInKeyValues ' @param {Collection} KeyValues -' @param {String} Key to find +' @param {Variant} Key to find ' @return {Variant} '' Public Function FindInKeyValues(KeyValues As Collection, Key As Variant) As Variant @@ -1259,7 +1295,7 @@ End Function ' ' @method AddOrReplaceInKeyValues ' @param {Collection} KeyValues -' @param {String} Key +' @param {Variant} Key ' @param {Variant} Value ' @return {Variant} '' @@ -1348,84 +1384,10 @@ Public Function MethodToName(Method As WebMethod) As String End Select End Function -'' -' Add request to watched requests -' -' @internal -' @method AddAsyncRequest -' @param {RestAsyncWrapper} AsyncWrapper -'' -Public Sub AddAsyncRequest(web_AsyncWrapper As Object) - If web_pAsyncRequests Is Nothing Then: Set web_pAsyncRequests = New Dictionary - If Not web_AsyncWrapper.Request Is Nothing Then - web_pAsyncRequests.Add web_AsyncWrapper.Request.Id, web_AsyncWrapper - End If -End Sub - -'' -' Get watched request -' -' @internal -' @method GetAsyncRequest -' @param {String} RequestId -' @return {RestAsyncWrapper} -'' -Public Function GetAsyncRequest(web_RequestId As String) As Object - If web_pAsyncRequests.Exists(web_RequestId) Then - Set GetAsyncRequest = web_pAsyncRequests(web_RequestId) - End If -End Function - -'' -' Remove request from watched requests -' -' @internal -' @method RemoveAsyncRequest -' @param {String} RequestId -'' -Public Sub RemoveAsyncRequest(web_RequestId As String) - If Not web_pAsyncRequests Is Nothing Then - If web_pAsyncRequests.Exists(web_RequestId) Then: web_pAsyncRequests.Remove web_RequestId - End If -End Sub - ' ============================================= ' ' 6. Timing ' ============================================= ' -'' -' Start timeout timer for request -' -' @internal -' @method StartTimeoutTimer -' @param {RestAsyncWrapper} AsyncWrapper -' @param {Long} TimeoutMS -'' -Public Sub StartTimeoutTimer(web_AsyncWrapper As Object, web_TimeoutMs As Long) - ' Round ms to seconds with minimum of 1 second if ms > 0 - Dim web_TimeoutS As Long - web_TimeoutS = Round(web_TimeoutMs / 1000, 0) - If web_TimeoutMs > 0 And web_TimeoutS = 0 Then - web_TimeoutS = 1 - End If - - AddAsyncRequest web_AsyncWrapper - Application.OnTime Now + TimeValue("00:00:" & web_TimeoutS), "'WebHelpers.OnTimeoutTimerExpired """ & web_AsyncWrapper.Request.Id & """'" -End Sub - -'' -' Stop timeout timer for request -' -' @internal -' @method StopTimeoutTimer -' @param {RestAsyncWrapper} AsyncWrapper -'' -Public Sub StopTimeoutTimer(web_AsyncWrapper As Object) - If Not web_AsyncWrapper.Request Is Nothing Then - RemoveAsyncRequest web_AsyncWrapper.Request.Id - End If -End Sub - '' ' Handle timeout timers expiring ' @@ -1434,14 +1396,12 @@ End Sub ' @param {String} RequestId '' Public Sub OnTimeoutTimerExpired(web_RequestId As String) - Dim web_AsyncWrapper As Object - Set web_AsyncWrapper = GetAsyncRequest(web_RequestId) - - If Not web_AsyncWrapper Is Nothing Then - StopTimeoutTimer web_AsyncWrapper - - LogDebug "Async Timeout: " & web_AsyncWrapper.Request.FormattedResource, "WebHelpers.OnTimeoutTimerExpired" - web_AsyncWrapper.TimedOut + If Not AsyncRequests Is Nothing Then + If AsyncRequests.Exists(web_RequestId) Then + Dim web_AsyncWrapper As Object + Set web_AsyncWrapper = AsyncRequests(web_RequestId) + web_AsyncWrapper.TimedOut + End If End If End Sub diff --git a/src/WebRequest.cls b/src/WebRequest.cls index c51413fe..0e321a89 100644 --- a/src/WebRequest.cls +++ b/src/WebRequest.cls @@ -11,7 +11,32 @@ Attribute VB_Exposed = True ' WebRequest v4.0.3 ' (c) Tim Hall - https://github.com/VBA-tools/VBA-Web ' -' Create a request for use with a WebClient +' `WebRequest` is used to create detailed requests +' (including formatting, querystrings, headers, cookies, and much more). +' +' Usage: +' ```VB.net +' Dim Request As New WebRequest +' Request.Resource = "users/{Id}" +' +' Request.Method = WebMethod.HttpPut +' Request.RequestFormat = WebFormat.UrlEncoded +' Request.ResponseFormat = WebFormat.Json +' +' Dim Body As New Dictionary +' Body.Add "name", "Tim" +' Body.Add "project", "VBA-Web" +' Set Request.Body = Body +' +' Request.AddUrlSegment "Id", 123 +' Request.AddQuerystringParam "api_key", "abcd" +' Request.AddHeader "Authorization", "Token ..." +' +' ' -> PUT (Client.BaseUrl)users/123?api_key=abcd +' ' Authorization: Token ... +' ' +' ' name=Tim&project=VBA-Web +' ``` ' ' Errors: ' 11020 / 80042b0c / -2147210484 - Cannot add body parameter to non-Dictionary diff --git a/src/WebResponse.cls b/src/WebResponse.cls index 63565ee0..a8870020 100644 --- a/src/WebResponse.cls +++ b/src/WebResponse.cls @@ -11,7 +11,21 @@ Attribute VB_Exposed = True ' WebResponse v4.0.3 ' (c) Tim Hall - https://github.com/VBA-tools/VBA-Web ' -' Wrapper for http/cURL responses +' Wrapper for http/cURL responses that includes parsed Data based on WebRequest.ResponseFormat. +' +' Usage: +' ```VB.net +' Dim Response As WebResponse +' Set Response = Client.Execute(Request) +' +' If Response.StatusCode = WebStatusCode.Ok Then +' ' Response.Headers, Response.Cookies +' ' Response.Data -> Parsed Response.Content based on Request.ResponseFormat +' ' Response.Body -> Raw response bytes +' Else +' Debug.Print "Error: " & Response.StatusCode & " - " & Response.Content +' End If +' ``` ' ' Errors: ' 11030 / 80042b16 / -2147210474 - Error creating from http