[FFmpeg-devel] [GSoC] Proof-of-concept HTTP Server

Stephan Holljes klaxa1337 at googlemail.com
Fri Mar 27 03:54:16 CET 2015


On Thu, 26 Mar 2015 10:15:41 +0100
Nicolas George <george at nsup.org> wrote:

> Le sextidi 6 germinal, an CCXXIII, Stephan Holljes a écrit :
> > I hope this time the patch is formatted correctly. I also attached
> > it in case it is corrupted again.
> 
> Sorry, still wrapped. See there:
> http://ffmpeg.org/pipermail/ffmpeg-devel/2015-March/170768.html
> 
> Especially the lines with the options after #define OFFSET. I suspect
> you can not achieve something correct with gmail's web interface. The
> attached version is fine, though.
> 
> > 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?
> 
> The request in the client part also has headers, so the code should be
> shared. But I believe that goes beyond the scope of the qualification
> task. For now, a constant header with hardcoded content-type seems
> fine.
> 
> > On Sun, Mar 22, 2015 at 10:33 AM, Nicolas George <george at nsup.org>
> > wrote:
> 
> Please remember not to top-post on FFmpeg's mailing lists; if you do
> not know what it means, look it up.
> 
> Also, I believe the deadline for applications is drawing near. Please
> make sure you did all paperwork necessary for Google.
> 
> See below for technical comments on the patch itself:
> 
> > From 3ec0259abd9025a1fba06a9cc4c8ee771675f5d7 Mon Sep 17 00:00:00
> > 2001 From: klaxa <klaxa1337 at googlemail.com>
> > Date: Thu, 26 Mar 2015 03:40:07 +0100
> > Subject: [PATCH] Implemented simple listen mode for http.
> 
> The first line of a Git message starts usually with the context: not
> "do foo for bar" but "bar: do foo".
> 
> > 
> > ---
> >  libavformat/http.c | 33 ++++++++++++++++++++++++++++++++-
> >  1 file changed, 32 insertions(+), 1 deletion(-)
> 
> There is a small section about http in doc/protocols.texi, it would
> be nice to have the option. Just something short:
> 
> "listen: enable experimental HTTP server mode"
> 
> > 
> > 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 },
> 
> Does the proof of concept work for input, output, or both? The "D" at
> the end seems to indicate it is only for receiving, but your patch
> changes http_write().

I just copied that from the line above, I was not aware of the meaning
of the letter at all. Changed to "E".

> 
> >      { 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];
> 
> Since these are only used in the listen case, maybe declare them in
> the corresponding bloc.
> 
> >  
> >      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);
> 
> Are you sure about AV_DICT_APPEND?

Not at all, it seemed like the flag I needed, but it also works with 0
passed as a flag.

> 
> > +        ret = ffurl_open(&s->hd, lower_url, AVIO_FLAG_READ_WRITE,
> > +                   &h->interrupt_callback, options);
> 
> I suspect you need a full-duplex connection for any case. Also,
> please align the second line with the parenthesis.

What do you mean with the full-duplex connection? Does
AVIO_FLAG_READ_WRITE not create a read- and writeable socket?

> 
> > +        if (ret < 0) {
> > +            return ret;
> > +        }
> > +
> > +        return ret;
> 
> The test on ret seems a bit redundant since the same thing is done
> anyway just after. Also, we usually do not put braces on single-line
> if blocs.
> 
> > +    }
> >      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));
> 
> The logic here seems strange. Is there a reason you do not send the
> headers immediately after establishing the connection?

I had some trouble with that in http_open() but that has been resolved
now.

> 
> Also, in this particular case, you seem to be completely ignoring the
> request. Well, if the request is small enough it should work at least
> with some clients, but it will only work for sending content, not
> receiving, so you probably should test that the URL context is not
> used for input.
> 
> > +            if (ret < 0) {
> > +                return ff_neterrno();
> > +            }
> 
> ret is already the correct error code, ff_neterrno() is only for when
> calling the network code directly.
> 
> > +            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);
> 
> I believe the ffurl_write() you just added and the ffurl_write just
> below do exactly the same thing, you can probably just leave the code
> reach here.
> 
> In fact, I suspect that if you move the headers sending in the
> http_open() function, you can leave http_write() completely unchanged.
> 
> Regards,
> 

This patch only adds the variables and options needed and only changes
http_open().

I hope this time the use of an alternative mail-client does not corrupt
it. Regardless, I attached it in case it does anyway.

Regards,
Stephan Holljes

---
 doc/protocols.texi |  3 +++
 libavformat/http.c | 21 +++++++++++++++++++++
 2 files changed, 24 insertions(+)

diff --git a/doc/protocols.texi b/doc/protocols.texi
index 2a19b41..5b7b6cf 100644
--- a/doc/protocols.texi
+++ b/doc/protocols.texi
@@ -277,6 +277,9 @@ Set initial byte offset.
 
 @item end_offset
 Try to limit the request to bytes preceding this offset.
+
+ at item listen
+If set to 1 enables experimental HTTP server.
 @end table
 
 @subsection HTTP Cookies
diff --git a/libavformat/http.c b/libavformat/http.c
index da3c9be..989dc95 100644
--- a/libavformat/http.c
+++ b/libavformat/http.c
@@ -96,6 +96,7 @@ typedef struct HTTPContext {
     int send_expect_100;
     char *method;
     int reconnect;
+    int listen;
 } HTTPContext;
 
 #define OFFSET(x) offsetof(HTTPContext, x)
@@ -127,6 +128,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, E },
     { NULL }
 };
 
@@ -321,6 +323,25 @@ static int http_open(URLContext *h, const char *uri, int flags,
                    "No trailing CRLF found in HTTP header.\n");
     }
 
+    if (s->listen) {
+        char header[] = "HTTP/1.1 200 OK\r\nContent-Type: application/octet-stream\r\nTransfer-Encoding: chunked\r\n\r\n";
+        char hostname[1024];
+        char lower_url[100];
+        int port;
+        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", 0);
+        ret = ffurl_open(&s->hd, lower_url, AVIO_FLAG_READ_WRITE,
+                         &h->interrupt_callback, options);
+        if (ret < 0)
+            return ret;
+        ret = ffurl_write(s->hd, header, strlen(header));
+        if (ret < 0)
+            return ret;
+        return 0;
+    }
     ret = http_open_cnx(h, options);
     if (ret < 0)
         av_dict_free(&s->chained_options);
-- 
2.3.3

-------------- next part --------------
A non-text attachment was scrubbed...
Name: 0001-libavformat-http.c-Add-proof-of-concept-http-server.patch
Type: text/x-patch
Size: 2640 bytes
Desc: not available
URL: <https://ffmpeg.org/pipermail/ffmpeg-devel/attachments/20150327/da358755/attachment.bin>


More information about the ffmpeg-devel mailing list