分享一个嵌入式httpd服务器开发库 - boahttpd library
来源:互联网 发布:java怎么写url接口 编辑:程序博客网 时间:2024/05/09 06:06
http://sourceforge.net/projects/boahttpd/
一个C接口的开发库,适用于 windows/linux/或其他嵌入式平台,支持CGI扩展,支持多线程。采用面向对象开发,一个应用里可以同时开多个http server,只要端口不同就互不影响。主要应用场景应该是嵌入式应用(所谓boa-server的概念),在需要做一个基本web的设备管理使用。在例子中就是展示,从页面信息的提交、到处理、到结果的返回,里面结合jquery/bootstrap网页技术,可以作出一个精致的设备管理控制页面。
- Web file downloading 网页文件浏览
- CGI support , CGI支持
- Multi-thread, Multi-instance 多线程、多实例
- Cross-Platform (Windows, Linux, other Embedded Linux) 跨平台支持
- Filter & Authentication support 过滤器 / 鉴权密码认证
- Cookie support , Cookie支持
这个开发库体积较小,已经编译好了windows, linux(fedora14,x86)版本的库。使用起来就是一个头文件、一个库文件。比如说下面几句话就完成了一个简单的http服务器:
#include "../boahttpd.h"int main(){ boa_server_t server; if(boa_server_create(&server, NULL, "wwwroot", 8888, "0.0.0.0") < 0) { printf("failed to create server!\n"); return 0; } getchar(); boa_server_destroy(&server); return 0;}
其实就是一个简单的create操作,传入主目录文件夹的位置,端口号就可以了。在当前目录下创建一个wwwroot, 在wwwroot放一个index.html,运行程序试试吧。在浏览器里输入http://127.0.0.1:8888试着访问一下。
上面是完成一个普通的http服务器,可以浏览下载网页了。但是若要支持cgi的处理,则需要注册一些回调函数。每个cgi服务有一个唯一的名称,并对应一个回调函数。当然,可以用一个回调函数来处理所有的cgi服务。示范代码如下:
static int cgi_handler(void* context, void* userdata){ … handle the cgi request … return 0;}int main(){ boa_cgi_t cgi ; boa_cgi_create(&cgi); boa_cgi_register(&cgi, "test", &cgi_handler, NULL); boa_server_t server; if(boa_server_create(&server,&cgi, wwwroot", 8888, "0.0.0.0") < 0) { printf("failed to create server!\n"); return 0; } getchar(); boa_cgi_destroy(&cgi); boa_server_destroy(&server); return 0;}
上面是先定义若干个handler(即callback),然后把这些handler都添加一个boa_cgi_t对象里,然后把这个boa_cgi_t对象交给server即可。在运行的时候,server在接收到cgi请求后,会根据cgi服务的名称、找到相应的handler来处理。
比如,输入cgi请求: http://127.0.0.1:8888/cgi/test?name=someone
server收到此cgi请求后,检查到服务名称为test,于是检查boa_cgi_t里有没有注册了名称为"test"的handler,如果有的话就调用之。在handler里,可以获取cgi请求的相关信息,例如参数"name=someone"、以及HTTP头部的其他field字段。如果是个POST请求,可以获得正文。
static int cgi_handler(void* context, void* userdata){ const char* service = boa_cgi_name(context); const char* method = boa_cgi_method(context); const char* argument = boa_cgi_args(context); const char* content = boa_cgi_content(context); const char* anyfield = boa_cgi_field(context,”Content-Length”); int sock = boa_cgi_socket(context);}
另外提供了2个函数,用来对此cgi请求做出回复。
boa_cgi_send_error ( context, status, reason); // 错误请求,如404, "Not Found" boa_cgi_send_text(context, "正文text/json/html什么都可以", CONTENT_TYPE_TXT); // 200 OK + 正文
需要铭记的是,此服务器是多线程的,每个cgi请求都新开了一个线程处理,因此这个handler回调函数其实是在各个线程里面被调用的。
注意这个userdata的使用,其实是面向对象的一个设计方法。比如,你想封装一个http服务器对象:
//////////////// .h /////////////////////class MyHttpd{public:int Open(int port, const char* ip);void Close();int HandleCgiRequest(void* context);private: boa_cgi_t m_cgi;boa_server_t m_server;}///////////////////////////// *.cpp /////////////////////////////static int cgi_handler(void* context, void* userdata){MyHttpd* server = (MyHttpd*) userdata; server->HandleCgiRequest(context); return 0;}int MyHttpd::Open(int port, const char* ip){boa_cgi_create(&cgi);boa_cgi_register(&cgi, "test", &cgi_handler, this); //这里将userdata指定为thisboa_server_create(&server,&cgi, wwwroot", 8888, "0.0.0.0") ; return 0;}int int MyHttpd::HandleCgiRequest(void* context){ const char* service = boa_cgi_name(context);...}
通过上面的转换,把一个C风格的回调转成了C++风格的回调,这样你可以有一个自己的服务器类了。
boahttpd Library Development Manual
The library, boahttpd, is designed to create a cgi-featured http server (normally called as boa-server)easy and fast. That means you can easily add CGI support to your server application. It support file downloading by default, like any other web servers.
Its written in C++ inside, but provides a C-Style API which you will find it to be Object-Oriented essentially. Multiple platforms are supported with a uqique set of interface, including Windows, Linux, or Embedded systems. It will take a few minutes to get to know how to use it.
Features:
- Web file downloading
- CGI support
- Multi-thread, Multi-instance
- Cross-Platform (Windows, Linux, other Embedded Linux)
- Filter & Authentication support
- Cookie support
2. Getting Started
First you have to decide which platform your application is running on. For windows you have to take ‘ boahttpd.lib/.dll’ into your project, plus the header file ‘boahttpd.h’. For linux(x86), a release built under Fedora14 is provided , which will work correctly under those systems similar (I mean the kernel version ) to Fedora 14.
For embedded systems, such as linux (arm), your have to provide the specific toolchains and ask for a specific build for your target platform.
2.1 A ‘helloworld’ Application
A most simple usage of the library would be like this: (see sample code `ex1`)
#include <stdio.h>
#include <stdlib.h>
/* include boahttpd library */
#include "../boahttpd.h"
#pragma comment(lib, "../boahttpd.lib")
/* start a simple web server */
int main()
{
boa_server_t server;
if(boa_server_create(&server, NULL,
"wwwroot",
8888, "0.0.0.0",
NULL, NULL) < 0)
{
printf("failed to create server!\n");
return 0;
}
getchar();
boa_server_destroy(&server);
return 0;
}
The code above sets up a http server running on port 8888, and the root directory of web pages is ‘wwwroot’ folder which should be located on the current directory. So to make things right, your have to put some files in your ‘wwwroot’ folder, for example, a ‘index.html’ as the default home page.
Now run the program, then try the following url in your web browser:
http://127.0.0.1:8888
or
http://127.0.0.1:8888/image/abc.jpg
if there is a picture file located in that sub-directory: wwwroot/image/abc.jpg.
2.2 Easy CGI Application
Now we get to the key feature of the library: CGI support. It also easy to know and to use, see the following snippet : (see sample code `ex2`)
… … …
static int cgi_handler(void* context, void* userdata)
{
… handle the cgi request …
return 0;
}
int main()
{
boa_cgi_t cgi ;
boa_cgi_create(&cgi);
boa_cgi_register(&cgi, "test", &cgi_handler, NULL);
boa_server_t server;
if(boa_server_create(&server, &cgi,
"wwwroot", 8888, "0.0.0.0", NULL, NULL) < 0)
{
printf("failed to create server!\n");
return 0;
}
getchar();
boa_cgi_destroy(&cgi);
boa_server_destroy(&server);
return 0;
}
By register a callback function , cgi_handler, you could have the chance to handle the CGI request. A number of such callbacks can be register to the single boa_cgi_t object .
You can register a default handler for all request , whose name is `*`:
boa_cgi_register(&m_cgi, "*", &cgi_handler, this);
(Note: each CGI request is called in a NEW thread, thus the callback handler is called in that NEW thread)
Take the follow request as an example. When you type
http://127.0.0.1:8888/cgi/mytest?name=shaofa&height=175
in your browser, your httpd server will got a CGI request with:
Name Value Meaning
method GET The HTTP method, ‘GET’ or ‘POST’
service mytest The name of the CGI service
argument name=shaofa&height=175 The argument passed with the URL
content Vaild if the method is ‘POST’
HTTP FIELD Any other HTTP head field
Socket The socket handle
The following snippet shows how to retrieve those values:
static int cgi_handler(void* context, void* userdata)
{
const char* service = boa_cgi_name(context);
const char* method = boa_cgi_method(context);
const char* argument = boa_cgi_args(context);
const char* content = boa_cgi_content(context);
const char* anyfield = boa_cgi_field(context,”Content-Length”);
int sock = boa_cgi_socket(context);
}
If you want to reply an error message , just call:
boa_cgi_send_error ( context, status, reason);
If you want to reply an 200 OK message with a text content, just call:
boa_cgi_send_text(context, “……”, CONTENT_TYPE_TXT);
Keep in mind that the framework has already created a thread for each CGI request, you need not to create a thread yourself.
2.3 Advanced CGI Application
Now we are talking about how to use the API in C++ manner. Support we want to create a http server object, the sample code would be like below. (see sample code `complex`)
//////////////// .h /////////////////////
class MyHttpd
{
public:
int Open(int port, const char* ip);
void Close();
int HandleCgiRequest(void* context);
private:
boa_cgi_t m_cgi;
boa_server_t m_server;
}
///////////////////////////// *.cpp /////////////////////////////
static int cgi_handler(void* context, void* userdata)
{
MyHttpd* server = (MyHttpd*) userdata;
server->HandleCgiRequest(context);
return 0;
}
int MyHttpd::Open(int port, const char* ip)
{
boa_cgi_create(&cgi);
// set userdata to `this`
boa_cgi_register(&cgi, "test", &cgi_handler, this);
boa_server_create(&server,&cgi, "wwwroot",
8888, "0.0.0.0", NULL, NULL) ;
return 0;
}
int int MyHttpd::HandleCgiRequest(void* context)
{
const char* service = boa_cgi_name(context);
...
}
3. Form Request
This section is about how to deal with FORM request. For clear demonstration, a demo page is built like this:
When user clicked OK button after filling the Name and URL fields, a POST request is triggered (here jquery is used).
function onAddStream()
{
var request = $.ajax({
type: "POST",
url: "cgi/addStream",
data: {
name: $("#strName").val() ,
url: $("#strUrl").val()
}
});
request.done(function(reply) {
var errorCode = reply.errorCode;
if(errorCode == 0)
{
}
});
}
The .ajax call send a POST request the boahttpd server, with a content string whose format is like “field1=value1&field2=value2&…”. So in the cgi handler you have to parse the content and extract the fields. The sample code parses the field, and make a reply text with JSON format.
const char* service = boa_cgi_name(context);
const char* content = boa_cgi_content(context);
if(strcmp(service, "addStream") == 0)
{
string name, url;
// parse request:
Property props(content, "&", "=");
props.Get("name", name);
props.Get("url", url);
// make JSON reply
json::Object obj;
obj["errorCode"] = 0;
obj["name"] = name;
obj["url"] = url;
// reply
std::string replytext = json::Serialize(obj);
boa_cgi_send_text(context, replytext.c_str(),
"application/json");
}
4. Filter & Authentication
The filter mechanism is designed to support Session / Authentication , which is used to prevent illegal user access. After filter handler is setup for a boa_server_t, it will be called on each request before other handler (cgi handler or other inner handler).
4.1 Filter Handler
Firstly, define a handler,
static int filter_handler(void* context, void* userdata)
{
MyHttpd* server = (MyHttpd*) userdata;
server->OnFilter(context);
return 0;
}
Then register it to the server,
boa_server_create(&m_server ,
&m_cgi,
"wwwroot",
8888, "0.0.0.0",
filter_handler, this) ;
You have full privileges to decide if the request should be rejected (returns non-zero) or continue (returns zero). For example, you define all files located in /images/ are always accessible.
int MyHttpd::OnFilter(void* context)
{
const char* filepath = boa_cgi_path(context);
const char* uri = boa_cgi_uri(context);
// Allow: ALL files under /images/ can be accessed
if(strcmp(filepath, "/images/")==0)
return 0;
4.2 Authentication
Here I will give a sample to illustrate how to setup a simple authentication. Session based authentication is also be feasible with the sample approach.
Setup A /cgi/login Service
User opens a browser, comes to the login page, fills in the password, and presses submit. The service gets the requests and invokes the handler, which will in turn check the password, and, if correct, set a cookie.
if(strcmp(m_passwd, passwd.c_str()) == 0)
{
boa_cgi_set_cookie(context, "Authentication", passwd.c_str());
boa_cgi_send_redirect(context, "/index.html");
}
( Alternatively, you could returns a Session ID rather than the password)
Test In The Filter
Henceforth, the browser will send a Cookie field containing the password in its HTTP request. In the filter handler, you check this Cookie field, and test the password.
string cookie = boa_cgi_field(context, "Cookie");
printf("--------- cookie: %s \n", cookie.c_str());
// GET authentication
Property props(cookie.c_str(), "; ", "=");
string auth;
props.Get("Authentication", auth);
if(auth.compare(m_passwd) != 0)
{
// redirect to login page
boa_cgi_send_redirect(context, "/login.html");
return -1;
}
If no appropriate information (correct password or session id) is found in the cookie, the request will be redirected to the login page.
- 分享一个嵌入式httpd服务器开发库 - boahttpd library
- 自主开发微型HTTPD服务器
- 嵌入式开发服务器构架
- 嵌入式开发资料整理分享
- 分享嵌入式开发前景总结
- httpd 服务器在6410开发板上的移植
- 分享一些国外嵌入式开发的网站
- linux-arm-嵌入式开发:分享两个网址
- Android嵌入式驱动开发教程课程分享
- 嵌入式工程师经验分享:嵌入式开发这样来学习!
- 一个嵌入式开发的blog
- httpd-apache服务器配置
- 安装httpd服务器
- 手动安装httpd服务器
- 学习一个月web开发的成果,服务器C++,数据库postgresql简易的知识分享平台
- 分享 library 到 bintray jcenter代码库
- 开发一个SSO服务器
- 为嵌入式Linux开发开启samba服务器
- Junit 4 Tutorials(Junit 4 教程) 四、Junit4 参数化测试
- 研大考研:考研全日制辅导
- Android控件拾零
- 水山蹇
- snmpd.conf的基础配置
- 分享一个嵌入式httpd服务器开发库 - boahttpd library
- Kafka学习三:Flumeng+Kafka+Storm
- JS监听整个页面的回车事件
- 下载snooper请到www.microissuer.com
- [Java][log4j]支持同时按日期和文件大小分割日志
- grid嵌套html标签
- Ibatis基础标签
- Cocos2d-x屏幕适配之Sprite绘制原理
- ios uivew过渡动画 翻页效果