Click here to Skip to main content
Click here to Skip to main content

Webio - An embedded web server

By , 20 Jul 2008
 

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:

  1. Unzip it (preserving the directory structure).
  2. Type buildfs to compile the embedded file system.
  3. 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.

License

This article, along with any associated source code and files, is licensed under The BSD License

About the Author

jbartas
Chief Technology Officer praemio.com
United States United States
Member
See my bio here:
 
http://www.bartas.net/resume.htm

Sign Up to vote   Poor Excellent
Add a reason or comment to your vote: x
Votes of 3 or less require a comment

Comments and Discussions

 
You must Sign In to use this message board.
Search this forum  
    Spacing  Noise  Layout  Per page   
GeneralRe: File buffering and embedded systemmemberpbisiac8 Jul '09 - 20:28 
Update: if I force sess->ws_flags |= WF_BINARY in wi_setftype download goes OK. The problem arise with non-binary files (wich get parsed and transferred to RAM before sending via Ethernet)
GeneralRe: File buffering and embedded systemmemberjbartas9 Jul '09 - 8:21 
Glad to hear you got it working. IIRC there's an option in the web page generator to force this flag on a per file basis, but when I went to check this out in the online manual I discovered the Praemio.com web site is defunct Sigh | :sigh: . Look like I have to find a new home for Webio and get everything moved. More soon..... -JB-
GeneralADDR_ABORT ARM exception on multiple GETmemberpbisiac3 Jul '09 - 5:22 
hi again (!)
 
If I refresh countinuosly my webpage my ARM system throws an ADDR_ABORT exception, probably due to recursion (but my stacks seem healty...) Any suggestion on how to avoid recursion on wi_readfile ?
GeneralRe: ADDR_ABORT ARM exception on multiple GETmemberpbisiac3 Jul '09 - 6:06 
Perhaps I've found the solution (memory leak). wi_alloc needs a check on malloc success:
 
wi_alloc(int bufsize)
{
char * buffer;
struct memmarker * mark;
int totalsize;
 
totalsize = bufsize + sizeof(struct memmarker) + 4;
 
buffer = WI_MALLOC(totalsize);

if (buffer == 0) // PB 03/07/2009 17.58.07
return (0); // PB 03/07/2009 17.58.12
...................
 
Hope this will help somebody
GeneralRe: ADDR_ABORT ARM exception on multiple GETmemberjbartas6 Jul '09 - 7:25 
This is definitely a bug. I'd better review the code for making sure I check all results of malloc. Thanks for pointing this out. -JB-
Generalwi_putfilememberpbisiac2 Jul '09 - 6:27 
Hi, I am porting your webserver to an ARM processor. I woud need to upload my files (with curl) and wi_putfile seem perfect - but it's empty... Did you put some work on this routine ? Any suggestion should I implement it by myself ?
QuestionWhat about AJAX ?memberpbisiac26 Jun '09 - 2:37 
Hi, very good work. How about adding AJAX support for dynamic refresh of portions of page ? I've already done some work on this, maybe we can cooperate....
AnswerRe: What about AJAX ?memberjbartas1 Jul '09 - 7:11 
I thought AJAX was mostly client side. As such it should "just work" with Webio. Are there any specific features that are needed? -JB-
GeneralRe: What about AJAX ?memberpbisiac2 Jul '09 - 20:58 
yes, you are right, it's almost client side. I was thinking to automate some functions (like XMLHttpRequest creation and handling) via fsbuilder, who creates callback stubs already....
GeneralThanksmemberZaqro26 Jun '09 - 0:25 
I couldn't compile but, codes written is exelent !!!
 
Zqr

GeneralMakefile for Linuxmemberjbartas11 May '09 - 8:36 
Several users have quite rightly pointed out that I forgot the Linux makefile. A Makefile for Linux is now available at the link below. I've tested it building the code base down-loadable from this page on Fedora 7. Let me know if it works (or not) with other code bases and Linux versions.
 
Here's the link:
 
http://www.praemio.com/webio/makefile
GeneralCompiling with Linuxmemberel06b15027 Apr '09 - 22:29 
Code works fine in Windows, but how to compile in Linux? There is no make file included! The explanation of compiling in Linux is quite short and I can't follow... Confused | :confused:
 
regards
GeneralRe: Compiling with Linuxmemberjbartas11 May '09 - 8:21 
Hi - sorry about forgetting the Linux makefile. I think the easiest way to provide one is to paste it directly into this message. Just copy into a local file, delete these leading lines, and make. Hope this works....
#===================================================
#-------------------------------------------------------------------------------
 
# Makefile for webio - Linux demo app
 
#
 

 
# The code files (object names) for webio.
 
WEBIO_OBJS = webclib.o webfs.o webio.o webobjs.o \
 
websys.o webutils.o webtest.o
 

# The Content-containing C files produced by fsbuilder
CONTENT_C = wsfdata.c wsfcode.c
 
# Object versions of the content-containing C files
CONTENT_OBJS = wsfdata.o
 
# The Ultimate Target of this makefile
 
WEBIO = webio
 
# File system builder utility to convert content into C files
FSBUILDER = fsbuilder
 
# C flags. If you forget the -DLINUX it will try to build a windows version
CC_FLAGS = -c -DLINUX
 

.c.o:
 
$(CC) $(CC_FLAGS) $*.c
 

# Build the actual server. This links both the code files (WEBIO_OBJS) and
# some embedded content $(CONTENT_OBJS)
$(WEBIO): $(WEBIO_OBJS) $(CONTENT_OBJS)
gcc $(WEBIO_OBJS) $(CONTENT_OBJS)
 
# Build C files containing content.
$(CONTENT_C): $(FSBUILDER) filelist
./fsbuilder filelist
 
# Make the fsbuilder utillity. This is required for this example. webio apps
# with no embedded content (i.e. content is all regular disk files) don't
# need fsbuilder
$(FSBUILDER): fsbuilder.cpp
g++ -o fsbuilder fsbuilder.cpp
 

 

 
clean:
 
rm -f *.o
rm -f $(CONTENT_C)
 
rm -f webio
GeneralRe: Compiling with LinuxmemberMember 14030153 Sep '09 - 1:10 
This is not working for me.
 
I am getting
cc -c -o webfs.o webfs.c
webfs.c:167:21: error: wsfdata.h: No such file or directory
webfs.c:175: error: ‘efslist’ undeclared here (not in a function)
make: *** [webfs.o] Error 1
 

If anyone has got the same error and fixed .please do shre the fix with me.
 
Thanks
GeneralRe: Compiling with LinuxmemberMember 362026328 Nov '09 - 5:57 
execute shell and type buildfs to compile the embedded file system then will appear wsfdata.h in your local project folder.
QuestionWhy don't you add webio to wiki?membersoltan1 Dec '08 - 21:45 
Wikipedia has a page listing/comparing embedded/lightweight web servers:
http://en.wikipedia.org/wiki/Comparison_of_lightweight_web_servers[^].
I would recommend adding webio to the list.
GeneralReturning file with a dynamically generated URLmemberasamama14 Nov '08 - 2:59 
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
QuestionCould we please have this wonderfule cWebio ?memberMicroImaging24 Oct '08 - 12:29 
Would ravenspoint be willing to share this cWebIo class that he/she talks about below ?
We would greatly appreciate the pointer.
AnswerRe: Could we please have this wonderfule cWebio ?memberravenspoint24 Nov '08 - 16:57 
The link is http://www.codeproject.com/KB/IP/webem.aspx[^]
GeneralA new release is ready.memberjbartas5 Oct '08 - 13:43 
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 Frown | :-( )
 
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.
GeneralWt -&gt; webtoolkit.eumemberpgquiles13 Sep '08 - 1:23 
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)
QuestionImpressive - but what about boost/asio?memberEllers6 Aug '08 - 13:25 
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.
GeneralLink errormemberNagrom28 Jul '08 - 3:02 
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
GeneralRe: Link errormemberjbartas29 Jul '08 - 5:31 
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-
GeneralRe: Link errormemberNagrom30 Jul '08 - 8:14 
Hi J,
 
thanks, it works now. just for your information i compiled it for Windows Vista on MinGw.
anyway, many thanks.

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Permalink | Advertise | Privacy | Mobile
Web03 | 2.6.130523.1 | Last Updated 20 Jul 2008
Article Copyright 2008 by jbartas
Everything else Copyright © CodeProject, 1999-2013
Terms of Use
Layout: fixed | fluid