source: mainline/uspace/app/download/main.c@ 6068476

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

Modify HelenOS version variables to use unambiguous names

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