Browse Source

New API function mg_split_form_encoded (#856)

bel2125 5 years ago
parent
commit
91d38a7149
2 changed files with 125 additions and 4 deletions
  1. 36 4
      include/civetweb.h
  2. 89 0
      src/civetweb.c

+ 36 - 4
include/civetweb.h

@@ -141,6 +141,10 @@ struct mg_header {
 };
 
 
+/* Maximum number of form fields for mg_spit_form_encoded. */
+#define MG_MAX_FORM_FIELDS (64)
+
+
 /* This structure contains information about the HTTP request. */
 struct mg_request_info {
 	const char *request_method;  /* "GET", "POST", etc */
@@ -1123,10 +1127,9 @@ CIVETWEB_API int mg_get_var(const char *data,
      var_name: variable name to decode from the buffer
      dst: destination buffer for the decoded variable
      dst_len: length of the destination buffer
-     occurrence: which occurrence of the variable, 0 is the first, 1 the
-                 second...
-                this makes it possible to parse a query like
-                b=x&a=y&a=z which will have occurrence values b:0, a:0 and a:1
+     occurrence: which occurrence of the variable, 0 is the 1st, 1 the 2nd, ...
+                 this makes it possible to parse a query like
+                 b=x&a=y&a=z which will have occurrence values b:0, a:0 and a:1
 
    Return:
      On success, length of the decoded variable.
@@ -1145,6 +1148,35 @@ CIVETWEB_API int mg_get_var2(const char *data,
                              size_t occurrence);
 
 
+/* Split form encoded data into a list of key value pairs.
+   A form encoded input might be a query string, the body of a
+   x-www-form-urlencoded POST request or any other data with this
+   structure: "keyName1=value1&keyName2=value2&keyName3=value3".
+   Values might be percent-encoded - this function will transform
+   them to the unencoded characters.
+   The input string is modified by this function: To split the
+   "query_string" member of struct request_info, create a copy first
+   (e.g., using strdup).
+   The function itself does not allocate memory. Thus, it is not
+   required to free any pointer returned from this function.
+   The output list of is limited to MG_MAX_FORM_FIELDS name-value-
+   pairs. The default value is reasonably oversized for typical
+   applications, however, for special purpose systems it might be
+   required to increase this value at compile time.
+
+   Parameters:
+     data: form encoded iput string. Will be modified by this function.
+     form_fields: output list of name/value-pairs.
+
+   Return:
+     On success: number of form_fields filled
+     On error:
+        -1 (parameter error). */
+CIVETWEB_API int
+mg_split_form_encoded(char *data,
+                      struct mg_header form_fields[MG_MAX_FORM_FIELDS]);
+
+
 /* Fetch value of certain cookie variable into the destination buffer.
 
    Destination buffer is guaranteed to be '\0' - terminated. In case of

+ 89 - 0
src/civetweb.c

@@ -7204,6 +7204,32 @@ mg_url_decode(const char *src,
 }
 
 
+/* form url decoding of an entire string */
+void
+url_decode_in_place(char *buf)
+{
+	size_t len = strlen(buf);
+	while (*buf) {
+		if (*buf == '%') {
+			if (isxdigit((unsigned char)buf[1])) {
+				if (isxdigit((unsigned char)buf[2])) {
+					int a = tolower((unsigned char)buf[1]);
+					int b = tolower((unsigned char)buf[2]);
+					char c = (char)((HEXTOI(a) << 4) | HEXTOI(b));
+					memmove(buf + 1, buf + 3, len - 2);
+					*buf = c;
+					len -= 2;
+				}
+			}
+		} else if (*buf == '+') {
+			*buf = ' ';
+		}
+		buf++;
+		len--;
+	}
+}
+
+
 int
 mg_get_var(const char *data,
            size_t data_len,
@@ -7272,6 +7298,69 @@ mg_get_var2(const char *data,
 }
 
 
+/* split a string "key1=val1&key2=val2" into key/value pairs */
+int
+mg_split_form_encoded(char *data,
+                      struct mg_header form_fields[MG_MAX_FORM_FIELDS])
+{
+	char *b;
+	int i;
+	int num = 0;
+
+	if ((data == NULL) || (form_fields == NULL)) {
+		/* parameter error */
+		return -1;
+	}
+
+	for (i = 0; i < MG_MAX_FORM_FIELDS; i++) {
+		/* extract key-value pairs from input data */
+		while ((*data == ' ') || (*data == '\t')) {
+			/* skip initial spaces */
+			data++;
+		}
+		if (*data = 0) {
+			/* end of string reached */
+			break;
+		}
+		form_fields[num].name = data;
+		b = strchr(data, '=');
+		if (b == NULL) {
+			/* key without value */
+			form_fields[num].value = NULL;
+		} else {
+			/* terminate string */
+			*b = 0;
+			/* value starts after '=' */
+			form_fields[num].value = b + 1;
+		}
+
+		/* new field is stored */
+		num++;
+
+		/* find a next key */
+		b = strchr(data, '&');
+		if (b == 0) {
+			/* no more data */
+			break;
+		} else {
+			/* terminate value of last field at '&' */
+			*b = 0;
+			/* next key-value-pairs starts after '&' */
+			data = b + 1;
+		}
+	}
+
+	/* Decode all values */
+	for (i = 0; i < num; i++) {
+		url_decode_in_place(form_fields[num].name);
+		url_decode_in_place(form_fields[num].value);
+	}
+
+	/* return number of fields found */
+	return num;
+}
+
+
 /* HCP24: some changes to compare hole var_name */
 int
 mg_get_cookie(const char *cookie_header,