{"record":{"id":"5145820714522856","repo":"tonhowtf/omniget","slug":"invalid-p2p-url-514582","errorCode":null,"errorMessage":"Invalid P2P URL","messagePattern":"Invalid P2P URL","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src-tauri/omniget-core/src/platforms/p2p.rs","lineNumber":115,"sourceCode":"            media_type: MediaType::Video,\n            file_size_bytes: None,\n        })\n    }\n\n    async fn download(\n        &self,\n        info: &MediaInfo,\n        opts: &DownloadOptions,\n        progress: mpsc::Sender<ProgressUpdate>,\n    ) -> anyhow::Result<DownloadResult> {\n        let url = match info.available_qualities.first() {\n            Some(q) => &q.url,\n            None => anyhow::bail!(\"No URL found in MediaInfo\"),\n        };\n\n        let code = url\n            .strip_prefix(\"p2p:\")\n            .ok_or_else(|| anyhow!(\"Invalid P2P URL\"))?;\n\n        let _ = progress.send(ProgressUpdate::percent(-2.0)).await;\n\n        tracing::info!(\"[p2p] connecting to relay for code: {}\", code);\n\n        let stream = connect_relay().await?;\n        let (read_half, mut write_half) = tokio::io::split(stream);\n        let mut reader = BufReader::new(read_half);\n\n        write_half\n            .write_all(format!(\"RECV {}\\n\", code).as_bytes())\n            .await?;\n        write_half.flush().await?;\n\n        let response = read_line(&mut reader).await?;\n        check_relay_error(&response)?;\n        if response != \"READY\" {\n            anyhow::bail!(\"Unexpected relay response: {}\", response);","sourceCodeStart":97,"sourceCodeEnd":133,"githubUrl":"https://github.com/tonhowtf/omniget/blob/8600b91f4246848bac346874daa9e61c1fc5677a/src-tauri/omniget-core/src/platforms/p2p.rs#L97-L133","documentation":"download() validates that the MediaInfo it received carries a URL with the 'p2p:' scheme. If the stored/download URL lacks the prefix, it cannot extract the share code to open a relay connection. It is a defensive re-check of data built earlier by get_media_info.","triggerScenarios":"Calling download with a MediaInfo whose url field is not 'p2p:<code>' — e.g. MediaInfo constructed manually, or a URL from a different platform leaked into the P2P downloader.","commonSituations":"Hand-built MediaInfo objects in tests or integrations; platform routing bugs assigning non-P2P media to the P2P fetcher; URLs mutated/rewritten between get_media_info and download.","solutions":["Ensure the MediaInfo comes from p2p get_media_info so the url is 'p2p:<code>'","Check the platform-dispatch logic so P2P downloads only handle p2p: URLs","Validate the URL scheme before calling download"],"exampleFix":"// before\nplatform.download(opts).await?;\n// after\nif !opts.url.starts_with(\"p2p:\") {\n    anyhow::bail!(\"expected p2p: URL, got {}\", opts.url);\n}\nplatform.download(opts).await?;","handlingStrategy":"validation","validationCode":"fn is_p2p_media(info: &MediaInfo) -> bool {\n    info.url.as_deref().map(|u| u.starts_with(\"p2p:\")).unwrap_or(false)\n}","typeGuard":null,"tryCatchPattern":"if !is_p2p_media(&info) {\n    return Err(anyhow!(\"MediaInfo is not a P2P transfer (missing p2p: URL)\"));\n}\nplatform.download(opts).await?;","preventionTips":["Only feed MediaInfo produced by the same platform's get_media_info into download","Assert the p2p: scheme in tests that build MediaInfo fixtures","Type-tag P2P media (e.g. enum MediaSource::P2p{code}) instead of free-form URLs"],"tags":["url","p2p","input-validation","state"],"backgroundTag":"invalid-url-format","analyzedSha":"8600b91f4246848bac346874daa9e61c1fc5677a","analyzedAt":"2026-09-12T14:29:19.317Z","contentChangedAt":"2026-09-12T14:29:19.317Z","schemaVersion":2},"datasetVersion":"2026-09-16T04:17:20.429Z"}