hashmap: add simplified hashmap_get_from_hash() API
[gitweb.git] / http.c
diff --git a/http.c b/http.c
index 6bfd0934b3cc977436f5955992918d8991270dec..3a28b219be5ecb270a6ff0422c7a4a5cdda023f0 100644 (file)
--- a/http.c
+++ b/http.c
@@ -906,6 +906,32 @@ static CURLcode curlinfo_strbuf(CURL *curl, CURLINFO info, struct strbuf *buf)
        return ret;
 }
 
+/*
+ * Check for and extract a content-type parameter. "raw"
+ * should be positioned at the start of the potential
+ * parameter, with any whitespace already removed.
+ *
+ * "name" is the name of the parameter. The value is appended
+ * to "out".
+ */
+static int extract_param(const char *raw, const char *name,
+                        struct strbuf *out)
+{
+       size_t len = strlen(name);
+
+       if (strncasecmp(raw, name, len))
+               return -1;
+       raw += len;
+
+       if (*raw != '=')
+               return -1;
+       raw++;
+
+       while (*raw && !isspace(*raw) && *raw != ';')
+               strbuf_addch(out, *raw++);
+       return 0;
+}
+
 /*
  * Extract a normalized version of the content type, with any
  * spaces suppressed, all letters lowercased, and no trailing ";"
@@ -916,11 +942,15 @@ static CURLcode curlinfo_strbuf(CURL *curl, CURLINFO info, struct strbuf *buf)
  * but "text/plain" is the only reasonable output, and this keeps
  * our code simple.
  *
+ * If the "charset" argument is not NULL, store the value of any
+ * charset parameter there.
+ *
  * Example:
- *   "TEXT/PLAIN; charset=utf-8" -> "text/plain"
+ *   "TEXT/PLAIN; charset=utf-8" -> "text/plain", "utf-8"
  *   "text / plain" -> "text/plain"
  */
-static void extract_content_type(struct strbuf *raw, struct strbuf *type)
+static void extract_content_type(struct strbuf *raw, struct strbuf *type,
+                                struct strbuf *charset)
 {
        const char *p;
 
@@ -929,10 +959,28 @@ static void extract_content_type(struct strbuf *raw, struct strbuf *type)
        for (p = raw->buf; *p; p++) {
                if (isspace(*p))
                        continue;
-               if (*p == ';')
+               if (*p == ';') {
+                       p++;
                        break;
+               }
                strbuf_addch(type, tolower(*p));
        }
+
+       if (!charset)
+               return;
+
+       strbuf_reset(charset);
+       while (*p) {
+               while (isspace(*p) || *p == ';')
+                       p++;
+               if (!extract_param(p, "charset", charset))
+                       return;
+               while (*p && !isspace(*p))
+                       p++;
+       }
+
+       if (!charset->len && starts_with(type->buf, "text/"))
+               strbuf_addstr(charset, "ISO-8859-1");
 }
 
 /* http_request() targets */
@@ -989,7 +1037,8 @@ static int http_request(const char *url,
        if (options && options->content_type) {
                struct strbuf raw = STRBUF_INIT;
                curlinfo_strbuf(slot->curl, CURLINFO_CONTENT_TYPE, &raw);
-               extract_content_type(&raw, options->content_type);
+               extract_content_type(&raw, options->content_type,
+                                    options->charset);
                strbuf_release(&raw);
        }