Rack to bardzo prosty protokół, który specyfikuje sposób komunikacji serwera HTTP z obiektem aplikacji. Protokół ten mówi, że obiekt aplikacji musi odpowiadać na metodę ''call''. Serwer wywoła tą metodę z jednym parametrem, w którym zawarte będą wszystkie niezbędne informacje o żądaniu (jest to ''Hash'' zawierający takie informacje jak ścieżka żądania, słowo HTTP, nagłówki, etc.).
==== Uruchamianie ====
Najprostszy przykład ilustrujący Racka mieści się w kilku ledwie linijkach:
require 'rack'
require 'pp'
class Racking
def call(env)
pp env
return [200, {}, [""]]
end
end
Rack::Handler::Thin.run(Racking.new, Port: 9000)
Po wizycie na ''localhost:9000'' na wyjściu programu pojawi się wspomniany wcześniej ''Hash'' z informacjami o żądaniu:
{"SERVER_SOFTWARE"=>"thin 1.5.0 codename Knife",
"SERVER_NAME"=>"localhost",
"rack.input"=>#,
"rack.version"=>[1, 0],
"rack.errors"=>#>,
"rack.multithread"=>false,
"rack.multiprocess"=>false,
"rack.run_once"=>false,
"REQUEST_METHOD"=>"GET",
"REQUEST_PATH"=>"/",
"PATH_INFO"=>"/",
"REQUEST_URI"=>"/",
"HTTP_VERSION"=>"HTTP/1.1",
"HTTP_HOST"=>"localhost:9000",
"HTTP_CONNECTION"=>"keep-alive",
"HTTP_USER_AGENT"=>
"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_8_2) AppleWebKit/537.11 (KHTML, like Gecko) Chrome/23.0.1271.101 Safari/537.11",
"HTTP_ACCEPT"=>
"text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8",
"HTTP_ACCEPT_ENCODING"=>"gzip,deflate,sdch",
"HTTP_ACCEPT_LANGUAGE"=>"en-US,en;q=0.8",
"HTTP_ACCEPT_CHARSET"=>"ISO-8859-1,utf-8;q=0.7,*;q=0.3",
"GATEWAY_INTERFACE"=>"CGI/1.2",
"SERVER_PORT"=>"9000",
"QUERY_STRING"=>"",
"SERVER_PROTOCOL"=>"HTTP/1.1",
"rack.url_scheme"=>"http",
"SCRIPT_NAME"=>"",
"REMOTE_ADDR"=>"127.0.0.1",
"async.callback"=>#,
"async.close"=>#}
=== Metoda call ===
Metoda ''call'' ma zwracać tablicę z trzema elementami:
* kod odpowiedzi HTTP, np. 200,
* ''hash'' lub podobny hashowi obiekt, zawierający nagłówki odpowiedzi (rozmiar odpowiedzi, czy cache'ować, etc.),
* treść odpowiedzi, która ma się zachowywać jak tablica łańcuchów znaków, tj. odpowiadać na metodę ''each'' i wywołać podany blok ''string''ami.
=== config.ru ===
Najczęściej uruchamia się ''Rack''a za pomocą komendy ''rackup'', która korzysta z pliku konfiguracyjnego ''config.ru''. Przykładowy plik mógłby wyglądać następująco:
==== Middleware ====
Specyfikacja przewiduje również możliwość tworzenia łańcuchów filtrów i routerów przed aplikacją. Te są ogólnie nazywane jako ''middleware''. One również odpowiadają na metodę ''call'' i zwracają omówioną wcześniej tablicę. Taki filter może zmodyfikować żądanie, przekazać je lub zatrzymać.
=== Tworzenie ===
''middleware'' jest tworzony poprzez obiekt ''factory''. Taki obiekt musi odpowiadać na metodę ''new'', przymującą conajmniej jeden parametr - aplikację (może nią być kolejny ''middleware''), do której ma przekazać zmodyfikowany ''hash'' z żądaniem.
FIXME Utworzyć własny
class MyMiddleware
def initialize(app)
@app = app
end
def call(env)
if env['PATH_INFO'] == '/'
@app.call(env)
else
[404, {'Content-Type' => 'text/plain'}, ['not ok']]
end
end
end
Na żądania poza ścieżkę główną, wysłana zostanie odpowiedź 404, ''not ok''.