/** This file is an example of how to embed web-server functionality
* into existing application.
* Compilation line:
* cc example.c shttpd.c -DEMBEDDED*/#ifdef _WIN32
#include#definesnprintf _snprintf#ifndef _WIN32_WCE
#ifdef _MSC_VER/*pragmas not valid on MinGW*/#pragmacomment(lib,"ws2_32")#endif/* _MSC_VER */#defineALIAS_URI "/my_c"#defineALIAS_DIR "c:\\"#else/* _WIN32_WCE *//*Windows CE-specific definitions*/#pragmacomment(lib,"ws2")//#include "compat_wince.h"#defineALIAS_URI "/my_root"#defineALIAS_DIR "\\"#endif/* _WIN32_WCE */#else#include#include#defineALIAS_URI "/my_etc"#defineALIAS_DIR "/etc/"#endif#ifndef _WIN32_WCE/*Some ANSI #includes are not available on Windows CE*/#include#include#include#endif#include#include#include#include#include"shttpd.h"/** This callback function is attached to the "/" and "/abc.html" URIs,
* thus is acting as "index.html" file. It shows a bunch of links
* to other URIs, and allows to change the value of program's
* internal variable. The pointer to that variable is passed to the
* callback function as arg->user_data.*/staticvoidshow_index(structshttpd_arg*arg)
{int*p=arg->user_data;/*integer passed to us*/charvalue[20];constchar*host,*request_method,*query_string,*request_uri;
request_method=shttpd_get_env(arg,"REQUEST_METHOD");
request_uri=shttpd_get_env(arg,"REQUEST_URI");
query_string=shttpd_get_env(arg,"QUERY_STRING");/*Change the value of integer variable*/value[0]='\0';if(!strcmp(request_method,"POST")) {/*If not all data is POSTed, wait for the rest*/if(arg->flags&SHTTPD_MORE_POST_DATA)return;
(void) shttpd_get_var("name1", arg->in.buf, arg->in.len,
value,sizeof(value));
}elseif(query_string!=NULL) {
(void) shttpd_get_var("name1", query_string,
strlen(query_string), value,sizeof(value));
}if(value[0]!='\0') {*p=atoi(value);/** Suggested by Luke Dunstan. When POST is used,
* send 303 code to force the browser to re-request the
* page using GET method. This prevents the possibility of
* the user accidentally resubmitting the form when using
* Refresh or Back commands in the browser.*/if(!strcmp(request_method,"POST")) {
shttpd_printf(arg,"HTTP/1.1 303 See Other\r\n""Location: %s\r\n\r\n", request_uri);
arg->flags|=SHTTPD_END_OF_OUTPUT;return;
}
}
shttpd_printf(arg,"%s","HTTP/1.1 200 OK\r\nContent-Type: text/html\r\n\r\n""
shttpd_printf(arg,"v. %s
shttpd_printf(arg,"
REQUEST_METHOD: %s""REQUEST_URI: \"%s\"QUERY_STRING: \"%s\"""REMOTE_ADDR: %s REMOTE_USER: \"(null)\"
request_method, request_uri,
query_string?query_string :"(null)",
shttpd_get_env(arg,"REMOTE_ADDR"));
shttpd_printf(arg,"
Internal int variable value: %d",*p);shttpd_printf(arg,"%s","
Enter new value:""""");shttpd_printf(arg,"%s","
Enter new value:""""");shttpd_printf(arg,"%s","
shttpd_printf(arg,"%s","
On-disk file (Makefile)host=shttpd_get_header(arg,"Host");
shttpd_printf(arg,"
'Host' header value: [%s]host?host :"NOT SET");
shttpd_printf(arg,"
Upload file example.""""");shttpd_printf(arg,"%s","");
arg->flags|=SHTTPD_END_OF_OUTPUT;
}/** This callback is attached to the URI "/post"
* It uploads file from a client to the server. This is the demostration
* of how to use POST method to send lots of data from the client.
* The uploaded file is saved into "uploaded.txt".
* This function is called many times during single request. To keep the
* state (how many bytes we have received, opened file etc), we allocate
* a "struct state" structure for every new connection.*/staticvoidshow_post(structshttpd_arg*arg)
{constchar*s,*path="uploaded.txt";structstate {
size_t cl;/*Content-Length*/size_t nread;/*Number of bytes read*/FILE*fp;
}*state;/*If the connection was broken prematurely, cleanup*/if(arg->flags&SHTTPD_CONNECTION_ERROR&&arg->state) {
(void) fclose(((structstate*) arg->state)->fp);
free(arg->state);
}elseif((s=shttpd_get_header(arg,"Content-Length"))==NULL) {
shttpd_printf(arg,"HTTP/1.0 411 Length Required\n\n");
arg->flags|=SHTTPD_END_OF_OUTPUT;
}elseif(arg->state==NULL) {/*New request. Allocate a state structure, and open a file*/arg->state=state=calloc(1,sizeof(*state));
state->cl=strtoul(s, NULL,10);
state->fp=fopen(path,"wb+");
shttpd_printf(arg,"HTTP/1.0 200 OK\n""Content-Type: text/plain\n\n");
}else{
state=arg->state;/** Write the POST data to a file. We do not do any URL
* decoding here. File will contain form-urlencoded stuff.*/(void) fwrite(arg->in.buf, arg->in.len,1, state->fp);
state->nread+=arg->in.len;/*Tell SHTTPD we have processed all data*/arg->in.num_bytes=arg->in.len;/*Data stream finished? Close the file, and free the state*/if(state->nread>=state->cl) {
shttpd_printf(arg,"Written %d bytes to %s",
state->nread, path);
(void) fclose(state->fp);
free(state);
arg->flags|=SHTTPD_END_OF_OUTPUT;
}
}
}/** This callback function is attached to the "/secret" URI.
* It shows simple text message, but in order to be shown, user must
* authorized himself against the passwords file "passfile".*/staticvoidshow_secret(structshttpd_arg*arg)
{
shttpd_printf(arg,"%s","HTTP/1.1 200 OK\r\n");
shttpd_printf(arg,"%s","Content-Type: text/html\r\n\r\n");
shttpd_printf(arg,"%s","
");shttpd_printf(arg,"%s","
This is a protected page");
arg->flags|=SHTTPD_END_OF_OUTPUT;
}/** This callback function is attached to the "/huge" URI.
* It outputs binary data to the client.
* The number of bytes already sent is stored directly in the arg->state.*/staticvoidshow_huge(structshttpd_arg*arg)
{intstate=(int) arg->state;if(state==0) {
shttpd_printf(arg,"%s","HTTP/1.1 200 OK\r\n");
shttpd_printf(arg,"%s","Content-Type: text/plain\r\n\r\n");
}while(arg->out.num_bytesout.len) {
arg->out.buf[arg->out.num_bytes]=state%72?'A':'\n';
arg->out.num_bytes++;
state++;if(state>1024*1024) {/*Output 1Mb Kb of data*/arg->flags|=SHTTPD_END_OF_OUTPUT;break;
}
}
arg->state=(void*) state;
}/** This callback function is used to show how to handle 404 error*/staticvoidshow_404(structshttpd_arg*arg)
{
shttpd_printf(arg,"%s","HTTP/1.1 200 OK\r\n");
shttpd_printf(arg,"%s","Content-Type: text/plain\r\n\r\n");
shttpd_printf(arg,"%s","Oops. File not found!");
shttpd_printf(arg,"%s","This is a custom error handler.");
arg->flags|=SHTTPD_END_OF_OUTPUT;
}/** This callback function is attached to the wildcard URI "/users/.*"
* It shows a greeting message and an actual URI requested by the user.*/staticvoidshow_users(structshttpd_arg*arg)
{
shttpd_printf(arg,"%s","HTTP/1.1 200 OK\r\n");
shttpd_printf(arg,"%s","Content-Type: text/html\r\n\r\n");
shttpd_printf(arg,"%s","
");shttpd_printf(arg,"%s","
shttpd_printf(arg,"
shttpd_get_env(arg,"REQUEST_URI"));
arg->flags|=SHTTPD_END_OF_OUTPUT;
}/** This function will be called on SSI directive , or
* , and 'returns' TRUE condition*/staticvoidssi_test_true(structshttpd_arg*arg)
{
arg->flags|=SHTTPD_SSI_EVAL_TRUE;
}/** This function will be called on SSI directive , or
* , and 'returns' FALSE condition*/staticvoidssi_test_false(structshttpd_arg*arg)
{/*Do not set SHTTPD_SSI_EVAL_TRUE flag, that means FALSE*/}/** This function will be called on SSI */staticvoidssi_print_stuff(structshttpd_arg*arg)
{
time_t t=time(NULL);
shttpd_printf(arg,"SSI user callback output: Current time: %s", ctime(&t));
arg->flags|=SHTTPD_END_OF_OUTPUT;
}