Re: Issues with HTTP multipart/form-data file upload

Xavier Del Campo Romero <[email protected]> Fri, 30 Aug 2024 15:07:51 +0200
Newsgroups gmane.comp.web.dillo.devel
Message-ID <[email protected]>
Hi Rodrigo,

> Dillo has a mechanism to read chunks of data from different sources as they are arriving and pass them to the next stage for processing. However, AFAIK it always reads a chunk and appends it to a large buffer. It doesn't free the processed part until is done with the whole thing.
> 
> This would require a change in the way Dillo processes data, but I think it would be required for large files. There are more details in the
> devdoc/CCCwork.txt file and in src/chain.c if you want to take a closer look.
> 
> As I'm planning to change the design of the CCC, I think I can take this into account too so it would be doable. I'll add it to the list of shortcomings of the current design. 

Thank you. I am still unfamiliar with that part of Dillo, so please let
me know about any progress.

> Okay, I'll focus on the boundary patch first, which is the easiest to merge and then I'll take a closer look at the others.
>
> Yeah, I would assume a lot of implementations are broken, so we want to try to minimize the chances we run into problems.

Limiting ourselves to a-z, A-Z and 0-9 would still account for 62 out of
the 75 possible characters, so roughly 82% of the set. I think that
removing the quoting in favour of the limited set reduce the risk for
broken implementations, yet still provide a good amount of randomness.

> Check sizeof " ": https://godbolt.org/z/7Tso8ooYz

Interestingly, the " " character on your last email is not really a
<space> (<U0020>):

$ printf "%s" " " | hd
00000000  e2 80 88                                          |...|
00000003

Compared to an ASCII whitespace:

$ printf "%s" " " | hd
00000000  20                                                | |
00000001

Both Godbolt and my editor also flag that multi-byte character with a
yellow rectangle around it because it would be highly confusing
otherwise. For example:

printf("len=%zu\n", strlen(" "));

Confusingly returns "len=3".

I am not sure whether this was an intentional modification from your
side. My patch is adding a <space> as defined by POSIX.1-2017 [1], so
that sizeof " " would always return 2. Was it your intention to flag
this potential confusion?

Also, there was not strict reason to use sizeof " ". Any other character
would do e.g.: sizeof "x", sizeof "A", etc.

> You can also use dStr_append_c() to only append one character, so you only need a single character. 

That would be an unnecessary use of the heap, because the size is static.

> If we only use alphanumeric characters, we can just use isalnum() right? 

According to POSIX.1-2017 [2], isalnum(3) depends on the current locale
configured by the system. For example, characters such as Ä or ú could
return non-zero. To avoid this, there are two possible solutions:

1. Use isalnum_l(3) to specify a locale_t object corresponding to the
"POSIX" locale (equivalent to "C" [3]), which must be previously
allocated by the newlocale(3) function [3] and released by the
freelocal(3) function [4]. A minimalist example is shown below:

        locale_t l = newlocale(LC_CTYPE, "POSIX", NULL);

        for (unsigned char i = 0; i < 255; i++)
                printf("hhu=%hhu, c=%c, isalnum=%d\n", i, i,
isalnum_l(i, l));

        freelocale(l);

2. Define a known subset from the portable character set defined by
POSIX.1-2017 [5] and use strspn(3), as already suggested by the patch.
IMHO this approach is better because:
	- It does not deal with locales, so developers not familiar with them
would understand the code better.
	- It is also portable outside a POSIX environment (not sure if this a
requirement, though).
	- It does not require dynamic allication via newlocale(3).
	- It is the only possible option if non-alnum characters, such as ':'
or '/', are appended to the boundary string.

[1]:
https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap06.html
[2]: https://pubs.opengroup.org/onlinepubs/9699919799/functions/isalnum.html
[3]:
https://pubs.opengroup.org/onlinepubs/9699919799/functions/newlocale.html
[4]:
https://pubs.opengroup.org/onlinepubs/9699919799/functions/freelocale.html
[5]:
https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap06.html

> I meant when is the next KoVoꓘ concert :-) 

No gigs ahead, but I will keep you informed. :)

Best regards,

Xavi

On 28/8/24 22:47, Rodrigo Arias wrote:
> Hi Xavier,
> 
> On Wed, Aug 28, 2024 at 01:04:04AM +0200, Xavier Del Campo Romero wrote:
>> Hi Rodrigo,
>>
>>> Glad to read that you also consider Dillo for slcl, and thanks for
>>> preparing the patches :-)
>>
>> Thank you! I want slcl to be useful to anyone, including users who care
>> about minimalist software like Dillo. The web is already too crowded
>> with bloated "webapps" and other terrible things. :)
> 
> Agreed!
> 
>>> Sounds good, not sure how complicated it would be to do this.
>>
>> I still need to investigate this further, but I assume this would
>> require Dillo to at least implement a sink callback.
>>
>> In other words, the component responsible for transmitting the data
>> (probably src/IO/IO.c) should trigger a user-defined callback with an
>> arbitrarily-sized buffer (typically, of BUFSIZ bytes, as defined by
>> stdio.h) that must filled with file data. Then, the user-defined
>> callback can fill from zero up to BUFSIZ bytes, which are eventually
>> trasmitted to the server.
> 
> Dillo has a mechanism to read chunks of data from different sources as
> they are arriving and pass them to the next stage for processing.
> However, AFAIK it always reads a chunk and appends it to a large buffer.
> It doesn't free the processed part until is done with the whole thing.
> 
> This would require a change in the way Dillo processes data, but I think
> it would be required for large files. There are more details in the
> devdoc/CCCwork.txt file and in src/chain.c if you want to take a closer
> look.
> 
> As I'm planning to change the design of the CCC, I think I can take this
> into account too so it would be doable. I'll add it to the list of
> shortcomings of the current design.
> 
>> That said, I am still not sure how much actual effort this would take.
>> But I am glad to receive positive feedback so far - I will then continue
>> to find a solution.
>>
>>> However, being able to upload multiple files at the same time sounds
>>> reasonable, so feel free to try on your own in the meanwhile.
>>
>> Uploading multiple files at once seems doable - the patches I sent on my
>> previous email are probably already doing most of the required work.
>> Again, the trickiest task is to send data on-the-fly for each selected
>> file.
> 
> Okay, I'll focus on the boundary patch first, which is the easiest to
> merge and then I'll take a closer look at the others.
> 
>>
>>> Shouldn't it be 68 then?
>>
>> I understand the opposite: the boundary string with the two leading
>> dashes ("--") included can be up to 72 bytes long, and 74 bytes long for
>> the ending boundary (which includes two more dashes after the boundary
>> string). This is confirmed by reading the BNF defined by RFC 2046 (some
>> bits omitted for simplicity), section 5.1.1 [1]:
>>
>>> boundary := 0*69<bchars> bcharsnospace
>>> bchars := bcharsnospace / " "
>>> bcharsnospace := DIGIT / ALPHA / "'" / "(" / ")" /
>>>                       "+" / "_" / "," / "-" / "." /
>>>                       "/" / ":" / "=" / "?"
>>> dash-boundary := "--" boundary
>>>                       ; boundary taken from the value of
>>>                       ; boundary parameter of the
>>>                       ; Content-Type field> multipart-body :=
>>> [preamble CRLF]
>>>                        dash-boundary transport-padding CRLF
>>>                        body-part *encapsulation
>>>                        close-delimiter transport-padding
>>>                        [CRLF epilogue]
>>> delimiter := CRLF dash-boundary
>>> close-delimiter := delimiter "--"
> 
> Oh right! I see that we are already using 70 characters anyway.
> 
>> Note: even if the specification tells receivers to handle transport
>> padding, for the time being I am assuming "transport-padding" as zero
>> length since composers must not generate non-zero length transport
>> padding. I am still not sure where transport padding would apply,
>> anyway. Probably outside web browsers?
>>
>>> I would leave out all the symbols to avoid quoting and only use A-Z
>>> a-z and 0-9.
>>
>> Interestingly, Dillo would always quote boundary strings [2], even if
>> only using A-Z, a-z and 0-9. In fact, this is one of the wrong
>> assumptions I spotted when testing slcl against Dillo.
> 
> Yeah, I would assume a lot of implementations are broken, so we want to
> try to minimize the chances we run into problems.
> 
> Apart from slcl we should also test this with some sites and see if they
> continue to work okay.
> 
> This will also increase the fingerprinting information to distinguish
> Dillo among other browsers, but I think it is not more information that
> the already leaked by the user agent.
> 
>>> Which, if I computed it correctly, is still too small to worry about.
>>
>> Not only it is too small of a chance: if we really wanted to do "the
>> right thing" and make Dillo absolutely sure the boundary string is not
>> contained within the selected files, this would imply a noticeable
>> performance impact when dealing with large files, much likely for a
>> near-zero benefit.
>>
>> I have not inspected their source code yet (and I do not want to), but I
>> understand both Gecko and Chromium are also making that assumption,
>> because otherwise it would take them a lot of CPU time to upload large
>> files.
> 
> But then they would be doing such assumption with a "much larger"
> probability it hits the file.
> 
> Skipping it with 70 characters is safe for one file, but also probably
> safe for all files ever uploaded with Dillo.
> 
> Maybe curl or other small codebases are easier to read, but not really
> needed.
> 
>>
>>> Why sizeof " " instead of just 2?
>>
>> Because, to my eyes, sizeof " " has more meaningful semantics, compared
>> to a magic integer constant such as 2. However, for this simple
>> scenario, I would still consider both acceptable.
> 
> Check sizeof " ": https://godbolt.org/z/7Tso8ooYz
> 
> You can also use dStr_append_c() to only append one character, so you
> only need a single character.
> 
> If we only use alphanumeric characters, we can just use isalnum() right?
> 
>> I can replace it with 2 if you find the other construct unacceptable.
>>
>>> PS: When are you playing?
>>
>> Sorry, I did not understand your last sentence. Could you please give a
>> bit more context? :)
> 
> I meant when is the next KoVoꓘ concert :-)
> 
> Best,
> Rodrigo.
> _______________________________________________
> Dillo-dev mailing list -- dillo-dev-lx9mn2B4QYRWk0Htik3J/[email protected]
> To unsubscribe send an email to dillo-dev-leave-lx9mn2B4QYRWk0Htik3J/[email protected]

_______________________________________________
Dillo-dev mailing list -- dillo-dev-lx9mn2B4QYRWk0Htik3J/[email protected]
To unsubscribe send an email to dillo-dev-leave-lx9mn2B4QYRWk0Htik3J/[email protected]
OpenPGP_0x84FF3612A9BF43F2.asc (application/pgp-keys, 4.8 KB)
-----BEGIN PGP PUBLIC KEY BLOCK-----

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
=Om+c
-----END PGP PUBLIC KEY BLOCK-----
OpenPGP_signature.asc (application/pgp-signature, 840 B)
-----BEGIN PGP SIGNATURE-----

wsF5BAABCAAjFiEEL4wEMJP9YSkk8Lb8hP82Eqm/Q/IFAmbRxCcFAwAAAAAACgkQhP82Eqm/Q/Kd
GxAAhtlMOmp10marS2JaWVuli0bP6f4Qojo9YYM/23H5BVd3I9DwAaQ/InHpHgK+UOP0xmgS5uzf
EKI2T7LDHhQzUPUQh8iiFRlp4NCeajXm/9VfWZ330JfvGTCRDtOK0TbPOtm8xI8kVtc00f8LfcUY
R3EL+4QagL3MoBq4RCnRba2C3B3woSbtYutPQ9Jnw4LzTwplz3CXzIh5dI90WeHUNy50WMUA0Kd0
rzqSAmrfnXBo5L7Tyvv6sWKR/SnTEPDwtXKZYgDkxsSGMBSYJ5yOe+94HabxF3OpIazhRv9AvFYe
kAzt1Bu/3TzrRC7MLDVTwUTchqqnovTj7wP35554PfsDyhgs1n0GKlCxroNmvNOJ1OIeio8Ghd32
Ikz2P2Uoifa1eckb3mlqbyoKCbM70ZpY0nJw/UpLR/O6oD542BKcMFKV+l8+o/rN3bggzA56sWH2
ZbE2ApUTqW6Ue+GrC3ar0vuGbug6Pi5EHIAqc2WLGKJg4xTPQ7Y2OoR1h+xEcqd13mEqaT8ZC5Hs
U3kI3r7eSZjD0YkkM1sEGKYe3tRgNQHpuP4D5i8t2rIIqgl8fv19jnkc1ImzH9WtUPmwjAY9XC1S
cqw+/P/mgMROjejeyvPYfM0mTbJmzWyrdm/znpKAVFEIaL/mYr5aoDMP0r4Zfm7A+Nf1futqjcP6
XvU=
=+0S0
-----END PGP SIGNATURE-----