markparticle / WebServer

C++ Linux WebServer服务器
Apache License 2.0
3.58k stars 733 forks source link

httprequest.cpp中的ParseFromUrlencoded_函数有问题 #97

Open InitialZJ opened 11 months ago

InitialZJ commented 11 months ago

httprequest.cpp 中的 ParseFromUrlencoded_ 函数有问题,无法解析加密字符,比如 # 字符在服务器端收到的是 %23 ,理论上应该解析为十进制数 35 ,然后直接替换 body_[i] 的值替换为 35 对应的字符 #

有三个函数需要修改,修改后的代码如下

void HttpRequest::ParseFromUrlencoded_() {
  if (body_.size() == 0) {
    return;
  }

  std::string key, value;
  int num = 0;
  int n = body_.size();
  int i = 0, j = 0;

  for (; i < n; i++) {
    char ch = body_[i];
    switch (ch) {
      case '=':
        key = body_.substr(j, i - j);
        j = i + 1;
        break;
      case '+':
        body_[i] = ' ';
        break;
      case '%':
        num = ConverHex(body_[i + 1]) * 16 + ConverHex(body_[i + 2]);
        body_[i] = num;
        body_.erase(body_.begin() + i + 1);
        body_.erase(body_.begin() + i + 1);
        n -= 2;
        break;
      case '&':
        value = body_.substr(j, i - j);
        j = i + 1;
        post_[key] = value;
        LOG_DEBUG("%s = %s", key.c_str(), value.c_str());
        break;
      default:
        break;
    }
  }
  assert(j <= i);
  if (post_.find(key) == post_.end() && j < i) {
    value = body_.substr(j, i - j);
    post_[key] = value;
  }
}
int HttpRequest::ConverHex(char ch) {
  unsigned int y;
  if (ch >= 'A' && ch <= 'F') {
    y = ch - 'A' + 10;
  } else if (ch >= 'a' && ch <= 'f') {
    y = ch - 'a' + 10;
  } else if (ch >= '0' && ch <= '9') {
    y = ch - '0';
  } else {
    assert(0);
  }
  return y;
}
bool HttpRequest::parse(Buffer& buff) {
  const char CRLF[] = "\r\n";
  if (buff.ReadableBytes() <= 0) {
    return false;
  }
  while (buff.ReadableBytes() && state_ != FINISH) {
    const char* lineEnd =
        std::search(buff.Peek(), buff.BeginWriteConst(), CRLF, CRLF + 2);
    std::string line(buff.Peek(), lineEnd);
    switch (state_) {
      case REQUEST_LINE:
        if (!ParseRequestLine_(line)) {
          return false;
        }
        ParsePath_();
        break;
      case HEADERS:
        ParseHeader_(line);
        if (buff.ReadableBytes() <= 2) {
          state_ = FINISH;
        }
        break;
      case BODY:
        ParseBody_(line);
        break;
      default:
        break;
    }
    if (lineEnd == buff.BeginWrite()) {
      buff.RetrieveUntil(lineEnd);
      break;
    }
    buff.RetrieveUntil(lineEnd + 2);
  }
  LOG_DEBUG("[%s], [%s], [%s]", method_.c_str(), path_.c_str(),
            version_.c_str());
  return true;
}
Cwj1212 commented 6 months ago

我也发现了,好像确实错了。