http.c
Go to the documentation of this file.
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 "libavutil/avstring.h"
23 #include "avformat.h"
24 #include "internal.h"
25 #include "network.h"
26 #include "http.h"
27 #include "os_support.h"
28 #include "httpauth.h"
29 #include "url.h"
30 #include "libavutil/opt.h"
31 
32 /* XXX: POST protocol is not completely implemented because avconv uses
33  only a subset of it. */
34 
35 /* The IO buffer size is unrelated to the max URL size in itself, but needs
36  * to be large enough to fit the full request headers (including long
37  * path names).
38  */
39 #define BUFFER_SIZE MAX_URL_SIZE
40 #define MAX_REDIRECTS 8
41 
42 typedef struct {
43  const AVClass *class;
45  unsigned char buffer[BUFFER_SIZE], *buf_ptr, *buf_end;
47  int http_code;
48  int64_t chunksize;
49  int64_t off, filesize;
50  char location[MAX_URL_SIZE];
53  char *headers;
54  int willclose;
57  int end_header;
61 } HTTPContext;
62 
63 #define OFFSET(x) offsetof(HTTPContext, x)
64 #define D AV_OPT_FLAG_DECODING_PARAM
65 #define E AV_OPT_FLAG_ENCODING_PARAM
66 static const AVOption options[] = {
67 {"chunked_post", "use chunked transfer-encoding for posts", OFFSET(chunked_post), AV_OPT_TYPE_INT, {.i64 = 1}, 0, 1, E },
68 {"headers", "custom HTTP headers, can override built in default headers", OFFSET(headers), AV_OPT_TYPE_STRING, { 0 }, 0, 0, D|E },
69 {"multiple_requests", "use persistent connections", OFFSET(multiple_requests), AV_OPT_TYPE_INT, {.i64 = 0}, 0, 1, D|E },
70 {"post_data", "custom HTTP post data", OFFSET(post_data), AV_OPT_TYPE_BINARY, .flags = D|E },
71 {NULL}
72 };
73 #define HTTP_CLASS(flavor)\
74 static const AVClass flavor ## _context_class = {\
75  .class_name = #flavor,\
76  .item_name = av_default_item_name,\
77  .option = options,\
78  .version = LIBAVUTIL_VERSION_INT,\
79 }
80 
81 HTTP_CLASS(http);
82 HTTP_CLASS(https);
83 
84 static int http_connect(URLContext *h, const char *path, const char *local_path,
85  const char *hoststr, const char *auth,
86  const char *proxyauth, int *new_location);
87 
89 {
90  memcpy(&((HTTPContext*)dest->priv_data)->auth_state,
91  &((HTTPContext*)src->priv_data)->auth_state, sizeof(HTTPAuthState));
92  memcpy(&((HTTPContext*)dest->priv_data)->proxy_auth_state,
93  &((HTTPContext*)src->priv_data)->proxy_auth_state,
94  sizeof(HTTPAuthState));
95 }
96 
97 /* return non zero if error */
98 static int http_open_cnx(URLContext *h)
99 {
100  const char *path, *proxy_path, *lower_proto = "tcp", *local_path;
101  char hostname[1024], hoststr[1024], proto[10];
102  char auth[1024], proxyauth[1024] = "";
103  char path1[MAX_URL_SIZE];
104  char buf[1024], urlbuf[MAX_URL_SIZE];
105  int port, use_proxy, err, location_changed = 0, redirects = 0, attempts = 0;
106  HTTPAuthType cur_auth_type, cur_proxy_auth_type;
107  HTTPContext *s = h->priv_data;
108 
109  proxy_path = getenv("http_proxy");
110  use_proxy = (proxy_path != NULL) && !getenv("no_proxy") &&
111  av_strstart(proxy_path, "http://", NULL);
112 
113  /* fill the dest addr */
114  redo:
115  /* needed in any case to build the host string */
116  av_url_split(proto, sizeof(proto), auth, sizeof(auth),
117  hostname, sizeof(hostname), &port,
118  path1, sizeof(path1), s->location);
119  ff_url_join(hoststr, sizeof(hoststr), NULL, NULL, hostname, port, NULL);
120 
121  if (!strcmp(proto, "https")) {
122  lower_proto = "tls";
123  use_proxy = 0;
124  if (port < 0)
125  port = 443;
126  }
127  if (port < 0)
128  port = 80;
129 
130  if (path1[0] == '\0')
131  path = "/";
132  else
133  path = path1;
134  local_path = path;
135  if (use_proxy) {
136  /* Reassemble the request URL without auth string - we don't
137  * want to leak the auth to the proxy. */
138  ff_url_join(urlbuf, sizeof(urlbuf), proto, NULL, hostname, port, "%s",
139  path1);
140  path = urlbuf;
141  av_url_split(NULL, 0, proxyauth, sizeof(proxyauth),
142  hostname, sizeof(hostname), &port, NULL, 0, proxy_path);
143  }
144 
145  ff_url_join(buf, sizeof(buf), lower_proto, NULL, hostname, port, NULL);
146 
147  if (!s->hd) {
148  err = ffurl_open(&s->hd, buf, AVIO_FLAG_READ_WRITE,
149  &h->interrupt_callback, NULL);
150  if (err < 0)
151  goto fail;
152  }
153 
154  cur_auth_type = s->auth_state.auth_type;
155  cur_proxy_auth_type = s->auth_state.auth_type;
156  if (http_connect(h, path, local_path, hoststr, auth, proxyauth, &location_changed) < 0)
157  goto fail;
158  attempts++;
159  if (s->http_code == 401) {
160  if ((cur_auth_type == HTTP_AUTH_NONE || s->auth_state.stale) &&
161  s->auth_state.auth_type != HTTP_AUTH_NONE && attempts < 4) {
162  ffurl_close(s->hd);
163  s->hd = NULL;
164  goto redo;
165  } else
166  goto fail;
167  }
168  if (s->http_code == 407) {
169  if ((cur_proxy_auth_type == HTTP_AUTH_NONE || s->proxy_auth_state.stale) &&
170  s->proxy_auth_state.auth_type != HTTP_AUTH_NONE && attempts < 4) {
171  ffurl_close(s->hd);
172  s->hd = NULL;
173  goto redo;
174  } else
175  goto fail;
176  }
177  if ((s->http_code == 301 || s->http_code == 302 || s->http_code == 303 || s->http_code == 307)
178  && location_changed == 1) {
179  /* url moved, get next */
180  ffurl_close(s->hd);
181  s->hd = NULL;
182  if (redirects++ >= MAX_REDIRECTS)
183  return AVERROR(EIO);
184  /* Restart the authentication process with the new target, which
185  * might use a different auth mechanism. */
186  memset(&s->auth_state, 0, sizeof(s->auth_state));
187  attempts = 0;
188  location_changed = 0;
189  goto redo;
190  }
191  return 0;
192  fail:
193  if (s->hd)
194  ffurl_close(s->hd);
195  s->hd = NULL;
196  return AVERROR(EIO);
197 }
198 
199 int ff_http_do_new_request(URLContext *h, const char *uri)
200 {
201  HTTPContext *s = h->priv_data;
202 
203  s->off = 0;
204  av_strlcpy(s->location, uri, sizeof(s->location));
205 
206  return http_open_cnx(h);
207 }
208 
209 static int http_open(URLContext *h, const char *uri, int flags)
210 {
211  HTTPContext *s = h->priv_data;
212 
213  h->is_streamed = 1;
214 
215  s->filesize = -1;
216  av_strlcpy(s->location, uri, sizeof(s->location));
217 
218  if (s->headers) {
219  int len = strlen(s->headers);
220  if (len < 2 || strcmp("\r\n", s->headers + len - 2))
221  av_log(h, AV_LOG_WARNING, "No trailing CRLF found in HTTP header.\n");
222  }
223 
224  return http_open_cnx(h);
225 }
226 static int http_getc(HTTPContext *s)
227 {
228  int len;
229  if (s->buf_ptr >= s->buf_end) {
230  len = ffurl_read(s->hd, s->buffer, BUFFER_SIZE);
231  if (len < 0) {
232  return len;
233  } else if (len == 0) {
234  return -1;
235  } else {
236  s->buf_ptr = s->buffer;
237  s->buf_end = s->buffer + len;
238  }
239  }
240  return *s->buf_ptr++;
241 }
242 
243 static int http_get_line(HTTPContext *s, char *line, int line_size)
244 {
245  int ch;
246  char *q;
247 
248  q = line;
249  for(;;) {
250  ch = http_getc(s);
251  if (ch < 0)
252  return ch;
253  if (ch == '\n') {
254  /* process line */
255  if (q > line && q[-1] == '\r')
256  q--;
257  *q = '\0';
258 
259  return 0;
260  } else {
261  if ((q - line) < line_size - 1)
262  *q++ = ch;
263  }
264  }
265 }
266 
267 static int process_line(URLContext *h, char *line, int line_count,
268  int *new_location)
269 {
270  HTTPContext *s = h->priv_data;
271  char *tag, *p, *end;
272 
273  /* end of header */
274  if (line[0] == '\0') {
275  s->end_header = 1;
276  return 0;
277  }
278 
279  p = line;
280  if (line_count == 0) {
281  while (!isspace(*p) && *p != '\0')
282  p++;
283  while (isspace(*p))
284  p++;
285  s->http_code = strtol(p, &end, 10);
286 
287  av_dlog(NULL, "http_code=%d\n", s->http_code);
288 
289  /* error codes are 4xx and 5xx, but regard 401 as a success, so we
290  * don't abort until all headers have been parsed. */
291  if (s->http_code >= 400 && s->http_code < 600 && (s->http_code != 401
292  || s->auth_state.auth_type != HTTP_AUTH_NONE) &&
293  (s->http_code != 407 || s->proxy_auth_state.auth_type != HTTP_AUTH_NONE)) {
294  end += strspn(end, SPACE_CHARS);
295  av_log(h, AV_LOG_WARNING, "HTTP error %d %s\n",
296  s->http_code, end);
297  return -1;
298  }
299  } else {
300  while (*p != '\0' && *p != ':')
301  p++;
302  if (*p != ':')
303  return 1;
304 
305  *p = '\0';
306  tag = line;
307  p++;
308  while (isspace(*p))
309  p++;
310  if (!av_strcasecmp(tag, "Location")) {
311  av_strlcpy(s->location, p, sizeof(s->location));
312  *new_location = 1;
313  } else if (!av_strcasecmp (tag, "Content-Length") && s->filesize == -1) {
314  s->filesize = strtoll(p, NULL, 10);
315  } else if (!av_strcasecmp (tag, "Content-Range")) {
316  /* "bytes $from-$to/$document_size" */
317  const char *slash;
318  if (!strncmp (p, "bytes ", 6)) {
319  p += 6;
320  s->off = strtoll(p, NULL, 10);
321  if ((slash = strchr(p, '/')) && strlen(slash) > 0)
322  s->filesize = strtoll(slash+1, NULL, 10);
323  }
324  h->is_streamed = 0; /* we _can_ in fact seek */
325  } else if (!av_strcasecmp(tag, "Accept-Ranges") && !strncmp(p, "bytes", 5)) {
326  h->is_streamed = 0;
327  } else if (!av_strcasecmp (tag, "Transfer-Encoding") && !av_strncasecmp(p, "chunked", 7)) {
328  s->filesize = -1;
329  s->chunksize = 0;
330  } else if (!av_strcasecmp (tag, "WWW-Authenticate")) {
332  } else if (!av_strcasecmp (tag, "Authentication-Info")) {
334  } else if (!av_strcasecmp (tag, "Proxy-Authenticate")) {
336  } else if (!av_strcasecmp (tag, "Connection")) {
337  if (!strcmp(p, "close"))
338  s->willclose = 1;
339  }
340  }
341  return 1;
342 }
343 
344 static inline int has_header(const char *str, const char *header)
345 {
346  /* header + 2 to skip over CRLF prefix. (make sure you have one!) */
347  if (!str)
348  return 0;
349  return av_stristart(str, header + 2, NULL) || av_stristr(str, header);
350 }
351 
352 static int http_read_header(URLContext *h, int *new_location)
353 {
354  HTTPContext *s = h->priv_data;
355  char line[MAX_URL_SIZE];
356  int err = 0;
357 
358  s->chunksize = -1;
359 
360  for (;;) {
361  if ((err = http_get_line(s, line, sizeof(line))) < 0)
362  return err;
363 
364  av_dlog(NULL, "header='%s'\n", line);
365 
366  err = process_line(h, line, s->line_count, new_location);
367  if (err < 0)
368  return err;
369  if (err == 0)
370  break;
371  s->line_count++;
372  }
373 
374  return err;
375 }
376 
377 static int http_connect(URLContext *h, const char *path, const char *local_path,
378  const char *hoststr, const char *auth,
379  const char *proxyauth, int *new_location)
380 {
381  HTTPContext *s = h->priv_data;
382  int post, err;
383  char headers[1024] = "";
384  char *authstr = NULL, *proxyauthstr = NULL;
385  int64_t off = s->off;
386  int len = 0;
387  const char *method;
388 
389 
390  /* send http header */
391  post = h->flags & AVIO_FLAG_WRITE;
392 
393  if (s->post_data) {
394  /* force POST method and disable chunked encoding when
395  * custom HTTP post data is set */
396  post = 1;
397  s->chunked_post = 0;
398  }
399 
400  method = post ? "POST" : "GET";
401  authstr = ff_http_auth_create_response(&s->auth_state, auth, local_path,
402  method);
403  proxyauthstr = ff_http_auth_create_response(&s->proxy_auth_state, proxyauth,
404  local_path, method);
405 
406  /* set default headers if needed */
407  if (!has_header(s->headers, "\r\nUser-Agent: "))
408  len += av_strlcatf(headers + len, sizeof(headers) - len,
409  "User-Agent: %s\r\n", LIBAVFORMAT_IDENT);
410  if (!has_header(s->headers, "\r\nAccept: "))
411  len += av_strlcpy(headers + len, "Accept: */*\r\n",
412  sizeof(headers) - len);
413  if (!has_header(s->headers, "\r\nRange: ") && !post)
414  len += av_strlcatf(headers + len, sizeof(headers) - len,
415  "Range: bytes=%"PRId64"-\r\n", s->off);
416 
417  if (!has_header(s->headers, "\r\nConnection: ")) {
418  if (s->multiple_requests) {
419  len += av_strlcpy(headers + len, "Connection: keep-alive\r\n",
420  sizeof(headers) - len);
421  } else {
422  len += av_strlcpy(headers + len, "Connection: close\r\n",
423  sizeof(headers) - len);
424  }
425  }
426 
427  if (!has_header(s->headers, "\r\nHost: "))
428  len += av_strlcatf(headers + len, sizeof(headers) - len,
429  "Host: %s\r\n", hoststr);
430  if (!has_header(s->headers, "\r\nContent-Length: ") && s->post_data)
431  len += av_strlcatf(headers + len, sizeof(headers) - len,
432  "Content-Length: %d\r\n", s->post_datalen);
433 
434  /* now add in custom headers */
435  if (s->headers)
436  av_strlcpy(headers + len, s->headers, sizeof(headers) - len);
437 
438  snprintf(s->buffer, sizeof(s->buffer),
439  "%s %s HTTP/1.1\r\n"
440  "%s"
441  "%s"
442  "%s"
443  "%s%s"
444  "\r\n",
445  method,
446  path,
447  post && s->chunked_post ? "Transfer-Encoding: chunked\r\n" : "",
448  headers,
449  authstr ? authstr : "",
450  proxyauthstr ? "Proxy-" : "", proxyauthstr ? proxyauthstr : "");
451 
452  av_freep(&authstr);
453  av_freep(&proxyauthstr);
454  if ((err = ffurl_write(s->hd, s->buffer, strlen(s->buffer))) < 0)
455  return err;
456 
457  if (s->post_data)
458  if ((err = ffurl_write(s->hd, s->post_data, s->post_datalen)) < 0)
459  return err;
460 
461  /* init input buffer */
462  s->buf_ptr = s->buffer;
463  s->buf_end = s->buffer;
464  s->line_count = 0;
465  s->off = 0;
466  s->filesize = -1;
467  s->willclose = 0;
468  s->end_chunked_post = 0;
469  s->end_header = 0;
470  if (post && !s->post_data) {
471  /* Pretend that it did work. We didn't read any header yet, since
472  * we've still to send the POST data, but the code calling this
473  * function will check http_code after we return. */
474  s->http_code = 200;
475  return 0;
476  }
477 
478  /* wait for header */
479  err = http_read_header(h, new_location);
480  if (err < 0)
481  return err;
482 
483  return (off == s->off) ? 0 : -1;
484 }
485 
486 
487 static int http_buf_read(URLContext *h, uint8_t *buf, int size)
488 {
489  HTTPContext *s = h->priv_data;
490  int len;
491  /* read bytes from input buffer first */
492  len = s->buf_end - s->buf_ptr;
493  if (len > 0) {
494  if (len > size)
495  len = size;
496  memcpy(buf, s->buf_ptr, len);
497  s->buf_ptr += len;
498  } else {
499  if (!s->willclose && s->filesize >= 0 && s->off >= s->filesize)
500  return AVERROR_EOF;
501  len = ffurl_read(s->hd, buf, size);
502  }
503  if (len > 0) {
504  s->off += len;
505  if (s->chunksize > 0)
506  s->chunksize -= len;
507  }
508  return len;
509 }
510 
511 static int http_read(URLContext *h, uint8_t *buf, int size)
512 {
513  HTTPContext *s = h->priv_data;
514  int err, new_location;
515 
516  if (!s->hd)
517  return AVERROR_EOF;
518 
519  if (s->end_chunked_post && !s->end_header) {
520  err = http_read_header(h, &new_location);
521  if (err < 0)
522  return err;
523  }
524 
525  if (s->chunksize >= 0) {
526  if (!s->chunksize) {
527  char line[32];
528 
529  for(;;) {
530  do {
531  if ((err = http_get_line(s, line, sizeof(line))) < 0)
532  return err;
533  } while (!*line); /* skip CR LF from last chunk */
534 
535  s->chunksize = strtoll(line, NULL, 16);
536 
537  av_dlog(NULL, "Chunked encoding data size: %"PRId64"'\n", s->chunksize);
538 
539  if (!s->chunksize)
540  return 0;
541  break;
542  }
543  }
544  size = FFMIN(size, s->chunksize);
545  }
546  return http_buf_read(h, buf, size);
547 }
548 
549 /* used only when posting data */
550 static int http_write(URLContext *h, const uint8_t *buf, int size)
551 {
552  char temp[11] = ""; /* 32-bit hex + CRLF + nul */
553  int ret;
554  char crlf[] = "\r\n";
555  HTTPContext *s = h->priv_data;
556 
557  if (!s->chunked_post) {
558  /* non-chunked data is sent without any special encoding */
559  return ffurl_write(s->hd, buf, size);
560  }
561 
562  /* silently ignore zero-size data since chunk encoding that would
563  * signal EOF */
564  if (size > 0) {
565  /* upload data using chunked encoding */
566  snprintf(temp, sizeof(temp), "%x\r\n", size);
567 
568  if ((ret = ffurl_write(s->hd, temp, strlen(temp))) < 0 ||
569  (ret = ffurl_write(s->hd, buf, size)) < 0 ||
570  (ret = ffurl_write(s->hd, crlf, sizeof(crlf) - 1)) < 0)
571  return ret;
572  }
573  return size;
574 }
575 
576 static int http_shutdown(URLContext *h, int flags)
577 {
578  int ret = 0;
579  char footer[] = "0\r\n\r\n";
580  HTTPContext *s = h->priv_data;
581 
582  /* signal end of chunked encoding if used */
583  if ((flags & AVIO_FLAG_WRITE) && s->chunked_post) {
584  ret = ffurl_write(s->hd, footer, sizeof(footer) - 1);
585  ret = ret > 0 ? 0 : ret;
586  s->end_chunked_post = 1;
587  }
588 
589  return ret;
590 }
591 
592 static int http_close(URLContext *h)
593 {
594  int ret = 0;
595  HTTPContext *s = h->priv_data;
596 
597  if (!s->end_chunked_post) {
598  /* Close the write direction by sending the end of chunked encoding. */
599  ret = http_shutdown(h, h->flags);
600  }
601 
602  if (s->hd)
603  ffurl_close(s->hd);
604  return ret;
605 }
606 
607 static int64_t http_seek(URLContext *h, int64_t off, int whence)
608 {
609  HTTPContext *s = h->priv_data;
610  URLContext *old_hd = s->hd;
611  int64_t old_off = s->off;
612  uint8_t old_buf[BUFFER_SIZE];
613  int old_buf_size;
614 
615  if (whence == AVSEEK_SIZE)
616  return s->filesize;
617  else if ((s->filesize == -1 && whence == SEEK_END) || h->is_streamed)
618  return -1;
619 
620  /* we save the old context in case the seek fails */
621  old_buf_size = s->buf_end - s->buf_ptr;
622  memcpy(old_buf, s->buf_ptr, old_buf_size);
623  s->hd = NULL;
624  if (whence == SEEK_CUR)
625  off += s->off;
626  else if (whence == SEEK_END)
627  off += s->filesize;
628  s->off = off;
629 
630  /* if it fails, continue on old connection */
631  if (http_open_cnx(h) < 0) {
632  memcpy(s->buffer, old_buf, old_buf_size);
633  s->buf_ptr = s->buffer;
634  s->buf_end = s->buffer + old_buf_size;
635  s->hd = old_hd;
636  s->off = old_off;
637  return -1;
638  }
639  ffurl_close(old_hd);
640  return off;
641 }
642 
643 static int
645 {
646  HTTPContext *s = h->priv_data;
647  return ffurl_get_file_handle(s->hd);
648 }
649 
650 #if CONFIG_HTTP_PROTOCOL
651 URLProtocol ff_http_protocol = {
652  .name = "http",
653  .url_open = http_open,
654  .url_read = http_read,
655  .url_write = http_write,
656  .url_seek = http_seek,
657  .url_close = http_close,
658  .url_get_file_handle = http_get_file_handle,
659  .url_shutdown = http_shutdown,
660  .priv_data_size = sizeof(HTTPContext),
661  .priv_data_class = &http_context_class,
663 };
664 #endif
665 #if CONFIG_HTTPS_PROTOCOL
666 URLProtocol ff_https_protocol = {
667  .name = "https",
668  .url_open = http_open,
669  .url_read = http_read,
670  .url_write = http_write,
671  .url_seek = http_seek,
672  .url_close = http_close,
673  .url_get_file_handle = http_get_file_handle,
674  .url_shutdown = http_shutdown,
675  .priv_data_size = sizeof(HTTPContext),
676  .priv_data_class = &https_context_class,
678 };
679 #endif
680 
681 #if CONFIG_HTTPPROXY_PROTOCOL
682 static int http_proxy_close(URLContext *h)
683 {
684  HTTPContext *s = h->priv_data;
685  if (s->hd)
686  ffurl_close(s->hd);
687  return 0;
688 }
689 
690 static int http_proxy_open(URLContext *h, const char *uri, int flags)
691 {
692  HTTPContext *s = h->priv_data;
693  char hostname[1024], hoststr[1024];
694  char auth[1024], pathbuf[1024], *path;
695  char lower_url[100];
696  int port, ret = 0, attempts = 0;
697  HTTPAuthType cur_auth_type;
698  char *authstr;
699  int new_loc;
700 
701  h->is_streamed = 1;
702 
703  av_url_split(NULL, 0, auth, sizeof(auth), hostname, sizeof(hostname), &port,
704  pathbuf, sizeof(pathbuf), uri);
705  ff_url_join(hoststr, sizeof(hoststr), NULL, NULL, hostname, port, NULL);
706  path = pathbuf;
707  if (*path == '/')
708  path++;
709 
710  ff_url_join(lower_url, sizeof(lower_url), "tcp", NULL, hostname, port,
711  NULL);
712 redo:
713  ret = ffurl_open(&s->hd, lower_url, AVIO_FLAG_READ_WRITE,
714  &h->interrupt_callback, NULL);
715  if (ret < 0)
716  return ret;
717 
719  path, "CONNECT");
720  snprintf(s->buffer, sizeof(s->buffer),
721  "CONNECT %s HTTP/1.1\r\n"
722  "Host: %s\r\n"
723  "Connection: close\r\n"
724  "%s%s"
725  "\r\n",
726  path,
727  hoststr,
728  authstr ? "Proxy-" : "", authstr ? authstr : "");
729  av_freep(&authstr);
730 
731  if ((ret = ffurl_write(s->hd, s->buffer, strlen(s->buffer))) < 0)
732  goto fail;
733 
734  s->buf_ptr = s->buffer;
735  s->buf_end = s->buffer;
736  s->line_count = 0;
737  s->filesize = -1;
738  cur_auth_type = s->proxy_auth_state.auth_type;
739 
740  /* Note: This uses buffering, potentially reading more than the
741  * HTTP header. If tunneling a protocol where the server starts
742  * the conversation, we might buffer part of that here, too.
743  * Reading that requires using the proper ffurl_read() function
744  * on this URLContext, not using the fd directly (as the tls
745  * protocol does). This shouldn't be an issue for tls though,
746  * since the client starts the conversation there, so there
747  * is no extra data that we might buffer up here.
748  */
749  ret = http_read_header(h, &new_loc);
750  if (ret < 0)
751  goto fail;
752 
753  attempts++;
754  if (s->http_code == 407 &&
755  (cur_auth_type == HTTP_AUTH_NONE || s->proxy_auth_state.stale) &&
756  s->proxy_auth_state.auth_type != HTTP_AUTH_NONE && attempts < 2) {
757  ffurl_close(s->hd);
758  s->hd = NULL;
759  goto redo;
760  }
761 
762  if (s->http_code < 400)
763  return 0;
764  ret = AVERROR(EIO);
765 
766 fail:
767  http_proxy_close(h);
768  return ret;
769 }
770 
771 static int http_proxy_write(URLContext *h, const uint8_t *buf, int size)
772 {
773  HTTPContext *s = h->priv_data;
774  return ffurl_write(s->hd, buf, size);
775 }
776 
777 URLProtocol ff_httpproxy_protocol = {
778  .name = "httpproxy",
779  .url_open = http_proxy_open,
780  .url_read = http_buf_read,
781  .url_write = http_proxy_write,
782  .url_close = http_proxy_close,
783  .url_get_file_handle = http_get_file_handle,
784  .priv_data_size = sizeof(HTTPContext),
785  .flags = URL_PROTOCOL_FLAG_NETWORK,
786 };
787 #endif
static int http_get_line(HTTPContext *s, char *line, int line_size)
Definition: http.c:243
void av_url_split(char *proto, int proto_size, char *authorization, int authorization_size, char *hostname, int hostname_size, int *port_ptr, char *path, int path_size, const char *url)
Split a URL string into components.
Definition: utils.c:3173
static int http_open(URLContext *h, const char *uri, int flags)
Definition: http.c:209
static int http_connect(URLContext *h, const char *path, const char *local_path, const char *hoststr, const char *auth, const char *proxyauth, int *new_location)
Definition: http.c:377
struct HTTPContext HTTPContext
int size
#define URL_PROTOCOL_FLAG_NETWORK
Definition: url.h:35
uint8_t * post_data
Definition: http.c:59
AVOption.
Definition: opt.h:233
char location[MAX_URL_SIZE]
Definition: http.c:50
HTTPAuthType
Authentication types, ordered from weakest to strongest.
Definition: httpauth.h:28
#define BUFFER_SIZE
Definition: http.c:39
static int http_close(URLContext *h)
Definition: http.c:592
int ffurl_write(URLContext *h, const unsigned char *buf, int size)
Write size bytes from buf to the resource accessed by h.
Definition: avio.c:265
char * av_stristr(const char *s1, const char *s2)
Locate the first case-independent occurrence in the string haystack of the string needle...
Definition: avstring.c:54
int is_streamed
true if streamed (no seek possible), default = false
Definition: url.h:48
AVIOInterruptCB interrupt_callback
Definition: url.h:50
HTTPAuthState proxy_auth_state
Definition: http.c:52
int av_strncasecmp(const char *a, const char *b, size_t n)
Locale-independent case-insensitive compare.
Definition: avstring.c:150
int flags
Definition: url.h:46
av_dlog(ac->avr,"%d samples - audio_convert: %s to %s (%s)\n", len, av_get_sample_fmt_name(ac->in_fmt), av_get_sample_fmt_name(ac->out_fmt), use_generic?ac->func_descr_generic:ac->func_descr)
static int http_getc(HTTPContext *s)
Definition: http.c:226
HTTP Authentication state structure.
Definition: httpauth.h:55
int ff_url_join(char *str, int size, const char *proto, const char *authorization, const char *hostname, int port, const char *fmt,...) av_printf_format(7
Assemble a URL string from components.
void av_freep(void *arg)
Free a memory block which has been allocated with av_malloc(z)() or av_realloc() and set the pointer ...
Definition: mem.c:151
#define MAX_URL_SIZE
Definition: internal.h:27
int end_chunked_post
A flag which indicates if the end of chunked encoding has been sent.
Definition: http.c:56
int av_stristart(const char *str, const char *pfx, const char **ptr)
Return non-zero if pfx is a prefix of str independent of case.
Definition: avstring.c:43
static int http_get_file_handle(URLContext *h)
Definition: http.c:644
static int http_buf_read(URLContext *h, uint8_t *buf, int size)
Definition: http.c:487
uint8_t
int post_datalen
Definition: http.c:60
AVOptions.
miscellaneous OS support macros and functions.
static int http_read_header(URLContext *h, int *new_location)
Definition: http.c:352
static int flags
Definition: log.c:42
uint32_t tag
Definition: movenc.c:802
void ff_http_init_auth_state(URLContext *dest, const URLContext *src)
Initialize the authentication state based on another HTTP URLContext.
Definition: http.c:88
int line_count
Definition: http.c:46
static int http_open_cnx(URLContext *h)
Definition: http.c:98
unsigned char * buf_end
Definition: http.c:45
int chunked_post
Definition: http.c:55
#define E
Definition: http.c:65
static int http_write(URLContext *h, const uint8_t *buf, int size)
Definition: http.c:550
static const AVOption options[]
Definition: http.c:66
Definition: graph2dot.c:48
void av_log(void *avcl, int level, const char *fmt,...)
Definition: log.c:146
#define OFFSET(x)
Definition: http.c:63
size_t av_strlcpy(char *dst, const char *src, size_t size)
Copy the string src to dst, but no more than size - 1 bytes, and null-terminate dst.
Definition: avstring.c:67
int off
Definition: dsputil_bfin.c:28
char * headers
Definition: http.c:53
int64_t off
Definition: http.c:49
int av_strcasecmp(const char *a, const char *b)
Definition: avstring.c:140
int willclose
Set if the server correctly handles Connection: close and will close the connection after feeding us ...
Definition: http.c:54
static char buffer[20]
Definition: seek-test.c:31
int ffurl_get_file_handle(URLContext *h)
Return the file descriptor associated with this URL.
Definition: avio.c:340
int stale
Auth ok, but needs to be resent with a new nonce.
Definition: httpauth.h:71
offset must point to a pointer immediately followed by an int for the length
Definition: opt.h:226
NULL
Definition: eval.c:52
static int http_read(URLContext *h, uint8_t *buf, int size)
Definition: http.c:511
Definition: url.h:41
Describe the class of an AVClass context structure.
Definition: log.h:33
#define SPACE_CHARS
Definition: internal.h:177
void * priv_data
Definition: url.h:44
size_t av_strlcatf(char *dst, size_t size, const char *fmt,...)
Definition: avstring.c:85
char * ff_http_auth_create_response(HTTPAuthState *state, const char *auth, const char *path, const char *method)
Definition: httpauth.c:243
const char * name
Definition: url.h:54
URLContext * hd
Definition: http.c:44
static int has_header(const char *str, const char *header)
Definition: http.c:344
int ffurl_close(URLContext *h)
Close the resource accessed by the URLContext h, and free the memory used by it.
Definition: avio.c:286
static int process_line(URLContext *h, char *line, int line_count, int *new_location)
Definition: http.c:267
int ff_http_do_new_request(URLContext *h, const char *uri)
Send a new HTTP request, reusing the old connection.
Definition: http.c:199
int av_strstart(const char *str, const char *pfx, const char **ptr)
Return non-zero if pfx is a prefix of str.
Definition: avstring.c:32
Main libavformat public API header.
#define MAX_REDIRECTS
Definition: http.c:40
int ffurl_open(URLContext **puc, const char *filename, int flags, const AVIOInterruptCB *int_cb, AVDictionary **options)
Create an URLContext for accessing to the resource indicated by url, and open it. ...
Definition: avio.c:203
int http_code
Definition: http.c:47
void ff_http_auth_handle_header(HTTPAuthState *state, const char *key, const char *value)
Definition: httpauth.c:91
int multiple_requests
A flag which indicates if we use persistent connections.
Definition: http.c:58
HTTPAuthState auth_state
Definition: http.c:51
int len
uint8_t * buffer
Definition: avserver.c:166
int64_t filesize
Definition: http.c:49
static int http_shutdown(URLContext *h, int flags)
Definition: http.c:576
int end_header
A flag which indicates we have finished to read POST reply.
Definition: http.c:57
unsigned char * buf_ptr
Definition: http.c:45
#define D
Definition: http.c:64
HTTPAuthType auth_type
The currently chosen auth type.
Definition: httpauth.h:59
unbuffered private I/O API
static int64_t http_seek(URLContext *h, int64_t off, int whence)
Definition: http.c:607
int ffurl_read(URLContext *h, unsigned char *buf, int size)
Read up to size bytes from the resource accessed by h, and store the read bytes in buf...
Definition: avio.c:251
int64_t chunksize
Used if "Transfer-Encoding: chunked" otherwise -1.
Definition: http.c:48
#define HTTP_CLASS(flavor)
Definition: http.c:73
No authentication specified.
Definition: httpauth.h:29