HTMLFormElement
Represents the form element.
using AngleSharp.DOM.Collections;
using System;
using System.IO;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
namespace AngleSharp.DOM.Html
{
[DOM("HTMLFormElement")]
public sealed class HTMLFormElement : HTMLElement
{
private Task ;
private CancellationTokenSource _cancel;
private HTMLFormControlsCollection _elements;
public Element this[int index] {
get {
return _elements[index];
}
}
public object this[string name] {
get {
return _elements[name];
}
}
[DOM("name")]
public string Name {
get {
return GetAttribute("name");
}
set {
SetAttribute("name", value);
}
}
[DOM("length")]
public int Length {
get {
return _elements.Length;
}
}
[DOM("elements")]
public HTMLFormControlsCollection Elements {
get {
return _elements;
}
}
[DOM("acceptCharset")]
public string AcceptCharset {
get {
return GetAttribute("acceptCharset");
}
set {
SetAttribute("acceptCharset", value);
}
}
[DOM("action")]
public string Action {
get {
return GetAttribute("action");
}
set {
SetAttribute("action", value);
}
}
[DOM("autocomplete")]
public PowerState Autocomplete {
get {
return Element.ToEnum(GetAttribute("autocomplete"), PowerState.On);
}
set {
SetAttribute("autocomplete", value.ToString());
}
}
[DOM("enctype")]
public string Enctype {
get {
return CheckEncType(GetAttribute("enctype"));
}
set {
SetAttribute("enctype", CheckEncType(value));
}
}
[DOM("encoding")]
public string Encoding {
get {
return Enctype;
}
set {
Enctype = value;
}
}
[DOM("method")]
public HttpMethod Method {
get {
return Element.ToEnum(GetAttribute("method"), HttpMethod.Get);
}
set {
SetAttribute("method", value.ToString());
}
}
[DOM("noValidate")]
public bool NoValidate {
get {
return GetAttribute("novalidate") != null;
}
set {
SetAttribute("novalidate", value ? string.Empty : null);
}
}
[DOM("target")]
public string Target {
get {
return GetAttribute("target");
}
set {
SetAttribute("target", value);
}
}
public Task => _plannedNavigation;
protected internal override bool IsSpecial => true;
internal HTMLFormElement()
{
_cancel = new CancellationTokenSource();
_name = "form";
_elements = new HTMLFormControlsCollection(this);
}
[DOM("submit")]
public void Submit()
{
SubmitForm(this, true);
}
[DOM("reset")]
public void Reset()
{
foreach (HTMLFormControlElement element in _elements) {
element.Reset();
}
}
[DOM("checkValidity")]
public bool CheckValidity()
{
foreach (HTMLFormControlElement element in _elements) {
if (!element.CheckValidity())
return false;
}
return true;
}
private void SubmitForm(HTMLElement from, bool submittedFromSubmitMethod)
{
Document ownerDocument = base.OwnerDocument;
if (!submittedFromSubmitMethod && from.Attributes[AttributeNames.FormNoValidate] == null && NoValidate && !CheckValidity())
FireSimpleEvent(EventNames.Invalid);
else {
string text = Action;
if (string.IsNullOrEmpty(text))
text = ownerDocument.DocumentUri;
if (!Location.IsAbsolute(text))
text = Location.MakeAbsolute(from.BaseURI, text);
Location location = new Location(text);
string a = location.Protocol.TrimEnd(new char[1] {
':'
});
if (a == KnownProtocols.Http || a == KnownProtocols.Https) {
if (Method == HttpMethod.Get)
MutateActionUrl(location);
else if (Method == HttpMethod.Post) {
SubmitAsEntityBody(location);
}
} else if (a == KnownProtocols.Data) {
if (Method == HttpMethod.Get)
GetActionUrl(location);
else if (Method == HttpMethod.Post) {
PostToData(location);
}
} else if (a == KnownProtocols.Mailto) {
if (Method == HttpMethod.Get)
MailWithHeaders(location);
else if (Method == HttpMethod.Post) {
MailAsBody(location);
}
} else if (a == KnownProtocols.Ftp || a == KnownProtocols.JavaScript) {
GetActionUrl(location);
} else {
MutateActionUrl(location);
}
}
}
private void PostToData(Location action)
{
string charset = string.IsNullOrEmpty(AcceptCharset) ? base.OwnerDocument.CharacterSet : AcceptCharset;
FormDataSet formDataSet = ConstructDataSet(null);
string enctype = Enctype;
string value = string.Empty;
if (enctype.Equals(MimeTypes.StandardForm, StringComparison.OrdinalIgnoreCase)) {
using (StreamReader streamReader = new StreamReader(formDataSet.AsUrlEncoded(DocumentEncoding.Resolve(charset))))
value = streamReader.ReadToEnd();
} else if (enctype.Equals(MimeTypes.MultipartForm, StringComparison.OrdinalIgnoreCase)) {
using (StreamReader streamReader2 = new StreamReader(formDataSet.AsMultipart(DocumentEncoding.Resolve(charset))))
value = streamReader2.ReadToEnd();
} else if (enctype.Equals(MimeTypes.Plain, StringComparison.OrdinalIgnoreCase)) {
using (StreamReader streamReader3 = new StreamReader(formDataSet.AsPlaintext(DocumentEncoding.Resolve(charset))))
value = streamReader3.ReadToEnd();
}
if (action.Href.Contains("%%%%")) {
value = value.UrlEncode(System.Text.Encoding.GetEncoding("us-ascii"));
action.Href = action.Href.ReplaceFirst("%%%%", value);
} else if (action.Href.Contains("%%")) {
value = value.UrlEncode(System.Text.Encoding.UTF8);
action.Href = action.Href.ReplaceFirst("%%", value);
}
_plannedNavigation = NavigateTo(action.ToUri(), HttpMethod.Get, null, null);
}
private void MailWithHeaders(Location action)
{
FormDataSet formDataSet = ConstructDataSet(null);
Stream stream = formDataSet.AsUrlEncoded(System.Text.Encoding.GetEncoding("us-ascii"));
string text = string.Empty;
using (StreamReader streamReader = new StreamReader(stream))
text = streamReader.ReadToEnd();
action.Search = text.Replace("+", "%20");
GetActionUrl(action);
}
private void MailAsBody(Location action)
{
FormDataSet formDataSet = ConstructDataSet(null);
string enctype = Enctype;
Encoding encoding = System.Text.Encoding.GetEncoding("us-ascii");
string value = string.Empty;
if (enctype.Equals(MimeTypes.StandardForm, StringComparison.OrdinalIgnoreCase)) {
using (StreamReader streamReader = new StreamReader(formDataSet.AsUrlEncoded(encoding)))
value = streamReader.ReadToEnd();
} else if (enctype.Equals(MimeTypes.MultipartForm, StringComparison.OrdinalIgnoreCase)) {
using (StreamReader streamReader2 = new StreamReader(formDataSet.AsMultipart(encoding)))
value = streamReader2.ReadToEnd();
} else if (enctype.Equals(MimeTypes.Plain, StringComparison.OrdinalIgnoreCase)) {
using (StreamReader streamReader3 = new StreamReader(formDataSet.AsPlaintext(encoding)))
value = streamReader3.ReadToEnd();
}
action.Search = "body=" + value.UrlEncode(encoding);
GetActionUrl(action);
}
private void GetActionUrl(Location action)
{
_plannedNavigation = NavigateTo(action.ToUri(), HttpMethod.Get, null, null);
}
private void SubmitAsEntityBody(Location action)
{
string charset = string.IsNullOrEmpty(AcceptCharset) ? base.OwnerDocument.CharacterSet : AcceptCharset;
FormDataSet formDataSet = ConstructDataSet(null);
string enctype = Enctype;
string mime = string.Empty;
Stream body = null;
if (enctype.Equals(MimeTypes.StandardForm, StringComparison.OrdinalIgnoreCase)) {
body = formDataSet.AsUrlEncoded(DocumentEncoding.Resolve(charset));
mime = MimeTypes.StandardForm;
} else if (enctype.Equals(MimeTypes.MultipartForm, StringComparison.OrdinalIgnoreCase)) {
body = formDataSet.AsMultipart(DocumentEncoding.Resolve(charset));
mime = MimeTypes.MultipartForm + "; boundary=" + formDataSet.Boundary;
} else if (enctype.Equals(MimeTypes.Plain, StringComparison.OrdinalIgnoreCase)) {
body = formDataSet.AsPlaintext(DocumentEncoding.Resolve(charset));
mime = MimeTypes.Plain;
}
_plannedNavigation = NavigateTo(action.ToUri(), HttpMethod.Post, body, mime);
}
private async Task (Uri action, HttpMethod method, Stream body = null, string mime = null)
{
if (_plannedNavigation != null) {
_cancel.Cancel();
_plannedNavigation = null;
_cancel = new CancellationTokenSource();
}
Stream stream = await _owner.Options.SendAsync(action, body, mime, method, _cancel.Token, false);
(_owner as HTMLDocument)?.Load(stream);
}
private void MutateActionUrl(Location action)
{
string charset = string.IsNullOrEmpty(AcceptCharset) ? base.OwnerDocument.CharacterSet : AcceptCharset;
FormDataSet formDataSet = ConstructDataSet(null);
Stream stream = formDataSet.AsUrlEncoded(DocumentEncoding.Resolve(charset));
using (StreamReader streamReader = new StreamReader(stream))
action.Search = streamReader.ReadToEnd();
GetActionUrl(action);
}
private FormDataSet ConstructDataSet(HTMLElement submitter = null)
{
FormDataSet formDataSet = new FormDataSet();
foreach (HTMLFormControlElement element in _elements) {
if (!(element.ParentElement is HTMLDataListElement) && !element.Disabled)
element.ConstructDataSet(formDataSet, submitter);
}
return formDataSet;
}
private string CheckEncType(string encType)
{
if (!string.IsNullOrEmpty(encType) && (encType.Equals(MimeTypes.Plain, StringComparison.OrdinalIgnoreCase) || encType.Equals(MimeTypes.MultipartForm, StringComparison.OrdinalIgnoreCase)))
return encType;
return MimeTypes.StandardForm;
}
}
}