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 }