23 #include <ns3/packet.h>
25 #include "ns3/http-header.h"
44 HttpHeader::CreateRequest(
45 const std::string& url,
46 const std::string& method,
47 const std::map<std::string, std::string>& parameters,
48 const std::vector<std::string>& headers)
55 for (
const auto& parameter : parameters)
57 if (!
first) body +=
"&";
63 CreateRequest(url, method, body, headers);
67 HttpHeader::CreateRequest(
68 const std::string& url,
69 const std::string& method,
70 const std::string& body,
71 const std::vector<std::string>& headers)
78 std::vector<uint8_t>(body.begin(), body.end()),
84 HttpHeader::CreateRequest(
85 const std::string& url,
86 const std::string& method,
87 const std::vector<uint8_t>& body,
88 const std::vector<std::string>& headers
96 std::string headerData = method +
" " + m_path +
" HTTP/1.1\r\n";
98 for (
const std::string& header : headers){
99 headerData += header +
"\r\n";
102 headerData +=
"Host: " + m_domain +
"\r\n"
107 headerData +=
"Accept-Language: en-us,en;q=0.5\r\n";
108 headerData +=
"Accept-Encoding: gzip,deflate\r\n";
109 headerData +=
"Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7\r\n";
110 headerData +=
"Keep-Alive: 300\r\n";
111 headerData +=
"Connection: keep-alive\r\n";
112 headerData +=
"Cookie: PHPSESSID=r2t5uvjq435r4q7ib3vtdjq120\r\n";
113 headerData +=
"Pragma: no-cache\r\n";
114 headerData +=
"Cache-Control: no-cache\r\n" "\r\n";
122 std::vector<uint8_t> requestData(headerData.begin(), headerData.end());
123 m_allData = requestData;
126 m_allData.insert(m_allData.end(), body.begin(), body.end());
127 m_payload.insert(m_payload.end(), body.begin(), body.end());
134 m_headerSize = headerData.size();
135 m_contentLength = m_payload.size();
141 HttpHeader::CreateResponse(
143 const std::string& body,
144 const std::vector<std::string>& headers)
148 std::vector<uint8_t>(body.begin(), body.end()),
154 HttpHeader::CreateResponse(
156 const std::vector<uint8_t>& body,
157 const std::vector<std::string>& headers
160 std::string bodyString = std::string{body.begin(), body.end()};
167 std::string headerData =
"HTTP/1.1 " +
std::to_string(m_status) +
" " + GetStatusString() +
"\r\n";
169 for (
const std::string& header : headers){
170 headerData += header +
"\r\n";
173 headerData +=
"Server: nginx/1.17.0 (Ubuntu)\r\n"
178 headerData +=
"Date: Sat, 28 Nov 2021 04:36:25 GMT\r\n";
179 headerData +=
"Connection: close\r\n";
180 headerData +=
"Pragma: public\r\n";
181 headerData +=
"Etag: pub1259380237;gz\r\n";
182 headerData +=
"Cache-Control: max-age=3600, public\r\n";
183 headerData +=
"Content-Encoding: gzip\r\n";
184 headerData +=
"Vary: Accept-Encoding, Cookie\r\n" "\r\n";
191 std::vector<uint8_t> requestData(headerData.begin(), headerData.end());
192 m_allData = requestData;
195 m_allData.insert(m_allData.end(), body.begin(), body.end());
196 m_payload.insert(m_payload.end(), body.begin(), body.end());
198 NS_LOG_FUNCTION(
this <<
"m_allData.size(): " << m_allData.size() << GetPayloadString() );
199 m_contentLength = m_allData.size();
204 HttpHeader::ParseResponse()
206 constexpr std::uint8_t crlf[] = {
'\r',
'\n'};
207 std::vector<std::uint8_t> responseData = m_allData;
208 bool firstLine =
true;
209 bool parsedHeaders =
false;
210 bool contentLengthReceived =
false;
211 bool chunkedResponse =
false;
212 std::size_t expectedChunkSize = 0;
213 bool removeCrlfAfterChunk =
false;
220 const auto i = std::search(responseData.begin(), responseData.end(), std::begin(crlf), std::end(crlf));
223 if (i == responseData.end())
break;
225 const std::string line(responseData.begin(), i);
226 responseData.erase(responseData.begin(), i + 2);
229 NS_LOG_FUNCTION(
this <<
"221: " <<
"\t" << line << line.size() << m_headerSize );
234 parsedHeaders =
true;
240 m_headerSize += line.size();
242 std::string::size_type lastPos = 0;
243 const auto length = line.length();
244 std::vector<std::string> parts;
247 while (lastPos < length + 1)
249 auto pos = line.find(
' ', lastPos);
250 if (pos == std::string::npos) pos = length;
253 parts.emplace_back(line.data() + lastPos,
254 static_cast<std::vector<std::string>::size_type
>(pos) - lastPos);
261 if (parts.size() >= 2){
262 if(parts[0] ==
"HTTP/1.1"){
263 m_status = std::stoi(parts[1]);
265 SetMethod( parts[0] );
272 m_headers.push_back(line);
273 m_headerSize += line.size() + 1;
275 const auto pos = line.find(
':');
277 if (pos != std::string::npos)
279 std::string headerName = line.substr(0, pos);
280 std::string headerValue = line.substr(pos + 1);
283 headerValue.erase(headerValue.begin(),
284 std::find_if(headerValue.begin(), headerValue.end(),
285 [](
int c) {return !std::isspace(c);}));
288 headerValue.erase(std::find_if(headerValue.rbegin(), headerValue.rend(),
289 [](
int c) {return !std::isspace(c);}).base(),
292 if (headerName ==
"Content-Length")
294 m_contentLength = std::stoul(headerValue);
295 contentLengthReceived =
true;
296 m_allData.reserve(m_contentLength);
298 else if (headerName ==
"Request URI")
300 m_request_uri = headerValue;
302 else if (headerName ==
"Transfer-Encoding")
304 if (headerValue ==
"chunked")
305 chunkedResponse =
true;
309 else if (headerName ==
"Host")
311 m_uri = headerValue + m_uri;
324 bool dataReceived =
false;
330 if (expectedChunkSize > 0)
332 const auto toWrite =
std::min(expectedChunkSize, responseData.size());
333 m_payload.insert(m_payload.end(), responseData.begin(), responseData.begin() +
static_cast<ptrdiff_t
>(toWrite));
334 m_allData.insert(m_allData.end(), responseData.begin(), responseData.begin() +
static_cast<ptrdiff_t
>(toWrite));
335 responseData.erase(responseData.begin(), responseData.begin() +
static_cast<ptrdiff_t
>(toWrite));
336 expectedChunkSize -= toWrite;
339 if (expectedChunkSize == 0) removeCrlfAfterChunk =
true;
340 if (responseData.empty())
break;
344 if (removeCrlfAfterChunk)
346 if (responseData.size() >= 2)
348 removeCrlfAfterChunk =
false;
349 responseData.erase(responseData.begin(), responseData.begin() + 2);
354 const auto i = std::search(responseData.begin(), responseData.end(), std::begin(crlf), std::end(crlf));
356 if (i == responseData.end())
break;
358 const std::string line(responseData.begin(), i);
359 responseData.erase(responseData.begin(), i + 2);
361 expectedChunkSize = std::stoul(line,
nullptr, 16);
363 if (expectedChunkSize == 0)
377 m_payload.insert(m_payload.end(), responseData.begin(), responseData.end());
378 responseData.clear();
383 if(m_contentLength > m_payload.size()){
386 }
else if(m_contentLength < m_payload.size()){
387 NS_LOG_FUNCTION(
this <<
"Extract header data from the rest of the payload!");
388 std::vector<uint8_t> vec2(m_payload.begin(), m_payload.begin()+m_contentLength);
395 std::string payload = std::string{m_payload.begin(), m_payload.end()};
396 NS_LOG_FUNCTION(
this <<
"287!!!!!!!" << chunkedResponse << contentLengthReceived << payload);
404 std::string payload = std::string{m_payload.begin(), m_payload.end()};
405 NS_LOG_FUNCTION(
this << parsedHeaders << payload <<
"374m_headerSize:" << m_headerSize <<
"m_contentLength:" << m_contentLength );
410 HttpHeader::GetHeaderString(){
414 output.assign(m_allData.begin(), m_allData.end());
421 HttpHeader::SetHeaderString(std::string input){
424 std::vector<uint8_t> vec(input.begin(), input.end());
427 if(m_headers.size() == 0 && m_payload.size() == 0) ParseResponse();
430 "input.size(): " << input.size() <<
"\n" <<
431 "Header-Length: " << m_headerSize <<
"\n" <<
432 "Content-Length: " << m_contentLength <<
"\n"
433 "Headers.size():" << m_headers.size() <<
"\n"
479 HttpHeader::GetTypeId ()
483 .AddConstructor<HttpHeader> ()
489 HttpHeader::GetInstanceTypeId ()
const
495 HttpHeader::GetSerializedSize ()
const
497 return (m_headerSize + m_contentLength) *
sizeof(uint8_t);
501 HttpHeader::Serialize (Buffer::Iterator
start)
const
506 <<
"m_contentLength: " << m_contentLength
509 start.WriteU32 (m_contentLength);
511 char tmpBuffer [ m_contentLength ];
512 std::copy(m_allData.begin(), m_allData.end(), tmpBuffer);
513 start.Write ((uint8_t *)tmpBuffer, m_contentLength);
518 HttpHeader::Deserialize (Buffer::Iterator
start)
521 Buffer::Iterator i =
start;
523 m_contentLength = i.ReadU32 ();
528 if(m_contentLength >
start.GetSize()){
529 return i.GetDistanceFrom (
start);
536 if(
start.GetSize() < i.GetDistanceFrom (
start) + m_contentLength){
537 return i.GetDistanceFrom (
start);
540 char tmpBuffer [ m_contentLength ];
541 i.Read ((uint8_t*)tmpBuffer, m_contentLength);
543 std::vector<uint8_t> receivedData(tmpBuffer, tmpBuffer + m_contentLength /
sizeof(
char));
544 m_allData = receivedData;
546 uint32_t dist = i.GetDistanceFrom (
start);
548 NS_ASSERT (dist == GetSerializedSize ());
550 if(m_headers.size() == 0 && m_payload.size() == 0){
561 "Header-Length: " << m_headerSize <<
"\n" <<
562 "Content-Length: " << m_contentLength <<
"\n" <<
563 std::string{m_allData.begin(), m_allData.end()} <<
"\n";
570 std::ostringstream oss;
576 HttpHeader::GetHeaderSize(){
581 HttpHeader::GetContentSize(){
583 return m_contentLength;
589 return m_headerSize + m_contentLength;
593 HttpHeader::SetStatus (HttpHeader::HttpStatus status)
601 case SwitchingProtocol:
620 case NonAuthoritativeInformation:
635 case AlreadyReported:
645 case MovedPermanently:
660 case TemporaryRedirect:
663 case PermanentRedirect:
673 case PaymentRequired:
682 case MethodNotAllowed:
688 case ProxyAuthenticationRequired:
703 case PreconditionFailed:
706 case PayloadTooLarge:
712 case UnsupportedMediaType:
715 case RangeNotSatisfiable:
718 case ExpectationFailed:
724 case MisdirectedRequest:
727 case UnprocessableEntity:
733 case FailedDependency:
739 case UpgradeRequired:
742 case PreconditionRequired:
745 case TooManyRequests:
748 case RequestHeaderFieldsTooLarge:
751 case UnavailableForLegalReasons:
755 case InternalServerError:
764 case ServiceUnavailable:
770 case HttpVersionNotSupported:
773 case VariantAlsoNegotiates:
776 case InsufficientStorage:
785 case NetworkAuthenticationRequired:
794 HttpHeader::HttpStatus
795 HttpHeader::GetStatus ()
const
804 ret = SwitchingProtocol;
823 ret = NonAuthoritativeInformation;
832 ret = PartialContent;
838 ret = AlreadyReported;
845 ret = MultipleChoice;
848 ret = MovedPermanently;
863 ret = TemporaryRedirect;
866 ret = PermanentRedirect;
876 ret = PaymentRequired;
885 ret = MethodNotAllowed;
891 ret = ProxyAuthenticationRequired;
894 ret = RequestTimeout;
903 ret = LengthRequired;
906 ret = PreconditionFailed;
909 ret = PayloadTooLarge;
915 ret = UnsupportedMediaType;
918 ret = RangeNotSatisfiable;
921 ret = ExpectationFailed;
927 ret = MisdirectedRequest;
930 ret = UnprocessableEntity;
936 ret = FailedDependency;
942 ret = UpgradeRequired;
945 ret = PreconditionRequired;
948 ret = TooManyRequests;
951 ret = RequestHeaderFieldsTooLarge;
954 ret = UnavailableForLegalReasons;
958 ret = InternalServerError;
961 ret = NotImplemented;
967 ret = ServiceUnavailable;
970 ret = GatewayTimeout;
973 ret = HttpVersionNotSupported;
976 ret = VariantAlsoNegotiates;
979 ret = InsufficientStorage;
988 ret = NetworkAuthenticationRequired;
999 HttpHeader::GetStatusString ()
const
1007 return "SwitchingProtocol";
1009 return "Processing";
1011 return "EarlyHints";
1020 return "NonAuthoritativeInformation";
1024 return "ResetContent";
1026 return "PartialContent";
1028 return "MultiStatus";
1030 return "AlreadyReported";
1035 return "MultipleChoice";
1037 return "MovedPermanently";
1043 return "NotModified";
1047 return "TemporaryRedirect";
1049 return "PermanentRedirect";
1052 return "BadRequest";
1054 return "Unauthorized";
1056 return "PaymentRequired";
1062 return "MethodNotAllowed";
1064 return "NotAcceptable";
1066 return "ProxyAuthenticationRequired";
1068 return "RequestTimeout";
1074 return "LengthRequired";
1076 return "PreconditionFailed";
1078 return "PayloadTooLarge";
1080 return "UriTooLong";
1082 return "UnsupportedMediaType";
1084 return "RangeNotSatisfiable";
1086 return "ExpectationFailed";
1090 return "MisdirectedRequest";
1092 return "UnprocessableEntity";
1096 return "FailedDependency";
1100 return "UpgradeRequired";
1102 return "PreconditionRequired";
1104 return "TooManyRequests";
1106 return "RequestHeaderFieldsTooLarge";
1108 return "UnavailableForLegalReasons";
1111 return "InternalServerError";
1113 return "NotImplemented";
1115 return "BadGateway";
1117 return "ServiceUnavailable";
1119 return "GatewayTimeout";
1121 return "HttpVersionNotSupported";
1123 return "VariantAlsoNegotiates";
1125 return "InsufficientStorage";
1127 return "LoopDetected";
1129 return "NotExtended";
1131 return "NetworkAuthenticationRequired";
1141 HttpHeader::SetMethod (
const std::string&
m){
1147 method = HttpHeader::DELETE;
1148 else if (
m ==
"GET")
1149 method = HttpHeader::GET;
1150 else if (
m ==
"HEAD")
1151 method = HttpHeader::HEAD;
1152 else if (
m ==
"PATCH")
1153 method = HttpHeader::PATCH;
1154 else if (
m ==
"POST")
1155 method = HttpHeader::POST;
1156 else if (
m ==
"PUT")
1157 method = HttpHeader::PUT;
1196 HttpHeader::HttpMethod
1197 HttpHeader::GetMethod ()
const
1231 constexpr
char hexChars[16] = {
'0',
'1',
'2',
'3',
'4',
'5',
'6',
'7',
'8',
'9',
'A',
'B',
'C',
'D',
'E',
'F'};
1235 for (
auto i = str.begin(); i != str.end(); ++i)
1237 const std::uint8_t cp = *i & 0xFF;
1239 if ((cp >= 0x30 && cp <= 0x39) ||
1240 (cp >= 0x41 && cp <= 0x5A) ||
1241 (cp >= 0x61 && cp <= 0x7A) ||
1242 cp == 0x2D || cp == 0x2E || cp == 0x5F)
1243 result +=
static_cast<char>(cp);
1244 else if (cp <= 0x7F)
1245 result += std::string(
"%") + hexChars[(*i & 0xF0) >> 4] + hexChars[*i & 0x0F];
1246 else if ((cp >> 5) == 0x06)
1248 result += std::string(
"%") + hexChars[(*i & 0xF0) >> 4] + hexChars[*i & 0x0F];
1249 if (++i == str.end())
break;
1250 result += std::string(
"%") + hexChars[(*i & 0xF0) >> 4] + hexChars[*i & 0x0F];
1252 else if ((cp >> 4) == 0x0E)
1254 result += std::string(
"%") + hexChars[(*i & 0xF0) >> 4] + hexChars[*i & 0x0F];
1255 if (++i == str.end())
break;
1256 result += std::string(
"%") + hexChars[(*i & 0xF0) >> 4] + hexChars[*i & 0x0F];
1257 if (++i == str.end())
break;
1258 result += std::string(
"%") + hexChars[(*i & 0xF0) >> 4] + hexChars[*i & 0x0F];
1260 else if ((cp >> 3) == 0x1E)
1262 result += std::string(
"%") + hexChars[(*i & 0xF0) >> 4] + hexChars[*i & 0x0F];
1263 if (++i == str.end())
break;
1264 result += std::string(
"%") + hexChars[(*i & 0xF0) >> 4] + hexChars[*i & 0x0F];
1265 if (++i == str.end())
break;
1266 result += std::string(
"%") + hexChars[(*i & 0xF0) >> 4] + hexChars[*i & 0x0F];
1267 if (++i == str.end())
break;
1268 result += std::string(
"%") + hexChars[(*i & 0xF0) >> 4] + hexChars[*i & 0x0F];
1276 HttpHeader::GetUri()
const
1282 HttpHeader::GetRequestUri()
const{
1283 return m_request_uri;
1287 HttpHeader::SetUri(
const std::string& url)
1293 const auto schemeEndPosition = url.find(
"://");
1295 if (schemeEndPosition != std::string::npos)
1297 m_scheme = url.substr(0, schemeEndPosition);
1298 m_path = url.substr(schemeEndPosition + 3);
1306 const auto fragmentPosition = m_path.find(
'#');
1309 if (fragmentPosition != std::string::npos)
1310 m_path.resize(fragmentPosition);
1312 const auto pathPosition = m_path.find(
'/');
1314 if (pathPosition == std::string::npos)
1321 m_domain = m_path.substr(0, pathPosition);
1322 m_path = m_path.substr(pathPosition);
1325 const auto portPosition = m_domain.find(
':');
1327 if (portPosition != std::string::npos)
1329 m_domain.resize(portPosition);
a unique identifier for an interface.
TypeId SetParent(TypeId tid)
Set the parent TypeId.
#define NS_ASSERT(condition)
At runtime, in debugging builds, if this condition is not true, the program prints the source file,...
#define NS_FATAL_ERROR(msg)
Report a fatal error with a message and terminate.
#define NS_LOG_COMPONENT_DEFINE(name)
Define a Log component with a specific name.
#define NS_LOG_FUNCTION(parameters)
If log level LOG_FUNCTION is enabled, this macro will output all input parameters separated by ",...
#define NS_OBJECT_ENSURE_REGISTERED(type)
Register an Object subclass with the TypeId system.
void Print(ComponentCarrier cc)
static const std::string & ToString(LteUeRrc::State s)
std::string urlEncode(const std::string &str)
NLOHMANN_BASIC_JSON_TPL_DECLARATION std::string to_string(const NLOHMANN_BASIC_JSON_TPL &j)
user-defined to_string function for JSON values
Every class exported by the ns3 library is enclosed in the ns3 namespace.
uint32_t GetSize(Ptr< const Packet > packet, const WifiMacHeader *hdr, bool isAmpdu)
Return the total size of the packet after WifiMacHeader and FCS trailer have been added.