|
|
|
@@ -578,3 +578,118 @@ URLProtocol ff_https_protocol = { |
|
|
|
.priv_data_class = &https_context_class, |
|
|
|
}; |
|
|
|
#endif |
|
|
|
|
|
|
|
#if CONFIG_HTTPPROXY_PROTOCOL |
|
|
|
static int http_proxy_close(URLContext *h) |
|
|
|
{ |
|
|
|
HTTPContext *s = h->priv_data; |
|
|
|
if (s->hd) |
|
|
|
ffurl_close(s->hd); |
|
|
|
return 0; |
|
|
|
} |
|
|
|
|
|
|
|
static int http_proxy_open(URLContext *h, const char *uri, int flags) |
|
|
|
{ |
|
|
|
HTTPContext *s = h->priv_data; |
|
|
|
char hostname[1024], hoststr[1024]; |
|
|
|
char auth[1024], pathbuf[1024], *path; |
|
|
|
char line[1024], lower_url[100]; |
|
|
|
int port, ret = 0; |
|
|
|
HTTPAuthType cur_auth_type; |
|
|
|
char *authstr; |
|
|
|
|
|
|
|
h->is_streamed = 1; |
|
|
|
|
|
|
|
av_url_split(NULL, 0, auth, sizeof(auth), hostname, sizeof(hostname), &port, |
|
|
|
pathbuf, sizeof(pathbuf), uri); |
|
|
|
ff_url_join(hoststr, sizeof(hoststr), NULL, NULL, hostname, port, NULL); |
|
|
|
path = pathbuf; |
|
|
|
if (*path == '/') |
|
|
|
path++; |
|
|
|
|
|
|
|
ff_url_join(lower_url, sizeof(lower_url), "tcp", NULL, hostname, port, |
|
|
|
NULL); |
|
|
|
redo: |
|
|
|
ret = ffurl_open(&s->hd, lower_url, AVIO_FLAG_READ_WRITE, |
|
|
|
&h->interrupt_callback, NULL); |
|
|
|
if (ret < 0) |
|
|
|
return ret; |
|
|
|
|
|
|
|
authstr = ff_http_auth_create_response(&s->proxy_auth_state, auth, |
|
|
|
path, "CONNECT"); |
|
|
|
snprintf(s->buffer, sizeof(s->buffer), |
|
|
|
"CONNECT %s HTTP/1.1\r\n" |
|
|
|
"Host: %s\r\n" |
|
|
|
"Connection: close\r\n" |
|
|
|
"%s%s" |
|
|
|
"\r\n", |
|
|
|
path, |
|
|
|
hoststr, |
|
|
|
authstr ? "Proxy-" : "", authstr ? authstr : ""); |
|
|
|
av_freep(&authstr); |
|
|
|
|
|
|
|
if ((ret = ffurl_write(s->hd, s->buffer, strlen(s->buffer))) < 0) |
|
|
|
goto fail; |
|
|
|
|
|
|
|
s->buf_ptr = s->buffer; |
|
|
|
s->buf_end = s->buffer; |
|
|
|
s->line_count = 0; |
|
|
|
s->filesize = -1; |
|
|
|
cur_auth_type = s->proxy_auth_state.auth_type; |
|
|
|
|
|
|
|
for (;;) { |
|
|
|
int new_loc; |
|
|
|
// Note: This uses buffering, potentially reading more than the |
|
|
|
// HTTP header. If tunneling a protocol where the server starts |
|
|
|
// the conversation, we might buffer part of that here, too. |
|
|
|
// Reading that requires using the proper ffurl_read() function |
|
|
|
// on this URLContext, not using the fd directly (as the tls |
|
|
|
// protocol does). This shouldn't be an issue for tls though, |
|
|
|
// since the client starts the conversation there, so there |
|
|
|
// is no extra data that we might buffer up here. |
|
|
|
if (http_get_line(s, line, sizeof(line)) < 0) { |
|
|
|
ret = AVERROR(EIO); |
|
|
|
goto fail; |
|
|
|
} |
|
|
|
|
|
|
|
av_dlog(h, "header='%s'\n", line); |
|
|
|
|
|
|
|
ret = process_line(h, line, s->line_count, &new_loc); |
|
|
|
if (ret < 0) |
|
|
|
goto fail; |
|
|
|
if (ret == 0) |
|
|
|
break; |
|
|
|
s->line_count++; |
|
|
|
} |
|
|
|
if (s->http_code == 407 && cur_auth_type == HTTP_AUTH_NONE && |
|
|
|
s->proxy_auth_state.auth_type != HTTP_AUTH_NONE) { |
|
|
|
ffurl_close(s->hd); |
|
|
|
s->hd = NULL; |
|
|
|
goto redo; |
|
|
|
} |
|
|
|
|
|
|
|
if (s->http_code < 400) |
|
|
|
return 0; |
|
|
|
ret = AVERROR(EIO); |
|
|
|
|
|
|
|
fail: |
|
|
|
http_proxy_close(h); |
|
|
|
return ret; |
|
|
|
} |
|
|
|
|
|
|
|
static int http_proxy_write(URLContext *h, const uint8_t *buf, int size) |
|
|
|
{ |
|
|
|
HTTPContext *s = h->priv_data; |
|
|
|
return ffurl_write(s->hd, buf, size); |
|
|
|
} |
|
|
|
|
|
|
|
URLProtocol ff_httpproxy_protocol = { |
|
|
|
.name = "httpproxy", |
|
|
|
.url_open = http_proxy_open, |
|
|
|
.url_read = http_buf_read, |
|
|
|
.url_write = http_proxy_write, |
|
|
|
.url_close = http_proxy_close, |
|
|
|
.url_get_file_handle = http_get_file_handle, |
|
|
|
.priv_data_size = sizeof(HTTPContext), |
|
|
|
}; |
|
|
|
#endif |