fix(videoplayback): Use HEAD requests to get the location of the videoplayback URL before doing a POST
All checks were successful
CI / build (push) Successful in 1m1s
All checks were successful
CI / build (push) Successful in 1m1s
"RFC 1945 and RFC 2068 specify that the client is not allowed to change
the method on the redirected request. However, most existing user agent
implementations treat 302 as if it were a 303 response, performing a GET
on the Location field-value regardless of the original request method.
The status codes 303 and 307 have been added for servers that wish to
make unambiguously clear which kind of reaction is expected of the
client."
Before doing this, POST requests that got a 302 status code, get
converted automatically to GET requests by the standard, which should
not happen. That is why Invidious does 5 HEAD requests to get the
Location header and send a correct URL on the POST request (NOTE:
INVIDIOUS UPSTREAMS STILL USES GET REQUESTS TO GET THE VIDEO FROM
YOUTUBE, THAT IS SUBJECT TO CHANGE with https://github.com/iv-org/invidious/issues/5034:
164d764d55/src/invidious/routes/video_playback.cr (L48-L78)
Due to this the redirects, the Host header can also change, so if the
stream is open for a long time and it gets redirected to another URL,
the Host header used the old Host header instead of the new one returned
by the Location header on the HEAD request to googlevideo.com, making
the request fail.
I hope this shit works tho
This commit is contained in:
parent
197a807b90
commit
319991c7b8
2 changed files with 59 additions and 38 deletions
90
httppaths.go
90
httppaths.go
|
@ -63,25 +63,25 @@ func videoplayback(w http.ResponseWriter, req *http.Request) {
|
|||
host := q.Get("host")
|
||||
q.Del("host")
|
||||
|
||||
if len(host) <= 0 {
|
||||
// Fallback to use mvi and mn to build a host
|
||||
mvi := q.Get("mvi")
|
||||
mn := strings.Split(q.Get("mn"), ",")
|
||||
// if len(host) <= 0 {
|
||||
// // Fallback to use mvi and mn to build a host
|
||||
// mvi := q.Get("mvi")
|
||||
// mn := strings.Split(q.Get("mn"), ",")
|
||||
|
||||
if len(mvi) <= 0 {
|
||||
w.WriteHeader(400)
|
||||
io.WriteString(w, "'mvi' query string undefined")
|
||||
return
|
||||
}
|
||||
// if len(mvi) <= 0 {
|
||||
// w.WriteHeader(400)
|
||||
// io.WriteString(w, "'mvi' query string undefined")
|
||||
// return
|
||||
// }
|
||||
|
||||
if len(mn) <= 0 {
|
||||
w.WriteHeader(400)
|
||||
io.WriteString(w, "'mn' query string undefined")
|
||||
return
|
||||
}
|
||||
// if len(mn) <= 0 {
|
||||
// w.WriteHeader(400)
|
||||
// io.WriteString(w, "'mn' query string undefined")
|
||||
// return
|
||||
// }
|
||||
|
||||
host = "rr" + mvi + "---" + mn[0] + ".googlevideo.com"
|
||||
}
|
||||
// host = "rr" + mvi + "---" + mn[0] + ".googlevideo.com"
|
||||
// }
|
||||
|
||||
parts := strings.Split(strings.ToLower(host), ".")
|
||||
if len(parts) < 2 {
|
||||
|
@ -124,45 +124,63 @@ func videoplayback(w http.ResponseWriter, req *http.Request) {
|
|||
// https://github.com/FreeTubeApp/FreeTube/blob/5a4cd981cdf2c2a20ab68b001746658fd0c6484e/src/renderer/components/ft-shaka-video-player/ft-shaka-video-player.js#L1097
|
||||
body := []byte{0x78, 0} // protobuf body
|
||||
|
||||
request, err := http.NewRequest("POST", proxyURL.String(), bytes.NewReader(body))
|
||||
postRequest, err := http.NewRequest("POST", proxyURL.String(), bytes.NewReader(body))
|
||||
if err != nil {
|
||||
log.Panic(err)
|
||||
log.Panic("Failed to create postRequest:", err)
|
||||
}
|
||||
copyHeaders(req.Header, request.Header, false)
|
||||
headRequest, err := http.NewRequest("HEAD", proxyURL.String(), nil)
|
||||
if err != nil {
|
||||
log.Panic("Failed to create headRequest:", err)
|
||||
}
|
||||
copyHeaders(req.Header, postRequest.Header, false)
|
||||
copyHeaders(req.Header, headRequest.Header, false)
|
||||
|
||||
switch c {
|
||||
case "ANDROID":
|
||||
request.Header.Set("User-Agent", "com.google.android.youtube/1537338816 (Linux; U; Android 13; en_US; ; Build/TQ2A.230505.002; Cronet/113.0.5672.24)")
|
||||
postRequest.Header.Set("User-Agent", "com.google.android.youtube/1537338816 (Linux; U; Android 13; en_US; ; Build/TQ2A.230505.002; Cronet/113.0.5672.24)")
|
||||
headRequest.Header.Set("User-Agent", "com.google.android.youtube/1537338816 (Linux; U; Android 13; en_US; ; Build/TQ2A.230505.002; Cronet/113.0.5672.24)")
|
||||
case "IOS":
|
||||
request.Header.Set("User-Agent", "com.google.ios.youtube/19.32.8 (iPhone14,5; U; CPU iOS 17_6 like Mac OS X;)")
|
||||
postRequest.Header.Set("User-Agent", "com.google.ios.youtube/19.32.8 (iPhone14,5; U; CPU iOS 17_6 like Mac OS X;)")
|
||||
headRequest.Header.Set("User-Agent", "com.google.ios.youtube/19.32.8 (iPhone14,5; U; CPU iOS 17_6 like Mac OS X;)")
|
||||
case "WEB":
|
||||
request.Header.Set("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/128.0.0.0 Safari/537.36")
|
||||
postRequest.Header.Set("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/128.0.0.0 Safari/537.36")
|
||||
headRequest.Header.Set("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/128.0.0.0 Safari/537.36")
|
||||
default:
|
||||
request.Header.Set("User-Agent", default_ua)
|
||||
postRequest.Header.Set("User-Agent", default_ua)
|
||||
headRequest.Header.Set("User-Agent", default_ua)
|
||||
}
|
||||
|
||||
request.Header.Add("Origin", "https://www.youtube.com")
|
||||
request.Header.Add("Referer", "https://www.youtube.com/")
|
||||
postRequest.Header.Add("Origin", "https://www.youtube.com")
|
||||
headRequest.Header.Add("Origin", "https://www.youtube.com")
|
||||
postRequest.Header.Add("Referer", "https://www.youtube.com/")
|
||||
headRequest.Header.Add("Referer", "https://www.youtube.com/")
|
||||
|
||||
if connectionChecker(req.Context()) {
|
||||
return
|
||||
}
|
||||
|
||||
resp, err := client.Do(request)
|
||||
resp := &http.Response{}
|
||||
|
||||
for i := 0; i < 5; i++ {
|
||||
resp, err = client.Do(headRequest)
|
||||
if err != nil {
|
||||
log.Panic(err)
|
||||
log.Panic("Failed to do HEAD request:", err)
|
||||
}
|
||||
if resp.Header.Get("Location") != "" {
|
||||
new_url, _ := url.Parse(resp.Header.Get("Location"))
|
||||
postRequest.URL = new_url
|
||||
headRequest.URL = new_url
|
||||
postRequest.Host = new_url.Host
|
||||
headRequest.Host = new_url.Host
|
||||
continue
|
||||
} else {
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if resp.Header.Get("location") != "" {
|
||||
new_url, err := url.Parse(resp.Header.Get("location"))
|
||||
resp, err = client.Do(postRequest)
|
||||
if err != nil {
|
||||
log.Panic(err)
|
||||
}
|
||||
request.URL = new_url
|
||||
resp, err = client.Do(request)
|
||||
if err != nil {
|
||||
log.Panic(err)
|
||||
}
|
||||
log.Panic("Failed to do POST request:", err)
|
||||
}
|
||||
|
||||
if err := forbiddenChecker(resp, w); err != nil {
|
||||
|
|
3
main.go
3
main.go
|
@ -48,6 +48,9 @@ var proxy string
|
|||
|
||||
// http/2 client
|
||||
var h2client = &http.Client{
|
||||
CheckRedirect: func(req *http.Request, via []*http.Request) error {
|
||||
return http.ErrUseLastResponse
|
||||
},
|
||||
Transport: &http.Transport{
|
||||
Dial: func(network, addr string) (net.Conn, error) {
|
||||
var net string
|
||||
|
|
Loading…
Add table
Reference in a new issue