{"action":"created","comment":{"url":"https://api.github.com/repos/netty/netty/pulls/comments/27711034","id":27711034,"diff_hunk":"@@ -673,6 +673,204 @@ static ApplicationProtocolConfig toApplicationProtocolConfig(Iterable<String> ne\n         return apn;\n     }\n \n+    /**\n+     * Creates a builder for new client-side {@link SslContext}.\n+     */\n+    public static Builder newBuilderForClient() {\n+        return new Builder(true);\n+    }\n+\n+    /**\n+     * Creates a builder for new server-side {@link SslContext}.\n+     *\n+     * @param keyCertChainFile an X.509 certificate chain file in PEM format\n+     * @param keyFile a PKCS#8 private key file in PEM format\n+     */\n+    public static Builder newBuilderForServer(File keyCertChainFile, File keyFile) {\n+        return new Builder(false).keyManager(keyCertChainFile, keyFile);\n+    }\n+\n+    /**\n+     * Creates a builder for new server-side {@link SslContext}.\n+     *\n+     * @param keyCertChainFile an X.509 certificate chain file in PEM format\n+     * @param keyFile a PKCS#8 private key file in PEM format\n+     * @param keyPassword the password of the {@code keyFile}, or {@code null} if it's not\n+     *     password-protected\n+     */\n+    public static Builder newBuilderForServer(File keyCertChainFile, File keyFile,\n+            String keyPassword) {\n+        return new Builder(false).keyManager(keyCertChainFile, keyFile, keyPassword);\n+    }\n+\n+    /** Builder for configuring a new SslContext for creation. */\n+    public static final class Builder {\n+        private final boolean forClient;\n+        private SslProvider provider;\n+        private File trustCertChainFile;\n+        private TrustManagerFactory trustManagerFactory;\n+        private File keyCertChainFile;\n+        private File keyFile;\n+        private String keyPassword;\n+        private KeyManagerFactory keyManagerFactory;\n+        private Iterable<String> ciphers;\n+        private CipherSuiteFilter cipherFilter = IdentityCipherSuiteFilter.INSTANCE;\n+        private ApplicationProtocolConfig apn;\n+        private long sessionCacheSize;\n+        private long sessionTimeout;\n+\n+        private Builder(boolean forClient) {\n+            this.forClient = forClient;\n+        }\n+\n+        /**\n+         * The {@link SslContext} implementation to use. {@code null} uses the default one.\n+         */\n+        public Builder sslProvider(SslProvider provider) {\n+            this.provider = provider;\n+            return this;\n+        }\n+\n+        /**\n+         * Trusted certificates for verifying the remote endpoint's certificate. The file should\n+         * contain an X.509 certificate chain in PEM format. {@code null} uses the system default.\n+         */\n+        public Builder trustManager(File trustCertChainFile) {\n+            this.trustCertChainFile = trustCertChainFile;\n+            this.trustManagerFactory = null;\n+            return this;\n+        }\n+\n+        /**\n+         * Trusted manager for verifying the remote endpoint's certificate. Using a {@code\n+         * TrustManagerFactory} is only supported for {@link SslProvider#JDK}; for other providers,\n+         * you must use {@link #trustManager(File)}. {@code null} uses the system default.\n+         */\n+        public Builder trustManager(TrustManagerFactory trustManagerFactory) {\n+            this.trustCertChainFile = null;\n+            this.trustManagerFactory = trustManagerFactory;\n+            return this;\n+        }\n+\n+        /**\n+         * Identifying certificate for this host. {@code keyCertChainFile} and {@code keyFile} may\n+         * be {@code null} for client contexts, which disables mutual authentication.\n+         *\n+         * @param keyCertChainFile an X.509 certificate chain file in PEM format\n+         * @param keyFile a PKCS#8 private key file in PEM format\n+         */\n+        public Builder keyManager(File keyCertChainFile, File keyFile) {\n+            return keyManager(keyCertChainFile, keyFile, null);\n+        }\n+\n+        /**\n+         * Identifying certificate for this host. {@code keyCertChainFile} and {@code keyFile} may\n+         * be {@code null} for client contexts, which disables mutual authentication.\n+         *\n+         * @param keyCertChainFile an X.509 certificate chain file in PEM format\n+         * @param keyFile a PKCS#8 private key file in PEM format\n+         * @param keyPassword the password of the {@code keyFile}, or {@code null} if it's not\n+         *     password-protected\n+         */\n+        public Builder keyManager(File keyCertChainFile, File keyFile, String keyPassword) {\n+            if (!forClient) {","path":"handler/src/main/java/io/netty/handler/ssl/SslContext.java","position":104,"original_position":104,"commit_id":"48aa2e6fa34d714c67288843840ce49035ecb1bc","original_commit_id":"48aa2e6fa34d714c67288843840ce49035ecb1bc","user":{"login":"ejona86","id":2811396,"avatar_url":"https://avatars.githubusercontent.com/u/2811396?v=3","gravatar_id":"","url":"https://api.github.com/users/ejona86","html_url":"https://github.com/ejona86","followers_url":"https://api.github.com/users/ejona86/followers","following_url":"https://api.github.com/users/ejona86/following{/other_user}","gists_url":"https://api.github.com/users/ejona86/gists{/gist_id}","starred_url":"https://api.github.com/users/ejona86/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/ejona86/subscriptions","organizations_url":"https://api.github.com/users/ejona86/orgs","repos_url":"https://api.github.com/users/ejona86/repos","events_url":"https://api.github.com/users/ejona86/events{/privacy}","received_events_url":"https://api.github.com/users/ejona86/received_events","type":"User","site_admin":false},"body":"It is useful to be able to clear previously set fields on the Builder. If calling the method required the proper parameters, even for clients, then once set, there is no way to revert such a configuration. If a utility provides you with a pre-formed Builder, you may want to clear the key manager.\r\n\r\nAlso, sometimes it is useful to call the method with null simply to not check whether the parameters you were passed were null. If your application has a bunch of configuration, you can just blindly call the various builder methods and not need a bunch of ```if (keyCertChainFile != null && keyFile != null)``` checks.","created_at":"2015-04-03T01:21:29Z","updated_at":"2015-04-03T01:21:29Z","html_url":"https://github.com/netty/netty/pull/3541#discussion_r27711034","pull_request_url":"https://api.github.com/repos/netty/netty/pulls/3541","_links":{"self":{"href":"https://api.github.com/repos/netty/netty/pulls/comments/27711034"},"html":{"href":"https://github.com/netty/netty/pull/3541#discussion_r27711034"},"pull_request":{"href":"https://api.github.com/repos/netty/netty/pulls/3541"}}},"pull_request":{"url":"https://api.github.com/repos/netty/netty/pulls/3541","id":32064339,"html_url":"https://github.com/netty/netty/pull/3541","diff_url":"https://github.com/netty/netty/pull/3541.diff","patch_url":"https://github.com/netty/netty/pull/3541.patch","issue_url":"https://api.github.com/repos/netty/netty/issues/3541","number":3541,"state":"open","locked":false,"title":"Create SslContext.Builder","user":{"login":"ejona86","id":2811396,"avatar_url":"https://avatars.githubusercontent.com/u/2811396?v=3","gravatar_id":"","url":"https://api.github.com/users/ejona86","html_url":"https://github.com/ejona86","followers_url":"https://api.github.com/users/ejona86/followers","following_url":"https://api.github.com/users/ejona86/following{/other_user}","gists_url":"https://api.github.com/users/ejona86/gists{/gist_id}","starred_url":"https://api.github.com/users/ejona86/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/ejona86/subscriptions","organizations_url":"https://api.github.com/users/ejona86/orgs","repos_url":"https://api.github.com/users/ejona86/repos","events_url":"https://api.github.com/users/ejona86/events{/privacy}","received_events_url":"https://api.github.com/users/ejona86/received_events","type":"User","site_admin":false},"body":"Motivation:\r\n\r\nSslContext factory methods have gotten out of control; it's past time to\r\nswap to a builder.\r\n\r\nModifications:\r\n\r\nNew Builder class. The existing factory methods are left as-is for\r\nbackward compatibility.\r\n\r\nResult:\r\n\r\nResolves #3531.\r\n\r\n\r\nThis is based on 4.0. I can base it on something else and file additional PRs, if that makes sense.","created_at":"2015-03-26T21:43:32Z","updated_at":"2015-04-03T01:21:29Z","closed_at":null,"merged_at":null,"merge_commit_sha":"103c1e4d52cfe3eb888e573b25914ff5a8295bc2","assignee":null,"milestone":{"url":"https://api.github.com/repos/netty/netty/milestones/115","html_url":"https://github.com/netty/netty/milestones/4.0.28.Final","labels_url":"https://api.github.com/repos/netty/netty/milestones/115/labels","id":1050260,"number":115,"title":"4.0.28.Final","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":56,"closed_issues":0,"state":"open","created_at":"2015-04-02T12:45:12Z","updated_at":"2015-04-02T12:48:14Z","due_on":null,"closed_at":null},"commits_url":"https://api.github.com/repos/netty/netty/pulls/3541/commits","review_comments_url":"https://api.github.com/repos/netty/netty/pulls/3541/comments","review_comment_url":"https://api.github.com/repos/netty/netty/pulls/comments{/number}","comments_url":"https://api.github.com/repos/netty/netty/issues/3541/comments","statuses_url":"https://api.github.com/repos/netty/netty/statuses/48aa2e6fa34d714c67288843840ce49035ecb1bc","head":{"label":"ejona86:sslcontext-builder","ref":"sslcontext-builder","sha":"48aa2e6fa34d714c67288843840ce49035ecb1bc","user":{"login":"ejona86","id":2811396,"avatar_url":"https://avatars.githubusercontent.com/u/2811396?v=3","gravatar_id":"","url":"https://api.github.com/users/ejona86","html_url":"https://github.com/ejona86","followers_url":"https://api.github.com/users/ejona86/followers","following_url":"https://api.github.com/users/ejona86/following{/other_user}","gists_url":"https://api.github.com/users/ejona86/gists{/gist_id}","starred_url":"https://api.github.com/users/ejona86/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/ejona86/subscriptions","organizations_url":"https://api.github.com/users/ejona86/orgs","repos_url":"https://api.github.com/users/ejona86/repos","events_url":"https://api.github.com/users/ejona86/events{/privacy}","received_events_url":"https://api.github.com/users/ejona86/received_events","type":"User","site_admin":false},"repo":{"id":32953128,"name":"netty","full_name":"ejona86/netty","owner":{"login":"ejona86","id":2811396,"avatar_url":"https://avatars.githubusercontent.com/u/2811396?v=3","gravatar_id":"","url":"https://api.github.com/users/ejona86","html_url":"https://github.com/ejona86","followers_url":"https://api.github.com/users/ejona86/followers","following_url":"https://api.github.com/users/ejona86/following{/other_user}","gists_url":"https://api.github.com/users/ejona86/gists{/gist_id}","starred_url":"https://api.github.com/users/ejona86/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/ejona86/subscriptions","organizations_url":"https://api.github.com/users/ejona86/orgs","repos_url":"https://api.github.com/users/ejona86/repos","events_url":"https://api.github.com/users/ejona86/events{/privacy}","received_events_url":"https://api.github.com/users/ejona86/received_events","type":"User","site_admin":false},"private":false,"html_url":"https://github.com/ejona86/netty","description":"Netty project - an event-driven asynchronous network application framework","fork":true,"url":"https://api.github.com/repos/ejona86/netty","forks_url":"https://api.github.com/repos/ejona86/netty/forks","keys_url":"https://api.github.com/repos/ejona86/netty/keys{/key_id}","collaborators_url":"https://api.github.com/repos/ejona86/netty/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/ejona86/netty/teams","hooks_url":"https://api.github.com/repos/ejona86/netty/hooks","issue_events_url":"https://api.github.com/repos/ejona86/netty/issues/events{/number}","events_url":"https://api.github.com/repos/ejona86/netty/events","assignees_url":"https://api.github.com/repos/ejona86/netty/assignees{/user}","branches_url":"https://api.github.com/repos/ejona86/netty/branches{/branch}","tags_url":"https://api.github.com/repos/ejona86/netty/tags","blobs_url":"https://api.github.com/repos/ejona86/netty/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/ejona86/netty/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/ejona86/netty/git/refs{/sha}","trees_url":"https://api.github.com/repos/ejona86/netty/git/trees{/sha}","statuses_url":"https://api.github.com/repos/ejona86/netty/statuses/{sha}","languages_url":"https://api.github.com/repos/ejona86/netty/languages","stargazers_url":"https://api.github.com/repos/ejona86/netty/stargazers","contributors_url":"https://api.github.com/repos/ejona86/netty/contributors","subscribers_url":"https://api.github.com/repos/ejona86/netty/subscribers","subscription_url":"https://api.github.com/repos/ejona86/netty/subscription","commits_url":"https://api.github.com/repos/ejona86/netty/commits{/sha}","git_commits_url":"https://api.github.com/repos/ejona86/netty/git/commits{/sha}","comments_url":"https://api.github.com/repos/ejona86/netty/comments{/number}","issue_comment_url":"https://api.github.com/repos/ejona86/netty/issues/comments{/number}","contents_url":"https://api.github.com/repos/ejona86/netty/contents/{+path}","compare_url":"https://api.github.com/repos/ejona86/netty/compare/{base}...{head}","merges_url":"https://api.github.com/repos/ejona86/netty/merges","archive_url":"https://api.github.com/repos/ejona86/netty/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/ejona86/netty/downloads","issues_url":"https://api.github.com/repos/ejona86/netty/issues{/number}","pulls_url":"https://api.github.com/repos/ejona86/netty/pulls{/number}","milestones_url":"https://api.github.com/repos/ejona86/netty/milestones{/number}","notifications_url":"https://api.github.com/repos/ejona86/netty/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/ejona86/netty/labels{/name}","releases_url":"https://api.github.com/repos/ejona86/netty/releases{/id}","created_at":"2015-03-26T21:34:39Z","updated_at":"2015-03-26T21:34:49Z","pushed_at":"2015-03-26T21:48:33Z","git_url":"git://github.com/ejona86/netty.git","ssh_url":"git@github.com:ejona86/netty.git","clone_url":"https://github.com/ejona86/netty.git","svn_url":"https://github.com/ejona86/netty","homepage":"http://netty.io/","size":40222,"stargazers_count":0,"watchers_count":0,"language":"Java","has_issues":false,"has_downloads":true,"has_wiki":true,"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":"netty:4.0","ref":"4.0","sha":"cb8a607ba5b592752bb3712511cb03c83a82f9c9","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-04-03T00:43:46Z","pushed_at":"2015-04-02T18:16:34Z","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":113756,"stargazers_count":4360,"watchers_count":4360,"language":"Java","has_issues":true,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":2150,"mirror_url":null,"open_issues_count":251,"forks":2150,"open_issues":251,"watchers":4360,"default_branch":"master"}},"_links":{"self":{"href":"https://api.github.com/repos/netty/netty/pulls/3541"},"html":{"href":"https://github.com/netty/netty/pull/3541"},"issue":{"href":"https://api.github.com/repos/netty/netty/issues/3541"},"comments":{"href":"https://api.github.com/repos/netty/netty/issues/3541/comments"},"review_comments":{"href":"https://api.github.com/repos/netty/netty/pulls/3541/comments"},"review_comment":{"href":"https://api.github.com/repos/netty/netty/pulls/comments{/number}"},"commits":{"href":"https://api.github.com/repos/netty/netty/pulls/3541/commits"},"statuses":{"href":"https://api.github.com/repos/netty/netty/statuses/48aa2e6fa34d714c67288843840ce49035ecb1bc"}}}}