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.client; 25 import dakka.vibe.server; 26 import vibe.http.common : HTTPResponse, HTTPRequest, HTTPVersion, HTTPMethod; 27 import vibe.http.server : HTTPServerRequest, SessionOption; 28 29 class DakkaHTTPResponse : HTTPResponse { 30 private { 31 HTTPReqResp reqresp_; 32 } 33 34 this(HTTPReqResp reqresp) { 35 reqresp_ = reqresp; 36 } 37 38 void writeBody(ubyte[] data, string content_type = null) { reqresp_.response_writeBody(data, content_type); } 39 void writeVoidBody() { reqresp_.response_writeVoidBody(); } 40 void redirect(string url, int status = HTTPStatus.Found) { reqresp_.response_redirect(url, status); } 41 DakkaCookie setCookie(string name, string value, string path = "/") { return DakkaCookie(reqresp_, name, value, path); } 42 DakkaSession startSession(string path = "/", SessionOption options = SessionOption.httpOnly) { return DakkaSession(reqresp_, path, cast(size_t)options); } 43 void terminateSession() { reqresp_.response_terminateSession(); } 44 } 45 46 struct DakkaCookie { 47 private { 48 HTTPReqResp reqresp_; 49 string m_name; 50 51 string m_value; 52 string m_domain; 53 string m_path; 54 string m_expires; 55 long m_maxAge; 56 } 57 58 this(HTTPReqResp reqresp, string m_name, string value, string path) { 59 reqresp_ = reqresp; 60 this.m_name = m_name; 61 this.m_value = value; 62 this.m_path = path; 63 set(); 64 } 65 66 @property string name() const { return m_name; } 67 68 @property void value(string value) { m_value = value; set(); } 69 @property string value() const { return m_value; } 70 71 @property void domain(string value) { m_domain = value; set(); } 72 @property string domain() const { return m_domain; } 73 74 @property void path(string value) { m_path = value; set(); } 75 @property string path() const { return m_path; } 76 77 @property void expires(string value) { m_expires = value; set(); } 78 @property string expires() const { return m_expires; } 79 80 @property void maxAge(long value) { m_maxAge = value; set(); } 81 @property long maxAge() const { return m_maxAge; } 82 83 void set() { reqresp_.response_setCookie(m_name, m_value, m_path, m_maxAge, m_expires, m_domain); } 84 } 85 86 final struct DakkaSession { 87 private { 88 string id_; 89 HTTPReqResp reqresp_; 90 } 91 92 this(HTTPReqResp reqresp, string path, size_t options) { 93 reqresp_ = reqresp; 94 reqresp.response_startSession(path, options); 95 id_ = reqresp.session_id; 96 } 97 98 bool opCast() { return !reqresp_.session_isnull; } 99 @property string id() const { return id_; } 100 bool isKeySet(string key) { return reqresp_.session_isKeySet(key); } 101 102 T get(T)(string key, lazy T def_value = T.init) { 103 import std.conv : to; 104 105 if (isKeySet(key)) 106 static if (is(T == string)) 107 return reqresp_.session_get(key); 108 else 109 return to!T(reqresp_.session_get(key)); 110 else 111 return def_value; 112 } 113 114 void set(T)(string key, T value) { 115 import std.conv : to; 116 static if (is(T == string)) 117 reqresp_.session_set(key, value); 118 else 119 reqresp_.session_set(key, to!string(value)); 120 } 121 122 int opApply(int delegate(string key, string value) del) { 123 foreach(key; reqresp_.session_keys) 124 if( auto ret = del(key, reqresp_.session_get(key)) != 0 ) 125 return ret; 126 return 0; 127 } 128 129 string opIndex(string name) { return reqresp_.session_get(name); } 130 void opIndexAssign(string value, string name) { set(name, value); } 131 } 132 133 class DakkaHTTPRequest : HTTPRequest { 134 HTTPServerRequest requestImpl; 135 alias requestImpl this; 136 137 this(HTTPReqResp reqresp) { 138 auto data = reqresp.request; 139 import std.datetime : SysTime; 140 requestImpl = new HTTPServerRequest(SysTime.fromISOExtString(data.timeCreated), data.port); 141 142 mixin(settingFromType!(RequestData, "data")(11)); 143 foreach(k, v; data.headers) { 144 headers[k] = v; 145 requestImpl.headers[k] = v; 146 } 147 foreach(k, v; data.query) { 148 requestImpl.query[k] = v; 149 } 150 foreach(k, v; data.form) { 151 requestImpl.form[k] = v; 152 } 153 } 154 } 155 156 private { 157 pure string settingFromType(T, string name)(size_t max = size_t.max) { 158 enum T t = T.init; 159 string ret; 160 foreach(i, id; __traits(allMembers, T)) { 161 if (id != "opAssign" && i < max) 162 ret ~= "static if (__traits(hasMember, typeof(this), \""~ id ~ "\"))" ~ id ~ " = " ~ name ~ "." ~ id ~ ";"; 163 } 164 return ret; 165 } 166 }