using System; using System.Collections.Generic; using System.Net; using UnityEngine; using System.Security.Cryptography.X509Certificates; using System.Net.Security; using Svelto.Tasks; using Svelto.Tasks.Enumerators; using UnityEngine.Networking; namespace Svelto.Services { public enum Method { GET, POST } public enum Result { Success, ServerHandledError, ServerException, ClientFailure, } public sealed class StandardWebRequest { static StandardWebRequest() { ServicePointManager.ServerCertificateValidationCallback = CannotVerifyMessageCertificate; ServicePointManager.DefaultConnectionLimit = 64; } public Result result { get; private set; } public int maxAttempts = 3; public int waitOnRetrySeconds = 1; public int timeoutSeconds = 10; public Method method = Method.POST; public Func processStatusCodes = code => false; public IResponseHandler responseHandler; public string URL; public IEnumerator Execute(byte[] bodyRaw) { int attemptNumber = 0; do { using (UnityWebRequest request = new UnityWebRequest()) { switch (method) { case Method.GET: request.method = UnityWebRequest.kHttpVerbGET; break; case Method.POST: request.method = UnityWebRequest.kHttpVerbPOST; break; default: request.method = UnityWebRequest.kHttpVerbPOST; break; } request.url = URL; request.uploadHandler = new UploadHandlerRaw(bodyRaw); request.downloadHandler = new UnityDownloadHandler(responseHandler); request.SetRequestHeader("Content-Type", "application/json"); request.timeout = timeoutSeconds; AsyncOperation op = request.SendWebRequest(); while (op.isDone == false) { yield return Yield.It; } if (request.isNetworkError == false) { if (ProcessResponse(request) == true) { result = Result.Success; Svelto.Console.LogDebug("web request completed"); yield break; } else { Svelto.Console.LogDebug("web request completed with failure ", URL); try { responseHandler?.CompleteContent(); result = Result.ServerHandledError; } catch { result = Result.ServerException; } yield break; //no retry on server error! } } else if (++attemptNumber < maxAttempts) { var wait = new ReusableWaitForSecondsEnumerator(waitOnRetrySeconds); while (wait.MoveNext() == true) yield return Yield.It; Svelto.Console.LogDebug("web request retry"); continue; //retry on client error } else { result = Result.ClientFailure; yield break; } } } while (true); } bool ProcessResponse(UnityWebRequest request) { HttpStatusCode statusCode = (HttpStatusCode) request.responseCode; if (statusCode != HttpStatusCode.OK) if (processStatusCodes(statusCode) == false) return false; return true; } // BOC:: After turning on SSL on the gameserver we started getting certificate problems. // Found this solution on Stack Overflow with Mike R // (https://stackoverflow.com/questions/4926676/mono-https-webrequest-fails-with-the-authentication-or-decryption-has-failed) static bool CannotVerifyMessageCertificate(System.Object sender, X509Certificate certificate, X509Chain chain, SslPolicyErrors sslPolicyErrors) { bool isOk = true; // If there are errors in the certificate chain, // look at each error to determine the cause. if (sslPolicyErrors != SslPolicyErrors.None) { for (int i = 0; i < chain.ChainStatus.Length; i++) { if (chain.ChainStatus[i].Status == X509ChainStatusFlags.RevocationStatusUnknown) continue; chain.ChainPolicy.RevocationFlag = X509RevocationFlag.EntireChain; chain.ChainPolicy.RevocationMode = X509RevocationMode.Online; chain.ChainPolicy.UrlRetrievalTimeout = new TimeSpan(0, 1, 0); chain.ChainPolicy.VerificationFlags = X509VerificationFlags.AllFlags; bool chainIsValid = chain.Build((X509Certificate2) certificate); if (!chainIsValid) { isOk = false; break; } } } return isOk; } } }