Coverage Report

Created: 2026-03-31 06:24

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/git/url.c
Line
Count
Source
1
#include "git-compat-util.h"
2
#include "hex-ll.h"
3
#include "strbuf.h"
4
#include "url.h"
5
6
int is_rfc3986_unreserved(char ch)
7
0
{
8
0
  return isalnum(ch) ||
9
0
    ch == '-' || ch == '_' || ch == '.' || ch == '~';
10
0
}
11
12
int is_casefolding_rfc3986_unreserved(char c)
13
0
{
14
0
  return (c >= 'a' && c <= 'z') ||
15
0
         (c >= '0' && c <= '9') ||
16
0
         c == '-' || c == '.' || c == '_' || c == '~';
17
0
}
18
19
int is_urlschemechar(int first_flag, int ch)
20
0
{
21
  /*
22
   * The set of valid URL schemes, as per STD66 (RFC3986) is
23
   * '[A-Za-z][A-Za-z0-9+.-]*'. But use slightly looser check
24
   * of '[A-Za-z0-9][A-Za-z0-9+.-]*' because earlier version
25
   * of check used '[A-Za-z0-9]+' so not to break any remote
26
   * helpers.
27
   */
28
0
  int alphanumeric, special;
29
0
  alphanumeric = ch > 0 && isalnum(ch);
30
0
  special = ch == '+' || ch == '-' || ch == '.';
31
0
  return alphanumeric || (!first_flag && special);
32
0
}
33
34
int is_url(const char *url)
35
0
{
36
  /* Is "scheme" part reasonable? */
37
0
  if (!url || !is_urlschemechar(1, *url++))
38
0
    return 0;
39
0
  while (*url && *url != ':') {
40
0
    if (!is_urlschemechar(0, *url++))
41
0
      return 0;
42
0
  }
43
  /* We've seen "scheme"; we want colon-slash-slash */
44
0
  return (url[0] == ':' && url[1] == '/' && url[2] == '/');
45
0
}
46
47
static char *url_decode_internal(const char **query, int len,
48
         const char *stop_at, struct strbuf *out,
49
         int decode_plus)
50
1.79k
{
51
1.79k
  const char *q = *query;
52
53
93.3M
  while (len) {
54
93.3M
    unsigned char c = *q;
55
56
93.3M
    if (!c)
57
587
      break;
58
93.3M
    if (stop_at && strchr(stop_at, c)) {
59
311
      q++;
60
311
      len--;
61
311
      break;
62
311
    }
63
64
93.3M
    if (c == '%' && (len < 0 || len >= 3)) {
65
4.74M
      int val = hex2chr(q + 1);
66
4.74M
      if (0 < val) {
67
42.2k
        strbuf_addch(out, val);
68
42.2k
        q += 3;
69
42.2k
        len -= 3;
70
42.2k
        continue;
71
42.2k
      }
72
4.74M
    }
73
74
93.2M
    if (decode_plus && c == '+')
75
2.46M
      strbuf_addch(out, ' ');
76
90.8M
    else
77
90.8M
      strbuf_addch(out, c);
78
93.2M
    q++;
79
93.2M
    len--;
80
93.2M
  }
81
1.79k
  *query = q;
82
1.79k
  return strbuf_detach(out, NULL);
83
1.79k
}
84
85
char *url_decode(const char *url)
86
449
{
87
449
  return url_decode_mem(url, strlen(url));
88
449
}
89
90
char *url_decode_mem(const char *url, int len)
91
449
{
92
449
  struct strbuf out = STRBUF_INIT;
93
449
  const char *colon = memchr(url, ':', len);
94
95
  /* Skip protocol part if present */
96
449
  if (colon && url < colon) {
97
299
    strbuf_add(&out, url, colon - url);
98
299
    len -= colon - url;
99
299
    url = colon;
100
299
  }
101
449
  return url_decode_internal(&url, len, NULL, &out, 0);
102
449
}
103
104
char *url_percent_decode(const char *encoded)
105
449
{
106
449
  struct strbuf out = STRBUF_INIT;
107
449
  return url_decode_internal(&encoded, strlen(encoded), NULL, &out, 0);
108
449
}
109
110
char *url_decode_parameter_name(const char **query)
111
449
{
112
449
  struct strbuf out = STRBUF_INIT;
113
449
  return url_decode_internal(query, -1, "&=", &out, 1);
114
449
}
115
116
char *url_decode_parameter_value(const char **query)
117
449
{
118
449
  struct strbuf out = STRBUF_INIT;
119
449
  return url_decode_internal(query, -1, "&", &out, 1);
120
449
}
121
122
void end_url_with_slash(struct strbuf *buf, const char *url)
123
0
{
124
0
  strbuf_addstr(buf, url);
125
0
  strbuf_complete(buf, '/');
126
0
}
127
128
void str_end_url_with_slash(const char *url, char **dest)
129
0
{
130
0
  struct strbuf buf = STRBUF_INIT;
131
0
  end_url_with_slash(&buf, url);
132
0
  free(*dest);
133
  *dest = strbuf_detach(&buf, NULL);
134
0
}