mirror of
https://github.com/emikulic/darkhttpd.git
synced 2023-08-10 21:13:08 +03:00
Adapt make_safe_uri() to work in-place.
We're currently failing some tests.
This commit is contained in:
parent
97ce3cb5d0
commit
4b90b875c6
@ -520,31 +520,38 @@ static void consolidate_slashes(char *s)
|
|||||||
|
|
||||||
|
|
||||||
/* ---------------------------------------------------------------------------
|
/* ---------------------------------------------------------------------------
|
||||||
* Resolve /./ and /../ in a URI, returning a new, safe URI, or NULL if the
|
* Resolve /./ and /../ in a URI, in-place. Returns NULL if the URI is
|
||||||
* URI is invalid/unsafe. Returned buffer needs to be deallocated.
|
* invalid/unsafe, or the original buffer if successful.
|
||||||
*/
|
*/
|
||||||
static char *make_safe_uri(char *uri)
|
static char *make_safe_uri(char *uri)
|
||||||
{
|
{
|
||||||
char **elem, *out;
|
struct {
|
||||||
unsigned int slashes = 0, elements = 0;
|
char *start;
|
||||||
|
size_t len;
|
||||||
|
} *chunks;
|
||||||
|
unsigned int num_slashes, num_chunks;
|
||||||
size_t urilen, i, j, pos;
|
size_t urilen, i, j, pos;
|
||||||
|
int ends_in_slash;
|
||||||
|
|
||||||
assert(uri != NULL);
|
assert(uri != NULL);
|
||||||
if (uri[0] != '/') return NULL;
|
if (uri[0] != '/') return NULL;
|
||||||
consolidate_slashes(uri);
|
consolidate_slashes(uri);
|
||||||
urilen = strlen(uri);
|
urilen = strlen(uri);
|
||||||
|
if (urilen > 0)
|
||||||
|
ends_in_slash = (uri[urilen-1] == '/');
|
||||||
|
else
|
||||||
|
ends_in_slash = 1;
|
||||||
|
|
||||||
/* count the slashes */
|
/* count the slashes */
|
||||||
for (i=0, slashes=0; i<urilen; i++)
|
for (i=0, num_slashes=0; i<urilen; i++)
|
||||||
if (uri[i] == '/') slashes++;
|
if (uri[i] == '/') num_slashes++;
|
||||||
|
|
||||||
/* make an array for the URI elements */
|
/* make an array for the URI elements */
|
||||||
elem = xmalloc(sizeof(char*) * slashes);
|
chunks = xmalloc(sizeof(*chunks) * num_slashes);
|
||||||
for (i=0; i<slashes; i++) elem[i] = NULL;
|
|
||||||
|
|
||||||
/* split by slashes and build elem[] array */
|
/* split by slashes and build chunks array */
|
||||||
for (i=1; i<urilen;)
|
num_chunks = 0;
|
||||||
{
|
for (i=1; i<urilen;) {
|
||||||
/* look for the next slash */
|
/* look for the next slash */
|
||||||
for (j=i; j<urilen && uri[j] != '/'; j++)
|
for (j=i; j<urilen && uri[j] != '/'; j++)
|
||||||
;
|
;
|
||||||
@ -552,53 +559,42 @@ static char *make_safe_uri(char *uri)
|
|||||||
/* process uri[i,j) */
|
/* process uri[i,j) */
|
||||||
if ((j == i+1) && (uri[i] == '.'))
|
if ((j == i+1) && (uri[i] == '.'))
|
||||||
/* "." */;
|
/* "." */;
|
||||||
else if ((j == i+2) && (uri[i] == '.') && (uri[i+1] == '.'))
|
else if ((j == i+2) && (uri[i] == '.') && (uri[i+1] == '.')) {
|
||||||
{
|
|
||||||
/* ".." */
|
/* ".." */
|
||||||
if (elements == 0)
|
if (num_chunks == 0) {
|
||||||
{
|
/* unsafe string so free chunks */
|
||||||
/* unsafe string so free elem[]; all its elements are free at
|
free(chunks);
|
||||||
* this point.
|
return (NULL);
|
||||||
*/
|
} else
|
||||||
free(elem);
|
num_chunks--;
|
||||||
return NULL;
|
} else {
|
||||||
}
|
chunks[num_chunks].start = uri+i;
|
||||||
else
|
chunks[num_chunks].len = j-i;
|
||||||
{
|
num_chunks++;
|
||||||
elements--;
|
|
||||||
free(elem[elements]);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else elem[elements++] = split_string(uri, i, j);
|
|
||||||
|
|
||||||
i = j + 1; /* uri[j] is a slash - move along one */
|
i = j + 1; /* uri[j] is a slash - move along one */
|
||||||
}
|
}
|
||||||
|
|
||||||
/* reassemble */
|
/* reassemble in-place */
|
||||||
out = xmalloc(urilen+1); /* it won't expand */
|
|
||||||
pos = 0;
|
pos = 0;
|
||||||
for (i=0; i<elements; i++)
|
for (i=0; i<num_chunks; i++) {
|
||||||
{
|
|
||||||
size_t delta = strlen(elem[i]);
|
|
||||||
|
|
||||||
assert(pos <= urilen);
|
assert(pos <= urilen);
|
||||||
out[pos++] = '/';
|
uri[pos++] = '/';
|
||||||
|
|
||||||
assert(pos+delta <= urilen);
|
assert(pos + chunks[i].len <= urilen);
|
||||||
memcpy(out+pos, elem[i], delta);
|
assert(uri + pos <= chunks[i].start);
|
||||||
free(elem[i]);
|
|
||||||
pos += delta;
|
if (uri+pos < chunks[i].start)
|
||||||
|
memmove(uri+pos, chunks[i].start, chunks[i].len);
|
||||||
|
pos += chunks[i].len;
|
||||||
}
|
}
|
||||||
free(elem);
|
free(chunks);
|
||||||
|
|
||||||
if ((elements == 0) || (uri[urilen-1] == '/')) out[pos++] = '/';
|
if (ends_in_slash) uri[pos++] = '/';
|
||||||
assert(pos <= urilen);
|
assert(pos <= urilen);
|
||||||
out[pos] = '\0';
|
uri[pos] = '\0';
|
||||||
|
return uri;
|
||||||
/* shorten buffer if necessary */
|
|
||||||
if (pos != urilen) out = xrealloc(out, strlen(out)+1);
|
|
||||||
|
|
||||||
return out;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -1761,7 +1757,7 @@ static void generate_dir_listing(struct connection *conn, const char *path)
|
|||||||
*/
|
*/
|
||||||
static void process_get(struct connection *conn)
|
static void process_get(struct connection *conn)
|
||||||
{
|
{
|
||||||
char *decoded_url, *safe_url, *target, *if_mod_since;
|
char *decoded_url, *target, *if_mod_since;
|
||||||
char date[DATE_LEN], lastmod[DATE_LEN];
|
char date[DATE_LEN], lastmod[DATE_LEN];
|
||||||
const char *mimetype = NULL;
|
const char *mimetype = NULL;
|
||||||
struct stat filestat;
|
struct stat filestat;
|
||||||
@ -1770,36 +1766,33 @@ static void process_get(struct connection *conn)
|
|||||||
decoded_url = urldecode(conn->uri);
|
decoded_url = urldecode(conn->uri);
|
||||||
|
|
||||||
/* make sure it's safe */
|
/* make sure it's safe */
|
||||||
safe_url = make_safe_uri(decoded_url);
|
if (make_safe_uri(decoded_url) == NULL) {
|
||||||
free(decoded_url);
|
|
||||||
if (safe_url == NULL)
|
|
||||||
{
|
|
||||||
default_reply(conn, 400, "Bad Request",
|
default_reply(conn, 400, "Bad Request",
|
||||||
"You requested an invalid URI: %s", conn->uri);
|
"You requested an invalid URI: %s", conn->uri);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* does it end in a slash? serve up url/index_name */
|
/* does it end in a slash? serve up url/index_name */
|
||||||
if (safe_url[strlen(safe_url)-1] == '/')
|
if (decoded_url[strlen(decoded_url)-1] == '/')
|
||||||
{
|
{
|
||||||
xasprintf(&target, "%s%s%s", wwwroot, safe_url, index_name);
|
xasprintf(&target, "%s%s%s", wwwroot, decoded_url, index_name);
|
||||||
if (!file_exists(target))
|
if (!file_exists(target))
|
||||||
{
|
{
|
||||||
free(target);
|
free(target);
|
||||||
xasprintf(&target, "%s%s", wwwroot, safe_url);
|
xasprintf(&target, "%s%s", wwwroot, decoded_url);
|
||||||
generate_dir_listing(conn, target);
|
generate_dir_listing(conn, target);
|
||||||
free(target);
|
free(target);
|
||||||
free(safe_url);
|
free(decoded_url);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
mimetype = uri_content_type(index_name);
|
mimetype = uri_content_type(index_name);
|
||||||
}
|
}
|
||||||
else /* points to a file */
|
else /* points to a file */
|
||||||
{
|
{
|
||||||
xasprintf(&target, "%s%s", wwwroot, safe_url);
|
xasprintf(&target, "%s%s", wwwroot, decoded_url);
|
||||||
mimetype = uri_content_type(safe_url);
|
mimetype = uri_content_type(decoded_url);
|
||||||
}
|
}
|
||||||
free(safe_url);
|
free(decoded_url);
|
||||||
if (debug) printf("uri=%s, target=%s, content-type=%s\n",
|
if (debug) printf("uri=%s, target=%s, content-type=%s\n",
|
||||||
conn->uri, target, mimetype);
|
conn->uri, target, mimetype);
|
||||||
|
|
||||||
@ -2076,7 +2069,7 @@ static void poll_send_header(struct connection *conn)
|
|||||||
|
|
||||||
/* ---------------------------------------------------------------------------
|
/* ---------------------------------------------------------------------------
|
||||||
* Send chunk on socket <s> from FILE *fp, starting at <ofs> and of size
|
* Send chunk on socket <s> from FILE *fp, starting at <ofs> and of size
|
||||||
* <size>. Use sendfile() is possible since it's zero-copy on some platforms.
|
* <size>. Use sendfile() if possible since it's zero-copy on some platforms.
|
||||||
* Returns the number of bytes sent, 0 on closure, -1 if send() failed, -2 if
|
* Returns the number of bytes sent, 0 on closure, -1 if send() failed, -2 if
|
||||||
* read error.
|
* read error.
|
||||||
*/
|
*/
|
||||||
|
Loading…
Reference in New Issue
Block a user