├── test ├── test_helper.exs ├── cauldron_test.exs └── headers_test.exs ├── .gitignore ├── examples ├── benchmark.ex └── rest.ex ├── mix.exs ├── mix.lock ├── README.md ├── lib ├── cauldron │ ├── response.ex │ ├── request.ex │ ├── http │ │ ├── request.ex │ │ └── response.ex │ └── http.ex └── cauldron.ex └── spec ├── npn └── spdy /test/test_helper.exs: -------------------------------------------------------------------------------- 1 | ExUnit.start 2 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /ebin 2 | /deps 3 | /doc 4 | _build 5 | erl_crash.dump 6 | fprof.trace 7 | fprof.analysis 8 | -------------------------------------------------------------------------------- /examples/benchmark.ex: -------------------------------------------------------------------------------- 1 | defmodule Benchmark do 2 | def handle("GET", uri, request) do 3 | request.reply(200, "Hello, World!") 4 | end 5 | end 6 | -------------------------------------------------------------------------------- /test/cauldron_test.exs: -------------------------------------------------------------------------------- 1 | Code.require_file "test_helper.exs", __DIR__ 2 | 3 | defmodule CauldronTest do 4 | use ExUnit.Case 5 | 6 | test "the truth" do 7 | assert(true) 8 | end 9 | end 10 | -------------------------------------------------------------------------------- /test/headers_test.exs: -------------------------------------------------------------------------------- 1 | Code.require_file "test_helper.exs", __DIR__ 2 | 3 | defmodule Test.HTTP.Headers do 4 | use ExUnit.Case 5 | 6 | alias Cauldron.HTTP.Headers, as: H 7 | 8 | test :from_list do 9 | h = H.from_list [{ "Content-Length", "234" }, { "hOsT", "google.com" }] 10 | 11 | assert H.values(h) == ["234", "google.com"] 12 | assert H.keys(h) == ["Content-Length", "hOsT"] 13 | 14 | assert H.get(h, "content-length") == "234" 15 | assert H.get(h, "host") == "google.com" 16 | end 17 | end 18 | -------------------------------------------------------------------------------- /mix.exs: -------------------------------------------------------------------------------- 1 | defmodule Cauldron.Mixfile do 2 | use Mix.Project 3 | 4 | def project do 5 | [ app: :cauldron, 6 | version: "0.1.9", 7 | deps: deps(), 8 | package: package(), 9 | description: "Web server library written in Elixir" ] 10 | end 11 | 12 | defp package do 13 | [ maintainers: ["meh"], 14 | licenses: ["WTFPL"], 15 | links: %{"GitHub" => "https://github.com/meh/cauldron"} ] 16 | end 17 | 18 | def application do 19 | [] 20 | end 21 | 22 | defp deps do 23 | [ { :reagent, "~> 0.1" }, 24 | { :httprot, "~> 0.1" }, 25 | { :datastructures, "~> 0.2" }, 26 | { :ex_doc, "~> 0.14", only: [:dev] } ] 27 | end 28 | end 29 | -------------------------------------------------------------------------------- /mix.lock: -------------------------------------------------------------------------------- 1 | %{"datastructures": {:hex, :datastructures, "0.2.8", "cd9f53bed18f1d9526689a9559676c682b5a3ba230c1e3de187182f4ff86899c", [:mix], []}, 2 | "earmark": {:hex, :earmark, "1.2.2", "f718159d6b65068e8daeef709ccddae5f7fdc770707d82e7d126f584cd925b74", [:mix], []}, 3 | "ex_doc": {:hex, :ex_doc, "0.15.1", "d5f9d588fd802152516fccfdb96d6073753f77314fcfee892b15b6724ca0d596", [:mix], [{:earmark, "~> 1.1", [hex: :earmark, optional: false]}]}, 4 | "exts": {:hex, :exts, "0.3.4", "ec2af096ab4494c087a9615fffe9d5ba8a0fa0ccc465b340ee522ed7aff79078", [:mix], [{:datastructures, "~> 0.2", [hex: :datastructures, optional: false]}]}, 5 | "httprot": {:hex, :httprot, "0.1.10", "7dc1b36c29cf901ddac073fe1ba05f425de6ac749b6ae59ffaf40b1be4283002", [:mix], [{:datastructures, "~> 0.2", [hex: :datastructures, optional: false]}, {:socket, "~> 0.3", [hex: :socket, optional: false]}]}, 6 | "reagent": {:hex, :reagent, "0.1.14", "f6eaa35266091a41c93ae18b510472fa7c931c1f67a030d213ab0206ace843e1", [:mix], [{:exts, "~> 0.3", [hex: :exts, optional: false]}, {:socket, "~> 0.3", [hex: :socket, optional: false]}]}, 7 | "socket": {:hex, :socket, "0.3.11", "46004230045c2207c0b90adb9abe3ba15a83e634b341ac37af39a4adf48ed00b", [:mix], []}} 8 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Cauldron - an HTTP/SPDY server as a library 2 | =========================================== 3 | Cauldron is a web server implemented as a library, it's easy to embed into 4 | other applications and fairly easy to implement DSLs on it, an example 5 | of a DSL using cauldron is [urna](https://github.com/meh/urna). 6 | 7 | Examples 8 | -------- 9 | 10 | ```elixir 11 | defmodule Foo do 12 | use Cauldron 13 | 14 | # respond to a GET / request with "Hello, World!" 15 | def handle("GET", %URI{path: "/"}, req) do 16 | req |> Request.reply(200, "Hello, World!") 17 | end 18 | end 19 | 20 | # open the cauldron on port 8080 21 | Cauldron.start Foo, port: 8080 22 | ``` 23 | 24 | Why? 25 | ---- 26 | Because I don't like how cowboy handles things and there are no other pure 27 | Elixir webservers around that I know of. 28 | 29 | Speed 30 | ----- 31 | Right now cauldron is faster than node.js and slower than cowboy, there' still 32 | space for speed improvements but it's not a high priority right now. 33 | 34 | The slowness comes from protocol dispatching in Elixir, protocol consolidation 35 | will fix that. 36 | 37 | Also we don't use an hand-crafted decoder like cowboy does but use 38 | `:erlang.decode_packet`. 39 | -------------------------------------------------------------------------------- /lib/cauldron/response.ex: -------------------------------------------------------------------------------- 1 | # DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE 2 | # Version 2, December 2004 3 | # 4 | # DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE 5 | # TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 6 | # 7 | # 0. You just DO WHAT THE FUCK YOU WANT TO. 8 | 9 | defprotocol Cauldron.Response do 10 | alias HTTProt.Headers 11 | 12 | @doc """ 13 | Send the HTTP status. 14 | """ 15 | @spec status(t, integer | { integer, String.t }) :: t 16 | def status(self, code) 17 | 18 | @doc """ 19 | Send the HTTP headers. 20 | """ 21 | @spec headers(t, Headers.t) :: t 22 | def headers(self, headers) 23 | 24 | @doc """ 25 | Stream a file or an IO device. 26 | """ 27 | @spec stream(t, String.t | :io.device) :: t 28 | def stream(self, string_or_io) 29 | 30 | @doc """ 31 | Stream a response body with a generator function. 32 | """ 33 | @spec stream(t, term, (term -> { iolist, term })) :: t 34 | def stream(self, acc, fun) 35 | 36 | @doc """ 37 | Send the passed binary as body. 38 | """ 39 | @spec body(t, iolist) :: t 40 | def body(self, body) 41 | 42 | @doc """ 43 | Send a chunk. 44 | """ 45 | def send(self, chunk) 46 | end 47 | -------------------------------------------------------------------------------- /lib/cauldron.ex: -------------------------------------------------------------------------------- 1 | # DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE 2 | # Version 2, December 2004 3 | # 4 | # DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE 5 | # TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 6 | # 7 | # 0. You just DO WHAT THE FUCK YOU WANT TO. 8 | 9 | defmodule Cauldron do 10 | defmacro __using__(_opts) do 11 | quote do 12 | alias HTTProt.Headers 13 | alias HTTProt.Status 14 | alias Cauldron.Request 15 | alias Cauldron.Response 16 | end 17 | end 18 | 19 | use Data 20 | 21 | @options backlog: 1024, 22 | recv: [buffer: 16 * 1024] 23 | 24 | def start(name, listener) do 25 | Reagent.start __MODULE__, Keyword.merge(listener, env: [callback: name], options: @options) 26 | end 27 | 28 | def start_link(name, listener) do 29 | Reagent.start_link __MODULE__, Keyword.merge(listener, env: [callback: name], options: @options) 30 | end 31 | 32 | use Reagent.Behaviour 33 | 34 | def start(connection) do 35 | case connection |> Reagent.Connection.negotiated_protocol || "http/1.1" do 36 | "http/" <> version -> 37 | Cauldron.HTTP.start(version, connection, Dict.get(connection.listener.env, :callback)) 38 | 39 | _ -> 40 | connection |> Socket.close 41 | end 42 | end 43 | end 44 | -------------------------------------------------------------------------------- /examples/rest.ex: -------------------------------------------------------------------------------- 1 | defmodule REST do 2 | use Cauldron 3 | 4 | def handle(method, uri, request) do 5 | try do 6 | case method do 7 | "GET" -> 8 | __MODULE__.get(uri, request) 9 | 10 | "POST" -> 11 | __MODULE__.post(uri, request) 12 | end 13 | rescue 14 | _ in [UndefinedFunctionError, FunctionClauseError] -> 15 | missing(method, uri, request) 16 | end 17 | end 18 | 19 | def get(%URI{path: "/file"}, request) do 20 | request |> Request.reply("mix.exs") 21 | end 22 | 23 | def get(%URI{path: "/io"}, request) do 24 | request |> Request.reply(200, File.open!("mix.exs")) 25 | end 26 | 27 | def get(%URI{path: "/generator"}, request) do 28 | request |> Request.reply(200, true, fn 29 | true -> { "lol", false } 30 | false -> :eof 31 | end) 32 | end 33 | 34 | def get(%URI{path: "/yawnt"}, request) do 35 | request |> Request.reply(200, "yawnt e' scemo\n") 36 | end 37 | 38 | def get(%URI{path: "/yawnt/" <> what}, request) do 39 | request |> Request.reply(200, "yawnt e' #{what}\n") 40 | end 41 | 42 | def get(%URI{path: "/chuzz"}, request) do 43 | request |> Request.reply(200, "chuzz idla\n") 44 | end 45 | 46 | def post(%URI{path: "/yawnt"}, request) do 47 | case request |> Request.body do 48 | "piace" -> 49 | request |> Request.reply(200, "dire cose sceme") 50 | 51 | _ -> 52 | request |> Request.reply(200, "a me lo chiedi?") 53 | end 54 | end 55 | 56 | def missing(_, _, request) do 57 | request |> Request.reply(404) 58 | end 59 | end 60 | -------------------------------------------------------------------------------- /lib/cauldron/request.ex: -------------------------------------------------------------------------------- 1 | # DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE 2 | # Version 2, December 2004 3 | # 4 | # DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE 5 | # TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 6 | # 7 | # 0. You just DO WHAT THE FUCK YOU WANT TO. 8 | 9 | defprotocol Cauldron.Request do 10 | alias HTTProt.Headers 11 | 12 | @doc """ 13 | Check if the request has a body. 14 | """ 15 | @spec has_body?(t) :: boolean 16 | def has_body?(self) 17 | 18 | @doc """ 19 | Get the method used by the request. 20 | """ 21 | @spec method(t) :: String.t 22 | def method(self) 23 | 24 | @doc """ 25 | Get the URI used by the request. 26 | """ 27 | @spec uri(t) :: URI.t 28 | def uri(self) 29 | 30 | @doc """ 31 | Get the headers used by the request. 32 | """ 33 | @spec headers(t) :: Headers.t 34 | def headers(self) 35 | 36 | @doc """ 37 | Read a chunk from the request body, chunks are split respecting the 38 | `chunk_size` option of the listener. 39 | """ 40 | @spec read(t) :: binary 41 | def read(self) 42 | 43 | @doc """ 44 | Read a chunk from the request body, chunks are split by the given size. 45 | """ 46 | @spec read(t, non_neg_integer) :: binary 47 | def read(self, size) 48 | 49 | @doc """ 50 | Fetch the whole body from the request, or the rest if you used `read` before. 51 | """ 52 | @spec body(t) :: binary 53 | def body(self) 54 | 55 | @doc """ 56 | Create a response for the request, it is not sent to allow for more 57 | fine-grained responses. 58 | """ 59 | @spec reply(t) :: Cauldron.Response.t 60 | def reply(self) 61 | 62 | 63 | @doc """ 64 | Respond to the request sending a file or with just the response code. 65 | """ 66 | @spec reply(t, String.t | integer) :: none 67 | def reply(self, path_or_code) 68 | 69 | @doc """ 70 | Respond to the request with the given code and body or with the given code 71 | and IO handle. 72 | """ 73 | @spec reply(t, integer | { integer, String.t }, :io.device | iolist) :: none 74 | def reply(self, code, io_or_body) 75 | 76 | @doc """ 77 | Respond to the request with the given code, headers and body or with the 78 | given code and and generator function. 79 | """ 80 | @spec reply(t, integer, Headers.t | term, iolist | (term -> { iolist, term })) :: none 81 | def reply(self, code, acc_or_headers, fun_or_body) 82 | 83 | @doc """ 84 | Respond to the request with the given code, headers and generator function. 85 | """ 86 | @spec reply(t, integer, H.t, term, (term -> { iolist, term })) :: none 87 | def reply(self, code, headers, acc, fun) 88 | end 89 | -------------------------------------------------------------------------------- /lib/cauldron/http/request.ex: -------------------------------------------------------------------------------- 1 | # DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE 2 | # Version 2, December 2004 3 | # 4 | # DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE 5 | # TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 6 | # 7 | # 0. You just DO WHAT THE FUCK YOU WANT TO. 8 | 9 | defmodule Cauldron.HTTP.Request do 10 | defstruct [:connection, :handler, :id, :method, :uri, :version, :headers] 11 | @opaque t :: %__MODULE__{} 12 | 13 | @doc """ 14 | Check if the request is the last in the pipeline. 15 | """ 16 | @spec last?(t) :: boolean 17 | def last?(self) do 18 | if connection = self.headers["Connection"] do 19 | String.downcase(connection) != "keep-alive" 20 | else 21 | true 22 | end 23 | end 24 | 25 | defimpl Cauldron.Request do 26 | alias Cauldron.Response, as: R 27 | 28 | def has_body?(self) do 29 | self.headers["Content-Length"] != nil or self.headers["Transfer-Encoding"] == "chunked" 30 | end 31 | 32 | def method(self) do 33 | self.method 34 | end 35 | 36 | def uri(self) do 37 | self.uri 38 | end 39 | 40 | def headers(self) do 41 | self.headers 42 | end 43 | 44 | def read(self, size \\ 4096) do 45 | :gen_server.call self.handler, { self, :read, :chunk, size } 46 | end 47 | 48 | def body(self) do 49 | :gen_server.call self.handler, { self, :read, :all } 50 | end 51 | 52 | def reply(self) do 53 | %Cauldron.HTTP.Response{request: self} 54 | end 55 | 56 | def reply(self, path) when path |> is_binary do 57 | self |> reply |> R.status(200) |> R.headers([]) |> R.stream(path) 58 | end 59 | 60 | def reply(self, code) do 61 | self |> reply |> R.status(code) |> R.headers([]) |> R.body("") 62 | end 63 | 64 | def reply(self, code, io) when io |> is_pid or io |> is_port do 65 | self |> reply |> R.status(code) |> R.headers([]) |> R.stream(io) 66 | end 67 | 68 | def reply(self, code, body) do 69 | self |> reply |> R.status(code) |> R.headers([]) |> R.body(body) 70 | end 71 | 72 | def reply(self, code, acc, fun) when fun |> is_function do 73 | self |> reply |> R.status(code) |> R.headers([]) |> R.stream(acc, fun) 74 | end 75 | 76 | def reply(self, code, headers, body) do 77 | self |> reply |> R.status(code) |> R.headers(headers) |> R.body(body) 78 | end 79 | 80 | def reply(self, code, headers, acc, fun) when fun |> is_function do 81 | self |> reply |> R.status(code) |> R.headers(headers) |> R.stream(acc, fun) 82 | end 83 | end 84 | 85 | defimpl Inspect do 86 | import Inspect.Algebra 87 | 88 | def inspect(request, _opts) do 89 | concat ["#Cauldron.Request<", to_string(request.method), " ", to_string(request.uri), ">"] 90 | end 91 | end 92 | end 93 | -------------------------------------------------------------------------------- /lib/cauldron/http/response.ex: -------------------------------------------------------------------------------- 1 | # DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE 2 | # Version 2, December 2004 3 | # 4 | # DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE 5 | # TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 6 | # 7 | # 0. You just DO WHAT THE FUCK YOU WANT TO. 8 | 9 | defmodule Cauldron.HTTP.Response do 10 | defstruct [:request] 11 | 12 | alias HTTProt.Headers 13 | alias HTTProt.Status 14 | 15 | defimpl Cauldron.Response do 16 | def status(self, code) when code |> is_integer do 17 | status(self, { code, Status.to_string(code) }) 18 | end 19 | 20 | def status(self, { code, text }) when code |> is_integer and text |> is_binary do 21 | :gen_server.cast self.request.handler, { self, :status, code, text } 22 | 23 | self 24 | end 25 | 26 | def headers(self, headers) when headers |> is_list do 27 | headers(self, Headers.parse(headers)) 28 | end 29 | 30 | def headers(self, headers) do 31 | :gen_server.cast self.request.handler, { self, :headers, headers } 32 | 33 | self 34 | end 35 | 36 | def stream(self, path) when path |> is_binary do 37 | unless File.exists?(path) do 38 | raise File.Error, reason: :enoent, action: "open", path: path 39 | end 40 | 41 | :gen_server.cast self.request.handler, { self, :stream, path } 42 | 43 | self 44 | end 45 | 46 | def stream(self, io) when io |> is_pid or io |> is_port do 47 | stream(self, self.request.handler, io, 4096) 48 | 49 | self 50 | end 51 | 52 | def stream(self, acc, fun) when fun |> is_function do 53 | stream(self, self.request.handler, fun, acc) 54 | 55 | self 56 | end 57 | 58 | defp stream(self, handler, fun, acc) when fun |> is_function do 59 | case fun.(acc) do 60 | :eof -> 61 | :gen_server.cast handler, { self, :chunk, nil } 62 | 63 | { data, acc } -> 64 | :gen_server.cast handler, { self, :chunk, data } 65 | 66 | stream(self, handler, fun, acc) 67 | end 68 | end 69 | 70 | defp stream(self, handler, io, chunk_size) do 71 | case IO.binread(io, chunk_size) do 72 | :eof -> 73 | :gen_server.cast handler, { self, :chunk, nil } 74 | 75 | data -> 76 | :gen_server.cast handler, { self, :chunk, data } 77 | 78 | stream(self, handler, io, chunk_size) 79 | end 80 | end 81 | 82 | def body(self, body) do 83 | :gen_server.cast self.request.handler, { self, :body, body } 84 | 85 | self 86 | end 87 | 88 | def send(self, chunk) do 89 | :gen_server.cast self.request.handler, { self, :chunk, chunk } 90 | 91 | self 92 | end 93 | end 94 | 95 | defimpl Inspect do 96 | import Inspect.Algebra 97 | 98 | def inspect(response, _opts) do 99 | concat ["#Cauldron.Response<", to_string(response.request.method), " ", to_string(response.request.uri), ">"] 100 | end 101 | end 102 | end 103 | -------------------------------------------------------------------------------- /lib/cauldron/http.ex: -------------------------------------------------------------------------------- 1 | # DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE 2 | # Version 2, December 2004 3 | # 4 | # DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE 5 | # TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 6 | # 7 | # 0. You just DO WHAT THE FUCK YOU WANT TO. 8 | 9 | defmodule Cauldron.HTTP do 10 | @doc false 11 | def start(version, connection, callback) do 12 | callback = if callback |> is_atom do 13 | &callback.handle/3 14 | else 15 | callback 16 | end 17 | 18 | { :ok, Kernel.spawn(__MODULE__, :init, [version, connection, callback]) } 19 | end 20 | 21 | alias Reagent.Connection 22 | alias HTTProt.Headers 23 | alias Cauldron.Request, as: R 24 | alias Cauldron.HTTP.Request 25 | alias Cauldron.HTTP.Response 26 | 27 | use Data 28 | 29 | def init(version, connection, callback) do 30 | Process.flag :trap_exit, true 31 | Reagent.wait 32 | 33 | run(version, connection, callback) 34 | end 35 | 36 | def run(_version, connection, callback) do 37 | { method, path, version } = request(connection) 38 | headers = headers(connection) 39 | uri = create_uri(path, connection, headers) 40 | 41 | request = %Request{ 42 | connection: connection, 43 | handler: Kernel.self, 44 | id: 0, 45 | method: method, 46 | uri: uri, 47 | version: version, 48 | headers: headers } 49 | 50 | Kernel.spawn_link fn -> 51 | callback.(method, uri, request) 52 | end 53 | 54 | handler(request) 55 | 56 | unless request |> Request.last? do 57 | run(version, connection, callback) 58 | end 59 | end 60 | 61 | defp request(connection) do 62 | connection |> Socket.packet!(:http_bin) 63 | 64 | case connection |> Socket.Stream.recv! do 65 | { :http_request, method, path, version } -> 66 | { method |> to_string |> String.upcase, path, version } 67 | 68 | { :http_error, _ } -> 69 | exit :closed 70 | 71 | nil -> 72 | exit :closed 73 | end 74 | end 75 | 76 | defp headers(connection) do 77 | headers([], connection) |> Seq.reverse |> Headers.parse 78 | end 79 | 80 | defp headers(acc, connection) do 81 | case connection |> Socket.Stream.recv! do 82 | { :http_header, _, name, _, value } -> 83 | [{ name, value } | acc] |> headers(connection) 84 | 85 | :http_eoh -> 86 | acc 87 | 88 | { :http_error, _ } -> 89 | exit :closed 90 | 91 | nil -> 92 | exit :closed 93 | end 94 | end 95 | 96 | defp create_uri({ :abs_path, path }, connection, headers) do 97 | destructure [path, fragment], String.split(path, "#", parts: 2) 98 | destructure [path, query], String.split(path, "?", parts: 2) 99 | 100 | { host, port } = if authority = Dict.get(headers, "Host") do 101 | destructure [host, port], String.split(authority, ":", parts: 2) 102 | { host, String.to_integer(port || "80") } 103 | else 104 | { nil, nil } 105 | end 106 | 107 | userinfo = if auth = Dict.get(headers, "Authorization") do 108 | case auth do 109 | "Basic " <> rest -> 110 | :base64.decode(rest) 111 | 112 | _ -> 113 | nil 114 | end 115 | end 116 | 117 | %URI{ 118 | scheme: if(connection |> Connection.secure?, do: "https", else: "http"), 119 | authority: authority, 120 | host: host, 121 | port: port, 122 | userinfo: userinfo, 123 | path: path, 124 | query: query, 125 | fragment: fragment } 126 | end 127 | 128 | defp create_uri({ :absoluteURI, scheme, host, port, path }, _connection, _headers) do 129 | destructure [path, fragment], String.split(path, "#", parts: 2) 130 | destructure [path, query], String.split(path, "?", parts: 2) 131 | 132 | port = case port do 133 | :undefined -> 134 | if scheme == :http do 135 | 80 136 | else 137 | 443 138 | end 139 | 140 | port -> 141 | port 142 | end 143 | 144 | %URI{ 145 | scheme: Atom.to_string(scheme), 146 | authority: "#{host}:#{port}", 147 | host: host, 148 | port: port, 149 | path: path, 150 | query: query, 151 | fragment: fragment } 152 | end 153 | 154 | defp create_uri({ :scheme, host, port }, _connection, _headers) do 155 | %URI{ 156 | host: host, 157 | port: String.to_integer(port) } 158 | end 159 | 160 | defp create_uri(path, _connection, _headers) when path |> is_binary do 161 | path 162 | end 163 | 164 | defp handler(request) do 165 | handler(request, nil, nil) 166 | end 167 | 168 | defp handler(%Request{connection: connection} = request, headers, body) do 169 | receive do 170 | { :EXIT, _pid, :normal } -> 171 | handler(request, headers, body) 172 | 173 | { :EXIT, _pid, reason } -> 174 | :error_logger.error_report(reason) 175 | request |> R.reply(500) 176 | 177 | handler(request, headers, body) 178 | 179 | { :"$gen_call", { pid, ref }, { %Request{headers: headers}, :read, :all } } -> 180 | body = unless body do 181 | read_body(connection, headers) 182 | else 183 | body 184 | end 185 | 186 | pid |> send({ ref, body }) 187 | 188 | handler(request, headers, body) 189 | 190 | { :"$gen_cast", { %Response{request: %Request{version: version}}, :status, code, text } } -> 191 | write_status(connection, version, code, text) 192 | 193 | handler(request, nil, body) 194 | 195 | { :"$gen_cast", { %Response{}, :headers, headers } } -> 196 | handler(request, headers, body) 197 | 198 | { :"$gen_cast", { %Response{}, :body, body } } -> 199 | headers = keep_alive(request, headers) 200 | headers = headers |> Dict.put("Content-Length", IO.iodata_length(body)) 201 | 202 | write_headers(connection, headers) 203 | write_body(connection, body) 204 | 205 | { :"$gen_cast", { %Response{}, :stream, path } } -> 206 | headers = keep_alive(request, headers) 207 | headers = headers |> Dict.put("Content-Length", File.stat!(path).size) 208 | 209 | write_headers(connection, headers) 210 | write_file(connection, path) 211 | 212 | { :"$gen_cast", { %Response{}, :chunk, chunk } } -> 213 | if headers do 214 | headers = keep_alive(request, headers) 215 | headers = headers |> Dict.put("Transfer-Encoding", "chunked") 216 | 217 | write_headers(connection, 218 | keep_alive(request, headers) |> 219 | Dict.put("Transfer-Encoding", "chunked")) 220 | end 221 | 222 | write_chunk(connection, chunk) 223 | 224 | unless chunk == nil do 225 | handler(request, nil, body) 226 | end 227 | 228 | _ -> 229 | handler(request, headers, body) 230 | end 231 | end 232 | 233 | defp keep_alive(request, headers) do 234 | if request |> Request.last? do 235 | headers |> Dict.put("Connection", "close") 236 | else 237 | headers |> Dict.put("Connection", "keep-alive") 238 | end 239 | end 240 | 241 | defp read_body(connection, headers) do 242 | cond do 243 | length = headers |> Dict.get("Content-Length") -> 244 | connection |> Socket.packet!(:raw) 245 | connection |> Socket.Stream.recv!(length) 246 | 247 | headers |> Dict.get("Transfer-Encoding") == "chunked" -> 248 | read_chunks(connection) 249 | 250 | true -> 251 | nil 252 | end 253 | end 254 | 255 | defp read_chunks(connection) do 256 | read_chunks([], connection) |> Enum.reverse |> IO.iodata_to_binary 257 | end 258 | 259 | defp read_chunks(acc, connection) do 260 | case read_chunk(connection) do 261 | nil -> 262 | acc 263 | 264 | chunk -> 265 | [chunk | acc] |> read_chunks(connection) 266 | end 267 | end 268 | 269 | defp read_chunk(connection) do 270 | connection |> Socket.packet!(:line) 271 | 272 | case connection |> Socket.Stream.recv! |> String.rstrip |> String.to_integer(16) do 273 | 0 -> 274 | connection |> Socket.Stream.recv! 275 | nil 276 | 277 | size -> 278 | connection |> Socket.packet!(:raw) 279 | res = connection |> Socket.Stream.recv!(size) 280 | connection |> Socket.packet!(:line) 281 | connection |> Socket.Stream.recv! 282 | res 283 | end 284 | end 285 | 286 | defp write_status(connection, { major, minor }, code, text) do 287 | connection |> Socket.Stream.send!([ 288 | "HTTP/", "#{major}.#{minor}", " ", 289 | Integer.to_string(code), " ", 290 | text, "\r\n" 291 | ]) 292 | end 293 | 294 | defp write_headers(connection, headers) do 295 | Enum.each headers, fn { name, value } -> 296 | connection |> Socket.Stream.send!([name, ": ", to_string(value), "\r\n"]) 297 | end 298 | 299 | connection |> Socket.Stream.send!("\r\n") 300 | end 301 | 302 | defp write_body(connection, body) do 303 | connection |> Socket.Stream.send!(body) 304 | end 305 | 306 | defp write_file(connection, path) do 307 | connection |> Socket.Stream.file!(path) 308 | end 309 | 310 | defp write_chunk(connection, nil) do 311 | connection |> Socket.Stream.send!("0\r\n\r\n") 312 | end 313 | 314 | defp write_chunk(connection, chunk) do 315 | connection |> Socket.Stream.send!([ 316 | :io_lib.format("~.16b", [IO.iodata_length(chunk)]), "\r\n", 317 | chunk, "\r\n" 318 | ]) 319 | end 320 | end 321 | -------------------------------------------------------------------------------- /spec/npn: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Network Working Group A. Langley 5 | Internet-Draft Google Inc 6 | Expires: October 26, 2012 April 24, 2012 7 | 8 | 9 | Transport Layer Security (TLS) Next Protocol Negotiation Extension 10 | draft-agl-tls-nextprotoneg-03 11 | 12 | Abstract 13 | 14 | This document describes a Transport Layer Security (TLS) extension 15 | for application layer protocol negotiation. This allows the 16 | application layer to negotiate which protocol should be performed 17 | over the secure connection. 18 | 19 | Status of this Memo 20 | 21 | This Internet-Draft is submitted in full conformance with the 22 | provisions of BCP 78 and BCP 79. 23 | 24 | Internet-Drafts are working documents of the Internet Engineering 25 | Task Force (IETF). Note that other groups may also distribute 26 | working documents as Internet-Drafts. The list of current Internet- 27 | Drafts is at http://datatracker.ietf.org/drafts/current/. 28 | 29 | Internet-Drafts are draft documents valid for a maximum of six months 30 | and may be updated, replaced, or obsoleted by other documents at any 31 | time. It is inappropriate to use Internet-Drafts as reference 32 | material or to cite them other than as "work in progress." 33 | 34 | This Internet-Draft will expire on October 26, 2012. 35 | 36 | Copyright Notice 37 | 38 | Copyright (c) 2012 IETF Trust and the persons identified as the 39 | document authors. All rights reserved. 40 | 41 | This document is subject to BCP 78 and the IETF Trust's Legal 42 | Provisions Relating to IETF Documents 43 | (http://trustee.ietf.org/license-info) in effect on the date of 44 | publication of this document. Please review these documents 45 | carefully, as they describe your rights and restrictions with respect 46 | to this document. Code Components extracted from this document must 47 | include Simplified BSD License text as described in Section 4.e of 48 | the Trust Legal Provisions and are provided without warranty as 49 | described in the Simplified BSD License. 50 | 51 | 52 | 53 | 54 | 55 | Langley Expires October 26, 2012 [Page 1] 56 | 57 | Internet-Draft TLS Next Protocol Negotiation April 2012 58 | 59 | 60 | Table of Contents 61 | 62 | 1. Introduction . . . . . . . . . . . . . . . . . . . . . . . . . 3 63 | 2. Requirements Notation . . . . . . . . . . . . . . . . . . . . 4 64 | 3. Next Protocol Negotiation Extension . . . . . . . . . . . . . 5 65 | 4. Protocol selection . . . . . . . . . . . . . . . . . . . . . . 8 66 | 5. Design discussion . . . . . . . . . . . . . . . . . . . . . . 9 67 | 6. Security considerations . . . . . . . . . . . . . . . . . . . 10 68 | 7. IANA Considerations . . . . . . . . . . . . . . . . . . . . . 11 69 | 8. Acknowledgments . . . . . . . . . . . . . . . . . . . . . . . 12 70 | 9. References . . . . . . . . . . . . . . . . . . . . . . . . . . 13 71 | 9.1. Normative References . . . . . . . . . . . . . . . . . . . 13 72 | 9.2. Informative References . . . . . . . . . . . . . . . . . . 13 73 | Author's Address . . . . . . . . . . . . . . . . . . . . . . . . . 14 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | Langley Expires October 26, 2012 [Page 2] 112 | 113 | Internet-Draft TLS Next Protocol Negotiation April 2012 114 | 115 | 116 | 1. Introduction 117 | 118 | The Next Protocol Negotiation extension (NPN) is currently used to 119 | negotiate the use of SPDY [spdy] as an application level protocol on 120 | port 443, and to perform SPDY version negotiation. However, it is 121 | not SPDY specific in any way. 122 | 123 | Designers of new application level protocols are faced with a 124 | problem: there are no good options for establishing a clean transport 125 | for a new protocol and negotiating its use. Negotiations on port 80 126 | will run afoul of intercepting proxies. Ports other than 80 and 443 127 | are likely to be firewalled without any fast method of detection, and 128 | are also unlikely to traverse HTTP proxies with CONNECT. Negotiating 129 | on port 443 is possible, but may run afoul of MITM proxies and also 130 | uses a round trip for negotiation on top of the round trips for 131 | establishing the TLS connection. Negotiation at that level is also 132 | dependent on the application level protocol, i.e. the real world 133 | tolerance of servers to HTTP Upgrade requests. 134 | 135 | Next Protocol Negotiation allows application level protocols to be 136 | negotiated without additional round trips and with clean fallback in 137 | the case of an unsupportive MITM proxy. 138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | 155 | 156 | 157 | 158 | 159 | 160 | 161 | 162 | 163 | 164 | 165 | 166 | 167 | Langley Expires October 26, 2012 [Page 3] 168 | 169 | Internet-Draft TLS Next Protocol Negotiation April 2012 170 | 171 | 172 | 2. Requirements Notation 173 | 174 | The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", 175 | "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this 176 | document are to be interpreted as described in RFC 2119 [RFC2119]. 177 | 178 | 179 | 180 | 181 | 182 | 183 | 184 | 185 | 186 | 187 | 188 | 189 | 190 | 191 | 192 | 193 | 194 | 195 | 196 | 197 | 198 | 199 | 200 | 201 | 202 | 203 | 204 | 205 | 206 | 207 | 208 | 209 | 210 | 211 | 212 | 213 | 214 | 215 | 216 | 217 | 218 | 219 | 220 | 221 | 222 | 223 | Langley Expires October 26, 2012 [Page 4] 224 | 225 | Internet-Draft TLS Next Protocol Negotiation April 2012 226 | 227 | 228 | 3. Next Protocol Negotiation Extension 229 | 230 | A new extension type ("next_protocol_negotiation(13172)") is defined 231 | and MAY be included by the client in its "ClientHello" message. If, 232 | and only if, the server sees this extension in the "ClientHello", it 233 | MAY choose to echo the extension in its "ServerHello". 234 | 235 | enum { 236 | next_protocol_negotiation(13172), (65535) 237 | } ExtensionType; 238 | 239 | The "extension_data" field of a "next_protocol_negotiation" extension 240 | in a "ClientHello" MUST be empty. 241 | 242 | The "extension_data" field of a "next_protocol_negotiation" extension 243 | in a "ServerHello" contains an optional list of protocols advertised 244 | by the server. Protocols are named by opaque, non-empty byte strings 245 | and the list of protocols is serialized as a concatenation of 8-bit, 246 | length prefixed byte strings. Implementations MUST ensure that the 247 | empty string is not included and that no byte strings are truncated. 248 | 249 | A new handshake message type ("next_protocol(67)") is defined. If, 250 | and only if, the server included a "next_protocol_negotiation" 251 | extension in its "ServerHello" message, the client MUST send a 252 | "NextProtocol" message after its "ChangeCipherSpec" and before its 253 | "Finished" message. 254 | 255 | enum { 256 | next_protocol(67), (65535) 257 | } HandshakeType; 258 | 259 | Therefore a full handshake with "NextProtocol" has the following flow 260 | (contrast with section 7.3 of RFC 5246 [RFC5246]): 261 | 262 | 263 | 264 | 265 | 266 | 267 | 268 | 269 | 270 | 271 | 272 | 273 | 274 | 275 | 276 | 277 | 278 | 279 | Langley Expires October 26, 2012 [Page 5] 280 | 281 | Internet-Draft TLS Next Protocol Negotiation April 2012 282 | 283 | 284 | Client Server 285 | 286 | ClientHello (NPN extension) --------> 287 | ServerHello 288 | (NPN extension & 289 | list of protocols) 290 | Certificate* 291 | ServerKeyExchange* 292 | CertificateRequest* 293 | <-------- ServerHelloDone 294 | Certificate* 295 | ClientKeyExchange 296 | CertificateVerify* 297 | [ChangeCipherSpec] 298 | NextProtocol 299 | Finished --------> 300 | [ChangeCipherSpec] 301 | <-------- Finished 302 | Application Data <-------> Application Data 303 | 304 | An abbreviated handshake with "NextProtocol" has the following flow: 305 | 306 | Client Server 307 | 308 | ClientHello (NPN extension) --------> 309 | ServerHello 310 | (NPN extension & 311 | list of protocols) 312 | [ChangeCipherSpec] 313 | <-------- Finished 314 | [ChangeCipherSpec] 315 | NextProtocol 316 | Finished --------> 317 | Application Data <-------> Application Data 318 | 319 | The "NextProtocol" message has the following format: 320 | 321 | struct { 322 | opaque selected_protocol<0..255>; 323 | opaque padding<0..255>; 324 | } NextProtocol; 325 | 326 | The contents of "selected_protocol" are an opaque protocol string, 327 | but need not have been advertised by the server. The length of 328 | "padding" SHOULD be 32 - ((len(selected_protocol) + 2) % 32). Note 329 | that len(selected_protocol) does not include its length prefix. 330 | 331 | Unlike many other TLS extensions, this extension does not establish 332 | 333 | 334 | 335 | Langley Expires October 26, 2012 [Page 6] 336 | 337 | Internet-Draft TLS Next Protocol Negotiation April 2012 338 | 339 | 340 | properties of the session, only of the connection. When session 341 | resumption or session tickets [RFC5077] are used, the previous 342 | contents of this extension are irrelevant and only the values in the 343 | new handshake messages are considered. 344 | 345 | For the same reasons, after a handshake has been performed for a 346 | given connection, renegotiations on the same connection MUST NOT 347 | include the "next_protocol_negotiation" extension. 348 | 349 | 350 | 351 | 352 | 353 | 354 | 355 | 356 | 357 | 358 | 359 | 360 | 361 | 362 | 363 | 364 | 365 | 366 | 367 | 368 | 369 | 370 | 371 | 372 | 373 | 374 | 375 | 376 | 377 | 378 | 379 | 380 | 381 | 382 | 383 | 384 | 385 | 386 | 387 | 388 | 389 | 390 | 391 | Langley Expires October 26, 2012 [Page 7] 392 | 393 | Internet-Draft TLS Next Protocol Negotiation April 2012 394 | 395 | 396 | 4. Protocol selection 397 | 398 | It's expected that a client will have a list of protocols that it 399 | supports, in preference order, and will only select a protocol if the 400 | server supports it. In that case, the client SHOULD select the first 401 | protocol advertised by the server that it also supports. In the 402 | event that the client doesn't support any of server's protocols, or 403 | the server doesn't advertise any, it SHOULD select the first protocol 404 | that it supports. 405 | 406 | There may be cases where the client knows, via other means, that a 407 | server supports an unadvertised protocol. In these cases the client 408 | can simply select that protocol. 409 | 410 | 411 | 412 | 413 | 414 | 415 | 416 | 417 | 418 | 419 | 420 | 421 | 422 | 423 | 424 | 425 | 426 | 427 | 428 | 429 | 430 | 431 | 432 | 433 | 434 | 435 | 436 | 437 | 438 | 439 | 440 | 441 | 442 | 443 | 444 | 445 | 446 | 447 | Langley Expires October 26, 2012 [Page 8] 448 | 449 | Internet-Draft TLS Next Protocol Negotiation April 2012 450 | 451 | 452 | 5. Design discussion 453 | 454 | NPN is an outlier from TLS in several respects: firstly that it 455 | introduces a handshake message between the "ChangeCipherSpec" and 456 | "Finished" message, that the handshake message is padded, and that 457 | the negotiation isn't done purely with the hello messages. All these 458 | aspects of the protocol are intended to prevent middle-ware 459 | discrimination based on the negotiated protocol and follow the 460 | general principle that anything that can be encrypted, should be 461 | encrypted. The server's list of advertised protocols is in the clear 462 | as a compromise between performance and robustness. 463 | 464 | 465 | 466 | 467 | 468 | 469 | 470 | 471 | 472 | 473 | 474 | 475 | 476 | 477 | 478 | 479 | 480 | 481 | 482 | 483 | 484 | 485 | 486 | 487 | 488 | 489 | 490 | 491 | 492 | 493 | 494 | 495 | 496 | 497 | 498 | 499 | 500 | 501 | 502 | 503 | Langley Expires October 26, 2012 [Page 9] 504 | 505 | Internet-Draft TLS Next Protocol Negotiation April 2012 506 | 507 | 508 | 6. Security considerations 509 | 510 | The server's list of supported protocols is still advertised in the 511 | clear with this extension. This may be undesirable for certain 512 | protocols (such as Tor [tor]) where one could imagine that hostile 513 | networks would terminate any TLS connection with a server that 514 | advertised such a capability. In this case, clients may wish to 515 | opportunistically select a protocol that wasn't advertised by the 516 | server. However, the workings of such a scheme are outside the scope 517 | of this document. 518 | 519 | 520 | 521 | 522 | 523 | 524 | 525 | 526 | 527 | 528 | 529 | 530 | 531 | 532 | 533 | 534 | 535 | 536 | 537 | 538 | 539 | 540 | 541 | 542 | 543 | 544 | 545 | 546 | 547 | 548 | 549 | 550 | 551 | 552 | 553 | 554 | 555 | 556 | 557 | 558 | 559 | Langley Expires October 26, 2012 [Page 10] 560 | 561 | Internet-Draft TLS Next Protocol Negotiation April 2012 562 | 563 | 564 | 7. IANA Considerations 565 | 566 | This document requires IANA to update its registry of TLS extensions 567 | to assign entry 13172 as "next_protocol_negotiation". 568 | 569 | This document also requires IANA to update its registry of TLS 570 | handshake types to assign entry 67 as "next_protocol". 571 | 572 | This document also requires IANA to create a registry of TLS Next 573 | Protocol Negotiation protocol strings on a first come, first served 574 | basis, initially containing the following entries: 575 | 576 | o "http/1.1": HTTP/1.1 [RFC2616] 577 | 578 | o "spdy/1": (obsolete) SPDY version 1 579 | 580 | o "spdy/2": SPDY version 2 581 | 582 | o "spdy/3": SPDY version 3 583 | 584 | 585 | 586 | 587 | 588 | 589 | 590 | 591 | 592 | 593 | 594 | 595 | 596 | 597 | 598 | 599 | 600 | 601 | 602 | 603 | 604 | 605 | 606 | 607 | 608 | 609 | 610 | 611 | 612 | 613 | 614 | 615 | Langley Expires October 26, 2012 [Page 11] 616 | 617 | Internet-Draft TLS Next Protocol Negotiation April 2012 618 | 619 | 620 | 8. Acknowledgments 621 | 622 | This document benefited specifically from discussions with Wan-Teh 623 | Chang and Nagendra Modadugu. 624 | 625 | 626 | 627 | 628 | 629 | 630 | 631 | 632 | 633 | 634 | 635 | 636 | 637 | 638 | 639 | 640 | 641 | 642 | 643 | 644 | 645 | 646 | 647 | 648 | 649 | 650 | 651 | 652 | 653 | 654 | 655 | 656 | 657 | 658 | 659 | 660 | 661 | 662 | 663 | 664 | 665 | 666 | 667 | 668 | 669 | 670 | 671 | Langley Expires October 26, 2012 [Page 12] 672 | 673 | Internet-Draft TLS Next Protocol Negotiation April 2012 674 | 675 | 676 | 9. References 677 | 678 | 9.1. Normative References 679 | 680 | [RFC2119] Bradner, S., "Key words for use in RFCs to Indicate 681 | Requirement Levels", BCP 14, RFC 2119, March 1997. 682 | 683 | [RFC5246] Dierks, T. and E. Rescorla, "The Transport Layer Security 684 | (TLS) Protocol Version 1.2", RFC 5246, August 2008. 685 | 686 | 9.2. Informative References 687 | 688 | [RFC2616] Fielding, R., Gettys, J., Mogul, J., Frystyk, H., 689 | Masinter, L., Leach, P., and T. Berners-Lee, "Hypertext 690 | Transfer Protocol -- HTTP/1.1", RFC 2616, June 1999. 691 | 692 | [RFC5077] Salowey, J., Zhou, H., Eronen, P., and H. Tschofenig, 693 | "Transport Layer Security (TLS) Session Resumption without 694 | Server-Side State", RFC 5077, January 2008. 695 | 696 | [tor] Dingledine, R., Matthewson, N., and P. Syverson, "Tor: The 697 | Second-Generation Onion Router", August 2004. 698 | 699 | [spdy] Belshe, M. and R. Peon, "SPDY Protocol (Internet Draft)", 700 | Feb 2012. 701 | 702 | 703 | 704 | 705 | 706 | 707 | 708 | 709 | 710 | 711 | 712 | 713 | 714 | 715 | 716 | 717 | 718 | 719 | 720 | 721 | 722 | 723 | 724 | 725 | 726 | 727 | Langley Expires October 26, 2012 [Page 13] 728 | 729 | Internet-Draft TLS Next Protocol Negotiation April 2012 730 | 731 | 732 | Author's Address 733 | 734 | Adam Langley 735 | Google Inc 736 | 737 | Email: agl@google.com 738 | 739 | 740 | 741 | 742 | 743 | 744 | 745 | 746 | 747 | 748 | 749 | 750 | 751 | 752 | 753 | 754 | 755 | 756 | 757 | 758 | 759 | 760 | 761 | 762 | 763 | 764 | 765 | 766 | 767 | 768 | 769 | 770 | 771 | 772 | 773 | 774 | 775 | 776 | 777 | 778 | 779 | 780 | 781 | 782 | 783 | Langley Expires October 26, 2012 [Page 14] 784 | 785 | -------------------------------------------------------------------------------- /spec/spdy: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Network Working Group M. Belshe 5 | Internet-Draft Twist 6 | Expires: August 4, 2012 R. Peon 7 | Google, Inc 8 | Feb 2012 9 | 10 | 11 | SPDY Protocol 12 | draft-mbelshe-httpbis-spdy-00 13 | 14 | Abstract 15 | 16 | This document describes SPDY, a protocol designed for low-latency 17 | transport of content over the World Wide Web. SPDY introduces two 18 | layers of protocol. The lower layer is a general purpose framing 19 | layer which can be used atop a reliable transport (likely TCP) for 20 | multiplexed, prioritized, and compressed data communication of many 21 | concurrent streams. The upper layer of the protocol provides HTTP- 22 | like RFC2616 [RFC2616] semantics for compatibility with existing HTTP 23 | application servers. 24 | 25 | Status of this Memo 26 | 27 | This Internet-Draft is submitted in full conformance with the 28 | provisions of BCP 78 and BCP 79. 29 | 30 | Internet-Drafts are working documents of the Internet Engineering 31 | Task Force (IETF). Note that other groups may also distribute 32 | working documents as Internet-Drafts. The list of current Internet- 33 | Drafts is at http://datatracker.ietf.org/drafts/current/. 34 | 35 | Internet-Drafts are draft documents valid for a maximum of six months 36 | and may be updated, replaced, or obsoleted by other documents at any 37 | time. It is inappropriate to use Internet-Drafts as reference 38 | material or to cite them other than as "work in progress." 39 | 40 | This Internet-Draft will expire on August 4, 2012. 41 | 42 | Copyright Notice 43 | 44 | Copyright (c) 2012 IETF Trust and the persons identified as the 45 | document authors. All rights reserved. 46 | 47 | This document is subject to BCP 78 and the IETF Trust's Legal 48 | Provisions Relating to IETF Documents 49 | (http://trustee.ietf.org/license-info) in effect on the date of 50 | publication of this document. Please review these documents 51 | carefully, as they describe your rights and restrictions with respect 52 | 53 | 54 | 55 | Belshe & Peon Expires August 4, 2012 [Page 1] 56 | 57 | Internet-Draft SPDY Feb 2012 58 | 59 | 60 | to this document. Code Components extracted from this document must 61 | include Simplified BSD License text as described in Section 4.e of 62 | the Trust Legal Provisions and are provided without warranty as 63 | described in the Simplified BSD License. 64 | 65 | 66 | Table of Contents 67 | 68 | 1. Overview . . . . . . . . . . . . . . . . . . . . . . . . . . . 4 69 | 1.1. Document Organization . . . . . . . . . . . . . . . . . . 4 70 | 1.2. Definitions . . . . . . . . . . . . . . . . . . . . . . . 5 71 | 2. SPDY Framing Layer . . . . . . . . . . . . . . . . . . . . . . 6 72 | 2.1. Session (Connections) . . . . . . . . . . . . . . . . . . 6 73 | 2.2. Framing . . . . . . . . . . . . . . . . . . . . . . . . . 6 74 | 2.2.1. Control frames . . . . . . . . . . . . . . . . . . . . 6 75 | 2.2.2. Data frames . . . . . . . . . . . . . . . . . . . . . 7 76 | 2.3. Streams . . . . . . . . . . . . . . . . . . . . . . . . . 8 77 | 2.3.1. Stream frames . . . . . . . . . . . . . . . . . . . . 9 78 | 2.3.2. Stream creation . . . . . . . . . . . . . . . . . . . 9 79 | 2.3.3. Stream priority . . . . . . . . . . . . . . . . . . . 10 80 | 2.3.4. Stream headers . . . . . . . . . . . . . . . . . . . . 10 81 | 2.3.5. Stream data exchange . . . . . . . . . . . . . . . . . 10 82 | 2.3.6. Stream half-close . . . . . . . . . . . . . . . . . . 10 83 | 2.3.7. Stream close . . . . . . . . . . . . . . . . . . . . . 11 84 | 2.4. Error Handling . . . . . . . . . . . . . . . . . . . . . . 11 85 | 2.4.1. Session Error Handling . . . . . . . . . . . . . . . . 11 86 | 2.4.2. Stream Error Handling . . . . . . . . . . . . . . . . 12 87 | 2.5. Data flow . . . . . . . . . . . . . . . . . . . . . . . . 12 88 | 2.6. Control frame types . . . . . . . . . . . . . . . . . . . 12 89 | 2.6.1. SYN_STREAM . . . . . . . . . . . . . . . . . . . . . . 12 90 | 2.6.2. SYN_REPLY . . . . . . . . . . . . . . . . . . . . . . 14 91 | 2.6.3. RST_STREAM . . . . . . . . . . . . . . . . . . . . . . 15 92 | 2.6.4. SETTINGS . . . . . . . . . . . . . . . . . . . . . . . 16 93 | 2.6.5. PING . . . . . . . . . . . . . . . . . . . . . . . . . 19 94 | 2.6.6. GOAWAY . . . . . . . . . . . . . . . . . . . . . . . . 20 95 | 2.6.7. HEADERS . . . . . . . . . . . . . . . . . . . . . . . 21 96 | 2.6.8. WINDOW_UPDATE . . . . . . . . . . . . . . . . . . . . 22 97 | 2.6.9. CREDENTIAL . . . . . . . . . . . . . . . . . . . . . . 24 98 | 2.6.10. Name/Value Header Block . . . . . . . . . . . . . . . 26 99 | 3. HTTP Layering over SPDY . . . . . . . . . . . . . . . . . . . 33 100 | 3.1. Connection Management . . . . . . . . . . . . . . . . . . 33 101 | 3.1.1. Use of GOAWAY . . . . . . . . . . . . . . . . . . . . 33 102 | 3.2. HTTP Request/Response . . . . . . . . . . . . . . . . . . 34 103 | 3.2.1. Request . . . . . . . . . . . . . . . . . . . . . . . 34 104 | 3.2.2. Response . . . . . . . . . . . . . . . . . . . . . . . 35 105 | 3.2.3. Authentication . . . . . . . . . . . . . . . . . . . . 36 106 | 3.3. Server Push Transactions . . . . . . . . . . . . . . . . . 37 107 | 3.3.1. Server implementation . . . . . . . . . . . . . . . . 38 108 | 109 | 110 | 111 | Belshe & Peon Expires August 4, 2012 [Page 2] 112 | 113 | Internet-Draft SPDY Feb 2012 114 | 115 | 116 | 3.3.2. Client implementation . . . . . . . . . . . . . . . . 39 117 | 4. Design Rationale and Notes . . . . . . . . . . . . . . . . . . 40 118 | 4.1. Separation of Framing Layer and Application Layer . . . . 40 119 | 4.2. Error handling - Framing Layer . . . . . . . . . . . . . . 40 120 | 4.3. One Connection Per Domain . . . . . . . . . . . . . . . . 40 121 | 4.4. Fixed vs Variable Length Fields . . . . . . . . . . . . . 41 122 | 4.5. Compression Context(s) . . . . . . . . . . . . . . . . . . 41 123 | 4.6. Unidirectional streams . . . . . . . . . . . . . . . . . . 42 124 | 4.7. Data Compression . . . . . . . . . . . . . . . . . . . . . 42 125 | 4.8. Server Push . . . . . . . . . . . . . . . . . . . . . . . 42 126 | 5. Security Considerations . . . . . . . . . . . . . . . . . . . 43 127 | 5.1. Use of Same-origin constraints . . . . . . . . . . . . . . 43 128 | 5.2. HTTP Headers and SPDY Headers . . . . . . . . . . . . . . 43 129 | 5.3. Cross-Protocol Attacks . . . . . . . . . . . . . . . . . . 43 130 | 5.4. Server Push Implicit Headers . . . . . . . . . . . . . . . 43 131 | 6. Privacy Considerations . . . . . . . . . . . . . . . . . . . . 44 132 | 6.1. Long Lived Connections . . . . . . . . . . . . . . . . . . 44 133 | 6.2. SETTINGS frame . . . . . . . . . . . . . . . . . . . . . . 44 134 | 7. Incompatibilities with SPDY draft #2 . . . . . . . . . . . . . 45 135 | 8. Requirements Notation . . . . . . . . . . . . . . . . . . . . 46 136 | 9. Acknowledgements . . . . . . . . . . . . . . . . . . . . . . . 47 137 | 10. Normative References . . . . . . . . . . . . . . . . . . . . . 48 138 | Appendix A. Changes . . . . . . . . . . . . . . . . . . . . . . . 50 139 | Authors' Addresses . . . . . . . . . . . . . . . . . . . . . . . . 51 140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | 155 | 156 | 157 | 158 | 159 | 160 | 161 | 162 | 163 | 164 | 165 | 166 | 167 | Belshe & Peon Expires August 4, 2012 [Page 3] 168 | 169 | Internet-Draft SPDY Feb 2012 170 | 171 | 172 | 1. Overview 173 | 174 | One of the bottlenecks of HTTP implementations is that HTTP relies on 175 | multiple connections for concurrency. This causes several problems, 176 | including additional round trips for connection setup, slow-start 177 | delays, and connection rationing by the client, where it tries to 178 | avoid opening too many connections to any single server. HTTP 179 | pipelining helps some, but only achieves partial multiplexing. In 180 | addition, pipelining has proven non-deployable in existing browsers 181 | due to intermediary interference. 182 | 183 | SPDY adds a framing layer for multiplexing multiple, concurrent 184 | streams across a single TCP connection (or any reliable transport 185 | stream). The framing layer is optimized for HTTP-like request- 186 | response streams, such that applications which run over HTTP today 187 | can work over SPDY with little or no change on behalf of the web 188 | application writer. 189 | 190 | The SPDY session offers four improvements over HTTP: 191 | 192 | Multiplexed requests: There is no limit to the number of requests 193 | that can be issued concurrently over a single SPDY connection. 194 | 195 | Prioritized requests: Clients can request certain resources to be 196 | delivered first. This avoids the problem of congesting the 197 | network channel with non-critical resources when a high-priority 198 | request is pending. 199 | 200 | Compressed headers: Clients today send a significant amount of 201 | redundant data in the form of HTTP headers. Because a single web 202 | page may require 50 or 100 subrequests, this data is significant. 203 | 204 | Server pushed streams: Server Push enables content to be pushed 205 | from servers to clients without a request. 206 | 207 | SPDY attempts to preserve the existing semantics of HTTP. All 208 | features such as cookies, ETags, Vary headers, Content-Encoding 209 | negotiations, etc work as they do with HTTP; SPDY only replaces the 210 | way the data is written to the network. 211 | 212 | 1.1. Document Organization 213 | 214 | The SPDY Specification is split into two parts: a framing layer 215 | (Section 2), which multiplexes a TCP connection into independent, 216 | length-prefixed frames, and an HTTP layer (Section 3), which 217 | specifies the mechanism for overlaying HTTP request/response pairs on 218 | top of the framing layer. While some of the framing layer concepts 219 | are isolated from the HTTP layer, building a generic framing layer 220 | 221 | 222 | 223 | Belshe & Peon Expires August 4, 2012 [Page 4] 224 | 225 | Internet-Draft SPDY Feb 2012 226 | 227 | 228 | has not been a goal. The framing layer is tailored to the needs of 229 | the HTTP protocol and server push. 230 | 231 | 1.2. Definitions 232 | 233 | client: The endpoint initiating the SPDY session. 234 | 235 | connection: A transport-level connection between two endpoints. 236 | 237 | endpoint: Either the client or server of a connection. 238 | 239 | frame: A header-prefixed sequence of bytes sent over a SPDY 240 | session. 241 | 242 | server: The endpoint which did not initiate the SPDY session. 243 | 244 | session: A synonym for a connection. 245 | 246 | session error: An error on the SPDY session. 247 | 248 | stream: A bi-directional flow of bytes across a virtual channel 249 | within a SPDY session. 250 | 251 | stream error: An error on an individual SPDY stream. 252 | 253 | 254 | 255 | 256 | 257 | 258 | 259 | 260 | 261 | 262 | 263 | 264 | 265 | 266 | 267 | 268 | 269 | 270 | 271 | 272 | 273 | 274 | 275 | 276 | 277 | 278 | 279 | Belshe & Peon Expires August 4, 2012 [Page 5] 280 | 281 | Internet-Draft SPDY Feb 2012 282 | 283 | 284 | 2. SPDY Framing Layer 285 | 286 | 2.1. Session (Connections) 287 | 288 | The SPDY framing layer (or "session") runs atop a reliable transport 289 | layer such as TCP [RFC0793]. The client is the TCP connection 290 | initiator. SPDY connections are persistent connections. 291 | 292 | For best performance, it is expected that clients will not close open 293 | connections until the user navigates away from all web pages 294 | referencing a connection, or until the server closes the connection. 295 | Servers are encouraged to leave connections open for as long as 296 | possible, but can terminate idle connections if necessary. When 297 | either endpoint closes the transport-level connection, it MUST first 298 | send a GOAWAY (Section 2.6.6) frame so that the endpoints can 299 | reliably determine if requests finished before the close. 300 | 301 | 2.2. Framing 302 | 303 | Once the connection is established, clients and servers exchange 304 | framed messages. There are two types of frames: control frames 305 | (Section 2.2.1) and data frames (Section 2.2.2). Frames always have 306 | a common header which is 8 bytes in length. 307 | 308 | The first bit is a control bit indicating whether a frame is a 309 | control frame or data frame. Control frames carry a version number, 310 | a frame type, flags, and a length. Data frames contain the stream 311 | ID, flags, and the length for the payload carried after the common 312 | header. The simple header is designed to make reading and writing of 313 | frames easy. 314 | 315 | All integer values, including length, version, and type, are in 316 | network byte order. SPDY does not enforce alignment of types in 317 | dynamically sized frames. 318 | 319 | 2.2.1. Control frames 320 | 321 | +----------------------------------+ 322 | |C| Version(15bits) | Type(16bits) | 323 | +----------------------------------+ 324 | | Flags (8) | Length (24 bits) | 325 | +----------------------------------+ 326 | | Data | 327 | +----------------------------------+ 328 | 329 | Control bit: The 'C' bit is a single bit indicating if this is a 330 | control message. For control frames this value is always 1. 331 | 332 | 333 | 334 | 335 | Belshe & Peon Expires August 4, 2012 [Page 6] 336 | 337 | Internet-Draft SPDY Feb 2012 338 | 339 | 340 | Version: The version number of the SPDY protocol. This document 341 | describes SPDY version 3. 342 | 343 | Type: The type of control frame. See Control Frames for the complete 344 | list of control frames. 345 | 346 | Flags: Flags related to this frame. Flags for control frames and 347 | data frames are different. 348 | 349 | Length: An unsigned 24-bit value representing the number of bytes 350 | after the length field. 351 | 352 | Data: data associated with this control frame. The format and length 353 | of this data is controlled by the control frame type. 354 | 355 | Control frame processing requirements: 356 | 357 | Note that full length control frames (16MB) can be large for 358 | implementations running on resource-limited hardware. In such 359 | cases, implementations MAY limit the maximum length frame 360 | supported. However, all implementations MUST be able to receive 361 | control frames of at least 8192 octets in length. 362 | 363 | 2.2.2. Data frames 364 | 365 | +----------------------------------+ 366 | |C| Stream-ID (31bits) | 367 | +----------------------------------+ 368 | | Flags (8) | Length (24 bits) | 369 | +----------------------------------+ 370 | | Data | 371 | +----------------------------------+ 372 | 373 | Control bit: For data frames this value is always 0. 374 | 375 | Stream-ID: A 31-bit value identifying the stream. 376 | 377 | Flags: Flags related to this frame. Valid flags are: 378 | 379 | 0x01 = FLAG_FIN - signifies that this frame represents the last 380 | frame to be transmitted on this stream. See Stream Close 381 | (Section 2.3.7) below. 382 | 383 | 0x02 = FLAG_COMPRESS - indicates that the data in this frame has 384 | been compressed. 385 | 386 | Length: An unsigned 24-bit value representing the number of bytes 387 | after the length field. The total size of a data frame is 8 bytes + 388 | 389 | 390 | 391 | Belshe & Peon Expires August 4, 2012 [Page 7] 392 | 393 | Internet-Draft SPDY Feb 2012 394 | 395 | 396 | length. It is valid to have a zero-length data frame. 397 | 398 | Data: The variable-length data payload; the length was defined in the 399 | length field. 400 | 401 | Data frame processing requirements: 402 | 403 | If an endpoint receives a data frame for a stream-id which is not 404 | open and the endpoint has not sent a GOAWAY (Section 2.6.6) frame, 405 | it MUST send issue a stream error (Section 2.4.2) with the error 406 | code INVALID_STREAM for the stream-id. 407 | 408 | If the endpoint which created the stream receives a data frame 409 | before receiving a SYN_REPLY on that stream, it is a protocol 410 | error, and the recipient MUST issue a stream error (Section 2.4.2) 411 | with the status code PROTOCOL_ERROR for the stream-id. 412 | 413 | Implementors note: If an endpoint receives multiple data frames 414 | for invalid stream-ids, it MAY close the session. 415 | 416 | All SPDY endpoints MUST accept compressed data frames. 417 | Compression of data frames is always done using zlib compression. 418 | Each stream initializes and uses its own compression context 419 | dedicated to use within that stream. Endpoints are encouraged to 420 | use application level compression rather than SPDY stream level 421 | compression. 422 | 423 | Each SPDY stream sending compressed frames creates its own zlib 424 | context for that stream, and these compression contexts MUST be 425 | distinct from the compression contexts used with SYN_STREAM/ 426 | SYN_REPLY/HEADER compression. (Thus, if both endpoints of a 427 | stream are compressing data on the stream, there will be two zlib 428 | contexts, one for sending and one for receiving). 429 | 430 | 2.3. Streams 431 | 432 | Streams are independent sequences of bi-directional data divided into 433 | frames with several properties: 434 | 435 | Streams may be created by either the client or server. 436 | 437 | Streams optionally carry a set of name/value header pairs. 438 | 439 | Streams can concurrently send data interleaved with other streams. 440 | 441 | Streams may be cancelled. 442 | 443 | 444 | 445 | 446 | 447 | Belshe & Peon Expires August 4, 2012 [Page 8] 448 | 449 | Internet-Draft SPDY Feb 2012 450 | 451 | 452 | 2.3.1. Stream frames 453 | 454 | SPDY defines 3 control frames to manage the lifecycle of a stream: 455 | 456 | SYN_STREAM - Open a new stream 457 | 458 | SYN_REPLY - Remote acknowledgement of a new, open stream 459 | 460 | RST_STREAM - Close a stream 461 | 462 | 2.3.2. Stream creation 463 | 464 | A stream is created by sending a control frame with the type set to 465 | SYN_STREAM (Section 2.6.1). If the server is initiating the stream, 466 | the Stream-ID must be even. If the client is initiating the stream, 467 | the Stream-ID must be odd. 0 is not a valid Stream-ID. Stream-IDs 468 | from each side of the connection must increase monotonically as new 469 | streams are created. E.g. Stream 2 may be created after stream 3, 470 | but stream 7 must not be created after stream 9. Stream IDs do not 471 | wrap: when a client or server cannot create a new stream id without 472 | exceeding a 31 bit value, it MUST NOT create a new stream. 473 | 474 | The stream-id MUST increase with each new stream. If an endpoint 475 | receives a SYN_STREAM with a stream id which is less than any 476 | previously received SYN_STREAM, it MUST issue a session error 477 | (Section 2.4.1) with the status PROTOCOL_ERROR. 478 | 479 | It is a protocol error to send two SYN_STREAMs with the same 480 | stream-id. If a recipient receives a second SYN_STREAM for the same 481 | stream, it MUST issue a stream error (Section 2.4.2) with the status 482 | code PROTOCOL_ERROR. 483 | 484 | Upon receipt of a SYN_STREAM, the recipient can reject the stream by 485 | sending a stream error (Section 2.4.2) with the error code 486 | REFUSED_STREAM. Note, however, that the creating endpoint may have 487 | already sent additional frames for that stream which cannot be 488 | immediately stopped. 489 | 490 | Once the stream is created, the creator may immediately send HEADERS 491 | or DATA frames for that stream, without needing to wait for the 492 | recipient to acknowledge. 493 | 494 | 2.3.2.1. Unidirectional streams 495 | 496 | When an endpoint creates a stream with the FLAG_UNIDIRECTIONAL flag 497 | set, it creates a unidirectional stream which the creating endpoint 498 | can use to send frames, but the receiving endpoint cannot. The 499 | receiving endpoint is implicitly already in the half-closed 500 | 501 | 502 | 503 | Belshe & Peon Expires August 4, 2012 [Page 9] 504 | 505 | Internet-Draft SPDY Feb 2012 506 | 507 | 508 | (Section 2.3.6) state. 509 | 510 | 2.3.2.2. Bidirectional streams 511 | 512 | SYN_STREAM frames which do not use the FLAG_UNIDIRECTIONAL flag are 513 | bidirectional streams. Both endpoints can send data on a bi- 514 | directional stream. 515 | 516 | 2.3.3. Stream priority 517 | 518 | The creator of a stream assigns a priority for that stream. Priority 519 | is represented as an integer from 0 to 7. 0 represents the highest 520 | priority and 7 represents the lowest priority. 521 | 522 | The sender and recipient SHOULD use best-effort to process streams in 523 | the order of highest priority to lowest priority. 524 | 525 | 2.3.4. Stream headers 526 | 527 | Streams carry optional sets of name/value pair headers which carry 528 | metadata about the stream. After the stream has been created, and as 529 | long as the sender is not closed (Section 2.3.7) or half-closed 530 | (Section 2.3.6), each side may send HEADERS frame(s) containing the 531 | header data. Header data can be sent in multiple HEADERS frames, and 532 | HEADERS frames may be interleaved with data frames. 533 | 534 | 2.3.5. Stream data exchange 535 | 536 | Once a stream is created, it can be used to send arbitrary amounts of 537 | data. Generally this means that a series of data frames will be sent 538 | on the stream until a frame containing the FLAG_FIN flag is set. The 539 | FLAG_FIN can be set on a SYN_STREAM (Section 2.6.1), SYN_REPLY 540 | (Section 2.6.2), HEADERS (Section 2.6.7) or a DATA (Section 2.2.2) 541 | frame. Once the FLAG_FIN has been sent, the stream is considered to 542 | be half-closed. 543 | 544 | 2.3.6. Stream half-close 545 | 546 | When one side of the stream sends a frame with the FLAG_FIN flag set, 547 | the stream is half-closed from that endpoint. The sender of the 548 | FLAG_FIN MUST NOT send further frames on that stream. When both 549 | sides have half-closed, the stream is closed. 550 | 551 | If an endpoint receives a data frame after the stream is half-closed 552 | from the sender (e.g. the endpoint has already received a prior frame 553 | for the stream with the FIN flag set), it MUST send a RST_STREAM to 554 | the sender with the status STREAM_ALREADY_CLOSED. 555 | 556 | 557 | 558 | 559 | Belshe & Peon Expires August 4, 2012 [Page 10] 560 | 561 | Internet-Draft SPDY Feb 2012 562 | 563 | 564 | 2.3.7. Stream close 565 | 566 | There are 3 ways that streams can be terminated: 567 | 568 | Normal termination: Normal stream termination occurs when both 569 | sender and recipient have half-closed the stream by sending a 570 | FLAG_FIN. 571 | 572 | Abrupt termination: Either the client or server can send a 573 | RST_STREAM control frame at any time. A RST_STREAM contains an 574 | error code to indicate the reason for failure. When a RST_STREAM 575 | is sent from the stream originator, it indicates a failure to 576 | complete the stream and that no further data will be sent on the 577 | stream. When a RST_STREAM is sent from the stream recipient, the 578 | sender, upon receipt, should stop sending any data on the stream. 579 | The stream recipient should be aware that there is a race between 580 | data already in transit from the sender and the time the 581 | RST_STREAM is received. See Stream Error Handling (Section 2.4.2) 582 | 583 | TCP connection teardown: If the TCP connection is torn down while 584 | un-closed streams exist, then the endpoint must assume that the 585 | stream was abnormally interrupted and may be incomplete. 586 | 587 | If an endpoint receives a data frame after the stream is closed, it 588 | must send a RST_STREAM to the sender with the status PROTOCOL_ERROR. 589 | 590 | 2.4. Error Handling 591 | 592 | The SPDY framing layer has only two types of errors, and they are 593 | always handled consistently. Any reference in this specification to 594 | "issue a session error" refers to Section 2.4.1. Any reference to 595 | "issue a stream error" refers to Section 2.4.2. 596 | 597 | 2.4.1. Session Error Handling 598 | 599 | A session error is any error which prevents further processing of the 600 | framing layer or which corrupts the session compression state. When 601 | a session error occurs, the endpoint encountering the error MUST 602 | first send a GOAWAY (Section 2.6.6) frame with the stream id of most 603 | recently received stream from the remote endpoint, and the error code 604 | for why the session is terminating. After sending the GOAWAY frame, 605 | the endpoint MUST close the TCP connection. 606 | 607 | Note that the session compression state is dependent upon both 608 | endpoints always processing all compressed data. If an endpoint 609 | partially processes a frame containing compressed data without 610 | updating compression state properly, future control frames which use 611 | compression will be always be errored. Implementations SHOULD always 612 | 613 | 614 | 615 | Belshe & Peon Expires August 4, 2012 [Page 11] 616 | 617 | Internet-Draft SPDY Feb 2012 618 | 619 | 620 | try to process compressed data so that errors which could be handled 621 | as stream errors do not become session errors. 622 | 623 | Note that because this GOAWAY is sent during a session error case, it 624 | is possible that the GOAWAY will not be reliably received by the 625 | receiving endpoint. It is a best-effort attempt to communicate with 626 | the remote about why the session is going down. 627 | 628 | 2.4.2. Stream Error Handling 629 | 630 | A stream error is an error related to a specific stream-id which does 631 | not affect processing of other streams at the framing layer. Upon a 632 | stream error, the endpoint MUST send a RST_STREAM (Section 2.6.3) 633 | frame which contains the stream id of the stream where the error 634 | occurred and the error status which caused the error. After sending 635 | the RST_STREAM, the stream is closed to the sending endpoint. After 636 | sending the RST_STREAM, if the sender receives any frames other than 637 | a RST_STREAM for that stream id, it will result in sending additional 638 | RST_STREAM frames. An endpoint MUST NOT send a RST_STREAM in 639 | response to an RST_STREAM, as doing so would lead to RST_STREAM 640 | loops. Sending a RST_STREAM does not cause the SPDY session to be 641 | closed. 642 | 643 | If an endpoint has multiple RST_STREAM frames to send in succession 644 | for the same stream-id and the same error code, it MAY coalesce them 645 | into a single RST_STREAM frame. (This can happen if a stream is 646 | closed, but the remote sends multiple data frames. There is no 647 | reason to send a RST_STREAM for each frame in succession). 648 | 649 | 2.5. Data flow 650 | 651 | Because TCP provides a single stream of data on which SPDY 652 | multiplexes multiple logical streams, clients and servers must 653 | intelligently interleave data messages for concurrent sessions. 654 | 655 | 2.6. Control frame types 656 | 657 | 2.6.1. SYN_STREAM 658 | 659 | The SYN_STREAM control frame allows the sender to asynchronously 660 | create a stream between the endpoints. See Stream Creation 661 | (Section 2.3.2) 662 | 663 | 664 | 665 | 666 | 667 | 668 | 669 | 670 | 671 | Belshe & Peon Expires August 4, 2012 [Page 12] 672 | 673 | Internet-Draft SPDY Feb 2012 674 | 675 | 676 | +------------------------------------+ 677 | |1| version | 1 | 678 | +------------------------------------+ 679 | | Flags (8) | Length (24 bits) | 680 | +------------------------------------+ 681 | |X| Stream-ID (31bits) | 682 | +------------------------------------+ 683 | |X| Associated-To-Stream-ID (31bits) | 684 | +------------------------------------+ 685 | | Pri|Unused | Slot | | 686 | +-------------------+ | 687 | | Number of Name/Value pairs (int32) | <+ 688 | +------------------------------------+ | 689 | | Length of name (int32) | | This section is the "Name/Value 690 | +------------------------------------+ | Header Block", and is compressed. 691 | | Name (string) | | 692 | +------------------------------------+ | 693 | | Length of value (int32) | | 694 | +------------------------------------+ | 695 | | Value (string) | | 696 | +------------------------------------+ | 697 | | (repeats) | <+ 698 | 699 | Flags: Flags related to this frame. Valid flags are: 700 | 701 | 0x01 = FLAG_FIN - marks this frame as the last frame to be 702 | transmitted on this stream and puts the sender in the half-closed 703 | (Section 2.3.6) state. 704 | 705 | 0x02 = FLAG_UNIDIRECTIONAL - a stream created with this flag puts 706 | the recipient in the half-closed (Section 2.3.6) state. 707 | 708 | Length: The length is the number of bytes which follow the length 709 | field in the frame. For SYN_STREAM frames, this is 10 bytes plus the 710 | length of the compressed Name/Value block. 711 | 712 | Stream-ID: The 31-bit identifier for this stream. This stream-id 713 | will be used in frames which are part of this stream. 714 | 715 | Associated-To-Stream-ID: The 31-bit identifier for a stream which 716 | this stream is associated to. If this stream is independent of all 717 | other streams, it should be 0. 718 | 719 | Priority: A 3-bit priority (Section 2.3.3) field. 720 | 721 | Unused: 5 bits of unused space, reserved for future use. 722 | 723 | Slot: An 8 bit unsigned integer specifying the index in the server's 724 | 725 | 726 | 727 | Belshe & Peon Expires August 4, 2012 [Page 13] 728 | 729 | Internet-Draft SPDY Feb 2012 730 | 731 | 732 | CREDENTIAL vector of the client certificate to be used for this 733 | request. see CREDENTIAL frame (Section 2.6.9). The value 0 means no 734 | client certificate should be associated with this stream. 735 | 736 | Name/Value Header Block: A set of name/value pairs carried as part of 737 | the SYN_STREAM. see Name/Value Header Block (Section 2.6.10). 738 | 739 | If an endpoint receives a SYN_STREAM which is larger than the 740 | implementation supports, it MAY send a RST_STREAM with error code 741 | FRAME_TOO_LARGE. All implementations MUST support the minimum size 742 | limits defined in the Control Frames section (Section 2.2.1). 743 | 744 | 2.6.2. SYN_REPLY 745 | 746 | SYN_REPLY indicates the acceptance of a stream creation by the 747 | recipient of a SYN_STREAM frame. 748 | 749 | +------------------------------------+ 750 | |1| version | 2 | 751 | +------------------------------------+ 752 | | Flags (8) | Length (24 bits) | 753 | +------------------------------------+ 754 | |X| Stream-ID (31bits) | 755 | +------------------------------------+ 756 | | Number of Name/Value pairs (int32) | <+ 757 | +------------------------------------+ | 758 | | Length of name (int32) | | This section is the "Name/Value 759 | +------------------------------------+ | Header Block", and is compressed. 760 | | Name (string) | | 761 | +------------------------------------+ | 762 | | Length of value (int32) | | 763 | +------------------------------------+ | 764 | | Value (string) | | 765 | +------------------------------------+ | 766 | | (repeats) | <+ 767 | 768 | Flags: Flags related to this frame. Valid flags are: 769 | 770 | 0x01 = FLAG_FIN - marks this frame as the last frame to be 771 | transmitted on this stream and puts the sender in the half-closed 772 | (Section 2.3.6) state. 773 | 774 | Length: The length is the number of bytes which follow the length 775 | field in the frame. For SYN_REPLY frames, this is 4 bytes plus the 776 | length of the compressed Name/Value block. 777 | 778 | Stream-ID: The 31-bit identifier for this stream. 779 | 780 | 781 | 782 | 783 | Belshe & Peon Expires August 4, 2012 [Page 14] 784 | 785 | Internet-Draft SPDY Feb 2012 786 | 787 | 788 | If an endpoint receives multiple SYN_REPLY frames for the same active 789 | stream ID, it MUST issue a stream error (Section 2.4.2) with the 790 | error code STREAM_IN_USE. 791 | 792 | Name/Value Header Block: A set of name/value pairs carried as part of 793 | the SYN_STREAM. see Name/Value Header Block (Section 2.6.10). 794 | 795 | If an endpoint receives a SYN_REPLY which is larger than the 796 | implementation supports, it MAY send a RST_STREAM with error code 797 | FRAME_TOO_LARGE. All implementations MUST support the minimum size 798 | limits defined in the Control Frames section (Section 2.2.1). 799 | 800 | 2.6.3. RST_STREAM 801 | 802 | The RST_STREAM frame allows for abnormal termination of a stream. 803 | When sent by the creator of a stream, it indicates the creator wishes 804 | to cancel the stream. When sent by the recipient of a stream, it 805 | indicates an error or that the recipient did not want to accept the 806 | stream, so the stream should be closed. 807 | 808 | +----------------------------------+ 809 | |1| version | 3 | 810 | +----------------------------------+ 811 | | Flags (8) | 8 | 812 | +----------------------------------+ 813 | |X| Stream-ID (31bits) | 814 | +----------------------------------+ 815 | | Status code | 816 | +----------------------------------+ 817 | 818 | Flags: Flags related to this frame. RST_STREAM does not define any 819 | flags. This value must be 0. 820 | 821 | Length: An unsigned 24-bit value representing the number of bytes 822 | after the length field. For RST_STREAM control frames, this value is 823 | always 8. 824 | 825 | Stream-ID: The 31-bit identifier for this stream. 826 | 827 | Status code: (32 bits) An indicator for why the stream is being 828 | terminated.The following status codes are defined: 829 | 830 | 1 - PROTOCOL_ERROR. This is a generic error, and should only be 831 | used if a more specific error is not available. 832 | 833 | 2 - INVALID_STREAM. This is returned when a frame is received for 834 | a stream which is not active. 835 | 836 | 837 | 838 | 839 | Belshe & Peon Expires August 4, 2012 [Page 15] 840 | 841 | Internet-Draft SPDY Feb 2012 842 | 843 | 844 | 3 - REFUSED_STREAM. Indicates that the stream was refused before 845 | any processing has been done on the stream. 846 | 847 | 4 - UNSUPPORTED_VERSION. Indicates that the recipient of a stream 848 | does not support the SPDY version requested. 849 | 850 | 5 - CANCEL. Used by the creator of a stream to indicate that the 851 | stream is no longer needed. 852 | 853 | 6 - INTERNAL_ERROR. This is a generic error which can be used 854 | when the implementation has internally failed, not due to anything 855 | in the protocol. 856 | 857 | 7 - FLOW_CONTROL_ERROR. The endpoint detected that its peer 858 | violated the flow control protocol. 859 | 860 | 8 - STREAM_IN_USE. The endpoint received a SYN_REPLY for a stream 861 | already open. 862 | 863 | 9 - STREAM_ALREADY_CLOSED. The endpoint received a data or 864 | SYN_REPLY frame for a stream which is half closed. 865 | 866 | 10 - INVALID_CREDENTIALS. The server received a request for a 867 | resource whose origin does not have valid credentials in the 868 | client certificate vector. 869 | 870 | 11 - FRAME_TOO_LARGE. The endpoint received a frame which this 871 | implementation could not support. If FRAME_TOO_LARGE is sent for 872 | a SYN_STREAM, HEADERS, or SYN_REPLY frame without fully processing 873 | the compressed portion of those frames, then the compression state 874 | will be out-of-sync with the other endpoint. In this case, 875 | senders of FRAME_TOO_LARGE MUST close the session. 876 | 877 | Note: 0 is not a valid status code for a RST_STREAM. 878 | 879 | After receiving a RST_STREAM on a stream, the recipient must not send 880 | additional frames for that stream, and the stream moves into the 881 | closed state. 882 | 883 | 2.6.4. SETTINGS 884 | 885 | A SETTINGS frame contains a set of id/value pairs for communicating 886 | configuration data about how the two endpoints may communicate. 887 | SETTINGS frames can be sent at any time by either endpoint, are 888 | optionally sent, and are fully asynchronous. When the server is the 889 | sender, the sender can request that configuration data be persisted 890 | by the client across SPDY sessions and returned to the server in 891 | future communications. 892 | 893 | 894 | 895 | Belshe & Peon Expires August 4, 2012 [Page 16] 896 | 897 | Internet-Draft SPDY Feb 2012 898 | 899 | 900 | Persistence of SETTINGS ID/Value pairs is done on a per origin/IP 901 | pair (the "origin" is the set of scheme, host, and port from the URI. 902 | See [RFC6454]). That is, when a client connects to a server, and the 903 | server persists settings within the client, the client SHOULD return 904 | the persisted settings on future connections to the same origin AND 905 | IP address and TCP port. Clients MUST NOT request servers to use the 906 | persistence features of the SETTINGS frames, and servers MUST ignore 907 | persistence related flags sent by a client. 908 | 909 | +----------------------------------+ 910 | |1| version | 4 | 911 | +----------------------------------+ 912 | | Flags (8) | Length (24 bits) | 913 | +----------------------------------+ 914 | | Number of entries | 915 | +----------------------------------+ 916 | | ID/Value Pairs | 917 | | ... | 918 | 919 | Control bit: The control bit is always 1 for this message. 920 | 921 | Version: The SPDY version number. 922 | 923 | Type: The message type for a SETTINGS message is 4. 924 | 925 | Flags: FLAG_SETTINGS_CLEAR_SETTINGS (0x1): When set, the client 926 | should clear any previously persisted SETTINGS ID/Value pairs. If 927 | this frame contains ID/Value pairs with the 928 | FLAG_SETTINGS_PERSIST_VALUE set, then the client will first clear its 929 | existing, persisted settings, and then persist the values with the 930 | flag set which are contained within this frame. Because persistence 931 | is only implemented on the client, this flag can only be used when 932 | the sender is the server. 933 | 934 | Length: An unsigned 24-bit value representing the number of bytes 935 | after the length field. The total size of a SETTINGS frame is 8 936 | bytes + length. 937 | 938 | Number of entries: A 32-bit value representing the number of ID/value 939 | pairs in this message. 940 | 941 | ID: A 32-bit ID number, comprised of 8 bits of flags and 24 bits of 942 | unique ID. 943 | 944 | ID.flags: 945 | 946 | FLAG_SETTINGS_PERSIST_VALUE (0x1): When set, the sender of this 947 | SETTINGS frame is requesting that the recipient persist the ID/ 948 | 949 | 950 | 951 | Belshe & Peon Expires August 4, 2012 [Page 17] 952 | 953 | Internet-Draft SPDY Feb 2012 954 | 955 | 956 | Value and return it in future SETTINGS frames sent from the 957 | sender to this recipient. Because persistence is only 958 | implemented on the client, this flag is only sent by the 959 | server. 960 | 961 | FLAG_SETTINGS_PERSISTED (0x2): When set, the sender is 962 | notifying the recipient that this ID/Value pair was previously 963 | sent to the sender by the recipient with the 964 | FLAG_SETTINGS_PERSIST_VALUE, and the sender is returning it. 965 | Because persistence is only implemented on the client, this 966 | flag is only sent by the client. 967 | 968 | Defined IDs: 969 | 970 | 1 - SETTINGS_UPLOAD_BANDWIDTH allows the sender to send its 971 | expected upload bandwidth on this channel. This number is an 972 | estimate. The value should be the integral number of kilobytes 973 | per second that the sender predicts as an expected maximum 974 | upload channel capacity. 975 | 976 | 2 - SETTINGS_DOWNLOAD_BANDWIDTH allows the sender to send its 977 | expected download bandwidth on this channel. This number is an 978 | estimate. The value should be the integral number of kilobytes 979 | per second that the sender predicts as an expected maximum 980 | download channel capacity. 981 | 982 | 3 - SETTINGS_ROUND_TRIP_TIME allows the sender to send its 983 | expected round-trip-time on this channel. The round trip time 984 | is defined as the minimum amount of time to send a control 985 | frame from this client to the remote and receive a response. 986 | The value is represented in milliseconds. 987 | 988 | 4 - SETTINGS_MAX_CONCURRENT_STREAMS allows the sender to inform 989 | the remote endpoint the maximum number of concurrent streams 990 | which it will allow. By default there is no limit. For 991 | implementors it is recommended that this value be no smaller 992 | than 100. 993 | 994 | 5 - SETTINGS_CURRENT_CWND allows the sender to inform the 995 | remote endpoint of the current TCP CWND value. 996 | 997 | 6 - SETTINGS_DOWNLOAD_RETRANS_RATE allows the sender to inform 998 | the remote endpoint the retransmission rate (bytes 999 | retransmitted / total bytes transmitted). 1000 | 1001 | 7 - SETTINGS_INITIAL_WINDOW_SIZE allows the sender to inform 1002 | the remote endpoint the initial window size (in bytes) for new 1003 | streams. 1004 | 1005 | 1006 | 1007 | Belshe & Peon Expires August 4, 2012 [Page 18] 1008 | 1009 | Internet-Draft SPDY Feb 2012 1010 | 1011 | 1012 | 8 - SETTINGS_CLIENT_CERTIFICATE_VECTOR_SIZE allows the server 1013 | to inform the client if the new size of the client certificate 1014 | vector. 1015 | 1016 | Value: A 32-bit value. 1017 | 1018 | The message is intentionally extensible for future information which 1019 | may improve client-server communications. The sender does not need 1020 | to send every type of ID/value. It must only send those for which it 1021 | has accurate values to convey. When multiple ID/value pairs are 1022 | sent, they should be sent in order of lowest id to highest id. A 1023 | single SETTINGS frame MUST not contain multiple values for the same 1024 | ID. If the recipient of a SETTINGS frame discovers multiple values 1025 | for the same ID, it MUST ignore all values except the first one. 1026 | 1027 | A server may send multiple SETTINGS frames containing different ID/ 1028 | Value pairs. When the same ID/Value is sent twice, the most recent 1029 | value overrides any previously sent values. If the server sends IDs 1030 | 1, 2, and 3 with the FLAG_SETTINGS_PERSIST_VALUE in a first SETTINGS 1031 | frame, and then sends IDs 4 and 5 with the 1032 | FLAG_SETTINGS_PERSIST_VALUE, when the client returns the persisted 1033 | state on its next SETTINGS frame, it SHOULD send all 5 settings (1, 1034 | 2, 3, 4, and 5 in this example) to the server. 1035 | 1036 | 2.6.5. PING 1037 | 1038 | The PING control frame is a mechanism for measuring a minimal round- 1039 | trip time from the sender. It can be sent from the client or the 1040 | server. Recipients of a PING frame should send an identical frame to 1041 | the sender as soon as possible (if there is other pending data 1042 | waiting to be sent, PING should take highest priority). Each ping 1043 | sent by a sender should use a unique ID. 1044 | 1045 | +----------------------------------+ 1046 | |1| version | 6 | 1047 | +----------------------------------+ 1048 | | 0 (flags) | 4 (length) | 1049 | +----------------------------------| 1050 | | 32-bit ID | 1051 | +----------------------------------+ 1052 | 1053 | Control bit: The control bit is always 1 for this message. 1054 | 1055 | Version: The SPDY version number. 1056 | 1057 | Type: The message type for a PING message is 6. 1058 | 1059 | Length: This frame is always 4 bytes long. 1060 | 1061 | 1062 | 1063 | Belshe & Peon Expires August 4, 2012 [Page 19] 1064 | 1065 | Internet-Draft SPDY Feb 2012 1066 | 1067 | 1068 | ID: A unique ID for this ping, represented as an unsigned 32 bit 1069 | value. When the client initiates a ping, it must use an odd numbered 1070 | ID. When the server initiates a ping, it must use an even numbered 1071 | ping. Use of odd/even IDs is required in order to avoid accidental 1072 | looping on PINGs (where each side initiates an identical PING at the 1073 | same time). 1074 | 1075 | Note: If a sender uses all possible PING ids (e.g. has sent all 2^31 1076 | possible IDs), it can wrap and start re-using IDs. 1077 | 1078 | If a server receives an even numbered PING which it did not initiate, 1079 | it must ignore the PING. If a client receives an odd numbered PING 1080 | which it did not initiate, it must ignore the PING. 1081 | 1082 | 2.6.6. GOAWAY 1083 | 1084 | The GOAWAY control frame is a mechanism to tell the remote side of 1085 | the connection to stop creating streams on this session. It can be 1086 | sent from the client or the server. Once sent, the sender will not 1087 | respond to any new SYN_STREAMs on this session. Recipients of a 1088 | GOAWAY frame must not send additional streams on this session, 1089 | although a new session can be established for new streams. The 1090 | purpose of this message is to allow an endpoint to gracefully stop 1091 | accepting new streams (perhaps for a reboot or maintenance), while 1092 | still finishing processing of previously established streams. 1093 | 1094 | There is an inherent race condition between an endpoint sending 1095 | SYN_STREAMs and the remote sending a GOAWAY message. To deal with 1096 | this case, the GOAWAY contains a last-stream-id indicating the 1097 | stream-id of the last stream which was created on the sending 1098 | endpoint in this session. If the receiver of the GOAWAY sent new 1099 | SYN_STREAMs for sessions after this last-stream-id, they were not 1100 | processed by the server and the receiver may treat the stream as 1101 | though it had never been created at all (hence the receiver may want 1102 | to re-create the stream later on a new session). 1103 | 1104 | Endpoints should always send a GOAWAY message before closing a 1105 | connection so that the remote can know whether a stream has been 1106 | partially processed or not. (For example, if an HTTP client sends a 1107 | POST at the same time that a server closes a connection, the client 1108 | cannot know if the server started to process that POST request if the 1109 | server does not send a GOAWAY frame to indicate where it stopped 1110 | working). 1111 | 1112 | After sending a GOAWAY message, the sender must ignore all SYN_STREAM 1113 | frames for new streams. 1114 | 1115 | 1116 | 1117 | 1118 | 1119 | Belshe & Peon Expires August 4, 2012 [Page 20] 1120 | 1121 | Internet-Draft SPDY Feb 2012 1122 | 1123 | 1124 | +----------------------------------+ 1125 | |1| version | 7 | 1126 | +----------------------------------+ 1127 | | 0 (flags) | 8 (length) | 1128 | +----------------------------------| 1129 | |X| Last-good-stream-ID (31 bits) | 1130 | +----------------------------------+ 1131 | | Status code | 1132 | +----------------------------------+ 1133 | 1134 | Control bit: The control bit is always 1 for this message. 1135 | 1136 | Version: The SPDY version number. 1137 | 1138 | Type: The message type for a GOAWAY message is 7. 1139 | 1140 | Length: This frame is always 8 bytes long. 1141 | 1142 | Last-good-stream-Id: The last stream id which was replied to (with 1143 | either a SYN_REPLY or RST_STREAM) by the sender of the GOAWAY 1144 | message. If no streams were replied to, this value MUST be 0. 1145 | 1146 | Status: The reason for closing the session. 1147 | 1148 | 0 - OK. This is a normal session teardown. 1149 | 1150 | 1 - PROTOCOL_ERROR. This is a generic error, and should only be 1151 | used if a more specific error is not available. 1152 | 1153 | 11 - INTERNAL_ERROR. This is a generic error which can be used 1154 | when the implementation has internally failed, not due to anything 1155 | in the protocol. 1156 | 1157 | 2.6.7. HEADERS 1158 | 1159 | The HEADERS frame augments a stream with additional headers. It may 1160 | be optionally sent on an existing stream at any time. Specific 1161 | application of the headers in this frame is application-dependent. 1162 | The name/value header block within this frame is compressed. 1163 | 1164 | 1165 | 1166 | 1167 | 1168 | 1169 | 1170 | 1171 | 1172 | 1173 | 1174 | 1175 | Belshe & Peon Expires August 4, 2012 [Page 21] 1176 | 1177 | Internet-Draft SPDY Feb 2012 1178 | 1179 | 1180 | +------------------------------------+ 1181 | |1| version | 8 | 1182 | +------------------------------------+ 1183 | | Flags (8) | Length (24 bits) | 1184 | +------------------------------------+ 1185 | |X| Stream-ID (31bits) | 1186 | +------------------------------------+ 1187 | | Number of Name/Value pairs (int32) | <+ 1188 | +------------------------------------+ | 1189 | | Length of name (int32) | | This section is the "Name/Value 1190 | +------------------------------------+ | Header Block", and is compressed. 1191 | | Name (string) | | 1192 | +------------------------------------+ | 1193 | | Length of value (int32) | | 1194 | +------------------------------------+ | 1195 | | Value (string) | | 1196 | +------------------------------------+ | 1197 | | (repeats) | <+ 1198 | 1199 | Flags: Flags related to this frame. Valid flags are: 1200 | 1201 | 0x01 = FLAG_FIN - marks this frame as the last frame to be 1202 | transmitted on this stream and puts the sender in the half-closed 1203 | (Section 2.3.6) state. 1204 | 1205 | Length: An unsigned 24 bit value representing the number of bytes 1206 | after the length field. The minimum length of the length field is 4 1207 | (when the number of name value pairs is 0). 1208 | 1209 | Stream-ID: The stream this HEADERS block is associated with. 1210 | 1211 | Name/Value Header Block: A set of name/value pairs carried as part of 1212 | the SYN_STREAM. see Name/Value Header Block (Section 2.6.10). 1213 | 1214 | 2.6.8. WINDOW_UPDATE 1215 | 1216 | The WINDOW_UPDATE control frame is used to implement per stream flow 1217 | control in SPDY. Flow control in SPDY is per hop, that is, only 1218 | between the two endpoints of a SPDY connection. If there are one or 1219 | more intermediaries between the client and the origin server, flow 1220 | control signals are not explicitly forwarded by the intermediaries. 1221 | (However, throttling of data transfer by any recipient may have the 1222 | effect of indirectly propagating flow control information upstream 1223 | back to the original sender.) Flow control only applies to the data 1224 | portion of data frames. Recipients must buffer all control frames. 1225 | If a recipient fails to buffer an entire control frame, it MUST issue 1226 | a stream error (Section 2.4.2) with the status code 1227 | FLOW_CONTROL_ERROR for the stream. 1228 | 1229 | 1230 | 1231 | Belshe & Peon Expires August 4, 2012 [Page 22] 1232 | 1233 | Internet-Draft SPDY Feb 2012 1234 | 1235 | 1236 | Flow control in SPDY is implemented by a data transfer window kept by 1237 | the sender of each stream. The data transfer window is a simple 1238 | uint32 that indicates how many bytes of data the sender can transmit. 1239 | After a stream is created, but before any data frames have been 1240 | transmitted, the sender begins with the initial window size. This 1241 | window size is a measure of the buffering capability of the 1242 | recipient. The sender must not send a data frame with data length 1243 | greater than the transfer window size. After sending each data 1244 | frame, the sender decrements its transfer window size by the amount 1245 | of data transmitted. When the window size becomes less than or equal 1246 | to 0, the sender must pause transmitting data frames. At the other 1247 | end of the stream, the recipient sends a WINDOW_UPDATE control back 1248 | to notify the sender that it has consumed some data and freed up 1249 | buffer space to receive more data. 1250 | 1251 | +----------------------------------+ 1252 | |1| version | 9 | 1253 | +----------------------------------+ 1254 | | 0 (flags) | 8 (length) | 1255 | +----------------------------------+ 1256 | |X| Stream-ID (31-bits) | 1257 | +----------------------------------+ 1258 | |X| Delta-Window-Size (31-bits) | 1259 | +----------------------------------+ 1260 | 1261 | Control bit: The control bit is always 1 for this message. 1262 | 1263 | Version: The SPDY version number. 1264 | 1265 | Type: The message type for a WINDOW_UPDATE message is 9. 1266 | 1267 | Length: The length field is always 8 for this frame (there are 8 1268 | bytes after the length field). 1269 | 1270 | Stream-ID: The stream ID that this WINDOW_UPDATE control frame is 1271 | for. 1272 | 1273 | Delta-Window-Size: The additional number of bytes that the sender can 1274 | transmit in addition to existing remaining window size. The legal 1275 | range for this field is 1 to 2^31 - 1 (0x7fffffff) bytes. 1276 | 1277 | The window size as kept by the sender must never exceed 2^31 1278 | (although it can become negative in one special case). If a sender 1279 | receives a WINDOW_UPDATE that causes the its window size to exceed 1280 | this limit, it must send RST_STREAM with status code 1281 | FLOW_CONTROL_ERROR to terminate the stream. 1282 | 1283 | When a SPDY connection is first established, the default initial 1284 | 1285 | 1286 | 1287 | Belshe & Peon Expires August 4, 2012 [Page 23] 1288 | 1289 | Internet-Draft SPDY Feb 2012 1290 | 1291 | 1292 | window size for all streams is 64KB. An endpoint can use the 1293 | SETTINGS control frame to adjust the initial window size for the 1294 | connection. That is, its peer can start out using the 64KB default 1295 | initial window size when sending data frames before receiving the 1296 | SETTINGS. Because SETTINGS is asynchronous, there may be a race 1297 | condition if the recipient wants to decrease the initial window size, 1298 | but its peer immediately sends 64KB on the creation of a new 1299 | connection, before waiting for the SETTINGS to arrive. This is one 1300 | case where the window size kept by the sender will become negative. 1301 | Once the sender detects this condition, it must stop sending data 1302 | frames and wait for the recipient to catch up. The recipient has two 1303 | choices: 1304 | 1305 | immediately send RST_STREAM with FLOW_CONTROL_ERROR status code. 1306 | 1307 | allow the head of line blocking (as there is only one stream for 1308 | the session and the amount of data in flight is bounded by the 1309 | default initial window size), and send WINDOW_UPDATE as it 1310 | consumes data. 1311 | 1312 | In the case of option 2, both sides must compute the window size 1313 | based on the initial window size in the SETTINGS. For example, if 1314 | the recipient sets the initial window size to be 16KB, and the sender 1315 | sends 64KB immediately on connection establishment, the sender will 1316 | discover its window size is -48KB on receipt of the SETTINGS. As the 1317 | recipient consumes the first 16KB, it must send a WINDOW_UPDATE of 1318 | 16KB back to the sender. This interaction continues until the 1319 | sender's window size becomes positive again, and it can resume 1320 | transmitting data frames. 1321 | 1322 | After the recipient reads in a data frame with FLAG_FIN that marks 1323 | the end of the data stream, it should not send WINDOW_UPDATE frames 1324 | as it consumes the last data frame. A sender should ignore all the 1325 | WINDOW_UPDATE frames associated with the stream after it send the 1326 | last frame for the stream. 1327 | 1328 | The data frames from the sender and the WINDOW_UPDATE frames from the 1329 | recipient are completely asynchronous with respect to each other. 1330 | This property allows a recipient to aggressively update the window 1331 | size kept by the sender to prevent the stream from stalling. 1332 | 1333 | 2.6.9. CREDENTIAL 1334 | 1335 | The CREDENTIAL control frame is used by the client to send additional 1336 | client certificates to the server. A SPDY client may decide to send 1337 | requests for resources from different origins on the same SPDY 1338 | session if it decides that that server handles both origins. For 1339 | example if the IP address associated with both hostnames matches and 1340 | 1341 | 1342 | 1343 | Belshe & Peon Expires August 4, 2012 [Page 24] 1344 | 1345 | Internet-Draft SPDY Feb 2012 1346 | 1347 | 1348 | the SSL server certificate presented in the initial handshake is 1349 | valid for both hostnames. However, because the SSL connection can 1350 | contain at most one client certificate, the client needs a mechanism 1351 | to send additional client certificates to the server. 1352 | 1353 | The server is required to maintain a vector of client certificates 1354 | associated with a SPDY session. When the client needs to send a 1355 | client certificate to the server, it will send a CREDENTIAL frame 1356 | that specifies the index of the slot in which to store the 1357 | certificate as well as proof that the client posesses the 1358 | corresponding private key. The initial size of this vector must be 1359 | 8. If the client provides a client certificate during the first TLS 1360 | handshake, the contents of this certificate must be copied into the 1361 | first slot (index 1) in the CREDENTIAL vector, though it may be 1362 | overwritten by subsequent CREDENTIAL frames. The server must 1363 | exclusively use the CREDNETIAL vector when evaluating the client 1364 | certificates associated with an origin. The server may change the 1365 | size of this vector by sending a SETTINGS frame with the setting 1366 | SETTINGS_CLIENT_CERTIFICATE_VECTOR_SIZE value specified. In the 1367 | event that the new size is smaller than the current size, truncation 1368 | occurs preserving lower-index slots as possible. 1369 | 1370 | TLS renegotiation with client authentication is incompatible with 1371 | SPDY given the multiplexed nature of SPDY. Specifically, imagine 1372 | that the client has 2 requests outstanding to the server for two 1373 | different pages (in different tabs). When the renegotiation + client 1374 | certificate request comes in, the browser is unable to determine 1375 | which resource triggered the client certificate request, in order to 1376 | prompt the user accordingly. 1377 | 1378 | +----------------------------------+ 1379 | |1|000000000000001|0000000000001011| 1380 | +----------------------------------+ 1381 | | flags (8) | Length (24 bits) | 1382 | +----------------------------------+ 1383 | | Slot (16 bits) | | 1384 | +-----------------+ | 1385 | | Proof Length (32 bits) | 1386 | +----------------------------------+ 1387 | | Proof | 1388 | +----------------------------------+ <+ 1389 | | Certificate Length (32 bits) | | 1390 | +----------------------------------+ | Repeated until end of frame 1391 | | Certificate | | 1392 | +----------------------------------+ <+ 1393 | 1394 | Slot: The index in the server's client certificate vector where this 1395 | certificate should be stored. If there is already a certificate 1396 | 1397 | 1398 | 1399 | Belshe & Peon Expires August 4, 2012 [Page 25] 1400 | 1401 | Internet-Draft SPDY Feb 2012 1402 | 1403 | 1404 | stored at this index, it will be overwritten. The index is one 1405 | based, not zero based; zero is an invalid slot index. 1406 | 1407 | Proof: Cryptographic proof that the client has possession of the 1408 | private key associated with the certificate. The format is a TLS 1409 | digitally-signed element 1410 | (http://tools.ietf.org/html/rfc5246#section-4.7). The signature 1411 | algorithm must be the same as that used in the CertificateVerify 1412 | message. However, since the MD5+SHA1 signature type used in TLS 1.0 1413 | connections can not be correctly encoded in a digitally-signed 1414 | element, SHA1 must be used when MD5+SHA1 was used in the SSL 1415 | connection. The signature is calculated over a 32 byte TLS extractor 1416 | value (http://tools.ietf.org/html/rfc5705) with a label of "EXPORTER 1417 | SPDY certificate proof" using the empty string as context. ForRSA 1418 | certificates the signature would be a PKCS#1 v1.5 signature. For 1419 | ECDSA, it would be an ECDSA-Sig-Value 1420 | (http://tools.ietf.org/html/rfc5480#appendix-A). For a 1024-bit RSA 1421 | key, the CREDENTIAL message would be ~500 bytes. 1422 | 1423 | Certificate: The certificate chain, starting with the leaf 1424 | certificate. Each certificate must be encoded as a 32 bit length, 1425 | followed by a DER encoded certificate. The certificate must be of 1426 | the same type (RSA, ECDSA, etc) as the client certificate associated 1427 | with the SSL connection. 1428 | 1429 | If the server receives a request for a resource with unacceptable 1430 | credential (either missing or invalid), it must reply with a 1431 | RST_STREAM frame with the status code INVALID_CREDENTIALS. Upon 1432 | receipt of a RST_STREAM frame with INVALID_CREDENTIALS, the client 1433 | should initiate a new stream directly to the requested origin and 1434 | resend the request. Note, SPDY does not allow the server to request 1435 | different client authentication for different resources in the same 1436 | origin. 1437 | 1438 | If the server receives an invalid CREDENTIAL frame, it MUST respond 1439 | with a GOAWAY frame and shutdown the session. 1440 | 1441 | 2.6.10. Name/Value Header Block 1442 | 1443 | The Name/Value Header Block is found in the SYN_STREAM, SYN_REPLY and 1444 | HEADERS control frames, and shares a common format: 1445 | 1446 | 1447 | 1448 | 1449 | 1450 | 1451 | 1452 | 1453 | 1454 | 1455 | Belshe & Peon Expires August 4, 2012 [Page 26] 1456 | 1457 | Internet-Draft SPDY Feb 2012 1458 | 1459 | 1460 | +------------------------------------+ 1461 | | Number of Name/Value pairs (int32) | 1462 | +------------------------------------+ 1463 | | Length of name (int32) | 1464 | +------------------------------------+ 1465 | | Name (string) | 1466 | +------------------------------------+ 1467 | | Length of value (int32) | 1468 | +------------------------------------+ 1469 | | Value (string) | 1470 | +------------------------------------+ 1471 | | (repeats) | 1472 | 1473 | Number of Name/Value pairs: The number of repeating name/value pairs 1474 | following this field. 1475 | 1476 | List of Name/Value pairs: 1477 | 1478 | Length of Name: a 32-bit value containing the number of octets in 1479 | the name field. Note that in practice, this length must not 1480 | exceed 2^24, as that is the maximum size of a SPDY frame. 1481 | 1482 | Name: 0 or more octets, 8-bit sequences of data, excluding 0. 1483 | 1484 | Length of Value: a 32-bit value containing the number of octets in 1485 | the value field. Note that in practice, this length must not 1486 | exceed 2^24, as that is the maximum size of a SPDY frame. 1487 | 1488 | Value: 0 or more octets, 8-bit sequences of data, excluding 0. 1489 | 1490 | Each header name must have at least one value. Header names are 1491 | encoded using the US-ASCII character set [ASCII] and must be all 1492 | lower case. The length of each name must be greater than zero. A 1493 | recipient of a zero-length name MUST issue a stream error 1494 | (Section 2.4.2) with the status code PROTOCOL_ERROR for the 1495 | stream-id. 1496 | 1497 | Duplicate header names are not allowed. To send two identically 1498 | named headers, send a header with two values, where the values are 1499 | separated by a single NUL (0) byte. A header value can either be 1500 | empty (e.g. the length is zero) or it can contain multiple, NUL- 1501 | separated values, each with length greater than zero. The value 1502 | never starts nor ends with a NUL character. Recipients of illegal 1503 | value fields MUST issue a stream error (Section 2.4.2) with the 1504 | status code PROTOCOL_ERROR for the stream-id. 1505 | 1506 | 1507 | 1508 | 1509 | 1510 | 1511 | Belshe & Peon Expires August 4, 2012 [Page 27] 1512 | 1513 | Internet-Draft SPDY Feb 2012 1514 | 1515 | 1516 | 2.6.10.1. Compression 1517 | 1518 | The Name/Value Header Block is a section of the SYN_STREAM, 1519 | SYN_REPLY, and HEADERS frames used to carry header meta-data. This 1520 | block is always compressed using zlib compression. Within this 1521 | specification, any reference to 'zlib' is referring to the ZLIB 1522 | Compressed Data Format Specification Version 3.3 as part of RFC1950. 1523 | [RFC1950] 1524 | 1525 | For each HEADERS compression instance, the initial state is 1526 | initialized using the following dictionary [UDELCOMPRESSION]: 1527 | 1528 | const unsigned char SPDY_dictionary_txt[] = { 1529 | 0x00, 0x00, 0x00, 0x07, 0x6f, 0x70, 0x74, 0x69, \\ - - - - o p t i 1530 | 0x6f, 0x6e, 0x73, 0x00, 0x00, 0x00, 0x04, 0x68, \\ o n s - - - - h 1531 | 0x65, 0x61, 0x64, 0x00, 0x00, 0x00, 0x04, 0x70, \\ e a d - - - - p 1532 | 0x6f, 0x73, 0x74, 0x00, 0x00, 0x00, 0x03, 0x70, \\ o s t - - - - p 1533 | 0x75, 0x74, 0x00, 0x00, 0x00, 0x06, 0x64, 0x65, \\ u t - - - - d e 1534 | 0x6c, 0x65, 0x74, 0x65, 0x00, 0x00, 0x00, 0x05, \\ l e t e - - - - 1535 | 0x74, 0x72, 0x61, 0x63, 0x65, 0x00, 0x00, 0x00, \\ t r a c e - - - 1536 | 0x06, 0x61, 0x63, 0x63, 0x65, 0x70, 0x74, 0x00, \\ - a c c e p t - 1537 | 0x00, 0x00, 0x0e, 0x61, 0x63, 0x63, 0x65, 0x70, \\ - - - a c c e p 1538 | 0x74, 0x2d, 0x63, 0x68, 0x61, 0x72, 0x73, 0x65, \\ t - c h a r s e 1539 | 0x74, 0x00, 0x00, 0x00, 0x0f, 0x61, 0x63, 0x63, \\ t - - - - a c c 1540 | 0x65, 0x70, 0x74, 0x2d, 0x65, 0x6e, 0x63, 0x6f, \\ e p t - e n c o 1541 | 0x64, 0x69, 0x6e, 0x67, 0x00, 0x00, 0x00, 0x0f, \\ d i n g - - - - 1542 | 0x61, 0x63, 0x63, 0x65, 0x70, 0x74, 0x2d, 0x6c, \\ a c c e p t - l 1543 | 0x61, 0x6e, 0x67, 0x75, 0x61, 0x67, 0x65, 0x00, \\ a n g u a g e - 1544 | 0x00, 0x00, 0x0d, 0x61, 0x63, 0x63, 0x65, 0x70, \\ - - - a c c e p 1545 | 0x74, 0x2d, 0x72, 0x61, 0x6e, 0x67, 0x65, 0x73, \\ t - r a n g e s 1546 | 0x00, 0x00, 0x00, 0x03, 0x61, 0x67, 0x65, 0x00, \\ - - - - a g e - 1547 | 0x00, 0x00, 0x05, 0x61, 0x6c, 0x6c, 0x6f, 0x77, \\ - - - a l l o w 1548 | 0x00, 0x00, 0x00, 0x0d, 0x61, 0x75, 0x74, 0x68, \\ - - - - a u t h 1549 | 0x6f, 0x72, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, \\ o r i z a t i o 1550 | 0x6e, 0x00, 0x00, 0x00, 0x0d, 0x63, 0x61, 0x63, \\ n - - - - c a c 1551 | 0x68, 0x65, 0x2d, 0x63, 0x6f, 0x6e, 0x74, 0x72, \\ h e - c o n t r 1552 | 0x6f, 0x6c, 0x00, 0x00, 0x00, 0x0a, 0x63, 0x6f, \\ o l - - - - c o 1553 | 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, \\ n n e c t i o n 1554 | 0x00, 0x00, 0x00, 0x0c, 0x63, 0x6f, 0x6e, 0x74, \\ - - - - c o n t 1555 | 0x65, 0x6e, 0x74, 0x2d, 0x62, 0x61, 0x73, 0x65, \\ e n t - b a s e 1556 | 0x00, 0x00, 0x00, 0x10, 0x63, 0x6f, 0x6e, 0x74, \\ - - - - c o n t 1557 | 0x65, 0x6e, 0x74, 0x2d, 0x65, 0x6e, 0x63, 0x6f, \\ e n t - e n c o 1558 | 0x64, 0x69, 0x6e, 0x67, 0x00, 0x00, 0x00, 0x10, \\ d i n g - - - - 1559 | 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x2d, \\ c o n t e n t - 1560 | 0x6c, 0x61, 0x6e, 0x67, 0x75, 0x61, 0x67, 0x65, \\ l a n g u a g e 1561 | 0x00, 0x00, 0x00, 0x0e, 0x63, 0x6f, 0x6e, 0x74, \\ - - - - c o n t 1562 | 0x65, 0x6e, 0x74, 0x2d, 0x6c, 0x65, 0x6e, 0x67, \\ e n t - l e n g 1563 | 0x74, 0x68, 0x00, 0x00, 0x00, 0x10, 0x63, 0x6f, \\ t h - - - - c o 1564 | 1565 | 1566 | 1567 | Belshe & Peon Expires August 4, 2012 [Page 28] 1568 | 1569 | Internet-Draft SPDY Feb 2012 1570 | 1571 | 1572 | 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x2d, 0x6c, 0x6f, \\ n t e n t - l o 1573 | 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x00, 0x00, \\ c a t i o n - - 1574 | 0x00, 0x0b, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, \\ - - c o n t e n 1575 | 0x74, 0x2d, 0x6d, 0x64, 0x35, 0x00, 0x00, 0x00, \\ t - m d 5 - - - 1576 | 0x0d, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, \\ - c o n t e n t 1577 | 0x2d, 0x72, 0x61, 0x6e, 0x67, 0x65, 0x00, 0x00, \\ - r a n g e - - 1578 | 0x00, 0x0c, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, \\ - - c o n t e n 1579 | 0x74, 0x2d, 0x74, 0x79, 0x70, 0x65, 0x00, 0x00, \\ t - t y p e - - 1580 | 0x00, 0x04, 0x64, 0x61, 0x74, 0x65, 0x00, 0x00, \\ - - d a t e - - 1581 | 0x00, 0x04, 0x65, 0x74, 0x61, 0x67, 0x00, 0x00, \\ - - e t a g - - 1582 | 0x00, 0x06, 0x65, 0x78, 0x70, 0x65, 0x63, 0x74, \\ - - e x p e c t 1583 | 0x00, 0x00, 0x00, 0x07, 0x65, 0x78, 0x70, 0x69, \\ - - - - e x p i 1584 | 0x72, 0x65, 0x73, 0x00, 0x00, 0x00, 0x04, 0x66, \\ r e s - - - - f 1585 | 0x72, 0x6f, 0x6d, 0x00, 0x00, 0x00, 0x04, 0x68, \\ r o m - - - - h 1586 | 0x6f, 0x73, 0x74, 0x00, 0x00, 0x00, 0x08, 0x69, \\ o s t - - - - i 1587 | 0x66, 0x2d, 0x6d, 0x61, 0x74, 0x63, 0x68, 0x00, \\ f - m a t c h - 1588 | 0x00, 0x00, 0x11, 0x69, 0x66, 0x2d, 0x6d, 0x6f, \\ - - - i f - m o 1589 | 0x64, 0x69, 0x66, 0x69, 0x65, 0x64, 0x2d, 0x73, \\ d i f i e d - s 1590 | 0x69, 0x6e, 0x63, 0x65, 0x00, 0x00, 0x00, 0x0d, \\ i n c e - - - - 1591 | 0x69, 0x66, 0x2d, 0x6e, 0x6f, 0x6e, 0x65, 0x2d, \\ i f - n o n e - 1592 | 0x6d, 0x61, 0x74, 0x63, 0x68, 0x00, 0x00, 0x00, \\ m a t c h - - - 1593 | 0x08, 0x69, 0x66, 0x2d, 0x72, 0x61, 0x6e, 0x67, \\ - i f - r a n g 1594 | 0x65, 0x00, 0x00, 0x00, 0x13, 0x69, 0x66, 0x2d, \\ e - - - - i f - 1595 | 0x75, 0x6e, 0x6d, 0x6f, 0x64, 0x69, 0x66, 0x69, \\ u n m o d i f i 1596 | 0x65, 0x64, 0x2d, 0x73, 0x69, 0x6e, 0x63, 0x65, \\ e d - s i n c e 1597 | 0x00, 0x00, 0x00, 0x0d, 0x6c, 0x61, 0x73, 0x74, \\ - - - - l a s t 1598 | 0x2d, 0x6d, 0x6f, 0x64, 0x69, 0x66, 0x69, 0x65, \\ - m o d i f i e 1599 | 0x64, 0x00, 0x00, 0x00, 0x08, 0x6c, 0x6f, 0x63, \\ d - - - - l o c 1600 | 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x00, 0x00, 0x00, \\ a t i o n - - - 1601 | 0x0c, 0x6d, 0x61, 0x78, 0x2d, 0x66, 0x6f, 0x72, \\ - m a x - f o r 1602 | 0x77, 0x61, 0x72, 0x64, 0x73, 0x00, 0x00, 0x00, \\ w a r d s - - - 1603 | 0x06, 0x70, 0x72, 0x61, 0x67, 0x6d, 0x61, 0x00, \\ - p r a g m a - 1604 | 0x00, 0x00, 0x12, 0x70, 0x72, 0x6f, 0x78, 0x79, \\ - - - p r o x y 1605 | 0x2d, 0x61, 0x75, 0x74, 0x68, 0x65, 0x6e, 0x74, \\ - a u t h e n t 1606 | 0x69, 0x63, 0x61, 0x74, 0x65, 0x00, 0x00, 0x00, \\ i c a t e - - - 1607 | 0x13, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x2d, 0x61, \\ - p r o x y - a 1608 | 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x7a, 0x61, \\ u t h o r i z a 1609 | 0x74, 0x69, 0x6f, 0x6e, 0x00, 0x00, 0x00, 0x05, \\ t i o n - - - - 1610 | 0x72, 0x61, 0x6e, 0x67, 0x65, 0x00, 0x00, 0x00, \\ r a n g e - - - 1611 | 0x07, 0x72, 0x65, 0x66, 0x65, 0x72, 0x65, 0x72, \\ - r e f e r e r 1612 | 0x00, 0x00, 0x00, 0x0b, 0x72, 0x65, 0x74, 0x72, \\ - - - - r e t r 1613 | 0x79, 0x2d, 0x61, 0x66, 0x74, 0x65, 0x72, 0x00, \\ y - a f t e r - 1614 | 0x00, 0x00, 0x06, 0x73, 0x65, 0x72, 0x76, 0x65, \\ - - - s e r v e 1615 | 0x72, 0x00, 0x00, 0x00, 0x02, 0x74, 0x65, 0x00, \\ r - - - - t e - 1616 | 0x00, 0x00, 0x07, 0x74, 0x72, 0x61, 0x69, 0x6c, \\ - - - t r a i l 1617 | 0x65, 0x72, 0x00, 0x00, 0x00, 0x11, 0x74, 0x72, \\ e r - - - - t r 1618 | 0x61, 0x6e, 0x73, 0x66, 0x65, 0x72, 0x2d, 0x65, \\ a n s f e r - e 1619 | 0x6e, 0x63, 0x6f, 0x64, 0x69, 0x6e, 0x67, 0x00, \\ n c o d i n g - 1620 | 1621 | 1622 | 1623 | Belshe & Peon Expires August 4, 2012 [Page 29] 1624 | 1625 | Internet-Draft SPDY Feb 2012 1626 | 1627 | 1628 | 0x00, 0x00, 0x07, 0x75, 0x70, 0x67, 0x72, 0x61, \\ - - - u p g r a 1629 | 0x64, 0x65, 0x00, 0x00, 0x00, 0x0a, 0x75, 0x73, \\ d e - - - - u s 1630 | 0x65, 0x72, 0x2d, 0x61, 0x67, 0x65, 0x6e, 0x74, \\ e r - a g e n t 1631 | 0x00, 0x00, 0x00, 0x04, 0x76, 0x61, 0x72, 0x79, \\ - - - - v a r y 1632 | 0x00, 0x00, 0x00, 0x03, 0x76, 0x69, 0x61, 0x00, \\ - - - - v i a - 1633 | 0x00, 0x00, 0x07, 0x77, 0x61, 0x72, 0x6e, 0x69, \\ - - - w a r n i 1634 | 0x6e, 0x67, 0x00, 0x00, 0x00, 0x10, 0x77, 0x77, \\ n g - - - - w w 1635 | 0x77, 0x2d, 0x61, 0x75, 0x74, 0x68, 0x65, 0x6e, \\ w - a u t h e n 1636 | 0x74, 0x69, 0x63, 0x61, 0x74, 0x65, 0x00, 0x00, \\ t i c a t e - - 1637 | 0x00, 0x06, 0x6d, 0x65, 0x74, 0x68, 0x6f, 0x64, \\ - - m e t h o d 1638 | 0x00, 0x00, 0x00, 0x03, 0x67, 0x65, 0x74, 0x00, \\ - - - - g e t - 1639 | 0x00, 0x00, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, \\ - - - s t a t u 1640 | 0x73, 0x00, 0x00, 0x00, 0x06, 0x32, 0x30, 0x30, \\ s - - - - 2 0 0 1641 | 0x20, 0x4f, 0x4b, 0x00, 0x00, 0x00, 0x07, 0x76, \\ - O K - - - - v 1642 | 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x00, 0x00, \\ e r s i o n - - 1643 | 0x00, 0x08, 0x48, 0x54, 0x54, 0x50, 0x2f, 0x31, \\ - - H T T P - 1 1644 | 0x2e, 0x31, 0x00, 0x00, 0x00, 0x03, 0x75, 0x72, \\ - 1 - - - - u r 1645 | 0x6c, 0x00, 0x00, 0x00, 0x06, 0x70, 0x75, 0x62, \\ l - - - - p u b 1646 | 0x6c, 0x69, 0x63, 0x00, 0x00, 0x00, 0x0a, 0x73, \\ l i c - - - - s 1647 | 0x65, 0x74, 0x2d, 0x63, 0x6f, 0x6f, 0x6b, 0x69, \\ e t - c o o k i 1648 | 0x65, 0x00, 0x00, 0x00, 0x0a, 0x6b, 0x65, 0x65, \\ e - - - - k e e 1649 | 0x70, 0x2d, 0x61, 0x6c, 0x69, 0x76, 0x65, 0x00, \\ p - a l i v e - 1650 | 0x00, 0x00, 0x06, 0x6f, 0x72, 0x69, 0x67, 0x69, \\ - - - o r i g i 1651 | 0x6e, 0x31, 0x30, 0x30, 0x31, 0x30, 0x31, 0x32, \\ n 1 0 0 1 0 1 2 1652 | 0x30, 0x31, 0x32, 0x30, 0x32, 0x32, 0x30, 0x35, \\ 0 1 2 0 2 2 0 5 1653 | 0x32, 0x30, 0x36, 0x33, 0x30, 0x30, 0x33, 0x30, \\ 2 0 6 3 0 0 3 0 1654 | 0x32, 0x33, 0x30, 0x33, 0x33, 0x30, 0x34, 0x33, \\ 2 3 0 3 3 0 4 3 1655 | 0x30, 0x35, 0x33, 0x30, 0x36, 0x33, 0x30, 0x37, \\ 0 5 3 0 6 3 0 7 1656 | 0x34, 0x30, 0x32, 0x34, 0x30, 0x35, 0x34, 0x30, \\ 4 0 2 4 0 5 4 0 1657 | 0x36, 0x34, 0x30, 0x37, 0x34, 0x30, 0x38, 0x34, \\ 6 4 0 7 4 0 8 4 1658 | 0x30, 0x39, 0x34, 0x31, 0x30, 0x34, 0x31, 0x31, \\ 0 9 4 1 0 4 1 1 1659 | 0x34, 0x31, 0x32, 0x34, 0x31, 0x33, 0x34, 0x31, \\ 4 1 2 4 1 3 4 1 1660 | 0x34, 0x34, 0x31, 0x35, 0x34, 0x31, 0x36, 0x34, \\ 4 4 1 5 4 1 6 4 1661 | 0x31, 0x37, 0x35, 0x30, 0x32, 0x35, 0x30, 0x34, \\ 1 7 5 0 2 5 0 4 1662 | 0x35, 0x30, 0x35, 0x32, 0x30, 0x33, 0x20, 0x4e, \\ 5 0 5 2 0 3 - N 1663 | 0x6f, 0x6e, 0x2d, 0x41, 0x75, 0x74, 0x68, 0x6f, \\ o n - A u t h o 1664 | 0x72, 0x69, 0x74, 0x61, 0x74, 0x69, 0x76, 0x65, \\ r i t a t i v e 1665 | 0x20, 0x49, 0x6e, 0x66, 0x6f, 0x72, 0x6d, 0x61, \\ - I n f o r m a 1666 | 0x74, 0x69, 0x6f, 0x6e, 0x32, 0x30, 0x34, 0x20, \\ t i o n 2 0 4 - 1667 | 0x4e, 0x6f, 0x20, 0x43, 0x6f, 0x6e, 0x74, 0x65, \\ N o - C o n t e 1668 | 0x6e, 0x74, 0x33, 0x30, 0x31, 0x20, 0x4d, 0x6f, \\ n t 3 0 1 - M o 1669 | 0x76, 0x65, 0x64, 0x20, 0x50, 0x65, 0x72, 0x6d, \\ v e d - P e r m 1670 | 0x61, 0x6e, 0x65, 0x6e, 0x74, 0x6c, 0x79, 0x34, \\ a n e n t l y 4 1671 | 0x30, 0x30, 0x20, 0x42, 0x61, 0x64, 0x20, 0x52, \\ 0 0 - B a d - R 1672 | 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x34, 0x30, \\ e q u e s t 4 0 1673 | 0x31, 0x20, 0x55, 0x6e, 0x61, 0x75, 0x74, 0x68, \\ 1 - U n a u t h 1674 | 0x6f, 0x72, 0x69, 0x7a, 0x65, 0x64, 0x34, 0x30, \\ o r i z e d 4 0 1675 | 0x33, 0x20, 0x46, 0x6f, 0x72, 0x62, 0x69, 0x64, \\ 3 - F o r b i d 1676 | 1677 | 1678 | 1679 | Belshe & Peon Expires August 4, 2012 [Page 30] 1680 | 1681 | Internet-Draft SPDY Feb 2012 1682 | 1683 | 1684 | 0x64, 0x65, 0x6e, 0x34, 0x30, 0x34, 0x20, 0x4e, \\ d e n 4 0 4 - N 1685 | 0x6f, 0x74, 0x20, 0x46, 0x6f, 0x75, 0x6e, 0x64, \\ o t - F o u n d 1686 | 0x35, 0x30, 0x30, 0x20, 0x49, 0x6e, 0x74, 0x65, \\ 5 0 0 - I n t e 1687 | 0x72, 0x6e, 0x61, 0x6c, 0x20, 0x53, 0x65, 0x72, \\ r n a l - S e r 1688 | 0x76, 0x65, 0x72, 0x20, 0x45, 0x72, 0x72, 0x6f, \\ v e r - E r r o 1689 | 0x72, 0x35, 0x30, 0x31, 0x20, 0x4e, 0x6f, 0x74, \\ r 5 0 1 - N o t 1690 | 0x20, 0x49, 0x6d, 0x70, 0x6c, 0x65, 0x6d, 0x65, \\ - I m p l e m e 1691 | 0x6e, 0x74, 0x65, 0x64, 0x35, 0x30, 0x33, 0x20, \\ n t e d 5 0 3 - 1692 | 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x20, \\ S e r v i c e - 1693 | 0x55, 0x6e, 0x61, 0x76, 0x61, 0x69, 0x6c, 0x61, \\ U n a v a i l a 1694 | 0x62, 0x6c, 0x65, 0x4a, 0x61, 0x6e, 0x20, 0x46, \\ b l e J a n - F 1695 | 0x65, 0x62, 0x20, 0x4d, 0x61, 0x72, 0x20, 0x41, \\ e b - M a r - A 1696 | 0x70, 0x72, 0x20, 0x4d, 0x61, 0x79, 0x20, 0x4a, \\ p r - M a y - J 1697 | 0x75, 0x6e, 0x20, 0x4a, 0x75, 0x6c, 0x20, 0x41, \\ u n - J u l - A 1698 | 0x75, 0x67, 0x20, 0x53, 0x65, 0x70, 0x74, 0x20, \\ u g - S e p t - 1699 | 0x4f, 0x63, 0x74, 0x20, 0x4e, 0x6f, 0x76, 0x20, \\ O c t - N o v - 1700 | 0x44, 0x65, 0x63, 0x20, 0x30, 0x30, 0x3a, 0x30, \\ D e c - 0 0 - 0 1701 | 0x30, 0x3a, 0x30, 0x30, 0x20, 0x4d, 0x6f, 0x6e, \\ 0 - 0 0 - M o n 1702 | 0x2c, 0x20, 0x54, 0x75, 0x65, 0x2c, 0x20, 0x57, \\ - - T u e - - W 1703 | 0x65, 0x64, 0x2c, 0x20, 0x54, 0x68, 0x75, 0x2c, \\ e d - - T h u - 1704 | 0x20, 0x46, 0x72, 0x69, 0x2c, 0x20, 0x53, 0x61, \\ - F r i - - S a 1705 | 0x74, 0x2c, 0x20, 0x53, 0x75, 0x6e, 0x2c, 0x20, \\ t - - S u n - - 1706 | 0x47, 0x4d, 0x54, 0x63, 0x68, 0x75, 0x6e, 0x6b, \\ G M T c h u n k 1707 | 0x65, 0x64, 0x2c, 0x74, 0x65, 0x78, 0x74, 0x2f, \\ e d - t e x t - 1708 | 0x68, 0x74, 0x6d, 0x6c, 0x2c, 0x69, 0x6d, 0x61, \\ h t m l - i m a 1709 | 0x67, 0x65, 0x2f, 0x70, 0x6e, 0x67, 0x2c, 0x69, \\ g e - p n g - i 1710 | 0x6d, 0x61, 0x67, 0x65, 0x2f, 0x6a, 0x70, 0x67, \\ m a g e - j p g 1711 | 0x2c, 0x69, 0x6d, 0x61, 0x67, 0x65, 0x2f, 0x67, \\ - i m a g e - g 1712 | 0x69, 0x66, 0x2c, 0x61, 0x70, 0x70, 0x6c, 0x69, \\ i f - a p p l i 1713 | 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x78, \\ c a t i o n - x 1714 | 0x6d, 0x6c, 0x2c, 0x61, 0x70, 0x70, 0x6c, 0x69, \\ m l - a p p l i 1715 | 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x78, \\ c a t i o n - x 1716 | 0x68, 0x74, 0x6d, 0x6c, 0x2b, 0x78, 0x6d, 0x6c, \\ h t m l - x m l 1717 | 0x2c, 0x74, 0x65, 0x78, 0x74, 0x2f, 0x70, 0x6c, \\ - t e x t - p l 1718 | 0x61, 0x69, 0x6e, 0x2c, 0x74, 0x65, 0x78, 0x74, \\ a i n - t e x t 1719 | 0x2f, 0x6a, 0x61, 0x76, 0x61, 0x73, 0x63, 0x72, \\ - j a v a s c r 1720 | 0x69, 0x70, 0x74, 0x2c, 0x70, 0x75, 0x62, 0x6c, \\ i p t - p u b l 1721 | 0x69, 0x63, 0x70, 0x72, 0x69, 0x76, 0x61, 0x74, \\ i c p r i v a t 1722 | 0x65, 0x6d, 0x61, 0x78, 0x2d, 0x61, 0x67, 0x65, \\ e m a x - a g e 1723 | 0x3d, 0x67, 0x7a, 0x69, 0x70, 0x2c, 0x64, 0x65, \\ - g z i p - d e 1724 | 0x66, 0x6c, 0x61, 0x74, 0x65, 0x2c, 0x73, 0x64, \\ f l a t e - s d 1725 | 0x63, 0x68, 0x63, 0x68, 0x61, 0x72, 0x73, 0x65, \\ c h c h a r s e 1726 | 0x74, 0x3d, 0x75, 0x74, 0x66, 0x2d, 0x38, 0x63, \\ t - u t f - 8 c 1727 | 0x68, 0x61, 0x72, 0x73, 0x65, 0x74, 0x3d, 0x69, \\ h a r s e t - i 1728 | 0x73, 0x6f, 0x2d, 0x38, 0x38, 0x35, 0x39, 0x2d, \\ s o - 8 8 5 9 - 1729 | 0x31, 0x2c, 0x75, 0x74, 0x66, 0x2d, 0x2c, 0x2a, \\ 1 - u t f - - - 1730 | 0x2c, 0x65, 0x6e, 0x71, 0x3d, 0x30, 0x2e \\ - e n q - 0 - 1731 | }; 1732 | 1733 | 1734 | 1735 | Belshe & Peon Expires August 4, 2012 [Page 31] 1736 | 1737 | Internet-Draft SPDY Feb 2012 1738 | 1739 | 1740 | The entire contents of the name/value header block is compressed 1741 | using zlib. There is a single zlib stream for all name value pairs 1742 | in one direction on a connection. SPDY uses a SYNC_FLUSH between 1743 | each compressed frame. 1744 | 1745 | Implementation notes: the compression engine can be tuned to favor 1746 | speed or size. Optimizing for size increases memory use and CPU 1747 | consumption. Because header blocks are generally small, implementors 1748 | may want to reduce the window-size of the compression engine from the 1749 | default 15bits (a 32KB window) to more like 11bits (a 2KB window). 1750 | The exact setting is chosen by the compressor, the decompressor will 1751 | work with any setting. 1752 | 1753 | 1754 | 1755 | 1756 | 1757 | 1758 | 1759 | 1760 | 1761 | 1762 | 1763 | 1764 | 1765 | 1766 | 1767 | 1768 | 1769 | 1770 | 1771 | 1772 | 1773 | 1774 | 1775 | 1776 | 1777 | 1778 | 1779 | 1780 | 1781 | 1782 | 1783 | 1784 | 1785 | 1786 | 1787 | 1788 | 1789 | 1790 | 1791 | Belshe & Peon Expires August 4, 2012 [Page 32] 1792 | 1793 | Internet-Draft SPDY Feb 2012 1794 | 1795 | 1796 | 3. HTTP Layering over SPDY 1797 | 1798 | SPDY is intended to be as compatible as possible with current web- 1799 | based applications. This means that, from the perspective of the 1800 | server business logic or application API, the features of HTTP are 1801 | unchanged. To achieve this, all of the application request and 1802 | response header semantics are preserved, although the syntax of 1803 | conveying those semantics has changed. Thus, the rules from the 1804 | HTTP/1.1 specification in RFC2616 [RFC2616] apply with the changes in 1805 | the sections below. 1806 | 1807 | 3.1. Connection Management 1808 | 1809 | Clients SHOULD NOT open more than one SPDY session to a given origin 1810 | [RFC6454] concurrently. 1811 | 1812 | Note that it is possible for one SPDY session to be finishing (e.g. a 1813 | GOAWAY message has been sent, but not all streams have finished), 1814 | while another SPDY session is starting. 1815 | 1816 | 3.1.1. Use of GOAWAY 1817 | 1818 | SPDY provides a GOAWAY message which can be used when closing a 1819 | connection from either the client or server. Without a server GOAWAY 1820 | message, HTTP has a race condition where the client sends a request 1821 | (a new SYN_STREAM) just as the server is closing the connection, and 1822 | the client cannot know if the server received the stream or not. By 1823 | using the last-stream-id in the GOAWAY, servers can indicate to the 1824 | client if a request was processed or not. 1825 | 1826 | Note that some servers will choose to send the GOAWAY and immediately 1827 | terminate the connection without waiting for active streams to 1828 | finish. The client will be able to determine this because SPDY 1829 | streams are determinstically closed. This abrupt termination will 1830 | force the client to heuristically decide whether to retry the pending 1831 | requests. Clients always need to be capable of dealing with this 1832 | case because they must deal with accidental connection termination 1833 | cases, which are the same as the server never having sent a GOAWAY. 1834 | 1835 | More sophisticated servers will use GOAWAY to implement a graceful 1836 | teardown. They will send the GOAWAY and provide some time for the 1837 | active streams to finish before terminating the connection. 1838 | 1839 | If a SPDY client closes the connection, it should also send a GOAWAY 1840 | message. This allows the server to know if any server-push streams 1841 | were received by the client. 1842 | 1843 | If the endpoint closing the connection has not received any 1844 | 1845 | 1846 | 1847 | Belshe & Peon Expires August 4, 2012 [Page 33] 1848 | 1849 | Internet-Draft SPDY Feb 2012 1850 | 1851 | 1852 | SYN_STREAMs from the remote, the GOAWAY will contain a last-stream-id 1853 | of 0. 1854 | 1855 | 3.2. HTTP Request/Response 1856 | 1857 | 3.2.1. Request 1858 | 1859 | The client initiates a request by sending a SYN_STREAM frame. For 1860 | requests which do not contain a body, the SYN_STREAM frame MUST set 1861 | the FLAG_FIN, indicating that the client intends to send no further 1862 | data on this stream. For requests which do contain a body, the 1863 | SYN_STREAM will not contain the FLAG_FIN, and the body will follow 1864 | the SYN_STREAM in a series of DATA frames. The last DATA frame will 1865 | set the FLAG_FIN to indicate the end of the body. 1866 | 1867 | The SYN_STREAM Name/Value section will contain all of the HTTP 1868 | headers which are associated with an HTTP request. The header block 1869 | in SPDY is mostly unchanged from today's HTTP header block, with the 1870 | following differences: 1871 | 1872 | The first line of the request is unfolded into name/value pairs 1873 | like other HTTP headers and MUST be present: 1874 | 1875 | ":method" - the HTTP method for this request (e.g. "GET", 1876 | "POST", "HEAD", etc) 1877 | 1878 | ":path" - the url-path for this url with "/" prefixed. (See 1879 | RFC1738 [RFC1738]). For example, for 1880 | "http://www.google.com/search?q=dogs" the path would be 1881 | "/search?q=dogs". 1882 | 1883 | ":version" - the HTTP version of this request (e.g. 1884 | "HTTP/1.1") 1885 | 1886 | In addition, the following two name/value pairs must also be 1887 | present in every request: 1888 | 1889 | ":host" - the hostport (See RFC1738 [RFC1738]) portion of the 1890 | URL for this request (e.g. "www.google.com:1234"). This header 1891 | is the same as the HTTP 'Host' header. 1892 | 1893 | ":scheme" - the scheme portion of the URL for this request 1894 | (e.g. "https")) 1895 | 1896 | Header names are all lowercase. 1897 | 1898 | The Connection, Host, Keep-Alive, Proxy-Connection, and Transfer- 1899 | Encoding headers are not valid and MUST not be sent. 1900 | 1901 | 1902 | 1903 | Belshe & Peon Expires August 4, 2012 [Page 34] 1904 | 1905 | Internet-Draft SPDY Feb 2012 1906 | 1907 | 1908 | User-agents MUST support gzip compression. Regardless of the 1909 | Accept-Encoding sent by the user-agent, the server may always send 1910 | content encoded with gzip or deflate encoding. 1911 | 1912 | If a server receives a request where the sum of the data frame 1913 | payload lengths does not equal the size of the Content-Length 1914 | header, the server MUST return a 400 (Bad Request) error. 1915 | 1916 | POST-specific changes: 1917 | 1918 | Although POSTs are inherently chunked, POST requests SHOULD 1919 | also be accompanied by a Content-Length header. There are two 1920 | reasons for this: First, it assists with upload progress meters 1921 | for an improved user experience. But second, we know from 1922 | early versions of SPDY that failure to send a content length 1923 | header is incompatible with many existing HTTP server 1924 | implementations. Existing user-agents do not omit the Content- 1925 | Length header, and server implementations have come to depend 1926 | upon this. 1927 | 1928 | The user-agent is free to prioritize requests as it sees fit. If the 1929 | user-agent cannot make progress without receiving a resource, it 1930 | should attempt to raise the priority of that resource. Resources 1931 | such as images, SHOULD generally use the lowest priority. 1932 | 1933 | If a client sends a SYN_STREAM without all of the method, host, path, 1934 | scheme, and version headers, the server MUST reply with a HTTP 400 1935 | Bad Request reply. 1936 | 1937 | 3.2.2. Response 1938 | 1939 | The server responds to a client request with a SYN_REPLY frame. 1940 | Symmetric to the client's upload stream, server will send data after 1941 | the SYN_REPLY frame via a series of DATA frames, and the last data 1942 | frame will contain the FLAG_FIN to indicate successful end-of-stream. 1943 | If a response (like a 202 or 204 response) contains no body, the 1944 | SYN_REPLY frame may contain the FLAG_FIN flag to indicate no further 1945 | data will be sent on the stream. 1946 | 1947 | The response status line is unfolded into name/value pairs like 1948 | other HTTP headers and must be present: 1949 | 1950 | ":status" - The HTTP response status code (e.g. "200" or "200 1951 | OK") 1952 | 1953 | ":version" - The HTTP response version (e.g. "HTTP/1.1") 1954 | 1955 | 1956 | 1957 | 1958 | 1959 | Belshe & Peon Expires August 4, 2012 [Page 35] 1960 | 1961 | Internet-Draft SPDY Feb 2012 1962 | 1963 | 1964 | All header names must be lowercase. 1965 | 1966 | The Connection, Keep-Alive, Proxy-Connection, and Transfer- 1967 | Encoding headers are not valid and MUST not be sent. 1968 | 1969 | Responses MAY be accompanied by a Content-Length header for 1970 | advisory purposes. (e.g. for UI progress meters) 1971 | 1972 | If a client receives a response where the sum of the data frame 1973 | payload lengths does not equal the size of the Content-Length 1974 | header, the client MUST ignore the content length header. 1975 | 1976 | If a client receives a SYN_REPLY without a status or without a 1977 | version header, the client must reply with a RST_STREAM frame 1978 | indicating a PROTOCOL ERROR. 1979 | 1980 | 3.2.3. Authentication 1981 | 1982 | When a client sends a request to an origin server that requires 1983 | authentication, the server can reply with a "401 Unauthorized" 1984 | response, and include a WWW-Authenticate challenge header that 1985 | defines the authentication scheme to be used. The client then 1986 | retries the request with an Authorization header appropriate to the 1987 | specified authentication scheme. 1988 | 1989 | There are four options for proxy authentication, Basic, Digest, NTLM 1990 | and Negotiate (SPNEGO). The first two options were defined in 1991 | RFC2617 [RFC2617], and are stateless. The second two options were 1992 | developed by Microsoft and specified in RFC4559 [RFC4559], and are 1993 | stateful; otherwise known as multi-round authentication, or 1994 | connection authentication. 1995 | 1996 | 3.2.3.1. Stateless Authentication 1997 | 1998 | Stateless Authentication over SPDY is identical to how it is 1999 | performed over HTTP. If multiple SPDY streams are concurrently sent 2000 | to a single server, each will authenticate independently, similar to 2001 | how two HTTP connections would independently authenticate to a proxy 2002 | server. 2003 | 2004 | 3.2.3.2. Stateful Authentication 2005 | 2006 | Unfortunately, the stateful authentication mechanisms were 2007 | implemented and defined in a such a way that directly violates 2008 | RFC2617 - they do not include a "realm" as part of the request. This 2009 | is problematic in SPDY because it makes it impossible for a client to 2010 | disambiguate two concurrent server authentication challenges. 2011 | 2012 | 2013 | 2014 | 2015 | Belshe & Peon Expires August 4, 2012 [Page 36] 2016 | 2017 | Internet-Draft SPDY Feb 2012 2018 | 2019 | 2020 | To deal with this case, SPDY servers using Stateful Authentication 2021 | MUST implement one of two changes: 2022 | 2023 | Servers can add a "realm=" header so that the two 2024 | authentication requests can be disambiguated and run concurrently. 2025 | Unfortunately, given how these mechanisms work, this is probably 2026 | not practical. 2027 | 2028 | Upon sending the first stateful challenge response, the server 2029 | MUST buffer and defer all further frames which are not part of 2030 | completing the challenge until the challenge has completed. 2031 | Completing the authentication challenge may take multiple round 2032 | trips. Once the client receives a "401 Authenticate" response for 2033 | a stateful authentication type, it MUST stop sending new requests 2034 | to the server until the authentication has completed by receiving 2035 | a non-401 response on at least one stream. 2036 | 2037 | 3.3. Server Push Transactions 2038 | 2039 | SPDY enables a server to send multiple replies to a client for a 2040 | single request. The rationale for this feature is that sometimes a 2041 | server knows that it will need to send multiple resources in response 2042 | to a single request. Without server push features, the client must 2043 | first download the primary resource, then discover the secondary 2044 | resource(s), and request them. Pushing of resources avoids the 2045 | round-trip delay, but also creates a potential race where a server 2046 | can be pushing content which a user-agent is in the process of 2047 | requesting. The following mechanics attempt to prevent the race 2048 | condition while enabling the performance benefit. 2049 | 2050 | Browsers receiving a pushed response MUST validate that the server is 2051 | authorized to push the URL using the browser same-origin [RFC6454] 2052 | policy. For example, a SPDY connection to www.foo.com is generally 2053 | not permitted to push a response for www.evil.com. 2054 | 2055 | If the browser accepts a pushed response (e.g. it does not send a 2056 | RST_STREAM), the browser MUST attempt to cache the pushed response in 2057 | same way that it would cache any other response. This means 2058 | validating the response headers and inserting into the disk cache. 2059 | 2060 | Because pushed responses have no request, they have no request 2061 | headers associated with them. At the framing layer, SPDY pushed 2062 | streams contain an "associated-stream-id" which indicates the 2063 | requested stream for which the pushed stream is related. The pushed 2064 | stream inherits all of the headers from the associated-stream-id with 2065 | the exception of ":host", ":scheme", and ":path", which are provided 2066 | as part of the pushed response stream headers. The browser MUST 2067 | store these inherited and implied request headers with the cached 2068 | 2069 | 2070 | 2071 | Belshe & Peon Expires August 4, 2012 [Page 37] 2072 | 2073 | Internet-Draft SPDY Feb 2012 2074 | 2075 | 2076 | resource. 2077 | 2078 | Implementation note: With server push, it is theoretically possible 2079 | for servers to push unreasonable amounts of content or resources to 2080 | the user-agent. Browsers MUST implement throttles to protect against 2081 | unreasonable push attacks. 2082 | 2083 | 3.3.1. Server implementation 2084 | 2085 | When the server intends to push a resource to the user-agent, it 2086 | opens a new stream by sending a unidirectional SYN_STREAM. The 2087 | SYN_STREAM MUST include an Associated-To-Stream-ID, and MUST set the 2088 | FLAG_UNIDIRECTIONAL flag. The SYN_STREAM MUST include headers for 2089 | ":scheme", ":host", ":path", which represent the URL for the resource 2090 | being pushed. Subsequent headers may follow in HEADERS frames. The 2091 | purpose of the association is so that the user-agent can 2092 | differentiate which request induced the pushed stream; without it, if 2093 | the user-agent had two tabs open to the same page, each pushing 2094 | unique content under a fixed URL, the user-agent would not be able to 2095 | differentiate the requests. 2096 | 2097 | The Associated-To-Stream-ID must be the ID of an existing, open 2098 | stream. The reason for this restriction is to have a clear endpoint 2099 | for pushed content. If the user-agent requested a resource on stream 2100 | 11, the server replies on stream 11. It can push any number of 2101 | additional streams to the client before sending a FLAG_FIN on stream 2102 | 11. However, once the originating stream is closed no further push 2103 | streams may be associated with it. The pushed streams do not need to 2104 | be closed (FIN set) before the originating stream is closed, they 2105 | only need to be created before the originating stream closes. 2106 | 2107 | It is illegal for a server to push a resource with the Associated-To- 2108 | Stream-ID of 0. 2109 | 2110 | To minimize race conditions with the client, the SYN_STREAM for the 2111 | pushed resources MUST be sent prior to sending any content which 2112 | could allow the client to discover the pushed resource and request 2113 | it. 2114 | 2115 | The server MUST only push resources which would have been returned 2116 | from a GET request. 2117 | 2118 | Note: If the server does not have all of the Name/Value Response 2119 | headers available at the time it issues the HEADERS frame for the 2120 | pushed resource, it may later use an additional HEADERS frame to 2121 | augment the name/value pairs to be associated with the pushed stream. 2122 | The subsequent HEADERS frame(s) must not contain a header for 2123 | ':host', ':scheme', or ':path' (e.g. the server can't change the 2124 | 2125 | 2126 | 2127 | Belshe & Peon Expires August 4, 2012 [Page 38] 2128 | 2129 | Internet-Draft SPDY Feb 2012 2130 | 2131 | 2132 | identity of the resource to be pushed). The HEADERS frame must not 2133 | contain duplicate headers with a previously sent HEADERS frame. The 2134 | server must send a HEADERS frame including the scheme/host/port 2135 | headers before sending any data frames on the stream. 2136 | 2137 | 3.3.2. Client implementation 2138 | 2139 | When fetching a resource the client has 3 possibilities: 2140 | 2141 | the resource is not being pushed 2142 | 2143 | the resource is being pushed, but the data has not yet arrived 2144 | 2145 | the resource is being pushed, and the data has started to arrive 2146 | 2147 | When a SYN_STREAM and HEADERS frame which contains an Associated-To- 2148 | Stream-ID is received, the client must not issue GET requests for the 2149 | resource in the pushed stream, and instead wait for the pushed stream 2150 | to arrive. 2151 | 2152 | If a client receives a server push stream with stream-id 0, it MUST 2153 | issue a session error (Section 2.4.1) with the status code 2154 | PROTOCOL_ERROR. 2155 | 2156 | When a client receives a SYN_STREAM from the server without a the 2157 | ':host', ':scheme', and ':path' headers in the Name/Value section, it 2158 | MUST reply with a RST_STREAM with error code HTTP_PROTOCOL_ERROR. 2159 | 2160 | To cancel individual server push streams, the client can issue a 2161 | stream error (Section 2.4.2) with error code CANCEL. Upon receipt, 2162 | the server MUST stop sending on this stream immediately (this is an 2163 | Abrupt termination). 2164 | 2165 | To cancel all server push streams related to a request, the client 2166 | may issue a stream error (Section 2.4.2) with error code CANCEL on 2167 | the associated-stream-id. By cancelling that stream, the server MUST 2168 | immediately stop sending frames for any streams with 2169 | in-association-to for the original stream. 2170 | 2171 | If the server sends a HEADER frame containing duplicate headers with 2172 | a previous HEADERS frame for the same stream, the client must issue a 2173 | stream error (Section 2.4.2) with error code PROTOCOL ERROR. 2174 | 2175 | If the server sends a HEADERS frame after sending a data frame for 2176 | the same stream, the client MAY ignore the HEADERS frame. Ignoring 2177 | the HEADERS frame after a data frame prevents handling of HTTP's 2178 | trailing headers 2179 | (http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.40). 2180 | 2181 | 2182 | 2183 | Belshe & Peon Expires August 4, 2012 [Page 39] 2184 | 2185 | Internet-Draft SPDY Feb 2012 2186 | 2187 | 2188 | 4. Design Rationale and Notes 2189 | 2190 | Authors' notes: The notes in this section have no bearing on the SPDY 2191 | protocol as specified within this document, and none of these notes 2192 | should be considered authoritative about how the protocol works. 2193 | However, these notes may prove useful in future debates about how to 2194 | resolve protocol ambiguities or how to evolve the protocol going 2195 | forward. They may be removed before the final draft. 2196 | 2197 | 4.1. Separation of Framing Layer and Application Layer 2198 | 2199 | Readers may note that this specification sometimes blends the framing 2200 | layer (Section 2) with requirements of a specific application - HTTP 2201 | (Section 3). This is reflected in the request/response nature of the 2202 | streams, the definition of the HEADERS and compression contexts which 2203 | are very similar to HTTP, and other areas as well. 2204 | 2205 | This blending is intentional - the primary goal of this protocol is 2206 | to create a low-latency protocol for use with HTTP. Isolating the 2207 | two layers is convenient for description of the protocol and how it 2208 | relates to existing HTTP implementations. However, the ability to 2209 | reuse the SPDY framing layer is a non goal. 2210 | 2211 | 4.2. Error handling - Framing Layer 2212 | 2213 | Error handling at the SPDY layer splits errors into two groups: Those 2214 | that affect an individual SPDY stream, and those that do not. 2215 | 2216 | When an error is confined to a single stream, but general framing is 2217 | in tact, SPDY attempts to use the RST_STREAM as a mechanism to 2218 | invalidate the stream but move forward without aborting the 2219 | connection altogether. 2220 | 2221 | For errors occuring outside of a single stream context, SPDY assumes 2222 | the entire session is hosed. In this case, the endpoint detecting 2223 | the error should initiate a connection close. 2224 | 2225 | 4.3. One Connection Per Domain 2226 | 2227 | SPDY attempts to use fewer connections than other protocols have 2228 | traditionally used. The rationale for this behavior is because it is 2229 | very difficult to provide a consistent level of service (e.g. TCP 2230 | slow-start), prioritization, or optimal compression when the client 2231 | is connecting to the server through multiple channels. 2232 | 2233 | Through lab measurements, we have seen consistent latency benefits by 2234 | using fewer connections from the client. The overall number of 2235 | packets sent by SPDY can be as much as 40% less than HTTP. Handling 2236 | 2237 | 2238 | 2239 | Belshe & Peon Expires August 4, 2012 [Page 40] 2240 | 2241 | Internet-Draft SPDY Feb 2012 2242 | 2243 | 2244 | large numbers of concurrent connections on the server also does 2245 | become a scalability problem, and SPDY reduces this load. 2246 | 2247 | The use of multiple connections is not without benefit, however. 2248 | Because SPDY multiplexes multiple, independent streams onto a single 2249 | stream, it creates a potential for head-of-line blocking problems at 2250 | the transport level. In tests so far, the negative effects of head- 2251 | of-line blocking (especially in the presence of packet loss) is 2252 | outweighed by the benefits of compression and prioritization. 2253 | 2254 | 4.4. Fixed vs Variable Length Fields 2255 | 2256 | SPDY favors use of fixed length 32bit fields in cases where smaller, 2257 | variable length encodings could have been used. To some, this seems 2258 | like a tragic waste of bandwidth. SPDY choses the simple encoding 2259 | for speed and simplicity. 2260 | 2261 | The goal of SPDY is to reduce latency on the network. The overhead 2262 | of SPDY frames is generally quite low. Each data frame is only an 8 2263 | byte overhead for a 1452 byte payload (~0.6%). At the time of this 2264 | writing, bandwidth is already plentiful, and there is a strong trend 2265 | indicating that bandwidth will continue to increase. With an average 2266 | worldwide bandwidth of 1Mbps, and assuming that a variable length 2267 | encoding could reduce the overhead by 50%, the latency saved by using 2268 | a variable length encoding would be less than 100 nanoseconds. More 2269 | interesting are the effects when the larger encodings force a packet 2270 | boundary, in which case a round-trip could be induced. However, by 2271 | addressing other aspects of SPDY and TCP interactions, we believe 2272 | this is completely mitigated. 2273 | 2274 | 4.5. Compression Context(s) 2275 | 2276 | When isolating the compression contexts used for communicating with 2277 | multiple origins, we had a few choices to make. We could have 2278 | maintained a map (or list) of compression contexts usable for each 2279 | origin. The basic case is easy - each HEADERS frame would need to 2280 | identify the context to use for that frame. However, compression 2281 | contexts are not cheap, so the lifecycle of each context would need 2282 | to be bounded. For proxy servers, where we could churn through many 2283 | contexts, this would be a concern. We considered using a static set 2284 | of contexts, say 16 of them, which would bound the memory use. We 2285 | also considered dynamic contexts, which could be created on the fly, 2286 | and would need to be subsequently destroyed. All of these are 2287 | complicated, and ultimately we decided that such a mechanism creates 2288 | too many problems to solve. 2289 | 2290 | Alternatively, we've chosen the simple approach, which is to simply 2291 | provide a flag for resetting the compression context. For the common 2292 | 2293 | 2294 | 2295 | Belshe & Peon Expires August 4, 2012 [Page 41] 2296 | 2297 | Internet-Draft SPDY Feb 2012 2298 | 2299 | 2300 | case (no proxy), this fine because most requests are to the same 2301 | origin and we never need to reset the context. For cases where we 2302 | are using two different origins over a single SPDY session, we simply 2303 | reset the compression state between each transition. 2304 | 2305 | 4.6. Unidirectional streams 2306 | 2307 | Many readers notice that unidirectional streams are both a bit 2308 | confusing in concept and also somewhat redundant. If the recipient 2309 | of a stream doesn't wish to send data on a stream, it could simply 2310 | send a SYN_REPLY with the FLAG_FIN bit set. The FLAG_UNIDIRECTIONAL 2311 | is, therefore, not necessary. 2312 | 2313 | It is true that we don't need the UNIDIRECTIONAL markings. It is 2314 | added because it avoids the recipient of pushed streams from needing 2315 | to send a set of empty frames (e.g. the SYN_STREAM w/ FLAG_FIN) which 2316 | otherwise serve no purpose. 2317 | 2318 | 4.7. Data Compression 2319 | 2320 | Generic compression of data portion of the streams (as opposed to 2321 | compression of the headers) without knowing the content of the stream 2322 | is redundant. There is no value in compressing a stream which is 2323 | already compressed. Because of this, SPDY does allow data 2324 | compression to be optional. We included it because study of existing 2325 | websites shows that many sites are not using compression as they 2326 | should, and users suffer because of it. We wanted a mechanism where, 2327 | at the SPDY layer, site administrators could simply force compression 2328 | - it is better to compress twice than to not compress. 2329 | 2330 | Overall, however, with this feature being optional and sometimes 2331 | redundant, it is unclear if it is useful at all. We will likely 2332 | remove it from the specification. 2333 | 2334 | 4.8. Server Push 2335 | 2336 | A subtle but important point is that server push streams must be 2337 | declared before the associated stream is closed. The reason for this 2338 | is so that proxies have a lifetime for which they can discard 2339 | information about previous streams. If a pushed stream could 2340 | associate itself with an already-closed stream, then endpoints would 2341 | not have a specific lifecycle for when they could disavow knowledge 2342 | of the streams which went before. 2343 | 2344 | 2345 | 2346 | 2347 | 2348 | 2349 | 2350 | 2351 | Belshe & Peon Expires August 4, 2012 [Page 42] 2352 | 2353 | Internet-Draft SPDY Feb 2012 2354 | 2355 | 2356 | 5. Security Considerations 2357 | 2358 | 5.1. Use of Same-origin constraints 2359 | 2360 | This specification uses the same-origin policy [RFC6454] in all cases 2361 | where verification of content is required. 2362 | 2363 | 5.2. HTTP Headers and SPDY Headers 2364 | 2365 | At the application level, HTTP uses name/value pairs in its headers. 2366 | Because SPDY merges the existing HTTP headers with SPDY headers, 2367 | there is a possibility that some HTTP applications already use a 2368 | particular header name. To avoid any conflicts, all headers 2369 | introduced for layering HTTP over SPDY are prefixed with ":". ":" is 2370 | not a valid sequence in HTTP header naming, preventing any possible 2371 | conflict. 2372 | 2373 | 5.3. Cross-Protocol Attacks 2374 | 2375 | By utilizing TLS, we believe that SPDY introduces no new cross- 2376 | protocol attacks. TLS encrypts the contents of all transmission 2377 | (except the handshake itself), making it difficult for attackers to 2378 | control the data which could be used in a cross-protocol attack. 2379 | 2380 | 5.4. Server Push Implicit Headers 2381 | 2382 | Pushed resources do not have an associated request. In order for 2383 | existing HTTP cache control validations (such as the Vary header) to 2384 | work, however, all cached resources must have a set of request 2385 | headers. For this reason, browsers MUST be careful to inherit 2386 | request headers from the associated stream for the push. This 2387 | includes the 'Cookie' header. 2388 | 2389 | 2390 | 2391 | 2392 | 2393 | 2394 | 2395 | 2396 | 2397 | 2398 | 2399 | 2400 | 2401 | 2402 | 2403 | 2404 | 2405 | 2406 | 2407 | Belshe & Peon Expires August 4, 2012 [Page 43] 2408 | 2409 | Internet-Draft SPDY Feb 2012 2410 | 2411 | 2412 | 6. Privacy Considerations 2413 | 2414 | 6.1. Long Lived Connections 2415 | 2416 | SPDY aims to keep connections open longer between clients and servers 2417 | in order to reduce the latency when a user makes a request. The 2418 | maintenance of these connections over time could be used to expose 2419 | private information. For example, a user using a browser hours after 2420 | the previous user stopped using that browser may be able to learn 2421 | about what the previous user was doing. This is a problem with HTTP 2422 | in its current form as well, however the short lived connections make 2423 | it less of a risk. 2424 | 2425 | 6.2. SETTINGS frame 2426 | 2427 | The SPDY SETTINGS frame allows servers to store out-of-band 2428 | transmitted information about the communication between client and 2429 | server on the client. Although this is intended only to be used to 2430 | reduce latency, renegade servers could use it as a mechanism to store 2431 | identifying information about the client in future requests. 2432 | 2433 | Clients implementing privacy modes, such as Google Chrome's 2434 | "incognito mode", may wish to disable client-persisted SETTINGS 2435 | storage. 2436 | 2437 | Clients MUST clear persisted SETTINGS information when clearing the 2438 | cookies. 2439 | 2440 | TODO: Put range maximums on each type of setting to limit 2441 | inappropriate uses. 2442 | 2443 | 2444 | 2445 | 2446 | 2447 | 2448 | 2449 | 2450 | 2451 | 2452 | 2453 | 2454 | 2455 | 2456 | 2457 | 2458 | 2459 | 2460 | 2461 | 2462 | 2463 | Belshe & Peon Expires August 4, 2012 [Page 44] 2464 | 2465 | Internet-Draft SPDY Feb 2012 2466 | 2467 | 2468 | 7. Incompatibilities with SPDY draft #2 2469 | 2470 | Here is a list of the major changes between this draft and draft #2. 2471 | 2472 | Addition of flow control 2473 | 2474 | Increased 16 bit length fields in SYN_STREAM and SYN_REPLY to 32 2475 | bits. 2476 | 2477 | Changed definition of compression for DATA frames 2478 | 2479 | Updated compression dictionary 2480 | 2481 | Fixed off-by-one on the compression dictionary for headers 2482 | 2483 | Increased priority field from 2bits to 3bits. 2484 | 2485 | Removed NOOP frame 2486 | 2487 | Split the request "url" into "scheme", "host", and "path" 2488 | 2489 | Added the requirement that POSTs contain content-length. 2490 | 2491 | Removed wasted 16bits of unused space from the end of the 2492 | SYN_REPLY and HEADERS frames. 2493 | 2494 | Fixed bug: Priorities were described backward (0 was lowest 2495 | instead of highest). 2496 | 2497 | Fixed bug: Name/Value header counts were duplicated in both the 2498 | Name Value header block and also the containing frame. 2499 | 2500 | 2501 | 2502 | 2503 | 2504 | 2505 | 2506 | 2507 | 2508 | 2509 | 2510 | 2511 | 2512 | 2513 | 2514 | 2515 | 2516 | 2517 | 2518 | 2519 | Belshe & Peon Expires August 4, 2012 [Page 45] 2520 | 2521 | Internet-Draft SPDY Feb 2012 2522 | 2523 | 2524 | 8. Requirements Notation 2525 | 2526 | The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", 2527 | "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this 2528 | document are to be interpreted as described in RFC 2119 [RFC2119]. 2529 | 2530 | 2531 | 2532 | 2533 | 2534 | 2535 | 2536 | 2537 | 2538 | 2539 | 2540 | 2541 | 2542 | 2543 | 2544 | 2545 | 2546 | 2547 | 2548 | 2549 | 2550 | 2551 | 2552 | 2553 | 2554 | 2555 | 2556 | 2557 | 2558 | 2559 | 2560 | 2561 | 2562 | 2563 | 2564 | 2565 | 2566 | 2567 | 2568 | 2569 | 2570 | 2571 | 2572 | 2573 | 2574 | 2575 | Belshe & Peon Expires August 4, 2012 [Page 46] 2576 | 2577 | Internet-Draft SPDY Feb 2012 2578 | 2579 | 2580 | 9. Acknowledgements 2581 | 2582 | Many individuals have contributed to the design and evolution of 2583 | SPDY: Adam Langley, Wan-Teh Chang, Jim Morrison, Mark Nottingham, 2584 | Alyssa Wilk, Costin Manolache, William Chan, Vitaliy Lvin, Joe Chan, 2585 | Adam Barth, Ryan Hamilton, Gavin Peters, Kent Alstad, Kevin Lindsay, 2586 | Paul Amer, Fan Yang, Jonathan Leighton 2587 | 2588 | 2589 | 2590 | 2591 | 2592 | 2593 | 2594 | 2595 | 2596 | 2597 | 2598 | 2599 | 2600 | 2601 | 2602 | 2603 | 2604 | 2605 | 2606 | 2607 | 2608 | 2609 | 2610 | 2611 | 2612 | 2613 | 2614 | 2615 | 2616 | 2617 | 2618 | 2619 | 2620 | 2621 | 2622 | 2623 | 2624 | 2625 | 2626 | 2627 | 2628 | 2629 | 2630 | 2631 | Belshe & Peon Expires August 4, 2012 [Page 47] 2632 | 2633 | Internet-Draft SPDY Feb 2012 2634 | 2635 | 2636 | 10. Normative References 2637 | 2638 | [RFC0793] Postel, J., "Transmission Control Protocol", STD 7, 2639 | RFC 793, September 1981. 2640 | 2641 | [RFC1738] Berners-Lee, T., Masinter, L., and M. McCahill, "Uniform 2642 | Resource Locators (URL)", RFC 1738, December 1994. 2643 | 2644 | [RFC1950] Deutsch, L. and J-L. Gailly, "ZLIB Compressed Data Format 2645 | Specification version 3.3", RFC 1950, May 1996. 2646 | 2647 | [RFC2119] Bradner, S., "Key words for use in RFCs to Indicate 2648 | Requirement Levels", BCP 14, RFC 2119, March 1997. 2649 | 2650 | [RFC2285] Mandeville, R., "Benchmarking Terminology for LAN 2651 | Switching Devices", RFC 2285, February 1998. 2652 | 2653 | [RFC2616] Fielding, R., Gettys, J., Mogul, J., Frystyk, H., 2654 | Masinter, L., Leach, P., and T. Berners-Lee, "Hypertext 2655 | Transfer Protocol -- HTTP/1.1", RFC 2616, June 1999. 2656 | 2657 | [RFC2617] Franks, J., Hallam-Baker, P., Hostetler, J., Lawrence, S., 2658 | Leach, P., Luotonen, A., and L. Stewart, "HTTP 2659 | Authentication: Basic and Digest Access Authentication", 2660 | RFC 2617, June 1999. 2661 | 2662 | [RFC4559] Jaganathan, K., Zhu, L., and J. Brezak, "SPNEGO-based 2663 | Kerberos and NTLM HTTP Authentication in Microsoft 2664 | Windows", RFC 4559, June 2006. 2665 | 2666 | [RFC4366] Blake-Wilson, S., Nystrom, M., Hopwood, D., Mikkelsen, J., 2667 | and T. Wright, "Transport Layer Security (TLS) 2668 | Extensions", RFC 4366, April 2006. 2669 | 2670 | [RFC5246] Dierks, T. and E. Rescorla, "The Transport Layer Security 2671 | (TLS) Protocol Version 1.2", RFC 5246, August 2008. 2672 | 2673 | [RFC6454] Barth, A., "The Web Origin Concept", RFC 6454, 2674 | December 2011. 2675 | 2676 | [TLSNPN] Langley, A., "TLS Next Protocol Negotiation", 2677 | . 2679 | 2680 | [ASCII] "US-ASCII. Coded Character Set - 7-Bit American Standard 2681 | Code for Information Interchange. Standard ANSI X3.4-1986, 2682 | ANSI, 1986.". 2683 | 2684 | 2685 | 2686 | 2687 | Belshe & Peon Expires August 4, 2012 [Page 48] 2688 | 2689 | Internet-Draft SPDY Feb 2012 2690 | 2691 | 2692 | [UDELCOMPRESSION] 2693 | Yang, F., Amer, P., and J. Leighton, "A Methodology to 2694 | Derive SPDY's Initial Dictionary for Zlib Compression", 2695 | . 2697 | 2698 | 2699 | 2700 | 2701 | 2702 | 2703 | 2704 | 2705 | 2706 | 2707 | 2708 | 2709 | 2710 | 2711 | 2712 | 2713 | 2714 | 2715 | 2716 | 2717 | 2718 | 2719 | 2720 | 2721 | 2722 | 2723 | 2724 | 2725 | 2726 | 2727 | 2728 | 2729 | 2730 | 2731 | 2732 | 2733 | 2734 | 2735 | 2736 | 2737 | 2738 | 2739 | 2740 | 2741 | 2742 | 2743 | Belshe & Peon Expires August 4, 2012 [Page 49] 2744 | 2745 | Internet-Draft SPDY Feb 2012 2746 | 2747 | 2748 | Appendix A. Changes 2749 | 2750 | To be removed by RFC Editor before publication 2751 | 2752 | 2753 | 2754 | 2755 | 2756 | 2757 | 2758 | 2759 | 2760 | 2761 | 2762 | 2763 | 2764 | 2765 | 2766 | 2767 | 2768 | 2769 | 2770 | 2771 | 2772 | 2773 | 2774 | 2775 | 2776 | 2777 | 2778 | 2779 | 2780 | 2781 | 2782 | 2783 | 2784 | 2785 | 2786 | 2787 | 2788 | 2789 | 2790 | 2791 | 2792 | 2793 | 2794 | 2795 | 2796 | 2797 | 2798 | 2799 | Belshe & Peon Expires August 4, 2012 [Page 50] 2800 | 2801 | Internet-Draft SPDY Feb 2012 2802 | 2803 | 2804 | Authors' Addresses 2805 | 2806 | Mike Belshe 2807 | Twist 2808 | 2809 | Email: mbelshe@chromium.org 2810 | 2811 | 2812 | Roberto Peon 2813 | Google, Inc 2814 | 2815 | Email: fenix@google.com 2816 | 2817 | 2818 | 2819 | 2820 | 2821 | 2822 | 2823 | 2824 | 2825 | 2826 | 2827 | 2828 | 2829 | 2830 | 2831 | 2832 | 2833 | 2834 | 2835 | 2836 | 2837 | 2838 | 2839 | 2840 | 2841 | 2842 | 2843 | 2844 | 2845 | 2846 | 2847 | 2848 | 2849 | 2850 | 2851 | 2852 | 2853 | 2854 | 2855 | Belshe & Peon Expires August 4, 2012 [Page 51] 2856 | 2857 | --------------------------------------------------------------------------------