CefResourceHandler.cs 9.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234
  1. namespace Xilium.CefGlue
  2. {
  3. using System;
  4. using System.Collections.Generic;
  5. using System.Diagnostics;
  6. using System.Runtime.InteropServices;
  7. using Xilium.CefGlue.Interop;
  8. using System.Threading;
  9. using System.IO;
  10. /// <summary>
  11. /// Class used to implement a custom request handler interface. The methods of
  12. /// this class will be called on the IO thread unless otherwise indicated.
  13. /// </summary>
  14. public abstract unsafe partial class CefResourceHandler
  15. {
  16. /// <summary>
  17. /// set to 1 for keeping, otherwise 0
  18. /// </summary>
  19. private int _keepObject;
  20. public void KeepObject()
  21. {
  22. if (Interlocked.CompareExchange(ref _keepObject, 1, 0) == 0)
  23. {
  24. add_ref(_self);
  25. }
  26. }
  27. public void ReleaseObject()
  28. {
  29. if (Interlocked.CompareExchange(ref _keepObject, 0, 1) == 1)
  30. {
  31. release(_self);
  32. }
  33. }
  34. private int open(cef_resource_handler_t* self, cef_request_t* request, int* handle_request, cef_callback_t* callback)
  35. {
  36. CheckSelf(self);
  37. var m_request = CefRequest.FromNative(request);
  38. var m_callback = CefCallback.FromNative(callback);
  39. var m_result = Open(m_request, out var m_handleRequest, m_callback);
  40. *handle_request = m_handleRequest ? 1 : 0;
  41. return m_result ? 1 : 0;
  42. }
  43. /// <summary>
  44. /// Open the response stream. To handle the request immediately set
  45. /// |handle_request| to true and return true. To decide at a later time set
  46. /// |handle_request| to false, return true, and execute |callback| to continue
  47. /// or cancel the request. To cancel the request immediately set
  48. /// |handle_request| to true and return false. This method will be called in
  49. /// sequence but not from a dedicated thread. For backwards compatibility set
  50. /// |handle_request| to false and return false and the ProcessRequest method
  51. /// will be called.
  52. /// </summary>
  53. protected abstract bool Open(CefRequest request, out bool handleRequest, CefCallback callback);
  54. private int process_request(cef_resource_handler_t* self, cef_request_t* request, cef_callback_t* callback)
  55. {
  56. CheckSelf(self);
  57. var m_request = CefRequest.FromNative(request);
  58. var m_callback = CefCallback.FromNative(callback);
  59. #pragma warning disable CS0618 // Type or member is obsolete
  60. var result = ProcessRequest(m_request, m_callback);
  61. #pragma warning restore CS0618 // Type or member is obsolete
  62. return result ? 1 : 0;
  63. }
  64. /// <summary>
  65. /// Begin processing the request. To handle the request return true and call
  66. /// CefCallback::Continue() once the response header information is available
  67. /// (CefCallback::Continue() can also be called from inside this method if
  68. /// header information is available immediately). To cancel the request return
  69. /// false.
  70. /// WARNING: This method is deprecated. Use Open instead.
  71. /// </summary>
  72. [Obsolete("This method is deprecated. Use Open instead.")]
  73. protected virtual bool ProcessRequest(CefRequest request, CefCallback callback)
  74. {
  75. request.Dispose();
  76. callback.Dispose();
  77. return false;
  78. }
  79. private void get_response_headers(cef_resource_handler_t* self, cef_response_t* response, long* response_length, cef_string_t* redirectUrl)
  80. {
  81. CheckSelf(self);
  82. var m_response = CefResponse.FromNative(response);
  83. long m_responseLength;
  84. string m_redirectUrl;
  85. GetResponseHeaders(m_response, out m_responseLength, out m_redirectUrl);
  86. *response_length = m_responseLength;
  87. if (!string.IsNullOrEmpty(m_redirectUrl))
  88. {
  89. cef_string_t.Copy(m_redirectUrl, redirectUrl);
  90. }
  91. }
  92. /// <summary>
  93. /// Retrieve response header information. If the response length is not known
  94. /// set |response_length| to -1 and ReadResponse() will be called until it
  95. /// returns false. If the response length is known set |response_length|
  96. /// to a positive value and ReadResponse() will be called until it returns
  97. /// false or the specified number of bytes have been read. Use the |response|
  98. /// object to set the mime type, http status code and other optional header
  99. /// values. To redirect the request to a new URL set |redirectUrl| to the new
  100. /// URL. |redirectUrl| can be either a relative or fully qualified URL.
  101. /// It is also possible to set |response| to a redirect http status code
  102. /// and pass the new URL via a Location header. Likewise with |redirectUrl| it
  103. /// is valid to set a relative or fully qualified URL as the Location header
  104. /// value. If an error occured while setting up the request you can call
  105. /// SetError() on |response| to indicate the error condition.
  106. /// </summary>
  107. protected abstract void GetResponseHeaders(CefResponse response, out long responseLength, out string redirectUrl);
  108. private int skip(cef_resource_handler_t* self, long bytes_to_skip, long* bytes_skipped, cef_resource_skip_callback_t* callback)
  109. {
  110. CheckSelf(self);
  111. var m_callback = CefResourceSkipCallback.FromNative(callback);
  112. var m_result = Skip(bytes_to_skip, out var m_bytesSkipped, m_callback);
  113. *bytes_skipped = m_bytesSkipped;
  114. return m_result ? 1 : 0;
  115. }
  116. /// <summary>
  117. /// Skip response data when requested by a Range header. Skip over and discard
  118. /// |bytes_to_skip| bytes of response data. If data is available immediately
  119. /// set |bytes_skipped| to the number of bytes skipped and return true. To
  120. /// read the data at a later time set |bytes_skipped| to 0, return true and
  121. /// execute |callback| when the data is available. To indicate failure set
  122. /// |bytes_skipped| to &lt; 0 (e.g. -2 for ERR_FAILED) and return false. This
  123. /// method will be called in sequence but not from a dedicated thread.
  124. /// </summary>
  125. protected abstract bool Skip(long bytesToSkip, out long bytesSkipped, CefResourceSkipCallback callback);
  126. private int read(cef_resource_handler_t* self, void* data_out, int bytes_to_read, int* bytes_read, cef_resource_read_callback_t* callback)
  127. {
  128. CheckSelf(self);
  129. var m_callback = CefResourceReadCallback.FromNative(callback);
  130. using (var m_stream = new UnmanagedMemoryStream((byte*)data_out, bytes_to_read, bytes_to_read, FileAccess.Write))
  131. {
  132. var m_result = Read(m_stream, bytes_to_read, out var m_bytesRead, m_callback);
  133. *bytes_read = m_bytesRead;
  134. return m_result ? 1 : 0;
  135. }
  136. }
  137. /// <summary>
  138. /// Read response data. If data is available immediately copy up to
  139. /// |bytes_to_read| bytes into |response|, set |bytes_read| to the number of
  140. /// bytes copied, and return true. To read the data at a later time keep a
  141. /// pointer to |data_out|, set |bytes_read| to 0, return true and execute
  142. /// |callback| when the data is available (|response| will remain valid until
  143. /// the callback is executed). To indicate response completion set |bytes_read|
  144. /// to 0 and return false. To indicate failure set |bytes_read| to &lt; 0 (e.g. -2
  145. /// for ERR_FAILED) and return false. This method will be called in sequence
  146. /// but not from a dedicated thread. For backwards compatibility set
  147. /// |bytes_read| to -1 and return false and the ReadResponse method will be
  148. /// called.
  149. /// </summary>
  150. protected abstract bool Read(Stream response, int bytesToRead, out int bytesRead, CefResourceReadCallback callback);
  151. private int read_response(cef_resource_handler_t* self, void* data_out, int bytes_to_read, int* bytes_read, cef_callback_t* callback)
  152. {
  153. CheckSelf(self);
  154. var m_callback = CefCallback.FromNative(callback);
  155. using (var m_stream = new UnmanagedMemoryStream((byte*)data_out, bytes_to_read, bytes_to_read, FileAccess.Write))
  156. {
  157. int m_bytesRead;
  158. #pragma warning disable CS0618 // Type or member is obsolete
  159. var result = ReadResponse(m_stream, bytes_to_read, out m_bytesRead, m_callback);
  160. #pragma warning restore CS0618 // Type or member is obsolete
  161. *bytes_read = m_bytesRead;
  162. return result ? 1 : 0;
  163. }
  164. }
  165. /// <summary>
  166. /// Read response data. If data is available immediately copy up to
  167. /// |bytes_to_read| bytes into |data_out|, set |bytes_read| to the number of
  168. /// bytes copied, and return true. To read the data at a later time set
  169. /// |bytes_read| to 0, return true and call CefCallback::Continue() when the
  170. /// data is available. To indicate response completion return false.
  171. /// WARNING: This method is deprecated. Use Skip and Read instead.
  172. /// </summary>
  173. [Obsolete("This method is deprecated. Use Skip and Read instead.")]
  174. protected virtual bool ReadResponse(Stream response, int bytesToRead, out int bytesRead, CefCallback callback)
  175. {
  176. bytesRead = 0;
  177. return false;
  178. }
  179. private void cancel(cef_resource_handler_t* self)
  180. {
  181. CheckSelf(self);
  182. Cancel();
  183. }
  184. /// <summary>
  185. /// Request processing has been canceled.
  186. /// </summary>
  187. protected abstract void Cancel();
  188. }
  189. }