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