HttpInput.cs 9.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263
  1. using System;
  2. using System.Collections;
  3. using System.Collections.Generic;
  4. namespace OSHttpServer
  5. {
  6. /// <summary>
  7. /// Contains some kind of input from the browser/client.
  8. /// can be QueryString, form data or any other request body content.
  9. /// </summary>
  10. public class HttpInput : IHttpInput
  11. {
  12. /// <summary> Representation of a non-initialized class instance </summary>
  13. public static readonly HttpInput Empty = new HttpInput("Empty", true);
  14. private readonly IDictionary<string, HttpInputItem> _items = new Dictionary<string, HttpInputItem>();
  15. private string _name;
  16. /// <summary> Variable telling the class that it is non-initialized <see cref="Empty"/> </summary>
  17. protected readonly bool _ignoreChanges;
  18. /// <summary>
  19. /// Initializes a new instance of the <see cref="HttpInput"/> class.
  20. /// </summary>
  21. /// <param name="name">form name.</param>
  22. public HttpInput(string name)
  23. {
  24. Name = name;
  25. }
  26. /// <summary>
  27. /// Initializes a new instance of the <see cref="HttpInput"/> class.
  28. /// </summary>
  29. /// <param name="name">form name.</param>
  30. /// <param name="ignoreChanges">if set to <c>true</c> all changes will be ignored. </param>
  31. /// <remarks>this constructor should only be used by Empty</remarks>
  32. protected HttpInput(string name, bool ignoreChanges)
  33. {
  34. _name = name;
  35. _ignoreChanges = ignoreChanges;
  36. }
  37. /// <summary>Creates a deep copy of the HttpInput class</summary>
  38. /// <param name="input">The object to copy</param>
  39. /// <remarks>The function makes a deep copy of quite a lot which can be slow</remarks>
  40. protected HttpInput(HttpInput input)
  41. {
  42. foreach (HttpInputItem item in input)
  43. _items.Add(item.Name, new HttpInputItem(item));
  44. _name = input._name;
  45. _ignoreChanges = input._ignoreChanges;
  46. }
  47. /// <summary>
  48. /// Form name as lower case
  49. /// </summary>
  50. public string Name
  51. {
  52. get { return _name; }
  53. set { _name = value; }
  54. }
  55. /// <summary>
  56. /// Add a new element. Form array elements are parsed
  57. /// and added in a correct hierarchy.
  58. /// </summary>
  59. /// <param name="name">Name is converted to lower case.</param>
  60. /// <param name="value"></param>
  61. /// <exception cref="ArgumentNullException"><c>name</c> is null.</exception>
  62. /// <exception cref="InvalidOperationException">Cannot add stuff to <see cref="HttpInput.Empty"/>.</exception>
  63. public void Add(string name, string value)
  64. {
  65. if (name == null)
  66. throw new ArgumentNullException("name");
  67. if (_ignoreChanges)
  68. throw new InvalidOperationException("Cannot add stuff to HttpInput.Empty.");
  69. // Check if it's a sub item.
  70. // we can have multiple levels of sub items as in user[extension[id]] => user -> extension -> id
  71. int pos = name.IndexOf('[');
  72. if (pos != -1)
  73. {
  74. string name1 = name.Substring(0, pos);
  75. string name2 = ExtractOne(name);
  76. if (!_items.ContainsKey(name1))
  77. _items.Add(name1, new HttpInputItem(name1, null));
  78. _items[name1].Add(name2, value);
  79. }
  80. else
  81. {
  82. if (_items.ContainsKey(name))
  83. _items[name].Add(value);
  84. else
  85. _items.Add(name, new HttpInputItem(name, value));
  86. }
  87. }
  88. /// <summary>
  89. /// Get a form item.
  90. /// </summary>
  91. /// <param name="name"></param>
  92. /// <returns>Returns <see cref="HttpInputItem.Empty"/> if item was not found.</returns>
  93. public HttpInputItem this[string name]
  94. {
  95. get
  96. {
  97. return _items.ContainsKey(name) ? _items[name] : HttpInputItem.Empty;
  98. }
  99. }
  100. /// <summary>
  101. /// Returns true if the class contains a <see cref="HttpInput"/> with the corresponding name.
  102. /// </summary>
  103. /// <param name="name">The field/query string name</param>
  104. /// <returns>True if the value exists</returns>
  105. public bool Contains(string name)
  106. {
  107. return _items.ContainsKey(name) && _items[name].Value != null;
  108. }
  109. /// <summary>
  110. /// Parses an item and returns it.
  111. /// This function is primarily used to parse array items as in user[name].
  112. /// </summary>
  113. /// <param name="name"></param>
  114. /// <param name="value"></param>
  115. /// <returns></returns>
  116. public static HttpInputItem ParseItem(string name, string value)
  117. {
  118. HttpInputItem item;
  119. // Check if it's a sub item.
  120. // we can have multiple levels of sub items as in user[extension[id]]] => user -> extension -> id
  121. int pos = name.IndexOf('[');
  122. if (pos != -1)
  123. {
  124. string name1 = name.Substring(0, pos);
  125. string name2 = ExtractOne(name);
  126. item = new HttpInputItem(name1, null);
  127. item.Add(name2, value);
  128. }
  129. else
  130. item = new HttpInputItem(name, value);
  131. return item;
  132. }
  133. /// <summary> Outputs the instance representing all its values joined together </summary>
  134. /// <returns></returns>
  135. public override string ToString()
  136. {
  137. string temp = string.Empty;
  138. foreach (KeyValuePair<string, HttpInputItem> item in _items)
  139. temp += item.Value.ToString(Name);
  140. return temp;
  141. }
  142. /// <summary>Returns all items as an unescaped query string.</summary>
  143. /// <returns></returns>
  144. public string ToString(bool asQueryString)
  145. {
  146. if (!asQueryString)
  147. return ToString();
  148. string temp = string.Empty;
  149. foreach (KeyValuePair<string, HttpInputItem> item in _items)
  150. temp += item.Value.ToString(null, true) + '&';
  151. return temp.Length > 0 ? temp.Substring(0, temp.Length - 1) : string.Empty;
  152. }
  153. /// <summary>
  154. /// Extracts one parameter from an array
  155. /// </summary>
  156. /// <param name="value">Containing the string array</param>
  157. /// <returns>All but the first value</returns>
  158. /// <example>
  159. /// string test1 = ExtractOne("system[user][extension][id]");
  160. /// string test2 = ExtractOne(test1);
  161. /// string test3 = ExtractOne(test2);
  162. /// // test1 = user[extension][id]
  163. /// // test2 = extension[id]
  164. /// // test3 = id
  165. /// </example>
  166. public static string ExtractOne(string value)
  167. {
  168. int pos = value.IndexOf('[');
  169. if (pos != -1)
  170. {
  171. ++pos;
  172. int gotMore = value.IndexOf('[', pos + 1);
  173. if (gotMore != -1)
  174. value = value.Substring(pos, gotMore - pos - 1) + value.Substring(gotMore);
  175. else
  176. value = value.Substring(pos, value.Length - pos - 1);
  177. }
  178. return value;
  179. }
  180. /// <summary>Resets all data contained by class</summary>
  181. virtual public void Clear()
  182. {
  183. _name = string.Empty;
  184. _items.Clear();
  185. }
  186. ///<summary>
  187. ///Returns an enumerator that iterates through the collection.
  188. ///</summary>
  189. ///
  190. ///<returns>
  191. ///A <see cref="T:System.Collections.Generic.IEnumerator`1"></see> that can be used to iterate through the collection.
  192. ///</returns>
  193. ///<filterpriority>1</filterpriority>
  194. IEnumerator<HttpInputItem> IEnumerable<HttpInputItem>.GetEnumerator()
  195. {
  196. return _items.Values.GetEnumerator();
  197. }
  198. ///<summary>
  199. ///Returns an enumerator that iterates through a collection.
  200. ///</summary>
  201. ///
  202. ///<returns>
  203. ///An <see cref="T:System.Collections.IEnumerator"></see> object that can be used to iterate through the collection.
  204. ///</returns>
  205. ///<filterpriority>2</filterpriority>
  206. public IEnumerator GetEnumerator()
  207. {
  208. return _items.Values.GetEnumerator();
  209. }
  210. }
  211. /// <summary>
  212. /// Base class for request data containers
  213. /// </summary>
  214. public interface IHttpInput : IEnumerable<HttpInputItem>
  215. {
  216. /// <summary>
  217. /// Adds a parameter mapped to the presented name
  218. /// </summary>
  219. /// <param name="name">The name to map the parameter to</param>
  220. /// <param name="value">The parameter value</param>
  221. void Add(string name, string value);
  222. /// <summary>
  223. /// Returns a request parameter
  224. /// </summary>
  225. /// <param name="name">The name associated with the parameter</param>
  226. /// <returns></returns>
  227. HttpInputItem this[string name]
  228. { get; }
  229. /// <summary>
  230. /// Returns true if the container contains the requested parameter
  231. /// </summary>
  232. /// <param name="name">Parameter id</param>
  233. /// <returns>True if parameter exists</returns>
  234. bool Contains(string name);
  235. }
  236. }