http: K&R formatting cosmetics
[ffmpeg.git] / libavformat / http.c
1 /*
2  * HTTP protocol for avconv client
3  * Copyright (c) 2000, 2001 Fabrice Bellard
4  *
5  * This file is part of Libav.
6  *
7  * Libav is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Lesser General Public
9  * License as published by the Free Software Foundation; either
10  * version 2.1 of the License, or (at your option) any later version.
11  *
12  * Libav is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * Lesser General Public License for more details.
16  *
17  * You should have received a copy of the GNU Lesser General Public
18  * License along with Libav; if not, write to the Free Software
19  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
20  */
21
22 #include "config.h"
23
24 #if CONFIG_ZLIB
25 #include <zlib.h>
26 #endif /* CONFIG_ZLIB */
27
28 #include "libavutil/avstring.h"
29 #include "libavutil/opt.h"
30
31 #include "avformat.h"
32 #include "http.h"
33 #include "httpauth.h"
34 #include "internal.h"
35 #include "network.h"
36 #include "os_support.h"
37 #include "url.h"
38
39 /* XXX: POST protocol is not completely implemented because avconv uses
40  * only a subset of it. */
41
42 /* The IO buffer size is unrelated to the max URL size in itself, but needs
43  * to be large enough to fit the full request headers (including long
44  * path names). */
45 #define BUFFER_SIZE   MAX_URL_SIZE
46 #define MAX_REDIRECTS 8
47
48 typedef struct {
49     const AVClass *class;
50     URLContext *hd;
51     unsigned char buffer[BUFFER_SIZE], *buf_ptr, *buf_end;
52     int line_count;
53     int http_code;
54     /* Used if "Transfer-Encoding: chunked" otherwise -1. */
55     int64_t chunksize;
56     int64_t off, end_off, filesize;
57     char *location;
58     HTTPAuthState auth_state;
59     HTTPAuthState proxy_auth_state;
60     char *headers;
61     char *mime_type;
62     char *user_agent;
63     char *content_type;
64     /* Set if the server correctly handles Connection: close and will close
65      * the connection after feeding us the content. */
66     int willclose;
67     int chunked_post;
68     /* A flag which indicates if the end of chunked encoding has been sent. */
69     int end_chunked_post;
70     /* A flag which indicates we have finished to read POST reply. */
71     int end_header;
72     /* A flag which indicates if we use persistent connections. */
73     int multiple_requests;
74     uint8_t *post_data;
75     int post_datalen;
76     int icy;
77     /* how much data was read since the last ICY metadata packet */
78     int icy_data_read;
79     /* after how many bytes of read data a new metadata packet will be found */
80     int icy_metaint;
81     char *icy_metadata_headers;
82     char *icy_metadata_packet;
83 #if CONFIG_ZLIB
84     int compressed;
85     z_stream inflate_stream;
86     uint8_t *inflate_buffer;
87 #endif /* CONFIG_ZLIB */
88     AVDictionary *chained_options;
89     int send_expect_100;
90     char *method;
91 } HTTPContext;
92
93 #define OFFSET(x) offsetof(HTTPContext, x)
94 #define D AV_OPT_FLAG_DECODING_PARAM
95 #define E AV_OPT_FLAG_ENCODING_PARAM
96 #define DEFAULT_USER_AGENT "Lavf/" AV_STRINGIFY(LIBAVFORMAT_VERSION)
97
98 static const AVOption options[] = {
99     { "chunked_post", "use chunked transfer-encoding for posts", OFFSET(chunked_post), AV_OPT_TYPE_INT, { .i64 = 1 }, 0, 1, E },
100     { "headers", "set custom HTTP headers, can override built in default headers", OFFSET(headers), AV_OPT_TYPE_STRING, { 0 }, 0, 0, D | E },
101     { "content_type", "set a specific content type for the POST messages", OFFSET(content_type), AV_OPT_TYPE_STRING, { 0 }, 0, 0, D | E },
102     { "user_agent", "override User-Agent header", OFFSET(user_agent), AV_OPT_TYPE_STRING, { .str = DEFAULT_USER_AGENT }, 0, 0, D },
103     { "user-agent", "override User-Agent header, for compatibility with ffmpeg", OFFSET(user_agent), AV_OPT_TYPE_STRING, { .str = DEFAULT_USER_AGENT }, 0, 0, D },
104     { "multiple_requests", "use persistent connections", OFFSET(multiple_requests), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, 1, D | E },
105     { "post_data", "set custom HTTP post data", OFFSET(post_data), AV_OPT_TYPE_BINARY, .flags = D | E },
106     { "mime_type", "export the MIME type", OFFSET(mime_type), AV_OPT_TYPE_STRING, { 0 }, 0, 0, AV_OPT_FLAG_EXPORT | AV_OPT_FLAG_READONLY },
107     { "icy", "request ICY metadata", OFFSET(icy), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, 1, D },
108     { "icy_metadata_headers", "return ICY metadata headers", OFFSET(icy_metadata_headers), AV_OPT_TYPE_STRING, { 0 }, 0, 0, AV_OPT_FLAG_EXPORT },
109     { "icy_metadata_packet", "return current ICY metadata packet", OFFSET(icy_metadata_packet), AV_OPT_TYPE_STRING, { 0 }, 0, 0, AV_OPT_FLAG_EXPORT },
110     { "auth_type", "HTTP authentication type", OFFSET(auth_state.auth_type), AV_OPT_TYPE_INT, { .i64 = HTTP_AUTH_NONE }, HTTP_AUTH_NONE, HTTP_AUTH_BASIC, D | E, "auth_type"},
111     { "none", "No auth method set, autodetect", 0, AV_OPT_TYPE_CONST, { .i64 = HTTP_AUTH_NONE }, 0, 0, D | E, "auth_type"},
112     { "basic", "HTTP basic authentication", 0, AV_OPT_TYPE_CONST, { .i64 = HTTP_AUTH_BASIC }, 0, 0, D | E, "auth_type"},
113     { "send_expect_100", "Force sending an Expect: 100-continue header for POST", OFFSET(send_expect_100), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, 1, E },
114     { "location", "The actual location of the data received", OFFSET(location), AV_OPT_TYPE_STRING, { 0 }, 0, 0, D | E },
115     { "offset", "initial byte offset", OFFSET(off), AV_OPT_TYPE_INT64, { .i64 = 0 }, 0, INT64_MAX, D },
116     { "end_offset", "try to limit the request to bytes preceding this offset", OFFSET(end_off), AV_OPT_TYPE_INT64, { .i64 = 0 }, 0, INT64_MAX, D },
117     { "method", "Override the HTTP method", OFFSET(method), AV_OPT_TYPE_STRING, { .str = NULL }, 0, 0, E },
118     { NULL }
119 };
120
121 static int http_connect(URLContext *h, const char *path, const char *local_path,
122                         const char *hoststr, const char *auth,
123                         const char *proxyauth, int *new_location);
124
125 void ff_http_init_auth_state(URLContext *dest, const URLContext *src)
126 {
127     memcpy(&((HTTPContext *)dest->priv_data)->auth_state,
128            &((HTTPContext *)src->priv_data)->auth_state,
129            sizeof(HTTPAuthState));
130     memcpy(&((HTTPContext *)dest->priv_data)->proxy_auth_state,
131            &((HTTPContext *)src->priv_data)->proxy_auth_state,
132            sizeof(HTTPAuthState));
133 }
134
135 /* return non zero if error */
136 static int http_open_cnx(URLContext *h, AVDictionary **options)
137 {
138     const char *path, *proxy_path, *lower_proto = "tcp", *local_path;
139     char hostname[1024], hoststr[1024], proto[10];
140     char auth[1024], proxyauth[1024] = "";
141     char path1[MAX_URL_SIZE];
142     char buf[1024], urlbuf[MAX_URL_SIZE];
143     int port, use_proxy, err, location_changed = 0, redirects = 0, attempts = 0;
144     HTTPAuthType cur_auth_type, cur_proxy_auth_type;
145     HTTPContext *s = h->priv_data;
146
147     /* fill the dest addr */
148 redo:
149     /* needed in any case to build the host string */
150     av_url_split(proto, sizeof(proto), auth, sizeof(auth),
151                  hostname, sizeof(hostname), &port,
152                  path1, sizeof(path1), s->location);
153     ff_url_join(hoststr, sizeof(hoststr), NULL, NULL, hostname, port, NULL);
154
155     proxy_path = getenv("http_proxy");
156     use_proxy  = !ff_http_match_no_proxy(getenv("no_proxy"), hostname) &&
157                  proxy_path != NULL && av_strstart(proxy_path, "http://", NULL);
158
159     if (!strcmp(proto, "https")) {
160         lower_proto = "tls";
161         use_proxy   = 0;
162         if (port < 0)
163             port = 443;
164     }
165     if (port < 0)
166         port = 80;
167
168     if (path1[0] == '\0')
169         path = "/";
170     else
171         path = path1;
172     local_path = path;
173     if (use_proxy) {
174         /* Reassemble the request URL without auth string - we don't
175          * want to leak the auth to the proxy. */
176         ff_url_join(urlbuf, sizeof(urlbuf), proto, NULL, hostname, port, "%s",
177                     path1);
178         path = urlbuf;
179         av_url_split(NULL, 0, proxyauth, sizeof(proxyauth),
180                      hostname, sizeof(hostname), &port, NULL, 0, proxy_path);
181     }
182
183     ff_url_join(buf, sizeof(buf), lower_proto, NULL, hostname, port, NULL);
184
185     if (!s->hd) {
186         err = ffurl_open(&s->hd, buf, AVIO_FLAG_READ_WRITE,
187                          &h->interrupt_callback, options);
188         if (err < 0)
189             goto fail;
190     }
191
192     cur_auth_type       = s->auth_state.auth_type;
193     cur_proxy_auth_type = s->auth_state.auth_type;
194     if (http_connect(h, path, local_path, hoststr,
195                      auth, proxyauth, &location_changed) < 0)
196         goto fail;
197     attempts++;
198     if (s->http_code == 401) {
199         if ((cur_auth_type == HTTP_AUTH_NONE || s->auth_state.stale) &&
200             s->auth_state.auth_type != HTTP_AUTH_NONE && attempts < 4) {
201             ffurl_close(s->hd);
202             s->hd = NULL;
203             goto redo;
204         } else
205             goto fail;
206     }
207     if (s->http_code == 407) {
208         if ((cur_proxy_auth_type == HTTP_AUTH_NONE || s->proxy_auth_state.stale) &&
209             s->proxy_auth_state.auth_type != HTTP_AUTH_NONE && attempts < 4) {
210             ffurl_close(s->hd);
211             s->hd = NULL;
212             goto redo;
213         } else
214             goto fail;
215     }
216     if ((s->http_code == 301 || s->http_code == 302 ||
217          s->http_code == 303 || s->http_code == 307) &&
218         location_changed == 1) {
219         /* url moved, get next */
220         ffurl_close(s->hd);
221         s->hd = NULL;
222         if (redirects++ >= MAX_REDIRECTS)
223             return AVERROR(EIO);
224         /* Restart the authentication process with the new target, which
225          * might use a different auth mechanism. */
226         memset(&s->auth_state, 0, sizeof(s->auth_state));
227         attempts         = 0;
228         location_changed = 0;
229         goto redo;
230     }
231     return 0;
232
233 fail:
234     if (s->hd)
235         ffurl_close(s->hd);
236     s->hd = NULL;
237     return AVERROR(EIO);
238 }
239
240 int ff_http_do_new_request(URLContext *h, const char *uri)
241 {
242     HTTPContext *s = h->priv_data;
243     AVDictionary *options = NULL;
244     int ret;
245
246     s->off           = 0;
247     s->icy_data_read = 0;
248     av_free(s->location);
249     s->location = av_strdup(uri);
250     if (!s->location)
251         return AVERROR(ENOMEM);
252
253     av_dict_copy(&options, s->chained_options, 0);
254     ret = http_open_cnx(h, &options);
255     av_dict_free(&options);
256     return ret;
257 }
258
259 static int http_open(URLContext *h, const char *uri, int flags,
260                      AVDictionary **options)
261 {
262     HTTPContext *s = h->priv_data;
263     int ret;
264
265     h->is_streamed = 1;
266
267     s->filesize = -1;
268     s->location = av_strdup(uri);
269     if (!s->location)
270         return AVERROR(ENOMEM);
271     if (options)
272         av_dict_copy(&s->chained_options, *options, 0);
273
274     if (s->headers) {
275         int len = strlen(s->headers);
276         if (len < 2 || strcmp("\r\n", s->headers + len - 2))
277             av_log(h, AV_LOG_WARNING,
278                    "No trailing CRLF found in HTTP header.\n");
279     }
280
281     ret = http_open_cnx(h, options);
282     if (ret < 0)
283         av_dict_free(&s->chained_options);
284     return ret;
285 }
286
287 static int http_getc(HTTPContext *s)
288 {
289     int len;
290     if (s->buf_ptr >= s->buf_end) {
291         len = ffurl_read(s->hd, s->buffer, BUFFER_SIZE);
292         if (len < 0) {
293             return len;
294         } else if (len == 0) {
295             return AVERROR_EOF;
296         } else {
297             s->buf_ptr = s->buffer;
298             s->buf_end = s->buffer + len;
299         }
300     }
301     return *s->buf_ptr++;
302 }
303
304 static int http_get_line(HTTPContext *s, char *line, int line_size)
305 {
306     int ch;
307     char *q;
308
309     q = line;
310     for (;;) {
311         ch = http_getc(s);
312         if (ch < 0)
313             return ch;
314         if (ch == '\n') {
315             /* process line */
316             if (q > line && q[-1] == '\r')
317                 q--;
318             *q = '\0';
319
320             return 0;
321         } else {
322             if ((q - line) < line_size - 1)
323                 *q++ = ch;
324         }
325     }
326 }
327
328 static int check_http_code(URLContext *h, int http_code, const char *end)
329 {
330     HTTPContext *s = h->priv_data;
331     /* error codes are 4xx and 5xx, but regard 401 as a success, so we
332      * don't abort until all headers have been parsed. */
333     if (http_code >= 400 && http_code < 600 &&
334         (http_code != 401 || s->auth_state.auth_type != HTTP_AUTH_NONE) &&
335         (http_code != 407 || s->proxy_auth_state.auth_type != HTTP_AUTH_NONE)) {
336         end += strspn(end, SPACE_CHARS);
337         av_log(h, AV_LOG_WARNING, "HTTP error %d %s\n", http_code, end);
338         return AVERROR(EIO);
339     }
340     return 0;
341 }
342
343 static int parse_location(HTTPContext *s, const char *p)
344 {
345     char redirected_location[MAX_URL_SIZE], *new_loc;
346     ff_make_absolute_url(redirected_location, sizeof(redirected_location),
347                          s->location, p);
348     new_loc = av_strdup(redirected_location);
349     if (!new_loc)
350         return AVERROR(ENOMEM);
351     av_free(s->location);
352     s->location = new_loc;
353     return 0;
354 }
355
356 /* "bytes $from-$to/$document_size" */
357 static void parse_content_range(URLContext *h, const char *p)
358 {
359     HTTPContext *s = h->priv_data;
360     const char *slash;
361
362     if (!strncmp(p, "bytes ", 6)) {
363         p     += 6;
364         s->off = strtoll(p, NULL, 10);
365         if ((slash = strchr(p, '/')) && strlen(slash) > 0)
366             s->filesize = strtoll(slash + 1, NULL, 10);
367     }
368     h->is_streamed = 0; /* we _can_ in fact seek */
369 }
370
371 static int parse_content_encoding(URLContext *h, const char *p)
372 {
373     HTTPContext *s = h->priv_data;
374
375     if (!av_strncasecmp(p, "gzip", 4) ||
376         !av_strncasecmp(p, "deflate", 7)) {
377 #if CONFIG_ZLIB
378         s->compressed = 1;
379         inflateEnd(&s->inflate_stream);
380         if (inflateInit2(&s->inflate_stream, 32 + 15) != Z_OK) {
381             av_log(h, AV_LOG_WARNING, "Error during zlib initialisation: %s\n",
382                    s->inflate_stream.msg);
383             return AVERROR(ENOSYS);
384         }
385         if (zlibCompileFlags() & (1 << 17)) {
386             av_log(h, AV_LOG_WARNING,
387                    "Your zlib was compiled without gzip support.\n");
388             return AVERROR(ENOSYS);
389         }
390 #else
391         av_log(h, AV_LOG_WARNING,
392                "Compressed (%s) content, need zlib with gzip support\n", p);
393         return AVERROR(ENOSYS);
394 #endif /* CONFIG_ZLIB */
395     } else if (!av_strncasecmp(p, "identity", 8)) {
396         // The normal, no-encoding case (although servers shouldn't include
397         // the header at all if this is the case).
398     } else {
399         av_log(h, AV_LOG_WARNING, "Unknown content coding: %s\n", p);
400         return AVERROR(ENOSYS);
401     }
402     return 0;
403 }
404
405 // Concat all Icy- header lines
406 static int parse_icy(HTTPContext *s, const char *tag, const char *p)
407 {
408     int len = 4 + strlen(p) + strlen(tag);
409     int is_first = !s->icy_metadata_headers;
410     int ret;
411
412     if (s->icy_metadata_headers)
413         len += strlen(s->icy_metadata_headers);
414
415     if ((ret = av_reallocp(&s->icy_metadata_headers, len)) < 0)
416         return ret;
417
418     if (is_first)
419         *s->icy_metadata_headers = '\0';
420
421     av_strlcatf(s->icy_metadata_headers, len, "%s: %s\n", tag, p);
422
423     return 0;
424 }
425
426 static int process_line(URLContext *h, char *line, int line_count,
427                         int *new_location)
428 {
429     HTTPContext *s = h->priv_data;
430     char *tag, *p, *end;
431     int ret;
432
433     /* end of header */
434     if (line[0] == '\0') {
435         s->end_header = 1;
436         return 0;
437     }
438
439     p = line;
440     if (line_count == 0) {
441         while (!av_isspace(*p) && *p != '\0')
442             p++;
443         while (av_isspace(*p))
444             p++;
445         s->http_code = strtol(p, &end, 10);
446
447         av_dlog(NULL, "http_code=%d\n", s->http_code);
448
449         if ((ret = check_http_code(h, s->http_code, end)) < 0)
450             return ret;
451     } else {
452         while (*p != '\0' && *p != ':')
453             p++;
454         if (*p != ':')
455             return 1;
456
457         *p  = '\0';
458         tag = line;
459         p++;
460         while (av_isspace(*p))
461             p++;
462         if (!av_strcasecmp(tag, "Location")) {
463             if ((ret = parse_location(s, p)) < 0)
464                 return ret;
465             *new_location = 1;
466         } else if (!av_strcasecmp(tag, "Content-Length") && s->filesize == -1) {
467             s->filesize = strtoll(p, NULL, 10);
468         } else if (!av_strcasecmp(tag, "Content-Range")) {
469             parse_content_range(h, p);
470         } else if (!av_strcasecmp(tag, "Accept-Ranges") &&
471                    !strncmp(p, "bytes", 5)) {
472             h->is_streamed = 0;
473         } else if (!av_strcasecmp(tag, "Transfer-Encoding") &&
474                    !av_strncasecmp(p, "chunked", 7)) {
475             s->filesize  = -1;
476             s->chunksize = 0;
477         } else if (!av_strcasecmp(tag, "WWW-Authenticate")) {
478             ff_http_auth_handle_header(&s->auth_state, tag, p);
479         } else if (!av_strcasecmp(tag, "Authentication-Info")) {
480             ff_http_auth_handle_header(&s->auth_state, tag, p);
481         } else if (!av_strcasecmp(tag, "Proxy-Authenticate")) {
482             ff_http_auth_handle_header(&s->proxy_auth_state, tag, p);
483         } else if (!av_strcasecmp(tag, "Connection")) {
484             if (!strcmp(p, "close"))
485                 s->willclose = 1;
486         } else if (!av_strcasecmp(tag, "Content-Type")) {
487             av_free(s->mime_type);
488             s->mime_type = av_strdup(p);
489         } else if (!av_strcasecmp(tag, "Icy-MetaInt")) {
490             s->icy_metaint = strtoll(p, NULL, 10);
491         } else if (!av_strncasecmp(tag, "Icy-", 4)) {
492             if ((ret = parse_icy(s, tag, p)) < 0)
493                 return ret;
494         } else if (!av_strcasecmp(tag, "Content-Encoding")) {
495             if ((ret = parse_content_encoding(h, p)) < 0)
496                 return ret;
497         }
498     }
499     return 1;
500 }
501
502 static inline int has_header(const char *str, const char *header)
503 {
504     /* header + 2 to skip over CRLF prefix. (make sure you have one!) */
505     if (!str)
506         return 0;
507     return av_stristart(str, header + 2, NULL) || av_stristr(str, header);
508 }
509
510 static int http_read_header(URLContext *h, int *new_location)
511 {
512     HTTPContext *s = h->priv_data;
513     char line[MAX_URL_SIZE];
514     int err = 0;
515
516     s->chunksize = -1;
517
518     for (;;) {
519         if ((err = http_get_line(s, line, sizeof(line))) < 0)
520             return err;
521
522         av_dlog(NULL, "header='%s'\n", line);
523
524         err = process_line(h, line, s->line_count, new_location);
525         if (err < 0)
526             return err;
527         if (err == 0)
528             break;
529         s->line_count++;
530     }
531
532     return err;
533 }
534
535 static int http_connect(URLContext *h, const char *path, const char *local_path,
536                         const char *hoststr, const char *auth,
537                         const char *proxyauth, int *new_location)
538 {
539     HTTPContext *s = h->priv_data;
540     int post, err;
541     char headers[HTTP_HEADERS_SIZE] = "";
542     char *authstr = NULL, *proxyauthstr = NULL;
543     int64_t off = s->off;
544     int len = 0;
545     const char *method;
546     int send_expect_100 = 0;
547
548     /* send http header */
549     post = h->flags & AVIO_FLAG_WRITE;
550
551     if (s->post_data) {
552         /* force POST method and disable chunked encoding when
553          * custom HTTP post data is set */
554         post            = 1;
555         s->chunked_post = 0;
556     }
557
558     if (s->method)
559         method = s->method;
560     else
561         method = post ? "POST" : "GET";
562
563     authstr      = ff_http_auth_create_response(&s->auth_state, auth,
564                                                 local_path, method);
565     proxyauthstr = ff_http_auth_create_response(&s->proxy_auth_state, proxyauth,
566                                                 local_path, method);
567     if (post && !s->post_data) {
568         send_expect_100 = s->send_expect_100;
569         /* The user has supplied authentication but we don't know the auth type,
570          * send Expect: 100-continue to get the 401 response including the
571          * WWW-Authenticate header, or an 100 continue if no auth actually
572          * is needed. */
573         if (auth && *auth &&
574             s->auth_state.auth_type == HTTP_AUTH_NONE &&
575             s->http_code != 401)
576             send_expect_100 = 1;
577     }
578
579     /* set default headers if needed */
580     if (!has_header(s->headers, "\r\nUser-Agent: "))
581         len += av_strlcatf(headers + len, sizeof(headers) - len,
582                            "User-Agent: %s\r\n", s->user_agent);
583     if (!has_header(s->headers, "\r\nAccept: "))
584         len += av_strlcpy(headers + len, "Accept: */*\r\n",
585                           sizeof(headers) - len);
586     // Note: we send this on purpose even when s->off is 0 when we're probing,
587     // since it allows us to detect more reliably if a (non-conforming)
588     // server supports seeking by analysing the reply headers.
589     if (!has_header(s->headers, "\r\nRange: ") && !post) {
590         len += av_strlcatf(headers + len, sizeof(headers) - len,
591                            "Range: bytes=%"PRId64"-", s->off);
592         if (s->end_off)
593             len += av_strlcatf(headers + len, sizeof(headers) - len,
594                                "%"PRId64, s->end_off - 1);
595         len += av_strlcpy(headers + len, "\r\n",
596                           sizeof(headers) - len);
597     }
598     if (send_expect_100 && !has_header(s->headers, "\r\nExpect: "))
599         len += av_strlcatf(headers + len, sizeof(headers) - len,
600                            "Expect: 100-continue\r\n");
601
602     if (!has_header(s->headers, "\r\nConnection: ")) {
603         if (s->multiple_requests)
604             len += av_strlcpy(headers + len, "Connection: keep-alive\r\n",
605                               sizeof(headers) - len);
606         else
607             len += av_strlcpy(headers + len, "Connection: close\r\n",
608                               sizeof(headers) - len);
609     }
610
611     if (!has_header(s->headers, "\r\nHost: "))
612         len += av_strlcatf(headers + len, sizeof(headers) - len,
613                            "Host: %s\r\n", hoststr);
614     if (!has_header(s->headers, "\r\nContent-Length: ") && s->post_data)
615         len += av_strlcatf(headers + len, sizeof(headers) - len,
616                            "Content-Length: %d\r\n", s->post_datalen);
617
618     if (!has_header(s->headers, "\r\nContent-Type: ") && s->content_type)
619         len += av_strlcatf(headers + len, sizeof(headers) - len,
620                            "Content-Type: %s\r\n", s->content_type);
621     if (!has_header(s->headers, "\r\nIcy-MetaData: ") && s->icy)
622         len += av_strlcatf(headers + len, sizeof(headers) - len,
623                            "Icy-MetaData: %d\r\n", 1);
624
625     /* now add in custom headers */
626     if (s->headers)
627         av_strlcpy(headers + len, s->headers, sizeof(headers) - len);
628
629     snprintf(s->buffer, sizeof(s->buffer),
630              "%s %s HTTP/1.1\r\n"
631              "%s"
632              "%s"
633              "%s"
634              "%s%s"
635              "\r\n",
636              method,
637              path,
638              post && s->chunked_post ? "Transfer-Encoding: chunked\r\n" : "",
639              headers,
640              authstr ? authstr : "",
641              proxyauthstr ? "Proxy-" : "", proxyauthstr ? proxyauthstr : "");
642
643     av_freep(&authstr);
644     av_freep(&proxyauthstr);
645     if ((err = ffurl_write(s->hd, s->buffer, strlen(s->buffer))) < 0)
646         return err;
647
648     if (s->post_data)
649         if ((err = ffurl_write(s->hd, s->post_data, s->post_datalen)) < 0)
650             return err;
651
652     /* init input buffer */
653     s->buf_ptr          = s->buffer;
654     s->buf_end          = s->buffer;
655     s->line_count       = 0;
656     s->off              = 0;
657     s->icy_data_read    = 0;
658     s->filesize         = -1;
659     s->willclose        = 0;
660     s->end_chunked_post = 0;
661     s->end_header       = 0;
662     if (post && !s->post_data && !send_expect_100) {
663         /* Pretend that it did work. We didn't read any header yet, since
664          * we've still to send the POST data, but the code calling this
665          * function will check http_code after we return. */
666         s->http_code = 200;
667         return 0;
668     }
669
670     /* wait for header */
671     err = http_read_header(h, new_location);
672     if (err < 0)
673         return err;
674
675     return (off == s->off) ? 0 : -1;
676 }
677
678 static int http_buf_read(URLContext *h, uint8_t *buf, int size)
679 {
680     HTTPContext *s = h->priv_data;
681     int len;
682     /* read bytes from input buffer first */
683     len = s->buf_end - s->buf_ptr;
684     if (len > 0) {
685         if (len > size)
686             len = size;
687         memcpy(buf, s->buf_ptr, len);
688         s->buf_ptr += len;
689     } else {
690         if (!s->willclose && s->filesize >= 0 && s->off >= s->filesize)
691             return AVERROR_EOF;
692         len = ffurl_read(s->hd, buf, size);
693     }
694     if (len > 0) {
695         s->off += len;
696         if (s->chunksize > 0)
697             s->chunksize -= len;
698     }
699     return len;
700 }
701
702 #if CONFIG_ZLIB
703 #define DECOMPRESS_BUF_SIZE (256 * 1024)
704 static int http_buf_read_compressed(URLContext *h, uint8_t *buf, int size)
705 {
706     HTTPContext *s = h->priv_data;
707     int ret;
708
709     if (!s->inflate_buffer) {
710         s->inflate_buffer = av_malloc(DECOMPRESS_BUF_SIZE);
711         if (!s->inflate_buffer)
712             return AVERROR(ENOMEM);
713     }
714
715     if (s->inflate_stream.avail_in == 0) {
716         int read = http_buf_read(h, s->inflate_buffer, DECOMPRESS_BUF_SIZE);
717         if (read <= 0)
718             return read;
719         s->inflate_stream.next_in  = s->inflate_buffer;
720         s->inflate_stream.avail_in = read;
721     }
722
723     s->inflate_stream.avail_out = size;
724     s->inflate_stream.next_out  = buf;
725
726     ret = inflate(&s->inflate_stream, Z_SYNC_FLUSH);
727     if (ret != Z_OK && ret != Z_STREAM_END)
728         av_log(h, AV_LOG_WARNING, "inflate return value: %d, %s\n",
729                ret, s->inflate_stream.msg);
730
731     return size - s->inflate_stream.avail_out;
732 }
733 #endif /* CONFIG_ZLIB */
734
735 static int http_read_stream(URLContext *h, uint8_t *buf, int size)
736 {
737     HTTPContext *s = h->priv_data;
738     int err, new_location;
739
740     if (!s->hd)
741         return AVERROR_EOF;
742
743     if (s->end_chunked_post && !s->end_header) {
744         err = http_read_header(h, &new_location);
745         if (err < 0)
746             return err;
747     }
748
749     if (s->chunksize >= 0) {
750         if (!s->chunksize) {
751             char line[32];
752
753             for (;;) {
754                 do {
755                     if ((err = http_get_line(s, line, sizeof(line))) < 0)
756                         return err;
757                 } while (!*line);    /* skip CR LF from last chunk */
758
759                 s->chunksize = strtoll(line, NULL, 16);
760
761                 av_dlog(NULL, "Chunked encoding data size: %"PRId64"'\n",
762                         s->chunksize);
763
764                 if (!s->chunksize)
765                     return 0;
766                 break;
767             }
768         }
769         size = FFMIN(size, s->chunksize);
770     }
771 #if CONFIG_ZLIB
772     if (s->compressed)
773         return http_buf_read_compressed(h, buf, size);
774 #endif /* CONFIG_ZLIB */
775     return http_buf_read(h, buf, size);
776 }
777
778 static int http_read_stream_all(URLContext *h, uint8_t *buf, int size)
779 {
780     int pos = 0;
781     while (pos < size) {
782         int len = http_read_stream(h, buf + pos, size - pos);
783         if (len < 0)
784             return len;
785         pos += len;
786     }
787     return pos;
788 }
789
790 static int store_icy(URLContext *h, int size)
791 {
792     HTTPContext *s = h->priv_data;
793     /* until next metadata packet */
794     int remaining = s->icy_metaint - s->icy_data_read;
795
796     if (remaining < 0)
797         return AVERROR_INVALIDDATA;
798
799     if (!remaining) {
800         /* The metadata packet is variable sized. It has a 1 byte header
801          * which sets the length of the packet (divided by 16). If it's 0,
802          * the metadata doesn't change. After the packet, icy_metaint bytes
803          * of normal data follows. */
804         uint8_t ch;
805         int len = http_read_stream_all(h, &ch, 1);
806         if (len < 0)
807             return len;
808         if (ch > 0) {
809             char data[255 * 16 + 1];
810             int ret;
811             len = ch * 16;
812             ret = http_read_stream_all(h, data, len);
813             if (ret < 0)
814                 return ret;
815             data[len + 1] = 0;
816             if ((ret = av_opt_set(s, "icy_metadata_packet", data, 0)) < 0)
817                 return ret;
818         }
819         s->icy_data_read = 0;
820         remaining        = s->icy_metaint;
821     }
822
823     return FFMIN(size, remaining);
824 }
825
826 static int http_read(URLContext *h, uint8_t *buf, int size)
827 {
828     HTTPContext *s = h->priv_data;
829
830     if (s->icy_metaint > 0) {
831         size = store_icy(h, size);
832         if (size < 0)
833             return size;
834     }
835
836     size = http_read_stream(h, buf, size);
837     if (size > 0)
838         s->icy_data_read += size;
839     return size;
840 }
841
842 /* used only when posting data */
843 static int http_write(URLContext *h, const uint8_t *buf, int size)
844 {
845     char temp[11] = "";  /* 32-bit hex + CRLF + nul */
846     int ret;
847     char crlf[] = "\r\n";
848     HTTPContext *s = h->priv_data;
849
850     if (!s->chunked_post) {
851         /* non-chunked data is sent without any special encoding */
852         return ffurl_write(s->hd, buf, size);
853     }
854
855     /* silently ignore zero-size data since chunk encoding that would
856      * signal EOF */
857     if (size > 0) {
858         /* upload data using chunked encoding */
859         snprintf(temp, sizeof(temp), "%x\r\n", size);
860
861         if ((ret = ffurl_write(s->hd, temp, strlen(temp))) < 0 ||
862             (ret = ffurl_write(s->hd, buf, size)) < 0          ||
863             (ret = ffurl_write(s->hd, crlf, sizeof(crlf) - 1)) < 0)
864             return ret;
865     }
866     return size;
867 }
868
869 static int http_shutdown(URLContext *h, int flags)
870 {
871     int ret = 0;
872     char footer[] = "0\r\n\r\n";
873     HTTPContext *s = h->priv_data;
874
875     /* signal end of chunked encoding if used */
876     if ((flags & AVIO_FLAG_WRITE) && s->chunked_post) {
877         ret = ffurl_write(s->hd, footer, sizeof(footer) - 1);
878         ret = ret > 0 ? 0 : ret;
879         s->end_chunked_post = 1;
880     }
881
882     return ret;
883 }
884
885 static int http_close(URLContext *h)
886 {
887     int ret = 0;
888     HTTPContext *s = h->priv_data;
889
890 #if CONFIG_ZLIB
891     inflateEnd(&s->inflate_stream);
892     av_freep(&s->inflate_buffer);
893 #endif /* CONFIG_ZLIB */
894
895     if (!s->end_chunked_post)
896         /* Close the write direction by sending the end of chunked encoding. */
897         ret = http_shutdown(h, h->flags);
898
899     if (s->hd)
900         ffurl_close(s->hd);
901     av_dict_free(&s->chained_options);
902     return ret;
903 }
904
905 static int64_t http_seek(URLContext *h, int64_t off, int whence)
906 {
907     HTTPContext *s = h->priv_data;
908     URLContext *old_hd = s->hd;
909     int64_t old_off = s->off;
910     uint8_t old_buf[BUFFER_SIZE];
911     int old_buf_size, ret;
912     AVDictionary *options = NULL;
913
914     if (whence == AVSEEK_SIZE)
915         return s->filesize;
916     else if ((whence == SEEK_CUR && off == 0) ||
917              (whence == SEEK_SET && off == s->off))
918         return s->off;
919     else if ((s->filesize == -1 && whence == SEEK_END) || h->is_streamed)
920         return AVERROR(ENOSYS);
921
922     /* we save the old context in case the seek fails */
923     old_buf_size = s->buf_end - s->buf_ptr;
924     memcpy(old_buf, s->buf_ptr, old_buf_size);
925     s->hd = NULL;
926     if (whence == SEEK_CUR)
927         off += s->off;
928     else if (whence == SEEK_END)
929         off += s->filesize;
930     s->off = off;
931
932     /* if it fails, continue on old connection */
933     av_dict_copy(&options, s->chained_options, 0);
934     if ((ret = http_open_cnx(h, &options)) < 0) {
935         av_dict_free(&options);
936         memcpy(s->buffer, old_buf, old_buf_size);
937         s->buf_ptr = s->buffer;
938         s->buf_end = s->buffer + old_buf_size;
939         s->hd      = old_hd;
940         s->off     = old_off;
941         return ret;
942     }
943     av_dict_free(&options);
944     ffurl_close(old_hd);
945     return off;
946 }
947
948 static int http_get_file_handle(URLContext *h)
949 {
950     HTTPContext *s = h->priv_data;
951     return ffurl_get_file_handle(s->hd);
952 }
953
954 #define HTTP_CLASS(flavor)                          \
955 static const AVClass flavor ## _context_class = {   \
956     .class_name = # flavor,                         \
957     .item_name  = av_default_item_name,             \
958     .option     = options,                          \
959     .version    = LIBAVUTIL_VERSION_INT,            \
960 }
961
962 #if CONFIG_HTTP_PROTOCOL
963 HTTP_CLASS(http);
964
965 URLProtocol ff_http_protocol = {
966     .name                = "http",
967     .url_open2           = http_open,
968     .url_read            = http_read,
969     .url_write           = http_write,
970     .url_seek            = http_seek,
971     .url_close           = http_close,
972     .url_get_file_handle = http_get_file_handle,
973     .url_shutdown        = http_shutdown,
974     .priv_data_size      = sizeof(HTTPContext),
975     .priv_data_class     = &http_context_class,
976     .flags               = URL_PROTOCOL_FLAG_NETWORK,
977 };
978 #endif /* CONFIG_HTTP_PROTOCOL */
979
980 #if CONFIG_HTTPS_PROTOCOL
981 HTTP_CLASS(https);
982
983 URLProtocol ff_https_protocol = {
984     .name                = "https",
985     .url_open2           = http_open,
986     .url_read            = http_read,
987     .url_write           = http_write,
988     .url_seek            = http_seek,
989     .url_close           = http_close,
990     .url_get_file_handle = http_get_file_handle,
991     .url_shutdown        = http_shutdown,
992     .priv_data_size      = sizeof(HTTPContext),
993     .priv_data_class     = &https_context_class,
994     .flags               = URL_PROTOCOL_FLAG_NETWORK,
995 };
996 #endif /* CONFIG_HTTPS_PROTOCOL */
997
998 #if CONFIG_HTTPPROXY_PROTOCOL
999 static int http_proxy_close(URLContext *h)
1000 {
1001     HTTPContext *s = h->priv_data;
1002     if (s->hd)
1003         ffurl_close(s->hd);
1004     return 0;
1005 }
1006
1007 static int http_proxy_open(URLContext *h, const char *uri, int flags)
1008 {
1009     HTTPContext *s = h->priv_data;
1010     char hostname[1024], hoststr[1024];
1011     char auth[1024], pathbuf[1024], *path;
1012     char lower_url[100];
1013     int port, ret = 0, attempts = 0;
1014     HTTPAuthType cur_auth_type;
1015     char *authstr;
1016     int new_loc;
1017
1018     h->is_streamed = 1;
1019
1020     av_url_split(NULL, 0, auth, sizeof(auth), hostname, sizeof(hostname), &port,
1021                  pathbuf, sizeof(pathbuf), uri);
1022     ff_url_join(hoststr, sizeof(hoststr), NULL, NULL, hostname, port, NULL);
1023     path = pathbuf;
1024     if (*path == '/')
1025         path++;
1026
1027     ff_url_join(lower_url, sizeof(lower_url), "tcp", NULL, hostname, port,
1028                 NULL);
1029 redo:
1030     ret = ffurl_open(&s->hd, lower_url, AVIO_FLAG_READ_WRITE,
1031                      &h->interrupt_callback, NULL);
1032     if (ret < 0)
1033         return ret;
1034
1035     authstr = ff_http_auth_create_response(&s->proxy_auth_state, auth,
1036                                            path, "CONNECT");
1037     snprintf(s->buffer, sizeof(s->buffer),
1038              "CONNECT %s HTTP/1.1\r\n"
1039              "Host: %s\r\n"
1040              "Connection: close\r\n"
1041              "%s%s"
1042              "\r\n",
1043              path,
1044              hoststr,
1045              authstr ? "Proxy-" : "", authstr ? authstr : "");
1046     av_freep(&authstr);
1047
1048     if ((ret = ffurl_write(s->hd, s->buffer, strlen(s->buffer))) < 0)
1049         goto fail;
1050
1051     s->buf_ptr    = s->buffer;
1052     s->buf_end    = s->buffer;
1053     s->line_count = 0;
1054     s->filesize   = -1;
1055     cur_auth_type = s->proxy_auth_state.auth_type;
1056
1057     /* Note: This uses buffering, potentially reading more than the
1058      * HTTP header. If tunneling a protocol where the server starts
1059      * the conversation, we might buffer part of that here, too.
1060      * Reading that requires using the proper ffurl_read() function
1061      * on this URLContext, not using the fd directly (as the tls
1062      * protocol does). This shouldn't be an issue for tls though,
1063      * since the client starts the conversation there, so there
1064      * is no extra data that we might buffer up here.
1065      */
1066     ret = http_read_header(h, &new_loc);
1067     if (ret < 0)
1068         goto fail;
1069
1070     attempts++;
1071     if (s->http_code == 407 &&
1072         (cur_auth_type == HTTP_AUTH_NONE || s->proxy_auth_state.stale) &&
1073         s->proxy_auth_state.auth_type != HTTP_AUTH_NONE && attempts < 2) {
1074         ffurl_close(s->hd);
1075         s->hd = NULL;
1076         goto redo;
1077     }
1078
1079     if (s->http_code < 400)
1080         return 0;
1081     ret = AVERROR(EIO);
1082
1083 fail:
1084     http_proxy_close(h);
1085     return ret;
1086 }
1087
1088 static int http_proxy_write(URLContext *h, const uint8_t *buf, int size)
1089 {
1090     HTTPContext *s = h->priv_data;
1091     return ffurl_write(s->hd, buf, size);
1092 }
1093
1094 URLProtocol ff_httpproxy_protocol = {
1095     .name                = "httpproxy",
1096     .url_open            = http_proxy_open,
1097     .url_read            = http_buf_read,
1098     .url_write           = http_proxy_write,
1099     .url_close           = http_proxy_close,
1100     .url_get_file_handle = http_get_file_handle,
1101     .priv_data_size      = sizeof(HTTPContext),
1102     .flags               = URL_PROTOCOL_FLAG_NETWORK,
1103 };
1104 #endif /* CONFIG_HTTPPROXY_PROTOCOL */