[项目][WebServer][读取请求 & 解析请求]详细讲解


1.ReadLine

  • 读取的基本单位:按照行来进行读取
  • 不同平台,对行分隔符的处理可能不同,所以要有一个函数可以统一处理不同平台的情况,兼容各种行分隔符
    • \r\n
    • \r
    • \n
  • 本函数将统一转化为\n结尾
  • [函数实现] -> 见[Util类]实现

2.RecvRequest

  • 读取出错处理:
    • 每一步读取都有可能出错,只有在请求行请求报头都正常读取的情况下,才去解析请求
void RecvRequest()
{
    if ((!RecvRequestLine()) && (!RecvRequestHeader()))
    {
        ParseRequestLine();
        ParseRequestHeader();
        RecvRequestBody();
    }
}

bool RecvRequestLine()
{
    if (Util::ReadLine(_sock, _request.request_line) > 0)
    {
        _request.request_line.resize(_request.request_line.size() - 1); // 去掉结尾换行符
        LOG(DEBUG, _request.request_line);
    }
    else
    {
        _stop = true; // 读取出错,不往下继续执行了
    }

    return _stop;
}

bool RecvRequestHeader()
{
    std::string line;
    while(true)
    {
        line.clear();
        if(Util::ReadLine(_sock, line) <= 0)
        {
            _stop = true; // 处理读取出错
            break;
        }

        if(line == "\n")
        {
            _request.blank = line;
            break;
        }

        line.resize(line.size() - 1); // 去掉结尾换行符
        _request.request_header.push_back(line);
    }

    return _stop;
}

3.ParseRequest

  • 要将请求行中的内容单独提出出来,可以用string.substr提取字串,但略显繁琐
    • stringstream类重载了operator>>可以将内部内容格式化输入到缓冲区中
      • 此类可以使用输入和输出流上允许的任何操作从流中插入/提取字符
      • 所以此处用法类似cin
  • 请求报头处,可以用unordered_map存储键值对,以便需要时拿取
void ParseRequestLine()
{
    std::stringstream ss(_request.request_line); // TODO 可整理
    ss >> _request.method >> _request.uri >> _request.version;

    // 可能不是所有人都严格遵守标准,所以将method统一转化为大写
    std::transform(_request.method.begin(), _request.method.end(), _request.method.begin(), ::toupper);
}

void ParseRequestHeader()
{
    std::string key;
    std::string value;
    for(auto& str : _request.request_header)
    {
        if(Util::CutString(str, key, value, SEP))
        {
            _request.headerMap[key] = value;
        }
    }
}

4.RecvRequestBody

  • GET方法通过url传参,POST方法通过正文传参**,所以是否要接收请求正文,还要判断此次请求是什么方法**
bool IsRecvRequestBody()
{
    std::string& method = _request.method;
    if(method == "POST")
    {
        _request.content_length = atoi(_request.headerMap["Content-Length"].c_str());
        return true;
    }

    return false;
}

bool RecvRequestBody()
{
    if(IsRecvRequestBody())
    {
        size_t length = _request.content_length;
        auto& body = _request.request_body;

        char ch = 'K';
        while(length)
        {
            ssize_t s = recv(_sock, &ch, 1, 0);
            if(s > 0)
            {
                body.push_back(ch);
                length--;
            }
            else
            {
                _stop = true; // 处理读取出错
                break;
            }
        }

        LOG(DEBUG, body);
    }

    return _stop;
}
评论 18
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

DieSnowK

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值