00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024 #include "libts.h"
00025 #include "HttpCompat.h"
00026 #include "HdrUtils.h"
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039
00040
00041
00042
00043
00044 void
00045 HttpCompat::parse_tok_list(StrList * list, int trim_quotes, const char *string, char sep)
00046 {
00047 if (string == NULL)
00048 return;
00049 HttpCompat::parse_tok_list(list, trim_quotes, string, (int) strlen(string), sep);
00050 }
00051
00052 void
00053 HttpCompat::parse_tok_list(StrList * list, int trim_quotes, const char *string, int len, char sep)
00054 {
00055 int in_quote;
00056 const char quot = '\"';
00057 const char *s, *e, *l, *s_before_skipping_ws;
00058 int index, byte_length, hit_sep;
00059
00060 if ((string == NULL) || (list == NULL) || (sep == NUL))
00061 return;
00062
00063 s = string;
00064 l = s + len - 1;
00065 index = 0;
00066
00067 hit_sep = 0;
00068 s_before_skipping_ws = s;
00069
00070 while (s <= l) {
00071
00072
00073
00074
00075
00076
00077 while ((s <= l) && ParseRules::is_ws(*s))
00078 ++s;
00079
00080
00081
00082
00083
00084
00085 if ((s <= l) && (*s == sep)) {
00086 list->append_string(s_before_skipping_ws, 0);
00087 ++index;
00088 s_before_skipping_ws = s + 1;
00089 s = s_before_skipping_ws;
00090 hit_sep = 1;
00091 continue;
00092 }
00093
00094
00095
00096
00097
00098
00099
00100 if (s > l)
00101 break;
00102
00103
00104
00105
00106
00107
00108
00109
00110 #define is_unquoted_separator(c) ((c == sep) && !in_quote)
00111
00112 if (*s == quot) {
00113 in_quote = 1;
00114 e = s + 1;
00115 if (trim_quotes)
00116 ++s;
00117 } else {
00118 in_quote = 0;
00119 e = s;
00120 }
00121
00122 while ((e <= l) && !is_unquoted_separator(*e)) {
00123 if (*e == quot) {
00124 in_quote = !in_quote;
00125 }
00126 e++;
00127 }
00128
00129
00130
00131
00132
00133
00134
00135 hit_sep = (e <= l);
00136
00137 s_before_skipping_ws = e + 1;
00138 while ((e > s) && ParseRules::is_ws(*(e - 1)))
00139 --e;
00140 if ((e > s) && (*(e - 1) == quot) && trim_quotes)
00141 --e;
00142
00143
00144
00145
00146
00147
00148
00149 byte_length = (int) (e - s);
00150 ink_assert(byte_length >= 0);
00151
00152
00153
00154
00155
00156 list->append_string(s, byte_length);
00157 s = s_before_skipping_ws;
00158 ++index;
00159 }
00160
00161
00162
00163
00164
00165
00166
00167
00168
00169 if (hit_sep || (index == 0)) {
00170 ink_assert(s == l + 1);
00171 list->append_string(s_before_skipping_ws, 0);
00172 ++index;
00173 }
00174 }
00175
00176
00177
00178
00179
00180
00181
00182
00183
00184
00185
00186
00187
00188
00189
00190
00191
00192
00193
00194
00195 bool
00196 HttpCompat::lookup_param_in_strlist(StrList * param_list, const char *param_name, char *param_val, int param_val_length)
00197 {
00198 int cnt;
00199 const char *s, *t;
00200 Str *param;
00201 bool is_match;
00202
00203 for (param = param_list->head; param != NULL; param = param->next) {
00204
00205
00206
00207
00208 s = param->str;
00209 t = param_name;
00210 while (*s && *t && (ParseRules::ink_tolower(*s) == ParseRules::ink_tolower(*t))) {
00211 ++s;
00212 ++t;
00213 }
00214
00215
00216
00217
00218
00219
00220 is_match = ((!*t) && ((!*s) || ParseRules::is_ws(*s) || (*s == '=')));
00221
00222
00223
00224
00225
00226 if (is_match) {
00227 param_val[0] = '\0';
00228
00229 while (*s && ParseRules::is_ws(*s))
00230 s++;
00231 if (*s == '=') {
00232 ++s;
00233 while (*s && ParseRules::is_ws(*s))
00234 s++;
00235
00236 for (cnt = 0; *s && (cnt < param_val_length - 1); s++, cnt++)
00237 param_val[cnt] = *s;
00238 if (cnt < param_val_length)
00239 param_val[cnt++] = '\0';
00240 }
00241 return (true);
00242 }
00243 }
00244
00245 return (false);
00246 }
00247
00248
00249
00250
00251
00252
00253
00254
00255
00256
00257
00258
00259
00260
00261
00262
00263
00264
00265 bool
00266 HttpCompat::lookup_param_in_semicolon_string(const char *semicolon_string, int semicolon_string_len,
00267 const char *param_name, char *param_val, int param_val_length)
00268 {
00269 StrList l;
00270 bool result;
00271
00272 parse_semicolon_list(&l, semicolon_string, semicolon_string_len);
00273 result = lookup_param_in_strlist(&l, param_name, param_val, param_val_length);
00274 return (result);
00275 }
00276
00277
00278
00279
00280
00281
00282
00283
00284
00285
00286
00287
00288
00289
00290
00291
00292 void
00293 HttpCompat::parse_mime_type(const char *mime_string, char *type, char *subtype, int type_len, int subtype_len)
00294 {
00295 const char *s, *e;
00296 char *d;
00297
00298 *type = *subtype = '\0';
00299
00300
00301
00302
00303
00304 for (s = mime_string; *s && ParseRules::is_ws(*s); s++);
00305
00306
00307
00308
00309
00310 d = type;
00311 e = type + type_len;
00312 while (*s && (d < e - 1) && (!ParseRules::is_ws(*s)) && (*s != ';') && (*s != ',') && (*s != '/')) {
00313 *d++ = *s++;
00314 }
00315 *d++ = '\0';
00316
00317
00318
00319
00320
00321 while (*s && (*s != ';') && (*s != ',') && (*s != '/'))
00322 ++s;
00323 if (*s == '/')
00324 ++s;
00325 while (*s && ParseRules::is_ws(*s))
00326 ++s;
00327
00328
00329
00330
00331
00332 d = subtype;
00333 e = subtype + subtype_len;
00334 while (*s && (d < e - 1) && (!ParseRules::is_ws(*s)) && (*s != ';') && (*s != ',') && (*s != '/')) {
00335 *d++ = *s++;
00336 }
00337 *d++ = '\0';
00338 }
00339
00340 void
00341 HttpCompat::parse_mime_type_with_len(const char *mime_string, int mime_string_len,
00342 char *type, char *subtype, int type_len, int subtype_len)
00343 {
00344 const char *s, *s_toofar, *e;
00345 char *d;
00346
00347 *type = *subtype = '\0';
00348 s_toofar = mime_string + mime_string_len;
00349
00350
00351
00352
00353
00354 for (s = mime_string; (s < s_toofar) && ParseRules::is_ws(*s); s++);
00355
00356
00357
00358
00359
00360 d = type;
00361 e = type + type_len;
00362 while ((s < s_toofar) && (d < e - 1) && (!ParseRules::is_ws(*s)) && (*s != ';') && (*s != ',') && (*s != '/')) {
00363 *d++ = *s++;
00364 }
00365 *d++ = '\0';
00366
00367
00368
00369
00370
00371 while ((s < s_toofar) && (*s != ';') && (*s != ',') && (*s != '/'))
00372 ++s;
00373 if ((s < s_toofar) && (*s == '/'))
00374 ++s;
00375 while ((s < s_toofar) && ParseRules::is_ws(*s))
00376 ++s;
00377
00378
00379
00380
00381
00382 d = subtype;
00383 e = subtype + subtype_len;
00384 while ((s < s_toofar) && (d < e - 1) && (!ParseRules::is_ws(*s)) && (*s != ';') && (*s != ',') && (*s != '/')) {
00385 *d++ = *s++;
00386 }
00387 *d++ = '\0';
00388 }
00389
00390
00391
00392
00393
00394
00395
00396
00397
00398
00399
00400
00401
00402
00403
00404
00405
00406
00407
00408
00409
00410
00411
00412
00413
00414 bool
00415 HttpCompat::do_header_values_rfc2068_14_43_match(MIMEField * hdr1, MIMEField * hdr2)
00416 {
00417
00418 if (!hdr1 && !hdr2)
00419 return true;
00420
00421
00422 if (!hdr1 || !hdr2)
00423 return false;
00424
00425
00426
00427 HdrCsvIter iter1, iter2;
00428 if (iter1.count_values(hdr1) != iter2.count_values(hdr2))
00429 return false;
00430
00431 int hdr1_val_len, hdr2_val_len;
00432 const char *hdr1_val = iter1.get_first(hdr1, &hdr1_val_len);
00433 const char *hdr2_val = iter2.get_first(hdr2, &hdr2_val_len);
00434
00435 while (hdr1_val || hdr2_val) {
00436 if (hdr1_val_len != hdr2_val_len || ParseRules::strncasecmp_eow(hdr1_val, hdr2_val, hdr1_val_len) == false)
00437 return false;
00438
00439 hdr1_val = iter1.get_next(&hdr1_val_len);
00440 hdr2_val = iter2.get_next(&hdr2_val_len);
00441 }
00442
00443 return true;
00444 }
00445
00446
00447
00448
00449
00450
00451
00452
00453
00454
00455 float
00456 HttpCompat::find_Q_param_in_strlist(StrList * strlist)
00457 {
00458 float f, this_q;
00459 char q_string[8];
00460
00461 this_q = 1.0;
00462 if (HttpCompat::lookup_param_in_strlist(strlist, (char *) "q", q_string, sizeof(q_string))) {
00463
00464 if (sscanf(q_string, "%f", &f) == 1)
00465 this_q = (f<0 ? 0 : (f> 1 ? 1 : f));
00466 }
00467
00468 return (this_q);
00469 }
00470
00471
00472
00473
00474
00475
00476
00477
00478
00479
00480
00481
00482
00483
00484
00485
00486
00487
00488
00489 static inline bool
00490 does_language_range_match(const char *pattern, int pattern_len, const char *tag, int tag_len)
00491 {
00492 bool match;
00493
00494 while (pattern_len && tag_len && (ParseRules::ink_tolower(*pattern) == ParseRules::ink_tolower(*tag))) {
00495 ++pattern;
00496 ++tag;
00497 --pattern_len;
00498 --tag_len;
00499 }
00500
00501
00502 if ((((pattern_len == 0) && (tag_len == 0)) || ((pattern_len == 0) && (*tag == '-'))))
00503 match = true;
00504 else
00505 match = false;
00506
00507 return (match);
00508 }
00509
00510 float
00511 HttpCompat::match_accept_language(const char *lang_str, int lang_len,
00512 StrList * acpt_lang_list,
00513 int *matching_length, int *matching_index, bool ignore_wildcards)
00514 {
00515 float Q, Q_wild;
00516 Str *a_value;
00517
00518 Q = -1;
00519 Q_wild = -1;
00520 int match_count = 0;
00521 int wild_match_count = 0;
00522 int longest_match_len = 0;
00523
00524 int index = 0;
00525 int Q_index = 0;
00526 int Q_wild_index = 0;
00527
00528 *matching_index = 0;
00529 *matching_length = 0;
00530
00531
00532
00533
00534 if (acpt_lang_list->count == 0)
00535 return (0.0);
00536
00537
00538
00539
00540 for (a_value = acpt_lang_list->head; a_value; a_value = a_value->next) {
00541 ++index;
00542
00543 if (a_value->len == 0)
00544 continue;
00545
00546
00547
00548
00549 StrList a_param_list(false);
00550 HttpCompat::parse_semicolon_list(&a_param_list, a_value->str, (int) a_value->len);
00551 if (!a_param_list.head)
00552 continue;
00553
00554
00555
00556
00557
00558
00559
00560
00561 const char *atag_str = a_param_list.head->str;
00562 int atag_len = (int) a_param_list.head->len;
00563
00564 float tq = HttpCompat::find_Q_param_in_strlist(&a_param_list);
00565
00566 if ((atag_len == 1) && (atag_str[0] == '*'))
00567 {
00568 ++wild_match_count;
00569 if (tq > Q_wild) {
00570 Q_wild = tq;
00571 Q_wild_index = index;
00572 }
00573 } else if (does_language_range_match(atag_str, atag_len, lang_str, lang_len)) {
00574 ++match_count;
00575 if (atag_len > longest_match_len) {
00576 longest_match_len = atag_len;
00577 Q = tq;
00578 Q_index = index;
00579 } else if (atag_len == longest_match_len)
00580 {
00581 if (tq > Q) {
00582 Q = tq;
00583 Q_index = index;
00584 }
00585 }
00586 }
00587 }
00588
00589 if ((ignore_wildcards == false) && wild_match_count && !match_count) {
00590 *matching_index = Q_wild_index;
00591 *matching_length = 1;
00592 return (Q_wild);
00593 } else if (match_count > 0)
00594 {
00595 *matching_index = Q_index;
00596 *matching_length = longest_match_len;
00597 return (Q);
00598 } else
00599 {
00600 *matching_index = 0;
00601 *matching_length = 0;
00602 return (0.0);
00603 }
00604 }
00605
00606
00607
00608
00609
00610
00611
00612
00613
00614
00615
00616
00617
00618
00619
00620
00621
00622
00623
00624
00625
00626 float
00627 HttpCompat::match_accept_charset(const char *charset_str, int charset_len,
00628 StrList * acpt_charset_list, int *matching_index, bool ignore_wildcards)
00629 {
00630 float Q, Q_wild;
00631 Str *a_value;
00632
00633 Q = -1;
00634 Q_wild = -1;
00635 int match_count = 0;
00636 int wild_match_count = 0;
00637
00638 int index = 0;
00639 int Q_index = 0;
00640 int Q_wild_index = 0;
00641
00642 *matching_index = 0;
00643
00644
00645
00646
00647 if (acpt_charset_list->count == 0)
00648 return (0.0);
00649
00650
00651
00652
00653 for (a_value = acpt_charset_list->head; a_value; a_value = a_value->next) {
00654 ++index;
00655 if (a_value->len == 0)
00656 continue;
00657
00658
00659
00660
00661 StrList a_param_list(false);
00662 HttpCompat::parse_semicolon_list(&a_param_list, a_value->str, (int) a_value->len);
00663 if (!a_param_list.head)
00664 continue;
00665
00666
00667
00668
00669 const char *atag_str = a_param_list.head->str;
00670 int atag_len = (int) a_param_list.head->len;
00671 float tq = HttpCompat::find_Q_param_in_strlist(&a_param_list);
00672
00673 if ((atag_len == 1) && (atag_str[0] == '*'))
00674 {
00675 ++wild_match_count;
00676 if (tq > Q_wild) {
00677 Q_wild = tq;
00678 Q_wild_index = index;
00679 }
00680 } else if ((atag_len == charset_len) && (strncasecmp(atag_str, charset_str, charset_len) == 0)) {
00681 ++match_count;
00682 if (tq > Q) {
00683 Q = tq;
00684 Q_index = index;
00685 }
00686 }
00687 }
00688
00689 if ((ignore_wildcards == false) && wild_match_count && !match_count) {
00690 *matching_index = Q_wild_index;
00691 return (Q_wild);
00692 } else if (match_count > 0)
00693 {
00694 *matching_index = Q_index;
00695 return (Q);
00696 } else
00697 {
00698 *matching_index = 0;
00699 return (0.0);
00700 }
00701 }
00702
00703 const char *
00704 HttpCompat::determine_set_by_language(RawHashTable * table_of_sets,
00705 StrList * acpt_language_list, StrList * acpt_charset_list,
00706 float *Q_best_ptr, int *La_best_ptr, int *Lc_best_ptr, int *I_best_ptr)
00707 {
00708 float Q, Ql, Qc, Q_best;
00709 int I, Idummy, I_best;
00710 int La, Lc, La_best, Lc_best;
00711 int is_the_default_set;
00712 const char *set_best;
00713
00714 RawHashTable_Key k1;
00715 RawHashTable_Value v1;
00716 RawHashTable_Binding *b1;
00717 RawHashTable_IteratorState i1;
00718 RawHashTable *table_of_pages;
00719 HttpBodySetRawData *body_set;
00720
00721 set_best = "default";
00722 Q_best = 0.00001;
00723 La_best = 0;
00724 Lc_best = INT_MAX;
00725 I_best = INT_MAX;
00726
00727 Debug("body_factory_determine_set", " INITIAL: [ set_best='%s', Q=%g, La=%d, Lc=%d, I=%d ]",
00728 set_best, Q_best, La_best, Lc_best, I_best);
00729
00730
00731
00732
00733
00734 if ((acpt_language_list->count == 0) && (acpt_charset_list->count == 0)) {
00735 Q_best = 1;
00736 Debug("body_factory_determine_set", " no constraints => returning '%s'", set_best);
00737 goto done;
00738 }
00739
00740 if (table_of_sets != NULL) {
00741
00742
00743
00744
00745 for (b1 = table_of_sets->firstBinding(&i1); b1 != NULL; b1 = table_of_sets->nextBinding(&i1)) {
00746 k1 = table_of_sets->getKeyFromBinding(b1);
00747 v1 = table_of_sets->getValueFromBinding(b1);
00748 const char *set_name = (const char *) k1;
00749
00750 body_set = (HttpBodySetRawData *) v1;
00751 table_of_pages = body_set->table_of_pages;
00752
00753 if ((set_name == NULL) || (table_of_pages == NULL))
00754 continue;
00755
00756
00757
00758
00759
00760
00761
00762
00763
00764
00765
00766
00767
00768
00769
00770 is_the_default_set = (strcmp(set_name, "default") == 0);
00771
00772 Debug("body_factory_determine_set", " --- SET: %-8s (Content-Language '%s', Content-Charset '%s')",
00773 set_name, body_set->content_language, body_set->content_charset);
00774
00775
00776
00777 if (acpt_language_list->count == 0) {
00778 Ql = (is_the_default_set ? 1.0001 : 1.000);
00779 La = 0;
00780 Lc = INT_MAX;
00781 I = 1;
00782 Debug("body_factory_determine_set", " SET: [%-8s] A-L not present => [ Ql=%g, La=%d, Lc=%d, I=%d ]",
00783 set_name, Ql, La, Lc, I);
00784 } else {
00785 Lc = strlen(body_set->content_language);
00786 Ql = HttpCompat::match_accept_language(body_set->content_language, Lc, acpt_language_list, &La, &I, true);
00787 Debug("body_factory_determine_set", " SET: [%-8s] A-L match value => [ Ql=%g, La=%d, Lc=%d, I=%d ]",
00788 set_name, Ql, La, Lc, I);
00789 }
00790
00791
00792
00793
00794
00795
00796
00797
00798
00799
00800
00801
00802
00803
00804
00805
00806
00807 if (acpt_charset_list->count == 0) {
00808 Qc = (is_the_default_set ? 1.0001 : 1.000);
00809 Idummy = 1;
00810 Debug("body_factory_determine_set", " SET: [%-8s] A-C not present => [ Qc=%g ]", set_name, Qc);
00811 } else {
00812 Qc = HttpCompat::match_accept_charset(body_set->content_charset, strlen(body_set->content_charset),
00813 acpt_charset_list, &Idummy, true);
00814 Debug("body_factory_determine_set", " SET: [%-8s] A-C match value => [ Qc=%g ]", set_name, Qc);
00815 }
00816
00817
00818
00819
00820
00821
00822
00823
00824
00825
00826 Q = min(Ql, Qc);
00827
00828
00829
00830
00831
00832
00833
00834
00835 if (is_the_default_set) {
00836 Q = Q + -0.00005;
00837 if (Q < 0.00001)
00838 Q = 0.00001;
00839 }
00840
00841 Debug("body_factory_determine_set", " NEW: [ set='%s', Q=%g, La=%d, Lc=%d, I=%d ]", set_name, Q, La, Lc, I);
00842 Debug("body_factory_determine_set", " OLD: [ set='%s', Q=%g, La=%d, Lc=%d, I=%d ]",
00843 set_best, Q_best, La_best, Lc_best, I_best);
00844
00845 if (((Q > Q_best)) ||
00846 ((Q == Q_best) && (La > La_best)) ||
00847 ((Q == Q_best) && (La == La_best) && (Lc < Lc_best)) ||
00848 ((Q == Q_best) && (La == La_best) && (Lc == Lc_best) && (I < I_best))) {
00849 Q_best = Q;
00850 La_best = La;
00851 Lc_best = Lc;
00852 I_best = I;
00853 set_best = set_name;
00854
00855 Debug("body_factory_determine_set", " WINNER: [ set_best='%s', Q=%g, La=%d, Lc=%d, I=%d ]",
00856 set_best, Q_best, La_best, Lc_best, I_best);
00857 } else {
00858 Debug("body_factory_determine_set", " LOSER: [ set_best='%s', Q=%g, La=%d, Lc=%d, I=%d ]",
00859 set_best, Q_best, La_best, Lc_best, I_best);
00860 }
00861 }
00862 }
00863
00864 done:
00865
00866 *Q_best_ptr = Q_best;
00867 *La_best_ptr = La_best;
00868 *Lc_best_ptr = Lc_best;
00869 *I_best_ptr = I_best;
00870 return (set_best);
00871 }