FormRequest.cs 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176
  1. using System;
  2. using System.Collections.Specialized;
  3. using System.Text;
  4. using System.Web;
  5. using System.IO;
  6. using System.Collections;
  7. using System.Xml;
  8. using System.Globalization;
  9. namespace MonoTests.SystemWeb.Framework
  10. {
  11. /// <summary>
  12. /// This class is used for HTML form postback request.
  13. /// </summary>
  14. [Serializable]
  15. public class FormRequest : PostableRequest
  16. {
  17. /// <summary>
  18. /// Create <see cref="FormRequest"/> instance from the given
  19. /// <paramref name="response">response</paramref> extracting
  20. /// form attributes and hidden controls from the form element
  21. /// with given id.
  22. /// </summary>
  23. /// <param name="response">The response to extract values from.</param>
  24. /// <param name="formId">The id of the form to use.</param>
  25. /// <remarks>Currently, the <paramref name="formId"/> is ignored, and the
  26. /// first form is used.</remarks>
  27. public FormRequest (Response response, string formId)
  28. {
  29. _controls = new BaseControlCollection ();
  30. ExtractFormAndHiddenControls (response, formId);
  31. }
  32. private BaseControlCollection _controls;
  33. /// <summary>
  34. /// Get or set the collection of controls, posted back to the server.
  35. /// </summary>
  36. public BaseControlCollection Controls
  37. {
  38. get { return _controls; }
  39. set { _controls = value; }
  40. }
  41. private void ExtractFormAndHiddenControls (Response response, string formId)
  42. {
  43. HtmlAgilityPack.HtmlDocument htmlDoc = new HtmlAgilityPack.HtmlDocument ();
  44. htmlDoc.LoadHtml (response.Body);
  45. StringBuilder tempxml = new StringBuilder ();
  46. StringWriter tsw = new StringWriter (tempxml);
  47. htmlDoc.OptionOutputAsXml = true;
  48. htmlDoc.Save (tsw);
  49. XmlDocument doc = new XmlDocument ();
  50. doc.LoadXml (tempxml.ToString ());
  51. const string HTML_NAMESPACE = "http://www.w3.org/1999/xhtml";
  52. XmlNamespaceManager nsmgr = new XmlNamespaceManager (doc.NameTable);
  53. nsmgr.AddNamespace ("html", HTML_NAMESPACE);
  54. #if USE_CORRECT_FORMID
  55. XmlNode formNode = doc.SelectSingleNode ("//html:form[@name='" + formId + "']", nsmgr);
  56. #else
  57. XmlNode formNode = doc.SelectSingleNode ("//html:form", nsmgr);
  58. #endif
  59. if (formNode == null)
  60. throw new ArgumentException ("Form with id='" + formId +
  61. "' was not found in document: " + response.Body);
  62. string actionUrl = formNode.Attributes["action"].Value;
  63. if (actionUrl != null && actionUrl != string.Empty)
  64. base.Url = actionUrl;
  65. XmlNode method = formNode.Attributes["method"];
  66. if (method != null && "POST" == method.Value.ToUpper(CultureInfo.InvariantCulture))
  67. base.IsPost = true;
  68. else
  69. base.IsPost = false;
  70. #if USE_CORRECT_FORMID
  71. foreach (XmlNode inputNode in formNode.SelectNodes ("//html:input", nsmgr))
  72. #else
  73. foreach (XmlNode inputNode in doc.SelectNodes ("//html:input[@type='hidden']", nsmgr))
  74. #endif
  75. {
  76. BaseControl bc = new BaseControl ();
  77. bc.Name = inputNode.Attributes["name"].Value;
  78. if (bc.Name == null || bc.Name == string.Empty)
  79. continue;
  80. if (inputNode.Attributes["value"] != null)
  81. bc.Value = inputNode.Attributes["value"].Value;
  82. else
  83. bc.Value = "";
  84. Controls[bc.Name] = bc;
  85. }
  86. }
  87. /// <summary>
  88. /// Get the URL extracted from the form. Unlike the base class, here this
  89. /// property should not be changed, otherwise an <see cref="Exception"/>
  90. /// is thrown.
  91. /// </summary>
  92. /// Get returns true if the form method was POST, otherwise returns false.
  93. /// Unlike the base class, here this property should not be
  94. /// changed, otherwise an <see cref="Exception"/> is thrown.
  95. /// </summary>
  96. /// <exception cref="Exception">Thrown when trying to change this property.</exception>
  97. public override bool IsPost
  98. {
  99. get { return base.IsPost; }
  100. set { throw new Exception ("Must not change IsPost of FormPostback"); }
  101. }
  102. /// <summary>
  103. /// Returns the HTTP content-type header value. Currently hard-coded to return
  104. /// <c>application/x-www-form-urlencoded</c>.
  105. /// </summary>
  106. public override string ContentType
  107. {
  108. get { return "application/x-www-form-urlencoded"; }
  109. set { throw new Exception ("Must not change PostContentType of FormPostback"); }
  110. }
  111. /// <summary>
  112. /// Returns the HTTP <c>entity-body</c> header value.
  113. /// </summary>
  114. public override byte[] EntityBody
  115. {
  116. get
  117. {
  118. if (IsPost)
  119. return Encoding.ASCII.GetBytes (GetUrlencodedDataset ());
  120. else
  121. return null;
  122. }
  123. set { throw new Exception ("Must not change EntityBody of FormPostback"); }
  124. }
  125. /// <summary>
  126. /// Get the URL encoded query string in format <c><![CDATA[name1=value1&name2=value2]]></c>, etc.
  127. /// </summary>
  128. protected override string QueryString
  129. {
  130. get
  131. {
  132. if (IsPost)
  133. return "";
  134. else
  135. return GetUrlencodedDataset ();
  136. }
  137. }
  138. private string GetUrlencodedDataset ()
  139. {
  140. StringBuilder query = new StringBuilder ();
  141. bool first = true;
  142. foreach (string key in Controls.Keys) {
  143. BaseControl ctrl = Controls[key];
  144. if (!ctrl.IsSuccessful ())
  145. continue;
  146. if (first)
  147. first = false;
  148. else
  149. query.Append ("&");
  150. query.Append (HttpUtility.UrlEncode (ctrl.Name));
  151. query.Append ("=");
  152. query.Append (HttpUtility.UrlEncode (ctrl.Value));
  153. }
  154. return query.ToString ();
  155. }
  156. }
  157. }