1 /*
2  * Collie - An asynchronous event-driven network framework using Dlang development
3  *
4  * Copyright (C) 2015-2017  Shanghai Putao Technology Co., Ltd 
5  *
6  * Developer: putao's Dlang team
7  *
8  * Licensed under the Apache-2.0 License.
9  *
10  */
11 module collie.codec.http.server.requesthandler;
12 import kiss.log;
13 import collie.codec.http.httpmessage;
14 import collie.codec.http.server.responsehandler;
15 import collie.codec.http.errocode;
16 import collie.codec.http.codec.wsframe;
17 import collie.codec.http.headers;
18 import collie.codec.http.httptansaction;
19 import collie.codec.http.server.responsebuilder;
20 import collie.codec.http.codec.httpcodec;
21 import collie.utils..string;
22 
23 abstract class RequestHandler
24 {
25 	void setResponseHandler(ResponseHandler handler) nothrow {
26 		_downstream = handler;
27 	}
28 
29 	/**
30    * Invoked when we have successfully fetched headers from client. This will
31    * always be the first callback invoked on your handler.
32    */
33 	void onRequest(HTTPMessage headers) nothrow
34 	{
35 	}
36 
37 	/**
38 	deprecated("Incorrect spelling. Using onRequest instead.")
39 	*/
40 	void onResquest(HTTPMessage headers) nothrow
41 	{
42 		onRequest(headers);
43 	}
44 
45 
46 	/**
47    * Invoked when we get part of body for the request.
48    */
49 	void onBody(const ubyte[] data) nothrow;
50 
51 	/**
52    * Invoked when we finish receiving the body.
53    */
54 	void onEOM() nothrow;
55 
56 	/**
57    * Invoked when request processing has been completed and nothing more
58    * needs to be done. This may be a good place to log some stats and
59    * clean up resources. This is distinct from onEOM() because it is
60    * invoked after the response is fully sent. Once this callback has been
61    * received, `downstream_` should be considered invalid.
62    */
63 	void requestComplete() nothrow;
64 
65 	/**
66    * Request failed. Maybe because of read/write error on socket or client
67    * not being able to send request in time.
68    *
69    * NOTE: Can be invoked at any time (except for before onRequest).
70    *
71    * No more callbacks will be invoked after this. You should clean up after
72    * yourself.
73    */
74 	void onError(HTTPErrorCode code) nothrow;
75 
76 	void onFrame(ref WSFrame frame) nothrow
77 	{}
78 
79 	bool onUpgtade(CodecProtocol protocol, HTTPMessage msg) nothrow {
80 		return false;
81 	}
82 
83 protected:
84 	ResponseHandler _downstream;
85 }
86 
87 final class RequestHandlerAdaptor : ResponseHandler,HTTPTransactionHandler
88 {
89 	this(RequestHandler handler)
90 	{
91 		super(handler);
92 	}
93 	
94 	override void setTransaction(HTTPTransaction txn) {
95 		_txn = txn;
96 		_upstream.setResponseHandler(this);
97 	}
98 	
99 	override void detachTransaction() {
100 		_txn = null;
101 		if(!_erro) {
102 			_upstream.requestComplete();
103 		}
104 	}
105 	
106 	override void onHeadersComplete(HTTPMessage msg) {
107 		// logDebug("onHeadersComplete , erro is : ", _erro , " _upstream is ", cast(void *)_upstream);
108 		if(msg.getHeaders.exists(HTTPHeaderCode.EXPECT)) {
109 			logDebug("has header EXPECT--------");
110 			string str = msg.getHeaders.getSingleOrEmpty(HTTPHeaderCode.EXPECT);
111 			if(!isSameIngnoreLowUp(str,"100-continue")) {
112 				scope HTTPMessage headers = new HTTPMessage();
113 				headers.constructDirectResponse(1,1,417,"Expectation Failed");
114 				headers.wantsKeepAlive(false);
115 				_txn.sendHeadersWithEOM(headers);
116 				return;
117 			}else {
118 				scope HTTPMessage headers = new HTTPMessage();
119 				headers.constructDirectResponse(1,1,100,"Continue");
120 				_txn.sendHeaders(headers);
121 			}
122 		}
123 		if(!_erro)
124 			_upstream.onResquest(msg);
125 	}
126 	
127 	override void onBody(const ubyte[] chain) {
128 		_upstream.onBody(chain);
129 	}
130 	
131 	override void onChunkHeader(size_t lenght){}
132 	
133 	override void onChunkComplete() {}
134 	
135 	override void onEOM() {
136 		if(!_erro)
137 			_upstream.onEOM();
138 	}
139 	
140 	override void onError(HTTPErrorCode erromsg)  {
141 		if(_erro) return;
142 		_erro = true;
143 		_upstream.onError(erromsg);
144 	}
145 	
146 	override void onWsFrame(ref WSFrame wsf) {
147 		_upstream.onFrame(wsf);
148 	}
149 	
150 	override void onEgressPaused() {}
151 	
152 	override void onEgressResumed() {}
153 	
154 	override void sendHeadersWithEOM(HTTPMessage msg) {
155 		if(_txn)
156 			_txn.sendHeadersWithEOM(msg);
157 	}
158 	
159 	override void sendHeaders(HTTPMessage msg)
160 	{
161 		_responseStarted = true;
162 		if(_txn)
163 			_txn.sendHeaders(msg);
164 	}
165 	
166 	override void sendChunkHeader(size_t len){if(_txn)_txn.sendChunkHeader(len);}
167 	
168 	override void sendBody(in ubyte[] data, bool iseom = false){if(_txn)_txn.sendBody(data,iseom);if(iseom)_responseStarted = false;}
169 	
170 	
171 	override void sendChunkTerminator(){if(_txn)_txn.sendChunkTerminator();}
172 	
173 	override void sendEOM(){if(_txn)_txn.sendEOM(); _responseStarted = false;}
174 	
175 	override void sendTimeOut() {
176 		if(_txn)
177 			_txn.sendTimeOut();
178 	}
179 	
180 	override void socketWrite(StreamWriteBuffer buffer) {
181 		if(_txn)
182 			_txn.socketWrite(buffer);
183 	}
184 	
185 	override void sendWsData(OpCode code,ubyte[] data)
186 	{
187 		if(_txn)
188 			_txn.sendWsData(code,data);
189 	}
190 	
191 	override bool onUpgtade(CodecProtocol protocol,HTTPMessage msg) {
192 		return _upstream.onUpgtade(protocol, msg);
193 	}
194 private:
195 	HTTPTransaction _txn;
196 	bool _erro = false;
197 	bool _responseStarted = false;
198 }