1
0
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:
Kalle Olavi Niemitalo 2008-07-11 14:15:32 +03:00 committed by Kalle Olavi Niemitalo
parent 50a3244dfb
commit 42123dab87
4 changed files with 40 additions and 39 deletions

View File

@ -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)

View File

@ -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;
};

View File

@ -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

View File

@ -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++) {