diff options
Diffstat (limited to 'lib')
-rw-r--r-- | lib/Makefile.inc | 4 | ||||
-rw-r--r-- | lib/curl_ntlm_wb.c | 55 | ||||
-rw-r--r-- | lib/doh.c | 92 | ||||
-rw-r--r-- | lib/doh.h | 13 | ||||
-rw-r--r-- | lib/dynbuf.c | 228 | ||||
-rw-r--r-- | lib/dynbuf.h | 61 | ||||
-rw-r--r-- | lib/easy.c | 19 | ||||
-rw-r--r-- | lib/easyif.h | 2 | ||||
-rw-r--r-- | lib/escape.c | 47 | ||||
-rw-r--r-- | lib/http.c | 626 | ||||
-rw-r--r-- | lib/http.h | 45 | ||||
-rw-r--r-- | lib/http2.c | 115 | ||||
-rw-r--r-- | lib/http2.h | 2 | ||||
-rw-r--r-- | lib/http_proxy.c | 58 | ||||
-rw-r--r-- | lib/mprintf.c | 71 | ||||
-rw-r--r-- | lib/multi.c | 2 | ||||
-rw-r--r-- | lib/rtsp.c | 83 | ||||
-rw-r--r-- | lib/sendf.c | 34 | ||||
-rw-r--r-- | lib/transfer.c | 42 | ||||
-rw-r--r-- | lib/url.c | 22 | ||||
-rw-r--r-- | lib/urldata.h | 25 |
21 files changed, 790 insertions, 856 deletions
diff --git a/lib/Makefile.inc b/lib/Makefile.inc index e3cf41891..12b2d7aa6 100644 --- a/lib/Makefile.inc +++ b/lib/Makefile.inc @@ -60,7 +60,7 @@ LIB_CFILES = altsvc.c amigaos.c asyn-ares.c asyn-thread.c base64.c \ sendf.c setopt.c sha256.c share.c slist.c smb.c smtp.c socketpair.c socks.c \ socks_gssapi.c socks_sspi.c speedcheck.c splay.c strcase.c strdup.c \ strerror.c strtok.c strtoofft.c system_win32.c telnet.c tftp.c timeval.c \ - transfer.c urlapi.c version.c warnless.c wildcard.c x509asn1.c + transfer.c urlapi.c version.c warnless.c wildcard.c x509asn1.c dynbuf.c LIB_HFILES = altsvc.h amigaos.h arpa_telnet.h asyn.h conncache.h connect.h \ content_encoding.h cookie.h curl_addrinfo.h curl_base64.h curl_ctype.h \ @@ -79,7 +79,7 @@ LIB_HFILES = altsvc.h amigaos.h arpa_telnet.h asyn.h conncache.h connect.h \ smb.h smtp.h sockaddr.h socketpair.h socks.h speedcheck.h splay.h strcase.h \ strdup.h strerror.h strtok.h strtoofft.h system_win32.h telnet.h tftp.h \ timeval.h transfer.h urlapi-int.h urldata.h warnless.h wildcard.h \ - x509asn1.h + x509asn1.h dynbuf.h LIB_RCFILES = libcurl.rc diff --git a/lib/curl_ntlm_wb.c b/lib/curl_ntlm_wb.c index f820b842e..062ac7b94 100644 --- a/lib/curl_ntlm_wb.c +++ b/lib/curl_ntlm_wb.c @@ -261,15 +261,11 @@ done: static CURLcode ntlm_wb_response(struct Curl_easy *data, struct ntlmdata *ntlm, const char *input, curlntlm state) { - char *buf = malloc(NTLM_BUFSIZE); size_t len_in = strlen(input), len_out = 0; - -#if defined(CURL_DISABLE_VERBOSE_STRINGS) - (void) data; -#endif - - if(!buf) - return CURLE_OUT_OF_MEMORY; + struct dynbuf b; + char *ptr = NULL; + unsigned char *buf = (unsigned char *)data->state.buffer; + Curl_dyn_init(&b, MAX_NTLM_WB_RESPONSE); while(len_in > 0) { ssize_t written = swrite(ntlm->ntlm_auth_hlpr_socket, input, len_in); @@ -285,10 +281,8 @@ static CURLcode ntlm_wb_response(struct Curl_easy *data, struct ntlmdata *ntlm, } /* Read one line */ while(1) { - ssize_t size; - char *newbuf; - - size = sread(ntlm->ntlm_auth_hlpr_socket, buf + len_out, NTLM_BUFSIZE); + ssize_t size = + sread(ntlm->ntlm_auth_hlpr_socket, buf, data->set.buffer_size); if(size == -1) { if(errno == EINTR) continue; @@ -297,48 +291,41 @@ static CURLcode ntlm_wb_response(struct Curl_easy *data, struct ntlmdata *ntlm, else if(size == 0) goto done; - len_out += size; - if(buf[len_out - 1] == '\n') { - buf[len_out - 1] = '\0'; - break; - } + if(Curl_dyn_addn(&b, buf, size)) + goto done; - if(len_out > MAX_NTLM_WB_RESPONSE) { - failf(data, "too large ntlm_wb response!"); - free(buf); - return CURLE_OUT_OF_MEMORY; + len_out = Curl_dyn_len(&b); + ptr = Curl_dyn_ptr(&b); + if(len_out && ptr[len_out - 1] == '\n') { + ptr[len_out - 1] = '\0'; + break; /* done! */ } - - newbuf = Curl_saferealloc(buf, len_out + NTLM_BUFSIZE); - if(!newbuf) - return CURLE_OUT_OF_MEMORY; - - buf = newbuf; + /* loop */ } /* Samba/winbind installed but not configured */ if(state == NTLMSTATE_TYPE1 && len_out == 3 && - buf[0] == 'P' && buf[1] == 'W') + ptr[0] == 'P' && ptr[1] == 'W') goto done; /* invalid response */ if(len_out < 4) goto done; if(state == NTLMSTATE_TYPE1 && - (buf[0]!='Y' || buf[1]!='R' || buf[2]!=' ')) + (ptr[0]!='Y' || ptr[1]!='R' || ptr[2]!=' ')) goto done; if(state == NTLMSTATE_TYPE2 && - (buf[0]!='K' || buf[1]!='K' || buf[2]!=' ') && - (buf[0]!='A' || buf[1]!='F' || buf[2]!=' ')) + (ptr[0]!='K' || ptr[1]!='K' || ptr[2]!=' ') && + (ptr[0]!='A' || ptr[1]!='F' || ptr[2]!=' ')) goto done; - ntlm->response = aprintf("%.*s", len_out - 4, buf + 3); - free(buf); + ntlm->response = strdup(ptr + 3); + Curl_dyn_free(&b); if(!ntlm->response) return CURLE_OUT_OF_MEMORY; return CURLE_OK; done: - free(buf); + Curl_dyn_free(&b); return CURLE_REMOTE_ACCESS_DENIED; } @@ -35,13 +35,13 @@ #include "curl_base64.h" #include "connect.h" #include "strdup.h" +#include "dynbuf.h" /* The last 3 #include files should be in this order */ #include "curl_printf.h" #include "curl_memory.h" #include "memdebug.h" #define DNS_CLASS_IN 0x01 -#define DOH_MAX_RESPONSE_SIZE 3000 /* bytes */ #ifndef CURL_DISABLE_VERBOSE_STRINGS static const char * const errors[]={ @@ -177,20 +177,11 @@ static size_t doh_write_cb(const void *contents, size_t size, size_t nmemb, void *userp) { size_t realsize = size * nmemb; - struct dohresponse *mem = (struct dohresponse *)userp; + struct dynbuf *mem = (struct dynbuf *)userp; - if((mem->size + realsize) > DOH_MAX_RESPONSE_SIZE) - /* suspiciously much for us */ + if(Curl_dyn_addn(mem, contents, realsize)) return 0; - mem->memory = Curl_saferealloc(mem->memory, mem->size + realsize); - if(!mem->memory) - /* out of memory! */ - return 0; - - memcpy(&(mem->memory[mem->size]), contents, realsize); - mem->size += realsize; - return realsize; } @@ -238,10 +229,7 @@ static CURLcode dohprobe(struct Curl_easy *data, } p->dnstype = dnstype; - p->serverdoh.memory = NULL; - /* the memory will be grown as needed by realloc in the doh_write_cb - function */ - p->serverdoh.size = 0; + Curl_dyn_init(&p->serverdoh, DYN_DOH_RESPONSE); /* Note: this is code for sending the DoH request with GET but there's still no logic that actually enables this. We should either add that ability or @@ -272,7 +260,7 @@ static CURLcode dohprobe(struct Curl_easy *data, if(!result) { /* pass in the struct pointer via a local variable to please coverity and the gcc typecheck helpers */ - struct dohresponse *resp = &p->serverdoh; + struct dynbuf *resp = &p->serverdoh; ERROR_CHECK_SETOPT(CURLOPT_URL, url); ERROR_CHECK_SETOPT(CURLOPT_WRITEFUNCTION, doh_write_cb); ERROR_CHECK_SETOPT(CURLOPT_WRITEDATA, resp); @@ -506,38 +494,12 @@ static DOHcode store_aaaa(const unsigned char *doh, return DOH_OK; } -static DOHcode cnameappend(struct cnamestore *c, - const unsigned char *src, - size_t len) -{ - if(!c->alloc) { - c->allocsize = len + 1; - c->alloc = malloc(c->allocsize); - if(!c->alloc) - return DOH_OUT_OF_MEM; - } - else if(c->allocsize < (c->allocsize + len + 1)) { - char *ptr; - c->allocsize += len + 1; - ptr = realloc(c->alloc, c->allocsize); - if(!ptr) { - free(c->alloc); - return DOH_OUT_OF_MEM; - } - c->alloc = ptr; - } - memcpy(&c->alloc[c->len], src, len); - c->len += len; - c->alloc[c->len] = 0; /* keep it zero terminated */ - return DOH_OK; -} - static DOHcode store_cname(const unsigned char *doh, size_t dohlen, unsigned int index, struct dohentry *d) { - struct cnamestore *c; + struct dynbuf *c; unsigned int loop = 128; /* a valid DNS name can never loop this much */ unsigned char length; @@ -566,18 +528,15 @@ static DOHcode store_cname(const unsigned char *doh, index++; if(length) { - DOHcode rc; - if(c->len) { - rc = cnameappend(c, (unsigned char *)".", 1); - if(rc) - return rc; + if(Curl_dyn_len(c)) { + if(Curl_dyn_add(c, ".")) + return DOH_OUT_OF_MEM; } if((index + length) > dohlen) return DOH_DNS_BAD_LABEL; - rc = cnameappend(c, &doh[index], length); - if(rc) - return rc; + if(Curl_dyn_addn(c, &doh[index], length)) + return DOH_OUT_OF_MEM; index += length; } } while(length && --loop); @@ -630,10 +589,13 @@ static DOHcode rdata(const unsigned char *doh, return DOH_OK; } -static void init_dohentry(struct dohentry *de) +UNITTEST void de_init(struct dohentry *de) { + int i; memset(de, 0, sizeof(*de)); de->ttl = INT_MAX; + for(i = 0; i < DOH_MAX_CNAME; i++) + Curl_dyn_init(&de->cname[i], DYN_DOH_CNAME); } @@ -808,7 +770,7 @@ static void showdoh(struct Curl_easy *data, } } for(i = 0; i < d->numcname; i++) { - infof(data, "CNAME: %s\n", d->cname[i].alloc); + infof(data, "CNAME: %s\n", Curl_dyn_ptr(&d->cname[i])); } } #else @@ -941,7 +903,7 @@ UNITTEST void de_cleanup(struct dohentry *d) { int i = 0; for(i = 0; i < d->numcname; i++) { - free(d->cname[i].alloc); + Curl_dyn_free(&d->cname[i]); } } @@ -959,7 +921,9 @@ CURLcode Curl_doh_is_resolved(struct connectdata *conn, CURLE_COULDNT_RESOLVE_HOST; } else if(!data->req.doh.pending) { - DOHcode rc[DOH_PROBE_SLOTS]; + DOHcode rc[DOH_PROBE_SLOTS] = { + DOH_OK, DOH_OK + }; struct dohentry de; int slot; /* remove DOH handles from multi handle and close them */ @@ -968,17 +932,19 @@ CURLcode Curl_doh_is_resolved(struct connectdata *conn, Curl_close(&data->req.doh.probe[slot].easy); } /* parse the responses, create the struct and return it! */ - init_dohentry(&de); + de_init(&de); for(slot = 0; slot < DOH_PROBE_SLOTS; slot++) { - rc[slot] = doh_decode(data->req.doh.probe[slot].serverdoh.memory, - data->req.doh.probe[slot].serverdoh.size, - data->req.doh.probe[slot].dnstype, + struct dnsprobe *p = &data->req.doh.probe[slot]; + if(!p->dnstype) + continue; + rc[slot] = doh_decode(Curl_dyn_uptr(&p->serverdoh), + Curl_dyn_len(&p->serverdoh), + p->dnstype, &de); - Curl_safefree(data->req.doh.probe[slot].serverdoh.memory); + Curl_dyn_free(&p->serverdoh); if(rc[slot]) { infof(data, "DOH: %s type %s for %s\n", doh_strerror(rc[slot]), - type2name(data->req.doh.probe[slot].dnstype), - data->req.doh.host); + type2name(p->dnstype), data->req.doh.host); } } /* next slot */ @@ -70,12 +70,6 @@ typedef enum { #define DOH_MAX_ADDR 24 #define DOH_MAX_CNAME 4 -struct cnamestore { - size_t len; /* length of cname */ - char *alloc; /* allocated pointer */ - size_t allocsize; /* allocated size */ -}; - struct dohaddr { int type; union { @@ -85,11 +79,11 @@ struct dohaddr { }; struct dohentry { - unsigned int ttl; - int numaddr; + struct dynbuf cname[DOH_MAX_CNAME]; struct dohaddr addr[DOH_MAX_ADDR]; + int numaddr; + unsigned int ttl; int numcname; - struct cnamestore cname[DOH_MAX_CNAME]; }; @@ -103,6 +97,7 @@ DOHcode doh_decode(const unsigned char *doh, size_t dohlen, DNStype dnstype, struct dohentry *d); +void de_init(struct dohentry *d); void de_cleanup(struct dohentry *d); #endif diff --git a/lib/dynbuf.c b/lib/dynbuf.c new file mode 100644 index 000000000..81e30ce94 --- /dev/null +++ b/lib/dynbuf.c @@ -0,0 +1,228 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 2020, Daniel Stenberg, <daniel@haxx.se>, et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.haxx.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ***************************************************************************/ + +#include "curl_setup.h" +#include "strdup.h" +#include "dynbuf.h" + +/* The last 3 #include files should be in this order */ +#include "curl_printf.h" +#include "curl_memory.h" +#include "memdebug.h" + +#define MIN_FIRST_ALLOC 32 + +#define DYNINIT 0xbee51da /* random pattern */ + +/* + * Init a dynbuf struct. + */ +void Curl_dyn_init(struct dynbuf *s, size_t toobig) +{ + DEBUGASSERT(s); + DEBUGASSERT(toobig); + s->bufr = NULL; + s->leng = 0; + s->allc = 0; + s->toobig = toobig; +#ifdef DEBUGBUILD + s->init = DYNINIT; +#endif +} + +/* + * free the buffer and re-init the necessary fields. It doesn't touch the + * 'init' field and thus this buffer can be reused to add data to again. + */ +void Curl_dyn_free(struct dynbuf *s) +{ + DEBUGASSERT(s); + Curl_safefree(s->bufr); + s->leng = s->allc = 0; +} + +/* + * Store/append an chunk of memory to the dynbuf. + */ +static CURLcode dyn_nappend(struct dynbuf *s, + const unsigned char *mem, size_t len) +{ + size_t indx = s->leng; + size_t a = s->allc; + size_t fit = len + indx + 1; /* new string + old string + zero byte */ + + /* try to detect if there's rubbish in the struct */ + DEBUGASSERT(s->init == DYNINIT); + DEBUGASSERT(s->toobig); + DEBUGASSERT(indx < s->toobig); + DEBUGASSERT(!s->leng || s->bufr); + + if(fit > s->toobig) { + Curl_dyn_free(s); + return CURLE_OUT_OF_MEMORY; + } + else if(!a) { + DEBUGASSERT(!indx); + /* first invoke */ + if(fit < MIN_FIRST_ALLOC) + a = MIN_FIRST_ALLOC; + else + a = fit; + } + else { + while(a < fit) + a *= 2; + } + + if(a != s->allc) { + s->bufr = Curl_saferealloc(s->bufr, a); + if(!s->bufr) { + s->leng = s->allc = 0; + return CURLE_OUT_OF_MEMORY; + } + s->allc = a; + } + + if(len) + memcpy(&s->bufr[indx], mem, len); + s->leng = indx + len; + s->bufr[s->leng] = 0; + return CURLE_OK; +} + +/* + * Clears the string, keeps the allocation. This can also be called on a + * buffer that already was freed. + */ +void Curl_dyn_reset(struct dynbuf *s) +{ + DEBUGASSERT(s); + DEBUGASSERT(s->init == DYNINIT); + DEBUGASSERT(!s->leng || s->bufr); + if(s->leng) + s->bufr[0] = 0; + s->leng = 0; +} + +#if 0 +/* + * Specify the size of the tail to keep (number of bytes from the end of the + * buffer). The rest will be dropped. + */ +CURLcode Curl_dyn_tail(struct dynbuf *s, size_t trail) +{ + DEBUGASSERT(s); + DEBUGASSERT(s->init == DYNINIT); + DEBUGASSERT(!s->leng || s->bufr); + if(trail > s->leng) + return CURLE_BAD_FUNCTION_ARGUMENT; + else if(trail == s->leng) + return CURLE_OK; + else if(!trail) { + Curl_dyn_reset(s); + } + else { + memmove(&s->bufr[0], &s->bufr[s->leng - trail], trail); + s->leng = trail; + } + return CURLE_OK; + +} + +#endif + +/* + * Appends a buffer with length. + */ +CURLcode Curl_dyn_addn(struct dynbuf *s, const void *mem, size_t len) +{ + DEBUGASSERT(s); + DEBUGASSERT(s->init == DYNINIT); + DEBUGASSERT(!s->leng || s->bufr); + return dyn_nappend(s, mem, len); +} + +/* + * Append a zero terminated string at the end. + */ +CURLcode Curl_dyn_add(struct dynbuf *s, const char *str) +{ + size_t n = strlen(str); + DEBUGASSERT(s); + DEBUGASSERT(s->init == DYNINIT); + DEBUGASSERT(!s->leng || s->bufr); + return dyn_nappend(s, (unsigned char *)str, n); +} + +/* + * Append a string printf()-style + */ +CURLcode Curl_dyn_addf(struct dynbuf *s, const char *fmt, ...) +{ + char *str; + va_list ap; + va_start(ap, fmt); + str = vaprintf(fmt, ap); /* this allocs a new string to append */ + va_end(ap); + + if(str) { + CURLcode result = dyn_nappend(s, (unsigned char *)str, strlen(str)); + free(str); + return result; + } + /* If we failed, we cleanup the whole buffer and return error */ + Curl_dyn_free(s); + return CURLE_OUT_OF_MEMORY; +} + +/* + * Returns a pointer to the buffer. + */ +char *Curl_dyn_ptr(const struct dynbuf *s) +{ + DEBUGASSERT(s); + DEBUGASSERT(s->init == DYNINIT); + DEBUGASSERT(!s->leng || s->bufr); + return s->leng ? s->bufr : (char *)""; +} + +/* + * Returns an unsigned pointer to the buffer. + */ +unsigned char *Curl_dyn_uptr(const struct dynbuf *s) +{ + DEBUGASSERT(s); + DEBUGASSERT(s->init == DYNINIT); + DEBUGASSERT(!s->leng || s->bufr); + return s->leng ? (unsigned char *)s->bufr : (unsigned char *)""; +} + +/* + * Returns the length of the buffer. + */ +size_t Curl_dyn_len(const struct dynbuf *s) +{ + DEBUGASSERT(s); + DEBUGASSERT(s->init == DYNINIT); + DEBUGASSERT(!s->leng || s->bufr); + return s->leng; +} diff --git a/lib/dynbuf.h b/lib/dynbuf.h new file mode 100644 index 000000000..96e2fce8a --- /dev/null +++ b/lib/dynbuf.h @@ -0,0 +1,61 @@ +#ifndef HEADER_CURL_DYNBUF_H +#define HEADER_CURL_DYNBUF_H +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 2020, Daniel Stenberg, <daniel@haxx.se>, et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.haxx.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ***************************************************************************/ + +struct dynbuf { + char *bufr; /* point to a zero terminated allocated buffer */ + size_t leng; /* number of bytes *EXCLUDING* the zero terminator */ + size_t allc; /* size of the current allocation */ + size_t toobig; /* size limit for the buffer */ +#ifdef DEBUGBUILD + int init; /* detect API usage mistakes */ +#endif +}; + +void Curl_dyn_init(struct dynbuf *s, size_t toobig); +void Curl_dyn_free(struct dynbuf *s); +CURLcode Curl_dyn_addn(struct dynbuf *s, const void *mem, size_t len) + WARN_UNUSED_RESULT; +CURLcode Curl_dyn_add(struct dynbuf *s, const char *str) + WARN_UNUSED_RESULT; +CURLcode Curl_dyn_addf(struct dynbuf *s, const char *fmt, ...) + WARN_UNUSED_RESULT; +void Curl_dyn_reset(struct dynbuf *s); +CURLcode Curl_dyn_tail(struct dynbuf *s, size_t trail); +char *Curl_dyn_ptr(const struct dynbuf *s); +unsigned char *Curl_dyn_uptr(const struct dynbuf *s); +size_t Curl_dyn_len(const struct dynbuf *s); + +/* Dynamic buffer max sizes */ +#define DYN_DOH_RESPONSE 3000 +#define DYN_DOH_CNAME 256 +#define DYN_PAUSE_BUFFER (64 * 1024 * 1024) +#define DYN_HAXPROXY 2048 +#define DYN_HTTP_REQUEST (128*1024) +#define DYN_H2_HEADERS (128*1024) +#define DYN_H2_TRAILERS (128*1024) +#define DYN_APRINTF 8000000 +#define DYN_RTSP_REQ_HEADER (64*1024) +#define DYN_TRAILERS (64*1024) + +#endif diff --git a/lib/easy.c b/lib/easy.c index d08c6066c..3cb3579f7 100644 --- a/lib/easy.c +++ b/lib/easy.c @@ -77,6 +77,7 @@ #include "http_digest.h" #include "system_win32.h" #include "http2.h" +#include "dynbuf.h" /* The last 3 #include files should be in this order */ #include "curl_printf.h" @@ -820,15 +821,12 @@ struct Curl_easy *curl_easy_duphandle(struct Curl_easy *data) if(!outcurl->state.buffer) goto fail; - outcurl->state.headerbuff = malloc(HEADERSIZE); - if(!outcurl->state.headerbuff) - goto fail; - outcurl->state.headersize = HEADERSIZE; - /* copy all userdefined values */ if(dupset(outcurl, data)) goto fail; + Curl_dyn_init(&outcurl->state.headerb, CURL_MAX_HTTP_HEADER); + /* the connection cache is setup on demand */ outcurl->state.conn_cache = NULL; @@ -921,7 +919,7 @@ struct Curl_easy *curl_easy_duphandle(struct Curl_easy *data) curl_slist_free_all(outcurl->change.cookielist); outcurl->change.cookielist = NULL; Curl_safefree(outcurl->state.buffer); - Curl_safefree(outcurl->state.headerbuff); + Curl_dyn_free(&outcurl->state.headerb); Curl_safefree(outcurl->change.url); Curl_safefree(outcurl->change.referer); Curl_freeset(outcurl); @@ -1040,7 +1038,7 @@ CURLcode curl_easy_pause(struct Curl_easy *data, int action) /* copy the structs to allow for immediate re-pausing */ for(i = 0; i < data->state.tempcount; i++) { writebuf[i] = data->state.tempwrite[i]; - data->state.tempwrite[i].buf = NULL; + Curl_dyn_init(&data->state.tempwrite[i].b, DYN_PAUSE_BUFFER); } data->state.tempcount = 0; @@ -1054,9 +1052,10 @@ CURLcode curl_easy_pause(struct Curl_easy *data, int action) /* even if one function returns error, this loops through and frees all buffers */ if(!result) - result = Curl_client_write(conn, writebuf[i].type, writebuf[i].buf, - writebuf[i].len); - free(writebuf[i].buf); + result = Curl_client_write(conn, writebuf[i].type, + Curl_dyn_ptr(&writebuf[i].b), + Curl_dyn_len(&writebuf[i].b)); + Curl_dyn_free(&writebuf[i].b); } /* recover previous owner of the connection */ diff --git a/lib/easyif.h b/lib/easyif.h index 8a309c55b..eda0d62e5 100644 --- a/lib/easyif.h +++ b/lib/easyif.h @@ -7,7 +7,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2019, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 1998 - 2020, Daniel Stenberg, <daniel@haxx.se>, et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms diff --git a/lib/escape.c b/lib/escape.c index 7121db31c..97352a91d 100644 --- a/lib/escape.c +++ b/lib/escape.c @@ -5,7 +5,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2018, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 1998 - 2020, Daniel Stenberg, <daniel@haxx.se>, et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -79,57 +79,42 @@ char *curl_unescape(const char *string, int length) char *curl_easy_escape(struct Curl_easy *data, const char *string, int inlength) { - size_t alloc; - char *ns; - char *testing_ptr = NULL; - size_t newlen; - size_t strindex = 0; size_t length; CURLcode result; + struct dynbuf d; if(inlength < 0) return NULL; - alloc = (inlength?(size_t)inlength:strlen(string)) + 1; - newlen = alloc; - - ns = malloc(alloc); - if(!ns) - return NULL; + Curl_dyn_init(&d, CURL_MAX_INPUT_LENGTH); - length = alloc-1; + length = (inlength?(size_t)inlength:strlen(string)); while(length--) { unsigned char in = *string; /* we need to treat the characters unsigned */ - if(Curl_isunreserved(in)) - /* just copy this */ - ns[strindex++] = in; + if(Curl_isunreserved(in)) { + /* append this */ + if(Curl_dyn_addn(&d, &in, 1)) + return NULL; + } else { /* encode it */ - newlen += 2; /* the size grows with two, since this'll become a %XX */ - if(newlen > alloc) { - alloc *= 2; - testing_ptr = Curl_saferealloc(ns, alloc); - if(!testing_ptr) - return NULL; - ns = testing_ptr; - } - + char encoded[4]; result = Curl_convert_to_network(data, (char *)&in, 1); if(result) { /* Curl_convert_to_network calls failf if unsuccessful */ - free(ns); + Curl_dyn_free(&d); return NULL; } - msnprintf(&ns[strindex], 4, "%%%02X", in); - - strindex += 3; + msnprintf(encoded, sizeof(encoded), "%%%02X", in); + if(Curl_dyn_add(&d, encoded)) + return NULL; } string++; } - ns[strindex] = 0; /* terminate it */ - return ns; + + return Curl_dyn_ptr(&d); } /* diff --git a/lib/http.c b/lib/http.c index c3f7c350c..345a78c43 100644 --- a/lib/http.c +++ b/lib/http.c @@ -1125,49 +1125,20 @@ static size_t readmoredata(char *buffer, return fullsize; } -/* ------------------------------------------------------------------------- */ -/* add_buffer functions */ - -/* - * Curl_add_buffer_init() sets up and returns a fine buffer struct - */ -Curl_send_buffer *Curl_add_buffer_init(void) -{ - return calloc(1, sizeof(Curl_send_buffer)); -} - -/* - * Curl_add_buffer_free() frees all associated resources. - */ -void Curl_add_buffer_free(Curl_send_buffer **inp) -{ - Curl_send_buffer *in; - if(!inp) - return; - in = *inp; - if(in) { /* deal with NULL input */ - free(in->buffer); - free(in); - } - *inp = NULL; -} - /* - * Curl_add_buffer_send() sends a header buffer and frees all associated + * Curl_buffer_send() sends a header buffer and frees all associated * memory. Body data may be appended to the header data if desired. * * Returns CURLcode */ -CURLcode Curl_add_buffer_send(Curl_send_buffer **inp, - struct connectdata *conn, - - /* add the number of sent bytes to this - counter */ - curl_off_t *bytes_written, - - /* how much of the buffer contains body data */ - size_t included_body_bytes, - int socketindex) +CURLcode Curl_buffer_send(struct dynbuf *in, + struct connectdata *conn, + /* add the number of sent bytes to this + counter */ + curl_off_t *bytes_written, + /* how much of the buffer contains body data */ + size_t included_body_bytes, + int socketindex) { ssize_t amount; CURLcode result; @@ -1178,7 +1149,6 @@ CURLcode Curl_add_buffer_send(Curl_send_buffer **inp, size_t sendsize; curl_socket_t sockfd; size_t headersize; - Curl_send_buffer *in = *inp; DEBUGASSERT(socketindex <= SECONDARYSOCKET); @@ -1187,8 +1157,8 @@ CURLcode Curl_add_buffer_send(Curl_send_buffer **inp, /* The looping below is required since we use non-blocking sockets, but due to the circumstances we will just loop and try again and again etc */ - ptr = in->buffer; - size = in->size_used; + ptr = Curl_dyn_ptr(in); + size = Curl_dyn_len(in); headersize = size - included_body_bytes; /* the initial part that isn't body is header */ @@ -1199,7 +1169,7 @@ CURLcode Curl_add_buffer_send(Curl_send_buffer **inp, /* Curl_convert_to_network calls failf if unsuccessful */ if(result) { /* conversion failed, free memory and return to the caller */ - Curl_add_buffer_free(inp); + Curl_dyn_free(in); return result; } @@ -1223,7 +1193,7 @@ CURLcode Curl_add_buffer_send(Curl_send_buffer **inp, result = Curl_get_upload_buffer(data); if(result) { /* malloc failed, free memory and return to the caller */ - Curl_add_buffer_free(&in); + Curl_dyn_free(in); return result; } memcpy(data->state.ulbuf, ptr, sendsize); @@ -1286,7 +1256,7 @@ CURLcode Curl_add_buffer_send(Curl_send_buffer **inp, size -= amount; - ptr = in->buffer + amount; + ptr = Curl_dyn_ptr(in) + amount; /* backup the currently set pointers */ http->backup.fread_func = data->state.fread_func; @@ -1300,7 +1270,7 @@ CURLcode Curl_add_buffer_send(Curl_send_buffer **inp, http->postdata = ptr; http->postsize = (curl_off_t)size; - http->send_buffer = in; + http->send_buffer = *in; /* copy the whole struct */ http->sending = HTTPSEND_REQUEST; return CURLE_OK; @@ -1320,87 +1290,11 @@ CURLcode Curl_add_buffer_send(Curl_send_buffer **inp, return CURLE_SEND_ERROR; } } - Curl_add_buffer_free(&in); + Curl_dyn_free(in); return result; } - -/* - * add_bufferf() add the formatted input to the buffer. - */ -CURLcode Curl_add_bufferf(Curl_send_buffer **inp, const char *fmt, ...) -{ - char *s; - va_list ap; - va_start(ap, fmt); - s = vaprintf(fmt, ap); /* this allocs a new string to append */ - va_end(ap); - - if(s) { - CURLcode result = Curl_add_buffer(inp, s, strlen(s)); - free(s); - return result; - } - /* If we failed, we cleanup the whole buffer and return error */ - Curl_add_buffer_free(inp); - return CURLE_OUT_OF_MEMORY; -} - -/* - * Curl_add_buffer() appends a memory chunk to the existing buffer - */ -CURLcode Curl_add_buffer(Curl_send_buffer **inp, const void *inptr, - size_t size) -{ - char *new_rb; - Curl_send_buffer *in = *inp; - - if(~size < in->size_used) { - /* If resulting used size of send buffer would wrap size_t, cleanup - the whole buffer and return error. Otherwise the required buffer - size will fit into a single allocatable memory chunk */ - Curl_add_buffer_free(inp); - return CURLE_OUT_OF_MEMORY; - } - - if(!in->buffer || - ((in->size_used + size) > (in->size_max - 1))) { - /* If current buffer size isn't enough to hold the result, use a - buffer size that doubles the required size. If this new size - would wrap size_t, then just use the largest possible one */ - size_t new_size; - - if((size > (size_t)-1 / 2) || (in->size_used > (size_t)-1 / 2) || - (~(size * 2) < (in->size_used * 2))) - new_size = (size_t)-1; - else - new_size = (in->size_used + size) * 2; - - if(in->buffer) - /* we have a buffer, enlarge the existing one */ - new_rb = Curl_saferealloc(in->buffer, new_size); - else - /* create a new buffer */ - new_rb = malloc(new_size); - - if(!new_rb) { - /* If we failed, we cleanup the whole buffer and return error */ - free(in); - *inp = NULL; - return CURLE_OUT_OF_MEMORY; - } - - in->buffer = new_rb; - in->size_max = new_size; - } - memcpy(&in->buffer[in->size_used], inptr, size); - - in->size_used += size; - - return CURLE_OK; -} - /* end of the add_buffer functions */ /* ------------------------------------------------------------------------- */ @@ -1525,7 +1419,7 @@ static int http_getsock_do(struct connectdata *conn, static CURLcode add_haproxy_protocol_header(struct connectdata *conn) { char proxy_header[128]; - Curl_send_buffer *req_buffer; + struct dynbuf req; CURLcode result; char tcp_version[5]; @@ -1546,19 +1440,14 @@ static CURLcode add_haproxy_protocol_header(struct connectdata *conn) conn->data->info.conn_local_port, conn->data->info.conn_primary_port); - req_buffer = Curl_add_buffer_init(); - if(!req_buffer) - return CURLE_OUT_OF_MEMORY; + Curl_dyn_init(&req, DYN_HAXPROXY); - result = Curl_add_bufferf(&req_buffer, proxy_header); + result = Curl_dyn_add(&req, proxy_header); if(result) return result; - result = Curl_add_buffer_send(&req_buffer, - conn, - &conn->data->info.request_size, - 0, - FIRSTSOCKET); + result = Curl_buffer_send(&req, conn, &conn->data->info.request_size, + 0, FIRSTSOCKET); return result; } @@ -1619,14 +1508,11 @@ CURLcode Curl_http_done(struct connectdata *conn, if(!http) return CURLE_OK; - if(http->send_buffer) { - Curl_add_buffer_free(&http->send_buffer); - } - + Curl_dyn_free(&http->send_buffer); Curl_http2_done(data, premature); Curl_quic_done(data, premature); - Curl_mime_cleanpart(&http->form); + Curl_dyn_reset(&data->state.headerb); if(status) return status; @@ -1692,7 +1578,7 @@ static const char *get_http_string(const struct Curl_easy *data, /* check and possibly add an Expect: header */ static CURLcode expect100(struct Curl_easy *data, struct connectdata *conn, - Curl_send_buffer *req_buffer) + struct dynbuf *req) { CURLcode result = CURLE_OK; data->state.expect100header = FALSE; /* default to false unless it is set @@ -1708,8 +1594,7 @@ static CURLcode expect100(struct Curl_easy *data, Curl_compareheader(ptr, "Expect:", "100-continue"); } else { - result = Curl_add_bufferf(&req_buffer, - "Expect: 100-continue\r\n"); + result = Curl_dyn_add(req, "Expect: 100-continue\r\n"); if(!result) data->state.expect100header = TRUE; } @@ -1728,7 +1613,7 @@ enum proxy_use { will return an error code if one of the headers is not formatted correctly */ CURLcode Curl_http_compile_trailers(struct curl_slist *trailers, - Curl_send_buffer **buffer, + struct dynbuf *b, struct Curl_easy *handle) { char *ptr = NULL; @@ -1754,8 +1639,10 @@ CURLcode Curl_http_compile_trailers(struct curl_slist *trailers, /* only add correctly formatted trailers */ ptr = strchr(trailers->data, ':'); if(ptr && *(ptr + 1) == ' ') { - result = Curl_add_bufferf(buffer, "%s%s", trailers->data, - endofline_native); + result = Curl_dyn_add(b, trailers->data); + if(result) + return result; + result = Curl_dyn_add(b, endofline_native); if(result) return result; } @@ -1763,14 +1650,13 @@ CURLcode Curl_http_compile_trailers(struct curl_slist *trailers, infof(handle, "Malformatted trailing header ! Skipping trailer."); trailers = trailers->next; } - result = Curl_add_buffer(buffer, endofline_network, - strlen(endofline_network)); + result = Curl_dyn_add(b, endofline_network); return result; } CURLcode Curl_add_custom_headers(struct connectdata *conn, bool is_connect, - Curl_send_buffer *req_buffer) + struct dynbuf *req) { char *ptr; struct curl_slist *h[2]; @@ -1832,7 +1718,7 @@ CURLcode Curl_add_custom_headers(struct connectdata *conn, /* copy the source */ semicolonp = strdup(headers->data); if(!semicolonp) { - Curl_add_buffer_free(&req_buffer); + Curl_dyn_free(req); return CURLE_OUT_OF_MEMORY; } /* put a colon where the semicolon is */ @@ -1893,7 +1779,7 @@ CURLcode Curl_add_custom_headers(struct connectdata *conn, !strcasecompare(data->state.first_host, conn->host.name))) ; else { - result = Curl_add_bufferf(&req_buffer, "%s\r\n", compare); + result = Curl_dyn_addf(req, "%s\r\n", compare); } if(semicolonp) free(semicolonp); @@ -1910,7 +1796,7 @@ CURLcode Curl_add_custom_headers(struct connectdata *conn, #ifndef CURL_DISABLE_PARSEDATE CURLcode Curl_add_timecondition(const struct connectdata *conn, - Curl_send_buffer *req_buffer) + struct dynbuf *req) { struct Curl_easy *data = conn->data; const struct tm *tm; @@ -1969,17 +1855,17 @@ CURLcode Curl_add_timecondition(const struct connectdata *conn, tm->tm_min, tm->tm_sec); - result = Curl_add_buffer(&req_buffer, datestr, strlen(datestr)); + result = Curl_dyn_add(req, datestr); return result; } #else /* disabled */ CURLcode Curl_add_timecondition(const struct connectdata *conn, - Curl_send_buffer *req_buffer) + struct dynbuf *req) { (void)conn; - (void)req_buffer; + (void)req; return CURLE_OK; } #endif @@ -2008,7 +1894,7 @@ CURLcode Curl_http(struct connectdata *conn, bool *done) #endif curl_off_t included_body = 0; const char *httpstring; - Curl_send_buffer *req_buffer; + struct dynbuf req; curl_off_t postsize = 0; /* curl_off_t to handle large file sizes */ char *altused = NULL; @@ -2567,14 +2453,11 @@ CURLcode Curl_http(struct connectdata *conn, bool *done) httpstring = get_http_string(data, conn); /* initialize a dynamic send-buffer */ - req_buffer = Curl_add_buffer_init(); - - if(!req_buffer) - return CURLE_OUT_OF_MEMORY; + Curl_dyn_init(&req, DYN_HTTP_REQUEST); /* add the main request stuff */ /* GET/HEAD/POST/PUT */ - result = Curl_add_bufferf(&req_buffer, "%s ", request); + result = Curl_dyn_addf(&req, "%s ", request); if(result) return result; @@ -2587,21 +2470,20 @@ CURLcode Curl_http(struct connectdata *conn, bool *done) /* url */ if(conn->bits.httpproxy && !conn->bits.tunnel_proxy) { char *url = data->set.str[STRING_TEMP_URL]; - result = Curl_add_buffer(&req_buffer, url, strlen(url)); + result = Curl_dyn_add(&req, url); Curl_safefree(data->set.str[STRING_TEMP_URL]); } else #endif if(paste_ftp_userpwd) - result = Curl_add_bufferf(&req_buffer, "ftp://%s:%s@%s", - conn->user, conn->passwd, - path + sizeof("ftp://") - 1); + result = Curl_dyn_addf(&req, "ftp://%s:%s@%s", conn->user, conn->passwd, + path + sizeof("ftp://") - 1); else { - result = Curl_add_buffer(&req_buffer, path, strlen(path)); + result = Curl_dyn_add(&req, path); if(result) return result; if(query) - result = Curl_add_bufferf(&req_buffer, "?%s", query); + result = Curl_dyn_addf(&req, "?%s", query); } if(result) return result; @@ -2611,54 +2493,54 @@ CURLcode Curl_http(struct connectdata *conn, bool *done) altused = aprintf("Alt-Used: %s:%d\r\n", conn->conn_to_host.name, conn->conn_to_port); if(!altused) { - Curl_add_buffer_free(&req_buffer); + Curl_dyn_free(&req); return CURLE_OUT_OF_MEMORY; } } #endif result = - Curl_add_bufferf(&req_buffer, - "%s" /* ftp typecode (;type=x) */ - " HTTP/%s\r\n" /* HTTP version */ - "%s" /* host */ - "%s" /* proxyuserpwd */ - "%s" /* userpwd */ - "%s" /* range */ - "%s" /* user agent */ - "%s" /* accept */ - "%s" /* TE: */ - "%s" /* accept-encoding */ - "%s" /* referer */ - "%s" /* Proxy-Connection */ - "%s" /* transfer-encoding */ - "%s",/* Alt-Used */ - - ftp_typecode, - httpstring, - (conn->allocptr.host?conn->allocptr.host:""), - conn->allocptr.proxyuserpwd? - conn->allocptr.proxyuserpwd:"", - conn->allocptr.userpwd?conn->allocptr.userpwd:"", - (data->state.use_range && conn->allocptr.rangeline)? - conn->allocptr.rangeline:"", - (data->set.str[STRING_USERAGENT] && - *data->set.str[STRING_USERAGENT] && - conn->allocptr.uagent)? - conn->allocptr.uagent:"", - http->p_accept?http->p_accept:"", - conn->allocptr.te?conn->allocptr.te:"", - (data->set.str[STRING_ENCODING] && - *data->set.str[STRING_ENCODING] && - conn->allocptr.accept_encoding)? - conn->allocptr.accept_encoding:"", - (data->change.referer && conn->allocptr.ref)? - conn->allocptr.ref:"" /* Referer: <data> */, - (conn->bits.httpproxy && - !conn->bits.tunnel_proxy && - !Curl_checkProxyheaders(conn, "Proxy-Connection"))? - "Proxy-Connection: Keep-Alive\r\n":"", - te, - altused ? altused : "" + Curl_dyn_addf(&req, + "%s" /* ftp typecode (;type=x) */ + " HTTP/%s\r\n" /* HTTP version */ + "%s" /* host */ + "%s" /* proxyuserpwd */ + "%s" /* userpwd */ + "%s" /* range */ + "%s" /* user agent */ + "%s" /* accept */ + "%s" /* TE: */ + "%s" /* accept-encoding */ + "%s" /* referer */ + "%s" /* Proxy-Connection */ + "%s" /* transfer-encoding */ + "%s",/* Alt-Used */ + + ftp_typecode, + httpstring, + (conn->allocptr.host?conn->allocptr.host:""), + conn->allocptr.proxyuserpwd? + conn->allocptr.proxyuserpwd:"", + conn->allocptr.userpwd?conn->allocptr.userpwd:"", + (data->state.use_range && conn->allocptr.rangeline)? + conn->allocptr.rangeline:"", + (data->set.str[STRING_USERAGENT] && + *data->set.str[STRING_USERAGENT] && + conn->allocptr.uagent)? + conn->allocptr.uagent:"", + http->p_accept?http->p_accept:"", + conn->allocptr.te?conn->allocptr.te:"", + (data->set.str[STRING_ENCODING] && + *data->set.str[STRING_ENCODING] && + conn->allocptr.accept_encoding)? + conn->allocptr.accept_encoding:"", + (data->change.referer && conn->allocptr.ref)? + conn->allocptr.ref:"" /* Referer: <data> */, + (conn->bits.httpproxy && + !conn->bits.tunnel_proxy && + !Curl_checkProxyheaders(conn, "Proxy-Connection"))? + "Proxy-Connection: Keep-Alive\r\n":"", + te, + altused ? altused : "" ); /* clear userpwd and proxyuserpwd to avoid re-using old credentials @@ -2675,7 +2557,7 @@ CURLcode Curl_http(struct connectdata *conn, bool *done) (data->set.httpversion == CURL_HTTP_VERSION_2)) { /* append HTTP2 upgrade magic stuff to the HTTP request if it isn't done over SSL */ - result = Curl_http2_request_upgrade(req_buffer, conn); + result = Curl_http2_request_upgrade(&req, conn); if(result) return result; } @@ -2701,13 +2583,12 @@ CURLcode Curl_http(struct connectdata *conn, bool *done) while(co) { if(co->value) { if(0 == count) { - result = Curl_add_bufferf(&req_buffer, "Cookie: "); + result = Curl_dyn_add(&req, "Cookie: "); if(result) break; } - result = Curl_add_bufferf(&req_buffer, - "%s%s=%s", count?"; ":"", - co->name, co->value); + result = Curl_dyn_addf(&req, "%s%s=%s", count?"; ":"", + co->name, co->value); if(result) break; count++; @@ -2718,26 +2599,25 @@ CURLcode Curl_http(struct connectdata *conn, bool *done) } if(addcookies && !result) { if(!count) - result = Curl_add_bufferf(&req_buffer, "Cookie: "); + result = Curl_dyn_add(&req, "Cookie: "); if(!result) { - result = Curl_add_bufferf(&req_buffer, "%s%s", count?"; ":"", - addcookies); + result = Curl_dyn_addf(&req, "%s%s", count?"; ":"", addcookies); count++; } } if(count && !result) - result = Curl_add_buffer(&req_buffer, "\r\n", 2); + result = Curl_dyn_add(&req, "\r\n"); if(result) return result; } #endif - result = Curl_add_timecondition(conn, req_buffer); + result = Curl_add_timecondition(conn, &req); if(result) return result; - result = Curl_add_custom_headers(conn, FALSE, req_buffer); + result = Curl_add_custom_headers(conn, FALSE, &req); if(result) return result; @@ -2760,20 +2640,20 @@ CURLcode Curl_http(struct connectdata *conn, bool *done) if((postsize != -1) && !data->req.upload_chunky && (conn->bits.authneg || !Curl_checkheaders(conn, "Content-Length"))) { /* only add Content-Length if not uploading chunked */ - result = Curl_add_bufferf(&req_buffer, - "Content-Length: %" CURL_FORMAT_CURL_OFF_T - "\r\n", postsize); + result = Curl_dyn_addf(&req, "Content-Length: %" CURL_FORMAT_CURL_OFF_T + "\r\n", postsize); if(result) return result; } if(postsize != 0) { - result = expect100(data, conn, req_buffer); + result = expect100(data, conn, &req); if(result) return result; } - result = Curl_add_buffer(&req_buffer, "\r\n", 2); /* end of headers */ + /* end of headers */ + result = Curl_dyn_add(&req, "\r\n"); if(result) return result; @@ -2781,8 +2661,8 @@ CURLcode Curl_http(struct connectdata *conn, bool *done) Curl_pgrsSetUploadSize(data, postsize); /* this sends the buffer and frees all the buffer resources */ - result = Curl_add_buffer_send(&req_buffer, conn, - &data->info.request_size, 0, FIRSTSOCKET); + result = Curl_buffer_send(&req, conn, &data->info.request_size, 0, + FIRSTSOCKET); if(result) failf(data, "Failed sending PUT request"); else @@ -2798,12 +2678,12 @@ CURLcode Curl_http(struct connectdata *conn, bool *done) /* This is form posting using mime data. */ if(conn->bits.authneg) { /* nothing to post! */ - result = Curl_add_bufferf(&req_buffer, "Content-Length: 0\r\n\r\n"); + result = Curl_dyn_add(&req, "Content-Length: 0\r\n\r\n"); if(result) return result; - result = Curl_add_buffer_send(&req_buffer, conn, - &data->info.request_size, 0, FIRSTSOCKET); + result = Curl_buffer_send(&req, conn, &data->info.request_size, 0, + FIRSTSOCKET); if(result) failf(data, "Failed sending POST request"); else @@ -2821,9 +2701,9 @@ CURLcode Curl_http(struct connectdata *conn, bool *done) (conn->bits.authneg || !Curl_checkheaders(conn, "Content-Length"))) { /* we allow replacing this header if not during auth negotiation, although it isn't very wise to actually set your own */ - result = Curl_add_bufferf(&req_buffer, - "Content-Length: %" CURL_FORMAT_CURL_OFF_T - "\r\n", postsize); + result = Curl_dyn_addf(&req, + "Content-Length: %" CURL_FORMAT_CURL_OFF_T + "\r\n", postsize); if(result) return result; } @@ -2834,7 +2714,7 @@ CURLcode Curl_http(struct connectdata *conn, bool *done) struct curl_slist *hdr; for(hdr = http->sendit->curlheaders; hdr; hdr = hdr->next) { - result = Curl_add_bufferf(&req_buffer, "%s\r\n", hdr->data); + result = Curl_dyn_addf(&req, "%s\r\n", hdr->data); if(result) return result; } @@ -2851,7 +2731,7 @@ CURLcode Curl_http(struct connectdata *conn, bool *done) Curl_compareheader(ptr, "Expect:", "100-continue"); } else if(postsize > EXPECT_100_THRESHOLD || postsize < 0) { - result = expect100(data, conn, req_buffer); + result = expect100(data, conn, &req); if(result) return result; } @@ -2859,7 +2739,7 @@ CURLcode Curl_http(struct connectdata *conn, bool *done) data->state.expect100header = FALSE; /* make the request end in a true CRLF */ - result = Curl_add_buffer(&req_buffer, "\r\n", 2); + result = Curl_dyn_add(&req, "\r\n"); if(result) return result; @@ -2872,8 +2752,8 @@ CURLcode Curl_http(struct connectdata *conn, bool *done) http->sending = HTTPSEND_BODY; /* this sends the buffer and frees all the buffer resources */ - result = Curl_add_buffer_send(&req_buffer, conn, - &data->info.request_size, 0, FIRSTSOCKET); + result = Curl_buffer_send(&req, conn, &data->info.request_size, 0, + FIRSTSOCKET); if(result) failf(data, "Failed sending POST request"); else @@ -2901,17 +2781,15 @@ CURLcode Curl_http(struct connectdata *conn, bool *done) (conn->bits.authneg || !Curl_checkheaders(conn, "Content-Length"))) { /* we allow replacing this header if not during auth negotiation, although it isn't very wise to actually set your own */ - result = Curl_add_bufferf(&req_buffer, - "Content-Length: %" CURL_FORMAT_CURL_OFF_T - "\r\n", postsize); + result = Curl_dyn_addf(&req, "Content-Length: %" CURL_FORMAT_CURL_OFF_T + "\r\n", postsize); if(result) return result; } if(!Curl_checkheaders(conn, "Content-Type")) { - result = Curl_add_bufferf(&req_buffer, - "Content-Type: application/" - "x-www-form-urlencoded\r\n"); + result = Curl_dyn_add(&req, "Content-Type: application/" + "x-www-form-urlencoded\r\n"); if(result) return result; } @@ -2926,7 +2804,7 @@ CURLcode Curl_http(struct connectdata *conn, bool *done) Curl_compareheader(ptr, "Expect:", "100-continue"); } else if(postsize > EXPECT_100_THRESHOLD || postsize < 0) { - result = expect100(data, conn, req_buffer); + result = expect100(data, conn, &req); if(result) return result; } @@ -2947,31 +2825,32 @@ CURLcode Curl_http(struct connectdata *conn, bool *done) is no magic limit but only set to prevent really huge POSTs to get the data duplicated with malloc() and family. */ - result = Curl_add_buffer(&req_buffer, "\r\n", 2); /* end of headers! */ + /* end of headers! */ + result = Curl_dyn_add(&req, "\r\n"); if(result) return result; if(!data->req.upload_chunky) { /* We're not sending it 'chunked', append it to the request already now to reduce the number if send() calls */ - result = Curl_add_buffer(&req_buffer, data->set.postfields, - (size_t)postsize); + result = Curl_dyn_addn(&req, data->set.postfields, + (size_t)postsize); included_body = postsize; } else { if(postsize) { /* Append the POST data chunky-style */ - result = Curl_add_bufferf(&req_buffer, "%x\r\n", (int)postsize); + result = Curl_dyn_addf(&req, "%x\r\n", (int)postsize); if(!result) { - result = Curl_add_buffer(&req_buffer, data->set.postfields, - (size_t)postsize); + result = Curl_dyn_addn(&req, data->set.postfields, + (size_t)postsize); if(!result) - result = Curl_add_buffer(&req_buffer, "\r\n", 2); + result = Curl_dyn_add(&req, "\r\n"); included_body = postsize + 2; } } if(!result) - result = Curl_add_buffer(&req_buffer, "\x30\x0d\x0a\x0d\x0a", 5); + result = Curl_dyn_add(&req, "\x30\x0d\x0a\x0d\x0a"); /* 0 CR LF CR LF */ included_body += 5; } @@ -2993,21 +2872,22 @@ CURLcode Curl_http(struct connectdata *conn, bool *done) /* set the upload size to the progress meter */ Curl_pgrsSetUploadSize(data, http->postsize); - result = Curl_add_buffer(&req_buffer, "\r\n", 2); /* end of headers! */ + /* end of headers! */ + result = Curl_dyn_add(&req, "\r\n"); if(result) return result; } } else { - result = Curl_add_buffer(&req_buffer, "\r\n", 2); /* end of headers! */ + /* end of headers! */ + result = Curl_dyn_add(&req, "\r\n"); if(result) return result; if(data->req.upload_chunky && conn->bits.authneg) { /* Chunky upload is selected and we're negotiating auth still, send end-of-data only */ - result = Curl_add_buffer(&req_buffer, - "\x30\x0d\x0a\x0d\x0a", 5); + result = Curl_dyn_add(&req, (char *)"\x30\x0d\x0a\x0d\x0a"); /* 0 CR LF CR LF */ if(result) return result; @@ -3027,8 +2907,8 @@ CURLcode Curl_http(struct connectdata *conn, bool *done) } } /* issue the request */ - result = Curl_add_buffer_send(&req_buffer, conn, &data->info.request_size, - (size_t)included_body, FIRSTSOCKET); + result = Curl_buffer_send(&req, conn, &data->info.request_size, + (size_t)included_body, FIRSTSOCKET); if(result) failf(data, "Failed sending HTTP POST request"); @@ -3038,13 +2918,13 @@ CURLcode Curl_http(struct connectdata *conn, bool *done) break; default: - result = Curl_add_buffer(&req_buffer, "\r\n", 2); + result = Curl_dyn_add(&req, "\r\n"); if(result) return result; /* issue the request */ - result = Curl_add_buffer_send(&req_buffer, conn, - &data->info.request_size, 0, FIRSTSOCKET); + result = Curl_buffer_send(&req, conn, &data->info.request_size, 0, + FIRSTSOCKET); if(result) failf(data, "Failed sending HTTP request"); @@ -3189,55 +3069,10 @@ checkprotoprefix(struct Curl_easy *data, struct connectdata *conn, return checkhttpprefix(data, s, len); } -/* - * header_append() copies a chunk of data to the end of the already received - * header. We make sure that the full string fit in the allocated header - * buffer, or else we enlarge it. - */ -static CURLcode header_append(struct Curl_easy *data, - struct SingleRequest *k, - size_t length) -{ - /* length is at most the size of a full read buffer, for which the upper - bound is CURL_MAX_READ_SIZE. There is thus no chance of overflow in this - calculation. */ - size_t newsize = k->hbuflen + length; - if(newsize > CURL_MAX_HTTP_HEADER) { - /* The reason to have a max limit for this is to avoid the risk of a bad - server feeding libcurl with a never-ending header that will cause - reallocs infinitely */ - failf(data, "Rejected %zu bytes header (max is %d)!", newsize, - CURL_MAX_HTTP_HEADER); - return CURLE_OUT_OF_MEMORY; - } - if(newsize >= data->state.headersize) { - /* We enlarge the header buffer as it is too small */ - char *newbuff; - size_t hbufp_index; - - newsize = CURLMAX((k->hbuflen + length) * 3 / 2, data->state.headersize*2); - hbufp_index = k->hbufp - data->state.headerbuff; - newbuff = realloc(data->state.headerbuff, newsize); - if(!newbuff) { - failf(data, "Failed to alloc memory for big header!"); - return CURLE_OUT_OF_MEMORY; - } - data->state.headersize = newsize; - data->state.headerbuff = newbuff; - k->hbufp = data->state.headerbuff + hbufp_index; - } - memcpy(k->hbufp, k->str_start, length); - k->hbufp += length; - k->hbuflen += length; - *k->hbufp = 0; - - return CURLE_OK; -} - static void print_http_error(struct Curl_easy *data) { struct SingleRequest *k = &data->req; - char *beg = k->p; + char *beg = Curl_dyn_ptr(&data->state.headerb); /* make sure that data->req.p points to the HTTP status line */ if(!strncmp(beg, "HTTP", 4)) { @@ -3275,14 +3110,17 @@ static void print_http_error(struct Curl_easy *data) * Read any HTTP header lines from the server and pass them to the client app. */ CURLcode Curl_http_readwrite_headers(struct Curl_easy *data, - struct connectdata *conn, - ssize_t *nread, - bool *stop_reading) + struct connectdata *conn, + ssize_t *nread, + bool *stop_reading) { CURLcode result; struct SingleRequest *k = &data->req; ssize_t onread = *nread; char *ostr = k->str; + char *headp; + char *str_start; + char *end_ptr; /* header line within buffer loop */ do { @@ -3291,22 +3129,25 @@ CURLcode Curl_http_readwrite_headers(struct Curl_easy *data, int writetype; /* str_start is start of line within buf */ - k->str_start = k->str; + str_start = k->str; /* data is in network encoding so use 0x0a instead of '\n' */ - k->end_ptr = memchr(k->str_start, 0x0a, *nread); + end_ptr = memchr(str_start, 0x0a, *nread); - if(!k->end_ptr) { + if(!end_ptr) { /* Not a complete header line within buffer, append the data to the end of the headerbuff. */ - result = header_append(data, k, *nread); + result = Curl_dyn_addn(&data->state.headerb, str_start, *nread); if(result) return result; if(!k->headerline) { /* check if this looks like a protocol header */ - statusline st = checkprotoprefix(data, conn, data->state.headerbuff, - k->hbuflen); + statusline st = + checkprotoprefix(data, conn, + Curl_dyn_ptr(&data->state.headerb), + Curl_dyn_len(&data->state.headerb)); + if(st == STATUS_BAD) { /* this is not the beginning of a protocol first header line */ k->header = FALSE; @@ -3324,28 +3165,26 @@ CURLcode Curl_http_readwrite_headers(struct Curl_easy *data, } /* decrease the size of the remaining (supposed) header line */ - rest_length = (k->end_ptr - k->str) + 1; + rest_length = (end_ptr - k->str) + 1; *nread -= (ssize_t)rest_length; - k->str = k->end_ptr + 1; /* move past new line */ + k->str = end_ptr + 1; /* move past new line */ - full_length = k->str - k->str_start; + full_length = k->str - str_start; - result = header_append(data, k, full_length); + result = Curl_dyn_addn(&data->state.headerb, str_start, full_length); if(result) return result; - k->end_ptr = k->hbufp; - k->p = data->state.headerbuff; - /**** - * We now have a FULL header line that p points to + * We now have a FULL header line in 'headerb'. *****/ if(!k->headerline) { /* the first read header */ - statusline st = checkprotoprefix(data, conn, data->state.headerbuff, - k->hbuflen); + statusline st = checkprotoprefix(data, conn, + Curl_dyn_ptr(&data->state.headerb), + Curl_dyn_len(&data->state.headerb)); if(st == STATUS_BAD) { streamclose(conn, "bad HTTP: No end-of-message indicator"); /* this is not the beginning of a protocol first header line */ @@ -3368,26 +3207,27 @@ CURLcode Curl_http_readwrite_headers(struct Curl_easy *data, } } - /* headers are in network encoding so - use 0x0a and 0x0d instead of '\n' and '\r' */ - if((0x0a == *k->p) || (0x0d == *k->p)) { + /* headers are in network encoding so use 0x0a and 0x0d instead of '\n' + and '\r' */ + headp = Curl_dyn_ptr(&data->state.headerb); + if((0x0a == *headp) || (0x0d == *headp)) { size_t headerlen; /* Zero-length header line means end of headers! */ #ifdef CURL_DOES_CONVERSIONS - if(0x0d == *k->p) { - *k->p = '\r'; /* replace with CR in host encoding */ - k->p++; /* pass the CR byte */ + if(0x0d == *headp) { + *headp = '\r'; /* replace with CR in host encoding */ + headp++; /* pass the CR byte */ } - if(0x0a == *k->p) { - *k->p = '\n'; /* replace with LF in host encoding */ - k->p++; /* pass the LF byte */ + if(0x0a == *headp) { + *headp = '\n'; /* replace with LF in host encoding */ + headp++; /* pass the LF byte */ } #else - if('\r' == *k->p) - k->p++; /* pass the \r byte */ - if('\n' == *k->p) - k->p++; /* pass the \n byte */ + if('\r' == *headp) + headp++; /* pass the \r byte */ + if('\n' == *headp) + headp++; /* pass the \n byte */ #endif /* CURL_DOES_CONVERSIONS */ if(100 <= k->httpcode && 199 >= k->httpcode) { @@ -3506,10 +3346,9 @@ CURLcode Curl_http_readwrite_headers(struct Curl_easy *data, if(data->set.include_header) writetype |= CLIENTWRITE_BODY; - headerlen = k->p - data->state.headerbuff; - + headerlen = Curl_dyn_len(&data->state.headerb); result = Curl_client_write(conn, writetype, - data->state.headerbuff, + Curl_dyn_ptr(&data->state.headerb), headerlen); if(result) return result; @@ -3662,14 +3501,12 @@ CURLcode Curl_http_readwrite_headers(struct Curl_easy *data, if(data->set.verbose) Curl_debug(data, CURLINFO_HEADER_IN, - k->str_start, headerlen); + str_start, headerlen); break; /* exit header line loop */ } - /* We continue reading headers, so reset the line-based - header parsing variables hbufp && hbuflen */ - k->hbufp = data->state.headerbuff; - k->hbuflen = 0; + /* We continue reading headers, reset the line-based header */ + Curl_dyn_reset(&data->state.headerb); continue; } @@ -3688,12 +3525,11 @@ CURLcode Curl_http_readwrite_headers(struct Curl_easy *data, #define SCRATCHSIZE 21 CURLcode res; char scratch[SCRATCHSIZE + 1]; /* "HTTP/major.minor 123" */ - /* We can't really convert this yet because we - don't know if it's the 1st header line or the body. - So we do a partial conversion into a scratch area, - leaving the data at k->p as-is. + /* We can't really convert this yet because we don't know if it's the + 1st header line or the body. So we do a partial conversion into a + scratch area, leaving the data at 'headp' as-is. */ - strncpy(&scratch[0], k->p, SCRATCHSIZE); + strncpy(&scratch[0], headp, SCRATCHSIZE); scratch[SCRATCHSIZE] = 0; /* null terminate */ res = Curl_convert_from_network(data, &scratch[0], @@ -3702,7 +3538,7 @@ CURLcode Curl_http_readwrite_headers(struct Curl_easy *data, /* Curl_convert_from_network calls failf if unsuccessful */ return res; #else -#define HEADER1 k->p /* no conversion needed, just use k->p */ +#define HEADER1 headp /* no conversion needed, just use headp */ #endif /* CURL_DOES_CONVERSIONS */ if(conn->handler->protocol & PROTO_FAMILY_HTTP) { @@ -3753,7 +3589,11 @@ CURLcode Curl_http_readwrite_headers(struct Curl_easy *data, compare header line against list of aliases */ if(!nc) { - if(checkhttpprefix(data, k->p, k->hbuflen) == STATUS_DONE) { + statusline check = + checkhttpprefix(data, + Curl_dyn_ptr(&data->state.headerb), + Curl_dyn_len(&data->state.headerb)); + if(check == STATUS_DONE) { nc = 1; k->httpcode = 200; conn->httpversion = 10; @@ -3865,16 +3705,16 @@ CURLcode Curl_http_readwrite_headers(struct Curl_easy *data, } } - result = Curl_convert_from_network(data, k->p, strlen(k->p)); + result = Curl_convert_from_network(data, headp, strlen(headp)); /* Curl_convert_from_network calls failf if unsuccessful */ if(result) return result; /* Check for Content-Length: header lines to get size */ if(!k->http_bodyless && - !data->set.ignorecl && checkprefix("Content-Length:", k->p)) { + !data->set.ignorecl && checkprefix("Content-Length:", headp)) { curl_off_t contentlength; - CURLofft offt = curlx_strtoofft(k->p + 15, NULL, 10, &contentlength); + CURLofft offt = curlx_strtoofft(headp + 15, NULL, 10, &contentlength); if(offt == CURL_OFFT_OK) { if(data->set.max_filesize && @@ -3905,8 +3745,8 @@ CURLcode Curl_http_readwrite_headers(struct Curl_easy *data, } } /* check for Content-Type: header lines to get the MIME-type */ - else if(checkprefix("Content-Type:", k->p)) { - char *contenttype = Curl_copy_header_value(k->p); + else if(checkprefix("Content-Type:", headp)) { + char *contenttype = Curl_copy_header_value(headp); if(!contenttype) return CURLE_OUT_OF_MEMORY; if(!*contenttype) @@ -3919,8 +3759,7 @@ CURLcode Curl_http_readwrite_headers(struct Curl_easy *data, } else if((conn->httpversion == 10) && conn->bits.httpproxy && - Curl_compareheader(k->p, - "Proxy-Connection:", "keep-alive")) { + Curl_compareheader(headp, "Proxy-Connection:", "keep-alive")) { /* * When a HTTP/1.0 reply comes when using a proxy, the * 'Proxy-Connection: keep-alive' line tells us the @@ -3932,8 +3771,7 @@ CURLcode Curl_http_readwrite_headers(struct Curl_easy *data, } else if((conn->httpversion == 11) && conn->bits.httpproxy && - Curl_compareheader(k->p, - "Proxy-Connection:", "close")) { + Curl_compareheader(headp, "Proxy-Connection:", "close")) { /* * We get a HTTP/1.1 response from a proxy and it says it'll * close down after this transfer. @@ -3942,7 +3780,7 @@ CURLcode Curl_http_readwrite_headers(struct Curl_easy *data, infof(data, "HTTP/1.1 proxy connection set close!\n"); } else if((conn->httpversion == 10) && - Curl_compareheader(k->p, "Connection:", "keep-alive")) { + Curl_compareheader(headp, "Connection:", "keep-alive")) { /* * A HTTP/1.0 reply with the 'Connection: keep-alive' line * tells us the connection will be kept alive for our @@ -3952,7 +3790,7 @@ CURLcode Curl_http_readwrite_headers(struct Curl_easy *data, connkeep(conn, "Connection keep-alive"); infof(data, "HTTP/1.0 connection set to keep alive!\n"); } - else if(Curl_compareheader(k->p, "Connection:", "close")) { + else if(Curl_compareheader(headp, "Connection:", "close")) { /* * [RFC 2616, section 8.1.2.1] * "Connection: close" is HTTP/1.1 language and means that @@ -3961,7 +3799,7 @@ CURLcode Curl_http_readwrite_headers(struct Curl_easy *data, */ streamclose(conn, "Connection: close used"); } - else if(!k->http_bodyless && checkprefix("Transfer-Encoding:", k->p)) { + else if(!k->http_bodyless && checkprefix("Transfer-Encoding:", headp)) { /* One or more encodings. We check for chunked and/or a compression algorithm. */ /* @@ -3973,11 +3811,11 @@ CURLcode Curl_http_readwrite_headers(struct Curl_easy *data, * of chunks, and a chunk-data set to zero signals the * end-of-chunks. */ - result = Curl_build_unencoding_stack(conn, k->p + 18, TRUE); + result = Curl_build_unencoding_stack(conn, headp + 18, TRUE); if(result) return result; } - else if(!k->http_bodyless && checkprefix("Content-Encoding:", k->p) && + else if(!k->http_bodyless && checkprefix("Content-Encoding:", headp) && data->set.str[STRING_ENCODING]) { /* * Process Content-Encoding. Look for the values: identity, @@ -3986,24 +3824,24 @@ CURLcode Curl_http_readwrite_headers(struct Curl_easy *data, * 2616). zlib cannot handle compress. However, errors are * handled further down when the response body is processed */ - result = Curl_build_unencoding_stack(conn, k->p + 17, FALSE); + result = Curl_build_unencoding_stack(conn, headp + 17, FALSE); if(result) return result; } - else if(checkprefix("Retry-After:", k->p)) { + else if(checkprefix("Retry-After:", headp)) { /* Retry-After = HTTP-date / delay-seconds */ curl_off_t retry_after = 0; /* zero for unknown or "now" */ - time_t date = Curl_getdate_capped(&k->p[12]); + time_t date = Curl_getdate_capped(&headp[12]); if(-1 == date) { /* not a date, try it as a decimal number */ - (void)curlx_strtoofft(&k->p[12], NULL, 10, &retry_after); + (void)curlx_strtoofft(&headp[12], NULL, 10, &retry_after); } else /* convert date to number of seconds into the future */ retry_after = date - time(NULL); data->info.retry_after = retry_after; /* store it */ } - else if(!k->http_bodyless && checkprefix("Content-Range:", k->p)) { + else if(!k->http_bodyless && checkprefix("Content-Range:", headp)) { /* Content-Range: bytes [num]- Content-Range: bytes: [num]- Content-Range: [num]- @@ -4015,7 +3853,7 @@ CURLcode Curl_http_readwrite_headers(struct Curl_easy *data, The forth means the requested range was unsatisfied. */ - char *ptr = k->p + 14; + char *ptr = headp + 14; /* Move forward until first digit or asterisk */ while(*ptr && !ISDIGIT(*ptr) && *ptr != '*') @@ -4034,11 +3872,11 @@ CURLcode Curl_http_readwrite_headers(struct Curl_easy *data, } #if !defined(CURL_DISABLE_COOKIES) else if(data->cookies && data->state.cookie_engine && - checkprefix("Set-Cookie:", k->p)) { + checkprefix("Set-Cookie:", headp)) { Curl_share_lock(data, CURL_LOCK_DATA_COOKIE, CURL_LOCK_ACCESS_SINGLE); Curl_cookie_add(data, - data->cookies, TRUE, FALSE, k->p + 11, + data->cookies, TRUE, FALSE, headp + 11, /* If there is a custom-set Host: name, use it here, or else use real peer host name. */ conn->allocptr.cookiehost? @@ -4049,19 +3887,19 @@ CURLcode Curl_http_readwrite_headers(struct Curl_easy *data, Curl_share_unlock(data, CURL_LOCK_DATA_COOKIE); } #endif - else if(!k->http_bodyless && checkprefix("Last-Modified:", k->p) && + else if(!k->http_bodyless && checkprefix("Last-Modified:", headp) && (data->set.timecondition || data->set.get_filetime) ) { - k->timeofdoc = Curl_getdate_capped(k->p + strlen("Last-Modified:")); + k->timeofdoc = Curl_getdate_capped(headp + strlen("Last-Modified:")); if(data->set.get_filetime) data->info.filetime = k->timeofdoc; } - else if((checkprefix("WWW-Authenticate:", k->p) && + else if((checkprefix("WWW-Authenticate:", headp) && (401 == k->httpcode)) || - (checkprefix("Proxy-authenticate:", k->p) && + (checkprefix("Proxy-authenticate:", headp) && (407 == k->httpcode))) { bool proxy = (k->httpcode == 407) ? TRUE : FALSE; - char *auth = Curl_copy_header_value(k->p); + char *auth = Curl_copy_header_value(headp); if(!auth) return CURLE_OUT_OF_MEMORY; @@ -4073,11 +3911,11 @@ CURLcode Curl_http_readwrite_headers(struct Curl_easy *data, return result; } #ifdef USE_SPNEGO - else if(checkprefix("Persistent-Auth", k->p)) { + else if(checkprefix("Persistent-Auth", headp)) { struct negotiatedata *negdata = &conn->negotiate; struct auth *authp = &data->state.authhost; if(authp->picked == CURLAUTH_NEGOTIATE) { - char *persistentauth = Curl_copy_header_value(k->p); + char *persistentauth = Curl_copy_header_value(headp); if(!persistentauth) return CURLE_OUT_OF_MEMORY; negdata->noauthpersist = checkprefix("false", persistentauth)? @@ -4090,10 +3928,10 @@ CURLcode Curl_http_readwrite_headers(struct Curl_easy *data, } #endif else if((k->httpcode >= 300 && k->httpcode < 400) && - checkprefix("Location:", k->p) && + checkprefix("Location:", headp) && !data->req.location) { /* this is the URL that the server advises us to use instead */ - char *location = Curl_copy_header_value(k->p); + char *location = Curl_copy_header_value(headp); if(!location) return CURLE_OUT_OF_MEMORY; if(!*location) @@ -4118,7 +3956,7 @@ CURLcode Curl_http_readwrite_headers(struct Curl_easy *data, } #ifdef USE_ALTSVC /* If enabled, the header is incoming and this is over HTTPS */ - else if(data->asi && checkprefix("Alt-Svc:", k->p) && + else if(data->asi && checkprefix("Alt-Svc:", headp) && ((conn->handler->flags & PROTOPT_SSL) || #ifdef CURLDEBUG /* allow debug builds to circumvent the HTTPS restriction */ @@ -4130,7 +3968,7 @@ CURLcode Curl_http_readwrite_headers(struct Curl_easy *data, /* the ALPN of the current request */ enum alpnid id = (conn->httpversion == 20) ? ALPN_h2 : ALPN_h1; result = Curl_altsvc_parse(data, data->asi, - &k->p[ strlen("Alt-Svc:") ], + &headp[ strlen("Alt-Svc:") ], id, conn->host.name, curlx_uitous(conn->remote_port)); if(result) @@ -4138,7 +3976,7 @@ CURLcode Curl_http_readwrite_headers(struct Curl_easy *data, } #endif else if(conn->handler->protocol & CURLPROTO_RTSP) { - result = Curl_rtsp_parseheader(conn, k->p); + result = Curl_rtsp_parseheader(conn, headp); if(result) return result; } @@ -4152,18 +3990,18 @@ CURLcode Curl_http_readwrite_headers(struct Curl_easy *data, writetype |= CLIENTWRITE_BODY; if(data->set.verbose) - Curl_debug(data, CURLINFO_HEADER_IN, k->p, (size_t)k->hbuflen); + Curl_debug(data, CURLINFO_HEADER_IN, headp, + Curl_dyn_len(&data->state.headerb)); - result = Curl_client_write(conn, writetype, k->p, k->hbuflen); + result = Curl_client_write(conn, writetype, headp, + Curl_dyn_len(&data->state.headerb)); if(result) return result; - data->info.header_size += (long)k->hbuflen; - data->req.headerbytecount += (long)k->hbuflen; + data->info.header_size += Curl_dyn_len(&data->state.headerb); + data->req.headerbytecount += Curl_dyn_len(&data->state.headerb); - /* reset hbufp pointer && hbuflen */ - k->hbufp = data->state.headerbuff; - k->hbuflen = 0; + Curl_dyn_reset(&data->state.headerb); } while(*k->str); /* header line within buffer */ diff --git a/lib/http.h b/lib/http.h index 4c1825f60..cc262f7d3 100644 --- a/lib/http.h +++ b/lib/http.h @@ -44,38 +44,19 @@ char *Curl_copy_header_value(const char *header); char *Curl_checkProxyheaders(const struct connectdata *conn, const char *thisheader); -/* ------------------------------------------------------------------------- */ -/* - * The add_buffer series of functions are used to build one large memory chunk - * from repeated function invokes. Used so that the entire HTTP request can - * be sent in one go. - */ -struct Curl_send_buffer { - char *buffer; - size_t size_max; - size_t size_used; -}; -typedef struct Curl_send_buffer Curl_send_buffer; - -Curl_send_buffer *Curl_add_buffer_init(void); -void Curl_add_buffer_free(Curl_send_buffer **inp); -CURLcode Curl_add_bufferf(Curl_send_buffer **inp, const char *fmt, ...) - WARN_UNUSED_RESULT; -CURLcode Curl_add_buffer(Curl_send_buffer **inp, const void *inptr, - size_t size) WARN_UNUSED_RESULT; -CURLcode Curl_add_buffer_send(Curl_send_buffer **inp, - struct connectdata *conn, - curl_off_t *bytes_written, - size_t included_body_bytes, - int socketindex); +CURLcode Curl_buffer_send(struct dynbuf *in, + struct connectdata *conn, + curl_off_t *bytes_written, + size_t included_body_bytes, + int socketindex); CURLcode Curl_add_timecondition(const struct connectdata *conn, - Curl_send_buffer *buf); + struct dynbuf *buf); CURLcode Curl_add_custom_headers(struct connectdata *conn, bool is_connect, - Curl_send_buffer *req_buffer); + struct dynbuf *req_buffer); CURLcode Curl_http_compile_trailers(struct curl_slist *trailers, - Curl_send_buffer **buffer, + struct dynbuf *buf, struct Curl_easy *handle); /* protocol-specific functions set up to be called by the main engine */ @@ -154,9 +135,9 @@ struct HTTP { } sending; #ifndef CURL_DISABLE_HTTP - Curl_send_buffer *send_buffer; /* used if the request couldn't be sent in - one chunk, points to an allocated - send_buffer struct */ + struct dynbuf send_buffer; /* used if the request couldn't be sent in one + chunk, points to an allocated send_buffer + struct */ #endif #ifdef USE_NGHTTP2 /*********** for HTTP/2 we store stream-local data here *************/ @@ -164,10 +145,10 @@ struct HTTP { bool bodystarted; /* We store non-final and final response headers here, per-stream */ - Curl_send_buffer *header_recvbuf; + struct dynbuf header_recvbuf; size_t nread_header_recvbuf; /* number of bytes in header_recvbuf fed into upper layer */ - Curl_send_buffer *trailer_recvbuf; + struct dynbuf trailer_recvbuf; int status_code; /* HTTP status code */ const uint8_t *pausedata; /* pointer to data received in on_data_chunk */ size_t pauselen; /* the number of bytes left in data */ diff --git a/lib/http2.c b/lib/http2.c index 93dfbdb7d..2ca0fdeb2 100644 --- a/lib/http2.c +++ b/lib/http2.c @@ -36,6 +36,7 @@ #include "connect.h" #include "strtoofft.h" #include "strdup.h" +#include "dynbuf.h" /* The last 3 #include files should be in this order */ #include "curl_printf.h" #include "curl_memory.h" @@ -124,8 +125,8 @@ static int http2_getsock(struct connectdata *conn, static void http2_stream_free(struct HTTP *http) { if(http) { - Curl_add_buffer_free(&http->header_recvbuf); - Curl_add_buffer_free(&http->trailer_recvbuf); + Curl_dyn_free(&http->header_recvbuf); + Curl_dyn_free(&http->trailer_recvbuf); for(; http->push_headers_used > 0; --http->push_headers_used) { free(http->push_headers[http->push_headers_used - 1]); } @@ -259,7 +260,6 @@ void Curl_http2_setup_req(struct Curl_easy *data) { struct HTTP *http = data->req.protop; - http->nread_header_recvbuf = 0; http->bodystarted = FALSE; http->status_code = -1; http->pausedata = NULL; @@ -463,15 +463,9 @@ static struct Curl_easy *duphandle(struct Curl_easy *data) } else { second->req.protop = http; - http->header_recvbuf = Curl_add_buffer_init(); - if(!http->header_recvbuf) { - free(http); - (void)Curl_close(&second); - } - else { - Curl_http2_setup_req(second); - second->state.stream_weight = data->state.stream_weight; - } + Curl_dyn_init(&http->header_recvbuf, DYN_H2_HEADERS); + Curl_http2_setup_req(second); + second->state.stream_weight = data->state.stream_weight; } } return second; @@ -668,15 +662,17 @@ static int on_frame_recv(nghttp2_session *session, const nghttp2_frame *frame, stream->status_code = -1; } - result = Curl_add_buffer(&stream->header_recvbuf, "\r\n", 2); + result = Curl_dyn_add(&stream->header_recvbuf, "\r\n"); if(result) return NGHTTP2_ERR_CALLBACK_FAILURE; - left = stream->header_recvbuf->size_used - stream->nread_header_recvbuf; + left = Curl_dyn_len(&stream->header_recvbuf) - + stream->nread_header_recvbuf; ncopy = CURLMIN(stream->len, left); memcpy(&stream->mem[stream->memlen], - stream->header_recvbuf->buffer + stream->nread_header_recvbuf, + Curl_dyn_ptr(&stream->header_recvbuf) + + stream->nread_header_recvbuf, ncopy); stream->nread_header_recvbuf += ncopy; @@ -852,12 +848,6 @@ static int on_begin_headers(nghttp2_session *session, return 0; } - if(!stream->trailer_recvbuf) { - stream->trailer_recvbuf = Curl_add_buffer_init(); - if(!stream->trailer_recvbuf) { - return NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE; - } - } return 0; } @@ -980,19 +970,19 @@ static int on_header(nghttp2_session *session, const nghttp2_frame *frame, H2BUGF(infof(data_s, "h2 trailer: %.*s: %.*s\n", namelen, name, valuelen, value)); - result = Curl_add_buffer(&stream->trailer_recvbuf, &n, sizeof(n)); + result = Curl_dyn_addn(&stream->trailer_recvbuf, &n, sizeof(n)); if(result) return NGHTTP2_ERR_CALLBACK_FAILURE; - result = Curl_add_buffer(&stream->trailer_recvbuf, name, namelen); + result = Curl_dyn_addn(&stream->trailer_recvbuf, name, namelen); if(result) return NGHTTP2_ERR_CALLBACK_FAILURE; - result = Curl_add_buffer(&stream->trailer_recvbuf, ": ", 2); + result = Curl_dyn_add(&stream->trailer_recvbuf, ": "); if(result) return NGHTTP2_ERR_CALLBACK_FAILURE; - result = Curl_add_buffer(&stream->trailer_recvbuf, value, valuelen); + result = Curl_dyn_addn(&stream->trailer_recvbuf, value, valuelen); if(result) return NGHTTP2_ERR_CALLBACK_FAILURE; - result = Curl_add_buffer(&stream->trailer_recvbuf, "\r\n\0", 3); + result = Curl_dyn_add(&stream->trailer_recvbuf, "\r\n\0"); if(result) return NGHTTP2_ERR_CALLBACK_FAILURE; @@ -1007,14 +997,14 @@ static int on_header(nghttp2_session *session, const nghttp2_frame *frame, stream->status_code = decode_status_code(value, valuelen); DEBUGASSERT(stream->status_code != -1); - result = Curl_add_buffer(&stream->header_recvbuf, "HTTP/2 ", 7); + result = Curl_dyn_add(&stream->header_recvbuf, "HTTP/2 "); if(result) return NGHTTP2_ERR_CALLBACK_FAILURE; - result = Curl_add_buffer(&stream->header_recvbuf, value, valuelen); + result = Curl_dyn_addn(&stream->header_recvbuf, value, valuelen); if(result) return NGHTTP2_ERR_CALLBACK_FAILURE; /* the space character after the status code is mandatory */ - result = Curl_add_buffer(&stream->header_recvbuf, " \r\n", 3); + result = Curl_dyn_add(&stream->header_recvbuf, " \r\n"); if(result) return NGHTTP2_ERR_CALLBACK_FAILURE; /* if we receive data for another handle, wake that up */ @@ -1029,16 +1019,16 @@ static int on_header(nghttp2_session *session, const nghttp2_frame *frame, /* nghttp2 guarantees that namelen > 0, and :status was already received, and this is not pseudo-header field . */ /* convert to a HTTP1-style header */ - result = Curl_add_buffer(&stream->header_recvbuf, name, namelen); + result = Curl_dyn_addn(&stream->header_recvbuf, name, namelen); if(result) return NGHTTP2_ERR_CALLBACK_FAILURE; - result = Curl_add_buffer(&stream->header_recvbuf, ": ", 2); + result = Curl_dyn_add(&stream->header_recvbuf, ": "); if(result) return NGHTTP2_ERR_CALLBACK_FAILURE; - result = Curl_add_buffer(&stream->header_recvbuf, value, valuelen); + result = Curl_dyn_addn(&stream->header_recvbuf, value, valuelen); if(result) return NGHTTP2_ERR_CALLBACK_FAILURE; - result = Curl_add_buffer(&stream->header_recvbuf, "\r\n", 2); + result = Curl_dyn_add(&stream->header_recvbuf, "\r\n"); if(result) return NGHTTP2_ERR_CALLBACK_FAILURE; /* if we receive data for another handle, wake that up */ @@ -1139,17 +1129,15 @@ void Curl_http2_done(struct Curl_easy *data, bool premature) /* there might be allocated resources done before this got the 'h2' pointer setup */ - if(http->header_recvbuf) { - Curl_add_buffer_free(&http->header_recvbuf); - Curl_add_buffer_free(&http->trailer_recvbuf); - if(http->push_headers) { - /* if they weren't used and then freed before */ - for(; http->push_headers_used > 0; --http->push_headers_used) { - free(http->push_headers[http->push_headers_used - 1]); - } - free(http->push_headers); - http->push_headers = NULL; + Curl_dyn_free(&http->header_recvbuf); + Curl_dyn_free(&http->trailer_recvbuf); + if(http->push_headers) { + /* if they weren't used and then freed before */ + for(; http->push_headers_used > 0; --http->push_headers_used) { + free(http->push_headers[http->push_headers_used - 1]); } + free(http->push_headers); + http->push_headers = NULL; } if(!httpc->h2) /* not HTTP/2 ? */ @@ -1238,7 +1226,7 @@ static CURLcode http2_init(struct connectdata *conn) /* * Append headers to ask for a HTTP1.1 to HTTP2 upgrade. */ -CURLcode Curl_http2_request_upgrade(Curl_send_buffer *req, +CURLcode Curl_http2_request_upgrade(struct dynbuf *req, struct connectdata *conn) { CURLcode result; @@ -1257,7 +1245,7 @@ CURLcode Curl_http2_request_upgrade(Curl_send_buffer *req, httpc->local_settings_num); if(!binlen) { failf(conn->data, "nghttp2 unexpectedly failed on pack_settings_payload"); - Curl_add_buffer_free(&req); + Curl_dyn_free(req); return CURLE_FAILED_INIT; } conn->proto.httpc.binlen = binlen; @@ -1265,15 +1253,15 @@ CURLcode Curl_http2_request_upgrade(Curl_send_buffer *req, result = Curl_base64url_encode(conn->data, (const char *)binsettings, binlen, &base64, &blen); if(result) { - Curl_add_buffer_free(&req); + Curl_dyn_free(req); return result; } - result = Curl_add_bufferf(&req, - "Connection: Upgrade, HTTP2-Settings\r\n" - "Upgrade: %s\r\n" - "HTTP2-Settings: %s\r\n", - NGHTTP2_CLEARTEXT_PROTO_VERSION_ID, base64); + result = Curl_dyn_addf(req, + "Connection: Upgrade, HTTP2-Settings\r\n" + "Upgrade: %s\r\n" + "HTTP2-Settings: %s\r\n", + NGHTTP2_CLEARTEXT_PROTO_VERSION_ID, base64); free(base64); k->upgr101 = UPGR101_REQUESTED; @@ -1432,9 +1420,9 @@ static ssize_t http2_handle_stream_close(struct connectdata *conn, return -1; } - if(stream->trailer_recvbuf && stream->trailer_recvbuf->buffer) { - trailer_pos = stream->trailer_recvbuf->buffer; - trailer_end = trailer_pos + stream->trailer_recvbuf->size_used; + if(Curl_dyn_len(&stream->trailer_recvbuf)) { + trailer_pos = Curl_dyn_ptr(&stream->trailer_recvbuf); + trailer_end = trailer_pos + Curl_dyn_len(&stream->trailer_recvbuf); for(; trailer_pos < trailer_end;) { uint32_t n; @@ -1541,13 +1529,13 @@ static ssize_t http2_recv(struct connectdata *conn, int sockindex, */ if(stream->bodystarted && - stream->nread_header_recvbuf < stream->header_recvbuf->size_used) { - /* If there is body data pending for this stream to return, do that */ + stream->nread_header_recvbuf < Curl_dyn_len(&stream->header_recvbuf)) { + /* If there is header data pending for this stream to return, do that */ size_t left = - stream->header_recvbuf->size_used - stream->nread_header_recvbuf; + Curl_dyn_len(&stream->header_recvbuf) - stream->nread_header_recvbuf; size_t ncopy = CURLMIN(len, left); - memcpy(mem, stream->header_recvbuf->buffer + stream->nread_header_recvbuf, - ncopy); + memcpy(mem, Curl_dyn_ptr(&stream->header_recvbuf) + + stream->nread_header_recvbuf, ncopy); stream->nread_header_recvbuf += ncopy; H2BUGF(infof(data, "http2_recv: Got %d bytes from header_recvbuf\n", @@ -2129,11 +2117,8 @@ CURLcode Curl_http2_setup(struct connectdata *conn) stream->stream_id = -1; - if(!stream->header_recvbuf) { - stream->header_recvbuf = Curl_add_buffer_init(); - if(!stream->header_recvbuf) - return CURLE_OUT_OF_MEMORY; - } + Curl_dyn_init(&stream->header_recvbuf, DYN_H2_HEADERS); + Curl_dyn_init(&stream->trailer_recvbuf, DYN_H2_TRAILERS); if((conn->handler == &Curl_handler_http2_ssl) || (conn->handler == &Curl_handler_http2)) @@ -2146,7 +2131,7 @@ CURLcode Curl_http2_setup(struct connectdata *conn) result = http2_init(conn); if(result) { - Curl_add_buffer_free(&stream->header_recvbuf); + Curl_dyn_free(&stream->header_recvbuf); return result; } diff --git a/lib/http2.h b/lib/http2.h index 1989aff82..e82b21280 100644 --- a/lib/http2.h +++ b/lib/http2.h @@ -42,7 +42,7 @@ const char *Curl_http2_strerror(uint32_t err); CURLcode Curl_http2_init(struct connectdata *conn); void Curl_http2_init_state(struct UrlState *state); void Curl_http2_init_userset(struct UserDefined *set); -CURLcode Curl_http2_request_upgrade(Curl_send_buffer *req, +CURLcode Curl_http2_request_upgrade(struct dynbuf *req, struct connectdata *conn); CURLcode Curl_http2_setup(struct connectdata *conn); CURLcode Curl_http2_switched(struct connectdata *conn, diff --git a/lib/http_proxy.c b/lib/http_proxy.c index 75c7a60c3..13c5da6a7 100644 --- a/lib/http_proxy.c +++ b/lib/http_proxy.c @@ -5,7 +5,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2019, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 1998 - 2020, Daniel Stenberg, <daniel@haxx.se>, et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -204,7 +204,7 @@ static CURLcode CONNECT(struct connectdata *conn, if(TUNNEL_INIT == s->tunnel_state) { /* BEGIN CONNECT PHASE */ char *host_port; - Curl_send_buffer *req_buffer; + struct dynbuf req_buffer; infof(data, "Establish HTTP proxy tunnel to %s:%d\n", hostname, remote_port); @@ -215,17 +215,12 @@ static CURLcode CONNECT(struct connectdata *conn, free(data->req.newurl); data->req.newurl = NULL; - /* initialize a dynamic send-buffer */ - req_buffer = Curl_add_buffer_init(); - - if(!req_buffer) - return CURLE_OUT_OF_MEMORY; - host_port = aprintf("%s:%d", hostname, remote_port); - if(!host_port) { - Curl_add_buffer_free(&req_buffer); + if(!host_port) return CURLE_OUT_OF_MEMORY; - } + + /* initialize a dynamic send-buffer */ + Curl_dyn_init(&req_buffer, DYN_HTTP_REQUEST); /* Setup the proxy-authorization header, if any */ result = Curl_http_output_auth(conn, "CONNECT", host_port, TRUE); @@ -248,7 +243,7 @@ static CURLcode CONNECT(struct connectdata *conn, aprintf("%s%s%s:%d", ipv6_ip?"[":"", hostname, ipv6_ip?"]":"", remote_port); if(!hostheader) { - Curl_add_buffer_free(&req_buffer); + Curl_dyn_free(&req_buffer); return CURLE_OUT_OF_MEMORY; } @@ -256,7 +251,7 @@ static CURLcode CONNECT(struct connectdata *conn, host = aprintf("Host: %s\r\n", hostheader); if(!host) { free(hostheader); - Curl_add_buffer_free(&req_buffer); + Curl_dyn_free(&req_buffer); return CURLE_OUT_OF_MEMORY; } } @@ -268,44 +263,43 @@ static CURLcode CONNECT(struct connectdata *conn, useragent = conn->allocptr.uagent; result = - Curl_add_bufferf(&req_buffer, - "CONNECT %s HTTP/%s\r\n" - "%s" /* Host: */ - "%s" /* Proxy-Authorization */ - "%s" /* User-Agent */ - "%s", /* Proxy-Connection */ - hostheader, - http, - host?host:"", - conn->allocptr.proxyuserpwd? - conn->allocptr.proxyuserpwd:"", - useragent, - proxyconn); + Curl_dyn_addf(&req_buffer, + "CONNECT %s HTTP/%s\r\n" + "%s" /* Host: */ + "%s" /* Proxy-Authorization */ + "%s" /* User-Agent */ + "%s", /* Proxy-Connection */ + hostheader, + http, + host?host:"", + conn->allocptr.proxyuserpwd? + conn->allocptr.proxyuserpwd:"", + useragent, + proxyconn); if(host) free(host); free(hostheader); if(!result) - result = Curl_add_custom_headers(conn, TRUE, req_buffer); + result = Curl_add_custom_headers(conn, TRUE, &req_buffer); if(!result) /* CRLF terminate the request */ - result = Curl_add_bufferf(&req_buffer, "\r\n"); + result = Curl_dyn_addf(&req_buffer, "\r\n"); if(!result) { /* Send the connect request to the proxy */ /* BLOCKING */ result = - Curl_add_buffer_send(&req_buffer, conn, - &data->info.request_size, 0, sockindex); + Curl_buffer_send(&req_buffer, conn, + &data->info.request_size, 0, sockindex); } - req_buffer = NULL; if(result) failf(data, "Failed sending CONNECT to proxy"); } - Curl_add_buffer_free(&req_buffer); + Curl_dyn_free(&req_buffer); if(result) return result; diff --git a/lib/mprintf.c b/lib/mprintf.c index bc0091351..d6d836c02 100644 --- a/lib/mprintf.c +++ b/lib/mprintf.c @@ -5,7 +5,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1999 - 2019, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 1999 - 2020, Daniel Stenberg, <daniel@haxx.se>, et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -36,6 +36,7 @@ */ #include "curl_setup.h" +#include "dynbuf.h" #include <curl/mprintf.h> #include "curl_memory.h" @@ -168,11 +169,9 @@ struct nsprintf { }; struct asprintf { - char *buffer; /* allocated buffer */ - size_t len; /* length of string */ - size_t alloc; /* length of alloc */ - int fail; /* (!= 0) if an alloc has failed and thus - the output is not the complete data */ + struct dynbuf b; + bool fail; /* if an alloc has failed and thus the output is not the complete + data */ }; static long dprintf_DollarString(char *input, char **end) @@ -1031,35 +1030,10 @@ static int alloc_addbyter(int output, FILE *data) struct asprintf *infop = (struct asprintf *)data; unsigned char outc = (unsigned char)output; - if(!infop->buffer) { - infop->buffer = malloc(32); - if(!infop->buffer) { - infop->fail = 1; - return -1; /* fail */ - } - infop->alloc = 32; - infop->len = 0; + if(Curl_dyn_addn(&infop->b, &outc, 1)) { + infop->fail = 1; + return -1; /* fail */ } - else if(infop->len + 1 >= infop->alloc) { - char *newptr = NULL; - size_t newsize = infop->alloc*2; - - /* detect wrap-around or other overflow problems */ - if(newsize > infop->alloc) - newptr = realloc(infop->buffer, newsize); - - if(!newptr) { - infop->fail = 1; - return -1; /* fail */ - } - infop->buffer = newptr; - infop->alloc = newsize; - } - - infop->buffer[ infop->len ] = outc; - - infop->len++; - return outc; /* fputc() returns like this on success */ } @@ -1068,24 +1042,18 @@ char *curl_maprintf(const char *format, ...) va_list ap_save; /* argument pointer */ int retcode; struct asprintf info; - - info.buffer = NULL; - info.len = 0; - info.alloc = 0; + Curl_dyn_init(&info.b, DYN_APRINTF); info.fail = 0; va_start(ap_save, format); retcode = dprintf_formatf(&info, alloc_addbyter, format, ap_save); va_end(ap_save); if((-1 == retcode) || info.fail) { - if(info.alloc) - free(info.buffer); + Curl_dyn_free(&info.b); return NULL; } - if(info.alloc) { - info.buffer[info.len] = 0; /* we terminate this with a zero byte */ - return info.buffer; - } + if(Curl_dyn_len(&info.b)) + return Curl_dyn_ptr(&info.b); return strdup(""); } @@ -1093,23 +1061,16 @@ char *curl_mvaprintf(const char *format, va_list ap_save) { int retcode; struct asprintf info; - - info.buffer = NULL; - info.len = 0; - info.alloc = 0; + Curl_dyn_init(&info.b, DYN_APRINTF); info.fail = 0; retcode = dprintf_formatf(&info, alloc_addbyter, format, ap_save); if((-1 == retcode) || info.fail) { - if(info.alloc) - free(info.buffer); + Curl_dyn_free(&info.b); return NULL; } - - if(info.alloc) { - info.buffer[info.len] = 0; /* we terminate this with a zero byte */ - return info.buffer; - } + if(Curl_dyn_len(&info.b)) + return Curl_dyn_ptr(&info.b); return strdup(""); } diff --git a/lib/multi.c b/lib/multi.c index b77a9a0ee..75b0357c3 100644 --- a/lib/multi.c +++ b/lib/multi.c @@ -616,7 +616,7 @@ static CURLcode multi_done(struct Curl_easy *data, /* if the transfer was completed in a paused state there can be buffered data left to free */ for(i = 0; i < data->state.tempcount; i++) { - free(data->state.tempwrite[i].buf); + Curl_dyn_free(&data->state.tempwrite[i].b); } data->state.tempcount = 0; diff --git a/lib/rtsp.c b/lib/rtsp.c index bba4c16a1..9c86b6171 100644 --- a/lib/rtsp.c +++ b/lib/rtsp.c @@ -5,7 +5,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2019, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 1998 - 2020, Daniel Stenberg, <daniel@haxx.se>, et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -233,7 +233,7 @@ static CURLcode rtsp_do(struct connectdata *conn, bool *done) CURLcode result = CURLE_OK; Curl_RtspReq rtspreq = data->set.rtspreq; struct RTSP *rtsp = data->req.protop; - Curl_send_buffer *req_buffer; + struct dynbuf req_buffer; curl_off_t postsize = 0; /* for ANNOUNCE and SET_PARAMETER */ curl_off_t putsize = 0; /* for ANNOUNCE and SET_PARAMETER */ @@ -430,16 +430,13 @@ static CURLcode rtsp_do(struct connectdata *conn, bool *done) } /* Initialize a dynamic send buffer */ - req_buffer = Curl_add_buffer_init(); - - if(!req_buffer) - return CURLE_OUT_OF_MEMORY; + Curl_dyn_init(&req_buffer, DYN_RTSP_REQ_HEADER); result = - Curl_add_bufferf(&req_buffer, - "%s %s RTSP/1.0\r\n" /* Request Stream-URI RTSP/1.0 */ - "CSeq: %ld\r\n", /* CSeq */ - p_request, p_stream_uri, rtsp->CSeq_sent); + Curl_dyn_addf(&req_buffer, + "%s %s RTSP/1.0\r\n" /* Request Stream-URI RTSP/1.0 */ + "CSeq: %ld\r\n", /* CSeq */ + p_request, p_stream_uri, rtsp->CSeq_sent); if(result) return result; @@ -448,7 +445,7 @@ static CURLcode rtsp_do(struct connectdata *conn, bool *done) * to make comparison easier */ if(p_session_id) { - result = Curl_add_bufferf(&req_buffer, "Session: %s\r\n", p_session_id); + result = Curl_dyn_addf(&req_buffer, "Session: %s\r\n", p_session_id); if(result) return result; } @@ -456,24 +453,24 @@ static CURLcode rtsp_do(struct connectdata *conn, bool *done) /* * Shared HTTP-like options */ - result = Curl_add_bufferf(&req_buffer, - "%s" /* transport */ - "%s" /* accept */ - "%s" /* accept-encoding */ - "%s" /* range */ - "%s" /* referrer */ - "%s" /* user-agent */ - "%s" /* proxyuserpwd */ - "%s" /* userpwd */ - , - p_transport ? p_transport : "", - p_accept ? p_accept : "", - p_accept_encoding ? p_accept_encoding : "", - p_range ? p_range : "", - p_referrer ? p_referrer : "", - p_uagent ? p_uagent : "", - p_proxyuserpwd ? p_proxyuserpwd : "", - p_userpwd ? p_userpwd : ""); + result = Curl_dyn_addf(&req_buffer, + "%s" /* transport */ + "%s" /* accept */ + "%s" /* accept-encoding */ + "%s" /* range */ + "%s" /* referrer */ + "%s" /* user-agent */ + "%s" /* proxyuserpwd */ + "%s" /* userpwd */ + , + p_transport ? p_transport : "", + p_accept ? p_accept : "", + p_accept_encoding ? p_accept_encoding : "", + p_range ? p_range : "", + p_referrer ? p_referrer : "", + p_uagent ? p_uagent : "", + p_proxyuserpwd ? p_proxyuserpwd : "", + p_userpwd ? p_userpwd : ""); /* * Free userpwd now --- cannot reuse this for Negotiate and possibly NTLM @@ -486,12 +483,12 @@ static CURLcode rtsp_do(struct connectdata *conn, bool *done) return result; if((rtspreq == RTSPREQ_SETUP) || (rtspreq == RTSPREQ_DESCRIBE)) { - result = Curl_add_timecondition(conn, req_buffer); + result = Curl_add_timecondition(conn, &req_buffer); if(result) return result; } - result = Curl_add_custom_headers(conn, FALSE, req_buffer); + result = Curl_add_custom_headers(conn, FALSE, &req_buffer); if(result) return result; @@ -516,9 +513,9 @@ static CURLcode rtsp_do(struct connectdata *conn, bool *done) * actually set a custom Content-Length in the headers */ if(!Curl_checkheaders(conn, "Content-Length")) { result = - Curl_add_bufferf(&req_buffer, - "Content-Length: %" CURL_FORMAT_CURL_OFF_T"\r\n", - (data->set.upload ? putsize : postsize)); + Curl_dyn_addf(&req_buffer, + "Content-Length: %" CURL_FORMAT_CURL_OFF_T"\r\n", + (data->set.upload ? putsize : postsize)); if(result) return result; } @@ -526,8 +523,8 @@ static CURLcode rtsp_do(struct connectdata *conn, bool *done) if(rtspreq == RTSPREQ_SET_PARAMETER || rtspreq == RTSPREQ_GET_PARAMETER) { if(!Curl_checkheaders(conn, "Content-Type")) { - result = Curl_add_bufferf(&req_buffer, - "Content-Type: text/parameters\r\n"); + result = Curl_dyn_addf(&req_buffer, + "Content-Type: text/parameters\r\n"); if(result) return result; } @@ -535,8 +532,8 @@ static CURLcode rtsp_do(struct connectdata *conn, bool *done) if(rtspreq == RTSPREQ_ANNOUNCE) { if(!Curl_checkheaders(conn, "Content-Type")) { - result = Curl_add_bufferf(&req_buffer, - "Content-Type: application/sdp\r\n"); + result = Curl_dyn_addf(&req_buffer, + "Content-Type: application/sdp\r\n"); if(result) return result; } @@ -554,20 +551,20 @@ static CURLcode rtsp_do(struct connectdata *conn, bool *done) /* RTSP never allows chunked transfer */ data->req.forbidchunk = TRUE; /* Finish the request buffer */ - result = Curl_add_buffer(&req_buffer, "\r\n", 2); + result = Curl_dyn_add(&req_buffer, "\r\n"); if(result) return result; if(postsize > 0) { - result = Curl_add_buffer(&req_buffer, data->set.postfields, - (size_t)postsize); + result = Curl_dyn_addn(&req_buffer, data->set.postfields, + (size_t)postsize); if(result) return result; } /* issue the request */ - result = Curl_add_buffer_send(&req_buffer, conn, - &data->info.request_size, 0, FIRSTSOCKET); + result = Curl_buffer_send(&req_buffer, conn, + &data->info.request_size, 0, FIRSTSOCKET); if(result) { failf(data, "Failed sending RTSP request"); return result; diff --git a/lib/sendf.c b/lib/sendf.c index 6ef47aa80..6ad32e1b3 100644 --- a/lib/sendf.c +++ b/lib/sendf.c @@ -498,7 +498,6 @@ static CURLcode pausewrite(struct Curl_easy *data, is again enabled */ struct SingleRequest *k = &data->req; struct UrlState *s = &data->state; - char *dupl; unsigned int i; bool newtype = TRUE; @@ -518,44 +517,21 @@ static CURLcode pausewrite(struct Curl_easy *data, else i = 0; - if(!newtype) { - /* append new data to old data */ - - /* figure out the new size of the data to save */ - size_t newlen = len + s->tempwrite[i].len; - /* allocate the new memory area */ - char *newptr = realloc(s->tempwrite[i].buf, newlen); - if(!newptr) - return CURLE_OUT_OF_MEMORY; - /* copy the new data to the end of the new area */ - memcpy(newptr + s->tempwrite[i].len, ptr, len); - - /* update the pointer and the size */ - s->tempwrite[i].buf = newptr; - s->tempwrite[i].len = newlen; - - len = newlen; /* for the debug output below */ - } - else { - dupl = Curl_memdup(ptr, len); - if(!dupl) - return CURLE_OUT_OF_MEMORY; - + if(newtype) { /* store this information in the state struct for later use */ - s->tempwrite[i].buf = dupl; - s->tempwrite[i].len = len; + Curl_dyn_init(&s->tempwrite[i].b, DYN_PAUSE_BUFFER); s->tempwrite[i].type = type; if(newtype) s->tempcount++; } + if(Curl_dyn_addn(&s->tempwrite[i].b, (unsigned char *)ptr, len)) + return CURLE_OUT_OF_MEMORY; + /* mark the connection as RECV paused */ k->keepon |= KEEP_RECV_PAUSE; - DEBUGF(infof(data, "Paused %zu bytes in buffer for type %02x\n", - len, type)); - return CURLE_OK; } diff --git a/lib/transfer.c b/lib/transfer.c index b9581d7ad..cc13bae18 100644 --- a/lib/transfer.c +++ b/lib/transfer.c @@ -128,12 +128,13 @@ static size_t Curl_trailers_read(char *buffer, size_t size, size_t nitems, void *raw) { struct Curl_easy *data = (struct Curl_easy *)raw; - Curl_send_buffer *trailers_buf = data->state.trailers_buf; - size_t bytes_left = trailers_buf->size_used-data->state.trailers_bytes_sent; + struct dynbuf *trailers_buf = &data->state.trailers_buf; + size_t bytes_left = Curl_dyn_len(trailers_buf) - + data->state.trailers_bytes_sent; size_t to_copy = (size*nitems < bytes_left) ? size*nitems : bytes_left; if(to_copy) { memcpy(buffer, - &trailers_buf->buffer[data->state.trailers_bytes_sent], + Curl_dyn_ptr(trailers_buf) + data->state.trailers_bytes_sent, to_copy); data->state.trailers_bytes_sent += to_copy; } @@ -143,8 +144,8 @@ static size_t Curl_trailers_read(char *buffer, size_t size, size_t nitems, static size_t Curl_trailers_left(void *raw) { struct Curl_easy *data = (struct Curl_easy *)raw; - Curl_send_buffer *trailers_buf = data->state.trailers_buf; - return trailers_buf->size_used - data->state.trailers_bytes_sent; + struct dynbuf *trailers_buf = &data->state.trailers_buf; + return Curl_dyn_len(trailers_buf) - data->state.trailers_bytes_sent; } #endif @@ -186,11 +187,8 @@ CURLcode Curl_fillreadbuffer(struct connectdata *conn, size_t bytes, infof(data, "Moving trailers state machine from initialized to sending.\n"); data->state.trailers_state = TRAILERS_SENDING; - data->state.trailers_buf = Curl_add_buffer_init(); - if(!data->state.trailers_buf) { - failf(data, "Unable to allocate trailing headers buffer !"); - return CURLE_OUT_OF_MEMORY; - } + Curl_dyn_init(&data->state.trailers_buf, DYN_TRAILERS); + data->state.trailers_bytes_sent = 0; Curl_set_in_callback(data, true); trailers_ret_code = data->set.trailer_callback(&trailers, @@ -206,7 +204,7 @@ CURLcode Curl_fillreadbuffer(struct connectdata *conn, size_t bytes, result = CURLE_ABORTED_BY_CALLBACK; } if(result) { - Curl_add_buffer_free(&data->state.trailers_buf); + Curl_dyn_free(&data->state.trailers_buf); curl_slist_free_all(trailers); return result; } @@ -369,7 +367,7 @@ CURLcode Curl_fillreadbuffer(struct connectdata *conn, size_t bytes, #ifndef CURL_DISABLE_HTTP if(data->state.trailers_state == TRAILERS_SENDING && !Curl_trailers_left(data)) { - Curl_add_buffer_free(&data->state.trailers_buf); + Curl_dyn_free(&data->state.trailers_buf); data->state.trailers_state = TRAILERS_DONE; data->set.trailer_data = NULL; data->set.trailer_callback = NULL; @@ -770,8 +768,9 @@ static CURLcode readwrite_data(struct Curl_easy *data, /* pass data to the debug function before it gets "dechunked" */ if(data->set.verbose) { if(k->badheader) { - Curl_debug(data, CURLINFO_DATA_IN, data->state.headerbuff, - (size_t)k->hbuflen); + Curl_debug(data, CURLINFO_DATA_IN, + Curl_dyn_ptr(&data->state.headerb), + Curl_dyn_len(&data->state.headerb)); if(k->badheader == HEADER_PARTHEADER) Curl_debug(data, CURLINFO_DATA_IN, k->str, (size_t)nread); @@ -822,9 +821,9 @@ static CURLcode readwrite_data(struct Curl_easy *data, /* Account for body content stored in the header buffer */ if((k->badheader == HEADER_PARTHEADER) && !k->ignorebody) { - DEBUGF(infof(data, "Increasing bytecount by %zu from hbuflen\n", - k->hbuflen)); - k->bytecount += k->hbuflen; + size_t headlen = Curl_dyn_len(&data->state.headerb); + DEBUGF(infof(data, "Increasing bytecount by %zu\n", headlen)); + k->bytecount += headlen; } if((-1 != k->maxdownload) && @@ -858,15 +857,16 @@ static CURLcode readwrite_data(struct Curl_easy *data, if(k->badheader && !k->ignorebody) { /* we parsed a piece of data wrongly assuming it was a header and now we output it as body instead */ + size_t headlen = Curl_dyn_len(&data->state.headerb); /* Don't let excess data pollute body writes */ - if(k->maxdownload == -1 || (curl_off_t)k->hbuflen <= k->maxdownload) + if(k->maxdownload == -1 || (curl_off_t)headlen <= k->maxdownload) result = Curl_client_write(conn, CLIENTWRITE_BODY, - data->state.headerbuff, - k->hbuflen); + Curl_dyn_ptr(&data->state.headerb), + headlen); else result = Curl_client_write(conn, CLIENTWRITE_BODY, - data->state.headerbuff, + Curl_dyn_ptr(&data->state.headerb), (size_t)k->maxdownload); if(result) @@ -122,6 +122,7 @@ bool curl_win32_idn_to_ascii(const char *in, char **out); #include "strdup.h" #include "setopt.h" #include "altsvc.h" +#include "dynbuf.h" /* The last 3 #include files should be in this order */ #include "curl_printf.h" @@ -380,7 +381,7 @@ CURLcode Curl_close(struct Curl_easy **datap) up_free(data); Curl_safefree(data->state.buffer); - Curl_safefree(data->state.headerbuff); + Curl_dyn_free(&data->state.headerb); Curl_safefree(data->state.ulbuf); Curl_flush_cookies(data, TRUE); #ifdef USE_ALTSVC @@ -408,8 +409,8 @@ CURLcode Curl_close(struct Curl_easy **datap) } #ifndef CURL_DISABLE_DOH - free(data->req.doh.probe[0].serverdoh.memory); - free(data->req.doh.probe[1].serverdoh.memory); + Curl_dyn_free(&data->req.doh.probe[0].serverdoh); + Curl_dyn_free(&data->req.doh.probe[1].serverdoh); curl_slist_free_all(data->req.doh.headers); #endif @@ -609,15 +610,9 @@ CURLcode Curl_open(struct Curl_easy **curl) result = CURLE_OUT_OF_MEMORY; } else { - data->state.headerbuff = malloc(HEADERSIZE); - if(!data->state.headerbuff) { - DEBUGF(fprintf(stderr, "Error: malloc of headerbuff failed\n")); - result = CURLE_OUT_OF_MEMORY; - } - else { - result = Curl_init_userdefined(data); - - data->state.headersize = HEADERSIZE; + result = Curl_init_userdefined(data); + if(!result) { + Curl_dyn_init(&data->state.headerb, CURL_MAX_HTTP_HEADER); Curl_convert_init(data); Curl_initinfo(data); @@ -632,7 +627,7 @@ CURLcode Curl_open(struct Curl_easy **curl) if(result) { Curl_resolver_cleanup(data->state.resolver); free(data->state.buffer); - free(data->state.headerbuff); + Curl_dyn_free(&data->state.headerb); Curl_freeset(data); free(data); data = NULL; @@ -3969,7 +3964,6 @@ CURLcode Curl_init_do(struct Curl_easy *data, struct connectdata *conn) k->bytecount = 0; k->buf = data->state.buffer; - k->hbufp = data->state.headerbuff; k->ignorebody = FALSE; Curl_speedinit(data); diff --git a/lib/urldata.h b/lib/urldata.h index 50d8b84a6..7eaa3513e 100644 --- a/lib/urldata.h +++ b/lib/urldata.h @@ -104,6 +104,7 @@ #include "hostip.h" #include "hash.h" #include "splay.h" +#include "dynbuf.h" /* return the count of bytes sent, or -1 on error */ typedef ssize_t (Curl_send)(struct connectdata *conn, /* connection data */ @@ -556,18 +557,13 @@ enum doh_slots { DOH_PROBE_SLOTS }; -struct dohresponse { - unsigned char *memory; - size_t size; -}; - /* one of these for each DoH request */ struct dnsprobe { CURL *easy; int dnstype; unsigned char dohbuffer[512]; size_t dohlen; - struct dohresponse serverdoh; + struct dynbuf serverdoh; }; struct dohdata { @@ -611,12 +607,7 @@ struct SingleRequest { written as body */ int headerline; /* counts header lines to better track the first one */ - char *hbufp; /* points at *end* of header line */ - size_t hbuflen; char *str; /* within buf */ - char *str_start; /* within buf */ - char *end_ptr; /* within buf */ - char *p; /* within headerbuff */ curl_off_t offset; /* possible resume offset read from the Content-Range: header */ int httpcode; /* error code from the 'HTTP/1.? XXX' or @@ -1278,9 +1269,7 @@ struct Curl_http2_dep { * BODY). */ struct tempbuf { - char *buf; /* allocated buffer to keep data in when a write callback - returns to make the connection paused */ - size_t len; /* size of the 'tempwrite' allocated buffer */ + struct dynbuf b; int type; /* type of the 'tempwrite' buffer as a bitmask that is used with Curl_client_write() */ }; @@ -1340,9 +1329,7 @@ struct UrlState { struct curltime keeps_speed; /* for the progress meter really */ struct connectdata *lastconnect; /* The last connection, NULL if undefined */ - - char *headerbuff; /* allocated buffer to store headers in */ - size_t headersize; /* size of the allocation */ + struct dynbuf headerb; /* buffer to store headers in */ char *buffer; /* download buffer */ char *ulbuf; /* allocated upload buffer or NULL */ @@ -1422,8 +1409,8 @@ struct UrlState { struct urlpieces up; #ifndef CURL_DISABLE_HTTP size_t trailers_bytes_sent; - Curl_send_buffer *trailers_buf; /* a buffer containing the compiled trailing - headers */ + struct dynbuf trailers_buf; /* a buffer containing the compiled trailing + headers */ #endif trailers_state trailers_state; /* whether we are sending trailers and what stage are we at */ |