扩展mod_helloworld -- 使用stdio-like IO

扩展mod_helloworld -- 使用stdio-like IO2008-11-10 22:19上一篇文章我介绍了如何编写第一个Apache模块,也是最简单的模块mod_helloworld,这里我们要对mod_helloworld进行一些简单的扩展。

这里我们还是来举一个例子,这个例子做的事情会比上一篇文章中介绍的mod_helloworld模块做的事情要多,但编写模块的整体框架不变,我们只是在处理函数中多做了一些事情。

我们扩展的mod_helloworld模块功能要实现的是根据客户端请求从服务器本地读取文件内容然后反馈给客户端。

要实现这个功能,我们要用到request_rec数据结构中的filename字段,它表示了客户端请求文件的文件名,我们还使用了文件信息对象来实现这一过程的优化。处理函数代码如下:

static int helloworld_handler(request_rec *r)
{
apr_file_t *fd;
apr_size_t sz;
apr_status_t rv;

if (r->filename == NULL) {
ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, "Incomplete request_rec!") ;
return HTTP_INTERNAL_SERVER_ERROR ;
}
ap_set_content_type(r, "text/html;charset=ascii");

/* Now we can usefully set some additional headers from file info
* (1) Content-Length
* (2) Last-Modified
*/
ap_set_content_length(r, r->finfo.size);
if (r->finfo.mtime) {
char *datestring = apr_palloc(r->pool, APR_RFC822_DATE_LEN);
apr_rfc822_date(datestring, r->finfo.mtime);
apr_table_setn(r->headers_out, "Last-Modified", datestring);
}
rv = apr_file_open(&fd, r->filename, APR_READ|APR_SHARELOCK|APR_SENDFILE_ENABLED, APR_OS_DEFAULT, r->pool);
if (rv != APR_SUCCESS) {
ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, "can't open %s", r->filename);
return HTTP_NOT_FOUND ;
}
ap_send_fd(fd, r, 0, r->finfo.size, &sz);
/* file_close here is purely optional. If we omit it, APR will close
* the file for us when r is destroyed, because apr_file_open
* registered a close on r->pool.
*/
apr_file_close(fd);
return OK;
}

这里的ap_log_rerror是登记日志的函数,他登记的是request类型的日志。

r->finfo中包含了请求文件的统计信息。根据r->finfo.mtime设置Last-Modified,可以使浏览器在请求文件时先检查缓存。

这里我们响应文件内容没有采用先读文件再使用ap_rwrite把文件内容发送出去的方式,而是使用了一个更简单的函数ap_send_fd,直接发送文件 

你可能感兴趣的:(helloworld)