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