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

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since d7b7f5e was d7b7f5e, checked in by Martin Sucha <sucha14@…>, 12 years ago

Add a basic HTTP download tool

  • Property mode set to 100644
File size: 5.5 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 <stdio.h>
39#include <stdlib.h>
40#include <str.h>
41#include <str_error.h>
42#include <task.h>
43#include <macros.h>
44
45#include <net/in.h>
46#include <net/inet.h>
47#include <net/socket.h>
48
49#include <http.h>
50#include <uri.h>
51
52#define NAME "download"
53#ifdef TIMESTAMP_UNIX
54#define VERSION STRING(RELEASE) "-" STRING(TIMESTAMP_UNIX)
55#else
56#define VERSION STRING(RELEASE)
57#endif
58#define USER_AGENT "HelenOS-" NAME "/" VERSION
59
60static void syntax_print(void)
61{
62 fprintf(stderr, "Usage: download <url>\n");
63 fprintf(stderr, " This will write the data to stdout, so you may want\n");
64 fprintf(stderr, " to redirect the output, e.g.\n");
65 fprintf(stderr, "\n");
66 fprintf(stderr, " download http://helenos.org/ | to helenos.html\n\n");
67}
68
69int main(int argc, char *argv[])
70{
71 if (argc != 2) {
72 syntax_print();
73 return 2;
74 }
75
76 uri_t *uri = uri_parse(argv[1]);
77 if (uri == NULL) {
78 fprintf(stderr, "Failed parsing URI\n");
79 return 2;
80 }
81
82 if (!uri_validate(uri)) {
83 fprintf(stderr, "The URI is invalid\n");
84 return 2;
85 }
86
87 /* TODO uri_normalize(uri) */
88
89 if (str_cmp(uri->scheme, "http") != 0) {
90 fprintf(stderr, "Only http scheme is supported at the moment\n");
91 return 2;
92 }
93
94 if (uri->host == NULL) {
95 fprintf(stderr, "host not set\n");
96 return 2;
97 }
98
99 uint16_t port = 80;
100 if (uri->port != NULL) {
101 int rc = str_uint16_t(uri->port, NULL, 10, true, &port);
102 if (rc != EOK) {
103 fprintf(stderr, "Invalid port number: %s\n", uri->port);
104 return 2;
105 }
106 }
107
108 const char *path = uri->path;
109 if (path == NULL || *path == 0)
110 path = "/";
111 char *server_path = NULL;
112 if (uri->query == NULL) {
113 server_path = str_dup(path);
114 if (server_path == NULL) {
115 fprintf(stderr, "Failed allocating path\n");
116 uri_destroy(uri);
117 return 3;
118 }
119 }
120 else {
121 int rc = asprintf(&server_path, "%s?%s", path, uri->query);
122 if (rc < 0) {
123 fprintf(stderr, "Failed allocating path\n");
124 uri_destroy(uri);
125 return 3;
126 }
127 }
128
129 http_request_t *req = http_request_create("GET", server_path);
130 free(server_path);
131 if (req == NULL) {
132 fprintf(stderr, "Failed creating request\n");
133 uri_destroy(uri);
134 free(server_path);
135 return 3;
136 }
137
138 http_header_t *header_host = http_header_create("Host", uri->host);
139 if (header_host == NULL) {
140 fprintf(stderr, "Failed creating Host header\n");
141 uri_destroy(uri);
142 free(server_path);
143 return 3;
144 }
145 list_append(&header_host->link, &req->headers);
146
147 http_header_t *header_ua = http_header_create("User-Agent", USER_AGENT);
148 if (header_ua == NULL) {
149 fprintf(stderr, "Failed creating User-Agent header\n");
150 uri_destroy(uri);
151 free(server_path);
152 return 3;
153 }
154 list_append(&header_ua->link, &req->headers);
155
156 http_t *http = http_create(uri->host, port);
157 if (http == NULL) {
158 uri_destroy(uri);
159 free(server_path);
160 fprintf(stderr, "Failed creating HTTP object\n");
161 return 3;
162 }
163
164 int rc = http_connect(http);
165 if (rc != EOK) {
166 fprintf(stderr, "Failed connecting: %s\n", str_error(rc));
167 uri_destroy(uri);
168 free(server_path);
169 return rc;
170 }
171
172 rc = http_send_request(http, req);
173 if (rc != EOK) {
174 fprintf(stderr, "Failed sending request: %s\n", str_error(rc));
175 uri_destroy(uri);
176 free(server_path);
177 return rc;
178 }
179
180 http_response_t *response = NULL;
181 rc = http_receive_response(http, &response);
182 if (rc != EOK) {
183 fprintf(stderr, "Failed receiving response: %s\n", str_error(rc));
184 uri_destroy(uri);
185 free(server_path);
186 return rc;
187 }
188
189 if (response->status != 200) {
190 fprintf(stderr, "Server returned status %d %s\n", response->status,
191 response->message);
192 }
193 else {
194 size_t buf_size = 4096;
195 void *buf = malloc(buf_size);
196 if (buf == NULL) {
197 fprintf(stderr, "Failed allocating buffer\n)");
198 uri_destroy(uri);
199 free(server_path);
200 return ENOMEM;
201 }
202
203 int body_size;
204 while ((body_size = http_receive_body(http, buf, buf_size)) > 0) {
205 fwrite(buf, 1, body_size, stdout);
206 }
207
208 if (body_size != 0) {
209 fprintf(stderr, "Failed receiving body: %s", str_error(body_size));
210 }
211 }
212
213 uri_destroy(uri);
214 free(server_path);
215 return EOK;
216}
217
218/** @}
219 */
Note: See TracBrowser for help on using the repository browser.