X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;f=libavformat%2Fhttp.c;h=53bdb985f0598791991afbc18cb97b981638a7ac;hb=a7e7c68b0e264f5db15bbbf9fb3cd557cc58e927;hp=4f6716a75bd75c0ae1c65810525407e55abd0210;hpb=c140227a8bbc2699b724c9076dc706400eb5cccd;p=ffmpeg diff --git a/libavformat/http.c b/libavformat/http.c index 4f6716a75bd..53bdb985f05 100644 --- a/libavformat/http.c +++ b/libavformat/http.c @@ -126,7 +126,7 @@ static const AVOption options[] = { { "location", "The actual location of the data received", OFFSET(location), AV_OPT_TYPE_STRING, { 0 }, 0, 0, D | E }, { "offset", "initial byte offset", OFFSET(off), AV_OPT_TYPE_INT64, { .i64 = 0 }, 0, INT64_MAX, D }, { "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 }, - { "method", "Override the HTTP method", OFFSET(method), AV_OPT_TYPE_STRING, { .str = NULL }, 0, 0, E }, + { "method", "Override the HTTP method or set the expected HTTP method from a client", OFFSET(method), AV_OPT_TYPE_STRING, { .str = NULL }, 0, 0, D | E }, { "reconnect", "auto reconnect after disconnect before EOF", OFFSET(reconnect), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, 1, D }, { "listen", "listen on HTTP", OFFSET(listen), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, 1, D | E }, { NULL } @@ -299,6 +299,23 @@ int ff_http_averror(int status_code, int default_averror) return default_averror; } +static void handle_http_errors(URLContext *h, int error) +{ + static const char bad_request[] = "HTTP/1.1 400 Bad Request\r\nContent-Type: text/plain\r\n\r\n400 Bad Request\r\n"; + static const char internal_server_error[] = "HTTP/1.1 500 Internal server error\r\nContent-Type: text/plain\r\n\r\n500 Internal server error\r\n"; + HTTPContext *s = h->priv_data; + if (h->is_connected) { + switch(error) { + case AVERROR_HTTP_BAD_REQUEST: + ffurl_write(s->hd, bad_request, strlen(bad_request)); + break; + default: + av_log(h, AV_LOG_ERROR, "Unhandled HTTP error.\n"); + ffurl_write(s->hd, internal_server_error, strlen(internal_server_error)); + } + } +} + static int http_listen(URLContext *h, const char *uri, int flags, AVDictionary **options) { HTTPContext *s = h->priv_data; @@ -318,13 +335,14 @@ static int http_listen(URLContext *h, const char *uri, int flags, if ((ret = ffurl_open(&s->hd, lower_url, AVIO_FLAG_READ_WRITE, &h->interrupt_callback, options)) < 0) goto fail; - if ((ret = ffurl_write(s->hd, header, strlen(header))) < 0) - goto fail; if ((ret = http_read_header(h, &new_location)) < 0) goto fail; + if ((ret = ffurl_write(s->hd, header, strlen(header))) < 0) + goto fail; return 0; fail: + handle_http_errors(h, ret); av_dict_free(&s->chained_options); return ret; } @@ -545,7 +563,7 @@ static int process_line(URLContext *h, char *line, int line_count, int *new_location) { HTTPContext *s = h->priv_data; - char *tag, *p, *end; + char *tag, *p, *end, *method, *resource, *version; int ret; /* end of header */ @@ -556,6 +574,44 @@ static int process_line(URLContext *h, char *line, int line_count, p = line; if (line_count == 0) { + if (s->listen) { + // HTTP method + method = p; + while (!av_isspace(*p)) + p++; + *(p++) = '\0'; + av_log(h, AV_LOG_TRACE, "Received method: %s\n", method); + if (s->method) { + if (av_strcasecmp(s->method, method)) { + av_log(h, AV_LOG_ERROR, "Received and expected HTTP method do not match. (%s expected, %s received)\n", + s->method, method); + return ff_http_averror(400, AVERROR(EIO)); + } + } + + // HTTP resource + while (av_isspace(*p)) + p++; + resource = p; + while (!av_isspace(*p)) + p++; + *(p++) = '\0'; + av_log(h, AV_LOG_TRACE, "Requested resource: %s\n", resource); + + // HTTP version + while (av_isspace(*p)) + p++; + version = p; + while (!av_isspace(*p)) + p++; + *p = '\0'; + if (av_strncasecmp(version, "HTTP/", 5)) { + av_log(h, AV_LOG_ERROR, "Malformed HTTP version string.\n"); + return ff_http_averror(400, AVERROR(EIO)); + } + av_log(h, AV_LOG_TRACE, "HTTP version string: %s\n", version); + } else { + /* TODO: reindent */ while (!av_isspace(*p) && *p != '\0') p++; while (av_isspace(*p)) @@ -566,6 +622,7 @@ static int process_line(URLContext *h, char *line, int line_count, if ((ret = check_http_code(h, s->http_code, end)) < 0) return ret; + } } else { while (*p != '\0' && *p != ':') p++;