Fix http-backend reading till EOF, ignoring CONTENT_LENGTH, violating rfc3875 -- WAS: Problem with git-http-backend.exe as iis cgi
PATCH 1/1 Fix http-backend reading till EOF, ignoring CONTENT_LENGTH, violating rfc3875 -- WAS: Problem with git-http-backend.exe as iis cgi
-----Ursprüngliche Nachricht-----
Von: Chris Packham [mailto:[email protected]]
Gesendet: Dienstag, 29. März 2016 11:28
An: Florian Manschwetus
Cc: Konstantin Khomoutov; [email protected]
Betreff: Re: Problem with git-http-backend.exe as iis cgi
Hi Florian
Quoted 55 lines · Florian Manschwetus
Hi,
I put together a first patch for the issue.Mit freundlichen Grüßen / With kind regards Florian Manschwetus
E-Mail: [email protected]
Tel.: +49-(0)611-8908534CS Software Concepts and Solutions GmbH Geschäftsführer / Managing
director: Dr. Werner Alexi Amtsgericht Wiesbaden HRB 10004 (Commercial registry) Schiersteiner Straße 31
D-65187 Wiesbaden
Germany
Tel.: 0611/8908555-----Ursprüngliche Nachricht-----
Von: Konstantin Khomoutov [mailto:[email protected]]
Gesendet: Donnerstag, 10. März 2016 13:55
An: Florian Manschwetus
Cc: [email protected]
Betreff: Re: Problem with git-http-backend.exe as iis cgiQuoted 7 lines · On Thu, 10 Mar 2016 07:28:50 +0000 Florian Manschwetus…
I tried to setup git-http-backend with iis, as iis provides proper impersonation for cgi under windows, which leads to have the filesystem access performed with the logon user, therefore the webserver doesn't need generic access to the files. I stumbled across a problem, ending up with post requests hanging forever. After some investigation I managed to get it work by wrapping the http-backend into a bash script, giving a lot of control about the environmental
Quoted 8 lines
things, I was unable to solve within IIS configuration. The workaround, I use currently, is to use "
/bin/head-c ${CONTENT_LENGTH}
| ./git-http-backend.exe", which directly shows the issue. Git http-backend should check ifCONTENT_LENGTHis set to something reasonable (e.g. >0) and should in this case read onlyCONTENT_LENGTHbytes from stdin, instead of reading till EOF what I suspect it is doing currently.The rfc [1] states in its section 4.2:
| A request-body is supplied with the request if the CONTENT_LENGTH is | not NULL. The server MUST make at least that many bytes available | for the script to read. The server MAY signal an end-of-file | condition after CONTENT_LENGTH bytes have been read or it MAY supply | extension data. Therefore, the script MUST NOT attempt to read more | than CONTENT_LENGTH bytes, even if more data is available. However, | it is not obliged to read any of the data.So yes, if Git currently reads until EOF, it's an error. The correct way would be:
Quoted 6 lines
1) Check to see if the
CONTENT_LENGTHvariable is available in the environment. If no, read nothing.2) Otherwise read as many bytes it specifies, and no more.
Your patch description seems well thought out but if you want someone to notice it you should have a read of https://git.kernel.org/cgit/git/git.git/tree/Documentation/SubmittingPatches
Moin,
I have cloned git and created a more clean patch...
--- http-backend.c | 48 +++++++++++++++++++++++++++++++----------------- 1 file changed, 31 insertions(+), 17 deletions(-)
http-backend.c +31 -17
@@ -277,16 +277,32 @@ static struct rpc_service *select_service(const char *name)*/ static ssize_t read_request (int fd,unsigned char **out) { -size_t len =0 , alloc =8192 ; -unsigned char *buf =xmalloc (alloc); +unsigned char *buf = null; +size_t len =0 ; +/* get request size */ +size_t req_len =git_env_ulong ("CONTENT_LENGTH" , +0 ); + +/* check request size */ +if (max_request_buffer < req_len) { +die ("request was larger than our maximum size (%lu);" +" try setting GIT_HTTP_MAX_REQUEST_BUFFER" , + max_request_buffer); + } + +if (req_len <=0 ) { + *out = null; +return 0 ; + } + +/* allocate buffer */ + buf = xmalloc(req_len) -if (max_request_buffer < alloc) - max_request_buffer = alloc;while (1 ) {ssize_t cnt; - cnt =read_in_full (fd, buf + len, alloc - len); + cnt =read_in_full (fd, buf + len, req_len - len);if (cnt <0 ) {free (buf);return -1 ;
@@ -294,21 +310,18 @@ static ssize_t read_request(int fd, unsigned char **out)/* partial read from read_in_full means we hit EOF */ len += cnt; -if (len < alloc) { +if (len < req_len) { +/* TODO request incomplete?? */ +/* maybe just remove this block and condition along with the loop, */ +/* if read_in_full is prooven reliable */ *out = buf;return len; + }else { +/* request complete */ + *out = buf; +return len; + } - -/* otherwise, grow and try again (if we can) */ -if (alloc == max_request_buffer) -die ("request was larger than our maximum size (%lu);" -" try setting GIT_HTTP_MAX_REQUEST_BUFFER" , - max_request_buffer); - - alloc =alloc_nr (alloc); -if (alloc > max_request_buffer) - alloc = max_request_buffer; -REALLOC_ARRAY (buf, alloc); } }
@@ -701,3 +714,4 @@ int main(int argc, char **argv) cmd->imp (cmd_arg);return 0 ; } +
Signature · 12 lines
2.7.2.windows.1 Mit freundlichen Grüßen / With kind regards Florian Manschwetus CS Software Concepts and Solutions GmbH Geschäftsführer / Managing director: Dr. Werner Alexi Amtsgericht Wiesbaden HRB 10004 (Commercial registry) Schiersteiner Straße 31 D-65187 Wiesbaden Germany
Quoted 11 lines · Florian Manschwetus
Quoted 11 lines
| A request-body is supplied with the request if the CONTENT_LENGTH is | not NULL. The server MUST make at least that many bytes available | for the script to read. The server MAY signal an end-of-file | condition after CONTENT_LENGTH bytes have been read or it MAY supply | extension data. Therefore, the script MUST NOT attempt to read more | than CONTENT_LENGTH bytes, even if more data is available. However, | it is not obliged to read any of the data.So yes, if Git currently reads until EOF, it's an error. The correct way would be:
Quoted 6 lines
Quoted 6 lines
1) Check to see if the
CONTENT_LENGTHvariable is available in the environment. If no, read nothing.2) Otherwise read as many bytes it specifies, and no more.
I don't think the second part of (1) will work very well if the client sends a chunked transfer-encoding (which git will do if the input is large). In such a case the server would either have to buffer the entire input to find its length, or stream the data to the CGI without setting $CONTENT_LENGTH. At least some servers choose the latter (including Apache).
Quoted 17 lines
http-backend.c +7
-2@@ -277,16 +277,32 @@ static struct rpc_service *select_service(const char *name)*/ static ssize_t read_request (int fd,unsigned char **out) { -size_t len =0 , alloc =8192 ; -unsigned char *buf =xmalloc (alloc); +unsigned char *buf = null; +size_t len =0 ; +/* get request size */ +size_t req_len =git_env_ulong ("CONTENT_LENGTH" , +0 ); + +/* check request size */
http-backend.c static struct rpc_service *select_service(const char *name) · line 296
Quoted 10 lines
http-backend.c +10
-0+if (max_request_buffer < req_len) { +die ("request was larger than our maximum size (%lu);" +" try setting GIT_HTTP_MAX_REQUEST_BUFFER" , + max_request_buffer); + } + +if (req_len <=0 ) { + *out = null; +return 0 ; + }
git-am complained that your patch did not apply, but after writing something similar locally, I found that t5551.25 hangs indefinitely. Which is not surprising. Most tests are doing very limited ref negotiation, so the content that hits read_request() here is small, and we send it in a single write with a content-length header. But t5551.25 uses a much bigger workload, which causes the client to use a chunked transfer-encoding, and this code to refuse to read anything (and then the protocol stalls, as we are waiting for the client to say something).
So I think you'd want to take a missing CONTENT_LENGTH as a hint to read until EOF.
That also raises another issue: what happens in the paths that don't hit read_request()? We may also process input via:
- inflate_request(), if the client gzipped it; for well-formed input, I think we'll stop reading when the gzip stream tells us there is no more data, but a malformed one would have us reading until EOF, regardless of what $CONTENT_LENGTH says.
- for input which we expect to be large (like incoming packfiles for a push), buffer_input will be unset, and we will pass the descriptor directly to a sub-program like git-index-pack. Again, for well-formed input it would read just the packfile, but it may actually continue to EOF.
So I don't think your patch is covering all cases.
-Peff
Quoted 74 lines
-----Ursprüngliche Nachricht-----
Von: Jeff King [mailto:[email protected]]
Gesendet: Dienstag, 29. März 2016 22:14
An: Florian Manschwetus
Cc: Chris Packham; Konstantin Khomoutov; [email protected]
Betreff: Re: [PATCH] Fix http-backend reading till EOF, ignoringCONTENT_LENGTH, violating rfc3875 -- WAS: Problem with git-http- backend.exe as iis cgiQuoted 11 lines · Florian Manschwetus
Quoted 11 lines
| A request-body is supplied with the request if the CONTENT_LENGTH | is not NULL. The server MUST make at least that many bytes | available for the script to read. The server MAY signal an | end-of-file condition after CONTENT_LENGTH bytes have been read or | it MAY supply extension data. Therefore, the script MUST NOT | attempt to read more than CONTENT_LENGTH bytes, even if more data | is available. However, it is not obliged to read any of the data.So yes, if Git currently reads until EOF, it's an error. The correct way would be:
Quoted 6 lines
Quoted 6 lines
1) Check to see if the
CONTENT_LENGTHvariable is available in the environment. If no, read nothing.2) Otherwise read as many bytes it specifies, and no more.
I don't think the second part of (1) will work very well if the client sends a chunked transfer-encoding (which git will do if the input is large). In such a case the server would either have to buffer the entire input to find its length, or stream the data to the CGI without setting $CONTENT_LENGTH. At least some servers choose the latter (including Apache).
http-backend.c static struct rpc_service *select_service(const
Quoted 5 lines
http-backend.c index 8870a26..94976df renamed from http-backend.c +0
-0100644
http-backend.c +0
-0@@ -277,16 +277,32 @@ static struct rpc_service *select_service(constchar *name)
http-backend.c static struct rpc_service *select_service(const · line 279
Quoted 6 lines
http-backend.c +1
-2*/ static ssize_t read_request (int fd,unsigned char **out) { -size_t len =0 , alloc =8192 ; -unsigned char *buf =xmalloc (alloc); +unsigned char *buf = null;git-am complained that your patch did not apply, but after writing something similar locally, I found that t5551.25 hangs indefinitely.
Which is not surprising. Most tests are doing very limited ref negotiation, so the content that hitsread_request()here is small, and we send it in a single write with a content-length header. But t5551.25 uses a much bigger workload, which causes the client to use a chunked transfer-encoding, and this code to refuse to read anything (and then the protocol stalls, as we are waiting for the client to say something).So I think you'd want to take a missing
CONTENT_LENGTHas a hint to read until EOF.That also raises another issue: what happens in the paths that don't hit
read_request()? We may also process input via:-
inflate_request(), if the client gzipped it; for well-formed input, I think we'll stop reading when the gzip stream tells us there is no more data, but a malformed one would have us reading until EOF, regardless of what $CONTENT_LENGTH says.- for input which we expect to be large (like incoming packfiles for a push),
buffer_inputwill be unset, and we will pass the descriptor directly to a sub-program like git-index-pack. Again, for well-formed input it would read just the packfile, but it may actually continue to EOF.
Quoted 3 lines
So I don't think your patch is covering all cases.
-Peff
After additional analysis it turned out, that in the case you mentioned, at least IIS, sets CONTENT_LENGTH to -1 resulting in the current behavior of git-http-backend being sufficient in this situation. Therefore I refactored the code again a bit, to match up the behavior I currently fake by using some bash magic...
From ccd6c88e39a850b253979b785463719cdc0fa1e2 Mon Sep 17 00:00:00 2001
From: manschwetus <[email protected]>
Date: Tue, 29 Mar 2016 12:16:21 +0200
Subject: [PATCH 1/2] Fix http-backend reading till EOF, ignoring
CONTENT_LENGTH, violating rfc3875
--- http-backend.c | 48 +++++++++++++++++++++++++++++++----------------- 1 file changed, 31 insertions(+), 17 deletions(-)
http-backend.c +30 -17
@@ -277,16 +277,32 @@ static struct rpc_service *select_service(const char *name)*/ static ssize_t read_request (int fd,unsigned char **out) { -size_t len =0 , alloc =8192 ; -unsigned char *buf =xmalloc (alloc); +unsigned char *buf = null; +size_t len =0 ; +/* get request size */ +size_t req_len =git_env_ulong ("CONTENT_LENGTH" , +0 ); + +/* check request size */ +if (max_request_buffer < req_len) { +die ("request was larger than our maximum size (%lu);" +" try setting GIT_HTTP_MAX_REQUEST_BUFFER" , + max_request_buffer); + } + +if (req_len <=0 ) { + *out = null; +return 0 ; + } + +/* allocate buffer */ + buf = xmalloc(req_len) -if (max_request_buffer < alloc) - max_request_buffer = alloc;while (1 ) {ssize_t cnt; - cnt =read_in_full (fd, buf + len, alloc - len); + cnt =read_in_full (fd, buf + len, req_len - len);if (cnt <0 ) {free (buf);return -1 ;
@@ -294,21 +310,18 @@ static ssize_t read_request(int fd, unsigned char **out)/* partial read from read_in_full means we hit EOF */ len += cnt; -if (len < alloc) { +if (len < req_len) { +/* TODO request incomplete?? */ +/* maybe just remove this block and condition along with the loop, */ +/* if read_in_full is prooven reliable */ *out = buf;return len; + }else { +/* request complete */ + *out = buf; +return len; + } - -/* otherwise, grow and try again (if we can) */ -if (alloc == max_request_buffer) -die ("request was larger than our maximum size (%lu);" -" try setting GIT_HTTP_MAX_REQUEST_BUFFER" , - max_request_buffer); - - alloc =alloc_nr (alloc); -if (alloc > max_request_buffer) - alloc = max_request_buffer; -REALLOC_ARRAY (buf, alloc); } }
Signature · 15 lines
2.7.2.windows.1 From 4b2aac3dfd4954098190745a9e4fa17f254cd6a1 Mon Sep 17 00:00:00 2001 From: Florian Manschwetus <[email protected]> Date: Wed, 30 Mar 2016 10:54:21 +0200 Subject: [PATCH 2/2] restored old behavior as read_request_eof(...) and moved new variant to read_request_fix_len(...) and introduced read_request(...) as wrapper, which decides based on value retrieved from CONTENT_LENGTH which variant to use Signed-off-by: Florian Manschwetus <[email protected]> --- http-backend.c | 67 ++++++++++++++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 63 insertions(+), 4 deletions(-)
http-backend.c +63 -4
82 lines not on this page · raw message
Signature · 12 lines
2.7.2.windows.1 Mit freundlichen Grüßen / With kind regards Florian Manschwetus CS Software Concepts and Solutions GmbH Geschäftsführer / Managing director: Dr. Werner Alexi Amtsgericht Wiesbaden HRB 10004 (Commercial registry) Schiersteiner Straße 31 D-65187 Wiesbaden Germany
Quoted 6 lines · Florian Manschwetus
After additional analysis it turned out, that in the case you mentioned, at least IIS, sets
CONTENT_LENGTHto -1 resulting in the current behavior of git-http-backend being sufficient in this situation.
Therefore I refactored the code again a bit, to match up the behavior I currently fake by using some bash magic...
OK, so I'd agree it makes sense to catch "-1", and read to EOF in that case (or if CONTENT_LENGTH is NULL).
Quoted 5 lines
From
ccd6c88e39a850b253979b785463719cdc0fa1e2Mon Sep 17 00:00:00 2001
From: manschwetus <[email protected]>
Date: Tue, 29 Mar 2016 12:16:21 +0200
Subject: [PATCH 1/2] Fix http-backend reading till EOF, ignoring
CONTENT_LENGTH, violating rfc3875
Please send one patch per email, and these header bits should be the header of your email.
Though we also generally revise and re-send patches, rather than presenting one patch that has problems and then tacking fixes on top. I'll ignore the problems in this patch 1, as it looks like it's just the original one repeated.
Quoted 7 lines
From
4b2aac3dfd4954098190745a9e4fa17f254cd6a1Mon Sep 17 00:00:00 2001
From: Florian Manschwetus <[email protected]>
Date: Wed, 30 Mar 2016 10:54:21 +0200
Subject: [PATCH 2/2] restored old behavior asread_request_eof(...)and moved
new variant toread_request_fix_len(...)and introducedread_request(...)as wrapper, which decides based on value retrieved fromCONTENT_LENGTHwhich variant to use
Please use a short subject for your commit message, followed by a blank line and then a more explanatory body. Also, don't just describe _what_ is happening (we can see that from the diff), but _why_. You can find more similar tips in SubmittingPatches.
Quoted 9 lines
http-backend.c +9
-0+/** +* wrapper function, whcih determines based on CONTENT_LENGTH value, +* to +* - use old behaviour of read_request, to read until EOF +* => read_request_eof(...) +* - just read CONTENT_LENGTH-bytes, when provided +* => read_request_fix_len(...) +*/ +static ssize_t read_request (int fd,unsigned char **out)
http-backend.c static ssize_t read_request(int fd, unsigned char **out) · line 385
Quoted 10 lines
http-backend.c +10
-0+{ +/* get request size */ +size_t req_len =git_env_ulong ("CONTENT_LENGTH" , +-1 ); +if (req_len <0 ){ +read_request_eof (fd, out); + }else { +read_request_fix_len (fd, req_len, out); + } +}
I don't think "if (req_len < 0)" can ever trigger, because size_t is an unsigned type (and I do not recall what kind of integer overflow validation we do in git_env_ulong, but I suspect it may complain about "-1"). You may have to parse the variable manually rather than using git_env_ulong (i.e., pick out the NULL and "-1" cases, and then feed the rest to git_parse_ulong()).
Also, a few style nits. We usually omit braces for one-line conditionals, and please make sure there is whitespace between the closing parenthesis and the opening brace. There's some discussing in CodingGuidelines.
-Peff
PATCH 1/1 http-backend: respect CONTENT_LENGTH as specified by rfc3875
http-backend reads whole input until EOF. However, the RFC 3875 specifies that a script must read only as many bytes as specified by CONTENT_LENGTH environment variable. This causes hang under IIS/Windows, for example.
Make http-backend read only CONTENT_LENGTH bytes, if it's defined, rather than the whole input until EOF. If the varibale is not defined, keep older behavior of reading until EOF because it is used to support chunked transfer-encoding.
---
Hi
I came across this issue, and I think is should be good to restore the patch. It is basically same but I squashed them, fixed the thing you mentioned and also some trivial build failures (null -> NULL and missing return from the wrapper). I hope I marked it correctly in the trailers.
config.c | 8 +++++++ config.h | 1 + http-backend.c | 72 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++- 3 files changed, 80 insertions(+), 1 deletion(-)
config.c +8 -0
@@ -1525,6 +1525,14 @@ unsigned long git_env_ulong(const char *k, unsigned long val)return val; } +ssize_t git_env_ssize_t (const char *k,ssize_t val) +{ +const char *v =getenv (k); +if (v && !git_parse_ssize_t (v, &val)) +die ("failed to parse %s" , k); +return val; +} +int git_config_system (void ) {return !git_env_bool ("GIT_CONFIG_NOSYSTEM" ,0 );
config.h +1 -0
@@ -74,6 +74,7 @@ extern int git_config_rename_section_in_file(const char *, const char *, const cextern const char *git_etc_gitconfig (void );extern int git_env_bool (const char *,int );extern unsigned long git_env_ulong (const char *,unsigned long ); +extern ssize_t git_env_ssize_t (const char *,ssize_t );extern int git_config_system (void );extern int config_error_nonbool (const char *);#if defined(__GNUC__)
http-backend.c +71 -1
84 lines not on this page · raw message
Signature · 1 line
2.11.0.1122.gc3fec58.dirty
Re: [PATCH] http-backend: respect CONTENT_LENGTH as specified by rfc3875
Quoted 1 line · Max Kirillov
[PATCH] http-backend: respect
CONTENT_LENGTHas specified by rfc3875
The "RFC" seems to be missing from the subject line of this unpolished patch.
Quoted 3 lines
http-backend reads whole input until EOF. However, the RFC 3875 specifies that a script must read only as many bytes as specified by
CONTENT_LENGTHenvironment variable. This causes hang under IIS/Windows, for example.
By "_this_ causes a hang", I presume you mean "not respecting CONTENT_LENGTH causes a hang"? Perhaps that could be spelled out explicitly.
Quoted 2 lines
Make http-backend read only
CONTENT_LENGTHbytes, if it's defined, rather than the whole input until EOF. If the varibale is not defined, keep older behavior
s/varibale/variable/
Quoted 9 lines
of reading until EOF because it is used to support chunked transfer-encoding.
Signed-off-by Florian Manschwetus <[email protected]>Authored-by Florian Manschwetus <[email protected]>Fixed-by Max Kirillov <[email protected]>Signed-off-by Max Kirillov <[email protected]>---
http-backend.c static ssize_t read_request(int fd, unsigned char **out) · line 321
Quoted 5 lines
http-backend.c +5
-0@@ -317,6 +317,76 @@ static ssize_t read_request(int fd, unsigned char **out) +/* +* replacement for original read_request, now renamed to read_request_eof, +* honoring given content_length (req_len), +* provided by new wrapper function read_request +*/
This comment has value only to someone who knew what the code was like before this change, and it merely repeats what is already implied by the commit message, rather than providing any valuable information about this new function itself. Therefore, it should be dropped.
http-backend.c static ssize_t read_request(int fd, unsigned char **out) · line 325
Quoted 1 line
http-backend.c +1
-0+static ssize_t read_request_fix_len (int fd,size_t req_len,unsigned char **out)
Wrong data type: s/size_t req_len/ssize_t req_len/
Also: s/fix/fixed/
http-backend.c static ssize_t read_request(int fd, unsigned char **out) · line 330
Quoted 5 lines
http-backend.c +5
-0+{ +unsigned char *buf =NULL ; +size_t len =0 ; + +/* check request size */
Comment merely repeats what code says, thus has no value. Please drop.
http-backend.c static ssize_t read_request(int fd, unsigned char **out) · line 334
Quoted 4 lines
http-backend.c +4
-0+if (max_request_buffer < req_len) { +die ("request was larger than our maximum size (%lu);" +" try setting GIT_HTTP_MAX_REQUEST_BUFFER" , + max_request_buffer);
This error message neglects to say what the request size was. Such information would be useful given that it suggests bumping GIT_HTTP_MAX_REQUEST_BUFFER to a larger value.
http-backend.c static ssize_t read_request(int fd, unsigned char **out) · line 342
Quoted 8 lines
http-backend.c +8
-0+ } + +if (req_len <=0 ) { + *out =NULL ; +return 0 ; + } + +/* allocate buffer */
Drop valueless comment.
http-backend.c static ssize_t read_request(int fd, unsigned char **out) · line 345
Quoted 3 lines
http-backend.c +3
-0+ buf =xmalloc (req_len); + +
Style: Too many blank lines.
Quoted 5 lines
http-backend.c +5
-0+while (1 ) { +ssize_t cnt; + + cnt =read_in_full (fd, buf + len, req_len - len); +if (cnt <0 ) {
http-backend.c static ssize_t read_request(int fd, unsigned char **out) · line 360
Quoted 10 lines
http-backend.c +10
-0+free (buf); +return -1 ; + } + +/* partial read from read_in_full means we hit EOF */ + len += cnt; +if (len < req_len) { +/* TODO request incomplete?? */ +/* maybe just remove this block and condition along with the loop, */ +/* if read_in_full is prooven reliable */
s/prooven/proven/
http-backend.c static ssize_t read_request(int fd, unsigned char **out) · line 369
Quoted 9 lines
http-backend.c +9
-0+ *out = buf; +return len; + }else { +/* request complete */ + *out = buf; +return len; + + } + }
What is the purpose of the while(1) loop? Every code path inside the loop returns, so it will never execute more than once. Likewise, why is 'len' needed?
Rather than writing an entirely new "read" function, how about just modifying the existing read_request() to optionally limit the read to a specified number of bytes?
http-backend.c static ssize_t read_request(int fd, unsigned char **out) · line 373
Quoted 4 lines
http-backend.c +4
-0+} + +/** +* wrapper function, whcih determines based on CONTENT_LENGTH value,
s/whcih/which/
Also, the placement of commas needs some attention.
http-backend.c static ssize_t read_request(int fd, unsigned char **out) · line 379
Quoted 6 lines
http-backend.c +6
-0+* to +* - use old behaviour of read_request, to read until EOF +* => read_request_eof(...) +* - just read CONTENT_LENGTH-bytes, when provided +* => read_request_fix_len(...) +*/
When talking about "old behavior", this comment is repeating information more suitable to the commit message (and effectively already covered there); information which only has value to someone who knew what the old code/behavior was like. The rest of this comment is merely repeating what the code itself already says, thus adds no value, so should be dropped.
http-backend.c static ssize_t read_request(int fd, unsigned char **out) · line 382
Quoted 3 lines
http-backend.c +3
-0+static ssize_t read_request (int fd,unsigned char **out) +{ +/* get request size */
Drop valueless comment.
Quoted 6 lines
http-backend.c +6
-0+ssize_t req_len =git_env_ssize_t ("CONTENT_LENGTH" ,-1 ); +if (req_len <0 ) +return read_request_eof (fd, out); +else +return read_request_fix_len (fd, req_len, out); +}
Re: [PATCH] http-backend: respect CONTENT_LENGTH as specified by rfc3875
Thanks for the review. I saw only reaction of the Jeff in the original thread and though that it is ok otherwise. I'm fixing the things you mentioned.
Quoted 3 lines · Eric Sunshine
Quoted 1 line
+static
ssize_tread_request_fix_len(int fd, size_t req_len, unsigned char **out)Wrong data type: s/size_t req_len/ssize_t req_len/
Passing negative value to the function makes no sense. I could add explicit type cast to make it clear. It should be safe as site_t's range is bigger, and overflown CONTENT_LENGTH results in die() at parsing (I have a test which verifies it)
Quoted 3 lines
Rather than writing an entirely new "read" function, how about just modifying the existing
read_request()to optionally limit the read to a specified number of bytes?
I'll check it a bit separately.
Signature · 1 line
Max
Re: [PATCH] http-backend: respect CONTENT_LENGTH as specified by rfc3875
Quoted 3 lines · Max Kirillov
Thanks for the review. I saw only reaction of the Jeff in the original thread and though that it is ok otherwise. I'm fixing the things you mentioned.
The commentary (in which you talked about restoring the patch and squashing) seemed to imply that this had been posted somewhere before, but it wasn't marked as "v2" (or whatever attempt) and lacked a URL pointing at the previous attempt, so it was difficult to judge.
Quoted 10 lines · Eric Sunshine
Quoted 3 lines
Quoted 1 line
+static
ssize_tread_request_fix_len(int fd, size_t req_len, unsigned char **out)Wrong data type: s/size_t req_len/ssize_t req_len/
Passing negative value to the function makes no sense. I could add explicit type cast to make it clear. It should be safe as site_t's range is bigger, and overflown
CONTENT_LENGTHresults indie()at parsing (I have a test which verifies it)
A concern with requesting size_t bytes is that, if it does read all bytes, that value can't necessarily be represented by the ssize_t returned from the function. Where would the cast be placed that you suggest? How do other git functions deal with this sort of situation?
Re: [PATCH] http-backend: respect CONTENT_LENGTH as specified by rfc3875
Quoted 12 lines · Eric Sunshine
Quoted 10 lines · Max Kirillov
Quoted 3 lines · Eric Sunshine
Quoted 1 line
+static
ssize_tread_request_fix_len(int fd, size_t req_len, unsigned char **out)Wrong data type: s/size_t req_len/ssize_t req_len/
Passing negative value to the function makes no sense. I could add explicit type cast to make it clear. It should be safe as site_t's range is bigger, and overflown
CONTENT_LENGTHresults indie()at parsing (I have a test which verifies it)
Quoted 4 lines
A concern with requesting
size_tbytes is that, if it does read all bytes, that value can't necessarily be represented by thessize_treturned from the function. Where would the cast be placed that you suggest? How do other git functions deal with this sort of situation?
Right... ok, let it be ssize_t
Re: [PATCH] http-backend: respect CONTENT_LENGTH as specified by rfc3875
In reply to Max KirillovQuoted 8 lines · Max Kirillov
http-backend reads whole input until EOF. However, the RFC 3875 specifies that a script must read only as many bytes as specified by
CONTENT_LENGTHenvironment variable. This causes hang under IIS/Windows, for example.Make http-backend read only
CONTENT_LENGTHbytes, if it's defined, rather than the whole input until EOF. If the varibale is not defined, keep older behavior of reading until EOF because it is used to support chunked transfer-encoding.
Quoted 7 lines
Signed-off-by Florian Manschwetus <[email protected]>Authored-by Florian Manschwetus <[email protected]>Fixed-by Max Kirillov <[email protected]>Signed-off-by Max Kirillov <[email protected]>---
...
I hope I marked it correctly in the trailers.
It is probably more conventional to do it like so:
From: Florian Manschwetus <[email protected]>
Date: <original date of Florian's patch series>
http-backend reads whole input until EOF. However, the RFC 3875... ... chunked transfer-encoding.
---
Quoted 6 lines
+/*
+ * replacement for originalread_request, now renamed toread_request_eof,
+ * honoring givencontent_length(req_len),
+ * provided by new wrapper functionread_request
+ */
I agree with Eric's suggestion. In-code comment is read by those who have the current code, without knowing/caring what it used to be. "It used to do this, but replace it with this new thing because..." is a valuable thing to record in the log message, but not here.
AW: [PATCH] http-backend: respect CONTENT_LENGTH as specified by rfc3875
Hi All,
thx Max for jumping in, I wasn't able to complete this due to serious lack of time. Later I forgot it. Great to see that this finally made it.
Mit freundlichen Grüßen / With kind regards
Florian Manschwetus
E-Mail: [email protected]
Tel.: +49-(0)611-8908534
CS Software Concepts and Solutions GmbH Geschäftsführer / Managing director: Dr. Werner Alexi Amtsgericht Wiesbaden HRB 10004 (Commercial registry) Schiersteiner Straße 31
D-65187 Wiesbaden
Germany
Tel.: 0611/8908555
Quoted 56 lines
-----Ursprüngliche Nachricht-----
Von: Junio C Hamano [mailto:[email protected]]
Gesendet: Freitag, 24. November 2017 06:55
An: Max Kirillov
Cc: Jeff King; Florian Manschwetus; Chris Packham; Konstantin Khomoutov; [email protected]
Betreff: Re: [PATCH] http-backend: respectCONTENT_LENGTHas specified by rfc3875Quoted 3 lines · Max Kirillov
http-backend reads whole input until EOF. However, the RFC 3875 specifies that a script must read only as many bytes as specified by
CONTENT_LENGTHenvironment variable. This causes hang underIIS/Windows, for example.
Quoted 4 lines
Make http-backend read only
CONTENT_LENGTHbytes, if it's defined, rather than the whole input until EOF. If the varibale is not defined, keep older behavior of reading until EOF because it is used to supportchunked transfer-encoding.
Quoted 2 lines
Signed-off-by Florian Manschwetus <manschwetus@cs-software-gmbh.de>
Quoted 1 line
Authored-by Florian Manschwetus <manschwetus@cs-software-gmbh.de>
Quoted 5 lines
Fixed-by Max Kirillov <[email protected]>Signed-off-by Max Kirillov <[email protected]>---
...
I hope I marked it correctly in the trailers.It is probably more conventional to do it like so:
From: Florian Manschwetus <[email protected]>
Date: <original date of Florian's patch series>http-backend reads whole input until EOF. However, the RFC 3875... ... chunked transfer-encoding.
Signed-off-by Florian Manschwetus <manschwetus@cs-software-gmbh.de>
[mk: fixed trivial build failures and stuff]Signed-off-by Max Kirillov <[email protected]>---
Review
Quoted 6 lines
(quoted diff) +5
-0+/* + * replacement for original read_request, now renamed to +read_request_eof, + * honoring given content_length (req_len), + * provided by new wrapper function read_request */I agree with Eric's suggestion. In-code comment is read by those who have the current code, without knowing/caring what it used to be. "It used to do this, but replace it with this new thing because..." is a valuable thing to record in the log message, but not here.
Re: [PATCH] http-backend: respect CONTENT_LENGTH as specified by rfc3875
In reply to Junio C HamanoQuoted 11 lines · Junio C Hamano
Quoted 1 line · Max Kirillov
I hope I marked it correctly in the trailers.
It is probably more conventional to do it like so:
From: Florian Manschwetus <[email protected]>
Date: <original date of Florian's patch series>Signed-off-by Florian Manschwetus <[email protected]>[mk: fixed trivial build failures and stuff]Signed-off-by Max Kirillov <[email protected]>
Thanks. Have done so
v4 cover http-backend: respect CONTENT_LENGTH as specified by rfc3875
In reply to Max Kirillov* polished style
* add tests
* marked the authorship more correctly
Max Kirillov (2):
http-backend: respect CONTENT_LENGTH as specified by rfc3875 t5560-http-backend-noserver.sh: add CONTENT_LENGTH cases
Makefile | 1 + config.c | 8 ++++++++ config.h | 1 + http-backend.c | 39 ++++++++++++++++++++++++++++++++++++++- t/helper/test-print-values.c | 10 ++++++++++ t/t5560-http-backend-noserver.sh | 30 ++++++++++++++++++++++++++++++ 6 files changed, 88 insertions(+), 1 deletion(-) create mode 100644 t/helper/test-print-values.c
Signature · 1 line
2.11.0.1122.gc3fec58.dirty
PATCH v4 1/2 http-backend: respect CONTENT_LENGTH as specified by rfc3875
http-backend reads whole input until EOF. However, the RFC 3875 specifies that a script must read only as many bytes as specified by CONTENT_LENGTH environment variable. Web server may exercise the specification by not closing the script's standard input after writing content. In that case http-backend would hang waiting for the input. The issue is known to happen with IIS/Windows, for example.
Make http-backend read only CONTENT_LENGTH bytes, if it's defined, rather than the whole input until EOF. If the variable is not defined, keep older behavior of reading until EOF because it is used to support chunked transfer-encoding.
--- config.c | 8 ++++++++ config.h | 1 + http-backend.c | 39 ++++++++++++++++++++++++++++++++++++++- 3 files changed, 47 insertions(+), 1 deletion(-)
config.c +8 -0
@@ -1525,6 +1525,14 @@ unsigned long git_env_ulong(const char *k, unsigned long val)return val; } +ssize_t git_env_ssize_t (const char *k,ssize_t val) +{ +const char *v =getenv (k); +if (v && !git_parse_ssize_t (v, &val)) +die ("failed to parse %s" , k); +return val; +} +int git_config_system (void ) {return !git_env_bool ("GIT_CONFIG_NOSYSTEM" ,0 );
config.h +1 -0
@@ -74,6 +74,7 @@ extern int git_config_rename_section_in_file(const char *, const char *, const cextern const char *git_etc_gitconfig (void );extern int git_env_bool (const char *,int );extern unsigned long git_env_ulong (const char *,unsigned long ); +extern ssize_t git_env_ssize_t (const char *,ssize_t );extern int git_config_system (void );extern int config_error_nonbool (const char *);#if defined(__GNUC__)
http-backend.c +38 -1
@@ -280,7 +280,7 @@ static struct rpc_service *select_service(struct strbuf *hdr, const char *name)* hit max_request_buffer we die (we'd rather reject a * maliciously large request than chew up infinite memory). */ -static ssize_t read_request (int fd,unsigned char **out) +static ssize_t read_request_eof (int fd,unsigned char **out) {size_t len =0 , alloc =8192 ;unsigned char *buf =xmalloc (alloc);
@@ -317,6 +317,43 @@ static ssize_t read_request(int fd, unsigned char **out) } } +static ssize_t read_request_fixed_len (int fd,ssize_t req_len,unsigned char **out) +{ +unsigned char *buf =NULL ; +ssize_t cnt =0 ; + +if (max_request_buffer < req_len) { +die ("request was larger than our maximum size (%lu): %lu;" +" try setting GIT_HTTP_MAX_REQUEST_BUFFER" , + max_request_buffer, + req_len); + } + +if (req_len <=0 ) { + *out =NULL ; +return 0 ; + } + + buf =xmalloc (req_len); + cnt =read_in_full (fd, buf, req_len); +if (cnt <0 ) { +free (buf); +return -1 ; + }else { + *out = buf; +return cnt; + } +} + +static ssize_t read_request (int fd,unsigned char **out) +{ +ssize_t req_len =git_env_ssize_t ("CONTENT_LENGTH" ,-1 ); +if (req_len <0 ) +return read_request_eof (fd, out); +else +return read_request_fixed_len (fd, req_len, out); +} +static void inflate_request (const char *prog_name,int out,int buffer_input) {git_zstream stream;
Signature · 1 line
2.11.0.1122.gc3fec58.dirty
PATCH v4 2/2 t5560-http-backend-noserver.sh: add CONTENT_LENGTH cases
Add tests for cases:
* CONTENT_LENGTH is set, script's stdin has more data.
(Failure would make it read GIT_HTTP_MAX_REQUEST_BUFFER bytes from /dev/zero and fail. It does not seem to cause any performance issues with the default value of GIT_HTTP_MAX_REQUEST_BUFFER.)
* CONTENT_LENGTH is specified to a value which does not fix into ssize_t.
--- Makefile | 1 + t/helper/test-print-values.c | 10 ++++++++++ t/t5560-http-backend-noserver.sh | 30 ++++++++++++++++++++++++++++++ 3 files changed, 41 insertions(+) create mode 100644 t/helper/test-print-values.c
Makefile +1 -0
@@ -653,6 +653,7 @@ TEST_PROGRAMS_NEED_X += test-mktemp TEST_PROGRAMS_NEED_X += test-online-cpus TEST_PROGRAMS_NEED_X += test-parse-options TEST_PROGRAMS_NEED_X += test-path-utils +TEST_PROGRAMS_NEED_X += test-print-values TEST_PROGRAMS_NEED_X += test-prio-queue TEST_PROGRAMS_NEED_X += test-read-cache TEST_PROGRAMS_NEED_X += test-ref-store
t/helper/test-print-values.c new file +10 -0
@@ -0,0 +1,10 @@ +#include <stdio.h> +#include <string.h> + +int cmd_main (int argc,const char **argv) +{ +if (argc ==2 &&strcmp (argv[1 ],"(size_t)(-20)" ) ==0 ) +printf ("%zu" , (ssize_t )(-20 )); + +return 0 ; +}
t/t5560-http-backend-noserver.sh +30 -0
@@ -71,4 +71,34 @@ test_expect_success 'http-backend blocks bad PATH_INFO' ' expect_aliased 1 //domain/data.txt ' +# overrides existing definition for further cases +run_backend() { + CONTENT_LENGTH="${#2}" && export CONTENT_LENGTH && + ( echo "$2" && cat /dev/zero ) | + QUERY_STRING="${1#*[?]}" \ + PATH_TRANSLATED="$HTTPD_DOCUMENT_ROOT_PATH/${1%%[?]*}" \ + git http-backend >act.out 2>act.err +} + +test_expect_success 'CONTENT_LENGTH set and infinite input' ' + config http.uploadpack true && + GET info/refs?service=git-upload-pack "200 OK" && + ! grep "fatal:.*" act.err && + POST git-upload-pack 0000 "200 OK" && + ! grep "fatal:.*" act.err +' + +test_expect_success 'CONTENT_LENGTH overflow ssite_t' ' + NOT_FIT_IN_SSIZE=`"$GIT_BUILD_DIR/t/helper/test-print-values" "(size_t)(-20)"` && + env \ + CONTENT_TYPE=application/x-git-upload-pack-request \ + QUERY_STRING=/repo.git/git-upload-pack \ + PATH_TRANSLATED="$PWD"/.git/git-upload-pack \ + GIT_HTTP_EXPORT_ALL=TRUE \ + REQUEST_METHOD=POST \ + CONTENT_LENGTH="$NOT_FIT_IN_SSIZE" \ + git http-backend </dev/zero >/dev/null 2>err && + grep -q "fatal:.*CONTENT_LENGTH" err +' + test_done
Signature · 1 line
2.11.0.1122.gc3fec58.dirty
v5 cover http-backend: respect CONTENT_LENGTH as specified by rfc3875
In reply to Max KirillovI seem to forgot to put the authorship lines, and also did something with replies, so sending another sequence.
v5:
* marked the authorship more correctly
v4:
* polished style
* add tests
Max Kirillov (2):
http-backend: respect CONTENT_LENGTH as specified by rfc3875 t5560-http-backend-noserver.sh: add CONTENT_LENGTH cases
Makefile | 1 + config.c | 8 ++++++++ config.h | 1 + http-backend.c | 39 ++++++++++++++++++++++++++++++++++++++- t/helper/test-print-values.c | 10 ++++++++++ t/t5560-http-backend-noserver.sh | 30 ++++++++++++++++++++++++++++++ 6 files changed, 88 insertions(+), 1 deletion(-) create mode 100644 t/helper/test-print-values.c
Signature · 1 line
2.11.0.1122.gc3fec58.dirty
PATCH v5 1/2 http-backend: respect CONTENT_LENGTH as specified by rfc3875
Author: Florian Manschwetus <[email protected]>
Date: Wed, 30 Mar 2016 09:08:56 +0000
http-backend reads whole input until EOF. However, the RFC 3875 specifies that a script must read only as many bytes as specified by CONTENT_LENGTH environment variable. Web server may exercise the specification by not closing the script's standard input after writing content. In that case http-backend would hang waiting for the input. The issue is known to happen with IIS/Windows, for example.
Make http-backend read only CONTENT_LENGTH bytes, if it's defined, rather than the whole input until EOF. If the variable is not defined, keep older behavior of reading until EOF because it is used to support chunked transfer-encoding.
--- config.c | 8 ++++++++ config.h | 1 + http-backend.c | 39 ++++++++++++++++++++++++++++++++++++++- 3 files changed, 47 insertions(+), 1 deletion(-)
config.c +8 -0
@@ -1525,6 +1525,14 @@ unsigned long git_env_ulong(const char *k, unsigned long val)return val; } +ssize_t git_env_ssize_t (const char *k,ssize_t val) +{ +const char *v =getenv (k); +if (v && !git_parse_ssize_t (v, &val)) +die ("failed to parse %s" , k); +return val; +} +int git_config_system (void ) {return !git_env_bool ("GIT_CONFIG_NOSYSTEM" ,0 );
config.h +1 -0
@@ -74,6 +74,7 @@ extern int git_config_rename_section_in_file(const char *, const char *, const cextern const char *git_etc_gitconfig (void );extern int git_env_bool (const char *,int );extern unsigned long git_env_ulong (const char *,unsigned long ); +extern ssize_t git_env_ssize_t (const char *,ssize_t );extern int git_config_system (void );extern int config_error_nonbool (const char *);#if defined(__GNUC__)
http-backend.c +38 -1
@@ -280,7 +280,7 @@ static struct rpc_service *select_service(struct strbuf *hdr, const char *name)* hit max_request_buffer we die (we'd rather reject a * maliciously large request than chew up infinite memory). */ -static ssize_t read_request (int fd,unsigned char **out) +static ssize_t read_request_eof (int fd,unsigned char **out) {size_t len =0 , alloc =8192 ;unsigned char *buf =xmalloc (alloc);
@@ -317,6 +317,43 @@ static ssize_t read_request(int fd, unsigned char **out) } } +static ssize_t read_request_fixed_len (int fd,ssize_t req_len,unsigned char **out) +{ +unsigned char *buf =NULL ; +ssize_t cnt =0 ; + +if (max_request_buffer < req_len) { +die ("request was larger than our maximum size (%lu): %lu;" +" try setting GIT_HTTP_MAX_REQUEST_BUFFER" , + max_request_buffer, + req_len); + } + +if (req_len <=0 ) { + *out =NULL ; +return 0 ; + } + + buf =xmalloc (req_len); + cnt =read_in_full (fd, buf, req_len); +if (cnt <0 ) { +free (buf); +return -1 ; + }else { + *out = buf; +return cnt; + } +} + +static ssize_t read_request (int fd,unsigned char **out) +{ +ssize_t req_len =git_env_ssize_t ("CONTENT_LENGTH" ,-1 ); +if (req_len <0 ) +return read_request_eof (fd, out); +else +return read_request_fixed_len (fd, req_len, out); +} +static void inflate_request (const char *prog_name,int out,int buffer_input) {git_zstream stream;
Signature · 1 line
2.11.0.1122.gc3fec58.dirty
Re: [PATCH v5 1/2] http-backend: respect CONTENT_LENGTH as specified by rfc3875
Quoted 1 line · Max Kirillov
Author: Florian Manschwetus <[email protected]>
This should read "From: ...";
Quoted 9 lines
Date: Wed, 30 Mar 2016 09:08:56 +0000
http-backend reads whole input until EOF. However, the RFC 3875 specifies that a script must read only as many bytes as specified by
CONTENT_LENGTHenvironment variable. Web server may exercise the specification by not closing the script's standard input after writing content. In that case http-backend would hang waiting for the input. The issue is known to happen with IIS/Windows, for example.
Quoted 8 lines
Make http-backend read only
CONTENT_LENGTHbytes, if it's defined, rather than the whole input until EOF. If the variable is not defined, keep older behavior of reading until EOF because it is used to support chunked transfer-encoding.Signed-off-by Florian Manschwetus <[email protected]>[mk: fixed trivial build failures and polished style issues]Signed-off-by Max Kirillov <[email protected]>
There shouldn't be a blank line before your sign-off.
The above are only for future reference; I can fix them up before queuing if there isn't any other issues in this patch.
config.c unsigned long git_env_ulong(const char *k, unsigned long val) · line 1535
Quoted 8 lines
config.c +8
-0+ssize_t git_env_ssize_t (const char *k,ssize_t val) +{ +const char *v =getenv (k); +if (v && !git_parse_ssize_t (v, &val)) +die ("failed to parse %s" , k); +return val; +} +
If this were passing "v" that is a string the caller obtains from any source (and the callee does not care about where it came from), that would be a different story, but as a public interface that is part of the config.c layer, "k" that has to be the name of the environment variable sticks out like a sore thumb.
If we were to add one more public function to the interface, I suspect that exposing the existing git_parse_ssize_t() and have the caller implement the above function for its use would be a much better way to go.
Re: [PATCH v5 1/2] http-backend: respect CONTENT_LENGTH as specified by rfc3875
Quoted 16 lines · Junio C Hamano
Review
Quoted 8 lines · Max Kirillov
(quoted diff) +8
-0+ssize_t git_env_ssize_t(const char *k, ssize_t val) +{ + const char *v = getenv(k); + if (v && !git_parse_ssize_t(v, &val)) + die("failed to parse %s", k); + return val; +} +If this were passing "v" that is a string the caller obtains from any source (and the callee does not care about where it came from), that would be a different story, but as a public interface that is part of the
config.clayer, "k" that has to be the name of the environment variable sticks out like a sore thumb.
Quoted 4 lines
If we were to add one more public function to the interface, I suspect that exposing the existing
git_parse_ssize_t()and have the caller implement the above function for its use would be a much better way to go.
I'm afraid I did not get the reasonsing and not fully the desired change. Is this http-backend code change (compared to the last patch) what you mean?
http-backend.c +10 -1
@@ -346,9 +346,18 @@ static ssize_t read_request_fixed_len(int fd, ssize_t req_len, unsigned char **o } } +static ssize_t env_content_length () +{ +const char *str =getenv ("CONTENT_LENGTH" ); +ssize_t val =-1 ; +if (str && !git_parse_ssize_t (str, &val)) +die ("failed to parse CONTENT_LENGTH: %s" , str); +return val; +} +static ssize_t read_request (int fd,unsigned char **out) { -ssize_t req_len =git_env_ssize_t ("CONTENT_LENGTH" ,-1 ); +ssize_t req_len =env_content_length ();if (req_len <0 )return read_request_eof (fd, out);else
Re: [PATCH v5 1/2] http-backend: respect CONTENT_LENGTH as specified by rfc3875
Quoted 3 lines · Max Kirillov
I'm afraid I did not get the reasonsing and not fully the desired change. Is this http-backend code change (compared to the last patch) what you mean?
Exactly.
The fact that the parsed string happens to come from CONTENT_LENGTH environment variable is http's business, not parsers for various types of values that come in the form of strings.
http-backend.c static ssize_t read_request_fixed_len(int fd, ssize_t req_len, unsigned char **o · line 349
Quoted 7 lines
http-backend.c +1
-0@@ -346,9 +346,18 @@ static ssize_t read_request_fixed_len(int fd, ssize_t req_len, unsigned char **o } } +static ssize_t env_content_length ()
We need s/length()/length(void)/; though.
Quoted 15 lines
http-backend.c +9
-1+{ +const char *str =getenv ("CONTENT_LENGTH" ); +ssize_t val =-1 ; +if (str && !git_parse_ssize_t (str, &val)) +die ("failed to parse CONTENT_LENGTH: %s" , str); +return val; +} +static ssize_t read_request (int fd,unsigned char **out) { -ssize_t req_len =git_env_ssize_t ("CONTENT_LENGTH" ,-1 ); +ssize_t req_len =env_content_length ();if (req_len <0 )return read_request_eof (fd, out);else
Re: [PATCH v5 1/2] http-backend: respect CONTENT_LENGTH as specified by rfc3875
Quoted 4 lines · Junio C Hamano
Quoted 1 line · Max Kirillov
+static
ssize_tenv_content_length()We need s/length()/length(void)/; though.
thanks, fixed it
PATCH v5 2/2 t5560-http-backend-noserver.sh: add CONTENT_LENGTH cases
In reply to Max KirillovAdd tests for cases:
* CONTENT_LENGTH is set, script's stdin has more data.
(Failure would make it read GIT_HTTP_MAX_REQUEST_BUFFER bytes from /dev/zero and fail. It does not seem to cause any performance issues with the default value of GIT_HTTP_MAX_REQUEST_BUFFER.)
* CONTENT_LENGTH is specified to a value which does not fix into ssize_t.
--- Makefile | 1 + t/helper/test-print-values.c | 10 ++++++++++ t/t5560-http-backend-noserver.sh | 30 ++++++++++++++++++++++++++++++ 3 files changed, 41 insertions(+) create mode 100644 t/helper/test-print-values.c
Makefile +1 -0
@@ -653,6 +653,7 @@ TEST_PROGRAMS_NEED_X += test-mktemp TEST_PROGRAMS_NEED_X += test-online-cpus TEST_PROGRAMS_NEED_X += test-parse-options TEST_PROGRAMS_NEED_X += test-path-utils +TEST_PROGRAMS_NEED_X += test-print-values TEST_PROGRAMS_NEED_X += test-prio-queue TEST_PROGRAMS_NEED_X += test-read-cache TEST_PROGRAMS_NEED_X += test-ref-store
t/helper/test-print-values.c new file +10 -0
@@ -0,0 +1,10 @@ +#include <stdio.h> +#include <string.h> + +int cmd_main (int argc,const char **argv) +{ +if (argc ==2 &&strcmp (argv[1 ],"(size_t)(-20)" ) ==0 ) +printf ("%zu" , (ssize_t )(-20 )); + +return 0 ; +}
t/t5560-http-backend-noserver.sh +30 -0
@@ -71,4 +71,34 @@ test_expect_success 'http-backend blocks bad PATH_INFO' ' expect_aliased 1 //domain/data.txt ' +# overrides existing definition for further cases +run_backend() { + CONTENT_LENGTH="${#2}" && export CONTENT_LENGTH && + ( echo "$2" && cat /dev/zero ) | + QUERY_STRING="${1#*[?]}" \ + PATH_TRANSLATED="$HTTPD_DOCUMENT_ROOT_PATH/${1%%[?]*}" \ + git http-backend >act.out 2>act.err +} + +test_expect_success 'CONTENT_LENGTH set and infinite input' ' + config http.uploadpack true && + GET info/refs?service=git-upload-pack "200 OK" && + ! grep "fatal:.*" act.err && + POST git-upload-pack 0000 "200 OK" && + ! grep "fatal:.*" act.err +' + +test_expect_success 'CONTENT_LENGTH overflow ssite_t' ' + NOT_FIT_IN_SSIZE=`"$GIT_BUILD_DIR/t/helper/test-print-values" "(size_t)(-20)"` && + env \ + CONTENT_TYPE=application/x-git-upload-pack-request \ + QUERY_STRING=/repo.git/git-upload-pack \ + PATH_TRANSLATED="$PWD"/.git/git-upload-pack \ + GIT_HTTP_EXPORT_ALL=TRUE \ + REQUEST_METHOD=POST \ + CONTENT_LENGTH="$NOT_FIT_IN_SSIZE" \ + git http-backend </dev/zero >/dev/null 2>err && + grep -q "fatal:.*CONTENT_LENGTH" err +' + test_done
Signature · 1 line
2.11.0.1122.gc3fec58.dirty
v6 cover http-backend: respect CONTENT_LENGTH as specified by rfc3875
In reply to Max Kirillovv6:
Do not implement generic git_env_ssize_t(), instead export git_parse_ssize_t() from config.c and hardcode the rest.
Florian Manschwetus (1):
http-backend: respect CONTENT_LENGTH as specified by rfc3875
Max Kirillov (1):
t5560-http-backend-noserver.sh: add CONTENT_LENGTH cases
Makefile | 1 + config.c | 2 +- config.h | 1 + http-backend.c | 50 +++++++++++++++++++++++++++++++++++++++- t/helper/test-print-values.c | 10 ++++++++ t/t5560-http-backend-noserver.sh | 30 ++++++++++++++++++++++++ 6 files changed, 92 insertions(+), 2 deletions(-) create mode 100644 t/helper/test-print-values.c
Signature · 1 line
2.11.0.1122.gc3fec58.dirty
PATCH v6 1/2 http-backend: respect CONTENT_LENGTH as specified by rfc3875
From: Florian Manschwetus <[email protected]>
From: Florian Manschwetus <[email protected]>
Date: Wed, 30 Mar 2016 10:54:21 +0200
http-backend reads whole input until EOF. However, the RFC 3875 specifies that a script must read only as many bytes as specified by CONTENT_LENGTH environment variable. Web server may exercise the specification by not closing the script's standard input after writing content. In that case http-backend would hang waiting for the input. The issue is known to happen with IIS/Windows, for example.
Make http-backend read only CONTENT_LENGTH bytes, if it's defined, rather than the whole input until EOF. If the variable is not defined, keep older behavior of reading until EOF because it is used to support chunked transfer-encoding.
--- config.c | 2 +- config.h | 1 + http-backend.c | 50 +++++++++++++++++++++++++++++++++++++++++++++++++- 3 files changed, 51 insertions(+), 2 deletions(-)
config.c +1 -1
@@ -853,7 +853,7 @@ int git_parse_ulong(const char *value, unsigned long *ret)return 1 ; } -static int git_parse_ssize_t (const char *value,ssize_t *ret) +int git_parse_ssize_t (const char *value,ssize_t *ret) {intmax_t tmp;if (!git_parse_signed (value, &tmp,maximum_signed_value_of_type (ssize_t)))
config.h +1 -0
@@ -48,6 +48,7 @@ extern void git_config(config_fn_t fn, void *);extern int config_with_options (config_fn_t fn,void *,struct git_config_source *config_source,const struct config_options *opts); +extern int git_parse_ssize_t (const char *,ssize_t *);extern int git_parse_ulong (const char *,unsigned long *);extern int git_parse_maybe_bool (const char *);extern int git_config_int (const char *,const char *);
http-backend.c +49 -1
62 lines not on this page · raw message
Signature · 1 line
2.11.0.1122.gc3fec58.dirty
Re: [PATCH v6 1/2] http-backend: respect CONTENT_LENGTH as specified by rfc3875
Quoted 5 lines · Max Kirillov
[...]
Make http-backend read onlyCONTENT_LENGTHbytes, if it's defined, rather than the whole input until EOF. If the variable is not defined, keep older behavior of reading until EOF because it is used to support chunked transfer-encoding. [...]
A few small comments below; with the possible exception of one, probably none worth a re-roll...
http-backend.c static ssize_t read_request(int fd, unsigned char **out) · line 326
Quoted 12 lines
http-backend.c +10
-0@@ -317,6 +317,54 @@ static ssize_t read_request(int fd, unsigned char **out) +static ssize_t read_request_fixed_len (int fd,ssize_t req_len,unsigned char **out) +{ +unsigned char *buf =NULL ; +ssize_t cnt =0 ; + +if (max_request_buffer < req_len) { +die ("request was larger than our maximum size (%lu): %lu;" +" try setting GIT_HTTP_MAX_REQUEST_BUFFER" , + max_request_buffer, + req_len);
Unsigned format conversion '%lu' doesn't seem correct for ssize_t.
Quoted 6 lines
http-backend.c +6
-0+ } + +if (req_len <=0 ) { + *out =NULL ; +return 0 ; + }
http-backend.c static ssize_t read_request(int fd, unsigned char **out) · line 345
Quoted 10 lines
http-backend.c +10
-0+ + buf =xmalloc (req_len); + cnt =read_in_full (fd, buf, req_len); +if (cnt <0 ) { +free (buf); +return -1 ; + }else { + *out = buf; +return cnt; + }
This could have been written:
if (cnt < 0) {
free(buf);
return -1;
}
*out = buf;
return cnt;but not worth a re-roll.
http-backend.c static ssize_t read_request(int fd, unsigned char **out) · line 348
Quoted 3 lines
http-backend.c +3
-0+} + +static ssize_t env_content_length (void )
The caller of this function doesn't care how the content length is being determined -- whether it comes from an environment variable or is computed some other way; it cares only about the result. Having "env" in the name ties it to checking only the environment. A more generic name, such as get_content_length(), would help to decouple the API from the implementation.
Nevertheless, not worth a re-roll.
http-backend.c static ssize_t read_request(int fd, unsigned char **out) · line 353
Quoted 5 lines
http-backend.c +5
-0+{ +ssize_t val =-1 ; +const char *str =getenv ("CONTENT_LENGTH" ); + +if (str && !git_parse_ssize_t (str, &val))
git_parse_ssize_t() does the right thing even when 'str' is NULL, so this condition could be simplified (but not worth a re-roll and may not improve clarity).
http-backend.c static ssize_t read_request(int fd, unsigned char **out) · line 360
Quoted 7 lines
http-backend.c +7
-0+die ("failed to parse CONTENT_LENGTH: %s" , str); +return val; +} + +static ssize_t read_request (int fd,unsigned char **out) +{ +ssize_t req_len =env_content_length ();
Grabbing and parsing the value from the environment variable is effectively a one-liner, so env_content_length() could be dropped altogether, and instead (taking advantage of git_parse_ssize_t()'s proper NULL-handling):
if (!git_parse_ssize_t(getenv(...), &req_len))
die(...);Not worth a re-roll.
Quoted 5 lines
http-backend.c +5
-0+if (req_len <0 ) +return read_request_eof (fd, out); +else +return read_request_fixed_len (fd, req_len, out); +}
Re: [PATCH v6 1/2] http-backend: respect CONTENT_LENGTH as specified by rfc3875
In reply to Max KirillovQuoted 10 lines · Max Kirillov
From: Florian Manschwetus <[email protected]>
Date: Wed, 30 Mar 2016 10:54:21 +0200http-backend reads whole input until EOF. However, the RFC 3875 specifies that a script must read only as many bytes as specified by
CONTENT_LENGTHenvironment variable. Web server may exercise the specification by not closing the script's standard input after writing content. In that case http-backend would hang waiting for the input. The issue is known to happen with IIS/Windows, for example.
Quoted 3 lines
Make http-backend read only
CONTENT_LENGTHbytes, if it's defined, rather than the whole input until EOF. If the variable is not defined, keep older behavior of reading until EOF because it is used to support chunked transfer-encoding.
I missed out on review of the earlier iterations from the past few days, but I looked this over in light of the comments I made long ago in:
https://public-inbox.org/git/[email protected]/
The concerns I had there were:
1. It did the wrong thing when CONTENT_LENGTH was not present in the environment. Your version here gets this right.
2. I earlier was worried that this wouldn't kick in for the inflate_request() code path. It looks like we do use read_request() from inflate_request(), but only when buffer_input is true. Which means we wouldn't do so for receive-pack (i.e., for pushes).
I'm not sure if the client would ever gzip a push request. Without double-checking, I suspect it would if the list of refs to update was sufficiently large (and at any rate, I think other clients potentially could do so).
That _might_ be OK in practice. If the gzip stream is well-formed, we'd stop at its end. We'd possibly still try to read() more bytes than were promised, but if I understand the original problem, that's not that big a deal as long as we don't hang waiting for EOF.
If the stream isn't well-formed, we'd hang waiting for more bytes (rather than seeing the EOF and complaining that the gzip stream is truncated). That's poor, but no worse than the current behavior.
3. For large inputs (like incoming packfiles), we connect the descriptor directly to index-pack or unpack-objects, and they try to read to EOF.
For a well-formed pack, I _think_ this would work OK. We'd see the end of the pack and quit (there's a check for garbage at the end of the pack, but it triggers only for the non-pipe case).
For a truncated input, we'd hang forever rather than report an error.
So I suspect there are lurking problems that may trigger in corner cases. That said, I don't think this pack makes any case _worse_, and it may make some common ones better. So I'm not opposed, though we may be giving people a false sense of security that it actually works robustly on IIS.
Quoted 5 lines
--- config.c | 2 +- config.h | 1 + http-backend.c | 50 +++++++++++++++++++++++++++++++++++++++++++++++++- 3 files changed, 51 insertions(+), 2 deletions(-)
The patch itself looks OK, modulo the comments already made by others. Two minor observations, and a possible bug:
Review
Quoted 2 lines
(quoted diff) +2
-0+static ssize_t read_request_fixed_len(int fd, ssize_t req_len, unsigned char **out) +{
I did wonder if this "stop at n bytes" could simply be rolled into the existing read_request loop (by limiting the length we pass to read_in_full there). But it may be cleaner to just have a separate function. There's some repetition, but not much since we can rely on a single malloc and read_in_full() for this case.
Quoted 4 lines
http-backend.c +4
-0+unsigned char *buf =NULL ; +ssize_t cnt =0 ; + +if (max_request_buffer < req_len) {
http-backend.c static ssize_t read_request(int fd, unsigned char **out) · line 335
Quoted 10 lines
http-backend.c +10
-0+die ("request was larger than our maximum size (%lu): %lu;" +" try setting GIT_HTTP_MAX_REQUEST_BUFFER" , + max_request_buffer, + req_len); + } + +if (req_len <=0 ) { + *out =NULL ; +return 0 ; + }
I was slightly surprised by "<= 0" here. We should never get here with a negative req_len, since we'd catch that in the read_request() wrapper here. If we want to document that assumption, should this be assert(req_len >= 0)?
I'm also puzzled about the behavior with a zero-byte CONTENT_LENGTH. We'd return NULL here. But in the other read_request_eof() path, we'd end up with a non-NULL pointer. I'm not sure if it matters to the caller or not, but it seems like a potential trap.
Is it even worth special-casing here? Our xmalloc and read_in_full wrappers should handle the zero-byte just fine. I think this whole conditional could just go away.
-Peff
Re: [PATCH v6 1/2] http-backend: respect CONTENT_LENGTH as specified by rfc3875
Quoted 10 lines · Jeff King
3. For large inputs (like incoming packfiles), we connect the descriptor directly to index-pack or unpack-objects, and they try to read to EOF.
For a well-formed pack, I _think_ this would work OK. We'd see the end of the pack and quit (there's a check for garbage at the end of the pack, but it triggers only for the non-pipe case).
For a truncated input, we'd hang forever rather than report an error.
Hmm. index-pack and/or unpack-objects would be fed directly from the incoming pipe, they are not told how many bytes to expect (by design), so they try to read to EOF, which may come after the end of the pack-stream data, and they write the remaining junk to their standard output IIRC.
For a well-formed pack, the above is what should heppen.
I am having trouble trying to come up with a case where the input stream is mangled and we cannot detect where the end of the pack-stream is without reading more than we will be fed through the pipe, and yet we do not trigger an "we tried to read because the data we received so far is incomplete, and got an EOF" error.
Wouldn't "early EOF" trigger in the fill() helper that these two programs have (but not share X-<)?
Re: [PATCH v6 1/2] http-backend: respect CONTENT_LENGTH as specified by rfc3875
Quoted 13 lines · Junio C Hamano
Quoted 10 lines · Jeff King
3. For large inputs (like incoming packfiles), we connect the descriptor directly to index-pack or unpack-objects, and they try to read to EOF.
For a well-formed pack, I _think_ this would work OK. We'd see the end of the pack and quit (there's a check for garbage at the end of the pack, but it triggers only for the non-pipe case).
For a truncated input, we'd hang forever rather than report an error.
Quoted 7 lines
Hmm. index-pack and/or unpack-objects would be fed directly from the incoming pipe, they are not told how many bytes to expect (by design), so they try to read to EOF, which may come after the end of the pack-stream data, and they write the remaining junk to their standard output IIRC.
For a well-formed pack, the above is what should heppen.
Yeah, there should be zero bytes of "remaining junk" in the normal well-formed case. And as long as the webserver does not mind us asking to read() a few extra bytes, we are fine (it tells us there are no more bytes available right now). The original problem report with IIS was that it would hang trying to read() that any final EOF, and I don't think that would happen here.
I wouldn't be surprised if there are webservers or situations where that extra read() behaves badly (e.g., because it is connected directly to the client socket and the client is trying to pipeline requests or something).
Quoted 8 lines
I am having trouble trying to come up with a case where the input stream is mangled and we cannot detect where the end of the pack-stream is without reading more than we will be fed through the pipe, and yet we do not trigger an "we tried to read because the data we received so far is incomplete, and got an EOF" error.
Wouldn't "early EOF" trigger in the
fill()helper that these two programs have (but not share X-<)?
I think the original problem was the opposite of "early EOF": the other side of the pipe never gives us EOF at all. So imagine the pack is mangled so that the zlib stream of an object never ends, and just keeps asking for more data. Eventually our fill() will block trying to get data that is not there. On an Apache server, the webserver would know there is nothing left to send us and close() the pipe, and we'd get EOF. But on IIS, I think the pipe remains open and we'd just block indefinitely trying to read().
I don't have such a setup to test on, and it's possible I'm mis-interpreting or mis-remembering the discussion around the original patch.
-Peff
Re: [PATCH v6 1/2] http-backend: respect CONTENT_LENGTH as specified by rfc3875
Quoted 5 lines · Jeff King
... Eventually our
fill()will block trying to get data that is not there. On an Apache server, the webserver would know there is nothing left to send us andclose()the pipe, and we'd get EOF. But on IIS, I think the pipe remains open and we'd just block indefinitely trying toread().
Ah, yeah, under that scenario, trusting content-length and trying to read, waiting for input that would never come, will be a problem, and it would probably want to get documented.
AW: [PATCH v6 1/2] http-backend: respect CONTENT_LENGTH as specified by rfc3875
Hi All,
I could provide a bash script I used in between to make this working with IIS, without fixing http-backend binary, maybe this helps to understand how this cases might be handled.
Mit freundlichen Grüßen / With kind regards
Florian Manschwetus
Quoted 20 lines
-----Ursprüngliche Nachricht-----
Von: Junio C Hamano [mailto:[email protected]]
Gesendet: Sonntag, 3. Dezember 2017 07:07
An: Jeff King
Cc: Max Kirillov; Eric Sunshine; Florian Manschwetus; Chris Packham; Konstantin Khomoutov; [email protected]
Betreff: Re: [PATCH v6 1/2] http-backend: respectCONTENT_LENGTHas specified by rfc3875Quoted 5 lines · Jeff King
... Eventually our
fill()will block trying to get data that is not there. On an Apache server, the webserver would know there is nothing left to send us andclose()the pipe, and we'd get EOF. But on IIS, I think the pipe remains open and we'd just block indefinitely trying toread().Ah, yeah, under that scenario, trusting content-length and trying to read, waiting for input that would never come, will be a problem, and it would probably want to get documented.
Re: [PATCH v6 1/2] http-backend: respect CONTENT_LENGTH as specified by rfc3875
Quoted 3 lines · Florian Manschwetus
I could provide a bash script I used in between to make this working with IIS, without fixing http-backend binary, maybe this helps to understand how this cases might be handled.
I think it would be pretty easy to handle all cases by inserting another process in front of http-backend that just reads $CONTENT_LENGTH bytes and then gives an EOF to http-backend. I assume that's what your bash script does. It's just that this passes the data through an extra layer of pipes.
If that's an acceptable tradeoff, it seems like an ideal solution from a maintainability standpoint, since it skips all the tricky situations inside the http-backend code.
-Peff
PATCH v6 2/2 t5560-http-backend-noserver.sh: add CONTENT_LENGTH cases
In reply to Max KirillovAdd tests for cases:
* CONTENT_LENGTH is set, script's stdin has more data.
(Failure would make it read GIT_HTTP_MAX_REQUEST_BUFFER bytes from /dev/zero and fail. It does not seem to cause any performance issues with the default value of GIT_HTTP_MAX_REQUEST_BUFFER.)
* CONTENT_LENGTH is specified to a value which does not fix into ssize_t.
--- Makefile | 1 + t/helper/test-print-values.c | 10 ++++++++++ t/t5560-http-backend-noserver.sh | 30 ++++++++++++++++++++++++++++++ 3 files changed, 41 insertions(+) create mode 100644 t/helper/test-print-values.c
Makefile +1 -0
@@ -653,6 +653,7 @@ TEST_PROGRAMS_NEED_X += test-mktemp TEST_PROGRAMS_NEED_X += test-online-cpus TEST_PROGRAMS_NEED_X += test-parse-options TEST_PROGRAMS_NEED_X += test-path-utils +TEST_PROGRAMS_NEED_X += test-print-values TEST_PROGRAMS_NEED_X += test-prio-queue TEST_PROGRAMS_NEED_X += test-read-cache TEST_PROGRAMS_NEED_X += test-ref-store
t/helper/test-print-values.c new file +10 -0
@@ -0,0 +1,10 @@ +#include <stdio.h> +#include <string.h> + +int cmd_main (int argc,const char **argv) +{ +if (argc ==2 &&strcmp (argv[1 ],"(size_t)(-20)" ) ==0 ) +printf ("%zu" , (ssize_t )(-20 )); + +return 0 ; +}
t/t5560-http-backend-noserver.sh +30 -0
@@ -71,4 +71,34 @@ test_expect_success 'http-backend blocks bad PATH_INFO' ' expect_aliased 1 //domain/data.txt ' +# overrides existing definition for further cases +run_backend() { + CONTENT_LENGTH="${#2}" && export CONTENT_LENGTH && + ( echo "$2" && cat /dev/zero ) | + QUERY_STRING="${1#*[?]}" \ + PATH_TRANSLATED="$HTTPD_DOCUMENT_ROOT_PATH/${1%%[?]*}" \ + git http-backend >act.out 2>act.err +} + +test_expect_success 'CONTENT_LENGTH set and infinite input' ' + config http.uploadpack true && + GET info/refs?service=git-upload-pack "200 OK" && + ! grep "fatal:.*" act.err && + POST git-upload-pack 0000 "200 OK" && + ! grep "fatal:.*" act.err +' + +test_expect_success 'CONTENT_LENGTH overflow ssite_t' ' + NOT_FIT_IN_SSIZE=`"$GIT_BUILD_DIR/t/helper/test-print-values" "(size_t)(-20)"` && + env \ + CONTENT_TYPE=application/x-git-upload-pack-request \ + QUERY_STRING=/repo.git/git-upload-pack \ + PATH_TRANSLATED="$PWD"/.git/git-upload-pack \ + GIT_HTTP_EXPORT_ALL=TRUE \ + REQUEST_METHOD=POST \ + CONTENT_LENGTH="$NOT_FIT_IN_SSIZE" \ + git http-backend </dev/zero >/dev/null 2>err && + grep -q "fatal:.*CONTENT_LENGTH" err +' + test_done
Signature · 1 line
2.11.0.1122.gc3fec58.dirty
Re: [PATCH v6 2/2] t5560-http-backend-noserver.sh: add CONTENT_LENGTH cases
Quoted 12 lines · Max Kirillov
Add tests for cases:
*
CONTENT_LENGTHis set, script's stdin has more data.
(Failure would make it readGIT_HTTP_MAX_REQUEST_BUFFERbytes from/dev/zeroand fail. It does not seem to cause any performance issues with the default value ofGIT_HTTP_MAX_REQUEST_BUFFER.)
*CONTENT_LENGTHis specified to a value which does not fix intossize_t.Signed-off-by Max Kirillov <[email protected]>---
t/helper/test-print-values.c line 6
Quoted 6 lines
t/helper/test-print-values.c +6
-0@@ -0,0 +1,10 @@ +int cmd_main (int argc,const char **argv) +{ +if (argc ==2 &&strcmp (argv[1 ],"(size_t)(-20)" ) ==0 ) +printf ("%zu" , (ssize_t )(-20 )); + +return 0 ;
Perhaps this should return 0 only if it gets the expected argument "(size_t)(-20)", and return an error otherwise.
t/t5560-http-backend-noserver.sh test_expect_success 'http-backend blocks bad PATH_INFO' ' · line 72
Quoted 5 lines
t/helper/test-print-values.c +1
-0+}t/t5560-http-backend-noserver.sh +2
-0@@ -71,4 +71,34 @@ test_expect_success 'http-backend blocks bad PATH_INFO' ' +test_expect_success 'CONTENT_LENGTH overflow ssite_t' ' + NOT_FIT_IN_SSIZE=`"$GIT_BUILD_DIR/t/helper/test-print-values" "(size_t)(-20)"` &&
Rather than introducing a new 'test' program, would it be possible to get by with just using 'printf' from the shell?
% printf "%zu\n" -20
18446744073709551596Quoted 10 lines
t/t5560-http-backend-noserver.sh +10
-0+ env \ + CONTENT_TYPE=application/x-git-upload-pack-request \ + QUERY_STRING=/repo.git/git-upload-pack \ + PATH_TRANSLATED="$PWD"/.git/git-upload-pack \ + GIT_HTTP_EXPORT_ALL=TRUE \ + REQUEST_METHOD=POST \ + CONTENT_LENGTH="$NOT_FIT_IN_SSIZE" \ + git http-backend </dev/zero >/dev/null 2>err && + grep -q "fatal:.*CONTENT_LENGTH" err +'
Re: [PATCH v6 2/2] t5560-http-backend-noserver.sh: add CONTENT_LENGTH cases
Quoted 10 lines · Eric Sunshine
t/helper/test-print-values.c line 9
Quoted 6 lines · Max Kirillov
t/helper/test-print-values.c new file +6
-0+int cmd_main (int argc,const char **argv) +{ +if (argc ==2 &&strcmp (argv[1 ],"(size_t)(-20)" ) ==0 ) +printf ("%zu" , (ssize_t )(-20 )); + +return 0 ;Perhaps this should return 0 only if it gets the expected argument "(size_t)(-20)", and return an error otherwise.
Yes, makes sense.
Quoted 5 lines
Rather than introducing a new 'test' program, would it be possible to get by with just using 'printf' from the shell?
% printf "%zu\n" -20 18446744073709551596
I thought about it, of course. But, I am not sure I can exclude cases when the shell's printf uses 64-bit size_t and git 32-bit one, or vise-versa. Same way, I cannot say it for sure for any other software which I might use here instead of the shell's printf. The only somewhat sure way would be to use the same compiler, with same settings, which is used for the production code.
I do not exclude possibility that my reasoning above is wrong, either in general of specifically for git case. If there are some examples where it is already used and the risk of type size mismatch is prevented I could do it similarly.
Re: [PATCH v6 2/2] t5560-http-backend-noserver.sh: add CONTENT_LENGTH cases
Quoted 14 lines · Max Kirillov
Quoted 5 lines
Rather than introducing a new 'test' program, would it be possible to get by with just using 'printf' from the shell?
% printf "%zu\n" -20 18446744073709551596I thought about it, of course. But, I am not sure I can exclude cases when the shell's printf uses 64-bit
size_tand git 32-bit one, or vise-versa. Same way, I cannot say it for sure for any other software which I might use here instead of the shell's printf. The only somewhat sure way would be to use the same compiler, with same settings, which is used for the production code.
Quoted 5 lines
I do not exclude possibility that my reasoning above is wrong, either in general of specifically for git case. If there are some examples where it is already used and the risk of type size mismatch is prevented I could do it similarly.
That's definitely something to worry about, and I have a vague recollection that build differences between the shell environment and git have bitten us in the past.
That said, we already have some precedent in "git version --build-options" to report sizes there. Can we do something like the patch below instead of adding a new test helper?
help.c +1 -0
@@ -413,6 +413,7 @@ int cmd_version(int argc, const char **argv, const char *prefix)if (build_options) {printf ("sizeof-long: %d\n" , (int )sizeof (long )); +printf ("sizeof-size_t: %d\n" , (int )sizeof (size_t ));/* NEEDSWORK: also save and output GIT-BUILD_OPTIONS? */ }return 0 ;
That does still require you to compute size_t based on the byte-size in the test script, that should be do-able.
-Peff
Re: [PATCH v6 2/2] t5560-http-backend-noserver.sh: add CONTENT_LENGTH cases
Quoted 10 lines · Jeff King
On Mon, Nov 27, 2017 at 12:40:51AM +0200, Max Kirillov wrote:
That said, we already have some precedent in "git version --build-options" to report sizes there. Can we do something like the patch below instead of adding a new test helper?help.c +0
-0
help.c int cmd_version(int argc, const char **argv, const char *prefix) · line 419
Quoted 7 lines
help.c +1
-0@@ -413,6 +413,7 @@ int cmd_version(int argc, const char **argv, const char *prefix)if (build_options) {printf ("sizeof-long: %d\n" , (int )sizeof (long )); +printf ("sizeof-size_t: %d\n" , (int )sizeof (size_t ));/* NEEDSWORK: also save and output GIT-BUILD_OPTIONS? */ }return 0 ;
Thank you! I knew there should have been something.
If nobody objects changing the user-visible behavior, I'll consider using this.
PS: I'll respond to your other reply a bit later.
Re: [PATCH v6 2/2] t5560-http-backend-noserver.sh: add CONTENT_LENGTH cases
Quoted 2 lines · Max Kirillov
If nobody objects changing the user-visible behavior, I'll consider using this.
What user-visible behaviour? A user tries to use a new test helper introduced by the previous round and does not find it? That's OK.
Quoted 1 line
PS: I'll respond to your other reply a bit later.
Thanks.
Re: [PATCH v6 2/2] t5560-http-backend-noserver.sh: add CONTENT_LENGTH cases
In reply to Max KirillovQuoted 7 lines · Max Kirillov
Add tests for cases:
*
CONTENT_LENGTHis set, script's stdin has more data.
(Failure would make it readGIT_HTTP_MAX_REQUEST_BUFFERbytes from/dev/zeroand fail. It does not seem to cause any performance issues with the default value ofGIT_HTTP_MAX_REQUEST_BUFFER.)
*CONTENT_LENGTHis specified to a value which does not fix intossize_t.
s/fix/fit/ you meant?
Quoted 6 lines
t/helper/test-print-values.c new file +0
-0
t/helper/test-print-values.c line 10
Quoted 10 lines
t/helper/test-print-values.c new file +10
-0@@ -0,0 +1,10 @@ +#include <stdio.h> +#include <string.h> + +int cmd_main (int argc,const char **argv) +{ +if (argc ==2 &&strcmp (argv[1 ],"(size_t)(-20)" ) ==0 ) +printf ("%zu" , (ssize_t )(-20 )); + +return 0 ; +}
As far as I know, we avoid %zu (C99), as it may not be safe yet to do so on all platforms.
e.g. c.f. https://public-inbox.org/git/[email protected]/
You may want to double check the 1/2 of this topic, too.
Forcing a test command line to spell out "(size_t)(-20)" feels a bit atrocious, especially given that this program is capable of ever showing that string and nothing else, and it does not even diagnose typos as errors.
I wonder if we would want to have "test-print-larger-than-ssize" and do something like
#include "cache.h"
int cmd_main(int ac, const char **av)
{
uintmax_t large = ((uintmax_t) SSIZE_MAX) + 1;
printf("%" PRIuMAX "\n", large);
return 0;
}perhaps?
Note that wrapper.c seems to assume that not everybody has SSIZE_MAX, so we might have to do something silly like
size_t large = ~0;
large = ~(large & ~(large >> 1)) + 1;
printf("%" PRIuMAX "\n", (uintmax_t) large);just to be careful (even though we now assume 2's complement), though.
Re: [PATCH v6 0/2] http-backend: respect CONTENT_LENGTH as specified by rfc3875
In reply to Max KirillovTo recap (other than the typofix in the proposed log message), here is what I would have as SQUASH??? on top of (or interspersed with) v6.
Thanks.
http-backend.c +3 -4
@@ -324,10 +324,9 @@ static ssize_t read_request_fixed_len(int fd, ssize_t req_len, unsigned char **ossize_t cnt =0 ;if (max_request_buffer < req_len) { -die ("request was larger than our maximum size (%lu): %lu;" -" try setting GIT_HTTP_MAX_REQUEST_BUFFER" , - max_request_buffer, - req_len); +die ("request was larger than our maximum size (%lu): " +"%" PRIuMAX"; try setting GIT_HTTP_MAX_REQUEST_BUFFER" , + max_request_buffer, (uintmax_t )req_len); }if (req_len <=0 ) {
Makefile +1 -1
@@ -661,7 +661,7 @@ TEST_PROGRAMS_NEED_X += test-mktemp TEST_PROGRAMS_NEED_X += test-online-cpus TEST_PROGRAMS_NEED_X += test-parse-options TEST_PROGRAMS_NEED_X += test-path-utils -TEST_PROGRAMS_NEED_X += test-print-values +TEST_PROGRAMS_NEED_X += test-print-larger-than-ssize TEST_PROGRAMS_NEED_X += test-prio-queue TEST_PROGRAMS_NEED_X += test-read-cache TEST_PROGRAMS_NEED_X += test-write-cache
t/helper/test-print-larger-than-ssize.c renamed from t/helper/test-print-values.c +4 -4
@@ -1,10 +1,10 @@ -#include <stdio.h> -#include <string.h> +#include "cache.h" int cmd_main (int argc,const char **argv) { -if (argc ==2 &&strcmp (argv[1 ],"(size_t)(-20)" ) ==0 ) -printf ("%zu" , (ssize_t )(-20 )); +size_t large = ~0 ; + large = ~(large & ~(large >>1 )) +1 ; +printf ("%" PRIuMAX"\n" , (uintmax_t ) large);return 0 ; }
t/t5560-http-backend-noserver.sh +2 -2
@@ -72,7 +72,7 @@ test_expect_success 'http-backend blocks bad PATH_INFO' ' ' # overrides existing definition for further cases -run_backend() { +run_backend () { CONTENT_LENGTH="${#2}" && export CONTENT_LENGTH && ( echo "$2" && cat /dev/zero ) | QUERY_STRING="${1#*[?]}" \
@@ -89,7 +89,7 @@ test_expect_success 'CONTENT_LENGTH set and infinite input' ' ' test_expect_success 'CONTENT_LENGTH overflow ssite_t' ' - NOT_FIT_IN_SSIZE=`"$GIT_BUILD_DIR/t/helper/test-print-values" "(size_t)(-20)"` && + NOT_FIT_IN_SSIZE=$("$GIT_BUILD_DIR/t/helper/test-print-larger-than-ssize") && env \ CONTENT_TYPE=application/x-git-upload-pack-request \ QUERY_STRING=/repo.git/git-upload-pack \
Re: [PATCH v6 0/2] http-backend: respect CONTENT_LENGTH as specified by rfc3875
Quoted 3 lines · Junio C Hamano
To recap (other than the typofix in the proposed log message), here is what I would have as SQUASH??? on top of (or interspersed with) v6.
Thank you. I'll update it a bit later. May/should I add "Signed-off-by:" from you?
Re: [PATCH v6 0/2] http-backend: respect CONTENT_LENGTH as specified by rfc3875
Quoted 7 lines · Max Kirillov
Quoted 3 lines · Junio C Hamano
To recap (other than the typofix in the proposed log message), here is what I would have as SQUASH??? on top of (or interspersed with) v6.
Thank you. I'll update it a bit later. May/should I add "Signed-off-by:" from you?
As you'd be dropping the new helper, I think you will not use a major part of that message. But even if you would, a "Helped-by:" before your sign-off should be enough for a small "help" like the one in the message you are responding.
Thanks.
Need to add test artifacts to .gitignore
FYI, I've noticed when building from "pu" that neither the "t/helper/test-print-values" or "t/helper/test-print-larger-than-ssize" testing artifacts added to Makefile in this patch series are not added to "t/helper/.gitignore" like other helpers, resulting in the testing artifact being recognized as an untracked file.
RFC PATCH 1/1 t/helper: Move sources to t/helper-src; gitignore any files in t/helper
Compiled test helpers in t/helper are out of sync with the .gitignore files quite frequently. This can happen when new test helpers are added, but the explicit .gitignore file is not updated in the same commit, or when you forget to 'make clean' before checking out a different version of git, as the different version may have a different explicit list of test helpers to ignore.
This can be fixed by using overly broad ignore patterns, such as ignoring the whole directory via '//t/helper/*' in .gitignore.
However we do not want to have an overlap of checked source files and ignored files, hence we'll move the the source files currently residing in t/helper to t/helper-src. To accommodate that we'll need to update the Makefile as well to look at a different place for the source files. (This patch takes the hacky approach in symlinking the sources back into the t/helper, which we'd want to avoid long term)
---
Makefile | 4 +++
t/{helper => helper-src}/.gitignore | 0
t/{helper => helper-src}/test-chmtime.c | 0
t/{helper => helper-src}/test-config.c | 0
t/{helper => helper-src}/test-ctype.c | 0
t/{helper => helper-src}/test-date.c | 0
t/{helper => helper-src}/test-delta.c | 0
t/{helper => helper-src}/test-dump-cache-tree.c | 0
t/{helper => helper-src}/test-dump-split-index.c | 0
.../test-dump-untracked-cache.c | 0
t/{helper => helper-src}/test-fake-ssh.c | 0
t/{helper => helper-src}/test-genrandom.c | 0
t/{helper => helper-src}/test-hashmap.c | 0
t/{helper => helper-src}/test-index-version.c | 0
.../test-lazy-init-name-hash.c | 0
t/{helper => helper-src}/test-line-buffer.c | 0
t/{helper => helper-src}/test-match-trees.c | 0
t/{helper => helper-src}/test-mergesort.c | 0
t/{helper => helper-src}/test-mktemp.c | 0
t/{helper => helper-src}/test-online-cpus.c | 0
t/{helper => helper-src}/test-parse-options.c | 0
t/{helper => helper-src}/test-path-utils.c | 0
t/{helper => helper-src}/test-prio-queue.c | 0
t/{helper => helper-src}/test-read-cache.c | 0
t/{helper => helper-src}/test-ref-store.c | 0
t/{helper => helper-src}/test-regex.c | 0
t/{helper => helper-src}/test-revision-walking.c | 0
t/{helper => helper-src}/test-run-command.c | 0
t/{helper => helper-src}/test-scrap-cache-tree.c | 0
t/{helper => helper-src}/test-sha1-array.c | 0
t/{helper => helper-src}/test-sha1.c | 0
t/{helper => helper-src}/test-sha1.sh | 0
t/{helper => helper-src}/test-sigchain.c | 0
t/{helper => helper-src}/test-strcmp-offset.c | 0
t/{helper => helper-src}/test-string-list.c | 0
t/{helper => helper-src}/test-submodule-config.c | 0
t/{helper => helper-src}/test-subprocess.c | 0
t/{helper => helper-src}/test-svn-fe.c | 0
.../test-urlmatch-normalization.c | 0
t/{helper => helper-src}/test-wildmatch.c | 0
t/{helper => helper-src}/test-write-cache.c | 0
t/helper/.gitignore | 39 +---------------------
42 files changed, 5 insertions(+), 38 deletions(-)
copy t/{helper => helper-src}/.gitignore (100%)
rename t/{helper => helper-src}/test-chmtime.c (100%)
rename t/{helper => helper-src}/test-config.c (100%)
rename t/{helper => helper-src}/test-ctype.c (100%)
rename t/{helper => helper-src}/test-date.c (100%)
rename t/{helper => helper-src}/test-delta.c (100%)
rename t/{helper => helper-src}/test-dump-cache-tree.c (100%)
rename t/{helper => helper-src}/test-dump-split-index.c (100%)
rename t/{helper => helper-src}/test-dump-untracked-cache.c (100%)
rename t/{helper => helper-src}/test-fake-ssh.c (100%)
rename t/{helper => helper-src}/test-genrandom.c (100%)
rename t/{helper => helper-src}/test-hashmap.c (100%)
rename t/{helper => helper-src}/test-index-version.c (100%)
rename t/{helper => helper-src}/test-lazy-init-name-hash.c (100%)
rename t/{helper => helper-src}/test-line-buffer.c (100%)
rename t/{helper => helper-src}/test-match-trees.c (100%)
rename t/{helper => helper-src}/test-mergesort.c (100%)
rename t/{helper => helper-src}/test-mktemp.c (100%)
rename t/{helper => helper-src}/test-online-cpus.c (100%)
rename t/{helper => helper-src}/test-parse-options.c (100%)
rename t/{helper => helper-src}/test-path-utils.c (100%)
rename t/{helper => helper-src}/test-prio-queue.c (100%)
rename t/{helper => helper-src}/test-read-cache.c (100%)
rename t/{helper => helper-src}/test-ref-store.c (100%)
rename t/{helper => helper-src}/test-regex.c (100%)
rename t/{helper => helper-src}/test-revision-walking.c (100%)
rename t/{helper => helper-src}/test-run-command.c (100%)
rename t/{helper => helper-src}/test-scrap-cache-tree.c (100%)
rename t/{helper => helper-src}/test-sha1-array.c (100%)
rename t/{helper => helper-src}/test-sha1.c (100%)
rename t/{helper => helper-src}/test-sha1.sh (100%)
rename t/{helper => helper-src}/test-sigchain.c (100%)
rename t/{helper => helper-src}/test-strcmp-offset.c (100%)
rename t/{helper => helper-src}/test-string-list.c (100%)
rename t/{helper => helper-src}/test-submodule-config.c (100%)
rename t/{helper => helper-src}/test-subprocess.c (100%)
rename t/{helper => helper-src}/test-svn-fe.c (100%)
rename t/{helper => helper-src}/test-urlmatch-normalization.c (100%)
rename t/{helper => helper-src}/test-wildmatch.c (100%)
rename t/{helper => helper-src}/test-write-cache.c (100%)rewrite t/helper/.gitignore (100%)
Makefile +4 -0
@@ -2454,6 +2454,10 @@ t/helper/test-svn-fe$X: $(VCSSVN_LIB) t/helper/test-%$X: t/helper/test-%.o GIT-LDFLAGS $(GITLIBS) $(QUIET_LINK)$(CC) $(ALL_CFLAGS) -o $@ $(ALL_LDFLAGS) $(filter %.o,$^) $(filter %.a,$^) $(LIBS) +t/helper/test-%.c: t/helper-src/test-%.c + @echo $@ $< + ln -s ../../$< $@ + check-sha1:: t/helper/test-sha1$X t/helper/test-sha1.sh
t/helper-src/.gitignore renamed from t/helper/.gitignore +0 -0
t/helper-src/test-chmtime.c renamed from t/helper/test-chmtime.c +0 -0
t/helper-src/test-config.c renamed from t/helper/test-config.c +0 -0
t/helper-src/test-ctype.c renamed from t/helper/test-ctype.c +0 -0
t/helper-src/test-date.c renamed from t/helper/test-date.c +0 -0
t/helper-src/test-delta.c renamed from t/helper/test-delta.c +0 -0
t/helper-src/test-dump-cache-tree.c renamed from t/helper/test-dump-cache-tree.c +0 -0
t/helper-src/test-dump-split-index.c renamed from t/helper/test-dump-split-index.c +0 -0
t/helper-src/test-dump-untracked-cache.c renamed from t/helper/test-dump-untracked-cache.c +0 -0
t/helper-src/test-fake-ssh.c renamed from t/helper/test-fake-ssh.c +0 -0
t/helper-src/test-genrandom.c renamed from t/helper/test-genrandom.c +0 -0
t/helper-src/test-hashmap.c renamed from t/helper/test-hashmap.c +0 -0
t/helper-src/test-index-version.c renamed from t/helper/test-index-version.c +0 -0
t/helper-src/test-lazy-init-name-hash.c renamed from t/helper/test-lazy-init-name-hash.c +0 -0
t/helper-src/test-line-buffer.c renamed from t/helper/test-line-buffer.c +0 -0
t/helper-src/test-match-trees.c renamed from t/helper/test-match-trees.c +0 -0
t/helper-src/test-mergesort.c renamed from t/helper/test-mergesort.c +0 -0
t/helper-src/test-mktemp.c renamed from t/helper/test-mktemp.c +0 -0
t/helper-src/test-online-cpus.c renamed from t/helper/test-online-cpus.c +0 -0
t/helper-src/test-parse-options.c renamed from t/helper/test-parse-options.c +0 -0
t/helper-src/test-path-utils.c renamed from t/helper/test-path-utils.c +0 -0
t/helper-src/test-prio-queue.c renamed from t/helper/test-prio-queue.c +0 -0
t/helper-src/test-read-cache.c renamed from t/helper/test-read-cache.c +0 -0
t/helper-src/test-ref-store.c renamed from t/helper/test-ref-store.c +0 -0
t/helper-src/test-regex.c renamed from t/helper/test-regex.c +0 -0
t/helper-src/test-revision-walking.c renamed from t/helper/test-revision-walking.c +0 -0
t/helper-src/test-run-command.c renamed from t/helper/test-run-command.c +0 -0
t/helper-src/test-scrap-cache-tree.c renamed from t/helper/test-scrap-cache-tree.c +0 -0
t/helper-src/test-sha1-array.c renamed from t/helper/test-sha1-array.c +0 -0
t/helper-src/test-sha1.c renamed from t/helper/test-sha1.c +0 -0
t/helper-src/test-sha1.sh renamed from t/helper/test-sha1.sh +0 -0
t/helper-src/test-sigchain.c renamed from t/helper/test-sigchain.c +0 -0
t/helper-src/test-strcmp-offset.c renamed from t/helper/test-strcmp-offset.c +0 -0
t/helper-src/test-string-list.c renamed from t/helper/test-string-list.c +0 -0
t/helper-src/test-submodule-config.c renamed from t/helper/test-submodule-config.c +0 -0
t/helper-src/test-subprocess.c renamed from t/helper/test-subprocess.c +0 -0
t/helper-src/test-svn-fe.c renamed from t/helper/test-svn-fe.c +0 -0
t/helper-src/test-urlmatch-normalization.c renamed from t/helper/test-urlmatch-normalization.c +0 -0
t/helper-src/test-wildmatch.c renamed from t/helper/test-wildmatch.c +0 -0
t/helper-src/test-write-cache.c renamed from t/helper/test-write-cache.c +0 -0
t/helper/.gitignore +1 -38
@@ -1,38 +1 @@ -/test-chmtime -/test-ctype -/test-config -/test-date -/test-delta -/test-dump-cache-tree -/test-dump-split-index -/test-dump-untracked-cache -/test-fake-ssh -/test-scrap-cache-tree -/test-genrandom -/test-hashmap -/test-index-version -/test-lazy-init-name-hash -/test-line-buffer -/test-match-trees -/test-mergesort -/test-mktemp -/test-online-cpus -/test-parse-options -/test-path-utils -/test-prio-queue -/test-read-cache -/test-ref-store -/test-regex -/test-revision-walking -/test-run-command -/test-sha1 -/test-sha1-array -/test-sigchain -/test-strcmp-offset -/test-string-list -/test-submodule-config -/test-subprocess -/test-svn-fe -/test-urlmatch-normalization -/test-wildmatch -/test-write-cache +*
Signature · 1 line
2.15.1.504.g5279b80103-goog
Re: [RFC PATCH] t/helper: Move sources to t/helper-src; gitignore any files in t/helper
Quoted 9 lines · Stefan Beller
Compiled test helpers in t/helper are out of sync with the .gitignore files quite frequently. This can happen when new test helpers are added, but the explicit .gitignore file is not updated in the same commit, or when you forget to 'make clean' before checking out a different version of git, as the different version may have a different explicit list of test helpers to ignore.
This can be fixed by using overly broad ignore patterns, such as ignoring the whole directory via '//t/helper/*' in .gitignore.
If we ignore everything but resurrect *.[ch] with negative exclude rules, can we do the same without moving things around?
PATCH 1/1 t/helper: ignore everything but sources
Compiled test helpers in t/helper are out of sync with the .gitignore files quite frequently. This can happen when new test helpers are added, but the explicit .gitignore file is not updated in the same commit, or when you forget to 'make clean' before checking out a different version of git, as the different version may have a different explicit list of test helpers to ignore.
Fix this by having an overly broad ignore pattern in that directory:
Anything, except C and shell source, will be ignored.
---
Quoted 2 lines
If we ignore everything but resurrect *.[ch] with negative exclude rules, can we do the same without moving things around?
Yes, there is also one lonely shell script in there, which also needs exclusion.
I guess we want to test this overly broad pattern in a sub directory, as I could imagine that at the top level directory we'd have more cases to think through (I used to put untracked files into the top level dir, but I do not do it anymore).
Thanks,
Stefan
t/helper/.gitignore | 43 +++---------------------------------------- 1 file changed, 3 insertions(+), 40 deletions(-)
t/helper/.gitignore +3 -40
@@ -1,40 +1,3 @@ -/test-chmtime -/test-ctype -/test-config -/test-date -/test-delta -/test-drop-caches -/test-dump-cache-tree -/test-dump-fsmonitor -/test-dump-split-index -/test-dump-untracked-cache -/test-fake-ssh -/test-scrap-cache-tree -/test-genrandom -/test-hashmap -/test-index-version -/test-lazy-init-name-hash -/test-line-buffer -/test-match-trees -/test-mergesort -/test-mktemp -/test-online-cpus -/test-parse-options -/test-path-utils -/test-prio-queue -/test-read-cache -/test-ref-store -/test-regex -/test-revision-walking -/test-run-command -/test-sha1 -/test-sha1-array -/test-sigchain -/test-strcmp-offset -/test-string-list -/test-submodule-config -/test-subprocess -/test-svn-fe -/test-urlmatch-normalization -/test-wildmatch -/test-write-cache +* +!.sh +!.[ch]
Signature · 1 line
2.15.1.504.g5279b80103-goog
Re: [PATCH] t/helper: ignore everything but sources
Quoted 2 lines · Stefan Beller
Yes, there is also one lonely shell script in there, which also needs exclusion.
Thanks for catching them.
Quoted 3 lines
+*
+!.sh
+!.[ch]
I'd use this instead, though.
-- >8 --
*
!*.sh
!*.[ch]
!*.gitignore
-- 8< --
In a dirty repository full of crufts but without any local modifications, if you do
$ git rm --cached -r t/helper
$ git add t/helperyou should be able to make your index identical to HEAD. The version that was posted did not resurrect .gitignore and none of the source files, but the replaced one should.
PATCH 1/1 t/helper: ignore everything but sources
Compiled test helpers in t/helper are out of sync with the .gitignore files quite frequently. This can happen when new test helpers are added, but the explicit .gitignore file is not updated in the same commit, or when you forget to 'make clean' before checking out a different version of git, as the different version may have a different explicit list of test helpers to ignore.
Fix this by having an overly broad ignore pattern in that directory:
Anything, except C and shell source, will be ignored.
---
Thanks Todd and Junio for mentioning the .gitignore file.
t/helper/.gitignore | 44 ++++---------------------------------------- 1 file changed, 4 insertions(+), 40 deletions(-)
t/helper/.gitignore +4 -40
@@ -1,40 +1,4 @@ -/test-chmtime -/test-ctype -/test-config -/test-date -/test-delta -/test-drop-caches -/test-dump-cache-tree -/test-dump-fsmonitor -/test-dump-split-index -/test-dump-untracked-cache -/test-fake-ssh -/test-scrap-cache-tree -/test-genrandom -/test-hashmap -/test-index-version -/test-lazy-init-name-hash -/test-line-buffer -/test-match-trees -/test-mergesort -/test-mktemp -/test-online-cpus -/test-parse-options -/test-path-utils -/test-prio-queue -/test-read-cache -/test-ref-store -/test-regex -/test-revision-walking -/test-run-command -/test-sha1 -/test-sha1-array -/test-sigchain -/test-strcmp-offset -/test-string-list -/test-submodule-config -/test-subprocess -/test-svn-fe -/test-urlmatch-normalization -/test-wildmatch -/test-write-cache +* +!*.[ch] +!*.sh +!.gitignore
Signature · 1 line
2.15.1.504.g5279b80103-goog
Re: [PATCH] t/helper: ignore everything but sources
In reply to Stefan BellerHi Stefan,
Quoted 5 lines · Stefan Beller
Quoted 2 lines
If we ignore everything but resurrect *.[ch] with negative exclude rules, can we do the same without moving things around?
Yes, there is also one lonely shell script in there, which also needs exclusion.
There aren't currently any .h files, but I suppose it doesn't hurt to include that pattern to be safer for the future.
Quoted 3 lines
+*
+!.sh
+!.[ch]
The ! patterns are missing a '*'. I think it should be:
*
!*.[ch]
!*.sh
Does it make sense to also include !.gitignore as well? It's already committed, so it's not ignored. But perhaps having it listed will save someone from getting their repo into a state where local changes to .gitignore aren't picked up (I know that's a bit of a stretch).
Signature · 5 lines
Todd
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
How much does it cost to entice a dope-smoking UNIX system guru to
Dayton?
-- Brian Boyle, UNIX/WORLD's First Annual Salary SurveyRe: [PATCH v6 0/2] http-backend: respect CONTENT_LENGTH as specified by rfc3875
In reply to Max KirillovQuoted 11 lines · Max Kirillov
v6:
Do not implement generic
git_env_ssize_t(), instead exportgit_parse_ssize_t()fromconfig.cand hardcode the rest.Florian Manschwetus (1):
http-backend: respectCONTENT_LENGTHas specified by rfc3875Max Kirillov (1):
t5560-http-backend-noserver.sh: addCONTENT_LENGTHcases
Quoted 8 lines
Makefile | 1 + config.c | 2 +- config.h | 1 + http-backend.c | 50 +++++++++++++++++++++++++++++++++++++++- t/helper/test-print-values.c | 10 ++++++++ t/t5560-http-backend-noserver.sh | 30 ++++++++++++++++++++++++ 6 files changed, 92 insertions(+), 2 deletions(-) create mode 100644 t/helper/test-print-values.c
So... is there going to be an update (or has there been one and I missed it)?
Thanks.
Re: [PATCH v6 0/2] http-backend: respect CONTENT_LENGTH as specified by rfc3875
Quoted 2 lines · Junio C Hamano
So... is there going to be an update (or has there been one and I missed it)?
Yes there it! I wanted to add tests for the cases Jeff mentioned. It is almost done, I just need to check I did not miss some note.
v7 cover http-backend: respect CONTENT_LENGTH as specified by rfc3875
In reply to Max KirillovIt's been time. Thank you for parience.
Changes:
* did most of the changes proposed
* rebase to newer master (latest conflicting change is addition of combined test helper)
* make tests which cover, hopefully, all cases.
* handle incorectly truncated input also in receive-pack. Considering the complications pointed out by Jeff, it just filters the input in the frontend process. I hope it is acceptable thing to do.
Max Kirillov (2):
http-backend: respect CONTENT_LENGTH as specified by rfc3875
http-backend: respect CONTENT_LENGTH for receive-pack
Makefile | 1 + config.c | 2 +- config.h | 1 + http-backend.c | 86 +++++++++++-- t/helper/test-print-larger-than-ssize.c | 11 ++ t/helper/test-tool.c | 1 + t/helper/test-tool.h | 1 + t/t5560-http-backend-noserver.sh | 13 ++ t/t5562-http-backend-content-length.sh | 155 ++++++++++++++++++++++++ t/t5562/invoke-with-content-length.pl | 30 +++++ 10 files changed, 291 insertions(+), 10 deletions(-) create mode 100644 t/helper/test-print-larger-than-ssize.c create mode 100755 t/t5562-http-backend-content-length.sh create mode 100755 t/t5562/invoke-with-content-length.pl
Signature · 1 line
2.17.0.1185.g782057d875
PATCH v7 1/2 http-backend: respect CONTENT_LENGTH as specified by rfc3875
http-backend reads whole input until EOF. However, the RFC 3875 specifies that a script must read only as many bytes as specified by CONTENT_LENGTH environment variable. Web server may exercise the specification by not closing the script's standard input after writing content. In that case http-backend would hang waiting for the input. The issue is known to happen with IIS/Windows, for example.
Make http-backend read only CONTENT_LENGTH bytes, if it's defined, rather than the whole input until EOF. If the variable is not defined, keep older behavior of reading until EOF because it is used to support chunked transfer-encoding.
--- config.c | 2 +- config.h | 1 + http-backend.c | 43 ++++++++++++++++++++++++++++++++++++++++++- 3 files changed, 44 insertions(+), 2 deletions(-)
config.c +1 -1
@@ -853,7 +853,7 @@ int git_parse_ulong(const char *value, unsigned long *ret)return 1 ; } -static int git_parse_ssize_t (const char *value,ssize_t *ret) +int git_parse_ssize_t (const char *value,ssize_t *ret) {intmax_t tmp;if (!git_parse_signed (value, &tmp,maximum_signed_value_of_type (ssize_t)))
config.h +1 -0
@@ -48,6 +48,7 @@ extern void git_config(config_fn_t fn, void *);extern int config_with_options (config_fn_t fn,void *,struct git_config_source *config_source,const struct config_options *opts); +extern int git_parse_ssize_t (const char *,ssize_t *);extern int git_parse_ulong (const char *,unsigned long *);extern int git_parse_maybe_bool (const char *);extern int git_config_int (const char *,const char *);
http-backend.c +42 -1
55 lines not on this page · raw message
Signature · 1 line
2.17.0.1185.g782057d875
Re: [PATCH v7 1/2] http-backend: respect CONTENT_LENGTH as specified by rfc3875
Quoted 15 lines · Max Kirillov
http-backend reads whole input until EOF. However, the RFC 3875 specifies that a script must read only as many bytes as specified by
CONTENT_LENGTHenvironment variable. Web server may exercise the specification by not closing the script's standard input after writing content. In that case http-backend would hang waiting for the input. The issue is known to happen with IIS/Windows, for example.Make http-backend read only
CONTENT_LENGTHbytes, if it's defined, rather than the whole input until EOF. If the variable is not defined, keep older behavior of reading until EOF because it is used to support chunked transfer-encoding.Signed-off-by Florian Manschwetus <[email protected]>[mk: fixed trivial build failures and polished style issues]Helped-by Junio C Hamano <[email protected]>Signed-off-by Max Kirillov <[email protected]>
Quoted 5 lines
--- config.c | 2 +- config.h | 1 + http-backend.c | 43 ++++++++++++++++++++++++++++++++++++++++++- 3 files changed, 44 insertions(+), 2 deletions(-)
This first patch looks good to me, though it may be worth mentioning in the commit message that we're only handling the buffered-input side here (that is obvious to anybody reading this whole series now, but it may help out people digging in the history later).
-Peff
PATCH v7 2/2 http-backend: respect CONTENT_LENGTH for receive-pack
In reply to Max KirillovPush passes to another commands, as described in
https://public-inbox.org/git/[email protected]/
As it gets complicated to correctly track the data length, instead transfer the data through parent process and cut the pipe as the specified length is reached. Do it only when CONTENT_LENGTH is set, otherwise pass the input directly to the forked commands.
Add tests for cases:
* CONTENT_LENGTH is set, script's stdin has more data, with all combinations of variations: fetch or push, plain or compressed body, correct or truncated input.
* CONTENT_LENGTH is specified to a value which does not fit into ssize_t.
--- Makefile | 1 + http-backend.c | 49 ++++++-- t/helper/test-print-larger-than-ssize.c | 11 ++ t/helper/test-tool.c | 1 + t/helper/test-tool.h | 1 + t/t5560-http-backend-noserver.sh | 13 ++ t/t5562-http-backend-content-length.sh | 155 ++++++++++++++++++++++++ t/t5562/invoke-with-content-length.pl | 30 +++++ 8 files changed, 250 insertions(+), 11 deletions(-) create mode 100644 t/helper/test-print-larger-than-ssize.c create mode 100755 t/t5562-http-backend-content-length.sh create mode 100755 t/t5562/invoke-with-content-length.pl
Makefile +1 -0
@@ -678,6 +678,7 @@ TEST_BUILTINS_OBJS += test-mergesort.o TEST_BUILTINS_OBJS += test-mktemp.o TEST_BUILTINS_OBJS += test-online-cpus.o TEST_BUILTINS_OBJS += test-path-utils.o +TEST_BUILTINS_OBJS += test-print-larger-than-ssize.o TEST_BUILTINS_OBJS += test-prio-queue.o TEST_BUILTINS_OBJS += test-read-cache.o TEST_BUILTINS_OBJS += test-ref-store.o
http-backend.c +38 -11
110 lines not on this page · raw message
t/helper/test-print-larger-than-ssize.c new file +11 -0
@@ -0,0 +1,11 @@ +#include "test-tool.h" +#include "cache.h" + +int cmd__print_larger_than_ssize (int argc,const char **argv) +{ +size_t large = ~0 ; + + large = ~(large & ~(large >>1 )) +1 ; +printf ("%" PRIuMAX"\n" , (uintmax_t ) large); +return 0 ; +}
t/helper/test-tool.c +1 -0
@@ -25,6 +25,7 @@ static struct test_cmd cmds[] = { { "mktemp", cmd__mktemp }, { "online-cpus", cmd__online_cpus }, { "path-utils", cmd__path_utils }, + { "print-larger-than-ssize", cmd__print_larger_than_ssize }, { "prio-queue", cmd__prio_queue }, { "read-cache", cmd__read_cache }, { "ref-store", cmd__ref_store },
t/helper/test-tool.h +1 -0
@@ -19,6 +19,7 @@ int cmd__mergesort(int argc, const char **argv);int cmd__mktemp (int argc,const char **argv);int cmd__online_cpus (int argc,const char **argv);int cmd__path_utils (int argc,const char **argv); +int cmd__print_larger_than_ssize (int argc,const char **argv);int cmd__prio_queue (int argc,const char **argv);int cmd__read_cache (int argc,const char **argv);int cmd__ref_store (int argc,const char **argv);
t/t5560-http-backend-noserver.sh +13 -0
@@ -71,4 +71,17 @@ test_expect_success 'http-backend blocks bad PATH_INFO' ' expect_aliased 1 //domain/data.txt ' +test_expect_success 'CONTENT_LENGTH overflow ssite_t' ' + NOT_FIT_IN_SSIZE=$("$GIT_BUILD_DIR/t/helper/test-tool" print-larger-than-ssize) && + env \ + CONTENT_TYPE=application/x-git-upload-pack-request \ + QUERY_STRING=/repo.git/git-upload-pack \ + PATH_TRANSLATED="$PWD"/.git/git-upload-pack \ + GIT_HTTP_EXPORT_ALL=TRUE \ + REQUEST_METHOD=POST \ + CONTENT_LENGTH="$NOT_FIT_IN_SSIZE" \ + git http-backend </dev/zero >/dev/null 2>err && + grep -q "fatal:.*CONTENT_LENGTH" err +' + test_done
t/t5562-http-backend-content-length.sh new file +155 -0
155 lines not on this page · raw message
t/t5562/invoke-with-content-length.pl new file +30 -0
@@ -0,0 +1,30 @@ +#!/usr/bin/perl +use 5.008; +use strict; +use warnings; + +my $body_filename = $ARGV[0]; +my @command = @ARGV[1 .. $#ARGV]; + +# read data +my $body_size = -s $body_filename; +$ENV{"CONTENT_LENGTH"} = $body_size; +open(my $body_fh, "<", $body_filename) or die "Cannot open $body_filename: $!"; +my $body_data; +defined read($body_fh, $body_data, $body_size) or die "Cannot read $body_filename: $!"; +close($body_fh); + +my $exited = 0; +$SIG{"CHLD"} = sub { + $exited = 1; +}; + +# write data +my $pid = open(my $out, "|-", @command); +defined syswrite($out, $body_data) or die "Cannot write data: $!"; + +sleep 1; # is interrupted by SIGCHLD +if (!$exited) { + close($out); + die "Command did not exit after reading whole body"; +}
Signature · 1 line
2.17.0.1185.g782057d875
Re: [PATCH v7 2/2] http-backend: respect CONTENT_LENGTH for receive-pack
http-backend.c static void copy_request(const char *prog_name, int out) · line 446
Quoted 10 lines · Max Kirillov
http-backend.c +10
-0+static void pipe_fixed_length (const char *prog_name,int out,size_t req_len) +{ +unsigned char buf[8192 ]; +size_t remaining_len = req_len; + +while (remaining_len >0 ) { +size_t chunk_length = remaining_len >sizeof (buf) ?sizeof (buf) : remaining_len; +size_t n =xread (0 , buf, chunk_length); +if (n <0 ) +die_errno ("Reading request failed" );
n that is of type size_t is unsigned and cannot be negative here.
Re: [PATCH v7 2/2] http-backend: respect CONTENT_LENGTH for receive-pack
Quoted 6 lines · Junio C Hamano
http-backend.c static void copy_request(const char *prog_name, int out) · line 446
Quoted 3 lines · Max Kirillov
http-backend.c +3
-0+size_t n =xread (0 , buf, chunk_length); +if (n <0 ) +die_errno ("Reading request failed" );n that is of type
size_tis unsigned and cannot be negative here.
Thanks, fixing it
Do you think sanity check for n <= chunk_length (the code will go mad in this case) is needed? As far as I can see n returns straight from system's read()
Re: [PATCH v7 2/2] http-backend: respect CONTENT_LENGTH for receive-pack
Quoted 8 lines · Max Kirillov
Quoted 6 lines · Junio C Hamano
http-backend.c static void copy_request(const char *prog_name, int out) · line 446
Quoted 3 lines · Max Kirillov
http-backend.c +3
-0+size_t n =xread (0 , buf, chunk_length); +if (n <0 ) +die_errno ("Reading request failed" );n that is of type
size_tis unsigned and cannot be negative here.
Hmm, xread() returns an ssize_t, which is a signed type ...
Quoted 4 lines
Thanks, fixing it
Do you think sanity check for n <=chunk_length(the code will go mad in this case) is needed? As far as I can see n returns straight from system'sread()
ATB,
Ramsay Jones
Re: [PATCH v7 2/2] http-backend: respect CONTENT_LENGTH for receive-pack
In reply to Max KirillovQuoted 7 lines · Max Kirillov
Push passes to another commands, as described in
https://public-inbox.org/git/[email protected]/As it gets complicated to correctly track the data length, instead transfer the data through parent process and cut the pipe as the specified length is reached. Do it only when
CONTENT_LENGTHis set, otherwise pass the input directly to the forked commands.
I think this approach is reasonable. It's basically converting the known-length case to a read-to-eof case for the sub-program, which should paper over any problems of this type. And it's what we really _want_ the web server to be doing in the first place.
Since this is slightly less efficient, and because it only matters if the web server does not already close the pipe, should this have a run-time configuration knob, even if it defaults to safe-but-slightly-slower?
I admit I don't overly care that much myself (the only large-scale Git server deployment I am personally familiar with does not use git-http-backend at all), but it might be nice to leave an escape hatch.
There are a few things in the patch worth fixing, but overall I think it looks like a pretty good direction. Comments inline.
Quoted 8 lines
http-backend.c +0
-0@@ -351,23 +351,22 @@ static ssize_t get_content_length(void)return val; }
http-backend.c static ssize_t get_content_length(void) · line 360
Quoted 10 lines
http-backend.c +1
-3-static ssize_t read_request (int fd,unsigned char **out) +static ssize_t read_request (int fd,unsigned char **out,ssize_t req_len) { -ssize_t req_len =get_content_length (); -if (req_len <0 )return read_request_eof (fd, out);else return read_request_fixed_len (fd, req_len, out); }
Minor nit, but it might have been nice to build in this infrastructure in the first patch, rather than refactoring it here. It would also make it much more obvious that the first one is not handling some cases, since we'd have "req_len" but not pass it to all of the code paths. ;)
Quoted 9 lines
http-backend.c +1
-2@@ -379,11 +378,18 @@ static void inflate_request(const char *prog_name, int out, int buffer_input)if (full_request) n =0 ;/* nothing left to read */ else - n =read_request (0 , &full_request); + n =read_request (0 , &full_request, req_len); stream.next_in = full_request; }else { - n =xread (0 , in_buf,sizeof (in_buf));
http-backend.c static void inflate_request(const char *prog_name, int out, int buffer_input) · line 393
Quoted 10 lines
http-backend.c +8
-0+ssize_t buffer_len; +if (req_remaining_len <0 || req_remaining_len >sizeof (in_buf)) + buffer_len =sizeof (in_buf); +else + buffer_len = req_remaining_len; + n =xread (0 , in_buf, buffer_len); stream.next_in = in_buf; +if (req_remaining_len >=0 ) + req_remaining_len -= n; }
What happens here if xread() returns an error? We probably don't want to modify req_remaining_len (it probably doesn't matter since we'd report the errot after this, but it feels funny not to check here).
http-backend.c static void copy_request(const char *prog_name, int out) · line 446
Quoted 10 lines
http-backend.c +10
-0+static void pipe_fixed_length (const char *prog_name,int out,size_t req_len) +{ +unsigned char buf[8192 ]; +size_t remaining_len = req_len; + +while (remaining_len >0 ) { +size_t chunk_length = remaining_len >sizeof (buf) ?sizeof (buf) : remaining_len; +size_t n =xread (0 , buf, chunk_length); +if (n <0 ) +die_errno ("Reading request failed" );
I was going to complain that we usually start our error messages with a lowercase, but this program seems to be an exception. So here you've followed the local custom, which is OK.
http-backend.c static void copy_request(const char *prog_name, int out) · line 448
Quoted 2 lines
http-backend.c +2
-0+if (write_in_full (out, buf, n) <0 ) +die_errno ("%s aborted reading request" , prog_name);
We don't necessarily know why the write failed. If it's EPIPE, then yes, the program probably did abort. But all we know is that write() failed. We should probably say something more generic like:
die_errno("unable to write to '%s'");or similar.
Quoted 7 lines
t/helper/test-print-larger-than-ssize.c new file +1
-0@@ -0,0 +1,11 @@ +#include "test-tool.h"
t/helper/test-print-larger-than-ssize.c line 11
Quoted 10 lines
t/helper/test-print-larger-than-ssize.c new file +10
-0+#include "cache.h" + +int cmd__print_larger_than_ssize (int argc,const char **argv) +{ +size_t large = ~0 ; + + large = ~(large & ~(large >>1 )) +1 ; +printf ("%" PRIuMAX"\n" , (uintmax_t ) large); +return 0 ; +}
I think this might be nicer as part of "git version --build-options". Either as a byte-size as I showed in [1], or directly showing this value.
t/helper/test-tool.c static struct test_cmd cmds[] = { · line 28
Quoted 9 lines
t/helper/test-tool.c +1
-0@@ -25,6 +25,7 @@ static struct test_cmd cmds[] = { { "mktemp", cmd__mktemp }, { "online-cpus", cmd__online_cpus }, { "path-utils", cmd__path_utils }, + { "print-larger-than-ssize", cmd__print_larger_than_ssize },
Indent with spaces?
t/t5560-http-backend-noserver.sh test_expect_success 'http-backend blocks bad PATH_INFO' ' · line 75
Quoted 10 lines
t/t5560-http-backend-noserver.sh +2
-0@@ -71,4 +71,17 @@ test_expect_success 'http-backend blocks bad PATH_INFO' ' expect_aliased 1 //domain/data.txt ' +test_expect_success 'CONTENT_LENGTH overflow ssite_t' ' + NOT_FIT_IN_SSIZE=$("$GIT_BUILD_DIR/t/helper/test-tool" print-larger-than-ssize) &&
We put helpers in the PATH, so this could just be "test-tool print-larger-than-ssize" (though I still prefer the --build-options variant).
t/t5560-http-backend-noserver.sh test_expect_success 'http-backend blocks bad PATH_INFO' ' · line 84
Quoted 9 lines
t/t5560-http-backend-noserver.sh +9
-0+ env \ + CONTENT_TYPE=application/x-git-upload-pack-request \ + QUERY_STRING=/repo.git/git-upload-pack \ + PATH_TRANSLATED="$PWD"/.git/git-upload-pack \ + GIT_HTTP_EXPORT_ALL=TRUE \ + REQUEST_METHOD=POST \ + CONTENT_LENGTH="$NOT_FIT_IN_SSIZE" \ + git http-backend </dev/zero >/dev/null 2>err && + grep -q "fatal:.*CONTENT_LENGTH" err
I'm not sure if these messages should be marked for translation. If so, you'd want test_i18ngrep here.
We also generally avoid "-q" to grep. If the script is in non-verbose mode it will go to /dev/null anyway, and in verbose mode it's useful to see (possibly ditto for the /dev/null redirection of stdout above, but I think that might actually spew a binary packfile if the test fails, which we'd rather avoid).
t/t5562-http-backend-content-length.sh line 4
Quoted 10 lines
t/t5562-http-backend-content-length.sh new file +4
-0@@ -0,0 +1,155 @@ +#!/bin/sh + +test_description='test git-http-backend respects CONTENT_LENGTH' +. ./test-lib.sh
Why is the too-large CONTENT_LENGTH test in another file? I'd have thought it would go well here, based on the description.
Quoted 4 lines
t/t5562-http-backend-content-length.sh new file +4
-0+verify_http_result() { + # sometimes there is fatal error buit the result is still 200 + if grep 'fatal:' act.err + then
t/t5562-http-backend-content-length.sh line 19
Quoted 10 lines
t/t5562-http-backend-content-length.sh new file +10
-0+ return 1 + fi + + if ! grep "Status" act.out >act + then + printf "Status: 200 OK\r\n" >act + fi + printf "Status: $1\r\n" >exp && + test_cmp exp act +}
200 with a fatal error sounds non-ideal. But I think it's unavoidable in some cases where we see write failures, etc.
t/t5562-http-backend-content-length.sh line 31
Quoted 11 lines
t/t5562-http-backend-content-length.sh new file +11
-0+test_http_env() { + handler_type="$1" + shift + env \ + CONTENT_TYPE="application/x-git-$handler_type-pack-request" \ + QUERY_STRING="/repo.git/git-$handler_type-pack" \ + PATH_TRANSLATED="$PWD/.git/git-$handler_type-pack" \ + GIT_HTTP_EXPORT_ALL=TRUE \ + REQUEST_METHOD=POST \ + "$@" +}
I think this env (and the earlier one) are not strictly necessary, as you could just use shell one-shot variables. But I'm OK with them as an abundance of caution, since in theory a caller could use a shell function rather than a real command here (in which case one-shot variables do the wrong thing).
t/t5562-http-backend-content-length.sh line 39
Quoted 7 lines
t/t5562-http-backend-content-length.sh new file +7
-0+test_expect_success 'setup repository' ' + test_commit c0 && + test_commit c1 +' + +hash_head=$(git rev-parse HEAD) +hash_prev=$(git rev-parse HEAD~1)
We generally prefer to have all commands, even ones we don't expect to fail, inside test_expect blocks (e.g., with a "setup" description).
t/t5562-http-backend-content-length.sh line 45
Quoted 5 lines
t/t5562-http-backend-content-length.sh new file +5
-0+cat >fetch_body <<EOF +0032want $hash_head +00000032have $hash_prev +0009done +EOF
This depends on the size of the hash. That's always 40 for now, but is something that may change soon.
We already have a packetize() helper; could we use it here?
(Looking at the definition of that helper, it's actually kind of expensive in terms of number of processes. We could perhaps convert it to perl and do it all in a single process, but that's orthogonal to your series).
t/t5562-http-backend-content-length.sh line 47
Quoted 1 line
t/t5562-http-backend-content-length.sh new file +1
-0+gzip -k fetch_body
We don't unconditionally rely on gzip elsewhere. The test blocks using it (and the ones that depend on them) should be marked with the GZIP prerequisite.
t/t5562-http-backend-content-length.sh line 51
Quoted 3 lines
t/t5562-http-backend-content-length.sh new file +3
-0+head -c -10 <fetch_body.gz >fetch_body.gz.trunc + +head -c -10 <fetch_body >fetch_body.trunc
We can into portability problems with "head -c", but I think they were mostly with different buffering behavior (i.e., reading more than 10 bytes). And that would be OK in this setting, since nobody is going to read the rest of the input after us.
So it's probably OK, but we could use "test_copy_bytes 10" here if it isn't.
t/t5562-http-backend-content-length.sh line 63
Quoted 1 line
t/t5562-http-backend-content-length.sh new file +1
-0+touch empty_body
We usually prefer ">empty_body" to using "touch".
t/t5562-http-backend-content-length.sh line 75
Quoted 5 lines
t/t5562-http-backend-content-length.sh new file +5
-0+test_expect_success 'fetch plain truncated' ' + test_http_env upload \ + "$TEST_DIRECTORY"/t5562/invoke-with-content-length.pl fetch_body.trunc git http-backend >act.out 2>act.err && + test_must_fail verify_http_result "200 OK" +'
Usually test_must_fail on a checking function like this is a sign that the check is not as robust as we'd like. If the function checks two things "A && B", then checking test_must_fail will only let us know "!A || !B", but you probably want to check both.
The usual solution is for verify_http_result to take an optional "!" in the first parameter and invert its sense. Or to just split it into two separate functions.
(We'd also generally not use test_must_fail with a non-git command, and just use a simple "! verify_http_result"; that would apply equally if gets split into two commands).
t/t5562-http-backend-content-length.sh line 53
Quoted 2 lines
t/t5562-http-backend-content-length.sh new file +2
-0+test_expect_success 'push plain' ' + git config http.receivepack true &&
This will persist after the test finishes. Try:
test_config http.receivepack true
which will clean up after the test finishes. Alternatively, since I think you'd want this whole script to run with http.receivepack set, this could be part of the repository setup in the earlier steps (and then _don't_ use test_config, because the whole point is for it to persist).
t/t5562-http-backend-content-length.sh line 113
Quoted 8 lines
t/t5562-http-backend-content-length.sh new file +8
-0+ test_http_env receive \ + "$TEST_DIRECTORY"/t5562/invoke-with-content-length.pl push_body git http-backend >act.out 2>act.err && + verify_http_result "200 OK" && + git rev-parse newbranch >act.head && + echo "$hash_next" >exp.head && + test_cmp act.head exp.head && + git branch -D newbranch +'
Should this "git branch -D" go into a "test_when_finished" block closer to when it is created?
t/t5562-http-backend-content-length.sh line 64
Quoted 3 lines
t/t5562-http-backend-content-length.sh new file +3
-0+# write data +my $pid = open(my $out, "|-", @command); +defined syswrite($out, $body_data) or die "Cannot write data: $!";
I assume perl's syswrite() has the usual write() pitfalls, like sometimes returning without writing all of the bytes. Could this just be:
print $out $body_date;
?
t/t5562-http-backend-content-length.sh line 69
Quoted 5 lines
t/t5562-http-backend-content-length.sh new file +5
-0+sleep 1; # is interrupted by SIGCHLD +if (!$exited) { + close($out); + die "Command did not exit after reading whole body"; +}
A sleep like this is a recipe for having the test fail when the system is under heavy load and it takes the sub-process more than a second to return (and the SIGCHLD to get delivered).
Normally I'd suggest wait() or pause(), but I think the intent is to sleep because in the failure case we'd never see the signal, and just hang? If so, then perhaps we should give a much higher sleep, like 60 seconds. That will mean the test eventually does report failure, but should be much less likely to cause a false negative. And if we do get the signal (which we'd usually expect), then we exit immediately.
Also, do we need to protect ourselves against other signals being delivered? E.g., if I resize my xterm and this process gets SIGWINCH, is it going to erroneously end the sleep and say "nope, no exited signal"?
My read through the tests was mostly looking for mechanical problems. I didn't give much though to whether we were getting full coverage, and now it's my bed-time here. So I'll leave that for later (or somebody else).
-Peff
Re: [PATCH v7 2/2] http-backend: respect CONTENT_LENGTH for receive-pack
On Mon, Jun 04, 2018 at 12:44:09AM -0400, Jeff King wrote:
Thanks for the comments, I will do the things you proposed, or try to and get back later if there are any issues. Some notes below.
Quoted 5 lines · Max Kirillov
Since this is slightly less efficient, and because it only matters if the web server does not already close the pipe, should this have a run-time configuration knob, even if it defaults to safe-but-slightly-slower?
Personally, I of course don't want this. Also, I don't think the difference is much noticeable. But you can never be sure without trying. I'll try to measure some numbers.
Quoted 10 lines
http-backend.c static void copy_request(const char *prog_name, int out) · line 448
Quoted 2 lines
http-backend.c +2
-0+if (write_in_full (out, buf, n) <0 ) +die_errno ("%s aborted reading request" , prog_name);We don't necessarily know why the write failed. If it's EPIPE, then yes, the program probably did abort. But all we know is that
write()failed. We should probably say something more generic like:die_errno("unable to write to '%s'");or similar.
Actually, it is already 3rd same error in this file. Maybe deserve some refactoring. I will change the message also.
Quoted 10 lines
t/t5562-http-backend-content-length.sh line 39
Quoted 7 lines
t/t5562-http-backend-content-length.sh new file +7
-0+test_expect_success 'setup repository' ' + test_commit c0 && + test_commit c1 +' + +hash_head=$(git rev-parse HEAD) +hash_prev=$(git rev-parse HEAD~1)We generally prefer to have all commands, even ones we don't expect to fail, inside
test_expectblocks (e.g., with a "setup" description).
Will the defined variables get to the next test? I'll try to do as you describe.
Quoted 10 lines
t/t5562-http-backend-content-length.sh line 45
Quoted 5 lines
t/t5562-http-backend-content-length.sh new file +5
-0+cat >fetch_body <<EOF +0032want $hash_head +00000032have $hash_prev +0009done +EOFThis depends on the size of the hash. That's always 40 for now, but is something that may change soon.
We already have a
packetize()helper; could we use it here?
Could you point me to it? I cannot find it.
My understanfing is that the current protocol assumes 40 symbols hash, so another hash length would be another protocol, and since it's manually forged here it would anyway has to be changeda.
Quoted 10 lines
t/t5562-http-backend-content-length.sh line 75
Quoted 5 lines
t/t5562-http-backend-content-length.sh new file +5
-0+test_expect_success 'fetch plain truncated' ' + test_http_env upload \ + "$TEST_DIRECTORY"/t5562/invoke-with-content-length.pl fetch_body.trunc git http-backend >act.out 2>act.err && + test_must_fail verify_http_result "200 OK" +'Usually
test_must_failon a checking function like this is a sign that the check is not as robust as we'd like. If the function checks two things "A && B", then checkingtest_must_failwill only let us know "!A || !B", but you probably want to check both.
Well here I just want to know that the request has failed, and we already know that it can fail in different ways, but the test is not going to differentiate those ways.
Quoted 3 lines
(We'd also generally not use
test_must_failwith a non-git command, and just use a simple "!verify_http_result"; that would apply equally if gets split into two commands).
Will use ! there.
Quoted 5 lines
Quoted 5 lines
t/t5562/invoke-with-content-length.pl new file +5
-0+sleep 1; # is interrupted by SIGCHLD +if (!$exited) { + close($out); + die "Command did not exit after reading whole body"; +}
...
Quoted 3 lines
Also, do we need to protect ourselves against other signals being delivered? E.g., if I resize my xterm and this process gets SIGWINCH, is it going to erroneously end the sleep and say "nope, no exited signal"?
I'll check, but what could I do? Should I add blocking other signals there?
Re: [PATCH v7 2/2] http-backend: respect CONTENT_LENGTH for receive-pack
Quoted 9 lines · Max Kirillov
Quoted 4 lines · Jeff King
Since this is slightly less efficient, and because it only matters if the web server does not already close the pipe, should this have a run-time configuration knob, even if it defaults to safe-but-slightly-slower?
Personally, I of course don't want this. Also, I don't think the difference is much noticeable. But you can never be sure without trying. I'll try to measure some numbers.
It seems to be challenging to see any effect at my system. At least not with any real operation because changing references needs IO and index-pack needs CPU so. I'll try it some more.
Quoted 8 lines
Quoted 5 lines
We should probably say something more generic like:
die_errno("unable to write to '%s'");or similar.
Actually, it is already 3rd same error in this file. Maybe deserve some refactoring. I will change the message also.
Extracted the writing and refactoring to a single function, also fixed the message.
Quoted 9 lines
Quoted 9 lines
t/t5562-http-backend-content-length.sh line 45
Quoted 5 lines
t/t5562-http-backend-content-length.sh new file +5
-0+cat >fetch_body <<EOF +0032want $hash_head +00000032have $hash_prev +0009done +EOFThis depends on the size of the hash. That's always 40 for now, but is something that may change soon.
Quoted 3 lines
Quoted 1 line
We already have a
packetize()helper; could we use it here?Could you point me to it? I cannot find it.
Sorry, misread it as packetSize. Found and used.
Quoted 6 lines
Quoted 3 lines
Also, do we need to protect ourselves against other signals being delivered? E.g., if I resize my xterm and this process gets SIGWINCH, is it going to erroneously end the sleep and say "nope, no exited signal"?
I'll check, but what could I do? Should I add blocking other signals there?
In my Linux I don't see the signal. Except that, there seem to be not that many ignored signals. Anyway, I don't see what could be done bout it.
Re: [PATCH v7 2/2] http-backend: respect CONTENT_LENGTH for receive-pack
In reply to Max KirillovQuoted 9 lines · Max Kirillov
Quoted 5 lines · Max Kirillov
Since this is slightly less efficient, and because it only matters if the web server does not already close the pipe, should this have a run-time configuration knob, even if it defaults to safe-but-slightly-slower?
Personally, I of course don't want this. Also, I don't think the difference is much noticeable. But you can never be sure without trying. I'll try to measure some numbers.
I don't know if it will matter or not. I just wonder if we want to leave an escape hatch for people who might. I could take or leave it.
Quoted 2 lines
Actually, it is already 3rd same error in this file. Maybe deserve some refactoring. I will change the message also.
Thanks, that kind of related cleanup is very welcome.
Quoted 5 lines
Quoted 2 lines
We generally prefer to have all commands, even ones we don't expect to fail, inside
test_expectblocks (e.g., with a "setup" description).Will the defined variables get to the next test? I'll try to do as you describe.
Yes, the tests are all run as evals. So as long as you don't open a subshell yourself, any changes you make to process state will persist.
Quoted 11 lines
Quoted 10 lines
t/t5562-http-backend-content-length.sh line 75
Quoted 5 lines
t/t5562-http-backend-content-length.sh new file +5
-0+test_expect_success 'fetch plain truncated' ' + test_http_env upload \ + "$TEST_DIRECTORY"/t5562/invoke-with-content-length.pl fetch_body.trunc git http-backend >act.out 2>act.err && + test_must_fail verify_http_result "200 OK" +'Usually
test_must_failon a checking function like this is a sign that the check is not as robust as we'd like. If the function checks two things "A && B", then checkingtest_must_failwill only let us know "!A || !B", but you probably want to check both.
Quoted 3 lines
Well here I just want to know that the request has failed, and we already know that it can fail in different ways, but the test is not going to differentiate those ways.
OK, looking over your verify_http_result function, I _think_ we are OK here, because the only && is against a printf, which we wouldn't really expect to fail.
Quoted 10 lines
Quoted 9 lines
t/t5562/invoke-with-content-length.pl line 30
Quoted 5 lines
t/t5562/invoke-with-content-length.pl new file +5
-0+sleep 1; # is interrupted by SIGCHLD +if (!$exited) { + close($out); + die "Command did not exit after reading whole body"; +}Also, do we need to protect ourselves against other signals being delivered? E.g., if I resize my xterm and this process gets SIGWINCH, is it going to erroneously end the sleep and say "nope, no exited signal"?
Quoted 2 lines
I'll check, but what could I do? Should I add blocking other signals there?
I think a more robust check may be to waitpid() on the child for up to N seconds. Something like this:
$SIG{ALRM} = sub {
kill(9, $pid);
die "command did not exit after reading whole body" };
alarm(60);
waitpid($pid, 0);
alarm(0);
That should exit immediately if $pid does, and otherwise die after exactly 60 seconds. Perl's waitpid implementation will restart automatically if it gets another signal.
-Peff
Re: [PATCH v7 2/2] http-backend: respect CONTENT_LENGTH for receive-pack
Quoted 19 lines · Jeff King
Quoted 10 lines
Quoted 9 lines
t/t5562/invoke-with-content-length.pl line 30
Quoted 5 lines
t/t5562/invoke-with-content-length.pl new file +5
-0+sleep 1; # is interrupted by SIGCHLD +if (!$exited) { + close($out); + die "Command did not exit after reading whole body"; +}Also, do we need to protect ourselves against other signals being delivered? E.g., if I resize my xterm and this process gets SIGWINCH, is it going to erroneously end the sleep and say "nope, no exited signal"?
Quoted 2 lines
I'll check, but what could I do? Should I add blocking other signals there?
I think a more robust check may be to
waitpid()on the child for up to N seconds. Something like this:$SIG{ALRM} = sub { kill(9, $pid); die "command did not exit after reading whole body"
Quoted 8 lines
};
alarm(60);
waitpid($pid, 0);
alarm(0);That should exit immediately if $pid does, and otherwise die after exactly 60 seconds. Perl's waitpid implementation will restart automatically if it gets another signal.
I tried your original, delivering some signals to it. I think it actually is OK, too, because perl's sleep() implementation will also restart for something like SIGWINCH.
E.g., stracing looks like this:
nanosleep({tv_sec=60, tv_nsec=0}, {tv_sec=57, tv_nsec=791891377}) = ? ERESTART_RESTARTBLOCK (Interrupted by signal) --- SIGWINCH {si_signo=SIGWINCH, si_code=SI_KERNEL} ---
restart_syscall(<... resuming interrupted nanosleep ...>
-Peff
Re: [PATCH v7 2/2] http-backend: respect CONTENT_LENGTH for receive-pack
In reply to Jeff KingQuoted 13 lines · Jeff King
t/t5560-http-backend-noserver.sh test_expect_success 'http-backend blocks bad PATH_INFO' ' · line 84
Quoted 9 lines · Max Kirillov
t/t5560-http-backend-noserver.sh +9
-0+ env \ + CONTENT_TYPE=application/x-git-upload-pack-request \ + QUERY_STRING=/repo.git/git-upload-pack \ + PATH_TRANSLATED="$PWD"/.git/git-upload-pack \ + GIT_HTTP_EXPORT_ALL=TRUE \ + REQUEST_METHOD=POST \ + CONTENT_LENGTH="$NOT_FIT_IN_SSIZE" \ + git http-backend </dev/zero >/dev/null 2>err && + grep -q "fatal:.*CONTENT_LENGTH" errI'm not sure if these messages should be marked for translation. If so, you'd want
test_i18ngrephere.
Message localization does not seem to be used in http-backend at all. It makes sense - server-side software probably does not know who is the user on the other side, if the message gets to the user at all. So, I think the message should not be translated.
Re: [PATCH v7 2/2] http-backend: respect CONTENT_LENGTH for receive-pack
Quoted 15 lines · Max Kirillov
Quoted 13 lines · Jeff King
t/t5560-http-backend-noserver.sh test_expect_success 'http-backend blocks bad PATH_INFO' ' · line 84
Quoted 9 lines · Max Kirillov
t/t5560-http-backend-noserver.sh +9
-0+ env \ + CONTENT_TYPE=application/x-git-upload-pack-request \ + QUERY_STRING=/repo.git/git-upload-pack \ + PATH_TRANSLATED="$PWD"/.git/git-upload-pack \ + GIT_HTTP_EXPORT_ALL=TRUE \ + REQUEST_METHOD=POST \ + CONTENT_LENGTH="$NOT_FIT_IN_SSIZE" \ + git http-backend </dev/zero >/dev/null 2>err && + grep -q "fatal:.*CONTENT_LENGTH" errI'm not sure if these messages should be marked for translation. If so, you'd want
test_i18ngrephere.
Quoted 5 lines
Message localization does not seem to be used in http-backend at all. It makes sense - server-side software probably does not know who is the user on the other side, if the message gets to the user at all. So, I think the message should not be translated.
OK. I think there's been talk of localizing "fatal:", but whoever does that patch would have to deal with fallout all over the test-suite. I don't think we need to worry about it yet.
-Peff
v8 cover http-backend: respect CONTENT_LENGTH as specified by rfc3875
In reply to Max KirillovDid the fixes proposed for v7
Max Kirillov (3):
http-backend: cleanup writing to child process
http-backend: respect CONTENT_LENGTH as specified by rfc3875
http-backend: respect CONTENT_LENGTH for receive-pack
config.c | 2 +- config.h | 1 + help.c | 1 + http-backend.c | 100 +++++++++++++-- t/t5562-http-backend-content-length.sh | 169 +++++++++++++++++++++++++ t/t5562/invoke-with-content-length.pl | 37 ++++++ 6 files changed, 295 insertions(+), 15 deletions(-) create mode 100755 t/t5562-http-backend-content-length.sh create mode 100755 t/t5562/invoke-with-content-length.pl
Signature · 1 line
2.17.0.1185.g782057d875
PATCH v8 1/3 http-backend: cleanup writing to child process
As explained in [1], we should not assume the reason why the writing has failed, and even if the reason is that child has existed not the reason why it have done so. So instead just say that writing has failed.
[1] https://public-inbox.org/git/[email protected]/
--- http-backend.c | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-)
http-backend.c +9 -5
@@ -278,6 +278,12 @@ static struct rpc_service *select_service(struct strbuf *hdr, const char *name)return svc; } +static void write_to_child (int out,const unsigned char *buf,ssize_t len,const char *prog_name) +{ +if (write_in_full (out, buf, len) <0 ) +die ("unable to write to '%s'" , prog_name); +} +/* * This is basically strbuf_read(), except that if we * hit max_request_buffer we die (we'd rather reject a
@@ -360,9 +366,8 @@ static void inflate_request(const char *prog_name, int out, int buffer_input)die ("zlib error inflating request, result %d" , ret); n = stream.total_out - cnt; -if (write_in_full (out, out_buf, n) <0 ) -die ("%s aborted reading request" , prog_name); - cnt += n; +write_to_child (out, out_buf, stream.total_out - cnt, prog_name); + cnt = stream.total_out;if (ret ==Z_STREAM_END ) goto done;
@@ -381,8 +386,7 @@ static void copy_request(const char *prog_name, int out)ssize_t n =read_request (0 , &buf);if (n <0 )die_errno ("error reading request body" ); -if (write_in_full (out, buf, n) <0 ) -die ("%s aborted reading request" , prog_name); +write_to_child (out, buf, n, prog_name);close (out);free (buf); }
Signature · 1 line
2.17.0.1185.g782057d875
PATCH v8 2/3 http-backend: respect CONTENT_LENGTH as specified by rfc3875
In reply to Max Kirillovhttp-backend reads whole input until EOF. However, the RFC 3875 specifies that a script must read only as many bytes as specified by CONTENT_LENGTH environment variable. Web server may exercise the specification by not closing the script's standard input after writing content. In that case http-backend would hang waiting for the input. The issue is known to happen with IIS/Windows, for example.
Make http-backend read only CONTENT_LENGTH bytes, if it's defined, rather than the whole input until EOF. If the variable is not defined, keep older behavior of reading until EOF because it is used to support chunked transfer-encoding.
This commit only fixes buffered input, whcih reads whole body before processign it. Non-buffered input is going to be fixed in subsequent commit.
--- config.c | 2 +- config.h | 1 + http-backend.c | 54 +++++++++++++++++++++++++++++++++++++++++++------- 3 files changed, 49 insertions(+), 8 deletions(-)
config.c +1 -1
@@ -853,7 +853,7 @@ int git_parse_ulong(const char *value, unsigned long *ret)return 1 ; } -static int git_parse_ssize_t (const char *value,ssize_t *ret) +int git_parse_ssize_t (const char *value,ssize_t *ret) {intmax_t tmp;if (!git_parse_signed (value, &tmp,maximum_signed_value_of_type (ssize_t)))
config.h +1 -0
@@ -48,6 +48,7 @@ extern void git_config(config_fn_t fn, void *);extern int config_with_options (config_fn_t fn,void *,struct git_config_source *config_source,const struct config_options *opts); +extern int git_parse_ssize_t (const char *,ssize_t *);extern int git_parse_ulong (const char *,unsigned long *);extern int git_parse_maybe_bool (const char *);extern int git_config_int (const char *,const char *);
http-backend.c +47 -7
93 lines not on this page · raw message
Signature · 1 line
2.17.0.1185.g782057d875
PATCH v8 3/3 http-backend: respect CONTENT_LENGTH for receive-pack
In reply to Max KirillovPush passes to another commands, as described in
https://public-inbox.org/git/[email protected]/
As it gets complicated to correctly track the data length, instead transfer the data through parent process and cut the pipe as the specified length is reached. Do it only when CONTENT_LENGTH is set, otherwise pass the input directly to the forked commands.
Add tests for cases:
* CONTENT_LENGTH is set, script's stdin has more data, with all combinations of variations: fetch or push, plain or compressed body, correct or truncated input.
* CONTENT_LENGTH is specified to a value which does not fit into ssize_t.
--- help.c | 1 + http-backend.c | 32 ++++- t/t5562-http-backend-content-length.sh | 169 +++++++++++++++++++++++++ t/t5562/invoke-with-content-length.pl | 37 ++++++ 4 files changed, 237 insertions(+), 2 deletions(-) create mode 100755 t/t5562-http-backend-content-length.sh create mode 100755 t/t5562/invoke-with-content-length.pl
help.c +1 -0
@@ -419,6 +419,7 @@ int cmd_version(int argc, const char **argv, const char *prefix)else printf ("no commit associated with this build\n" );printf ("sizeof-long: %d\n" , (int )sizeof (long )); +printf ("sizeof-size_t: %d\n" , (int )sizeof (size_t ));/* NEEDSWORK: also save and output GIT-BUILD_OPTIONS? */ }return 0 ;
http-backend.c +30 -2
@@ -372,6 +372,8 @@ static void inflate_request(const char *prog_name, int out, int buffer_input, ssunsigned char in_buf[8192 ];unsigned char out_buf[8192 ];unsigned long cnt =0 ; +int req_len_defined = req_len >=0 ; +size_t req_remaining_len = req_len;memset (&stream,0 ,sizeof (stream));git_inflate_init_gzip_only (&stream);
@@ -386,8 +388,15 @@ static void inflate_request(const char *prog_name, int out, int buffer_input, ss n =read_request (0 , &full_request, req_len); stream.next_in = full_request; }else { - n =xread (0 , in_buf,sizeof (in_buf)); +ssize_t buffer_len; +if (req_len_defined && req_remaining_len <=sizeof (in_buf)) + buffer_len = req_remaining_len; +else + buffer_len =sizeof (in_buf); + n =xread (0 , in_buf, buffer_len); stream.next_in = in_buf; +if (req_len_defined && n >0 ) + req_remaining_len -= n; }if (n <=0 )
@@ -430,6 +439,23 @@ static void copy_request(const char *prog_name, int out, ssize_t req_len)free (buf); } +static void pipe_fixed_length (const char *prog_name,int out,size_t req_len) +{ +unsigned char buf[8192 ]; +size_t remaining_len = req_len; + +while (remaining_len >0 ) { +size_t chunk_length = remaining_len >sizeof (buf) ?sizeof (buf) : remaining_len; +ssize_t n =xread (0 , buf, chunk_length); +if (n <0 ) +die_errno ("Reading request failed" ); +write_to_child (out, buf, n, prog_name); + remaining_len -= n; + } + +close (out); +} +static void run_service (const char **argv,int buffer_input) {const char *encoding =getenv ("HTTP_CONTENT_ENCODING" );
@@ -456,7 +482,7 @@ static void run_service(const char **argv, int buffer_input) "GIT_COMMITTER_EMAIL=%s@http.%s", user, host); cld.argv = argv; -if (buffer_input || gzipped_request) +if (buffer_input || gzipped_request || req_len >=0 ) cld.in =-1 ; cld.git_cmd =1 ;if (start_command (&cld))
@@ -467,6 +493,8 @@ static void run_service(const char **argv, int buffer_input)inflate_request (argv[0 ], cld.in, buffer_input, req_len); else if (buffer_input) copy_request(argv[0], cld.in, req_len); + else if (req_len >= 0) + pipe_fixed_length(argv[0], cld.in, req_len); else close(0);
t/t5562-http-backend-content-length.sh new file +169 -0
169 lines not on this page · raw message
t/t5562/invoke-with-content-length.pl new file +37 -0
@@ -0,0 +1,37 @@ +#!/usr/bin/perl +use 5.008; +use strict; +use warnings; + +my $body_filename = $ARGV[0]; +my @command = @ARGV[1 .. $#ARGV]; + +# read data +my $body_size = -s $body_filename; +$ENV{"CONTENT_LENGTH"} = $body_size; +open(my $body_fh, "<", $body_filename) or die "Cannot open $body_filename: $!"; +my $body_data; +defined read($body_fh, $body_data, $body_size) or die "Cannot read $body_filename: $!"; +close($body_fh); + +my $exited = 0; +$SIG{"CHLD"} = sub { + $exited = 1; +}; + +# write data +my $pid = open(my $out, "|-", @command); +{ + # disable buffering at $out + my $old_selected = select; + select $out; + $| = 1; + select $old_selected; +} +print $out $body_data or die "Cannot write data: $!"; + +sleep 60; # is interrupted by SIGCHLD +if (!$exited) { + close($out); + die "Command did not exit after reading whole body"; +}
Signature · 1 line
2.17.0.1185.g782057d875
Re: [PATCH v8 3/3] http-backend: respect CONTENT_LENGTH for receive-pack
[Hrm, this time with hopefully proper In-Reply-To: header.
Sorry for the double post.]
Quoted 34 lines
Push passes to another commands, as described in
https://public-inbox.org/git/[email protected]/As it gets complicated to correctly track the data length, instead transfer the data through parent process and cut the pipe as the specified length is reached. Do it only when
CONTENT_LENGTHis set, otherwise pass the input directly to the forked commands.Add tests for cases:
*
CONTENT_LENGTHis set, script's stdin has more data, with all combinations of variations: fetch or push, plain or compressed body, correct or truncated input.*
CONTENT_LENGTHis specified to a value which does not fit intossize_t.Helped-by Junio C Hamano <[email protected]>Signed-off-by Max Kirillov <[email protected]>--- help.c | 1 + http-backend.c | 32 ++++- t/t5562-http-backend-content-length.sh | 169 +++++++++++++++++++++++++ t/t5562/invoke-with-content-length.pl | 37 ++++++ 4 files changed, 237 insertions(+), 2 deletions(-) create mode 100755 t/t5562-http-backend-content-length.sh create mode 100755 t/t5562/invoke-with-content-length.plt/t5562-http-backend-content-length.sh new file +0
-0
t/t5562-http-backend-content-length.sh line 9
Quoted 9 lines
t/t5562-http-backend-content-length.sh new file +9
-0@@ -0,0 +1,169 @@ +#!/bin/sh + +test_description='test git-http-backend respects CONTENT_LENGTH' +. ./test-lib.sh + +test_lazy_prereq GZIP 'gzip --version' + +verify_http_result() { + # sometimes there is fatal error buit the result is still 200
s/buit/but/
t/t5562-http-backend-content-length.sh line 13
Quoted 4 lines
t/t5562-http-backend-content-length.sh new file +4
-0+ if grep 'fatal:' act.err + then + return 1 + fi
I just happened to stumble upon a failure because of 'fatal: the remote end hung up unexpectedly' in the test 'push plain'.
What does that "sometimes" in the above comment mean, and how often does such a failure happen? I see these patches are in 'pu' for over a month now, so based on the number of reflog entries since then it happened once from about 30-35 builds on Travis CI so far.
I don't really like the idea of adding a bunch of flaky test cases... we have enough of them already, unfortunately.
Quoted 49 lines
t/t5562-http-backend-content-length.sh new file +49
-0+ + if ! grep "Status" act.out >act + then + printf "Status: 200 OK\r\n" >act + fi + printf "Status: $1\r\n" >exp && + test_cmp exp act +} + +test_http_env() { + handler_type="$1" + shift + env \ + CONTENT_TYPE="application/x-git-$handler_type-pack-request" \ + QUERY_STRING="/repo.git/git-$handler_type-pack" \ + PATH_TRANSLATED="$PWD/.git/git-$handler_type-pack" \ + GIT_HTTP_EXPORT_ALL=TRUE \ + REQUEST_METHOD=POST \ + "$@" +} + +ssize_b100dots() { + # hardcoded ((size_t) SSIZE_MAX) + 1 + case "$(build_option sizeof-size_t)" in + 8) echo 9223372036854775808;; + 4) echo 2147483648;; + *) die "Unexpected ssize_t size: $(build_option sizeof-size_t)";; + esac +} + +test_expect_success 'setup' ' + git config http.receivepack true && + test_commit c0 && + test_commit c1 && + hash_head=$(git rev-parse HEAD) && + hash_prev=$(git rev-parse HEAD~1) && + printf "want %s" "$hash_head" | packetize >fetch_body && + printf 0000 >>fetch_body && + printf "have %s" "$hash_prev" | packetize >>fetch_body && + printf done | packetize >>fetch_body && + test_copy_bytes 10 <fetch_body >fetch_body.trunc && + hash_next=$(git commit-tree -p HEAD -m next HEAD^{tree}) && + printf "%s %s refs/heads/newbranch\\0report-status\\n" "$_z40" "$hash_next" | packetize >push_body && + printf 0000 >>push_body && + echo "$hash_next" | git pack-objects --stdout >>push_body && + test_copy_bytes 10 <push_body >push_body.trunc && + : >empty_body +' +
t/t5562-http-backend-content-length.sh line 72
Quoted 10 lines
t/t5562-http-backend-content-length.sh new file +10
-0+test_expect_success GZIP 'setup, compression related' ' + gzip -k fetch_body && + test_copy_bytes 10 <fetch_body.gz >fetch_body.gz.trunc && + gzip -k push_body && + test_copy_bytes 10 <push_body.gz >push_body.gz.trunc +' + +test_expect_success 'fetch plain' ' + test_http_env upload \ + "$TEST_DIRECTORY"/t5562/invoke-with-content-length.pl fetch_body git http-backend >act.out 2>act.err &&
Don't save the standard error of the whole shell function. When running the test with /bin/sh and '-x' tracing, then the trace of commands executed in the function will be included in the standard error as well, which may interfere with later verification (though in this case it doesn't seem like it would cause any issues).
Please limit the redirections to the relevant command's output. AFAICT all invocations of 'test_http_env' in these tests have their stdout and stderr redirected to the same pair of files, so perhaps you could simply move all these redirections inside the function.
t/t5562-http-backend-content-length.sh line 78
Quoted 6 lines
t/t5562-http-backend-content-length.sh new file +6
-0+ verify_http_result "200 OK" +' + +test_expect_success 'fetch plain truncated' ' + test_http_env upload \ + "$TEST_DIRECTORY"/t5562/invoke-with-content-length.pl fetch_body.trunc git http-backend >act.out 2>act.err &&
If this command were to print a "fatal: ..." message to its standard error, then ...
t/t5562-http-backend-content-length.sh line 79
Quoted 1 line
t/t5562-http-backend-content-length.sh new file +1
-0+ ! verify_http_result "200 OK"
... this function would return error (because of that 'if grep fatal:
...' statement) without even looking at the status, but the test would still succeed. Is that really the desired behavior here?
Quoted 137 lines
t/t5562-http-backend-content-length.sh new file +90
-0+' + +test_expect_success 'fetch plain empty' ' + test_http_env upload \ + "$TEST_DIRECTORY"/t5562/invoke-with-content-length.pl empty_body git http-backend >act.out 2>act.err && + ! verify_http_result "200 OK" +' + +test_expect_success GZIP 'fetch gzipped' ' + test_http_env upload \ + HTTP_CONTENT_ENCODING="gzip" \ + "$TEST_DIRECTORY"/t5562/invoke-with-content-length.pl fetch_body.gz git http-backend >act.out 2>act.err && + verify_http_result "200 OK" +' + +test_expect_success GZIP 'fetch gzipped truncated' ' + test_http_env upload \ + HTTP_CONTENT_ENCODING="gzip" \ + "$TEST_DIRECTORY"/t5562/invoke-with-content-length.pl fetch_body.gz.trunc git http-backend >act.out 2>act.err && + ! verify_http_result "200 OK" +' + +test_expect_success GZIP 'fetch gzipped empty' ' + test_http_env upload \ + HTTP_CONTENT_ENCODING="gzip" \ + "$TEST_DIRECTORY"/t5562/invoke-with-content-length.pl empty_body git http-backend >act.out 2>act.err && + ! verify_http_result "200 OK" +' + +test_expect_success GZIP 'push plain' ' + test_when_finished "git branch -D newbranch" && + test_http_env receive \ + "$TEST_DIRECTORY"/t5562/invoke-with-content-length.pl push_body git http-backend >act.out 2>act.err && + verify_http_result "200 OK" && + git rev-parse newbranch >act.head && + echo "$hash_next" >exp.head && + test_cmp act.head exp.head +' + +test_expect_success 'push plain truncated' ' + test_http_env receive \ + "$TEST_DIRECTORY"/t5562/invoke-with-content-length.pl push_body.trunc git http-backend >act.out 2>act.err && + ! verify_http_result "200 OK" +' + +test_expect_success 'push plain empty' ' + test_http_env receive \ + "$TEST_DIRECTORY"/t5562/invoke-with-content-length.pl empty_body git http-backend >act.out 2>act.err && + ! verify_http_result "200 OK" +' + +test_expect_success GZIP 'push gzipped' ' + test_when_finished "git branch -D newbranch" && + test_http_env receive \ + HTTP_CONTENT_ENCODING="gzip" \ + "$TEST_DIRECTORY"/t5562/invoke-with-content-length.pl push_body.gz git http-backend >act.out 2>act.err && + verify_http_result "200 OK" && + git rev-parse newbranch >act.head && + echo "$hash_next" >exp.head && + test_cmp act.head exp.head +' + +test_expect_success GZIP 'push gzipped truncated' ' + test_http_env receive \ + HTTP_CONTENT_ENCODING="gzip" \ + "$TEST_DIRECTORY"/t5562/invoke-with-content-length.pl push_body.gz.trunc git http-backend >act.out 2>act.err && + ! verify_http_result "200 OK" +' + +test_expect_success GZIP 'push gzipped empty' ' + test_http_env receive \ + HTTP_CONTENT_ENCODING="gzip" \ + "$TEST_DIRECTORY"/t5562/invoke-with-content-length.pl empty_body git http-backend >act.out 2>act.err && + ! verify_http_result "200 OK" +' + +test_expect_success 'CONTENT_LENGTH overflow ssite_t' ' + NOT_FIT_IN_SSIZE=$(ssize_b100dots) && + env \ + CONTENT_TYPE=application/x-git-upload-pack-request \ + QUERY_STRING=/repo.git/git-upload-pack \ + PATH_TRANSLATED="$PWD"/.git/git-upload-pack \ + GIT_HTTP_EXPORT_ALL=TRUE \ + REQUEST_METHOD=POST \ + CONTENT_LENGTH="$NOT_FIT_IN_SSIZE" \ + git http-backend </dev/zero >/dev/null 2>err && + grep "fatal:.*CONTENT_LENGTH" err +' + +test_donet/t5562/invoke-with-content-length.pl new file +37
-0@@ -0,0 +1,37 @@ +#!/usr/bin/perl +use 5.008; +use strict; +use warnings; + +my $body_filename = $ARGV[0]; +my @command = @ARGV[1 .. $#ARGV]; + +# read data +my $body_size = -s $body_filename; +$ENV{"CONTENT_LENGTH"} = $body_size; +open(my $body_fh, "<", $body_filename) or die "Cannot open $body_filename: $!"; +my $body_data; +defined read($body_fh, $body_data, $body_size) or die "Cannot read $body_filename: $!"; +close($body_fh); + +my $exited = 0; +$SIG{"CHLD"} = sub { + $exited = 1; +}; + +# write data +my $pid = open(my $out, "|-", @command); +{ + # disable buffering at $out + my $old_selected = select; + select $out; + $| = 1; + select $old_selected; +} +print $out $body_data or die "Cannot write data: $!"; + +sleep 60; # is interrupted by SIGCHLD +if (!$exited) { + close($out); + die "Command did not exit after reading whole body"; +}Signature · 1 line
2.17.0.1185.g782057d875
Re: [PATCH v8 3/3] http-backend: respect CONTENT_LENGTH for receive-pack
Quoted 3 lines · SZEDER Gábor
t/t5562-http-backend-content-length.sh line 9
Quoted 1 line
t/t5562-http-backend-content-length.sh new file +1
-0+ # sometimes there is fatal error buit the result is still 200s/buit/but/
Thanks, will fix
Quoted 7 lines
t/t5562-http-backend-content-length.sh line 13
Quoted 4 lines
t/t5562-http-backend-content-length.sh new file +4
-0+ if grep 'fatal:' act.err + then + return 1 + fiI just happened to stumble upon a failure because of 'fatal: the remote end hung up unexpectedly' in the test 'push plain'.
Did it happen once or repeated? It is rather strange, that one shoud not fail. Which OS it was?
There have been doubds that a random incoming signal can trigger such a failure.
Quoted 4 lines
What does that "sometimes" in the above comment mean, and how often does such a failure happen? I see these patches are in 'pu' for over a month now, so based on the number of reflog entries since then it happened once from about 30-35 builds on Travis CI so far.
"sometimes" here means "for some kinds of fatal error failure", there is nothing random in it.
Quoted 8 lines
t/t5562-http-backend-content-length.sh line 72
Quoted 1 line
t/t5562-http-backend-content-length.sh new file +1
-0+ "$TEST_DIRECTORY"/t5562/invoke-with-content-length.pl fetch_body git http-backend >act.out 2>act.err &&Don't save the standard error of the whole shell function. When running the test with
/bin/shand '-x' tracing, then the trace of commands executed in the function will be included in the standard error as well, which may interfere with later verification (though in this case it doesn't seem like it would cause any issues).
Quoted 4 lines
Please limit the redirections to the relevant command's output. AFAICT all invocations of '
test_http_env' in these tests have their stdout and stderr redirected to the same pair of files, so perhaps you could simply move all these redirections inside the function.
Thanks, I'll try to fix it
Quoted 5 lines
Review
Quoted 1 line
(quoted diff) +1
-0+ ! verify_http_result "200 OK"... this function would return error (because of that 'if grep fatal:
...' statement) without even looking at the status, but the test would still succeed. Is that really the desired behavior here?
Yes, it is a desired behavior. A failure is expected here, and the failure does not show up as non-200 status, as described above.
Re: [PATCH v8 3/3] http-backend: respect CONTENT_LENGTH for receive-pack
Quoted 9 lines · Max Kirillov
Quoted 7 lines · SZEDER Gábor
Quoted 6 lines
t/t5562-http-backend-content-length.sh new file +5
-0+ # sometimes there is fatal error buit the result is still 200 + if grep 'fatal:' act.err + then + return 1 + fi
Quoted 5 lines
Quoted 2 lines
I just happened to stumble upon a failure because of 'fatal: the remote end hung up unexpectedly' in the test 'push plain'.
Did it happen once or repeated? It is rather strange, that one shoud not fail. Which OS it was?
Only once, so far. It was one of my OSX build jobs on Travis CI, but I don't know what OSX version is used.
'act.err' contained this (which will get line-wrapped, I'm afraid):
++handler_type=receive
++shift
++env CONTENT_TYPE=application/x-git-receive-pack-request QUERY_STRING=/repo.git/git-receive-pack
'PATH_TRANSLATED=/Users/travis/t/trash
dir.t5562/.git/git-receive-pack' GIT_HTTP_EXPORT_ALL=TRUE
REQUEST_METHOD=POST /Users/travis/build/szeder/git-cooking-topics-for-travis-ci/t/t5562/invoke-with-content-length.pl push_body git http-backend
<...128 zero bytes...>fatal: the remote end hung up unexpectedly
I couldn't reproduce it on my Linux box.
Quoted 13 lines
There have been doubds that a random incoming signal can trigger such a failure.
Quoted 4 lines
What does that "sometimes" in the above comment mean, and how often does such a failure happen? I see these patches are in 'pu' for over a month now, so based on the number of reflog entries since then it happened once from about 30-35 builds on Travis CI so far.
"sometimes" here means "for some kinds of fatal error failure", there is nothing random in it.
Quoted 2 lines
Quoted 1 line
+ !
verify_http_result"200 OK"
Quoted 7 lines
Quoted 3 lines
... this function would return error (because of that 'if grep fatal:
...' statement) without even looking at the status, but the test would still succeed. Is that really the desired behavior here?Yes, it is a desired behavior. A failure is expected here, and the failure does not show up as non-200 status, as described above.
OK, then I misunderstood that comment.
Perhaps a different wording could make it slightly better? E.g. "In some of these tests ..." instead of that "sometimes". Dunno.
Re: [PATCH v8 3/3] http-backend: respect CONTENT_LENGTH for receive-pack
Quoted 23 lines · SZEDER Gábor
Quoted 5 lines · Max Kirillov
Quoted 2 lines
I just happened to stumble upon a failure because of 'fatal: the remote end hung up unexpectedly' in the test 'push plain'.
Did it happen once or repeated? It is rather strange, that one shoud not fail. Which OS it was?
Only once, so far. It was one of my OSX build jobs on Travis CI, but I don't know what OSX version is used.
'act.err' contained this (which will get line-wrapped, I'm afraid):
++handler_type=receive
++shift
++env CONTENT_TYPE=application/x-git-receive-pack-request QUERY_STRING=/repo.git/git-receive-pack
'PATH_TRANSLATED=/Users/travis/t/trash
dir.t5562/.git/git-receive-pack' GIT_HTTP_EXPORT_ALL=TRUE
REQUEST_METHOD=POST /Users/travis/build/szeder/git-cooking-topics-for-travis-ci/t/t5562/invoke-with-content-length.plpush_bodygit http-backend
<...128 zero bytes...>fatal: the remote end hung up unexpectedly
Quoted 1 line
I couldn't reproduce it on my Linux box.
The only reason for this I could imagine is some perl utility failure to feed the body to git http-backend. I could not reproduce it either, but if such things happen often again maybe should concider C helper instead. Though I'm afraid I easily can make more mistakes in it than perl interpreter authors.
I'll make the other changes, and sofar just hope it would not happen again.
v9 cover http-backend: respect CONTENT_LENGTH as specified by rfc3875
In reply to Max Kirillov* fix the gzip usage as suggested in https://public-inbox.org/git/[email protected]/
* better explanation of why status check is needed
* redirect only the helper call, not the whole shell function, also move more into the shell function
Max Kirillov (3):
http-backend: cleanup writing to child process
http-backend: respect CONTENT_LENGTH as specified by rfc3875
http-backend: respect CONTENT_LENGTH for receive-pack
config.c | 2 +- config.h | 1 + help.c | 1 + http-backend.c | 100 +++++++++++++--- t/t5562-http-backend-content-length.sh | 155 +++++++++++++++++++++++++ t/t5562/invoke-with-content-length.pl | 37 ++++++ 6 files changed, 281 insertions(+), 15 deletions(-) create mode 100755 t/t5562-http-backend-content-length.sh create mode 100755 t/t5562/invoke-with-content-length.pl
Signature · 1 line
2.17.0.1185.g782057d875
PATCH v9 1/3 http-backend: cleanup writing to child process
As explained in [1], we should not assume the reason why the writing has failed, and even if the reason is that child has existed not the reason why it have done so. So instead just say that writing has failed.
[1] https://public-inbox.org/git/[email protected]/
--- http-backend.c | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-)
http-backend.c +9 -5
@@ -279,6 +279,12 @@ static struct rpc_service *select_service(struct strbuf *hdr, const char *name)return svc; } +static void write_to_child (int out,const unsigned char *buf,ssize_t len,const char *prog_name) +{ +if (write_in_full (out, buf, len) <0 ) +die ("unable to write to '%s'" , prog_name); +} +/* * This is basically strbuf_read(), except that if we * hit max_request_buffer we die (we'd rather reject a
@@ -361,9 +367,8 @@ static void inflate_request(const char *prog_name, int out, int buffer_input)die ("zlib error inflating request, result %d" , ret); n = stream.total_out - cnt; -if (write_in_full (out, out_buf, n) <0 ) -die ("%s aborted reading request" , prog_name); - cnt += n; +write_to_child (out, out_buf, stream.total_out - cnt, prog_name); + cnt = stream.total_out;if (ret ==Z_STREAM_END ) goto done;
@@ -382,8 +387,7 @@ static void copy_request(const char *prog_name, int out)ssize_t n =read_request (0 , &buf);if (n <0 )die_errno ("error reading request body" ); -if (write_in_full (out, buf, n) <0 ) -die ("%s aborted reading request" , prog_name); +write_to_child (out, buf, n, prog_name);close (out);free (buf); }
Signature · 1 line
2.17.0.1185.g782057d875
PATCH v9 2/3 http-backend: respect CONTENT_LENGTH as specified by rfc3875
In reply to Max Kirillovhttp-backend reads whole input until EOF. However, the RFC 3875 specifies that a script must read only as many bytes as specified by CONTENT_LENGTH environment variable. Web server may exercise the specification by not closing the script's standard input after writing content. In that case http-backend would hang waiting for the input. The issue is known to happen with IIS/Windows, for example.
Make http-backend read only CONTENT_LENGTH bytes, if it's defined, rather than the whole input until EOF. If the variable is not defined, keep older behavior of reading until EOF because it is used to support chunked transfer-encoding.
This commit only fixes buffered input, whcih reads whole body before processign it. Non-buffered input is going to be fixed in subsequent commit.
--- config.c | 2 +- config.h | 1 + http-backend.c | 54 +++++++++++++++++++++++++++++++++++++++++++------- 3 files changed, 49 insertions(+), 8 deletions(-)
config.c +1 -1
@@ -921,7 +921,7 @@ int git_parse_ulong(const char *value, unsigned long *ret)return 1 ; } -static int git_parse_ssize_t (const char *value,ssize_t *ret) +int git_parse_ssize_t (const char *value,ssize_t *ret) {intmax_t tmp;if (!git_parse_signed (value, &tmp,maximum_signed_value_of_type (ssize_t)))
config.h +1 -0
@@ -73,6 +73,7 @@ extern void git_config(config_fn_t fn, void *);extern int config_with_options (config_fn_t fn,void *,struct git_config_source *config_source,const struct config_options *opts); +extern int git_parse_ssize_t (const char *,ssize_t *);extern int git_parse_ulong (const char *,unsigned long *);extern int git_parse_maybe_bool (const char *);extern int git_config_int (const char *,const char *);
http-backend.c +47 -7
93 lines not on this page · raw message
Signature · 1 line
2.17.0.1185.g782057d875
Re: [PATCH v9 2/3] http-backend: respect CONTENT_LENGTH as specified by rfc3875
http-backend.c static ssize_t read_request(int fd, unsigned char **out) · line 338
Quoted 10 lines · Max Kirillov
http-backend.c +9
-1-static void inflate_request (const char *prog_name,int out,int buffer_input) +static ssize_t read_request_fixed_len (int fd,ssize_t req_len,unsigned char **out) +{ +unsigned char *buf =NULL ; +ssize_t cnt =0 ; + +if (max_request_buffer < req_len) { +die ("request was larger than our maximum size (%lu): " +"%" PRIuMAX"; try setting GIT_HTTP_MAX_REQUEST_BUFFER" , + max_request_buffer, (uintmax_t )req_len);
Please mark these strings for translation with _().
Signature · 1 line
Duy
Re: [PATCH v9 2/3] http-backend: respect CONTENT_LENGTH as specified by rfc3875
Quoted 7 lines · Duy Nguyen
http-backend.c static ssize_t read_request(int fd, unsigned char **out) · line 338
Quoted 4 lines · Max Kirillov
http-backend.c +4
-0+if (max_request_buffer < req_len) { +die ("request was larger than our maximum size (%lu): " +"%" PRIuMAX"; try setting GIT_HTTP_MAX_REQUEST_BUFFER" , + max_request_buffer, (uintmax_t )req_len);Please mark these strings for translation with
_().
It has been discussed in [1]. Since it is not a local user facing part, probably should not be translated.
[1] https://public-inbox.org/git/[email protected]/
Signature · 1 line
Max
Re: [PATCH v9 2/3] http-backend: respect CONTENT_LENGTH as specified by rfc3875
Quoted 7 lines · Max Kirillov
Quoted 6 lines · Duy Nguyen
Quoted 4 lines · Max Kirillov
http-backend.c +4
-0+if (max_request_buffer < req_len) { +die ("request was larger than our maximum size (%lu): " +"%" PRIuMAX"; try setting GIT_HTTP_MAX_REQUEST_BUFFER" , + max_request_buffer, (uintmax_t )req_len);
Quoted 6 lines
Quoted 1 line
Please mark these strings for translation with
_().It has been discussed in [1]. Since it is not a local user facing part, probably should not be translated.
I'd support that design decision, FWIW.
PATCH v9 3/3 http-backend: respect CONTENT_LENGTH for receive-pack
In reply to Max KirillovPush passes to another commands, as described in
https://public-inbox.org/git/[email protected]/
As it gets complicated to correctly track the data length, instead transfer the data through parent process and cut the pipe as the specified length is reached. Do it only when CONTENT_LENGTH is set, otherwise pass the input directly to the forked commands.
Add tests for cases:
* CONTENT_LENGTH is set, script's stdin has more data, with all combinations of variations: fetch or push, plain or compressed body, correct or truncated input.
* CONTENT_LENGTH is specified to a value which does not fit into ssize_t.
--- help.c | 1 + http-backend.c | 32 ++++- t/t5562-http-backend-content-length.sh | 155 +++++++++++++++++++++++++ t/t5562/invoke-with-content-length.pl | 37 ++++++ 4 files changed, 223 insertions(+), 2 deletions(-) create mode 100755 t/t5562-http-backend-content-length.sh create mode 100755 t/t5562/invoke-with-content-length.pl
help.c +1 -0
@@ -609,6 +609,7 @@ int cmd_version(int argc, const char **argv, const char *prefix)else printf ("no commit associated with this build\n" );printf ("sizeof-long: %d\n" , (int )sizeof (long )); +printf ("sizeof-size_t: %d\n" , (int )sizeof (size_t ));/* NEEDSWORK: also save and output GIT-BUILD_OPTIONS? */ }return 0 ;
http-backend.c +30 -2
@@ -373,6 +373,8 @@ static void inflate_request(const char *prog_name, int out, int buffer_input, ssunsigned char in_buf[8192 ];unsigned char out_buf[8192 ];unsigned long cnt =0 ; +int req_len_defined = req_len >=0 ; +size_t req_remaining_len = req_len;memset (&stream,0 ,sizeof (stream));git_inflate_init_gzip_only (&stream);
@@ -387,8 +389,15 @@ static void inflate_request(const char *prog_name, int out, int buffer_input, ss n =read_request (0 , &full_request, req_len); stream.next_in = full_request; }else { - n =xread (0 , in_buf,sizeof (in_buf)); +ssize_t buffer_len; +if (req_len_defined && req_remaining_len <=sizeof (in_buf)) + buffer_len = req_remaining_len; +else + buffer_len =sizeof (in_buf); + n =xread (0 , in_buf, buffer_len); stream.next_in = in_buf; +if (req_len_defined && n >0 ) + req_remaining_len -= n; }if (n <=0 )
@@ -431,6 +440,23 @@ static void copy_request(const char *prog_name, int out, ssize_t req_len)free (buf); } +static void pipe_fixed_length (const char *prog_name,int out,size_t req_len) +{ +unsigned char buf[8192 ]; +size_t remaining_len = req_len; + +while (remaining_len >0 ) { +size_t chunk_length = remaining_len >sizeof (buf) ?sizeof (buf) : remaining_len; +ssize_t n =xread (0 , buf, chunk_length); +if (n <0 ) +die_errno ("Reading request failed" ); +write_to_child (out, buf, n, prog_name); + remaining_len -= n; + } + +close (out); +} +static void run_service (const char **argv,int buffer_input) {const char *encoding =getenv ("HTTP_CONTENT_ENCODING" );
@@ -457,7 +483,7 @@ static void run_service(const char **argv, int buffer_input) "GIT_COMMITTER_EMAIL=%s@http.%s", user, host); cld.argv = argv; -if (buffer_input || gzipped_request) +if (buffer_input || gzipped_request || req_len >=0 ) cld.in =-1 ; cld.git_cmd =1 ;if (start_command (&cld))
@@ -468,6 +494,8 @@ static void run_service(const char **argv, int buffer_input)inflate_request (argv[0 ], cld.in, buffer_input, req_len); else if (buffer_input) copy_request(argv[0], cld.in, req_len); + else if (req_len >= 0) + pipe_fixed_length(argv[0], cld.in, req_len); else close(0);
t/t5562-http-backend-content-length.sh new file +155 -0
155 lines not on this page · raw message
t/t5562/invoke-with-content-length.pl new file +37 -0
@@ -0,0 +1,37 @@ +#!/usr/bin/perl +use 5.008; +use strict; +use warnings; + +my $body_filename = $ARGV[0]; +my @command = @ARGV[1 .. $#ARGV]; + +# read data +my $body_size = -s $body_filename; +$ENV{"CONTENT_LENGTH"} = $body_size; +open(my $body_fh, "<", $body_filename) or die "Cannot open $body_filename: $!"; +my $body_data; +defined read($body_fh, $body_data, $body_size) or die "Cannot read $body_filename: $!"; +close($body_fh); + +my $exited = 0; +$SIG{"CHLD"} = sub { + $exited = 1; +}; + +# write data +my $pid = open(my $out, "|-", @command); +{ + # disable buffering at $out + my $old_selected = select; + select $out; + $| = 1; + select $old_selected; +} +print $out $body_data or die "Cannot write data: $!"; + +sleep 60; # is interrupted by SIGCHLD +if (!$exited) { + close($out); + die "Command did not exit after reading whole body"; +}
Signature · 1 line
2.17.0.1185.g782057d875
Re: [PATCH v9 0/3] http-backend: respect CONTENT_LENGTH as specified by rfc3875
In reply to Max KirillovOnly the 3rd patch has changed
Re: [PATCH v9 0/3] http-backend: respect CONTENT_LENGTH as specified by rfc3875
Quoted 1 line · Max Kirillov
Only the 3rd patch has changed
Thanks.