Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
79 changes: 78 additions & 1 deletion dotnet/src/dotnetframework/GxClasses/Helpers/HttpHelper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@
using System.Text.RegularExpressions;
using Microsoft.Net.Http.Headers;
using System.Net.Http;
using System.Linq;
using System.Globalization;

namespace GeneXus.Http
{
Expand Down Expand Up @@ -451,6 +451,83 @@ internal static void AllowHeader(HttpContext httpContext, List<string> methods)
{
httpContext.Response.AppendHeader(HeaderNames.Allow, string.Join(",", methods));
}
internal static string HtmlEncodeJsonValue(string value)
{
return GXUtil.HtmlEncodeInputValue(JsonQuote(value));
}

static void AppendCharAsUnicodeJavaScript(StringBuilder builder, char c)
{
builder.Append("\\u");
int num = c;
builder.Append(num.ToString("x4", CultureInfo.InvariantCulture));
}
/**
* Produce a string in double quotes with backslash sequences in all the
* right places. A backslash will be inserted within </, allowing JSON
* text to be delivered in HTML. In JSON text, a string cannot contain a
* control character or an unescaped quote or backslash.
* */
internal static string JsonQuote(string value, bool addDoubleQuotes=false)
{
string text = string.Empty;
if (!string.IsNullOrEmpty(value))
{
int i;
int len = value.Length;
StringBuilder sb = new StringBuilder(len + 4);

for (i = 0; i < len; i += 1)
{
char c = value[i];
switch (c)
{
case '\\':
case '"':
sb.Append('\\');
sb.Append(c);
break;
case '\b':
sb.Append("\\b");
break;
case '\t':
sb.Append("\\t");
break;
case '\n':
sb.Append("\\n");
break;
case '\f':
sb.Append("\\f");
break;
case '\r':
sb.Append("\\r");
break;
default:
{
if (c < ' ')
{
AppendCharAsUnicodeJavaScript(sb, c);
}
else
{
sb.Append(c);
}
}
break;
}
}
text = sb.ToString();
}
if (!addDoubleQuotes)
{
return text;
}
else
{
return "\"" + text + "\"";
}
}

}
#if NETCORE
public class HttpCookieCollection : Dictionary<string, HttpCookie>
Expand Down
2 changes: 1 addition & 1 deletion dotnet/src/dotnetframework/GxClasses/Middleware/GXHttp.cs
Original file line number Diff line number Diff line change
Expand Up @@ -1585,7 +1585,7 @@ protected void SendState()
context.httpAjaxContext.AddStylesHidden();
if (IsSpaRequest())
{
context.WriteHtmlTextNl("<script>gx.ajax.saveJsonResponse('" + GXUtil.HtmlEncodeInputValue(HttpUtility.JavaScriptStringEncode(context.getJSONResponse())) + "');</script>");
context.WriteHtmlTextNl("<script>gx.ajax.saveJsonResponse('" + HttpHelper.HtmlEncodeJsonValue(context.getJSONResponse()) + "');</script>");
}
else
{
Expand Down
14 changes: 14 additions & 0 deletions dotnet/test/DotNetCoreUnitTest/HttpUtils/HttpUtils.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
using System;
using System.Web;
using GeneXus.Application;
using GeneXus.Http;
using GeneXus.Utils;
using Xunit;

Expand Down Expand Up @@ -62,5 +64,17 @@ private static void DoTest(string contentDisposition, string expectedContentDisp

Assert.Equal(expectedContentDisposition, encodedValue);
}

[Fact]
public void TestDoNotDoubleEncodeAmpersand()
{
string state = "{\"gxProps\":[\"FORM\":{\"Class\":\"form-horizontal Form\"}}], \"gxHiddens\":{\"gxhash_vA\":\"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9\"," +
"\"hsh\":\"C/CAcgMV0JZC/+o3ikT+R2Hhb1LcQ==\",\"Z3c\":\"&#039;\"}]}}";

string jsonEncoded = HttpHelper.HtmlEncodeJsonValue(state);
Assert.Contains("&amp;", jsonEncoded, StringComparison.OrdinalIgnoreCase);
Assert.StartsWith("{", jsonEncoded, StringComparison.OrdinalIgnoreCase);
}

}
}