{"record":{"id":"6642bae0024e21c9","repo":"CarGuo/GSYVideoPlayer","slug":"error-reading-data-from-sourceinfo-url","errorCode":null,"errorMessage":"Error reading data from ${sourceInfo.url}","messagePattern":"Error reading data from (.+?)","errorType":"exception","errorClass":"ProxyCacheException","httpStatus":null,"severity":"error","filePath":"gsyVideoPlayer-proxy_cache/src/main/java/com/danikula/videocache/HttpUrlSource.java","lineNumber":140,"sourceCode":"            } catch (ArrayIndexOutOfBoundsException e) {\n                HttpProxyCacheDebuger.printfError(\"Error closing connection correctly. Should happen only on Android L. \" +\n                    \"If anybody know how to fix it, please visit https://github.com/danikula/AndroidVideoCache/issues/88. \" +\n                    \"Until good solution is not know, just ignore this issue :(\", e);\n            }\n        }\n    }\n\n    @Override\n    public int read(byte[] buffer) throws ProxyCacheException {\n        if (inputStream == null) {\n            throw new ProxyCacheException(\"Error reading data from \" + sourceInfo.url + \": connection is absent!\");\n        }\n        try {\n            return inputStream.read(buffer, 0, buffer.length);\n        } catch (InterruptedIOException e) {\n            throw new InterruptedProxyCacheException(\"Reading source \" + sourceInfo.url + \" is interrupted\", e);\n        } catch (IOException e) {\n            throw new ProxyCacheException(\"Error reading data from \" + sourceInfo.url, e);\n        }\n    }\n\n    private void fetchContentInfo() throws ProxyCacheException {\n        HttpURLConnection urlConnection = null;\n        InputStream inputStream = null;\n        try {\n            urlConnection = openConnection(0, 10000);\n            long length = getContentLength(urlConnection);\n            String mime = urlConnection.getContentType();\n            inputStream = urlConnection.getInputStream();\n            this.sourceInfo = new SourceInfo(sourceInfo.url, length, mime);\n            this.sourceInfoStorage.put(sourceInfo.url, sourceInfo);\n        } catch (IOException e) {\n            HttpProxyCacheDebuger.printfError(\"Error fetching info from \" + sourceInfo.url, e);\n        } finally {\n            ProxyCacheUtils.close(inputStream);\n            if (urlConnection != null) {","sourceCodeStart":122,"sourceCodeEnd":158,"githubUrl":"https://github.com/CarGuo/GSYVideoPlayer/blob/e5d74d3aa9d7fb1393a879e33ee380f8f41354f1/gsyVideoPlayer-proxy_cache/src/main/java/com/danikula/videocache/HttpUrlSource.java#L122-L158","documentation":"HttpUrlSource.openConnection implements manual redirect following: on 301/302/303 it takes the Location header and re-opens, counting hops. If redirectCount exceeds MAX_REDIRECTS (5), it throws ProxyCacheException('Too many redirects: N'). This guards against redirect loops (A->B->A) and auth walls that keep bouncing the proxy.","triggerScenarios":"A redirect cycle on the origin (common with tokens: url redirects to a login/refresh page that redirects back); a CDN chain longer than 5 hops; a Location header pointing back to the same url; captive portals that redirect every request to a sign-in page.","commonSituations":"Expired auth tokens causing bounce between content and auth endpoints; hotel/airport captive portals while caching; misconfigured server redirect rules; deep multi-CDN chains (rare but real with geo-routing).","solutions":["Verify the URL in a browser/curl -L and fix the server-side redirect loop","Re-acquire a fresh signed URL before playback instead of reusing a stale one","Whitelist the captive-portal check: detect portal redirect and prompt the user to sign in","If a legitimate chain exceeds 5, fork and raise MAX_REDIRECTS in a custom HttpUrlSource"],"exampleFix":"# before\ncurl -I \"https://cdn.example.com/v.mp4?token=stale\"\n# HTTP 302 -> https://auth.example.com/login\n# HTTP 302 -> https://cdn.example.com/v.mp4?token=stale  (loop)\n\n# after - fetch fresh url at play time\nString freshUrl = api.getPlaybackUrl(videoId);\nplayer.setUp(proxyCacheServer.getProxyUrl(freshUrl), true, headers);","handlingStrategy":"validation","validationCode":"// detect a redirect loop before playing\nString loc = url; int hops = 0;\nwhile (hops++ < 5) {\n    HttpURLConnection c = (HttpURLConnection) new URL(loc).openConnection();\n    int code = c.getResponseCode();\n    if (code/100 == 3) loc = c.getHeaderField(\"Location\"); else break;\n}\nif (hops >= 5) throw new IllegalArgumentException(\"redirect loop on \" + url);","typeGuard":null,"tryCatchPattern":"catch (ProxyCacheException e) {\n    if (String.valueOf(e.getMessage()).contains(\"Too many redirects\")) {\n        url = api.getFreshPlaybackUrl(videoId); // fresh signed url, then replay\n    } else throw e;\n}","preventionTips":["Fetch playback urls at play time when they are signed/authenticated","Detect captive portals before streaming","Fix server-side redirect loops (A->B->A)"],"tags":["http","redirects","signed-url","captive-portal","proxy-cache"],"backgroundTag":null,"analyzedSha":"e5d74d3aa9d7fb1393a879e33ee380f8f41354f1","analyzedAt":"2026-08-14T11:56:11.997Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}