http 协议目录操作--mongoose

17 篇文章 64 订阅
11 篇文章 0 订阅

        前几篇文章已经介绍了文件的下载与上传,操作的都是文件,而如果是操作目录呢,应该怎么做呢?这里介绍的还是 mongoose 源码接口。先看实际操作的效果:

这里有两个目录,点击后可以进到目录里:

 

可以点击查看目录里文件的内容:

 要实现目录的展示,就加了一段代码:

整个 handleRequest() 函数的代码为:

void handleRequest(struct mg_connection *connection, int32_t event, void *data)
{
    struct http_message* msg = (struct http_message*)data;
 
    std::string uri(msg->uri.p, msg->uri.len);
    tracef("connect from ip: %s, uri = %s\n", inet_ntoa(connection->sa.sin.sin_addr), uri.c_str());

    //设置资源根目录
    if(uri == "/")
    {
        struct mg_serve_http_opts opts;
        memset(&opts, 0, sizeof(opts));
        opts.enable_directory_listing = "yes";
        opts.document_root = "./";
        mg_serve_http(connection, msg, opts);

        //第一次请求根目录时,可以不往下处理了
        return;
    }
 
    CHttpResponse response;

    //保存请求头,用于应答
    for (int32_t index = 0; index < MG_MAX_HTTP_HEADERS; ++index) 
    {
        if (msg->header_names[index].p == nullptr || msg->header_names[index].len == 0
            || std::string(msg->header_names[index].p,msg->header_names[index].len).find("Accept") != std::string::npos) 
        {
            continue;
        }
 
        std::string header(msg->header_names[index].p, msg->header_names[index].len);
        std::string value(msg->header_values[index].p, msg->header_values[index].len);

        response.setHead(header.c_str(), value.c_str());
    }

    //请求的方法,GET、POST、PUT等
    std::string method(msg->method.p, msg->method.len);
    tracef("request method: %s\n", method.c_str());
    
    std::string fileName = uri.substr(1);
    if(fileName.at(fileName.length() - 1) == '/') //目录最后多一个"/"
    {
        fileName = fileName.substr(0, fileName.length() - 1);
    }
    
    struct stat st;

    //文件或目录存在
    if(lstat(fileName.c_str(), &st) == 0)
    {
        if(S_ISDIR(st.st_mode)) //目录
        {
            tracef("%s is a dirctory\n", fileName.c_str());
            struct mg_serve_http_opts opts;
            memset(&opts, 0, sizeof(opts));
            opts.enable_directory_listing = "yes";
            opts.document_root = "./";
            mg_serve_http(connection, msg, opts);
        }
        else if(S_ISREG(st.st_mode)) //普通文件
        {
            tracef("%s is a regular file\n", fileName.c_str());
            if(method == "GET") 
            {   
                if(!isGiantFile(fileName.c_str()))
                {
                    if(response.setBody(fileName.c_str()) == 0) //文件大小为0直接返回错误信息
                    {
                        mg_http_send_error(connection, 500, "file length is 0");
                        return;
                    }
                    std::string content;
                    response.getContent(content);
                    mg_send(connection, content.c_str(), content.length());            
                }
                else 
                {
                    //处理大文件,采用分块传输的方式
                    std::string headers;
                    headers.append("HTTP/1.1 200 ok").append("\r\n");
                    response.getHead(headers);
                    headers.append("Content-Type: application/octet-stream").append("\r\n");
                    headers.append("Transfer-Encoding: chunked").append("\r\n").append("\r\n");
                    mg_send(connection, headers.c_str(), headers.length());

                    sendGiantFile(connection, fileName.c_str());
                }
            }           
        }
    }
    else
    {
        mg_http_send_error(connection, 404, NULL);
    }  
}

 这里只是简单地处理了目录和普通文件的区别,还有其他如字符设备文件、块设备文件、链接文件、socket 文件这里不作处理。

函数原型:

void mg_serve_http(struct mg_connection *nc, struct http_message *hm, struct mg_serve_http_opts opts) 

就是用来设置目录的,我们可以简单看下这个函数做了什么。

函数的第三个参数其实可以不给成员赋值,这里都赋了默认值 。其实这个参数最主要关心两个成员:opts.document_root 和 opts.enable_directory_listing。opts.document_root 主要是标记起点,可以理解为从哪里去查找文件或目录来进行展示;opts.enable_directory_listing 可以理解为是否要展示。

接下来的函数 mg_uri_to_local_path(hm, &opts, &path, &path_info) 就是要把请求过来的目录(uri)进行本地化处理,因为我们请求目录的时候的 uri 是这样的: 

http://10.91.90.99:8190/compile/

那服务器必须要把目标目录 compile 进行本地化,最后得出它是在哪个目录下,如用 GDB 跟踪调试时,当请求目录是 compile 时,实际得出的是:

 这样就得出了 compile 的相对路径了,那程序本身就可以访问这个目录。

MG_INTERNAL void mg_send_http_file(struct mg_connection *nc, char *path,
                                   const struct mg_str *path_info,
                                   struct http_message *hm,
                                   struct mg_serve_http_opts *opts) 

 而这个函数最主要是做什么呢?它其实就是显示指定目录下文件列表了:

static void mg_send_directory_listing(struct mg_connection *nc, const char *dir,
                                      struct http_message *hm,
                                      struct mg_serve_http_opts *opts)

 这个函数里就是收集指定目录下的文件信息了,然后它会将它们组成 html 的形式进行发送,浏览器收到后就以 html 页面的形式展示,以 chunked 方式发送,这个 html 形式如下:

 源码片段如下:

这样目录操作就已经正常了。 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值