1 module hunt.http.client.Http2ClientHandler; 2 3 import hunt.http.client.Http1ClientConnection; 4 import hunt.http.client.Http2ClientContext; 5 import hunt.http.client.Http2ClientConnection; 6 7 import hunt.http.codec.http.model.HttpVersion; 8 import hunt.http.codec.http.stream.AbstractHttpHandler; 9 import hunt.http.codec.http.stream.Http2Configuration; 10 import hunt.net.secure.SecureSession; 11 import hunt.net.secure.SecureSessionFactory; 12 import hunt.net.Session; 13 14 import hunt.util.concurrent.Promise; 15 import hunt.lang.exception; 16 import hunt.string; 17 18 import hunt.container.Map; 19 20 import hunt.logging; 21 import std.array; 22 23 class Http2ClientHandler : AbstractHttpHandler { 24 25 private Map!(int, Http2ClientContext) http2ClientContext; 26 27 this(Http2Configuration config, Map!(int, Http2ClientContext) http2ClientContext) { 28 super(config); 29 this.http2ClientContext = http2ClientContext; 30 } 31 32 override 33 void sessionOpened(Session session) { 34 Http2ClientContext context = http2ClientContext.get(session.getSessionId()); 35 36 if (context is null) { 37 errorf("http2 client can not get the client context of session %s", session.getSessionId()); 38 session.closeNow(); 39 return; 40 } 41 42 if (config.isSecureConnectionEnabled()) { 43 SecureSessionFactory factory = config.getSecureSessionFactory(); 44 SecureSession secureSession = factory.create(session, true, delegate void (SecureSession sslSession) { 45 46 string protocol = "http/1.1"; 47 string p = sslSession.getApplicationProtocol(); 48 if(p.empty) 49 warningf("The selected application protocol is empty. now use default: %s", protocol); 50 else 51 protocol = p; 52 53 infof("Client session %s SSL handshake finished. The app protocol is %s", session.getSessionId(), protocol); 54 switch (protocol) { 55 case "http/1.1": 56 initializeHttp1ClientConnection(session, context, sslSession); 57 break; 58 case "h2": 59 initializeHttp2ClientConnection(session, context, sslSession); 60 break; 61 default: 62 throw new IllegalStateException("SSL application protocol negotiates failure. The protocol " ~ protocol ~ " is not supported"); 63 } 64 }); 65 66 session.attachObject(cast(Object)secureSession); 67 } else { 68 if (config.getProtocol().empty) { 69 initializeHttp1ClientConnection(session, context, null); 70 } else { 71 HttpVersion httpVersion = HttpVersion.fromString(config.getProtocol()); 72 if (httpVersion == HttpVersion.Null) { 73 throw new IllegalArgumentException("the protocol " ~ config.getProtocol() ~ " is not support."); 74 } 75 if(httpVersion == HttpVersion.HTTP_1_1) { 76 initializeHttp1ClientConnection(session, context, null); 77 } else if(httpVersion == HttpVersion.HTTP_2) { 78 initializeHttp2ClientConnection(session, context, null); 79 } else { 80 throw new IllegalArgumentException("the protocol " ~ config.getProtocol() ~ " is not support."); 81 } 82 } 83 84 } 85 } 86 87 private void initializeHttp1ClientConnection(Session session, Http2ClientContext context, 88 SecureSession sslSession) { 89 try { 90 Http1ClientConnection http1ClientConnection = new Http1ClientConnection(config, session, sslSession); 91 session.attachObject(http1ClientConnection); 92 // context.getPromise().succeeded(http1ClientConnection); 93 import hunt.http.client.HttpClientConnection; 94 Promise!(HttpClientConnection) promise = context.getPromise(); 95 infof("Promise id = %s", promise.id); 96 promise.succeeded(http1ClientConnection); 97 98 } catch (Exception t) { 99 context.getPromise().failed(t); 100 } finally { 101 http2ClientContext.remove(session.getSessionId()); 102 } 103 } 104 105 private void initializeHttp2ClientConnection(Session session, Http2ClientContext context, 106 SecureSession sslSession) { 107 try { 108 Http2ClientConnection connection = new Http2ClientConnection(config, session, sslSession, context.getListener()); 109 session.attachObject(connection); 110 context.getListener().setConnection(connection); 111 // connection.initialize(config, cast(Promise!(Http2ClientConnection))context.getPromise(), context.getListener()); 112 connection.initialize(config, context.getPromise(), context.getListener()); 113 } finally { 114 http2ClientContext.remove(session.getSessionId()); 115 } 116 } 117 118 override 119 void sessionClosed(Session session) { 120 try { 121 super.sessionClosed(session); 122 } finally { 123 http2ClientContext.remove(session.getSessionId()); 124 } 125 } 126 127 override 128 void failedOpeningSession(int sessionId, Exception t) { 129 130 auto c = http2ClientContext.remove(sessionId); 131 if(c !is null) 132 { 133 auto promise = c.getPromise(); 134 if(promise !is null) 135 promise.failed(t); 136 } 137 138 // Optional.ofNullable(http2ClientContext.remove(sessionId)) 139 // .map(Http2ClientContext::getPromise) 140 // .ifPresent(promise => promise.failed(t)); 141 } 142 143 override 144 void exceptionCaught(Session session, Exception t) { 145 try { 146 super.exceptionCaught(session, t); 147 } finally { 148 http2ClientContext.remove(session.getSessionId()); 149 } 150 } 151 152 }