Http://sourceforge.net/projects/boahttpd/
A c-interface development library for Windows/Linux/or other embedded platforms. It supports CGI extension and multithreading. Using object-oriented development, a single application can open multiple HTTP servers at the same time, but it does not affect each other if the port is different. The main application scenario should be embedded applications (the so-called BOA-server concept), in the need for a basic web device management and use. In this example, we will show that, from page information submission, processing, to result return, we can combine jquery/Bootstrap web page technology to create a refined device management control page.
-Web file downloading
-CGI support, CGI support
-Multi-thread, multi-instance multi-thread, multi-instance
-Cross-platform (Windows, Linux, other embedded Linux) cross-platform support
-Filter & authentication support filter/authentication Password Authentication
-Cookie support: Cookie support
This development library is small and has compiled Windows and Linux (fedora14, x86) versions. It is a header file and a library file. Let's say the following sentence completes a simple 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;}
In fact, it is a simple create operation. input the location of the main folder and the port number. Create a wwwroot file in the current folder and put an index.html file in the wwwrootfile. Run the program. Enter http: // 127.0.0.1: 8888 in the browser and try to answer the question.
The above is an ordinary httpserver that can browse and download the web page. However, to support CGI processing, you must note some callback functions. Each CGI service has a unique name and a callback function. Of course, a callback function can be used to process all CGI services. The Demo code is as follows:
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;}
In the preceding example, several handler (namely callback) are defined first, and then all these Handler are added? In a boa_cgi_t object, you can submit the boa_cgi_t object to the server. During execution, after receiving the CGI request, the server finds the corresponding handler Based on the CGI service name.
For example, input CGI request: http: // 127.0.0.1: 8888/cgi/test? Name = someone
After the server receives the CGI request, it checks that the service name is test. Therefore, it checks whether the handler named "test" is specified in boa_cgi_t. If yes, it is called. In handler, you can obtain information about CGI requests, such as the number of workers "name = someone" and other field fields in the HTTP header. Assume that a POST request can obtain the body.
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);}
Two other functions are provided to reply to the CGI request.
Boa_cgi_send_error (context, status, reason); // error request, such as 404, "not found" boa_cgi_send_text (context, "text/JSON/html ", content_type_txt ); // 200 OK + body
It should be noted that this server is multi-threaded, and each CGI request has a new thread for processing. Therefore, this handler callback function is actually called in each thread.
Note that the use of this userdata is actually an object-oriented design method. For example, you want to encapsulate an httpserver object:
////////////////. 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); // specify userdata as thisboa_server_create (& server, & CGI, wwwroot ", 8888," 0.0.0.0 "); Return 0;} int myhttpd: handlecgirequest (void * context) {const char * service = boa_cgi_name (context );...}
Through the above conversion, a C-style callback is converted into a C ++-style callback, so that you can have your own server class.
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 essential. 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 wocould 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 shoshould 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 coshould 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:
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 wocould be like below. (See sample code 'compute ')
//// //. 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 'eas'
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 sends 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 mechanic 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 shocould 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 explain strate 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 cocould 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.