ResponseBody.cs 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353
  1. using System;
  2. using System.IO;
  3. using COSXML.Log;
  4. namespace COSXML.Network
  5. {
  6. public sealed class ResponseBody
  7. {
  8. private const int SEGMENT_SIZE = 4096;
  9. private long contentLength = -1L;
  10. private string contentType;
  11. private COSXML.Callback.OnProgressCallback progressCallback;
  12. private COSXML.Callback.OnParseStream parseStream;
  13. private string filePath;
  14. private long fileOffset;
  15. private FileStream fileStream;
  16. private bool isDownload = false;
  17. private MemoryStream memoryStream;
  18. public long ContentLength
  19. {
  20. get
  21. {
  22. return contentLength;
  23. }
  24. set { contentLength = value; }
  25. }
  26. public string ContentType
  27. {
  28. get
  29. {
  30. return contentType;
  31. }
  32. set { contentType = value; }
  33. }
  34. public COSXML.Callback.OnProgressCallback ProgressCallback
  35. {
  36. get
  37. {
  38. return progressCallback;
  39. }
  40. set { progressCallback = value; }
  41. }
  42. public COSXML.Callback.OnParseStream ParseStream
  43. {
  44. get
  45. {
  46. return parseStream;
  47. }
  48. set { parseStream = value; }
  49. }
  50. public string rawContentBodyString { get; private set; }
  51. public ResponseBody()
  52. {
  53. }
  54. public ResponseBody(string filePath, long fileOffset)
  55. {
  56. this.filePath = filePath;
  57. this.fileOffset = fileOffset;
  58. this.isDownload = true;
  59. }
  60. /// <summary>
  61. /// handle cos response
  62. /// </summary>
  63. /// <param name="inputStream"></param>
  64. /// <exception cref="CosServerException"> throw CosServerException </exception>
  65. /// <exception cref="Exception">throw Exception</exception>
  66. public void HandleResponseBody(Stream inputStream)
  67. {
  68. try
  69. {
  70. if (isDownload)
  71. {
  72. if (File.Exists(filePath) && new FileInfo(filePath).Length > fileOffset)
  73. {
  74. // 写脏文件了,直接 Truncate
  75. fileStream = new FileStream(filePath, FileMode.Truncate, FileAccess.Write);
  76. }
  77. else
  78. {
  79. // 正常文件或者追加写场景,直接写入
  80. fileStream = new FileStream(filePath, FileMode.OpenOrCreate, FileAccess.Write);
  81. }
  82. fileStream.Seek(fileOffset, SeekOrigin.Begin);
  83. byte[] buffer = new byte[SEGMENT_SIZE];
  84. int recvLen = 0;
  85. long completed = recvLen;
  86. while ((recvLen = inputStream.Read(buffer, 0, buffer.Length)) != 0)
  87. {
  88. fileStream.Write(buffer, 0, recvLen);
  89. if (progressCallback != null)
  90. {
  91. completed += recvLen;
  92. progressCallback(completed, contentLength);
  93. }
  94. }
  95. fileStream.Flush();
  96. }
  97. else
  98. {
  99. if ("application/xml".Equals(contentType, StringComparison.OrdinalIgnoreCase) &&
  100. contentLength > 0 && contentLength < 10 * 1000)
  101. {
  102. // save raw content
  103. memoryStream = new MemoryStream((int)contentLength);
  104. //inputStream.CopyTo(memoryStream);
  105. byte[] buffer = new byte[10 * 1000];
  106. int count;
  107. while ((count = inputStream.Read(buffer, 0, buffer.Length)) != 0)
  108. {
  109. memoryStream.Write(buffer, 0, count);
  110. }
  111. rawContentBodyString = System.Text.Encoding.UTF8.GetString(memoryStream.ToArray());
  112. memoryStream.Seek(0, SeekOrigin.Begin);
  113. inputStream = memoryStream;
  114. }
  115. if (parseStream != null)
  116. {
  117. parseStream(inputStream, contentType, contentLength);
  118. }
  119. }
  120. }
  121. catch (Exception ex)
  122. {
  123. QLog.Error("ResponseBody", ex.Message, ex);
  124. throw;
  125. }
  126. finally
  127. {
  128. if (inputStream != null)
  129. {
  130. inputStream.Close();
  131. inputStream.Dispose();
  132. }
  133. if (fileStream != null)
  134. {
  135. fileStream.Close();
  136. fileStream.Dispose();
  137. }
  138. //if (memoryStream != null) memoryStream.Close();
  139. }
  140. }
  141. public void StartHandleResponseBody(Stream inputStream, EndResponseBody endResponseBody)
  142. {
  143. ResponseBodyState responseBodyState = new ResponseBodyState();
  144. responseBodyState.inputStream = inputStream;
  145. responseBodyState.endResponseBody = endResponseBody;
  146. responseBodyState.completed = 0L;
  147. try
  148. {
  149. int count = (int)((contentLength > SEGMENT_SIZE || contentLength <= 0) ? SEGMENT_SIZE : contentLength);
  150. byte[] buffer = new byte[count];
  151. responseBodyState.buffer = buffer;
  152. if (isDownload)
  153. {
  154. if (File.Exists(filePath) && new FileInfo(filePath).Length > fileOffset)
  155. {
  156. // 写脏文件了,直接 Truncate
  157. fileStream = new FileStream(filePath, FileMode.Truncate, FileAccess.Write);
  158. }
  159. else
  160. {
  161. // 正常文件或者追加写场景,直接写入
  162. fileStream = new FileStream(filePath, FileMode.OpenOrCreate, FileAccess.Write);
  163. }
  164. fileStream.Seek(fileOffset, SeekOrigin.Begin);
  165. responseBodyState.inputStream.BeginRead(responseBodyState.buffer, 0, responseBodyState.buffer.Length, AsyncStreamCallback, responseBodyState);
  166. }
  167. else
  168. {
  169. memoryStream = new MemoryStream(count);
  170. responseBodyState.buffer = buffer;
  171. responseBodyState.inputStream.BeginRead(responseBodyState.buffer, 0, responseBodyState.buffer.Length, AsyncStreamCallback, responseBodyState);
  172. }
  173. }
  174. catch (Exception ex)
  175. {
  176. if (fileStream != null)
  177. {
  178. fileStream.Close();
  179. fileStream.Dispose();
  180. }
  181. if (memoryStream != null)
  182. {
  183. memoryStream.Close();
  184. memoryStream.Dispose();
  185. }
  186. responseBodyState.endResponseBody(false, ex);
  187. responseBodyState.Clear();
  188. QLog.Error("ResponseBody", ex.Message, ex);
  189. }
  190. }
  191. private void AsyncStreamCallback(IAsyncResult ar)
  192. {
  193. ResponseBodyState responseBodyState = ar.AsyncState as ResponseBodyState;
  194. Stream inputStream = responseBodyState.inputStream;
  195. try
  196. {
  197. int recvLen = inputStream.EndRead(ar);
  198. responseBodyState.completed += recvLen;
  199. if (recvLen > 0)
  200. {
  201. if (isDownload)
  202. {
  203. fileStream.Write(responseBodyState.buffer, 0, recvLen);
  204. if (progressCallback != null)
  205. {
  206. progressCallback(responseBodyState.completed, contentLength);
  207. }
  208. }
  209. else
  210. {
  211. memoryStream.Write(responseBodyState.buffer, 0, recvLen);
  212. }
  213. inputStream.BeginRead(responseBodyState.buffer, 0, responseBodyState.buffer.Length, AsyncStreamCallback, responseBodyState);
  214. }
  215. else if (recvLen == 0)
  216. {
  217. if (isDownload)
  218. {
  219. fileStream.Flush();
  220. }
  221. else
  222. {
  223. if ("application/xml".Equals(contentType, StringComparison.OrdinalIgnoreCase) &&
  224. memoryStream.Length > 0 && memoryStream.Length < 10 * 1000)
  225. {
  226. memoryStream.Seek(0, SeekOrigin.Begin);
  227. rawContentBodyString = System.Text.Encoding.UTF8.GetString(memoryStream.ToArray());
  228. }
  229. memoryStream.Seek(0, SeekOrigin.Begin);
  230. parseStream(memoryStream, contentType, responseBodyState.completed);
  231. }
  232. if (fileStream != null)
  233. {
  234. fileStream.Close();
  235. fileStream.Dispose();
  236. }
  237. if (memoryStream != null)
  238. {
  239. memoryStream.Close();
  240. memoryStream.Dispose();
  241. }
  242. responseBodyState.endResponseBody(true, null);
  243. responseBodyState.Clear();
  244. }
  245. }
  246. catch (Exception ex)
  247. {
  248. if (fileStream != null)
  249. {
  250. fileStream.Close();
  251. fileStream.Dispose();
  252. }
  253. if (memoryStream != null)
  254. {
  255. memoryStream.Close();
  256. memoryStream.Dispose();
  257. }
  258. responseBodyState.endResponseBody(false, ex);
  259. responseBodyState.Clear();
  260. QLog.Error("ResponseBody", ex.Message, ex);
  261. }
  262. }
  263. }
  264. public delegate void EndResponseBody(bool isSuccess, Exception ex);
  265. public class ResponseBodyState
  266. {
  267. public Stream inputStream;
  268. public byte[] buffer;
  269. public long completed;
  270. public EndResponseBody endResponseBody;
  271. public void Clear()
  272. {
  273. if (inputStream != null)
  274. {
  275. inputStream.Close();
  276. }
  277. if (buffer != null)
  278. {
  279. buffer = null;
  280. }
  281. }
  282. }
  283. }