]> arthur.barton.de Git - netdata.git/commitdiff
prevent a malloc/free per web request
authorCosta Tsaousis (ktsaou) <costa@tsaousis.gr>
Fri, 20 May 2016 21:12:44 +0000 (00:12 +0300)
committerCosta Tsaousis (ktsaou) <costa@tsaousis.gr>
Fri, 20 May 2016 21:12:44 +0000 (00:12 +0300)
src/url.c
src/url.h
src/web_client.c
src/web_client.h

index 010b07dddc69a8a88253d6cc7bf16d28ca665332..bd22b8187fe05d335d3400a26386bd6c0c7cdbd8 100644 (file)
--- a/src/url.c
+++ b/src/url.c
@@ -63,31 +63,37 @@ char *url_encode(char *str) {
 /* Returns a url-decoded version of str */
 /* IMPORTANT: be sure to free() the returned string after use */
 char *url_decode(char *str) {
-       char *pstr = str,
-               *buf = malloc(strlen(str) + 1),
-               *pbuf = buf;
+       size_t size = strlen(str) + 1;
 
+       char *buf = malloc(size);
        if(!buf)
-               fatal("Cannot allocate memory.");
+               fatal("Cannot allocate %zu bytes of memory.", size);
+
+       return url_decode_r(buf, str, size);
+}
+
+char *url_decode_r(char *to, char *url, size_t size) {
+       char *s = url,           // source
+                *d = to,            // destination
+                *e = &to[size - 1]; // destination end
 
-       while (*pstr) {
-               if (*pstr == '%') {
-                       if (pstr[1] && pstr[2]) {
-                               *pbuf++ = from_hex(pstr[1]) << 4 | from_hex(pstr[2]);
-                               pstr += 2;
+       while(*s && d < e) {
+               if(unlikely(*s == '%')) {
+                       if(likely(s[1] && s[2])) {
+                               *d++ = from_hex(s[1]) << 4 | from_hex(s[2]);
+                               s += 2;
                        }
                }
-               else if (*pstr == '+')
-                       *pbuf++ = ' ';
+               else if(unlikely(*s == '+'))
+                       *d++ = ' ';
 
                else
-                       *pbuf++ = *pstr;
+                       *d++ = *s;
 
-               pstr++;
+               s++;
        }
 
-       *pbuf = '\0';
+       *d = '\0';
 
-       return buf;
+       return to;
 }
-
index f79a20ea0c0f7973e4fe92a42522b008d7abe3e2..fa44d49a8e856d081f1907b85ae06dad45a37281 100644 (file)
--- a/src/url.h
+++ b/src/url.h
@@ -19,4 +19,6 @@ extern char *url_encode(char *str);
 /* IMPORTANT: be sure to free() the returned string after use */
 extern char *url_decode(char *str);
 
+extern char *url_decode_r(char *to, char *url, size_t size);
+
 #endif /* NETDATA_URL_H */
index f9223117eff76c6820ef7fd8d638db9a4648a55c..d78624c9c37693513ba7fa459527a2eddeb7f475 100644 (file)
@@ -194,10 +194,7 @@ void web_client_reset(struct web_client *w)
        w->mode = WEB_CLIENT_MODE_NORMAL;
        w->enable_gzip = 0;
        w->keepalive = 0;
-       if(w->decoded_url) {
-               free(w->decoded_url);
-               w->decoded_url = NULL;
-       }
+       w->decoded_url[0] = '\0';
 
        buffer_reset(w->response.header_output);
        buffer_reset(w->response.header);
@@ -1246,7 +1243,7 @@ static inline char *http_header_parse(struct web_client *w, char *s) {
 // http_request_validate()
 // returns:
 // = 0 : all good, process the request
-// > 0 : request is complete, but is not supported
+// > 0 : request is not supported
 // < 0 : request is incomplete - wait for more data
 
 static inline int http_request_validate(struct web_client *w) {
@@ -1268,7 +1265,7 @@ static inline int http_request_validate(struct web_client *w) {
 
        // find the SPACE + "HTTP/"
        while(*s) {
-               // find the space
+               // find the next space
                while (*s && *s != ' ') s++;
 
                // is it SPACE + "HTTP/" ?
@@ -1277,7 +1274,7 @@ static inline int http_request_validate(struct web_client *w) {
        }
 
        // incomplete requests
-       if(!*s) {
+       if(unlikely(!*s)) {
                w->wait_receive = 1;
                return -2;
        }
@@ -1285,32 +1282,37 @@ static inline int http_request_validate(struct web_client *w) {
        // we have the end of encoded_url - remember it
        char *ue = s;
 
+       // make sure we have complete request
+       // complete requests contain: \r\n\r\n
        while(*s) {
                // find a line feed
-               while (*s && *s != '\r') s++;
+               while(*s && *s++ != '\r');
 
                // did we reach the end?
                if(unlikely(!*s)) break;
 
                // is it \r\n ?
-               if (likely(s[1] == '\n')) {
+               if(likely(*s++ == '\n')) {
 
                        // is it again \r\n ? (header end)
-                       if(unlikely(s[2] == '\r' && s[3] == '\n')) {
+                       if(unlikely(*s == '\r' && s[1] == '\n')) {
                                // a valid complete HTTP request found
 
                                *ue = '\0';
-                               w->decoded_url = url_decode(encoded_url);
+                               url_decode_r(w->decoded_url, encoded_url, URL_MAX + 1);
                                *ue = ' ';
+                               
+                               // copy the URL - we are going to overwrite parts of it
+                               // FIXME -- we should avoid it
+                               strncpyz(w->last_url, w->decoded_url, URL_MAX);
 
                                w->wait_receive = 0;
                                return 0;
                        }
 
                        // another header line
-                       s = http_header_parse(w, &s[2]);
+                       s = http_header_parse(w, s);
                }
-               else s++;
        }
 
        // incomplete request
@@ -1352,10 +1354,6 @@ void web_client_process(struct web_client *w) {
        else { // what_to_do == 0
                gettimeofday(&w->tv_in, NULL);
 
-               // copy the URL - we are going to overwrite parts of it
-               // FIXME -- we should avoid it
-               strncpyz(w->last_url, w->decoded_url, URL_MAX);
-
                if(w->mode == WEB_CLIENT_MODE_OPTIONS) {
                        code = 200;
                        w->response.data->contenttype = CT_TEXT_PLAIN;
index 559c4459d9be53eefe25f4f2241aa6701490fa97..da3707d20a3910c01c92e794b874fdc9144c19e8 100644 (file)
@@ -57,7 +57,8 @@ struct web_client {
        char client_ip[NI_MAXHOST+1];
        char client_port[NI_MAXSERV+1];
 
-       char last_url[URL_MAX+1];
+       char decoded_url[URL_MAX + 1];  // we decode the URL in this buffer
+       char last_url[URL_MAX+1];               // we keep a copy of the decoded URL here
 
        struct timeval tv_in, tv_ready;
 
@@ -68,7 +69,6 @@ struct web_client {
        int mode;
        int keepalive;
        int enable_gzip;
-       char *decoded_url;
 
        struct sockaddr_storage clientaddr;