Construindo seu próprio web server

Geovane Fedrecheski

geonnave@gmail.com

Um resumo bem rápido de como dois computadores se comunicam na internet

Como o browser pede e obtém os sites; e principalmente como o servidor recebe os pedidos e os responde

Um pouquinho da linguagem Ruby

Iremos Aprender



Web
Server?

Frodo

Gandalf

Frodo

Gandalf

The Ring?

0  1  2  3
0  1  2  3

Gandalf | 2

Frodo | 1

Frodo

Gandalf

The Ring?

0  1  2  3
0  1  2  3

Gandalf | 2

Frodo | 1

1.2.3.7

1.2.3.8

0  1  2  3 ... 65536
0  1  2  3 ... 65536

1.2.3.7 | 4970

1.2.3.8 | 2222

The Ring?

1.2.3.8 | 2222

1.2.3.7 | 4980

1.2.3.7

1.2.3.8

0
1
.
.
.
65536
0
1
.
.
.
65536

Sockets

1.2.3.7

1.2.3.8

0
1
.
.
.
65536
0
1
.
.
.
65536

1.2.3.7

1.2.3.8

0
1
...
2222
...
65536
0
1
...
 ?
...
65536
socket.open()
socket.listen()
socket.accept()

TCP socket (server)

TCP socket (client)

Mãos no código!

  • Abra o editor de texto
  • Abra 2 teminais

#0 Sockets + telnet

Um programa em Ruby que:

  • Cria um socket TCP do tipo "server"
  • No endereço "localhost" e na porta 2222
  • Aceita conexões e as responde
require 'socket' # Inclui as classes TCPServer e TCPSocket

# Inicializa um objeto TCPServer que irá escutar
# por pedidos de conexão em localhost:2222
server = TCPServer.new('localhost', 2222)

# loop infinito, irá processar uma conexão de cada vez
loop do
  # espera até um cliente conectar
  puts "accepting connections.."
  socket = server.accept

  # Lê a primeira linha do request
  request = socket.gets

  # Imprime essa linha na tela só pra conferir
  puts request

  # Devolvendo pro telnet
  socket.print "Whatever you ask, the answer is 42!\n"

  # Essa conexão já fez seu trabalho, fechou!
  socket.close
end
  • Salve como "web_server_0.rb"
  • Abra um terminal na mesma pasta
  • Digite "ruby web_server_0.rb"
web_server_0.rb
> ruby web_server_0.rb
accepting connections...
> telnet localhost 2222
testando!
testando!
accepting connections...

Terminal B

Terminal A

Whatever you ask, the answer is 42!


Conexão ao host perdida!

E se..

 

definíssemos regras nessa comunicação?

up abcDE
ABCDE

Protocolo

Chamamos esse tipo de regra de

HTTP

(HyperText Transfer Protocol)

Browsers e Web Servers costumam usar um protocolo chamado

#1 Básico HTTP

Um programa em Ruby que:

  • Faz tudo que o anterior faz
  • Recebe e responde conexões em formato HTTP
    (ou seja, pode ser acessado através de um browser)

HyperText Transfer Protocol

GET / HTTP/1.1
HTTP/1.1 200 OK
Content-Type: text/plain

Hello World
require 'socket'

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

loop do
  puts "accepting connections.."
  socket = server.accept

  # Lê a primeira linha do request
  #  (algo como "GET / HTTP/1.1")
  request = socket.gets
  puts request

  # Resposta no formato HTTP!
  response = "HTTP/1.1 200 OK\r\n" +
             "Content-Type: text/plain\r\n" +
             "\r\n" +
             "Hello World!\n"

  # devolvendo pro cliente
  socket.print response

  socket.close
end
web_server_1.rb

#2 Básico HTTP +
filtrando por path

Um programa em Ruby que:

  • Faz tudo que o anterior faz
  • Envia uma resposta diferente, dependendo do caminho especificado pelo browser
require 'socket'

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

def process_request_path(request_line)
  method, path, version = request_line.split(" ")
  puts path

  case path
  when "/"
    "Hello World\n"
  when "/oraculo"
    "A resposta é sempre 42!\n"
  else
    "Você veio ao lugar errado :/"
  end
end

loop do
  puts "\naccepting connections.."
  socket = server.accept

  # Lê a primeira linha do request
  #  (algo como "GET / HTTP/1.1")
  request_line = socket.gets
  puts request_line

  response_text = process_request_path(request_line)

  # a nossa resposta...
  response = "HTTP/1.1 200 OK\r\n" +
             "Content-Type: text/plain\r\n" +
             "\r\n" +
             "#{response_text}"

  # devolvendo pro cliente
  socket.print response

  socket.close
end
web_server_2.rb

#3 Básico HTTP +
filtrando por path + HTML

Um programa em Ruby que:

  • Faz tudo que o anterior faz
  • Carrega a resposta a partir de um arquivo
  • Responde com HTML no payload 
<!DOCTYPE html>
<html>
    <body>
        <h1>Hello World!</h1>
    </body>
</html>
index.html
require 'socket'

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

def process_request_path(request_line)
  method, path, version = request_line.split(" ")
  puts path

  case path
  when "/"
    File.read("index.html")
  when "/oraculo"
    "<html><body><h1>A resposta é sempre 42!</h1></body></html>\n"
  else
    "<html><body><h1>Você veio ao lugar errado :/</h1></body></html>\n"
  end
end

loop do
  puts "\naccepting connections.."
  socket = server.accept

  request_line = socket.gets
  puts request_line

  response_text = process_request_path(request_line)

  response = "HTTP/1.1 200 OK\r\n" +
             "Content-Type: text/plain\r\n" +
             "\r\n" +
             "#{response_text}"

  socket.print response

  socket.close
end
web_server_3.rb

Isso é tudo!

Um resumo bem rápido de como dois computadores se comunicam na internet

TCP, IP, Sockets

HTTP

puts "Hello World"

Como o browser pede e obtém os sites; e principalmente como o servidor recebe os pedidos e os responde

Um pouquinho da linguagem Ruby

Agora.. pra que?

Para realmente entender, faça!

depois fica + fácil aprender fazer sites etc

(tutorial de frameworks tem de monte na internet, livros tbm)

Obrigado!

Geovane Fedrecheski

geonnave@gmail.com

Made with Slides.com