/*
* Curl_headers_push() gets passed a full HTTP header to store. It gets called
- * immediately before the header callback. The header is CRLF terminated.
+ * immediately before the header callback. The header is CRLF, CR or LF
+ * terminated.
*/
CURLcode Curl_headers_push(struct Curl_easy *data, const char *header,
+ size_t hlen, /* length of header */
unsigned char type)
{
char *value = NULL;
char *name = NULL;
- char *end;
- size_t hlen; /* length of the incoming header */
struct Curl_header_store *hs;
CURLcode result = CURLE_OUT_OF_MEMORY;
+ const size_t ilen = hlen;
if((header[0] == '\r') || (header[0] == '\n'))
/* ignore the body separator */
return CURLE_OK;
- end = strchr(header, '\r');
- if(!end) {
- end = strchr(header, '\n');
- if(!end)
- /* neither CR nor LF as terminator is not a valid header */
- return CURLE_WEIRD_SERVER_REPLY;
- }
- hlen = end - header;
+ /* trim off newline characters */
+ if(hlen && (header[hlen - 1] == '\n'))
+ hlen--;
+ if(hlen && (header[hlen - 1] == '\r'))
+ hlen--;
+ if(hlen == ilen)
+ /* neither CR nor LF as terminator is not a valid header */
+ return CURLE_WEIRD_SERVER_REPLY;
if((header[0] == ' ') || (header[0] == '\t')) {
if(data->state.prevhead)
(type & CLIENTWRITE_1XX ? CURLH_1XX :
(type & CLIENTWRITE_TRAILER ? CURLH_TRAILER :
CURLH_HEADER)));
- CURLcode result = Curl_headers_push(data, buf, htype);
+ CURLcode result = Curl_headers_push(data, buf, blen, htype);
CURL_TRC_WRITE(data, "header_collect pushed(type=%x, len=%zu) -> %d",
htype, blen, result);
if(result)
* Curl_headers_push() gets passed a full header to store.
*/
CURLcode Curl_headers_push(struct Curl_easy *data, const char *header,
- unsigned char type);
+ size_t hlen, unsigned char type);
/*
* Curl_headers_cleanup(). Free all stored headers and associated memory.
#else
#define Curl_headers_init(x) CURLE_OK
-#define Curl_headers_push(x, y, z) CURLE_OK
+#define Curl_headers_push(x,y,z,a) CURLE_OK
#define Curl_headers_cleanup(x) Curl_nop_stmt
#endif
memcmp(HTTP_PSEUDO_STATUS, name, namelen) == 0) {
/* nghttp2 guarantees :status is received first and only once. */
char buffer[32];
+ size_t hlen;
result = Curl_http_decode_status(&stream->status_code,
(const char *)value, valuelen);
if(result) {
cf_h2_header_error(cf, data_s, stream, result);
return NGHTTP2_ERR_CALLBACK_FAILURE;
}
- curl_msnprintf(buffer, sizeof(buffer), HTTP_PSEUDO_STATUS ":%u\r",
- stream->status_code);
- result = Curl_headers_push(data_s, buffer, CURLH_PSEUDO);
+ hlen = curl_msnprintf(buffer, sizeof(buffer), HTTP_PSEUDO_STATUS ":%u\r",
+ stream->status_code);
+ result = Curl_headers_push(data_s, buffer, hlen, CURLH_PSEUDO);
if(result) {
cf_h2_header_error(cf, data_s, stream, result);
return NGHTTP2_ERR_CALLBACK_FAILURE;