12-bo‘lim

HTTP asoslari

So'rov va javob tuzilishi, usullar, holat kodlari, sarlavhalar, Content-Length ning roli va xom soket ustida HTTP.

🕑 9 daqiqa o‘qish 📄 928 so‘z 👁 1 marta ko‘rilgan
Ushbu bo‘lim mundarijasi
  1. So'rov tuzilishi
  2. Xom soket ustida HTTP
  3. Javobni o'qish
  4. Usullar
  5. Holat kodlari
  6. Xulosa

HTTP - bugungi internetda eng ko'p ishlatiladigan ilova protokoli. Uning eng ajablanarli tomoni - u oddiy matn.

Shuning uchun HTTP so'rovini qo'lda yozib, oddiy soket orqali yuborish mumkin. Aynan shuni qilamiz.

So'rov tuzilishi #

HTTP so'rovi GET /darslik/tarmoqlar HTTP/1.1 so'rov qatori: usul + yo'l + versiya Host: edu.softromeda.com User-Agent: qollanma/1.0 Accept: text/html sarlavhalar: har biri "nom: qiymat" (bo'sh qator) Bo'sh qator - sarlavhalar tugaganini bildiradi. Undan keyin tana boshlanadi. Har qator \r\n bilan tugaydi - faqat \n emas
GET so'rovida odatda tana bo'lmaydi, POST da esa bo'ladi
Python
SOROV = (
    "GET /darslik/tarmoqlar HTTP/1.1\r\n"
    "Host: edu.softromeda.com\r\n"
    "User-Agent: qollanma/1.0\r\n"
    "Accept: text/html\r\n"
    "Accept-Language: uz\r\n"
    "\r\n"
)

print("so'rov uzunligi:", len(SOROV), "bayt")
print()

qatorlar = SOROV.split("\r\n")
usul, yol, versiya = qatorlar[0].split(" ")
print("so'rov qatori:")
print("  usul   :", usul)
print("  yo'l   :", yol)
print("  versiya:", versiya)

print()
print("sarlavhalar:")
for q in qatorlar[1:]:
    if q == "":
        break
    nom, qiymat = q.split(": ", 1)
    print(f"  {nom:<16} {qiymat}")

tana = SOROV.split("\r\n\r\n", 1)[1]
print()
print("tana uzunligi:", len(tana), "- GET da odatda tana bo'lmaydi")
Natija
so'rov uzunligi: 127 bayt

so'rov qatori:
  usul   : GET
  yo'l   : /darslik/tarmoqlar
  versiya: HTTP/1.1

sarlavhalar:
  Host             edu.softromeda.com
  User-Agent       qollanma/1.0
  Accept           text/html
  Accept-Language  uz

tana uzunligi: 0 - GET da odatda tana bo'lmaydi
\r\n - \n emas

HTTP standarti qator oxiri sifatida \r\n ni talab qiladi (carriage return + line feed).

Faqat \n yozsangiz, ko'p serverlar baribir tushunadi - lekin ba'zilari tushunmaydi va so'rovingiz sababsiz rad etiladi.

Shuning uchun HTTP yozayotganda har doim \r\n ishlating.

Host sarlavhasi nima uchun majburiy?

Bitta IP manzilda yuzlab sayt joylashishi mumkin. Server qaysi sayt so'ralayotganini qayerdan biladi?

Javob: Host sarlavhasidan. HTTP/1.1 da u majburiy - usiz server 400 Bad Request qaytaradi.

Bu virtual xosting ning asosi. HTTP/1.0 da bunday sarlavha yo'q edi va har sayt uchun alohida IP kerak bo'lardi.

Xom soket ustida HTTP #

Endi haqiqiy so'rov yuboramiz. Hech qanday HTTP kutubxonasi yo'q - faqat soket:

Python
import socket
import threading

PORT = 9600
SAHIFA = b"<h1>Salom, tarmoq!</h1>"

# Tinglash ASOSIY oqimda ochiladi - shunda mijoz ulanganda
# port allaqachon band bo'ladi (poyga holati bo'lmaydi)
tinglovchi = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
tinglovchi.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
tinglovchi.bind(("127.0.0.1", PORT))
tinglovchi.listen(1)


def server():
    ulanish, _ = tinglovchi.accept()
    sorov = ulanish.recv(4096).decode()
    birinchi = sorov.split("\r\n")[0]
    print("server so'rov qatorini oldi:", birinchi)

    javob = (
        "HTTP/1.1 200 OK\r\n"
        "Content-Type: text/html; charset=utf-8\r\n"
        f"Content-Length: {len(SAHIFA)}\r\n"
        "Connection: close\r\n"
        "\r\n"
    ).encode() + SAHIFA
    ulanish.sendall(javob)
    ulanish.close()


oqim = threading.Thread(target=server, daemon=True)
oqim.start()

mijoz = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
mijoz.settimeout(5)
mijoz.connect(("127.0.0.1", PORT))
mijoz.sendall(b"GET / HTTP/1.1\r\nHost: localhost\r\n\r\n")

javob = b""
while True:
    bolak = mijoz.recv(1024)
    if not bolak:
        break
    javob += bolak
mijoz.close()
oqim.join()
tinglovchi.close()

print()
print("--- xom javob")
for q in javob.decode().split("\r\n"):
    print("  " + (q if q else "(bo'sh qator - sarlavhalar tugadi)"))
Natija
server so'rov qatorini oldi: GET / HTTP/1.1

--- xom javob
  HTTP/1.1 200 OK
  Content-Type: text/html; charset=utf-8
  Content-Length: 23
  Connection: close
  (bo'sh qator - sarlavhalar tugadi)
  <h1>Salom, tarmoq!</h1>

Mana shu - brauzeringiz har sahifa ochganda qiladigan ishning o'zi. Faqat brauzer bundan keyin HTML ni chizadi.

bind va listen nima uchun asosiy oqimda?

Serverni butunlay alohida oqimga joylashtirish tabiiy tuyuladi. Lekin unda poyga holati (race condition) paydo bo'ladi:

OqimNima qiladi
AsosiyOqimni ishga tushiradi va darhol connect qiladi
ServerHali bind va listen ga ulgurmagan

Natijada connect ConnectionRefusedError bilan yiqiladi - lekin har safar emas. Uch urinishdan bittasida.

Aynan shunday xatolar eng yomoni: sinovda o'tib ketadi, keyin tasodifan yiqiladi.

Yechim ikki xil bo'lishi mumkin:

UsulIzoh
Bu yerdagidek: bind va listen asosiy oqimdaEng sodda
threading.Event bilan tayyorligini kutishMurakkabroq holatlarda

Ikkinchisini 1-bo'limdagi birinchi misolda ko'rgansiz.

Xuddi shuni terminaldan ham qilish mumkin

curl ning -v bayrog'i xom so'rov va javobni ko'rsatadi:

Terminal
curl -v https://edu.softromeda.com/

> bilan boshlangan qatorlar - siz yuborgan so'rov, < bilan boshlanganlari - server javobi.

Faqat sarlavhalar kerak bo'lsa:

Terminal
curl -I https://edu.softromeda.com/

Javobni o'qish #

Javob tuzilishi so'rovnikiga juda o'xshash - farqi birinchi qatorda:

Python
XOM = (
    b"HTTP/1.1 301 Moved Permanently\r\n"
    b"Location: https://edu.softromeda.com/darslik/tarmoqlar\r\n"
    b"Content-Type: text/html; charset=utf-8\r\n"
    b"Content-Length: 28\r\n"
    b"\r\n"
    b"<a>Yangi manzilga o'ting</a>"
)


def javobni_och(xom):
    sarlavha_qismi, tana = xom.split(b"\r\n\r\n", 1)
    qatorlar = sarlavha_qismi.decode().split("\r\n")
    versiya, kod, izoh = qatorlar[0].split(" ", 2)
    sarlavhalar = {}
    for q in qatorlar[1:]:
        nom, qiymat = q.split(": ", 1)
        sarlavhalar[nom.lower()] = qiymat
    return int(kod), izoh, sarlavhalar, tana


kod, izoh, sarlavhalar, tana = javobni_och(XOM)

SINFLAR = {
    1: "ma'lumot", 2: "muvaffaqiyat", 3: "yo'naltirish",
    4: "mijoz xatosi", 5: "server xatosi",
}

print("holat kodi :", kod, izoh)
print("sinfi      :", SINFLAR[kod // 100])
print()
for nom, qiymat in sarlavhalar.items():
    print(f"  {nom:<16} {qiymat}")

print()
print("e'lon qilingan uzunlik:", sarlavhalar["content-length"])
print("haqiqiy tana uzunligi :", len(tana))
print("mos keldimi:", int(sarlavhalar["content-length"]) == len(tana))
Natija
holat kodi : 301 Moved Permanently
sinfi      : yo'naltirish

  location         https://edu.softromeda.com/darslik/tarmoqlar
  content-type     text/html; charset=utf-8
  content-length   28

e'lon qilingan uzunlik: 28
haqiqiy tana uzunligi : 28
mos keldimi: True

E'tibor bering: sarlavha nomlari kichik harfga o'tkazildi. HTTP da sarlavha nomlari katta-kichikligiga sezgir emas, shuning uchun ularni bir xil ko'rinishga keltirish odat.

Content-Length xato bo'lsa - ulanish buziladi

8-bo'limda ko'rgandik: TCP - bayt oqimi, xabar chegarasi yo'q. HTTP bu muammoni Content-Length bilan hal qiladi.

Agar u noto'g'ri bo'lsa:

XatoOqibati
Haqiqiydan kichikOrtiqcha baytlar keyingi javobning boshi deb o'qiladi
Haqiqiydan kattaMijoz kelmaydigan baytlarni kutib qotib qoladi

Birinchi holat ayniqsa xavfli: ulanish qayta ishlatilsa (HTTP/1.1 da bu odatiy hol), hujumchi shu yo'l bilan boshqa foydalanuvchining javobiga o'z mazmunini qo'shib qo'yishi mumkin.

Bu so'rovni ajratish (request smuggling) deb ataladi.

Shuning uchun uzunlikni qo'lda hisoblamang - har doim len() dan oling.

Usullar #

UsulNima qiladiXavfsizmiTakrorlansa
GETO'qiydiHaZarar yo'q
HEADFaqat sarlavhalarni o'qiydiHaZarar yo'q
POSTYangi narsa yaratadiYo'qTakrorlanadi
PUTTo'liq almashtiradiYo'qZarar yo'q
PATCHQisman o'zgartiradiYo'qBog'liq
DELETEO'chiradiYo'qZarar yo'q

Ikkita muhim tushuncha bor:

  • Xavfsiz (safe) - hech narsani o'zgartirmaydi.
  • Takrorlansa zarar yo'q (idempotent) - bir marta ham, o'n marta ham natija bir xil.

POST ikkalasi ham emas. Aynan shuning uchun brauzer sahifani yangilashda "formani qayta yuborasizmi?" deb so'raydi - u ikkinchi buyurtma yaratib yuborishi mumkin.

Holat kodlari #

SinfMa'nosiEng ko'p uchraydiganlari
1xxMa'lumot101 Switching Protocols
2xxMuvaffaqiyat200 OK, 201 Created, 204 No Content
3xxYo'naltirish301, 302, 304 Not Modified
4xxMijoz xatosi400, 401, 403, 404, 429
5xxServer xatosi500, 502, 503, 504
Eng ko'p chalkashtiriladigan juftliklar
JuftlikFarqi
401 va 403401 - "kimligingizni bilmayman", 403 - "bilaman, lekin ruxsat yo'q"
301 va 302301 - doimiy (brauzer keshlaydi), 302 - vaqtinchalik
500 va 502500 - ilova qulagan, 502 - proksi orqadagi serverdan javob ololmadi
404 va 410404 - topilmadi, 410 - bor edi, o'chirilgan

301 bilan ehtiyot bo'ling: brauzer uni uzoq muddat keshlaydi va xato yo'naltirishni orqaga qaytarish qiyin bo'ladi. Shubha bo'lsa, avval 302 dan boshlang.

Amaliy topshiriq
  1. So'rov tahlili misolini ishga tushiring.
  2. Unga Accept-Encoding: gzip sarlavhasini qo'shing.
  3. \r\n ni \n ga almashtiring - tahlil qanday buzildi?
  4. Xom soket misolini ishga tushiring.
  5. Serverni 404 Not Found qaytaradigan qiling.
  6. So'ralgan yo'lga qarab ikki xil javob bering.
  7. Javobni tahlil qilish misolini ishga tushiring.
  8. Content-Length ni ataylab 10 ga o'zgartiring va natijani izohlang.
  9. curl -v bilan biror saytga murojaat qiling va sarlavhalarni o'qing.
  10. 401 va 403 farqini o'z so'zlaringiz bilan yozing.

Xulosa #

  • HTTP - matnli protokol, so'rovni qo'lda yozish mumkin.
  • So'rov: so'rov qatori, sarlavhalar, bo'sh qator, tana.
  • Javob: holat qatori, sarlavhalar, bo'sh qator, tana.
  • Qator oxiri \r\n bo'lishi kerak.
  • Host sarlavhasi HTTP/1.1 da majburiy - virtual xosting shunga tayanadi.
  • Sarlavha nomlari katta-kichiklikka sezgir emas.
  • Content-Length TCP oqimida xabar chegarasini belgilaydi.
  • Noto'g'ri Content-Length so'rovni ajratish zaifligiga olib keladi.
  • GET va HEAD - xavfsiz; POST takrorlansa yangi yozuv yaratadi.
  • Holat kodlari sinflari: 2xx muvaffaqiyat, 3xx yo'naltirish, 4xx mijoz, 5xx server.

Keyingi bo'limda HTTP ning yangi versiyalarini va ular qanday muammolarni yechganini ko'ramiz.

Xatolik topdingizmi?

Imlo xatosi, ishlamaydigan kod yoki noto‘g‘ri ma‘lumotni ko‘rsangiz - bizga xabar bering. Har bir xabar administrator tomonidan ko‘rib chiqiladi.