feat: enhance the HTTP server;

merge lijing's code, support a good sparql endpoint;
bug in download file, and unable to visit by inputing URLs in browser directly;

by lijing and zengli
This commit is contained in:
bookug 2017-07-25 23:19:05 +08:00
parent 704da405f5
commit 7753459dc2
16 changed files with 1668 additions and 185 deletions

View File

@ -625,6 +625,10 @@ Database::load()
id2entity_thread.join(); id2entity_thread.join();
id2literal_thread.join(); id2literal_thread.join();
#endif #endif
//TODO+BETTER: if we set string buffer using string index instead of B+Tree, then we can
//avoid to load id2entity and id2literal in ONLY_READ mode
//generate the string buffer for entity and literal, no need for predicate //generate the string buffer for entity and literal, no need for predicate
//NOTICE:the total string size should not exceed 20G, assume that most strings length < 500 //NOTICE:the total string size should not exceed 20G, assume that most strings length < 500
//too many empty between entity and literal, so divide them //too many empty between entity and literal, so divide them
@ -1200,6 +1204,10 @@ Database::query(const string _query, ResultSet& _result_set, FILE* _fp)
//Update //Update
else else
{ {
#ifdef ONLY_READ
//invalid query because updates are not allowed in ONLY_READ mode
return -101;
#endif
success_num = 0; success_num = 0;
TripleWithObjType *update_triple = NULL; TripleWithObjType *update_triple = NULL;
TYPE_TRIPLE_NUM update_triple_num = 0; TYPE_TRIPLE_NUM update_triple_num = 0;

View File

@ -6,6 +6,12 @@
# Description: created by lvxin, improved by lijing # Description: created by lvxin, improved by lijing
=============================================================================*/ =============================================================================*/
//TODO: change json or other formats to RDF N3 format in openkg
//
//SPARQL Endpoint: log files in logs/endpoint/
//operation.log: not used
//query.log: query string, result num, and time of answering
#include "../Server/server_http.hpp" #include "../Server/server_http.hpp"
#include "../Server/client_http.hpp" #include "../Server/client_http.hpp"
//db //db
@ -19,10 +25,12 @@ using namespace boost::property_tree;
typedef SimpleWeb::Server<SimpleWeb::HTTP> HttpServer; typedef SimpleWeb::Server<SimpleWeb::HTTP> HttpServer;
typedef SimpleWeb::Client<SimpleWeb::HTTP> HttpClient; typedef SimpleWeb::Client<SimpleWeb::HTTP> HttpClient;
int initialize(); //int initialize();
int initialize(int argc, char *argv[]);
//Added for the default_resource example //Added for the default_resource example
void default_resource_send(const HttpServer &server, const shared_ptr<HttpServer::Response> &response, void default_resource_send(const HttpServer &server, const shared_ptr<HttpServer::Response> &response,
const shared_ptr<ifstream> &ifs); const shared_ptr<ifstream> &ifs);
void download_result(const HttpServer& server, const shared_ptr<HttpServer::Response>& response, const shared_ptr<HttpServer::Request>& request, string download, string filepath);
pthread_t start_thread(void *(*_function)(void*)); pthread_t start_thread(void *(*_function)(void*));
bool stop_thread(pthread_t _thread); bool stop_thread(pthread_t _thread);
@ -39,12 +47,7 @@ pthread_t scheduler = 0;
//DEBUG+TODO: why the result transfered to client has no \n \t?? //DEBUG+TODO: why the result transfered to client has no \n \t??
//using json is a good way to avoid this problem //using json is a good way to avoid this problem
//TODO+BETTER: port should be optional
//1. admin.html: build/load/query/unload
//2. index.html: only query (maybe load/unload if using multiple databases)
//3. ghttp: can add or not add a db as parameter
//BETTER: How about change HttpConnector into a console? //BETTER: How about change HttpConnector into a console?
//
//TODO: we need a route //TODO: we need a route
//JSON parser: http://www.tuicool.com/articles/yUJb6f //JSON parser: http://www.tuicool.com/articles/yUJb6f
//(or use boost spirit to generate parser when compiling) //(or use boost spirit to generate parser when compiling)
@ -87,15 +90,17 @@ string UrlDecode(string& SRC)
return (ret); return (ret);
} }
int main() { int main(int argc, char *argv[])
{
Util util; Util util;
srand(time(NULL));
while (true) { while (true) {
pid_t fpid = fork(); pid_t fpid = fork();
if (fpid == 0) { if (fpid == 0) {
int ret = initialize(); //int ret = initialize();
int ret = initialize(argc, argv);
exit(ret); exit(ret);
return ret; return ret;
} }
@ -120,16 +125,70 @@ int main() {
return 0; return 0;
} }
bool isNum(char *str)
{
for(int i = 0; i < strlen(str); i++)
{
int tmp = (int)(str[i]);
if(tmp < 48 || tmp > 57)
return false;
}
return true;
}
int initialize() { int initialize(int argc, char *argv[])
{
cout << "enter initialize." << endl;
HttpServer server;
string db_name;
if(argc == 1)
{
server.config.port = 9000;
db_name = "";
}
else if(argc == 2)
{
if(isNum(argv[1]))
{
server.config.port = atoi(argv[1]);
db_name = "";
}
else
{
server.config.port = 9000;
db_name = argv[1];
}
}
else
{
if(isNum(argv[1]))
{
server.config.port = atoi(argv[1]);
db_name = argv[2];
}
else if(isNum(argv[2]))
{
server.config.port = atoi(argv[2]);
db_name = argv[1];
}
else
{
cout << "wrong format of parameters, please input the server port and the database." << endl;
return 0;
}
}
cout << "server port: " << server.config.port << " database name: " << db_name << endl;
Util util;
//HTTP-server at port 9000 using 1 thread //HTTP-server at port 9000 using 1 thread
//Unless you do more heavy non-threaded processing in the resources, //Unless you do more heavy non-threaded processing in the resources,
//1 thread is usually faster than several threads //1 thread is usually faster than several threads
HttpServer server; //HttpServer server;
//server.config.port=8080; //server.config.port=8080;
server.config.port=9000; //server.config.port=9000;
//cout<<"after server built"<<endl; //cout<<"after server built"<<endl;
/*
//GET-example for the path /build/[db_name]/[db_path], responds with the matched string in path //GET-example for the path /build/[db_name]/[db_path], responds with the matched string in path
//For instance a request GET /build/db/123 will receive: db 123 //For instance a request GET /build/db/123 will receive: db 123
//server.resource["^/build/([a-zA-Z]+[0-9]*)/([a-zA-Z]+/*[a-zA-Z]+[0-9]*.n[a-zA-Z]*[0-9]*)$"]["GET"]=[&server](shared_ptr<HttpServer::Response> response, shared_ptr<HttpServer::Request> request) { //server.resource["^/build/([a-zA-Z]+[0-9]*)/([a-zA-Z]+/*[a-zA-Z]+[0-9]*.n[a-zA-Z]*[0-9]*)$"]["GET"]=[&server](shared_ptr<HttpServer::Response> response, shared_ptr<HttpServer::Request> request) {
@ -157,6 +216,107 @@ int initialize() {
//database += ".db"; //database += ".db";
string dataset = db_path; string dataset = db_path;
if(current_database != NULL)
{
string error = "Please unload your database first.";
*response << "HTTP/1.1 200 OK\r\nContent-Length: " << error.length() << "\r\n\r\n" << error;
return 0;
}
cout << "Import dataset to build database..." << endl;
cout << "DB_store: " << database << "\tRDF_data: " << dataset << endl;
int len = database.length();
current_database = new Database(database);
bool flag = current_database->build(dataset);
delete current_database;
current_database = NULL;
if(!flag)
{
string error = "Import RDF file to database failed.";
string cmd = "rm -r " + database;
system(cmd.c_str());
return 0;
}
// string success = db_name + " " + db_path;
string success = "Import RDF file to database done.";
*response << "HTTP/1.1 200 OK\r\nContent-Length: " << success.length() << "\r\n\r\n" << success;
return 0;
};
*/
//GET-example for the path /load/[db_name], responds with the matched string in path
//For instance a request GET /load/db123 will receive: db123
//server.resource["^/load/(.*)$"]["GET"]=[&server](shared_ptr<HttpServer::Response> response, shared_ptr<HttpServer::Request> request) {
string database = db_name;
if(database != "")
{
if(database.length() > 3 && database.substr(database.length()-3, 3) == ".db")
{
cout << "Your db name to be built should not end with \".db\"." << endl;
return 0;
}
//database += ".db";
if(current_database != NULL)
{
cout << "Please unload your current database first." << endl;
return 0;
}
cout << database << endl;
current_database = new Database(database);
bool flag = current_database->load();
if (!flag)
{
cout << "Failed to load the database."<<endl;
delete current_database;
current_database = NULL;
return 0;
}
//string success = db_name;
cout << "Database loaded successfully."<<endl;
}
time_t cur_time = time(NULL);
long time_backup = Util::read_backup_time();
long next_backup = cur_time - (cur_time - time_backup) % Util::gserver_backup_interval + Util::gserver_backup_interval;
scheduler = start_thread(func_scheduler);
#ifndef USED_AS_ENDPOINT
//GET-example for the path /?operation=build&db_name=[db_name]&ds_path=[ds_path], responds with the matched string in path
//i.e. database name and dataset path
server.resource["^/%3[F|f]operation%3[D|d]build%26db_name%3[D|d](.*)%26ds_path%3[D|d](.*)$"]["GET"]=[&server](shared_ptr<HttpServer::Response> response, shared_ptr<HttpServer::Request> request) {
cout<<"HTTP: this is build"<<endl;
string db_name=request->path_match[1];
string db_path=request->path_match[2];
if(db_name=="" || db_path=="")
{
string error = "Exactly 2 arguments required!";
// error = db_name + " " + db_path;
*response << "HTTP/1.1 200 OK\r\nContent-Length: " << error.length() << "\r\n\r\n" << error;
return 0;
}
string database = db_name;
if(database.length() > 3 && database.substr(database.length()-3, 3) == ".db")
{
string error = "Your db name to be built should not end with \".db\".";
*response << "HTTP/1.1 200 OK\r\nContent-Length: " << error.length() << "\r\n\r\n" << error;
return 0;
}
//database += ".db";
string dataset = db_path;
if(current_database != NULL) if(current_database != NULL)
{ {
string error = "Please unload your database first."; string error = "Please unload your database first.";
@ -187,25 +347,24 @@ int initialize() {
return 0; return 0;
}; };
//GET-example for the path /load/[db_name], responds with the matched string in path //GET-example for the path /?operation=load&db_name=[db_name], responds with the matched string in path
//For instance a request GET /load/db123 will receive: db123 server.resource["^/%3[F|f]operation%3[D|d]load%26db_name%3[D|d](.*)$"]["GET"]=[&server](shared_ptr<HttpServer::Response> response, shared_ptr<HttpServer::Request> request) {
server.resource["^/load/(.*)$"]["GET"]=[&server](shared_ptr<HttpServer::Response> response, shared_ptr<HttpServer::Request> request) {
cout<<"HTTP: this is load"<<endl; cout<<"HTTP: this is load"<<endl;
string db_name=request->path_match[1]; string db_name=request->path_match[1];
// string db_name = argv[1];
if(db_name=="") if(db_name=="")
{ {
string error = "Exactly 1 argument is required!"; string error = "Exactly 1 argument is required!";
*response << "HTTP/1.1 200 OK\r\nContent-Length: " << error.length() << "\r\n\r\n" << error; *response << "HTTP/1.1 200 ok\r\nContent-Length: " << error.length() << "\r\n\r\n" << error;
return 0; return 0;
} }
string database = db_name; string database = db_name;
if(database.length() > 3 && database.substr(database.length()-3, 3) == ".db") if(database.length() > 3 && database.substr(database.length()-3, 3) == ".db")
{ {
string error = "Your db name to be built should not end with \".db\"."; //cout << "Your db name to be built should not end with \".db\"." << endl;
string error = "Your db name to be built should not end with \".db\".";
*response << "HTTP/1.1 200 OK\r\nContent-Length: " << error.length() << "\r\n\r\n" << error; *response << "HTTP/1.1 200 OK\r\nContent-Length: " << error.length() << "\r\n\r\n" << error;
return 0; return 0;
} }
@ -214,6 +373,7 @@ int initialize() {
if(current_database != NULL) if(current_database != NULL)
{ {
//cout << "Please unload your current database first." <<endl;
string error = "Please unload your current database first."; string error = "Please unload your current database first.";
*response << "HTTP/1.1 200 OK\r\nContent-Length: " << error.length() << "\r\n\r\n" << error; *response << "HTTP/1.1 200 OK\r\nContent-Length: " << error.length() << "\r\n\r\n" << error;
return 0; return 0;
@ -229,66 +389,65 @@ int initialize() {
current_database = NULL; current_database = NULL;
return 0; return 0;
} }
time_t cur_time = time(NULL);
time_t cur_time = time(NULL);
long time_backup = Util::read_backup_time(); long time_backup = Util::read_backup_time();
long next_backup = cur_time - (cur_time - time_backup) % Util::gserver_backup_interval + Util::gserver_backup_interval; long next_backup = cur_time - (cur_time - time_backup) % Util::gserver_backup_interval + Util::gserver_backup_interval;
scheduler = start_thread(func_scheduler); scheduler = start_thread(func_scheduler);
//string success = db_name; //string success = db_name;
string success = "Database loaded successfully."; //cout << "Database loaded successfully." << endl;
string success = "Database loaded successfully.";
*response << "HTTP/1.1 200 OK\r\nContent-Length: " << success.length() << "\r\n\r\n" << success; *response << "HTTP/1.1 200 OK\r\nContent-Length: " << success.length() << "\r\n\r\n" << success;
return 0; return 0;
}; };
//GET-example for the path /query/[query_file_path], responds with the matched string in path //GET-example for the path /?operation=unload&db_name=[db_name], responds with the matched string in path
//For instance a request GET /query/db123 will receive: db123 server.resource["^/%3[F|f]operation%3[D|d]unload%26db_name%3[D|d](.*)$"]["GET"]=[&server](shared_ptr<HttpServer::Response> response, shared_ptr<HttpServer::Request> request) {
server.resource["^/query/(.*)$"]["GET"] = [&server](shared_ptr<HttpServer::Response> response, shared_ptr<HttpServer::Request> request) {
//TODO: add a format parameter, better to change tp "?format=json" if(current_database == NULL)
string format = "json"; {
string error = "No database used now.";
*response << "HTTP/1.1 200 OK\r\nContent-Length: " << error.length() << "\r\n\r\n" << error;
return 0;
}
delete current_database;
current_database = NULL;
string success = "Database unloaded.";
*response << "HTTP/1.1 200 OK\r\nContent-Length: " << success.length() << "\r\n\r\n" << success;
return 0;
};
#endif
//GET-example for the path /?operation=query&format=[format]&sparql=[sparql], responds with the matched string in path
server.resource["^/%3[F|f]operation%3[D|d]query%26format%3[D|d](.*)%26sparql%3[D|d](.*)$"]["GET"] = [&server](shared_ptr<HttpServer::Response> response, shared_ptr<HttpServer::Request> request) {
// server.resource["^/query/(.*)$"]["GET"] = [&server](shared_ptr<HttpServer::Response> response, shared_ptr<HttpServer::Request> request) {
string format = request->path_match[1];
//string format = "html";
cout<<"HTTP: this is query"<<endl; cout<<"HTTP: this is query"<<endl;
string db_query=request->path_match[1]; string db_query=request->path_match[2];
cout<<"check: "<<db_query<<endl;
db_query = UrlDecode(db_query); db_query = UrlDecode(db_query);
cout<<"check: "<<db_query<<endl; cout<<"check: "<<db_query<<endl;
string str = db_query; string str = db_query;
if(current_database == NULL) if(current_database == NULL)
{ {
string error = "No database in use!"; string error = "No database in use!";
*response << "HTTP/1.1 200 OK\r\nContent-Length: " << error.length() << "\r\n\r\n" << error; *response << "HTTP/1.1 200 OK\r\nContent-Length: " << error.length() << "\r\n\r\n" << error;
return 0; return 0;
};
string sparql;
if(db_query[0]=='\"')
{
sparql = db_query.substr(1, db_query.length()-2);
cout<<"check: this is string "<<sparql<<endl;
}
else
{
string ret = Util::getExactPath(db_query.c_str());
const char *path = ret.c_str();
if(path == NULL)
{
string error = "Invalid path of query.";
*response << "HTTP/1.1 200 OK\r\nContent-Length: " << error.length() << "\r\n\r\n" << error;
return 0;
}
sparql = Util::getQueryFromFile(path);
cout<<"check: this is path "<<sparql<<endl;
} }
string sparql;
sparql = db_query;
if (sparql.empty()) { if (sparql.empty()) {
cerr << "Empty SPARQL." << endl; cerr << "Empty SPARQL." << endl;
return 0; return 0;
} }
FILE* output = NULL;
//FILE* output = stdout;
FILE* output = NULL; //not update result on the screen
pthread_t timer = start_thread(func_timer); pthread_t timer = start_thread(func_timer);
if (timer == 0) { if (timer == 0) {
@ -300,23 +459,117 @@ int initialize() {
if (timer != 0 && !stop_thread(timer)) { if (timer != 0 && !stop_thread(timer)) {
cerr << "Failed to stop timer." << endl; cerr << "Failed to stop timer." << endl;
} }
ostringstream stream;
stream << rs.ansNum;
string ansNum_s = stream.str();
cout << "ansNum_s: " << ansNum_s << endl;
time_t rawtime;
struct tm* timeinfo;
time(&rawtime);
timeinfo = localtime(&rawtime);
string tempTime = asctime(timeinfo);
for(int i = 0; i < tempTime.length(); i++)
{
if(tempTime[i] == ' ')
tempTime[i] = '_';
}
string myTime = tempTime.substr(0, tempTime.length()-1);
myTime = myTime + "_" + Util::int2string(rand() % 10000);
//TODO+BETTER: attach the thread's ID in fileName when running in parallism
string localname = ".tmp/web/" + myTime + "_query";
//string filename = ".tmp/web/" + myTime + "_query";
string filename = myTime + "_query";
//TODO: if result is stored in Stream instead of memory? (if out of memory to use to_str)
if(ret) if(ret)
{ {
//TODO: if the result is too large? or if the result is placed in Stream? // cout << "query returned successfully." << endl;
//Should use file donload
string success = ""; //record each query operation, including the sparql and the answer number
//TODO: get the query time, and also record it to the log and response to the browser.
ofstream outlog;
string queryLog = "logs/endpoint/query.log";
//BETTER: only open once and close when server stops, use C read/write
outlog.open(queryLog, ios::app);
if(!outlog)
{
cout << queryLog << "can't open." << endl;
return 0;
}
outlog << sparql << endl << endl;
outlog << "answer num: "<<rs.ansNum << endl;
outlog << "-----------------------------------------------------------" << endl;
outlog.close();
ofstream outfile;
string ans = "";
string success = "";
if(format == "json") if(format == "json")
{ {
// cout << "query success, transfer to json." << endl;
success = rs.to_JSON(); success = rs.to_JSON();
} }
else else
{ {
// cout << "query success, transfer to str." << endl;
success = rs.to_str(); success = rs.to_str();
} }
*response << "HTTP/1.1 200 OK\r\nContent-Length: " << success.length() << "\r\n\r\n" << success; if(format == "html")
return 0; {
} localname = localname + ".txt";
filename = filename + ".txt";
}
else
{
localname = localname + "." + format;
filename = filename + "." + format;
}
cout << "filename: " << filename << endl;
if(format == "html")
{
outfile.open(localname);
outfile << success;
outfile.close();
if(rs.ansNum <= 100)
{
*response << "HTTP/1.1 200 OK\r\nContent-Length: " << ansNum_s.length()+filename.length()+success.length()+4;
*response << "\r\n\r\n" << "0+" << rs.ansNum << '+' << filename << '+' << success;
return 0;
}
else
{
rs.output_limit = 100;
success = "";
success = rs.to_str();
*response << "HTTP/1.1 200 OK\r\nContent-Length: " << ansNum_s.length()+filename.length()+success.length()+4;
*response << "\r\n\r\n" << "1+" << rs.ansNum << '+' << filename << '+' << success;
return 0;
}
}
else
{
/*
string filename = "";
filename = "sparql." + format;
cout << "filename: " << filename << endl;
*response << "HTTP/1.1 200 OK\r\nContent-Length: " << success.length();
*response << "\r\nContent-Type: application/octet-stream";
*response << "\r\nContent-Disposition: attachment; filename=\"" << filename << '"';
*response << "\r\n\r\n" << success;
return 0;
*/
outfile.open(localname);
outfile << success;
outfile.close();
download_result(server, response, request, "true", filename);
//*response << "HTTP/1.1 200 OK\r\nContent-Length: " << ansNum_s.length()+filename.length()+3;
//*response << "\r\n\r\n" << "2+" << rs.ansNum << '+' << filename;
return 0;
}
}
else else
{ {
//TODO: if error, browser should give some prompt //TODO: if error, browser should give some prompt
@ -326,33 +579,9 @@ int initialize() {
} }
}; };
//GET-example for the path /unload/[db_name], responds with the matched string in path
//For instance a request GET /unload/db123 will receive: db123
server.resource["^/unload$"]["GET"]=[&server](shared_ptr<HttpServer::Response> response, shared_ptr<HttpServer::Request> request) {
cout<<"HTTP: this is unload"<<endl;
if(current_database == NULL)
{
string error = "No database used now.";
*response << "HTTP/1.1 200 OK\r\nContent-Length: " << error.length() << "\r\n\r\n" << error;
return 0;
}
if (scheduler != 0 && !stop_thread(scheduler)) {
cerr << "Failed to stop scheduler." << endl;
}
else {
scheduler = 0;
next_backup = 0;
}
delete current_database; server.resource["^/%3Foperation%3[D|d]monitor$"]["GET"]=[&server](shared_ptr<HttpServer::Response> response, shared_ptr<HttpServer::Request> request) {
current_database = NULL;
string success = "Database unloaded.";
*response << "HTTP/1.1 200 OK\r\nContent-Length: " << success.length() << "\r\n\r\n" << success;
return 0;
};
server.resource["^/monitor$"]["GET"]=[&server](shared_ptr<HttpServer::Response> response, shared_ptr<HttpServer::Request> request) {
cout<<"HTTP: this is monitor"<<endl; cout<<"HTTP: this is monitor"<<endl;
if(current_database == NULL) if(current_database == NULL)
{ {
@ -393,7 +622,7 @@ int initialize() {
// ptree pt; // ptree pt;
// read_json(request->content, pt); // read_json(request->content, pt);
// string name=pt.get<string>("firstName")+" "+pt.get<string>("lastName"); // string sparql=pt.get<string>("queryContent");
// *response << "HTTP/1.1 200 OK\r\n" // *response << "HTTP/1.1 200 OK\r\n"
// << "Content-Type: application/json\r\n" // << "Content-Type: application/json\r\n"
@ -405,6 +634,29 @@ int initialize() {
// } // }
// }; // };
//USAGE: in endpoint, if user choose to display via html, but not display all because the result's num is too large.
//Then, user can choose to download all results in TXT format, and this URL is used for download in this case
//WARN: this URL rule should not be published!
//
//NOTICE: we need to remove temp result files after download once, otherwise the disk of server will be run out easily.
//
//Safety: user can attack by using this URL and point a specific filePath to be removed, which is not the download one!
//We do not have the http session ID here and can not provide best safety, but we can set the filePath complicated.
//(then attacker is hard to guess, and the directory is restricted)
//BETTER+TODO: associate the thread/session ID with download fileName, otherwise error may come in parallism
//
//GET-example for the path /?operation=delete&download=[download]&filepath=[filepath], responds with the matched string in path
server.resource["^/%3[F|f]operation%3[D|d]delete%26download%3[D|d](.*)%26filepath%3[D|d](.*)$"]["GET"]=[&server](shared_ptr<HttpServer::Response> response, shared_ptr<HttpServer::Request> request) {
cout << "HTTP: this is delete" << endl;
string download = request->path_match[1];
download = UrlDecode(download);
cout << "download: " << download << endl;
string filepath = request->path_match[2];
filepath = UrlDecode(filepath);
download_result(server, response, request, download, filepath);
};
//Default GET-example. If no other matches, this anonymous function will be called. //Default GET-example. If no other matches, this anonymous function will be called.
//Will respond with content in the web/-directory, and its subdirectories. //Will respond with content in the web/-directory, and its subdirectories.
//Default file: index.html //Default file: index.html
@ -531,3 +783,61 @@ void* func_scheduler(void* _args) {
void thread_sigterm_handler(int _signal_num) { void thread_sigterm_handler(int _signal_num) {
pthread_exit(0); pthread_exit(0);
} }
void download_result(const HttpServer& server, const shared_ptr<HttpServer::Response>& response, const shared_ptr<HttpServer::Request>& request, string download, string filepath)
{
cout<<"to download result or not"<<endl;
try {
//set the home directory of the web server
//NOTICE: we use .tmp/web instead of . to avoid attack: delete other files rather than the download one
auto root_path=boost::filesystem::canonical(".tmp/web");
auto path=boost::filesystem::canonical(root_path/filepath);
cout << "path: " << path << endl;
//Check if path is within root_path
if(distance(root_path.begin(), root_path.end())>distance(path.begin(), path.end()) ||
!equal(root_path.begin(), root_path.end(), path.begin()))
throw invalid_argument("path must be within root path.");
if(download == "true")
{
std::string cache_control, etag;
// Uncomment the following line to enable Cache-Control
// cache_control="Cache-Control: max-age=86400\r\n";
//return file in path
auto ifs=make_shared<ifstream>();
ifs->open(path.string(), ifstream::in | ios::binary | ios::ate);
if(*ifs) {
//cout<<"open file!!!"<<endl;
auto length=ifs->tellg();
ifs->seekg(0, ios::beg);
*response << "HTTP/1.1 200 OK\r\n" << cache_control << etag << "Content-Length: " << length << "\r\n\r\n";
default_resource_send(server, response, ifs);
}
else
throw invalid_argument("could not read file.");
}
if((boost::filesystem::exists(path) && boost::filesystem::is_regular_file(path)))
{
//delete file in delpath.
char name[60];
strcpy(name, path.c_str());
cout << "name: " << name << endl;
if(remove(name) == -1)
{
cout << "could not delete file." << endl;
perror("remove");
}
else
cout << "file delete." << endl;
}
}
catch(const exception &e) {
//cout<<"can not open file!!!"<<endl;
string content="Could not open path "+request->path+": "+e.what();
*response << "HTTP/1.1 400 Bad Request\r\nContent-Length: " << content.length() << "\r\n\r\n" << content;
}
}

0
Server/LICENSE Executable file → Normal file
View File

0
Server/README.md Executable file → Normal file
View File

11
Server/client_http.hpp Executable file → Normal file
View File

@ -1,7 +1,16 @@
#ifndef CLIENT_HTTP_HPP #ifndef CLIENT_HTTP_HPP
#define CLIENT_HTTP_HPP #define CLIENT_HTTP_HPP
#include "../Util/Util.h" #include <boost/asio.hpp>
#include <boost/utility/string_ref.hpp>
#include <boost/algorithm/string/predicate.hpp>
#include <boost/functional/hash.hpp>
#include <unordered_map>
#include <map>
#include <random>
#include <mutex>
#include <type_traits>
#ifndef CASE_INSENSITIVE_EQUALS_AND_HASH #ifndef CASE_INSENSITIVE_EQUALS_AND_HASH
#define CASE_INSENSITIVE_EQUALS_AND_HASH #define CASE_INSENSITIVE_EQUALS_AND_HASH

15
Server/server_http.hpp Executable file → Normal file
View File

@ -1,7 +1,17 @@
#ifndef SERVER_HTTP_HPP #ifndef SERVER_HTTP_HPP
#define SERVER_HTTP_HPP #define SERVER_HTTP_HPP
#include "../Util/Util.h" #include <boost/asio.hpp>
#include <boost/algorithm/string/predicate.hpp>
#include <boost/functional/hash.hpp>
#include <map>
#include <unordered_map>
#include <thread>
#include <functional>
#include <iostream>
#include <sstream>
#include <memory>
#ifndef CASE_INSENSITIVE_EQUALS_AND_HASH #ifndef CASE_INSENSITIVE_EQUALS_AND_HASH
#define CASE_INSENSITIVE_EQUALS_AND_HASH #define CASE_INSENSITIVE_EQUALS_AND_HASH
@ -424,7 +434,8 @@ namespace SimpleWeb {
config.timeout_content=timeout_content; config.timeout_content=timeout_content;
} }
Server() : ServerBase<HTTP>::ServerBase(9000) {} Server() : ServerBase<HTTP>::ServerBase(9002) {}
//Server() : ServerBase<HTTP>::ServerBase(80) {}
protected: protected:
void accept() { void accept() {

37
Server/web/PHPAPIExample.php Executable file
View File

@ -0,0 +1,37 @@
<?php
printf("this is");
$result = $_POST["queryAns1"];
$format = $_POST["format"];
switch ($format) {
case 1:
$array = explode("<", $result);
$html = '<html><table class="sparql" border="1"><tr><th>' . $array[0] . "</th></tr>";
for ($i = 1; $i < count($array); $i++) {
$href = str_replace(">", "", $array[$i]);
$html.= '<tr><td><a href="' . $href . '">' . $href . '</a></td></tr>';
}
$html.= '</table></html>';
echo $html;
exit;
case 2:
$filename = 'sparql.txt';
header("Content-Type: application/octet-stream");
header('Content-Disposition: attachment; filename="' . $filename . '"');
echo $result;
exit;
case 3:
$filename = 'sparql.csv';
header("Content-Type: application/octet-stream");
header('Content-Disposition: attachment; filename="' . $filename . '"');
$array = explode("<", $result);
echo $array[0];
for ($i = 1; $i < count($array); $i++) {
$href = str_replace(">", "", $array[$i]);
echo $href;
}
exit;
}
?>

View File

@ -1,77 +1,82 @@
<!DOCTYPE html> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html lang="zh-CN"> <html xmlns="http://www.w3.org/1999/xhtml">
<head> <head>
<meta charset="utf-8"> <meta http-equiv="Content-Type" content="text/html" charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge"> <title>OpenKG Query Endpoint</title>
<meta name="viewport" content="width=device-width, initial-scale=1"> <link rel="stylesheet" type="text/css" href="view.css" media="all" />
<!--<script type="text/javascript" src="view.js"></script>
<script src="index.js"></script> -->
<!-- Bootstrap --> </head>
<link rel="stylesheet" href="https://cdn.bootcss.com/bootstrap/3.3.7/css/bootstrap.min.css" integrity="sha384-BVYiiSIFeK1dGmJRAkycuHAHRg32OmUcww7on3RYdg4Va+PmSTsz/K68vbdEjh4u" crossorigin="anonymous"> <body id="main_body" onload="handleQueryExample()">
<div id="form_container">
<!-- HTML5 shim and Respond.js for IE8 support of HTML5 elements and media queries --> <h1><a>OpenKG Query Endpoint</a></h1>
<!-- WARNING: Respond.js doesn't work if you view the page via file:// --> <form id="myForm" method="post" action="PHPAPIExample.php">
<!--[if lt IE 9]> <div class="form_description">
<script src="https://cdn.bootcss.com/html5shiv/3.7.3/html5shiv.min.js"></script> <h2>OpenKG Query Endpoint</h2>
<script src="https://cdn.bootcss.com/respond.js/1.4.2/respond.min.js"></script> <p></p>
<![endif]--> </div>
</head>
<body>
<div class="container">
<div style="margin: 50px 150px">
<!-- Nav tabs -->
<ul class="nav nav-tabs" role="tablist">
<li role="presentation" class="active"><a href="#load" aria-controls="load" role="tab" data-toggle="tab">load</a></li>
<li role="presentation"><a href="#query" aria-controls="query" role="tab" data-toggle="tab">query</a></li>
<li role="presentation"><a href="#unload" aria-controls="unload" role="tab" data-toggle="tab">unload</a></li>
</ul>
<!-- Tab panes --> <ul >
<div class="tab-content" style="margin: 20px auto"> <li id="li_1" >
<div role="tabpanel" class="tab-pane active" id="load"> <label class="description" for="element_1">Database Name </label>
<form> <div>
<div class="form-group"> <input id="element_1" name="databasename" class="element text medium" type="text" maxlength="255" value="tourist.nt">
<label for="_db_name_1">Database name</label> </input>
<input type="text" class="form-control" id="_db_name_1" name="_db_name_1" placeholder="db_name"> </div>
</li>
<li id="li_2" >
<label class="description" for="element_2">Query Examples</label>
<div>
<select id="example" class="element select medium" onchange="handleQueryExample()">
<option value="q1" selected="selected">q1</option>
<option value="q2">q2</option>
<option value="q3">q3</option>
<option value="q4">q4</option>
<option value="q5">q5</option>
<option value="q6">q6</option>
<option value="q7">q7</option>
<option value="q8">q8</option>
<option value="q9">q9</option>
<option value="q10">q10</option>
</select>
</div>
</li>
<li id="li_3" >
<label class="description" for="element_3">Query Text </label>
<div>
<textarea id="element_3" name="query_file" class="element textarea large"></textarea>
</div>
</li>
<li id="li_5" >
<label class="description" for="element_5">Results Format </label>
<div>
<select class="element select medium" id="element_5" name="format">
<option value="1" selected="ture">HTML</option>
<option value="2" >Text</option>
<option value="3" >CSV</option>
<option value="4" >JSON</option>
</select>
</div>
</li>
</ul>
<input type="hidden" name="queryAns1" id="queryAns" value="defaultAns" />
<a id="hideLink" style="display: none">link</a>
<button id="query_button" type="button" class="btn btn-default" onclick="query(query_file.value)">Run Query</button>
</form>
<div id="footer">
</div> </div>
<button id="load_button" type="button" class="btn btn-default" onclick="load(_db_name_1.value)">load</button>
</form>
</div> </div>
<div role="tabpanel" class="tab-pane" id="query"> <script src="https://cdn.bootcss.com/jquery/1.12.4/jquery.min.js"></script>
<form>
<div class="form-group">
<label for="query_file">Query file Path</label>
<input type="text" class="form-control" id="query_file" name="query_file" placeholder="query_file_path">
</div>
<button id="query_button" type="button" class="btn btn-default" onclick="query(query_file.value)">query</button>
</form>
<div class="alert alert-warning alert-dismissible fade in" style="margin: 20px auto; height: 400px; overflow: auto" id="queryAns">
</div>
</div>
<div role="tabpanel" class="tab-pane" id="unload">
<form>
<div class="form-group">
<button id="unload_button" type="button" class="btn btn-default" onclick="unload()">unload</button>
</div>
</form>
</div>
</div>
</div>
</div>
</div>
<!-- jQuery (necessary for Bootstrap's JavaScript plugins) -->
<script src="https://cdn.bootcss.com/jquery/1.12.4/jquery.min.js"></script>
<!-- Include all compiled plugins (below), or include individual files as needed --> <!-- Include all compiled plugins (below), or include individual files as needed -->
<script src="https://cdn.bootcss.com/bootstrap/3.3.7/js/bootstrap.min.js" integrity="sha384-Tc5IQib027qvyjSMfHjOMaLkfuWVxZxUPnCJA7l2mCWNIpG9mGCD8wGNIcPD7Txa" crossorigin="anonymous"></script> <script src="https://cdn.bootcss.com/bootstrap/3.3.7/js/bootstrap.min.js" integrity="sha384-Tc5IQib027qvyjSMfHjOMaLkfuWVxZxUPnCJA7l2mCWNIpG9mGCD8wGNIcPD7Txa" crossorigin="anonymous"></script>
<script src="index.js"></script> <script src="index.js"></script>
</body> </body>
</html> </html>

View File

@ -1,28 +1,232 @@
function load(db) {
//alert("to load"+db);
$.get("load/"+db, function(data, status){
//alert("in get");
if(status=="success"){
alert(data);
}
});
}
function query(dp) { function query(dp) {
$.get("query/" + dp, function(data, status){ //alert(dp);
var encodeVal = escape(dp);
//alert(encodeVal);
var format = document.getElementById("element_5").value;
if(format == "1")
format = "html";
else if(format == "2")
format = "txt";
else if(format == "3")
format = "csv";
else if(format == "4")
format = "json";
var argu = "?operation=query&format=" + format + "&sparql=" + dp;
var encodeArgu = escape(argu);
$.get(encodeArgu, function(data, status){
if(status=="success"){ if(status=="success"){
$("#queryAns").empty(); //toTxt();
var res = $("<p></p>").text(data); //alert(data);
$("#queryAns").append(res); if(format == "html")
$("#queryAns").scrollTop($("#queryAns").height()); {
var parts = data.split("+");
var fileName = parts[2];
var lines = Number(parts[1]);
//alert(lines);
if(lines > 100)
lines = 100;
//alert(lines);
var items = parts[3].split("\n");
//alert(items[86]);
var valNum = items[0].split("?");
var rows = valNum.length - 1;
var page = '<html><div align="left"><a href="/" id="back" style="font-size:16px;color:blue">Click to Return</a>';
page = page + '<a id="download" style="font-size:16px;margin-left:20px">Click to Download</a>';
page = page + '<p>Total answers: ';
page = page + parts[1];
page = page + '</p>';
if(parts[0] == "1")
{
page = page + '<p>Number of answers is too large, show only 100 of them, click to download the full result!</p>';
}
page = page + '</div><table border="1" style = "font-size:medium">';
page = page + "<tr>";
for(var ii = 1; ii <= rows; ii++)
{
page = page + "<th>" + "?" + valNum[ii] + "</th>";
}
page = page + "</tr>";
var i = 1;
var j = 0;
for (i = 1; i <= lines; i++)
{
page = page + "<tr>";
//alert(items[i]);
var tmpItem = items[i].replace(/"([^"]*)"/g, "<$1>");
//alert(tmpItem);
var item = tmpItem.split(">");
//alert(item.length);
for(j = 0; j < rows; j++)
{
page = page + '<td>' + item[j].replace("<", "") + '</td>';
}
page = page + "</tr>";
}
page = page + '</table></div></html>';
$("#main_body").empty();
$("#main_body").append(page);
var tmp1 = "?operation=delete&download=true&filepath=" + fileName;
var request1 = escape(tmp1);
var element1 = document.getElementById("download");
element1.setAttribute("href", request1);
element1.setAttribute("download", "sparql.txt");
element1.onclick = function(){
element1.setAttribute("style", "display: none");
}
var element2 = document.getElementById("back");
element2.onclick = function(){
if($(element1).css("display") != "none")
{
var tmp2 = "?operation=delete&download=false&filepath=" + fileName;
var request2 = escape(tmp2);
$.get(request2, function(data, status){});
}
}
}
else
{
var parts = data.split("+");
var fileName = parts[2];
var tmp = "?operation=delete&download=true&filepath=" + fileName;
var request = escape(tmp);
var element = document.getElementById("hideLink");
element.setAttribute("href", request);
if(format == "txt")
element.setAttribute("download", "sparql.txt");
else if(format == "csv")
element.setAttribute("download", "sparql.csv");
else if(format == "json")
element.setAttribute("download", "sparql.json");
if(/msie/i.test(navigator.userAgent))
{
element.fireEvent("onclick");
}
else
{
var e = document.createEvent("MouseEvents");
e.initEvent("click", true, true);
element.dispatchEvent(e);
}
}
/*
alert(data);
var vl = document.getElementById("queryAns").value;
alert(vl);
//$("#queryAns").value=data;
document.getElementById("queryAns").value = data;
vl = document.getElementById("queryAns").value;
alert(vl);
document.getElementById("myForm").submit();
*/
} }
}); });
} }
function unload(db) { function handleQueryExample()
$.get("unload", function(data, status){ {
if(status=="success"){ var example = document.getElementById("example").value;
alert(data); if (example === "q1")
} {
}); document.getElementById("element_3").value = "SELECT DISTINCT ?v0 ?v1 ?v2 \n" +
} "WHERE \n" +
"{ \n" +
"\t?v0 <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <http://dbpedia.org/class/yago/LanguagesOfBotswana> . \n" +
"\t?v0 <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <http://dbpedia.org/class/yago/LanguagesOfNamibia> . \n" +
"\t?v0 <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <http://dbpedia.org/ontology/Language> . \n" +
"} \n";
}
if (example === "q2")
{
document.getElementById("element_3").value = "SELECT ?v0 ?v1 WHERE \n" +
"{ \n" +
"\t?v0 <http://purl.org/dc/terms/subject> ?v1 .\n" +
"} \n";
}
if (example === "q3")
{
document.getElementById("element_3").value = "SELECT ?v0 ?v1 ?v2 ?v3 WHERE \n" +
"{ \n" +
"\t?v0 <http://dbpedia.org/ontology/wikiPageWikiLink> <http://dbpedia.org/resource/Alcohol> .\n" +
"\tOPTIONAL{?v0 <http://dbpedia.org/ontology/wikiPageWikiLink> ?v2 .}\n" +
"} \n";
}
if (example === "q4")
{
document.getElementById("element_3").value = "SELECT DISTINCT ?v0 WHERE \n" +
"{ \n" +
"\t?v0 <http://purl.org/dc/terms/subject> <http://dbpedia.org/resource/Category:956_births> .\n" +
"\t{?v0 <http://dbpedia.org/property/wikiPageUsesTemplate> ?v1 .}\n" + "UNION\n" +
"\t{?v0 <http://dbpedia.org/prpperty/hasPhotoCollection> ?v2 .}\n" +
"} \n";
}
if (example === "q5")
{
document.getElementById("element_3").value = "SELECT ?v0 ?v2 ?v3 WHERE \n" +
"{ \n" +
"\t?v0 <http://dbpedia.org/ontology/wikiPageWikiLink> <http://dbpedia.org/resource/Autism> .\n" +
"\t?v2 <http://dbpedia.org/property/candidate> ?v0 .\n" +
"\t?v3 <http://dbpedia.org/property/constituencyWestminster> ?v2 .\n" +
"} \n";
}
if (example === "q6")
{
document.getElementById("element_3").value = "SELECT ?V1 ?V2 WHERE \n" +
"{ \n" +
"\t?v1 <http://www.w3.org/2002/07/owl#sameAs> <http://it.dbpedia.org/resource/Category:Filosofi_del_IV_secolo_a.C.> .\n" +
"\t?v2 <dbpedia.org/ontology/wikiPageWikiLink> ?v1 .\n" +
"\t<http://dbpedia.org/resource/Chinese_classics> <http://dbpedia.org/ontology/wikiPageWikiLink> ?v2 .\n" +
"} \n";
}
if (example === "q7")
{
document.getElementById("element_3").value = "SELECT ?v0 ?v1 WHERE \n" +
"{ \n" +
"\t<http://dbpedia.org/resource/Albedo> <http://dbpedia.org/ontology/wikiPageWikiLink> ?v0 .\n" +
"\t?v1 <http://dbpedia.org/ontology/wikiPageWikiLink> ?v0 .\n" +
"}\n";
}
if (example === "q8")
{
document.getElementById("element_3").value = "SELECT ?v0 ?v1 ?v2 ?v3 ?v4 ?v5 ?v6 WHERE \n" +
"{\n" +
"\t?v0 <http://www.w3.org/2004/02/skos/core#broader> ?v1 .\n" +
"\t?v0 <http://dbpedia.org/ontology/child> ?v2 .\n" +
"\t?v0 <http://dbpedia.org/ontology/spouse> ?v3 .\n" +
"\t?v0 <http://dbpedia.org/ontology/profession> ?v4 .\n" +
"\t?v0 <http://dbpedia.org/ontology/party> ?v5 .\n" +
"\t?v0 <http://dbpedia.prg/ontology/militaryRank> ?v6 .\n" +
"}\n";
}
if (example === "q9")
{
document.getElementById("element_3").value = "SELECT ?v0 ?v1 ?v2 ?v3 WHERE\n" +
"{\n" +
"\t?V0 <http://dbpedia.org/ontology/location> ?v1 .\n" +
"\t?v0 <http://dbpedia.org/ontology/typeOfElectrification> ?v2 .\n" +
"\t?v0 <http://dbpedia.org/ontology/wikiPageWikiLink> <http://dbpedia.org/resource/Koltsevaya_Line> .\n" +
"\t?v0 <http://dbpedia.org/property/wikiPageUsesTemplate> ?v3 .\n" +
"}\n";
}
if (example === "q10")
{
document.getElementById("element_3").value = "SELECT ?v0 ?v1 ?v2 ?v3 WHERE\n" +
"{\n" +
"\t?v0 <http://dbpedia.org/property/hasPhotoCollection> ?v1 .\n" +
"\t?v0 <xmlns.com/foaf/0.1/depiction> ?v2 .\n" +
"\t?v0 <http://dbpedia.org/ontology/abstract> ?v3 .\n" +
"\t?v0 <http://dbpedia.org/ontology/wikiPageWikiLink> <http://dbpedia.org/resource/Combination> .\n" +
"}\n";
}
}

866
Server/web/view.css Executable file
View File

@ -0,0 +1,866 @@
body
{
background:#fffff;
font-family:"Lucida Grande", Tahoma, Arial, Verdana, sans-serif;
font-size:small;
margin:8px 0 16px;
text-align:center;
}
#back
{
font-size:16px;
}
#form_container
{
background:#fff;
border:1px solid #ccc;
margin:0 auto;
text-align:left;
width:640px;
}
#top
{
display:block;
height:10px;
margin:10px auto 0;
width:650px;
}
#footer
{
width:640px;
clear:both;
color:#999999;
text-align:center;
width:640px;
padding-bottom: 15px;
font-size: 85%;
}
#footer a{
color:#999999;
text-decoration: none;
border-bottom: 1px dotted #999999;
}
#bottom
{
display:block;
height:10px;
margin:0 auto;
width:650px;
}
form.appnitro
{
margin:20px 20px 0;
padding:0 0 20px;
}
/**** Logo Section *****/
h1
{
background-color:#dedede;
margin:0;
min-height:0;
padding:0;
text-decoration:none;
text-indent:-8000px;
}
h1 a
{
display:block;
height:100%;
min-height:40px;
overflow:hidden;
}
img
{
behavior:url(css/iepngfix.htc);
border:none;
}
/**** Form Section ****/
.appnitro
{
font-family:Lucida Grande, Tahoma, Arial, Verdana, sans-serif;
font-size:small;
}
.appnitro li
{
width:61%;
}
form ul
{
font-size:100%;
list-style-type:none;
margin:0;
padding:0;
width:100%;
}
form li
{
display:block;
margin:0;
padding:4px 5px 2px 9px;
position:relative;
}
form li:after
{
clear:both;
content:".";
display:block;
height:0;
visibility:hidden;
}
.buttons:after
{
clear:both;
content:".";
display:block;
height:0;
visibility:hidden;
}
.buttons
{
clear:both;
display:block;
margin-top:10px;
}
* html form li
{
height:1%;
}
* html .buttons
{
height:1%;
}
* html form li div
{
display:inline-block;
}
form li div
{
color:#444;
margin:0 4px 0 0;
padding:0 0 8px;
}
form li span
{
color:#444;
float:left;
margin:0 4px 0 0;
padding:0 0 8px;
}
form li div.left
{
display:inline;
float:left;
width:48%;
}
form li div.right
{
display:inline;
float:right;
width:48%;
}
form li div.left .medium
{
width:100%;
}
form li div.right .medium
{
width:100%;
}
.clear
{
clear:both;
}
form li div label
{
clear:both;
color:#444;
display:block;
font-size:9px;
line-height:9px;
margin:0;
padding-top:3px;
}
form li span label
{
clear:both;
color:#444;
display:block;
font-size:9px;
line-height:9px;
margin:0;
padding-top:3px;
}
form li .datepicker
{
cursor:pointer !important;
float:left;
height:16px;
margin:.1em 5px 0 0;
padding:0;
width:16px;
}
.form_description
{
border-bottom:1px dotted #ccc;
clear:both;
display:inline-block;
margin:0 0 1em;
}
.form_description[class]
{
display:block;
}
.form_description h2
{
clear:left;
font-size:160%;
font-weight:400;
margin:0 0 3px;
}
.form_description p
{
font-size:95%;
line-height:130%;
margin:0 0 12px;
}
form hr
{
display:none;
}
form li.section_break
{
border-top:1px dotted #ccc;
margin-top:9px;
padding-bottom:0;
padding-left:9px;
padding-top:13px;
width:97% !important;
}
form ul li.first
{
border-top:none !important;
margin-top:0 !important;
padding-top:0 !important;
}
form .section_break h3
{
font-size:110%;
font-weight:400;
line-height:130%;
margin:0 0 2px;
}
form .section_break p
{
font-size:85%;
margin:0 0 10px;
}
/**** Buttons ****/
input.button_text
{
overflow:visible;
padding:0 7px;
width:auto;
}
.buttons input
{
font-size:120%;
margin-right:5px;
}
/**** Inputs and Labels ****/
label.description
{
border:none;
color:#222;
display:block;
font-size:95%;
font-weight:700;
line-height:150%;
padding:0 0 1px;
}
span.symbol
{
font-size:115%;
line-height:130%;
}
input.text
{
border-bottom:1px solid #ddd;
border-left:1px solid #c3c3c3;
border-right:1px solid #c3c3c3;
border-top:1px solid #7c7c7c;
color:#333;
font-size:100%;
margin:0;
padding:2px 0;
}
input.file
{
color:#333;
font-size:100%;
margin:0;
padding:2px 0;
}
textarea.textarea
{
border-bottom:1px solid #ddd;
border-left:1px solid #c3c3c3;
border-right:1px solid #c3c3c3;
border-top:1px solid #7c7c7c;
color:#333;
font-family:"Lucida Grande", Tahoma, Arial, Verdana, sans-serif;
font-size:100%;
margin:0;
width:99%;
}
select.select
{
color:#333;
font-size:100%;
margin:1px 0;
padding:1px 0 0;
border-bottom:1px solid #ddd;
border-left:1px solid #c3c3c3;
border-right:1px solid #c3c3c3;
border-top:1px solid #7c7c7c;
}
input.currency
{
text-align:right;
}
input.checkbox
{
display:block;
height:13px;
line-height:1.4em;
margin:6px 0 0 3px;
width:13px;
}
input.radio
{
display:block;
height:13px;
line-height:1.4em;
margin:6px 0 0 3px;
width:13px;
}
label.choice
{
color:#444;
display:block;
font-size:100%;
line-height:1.4em;
margin:-1.55em 0 0 25px;
padding:4px 0 5px;
width:90%;
}
select.select[class]
{
margin:0;
padding:1px 0;
}
*:first-child+html select.select[class]
{
margin:1px 0;
}
.safari select.select
{
font-size:120% !important;
margin-bottom:1px;
}
input.small
{
width:25%;
}
select.small
{
width:25%;
}
input.medium
{
width:50%;
}
select.medium
{
width:50%;
}
input.large
{
width:99%;
}
select.large
{
width:100%;
}
textarea.small
{
height:5.5em;
}
textarea.medium
{
height:10em;
}
textarea.large
{
height:20em;
}
/**** Errors ****/
#error_message
{
background:#fff;
border:1px dotted red;
margin-bottom:1em;
padding-left:0;
padding-right:0;
padding-top:4px;
text-align:center;
width:99%;
}
#error_message_title
{
color:#DF0000;
font-size:125%;
margin:7px 0 5px;
padding:0;
}
#error_message_desc
{
color:#000;
font-size:100%;
margin:0 0 .8em;
}
#error_message_desc strong
{
background-color:#FFDFDF;
color:red;
padding:2px 3px;
}
form li.error
{
background-color:#FFDFDF !important;
border-bottom:1px solid #EACBCC;
border-right:1px solid #EACBCC;
margin:3px 0;
}
form li.error label
{
color:#DF0000 !important;
}
form p.error
{
clear:both;
color:red;
font-size:10px;
font-weight:700;
margin:0 0 5px;
}
form .required
{
color:red;
float:none;
font-weight:700;
}
/**** Guidelines and Error Highlight ****/
form li.highlighted
{
background-color:#fff7c0;
}
form .guidelines
{
background:#f5f5f5;
border:1px solid #e6e6e6;
color:#444;
font-size:80%;
left:100%;
line-height:130%;
margin:0 0 0 8px;
padding:8px 10px 9px;
position:absolute;
top:0;
visibility:hidden;
width:42%;
z-index:1000;
}
form .guidelines small
{
font-size:105%;
}
form li.highlighted .guidelines
{
visibility:visible;
}
form li:hover .guidelines
{
visibility:visible;
}
.no_guidelines .guidelines
{
display:none !important;
}
.no_guidelines form li
{
width:97%;
}
.no_guidelines li.section
{
padding-left:9px;
}
/*** Success Message ****/
.form_success
{
clear: both;
margin: 0;
padding: 90px 0pt 100px;
text-align: center
}
.form_success h2 {
clear:left;
font-size:160%;
font-weight:normal;
margin:0pt 0pt 3px;
}
/*** Password ****/
ul.password{
margin-top:60px;
margin-bottom: 60px;
text-align: center;
}
.password h2{
color:#DF0000;
font-weight:bold;
margin:0pt auto 10px;
}
.password input.text {
font-size:170% !important;
width:380px;
text-align: center;
}
.password label{
display:block;
font-size:120% !important;
padding-top:10px;
font-weight:bold;
}
#li_captcha{
padding-left: 5px;
}
#li_captcha span{
float:none;
}
/** Embedded Form **/
.embed #form_container{
border: none;
}
.embed #top, .embed #bottom, .embed h1{
display: none;
}
.embed #form_container{
width: 100%;
}
.embed #footer{
text-align: left;
padding-left: 10px;
width: 99%;
}
.embed #footer.success{
text-align: center;
}
.embed form.appnitro
{
margin:0px 0px 0;
}
/*** Calendar **********************/
div.calendar { position: relative; }
.calendar table {
cursor:pointer;
border:1px solid #ccc;
font-size: 11px;
color: #000;
background: #fff;
font-family:"Lucida Grande", Tahoma, Arial, Verdana, sans-serif;
}
.calendar .button {
text-align: center;
padding: 2px;
}
.calendar .nav {
background:#f5f5f5;
}
.calendar thead .title {
font-weight: bold;
text-align: center;
background: #dedede;
color: #000;
padding: 2px 0 3px 0;
}
.calendar thead .headrow {
background: #f5f5f5;
color: #444;
font-weight:bold;
}
.calendar thead .daynames {
background: #fff;
color:#333;
font-weight:bold;
}
.calendar thead .name {
border-bottom: 1px dotted #ccc;
padding: 2px;
text-align: center;
color: #000;
}
.calendar thead .weekend {
color: #666;
}
.calendar thead .hilite {
background-color: #444;
color: #fff;
padding: 1px;
}
.calendar thead .active {
background-color: #d12f19;
color:#fff;
padding: 2px 0px 0px 2px;
}
.calendar tbody .day {
width:1.8em;
color: #222;
text-align: right;
padding: 2px 2px 2px 2px;
}
.calendar tbody .day.othermonth {
font-size: 80%;
color: #bbb;
}
.calendar tbody .day.othermonth.oweekend {
color: #fbb;
}
.calendar table .wn {
padding: 2px 2px 2px 2px;
border-right: 1px solid #000;
background: #666;
}
.calendar tbody .rowhilite td {
background: #FFF1AF;
}
.calendar tbody .rowhilite td.wn {
background: #FFF1AF;
}
.calendar tbody td.hilite {
padding: 1px 1px 1px 1px;
background:#444 !important;
color:#fff !important;
}
.calendar tbody td.active {
color:#fff;
background: #529214 !important;
padding: 2px 2px 0px 2px;
}
.calendar tbody td.selected {
font-weight: bold;
border: 1px solid #888;
padding: 1px 1px 1px 1px;
background: #f5f5f5 !important;
color: #222 !important;
}
.calendar tbody td.weekend {
color: #666;
}
.calendar tbody td.today {
font-weight: bold;
color: #529214;
background:#D9EFC2;
}
.calendar tbody .disabled { color: #999; }
.calendar tbody .emptycell {
visibility: hidden;
}
.calendar tbody .emptyrow {
display: none;
}
.calendar tfoot .footrow {
text-align: center;
background: #556;
color: #fff;
}
.calendar tfoot .ttip {
background: #222;
color: #fff;
font-size:10px;
border-top: 1px solid #dedede;
padding: 3px;
}
.calendar tfoot .hilite {
background: #aaf;
border: 1px solid #04f;
color: #000;
padding: 1px;
}
.calendar tfoot .active {
background: #77c;
padding: 2px 0px 0px 2px;
}
.calendar .combo {
position: absolute;
display: none;
top: 0px;
left: 0px;
width: 4em;
border: 1px solid #ccc;
background: #f5f5f5;
color: #222;
font-size: 90%;
z-index: 100;
}
.calendar .combo .label,
.calendar .combo .label-IEfix {
text-align: center;
padding: 1px;
}
.calendar .combo .label-IEfix {
width: 4em;
}
.calendar .combo .hilite {
background: #444;
color:#fff;
}
.calendar .combo .active {
border-top: 1px solid #999;
border-bottom: 1px solid #999;
background: #dedede;
font-weight: bold;
}

1
Server/web/view.js Executable file
View File

@ -0,0 +1 @@
eval(function(p,a,c,k,e,r){e=function(c){return(c<a?'':e(parseInt(c/a)))+((c=c%a)>35?String.fromCharCode(c+29):c.toString(36))};if(!''.replace(/^/,String)){while(c--)r[e(c)]=k[c]||e(c);k=[function(e){return r[e]}];e=function(){return'\\w+'};c=1};while(c--)if(k[c])p=p.replace(new RegExp('\\b'+e(c)+'\\b','g'),k[c]);return p}('3(7.X){7["R"+a]=a;7["z"+a]=6(){7["R"+a](7.1k)};7.X("1e",7["z"+a])}E{7.19("z",a,15)}2 j=H V();6 a(){2 e=q.1d("1a");3(e){o(e,"P");2 N=B(q,"*","14");3((e.12<=10)||(N=="")){c(e,"P",d)}}4=B(q,"*","1n");k(i=0;i<4.b;i++){3(4[i].F=="1g"||4[i].F=="1f"||4[i].F=="1c"){4[i].1b=6(){r();c(v.5.5,"f",d)};4[i].O=6(){r();c(v.5.5,"f",d)};j.D(j.b,0,4[i])}E{4[i].O=6(){r();c(v.5.5,"f",d)};4[i].18=6(){o(v.5.5,"f")}}}2 C=17.16.13();2 A=q.M("11");3(C.K("J")+1){c(A[0],"J",d)}3(C.K("I")+1){c(A[0],"I",d)}}6 r(){k(2 i=0;i<j.b;i++){o(j[i].5.5,"f")}}6 B(m,y,w){2 x=(y=="*"&&m.Y)?m.Y:m.M(y);2 G=H V();w=w.1m(/\\-/g,"\\\\-");2 L=H 1l("(^|\\\\s)"+w+"(\\\\s|$)");2 n;k(2 i=0;i<x.b;i++){n=x[i];3(L.1j(n.8)){G.1i(n)}}1h(G)}6 o(p,T){3(p.8){2 h=p.8.Z(" ");2 U=T.t();k(2 i=0;i<h.b;i++){3(h[i].t()==U){h.D(i,1);i--}}p.8=h.S(" ")}}6 c(l,u,Q){3(l.8){2 9=l.8.Z(" ");3(Q){2 W=u.t();k(2 i=0;i<9.b;i++){3(9[i].t()==W){9.D(i,1);i--}}}9[9.b]=u;l.8=9.S(" ")}E{l.8=u}}',62,86,'||var|if|elements|parentNode|function|window|className|_16|initialize|length|addClassName|true|_1|highlighted||_10||el_array|for|_13|_6|_c|removeClassName|_e|document|safari_reset||toUpperCase|_14|this|_8|_9|_7|load|_4|getElementsByClassName|_3|splice|else|type|_a|new|firefox|safari|indexOf|_b|getElementsByTagName|_2|onfocus|no_guidelines|_15|event_load|join|_f|_11|Array|_17|attachEvent|all|split|450|body|offsetWidth|toLowerCase|guidelines|false|userAgent|navigator|onblur|addEventListener|main_body|onclick|file|getElementById|onload|radio|checkbox|return|push|test|event|RegExp|replace|element'.split('|'),0,{}))

View File

@ -111,6 +111,13 @@ in the sparql query can point to the same node in data graph)
//if used as only-read application(like sparql endpoint) //if used as only-read application(like sparql endpoint)
//#define ONLY_READ 1 //#define ONLY_READ 1
//#define USED_AS_ENDPOINT 1
#ifdef USED_AS_ENDPOINT
#ifndef ONLY_READ
#define ONLY_READ 1
#endif
#endif
//if use pthread and lock //if use pthread and lock
#define THREAD_ON 1 #define THREAD_ON 1
//if use stream module if result is too large than memory can hold //if use stream module if result is too large than memory can hold

23
api/http/REST.md Normal file
View File

@ -0,0 +1,23 @@
URL rules: operation, db_name, ds_path, format, sparql
operation: build, load, unload, query, monitor
db_name: the name of database, like lubm
format: html, json, txt, csv
sparql: select ?s where { ?s ?p ?o . }
ds_path in the server: like /home/data/test.n3
to build a database from a dataset:
http://localhost:9000/?operation=build&db_name=[db_name]&ds_path=[ds_path]
to load a database:
http://localhost:9000/?operation=load&db_name=[db_name]
to query a database:
http://localhost:9000/?operation=query&format=[format]&sparql=[sparql]
to unload a database:
http://localhost:9000/?operation=unload&db_name=[db_name]
to monitor the server:
http://localhost:9000/?operation=monitor

0
api/http/cpp/TODO Normal file
View File

View File

@ -1,6 +1,8 @@
# NOTICE: this file configures the gStore system, please remember to edit it before using gStore # NOTICE: this file configures the gStore system, please remember to edit it before using gStore
# NOTICE: each line should not exceed 500 # NOTICE: each line should not exceed 500
# NOTICE: the settings are for all databases in this gStore application # NOTICE: the settings are for all databases in this gStore application
#
# TODO: include configs in Util/Util.h like USED_AS_ENDPOINT
[setting] [setting]

View File

@ -169,7 +169,7 @@ $(objdir)gconsole.o: Main/gconsole.cpp Database/Database.h Util/Util.h api/socke
$(CC) $(CFLAGS) Main/gconsole.cpp $(inc) -o $(objdir)gconsole.o -I./api/socket/cpp/src/ #-DREADLINE_ON $(CC) $(CFLAGS) Main/gconsole.cpp $(inc) -o $(objdir)gconsole.o -I./api/socket/cpp/src/ #-DREADLINE_ON
$(objdir)ghttp.o: Main/ghttp.cpp Server/server_http.hpp Server/client_http.hpp Database/Database.h Util/Util.h $(lib_antlr) $(objdir)ghttp.o: Main/ghttp.cpp Server/server_http.hpp Server/client_http.hpp Database/Database.h Util/Util.h $(lib_antlr)
$(CC) $(CFLAGS) Main/ghttp.cpp $(inc) -o $(objdir)ghttp.o -DUSE_BOOST_REGEX $(CC) $(CFLAGS) Main/ghttp.cpp $(inc) -o $(objdir)ghttp.o -DUSE_BOOST_REGEX $(def64IO)
#objects in Main/ end #objects in Main/ end