公司很久以前有个task需要在板子上搭建个webserver以响应局域网内手机的请求。
以前是用lighttpd plugin实现的,后来仔细想想用fast cgi来弄也可以。
在install lighttpd之前,先要install pcre和fcgi。我习惯install到/usr/local/pcre和/usr/local/libfcgi.
写个简单的配置文件,如下:
server.document-root = "/mnt/hgfs/share/test/fcgi/"
server.port = 9090
socket_dir = "/tmp/"
server.username = "weifeilong"
server.groupname = "weifeilong"
server.errorlog = "/mnt/hgfs/share/test/fcgi/err.log"
mimetype.assign = (
".html" => "text/html",
".txt" => "text/plain",
".jpg" => "image/jpeg",
".png" => "image/png"
)
static-file.exclude-extensions = ( ".fcgi", ".php", ".rb", "~", ".inc" )
index-file.names = ( "index.html" )
server.modules += ("mod_fastcgi")
fastcgi.server = (
"/fellow" => (
"test.fastcgi.handler" => (
"socket" => socket_dir + "test.fastcgi.socket",
"check-local" => "disable",
"bin-path" => "/mnt/hgfs/share/test/fcgi/test.fastcgi",
"max-procs" => 10,
)
)
)
这里fastcgi程序就用官网的sample,
#include <stdlib.h>
#include <string.h>
#include <syslog.h>
#include <alloca.h>
#include <fcgiapp.h>
#define LISTENSOCK_FILENO 0
#define LISTENSOCK_FLAGS 0
int main(int argc, char** argv) {
openlog("testfastcgi", LOG_CONS|LOG_NDELAY, LOG_USER);
int err = FCGX_Init(); /* call before Accept in multithreaded apps */
if (err) { syslog (LOG_INFO, "FCGX_Init failed: %d", err); return 1; }
FCGX_Request cgi;
err = FCGX_InitRequest(&cgi, LISTENSOCK_FILENO, LISTENSOCK_FLAGS);
if (err) { syslog(LOG_INFO, "FCGX_InitRequest failed: %d", err); return 2; }
while (1) {
err = FCGX_Accept_r(&cgi);
if (err) { syslog(LOG_INFO, "FCGX_Accept_r stopped: %d", err); break; }
char** envp;
int size = 200;
for (envp = cgi.envp; *envp; ++envp) size += strlen(*envp) + 11;
char* result = (char*) alloca(size);
strcpy(result, "Status: 200 OK
Content-Type: text/html
");
strcat(result, "<html><head><title>testcgi</title></head><body><ul>
");
for (envp = cgi.envp; *envp; ++envp) {
strcat(result, "<li>");
strcat(result, *envp);
strcat(result, "</li>
");
}
strcat(result, "</ul></body></html>
");
FCGX_PutStr(result, strlen(result), cgi.out);
}
return 0;
}
gcc -I/usr/local/libfcgi testfastcgi.c -L/usr/local/libfcgi/lib -lfcgi -o test.fastcgi
启动lighttpd:/usr/local/lighttpd/sbin/lighttpd -f /mnt/hgfs/share/test/fcgi/lighttpd.conf(运行前需要export LD_LIBRARY_PATH=/usr/local/libfcgi/lib)
通过curl -v http://localhost:9090/fellow
就可返回结果:
对上面sample 稍作修改,以处理GET和POST请求。
#include <stdlib.h>
#include <string.h>
#include <syslog.h>
#include <alloca.h>
#include <fcgiapp.h>
#include <stdio.h>
#define LISTENSOCK_FILENO 0
#define LISTENSOCK_FLAGS 0
int main(int argc, char** argv) {
openlog("testfastcgi", LOG_CONS|LOG_NDELAY, LOG_USER);
int err = FCGX_Init(); /* call before Accept in multithreaded apps */
if (err) { syslog (LOG_INFO, "FCGX_Init failed: %d", err); return 1; }
FCGX_Request cgi;
err = FCGX_InitRequest(&cgi, LISTENSOCK_FILENO, LISTENSOCK_FLAGS);
if (err) { syslog(LOG_INFO, "FCGX_InitRequest failed: %d", err); return 2; }
while (1) {
err = FCGX_Accept_r(&cgi);
if (err) { syslog(LOG_INFO, "FCGX_Accept_r stopped: %d", err); break; }
#if 1
char* header = (char*) alloca(200);
strcpy(header, "Status: 200 OK
Content-Type: text/html
");
FCGX_PutStr(header, strlen(header), cgi.out);
char response[1024];
if(!strncmp("GET", FCGX_GetParam("REQUEST_METHOD", cgi.envp), strlen("GET")))
{
FCGX_PutStr("GET", strlen("GET"), cgi.err);
if(!strncmp("action=getInfo", FCGX_GetParam("QUERY_STRING", cgi.envp), strlen("action=getInfo")))
{
snprintf(response, sizeof(response), "{"action": "getInfo"}
");
}
}
else if(!strncmp("POST", FCGX_GetParam("REQUEST_METHOD", cgi.envp), strlen("POST")))
{
char *post_data = (char*)malloc(1024);
FCGX_GetStr(post_data, 1024, cgi.in);
FCGX_PutStr(post_data, 1024, cgi.err);
if(!strncmp("action=resetInfo", post_data, strlen("action=resetInfo")))
{
snprintf(response, sizeof(response), "{"action": "resetInfo"}
");
}
}
FCGX_PutStr(response, strlen(response), cgi.out);
#endif
}
return 0;
}
curl -v http://localhost:9090/fellow?action=getInfo
结果如下:
curl -v -d "action=resetInfo" http://localhost:9090/fellow
结果如下: