Mirror of Svelto.ECS because we're a fan of it
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

176 lines
5.9KB

  1. using System;
  2. using System.Collections.Generic;
  3. using System.Net;
  4. using UnityEngine;
  5. using System.Security.Cryptography.X509Certificates;
  6. using System.Net.Security;
  7. using Svelto.Tasks;
  8. using Svelto.Tasks.Enumerators;
  9. using UnityEngine.Networking;
  10. namespace Svelto.Services
  11. {
  12. public enum Method
  13. {
  14. GET,
  15. POST
  16. }
  17. public enum Result
  18. {
  19. Success,
  20. ServerHandledError,
  21. ServerException,
  22. ClientFailure,
  23. }
  24. public sealed class StandardWebRequest
  25. {
  26. static StandardWebRequest()
  27. {
  28. ServicePointManager.ServerCertificateValidationCallback = CannotVerifyMessageCertificate;
  29. ServicePointManager.DefaultConnectionLimit = 64;
  30. }
  31. public Result result { get; private set; }
  32. public int maxAttempts = 3;
  33. public int waitOnRetrySeconds = 1;
  34. public int timeoutSeconds = 10;
  35. public Method method = Method.POST;
  36. public Func<HttpStatusCode, bool> processStatusCodes = code => false;
  37. public IResponseHandler responseHandler;
  38. public string URL;
  39. public IEnumerator<TaskContract> Execute(byte[] bodyRaw)
  40. {
  41. int attemptNumber = 0;
  42. do
  43. {
  44. using (UnityWebRequest request = new UnityWebRequest())
  45. {
  46. switch (method)
  47. {
  48. case Method.GET:
  49. request.method = UnityWebRequest.kHttpVerbGET;
  50. break;
  51. case Method.POST:
  52. request.method = UnityWebRequest.kHttpVerbPOST;
  53. break;
  54. default:
  55. request.method = UnityWebRequest.kHttpVerbPOST;
  56. break;
  57. }
  58. request.url = URL;
  59. request.uploadHandler = new UploadHandlerRaw(bodyRaw);
  60. request.downloadHandler = new UnityDownloadHandler(responseHandler);
  61. request.SetRequestHeader("Content-Type", "application/json");
  62. request.timeout = timeoutSeconds;
  63. AsyncOperation op = request.SendWebRequest();
  64. while (op.isDone == false)
  65. {
  66. yield return Yield.It;
  67. }
  68. if (request.isNetworkError == false)
  69. {
  70. if (ProcessResponse(request) == true)
  71. {
  72. result = Result.Success;
  73. Svelto.Console.LogDebug("web request completed");
  74. yield break;
  75. }
  76. else
  77. {
  78. Svelto.Console.LogDebug("web request completed with failure ", URL);
  79. try
  80. {
  81. responseHandler?.CompleteContent();
  82. result = Result.ServerHandledError;
  83. }
  84. catch
  85. {
  86. result = Result.ServerException;
  87. }
  88. yield break; //no retry on server error!
  89. }
  90. }
  91. else
  92. if (++attemptNumber < maxAttempts)
  93. {
  94. var wait = new ReusableWaitForSecondsEnumerator(waitOnRetrySeconds);
  95. while (wait.MoveNext() == true) yield return Yield.It;
  96. Svelto.Console.LogDebug("web request retry");
  97. continue; //retry on client error
  98. }
  99. else
  100. {
  101. result = Result.ClientFailure;
  102. yield break;
  103. }
  104. }
  105. }
  106. while (true);
  107. }
  108. bool ProcessResponse(UnityWebRequest request)
  109. {
  110. HttpStatusCode statusCode = (HttpStatusCode) request.responseCode;
  111. if (statusCode != HttpStatusCode.OK)
  112. if (processStatusCodes(statusCode) == false)
  113. return false;
  114. return true;
  115. }
  116. // BOC:: After turning on SSL on the gameserver we started getting certificate problems.
  117. // Found this solution on Stack Overflow with Mike R
  118. // (https://stackoverflow.com/questions/4926676/mono-https-webrequest-fails-with-the-authentication-or-decryption-has-failed)
  119. static bool CannotVerifyMessageCertificate(System.Object sender, X509Certificate certificate, X509Chain chain,
  120. SslPolicyErrors sslPolicyErrors)
  121. {
  122. bool isOk = true;
  123. // If there are errors in the certificate chain,
  124. // look at each error to determine the cause.
  125. if (sslPolicyErrors != SslPolicyErrors.None)
  126. {
  127. for (int i = 0; i < chain.ChainStatus.Length; i++)
  128. {
  129. if (chain.ChainStatus[i].Status == X509ChainStatusFlags.RevocationStatusUnknown)
  130. continue;
  131. chain.ChainPolicy.RevocationFlag = X509RevocationFlag.EntireChain;
  132. chain.ChainPolicy.RevocationMode = X509RevocationMode.Online;
  133. chain.ChainPolicy.UrlRetrievalTimeout = new TimeSpan(0, 1, 0);
  134. chain.ChainPolicy.VerificationFlags = X509VerificationFlags.AllFlags;
  135. bool chainIsValid = chain.Build((X509Certificate2) certificate);
  136. if (!chainIsValid)
  137. {
  138. isOk = false;
  139. break;
  140. }
  141. }
  142. }
  143. return isOk;
  144. }
  145. }
  146. }