mirror of
https://github.com/jart/cosmopolitan.git
synced 2025-01-31 11:37:35 +00:00
150 lines
4.7 KiB
C
150 lines
4.7 KiB
C
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
|
|
│ vi: set et ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi │
|
|
╞══════════════════════════════════════════════════════════════════════════════╡
|
|
│ Copyright 2021 Justine Alexandra Roberts Tunney │
|
|
│ │
|
|
│ Permission to use, copy, modify, and/or distribute this software for │
|
|
│ any purpose with or without fee is hereby granted, provided that the │
|
|
│ above copyright notice and this permission notice appear in all copies. │
|
|
│ │
|
|
│ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │
|
|
│ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │
|
|
│ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │
|
|
│ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │
|
|
│ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │
|
|
│ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │
|
|
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
|
│ PERFORMANCE OF THIS SOFTWARE. │
|
|
╚─────────────────────────────────────────────────────────────────────────────*/
|
|
#include "libc/mem/mem.h"
|
|
#include "libc/str/str.h"
|
|
#include "libc/str/tab.h"
|
|
#include "net/http/escape.h"
|
|
#include "net/http/url.h"
|
|
|
|
static size_t DimensionUrl(struct Url *h) {
|
|
size_t i, n;
|
|
n = 0;
|
|
n += h->scheme.n;
|
|
n += 1;
|
|
n += 2;
|
|
n += h->user.n * 3;
|
|
n += 1;
|
|
n += h->pass.n * 3;
|
|
n += 1;
|
|
n += 1;
|
|
n += h->host.n * 3;
|
|
n += 1;
|
|
n += 1;
|
|
n += h->port.n * 3;
|
|
n += 1;
|
|
n += h->path.n * 3;
|
|
n += 1;
|
|
n += h->params.n;
|
|
for (i = 0; i < h->params.n; ++i) {
|
|
n += h->params.p[i].key.n * 3;
|
|
n += 1;
|
|
n += h->params.p[i].val.n * 3;
|
|
}
|
|
n += 1;
|
|
n += h->fragment.n * 3;
|
|
n += 1;
|
|
return n;
|
|
}
|
|
|
|
static bool NeedsSquareBrackets(struct Url *h) {
|
|
int c;
|
|
size_t i;
|
|
if (!memchr(h->host.p, ':', h->host.n))
|
|
return false;
|
|
if (h->pass.p)
|
|
return true;
|
|
if (h->host.n >= 4 && h->host.p[0] == 'v' && h->host.p[2] == '.' &&
|
|
kHexToInt[h->host.p[1] & 0xFF] != -1) {
|
|
for (i = 3; i < h->host.n; ++i) {
|
|
if (kEscapeIp[h->host.p[i] & 0xFF]) {
|
|
return false;
|
|
}
|
|
}
|
|
} else {
|
|
for (i = 0; i < h->host.n; ++i) {
|
|
c = h->host.p[i] & 0xFF;
|
|
if (!(kHexToInt[c] || c == '.' || c == ':')) {
|
|
return false;
|
|
}
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
|
|
/**
|
|
* Encodes URL.
|
|
*
|
|
* @param z if not null receives string length of result
|
|
* @return nul-terminated url string needing free
|
|
* @see ParseUrl()
|
|
*/
|
|
char *EncodeUrl(struct Url *h, size_t *z) {
|
|
size_t i, n;
|
|
char *m, *p;
|
|
if ((p = m = malloc(DimensionUrl(h)))) {
|
|
if (h->scheme.n) {
|
|
p = mempcpy(p, h->scheme.p, h->scheme.n);
|
|
*p++ = ':';
|
|
}
|
|
if (h->host.p) {
|
|
*p++ = '/';
|
|
*p++ = '/';
|
|
if (h->user.p) {
|
|
p = EscapeUrlView(p, &h->user, kEscapeAuthority);
|
|
if (h->pass.p) {
|
|
*p++ = ':';
|
|
p = EscapeUrlView(p, &h->pass, kEscapeAuthority);
|
|
}
|
|
*p++ = '@';
|
|
}
|
|
if (h->host.p) {
|
|
if (NeedsSquareBrackets(h)) {
|
|
*p++ = '[';
|
|
p = EscapeUrlView(p, &h->host, kEscapeIp);
|
|
*p++ = ']';
|
|
} else {
|
|
p = EscapeUrlView(p, &h->host, kEscapeAuthority);
|
|
}
|
|
if (h->port.p) {
|
|
*p++ = ':';
|
|
p = EscapeUrlView(p, &h->port, kEscapeAuthority);
|
|
}
|
|
}
|
|
if (h->path.n && h->path.p[0] != '/') {
|
|
*p++ = '/';
|
|
}
|
|
}
|
|
p = EscapeUrlView(p, &h->path, kEscapePath);
|
|
if (h->params.p) {
|
|
*p++ = '?';
|
|
for (i = 0; i < h->params.n; ++i) {
|
|
if (i)
|
|
*p++ = '&';
|
|
p = EscapeUrlView(p, &h->params.p[i].key, kEscapeParam);
|
|
if (h->params.p[i].val.p) {
|
|
*p++ = '=';
|
|
p = EscapeUrlView(p, &h->params.p[i].val, kEscapeParam);
|
|
}
|
|
}
|
|
}
|
|
if (h->fragment.p) {
|
|
*p++ = '#';
|
|
p = EscapeUrlView(p, &h->fragment, kEscapeFragment);
|
|
}
|
|
n = p - m;
|
|
*p++ = '\0';
|
|
if ((p = realloc(m, p - m)))
|
|
m = p;
|
|
} else {
|
|
n = 0;
|
|
}
|
|
if (z)
|
|
*z = n;
|
|
return m;
|
|
}
|