İçeriğe geç
academia.sh

Ders 01 / 16

HTTP Yöntemleri ve Anlamları

Yöntem bir bildirimdir: aradaki aracı ondan yinelenebilir ve saklanabilir kararını çıkarır, ve bildirimi doğrulayan hiçbir şey yoktur.

İçindekiler

Ağ Modelleri ve Protokoller kursu taşıma katmanını (transport layer) bitirirken elde tek bir söz kalmıştı: TCP sıralı, kayıpsız, yinelemesiz bir bayt akışı verir. Bu sözün içinde bir boşluk durur. Taşıma katmanı baytı taşır; baytın ne anlama geldiğini bilmez. Aynı kırk bayt bir ölçüm kaydı da olabilir, bir silme buyruğu da; TCP ikisini birbirinden ayırmaz ve ayırmayı üstlenmez.

Anlamı uygulama katmanı kurar. Ve anlamı kuran şey, iletide yazandan başkası değildir: bir yöntem adı, bir yol, bir başlık alanı (header field). Bu kurs boyunca sayılacak şey de budur — iletide yazanın, iletiyi okuyan üçüncü bir tarafa kaç kararı aldırdığı. Bu ders önce o üçüncü tarafı ve ölçüyü kurar, sonra ilk alanı ölçer: yöntemi.

Aracı: Uygulamayı Bilmeyen Katman

Kuzey Yamaç ölçüm istasyonu, ölçümlerini bir istemciye sunar. İkisinin arasında bir aracı (intermediary) durur: önbellekleyen, yönlendiren, gerektiğinde yeniden deneyen bir katman. Vekil (proxy) aracının bir türüdür; genel ad aracıdır.

Aracı uygulamayı bilmez. Ne ölçüldüğünü, kaydın ne anlama geldiğini, hangi oturumun kime ait olduğunu bilmez. Bildiği tek şey iletide yazandır. Kursun bütün konusu bu tek cümlede toplanır: iletide ne yazıyorsa aracı onu bilir; yazmıyorsa bilmez; yanlış yazıyorsa yanlış bilir.

Aracının gördüğü istek şuna benzer. Aşağıdaki döküm öğretim amaçlıdır ve çalıştırılmaz:

POST /kayit HTTP/1.1
Host: istasyon.ornek
Content-Type: application/json
Content-Length: 74

Yanıt tarafında aracının okuduğu iki im daha vardır. Yanıtın ilk satırı sonraki dersin konusudur; burada yalnız başlık alanları okunur:

Cache-Control: private
ETag: "s-0417"

Bu dört satırın modeldeki karşılıkları şunlardır:

Dökümdeki yer Modeldeki alan Aracının çıkardığı
İstek satırının ilk sözcüğü yontem yinelenebilir, saklanabilir
İstek satırının ikinci sözcüğü yol kaynağın kimliği
Host konak yonlendirilebilir
Cache-Control: private ozel_imi paylasilabilir, saklanabilir
ETag dogrulayici taze

Yöntem Bir Bildirimdir

Yöntem iki ayrı özellik bildirir. Bir yöntem güvenli (safe) ise, isteği göndermek sunucudaki durumu değiştirmeyi amaçlamaz. Bir yöntem etkisiz (idempotent) ise, aynı isteği bir kez ya da art arda beş kez göndermek aynı sonucu bırakır.

Yöntem Güvenli Etkisiz Aracının çıkardığı
GET evet evet yanıt saklanabilir, istek yinelenebilir
HEAD evet evet yanıt saklanabilir, istek yinelenebilir
PUT hayır evet yanıt saklanmaz, istek yinelenebilir
DELETE hayır evet yanıt saklanmaz, istek yinelenebilir
POST hayır hayır ikisi de değil

Güvenlilik etkisizliği içerir: durumu değiştirmeyen bir istek, yinelendiğinde de değiştirmez. Tersi doğru değildir; PUT durumu değiştirir ama aynı gövdeyle yinelendiğinde aynı durumu bırakır.

Web API Tasarımı kursunun kaynak tasarımı konusu bu ayrımı tasarımcının taahhüdü olarak ele alır ve hangi yöntemin seçilmesi gerektiğini söyler. Burada seçim çoktan yapılmıştır; ölçülen şey, yapılmış seçimin aracıya ne bildirdiğidir. Etkisizlik anahtarı da aynı kursta kurulmuştur ve bir uygulama sözleşmesidir; bu ders protokolün kendi bildirimini ölçer, uygulamanın eklediğini değil.

Ölçü: Fazladan Tur Olmadan Alınan Karar

Bir protokolün sayısı, taşıdığı alan değil, alıcı tarafa fazladan bir gidiş–dönüş (round trip) olmadan kaç kararı aldırdığıdır. Alınamayan bir karar bir tur borcudur: aracı bilemediği şeyi sormak zorunda kalır ve sormak bir tur eder.

Kurgu kırk alışveriş üretir. Her alışverişte aracının vermesi istenen beş karar vardır.

Karar Sorusu
saklanabilir Bu yanıt önbelleğe konabilir mi
paylasilabilir Saklanan kopya başka bir istemciye verilebilir mi
taze Elde tutulan kopya hâlâ geçerli mi
yinelenebilir İstek yanıtsız kalırsa yeniden gönderilebilir mi
yonlendirilebilir İleti hedefine yönlendirilebilir mi

Kırk alışveriş ve beş karar, iki yüz kararlık bir kümedir. Bu küme ölçümün çözünürlüğünü de belirler: burada ölçülebilen en küçük fark 1/200=0,00501/200 = 0{,}0050’dir ve bundan küçük bir fark iddia edilmez.

Gerçeğin kendisi kâhin (oracle) ile temsil edilir. Kurguyu biz ürettiğimiz için her alışverişin gerçekten kişiye özel olup olmadığı ve kopyanın gerçekten bayatlayıp bayatlamadığı bilinir. Aracının kararı bu gerçeğe göre doğru, yanlış ya da alınamayan diye sayılır.

Ölçümün varsayımları:

  • HA1 — Kırk alışveriş tek bir tohumdan üretilir; yöntem ve yol sabit listelerden çekilir ve ölçüm her koşumda aynı kümeyi verir.
  • HA2 — Kâhinin gerçeği kurguyu biz ürettiğimiz için bilinir: yanıtın kişiye özel olup olmadığı ve kopyanın bayatlayıp bayatlamadığı üretim anında belirlenir, iletiden okunmaz.
  • HA3 — Bu derste tek bir rejim ölçülür: ileti açıktır ve beş alanın beşi de aracıya görünür. Alanın gizlendiği rejimler sonraki derslerin konusudur.
  • HA4 — Aracı uygulamayı bilmez ve her kararı yalnız iletide bulunan alandan kurar. Alan iletide yoksa karar hiç verilmez — yanlış karar değil, alınamayan karar.
  • HA5 — Kişiye özel im sunucunun bildirimidir ve sunucu kimi kişiye özel yanıtta onu koymayı atlar; doğrulayıcı damganın da bir çözünürlüğü vardır ve kimi değişimi kaçırır. İletide yazanı doğrulayan hiçbir şey yoktur.
  • HA6 — Bayt sayımı alan adı, değer ve ayraç uzunluğundan hesaplanır; ölçüm bir ağ ölçümü değil, ileti içeriğinin sayımıdır.

Çekirdek

Kurgu, kâhin ve aracı aşağıdaki çekirdekte kurulur. ACIK demeti, aracının okuyabildiği alanları verir: bu derste ileti açıktır, beş alanın beşi de görünür.

TOHUM = 20260809
GUVENLI = {"GET", "HEAD"}
ETKISIZ = {"GET", "HEAD", "PUT", "DELETE"}
YONTEMLER = ["GET", "GET", "GET", "HEAD", "POST", "PUT", "DELETE"]
YOLLAR = ["/olcum/kuzey", "/olcum/yamac", "/ozet", "/kayit", "/oturum"]
KARARLAR = ("saklanabilir", "paylasilabilir", "taze", "yinelenebilir",
            "yonlendirilebilir")
ACIK = ("yontem", "yol", "konak", "ozel_imi", "dogrulayici")


def uretec(tohum: int):
    d = tohum % 2147483646 + 1

    def r(n: int) -> int:
        nonlocal d
        d = (d * 48271) % 2147483647
        return d % n
    return r


def alisverisler(sayi: int = 40, tohum: int = TOHUM) -> list[dict]:
    r, liste = uretec(tohum), []
    for i in range(sayi):
        yontem, yol = YONTEMLER[r(7)], YOLLAR[r(5)]
        ozel = yol == "/oturum" or r(5) == 0
        degisti = r(3) == 0
        liste.append({
            "no": i + 1, "yontem": yontem, "yol": yol,
            "ozel": ozel,                           # gerçek: yanıt kişiye özel
            "degisti": degisti,                     # gerçek: kopya bayat
            "ozel_imi": ozel and r(4) != 0,         # bildirim: sunucu im koydu
            "damga_atladi": degisti and r(6) == 0,  # doğrulayıcı değişimi kaçırdı
        })
    return liste


def kahin(a: dict) -> dict:
    return {
        "saklanabilir": a["yontem"] in GUVENLI and not a["ozel"],
        "paylasilabilir": not a["ozel"],
        "taze": not a["degisti"],
        "yinelenebilir": a["yontem"] in ETKISIZ,
        "yonlendirilebilir": True,
    }


def ileti(a: dict, gorunur: tuple) -> dict:
    tam = {"yontem": a["yontem"], "yol": a["yol"], "konak": "istasyon.ornek",
           "ozel_imi": a["ozel_imi"],
           "dogrulayici": a["degisti"] and not a["damga_atladi"]}
    return {k: v for k, v in tam.items() if k in gorunur}


def bayt(i: dict) -> int:
    return sum(len(k) + len(str(v)) + 4 for k, v in i.items())


def araci(i: dict) -> dict:
    k = {}
    if "yontem" in i:
        k["yinelenebilir"] = i["yontem"] in ETKISIZ
    if "ozel_imi" in i:
        k["paylasilabilir"] = not i["ozel_imi"]
        if "yontem" in i:
            k["saklanabilir"] = i["yontem"] in GUVENLI and not i["ozel_imi"]
    if "dogrulayici" in i:
        k["taze"] = not i["dogrulayici"]
    if "konak" in i:
        k["yonlendirilebilir"] = True
    return k

araci işlevinin yapısı dikkat ister: her karar bir in denetiminin arkasındadır. Alan iletide yoksa karar sözlüğe hiç girmez — aracı yanlış karar vermez, karar veremez. İki sonuç arasındaki bu ayrım kursun geri kalanında sayılacaktır.

Açık Rejimin Ölçümü

Ölçüm, yukarıdaki çekirdeğin ardından koşar. Her alışverişte kâhinin gerçeği ile aracının kararı karşılaştırılır; bir karar hiç alınamadıysa o alışveriş bir tur borçlanır.

alis = alisverisler()
sayac = {k: [0, 0, 0] for k in KARARLAR}    # doğru, yanlış, alınamayan
tur = bayt_toplam = 0
for x in alis:
    gercek, verilen = kahin(x), araci(ileti(x, ACIK))
    eksik = False
    for karar in KARARLAR:
        if karar not in verilen:
            sayac[karar][2] += 1
            eksik = True
        elif verilen[karar] == gercek[karar]:
            sayac[karar][0] += 1
        else:
            sayac[karar][1] += 1
    tur += 1 if eksik else 0
    bayt_toplam += bayt(ileti(x, ACIK))

print(f"alışveriş {len(alis)}, karar {len(alis) * len(KARARLAR)}, "
      f"etkisiz bildiren {sum(x['yontem'] in ETKISIZ for x in alis)}, "
      f"etkisiz bildirmeyen {sum(x['yontem'] not in ETKISIZ for x in alis)}, "
      f"güvenli bildiren {sum(x['yontem'] in GUVENLI for x in alis)}")
print(f"kişiye özel {sum(x['ozel'] for x in alis)}, "
      f"imsiz kalan {sum(x['ozel'] and not x['ozel_imi'] for x in alis)}, "
      f"bayat {sum(x['degisti'] for x in alis)}")
print(f"açık rejim: doğru {sum(v[0] for v in sayac.values())}, "
      f"yanlış {sum(v[1] for v in sayac.values())}, "
      f"alınamayan {sum(v[2] for v in sayac.values())}, "
      f"fazladan tur {tur}, bayt {bayt_toplam}")
print()
print(f"{'karar':<18s} {'doğru':>6s} {'yanlış':>7s} {'alınamayan':>11s}")
for karar, (d, y, e) in sayac.items():
    print(f"{karar:<18s} {d:6d} {y:7d} {e:11d}")
alışveriş 40, karar 200, etkisiz bildiren 31, etkisiz bildirmeyen 9, güvenli bildiren 18
kişiye özel 17, imsiz kalan 2, bayat 12
açık rejim: doğru 195, yanlış 5, alınamayan 0, fazladan tur 0, bayt 3524

karar               doğru  yanlış  alınamayan
saklanabilir           40       0           0
paylasilabilir         38       2           0
taze                   37       3           0
yinelenebilir          40       0           0
yonlendirilebilir      40       0           0

Okunacak ilk satır alınamayan 0 ve fazladan tur 0. İleti açıkken aracı iki yüz kararın iki yüzünü de alır ve sunucuya bir kez bile dönmez. Üç bin beş yüz yirmi dört baytın karşılığı budur.

İkinci satır yöntemin payıdır. Kırk alışverişin otuz biri etkisiz bir yöntem bildirir, on sekizi güvenli bir yöntem bildirir. yinelenebilir kırk kararın kırkında doğrudur, çünkü kâhin de aracı da aynı kümeye bakar: yöntem adı iletide yazılıdır ve başka hiçbir şeye bağlı değildir. Yanıtsız kalan bir istekte aracının yeniden gönderip göndermeyeceğine karar veren tek şey bu tek sözcüktür.

saklanabilir de kırk kararın kırkında doğrudur, ama gerekçesi aynı değildir. Bu karar iki alana birden bağlıdır: yöntem güvenli olmalı ve yanıt kişiye özel olmamalıdır. Kırk alışverişin on yedisi gerçekten kişiye özeldir. Aracı bunu yöntemden çıkaramaz; sunucunun koyduğu ime bakar.

Yinelemenin Bedeli

yinelenebilir kararının kırkında da doğru çıkması onun bedelsiz olduğu anlamına gelmez; karşılığı olan durumda pahalıdır. Bir istek gönderildi ve yanıt gelmedi diyelim. Aracının bildiği tek şey yanıtın gelmediğidir. İsteğin sunucuya hiç ulaşmadığını mı, yoksa ulaşıp işlendiğini ve yanıtın dönüş yolunda kaybolduğunu mu, ayırt edemez. Taşıma katmanı bu ayrımı vermez: kopan bir bağlantı iki durumda da aynı görünür.

Yöntem etkisizse ayrım gerekmez. İstek ister ulaşmış ister ulaşmamış olsun, ikinci kez göndermek aynı durumu bırakır; aracı kimseye sormadan yeniden gönderir. Kırk alışverişin otuz birinde durum budur ve karar fazladan tur olmadan alınır.

Kalan dokuz alışverişte yöntem POSTtur. Aracı burada yeniden gönderemez, çünkü ikinci gönderim ilk gönderimin sonucunu iki katına çıkarabilir. Yapabileceği tek şey kararı uca taşımaktır: durumu istemciye bildirmek ya da sunucuya sormak. İkisi de bir gidiş–dönüştür. Tek bir sözcük, otuz bir alışverişte turu sıfırlar, dokuzunda ödetir.

Ölçünün ilk somut karşılığı budur. Aynı alan aynı yerde durur; taşıdığı değere göre bir kararı ya iletinin içinde kapatır ya da bir tur borcuna çevirir. Protokolün sayısı, bu iki sonucun kırk alışveriş boyunca nasıl dağıldığıdır.

Eksik İm Neden Dört Değil İki Yanlış Doğurur

Kişiye özel on yedi yanıtın ikisinde sunucu imi koymamıştır. Bu iki alışverişte aracı elindeki tek bildirime inanır ve yanıtı paylaşılabilir sayar. Ama yanlış sayısı dört değil ikidir. Nedeni aşağıdaki dökümdedir; çekirdek ve ölçüm bloklarının ardından koşar:

print(f"{'imsiz kalan':<21s} {'paylasilabilir':>21s} {'saklanabilir':>21s}")
print(f"{'no':>3s} {'yöntem':<7s} {'yol':<9s} {'verilen':>10s} {'gerçek':>10s} "
      f"{'verilen':>10s} {'gerçek':>10s}")
for x in alis:
    if x["ozel"] and not x["ozel_imi"]:
        g, v = kahin(x), araci(ileti(x, ACIK))
        print(f"{x['no']:3d} {x['yontem']:<7s} {x['yol']:<9s} "
              f"{str(v['paylasilabilir']):>10s} {str(g['paylasilabilir']):>10s} "
              f"{str(v['saklanabilir']):>10s} {str(g['saklanabilir']):>10s}")
imsiz kalan                  paylasilabilir          saklanabilir
 no yöntem  yol          verilen     gerçek    verilen     gerçek
  1 POST    /kayit          True      False      False      False
 34 POST    /kayit          True      False      False      False

İki alışverişin de yöntemi POSTtur. POST güvenli değildir; aracı onun yanıtını im olsun olmasın zaten saklamaz. saklanabilir bu yüzden ikisinde de doğru çıkar — doğru gerekçeyle değil, ama doğru. paylasilabilir ise yalnız ime bağlıdır ve ikisinde de yanlış çıkar.

Buradan çıkan kural ölçünün kendisi kadar önemlidir: eksik bir bildirim, ancak başka türlü karar verilebilecek bir yerde bedel ödetir. Aynı iki alışverişin yöntemi GET olsaydı saklanabilir de yanlışa düşerdi ve toplam yanlış beş değil yedi olurdu. İki alanın kesiştiği kararlar, tek alana bağlı kararlardan daha dayanıklıdır; çünkü ikinci alan birinciyi örtebilir.

Kalan üç yanlış taze kararındandır. Kırk kopyanın on ikisi gerçekten bayatlamıştır; bunların üçünde doğrulayıcı damga değişimi yakalayamamıştır ve aracı bayat kopyaya taze demiştir. Doğrulayıcının çözünürlüğü bu kursun ilerleyen bir dersinin konusudur; burada yalnız yanlış sayısına katkısı sayılır: iki artı üç, beş.

Bildirimi Doğrulayan Yoktur

Beş yanlışın ikisi sunucunun koymadığı bir imden, üçü bir damganın çözünürlüğünden gelir. Ortak yanları şudur: hiçbiri aracının hatası değildir. Aracı iletide yazanı okumuş ve doğru işlemiştir. Yanlış, iletide yazanla gerçeğin ayrılmasından doğar.

Protokolde bu ayrımı kapatan bir düzenek yoktur. Aracı, bir yöntemin gerçekten güvenli olup olmadığını sınayamaz; POST bildiren bir isteğin sunucuda hiçbir şeyi değiştirmediğini ya da GET bildiren bir isteğin bir kaydı sildiğini göremez. Elindeki tek şey bildirimdir ve aracı bildirime inanır.

Bunun bir de daraltma tarafı vardır. Sunucu bir alanı iletiye koymadığında aracı o alana bağlı kararı veremez; koyduğunda ise aracı o alanı sorgusuz kullanır. İki uç arasındaki seçim, sonraki derslerde tek tek ölçülecek olan şeydir: hangi alan görünür kalırsa aracı ne kazanır, görünmez olursa ne kaybeder.

Özet

  • Taşıma katmanı baytı taşır ve anlamını bilmez; anlamı uygulama katmanı kurar ve o anlamı kuran şey yalnızca iletide yazandır.
  • Bir protokolün ölçüsü taşıdığı alan sayısı değil, fazladan bir gidiş–dönüş olmadan aldırdığı karar sayısıdır; alınamayan karar bir tur borcudur.
  • Yöntem iki şey bildirir: güvenlilik ve etkisizlik. Aracı bunlardan yinelenebilir ve saklanabilir kararlarını çıkarır.
  • Kırk alışveriş ve beş kararlık kümede açık rejim 195 doğru, 5 yanlış, 0 alınamayan karar ve 0 fazladan tur verir; ölçüm 3524 bayt okur.
  • Beş yanlışın ikisi imsiz kalan iki yanıttandır ve dört değil ikidir, çünkü o iki alışverişin yöntemi zaten güvenli değildir; kalan üçü doğrulayıcı damgasının kaçırdığı değişimlerden gelir.
  • İletide yazanı doğrulayan hiçbir düzenek yoktur; aracı bildirime inanır ve yanlışlar bu güvenden doğar.

Sonraki Adım

Bu derste ölçülen alanların hepsi isteğin tarafındaydı: yöntem, yol, konak. Yanıtın başlıklarına bakıldı ama ilk satırı bilerek dışarıda bırakıldı. Oysa aracının yanıt üzerinde alacağı ilk karar o satırdadır ve satırın taşıdığı şey üç basamaklı bir sayıdır. Sonraki ders bu sayıyı ölçer: aracı gövdeyi hiç açmadan, yalnız ilk basamağa bakarak yeniden deneyip denemeyeceğine, saklayıp saklamayacağına karar verebilir mi — ve gövdeyi açan bir aracı aynı kararı alırken kaç bayt fazla okur.

İ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