Boost.Asio学习之简单的HTTP服务器的完善

参考源代码:
https://www.boost.org/doc/libs/1_61_0/doc/html/boost_asio/examples/cpp11_examples.html

以上链接里面的源代码至少有下面两个问题:
1.只解析了http协议的头部信息(header)。
2.没有对tcp数据包进行合并的处理,如果客户端的tcp数据是分包发过来的,该代码的解析会出错,所以这是不可预料的错误。

以下是修改后的部分代码:

1.在 request.hpp 中添加两个成员变量

        std::string short_uri;//客户端请求的uri,去掉‘?’后面的参数
        std::vector<header> params;//客户端请求所带的参数,包括get和post表单里的参数

2.在 request_parser.cpp 里添加成员方法 parse_param ,用来获得表单提交的参数:

    void request_parser::parse_param(request& req, std::string& data_)
    {
        //开始解析get参数
        int index = req.uri.find_first_of("?");
        if (index >= 0)
        {
            req.short_uri = req.uri.substr(0, index);

            std::string param_str = req.uri.substr(index + 1, req.uri.size());

            std::vector<std::string> split_result;
            boost::split(split_result, param_str, boost::is_any_of("&"));

            for (int i = 0; i < split_result.size(); i++)
            {
                std::vector<std::string> split_result_temp;
                boost::split(split_result_temp, split_result.at(i), boost::is_any_of("="));
                if (split_result_temp.size() >= 2)
                {
                    req.params.push_back(header());
                    req.params.back().name = split_result_temp.at(0);
                    req.params.back().value = split_result_temp.at(1);
                }
            }
        }
        else
        {
            req.short_uri = req.uri;
        }
        //解析get参数结束

        std::string content_type;
        for (int i = 0; i < req.headers.size(); i++)
        {
            if (boost::algorithm::iequals(req.headers[i].name, "content_type"))
            {
                content_type = req.headers[i].value;
                break;
            }
        }

        int index_content_type = content_type.find_first_of(';');
        if (index_content_type > 0)
        {
            content_type = content_type.substr(0, index_content_type);
        }

        //开始解析post参数
        if (boost::algorithm::iequals(req.method, "post")
            && boost::algorithm::iequals(content_type, "multipart/form-data"))
        {
            const char* find_str = "\nContent-Disposition: form-data; name=\"";
            int index = 0;
            auto it = boost::algorithm::ifind_nth(data_, find_str, index);
            while (!it.empty())
            {
                req.params.push_back(header());
                auto it_temp = it.end();
                while (it_temp != data_.end())
                {
                    if (*it_temp == '\"')
                    {
                        break;
                    }

                    req.params.back().name.push_back(*it_temp);
                    it_temp++;
                }

                it_temp++;
                while (*it_temp == '\r' || *it_temp == '\n')
                {
                    it_temp++;
                }

                while (it_temp != data_.end())
                {
                    if (*it_temp == '\r')
                    {
                        break;
                    }

                    req.params.back().value.push_back(*it_temp);
                    it_temp++;
                }

                index++;
                it = boost::algorithm::ifind_nth(data_, find_str, index);
            }
        }
        //解析post参数结束
    }

3.在 connection.hpp 里添加两个成员变量:

        std::string data_;//合并tcp数据包后的数据
        bool is_header_parsed;//是否已经解析过header信息

4.对 connection.cpp 里的 do_read() 方法修改如下(关键就是修改这个方法,让它能够合并tcp数据包)

    void connection::do_read()
    {
        auto self(shared_from_this());
        socket_.async_read_some(boost::asio::buffer(buffer_),
            [this, self](boost::system::error_code ec, std::size_t bytes_transferred)
        {
            if (!ec)
            {
                std::string this_data(buffer_.data(), bytes_transferred);
                data_.append(this_data);

                int header_end = data_.find("\r\n\r\n");//http协议的头部结束标识
                if (header_end < 0)
                {
                    do_read();
                    return;
                }

                request_parser::result_type result;
                if (!is_header_parsed)
                {
                    std::tie(result, std::ignore) = request_parser_.parse(
                        request_, data_.begin(), data_.end());
                }

                if (is_header_parsed || result == request_parser::good)
                {
                    is_header_parsed = true;

                    std::string length_str;
                    for (int i = 0; i < request_.headers.size(); i++)
                    {
                        if (boost::algorithm::iequals(request_.headers[i].name, "content-length"))
                        {
                            length_str = request_.headers[i].value;
                            break;
                        }
                    }

                    int content_length = 0;
                    if (!length_str.empty())
                    {
                        content_length = atoi(length_str.c_str());
                    }

                    if (data_.size() < (content_length + header_end + 4))
                    {//数据不全,继续接受tcp数据
                        do_read();
                        return;
                    }

                    //data_ = utf8_to_ascii(data_);//

                    request_parser_.parse_param(request_, data_);//新加的方法

                    request_handler_.handle_request(request_, reply_);
                    do_write();
                }
                else if (result == request_parser::bad)
                {
                    reply_ = reply::stock_reply(reply::bad_request);
                    do_write();
                }
                else
                {
                    do_read();
                }
            }
            else if (ec != boost::asio::error::operation_aborted)
            {
                connection_manager_.stop(shared_from_this());
            }
        });
    }

猜你喜欢

转载自blog.csdn.net/leon528/article/details/81485916