/// <summary> /// Co-routine that services one PendingRequest. This method must be called with StartCoroutine. /// </summary> /// <param name="request">The request to service.</param> private IEnumerator HandleWebRequest(PendingRequest request, BufferHolder bufferHolder) { // NOTE: This method runs on the main thread, but never blocks -- the blocking part of the work is // done by yielding the UnityWebRequest, which releases the main thread for other tasks while we // are waiting for the web request to complete (by the miracle of coroutines). // Let the caller create the UnityWebRequest, configuring it as they want. The caller can set the URL, // method, headers, anything they want. The only thing they can't do is call Send(), as we're in charge // of doing that. UnityWebRequest webRequest = request.creationCallback(); PtDebug.LogVerboseFormat("Web request: {0} {1}", webRequest.method, webRequest.url); bool cacheAllowed = cache != null && webRequest.method == "GET" && request.maxAgeMillis != CACHE_NONE; // Check the cache (if it's a GET request and cache is enabled). if (cacheAllowed) { bool cacheHit = false; byte[] cacheData = null; bool cacheReadDone = false; cache.RequestRead(webRequest.url, request.maxAgeMillis, (bool success, byte[] data) => { cacheHit = success; cacheData = data; cacheReadDone = true; }); while (!cacheReadDone) { yield return(null); } if (cacheHit) { PtDebug.LogVerboseFormat("Web request CACHE HIT: {0}, response: {1} bytes", webRequest.url, cacheData.Length); request.completionCallback(PolyStatus.Success(), /* responseCode */ 200, cacheData); // Return the buffer to the pool for reuse. CleanUpAfterWebRequest(bufferHolder); yield break; } else { PtDebug.LogVerboseFormat("Web request CACHE MISS: {0}.", webRequest.url); } } DownloadHandlerBuffer handler = new DownloadHandlerBuffer(); webRequest.downloadHandler = handler; // We need to asset that we actually succeeded in setting the download handler, because this can fail // if, for example, the creation callback mistakenly called Send(). PolyUtils.AssertTrue(webRequest.downloadHandler == handler, "Couldn't set download handler. It's either disposed of, or the creation callback mistakenly called Send()."); // Start the web request. This will suspend this coroutine until the request is done. PtDebug.LogVerboseFormat("Sending web request: {0}", webRequest.url); yield return(UnityCompat.SendWebRequest(webRequest)); // Request is finished. Call user-supplied callback. PtDebug.LogVerboseFormat("Web request finished: {0}, HTTP response code {1}, response: {2}", webRequest.url, webRequest.responseCode, webRequest.downloadHandler.text); PolyStatus status = UnityCompat.IsNetworkError(webRequest) ? PolyStatus.Error(webRequest.error) : PolyStatus.Success(); request.completionCallback(status, (int)webRequest.responseCode, webRequest.downloadHandler.data); // Cache the result, if applicable. if (!UnityCompat.IsNetworkError(webRequest) && cacheAllowed) { byte[] data = webRequest.downloadHandler.data; if (data != null && data.Length > 0) { byte[] copy = new byte[data.Length]; Buffer.BlockCopy(data, 0, copy, 0, data.Length); cache.RequestWrite(webRequest.url, copy); } } // Clean up. webRequest.Dispose(); CleanUpAfterWebRequest(bufferHolder); }