source: mainline/uspace/app/download/main.c@ 045186b

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 045186b was a35b458, checked in by Jiří Zárevúcky <zarevucky.jiri@…>, 7 years ago

style: Remove trailing whitespace on _all_ lines, including empty ones, for particular file types.

Command used: tools/srepl '\s\+$' '' -- *.c *.h *.py *.sh *.s *.S *.ag

Currently, whitespace on empty lines is very inconsistent.
There are two basic choices: Either remove the whitespace, or keep empty lines
indented to the level of surrounding code. The former is AFAICT more common,
and also much easier to do automatically.

Alternatively, we could write script for automatic indentation, and use that
instead. However, if such a script exists, it's possible to use the indented
style locally, by having the editor apply relevant conversions on load/save,
without affecting remote repository. IMO, it makes more sense to adopt
the simpler rule.

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