#include "http.h"
#include "os_support.h"
#include "httpauth.h"
+#include "libavutil/opt.h"
/* XXX: POST protocol is not completely implemented because ffmpeg uses
only a subset of it. */
/* used for protocol handling */
#define BUFFER_SIZE 1024
-#define URL_SIZE 4096
#define MAX_REDIRECTS 8
typedef struct {
+ const AVClass *class;
URLContext *hd;
unsigned char buffer[BUFFER_SIZE], *buf_ptr, *buf_end;
int line_count;
int http_code;
int64_t chunksize; /**< Used if "Transfer-Encoding: chunked" otherwise -1. */
int64_t off, filesize;
- char location[URL_SIZE];
+ char location[MAX_URL_SIZE];
HTTPAuthState auth_state;
- int init;
unsigned char headers[BUFFER_SIZE];
+ int willclose; /**< Set if the server correctly handles Connection: close and will close the connection after feeding us the content. */
} HTTPContext;
+#define OFFSET(x) offsetof(HTTPContext, x)
+static const AVOption options[] = {
+{"chunksize", "use chunked transfer-encoding for posts, -1 disables it, 0 enables it", OFFSET(chunksize), FF_OPT_TYPE_INT64, 0, -1, 0 }, /* Default to 0, for chunked POSTs */
+{NULL}
+};
+static const AVClass httpcontext_class = {
+ "HTTP", av_default_item_name, options, LIBAVUTIL_VERSION_INT
+};
+
static int http_connect(URLContext *h, const char *path, const char *hoststr,
const char *auth, int *new_location);
HTTPContext *s = h->priv_data;
URLContext *hd = NULL;
- s->init = 1;
proxy_path = getenv("http_proxy");
use_proxy = (proxy_path != NULL) && !getenv("no_proxy") &&
av_strstart(proxy_path, "http://", NULL);
/* fill the dest addr */
redo:
/* needed in any case to build the host string */
- ff_url_split(NULL, 0, auth, sizeof(auth), hostname, sizeof(hostname), &port,
+ av_url_split(NULL, 0, auth, sizeof(auth), hostname, sizeof(hostname), &port,
path1, sizeof(path1), s->location);
ff_url_join(hoststr, sizeof(hoststr), NULL, NULL, hostname, port, NULL);
if (use_proxy) {
- ff_url_split(NULL, 0, auth, sizeof(auth), hostname, sizeof(hostname), &port,
+ av_url_split(NULL, 0, auth, sizeof(auth), hostname, sizeof(hostname), &port,
NULL, 0, proxy_path);
path = s->location;
} else {
} else
goto fail;
}
- if ((s->http_code == 302 || s->http_code == 303) && location_changed == 1) {
+ if ((s->http_code == 301 || s->http_code == 302 || s->http_code == 303 || s->http_code == 307)
+ && location_changed == 1) {
/* url moved, get next */
url_close(hd);
if (redirects++ >= MAX_REDIRECTS)
h->is_streamed = 1;
s->filesize = -1;
- s->chunksize = 0; /* Default to chunked POSTs */
- av_strlcpy(s->location, uri, URL_SIZE);
+ av_strlcpy(s->location, uri, sizeof(s->location));
- return 0;
+ return http_open_cnx(h);
}
static int http_getc(HTTPContext *s)
{
int *new_location)
{
HTTPContext *s = h->priv_data;
- char *tag, *p;
+ char *tag, *p, *end;
/* end of header */
if (line[0] == '\0')
p++;
while (isspace(*p))
p++;
- s->http_code = strtol(p, NULL, 10);
+ s->http_code = strtol(p, &end, 10);
dprintf(NULL, "http_code=%d\n", s->http_code);
/* error codes are 4xx and 5xx, but regard 401 as a success, so we
* don't abort until all headers have been parsed. */
- if (s->http_code >= 400 && s->http_code < 600 && s->http_code != 401)
+ if (s->http_code >= 400 && s->http_code < 600 && s->http_code != 401) {
+ end += strspn(end, SPACE_CHARS);
+ av_log(NULL, AV_LOG_WARNING, "HTTP error %d %s\n",
+ s->http_code, end);
return -1;
+ }
} else {
while (*p != '\0' && *p != ':')
p++;
ff_http_auth_handle_header(&s->auth_state, tag, p);
} else if (!strcmp (tag, "Authentication-Info")) {
ff_http_auth_handle_header(&s->auth_state, tag, p);
+ } else if (!strcmp (tag, "Connection")) {
+ if (!strcmp(p, "close"))
+ s->willclose = 1;
}
}
return 1;
s->line_count = 0;
s->off = 0;
s->filesize = -1;
+ s->willclose = 0;
if (post) {
/* Pretend that it did work. We didn't read any header yet, since
* we've still to send the POST data, but the code calling this
HTTPContext *s = h->priv_data;
int len;
- if (!s->init) {
- int ret = http_open_cnx(h);
- if (ret != 0)
- return ret;
- }
- if (!s->hd)
- return AVERROR(EIO);
-
- /* A size of zero can be used to force
- * initializaton of the connection. */
- if (!size)
- return 0;
-
if (s->chunksize >= 0) {
if (!s->chunksize) {
char line[32];
memcpy(buf, s->buf_ptr, len);
s->buf_ptr += len;
} else {
+ if (!s->willclose && s->filesize >= 0 && s->off >= s->filesize)
+ return AVERROR_EOF;
len = url_read(s->hd, buf, size);
}
if (len > 0) {
char crlf[] = "\r\n";
HTTPContext *s = h->priv_data;
- if (!s->init) {
- int ret = http_open_cnx(h);
- if (ret != 0)
- return ret;
- }
- if (!s->hd)
- return AVERROR(EIO);
-
if (s->chunksize == -1) {
/* non-chunked data is sent without any special encoding */
return url_write(s->hd, buf, size);
uint8_t old_buf[BUFFER_SIZE];
int old_buf_size;
- if (!s->init) {
- int ret = http_open_cnx(h);
- if (ret != 0)
- return ret;
- }
- if (!s->hd)
- return AVERROR(EIO);
-
if (whence == AVSEEK_SIZE)
return s->filesize;
else if ((s->filesize == -1 && whence == SEEK_END) || h->is_streamed)
return url_get_file_handle(s->hd);
}
-URLProtocol http_protocol = {
+URLProtocol ff_http_protocol = {
"http",
http_open,
http_read,
http_close,
.url_get_file_handle = http_get_file_handle,
.priv_data_size = sizeof(HTTPContext),
+ .priv_data_class = &httpcontext_class,
};