[FFmpeg-devel] [PATCH v4 1/1] avformat: Add IPFS protocol support.

Tomas Härdin tjoppen at acc.umu.se
Mon Feb 7 17:09:40 EET 2022


fre 2022-02-04 klockan 15:12 +0100 skrev Mark Gaiser:
> On Fri, Feb 4, 2022 at 12:10 PM Tomas Härdin <tjoppen at acc.umu.se>
> wrote:
> 
> > tor 2022-02-03 klockan 18:29 +0100 skrev Mark Gaiser:
> > > 
> > > +typedef struct IPFSGatewayContext {
> > > +    AVClass *class;
> > > +    URLContext *inner;
> > > +    char *gateway;
> > 
> > Consider two separate variables. One for AVOption and one for the
> > dynamically allocated string. Or put the latter on the stack.
> > 
> 
> There always needs to be a gateway so why is reusing that variable an
> issue?
> I'm fine splitting it up but I'd like to understand the benefit of it
> as
> currently I don't see that benefit.

Because of the way AVOption memory allocation works

> 
> > > +static int populate_ipfs_gateway(URLContext *h)
> > > +{
> > > +    IPFSGatewayContext *c = h->priv_data;
> > > +    char *ipfs_full_data_folder = NULL;
> > > +    char *ipfs_gateway_file = NULL;
> > 
> > These can be char[PATH_MAX]
> > 
> 
> Oke, will do.
> C code question though.
> How do I use av_asprintf on stack arrays like that?

snprintf(). Also be careful with PATH_MAX and +-1 bytes for the NUL.

> 
> > Again, there is no reason to stat this. Just try opening the
> > gateway
> > file directly.
> > 
> 
> This is a folder, not a file.
> 
> The other stat that was here too was a file, I replaced that with an
> fopen.
> It smells sketchy to me to (ab)use fopen to check if a folder exists.
> There's stat for that.

You don't need to check whether the folder exists at all. The only
thing that accomplishes is some AV_LOG_DEBUG prints that won't even get
compiled in unless a users builds with -g (I think). It's not sketchy -
it's spec'd behavior.

> 
> 
> > 
> > > +
> > > +    // Read a single line (fgets stops at new line mark).
> > > +    fgets(gateway_file_data, sizeof(gateway_file_data) - 1,
> > > gateway_file);
> > 
> > This can result in gateway_file_data not being NUL terminated
> 
> 
> > > +
> > > +    // Replace first occurence of end of line to \0
> > > +    gateway_file_data[strcspn(gateway_file_data, "\r\n")] = 0;
> > 
> > What if the file uses \n or no newlines at all?
> > 
> 
> Right.
> So I guess the fix here is:
> 1. Initialize gateway_file_data so all bytes are zero
> 2. read a line
> 3. set the last byte of gateway_file_data to 0
> 
> Now any text in the string will be the gateway.
> 
> Is that a proper fix?

Yes always putting a NUL at the end works. You don't need to initialize
with zero in that case. fgets() will NUL terminate except when there's
an error like the line being too long.

> 
> 
> > > +err:
> > > +    if (gateway_file)
> > > +        fclose(gateway_file);
> > > +
> > > +    av_free(ipfs_full_data_folder);
> > > +    av_free(ipfs_gateway_file);
> > 
> > This is not cleaning up dynamic allocations of c->gateway
> > 
> 
> So I should do that in  ipfs_close, right?

That's one place to do it yes. I forget whether _close() is called in
case of errors. av_freep() will set the pointer to NULL after freeing
so no double-frees occur.

> 
> > 
> > 
> > > +    // Test if the gateway starts with either http:// or
> > > https://
> > > +    // The remainder is stored in url_without_protocol
> > > +    if (av_stristart(uri, "http://", &url_without_protocol) == 0
> > > +        && av_stristart(uri, "https://", &url_without_protocol)
> > > ==
> > > 0) {
> > > +        av_log(h, AV_LOG_ERROR, "The gateway URL didn't start
> > > with
> > > http:// or https:// and is therefore invalid.\n");
> > > +        ret = -2;
> > > +        goto err;
> > > +    }
> > 
> > I guess restricting this to HTTP schemes is OK. Or are there non-
> > HTTP
> > gateways for this?
> > 
> 
> No.
> At least not from the IPFS camp.
> The IPFS software creates a gateway and that is specifically an http
> gateway.
> Users can put that behind a proxy making it (potentially) a https
> gateway
> but that's about it.

I see. I guess if any user puts this stuff behind gopher:// or
something then that's their problem.

> 
> > 
> > > +    if (last_gateway_char != '/') {
> > > +        c->gateway = av_asprintf("%s/", c->gateway);
> > 
> > Yet another leak
> > 
> 
> Please tell me how to fix this one.
> As you can see, I need the c->gateway value to copy and add a "/" to
> it.
> 
> In C++ this would just be a dead simple append ;)

Ensure there's enough space for '/' and a NUL and just write that to
the end.

snprintf() can do all of this if used appropriately. For example to
conditionally append "/" you can put %s in the format string and the
ternary

 needs_slash ? "/" : ""

as the associated argument

/Tomas



More information about the ffmpeg-devel mailing list