• Main Page
  • Related Pages
  • Namespaces
  • Data Structures
  • Files
  • File List
  • Globals

HdrTest.cc

Go to the documentation of this file.
00001 /** @file
00002 
00003   A brief file description
00004 
00005   @section license License
00006 
00007   Licensed to the Apache Software Foundation (ASF) under one
00008   or more contributor license agreements.  See the NOTICE file
00009   distributed with this work for additional information
00010   regarding copyright ownership.  The ASF licenses this file
00011   to you under the Apache License, Version 2.0 (the
00012   "License"); you may not use this file except in compliance
00013   with the License.  You may obtain a copy of the License at
00014 
00015       http://www.apache.org/licenses/LICENSE-2.0
00016 
00017   Unless required by applicable law or agreed to in writing, software
00018   distributed under the License is distributed on an "AS IS" BASIS,
00019   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
00020   See the License for the specific language governing permissions and
00021   limitations under the License.
00022  */
00023 
00024 /****************************************************************************
00025 
00026    HdrTest.cc
00027 
00028    Description:
00029        Unit test code for sanity checking the header system is functioning
00030          properly
00031 
00032 
00033  ****************************************************************************/
00034 
00035 #include "libts.h"
00036 
00037 #include "Arena.h"
00038 #include "HTTP.h"
00039 #include "MIME.h"
00040 #include "Regex.h"
00041 #include "URL.h"
00042 #include "HttpCompat.h"
00043 
00044 #include "HdrTest.h"
00045 
00046 //////////////////////
00047 // Main Test Driver //
00048 //////////////////////
00049 
00050 int
00051 HdrTest::go(RegressionTest * t, int /* atype ATS_UNUSED */)
00052 {
00053   HdrTest::rtest = t;
00054   int status = 1;
00055 
00056   hdrtoken_init();
00057   url_init();
00058   mime_init();
00059   http_init();
00060 
00061   status = status & test_error_page_selection();
00062   status = status & test_http_hdr_print_and_copy();
00063   status = status & test_comma_vals();
00064   status = status & test_parse_comma_list();
00065   status = status & test_set_comma_vals();
00066   status = status & test_delete_comma_vals();
00067   status = status & test_extend_comma_vals();
00068   status = status & test_insert_comma_vals();
00069   status = status & test_accept_language_match();
00070   status = status & test_accept_charset_match();
00071   status = status & test_parse_date();
00072   status = status & test_format_date();
00073   status = status & test_url();
00074   status = status & test_arena();
00075   status = status & test_regex();
00076   status = status & test_http_parser_eos_boundary_cases();
00077   status = status & test_http_mutation();
00078   status = status & test_mime();
00079   status = status & test_http();
00080 
00081   return (status ? REGRESSION_TEST_PASSED : REGRESSION_TEST_FAILED);
00082 }
00083 
00084 ////////////////////////////////////////////////////////////
00085 // Individual Tests --- return 1 on success, 0 on failure //
00086 ////////////////////////////////////////////////////////////
00087 
00088 int
00089 HdrTest::test_error_page_selection()
00090 {
00091   static struct
00092   {
00093     const char *set_name;
00094     const char *content_language;
00095     const char *content_charset;
00096   } sets[] = {
00097     {
00098     "default", "en", "iso-8859-1"}, {
00099     "en-cockney", "en-cockney", "iso-8859-1"}, {
00100     "en", "en", "iso-8859-1"}, {
00101     "en-us", "en-us", "us-ascii"}, {
00102     "en", "en", "unicode"}, {
00103     "en-cockney-slang", "en-cockney-slang", "iso-8859-1"}, {
00104     "ko", "ko", "iso-8859-1"}, {
00105     "ko", "ko", "iso-2022-kr"}, {
00106     "jp", "jp", "shift-jis"}
00107   };
00108 
00109   static struct
00110   {
00111     const char *accept_language;
00112     const char *accept_charset;
00113     const char *expected_set;
00114     float expected_Q;
00115     int expected_La;
00116     int expected_I;
00117   } tests[] = {
00118     {
00119     NULL, NULL, "default", 1, 0, INT_MAX}, {
00120     "en", NULL, "en", 1, 2, 1}, {
00121     "ko", NULL, "ko", 1, 2, 1}, {
00122     "en-us", NULL, "en-us", 1, 5, 1}, {
00123     "en-US", NULL, "en-us", 1, 5, 1}, {
00124     "en,ko", NULL, "en", 1, 2, 1}, {
00125     "ko,en", NULL, "ko", 1, 2, 1}, {
00126     "en;q=0.7,ko", NULL, "ko", 1, 2, 2}, {
00127     "en;q=.7,ko", NULL, "ko", 1, 2, 2}, {
00128     "en;q=.7,ko;q=.7", NULL, "en", 0.7, 2, 1}, {
00129     "en;q=.7,ko;q=.701", NULL, "ko", 0.701, 2, 2}, {
00130     "en;q=.7  ,  ko;q=.701", NULL, "ko", 0.701, 2, 2}, {
00131     "en  ;  q=.7  ,  ko  ;  ;  ;  ; q=.701", NULL, "ko", 0.701, 2, 2}, {
00132     "en,ko;q=.7", NULL, "en", 1, 2, 1}, {
00133     "en;q=1,ko;q=.7", NULL, "en", 1, 2, 1}, {
00134     "en;;;q=1,ko;q=.7", NULL, "en", 1, 2, 1}, {
00135     "en;;;q=1,,,,ko;q=.7", NULL, "en", 1, 2, 1}, {
00136     "en;;;q=.7,,,,ko;q=.7", NULL, "en", 0.7, 2, 1}, {
00137     "en;;;q=.699,,,,ko;q=.7", NULL, "ko", 0.7, 2, 5}, {
00138     "en;q=0,ko;q=1", NULL, "ko", 1, 2, 2}, {
00139     "en;q=0, ko;q=1", NULL, "ko", 1, 2, 2}, {
00140     "en;q=0,ko;q=.5", NULL, "ko", 0.5, 2, 2}, {
00141     "en;q=0, ko;q=.5", NULL, "ko", 0.5, 2, 2}, {
00142     "en;q=000000000.00000000000000000000,ko;q=1.0000000000000000000", NULL, "ko", 1, 2, 2}
00143   };
00144 
00145   bri_box("test_error_page_selection");
00146 
00147   int i;
00148   int failures = 0;
00149 
00150   int nsets = sizeof(sets) / sizeof(sets[0]);
00151   int ntests = sizeof(tests) / sizeof(tests[0]);
00152 
00153   // (1) build fake hash table of sets
00154 
00155   RawHashTable *table_of_sets = new RawHashTable(RawHashTable_KeyType_String);
00156 
00157   for (i = 0; i < nsets; i++) {
00158     HttpBodySetRawData *body_set;
00159 
00160     body_set = (HttpBodySetRawData *)ats_malloc(sizeof(HttpBodySetRawData));
00161     body_set->magic = 0;
00162     body_set->set_name = (char *) (sets[i].set_name);
00163     body_set->content_language = (char *) (sets[i].content_language);
00164     body_set->content_charset = (char *) (sets[i].content_charset);
00165     body_set->table_of_pages = (RawHashTable *) 1;      // hack --- can't be NULL
00166 
00167     table_of_sets->setValue((RawHashTable_Key) (body_set->set_name), (RawHashTable_Value) body_set);
00168   }
00169 
00170   // (2) for each test, parse accept headers into lists, and test matching
00171 
00172   for (i = 0; i < ntests; i++) {
00173     float Q_best;
00174     int La_best, Lc_best, I_best;
00175     const char *set_best;
00176 
00177     StrList accept_language_list;
00178     StrList accept_charset_list;
00179 
00180     HttpCompat::parse_comma_list(&accept_language_list, tests[i].accept_language);
00181     HttpCompat::parse_comma_list(&accept_charset_list, tests[i].accept_charset);
00182 
00183     printf("         test #%d: (Accept-Language='%s', Accept-Charset='%s')\n",
00184            i + 1,
00185            (tests[i].accept_language ? tests[i].accept_language : "<null>"),
00186            (tests[i].accept_charset ? tests[i].accept_charset : "<null>"));
00187 
00188     set_best = HttpCompat::determine_set_by_language(table_of_sets,
00189                                                      &(accept_language_list), &(accept_charset_list),
00190                                                      &Q_best, &La_best, &Lc_best, &I_best);
00191 
00192     if ((strcmp(set_best, tests[i].expected_set) == 0) &&
00193         (Q_best == tests[i].expected_Q) && (La_best == tests[i].expected_La) && (I_best == tests[i].expected_I)) {
00194       printf("SUCCESS: test #%d expected [ S='%s', Q=%g, La=%d, I=%d ] got [ S='%s', Q=%g, La=%d, I=%d ]\n",
00195              i + 1,
00196              tests[i].expected_set, tests[i].expected_Q, tests[i].expected_La, tests[i].expected_I,
00197              set_best, Q_best, La_best, I_best);
00198     } else {
00199       ++failures;
00200       printf(" FAILED: test #%d expected [ S='%s', Q=%g, La=%d, I=%d ] got [ S='%s', Q=%g, La=%d, I=%d ]\n",
00201              i + 1,
00202              tests[i].expected_set, tests[i].expected_Q, tests[i].expected_La, tests[i].expected_I,
00203              set_best, Q_best, La_best, I_best);
00204     }
00205   }
00206 
00207   delete table_of_sets;
00208   return (failures_to_status("test_error_page_selection", failures));
00209 }
00210 
00211 /*-------------------------------------------------------------------------
00212   -------------------------------------------------------------------------*/
00213 
00214 int
00215 HdrTest::test_parse_date()
00216 {
00217   static struct
00218   {
00219     const char *fast;
00220     const char *slow;
00221   } dates[] = {
00222     {
00223     "Sun, 06 Nov 1994 08:49:37 GMT", "Sunday, 06-Nov-1994 08:49:37 GMT"}, {
00224     "Mon, 07 Nov 1994 08:49:37 GMT", "Monday, 07-Nov-1994 08:49:37 GMT"}, {
00225     "Tue, 08 Nov 1994 08:49:37 GMT", "Tuesday, 08-Nov-1994 08:49:37 GMT"}, {
00226     "Wed, 09 Nov 1994 08:49:37 GMT", "Wednesday, 09-Nov-1994 08:49:37 GMT"}, {
00227     "Thu, 10 Nov 1994 08:49:37 GMT", "Thursday, 10-Nov-1994 08:49:37 GMT"}, {
00228     "Fri, 11 Nov 1994 08:49:37 GMT", "Friday, 11-Nov-1994 08:49:37 GMT"}, {
00229     "Sat, 11 Nov 1994 08:49:37 GMT", "Saturday, 11-Nov-1994 08:49:37 GMT"}, {
00230     "Sun, 03 Jan 1999 08:49:37 GMT", "Sunday, 03-Jan-1999 08:49:37 GMT"}, {
00231     "Sun, 07 Feb 1999 08:49:37 GMT", "Sunday, 07-Feb-1999 08:49:37 GMT"}, {
00232     "Sun, 07 Mar 1999 08:49:37 GMT", "Sunday, 07-Mar-1999 08:49:37 GMT"}, {
00233     "Sun, 04 Apr 1999 08:49:37 GMT", "Sunday, 04-Apr-1999 08:49:37 GMT"}, {
00234     "Sun, 02 May 1999 08:49:37 GMT", "Sunday, 02-May-1999 08:49:37 GMT"}, {
00235     "Sun, 06 Jun 1999 08:49:37 GMT", "Sunday, 06-Jun-1999 08:49:37 GMT"}, {
00236     "Sun, 04 Jul 1999 08:49:37 GMT", "Sunday, 04-Jul-1999 08:49:37 GMT"}, {
00237     "Sun, 01 Aug 1999 08:49:37 GMT", "Sunday, 01-Aug-1999 08:49:37 GMT"}, {
00238     "Sun, 05 Sep 1999 08:49:37 GMT", "Sunday, 05-Sep-1999 08:49:37 GMT"}, {
00239     "Sun, 03 Oct 1999 08:49:37 GMT", "Sunday, 03-Oct-1999 08:49:37 GMT"}, {
00240     "Sun, 07 Nov 1999 08:49:37 GMT", "Sunday, 07-Nov-1999 08:49:37 GMT"}, {
00241     "Sun, 05 Dec 1999 08:49:37 GMT", "Sunday, 05-Dec-1999 08:49:37 GMT"}, {
00242   NULL, NULL}};
00243 
00244   int i;
00245   int failures = 0;
00246   time_t fast_t, slow_t;
00247 
00248   bri_box("test_parse_date");
00249 
00250   for (i = 0; dates[i].fast; i++) {
00251     fast_t = mime_parse_date(dates[i].fast, dates[i].fast + (int) strlen(dates[i].fast));
00252     slow_t = mime_parse_date(dates[i].slow, dates[i].slow + (int) strlen(dates[i].slow));
00253     // compare with strptime here!
00254     if (fast_t != slow_t) {
00255       printf("FAILED: date %lu (%s) != %lu (%s)\n",
00256              (unsigned long) fast_t, dates[i].fast, (unsigned long) slow_t, dates[i].slow);
00257       ++failures;
00258     }
00259   }
00260 
00261   return (failures_to_status("test_parse_date", failures));
00262 }
00263 
00264 /*-------------------------------------------------------------------------
00265   -------------------------------------------------------------------------*/
00266 
00267 int
00268 HdrTest::test_format_date()
00269 {
00270   static const char *dates[] = {
00271     "Sun, 06 Nov 1994 08:49:37 GMT",
00272     "Sun, 03 Jan 1999 08:49:37 GMT",
00273     "Sun, 05 Dec 1999 08:49:37 GMT",
00274     "Tue, 25 Apr 2000 20:29:53 GMT",
00275     NULL
00276   };
00277 
00278   bri_box("test_format_date");
00279 
00280   // (1) Test a few hand-created dates
00281 
00282   int i;
00283   time_t t, t2, t3;
00284   char buffer[128], buffer2[128];
00285   static const char *envstr = "TZ=GMT0";
00286   int failures = 0;
00287 
00288   // shift into GMT timezone for cftime conversions
00289   putenv((char*)envstr);
00290   tzset();
00291 
00292   for (i = 0; dates[i]; i++) {
00293     t = mime_parse_date(dates[i], dates[i] + (int) strlen(dates[i]));
00294 
00295     cftime_replacement(buffer, sizeof(buffer), "%a, %d %b %Y %T %Z", &t);
00296     if (memcmp(dates[i], buffer, 29) != 0) {
00297       printf("FAILED: original date doesn't match cftime date\n");
00298       printf("  input date:  %s\n", dates[i]);
00299       printf("  cftime date: %s\n", buffer);
00300       ++failures;
00301     }
00302 
00303     mime_format_date(buffer, t);
00304     if (memcmp(dates[i], buffer, 29) != 0) {
00305       printf("FAILED: original date doesn't match mime_format_date date\n");
00306       printf("  input date:  %s\n", dates[i]);
00307       printf("  cftime date: %s\n", buffer);
00308       ++failures;
00309     }
00310   }
00311 
00312   // (2) test a few times per day from 1/1/1970 to past 2010
00313 
00314   // coverity[secure_coding]
00315   for (t = 0; t < 40 * 366 * (24 * 60 * 60); t += (int) (drand48() * (24 * 60 * 60))) {
00316     cftime_replacement(buffer, sizeof(buffer), "%a, %d %b %Y %T %Z", &t);
00317     t2 = mime_parse_date(buffer, buffer + (int) strlen(buffer));
00318     if (t2 != t) {
00319       printf("FAILED: parsed time_t doesn't match original time_t\n");
00320       printf("  input time_t:  %d (%s)\n", (int) t, buffer);
00321       printf("  parsed time_t: %d\n", (int) t2);
00322       ++failures;
00323     }
00324     mime_format_date(buffer2, t);
00325     if (memcmp(buffer, buffer2, 29) != 0) {
00326       printf("FAILED: formatted date doesn't match original date\n");
00327       printf("  original date:  %s\n", buffer);
00328       printf("  formatted date: %s\n", buffer2);
00329       ++failures;
00330     }
00331     t3 = mime_parse_date(buffer2, buffer2 + (int) strlen(buffer2));
00332     if (t != t3) {
00333       printf("FAILED: parsed time_t doesn't match original time_t\n");
00334       printf("  input time_t:  %d (%s)\n", (int) t, buffer2);
00335       printf("  parsed time_t: %d\n", (int) t3);
00336       ++failures;
00337     }
00338 
00339     if (failures > 20) {
00340       // Already too many failures, don't need to continue
00341       break;
00342     }
00343   }
00344 
00345   return (failures_to_status("test_format_date", failures));
00346 }
00347 
00348 /*-------------------------------------------------------------------------
00349   -------------------------------------------------------------------------*/
00350 
00351 int
00352 HdrTest::test_url()
00353 {
00354   static const char *strs[] = {
00355     "http://some.place/path;params?query#fragment",
00356 
00357     // Start with an easy one...
00358     "http://trafficserver.apache.org/index.html",
00359 
00360     // "cheese://bogosity",         This fails, but it's not clear it should work...
00361 
00362     "some.place",
00363     "some.place/",
00364     "http://some.place",
00365     "http://some.place/",
00366     "http://some.place/path",
00367     "http://some.place/path;params",
00368     "http://some.place/path;params?query",
00369     "http://some.place/path;params?query#fragment",
00370     "http://some.place/path?query#fragment",
00371     "http://some.place/path#fragment",
00372 
00373     "some.place:80",
00374     "some.place:80/",
00375     "http://some.place:80",
00376     "http://some.place:80/",
00377 
00378     "foo@some.place:80",
00379     "foo@some.place:80/",
00380     "http://foo@some.place:80",
00381     "http://foo@some.place:80/",
00382 
00383     "foo:bar@some.place:80",
00384     "foo:bar@some.place:80/",
00385     "http://foo:bar@some.place:80",
00386     "http://foo:bar@some.place:80/",
00387 
00388     // Some address stuff
00389     "http://172.16.28.101",
00390     "http://172.16.28.101:8080",
00391     "http://[::]",
00392     "http://[::1]",
00393     "http://[fc01:172:16:28::101]",
00394     "http://[fc01:172:16:28::101]:80",
00395     "http://[fc01:172:16:28:BAAD:BEEF:DEAD:101]",
00396     "http://[fc01:172:16:28:BAAD:BEEF:DEAD:101]:8080",
00397     "http://172.16.28.101/some/path",
00398     "http://172.16.28.101:8080/some/path",
00399     "http://[::1]/some/path",
00400     "http://[fc01:172:16:28::101]/some/path",
00401     "http://[fc01:172:16:28::101]:80/some/path",
00402     "http://[fc01:172:16:28:BAAD:BEEF:DEAD:101]/some/path",
00403     "http://[fc01:172:16:28:BAAD:BEEF:DEAD:101]:8080/some/path",
00404     "http://172.16.28.101/",
00405     "http://[fc01:172:16:28:BAAD:BEEF:DEAD:101]:8080/",
00406 
00407 
00408     "foo:bar@some.place",
00409     "foo:bar@some.place/",
00410     "http://foo:bar@some.place",
00411     "http://foo:bar@some.place/",
00412     "http://foo:bar@[::1]:8080/",
00413     "http://foo@[::1]",
00414 
00415     "mms://sm02.tsqa.example.com/0102rally.asf",
00416     "pnm://foo:bar@some.place:80/path;params?query#fragment",
00417     "rtsp://foo:bar@some.place:80/path;params?query#fragment",
00418     "rtspu://foo:bar@some.place:80/path;params?query#fragment",
00419     "/finance/external/cbsm/*http://cbs.marketwatch.com/archive/19990713/news/current/net.htx?source=blq/yhoo&dist=yhoo",
00420     "http://a.b.com/xx.jpg?newpath=http://bob.dave.com"
00421   };
00422   static int nstrs = sizeof(strs) / sizeof(strs[0]);
00423 
00424   static char const* bad[] = {
00425     "http://[1:2:3:4:5:6:7:8:9]",
00426     "http://1:2:3:4:5:6:7:8:A:B",
00427     "http://bob.com[::1]",
00428     "http://[::1].com"
00429     "http://foo:bar:baz@bob.com/",
00430     "http://foo:bar:baz@[::1]:8080/",
00431     "http://]",
00432     "http://:",
00433     "http:/"
00434   };
00435   static int nbad = sizeof(bad) / sizeof(bad[0]);
00436 
00437   int err, failed;
00438   URL url;
00439   const char *start;
00440   const char *end;
00441   int i, old_length, new_length;
00442 
00443   bri_box("test_url");
00444 
00445   failed = 0;
00446   for (i = 0; i < nstrs; i++) {
00447     old_length = (int) strlen(strs[i]);
00448     start = strs[i];
00449     end = start + old_length;
00450 
00451     url.create(NULL);
00452     err = url.parse(&start, end);
00453     if (err < 0) {
00454       failed = 1;
00455       break;
00456     }
00457 
00458     char print_buf[1024];
00459     new_length = 0;
00460     int offset = 0;
00461     url.print(print_buf, 1024, &new_length, &offset);
00462     print_buf[new_length] = '\0';
00463 
00464     const char *fail_text = NULL;
00465 
00466     if (old_length == new_length) {
00467       if (memcmp(print_buf, strs[i], new_length) != 0)
00468         fail_text = "URLS DIFFER";
00469     } else if (old_length == new_length - 1) {
00470       // Check to see if the difference is the trailing
00471       //   slash we add
00472       if (memcmp(print_buf, strs[i], old_length) != 0 ||
00473           print_buf[new_length - 1] != '/' || (strs[i])[old_length - 1] == '/') {
00474         fail_text = "TRAILING SLASH";
00475       }
00476     } else {
00477       fail_text = "LENGTHS DIFFER";
00478     }
00479 
00480     if (fail_text) {
00481       failed = 1;
00482       printf("%16s: OLD: (%4d) %s\n", fail_text, old_length, strs[i]);
00483       printf("%16s: NEW: (%4d) %s\n", "", new_length, print_buf);
00484       obj_describe(url.m_url_impl, true);
00485     } else {
00486       printf("%16s: '%s'\n", "PARSE SUCCESS", strs[i]);
00487     }
00488 
00489     url.destroy();
00490   }
00491 
00492   for (i = 0 ; i < nbad ; ++i) {
00493     char const* x = bad[i];
00494     url.create(NULL);
00495     err = url.parse(x, strlen(x));
00496     url.destroy();
00497     if (err == PARSE_DONE) {
00498       failed = 1;
00499       printf("Successfully parsed invalid url '%s'", x);
00500       break;
00501     }
00502   }
00503 
00504 #if 0
00505   if (!failed) {
00506     Note("URL performance test start");
00507     for (int j = 0 ; j < 100000 ; ++j) {
00508       for (i = 0 ; i < nstrs ; ++i) {
00509         char const* x = strs[i];
00510         url.create(NULL);
00511         err = url.parse(x, strlen(x));
00512         url.destroy();
00513       }
00514     }
00515     Note("URL performance test end");
00516   }
00517 #endif
00518 
00519   return (failures_to_status("test_url", failed));
00520 }
00521 
00522 /*-------------------------------------------------------------------------
00523   -------------------------------------------------------------------------*/
00524 
00525 int
00526 HdrTest::test_mime()
00527 {
00528   static const char mime[] = {
00529     //        "Date: Tuesday, 08-Dec-98 20:32:17 GMT\r\n"
00530     "Date: 6 Nov 1994 08:49:37 GMT\r\n"
00531       "Max-Forwards: 65535\r\n"
00532       "Cache-Control: private\r\n"
00533       "accept: foo\r\n"
00534       "accept: bar\n"
00535       ": (null) field name\r\n"
00536       "aCCept: \n"
00537       "ACCEPT\r\n"
00538       "foo: bar\r\n"
00539       "foo: argh\r\n"
00540       "word word: word \r\n"
00541       "accept: \"fazzle, dazzle\"\r\n"
00542       "accept: 1, 2, 3, 4, 5, 6, 7, 8\r\n"
00543       "continuation: part1\r\n" " part2\r\n" "scooby: doo\r\n" "scooby : doo\r\n" "bar: foo\r\n" "\r\n"
00544   };
00545 
00546   int err;
00547   MIMEHdr hdr;
00548   MIMEParser parser;
00549   const char *start;
00550   const char *end;
00551 
00552   bri_box("test_mime");
00553 
00554   printf("   <<< MUST BE HAND-VERIFIED FOR FULL-BENEFIT>>>\n\n");
00555 
00556   start = mime;
00557   end = start + strlen(start);
00558 
00559   mime_parser_init(&parser);
00560 
00561   bool must_copy_strs = 0;
00562 
00563   hdr.create(NULL);
00564   err = hdr.parse(&parser, &start, end, must_copy_strs, false);
00565 
00566   if (err < 0)
00567     return (failures_to_status("test_mime", 1));
00568 
00569   hdr.field_delete("not_there", 9);
00570   hdr.field_delete("accept", 6);
00571   hdr.field_delete("scooby", 6);
00572   hdr.field_delete("scooby", 6);
00573   hdr.field_delete("bar", 3);
00574   hdr.field_delete("continuation", 12);
00575 
00576   int count = hdr.fields_count();
00577   printf("hdr.fields_count() = %d\n", count);
00578 
00579   int i_max_forwards = hdr.value_get_int("Max-Forwards", 12);
00580   int u_max_forwards = hdr.value_get_uint("Max-Forwards", 12);
00581   printf("i_max_forwards = %d   u_max_forwards = %d\n", i_max_forwards, u_max_forwards);
00582 
00583   hdr.set_age(9999);
00584 
00585   int length = hdr.length_get();
00586   printf("hdr.length_get() = %d\n", length);
00587 
00588   time_t t0, t1, t2;
00589 
00590   t0 = hdr.get_date();
00591   if (t0 == 0) {
00592     printf("FAILED: Initial date is zero but shouldn't be\n");
00593     return (failures_to_status("test_mime", 1));
00594   }
00595 
00596   t1 = time(NULL);
00597   hdr.set_date(t1);
00598   t2 = hdr.get_date();
00599   if (t1 != t2) {
00600     printf("FAILED: set_date(%" PRId64 ") ... get_date = %" PRId64 "\n\n", (int64_t)t1, (int64_t)t2);
00601     return (failures_to_status("test_mime", 1));
00602   }
00603 
00604   hdr.value_append("Cache-Control", 13, "no-cache", 8, 1);
00605 
00606   MIMEField *cc_field;
00607   StrList slist;
00608 
00609   cc_field = hdr.field_find("Cache-Control", 13);
00610   // TODO: Do we need to check the "count" returned?
00611   cc_field->value_get_comma_list(&slist); // FIX: correct usage?
00612 
00613   mime_parser_clear(&parser);
00614 
00615   hdr.print(NULL, 0, NULL, NULL);
00616   printf("\n");
00617 
00618   obj_describe((HdrHeapObjImpl *) (hdr.m_mime), true);
00619 
00620   hdr.fields_clear();
00621 
00622   hdr.destroy();
00623 
00624   return (failures_to_status("test_mime", 0));
00625 }
00626 
00627 /*-------------------------------------------------------------------------
00628   -------------------------------------------------------------------------*/
00629 
00630 int
00631 HdrTest::test_http_parser_eos_boundary_cases()
00632 {
00633   struct
00634   {
00635     const char *msg;
00636     int expected_result;
00637     int expected_bytes_consumed;
00638   } tests[] = {
00639     {
00640     "GET /index.html HTTP/1.0\r\n", PARSE_DONE, 26}, {
00641     "GET /index.html HTTP/1.0\r\n\r\n***BODY****", PARSE_DONE, 28}, {
00642     "GET /index.html HTTP/1.0\r\nUser-Agent: foobar\r\n\r\n***BODY****", PARSE_DONE, 48}, {
00643     "GET", PARSE_ERROR, 3}, {
00644     "GET /index.html", PARSE_ERROR, 15}, {
00645     "GET /index.html\r\n", PARSE_DONE, 17}, {
00646     "GET /index.html HTTP/1.0", PARSE_ERROR, 24}, {
00647     "GET /index.html HTTP/1.0\r", PARSE_ERROR, 25}, {
00648     "GET /index.html HTTP/1.0\n", PARSE_DONE, 25}, {
00649     "GET /index.html HTTP/1.0\n\n", PARSE_DONE, 26}, {
00650     "GET /index.html HTTP/1.0\r\n\r\n", PARSE_DONE, 28}, {
00651     "GET /index.html HTTP/1.0\r\nUser-Agent: foobar", PARSE_ERROR, 44}, {
00652     "GET /index.html HTTP/1.0\r\nUser-Agent: foobar\n", PARSE_DONE, 45}, {
00653     "GET /index.html HTTP/1.0\r\nUser-Agent: foobar\r\n", PARSE_DONE, 46}, {
00654     "GET /index.html HTTP/1.0\r\nUser-Agent: foobar\r\n\r\n", PARSE_DONE, 48}, {
00655     "GET /index.html HTTP/1.0\nUser-Agent: foobar\n", PARSE_DONE, 44}, {
00656     "GET /index.html HTTP/1.0\nUser-Agent: foobar\nBoo: foo\n", PARSE_DONE, 53}, {
00657     "GET /index.html HTTP/1.0\r\nUser-Agent: foobar\r\n", PARSE_DONE, 46}, {
00658     "GET /index.html HTTP/1.0\r\n", PARSE_DONE, 26}, {
00659     "", PARSE_ERROR, 0}, {
00660     NULL, 0, 0}
00661   };
00662 
00663   int i, ret, bytes_consumed;
00664   const char *orig_start;
00665   const char *start;
00666   const char *end;
00667   HTTPParser parser;
00668 
00669   int failures = 0;
00670 
00671   bri_box("test_http_parser_eos_boundary_cases");
00672 
00673   http_parser_init(&parser);
00674 
00675   for (i = 0; tests[i].msg != NULL; i++) {
00676     HTTPHdr req_hdr;
00677 
00678     start = tests[i].msg;
00679     end = start + strlen(start);        // 1 character past end of string
00680 
00681     req_hdr.create(HTTP_TYPE_REQUEST);
00682 
00683     http_parser_clear(&parser);
00684 
00685     orig_start = start;
00686     ret = req_hdr.parse_req(&parser, &start, end, true);
00687     bytes_consumed = (int) (start - orig_start);
00688 
00689     printf("======== test %d (length=%d, consumed=%d)\n", i, (int)strlen(tests[i].msg), bytes_consumed);
00690     printf("[%s]\n", tests[i].msg);
00691     printf("\n[");
00692     req_hdr.print(NULL, 0, NULL, NULL);
00693     printf("]\n\n");
00694 
00695     if ((ret != tests[i].expected_result) || (bytes_consumed != tests[i].expected_bytes_consumed)) {
00696       ++failures;
00697       printf("FAILED: test %d: retval <expected %d, got %d>, eaten <expected %d, got %d>\n\n",
00698              i, tests[i].expected_result, ret, tests[i].expected_bytes_consumed, bytes_consumed);
00699     }
00700 
00701     req_hdr.destroy();
00702   }
00703 
00704   return (failures_to_status("test_http_parser_eos_boundary_cases", failures));
00705 }
00706 
00707 /*-------------------------------------------------------------------------
00708   -------------------------------------------------------------------------*/
00709 
00710 int
00711 HdrTest::test_http_aux(const char *request, const char *response)
00712 {
00713   int err;
00714   HTTPHdr req_hdr, rsp_hdr;
00715   HTTPParser parser;
00716   const char *start;
00717   const char *end;
00718 
00719   int status = 1;
00720 
00721   printf("   <<< MUST BE HAND-VERIFIED FOR FULL BENEFIT >>>\n\n");
00722 
00723     /*** (1) parse the request string into req_hdr ***/
00724 
00725   start = request;
00726   end = start + strlen(start);  // 1 character past end of string
00727 
00728   http_parser_init(&parser);
00729 
00730   req_hdr.create(HTTP_TYPE_REQUEST);
00731   rsp_hdr.create(HTTP_TYPE_RESPONSE);
00732 
00733   printf("======== parsing\n\n");
00734   while (1) {
00735     err = req_hdr.parse_req(&parser, &start, end, true);
00736     if (err != PARSE_CONT)
00737       break;
00738   }
00739   if (err == PARSE_ERROR) {
00740     req_hdr.destroy();
00741     rsp_hdr.destroy();
00742     return (failures_to_status("test_http_aux", (status == 0)));
00743   }
00744 
00745     /*** useless copy to exercise copy function ***/
00746 
00747   HTTPHdr new_hdr;
00748   new_hdr.create(HTTP_TYPE_REQUEST);
00749   new_hdr.copy(&req_hdr);
00750   new_hdr.destroy();
00751 
00752     /*** (2) print out the request ***/
00753 
00754   printf("======== real request (length=%d)\n\n", (int)strlen(request));
00755   printf("%s\n", request);
00756 
00757   printf("\n[");
00758   req_hdr.print(NULL, 0, NULL, NULL);
00759   printf("]\n\n");
00760 
00761   obj_describe(req_hdr.m_http, true);
00762 
00763   // req_hdr.destroy ();
00764   // ink_release_assert(!"req_hdr.destroy() not defined");
00765 
00766     /*** (3) parse the response string into rsp_hdr ***/
00767 
00768   start = response;
00769   end = start + strlen(start);
00770 
00771   http_parser_clear(&parser);
00772   http_parser_init(&parser);
00773 
00774   while (1) {
00775     err = rsp_hdr.parse_resp(&parser, &start, end, true);
00776     if (err != PARSE_CONT)
00777       break;
00778   }
00779   if (err == PARSE_ERROR) {
00780     req_hdr.destroy();
00781     rsp_hdr.destroy();
00782     return (failures_to_status("test_http_aux", (status == 0)));
00783   }
00784 
00785   http_parser_clear(&parser);
00786 
00787     /*** (4) print out the response ***/
00788 
00789   printf("\n======== real response (length=%d)\n\n", (int)strlen(response));
00790   printf("%s\n", response);
00791 
00792   printf("\n[");
00793   rsp_hdr.print(NULL, 0, NULL, NULL);
00794   printf("]\n\n");
00795 
00796   obj_describe(rsp_hdr.m_http, true);
00797 
00798 #define NNN 1000
00799   {
00800     char buf[NNN];
00801     int bufindex, last_bufindex;
00802     int tmp;
00803     int i;
00804 
00805     bufindex = 0;
00806 
00807     do {
00808       last_bufindex = bufindex;
00809       tmp = bufindex;
00810       buf[0] = '#';             // make it obvious if hdr.print doesn't print anything
00811       err = rsp_hdr.print(buf, NNN, &bufindex, &tmp);
00812 
00813       // printf("test_header: tmp = %d  err = %d  bufindex = %d\n", tmp, err, bufindex);
00814       putchar('{');
00815       for (i = 0; i < bufindex - last_bufindex; i++) {
00816         if (!iscntrl(buf[i]))
00817           putchar(buf[i]);
00818         else
00819           printf("\\%o", buf[i]);
00820       }
00821       putchar('}');
00822     } while (!err);
00823   }
00824 
00825   // rsp_hdr.print (NULL, 0, NULL, NULL);
00826 
00827   req_hdr.destroy();
00828   rsp_hdr.destroy();
00829 
00830   return (failures_to_status("test_http_aux", (status == 0)));
00831 }
00832 
00833 /*-------------------------------------------------------------------------
00834   -------------------------------------------------------------------------*/
00835 
00836 int
00837 HdrTest::test_http_hdr_print_and_copy()
00838 {
00839   static struct
00840   {
00841     const char *req;
00842     const char *req_tgt;
00843     const char *rsp;
00844     const char *rsp_tgt;
00845   } tests[] = {
00846     {
00847     "GET http://foo.com/bar.txt HTTP/1.0\r\n"
00848         "Accept-Language: fjdfjdslkf dsjkfdj flkdsfjlk sjfdlk ajfdlksa\r\n"
00849         "\r\n",
00850         "GET http://foo.com/bar.txt HTTP/1.0\r\n"
00851         "Accept-Language: fjdfjdslkf dsjkfdj flkdsfjlk sjfdlk ajfdlksa\r\n"
00852         "\r\n", "HTTP/1.0 200 OK\r\n" "\r\n", "HTTP/1.0 200 OK\r\n" "\r\n"}, {
00853     "GET http://foo.com/bar.txt HTTP/1.0\r\n"
00854         "Accept-Language: fjdfjdslkf dsjkfdj flkdsfjlk sjfdlk ajfdlksa fjfj dslkfjdslk fjsdafkl dsajfkldsa jfkldsafj klsafjs lkafjdsalk fsdjakfl sdjaflkdsaj flksdjflsd ;ffd salfdjs lf;sdaf ;dsaf jdsal;fdjsaflkjsda \r\n"
00855         "\r\n",
00856         "GET http://foo.com/bar.txt HTTP/1.0\r\n"
00857         "Accept-Language: fjdfjdslkf dsjkfdj flkdsfjlk sjfdlk ajfdlksa fjfj dslkfjdslk fjsdafkl dsajfkldsa jfkldsafj klsafjs lkafjdsalk fsdjakfl sdjaflkdsaj flksdjflsd ;ffd salfdjs lf;sdaf ;dsaf jdsal;fdjsaflkjsda \r\n"
00858         "\r\n", "HTTP/1.0 200 OK\r\n" "\r\n", "HTTP/1.0 200 OK\r\n" "\r\n"}, {
00859     "GET http://foo.com/bar.txt HTTP/1.0\r\n"
00860         "Accept-Language: fjdfjdslkf dsjkfdj flkdsfjlk sjfdlk ajfdlksa fjfj dslkfjdslk fjsdafkl dsajfkldsa jfkldsafj klsafjs lkafjdsalk fsdjakfl sdjaflkdsaj flksdjflsd ;ffd salfdjs lf;sdaf ;dsaf jdsal;fdjsaflkjsda kfl; fsdajfl; sdjafl;dsajlsjfl;sdafjsdal;fjds al;fdjslaf ;slajdk;f\r\n"
00861         "\r\n",
00862         "GET http://foo.com/bar.txt HTTP/1.0\r\n"
00863         "Accept-Language: fjdfjdslkf dsjkfdj flkdsfjlk sjfdlk ajfdlksa fjfj dslkfjdslk fjsdafkl dsajfkldsa jfkldsafj klsafjs lkafjdsalk fsdjakfl sdjaflkdsaj flksdjflsd ;ffd salfdjs lf;sdaf ;dsaf jdsal;fdjsaflkjsda kfl; fsdajfl; sdjafl;dsajlsjfl;sdafjsdal;fjds al;fdjslaf ;slajdk;f\r\n"
00864         "\r\n", "HTTP/1.0 200 OK\r\n" "\r\n", "HTTP/1.0 200 OK\r\n" "\r\n"}, {
00865       "GET http://people.netscape.com/jwz/hacks-1.gif HTTP/1.0\r\n" "If-Modified-Since: Wednesday, 26-Feb-97 06:58:17 GMT; length=842\r\n" "Referer: chocolate fribble\r\n",    // missing final CRLF
00866         "GET http://people.netscape.com/jwz/hacks-1.gif HTTP/1.0\r\n" "If-Modified-Since: Wednesday, 26-Feb-97 06:58:17 GMT; length=842\r\n" "Referer: chocolate fribble\r\n" "\r\n", "HTTP/1.0 200 OK\r\n" "MIME-Version: 1.0\r\n" "Server: WebSTAR/2.1 ID/30013\r\n" "Content-Type: text/html\r\n" "Content-Length: 939\r\n" "Last-Modified: Thursday, 01-Jan-04 05:00:00 GMT\r\n",   // missing final CRLF
00867     "HTTP/1.0 200 OK\r\n"
00868         "MIME-Version: 1.0\r\n"
00869         "Server: WebSTAR/2.1 ID/30013\r\n"
00870         "Content-Type: text/html\r\n"
00871         "Content-Length: 939\r\n" "Last-Modified: Thursday, 01-Jan-04 05:00:00 GMT\r\n" "\r\n"}, {
00872       "GET http://people.netscape.com/jwz/hacks-1.gif HTTP/1.0\r\n" "If-Modified-Since: Wednesday, 26-Feb-97 06:58:17 GMT; length=842\r\n" "Referer: \r\n",     // missing final CRLF
00873     "GET http://people.netscape.com/jwz/hacks-1.gif HTTP/1.0\r\n"
00874         "If-Modified-Since: Wednesday, 26-Feb-97 06:58:17 GMT; length=842\r\n"
00875         "Referer: \r\n"
00876         "\r\n",
00877         "HTTP/1.0 200 OK\r\n"
00878         "MIME-Version: 1.0\r\n"
00879         "Server: WebSTAR/2.1 ID/30013\r\n"
00880         "Content-Type: text/html\r\n"
00881         "Content-Length: 939\r\n"
00882         "Last-Modified: Thursday, 01-Jan-04 05:00:00 GMT\r\n"
00883         "\r\n",
00884         "HTTP/1.0 200 OK\r\n"
00885         "MIME-Version: 1.0\r\n"
00886         "Server: WebSTAR/2.1 ID/30013\r\n"
00887         "Content-Type: text/html\r\n"
00888         "Content-Length: 939\r\n" "Last-Modified: Thursday, 01-Jan-04 05:00:00 GMT\r\n" "\r\n"}, {
00889     "GET http://www.news.com:80/ HTTP/1.0\r\n"
00890         "Proxy-Connection: Keep-Alive\r\n"
00891         "User-Agent: Mozilla/4.04 [en] (X11; I; Linux 2.0.33 i586)\r\n"
00892         "Pragma: no-cache\r\n"
00893         "Host: www.news.com\r\n"
00894         "Accept: image/gif, image/x-xbitmap, image/jpeg, image/pjpeg, image/png, */*\r\n"
00895         "Accept-Language: en\r\n"
00896         "Accept-Charset: iso-8859-1, *, utf-8\r\n"
00897         "Client-ip: D1012148\r\n"
00898         "Foo: abcdefghijklmnopqrtu\r\n"
00899         "\r\n",
00900         "GET http://www.news.com:80/ HTTP/1.0\r\n"
00901         "Proxy-Connection: Keep-Alive\r\n"
00902         "User-Agent: Mozilla/4.04 [en] (X11; I; Linux 2.0.33 i586)\r\n"
00903         "Pragma: no-cache\r\n"
00904         "Host: www.news.com\r\n"
00905         "Accept: image/gif, image/x-xbitmap, image/jpeg, image/pjpeg, image/png, */*\r\n"
00906         "Accept-Language: en\r\n"
00907         "Accept-Charset: iso-8859-1, *, utf-8\r\n"
00908         "Client-ip: D1012148\r\n"
00909         "Foo: abcdefghijklmnopqrtu\r\n"
00910         "\r\n",
00911         "HTTP/1.0 200 OK\r\n"
00912         "Content-Length: 16428\r\n"
00913         "Content-Type: text/html\r\n"
00914         "\r\n", "HTTP/1.0 200 OK\r\n" "Content-Length: 16428\r\n" "Content-Type: text/html\r\n" "\r\n"}, {
00915     "GET http://people.netscape.com/jwz/hacks-1.gif HTTP/1.0\r\n"
00916         "If-Modified-Since: Wednesday, 26-Feb-97 06:58:17 GMT; length=842\r\n"
00917         "Referer: http://people.netscape.com/jwz/index.html\r\n"
00918         "Proxy-Connection: Keep-Alive\r\n"
00919         "User-Agent:  Mozilla/3.01 (X11; I; Linux 2.0.28 i586)\r\n"
00920         "Pragma: no-cache\r\n"
00921         "Host: people.netscape.com\r\n"
00922         "Accept: image/gif, image/x-xbitmap, image/jpeg, image/pjpeg, */*\r\n"
00923         "\r\n",
00924         "GET http://people.netscape.com/jwz/hacks-1.gif HTTP/1.0\r\n"
00925         "If-Modified-Since: Wednesday, 26-Feb-97 06:58:17 GMT; length=842\r\n"
00926         "Referer: http://people.netscape.com/jwz/index.html\r\n"
00927         "Proxy-Connection: Keep-Alive\r\n"
00928         "User-Agent:  Mozilla/3.01 (X11; I; Linux 2.0.28 i586)\r\n"
00929         "Pragma: no-cache\r\n"
00930         "Host: people.netscape.com\r\n"
00931         "Accept: image/gif, image/x-xbitmap, image/jpeg, image/pjpeg, */*\r\n"
00932         "\r\n",
00933         "HTTP/1.0 200 OK\r\n"
00934         "Content-Length: 16428\r\n"
00935         "Content-Type: text/html\r\n"
00936         "\r\n", "HTTP/1.0 200 OK\r\n" "Content-Length: 16428\r\n" "Content-Type: text/html\r\n" "\r\n"}
00937   };
00938 
00939   int ntests = sizeof(tests) / sizeof(tests[0]);
00940   int i, failures;
00941 
00942   failures = 0;
00943 
00944   bri_box("test_http_hdr_print_and_copy");
00945 
00946   for (i = 0; i < ntests; i++) {
00947     int status =
00948       test_http_hdr_print_and_copy_aux(i + 1, tests[i].req, tests[i].req_tgt, tests[i].rsp, tests[i].rsp_tgt);
00949     if (status == 0)
00950       ++failures;
00951   }
00952 
00953   return (failures_to_status("test_http_hdr_print_and_copy", failures));
00954 }
00955 
00956 /*-------------------------------------------------------------------------
00957   -------------------------------------------------------------------------*/
00958 static const char *
00959 comp_http_hdr(HTTPHdr * h1, HTTPHdr * h2)
00960 {
00961 
00962   int h1_len, h2_len;
00963   int p_index, p_dumpoffset, rval;
00964   char *h1_pbuf, *h2_pbuf;
00965 
00966   h1_len = h1->length_get();
00967   h2_len = h2->length_get();
00968 
00969   if (h1_len != h2_len) {
00970     return "length mismatch";
00971   }
00972 
00973   h1_pbuf = (char *)ats_malloc(h1_len + 1);
00974   h2_pbuf = (char *)ats_malloc(h2_len + 1);
00975 
00976   p_index = p_dumpoffset = 0;
00977   rval = h1->print(h1_pbuf, h1_len, &p_index, &p_dumpoffset);
00978   if (rval != 1) {
00979     ats_free(h1_pbuf);
00980     ats_free(h2_pbuf);
00981     return "hdr print failed";
00982   }
00983 
00984   p_index = p_dumpoffset = 0;
00985   rval = h2->print(h2_pbuf, h2_len, &p_index, &p_dumpoffset);
00986   if (rval != 1) {
00987     ats_free(h1_pbuf);
00988     ats_free(h2_pbuf);
00989     return "hdr print failed";
00990   }
00991 
00992   rval = memcmp(h1_pbuf, h2_pbuf, h1_len);
00993   ats_free(h1_pbuf);
00994   ats_free(h2_pbuf);
00995 
00996   if (rval != 0) {
00997     return "compare failed";
00998   } else {
00999     return NULL;
01000   }
01001 }
01002 
01003 
01004 /*-------------------------------------------------------------------------
01005   -------------------------------------------------------------------------*/
01006 
01007 int
01008 HdrTest::test_http_hdr_copy_over_aux(int testnum, const char *request, const char *response)
01009 {
01010   int err;
01011   HTTPHdr req_hdr;
01012   HTTPHdr resp_hdr;
01013   HTTPHdr copy1;
01014   HTTPHdr copy2;
01015 
01016   HTTPParser parser;
01017   const char *start;
01018   const char *end;
01019   const char *comp_str = NULL;
01020 
01021     /*** (1) parse the request string into hdr ***/
01022 
01023   req_hdr.create(HTTP_TYPE_REQUEST);
01024 
01025   start = request;
01026   end = start + strlen(start);  // 1 character past end of string
01027 
01028   http_parser_init(&parser);
01029 
01030   while (1) {
01031     err = req_hdr.parse_req(&parser, &start, end, true);
01032     if (err != PARSE_CONT)
01033       break;
01034   }
01035 
01036   if (err == PARSE_ERROR) {
01037     printf("FAILED: (test #%d) parse error parsing request hdr\n", testnum);
01038     return (0);
01039   }
01040   http_parser_clear(&parser);
01041 
01042 
01043     /*** (2) parse the response string into hdr ***/
01044 
01045   resp_hdr.create(HTTP_TYPE_RESPONSE);
01046 
01047   start = response;
01048   end = start + strlen(start);  // 1 character past end of string
01049 
01050   http_parser_init(&parser);
01051 
01052   while (1) {
01053     err = resp_hdr.parse_resp(&parser, &start, end, true);
01054     if (err != PARSE_CONT)
01055       break;
01056   }
01057 
01058   if (err == PARSE_ERROR) {
01059     printf("FAILED: (test #%d) parse error parsing response hdr\n", testnum);
01060     return (0);
01061   }
01062 
01063     /*** (3) Basic copy testing ***/
01064   copy1.create(HTTP_TYPE_REQUEST);
01065   copy1.copy(&req_hdr);
01066   comp_str = comp_http_hdr(&req_hdr, &copy1);
01067   if (comp_str)
01068     goto done;
01069 
01070   copy2.create(HTTP_TYPE_RESPONSE);
01071   copy2.copy(&resp_hdr);
01072   comp_str = comp_http_hdr(&resp_hdr, &copy2);
01073   if (comp_str)
01074     goto done;
01075 
01076   // The APIs for copying headers uses memcpy() which can be unsafe for
01077   // overlapping memory areas. It's unclear to me why these tests were
01078   // created in the first place honestly, since nothing else does this.
01079 #if 0
01080     /*** (4) Copying over yourself ***/
01081   copy1.copy(&copy1);
01082   comp_str = comp_http_hdr(&req_hdr, &copy1);
01083   if (comp_str)
01084     goto done;
01085 
01086   copy2.copy(&copy2);
01087   comp_str = comp_http_hdr(&resp_hdr, &copy2);
01088   if (comp_str)
01089     goto done;
01090 #endif
01091 
01092     /*** (5) Gender bending copying ***/
01093   copy1.copy(&resp_hdr);
01094   comp_str = comp_http_hdr(&resp_hdr, &copy1);
01095   if (comp_str)
01096     goto done;
01097 
01098   copy2.copy(&req_hdr);
01099   comp_str = comp_http_hdr(&req_hdr, &copy2);
01100   if (comp_str)
01101     goto done;
01102 
01103 done:
01104   req_hdr.destroy();
01105   resp_hdr.destroy();
01106   copy1.destroy();
01107   copy2.destroy();
01108 
01109   if (comp_str) {
01110     printf("FAILED: (test #%d) copy & compare: %s\n", testnum, comp_str);
01111     printf("REQ:\n[%.*s]\n", (int)strlen(request), request);
01112     printf("RESP  :\n[%.*s]\n", (int)strlen(response), response);
01113     return (0);
01114   } else {
01115     return (1);
01116   }
01117 }
01118 
01119 
01120 /*-------------------------------------------------------------------------
01121   -------------------------------------------------------------------------*/
01122 
01123 int
01124 HdrTest::test_http_hdr_print_and_copy_aux(int testnum,
01125                                           const char *request, const char *request_tgt,
01126                                           const char *response, const char *response_tgt)
01127 {
01128   int err;
01129   HTTPHdr hdr;
01130   HTTPParser parser;
01131   const char *start;
01132   const char *end;
01133 
01134   char prt_buf[2048];
01135   int prt_bufsize = sizeof(prt_buf);
01136   int prt_bufindex, prt_dumpoffset, prt_ret;
01137 
01138   char cpy_buf[2048];
01139   int cpy_bufsize = sizeof(cpy_buf);
01140   int cpy_bufindex, cpy_dumpoffset, cpy_ret;
01141 
01142   char *marshal_buf = (char*)ats_malloc(2048);
01143   int marshal_bufsize = sizeof(cpy_buf);
01144 
01145     /*** (1) parse the request string into hdr ***/
01146 
01147   hdr.create(HTTP_TYPE_REQUEST);
01148 
01149   start = request;
01150   end = start + strlen(start);  // 1 character past end of string
01151 
01152   http_parser_init(&parser);
01153 
01154   while (1) {
01155     err = hdr.parse_req(&parser, &start, end, true);
01156     if (err != PARSE_CONT)
01157       break;
01158   }
01159 
01160   if (err == PARSE_ERROR) {
01161     printf("FAILED: (test #%d) parse error parsing request hdr\n", testnum);
01162     return (0);
01163   }
01164 
01165     /*** (2) copy the request header ***/
01166   HTTPHdr new_hdr, marshal_hdr;
01167   RefCountObj ref;
01168   ref.m_refcount = 100;
01169   int marshal_len = hdr.m_heap->marshal(marshal_buf, marshal_bufsize);
01170   marshal_hdr.create(HTTP_TYPE_REQUEST);
01171   marshal_hdr.unmarshal(marshal_buf, marshal_len, &ref);
01172   new_hdr.create(HTTP_TYPE_REQUEST);
01173   new_hdr.copy(&marshal_hdr);
01174   ats_free(marshal_buf);
01175 
01176     /*** (3) print the request header and copy to buffers ***/
01177 
01178   prt_bufindex = prt_dumpoffset = 0;
01179   prt_ret = hdr.print(prt_buf, prt_bufsize, &prt_bufindex, &prt_dumpoffset);
01180 
01181   cpy_bufindex = cpy_dumpoffset = 0;
01182   cpy_ret = new_hdr.print(cpy_buf, cpy_bufsize, &cpy_bufindex, &cpy_dumpoffset);
01183 
01184   if ((prt_ret != 1) || (cpy_ret != 1)) {
01185     printf("FAILED: (test #%d) couldn't print req hdr or copy --- prt_ret=%d, cpy_ret=%d\n", testnum, prt_ret, cpy_ret);
01186     return (0);
01187   }
01188 
01189   if (((size_t) prt_bufindex != strlen(request_tgt)) || ((size_t) cpy_bufindex != strlen(request_tgt))) {
01190     printf("FAILED: (test #%d) print req output size mismatch --- tgt=%d, prt_bufsize=%d, cpy_bufsize=%d\n",
01191            testnum, (int)strlen(request_tgt), prt_bufindex, cpy_bufindex);
01192 
01193     printf("ORIGINAL:\n[%.*s]\n", (int)strlen(request), request);
01194     printf("TARGET  :\n[%.*s]\n", (int)strlen(request_tgt), request_tgt);
01195     printf("PRT_BUFF:\n[%.*s]\n", prt_bufindex, prt_buf);
01196     printf("CPY_BUFF:\n[%.*s]\n", cpy_bufindex, cpy_buf);
01197     return (0);
01198   }
01199 
01200   if ((strncasecmp(request_tgt, prt_buf, strlen(request_tgt)) != 0) ||
01201       (strncasecmp(request_tgt, cpy_buf, strlen(request_tgt)) != 0)) {
01202     printf("FAILED: (test #%d) print req output mismatch\n", testnum);
01203     printf("ORIGINAL:\n[%.*s]\n", (int)strlen(request), request);
01204     printf("TARGET  :\n[%.*s]\n", (int)strlen(request_tgt), request_tgt);
01205     printf("PRT_BUFF:\n[%.*s]\n", prt_bufindex, prt_buf);
01206     printf("CPY_BUFF:\n[%.*s]\n", cpy_bufindex, cpy_buf);
01207     return (0);
01208   }
01209 
01210   hdr.destroy();
01211   new_hdr.destroy();
01212 
01213     /*** (4) parse the response string into hdr ***/
01214 
01215   hdr.create(HTTP_TYPE_RESPONSE);
01216 
01217   start = response;
01218   end = start + strlen(start);  // 1 character past end of string
01219 
01220   http_parser_init(&parser);
01221 
01222   while (1) {
01223     err = hdr.parse_resp(&parser, &start, end, true);
01224     if (err != PARSE_CONT)
01225       break;
01226   }
01227 
01228   if (err == PARSE_ERROR) {
01229     printf("FAILED: (test #%d) parse error parsing response hdr\n", testnum);
01230     return (0);
01231   }
01232 
01233     /*** (2) copy the response header ***/
01234 
01235   new_hdr.create(HTTP_TYPE_RESPONSE);
01236   new_hdr.copy(&hdr);
01237 
01238     /*** (3) print the response header and copy to buffers ***/
01239 
01240   prt_bufindex = prt_dumpoffset = 0;
01241   prt_ret = hdr.print(prt_buf, prt_bufsize, &prt_bufindex, &prt_dumpoffset);
01242 
01243   cpy_bufindex = cpy_dumpoffset = 0;
01244   cpy_ret = new_hdr.print(cpy_buf, cpy_bufsize, &cpy_bufindex, &cpy_dumpoffset);
01245 
01246   if ((prt_ret != 1) || (cpy_ret != 1)) {
01247     printf("FAILED: (test #%d) couldn't print rsp hdr or copy --- prt_ret=%d, cpy_ret=%d\n", testnum, prt_ret, cpy_ret);
01248     return (0);
01249   }
01250 
01251   if (((size_t) prt_bufindex != strlen(response_tgt)) || ((size_t) cpy_bufindex != strlen(response_tgt))) {
01252     printf("FAILED: (test #%d) print rsp output size mismatch --- tgt=%d, prt_bufsize=%d, cpy_bufsize=%d\n",
01253            testnum, (int)strlen(response_tgt), prt_bufindex, cpy_bufindex);
01254     printf("ORIGINAL:\n[%.*s]\n", (int)strlen(response), response);
01255     printf("TARGET  :\n[%.*s]\n", (int)strlen(response_tgt), response_tgt);
01256     printf("PRT_BUFF:\n[%.*s]\n", prt_bufindex, prt_buf);
01257     printf("CPY_BUFF:\n[%.*s]\n", cpy_bufindex, cpy_buf);
01258     return (0);
01259   }
01260 
01261   if ((strncasecmp(response_tgt, prt_buf, strlen(response_tgt)) != 0) ||
01262       (strncasecmp(response_tgt, cpy_buf, strlen(response_tgt)) != 0)) {
01263     printf("FAILED: (test #%d) print rsp output mismatch\n", testnum);
01264     printf("ORIGINAL:\n[%.*s]\n", (int)strlen(response), response);
01265     printf("TARGET  :\n[%.*s]\n", (int)strlen(response_tgt), response_tgt);
01266     printf("PRT_BUFF:\n[%.*s]\n", prt_bufindex, prt_buf);
01267     printf("CPY_BUFF:\n[%.*s]\n", cpy_bufindex, cpy_buf);
01268     return (0);
01269   }
01270 
01271   hdr.destroy();
01272   new_hdr.destroy();
01273 
01274   if (test_http_hdr_copy_over_aux(testnum, request, response) == 0) {
01275     return 0;
01276   }
01277 
01278   return (1);
01279 }
01280 
01281 /*-------------------------------------------------------------------------
01282   -------------------------------------------------------------------------*/
01283 
01284 int
01285 HdrTest::test_http()
01286 {
01287   int status = 1;
01288 
01289   static const char request0[] = {
01290     "GET http://www.news.com:80/ HTTP/1.0\r\n"
01291       "Proxy-Connection: Keep-Alive\r\n"
01292       "User-Agent: Mozilla/4.04 [en] (X11; I; Linux 2.0.33 i586)\r\n"
01293       "Pragma: no-cache\r\n"
01294       "Host: www.news.com\r\n"
01295       "Accept: image/gif, image/x-xbitmap, image/jpeg, image/pjpeg, image/png, */*\r\n"
01296       "Accept-Language: en\r\n"
01297       "Accept-Charset: iso-8859-1, *, utf-8\r\n"
01298       "Cookie: u_vid_0_0=00031ba3; s_cur_0_0=0101sisi091314775496e7d3Jx4+POyJakrMybmNOsq6XOn5bVn5Z6a4Ln5crU5M7Rxq2lm5aWpqupo20=; SC_Cnet001=Sampled; SC_Cnet002=Sampled\r\n"
01299       "Client-ip: D1012148\r\n" "Foo: abcdefghijklmnopqrtu\r\n" "\r\n"
01300   };
01301 
01302   static const char request09[] = {
01303     "GET /index.html\r\n" "\r\n"
01304   };
01305 
01306   static const char request1[] = {
01307     "GET http://people.netscape.com/jwz/hacks-1.gif HTTP/1.0\r\n"
01308       "If-Modified-Since: Wednesday, 26-Feb-97 06:58:17 GMT; length=842\r\n"
01309       "Referer: http://people.netscape.com/jwz/index.html\r\n"
01310       "Proxy-Connection: Keep-Alive\r\n"
01311       "User-Agent:  Mozilla/3.01 (X11; I; Linux 2.0.28 i586)\r\n"
01312       "Pragma: no-cache\r\n"
01313       "Host: people.netscape.com\r\n" "Accept: image/gif, image/x-xbitmap, image/jpeg, image/pjpeg, */*\r\n" "\r\n"
01314   };
01315 
01316   static const char request_no_colon[] = {
01317     "GET http://people.netscape.com/jwz/hacks-1.gif HTTP/1.0\r\n"
01318       "If-Modified-Since Wednesday, 26-Feb-97 06:58:17 GMT; length=842\r\n"
01319       "Referer http://people.netscape.com/jwz/index.html\r\n"
01320       "Proxy-Connection Keep-Alive\r\n"
01321       "User-Agent  Mozilla/3.01 (X11; I; Linux 2.0.28 i586)\r\n"
01322       "Pragma no-cache\r\n"
01323       "Host people.netscape.com\r\n" "Accept image/gif, image/x-xbitmap, image/jpeg, image/pjpeg, */*\r\n" "\r\n"
01324   };
01325 
01326   static const char request_no_val[] = {
01327     "GET http://people.netscape.com/jwz/hacks-1.gif HTTP/1.0\r\n"
01328       "If-Modified-Since:\r\n" "Referer:     " "Proxy-Connection:\r\n" "User-Agent:     \r\n" "Host:::\r\n" "\r\n"
01329   };
01330 
01331   static const char request_multi_fblock[] = {
01332     "GET http://people.netscape.com/jwz/hacks-1.gif HTTP/1.0\r\n"
01333       "If-Modified-Since: Wednesday, 26-Feb-97 06:58:17 GMT; length=842\r\n"
01334       "Referer: http://people.netscape.com/jwz/index.html\r\n"
01335       "Proxy-Connection: Keep-Alive\r\n"
01336       "User-Agent:  Mozilla/3.01 (X11; I; Linux 2.0.28 i586)\r\n"
01337       "Pragma: no-cache\r\n"
01338       "Host: people.netscape.com\r\n"
01339       "Accept: image/gif, image/x-xbitmap, image/jpeg, image/pjpeg, */*\r\n"
01340       "X-1: blah\r\n"
01341       "X-2: blah\r\n"
01342       "X-3: blah\r\n"
01343       "X-4: blah\r\n"
01344       "X-5: blah\r\n"
01345       "X-6: blah\r\n"
01346       "X-7: blah\r\n"
01347       "X-8: blah\r\n"
01348       "X-9: blah\r\n"
01349       "Pragma: no-cache\r\n"
01350       "X-X-1: blah\r\n"
01351       "X-X-2: blah\r\n"
01352       "X-X-3: blah\r\n"
01353       "X-X-4: blah\r\n" "X-X-5: blah\r\n" "X-X-6: blah\r\n" "X-X-7: blah\r\n" "X-X-8: blah\r\n" "X-X-9: blah\r\n" "\r\n"
01354   };
01355 
01356   static const char request_leading_space[] = {
01357     " GET http://www.news.com:80/ HTTP/1.0\r\n"
01358       "Proxy-Connection: Keep-Alive\r\n" "User-Agent: Mozilla/4.04 [en] (X11; I; Linux 2.0.33 i586)\r\n" "\r\n"
01359   };
01360 
01361   static const char request_padding[] = {
01362     "GET http://www.padding.com:80/ HTTP/1.0\r\n" "X-1: blah1\r\n"
01363       //       "X-2:  blah2\r\n"
01364       "X-3:   blah3\r\n"
01365       //       "X-4:    blah4\r\n"
01366       "X-5:     blah5\r\n"
01367       //       "X-6:      blah6\r\n"
01368       "X-7:       blah7\r\n"
01369       //       "X-8:        blah8\r\n"
01370     "X-9:         blah9\r\n" "\r\n"
01371   };
01372 
01373   static const char request_09p[] = {
01374     "GET http://www.news09.com/\r\n" "\r\n"
01375   };
01376 
01377   static const char request_09ht[] = {
01378     "GET http://www.news09.com/ HT\r\n" "\r\n"
01379   };
01380 
01381   static const char request_11[] = {
01382     "GET http://www.news.com/ HTTP/1.1\r\n" "Connection: close\r\n" "\r\n"
01383   };
01384 
01385   static const char request_unterminated[] = {
01386     "GET http://www.unterminated.com/ HTTP/1.1"
01387   };
01388 
01389   static const char request_blank[] = {
01390     "\r\n"
01391   };
01392 
01393   static const char request_blank2[] = {
01394     "\r\n" "\r\n"
01395   };
01396 
01397   static const char request_blank3[] = {
01398     "     " "\r\n"
01399   };
01400 
01401   ////////////////////////////////////////////////////
01402 
01403   static const char response0[] = {
01404     "HTTP/1.0 200 OK\r\n"
01405       "MIME-Version: 1.0\r\n"
01406       "Server: WebSTAR/2.1 ID/30013\r\n"
01407       "Content-Type: text/html\r\n"
01408       "Content-Length: 939\r\n" "Last-Modified: Thursday, 01-Jan-04 05:00:00 GMT\r\n" "\r\n"
01409   };
01410 
01411   static const char response1[] = {
01412     "HTTP/1.0 200 OK\r\n"
01413       "Server: Netscape-Communications/1.12\r\n"
01414       "Date: Tuesday, 08-Dec-98 20:32:17 GMT\r\n" "Content-Type: text/html\r\n" "\r\n"
01415   };
01416 
01417   static const char response_no_colon[] = {
01418     "HTTP/1.0 200 OK\r\n"
01419       "Server Netscape-Communications/1.12\r\n"
01420       "Date: Tuesday, 08-Dec-98 20:32:17 GMT\r\n" "Content-Type: text/html\r\n" "\r\n"
01421   };
01422 
01423   static const char response_unterminated[] = {
01424     "HTTP/1.0 200 OK"
01425   };
01426 
01427   static const char response09[] = {
01428     ""
01429   };
01430 
01431   static const char response_blank[] = {
01432     "\r\n"
01433   };
01434 
01435   static const char response_blank2[] = {
01436     "\r\n" "\r\n"
01437   };
01438 
01439   static const char response_blank3[] = {
01440     "     " "\r\n"
01441   };
01442 
01443   status = status & test_http_aux(request0, response0);
01444   status = status & test_http_aux(request09, response09);
01445   status = status & test_http_aux(request1, response1);
01446   status = status & test_http_aux(request_no_colon, response_no_colon);
01447   status = status & test_http_aux(request_no_val, response_no_colon);
01448   status = status & test_http_aux(request_leading_space, response0);
01449   status = status & test_http_aux(request_multi_fblock, response0);
01450   status = status & test_http_aux(request_padding, response0);
01451   status = status & test_http_aux(request_09p, response0);
01452   status = status & test_http_aux(request_09ht, response0);
01453   status = status & test_http_aux(request_11, response0);
01454   status = status & test_http_aux(request_unterminated, response_unterminated);
01455   status = status & test_http_aux(request_blank, response_blank);
01456   status = status & test_http_aux(request_blank2, response_blank2);
01457   status = status & test_http_aux(request_blank3, response_blank3);
01458 
01459   return (failures_to_status("test_http", (status == 0)));
01460 }
01461 
01462 /*-------------------------------------------------------------------------
01463   -------------------------------------------------------------------------*/
01464 
01465 int
01466 HdrTest::test_http_mutation()
01467 {
01468   int status = 1;
01469 
01470   bri_box("test_http_mutation");
01471 
01472   printf("   <<< MUST BE HAND-VERIFIED FOR FULL BENEFIT>>>\n\n");
01473 
01474   HTTPHdr resp_hdr;
01475   int err, i;
01476   HTTPParser parser;
01477   const char base_resp[] = "HTTP/1.0 200 OK\r\n\r\n";
01478   const char *start, *end;
01479 
01480     /*** (1) parse the response string into req_hdr ***/
01481 
01482   start = base_resp;
01483   end = start + strlen(start);
01484 
01485   http_parser_init(&parser);
01486 
01487   resp_hdr.create(HTTP_TYPE_RESPONSE);
01488 
01489   while (1) {
01490     err = resp_hdr.parse_resp(&parser, &start, end, true);
01491     if (err != PARSE_CONT)
01492       break;
01493   }
01494 
01495   printf("\n======== before mutation ==========\n\n");
01496   printf("\n[");
01497   resp_hdr.print(NULL, 0, NULL, NULL);
01498   printf("]\n\n");
01499 
01500     /*** (2) add in a bunch of header fields ****/
01501   char field_name[1024];
01502   char field_value[1024];
01503   for (i = 1; i <= 100; i++) {
01504     snprintf(field_name, sizeof(field_name), "Test%d", i);
01505     snprintf(field_value, sizeof(field_value), "%d %d %d %d %d", i, i, i, i, i);
01506     resp_hdr.value_set(field_name, (int) strlen(field_name), field_value, (int) strlen(field_value));
01507   }
01508 
01509     /**** (3) delete all the even numbered fields *****/
01510   for (i = 2; i <= 100; i += 2) {
01511     snprintf(field_name, sizeof(field_name), "Test%d", i);
01512     resp_hdr.field_delete(field_name, (int) strlen(field_name));
01513   }
01514 
01515     /***** (4) add in secondary fields for all multiples of 3 ***/
01516   for (i = 3; i <= 100; i += 3) {
01517     snprintf(field_name, sizeof(field_name), "Test%d", i);
01518     MIMEField *f = resp_hdr.field_create(field_name, (int) strlen(field_name));
01519     resp_hdr.field_attach(f);
01520     snprintf(field_value, sizeof(field_value), "d %d %d %d %d %d", i, i, i, i, i);
01521     f->value_set(resp_hdr.m_heap, resp_hdr.m_mime, field_value, (int) strlen(field_value));
01522 
01523   }
01524 
01525     /***** (5) append all fields with multiples of 5 ***/
01526   for (i = 5; i <= 100; i += 5) {
01527     snprintf(field_name, sizeof(field_name), "Test%d", i);
01528     snprintf(field_value, sizeof(field_value), "a %d", i);
01529 
01530     resp_hdr.value_append(field_name, (int) strlen(field_name), field_value, (int) strlen(field_value), true);
01531   }
01532 
01533     /**** (6) delete all multiples of nine *****/
01534   for (i = 9; i <= 100; i += 9) {
01535     snprintf(field_name, sizeof(field_name), "Test%d", i);
01536     resp_hdr.field_delete(field_name, (int) strlen(field_name));
01537   }
01538 
01539 
01540   printf("\n======== mutated response ==========\n\n");
01541   printf("\n[");
01542   resp_hdr.print(NULL, 0, NULL, NULL);
01543   printf("]\n\n");
01544 
01545   resp_hdr.destroy();
01546 
01547   return (failures_to_status("test_http_mutation", (status == 0)));
01548 }
01549 
01550 /*-------------------------------------------------------------------------
01551   -------------------------------------------------------------------------*/
01552 
01553 int
01554 HdrTest::test_arena_aux(Arena * arena, int len)
01555 {
01556   char *str = arena->str_alloc(len);
01557   int verify_len = (int) arena->str_length(str);
01558 
01559   if (len != verify_len) {
01560     printf("FAILED: requested %d, got %d bytes\n", len, verify_len);
01561     return (1);                 // 1 error (different return convention)
01562   } else {
01563     return (0);                 // no errors (different return convention)
01564   }
01565 }
01566 
01567 /*-------------------------------------------------------------------------
01568   -------------------------------------------------------------------------*/
01569 
01570 int
01571 HdrTest::test_arena()
01572 {
01573   bri_box("test_arena");
01574 
01575   Arena *arena;
01576   int failures = 0;
01577 
01578   arena = new Arena;
01579 
01580   failures += test_arena_aux(arena, 1);
01581   failures += test_arena_aux(arena, 127);
01582   failures += test_arena_aux(arena, 128);
01583   failures += test_arena_aux(arena, 129);
01584   failures += test_arena_aux(arena, 255);
01585   failures += test_arena_aux(arena, 256);
01586   failures += test_arena_aux(arena, 16384);
01587   failures += test_arena_aux(arena, 16385);
01588   failures += test_arena_aux(arena, 16511);
01589   failures += test_arena_aux(arena, 16512);
01590   failures += test_arena_aux(arena, 2097152);
01591   failures += test_arena_aux(arena, 2097153);
01592   failures += test_arena_aux(arena, 2097279);
01593   failures += test_arena_aux(arena, 2097280);
01594 
01595   delete arena;
01596 
01597   return (failures_to_status("test_arena", failures));
01598 }
01599 
01600 /*-------------------------------------------------------------------------
01601   -------------------------------------------------------------------------*/
01602 
01603 int
01604 HdrTest::test_regex()
01605 {
01606   DFA dfa;
01607   int status = 1;
01608   
01609   const char *test_harness[] = {
01610     "foo",
01611     "(.*\\.apache\\.org)",
01612     "(.*\\.example\\.com)"
01613   };
01614   
01615   bri_box("test_regex");
01616   
01617   dfa.compile(test_harness,SIZEOF(test_harness));
01618   status = status & (dfa.match("trafficserver.apache.org") == 1);
01619   status = status & (dfa.match("www.example.com") == 2);
01620   status = status & (dfa.match("aaaaaafooooooooinktomi....com.org") == -1);
01621   status = status & (dfa.match("foo") == 0);
01622 
01623   return (failures_to_status("test_regex", (status != 1)));
01624 }
01625 
01626 /*-------------------------------------------------------------------------
01627   -------------------------------------------------------------------------*/
01628 
01629 int
01630 HdrTest::test_accept_language_match()
01631 {
01632   bri_box("test_accept_language_match");
01633 
01634   struct
01635   {
01636     const char *content_language;
01637     const char *accept_language;
01638     float Q;
01639     int L;
01640     int I;
01641   } test_cases[] = {
01642     {
01643     "en", "*", 1.0, 1, 1}, {
01644     "en", "fr", 0.0, 0, 0}, {
01645     "en", "de, fr, en;q=0.7", 0.7, 2, 3}, {
01646     "en-cockney", "de, fr, en;q=0.7", 0.7, 2, 3}, {
01647     "en-cockney", "de, fr, en-foobar;q=0.8, en;q=0.7", 0.7, 2, 4}, {
01648     "en-cockney", "de, fr, en-cockney;q=0.8, en;q=0.7", 0.8, 10, 3}, {
01649     "en-cockney", "de, fr, en;q=0.8, en;q=0.7", 0.8, 2, 3}, {
01650     "en-cockney", "de, fr, en;q=0.7, en;q=0.8", 0.8, 2, 4}, {
01651     "en-cockney", "de, fr, en;q=0.8, en;q=0.8", 0.8, 2, 3}, {
01652     "en-cockney", "de, fr, en-cockney;q=0.7, en;q=0.8", 0.7, 10, 3}, {
01653     "en-cockney", "de, fr, en;q=0.8, en-cockney;q=0.7", 0.7, 10, 4}, {
01654     "en-cockney", "de, fr, en-cockney;q=0.8, en;q=0.8", 0.8, 10, 3}, {
01655     "en-cockney", "de, fr, en-cockney;q=0.8, en;q=0.7", 0.8, 10, 3}, {
01656     "en-cockney", "de, fr, en-american", 0.0, 0, 0}, {
01657     "en-cockney", "de, fr, en;q=0.8, en;q=0.8, *", 0.8, 2, 3}, {
01658     "en-cockney", "de, fr, en;q=0.8, en;q=0.8, *;q=0.9", 0.8, 2, 3}, {
01659     "en-foobar", "de, fr, en;q=0.8, en;q=0.8, *;q=0.9", 0.8, 2, 3}, {
01660     "oo-foobar", "de, fr, en;q=0.8, en;q=0.8, *;q=0.9", 0.9, 1, 5}, {
01661     "oo-foobar", "de, fr, en;q=0.8, en;q=0.8, *;q=0.9, *", 1.0, 1, 6}, {
01662     "oo-foobar", "de, fr, en;q=0.8, en;q=0.8, *, *;q=0.9", 1.0, 1, 5}, {
01663     "fr-belgian", "de, fr;hi-there;q=0.9, fr;q=0.8, en", 0.9, 2, 2}, {
01664     "fr-belgian", "de, fr;q=0.8, fr;hi-there;q=0.9, en", 0.9, 2, 3}, {
01665     NULL, NULL, 0.0}
01666   };
01667 
01668   int i, I, L;
01669   float Q;
01670   int failures = 0;
01671 
01672   for (i = 0; test_cases[i].accept_language; i++) {
01673     StrList acpt_lang_list(false);
01674     HttpCompat::parse_comma_list(&acpt_lang_list, test_cases[i].accept_language,
01675                                  (int) strlen(test_cases[i].accept_language));
01676 
01677     Q = HttpCompat::match_accept_language(test_cases[i].content_language,
01678                                           (int) strlen(test_cases[i].content_language), &acpt_lang_list, &L, &I);
01679 
01680     if ((Q != test_cases[i].Q) || (L != test_cases[i].L) || (I != test_cases[i].I)) {
01681       printf
01682         ("FAILED: (#%d) got { Q = %.3f; L = %d; I = %d; }, expected { Q = %.3f; L = %d; I = %d; }, from matching\n  '%s' against '%s'\n",
01683          i, Q, L, I, test_cases[i].Q, test_cases[i].L, test_cases[i].I, test_cases[i].content_language,
01684          test_cases[i].accept_language);
01685       ++failures;
01686     }
01687   }
01688 
01689   return (failures_to_status("test_accept_language_match", failures));
01690 }
01691 
01692 
01693 /*-------------------------------------------------------------------------
01694   -------------------------------------------------------------------------*/
01695 
01696 int
01697 HdrTest::test_accept_charset_match()
01698 {
01699   bri_box("test_accept_charset_match");
01700 
01701   struct
01702   {
01703     const char *content_charset;
01704     const char *accept_charset;
01705     float Q;
01706     int I;
01707   } test_cases[] = {
01708     {
01709     "iso-8859-1", "*", 1.0, 1}, {
01710     "iso-8859-1", "iso-8859-2", 0.0, 0}, {
01711     "iso-8859-1", "iso-8859", 0.0, 0}, {
01712     "iso-8859-1", "iso-8859-12", 0.0, 0}, {
01713     "iso-8859-1", "koi-8-r", 0.0, 0}, {
01714     "euc-jp", "shift_jis, iso-2022-jp, euc-jp;q=0.7", 0.7, 3}, {
01715     "euc-jp", "shift_jis, iso-2022-jp, euc-jp;q=0.7", 0.7, 3}, {
01716     "euc-jp", "shift_jis, iso-2022-jp, euc-jp;q=0.8, euc-jp;q=0.7", 0.8, 3}, {
01717     "euc-jp", "shift_jis, iso-2022-jp, euc-jp;q=0.7, euc-jp;q=0.8", 0.8, 4}, {
01718     "euc-jp", "euc-jp;q=0.9, shift_jis, iso-2022-jp, euc-jp;q=0.7, euc-jp;q=0.8", 0.9, 1}, {
01719     "EUC-JP", "euc-jp;q=0.9, shift_jis, iso-2022-jp, euc-jp, euc-jp;q=0.8", 1.0, 4}, {
01720     "euc-jp", "euc-jp;q=0.9, shift_jis, iso-2022-jp, EUC-JP, euc-jp;q=0.8", 1.0, 4}, {
01721     "euc-jp", "shift_jis, iso-2022-jp, euc-jp-foobar", 0.0, 0}, {
01722     "euc-jp", "shift_jis, iso-2022-jp, euc-jp-foobar, *", 1.0, 4}, {
01723     "euc-jp", "shift_jis, iso-2022-jp, euc-jp-foobar, *;q=0.543", 0.543, 4}, {
01724     "euc-jp", "shift_jis, iso-2022-jp, euc-jp-foobar, *;q=0.0", 0.0, 4}, {
01725     "euc-jp", "shift_jis, iso-2022-jp, *;q=0.0, euc-jp-foobar, *;q=0.0", 0.0, 3}, {
01726     "euc-jp", "shift_jis, iso-2022-jp, *;q=0.0, euc-jp-foobar, *;q=0.5", 0.5, 5}, {
01727     "euc-jp", "shift_jis, iso-2022-jp, *;q=0.5, euc-jp-foobar, *;q=0.0", 0.5, 3}, {
01728     "euc-jp", "shift_jis, iso-2022-jp, *;q=0.5, euc-jp-foobar, *, *;q=0.0", 1.0, 5}, {
01729     "euc-jp", "shift_jis, euc-jp;hi-there;q=0.5, iso-2022-jp", 0.5, 2}, {
01730     "euc-jp", "shift_jis, euc-jp;hi-there;q= 0.5, iso-2022-jp", 0.5, 2}, {
01731     "euc-jp", "shift_jis, euc-jp;hi-there;q = 0.5, iso-2022-jp", 0.5, 2}, {
01732     "euc-jp", "shift_jis, euc-jp;hi-there ; q = 0.5, iso-2022-jp", 0.5, 2}, {
01733     "euc-jp", "shift_jis, euc-jp;hi-there ;; q = 0.5, iso-2022-jp", 0.5, 2}, {
01734     "euc-jp", "shift_jis, euc-jp;hi-there ;; Q = 0.5, iso-2022-jp", 0.5, 2}, {
01735     NULL, NULL, 0.0, 0}
01736   };
01737 
01738   int i, I;
01739   float Q;
01740   int failures = 0;
01741 
01742   for (i = 0; test_cases[i].accept_charset; i++) {
01743     StrList acpt_lang_list(false);
01744     HttpCompat::parse_comma_list(&acpt_lang_list, test_cases[i].accept_charset,
01745                                  (int) strlen(test_cases[i].accept_charset));
01746 
01747     Q = HttpCompat::match_accept_charset(test_cases[i].content_charset,
01748                                          (int) strlen(test_cases[i].content_charset), &acpt_lang_list, &I);
01749 
01750     if ((Q != test_cases[i].Q) || (I != test_cases[i].I)) {
01751       printf
01752         ("FAILED: (#%d) got { Q = %.3f; I = %d; }, expected { Q = %.3f; I = %d; }, from matching\n  '%s' against '%s'\n",
01753          i, Q, I, test_cases[i].Q, test_cases[i].I, test_cases[i].content_charset, test_cases[i].accept_charset);
01754       ++failures;
01755     }
01756   }
01757 
01758   return (failures_to_status("test_accept_charset_match", failures));
01759 }
01760 
01761 /*-------------------------------------------------------------------------
01762   -------------------------------------------------------------------------*/
01763 
01764 int
01765 HdrTest::test_comma_vals()
01766 {
01767   static struct
01768   {
01769     const char *value;
01770     int value_count;
01771     struct
01772     {
01773       int offset;
01774       int len;
01775     } pieces[4];
01776   } tests[] = {
01777     {
01778       ",", 2, { {
01779       0, 0}, {
01780       1, 0}, {
01781       -1, 0}, {
01782     -1, 0}}}, {
01783       "", 1, { {
01784       0, 0}, {
01785       -1, 0}, {
01786       -1, 0}, {
01787     -1, 0}}}, {
01788       " ", 1, { {
01789       0, 0}, {
01790       -1, 0}, {
01791       -1, 0}, {
01792     -1, 0}}}, {
01793       ", ", 2, { {
01794       0, 0}, {
01795       1, 0}, {
01796       -1, 0}, {
01797     -1, 0}}}, {
01798       ",,", 3, { {
01799       0, 0}, {
01800       1, 0}, {
01801       2, 0}, {
01802     -1, 0}}}, {
01803       " ,", 2, { {
01804       0, 0}, {
01805       2, 0}, {
01806       -1, 0}, {
01807     -1, 0}}}, {
01808       " , ", 2, { {
01809       0, 0}, {
01810       2, 0}, {
01811       -1, 0}, {
01812     -1, 0}}}, {
01813       "a, ", 2, { {
01814       0, 1}, {
01815       2, 0}, {
01816       -1, 0}, {
01817     -1, 0}}}, {
01818       " a, ", 2, { {
01819       1, 1}, {
01820       3, 0}, {
01821       -1, 0}, {
01822     -1, 0}}}, {
01823       " ,a", 2, { {
01824       0, 0}, {
01825       2, 1}, {
01826       -1, 0}, {
01827     -1, 0}}}, {
01828       " , a", 2, { {
01829       0, 0}, {
01830       3, 1}, {
01831       -1, 0}, {
01832     -1, 0}}}, {
01833       "a,a", 2, { {
01834       0, 1}, {
01835       2, 1}, {
01836       -1, 0}, {
01837     -1, 0}}}, {
01838       "foo", 1, { {
01839       0, 3}, {
01840       -1, 0}, {
01841       -1, 0}, {
01842     -1, 0}}}, {
01843       "foo,", 2, { {
01844       0, 3}, {
01845       4, 0}, {
01846       -1, 0}, {
01847     -1, 0}}}, {
01848       "foo, ", 2, { {
01849       0, 3}, {
01850       4, 0}, {
01851       -1, 0}, {
01852     -1, 0}}}, {
01853       "foo, bar", 2, { {
01854       0, 3}, {
01855       5, 3}, {
01856       -1, 0}, {
01857     -1, 0}}}, {
01858       "foo, bar,", 3, { {
01859       0, 3}, {
01860       5, 3}, {
01861       9, 0}, {
01862     -1, 0}}}, {
01863       "foo, bar, ", 3, { {
01864       0, 3}, {
01865       5, 3}, {
01866       9, 0}, {
01867     -1, 0}}}, {
01868       ",foo,bar,", 4, { {
01869       0, 0}, {
01870       1, 3}, {
01871       5, 3}, {
01872     9, 0}}}
01873   };
01874 
01875   bri_box("test_comma_vals");
01876 
01877   HTTPHdr hdr;
01878   char field_name[32];
01879   int i, j, len, failures, ntests, ncommavals;
01880 
01881   failures = 0;
01882   ntests = sizeof(tests) / sizeof(tests[0]);
01883 
01884   hdr.create(HTTP_TYPE_REQUEST);
01885 
01886   for (i = 0; i < ntests; i++) {
01887     snprintf(field_name, sizeof(field_name), "Test%d", i);
01888 
01889     MIMEField *f = hdr.field_create(field_name, (int) strlen(field_name));
01890     ink_release_assert(f->m_ptr_value == NULL);
01891 
01892     hdr.field_attach(f);
01893     ink_release_assert(f->m_ptr_value == NULL);
01894 
01895     hdr.field_value_set(f, tests[i].value, strlen(tests[i].value));
01896     ink_release_assert(f->m_ptr_value != tests[i].value);       // should be copied
01897     ink_release_assert(f->m_len_value == strlen(tests[i].value));
01898     ink_release_assert(memcmp(f->m_ptr_value, tests[i].value, f->m_len_value) == 0);
01899 
01900     ncommavals = mime_field_value_get_comma_val_count(f);
01901     if (ncommavals != tests[i].value_count) {
01902       ++failures;
01903       printf("FAILED: test #%d (field value '%s') expected val count %d, got %d\n",
01904              i + 1, tests[i].value, tests[i].value_count, ncommavals);
01905     }
01906 
01907     for (j = 0; j < tests[i].value_count; j++) {
01908       const char *val = mime_field_value_get_comma_val(f, &len, j);
01909       int offset = ((val == NULL) ? -1 : (val - f->m_ptr_value));
01910 
01911       if ((offset != tests[i].pieces[j].offset) || (len != tests[i].pieces[j].len)) {
01912         ++failures;
01913         printf
01914           ("FAILED: test #%d (field value '%s', commaval idx %d) expected [offset %d, len %d], got [offset %d, len %d]\n",
01915            i + 1, tests[i].value, j, tests[i].pieces[j].offset, tests[i].pieces[j].len, offset, len);
01916       }
01917     }
01918   }
01919 
01920   hdr.destroy();
01921   return (failures_to_status("test_comma_vals", failures));
01922 }
01923 
01924 /*-------------------------------------------------------------------------
01925   -------------------------------------------------------------------------*/
01926 
01927 int
01928 HdrTest::test_set_comma_vals()
01929 {
01930   static struct
01931   {
01932     const char *old_raw;
01933     int idx;
01934     const char *slice;
01935     const char *new_raw;
01936   } tests[] = {
01937     {
01938     "a,b,c", 0, "fred", "fred, b, c"}, {
01939     "a,b,c", 1, "fred", "a, fred, c"}, {
01940     "a,b,c", 2, "fred", "a, b, fred"}, {
01941     "a,b,c", 3, "fred", "a,b,c"}, {
01942     "", 0, "", ""}, {
01943     "", 0, "foo", "foo"}, {
01944     "", 1, "foo", ""}, {
01945     " ", 0, "", ""}, {
01946     " ", 0, "foo", "foo"}, {
01947     " ", 1, "foo", " "}, {
01948     ",", 0, "foo", "foo, "}, {
01949     ",", 1, "foo", ", foo"}, {
01950     ",,", 0, "foo", "foo, , "}, {
01951     ",,", 1, "foo", ", foo, "}, {
01952     ",,", 2, "foo", ", , foo"}, {
01953     "foo", 0, "abc", "abc"}, {
01954     "foo", 1, "abc", "foo"}, {
01955     "foo", 0, "abc,", "abc,"}, {
01956     "foo", 0, ",abc", ",abc"}, {
01957     ",,", 1, ",,,", ", ,,,, "}, {
01958     " a , b , c", 0, "fred", "fred, b, c"}, {
01959     " a , b , c", 1, "fred", "a, fred, c"}, {
01960     " a , b , c", 2, "fred", "a, b, fred"}, {
01961     " a , b , c", 3, "fred", " a , b , c"}, {
01962     "    a   ,   b ", 0, "fred", "fred, b"}, {
01963     "    a   ,   b ", 1, "fred", "a, fred"}, {
01964     "    a   , b ", 1, "fred", "a, fred"}, {
01965     "    a   ,b ", 1, "fred", "a, fred"}, {
01966     "a, , , , e, , g,", 0, "fred", "fred, , , , e, , g, "}, {
01967     "a, , , , e, , g,", 1, "fred", "a, fred, , , e, , g, "}, {
01968     "a, , , , e, , g,", 2, "fred", "a, , fred, , e, , g, "}, {
01969     "a, , , , e, , g,", 5, "fred", "a, , , , e, fred, g, "}, {
01970     "a, , , , e, , g,", 7, "fred", "a, , , , e, , g, fred"}, {
01971     "a, , , , e, , g,", 8, "fred", "a, , , , e, , g,"}, {
01972     "a, \"boo,foo\", c", 0, "wawa", "wawa, \"boo,foo\", c"}, {
01973     "a, \"boo,foo\", c", 1, "wawa", "a, wawa, c"}, {
01974   "a, \"boo,foo\", c", 2, "wawa", "a, \"boo,foo\", wawa"},};
01975 
01976   bri_box("test_set_comma_vals");
01977 
01978   HTTPHdr hdr;
01979   char field_name[32];
01980   int i, failures, ntests;
01981 
01982   failures = 0;
01983   ntests = sizeof(tests) / sizeof(tests[0]);
01984 
01985   hdr.create(HTTP_TYPE_REQUEST);
01986 
01987   for (i = 0; i < ntests; i++) {
01988     snprintf(field_name, sizeof(field_name), "Test%d", i);
01989 
01990     MIMEField *f = hdr.field_create(field_name, (int) strlen(field_name));
01991     hdr.field_value_set(f, tests[i].old_raw, strlen(tests[i].old_raw));
01992     mime_field_value_set_comma_val(hdr.m_heap, hdr.m_mime, f, tests[i].idx, tests[i].slice, strlen(tests[i].slice));
01993     ink_release_assert(f->m_ptr_value != NULL);
01994 
01995     if ((f->m_len_value != strlen(tests[i].new_raw)) || (memcmp(f->m_ptr_value, tests[i].new_raw, f->m_len_value) != 0)) {
01996       ++failures;
01997       printf("FAILED:  test #%d (setting idx %d of '%s' to '%s') expected '%s' len %d, got '%.*s' len %d\n",
01998              i + 1, tests[i].idx, tests[i].old_raw, tests[i].slice,
01999              tests[i].new_raw, (int)strlen(tests[i].new_raw), f->m_len_value, f->m_ptr_value, f->m_len_value);
02000     }
02001   }
02002 
02003   hdr.destroy();
02004   return (failures_to_status("test_set_comma_vals", failures));
02005 }
02006 
02007 /*-------------------------------------------------------------------------
02008   -------------------------------------------------------------------------*/
02009 
02010 int
02011 HdrTest::test_delete_comma_vals()
02012 {
02013   bri_box("test_delete_comma_vals");
02014   rprintf(rtest, "  HdrTest test_delete_comma_vals: TEST NOT IMPLEMENTED\n");
02015   return (1);
02016 }
02017 
02018 /*-------------------------------------------------------------------------
02019   -------------------------------------------------------------------------*/
02020 
02021 int
02022 HdrTest::test_extend_comma_vals()
02023 {
02024   bri_box("test_extend_comma_vals");
02025   rprintf(rtest, "  HdrTest test_extend_comma_vals: TEST NOT IMPLEMENTED\n");
02026   return (1);
02027 }
02028 
02029 /*-------------------------------------------------------------------------
02030   -------------------------------------------------------------------------*/
02031 
02032 int
02033 HdrTest::test_insert_comma_vals()
02034 {
02035   bri_box("test_insert_comma_vals");
02036   rprintf(rtest, "  HdrTest test_insert_comma_vals: TEST NOT IMPLEMENTED\n");
02037   return (1);
02038 }
02039 
02040 /*-------------------------------------------------------------------------
02041   -------------------------------------------------------------------------*/
02042 
02043 int
02044 HdrTest::test_parse_comma_list()
02045 {
02046   static struct
02047   {
02048     const char *value;
02049     int count;
02050     struct
02051     {
02052       int offset;
02053       int len;
02054     } pieces[3];
02055   } tests[] = {
02056     {
02057       "", 1, { {
02058       0, 0}, {
02059       -1, 0}, {
02060     -1, 0}}}, {
02061       ",", 2, { {
02062       0, 0}, {
02063       1, 0}, {
02064     -1, 0}}}, {
02065       " ,", 2, { {
02066       0, 0}, {
02067       2, 0}, {
02068     -1, 0}}}, {
02069       ", ", 2, { {
02070       0, 0}, {
02071       1, 0}, {
02072     -1, 0}}}, {
02073       " , ", 2, { {
02074       0, 0}, {
02075       2, 0}, {
02076     -1, 0}}}, {
02077       "abc,", 2, { {
02078       0, 3}, {
02079       4, 0}, {
02080     -1, 0}}}, {
02081       "abc, ", 2, { {
02082       0, 3}, {
02083       4, 0}, {
02084     -1, 0}}}, {
02085       "", 1, { {
02086       0, 0}, {
02087       -1, 0}, {
02088     -1, 0}}}, {
02089       " ", 1, { {
02090       0, 0}, {
02091       -1, 0}, {
02092     -1, 0}}}, {
02093       "  ", 1, { {
02094       0, 0}, {
02095       -1, 0}, {
02096     -1, 0}}}, {
02097       "a", 1, { {
02098       0, 1}, {
02099       -1, 0}, {
02100     -1, 0}}}, {
02101       " a", 1, { {
02102       1, 1}, {
02103       -1, 0}, {
02104     -1, 0}}}, {
02105       "  a  ", 1, { {
02106       2, 1}, {
02107       -1, 0}, {
02108     -1, 0}}}, {
02109       "abc,defg", 2, { {
02110       0, 3}, {
02111       4, 4}, {
02112     -1, 0}}}, {
02113       " abc,defg", 2, { {
02114       1, 3}, {
02115       5, 4}, {
02116     -1, 0}}}, {
02117       " abc, defg", 2, { {
02118       1, 3}, {
02119       6, 4}, {
02120     -1, 0}}}, {
02121       " abc , defg", 2, { {
02122       1, 3}, {
02123       7, 4}, {
02124     -1, 0}}}, {
02125       " abc , defg ", 2, { {
02126       1, 3}, {
02127       7, 4}, {
02128     -1, 0}}}, {
02129       " abc , defg, ", 3, { {
02130       1, 3}, {
02131       7, 4}, {
02132     12, 0}}}, {
02133       " abc , defg ,", 3, { {
02134       1, 3}, {
02135       7, 4}, {
02136     13, 0}}}, {
02137       ", abc , defg ", 3, { {
02138       0, 0}, {
02139       2, 3}, {
02140     8, 4}}}, {
02141       " ,abc , defg ", 3, { {
02142       0, 0}, {
02143       2, 3}, {
02144     8, 4}}}, {
02145       "a,b", 2, { {
02146       0, 1}, {
02147       2, 1}, {
02148     -1, 0}}}, {
02149       "a,,b", 3, { {
02150       0, 1}, {
02151       2, 0}, {
02152     3, 1}}}, {
02153       "a, ,b", 3, { {
02154       0, 1}, {
02155       2, 0}, {
02156     4, 1}}}, {
02157       "a ,,b", 3, { {
02158       0, 1}, {
02159       3, 0}, {
02160     4, 1}}}, {
02161       ",", 2, { {
02162       0, 0}, {
02163       1, 0}, {
02164     -1, 0}}}, {
02165       " ,", 2, { {
02166       0, 0}, {
02167       2, 0}, {
02168     -1, 0}}}, {
02169       ", ", 2, { {
02170       0, 0}, {
02171       1, 0}, {
02172     -1, 0}}}, {
02173       " , ", 2, { {
02174       0, 0}, {
02175       2, 0}, {
02176     -1, 0}}}, {
02177       "a,b,", 3, { {
02178       0, 1}, {
02179       2, 1}, {
02180     4, 0}}}, {
02181       "a,b, ", 3, { {
02182       0, 1}, {
02183       2, 1}, {
02184     4, 0}}}, {
02185       "a,b,  ", 3, { {
02186       0, 1}, {
02187       2, 1}, {
02188     4, 0}}}, {
02189       "a,b,  c", 3, { {
02190       0, 1}, {
02191       2, 1}, {
02192     6, 1}}}, {
02193       "a,b,  c ", 3, { {
02194       0, 1}, {
02195       2, 1}, {
02196     6, 1}}}, {
02197       "a,\"b,c\",d", 3, { {
02198       0, 1}, {
02199       3, 3}, {
02200     8, 1}}}
02201   };
02202 
02203   bri_box("test_parse_comma_list");
02204 
02205   int i, j, failures, ntests, offset;
02206 
02207   failures = (offset = 0);
02208   ntests = sizeof(tests) / sizeof(tests[0]);
02209 
02210   for (i = 0; i < ntests; i++) {
02211     StrList list(false);
02212     HttpCompat::parse_comma_list(&list, tests[i].value);
02213     if (list.count != tests[i].count) {
02214       ++failures;
02215       printf("FAILED: test #%d (string '%s') expected list count %d, got %d\n",
02216              i + 1, tests[i].value, tests[i].count, list.count);
02217     }
02218 
02219     for (j = 0; j < tests[i].count; j++) {
02220       Str *cell = list.get_idx(j);
02221       if (cell != NULL)
02222         offset = cell->str - tests[i].value;
02223 
02224       if (tests[i].pieces[j].offset == -1)      // should not have a piece
02225       {
02226         if (cell != NULL) {
02227           ++failures;
02228           printf("FAILED: test #%d (string '%s', idx %d) expected NULL piece, got [offset %d len %d]\n",
02229                  i + 1, tests[i].value, j, offset, (int)cell->len);
02230         }
02231       } else                    // should have a piece
02232       {
02233         if (cell == NULL) {
02234           ++failures;
02235           printf("FAILED: test #%d (string '%s', idx %d) expected [offset %d len %d], got NULL piece\n",
02236                  i + 1, tests[i].value, j, tests[i].pieces[j].offset, tests[i].pieces[j].len);
02237         } else if ((offset != tests[i].pieces[j].offset) || (cell->len != (size_t) tests[i].pieces[j].len)) {
02238           ++failures;
02239           printf("FAILED: test #%d (string '%s', idx %d) expected [offset %d len %d], got [offset %d len %d]\n",
02240                  i + 1, tests[i].value, j, tests[i].pieces[j].offset, tests[i].pieces[j].len, offset, (int)cell->len);
02241         }
02242       }
02243     }
02244   }
02245 
02246   return (failures_to_status("test_parse_comma_list", failures));
02247 }
02248 
02249 /*-------------------------------------------------------------------------
02250   -------------------------------------------------------------------------*/
02251 
02252 void
02253 HdrTest::bri_box(const char *s)
02254 {
02255   int i, len;
02256 
02257   len = (int) strlen(s);
02258   printf("\n+-");
02259   for (i = 0; i < len; i++)
02260     putchar('-');
02261   printf("-+\n");
02262   printf("| %s |\n", s);
02263   printf("+-");
02264   for (i = 0; i < len; i++)
02265     putchar('-');
02266   printf("-+\n\n");
02267 }
02268 
02269 /*-------------------------------------------------------------------------
02270   -------------------------------------------------------------------------*/
02271 
02272 int
02273 HdrTest::failures_to_status(const char *testname, int nfail)
02274 {
02275   rprintf(rtest, "  HdrTest %s: %s\n", testname, ((nfail > 0) ? "FAILED" : "PASSED"));
02276   return ((nfail > 0) ? 0 : 1);
02277 }
02278 

Generated by  doxygen 1.7.1