static RRDSET *rrdset_index_find(const char *id, uint32_t hash) {
RRDSET *result = NULL, tmp;
- strncpy(tmp.id, id, RRD_ID_LENGTH_MAX);
- tmp.id[RRD_ID_LENGTH_MAX] = '\0';
+ strncpyz(tmp.id, id, RRD_ID_LENGTH_MAX);
tmp.hash = (hash)?hash:simple_hash(tmp.id);
- avl_search(&(rrdset_root_index), (avl *)&tmp, rrdset_iterator, (avl **)&result);
+ avl_search_lock(&(rrdset_root_index), (avl *) &tmp, rrdset_iterator, (avl **) &result);
return result;
}
static RRDDIM *rrddim_index_find(RRDSET *st, const char *id, uint32_t hash) {
RRDDIM *result = NULL, tmp;
- strncpy(tmp.id, id, RRD_ID_LENGTH_MAX);
- tmp.id[RRD_ID_LENGTH_MAX] = '\0';
+ strncpyz(tmp.id, id, RRD_ID_LENGTH_MAX);
tmp.hash = (hash)?hash:simple_hash(tmp.id);
- avl_search(&(st->dimensions_index), (avl *)&tmp, rrddim_iterator, (avl **)&result);
+ avl_search_lock(&(st->dimensions_index), (avl *) &tmp, rrddim_iterator, (avl **) &result);
return result;
}
}
*/
-void web_client_process(struct web_client *w) {
- int code = 500;
- ssize_t bytes;
- int enable_gzip = 0;
- w->wait_receive = 0;
+static inline char *http_header_parse(struct web_client *w, char *s) {
+ char *e = s;
- // check if we have an empty line (end of HTTP header)
- if(strstr(w->response.data->buffer, "\r\n\r\n")) {
- global_statistics_lock();
- global_statistics.web_requests++;
- global_statistics_unlock();
+ // find the :
+ while(*e && *e != ':') e++;
+ if(!*e || e[1] != ' ') return e;
- gettimeofday(&w->tv_in, NULL);
- debug(D_WEB_DATA, "%llu: Processing data buffer of %d bytes: '%s'.", w->id, w->response.data->len, w->response.data->buffer);
+ // get the name
+ *e = '\0';
- // check if the client requested keep-alive HTTP
- if(strcasestr(w->response.data->buffer, "Connection: keep-alive")) w->keepalive = 1;
- else w->keepalive = 0;
+ // find the value
+ char *v, *ve;
+ v = ve = e + 2;
+ // find the \r
+ while(*ve && *ve != '\r') ve++;
+ if(!*ve || ve[1] != '\n') {
+ *e = ':';
+ return ve;
+ }
+
+ // terminate the value
+ *ve = '\0';
+
+ // fprintf(stderr, "HEADER: '%s' = '%s'\n", s, v);
+
+ if(!strcasecmp(s, "Origin")) {
+ strncpy(w->origin, v, ORIGIN_MAX);
+ }
+ else if(!strcasecmp(s, "Connection")) {
+ if(strcasestr(v, "keep-alive"))
+ w->keepalive = 1;
+ }
#ifdef NETDATA_WITH_ZLIB
- // check if the client accepts deflate
- if(web_enable_gzip && strstr(w->response.data->buffer, "gzip"))
- enable_gzip = 1;
-#endif // NETDATA_WITH_ZLIB
+ else if(!strcasecmp(s, "Accept-Encoding")) {
+ if(web_enable_gzip && strcasestr(v, "gzip")) {
+ w->enable_gzip = 1;
+ }
+ }
+#endif /* NETDATA_WITH_ZLIB */
+
+ *e = ':';
+ *ve = '\r';
+ return ve;
+}
- int datasource_type = DATASOURCE_DATATABLE_JSONP;
- //if(strstr(w->response.data->buffer, "X-DataSource-Auth"))
- // datasource_type = DATASOURCE_GOOGLE_JSON;
+// http_request_validate()
+// returns:
+// = 0 : all good, process the request
+// > 0 : request is complete, but is not supported
+// < 0 : request is incomplete - wait for more data
- char *buf = (char *)buffer_tostring(w->response.data);
- char *tok = strsep(&buf, " \r\n");
- char *url = NULL;
- char *pointer_to_free = NULL; // keep url_decode() allocated buffer
+static inline int http_request_validate(struct web_client *w) {
+ char *s = w->response.data->buffer, *encoded_url = NULL;
+ // is is a valid request?
+ if(!strncmp(s, "GET ", 4)) {
+ encoded_url = s = &s[4];
w->mode = WEB_CLIENT_MODE_NORMAL;
+ }
+ else if(!strncmp(s, "OPTIONS ", 8)) {
+ encoded_url = s = &s[8];
+ w->mode = WEB_CLIENT_MODE_OPTIONS;
+ }
+ else {
+ w->wait_receive = 0;
+ return 1;
+ }
+
+ // find the SPACE + "HTTP/"
+ while(*s) {
+ // find the space
+ while (*s && *s != ' ') s++;
+
+ // is it SPACE + "HTTP/" ?
+ if(*s && !strncmp(s, " HTTP/", 6)) break;
+ else s++;
+ }
+
+ // incomplete requests
+ if(!*s) {
+ w->wait_receive = 1;
+ return -2;
+ }
+
+ // we have the end of encoded_url - remember it
+ char *ue = s;
+
+ while(*s) {
+ // find a line feed
+ while (*s && *s != '\r') s++;
+
+ // did we reach the end?
+ if(unlikely(!*s)) break;
+
+ // is it \r\n ?
+ if (likely(s[1] == '\n')) {
+
+ // is it again \r\n ? (header end)
+ if(unlikely(s[2] == '\r' && s[3] == '\n')) {
+ // a valid complete HTTP request found
- if(buf && strcmp(tok, "GET") == 0) {
- tok = strsep(&buf, " \r\n");
- pointer_to_free = url = url_decode(tok);
- debug(D_WEB_CLIENT, "%llu: Processing HTTP GET on url '%s'.", w->id, url);
+ *ue = '\0';
+ w->decoded_url = url_decode(encoded_url);
+ *ue = ' ';
+
+ w->wait_receive = 0;
+ return 0;
+ }
+
+ // another header line
+ s = http_header_parse(w, &s[2]);
}
- else if(buf && strcmp(tok, "OPTIONS") == 0) {
- tok = strsep(&buf, " \r\n");
- pointer_to_free = url = url_decode(tok);
- debug(D_WEB_CLIENT, "%llu: Processing HTTP OPTIONS on url '%s'.", w->id, url);
- w->mode = WEB_CLIENT_MODE_OPTIONS;
+ else s++;
+ }
+
+ // incomplete request
+ w->wait_receive = 1;
+ return -3;
+}
+
+void web_client_process(struct web_client *w) {
+ int code = 500;
+ ssize_t bytes;
+
+ int what_to_do = http_request_validate(w);
+
+ // wait for more data
+ if(what_to_do < 0) {
+ if(w->response.data->len > TOO_BIG_REQUEST) {
+ strcpy(w->last_url, "too big request");
+
+ debug(D_WEB_CLIENT_ACCESS, "%llu: Received request is too big (%zd bytes).", w->id, w->response.data->len);
+
+ code = 400;
+ buffer_flush(w->response.data);
+ buffer_sprintf(w->response.data, "Received request is too big (%zd bytes).\r\n", w->response.data->len);
}
- else if (buf && strcmp(tok, "POST") == 0) {
- w->keepalive = 0;
- tok = strsep(&buf, " \r\n");
- pointer_to_free = url = url_decode(tok);
- debug(D_WEB_CLIENT, "%llu: I don't know how to handle POST with form data. Assuming it is a GET on url '%s'.", w->id, url);
+ else {
+ // wait for more data
+ return;
}
+ }
+ else if(what_to_do > 0) {
+ strcpy(w->last_url, "not a valid response");
- w->last_url[0] = '\0';
+ debug(D_WEB_CLIENT_ACCESS, "%llu: Cannot understand '%s'.", w->id, w->response.data->buffer);
++<<<<<<< HEAD
+ code = 500;
+ buffer_flush(w->response.data);
+ buffer_strcat(w->response.data, "I don't understand you...\r\n");
+ }
+ else { // what_to_do == 0
+ gettimeofday(&w->tv_in, NULL);
+
+ global_statistics_lock();
+ global_statistics.web_requests++;
+ global_statistics_unlock();
++=======
+ if(w->mode == WEB_CLIENT_MODE_OPTIONS) {
+ strncpyz(w->last_url, url, URL_MAX);
++>>>>>>> fredericopissarra/changes
+ // copy the URL - we are going to overwrite parts of it
+ // FIXME -- we should avoid it
+ strncpy(w->last_url, w->decoded_url, URL_MAX);
+ w->last_url[URL_MAX] = '\0';
+
+ if(w->mode == WEB_CLIENT_MODE_OPTIONS) {
code = 200;
w->response.data->contenttype = CT_TEXT_PLAIN;
buffer_flush(w->response.data);
web_client_enable_deflate(w);
#endif
++<<<<<<< HEAD
+ char *url = w->decoded_url;
+ char *tok = mystrsep(&url, "/?");
++=======
+ strncpyz(w->last_url, url, URL_MAX);
+
+ tok = mystrsep(&url, "/?");
++>>>>>>> fredericopissarra/changes
if(tok && *tok) {
debug(D_WEB_CLIENT, "%llu: Processing command '%s'.", w->id, tok);