Przeglądaj źródła

Alternative to mg_upload (Step 46/?)

bel 9 lat temu
rodzic
commit
30b7abbd20
2 zmienionych plików z 124 dodań i 107 usunięć
  1. 8 13
      examples/embedded_c/embedded_c.c
  2. 116 94
      src/handle_form.inl

+ 8 - 13
examples/embedded_c/embedded_c.c

@@ -159,11 +159,11 @@ FileHandler(struct mg_connection *conn, void *cbdata)
 /* proposed interface */
 
 enum {
-	FORM_DISPOSITION_SKIP = 0x0,
-	FORM_DISPOSITION_GET = 0x1,
-	FORM_DISPOSITION_STORE = 0x2,
-	/*	FORM_DISPOSITION_READ = 0x3, not in the first step */
-	FORM_DISPOSITION_ABORT = 0x10
+	FORM_FIELD_STORAGE_SKIP = 0x0,
+	FORM_FIELD_STORAGE_GET = 0x1,
+	FORM_FIELD_STORAGE_STORE = 0x2,
+	/*	FORM_FIELD_STORAGE_READ = 0x3, not in the first step */
+	FORM_FIELD_STORAGE_ABORT = 0x10
 };
 
 
@@ -174,7 +174,6 @@ struct mg_form_data_handler {
 	                   size_t pathlen,
 	                   void *user_data);
 	int (*field_get)(const char *key,
-	                 const char *filename,
 	                 const char *value,
 	                 size_t valuelen,
 	                 void *user_data);
@@ -202,18 +201,14 @@ field_found(const char *key,
 
 	if (filename && *filename) {
 		_snprintf(path, pathlen, "C:\\tmp\\%s", filename);
-		return FORM_DISPOSITION_STORE;
+		return FORM_FIELD_STORAGE_STORE;
 	}
-	return FORM_DISPOSITION_GET;
+	return FORM_FIELD_STORAGE_GET;
 }
 
 
 int
-field_get(const char *key,
-          const char *filename,
-          const char *value,
-          size_t valuelen,
-          void *user_data)
+field_get(const char *key, const char *value, size_t valuelen, void *user_data)
 {
 	struct mg_connection *conn = (struct mg_connection *)user_data;
 

+ 116 - 94
src/handle_form.inl

@@ -27,31 +27,78 @@
 /**********************/
 /* proposed interface */
 
-enum {
-	FORM_DISPOSITION_SKIP = 0x0,
-	FORM_DISPOSITION_GET = 0x1,
-	FORM_DISPOSITION_STORE = 0x2,
-	/*	FORM_DISPOSITION_READ = 0x3, not in the first step */
-	FORM_DISPOSITION_ABORT = 0x10
-};
-
 
+/* This structure contains callback functions for handling form fields.
+   It is used as an argument to mg_handle_form_data.
+*/
 struct mg_form_data_handler {
+	/* This callback is called, if a new field is about to be read.
+	 * Parameters:
+	 *   key: Name of the field ("name" property of the HTML input field).
+	 *   filename: Name of a file to upload, at the client computer.
+	 *             Only set for input fields of type "file", otherwise NULL.
+	 *   path: Output parameter: File name (incl. path) to store the file
+	 *         at the server computer. Only used if FORM_FIELD_STORAGE_STORE
+	 *         is returned by this callback.
+	 *   pathlen: Length of the buffer for path.
+	 *   user_data: Value of the member user_data of mg_form_data_handler
+	 * Return value:
+	 *   The callback must return the intended storage for this field
+	 *   (See FORM_FIELD_STORAGE_*).
+	 */
 	int (*field_found)(const char *key,
 	                   const char *filename,
 	                   char *path,
 	                   size_t pathlen,
 	                   void *user_data);
+
+	/* If the "field_found" callback returned FORM_FIELD_STORAGE_GET,
+	 * this callback will receive the field data.
+	 * Parameters:
+	 *   key: Name of the field ("name" property of the HTML input field).
+	 *   value: Value of the input field.
+	 *   user_data: Value of the member user_data of mg_form_data_handler
+	 * Return value:
+	 *   TODO: Needs to be defined.
+	 */
 	int (*field_get)(const char *key,
-	                 const char *filename,
 	                 const char *value,
 	                 size_t valuelen,
 	                 void *user_data);
+
+	/* If the "field_found" callback returned FORM_FIELD_STORAGE_STORE,
+	 * the data will be stored into a file. If the file has been written
+	 * sucessfully, this callback will be called.
+	 * Parameters:
+	 *   path: Path of the file stored at the server.
+	 *   user_data: Value of the member user_data of mg_form_data_handler
+	 * Return value:
+	 *   TODO: Needs to be defined.
+	 */
 	int (*field_stored)(const char *path, void *user_data);
+
+	/* User supplied argument, passed to all callbacks. */
 	void *user_data;
 };
 
 
+/* Return values definition for the "field_found" callback in
+ * mg_form_data_handler. */
+enum {
+	/* Skip this field (neither get nor store it). Continue with the
+     * next field. */
+	FORM_FIELD_STORAGE_SKIP = 0x0,
+	/* Get the field value. */
+	FORM_FIELD_STORAGE_GET = 0x1,
+	/* Store the field value into a file. */
+	FORM_FIELD_STORAGE_STORE = 0x2,
+	/* Read the filed in chunks using a read function. */
+	/*	FORM_FIELD_STORAGE_READ = 0x3, not in the first step */
+	/* Stop parsing this request. Skip the remaining fields. */
+	FORM_FIELD_STORAGE_ABORT = 0x10
+};
+
+
 int mg_handle_form_data(struct mg_connection *conn,
                         struct mg_form_data_handler *fdh);
 
@@ -77,7 +124,7 @@ url_encoded_field_found(const struct mg_connection *conn,
 	    mg_url_decode(key, (int)key_len, key_dec, (int)sizeof(key_dec), 1);
 
 	if (((size_t)key_dec_len >= (size_t)sizeof(key_dec)) || (key_dec_len < 0)) {
-		return FORM_DISPOSITION_SKIP;
+		return FORM_FIELD_STORAGE_SKIP;
 	}
 
 	if (filename) {
@@ -91,7 +138,7 @@ url_encoded_field_found(const struct mg_connection *conn,
 		    || (filename_dec_len < 0)) {
 			/* Log error message and skip this field. */
 			mg_cry(conn, "%s: Cannot decode filename", __func__);
-			return FORM_DISPOSITION_SKIP;
+			return FORM_FIELD_STORAGE_SKIP;
 		}
 	} else {
 		filename_dec[0] = 0;
@@ -106,14 +153,11 @@ static int
 url_encoded_field_get(const struct mg_connection *conn,
                       const char *key,
                       size_t key_len,
-                      const char *filename,
-                      size_t filename_len,
                       const char *value,
                       size_t value_len,
                       struct mg_form_data_handler *fdh)
 {
 	char key_dec[1024];
-	char filename_dec[1024];
 
 	char *value_dec = mg_malloc(value_len + 1);
 	int value_dec_len;
@@ -124,26 +168,15 @@ url_encoded_field_get(const struct mg_connection *conn,
 		       "%s: Not enough memory (required: %lu)",
 		       __func__,
 		       (unsigned long)(value_len + 1));
-		return FORM_DISPOSITION_ABORT;
+		return FORM_FIELD_STORAGE_ABORT;
 	}
 
 	mg_url_decode(key, (int)key_len, key_dec, (int)sizeof(key_dec), 1);
 
-	if (filename) {
-		mg_url_decode(filename,
-		              (int)filename_len,
-		              filename_dec,
-		              (int)sizeof(filename_dec),
-		              1);
-	} else {
-		filename_dec[0] = 0;
-	}
-
 	value_dec_len =
 	    mg_url_decode(value, (int)value_len, value_dec, (int)value_len + 1, 1);
 
 	return fdh->field_get(key_dec,
-	                      filename_dec,
 	                      value_dec,
 	                      (size_t)value_dec_len,
 	                      fdh->user_data);
@@ -202,7 +235,7 @@ mg_handle_form_data(struct mg_connection *conn,
 	const char *content_type;
 	char path[512];
 	char buf[1024];
-	int disposition;
+	int field_storage;
 	int buf_fill = 0;
 	int r;
 	FILE *fstore = NULL;
@@ -252,25 +285,25 @@ mg_handle_form_data(struct mg_connection *conn,
 			keylen = val - data;
 
 			/* In every "field_found" callback we ask what to do with the
-			 * data ("disposition"). This could be:
-			 * FORM_DISPOSITION_SKIP (0) ... ignore the value of this field
-			 * FORM_DISPOSITION_GET (1) ... read the data and call the get
+			 * data ("field_storage"). This could be:
+			 * FORM_FIELD_STORAGE_SKIP (0) ... ignore the value of this field
+			 * FORM_FIELD_STORAGE_GET (1) ... read the data and call the get
 			 *                              callback function
-			 * FORM_DISPOSITION_STORE (2) ... store the data in a file
-			 * FORM_DISPOSITION_READ (3) ... let the user read the data
+			 * FORM_FIELD_STORAGE_STORE (2) ... store the data in a file
+			 * FORM_FIELD_STORAGE_READ (3) ... let the user read the data
 			 *                               (for parsing long data on the fly)
 			 *                               (currently not implemented)
-			 * FORM_DISPOSITION_ABORT (flag) ... stop parsing
+			 * FORM_FIELD_STORAGE_ABORT (flag) ... stop parsing
 			 */
 			memset(path, 0, sizeof(path));
-			disposition = url_encoded_field_found(conn,
-			                                      data,
-			                                      (size_t)keylen,
-			                                      NULL,
-			                                      0,
-			                                      path,
-			                                      sizeof(path) - 1,
-			                                      fdh);
+			field_storage = url_encoded_field_found(conn,
+			                                        data,
+			                                        (size_t)keylen,
+			                                        NULL,
+			                                        0,
+			                                        path,
+			                                        sizeof(path) - 1,
+			                                        fdh);
 
 			val++;
 			next = strchr(val, '&');
@@ -282,18 +315,12 @@ mg_handle_form_data(struct mg_connection *conn,
 				next = val + vallen;
 			}
 
-			if (disposition == FORM_DISPOSITION_GET) {
+			if (field_storage == FORM_FIELD_STORAGE_GET) {
 				/* Call callback */
-				url_encoded_field_get(conn,
-				                      data,
-				                      (size_t)keylen,
-				                      NULL,
-				                      0,
-				                      val,
-				                      (size_t)vallen,
-				                      fdh);
+				url_encoded_field_get(
+				    conn, data, (size_t)keylen, val, (size_t)vallen, fdh);
 			}
-			if (disposition == FORM_DISPOSITION_STORE) {
+			if (field_storage == FORM_FIELD_STORAGE_STORE) {
 				/* Store the content to a file */
 				fstore = fopen(path, "wb");
 				if (fstore != NULL) {
@@ -328,21 +355,21 @@ mg_handle_form_data(struct mg_connection *conn,
 				}
 			}
 
-			/* if (disposition == FORM_DISPOSITION_READ) { */
-			/* The idea of "disposition=read" is to let the API user read
+			/* if (field_storage == FORM_FIELD_STORAGE_READ) { */
+			/* The idea of "field_storage=read" is to let the API user read
 			 * data chunk by chunk and to some data processing on the fly.
 			 * This should avoid the need to store data in the server:
 			 * It should neither be stored in memory, like
-			 * "disposition=get" does, nor in a file like
-			 * "disposition=store".
+			 * "field_storage=get" does, nor in a file like
+			 * "field_storage=store".
 			 * However, for a "GET" request this does not make any much
 			 * sense, since the data is already stored in memory, as it is
 			 * part of the query string.
 			 */
 			/* } */
 
-			if ((disposition & FORM_DISPOSITION_ABORT)
-			    == FORM_DISPOSITION_ABORT) {
+			if ((field_storage & FORM_FIELD_STORAGE_ABORT)
+			    == FORM_FIELD_STORAGE_ABORT) {
 				/* Stop parsing the request */
 				break;
 			}
@@ -406,22 +433,22 @@ mg_handle_form_data(struct mg_connection *conn,
 
 			/* Call callback */
 			memset(path, 0, sizeof(path));
-			disposition = url_encoded_field_found(conn,
-			                                      buf,
-			                                      (size_t)keylen,
-			                                      NULL,
-			                                      0,
-			                                      path,
-			                                      sizeof(path) - 1,
-			                                      fdh);
-
-			if ((disposition & FORM_DISPOSITION_ABORT)
-			    == FORM_DISPOSITION_ABORT) {
+			field_storage = url_encoded_field_found(conn,
+			                                        buf,
+			                                        (size_t)keylen,
+			                                        NULL,
+			                                        0,
+			                                        path,
+			                                        sizeof(path) - 1,
+			                                        fdh);
+
+			if ((field_storage & FORM_FIELD_STORAGE_ABORT)
+			    == FORM_FIELD_STORAGE_ABORT) {
 				/* Stop parsing the request */
 				break;
 			}
 
-			if (disposition == FORM_DISPOSITION_STORE) {
+			if (field_storage == FORM_FIELD_STORAGE_STORE) {
 				fstore = fopen(path, "wb");
 				if (!fstore) {
 					mg_cry(conn, "%s: Cannot create file %s", __func__, path);
@@ -452,7 +479,7 @@ mg_handle_form_data(struct mg_connection *conn,
 						remove_bad_file(conn, path);
 					}
 				}
-				if (disposition == FORM_DISPOSITION_GET) {
+				if (field_storage == FORM_FIELD_STORAGE_GET) {
 					if (!end_of_key_value_pair_found && !all_data_read) {
 						/* TODO: check for an easy way to get longer data */
 						mg_cry(conn,
@@ -461,14 +488,8 @@ mg_handle_form_data(struct mg_connection *conn,
 						return 0;
 					}
 					/* Call callback */
-					url_encoded_field_get(conn,
-					                      buf,
-					                      (size_t)keylen,
-					                      NULL,
-					                      0,
-					                      val,
-					                      (size_t)vallen,
-					                      fdh);
+					url_encoded_field_get(
+					    conn, buf, (size_t)keylen, val, (size_t)vallen, fdh);
 				}
 
 				if (!end_of_key_value_pair_found) {
@@ -629,20 +650,23 @@ mg_handle_form_data(struct mg_connection *conn,
 			}
 
 			memset(path, 0, sizeof(path));
-			disposition = url_encoded_field_found(conn,
-			                                      nbeg,
-			                                      (size_t)(nend - nbeg),
-			                                      fbeg,
-			                                      (size_t)(fend - fbeg),
-			                                      path,
-			                                      sizeof(path) - 1,
-			                                      fdh);
+			field_storage = url_encoded_field_found(conn,
+			                                        nbeg,
+			                                        (size_t)(nend - nbeg),
+			                                        fbeg,
+			                                        (size_t)(fend - fbeg),
+			                                        path,
+			                                        sizeof(path) - 1,
+			                                        fdh);
 
 			/* If the boundary is already in the buffer, get the address,
 			 * otherwise next will be NULL. */
-			next = search_boundary(hbuf, buf - hbuf + buf_fill, boundary, bl);
+			next = search_boundary(hbuf,
+			                       (size_t)((buf - hbuf) + buf_fill),
+			                       boundary,
+			                       bl);
 
-			if (disposition == FORM_DISPOSITION_GET) {
+			if (field_storage == FORM_FIELD_STORAGE_GET) {
 				if (!next) {
 					/* TODO: check for an easy way to get longer data */
 					mg_cry(conn, "%s: Data too long for callback", __func__);
@@ -653,14 +677,12 @@ mg_handle_form_data(struct mg_connection *conn,
 				url_encoded_field_get(conn,
 				                      nbeg,
 				                      (size_t)(nend - nbeg),
-				                      fbeg,
-				                      (size_t)(fend - fbeg),
 				                      hend,
 				                      (size_t)(next - hend),
 				                      fdh);
 			}
 
-			if (disposition == FORM_DISPOSITION_STORE) {
+			if (field_storage == FORM_FIELD_STORAGE_STORE) {
 				/* Store the content to a file */
 				size_t towrite, n;
 				size_t flen = 0;
@@ -715,7 +737,7 @@ mg_handle_form_data(struct mg_connection *conn,
 					}
 
 					/* Find boundary */
-					next = search_boundary(buf, buf_fill, boundary, bl);
+					next = search_boundary(buf, (size_t)buf_fill, boundary, bl);
 				}
 
 				if (fstore) {
@@ -749,8 +771,8 @@ mg_handle_form_data(struct mg_connection *conn,
 				}
 			}
 
-			if ((disposition & FORM_DISPOSITION_ABORT)
-			    == FORM_DISPOSITION_ABORT) {
+			if ((field_storage & FORM_FIELD_STORAGE_ABORT)
+			    == FORM_FIELD_STORAGE_ABORT) {
 				/* Stop parsing the request */
 				return 0;
 			}