Предоставление любого объекта Ruby через Интернет - PullRequest
4 голосов
/ 16 ноября 2010

Может кто-нибудь объяснить, как работает следующий код Ruby? (взято из суть: 675667 )

require 'rubygems'
require 'rack'

class Object
  def webapp
    class << self
       define_method :call do |env|
         func, *attrs = env['PATH_INFO'].split('/').reject(&:empty?)
         [200, {}, [send(func, *attrs).to_s]]
       end
    end
    self
  end
end

Rack::Handler::Mongrel.run [].webapp, :Port => 9292
#                         ^^^^^^^^^^^
#                              |          (x)
#                         ROFLSCALE DB ---/
#

Если мы запустим его, мы сможем получить к нему доступ через Интернет:

GET http://localhost:9292/push/1  -> 1
GET http://localhost:9292/push/2  -> 12
GET http://localhost:9292/push/3  -> 123
GET http://localhost:9292/to_a    -> 123
GET http://localhost:9292/pop     -> 3
GET http://localhost:9292/shift   -> 1

Конечно, мы можем запустить что-то вроде:

GET http://localhost:9292/instance_eval/exec("rm -rf /")

В любом случае ... как это работает? Вы можете пошагово рассказать мне код?

Ответы [ 2 ]

11 голосов
/ 17 ноября 2010

Класс Object является базовым классом для всех объектов в Ruby. Здесь определен новый метод webapp, который делает его доступным для всех объектов.

При вызове webapp метод self.define_method вызывается для класса объектов (но только для этого конкретного объекта - кстати, это называется мета-класс ). Это определяет новый метод call для его экземпляра (например, объект).

Этот новый метод call принимает env в качестве аргумента и разделяет PATH_INFO косой чертой и сохраняет в массиве. Первый элемент затем присваивается переменной func, а остаток - переменной attrs. Затем вызывается магический метод send, который в основном вызывает метод по имени переменной func. Затем он возвращает массив, состоящий из кода состояния (200), пустого хеша и результата вызова метода.

В последней строке создается новый экземпляр массива ([] является сокращением для Array.new). Затем вызывается метод webapp, который обогащает его методом call, как описано выше. webapp удобно возвращает self. Таким образом, вы можете передать его непосредственно в Rack::Handler::Mongrel.run, который запустит веб-сервер (Mongrel - это веб-сервер - Rack - это уровень абстракции, который дает различным веб-серверам единый интерфейс). Сервер будет передавать запросы методу call и интерпретировать возвращаемое значение, чтобы отправить ответ обратно.

0 голосов
/ 17 ноября 2010

Не уверен, насколько вы знакомы с ruby ​​- дайте мне знать, что не имеет смысла.

Строки 1 и 2 импортируют библиотеки, необходимые для запуска веб-сервера.

Затем в сети4, базовый класс Object вновь открывается, чтобы добавить в него новый метод - вы можете делать это где угодно в ruby.Все классы наследуются от Object, поэтому любые методы, которые вы здесь определяете, можно вызывать для любого объекта.

В строке 5 начинается определение нового метода для всех объектов, который называется webapp.

.6 и 7 определяют метод call для каждого экземпляра Object, который создается.Я думаю, что это в основном эквивалентно использованию self.call для определения метода.

Строки 8 берет относительную часть URL (например, push/1 или to_a) и разбивает его на две части (т.е.func и строка переменной длины attrs).

Строка 9 затем возвращает необработанный HTTP-ответ, состоящий из кода состояния (200), заголовков (в данном случае пустых: {}) и тело ([send(func, *attrs).to_s])

Тело состоит из ответа объекта на метод func с аргументами attrs.Таким образом, если запрошенный URL-адрес был push/1, метод push будет вызван с аргументом 1.Это эквивалентно [push(1).to_s].to_s преобразует значение, возвращаемое методом, в строку.

Наконец, в строке 16 веб-сервер запускается через порт 9292. Объект, для которого вызывается метод webapp, являетсяпустой массив - вы можете использовать String (т.е. ''), Hash (т.е. {}), Proc (т.е. Proc.new) или любой класс ruby, который вам нравится.

Затем вы можете манипулировать объектом, нажимая URL-адреса вида func/attribute1/attribute2/attribute3..., и объект будет вызывать метод func со строкой аргументов attribute1, attribute2, attribute3....

Интересный код!

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...