@cryptotaxi247 / netdata-1 / commits / 3108058f0

prevent a malloc/free per web request

Costa Tsaousis (ktsaou) committed May 21, 2016 at 00:12 UTC 3108058f003c1311c39300e4a4c115870827b937
4 files changed +41 -35
src/url.c
+22 -16
@@ -63,31 +63,37 @@ char *url_encode(char *str) {
63 /* Returns a url-decoded version of str */
64 /* IMPORTANT: be sure to free() the returned string after use */
65 char *url_decode(char *str) {
66 - char *pstr = str,
67 - *buf = malloc(strlen(str) + 1),
68 - *pbuf = buf;
66 + size_t size = strlen(str) + 1;
67
68 + char *buf = malloc(size);
69 if(!buf)
71 - fatal("Cannot allocate memory.");
70 + fatal("Cannot allocate %zu bytes of memory.", size);
71 +
72 + return url_decode_r(buf, str, size);
73 +}
74 +
75 +char *url_decode_r(char *to, char *url, size_t size) {
76 + char *s = url, // source
77 + *d = to, // destination
78 + *e = &to[size - 1]; // destination end
79
73 - while (*pstr) {
74 - if (*pstr == '%') {
75 - if (pstr[1] && pstr[2]) {
76 - *pbuf++ = from_hex(pstr[1]) << 4 | from_hex(pstr[2]);
77 - pstr += 2;
80 + while(*s && d < e) {
81 + if(unlikely(*s == '%')) {
82 + if(likely(s[1] && s[2])) {
83 + *d++ = from_hex(s[1]) << 4 | from_hex(s[2]);
84 + s += 2;
85 }
86 }
80 - else if (*pstr == '+')
81 - *pbuf++ = ' ';
87 + else if(unlikely(*s == '+'))
88 + *d++ = ' ';
89
90 else
84 - *pbuf++ = *pstr;
91 + *d++ = *s;
92
86 - pstr++;
93 + s++;
94 }
95
89 - *pbuf = '\0';
96 + *d = '\0';
97
91 - return buf;
98 + return to;
99 }
93 -
src/url.h
+2
@@ -19,4 +19,6 @@ extern char *url_encode(char *str);
19 /* IMPORTANT: be sure to free() the returned string after use */
20 extern char *url_decode(char *str);
21
22 +extern char *url_decode_r(char *to, char *url, size_t size);
23 +
24 #endif /* NETDATA_URL_H */
src/web_client.c
+15 -17
@@ -194,10 +194,7 @@ void web_client_reset(struct web_client *w)
194 w->mode = WEB_CLIENT_MODE_NORMAL;
195 w->enable_gzip = 0;
196 w->keepalive = 0;
197 - if(w->decoded_url) {
198 - free(w->decoded_url);
199 - w->decoded_url = NULL;
200 - }
197 + w->decoded_url[0] = '\0';
198
199 buffer_reset(w->response.header_output);
200 buffer_reset(w->response.header);
@@ -1246,7 +1243,7 @@ static inline char *http_header_parse(struct web_client *w, char *s) {
1243 // http_request_validate()
1244 // returns:
1245 // = 0 : all good, process the request
1249 -// > 0 : request is complete, but is not supported
1246 +// > 0 : request is not supported
1247 // < 0 : request is incomplete - wait for more data
1248
1249 static inline int http_request_validate(struct web_client *w) {
@@ -1268,7 +1265,7 @@ static inline int http_request_validate(struct web_client *w) {
1265
1266 // find the SPACE + "HTTP/"
1267 while(*s) {
1271 - // find the space
1268 + // find the next space
1269 while (*s && *s != ' ') s++;
1270
1271 // is it SPACE + "HTTP/" ?
@@ -1277,7 +1274,7 @@ static inline int http_request_validate(struct web_client *w) {
1274 }
1275
1276 // incomplete requests
1280 - if(!*s) {
1277 + if(unlikely(!*s)) {
1278 w->wait_receive = 1;
1279 return -2;
1280 }
@@ -1285,32 +1282,37 @@ static inline int http_request_validate(struct web_client *w) {
1282 // we have the end of encoded_url - remember it
1283 char *ue = s;
1284
1285 + // make sure we have complete request
1286 + // complete requests contain: \r\n\r\n
1287 while(*s) {
1288 // find a line feed
1290 - while (*s && *s != '\r') s++;
1289 + while(*s && *s++ != '\r');
1290
1291 // did we reach the end?
1292 if(unlikely(!*s)) break;
1293
1294 // is it \r\n ?
1296 - if (likely(s[1] == '\n')) {
1295 + if(likely(*s++ == '\n')) {
1296
1297 // is it again \r\n ? (header end)
1299 - if(unlikely(s[2] == '\r' && s[3] == '\n')) {
1298 + if(unlikely(*s == '\r' && s[1] == '\n')) {
1299 // a valid complete HTTP request found
1300
1301 *ue = '\0';
1303 - w->decoded_url = url_decode(encoded_url);
1302 + url_decode_r(w->decoded_url, encoded_url, URL_MAX + 1);
1303 *ue = ' ';
1304 +
1305 + // copy the URL - we are going to overwrite parts of it
1306 + // FIXME -- we should avoid it
1307 + strncpyz(w->last_url, w->decoded_url, URL_MAX);
1308
1309 w->wait_receive = 0;
1310 return 0;
1311 }
1312
1313 // another header line
1311 - s = http_header_parse(w, &s[2]);
1314 + s = http_header_parse(w, s);
1315 }
1313 - else s++;
1316 }
1317
1318 // incomplete request
@@ -1352,10 +1354,6 @@ void web_client_process(struct web_client *w) {
1354 else { // what_to_do == 0
1355 gettimeofday(&w->tv_in, NULL);
1356
1355 - // copy the URL - we are going to overwrite parts of it
1356 - // FIXME -- we should avoid it
1357 - strncpyz(w->last_url, w->decoded_url, URL_MAX);
1358 -
1357 if(w->mode == WEB_CLIENT_MODE_OPTIONS) {
1358 code = 200;
1359 w->response.data->contenttype = CT_TEXT_PLAIN;
src/web_client.h
+2 -2
@@ -57,7 +57,8 @@ struct web_client {
57 char client_ip[NI_MAXHOST+1];
58 char client_port[NI_MAXSERV+1];
59
60 - char last_url[URL_MAX+1];
60 + char decoded_url[URL_MAX + 1]; // we decode the URL in this buffer
61 + char last_url[URL_MAX+1]; // we keep a copy of the decoded URL here
62
63 struct timeval tv_in, tv_ready;
64
@@ -68,7 +69,6 @@ struct web_client {
69 int mode;
70 int keepalive;
71 int enable_gzip;
71 - char *decoded_url;
72
73 struct sockaddr_storage clientaddr;
74