diff options
-rw-r--r-- | lib/http.c | 82 | ||||
-rw-r--r-- | lib/http.h | 2 | ||||
-rw-r--r-- | lib/transfer.c | 85 |
3 files changed, 90 insertions, 79 deletions
diff --git a/lib/http.c b/lib/http.c index c65b0cf1f..0da7156e3 100644 --- a/lib/http.c +++ b/lib/http.c @@ -181,6 +181,60 @@ static char *checkheaders(struct SessionHandle *data, const char *thisheader) } /* + * Strip off leading and trailing whitespace from the value in the + * given HTTP header line and return a strdupped copy. Returns NULL in + * case of allocation failure. Returns an empty string if the header value + * consists entirely of whitespace. + */ +char *Curl_copy_header_value(const char *h) +{ + const char *start; + const char *end; + char *value; + size_t len; + + DEBUGASSERT(h); + + /* Find the end of the header name */ + while (*h && (*h != ':')) + ++h; + + if (*h) + /* Skip over colon */ + ++h; + + /* Find the first non-space letter */ + for(start=h; + *start && ISSPACE(*start); + start++) + ; /* empty loop */ + + /* data is in the host encoding so + use '\r' and '\n' instead of 0x0d and 0x0a */ + end = strchr(start, '\r'); + if(!end) + end = strchr(start, '\n'); + if(!end) + end = strchr(start, '\0'); + + /* skip all trailing space letters */ + for(; ISSPACE(*end) && (end > start); end--) + ; /* empty loop */ + + /* get length of the type */ + len = end-start+1; + + value = malloc(len + 1); + if(!value) + return NULL; + + memcpy(value, start, len); + value[len] = 0; /* zero terminate */ + + return value; +} + +/* * http_output_basic() sets up an Authorization: header (or the proxy version) * for HTTP Basic authentication. * @@ -668,6 +722,7 @@ CURLcode Curl_http_input_auth(struct connectdata *conn, /* if exactly this is wanted, go */ int neg = Curl_input_negotiate(conn, (bool)(httpcode == 407), start); if(neg == 0) { + DEBUGASSERT(!data->req.newurl); data->req.newurl = strdup(data->change.url); data->state.authproblem = (data->req.newurl == NULL); } @@ -2094,23 +2149,18 @@ CURLcode Curl_http(struct connectdata *conn, bool *done) custom Host: header if this is NOT a redirect, as setting Host: in the redirected request is being out on thin ice. Except if the host name is the same as the first one! */ - char *start = ptr+strlen("Host:"); - while(*start && ISSPACE(*start )) - start++; - ptr = start; /* start host-scanning here */ - - /* scan through the string to find the end (space or colon) */ - while(*ptr && !ISSPACE(*ptr) && !(':'==*ptr)) - ptr++; - - if(ptr != start) { - size_t len=ptr-start; + char *cookiehost = Curl_copy_header_value(ptr); + if (!cookiehost) + return CURLE_OUT_OF_MEMORY; + if (!*cookiehost) + /* ignore empty data */ + free(cookiehost); + else { + char *colon = strchr(cookiehost, ':'); + if (colon) + *colon = 0; /* The host must not include an embedded port number */ Curl_safefree(conn->allocptr.cookiehost); - conn->allocptr.cookiehost = malloc(len+1); - if(!conn->allocptr.cookiehost) - return CURLE_OUT_OF_MEMORY; - memcpy(conn->allocptr.cookiehost, start, len); - conn->allocptr.cookiehost[len]=0; + conn->allocptr.cookiehost = cookiehost; } #endif diff --git a/lib/http.h b/lib/http.h index f41ebb6e8..5a04f8c43 100644 --- a/lib/http.h +++ b/lib/http.h @@ -35,6 +35,8 @@ bool Curl_compareheader(const char *headerline, /* line to check */ const char *header, /* header keyword _with_ colon */ const char *content); /* content string to find */ +char *Curl_copy_header_value(const char *h); + /* ftp can use this as well */ CURLcode Curl_proxyCONNECT(struct connectdata *conn, int tunnelsocket, diff --git a/lib/transfer.c b/lib/transfer.c index 4201ad18a..7f59be876 100644 --- a/lib/transfer.c +++ b/lib/transfer.c @@ -109,6 +109,7 @@ #define CURL_TIMEOUT_EXPECT_100 1000 /* counting ms here */ + /* * This function will call the read callback to fill our buffer with data * to upload. @@ -927,42 +928,17 @@ CURLcode Curl_readwrite(struct connectdata *conn, ", closing after transfer\n", contentlength); } } - /* check for Content-Type: header lines to get the mime-type */ + /* check for Content-Type: header lines to get the MIME-type */ else if(checkprefix("Content-Type:", k->p)) { - char *start; - char *end; - size_t len; - - /* Find the first non-space letter */ - for(start=k->p+13; - *start && ISSPACE(*start); - start++) - ; /* empty loop */ - - /* data is now in the host encoding so - use '\r' and '\n' instead of 0x0d and 0x0a */ - end = strchr(start, '\r'); - if(!end) - end = strchr(start, '\n'); - - if(end) { - /* skip all trailing space letters */ - for(; ISSPACE(*end) && (end > start); end--) - ; /* empty loop */ - - /* get length of the type */ - len = end-start+1; - - /* allocate memory of a cloned copy */ + char *contenttype = Curl_copy_header_value(k->p); + if (!contenttype) + return CURLE_OUT_OF_MEMORY; + if (!*contenttype) + /* ignore empty data */ + free(contenttype); + else { Curl_safefree(data->info.contenttype); - - data->info.contenttype = malloc(len + 1); - if(NULL == data->info.contenttype) - return CURLE_OUT_OF_MEMORY; - - /* copy the content-type string */ - memcpy(data->info.contenttype, start, len); - data->info.contenttype[len] = 0; /* zero terminate */ + data->info.contenttype = contenttype; } } #ifndef CURL_DISABLE_HTTP @@ -1123,36 +1099,19 @@ CURLcode Curl_readwrite(struct connectdata *conn, } else if((k->httpcode >= 300 && k->httpcode < 400) && checkprefix("Location:", k->p)) { - /* this is the URL that the server advices us to use instead */ - char *ptr; - char *start=k->p; - char backup; - - start += 9; /* pass "Location:" */ - - /* Skip spaces and tabs. We do this to support multiple - white spaces after the "Location:" keyword. */ - while(*start && ISSPACE(*start )) - start++; - - /* Scan through the string from the end to find the last - non-space. k->end_ptr points to the actual terminating zero - letter, move pointer one letter back and start from - there. This logic strips off trailing whitespace, but keeps - any embedded whitespace. */ - ptr = k->end_ptr-1; - while((ptr>=start) && ISSPACE(*ptr)) - ptr--; - ptr++; - - backup = *ptr; /* store the ending letter */ - if(ptr != start) { - *ptr = '\0'; /* zero terminate */ - data->req.location = strdup(start); /* clone string */ - *ptr = backup; /* restore ending letter */ - if(!data->req.location) - return CURLE_OUT_OF_MEMORY; + /* this is the URL that the server advises us to use instead */ + char *location = Curl_copy_header_value(k->p); + if (!location) + return CURLE_OUT_OF_MEMORY; + if (!*location) + /* ignore empty data */ + free(location); + else { + DEBUGASSERT(!data->req.location); + data->req.location = location; + if(data->set.http_follow_location) { + DEBUGASSERT(!data->req.newurl); data->req.newurl = strdup(data->req.location); /* clone */ if(!data->req.newurl) return CURLE_OUT_OF_MEMORY; |