blob: 3f050658915f186c58696cd6bcf3aeb2d1aec0ad [file] [log] [blame]
/*
* Copyright (C) 2019 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <https/HTTPRequestResponse.h>
#include <cerrno>
#include <iostream>
#include <regex>
HTTPRequestResponse::HTTPRequestResponse()
: mInitCheck(-ENODEV),
mContentLength(0) {
}
int HTTPRequestResponse::setTo(const uint8_t *data, size_t size) {
mInitCheck = -EINVAL;
bool sawEmptyLine = false;
size_t start = 0;
while (start < size) {
size_t end = start;
while (end + 1 < size && memcmp(&data[end], "\r\n", 2)) {
++end;
}
if ((end + 1) == size) {
return mInitCheck;
}
std::string line(
reinterpret_cast<const char *>(&data[start]), end - start);
if (start == 0) {
// Parse the request/response line.
if (!parseRequestResponseLine(line)) {
return mInitCheck;
}
} else if (end > start) {
std::regex re("([a-zA-Z0-9-]+): (.*)");
std::smatch match;
if (!std::regex_match(line, match, re)) {
return mInitCheck;
}
auto key = match[1];
auto value = match[2];
mHeaders[key] = value;
}
sawEmptyLine = line.empty();
start = end + 2;
}
if (!sawEmptyLine) {
return mInitCheck;
}
std::string stringValue;
if (getHeaderField("Content-Length", &stringValue)) {
char *end;
unsigned long value = strtoul(stringValue.c_str(), &end, 10);
if (end == stringValue.c_str() || *end != '\0') {
return mInitCheck;
}
mContentLength = value;
}
mInitCheck = 0;
return mInitCheck;
}
int HTTPRequestResponse::initCheck() const {
return mInitCheck;
}
bool HTTPRequestResponse::getHeaderField(
std::string_view key, std::string *value) const {
auto it = mHeaders.find(std::string(key));
if (it != mHeaders.end()) {
*value = it->second;
return true;
}
return false;
}
size_t HTTPRequestResponse::getContentLength() const {
return mContentLength;
}
////////////////////////////////////////////////////////////////////////////////
std::string HTTPRequest::getMethod() const {
return mMethod;
}
std::string HTTPRequest::getPath() const {
return mPath;
}
std::string HTTPRequest::getVersion() const {
return mVersion;
}
bool HTTPRequest::parseRequestResponseLine(const std::string &line) {
std::regex re("(GET|HEAD) ([a-zA-Z_/.0-9?&=]+) (HTTP/1\\.1)");
std::smatch match;
if (!std::regex_match(line, match, re)) {
return false;
}
mMethod = match[1];
mPath = match[2];
mVersion = match[3];
return true;
}
////////////////////////////////////////////////////////////////////////////////
std::string HTTPResponse::getVersion() const {
return mVersion;
}
int32_t HTTPResponse::getStatusCode() const {
return mStatusCode;
}
std::string HTTPResponse::getStatusMessage() const {
return mStatusMessage;
}
bool HTTPResponse::parseRequestResponseLine(const std::string &line) {
std::regex re(
"(HTTP/1\\.1) ([1-9][0-9][0-9]) ([a-zA-Z _0-9.]+)");
std::smatch match;
if (!std::regex_match(line, match, re)) {
return false;
}
mVersion = match[1];
std::string statusString = match[2];
mStatusMessage = match[3];
mStatusCode =
static_cast<int32_t>(strtol(statusString.c_str(), nullptr, 10));
return true;
}