I need a minimal SSL server and came up with the following:
confirm(WSAStartup(MakeWord(1,1), WData) = 0);
SSL_library_init;
SSL_load_error_strings;
ctx := SSL_CTX_new(SSLv23_server_method);
confirm(ctx <> nil);
confirm(SSL_CTX_use_certificate_chain_file(ctx, 'cert.pem') > 0);
confirm(SSL_CTX_use_PrivateKey_file(ctx, 'key.pem', SSL_FILETYPE_PEM) > 0);
confirm(SSL_CTX_check_private_key(ctx));
SSL_CTX_set_mode(ctx, SSL_MODE_AUTO_RETRY);
listen_socket := socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
confirm(listen_socket <> 0);
sa_serv.sin_family := AF_INET;
sa_serv.sin_port := htons(DEFAULTPORT);
sa_serv.sin_addr.s_addr := INADDR_ANY;
confirm(bind(listen_socket, sa_serv, SizeOf(sa_serv)) = 0);
while TRUE do
begin
if listen(listen_socket, 100) <> 0 then continue;
client_len := SizeOf(sa_cli);
sock := accept(listen_socket, @sa_cli, @client_len);
if sock = INVALID_SOCKET then continue;
ssl := SSL_new(ctx);
if ssl = nil then continue;
SSL_set_fd(ssl, sock);
if SSL_accept(ssl) = 1 then
begin
bytesin := SSL_read(ssl, buffer, sizeof(buffer)-1);
if bytesin > 0 then
begin
buffer[bytesin] := #0;
response := getresponse(buffer);
SSL_write(ssl, pchar(response)^, length(response));
end;
end;
SSL_set_shutdown(ssl, SSL_SENT_SHUTDOWN or SSL_RECEIVED_SHUTDOWN);
CloseSocket(sock);
SSL_free(ssl);
end;
The single SSL_read will grab an entire GET or POST request from Firefox, and everything works great. On the other hand, a Chrome GET will cause the first few SSL_read calls to return zero bytes, but eventually a SSL_read will grab the entire GET request and the code still works.
But when Chrome sends a POST, the first few SSL_read calls fetch zero bytes, and the next SSL_read will grab ONLY THE HEADERS. The getresponse() routine can't make sense of the POST because one more SSL_read is necessary to grab the POST content.
SSL_MODE_AUTO_RETRY was set, hoping SSL_read would then not return until an entire request was done, but that doesn't work. SSL_pending always returns zero, before or after every SSL_read, so that's no help either.
As this question's answer says, non-blocking SSL appears to involve lots of torture and heartburn. I've played with doing SSL_reads in a separate thread and killing the thread after timing out on a hung read, but that seems dangerous since it's unknown what state SSL is in (or how to reset it) as the thread is killed.
Does anyone have code for a minimal loop similar to the above, but that won't hang on a Chrome POST or SSL_read, that's simple and vanilla enough to easily convert to Delphi 6?