Coverage Report

Created: 2023-06-07 06:20

/src/h2o/lib/common/string.c
Line
Count
Source (jump to first uncovered line)
1
/*
2
 * Copyright (c) 2014-2016 DeNA Co., Ltd., Kazuho Oku, Justin Zhu, Fastly, Inc.
3
 *
4
 * Permission is hereby granted, free of charge, to any person obtaining a copy
5
 * of this software and associated documentation files (the "Software"), to
6
 * deal in the Software without restriction, including without limitation the
7
 * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
8
 * sell copies of the Software, and to permit persons to whom the Software is
9
 * furnished to do so, subject to the following conditions:
10
 *
11
 * The above copyright notice and this permission notice shall be included in
12
 * all copies or substantial portions of the Software.
13
 *
14
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
19
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
20
 * IN THE SOFTWARE.
21
 */
22
#include <stdint.h>
23
#include <stdio.h>
24
#include <stdlib.h>
25
#include <string.h>
26
#include <time.h>
27
#include "h2o/string_.h"
28
29
h2o_iovec_t h2o_strdup(h2o_mem_pool_t *pool, const char *s, size_t slen)
30
32.6k
{
31
    /* We do not need this check to be here, but it needs to be somewhere, see the definition of H2O_SIZE_T_LONGEST_STR */
32
32.6k
    H2O_BUILD_ASSERT(sizeof(size_t) <= sizeof(uint64_t));
33
34
32.6k
    h2o_iovec_t ret;
35
36
32.6k
    if (slen == SIZE_MAX)
37
1.24k
        slen = strlen(s);
38
39
32.6k
    if (pool != NULL) {
40
32.6k
        ret.base = h2o_mem_alloc_pool(pool, char, slen + 1);
41
32.6k
    } else {
42
11
        ret.base = h2o_mem_alloc(slen + 1);
43
11
    }
44
32.6k
    h2o_memcpy(ret.base, s, slen);
45
32.6k
    ret.base[slen] = '\0';
46
32.6k
    ret.len = slen;
47
32.6k
    return ret;
48
32.6k
}
49
50
h2o_iovec_t h2o_strdup_shared(h2o_mem_pool_t *pool, const char *s, size_t slen)
51
0
{
52
0
    h2o_iovec_t ret;
53
54
0
    if (slen == SIZE_MAX)
55
0
        slen = strlen(s);
56
57
0
    ret.base = h2o_mem_alloc_shared(pool, slen + 1, NULL);
58
0
    memcpy(ret.base, s, slen);
59
0
    ret.base[slen] = '\0';
60
0
    ret.len = slen;
61
0
    return ret;
62
0
}
63
64
h2o_iovec_t h2o_strdup_slashed(h2o_mem_pool_t *pool, const char *src, size_t len)
65
2
{
66
2
    h2o_iovec_t ret;
67
68
2
    ret.len = len != SIZE_MAX ? len : strlen(src);
69
2
    ret.base = pool != NULL ? h2o_mem_alloc_pool(pool, char, ret.len + 2) : h2o_mem_alloc(ret.len + 2);
70
2
    memcpy(ret.base, src, ret.len);
71
2
    if (ret.len != 0 && ret.base[ret.len - 1] != '/')
72
1
        ret.base[ret.len++] = '/';
73
2
    ret.base[ret.len] = '\0';
74
75
2
    return ret;
76
2
}
77
78
int h2o__lcstris_core(const char *target, const char *test, size_t test_len)
79
1.57k
{
80
4.05k
    for (; test_len != 0; --test_len)
81
3.74k
        if (h2o_tolower(*target++) != *test++)
82
1.26k
            return 0;
83
307
    return 1;
84
1.57k
}
85
86
size_t h2o_strtosize(const char *s, size_t len)
87
7.42k
{
88
7.42k
    uint64_t v = 0, m = 1;
89
7.42k
    const char *p = s + len;
90
91
7.42k
    if (len == 0)
92
3
        goto Error;
93
94
13.5k
    while (1) {
95
13.5k
        int ch = *--p;
96
13.5k
        if (!('0' <= ch && ch <= '9'))
97
35
            goto Error;
98
13.5k
        v += (ch - '0') * m;
99
13.5k
        if (p == s)
100
7.38k
            break;
101
6.11k
        m *= 10;
102
        /* do not even try to overflow */
103
6.11k
        if (m == 10000000000000000000ULL)
104
2
            goto Error;
105
6.11k
    }
106
107
7.38k
    if (v >= SIZE_MAX)
108
0
        goto Error;
109
7.38k
    return v;
110
111
40
Error:
112
40
    return SIZE_MAX;
113
7.38k
}
114
115
size_t h2o_strtosizefwd(char **s, size_t len)
116
0
{
117
0
    uint64_t v, c;
118
0
    char *p = *s, *p_end = *s + len;
119
120
0
    if (len == 0)
121
0
        goto Error;
122
123
0
    int ch = *p++;
124
0
    if (!('0' <= ch && ch <= '9'))
125
0
        goto Error;
126
0
    v = ch - '0';
127
0
    c = 1;
128
129
0
    while (1) {
130
0
        ch = *p;
131
0
        if (!('0' <= ch && ch <= '9'))
132
0
            break;
133
0
        v *= 10;
134
0
        v += ch - '0';
135
0
        p++;
136
0
        c++;
137
0
        if (p == p_end)
138
0
            break;
139
        /* similar as above, do not even try to overflow */
140
0
        if (c == 20)
141
0
            goto Error;
142
0
    }
143
144
0
    if (v >= SIZE_MAX)
145
0
        goto Error;
146
0
    *s = p;
147
0
    return v;
148
149
0
Error:
150
0
    return SIZE_MAX;
151
0
}
152
153
static uint32_t decode_base64url_quad(const char *src)
154
0
{
155
0
    const char *src_end = src + 4;
156
0
    uint32_t decoded = 0;
157
158
0
    while (1) {
159
0
        if ('A' <= *src && *src <= 'Z') {
160
0
            decoded |= *src - 'A';
161
0
        } else if ('a' <= *src && *src <= 'z') {
162
0
            decoded |= *src - 'a' + 26;
163
0
        } else if ('0' <= *src && *src <= '9') {
164
0
            decoded |= *src - '0' + 52;
165
0
        } else if (*src == '-') {
166
0
            decoded |= 62;
167
0
        } else if (*src == '_') {
168
0
            decoded |= 63;
169
0
#if 1 /* curl uses normal base64 */
170
0
        } else if (*src == '+') {
171
0
            decoded |= 62;
172
0
        } else if (*src == '/') {
173
0
            decoded |= 63;
174
0
#endif
175
0
        } else {
176
0
            return UINT32_MAX;
177
0
        }
178
0
        if (++src == src_end)
179
0
            break;
180
0
        decoded <<= 6;
181
0
    }
182
183
0
    return decoded;
184
0
}
185
186
h2o_iovec_t h2o_decode_base64url(h2o_mem_pool_t *pool, const char *src, size_t len)
187
0
{
188
0
    h2o_iovec_t decoded;
189
0
    uint32_t t;
190
0
    uint8_t *dst;
191
0
    char remaining_input[4];
192
193
0
    decoded.len = len * 3 / 4;
194
0
    decoded.base = pool != NULL ? h2o_mem_alloc_pool(pool, char, decoded.len + 1) : h2o_mem_alloc(decoded.len + 1);
195
0
    dst = (uint8_t *)decoded.base;
196
197
0
    while (len >= 4) {
198
0
        if ((t = decode_base64url_quad(src)) == UINT32_MAX)
199
0
            goto Error;
200
0
        *dst++ = t >> 16;
201
0
        *dst++ = t >> 8;
202
0
        *dst++ = t;
203
0
        src += 4;
204
0
        len -= 4;
205
0
    }
206
0
    switch (len) {
207
0
    case 0:
208
0
        break;
209
0
    case 1:
210
0
        goto Error;
211
0
    case 2:
212
0
        remaining_input[0] = *src++;
213
0
        remaining_input[1] = *src++;
214
0
        remaining_input[2] = 'A';
215
0
        remaining_input[3] = 'A';
216
0
        if ((t = decode_base64url_quad(remaining_input)) == UINT32_MAX)
217
0
            goto Error;
218
0
        *dst++ = t >> 16;
219
0
        break;
220
0
    case 3:
221
0
        remaining_input[0] = *src++;
222
0
        remaining_input[1] = *src++;
223
0
        remaining_input[2] = *src++;
224
0
        remaining_input[3] = 'A';
225
0
        if ((t = decode_base64url_quad(remaining_input)) == UINT32_MAX)
226
0
            goto Error;
227
0
        *dst++ = t >> 16;
228
0
        *dst++ = t >> 8;
229
0
        break;
230
0
    }
231
232
0
    assert((char *)dst - decoded.base == decoded.len);
233
0
    decoded.base[decoded.len] = '\0';
234
235
0
    return decoded;
236
237
0
Error:
238
0
    if (pool == NULL)
239
0
        free(decoded.base);
240
0
    return h2o_iovec_init(NULL, 0);
241
0
}
242
243
size_t h2o_base64_encode(char *_dst, const void *_src, size_t len, int url_encoded)
244
0
{
245
0
    static const char *MAP = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
246
0
                             "abcdefghijklmnopqrstuvwxyz"
247
0
                             "0123456789+/";
248
0
    static const char *MAP_URL_ENCODED = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
249
0
                                         "abcdefghijklmnopqrstuvwxyz"
250
0
                                         "0123456789-_";
251
252
0
    char *dst = _dst;
253
0
    const uint8_t *src = _src;
254
0
    const char *map = url_encoded ? MAP_URL_ENCODED : MAP;
255
0
    uint32_t quad;
256
257
0
    for (; len >= 3; src += 3, len -= 3) {
258
0
        quad = ((uint32_t)src[0] << 16) | ((uint32_t)src[1] << 8) | src[2];
259
0
        *dst++ = map[quad >> 18];
260
0
        *dst++ = map[(quad >> 12) & 63];
261
0
        *dst++ = map[(quad >> 6) & 63];
262
0
        *dst++ = map[quad & 63];
263
0
    }
264
0
    if (len != 0) {
265
0
        quad = (uint32_t)src[0] << 16;
266
0
        *dst++ = map[quad >> 18];
267
0
        if (len == 2) {
268
0
            quad |= (uint32_t)src[1] << 8;
269
0
            *dst++ = map[(quad >> 12) & 63];
270
0
            *dst++ = map[(quad >> 6) & 63];
271
0
            if (!url_encoded)
272
0
                *dst++ = '=';
273
0
        } else {
274
0
            *dst++ = map[(quad >> 12) & 63];
275
0
            if (!url_encoded) {
276
0
                *dst++ = '=';
277
0
                *dst++ = '=';
278
0
            }
279
0
        }
280
0
    }
281
282
0
    *dst = '\0';
283
0
    return dst - _dst;
284
0
}
285
286
static int decode_hex(int ch)
287
0
{
288
0
    if ('0' <= ch && ch <= '9')
289
0
        return ch - '0';
290
0
    if ('A' <= ch && ch <= 'F')
291
0
        return ch - 'A' + 0xa;
292
0
    if ('a' <= ch && ch <= 'f')
293
0
        return ch - 'a' + 0xa;
294
0
    return -1;
295
0
}
296
297
int h2o_hex_decode(void *_dst, const char *src, size_t src_len)
298
0
{
299
0
    unsigned char *dst = _dst;
300
301
0
    if (src_len % 2 != 0)
302
0
        return -1;
303
0
    for (; src_len != 0; src_len -= 2) {
304
0
        int hi, lo;
305
0
        if ((hi = decode_hex(*src++)) == -1 || (lo = decode_hex(*src++)) == -1)
306
0
            return -1;
307
0
        *dst++ = (hi << 4) | lo;
308
0
    }
309
0
    return 0;
310
0
}
311
312
void h2o_hex_encode(char *dst, const void *_src, size_t src_len)
313
0
{
314
0
    const unsigned char *src = _src, *src_end = src + src_len;
315
0
    for (; src != src_end; ++src) {
316
0
        *dst++ = "0123456789abcdef"[*src >> 4];
317
0
        *dst++ = "0123456789abcdef"[*src & 0xf];
318
0
    }
319
0
    *dst = '\0';
320
0
}
321
322
h2o_iovec_t h2o_uri_escape(h2o_mem_pool_t *pool, const char *s, size_t l, const char *preserve_chars)
323
0
{
324
0
    h2o_iovec_t encoded;
325
0
    size_t i, capacity = l * 3 + 1;
326
327
0
    encoded.base = pool != NULL ? h2o_mem_alloc_pool(pool, char, capacity) : h2o_mem_alloc(capacity);
328
0
    encoded.len = 0;
329
330
    /* RFC 3986:
331
        path-noscheme = segment-nz-nc *( "/" segment )
332
        segment-nz-nc = 1*( unreserved / pct-encoded / sub-delims / "@" )
333
        unreserved  = ALPHA / DIGIT / "-" / "." / "_" / "~"
334
        sub-delims    = "!" / "$" / "&" / "'" / "(" / ")"
335
                     / "*" / "+" / "," / ";" / "="
336
    */
337
0
    for (i = 0; i != l; ++i) {
338
0
        int ch = s[i];
339
0
        if (('A' <= ch && ch <= 'Z') || ('a' <= ch && ch <= 'z') || ('0' <= ch && ch <= '9') || ch == '-' || ch == '.' ||
340
0
            ch == '_' || ch == '~' || ch == '!' || ch == '$' || ch == '&' || ch == '\'' || ch == '(' || ch == ')' || ch == '*' ||
341
0
            ch == '+' || ch == ',' || ch == ';' || ch == '=' ||
342
0
            (ch != '\0' && preserve_chars != NULL && strchr(preserve_chars, ch) != NULL)) {
343
0
            encoded.base[encoded.len++] = ch;
344
0
        } else {
345
0
            encoded.base[encoded.len++] = '%';
346
0
            encoded.base[encoded.len++] = "0123456789ABCDEF"[(ch >> 4) & 0xf];
347
0
            encoded.base[encoded.len++] = "0123456789ABCDEF"[ch & 0xf];
348
0
        }
349
0
    }
350
0
    encoded.base[encoded.len] = '\0';
351
352
0
    return encoded;
353
0
}
354
355
h2o_iovec_t h2o_get_filext(const char *path, size_t len)
356
0
{
357
0
    const char *end = path + len, *p = end;
358
359
0
    while (--p != path) {
360
0
        if (*p == '.') {
361
0
            return h2o_iovec_init(p + 1, end - (p + 1));
362
0
        } else if (*p == '/') {
363
0
            break;
364
0
        }
365
0
    }
366
0
    return h2o_iovec_init(NULL, 0);
367
0
}
368
369
static int is_ws(int ch)
370
0
{
371
0
    return ch == ' ' || ch == '\t' || ch == '\r' || ch == '\n';
372
0
}
373
374
h2o_iovec_t h2o_str_stripws(const char *s, size_t len)
375
0
{
376
0
    const char *end = s + len;
377
378
0
    while (s != end) {
379
0
        if (!is_ws(*s))
380
0
            break;
381
0
        ++s;
382
0
    }
383
0
    while (s != end) {
384
0
        if (!is_ws(end[-1]))
385
0
            break;
386
0
        --end;
387
0
    }
388
0
    return h2o_iovec_init(s, end - s);
389
0
}
390
391
size_t h2o_strstr(const char *haysack, size_t haysack_len, const char *needle, size_t needle_len)
392
1.65k
{
393
    /* TODO optimize */
394
1.65k
    if (haysack_len >= needle_len) {
395
1.51k
        size_t off, max = haysack_len - needle_len + 1;
396
1.51k
        if (needle_len == 0)
397
0
            return 0;
398
305k
        for (off = 0; off != max; ++off)
399
303k
            if (haysack[off] == needle[0] && memcmp(haysack + off + 1, needle + 1, needle_len - 1) == 0)
400
0
                return off;
401
1.51k
    }
402
1.65k
    return SIZE_MAX;
403
1.65k
}
404
405
/* note: returns a zero-width match as well */
406
const char *h2o_next_token(h2o_iovec_t *iter, int inner, int outer, size_t *element_len, h2o_iovec_t *value)
407
8.58k
{
408
8.58k
    const char *cur = iter->base, *end = iter->base + iter->len, *token_start, *token_end;
409
410
    /* find start */
411
9.92k
    for (;; ++cur) {
412
9.92k
        if (cur == end)
413
906
            return NULL;
414
9.02k
        if (!(*cur == ' ' || *cur == '\t'))
415
7.67k
            break;
416
9.02k
    }
417
7.67k
    token_start = cur;
418
7.67k
    token_end = cur;
419
420
    /* find last */
421
47.2k
    for (;; ++cur) {
422
47.2k
        if (cur == end)
423
830
            break;
424
46.3k
        if (*cur == inner) {
425
4.89k
            ++cur;
426
4.89k
            break;
427
4.89k
        }
428
41.4k
        if (*cur == outer) {
429
0
            if (token_start == cur) {
430
0
                ++cur;
431
0
                token_end = cur;
432
0
            }
433
0
            break;
434
0
        }
435
41.4k
        if (value != NULL && *cur == '=') {
436
1.95k
            ++cur;
437
1.95k
            goto FindValue;
438
1.95k
        }
439
39.5k
        if (!(*cur == ' ' || *cur == '\t'))
440
38.5k
            token_end = cur + 1;
441
39.5k
    }
442
443
    /* found */
444
5.72k
    *iter = h2o_iovec_init(cur, end - cur);
445
5.72k
    *element_len = token_end - token_start;
446
5.72k
    if (value != NULL)
447
3.18k
        *value = (h2o_iovec_t){NULL};
448
5.72k
    return token_start;
449
450
1.95k
FindValue:
451
1.95k
    *iter = h2o_iovec_init(cur, end - cur);
452
1.95k
    *element_len = token_end - token_start;
453
1.95k
    if ((value->base = (char *)h2o_next_token(iter, inner, outer, &value->len, NULL)) == NULL) {
454
22
        *value = (h2o_iovec_t){"", 0};
455
1.92k
    } else if (h2o_memis(value->base, value->len, H2O_STRLIT(","))) {
456
0
        *value = (h2o_iovec_t){"", 0};
457
0
        iter->base -= 1;
458
0
        iter->len += 1;
459
0
    }
460
1.95k
    return token_start;
461
7.67k
}
462
463
int h2o_contains_token(const char *haysack, size_t haysack_len, const char *needle, size_t needle_len, int separator)
464
618
{
465
618
    h2o_iovec_t iter = h2o_iovec_init(haysack, haysack_len);
466
618
    const char *token = NULL;
467
618
    size_t token_len = 0;
468
469
1.23k
    while ((token = h2o_next_token(&iter, separator, ',', &token_len, NULL)) != NULL) {
470
618
        if (h2o_lcstris(token, token_len, needle, needle_len)) {
471
0
            return 1;
472
0
        }
473
618
    }
474
618
    return 0;
475
618
}
476
477
h2o_iovec_t h2o_htmlescape(h2o_mem_pool_t *pool, const char *src, size_t len)
478
0
{
479
0
    const char *s, *end = src + len;
480
0
    size_t add_size = 0;
481
482
0
#define ENTITY_MAP()                                                                                                               \
483
0
    ENTITY('"', "&quot;");                                                                                                         \
484
0
    ENTITY('&', "&amp;");                                                                                                          \
485
0
    ENTITY('\'', "&#39;");                                                                                                         \
486
0
    ENTITY('<', "&lt;");                                                                                                           \
487
0
    ENTITY('>', "&gt;");
488
489
0
    for (s = src; s != end; ++s) {
490
0
        if ((unsigned)(unsigned char)*s - '"' <= '>' - '"') {
491
0
            switch (*s) {
492
0
#define ENTITY(code, quoted)                                                                                                       \
493
0
    case code:                                                                                                                     \
494
0
        add_size += sizeof(quoted) - 2;                                                                                            \
495
0
        break
496
0
                ENTITY_MAP()
497
0
#undef ENTITY
498
0
            }
499
0
        }
500
0
    }
501
502
    /* escape and return the result if necessary */
503
0
    if (add_size != 0) {
504
        /* allocate buffer and fill in the chars that are known not to require escaping */
505
0
        h2o_iovec_t escaped = {h2o_mem_alloc_pool(pool, char, len + add_size + 1), 0};
506
        /* fill-in the rest */
507
0
        for (s = src; s != end; ++s) {
508
0
            switch (*s) {
509
0
#define ENTITY(code, quoted)                                                                                                       \
510
0
    case code:                                                                                                                     \
511
0
        memcpy(escaped.base + escaped.len, quoted, sizeof(quoted) - 1);                                                            \
512
0
        escaped.len += sizeof(quoted) - 1;                                                                                         \
513
0
        break
514
0
                ENTITY_MAP()
515
0
#undef ENTITY
516
0
            default:
517
0
                escaped.base[escaped.len++] = *s;
518
0
                break;
519
0
            }
520
0
        }
521
0
        assert(escaped.len == len + add_size);
522
0
        escaped.base[escaped.len] = '\0';
523
524
0
        return escaped;
525
0
    }
526
527
0
#undef ENTITY_MAP
528
529
    /* no need not escape; return the original */
530
0
    return h2o_iovec_init(src, len);
531
0
}
532
533
h2o_iovec_t h2o_concat_list(h2o_mem_pool_t *pool, h2o_iovec_t *list, size_t count)
534
1.48k
{
535
1.48k
    h2o_iovec_t ret = {NULL, 0};
536
1.48k
    size_t i;
537
538
    /* calc the length */
539
383k
    for (i = 0; i != count; ++i) {
540
381k
        ret.len += list[i].len;
541
381k
    }
542
543
    /* allocate memory */
544
1.48k
    if (pool != NULL)
545
1.48k
        ret.base = h2o_mem_alloc_pool(pool, char, ret.len + 1);
546
0
    else
547
0
        ret.base = h2o_mem_alloc(ret.len + 1);
548
549
    /* concatenate */
550
1.48k
    ret.len = 0;
551
383k
    for (i = 0; i != count; ++i) {
552
381k
        h2o_memcpy(ret.base + ret.len, list[i].base, list[i].len);
553
381k
        ret.len += list[i].len;
554
381k
    }
555
1.48k
    ret.base[ret.len] = '\0';
556
557
1.48k
    return ret;
558
1.48k
}
559
560
h2o_iovec_t h2o_join_list(h2o_mem_pool_t *pool, h2o_iovec_t *list, size_t count, h2o_iovec_t delimiter)
561
246
{
562
246
    if (count == 0) {
563
0
        return h2o_iovec_init(NULL, 0);
564
0
    }
565
566
246
    size_t joined_len = 0;
567
246
    h2o_iovec_t *joined = alloca(sizeof(*joined) * (count * 2 - 1));
568
569
246
    size_t i;
570
190k
    for (i = 0; i != count; ++i) {
571
190k
        if (i != 0) {
572
189k
            joined[joined_len++] = delimiter;
573
189k
        }
574
190k
        joined[joined_len++] = list[i];
575
190k
    }
576
246
    return h2o_concat_list(pool, joined, joined_len);
577
246
}
578
579
void h2o_split(h2o_mem_pool_t *pool, h2o_iovec_vector_t *list, h2o_iovec_t str, const char needle)
580
0
{
581
0
    const char *p = str.base, *end = str.base + str.len, *found;
582
583
0
    while (p < end && (found = memchr(p, needle, end - p)) != NULL) {
584
0
        h2o_vector_reserve(pool, list, list->size + 1);
585
0
        list->entries[list->size++] = h2o_strdup(pool, p, found - p);
586
0
        p = found + 1;
587
0
    }
588
0
    h2o_vector_reserve(pool, list, list->size + 1);
589
0
    list->entries[list->size++] = h2o_strdup(pool, p, end - p);
590
0
}
591
592
int h2o_str_at_position(char *buf, const char *src, size_t src_len, int lineno, int column)
593
0
{
594
0
    const char *src_end = src + src_len;
595
0
    int i;
596
597
    /* find the line */
598
0
    if (lineno <= 0 || column <= 0)
599
0
        return -1;
600
0
    for (--lineno; lineno != 0; --lineno) {
601
0
        do {
602
0
            if (src == src_end)
603
0
                return -1;
604
0
        } while (*src++ != '\n');
605
0
    }
606
607
    /* adjust the starting column */
608
0
    while (column > 40) {
609
0
        if (src != src_end)
610
0
            ++src;
611
0
        --column;
612
0
    }
613
614
    /* emit */
615
0
    for (i = 1; i <= 76; ++i) {
616
0
        if (src == src_end || *src == '\n')
617
0
            break;
618
0
        *buf++ = *src++;
619
0
    }
620
0
    if (i < column)
621
0
        column = i;
622
0
    *buf++ = '\n';
623
0
    for (i = 1; i < column; ++i)
624
0
        *buf++ = ' ';
625
0
    *buf++ = '^';
626
0
    *buf++ = '\n';
627
0
    *buf = '\0';
628
0
    return 0;
629
0
}
630
631
h2o_iovec_t h2o_encode_sf_string(h2o_mem_pool_t *pool, const char *s, size_t slen)
632
0
{
633
0
    if (slen == SIZE_MAX)
634
0
        slen = strlen(s);
635
636
    /* https://tools.ietf.org/html/rfc8941#section-3.3.3 */
637
0
    size_t to_escape = 0;
638
0
    for (size_t i = 0; i < slen; ++i) {
639
0
        if (s[i] == '\\' || s[i] == '"')
640
0
            ++to_escape;
641
0
    }
642
643
0
    h2o_iovec_t ret;
644
0
    ret.len = slen + to_escape + 2;
645
0
    if (pool != NULL) {
646
0
        ret.base = h2o_mem_alloc_pool(pool, char, ret.len + 1);
647
0
    } else {
648
0
        ret.base = h2o_mem_alloc(ret.len + 1);
649
0
    }
650
0
    char *dst = ret.base;
651
0
    *dst++ = '"';
652
0
    for (size_t i = 0; i < slen; ++i) {
653
0
        if (s[i] == '\\' || s[i] == '"')
654
0
            *dst++ = '\\';
655
0
        *dst++ = s[i];
656
0
    }
657
0
    *dst++ = '"';
658
0
    *dst++ = '\0';
659
0
    return ret;
660
0
}