{"action":"created","comment":{"url":"https://api.github.com/repos/flynn/flynn/pulls/comments/23423281","id":23423281,"diff_hunk":"@@ -275,62 +303,36 @@ func (s *HTTPListener) findRouteForHost(host string) *httpRoute {\n \treturn nil\n }\n \n-func fail(sc *httputil.ServerConn, req *http.Request, code int, msg string) {\n-\tresp := &http.Response{\n-\t\tStatusCode:    code,\n-\t\tProtoMajor:    1,\n-\t\tProtoMinor:    0,\n-\t\tRequest:       req,\n-\t\tBody:          ioutil.NopCloser(bytes.NewBufferString(msg)),\n-\t\tContentLength: int64(len(msg)),\n-\t}\n-\tsc.Write(req, resp)\n+func failAndClose(w http.ResponseWriter, code int) {\n+\tw.Header().Set(\"Connection\", \"close\")\n+\tfail(w, code)\n }\n \n-var errMissingTLS = errors.New(\"router: route not found or TLS not configured\")\n-\n-func (s *HTTPListener) handle(conn net.Conn, isTLS bool) {\n-\tdefer conn.Close() // TODO(benburkert): for TLS, check that closing this conn sends the TLS \"close notify\"\n+func fail(w http.ResponseWriter, code int) {\n+\tmsg := []byte(http.StatusText(code))\n+\tw.Header().Set(\"Content-Length\", strconv.Itoa(len(msg)))\n+\tw.WriteHeader(code)\n+\tw.Write(msg)","path":"router/http.go","position":153,"original_position":153,"commit_id":"4245d3887c5a28e480733934656423b3e63fff20","original_commit_id":"4245d3887c5a28e480733934656423b3e63fff20","user":{"login":"titanous","id":13026,"avatar_url":"https://avatars.githubusercontent.com/u/13026?v=3","gravatar_id":"","url":"https://api.github.com/users/titanous","html_url":"https://github.com/titanous","followers_url":"https://api.github.com/users/titanous/followers","following_url":"https://api.github.com/users/titanous/following{/other_user}","gists_url":"https://api.github.com/users/titanous/gists{/gist_id}","starred_url":"https://api.github.com/users/titanous/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/titanous/subscriptions","organizations_url":"https://api.github.com/users/titanous/orgs","repos_url":"https://api.github.com/users/titanous/repos","events_url":"https://api.github.com/users/titanous/events{/privacy}","received_events_url":"https://api.github.com/users/titanous/received_events","type":"User","site_admin":false},"body":"Add a trailing newline so that when we curl it looks better?","created_at":"2015-01-23T00:25:22Z","updated_at":"2015-01-23T00:25:22Z","html_url":"https://github.com/flynn/flynn/pull/781#discussion_r23423281","pull_request_url":"https://api.github.com/repos/flynn/flynn/pulls/781","_links":{"self":{"href":"https://api.github.com/repos/flynn/flynn/pulls/comments/23423281"},"html":{"href":"https://github.com/flynn/flynn/pull/781#discussion_r23423281"},"pull_request":{"href":"https://api.github.com/repos/flynn/flynn/pulls/781"}}},"pull_request":{"url":"https://api.github.com/repos/flynn/flynn/pulls/781","id":27866726,"html_url":"https://github.com/flynn/flynn/pull/781","diff_url":"https://github.com/flynn/flynn/pull/781.diff","patch_url":"https://github.com/flynn/flynn/pull/781.patch","issue_url":"https://api.github.com/repos/flynn/flynn/issues/781","number":781,"state":"open","locked":false,"title":"router: switch to from net/http/httputil to net/http","user":{"login":"bgentry","id":114033,"avatar_url":"https://avatars.githubusercontent.com/u/114033?v=3","gravatar_id":"","url":"https://api.github.com/users/bgentry","html_url":"https://github.com/bgentry","followers_url":"https://api.github.com/users/bgentry/followers","following_url":"https://api.github.com/users/bgentry/following{/other_user}","gists_url":"https://api.github.com/users/bgentry/gists{/gist_id}","starred_url":"https://api.github.com/users/bgentry/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/bgentry/subscriptions","organizations_url":"https://api.github.com/users/bgentry/orgs","repos_url":"https://api.github.com/users/bgentry/repos","events_url":"https://api.github.com/users/bgentry/events{/privacy}","received_events_url":"https://api.github.com/users/bgentry/received_events","type":"User","site_admin":false},"body":"This PR switches Flynn's router away from using the somewhat-deprecated `httputil.ClientConn` and `httputil.ServerConn` to using `net/http` HTTP parsers and handlers.\r\n\r\nBecause there are subtle differences between handling protocol upgrades (i.e. for websockets) and regular request proxying, there's a lot of duplicated logic between the functions that handle these paths. I think we'll be able to clean that up a lot, but would rather this doesn't spend too much more time in a side branch :)\r\n\r\nWe pretty quickly had to move away from `httputil.ReverseProxy` as it makes it basically impossible to do some of the stuff we want to do with trying conns to multiple backends, and it also wouldn't work for the websocket upgrade. In doing so, we've currently lost some of the nice parts of that package like periodic flushing of buffers (see [ReverseProxy.FlushInterval](http://golang.org/pkg/net/http/httputil/#ReverseProxy)). I've left a couple of TODOs for that in the code and intend to bring it in in a future PR. I also think that we can better package up some of the stuff we've done into a nice encapsulation similar to `httputil.ReverseProxy`, but again, didn't want to branch off for too long.\r\n\r\nFinally, the way we pass down the sticky session setting from the route to the service is pretty ugly (using a temporary internal header). I didn't see an obvious way to access this bool (`r.Sticky`) from the part of the code where I needed to use it, so this was a compromise for expediency. I suspect we can find a much better way to do this, either by refactoring to make the setting available where we need it or by storing that setting inside of [a request context](https://blog.golang.org/context).\r\n\r\nFixes #61. Fixes #64. Makes some progress on #67 by setting some sane defaults for TCP timeouts.","created_at":"2015-01-22T18:44:22Z","updated_at":"2015-01-23T00:25:22Z","closed_at":null,"merged_at":null,"merge_commit_sha":"63ade51f329d13b8fab28802318b0cd71f0d8144","assignee":null,"milestone":null,"commits_url":"https://api.github.com/repos/flynn/flynn/pulls/781/commits","review_comments_url":"https://api.github.com/repos/flynn/flynn/pulls/781/comments","review_comment_url":"https://api.github.com/repos/flynn/flynn/pulls/comments/{number}","comments_url":"https://api.github.com/repos/flynn/flynn/issues/781/comments","statuses_url":"https://api.github.com/repos/flynn/flynn/statuses/4245d3887c5a28e480733934656423b3e63fff20","head":{"label":"bgentry:router-net-http","ref":"router-net-http","sha":"4245d3887c5a28e480733934656423b3e63fff20","user":{"login":"bgentry","id":114033,"avatar_url":"https://avatars.githubusercontent.com/u/114033?v=3","gravatar_id":"","url":"https://api.github.com/users/bgentry","html_url":"https://github.com/bgentry","followers_url":"https://api.github.com/users/bgentry/followers","following_url":"https://api.github.com/users/bgentry/following{/other_user}","gists_url":"https://api.github.com/users/bgentry/gists{/gist_id}","starred_url":"https://api.github.com/users/bgentry/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/bgentry/subscriptions","organizations_url":"https://api.github.com/users/bgentry/orgs","repos_url":"https://api.github.com/users/bgentry/repos","events_url":"https://api.github.com/users/bgentry/events{/privacy}","received_events_url":"https://api.github.com/users/bgentry/received_events","type":"User","site_admin":false},"repo":{"id":29484741,"name":"flynn","full_name":"bgentry/flynn","owner":{"login":"bgentry","id":114033,"avatar_url":"https://avatars.githubusercontent.com/u/114033?v=3","gravatar_id":"","url":"https://api.github.com/users/bgentry","html_url":"https://github.com/bgentry","followers_url":"https://api.github.com/users/bgentry/followers","following_url":"https://api.github.com/users/bgentry/following{/other_user}","gists_url":"https://api.github.com/users/bgentry/gists{/gist_id}","starred_url":"https://api.github.com/users/bgentry/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/bgentry/subscriptions","organizations_url":"https://api.github.com/users/bgentry/orgs","repos_url":"https://api.github.com/users/bgentry/repos","events_url":"https://api.github.com/users/bgentry/events{/privacy}","received_events_url":"https://api.github.com/users/bgentry/received_events","type":"User","site_admin":false},"private":false,"html_url":"https://github.com/bgentry/flynn","description":"A next generation open source platform as a service (PaaS)","fork":true,"url":"https://api.github.com/repos/bgentry/flynn","forks_url":"https://api.github.com/repos/bgentry/flynn/forks","keys_url":"https://api.github.com/repos/bgentry/flynn/keys{/key_id}","collaborators_url":"https://api.github.com/repos/bgentry/flynn/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/bgentry/flynn/teams","hooks_url":"https://api.github.com/repos/bgentry/flynn/hooks","issue_events_url":"https://api.github.com/repos/bgentry/flynn/issues/events{/number}","events_url":"https://api.github.com/repos/bgentry/flynn/events","assignees_url":"https://api.github.com/repos/bgentry/flynn/assignees{/user}","branches_url":"https://api.github.com/repos/bgentry/flynn/branches{/branch}","tags_url":"https://api.github.com/repos/bgentry/flynn/tags","blobs_url":"https://api.github.com/repos/bgentry/flynn/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/bgentry/flynn/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/bgentry/flynn/git/refs{/sha}","trees_url":"https://api.github.com/repos/bgentry/flynn/git/trees{/sha}","statuses_url":"https://api.github.com/repos/bgentry/flynn/statuses/{sha}","languages_url":"https://api.github.com/repos/bgentry/flynn/languages","stargazers_url":"https://api.github.com/repos/bgentry/flynn/stargazers","contributors_url":"https://api.github.com/repos/bgentry/flynn/contributors","subscribers_url":"https://api.github.com/repos/bgentry/flynn/subscribers","subscription_url":"https://api.github.com/repos/bgentry/flynn/subscription","commits_url":"https://api.github.com/repos/bgentry/flynn/commits{/sha}","git_commits_url":"https://api.github.com/repos/bgentry/flynn/git/commits{/sha}","comments_url":"https://api.github.com/repos/bgentry/flynn/comments{/number}","issue_comment_url":"https://api.github.com/repos/bgentry/flynn/issues/comments/{number}","contents_url":"https://api.github.com/repos/bgentry/flynn/contents/{+path}","compare_url":"https://api.github.com/repos/bgentry/flynn/compare/{base}...{head}","merges_url":"https://api.github.com/repos/bgentry/flynn/merges","archive_url":"https://api.github.com/repos/bgentry/flynn/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/bgentry/flynn/downloads","issues_url":"https://api.github.com/repos/bgentry/flynn/issues{/number}","pulls_url":"https://api.github.com/repos/bgentry/flynn/pulls{/number}","milestones_url":"https://api.github.com/repos/bgentry/flynn/milestones{/number}","notifications_url":"https://api.github.com/repos/bgentry/flynn/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/bgentry/flynn/labels{/name}","releases_url":"https://api.github.com/repos/bgentry/flynn/releases{/id}","created_at":"2015-01-19T18:20:14Z","updated_at":"2015-01-22T22:06:47Z","pushed_at":"2015-01-22T22:44:21Z","git_url":"git://github.com/bgentry/flynn.git","ssh_url":"git@github.com:bgentry/flynn.git","clone_url":"https://github.com/bgentry/flynn.git","svn_url":"https://github.com/bgentry/flynn","homepage":"https://flynn.io","size":10877,"stargazers_count":0,"watchers_count":0,"language":"Go","has_issues":false,"has_downloads":true,"has_wiki":false,"has_pages":false,"forks_count":0,"mirror_url":null,"open_issues_count":0,"forks":0,"open_issues":0,"watchers":0,"default_branch":"master"}},"base":{"label":"flynn:master","ref":"master","sha":"e2b94ae693e28627e7653020b5909901359d3608","user":{"login":"flynn","id":4973613,"avatar_url":"https://avatars.githubusercontent.com/u/4973613?v=3","gravatar_id":"","url":"https://api.github.com/users/flynn","html_url":"https://github.com/flynn","followers_url":"https://api.github.com/users/flynn/followers","following_url":"https://api.github.com/users/flynn/following{/other_user}","gists_url":"https://api.github.com/users/flynn/gists{/gist_id}","starred_url":"https://api.github.com/users/flynn/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/flynn/subscriptions","organizations_url":"https://api.github.com/users/flynn/orgs","repos_url":"https://api.github.com/users/flynn/repos","events_url":"https://api.github.com/users/flynn/events{/privacy}","received_events_url":"https://api.github.com/users/flynn/received_events","type":"Organization","site_admin":false},"repo":{"id":11290232,"name":"flynn","full_name":"flynn/flynn","owner":{"login":"flynn","id":4973613,"avatar_url":"https://avatars.githubusercontent.com/u/4973613?v=3","gravatar_id":"","url":"https://api.github.com/users/flynn","html_url":"https://github.com/flynn","followers_url":"https://api.github.com/users/flynn/followers","following_url":"https://api.github.com/users/flynn/following{/other_user}","gists_url":"https://api.github.com/users/flynn/gists{/gist_id}","starred_url":"https://api.github.com/users/flynn/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/flynn/subscriptions","organizations_url":"https://api.github.com/users/flynn/orgs","repos_url":"https://api.github.com/users/flynn/repos","events_url":"https://api.github.com/users/flynn/events{/privacy}","received_events_url":"https://api.github.com/users/flynn/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/flynn/flynn","description":"A next generation open source platform as a service (PaaS)","fork":false,"url":"https://api.github.com/repos/flynn/flynn","forks_url":"https://api.github.com/repos/flynn/flynn/forks","keys_url":"https://api.github.com/repos/flynn/flynn/keys{/key_id}","collaborators_url":"https://api.github.com/repos/flynn/flynn/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/flynn/flynn/teams","hooks_url":"https://api.github.com/repos/flynn/flynn/hooks","issue_events_url":"https://api.github.com/repos/flynn/flynn/issues/events{/number}","events_url":"https://api.github.com/repos/flynn/flynn/events","assignees_url":"https://api.github.com/repos/flynn/flynn/assignees{/user}","branches_url":"https://api.github.com/repos/flynn/flynn/branches{/branch}","tags_url":"https://api.github.com/repos/flynn/flynn/tags","blobs_url":"https://api.github.com/repos/flynn/flynn/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/flynn/flynn/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/flynn/flynn/git/refs{/sha}","trees_url":"https://api.github.com/repos/flynn/flynn/git/trees{/sha}","statuses_url":"https://api.github.com/repos/flynn/flynn/statuses/{sha}","languages_url":"https://api.github.com/repos/flynn/flynn/languages","stargazers_url":"https://api.github.com/repos/flynn/flynn/stargazers","contributors_url":"https://api.github.com/repos/flynn/flynn/contributors","subscribers_url":"https://api.github.com/repos/flynn/flynn/subscribers","subscription_url":"https://api.github.com/repos/flynn/flynn/subscription","commits_url":"https://api.github.com/repos/flynn/flynn/commits{/sha}","git_commits_url":"https://api.github.com/repos/flynn/flynn/git/commits{/sha}","comments_url":"https://api.github.com/repos/flynn/flynn/comments{/number}","issue_comment_url":"https://api.github.com/repos/flynn/flynn/issues/comments/{number}","contents_url":"https://api.github.com/repos/flynn/flynn/contents/{+path}","compare_url":"https://api.github.com/repos/flynn/flynn/compare/{base}...{head}","merges_url":"https://api.github.com/repos/flynn/flynn/merges","archive_url":"https://api.github.com/repos/flynn/flynn/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/flynn/flynn/downloads","issues_url":"https://api.github.com/repos/flynn/flynn/issues{/number}","pulls_url":"https://api.github.com/repos/flynn/flynn/pulls{/number}","milestones_url":"https://api.github.com/repos/flynn/flynn/milestones{/number}","notifications_url":"https://api.github.com/repos/flynn/flynn/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/flynn/flynn/labels{/name}","releases_url":"https://api.github.com/repos/flynn/flynn/releases{/id}","created_at":"2013-07-09T18:22:06Z","updated_at":"2015-01-22T23:58:31Z","pushed_at":"2015-01-21T20:54:41Z","git_url":"git://github.com/flynn/flynn.git","ssh_url":"git@github.com:flynn/flynn.git","clone_url":"https://github.com/flynn/flynn.git","svn_url":"https://github.com/flynn/flynn","homepage":"https://flynn.io","size":31038,"stargazers_count":3167,"watchers_count":3167,"language":"Go","has_issues":true,"has_downloads":true,"has_wiki":false,"has_pages":false,"forks_count":199,"mirror_url":null,"open_issues_count":111,"forks":199,"open_issues":111,"watchers":3167,"default_branch":"master"}},"_links":{"self":{"href":"https://api.github.com/repos/flynn/flynn/pulls/781"},"html":{"href":"https://github.com/flynn/flynn/pull/781"},"issue":{"href":"https://api.github.com/repos/flynn/flynn/issues/781"},"comments":{"href":"https://api.github.com/repos/flynn/flynn/issues/781/comments"},"review_comments":{"href":"https://api.github.com/repos/flynn/flynn/pulls/781/comments"},"review_comment":{"href":"https://api.github.com/repos/flynn/flynn/pulls/comments/{number}"},"commits":{"href":"https://api.github.com/repos/flynn/flynn/pulls/781/commits"},"statuses":{"href":"https://api.github.com/repos/flynn/flynn/statuses/4245d3887c5a28e480733934656423b3e63fff20"}}}}