|
|
Comments and Discussions
|
|
 |

|
Hi All,
I downloaded the current zip and unpacked it. Not seeing any Makefile in this archive but saw a link in another email. Tried downloading that but daddywall.com is dead (expired on 11-15-12 I think). Also looked at the code browser on Code Project and can see a Makefile in the manifest but it is not viewable or downloadable. Any chance I can get either Makefile or a zip with everything included?
Thanks,
CS
|
|
|
|

|
does anybody have a simple push function that will do something like update a clock on screen?
I could sure use some help here. This is the only thing preventing me from using this as a real UI.
(I realize it was an exercise left for the student...but I can't seem to get there from here)
|
|
|
|
|

|
Yikes! I was going to name my next code project "Ponzi", but I've changed my mind.
|
|
|
|

|
bright.
Chicagosportswebio.com
|
|
|
|

|
I got the latest version and have succeeded in compiling it for DOS Real Mode, DOS-32 Protected Mode, Win-32 and Linux all from targets on the Open Watcom compiler. In addition to being the greatest thing in web technology since sliced bread, it is also the easiest ANSI C portable source I have ever used. If you need a Berkeley Sockets compliant library for TCP-IP on DOS try :
http://www.softsystem.co.uk/products/swssock.htm[^]
I had very little trouble compiling and inserting the DOS wrapper into WebIO using this library. I also got SQLite to compile to 224K on the DOS platform.
So far my realtime embedded SCADA server is compiling to around 634K with a couple dozen embedded pages. It is distributed as a single executable, zero configuration, zero installation, zero maintenance, you run it and surf to "localhost" and can see a colossal web site.
WebIO is incredible. The recent fixes have improved performance noticeably on Windows NT Workstation and Windows 2000 in my testing. Now all I need to do is compile the Dillo Browser for DOS into this source and I will have an X-Windows compliant web server realtime workstation.
|
|
|
|

|
I've finally gotten around to some belated fixes to the build system. Praemio.com is now dead, so the new sources are here:
http://www.daddywall.com/webio/webio-dec2011.zip[^]
The programmers manual is there too:
http://www.daddywall.com/webio/progman.html[^]
Here's the text of the new readme.txt file:
Quote: Readme file for Webio embedded we server directory.
Last Edit Dec. 31st, 2011
Webio sources are currently available at codeproject.com, daddywall.com,
and soon sourceforge.com. Once we find someone will to donate a Subversion
server we'll start publishing specific version numbers. Until then just find
source and documentation that seems to have consistent dates across the system.
The latest and greatest is currently at:
http://www.daddywall.com/webio/webio-dec2011.zip
Detailed documentation is in the file progman.html, which should have been included
with sources and samples. This file fills in update info which may not make it
into the html file.
During 2011 the demo application was built and run on Centos Linux 5.6 and
Windows & using Microsoft Visual Studio 2010. Project files for Visual
Studio 6.0 are preserved with "-60" added to the main filename, i.e.
webio.dsp for MSVC 6.0 is named webio-60.dsp. These files have not been tested
in a few years - use at your own risk.
A new Linux makefile has been added so that both the demo and a library can be
built int he same directory. The demo is built be the default "makefile", the
library (at least the "daddywall" version) can be built be dwallweb.mk. Since the
Daddywall sources are not open the latter file is purely informational.
Known bugs & problems:
* The cticks counter is not maintained in the demo programs.
* The -c flag (for cache control) is documented but not supported.
* On at least some Windows 7 machines, bind fails on port 80. It seems Microsoft
used it for their proprietary "IIS". To get around this the default port for
windows builds is changed to 88, thus your browser can access your web
server's pages at http://127.0.0.1:80 More proof that if Bill Gates
pair a nickel to every programmer who had to work around a
Microsoft bug he would be broke.
|
|
|
|

|
I have been struggling with some cache issues on my embedded web site. Turns out the contractor who coded the original site used the <meta> tag (<META http-equiv="Pragma" content="no-cache">) to ensure that the browser did not cache certain pages. However, that doesn't work on IE and I am not sure FF is working properly either; I am seeing strange behaviour that can only be rectified by clearing the browser cache.
So I added the -c flag to the appropriate files in my "filelist" file, but the resulting code in wfsdata.c had not changed. I looked at the source of fsbuilder.cpp and although it says it supports the -c flag, it accepts as valid but does not do anything with it.
I think it would be relatively easy to support caching at file level. A simple mod to fsbuilder.cpp should ensure we could turn on the cache bit EMF_CACHE. Then in the function..
int wi_replyhdr(wi_sess * sess, int contentlen)
you could generate the following http headers for GET operations on non-cached files.
Cache-Control: no-cache
Pragma: no-cache
Well it sounds simple enough, anyone else come across this? I am just surprised no one else had mentioned it before?
Phil
modified 22 Nov '11 - 8:24.
|
|
|
|

|
Hello,
I've been trying to build webio for Linux, but the Makefile (supplied in reply to a question from someone else) doesn't work on my system. I'm using Ubuntu 11, and I'm getting error messages from make about missing separators, and it doesn't perform the build.
Can you help with this please?
Peter
|
|
|
|

|
Adam Fullerton sent in a couple bugs, along with the fixes. It's really past time to spin a new code base for Webio.
If you use it before I get around to the update, make sure you fix these:
1) In webobjs.c oldsess->ws_formlist is not cleared before the wi_free(oldsess) call. the form list dshould be cleared in a loop, similar to ws_filelist and ws_txbufs list.
2) In webutils.c sess->ws_formlist->next is referenced right after the call "wi_free(sess->ws_formlist)". A temporary pointer should be used to save sess->ws_formlist->next before sess->ws_formlist is freed.
|
|
|
|

|
Hi, perhaps my question has few to do with WebIO, When I browse a page that's configured to ask user/password some browsers (Opera on IPhone and Chrome) refuse to load it but ask continuously same credentials. Perhaps the access policy to those files should be different by design. Any ideas ? Thanks, regards, Paolo
|
|
|
|

|
I'd like to reproduce this and watch it with Wireshark. I don't have an IPhone (I'm about to buy an android ), but I can try Chrome on Windows or Linux. Do you see the problem with Chrome on either of those systems? -JB-
|
|
|
|

|
JB,
I am so glad to have your webio running on my small board(with 2M ram), and it works good so far.
I have same issue at beginning when I use chrome as browser, and I found that decode[80] in webutils.c - wi_decode_auth(...) seems not big enough for chrome, change it to decode[400] works.
Thanks again for the great job.
cren
|
|
|
|

|
I found that the Stock Android browser (on Android 2.3.3) and the Blackberry (on 5.0) don't send the HTTP Authentication headers for every html file (marked as requiring authentication in "filelist") which is why you get multiple user/password request. WireShark was not much use when debugging Mobile browsers over Wifi, so I simply pushed the incoming HTTP requests out the Serial Debug port on my development board which confirmed this behaviour. The iPhone browser (3GS) works fine with authentication as do most of the Desktop browsers.
I really don't know whether this is a bug in those browsers or perhaps a feature of my mobile web pages or the way I have set up the authentication if "filelist".
I inherited the WebIo port and web site from a contractor so I am on a steep learning curve.
In the end the only way I could get around this was to remember the login credentials for any session from those browsers. I do check IP and MAC addresses and there is a session time-out as well, but I wouldn't recommend this solution as a secure. Also, my application only allows one session to login at anyone time.
|
|
|
|

|
When I run the server, it shows message below:
Webio server starting...
It seems the server is running. But when I try to brower to it, the webio terminal, and show this message: Segmentation fault
I run on embedded sytem.
Our System: mips chip, RAM 512MB, linux 2.6.22.19-12.
Our compile: gcc4
Thanks
|
|
|
|

|
I have the same problem on my linux build. When I use in the debugger I get also a message Program received signal SIGSEGV, Segmentation fault.
I also notice that sometimes when I press 'F5' (refresh) and keep it pressed on my browser an other error is reported: Program received signal SIGPIPE, Broken pipe.
Build with GCC on Ubuntu (4.4.3)
Anyone a suggestion how to solve this?
modified on Tuesday, June 15, 2010 8:30 AM
|
|
|
|

|
Hello,
If I leave my embedded device webserver working for hours, with 4-10 clients (Internet Explorer) calling periodically a CGI function my heap keeps filling until I get an exception.
My opinion is that some sessions are not well closed and generate some memory leak.
I can reproduce this behaviour in this way:
start.....20%heap
open 10 IE clients....30% heap
keep working some time....
close 10 clients...HEAP doesnt reduce
open 10 new IE clients....40% heap
and so on
Any ideas ?
Thanks, regards
Paolo
|
|
|
|

|
Hi Paolo,
I sure does sound like a memory leak. I'll try to reproduce it over the next few days and see if I can spot it.
In your example above, when you "close 10 clients...", how do you close them? Do you lose the IE application with an exit, kill it from the process controller, or something else?
Please let me know,
-JB-
|
|
|
|

|
Hi JB,
I made some more investigation and found a memory leak.
My webpage sends a GET avery 10 seconds to WebIO. Here some logs with caller routine in evidence:
****WI_MALLOC (0654) = 380031F4...wi_newsess:wi_alloc(sizeof(wi_sess)) = 380031FC
****WI_MALLOC (0024) = 3800D868...wi_buildform:wi_alloc(sizeof(total 24 bytes)) = 3800D870
****WI_MALLOC (001C) = 3800D894...em_fopen:wi_alloc(sizeof(EOFILE)) = 3800D89C
****WI_MALLOC (0824) = 38003850...wi_newfile:wi_alloc(sizeof(wi_file)) = 38003858
wi_newfile GetUpdate.cgi
****WI_FREE (3800D894)...em_fclose:wi_free(passedfd) = 3800D89C
wi_fclose
****WI_FREE (38003850)...wi_delfile:wi_free(delfile) = 38003858
wi_delfile
wi_txdone:socket close
wi_delsess:oldsess->ws_socket == INVALID_SOCKET
****WI_FREE (3800D868)...****WI_FREE (380031F4)...wi_delsess:wi_free(oldsess) = 380031FC
The form data (24 bytes) malloc never get freed. I think the problem in resourse freeing in wi_delsess:
.................
/* Unlink from master session list */
lastsess = NULL;
for(tmpsess = wi_sessions; tmpsess; tmpsess = tmpsess->ws_next)
{
if(tmpsess == oldsess) /* Found session to unlink? */
{
if(lastsess)
lastsess->ws_next = tmpsess->ws_next;
else
wi_sessions = tmpsess->ws_next;
break;
}
lastsess= tmpsess;
}
/* Make sure there are no dangling resources */
if(oldsess->ws_txbufs)
{
while(oldsess->ws_txbufs)
{
wi_txfree(oldsess->ws_txbufs);
}
}
if(oldsess->ws_filelist)
{
if(oldsess->ws_filelist) // THIS IS STRANGE INDEED
{
wi_fclose( oldsess->ws_filelist);
}
}
// PB 09/11/2009 18.39.29
if(oldsess->ws_formlist)
{
if(oldsess->ws_formlist)
{
wi_free( oldsess->ws_formlist);
}
}
// PB 09/11/2009 18.39.29
...........................
I added the oldsess->ws_formlist cleanup, but I'm not sure if you can have more than 1 form attached to a session; in that case, my correction would not be enough
I Wait for news from you, best regards,
Paolo
|
|
|
|

|
Yup, looks like a leak. Sorry about that.
I'm pretty sure the form is a linked list, so I'll have to come with some code that traverses the list, free()ing memory as it goes. What you've posted should be OK for pages with only one form.
I finally have the code on a public SVN server - I'll check in these fixes and publish the link in a note here as soon permissions are set up.
Thanks for the fix,
-JB-
|
|
|
|

|
Hi! Any news on this public SVN server? Or any other place to download newer than 1.1 release (www.praemio.com doesn't seem to exist any more) ?
|
|
|
|

|
Hi, this is my (tested) upload routine:
/* wi_putfile()
*
* This is called when a session receives a PUT command.
*
*
* Returns: 0 if no error, else negative WIE_ error code.
*
*/
int
wi_putfile( wi_sess * sess)
{
wi_file *fi; /* info about current file */
char * cp;
char * cl;
char * rxend;
int res;
long b_read, b_remain;
/* First find end of HTTP header */
rxend = strstr(sess->ws_rxbuf, "\r\n\r\n" );
/* Extract the URL */
cp = wi_nextarg(&sess->ws_rxbuf[3]);
if(!cp)
{
wi_senderr(sess, 400); /* Bad request */
return WIE_CLIENT;
}
if(*cp == '/')
{
if(*(cp+1) == ' ')
sess->ws_uri = wi_rootfile;
else
sess->ws_uri = cp+1; /* strip leading slash */
}
else
sess->ws_uri = cp;
/* Extract other useful fields from header */
sess->ws_auth = wi_getline("Authorization:", cp);
sess->ws_referer = wi_getline("Referer:", cp);
sess->ws_host = wi_getline("Host:", cp);
cl = wi_getline("Content-Length:", cp);
if(cl)
sess->ws_contentLength = atoi(cl);
else
sess->ws_contentLength = 0; /* unset */
/* insert the null terminators in any strings in the rxbuf */
if((sess->ws_uri > sess->ws_rxbuf) && (sess->ws_uri < rxend))
wi_argterm(sess->ws_uri); /* Null terminate the URI */
if((sess->ws_auth > sess->ws_rxbuf) && (sess->ws_auth < rxend))
wi_argterm(sess->ws_auth); /* etc */
if((sess->ws_referer > sess->ws_rxbuf) && (sess->ws_referer < rxend))
wi_argterm(sess->ws_referer);
if((sess->ws_uri > sess->ws_host) && (sess->ws_host < rxend))
wi_argterm(sess->ws_host);
/* --------------------------------------------- */
/* Decode filename */
wi_urldecode(sess->ws_uri);
/* Inizio a leggere il file da scrivere nel mio filesystem */
b_remain = sess->ws_contentLength;
res = wi_fopen(sess, fname_path, "w");
if (res == 0)
{
/* file da scrivere */
fi = sess->ws_filelist;
/* vedo se nel primo pacchetto ci sono anche dati da scrivere */
if (sess->ws_data)
{
b_read = sess->ws_rxsize - (sess->ws_data - sess->ws_rxbuf);
b_remain -= b_read;
res = wi_fwrite(sess->ws_data, 1, b_read, fi);
}
if (b_remain > 0)
do
{
b_read = recv (sess->ws_socket, sess->ws_rxbuf,
sizeof(sess->ws_rxbuf), 0);
if (b_read != -1)
{
b_remain -= b_read;
res = wi_fwrite(sess->ws_rxbuf, 1, b_read, fi);
/* all data written ? */
if (res != b_read)
{
/* TODO: check, why not all data was written */
b_remain = -1; // segnalo abort
}
}
else
{
b_remain = -1; // segnalo abort
break;
}
} // do
while (b_remain > 0);
if (b_remain == 0)
{
wi_replyhdr(sess, sess->ws_contentLength);
wi_fclose(fi);
}
else
{
wi_fclose(fi);
wi_fremove(sess->ws_uri);
wi_senderr(sess, 501); /* Send "Internal server error" reply */
}
}
else
{
wi_senderr(sess, 503); /* Send "Service Unavailable" reply */
}
return 0; /* No Error */
}
Hope will be useful...
|
|
|
|

|
hi again,
if I ask Webio a "big" file (25Kbytes) it seems like wi_readfile allocates more and more sessions with
wi_txalloc(sess), until my embedded system runs out of memory.
Is that true ? could you help me modify this routine so no more than, say, 3 sessions get allocated at any time ?
I understand 26K is insignificant on Linux and Windows, but can be a problem in embedded system with limited heap...
|
|
|
|

|
Hi -
Is this a binary file, or is a "normal" one which may have SSI-type includes?
This could be a bug (after all you've found 'em before ) or it could be an artifact of the way Webio handles the SSI-containing (I'll call them dynamic) files. To return the Content-Length of a dymanic file Webio reads the whole file, including files inside SSIs, into a chain of buffers; then measures the ready-to-send set of buffers to get the length. These buffers can eat a lot of space.
So - is the file binary?
Let me know,
-JB-
|
|
|
|

|
Hi, tanks for replying so fast,
it is a normal text file (license_lgpl.txt). If I change the extension to htm nothing changes. I guess It's treated as binary file.
|
|
|
|

|
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)
|
|
|
|

|
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 . Look like I have to find a new home for Webio and get everything moved. More soon..... -JB-
|
|
|
|

|
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 ?
|
|
|
|

|
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
|
|
|
|

|
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-
|
|
|
|

|
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 ?
|
|
|
|

|
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....
|
|
|
|

|
I thought AJAX was mostly client side. As such it should "just work" with Webio. Are there any specific features that are needed? -JB-
|
|
|
|

|
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....
|
|
|
|

|
I couldn't compile but, codes written is exelent !!!
Zqr
|
|
|
|

|
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
|
|
|
|

|
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...
regards
|
|
|
|

|
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
|
|
|
|

|
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
|
|
|
|

|
execute shell and type buildfs to compile the embedded file system then will appear wsfdata.h in your local project folder.
|
|
|
|
|

|
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
|
|
|
|

|
Would ravenspoint be willing to share this cWebIo class that he/she talks about below ?
We would greatly appreciate the pointer.
|
|
|
|
|

|
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.
|
|
|
|

|
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)
|
|
|
|

|
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.
|
|
|
|

|
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
|
|
|
|

|
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-
|
|
|
|

|
Hi J,
thanks, it works now. just for your information i compiled it for Windows Vista on MinGw.
anyway, many thanks.
|
|
|
|
 |
|
|
General News Suggestion Question Bug Answer Joke Rant Admin
|
A C-language web server with embedded files and CGI.
| Type | Article |
| Licence | BSD |
| First Posted | 20 Jul 2008 |
| Views | 81,862 |
| Downloads | 1,978 |
| Bookmarked | 97 times |
|
|