[http] Avoid using stack-allocated memory in http_step()
http_step() allocates a potentially large block of storage (since the URI can be arbitrarily long), and can be invoked as part of an already deep call stack via xfer_window_changed(). Signed-off-by: Michael Brown <mcb30@ipxe.org>
This commit is contained in:
parent
a026a27f04
commit
45e0327987
|
@ -643,14 +643,16 @@ static void http_step ( struct http_request *http ) {
|
||||||
size_t user_pw_len = ( user ? ( strlen ( user ) + 1 /* ":" */ +
|
size_t user_pw_len = ( user ? ( strlen ( user ) + 1 /* ":" */ +
|
||||||
strlen ( password ) ) : 0 );
|
strlen ( password ) ) : 0 );
|
||||||
size_t user_pw_base64_len = base64_encoded_len ( user_pw_len );
|
size_t user_pw_base64_len = base64_encoded_len ( user_pw_len );
|
||||||
uint8_t user_pw[ user_pw_len + 1 /* NUL */ ];
|
|
||||||
char user_pw_base64[ user_pw_base64_len + 1 /* NUL */ ];
|
|
||||||
int rc;
|
|
||||||
int request_len = unparse_uri ( NULL, 0, http->uri,
|
int request_len = unparse_uri ( NULL, 0, http->uri,
|
||||||
URI_PATH_BIT | URI_QUERY_BIT );
|
URI_PATH_BIT | URI_QUERY_BIT );
|
||||||
char request[ request_len + 1 /* NUL */ ];
|
struct {
|
||||||
char range[48]; /* Enough for two 64-bit integers in decimal */
|
uint8_t user_pw[ user_pw_len + 1 /* NUL */ ];
|
||||||
|
char user_pw_base64[ user_pw_base64_len + 1 /* NUL */ ];
|
||||||
|
char request[ request_len + 1 /* NUL */ ];
|
||||||
|
char range[48]; /* Enough for two 64-bit integers in decimal */
|
||||||
|
} *dynamic;
|
||||||
int partial;
|
int partial;
|
||||||
|
int rc;
|
||||||
|
|
||||||
/* Do nothing if we have already transmitted the request */
|
/* Do nothing if we have already transmitted the request */
|
||||||
if ( ! ( http->flags & HTTP_TX_PENDING ) )
|
if ( ! ( http->flags & HTTP_TX_PENDING ) )
|
||||||
|
@ -660,18 +662,27 @@ static void http_step ( struct http_request *http ) {
|
||||||
if ( ! xfer_window ( &http->socket ) )
|
if ( ! xfer_window ( &http->socket ) )
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
/* Allocate dynamic storage */
|
||||||
|
dynamic = malloc ( sizeof ( *dynamic ) );
|
||||||
|
if ( ! malloc ) {
|
||||||
|
rc = -ENOMEM;
|
||||||
|
goto err_alloc;
|
||||||
|
}
|
||||||
|
|
||||||
/* Construct path?query request */
|
/* Construct path?query request */
|
||||||
unparse_uri ( request, sizeof ( request ), http->uri,
|
unparse_uri ( dynamic->request, sizeof ( dynamic->request ), http->uri,
|
||||||
URI_PATH_BIT | URI_QUERY_BIT );
|
URI_PATH_BIT | URI_QUERY_BIT );
|
||||||
|
|
||||||
/* Construct authorisation, if applicable */
|
/* Construct authorisation, if applicable */
|
||||||
if ( user ) {
|
if ( user ) {
|
||||||
/* Make "user:password" string from decoded fields */
|
/* Make "user:password" string from decoded fields */
|
||||||
snprintf ( ( ( char * ) user_pw ), sizeof ( user_pw ),
|
snprintf ( ( ( char * ) dynamic->user_pw ),
|
||||||
"%s:%s", user, password );
|
sizeof ( dynamic->user_pw ), "%s:%s",
|
||||||
|
user, password );
|
||||||
|
|
||||||
/* Base64-encode the "user:password" string */
|
/* Base64-encode the "user:password" string */
|
||||||
base64_encode ( user_pw, user_pw_len, user_pw_base64 );
|
base64_encode ( dynamic->user_pw, user_pw_len,
|
||||||
|
dynamic->user_pw_base64 );
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Force a HEAD request if we have nowhere to send any received data */
|
/* Force a HEAD request if we have nowhere to send any received data */
|
||||||
|
@ -682,7 +693,8 @@ static void http_step ( struct http_request *http ) {
|
||||||
|
|
||||||
/* Determine type of request */
|
/* Determine type of request */
|
||||||
partial = ( http->partial_len != 0 );
|
partial = ( http->partial_len != 0 );
|
||||||
snprintf ( range, sizeof ( range ), "%zd-%zd", http->partial_start,
|
snprintf ( dynamic->range, sizeof ( dynamic->range ),
|
||||||
|
"%zd-%zd", http->partial_start,
|
||||||
( http->partial_start + http->partial_len - 1 ) );
|
( http->partial_start + http->partial_len - 1 ) );
|
||||||
|
|
||||||
/* Mark request as transmitted */
|
/* Mark request as transmitted */
|
||||||
|
@ -698,7 +710,7 @@ static void http_step ( struct http_request *http ) {
|
||||||
( ( http->flags & HTTP_HEAD_ONLY ) ?
|
( ( http->flags & HTTP_HEAD_ONLY ) ?
|
||||||
"HEAD" : "GET" ),
|
"HEAD" : "GET" ),
|
||||||
( http->uri->path ? "" : "/" ),
|
( http->uri->path ? "" : "/" ),
|
||||||
request, host,
|
dynamic->request, host,
|
||||||
( http->uri->port ?
|
( http->uri->port ?
|
||||||
":" : "" ),
|
":" : "" ),
|
||||||
( http->uri->port ?
|
( http->uri->port ?
|
||||||
|
@ -706,14 +718,20 @@ static void http_step ( struct http_request *http ) {
|
||||||
( ( http->flags & HTTP_KEEPALIVE ) ?
|
( ( http->flags & HTTP_KEEPALIVE ) ?
|
||||||
"Connection: Keep-Alive\r\n" : "" ),
|
"Connection: Keep-Alive\r\n" : "" ),
|
||||||
( partial ? "Range: bytes=" : "" ),
|
( partial ? "Range: bytes=" : "" ),
|
||||||
( partial ? range : "" ),
|
( partial ? dynamic->range : "" ),
|
||||||
( partial ? "\r\n" : "" ),
|
( partial ? "\r\n" : "" ),
|
||||||
( user ?
|
( user ?
|
||||||
"Authorization: Basic " : "" ),
|
"Authorization: Basic " : "" ),
|
||||||
( user ? user_pw_base64 : "" ),
|
( user ? dynamic->user_pw_base64 : "" ),
|
||||||
( user ? "\r\n" : "" ) ) ) != 0 ) {
|
( user ? "\r\n" : "" ) ) ) != 0 ) {
|
||||||
http_close ( http, rc );
|
goto err_xfer;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
err_xfer:
|
||||||
|
free ( dynamic );
|
||||||
|
err_alloc:
|
||||||
|
if ( rc != 0 )
|
||||||
|
http_close ( http, rc );
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
Reference in New Issue