CodeCrafters
774 subscribers
90 photos
50 videos
42 files
170 links
Download Telegram
در این مجموعه پست‌ها، می‌خواهیم کتاب http guideline را مطالعه کنیم و نکات آن را خلاصه نویسی کرده و به اشتراک بگذاریم.
این کتاب به شما دید خوبی درمورد http می‌دهد و با خواندن این کتاب میتوانید درک خوبی از مسائل مربوط به این پروتکل و اپلیکیشن‌های تحت وب به دست آورید.
این مجموعه پست ها را با هشتگ
#http_guideline
می‌توانید در کانال دنبال کنید.


کتاب در ابتدا خیلی ساده و کوتاه شروع شده و در فصل‌های بعدی هر بخش از فصل قبل را بازتر کرده و به جزئیات موارد می پردازد

در این پیام می‌خواهیم درمورد ssl certificate صحبت کنیم.
چگونه سرور‌ها هویت خود را ثابت می‌کنند؟

در پروتکل HTTP اطلاعات رمزگذاری نمی‌شوند.
درواقع یک connection به پورت ۸۰ سرور ایجاد می‌شود و یک request message از سمت کاربر ارسال می‌شود و یک response message از سوی سرور دریافت می‌شود و در نهایت این کانکشن بسته می‌شود.

این flow برای انتقال اطلاعات حساس همچون اطلاعات بانکی اصلأ مناسب نیست، چرا که هرکسی می‌تواند message ها را باز کند و اطلاعات آن را استخراج کند.

برای جلوگیری از این اتفاق HTTPS ظهور کرد!
درواقع HTTPS همان HTTP است، با این تفاوت که در این پروتوکل یک لایهٔ امنیتی نیز اضافه شده است.

اکنون flow مقداری پیچیده می‌شود!
کاربر یک connection به پورت ۴۴۳ ایجاد می‌کند. هنگامی که سرور کانکشن را قبول کرد، ssl initialization انجام می‌شود.
در این مرحله پارامتر های رمزنگاری توسط client و server جابجا می‌شود. هنگامی که این handshake انجام شد، اطلاعات ابتدا به لایهٔ ssl ارسال و رمزنگاری می‌شود و سپس به سمت کلاینت/سرور ارسال می‌شود.

در مرحله ssl handshake اطلاعات زیر توسط کلاینت و سرور جابجا می‌شود:
- ورژن پروتوکل http
- یک کلید برای رمزنگاری
- یک session key موقت برای رمزنگاری شبکه
- اطلاعات هویتی سرور (certificate)

بیاید و یکم certificate رو باز کنیم!
درواقع certificate یک فایلی است که سرور برای اثبات هویت خود، به کلاینت ارسال می‌کند. این سرتیفیکیت برای اینکه اعتبار خود را نشان دهد، از پیش توسط یک Certificate authority امضا شده است.

این فایل شامل اطلاعات زیر می‌باشد:
- Public key
- Hostname of website
- Name of signing authority
- Signature of signing authority

هنگامی که این فایل توسط کلاینت دریافت می‌شود، مرورگر به صورت اتوماتیک ولیدیشن هایی را روی این فایل انجام می‌دهد. برای مثال:
۱- ابتدا تاریخ certificate بررسی می‌شود که منقضی نشده باشد
۲- امضای signature مورد بررسی قرار می‌گیرد تا مطمئن شویم authority قابل اعتمادی این certificate را امضا کرده.
۳- در این مرحله با authorities public key سیگنیچر را مقایسه می‌کنند تا مطمئن شوند CA واقعاً این certificate را امضا کرده.
۴- برای اطمینان از اینکه این certificate تنها برای این سرور است، domain سرور را با دامین سرتیفیکیت مقایسه می‌کنیم.


کاری از بچه‌های گروه منتوری

@code_crafters
7👍6
یک اتصال امن با HTTPS

پیش‌تر آموختیم که ssl یک لایه رمزگذاری است که با رمزنگاری کردن پیام‌ها، امنیت اطلاعاتمان را در شبکه تضمین می‌کند.

تا زمانی که شما تبدیل به یک متخصص در زمینه ارز ها نشدید، نیاز نیست بدانید چگونه می‌توانید با raw ssl پیام‌های خود را جابجا کنید؛ چرا که کتابخانه‌های مختلفی وجود دارد تا بتوانید ssl program های خود را توسعه دهید!

برای مثال یکی از معروف‌ترین آن‌ها، OpenSsl است.

بیایید و ببینیم چگونه می‌توانیم به کمک ssl, پیام‌های خود را رمزنگاری و ارسال کنیم.

تصور کنید می‌خواهید یک پیام از کامپیوتر خود به یک سرور در آمریکا ارسال کنید.

۱- کامپیوتر شما یک local context می‌سازد و تمام اطلاعات handshake را با فراخوانی SSL_CTX آماده می‌کند.
۲- دامنهٔ سرور مقصد را به ip تبدیل می‌کند
۳- یک اتصال به پورت ۴۴۳ مقصد ایجاد می‌کند که نیازمند ساخت یک local socket است.
۴- هنگامی که اتصال برقرار شد، می‌توانیم لایهٔ ssl را به اتصال TCP خود وصل کنیم..
۵- سرور certificate خود را ارسال می‌کند و با کامپیوتر شما یک کلید رمزنگاری ارسال می‌کند
۶- تمامی اطلاعات با کلیدی که در مرحله ۵ ارسال شده بود، رمزنگاری و رمزگشایی می‌شود!

اما آیا این تنها راه است؟ جواب به این سوال، خیر است.

ما میتوانیم به واسطهٔ یک proxy server نیز، به صورت امن اطلاعات خود را جابجا کنیم.

به صورت ساده، این ارتباط به صورت زیر است:

«لوکال -> سرور پروکسی -> مقصد»

اما یک مشکلی داریم!
ما می‌دانیم که برای رمزنگاری، از public key سرور مقصد استفاده می‌کنیم.
اینجا اگر اطلاعات را به پروکسی سرور دهیم، باید آن را بازگشایی و مجدد رمزنگاری کند و به سرور ارسال کند. این مسلما چیزی نیست که ما می‌خواهیم.

اینجا باید به گونه‌ای با سرور پروکسی صحبت کنیم که بداند می‌خواهیم از آن به عنوان یک middle man استفاده کنیم.

برای این‌کار از پروتکل HTTPS SSL TUNNELING استفاده می‌کنیم!

ابتدا به سرور پروکسی، یک درخواست با پروتکل مخصوص CONNECT می‌زنیم.
در payload آدرس سرور مقصد را می‌دهیم.

هنگامی که سرور این پیام را دریافت کرد، تمامی پیام‌های کلاینت را به سمت سرور ارسال می‌کند و جواب را به کلاینت برمی‌گرداند.

#http_guideline
@code_crafters
8😁1
انتیتی (entity) و انکدینگ (encoding)

می‌دانیم که http روزانه میلیارد‌ها آبجکت از هر نوع اطلاعاتی (مانند عکس، فیلم، متن و...) را جابجا می‌کند؛
اما ارسال پیام برای ما کافی نیست!
ما باید مطمئن شویم که این پیام‌ها کاملا ارسال شده‌اند، identify شده‌اند، استخراج و پراسس شده اند.

برای اینکه اطلاعاتمان را به شیوه صحیح ارسال کنیم، می‌بایستی از header های درستی استفاده کنیم.

قبل از اینکه بدانیم هدر ها کجا ست می‌شوند، بیایید یک نگاهی مختصر به ساختار http message داشته باشیم:

هر http message می‌تواند یا برای request باشد و یا برای response.
این پیام‌ها از سه بخش تشکیل شده‌اند:

۱- در این بخش ما ریسورس خود را مشخص می‌کنیم.
برای ریکوئست: url و host را به همراه method در این بخش ست میکنیم.
مثال:
GET google.com/random/path

برای ریسپانس: تنها جواب از سوی سرور را در اینجا ست می‌کنیم
404 google.com/random/path

۲- در این بخش هدرهای خود را ست میکنیم. هدر ها برای ریکوئست و ریسپانس گاهی متفاوت است.
برای ریکوئست، می‌گوییم: «من انتظار یک ایمیج را دارم» اما برای ریسپانس می‌گوییم «در این پیام برایت یک ایمیج را فرستادم».

۳- این بخش، بخش بدنه است. تنها در ریسپانس، در این بخش اطلاعات را می‌گذاریم.


* درواقع http headers یک plain text از هدر ها هستند که در لایه دوم http message قرار می‌گیرند.

در این بخش به مرور چند هدر معروف می‌پردازیم:

1- Content-type:
این هدر، نشان میدهد که شما در بخش body، انتظار چه اطلاعاتی را خواهید داشت.
برای مثال، هنگامی که شما یک متن را باز می‌کنید، content-type از سمت سرور مقصد به مقدار text/plain ست می‌شود.

2- content length
پیش از اینکه body را از یک http message استخراج کنیم، می‌بایستی بدانیم که چه انتظاری از بدنه خواهیم داشت.
برای مثال انتظار یک عکس با حجم ۲ مگابایت را داریم. پس در این هدر، ما حجم content را ست می‌کنیم.

3- content encoding
گاهی برای امنیت بیشتر و یا کم کردن حجم، ما اطلاعات یک پیام را encode می‌کنیم. در این هدر، به مقصد می‌فهمانیم که پیام از قبل با این الگوریتم encode شده، پس برای خواندن آن، آن را decode کنید.

#http_guideline
@code_crafters
5
Http Internationalization

روزانه میلیاردها انسان در جهان document هایی را به زبان‌های مختلفی در اینترنت به اشتراک می‌گذارند. همانطور که از اسم world-wide web مشخص است, این شبکه برای تمام افراد جهان با هر زبانی است. پس باید راهی باشد که بتوانیم به نوعی تمامی این اطلاعات را منتقل کنیم

هرگاه یک درخواستی ارسال می‌شود, یک هدر accept-language نیز با آن ارسال می‌شود. با این هدر کلاینت به سرور می‌گوید که من انتظار دارم پیامی که دریافت می‌کنم, زبانش این باشد.

پس از اینکه سرور با توجه به این هدر ریسپانس را فراهم و ارسال کرد, در آن یک هدر به نام content-language ارسال می‌کند. اینگونه کلاینت می‌تواند با استفاده از آن محتوای پیام را باز کرده و از ان استفاده کند.

اما چگونه این اطلاعات باینری تبدیل به متون قابل خواندن می‌شود؟ برای درک این موضوع ابتدا باید به مفهوم Charset ها بپردازیم.

درواقع این charset ها هستند که می‌گویند این مقدار باینری را به کدام یک از کاراکتر های کدام زبان وصل کنیم.

هنگامی که ریسپانس را دریافت می‌کنیم, در هدر content-type یک charset نیز ثبت شده است.
مثال:
Content-Type: text/html; charset=iso-8859-6

این به این معنی است که داده ما به صورت ۸ بیتی map می‌شود (که احتمالا یا لاتین است یا عربی!)

حالا کار این character set ها چیست؟
کرکتر ست ها درواقع دو کار را انجام می‌دهند.
۱- تبدیل باینری به کد کاراکتر
۲- تبدیل کد کاراکتر به کلمه

برای مثال ما می‌خواهیم به کمک کرکتر ست ها مقدار زیر را به کاراکتر تبدیل کنیم.

11100001
ابتدا این را به کاراکتر کد ۲۲۵ تبدیل می‌‌کنیم و سپس کد ۲۲۵ را به کلمه اصلی خود مپ می‌کنیم که درواقع کاراکتر «ف» است.
پس:
11100001 -> 225 -> ف

حالا که متوجه شدیم تمامی این کارها را کرکتر ست ها انجام می‌دهند, پس چرا هدر content-language ارسال می‌کنیم؟

کاراکتر ست ها صرفا الگوریتم هایی هستند که صرفا بر اساس زبان, می‌توانند کد ها را به کلمات مپ کنند.
برای مثال کرکتر کد ۲۲۵ در زبان‌های مختلف شکل های مختلفی دارد.
در زبان لاتین a و در زبان عربی «ف» است و در زبان یونانی «الفا».

به عنوان نکته پایانی باید درنظر داشت که کاراکتر‌ها می‌توانند فرم‌های گوناگونی داشته باشند.
برای مثال کاراکتر «ع» می‌تواند گاهی «عـ» نیز باشد.
اینجا نیاز است که مفهوم glyph را درک کنیم.

هنگامی که کاراکتر کد به یک کاراکتر مپ می‌شود, نوع نشان دادن آن مشخص نمی‌شود. ما صرفا می‌دانیم که 225 عدد کاراکتر «ف» است. حال نمایش دادن این عبارات بر عهده glyph است.
اگر بخواهیم موشکافانه تر به قضیه نگاه کنیم, فرایند تبدیل بصورت زیر خواهد بود:

11100001 -> 225 -> "ARABIT LETTER FEH" -> glyph shows «ف»

#http_guideline
@code_crafters
7
Content Negotiation

تصور کنید که ما یک سایت بین‌المللی داریم که روزانه هزاران درخواست توسط افراد از سرتاسر جهان دریافت می‌کند. همه‌مان می‌دانیم که برای چنین سایت بزرگی نمی‌توانیم صرفا محتوا را به زبان انگلیسی به اشتراک بگذاریم بلکه باید از یک مکانیزم استفاده کنیم تا هر کاربر به زبان کشور خودش محتوا را دریافت کند.

به این موضوع Content Negotiation می‌گوییم.
در این پیام به نحوه تصمیم‌گیری برای انتخاب یک زبان می‌پردازیم.
به طور کلی ما دو روش برای انتخاب زبان داریم:
- Client-driven negotiation
- Server-driven negotiation


اکنون به Client-driven negotiation می‌پردازیم.
در این مکانیزم هنکامی که کاربر به سایت codecrafters.ir درخواست می‌زنند, سرور کد کرفرترز برای کلاینت لیستی از زبان‌‌ها را ارسال می‌کند. اکنون مرورگر می‌تواند تصمیم بگیرد که کدام یک از url ها را باز کرده و به کاربر نشان دهد.
همانطور که متوجه شدید, این روش اصلا مناسب نیست! چرا که باید ۲ برابر ریکوئست ارسال شود و این موضوع latency را به شدت افزایش می‌دهد. پس بهتر است به فکر یک روش دیگری باشیم تا دیگر کلاینت این‌همه درگیر انتخاب زبان نباشد.

برای حل این موضوع Server-side negotiation بوجود آمد.
وب‌سرور به ۲ روش تصمیم می‌گیرد که کدام یک از زبان‌ها را انتخاب کند.
۱- استفاده از header هایی مانند Accept-language و Accept-charset.
۲- استفاده از User-agent کاربر.

شاید این سوال برایتان پیش‌ بیاید که چرا مورد دوم را بررسی می‌کنیم.
در جواب این سوال باید بدانیم که گاهی تنها زبان مهم نیست بلکه مهم این است که اطلاعات درست به کاربر نمایش داده شود. تصور کنید که یک وبسایت در صفحاتش از جاوااسکریپت استفاده می‌کند و مرورگر قدیمی ما از جاوا اسکریپت پشتیبانی نمی‌کنید.
پس سرور باید محتوای درستی که از JS استفاده نمی‌کند را با زبان درست برای کاربر ارسال کنید.

گاهی Http اجازه می‌دهد که کاربران یک لیست از انتظارات خود ارسال کنند.
تصور کنید ما می‌خواهیم به سایت codecrafters.ir درخواست بزنیم اما نمی‌دانیم که آیا زبان المانی پشتیبانی می‌شود یا خیر.
پس ما در هدر Accept-language مقدار زیر را ارسال می‌کنیم:

Accept-language: en;q=0.5, fr;q=0.0., du;1.0.

هنگامی که سرور این پیام را دریافت می‌کند, اینگونه برداشت می‌‌کند که محتوا باید المانی باشد, اگر چنین چیزی موجود نبود, انگلیسی نیز می‌پذیرد. اما باید توجه داشته باشد که هیچگاه محتوای فرانسوی ارسال نکند.

گاهی نیز این تصمیمات را بر عهده proxy می‌سپاریم.
این proxy server است که تصمیم می‌گیرد به کدام resource درخواست بزند و اطلاعات لازم را به کاربر ارسال کند.


#http_guideline
@code_crafters
8👍2
Web hosting

در روزهای نخستین WWW هنگامی که مردم می‌خواستند محتوایی را در این شبکه به اشتراک بگذارند, می‌بایستی یک ماشین تهیه می‌کردند و با کانفیگ کردن آن در شبکه, اطلاعات ذخیره شده در آن را برای عموم قابل دستیابی می‌کردند. با گذر زمان و رشد این شبکه, شرکت‌ها متوجه شدند که همه مردم نمی‌توانند یک سرور فیزیکی بخرند و آن را کانفیگ کنند. پس شرکت های web hosting تاسیس شدند.

در این پیام می‌خواهیم به این بپردازیم که این شرکت‌ها دقیقا چه کاری انجام می‌دادند.

Dedicated Hosting:
تصور کنید Joe و Mary هرکدامشان یک سایت فروشگاهی دارند. آنها از یک شرکت به نام Irene’s Isp درخواست می‌کنند تا سایت آن‌ها را host کنند. شرکت پروایدر که در رک خود چند سرور دارد, یکی را به Joe و یکی را به Mary می‌دهد که هرکس دامنه سایت آن‌ها را وارد کرد, شرکت پروایدر تصمیم بگیرد که درخواست را به سمت کدام سرور هدایت کند.


Virtual Hosting:
تا اینجای ماجرا همه چیز خوب بنظر میرسه اما وقتی بحث قیمت سرورا میشه, هیچکس حاضر نیست هزاران دلار برای یک سرور بده که یک سایت ساده رو بیاره بالا!
پرووایدر ها تصمیم گرفتند که بجای اینکه به هر مشتری یک سرور گران بدهند, آن سرور را بخش بخش کنند و چندین سایت را روی آن serve کنند.
در این موقعیت کلی پول و منابع ذخیره می‌شود.
اما این به این معنی نیست که یک سرور چندین سایت را serve می‌کند. بلکه ممکن است replication انجام بشود و ترافیک این سایت ها بین چندین سرور پخش شود!


برسی یکی از مشکلات Virtual hosting:
تصور کنید دو سایت را روی یک سرور serve می‌کنیم.
a.com/index.html
b.com/index.html
برای دسترسی به این ریسورس‌‌ها یک ریکوئست مانند ریکوئست زیر ساخته و ارسال می‌شود:
GET /index.html HTTP/1.0

ما فقط می‌گوییم که از این host فایل index.html را می‌خواهیم اما سرور نمیداند که فایل را از کدام یکی از سایت های موجود بردارد.

برای حل این مشکل, در HTTP 1.1 تصمیم گرفتند که URL کامل را ارسال کنند تا وب سرور تصمیم بگیرد به کدام اپلیکیشن درخواست را ارسال کند. اما مشکل این‌ است که این تصمیم بعد از توسعه هزاران اپلیکیشن گرفته شد. تکلیف برنامه های قدیمی چیست؟

1- ارسال url کامل
2- ارسال port اپلیکیشن
3- ارسال یک ip که isp آن را به یک اپلیکیشن منتسب کرده.
4- ارسال یک header که مشخص می‌کند به کدام برنامه ارسال شود

موارد ۱ و ۲ و ۴ تا حدودی مشخص است اما مورد سوم نیاز به توضیح بیشتری دارد.
در این روش که بسیار مرسوم است, پرووایدر یک آیپی را به joe می‌دهد که آن را برای سایت خودش استفاده کند. هنگامی که به این ایپی درخواست بزنیم, پرووایدر دقیقا می‌داند که این درخواست برای کدام یک از سرور ها و برای کدام سایت دیپلوی شده روی آن است.


#http_guideline
@code_crafters
6
Redirection - بخش اول

پروتکل HTTP به تنهایی برای تمام نیازهای ارتباطی وب کافی نیست. گاهی اوقات پیام‌های کاربر تا رسیدن به سرور اصلی از مسیرهای مختلفی عبور می‌کنند و بین چندین سرور جابه‌جا می‌شوند. این مسیرهای پیچیده می‌توانند باعث تاخیر یا حتی نرسیدن پیام به مقصد شوند. Redirection یکی از راهکارهایی‌ست که برای بهینه‌سازی این فرایند استفاده می‌شود.

چرا از Redirection استفاده می‌کنیم؟
هدف اصلی Redirection سریع‌تر شدن ترنزکشن‌ها و کاهش زمان انتظار کاربر است. مثلا ممکن است درخواست کاربر به سروری نزدیک‌تر فرستاده شود تا با سرعت بیشتری پاسخ دریافت شود.

ریدایرکشن چگونه انجام می‌شود؟
ریدایرکشن می‌تواند در لایه‌های مختلفی انجام شود.
گاهی مرورگر طوری تنظیم می‌شود که درخواست را به یک پروکسی سرور بفرستد. گاهی هم DNS resolver آدرس یک سرور دیگر را ارائه می‌دهد. حتی در برخی موارد این روترها یا سوییچ‌ها هستند که مسیر پیام را مشخص می‌کنند. گاهی هم خود وب‌سرور تصمیم می‌گیرد پیام را به سرور مناسب‌تری منتقل کند.

HTTP Redirection
یکی از روش‌های رایج برای این موضوع، ارسال HTTP Redirection با کد ۳۰۲ است.
فرض کنید یک Load Balancer دارید که وظیفه‌اش تقسیم درخواست‌ها بین چند سرور است. کاربر A درخواست خود را به لود بالانسر می‌فرستد و پاسخ ۳۰۲ دریافت می‌کند که در آن آدرس سرور مناسب قرار دارد. حالا مرورگر باید درخواست را به این آدرس جدید ارسال کند.
این‌که لود بالانسر بر چه اساسی تصمیم‌گیری می‌کند، موضوعی‌ست که در آینده به آن خواهیم پرداخت.
البته یکی از مشکلات این روش، نیاز به ارسال چند درخواست برای رسیدن به سرور نهایی است که باعث افزایش تاخیر می‌شود.

DNS Redirection
زمانی که کاربر می‌خواهد به سایت codecrafters.ir دسترسی پیدا کند، DNS resolver باید این نام دامنه را به یک IP تبدیل کند. این IP می‌تواند از منابع مختلفی مثل مرورگر، DNS سرور شبکه یا منابع دیگر بیاید.
ما می‌توانیم DNS سرور را طوری تنظیم کنیم که هر بار IP متفاوتی ارائه دهد. این کار می‌تواند به روش ساده‌ای مثل round robin انجام شود یا با تحلیل متریک‌های پیچیده‌تر، تصمیم بهتری بگیرد.

در بخش بعدی به روش‌هایی مثل Anycast Addressing و IP-MAC Forwarding می‌پردازیم.

#http_guideline
@code_crafters
👍8