✓ProveIt
Examples / Report #547630 Saved analysis

CVE-2019-5435: An integer overflow found in /lib/urlapi.c

curl · 2019-04-2415.0s analysis · $0.023 in model calls

What the report claims

An integer overflow in curl's seturl function may cause a heap-based buffer overrun when processing URLs up to 2GB in length on 32-bit systems.

Compare with curl's recorded outcome

Known vulnerability

A real vulnerability: CVE-2019-5435 Integer overflows in URL parser

Shown for comparison after analysis. The pipeline did not see this label.

ProveIt's finding

Code supports the claim

The code supports the reported flaw. A maintainer should review its impact and decide what to do next.

Why this finding?
  • The integer overflow in urllen * 2 + 2 is real and present in the provided code at lib/urlapi.c:645.
  • No length check guards the multiplication; the call chain curl_url_set -> parseurl -> seturl is reachable with an absolute URL.
  • On 32-bit systems the wrap causes malloc to return a small buffer, and subsequent writes using the original urllen overrun the heap.
  • Practical exploitability on 32-bit is limited by address-space constraints (a 2+ GB string is hard to allocate), but the flaw is a classic heap overflow via integer wrap and similar issues (e.g., CVE-2018-14618) have been treated as security vulnerabilities in curl.
How this analysis ran 5 claims · 12 citations verified

Checked against curl master on 2019-04-24 (e7d3f65ab95a). Test evaluation split. Citation verification checks that a referenced line was in the evidence; it does not prove the model interpreted it correctly.

1 · Grounding
grounded
no model · 13 references checked out, 0 did not
2 · Claims
NVIDIA-Nemotron-3-Nano-30B-A3B
5 claims · 1632 tokens · $0.0002
3 · Evidence
9 code snippets
real curl source at e7d3f65ab95a
4 · Judgment
Nemotron-3-Ultra-550b-a55b
14321 tokens · 12.9s · $0.0224
5 · Receipts
12 of 12 citations verified
every citation must point at code the judge was shown
Review a draft reply to the reporter

Edit and verify before sending.

Thank you for the report. The integer overflow at lib/urlapi.c:645 (urllen * 2 + 2) is real and reachable via curl_url_set with an absolute URL. On 32-bit systems the multiplication wraps, malloc returns an undersized buffer, and later writes overrun the heap. While a 2+ GB URL is difficult to supply on 32-bit due to address-space limits, the flaw is a genuine heap buffer overrun and matches patterns we have fixed before (e.g., CVE-2018-14618). We will address it.

Inspect all claims and source code 5 claims · 9 code excerpts

Report claims

C1flaw supported

urllen was multiplied by 2 and then passed to malloc, causing integer overflow when url length reaches 2GB on 32-bit OS

Read the reasoning

The code computes urllen * 2 + 2 in size_t and passes it to malloc. On 32-bit systems where size_t is 32-bit unsigned, this multiplication wraps modulo 2^32 when urllen exceeds ~2.1GB, causing malloc to allocate a small buffer instead of the intended large one.

C2location supported

in function seturl in /lib/urlapi.c

Read the reasoning

The function seturl is defined at line 622 in lib/urlapi.c and contains the allocation at line 645.

C3trigger supported

when a URL of length 2GB is processed on a 32-bit OS

Read the reasoning

No bounds check on the full URL length exists before the multiplication. The trigger condition (2GB URL on 32-bit) is theoretically reachable via the public API curl_url_set with an absolute URL.

C4impact supported

may lead to a crash or buffer overrun

Read the reasoning

After the integer overflow, malloc returns a tiny buffer. Subsequent pointer arithmetic (path[urllen + 1]) and writes (hostname[0] = 0) use the original huge urllen value, causing out-of-bounds heap access — a buffer overrun that can crash or corrupt memory.

C5reproduction supported

use curl_url_set with an extreme long URL to trigger parseurl and seturl

Read the reasoning

The call chain curl_url_set -> parseurl -> seturl is present and reachable when the input is an absolute URL. An attacker controlling the URL string passed to curl_url_set can trigger the flaw.

Read the original report

Full report on HackerOne ↗

## Summary: libcurl contains a heap-based buffer overrun in /lib/urlapi.c. A similiar issue to CVE-2018-14618. ## Steps To Reproduce: ### analysis I found a potential integer overflow which may lead to a buffer overrun in /curl/lib/urlapi.c. In function `seturl`, urllen was multiplied by 2 and then passed to malloc. So an integer overflow will happen when the url is as long as 2GB in a 32 bit OS. ```c static CURLUcode seturl(const char *url, CURLU *u, unsigned int flags) { char *path; bool path_alloced = FALSE; char *hostname; char *query = NULL; char *fragment = NULL; CURLUcode result; bool url_has_scheme = FALSE; char schemebuf[MAX_SCHEME_LEN]; char *schemep = NULL; size_t schemelen = 0; size_t urllen; const struct Curl_handler *h = NULL; if(!url) return CURLUE_MALFORMED_INPUT; /************************************************************* * Parse the URL. ************************************************************/ /* allocate scratch area */ urllen = strlen(url); path = u->scratch = malloc(urllen * 2 + 2); <= overflow here ``` The url was passed by `parseurl` to `seturl`. ```c static CURLUcode parseurl(const char *url, CURLU *u, unsigned int flags) { CURLUcode result = seturl(url, u, flags); if(result) { free_urlhandle(u); memset(u, 0, sizeof(struct Curl_URL)); } return result; } ``` And the `parseurl` was called when do `curl_url_set` and execute the parse of url. If someone use libcurl to code, and call `curl_url_set` with a extreme long url, it might be triggered. ```c  CURLUcode curl_url_set(CURLU *u, CURLUPart what, const char *part, unsigned int flags) ...... case CURLUPART_URL: { /* * Allow a new URL to replace the existing (if any) contents. * * If the existing contents is enough for a URL, allow a relative URL to * replace it. */ CURLUcode result; char *oldurl; char *redired_url; CURLU *handle2; if(Curl_is_absolute_url(part, NULL, MAX_SCHEME_LEN)) { handle2 = curl_url(); if(!handle2) return CURLUE_OUT_OF_MEMORY; result = parseurl(part, handle2, flags); <= call parseurl if(!result) mv_urlhandle(handle2, u); else curl_url_cleanup(handle2); return result; } ``` ## Impact It might leads to a crash or some other impact.

Source code

lib/urlapi.clines 622–782 · definition of seturl (truncated)
622static CURLUcode seturl(const char *url, CURLU *u, unsigned int flags)
C2: static CURLUcode seturl(const char *url, CURLU *u, unsigned int flags)
623{
624 char *path;
625 bool path_alloced = FALSE;
626 char *hostname;
627 char *query = NULL;
628 char *fragment = NULL;
629 CURLUcode result;
630 bool url_has_scheme = FALSE;
631 char schemebuf[MAX_SCHEME_LEN];
632 char *schemep = NULL;
633 size_t schemelen = 0;
634 size_t urllen;
C1: urllen declared as size_t
635 const struct Curl_handler *h = NULL;
636
637 if(!url)
638 return CURLUE_MALFORMED_INPUT;
639
640 /*************************************************************
641 * Parse the URL.
642 ************************************************************/
643 /* allocate scratch area */
644 urllen = strlen(url);
C1: urllen = strlen(url); returns size_t
C3: urllen = strlen(url); no length check before multiplication
645 path = u->scratch = malloc(urllen * 2 + 2);
C1: malloc(urllen * 2 + 2); multiplication in size_t arithmetic, wraps on 32-bit when urllen > ~2GB
C4: malloc(urllen * 2 + 2) returns undersized buffer after wrap
646 if(!path)
647 return CURLUE_OUT_OF_MEMORY;
648
649 hostname = &path[urllen + 1];
C4: hostname = &path[urllen + 1]; pointer arithmetic with huge urllen
650 hostname[0] = 0;
C4: hostname[0] = 0; writes to wrapped pointer location
651
652 if(Curl_is_absolute_url(url, schemebuf, sizeof(schemebuf))) {
653 url_has_scheme = TRUE;
654 schemelen = strlen(schemebuf);
655 }
656
657 /* handle the file: scheme */
658 if(url_has_scheme && strcasecompare(schemebuf, "file")) {
659 /* path has been allocated large enough to hold this */
660 strcpy(path, &url[5]);
661
662 hostname = NULL; /* no host for file: URLs */
663 u->scheme = strdup("file");
664 if(!u->scheme)
665 return CURLUE_OUT_OF_MEMORY;
666
667 /* Extra handling URLs with an authority component (i.e. that start with
668 * "file://")
669 *
670 * We allow omitted hostname (e.g. file:/<path>) -- valid according to
671 * RFC 8089, but not the (current) WHAT-WG URL spec.
672 */
673 if(path[0] == '/' && path[1] == '/') {
674 /* swallow the two slashes */
675 char *ptr = &path[2];
676
677 /*
678 * According to RFC 8089, a file: URL can be reliably dereferenced if:
679 *
680 * o it has no/blank hostname, or
681 *
682 * o the hostname matches "localhost" (case-insensitively), or
683 *
684 * o the hostname is a FQDN that resolves to this machine.
685 *
686 * For brevity, we only consider URLs with empty, "localhost", or
687 * "127.0.0.1" hostnames as local.
688 *
689 * Additionally, there is an exception for URLs with a Windows drive
690 * letter in the authority (which was accidentally omitted from RFC 8089
691 * Appendix E, but believe me, it was meant to be there. --MK)
692 */
693 if(ptr[0] != '/' && !STARTS_WITH_URL_DRIVE_PREFIX(ptr)) {
694 /* the URL includes a host name, it must match "localhost" or
695 "127.0.0.1" to be valid */
696 if(!checkprefix("localhost/", ptr) &&
697 !checkprefix("127.0.0.1/", ptr)) {
698 /* Invalid file://hostname/, expected localhost or 127.0.0.1 or
699 none */
700 return CURLUE_MALFORMED_INPUT;
701 }
702 ptr += 9; /* now points to the slash after the host */
703 }
704
705 path = ptr;
706 }
707
708#if !defined(MSDOS) && !defined(WIN32) && !defined(__CYGWIN__)
709 /* Don't allow Windows drive letters when not in Windows.
710 * This catches both "file:/c:" and "file:c:" */
711 if(('/' == path[0] && STARTS_WITH_URL_DRIVE_PREFIX(&path[1])) ||
712 STARTS_WITH_URL_DRIVE_PREFIX(path)) {
713 /* File drive letters are only accepted in MSDOS/Windows */
714 return CURLUE_MALFORMED_INPUT;
715 }
716#else
717 /* If the path starts with a slash and a drive letter, ditch the slash */
718 if('/' == path[0] && STARTS_WITH_URL_DRIVE_PREFIX(&path[1])) {
719 /* This cannot be done with strcpy, as the memory chunks overlap! */
720 memmove(path, &path[1], strlen(&path[1]) + 1);
721 }
722#endif
723
724 }
725 else {
726 /* clear path */
727 const char *p;
728 const char *hostp;
729 size_t len;
730 path[0] = 0;
731
732 if(url_has_scheme) {
733 int i = 0;
734 p = &url[schemelen + 1];
735 while(p && (*p == '/') && (i < 4)) {
736 p++;
737 i++;
738 }
739 if((i < 1) || (i>3))
740 /* less than one or more than three slashes */
741 return CURLUE_MALFORMED_INPUT;
742
743 schemep = schemebuf;
744 if(!Curl_builtin_scheme(schemep) &&
745 !(flags & CURLU_NON_SUPPORT_SCHEME))
746 return CURLUE_UNSUPPORTED_SCHEME;
747
748 if(junkscan(schemep))
749 return CURLUE_MALFORMED_INPUT;
750 }
751 else {
752 /* no scheme! */
753
754 if(!(flags & (CURLU_DEFAULT_SCHEME|CURLU_GUESS_SCHEME)))
755 return CURLUE_MALFORMED_INPUT;
756 if(flags & CURLU_DEFAULT_SCHEME)
757 schemep = (char *) DEFAULT_SCHEME;
758
759 /*
760 * The URL was badly formatted, let's try without scheme specified.
761 */
762 p = url;
763 }
764 hostp = p; /* host name starts here */
765
766 while(*p && !HOSTNAME_END(*p)) /* find end of host name */
767 p++;
768
769 len = p - hostp;
770 if(!len)
771 return CURLUE_MALFORMED_INPUT;
772
773 memcpy(hostname, hostp, len);
774 hostname[len] = 0;
775
776 if((flags & CURLU_GUESS_SCHEME) && !schemep) {
777 /* legacy curl-style guess based on host name */
778 if(checkprefix("ftp.", hostname))
779 schemep = (char *)"ftp";
780 else if(checkprefix("dict.", hostname))
781 schemep = (char *)"dict";
782 else if(checkprefix("ldap.", hostname))
lib/urlapi.clines 1114–1274 · definition of curl_url_set (truncated)
1114CURLUcode curl_url_set(CURLU *u, CURLUPart what,
C5: CURLUcode curl_url_set(CURLU *u, CURLUPart what, const char *part, unsigned int flags)
1115 const char *part, unsigned int flags)
1116{
1117 char **storep = NULL;
1118 long port = 0;
1119 bool urlencode = (flags & CURLU_URLENCODE)? 1 : 0;
1120 bool plusencode = FALSE;
1121 bool urlskipslash = FALSE;
1122 bool appendquery = FALSE;
1123 bool equalsencode = FALSE;
1124
1125 if(!u)
1126 return CURLUE_BAD_HANDLE;
1127 if(!part) {
1128 /* setting a part to NULL clears it */
1129 switch(what) {
1130 case CURLUPART_URL:
1131 break;
1132 case CURLUPART_SCHEME:
1133 storep = &u->scheme;
1134 break;
1135 case CURLUPART_USER:
1136 storep = &u->user;
1137 break;
1138 case CURLUPART_PASSWORD:
1139 storep = &u->password;
1140 break;
1141 case CURLUPART_OPTIONS:
1142 storep = &u->options;
1143 break;
1144 case CURLUPART_HOST:
1145 storep = &u->host;
1146 break;
1147 case CURLUPART_PORT:
1148 u->portnum = 0;
1149 storep = &u->port;
1150 break;
1151 case CURLUPART_PATH:
1152 storep = &u->path;
1153 break;
1154 case CURLUPART_QUERY:
1155 storep = &u->query;
1156 break;
1157 case CURLUPART_FRAGMENT:
1158 storep = &u->fragment;
1159 break;
1160 default:
1161 return CURLUE_UNKNOWN_PART;
1162 }
1163 if(storep && *storep) {
1164 free(*storep);
1165 *storep = NULL;
1166 }
1167 return CURLUE_OK;
1168 }
1169
1170 switch(what) {
1171 case CURLUPART_SCHEME:
1172 if(!(flags & CURLU_NON_SUPPORT_SCHEME) &&
1173 /* verify that it is a fine scheme */
1174 !Curl_builtin_scheme(part))
1175 return CURLUE_UNSUPPORTED_SCHEME;
1176 storep = &u->scheme;
1177 urlencode = FALSE; /* never */
1178 break;
1179 case CURLUPART_USER:
1180 storep = &u->user;
1181 break;
1182 case CURLUPART_PASSWORD:
1183 storep = &u->password;
1184 break;
1185 case CURLUPART_OPTIONS:
1186 storep = &u->options;
1187 break;
1188 case CURLUPART_HOST:
1189 storep = &u->host;
1190 break;
1191 case CURLUPART_PORT:
1192 {
1193 char *endp;
1194 urlencode = FALSE; /* never */
1195 port = strtol(part, &endp, 10); /* Port number must be decimal */
1196 if((port <= 0) || (port > 0xffff))
1197 return CURLUE_BAD_PORT_NUMBER;
1198 if(*endp)
1199 /* weirdly provided number, not good! */
1200 return CURLUE_MALFORMED_INPUT;
1201 storep = &u->port;
1202 }
1203 break;
1204 case CURLUPART_PATH:
1205 urlskipslash = TRUE;
1206 storep = &u->path;
1207 break;
1208 case CURLUPART_QUERY:
1209 plusencode = urlencode;
1210 appendquery = (flags & CURLU_APPENDQUERY)?1:0;
1211 equalsencode = appendquery;
1212 storep = &u->query;
1213 break;
1214 case CURLUPART_FRAGMENT:
1215 storep = &u->fragment;
1216 break;
1217 case CURLUPART_URL: {
1218 /*
1219 * Allow a new URL to replace the existing (if any) contents.
1220 *
1221 * If the existing contents is enough for a URL, allow a relative URL to
1222 * replace it.
1223 */
1224 CURLUcode result;
1225 char *oldurl;
1226 char *redired_url;
1227 CURLU *handle2;
1228
1229 if(Curl_is_absolute_url(part, NULL, MAX_SCHEME_LEN)) {
C3: curl_url_set calls Curl_is_absolute_url which only checks scheme length (MAX_SCHEME_LEN), not total URL length
C5: if(Curl_is_absolute_url(part, NULL, MAX_SCHEME_LEN)) { handle2 = curl_url(); result = parseurl(part, handle2, flags); }
1230 handle2 = curl_url();
1231 if(!handle2)
1232 return CURLUE_OUT_OF_MEMORY;
1233 result = parseurl(part, handle2, flags);
1234 if(!result)
1235 mv_urlhandle(handle2, u);
1236 else
1237 curl_url_cleanup(handle2);
1238 return result;
1239 }
1240 /* extract the full "old" URL to do the redirect on */
1241 result = curl_url_get(u, CURLUPART_URL, &oldurl, flags);
1242 if(result) {
1243 /* couldn't get the old URL, just use the new! */
1244 handle2 = curl_url();
1245 if(!handle2)
1246 return CURLUE_OUT_OF_MEMORY;
1247 result = parseurl(part, handle2, flags);
1248 if(!result)
1249 mv_urlhandle(handle2, u);
1250 else
1251 curl_url_cleanup(handle2);
1252 return result;
1253 }
1254
1255 /* apply the relative part to create a new URL */
1256 redired_url = concat_url(oldurl, part);
1257 free(oldurl);
1258 if(!redired_url)
1259 return CURLUE_OUT_OF_MEMORY;
1260
1261 /* now parse the new URL */
1262 handle2 = curl_url();
1263 if(!handle2) {
1264 free(redired_url);
1265 return CURLUE_OUT_OF_MEMORY;
1266 }
1267 result = parseurl(redired_url, handle2, flags);
1268 free(redired_url);
1269 if(!result)
1270 mv_urlhandle(handle2, u);
1271 else
1272 curl_url_cleanup(handle2);
1273 return result;
1274 }
lib/urlapi.clines 884–892 · definition of parseurl
884static CURLUcode parseurl(const char *url, CURLU *u, unsigned int flags)
C5: static CURLUcode parseurl(const char *url, CURLU *u, unsigned int flags) { result = seturl(url, u, flags); }
885{
886 CURLUcode result = seturl(url, u, flags);
887 if(result) {
888 free_urlhandle(u);
889 memset(u, 0, sizeof(struct Curl_URL));
890 }
891 return result;
892}
lib/urlapi.c@curl-7_64_1lines 1114–1274 · definition of curl_url_set as in release curl-7_64_1; differs from master; commits that changed it since: d715d2ac89 urlapi: stricter CURLUPART_PORT parsing | 0dd47c2a3d urlapi: urlencode characters above 0x7f correctly
Show 161 lines (not cited by the judge)
1114CURLUcode curl_url_set(CURLU *u, CURLUPart what,
1115 const char *part, unsigned int flags)
1116{
1117 char **storep = NULL;
1118 long port = 0;
1119 bool urlencode = (flags & CURLU_URLENCODE)? 1 : 0;
1120 bool plusencode = FALSE;
1121 bool urlskipslash = FALSE;
1122 bool appendquery = FALSE;
1123 bool equalsencode = FALSE;
1124
1125 if(!u)
1126 return CURLUE_BAD_HANDLE;
1127 if(!part) {
1128 /* setting a part to NULL clears it */
1129 switch(what) {
1130 case CURLUPART_URL:
1131 break;
1132 case CURLUPART_SCHEME:
1133 storep = &u->scheme;
1134 break;
1135 case CURLUPART_USER:
1136 storep = &u->user;
1137 break;
1138 case CURLUPART_PASSWORD:
1139 storep = &u->password;
1140 break;
1141 case CURLUPART_OPTIONS:
1142 storep = &u->options;
1143 break;
1144 case CURLUPART_HOST:
1145 storep = &u->host;
1146 break;
1147 case CURLUPART_PORT:
1148 storep = &u->port;
1149 break;
1150 case CURLUPART_PATH:
1151 storep = &u->path;
1152 break;
1153 case CURLUPART_QUERY:
1154 storep = &u->query;
1155 break;
1156 case CURLUPART_FRAGMENT:
1157 storep = &u->fragment;
1158 break;
1159 default:
1160 return CURLUE_UNKNOWN_PART;
1161 }
1162 if(storep && *storep) {
1163 free(*storep);
1164 *storep = NULL;
1165 }
1166 return CURLUE_OK;
1167 }
1168
1169 switch(what) {
1170 case CURLUPART_SCHEME:
1171 if(!(flags & CURLU_NON_SUPPORT_SCHEME) &&
1172 /* verify that it is a fine scheme */
1173 !Curl_builtin_scheme(part))
1174 return CURLUE_UNSUPPORTED_SCHEME;
1175 storep = &u->scheme;
1176 urlencode = FALSE; /* never */
1177 break;
1178 case CURLUPART_USER:
1179 storep = &u->user;
1180 break;
1181 case CURLUPART_PASSWORD:
1182 storep = &u->password;
1183 break;
1184 case CURLUPART_OPTIONS:
1185 storep = &u->options;
1186 break;
1187 case CURLUPART_HOST:
1188 storep = &u->host;
1189 break;
1190 case CURLUPART_PORT:
1191 urlencode = FALSE; /* never */
1192 port = strtol(part, NULL, 10); /* Port number must be decimal */
1193 if((port <= 0) || (port > 0xffff))
1194 return CURLUE_BAD_PORT_NUMBER;
1195 storep = &u->port;
1196 break;
1197 case CURLUPART_PATH:
1198 urlskipslash = TRUE;
1199 storep = &u->path;
1200 break;
1201 case CURLUPART_QUERY:
1202 plusencode = urlencode;
1203 appendquery = (flags & CURLU_APPENDQUERY)?1:0;
1204 equalsencode = appendquery;
1205 storep = &u->query;
1206 break;
1207 case CURLUPART_FRAGMENT:
1208 storep = &u->fragment;
1209 break;
1210 case CURLUPART_URL: {
1211 /*
1212 * Allow a new URL to replace the existing (if any) contents.
1213 *
1214 * If the existing contents is enough for a URL, allow a relative URL to
1215 * replace it.
1216 */
1217 CURLUcode result;
1218 char *oldurl;
1219 char *redired_url;
1220 CURLU *handle2;
1221
1222 if(Curl_is_absolute_url(part, NULL, MAX_SCHEME_LEN)) {
1223 handle2 = curl_url();
1224 if(!handle2)
1225 return CURLUE_OUT_OF_MEMORY;
1226 result = parseurl(part, handle2, flags);
1227 if(!result)
1228 mv_urlhandle(handle2, u);
1229 else
1230 curl_url_cleanup(handle2);
1231 return result;
1232 }
1233 /* extract the full "old" URL to do the redirect on */
1234 result = curl_url_get(u, CURLUPART_URL, &oldurl, flags);
1235 if(result) {
1236 /* couldn't get the old URL, just use the new! */
1237 handle2 = curl_url();
1238 if(!handle2)
1239 return CURLUE_OUT_OF_MEMORY;
1240 result = parseurl(part, handle2, flags);
1241 if(!result)
1242 mv_urlhandle(handle2, u);
1243 else
1244 curl_url_cleanup(handle2);
1245 return result;
1246 }
1247
1248 /* apply the relative part to create a new URL */
1249 redired_url = concat_url(oldurl, part);
1250 free(oldurl);
1251 if(!redired_url)
1252 return CURLUE_OUT_OF_MEMORY;
1253
1254 /* now parse the new URL */
1255 handle2 = curl_url();
1256 if(!handle2) {
1257 free(redired_url);
1258 return CURLUE_OUT_OF_MEMORY;
1259 }
1260 result = parseurl(redired_url, handle2, flags);
1261 free(redired_url);
1262 if(!result)
1263 mv_urlhandle(handle2, u);
1264 else
1265 curl_url_cleanup(handle2);
1266 return result;
1267 }
1268 default:
1269 return CURLUE_UNKNOWN_PART;
1270 }
1271 if(storep) {
1272 const char *newp = part;
1273 size_t nalloc = strlen(part);
1274
lib/urlapi.clines 232–257 · definition of Curl_is_absolute_url
Show 26 lines (not cited by the judge)
232bool Curl_is_absolute_url(const char *url, char *buf, size_t buflen)
233{
234 size_t i;
235#ifdef WIN32
236 if(STARTS_WITH_DRIVE_PREFIX(url))
237 return FALSE;
238#endif
239 for(i = 0; i < buflen && url[i]; ++i) {
240 char s = url[i];
241 if((s == ':') && (url[i + 1] == '/')) {
242 if(buf)
243 buf[i] = 0;
244 return TRUE;
245 }
246 /* RFC 3986 3.1 explains:
247 scheme = ALPHA *( ALPHA / DIGIT / "+" / "-" / "." )
248 */
249 else if(ISALNUM(s) || (s == '+') || (s == '-') || (s == '.') ) {
250 if(buf)
251 buf[i] = (char)TOLOWER(s);
252 }
253 else
254 break;
255 }
256 return FALSE;
257}
lib/urlapi.clines 896–899 · definition of curl_url
Show 4 lines (not cited by the judge)
896CURLU *curl_url(void)
897{
898 return calloc(sizeof(struct Curl_URL), 1);
899}
lib/urlapi.clines 901–907 · definition of curl_url_cleanup
Show 7 lines (not cited by the judge)
901void curl_url_cleanup(CURLU *u)
902{
903 if(u) {
904 free_urlhandle(u);
905 free(u);
906 }
907}
lib/urlapi.clines 70–82 · definition of free_urlhandle
Show 13 lines (not cited by the judge)
70static void free_urlhandle(struct Curl_URL *u)
71{
72 free(u->scheme);
73 free(u->user);
74 free(u->password);
75 free(u->options);
76 free(u->host);
77 free(u->port);
78 free(u->path);
79 free(u->query);
80 free(u->fragment);
81 free(u->scratch);
82}
lib/urlapi.clines 86–92 · definition of mv_urlhandle
Show 7 lines (not cited by the judge)
86static void mv_urlhandle(struct Curl_URL *from,
87 struct Curl_URL *to)
88{
89 free_urlhandle(to);
90 *to = *from;
91 free(from);
92}