Computer >> कंप्यूटर >  >> प्रोग्रामिंग >> Ruby

रूबी के साथ अपना खुद का वेब सर्वर बनाएं

क्या आपने कभी रूबी के साथ अपना स्वयं का वेब सर्वर बनाया है?

हमारे पास पहले से ही कई सर्वर हैं, जैसे:

  • प्यूमा
  • पतला
  • गेंडा

लेकिन मुझे लगता है कि यह सीखने का एक अच्छा अभ्यास . है यदि आप जानना चाहते हैं कि एक साधारण वेब सर्वर कैसे काम करता है।

इस लेख में, आप सीखेंगे कि यह कैसे करना है।

चरण-दर-चरण!

चरण 1:कनेक्शन के लिए सुनना

हम कहाँ से शुरू करें?

सबसे पहले हमें टीसीपी पोर्ट 80 पर नए कनेक्शन सुनने की जरूरत है।

मैंने पहले ही रूबी में नेटवर्क प्रोग्रामिंग के बारे में एक पोस्ट लिखी है, इसलिए मैं यह नहीं बताऊंगा कि यह कैसे काम करता है।

मैं आपको केवल कोड देने जा रहा हूं :

require 'socket'

server  = TCPServer.new('localhost', 80)

loop {
  client  = server.accept
  request = client.readpartial(2048)

  puts request
}

जब आप इस कोड को चलाते हैं तो आपके पास एक सर्वर होगा जो पोर्ट 80 पर कनेक्शन स्वीकार करता है। यह अभी तक बहुत कुछ नहीं करता है, लेकिन यह आपको यह देखने की अनुमति देगा कि आने वाला अनुरोध कैसा दिखता है।

<ब्लॉकक्वॉट>

नोट :Linux/Mac सिस्टम में पोर्ट 80 का उपयोग करने के लिए आपको रूट विशेषाधिकारों की आवश्यकता होगी। एक विकल्प के रूप में, आप 1024 से ऊपर के किसी अन्य पोर्ट का उपयोग कर सकते हैं। मुझे 8080

. पसंद है

अनुरोध उत्पन्न करने का एक आसान तरीका है कि आप अपने ब्राउज़र या curl . जैसी किसी चीज़ का उपयोग करें ।

जब आप ऐसा करेंगे तो आप देखेंगे कि यह आपके सर्वर में छपा हुआ है:

GET / HTTP/1.1
Host: localhost
User-Agent: curl/7.49.1
Accept: */*

यह एक HTTP अनुरोध है। HTTP एक सादा पाठ प्रोटोकॉल है जिसका उपयोग वेब ब्राउज़र और वेब सर्वर के बीच संचार के लिए किया जाता है।

आधिकारिक प्रोटोकॉल विनिर्देश यहां पाया जा सकता है:https://tools.ietf.org/html/rfc7230।

चरण 2:अनुरोध को पार्स करना

अब हमें अनुरोध को छोटे घटकों में विभाजित करने की आवश्यकता है जिसे हमारा सर्वर समझ सकता है।

ऐसा करने के लिए हम अपना खुद का पार्सर बना सकते हैं या पहले से मौजूद एक का उपयोग कर सकते हैं। हम अपना स्वयं का निर्माण करने जा रहे हैं, इसलिए हमें यह समझने की आवश्यकता है कि अनुरोध के विभिन्न भागों का क्या अर्थ है।

इस छवि को मदद करनी चाहिए :

रूबी के साथ अपना खुद का वेब सर्वर बनाएं

अनुरोध प्राप्त करें

हेडर का उपयोग ब्राउज़र कैशिंग, वर्चुअल होस्टिंग और डेटा कम्प्रेशन जैसी चीज़ों के लिए किया जाता है, लेकिन एक बुनियादी कार्यान्वयन के लिए हम उन्हें अनदेखा कर सकते हैं और अभी भी एक कार्यात्मक सर्वर है।

एक साधारण HTTP पार्सर बनाने के लिए हम इस तथ्य का लाभ उठा सकते हैं कि अनुरोध डेटा को नई लाइनों (\r\n के माध्यम से अलग किया जाता है। ) हम चीजों को सरल रखने के लिए कोई त्रुटि या वैधता जाँच नहीं करने जा रहे हैं।

यहाँ वह कोड है जिसके साथ मैं आया था:

def parse(request)
  method, path, version = request.lines[0].split

  {
    path: path,
    method: method,
    headers: parse_headers(request)
  }
end

def parse_headers(request)
  headers = {}

  request.lines[1..-1].each do |line|
    return headers if line == "\r\n"

    header, value = line.split
    header        = normalize(header)

    headers[header] = value
  end

  def normalize(header)
    header.gsub(":", "").downcase.to_sym
  end
end

यह पार्स किए गए अनुरोध डेटा के साथ एक हैश लौटाएगा। अब जब हमारे पास एक प्रयोग करने योग्य प्रारूप में हमारा अनुरोध है तो हम ग्राहक के लिए अपनी प्रतिक्रिया तैयार कर सकते हैं।

चरण 3:प्रतिक्रिया तैयार करना और भेजना

प्रतिक्रिया बनाने के लिए हमें यह देखना होगा कि अनुरोधित संसाधन उपलब्ध है या नहीं। दूसरे शब्दों में, हमें यह जांचना होगा कि फ़ाइल मौजूद है या नहीं।

ऐसा करने के लिए मैंने जो कोड लिखा है वह यहां दिया गया है:

SERVER_ROOT = "/tmp/web-server/"

def prepare_response(request)
  if request.fetch(:path) == "/"
    respond_with(SERVER_ROOT + "index.html")
  else
    respond_with(SERVER_ROOT + request.fetch(:path))
  end
end

def respond_with(path)
  if File.exists?(path)
    send_ok_response(File.binread(path))
  else
    send_file_not_found
  end
end

यहां दो चीजें हो रही हैं :

  • सबसे पहले, यदि पथ / पर सेट है हम मानते हैं कि हमें जो फ़ाइल चाहिए वह है index.html
  • दूसरा, यदि अनुरोधित फ़ाइल मिलती है, तो हम फ़ाइल सामग्री को ठीक प्रतिक्रिया के साथ भेजने जा रहे हैं।

लेकिन अगर फाइल नहीं मिलती है तो हम ठेठ 404 Not Found . भेजने जा रहे हैं प्रतिक्रिया।

सबसे सामान्य HTTP प्रतिक्रिया कोड की तालिका

संदर्भ के लिए।

Code विवरण
200 ठीक
301 स्थायी रूप से स्थानांतरित हो गया
302 मिला
304 संशोधित नहीं
400 खराब अनुरोध
401 अनधिकृत
403 वर्जित
404 नहीं मिला
500 आंतरिक सर्वर त्रुटि
502 खराब गेटवे

प्रतिक्रिया वर्ग और तरीके

पिछले उदाहरण में उपयोग की गई "भेजें" विधियां यहां दी गई हैं:

def send_ok_response(data)
  Response.new(code: 200, data: data)
end

def send_file_not_found
  Response.new(code: 404)
end

और यहाँ Response है कक्षा:

class Response
  attr_reader :code

  def initialize(code:, data: "")
    @response =
    "HTTP/1.1 #{code}\r\n" +
    "Content-Length: #{data.size}\r\n" +
    "\r\n" +
    "#{data}\r\n"

    @code = code
  end

  def send(client)
    client.write(@response)
  end
end

प्रतिक्रिया एक टेम्पलेट और कुछ स्ट्रिंग इंटरपोलेशन से बनाई गई है।

इस बिंदु पर हमें बस अपने कनेक्शन-स्वीकार करने वाले loop . में सब कुछ एक साथ जोड़ने की जरूरत है और फिर हमारे पास एक कार्यात्मक सर्वर होना चाहिए।

loop {
  client  = server.accept
  request = client.readpartial(2048)

  request  = RequestParser.new.parse(request)
  response = ResponsePreparer.new.prepare(request)

  puts "#{client.peeraddr[3]} #{request.fetch(:path)} - #{response.code}"

  response.send(client)
  client.close
}

SERVER_ROOT . के अंतर्गत कुछ HTML फ़ाइलें जोड़ने का प्रयास करें निर्देशिका और आप उन्हें अपने ब्राउज़र से लोड करने में सक्षम होना चाहिए। यह छवियों सहित किसी भी अन्य स्थिर संपत्ति की भी सेवा करेगा।

बेशक एक वास्तविक वेब-सर्वर में कई और विशेषताएं होती हैं जिन्हें हमने यहां शामिल नहीं किया।

यहां कुछ . की सूची दी गई है गायब सुविधाओं में से, ताकि आप उन्हें एक अभ्यास के रूप में अपने दम पर लागू कर सकें (अभ्यास कौशल की जननी है!):

  • वर्चुअल होस्टिंग
  • माइम प्रकार
  • डेटा संपीड़न
  • पहुंच नियंत्रण
  • मल्टी-थ्रेडिंग
  • सत्यापन का अनुरोध करें
  • क्वेरी स्ट्रिंग पार्सिंग
  • पोस्ट बॉडी पार्सिंग
  • ब्राउज़र कैशिंग (प्रतिक्रिया कोड 304)
  • रीडायरेक्ट

सुरक्षा पर एक पाठ

किसी यूजर से इनपुट लेना और उसके साथ कुछ करना हमेशा खतरनाक होता है। हमारे छोटे से वेब सर्वर प्रोजेक्ट में, उपयोगकर्ता इनपुट HTTP अनुरोध है।

हमने एक छोटी सी भेद्यता पेश की है जिसे "पथ ट्रैवर्सल" के रूप में जाना जाता है। लोग किसी भी फाइल को पढ़ने में सक्षम होंगे जिस तक हमारे वेब सर्वर उपयोगकर्ता की पहुंच है, भले ही वे हमारे SERVER_ROOT से बाहर हों। निर्देशिका।

यह इस मुद्दे के लिए जिम्मेदार लाइन है:

File.binread(path)

आप इस मुद्दे को कार्रवाई में देखने के लिए स्वयं इसका फायदा उठाने का प्रयास कर सकते हैं। आपको "मैन्युअल" HTTP अनुरोध करने की आवश्यकता होगी, क्योंकि अधिकांश HTTP क्लाइंट (curl . सहित) ) आपके URL को पूर्व-संसाधित करेगा और भेद्यता को ट्रिगर करने वाले हिस्से को हटा देगा।

एक उपकरण जिसका आप उपयोग कर सकते हैं उसे नेटकैट कहा जाता है।

यहाँ एक संभावित शोषण है:

$ nc localhost 8080
GET ../../etc/passwd HTTP/1.1

यह /etc/passwd की सामग्री लौटाएगा फ़ाइल यदि आप यूनिक्स-आधारित सिस्टम पर हैं। इसके काम करने का कारण यह है कि एक डबल डॉट (.. .) ) आपको एक निर्देशिका ऊपर जाने की अनुमति देता है, इसलिए आप SERVER_ROOT से "बच" रहे हैं निर्देशिका।

एक संभावित समाधान एक में कई बिंदुओं को "संपीड़ित" करना है:

path.gsub!(/\.+/, ".")

सुरक्षा के बारे में सोचते समय हमेशा अपनी "हैकर टोपी" लगाएं और अपने समाधान को तोड़ने के तरीके खोजने का प्रयास करें। उदाहरण के लिए, यदि आपने अभी-अभी path.gsub!("..", ".") किया है , आप ट्रिपल डॉट्स (... . का उपयोग करके इसे बायपास कर सकते हैं )।

समाप्त और कार्य कोड

मुझे पता है कि इस पोस्ट में कोड हर जगह है, इसलिए यदि आप समाप्त, कार्यशील कोड की तलाश कर रहे हैं…

यहां लिंक है :

https://gist.github.com/matugm/efe0a1c4fc53310f7ac93dcd1f041f6c#file-web-server-rb

आनंद लें!

सारांश

इस पोस्ट में, आपने सीखा कि नए कनेक्शन कैसे सुनें, HTTP अनुरोध कैसा दिखता है और इसे कैसे पार्स करना है। आपने यह भी सीखा कि प्रतिक्रिया कोड और आवश्यक फ़ाइल की सामग्री (यदि उपलब्ध हो) का उपयोग करके प्रतिक्रिया कैसे बनाई जाती है।

और अंत में आपने "पाथ ट्रैवर्सल" भेद्यता और इससे बचने के तरीके के बारे में सीखा।

मुझे आशा है कि आपको यह पोस्ट अच्छी लगी होगी और कुछ नया सीखा होगा! नीचे दिए गए फॉर्म पर मेरे न्यूज़लेटर की सदस्यता लेना न भूलें, ताकि आप एक भी पोस्ट मिस न करें 🙂


  1. रूबी के साथ कमांड-लाइन एप्लिकेशन (सीएलआई) कैसे बनाएं?

    बहुत से लोग भूल जाते हैं कि रूबी ऐसे काम कर सकती है जो वेब एप्लिकेशन नहीं हैं। इस लेख में, मैं आपको दिखाना चाहता हूं कि इसका समाधान करने में मदद के लिए एक कमांड-लाइन एप्लिकेशन कैसे बनाया जाए! यहां कुछ कमांड-लाइन एप्लिकेशन दिए गए हैं जिनसे आप परिचित हो सकते हैं: psql rails bundler gem git कम

  1. रूबी के साथ एक पार्सर कैसे बनाएं

    पार्सिंग स्ट्रिंग्स के एक गुच्छा को समझने और उन्हें किसी ऐसी चीज़ में बदलने की कला है जिसे हम समझ सकते हैं। आप रेगुलर एक्सप्रेशन का उपयोग कर सकते हैं, लेकिन वे हमेशा कार्य के लिए उपयुक्त नहीं होते हैं। उदाहरण के लिए, यह सामान्य ज्ञान है कि नियमित अभिव्यक्तियों के साथ HTML को पार्स करना शायद एक अच्छ

  1. मंगलवार टिप्स:Plex सर्वर के साथ अपना खुद का Spotify बनाएं

    जब से Apple ने खरीदा और लाला को मार डाला, मैंने अंतर को बंद करने के लिए Spotify और अन्य स्ट्रीमिंग सेवाओं का उपयोग किया है। लेकिन मेरे पास बहुत सारा संगीत है जो कहीं भी स्ट्रीमिंग के लिए उपलब्ध नहीं है (जब तक कि आप खराब एन्कोडेड YouTube संस्करणों की गणना नहीं करते हैं) जिसे मैं अपने सभी उपकरणों पर स