diff --git a/dotnet/src/dotnetframework/GxClasses/Core/Web/GxHttpServer.cs b/dotnet/src/dotnetframework/GxClasses/Core/Web/GxHttpServer.cs index 14d4b2e10..1af295604 100644 --- a/dotnet/src/dotnetframework/GxClasses/Core/Web/GxHttpServer.cs +++ b/dotnet/src/dotnetframework/GxClasses/Core/Web/GxHttpServer.cs @@ -11,6 +11,12 @@ namespace GeneXus.Http.Server using Microsoft.AspNetCore.Http.Extensions; using System.Linq; using Microsoft.AspNetCore.Http.Features; + using System.Text; + using System.Threading.Tasks; + using Microsoft.AspNetCore.Mvc.Formatters; + using System.Net.Http; + using Stubble.Core.Contexts; + using System.Net.Mime; #endif public class GxHttpCookie @@ -391,9 +397,9 @@ public string GetValue( string name) public override string ToString() { if (_httpReq == null) - return ""; + return String.Empty; #if NETCORE - return (new StreamReader(_httpReq.Body)).ReadToEnd(); + return _httpReq.GetRawBodyString(); #else return (new StreamReader(_httpReq.InputStream)).ReadToEnd(); #endif diff --git a/dotnet/src/dotnetframework/GxClasses/Helpers/HttpHelper.cs b/dotnet/src/dotnetframework/GxClasses/Helpers/HttpHelper.cs index 8fb9bf054..109c871e6 100644 --- a/dotnet/src/dotnetframework/GxClasses/Helpers/HttpHelper.cs +++ b/dotnet/src/dotnetframework/GxClasses/Helpers/HttpHelper.cs @@ -9,6 +9,7 @@ using Microsoft.AspNetCore.Http.Features; using Microsoft.Extensions.Primitives; using System.Net.Http; +using Microsoft.AspNetCore.Mvc.Formatters; #else using System.ServiceModel.Web; using System.ServiceModel; @@ -21,10 +22,6 @@ using System.Net; using System.Text; using System.Web; -using System.Threading.Tasks; -using System.Threading; -using System.Linq; -using GeneXus.Data; using System.Runtime.Serialization; using GeneXus.Mime; using System.Text.RegularExpressions; @@ -711,8 +708,37 @@ public static NameValueCollection GetParams(this HttpRequest request) return request.Params; #endif } +#if NETCORE + static readonly MediaType URLEncoded = new MediaType("application/x-www-form-urlencoded"); + public static string GetRawBodyString(this HttpRequest request, Encoding encoding = null) + { + if (encoding == null) + encoding = Encoding.UTF8; + if (!string.IsNullOrEmpty(request.ContentType)) + { + MediaType mediaType = new MediaType(request.ContentType); + if (mediaType.IsSubsetOf(URLEncoded)) + { + string content = string.Empty; + foreach (string key in request.Form.Keys) + { + if (request.Form.TryGetValue(key, out var value)) + { + content += $"{GXUtil.UrlEncode(key)}={GXUtil.UrlEncode(value)}&"; + } + } + content = content.TrimEnd('&'); + return content; + } + } + using (StreamReader sr = new StreamReader(request.Body, encoding)) + { + return sr.ReadToEnd(); + } + } +#endif public static string GetRawUrl(this HttpRequest request) { #if NETCORE diff --git a/dotnet/test/DotNetCoreUnitTest/Middleware/WebPanelTest.cs b/dotnet/test/DotNetCoreUnitTest/Middleware/WebPanelTest.cs new file mode 100644 index 000000000..e38816304 --- /dev/null +++ b/dotnet/test/DotNetCoreUnitTest/Middleware/WebPanelTest.cs @@ -0,0 +1,52 @@ +using System.Collections.Generic; +using System.Net.Http; +using System.Reflection; +using System.Text; +using System.Threading.Tasks; +using GeneXus.Metadata; +using Xunit; +namespace xUnitTesting +{ + public class WebPanelTest : MiddlewareTest + { + Dictionary parms = new Dictionary(); + FormUrlEncodedContent formUrlEncodedContent; + public WebPanelTest():base() + { + ClassLoader.FindType("webhook", "GeneXus.Programs", "webhook", Assembly.GetExecutingAssembly(), true);//Force loading assembly for webhook procedure + server.AllowSynchronousIO=true; + parms.Add("SmsMessageSid", "SM40d2cbda93b2de0a15df7a1598c7db83"); + parms.Add("NumMedia", "99"); + parms.Add("WaId", "5215532327636"); + parms.Add("From", "whatsapp:+5215532327636"); + parms.Add("ProfileName", "Jhon Thomas"); + formUrlEncodedContent = new FormUrlEncodedContent(parms); + } + [Fact] + public async Task HtttpResponseBodyNotEmpty_WhenFormURLEncoded() + { + HttpClient client = server.CreateClient(); + + HttpResponseMessage response = await client.PostAsync("webhook.aspx", formUrlEncodedContent);//"application/x-www-form-urlencoded" + response.EnsureSuccessStatusCode(); + string resp = await response.Content.ReadAsStringAsync(); + string expected = await formUrlEncodedContent.ReadAsStringAsync(); + Assert.Equal(expected, resp); + Assert.Equal(System.Net.HttpStatusCode.OK, response.StatusCode); + } + [Fact] + public async Task HtttpResponseBodyNotEmpty_WhenTextPlain() + { + HttpClient client = server.CreateClient(); + string plainText = await formUrlEncodedContent.ReadAsStringAsync(); + StringContent content = new StringContent(plainText, Encoding.UTF8, "text/plain"); + HttpResponseMessage response = await client.PostAsync("webhook.aspx", content); + response.EnsureSuccessStatusCode(); + string resp = await response.Content.ReadAsStringAsync(); + string expected = await content.ReadAsStringAsync(); + Assert.Equal(expected, resp); + Assert.Equal(System.Net.HttpStatusCode.OK, response.StatusCode); + } + } + +} diff --git a/dotnet/test/DotNetCoreUnitTest/Middleware/webhook.cs b/dotnet/test/DotNetCoreUnitTest/Middleware/webhook.cs new file mode 100644 index 000000000..7dfef187b --- /dev/null +++ b/dotnet/test/DotNetCoreUnitTest/Middleware/webhook.cs @@ -0,0 +1,103 @@ +using System; +using GeneXus.Application; +using GeneXus.Data.NTier; +using GeneXus.Http.Server; +using GeneXus.Procedure; +using GeneXus.Utils; +namespace GeneXus.Programs +{ + public class webhook : GXWebProcedure + { + public override void webExecute() + { + context.SetDefaultTheme("Carmine"); + initialize(); + executePrivate(); + cleanup(); + } + + public webhook() + { + context = new GxContext(); + DataStoreUtil.LoadDataStores(context); + IsMain = true; + context.SetDefaultTheme("Carmine"); + } + + public webhook(IGxContext context) + { + this.context = context; + IsMain = false; + } + + public void execute() + { + initialize(); + executePrivate(); + } + + public void executeSubmit() + { + webhook objwebhook; + objwebhook = new webhook(); + objwebhook.context.SetSubmitInitialConfig(context); + objwebhook.initialize(); + Submit(executePrivateCatch, objwebhook); + } + + void executePrivateCatch(object stateInfo) + { + try + { + ((webhook)stateInfo).executePrivate(); + } + catch (Exception e) + { + GXUtil.SaveToEventLog("Design", e); + throw; + } + } + + void executePrivate() + { + /* GeneXus formulas */ + /* Output device settings */ + AV9body = AV8httprequest.ToString(); + AV10httpresponse.AddString(AV9body); + if (context.WillRedirect()) + { + context.Redirect(context.wjLoc); + context.wjLoc = ""; + } + this.cleanup(); + } + + public override void cleanup() + { + CloseOpenCursors(); + base.cleanup(); + if (IsMain) + { + context.CloseConnections(); + } + ExitApp(); + } + + protected void CloseOpenCursors() + { + } + + public override void initialize() + { + AV8httprequest = new GxHttpRequest(context); + AV10httpresponse = new GxHttpResponse(context); + /* GeneXus formulas. */ + context.Gx_err = 0; + } + + private string AV9body; + private GxHttpRequest AV8httprequest; + private GxHttpResponse AV10httpresponse; + } + +}