1 /* 2 * The MIT License (MIT) 3 * 4 * Copyright (c) 2014 Richard Andrew Cattermole 5 * 6 * Permission is hereby granted, free of charge, to any person obtaining a copy 7 * of this software and associated documentation files (the "Software"), to deal 8 * in the Software without restriction, including without limitation the rights 9 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 * copies of the Software, and to permit persons to whom the Software is 11 * furnished to do so, subject to the following conditions: 12 * 13 * The above copyright notice and this permission notice shall be included in all 14 * copies or substantial portions of the Software. 15 * 16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 * SOFTWARE. 23 */ 24 module dakka.vibe.server; 25 import dakka.base.defs; 26 import vibe.http.server : HTTPServerRequest, HTTPServerResponse, SessionOption; 27 import vibe.http.common : HTTPVersion, HTTPMethod, CookieValueMap; 28 import vibe.http.session : Session; 29 import vibe.http.status : HTTPStatus; 30 import vibe.inet.webform : FormFields; 31 import vibe.inet.message : InetHeaderMap; 32 import vibe.data.json : Json; 33 import std.datetime : SysTime; 34 35 final struct RequestData { 36 //HTTPRequest 37 HTTPVersion httpVersion; 38 HTTPMethod method; 39 string requestURL; 40 41 //HTTPServerRequest 42 string peer; 43 bool ssl; 44 string path; 45 string username; 46 string password; 47 string queryString; 48 CookieValueMap cookies; 49 string[string] params; 50 51 // not included by arg copy 52 53 //HTTPRequest 54 string[string] headers; 55 56 //HTTPServerRequest 57 string[string] query; 58 string[string] form; 59 60 ushort port; 61 string timeCreated; 62 } 63 64 class HTTPReqResp : Actor { 65 import cerealed.attrs; 66 67 @NoCereal private __gshared { 68 HTTPServerRequest request_; 69 HTTPServerResponse response_; 70 Session session_; 71 bool reassigned; 72 } 73 74 @DakkaLocalOnly 75 void assignData(HTTPServerRequest request, HTTPServerResponse response, Session session) { 76 synchronized { 77 reassigned = true; 78 request_ = request; 79 response_ = response; 80 session_ = session; 81 } 82 } 83 84 @NoCereal { 85 @property { 86 bool hasBeenReassigned() { 87 synchronized { 88 if (reassigned) { 89 reassigned = false; 90 return true; 91 } else { 92 return false; 93 } 94 } 95 } 96 97 /* 98 * Request 99 */ 100 101 RequestData request() { 102 import vibe.utils.array : FixedAppender; 103 104 synchronized { 105 string[string] headers; 106 foreach(key, value; request_.headers) 107 headers[key] = value; 108 string[string] query; 109 foreach(key, value; request_.query) 110 headers[key] = value; 111 string[string] form; 112 foreach(key, value; request_.form) 113 headers[key] = value; 114 ushort port = request_.clientAddress.port; 115 return mixin("RequestData(" ~ argsFromNames!(RequestData, "request_")(11) ~ ", headers, query, form, port, request_.timeCreated.toISOExtString)"); 116 } 117 } 118 119 @DakkaLocalOnly { 120 import dakka.vibe.client : DakkaHTTPRequest, DakkaHTTPResponse; 121 DakkaHTTPRequest client_request() { return new DakkaHTTPRequest(this); } 122 DakkaHTTPResponse client_response() { return new DakkaHTTPResponse(this); } 123 } 124 } 125 126 /* 127 * Response 128 */ 129 130 void response_writeBody(ubyte[] data, string content_type = null) { 131 synchronized 132 response_.writeBody(data, content_type); 133 } 134 135 void response_writeVoidBody() { 136 synchronized 137 response_.writeVoidBody(); 138 } 139 140 void response_redirect(string url, int status = HTTPStatus.Found) { 141 synchronized 142 response_.redirect(url, status); 143 } 144 145 void response_setCookie(string name, string value, string path = "/", long maxAge = long.min, string expires = null, string domain=null) { 146 synchronized { 147 auto cookie = response_.setCookie(name, value, path); 148 if (maxAge != long.min) 149 cookie.maxAge = maxAge; 150 if (expires !is null) 151 cookie.expires = expires; 152 if (domain !is null) 153 cookie.domain = domain; 154 } 155 156 } 157 158 void response_startSession(string path = "/", size_t options = SessionOption.httpOnly) { 159 synchronized 160 session_ = response_.startSession(path, cast(SessionOption)options); 161 } 162 163 void response_terminateSession() { 164 synchronized 165 response_.terminateSession(); 166 } 167 168 /* 169 * Session 170 */ 171 172 bool session_isnull() { 173 synchronized 174 return session_.id is null; 175 } 176 177 string session_id() { 178 synchronized { 179 assert(session_.id !is null, "Session is currently null. Cannot get id from it."); 180 return session_.id; 181 } 182 } 183 184 bool session_isKeySet(string name) { 185 synchronized { 186 assert(session_.id !is null, "Session is currently null. Cannot get id from it."); 187 return session_.isKeySet(name); 188 } 189 } 190 191 void session_set(string key, string value) { 192 synchronized { 193 assert(session_.id !is null, "Session is currently null. Cannot get id from it."); 194 session_.set(key, value); 195 } 196 } 197 198 string session_get(string key) { 199 synchronized { 200 assert(session_.id !is null, "Session is currently null. Cannot get id from it."); 201 return session_.get!string(key); 202 } 203 } 204 205 string[] session_keys() { 206 synchronized { 207 assert(session_.id !is null, "Session is currently null. Cannot get id from it."); 208 string[] ret; 209 foreach(k, v; session_) { 210 ret ~= k; 211 } 212 return ret; 213 } 214 } 215 } 216 } 217 218 private { 219 pure string argsFromNames(T, string name)(size_t max = size_t.max) { 220 enum T t = T.init; 221 string ret; 222 foreach(i, id; __traits(allMembers, T)) { 223 if (id != "opAssign" && i < max) 224 ret ~= name ~ "." ~ id ~ ","; 225 } 226 ret.length--; 227 return ret; 228 } 229 }