mirror of https://github.com/ipxe/ipxe.git
[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>pull/14/head
parent
e52380fa3b
commit
82e452d427
|
@ -49,6 +49,7 @@ FILE_LICENCE ( GPL2_OR_LATER );
|
||||||
#include <ipxe/blockdev.h>
|
#include <ipxe/blockdev.h>
|
||||||
#include <ipxe/acpi.h>
|
#include <ipxe/acpi.h>
|
||||||
#include <ipxe/version.h>
|
#include <ipxe/version.h>
|
||||||
|
#include <ipxe/params.h>
|
||||||
#include <ipxe/http.h>
|
#include <ipxe/http.h>
|
||||||
|
|
||||||
/* Disambiguate the various error causes */
|
/* Disambiguate the various error causes */
|
||||||
|
@ -1059,17 +1060,101 @@ static char * http_digest_auth ( struct http_request *http,
|
||||||
return auth;
|
return auth;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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
|
* HTTP process
|
||||||
*
|
*
|
||||||
* @v http HTTP request
|
* @v http HTTP request
|
||||||
*/
|
*/
|
||||||
static void http_step ( struct http_request *http ) {
|
static void http_step ( struct http_request *http ) {
|
||||||
|
struct io_buffer *post;
|
||||||
size_t uri_len;
|
size_t uri_len;
|
||||||
char *method;
|
char *method;
|
||||||
char *uri;
|
char *uri;
|
||||||
char *range;
|
char *range;
|
||||||
char *auth;
|
char *auth;
|
||||||
|
char *content;
|
||||||
int len;
|
int len;
|
||||||
int rc;
|
int rc;
|
||||||
|
|
||||||
|
@ -1088,7 +1173,8 @@ static void http_step ( struct http_request *http ) {
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Determine method */
|
/* 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 */
|
/* Construct path?query request */
|
||||||
uri_len = ( unparse_uri ( NULL, 0, http->uri,
|
uri_len = ( unparse_uri ( NULL, 0, http->uri,
|
||||||
|
@ -1136,6 +1222,25 @@ static void http_step ( struct http_request *http ) {
|
||||||
auth = NULL;
|
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 */
|
/* Mark request as transmitted */
|
||||||
http->flags &= ~HTTP_TX_PENDING;
|
http->flags &= ~HTTP_TX_PENDING;
|
||||||
|
|
||||||
|
@ -1144,7 +1249,7 @@ static void http_step ( struct http_request *http ) {
|
||||||
"%s %s HTTP/1.1\r\n"
|
"%s %s HTTP/1.1\r\n"
|
||||||
"User-Agent: iPXE/%s\r\n"
|
"User-Agent: iPXE/%s\r\n"
|
||||||
"Host: %s%s%s\r\n"
|
"Host: %s%s%s\r\n"
|
||||||
"%s%s%s"
|
"%s%s%s%s"
|
||||||
"\r\n",
|
"\r\n",
|
||||||
method, uri, product_version, http->uri->host,
|
method, uri, product_version, http->uri->host,
|
||||||
( http->uri->port ?
|
( http->uri->port ?
|
||||||
|
@ -1154,11 +1259,24 @@ static void http_step ( struct http_request *http ) {
|
||||||
( ( http->flags & HTTP_CLIENT_KEEPALIVE ) ?
|
( ( http->flags & HTTP_CLIENT_KEEPALIVE ) ?
|
||||||
"Connection: keep-alive\r\n" : "" ),
|
"Connection: keep-alive\r\n" : "" ),
|
||||||
( range ? range : "" ),
|
( range ? range : "" ),
|
||||||
( auth ? auth : "" ) ) ) != 0 ) {
|
( auth ? auth : "" ),
|
||||||
|
( content ? content : "" ) ) ) != 0 ) {
|
||||||
goto err_xfer;
|
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:
|
err_xfer:
|
||||||
|
free ( content );
|
||||||
|
err_content:
|
||||||
|
free ( post );
|
||||||
|
err_post:
|
||||||
free ( auth );
|
free ( auth );
|
||||||
err_auth:
|
err_auth:
|
||||||
free ( range );
|
free ( range );
|
||||||
|
|
Loading…
Reference in New Issue