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 tohttp://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.