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 }