A Discrete-Event Network Simulator
API
http.h
Go to the documentation of this file.
1 /* -*- Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- */
2 /*
3  * MIT License
4  *
5  * Copyright (c) 2019 Maxwell Flynn
6  *
7  * Permission is hereby granted, free of charge, to any person obtaining a copy
8  * of this software and associated documentation files (the "Software"), to deal
9  * in the Software without restriction, including without limitation the rights
10  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11  * copies of the Software, and to permit persons to whom the Software is
12  * furnished to do so, subject to the following conditions:
13  *
14  * The above copyright notice and this permission notice shall be included in all
15  * copies or substantial portions of the Software.
16  *
17  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
23  * SOFTWARE.
24  *
25  * Source-code taken from https://github.com/tinfoilboy/atomizes
26  * Adopted by: Miralem Mehic <miralem.mehic@ieee.org>
27  */
28 
29 #ifndef HTTP_CONTENT_H
30 #define HTTP_CONTENT_H
31 
32 #include <string>
33 #include <unordered_map>
34 #include <cstdint>
35 #include <vector>
36 #include <sstream>
37 #include <algorithm> // std::remove_if
38 
39 #include "ns3/log.h"
40 
41 namespace ns3 {
42 
48  const std::string CarriageReturn = "\r\n";
49 
53  const std::string HTTPVersion1 = "HTTP/1.0";
54 
58  const std::string HTTPVersion11 = "HTTP/1.1";
59 
78  {
79  public:
80 
81  enum HttpMethod {
84  GET,
85  HEAD,
87  POST,
88  PUT
89  };
90 
92  {
93  Continue = 100,
95  Processing = 102,
96  EarlyHints = 103,
97 
98  Ok = 200,
99  Created = 201,
100  Accepted = 202,
102  NoContent = 204,
105  MultiStatus = 207,
107  ImUsed = 226,
108 
111  Found = 302,
112  SeeOther = 303,
113  NotModified = 304,
114  UseProxy = 305,
117 
118  BadRequest = 400,
121  Forbidden = 403,
122  NotFound = 404,
127  Conflict = 409,
128  Gone = 410,
132  UriTooLong = 414,
136  ImaTeapot = 418,
139  Locked = 423,
141  TooEarly = 425,
147 
150  BadGateway = 502,
157  NotExtended = 510,
159  };
160 
161 
162 
170  {
171  switch (m_statusCode)
172  {
173  case 100:
174  return HTTPMessage::HttpStatus::Continue;
175  case 101:
176  return HTTPMessage::HttpStatus::SwitchingProtocol;
177  case 200:
178  return HTTPMessage::HttpStatus::Ok;
179  case 201:
180  return HTTPMessage::HttpStatus::Created;
181  case 202:
182  return HTTPMessage::HttpStatus::Accepted;
183  case 203:
184  return HTTPMessage::HttpStatus::NonAuthoritativeInformation;
185  case 204:
186  return HTTPMessage::HttpStatus::NoContent;
187  case 205:
188  return HTTPMessage::HttpStatus::ResetContent;
189  case 206:
190  return HTTPMessage::HttpStatus::PartialContent;
191  case 300:
192  return HTTPMessage::HttpStatus::MultipleChoice;
193  case 301:
194  return HTTPMessage::HttpStatus::MovedPermanently;
195  case 302:
196  return HTTPMessage::HttpStatus::Found;
197  case 303:
198  return HTTPMessage::HttpStatus::SeeOther;
199  case 304:
200  return HTTPMessage::HttpStatus::NotModified;
201  // 305 is deprecated and 306 is only reserved, skip
202  case 307:
203  return HTTPMessage::HttpStatus::TemporaryRedirect;
204  case 308:
205  return HTTPMessage::HttpStatus::PermanentRedirect;
206  case 400:
207  return HTTPMessage::HttpStatus::BadRequest;
208  case 401:
209  return HTTPMessage::HttpStatus::Unauthorized;
210  case 402:
211  // 402 is reserved for future use but has a status message, adding it
212  return HTTPMessage::HttpStatus::PaymentRequired;
213  case 403:
214  return HTTPMessage::HttpStatus::Forbidden;
215  case 404:
216  return HTTPMessage::HttpStatus::NotFound;
217  case 405:
218  return HTTPMessage::HttpStatus::MethodNotAllowed;
219  case 406:
220  return HTTPMessage::HttpStatus::NotAcceptable;
221  case 407:
222  return HTTPMessage::HttpStatus::ProxyAuthenticationRequired;
223  case 408:
224  return HTTPMessage::HttpStatus::RequestTimeout;
225  case 409:
226  return HTTPMessage::HttpStatus::Conflict;
227  case 410:
228  return HTTPMessage::HttpStatus::Gone;
229  case 411:
230  return HTTPMessage::HttpStatus::LengthRequired;
231  case 412:
232  return HTTPMessage::HttpStatus::PreconditionFailed;
233  case 413:
234  return HTTPMessage::HttpStatus::PayloadTooLarge;
235  case 414:
236  return HTTPMessage::HttpStatus::UriTooLong;
237  case 415:
238  return HTTPMessage::HttpStatus::UnsupportedMediaType;
239  case 416:
240  return HTTPMessage::HttpStatus::RangeNotSatisfiable;
241  case 417:
242  return HTTPMessage::HttpStatus::ExpectationFailed;
243  case 418:
244  // might as well return the teapot joke
245  return HTTPMessage::HttpStatus::ImaTeapot;
246  case 421:
247  return HTTPMessage::HttpStatus::MisdirectedRequest;
248  case 425:
249  return HTTPMessage::HttpStatus::TooEarly;
250  case 426:
251  return HTTPMessage::HttpStatus::UpgradeRequired;
252  case 428:
253  return HTTPMessage::HttpStatus::PreconditionRequired;
254  case 429:
255  return HTTPMessage::HttpStatus::TooManyRequests;
256  case 431:
257  return HTTPMessage::HttpStatus::RequestHeaderFieldsTooLarge;
258  case 451:
259  return HTTPMessage::HttpStatus::UnavailableForLegalReasons;
260  case 500:
261  return HTTPMessage::HttpStatus::InternalServerError;
262  case 501:
263  return HTTPMessage::HttpStatus::NotImplemented;
264  case 502:
265  return HTTPMessage::HttpStatus::BadGateway;
266  case 503:
267  return HTTPMessage::HttpStatus::ServiceUnavailable;
268  case 504:
269  return HTTPMessage::HttpStatus::GatewayTimeout;
270  case 505:
271  return HTTPMessage::HttpStatus::HttpVersionNotSupported;
272  case 506:
273  return HTTPMessage::HttpStatus::VariantAlsoNegotiates;
274  case 507:
275  return HTTPMessage::HttpStatus::InsufficientStorage;
276  case 510:
277  return HTTPMessage::HttpStatus::NotExtended;
278  case 511:
279  return HTTPMessage::HttpStatus::NetworkAuthenticationRequired;
280  default:
281  return HTTPMessage::HttpStatus::InternalServerError;
282  }
283  }
284 
291  inline std::string StatusTextFromStatusCode(const uint16_t statusCode)
292  {
293  switch (statusCode)
294  {
295  case 100:
296  return "Continue";
297  case 101:
298  return "Switching Protocol";
299  case 200:
300  return "OK";
301  case 201:
302  return "Created";
303  case 202:
304  return "Accepted";
305  case 203:
306  return "Non-Authoritative Information";
307  case 204:
308  return "No Content";
309  case 205:
310  return "Reset Content";
311  case 206:
312  return "Partial Content";
313  case 300:
314  return "Multiple Choice";
315  case 301:
316  return "Moved Permanently";
317  case 302:
318  return "Found";
319  case 303:
320  return "See Other";
321  case 304:
322  return "Not Modified";
323  // 305 is deprecated and 306 is only reserved, skip
324  case 307:
325  return "Temporary Redirect";
326  case 308:
327  return "Permanent Redirect";
328  case 400:
329  return "Bad Request";
330  case 401:
331  return "Unauthorized";
332  case 402:
333  // 402 is reserved for future use but has a status message, adding it
334  return "Payment Required";
335  case 403:
336  return "Forbidden";
337  case 404:
338  return "Not Found";
339  case 405:
340  return "Method Not Allowed";
341  case 406:
342  return "Not Acceptable";
343  case 407:
344  return "Proxy Authentication Required";
345  case 408:
346  return "Request Timeout";
347  case 409:
348  return "Conflict";
349  case 410:
350  return "Gone";
351  case 411:
352  return "Length Required";
353  case 412:
354  return "Precondition Failed";
355  case 413:
356  return "Payload Too Large";
357  case 414:
358  return "URI Too Long";
359  case 415:
360  return "Unsupported Media Type";
361  case 416:
362  return "Requested Range Not Satisfiable";
363  case 417:
364  return "Expectation Failed";
365  case 418:
366  // might as well return the teapot joke
367  return "I'm a teapot";
368  case 421:
369  return "Misdirected Request";
370  case 425:
371  return "Too Early";
372  case 426:
373  return "Upgrade Required";
374  case 428:
375  return "Precondition Required";
376  case 429:
377  return "Too Many Requests";
378  case 431:
379  return "Request Header Fields Too Large";
380  case 451:
381  return "Unavailable for Legal Reasons";
382  case 500:
383  return "Internal Server Error";
384  case 501:
385  return "Not Implemented";
386  case 502:
387  return "Bad Gateway";
388  case 503:
389  return "Service Unavailable";
390  case 504:
391  return "Gateway Timeout";
392  case 505:
393  return "HTTP Version Not Supported";
394  case 506:
395  return "Variant Also Negotiates";
396  case 507:
397  return "Insufficient Storage";
398  case 510:
399  return "Not Extended";
400  case 511:
401  return "Network Authentication Required";
402  default:
403  return "Undefined";
404  }
405  }
406 
410  HTTPMessage& SetHeader(const std::string& name, const std::string& value)
411  {
412  m_headers[name] = value;
413 
414  if(name == "Content-Length") {
415  m_contentLength = std::stoi(value);
416  }else if(name == "Request URI"){
417  m_request_uri = value;
418  }else if(name == "Host"){
419  if(m_domain == ""){
420  m_domain = value;
421  m_uri = value + m_uri;
422  }
423  }
424 
425  return *this;
426  }
427 
431  std::string GetRequestUri() const{
432  return m_request_uri;
433  }
434 
438  HTTPMessage& SetHeaders(const std::unordered_map<std::string, std::string>& headers)
439  {
440  m_headers.insert(headers.begin(), headers.end());
441  return *this;
442  }
443 
449  inline std::string GetHeader(const std::string& name) const
450  {
451  auto find = m_headers.find(name);
452 
453  if (find != m_headers.end())
454  return find->second;
455 
456  return "";
457  }
458 
464  void
465  SetMethod (const std::string& m){
466 
467  if (m == "DELETE")
469  else if (m == "GET")
471  else if (m == "HEAD")
473  else if (m == "PATCH")
475  else if (m == "POST")
477  else if (m == "PUT")
479 
480  }
481 
483  {
484  return m_method;
485  }
486 
487  std::string GetMethodToString() const
488  {
489  switch (m_method)
490  {
491  case HTTPMessage::NONE:
492  return "NONE";
493  break;
494  case HTTPMessage::DELETE:
495  return "DELETE";
496  break;
497  case HTTPMessage::GET:
498  return "GET";
499  break;
500  case HTTPMessage::HEAD:
501  return "HEAD";
502  break;
503  case HTTPMessage::PATCH:
504  return "PATCH";
505  break;
506  case HTTPMessage::POST:
507  return "POST";
508  break;
509  case HTTPMessage::PUT:
510  return "PUT";
511  break;
512  }
513  return "NONE";
514  }
515 
519  inline std::string GetUri() const
520  {
521  return m_uri;
522  }
523 
527  void SetPath(const std::string& url)
528  {
529  const auto schemeEndPosition = url.find("://");
530  if (schemeEndPosition != std::string::npos)
531  {
532  m_scheme = url.substr(0, schemeEndPosition);
533  m_path = url.substr(schemeEndPosition + 3);
534  }
535  else
536  {
537  m_scheme = "http";
538  m_path = url;
539  }
540 
541  const auto fragmentPosition = m_path.find('#');
542 
543  // remove the fragment part
544  if (fragmentPosition != std::string::npos)
545  m_path.resize(fragmentPosition);
546 
547  const auto pathPosition = m_path.find('/');
548 
549  if (pathPosition == std::string::npos)
550  {
551  m_domain = m_path;
552  m_path = "/";
553  }
554  else
555  {
556  m_domain = m_path.substr(0, pathPosition);
557  m_path = m_path.substr(pathPosition);
558  }
559 
560  const auto portPosition = m_domain.find(':');
561 
562  if (portPosition != std::string::npos)
563  {
564  m_domain.resize(portPosition);
565  }
566  m_uri = m_domain + url;
567 
568  }
569 
573  inline std::string GetPath() const
574  {
575  return m_path;
576  }
577 
581  void SetVersion(const std::string& version)
582  {
583  m_version = version;
584  }
585 
589  inline std::string GetVersion() const
590  {
591  return m_version;
592  }
593 
597  void SetStatusCode(uint16_t code)
598  {
599  m_statusCode = code;
600  }
601 
605  inline uint16_t GetStatusCode() const
606  {
607  return m_statusCode;
608  }
609 
613  void SetStatusMessage(const std::string& message)
614  {
615  m_statusMessage = message;
616  }
617 
623  inline std::string GetStatusMessage() const
624  {
625  return m_statusMessage;
626  }
627 
633  std::string ToString()
634  {
635  std::stringstream output;
636 
637  // begin by forming the start line of the message
638  if (m_method == HTTPMessage::HttpMethod::NONE)
639  {
640  output << HTTPVersion11 << " " << m_statusCode << " ";
641 
642  if (m_statusMessage.empty())
644  else
645  output << m_statusMessage;
646  }
647  else
648  {
649  output << GetMethodToString() << " ";
650  output << m_path << " ";
651  output << HTTPVersion11;
652  }
653 
654  // output the status lines line break to move on
655  output << CarriageReturn;
656 
657  // output headers to the message string
658  for (auto& header : m_headers)
659  output << header.first << ": " << header.second << CarriageReturn;
660 
661  // automatically output the content length based on
662  // the size of the body member if body isn't empty
663  if (!m_contentLength && !m_body.empty()){
664  m_contentLength = m_body.size();
665  output << "Content-Length: " << m_contentLength << CarriageReturn;
666  }
667 
668  // seperate headers and body with an extra carriage return
669  output << CarriageReturn;
670 
671  m_headersLength = output.str().size();
672 
673  // convert the 8-bit unsigned body to a std::string for output
674  std::string body(m_body.begin(), m_body.end());
675 
676  output << body;
677 
678  return output.str();
679  }
680 
681  uint32_t GetHeadersSize(){
682  if(m_headersLength == 0) ToString();
683  return m_headersLength;
684  }
685 
686  uint32_t GetSize(){
687  return GetHeadersSize() + GetContentLength();
688  }
689 
693  void SetMessageBody(const std::string& body)
694  {
695  SetMessageBody(std::vector<uint8_t>(body.begin(), body.end()));
696  }
697 
701  void SetMessageBody(const std::vector<uint8_t>& body)
702  {
703  m_body = std::vector<uint8_t>(body);
704  }
705 
709  inline std::vector<uint8_t>& GetMessageBody()
710  {
711  return m_body;
712  }
713 
714  inline std::string GetMessageBodyString()
715  {
716  // convert the 8-bit unsigned body to a std::string for output
717  return std::string(m_body.begin(), m_body.end());
718  }
719 
720 
724  inline size_t GetContentLength()
725  {
726  return m_contentLength;
727  }
728 
732  inline size_t HeaderCount()
733  {
734  return m_headers.size();
735  }
736 
737  void
739  const std::string& url,
740  const std::string& method
741  )
742  {
744  url,
745  method,
746  ""
747  );
748  }
749  void
751  const std::string& url,
752  const std::string& method,
753  const std::string& body)
754  {
755 
757  url,
758  method,
759  std::vector<uint8_t>(body.begin(), body.end())
760  );
761  }
762  void
764  const std::string& url,
765  const std::string& method,
766  const std::vector<uint8_t>& body
767  ) {
768  SetMethod(method);
769  SetPath(url);
770  SetHeader("User-Agent", "Test Agent");
771  SetHeader("Host", m_domain);
772  SetHeader("Accept-Language", "en-us,en;q=0.5");
773  SetHeader("Accept-Encoding", "gzip,deflate");
774  SetHeader("Accept-Charset", "ISO-8859-1,utf-8;q=0.7,*;q=0.7");
775  SetHeader("Keep-Alive", "300");
776  SetHeader("Connection", "keep-alive");
777  SetHeader("Cookie", "PHPSESSID=r2t5uvjq435r4q7ib3vtdjq120");
778  SetHeader("Pragma", "no-cache");
779  SetHeader("Cache-Control", "no-cache");
780  SetHeader("Content-Length", std::to_string(body.size()) );
781  SetMessageBody(body);
782  }
783 
784  void
786  const HttpStatus status
787  ){
789  status,
790  ""
791  );
792  }
793  void
795  const HttpStatus status,
796  const std::string& body
797  ){
799  status,
800  std::vector<uint8_t>(body.begin(), body.end())
801  );
802  }
803  void
805  const HttpStatus status,
806  const std::vector<uint8_t>& body
807  ){
808  //response
809  SetMethod("NONE");
810  SetStatusCode(status);
811  SetHeader("Server", "QKDNetSim KMS/3.36");
812  SetHeader("Date", "Sat, 28 Aug 2022 04:36:25 GMT");
813  SetHeader("Connection", "close");
814  SetHeader("Pragma", "public");
815  SetHeader("Content-Encoding", "gzip");
816  SetHeader("Vary", "Accept-Encoding, Cookie");
817  SetHeader("Cache-Control", "max-age=3600, public");
818  SetHeader("Content-Length", std::to_string(body.size()) );
819  SetMessageBody(body);
820  }
821  void
823  const HttpStatus status,
824  const std::string& body,
825  const std::unordered_map<std::string, std::string>& headers
826  ){
827  SetHeaders(headers);
829  status,
830  std::vector<uint8_t>(body.begin(), body.end())
831  );
832  }
833  void
835  const HttpStatus status,
836  const std::vector<uint8_t>& body,
837  const std::unordered_map<std::string, std::string>& headers
838  ){
839  SetHeaders(headers);
841  status,
842  body
843  );
844  }
845 
846  void
847  SetFragmented(bool value){
848  m_fragmented = value;
849  }
850 
851  bool
853  return m_fragmented;
854  }
855 
856  private:
862  HTTPMessage::HttpMethod m_method = HTTPMessage::HttpMethod::NONE;
863 
869  uint16_t m_statusCode = 0;
870 
876  std::string m_statusMessage = "";
877 
883  std::string m_path = "";
884 
885  std::string m_scheme;
886  std::string m_domain;
887  std::string m_uri;
888  std::string m_request_uri;
889 
895  std::string m_version = HTTPVersion11;
896 
901  std::unordered_map<std::string, std::string> m_headers;
902 
906  std::vector<uint8_t> m_body;
907 
911  bool m_fragmented = false;
912 
913  uint32_t m_contentLength = 0;
914  uint32_t m_headersLength = 0;
915 
916  };
917 
921  enum class MessageParserState : uint8_t
922  {
923  NONE,
927  HEADER_KEY,
928  HEADER_VALUE,
929  PARSING_BODY,
930  };
931 
941  {
942  public:
951  void Parse(HTTPMessage* httpMessage, const std::string& buffer)
952  {
953 
954  std::string cleanText = buffer;
955  stripUnicode(cleanText);
956  Parse(httpMessage, std::vector<uint8_t>(cleanText.begin(), cleanText.end()));
957  }
958 
969  void Parse(HTTPMessage* httpMessage, const std::vector<uint8_t>& buffer)
970  {
971  // begin by parsing the start line without knowing if it is a
972  // request or a response by setting as undetermined
974 
975  // a temporary string instance used for storing characters of a
976  // current line in the message being parsed
977  std::string temp = "";
978 
979  // whether to skip the next character (for a carriage return)
980  bool skipNext = false;
981 
982  // the current key for a header
983  std::string headerKey = "";
984 
985  // whether or not a message body is present
986  bool hasMessageBody = false;
987 
988  // the index at which the message body begins
989  size_t bodyStartIndex = 0;
990 
991  for (size_t index = 0; index < buffer.size(); index++)
992  {
993  uint8_t character = buffer[index];
994 
995  // skip this character as it was marked
996  if (skipNext)
997  {
998  skipNext = false;
999 
1000  continue;
1001  }
1002 
1003  // if we are parsing the body, then we only need to grab an index and break
1004  // out of this loop as we want to merely insert the data from this vector
1005  // into the body vector
1006  if (state == MessageParserState::PARSING_BODY)
1007  {
1008  hasMessageBody = true;
1009 
1010  bodyStartIndex = index;
1011 
1012  break;
1013  }
1014 
1015  // if we are parsing the start line but neither a response or request
1017  {
1018  // if we hit a space, we have to check if the start line begins
1019  // with the HTTP version or the method verb
1020  if (character == ' ')
1021  {
1022  // this message has a leading version string, thus it is
1023  // a response and not a request
1024  if (temp == HTTPVersion1 || temp == HTTPVersion11)
1025  {
1026  httpMessage->SetMethod("NONE");
1027 
1029 
1030  temp = "";
1031 
1032  continue;
1033  }
1034  // this must be a request, so grab the HTTPMessage::HttpMethod type
1035  // for the request, set it, and move on
1036  else
1037  {
1038  httpMessage->SetMethod(temp);
1039 
1041 
1042  temp = "";
1043 
1044  continue;
1045  }
1046  }
1047  }
1048  // do actions for when the start line is a request
1049  else if (state == MessageParserState::START_LINE_REQUEST)
1050  {
1051  // once a space is hit, add the path to the message
1052  if (character == ' ')
1053  {
1054  httpMessage->SetPath(temp);
1055 
1056  temp = "";
1057 
1058  continue;
1059  }
1060  // when the beginning of a carriage return is hit, add the version string
1061  // to the message and then skip the following new line character, setting
1062  // the state of the parser to be parsing headers
1063  else if (character == '\r')
1064  {
1065  httpMessage->SetVersion(temp);
1066 
1067  temp = "";
1068 
1070 
1071  skipNext = true;
1072 
1073  continue;
1074  }
1075  }
1076  // do actions for when the start line is a response
1077  else if (state == MessageParserState::START_LINE_RESPONSE)
1078  {
1079  // if we are at a space, then we have hit the status code for the response
1080  if (character == ' ' && httpMessage->GetStatusCode() == 0)
1081  {
1082  int code = std::stoi(temp);
1083 
1084  httpMessage->SetStatusCode(static_cast<uint16_t>(code));
1085 
1086  temp = "";
1087 
1088  continue;
1089  }
1090  // if we are at a carriage return start, then set the status message for
1091  // the response, this can be blank in which it will use a generated status
1092  //
1093  // this will also set the state of the parser to move on to headers
1094  else if (character == '\r')
1095  {
1096  httpMessage->SetStatusMessage(temp);
1097 
1098  temp = "";
1099 
1101 
1102  skipNext = true;
1103 
1104  continue;
1105  }
1106  }
1107  // if we are parsing header keys and hit a colon, then the key for the header has
1108  // been fully parsed and should be added to the temporary key holder
1109  else if (state == MessageParserState::HEADER_KEY && character == ':')
1110  {
1111  headerKey = temp;
1112 
1113  temp = "";
1114 
1116 
1117  // HTTP defines that the next character in a header should be a space
1118  // so skip that for parsing the value of the header
1119  skipNext = true;
1120 
1121  continue;
1122  }
1123  // if we are parsing header values and hit the beginning of a carriage return then
1124  // it is time to add the header to the message with the key and value, and move the
1125  // state back to parsing keys
1126  else if (state == MessageParserState::HEADER_VALUE && character == '\r')
1127  {
1128  httpMessage->SetHeader(headerKey, temp);
1129 
1130  headerKey = "";
1131  temp = "";
1132 
1134 
1135  // skip the next character as it will just be a newline
1136  skipNext = true;
1137 
1138  continue;
1139  }
1140  // if we are parsing header keys and we hit a carriage return, then we should assume
1141  // that the headers have ended, and that we are now parsing a message body.
1142  else if (state == MessageParserState::HEADER_KEY && character == '\r')
1143  {
1144  temp = "";
1145 
1147 
1148  // skip the next character as it'll be a newline
1149  skipNext = true;
1150 
1151  continue;
1152  }
1153 
1154  temp += character;
1155  }
1156 
1157  // add the body to the message if it is present
1158  if (hasMessageBody){
1159  httpMessage->GetMessageBody().insert(
1160  httpMessage->GetMessageBody().begin(),
1161  buffer.begin() + bodyStartIndex,
1162  buffer.end()
1163  );
1164  if(httpMessage->GetContentLength() > httpMessage->GetMessageBody().size()){
1165  httpMessage->SetFragmented(true);
1166  }
1167  }
1168 
1169  /*
1170  std::cout << "\n\n\n <<<<<<<<<<<<<<<<<<<<<<<<< " << std::string{buffer.begin(), buffer.end()};
1171  std::cout << "content-length:" << httpMessage->GetContentLength() << "\n";
1172  std::cout << "body-length:" << buffer.end() - buffer.begin()+bodyStartIndex << "\n";
1173  std::cout << "body-size:" << httpMessage->GetMessageBody().size() << "\n";
1174  std::cout << "\n\n\n <<<<<<<<<<<<<<<<<<<<<<<<< \n";
1175  */
1176 
1177  if(httpMessage->GetContentLength() < httpMessage->GetMessageBody().size()){
1178  httpMessage->GetMessageBody().resize(
1179  httpMessage->GetContentLength()
1180  );
1181  }
1182  }
1183  static bool invalidChar (char c)
1184  {
1185  return !(c>=0 && c <128);
1186  }
1187  void stripUnicode(std::string & str)
1188  {
1189  str.erase(
1190  std::remove_if(str.begin(),str.end(), invalidChar), str.end()
1191  );
1192  }
1193 
1194  };
1195 
1196 
1197 } // end of `namespace ns3`
1198 
1199 
1200 #endif /* HTTP_CONTENT_H */
The basic class to represent both HTTP requests and responses.
Definition: http.h:78
void SetVersion(const std::string &version)
Set the version of this HTTP message to the string specified.
Definition: http.h:581
std::string GetHeader(const std::string &name) const
Get the string value of a single header from the message.
Definition: http.h:449
std::string m_path
The path for the resource specified in the message.
Definition: http.h:883
uint16_t GetStatusCode() const
Get the status code for this message.
Definition: http.h:605
void CreateRequest(const std::string &url, const std::string &method, const std::string &body)
Definition: http.h:750
void CreateResponse(const HttpStatus status, const std::string &body)
Definition: http.h:794
std::string GetVersion() const
Get the current HTTP version for this message.
Definition: http.h:589
std::string GetRequestUri() const
Definition: http.h:431
std::string ToString()
Takes the headers added to the message along with the body and outputs it to a std::string for use in...
Definition: http.h:633
std::string m_scheme
Definition: http.h:885
void SetMethod(const std::string &m)
Set the associated message method for this message.
Definition: http.h:465
@ HEAD
Http Method Head.
Definition: http.h:85
@ PUT
Http Method Put.
Definition: http.h:88
@ PATCH
Http Method Patch.
Definition: http.h:86
@ DELETE
Http Method Delete.
Definition: http.h:83
@ POST
Http Method Post.
Definition: http.h:87
@ GET
Http Method GET.
Definition: http.h:84
uint32_t GetSize()
Definition: http.h:686
std::string GetMethodToString() const
Definition: http.h:487
std::string m_uri
Definition: http.h:887
std::vector< uint8_t > & GetMessageBody()
Get the body vector for this message.
Definition: http.h:709
std::string m_version
The version used for this HTTP message as a string.
Definition: http.h:895
void CreateResponse(const HttpStatus status, const std::string &body, const std::unordered_map< std::string, std::string > &headers)
Definition: http.h:822
std::string GetUri() const
Grab the uri.
Definition: http.h:519
void CreateRequest(const std::string &url, const std::string &method)
Definition: http.h:738
@ GatewayTimeout
Definition: http.h:152
@ RangeNotSatisfiable
Definition: http.h:134
@ PaymentRequired
Definition: http.h:120
@ MovedPermanently
Definition: http.h:110
@ RequestTimeout
Definition: http.h:126
@ VariantAlsoNegotiates
Definition: http.h:154
@ FailedDependency
Definition: http.h:140
@ NetworkAuthenticationRequired
Definition: http.h:158
@ UnavailableForLegalReasons
Definition: http.h:146
@ TooManyRequests
Definition: http.h:144
@ NonAuthoritativeInformation
Definition: http.h:101
@ SwitchingProtocol
Definition: http.h:94
@ UnsupportedMediaType
Definition: http.h:133
@ PartialContent
Definition: http.h:104
@ PreconditionFailed
Definition: http.h:130
@ MethodNotAllowed
Definition: http.h:123
@ ExpectationFailed
Definition: http.h:135
@ RequestHeaderFieldsTooLarge
Definition: http.h:145
@ ProxyAuthenticationRequired
Definition: http.h:125
@ PermanentRedirect
Definition: http.h:116
@ ServiceUnavailable
Definition: http.h:151
@ NotImplemented
Definition: http.h:149
@ PreconditionRequired
Definition: http.h:143
@ TemporaryRedirect
Definition: http.h:115
@ MultipleChoice
Definition: http.h:109
@ LengthRequired
Definition: http.h:129
@ InternalServerError
Definition: http.h:148
@ UpgradeRequired
Definition: http.h:142
@ AlreadyReported
Definition: http.h:106
@ PayloadTooLarge
Definition: http.h:131
@ UnprocessableEntity
Definition: http.h:138
@ HttpVersionNotSupported
Definition: http.h:153
@ InsufficientStorage
Definition: http.h:155
@ MisdirectedRequest
Definition: http.h:137
std::string StatusTextFromStatusCode(const uint16_t statusCode)
To be returned with a status code in a response is a status text describing the status code by text r...
Definition: http.h:291
bool IsFragmented()
Definition: http.h:852
void CreateRequest(const std::string &url, const std::string &method, const std::vector< uint8_t > &body)
Definition: http.h:763
uint32_t m_headersLength
Definition: http.h:914
std::string GetMessageBodyString()
Definition: http.h:714
std::unordered_map< std::string, std::string > m_headers
An unordered_map of headers using a std::string for both the key and the value.
Definition: http.h:901
std::string m_request_uri
Definition: http.h:888
void SetStatusMessage(const std::string &message)
Set the status message of this HTTP message.
Definition: http.h:613
uint16_t m_statusCode
A status code for this message.
Definition: http.h:869
std::string m_statusMessage
A status message to be associated with the status code for this message.
Definition: http.h:876
size_t GetContentLength()
Return the size of the binary body vector.
Definition: http.h:724
std::string GetPath() const
Grab the current associated path of this message.
Definition: http.h:573
void CreateResponse(const HttpStatus status, const std::vector< uint8_t > &body)
Definition: http.h:804
void SetFragmented(bool value)
Definition: http.h:847
void CreateResponse(const HttpStatus status)
Definition: http.h:785
std::string m_domain
Definition: http.h:886
void SetPath(const std::string &url)
Set the path of this message, which will be used if it is a request.
Definition: http.h:527
void SetMessageBody(const std::string &body)
Set the body of this message to a string value.
Definition: http.h:693
void SetStatusCode(uint16_t code)
Set the status code of this HTTP message.
Definition: http.h:597
size_t HeaderCount()
Return the amount of headers in the message.
Definition: http.h:732
HTTPMessage::HttpStatus GetStatus()
To be returned with a status code in a response is a status text describing the status code by text r...
Definition: http.h:169
bool m_fragmented
Whether the payload size is less then content-length.
Definition: http.h:911
void SetMessageBody(const std::vector< uint8_t > &body)
Set the body of this message to an unsigned 8-bit binary value.
Definition: http.h:701
HTTPMessage & SetHeader(const std::string &name, const std::string &value)
Set a header in the map to the value provided.
Definition: http.h:410
HTTPMessage & SetHeaders(const std::unordered_map< std::string, std::string > &headers)
Set a number of headers based on a generic map of keys and values.
Definition: http.h:438
HTTPMessage::HttpMethod GetMethod() const
Definition: http.h:482
uint32_t GetHeadersSize()
Definition: http.h:681
std::string GetStatusMessage() const
Get the current status message for this message.
Definition: http.h:623
HTTPMessage::HttpMethod m_method
The HTTP method for this message.
Definition: http.h:862
void CreateResponse(const HttpStatus status, const std::vector< uint8_t > &body, const std::unordered_map< std::string, std::string > &headers)
Definition: http.h:834
std::vector< uint8_t > m_body
A vector of unsigned 8-bit integers used to store message bodies.
Definition: http.h:906
uint32_t m_contentLength
Definition: http.h:913
A basic class to parse a HTTP message, both request and response.
Definition: http.h:941
void Parse(HTTPMessage *httpMessage, const std::string &buffer)
Parse a std::string to a HTTP message.
Definition: http.h:951
static bool invalidChar(char c)
Definition: http.h:1183
void Parse(HTTPMessage *httpMessage, const std::vector< uint8_t > &buffer)
Parse a binary vector to an HTTP message.
Definition: http.h:969
void stripUnicode(std::string &str)
Definition: http.h:1187
string version
Definition: conf.py:51
NLOHMANN_BASIC_JSON_TPL_DECLARATION std::string to_string(const NLOHMANN_BASIC_JSON_TPL &j)
user-defined to_string function for JSON values
Definition: json.h:25255
Every class exported by the ns3 library is enclosed in the ns3 namespace.
const std::string HTTPVersion1
The string for HTTP version 1.0.
Definition: http.h:53
MessageParserState
An enum of states that the HTTPMessageParser can be in.
Definition: http.h:922
const std::string CarriageReturn
HTTP defines that any lines must be seperated with a carriage return.
Definition: http.h:48
const std::string HTTPVersion11
The string for HTTP version 1.1.
Definition: http.h:58