proxygen
HTTPMessageTest.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  */
10 #include <fcntl.h>
14 #include <signal.h>
15 #include <stdlib.h>
16 #include <string.h>
17 #include <sys/types.h>
18 
19 using namespace proxygen;
20 using namespace std;
21 
22 TEST(HTTPMessage, TestParseCookiesSimple) {
23  HTTPMessage msg;
24 
25  msg.getHeaders().add("Cookie", "id=1256679245; data=0:1234567");
26  EXPECT_EQ(msg.getCookie("id"), "1256679245");
27  EXPECT_EQ(msg.getCookie("data"), "0:1234567");
28  EXPECT_EQ(msg.getCookie("mising"), "");
29 }
30 
31 TEST(HTTPMessage, TestParseCookiesSpaces) {
32  HTTPMessage msg;
33 
34  msg.getHeaders().add("Cookie", " id=1256679245 ; data=0:1234567 ;");
35  EXPECT_EQ(msg.getCookie("id"), "1256679245");
36  EXPECT_EQ(msg.getCookie("data"), "0:1234567");
37 }
38 
39 TEST(HTTPMessage, TestParseCookiesSingleCookie) {
40  HTTPMessage msg;
41 
42  msg.getHeaders().add("Cookie", " user_id=1256679245 ");
43  EXPECT_EQ(msg.getCookie("user_id"), "1256679245");
44 }
45 
46 TEST(HTTPMessage, TestParseCookiesMultipleCookies) {
47  HTTPMessage msg;
48 
49  msg.getHeaders().add(
50  "Cookie", "id=1256679245; data=0:1234567; same=Always; Name");
51  msg.getHeaders().add(
52  "Cookie", "id2=1256679245; data2=0:1234567; same=Always; ");
53  EXPECT_EQ(msg.getCookie("id"), "1256679245");
54  EXPECT_EQ(msg.getCookie("id2"), "1256679245");
55  EXPECT_EQ(msg.getCookie("data"), "0:1234567");
56  EXPECT_EQ(msg.getCookie("data2"), "0:1234567");
57  EXPECT_EQ(msg.getCookie("same"), "Always");
58  EXPECT_EQ(msg.getCookie("Name"), "");
59 }
60 
61 TEST(HTTPMessage, TestParseQueryParamsSimple) {
62  HTTPMessage msg;
63  string url = "/test?seq=123456&userid=1256679245&dup=1&dup=2&helloWorld"
64  "&second=was+it+clear+%28already%29%3F";
65 
66  msg.setURL(url);
67  EXPECT_EQ(msg.getQueryParam("seq"), "123456");
68  EXPECT_EQ(msg.getQueryParam("userid"), "1256679245");
69  EXPECT_EQ(msg.getQueryParam("dup"), "2");
70  EXPECT_EQ(msg.getQueryParam("helloWorld"), "");
71  EXPECT_EQ(msg.getIntQueryParam("dup", 5), 2);
72  EXPECT_EQ(msg.getIntQueryParam("abc", 5), 5);
73  EXPECT_EQ(msg.getDecodedQueryParam("second"), "was it clear (already)?");
74  EXPECT_EQ(msg.getDecodedQueryParam("seq"), "123456");
75  EXPECT_EQ(msg.hasQueryParam("seq"), true);
76  EXPECT_EQ(msg.hasQueryParam("seq1"), false);
77  EXPECT_EQ(msg.getIntQueryParam("dup"), 2);
79  EXPECT_ANY_THROW(msg.getIntQueryParam("second"));
80 }
81 
82 TEST(HTTPMessage, TestParseQueryParamsComplex) {
83  HTTPMessage msg;
84  std::vector<std::vector<std::string>> input = {
85  {"", "", ""},
86  {"key_and_equal_but_no_value", "=", ""},
87  {"only_key", "", ""},
88  {"key_and_value", "=", "value"},
89  {"key_and_value_2", "=", "value2"},
90  {"key_and_value_3", "=", "value3"}
91  };
92 
93  for (int i = 0; i < (1 << input.size()); ++i) {
94  std::vector<std::vector<std::string>> sub;
95  for (size_t j = 0; j < input.size(); ++j) {
96  if ((i & (1 << j))) {
97  sub.push_back(input[j]);
98  }
99  }
100 
101  sort(sub.begin(), sub.end());
102  do {
103  bool first = true;
104  std::string url = "/test?";
105  for (const auto& val: sub) {
106  if (first) {
107  first = false;
108  } else {
109  url += "&";
110  }
111 
112  url += val[0] + val[1] + val[2];
113  }
114 
115  msg.setURL(url);
116  for (const auto& val: sub) {
117  if (val[0].empty()) {
118  continue;
119  }
120 
121  EXPECT_EQ(val[2], msg.getQueryParam(val[0]));
122  }
123 
124  } while (next_permutation(sub.begin(), sub.end()));
125  }
126 }
127 
128 TEST(HTTPMessage, TestHeaderPreservation) {
129  HTTPMessage msg;
130  HTTPHeaders& hdrs = msg.getHeaders();
131 
132  hdrs.add("Jojo", "1");
133  hdrs.add("Binky", "2");
134  hdrs.add("jOJo", "3");
135  hdrs.add("bINKy", "4");
136 
137  EXPECT_EQ(hdrs.size(), 4);
138  EXPECT_EQ(hdrs.getNumberOfValues("jojo"), 2);
139  EXPECT_EQ(hdrs.getNumberOfValues("binky"), 2);
140 }
141 
142 TEST(HTTPMessage, TestHeaderRemove) {
143  HTTPMessage msg;
144  HTTPHeaders& hdrs = msg.getHeaders();
145 
146  hdrs.add("Jojo", "1");
147  hdrs.add("Binky", "2");
148  hdrs.add("jOJo", "3");
149  hdrs.add("bINKy", "4");
150  hdrs.remove("jojo");
151 
152  EXPECT_EQ(hdrs.size(), 2);
153  EXPECT_EQ(hdrs.getNumberOfValues("binky"), 2);
154 }
155 
156 TEST(HTTPMessage, TestSetHeader) {
157  HTTPMessage msg;
158  HTTPHeaders& hdrs = msg.getHeaders();
159 
160  hdrs.set("Jojo", "1");
161  EXPECT_EQ(hdrs.size(), 1);
162  EXPECT_EQ(hdrs.getNumberOfValues("Jojo"), 1);
163 
164  hdrs.add("jojo", "2");
165  hdrs.add("jojo", "3");
166  hdrs.add("bar", "4");
167  EXPECT_EQ(hdrs.size(), 4);
168  EXPECT_EQ(hdrs.getNumberOfValues("Jojo"), 3);
169 
170  hdrs.set("joJO", "5");
171  EXPECT_EQ(hdrs.size(), 2);
172  EXPECT_EQ(hdrs.getNumberOfValues("Jojo"), 1);
173 }
174 
175 TEST(HTTPMessage, TestCombine) {
176  HTTPMessage msg;
177  HTTPHeaders& headers = msg.getHeaders();
178 
179  EXPECT_EQ(headers.combine("Combine"), "");
180 
181  headers.add("Combine", "first value");
182  EXPECT_EQ(headers.combine("Combine"), "first value");
183 
184  headers.add("Combine", "second value");
185  EXPECT_EQ(headers.combine("Combine"), "first value, second value");
186 
187  headers.add("Combine", "third value");
188  EXPECT_EQ(headers.combine("Combine"),
189  "first value, second value, third value");
190  VLOG(4) << msg;
191 }
192 
193 TEST(HTTPMessage, TestProxification) {
194  HTTPMessage msg;
195 
196  folly::SocketAddress dstAddr("192.168.1.1", 1887);
197  folly::SocketAddress clientAddr("74.125.127.9", 1987);
198  msg.setDstAddress(dstAddr);
199  msg.setLocalIp("10.0.0.1");
200  msg.ensureHostHeader();
201  msg.setWantsKeepalive(false);
202 
203  HTTPHeaders& hdrs = msg.getHeaders();
204  EXPECT_EQ("192.168.1.1", hdrs.getSingleOrEmpty(HTTP_HEADER_HOST));
206 }
207 
208 TEST(HTTPMessage, TestKeepaliveCheck) {
209  {
210  HTTPMessage msg;
211  msg.setHTTPVersion(1, 0);
213  }
214 
215  {
216  HTTPMessage msg;
217  msg.setHTTPVersion(1, 1);
219  }
220 
221  {
222  HTTPMessage msg;
223  msg.setHTTPVersion(1, 1);
224  msg.getHeaders().add(HTTP_HEADER_CONNECTION, "close");
226  }
227 
228  {
229  HTTPMessage msg;
230  msg.setHTTPVersion(1, 1);
231  msg.getHeaders().add(HTTP_HEADER_CONNECTION, "ClOsE");
233  }
234 
235  {
236  HTTPMessage msg;
237  msg.setHTTPVersion(1, 1);
238  msg.getHeaders().add(HTTP_HEADER_CONNECTION, "foo,bar");
240  }
241 
242  {
243  HTTPMessage msg;
244  msg.setHTTPVersion(1, 1);
245  msg.getHeaders().add(HTTP_HEADER_CONNECTION, "foo,bar");
246  msg.getHeaders().add(HTTP_HEADER_CONNECTION, "abc,CLOSE,def");
247  msg.getHeaders().add(HTTP_HEADER_CONNECTION, "xyz");
249  }
250 
251  {
252  HTTPMessage msg;
253  msg.setHTTPVersion(1, 1);
254  msg.getHeaders().add(HTTP_HEADER_CONNECTION, "foo,bar");
255  msg.getHeaders().add(HTTP_HEADER_CONNECTION, "abc , CLOSE , def");
256  msg.getHeaders().add(HTTP_HEADER_CONNECTION, "xyz");
258  }
259 
260  {
261  HTTPMessage msg;
262  msg.setHTTPVersion(1, 1);
263  msg.getHeaders().add(HTTP_HEADER_CONNECTION, " close ");
265  }
266 
267  {
268  HTTPMessage msg;
269  msg.setHTTPVersion(1, 1);
270  msg.getHeaders().add(HTTP_HEADER_CONNECTION, ", close ");
272  }
273 
274  {
275  HTTPMessage msg;
276  msg.setHTTPVersion(1, 1);
277  msg.getHeaders().add(HTTP_HEADER_CONNECTION, " close , ");
279  }
280 
281  {
282  HTTPMessage msg;
283  msg.setHTTPVersion(1, 0);
284  msg.getHeaders().add(HTTP_HEADER_CONNECTION, "Keep-Alive");
286  }
287 
288  {
289  HTTPMessage msg;
290  msg.setHTTPVersion(1, 0);
291  msg.getHeaders().add(HTTP_HEADER_CONNECTION, "keep-alive");
293  }
294 
295  {
296  HTTPMessage msg;
297  msg.setHTTPVersion(1, 0);
298  msg.getHeaders().add(HTTP_HEADER_CONNECTION, "keep-alive");
299  msg.getHeaders().add(HTTP_HEADER_CONNECTION, "close");
301  }
302 
303  {
304  HTTPMessage msg;
305  msg.setHTTPVersion(1, 0);
306  msg.getHeaders().add(HTTP_HEADER_CONNECTION, "keep-alive");
307  msg.stripPerHopHeaders();
309  }
310 }
311 
312 TEST(HTTPMessage, TestHeaderStripPerHop) {
313  HTTPMessage msg;
314 
315  msg.getHeaders().add(HTTP_HEADER_CONNECTION, "a, b, c");
317  msg.getHeaders().add(HTTP_HEADER_CONNECTION, ",,,,");
318  msg.getHeaders().add(HTTP_HEADER_CONNECTION, " , , , ,");
319  msg.getHeaders().add(HTTP_HEADER_CONNECTION, ", e");
320  msg.getHeaders().add(HTTP_HEADER_CONNECTION, " f ,\tg\t, \r\n\th ");
321  msg.getHeaders().add("Keep-Alive", "true");
322 
323  msg.getHeaders().add("a", "1");
324  msg.getHeaders().add("b", "2");
325  msg.getHeaders().add("c", "3");
326  msg.getHeaders().add("d", "4");
327  msg.getHeaders().add("e", "5");
328  msg.getHeaders().add("f", "6");
329  msg.getHeaders().add("g", "7");
330  msg.getHeaders().add("h", "8");
331 
332  EXPECT_EQ(msg.getHeaders().size(), 15);
333  msg.stripPerHopHeaders();
334  EXPECT_EQ(msg.getHeaders().size(), 0);
336 }
337 
338 TEST(HTTPMessage, TestEmptyName) {
339  HTTPMessage msg;
340  EXPECT_DEATH_NO_CORE(msg.getHeaders().set("", "empty name?!"), ".*");
341 }
342 
343 TEST(HTTPMessage, TestMethod) {
344  HTTPMessage msg;
345 
347  EXPECT_EQ("GET", msg.getMethodString());
348  EXPECT_EQ(HTTPMethod::GET == msg.getMethod(), true);
349 
350  msg.setMethod("FOO");
351  EXPECT_EQ("FOO", msg.getMethodString());
353 
355  EXPECT_EQ("CONNECT", msg.getMethodString());
356  EXPECT_EQ(HTTPMethod::CONNECT == msg.getMethod(), true);
357 }
358 
359 void testPathAndQuery(const string& url,
360  const string& expectedPath,
361  const string& expectedQuery) {
362  HTTPMessage msg;
363  msg.setURL(url);
364 
365  EXPECT_EQ(msg.getURL(), url);
366  EXPECT_EQ(msg.getPath(), expectedPath);
367  EXPECT_EQ(msg.getQueryString(), expectedQuery);
368 }
369 
370 TEST(GetPathAndQuery, ParseURL) {
371  testPathAndQuery("http://localhost:80/foo?bar#qqq", "/foo", "bar");
372  testPathAndQuery("localhost:80/foo?bar#qqq", "/foo", "bar");
373  testPathAndQuery("localhost", "", "");
374  testPathAndQuery("/f/o/o?bar#qqq", "/f/o/o", "bar");
375  testPathAndQuery("#?hello", "", "");
376 }
377 
378 TEST(HTTPHeaders, AddStringPiece) {
379  const char foo[] = "name:value";
380  HTTPHeaders headers;
381 
382  folly::StringPiece str(foo);
384  headers.add(name, str);
385  EXPECT_EQ("value", headers.getSingleOrEmpty("name"));
386 }
387 
388 TEST(HTTPHeaders, InitializerList) {
389  HTTPHeaders hdrs;
390 
391  hdrs.add({{"name", "value"}});
392  hdrs.add({{HTTP_HEADER_CONNECTION, "close"}});
393  hdrs.add({{"a", "b"},
394  {HTTP_HEADER_CONNECTION, "foo"},
395  {HTTP_HEADER_SERVER, "x"}});
396 
397  EXPECT_EQ("value", hdrs.getSingleOrEmpty("name"));
398  EXPECT_EQ("close, foo", hdrs.combine(HTTP_HEADER_CONNECTION));
400 }
401 
402 TEST(HTTPHeaders, InitializerListStringPiece) {
403  HTTPHeaders hdrs;
404 
405  const char* foo = "name:value";
406  folly::StringPiece str(foo);
408  hdrs.add({{name, str}, {HTTP_HEADER_CONNECTION, str}});
409 
410  EXPECT_EQ("value", hdrs.getSingleOrEmpty("name"));
412 }
413 
414 void testRemoveQueryParam(const string& url,
415  const string& queryParam,
416  const string& expectedUrl,
417  const string& expectedQuery) {
418  HTTPMessage msg;
419  msg.setURL(url);
420  bool expectedChange = (url != expectedUrl);
421  EXPECT_EQ(msg.removeQueryParam(queryParam), expectedChange);
422 
423  EXPECT_EQ(msg.getURL(), expectedUrl);
424  EXPECT_EQ(msg.getQueryString(), expectedQuery);
425 }
426 
427 TEST(HTTPMessage, RemoveQueryParamTests) {
428  // Query param present
429  testRemoveQueryParam("http://localhost:80/foo?param1=a&param2=b#qqq",
430  "param2",
431  "http://localhost:80/foo?param1=a#qqq",
432  "param1=a");
433  // Query param not present
434  testRemoveQueryParam("http://localhost/foo?param1=a&param2=b#qqq",
435  "param3",
436  "http://localhost/foo?param1=a&param2=b#qqq",
437  "param1=a&param2=b");
438  // No scheme
439  testRemoveQueryParam("localhost:80/foo?param1=a&param2=b#qqq",
440  "param2",
441  "localhost:80/foo?param1=a#qqq",
442  "param1=a");
443  // Just hostname as URL and empty query param
444  testRemoveQueryParam("localhost", "param2", "localhost", "");
445  testRemoveQueryParam("localhost", "", "localhost", "");
446  // Just path as URL
447  testRemoveQueryParam("/f/o/o?bar#qqq", "bar", "/f/o/o#qqq", "");
448 }
449 
450 void testSetQueryParam(const string& url,
451  const string& queryParam,
452  const string& paramValue,
453  const string& expectedUrl,
454  const string& expectedQuery) {
455  HTTPMessage msg;
456  msg.setURL(url);
457  bool expectedChange = (url != expectedUrl);
458  EXPECT_EQ(msg.setQueryParam(queryParam, paramValue), expectedChange);
459 
460  EXPECT_EQ(msg.getURL(), expectedUrl);
461  EXPECT_EQ(msg.getQueryString(), expectedQuery);
462 }
463 
464 TEST(HTTPMessage, SetQueryParamTests) {
465  // Overwrite existing parameter
466  testSetQueryParam("http://localhost:80/foo?param1=a&param2=b#qqq",
467  "param2",
468  "true",
469  "http://localhost:80/foo?param1=a&param2=true#qqq",
470  "param1=a&param2=true");
471  // Add a query parameter
472  testSetQueryParam("http://localhost/foo?param1=a&param2=b#qqq",
473  "param3",
474  "true",
475  "http://localhost/foo?param1=a&param2=b&param3=true#qqq",
476  "param1=a&param2=b&param3=true");
477  // Add a query parameter, should be alphabetical order
478  testSetQueryParam("localhost:80/foo?param1=a&param3=c#qqq",
479  "param2",
480  "b",
481  "localhost:80/foo?param1=a&param2=b&param3=c#qqq",
482  "param1=a&param2=b&param3=c");
483  // Add a query parameter when no query parameters exist
484  testSetQueryParam("localhost:80/foo#qqq",
485  "param2",
486  "b",
487  "localhost:80/foo?param2=b#qqq",
488  "param2=b");
489 }
490 
491 TEST(HTTPMessage, TestCheckForHeaderToken) {
492  HTTPMessage msg;
493  HTTPHeaders& headers = msg.getHeaders();
494 
495  headers.add(HTTP_HEADER_CONNECTION, "HTTP2-Settings");
497  false));
499  true));
500 }
501 
502 TEST(HttpMessage, TestProtocolStringHTTPVersion) {
503  HTTPMessage msg;
504  msg.setHTTPVersion(1, 1);
505 
506  EXPECT_EQ(msg.getProtocolString(), "1.1");
507 }
508 
509 TEST(HttpMessage, TestProtocolStringAdvancedProtocol) {
510  HTTPMessage msg;
511  std::string advancedProtocol = "h2";
512  msg.setAdvancedProtocolString(advancedProtocol);
513  EXPECT_EQ(msg.getProtocolString(), advancedProtocol);
514 }
#define EXPECT_ANY_THROW(statement)
Definition: gtest.h:1847
Sub sub(Sink sink)
Definition: Parallel.h:104
bool remove(folly::StringPiece name)
void setWantsKeepalive(bool wantsKeepaliveVal)
Definition: HTTPMessage.h:343
const std::string & getPath() const
Definition: HTTPMessage.h:215
void testPathAndQuery(const string &url, const string &expectedPath, const string &expectedQuery)
#define EXPECT_DEATH_NO_CORE(token, regex)
Definition: TestUtils.h:19
#define EXPECT_EQ(val1, val2)
Definition: gtest.h:1922
TEST(HTTPMessage, TestParseCookiesSimple)
void testRemoveQueryParam(const string &url, const string &queryParam, const string &expectedUrl, const string &expectedQuery)
STL namespace.
void setDstAddress(const folly::SocketAddress &addr, std::string addressStr=empty_string, std::string portStr=empty_string)
Definition: HTTPMessage.h:119
double val
Definition: String.cpp:273
size_t getNumberOfValues(HTTPHeaderCode code) const
Range split_step(value_type delimiter)
Definition: Range.h:1001
std::string combine(const T &header, const std::string &separator=COMBINE_SEPARATOR) const
Definition: HTTPHeaders.h:382
const HTTPHeaders & getStrippedPerHopHeaders() const
Definition: HTTPMessage.h:530
void setAdvancedProtocolString(const std::string &protocol)
Definition: HTTPMessage.h:542
void setLocalIp(T &&ip)
Definition: HTTPMessage.h:148
bool computeKeepalive() const
const std::string & getQueryString() const
Definition: HTTPMessage.h:222
const char * name
Definition: http_parser.c:437
void set(folly::StringPiece name, const std::string &value)
Definition: HTTPHeaders.h:119
const folly::StringPiece getCookie(const std::string &name) const
const std::string & getQueryParam(const std::string &name) const
bool checkForHeaderToken(const HTTPHeaderCode headerCode, char const *token, bool caseSensitive) const
constexpr auto empty(C const &c) -> decltype(c.empty())
Definition: Access.h:55
ParseURL setURL(T &&url)
Definition: HTTPMessage.h:183
int getIntQueryParam(const std::string &name) const
bool setQueryParam(const std::string &name, const std::string &value)
HTTPHeaders & getHeaders()
Definition: HTTPMessage.h:273
const std::string & getSingleOrEmpty(const T &nameOrCode) const
Definition: HTTPHeaders.h:420
void setMethod(HTTPMethod method)
size_t size() const
std::string getDecodedQueryParam(const std::string &name) const
#define EXPECT_TRUE(condition)
Definition: gtest.h:1859
bool removeQueryParam(const std::string &name)
const char * string
Definition: Conv.cpp:212
bool hasQueryParam(const std::string &name) const
const std::string & getMethodString() const
void setHTTPVersion(uint8_t major, uint8_t minor)
void add(folly::StringPiece name, folly::StringPiece value)
Definition: HTTPHeaders.cpp:52
#define EXPECT_FALSE(condition)
Definition: gtest.h:1862
folly::Optional< HTTPMethod > getMethod() const
const std::string & getProtocolString() const
Definition: HTTPMessage.h:558
const std::string & getURL() const
Definition: HTTPMessage.h:205
constexpr None none
Definition: Optional.h:87
void testSetQueryParam(const string &url, const string &queryParam, const string &paramValue, const string &expectedUrl, const string &expectedQuery)
bool wantsKeepalive() const
Definition: HTTPMessage.h:346
constexpr detail::First first
Definition: Base-inl.h:2553