Abusing bang methods in Ruby for fun and profit

Ruby has a quasi-convention of taking a method, slightly modifying its behavior, and denoting it with a trailing exclaimation mark, e.g. #select becomes #select!. Sometimes these methods raise an error, modify the receiver in place, or return nil on no-op, or do some combination of these, or something else entirely. Such methods are collectively referred to as “bang” methods, and there’s no hard-and-fast rule for what makes them special—just that they are “more dangerous” than their non-bang counterparts.

Today I’d like to write about bang methods that modify their receivers in place and return nil on no-op, and how you can improve performance in Ruby applications by (ab)using them to reduce object churn in hot paths.

Continue reading

Whole-home audio redux with Amazon and Google

Image courtesy of Monoprice

Hey, it was 2002, and it worked.

I’ve been experimenting with whole-home audio since college. I bought a 100′ stereo cable and ran it from my roommate’s bedroom all the way down to the front room so we could have music playing on both floors of our four-person townhome. I remember price-shopping multi-zone amplifiers when I didn’t have two nickels to rub together. It seemed the height of luxury to be able to listen to the same song no matter where you were in the house.

Continue reading

One man’s search for the perfect streaming media player

I am neither an audiophile nor a videophile, but I like to have a functional home theater that takes advantage of the state of the art without investing a ton of time and money into it. About eight years ago I assembled some mid-range gear—including a 46″ Samsung LCD panel, Denon AVR, Sony Blu-ray player, and Polk Audio speakers—that enabled me to watch movies in judder-free 1080p24 with lossless, 5.1-channel surround sound. It doesn’t hold a candle to e.g. a modern 4K HDR and Dolby Atmos setup, but it’s still a fine setup for our viewing distance and family room needs (if anything, it’s probably overkill).

We also have an Apple TV (3rd gen) and a 2010 TiVo Premiere that are getting a little long in the tooth. (Incredibly, the TiVo plays Prime Video at 1080p24 with Dolby Digital Plus, but it’s slow as molasses and you have to pay for the TiVo service to use their OnePass feature.) A few weeks ago I decided that I wanted to cancel cable TV and the TiVo subscription and replace the Apple TV and the TiVo with a new, future-proof streaming media player that supports Plex, streaming TV services, 4K HDR, and Dolby Digital Plus. I tried out the latest offerings from Amazon, Roku, and Apple.

Continue reading

Session-only cookie corruption in Ruby web apps

Rack and Rails have a cookie monster.

Browsers place limits on the number and size of cookies present for a domain or in a response. If you exceed these limits, Bad Things can happen. Rack and Rails try to prevent this in the obvious cases, but this post describes what they get wrong in their current implementations. We’ll also review the potential impact of—and how you can mitigate—this type of issue in your Ruby web apps.

This information is most relevant for web apps that transmit session cookies that contain the encoded contents of the entire session hash—not just the session ID. In other words, a cookie-only session. For example, Rack::Session::Cookie with Marshal or JSON, Rails’ default ActionDispatch::Session::CookieStore, or an implementation of JWT (JSON Web Tokens) that uses a cookie (instead of a dedicated response header) as its transport. The security risks are greatest when cookie-only sessions meet the cookie-truncation behavior of older browsers (and can be compounded when the sessions contain arbitrarily-large data, such as flash messages).

TL;DR: If your Ruby web apps use cookie-only sessions, consider adding Rack::Protection::MaximumCookie to their middleware stacks.

Continue reading

How fanriff.com works, Part I

I thought I’d write about how fanriff.com serves its Ember.js index from its Sinatra.rb API, and how web clients interacts with the back-end once the application is loaded. It started to run a little long so I’ve broken it up into parts. This first chapter will cover some background information on Ember, the fanriff.com web architecture, and how we deploy our Ember index to our stack.

Continue reading

Always set X-Forwarded-Proto

Aside

If your Rack application (and probably other types of applications) lives behind a reverse proxy, always set an X-Forwarded-Proto request header. I recently ran into an issue where Rack::Session (which I’m using for an OAuth1.0a server-side login flow) wouldn’t let me set a secure cookie because it didn’t think I was serving a secure web site.

I have forwardfor disabled in my HAproxy config because I’m using PROXY protocol to talk to Varnish. Manually adding the X-Forwarded-Proto header to the request fixed the issue, and now I want those three hours of my life back! Hopefully this comes up in someone else’s frantic googling at some point in the future and saves them a similar headache.

Web site security checklists

There are a tremendous number of things you can do today to make your site more secure, while preserving compatibility with all but the oldest web clients (I’m looking at you, Java 6 and Internet Explorer 6). If you haven’t been keeping up with the state of the art, this includes things like (cue Benny Hill music):

Continue reading