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 }