upload.c (3253B)
1 /*
2 * Copyright (c) 2016-2018 Joris Vink <joris@coders.se>
3 *
4 * Permission to use, copy, modify, and distribute this software for any
5 * purpose with or without fee is hereby granted, provided that the above
6 * copyright notice and this permission notice appear in all copies.
7 *
8 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
15 */
16
17 /*
18 * This example demonstrates how to properly deal with file uploads
19 * coming from a multipart form.
20 *
21 * The basics are quite trivial:
22 * 1) call http_populate_multipart_form()
23 * 2) find the file using http_file_lookup().
24 * 3) read the file data using http_file_read().
25 *
26 * In this example the contents is written to a newly created file
27 * on the server that matches the naming given by the uploader.
28 *
29 * Note that the above is probably not what you want to do in real life.
30 */
31
32 #include <kore/kore.h>
33 #include <kore/http.h>
34
35 #include <fcntl.h>
36 #include <unistd.h>
37
38 int page(struct http_request *);
39
40 int
41 page(struct http_request *req)
42 {
43 int fd;
44 struct http_file *file;
45 u_int8_t buf[BUFSIZ];
46 ssize_t ret, written;
47
48 /* Only deal with POSTs. */
49 if (req->method != HTTP_METHOD_POST) {
50 http_response(req, 405, NULL, 0);
51 return (KORE_RESULT_OK);
52 }
53
54 /* Parse the multipart data that was present. */
55 http_populate_multipart_form(req);
56
57 /* Find our file. */
58 if ((file = http_file_lookup(req, "file")) == NULL) {
59 http_response(req, 400, NULL, 0);
60 return (KORE_RESULT_OK);
61 }
62
63 /* Open dump file where we will write file contents. */
64 fd = open(file->filename, O_CREAT | O_TRUNC | O_WRONLY, 0700);
65 if (fd == -1) {
66 http_response(req, 500, NULL, 0);
67 return (KORE_RESULT_OK);
68 }
69
70 /* While we have data from http_file_read(), write it. */
71 /* Alternatively you could look at file->offset and file->length. */
72 ret = KORE_RESULT_ERROR;
73 for (;;) {
74 ret = http_file_read(file, buf, sizeof(buf));
75 if (ret == -1) {
76 kore_log(LOG_ERR, "failed to read from file");
77 http_response(req, 500, NULL, 0);
78 goto cleanup;
79 }
80
81 if (ret == 0)
82 break;
83
84 written = write(fd, buf, ret);
85 if (written == -1) {
86 kore_log(LOG_ERR,"write(%s): %s",
87 file->filename, errno_s);
88 http_response(req, 500, NULL, 0);
89 goto cleanup;
90 }
91
92 if (written != ret) {
93 kore_log(LOG_ERR, "partial write on %s",
94 file->filename);
95 http_response(req, 500, NULL, 0);
96 goto cleanup;
97 }
98 }
99
100 ret = KORE_RESULT_OK;
101 http_response(req, 200, NULL, 0);
102 kore_log(LOG_INFO, "file '%s' successfully received",
103 file->filename);
104
105 cleanup:
106 if (close(fd) == -1)
107 kore_log(LOG_WARNING, "close(%s): %s", file->filename, errno_s);
108
109 if (ret == KORE_RESULT_ERROR) {
110 if (unlink(file->filename) == -1) {
111 kore_log(LOG_WARNING, "unlink(%s): %s",
112 file->filename, errno_s);
113 }
114 ret = KORE_RESULT_OK;
115 }
116
117 return (KORE_RESULT_OK);
118 }