1 /*
2 * Copyright (C) 2019 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #include <https/HTTPRequestResponse.h>
18
19 #include <cerrno>
20 #include <iostream>
21 #include <regex>
22
HTTPRequestResponse()23 HTTPRequestResponse::HTTPRequestResponse()
24 : mInitCheck(-ENODEV),
25 mContentLength(0) {
26 }
27
setTo(const uint8_t * data,size_t size)28 int HTTPRequestResponse::setTo(const uint8_t *data, size_t size) {
29 mInitCheck = -EINVAL;
30
31 bool sawEmptyLine = false;
32
33 size_t start = 0;
34 while (start < size) {
35 size_t end = start;
36 while (end + 1 < size && memcmp(&data[end], "\r\n", 2)) {
37 ++end;
38 }
39
40 if ((end + 1) == size) {
41 return mInitCheck;
42 }
43
44 std::string line(
45 reinterpret_cast<const char *>(&data[start]), end - start);
46
47 if (start == 0) {
48 // Parse the request/response line.
49
50 if (!parseRequestResponseLine(line)) {
51 return mInitCheck;
52 }
53
54 } else if (end > start) {
55 std::regex re("([a-zA-Z0-9-]+): (.*)");
56 std::smatch match;
57
58 if (!std::regex_match(line, match, re)) {
59 return mInitCheck;
60 }
61
62 auto key = match[1];
63 auto value = match[2];
64 mHeaders[key] = value;
65 }
66
67 sawEmptyLine = line.empty();
68
69 start = end + 2;
70 }
71
72 if (!sawEmptyLine) {
73 return mInitCheck;
74 }
75
76 std::string stringValue;
77 if (getHeaderField("Content-Length", &stringValue)) {
78 char *end;
79 unsigned long value = strtoul(stringValue.c_str(), &end, 10);
80
81 if (end == stringValue.c_str() || *end != '\0') {
82 return mInitCheck;
83 }
84
85 mContentLength = value;
86 }
87
88 mInitCheck = 0;
89 return mInitCheck;
90 }
91
initCheck() const92 int HTTPRequestResponse::initCheck() const {
93 return mInitCheck;
94 }
95
getHeaderField(std::string_view key,std::string * value) const96 bool HTTPRequestResponse::getHeaderField(
97 std::string_view key, std::string *value) const {
98 auto it = mHeaders.find(std::string(key));
99
100 if (it != mHeaders.end()) {
101 *value = it->second;
102 return true;
103 }
104
105 return false;
106 }
107
getContentLength() const108 size_t HTTPRequestResponse::getContentLength() const {
109 return mContentLength;
110 }
111
112 ////////////////////////////////////////////////////////////////////////////////
113
getMethod() const114 std::string HTTPRequest::getMethod() const {
115 return mMethod;
116 }
117
getPath() const118 std::string HTTPRequest::getPath() const {
119 return mPath;
120 }
121
getVersion() const122 std::string HTTPRequest::getVersion() const {
123 return mVersion;
124 }
125
parseRequestResponseLine(const std::string & line)126 bool HTTPRequest::parseRequestResponseLine(const std::string &line) {
127 std::regex re("(GET|HEAD) ([a-zA-Z_/.0-9?&=]+) (HTTP/1\\.1)");
128 std::smatch match;
129
130 if (!std::regex_match(line, match, re)) {
131 return false;
132 }
133
134 mMethod = match[1];
135 mPath = match[2];
136 mVersion = match[3];
137
138 return true;
139 }
140
141 ////////////////////////////////////////////////////////////////////////////////
142
getVersion() const143 std::string HTTPResponse::getVersion() const {
144 return mVersion;
145 }
146
getStatusCode() const147 int32_t HTTPResponse::getStatusCode() const {
148 return mStatusCode;
149 }
150
getStatusMessage() const151 std::string HTTPResponse::getStatusMessage() const {
152 return mStatusMessage;
153 }
154
parseRequestResponseLine(const std::string & line)155 bool HTTPResponse::parseRequestResponseLine(const std::string &line) {
156 std::regex re(
157 "(HTTP/1\\.1) ([1-9][0-9][0-9]) ([a-zA-Z _0-9.]+)");
158
159 std::smatch match;
160
161 if (!std::regex_match(line, match, re)) {
162 return false;
163 }
164
165 mVersion = match[1];
166 std::string statusString = match[2];
167 mStatusMessage = match[3];
168
169 mStatusCode =
170 static_cast<int32_t>(strtol(statusString.c_str(), nullptr, 10));
171
172 return true;
173 }
174
175