{"action":"created","comment":{"url":"https://api.github.com/repos/letsencrypt/boulder/pulls/comments/64933391","id":64933391,"diff_hunk":"@@ -192,43 +183,77 @@ func marshalIndent(v interface{}) ([]byte, error) {\n \treturn json.MarshalIndent(v, \"\", \"  \")\n }\n \n-// Handler returns an http.Handler that uses various functions for\n-// various ACME-specified paths.\n-func (wfe *WebFrontEndImpl) Handler() (http.Handler, error) {\n-\twfe.NewReg = wfe.BaseURL + NewRegPath\n-\twfe.RegBase = wfe.BaseURL + RegPath\n-\twfe.NewAuthz = wfe.BaseURL + NewAuthzPath\n-\twfe.AuthzBase = wfe.BaseURL + AuthzPath\n-\twfe.ChallengeBase = wfe.BaseURL + ChallengePath\n-\twfe.NewCert = wfe.BaseURL + NewCertPath\n-\twfe.CertBase = wfe.BaseURL + CertPath\n-\n-\t// Only generate directory once\n-\tdirectory := map[string]string{\n-\t\t\"new-reg\":     wfe.NewReg,\n-\t\t\"new-authz\":   wfe.NewAuthz,\n-\t\t\"new-cert\":    wfe.NewCert,\n-\t\t\"revoke-cert\": wfe.BaseURL + RevokeCertPath,\n-\t}\n-\tdirectoryJSON, err := marshalIndent(directory)\n+func (wfe *WebFrontEndImpl) relativeEndpoint(request *http.Request, endpoint string) string {\n+\tvar result string\n+\tproto := \"http\"\n+\thost := request.Host\n+\n+\t// If the request was received via TLS, use `https://` for the protocol\n+\tif request.TLS != nil {\n+\t\tproto = \"https\"\n+\t}\n+\n+\t// Allow upstream proxies  to specify the forwarded protocol. Allow this value\n+\t// to override our own guess.\n+\tif specifiedProto := request.Header.Get(\"X-Forwarded-Proto\"); specifiedProto != \"\" {\n+\t\tproto = specifiedProto\n+\t}\n+\n+\t// Default to \"localhost\" when no request.Host is provided. Otherwise requests\n+\t// with an empty `Host` produce results like `http:///acme/new-authz`\n+\tif request.Host == \"\" {\n+\t\thost = \"localhost\"\n+\t}\n+\n+\tif wfe.BaseURL != \"\" {\n+\t\tresult = fmt.Sprintf(\"%s%s\", wfe.BaseURL, endpoint)\n+\t} else {\n+\t\tresultUrl := url.URL{Scheme: proto, Host: host, Path: endpoint}\n+\t\tresult = resultUrl.String()\n+\t}\n+\n+\treturn result\n+}\n+\n+func (wfe *WebFrontEndImpl) relativeDirectory(request *http.Request, directory map[string]string) ([]byte, error) {\n+\t// Create an empty map sized equal to the provided directory to store the\n+\t// relative-ized result\n+\trelativeDir := make(map[string]string, len(directory))\n+\n+\t// Copy each entry of the provided directory into the new relative map. If\n+\t// `wfe.BaseURL` != \"\", use the old behaviour and prefix each endpoint with\n+\t// the `BaseURL`. Otherwise, prefix each endpoint using the request protocol\n+\t// & host.\n+\tfor k, v := range directory {\n+\t\trelativeDir[k] = wfe.relativeEndpoint(request, v)\n+\t}\n+\n+\tdirectoryJSON, err := marshalIndent(relativeDir)\n+","path":"wfe/web-front-end.go","position":127,"original_position":127,"commit_id":"1a9350debc075743c50690da6b2b1118f5a6df00","original_commit_id":"1a9350debc075743c50690da6b2b1118f5a6df00","user":{"login":"rolandshoemaker","id":5080674,"avatar_url":"https://avatars.githubusercontent.com/u/5080674?v=3","gravatar_id":"","url":"https://api.github.com/users/rolandshoemaker","html_url":"https://github.com/rolandshoemaker","followers_url":"https://api.github.com/users/rolandshoemaker/followers","following_url":"https://api.github.com/users/rolandshoemaker/following{/other_user}","gists_url":"https://api.github.com/users/rolandshoemaker/gists{/gist_id}","starred_url":"https://api.github.com/users/rolandshoemaker/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/rolandshoemaker/subscriptions","organizations_url":"https://api.github.com/users/rolandshoemaker/orgs","repos_url":"https://api.github.com/users/rolandshoemaker/repos","events_url":"https://api.github.com/users/rolandshoemaker/events{/privacy}","received_events_url":"https://api.github.com/users/rolandshoemaker/received_events","type":"User","site_admin":false},"body":"nit: unnecessary whitespace.","created_at":"2016-05-27T16:42:01Z","updated_at":"2016-05-27T16:42:01Z","html_url":"https://github.com/letsencrypt/boulder/pull/1847#discussion_r64933391","pull_request_url":"https://api.github.com/repos/letsencrypt/boulder/pulls/1847","_links":{"self":{"href":"https://api.github.com/repos/letsencrypt/boulder/pulls/comments/64933391"},"html":{"href":"https://github.com/letsencrypt/boulder/pull/1847#discussion_r64933391"},"pull_request":{"href":"https://api.github.com/repos/letsencrypt/boulder/pulls/1847"}}},"pull_request":{"url":"https://api.github.com/repos/letsencrypt/boulder/pulls/1847","id":71598613,"html_url":"https://github.com/letsencrypt/boulder/pull/1847","diff_url":"https://github.com/letsencrypt/boulder/pull/1847.diff","patch_url":"https://github.com/letsencrypt/boulder/pull/1847.patch","issue_url":"https://api.github.com/repos/letsencrypt/boulder/issues/1847","number":1847,"state":"open","locked":false,"title":"Make directory URLs relative to requested URL","user":{"login":"ccppuu","id":292650,"avatar_url":"https://avatars.githubusercontent.com/u/292650?v=3","gravatar_id":"","url":"https://api.github.com/users/ccppuu","html_url":"https://github.com/ccppuu","followers_url":"https://api.github.com/users/ccppuu/followers","following_url":"https://api.github.com/users/ccppuu/following{/other_user}","gists_url":"https://api.github.com/users/ccppuu/gists{/gist_id}","starred_url":"https://api.github.com/users/ccppuu/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/ccppuu/subscriptions","organizations_url":"https://api.github.com/users/ccppuu/orgs","repos_url":"https://api.github.com/users/ccppuu/repos","events_url":"https://api.github.com/users/ccppuu/events{/privacy}","received_events_url":"https://api.github.com/users/ccppuu/received_events","type":"User","site_admin":false},"body":"Prior to this PR the `/directory` JSON result was built once in `Handler()` and returned as-is for all requests. Each endpoint URL was fully qualified as an absolute URL using the `BaseURL` configuration\r\nparameter. This required a configuration change in order to tweak the origin being used for subsequent requests. Returning purely relative URLs (e.g. `/acme/new-reg` vs `http://localhost:4000/acme/new-reg`) would break clients that assume absolute paths and we don't want that.\r\n\r\nThis PR introduces a new behaviour where the `/directory` JSON is built per-request using the HTTP Host header in place of the `BaseURL`. Clients will still receive a fully qualified URL in each directory entry but we gain the ability to more easily control the host without requiring config changes. To allow gradual migration via the config file we use the old `/directory` behaviour when a `BaseURL` is specified in the configuration file. This will address #1823.\r\n\r\nSince the `request.URL` is not populated (Spare the `Path` attribute) we can not use `request.URL.Scheme` for the initial `http://` vs `https://` prefix when constructing the URLs and instead differentiate between the two cases using the `req.TLS` attribute. For cases (such as in production) where another service is terminating the initial request and making a subsequent HTTP request to the WFE we support the `X-Forwarded-Proto` header to ensure we use the original request's protocol when building URLs.\r\n\r\nMany unit tests for the WFE assumed that when there is no `BaseURL` specified and no `Host` header is sent in the request, that the output will return relative paths. This PR changes that behaviour to always return absolute URLs by defaulting to `localhost` for the `Host` when it is not specified via the initial request or the `BaseURL` config option. This PR changes the expected test output to match this behaviour.","created_at":"2016-05-26T18:03:44Z","updated_at":"2016-05-27T16:42:01Z","closed_at":null,"merged_at":null,"merge_commit_sha":"703df98c0eb77f2a9c1ba0eb0d1bab298bca7bae","assignee":null,"milestone":null,"commits_url":"https://api.github.com/repos/letsencrypt/boulder/pulls/1847/commits","review_comments_url":"https://api.github.com/repos/letsencrypt/boulder/pulls/1847/comments","review_comment_url":"https://api.github.com/repos/letsencrypt/boulder/pulls/comments{/number}","comments_url":"https://api.github.com/repos/letsencrypt/boulder/issues/1847/comments","statuses_url":"https://api.github.com/repos/letsencrypt/boulder/statuses/1a9350debc075743c50690da6b2b1118f5a6df00","head":{"label":"letsencrypt:cpu-rel-dir","ref":"cpu-rel-dir","sha":"1a9350debc075743c50690da6b2b1118f5a6df00","user":{"login":"letsencrypt","id":9289019,"avatar_url":"https://avatars.githubusercontent.com/u/9289019?v=3","gravatar_id":"","url":"https://api.github.com/users/letsencrypt","html_url":"https://github.com/letsencrypt","followers_url":"https://api.github.com/users/letsencrypt/followers","following_url":"https://api.github.com/users/letsencrypt/following{/other_user}","gists_url":"https://api.github.com/users/letsencrypt/gists{/gist_id}","starred_url":"https://api.github.com/users/letsencrypt/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/letsencrypt/subscriptions","organizations_url":"https://api.github.com/users/letsencrypt/orgs","repos_url":"https://api.github.com/users/letsencrypt/repos","events_url":"https://api.github.com/users/letsencrypt/events{/privacy}","received_events_url":"https://api.github.com/users/letsencrypt/received_events","type":"Organization","site_admin":false},"repo":{"id":28283593,"name":"boulder","full_name":"letsencrypt/boulder","owner":{"login":"letsencrypt","id":9289019,"avatar_url":"https://avatars.githubusercontent.com/u/9289019?v=3","gravatar_id":"","url":"https://api.github.com/users/letsencrypt","html_url":"https://github.com/letsencrypt","followers_url":"https://api.github.com/users/letsencrypt/followers","following_url":"https://api.github.com/users/letsencrypt/following{/other_user}","gists_url":"https://api.github.com/users/letsencrypt/gists{/gist_id}","starred_url":"https://api.github.com/users/letsencrypt/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/letsencrypt/subscriptions","organizations_url":"https://api.github.com/users/letsencrypt/orgs","repos_url":"https://api.github.com/users/letsencrypt/repos","events_url":"https://api.github.com/users/letsencrypt/events{/privacy}","received_events_url":"https://api.github.com/users/letsencrypt/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/letsencrypt/boulder","description":"An ACME-based CA, written in Go.","fork":false,"url":"https://api.github.com/repos/letsencrypt/boulder","forks_url":"https://api.github.com/repos/letsencrypt/boulder/forks","keys_url":"https://api.github.com/repos/letsencrypt/boulder/keys{/key_id}","collaborators_url":"https://api.github.com/repos/letsencrypt/boulder/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/letsencrypt/boulder/teams","hooks_url":"https://api.github.com/repos/letsencrypt/boulder/hooks","issue_events_url":"https://api.github.com/repos/letsencrypt/boulder/issues/events{/number}","events_url":"https://api.github.com/repos/letsencrypt/boulder/events","assignees_url":"https://api.github.com/repos/letsencrypt/boulder/assignees{/user}","branches_url":"https://api.github.com/repos/letsencrypt/boulder/branches{/branch}","tags_url":"https://api.github.com/repos/letsencrypt/boulder/tags","blobs_url":"https://api.github.com/repos/letsencrypt/boulder/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/letsencrypt/boulder/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/letsencrypt/boulder/git/refs{/sha}","trees_url":"https://api.github.com/repos/letsencrypt/boulder/git/trees{/sha}","statuses_url":"https://api.github.com/repos/letsencrypt/boulder/statuses/{sha}","languages_url":"https://api.github.com/repos/letsencrypt/boulder/languages","stargazers_url":"https://api.github.com/repos/letsencrypt/boulder/stargazers","contributors_url":"https://api.github.com/repos/letsencrypt/boulder/contributors","subscribers_url":"https://api.github.com/repos/letsencrypt/boulder/subscribers","subscription_url":"https://api.github.com/repos/letsencrypt/boulder/subscription","commits_url":"https://api.github.com/repos/letsencrypt/boulder/commits{/sha}","git_commits_url":"https://api.github.com/repos/letsencrypt/boulder/git/commits{/sha}","comments_url":"https://api.github.com/repos/letsencrypt/boulder/comments{/number}","issue_comment_url":"https://api.github.com/repos/letsencrypt/boulder/issues/comments{/number}","contents_url":"https://api.github.com/repos/letsencrypt/boulder/contents/{+path}","compare_url":"https://api.github.com/repos/letsencrypt/boulder/compare/{base}...{head}","merges_url":"https://api.github.com/repos/letsencrypt/boulder/merges","archive_url":"https://api.github.com/repos/letsencrypt/boulder/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/letsencrypt/boulder/downloads","issues_url":"https://api.github.com/repos/letsencrypt/boulder/issues{/number}","pulls_url":"https://api.github.com/repos/letsencrypt/boulder/pulls{/number}","milestones_url":"https://api.github.com/repos/letsencrypt/boulder/milestones{/number}","notifications_url":"https://api.github.com/repos/letsencrypt/boulder/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/letsencrypt/boulder/labels{/name}","releases_url":"https://api.github.com/repos/letsencrypt/boulder/releases{/id}","deployments_url":"https://api.github.com/repos/letsencrypt/boulder/deployments","created_at":"2014-12-21T00:29:54Z","updated_at":"2016-05-27T15:02:52Z","pushed_at":"2016-05-27T16:24:09Z","git_url":"git://github.com/letsencrypt/boulder.git","ssh_url":"git@github.com:letsencrypt/boulder.git","clone_url":"https://github.com/letsencrypt/boulder.git","svn_url":"https://github.com/letsencrypt/boulder","homepage":null,"size":21091,"stargazers_count":1208,"watchers_count":1208,"language":"Go","has_issues":true,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":148,"mirror_url":null,"open_issues_count":294,"forks":148,"open_issues":294,"watchers":1208,"default_branch":"master"}},"base":{"label":"letsencrypt:master","ref":"master","sha":"5c175f0d9c4f406c8700b59ad4ebe9c446932386","user":{"login":"letsencrypt","id":9289019,"avatar_url":"https://avatars.githubusercontent.com/u/9289019?v=3","gravatar_id":"","url":"https://api.github.com/users/letsencrypt","html_url":"https://github.com/letsencrypt","followers_url":"https://api.github.com/users/letsencrypt/followers","following_url":"https://api.github.com/users/letsencrypt/following{/other_user}","gists_url":"https://api.github.com/users/letsencrypt/gists{/gist_id}","starred_url":"https://api.github.com/users/letsencrypt/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/letsencrypt/subscriptions","organizations_url":"https://api.github.com/users/letsencrypt/orgs","repos_url":"https://api.github.com/users/letsencrypt/repos","events_url":"https://api.github.com/users/letsencrypt/events{/privacy}","received_events_url":"https://api.github.com/users/letsencrypt/received_events","type":"Organization","site_admin":false},"repo":{"id":28283593,"name":"boulder","full_name":"letsencrypt/boulder","owner":{"login":"letsencrypt","id":9289019,"avatar_url":"https://avatars.githubusercontent.com/u/9289019?v=3","gravatar_id":"","url":"https://api.github.com/users/letsencrypt","html_url":"https://github.com/letsencrypt","followers_url":"https://api.github.com/users/letsencrypt/followers","following_url":"https://api.github.com/users/letsencrypt/following{/other_user}","gists_url":"https://api.github.com/users/letsencrypt/gists{/gist_id}","starred_url":"https://api.github.com/users/letsencrypt/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/letsencrypt/subscriptions","organizations_url":"https://api.github.com/users/letsencrypt/orgs","repos_url":"https://api.github.com/users/letsencrypt/repos","events_url":"https://api.github.com/users/letsencrypt/events{/privacy}","received_events_url":"https://api.github.com/users/letsencrypt/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/letsencrypt/boulder","description":"An ACME-based CA, written in Go.","fork":false,"url":"https://api.github.com/repos/letsencrypt/boulder","forks_url":"https://api.github.com/repos/letsencrypt/boulder/forks","keys_url":"https://api.github.com/repos/letsencrypt/boulder/keys{/key_id}","collaborators_url":"https://api.github.com/repos/letsencrypt/boulder/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/letsencrypt/boulder/teams","hooks_url":"https://api.github.com/repos/letsencrypt/boulder/hooks","issue_events_url":"https://api.github.com/repos/letsencrypt/boulder/issues/events{/number}","events_url":"https://api.github.com/repos/letsencrypt/boulder/events","assignees_url":"https://api.github.com/repos/letsencrypt/boulder/assignees{/user}","branches_url":"https://api.github.com/repos/letsencrypt/boulder/branches{/branch}","tags_url":"https://api.github.com/repos/letsencrypt/boulder/tags","blobs_url":"https://api.github.com/repos/letsencrypt/boulder/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/letsencrypt/boulder/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/letsencrypt/boulder/git/refs{/sha}","trees_url":"https://api.github.com/repos/letsencrypt/boulder/git/trees{/sha}","statuses_url":"https://api.github.com/repos/letsencrypt/boulder/statuses/{sha}","languages_url":"https://api.github.com/repos/letsencrypt/boulder/languages","stargazers_url":"https://api.github.com/repos/letsencrypt/boulder/stargazers","contributors_url":"https://api.github.com/repos/letsencrypt/boulder/contributors","subscribers_url":"https://api.github.com/repos/letsencrypt/boulder/subscribers","subscription_url":"https://api.github.com/repos/letsencrypt/boulder/subscription","commits_url":"https://api.github.com/repos/letsencrypt/boulder/commits{/sha}","git_commits_url":"https://api.github.com/repos/letsencrypt/boulder/git/commits{/sha}","comments_url":"https://api.github.com/repos/letsencrypt/boulder/comments{/number}","issue_comment_url":"https://api.github.com/repos/letsencrypt/boulder/issues/comments{/number}","contents_url":"https://api.github.com/repos/letsencrypt/boulder/contents/{+path}","compare_url":"https://api.github.com/repos/letsencrypt/boulder/compare/{base}...{head}","merges_url":"https://api.github.com/repos/letsencrypt/boulder/merges","archive_url":"https://api.github.com/repos/letsencrypt/boulder/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/letsencrypt/boulder/downloads","issues_url":"https://api.github.com/repos/letsencrypt/boulder/issues{/number}","pulls_url":"https://api.github.com/repos/letsencrypt/boulder/pulls{/number}","milestones_url":"https://api.github.com/repos/letsencrypt/boulder/milestones{/number}","notifications_url":"https://api.github.com/repos/letsencrypt/boulder/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/letsencrypt/boulder/labels{/name}","releases_url":"https://api.github.com/repos/letsencrypt/boulder/releases{/id}","deployments_url":"https://api.github.com/repos/letsencrypt/boulder/deployments","created_at":"2014-12-21T00:29:54Z","updated_at":"2016-05-27T15:02:52Z","pushed_at":"2016-05-27T16:24:09Z","git_url":"git://github.com/letsencrypt/boulder.git","ssh_url":"git@github.com:letsencrypt/boulder.git","clone_url":"https://github.com/letsencrypt/boulder.git","svn_url":"https://github.com/letsencrypt/boulder","homepage":null,"size":21091,"stargazers_count":1208,"watchers_count":1208,"language":"Go","has_issues":true,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":148,"mirror_url":null,"open_issues_count":294,"forks":148,"open_issues":294,"watchers":1208,"default_branch":"master"}},"_links":{"self":{"href":"https://api.github.com/repos/letsencrypt/boulder/pulls/1847"},"html":{"href":"https://github.com/letsencrypt/boulder/pull/1847"},"issue":{"href":"https://api.github.com/repos/letsencrypt/boulder/issues/1847"},"comments":{"href":"https://api.github.com/repos/letsencrypt/boulder/issues/1847/comments"},"review_comments":{"href":"https://api.github.com/repos/letsencrypt/boulder/pulls/1847/comments"},"review_comment":{"href":"https://api.github.com/repos/letsencrypt/boulder/pulls/comments{/number}"},"commits":{"href":"https://api.github.com/repos/letsencrypt/boulder/pulls/1847/commits"},"statuses":{"href":"https://api.github.com/repos/letsencrypt/boulder/statuses/1a9350debc075743c50690da6b2b1118f5a6df00"}}}}
{"actor":{"display_login":"rolandshoemaker"}}