İçeriğe geç
academia.sh

Ders 10 / 12

Tarayıcı Ne Yapar

Adres satırındaki metnin çözümlenmesinden ekrandaki çizime uzanan aşamalar, alt kaynak istekleri ve bağlantıların yeniden kullanımı.

İçindekiler

Önceki ders tek bir isteği ve tek bir yanıtı inceledi. Buna karşın bir sayfa açıldığında tek bir istek yapılmaz. Gelen belge başka kaynaklara başvurur ve tarayıcı onları da ister.

Bu ders tarayıcının işini sırasıyla ele alır: adres satırındaki metnin çözümlenmesinden ekrandaki çizime kadar. Tarayıcı bir görüntüleyici değil, bu aşamaları yürüten bir düzenleyicidir.

Adresin Çözümlenmesi

İlk iş, yazılan metni bölümlerine ayırmaktır. Bir adres tek bir dizgi değil, yapılı bir değerdir.

from urllib.parse import urlsplit

adres = "https://ornek.test:8443/arsiv/belge?konu=ag&sayfa=2#bolum3"
parca = urlsplit(adres)

print("sema      :", parca.scheme)
print("konak     :", parca.hostname)
print("bag. nok. :", parca.port)
print("yol       :", parca.path)
print("sorgu     :", parca.query)
print("parca     :", parca.fragment)
sema      : https
konak     : ornek.test
bag. nok. : 8443
yol       : /arsiv/belge
sorgu     : konu=ag&sayfa=2
parca     : bolum3

Bölümlerin her biri farklı bir aşamada kullanılır:

Bölüm Kullanıldığı yer
Şema Hangi protokolün konuşulacağı; bağlantı noktası varsayılanını da belirler
Konak Alan Adı Sistemi dersindeki çözümlemeye verilen ad
Bağlantı noktası Bağlantı kurulurken; yazılmazsa şemanın varsayılanı
Yol İstek satırına konur, sunucuya gönderilir
Sorgu İstek satırına yolla birlikte konur, sunucuya gönderilir
Parça Sunucuya gönderilmez; yalnızca tarayıcıda kullanılır

Son satır dikkat çekicidir. #bolum3 bölümü ağa hiç çıkmaz; tarayıcı belgeyi aldıktan sonra o adı taşıyan bölüme kaydırmak için kendisi kullanır. Sunucu bu değeri göremez.

Adın büyük–küçük harf ayrımı gözetmediği Alan Adı Nedir dersinde belirtilmişti. Yol bölümü için aynı şey geçerli değildir: /Arsiv ile /arsiv farklı iki yol olabilir ve bunu belirleyen sunucudur.

Aşamalar

Adres çözümlendikten sonra tarayıcı şu adımları izler:

  1. Ad çözümleme. Konak adı bir adrese çevrilir. Alan Adı Sistemi dersindeki zincir burada işler ve önbellekler devreye girer.
  2. Bağlantı kurma. Hedef adres ve bağlantı noktasına bağlanılır.
  3. Güvenlik el sıkışması. Şema https ise şifreli kanal kurulur; sonraki dersin konusudur.
  4. İstek gönderme. Önceki derste tanımlanan biçimde istek yazılır.
  5. Yanıt alma ve yorumlama. Durum kodu ve Content-Type başlığına göre gövdenin ne olduğu belirlenir.
  6. Belgeyi ayrıştırma. İçerik bir belgeyse yapısı çıkarılır.
  7. Alt kaynakları isteme. Belgenin başvurduğu her kaynak için 1–5 adımları yinelenir.
  8. Yerleşim ve çizim. Öğelerin ekrandaki yeri ve görünümü hesaplanır, çizilir.

Adımların bir bölümü örtüşür. Tarayıcı belgenin tamamını beklemeden ayrıştırmaya başlar ve gördüğü ilk alt kaynak başvurusunda isteği yollar.

Alt Kaynak İstekleri

Yedinci adım, açılan bir sayfanın neden tek bir isteğe indirgenemeyeceğini açıklar. Aşağıdaki sunucu üç kaynak sunar; kök belge diğer ikisine başvurur.

from http.server import BaseHTTPRequestHandler, HTTPServer

SAYFALAR: dict[str, tuple[str, bytes]] = {
    "/": ("text/html; charset=utf-8",
          b"<!doctype html>\n<html lang=\"tr\">\n"
          b"<head><link rel=\"stylesheet\" href=\"/bicem.css\"></head>\n"
          b"<body><h1>Ornek Sayfa</h1><img src=\"/logo.svg\" alt=\"\"></body>\n"
          b"</html>\n"),
    "/bicem.css": ("text/css; charset=utf-8", b"h1 { color: #333; }\n"),
    "/logo.svg": ("image/svg+xml",
                  b"<svg xmlns=\"http://www.w3.org/2000/svg\" width=\"8\" height=\"8\"></svg>\n"),
}


class Isleyici(BaseHTTPRequestHandler):
    protocol_version = "HTTP/1.1"

    def log_message(self, bicem: str, *arg: object) -> None:
        print(f"{self.command} {self.path} -> {arg[1]}", flush=True)

    def _yanitla(self, durum: int, tip: str, govde: bytes, govde_gonder: bool) -> None:
        self.send_response_only(durum)
        self.send_header("Content-Type", tip)
        self.send_header("Content-Length", str(len(govde)))
        self.end_headers()
        if govde_gonder:
            self.wfile.write(govde)

    def _dagit(self, govde_gonder: bool) -> None:
        if self.path in SAYFALAR:
            tip, govde = SAYFALAR[self.path]
            self.log_request(200)
            self._yanitla(200, tip, govde, govde_gonder)
        else:
            govde = b"<h1>404 Bulunamadi</h1>\n"
            self.log_request(404)
            self._yanitla(404, "text/html; charset=utf-8", govde, govde_gonder)

    def do_GET(self) -> None:
        self._dagit(govde_gonder=True)

    def do_HEAD(self) -> None:
        self._dagit(govde_gonder=False)


HTTPServer(("127.0.0.1", 8080), Isleyici).serve_forever()

Bir tarayıcının yapacağı üç istek, curl ile açıkça yapılır:

curl -sv --resolve ornek.test:8080:127.0.0.1 -A "ornek-istemci" -o /dev/null \
  http://ornek.test:8080/ http://ornek.test:8080/bicem.css http://ornek.test:8080/logo.svg

Sunucunun kaydı üç isteği gösterir:

GET / -> 200
GET /bicem.css -> 200
GET /logo.svg -> 200

Kullanıcı tek bir adres yazdı; sunucu üç istek gördü. Gerçek sayfalarda bu sayı çok daha yüksektir ve alt kaynaklar başka alan adlarında bulunabilir — bu durumda her yeni alan adı için ad çözümleme ve bağlantı kurma adımları yeniden yürütülür.

Bağlantıların Yeniden Kullanımı

Her istek için ayrı bir bağlantı kurmak pahalıdır. Bağlantı kurmak en az bir gidiş–dönüş süresi gerektirir; şifreli bağlantıda daha fazlası. Ağ Nedir dersinde kurulduğu üzere gecikmenin bir bölümü fiziksel olarak azaltılamaz, dolayısıyla gidiş–dönüş sayısını azaltmak doğrudan bir kazançtır.

Yukarıdaki üç isteğin bağlantı davranışı incelendiğinde durum görünür:

*   Trying 127.0.0.1:8080...
* Connected to ornek.test (127.0.0.1) port 8080
> GET / HTTP/1.1
< HTTP/1.1 200 OK
* Connection #0 to host ornek.test left intact
* Re-using existing connection with host ornek.test
> GET /bicem.css HTTP/1.1
< HTTP/1.1 200 OK
* Connection #0 to host ornek.test left intact
* Re-using existing connection with host ornek.test
> GET /logo.svg HTTP/1.1
< HTTP/1.1 200 OK
* Connection #0 to host ornek.test left intact

Bir kez bağlanıldı, üç istek aynı bağlantı üzerinden geçti. Bu kalıcı bağlantı (persistent connection) davranışıdır ve HTTP/1.1 ile protokolün varsayılanı durumuna gelmiştir; önceki sürümde her istek için bağlantı kurulup kapatılıyordu.

Kalıcı bağlantının çözmediği bir sorun kalır. Aynı bağlantı üzerindeki istekler sırayla işlenir: ilk yanıt tamamlanmadan ikincisi gönderilemez. Yavaş bir yanıt, arkasındakileri bekletir. Bu davranış sıra başı engellemesi olarak adlandırılır.

HTTP/2, aynı bağlantı üzerinde birden çok isteğin iç içe geçmesine izin vererek bu soruna yanıt verir; buna çoğullama (multiplexing) denir. İstekler ve yanıtlar numaralanmış akışlara bölünür, parçalar karışık sırayla gönderilir ve alıcı tarafta ayrıştırılır. Bu fikir, Ağ Nedir dersindeki paket numaralandırma ile aynı akıl yürütmedir.

Özellik Ayrı bağlantı Kalıcı bağlantı Çoğullama
İstek başına bağlantı kurma Her istekte İlk istekte İlk istekte
Aynı anda bekleyen istek Bağlantı sayısı kadar Bir Çok
Yavaş yanıtın etkisi Yalnız kendisi Arkasındakileri bekletir Diğerlerini bekletmez

Bu üç davranış, protokolün sürümleri arasındaki teknik ayrımdır. Hangisinin kullanıldığı istemci ile sunucunun bağlantı kurarken anlaşmasıyla belirlenir.

Belgeden Çizime

Alınan belge metindir; ekranda görünen ise yerleşimi ve biçimi hesaplanmış öğelerdir. Arada üç iş vardır.

Ayrıştırma. Belge metni, iç içe geçmiş öğelerden oluşan bir ağaca çevrilir. Veri Yapıları kursundaki ağaç yapısı burada doğrudan karşılığını bulur: her öğe bir düğüm, iç içelik ise ata–alt ilişkisidir.

Biçim hesabı. Biçem kuralları öğelere uygulanır ve her öğenin görünüm özellikleri belirlenir.

Yerleşim ve çizim. Her öğenin ekrandaki konumu ve boyutu hesaplanır, sonra çizilir.

Alt kaynakların bu sırayı etkileme biçimi farklıdır ve bu fark gözlenebilir bir sonuç doğurur. Biçem dosyası alınmadan çizim yapmak, sayfanın önce biçimsiz görünüp sonra değişmesine yol açar; bu yüzden çizim biçem dosyası beklenerek yapılır. Betikler ise belgeyi değiştirebildikleri için ayrıştırmayı durdurabilir. Görseller ise beklenmez; geldiklerinde yerlerine konur.

Bu, alt kaynakların yalnızca sayılarının değil sıralarının da sayfanın görünme süresini belirlediği anlamına gelir.

Tarayıcı Önbelleği

Alınan kaynakların yeniden istenmemesi için tarayıcı bir önbellek tutar. Alan Adı Sistemi dersindeki yaşam süresi mantığı burada da geçerlidir, ancak denetim başlıklarla yapılır.

Sunucu bir yanıtın ne kadar süre saklanabileceğini bildirir. Süre dolduğunda tarayıcı kaynağı yeniden indirmek yerine koşullu istek yapar: elindeki kopyanın kimliğini gönderir ve “değiştiyse gönder” der. Değişmemişse sunucu gövdesiz kısa bir yanıt döndürür ve gövde ikinci kez taşınmamış olur.

Bu düzen, ilk açılış ile sonraki açılışlar arasındaki farkın kaynağıdır ve önceki dersteki HEAD yönteminin gerekçesiyle aynı fikre dayanır: içeriği taşımadan içerik hakkında bilgi almak.

Özet

  • Adres yapılı bir değerdir; şema, konak, bağlantı noktası, yol, sorgu ve parça bölümleri farklı aşamalarda kullanılır ve parça bölümü sunucuya hiç gönderilmez.
  • Tarayıcı ad çözümleme, bağlantı kurma, istek gönderme, ayrıştırma, alt kaynak isteme ve çizim adımlarını yürütür; adımlar örtüşerek ilerler.
  • Tek bir adres yazılması çok sayıda isteğe yol açar; alt kaynaklar farklı alan adlarındaysa çözümleme ve bağlantı adımları yeniden yürütülür.
  • Kalıcı bağlantı, bağlantı kurma maliyetini istekler arasında paylaştırır; çoğullama, aynı bağlantıdaki isteklerin birbirini beklemesini ortadan kaldırır.
  • Belge bir öğe ağacına çevrilir; biçem beklenerek, betikler ayrıştırmayı durdurarak, görseller beklenmeden işlenir.
  • Tarayıcı önbelleği, süresi dolan kaynaklar için koşullu istek yaparak gövdenin yeniden taşınmasını önler.

Sonraki Adım

Bu ders adresin şema bölümünü ayırdı ve https durumunda bir güvenlik el sıkışması yapıldığını söyleyip geçti. O adım atlanamaz: alışverişin yol üzerindeki hiç kimse tarafından okunamaması, değiştirilememesi ve karşı tarafın gerçekten iddia ettiği taraf olması gerekir. Sonraki ders bu üç sözü ayrı ayrı tanımlayacak ve yerel olarak üretilmiş bir sertifikayla her birinin nasıl sınandığını gösterecek.

İlerlemeni kaydetmek ve not almak için Giriş yap

Notlarım

Not almak için giriş yapmalısın.

Aramak için yazmaya başlayın.

↑↓ Esc gezin · aç · kapat