Google Chrome POST会破坏此SSL_read。有人有代码吗?

时间:2011-08-14 01:47:56

标签: delphi google-chrome ssl https

我需要一个最小 SSL服务器,并提出以下建议:

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;

单个SSL_read将获取整个GET或POST请求 来自Firefox,一切都很棒。另一方面,Chrome GET会导致 前几个SSL_read调用返回零字节,但最终 SSL_read将获取整个GET请求,代码仍然有效。

但是当Chrome发送POST时,前几个SSL_read调用 获取零字节,下一个SSL_read将获取 ONLY THE HEADERS 。 getresponse()例程无法理解POST,因为 获取POST内容需要多一次SSL_read。

设置了SSL_MODE_AUTO_RETRY,希望SSL_read不会 返回,直到整个请求完成, 但这不起作用。 SSL_pending始终在之前或之后返回零 每个SSL_read,所以也没有任何帮助。

作为this question's answer says,非阻塞SSL似乎涉及许多折磨和胃灼热。我已经玩过在一个单独的线程中执行SSL_reads并在挂起读取超时后终止线程,但这似乎很危险,因为在线程被杀死时,SSL处于什么状态(或如何重置它)是未知的。

是否有人拥有与上述类似的最小循环代码, 但这不会挂在Chrome POST或SSL_read上,这很简单,而且足够香草 轻松转换为Delphi 6?

2 个答案:

答案 0 :(得分:3)

你需要记住,TCP是基于流的,对Read的单次调用可以返回它可以的任何数据,这可以是例如标题的一半,或者标题+一些帖子数据或之间的任何东西您不能指望一次读取返回完整的数据。

因此,您唯一的选择是以下算法:

  1. 读了一些东西。
  2. 检查你的内部是否有完整的标题。
  3. 如果您有标题,请检查它是否包含Content-Length(某些帖子可能不包含它)
  4. 如果您有Content-length,请继续从套接字读取内容长度,然后处理完整的请求。
  5. 如果您没有Content-length,那么您必须处理分块编码。这是一件很复杂的事情,远远超出了SO问题的范围。
  6. 如果我是你,我会采用一些现有的HTTP / HTTPS服务器实现。明显的选择是我们的SecureBlackbox的Indy + SSL层或HTTPBlackbox服务器包。

答案 1 :(得分:0)

我修改了OpenSSL s_server.c,现在可以解决这个问题,并将其发布为answer to Question 7080958