1 /* 2 * Hunt - A high-level D Programming Language Web framework that encourages rapid development and clean, pragmatic design. 3 * 4 * Copyright (C) 2015-2019, HuntLabs 5 * 6 * Website: https://www.huntlabs.net/ 7 * 8 * Licensed under the Apache-2.0 License. 9 * 10 */ 11 12 module hunt.framework.http.Response; 13 14 import hunt.framework.http.HttpErrorResponseHandler; 15 import hunt.http.HttpStatus; 16 import hunt.http.server; 17 import hunt.io.ByteBuffer; 18 import hunt.serialization.JsonSerializer; 19 import hunt.logging; 20 21 import std.conv; 22 import std.json; 23 import std.range; 24 import std.traits; 25 26 /** 27 * 28 */ 29 class Response { 30 protected HttpServerResponse _response; 31 private bool _bodySet = false; 32 33 this() { 34 _response = new HttpServerResponse(); 35 } 36 37 this(string content) { 38 HttpBody hb = HttpBody.create(content); 39 this(hb); 40 } 41 42 this(HttpBody bodyContent) { 43 this(new HttpServerResponse(bodyContent)); 44 } 45 46 this(HttpServerResponse response) { 47 this._response = response; 48 } 49 50 HttpServerResponse httpResponse() { 51 return _response; 52 } 53 54 HttpFields getFields() { 55 return _response.getFields(); 56 } 57 58 Response header(T)(string header, T value) { 59 getFields().put(header, value); 60 return this; 61 } 62 63 Response header(T)(HttpHeader header, T value) { 64 getFields().put(header, value); 65 return this; 66 } 67 68 Response headers(T = string)(T[string] headers) { 69 foreach (string k, T v; headers) 70 getFields().add(k, v); 71 return this; 72 } 73 74 Response setRestContent(T)(T content) { 75 if(_bodySet) { 76 version(HUNT_DEBUG) warning("The body is set again."); 77 } 78 79 string contentType = MimeType.APPLICATION_JSON_VALUE; 80 81 static if(is(T : ByteBuffer)) { 82 HttpBody hb = HttpBody.create(contentType, content); 83 } else static if(isSomeString!T) { 84 HttpBody hb = HttpBody.create(contentType, content); 85 } else { 86 JSONValue js = JsonSerializer.toJson(content); 87 string c = js.toString(); 88 HttpBody hb = HttpBody.create(contentType, c); 89 } 90 _response.setBody(hb); 91 _bodySet = true; 92 return this; 93 } 94 95 /** 96 * Sets the response content. 97 * 98 * @return this 99 */ 100 Response setContent(T)(T content, string contentType = MimeType.TEXT_HTML_VALUE) { 101 if(_bodySet) { 102 version(HUNT_DEBUG) warning("The body is set again."); 103 } 104 105 static if(is(T : ByteBuffer)) { 106 HttpBody hb = HttpBody.create(contentType, content); 107 } else static if(isSomeString!T) { 108 HttpBody hb = HttpBody.create(contentType, content); 109 } else static if(is(T : K[], K) && is(Unqual!K == ubyte)) { 110 HttpBody hb = HttpBody.create(contentType, content); 111 } else { 112 string c = content.to!string(); 113 HttpBody hb = HttpBody.create(contentType, c); 114 } 115 _response.setBody(hb); 116 _bodySet = true; 117 return this; 118 } 119 120 Response setHtmlContent(string content) { 121 setContent(content, MimeType.TEXT_HTML_UTF_8.toString()); 122 return this; 123 } 124 125 126 ///set http status code eg. 404 200 127 Response setStatus(int status) { 128 _response.setStatus(status); 129 return this; 130 } 131 132 int status() @property { 133 return _response.getStatus(); 134 } 135 136 137 Response setReason(string reason) { 138 _response.setReason(reason); 139 return this; 140 } 141 142 ///download file 143 Response download(string filename, ubyte[] file, string content_type = "binary/octet-stream") { 144 header(HttpHeader.CONTENT_TYPE, content_type); 145 header(HttpHeader.CONTENT_DISPOSITION, 146 "attachment; filename=" ~ filename ~ "; size=" ~ (file.length.to!string)); 147 setContent(file); 148 149 return this; 150 } 151 152 /** 153 * Add a cookie to the response. 154 * 155 * @param Cookie cookie 156 * @return this 157 */ 158 Response withCookie(Cookie cookie) { 159 _response.withCookie(cookie); 160 return this; 161 } 162 163 // /// the session store implementation. 164 // @property HttpSession session() { 165 // return _request.session(); 166 // } 167 168 // /// ditto 169 // // @property void session(HttpSession se) { 170 // // _session = se; 171 // // } 172 173 174 // // void redirect(string url, bool is301 = false) 175 // // { 176 // // if (_isDone) 177 // // return; 178 179 // // setStatus((is301 ? 301 : 302)); 180 // // setHeader(HttpHeader.LOCATION, url); 181 182 // // connectionClose(); 183 // // done(); 184 // // } 185 186 void do404(string body_ = "", string contentype = "text/html;charset=UTF-8") { 187 doError(404, body_, contentype); 188 } 189 190 void do403(string body_ = "", string contentype = "text/html;charset=UTF-8") { 191 doError(403, body_, contentype); 192 } 193 194 void doError(ushort code, string body_ = "", string contentype = "text/html;charset=UTF-8") { 195 196 setStatus(code); 197 getFields().put(HttpHeader.CONTENT_TYPE, contentype); 198 setContent(errorPageHtml(code, body_)); 199 } 200 201 void doError(ushort code, Throwable exception, string contentype = "text/html;charset=UTF-8") { 202 203 setStatus(code); 204 getFields().put(HttpHeader.CONTENT_TYPE, contentype); 205 206 version(HUNT_DEBUG) { 207 setContent(errorPageWithStack(code, "<pre>" ~ exception.toString() ~ "/<pre>")); 208 } else { 209 setContent(errorPageWithStack(code, exception.msg)); 210 } 211 } 212 213 void setHttpError(ushort code) { 214 this.setStatus(code); 215 this.setContent(errorPageHtml(code)); 216 } 217 218 219 alias setHeader = header; 220 alias withHeaders = headers; 221 alias withContent = setContent; 222 }