Do modułu “base” dodałem podstawową obsługę klienta HTTP/1.1 i HTTP/2, korzystając z szyfrowania TLS zapewnianego przez OpenSSL. Procedura inicjująca połączenie automatycznie negocjuje najwyższy możliwy standard HTTP spośród tych dwóch (nie ma możliwości wyboru).
Kod klienta znajduje się w plikach: “net-cli.cx”, “net-http.cx” i “net-http2.cx”.
Klient realizuje pojedyncze żądanie i wraca z tekstem odpowiedzi znajdującym się w pliku tymczasowym.
Procedura realizacji żądania
Najpierw należy utworzyć kontekst SSL procedurą “E_net_cli_Q_ssl_M”. Następnie połączyć się z serwerem procedurą “E_net_cli_Q_ssl_I_connect”, która wraca z flagą, czy udało się wynegocjować HTTP/2. Wtedy można wysłać żądanie pobrania ścieżki na serwerze przez HTTP/2 procedurą “E_net_http2_I_request” lub przez HTTP/1.1 procedurą “E_net_http_I_request”; zależnie od tego, której wersji wynegocjowano połączenie.
Klient HTTP wykorzystuje ‹raport› “ret” modułu “net”, więc można na niego czekać, oczekując na tekst odpowiedzi. Procedury *“_I_request” otrzymują jako argument procedurę ‘callback’, która jest wywoływana, gdy otrzymano tekst odpowiedzi z serwera. Ta procedura ‘callback’ otrzyma jako argument numer połączenia, a dla HTTP/2 dodatkowo identyfikator strumienia w połączeniu. Procedury ‘callback’ powinny usunąć plik tymczasowy po jego użyciu. Ponadto procedura ‘callback’ połączenia HTTP/1.1 musi zasygnalizować wykonanie, zerując wskaźnik do samej siebie w zmiennej “ret_func” struktury połączenia.
Na końcu można rozłączyć pozostałe połączenia z serwerami i wyrzucić kontekst SSL procedurą “E_net_cli_Q_ssl_W”.
Demonstracyjny kod
N E_main_Q_http_req_ret_count;
void
http_req_ret_func( N connection_i
){ E_main_Q_http_req_ret_count++;
V0( unlink( E_net_http_S_connect[ connection_i ].file_name ) ){}
E_net_http_S_connect[ connection_i ].ret_func = 0;
}
void
http2_req_ret_func( N connection_i
, I stream_id
){ E_main_Q_http_req_ret_count++;
struct E_net_http2_Z_stream *stream = E_mem_Q_tab_R( E_net_http2_S_connect[ connection_i ].stream, stream_id );
V0( unlink( stream->file_name ) ){}
}
SSL_CTX *ssl_ctx = E_net_cli_Q_ssl_M();
if( !ssl_ctx )
goto End; // Nie udało się utworzyć kontekstu SSL.
B http2;
N connection = E_net_cli_Q_ssl_I_connect( ssl_ctx, "gentoo", &http2 );
if( !~connection )
goto Skip; // Nie udało się utworzyć połączenia.
if(http2)
{ N ret = E_net_http2_I_request( connection, "/", http2_req_ret_func );
if(ret)
goto Skip; // Nie udało się wysłać ścieżki żądania.
ret = E_net_http2_I_request( connection, "/", http2_req_ret_func );
if(ret)
goto Skip; // Nie udało się wysłać ścieżki żądania.
}else
{ N ret = E_net_http_I_request( connection, "/", http_req_ret_func );
if(ret)
goto Skip; // Nie udało się wysłać ścieżki żądania.
}
X_M( net, ret );
E_main_Q_http_req_ret_count = 0;
O{ X_B( net, ret, 0 )
break;
if(( http2
&& ( !E_net_http2_S_connect_n
|| E_main_Q_http_req_ret_count == 2 // Zrealizowano dwa połączenia HTTP/2.
))
|| ( !http2
&& ( !E_net_http_S_connect_n
|| E_main_Q_http_req_ret_count == 1 // Zrealizowano jedno połączenie HTTP/1.1.
)))
break;
}
Skip:
E_net_cli_Q_ssl_W( ssl_ctx );
End:;
W tym programie wykonywane jest dwukrotnie żądanie ścieżki “/”, jeśli połączono przez HTTP/2, a jednokrotnie, jeśli połączono przez HTTP/1.1. Stąd oczekiwanie na licznik zrealizowanych połączeń równy 2 lub 1.
Zewnętrzne wykorzystanie kodu klienta
Plik “net-http2.cx” zawiera procedury obsługi kodowania i inne w protokole HTTP/2, które mogą być wykorzystane w programach i są wykorzystywane w programie serwera ‟OUX/C+ web-srv”.