summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/libutil/http.c105
-rw-r--r--src/libutil/http.h8
2 files changed, 113 insertions, 0 deletions
diff --git a/src/libutil/http.c b/src/libutil/http.c
index 3e4e4a7c4..82ffdc19f 100644
--- a/src/libutil/http.c
+++ b/src/libutil/http.c
@@ -2325,3 +2325,108 @@ rspamd_http_connection_make_peer_key (const gchar *key)
return kp;
}
+
+GHashTable *
+rspamd_http_message_parse_query (struct rspamd_http_message *msg)
+{
+ GHashTable *res;
+ GString *key = NULL, *value = NULL;
+ const gchar *p, *c, *end;
+ struct http_parser_url u;
+ enum {
+ parse_key,
+ parse_eqsign,
+ parse_value,
+ parse_ampersand
+ } state = parse_key;
+
+ res = g_hash_table_new_full (rspamd_gstring_icase_hash,
+ rspamd_gstring_icase_equal, rspamd_gstring_free_hard,
+ rspamd_gstring_free_hard);
+
+ if (msg->url && msg->url->len > 0) {
+ http_parser_parse_url (msg->url->str, msg->url->len, TRUE, &u);
+
+ if (u.field_set & (1 << UF_QUERY)) {
+ p = msg->url->str + u.field_data[UF_QUERY].off;
+ c = p;
+ end = p + u.field_data[UF_QUERY].len;
+
+ while (p <= end) {
+ switch (state) {
+ case parse_key:
+ if ((*p == '&' || p == end) && p > c) {
+ /* We have a single parameter without a value */
+ key = g_string_sized_new (p - c);
+ g_string_append_len (key, c, p - c);
+ key->len = rspamd_decode_url (key->str, key->str,
+ key->len);
+ value = g_string_new ("");
+ g_hash_table_insert (res, key, value);
+ state = parse_ampersand;
+ }
+ else if (*p == '=' && p > c) {
+ /* We have something like key=value */
+ key = g_string_sized_new (p - c);
+ g_string_append_len (key, c, p - c);
+ key->len = rspamd_decode_url (key->str, key->str,
+ key->len);
+ state = parse_eqsign;
+ }
+ else {
+ p ++;
+ }
+ break;
+
+ case parse_eqsign:
+ if (*p != '=') {
+ c = p;
+ state = parse_value;
+ }
+ else {
+ p ++;
+ }
+ break;
+
+ case parse_value:
+ if ((*p == '&' || p == end) && p >= c) {
+ g_assert (key != NULL);
+ if (p > c) {
+ value = g_string_sized_new (p - c);
+ g_string_append_len (key, c, p - c);
+ value->len = rspamd_decode_url (value->str, value->str,
+ value->len);
+ }
+ else {
+ value = g_string_new ("");
+ }
+
+ g_hash_table_insert (res, key, value);
+ key = value = NULL;
+ state = parse_ampersand;
+ }
+ else {
+ p ++;
+ }
+ break;
+
+ case parse_ampersand:
+ if (*p != '&') {
+ c = p;
+ state = parse_key;
+ }
+ else {
+ p ++;
+ }
+ break;
+ }
+ }
+ }
+
+ if (state != parse_ampersand && key != NULL) {
+ g_string_free (key, TRUE);
+ }
+ }
+
+ return res;
+}
diff --git a/src/libutil/http.h b/src/libutil/http.h
index 46c79ebb4..efd6d1e17 100644
--- a/src/libutil/http.h
+++ b/src/libutil/http.h
@@ -398,4 +398,12 @@ void rspamd_http_router_handle_socket (
*/
void rspamd_http_router_free (struct rspamd_http_connection_router *router);
+/**
+ * Extract arguments from a messsage's URI contained inside query string decoding
+ * them if needed
+ * @param msg HTTP request message
+ * @return new GHashTable which maps GString * to GString * (table must be freed by a caller)
+ */
+GHashTable* rspamd_http_message_parse_query (struct rspamd_http_message *msg);
+
#endif /* HTTP_H_ */