1 module hunt.http.client.Http1ClientResponseHandler; 2 3 import hunt.http.client.ClientHttpHandler; 4 import hunt.http.client.Http1ClientConnection; 5 import hunt.http.client.HttpClientResponse; 6 7 import hunt.http.codec.http.decode.HttpParser; 8 import hunt.http.codec.http.model; 9 import hunt.http.HttpOutputStream; 10 11 import hunt.http.HttpHeader; 12 import hunt.http.HttpField; 13 import hunt.http.HttpFields; 14 import hunt.http.HttpRequest; 15 import hunt.http.HttpResponse; 16 import hunt.http.HttpStatus; 17 import hunt.http.HttpVersion; 18 19 import hunt.io.ByteBuffer; 20 import hunt.stream; 21 import hunt.logging; 22 import hunt.text.Common; 23 24 version(WITH_HUNT_TRACE) { 25 import hunt.trace.Constrants; 26 import hunt.trace.Span; 27 } 28 29 import std.string : icmp; 30 import std.conv; 31 32 33 /** 34 * 35 */ 36 class Http1ClientResponseHandler : HttpResponseParsingHandler { 37 package(hunt.http.client) Http1ClientConnection connection; 38 package(hunt.http.client) HttpResponse response; 39 package(hunt.http.client) HttpRequest request; 40 package(hunt.http.client) HttpOutputStream outputStream; 41 protected ClientHttpHandler clientHttpHandler; 42 protected HttpFields trailer; 43 44 this(ClientHttpHandler clientHttpHandler) { 45 this.clientHttpHandler = clientHttpHandler; 46 47 } 48 49 package(hunt.http.client) void onReady() { 50 // do nothing 51 } 52 53 override 54 final bool startResponse(HttpVersion ver, int status, string reason) { 55 version(HUNT_HTTP_DEBUG) { 56 tracef("client received the response line, %s, %s, %s", ver, status, reason); 57 } 58 59 if (status == HttpStatus.CONTINUE_100 && HttpStatus.Code.CONTINUE.getMessage().equalsIgnoreCase(reason)) { 60 clientHttpHandler.continueToSendData(request, response, outputStream, connection); 61 version(HUNT_HTTP_DEBUG) { 62 tracef("client received 100 continue, current parser state is %s", connection.getParser().getState()); 63 } 64 return true; 65 } else { 66 response = new HttpClientResponse(ver, status, reason); 67 return false; 68 } 69 } 70 71 override 72 final void parsedHeader(HttpField field) { 73 response.getFields().add(field); 74 } 75 76 override 77 final int getHeaderCacheSize() { 78 return 1024; 79 } 80 81 override 82 final bool headerComplete() { 83 version(HUNT_HTTP_DEBUG_MORE) trace("handle response"); 84 return clientHttpHandler.headerComplete(request, response, outputStream, connection); 85 } 86 87 override 88 final bool content(ByteBuffer item) { 89 version(HUNT_HTTP_DEBUG_MORE) trace("handle response"); 90 return clientHttpHandler.content(item, request, response, outputStream, connection); 91 } 92 93 override 94 bool contentComplete() { 95 version(HUNT_HTTP_DEBUG_MORE) trace("handle response"); 96 return clientHttpHandler.contentComplete(request, response, outputStream, connection); 97 } 98 99 override 100 void parsedTrailer(HttpField field) { 101 if (trailer is null) { 102 trailer = new HttpFields(); 103 response.setTrailerSupplier(() => trailer); 104 } 105 trailer.add(field); 106 } 107 108 protected bool http1MessageComplete() { 109 version(HUNT_HTTP_DEBUG_MORE) trace("handle response"); 110 try { 111 // version(WITH_HUNT_TRACE) endTraceSpan(""); 112 return clientHttpHandler.messageComplete(request, response, outputStream, connection); 113 } finally { 114 string requestConnectionValue = request.getFields().get(HttpHeader.CONNECTION); 115 string responseConnectionValue = response.getFields().get(HttpHeader.CONNECTION); 116 117 connection.getParser().reset(); 118 119 HttpVersion httpVersion = response.getHttpVersion(); 120 121 if(httpVersion == HttpVersion.HTTP_1_0) { 122 if (icmp("keep-alive", requestConnectionValue) 123 && icmp("keep-alive", responseConnectionValue)) { 124 tracef("the client %s connection is persistent", response.getHttpVersion()); 125 } else { 126 IOUtils.close(connection); 127 } 128 } else if (httpVersion == HttpVersion.HTTP_1_1){ // the persistent connection is default in HTTP 1.1 129 if (icmp("close", requestConnectionValue) 130 || icmp("close", responseConnectionValue)) { 131 IOUtils.close(connection); 132 } else { 133 tracef("the client %s connection is persistent", response.getHttpVersion()); 134 } 135 } 136 137 } 138 } 139 140 override 141 final bool messageComplete() { 142 bool success = connection.upgradeProtocolComplete(request, response); 143 if (success) { 144 tracef("client upgraded protocol successfully"); 145 } 146 return http1MessageComplete(); 147 } 148 149 150 void badMessage(BadMessageException failure) { 151 badMessage(failure.getCode(), failure.getReason()); 152 } 153 154 override 155 final void badMessage(int status, string reason) { 156 clientHttpHandler.badMessage(status, reason, request, response, outputStream, connection); 157 } 158 159 override 160 void earlyEOF() { 161 clientHttpHandler.earlyEOF(request, response, outputStream, connection); 162 } 163 164 }