Press ESC to close

Kenapa Chrome Tidak Menampilkan Final URL pada HTML5 Video?

Singkat cerita, pada sebuah website yang menggunakan player Plyr.io, patcher video NetMeter Web tiba-tiba tidak bekerja sama sekali (tidak melaporkan bytes), padahal video tersebut jelas menggunakan native HTML5, bukan MSE atau DASH/HLS atau pun worker yang aneh.

Awalnya saya mengira ada bug kecil, tetapi hasil trace menunjukkan hal yang jauh lebih menarik sekaligus membagongkan lagi.

Video tersebut memuat sumber .php, lalu Chrome diam-diam mengikuti redirect ke .mp4, sementara DOM tetap diam dan tetap menampilkan sumbernya sebagai .php.

Perbedaan kecil ini akhirnya membawa saya pada “penyimpangan besar” dalam perilaku browser modern.

Kenapa Video HTML5 Sering Bohong URL Aslinya?

Pada kasus website tersebut, saat saya membuka DevTools, semuanya terlihat terang: .php berubah menjadi .mp4 melalui status code 302.

Namun DOM tetap diam, seolah-olah redirect itu tidak pernah terjadi. Nilai src dan currentSrc sama sekali tidak menunjukkan URL final tersebut.

Di DevTools Network, kita bisa lihat jelas:

video-uploads.php?key=xxx → 302 → final.mp4

Tetapi di DOM?

<video src="video-uploads.php?key=xxx">

Kenapa bisa seperti ini? Ternyata, bagian ini sudah ada dalam spesifikasi HTML5. Redirect untuk media diproses di luar jangkauan JavaScript, yaitu di network stack. Browser mengikuti redirect, memuat file final, tetapi tidak mengubah atribut DOM yang terlihat oleh developer.

“User agents may follow redirects, but must not expose the final URL to scripts.
>> WHATWG HTML Living Standard

Dengan kata lain, Chrome hanya memberi tahu kita apa yang DOM tulis, bukan apa yang sebenarnya dilakukan di belakang layar.

Alasan lain yang saya temukan terkait hal ini adalah:

  • Same-Origin Policy & CORS – JavaScript tidak bisa mengakses HTTP headers dari response, termasuk Location header dari redirect 302. Browser menyembunyikan informasi ini dari script untuk alasan keamanan.
  • Redirect terjadi di level browser – Ketika browser mengikuti 302 redirect, itu adalah operasi internal browser sebelum resource dikirim ke page. Sedangkan patch tidak punya visibility ke intermediate requests tersebut.

Ganjalan dari GPU Decoder

Masalah pelik lain adalah adanya satu ganjalan besar bin penting yang sering terlupakan saat memantau video native di Chrome. Dimana tidak semua video diproses melalui software decoder. Beberapa format atau resolusi tinggi akan membuat Chrome memindahkan proses decode ke GPU. Mari lihat workflow yang saya ambil dari situs resmi Chromium ini:

Chrome Media Pipeline (sumber: Chromium)

Dalam mode GPU, dua properti utama yang biasa digunakan NetMeter:

  • webkitVideoDecodedByteCount
  • webkitAudioDecodedByteCount

akan tetap nol selamanya, meskipun video jelas diputar dengan lancar.

Hal ini terjadi karena GPU decoding berjalan di pipeline terpisah yang tidak mengembalikan statistik byte ke lapisan JavaScript. 😤

Tak Ada Solusi?

Sempat melakukan trial dengan cara menggabungkan patcher video DOM dan WebRequest Redirect Mapping, tapi secara implementasi benar-benar tidak sederhana, bahkan tidak memberikan hasil yang stabil.

Meskipun kita bisa mendeteksi URL final, tidak ada cara realtime untuk menghubungkannya langsung dengan aktivitas playback <video>. Browser terlalu banyak menyembunyikan detail internal, terutama pada jalur GPU dan media pipeline.

Inti Solusinya: Menunggu Request Media Selesai

Saya mencoba memasang listener WebRequest untuk jenis request media dengan status 206 Partial Content.
Begitu request ini selesai onCompleted, data bandwidth bisa kita hitung dari ukuran respon yang diterima. Terdengar sangat tidak realtime untuk kasus video dengan filesize besar, tapi beginilah kenyataannya.

Versi sederhana implementasinya sebagai berikut:

webRequest.onCompleted.addListener(
  (details) => {
    try {
      if (
        details.statusCode === 206 &&
        details.type === "media" &&
        details.fromCache === false
      ) {
        // Mesin dan dapur rahasia penghitung bandwidth khusus media 206 😆
        media206Engine.verifyMedia206Commit(
          details,
          addBandwidthToLocalV3
        ); 
      }
    } catch (e) {
      console.error("Error in onCompleted 206:", e);
    }
  },
  { urls: ["http://*/*", "https://*/*"] },
  ["extraHeaders"]
);

Dengan bantuan ChatGPT, alurnya adalah seperti ini:

                     ┌────────────────────────────────────────┐
                     │  Browser Memulai Request Media (206)   │
                     │     HTML5 Video memainkan segmen       │
                     └────────────────────────────────────────┘
                                        │
                                        ▼
                   ┌────────────────────────────────────────────┐
                   │   WebRequest: onHeadersReceived Fired      │
                   │  - Mendeteksi type: "media"                │
                   │  - Status: 206 Partial Content + no cache  │
                   └────────────────────────────────────────────┘
                                        │
                                        │ Waiting for lifecycle request
                                        ▼
           ┌───────────────────────────────────────────────────────────┐
           │                         Possibly?                         │
           └───────────────────────────────────────────────────────────┘                    
                   ▼ sukses                                     ▼ gagal
 ┌────────────────────────────────────────┐  ┌────────────────────────────────────┐
 │    WebRequest: "onCompleted".          │  │   WebRequest: "onErrorOccurred".   │
 │  - Request selesai tanpa error         │  │  - Request gagal / terputus        |
 │  - Data akan dihitung (kemungkinan)    |  │  - Data tidak digunakan            │
 └────────────────────────────────────────┘  └────────────────────────────────────┘

Meskipun tidak realtime per detik, metode ini memberikan gambaran bandwidth yang jauh lebih stabil pada kasus redirect media yang tidak dapat dipantau oleh JavaScript sama sekali.

Pelajaran kali ini

Redirect media ternyata memiliki aturan yang lebih ketat daripada request biasa, dan GPU decoding membuat statistik video tidak bisa diakses Javascript sama sekali.

Masalah dan trial solusi diatas, memaksa kita memahami cara browser bekerja dari lapisan paling bawah, meskipun tidak ada solusi yang benar-benar akurat dan tepat, “tapi perjalanan tetap harus dilanjutkan”.

Terima kasih!


Sumber-sumber
  1. WHATWG HTML Standard (Navigation and Fetching Rules):
    https://html.spec.whatwg.org/multipage/urls-and-fetching.html#following-hyperlinks
  2. Chromium Media Pipeline:
    https://chromium.googlesource.com/chromium/src/+/main/media/

Muhammad K Huda

A non exhausted blogger person within fullstack engineer (spicy food), open source religion, self-taught driver and maybe you know or don't like it. Simply says, Hello from Me!

Tinggalkan Balasan

Alamat email Anda tidak akan dipublikasikan. Ruas yang wajib ditandai *

Cek untuk notifikasi e-mail jika komentar dibalas.

This site uses Akismet to reduce spam. Learn how your comment data is processed.