Sfoglia il codice sorgente

[http] Add support for HTTP POST

Allow HTTP POST requests to be generated when the URI includes a
parameter list.  For example:

  #!ipxe
  params
  param mac ${net0/mac}
  param uuid ${uuid}
  param asset ${asset}
  chain http://boot.ipxe.org/demo/boot.php##params

Signed-off-by: Michael Brown <mcb30@ipxe.org>
tags/v1.20.1
Michael Brown 10 anni fa
parent
commit
82e452d427
1 ha cambiato i file con 121 aggiunte e 3 eliminazioni
  1. 121
    3
      src/net/tcp/httpcore.c

+ 121
- 3
src/net/tcp/httpcore.c Vedi File

@@ -49,6 +49,7 @@ FILE_LICENCE ( GPL2_OR_LATER );
49 49
 #include <ipxe/blockdev.h>
50 50
 #include <ipxe/acpi.h>
51 51
 #include <ipxe/version.h>
52
+#include <ipxe/params.h>
52 53
 #include <ipxe/http.h>
53 54
 
54 55
 /* Disambiguate the various error causes */
@@ -1059,17 +1060,101 @@ static char * http_digest_auth ( struct http_request *http,
1059 1060
 	return auth;
1060 1061
 }
1061 1062
 
1063
+/**
1064
+ * Generate HTTP POST parameter list
1065
+ *
1066
+ * @v http		HTTP request
1067
+ * @v buf		Buffer to contain HTTP POST parameters
1068
+ * @v len		Length of buffer
1069
+ * @ret len		Length of parameter list (excluding terminating NUL)
1070
+ */
1071
+static size_t http_post_params ( struct http_request *http,
1072
+				 char *buf, size_t len ) {
1073
+	struct parameter *param;
1074
+	ssize_t remaining = len;
1075
+	size_t frag_len;
1076
+
1077
+	/* Add each parameter in the form "key=value", joined with "&" */
1078
+	len = 0;
1079
+	for_each_param ( param, http->uri->params ) {
1080
+
1081
+		/* Add the "&", if applicable */
1082
+		if ( len ) {
1083
+			if ( remaining > 0 )
1084
+				*buf = '&';
1085
+			buf++;
1086
+			len++;
1087
+			remaining--;
1088
+		}
1089
+
1090
+		/* URI-encode the key */
1091
+		frag_len = uri_encode ( param->key, buf, remaining, 0 );
1092
+		buf += frag_len;
1093
+		len += frag_len;
1094
+		remaining -= frag_len;
1095
+
1096
+		/* Add the "=" */
1097
+		if ( remaining > 0 )
1098
+			*buf = '=';
1099
+		buf++;
1100
+		len++;
1101
+		remaining--;
1102
+
1103
+		/* URI-encode the value */
1104
+		frag_len = uri_encode ( param->value, buf, remaining, 0 );
1105
+		buf += frag_len;
1106
+		len += frag_len;
1107
+		remaining -= frag_len;
1108
+	}
1109
+
1110
+	/* Ensure string is NUL-terminated even if no parameters are present */
1111
+	if ( remaining > 0 )
1112
+		*buf = '\0';
1113
+
1114
+	return len;
1115
+}
1116
+
1117
+/**
1118
+ * Generate HTTP POST body
1119
+ *
1120
+ * @v http		HTTP request
1121
+ * @ret post		I/O buffer containing POST body, or NULL on error
1122
+ */
1123
+static struct io_buffer * http_post ( struct http_request *http ) {
1124
+	struct io_buffer *post;
1125
+	size_t len;
1126
+	size_t check_len;
1127
+
1128
+	/* Calculate length of parameter list */
1129
+	len = http_post_params ( http, NULL, 0 );
1130
+
1131
+	/* Allocate parameter list */
1132
+	post = alloc_iob ( len + 1 /* NUL */ );
1133
+	if ( ! post )
1134
+		return NULL;
1135
+
1136
+	/* Fill parameter list */
1137
+	check_len = http_post_params ( http, iob_put ( post, len ),
1138
+				       ( len + 1 /* NUL */ ) );
1139
+	assert ( len == check_len );
1140
+	DBGC ( http, "HTTP %p POST %s\n", http, ( ( char * ) post->data ) );
1141
+
1142
+	return post;
1143
+}
1144
+
1062 1145
 /**
1063 1146
  * HTTP process
1064 1147
  *
1065 1148
  * @v http		HTTP request
1066 1149
  */
1067 1150
 static void http_step ( struct http_request *http ) {
1151
+	struct io_buffer *post;
1068 1152
 	size_t uri_len;
1069 1153
 	char *method;
1070 1154
 	char *uri;
1071 1155
 	char *range;
1072 1156
 	char *auth;
1157
+	char *content;
1073 1158
 	int len;
1074 1159
 	int rc;
1075 1160
 
@@ -1088,7 +1173,8 @@ static void http_step ( struct http_request *http ) {
1088 1173
 	}
1089 1174
 
1090 1175
 	/* Determine method */
1091
-	method = ( ( http->flags & HTTP_HEAD_ONLY ) ? "HEAD" : "GET" );
1176
+	method = ( ( http->flags & HTTP_HEAD_ONLY ) ? "HEAD" :
1177
+		   ( http->uri->params ? "POST" : "GET" ) );
1092 1178
 
1093 1179
 	/* Construct path?query request */
1094 1180
 	uri_len = ( unparse_uri ( NULL, 0, http->uri,
@@ -1136,6 +1222,25 @@ static void http_step ( struct http_request *http ) {
1136 1222
 		auth = NULL;
1137 1223
 	}
1138 1224
 
1225
+	/* Construct POST content, if applicable */
1226
+	if ( http->uri->params ) {
1227
+		post = http_post ( http );
1228
+		if ( ! post ) {
1229
+			rc = -ENOMEM;
1230
+			goto err_post;
1231
+		}
1232
+		len = asprintf ( &content, "Content-Type: "
1233
+				 "application/x-www-form-urlencoded\r\n"
1234
+				 "Content-Length: %zd\r\n", iob_len ( post ) );
1235
+		if ( len < 0 ) {
1236
+			rc = len;
1237
+			goto err_content;
1238
+		}
1239
+	} else {
1240
+		post = NULL;
1241
+		content = NULL;
1242
+	}
1243
+
1139 1244
 	/* Mark request as transmitted */
1140 1245
 	http->flags &= ~HTTP_TX_PENDING;
1141 1246
 
@@ -1144,7 +1249,7 @@ static void http_step ( struct http_request *http ) {
1144 1249
 				  "%s %s HTTP/1.1\r\n"
1145 1250
 				  "User-Agent: iPXE/%s\r\n"
1146 1251
 				  "Host: %s%s%s\r\n"
1147
-				  "%s%s%s"
1252
+				  "%s%s%s%s"
1148 1253
 				  "\r\n",
1149 1254
 				  method, uri, product_version, http->uri->host,
1150 1255
 				  ( http->uri->port ?
@@ -1154,11 +1259,24 @@ static void http_step ( struct http_request *http ) {
1154 1259
 				  ( ( http->flags & HTTP_CLIENT_KEEPALIVE ) ?
1155 1260
 				    "Connection: keep-alive\r\n" : "" ),
1156 1261
 				  ( range ? range : "" ),
1157
-				  ( auth ? auth : "" ) ) ) != 0 ) {
1262
+				  ( auth ? auth : "" ),
1263
+				  ( content ? content : "" ) ) ) != 0 ) {
1158 1264
 		goto err_xfer;
1159 1265
 	}
1160 1266
 
1267
+	/* Send POST content, if applicable */
1268
+	if ( post ) {
1269
+		if ( ( rc = xfer_deliver_iob ( &http->socket,
1270
+					       iob_disown ( post ) ) ) != 0 )
1271
+			goto err_xfer_post;
1272
+	}
1273
+
1274
+ err_xfer_post:
1161 1275
  err_xfer:
1276
+	free ( content );
1277
+ err_content:
1278
+	free ( post );
1279
+ err_post:
1162 1280
 	free ( auth );
1163 1281
  err_auth:
1164 1282
 	free ( range );

Loading…
Annulla
Salva