From 473b171a168d8756aca6a50410553e245e10da03 Mon Sep 17 00:00:00 2001 From: Ryan Kistner Date: Sat, 27 Apr 2019 14:23:19 -0600 Subject: [PATCH 1/3] Pass WebAPI arguments around as generic objects, encoding them with the correct override of HttpUtility.UrlEncode at request time --- .../SteamKit2/Steam/WebAPI/SteamDirectory.cs | 2 +- SteamKit2/SteamKit2/Steam/WebAPI/WebAPI.cs | 31 ++++++++++++------- 2 files changed, 20 insertions(+), 13 deletions(-) diff --git a/SteamKit2/SteamKit2/Steam/WebAPI/SteamDirectory.cs b/SteamKit2/SteamKit2/Steam/WebAPI/SteamDirectory.cs index 338463b92..bff980991 100644 --- a/SteamKit2/SteamKit2/Steam/WebAPI/SteamDirectory.cs +++ b/SteamKit2/SteamKit2/Steam/WebAPI/SteamDirectory.cs @@ -48,7 +48,7 @@ static async Task> LoadCoreAsync( SteamConfigu } var directory = configuration.GetAsyncWebAPIInterface( "ISteamDirectory" ); - var args = new Dictionary + var args = new Dictionary { ["cellid"] = configuration.CellID.ToString( CultureInfo.InvariantCulture ) }; diff --git a/SteamKit2/SteamKit2/Steam/WebAPI/WebAPI.cs b/SteamKit2/SteamKit2/Steam/WebAPI/WebAPI.cs index cdce8043c..64cadff54 100644 --- a/SteamKit2/SteamKit2/Steam/WebAPI/WebAPI.cs +++ b/SteamKit2/SteamKit2/Steam/WebAPI/WebAPI.cs @@ -11,6 +11,7 @@ using System.Text; using System.Text.RegularExpressions; using System.Threading.Tasks; +using System.Web; namespace SteamKit2 { @@ -67,7 +68,7 @@ internal Interface( HttpClient httpClient, string iface, string apiKey ) /// An network error occurred when performing the request. /// A network error occurred when performing the request. /// An error occured when parsing the response from the WebAPI. - public KeyValue Call( string func, int version = 1, Dictionary args = null ) + public KeyValue Call( string func, int version = 1, Dictionary args = null ) => Call( HttpMethod.Get, func, version, args ); @@ -83,7 +84,7 @@ public KeyValue Call( string func, int version = 1, Dictionary a /// An network error occurred when performing the request. /// A network error occurred when performing the request. /// An error occured when parsing the response from the WebAPI. - public KeyValue Call( HttpMethod method, string func, int version = 1, Dictionary args = null ) + public KeyValue Call( HttpMethod method, string func, int version = 1, Dictionary args = null ) { var callTask = asyncInterface.CallAsync( method, func, version, args ); @@ -209,7 +210,7 @@ internal AsyncInterface( HttpClient httpClient, string iface, string apiKey ) /// An network error occurred when performing the request. /// A network error occurred when performing the request. /// An error occured when parsing the response from the WebAPI. - public Task CallAsync( HttpMethod method, string func, int version = 1, Dictionary args = null ) + public Task CallAsync( HttpMethod method, string func, int version = 1, Dictionary args = null ) { var task = CallAsyncCore( method, func, version, args ); @@ -226,7 +227,7 @@ public Task CallAsync( HttpMethod method, string func, int version = 1 return task; } - async Task CallAsyncCore( HttpMethod method, string func, int version = 1, Dictionary args = null ) + async Task CallAsyncCore( HttpMethod method, string func, int version = 1, Dictionary args = null ) { if ( method == null ) { @@ -240,7 +241,7 @@ async Task CallAsyncCore( HttpMethod method, string func, int version if ( args == null ) { - args = new Dictionary(); + args = new Dictionary(); } @@ -268,11 +269,17 @@ async Task CallAsyncCore( HttpMethod method, string func, int version // append any args paramBuilder.Append( string.Join( "&", args.Select( kvp => { - // TODO: the WebAPI is a special snowflake that needs to appropriately handle url encoding - // this is in contrast to the steam3 content server APIs which use an entirely different scheme of encoding + string key = HttpUtility.UrlEncode( kvp.Key ); + string value; - string key = WebHelpers.UrlEncode( kvp.Key ); - string value = kvp.Value; // WebHelpers.UrlEncode( kvp.Value ); + if ( kvp.Value is byte[] ) + { + value = HttpUtility.UrlEncode( kvp.Value as byte[] ); + } + else + { + value = HttpUtility.UrlEncode( kvp.Value.ToString() ); + } return string.Format( "{0}={1}", key, value ); } ) ) ); @@ -360,7 +367,7 @@ public override bool TryInvokeMember( InvokeMemberBinder binder, object[] args, throw new InvalidOperationException( "Argument mismatch in API call. All parameters must be passed as named arguments." ); } - var apiArgs = new Dictionary(); + var apiArgs = new Dictionary(); var requestMethod = HttpMethod.Get; @@ -384,14 +391,14 @@ public override bool TryInvokeMember( InvokeMemberBinder binder, object[] args, foreach ( object value in enumerable ) { - apiArgs.Add( String.Format( "{0}[{1}]", argName, index++ ), value.ToString() ); + apiArgs.Add( String.Format( "{0}[{1}]", argName, index++ ), value ); } continue; } - apiArgs.Add( argName, argValue.ToString() ); + apiArgs.Add( argName, argValue ); } Match match = funcNameRegex.Match( binder.Name ); From 6bb55547bad4ca1f4ab35cf1735464d8d3c2b672 Mon Sep 17 00:00:00 2001 From: Ryan Kistner Date: Sat, 27 Apr 2019 14:53:42 -0600 Subject: [PATCH 2/3] Updated WebAPI sample --- Samples/6.WebAPI/Program.cs | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/Samples/6.WebAPI/Program.cs b/Samples/6.WebAPI/Program.cs index 3f0c46738..df01c03d6 100644 --- a/Samples/6.WebAPI/Program.cs +++ b/Samples/6.WebAPI/Program.cs @@ -92,10 +92,15 @@ static void Main( string[] args ) // you can call interface functions through a Call method using ( WebAPI.Interface steamNews = WebAPI.GetInterface( "ISteamNews" ) ) { - Dictionary newsArgs = new Dictionary(); + Dictionary newsArgs = new Dictionary(); newsArgs[ "appid" ] = "440"; KeyValue results = steamNews.Call( "GetNewsForApp", /* version */ 1, newsArgs ); + + foreach ( KeyValue news in results[ "newsitems" ][ "newsitem" ].Children ) + { + Console.WriteLine( "News: {0}", news[ "title" ].AsString() ); + } } } } From 49f33828f582826f3a606000d4a7fd8e165e34f9 Mon Sep 17 00:00:00 2001 From: Ryan Kistner Date: Sat, 27 Apr 2019 19:08:20 -0600 Subject: [PATCH 3/3] Leave null WebAPI args defined but empty --- Samples/6.WebAPI/Program.cs | 2 +- SteamKit2/SteamKit2/Steam/WebAPI/WebAPI.cs | 8 ++++++-- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/Samples/6.WebAPI/Program.cs b/Samples/6.WebAPI/Program.cs index df01c03d6..9efdb6761 100644 --- a/Samples/6.WebAPI/Program.cs +++ b/Samples/6.WebAPI/Program.cs @@ -92,7 +92,7 @@ static void Main( string[] args ) // you can call interface functions through a Call method using ( WebAPI.Interface steamNews = WebAPI.GetInterface( "ISteamNews" ) ) { - Dictionary newsArgs = new Dictionary(); + Dictionary newsArgs = new Dictionary(); newsArgs[ "appid" ] = "440"; KeyValue results = steamNews.Call( "GetNewsForApp", /* version */ 1, newsArgs ); diff --git a/SteamKit2/SteamKit2/Steam/WebAPI/WebAPI.cs b/SteamKit2/SteamKit2/Steam/WebAPI/WebAPI.cs index 64cadff54..78369142f 100644 --- a/SteamKit2/SteamKit2/Steam/WebAPI/WebAPI.cs +++ b/SteamKit2/SteamKit2/Steam/WebAPI/WebAPI.cs @@ -272,9 +272,13 @@ async Task CallAsyncCore( HttpMethod method, string func, int version string key = HttpUtility.UrlEncode( kvp.Key ); string value; - if ( kvp.Value is byte[] ) + if ( kvp.Value == null ) { - value = HttpUtility.UrlEncode( kvp.Value as byte[] ); + value = string.Empty; + } + else if ( kvp.Value is byte[] buffer ) + { + value = HttpUtility.UrlEncode( buffer ); } else {