using AngleSharp.Dom;
using AngleSharp.Html.Dom;
namespace XFESystem.Browser;
public sealed partial class BrowserService
{
private string? pendingNavigation;
private bool SubmitForm(IElement form, IElement? submitter = null, bool fireEvent = true)
{
if (fireEvent && dom?.DispatchEvent(form, "submit") == false) return false;
string method = submitter?.GetAttribute("formmethod") ?? form.GetAttribute("method") ?? "get";
if (!method.Equals("get", StringComparison.OrdinalIgnoreCase))
{ Diagnostic("Form navigation failed: only GET form submission is supported."); return false; }
if (scriptPolicy?.BlocksAllScripts == true)
{ Diagnostic("Form navigation blocked: the declared policy cannot be enforced."); return false; }
string action = submitter?.GetAttribute("formaction") ?? form.GetAttribute("action") ?? "";
Uri target = action.Length == 0 ? currentAddress! : ResourceAddress(action);
if (currentAddress!.Scheme == "https" && target.Scheme != "https")
{ Diagnostic("Form navigation blocked: HTTPS cannot downgrade to HTTP."); return false; }
var fields = new List<string>();
string Encode(string value) => Uri.EscapeDataString(value.Replace("\r\n", "\n").Replace("\r", "\n").Replace("\n", "\r\n")).Replace("%20", "+");
foreach (var control in document!.QuerySelectorAll("input,textarea,select,button"))
{
string? owner = control.GetAttribute("form");
if (owner is not null ? owner != form.Id : !ReferenceEquals(control.Closest("form"), form)) continue;
string name = control.GetAttribute("name") ?? "";
if (name.Length == 0 || control.HasAttribute("disabled")) continue;
string type = (control.GetAttribute("type") ?? (control.LocalName == "button" ? "submit" : "text")).ToLowerInvariant();
if (type is "reset" or "button" or "file" || type is "submit" or "image" && !ReferenceEquals(control, submitter)) continue;
if (control is IHtmlInputElement check && type is "checkbox" or "radio" && !check.IsChecked) continue;
string value = (control switch { IHtmlInputElement input => input.Value, IHtmlTextAreaElement area => area.Value,
IHtmlSelectElement select => select.Value, _ => control.GetAttribute("value") }) ?? "";
fields.Add(Encode(name) + "=" + Encode(value));
}
var destination = new UriBuilder(target) { Query = string.Join('&', fields), Fragment = "" };
pendingNavigation = destination.Uri.AbsoluteUri;
return true;
}
private void FollowPendingNavigation()
{
if (pendingNavigation is not { } next) return;
pendingNavigation = null;
Navigate(next);
}
private void DefaultClick(IElement? element)
{
var control = element?.Closest("button,input[type=submit],input[type=image]");
if (control is not null && !control.HasAttribute("disabled") &&
(control.GetAttribute("type") ?? "submit").Equals("submit", StringComparison.OrdinalIgnoreCase) && control.Closest("form") is { } form)
SubmitForm(form, control);
else if (element?.Closest("a[href]") is { } anchor && anchor.GetAttribute("href") is { } href && !href.StartsWith("javascript:", StringComparison.OrdinalIgnoreCase))
pendingNavigation = ResourceAddress(href).AbsoluteUri;
}
}
using AngleSharp.Dom;
using AngleSharp.Html.Dom;
namespace XFESystem.Browser;
public sealed partial class BrowserService
{
private string? pendingNavigation;
private bool SubmitForm(IElement form, IElement? submitter = null, bool fireEvent = true)
{
if (fireEvent && dom?.DispatchEvent(form, "submit") == false) return false;
string method = submitter?.GetAttribute("formmethod") ?? form.GetAttribute("method") ?? "get";
if (!method.Equals("get", StringComparison.OrdinalIgnoreCase))
{ Diagnostic("Form navigation failed: only GET form submission is supported."); return false; }
if (scriptPolicy?.BlocksAllScripts == true)
{ Diagnostic("Form navigation blocked: the declared policy cannot be enforced."); return false; }
string action = submitter?.GetAttribute("formaction") ?? form.GetAttribute("action") ?? "";
Uri target = action.Length == 0 ? currentAddress! : ResourceAddress(action);
if (currentAddress!.Scheme == "https" && target.Scheme != "https")
{ Diagnostic("Form navigation blocked: HTTPS cannot downgrade to HTTP."); return false; }
var fields = new List<string>();
string Encode(string value) => Uri.EscapeDataString(value.Replace("\r\n", "\n").Replace("\r", "\n").Replace("\n", "\r\n")).Replace("%20", "+");
foreach (var control in document!.QuerySelectorAll("input,textarea,select,button"))
{
string? owner = control.GetAttribute("form");
if (owner is not null ? owner != form.Id : !ReferenceEquals(control.Closest("form"), form)) continue;
string name = control.GetAttribute("name") ?? "";
if (name.Length == 0 || control.HasAttribute("disabled")) continue;
string type = (control.GetAttribute("type") ?? (control.LocalName == "button" ? "submit" : "text")).ToLowerInvariant();
if (type is "reset" or "button" or "file" || type is "submit" or "image" && !ReferenceEquals(control, submitter)) continue;
if (control is IHtmlInputElement check && type is "checkbox" or "radio" && !check.IsChecked) continue;
string value = (control switch { IHtmlInputElement input => input.Value, IHtmlTextAreaElement area => area.Value,
IHtmlSelectElement select => select.Value, _ => control.GetAttribute("value") }) ?? "";
fields.Add(Encode(name) + "=" + Encode(value));
}
var destination = new UriBuilder(target) { Query = string.Join('&', fields), Fragment = "" };
pendingNavigation = destination.Uri.AbsoluteUri;
return true;
}
private void FollowPendingNavigation()
{
if (pendingNavigation is not { } next) return;
pendingNavigation = null;
Navigate(next);
}
private void DefaultClick(IElement? element)
{
var control = element?.Closest("button,input[type=submit],input[type=image]");
if (control is not null && !control.HasAttribute("disabled") &&
(control.GetAttribute("type") ?? "submit").Equals("submit", StringComparison.OrdinalIgnoreCase) && control.Closest("form") is { } form)
SubmitForm(form, control);
else if (element?.Closest("a[href]") is { } anchor && anchor.GetAttribute("href") is { } href && !href.StartsWith("javascript:", StringComparison.OrdinalIgnoreCase))
pendingNavigation = ResourceAddress(href).AbsoluteUri;
}
}