{"action":"created","comment":{"url":"https://api.github.com/repos/twitter-forks/statsite/pulls/comments/51088810","id":51088810,"diff_hunk":"@@ -156,76 +178,246 @@ static int add_metrics(void* data,\n         syslog(LOG_ERR, \"Unknown metric type: %d\", type);\n         break;\n     }\n+}\n+\n+\n+/*\n+ * Callback function for adding a metric into json object. This function\n+ * is called by iterator of metrics object.\n+ * TODO: There is a lot redundant code here with sink_stream to normalize\n+ * an output representation of a metrics.\n+ * @arg data The config data, including configs and the output objects.\n+ * @arg type The type of metrics.\n+ * @arg metric The metirc key.\n+ * @arg value The metric value.\n+ * @return 0 on success.\n+ */\n+static int _add_metric_cb(void* data,\n+                          metric_type type,\n+                          char* metric,\n+                          void* value) {\n+\n+    struct metric_cb_info* info = (struct metric_cb_info*)data;\n+    hashmap* json_map = info->json_map;\n+    const statsite_config* config = info->config;\n+    const sink_config_http* httpconfig = info->httpconfig;\n+\n+    /* Extract partition info */\n+    char* partition;\n+    int name_len;\n+    char* pos = strchr(metric, PARTITION_DELIMITER);\n+    if (pos == NULL) {\n+        /* There is no partition data */\n+        partition = DEFAULT_PARTITION;\n+        name_len = strlen(metric);\n+    } else {\n+        /* There is partition data, separate name and partition */\n+        partition = pos + 1;\n+        name_len = pos - metric;\n+    }\n \n+    /* Early out if the metric name is empty */\n+    if (name_len == 0) {\n+        return 0;\n+    }\n+\n+    /* Get prefix from config */\n+    char* prefix = NULL;\n+    uint16_t pre_len = 0;\n+    if (httpconfig->use_prefix) {\n+        prefix = config->prefixes_final[type];\n+        pre_len = strlen(prefix);\n+    }\n+\n+    /*\n+     * Find the json object mapped to the partition string.\n+     * Create one if there isn't one yet.\n+     */\n+    json_t* obj = NULL;\n+    if (hashmap_get(json_map, partition, (void**)&obj) == -1) {\n+        /* Create a new json object if it doesn't exist */\n+        obj = json_object();\n+        hashmap_put(json_map, partition, obj);\n+    }\n+\n+    assert(obj != NULL);\n+    _add_metric_to_json(obj, type, prefix, pre_len, metric, name_len, value, config);\n     return 0;\n }\n \n-static int json_cb(const char* buf, size_t size, void* d) {\n+/*\n+ * Callback function for dumping json object to string.\n+ * @arg buf The data buffer to dump.\n+ * @arg size Number of bytes to dump.\n+ * @arg buf The output buffer.\n+ * @return 0 on success.\n+ */\n+static int _json_cb(const char* buf, size_t size, void* d) {\n     strbuf* sbuf = (strbuf*)d;\n     strbuf_cat(sbuf, buf, size);\n     return 0;\n }\n \n-static int serialize_metrics(struct http_sink* sink, metrics* m, void* data) {\n-    json_t* jobject = json_object();\n-    const sink_config_http* httpconfig = (const sink_config_http*)sink->sink.sink_config;\n+/*\n+ * Escape a string and add it to the post buffer.\n+ * @arg post_buf The post buffer.\n+ * @arg value The string to escape and append.\n+ * @arg len The length of the string to append. 0 if the full string should be appended.\n+ * @arg curl The CURL object for string escaping.\n+ */\n+static void _escape_and_append_to_buffer(strbuf* post_buf,\n+                                         const char* value,\n+                                         int len,\n+                                         CURL* curl) {\n+    char* escaped_data = curl_easy_escape(curl, value, len);\n+    strbuf_cat(post_buf, escaped_data, strlen(escaped_data));\n+    curl_free(escaped_data);\n+}\n \n-    struct cb_info info = {\n-        .jobject = jobject,\n-        .config = sink->sink.global_config,\n-        .httpconfig = httpconfig\n-    };\n-    /* produce a metrics json object */\n-    metrics_iter(m, &info, add_metrics);\n+/*\n+ * Verify if a key exists in a query string or not. This function simply scans\n+ * through the query string, hence it shouldn't be called often.\n+ * @arg key The key to search. It should not contain characters '&' and '='.\n+ * @arg partition_string The partition string to search in.\n+ * @return True if the key exists as a key name(as key in key=123 but not in key123=123)\n+ *         in the query string, false otherwise.\n+ */\n+bool _key_exists_in_query_string(const char* key,\n+                                 const char* query_string) {\n+    if (key == NULL || query_string == NULL) {\n+        return false;\n+    }\n+\n+    int len = strlen(key);\n+    do {\n+        if (strncmp(query_string, key, len) == 0 &&\n+            (query_string[len] == '=' || query_string[len] == '&' || query_string[len] == '\\0')) {\n+            return true;\n+        }\n+        query_string = strchr(query_string + 1, '&');","path":"src/sink_http.c","position":252,"original_position":252,"commit_id":"54bbdccd37d5831d02915edc7d822bcc40d3745e","original_commit_id":"54bbdccd37d5831d02915edc7d822bcc40d3745e","user":{"login":"thinkingfish","id":366406,"avatar_url":"https://avatars.githubusercontent.com/u/366406?v=3","gravatar_id":"","url":"https://api.github.com/users/thinkingfish","html_url":"https://github.com/thinkingfish","followers_url":"https://api.github.com/users/thinkingfish/followers","following_url":"https://api.github.com/users/thinkingfish/following{/other_user}","gists_url":"https://api.github.com/users/thinkingfish/gists{/gist_id}","starred_url":"https://api.github.com/users/thinkingfish/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/thinkingfish/subscriptions","organizations_url":"https://api.github.com/users/thinkingfish/orgs","repos_url":"https://api.github.com/users/thinkingfish/repos","events_url":"https://api.github.com/users/thinkingfish/events{/privacy}","received_events_url":"https://api.github.com/users/thinkingfish/received_events","type":"User","site_admin":false},"body":"Is it possible to have ```query_string``` as an empty string (but with a larger allocation size)? If so, this would run over.\r\n","created_at":"2016-01-28T07:37:00Z","updated_at":"2016-01-28T07:37:00Z","html_url":"https://github.com/twitter-forks/statsite/pull/27#discussion_r51088810","pull_request_url":"https://api.github.com/repos/twitter-forks/statsite/pulls/27","_links":{"self":{"href":"https://api.github.com/repos/twitter-forks/statsite/pulls/comments/51088810"},"html":{"href":"https://github.com/twitter-forks/statsite/pull/27#discussion_r51088810"},"pull_request":{"href":"https://api.github.com/repos/twitter-forks/statsite/pulls/27"}}},"pull_request":{"url":"https://api.github.com/repos/twitter-forks/statsite/pulls/27","id":57437870,"html_url":"https://github.com/twitter-forks/statsite/pull/27","diff_url":"https://github.com/twitter-forks/statsite/pull/27.diff","patch_url":"https://github.com/twitter-forks/statsite/pull/27.patch","issue_url":"https://api.github.com/repos/twitter-forks/statsite/issues/27","number":27,"state":"open","locked":false,"title":"Add partitioning(to support dynamic service and source) in http sink","user":{"login":"nwangtw","id":6353055,"avatar_url":"https://avatars.githubusercontent.com/u/6353055?v=3","gravatar_id":"","url":"https://api.github.com/users/nwangtw","html_url":"https://github.com/nwangtw","followers_url":"https://api.github.com/users/nwangtw/followers","following_url":"https://api.github.com/users/nwangtw/following{/other_user}","gists_url":"https://api.github.com/users/nwangtw/gists{/gist_id}","starred_url":"https://api.github.com/users/nwangtw/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/nwangtw/subscriptions","organizations_url":"https://api.github.com/users/nwangtw/orgs","repos_url":"https://api.github.com/users/nwangtw/repos","events_url":"https://api.github.com/users/nwangtw/events{/privacy}","received_events_url":"https://api.github.com/users/nwangtw/received_events","type":"User","site_admin":false},"body":"","created_at":"2016-01-27T23:05:17Z","updated_at":"2016-01-28T07:37:00Z","closed_at":null,"merged_at":null,"merge_commit_sha":"c8cd32e895ab1430c02444e267c710b35e1e4715","assignee":null,"milestone":null,"commits_url":"https://api.github.com/repos/twitter-forks/statsite/pulls/27/commits","review_comments_url":"https://api.github.com/repos/twitter-forks/statsite/pulls/27/comments","review_comment_url":"https://api.github.com/repos/twitter-forks/statsite/pulls/comments{/number}","comments_url":"https://api.github.com/repos/twitter-forks/statsite/issues/27/comments","statuses_url":"https://api.github.com/repos/twitter-forks/statsite/statuses/54bbdccd37d5831d02915edc7d822bcc40d3745e","head":{"label":"nwangtw:master","ref":"master","sha":"54bbdccd37d5831d02915edc7d822bcc40d3745e","user":{"login":"nwangtw","id":6353055,"avatar_url":"https://avatars.githubusercontent.com/u/6353055?v=3","gravatar_id":"","url":"https://api.github.com/users/nwangtw","html_url":"https://github.com/nwangtw","followers_url":"https://api.github.com/users/nwangtw/followers","following_url":"https://api.github.com/users/nwangtw/following{/other_user}","gists_url":"https://api.github.com/users/nwangtw/gists{/gist_id}","starred_url":"https://api.github.com/users/nwangtw/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/nwangtw/subscriptions","organizations_url":"https://api.github.com/users/nwangtw/orgs","repos_url":"https://api.github.com/users/nwangtw/repos","events_url":"https://api.github.com/users/nwangtw/events{/privacy}","received_events_url":"https://api.github.com/users/nwangtw/received_events","type":"User","site_admin":false},"repo":{"id":50396293,"name":"statsite","full_name":"nwangtw/statsite","owner":{"login":"nwangtw","id":6353055,"avatar_url":"https://avatars.githubusercontent.com/u/6353055?v=3","gravatar_id":"","url":"https://api.github.com/users/nwangtw","html_url":"https://github.com/nwangtw","followers_url":"https://api.github.com/users/nwangtw/followers","following_url":"https://api.github.com/users/nwangtw/following{/other_user}","gists_url":"https://api.github.com/users/nwangtw/gists{/gist_id}","starred_url":"https://api.github.com/users/nwangtw/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/nwangtw/subscriptions","organizations_url":"https://api.github.com/users/nwangtw/orgs","repos_url":"https://api.github.com/users/nwangtw/repos","events_url":"https://api.github.com/users/nwangtw/events{/privacy}","received_events_url":"https://api.github.com/users/nwangtw/received_events","type":"User","site_admin":false},"private":false,"html_url":"https://github.com/nwangtw/statsite","description":"C implementation of statsd","fork":true,"url":"https://api.github.com/repos/nwangtw/statsite","forks_url":"https://api.github.com/repos/nwangtw/statsite/forks","keys_url":"https://api.github.com/repos/nwangtw/statsite/keys{/key_id}","collaborators_url":"https://api.github.com/repos/nwangtw/statsite/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/nwangtw/statsite/teams","hooks_url":"https://api.github.com/repos/nwangtw/statsite/hooks","issue_events_url":"https://api.github.com/repos/nwangtw/statsite/issues/events{/number}","events_url":"https://api.github.com/repos/nwangtw/statsite/events","assignees_url":"https://api.github.com/repos/nwangtw/statsite/assignees{/user}","branches_url":"https://api.github.com/repos/nwangtw/statsite/branches{/branch}","tags_url":"https://api.github.com/repos/nwangtw/statsite/tags","blobs_url":"https://api.github.com/repos/nwangtw/statsite/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/nwangtw/statsite/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/nwangtw/statsite/git/refs{/sha}","trees_url":"https://api.github.com/repos/nwangtw/statsite/git/trees{/sha}","statuses_url":"https://api.github.com/repos/nwangtw/statsite/statuses/{sha}","languages_url":"https://api.github.com/repos/nwangtw/statsite/languages","stargazers_url":"https://api.github.com/repos/nwangtw/statsite/stargazers","contributors_url":"https://api.github.com/repos/nwangtw/statsite/contributors","subscribers_url":"https://api.github.com/repos/nwangtw/statsite/subscribers","subscription_url":"https://api.github.com/repos/nwangtw/statsite/subscription","commits_url":"https://api.github.com/repos/nwangtw/statsite/commits{/sha}","git_commits_url":"https://api.github.com/repos/nwangtw/statsite/git/commits{/sha}","comments_url":"https://api.github.com/repos/nwangtw/statsite/comments{/number}","issue_comment_url":"https://api.github.com/repos/nwangtw/statsite/issues/comments{/number}","contents_url":"https://api.github.com/repos/nwangtw/statsite/contents/{+path}","compare_url":"https://api.github.com/repos/nwangtw/statsite/compare/{base}...{head}","merges_url":"https://api.github.com/repos/nwangtw/statsite/merges","archive_url":"https://api.github.com/repos/nwangtw/statsite/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/nwangtw/statsite/downloads","issues_url":"https://api.github.com/repos/nwangtw/statsite/issues{/number}","pulls_url":"https://api.github.com/repos/nwangtw/statsite/pulls{/number}","milestones_url":"https://api.github.com/repos/nwangtw/statsite/milestones{/number}","notifications_url":"https://api.github.com/repos/nwangtw/statsite/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/nwangtw/statsite/labels{/name}","releases_url":"https://api.github.com/repos/nwangtw/statsite/releases{/id}","deployments_url":"https://api.github.com/repos/nwangtw/statsite/deployments","created_at":"2016-01-26T02:15:11Z","updated_at":"2016-01-26T02:15:12Z","pushed_at":"2016-01-27T23:03:31Z","git_url":"git://github.com/nwangtw/statsite.git","ssh_url":"git@github.com:nwangtw/statsite.git","clone_url":"https://github.com/nwangtw/statsite.git","svn_url":"https://github.com/nwangtw/statsite","homepage":"http://armon.github.io/statsite","size":1899,"stargazers_count":0,"watchers_count":0,"language":"C","has_issues":false,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":0,"mirror_url":null,"open_issues_count":0,"forks":0,"open_issues":0,"watchers":0,"default_branch":"master"}},"base":{"label":"twitter-forks:master","ref":"master","sha":"8fee12477723400f3ec46f36b0b5bdc890274d02","user":{"login":"twitter-forks","id":5349157,"avatar_url":"https://avatars.githubusercontent.com/u/5349157?v=3","gravatar_id":"","url":"https://api.github.com/users/twitter-forks","html_url":"https://github.com/twitter-forks","followers_url":"https://api.github.com/users/twitter-forks/followers","following_url":"https://api.github.com/users/twitter-forks/following{/other_user}","gists_url":"https://api.github.com/users/twitter-forks/gists{/gist_id}","starred_url":"https://api.github.com/users/twitter-forks/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/twitter-forks/subscriptions","organizations_url":"https://api.github.com/users/twitter-forks/orgs","repos_url":"https://api.github.com/users/twitter-forks/repos","events_url":"https://api.github.com/users/twitter-forks/events{/privacy}","received_events_url":"https://api.github.com/users/twitter-forks/received_events","type":"Organization","site_admin":false},"repo":{"id":34355843,"name":"statsite","full_name":"twitter-forks/statsite","owner":{"login":"twitter-forks","id":5349157,"avatar_url":"https://avatars.githubusercontent.com/u/5349157?v=3","gravatar_id":"","url":"https://api.github.com/users/twitter-forks","html_url":"https://github.com/twitter-forks","followers_url":"https://api.github.com/users/twitter-forks/followers","following_url":"https://api.github.com/users/twitter-forks/following{/other_user}","gists_url":"https://api.github.com/users/twitter-forks/gists{/gist_id}","starred_url":"https://api.github.com/users/twitter-forks/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/twitter-forks/subscriptions","organizations_url":"https://api.github.com/users/twitter-forks/orgs","repos_url":"https://api.github.com/users/twitter-forks/repos","events_url":"https://api.github.com/users/twitter-forks/events{/privacy}","received_events_url":"https://api.github.com/users/twitter-forks/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/twitter-forks/statsite","description":"C implementation of statsd","fork":true,"url":"https://api.github.com/repos/twitter-forks/statsite","forks_url":"https://api.github.com/repos/twitter-forks/statsite/forks","keys_url":"https://api.github.com/repos/twitter-forks/statsite/keys{/key_id}","collaborators_url":"https://api.github.com/repos/twitter-forks/statsite/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/twitter-forks/statsite/teams","hooks_url":"https://api.github.com/repos/twitter-forks/statsite/hooks","issue_events_url":"https://api.github.com/repos/twitter-forks/statsite/issues/events{/number}","events_url":"https://api.github.com/repos/twitter-forks/statsite/events","assignees_url":"https://api.github.com/repos/twitter-forks/statsite/assignees{/user}","branches_url":"https://api.github.com/repos/twitter-forks/statsite/branches{/branch}","tags_url":"https://api.github.com/repos/twitter-forks/statsite/tags","blobs_url":"https://api.github.com/repos/twitter-forks/statsite/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/twitter-forks/statsite/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/twitter-forks/statsite/git/refs{/sha}","trees_url":"https://api.github.com/repos/twitter-forks/statsite/git/trees{/sha}","statuses_url":"https://api.github.com/repos/twitter-forks/statsite/statuses/{sha}","languages_url":"https://api.github.com/repos/twitter-forks/statsite/languages","stargazers_url":"https://api.github.com/repos/twitter-forks/statsite/stargazers","contributors_url":"https://api.github.com/repos/twitter-forks/statsite/contributors","subscribers_url":"https://api.github.com/repos/twitter-forks/statsite/subscribers","subscription_url":"https://api.github.com/repos/twitter-forks/statsite/subscription","commits_url":"https://api.github.com/repos/twitter-forks/statsite/commits{/sha}","git_commits_url":"https://api.github.com/repos/twitter-forks/statsite/git/commits{/sha}","comments_url":"https://api.github.com/repos/twitter-forks/statsite/comments{/number}","issue_comment_url":"https://api.github.com/repos/twitter-forks/statsite/issues/comments{/number}","contents_url":"https://api.github.com/repos/twitter-forks/statsite/contents/{+path}","compare_url":"https://api.github.com/repos/twitter-forks/statsite/compare/{base}...{head}","merges_url":"https://api.github.com/repos/twitter-forks/statsite/merges","archive_url":"https://api.github.com/repos/twitter-forks/statsite/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/twitter-forks/statsite/downloads","issues_url":"https://api.github.com/repos/twitter-forks/statsite/issues{/number}","pulls_url":"https://api.github.com/repos/twitter-forks/statsite/pulls{/number}","milestones_url":"https://api.github.com/repos/twitter-forks/statsite/milestones{/number}","notifications_url":"https://api.github.com/repos/twitter-forks/statsite/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/twitter-forks/statsite/labels{/name}","releases_url":"https://api.github.com/repos/twitter-forks/statsite/releases{/id}","deployments_url":"https://api.github.com/repos/twitter-forks/statsite/deployments","created_at":"2015-04-21T22:40:41Z","updated_at":"2016-01-26T22:14:44Z","pushed_at":"2016-01-27T23:05:18Z","git_url":"git://github.com/twitter-forks/statsite.git","ssh_url":"git@github.com:twitter-forks/statsite.git","clone_url":"https://github.com/twitter-forks/statsite.git","svn_url":"https://github.com/twitter-forks/statsite","homepage":"http://armon.github.io/statsite","size":1911,"stargazers_count":8,"watchers_count":8,"language":"C","has_issues":false,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":4,"mirror_url":null,"open_issues_count":2,"forks":4,"open_issues":2,"watchers":8,"default_branch":"master"}},"_links":{"self":{"href":"https://api.github.com/repos/twitter-forks/statsite/pulls/27"},"html":{"href":"https://github.com/twitter-forks/statsite/pull/27"},"issue":{"href":"https://api.github.com/repos/twitter-forks/statsite/issues/27"},"comments":{"href":"https://api.github.com/repos/twitter-forks/statsite/issues/27/comments"},"review_comments":{"href":"https://api.github.com/repos/twitter-forks/statsite/pulls/27/comments"},"review_comment":{"href":"https://api.github.com/repos/twitter-forks/statsite/pulls/comments{/number}"},"commits":{"href":"https://api.github.com/repos/twitter-forks/statsite/pulls/27/commits"},"statuses":{"href":"https://api.github.com/repos/twitter-forks/statsite/statuses/54bbdccd37d5831d02915edc7d822bcc40d3745e"}}}}