Skip to content

Commit bf197fd

Browse files
peffgitster
authored andcommitted
http: extract type/subtype portion of content-type
When we get a content-type from curl, we get the whole header line, including any parameters, and without any normalization (like downcasing or whitespace) applied. If we later try to match it with strcmp() or even strcasecmp(), we may get false negatives. This could cause two visible behaviors: 1. We might fail to recognize a smart-http server by its content-type. 2. We might fail to relay text/plain error messages to users (especially if they contain a charset parameter). This patch teaches the http code to extract and normalize just the type/subtype portion of the string. This is technically passing out less information to the callers, who can no longer see the parameters. But none of the current callers cares, and a future patch will add back an easier-to-use method for accessing those parameters. Signed-off-by: Jeff King <[email protected]> Signed-off-by: Junio C Hamano <[email protected]>
1 parent dbcf2bd commit bf197fd

File tree

4 files changed

+48
-5
lines changed

4 files changed

+48
-5
lines changed

http.c

Lines changed: 35 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -906,6 +906,35 @@ static CURLcode curlinfo_strbuf(CURL *curl, CURLINFO info, struct strbuf *buf)
906906
return ret;
907907
}
908908

909+
/*
910+
* Extract a normalized version of the content type, with any
911+
* spaces suppressed, all letters lowercased, and no trailing ";"
912+
* or parameters.
913+
*
914+
* Note that we will silently remove even invalid whitespace. For
915+
* example, "text / plain" is specifically forbidden by RFC 2616,
916+
* but "text/plain" is the only reasonable output, and this keeps
917+
* our code simple.
918+
*
919+
* Example:
920+
* "TEXT/PLAIN; charset=utf-8" -> "text/plain"
921+
* "text / plain" -> "text/plain"
922+
*/
923+
static void extract_content_type(struct strbuf *raw, struct strbuf *type)
924+
{
925+
const char *p;
926+
927+
strbuf_reset(type);
928+
strbuf_grow(type, raw->len);
929+
for (p = raw->buf; *p; p++) {
930+
if (isspace(*p))
931+
continue;
932+
if (*p == ';')
933+
break;
934+
strbuf_addch(type, tolower(*p));
935+
}
936+
}
937+
909938
/* http_request() targets */
910939
#define HTTP_REQUEST_STRBUF 0
911940
#define HTTP_REQUEST_FILE 1
@@ -957,9 +986,12 @@ static int http_request(const char *url,
957986

958987
ret = run_one_slot(slot, &results);
959988

960-
if (options && options->content_type)
961-
curlinfo_strbuf(slot->curl, CURLINFO_CONTENT_TYPE,
962-
options->content_type);
989+
if (options && options->content_type) {
990+
struct strbuf raw = STRBUF_INIT;
991+
curlinfo_strbuf(slot->curl, CURLINFO_CONTENT_TYPE, &raw);
992+
extract_content_type(&raw, options->content_type);
993+
strbuf_release(&raw);
994+
}
963995

964996
if (options && options->effective_url)
965997
curlinfo_strbuf(slot->curl, CURLINFO_EFFECTIVE_URL,

remote-curl.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -205,7 +205,7 @@ static int show_http_message(struct strbuf *type, struct strbuf *msg)
205205
* TODO should handle "; charset=XXX", and re-encode into
206206
* logoutputencoding
207207
*/
208-
if (strcasecmp(type->buf, "text/plain"))
208+
if (strcmp(type->buf, "text/plain"))
209209
return -1;
210210

211211
strbuf_trim(msg);

t/lib-httpd/error.sh

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,15 +3,21 @@
33
printf "Status: 500 Intentional Breakage\n"
44

55
printf "Content-Type: "
6+
charset=iso-8859-1
67
case "$PATH_INFO" in
78
*html*)
89
printf "text/html"
910
;;
1011
*text*)
1112
printf "text/plain"
1213
;;
14+
*charset*)
15+
printf "text/plain; charset=utf-8"
16+
charset=utf-8
17+
;;
1318
esac
1419
printf "\n"
1520

1621
printf "\n"
17-
printf "this is the error message\n"
22+
printf "this is the error message\n" |
23+
iconv -f us-ascii -t $charset

t/t5550-http-fetch-dumb.sh

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -181,5 +181,10 @@ test_expect_success 'git client does not show html errors' '
181181
! grep "this is the error message" stderr
182182
'
183183

184+
test_expect_success 'git client shows text/plain with a charset' '
185+
test_must_fail git clone "$HTTPD_URL/error/charset" 2>stderr &&
186+
grep "this is the error message" stderr
187+
'
188+
184189
stop_httpd
185190
test_done

0 commit comments

Comments
 (0)