{"action":"created","comment":{"url":"https://api.github.com/repos/zalando/skipper/pulls/comments/65524208","id":65524208,"diff_hunk":"@@ -0,0 +1,323 @@\n+package builtin\n+\n+import (\n+\t\"compress/flate\"\n+\t\"compress/gzip\"\n+\t\"errors\"\n+\t\"io\"\n+\t\"net/http\"\n+\t\"runtime\"\n+\t\"sort\"\n+\t\"strconv\"\n+\t\"strings\"\n+\t\"sync\"\n+\n+\tlog \"github.com/Sirupsen/logrus\"\n+\t\"github.com/zalando/skipper/filters\"\n+)\n+\n+const bufferSize = 8192\n+\n+type encoding struct {\n+\tname string\n+\tq    float32\n+}\n+\n+type encodings []*encoding\n+\n+type compress struct {\n+\tmime []string\n+}\n+\n+type encoder interface {\n+\tio.WriteCloser\n+\tReset(io.Writer)\n+}\n+\n+var (\n+\tsupportedEncodings  = []string{\"gzip\", \"deflate\"}\n+\tunsupportedEncoding = errors.New(\"unsupported encoding\")\n+)\n+\n+var defaultCompressMIME = []string{\n+\t\"text/plain\",\n+\t\"text/html\",\n+\t\"application/json\",\n+\t\"application/javascript\",\n+\t\"application/x-javascript\",\n+\t\"text/javascript\",\n+\t\"text/css\",\n+\t\"image/svg+xml\",\n+\t\"application/octet-stream\",\n+}\n+\n+var (\n+\tgzipPool    = &sync.Pool{}\n+\tdeflatePool = &sync.Pool{}\n+)\n+\n+func init() {\n+\tfor i := 0; i < runtime.NumCPU()*4; i++ {\n+\t\tge := newEncoder(\"gzip\")\n+\t\tgzipPool.Put(ge)\n+\t\tfe := newEncoder(\"deflate\")\n+\t\tdeflatePool.Put(fe)\n+\t}\n+}\n+\n+func (e encodings) Len() int           { return len(e) }\n+func (e encodings) Less(i, j int) bool { return e[i].q > e[j].q } // higher first\n+func (e encodings) Swap(i, j int)      { e[i], e[j] = e[j], e[i] }\n+\n+// Returns a filter specification that is used to compress the response content.\n+//\n+// Example:\n+//\n+// \t* -> compress() -> \"https://www.example.org\"\n+//\n+// The filter, when executed on the response path, checks if the response\n+// entity can be compressed. To decide, it checks the Content-Encoding, the\n+// Cache-Control and the Content-Type headers. It doesn't compress the content\n+// if the Content-Encoding is set to other than identity, or the Cache-Control\n+// applies the no-transform pragma, or the Content-Type is set to an unsupported\n+// value.\n+//\n+// The default supported content types are: text/plain, text/html,\n+// application/json, application/javascript, application/x-javascript,\n+// text/javascript, text/css, image/svg+xml, application/octet-stream.\n+//\n+// The default set of MIME types can be reset or extended by passing in the desired\n+// types as filter arguments. When extending the defaults, the first argument needs\n+// to be \"...\". E.g. to compress tiff in addition to the defaults:\n+//\n+// \t* -> compress(\"...\", \"image/tiff\") -> \"https://www.example.org\"\n+//\n+// To reset the supported types, e.g. to compress only HTML, the \"...\" argument\n+// needs to be omitted:\n+//\n+// \t* -> compress(\"text/html\") -> \"https://www.example.org\"\n+//\n+// The filter also checks the incoming request, if it accepts the supported\n+// encodings, explicitly stated in the Accept-Encoding header. The filter currently\n+// supports gzip and deflate. It does not assume that the client accepts any\n+// encoding if the Accept-Encoding header is not set. It ignores * in the\n+// Accept-Encoding header.\n+//\n+// When compressing the response, it updates the response header. It deletes the\n+// the Content-Length value triggering the proxy to always return the response\n+// with chunked transfer encoding, sets the Content-Encoding to the selected\n+// encoding and sets the Vary: Accept-Encoding header, if missing.\n+//\n+// The compression happens in a streaming way, using only a small internal buffer.\n+//\n+func NewCompress() filters.Spec { return &compress{} }\n+\n+func (c *compress) Name() string {\n+\treturn CompressName\n+}\n+\n+func (c *compress) CreateFilter(args []interface{}) (filters.Filter, error) {\n+\tf := &compress{}\n+\n+\tif len(args) == 0 {\n+\t\tf.mime = defaultCompressMIME\n+\t\treturn f, nil\n+\t}\n+\n+\tif args[0] == \"...\" {\n+\t\tf.mime = defaultCompressMIME\n+\t\targs = args[1:]\n+\t}\n+\n+\tfor _, a := range args {\n+\t\tif s, ok := a.(string); ok {\n+\t\t\tf.mime = append(f.mime, s)\n+\t\t} else {\n+\t\t\treturn nil, filters.ErrInvalidFilterParameters\n+\t\t}\n+\t}\n+\n+\treturn f, nil\n+}\n+\n+func (c *compress) Request(_ filters.FilterContext) {}\n+\n+func stringsContain(ss []string, s string, transform ...func(string) string) bool {\n+\tfor _, si := range ss {\n+\t\tfor _, t := range transform {\n+\t\t\tsi = t(si)\n+\t\t}\n+\n+\t\tif si == s {\n+\t\t\treturn true\n+\t\t}\n+\t}\n+\n+\treturn false\n+}\n+\n+func canEncodeEntity(r *http.Response, mime []string) bool {\n+\tif ce := r.Header.Get(\"Content-Encoding\"); ce != \"\" && ce != \"identity\" /* forgiving for identity */ {\n+\t\treturn false\n+\t}\n+\n+\tcc := strings.Split(r.Header.Get(\"Cache-Control\"), \",\")\n+\tif stringsContain(cc, \"no-transform\", strings.TrimSpace, strings.ToLower) {\n+\t\treturn false\n+\t}\n+\n+\tct := r.Header.Get(\"Content-Type\")\n+\tif i := strings.Index(ct, \";\"); i >= 0 {\n+\t\tct = ct[:i]\n+\t}\n+\n+\tif !stringsContain(mime, ct) {\n+\t\treturn false\n+\t}\n+\n+\treturn true\n+}\n+\n+func acceptedEncoding(r *http.Request) string {\n+\tvar encs encodings\n+\tfor _, s := range strings.Split(r.Header.Get(\"Accept-Encoding\"), \",\") {\n+\t\tsp := strings.Split(s, \";\")\n+\t\tif len(sp) == 0 {\n+\t\t\tcontinue\n+\t\t}\n+\n+\t\tname := strings.ToLower(strings.TrimSpace(sp[0]))\n+\t\tif !stringsContain(supportedEncodings, name) {\n+\t\t\tcontinue\n+\t\t}\n+\n+\t\tenc := &encoding{name, 1}\n+\t\tencs = append(encs, enc)\n+\n+\t\tfor _, spi := range sp[1:] {\n+\t\t\tspi = strings.TrimSpace(spi)\n+\t\t\tif !strings.HasPrefix(spi, \"q=\") {\n+\t\t\t\tcontinue\n+\t\t\t}\n+\n+\t\t\tq, err := strconv.ParseFloat(strings.TrimPrefix(spi, \"q=\"), 32)\n+\t\t\tif err != nil {\n+\t\t\t\tcontinue\n+\t\t\t}\n+\n+\t\t\tenc.q = float32(q)\n+\t\t\tbreak\n+\t\t}\n+\t}\n+\n+\tif len(encs) == 0 {\n+\t\treturn \"\"\n+\t}\n+\n+\tsort.Sort(encs)\n+\treturn encs[0].name\n+}\n+\n+func responseHeader(r *http.Response, enc string) {\n+\tr.Header.Del(\"Content-Length\")\n+\tr.Header.Set(\"Content-Encoding\", enc)\n+\n+\tif !stringsContain(r.Header[\"Vary\"], \"Accept-Encoding\", http.CanonicalHeaderKey) {\n+\t\tr.Header.Add(\"Vary\", \"Accept-Encoding\")\n+\t}\n+}\n+\n+// Not handled encoding is considered as an implementation error, since\n+// these functions are only called from inside the package, and the\n+// encoding should be selected from a predefined set.\n+func unsupported() {\n+\tpanic(unsupportedEncoding)\n+}\n+\n+func newEncoder(enc string) encoder {\n+\tswitch enc {\n+\tcase \"gzip\":\n+\t\tgw, err := gzip.NewWriterLevel(nil, gzip.BestSpeed)\n+\t\tif err != nil {\n+\t\t\t// This is considered as an implementation error, since the compress/gzip doc\n+\t\t\t// states that it returns an error only if the compression level is invalid.\n+\t\t\tpanic(err)\n+\t\t}\n+\n+\t\treturn gw\n+\tcase \"deflate\":\n+\t\tfw, err := flate.NewWriter(nil, flate.BestSpeed)","path":"filters/builtin/compress.go","position":252,"original_position":249,"commit_id":"2901d40eb0637919a2325da851686c38426230b0","original_commit_id":"5ebdb6fb6c7ae88ad69151d0fa9c5eb5670f5911","user":{"login":"mo-gr","id":95577,"avatar_url":"https://avatars.githubusercontent.com/u/95577?v=3","gravatar_id":"","url":"https://api.github.com/users/mo-gr","html_url":"https://github.com/mo-gr","followers_url":"https://api.github.com/users/mo-gr/followers","following_url":"https://api.github.com/users/mo-gr/following{/other_user}","gists_url":"https://api.github.com/users/mo-gr/gists{/gist_id}","starred_url":"https://api.github.com/users/mo-gr/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/mo-gr/subscriptions","organizations_url":"https://api.github.com/users/mo-gr/orgs","repos_url":"https://api.github.com/users/mo-gr/repos","events_url":"https://api.github.com/users/mo-gr/events{/privacy}","received_events_url":"https://api.github.com/users/mo-gr/received_events","type":"User","site_admin":false},"body":"No, I mean just provide an option for gzip.BestCompression (or whatever) when you configure skippers filters","created_at":"2016-06-02T11:40:00Z","updated_at":"2016-06-02T11:40:00Z","html_url":"https://github.com/zalando/skipper/pull/161#discussion_r65524208","pull_request_url":"https://api.github.com/repos/zalando/skipper/pulls/161","_links":{"self":{"href":"https://api.github.com/repos/zalando/skipper/pulls/comments/65524208"},"html":{"href":"https://github.com/zalando/skipper/pull/161#discussion_r65524208"},"pull_request":{"href":"https://api.github.com/repos/zalando/skipper/pulls/161"}}},"pull_request":{"url":"https://api.github.com/repos/zalando/skipper/pulls/161","id":72209132,"html_url":"https://github.com/zalando/skipper/pull/161","diff_url":"https://github.com/zalando/skipper/pull/161.diff","patch_url":"https://github.com/zalando/skipper/pull/161.patch","issue_url":"https://api.github.com/repos/zalando/skipper/issues/161","number":161,"state":"open","locked":false,"title":"Compression","user":{"login":"aryszka","id":733217,"avatar_url":"https://avatars.githubusercontent.com/u/733217?v=3","gravatar_id":"","url":"https://api.github.com/users/aryszka","html_url":"https://github.com/aryszka","followers_url":"https://api.github.com/users/aryszka/followers","following_url":"https://api.github.com/users/aryszka/following{/other_user}","gists_url":"https://api.github.com/users/aryszka/gists{/gist_id}","starred_url":"https://api.github.com/users/aryszka/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/aryszka/subscriptions","organizations_url":"https://api.github.com/users/aryszka/orgs","repos_url":"https://api.github.com/users/aryszka/repos","events_url":"https://api.github.com/users/aryszka/events{/privacy}","received_events_url":"https://api.github.com/users/aryszka/received_events","type":"User","site_admin":false},"body":"","created_at":"2016-06-01T16:10:54Z","updated_at":"2016-06-02T11:40:00Z","closed_at":null,"merged_at":null,"merge_commit_sha":"e1af6418f96cf7a06ea7fcab0405e11fd8061c2b","assignee":null,"milestone":null,"commits_url":"https://api.github.com/repos/zalando/skipper/pulls/161/commits","review_comments_url":"https://api.github.com/repos/zalando/skipper/pulls/161/comments","review_comment_url":"https://api.github.com/repos/zalando/skipper/pulls/comments{/number}","comments_url":"https://api.github.com/repos/zalando/skipper/issues/161/comments","statuses_url":"https://api.github.com/repos/zalando/skipper/statuses/2901d40eb0637919a2325da851686c38426230b0","head":{"label":"zalando:compression","ref":"compression","sha":"2901d40eb0637919a2325da851686c38426230b0","user":{"login":"zalando","id":1564818,"avatar_url":"https://avatars.githubusercontent.com/u/1564818?v=3","gravatar_id":"","url":"https://api.github.com/users/zalando","html_url":"https://github.com/zalando","followers_url":"https://api.github.com/users/zalando/followers","following_url":"https://api.github.com/users/zalando/following{/other_user}","gists_url":"https://api.github.com/users/zalando/gists{/gist_id}","starred_url":"https://api.github.com/users/zalando/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/zalando/subscriptions","organizations_url":"https://api.github.com/users/zalando/orgs","repos_url":"https://api.github.com/users/zalando/repos","events_url":"https://api.github.com/users/zalando/events{/privacy}","received_events_url":"https://api.github.com/users/zalando/received_events","type":"Organization","site_admin":false},"repo":{"id":38812664,"name":"skipper","full_name":"zalando/skipper","owner":{"login":"zalando","id":1564818,"avatar_url":"https://avatars.githubusercontent.com/u/1564818?v=3","gravatar_id":"","url":"https://api.github.com/users/zalando","html_url":"https://github.com/zalando","followers_url":"https://api.github.com/users/zalando/followers","following_url":"https://api.github.com/users/zalando/following{/other_user}","gists_url":"https://api.github.com/users/zalando/gists{/gist_id}","starred_url":"https://api.github.com/users/zalando/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/zalando/subscriptions","organizations_url":"https://api.github.com/users/zalando/orgs","repos_url":"https://api.github.com/users/zalando/repos","events_url":"https://api.github.com/users/zalando/events{/privacy}","received_events_url":"https://api.github.com/users/zalando/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/zalando/skipper","description":"An HTTP router, built with Go, that acts as a reverse proxy with support for custom route definitions","fork":false,"url":"https://api.github.com/repos/zalando/skipper","forks_url":"https://api.github.com/repos/zalando/skipper/forks","keys_url":"https://api.github.com/repos/zalando/skipper/keys{/key_id}","collaborators_url":"https://api.github.com/repos/zalando/skipper/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/zalando/skipper/teams","hooks_url":"https://api.github.com/repos/zalando/skipper/hooks","issue_events_url":"https://api.github.com/repos/zalando/skipper/issues/events{/number}","events_url":"https://api.github.com/repos/zalando/skipper/events","assignees_url":"https://api.github.com/repos/zalando/skipper/assignees{/user}","branches_url":"https://api.github.com/repos/zalando/skipper/branches{/branch}","tags_url":"https://api.github.com/repos/zalando/skipper/tags","blobs_url":"https://api.github.com/repos/zalando/skipper/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/zalando/skipper/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/zalando/skipper/git/refs{/sha}","trees_url":"https://api.github.com/repos/zalando/skipper/git/trees{/sha}","statuses_url":"https://api.github.com/repos/zalando/skipper/statuses/{sha}","languages_url":"https://api.github.com/repos/zalando/skipper/languages","stargazers_url":"https://api.github.com/repos/zalando/skipper/stargazers","contributors_url":"https://api.github.com/repos/zalando/skipper/contributors","subscribers_url":"https://api.github.com/repos/zalando/skipper/subscribers","subscription_url":"https://api.github.com/repos/zalando/skipper/subscription","commits_url":"https://api.github.com/repos/zalando/skipper/commits{/sha}","git_commits_url":"https://api.github.com/repos/zalando/skipper/git/commits{/sha}","comments_url":"https://api.github.com/repos/zalando/skipper/comments{/number}","issue_comment_url":"https://api.github.com/repos/zalando/skipper/issues/comments{/number}","contents_url":"https://api.github.com/repos/zalando/skipper/contents/{+path}","compare_url":"https://api.github.com/repos/zalando/skipper/compare/{base}...{head}","merges_url":"https://api.github.com/repos/zalando/skipper/merges","archive_url":"https://api.github.com/repos/zalando/skipper/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/zalando/skipper/downloads","issues_url":"https://api.github.com/repos/zalando/skipper/issues{/number}","pulls_url":"https://api.github.com/repos/zalando/skipper/pulls{/number}","milestones_url":"https://api.github.com/repos/zalando/skipper/milestones{/number}","notifications_url":"https://api.github.com/repos/zalando/skipper/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/zalando/skipper/labels{/name}","releases_url":"https://api.github.com/repos/zalando/skipper/releases{/id}","deployments_url":"https://api.github.com/repos/zalando/skipper/deployments","created_at":"2015-07-09T09:54:40Z","updated_at":"2016-05-27T06:55:23Z","pushed_at":"2016-06-02T10:09:09Z","git_url":"git://github.com/zalando/skipper.git","ssh_url":"git@github.com:zalando/skipper.git","clone_url":"https://github.com/zalando/skipper.git","svn_url":"https://github.com/zalando/skipper","homepage":"","size":4581,"stargazers_count":153,"watchers_count":153,"language":"Go","has_issues":true,"has_downloads":true,"has_wiki":true,"has_pages":true,"forks_count":15,"mirror_url":null,"open_issues_count":37,"forks":15,"open_issues":37,"watchers":153,"default_branch":"master"}},"base":{"label":"zalando:master","ref":"master","sha":"909d0108aa7e32df34ed501b06b5fa6c3834e3bb","user":{"login":"zalando","id":1564818,"avatar_url":"https://avatars.githubusercontent.com/u/1564818?v=3","gravatar_id":"","url":"https://api.github.com/users/zalando","html_url":"https://github.com/zalando","followers_url":"https://api.github.com/users/zalando/followers","following_url":"https://api.github.com/users/zalando/following{/other_user}","gists_url":"https://api.github.com/users/zalando/gists{/gist_id}","starred_url":"https://api.github.com/users/zalando/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/zalando/subscriptions","organizations_url":"https://api.github.com/users/zalando/orgs","repos_url":"https://api.github.com/users/zalando/repos","events_url":"https://api.github.com/users/zalando/events{/privacy}","received_events_url":"https://api.github.com/users/zalando/received_events","type":"Organization","site_admin":false},"repo":{"id":38812664,"name":"skipper","full_name":"zalando/skipper","owner":{"login":"zalando","id":1564818,"avatar_url":"https://avatars.githubusercontent.com/u/1564818?v=3","gravatar_id":"","url":"https://api.github.com/users/zalando","html_url":"https://github.com/zalando","followers_url":"https://api.github.com/users/zalando/followers","following_url":"https://api.github.com/users/zalando/following{/other_user}","gists_url":"https://api.github.com/users/zalando/gists{/gist_id}","starred_url":"https://api.github.com/users/zalando/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/zalando/subscriptions","organizations_url":"https://api.github.com/users/zalando/orgs","repos_url":"https://api.github.com/users/zalando/repos","events_url":"https://api.github.com/users/zalando/events{/privacy}","received_events_url":"https://api.github.com/users/zalando/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/zalando/skipper","description":"An HTTP router, built with Go, that acts as a reverse proxy with support for custom route definitions","fork":false,"url":"https://api.github.com/repos/zalando/skipper","forks_url":"https://api.github.com/repos/zalando/skipper/forks","keys_url":"https://api.github.com/repos/zalando/skipper/keys{/key_id}","collaborators_url":"https://api.github.com/repos/zalando/skipper/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/zalando/skipper/teams","hooks_url":"https://api.github.com/repos/zalando/skipper/hooks","issue_events_url":"https://api.github.com/repos/zalando/skipper/issues/events{/number}","events_url":"https://api.github.com/repos/zalando/skipper/events","assignees_url":"https://api.github.com/repos/zalando/skipper/assignees{/user}","branches_url":"https://api.github.com/repos/zalando/skipper/branches{/branch}","tags_url":"https://api.github.com/repos/zalando/skipper/tags","blobs_url":"https://api.github.com/repos/zalando/skipper/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/zalando/skipper/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/zalando/skipper/git/refs{/sha}","trees_url":"https://api.github.com/repos/zalando/skipper/git/trees{/sha}","statuses_url":"https://api.github.com/repos/zalando/skipper/statuses/{sha}","languages_url":"https://api.github.com/repos/zalando/skipper/languages","stargazers_url":"https://api.github.com/repos/zalando/skipper/stargazers","contributors_url":"https://api.github.com/repos/zalando/skipper/contributors","subscribers_url":"https://api.github.com/repos/zalando/skipper/subscribers","subscription_url":"https://api.github.com/repos/zalando/skipper/subscription","commits_url":"https://api.github.com/repos/zalando/skipper/commits{/sha}","git_commits_url":"https://api.github.com/repos/zalando/skipper/git/commits{/sha}","comments_url":"https://api.github.com/repos/zalando/skipper/comments{/number}","issue_comment_url":"https://api.github.com/repos/zalando/skipper/issues/comments{/number}","contents_url":"https://api.github.com/repos/zalando/skipper/contents/{+path}","compare_url":"https://api.github.com/repos/zalando/skipper/compare/{base}...{head}","merges_url":"https://api.github.com/repos/zalando/skipper/merges","archive_url":"https://api.github.com/repos/zalando/skipper/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/zalando/skipper/downloads","issues_url":"https://api.github.com/repos/zalando/skipper/issues{/number}","pulls_url":"https://api.github.com/repos/zalando/skipper/pulls{/number}","milestones_url":"https://api.github.com/repos/zalando/skipper/milestones{/number}","notifications_url":"https://api.github.com/repos/zalando/skipper/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/zalando/skipper/labels{/name}","releases_url":"https://api.github.com/repos/zalando/skipper/releases{/id}","deployments_url":"https://api.github.com/repos/zalando/skipper/deployments","created_at":"2015-07-09T09:54:40Z","updated_at":"2016-05-27T06:55:23Z","pushed_at":"2016-06-02T10:09:09Z","git_url":"git://github.com/zalando/skipper.git","ssh_url":"git@github.com:zalando/skipper.git","clone_url":"https://github.com/zalando/skipper.git","svn_url":"https://github.com/zalando/skipper","homepage":"","size":4581,"stargazers_count":153,"watchers_count":153,"language":"Go","has_issues":true,"has_downloads":true,"has_wiki":true,"has_pages":true,"forks_count":15,"mirror_url":null,"open_issues_count":37,"forks":15,"open_issues":37,"watchers":153,"default_branch":"master"}},"_links":{"self":{"href":"https://api.github.com/repos/zalando/skipper/pulls/161"},"html":{"href":"https://github.com/zalando/skipper/pull/161"},"issue":{"href":"https://api.github.com/repos/zalando/skipper/issues/161"},"comments":{"href":"https://api.github.com/repos/zalando/skipper/issues/161/comments"},"review_comments":{"href":"https://api.github.com/repos/zalando/skipper/pulls/161/comments"},"review_comment":{"href":"https://api.github.com/repos/zalando/skipper/pulls/comments{/number}"},"commits":{"href":"https://api.github.com/repos/zalando/skipper/pulls/161/commits"},"statuses":{"href":"https://api.github.com/repos/zalando/skipper/statuses/2901d40eb0637919a2325da851686c38426230b0"}}}}
{"actor":{"display_login":"mo-gr"}}