Skip to content

Commit

Permalink
http: use common canonify at request parse time
Browse files Browse the repository at this point in the history
  • Loading branch information
gdamore committed Jan 12, 2025
1 parent 4f44506 commit 169166a
Show file tree
Hide file tree
Showing 5 changed files with 21 additions and 99 deletions.
6 changes: 3 additions & 3 deletions src/core/url.c
Original file line number Diff line number Diff line change
Expand Up @@ -119,8 +119,8 @@ nni_url_decode(uint8_t *out, const char *in, size_t max_len)
return (len);
}

static int
url_canonify_uri(char *out)
int
nni_url_canonify_uri(char *out)
{
size_t src, dst;
uint8_t c;
Expand Down Expand Up @@ -435,7 +435,7 @@ nni_url_parse_inline_inner(nng_url *url, const char *raw)
url->u_hostname[i] = (char) tolower(url->u_hostname[i]);
}

if ((rv = url_canonify_uri(p)) != 0) {
if ((rv = nni_url_canonify_uri(p)) != 0) {
return (rv);
}

Expand Down
1 change: 1 addition & 0 deletions src/core/url.h
Original file line number Diff line number Diff line change
Expand Up @@ -35,5 +35,6 @@ extern int nni_url_to_address(nng_sockaddr *, const nng_url *);
extern int nni_url_parse_inline(nng_url *, const char *);
extern int nni_url_clone_inline(nng_url *, const nng_url *);
extern void nni_url_fini(nng_url *);
extern int nni_url_canonify_uri(char *);

#endif // CORE_URL_H
2 changes: 1 addition & 1 deletion src/supplemental/http/http_conn.c
Original file line number Diff line number Diff line change
Expand Up @@ -1145,7 +1145,7 @@ nni_http_set_content_type(nng_http *conn, const char *ctype)
const char *
nni_http_get_uri(nng_http *conn)
{
return (conn->uri);
return ((conn->uri && conn->uri[0]) ? conn->uri : "/");
}

int
Expand Down
4 changes: 3 additions & 1 deletion src/supplemental/http/http_msg.c
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@

#include "core/list.h"
#include "core/nng_impl.h"
#include "core/url.h"
#include "http_api.h"
#include "http_msg.h"
#include "nng/http.h"
Expand Down Expand Up @@ -231,7 +232,8 @@ http_req_parse_line(nng_http *conn, void *line)
version++;

nni_http_set_method(conn, method);
if (((rv = nni_http_set_uri(conn, uri, NULL)) != 0) ||
if (((rv = nni_url_canonify_uri(uri)) != 0) ||
((rv = nni_http_set_uri(conn, uri, NULL)) != 0) ||
((rv = nni_http_set_version(conn, version)) != 0)) {
return (rv);
}
Expand Down
107 changes: 13 additions & 94 deletions src/supplemental/http/http_server.c
Original file line number Diff line number Diff line change
Expand Up @@ -332,83 +332,6 @@ http_sconn_txdone(void *arg)
}
}

static char
http_hexval(char c)
{
if ((c >= '0') && (c <= '9')) {
return (c - '0');
}
if ((c >= 'a') && (c <= 'f')) {
return ((c - 'a') + 10);
}
if ((c >= 'A') && (c <= 'F')) {
return ((c - 'A') + 10);
}
return (0);
}

// XXX: REPLACE THIS WITH CODE USING THE URL FRAMEWORK.
static char *
http_uri_canonify(char *path)
{
char *tmp;
char *dst;

// Chomp off query string.
if ((tmp = strchr(path, '?')) != NULL) {
*tmp = '\0';
}
// If the URI was absolute, make it relative.
if ((nni_strncasecmp(path, "http://", strlen("http://")) == 0) ||
(nni_strncasecmp(path, "https://", strlen("https://")) == 0)) {
// Skip past the ://
path = strchr(path, ':');
path += 3;

// scan for the end of the host, distinguished by a /
// path delimiter. There might not be one, in which
// case the whole thing is the host and we assume the
// path is just /.
if ((path = strchr(path, '/')) == NULL) {
return ("/");
}
}

// Now we have to unescape things. Unescaping is a shrinking
// operation (strictly), so this is safe. This is just URL
// decode. Note that paths with an embedded NUL are going to be
// treated as though truncated. Don't be that guy that sends
// %00 in a URL.
//
// XXX: Normalizer needs to leave % encoded stuff in there if
// the characters to which they refer are reserved. See RFC 3986
// section 6.2.2.
tmp = path;
dst = path;
while (*tmp != '\0') {
char c;
if ((c = *tmp) != '%') {
*dst++ = c;
tmp++;
continue;
}
if (isxdigit(tmp[1]) && isxdigit(tmp[2])) {
c = http_hexval(tmp[1]);
c *= 16;
c += http_hexval(tmp[2]);
*dst++ = c;
tmp += 3;
} else {
// garbage in, garbage out
*dst++ = c;
tmp++;
}
}
*dst = '\0';

return ((strlen(path) != 0) ? path : "/");
}

static void
http_sconn_error(http_sconn *sc, uint16_t err)
{
Expand Down Expand Up @@ -509,9 +432,7 @@ http_sconn_rxdone(void *arg)
nni_http_handler *head = NULL;
const char *val;
nni_http_req *req = nni_http_conn_req(sc->conn);
char *uri;
size_t urisz;
char *path;
const char *uri;
bool badmeth = false;
bool needhost = false;
const char *host;
Expand Down Expand Up @@ -563,6 +484,15 @@ http_sconn_rxdone(void *arg)
needhost = true;
}

// NB: The URI will already have been canonified by the REQ parser
uri = nni_http_get_uri(sc->conn);
if (uri[0] != '/') {
// We do not support authority form or asterisk form at present
sc->close = true;
http_sconn_error(sc, NNG_HTTP_STATUS_BAD_REQUEST);
return;

Check warning on line 493 in src/supplemental/http/http_server.c

View check run for this annotation

Codecov / codecov/patch

src/supplemental/http/http_server.c#L491-L493

Added lines #L491 - L493 were not covered by tests
}

// If the connection was 1.0, or a connection: close was
// requested, then mark this close on our end.
if ((val = nni_http_get_header(sc->conn, "Connection")) != NULL) {
Expand All @@ -588,20 +518,10 @@ http_sconn_rxdone(void *arg)
}
}

val = nni_http_get_uri(sc->conn);
urisz = strlen(val) + 1;
if ((uri = nni_alloc(urisz)) == NULL) {
http_sconn_close(sc); // out of memory
return;
}
strncpy(uri, val, urisz);
path = http_uri_canonify(uri);

host = nni_http_get_header(sc->conn, "Host");
if ((host == NULL) && (needhost)) {
// Per RFC 2616 14.23 we have to send 400 status here.
http_sconn_error(sc, NNG_HTTP_STATUS_BAD_REQUEST);
nni_free(uri, urisz);
return;
}

Expand All @@ -614,14 +534,14 @@ http_sconn_rxdone(void *arg)
}

len = strlen(h->uri);
if (strncmp(path, h->uri, len) != 0) {
if (strncmp(uri, h->uri, len) != 0) {
continue;
}
switch (path[len]) {
switch (uri[len]) {
case '\0':
break;
case '/':
if ((path[len + 1] != '\0') && (!h->tree)) {
if ((uri[len + 1] != '\0') && (!h->tree)) {
// Trailing component and not a directory.
continue;
}
Expand Down Expand Up @@ -652,7 +572,6 @@ http_sconn_rxdone(void *arg)
if ((h == NULL) && (head != NULL)) {
h = head;
}
nni_free(uri, urisz);
if (h == NULL) {
nni_mtx_unlock(&s->mtx);
if (badmeth) {
Expand Down

0 comments on commit 169166a

Please sign in to comment.