I hope this time the patch is formatted correctly. I also attached it in case it is corrupted again. I changed the indentation of the code and used ffurl_open() instead of creating my own listening socket.
I am still having some trouble with the Content-Type header. I would guess creating functions like http_write_header() as the counterpart for http_read_header() would be the most appropriate approach? --- libavformat/http.c | 33 ++++++++++++++++++++++++++++++++- 1 file changed, 32 insertions(+), 1 deletion(-) diff --git a/libavformat/http.c b/libavformat/http.c index da3c9be..472d8dd 100644 --- a/libavformat/http.c +++ b/libavformat/http.c @@ -96,6 +96,8 @@ typedef struct HTTPContext { int send_expect_100; char *method; int reconnect; + int listen; + int header_sent; } HTTPContext; #define OFFSET(x) offsetof(HTTPContext, x) @@ -127,6 +129,7 @@ static const AVOption options[] = { { "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 }, { "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 }, { NULL } }; @@ -300,7 +303,9 @@ static int http_open(URLContext *h, const char *uri, int flags, AVDictionary **options) { HTTPContext *s = h->priv_data; - int ret; + int port, ret = 0; + char hostname[1024]; + char lower_url[100]; if( s->seekable == 1 ) h->is_streamed = 0; @@ -321,6 +326,20 @@ static int http_open(URLContext *h, const char *uri, int flags, "No trailing CRLF found in HTTP header.\n"); } + if (s->listen) { + av_url_split(NULL, 0, NULL, 0, hostname, sizeof(hostname), &port, + NULL, 0, uri); + ff_url_join(lower_url, sizeof(lower_url), "tcp", NULL, hostname, port, + NULL); + av_dict_set(options, "listen", "1", AV_DICT_APPEND); + ret = ffurl_open(&s->hd, lower_url, AVIO_FLAG_READ_WRITE, + &h->interrupt_callback, options); + if (ret < 0) { + return ret; + } + + return ret; + } ret = http_open_cnx(h, options); if (ret < 0) av_dict_free(&s->chained_options); @@ -1100,10 +1119,22 @@ static int http_read(URLContext *h, uint8_t *buf, int size) static int http_write(URLContext *h, const uint8_t *buf, int size) { char temp[11] = ""; /* 32-bit hex + CRLF + nul */ + char header[] = "HTTP 200 OK\r\nContent-Type: application/octet-stream\r\n\r\n"; int ret; char crlf[] = "\r\n"; HTTPContext *s = h->priv_data; + if (s->listen) { + if (!s->header_sent) { + ret = ffurl_write(s->hd, header, strlen(header)); + if (ret < 0) { + return ff_neterrno(); + } + s->header_sent = 1; + } + ret = ffurl_write(s->hd, buf, size); + return ret < 0 ? ff_neterrno() : ret; + } if (!s->chunked_post) { /* non-chunked data is sent without any special encoding */ return ffurl_write(s->hd, buf, size); -- 2.3.3 On Sun, Mar 22, 2015 at 10:33 AM, Nicolas George <geo...@nsup.org> wrote: > Le primidi 1er germinal, an CCXXIII, Stephan Holljes a écrit : >> Please comment. > > As Michael pointed out, the patch was mangled at sending. That happens with > mail user agent that rely on "rich" text editor and do not let users control > the formatting finely. Using git send-email or attaching the file will solve > the problem. They also include authorship and date information. > >> >> Regards, >> Stephan Holljes >> >> --- >> libavformat/http.c | 113 >> ++++++++++++++++++++++++++++++++++++++-------------- >> 1 file changed, 83 insertions(+), 30 deletions(-) >> >> diff --git a/libavformat/http.c b/libavformat/http.c >> index da3c9be..d61e4e2 100644 >> --- a/libavformat/http.c >> +++ b/libavformat/http.c >> @@ -96,8 +96,12 @@ typedef struct HTTPContext { >> int send_expect_100; >> char *method; >> int reconnect; >> + int listen; >> + int fd; >> + int header_sent; >> } HTTPContext; >> >> + >> #define OFFSET(x) offsetof(HTTPContext, x) >> #define D AV_OPT_FLAG_DECODING_PARAM >> #define E AV_OPT_FLAG_ENCODING_PARAM >> @@ -127,6 +131,7 @@ static const AVOption options[] = { >> { "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 }, >> { "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 }, >> { NULL } >> }; >> >> @@ -299,8 +304,10 @@ int ff_http_averror(int status_code, int >> default_averror) >> static int http_open(URLContext *h, const char *uri, int flags, >> AVDictionary **options) >> { >> + struct addrinfo hints = { 0 }, *ai; >> HTTPContext *s = h->priv_data; >> - int ret; >> + int ret = -1, fd; >> + char portstr[] = "8080"; // allow non-root users for now >> >> if( s->seekable == 1 ) >> h->is_streamed = 0; >> @@ -320,11 +327,39 @@ static int http_open(URLContext *h, const char *uri, >> int flags, >> av_log(h, AV_LOG_WARNING, >> "No trailing CRLF found in HTTP header.\n"); >> } > >> + if (s->listen) { >> + hints.ai_family = AF_UNSPEC; >> + hints.ai_socktype = SOCK_STREAM; >> + hints.ai_flags |= AI_PASSIVE; >> + ret = getaddrinfo(NULL, portstr, &hints, &ai); >> + if (ret) { >> + av_log(h, AV_LOG_ERROR, "borked"); >> + return AVERROR(EIO); >> + } >> + fd = ff_socket(ai->ai_family, >> + ai->ai_socktype, >> + ai->ai_protocol); >> + if (fd < 0) { >> + ret = ff_neterrno(); >> + freeaddrinfo(ai); >> + return -1; >> + } > > This part looks copied from tcp.c. It would be much better to use the API > provided by TCP. In other words, just like the client part does: > > err = ffurl_open(&s->hd, buf, AVIO_FLAG_READ_WRITE, > &h->interrupt_callback, options); > > you should do the same thing for creating the listening socket, just adding > the listen option. There are several reasons for doing that. > > First, you avoid reimplementing all the interrupt_callback logic and cie, > which would be necessary for a complete implementation. > > Second, this code with getaddrinfo is slightly wrong (wrt multi-protocol > hosts), so when it gets fixed in tcp.c, it would benefit to all the code. > >> >> - ret = http_open_cnx(h, options); >> - if (ret < 0) >> - av_dict_free(&s->chained_options); >> - return ret; >> + fd = ff_listen_bind(fd, ai->ai_addr, ai->ai_addrlen, -1, h); >> + if (fd < 0) { >> + freeaddrinfo(ai); >> + return fd; >> + } >> + h->is_streamed = 1; >> + s->fd = fd; >> + freeaddrinfo(ai); >> + return 0; >> + } else { >> + ret = http_open_cnx(h, options); >> + if (ret < 0) >> + av_dict_free(&s->chained_options); >> + return ret; >> + } >> } >> >> static int http_getc(HTTPContext *s) >> @@ -1102,25 +1137,40 @@ static int http_write(URLContext *h, const uint8_t >> *buf, int size) >> char temp[11] = ""; /* 32-bit hex + CRLF + nul */ >> int ret; >> char crlf[] = "\r\n"; >> + char header[] = "HTTP 200 OK\r\n\r\n"; >> HTTPContext *s = h->priv_data; >> + if (!s->listen) { >> + if (!s->chunked_post) { >> + /* non-chunked data is sent without any special encoding */ >> + return ffurl_write(s->hd, buf, size); >> + } >> >> - if (!s->chunked_post) { >> - /* non-chunked data is sent without any special encoding */ >> - return ffurl_write(s->hd, buf, size); >> - } >> - >> - /* silently ignore zero-size data since chunk encoding that would >> - * signal EOF */ >> - if (size > 0) { >> - /* upload data using chunked encoding */ >> - snprintf(temp, sizeof(temp), "%x\r\n", size); >> + /* silently ignore zero-size data since chunk encoding that would >> + * signal EOF */ >> + if (size > 0) { >> + /* upload data using chunked encoding */ >> + snprintf(temp, sizeof(temp), "%x\r\n", size); >> >> - if ((ret = ffurl_write(s->hd, temp, strlen(temp))) < 0 || >> - (ret = ffurl_write(s->hd, buf, size)) < 0 || >> - (ret = ffurl_write(s->hd, crlf, sizeof(crlf) - 1)) < 0) >> - return ret; >> + if ((ret = ffurl_write(s->hd, temp, strlen(temp))) < 0 || >> + (ret = ffurl_write(s->hd, buf, size)) < 0 || >> + (ret = ffurl_write(s->hd, crlf, sizeof(crlf) - 1)) < 0) >> + return ret; >> + } >> + return size; >> + } else { >> + if (!s->header_sent) { >> + ret = send(s->fd, header, sizeof(header), MSG_NOSIGNAL); >> + s->header_sent = 1; >> + return ret < 0 ? ff_neterrno() : ret; >> + } >> + if (size > 0) { >> + ret = send(s->fd, buf, size, MSG_NOSIGNAL); >> + return ret < 0 ? ff_neterrno() : ret; >> + } else { >> + ret = -1; >> + } >> + return ret; > > When you add a test or a loop around a large portion of the code, do not > reindent the existing code immediately, leave that for a second commit when > the patch is finished. That makes it simpler to see what was actually > changed. > > You can also consider using a more separate approach: > > if (old_case) { > old_code > } else { > new_code > } > > can also be written: > > if (new_case) > return do_new_code(); > >> } >> - return size; >> } >> >> static int http_shutdown(URLContext *h, int flags) >> @@ -1143,20 +1193,23 @@ static int http_close(URLContext *h) >> { >> int ret = 0; >> HTTPContext *s = h->priv_data; >> - >> + if (!s->listen) { >> #if CONFIG_ZLIB >> - inflateEnd(&s->inflate_stream); >> - av_freep(&s->inflate_buffer); >> + inflateEnd(&s->inflate_stream); >> + av_freep(&s->inflate_buffer); >> #endif /* CONFIG_ZLIB */ >> >> - if (!s->end_chunked_post) >> - /* Close the write direction by sending the end of chunked >> encoding. */ >> - ret = http_shutdown(h, h->flags); >> + if (!s->end_chunked_post) >> + /* Close the write direction by sending the end of chunked >> encoding. */ >> + ret = http_shutdown(h, h->flags); >> >> - if (s->hd) >> - ffurl_closep(&s->hd); >> - av_dict_free(&s->chained_options); >> - return ret; >> + if (s->hd) >> + ffurl_closep(&s->hd); >> + av_dict_free(&s->chained_options); >> + return ret; >> + } else { >> + return shutdown(s->fd, SHUT_RDWR); >> + } >> } >> >> static int64_t http_seek_internal(URLContext *h, int64_t off, int whence, >> int force_reconnect) > > Regards, > > -- > Nicolas George > > _______________________________________________ > ffmpeg-devel mailing list > ffmpeg-devel@ffmpeg.org > http://ffmpeg.org/mailman/listinfo/ffmpeg-devel >
From 3ec0259abd9025a1fba06a9cc4c8ee771675f5d7 Mon Sep 17 00:00:00 2001 From: klaxa <klaxa1...@googlemail.com> Date: Thu, 26 Mar 2015 03:40:07 +0100 Subject: [PATCH] Implemented simple listen mode for http. --- libavformat/http.c | 33 ++++++++++++++++++++++++++++++++- 1 file changed, 32 insertions(+), 1 deletion(-) diff --git a/libavformat/http.c b/libavformat/http.c index da3c9be..472d8dd 100644 --- a/libavformat/http.c +++ b/libavformat/http.c @@ -96,6 +96,8 @@ typedef struct HTTPContext { int send_expect_100; char *method; int reconnect; + int listen; + int header_sent; } HTTPContext; #define OFFSET(x) offsetof(HTTPContext, x) @@ -127,6 +129,7 @@ static const AVOption options[] = { { "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 }, { "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 }, { NULL } }; @@ -300,7 +303,9 @@ static int http_open(URLContext *h, const char *uri, int flags, AVDictionary **options) { HTTPContext *s = h->priv_data; - int ret; + int port, ret = 0; + char hostname[1024]; + char lower_url[100]; if( s->seekable == 1 ) h->is_streamed = 0; @@ -321,6 +326,20 @@ static int http_open(URLContext *h, const char *uri, int flags, "No trailing CRLF found in HTTP header.\n"); } + if (s->listen) { + av_url_split(NULL, 0, NULL, 0, hostname, sizeof(hostname), &port, + NULL, 0, uri); + ff_url_join(lower_url, sizeof(lower_url), "tcp", NULL, hostname, port, + NULL); + av_dict_set(options, "listen", "1", AV_DICT_APPEND); + ret = ffurl_open(&s->hd, lower_url, AVIO_FLAG_READ_WRITE, + &h->interrupt_callback, options); + if (ret < 0) { + return ret; + } + + return ret; + } ret = http_open_cnx(h, options); if (ret < 0) av_dict_free(&s->chained_options); @@ -1100,10 +1119,22 @@ static int http_read(URLContext *h, uint8_t *buf, int size) static int http_write(URLContext *h, const uint8_t *buf, int size) { char temp[11] = ""; /* 32-bit hex + CRLF + nul */ + char header[] = "HTTP 200 OK\r\nContent-Type: application/octet-stream\r\n\r\n"; int ret; char crlf[] = "\r\n"; HTTPContext *s = h->priv_data; + if (s->listen) { + if (!s->header_sent) { + ret = ffurl_write(s->hd, header, strlen(header)); + if (ret < 0) { + return ff_neterrno(); + } + s->header_sent = 1; + } + ret = ffurl_write(s->hd, buf, size); + return ret < 0 ? ff_neterrno() : ret; + } if (!s->chunked_post) { /* non-chunked data is sent without any special encoding */ return ffurl_write(s->hd, buf, size); -- 2.3.3
_______________________________________________ ffmpeg-devel mailing list ffmpeg-devel@ffmpeg.org http://ffmpeg.org/mailman/listinfo/ffmpeg-devel