322 lines
6.1 KiB
C++
322 lines
6.1 KiB
C++
#include "uri.h"
|
|
|
|
String var_dump(URI uri, String prefix, String postfix)
|
|
{
|
|
return(
|
|
prefix + "URI Parts: " + postfix +
|
|
var_dump(uri.parts, prefix+" ", postfix)+
|
|
prefix + " Query: " + postfix +
|
|
var_dump(uri.query, prefix+" ", postfix)
|
|
);
|
|
}
|
|
|
|
String uri_decode(String q)
|
|
{
|
|
String result;
|
|
for(u32 i = 0; i < q.length(); i++)
|
|
{
|
|
char c = q[i];
|
|
if(c == '%' && q[i+1] != '%')
|
|
{
|
|
result.append(1, hex_to_u8(q.substr(i+1, 2)));
|
|
i += 2;
|
|
}
|
|
else if(c == '+')
|
|
{
|
|
result.append(1, ' ');
|
|
}
|
|
else
|
|
{
|
|
result.append(1, c);
|
|
}
|
|
}
|
|
return(result);
|
|
}
|
|
|
|
String uri_encode(String q)
|
|
{
|
|
String result;
|
|
for(u32 i = 0; i < q.length(); i++)
|
|
{
|
|
char c = q[i];
|
|
if(isalnum(c) || c == '~' || c == '.' || c == '_' || c == '-')
|
|
result.append(1, c);
|
|
else
|
|
{
|
|
result.append(1, '%');
|
|
result.append(to_hex(c));
|
|
}
|
|
}
|
|
return(result);
|
|
}
|
|
|
|
StringMap parse_query(String q)
|
|
{
|
|
StringMap result;
|
|
if(q.length() == 0)
|
|
return(result);
|
|
|
|
bool is_key = true;
|
|
String key = "";
|
|
String value = "";
|
|
for (char &c: q)
|
|
{
|
|
if(c == '=')
|
|
{
|
|
is_key = !is_key;
|
|
}
|
|
else if(c == '&')
|
|
{
|
|
result[uri_decode(key)] = uri_decode(value);
|
|
key = "";
|
|
value = "";
|
|
is_key = true;
|
|
}
|
|
else if(is_key)
|
|
{
|
|
key.append(1, c);
|
|
}
|
|
else
|
|
{
|
|
value.append(1, c);
|
|
}
|
|
}
|
|
|
|
result[uri_decode(key)] = uri_decode(value);
|
|
|
|
return(result);
|
|
}
|
|
|
|
String encode_query(StringMap map)
|
|
{
|
|
String result;
|
|
|
|
for (auto it = map.begin(); it != map.end(); ++it)
|
|
{
|
|
if(result.length() > 0)
|
|
result.append(1, '&');
|
|
result.append(uri_encode(it->first) + "=" + uri_encode(it->second));
|
|
}
|
|
|
|
return(result);
|
|
}
|
|
|
|
StringMap parse_multipart(String q, String boundary, std::vector<UploadedFile>& uploaded_files)
|
|
{
|
|
StringMap result;
|
|
|
|
auto i = boundary.length();
|
|
while(i < q.length())
|
|
{
|
|
auto end_pos = q.find(boundary, i);
|
|
if(end_pos != String::npos)
|
|
{
|
|
String field = q.substr(i, end_pos - i);
|
|
nibble(":", field);
|
|
String ftype = trim(nibble(";", field));
|
|
if(ftype == "form-data")
|
|
{
|
|
nibble("=\"", field);
|
|
String field_name = nibble("\"", field);
|
|
result[field_name] = field.substr(4, field.length()-6);
|
|
}
|
|
else if(ftype == "attachment")
|
|
{
|
|
nibble("=\"", field);
|
|
UploadedFile f;
|
|
f.tmp_name = context->server->config.TMP_UPLOAD_PATH + std::to_string(rand());
|
|
f.file_name = nibble("\"", field);
|
|
String bin = field.substr(4, field.length()-6);
|
|
f.size = bin.length();
|
|
file_put_contents(f.tmp_name, bin);
|
|
uploaded_files.push_back(f);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// we're done
|
|
end_pos = q.length();
|
|
}
|
|
i = end_pos + boundary.length();
|
|
}
|
|
|
|
return(result);
|
|
}
|
|
|
|
URI parse_uri(String uri_String)
|
|
{
|
|
URI result;
|
|
|
|
u8 state = 0;
|
|
String current = "";
|
|
char expect = 0;
|
|
|
|
result.parts["raw"] = uri_String;
|
|
|
|
String part_names[] = {
|
|
"scheme",
|
|
"host",
|
|
"port",
|
|
"path",
|
|
"query",
|
|
"fragment",
|
|
};
|
|
|
|
if(uri_String[0] == '/')
|
|
state = 3;
|
|
|
|
for (char &c: uri_String)
|
|
{
|
|
bool append_it = true;
|
|
|
|
if(expect && expect != c)
|
|
{
|
|
result.parts["error"] = String("\'") + c + String("\' expected");
|
|
result.parts["error_parsing"] = current;
|
|
result.parts["error_part"] = part_names[state];
|
|
return(result);
|
|
}
|
|
expect = 0;
|
|
|
|
switch(state)
|
|
{
|
|
case(0): // scheme
|
|
if(c == ':')
|
|
{
|
|
result.parts[part_names[state]] = current;
|
|
append_it = false;
|
|
current = "";
|
|
state = 1;
|
|
}
|
|
break;
|
|
case(1): // host name
|
|
if(c == '/')
|
|
{
|
|
if(current == "")
|
|
{
|
|
append_it = false;
|
|
break;
|
|
}
|
|
result.parts[part_names[state]] = current;
|
|
append_it = false;
|
|
current = "";
|
|
state = 3;
|
|
expect = '/';
|
|
}
|
|
else if(c == ':')
|
|
{
|
|
result.parts[part_names[state]] = current;
|
|
append_it = false;
|
|
current = "";
|
|
state = 2;
|
|
}
|
|
break;
|
|
case(2): // port
|
|
if(c == '/')
|
|
{
|
|
result.parts[part_names[state]] = current;
|
|
append_it = false;
|
|
current = "";
|
|
state = 3;
|
|
expect = '/';
|
|
}
|
|
break;
|
|
case(3): // path
|
|
if(c == '/' && current == "")
|
|
{
|
|
append_it = false;
|
|
break;
|
|
}
|
|
if(c == '?')
|
|
{
|
|
result.parts[part_names[state]] = current;
|
|
append_it = false;
|
|
current = "";
|
|
state = 4;
|
|
}
|
|
break;
|
|
case(4): // query
|
|
if(c == '#')
|
|
{
|
|
result.parts[part_names[state]] = current;
|
|
append_it = false;
|
|
current = "";
|
|
state = 5;
|
|
}
|
|
break;
|
|
}
|
|
|
|
if(append_it)
|
|
current.append(1, c);
|
|
}
|
|
|
|
result.parts[part_names[state]] = current;
|
|
|
|
result.query = parse_query(result.parts["query"]);
|
|
|
|
return(result);
|
|
}
|
|
|
|
void set_cookie(
|
|
String name, String value,
|
|
u64 expires, String path, String domain,
|
|
bool secure, bool http_only)
|
|
{
|
|
String cookie = "Set-Cookie: ";
|
|
cookie.append(uri_encode(name) + "=" + uri_encode(value));
|
|
if(expires > 0)
|
|
cookie.append(String("; Expires=") + gmdate("RFC1123", expires));
|
|
context->set_cookies.push_back(cookie);
|
|
context->cookies[name] = value;
|
|
}
|
|
|
|
StringMap parse_cookies(String cookie_String)
|
|
{
|
|
StringMap result;
|
|
while(cookie_String.length() > 0)
|
|
{
|
|
String key = trim(nibble("=", cookie_String));
|
|
String value = nibble(";", cookie_String);
|
|
result[key] = value;
|
|
}
|
|
return(result);
|
|
}
|
|
|
|
String make_session_id()
|
|
{
|
|
return(to_hex(rand())+to_hex(rand())+to_hex(rand())+to_hex(rand()));
|
|
}
|
|
|
|
StringMap load_session_data(String session_id)
|
|
{
|
|
return(parse_query(file_get_contents(context->server->config.SESSION_PATH + "/" + session_id)));
|
|
}
|
|
|
|
void save_session_data(String session_id, StringMap data)
|
|
{
|
|
file_put_contents(context->server->config.SESSION_PATH + "/" + session_id, encode_query(data));
|
|
}
|
|
|
|
String session_start(String session_name)
|
|
{
|
|
if(context->cookies[session_name].length() == 0)
|
|
{
|
|
set_cookie(session_name, make_session_id(), time() + context->server->config.SESSION_TIME);
|
|
}
|
|
context->session_id = context->cookies[session_name];
|
|
context->session_name = session_name;
|
|
context->session = load_session_data(context->session_id);
|
|
return(context->session_id);
|
|
}
|
|
|
|
void session_destroy(String session_name)
|
|
{
|
|
if(context->cookies[session_name].length() > 0)
|
|
{
|
|
set_cookie(session_name, "", time() - context->server->config.SESSION_TIME);
|
|
context->session.clear();
|
|
save_session_data(context->session_id, context->session);
|
|
context->session_id = "";
|
|
}
|
|
}
|