proxygen
HTTPArchive.cpp
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2015-present, Facebook, Inc.
3  * All rights reserved.
4  *
5  * This source code is licensed under the BSD-style license found in the
6  * LICENSE file in the root directory of this source tree. An additional grant
7  * of patent rights can be found in the PATENTS file in the same directory.
8  *
9  */
11 
12 #include <algorithm>
13 #include <folly/io/IOBuf.h>
14 #include <folly/json.h>
15 #include <fstream>
16 #include <glog/logging.h>
17 #include <ios>
18 #include <string>
19 
20 using folly::IOBuf;
21 using std::ifstream;
22 using std::ios;
23 using std::string;
24 using std::unique_ptr;
25 using std::vector;
26 
27 namespace {
28 
30 parseHTTPArchiveTime(const std::string& s) {
31  struct tm tm = {};
32 
33  if (s.empty()) {
34  return folly::none;
35  }
36 
37  uint32_t ms = 0;
38  // Sun, 06 Nov 1994 08:49:37 GMT ; RFC 822, updated by RFC 1123
39  // Example: 2013-12-09T16:38:03.701Z
40  if (sscanf(s.c_str(), "%d-%d-%dT%d:%d:%d.%dZ",
41  &tm.tm_year,
42  &tm.tm_mon,
43  &tm.tm_mday,
44  &tm.tm_hour,
45  &tm.tm_min,
46  &tm.tm_sec,
47  &ms) != 7) {
48  return folly::none;
49  }
50  // Per the spec, for some reason the API is inconsistent and requires
51  // years to be offset from 1900 and even more strange for month to be 0
52  // offset despite the fact it expects days to be 1 offset
53  // https://linux.die.net/man/3/mktime
54  tm.tm_year = tm.tm_year - 1900;
55  tm.tm_mon = tm.tm_mon - 1;
56 
57  auto res = mktime(&tm);
58  return std::chrono::steady_clock::time_point(
59  std::chrono::seconds(res) + std::chrono::milliseconds(ms));
60 }
61 
62 proxygen::HTTPMessage extractMessage(folly::dynamic& obj,
63  const std::string& timeStr,
64  bool request) {
66  auto& headersObj = obj["headers"];
67  for (size_t i = 0; i < headersObj.size(); i++) {
68  string name = headersObj[i]["name"].asString();
69  std::transform(name.begin(), name.end(), name.begin(), ::tolower);
70  if (name[0] == ':') {
71  if (name == ":host" || name == ":authority") {
72  name = "host";
73  } else {
74  continue;
75  }
76  }
77  msg.getHeaders().add(
78  name,
79  headersObj[i]["value"].asString());
80  }
81  try {
82  if (request) {
83  msg.setURL(obj["url"].asString());
84  msg.setMethod(obj["method"].asString());
85  auto t = parseHTTPArchiveTime(timeStr);
86  if (t.hasValue()) {
87  msg.setStartTime(t.value());
88  }
89  } else {
90  msg.setStatusCode(obj["status"].asInt());
91  msg.setStatusMessage(obj["statusText"].asString());
92  }
93 
94  string proto;
95  string version;
96  folly::split('/', obj["httpVersion"].asString(), proto, version);
97  msg.setVersionString(version);
98  } catch (...) {
99  }
100 
101  return msg;
102 }
103 
104 proxygen::HTTPMessage extractMessageFromPublic(folly::dynamic& obj) {
106  auto& headersObj = obj["headers"];
107  for (size_t i = 0; i < headersObj.size(); i++) {
108  auto& headerObj = headersObj[i];
109  for (auto& k: headerObj.keys()) {
110  string name = k.asString();
111  string value = headerObj[name].asString();
112  std::transform(name.begin(), name.end(), name.begin(), ::tolower);
113  msg.getHeaders().add(name, value);
114  }
115  }
116  return msg;
117 }
118 }
119 
120 namespace proxygen {
121 
122 std::unique_ptr<IOBuf> readFileToIOBuf(const std::string& filename) {
123  // read the contents of the file
124  ifstream file(filename);
125  if (!file.is_open()) {
126  LOG(ERROR) << "could not open file '" << filename << "'";
127  return nullptr;
128  }
129  file.seekg(0, ios::end);
130  int64_t size = file.tellg();
131  if (size < 0) {
132  LOG(ERROR) << "failed to fetch the position at the end of the file";
133  return nullptr;
134  }
135  file.seekg(0, ios::beg);
136  unique_ptr<IOBuf> buffer = IOBuf::create(size + 1);
137  file.read((char *)buffer->writableData(), size);
138  buffer->writableData()[size] = 0;
139  buffer->append(size + 1);
140  if (!file) {
141  LOG(ERROR) << "error occurred, was able to read only "
142  << file.gcount() << " bytes out of " << size;
143  return nullptr;
144  }
145  return buffer;
146 }
147 
148 unique_ptr<HTTPArchive> HTTPArchive::fromFile(const string& filename) {
149  unique_ptr<HTTPArchive> har = std::make_unique<HTTPArchive>();
150  auto buffer = readFileToIOBuf(filename);
151  if (!buffer) {
152  return nullptr;
153  }
154  folly::dynamic jsonObj = folly::parseJson((const char *)buffer->data());
155  auto entries = jsonObj["log"]["entries"];
156  // go over all the transactions
157  for (size_t i = 0; i < entries.size(); i++) {
158  HTTPMessage msg = extractMessage(entries[i]["request"],
159  entries[i]["startedDateTime"].asString(),
160  true);
161  if (msg.getHeaders().size() != 0) {
162  har->requests.push_back(msg);
163  }
164  msg = extractMessage(entries[i]["response"], "", false);
165  if (msg.getHeaders().size() != 0) {
166  har->responses.push_back(msg);
167  }
168  }
169 
170  return har;
171 }
172 
174  uint32_t size = 0;
175 
176  msg.getHeaders().forEach([&size] (const string& name, const string& value) {
177  size += name.size() + value.size() + 2;
178  });
179  return size;
180 }
181 
182 uint32_t HTTPArchive::getSize(const vector<HPACKHeader> &headers) {
183  uint32_t size = 0;
184 
185  for (const auto& header : headers) {
186  size += header.name.size() + header.value.size() + 2;
187  }
188  return size;
189 }
190 
191 unique_ptr<HTTPArchive> HTTPArchive::fromPublicFile(const string& filename) {
192  unique_ptr<HTTPArchive> har = std::make_unique<HTTPArchive>();
193  auto buffer = readFileToIOBuf(filename);
194  if (!buffer) {
195  return nullptr;
196  }
197  folly::dynamic jsonObj = folly::parseJson((const char *)buffer->data());
198  auto entries = jsonObj["cases"];
199  // go over all the transactions
200  for (size_t i = 0; i < entries.size(); i++) {
201  HTTPMessage msg = extractMessageFromPublic(entries[i]);
202  if (msg.getHeaders().size() != 0) {
203  har->requests.emplace_back(msg);
204  }
205  }
206 
207  return har;
208 }
209 
210 std::vector<std::vector<HPACKHeader>> HTTPArchive::convertToHPACK(
211  const std::vector<HTTPMessage>& msgs) {
212  std::vector<std::vector<HPACKHeader>> result;
213  for (const HTTPMessage& msg: msgs) {
214  std::vector<HPACKHeader> headers;
215  msg.getHeaders().forEach(
216  [&headers] (const string& name, const string& value) {
217  headers.emplace_back(name, value);
218  });
219  result.emplace_back(std::move(headers));
220  }
221  return result;
222 }
223 
224 }
std::vector< uint8_t > buffer(kBufferSize+16)
dynamic parseJson(StringPiece range)
Definition: json.cpp:900
void setStatusMessage(T &&msg)
Definition: HTTPMessage.h:242
constexpr detail::Map< Move > move
Definition: Base-inl.h:2567
static uint32_t getSize(const HTTPMessage &msg)
static std::vector< std::vector< HPACKHeader > > convertToHPACK(const std::vector< HTTPMessage > &msgs)
static std::unique_ptr< HTTPArchive > fromPublicFile(const std::string &fname)
void setVersionString(const std::string &ver)
Definition: HTTPMessage.h:259
PUSHMI_INLINE_VAR constexpr detail::transform_fn transform
Definition: transform.h:158
void split(const Delim &delimiter, const String &input, std::vector< OutputType > &out, bool ignoreEmpty)
Definition: String-inl.h:382
std::unique_ptr< IOBuf > readFileToIOBuf(const std::string &filename)
ProtocolVersion version
const char * name
Definition: http_parser.c:437
constexpr auto size(C const &c) -> decltype(c.size())
Definition: Access.h:45
ParseURL setURL(T &&url)
Definition: HTTPMessage.h:183
uint8_t * writableData()
Definition: IOBuf.h:509
auto end(TestAdlIterable &instance)
Definition: ForeachTest.cpp:62
static std::unique_ptr< HTTPArchive > fromFile(const std::string &filename)
void setStartTime(const TimePoint &startTime)
Definition: HTTPMessage.h:623
void forEach(LAMBDA func) const
Definition: HTTPHeaders.h:337
static const char *const value
Definition: Conv.cpp:50
HTTPHeaders & getHeaders()
Definition: HTTPMessage.h:273
void setMethod(HTTPMethod method)
size_t size() const
const char * string
Definition: Conv.cpp:212
static set< string > s
void add(folly::StringPiece name, folly::StringPiece value)
Definition: HTTPHeaders.cpp:52
KeyT k
void append(std::size_t amount)
Definition: IOBuf.h:689
constexpr None none
Definition: Optional.h:87
void setStatusCode(uint16_t status)