mirror of
https://github.com/rkd77/elinks.git
synced 2024-12-04 14:46:47 -05:00
1008: percent-encode file names in uri.post
In uri.post, each file name begins and ends with FILE_CHAR. Previously, file names were not encoded, and names containing FILE_CHAR could not be used. Because FILE_CHAR is a control character, the user cannot directly type it in a file input field, so ELinks asserted that the field did not contain FILE_CHAR. However, it is possible to get FILE_CHAR in a file input field with file name completion (ACT_EDIT_AUTO_COMPLETE), causing the assertion to fail. Now, ELinks encodes FILE_CHAR as "%02", so it is no longer ambiguous and the assertion is not needed.
This commit is contained in:
parent
50a3244dfb
commit
42123dab87
@ -46,6 +46,8 @@ init_http_post(struct http_post *http_post)
|
||||
void
|
||||
done_http_post(struct http_post *http_post)
|
||||
{
|
||||
size_t i;
|
||||
|
||||
http_post->total_upload_length = 0;
|
||||
http_post->uploaded = 0;
|
||||
http_post->post_data = NULL;
|
||||
@ -53,6 +55,8 @@ done_http_post(struct http_post *http_post)
|
||||
close(http_post->post_fd);
|
||||
http_post->post_fd = -1;
|
||||
}
|
||||
for (i = 0; i < http_post->file_count; i++)
|
||||
mem_free(http_post->files[i].name);
|
||||
http_post->file_index = 0;
|
||||
http_post->file_count = 0;
|
||||
http_post->file_read = 0;
|
||||
@ -98,15 +102,25 @@ open_http_post(struct http_post *http_post, unsigned char *post_data,
|
||||
unsigned char *begin;
|
||||
int res;
|
||||
struct http_post_file *new_files;
|
||||
unsigned char *filename;
|
||||
|
||||
begin = strchr(end, FILE_CHAR);
|
||||
if (!begin) break;
|
||||
end = strchr(begin + 1, FILE_CHAR);
|
||||
if (!end) break;
|
||||
*end = '\0';
|
||||
res = stat(begin + 1, &sb);
|
||||
*end = FILE_CHAR;
|
||||
if (res) break;
|
||||
filename = memacpy(begin + 1, end - begin - 1); /* adds '\0' */
|
||||
if (!filename) {
|
||||
done_http_post(http_post);
|
||||
*error = S_OUT_OF_MEM;
|
||||
return 0;
|
||||
}
|
||||
decode_uri(filename);
|
||||
res = stat(filename, &sb);
|
||||
if (res) {
|
||||
*error = -errno;
|
||||
done_http_post(http_post);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* This use of mem_realloc() in a loop consumes O(n^2)
|
||||
* time but how many files are you really going to
|
||||
@ -115,11 +129,13 @@ open_http_post(struct http_post *http_post, unsigned char *post_data,
|
||||
(http_post->file_count + 1)
|
||||
* sizeof(*new_files));
|
||||
if (new_files == NULL) {
|
||||
mem_free(filename);
|
||||
done_http_post(http_post);
|
||||
*error = S_OUT_OF_MEM;
|
||||
return 0;
|
||||
}
|
||||
http_post->files = new_files;
|
||||
new_files[http_post->file_count].name = filename;
|
||||
new_files[http_post->file_count].size = sb.st_size;
|
||||
http_post->file_count++;
|
||||
|
||||
@ -175,10 +191,9 @@ read_http_post_inline(struct http_post *http_post,
|
||||
http_post->file_read = 0;
|
||||
end = strchr(post + 1, FILE_CHAR);
|
||||
assert(end);
|
||||
*end = '\0';
|
||||
http_post->post_fd = open(post + 1, O_RDONLY);
|
||||
http_post->post_fd = open(http_post->files[http_post->file_index].name,
|
||||
O_RDONLY);
|
||||
/* Be careful not to change errno here. */
|
||||
*end = FILE_CHAR;
|
||||
if (http_post->post_fd < 0) {
|
||||
http_post->post_data = post;
|
||||
if (total > 0)
|
||||
|
@ -10,6 +10,9 @@
|
||||
* open_http_post() collects this information and done_http_post()
|
||||
* discards it. */
|
||||
struct http_post_file {
|
||||
/** The name of the file. Must be freed with mem_free(). */
|
||||
unsigned char *name;
|
||||
|
||||
/** The size of the file. */
|
||||
off_t size;
|
||||
};
|
||||
|
@ -65,8 +65,8 @@ struct uri {
|
||||
*
|
||||
* - file-name is the name of a file that ELinks should send
|
||||
* to the server. It is in the charset accepted by open(),
|
||||
* and not encoded. Therefore, file names that contain
|
||||
* ::FILE_CHAR cannot be used. */
|
||||
* and some characters (especially ::FILE_CHAR) are
|
||||
* percent-encoded. */
|
||||
unsigned char *post;
|
||||
|
||||
/* @protocollen should only be usable if @protocol is either
|
||||
|
@ -878,9 +878,10 @@ add_boundary(struct string *data, struct boundary_info *boundary)
|
||||
* List of values to be sent to the server.
|
||||
* @param[out] data
|
||||
* Append the body here. This is in the same format as uri.post,
|
||||
* except this never has a Content-Type at the beginning, and the
|
||||
* literal parts are not encoded in hexadecimal. Therefore the
|
||||
* result would be ambiguous without @a bfs.
|
||||
* except this never has a Content-Type at the beginning, the
|
||||
* literal parts are not encoded in hexadecimal, and the file names
|
||||
* are not percent-encoded. Therefore the result would be ambiguous
|
||||
* without @a bfs.
|
||||
* @param[out] boundary
|
||||
* A random boundary %string, and a list of offsets where the
|
||||
* boundary was used, so that the caller can in principle change the
|
||||
@ -969,36 +970,11 @@ encode_multipart(struct session *ses, LIST_OF(struct submitted_value) *l,
|
||||
filename = expand_tilde(sv->value);
|
||||
if (!filename) goto encode_error;
|
||||
|
||||
/* Do not allow FILE_CHAR in file
|
||||
* names. It would make the resulting
|
||||
* *data string ambiguous.
|
||||
*
|
||||
* Because FILE_CHAR is a control
|
||||
* character, the user cannot directly
|
||||
* type it in a file upload field.
|
||||
* ELinks also does not let scripts
|
||||
* modify such fields, for security
|
||||
* reasons. It seems impossible to
|
||||
* get FILE_CHAR here, so use assert.
|
||||
*
|
||||
* In uri.post, the first '\n' also
|
||||
* has special meaning. However, '\n'
|
||||
* in a file name does not cause any
|
||||
* ambiguity, because get_form_uri()
|
||||
* always adds a content-type and '\n'
|
||||
* to the beginning of the encoded
|
||||
* POST data. */
|
||||
assert(strchr(filename, FILE_CHAR) == NULL);
|
||||
if_assert_failed {
|
||||
mem_free(filename);
|
||||
errno = EINVAL;
|
||||
goto encode_error;
|
||||
}
|
||||
|
||||
if (access(filename, R_OK)) {
|
||||
mem_free(filename);
|
||||
goto encode_error;
|
||||
}
|
||||
|
||||
bfs_new = mem_calloc(1, sizeof(*bfs_new));
|
||||
if (!bfs_new) {
|
||||
mem_free(filename);
|
||||
@ -1287,7 +1263,14 @@ get_form_uri(struct session *ses, struct document_view *doc_view,
|
||||
ulonghexcat(p, NULL, (int) data.source[i], 2, '0', 0);
|
||||
add_to_string(&go, p);
|
||||
}
|
||||
add_bytes_to_string(&go, data.source + i, b->end - b->begin);
|
||||
assert(i == b->begin);
|
||||
assert(b->end - b->begin >= 2);
|
||||
assert(data.source[b->begin] == FILE_CHAR);
|
||||
assert(data.source[b->end - 1] == FILE_CHAR);
|
||||
add_char_to_string(&go, FILE_CHAR);
|
||||
encode_uri_string(&go, data.source + i + 1,
|
||||
b->end - b->begin - 2, 0);
|
||||
add_char_to_string(&go, FILE_CHAR);
|
||||
i = b->end;
|
||||
}
|
||||
for (; i < data.length; i++) {
|
||||
|
Loading…
Reference in New Issue
Block a user