summaryrefslogtreecommitdiffstats
path: root/src/net/tcp
diff options
context:
space:
mode:
authorMichael Brown2013-08-19 18:17:49 +0200
committerMichael Brown2013-08-19 18:22:58 +0200
commit82e452d4272ed447cbc302421cf1b3bf1ca2d8fd (patch)
tree0ab453aa5ce58a3ae9cbb23a783fa43c9aa28a96 /src/net/tcp
parent[uri] Allow URIs to incorporate a parameter list (diff)
downloadipxe-82e452d4272ed447cbc302421cf1b3bf1ca2d8fd.tar.gz
ipxe-82e452d4272ed447cbc302421cf1b3bf1ca2d8fd.tar.xz
ipxe-82e452d4272ed447cbc302421cf1b3bf1ca2d8fd.zip
[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>
Diffstat (limited to 'src/net/tcp')
-rw-r--r--src/net/tcp/httpcore.c124
1 files changed, 121 insertions, 3 deletions
diff --git a/src/net/tcp/httpcore.c b/src/net/tcp/httpcore.c
index bccb35f5..bfa7d7f7 100644
--- a/src/net/tcp/httpcore.c
+++ b/src/net/tcp/httpcore.c
@@ -49,6 +49,7 @@ FILE_LICENCE ( GPL2_OR_LATER );
#include <ipxe/blockdev.h>
#include <ipxe/acpi.h>
#include <ipxe/version.h>
+#include <ipxe/params.h>
#include <ipxe/http.h>
/* Disambiguate the various error causes */
@@ -1060,16 +1061,100 @@ static char * http_digest_auth ( struct http_request *http,
}
/**
+ * Generate HTTP POST parameter list
+ *
+ * @v http HTTP request
+ * @v buf Buffer to contain HTTP POST parameters
+ * @v len Length of buffer
+ * @ret len Length of parameter list (excluding terminating NUL)
+ */
+static size_t http_post_params ( struct http_request *http,
+ char *buf, size_t len ) {
+ struct parameter *param;
+ ssize_t remaining = len;
+ size_t frag_len;
+
+ /* Add each parameter in the form "key=value", joined with "&" */
+ len = 0;
+ for_each_param ( param, http->uri->params ) {
+
+ /* Add the "&", if applicable */
+ if ( len ) {
+ if ( remaining > 0 )
+ *buf = '&';
+ buf++;
+ len++;
+ remaining--;
+ }
+
+ /* URI-encode the key */
+ frag_len = uri_encode ( param->key, buf, remaining, 0 );
+ buf += frag_len;
+ len += frag_len;
+ remaining -= frag_len;
+
+ /* Add the "=" */
+ if ( remaining > 0 )
+ *buf = '=';
+ buf++;
+ len++;
+ remaining--;
+
+ /* URI-encode the value */
+ frag_len = uri_encode ( param->value, buf, remaining, 0 );
+ buf += frag_len;
+ len += frag_len;
+ remaining -= frag_len;
+ }
+
+ /* Ensure string is NUL-terminated even if no parameters are present */
+ if ( remaining > 0 )
+ *buf = '\0';
+
+ return len;
+}
+
+/**
+ * Generate HTTP POST body
+ *
+ * @v http HTTP request
+ * @ret post I/O buffer containing POST body, or NULL on error
+ */
+static struct io_buffer * http_post ( struct http_request *http ) {
+ struct io_buffer *post;
+ size_t len;
+ size_t check_len;
+
+ /* Calculate length of parameter list */
+ len = http_post_params ( http, NULL, 0 );
+
+ /* Allocate parameter list */
+ post = alloc_iob ( len + 1 /* NUL */ );
+ if ( ! post )
+ return NULL;
+
+ /* Fill parameter list */
+ check_len = http_post_params ( http, iob_put ( post, len ),
+ ( len + 1 /* NUL */ ) );
+ assert ( len == check_len );
+ DBGC ( http, "HTTP %p POST %s\n", http, ( ( char * ) post->data ) );
+
+ return post;
+}
+
+/**
* HTTP process
*
* @v http HTTP request
*/
static void http_step ( struct http_request *http ) {
+ struct io_buffer *post;
size_t uri_len;
char *method;
char *uri;
char *range;
char *auth;
+ char *content;
int len;
int rc;
@@ -1088,7 +1173,8 @@ static void http_step ( struct http_request *http ) {
}
/* Determine method */
- method = ( ( http->flags & HTTP_HEAD_ONLY ) ? "HEAD" : "GET" );
+ method = ( ( http->flags & HTTP_HEAD_ONLY ) ? "HEAD" :
+ ( http->uri->params ? "POST" : "GET" ) );
/* Construct path?query request */
uri_len = ( unparse_uri ( NULL, 0, http->uri,
@@ -1136,6 +1222,25 @@ static void http_step ( struct http_request *http ) {
auth = NULL;
}
+ /* Construct POST content, if applicable */
+ if ( http->uri->params ) {
+ post = http_post ( http );
+ if ( ! post ) {
+ rc = -ENOMEM;
+ goto err_post;
+ }
+ len = asprintf ( &content, "Content-Type: "
+ "application/x-www-form-urlencoded\r\n"
+ "Content-Length: %zd\r\n", iob_len ( post ) );
+ if ( len < 0 ) {
+ rc = len;
+ goto err_content;
+ }
+ } else {
+ post = NULL;
+ content = NULL;
+ }
+
/* Mark request as transmitted */
http->flags &= ~HTTP_TX_PENDING;
@@ -1144,7 +1249,7 @@ static void http_step ( struct http_request *http ) {
"%s %s HTTP/1.1\r\n"
"User-Agent: iPXE/%s\r\n"
"Host: %s%s%s\r\n"
- "%s%s%s"
+ "%s%s%s%s"
"\r\n",
method, uri, product_version, http->uri->host,
( http->uri->port ?
@@ -1154,11 +1259,24 @@ static void http_step ( struct http_request *http ) {
( ( http->flags & HTTP_CLIENT_KEEPALIVE ) ?
"Connection: keep-alive\r\n" : "" ),
( range ? range : "" ),
- ( auth ? auth : "" ) ) ) != 0 ) {
+ ( auth ? auth : "" ),
+ ( content ? content : "" ) ) ) != 0 ) {
goto err_xfer;
}
+ /* Send POST content, if applicable */
+ if ( post ) {
+ if ( ( rc = xfer_deliver_iob ( &http->socket,
+ iob_disown ( post ) ) ) != 0 )
+ goto err_xfer_post;
+ }
+
+ err_xfer_post:
err_xfer:
+ free ( content );
+ err_content:
+ free ( post );
+ err_post:
free ( auth );
err_auth:
free ( range );