feat: add cpp example for http

This commit is contained in:
bookug 2017-06-15 23:33:24 +08:00
parent 670093e42a
commit 29505b6ec2
6 changed files with 308 additions and 0 deletions

View File

@ -31,9 +31,20 @@ int connection_num = 0;
//2. index.html: only query (maybe load/unload if using multiple databases) //2. index.html: only query (maybe load/unload if using multiple databases)
//3. ghttp: can add or not add a db as parameter //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)
//
//NOTICE: no need to close connection here due to the usage of shared_ptr
//http://www.tuicool.com/articles/3Ub2y2
//
//TODO: the URL format is terrible, i.e. 127.0.0.1:8080/build/lubm/data/LUBM_10.n3
//we should define some keys like operation, database, dataset, query, path ...
//127.0.0.1:8080?operation=build&database=lubm&dataset=data/LUBM_10.n3
//
//TODO: control the authority, check it if requesting for build/load/unload
//for sparql endpoint, just load database when starting, and comment out all functions except for query()
int main() { int main() {
Util util; Util util;
@ -50,6 +61,7 @@ int main() {
//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) {
// server.resource["^/build/([a-zA-Z0-9]+)/([a-zA-Z0-9]+)$"]["GET"]=[&server](shared_ptr<HttpServer::Response> response, shared_ptr<HttpServer::Request> request) { // server.resource["^/build/([a-zA-Z0-9]+)/([a-zA-Z0-9]+)$"]["GET"]=[&server](shared_ptr<HttpServer::Response> response, shared_ptr<HttpServer::Request> request) {
server.resource["^/build/([a-zA-Z0-9]*)/(.*)$"]["GET"]=[&server](shared_ptr<HttpServer::Response> response, shared_ptr<HttpServer::Request> request) { server.resource["^/build/([a-zA-Z0-9]*)/(.*)$"]["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_name=request->path_match[1];
string db_path=request->path_match[2]; string db_path=request->path_match[2];
if(db_name=="" || db_path=="") if(db_name=="" || db_path=="")
@ -104,6 +116,7 @@ int main() {
//GET-example for the path /load/[db_name], responds with the matched string in path //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 //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) { server.resource["^/load/(.*)$"]["GET"]=[&server](shared_ptr<HttpServer::Response> response, shared_ptr<HttpServer::Request> request) {
cout<<"HTTP: this is load"<<endl;
string db_name=request->path_match[1]; string db_name=request->path_match[1];
@ -154,6 +167,7 @@ int main() {
//GET-example for the path /query/[query_file_path], responds with the matched string in path //GET-example for the path /query/[query_file_path], responds with the matched string in path
//For instance a request GET /query/db123 will receive: db123 //For instance a request GET /query/db123 will receive: db123
server.resource["^/query/(.*)$"]["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) {
cout<<"HTTP: this is query"<<endl;
string db_query=request->path_match[1]; string db_query=request->path_match[1];
string str = db_query; string str = db_query;
@ -213,6 +227,7 @@ int main() {
//GET-example for the path /unload/[db_name], responds with the matched string in path //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 //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) { 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) if(current_database == NULL)
{ {
string error = "No database used now."; string error = "No database used now.";
@ -228,6 +243,7 @@ int main() {
}; };
server.resource["^/monitor$"]["GET"]=[&server](shared_ptr<HttpServer::Response> response, shared_ptr<HttpServer::Request> request) { server.resource["^/monitor$"]["GET"]=[&server](shared_ptr<HttpServer::Response> response, shared_ptr<HttpServer::Request> request) {
cout<<"HTTP: this is monitor"<<endl;
if(current_database == NULL) if(current_database == NULL)
{ {
string error = "No database used now."; string error = "No database used now.";
@ -284,6 +300,7 @@ int main() {
//Can for instance be used to retrieve an HTML 5 client that uses REST-resources on this server //Can for instance be used to retrieve an HTML 5 client that uses REST-resources on this server
server.default_resource["GET"]=[&server](shared_ptr<HttpServer::Response> response, shared_ptr<HttpServer::Request> request) { server.default_resource["GET"]=[&server](shared_ptr<HttpServer::Response> response, shared_ptr<HttpServer::Request> request) {
//BETTER: use lock to ensure thread safe //BETTER: use lock to ensure thread safe
cout<<"HTTP: this is default"<<endl;
connection_num++; connection_num++;
//NOTICE: it seems a visit will output twice times //NOTICE: it seems a visit will output twice times
//And different pages in a browser is viewed as two connections here //And different pages in a browser is viewed as two connections here

5
api/http/cpp/Makefile Normal file
View File

@ -0,0 +1,5 @@
example: example.cpp client.cpp client.h
g++ -o example example.cpp client.cpp -lcurl
clean:
rm *.o example

194
api/http/cpp/client.cpp Normal file
View File

@ -0,0 +1,194 @@
#include "client.h"
#include <curl/curl.h>
#include <string>
CHttpClient::CHttpClient(void) :
m_bDebug(false)
{
}
CHttpClient::~CHttpClient(void)
{
}
static int OnDebug(CURL *, curl_infotype itype, char * pData, size_t size, void *)
{
if(itype == CURLINFO_TEXT)
{
//printf("[TEXT]%s\n", pData);
}
else if(itype == CURLINFO_HEADER_IN)
{
printf("[HEADER_IN]%s\n", pData);
}
else if(itype == CURLINFO_HEADER_OUT)
{
printf("[HEADER_OUT]%s\n", pData);
}
else if(itype == CURLINFO_DATA_IN)
{
printf("[DATA_IN]%s\n", pData);
}
else if(itype == CURLINFO_DATA_OUT)
{
printf("[DATA_OUT]%s\n", pData);
}
return 0;
}
static size_t OnWriteData(void* buffer, size_t size, size_t nmemb, void* lpVoid)
{
std::string* str = dynamic_cast<std::string*>((std::string *)lpVoid);
if( NULL == str || NULL == buffer )
{
return -1;
}
char* pData = (char*)buffer;
str->append(pData, size * nmemb);
return nmemb;
}
int CHttpClient::Post(const std::string & strUrl, const std::string & strPost, std::string & strResponse)
{
strResponse.clear();
CURLcode res;
CURL* curl = curl_easy_init();
if(NULL == curl)
{
return CURLE_FAILED_INIT;
}
if(m_bDebug)
{
curl_easy_setopt(curl, CURLOPT_VERBOSE, 1);
curl_easy_setopt(curl, CURLOPT_DEBUGFUNCTION, OnDebug);
}
curl_easy_setopt(curl, CURLOPT_URL, strUrl.c_str());
curl_easy_setopt(curl, CURLOPT_POST, 1);
curl_easy_setopt(curl, CURLOPT_POSTFIELDS, strPost.c_str());
curl_easy_setopt(curl, CURLOPT_READFUNCTION, NULL);
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, OnWriteData);
curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void *)&strResponse);
curl_easy_setopt(curl, CURLOPT_NOSIGNAL, 1);
curl_easy_setopt(curl, CURLOPT_CONNECTTIMEOUT, 3);
curl_easy_setopt(curl, CURLOPT_TIMEOUT, 3);
res = curl_easy_perform(curl);
curl_easy_cleanup(curl);
return res;
}
int CHttpClient::Get(const std::string & strUrl, std::string & strResponse)
{
strResponse.clear();
CURLcode res;
CURL* curl = curl_easy_init();
if(NULL == curl)
{
return CURLE_FAILED_INIT;
}
if(m_bDebug)
{
curl_easy_setopt(curl, CURLOPT_VERBOSE, 1);
curl_easy_setopt(curl, CURLOPT_DEBUGFUNCTION, OnDebug);
}
curl_easy_setopt(curl, CURLOPT_URL, strUrl.c_str());
curl_easy_setopt(curl, CURLOPT_READFUNCTION, NULL);
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, OnWriteData);
curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void *)&strResponse);
/**
* 线使线sleep或是wait等操作
* libcurl将会发信号打断这个wait从而导致程序退出
*/
curl_easy_setopt(curl, CURLOPT_NOSIGNAL, 1);
curl_easy_setopt(curl, CURLOPT_CONNECTTIMEOUT, 3);
curl_easy_setopt(curl, CURLOPT_TIMEOUT, 3);
res = curl_easy_perform(curl);
curl_easy_cleanup(curl);
return res;
}
int CHttpClient::Posts(const std::string & strUrl, const std::string & strPost, std::string & strResponse, const char * pCaPath)
{
strResponse.clear();
CURLcode res;
CURL* curl = curl_easy_init();
if(NULL == curl)
{
return CURLE_FAILED_INIT;
}
if(m_bDebug)
{
curl_easy_setopt(curl, CURLOPT_VERBOSE, 1);
curl_easy_setopt(curl, CURLOPT_DEBUGFUNCTION, OnDebug);
}
curl_easy_setopt(curl, CURLOPT_URL, strUrl.c_str());
curl_easy_setopt(curl, CURLOPT_POST, 1);
curl_easy_setopt(curl, CURLOPT_POSTFIELDS, strPost.c_str());
curl_easy_setopt(curl, CURLOPT_READFUNCTION, NULL);
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, OnWriteData);
curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void *)&strResponse);
curl_easy_setopt(curl, CURLOPT_NOSIGNAL, 1);
if(NULL == pCaPath)
{
curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, false);
curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, false);
}
else
{
//缺省情况就是PEM所以无需设置另外支持DER
//curl_easy_setopt(curl,CURLOPT_SSLCERTTYPE,"PEM");
curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, true);
curl_easy_setopt(curl, CURLOPT_CAINFO, pCaPath);
}
curl_easy_setopt(curl, CURLOPT_CONNECTTIMEOUT, 3);
curl_easy_setopt(curl, CURLOPT_TIMEOUT, 3);
res = curl_easy_perform(curl);
curl_easy_cleanup(curl);
return res;
}
int CHttpClient::Gets(const std::string & strUrl, std::string & strResponse, const char * pCaPath)
{
strResponse.clear();
CURLcode res;
CURL* curl = curl_easy_init();
if(NULL == curl)
{
return CURLE_FAILED_INIT;
}
if(m_bDebug)
{
curl_easy_setopt(curl, CURLOPT_VERBOSE, 1);
curl_easy_setopt(curl, CURLOPT_DEBUGFUNCTION, OnDebug);
}
curl_easy_setopt(curl, CURLOPT_URL, strUrl.c_str());
curl_easy_setopt(curl, CURLOPT_READFUNCTION, NULL);
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, OnWriteData);
curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void *)&strResponse);
curl_easy_setopt(curl, CURLOPT_NOSIGNAL, 1);
if(NULL == pCaPath)
{
curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, false);
curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, false);
}
else
{
curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, true);
curl_easy_setopt(curl, CURLOPT_CAINFO, pCaPath);
}
curl_easy_setopt(curl, CURLOPT_CONNECTTIMEOUT, 3);
curl_easy_setopt(curl, CURLOPT_TIMEOUT, 3);
res = curl_easy_perform(curl);
curl_easy_cleanup(curl);
return res;
}
///////////////////////////////////////////////////////////////////////////////////////////////
void CHttpClient::SetDebug(bool bDebug)
{
m_bDebug = bDebug;
}

62
api/http/cpp/client.h Normal file
View File

@ -0,0 +1,62 @@
#ifndef __HTTP_CURL_H__
#define __HTTP_CURL_H__
//REFERENCE: https://curl.haxx.se/
//
//TODO: deal with cookie
//URL encode: http://www.ruanyifeng.com/blog/2010/02/url_encoding.html
#include <string>
class CHttpClient
{
public:
CHttpClient(void);
~CHttpClient(void);
public:
/**
* @brief HTTP POST请求
* @param strUrl ,Url地址,:http://www.baidu.com
* @param strPost ,使para1=val12=val2&
* @param strResponse ,
* @return Post成功
*/
int Post(const std::string & strUrl, const std::string & strPost, std::string & strResponse);
/**
* @brief HTTP GET请求
* @param strUrl ,Url地址,:http://www.baidu.com
* @param strResponse ,
* @return Post成功
*/
int Get(const std::string & strUrl, std::string & strResponse);
/**
* @brief HTTPS POST请求,
* @param strUrl ,Url地址,:https://www.alipay.com
* @param strPost ,使para1=val12=val2&
* @param strResponse ,
* @param pCaPath ,CA证书的路径.NULL,.
* @return Post成功
*/
int Posts(const std::string & strUrl, const std::string & strPost, std::string & strResponse, const char * pCaPath = NULL);
/**
* @brief HTTPS GET请求,
* @param strUrl ,Url地址,:https://www.alipay.com
* @param strResponse ,
* @param pCaPath ,CA证书的路径.NULL,.
* @return Post成功
*/
int Gets(const std::string & strUrl, std::string & strResponse, const char * pCaPath = NULL);
public:
void SetDebug(bool bDebug);
private:
bool m_bDebug;
};
#endif

BIN
api/http/cpp/example Executable file

Binary file not shown.

30
api/http/cpp/example.cpp Normal file
View File

@ -0,0 +1,30 @@
//NOTICE: you need to use libcurl-devel for C++ to use HTTP client, please read client.cpp and client.h seriously
#include <stdio.h>
#include <iostream>
#include <string>
#include "client.h"
using namespace std;
int main()
{
CHttpClient hc;
string res;
int ret;
//NOTICE: here no need to add admin.html
ret = hc.Get("127.0.0.1:8080/build/lubm/data/LUBM_10.n3", res);
cout<<res<<endl;
ret = hc.Get("127.0.0.1:8080/load/lubm", res);
cout<<res<<endl;
ret = hc.Get("127.0.0.1:8080/query/data/ex0.sql", res);
cout<<res<<endl;
ret = hc.Get("127.0.0.1:8080/monitor", res);
cout<<res<<endl;
ret = hc.Get("127.0.0.1:8080/unload", res);
cout<<res<<endl;
return 0;
}