10Sigor@sysoev.ru 20Sigor@sysoev.ru /* 30Sigor@sysoev.ru * Copyright (C) Igor Sysoev 40Sigor@sysoev.ru * Copyright (C) NGINX, Inc. 50Sigor@sysoev.ru */ 60Sigor@sysoev.ru 70Sigor@sysoev.ru #include <nxt_main.h> 80Sigor@sysoev.ru 90Sigor@sysoev.ru 100Sigor@sysoev.ru nxt_str_t * 1165Sigor@sysoev.ru nxt_str_alloc(nxt_mp_t *mp, size_t length) 120Sigor@sysoev.ru { 130Sigor@sysoev.ru nxt_str_t *s; 140Sigor@sysoev.ru 1510Sigor@sysoev.ru /* The string start is allocated aligned to be close to nxt_str_t. */ 1665Sigor@sysoev.ru s = nxt_mp_get(mp, sizeof(nxt_str_t) + length); 170Sigor@sysoev.ru 180Sigor@sysoev.ru if (nxt_fast_path(s != NULL)) { 1910Sigor@sysoev.ru s->length = length; 2098Svbart@nginx.com s->start = nxt_pointer_to(s, sizeof(nxt_str_t)); 210Sigor@sysoev.ru } 220Sigor@sysoev.ru 230Sigor@sysoev.ru return s; 240Sigor@sysoev.ru } 250Sigor@sysoev.ru 260Sigor@sysoev.ru 270Sigor@sysoev.ru /* 280Sigor@sysoev.ru * nxt_str_dup() creates a new string with a copy of a source string. 290Sigor@sysoev.ru * If length of the source string is zero, then the new string anyway 300Sigor@sysoev.ru * gets a pointer somewhere in mem_pool. 310Sigor@sysoev.ru */ 320Sigor@sysoev.ru 330Sigor@sysoev.ru nxt_str_t * 3465Sigor@sysoev.ru nxt_str_dup(nxt_mp_t *mp, nxt_str_t *dst, const nxt_str_t *src) 350Sigor@sysoev.ru { 360Sigor@sysoev.ru u_char *p; 370Sigor@sysoev.ru 380Sigor@sysoev.ru if (dst == NULL) { 3910Sigor@sysoev.ru /* The string start is allocated aligned to be close to nxt_str_t. */ 4065Sigor@sysoev.ru dst = nxt_mp_get(mp, sizeof(nxt_str_t) + src->length); 410Sigor@sysoev.ru if (nxt_slow_path(dst == NULL)) { 420Sigor@sysoev.ru return NULL; 430Sigor@sysoev.ru } 440Sigor@sysoev.ru 450Sigor@sysoev.ru p = (u_char *) dst; 460Sigor@sysoev.ru p += sizeof(nxt_str_t); 4710Sigor@sysoev.ru dst->start = p; 480Sigor@sysoev.ru 490Sigor@sysoev.ru } else { 5065Sigor@sysoev.ru dst->start = nxt_mp_nget(mp, src->length); 5110Sigor@sysoev.ru if (nxt_slow_path(dst->start == NULL)) { 520Sigor@sysoev.ru return NULL; 530Sigor@sysoev.ru } 540Sigor@sysoev.ru } 550Sigor@sysoev.ru 5610Sigor@sysoev.ru nxt_memcpy(dst->start, src->start, src->length); 5710Sigor@sysoev.ru dst->length = src->length; 580Sigor@sysoev.ru 590Sigor@sysoev.ru return dst; 600Sigor@sysoev.ru } 610Sigor@sysoev.ru 620Sigor@sysoev.ru 630Sigor@sysoev.ru /* 64212Svbart@nginx.com * nxt_str_cstrz() creates a C style zero-terminated copy of a source 650Sigor@sysoev.ru * nxt_str_t. The function is intended to create strings suitable 660Sigor@sysoev.ru * for libc and kernel interfaces so result is pointer to char instead 67216Sigor@sysoev.ru * of u_char to minimize casts. 680Sigor@sysoev.ru */ 690Sigor@sysoev.ru 700Sigor@sysoev.ru char * 71212Svbart@nginx.com nxt_str_cstrz(nxt_mp_t *mp, const nxt_str_t *src) 720Sigor@sysoev.ru { 730Sigor@sysoev.ru char *p, *dst; 740Sigor@sysoev.ru 75216Sigor@sysoev.ru dst = nxt_mp_alloc(mp, src->length + 1); 760Sigor@sysoev.ru 770Sigor@sysoev.ru if (nxt_fast_path(dst != NULL)) { 7810Sigor@sysoev.ru p = nxt_cpymem(dst, src->start, src->length); 790Sigor@sysoev.ru *p = '\0'; 800Sigor@sysoev.ru } 810Sigor@sysoev.ru 820Sigor@sysoev.ru return dst; 830Sigor@sysoev.ru } 840Sigor@sysoev.ru 850Sigor@sysoev.ru 860Sigor@sysoev.ru void 8710Sigor@sysoev.ru nxt_memcpy_lowcase(u_char *dst, const u_char *src, size_t length) 880Sigor@sysoev.ru { 890Sigor@sysoev.ru u_char c; 900Sigor@sysoev.ru 9110Sigor@sysoev.ru while (length != 0) { 920Sigor@sysoev.ru c = *src++; 930Sigor@sysoev.ru *dst++ = nxt_lowcase(c); 9410Sigor@sysoev.ru length--; 950Sigor@sysoev.ru } 960Sigor@sysoev.ru } 970Sigor@sysoev.ru 980Sigor@sysoev.ru 990Sigor@sysoev.ru u_char * 10010Sigor@sysoev.ru nxt_cpystrn(u_char *dst, const u_char *src, size_t length) 1010Sigor@sysoev.ru { 10210Sigor@sysoev.ru if (length == 0) { 1030Sigor@sysoev.ru return dst; 1040Sigor@sysoev.ru } 1050Sigor@sysoev.ru 10610Sigor@sysoev.ru while (--length != 0) { 1070Sigor@sysoev.ru *dst = *src; 1080Sigor@sysoev.ru 1090Sigor@sysoev.ru if (*dst == '\0') { 1100Sigor@sysoev.ru return dst; 1110Sigor@sysoev.ru } 1120Sigor@sysoev.ru 1130Sigor@sysoev.ru dst++; 1140Sigor@sysoev.ru src++; 1150Sigor@sysoev.ru } 1160Sigor@sysoev.ru 1170Sigor@sysoev.ru *dst = '\0'; 1180Sigor@sysoev.ru 1190Sigor@sysoev.ru return dst; 1200Sigor@sysoev.ru } 1210Sigor@sysoev.ru 1220Sigor@sysoev.ru 1230Sigor@sysoev.ru nxt_int_t 1240Sigor@sysoev.ru nxt_strcasecmp(const u_char *s1, const u_char *s2) 1250Sigor@sysoev.ru { 1260Sigor@sysoev.ru u_char c1, c2; 1270Sigor@sysoev.ru nxt_int_t n; 1280Sigor@sysoev.ru 1290Sigor@sysoev.ru for ( ;; ) { 1300Sigor@sysoev.ru c1 = *s1++; 1310Sigor@sysoev.ru c2 = *s2++; 1320Sigor@sysoev.ru 1330Sigor@sysoev.ru c1 = nxt_lowcase(c1); 1340Sigor@sysoev.ru c2 = nxt_lowcase(c2); 1350Sigor@sysoev.ru 1360Sigor@sysoev.ru n = c1 - c2; 1370Sigor@sysoev.ru 1380Sigor@sysoev.ru if (n != 0) { 1390Sigor@sysoev.ru return n; 1400Sigor@sysoev.ru } 1410Sigor@sysoev.ru 1420Sigor@sysoev.ru if (c1 == 0) { 1430Sigor@sysoev.ru return 0; 1440Sigor@sysoev.ru } 1450Sigor@sysoev.ru } 1460Sigor@sysoev.ru } 1470Sigor@sysoev.ru 1480Sigor@sysoev.ru 1490Sigor@sysoev.ru nxt_int_t 15010Sigor@sysoev.ru nxt_strncasecmp(const u_char *s1, const u_char *s2, size_t length) 1510Sigor@sysoev.ru { 1520Sigor@sysoev.ru u_char c1, c2; 1530Sigor@sysoev.ru nxt_int_t n; 1540Sigor@sysoev.ru 15510Sigor@sysoev.ru while (length-- != 0) { 1560Sigor@sysoev.ru c1 = *s1++; 1570Sigor@sysoev.ru c2 = *s2++; 1580Sigor@sysoev.ru 1590Sigor@sysoev.ru c1 = nxt_lowcase(c1); 1600Sigor@sysoev.ru c2 = nxt_lowcase(c2); 1610Sigor@sysoev.ru 1620Sigor@sysoev.ru n = c1 - c2; 1630Sigor@sysoev.ru 1640Sigor@sysoev.ru if (n != 0) { 1650Sigor@sysoev.ru return n; 1660Sigor@sysoev.ru } 1670Sigor@sysoev.ru 1680Sigor@sysoev.ru if (c1 == 0) { 1690Sigor@sysoev.ru return 0; 1700Sigor@sysoev.ru } 1710Sigor@sysoev.ru } 1720Sigor@sysoev.ru 1730Sigor@sysoev.ru return 0; 1740Sigor@sysoev.ru } 1750Sigor@sysoev.ru 1760Sigor@sysoev.ru 1770Sigor@sysoev.ru nxt_int_t 17810Sigor@sysoev.ru nxt_memcasecmp(const u_char *s1, const u_char *s2, size_t length) 1790Sigor@sysoev.ru { 1800Sigor@sysoev.ru u_char c1, c2; 1810Sigor@sysoev.ru nxt_int_t n; 1820Sigor@sysoev.ru 18310Sigor@sysoev.ru while (length-- != 0) { 1840Sigor@sysoev.ru c1 = *s1++; 1850Sigor@sysoev.ru c2 = *s2++; 1860Sigor@sysoev.ru 1870Sigor@sysoev.ru c1 = nxt_lowcase(c1); 1880Sigor@sysoev.ru c2 = nxt_lowcase(c2); 1890Sigor@sysoev.ru 1900Sigor@sysoev.ru n = c1 - c2; 1910Sigor@sysoev.ru 1920Sigor@sysoev.ru if (n != 0) { 1930Sigor@sysoev.ru return n; 1940Sigor@sysoev.ru } 1950Sigor@sysoev.ru } 1960Sigor@sysoev.ru 1970Sigor@sysoev.ru return 0; 1980Sigor@sysoev.ru } 1990Sigor@sysoev.ru 2000Sigor@sysoev.ru 2010Sigor@sysoev.ru /* 2020Sigor@sysoev.ru * nxt_memstrn() is intended for search of static substring "ss" 20310Sigor@sysoev.ru * with known length "length" in string "s" limited by parameter "end". 2040Sigor@sysoev.ru * Zeros are ignored in both strings. 2050Sigor@sysoev.ru */ 2060Sigor@sysoev.ru 2070Sigor@sysoev.ru u_char * 20810Sigor@sysoev.ru nxt_memstrn(const u_char *s, const u_char *end, const char *ss, size_t length) 2090Sigor@sysoev.ru { 2100Sigor@sysoev.ru u_char c1, c2, *s2; 2110Sigor@sysoev.ru 2120Sigor@sysoev.ru s2 = (u_char *) ss; 2130Sigor@sysoev.ru c2 = *s2++; 21410Sigor@sysoev.ru length--; 2150Sigor@sysoev.ru 2160Sigor@sysoev.ru while (s < end) { 2170Sigor@sysoev.ru c1 = *s++; 2180Sigor@sysoev.ru 2190Sigor@sysoev.ru if (c1 == c2) { 2200Sigor@sysoev.ru 22110Sigor@sysoev.ru if (s + length > end) { 2220Sigor@sysoev.ru return NULL; 2230Sigor@sysoev.ru } 2240Sigor@sysoev.ru 22510Sigor@sysoev.ru if (nxt_memcmp(s, s2, length) == 0) { 2260Sigor@sysoev.ru return (u_char *) s - 1; 2270Sigor@sysoev.ru } 2280Sigor@sysoev.ru } 2290Sigor@sysoev.ru } 2300Sigor@sysoev.ru 2310Sigor@sysoev.ru return NULL; 2320Sigor@sysoev.ru } 2330Sigor@sysoev.ru 2340Sigor@sysoev.ru 2350Sigor@sysoev.ru /* 2360Sigor@sysoev.ru * nxt_strcasestrn() is intended for caseless search of static substring 23710Sigor@sysoev.ru * "ss" with known length "length" in string "s" limited by parameter "end". 2380Sigor@sysoev.ru * Zeros are ignored in both strings. 2390Sigor@sysoev.ru */ 2400Sigor@sysoev.ru 2410Sigor@sysoev.ru u_char * 24210Sigor@sysoev.ru nxt_memcasestrn(const u_char *s, const u_char *end, const char *ss, 24310Sigor@sysoev.ru size_t length) 2440Sigor@sysoev.ru { 2450Sigor@sysoev.ru u_char c1, c2, *s2; 2460Sigor@sysoev.ru 2470Sigor@sysoev.ru s2 = (u_char *) ss; 2480Sigor@sysoev.ru c2 = *s2++; 2490Sigor@sysoev.ru c2 = nxt_lowcase(c2); 25010Sigor@sysoev.ru length--; 2510Sigor@sysoev.ru 2520Sigor@sysoev.ru while (s < end) { 2530Sigor@sysoev.ru c1 = *s++; 2540Sigor@sysoev.ru c1 = nxt_lowcase(c1); 2550Sigor@sysoev.ru 2560Sigor@sysoev.ru if (c1 == c2) { 2570Sigor@sysoev.ru 25810Sigor@sysoev.ru if (s + length > end) { 2590Sigor@sysoev.ru return NULL; 2600Sigor@sysoev.ru } 2610Sigor@sysoev.ru 26210Sigor@sysoev.ru if (nxt_memcasecmp(s, s2, length) == 0) { 2630Sigor@sysoev.ru return (u_char *) s - 1; 2640Sigor@sysoev.ru } 2650Sigor@sysoev.ru } 2660Sigor@sysoev.ru } 2670Sigor@sysoev.ru 2680Sigor@sysoev.ru return NULL; 2690Sigor@sysoev.ru } 2700Sigor@sysoev.ru 2710Sigor@sysoev.ru 2720Sigor@sysoev.ru /* 2730Sigor@sysoev.ru * nxt_rstrstrn() is intended to search for static substring "ss" 27410Sigor@sysoev.ru * with known length "length" in string "s" limited by parameter "end" 2750Sigor@sysoev.ru * in reverse order. Zeros are ignored in both strings. 2760Sigor@sysoev.ru */ 2770Sigor@sysoev.ru 2780Sigor@sysoev.ru u_char * 27910Sigor@sysoev.ru nxt_rmemstrn(const u_char *s, const u_char *end, const char *ss, size_t length) 2800Sigor@sysoev.ru { 2810Sigor@sysoev.ru u_char c1, c2; 2820Sigor@sysoev.ru const u_char *s1, *s2; 2830Sigor@sysoev.ru 28410Sigor@sysoev.ru s1 = end - length; 2850Sigor@sysoev.ru s2 = (u_char *) ss; 2860Sigor@sysoev.ru c2 = *s2++; 28710Sigor@sysoev.ru length--; 2880Sigor@sysoev.ru 2890Sigor@sysoev.ru while (s < s1) { 2900Sigor@sysoev.ru c1 = *s1; 2910Sigor@sysoev.ru 2920Sigor@sysoev.ru if (c1 == c2) { 29310Sigor@sysoev.ru if (nxt_memcmp(s1 + 1, s2, length) == 0) { 2940Sigor@sysoev.ru return (u_char *) s1; 2950Sigor@sysoev.ru } 2960Sigor@sysoev.ru } 2970Sigor@sysoev.ru 2980Sigor@sysoev.ru s1--; 2990Sigor@sysoev.ru } 3000Sigor@sysoev.ru 3010Sigor@sysoev.ru return NULL; 3020Sigor@sysoev.ru } 3030Sigor@sysoev.ru 3040Sigor@sysoev.ru 3050Sigor@sysoev.ru size_t 3060Sigor@sysoev.ru nxt_str_strip(u_char *start, u_char *end) 3070Sigor@sysoev.ru { 3080Sigor@sysoev.ru u_char *p; 3090Sigor@sysoev.ru 3100Sigor@sysoev.ru for (p = end - 1; p >= start; p--) { 3110Sigor@sysoev.ru if (*p != NXT_CR && *p != NXT_LF) { 3120Sigor@sysoev.ru break; 3130Sigor@sysoev.ru } 3140Sigor@sysoev.ru } 3150Sigor@sysoev.ru 3160Sigor@sysoev.ru return (p + 1) - start; 3170Sigor@sysoev.ru } 318*354Svbart@nginx.com 319*354Svbart@nginx.com 320*354Svbart@nginx.com nxt_int_t 321*354Svbart@nginx.com nxt_strverscmp(const u_char *s1, const u_char *s2) 322*354Svbart@nginx.com { 323*354Svbart@nginx.com u_char c1, c2; 324*354Svbart@nginx.com nxt_int_t diff; 325*354Svbart@nginx.com 326*354Svbart@nginx.com enum { 327*354Svbart@nginx.com st_str = 0, 328*354Svbart@nginx.com st_num, 329*354Svbart@nginx.com st_zero, 330*354Svbart@nginx.com st_frac, 331*354Svbart@nginx.com } state; 332*354Svbart@nginx.com 333*354Svbart@nginx.com state = st_str; 334*354Svbart@nginx.com 335*354Svbart@nginx.com for ( ;; ) { 336*354Svbart@nginx.com c1 = *s1++; 337*354Svbart@nginx.com c2 = *s2++; 338*354Svbart@nginx.com 339*354Svbart@nginx.com diff = c1 - c2; 340*354Svbart@nginx.com 341*354Svbart@nginx.com if (diff != 0) { 342*354Svbart@nginx.com break; 343*354Svbart@nginx.com } 344*354Svbart@nginx.com 345*354Svbart@nginx.com if (c1 == '\0') { 346*354Svbart@nginx.com return 0; 347*354Svbart@nginx.com } 348*354Svbart@nginx.com 349*354Svbart@nginx.com if (!nxt_isdigit(c1)) { 350*354Svbart@nginx.com state = st_str; 351*354Svbart@nginx.com continue; 352*354Svbart@nginx.com } 353*354Svbart@nginx.com 354*354Svbart@nginx.com if (state == st_str) { 355*354Svbart@nginx.com state = (c1 != '0') ? st_num : st_zero; 356*354Svbart@nginx.com continue; 357*354Svbart@nginx.com } 358*354Svbart@nginx.com 359*354Svbart@nginx.com if (state == st_zero && c1 != '0') { 360*354Svbart@nginx.com state = st_frac; 361*354Svbart@nginx.com continue; 362*354Svbart@nginx.com } 363*354Svbart@nginx.com } 364*354Svbart@nginx.com 365*354Svbart@nginx.com switch (state) { 366*354Svbart@nginx.com 367*354Svbart@nginx.com case st_str: 368*354Svbart@nginx.com 369*354Svbart@nginx.com if ((u_char) (c1 - '1') > 8 || (u_char) (c2 - '1') > 8) { 370*354Svbart@nginx.com return diff; 371*354Svbart@nginx.com } 372*354Svbart@nginx.com 373*354Svbart@nginx.com c1 = *s1++; 374*354Svbart@nginx.com c2 = *s2++; 375*354Svbart@nginx.com 376*354Svbart@nginx.com /* Fall through. */ 377*354Svbart@nginx.com 378*354Svbart@nginx.com case st_num: 379*354Svbart@nginx.com 380*354Svbart@nginx.com while (nxt_isdigit(c1) && nxt_isdigit(c2)) { 381*354Svbart@nginx.com c1 = *s1++; 382*354Svbart@nginx.com c2 = *s2++; 383*354Svbart@nginx.com } 384*354Svbart@nginx.com 385*354Svbart@nginx.com if (nxt_isdigit(c1)) { 386*354Svbart@nginx.com return 1; 387*354Svbart@nginx.com } 388*354Svbart@nginx.com 389*354Svbart@nginx.com if (nxt_isdigit(c2)) { 390*354Svbart@nginx.com return -1; 391*354Svbart@nginx.com } 392*354Svbart@nginx.com 393*354Svbart@nginx.com return diff; 394*354Svbart@nginx.com 395*354Svbart@nginx.com case st_zero: 396*354Svbart@nginx.com 397*354Svbart@nginx.com if (c1 == '0' || c2 == '\0') { 398*354Svbart@nginx.com return -1; 399*354Svbart@nginx.com } 400*354Svbart@nginx.com 401*354Svbart@nginx.com if (c2 == '0' || c1 == '\0') { 402*354Svbart@nginx.com return 1; 403*354Svbart@nginx.com } 404*354Svbart@nginx.com 405*354Svbart@nginx.com /* Fall through. */ 406*354Svbart@nginx.com 407*354Svbart@nginx.com case st_frac: 408*354Svbart@nginx.com return diff; 409*354Svbart@nginx.com } 410*354Svbart@nginx.com 411*354Svbart@nginx.com nxt_unreachable(); 412*354Svbart@nginx.com } 413*354Svbart@nginx.com 414*354Svbart@nginx.com 415*354Svbart@nginx.com nxt_bool_t 416*354Svbart@nginx.com nxt_strvers_match(u_char *version, u_char *prefix, size_t length) 417*354Svbart@nginx.com { 418*354Svbart@nginx.com u_char next, last; 419*354Svbart@nginx.com 420*354Svbart@nginx.com if (nxt_strncmp(version, prefix, length) == 0) { 421*354Svbart@nginx.com 422*354Svbart@nginx.com next = version[length]; 423*354Svbart@nginx.com 424*354Svbart@nginx.com if (next == '\0') { 425*354Svbart@nginx.com return 1; 426*354Svbart@nginx.com } 427*354Svbart@nginx.com 428*354Svbart@nginx.com last = version[length - 1]; 429*354Svbart@nginx.com 430*354Svbart@nginx.com if (nxt_isdigit(last) != nxt_isdigit(next)) { 431*354Svbart@nginx.com /* This is a version part boundary. */ 432*354Svbart@nginx.com return 1; 433*354Svbart@nginx.com } 434*354Svbart@nginx.com } 435*354Svbart@nginx.com 436*354Svbart@nginx.com return 0; 437*354Svbart@nginx.com } 438