mirror of
https://github.com/ultimatepp/ultimatepp.git
synced 2026-05-25 22:03:45 -06:00
.docs
git-svn-id: svn://ultimatepp.org/upp/trunk@5265 f0d560ea-af0d-0410-9eb7-867de7ffcac7
This commit is contained in:
parent
1d8e2578d9
commit
f7e4f73e95
3 changed files with 549 additions and 500 deletions
|
|
@ -1,409 +1,409 @@
|
|||
#include "Skylark.h"
|
||||
|
||||
#define LLOG(x) //DLOG(x)
|
||||
#define LDUMP(x) //DDUMP(x)
|
||||
#define LDUMPC(x) //DDUMPC(x)
|
||||
#define LDUMPM(x) //DDUMPM(x)
|
||||
#define LTIMING(x) //RTIMING(x)
|
||||
|
||||
namespace Upp {
|
||||
|
||||
enum { DISPATCH_VARARGS = -1 };
|
||||
|
||||
struct DispatchNode : Moveable<DispatchNode> {
|
||||
VectorMap<String, int> subnode;
|
||||
void (*view)(Http&);
|
||||
int argpos;
|
||||
int method;
|
||||
bool post_raw;
|
||||
String id;
|
||||
|
||||
enum { GET, POST };
|
||||
|
||||
DispatchNode() { view = NULL; argpos = Null; method = GET; post_raw = false; }
|
||||
};
|
||||
|
||||
static Vector<DispatchNode>& sDispatchMap()
|
||||
{
|
||||
static Vector<DispatchNode> x;
|
||||
return x;
|
||||
}
|
||||
|
||||
static VectorMap<String, Vector<String> >& sLinkMap()
|
||||
{
|
||||
static VectorMap<String, Vector<String> > x;
|
||||
return x;
|
||||
}
|
||||
|
||||
static Index<uintptr_t>& sViewIndex()
|
||||
{
|
||||
static Index<uintptr_t> x;
|
||||
return x;
|
||||
}
|
||||
|
||||
void DumpDispatchMap()
|
||||
{
|
||||
Vector<DispatchNode>& DispatchMap = sDispatchMap();
|
||||
for(int i = 0; i < DispatchMap.GetCount(); i++) {
|
||||
LLOG("-------------");
|
||||
String sub;
|
||||
for(int j = 0; j < DispatchMap[i].subnode.GetCount(); j++)
|
||||
sub << DispatchMap[i].subnode.GetKey(j) << "->" << DispatchMap[i].subnode[j] << ", ";
|
||||
LLOG(i << " " << (bool)DispatchMap[i].view << ": " << sub);
|
||||
}
|
||||
}
|
||||
|
||||
Vector<String> *GetUrlViewLinkParts(const String& id)
|
||||
{
|
||||
int q = sLinkMap().Find(id);
|
||||
if(q < 0)
|
||||
return NULL;
|
||||
return &sLinkMap()[q];
|
||||
}
|
||||
|
||||
String MakeLink(void (*view)(Http&), const Vector<Value>& arg)
|
||||
{
|
||||
int q = sViewIndex().Find((uintptr_t)view);
|
||||
if(q < 0)
|
||||
throw Exc("Invalid view");
|
||||
if(q < 0)
|
||||
return String();
|
||||
StringBuffer out;
|
||||
MakeLink(out, sLinkMap()[q], arg);
|
||||
return out;
|
||||
}
|
||||
|
||||
void RegisterView0(void (*view)(Http&), const char *id, String path, bool primary)
|
||||
{
|
||||
LLOG("RegisterView " << path);
|
||||
Vector<String>& linkpart = sLinkMap().GetAdd(id);
|
||||
sViewIndex().FindAdd((uintptr_t)view);
|
||||
Vector<DispatchNode>& DispatchMap = sDispatchMap();
|
||||
int method = DispatchNode::GET;
|
||||
bool post_raw = false;
|
||||
int q = path.Find(':');
|
||||
if(q >= 0) {
|
||||
if(path.Mid(q + 1) == "POST")
|
||||
method = DispatchNode::POST;
|
||||
if(path.Mid(q + 1) == "POST_RAW") {
|
||||
method = DispatchNode::POST;
|
||||
post_raw = true;
|
||||
}
|
||||
path = path.Mid(0, q);
|
||||
}
|
||||
Vector<String> h = Split(path, '/');
|
||||
if(DispatchMap.GetCount() == 0)
|
||||
DispatchMap.Add();
|
||||
q = 0;
|
||||
int linkargpos = 0;
|
||||
for(int i = 0; i < h.GetCount(); i++) {
|
||||
String s = h[i];
|
||||
LLOG(" Node " << h[i]);
|
||||
DispatchNode& n = DispatchMap[q];
|
||||
if(*s == '*') {
|
||||
int argpos = Null;
|
||||
if(IsDigit(s[1]))
|
||||
linkargpos = argpos = minmax(atoi(~s + 1), 0, 30);
|
||||
else
|
||||
if(s[1] == '*')
|
||||
argpos = DISPATCH_VARARGS;
|
||||
q = DispatchMap.GetCount();
|
||||
LLOG(" Adding arg " << argpos << ": " << q);
|
||||
n.subnode.Add(Null, q);
|
||||
DispatchMap.Add();
|
||||
DispatchMap[q].argpos = argpos;
|
||||
if(primary)
|
||||
linkpart.Add(String(linkargpos++, 1));
|
||||
}
|
||||
else {
|
||||
if(primary)
|
||||
linkpart.Add(s);
|
||||
q = n.subnode.Get(s, -1);
|
||||
if(q < 0) {
|
||||
q = DispatchMap.GetCount();
|
||||
LLOG(" Adding " << s << ": " << q);
|
||||
n.subnode.Add(s, q);
|
||||
DispatchMap.Add();
|
||||
}
|
||||
}
|
||||
}
|
||||
ASSERT_(!DispatchMap[q].view, "duplicate view " + String(path));
|
||||
DispatchMap[q].view = view;
|
||||
DispatchMap[q].method = method;
|
||||
DispatchMap[q].id = id;
|
||||
DispatchMap[q].post_raw = post_raw;
|
||||
// DumpDispatchMap();
|
||||
}
|
||||
|
||||
struct ViewData {
|
||||
void (*view)(Http&);
|
||||
String id;
|
||||
String path;
|
||||
};
|
||||
|
||||
static Array<ViewData>& sViewData()
|
||||
{
|
||||
static Array<ViewData> x;
|
||||
return x;
|
||||
}
|
||||
|
||||
void RegisterHandler(void (*view)(Http&), const char *id, const char *path)
|
||||
{
|
||||
Array<ViewData>& v = sViewData();
|
||||
ViewData& w = v.Add();
|
||||
w.view = view;
|
||||
w.id = id;
|
||||
w.path = path;
|
||||
}
|
||||
|
||||
void SkylarkApp::FinalizeViews()
|
||||
{
|
||||
Array<ViewData>& w = sViewData();
|
||||
for(int i = 0; i < w.GetCount(); i++) {
|
||||
const ViewData& v = w[i];
|
||||
ASSERT_(sViewIndex().Find((uintptr_t)v.view) < 0, "duplicate view function registration " + String(v.id));
|
||||
String p = v.path;
|
||||
if(*p == '/')
|
||||
p = p.Mid(1);
|
||||
else
|
||||
p = root + '/' + p;
|
||||
Vector<String> h = Split(ReplaceVars(p, view_var, '$'), ';');
|
||||
for(int i = 0; i < h.GetCount(); i++)
|
||||
RegisterView0(v.view, v.id, h[i], i == 0);
|
||||
}
|
||||
w.Clear();
|
||||
}
|
||||
|
||||
struct BestDispatch {
|
||||
void (*view)(Http&);
|
||||
int matched_parts;
|
||||
int matched_params;
|
||||
Vector<String>& arg;
|
||||
String id;
|
||||
bool post_raw;
|
||||
|
||||
BestDispatch(Vector<String>& arg) : arg(arg) { matched_parts = -1; matched_params = 0; view = NULL; post_raw = false; }
|
||||
};
|
||||
|
||||
void GetBestDispatch(int method,
|
||||
const Vector<String>& part, int ii, const DispatchNode& n, Vector<String>& arg,
|
||||
BestDispatch& bd, int matched_parts, int matched_params)
|
||||
{
|
||||
Vector<DispatchNode>& DispatchMap = sDispatchMap();
|
||||
if(ii >= part.GetCount()) {
|
||||
if(n.view && n.method == method &&
|
||||
(matched_parts > bd.matched_parts ||
|
||||
matched_parts == bd.matched_parts && matched_params > bd.matched_params)) {
|
||||
LLOG("Matched " << n.id << " parts " << matched_parts << " params " << matched_params);
|
||||
bd.arg <<= arg;
|
||||
bd.view = n.view;
|
||||
bd.matched_parts = matched_parts;
|
||||
bd.id = n.id;
|
||||
bd.post_raw = n.post_raw;
|
||||
}
|
||||
if(!bd.view) {
|
||||
int q = n.subnode.Find(String());
|
||||
while(q >= 0) {
|
||||
const DispatchNode& an = DispatchMap[n.subnode[q]];
|
||||
if(an.argpos == DISPATCH_VARARGS && an.view && an.method == method) {
|
||||
bd.view = an.view;
|
||||
bd.id = n.id;
|
||||
bd.arg.Clear();
|
||||
break;
|
||||
}
|
||||
q = n.subnode.FindNext(q);
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
int qq = n.subnode.Get(part[ii], -1);
|
||||
if(qq >= 0)
|
||||
GetBestDispatch(method, part, ii + 1, DispatchMap[qq], arg, bd, matched_parts + 1, matched_params);
|
||||
int q = n.subnode.Find(String());
|
||||
while(q >= 0) {
|
||||
int qq = n.subnode[q];
|
||||
int ac = arg.GetCount();
|
||||
const DispatchNode& an = DispatchMap[qq];
|
||||
int apos = an.argpos;
|
||||
LLOG(" *" << qq << " apos: " << apos);
|
||||
if(apos == DISPATCH_VARARGS) {
|
||||
if(an.view && an.method == method &&
|
||||
(matched_parts > bd.matched_parts || matched_parts == bd.matched_parts && matched_params > bd.matched_params)) {
|
||||
LLOG("Matched VARARGS " << an.id << " parts " << matched_parts << " params " << matched_params);
|
||||
bd.arg <<= arg;
|
||||
bd.arg.Append(part, ii, part.GetCount() - ii);
|
||||
bd.view = an.view;
|
||||
bd.matched_parts = matched_parts;
|
||||
bd.id = an.id;
|
||||
}
|
||||
}
|
||||
else {
|
||||
String pv;
|
||||
if(IsNull(apos))
|
||||
arg.Add(part[ii]);
|
||||
else {
|
||||
String& at = arg.At(apos);
|
||||
pv = at;
|
||||
at = part[ii];
|
||||
}
|
||||
GetBestDispatch(method, part, ii + 1, an, arg, bd, matched_parts, matched_params + 1);
|
||||
if(!IsNull(apos))
|
||||
arg[apos] = pv;
|
||||
}
|
||||
arg.SetCount(ac);
|
||||
q = n.subnode.FindNext(q);
|
||||
}
|
||||
}
|
||||
|
||||
void Http::Dispatch(TcpSocket& socket)
|
||||
{
|
||||
const Vector<DispatchNode>& DispatchMap = sDispatchMap();
|
||||
if(hdr.Read(socket)) {
|
||||
int len = GetLength();
|
||||
content = socket.GetAll(len);
|
||||
LLOG("--------------------------------------------");
|
||||
SKYLARKLOG(hdr.GetMethod() << " " << hdr.GetURI());
|
||||
LDUMP(content);
|
||||
String r;
|
||||
var.Clear();
|
||||
arg.Clear();
|
||||
LTIMING("Request processing");
|
||||
request_content_type = GetHeader("content-type");
|
||||
String rc = ToLower(request_content_type);
|
||||
bool post = hdr.GetMethod() == "POST";
|
||||
if(post)
|
||||
if(rc.StartsWith("application/x-www-form-urlencoded"))
|
||||
ParseRequest(content);
|
||||
else
|
||||
if(rc.StartsWith("multipart/"))
|
||||
ReadMultiPart(content);
|
||||
String uri = hdr.GetURI();
|
||||
int q = uri.Find('?');
|
||||
if(q >= 0) {
|
||||
if(!post)
|
||||
ParseRequest(~uri + q + 1);
|
||||
uri.Trim(q);
|
||||
}
|
||||
for(int i = hdr.fields.Find("cookie"); i >= 0; i = hdr.fields.FindNext(i)) {
|
||||
const String& h = hdr.fields[i];
|
||||
int q = 0;
|
||||
for(;;) {
|
||||
int qq = h.Find('=', q);
|
||||
if(qq < 0)
|
||||
break;
|
||||
String id = ToLower(TrimBoth(h.Mid(q, qq - q)));
|
||||
qq++;
|
||||
q = h.Find(';', qq);
|
||||
if(q < 0) {
|
||||
var.Add('@' + id, UrlDecode(h.Mid(qq)));
|
||||
break;
|
||||
}
|
||||
var.Add('@' + id, UrlDecode(h.Mid(qq, q - qq)));
|
||||
q++;
|
||||
}
|
||||
}
|
||||
var.GetAdd("static") = app.static_dir;
|
||||
var.GetAdd(".__identity__"); // To make StdLib.icpp GetIndentity work without changing preset stack positions
|
||||
LDUMPM(var);
|
||||
Vector<String> part = Split(uri, '/');
|
||||
for(int i = 0; i < part.GetCount(); i++)
|
||||
part[i] = UrlDecode(part[i]);
|
||||
LDUMPC(part);
|
||||
Vector<String> a;
|
||||
BestDispatch bd(arg);
|
||||
if(DispatchMap.GetCount())
|
||||
GetBestDispatch(post ? DispatchNode::POST : DispatchNode::GET, part, 0, DispatchMap[0], a, bd, 0, 0);
|
||||
LDUMPC(arg);
|
||||
response.Clear();
|
||||
if(bd.view) {
|
||||
try {
|
||||
if(SQL.IsOpen())
|
||||
SQL.Begin();
|
||||
LoadSession();
|
||||
session_dirty = false;
|
||||
if(post && !bd.post_raw) {
|
||||
String id = Nvl((*this)["__post_identity__"], (*this)["__js_identity__"]);
|
||||
if(id != (*this)[".__identity__"])
|
||||
throw AuthExc("identity error");
|
||||
}
|
||||
lang = Nvl(Int(".__lang__"), LNG_ENGLISH);
|
||||
Upp::SetLanguage(lang);
|
||||
var.GetAdd(".__lang__") = lang;
|
||||
var.GetAdd(".language") = ToLower(LNGAsText(lang));
|
||||
viewid = bd.id;
|
||||
LDUMP(viewid);
|
||||
(*bd.view)(*this);
|
||||
if(session_dirty)
|
||||
SaveSession();
|
||||
if(SQL.IsOpen())
|
||||
SQL.Commit();
|
||||
}
|
||||
catch(SqlExc e) {
|
||||
if(SQL.IsOpen())
|
||||
SQL.Rollback();
|
||||
response << "Internal server error<br>"
|
||||
<< "SQL ERROR: " << e;
|
||||
code = 500;
|
||||
code_text = "Internal server error";
|
||||
app.SqlError(*this);
|
||||
}
|
||||
catch(AuthExc e) {
|
||||
if(SQL.IsOpen())
|
||||
SQL.Rollback();
|
||||
response << e;
|
||||
code = 403;
|
||||
code_text = "Unauthorized";
|
||||
app.Unauthorized(*this);
|
||||
}
|
||||
catch(BadRequestExc e) {
|
||||
if(SQL.IsOpen())
|
||||
SQL.Rollback();
|
||||
response << "Bad request";
|
||||
code = 400;
|
||||
code_text = "Bad request";
|
||||
app.Unauthorized(*this);
|
||||
}
|
||||
catch(Exc e) {
|
||||
if(SQL.IsOpen())
|
||||
SQL.Rollback();
|
||||
response << "Internal server error<br>"
|
||||
<< e;
|
||||
code = 500;
|
||||
code_text = "Internal server error";
|
||||
app.InternalError(*this);
|
||||
}
|
||||
}
|
||||
else {
|
||||
response << "Page not found";
|
||||
code = 404;
|
||||
code_text = "Not found";
|
||||
app.NotFound(*this);
|
||||
}
|
||||
r.Clear();
|
||||
SKYLARKLOG("=== Response: " << code << ' ' << code_text);
|
||||
if(redirect.GetCount()) {
|
||||
SKYLARKLOG("Redirect to: " << redirect);
|
||||
r << "HTTP/1.1 " << code << " Found\r\n";
|
||||
r << "Location: " << redirect << "\r\n";
|
||||
for(int i = 0; i < cookies.GetCount(); i++)
|
||||
r << cookies[i];
|
||||
}
|
||||
else {
|
||||
r <<
|
||||
"HTTP/1.0 " << code << ' ' << code_text << "\r\n"
|
||||
"Date: " << WwwFormat(GetUtcTime()) << "\r\n"
|
||||
"Server: U++\r\n"
|
||||
"Content-Length: " << response.GetCount() << "\r\n"
|
||||
"Connection: close\r\n"
|
||||
"Cache-Control: no-cache\r\n"
|
||||
"Content-Type: " << content_type << "\r\n";
|
||||
for(int i = 0; i < cookies.GetCount(); i++)
|
||||
r << cookies[i];
|
||||
r << "\r\n";
|
||||
}
|
||||
socket.PutAll(r);
|
||||
socket.PutAll(response);
|
||||
}
|
||||
}
|
||||
|
||||
#include "Skylark.h"
|
||||
|
||||
#define LLOG(x) //DLOG(x)
|
||||
#define LDUMP(x) //DDUMP(x)
|
||||
#define LDUMPC(x) //DDUMPC(x)
|
||||
#define LDUMPM(x) //DDUMPM(x)
|
||||
#define LTIMING(x) //RTIMING(x)
|
||||
|
||||
namespace Upp {
|
||||
|
||||
enum { DISPATCH_VARARGS = -1 };
|
||||
|
||||
struct DispatchNode : Moveable<DispatchNode> {
|
||||
VectorMap<String, int> subnode;
|
||||
void (*view)(Http&);
|
||||
int argpos;
|
||||
int method;
|
||||
bool post_raw;
|
||||
String id;
|
||||
|
||||
enum { GET, POST };
|
||||
|
||||
DispatchNode() { view = NULL; argpos = Null; method = GET; post_raw = false; }
|
||||
};
|
||||
|
||||
static Vector<DispatchNode>& sDispatchMap()
|
||||
{
|
||||
static Vector<DispatchNode> x;
|
||||
return x;
|
||||
}
|
||||
|
||||
static VectorMap<String, Vector<String> >& sLinkMap()
|
||||
{
|
||||
static VectorMap<String, Vector<String> > x;
|
||||
return x;
|
||||
}
|
||||
|
||||
static Index<uintptr_t>& sViewIndex()
|
||||
{
|
||||
static Index<uintptr_t> x;
|
||||
return x;
|
||||
}
|
||||
|
||||
void DumpDispatchMap()
|
||||
{
|
||||
Vector<DispatchNode>& DispatchMap = sDispatchMap();
|
||||
for(int i = 0; i < DispatchMap.GetCount(); i++) {
|
||||
LLOG("-------------");
|
||||
String sub;
|
||||
for(int j = 0; j < DispatchMap[i].subnode.GetCount(); j++)
|
||||
sub << DispatchMap[i].subnode.GetKey(j) << "->" << DispatchMap[i].subnode[j] << ", ";
|
||||
LLOG(i << " " << (bool)DispatchMap[i].view << ": " << sub);
|
||||
}
|
||||
}
|
||||
|
||||
Vector<String> *GetUrlViewLinkParts(const String& id)
|
||||
{
|
||||
int q = sLinkMap().Find(id);
|
||||
if(q < 0)
|
||||
return NULL;
|
||||
return &sLinkMap()[q];
|
||||
}
|
||||
|
||||
String MakeLink(void (*view)(Http&), const Vector<Value>& arg)
|
||||
{
|
||||
int q = sViewIndex().Find((uintptr_t)view);
|
||||
if(q < 0)
|
||||
throw Exc("Invalid view");
|
||||
if(q < 0)
|
||||
return String();
|
||||
StringBuffer out;
|
||||
MakeLink(out, sLinkMap()[q], arg);
|
||||
return out;
|
||||
}
|
||||
|
||||
void RegisterView0(void (*view)(Http&), const char *id, String path, bool primary)
|
||||
{
|
||||
LLOG("RegisterView " << path);
|
||||
Vector<String>& linkpart = sLinkMap().GetAdd(id);
|
||||
sViewIndex().FindAdd((uintptr_t)view);
|
||||
Vector<DispatchNode>& DispatchMap = sDispatchMap();
|
||||
int method = DispatchNode::GET;
|
||||
bool post_raw = false;
|
||||
int q = path.Find(':');
|
||||
if(q >= 0) {
|
||||
if(path.Mid(q + 1) == "POST")
|
||||
method = DispatchNode::POST;
|
||||
if(path.Mid(q + 1) == "POST_RAW") {
|
||||
method = DispatchNode::POST;
|
||||
post_raw = true;
|
||||
}
|
||||
path = path.Mid(0, q);
|
||||
}
|
||||
Vector<String> h = Split(path, '/');
|
||||
if(DispatchMap.GetCount() == 0)
|
||||
DispatchMap.Add();
|
||||
q = 0;
|
||||
int linkargpos = 0;
|
||||
for(int i = 0; i < h.GetCount(); i++) {
|
||||
String s = h[i];
|
||||
LLOG(" Node " << h[i]);
|
||||
DispatchNode& n = DispatchMap[q];
|
||||
if(*s == '*') {
|
||||
int argpos = Null;
|
||||
if(IsDigit(s[1]))
|
||||
linkargpos = argpos = minmax(atoi(~s + 1), 0, 30);
|
||||
else
|
||||
if(s[1] == '*')
|
||||
argpos = DISPATCH_VARARGS;
|
||||
q = DispatchMap.GetCount();
|
||||
LLOG(" Adding arg " << argpos << ": " << q);
|
||||
n.subnode.Add(Null, q);
|
||||
DispatchMap.Add();
|
||||
DispatchMap[q].argpos = argpos;
|
||||
if(primary)
|
||||
linkpart.Add(String(linkargpos++, 1));
|
||||
}
|
||||
else {
|
||||
if(primary)
|
||||
linkpart.Add(s);
|
||||
q = n.subnode.Get(s, -1);
|
||||
if(q < 0) {
|
||||
q = DispatchMap.GetCount();
|
||||
LLOG(" Adding " << s << ": " << q);
|
||||
n.subnode.Add(s, q);
|
||||
DispatchMap.Add();
|
||||
}
|
||||
}
|
||||
}
|
||||
ASSERT_(!DispatchMap[q].view, "duplicate view " + String(path));
|
||||
DispatchMap[q].view = view;
|
||||
DispatchMap[q].method = method;
|
||||
DispatchMap[q].id = id;
|
||||
DispatchMap[q].post_raw = post_raw;
|
||||
// DumpDispatchMap();
|
||||
}
|
||||
|
||||
struct ViewData {
|
||||
void (*view)(Http&);
|
||||
String id;
|
||||
String path;
|
||||
};
|
||||
|
||||
static Array<ViewData>& sViewData()
|
||||
{
|
||||
static Array<ViewData> x;
|
||||
return x;
|
||||
}
|
||||
|
||||
void RegisterHandler(void (*view)(Http&), const char *id, const char *path)
|
||||
{
|
||||
Array<ViewData>& v = sViewData();
|
||||
ViewData& w = v.Add();
|
||||
w.view = view;
|
||||
w.id = id;
|
||||
w.path = path;
|
||||
}
|
||||
|
||||
void SkylarkApp::FinalizeViews()
|
||||
{
|
||||
Array<ViewData>& w = sViewData();
|
||||
for(int i = 0; i < w.GetCount(); i++) {
|
||||
const ViewData& v = w[i];
|
||||
ASSERT_(sViewIndex().Find((uintptr_t)v.view) < 0, "duplicate view function registration " + String(v.id));
|
||||
String p = v.path;
|
||||
if(*p == '/')
|
||||
p = p.Mid(1);
|
||||
else
|
||||
p = root + '/' + p;
|
||||
Vector<String> h = Split(ReplaceVars(p, view_var, '$'), ';');
|
||||
for(int i = 0; i < h.GetCount(); i++)
|
||||
RegisterView0(v.view, v.id, h[i], i == 0);
|
||||
}
|
||||
w.Clear();
|
||||
}
|
||||
|
||||
struct BestDispatch {
|
||||
void (*view)(Http&);
|
||||
int matched_parts;
|
||||
int matched_params;
|
||||
Vector<String>& arg;
|
||||
String id;
|
||||
bool post_raw;
|
||||
|
||||
BestDispatch(Vector<String>& arg) : arg(arg) { matched_parts = -1; matched_params = 0; view = NULL; post_raw = false; }
|
||||
};
|
||||
|
||||
void GetBestDispatch(int method,
|
||||
const Vector<String>& part, int ii, const DispatchNode& n, Vector<String>& arg,
|
||||
BestDispatch& bd, int matched_parts, int matched_params)
|
||||
{
|
||||
Vector<DispatchNode>& DispatchMap = sDispatchMap();
|
||||
if(ii >= part.GetCount()) {
|
||||
if(n.view && n.method == method &&
|
||||
(matched_parts > bd.matched_parts ||
|
||||
matched_parts == bd.matched_parts && matched_params > bd.matched_params)) {
|
||||
LLOG("Matched " << n.id << " parts " << matched_parts << " params " << matched_params);
|
||||
bd.arg <<= arg;
|
||||
bd.view = n.view;
|
||||
bd.matched_parts = matched_parts;
|
||||
bd.id = n.id;
|
||||
bd.post_raw = n.post_raw;
|
||||
}
|
||||
if(!bd.view) {
|
||||
int q = n.subnode.Find(String());
|
||||
while(q >= 0) {
|
||||
const DispatchNode& an = DispatchMap[n.subnode[q]];
|
||||
if(an.argpos == DISPATCH_VARARGS && an.view && an.method == method) {
|
||||
bd.view = an.view;
|
||||
bd.id = n.id;
|
||||
bd.arg.Clear();
|
||||
break;
|
||||
}
|
||||
q = n.subnode.FindNext(q);
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
int qq = n.subnode.Get(part[ii], -1);
|
||||
if(qq >= 0)
|
||||
GetBestDispatch(method, part, ii + 1, DispatchMap[qq], arg, bd, matched_parts + 1, matched_params);
|
||||
int q = n.subnode.Find(String());
|
||||
while(q >= 0) {
|
||||
int qq = n.subnode[q];
|
||||
int ac = arg.GetCount();
|
||||
const DispatchNode& an = DispatchMap[qq];
|
||||
int apos = an.argpos;
|
||||
LLOG(" *" << qq << " apos: " << apos);
|
||||
if(apos == DISPATCH_VARARGS) {
|
||||
if(an.view && an.method == method &&
|
||||
(matched_parts > bd.matched_parts || matched_parts == bd.matched_parts && matched_params > bd.matched_params)) {
|
||||
LLOG("Matched VARARGS " << an.id << " parts " << matched_parts << " params " << matched_params);
|
||||
bd.arg <<= arg;
|
||||
bd.arg.Append(part, ii, part.GetCount() - ii);
|
||||
bd.view = an.view;
|
||||
bd.matched_parts = matched_parts;
|
||||
bd.id = an.id;
|
||||
}
|
||||
}
|
||||
else {
|
||||
String pv;
|
||||
if(IsNull(apos))
|
||||
arg.Add(part[ii]);
|
||||
else {
|
||||
String& at = arg.At(apos);
|
||||
pv = at;
|
||||
at = part[ii];
|
||||
}
|
||||
GetBestDispatch(method, part, ii + 1, an, arg, bd, matched_parts, matched_params + 1);
|
||||
if(!IsNull(apos))
|
||||
arg[apos] = pv;
|
||||
}
|
||||
arg.SetCount(ac);
|
||||
q = n.subnode.FindNext(q);
|
||||
}
|
||||
}
|
||||
|
||||
void Http::Dispatch(TcpSocket& socket)
|
||||
{
|
||||
const Vector<DispatchNode>& DispatchMap = sDispatchMap();
|
||||
if(hdr.Read(socket)) {
|
||||
int len = GetLength();
|
||||
content = socket.GetAll(len);
|
||||
LLOG("--------------------------------------------");
|
||||
SKYLARKLOG(hdr.GetMethod() << " " << hdr.GetURI());
|
||||
LDUMP(content);
|
||||
String r;
|
||||
var.Clear();
|
||||
arg.Clear();
|
||||
LTIMING("Request processing");
|
||||
request_content_type = GetHeader("content-type");
|
||||
String rc = ToLower(request_content_type);
|
||||
bool post = hdr.GetMethod() == "POST";
|
||||
if(post)
|
||||
if(rc.StartsWith("application/x-www-form-urlencoded"))
|
||||
ParseRequest(content);
|
||||
else
|
||||
if(rc.StartsWith("multipart/"))
|
||||
ReadMultiPart(content);
|
||||
String uri = hdr.GetURI();
|
||||
int q = uri.Find('?');
|
||||
if(q >= 0) {
|
||||
if(!post)
|
||||
ParseRequest(~uri + q + 1);
|
||||
uri.Trim(q);
|
||||
}
|
||||
for(int i = hdr.fields.Find("cookie"); i >= 0; i = hdr.fields.FindNext(i)) {
|
||||
const String& h = hdr.fields[i];
|
||||
int q = 0;
|
||||
for(;;) {
|
||||
int qq = h.Find('=', q);
|
||||
if(qq < 0)
|
||||
break;
|
||||
String id = ToLower(TrimBoth(h.Mid(q, qq - q)));
|
||||
qq++;
|
||||
q = h.Find(';', qq);
|
||||
if(q < 0) {
|
||||
var.Add('@' + id, UrlDecode(h.Mid(qq)));
|
||||
break;
|
||||
}
|
||||
var.Add('@' + id, UrlDecode(h.Mid(qq, q - qq)));
|
||||
q++;
|
||||
}
|
||||
}
|
||||
var.GetAdd("static") = app.static_dir;
|
||||
var.GetAdd(".__identity__"); // To make StdLib.icpp GetIndentity work without changing preset stack positions
|
||||
LDUMPM(var);
|
||||
Vector<String> part = Split(uri, '/');
|
||||
for(int i = 0; i < part.GetCount(); i++)
|
||||
part[i] = UrlDecode(part[i]);
|
||||
LDUMPC(part);
|
||||
Vector<String> a;
|
||||
BestDispatch bd(arg);
|
||||
if(DispatchMap.GetCount())
|
||||
GetBestDispatch(post ? DispatchNode::POST : DispatchNode::GET, part, 0, DispatchMap[0], a, bd, 0, 0);
|
||||
LDUMPC(arg);
|
||||
response.Clear();
|
||||
if(bd.view) {
|
||||
try {
|
||||
if(SQL.IsOpen())
|
||||
SQL.Begin();
|
||||
LoadSession();
|
||||
session_dirty = false;
|
||||
if(post && !bd.post_raw) {
|
||||
String id = Nvl((*this)["__post_identity__"], (*this)["__js_identity__"]);
|
||||
if(id != (*this)[".__identity__"])
|
||||
throw AuthExc("identity error");
|
||||
}
|
||||
lang = Nvl(Int(".__lang__"), LNG_ENGLISH);
|
||||
Upp::SetLanguage(lang);
|
||||
var.GetAdd(".__lang__") = lang;
|
||||
var.GetAdd(".language") = ToLower(LNGAsText(lang));
|
||||
handlerid = bd.id;
|
||||
LDUMP(viewid);
|
||||
(*bd.view)(*this);
|
||||
if(session_dirty)
|
||||
SaveSession();
|
||||
if(SQL.IsOpen())
|
||||
SQL.Commit();
|
||||
}
|
||||
catch(SqlExc e) {
|
||||
if(SQL.IsOpen())
|
||||
SQL.Rollback();
|
||||
response << "Internal server error<br>"
|
||||
<< "SQL ERROR: " << e;
|
||||
code = 500;
|
||||
code_text = "Internal server error";
|
||||
app.SqlError(*this);
|
||||
}
|
||||
catch(AuthExc e) {
|
||||
if(SQL.IsOpen())
|
||||
SQL.Rollback();
|
||||
response << e;
|
||||
code = 403;
|
||||
code_text = "Unauthorized";
|
||||
app.Unauthorized(*this);
|
||||
}
|
||||
catch(BadRequestExc e) {
|
||||
if(SQL.IsOpen())
|
||||
SQL.Rollback();
|
||||
response << "Bad request";
|
||||
code = 400;
|
||||
code_text = "Bad request";
|
||||
app.Unauthorized(*this);
|
||||
}
|
||||
catch(Exc e) {
|
||||
if(SQL.IsOpen())
|
||||
SQL.Rollback();
|
||||
response << "Internal server error<br>"
|
||||
<< e;
|
||||
code = 500;
|
||||
code_text = "Internal server error";
|
||||
app.InternalError(*this);
|
||||
}
|
||||
}
|
||||
else {
|
||||
response << "Page not found";
|
||||
code = 404;
|
||||
code_text = "Not found";
|
||||
app.NotFound(*this);
|
||||
}
|
||||
r.Clear();
|
||||
SKYLARKLOG("=== Response: " << code << ' ' << code_text);
|
||||
if(redirect.GetCount()) {
|
||||
SKYLARKLOG("Redirect to: " << redirect);
|
||||
r << "HTTP/1.1 " << code << " Found\r\n";
|
||||
r << "Location: " << redirect << "\r\n";
|
||||
for(int i = 0; i < cookies.GetCount(); i++)
|
||||
r << cookies[i];
|
||||
}
|
||||
else {
|
||||
r <<
|
||||
"HTTP/1.0 " << code << ' ' << code_text << "\r\n"
|
||||
"Date: " << WwwFormat(GetUtcTime()) << "\r\n"
|
||||
"Server: U++\r\n"
|
||||
"Content-Length: " << response.GetCount() << "\r\n"
|
||||
"Connection: close\r\n"
|
||||
"Cache-Control: no-cache\r\n"
|
||||
"Content-Type: " << content_type << "\r\n";
|
||||
for(int i = 0; i < cookies.GetCount(); i++)
|
||||
r << cookies[i];
|
||||
r << "\r\n";
|
||||
}
|
||||
socket.PutAll(r);
|
||||
socket.PutAll(response);
|
||||
}
|
||||
}
|
||||
|
||||
};
|
||||
|
|
@ -41,7 +41,7 @@ class Http : public Renderer {
|
|||
HttpHeader hdr;
|
||||
|
||||
String content;
|
||||
String viewid;
|
||||
String handlerid;
|
||||
|
||||
Vector<String> arg;
|
||||
String session_id;
|
||||
|
|
@ -82,7 +82,7 @@ public:
|
|||
String GetHeader(const char *s) const { return hdr[s]; }
|
||||
int GetLength() const { return atoi(GetHeader("content-length")); }
|
||||
|
||||
String GetViewId() const { return viewid; }
|
||||
String GetHandlerId() const { return viewid; }
|
||||
|
||||
Value operator[](const char *id) const { return Renderer::operator[](id); }
|
||||
int Int(const char *id) const;
|
||||
|
|
@ -106,9 +106,10 @@ public:
|
|||
|
||||
Http& ClearSession();
|
||||
Http& SessionSet(const char *id, const Value& value);
|
||||
Http& NewSessionId();
|
||||
|
||||
Http& NewIdentity() { SessionSet("__identity__", Null); return *this; }
|
||||
Http& NewSessionId();
|
||||
|
||||
Http& SetLanguage(int lang);
|
||||
|
||||
Http& Response(int code_, const String& ctext) { code = code_; code_text = ctext; return *this; }
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
topic "";
|
||||
topic "Http";
|
||||
[2 $$0,0#00000000000000000000000000000000:Default]
|
||||
[i448;a25;kKO9;2 $$1,0#37138531426314131252341829483380:class]
|
||||
[l288;2 $$2,2#27521748481378242620020725143825:desc]
|
||||
|
|
@ -10,134 +10,163 @@ topic "";
|
|||
[i448;b42;O9;2 $$8,8#61672508125594000341940100500538:tparam]
|
||||
[b42;2 $$9,9#13035079074754324216151401829390:normal]
|
||||
[{_}%EN-US
|
||||
[ {{10000@(113.42.0) [s0; [*@7;4 Title]]}}&]
|
||||
[ {{10000@(113.42.0) [s0; [*@7;4 Http]]}}&]
|
||||
[s0;%- &]
|
||||
[s1;:Http`:`:class:%- [@(0.0.255)3 class][3 _][*3 Http][3 _:_][@(0.0.255)3 public][3 _][*@3;3 Render
|
||||
er]&]
|
||||
[s2; Http is the reference parameter passed to Skylark handlers.
|
||||
It provides data associated with request, like POST or GET form
|
||||
values, session variables or cookie values, and is used to store
|
||||
any `'output`' values like response fields, cookies, new values
|
||||
of session variables..&]
|
||||
[s2; &]
|
||||
[ {{10000F(128)G(128)@1 [s0; [* Public Method List]]}}&]
|
||||
[s4;%- &]
|
||||
[s3;%- &]
|
||||
[s5;:Http`:`:operator`(`)`(const char`*`,const Value`&`):%- [_^Http^ Http][@(0.0.255) `&]_
|
||||
[* operator()]([@(0.0.255) const]_[@(0.0.255) char]_`*[*@3 id], [@(0.0.255) const]_[_^Value^ V
|
||||
alue][@(0.0.255) `&]_[*@3 v])&]
|
||||
[s2; Calls Renderer`::operator([%-*@3 id] , [%-*@3 v]) to set the value
|
||||
of variable from shared variable space. Return `*this.&]
|
||||
of shared space variable. Returns `*this.&]
|
||||
[s3; &]
|
||||
[s4; &]
|
||||
[s5;:Http`:`:operator`(`)`(const ValueMap`&`):%- [@(0.0.255) virtual]
|
||||
[_^Http^ Http][@(0.0.255) `&]_[* operator()]([@(0.0.255) const]_[_^ValueMap^ ValueMap][@(0.0.255) `&
|
||||
]_[*@3 map])&]
|
||||
[s2; Calls Renderer`::operator([%-*@3 map]) to set the values of variables
|
||||
from shared variable space based on key`-value pairs of [%-*@3 map].
|
||||
Return `*this.&]
|
||||
[s2; Calls Renderer`::operator([%-*@3 map]) to set the values of shared
|
||||
space variables based on key`-value pairs of [%-*@3 map]. Returns
|
||||
`*this.&]
|
||||
[s3; &]
|
||||
[s4; &]
|
||||
[s5;:Http`:`:operator`(`)`(const char`*`,void`(`*`)`(Http`&`)`):%- [_^Http^ Http][@(0.0.255) `&
|
||||
]_[* operator()]([@(0.0.255) const]_[@(0.0.255) char]_`*[*@3 id], [@(0.0.255) void]_(`*[*@3 v
|
||||
iew])([_^Http^ Http][@(0.0.255) `&]))&]
|
||||
[s2; Calls Render [%-*@3 id] [%-*@3 view] .&]
|
||||
]_[* operator()]([@(0.0.255) const]_[@(0.0.255) char]_`*[*@3 id], [@(0.0.255) void]_(`*[*@3 h
|
||||
andler])([_^Http^ Http][@(0.0.255) `&]))&]
|
||||
[s2; Calls Renderer`::operator([%-*@3 id], [%-*@3 handler]) to set the
|
||||
value of shared space variable to url link. Returns `*this.&]
|
||||
[s3; &]
|
||||
[s4; &]
|
||||
[s5;:Http`:`:operator`(`)`(const char`*`,void`(`*`)`(Http`&`)`,const Value`&`):%- [@(0.0.255) v
|
||||
irtual] [_^Http^ Http][@(0.0.255) `&]_[* operator()]([@(0.0.255) const]_[@(0.0.255) char]_`*
|
||||
[*@3 id], [@(0.0.255) void]_(`*[*@3 view])([_^Http^ Http][@(0.0.255) `&]),
|
||||
[*@3 id], [@(0.0.255) void]_(`*[*@3 handler])([_^Http^ Http][@(0.0.255) `&]),
|
||||
[@(0.0.255) const]_Value[@(0.0.255) `&]_[*@3 arg1])&]
|
||||
[s2; [%-*@3 id] [%-*@3 view] [%-*@3 arg1] .&]
|
||||
[s2; Calls Renderer`::operator([%-*@3 id], [%-*@3 handler], [%-*@3 arg1])
|
||||
to set the value of shared space variable to url link with one
|
||||
url argument. Returns `*this.&]
|
||||
[s3; &]
|
||||
[s4; &]
|
||||
[s5;:Http`:`:operator`(`)`(const char`*`,void`(`*`)`(Http`&`)`,const Value`&`,const Value`&`):%- [@(0.0.255) v
|
||||
irtual] [_^Http^ Http][@(0.0.255) `&]_[* operator()]([@(0.0.255) const]_[@(0.0.255) char]_`*
|
||||
[*@3 id], [@(0.0.255) void]_(`*[*@3 view])([_^Http^ Http][@(0.0.255) `&]),
|
||||
[*@3 id], [@(0.0.255) void]_(`*[*@3 handler])([_^Http^ Http][@(0.0.255) `&]),
|
||||
[@(0.0.255) const]_Value[@(0.0.255) `&]_[*@3 arg1], [@(0.0.255) const]_Value[@(0.0.255) `&]_
|
||||
[*@3 arg2])&]
|
||||
[s2; [%-*@3 id] [%-*@3 view] [%-*@3 arg1] [%-*@3 arg2] .&]
|
||||
[s2; Calls Renderer`::operator([%-*@3 id], [%-*@3 handler], [%-*@3 arg1],
|
||||
[%-*@3 arg2]) to set the value of shared space variable to url
|
||||
link with two url arguments. Returns `*this.&]
|
||||
[s3; &]
|
||||
[s4; &]
|
||||
[s5;:Http`:`:operator`(`)`(const Sql`&`):%- [_^Http^ Http][@(0.0.255) `&]_[* operator()]([@(0.0.255) c
|
||||
onst]_[_^Sql^ Sql][@(0.0.255) `&]_[*@3 sql])&]
|
||||
[s2; [%-*@3 sql] .&]
|
||||
[s2; Calls Renderer`::operator([%-*@3 sql]) to set the values of shared
|
||||
space variables based on column`-name/value pairs of current
|
||||
row fetched in [%-*@3 sql]. Returns `*this.&]
|
||||
[s3; &]
|
||||
[s4; &]
|
||||
[s5;:Http`:`:operator`(`)`(Fields`):%- [_^Http^ Http][@(0.0.255) `&]_[* operator()]([_^Fields^ F
|
||||
ields]_[*@3 rec])&]
|
||||
[s2; [%-*@3 rec] .&]
|
||||
[s2; Calls Renderer`::operator([%-*@3 rec]) to set the values of shared
|
||||
space variables based on column`-name/value pairs of [%-*@3 rec]
|
||||
fields. Returns `*this.&]
|
||||
[s3; &]
|
||||
[s4; &]
|
||||
[s5;:Http`:`:operator`(`)`(const SqlSelect`&`):%- [_^Http^ Http][@(0.0.255) `&]_[* operator
|
||||
()]([@(0.0.255) const]_[_^SqlSelect^ SqlSelect][@(0.0.255) `&]_[*@3 row`_sel])&]
|
||||
[s2; [%-*@3 row`_sel] .&]
|
||||
[s2; Calls Renderer`::operator([%-*@3 row`_sel]) to set the values of
|
||||
shared space variables based on column`-name/value pairs of single
|
||||
row fetched from database using [%-*@3 row`_sel]. Returns `*this.&]
|
||||
[s3; &]
|
||||
[s4; &]
|
||||
[s5;:Http`:`:operator`(`)`(const char`*`,const SqlSelect`&`):%- [_^Http^ Http][@(0.0.255) `&
|
||||
]_[* operator()]([@(0.0.255) const]_[@(0.0.255) char]_`*[*@3 id], [@(0.0.255) const]_[_^SqlSelect^ S
|
||||
qlSelect][@(0.0.255) `&]_[*@3 sel])&]
|
||||
[s2; [%-*@3 id] [%-*@3 sel] .&]
|
||||
[s2; Calls Renderer`::operator([%-*@3 id], [%-*@3 sel]) to set the value
|
||||
of shared space variable [%-*@3 id] to the complete result set
|
||||
of [%-*@3 sel] represented as ValueArray of ValueMaps. Returns
|
||||
`*this.&]
|
||||
[s3; &]
|
||||
[s4; &]
|
||||
[s5;:Http`:`:Render`(const char`*`,const String`&`):%- [@(0.0.255) virtual]
|
||||
[_^Http^ Http][@(0.0.255) `&]_[* Render]([@(0.0.255) const]_[@(0.0.255) char]_`*[*@3 id],
|
||||
[@(0.0.255) const]_[_^String^ String][@(0.0.255) `&]_[*@3 template`_name])&]
|
||||
[s2; [%-*@3 id] [%-*@3 template`_name] .&]
|
||||
[s5;:Http`:`:Render`(const char`*`,const String`&`):%- [_^Http^ Http][@(0.0.255) `&]_[* Ren
|
||||
der]([@(0.0.255) const]_[@(0.0.255) char]_`*[*@3 id], [@(0.0.255) const]_[_^String^ String][@(0.0.255) `&
|
||||
]_[*@3 template`_name])&]
|
||||
[s2; Calls Renderer`::Render([%-*@3 id], [%-*@3 template`_name]) to render
|
||||
witz template as RawHtmlText into shared space variable [%-*@3 id].
|
||||
Returns `*this.&]
|
||||
[s3; &]
|
||||
[s4; &]
|
||||
[s5;:Http`:`:Render`(const String`&`):%- [@(0.0.255) virtual] [_^Value^ Value]_[* Render]([@(0.0.255) c
|
||||
onst]_[_^String^ String][@(0.0.255) `&]_[*@3 template`_name])&]
|
||||
[s2; [%-*@3 template`_name] .&]
|
||||
[s5;:Http`:`:Render`(const String`&`):%- [_^Value^ Value]_[* Render]([@(0.0.255) const]_[_^String^ S
|
||||
tring][@(0.0.255) `&]_[*@3 template`_name])&]
|
||||
[s2; Calls Renderer`::Render([%-*@3 template`_name]) to render witz
|
||||
template and return the result as RawHtmlText.&]
|
||||
[s3; &]
|
||||
[s4; &]
|
||||
[s5;:Http`:`:GetHeader`(const char`*`)const:%- [_^String^ String]_[* GetHeader]([@(0.0.255) c
|
||||
onst]_[@(0.0.255) char]_`*[*@3 s])_[@(0.0.255) const]&]
|
||||
[s2; [%-*@3 s] .&]
|
||||
[s2; Returns HTTP request header field value.&]
|
||||
[s3; &]
|
||||
[s4; &]
|
||||
[s5;:Http`:`:GetLength`(`)const:%- [@(0.0.255) int]_[* GetLength]()_[@(0.0.255) const]&]
|
||||
[s2; &]
|
||||
[s2; Returns request content length.&]
|
||||
[s3; &]
|
||||
[s4;%- &]
|
||||
[s5;:Http`:`:GetHandlerId`(`)const:%- [_^String^ String]_[* GetHandlerId]()_[@(0.0.255) con
|
||||
st]&]
|
||||
[s2; Returns the name of handler currently invoked.&]
|
||||
[s3; &]
|
||||
[s4; &]
|
||||
[s5;:Http`:`:GetViewId`(`)const:%- [_^String^ String]_[* GetViewId]()_[@(0.0.255) const]&]
|
||||
[s2; &]
|
||||
[s3; &]
|
||||
[s4; &]
|
||||
[s5;:Http`:`:operator`[`]`(const char`*`)const:%- [@(0.0.255) virtual]
|
||||
[_^Value^ Value]_[* operator`[`]]([@(0.0.255) const]_[@(0.0.255) char]_`*[*@3 id])_[@(0.0.255) c
|
||||
onst]&]
|
||||
[s2; [%-*@3 id] .&]
|
||||
[s5;:Http`:`:operator`[`]`(const char`*`)const:%- [_^Value^ Value]_[* operator`[`]]([@(0.0.255) c
|
||||
onst]_[@(0.0.255) char]_`*[*@3 id])_[@(0.0.255) const]&]
|
||||
[s2; Returns the shared space variable [%-*@3 id, ]void Value if missing.&]
|
||||
[s3; &]
|
||||
[s4; &]
|
||||
[s5;:Http`:`:Int`(const char`*`)const:%- [@(0.0.255) int]_[* Int]([@(0.0.255) const]_[@(0.0.255) c
|
||||
har]_`*[*@3 id])_[@(0.0.255) const]&]
|
||||
[s2; [%-*@3 id] .&]
|
||||
[s2; Returns the shared space variable [%-*@3 id] converted to integer,
|
||||
Null if missing or if it cannot be converted.&]
|
||||
[s3; &]
|
||||
[s4; &]
|
||||
[s5;:Http`:`:operator`[`]`(int`)const:%- [_^String^ String]_[* operator`[`]]([@(0.0.255) in
|
||||
t]_[*@3 i])_[@(0.0.255) const]&]
|
||||
[s2; [%-*@3 i] .&]
|
||||
[s2; Returns the value of URL argument at position [%-*@3 i], empty
|
||||
String if not available.&]
|
||||
[s3; &]
|
||||
[s4; &]
|
||||
[s5;:Http`:`:Int`(int`)const:%- [@(0.0.255) int]_[* Int]([@(0.0.255) int]_[*@3 i])_[@(0.0.255) c
|
||||
onst]&]
|
||||
[s2; [%-*@3 i] .&]
|
||||
[s2; Returns the value of URL argument at position [%-*@3 i] converted
|
||||
to integer, Null if not available.&]
|
||||
[s3; &]
|
||||
[s4; &]
|
||||
[s5;:Http`:`:GetParamCount`(`)const:%- [@(0.0.255) int]_[* GetParamCount]()_[@(0.0.255) con
|
||||
st]&]
|
||||
[s2; &]
|
||||
[s2; Returns the number of URL arguments.&]
|
||||
[s3; &]
|
||||
[s4; &]
|
||||
[s5;:Http`:`:ContentType`(const char`*`):%- [_^Http^ Http][@(0.0.255) `&]_[* ContentType]([@(0.0.255) c
|
||||
onst]_[@(0.0.255) char]_`*[*@3 s])&]
|
||||
[s2; [%-*@3 s] .&]
|
||||
[s2; Sets the response content`-type. Default value is `"text/html;
|
||||
charset`=UTF`-8`". Returns `*this.&]
|
||||
[s3; &]
|
||||
[s4; &]
|
||||
[s5;:Http`:`:Content`(const char`*`,const Value`&`):%- [_^Http^ Http][@(0.0.255) `&]_[* Con
|
||||
tent]([@(0.0.255) const]_[@(0.0.255) char]_`*[*@3 s], [@(0.0.255) const]_[_^Value^ Value][@(0.0.255) `&
|
||||
]_[*@3 data])&]
|
||||
[s2; [%-*@3 s] [%-*@3 data] .&]
|
||||
[s2; Sets the response content`-type to [%-*@3 s] and response content
|
||||
to [%-*@3 data] converted to text. No html escaping is performed.
|
||||
Returns `*this.&]
|
||||
[s3; &]
|
||||
[s4; &]
|
||||
[s5;:Http`:`:operator`<`<`(const Value`&`):%- [_^Http^ Http][@(0.0.255) `&]_[* operator<<](
|
||||
[@(0.0.255) const]_[_^Value^ Value][@(0.0.255) `&]_[*@3 s])&]
|
||||
[s2; [%-*@3 s] .&]
|
||||
[s2; Sets the response content to [%-*@3 data] converted to text. No
|
||||
html escaping is performed. Returns `*this.&]
|
||||
[s3; &]
|
||||
[s4; &]
|
||||
[s5;:Http`:`:SetRawCookie`(const char`*`,const String`&`,Time`,const char`*`,const char`*`,bool`,bool`):%- [_^Http^ H
|
||||
|
|
@ -146,8 +175,9 @@ ttp][@(0.0.255) `&]_[* SetRawCookie]([@(0.0.255) const]_[@(0.0.255) char]_`*[*@3
|
|||
]_`=_Null, [@(0.0.255) const]_[@(0.0.255) char]_`*[*@3 path]_`=_NULL,
|
||||
[@(0.0.255) const]_[@(0.0.255) char]_`*[*@3 domain]_`=_NULL, [@(0.0.255) bool]_[*@3 secure]_
|
||||
`=_[@(0.0.255) false], [@(0.0.255) bool]_[*@3 httponly]_`=_[@(0.0.255) false])&]
|
||||
[s2; [%-*@3 id] [%-*@3 value] [%-*@3 expires] [%-*@3 path] [%-*@3 domain]
|
||||
[%-*@3 secure] [%-*@3 httponly] .&]
|
||||
[s2; Sets the cookie [%-*@3 id] to [%-*@3 value], using [%-*@3 expires],
|
||||
[%-*@3 path], [%-*@3 domain], [%-*@3 secure], [%-*@3 httponly] to setup
|
||||
cookie attributes. [%-*@3 value] is not url`-encoded. Returns `*this.&]
|
||||
[s3; &]
|
||||
[s4; &]
|
||||
[s5;:Http`:`:SetCookie`(const char`*`,const String`&`,Time`,const char`*`,const char`*`,bool`,bool`):%- [_^Http^ H
|
||||
|
|
@ -156,113 +186,131 @@ ttp][@(0.0.255) `&]_[* SetCookie]([@(0.0.255) const]_[@(0.0.255) char]_`*[*@3 id
|
|||
]_`=_Null, [@(0.0.255) const]_[@(0.0.255) char]_`*[*@3 path]_`=_NULL,
|
||||
[@(0.0.255) const]_[@(0.0.255) char]_`*[*@3 domain]_`=_NULL, [@(0.0.255) bool]_[*@3 secure]_
|
||||
`=_[@(0.0.255) false], [@(0.0.255) bool]_[*@3 httponly]_`=_[@(0.0.255) false])&]
|
||||
[s2; [%-*@3 id] [%-*@3 value] [%-*@3 expires] [%-*@3 path] [%-*@3 domain]
|
||||
[%-*@3 secure] [%-*@3 httponly] .&]
|
||||
[s2; Same as SetRawCookie, but url`-encoding the [%-*@3 value]. Returns
|
||||
`*this.&]
|
||||
[s3; &]
|
||||
[s4; &]
|
||||
[s5;:Http`:`:ClearSession`(`):%- [_^Http^ Http][@(0.0.255) `&]_[* ClearSession]()&]
|
||||
[s2; &]
|
||||
[s2; Clears the session variables and session id (but their values
|
||||
in shared variable space are retained). Returns `*this.&]
|
||||
[s3; &]
|
||||
[s4; &]
|
||||
[s5;:Http`:`:SessionSet`(const char`*`,const Value`&`):%- [_^Http^ Http][@(0.0.255) `&]_[* S
|
||||
essionSet]([@(0.0.255) const]_[@(0.0.255) char]_`*[*@3 id], [@(0.0.255) const]_[_^Value^ Va
|
||||
lue][@(0.0.255) `&]_[*@3 value])&]
|
||||
[s2; [%-*@3 id] [%-*@3 value] .&]
|
||||
[s3; &]
|
||||
[s4; &]
|
||||
[s5;:Http`:`:NewIdentity`(`):%- [_^Http^ Http][@(0.0.255) `&]_[* NewIdentity]()&]
|
||||
[s2; &]
|
||||
[s2; Sets the session value [%-*@3 id] to [%-*@3 value], also sets shared
|
||||
variable space to the same value. [%-*@3 id] must start with `'.`'.
|
||||
Session variables are preserved for session across HTTP requests
|
||||
(using session cookies). Returns `*this.&]
|
||||
[s3; &]
|
||||
[s4; &]
|
||||
[s5;:Http`:`:NewSessionId`(`):%- [_^Http^ Http][@(0.0.255) `&]_[* NewSessionId]()&]
|
||||
[s2; &]
|
||||
[s2; Sets the new session id, effectively changing the session cookie
|
||||
value and storage for current session. Returns `*this.&]
|
||||
[s3; &]
|
||||
[s4; &]
|
||||
[s5;:Http`:`:NewIdentity`(`):%- [_^Http^ Http][@(0.0.255) `&]_[* NewIdentity]()&]
|
||||
[s2; Sets the new CSRF prevention identity. It might be a good idea
|
||||
to call this function after login. Returns `*this.&]
|
||||
[s3; &]
|
||||
[s4; &]
|
||||
[s5;:Http`:`:SetLanguage`(int`):%- [_^Http^ Http][@(0.0.255) `&]_[* SetLanguage]([@(0.0.255) i
|
||||
nt]_[*@3 lang])&]
|
||||
[s2; [%-*@3 lang] .&]
|
||||
[s2; Sets the session language to [%-*@3 lang]. This calls Renderer`::SetLanguage
|
||||
to change the language of witz templates and also sets language
|
||||
related session variables `".`_`_lang`_`_`" (integer value) and
|
||||
`".language`" (text value), so that language can be restored
|
||||
during following HTTP requests. Returns `*this.&]
|
||||
[s3; &]
|
||||
[s4; &]
|
||||
[s5;:Http`:`:Response`(int`,const String`&`):%- [_^Http^ Http][@(0.0.255) `&]_[* Response](
|
||||
[@(0.0.255) int]_[*@3 code`_], [@(0.0.255) const]_[_^String^ String][@(0.0.255) `&]_[*@3 ctex
|
||||
t])&]
|
||||
[s2; [%-*@3 code`_] [%-*@3 ctext] .&]
|
||||
[@(0.0.255) int]_[*@3 code], [@(0.0.255) const]_[_^String^ String][@(0.0.255) `&]_[*@3 ctext])
|
||||
&]
|
||||
[s2; Sets the HTTP response [%-*@3 code] and reason [%-*@3 ctext]. Returns
|
||||
`*this.&]
|
||||
[s3; &]
|
||||
[s4; &]
|
||||
[s5;:Http`:`:RenderResult`(const char`*`):%- [_^Http^ Http][@(0.0.255) `&]_[* RenderResult](
|
||||
[@(0.0.255) const]_[@(0.0.255) char]_`*[*@3 template`_name])&]
|
||||
[s2; [%-*@3 template`_name] .&]
|
||||
[s2; Renders result content using witz template. Returns `*this.&]
|
||||
[s3; &]
|
||||
[s4; &]
|
||||
[s5;:Http`:`:Redirect`(const char`*`,int`):%- [_^Http^ Http][@(0.0.255) `&]_[* Redirect]([@(0.0.255) c
|
||||
onst]_[@(0.0.255) char]_`*[*@3 url], [@(0.0.255) int]_[*@3 code`_]_`=_[@3 302])&]
|
||||
[s2; [%-*@3 url] [%-*@3 code`_] .&]
|
||||
onst]_[@(0.0.255) char]_`*[*@3 url], [@(0.0.255) int]_[*@3 code]_`=_[@3 302])&]
|
||||
[s2; Sets the response to be redirection. [%-*@3 url][%- sets the Location:
|
||||
header of response, ][%-*@3 code][%- the response code.] Returns
|
||||
`*this.&]
|
||||
[s3; &]
|
||||
[s4; &]
|
||||
[s5;:Http`:`:Redirect`(void`(`*`)`(Http`&`)`,const Vector`<Value`>`&`):%- [_^Http^ Http
|
||||
][@(0.0.255) `&]_[* Redirect]([@(0.0.255) void]_(`*[*@3 view])([_^Http^ Http][@(0.0.255) `&])
|
||||
, [@(0.0.255) const]_Vector<Value>`&_[*@3 arg])&]
|
||||
[s2; [%-*@3 view] [%-*@3 arg] .&]
|
||||
][@(0.0.255) `&]_[* Redirect]([@(0.0.255) void]_(`*[*@3 handler])([_^Http^ Http][@(0.0.255) `&
|
||||
]), [@(0.0.255) const]_Vector<Value>`&_[*@3 arg])&]
|
||||
[s2; Sets the redirection response to [%-*@3 handler] with a set of
|
||||
url arguments [%-*@3 arg]. Returns `*this.&]
|
||||
[s3; &]
|
||||
[s4; &]
|
||||
[s5;:Http`:`:Redirect`(void`(`*`)`(Http`&`)`):%- [_^Http^ Http][@(0.0.255) `&]_[* Redirect](
|
||||
[@(0.0.255) void]_(`*[*@3 view])([_^Http^ Http][@(0.0.255) `&]))&]
|
||||
[s2; [%-*@3 view] .&]
|
||||
[@(0.0.255) void]_(`*[*@3 handler])([_^Http^ Http][@(0.0.255) `&]))&]
|
||||
[s2; Sets the redirection response to [%-*@3 handler]. Returns `*this.&]
|
||||
[s3; &]
|
||||
[s4; &]
|
||||
[s5;:Http`:`:Redirect`(void`(`*`)`(Http`&`)`,const Value`&`):%- [_^Http^ Http][@(0.0.255) `&
|
||||
]_[* Redirect]([@(0.0.255) void]_(`*[*@3 view])([_^Http^ Http][@(0.0.255) `&]),
|
||||
[@(0.0.255) const]_Value[@(0.0.255) `&]_[*@3 v1])&]
|
||||
[s2; [%-*@3 view] [%-*@3 v1] .&]
|
||||
]_[* Redirect]([@(0.0.255) void]_(`*[*@3 handler])([_^Http^ Http][@(0.0.255) `&]),
|
||||
[@(0.0.255) const]_Value[@(0.0.255) `&]_[*@3 arg1])&]
|
||||
[s2; Sets the redirection response to [%-*@3 handler] with one url
|
||||
argument. Returns `*this.&]
|
||||
[s3; &]
|
||||
[s4; &]
|
||||
[s5;:Http`:`:Redirect`(void`(`*`)`(Http`&`)`,const Value`&`,const Value`&`):%- [_^Http^ H
|
||||
ttp][@(0.0.255) `&]_[* Redirect]([@(0.0.255) void]_(`*[*@3 view])([_^Http^ Http][@(0.0.255) `&
|
||||
]), [@(0.0.255) const]_Value[@(0.0.255) `&]_[*@3 v1], [@(0.0.255) const]_Value[@(0.0.255) `&
|
||||
]_[*@3 v2])&]
|
||||
[s2; [%-*@3 view] [%-*@3 v1] [%-*@3 v2] .&]
|
||||
ttp][@(0.0.255) `&]_[* Redirect]([@(0.0.255) void]_(`*[*@3 handler])([_^Http^ Http][@(0.0.255) `&
|
||||
]), [@(0.0.255) const]_Value[@(0.0.255) `&]_[*@3 arg1], [@(0.0.255) const]_Value[@(0.0.255) `&
|
||||
]_[*@3 arg2])&]
|
||||
[s2; Sets the redirection response to [%-*@3 handler] with two url
|
||||
arguments. Returns `*this.&]
|
||||
[s3; &]
|
||||
[s4; &]
|
||||
[s5;:Http`:`:Ux`(const char`*`,const String`&`):%- [_^Http^ Http][@(0.0.255) `&]_[* Ux]([@(0.0.255) c
|
||||
onst]_[@(0.0.255) char]_`*[*@3 id], [@(0.0.255) const]_[_^String^ String][@(0.0.255) `&]_[*@3 t
|
||||
ext])&]
|
||||
[s2; [%-*@3 id] [%-*@3 text] .&]
|
||||
[s2; Sets the response in special Skylark format used to provide
|
||||
Ajax support. When using `"skylark.js`" module for Ajax, this
|
||||
response replaces html element with specified html id to [%-*@3 text].
|
||||
(text is not html`-escaped). Returns `*this.&]
|
||||
[s3; &]
|
||||
[s4; &]
|
||||
[s5;:Http`:`:UxRender`(const char`*`,const char`*`):%- [_^Http^ Http][@(0.0.255) `&]_[* UxR
|
||||
ender]([@(0.0.255) const]_[@(0.0.255) char]_`*[*@3 id], [@(0.0.255) const]_[@(0.0.255) char
|
||||
]_`*[*@3 template`_name])&]
|
||||
[s2; [%-*@3 id] [%-*@3 template`_name] .&]
|
||||
[s2; Sets the response in special Skylark format used to provide
|
||||
Ajax support. When using `"skylark.js`" module for Ajax, this
|
||||
response replaces html element with specified html id to the
|
||||
rendered template. Returns `*this.&]
|
||||
[s3; &]
|
||||
[s4; &]
|
||||
[s5;:Http`:`:UxSet`(const char`*`,const String`&`):%- [_^Http^ Http][@(0.0.255) `&]_[* UxSe
|
||||
t]([@(0.0.255) const]_[@(0.0.255) char]_`*[*@3 id], [@(0.0.255) const]_[_^String^ String][@(0.0.255) `&
|
||||
]_[*@3 value])&]
|
||||
[s2; [%-*@3 id] [%-*@3 value] .&]
|
||||
[s2; Sets the response in special Skylark format used to provide
|
||||
Ajax support. When using `"skylark.js`" module for Ajax, this
|
||||
response replaces [*/ the value] of html element with specified
|
||||
html id to the rendered template. Returns `*this.&]
|
||||
[s3; &]
|
||||
[s4; &]
|
||||
[s5;:Http`:`:UxRun`(const String`&`):%- [_^Http^ Http][@(0.0.255) `&]_[* UxRun]([@(0.0.255) c
|
||||
onst]_[_^String^ String][@(0.0.255) `&]_[*@3 js`_code])&]
|
||||
[s2; [%-*@3 js`_code] .&]
|
||||
[s2; Sets the response in special Skylark format used to provide
|
||||
Ajax support. When using `"skylark.js`" module for Ajax, this
|
||||
response makes browser to run arbitrary javascript code. Returns
|
||||
`*this.&]
|
||||
[s3; &]
|
||||
[s4; &]
|
||||
[s5;:Http`:`:GetResponse`(`)const:%- [_^String^ String]_[* GetResponse]()_[@(0.0.255) const
|
||||
]&]
|
||||
[s2; &]
|
||||
[s2; Returns the current response.&]
|
||||
[s3; &]
|
||||
[s4; &]
|
||||
[s5;:Http`:`:Dispatch`(TcpSocket`&`):%- [@(0.0.255) void]_[* Dispatch]([_^TcpSocket^ TcpSoc
|
||||
ket][@(0.0.255) `&]_[*@3 socket])&]
|
||||
[s2; [%-*@3 socket] .&]
|
||||
[s3; &]
|
||||
[s4; &]
|
||||
[s5;:Http`:`:App`(`)const:%- [@(0.0.255) const]_[_^SkylarkApp^ SkylarkApp][@(0.0.255) `&]_[* A
|
||||
pp]()_[@(0.0.255) const]&]
|
||||
[s2; &]
|
||||
[s3; &]
|
||||
[s4; &]
|
||||
[s5;:Http`:`:Http`(SkylarkApp`&`):%- [* Http]([_^SkylarkApp^ SkylarkApp][@(0.0.255) `&]_[*@3 a
|
||||
pp])&]
|
||||
[s2; [%-*@3 app] .&]
|
||||
[s3; &]
|
||||
[s2; This method is not usually called by client application. Skylark
|
||||
framework calls it to process incoming HTTP request.&]
|
||||
[s0; ]]
|
||||
Loading…
Add table
Add a link
Reference in a new issue