HttpInputItem.cs 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309
  1. using System;
  2. using System.Collections;
  3. using System.Collections.Generic;
  4. namespace OSHttpServer
  5. {
  6. /// <summary>
  7. /// represents a HTTP input item. Each item can have multiple sub items, a sub item
  8. /// is made in a HTML form by using square brackets
  9. /// </summary>
  10. /// <example>
  11. /// // <input type="text" name="user[FirstName]" value="jonas" /> becomes:
  12. /// Console.WriteLine("Value: {0}", form["user"]["FirstName"].Value);
  13. /// </example>
  14. /// <remarks>
  15. /// All names in a form SHOULD be in lowercase.
  16. /// </remarks>
  17. public class HttpInputItem : IHttpInput
  18. {
  19. /// <summary> Representation of a non-initialized <see cref="HttpInputItem"/>.</summary>
  20. public static readonly HttpInputItem Empty = new HttpInputItem(string.Empty, true);
  21. private readonly IDictionary<string, HttpInputItem> _items = new Dictionary<string, HttpInputItem>();
  22. private readonly List<string> _values = new List<string>();
  23. private string _name;
  24. private readonly bool _ignoreChanges;
  25. /// <summary>
  26. /// Initializes an input item setting its name/identifier and value
  27. /// </summary>
  28. /// <param name="name">Parameter name/id</param>
  29. /// <param name="value">Parameter value</param>
  30. public HttpInputItem(string name, string value)
  31. {
  32. Name = name;
  33. Add(value);
  34. }
  35. private HttpInputItem(string name, bool ignore)
  36. {
  37. Name = name;
  38. _ignoreChanges = ignore;
  39. }
  40. /// <summary>Creates a deep copy of the item specified</summary>
  41. /// <param name="item">The item to copy</param>
  42. /// <remarks>The function makes a deep copy of quite a lot which can be slow</remarks>
  43. public HttpInputItem(HttpInputItem item)
  44. {
  45. foreach (KeyValuePair<string, HttpInputItem> pair in item._items)
  46. _items.Add(pair.Key, pair.Value);
  47. foreach (string value in item._values)
  48. _values.Add(value);
  49. _ignoreChanges = item._ignoreChanges;
  50. _name = item.Name;
  51. }
  52. /// <summary>
  53. /// Number of values
  54. /// </summary>
  55. public int Count
  56. {
  57. get { return _values.Count; }
  58. }
  59. /// <summary>
  60. /// Get a sub item
  61. /// </summary>
  62. /// <param name="name">name in lower case.</param>
  63. /// <returns><see cref="HttpInputItem.Empty"/> if no item was found.</returns>
  64. public HttpInputItem this[string name]
  65. {
  66. get {
  67. return _items.ContainsKey(name) ? _items[name] : Empty;
  68. }
  69. }
  70. /// <summary>
  71. /// Name of item (in lower case).
  72. /// </summary>
  73. public string Name
  74. {
  75. get { return _name; }
  76. set { _name = value; }
  77. }
  78. /// <summary>
  79. /// Returns the first value, or null if no value exist.
  80. /// </summary>
  81. public string Value
  82. {
  83. get {
  84. return _values.Count == 0 ? null : _values[0];
  85. }
  86. set
  87. {
  88. if (_values.Count == 0)
  89. _values.Add(value);
  90. else
  91. _values[0] = value;
  92. }
  93. }
  94. /// <summary>
  95. /// Returns the last value, or null if no value exist.
  96. /// </summary>
  97. public string LastValue
  98. {
  99. get
  100. {
  101. return _values.Count == 0 ? null : _values[_values.Count - 1];
  102. }
  103. }
  104. /// <summary>
  105. /// Returns the list with values.
  106. /// </summary>
  107. public IList<string> Values
  108. {
  109. get { return _values.AsReadOnly(); }
  110. }
  111. /// <summary>
  112. /// Add another value to this item
  113. /// </summary>
  114. /// <param name="value">Value to add.</param>
  115. /// <exception cref="InvalidOperationException">Cannot add stuff to <see cref="HttpInput.Empty"/>.</exception>
  116. public void Add(string value)
  117. {
  118. if (value == null)
  119. return;
  120. if (_ignoreChanges)
  121. throw new InvalidOperationException("Cannot add stuff to HttpInput.Empty.");
  122. _values.Add(value);
  123. }
  124. /// <summary>
  125. /// checks if a sub-item exists (and has a value).
  126. /// </summary>
  127. /// <param name="name">name in lower case</param>
  128. /// <returns>true if the sub-item exists and has a value; otherwise false.</returns>
  129. public bool Contains(string name)
  130. {
  131. return _items.ContainsKey(name) && _items[name].Value != null;
  132. }
  133. /// <summary> Returns a formatted representation of the instance with the values of all contained parameters </summary>
  134. public override string ToString()
  135. {
  136. return ToString(string.Empty);
  137. }
  138. /// <summary>
  139. /// Outputs the string in a formatted manner
  140. /// </summary>
  141. /// <param name="prefix">A prefix to append, used internally</param>
  142. /// <param name="asQuerySting">produce a query string</param>
  143. public string ToString(string prefix, bool asQuerySting)
  144. {
  145. string name;
  146. if (string.IsNullOrEmpty(prefix))
  147. name = Name;
  148. else
  149. name = prefix + "[" + Name + "]";
  150. if (asQuerySting)
  151. {
  152. string temp;
  153. if (_values.Count == 0 && _items.Count > 0)
  154. temp = string.Empty;
  155. else
  156. temp = name;
  157. if (_values.Count > 0)
  158. {
  159. temp += '=';
  160. foreach (string value in _values)
  161. temp += value + ',';
  162. temp = temp.Remove(temp.Length - 1, 1);
  163. }
  164. foreach (KeyValuePair<string, HttpInputItem> item in _items)
  165. temp += item.Value.ToString(name, true) + '&';
  166. return _items.Count > 0 ? temp.Substring(0, temp.Length - 1) : temp;
  167. }
  168. else
  169. {
  170. string temp = name;
  171. if (_values.Count > 0)
  172. {
  173. temp += " = ";
  174. foreach (string value in _values)
  175. temp += value + ", ";
  176. temp = temp.Remove(temp.Length - 2, 2);
  177. }
  178. temp += Environment.NewLine;
  179. foreach (KeyValuePair<string, HttpInputItem> item in _items)
  180. temp += item.Value.ToString(name, false);
  181. return temp;
  182. }
  183. }
  184. #region IHttpInput Members
  185. /// <summary>
  186. ///
  187. /// </summary>
  188. /// <param name="name">name in lower case</param>
  189. /// <returns></returns>
  190. HttpInputItem IHttpInput.this[string name]
  191. {
  192. get
  193. {
  194. return _items.ContainsKey(name) ? _items[name] : Empty;
  195. }
  196. }
  197. /// <summary>
  198. /// Add a sub item.
  199. /// </summary>
  200. /// <param name="name">Can contain array formatting, the item is then parsed and added in multiple levels</param>
  201. /// <param name="value">Value to add.</param>
  202. /// <exception cref="ArgumentNullException">Argument is null.</exception>
  203. /// <exception cref="InvalidOperationException">Cannot add stuff to <see cref="HttpInput.Empty"/>.</exception>
  204. public void Add(string name, string value)
  205. {
  206. if (name == null && value != null)
  207. throw new ArgumentNullException("name");
  208. if (name == null)
  209. return;
  210. if (_ignoreChanges)
  211. throw new InvalidOperationException("Cannot add stuff to HttpInput.Empty.");
  212. int pos = name.IndexOf('[');
  213. if (pos != -1)
  214. {
  215. string name1 = name.Substring(0, pos);
  216. string name2 = HttpInput.ExtractOne(name);
  217. if (!_items.ContainsKey(name1))
  218. _items.Add(name1, new HttpInputItem(name1, null));
  219. _items[name1].Add(name2, value);
  220. /*
  221. HttpInputItem item = HttpInput.ParseItem(name, value);
  222. // Add the value to an existing sub item
  223. if (_items.ContainsKey(item.Name))
  224. _items[item.Name].Add(item.Value);
  225. else
  226. _items.Add(item.Name, item);
  227. */
  228. }
  229. else
  230. {
  231. if (_items.ContainsKey(name))
  232. _items[name].Add(value);
  233. else
  234. _items.Add(name, new HttpInputItem(name, value));
  235. }
  236. }
  237. #endregion
  238. ///<summary>
  239. ///Returns an enumerator that iterates through the collection.
  240. ///</summary>
  241. ///
  242. ///<returns>
  243. ///A <see cref="T:System.Collections.Generic.IEnumerator`1"></see> that can be used to iterate through the collection.
  244. ///</returns>
  245. ///<filterpriority>1</filterpriority>
  246. IEnumerator<HttpInputItem> IEnumerable<HttpInputItem>.GetEnumerator()
  247. {
  248. return _items.Values.GetEnumerator();
  249. }
  250. #region IEnumerable Members
  251. ///<summary>
  252. ///Returns an enumerator that iterates through a collection.
  253. ///</summary>
  254. ///
  255. ///<returns>
  256. ///An <see cref="T:System.Collections.IEnumerator"></see> object that can be used to iterate through the collection.
  257. ///</returns>
  258. ///<filterpriority>2</filterpriority>
  259. public IEnumerator GetEnumerator()
  260. {
  261. return _items.Values.GetEnumerator();
  262. }
  263. #endregion
  264. /// <summary>
  265. /// Outputs the string in a formatted manner
  266. /// </summary>
  267. /// <param name="prefix">A prefix to append, used internally</param>
  268. /// <returns></returns>
  269. public string ToString(string prefix)
  270. {
  271. return ToString(prefix, false);
  272. }
  273. }
  274. }