2 * Copyright (c) 2013 Martin Sucha
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
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.
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.
29 /** @addtogroup download
34 * Download a file from a HTTP server
42 #include <str_error.h>
46 #include <http/http.h>
49 #define NAME "download"
51 #define VERSION STRING(RELEASE) "-" STRING(TIMESTAMP_UNIX)
53 #define VERSION STRING(RELEASE)
55 #define USER_AGENT "HelenOS-" NAME "/" VERSION
57 static void syntax_print(void)
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");
66 int main(int argc
, char *argv
[])
71 size_t buf_size
= 4096;
85 if (str_cmp(argv
[i
], "-o") == 0) {
94 ofile
= fopen(ofname
, "wb");
96 fprintf(stderr
, "Error creating '%s'.\n", ofname
);
108 uri
= uri_parse(argv
[i
]);
110 fprintf(stderr
, "Failed parsing URI\n");
115 if (!uri_validate(uri
)) {
116 fprintf(stderr
, "The URI is invalid\n");
121 /* TODO uri_normalize(uri) */
123 if (str_cmp(uri
->scheme
, "http") != 0) {
124 fprintf(stderr
, "Only http scheme is supported at the moment\n");
129 if (uri
->host
== NULL
) {
130 fprintf(stderr
, "host not set\n");
136 if (uri
->port
!= NULL
) {
137 rc
= str_uint16_t(uri
->port
, NULL
, 10, true, &port
);
139 fprintf(stderr
, "Invalid port number: %s\n", uri
->port
);
145 const char *path
= uri
->path
;
146 if (path
== NULL
|| *path
== 0)
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");
157 rc
= asprintf(&server_path
, "%s?%s", path
, uri
->query
);
159 fprintf(stderr
, "Failed allocating path\n");
165 http_request_t
*req
= http_request_create("GET", server_path
);
168 fprintf(stderr
, "Failed creating request\n");
173 rc
= http_headers_append(&req
->headers
, "Host", uri
->host
);
175 fprintf(stderr
, "Failed setting Host header: %s\n", str_error(rc
));
179 rc
= http_headers_append(&req
->headers
, "User-Agent", USER_AGENT
);
181 fprintf(stderr
, "Failed creating User-Agent header: %s\n", str_error(rc
));
185 http
= http_create(uri
->host
, port
);
187 fprintf(stderr
, "Failed creating HTTP object\n");
192 rc
= http_connect(http
);
194 fprintf(stderr
, "Failed connecting: %s\n", str_error(rc
));
199 rc
= http_send_request(http
, req
);
201 fprintf(stderr
, "Failed sending request: %s\n", str_error(rc
));
206 http_response_t
*response
= NULL
;
207 rc
= http_receive_response(&http
->recv_buffer
, &response
, 16 * 1024,
210 fprintf(stderr
, "Failed receiving response: %s\n", str_error(rc
));
215 if (response
->status
!= 200) {
216 fprintf(stderr
, "Server returned status %d %s\n", response
->status
,
219 buf
= malloc(buf_size
);
221 fprintf(stderr
, "Failed allocating buffer\n)");
227 while ((rc
= recv_buffer(&http
->recv_buffer
, buf
, buf_size
, &body_size
)) == EOK
&& body_size
> 0) {
228 fwrite(buf
, 1, body_size
, ofile
!= NULL
? ofile
: stdout
);
232 fprintf(stderr
, "Failed receiving body: %s", str_error(rc
));
239 if (ofile
!= NULL
&& fclose(ofile
) != 0) {
240 printf("Error writing '%s'.\n", ofname
);