分享一个嵌入式httpdserver开发库 - boahttpd library
http://sourceforge.net/projects/boahttpd/
一个C接口的开发库,适用于 windows/linux/或其它嵌入式平台,支持CGI扩展,支持多线程。採用面向对象开发,一个应用里能够同一时候开多个http server,仅仅要port不同就互不影响。主要应用场景应该是嵌入式应用(所谓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 过滤器 / 鉴权password认证
- Cookie support , Cookie支持
这个开发库体积较小,已经编译好了windows, linux(fedora14,x86)版本号的库。使用起来就是一个头文件、一个库文件。比方说以下几句话就完毕了一个简单的httpserver:
#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操作,传入主文件夹文件夹的位置,port号就能够了。在当前文件夹下创建一个wwwroot, 在wwwroot放一个index.html,执行程序试试吧。在浏览器里输入http://127.0.0.1:8888试着訪问一下。
上面是完毕一个普通的httpserver,能够浏览下载网页了。可是若要支持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 + 正文
须要铭记的是,此server是多线程的,每一个cgi请求都新开了一个线程处理,因此这个handler回调函数事实上是在各个线程里面被调用的。
注意这个userdata的使用,事实上是面向对象的一个设计方法。比方,你想封装一个httpserver对象:
//////////////// .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指定为this
boa_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++风格的回调,这样你能够有一个自己的server类了。
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.
分享一个嵌入式httpdserver开发库 - boahttpd library的更多相关文章
- C 封装一个通用链表 和 一个简单字符串开发库
引言 这里需要分享的是一个 简单字符串库和 链表的基库,代码也许用到特定技巧.有时候回想一下, 如果我读书的时候有人告诉我这些关于C开发的积淀, 那么会走的多直啊.刚参加工作的时候做桌面开发, 服务是 ...
- 【整站源码分享】分享一个JFinal3.4开发的整站源码,适合新手学习
分享这个源码是14年开发上线的<威海创业者>站点的全套整站源码,前后端都在一个包里.当时开发使用的是JFinal1.4,最近改成了JFinal3.4.使用的JSP做的页面.有一定的参考价值 ...
- 分享一个自研开发的QA自动化审计工具-Sonar检查
评价一个系统或软件的质量高低,我始终认为除了需求和设计外,代码质量很重要,一个高质量的系统或软件,并不是被测试出来的,更多的是要靠设计和开发出来的.目前也有很多自动化的测试工具,更多的是从功能和性能角 ...
- 分享一个Delphi跨平台Http库的封装,一个Delphi跨平台TCP库的封装
{ 单元名:跨平台的TCP客户端库封装 作者:5bug 网站:http://www.5bug.wang } unit uCPTcpClient; interface uses System.Class ...
- 分享一个js对象开发组件写法
var TextCount = (function(){ //私有方法,外面将访问不到 var _bind = function(that){ that.input.on('keyup',functi ...
- 分享一个WebGL开发的网站-用JavaScript + WebGL开发3D模型
这张图每位程序员应该都深有感触. 人民心目中的程序员是这样的:坐在电脑面前噼里啪啦敲着键盘,运键如飞. 现实中程序员是这样的:编码5分钟,调试两小时. 今天我要给大家分享一个用WebGL开发的网站,感 ...
- [资料搜集狂]D3.js数据可视化开发库
偶然看到一个强大的D3.js,存档之. D3.js 是近年来十分流行的一个数据可视化开发库. 采用BSD协议 源码:https://github.com/mbostock/d3 官网:http://d ...
- Git.Framework 框架随手记-- 分享一个"比较垃圾"的项目
本文主要分享一个Git.Framework 开发的一个项目的部分源码,此项目代码"比较垃圾",所以请各位码农,码畜,码神,码圣勿喷!发此文只为记录工作问题以及分享问题! 一. 项目 ...
- (原创)发布一个c++11开发的轻量级的并行Task库TaskCpp
TaskCpp简介 TaskCpp是c++11开发的一个跨平台的并行task库,它的设计思路来源于微软的并行计算库ppl和intel的并行计算库tbb,关于ppl和tbb我在前面有介绍.既然已经有了这 ...
随机推荐
- NSArray的4种遍历方式
前言:NSArray对应的是java的List,不同的是其元素不能更改,不过其派生类NSMutableArray可以更改,遍历的方式跟java的List基本一样 一. for循环 Student * ...
- Quiz 6a Question 7————An Introduction to Interactive Programming in Python
First, complete the following class definition: class BankAccount: def __init__(self, initial_bal ...
- TF-IDF算法-自动提取关键词汇
引子:Automatic Keyphrase extraction 很长文章里面,如何自动提取关键词汇呢? 比如在<中国的蜜蜂养殖>的长文里面,我们准备提取它的关键词.首先一个思路, 那些 ...
- asp.net 开发注意的几点
WIN7中组件服务中的DCOM配置找不到Microsoft Excel应用程序的解决办法: 这主要是64位系统的问题,excel是32位的组件,所以在正常的系统组件服务里是看不到的 可以通过在运行里面 ...
- Linux的五个查找命令find,locate,whereis,which,type
Linux的五个查找命令 1. find 最常见且最强大的命令,可以查找任何文件. 格式 $ find 指定目录 指定条件 指定动作 指定目录: 所要搜索的目录及其子目录,默认当前目录 ...
- java学习之内省
反射加内省解决耦合问题 package com.gh.introspector; /** * JavaBean * @author ganhang * */ public class Dog { pr ...
- 【C语言学习】存储类型
C语言中的存储类型主要有四种:auto.static.extern.register ★auto存储类型 默认的存储类型.在C语言中,假设忽略了变量的存储类型,那么编译器就会自己主动默认为auto型 ...
- Codeforces 360C Levko and Strings dp
题目链接:点击打开链接 题意: 给定长度为n的字符串s,常数k 显然s的子串一共同拥有 n(n-1)/2 个 要求找到一个长度为n的字符串t,使得t相应位置的k个子串字典序>s #include ...
- Javascript-one
今天,学习Javascript第一天,学习了一些基本的概念,下面就对今天所学的知识进行一个整理,回顾吧! 首先,将Javascript代码包含在(X)html文档中,主要的方法是使用<scrip ...
- 素数环(C - 暴力求解)
素数环(暴力)(紫书194页) Description A ring is composed of n (even number) circles as shown in diagram. Put ...