Skip to content

Commit fd357c4

Browse files
committed
Merge branch 'js/smart-http-detect-remote-error'
Some errors from the other side coming over smart HTTP transport were not noticed, which has been corrected. * js/smart-http-detect-remote-error: t5551: test server-side ERR packet remote-curl: tighten "version 2" check for smart-http remote-curl: refactor smart-http discovery
2 parents 5a5f408 + 30dea56 commit fd357c4

File tree

5 files changed

+70
-43
lines changed

5 files changed

+70
-43
lines changed

remote-curl.c

Lines changed: 57 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -331,9 +331,63 @@ static int get_protocol_http_header(enum protocol_version version,
331331
return 0;
332332
}
333333

334+
static void check_smart_http(struct discovery *d, const char *service,
335+
struct strbuf *type)
336+
{
337+
const char *p;
338+
struct packet_reader reader;
339+
340+
/*
341+
* If we don't see x-$service-advertisement, then it's not smart-http.
342+
* But once we do, we commit to it and assume any other protocol
343+
* violations are hard errors.
344+
*/
345+
if (!skip_prefix(type->buf, "application/x-", &p) ||
346+
!skip_prefix(p, service, &p) ||
347+
strcmp(p, "-advertisement"))
348+
return;
349+
350+
packet_reader_init(&reader, -1, d->buf, d->len,
351+
PACKET_READ_CHOMP_NEWLINE |
352+
PACKET_READ_DIE_ON_ERR_PACKET);
353+
if (packet_reader_read(&reader) != PACKET_READ_NORMAL)
354+
die("invalid server response; expected service, got flush packet");
355+
356+
if (skip_prefix(reader.line, "# service=", &p) && !strcmp(p, service)) {
357+
/*
358+
* The header can include additional metadata lines, up
359+
* until a packet flush marker. Ignore these now, but
360+
* in the future we might start to scan them.
361+
*/
362+
for (;;) {
363+
packet_reader_read(&reader);
364+
if (reader.pktlen <= 0) {
365+
break;
366+
}
367+
}
368+
369+
/*
370+
* v0 smart http; callers expect us to soak up the
371+
* service and header packets
372+
*/
373+
d->buf = reader.src_buffer;
374+
d->len = reader.src_len;
375+
d->proto_git = 1;
376+
377+
} else if (!strcmp(reader.line, "version 2")) {
378+
/*
379+
* v2 smart http; do not consume version packet, which will
380+
* be handled elsewhere.
381+
*/
382+
d->proto_git = 1;
383+
384+
} else {
385+
die("invalid server response; got '%s'", reader.line);
386+
}
387+
}
388+
334389
static struct discovery *discover_refs(const char *service, int for_push)
335390
{
336-
struct strbuf exp = STRBUF_INIT;
337391
struct strbuf type = STRBUF_INIT;
338392
struct strbuf charset = STRBUF_INIT;
339393
struct strbuf buffer = STRBUF_INIT;
@@ -405,55 +459,15 @@ static struct discovery *discover_refs(const char *service, int for_push)
405459
last->buf_alloc = strbuf_detach(&buffer, &last->len);
406460
last->buf = last->buf_alloc;
407461

408-
strbuf_addf(&exp, "application/x-%s-advertisement", service);
409-
if (maybe_smart &&
410-
(5 <= last->len && last->buf[4] == '#') &&
411-
!strbuf_cmp(&exp, &type)) {
412-
struct packet_reader reader;
413-
packet_reader_init(&reader, -1, last->buf, last->len,
414-
PACKET_READ_CHOMP_NEWLINE |
415-
PACKET_READ_DIE_ON_ERR_PACKET);
416-
417-
/*
418-
* smart HTTP response; validate that the service
419-
* pkt-line matches our request.
420-
*/
421-
if (packet_reader_read(&reader) != PACKET_READ_NORMAL)
422-
die("invalid server response; expected service, got flush packet");
423-
424-
strbuf_reset(&exp);
425-
strbuf_addf(&exp, "# service=%s", service);
426-
if (strcmp(reader.line, exp.buf))
427-
die("invalid server response; got '%s'", reader.line);
428-
strbuf_release(&exp);
429-
430-
/* The header can include additional metadata lines, up
431-
* until a packet flush marker. Ignore these now, but
432-
* in the future we might start to scan them.
433-
*/
434-
for (;;) {
435-
packet_reader_read(&reader);
436-
if (reader.pktlen <= 0) {
437-
break;
438-
}
439-
}
440-
441-
last->buf = reader.src_buffer;
442-
last->len = reader.src_len;
443-
444-
last->proto_git = 1;
445-
} else if (maybe_smart &&
446-
last->len > 5 && starts_with(last->buf + 4, "version 2")) {
447-
last->proto_git = 1;
448-
}
462+
if (maybe_smart)
463+
check_smart_http(last, service, &type);
449464

450465
if (last->proto_git)
451466
last->refs = parse_git_refs(last, for_push);
452467
else
453468
last->refs = parse_info_refs(last);
454469

455470
strbuf_release(&refs_url);
456-
strbuf_release(&exp);
457471
strbuf_release(&type);
458472
strbuf_release(&charset);
459473
strbuf_release(&effective_url);

t/lib-httpd.sh

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -131,6 +131,7 @@ prepare_httpd() {
131131
mkdir -p "$HTTPD_DOCUMENT_ROOT_PATH"
132132
cp "$TEST_PATH"/passwd "$HTTPD_ROOT_PATH"
133133
install_script broken-smart-http.sh
134+
install_script error-smart-http.sh
134135
install_script error.sh
135136
install_script apply-one-time-sed.sh
136137

t/lib-httpd/apache.conf

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -119,6 +119,7 @@ Alias /auth/dumb/ www/auth/dumb/
119119
ScriptAliasMatch /error_git_upload_pack/(.*)/git-upload-pack error.sh/
120120
ScriptAliasMatch /smart_*[^/]*/(.*) ${GIT_EXEC_PATH}/git-http-backend/$1
121121
ScriptAlias /broken_smart/ broken-smart-http.sh/
122+
ScriptAlias /error_smart/ error-smart-http.sh/
122123
ScriptAlias /error/ error.sh/
123124
ScriptAliasMatch /one_time_sed/(.*) apply-one-time-sed.sh/$1
124125
<Directory ${GIT_EXEC_PATH}>
@@ -127,6 +128,9 @@ ScriptAliasMatch /one_time_sed/(.*) apply-one-time-sed.sh/$1
127128
<Files broken-smart-http.sh>
128129
Options ExecCGI
129130
</Files>
131+
<Files error-smart-http.sh>
132+
Options ExecCGI
133+
</Files>
130134
<Files error.sh>
131135
Options ExecCGI
132136
</Files>

t/lib-httpd/error-smart-http.sh

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
echo "Content-Type: application/x-git-upload-pack-advertisement"
2+
echo
3+
printf "%s" "0019ERR server-side error"

t/t5551-http-fetch-smart.sh

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -429,5 +429,10 @@ test_expect_success 'GIT_TRACE_CURL_NO_DATA prevents data from being traced' '
429429
! grep "=> Send data" err
430430
'
431431

432+
test_expect_success 'server-side error detected' '
433+
test_must_fail git clone $HTTPD_URL/error_smart/repo.git 2>actual &&
434+
grep "server-side error" actual
435+
'
436+
432437
stop_httpd
433438
test_done

0 commit comments

Comments
 (0)