|
Introduction
Webio is a small-footprint web server, designed to be embedded in an application or an embedded system. It's useful when you want to implement a complex browser based GUI (which can be accessed by everything from PCs to cell phones) in a very efficient manner. Webio compiles and runs equally well under Linux and Windows, and should be easy to port to most other platforms. It comes with a programmer's manual (progman.html) which explains how to use it and how to port it.
Background
In 1996, I wrote one of the first web servers designed for embedded devices. In those days, most embedded devices had no file systems, so I created the "HTML compiler" to embed the files into the code image. Similarly, the lack of a file system led to C-language CGI functions.
Creating basic GUIs with this system was so easy that I started using it in Windows applications in preference to the Windows GUI. Back then, before JavaScript and CSS, it was somewhat limited - for example, it wouldn't make a very good "photo shop" type program - but for basic GUIs, it was great.
As my company started using Linux and Browser-enabled hand-held devices, a really huge advantage became obvious - my new applications worked everywhere, not just on Windows. The user was not tied on one OS or one type of device. They didn't even have to be near the machine running the application.
In 2007, I needed a similar server for an open-source project. I had left the previous company, which still retained the rights to the my old server. They wouldn't open source it, and nothing suitable was available in the public domain. I decided to create a second generation version of the server and release it under the BSD license so I would never have to write it again.
The result is Webio - my second (and hopefully last) embedded web server.
Using the code
The Windows version is probably of most interest to CodeProject readers, and so the .zip file is made available here. Follow these steps:
- Unzip it (preserving the directory structure).
- Type buildfs to compile the embedded file system.
- Open the project file with Visual C++ 6.0 or newer, and click Build.
You should get a little application which, when run, allows your PC to act as a web server - point a browser at it. You can do this in loopback by typing "http://127.1" in your browser's location bar.
Points of interest
Webio has a few improvements over my first embedded web server:
- The "HTML compiler" is now a full-fledged file system builder, designed from the group up to generate not only file images in your C code, but also generate code for C-language CGI.
- The server buffers all code-generated output, allowing accurate Content-Length fields on files with variable sized SSIs.
- A fast path for binary files improves performance.
- Portability across Windows/Linux/Embedded systems is enhanced.
History
- July 2008 - First public release.
- July 27th - Updated, call this release 1.1. Changes:
- Added command line option to set the HTTP port (default is still 80).
- Error message is more helpful if another web server already has port 80.
- Fixed some typos and omissions in the manual.
| You must Sign In to use this message board. |
|
| | Msgs 1 to 23 of 23 (Total in Forum: 23) (Refresh) | FirstPrevNext |
|
 |
|
|
 |
|
|
Hi, I recently discover the embedded server, and I find it great.
In my case, I have to return image whose the name is dynamically generated. In my use case, the user retrieves an XML file containing the image names. From these names he can retrieve the images. As the XML contains data about the images, and they are always changing, the unique name is useful to be sure the images are properly matching the XML. So to summarize I have: http://localhost/data.xml containing
<foo> <image="12345.jpg" x=7 y=5 /> <image="12346.jpg" x=7 y=6 /> </foo>
I need to provide http://localhost/12345.jpg and http://localhost/123456.jpg As these names are always changing, they can not come from the fsbuilder.
If I'm correct it's not possible with the current webio version. Is it true ? To do it, I was thinking to add a new filesystems in the wi_filesys table, allowing pure dynamic recording of file. Is it the right way to do it ?
Thanks
Arno
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
|
Would ravenspoint be willing to share this cWebIo class that he/she talks about below ? We would greatly appreciate the pointer.
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
|
 |
|
|
Hi Folks, Release 1.3. is ready. Source download is available here:
http://www.praemio.com/webio/webio1_3.zip http://www.praemio.com/webio/progman.html
I'm working on getting this site updated (author's can't edit their own projects )
The main additions Are:
- A new feature in fsbuilder which allows it to build form code form a scanned HTML page, but without including the HTML page in the embedded file set. This is useful for folks who want the page containing the form on disk, but also want to take advantage of fsbuilder code generation.
- A feature to spawn a new thread to process each CCGI routine. This allows time consuming CGI functons to execute with blocking the core processing thread. This is currently in the windows port - Linux support will come soon.
And threee bugs were fixed:
* fsbuilder now replaces spaces in form control names with underscore when generating C language names. * fsbuilder bug fixed: It crashed if form name was omitted after "-f" option * Fixed webio authentication bug when receiving large http headers. Symptom was authentication just failed when it should have passed.
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
|
For supersimple web applications, developing your own C++ embedded web server is OK but if you need to do something "real", which needs scalability, ease of development (no need to write HTML, CSS or Javascript), multithread, etc, use Wt (there are packages available for Debian and Ubuntu under the name witty)
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
|
Firstly, great article, and great project. Well written up - clearly something that has been evolved over time (if not in code, then in concept), and clearly a topic the author knows well.
For many projects will be able embed a http server using webio as-is.
But I have some code using boost::asio for network servers, and I don't want to add a separate thread and a new library to enable http. However, I'd like to leverage webio within the boost::asio code that I have.
It seems to me the ideal would be using boost::asio for the network management, webio for aspects of url management and file embedding, and some django-style glue code for mapping urls to files or to embedded data or to function calls.
For example:
main() { // simplified ... http_server http(8080); http.map_url("/media(.*)$", media_url_mapper("./rawfiles")); http.map_url("/res(.*)$", embed_resource_mapper()); http.map_url("/stat", boost::bind(do_stat_function)); io_service.run(); }
I know this is a bit off topic, but WDYT?
Thanks again for a great article and the excellent webio library and embedding tool/resource compiler.
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
|
Hi J,
i'm unable to link your project i always get the following error [Linker Error] undefined reference to `WI_NOBLOCKSOCK'
can you help me.
thanks
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
|
Hi,
The WI_NOBLOCKSOCK() macro is supposed to set a socket into non-blocking mode. Since this is different between Windows and Linux, it's ifdeffed based on OS.
If you are building for windows it should be a function in the file websys.c. The complete source is:
#ifdef _WINSOCKAPI_ int WI_NOBLOCKSOCK(long sock) { int err; int option = TRUE;
err = ioctlsocket((int)sock, FIONBIO, (u_long *)&option); return(err); }
The easiest way to get this on windows is probably to include websys.c in your build; if you can't do that then use the source above.
If you're not building for windows, let me know what your target OS is.
Hope this helps,
-JB-
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
|
Hi J,
thanks, it works now. just for your information i compiled it for Windows Vista on MinGw. anyway, many thanks.
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
|
I'm looking for a good embedded web server day by day, and today i find webio. I haven't try it now, wish it will lead a great world to me. thanks
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
|
The procedure for displaying dynamic content in a webpage using webio is quite complex. Unfortunately, the explanation in progman.html makes it seem harder than it really is. Here is a simple recipe to get you started.
- Choose a unique identifier for the string to be displayed. Let's call it XYZ.
- Create a method that returns a pointer to a buffer containing the string to be displayed. Something like this
static char * cMyClass::getDisplayStringXYZ();
- Add html to place the string where you want it in the web page. Something like this
Display Sting XYZ goes just here: <!--#include file="XYZ" -->
- Add a line to the file "filelist" like this
XYZ -e u_long x ( The "u_long x" does not have any significance, but must be there anyhow )
- Run this command
fsbuilder -g wsfcode.c filelist
- Open wsfcode.c and find the identifier XYZ. It will be followed by a number. Let's say 43.
- If it does not already exist, create a C routine called wi_cvariables in the global namespace. This is NOT a C++ routine. Something like this
#include "MyClass.h"
extern "C" { int wi_cvariables(wi_sess * sess, int token) { switch(token) { } return 0; } }
- Add code to the switch statement like this
case 43: wi_printf( sess, cMyClass::getDisplayStringXYZ() ); break;
- Rebuild your application.
It is a lot of steps, some of them quite mysterious. Just do it a couple times, then re-read the explanation in progman.html. It should be easier to understand now, and will give you lots of suggestions for modifying the recipe.
|
| Sign In·View Thread·PermaLink | 5.00/5 (1 vote) |
|
|
|
 |
|
|
A simple, one line change to webio has allowed me to simplify the recipe for displaying dynamic content. You no longer need to muck about with BOTH a string identifier and a string token. ( The token is not only unnecessary, but liable to change from time to time, which I would consider a bug ) Here is the recipe first:
- Choose a unique identifier for the string to be displayed. Let's call it XYZ.
- Create a function that returns a pointer to a buffer containing the string to be displayed. Unfortunately, this has to be a function in the global namespace, because I do not know how to store pointer to member functions. Something like this
char * getDisplayStringXYZ();
- Add html to place the string where you want it in the web page. Something like this
Display Sting XYZ goes just here: <!--#include file="XYZ" -->
- Add a line to the file "filelist" like this
XYZ -e u_long x
( The "u_long x" does not have any significance, but must be there anyhow )
- Run this command
fsbuilder -g wsfcode.c filelist
- Add code like this, before you start the server
cWebio::SetLink( "XYZ", &getDisplayStringXYZ );
- Rebuild your application.
-------------------------------------
The trick to achieving this is to change the call to wi_cvariables ( line 639, webutils.c ) to
error = wi_cvariables(sess, ssifname );
Now wi_cvariables can be implemented as a one line routine that need never be changed
int wi_cvariables(wi_sess * sess, char * idname) { return cWebio::ResolveLink( sess, idname ); }
cWebio is needed to make this work, of course, because it maintains a private map of idnames to function pointers.
----------------------------------------
I would really like to avoid using filelist altogether. However, I cannot immediatly see how to manage this. The issue seems to be that without running fsbuilder with the string identifier specified in filelist, line 729 in webio.c is not executed. Perhaps John Bartas could explain this mystery to me?
|
| Sign In·View Thread·PermaLink | 5.00/5 (1 vote) |
|
|
|
 |
|
|
ravenspoint wrote: The issue seems to be that without running fsbuilder with the string identifier specified in filelist, line 729 in webio.c is not executed. Perhaps John Bartas could explain this mystery to me?
Found it! If the filename does not contain a dot, and is not mentioned in filelist, it is assumed to be binary. ( line 535, webutils.c )
|
| Sign In·View Thread·PermaLink | 5.00/5 (1 vote) |
|
|
|
 |
|
|
OK, final version, done without using filelist! Here is the recipe:
- Choose a unique identifiier for the string to be displayed. Let's call it XYZ.
- Create a function that returns a pointer to a buffer containing the string to be displayed. Unfortunately, this has to be a function in the global namespace, because I do not know how to store pointer to member functions. Something like this
char * getDisplayStringXYZ();
- Add html to place the string where you want it in the web page. Append .cex to the identifier, so the server can recognize it as a 'c executable'. Something like this
Display Sting XYZ goes just here: <!--#include file="XYZ.cex" -->
- Run this command, to embed the new html
fsbuilder -g wsfcode.c filelist
- Add code like this, before you start the server
cWebio::SetLink( "XYZ", &getDisplayStringXYZ );
- Rebuild your application.
Much better - just necessary steps!
-------------------------------------
Here are the changes required, all in file webutils.c
delete line 636 to 640
replace with this code
if( strstr( ssifname, ".cex" ) ) { *(ssifname + strlen(ssifname) - 4 ) = '\0'; wi_cvariables(sess, ssifname ); return 0; }
delete line 624 to 628
You will also need cWebio.
|
| Sign In·View Thread·PermaLink | 5.00/5 (1 vote) |
|
|
|
 |
|
|
I have worked out how to store a pointer to member function.
Here is the complete code for a console application using the cWebio class to run a webio server without using filelist.
#include "stdafx.h" #include "cWebio.h"
char * fun3() { return "CCCC"; }
class cMyClass { public: char * Display6() { return "well done!"; }
};
int _tmain(int argc, _TCHAR* argv[]) {
cMyClass theClass;
cWebio webio;
// specify port
if( argc == 2 ) webio.setPort( _wtoi( argv[1] ) );
// make arrangements so that when webio encounters XYZ.cex // global method fun3 is called
webio.setLink( "XYZ", // display string id &fun3); // global function
// make arrangements so that when webio encounters HAHA.cex // method Display6 is called on theClass an instance of cMyClass
webio.setLink( "HAHA", // display string id boost::bind( &cMyClass::Display6, // member function &theClass ) ); // instance of class
// start the web server webio.Start(); if( webio.myError ) { printf("ERROR: Could not start web server\n%s\n",webio.myErrorMsg ); return 1; } printf("OK, web server is up and running\n");
// keep busy while( 1 ) { Sleep(5000); printf("I'm not dead yet\n"); }
return 0; }
|
| Sign In·View Thread·PermaLink | 5.00/5 (2 votes) |
|
|
|
 |
|
|
Using Webio in a C++ program involves a number of untidy details, none of which by itself is a big deal if you know what you are doing. There are enough of them, and the compiler/linker errors are intimidating enough until they are sorted out, that it seems worthwhile to provide a C++ class to hide the mess.
I have hacked together a quick class that does the job, staring up the server in its own thread. This makes getting a server up and running extremely simple. If course, to begin developing dynamic content still requires an intimate acquaintance with the details, but I think having a server up and running should provide the motivation needed.
Here's the code required to use the cWebio wrapper class.
#include "stdafx.h" #include "cWebio.h"
int _tmain(int argc, _TCHAR* argv[]) { // start the web server, listening on port 1570
cWebio webio; webio.setPort( 1570 ); webio.Start();
// keep busy while( 1 ) { Sleep(5000); printf("I'm not dead yet\n"); }
return 0; }
|
| Sign In·View Thread·PermaLink | 5.00/5 (1 vote) |
|
|
|
 |
|
|
To solve unresolved link errors in the build, specify library Ws2_32.lib
If you get this:
Webio server starting... Error -1 binding web server wi_init error -1001
Your IIS is probably running. To stop it
- Start - Run inetmgr - Action - All tasks - Restart IIS - Stop IIS
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
|
A better workaround for the conflict between servers is to change the port number the server listens on. In this way you can have as many servers as you want on one machine.
Go to line #40 in webio.c and change the port from the standard 80 to something unique.
It might be a good idea to make this a command line option for the demo program.
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
|
I really like that idea (making the port a command line option). I've also found some bugs in the fsbuilder. I'll try to get it implemented and updated by this weekend.
Cheers,
-JB-
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
|
 |
|
|
First run "fsbuilder.exe filelist". This creates a .h and.c file needed for compilation of webio.
|
| Sign In·View Thread·PermaLink | 5.00/5 (2 votes) |
|
|
|
 |
|
|
I gave up writing my own webserver in C for my PSP when I came across this. It's very complete for an embedded web server (SSI support =D). Keep up the good work.
|
| Sign In·View Thread·PermaLink | 3.50/5 (2 votes) |
|
|
|
 |
|
|
General News Question Answer Joke Rant Admin
|