image/svg+xml
Fast, secure, safe
The web that can still be
Chris Morganirc://irc.mozilla.org/ChrisMorganmailto:me@chrismorgan.infohttps://twitter.com/__chrismorganhttps://github.com/chris-morgan
The mess we’re in
Subject matter
Specifically web servers. Client side matters too, but: • Scope creep for this talk• Stuck with JavaScript anywayStrong, statically typed languages. • The benefits of a good type system• All sorts of performance
Not a practicing web developer?
Survey
C
C++
Epilogue
Epilogue
Performance
RubyNo compile time.Dev server startup: 1s–1m.Runtime performance “slow”.
RustTypical dev compile: 3s–1m.Dev server start: <5ms.Runtime performance “fast”.
Taken from RailsConf 2013 talk “New Relic Performance Code Kata”
What is it doing in that time?
Saving you time.** OK, possibly not up front, but pretty surely in the long run.
Completely synthetic example
RubyTest suite time to failure: 15s.Finding an error Rust wouldhave found days ago, gettingsidetracked, &c.: 2h.Fixing the error: 3m.Running test suite again: 1m.
RustCompile: 5s, fails.Fixing the error: 2m.Compile: 1m.All tests: 10s.Hallway swordfight withouta legitimate reason: 2h.
1m faster!
Who is saved time?
Users: response times decrease.Inverse correlation between response time and revenue.Happier users, too. Ethics, anyone?
Who is saved time?
Developers: maintenance becomes more sure.(On a mature system you can be more sure that you’re touching the right thing.)Fewer users get annoyed, less time taken supporting them.
Who is saved time?
Ops and servers: resource usage is diminished,fewer servers to maintain,lower AWS bills.
Who is saved time?
Security: dangerous security bugscan be structurally avoided.Less patching up of leaks,pain of disclosure, loss of confidence, &c.
Why you need agood type system
Case study: HTTP headers
Stringly typed in almost every library.
Example: DNT header
if "DNT" not in request.headers: message = "Did not specify any preference."elif request.headers["DNT"] == "0": message = "Explicitly opted in to tracking."elif request.headers["DNT"] == "1": message = "Explicitly asked not to be tracked."
let message = match request.headers.get(DNT) { Some(OptIn) => "Explicitly opted in to tracking.", Some(OptOut) => "Explicitly asked not to be tracked.", None => "Did not specify any preference.",};
#[deriving(Clone)]pub enum Dnt { OptIn, OptOut,}impl Header for Dnt { fn parse_header(raw: &[Vec<u8>]) -> Option<Dnt> { match require_single_field!(raw) { b"0" => Some(OptIn), b"1" => Some(OptOut), _ => None, } } fn fmt_header(&self, writer: &mut Writer) -> IoResult<()> { writer.write_u8(match *self { OptIn => b'0', OptOut => b'1', }) }}define_header_marker!(DNT for Dnt, "dnt")
pub struct DNT;impl HeaderMarker for DNT { type Header = Dnt; fn header_name(&self) -> SendStr { Slice("dnt") }}
pub trait Header { fn parse_header(raw_field_values: &[Vec<u8>]) -> Option<Self>; fn fmt_header(&self, writer: &mut Writer) -> IoResult<()>;}pub trait HeaderMarker { type Header: Header; fn header_name(&self) -> SendStr;}pub struct Headers { data: HashMap<SendStr /* name */, internals::Item /* value, stored raw and/or typed */>,}impl<M> Headers where M: HeaderMarker { pub fn get(&mut self, header_marker: M) -> Option<<M as HeaderMarker>::Header>; pub fn get_raw(&mut self, header_marker: M) -> Option<Vec<Vec<u8>>>; pub fn set(&mut self, header_marker: M, value: <M as HeaderMarker>::Header); pub fn set_raw(&mut self, header_marker: M, value: Vec<Vec<u8>>); …}
The really good part?
It can’t possibly go wrong.
The really good part?
Could be done in dynamic languages,but it’d be hazardous.The type system lets you do exoticthings and know it’s correct.(Oh, and this way no type is privileged,nor are header names “reserved”.)
Headersare NOTstrings.
(Just thought I’d make sure I made myself clear.)
Ur/Web
… dynamic web applications backed by SQL databases. … well-typed Ur/Web programs“don’t go wrong” in a very broad sense. Not only do they not crash during particularpage generations, but they also may not: • Suffer from any kinds of code-injection attacks• Return invalid HTML• Contain dead intra-application links• Have mismatches between HTML forms and the fields expected by their handlers• Include client-side code that makes incorrect assumptions about the “AJAX”-styleservices that the remote web server provides• Attempt invalid SQL queries• Use improper marshaling or unmarshaling in communication with SQL databasesor between browsers and web servers
“
”
http://impredicative.com/ur/
Code injection and bad HTML
Compile templates as a DOM and use the power of the type system!<tag class="{{ a }}">{{ b }}</tag><style>* { background: url({{ c }}) }</style><script>alert({{ d }})</script>a must implement ToStringb must implement ToHtml or ToStringc must implement ToUrld must implement ToJson or ToJsDjango/Rails autoescape is not enough for meaningful security.
And so forth.
Same basic approach in SQL.These security bugs do not need to exist.http://www.more-magic.net/posts/structurally-fixing-injection-bugs.html
What more shall I say?
For time would fail me to tell of:• How awesome Rust’s ownership model is• How sensible encoding errors into the type system is• How well Rust can integrate with dynamic languages• And all the other great things about Rust.
In the morning sow your seed,and in the evening don’t withhold your hand;for you don’t know which will prosper,whether this or that, or whether theyboth will be equally good.— Ecclesiastes 11:6 —