আজকাল প্রায় সকল ওয়েব ডেভেলপমেন্ট ফ্রেমওয়ার্কের মাধ্যমে হয়। আপনি Rails, Sinatra বা Lotus যেকোনো ব্যবহার করুন, কুকি এবং অন্যান্য হেডার কীভাবে Nginx বা Apache থেকে অ্যাপ্লিকেশন সার্ভারের মাধ্যমে আপনার অ্যাপে যায় সেটি নিয়ে চিন্তা করতে হয় না। সেগুলো স্বয়ংক্রিয়ভাবে ঘটে।
আমরা এই যাত্রাটি কিছুটা গভীরে যাব। কারণ হেডারগুলির গল্পে ওয়েবের ইতিহাস সম্পর্কে অনেক रोचক তথ্য লুকিয়ে আছে।
HTTP হেডার আসলে কী?
যখন কোনো ওয়েব ব্রাউজার রিকোয়েস্ট পাঠায়, তখন সেটি সাথে HTTP হেডারও পাঠায়। এগুলিতে কুকি, ইউজার এজেন্টের তথ্য, ক্যাশিং ইনফো — এরকম অনেক গুরুত্বপূর্ণ জিনিস থাকে।
আপনি ব্রাউজারের ডেভেলপমেন্ট টুলসে রিকোয়েস্ট দেখে বুঝতে পারেন কোন হেডারগুলো পাঠানো হচ্ছে। এখানে একটি উদাহরণ দেওয়া হল। আপনি দেখতে পাচ্ছেন, হেডারগুলো কিছু জাদু নন। সেগুলো কেবল নির্দিষ্ট ফরম্যাটে সাজানো টেক্সট।

হেডার আপনার অ্যাপে কীভাবে পাস হয় না
আপনি যদি কখনো Rack অ্যাপ লিখে থাকেন, তাহলে env হ্যাশটি অবশ্যই দেখেছেন होंगे, যাতে অ্যাপের এনভায়রনমেন্ট ভেরিয়েবল থাকে। যদি এর ভিতর ঝাঁকেন, তবে দেখবেন সাধারণ সিস্টেম এনভায়রনমেন্ট ভেরিয়েবলের পাশাপাশি সেটিতে সকল রিকোয়েস্ট হেডারও থাকে।
# config.ru
run lambda { |env| [200, {"Content-Type" => "text/plain"}, [env.inspect]] }
# আউটপুট:
# { "HTTP_HOST"=>"localhost:9000", "HTTP_CONNECTION"=>"keep-alive", "HTTP_PRAGMA"=>"no-cache", "HTTP_CACHE_CONTROL"=>"no-cache", "HTTP_ACCEPT"=>"text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8", "HTTP_UPGRADE_INSECURE_REQUESTS"=>"1", "HTTP_USER_AGENT"=>"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/47.0.2526.106 Safari/537.36", ... }
এটি নहीं হল Nginx হেডার আপনার অ্যাপে পাস করার পদ্ধতি। :)
অ্যাপ্লিকেশন সার্ভার
আজকাল অধিকাংশ Ruby ওয়েব অ্যাপ Unicornের মতো অ্যাপ্লিকেশন সার্ভারে চলে। যেহেতু অ্যাপ সার্ভারগুলো Nginx দ্বারা স্পান করা হয় না, তাই Nginx তাদের এনভায়রনমেন্ট ভেরিয়েবল সেট করতে পারে না।
তবে হেডারগুলো Nginx থেকে Unicorn-এ কীভাবে যায়? সহজ। যখন Nginx রিকোয়েস্টটি অ্যাপ সার্ভারে ফরওয়ার্ড করে, তবে সেটি পুরো রিকোয়েস্টটিই — হেডারসহ — পাঠায়।
এটি প্রদর্শন করার জন্য আমি একটি সাধারণ অ্যাপ্লিকেশন সার্ভার বানিয়েছি যা Nginx যা পাঠায় সেটি STDOUT-এ ডাম্প করে।
require "socket"
# সকেট তৈরি করে ফাইল সিস্টেমে সংরক্ষণ
server = UNIXServer.new('/tmp/socktest.sock')
# Nginx-এর কানেকশনের জন্য অপেক্ষা
socket = server.accept
# সকেট থেকে সব কিছু পড়া
while line = socket.readline
puts line.inspect
end
socket.close
আপনি যদি Unicorn-এর বদলে এই সার্ভারের সাথে Nginx কনফিগার করুন, তবে আপনি সঠিকভাবে দেখতে পাবেন অ্যাপ সার্ভারে কী তথ্য পাঠানো হচ্ছে: সাধারণ একটি HTTP রিকোয়েস্ট। হেডারসহ।

সিম্পল আপস্ট্রিম অ্যাপ সার্ভার লিখার বিষয়ে আরও জানতে আমার ইউনিক্স সকেট নিয়ে পোস্টটি দেখুন।
তবে এনভায়রনমেন্ট ভেরিয়েবলের ঝামেলা কেন?
১৯৯৩ সালে NSCA একটি স্পেসিফিকেশন প্রকাশ করেছিল যা বলা जाता Common Gateway Interface বা সংক্ষেপে CGI।

এটি Apache-এর মতো সার্ভারগুলোর জন্য ডিস্কে থাকা যেকোনো প্রোগ্রাম চালিয়ে ডাইনামিক ওয়েবপেজ তৈরি করার একটি পদ্ধতি ছিল। ইউজার পেজ রিকোয়েস্ট করলে, Apache শেল আউট করে একটি প্রোগ্রাম চালাত এবং ফলাফল তৈরি করত। যেহেতু Apache সরাসরি অ্যাপগুলো স্পান করত, তাই সেটি তাদের এনভায়রনমেন্ট ভেরিয়েবল সেট করতে পারত।
CGI стандар বলে, HTTP হেডারগুলো এনভায়রনমেন্ট ভেরিয়েবল হিসেবে পাস করা উচিত। এবং বিদ্যমান এনভায়রনমেন্ট ভেরিয়েবলগুলির সাথে নামের সংঘর্ষ এড়াতে, এটি নির্দিষ্ট করে যে নামের আগে "HTTP_" যুক্ত করতে হবে।
ফলস্বরূপ আপনি এরকম এনভায়রনমেন্ট ভেরিয়েবল পাবেন:
HTTP_ACCEPT="text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8"
HTTP_ACCEPT_CHARSET="ISO-8859-1,utf-8;q=0.7,*;q=0.7"
HTTP_ACCEPT_ENCODING="gzip, deflate"
HTTP_ACCEPT_LANGUAGE="en-us,en;q=0.5"
HTTP_CONNECTION="keep-alive"
HTTP_HOST="example.com"
HTTP_USER_AGENT="Mozilla/5.0 (Windows NT 6.1; WOW64; rv:5.0) Gecko/20100101 Firefox/5.0"
আজকাল নতুন ডেভেলপমেন্টে কেউ CGI ব্যবহার করে না, কিন্তু HTTP হেডার এনভায়রনমেন্ট ভেরিয়েবল হিসেবে সংরক্ষণ করা এখনও খুব সাধারণ — এমনকি иногда সেগুলো নকল এনভায়রনমেন্ট ভেরিয়েবল হোক।
অ্যাপ সার্ভার কীভাবে এটি নকল করে
অ্যাপ্লিকেশন সার্ভার কাঁচা HTTP রিকোয়েস্ট থেকে হেডারগুলো পার্স করে। তবে সেগুলো এনভায়রনমেন্টে কীভাবে যায়? আসলে অ্যাপ সার্ভার সেগুলো সেখানে রাখে।
আমি WEBrick-এ কিছু খুঁজে বের করতে পারলাম:
self.each{|key, val|
next if /^content-type$/i =~ key
next if /^content-length$/i =~ key
name = "HTTP_" + key
name.gsub!(/-/o, "_")
name.upcase!
meta[name] = val
}
শেষে এই "নকল" এনভায়রনমেন্ট ভেরিয়েবলগুলো অন্যান্য অধিক বাস্তব এনভায়রনমেন্ট ভেরিয়েবলগুলির সাথে মার্জ হয়ে আপনার Rack অ্যাপে এবং তারপর Rails-এ যায়, যা সেগুলো আবার এনভায়রনমেন্ট হ্যাশ থেকে বের করে নেয়। :)