Skip to content

Instantly share code, notes, and snippets.

@JoshCheek
Last active August 29, 2015 14:21
Show Gist options
  • Save JoshCheek/7f8c5afb8850c5cb8f22 to your computer and use it in GitHub Desktop.
Save JoshCheek/7f8c5afb8850c5cb8f22 to your computer and use it in GitHub Desktop.
Possible exercises to make HTTP more concrete

Use nc -l 3000 to start a server on port 3000 that will let you read and write http responses directly. Example: https://github.com/JoshCheek/playgrounds/blob/master/nc-http-response.gif

Possible exercises:

  • Redirect the browser (status code and Location header)
  • Return some JSON (Content-Type, Content-Length headers, body)
  • 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)

Find the IP address of a server (I usually give a 1 or 2 sentence explanation of what DNS is... not more, b/c I'm too ignorant >.<)

  • ping google.com
  • Now take that address and go there in the browser (http://216.58.217.14/)
  • Now include the port information, the internet is on 80 by default: http://216.58.217.14:80/
  • Make it a point to emphasize that this is the same as their 3000. the corollary between the 3000 they start their servers on, and 80
  • Show them that "localhost" has an address, too: cat /etc/hosts which outputs ...127.0.0.1 localhost... so they can start a server, navigate the browser to http://127.0.0.1:3000

Get in between Rack and Rails

  • Now they hopefully have a better understanding of what HTTP does, and have a more concrete understanding of the similarity between what they do and what Google does.

  • Lets see how Rails sits in there, go to a Rails app, and edit config.ru, the file that hooks it up to Rack.

    $ cat config.ru
    # This file is used by Rack-based servers to start the application.
    
    require ::File.expand_path('../config/environment',  __FILE__)
    run Rails.application
    

    Lets edit it to look like this:

    require ::File.expand_path('../config/environment',  __FILE__)
    # run Rails.application
    run lambda { |env|
      status  = 200
      headers = {'Content-Type' => 'text/plain'}
      body    = ['Hello, world!']
    
      require "pry"
      binding.pry
    
      [status, headers, body]
    }
    
  • Try doing all the same exercises from above, that we we did with nc. Notice that Rack does a little more for you, e.g. Separating the query params and the path.

  • Try parsing the query params, eg:

    pry> env['QUERY_STRING']
    # => "def=ghi"
    
    pry> params = Rack::Utils.parse_nested_query(env['QUERY_STRING'])
    # => {"def"=>"ghi"}
    
    pry> params['def']
    # => "ghi"
    
    pry> params[:def]
    # => nil
    
    pry> params.with_indifferent_access['def']
    # => "ghi"
    
    pry> params.with_indifferent_access[:def]
    # => "ghi"
  • Call into Rails and see what comes back:

    pry> status, headers, body = Rails.application.call(env)
    pry> status                    # 404
    pry> headers                   # {"Content-Type"=>"application/json; charset=utf-8", ...
    pry> body.each.to_a.join("\n") # "{\"message\":\"page not found\"}"
  • Redirect to another endpoint within the same app, see the browser make a second request to your app.

  • Edit the "HTTP_ACCEPT" header for an endpoint that responds to both HTML and JSON, and see the different request come back.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment