source: mainline/uspace/app/download/main.c@ 887c9de

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 887c9de was 9713b0b, checked in by Jiri Svoboda <jiri@…>, 8 years ago

Fix downloader null pointer dereference when writing to stdout.

  • Property mode set to 100644
File size: 6.0 KB
RevLine 
[d7b7f5e]1/*
2 * Copyright (c) 2013 Martin Sucha
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 *
9 * - Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * - Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * - The name of the author may not be used to endorse or promote products
15 * derived from this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28
29/** @addtogroup download
30 * @{
31 */
32
33/** @file
34 * Download a file from a HTTP server
35 *
36 */
37
[fab2746]38#include <errno.h>
[d7b7f5e]39#include <stdio.h>
40#include <stdlib.h>
41#include <str.h>
42#include <str_error.h>
43#include <task.h>
44#include <macros.h>
45
[b623b68]46#include <http/http.h>
[d7b7f5e]47#include <uri.h>
48
49#define NAME "download"
50#ifdef TIMESTAMP_UNIX
51#define VERSION STRING(RELEASE) "-" STRING(TIMESTAMP_UNIX)
52#else
53#define VERSION STRING(RELEASE)
54#endif
55#define USER_AGENT "HelenOS-" NAME "/" VERSION
56
57static void syntax_print(void)
58{
[9621c7d]59 fprintf(stderr, "Usage: download [-o <outfile>] <url>\n");
60 fprintf(stderr, " Without -o, data will be written to stdout, so you may want\n");
[d7b7f5e]61 fprintf(stderr, " to redirect the output, e.g.\n");
62 fprintf(stderr, "\n");
63 fprintf(stderr, " download http://helenos.org/ | to helenos.html\n\n");
64}
65
66int main(int argc, char *argv[])
67{
[9621c7d]68 int i;
69 char *ofname = NULL;
70 FILE *ofile = NULL;
71 size_t buf_size = 4096;
72 void *buf = NULL;
73 uri_t *uri = NULL;
[fc3d4fd5]74 http_t *http = NULL;
[9621c7d]75 int rc;
76
77 if (argc < 2) {
[d7b7f5e]78 syntax_print();
[9621c7d]79 rc = EINVAL;
80 goto error;
[d7b7f5e]81 }
82
[9621c7d]83 i = 1;
84
85 if (str_cmp(argv[i], "-o") == 0) {
86 ++i;
87 if (argc < i + 1) {
88 syntax_print();
89 rc = EINVAL;
90 goto error;
91 }
92
93 ofname = argv[i++];
94 ofile = fopen(ofname, "wb");
95 if (ofile == NULL) {
96 fprintf(stderr, "Error creating '%s'.\n", ofname);
97 rc = EINVAL;
98 goto error;
99 }
100 }
101
102 if (argc != i + 1) {
103 syntax_print();
104 rc = EINVAL;
105 goto error;
106 }
107
108 uri = uri_parse(argv[i]);
[d7b7f5e]109 if (uri == NULL) {
110 fprintf(stderr, "Failed parsing URI\n");
[9621c7d]111 rc = EINVAL;
112 goto error;
[d7b7f5e]113 }
114
115 if (!uri_validate(uri)) {
116 fprintf(stderr, "The URI is invalid\n");
[9621c7d]117 rc = EINVAL;
118 goto error;
[d7b7f5e]119 }
120
121 /* TODO uri_normalize(uri) */
122
123 if (str_cmp(uri->scheme, "http") != 0) {
124 fprintf(stderr, "Only http scheme is supported at the moment\n");
[9621c7d]125 rc = EINVAL;
126 goto error;
[d7b7f5e]127 }
128
129 if (uri->host == NULL) {
130 fprintf(stderr, "host not set\n");
[9621c7d]131 rc = EINVAL;
132 goto error;
[d7b7f5e]133 }
134
135 uint16_t port = 80;
136 if (uri->port != NULL) {
[9621c7d]137 rc = str_uint16_t(uri->port, NULL, 10, true, &port);
[d7b7f5e]138 if (rc != EOK) {
139 fprintf(stderr, "Invalid port number: %s\n", uri->port);
[9621c7d]140 rc = EINVAL;
141 goto error;
[d7b7f5e]142 }
143 }
144
145 const char *path = uri->path;
146 if (path == NULL || *path == 0)
147 path = "/";
148 char *server_path = NULL;
149 if (uri->query == NULL) {
150 server_path = str_dup(path);
151 if (server_path == NULL) {
152 fprintf(stderr, "Failed allocating path\n");
[9621c7d]153 rc = ENOMEM;
154 goto error;
[d7b7f5e]155 }
[9621c7d]156 } else {
157 rc = asprintf(&server_path, "%s?%s", path, uri->query);
[d7b7f5e]158 if (rc < 0) {
159 fprintf(stderr, "Failed allocating path\n");
[9621c7d]160 rc = ENOMEM;
161 goto error;
[d7b7f5e]162 }
163 }
164
165 http_request_t *req = http_request_create("GET", server_path);
166 free(server_path);
167 if (req == NULL) {
168 fprintf(stderr, "Failed creating request\n");
[9621c7d]169 rc = ENOMEM;
170 goto error;
[d7b7f5e]171 }
172
[9621c7d]173 rc = http_headers_append(&req->headers, "Host", uri->host);
[4d4f656]174 if (rc != EOK) {
175 fprintf(stderr, "Failed setting Host header: %s\n", str_error(rc));
[9621c7d]176 goto error;
[d7b7f5e]177 }
178
[4d4f656]179 rc = http_headers_append(&req->headers, "User-Agent", USER_AGENT);
180 if (rc != EOK) {
181 fprintf(stderr, "Failed creating User-Agent header: %s\n", str_error(rc));
[9621c7d]182 goto error;
[d7b7f5e]183 }
184
[fc3d4fd5]185 http = http_create(uri->host, port);
[d7b7f5e]186 if (http == NULL) {
187 fprintf(stderr, "Failed creating HTTP object\n");
[9621c7d]188 rc = ENOMEM;
189 goto error;
[d7b7f5e]190 }
191
[4d4f656]192 rc = http_connect(http);
[d7b7f5e]193 if (rc != EOK) {
194 fprintf(stderr, "Failed connecting: %s\n", str_error(rc));
[9621c7d]195 rc = EIO;
196 goto error;
[d7b7f5e]197 }
198
199 rc = http_send_request(http, req);
200 if (rc != EOK) {
201 fprintf(stderr, "Failed sending request: %s\n", str_error(rc));
[9621c7d]202 rc = EIO;
203 goto error;
[d7b7f5e]204 }
205
206 http_response_t *response = NULL;
[cbfc8b7]207 rc = http_receive_response(&http->recv_buffer, &response, 16 * 1024,
208 100);
[d7b7f5e]209 if (rc != EOK) {
210 fprintf(stderr, "Failed receiving response: %s\n", str_error(rc));
[9621c7d]211 rc = EIO;
212 goto error;
[d7b7f5e]213 }
214
215 if (response->status != 200) {
216 fprintf(stderr, "Server returned status %d %s\n", response->status,
217 response->message);
[9621c7d]218 } else {
219 buf = malloc(buf_size);
[d7b7f5e]220 if (buf == NULL) {
221 fprintf(stderr, "Failed allocating buffer\n)");
[9621c7d]222 rc = ENOMEM;
223 goto error;
[d7b7f5e]224 }
225
226 int body_size;
[408424e]227 while ((body_size = recv_buffer(&http->recv_buffer, buf, buf_size)) > 0) {
[9621c7d]228 fwrite(buf, 1, body_size, ofile != NULL ? ofile : stdout);
[d7b7f5e]229 }
230
231 if (body_size != 0) {
232 fprintf(stderr, "Failed receiving body: %s", str_error(body_size));
233 }
234 }
235
[9621c7d]236 free(buf);
[fc3d4fd5]237 http_destroy(http);
[d7b7f5e]238 uri_destroy(uri);
[9713b0b]239 if (ofile != NULL && fclose(ofile) != 0) {
[9621c7d]240 printf("Error writing '%s'.\n", ofname);
241 return EIO;
242 }
243
[d7b7f5e]244 return EOK;
[9621c7d]245error:
246 free(buf);
[fc3d4fd5]247 if (http != NULL)
248 http_destroy(http);
[9621c7d]249 if (uri != NULL)
250 uri_destroy(uri);
251 if (ofile != NULL)
252 fclose(ofile);
253 return rc;
[d7b7f5e]254}
255
256/** @}
257 */
Note: See TracBrowser for help on using the repository browser.