xref: /haiku/src/tests/kits/net/cookie/cookie_test.cpp (revision f8da8f3477d3c18142e59d17d05a545982faa5a8)
1 #include <cstdlib>
2 #include <cstring>
3 #include <cstdio>
4 #include <ctime>
5 #include <iostream>
6 
7 #include <NetworkKit.h>
8 #include <SupportKit.h>
9 
10 #ifdef ASSERT
11 #undef ASSERT
12 #endif
13 
14 #define REPORT(i, assert, line) cout << "ASSERT() failed at line " << line \
15 									<< ": " <<  #assert << " (test #" << i << ")" << endl
16 #define ASSERT(index, assertion) { if (!(assertion)) { REPORT(index, assertion, __LINE__ ); } }
17 
18 
19 using std::cout;
20 using std::endl;
21 
22 
23 typedef struct {
24 	const char* cookieString;
25 	const char*	url;
26 	struct
27 	{
28 		bool		valid;
29 		const char* name;
30 		const char* value;
31 		const char* domain;
32 		const char* path;
33 		bool 		secure;
34 		bool 		httponly;
35 		bool		session;
36 		BDateTime	expire;
37 	} expected;
38 } ExplodeTest;
39 
40 
41 ExplodeTest kTestExplode[] =
42 	//     Cookie string      URL
43 	//     ------------- -------------
44 	//		   Valid     Name     Value	       Domain         Path      Secure  HttpOnly Session  Expiration
45 	//       --------- -------- --------- ----------------- ---------  -------- -------- -------  ----------
46 	{
47 		// Normal cookies
48 		{ "name=value", "http://www.example.com/path/path",
49 			{  true,    "name",  "value", "www.example.com", "/path",   false,   false,   true,   BDateTime() } },
50 		{ "name=value; domain=example.com; path=/; secure", "http://www.example.com/path/path",
51 			{  true,    "name",  "value",   "example.com",   "/"    ,   true,    false,   true,   BDateTime() } },
52 		{ "name=value; httponly; secure", "http://www.example.com/path/path",
53 			{  true,    "name",  "value", "www.example.com", "/path",   true,    true,    true,   BDateTime() } },
54 		{ "name=value; expires=Wed, 20 Feb 2013 20:00:00 UTC", "http://www.example.com/path/path",
55 			{  true,    "name",  "value", "www.example.com", "/path",   false,   false,   false,
56 				BDateTime(BDate(2012, 2, 20), BTime(20, 0, 0, 0)) } },
57 		// Valid cookie with bad form
58 		{ "name=  ;  domain   =example.com  ;path=/;  secure = yup  ; blahblah ;)", "http://www.example.com/path/path",
59 			{  true,    "name",  "",   "example.com",   "/"    ,   true,    false,   true,   BDateTime() } },
60 		// Invalid path, default path should be used instead
61 		{ "name=value; path=invalid", "http://www.example.com/path/path",
62 			{  true,    "name",  "value", "www.example.com", "/path",   false,   false,   true,   BDateTime() } },
63 		// Setting for other subdomain (invalid)
64 		{ "name=value; domain=subdomain.example.com", "http://www.example.com/path/path",
65 			{  false,   "name",  "value", "www.example.com", "/path",   false,   false,   true,   BDateTime() } },
66 		// Various invalid cookies
67 		{ "name", "http://www.example.com/path/path",
68 			{  false,   "name",  "value", "www.example.com", "/path",   false,   false,   true,   BDateTime() } },
69 		{ "; domain=example.com", "http://www.example.com/path/path",
70 			{  false,   "name",  "value", "www.example.com", "/path",   false,   false,   true,   BDateTime() } }
71 	};
72 
73 
74 void explodeImplodeTest()
75 {
76 	uint32 testIndex;
77 	BNetworkCookie cookie;
78 
79 	for (testIndex = 0; testIndex < (sizeof(kTestExplode) / sizeof(ExplodeTest)); testIndex++)
80 	{
81 		BUrl url(kTestExplode[testIndex].url);
82 		cookie.ParseCookieStringFromUrl(kTestExplode[testIndex].cookieString, url);
83 
84 		ASSERT(testIndex, kTestExplode[testIndex].expected.valid == cookie.IsValid());
85 
86 		if (kTestExplode[testIndex].expected.valid) {
87 			ASSERT(testIndex, BString(kTestExplode[testIndex].expected.name) == cookie.Name());
88 			ASSERT(testIndex, BString(kTestExplode[testIndex].expected.value) == cookie.Value());
89 			ASSERT(testIndex, BString(kTestExplode[testIndex].expected.domain) == cookie.Domain());
90 			ASSERT(testIndex, BString(kTestExplode[testIndex].expected.path) == cookie.Path());
91 			ASSERT(testIndex, kTestExplode[testIndex].expected.secure == cookie.Secure());
92 			ASSERT(testIndex, kTestExplode[testIndex].expected.httponly == cookie.HttpOnly());
93 			ASSERT(testIndex, kTestExplode[testIndex].expected.session == cookie.IsSessionCookie());
94 
95 			if (!cookie.IsSessionCookie())
96 				ASSERT(testIndex, kTestExplode[testIndex].expected.expire.Time_t() == cookie.ExpirationDate());
97 		}
98 	}
99 }
100 
101 
102 void stressTest(int32 domainNumber, int32 totalCookies, char** flat, ssize_t* size)
103 {
104 	char **domains = new char*[domainNumber];
105 
106 	cout << "Creating random domains" << endl;
107 	srand(time(NULL));
108 	for (int32 i = 0; i < domainNumber; i++) {
109 		int16 charNum = (rand() % 16) + 1;
110 
111 		domains[i] = new char[charNum + 5];
112 
113 		// Random domain
114 		for (int32 c = 0; c < charNum; c++)
115 			domains[i][c] = (rand() % 26) + 'a';
116 
117 		domains[i][charNum] = '.';
118 
119 		// Random tld
120 		for (int32 c = 0; c < 3; c++)
121 			domains[i][charNum+1+c] = (rand() % 26) + 'a';
122 
123 		domains[i][charNum+4] = 0;
124 	}
125 
126 	BNetworkCookieJar j;
127 	BStopWatch* watch = new BStopWatch("Cookie insertion");
128 	for (int32 i = 0; i < totalCookies; i++) {
129 		BNetworkCookie c;
130 		int16 domain = (rand() % domainNumber);
131 		BString name("Foo");
132 		name << i;
133 
134 		c.SetName(name);
135 		c.SetValue("Bar");
136 		c.SetDomain(domains[domain]);
137 		c.SetPath("/");
138 
139 		j.AddCookie(c);
140 	}
141 	delete watch;
142 
143 	BNetworkCookie* c;
144 	int16 domain = (rand() % domainNumber);
145 	BString host("http://");
146 	host << domains[domain] << "/";
147 
148 	watch = new BStopWatch("Cookie filtering");
149 	BUrl url(host);
150 	int32 count = 0;
151 	for (BNetworkCookieJar::UrlIterator it(j.GetUrlIterator(url)); (c = it.Next()); ) {
152 	//for (BNetworkCookieJar::Iterator it(j.GetIterator()); c = it.Next(); ) {
153 		count++;
154 	}
155 	delete watch;
156 	cout << "Count for " << host << ": " << count << endl;
157 
158 
159 	cout << "Flat view of cookie jar is " << j.FlattenedSize() << " bytes large." << endl;
160 	*flat = new char[j.FlattenedSize()];
161 	*size = j.FlattenedSize();
162 
163 	if (j.Flatten(*flat, j.FlattenedSize()) == B_OK)
164 		cout << "Flatten() success!" << endl;
165 	else
166 		cout << "Flatten() error!" << endl;
167 
168 	delete[] domains;
169 }
170 
171 
172 int
173 main(int, char**)
174 {
175 	cout << "Running explodeImplodeTest:" << endl;
176 	explodeImplodeTest();
177 	cout << endl << endl;
178 
179 	cout << "Running stressTest:" << endl;
180 	char* flatJar;
181 	ssize_t size;
182 	stressTest(10000, 40000, &flatJar, &size);
183 
184 	BNetworkCookieJar j;
185 	j.Unflatten(B_ANY_TYPE, flatJar, size);
186 
187 	int32 count = 0;
188 	BNetworkCookie* c;
189 	for (BNetworkCookieJar::Iterator it(j.GetIterator()); (c = it.Next()); )
190 		count++;
191 	cout << "Count : " << count << endl;
192 
193 	delete[] flatJar;
194 
195 	return EXIT_SUCCESS;
196 }
197