Skip to content

Instantly share code, notes, and snippets.

@JoshCheek
Created September 24, 2015 22:24
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save JoshCheek/dd4319c8d1b3f55890c5 to your computer and use it in GitHub Desktop.
Save JoshCheek/dd4319c8d1b3f55890c5 to your computer and use it in GitHub Desktop.
Building a webserver project

I'll move this over to curriculum when it's more legitimate :)


  • Due Tuesday, we'll have a fun lunch at the Vault and "evaluate" the solutions all together!
  • Your pairs are: ["pat", "jason"], ["shannon", "robbie"], ["chad", "charissa"], ["ryan", "tyler"], ["matt", "emily"], ["ross"]

Project Overview

Goals

  • Demystify servers, the internet, http, and everything else that is ultimately just these... AJAX, sessions, cookies, APIs, Service Oriented Architectures, Oauth
  • Show you that the things you've learned can be used to accomplish real goals and write real programs
  • Show you that all the things that seem like magic... are not magic
  • Don't spend forever on this thing

What is it?

The internet... how does that work? It's really just strings going back and forth across the internet. Something like a browser will send a string called a "request" which will hit a server, which will send back a string called a "response".

You can make your own server if you can accept a request, parse the request (which means turn the string into something more useful, like a hash), and write the response.

The format of the request and response is defined by something called "http", which probably stands for something, but who cares.

The HTTP Request

Anatomy:

  1. The first line
  2. the method aka verb ("POST")
  3. the path ("/to_braille")
  4. version or protocol, something ("HTTP/1.1")
  5. Headers
  • Any number of "Key: Value" pairs
  • Some headers have meaning, eg Content-Length tells you how long the body is
  1. Body

View an HTTP request by starting a server, in order to see http

$ nc -l 9292

And now click this link: http://localhost:9292/this/is/the/path

The HTTP Response

Anatomy:

  1. The first line
  2. version or protocol, something "HTTP/1.1"
  3. The status code (eg 404)
  4. The status code for humans (eg "Not Found")
  5. Headers
  • any number of "Key: Value" pairs
  • Ending when you find a blank line
  1. Body

Make a request from the command line, and see the response

$ curl -i http://google.com

Accepting a request

# Tell my computer that web requests to http://localhost:9292 should be sent to me
require 'socket'
port       = 9292
tcp_server = TCPServer.new(port)

# Wait for a request
client = tcp_server.accept

# Read the request
first_line = client.gets
puts "The first line is: #{first_line}"

# Write the response
client.print("HTTP/1.1 302 Found\r\n")
client.print("Location: http://turing.io\r\n")
client.print("Content-Type: text/html; charset=UTF-8\r\n")
client.print("Content-Length: 219\r\n")
client.print("\r\n")
client.print("<HTML><HEAD></HEAD><BODY></BODY>\r\n")
client.close

# I'm done now, computer ^_^
tcp_server.close_read
tcp_server.close_write

A successful Ruby webserver

Does this:

  • Receive the request

  • Parse it into a Hash

  • Give it to Sinatra or whatever (called the "app")

  • Receive the instructions for what to put in the response, an array with the status code, headers, body, eg:

    [302, {'Location' => 'http://turing.io'}, ["<h1>hi</h1>"]]

  • Write the response

Getting Feedback

See what a real server parses a request as:

Install server stuff:

$ gem install rack puma

In a file called "config.ru"

class LetsGoExploring
  def call(hash)
    status_code = 200
    headers     = {'Content-Type' => 'text/html;', 'Content-Length' => '15'}
    body        = ["<h1>Hello!</h1>"]

    require "pry"
    binding.pry

    [status_code, headers, body]
  end
run

Then run it with

$ rackup config.ru -p 9292

And now click this link: http://localhost:9292/this/is/the/path

Getting comfortable

To familiarize yourself with this stuff, try using nc -l 9292 to start servers, and type the responses by hand. Can you do these things?

  • Redirect the browser (status code and Location header)
  • Return some JSON (Content-Type, Content-Length headers, body)
  • Try starting the server on a couple of different ports
  • Set a cookie (forgot what the header is, I think it's "Set-Cookie", then make a second request and see that the browser sends you back the cookie you set)
  • See how the path comes in (any request from the browser)
  • See how query params come in (any request from the browser)
  • See a form submission (edit any form on any page to point at your server -- another way is to start your Rails server, request the form, stop the server, start nc on that port, and then submit it)
  • Decrypt a Rails session -- We can get the session from the cookie, and the secret_key_base from config/secrets.yml, these should be all we need, but I'd have to look into how the encryption is done.
  • Render your own http response (probably have them write it independently, set the status, and the headers (Content-Type and Content-Length), and then paste the body in)
  • Render arbitrary other headers and see that they are present in the browser (Network tab from dev Webkit's dev tools)
  • Start nc on two different ports and redirect the browser from the one to the other, then you can see it come in twice.
  • Often, a redirect url will be sent.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment