source: mainline/uspace/app/download/main.c@ 1ddbf81

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

Add simple coastline package installer. Add downloader option to save output to file.

  • Property mode set to 100644
File size: 5.9 KB
Line 
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
38#include <errno.h>
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
46#include <http/http.h>
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{
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");
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{
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;
74 int rc;
75
76 if (argc < 2) {
77 syntax_print();
78 rc = EINVAL;
79 goto error;
80 }
81
82 i = 1;
83
84 if (str_cmp(argv[i], "-o") == 0) {
85 ++i;
86 if (argc < i + 1) {
87 syntax_print();
88 rc = EINVAL;
89 goto error;
90 }
91
92 ofname = argv[i++];
93 ofile = fopen(ofname, "wb");
94 if (ofile == NULL) {
95 fprintf(stderr, "Error creating '%s'.\n", ofname);
96 rc = EINVAL;
97 goto error;
98 }
99 }
100
101 if (argc != i + 1) {
102 syntax_print();
103 rc = EINVAL;
104 goto error;
105 }
106
107 uri = uri_parse(argv[i]);
108 if (uri == NULL) {
109 fprintf(stderr, "Failed parsing URI\n");
110 rc = EINVAL;
111 goto error;
112 }
113
114 if (!uri_validate(uri)) {
115 fprintf(stderr, "The URI is invalid\n");
116 rc = EINVAL;
117 goto error;
118 }
119
120 /* TODO uri_normalize(uri) */
121
122 if (str_cmp(uri->scheme, "http") != 0) {
123 fprintf(stderr, "Only http scheme is supported at the moment\n");
124 rc = EINVAL;
125 goto error;
126 }
127
128 if (uri->host == NULL) {
129 fprintf(stderr, "host not set\n");
130 rc = EINVAL;
131 goto error;
132 }
133
134 uint16_t port = 80;
135 if (uri->port != NULL) {
136 rc = str_uint16_t(uri->port, NULL, 10, true, &port);
137 if (rc != EOK) {
138 fprintf(stderr, "Invalid port number: %s\n", uri->port);
139 rc = EINVAL;
140 goto error;
141 }
142 }
143
144 const char *path = uri->path;
145 if (path == NULL || *path == 0)
146 path = "/";
147 char *server_path = NULL;
148 if (uri->query == NULL) {
149 server_path = str_dup(path);
150 if (server_path == NULL) {
151 fprintf(stderr, "Failed allocating path\n");
152 rc = ENOMEM;
153 goto error;
154 }
155 } else {
156 rc = asprintf(&server_path, "%s?%s", path, uri->query);
157 if (rc < 0) {
158 fprintf(stderr, "Failed allocating path\n");
159 rc = ENOMEM;
160 goto error;
161 }
162 }
163
164 http_request_t *req = http_request_create("GET", server_path);
165 free(server_path);
166 if (req == NULL) {
167 fprintf(stderr, "Failed creating request\n");
168 rc = ENOMEM;
169 goto error;
170 }
171
172 rc = http_headers_append(&req->headers, "Host", uri->host);
173 if (rc != EOK) {
174 fprintf(stderr, "Failed setting Host header: %s\n", str_error(rc));
175 goto error;
176 }
177
178 rc = http_headers_append(&req->headers, "User-Agent", USER_AGENT);
179 if (rc != EOK) {
180 fprintf(stderr, "Failed creating User-Agent header: %s\n", str_error(rc));
181 goto error;
182 }
183
184 http_t *http = http_create(uri->host, port);
185 if (http == NULL) {
186 fprintf(stderr, "Failed creating HTTP object\n");
187 rc = ENOMEM;
188 goto error;
189 }
190
191 rc = http_connect(http);
192 if (rc != EOK) {
193 fprintf(stderr, "Failed connecting: %s\n", str_error(rc));
194 rc = EIO;
195 goto error;
196 }
197
198 rc = http_send_request(http, req);
199 if (rc != EOK) {
200 fprintf(stderr, "Failed sending request: %s\n", str_error(rc));
201 rc = EIO;
202 goto error;
203 }
204
205 http_response_t *response = NULL;
206 rc = http_receive_response(&http->recv_buffer, &response, 16 * 1024,
207 100);
208 if (rc != EOK) {
209 fprintf(stderr, "Failed receiving response: %s\n", str_error(rc));
210 rc = EIO;
211 goto error;
212 }
213
214 if (response->status != 200) {
215 fprintf(stderr, "Server returned status %d %s\n", response->status,
216 response->message);
217 } else {
218 buf = malloc(buf_size);
219 if (buf == NULL) {
220 fprintf(stderr, "Failed allocating buffer\n)");
221 rc = ENOMEM;
222 goto error;
223 }
224
225 int body_size;
226 while ((body_size = recv_buffer(&http->recv_buffer, buf, buf_size)) > 0) {
227 fwrite(buf, 1, body_size, ofile != NULL ? ofile : stdout);
228 }
229
230 if (body_size != 0) {
231 fprintf(stderr, "Failed receiving body: %s", str_error(body_size));
232 }
233 }
234
235 free(buf);
236 uri_destroy(uri);
237 if (fclose(ofile) != 0) {
238 printf("Error writing '%s'.\n", ofname);
239 return EIO;
240 }
241
242 return EOK;
243error:
244 free(buf);
245 if (uri != NULL)
246 uri_destroy(uri);
247 if (ofile != NULL)
248 fclose(ofile);
249 return rc;
250}
251
252/** @}
253 */
Note: See TracBrowser for help on using the repository browser.