嵌入式web服务器BOA源码解析

BOA是一个单进程的web服务器,支持CGI交互,浏览器每次发送一个POAT请求,BOA会对应fork一个CGI进程,数据发送完成后,CGI进程退出,尽管存在这样的进程创建和销毁的开销,但BOA仍然是一款轻量级的web服务器,适用于需要较为简单的web页面访问。下面对BOA的主要部分进行代码分析,包含GET和POST两种方法。
GET和POST对客户端请求数据的解析过程都差不多,GET主要的函数为init_get,而POST主要为init_cgi
1 GET
1.1 GET调用过程源码分析

if (request_block)
	fdset_update();
process_requests(server_s);
	read_header(current);
		read()//读取客户端发来的数据到req->client_stream
		//解析请求行,获取http版本和请求方法,URL
		process_logline()
		process_option_line()//解析每一行请求头并保存属性值
		process_header_end()
			unescape_uri()//如果请求行中有query_string,则解析
			clean_pathname()//确保URL中路径分隔符是'/'
			translate_uri()//解析出req->pathname,绝对路径
			req->status = WRITE;
            init_get(req);//获取请求的文件并发送
	//如果在init_get中已经发送完,则req->status = DONE;
	//process_get就不会执行了
	process_get() //WRITE 状态机
		调用系统write()发送get的文件
	free_request //释放这次请求
		release_mmap(req->mmap_entry_var);
			munmap()
		close() //关闭fd
init_get(req)
    //pathname是路径,一般会返回index.html
	//如果是文件,直接打开文件
	open(req->pathname, O_RDONLY);
	fstat(data_fd, &statbuf);//获取文件信息
	if (S_ISDIR(statbuf.st_mode))//路径
		data_fd = get_dir(req, &statbuf);//获取index.html	
	req->filesize = statbuf.st_size;
	//mmap映射文件
	req->mmap_entry_var = find_mmap(data_fd, &statbuf);
	req->data_mem = req->mmap_entry_var->mmap;
	send_r_request_ok(req);//copy响应行和头到req->buffer
	//copy响应体,也就是get的文件内容
	memcpy(req->buffer + req->buffer_end, req->data_mem, bytes);
	req_flush(req); //发送响应行,响应头,响应体

1.2 GET调用过程内存数据传输图
在这里插入图片描述2 POST
BOA针对POST方法会fork一个子进程进行CGI的输出,父子进程通过pipe进行通信,程序主要调用过程如下所示
2.1 POST代码执行过程

process_requests
	read_header(current);//READ_HEADER状态机
		process_header_end()
			unescape_uri()//如果请求行中有query_string,则解析
			clean_pathname()//确保URL中路径分隔符是'/'
			translate_uri()//解析出req->pathname,绝对路径
			//创建临时文件
			req->post_data_fd = create_temporary_file(1, NULL, 0);
		req->status = BODY_WRITE;
		req->header_line //执行请求体内容的开始
		req->header_end  //执行请求体内容的结束
	write_body(current);//BODY_WRITE状态机
		write(req->post_data_fd)//向临时文件中发送client的请求体
		req->header_line = req->header_end = req->buffer;
		init_cgi(req);
		    req->status = PIPE_READ;
			req->header_line = req->header_end =
                (req->buffer + BUFFER_SIZE / 2);
	read_from_pipe(current);//PIPE_READ状态机,从pipe中读取cgi写入的数据
		bytes_read = read(req->data_fd,req->header_end) 
		header_end += bytes_read
		req->status = PIPE_WRITE;
		process_cgi_header(req);
			send_r_request_ok(req);//响应行和头写入req->buffer
			dest = req->buffer + req->buffer_end;
			howmuch = req->header_end - req->header_line;
			memmove(dest, req->header_line, howmuch);
			req->buffer_end += howmuch;
			req->header_line = req->buffer + req->buffer_end;
            req->header_end = req->header_line;
			req_flush(req);//发送响应行、头、体
	write_from_pipe //PIPE_WRITE状态机
		write()
		return 0;
		
init_cgi(req);
	pipe(pipes)
	child_pid = fork();
	child 
		close(pipes[0]);
		dup2(pipes[1], STDOUT_FILENO)
		close(pipes[1]);
		//从标准输入中读取临时文件的内容,即client的请求体
		dup2(req->post_data_fd, STDIN_FILENO);
	    close(req->post_data_fd);
		execve(req->pathname, aargv, req->cgi_env);//执行cgi
	parent
		close(req->post_data_fd); 
        eq->post_data_fd = 0;
		close(pipes[1]);
        req->data_fd = pipes[0];//可以从pipe中读取cgi写入的响应体
		req->status = PIPE_READ;

2.2 POST程序执行过程中内存中数据流图
在这里插入图片描述

  • 1
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值