summaryrefslogtreecommitdiff
path: root/libavformat/http.c
diff options
context:
space:
mode:
authorMartin Storsjö <martin@martin.st>2013-10-09 13:24:40 +0300
committerMartin Storsjö <martin@martin.st>2013-10-13 12:59:03 +0300
commit71549a857b13edf4c4f95037de6ed5bb4c4bd4af (patch)
tree95e0825c3d800c896bcc4fc075306084bdbb891b /libavformat/http.c
parenteb8b05a3824a9fa85e20d603595ac8a3b83505d4 (diff)
http: Support auth method detection for POST
Inspired by a patch by Jakob van Bethlehem. But instead of doing an empty POST first to trigger the WWW-Authenticate header (which would succeed if no auth actually was required), add an Expect: 100-continue header, which is meant to be used exactly for cases like this. The header is added if doing a post, and the user has specified authentication but we don't know the auth method yet. Not all common HTTP servers support the Expect: 100-continue header, though, so we only try to use it when it really is needed. The user can request it to be added for other POST requests as well via an option - which would allow the caller to know immediately that the POST has failed (e.g. if no auth was provided but the server required it, or if the target URL simply doesn't exist). This is only done for write mode posts (e.g. posts without pre-set post_data) - for posts with pre-set data, we can just redo the post if it failed due to 401. Signed-off-by: Martin Storsjö <martin@martin.st>
Diffstat (limited to 'libavformat/http.c')
-rw-r--r--libavformat/http.c18
1 files changed, 17 insertions, 1 deletions
diff --git a/libavformat/http.c b/libavformat/http.c
index 890150b9b1..2e43dd627d 100644
--- a/libavformat/http.c
+++ b/libavformat/http.c
@@ -68,6 +68,7 @@ typedef struct {
uint8_t *inflate_buffer;
#endif
AVDictionary *chained_options;
+ int send_expect_100;
} HTTPContext;
#define OFFSET(x) offsetof(HTTPContext, x)
@@ -81,6 +82,7 @@ static const AVOption options[] = {
{"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" },
{"none", "No auth method set, autodetect", 0, AV_OPT_TYPE_CONST, {.i64 = HTTP_AUTH_NONE}, 0, 0, D|E, "auth_type" },
{"basic", "HTTP basic authentication", 0, AV_OPT_TYPE_CONST, {.i64 = HTTP_AUTH_BASIC}, 0, 0, D|E, "auth_type" },
+{"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, "auth_type" },
{NULL}
};
#define HTTP_CLASS(flavor)\
@@ -435,6 +437,7 @@ static int http_connect(URLContext *h, const char *path, const char *local_path,
int64_t off = s->off;
int len = 0;
const char *method;
+ int send_expect_100 = 0;
/* send http header */
@@ -452,6 +455,16 @@ static int http_connect(URLContext *h, const char *path, const char *local_path,
method);
proxyauthstr = ff_http_auth_create_response(&s->proxy_auth_state, proxyauth,
local_path, method);
+ if (post && !s->post_data) {
+ send_expect_100 = s->send_expect_100;
+ /* The user has supplied authentication but we don't know the auth type,
+ * send Expect: 100-continue to get the 401 response including the
+ * WWW-Authenticate header, or an 100 continue if no auth actually
+ * is needed. */
+ if (auth && s->auth_state.auth_type == HTTP_AUTH_NONE &&
+ s->http_code != 401)
+ send_expect_100 = 1;
+ }
/* set default headers if needed */
if (!has_header(s->headers, "\r\nUser-Agent: "))
@@ -463,6 +476,9 @@ static int http_connect(URLContext *h, const char *path, const char *local_path,
if (!has_header(s->headers, "\r\nRange: ") && !post)
len += av_strlcatf(headers + len, sizeof(headers) - len,
"Range: bytes=%"PRId64"-\r\n", s->off);
+ if (send_expect_100 && !has_header(s->headers, "\r\nExpect: "))
+ len += av_strlcatf(headers + len, sizeof(headers) - len,
+ "Expect: 100-continue\r\n");
if (!has_header(s->headers, "\r\nConnection: ")) {
if (s->multiple_requests) {
@@ -517,7 +533,7 @@ static int http_connect(URLContext *h, const char *path, const char *local_path,
s->willclose = 0;
s->end_chunked_post = 0;
s->end_header = 0;
- if (post && !s->post_data) {
+ if (post && !s->post_data && !send_expect_100) {
/* 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
* function will check http_code after we return. */