Linux下goahead3.3.6的移植以及文件上传下载示例

#开源库下载

下载地址
https://embedthis.com/goahead/download.html

在下载地址中可以看到说明
Source Code Repository
To access the GoAhead source code at GitHub, see: GitHub GoAhead Repository.
To download source code for specific versions, see: GoAhead Releases.
分别是两个地址
github的托管地址 https://github.com/embedthis/goahead
下载之前不同版本的地址 https://github.com/embedthis/goahead/releases

当前能够看到的最新的版本是v3.6.5
并且可以依次往下看到版本有
2017-06-10 v3.6.5
2017-06-10 v3.6.4
2016-06-03 v3.6.3

2012-06-28 v2.5.0

我随机下载了 3.3.6 版本;

#开源库编译

$ tar -zxvf goahead-3.3.6.tar.gz 
$ cd goahead-3.3.6/
$ make CC=arm-none-linux-gnueabi-gcc ARCH=arm

编译完成后提示

You can now install via "sudo make ARCH=arm CC=arm-none-linux-gnueabi-gcc install" or run GoAhead via: "sudo make run"
To run locally, put linux-arm-default/bin in your path

说明已经编译成功;
进入目录 goahead-3.3.6/build/linux-arm-default/bin
看到了编译出来的嵌入式可执行文件 goahead 已经相关的库文件
ca.crt goahead goahead-test gopass libest.so libgo.so

其中 goahead 可以测试相关的get方法请求;
goahead-test 则有相关的post请求,并且有文件上传的例程;

编译过程中如果需要看到编译语句,可以使用 SHOW=1

$ make CC=arm-none-linux-gnueabi-gcc ARCH=arm SHOW=1
$ make clean CC=arm-none-linux-gnueabi-gcc ARCH=arm SHOW=1

添加断点调试 (-g) :

$ make CC='arm-none-linux-gnueabi-gcc -g' ARCH=arm SHOW=1

可执行程序goahead 是从 goahead-3.3.6/src/goahead.c 的 MAIN() 函数开始执行的;
goahead-test 是从 goahead-3.3.6/test/test.c 的 MAIN() 函数开始;

#开源库使用
在嵌入式 开发板上执行生成的goahead可执行文件

/mnt/test # ./goahead -v web 192.168.1.44:80
src/goahead.c(main)
goahead: 1: This system does not have IPv6 support
goahead: 2: Configuration for Embedthis GoAhead
goahead: 2: ---------------------------------------------
goahead: 2: Version:            3.3.6
goahead: 2: BuildType:          Debug
goahead: 2: CPU:                arm
goahead: 2: OS:                 linux
goahead: 2: Host:               192.168.1.44
goahead: 2: Directory:          /mnt/test
goahead: 2: Documents:          web
goahead: 2: Configure:          me -d -q -platform linux-x86-default -configure . -with est -gen make
goahead: 2: ---------------------------------------------
goahead: 2: Started http://192.168.1.44:80

问题1
/mnt/goahead-3.3.6/build/linux-arm-default/bin # ./goahead
goahead: 0: Cannot get host address for host sun5i: errno 11
goahead: 0: Cannot initialize server. Exiting.

修改代码 src/http.c
函数 static int setLocalHost()

	#if VXWORKS
	...
	#elif ECOS
	...
	#elif TIDSP
	...
	#elif MACOSX
	...
	#else
	{
		struct hostent  *hp;
		//if ((hp = gethostbyname(host)) == NULL) {
		//    error("Cannot get host address for host %s: errno %d", host, errno);
		//    return -1;
		// }
		//memcpy((char*) &intaddr, (char *) hp->h_addr_list[0], (size_t) hp->h_length);
		//ipaddr = inet_ntoa(intaddr);
		int sockfd;   
		struct sockaddr_in sin;   
		struct ifreq ifr;         
		sockfd = socket(AF_INET, SOCK_DGRAM, 0);      
		if (sockfd == -1)   {             
			return -1;            
		}         
		strncpy(ifr.ifr_name, "eth0", IFNAMSIZ);    // 指定网卡  
		ifr.ifr_name[IFNAMSIZ - 1] = 0;       
		if (ioctl(sockfd, SIOCGIFADDR, &ifr) < 0)    {             
			return -1;    
		}     
		memcpy(&sin, &ifr.ifr_addr, sizeof(sin));     
		ipaddr=inet_ntoa(sin.sin_addr); 
		
		websSetIpAddr(ipaddr);
		websSetHost(ipaddr);
	}
	#endif

问题2
/mnt/goahead-3.3.6/build/linux-arm-default/bin # ./goahead
goahead: 0: Cannot open config file route.txt
goahead: 0: Cannot initialize server. Exiting.

拷贝 src/route.txt 到 build/linux-arm-default/bin/

问题3
/mnt/goahead-3.3.6/build/linux-arm-default/bin # ./goahead
goahead: 0: Cannot open config file auth.txt
goahead: 0: Cannot load auth.txt
拷贝 src/auth.txt 到 build/linux-arm-default/bin/

拷贝网页并进行访问
新建目录 build/linux-arm-default/web/
拷贝 test/web/index.html 到 build/linux-arm-default/web/目录
直接网页上输入开发板的IP地址 192.168.1.123 即可看到
这里写图片描述
这里我修改了一下网页的显示文字

使用get方法访问数据
修改 src/auth.c 的 loginServiceProc 函数;

static void loginServiceProc(Webs *wp)
{
    WebsRoute   *route;

    assert(wp);
    route = wp->route;
    assert(route);
    printf("%s(%s:%d)%s, %s\n", __FILE__, __FUNCTION__, __LINE__, 
	websGetVar(wp, "username", ""), websGetVar(wp, "password", ""));
    if (websLoginUser(wp, websGetVar(wp, "username", ""), websGetVar(wp, "password", ""))) {
        /* If the application defines a referrer session var, redirect to that */
        char *referrer;
        if ((referrer = websGetSessionVar(wp, "referrer", 0)) != 0) {
            websRedirect(wp, referrer);
        } else {
            websRedirectByStatus(wp, HTTP_CODE_OK);
        }
        websSetSessionVar(wp, "loginStatus", "ok");
    } else {
        if (route->askLogin) {
            (route->askLogin)(wp);
        }
        websSetSessionVar(wp, "loginStatus", "failed");
        //websRedirectByStatus(wp, HTTP_CODE_UNAUTHORIZED);
        websWrite(wp,(char *)"I am test");
        // websRedirectByStatus(wp, HTTP_CODE_OK);
        websDone(wp);
    }
}

在浏览器中访问开发板上的接口

这里写图片描述

其中这里访问了bbbb/目录,因为修改了 goahead-3.3.6/build/linux-arm-default/bin/route.txt

#   For legacy GoAhead applications using /goform
#route uri=/goform handler=action
route uri=/bbbb handler=action

#GET请求和文件上传下载

get请求和文件上传

// $ export LD_LIBRARY_PATH=`pwd`:$LD_LIBRARY_PATH
// $ arm-none-linux-gnueabi-gcc main.c -L ./ -lgo -lest
// $ ./a.out
#include <stdio.h>
#include <signal.h>
#include <stdlib.h>
#include "goahead.h"

#define wfree(p) if (p) { free(p); } else

static int finished = 0;
static void initPlatform();
static void ShowString(Webs *wp);
static void uploadTest(Webs *wp, char *path, char *query);

int main(){
	printf("starting...\n");
	char *route = (char*)"route.txt";
    char *auth = (char*)"auth.txt";
	char *documents = (char*)"web";
	
	initPlatform();
    if (websOpen(documents, route) < 0) {
        error("Cannot initialize server. Exiting.");
        return -1;
    }
    if (websLoad(auth) < 0) {
        error("Cannot load %s", auth);
        return -1;
    }
	websDefineAction("showString", ShowString);
	websDefineAction("uploadTest", uploadTest);
	char *endpoints = (char*)sclone((char*)"http://*:80,https://*:443");
	char *tok;
	char *endpoint;
	printf("(%d)\n", __LINE__);
	for (endpoint = stok(endpoints, ", \t", &tok); endpoint; endpoint = stok(NULL, ", \t,", &tok)) {
		printf("(%d)\n", __LINE__);
		if (websListen(endpoint) < 0) {
			return -1;
		}
		printf("(%d)\n", __LINE__);
	}
	printf("(%d)\n", __LINE__);
	wfree(endpoints);
	/
	if (websGetBackground()) {
        if (daemon(0, 0) < 0) {
            error("Cannot run as daemon");
            return -1;
        }
    }
	
    websServiceEvents(&finished);
	printf("Instructed to exit");
    websClose();
	return 0;
}

static void sigHandler(int signo){
	printf("(%s:%d)\n", __FUNCTION__, __LINE__);
    finished = 1;
}

static void initPlatform(){
	printf("(%s:%d)\n", __FUNCTION__, __LINE__);
    signal(SIGTERM, sigHandler);
    signal(SIGKILL, sigHandler);
    signal(SIGPIPE, SIG_IGN);
}

static void ShowString(Webs *wp){
    WebsRoute *route;
	char result[64];
    assert(wp);
    route = wp->route;
    assert(route);
	sprintf(result, "I am ShowString : %s", websGetVar(wp, "str", ""));
	websWrite(wp,result);
	websDone(wp);
}

static void uploadTest(Webs *wp, char *path, char *query)
{
    WebsKey         *s;
    WebsUpload  *up;
    char            *upfile;

    websSetStatus(wp, 200);
    websWriteHeaders(wp, -1, 0);
    websWriteHeader(wp, "Content-Type", "text/plain");
    websWriteEndHeaders(wp);
    if (scaselessmatch(wp->method, "POST")) {
        for (s = hashFirst(wp->files); s; s = hashNext(wp->files, s)) {
            up = s->content.value.symbol;
			websWrite(wp, "TEST : 2017-8-10 14:06:04\r\n");
            websWrite(wp, "FILE: %s\r\n", s->name.value.string);
            websWrite(wp, "FILENAME=%s\r\n", up->filename);
            websWrite(wp, "CLIENT=%s\r\n", up->clientFilename);
            websWrite(wp, "TYPE=%s\r\n", up->contentType);
            websWrite(wp, "SIZE=%d\r\n", up->size);
            //upfile = sfmt("%s/tmp/%s", websGetDocuments(), up->clientFilename);
            upfile = sfmt("/tmp/%s", up->clientFilename);
            rename(up->filename, upfile);
            websWrite(wp, "UPFILE=%s\r\n", upfile);
            wfree(upfile);
        }
        websWrite(wp, "\r\nVARS:\r\n");
        for (s = hashFirst(wp->vars); s; s = hashNext(wp->vars, s)) {
            websWrite(wp, "%s=%s\r\n", s->name.value.string, s->content.value.string);
        }
    }
    websDone(wp);
}

/*
#
# 其中用的接口来自于 libgo.so
# websOpen
# websLoad
# sclone
# stok
# websListen
# websGetBackground
# websServiceEvents
# websClose
#
*/

这里写图片描述

文件上传接口

这里写图片描述
(直接使用自带的 goahead-3.3.6/test/web/upload/upload.html,拷贝到同级目录后使用)

上传完成之后,页面自动跳转显示(文件上传到开发板的 /tmp/ 目录下,由变量 upfile 决定)

TEST : 2017-8-10 14:06:04
FILE: file
FILENAME=/tmp/tmp-0.tmp
CLIENT=test.txt
TYPE=text/plain
SIZE=3
UPFILE=/tmp/test.txt

VARS:
HTTP_CONNECTION=keep-alive
HTTP_CONTENT_LENGTH=481
HTTP_CACHE_CONTROL=max-age=0
FILE_FILENAME_file=/tmp/tmp-0.tmp
UPLOAD_DIR=/tmp
HTTP_ACCEPT_ENCODING=gzip, deflate
HTTP_ORIGIN=http://192.168.1.123
Address=ddd
FILE_SIZE_file=3
HTTP_CONTENT_TYPE=multipart/form-data; boundary=----WebKitFormBoundary5gPnTrFrUlfqmM73
HTTP_REFERER=http://192.168.1.123/upload.html
HTTP_ACCEPT=text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8
Name=abc
HTTP_ACCEPT_LANGUAGE=zh-CN,zh;q=0.8
MAX_FILE_SIZE=30000
HTTP_UPGRADE_INSECURE_REQUESTS=1
FILE_CLIENT_FILENAME_file=test.txt
HTTP_HOST=192.168.1.123
HTTP_USER_AGENT=Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 Safari/537.36
FILE_CONTENT_TYPE_file=text/plain

文件下载

// 开始下载 192.168.8.41/action/down?video=\UserDev\ip.dat
static void actionDownLoad(Webs *wp, char *path, char *query);

int main(){
	// 省略很多
	websDefineAction("down", actionDownLoad);
}


static void actionDownLoad(Webs *wp, char *path, char *query){
	//(*wp).route->handler->close = (*avolfileClose);
	//(*wp).route->handler->service = (*avolfileHandler);
	//(*wp).route->handler->service(wp);
	
	WebsHandlerProc service = (*wp).route->handler->service; 
	(*wp).route->handler->close = (*avolfileClose);
	(*wp).route->handler->service =(*avolfileHandler); 
	(*wp).route->handler->service(wp); 
	(*wp).route->handler->service= service; 
}

static void avolfileClose(){
	//wfree(websIndex);
	//websIndex = NULL;
	//wfree(websDocuments);
	//websDocuments = NULL;
}


static bool avolfileHandler(Webs *wp){
	WebsFileInfo    info;
	char *tmp, *date;
	ssize nchars;
	int code;

	char* pathfilename; //带路径的文件名 用于找到对应的文件
	char* filenameExt; //文件扩展名 用于 设置 MIME类型
	char* filename; //文件名 用于下载后保存的文件名称
	char* disposition; //临时保存 附件 标识
	
	assert(websValid(wp));
	assert(wp->method);
	assert(wp->filename && wp->filename[0]);

	// 取download.lua?video=C:\aaa.wmv 中的 C:\aaa.wmv
	pathfilename = websGetVar(wp, "video", NULL);
	if (pathfilename==NULL)
		return true;

	//取文件名和扩展名
	filename =sclone(getUrlLastSplit(sclone(pathfilename),"\\"));
	filenameExt =sclone(getUrlLastSplit(sclone(filename),"."));
	
	if (wp->ext) wfree(wp->ext);
 
	wp->ext=(char*)walloc(1+strlen(filenameExt)+1);
	sprintf(wp->ext,".%s",sclone(filenameExt));
	free(filenameExt);
	filenameExt=NULL;

	if (wp->filename) {
		wfree(wp->filename);
	}
	wp->filename=sclone(pathfilename);

	if (wp->path) {
		wfree(wp->path);
	}
	wp->path=sclone(pathfilename);
    
        //If the file is a directory, redirect using the nominated default page
        if (websPageIsDirectory(wp)) {
            nchars = strlen(wp->path);
            if (wp->path[nchars - 1] == '/' || wp->path[nchars - 1] == '\\') {
                wp->path[--nchars] = '\0';
            }
	    char* websIndex = "testdownload";
            tmp = sfmt("%s/%s", wp->path, websIndex);
            websRedirect(wp, tmp);
            wfree(tmp);
            return true;
        }
        if (websPageOpen(wp, O_RDONLY | O_BINARY, 0666) < 0) {
            websError(wp, HTTP_CODE_NOT_FOUND, "Cannot open document for: %s", wp->path);
            return true;
        }
        if (websPageStat(wp, &info) < 0) {
            websError(wp, HTTP_CODE_NOT_FOUND, "Cannot stat page for URL");
            return true;
        }
        code = 200;
        if (wp->since && info.mtime <= wp->since) {
            code = 304;
        }
        websSetStatus(wp, code);
        websWriteHeaders(wp, info.size, 0);

	//浏览器下载文件时的文件名 
	disposition = (char*)walloc(20+strlen(filename)+1);
	sprintf(disposition,"attachment;filename=%s",sclone(filename));
	websWriteHeader(wp, "Content-Disposition", sclone(disposition));
	free(filename);
	free(disposition);
	filename=NULL;
	disposition=NULL;

        if ((date = websGetDateString(&info)) != NULL) {
            websWriteHeader(wp, "Last-modified", "%s", date);
            wfree(date);
        }
        websWriteEndHeaders(wp);

        //All done if the browser did a HEAD request
        if (smatch(wp->method, "HEAD")) {
            websDone(wp);
            return true;
        }
        websSetBackgroundWriter(wp, fileWriteEvent);
	return true;
}

文件下载例程来自:
http://blog.csdn.net/china_boys/article/details/8710450
http://download.csdn.net/download/china_boys/5173588#comment

/demo目录下需要用到的库文件以及配置文件

auth.txt 	est.h 		goahead.h 	js.h
libest.so 	libgo.so 	main.c 		me.h
osdep.h 	route.txt

上传过大文件的时候,会直接出现找不到接口的网页报错;
修改上传文件的限制:
src/http.c/parseHeaders()

//if (wp->rxLen > ME_GOAHEAD_LIMIT_POST) {
if (wp->rxLen > ME_GOAHEAD_LIMIT_UPLOAD) {
	websError(wp, HTTP_CODE_REQUEST_TOO_LARGE | WEBS_CLOSE, "Too big");
	return;
}

其中
#define ME_GOAHEAD_LIMIT_POST 16384
#define ME_GOAHEAD_LIMIT_UPLOAD 204800000

这里直接用 ME_GOAHEAD_LIMIT_UPLOAD 替换掉原来的 ME_GOAHEAD_LIMIT_POST;
重新更新应用程序的动态库 libest.solibgo.so 实现更大文件的上传;

实际运行时别漏掉添加动态库的搜索路径

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值