1 /* $Id: cgitest.cpp 617534 2020-10-02 15:05:55Z vakatov $
2 * ===========================================================================
3 *
4 * PUBLIC DOMAIN NOTICE
5 * National Center for Biotechnology Information
6 *
7 * This software/database is a "United States Government Work" under the
8 * terms of the United States Copyright Act. It was written as part of
9 * the author's official duties as a United States Government employee and
10 * thus cannot be copyrighted. This software/database is freely available
11 * to the public for use. The National Library of Medicine and the U.S.
12 * Government have not placed any restriction on its use or reproduction.
13 *
14 * Although all reasonable efforts have been taken to ensure the accuracy
15 * and reliability of the software and data, the NLM and the U.S.
16 * Government do not and cannot warrant the performance or results that
17 * may be obtained by using this software or data. The NLM and the U.S.
18 * Government disclaim all warranties, express or implied, including
19 * warranties of performance, merchantability or fitness for any particular
20 * purpose.
21 *
22 * Please cite the author in any work or product based on this material.
23 *
24 * ===========================================================================
25 *
26 * Author: Denis Vakatov, Eugene Vasilchenko, Vsevolod Sandomirsky
27 *
28 * File Description:
29 * TEST for: NCBI C++ core CGI API
30 *
31 */
32
33 #include <ncbi_pch.hpp>
34 #include <corelib/ncbiapp.hpp>
35 #include <corelib/ncbienv.hpp>
36 #include <corelib/ncbireg.hpp>
37 #include <corelib/ncbisys.hpp>
38 #include <cgi/ncbires.hpp>
39 #include <cgi/ncbicgir.hpp>
40 #include <cgi/cgi_util.hpp>
41 #include <cgi/cgi_exception.hpp>
42
43 #include <algorithm>
44 #include <time.h>
45 #include <stdio.h>
46 #include <stdlib.h>
47
48 #include <common/test_assert.h> /* This header must go last */
49
50
51 USING_NCBI_SCOPE;
52
53
54 /////////////////////////////////
55 // CGI
56 //
57
TestCgi_Cookies(void)58 static void TestCgi_Cookies(void)
59 {
60 CCgiCookies cookies("coo1=kie1BAD1;coo2=kie2_ValidPath; ");
61 cookies.Add(" coo1=kie1BAD2;CooT=KieT_ExpTime ");
62
63 string str =
64 "eee; BAD COOKIE; Coo11=Kie11_OK; Coo3=Kie2 SEMI-BAD;"
65 "B COO= 7; X C =3; uuu; coo1=Kie1_OK; Coo6=kie6; iii";
66 cookies.Add(str);
67 cookies.Add("RemoveThisCookie", "BAD");
68 cookies.Add(str);
69
70 assert( cookies.Find("eee") );
71 assert( !cookies.Find("BAD COOKIE") );
72 assert( cookies.Find("Coo11") );
73 assert( cookies.Find("Coo2") );
74 assert( cookies.Find("Coo3") );
75 assert( !cookies.Find("B COO") );
76 assert( !cookies.Find("X C") );
77 assert( !cookies.Find("X C ") );
78 assert( cookies.Find("uuu") );
79 assert( cookies.Find("coo1") );
80 assert( cookies.Find("CooT") );
81 assert( cookies.Find("Coo6") );
82 assert( !cookies.Find("Coo2", "qq.rr.oo", NcbiEmptyString) );
83 assert( !cookies.Find("Coo2", "qq.rr.oo", NcbiEmptyString) );
84 assert(cookies.Find("Coo2") == cookies.Find("Coo2", "", ""));
85 cookies.Find("Coo2")->SetValue("Kie2_OK");
86
87 CCgiCookie c0("Coo5", "Kie5BAD");
88 CCgiCookie c1("Coo5", "Kie", "aaa.bbb.ccc", "/");
89 CCgiCookie c2(c1);
90 c2.SetValue("Kie5_Dom_Sec");
91 c2.SetPath("");
92 c2.SetSecure(true);
93
94 cookies.Add(c1);
95 cookies.Add(c2);
96
97 CCgiCookie* c3 = cookies.Find("coo2", NcbiEmptyString, "");
98 c3->SetPath("coo2_ValidPath");
99
100 assert( !cookies.Remove(cookies.Find("NoSuchCookie")) );
101 assert( cookies.Remove(cookies.Find("RemoveThisCookie")) );
102 assert( !cookies.Remove(cookies.Find("RemoveThisCookie")) );
103 assert( !cookies.Find("RemoveThisCookie") );
104
105 assert( cookies.Find("CoO5") );
106 assert( cookies.Find("cOo5") == cookies.Find("Coo5", "aaa.bBb.ccC", "") );
107 assert( cookies.Find("Coo5")->GetDomain() == "aaa.bbb.ccc" );
108 assert( cookies.Find("coo2")->GetDomain().empty() );
109 assert( cookies.Find("cOO5")->GetSecure() );
110 assert( !cookies.Find("cOo2")->GetSecure() );
111
112 time_t timer = time(0);
113 tm *date = gmtime(&timer);
114 CCgiCookie *ct = cookies.Find("CooT");
115 ct->SetExpDate(*date);
116
117 cookies.Add("AAA", "11", "qq.yy.dd");
118 cookies.Add("AAA", "12", "QQ.yy.Dd");
119 assert( cookies.Find("AAA", "qq.yy.dd", NcbiEmptyString)->GetValue()
120 == "12" );
121
122 cookies.Add("aaa", "1", "QQ.yy.Dd");
123 assert( cookies.Find("AAA", "qq.yy.dd", NcbiEmptyString)->GetValue()
124 == "1" );
125
126 cookies.Add("aaa", "19");
127
128 cookies.Add("aaa", "21", "QQ.yy.Dd", "path");
129 assert( cookies.Find("AAA", "qq.yy.dd", "path")->GetValue() == "21");
130
131 cookies.Add("aaa", "22", "QQ.yy.Dd", "Path");
132 assert( cookies.Find("AAA", "qq.yy.dd", "path")->GetValue() == "21" );
133 assert( cookies.Find("AAA")->GetValue() == "19" );
134
135 cookies.Add("AAA", "2", "QQ.yy.Dd", "path");
136 assert( cookies.Find("AAA", "qq.yy.dd", "path")->GetValue() == "2" );
137
138 cookies.Add("AAA", "3");
139
140 cookies.Add("BBA", "BBA1");
141 cookies.Add("BBA", "BBA2", "", "path");
142
143 cookies.Add("BBB", "B1", "oo.pp.yy");
144 cookies.Add("BBB", "B2");
145 cookies.Add("BBB", "B3", "bb.pp.yy", "path3");
146 cookies.Add("BBB", "B3", "cc.pp.yy", "path3");
147
148 CCgiCookies::TRange range;
149 assert( cookies.Find("BBA", &range)->GetValue() == "BBA1" );
150 assert( cookies.Remove(range) );
151
152 cookies.Add("BBB", "B3", "dd.pp.yy", "path3");
153 cookies.Add("BBB", "B3", "aa.pp.yy", "path3");
154 cookies.Add("BBB", "B3", "", "path3");
155
156 cookies.Add("BBC", "BBC1", "", "path");
157 cookies.Add("BBC", "BBC2", "44.88.99", "path");
158
159 cookies.Add("BBD", "BBD1", "", "path");
160 cookies.Add("BBD", "BBD20", "44.88.99", "path");
161 cookies.Add("BBD", "BBD2", "44.88.99", "path");
162 cookies.Add("BBD", "BBD3", "77.99.00", "path");
163
164 assert( cookies.Remove( cookies.Find("BBB", "dd.pp.yy", "path3") ) );
165
166 cookies.Add("DDD", "DDD1", "aa.bb.cc", "p1/p2");
167 cookies.Add("DDD", "DDD2", "aa.bb.cc");
168 cookies.Add("DDD", "DDD3", "aa.bb.cc", "p3/p4");
169 cookies.Add("DDD", "DDD4", "aa.bb.cc", "p1");
170 cookies.Add("DDD", "DDD5", "aa.bb.cc", "p1/p2/p3");
171 cookies.Add("DDD", "DDD6", "aa.bb.cc", "p1/p4");
172 assert( cookies.Find("DDD", &range)->GetValue() == "DDD2" );
173
174 assert( cookies.Find("BBD", "44.88.99", "path")->GetValue() == "BBD2" );
175 assert( cookies.Remove(cookies.Find("BBD", "77.99.00", "path")) );
176 assert( cookies.Remove("BBD") == 2 );
177
178 string enc_name ="name%20%21%22%23";
179 string enc_val = "val%25%26%27";
180 cookies.Add(enc_name + "=" + enc_val);
181 assert( cookies.Find(NStr::URLDecode(enc_name))->GetValue() ==
182 NStr::URLDecode(enc_val));
183 enc_name ="name with bad chars;";
184 enc_val = "value with bad chars;";
185 cookies.Add(enc_name, enc_val);
186 assert( cookies.Find(NStr::URLDecode(enc_name))->GetValue() ==
187 NStr::URLDecode(enc_val));
188
189 NcbiCerr << "\n\nCookies:\n\n" << cookies << NcbiEndl;
190
191 cookies.Add("bad name=good_value; good_name=bad value; bad both=bad both",
192 CCgiCookies::eOnBadCookie_StoreAndError);
193 CCgiCookies::TCRange rg = cookies.GetAll();
194 for (CCgiCookies::TCIter it = rg.first; it != rg.second; it++) {
195 if ( !(*it)->IsInvalid() ) {
196 _ASSERT(cookies.Find((*it)->GetName()));
197 }
198 }
199 }
200
201
PrintEntries(TCgiEntries & entries)202 static void PrintEntries(TCgiEntries& entries)
203 {
204 for (TCgiEntries::iterator iter = entries.begin();
205 iter != entries.end(); ++iter) {
206 // assert( !NStr::StartsWith(iter->first, "amp;", NStr::eNocase) );
207 NcbiCout << " (\"" << iter->first << "\", \""
208 << iter->second << "\")" << NcbiEndl;
209 }
210 }
211
TestEntries(TCgiEntries & entries,const string & str)212 static bool TestEntries(TCgiEntries& entries, const string& str)
213 {
214 NcbiCout << "\n Entries: `" << str << "'\n";
215 SIZE_TYPE err_pos = CCgiRequest::ParseEntries(str, entries);
216 PrintEntries(entries);
217
218 if ( err_pos ) {
219 NcbiCout << "-- Error at position #" << err_pos << NcbiEndl;
220 return false;
221 }
222 return true;
223 }
224
PrintIndexes(TCgiIndexes & indexes)225 static void PrintIndexes(TCgiIndexes& indexes)
226 {
227 for (TCgiIndexes::iterator iter = indexes.begin();
228 iter != indexes.end(); ++iter) {
229 NcbiCout << " \"" << *iter << "\" ";
230 }
231 NcbiCout << NcbiEndl;
232 }
233
TestIndexes(TCgiIndexes & indexes,const string & str)234 static bool TestIndexes(TCgiIndexes& indexes, const string& str)
235 {
236 NcbiCout << "\n Indexes: `" << str << "'\n";
237 SIZE_TYPE err_pos = CCgiRequest::ParseIndexes(str, indexes);
238 PrintIndexes(indexes);
239
240 if ( err_pos ) {
241 NcbiCout << "-- Error at position #" << err_pos << NcbiEndl;
242 return false;
243 }
244 return true;
245 }
246
TestCgi_Request_Static(void)247 static void TestCgi_Request_Static(void)
248 {
249 // Test CCgiRequest::ParseEntries()
250 TCgiEntries entries;
251 assert( TestEntries(entries, "aa=bb&cc=dd") );
252 assert( TestEntries(entries, "e%20e=f%26f&g%2Ag=h+h%2e") );
253 entries.clear();
254 assert( !TestEntries(entries, " xx=yy") );
255 assert( TestEntries(entries, "xx=&yy=zz") );
256 assert( TestEntries(entries, "rr=") );
257 entries.clear();
258
259 assert( TestEntries(entries, "&&") );
260 assert( TestEntries(entries, "aa") );
261 assert( TestEntries(entries, "bb&") );
262 assert( TestEntries(entries, "&cc") );
263 assert( TestEntries(entries, "&dd&") );
264 assert( TestEntries(entries, "ee&&") );
265 assert( TestEntries(entries, "&&ff") );
266 assert( TestEntries(entries, "&&gg&&") );
267 entries.clear();
268
269 assert( TestEntries(entries, "aa=") );
270 assert( TestEntries(entries, "bb=&") );
271 assert( TestEntries(entries, "&cc=") );
272 assert( TestEntries(entries, "dd=&&") );
273 assert( TestEntries(entries, "&&ee=") );
274 entries.clear();
275
276 assert( TestEntries(entries, "&aa=uu") );
277 assert( TestEntries(entries, "bb=vv&") );
278 assert( TestEntries(entries, "&cc=ww&") );
279 assert( TestEntries(entries, "&&dd=xx") );
280 assert( TestEntries(entries, "ee=yy&&") );
281 assert( TestEntries(entries, "&&ff=zz&&") );
282 entries.clear();
283
284 assert( TestEntries(entries, "aa=vv&&bb=ww") );
285 assert( TestEntries(entries, "cc=&&dd=xx") );
286 assert( TestEntries(entries, "ee=yy&&ff") );
287 assert( TestEntries(entries, "gg&&hh=zz") );
288 entries.clear();
289
290 // assert( !TestEntries(entries, "tt=qq=pp") );
291 assert( TestEntries(entries, "=ggg&ppp=PPP") );
292 assert( TestEntries(entries, "a=d&eee") );
293 assert( TestEntries(entries, "xxx&eee") );
294 assert( TestEntries(entries, "xxx+eee") );
295 assert( TestEntries(entries, "UUU") );
296 assert( TestEntries(entries, "a%21%2f%25aa=%2Fd%2c&eee=%3f") );
297 entries.clear();
298
299 // some older browsers fail to parse & in HREFs; ensure that
300 // we handle it properly.
301 assert( TestEntries(entries, "a=b&c=d&e=f") );
302 assert( TestEntries(entries, "&c=d&e=f") );
303 assert( TestEntries(entries, "&&c=d&&e=f&&") );
304 assert( TestEntries(entries, "amp;c=d&amp;e=f") );
305 entries.clear();
306
307 // Test CCgiRequest::ParseIndexes()
308 TCgiIndexes indexes;
309 assert( TestIndexes(indexes, "a+bb+ccc+d") );
310 assert( TestIndexes(indexes, "e%20e+f%26f+g%2Ag+hh%2e") );
311 indexes.clear();
312 assert( !TestIndexes(indexes, " jhg") );
313 // assert( !TestIndexes(indexes, "e%h%2e+3") );
314 assert( TestIndexes(indexes, "aa+%20+bb") );
315 assert( TestIndexes(indexes, "aa++bb") );
316 indexes.clear();
317 assert( TestIndexes(indexes, "+1") );
318 assert( TestIndexes(indexes, "aa+") );
319 assert( !TestIndexes(indexes, "aa+bb ") );
320 assert( TestIndexes(indexes, "c++b") );
321 assert( !TestIndexes(indexes, "ff++ ") );
322 assert( TestIndexes(indexes, "++") );
323 }
324
TestCgi_Request_Full(CNcbiIstream * istr,const CNcbiArguments * args=0,CCgiRequest::TFlags flags=0)325 static void TestCgi_Request_Full(CNcbiIstream* istr,
326 const CNcbiArguments* args = 0,
327 CCgiRequest::TFlags flags = 0)
328 {
329 CCgiRequest CCR(args, 0, istr, flags);
330
331 NcbiCout << "\n\nCCgiRequest::\n";
332
333 try {
334 NcbiCout << "GetContentLength(): "
335 << CCR.GetContentLength() << NcbiEndl;
336 }
337 STD_CATCH ("TestCgi_Request_Full");
338
339 NcbiCout << "GetRandomProperty(\"USER_AGENT\"): "
340 << CCR.GetRandomProperty("USER_AGENT") << NcbiEndl;
341 NcbiCout << "GetRandomProperty(\"MY_RANDOM_PROP\"): "
342 << CCR.GetRandomProperty("MY_RANDOM_PROP") << NcbiEndl;
343
344 NcbiCout << "GetRandomProperty(\"HTTP_MY_RANDOM_PROP\"): "
345 << CCR.GetRandomProperty("HTTP_MY_RANDOM_PROP")
346 << NcbiEndl;
347 NcbiCout << "GetRandomProperty(\"HTTP_MY_RANDOM_PROP\", false): "
348 << CCR.GetRandomProperty("HTTP_MY_RANDOM_PROP", false)
349 << NcbiEndl;
350
351 NcbiCout << "\nCCgiRequest:: All properties:\n";
352 for (size_t prop = 0; prop < (size_t)eCgi_NProperties; prop++) {
353 NcbiCout << NcbiSetw(24)
354 << CCgiRequest::GetPropertyName((ECgiProp)prop) << " = \""
355 << CCR.GetProperty((ECgiProp)prop) << "\"\n";
356 }
357
358 CCgiCookies cookies;
359 {{ // Just an example of copying the cookies from a request data
360 // Of course, we could use the original request's cookie set
361 // ("x_cookies") if we performed only "const" operations on it
362 const CCgiCookies& x_cookies = CCR.GetCookies();
363 cookies.Add(x_cookies);
364 }}
365 NcbiCout << "\nCCgiRequest:: All cookies:\n";
366 if ( cookies.Empty() )
367 NcbiCout << "No cookies specified" << NcbiEndl;
368 else
369 NcbiCout << cookies << NcbiEndl;
370
371 TCgiEntries entries = CCR.GetEntries();
372 NcbiCout << "\nCCgiRequest:: All entries:\n";
373 if ( entries.empty() ) {
374 NcbiCout << "No entries specified" << NcbiEndl;
375 } else {
376 PrintEntries(entries);
377
378 if ( !CCR.GetEntry("get_query1").empty() ) {
379 NcbiCout << "GetEntry() check." << NcbiEndl;
380
381 assert(CCR.GetEntry("get_query1") == "gq1");
382 bool is_found = false;
383 assert(CCR.GetEntry("get_query1", &is_found) == "gq1");
384 assert(is_found);
385
386 assert(CCR.GetEntry("get_query2", 0).empty());
387 is_found = false;
388 assert(CCR.GetEntry("get_query2", &is_found).empty());
389 assert(is_found);
390
391 assert(CCR.GetEntry("qwe1rtyuioop", &is_found).empty());
392 assert(!is_found);
393 }
394 }
395
396 TCgiIndexes indexes = CCR.GetIndexes();
397 NcbiCout << "\nCCgiRequest:: ISINDEX values:\n";
398 if ( indexes.empty() ) {
399 NcbiCout << "No ISINDEX values specified" << NcbiEndl;
400 } else {
401 PrintIndexes(indexes);
402 }
403
404 CNcbiIstream* is = CCR.GetInputStream();
405 if ( is ) {
406 NcbiCout << "\nUn-parsed content body:\n";
407 NcbiCout << is->rdbuf() << NcbiEndl << NcbiEndl;
408 }
409 }
410
TestCgiMisc(void)411 static void TestCgiMisc(void)
412 {
413 const string str("_ _%_;_\n_:_'_*_\\_\"_");
414 {{
415 string url = "qwerty";
416 url = NStr::URLEncode(str);
417 NcbiCout << str << NcbiEndl << url << NcbiEndl;
418 assert( url.compare("_+_%25_%3B_%0A_%3A_'_*_%5C_%22_") == 0 );
419
420 string str1 = NStr::URLDecode(url);
421 assert( str1 == str );
422
423 string url1 = NStr::URLEncode(str1);
424 assert( url1 == url );
425 }}
426 {{
427 string url = "qwerty";
428 url = NStr::URLEncode(str, NStr::eUrlEnc_ProcessMarkChars);
429 NcbiCout << str << NcbiEndl << url << NcbiEndl;
430 assert( url.compare("%5F+%5F%25%5F%3B%5F%0A%5F%3A%5F%27%5F%2A%5F%5C%5F%22%5F") == 0 );
431
432 string str1 = NStr::URLDecode(url);
433 assert( str1 == str );
434
435 string url1 = NStr::URLEncode(str1, NStr::eUrlEnc_ProcessMarkChars);
436 assert( url1 == url );
437 }}
438
439 const string bad_url("%ax");
440 try {
441 NStr::URLDecode(bad_url);
442 } STD_CATCH("%ax");
443 }
444
445
TestCgi(const CNcbiArguments & args)446 static void TestCgi(const CNcbiArguments& args)
447 {
448 // this is to get rid of warnings on some strict compilers (like SUN Forte)
449 #define X_PUTENV(s) NcbiSysChar_putenv((char*) s)
450
451 TestCgi_Cookies();
452 TestCgi_Request_Static();
453
454 assert( !X_PUTENV("CONTENT_TYPE=application/x-www-form-urlencoded") );
455
456 try { // POST only
457 char inp_str[] = "post11=val11&post12void=&post13=val13";
458 CNcbiIstrstream istr(inp_str);
459 char len[64];
460 assert(::sprintf(len, "CONTENT_LENGTH=%ld", (long) ::strlen(inp_str)));
461 assert( !NcbiSysChar_putenv(len) );
462
463 assert( !X_PUTENV("SERVER_PORT=") );
464 assert( !X_PUTENV("REMOTE_ADDRESS=") );
465 assert( !X_PUTENV("REQUEST_METHOD=POST") );
466 assert( !X_PUTENV("QUERY_STRING=") );
467 assert( !X_PUTENV("HTTP_COOKIE=") );
468 TestCgi_Request_Full(&istr);
469 } STD_CATCH("TestCgi(POST only)");
470
471 try { // POST, fDoNotParseContent
472 char inp_str[] = "post11=val11&post12void=&post13=val13";
473 CNcbiIstrstream istr(inp_str);
474 char len[64];
475 assert(::sprintf(len, "CONTENT_LENGTH=%ld", (long) ::strlen(inp_str)));
476 assert( !NcbiSysChar_putenv(len) );
477
478 assert( !X_PUTENV("SERVER_PORT=") );
479 assert( !X_PUTENV("REMOTE_ADDRESS=") );
480 assert( !X_PUTENV("REQUEST_METHOD=POST") );
481 assert( !X_PUTENV("QUERY_STRING=") );
482 assert( !X_PUTENV("HTTP_COOKIE=") );
483 TestCgi_Request_Full(&istr, 0, CCgiRequest::fDoNotParseContent);
484 } STD_CATCH("TestCgi(POST only)");
485
486 try { // POST + aux. functions
487 char inp_str[] = "post22void=&post23void=";
488 CNcbiIstrstream istr(inp_str);
489 char len[64];
490 assert(::sprintf(len, "CONTENT_LENGTH=%ld", (long) ::strlen(inp_str)));
491 assert( !NcbiSysChar_putenv(len) );
492
493 assert( !X_PUTENV("SERVER_PORT=9999") );
494 assert( !X_PUTENV("HTTP_USER_AGENT=MyUserAgent") );
495 assert( !X_PUTENV("HTTP_MY_RANDOM_PROP=MyRandomPropValue") );
496 assert( !X_PUTENV("REMOTE_ADDRESS=130.14.25.129") );
497 TestCgi_Request_Full(&istr);
498 } STD_CATCH("TestCgi(POST + aux. functions)");
499
500 // this is for all following tests...
501 char inp_str[] = "postXXX=valXXX";
502 char len[64];
503 assert( ::sprintf(len, "CONTENT_LENGTH=%ld", (long) ::strlen(inp_str)) );
504 assert( !NcbiSysChar_putenv(len) );
505
506 try { // POST + ISINDEX(action)
507 CNcbiIstrstream istr(inp_str);
508 assert( !X_PUTENV("QUERY_STRING=isidx1+isidx2+isidx3") );
509 TestCgi_Request_Full(&istr);
510 } STD_CATCH("TestCgi(POST + ISINDEX(action))");
511
512 try { // POST + QUERY(action)
513 CNcbiIstrstream istr(inp_str);
514 assert( !X_PUTENV("QUERY_STRING=query1=vv1&query2=") );
515 TestCgi_Request_Full(&istr);
516 } STD_CATCH("TestCgi(POST + QUERY(action))");
517
518 try { // GET ISINDEX + COOKIES
519 CNcbiIstrstream istr(inp_str);
520 assert( !X_PUTENV("QUERY_STRING=get_isidx1+get_isidx2+get_isidx3") );
521 assert( !X_PUTENV("HTTP_COOKIE=cook1=val1; cook2=val2;") );
522 TestCgi_Request_Full(&istr, 0, CCgiRequest::fIndexesNotEntries);
523 } STD_CATCH("TestCgi(GET ISINDEX + COOKIES)");
524
525 try { // GET REGULAR, NO '='
526 CNcbiIstrstream istr(inp_str);
527 assert( !X_PUTENV("QUERY_STRING=get_query1_empty&get_query2_empty") );
528 TestCgi_Request_Full(&istr);
529 } STD_CATCH("TestCgi(GET REGULAR, NO '=' )");
530
531 try { // GET REGULAR + COOKIES
532 CNcbiIstrstream istr(inp_str);
533 assert( !X_PUTENV("QUERY_STRING=get_query1=gq1&get_query2=") );
534 assert( !X_PUTENV("HTTP_COOKIE=_cook1=_val1;_cook2=_val2") );
535 TestCgi_Request_Full(&istr);
536 } STD_CATCH("TestCgi(GET REGULAR + COOKIES)");
537
538 try { // ERRONEOUS STDIN
539 CNcbiIstrstream istr("123");
540 assert( !X_PUTENV("QUERY_STRING=get_query1=gq1&get_query2=") );
541 assert( !X_PUTENV("HTTP_COOKIE=_cook1=_val1;_cook2=_val2") );
542 TestCgi_Request_Full(&istr);
543 } STD_CATCH("TestCgi(ERRONEOUS STDIN)");
544
545 try { // USER INPUT(real STDIN)
546 assert( !X_PUTENV("QUERY_STRING=u_query1=uq1") );
547 assert( !X_PUTENV("HTTP_COOKIE=u_cook1=u_val1; u_cook2=u_val2") );
548 assert( !X_PUTENV("REQUEST_METHOD=POST") );
549 NcbiCout << "Enter the length of CGI posted data now: " << NcbiFlush;
550 long l = 0;
551 if (!(NcbiCin >> l) || l < 0) {
552 NcbiCin.clear();
553 throw runtime_error("Invalid length of CGI posted data");
554 }
555 char cs[64];
556 assert( ::sprintf(cs, "CONTENT_LENGTH=%ld", (long) l) );
557 assert( !X_PUTENV(cs) );
558 NcbiCout << "Enter the CGI posted data now(no spaces): " << NcbiFlush;
559 NcbiCin >> NcbiWs;
560 TestCgi_Request_Full(0);
561 NcbiCin.clear();
562 } STD_CATCH("TestCgi(USER STDIN)");
563
564 try { // CMD.-LINE ARGS
565 assert( !X_PUTENV("REQUEST_METHOD=") );
566 assert( !X_PUTENV("QUERY_STRING=MUST NOT BE USED HERE!!!") );
567 TestCgi_Request_Full(&NcbiCin/* dummy */, &args);
568 } STD_CATCH("TestCgi(CMD.-LINE ARGS)");
569
570 TestCgiMisc();
571 }
572
573
TestCgiResponse(const CNcbiArguments & args)574 static void TestCgiResponse(const CNcbiArguments& args)
575 {
576 NcbiCout << "Starting CCgiResponse test" << NcbiEndl;
577
578 CCgiResponse response1;
579 // Optional (since it's the default)
580 response1.SetOutput(&NcbiCout);
581
582 if (args.Size() > 2) {
583 CCgiCookies cookies(args[2]);
584 response1.Cookies().Add(cookies);
585 }
586 response1.Cookies().Remove(response1.Cookies().Find("to-Remove"));
587 NcbiCout << "Cookies: " << response1.Cookies() << NcbiEndl;
588
589 CCgiResponse response2;
590
591 NcbiCout << "Generated simple HTTP response:" << NcbiEndl;
592 response2.WriteHeader() << "Data1" << NcbiEndl << NcbiFlush;
593 response2.out() << "Data2" << NcbiEndl << NcbiFlush;
594 NcbiCout << "End of simple HTTP response" << NcbiEndl << NcbiEndl;
595
596 CCgiResponse response3;
597
598 response3.SetHeaderValue("Some-Header-Name", "Some Header Value");
599 response3.SetHeaderValue("status", "399 Something is BAAAAD!!!!!");
600 response3.SetStatus(301, "Moved");
601
602 NcbiCout << "Generated HTTP response:" << NcbiEndl;
603 response3.WriteHeader() << "Data1" << NcbiEndl << NcbiFlush;
604 response3.out() << "Data2" << NcbiEndl << NcbiFlush;
605 NcbiCout << "End of HTTP response" << NcbiEndl << NcbiEndl;
606
607 CCgiResponse response4;
608
609 response4.SetRawCgi(true);
610 NcbiCout << "Generated HTTP \"raw CGI\" response:" << NcbiEndl;
611 response4.WriteHeader() << "Data1" << NcbiEndl << NcbiFlush;
612 response4.out() << "Data2" << NcbiEndl << NcbiFlush;
613 NcbiCout << "End of HTTP \"raw CGI\" response" << NcbiEndl << NcbiEndl;
614
615 try {
616 NcbiCout << "Checking double headed HTTP response:" << NcbiEndl;
617 response4.WriteHeader() << "Data1" << NcbiEndl << NcbiFlush;
618 } catch (CCgiResponseException& e) {
619 _ASSERT(e.GetErrCode() == CCgiResponseException::eDoubleHeader);
620 NCBI_REPORT_EXCEPTION("Caught", e);
621 }
622 NcbiCout << "Checking double headed HTTP response into a different stream:"
623 << NcbiEndl;
624 response4.WriteHeader(NcbiCerr);
625 }
626
627
628 class CTestApplication : public CNcbiApplication
629 {
630 public:
631 virtual ~CTestApplication(void);
632 virtual int Run(void);
633 };
634
635
Run(void)636 int CTestApplication::Run(void)
637 {
638 TestCgi( GetArguments() );
639 TestCgiResponse( GetArguments() );
640 return 0;
641 }
642
643
~CTestApplication()644 CTestApplication::~CTestApplication()
645 {
646 SetDiagStream(0);
647 }
648
649
main(int argc,char ** argv)650 int main(int argc, char** argv)
651 {
652 return CTestApplication().AppMain(argc, argv);
653 }
654