|
@@ -48,6 +48,12 @@ FILE_LICENCE ( GPL2_OR_LATER );
|
48
|
48
|
|
49
|
49
|
FEATURE ( FEATURE_PROTOCOL, "HTTP", DHCP_EB_FEATURE_HTTP, 1 );
|
50
|
50
|
|
|
51
|
+/** HTTP transmission state */
|
|
52
|
+enum http_tx_state {
|
|
53
|
+ HTTP_TX_REQUEST = 0,
|
|
54
|
+ HTTP_TX_DONE,
|
|
55
|
+};
|
|
56
|
+
|
51
|
57
|
/** HTTP receive state */
|
52
|
58
|
enum http_rx_state {
|
53
|
59
|
HTTP_RX_RESPONSE = 0,
|
|
@@ -75,6 +81,8 @@ struct http_request {
|
75
|
81
|
|
76
|
82
|
/** TX process */
|
77
|
83
|
struct process process;
|
|
84
|
+ /** TX state */
|
|
85
|
+ enum http_tx_state tx_state;
|
78
|
86
|
|
79
|
87
|
/** HTTP response code */
|
80
|
88
|
unsigned int response;
|
|
@@ -498,49 +506,55 @@ static void http_step ( struct http_request *http ) {
|
498
|
506
|
int rc;
|
499
|
507
|
int request_len = unparse_uri ( NULL, 0, http->uri,
|
500
|
508
|
URI_PATH_BIT | URI_QUERY_BIT );
|
|
509
|
+ char request[ request_len + 1 /* NUL */ ];
|
501
|
510
|
|
502
|
|
- if ( xfer_window ( &http->socket ) ) {
|
503
|
|
- char request[request_len + 1];
|
|
511
|
+ /* Do nothing if we have already transmitted the request */
|
|
512
|
+ if ( http->tx_state != HTTP_TX_REQUEST )
|
|
513
|
+ return;
|
504
|
514
|
|
505
|
|
- /* Construct path?query request */
|
506
|
|
- unparse_uri ( request, sizeof ( request ), http->uri,
|
507
|
|
- URI_PATH_BIT | URI_QUERY_BIT );
|
|
515
|
+ /* Do nothing until socket is ready */
|
|
516
|
+ if ( ! xfer_window ( &http->socket ) )
|
|
517
|
+ return;
|
508
|
518
|
|
509
|
|
- /* We want to execute only once */
|
510
|
|
- process_del ( &http->process );
|
|
519
|
+ /* Construct path?query request */
|
|
520
|
+ unparse_uri ( request, sizeof ( request ), http->uri,
|
|
521
|
+ URI_PATH_BIT | URI_QUERY_BIT );
|
511
|
522
|
|
512
|
|
- /* Construct authorisation, if applicable */
|
513
|
|
- if ( user ) {
|
514
|
|
- /* Make "user:password" string from decoded fields */
|
515
|
|
- snprintf ( ( ( char * ) user_pw ), sizeof ( user_pw ),
|
516
|
|
- "%s:%s", user, password );
|
|
523
|
+ /* Construct authorisation, if applicable */
|
|
524
|
+ if ( user ) {
|
|
525
|
+ /* Make "user:password" string from decoded fields */
|
|
526
|
+ snprintf ( ( ( char * ) user_pw ), sizeof ( user_pw ),
|
|
527
|
+ "%s:%s", user, password );
|
517
|
528
|
|
518
|
|
- /* Base64-encode the "user:password" string */
|
519
|
|
- base64_encode ( user_pw, user_pw_len, user_pw_base64 );
|
520
|
|
- }
|
|
529
|
+ /* Base64-encode the "user:password" string */
|
|
530
|
+ base64_encode ( user_pw, user_pw_len, user_pw_base64 );
|
|
531
|
+ }
|
521
|
532
|
|
522
|
|
- /* Send GET request */
|
523
|
|
- if ( ( rc = xfer_printf ( &http->socket,
|
524
|
|
- "GET %s%s HTTP/1.1\r\n"
|
525
|
|
- "User-Agent: iPXE/" VERSION "\r\n"
|
526
|
|
- "%s%s%s"
|
527
|
|
- "Host: %s\r\n"
|
528
|
|
- "\r\n",
|
529
|
|
- http->uri->path ? "" : "/",
|
530
|
|
- request,
|
531
|
|
- ( user ?
|
532
|
|
- "Authorization: Basic " : "" ),
|
533
|
|
- ( user ? user_pw_base64 : "" ),
|
534
|
|
- ( user ? "\r\n" : "" ),
|
535
|
|
- host ) ) != 0 ) {
|
536
|
|
- http_done ( http, rc );
|
537
|
|
- }
|
|
533
|
+ /* Mark request as transmitted */
|
|
534
|
+ http->tx_state = HTTP_TX_DONE;
|
|
535
|
+
|
|
536
|
+ /* Send GET request */
|
|
537
|
+ if ( ( rc = xfer_printf ( &http->socket,
|
|
538
|
+ "GET %s%s HTTP/1.1\r\n"
|
|
539
|
+ "User-Agent: iPXE/" VERSION "\r\n"
|
|
540
|
+ "%s%s%s"
|
|
541
|
+ "Host: %s\r\n"
|
|
542
|
+ "\r\n",
|
|
543
|
+ http->uri->path ? "" : "/",
|
|
544
|
+ request,
|
|
545
|
+ ( user ?
|
|
546
|
+ "Authorization: Basic " : "" ),
|
|
547
|
+ ( user ? user_pw_base64 : "" ),
|
|
548
|
+ ( user ? "\r\n" : "" ),
|
|
549
|
+ host ) ) != 0 ) {
|
|
550
|
+ http_done ( http, rc );
|
538
|
551
|
}
|
539
|
552
|
}
|
540
|
553
|
|
541
|
554
|
/** HTTP socket interface operations */
|
542
|
555
|
static struct interface_operation http_socket_operations[] = {
|
543
|
556
|
INTF_OP ( xfer_deliver, struct http_request *, http_socket_deliver ),
|
|
557
|
+ INTF_OP ( xfer_window_changed, struct http_request *, http_step ),
|
544
|
558
|
INTF_OP ( intf_close, struct http_request *, http_done ),
|
545
|
559
|
};
|
546
|
560
|
|
|
@@ -561,7 +575,7 @@ static struct interface_descriptor http_xfer_desc =
|
561
|
575
|
|
562
|
576
|
/** HTTP process descriptor */
|
563
|
577
|
static struct process_descriptor http_process_desc =
|
564
|
|
- PROC_DESC ( struct http_request, process, http_step );
|
|
578
|
+ PROC_DESC_ONCE ( struct http_request, process, http_step );
|
565
|
579
|
|
566
|
580
|
/**
|
567
|
581
|
* Initiate an HTTP connection, with optional filter
|