/src/EasyHttp/Codecs/JsonFXExtensions/RegExBasedDataWriterProvider.cs

http://github.com/hhariri/EasyHttp · C# · 214 lines · 124 code · 28 blank · 62 comment · 16 complexity · 1968285454719c6eaec272f667bc4b59 MD5 · raw file

  1. #region License
  2. // Distributed under the BSD License
  3. // =================================
  4. //
  5. // Copyright (c) 2010, Hadi Hariri
  6. // All rights reserved.
  7. //
  8. // Redistribution and use in source and binary forms, with or without
  9. // modification, are permitted provided that the following conditions are met:
  10. // * Redistributions of source code must retain the above copyright
  11. // notice, this list of conditions and the following disclaimer.
  12. // * Redistributions in binary form must reproduce the above copyright
  13. // notice, this list of conditions and the following disclaimer in the
  14. // documentation and/or other materials provided with the distribution.
  15. // * Neither the name of Hadi Hariri nor the
  16. // names of its contributors may be used to endorse or promote products
  17. // derived from this software without specific prior written permission.
  18. //
  19. // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
  20. // ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
  21. // WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
  22. // DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
  23. // DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
  24. // (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
  25. // LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
  26. // ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  27. // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
  28. // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  29. // =============================================================
  30. //
  31. //
  32. // Parts of this Software use JsonFX Serialization Library which is distributed under the MIT License:
  33. //
  34. // Distributed under the terms of an MIT-style license:
  35. //
  36. // The MIT License
  37. //
  38. // Copyright (c) 2006-2009 Stephen M. McKamey
  39. //
  40. // Permission is hereby granted, free of charge, to any person obtaining a copy
  41. // of this software and associated documentation files (the "Software"), to deal
  42. // in the Software without restriction, including without limitation the rights
  43. // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  44. // copies of the Software, and to permit persons to whom the Software is
  45. // furnished to do so, subject to the following conditions:
  46. //
  47. // The above copyright notice and this permission notice shall be included in
  48. // all copies or substantial portions of the Software.
  49. //
  50. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  51. // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  52. // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  53. // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  54. // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  55. // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  56. // THE SOFTWARE.
  57. #endregion
  58. using System;
  59. using System.Collections.Generic;
  60. using System.IO;
  61. using System.Linq;
  62. using System.Text.RegularExpressions;
  63. using JsonFx.Serialization;
  64. using JsonFx.Serialization.Providers;
  65. namespace EasyHttp.Codecs.JsonFXExtensions
  66. {
  67. // TODO: This is a copy of the DataWriterProvider in JsonFX. Need to clean it up and move things elsewhere
  68. public class RegExBasedDataWriterProvider: IDataWriterProvider
  69. {
  70. readonly IDataWriter _defaultWriter;
  71. readonly IDictionary<string, IDataWriter> _writersByExt = new Dictionary<string, IDataWriter>(StringComparer.OrdinalIgnoreCase);
  72. readonly IDictionary<string, IDataWriter> _writersByMime = new Dictionary<string, IDataWriter>(StringComparer.OrdinalIgnoreCase);
  73. public RegExBasedDataWriterProvider(IEnumerable<IDataWriter> writers)
  74. {
  75. if (writers != null)
  76. {
  77. foreach (IDataWriter writer in writers)
  78. {
  79. if (_defaultWriter == null)
  80. {
  81. // TODO: decide less arbitrary way to choose default
  82. // without hardcoding value into IDataWriter.
  83. // Currently first DataWriter wins default.
  84. _defaultWriter = writer;
  85. }
  86. foreach (string contentType in writer.ContentType)
  87. {
  88. if (String.IsNullOrEmpty(contentType) ||
  89. _writersByMime.ContainsKey(contentType))
  90. {
  91. continue;
  92. }
  93. _writersByMime[contentType] = writer;
  94. }
  95. foreach (string fileExt in writer.FileExtension)
  96. {
  97. if (String.IsNullOrEmpty(fileExt) ||
  98. _writersByExt.ContainsKey(fileExt))
  99. {
  100. continue;
  101. }
  102. string ext = NormalizeExtension(fileExt);
  103. _writersByExt[ext] = writer;
  104. }
  105. }
  106. }
  107. }
  108. public IDataWriter DefaultDataWriter
  109. {
  110. get { return _defaultWriter; }
  111. }
  112. public IDataWriter Find(string extension)
  113. {
  114. extension = NormalizeExtension(extension);
  115. IDataWriter writer;
  116. if (_writersByExt.TryGetValue(extension, out writer))
  117. {
  118. return writer;
  119. }
  120. return null;
  121. }
  122. public IDataWriter Find(string acceptHeader, string contentTypeHeader)
  123. {
  124. foreach (string type in ParseHeaders(acceptHeader, contentTypeHeader))
  125. {
  126. var readers = from writer in _writersByMime
  127. where Regex.Match(type, writer.Key, RegexOptions.Singleline).Success
  128. select writer;
  129. if (readers.Count() > 0)
  130. {
  131. return readers.First().Value;
  132. }
  133. }
  134. return null;
  135. }
  136. public static IEnumerable<string> ParseHeaders(string accept, string contentType)
  137. {
  138. string mime;
  139. // check for a matching accept type
  140. foreach (string type in SplitTrim(accept, ','))
  141. {
  142. mime = DataProviderUtility.ParseMediaType(type);
  143. if (!String.IsNullOrEmpty(mime))
  144. {
  145. yield return mime;
  146. }
  147. }
  148. // fallback on content-type
  149. mime = DataProviderUtility.ParseMediaType(contentType);
  150. if (!String.IsNullOrEmpty(mime))
  151. {
  152. yield return mime;
  153. }
  154. }
  155. private static IEnumerable<string> SplitTrim(string source, char ch)
  156. {
  157. if (String.IsNullOrEmpty(source))
  158. {
  159. yield break;
  160. }
  161. int length = source.Length;
  162. for (int prev=0, next=0; prev<length && next>=0; prev=next+1)
  163. {
  164. next = source.IndexOf(ch, prev);
  165. if (next < 0)
  166. {
  167. next = length;
  168. }
  169. string part = source.Substring(prev, next-prev).Trim();
  170. if (part.Length > 0)
  171. {
  172. yield return part;
  173. }
  174. }
  175. }
  176. private static string NormalizeExtension(string extension)
  177. {
  178. if (String.IsNullOrEmpty(extension))
  179. {
  180. return String.Empty;
  181. }
  182. // ensure is only extension with leading dot
  183. return Path.GetExtension(extension);
  184. }
  185. }
  186. }