On Wed, Jun 3, 2015 at 10:39 PM, Nicolas George <geo...@nsup.org> wrote: > http_listen(), you wrote it yourself. Maybe I was not clear enough, I just > suggested to move the code in a function for better readability (the name of > the function is self-documentating), nothing more complicated.
I hope I understood what you meant. >> From 3af5c5867672624d45de447d11c2107b3c77742c Mon Sep 17 00:00:00 2001 >> From: Stephan Holljes <klaxa1...@googlemail.com> >> Date: Wed, 3 Jun 2015 20:57:53 +0200 >> Subject: [PATCH 5/5] lavf/http: Indent else-clause. >> >> Signed-off-by: Stephan Holljes <klaxa1...@googlemail.com> >> --- >> libavformat/http.c | 16 ++++++++-------- >> 1 file changed, 8 insertions(+), 8 deletions(-) > > This looks ok. > > Personally, I have the habit of inserting "/* TODO reindent */" in the code > where it is needed and only make the reindent patch at the last moment, to > reduce rebase nuisance. The order of the patches attached was reversed, maybe that's why it looked like the indentation was done first. > >> From 90f17ce9711304228bc3b7bf8cb4cdfac6b14011 Mon Sep 17 00:00:00 2001 >> From: Stephan Holljes <klaxa1...@googlemail.com> >> Date: Wed, 3 Jun 2015 20:57:23 +0200 >> Subject: [PATCH 4/5] lavf/http: Properly process HTTP header on listen. >> >> Signed-off-by: Stephan Holljes <klaxa1...@googlemail.com> >> --- >> libavformat/http.c | 44 +++++++++++++++++++++++++++++++++++++++++++- >> 1 file changed, 43 insertions(+), 1 deletion(-) >> >> diff --git a/libavformat/http.c b/libavformat/http.c >> index 6fad584..dfe2616 100644 >> --- a/libavformat/http.c >> +++ b/libavformat/http.c >> @@ -558,7 +558,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 */ >> @@ -569,6 +569,47 @@ static int process_line(URLContext *h, char *line, int >> line_count, >> >> p = line; >> if (line_count == 0) { >> + if (s->listen) { >> + // HTTP method > >> + while (av_isspace(*p)) >> + p++; > > I believe spaces are not allowed before the request. Fixed. > >> + method = p; >> + while (!av_isspace(*p)) >> + p++; > >> + *p = '\0'; > > Plain 0 is acceptable, your choice. The rest of the function uses '\0' and I wanted to keep it consistent. > >> + 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)); >> + } >> + } > >> + p++; > > Maybe better keep it grouped with "*p = 0", possibly in a single step: > *(p++) = 0. Fixed. > >> + >> + // HTTP resource >> + while (av_isspace(*p)) >> + p++; >> + resource = p; >> + while (!av_isspace(*p)) >> + p++; >> + *p = '\0'; >> + p++; >> + 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 { >> while (!av_isspace(*p) && *p != '\0') >> p++; >> while (av_isspace(*p)) >> @@ -579,6 +620,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++; >> -- >> 2.1.0 >> > >> From bbe015d20c1852e7c0c8885ca49a8ba2d926911d Mon Sep 17 00:00:00 2001 >> From: Stephan Holljes <klaxa1...@googlemail.com> >> Date: Wed, 3 Jun 2015 20:45:08 +0200 >> Subject: [PATCH 3/5] lavf/http: Rudimentary error handling for HTTP requests >> received from clients. >> >> Signed-off-by: Stephan Holljes <klaxa1...@googlemail.com> >> --- >> libavformat/http.c | 13 +++++++++++++ >> 1 file changed, 13 insertions(+) >> >> diff --git a/libavformat/http.c b/libavformat/http.c >> index e51f524..6fad584 100644 >> --- a/libavformat/http.c >> +++ b/libavformat/http.c >> @@ -304,6 +304,9 @@ static int http_listen(URLContext *h, const char *uri, >> int flags, >> HTTPContext *s = h->priv_data; >> int ret; >> static const char header[] = "HTTP/1.1 200 OK\r\nContent-Type: >> application/octet-stream\r\nTransfer-Encoding: chunked\r\n\r\n"; >> + 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"; >> + >> char hostname[1024], proto[10]; >> char lower_url[100]; >> const char *lower_proto = "tcp"; >> @@ -325,6 +328,16 @@ static int http_listen(URLContext *h, const char *uri, >> int flags, >> return 0; >> >> fail: >> + if (h->is_connected) { >> + switch(ret) { >> + case AVERROR_HTTP_BAD_REQUEST: >> + ffurl_write(s->hd, bad_request, strlen(bad_request)); >> + break; >> + default: > >> + av_log(h, AV_LOG_ERROR, "Internal server error.\n"); > > "Unhandled HTTP error"? Your choice. > >> + ffurl_write(s->hd, internal_server_error, >> strlen(internal_server_error)); >> + } >> + } >> av_dict_free(&s->chained_options); >> return ret; >> } >> -- >> 2.1.0 >> > >> From a1a13c83724f3b2ec0ee46efbf6e84e123e5538d Mon Sep 17 00:00:00 2001 >> From: Stephan Holljes <klaxa1...@googlemail.com> >> Date: Wed, 3 Jun 2015 20:41:50 +0200 >> Subject: [PATCH 2/5] lavf/http: Process HTTP header before sending response. >> >> Signed-off-by: Stephan Holljes <klaxa1...@googlemail.com> >> --- >> libavformat/http.c | 4 ++-- >> 1 file changed, 2 insertions(+), 2 deletions(-) > > LGTM. Will test when time permits. > >> From 40cd84a08ab76fcf5d22e6ca47e3aa3cb4bc0bc1 Mon Sep 17 00:00:00 2001 >> From: Stephan Holljes <klaxa1...@googlemail.com> >> Date: Wed, 3 Jun 2015 20:26:37 +0200 >> Subject: [PATCH 1/5] lavf/http: Document method option. >> >> Signed-off-by: Stephan Holljes <klaxa1...@googlemail.com> >> --- >> doc/protocols.texi | 9 +++++++++ >> libavformat/http.c | 2 +- >> 2 files changed, 10 insertions(+), 1 deletion(-) >> >> diff --git a/doc/protocols.texi b/doc/protocols.texi >> index f822d81..3a4dbb0 100644 >> --- a/doc/protocols.texi >> +++ b/doc/protocols.texi >> @@ -278,6 +278,15 @@ Set initial byte offset. >> @item end_offset >> Try to limit the request to bytes preceding this offset. >> >> +@item method >> +When used as a client option it sets the HTTP method for the request. >> + >> +When used as a server option it sets the HTTP method that is going to be >> +expected from the client(s). >> +If the expected and the received HTTP method do not match the client will >> +be given a Bad Request response. > >> +When unset the HTTP method is not checked. > > Maybe add something like "not checked for now" or "but this may change", so > that people will not start relying on it. But this is very minor. Also fixed. > >> + >> @item listen >> If set to 1 enables experimental HTTP server. This can be used to send data >> when >> used as an output option, or read data from a client with HTTP POST when >> used as >> diff --git a/libavformat/http.c b/libavformat/http.c >> index 4f6716a..546741a 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 } > > LGTM apart from that. > > Regards, > > -- > Nicolas George > > _______________________________________________ > ffmpeg-devel mailing list > ffmpeg-devel@ffmpeg.org > http://ffmpeg.org/mailman/listinfo/ffmpeg-devel >
From 5ec28499e32ede262c690c556aef5e54fd3ef5d7 Mon Sep 17 00:00:00 2001 From: Stephan Holljes <klaxa1...@googlemail.com> Date: Thu, 4 Jun 2015 01:16:59 +0200 Subject: [PATCH 1/5] lavf/http: Document method option. Signed-off-by: Stephan Holljes <klaxa1...@googlemail.com> --- doc/protocols.texi | 10 ++++++++++ libavformat/http.c | 2 +- 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/doc/protocols.texi b/doc/protocols.texi index f822d81..453dbcf 100644 --- a/doc/protocols.texi +++ b/doc/protocols.texi @@ -278,6 +278,16 @@ Set initial byte offset. @item end_offset Try to limit the request to bytes preceding this offset. +@item method +When used as a client option it sets the HTTP method for the request. + +When used as a server option it sets the HTTP method that is going to be +expected from the client(s). +If the expected and the received HTTP method do not match the client will +be given a Bad Request response. +When unset the HTTP method is not checked for now. This will be replaced by +autodetection in the future. + @item listen If set to 1 enables experimental HTTP server. This can be used to send data when used as an output option, or read data from a client with HTTP POST when used as diff --git a/libavformat/http.c b/libavformat/http.c index 4f6716a..546741a 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 } -- 2.1.0
From 6e3f560af5f8d9c87154f60c5de0e66eada26b63 Mon Sep 17 00:00:00 2001 From: Stephan Holljes <klaxa1...@googlemail.com> Date: Thu, 4 Jun 2015 01:17:51 +0200 Subject: [PATCH 2/5] lavf/http: Process HTTP header before sending response. Signed-off-by: Stephan Holljes <klaxa1...@googlemail.com> --- libavformat/http.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libavformat/http.c b/libavformat/http.c index 546741a..e51f524 100644 --- a/libavformat/http.c +++ b/libavformat/http.c @@ -318,10 +318,10 @@ 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: -- 2.1.0
From 500462610f1389a4e8dfa76ca4598500691ea6a7 Mon Sep 17 00:00:00 2001 From: Stephan Holljes <klaxa1...@googlemail.com> Date: Thu, 4 Jun 2015 01:20:28 +0200 Subject: [PATCH 3/5] lavf/http: Rudimentary error handling for HTTP requests received from clients. Signed-off-by: Stephan Holljes <klaxa1...@googlemail.com> --- libavformat/http.c | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/libavformat/http.c b/libavformat/http.c index e51f524..965967d 100644 --- a/libavformat/http.c +++ b/libavformat/http.c @@ -299,11 +299,28 @@ 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; int ret; static const char header[] = "HTTP/1.1 200 OK\r\nContent-Type: application/octet-stream\r\nTransfer-Encoding: chunked\r\n\r\n"; + char hostname[1024], proto[10]; char lower_url[100]; const char *lower_proto = "tcp"; @@ -325,6 +342,7 @@ static int http_listen(URLContext *h, const char *uri, int flags, return 0; fail: + handle_http_errors(h, ret); av_dict_free(&s->chained_options); return ret; } -- 2.1.0
From 986e5fe885ec267357855702c3075db1fea944e5 Mon Sep 17 00:00:00 2001 From: Stephan Holljes <klaxa1...@googlemail.com> Date: Thu, 4 Jun 2015 01:21:02 +0200 Subject: [PATCH 4/5] lavf/http: Properly process HTTP header on listen. Signed-off-by: Stephan Holljes <klaxa1...@googlemail.com> --- libavformat/http.c | 41 ++++++++++++++++++++++++++++++++++++++++- 1 file changed, 40 insertions(+), 1 deletion(-) diff --git a/libavformat/http.c b/libavformat/http.c index 965967d..b841f3f 100644 --- a/libavformat/http.c +++ b/libavformat/http.c @@ -563,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 */ @@ -574,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)) @@ -584,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++; -- 2.1.0
From 960333650d17dbb1646dbbd236ec535717b7a1eb Mon Sep 17 00:00:00 2001 From: Stephan Holljes <klaxa1...@googlemail.com> Date: Thu, 4 Jun 2015 01:21:26 +0200 Subject: [PATCH 5/5] lavf/http: Indent else-clause. Signed-off-by: Stephan Holljes <klaxa1...@googlemail.com> --- libavformat/http.c | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/libavformat/http.c b/libavformat/http.c index b841f3f..90e88ad 100644 --- a/libavformat/http.c +++ b/libavformat/http.c @@ -611,17 +611,16 @@ static int process_line(URLContext *h, char *line, int line_count, } 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)) - p++; - s->http_code = strtol(p, &end, 10); + while (!av_isspace(*p) && *p != '\0') + p++; + while (av_isspace(*p)) + p++; + s->http_code = strtol(p, &end, 10); - av_log(h, AV_LOG_TRACE, "http_code=%d\n", s->http_code); + av_log(h, AV_LOG_TRACE, "http_code=%d\n", s->http_code); - if ((ret = check_http_code(h, s->http_code, end)) < 0) - return ret; + if ((ret = check_http_code(h, s->http_code, end)) < 0) + return ret; } } else { while (*p != '\0' && *p != ':') -- 2.1.0
_______________________________________________ ffmpeg-devel mailing list ffmpeg-devel@ffmpeg.org http://ffmpeg.org/mailman/listinfo/ffmpeg-devel