http: optionally extract charset parameter from content-type

Since the previous commit, we now give a sanitized, shortened version of the content-type header to any callers who ask for it. This patch adds back a way for them to cleanly access specific parameters to the type. We could easily extract all parameters and make them available via a string_list, but: 1. That complicates the interface and memory management. 2. In practice, no planned callers care about anything except the charset. This patch therefore goes with the simplest thing, and we can expand or change the interface later if it becomes necessary. Signed-off-by: Jeff King <peff@peff.net> Signed-off-by: Junio C Hamano <gitster@pobox.com>

Jeff King committed May 22, 2014 at 05:30 UTC e31316263af98c4583be39b469f3152a23eba91d
2 files changed +57 -4
http.c
+50 -4
@@ -906,6 +906,32 @@ static CURLcode curlinfo_strbuf(CURL *curl, CURLINFO info, struct strbuf *buf)
906 return ret;
907 }
908
909 +/*
910 + * Check for and extract a content-type parameter. "raw"
911 + * should be positioned at the start of the potential
912 + * parameter, with any whitespace already removed.
913 + *
914 + * "name" is the name of the parameter. The value is appended
915 + * to "out".
916 + */
917 +static int extract_param(const char *raw, const char *name,
918 + struct strbuf *out)
919 +{
920 + size_t len = strlen(name);
921 +
922 + if (strncasecmp(raw, name, len))
923 + return -1;
924 + raw += len;
925 +
926 + if (*raw != '=')
927 + return -1;
928 + raw++;
929 +
930 + while (*raw && !isspace(*raw))
931 + strbuf_addch(out, *raw++);
932 + return 0;
933 +}
934 +
935 /*
936 * Extract a normalized version of the content type, with any
937 * spaces suppressed, all letters lowercased, and no trailing ";"
@@ -916,11 +942,15 @@ static CURLcode curlinfo_strbuf(CURL *curl, CURLINFO info, struct strbuf *buf)
942 * but "text/plain" is the only reasonable output, and this keeps
943 * our code simple.
944 *
945 + * If the "charset" argument is not NULL, store the value of any
946 + * charset parameter there.
947 + *
948 * Example:
920 - * "TEXT/PLAIN; charset=utf-8" -> "text/plain"
949 + * "TEXT/PLAIN; charset=utf-8" -> "text/plain", "utf-8"
950 * "text / plain" -> "text/plain"
951 */
923 -static void extract_content_type(struct strbuf *raw, struct strbuf *type)
952 +static void extract_content_type(struct strbuf *raw, struct strbuf *type,
953 + struct strbuf *charset)
954 {
955 const char *p;
956
@@ -929,10 +959,25 @@ static void extract_content_type(struct strbuf *raw, struct strbuf *type)
959 for (p = raw->buf; *p; p++) {
960 if (isspace(*p))
961 continue;
932 - if (*p == ';')
962 + if (*p == ';') {
963 + p++;
964 break;
965 + }
966 strbuf_addch(type, tolower(*p));
967 }
968 +
969 + if (!charset)
970 + return;
971 +
972 + strbuf_reset(charset);
973 + while (*p) {
974 + while (isspace(*p))
975 + p++;
976 + if (!extract_param(p, "charset", charset))
977 + return;
978 + while (*p && !isspace(*p))
979 + p++;
980 + }
981 }
982
983 /* http_request() targets */
@@ -989,7 +1034,8 @@ static int http_request(const char *url,
1034 if (options && options->content_type) {
1035 struct strbuf raw = STRBUF_INIT;
1036 curlinfo_strbuf(slot->curl, CURLINFO_CONTENT_TYPE, &raw);
992 - extract_content_type(&raw, options->content_type);
1037 + extract_content_type(&raw, options->content_type,
1038 + options->charset);
1039 strbuf_release(&raw);
1040 }
1041
http.h
+7
@@ -143,6 +143,13 @@ struct http_get_options {
143 /* If non-NULL, returns the content-type of the response. */
144 struct strbuf *content_type;
145
146 + /*
147 + * If non-NULL, and content_type above is non-NULL, returns
148 + * the charset parameter from the content-type. If none is
149 + * present, returns an empty string.
150 + */
151 + struct strbuf *charset;
152 +
153 /*
154 * If non-NULL, returns the URL we ended up at, including any
155 * redirects we followed.