{"action":"created","comment":{"url":"https://api.github.com/repos/netty/netty/pulls/comments/35913184","id":35913184,"diff_hunk":"@@ -59,234 +58,27 @@\n     }\n \n     private final TextHeaders headers;\n-    private static final class HttpHeadersValidationConverter extends DefaultTextValueTypeConverter {\n-        private final boolean validate;\n-\n-        HttpHeadersValidationConverter(boolean validate) {\n-            this.validate = validate;\n-        }\n-\n-        @Override\n-        public CharSequence convertObject(Object value) {\n-            if (value == null) {\n-                throw new NullPointerException(\"value\");\n-            }\n-\n-            CharSequence seq;\n-            if (value instanceof CharSequence) {\n-                seq = (CharSequence) value;\n-            } else if (value instanceof Number) {\n-                seq = value.toString();\n-            } else if (value instanceof Date) {\n-                seq = HttpHeaderDateFormat.get().format((Date) value);\n-            } else if (value instanceof Calendar) {\n-                seq = HttpHeaderDateFormat.get().format(((Calendar) value).getTime());\n-            } else {\n-                seq = value.toString();\n-            }\n-\n-            if (validate) {\n-                if (value instanceof AsciiString) {\n-                    validateValue((AsciiString) seq);\n-                } else {\n-                    validateValue(seq);\n-                }\n-            }\n-\n-            return seq;\n-        }\n-\n-        private static final class ValidateValueProcessor implements ByteProcessor {\n-            private final CharSequence seq;\n-            private int state;\n-\n-            public ValidateValueProcessor(CharSequence seq) {\n-                this.seq = seq;\n-            }\n-\n-            @Override\n-            public boolean process(byte value) throws Exception {\n-                state = validateValueChar(state, (char) value, seq);\n-                return true;\n-            }\n-\n-            public int state() {\n-                return state;\n-            }\n-        }\n-\n-        private static void validateValue(AsciiString seq) {\n-            ValidateValueProcessor processor = new ValidateValueProcessor(seq);\n-            try {\n-                seq.forEachByte(processor);\n-            } catch (Throwable t) {\n-                PlatformDependent.throwException(t);\n-            }\n-\n-            if (processor.state() != 0) {\n-                throw new IllegalArgumentException(\"a header value must not end with '\\\\r' or '\\\\n':\" + seq);\n-            }\n-        }\n-\n-        private static void validateValue(CharSequence seq) {\n-            int state = 0;\n-            // Start looping through each of the character\n-            for (int index = 0; index < seq.length(); index++) {\n-                state = validateValueChar(state, seq.charAt(index), seq);\n-            }\n-\n-            if (state != 0) {\n-                throw new IllegalArgumentException(\"a header value must not end with '\\\\r' or '\\\\n':\" + seq);\n-            }\n-        }\n-\n-        private static int validateValueChar(int state, char c, CharSequence seq) {\n-            /*\n-             * State:\n-             * 0: Previous character was neither CR nor LF\n-             * 1: The previous character was CR\n-             * 2: The previous character was LF\n-             */\n-            if ((c & HIGHEST_INVALID_VALUE_CHAR_MASK) == 0) {\n-                // Check the absolutely prohibited characters.\n-                switch (c) {\n-                case 0x0: // NULL\n-                    throw new IllegalArgumentException(\"a header value contains a prohibited character '\\0': \" + seq);\n-                case 0x0b: // Vertical tab\n-                    throw new IllegalArgumentException(\"a header value contains a prohibited character '\\\\v': \" + seq);\n-                case '\\f':\n-                    throw new IllegalArgumentException(\"a header value contains a prohibited character '\\\\f': \" + seq);\n-                }\n-            }\n-\n-            // Check the CRLF (HT | SP) pattern\n-            switch (state) {\n-            case 0:\n-                switch (c) {\n-                case '\\r':\n-                    state = 1;\n-                    break;\n-                case '\\n':\n-                    state = 2;\n-                    break;\n-                }\n-                break;\n-            case 1:\n-                switch (c) {\n-                case '\\n':\n-                    state = 2;\n-                    break;\n-                default:\n-                    throw new IllegalArgumentException(\"only '\\\\n' is allowed after '\\\\r': \" + seq);\n-                }\n-                break;\n-            case 2:\n-                switch (c) {\n-                case '\\t':\n-                case ' ':\n-                    state = 0;\n-                    break;\n-                default:\n-                    throw new IllegalArgumentException(\"only ' ' and '\\\\t' are allowed after '\\\\n': \" + seq);\n-                }\n-            }\n-            return state;\n-        }\n-    }\n-\n-    static class HttpHeadersNameConverter implements NameConverter<CharSequence> {\n-        protected final boolean validate;\n-\n-        private static final class ValidateNameProcessor implements ByteProcessor {\n-            private final CharSequence seq;\n-\n-            public ValidateNameProcessor(CharSequence seq) {\n-                this.seq = seq;\n-            }\n-\n-            @Override\n-            public boolean process(byte value) throws Exception {\n-                // Check to see if the character is not an ASCII character.\n-                if (value < 0) {\n-                    throw new IllegalArgumentException(\"a header name cannot contain non-ASCII character: \" + seq);\n-                }\n-                validateNameChar(value, seq);\n-                return true;\n-            }\n-        }\n-\n-        HttpHeadersNameConverter(boolean validate) {\n-            this.validate = validate;\n-        }\n-\n-        @Override\n-        public CharSequence convertName(CharSequence name) {\n-            if (validate) {\n-                if (name instanceof AsciiString) {\n-                    validateName((AsciiString) name);\n-                } else {\n-                    validateName(name);\n-                }\n-            }\n-\n-            return name;\n-        }\n-\n-        private static void validateName(AsciiString name) {\n-            try {\n-                name.forEachByte(new ValidateNameProcessor(name));\n-            } catch (Throwable t) {\n-                PlatformDependent.throwException(t);\n-            }\n-        }\n-\n-        private static void validateName(CharSequence name) {\n-            // Go through each characters in the name.\n-            for (int index = 0; index < name.length(); index++) {\n-                char c = name.charAt(index);\n-\n-                // Check to see if the character is not an ASCII character.\n-                if (c > 127) {\n-                    throw new IllegalArgumentException(\"a header name cannot contain non-ASCII characters: \" + name);\n-                }\n-\n-                // Check for prohibited characters.\n-                validateNameChar(c, name);\n-            }\n-        }\n-\n-        private static void validateNameChar(int character, CharSequence seq) {\n-            if ((character & HIGHEST_INVALID_NAME_CHAR_MASK) == 0 && LOOKUP_TABLE[character] != 0) {\n-                throw new IllegalArgumentException(\n-                        \"a header name cannot contain the following prohibited characters: =,;: \\\\t\\\\r\\\\n\\\\v\\\\f: \" +\n-                                seq);\n-            }\n-        }\n-    }\n-\n-    private static final HttpHeadersValidationConverter\n-        VALIDATE_OBJECT_CONVERTER = new HttpHeadersValidationConverter(true);\n-    private static final HttpHeadersValidationConverter\n-        NO_VALIDATE_OBJECT_CONVERTER = new HttpHeadersValidationConverter(false);\n-    private static final HttpHeadersNameConverter VALIDATE_NAME_CONVERTER = new HttpHeadersNameConverter(true);\n-    private static final HttpHeadersNameConverter NO_VALIDATE_NAME_CONVERTER = new HttpHeadersNameConverter(false);\n \n     public DefaultHttpHeaders() {\n         this(true);\n     }\n \n     public DefaultHttpHeaders(boolean validate) {\n-        this(true, validate? VALIDATE_NAME_CONVERTER : NO_VALIDATE_NAME_CONVERTER, false);\n+        this(validate, false);\n     }\n \n-    public DefaultHttpHeaders(boolean validate, boolean singleHeaderFields) {\n-        this(true, validate? VALIDATE_NAME_CONVERTER : NO_VALIDATE_NAME_CONVERTER, singleHeaderFields);\n+    protected DefaultHttpHeaders(boolean validate, boolean singleHeaderFields) {\n+        this(true, validate ? HeaderNameValidator.INSTANCE : DefaultTextHeaders.NO_NAME_VALIDATOR, singleHeaderFields);\n     }\n \n-    protected DefaultHttpHeaders(boolean validate, NameConverter<CharSequence> nameConverter,\n+    protected DefaultHttpHeaders(boolean validate,\n+                                 DefaultHeaders.NameValidator<CharSequence> nameValidator,\n                                  boolean singleHeaderFields) {\n-        headers = new DefaultTextHeaders(true,\n-                validate ? VALIDATE_OBJECT_CONVERTER : NO_VALIDATE_OBJECT_CONVERTER, nameConverter, singleHeaderFields);\n+        headers = new DefaultTextHeaders(\n+                    new TreeMap<CharSequence, Object>(AsciiString.CHARSEQUENCE_CASE_INSENSITIVE_ORDER),","path":"codec-http/src/main/java/io/netty/handler/codec/http/DefaultHttpHeaders.java","position":274,"original_position":274,"commit_id":"ae7f182810191be60cbb714f5f51de5195910578","original_commit_id":"ae7f182810191be60cbb714f5f51de5195910578","user":{"login":"Scottmitch","id":7562868,"avatar_url":"https://avatars.githubusercontent.com/u/7562868?v=3","gravatar_id":"","url":"https://api.github.com/users/Scottmitch","html_url":"https://github.com/Scottmitch","followers_url":"https://api.github.com/users/Scottmitch/followers","following_url":"https://api.github.com/users/Scottmitch/following{/other_user}","gists_url":"https://api.github.com/users/Scottmitch/gists{/gist_id}","starred_url":"https://api.github.com/users/Scottmitch/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/Scottmitch/subscriptions","organizations_url":"https://api.github.com/users/Scottmitch/orgs","repos_url":"https://api.github.com/users/Scottmitch/repos","events_url":"https://api.github.com/users/Scottmitch/events{/privacy}","received_events_url":"https://api.github.com/users/Scottmitch/received_events","type":"User","site_admin":false},"body":"@normanmaurer - @buchgr could answer more. But I think it had to do with:\r\n\r\n1. not having to \"resize/copy\" \r\n2. not having to generate hash codes and using the equals method continuously.","created_at":"2015-07-30T19:57:43Z","updated_at":"2015-07-30T19:57:43Z","html_url":"https://github.com/netty/netty/pull/4051#discussion_r35913184","pull_request_url":"https://api.github.com/repos/netty/netty/pulls/4051","_links":{"self":{"href":"https://api.github.com/repos/netty/netty/pulls/comments/35913184"},"html":{"href":"https://github.com/netty/netty/pull/4051#discussion_r35913184"},"pull_request":{"href":"https://api.github.com/repos/netty/netty/pulls/4051"}}},"pull_request":{"url":"https://api.github.com/repos/netty/netty/pulls/4051","id":41273476,"html_url":"https://github.com/netty/netty/pull/4051","diff_url":"https://github.com/netty/netty/pull/4051.diff","patch_url":"https://github.com/netty/netty/pull/4051.patch","issue_url":"https://api.github.com/repos/netty/netty/issues/4051","number":4051,"state":"open","locked":false,"title":"Faster and more memory efficient headers for HTTP, HTTP/2, STOMP and …","user":{"login":"Scottmitch","id":7562868,"avatar_url":"https://avatars.githubusercontent.com/u/7562868?v=3","gravatar_id":"","url":"https://api.github.com/users/Scottmitch","html_url":"https://github.com/Scottmitch","followers_url":"https://api.github.com/users/Scottmitch/followers","following_url":"https://api.github.com/users/Scottmitch/following{/other_user}","gists_url":"https://api.github.com/users/Scottmitch/gists{/gist_id}","starred_url":"https://api.github.com/users/Scottmitch/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/Scottmitch/subscriptions","organizations_url":"https://api.github.com/users/Scottmitch/orgs","repos_url":"https://api.github.com/users/Scottmitch/repos","events_url":"https://api.github.com/users/Scottmitch/events{/privacy}","received_events_url":"https://api.github.com/users/Scottmitch/received_events","type":"User","site_admin":false},"body":"…SPYD. Fixes #3600\r\n\r\nMotivation:\r\n\r\nWe noticed that the headers implementation in Netty for HTTP/2 uses quite a lot of memory\r\nand that also at least the performance of randomly accessing a header is quite poor. The main\r\nconcern however was memory usage, as profiling has shown that a DefaultHttp2Headers\r\nnot only use a lot of memory it also wastes a lot due to the underlying hashmaps having\r\nto be resized potentially several times as new headers are being inserted.\r\n\r\nThis is tracked as issue #3600.\r\n\r\nModifications:\r\nWe redesigned the DefaultHeaders to simply take a Map object in its constructor and\r\nreimplemented the class using only the Map primitives. That way the implementation\r\nis very concise and hopefully easy to understand and it allows each concrete headers\r\nimplementation to provide its own map or to even use a different headers implementation\r\nfor processing requests and writing responses i.e. incoming headers need to provide\r\nfast random access while outgoing headers need fast insertion and fast iteration. The\r\nnew implementation can support this with hardly any code changes. It also comes\r\nwith the advantage that if the Netty project decides to add a third party collections library\r\nas a dependency, one can simply plug in one of those very fast and memory efficient map\r\nimplementations and get faster and smaller headers for free.\r\n\r\nFor now, we are using the JDK's TreeMap for HTTP and HTTP/2 default headers.\r\n\r\nResult:\r\n\r\n- Significantly fewer lines of code in the implementation. While the total commit is still\r\n  roughly 400 lines less, the actual implementation is a lot less. I just added some more\r\n  tests and microbenchmarks.\r\n\r\n- Overall performance is up. The current implementation should be significantly faster\r\n  for insertion and retrieval. However, it is slower when it comes to iteration. There is simply\r\n  no way a TreeMap can have the same iteration performance as a linked list (as used in the\r\n  current headers implementation). That's totally fine though, because when looking at the\r\n  benchmark results @ejona86 pointed out that the performance of the headers is completely\r\n  dominated by insertion, that is insertion is so significantly faster in the new implementation\r\n  that it does make up for several times the iteration speed. You can't iterate what you haven't\r\n  inserted. I am demonstrating that in this spreadsheet [1]. (Actually, iteration performance is\r\n  only down for HTTP, it's significantly improved for HTTP/2).\r\n\r\n- Memory is down. The implementation with TreeMap uses on avg ~30% less memory. It also does not\r\n  produce any garbage while being resized. In load tests for GRPC we have seen a memory reduction\r\n  of up to 1.2KB per RPC. I summarized the memory improvements in this spreadsheet [1]. The data\r\n  was generated by [2] using JOL.\r\n\r\n- While it was my original intend to only improve the memory usage for HTTP/2, it should be similarly\r\n  improved for HTTP, SPDY and STOMP as they all share a common implementation.\r\n\r\n[1] https://docs.google.com/spreadsheets/d/1ck3RQklyzEcCLlyJoqDXPCWRGVUuS-ArZf0etSXLVDQ/edit#gid=0\r\n[2] https://gist.github.com/buchgr/4458a8bdb51dd58c82b4","created_at":"2015-07-30T19:39:59Z","updated_at":"2015-07-30T19:57:43Z","closed_at":null,"merged_at":null,"merge_commit_sha":"2154bb0e492d56e0fea7def358b385bbbf83c894","assignee":{"login":"Scottmitch","id":7562868,"avatar_url":"https://avatars.githubusercontent.com/u/7562868?v=3","gravatar_id":"","url":"https://api.github.com/users/Scottmitch","html_url":"https://github.com/Scottmitch","followers_url":"https://api.github.com/users/Scottmitch/followers","following_url":"https://api.github.com/users/Scottmitch/following{/other_user}","gists_url":"https://api.github.com/users/Scottmitch/gists{/gist_id}","starred_url":"https://api.github.com/users/Scottmitch/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/Scottmitch/subscriptions","organizations_url":"https://api.github.com/users/Scottmitch/orgs","repos_url":"https://api.github.com/users/Scottmitch/repos","events_url":"https://api.github.com/users/Scottmitch/events{/privacy}","received_events_url":"https://api.github.com/users/Scottmitch/received_events","type":"User","site_admin":false},"milestone":{"url":"https://api.github.com/repos/netty/netty/milestones/117","html_url":"https://github.com/netty/netty/milestones/4.1.0.Beta6","labels_url":"https://api.github.com/repos/netty/netty/milestones/117/labels","id":1100817,"number":117,"title":"4.1.0.Beta6","description":"","creator":{"login":"normanmaurer","id":439362,"avatar_url":"https://avatars.githubusercontent.com/u/439362?v=3","gravatar_id":"","url":"https://api.github.com/users/normanmaurer","html_url":"https://github.com/normanmaurer","followers_url":"https://api.github.com/users/normanmaurer/followers","following_url":"https://api.github.com/users/normanmaurer/following{/other_user}","gists_url":"https://api.github.com/users/normanmaurer/gists{/gist_id}","starred_url":"https://api.github.com/users/normanmaurer/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/normanmaurer/subscriptions","organizations_url":"https://api.github.com/users/normanmaurer/orgs","repos_url":"https://api.github.com/users/normanmaurer/repos","events_url":"https://api.github.com/users/normanmaurer/events{/privacy}","received_events_url":"https://api.github.com/users/normanmaurer/received_events","type":"User","site_admin":false},"open_issues":74,"closed_issues":58,"state":"open","created_at":"2015-05-07T19:29:09Z","updated_at":"2015-07-30T19:39:59Z","due_on":null,"closed_at":null},"commits_url":"https://api.github.com/repos/netty/netty/pulls/4051/commits","review_comments_url":"https://api.github.com/repos/netty/netty/pulls/4051/comments","review_comment_url":"https://api.github.com/repos/netty/netty/pulls/comments{/number}","comments_url":"https://api.github.com/repos/netty/netty/issues/4051/comments","statuses_url":"https://api.github.com/repos/netty/netty/statuses/ae7f182810191be60cbb714f5f51de5195910578","head":{"label":"Scottmitch:newheaders_backport","ref":"newheaders_backport","sha":"ae7f182810191be60cbb714f5f51de5195910578","user":{"login":"Scottmitch","id":7562868,"avatar_url":"https://avatars.githubusercontent.com/u/7562868?v=3","gravatar_id":"","url":"https://api.github.com/users/Scottmitch","html_url":"https://github.com/Scottmitch","followers_url":"https://api.github.com/users/Scottmitch/followers","following_url":"https://api.github.com/users/Scottmitch/following{/other_user}","gists_url":"https://api.github.com/users/Scottmitch/gists{/gist_id}","starred_url":"https://api.github.com/users/Scottmitch/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/Scottmitch/subscriptions","organizations_url":"https://api.github.com/users/Scottmitch/orgs","repos_url":"https://api.github.com/users/Scottmitch/repos","events_url":"https://api.github.com/users/Scottmitch/events{/privacy}","received_events_url":"https://api.github.com/users/Scottmitch/received_events","type":"User","site_admin":false},"repo":{"id":21251366,"name":"netty","full_name":"Scottmitch/netty","owner":{"login":"Scottmitch","id":7562868,"avatar_url":"https://avatars.githubusercontent.com/u/7562868?v=3","gravatar_id":"","url":"https://api.github.com/users/Scottmitch","html_url":"https://github.com/Scottmitch","followers_url":"https://api.github.com/users/Scottmitch/followers","following_url":"https://api.github.com/users/Scottmitch/following{/other_user}","gists_url":"https://api.github.com/users/Scottmitch/gists{/gist_id}","starred_url":"https://api.github.com/users/Scottmitch/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/Scottmitch/subscriptions","organizations_url":"https://api.github.com/users/Scottmitch/orgs","repos_url":"https://api.github.com/users/Scottmitch/repos","events_url":"https://api.github.com/users/Scottmitch/events{/privacy}","received_events_url":"https://api.github.com/users/Scottmitch/received_events","type":"User","site_admin":false},"private":false,"html_url":"https://github.com/Scottmitch/netty","description":"Netty project - an event-driven asynchronous network application framework","fork":true,"url":"https://api.github.com/repos/Scottmitch/netty","forks_url":"https://api.github.com/repos/Scottmitch/netty/forks","keys_url":"https://api.github.com/repos/Scottmitch/netty/keys{/key_id}","collaborators_url":"https://api.github.com/repos/Scottmitch/netty/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/Scottmitch/netty/teams","hooks_url":"https://api.github.com/repos/Scottmitch/netty/hooks","issue_events_url":"https://api.github.com/repos/Scottmitch/netty/issues/events{/number}","events_url":"https://api.github.com/repos/Scottmitch/netty/events","assignees_url":"https://api.github.com/repos/Scottmitch/netty/assignees{/user}","branches_url":"https://api.github.com/repos/Scottmitch/netty/branches{/branch}","tags_url":"https://api.github.com/repos/Scottmitch/netty/tags","blobs_url":"https://api.github.com/repos/Scottmitch/netty/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/Scottmitch/netty/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/Scottmitch/netty/git/refs{/sha}","trees_url":"https://api.github.com/repos/Scottmitch/netty/git/trees{/sha}","statuses_url":"https://api.github.com/repos/Scottmitch/netty/statuses/{sha}","languages_url":"https://api.github.com/repos/Scottmitch/netty/languages","stargazers_url":"https://api.github.com/repos/Scottmitch/netty/stargazers","contributors_url":"https://api.github.com/repos/Scottmitch/netty/contributors","subscribers_url":"https://api.github.com/repos/Scottmitch/netty/subscribers","subscription_url":"https://api.github.com/repos/Scottmitch/netty/subscription","commits_url":"https://api.github.com/repos/Scottmitch/netty/commits{/sha}","git_commits_url":"https://api.github.com/repos/Scottmitch/netty/git/commits{/sha}","comments_url":"https://api.github.com/repos/Scottmitch/netty/comments{/number}","issue_comment_url":"https://api.github.com/repos/Scottmitch/netty/issues/comments{/number}","contents_url":"https://api.github.com/repos/Scottmitch/netty/contents/{+path}","compare_url":"https://api.github.com/repos/Scottmitch/netty/compare/{base}...{head}","merges_url":"https://api.github.com/repos/Scottmitch/netty/merges","archive_url":"https://api.github.com/repos/Scottmitch/netty/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/Scottmitch/netty/downloads","issues_url":"https://api.github.com/repos/Scottmitch/netty/issues{/number}","pulls_url":"https://api.github.com/repos/Scottmitch/netty/pulls{/number}","milestones_url":"https://api.github.com/repos/Scottmitch/netty/milestones{/number}","notifications_url":"https://api.github.com/repos/Scottmitch/netty/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/Scottmitch/netty/labels{/name}","releases_url":"https://api.github.com/repos/Scottmitch/netty/releases{/id}","created_at":"2014-06-26T18:56:19Z","updated_at":"2015-02-02T14:45:48Z","pushed_at":"2015-07-30T19:54:13Z","git_url":"git://github.com/Scottmitch/netty.git","ssh_url":"git@github.com:Scottmitch/netty.git","clone_url":"https://github.com/Scottmitch/netty.git","svn_url":"https://github.com/Scottmitch/netty","homepage":"http://netty.io/","size":44383,"stargazers_count":0,"watchers_count":0,"language":"Java","has_issues":false,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":1,"mirror_url":null,"open_issues_count":0,"forks":1,"open_issues":0,"watchers":0,"default_branch":"master"}},"base":{"label":"netty:4.1","ref":"4.1","sha":"f65717be827cc8d141daafc96cc6b8e11028aa92","user":{"login":"netty","id":473791,"avatar_url":"https://avatars.githubusercontent.com/u/473791?v=3","gravatar_id":"","url":"https://api.github.com/users/netty","html_url":"https://github.com/netty","followers_url":"https://api.github.com/users/netty/followers","following_url":"https://api.github.com/users/netty/following{/other_user}","gists_url":"https://api.github.com/users/netty/gists{/gist_id}","starred_url":"https://api.github.com/users/netty/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/netty/subscriptions","organizations_url":"https://api.github.com/users/netty/orgs","repos_url":"https://api.github.com/users/netty/repos","events_url":"https://api.github.com/users/netty/events{/privacy}","received_events_url":"https://api.github.com/users/netty/received_events","type":"Organization","site_admin":false},"repo":{"id":1064563,"name":"netty","full_name":"netty/netty","owner":{"login":"netty","id":473791,"avatar_url":"https://avatars.githubusercontent.com/u/473791?v=3","gravatar_id":"","url":"https://api.github.com/users/netty","html_url":"https://github.com/netty","followers_url":"https://api.github.com/users/netty/followers","following_url":"https://api.github.com/users/netty/following{/other_user}","gists_url":"https://api.github.com/users/netty/gists{/gist_id}","starred_url":"https://api.github.com/users/netty/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/netty/subscriptions","organizations_url":"https://api.github.com/users/netty/orgs","repos_url":"https://api.github.com/users/netty/repos","events_url":"https://api.github.com/users/netty/events{/privacy}","received_events_url":"https://api.github.com/users/netty/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/netty/netty","description":"Netty project - an event-driven asynchronous network application framework","fork":false,"url":"https://api.github.com/repos/netty/netty","forks_url":"https://api.github.com/repos/netty/netty/forks","keys_url":"https://api.github.com/repos/netty/netty/keys{/key_id}","collaborators_url":"https://api.github.com/repos/netty/netty/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/netty/netty/teams","hooks_url":"https://api.github.com/repos/netty/netty/hooks","issue_events_url":"https://api.github.com/repos/netty/netty/issues/events{/number}","events_url":"https://api.github.com/repos/netty/netty/events","assignees_url":"https://api.github.com/repos/netty/netty/assignees{/user}","branches_url":"https://api.github.com/repos/netty/netty/branches{/branch}","tags_url":"https://api.github.com/repos/netty/netty/tags","blobs_url":"https://api.github.com/repos/netty/netty/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/netty/netty/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/netty/netty/git/refs{/sha}","trees_url":"https://api.github.com/repos/netty/netty/git/trees{/sha}","statuses_url":"https://api.github.com/repos/netty/netty/statuses/{sha}","languages_url":"https://api.github.com/repos/netty/netty/languages","stargazers_url":"https://api.github.com/repos/netty/netty/stargazers","contributors_url":"https://api.github.com/repos/netty/netty/contributors","subscribers_url":"https://api.github.com/repos/netty/netty/subscribers","subscription_url":"https://api.github.com/repos/netty/netty/subscription","commits_url":"https://api.github.com/repos/netty/netty/commits{/sha}","git_commits_url":"https://api.github.com/repos/netty/netty/git/commits{/sha}","comments_url":"https://api.github.com/repos/netty/netty/comments{/number}","issue_comment_url":"https://api.github.com/repos/netty/netty/issues/comments{/number}","contents_url":"https://api.github.com/repos/netty/netty/contents/{+path}","compare_url":"https://api.github.com/repos/netty/netty/compare/{base}...{head}","merges_url":"https://api.github.com/repos/netty/netty/merges","archive_url":"https://api.github.com/repos/netty/netty/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/netty/netty/downloads","issues_url":"https://api.github.com/repos/netty/netty/issues{/number}","pulls_url":"https://api.github.com/repos/netty/netty/pulls{/number}","milestones_url":"https://api.github.com/repos/netty/netty/milestones{/number}","notifications_url":"https://api.github.com/repos/netty/netty/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/netty/netty/labels{/name}","releases_url":"https://api.github.com/repos/netty/netty/releases{/id}","created_at":"2010-11-09T09:22:21Z","updated_at":"2015-07-30T19:19:52Z","pushed_at":"2015-07-30T19:54:15Z","git_url":"git://github.com/netty/netty.git","ssh_url":"git@github.com:netty/netty.git","clone_url":"https://github.com/netty/netty.git","svn_url":"https://github.com/netty/netty","homepage":"http://netty.io/","size":131749,"stargazers_count":4994,"watchers_count":4994,"language":"Java","has_issues":true,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":2502,"mirror_url":null,"open_issues_count":321,"forks":2502,"open_issues":321,"watchers":4994,"default_branch":"master"}},"_links":{"self":{"href":"https://api.github.com/repos/netty/netty/pulls/4051"},"html":{"href":"https://github.com/netty/netty/pull/4051"},"issue":{"href":"https://api.github.com/repos/netty/netty/issues/4051"},"comments":{"href":"https://api.github.com/repos/netty/netty/issues/4051/comments"},"review_comments":{"href":"https://api.github.com/repos/netty/netty/pulls/4051/comments"},"review_comment":{"href":"https://api.github.com/repos/netty/netty/pulls/comments{/number}"},"commits":{"href":"https://api.github.com/repos/netty/netty/pulls/4051/commits"},"statuses":{"href":"https://api.github.com/repos/netty/netty/statuses/ae7f182810191be60cbb714f5f51de5195910578"}}}}