257
257
if(*q == ':') { /* port specified */
259
259
const char *cc, *pp = q + strcspn(q, "/?#\1");
260
n = strtol(q + 1, (char **)&cc, 10);
261
if(cc != pp || !isdigitByte(q[1])) {
262
setError(MSG_BadPort);
261
n = strtol(q + 1, (char **)&cc, 10);
262
if(cc != pp || !isdigitByte(q[1])) {
263
setError(MSG_BadPort);
269
271
q = pp; /* up to the slash */
502
504
return ((url[0] | 0x20) == 'p');
508
* hasPrefix: return true if s has a prefix of p, false otherwise.
511
hasPrefix(char *s, char *p)
515
ret = true; /* Empty string is a prefix of all strings. */
517
size_t slen = strlen(s);
518
size_t plen = strlen(p);
519
ret = (plen <= slen) && !strncmp(p, s, plen);
525
* copyPathSegment: copy everything from *src, starting with the leftmost
526
* character (a slash), and ending with either the next slash (not included)
527
* or the end of the string.
528
* Advance *src to point to the character succeeding the copied text.
531
copyPathSegment(char **src, char **dest, int *destlen)
533
int spanlen = strcspn(*src + 1, "/") + 1;
534
stringAndBytes(dest, destlen, *src, spanlen);
535
*src = *src + spanlen;
536
} /* copyPathSegment */
539
* Remove the rightmost component of a path,
540
* including the preceding slash, if any.
543
snipLastSegment(char **path, int *pathLen)
545
char *rightmostSlash = strrchr(*path, '/');
546
if(rightmostSlash == NULL)
547
rightmostSlash = *path;
548
*rightmostSlash = '\0';
549
*pathLen = rightmostSlash - *path;
550
} /* snipLastSegment */
506
553
squashDirectories(char *url)
508
555
char *dd = (char *)getDataURL(url);
509
556
char *s, *t, *end;
559
size_t outPathLen = 0;
562
outPath = initString(&outPathLen);
510
563
if(memEqualCI(url, "javascript:", 11))
512
565
if(!dd || dd == url)
520
573
i_printfExit(MSG_BadSlash, url);
521
574
end = dd + strcspn(dd, "?#\1");
523
s = strstr(dd, "/./");
528
s = strstr(dd, "/../");
537
for(t = s - 1; *t != '/'; --t) ;
575
rest = cloneString(end);
576
inPath = pullString1(dd, end);
579
/* The following algorithm is straight out of RFC 3986, section 5.2.4. */
580
/* We can ignore several steps because of a loop invariant: */
581
/* After the test, *s is always a slash. */
583
if(hasPrefix(s, "/./"))
584
s += 2; /* Point s at 2nd slash */
585
else if(!strcmp(s, "/.")) {
587
/* We'll copy the segment "/" on the next iteration. */
588
/* And that will be the final iteration of the loop. */
589
} else if(hasPrefix(s, "/../")) {
590
s += 3; /* Point s at 2nd slash */
591
snipLastSegment(&outPath, &outPathLen);
592
} else if(!strcmp(s, "/..")) {
594
snipLastSegment(&outPath, &outPathLen);
595
/* As above, copy "/" on the next and final iteration. */
597
copyPathSegment(&s, &outPath, &outPathLen);
600
strcat(url, outPath);
541
605
} /* squashDirectories */