Google Chrome POST нарушает этот SSL_read.У кого-нибудь есть код, который работает? - PullRequest
2 голосов
/ 14 августа 2011

Мне нужен минимальный сервер 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 захватит ТОЛЬКО ЗАГОЛОВОК .Подпрограмма getresponse () не может иметь смысла для POST, потому что для захвата содержимого POST необходим еще один SSL_read.

SSL_MODE_AUTO_RETRY был установлен, надеясь, что SSL_read не вернется, пока не будет выполнен весь запрос, но этоне работаетSSL_pending всегда возвращает ноль, до или после каждого SSL_read, так что это тоже не поможет.

Поскольку ответ на этот вопрос говорит , неблокируемый SSL, похоже, включает в себя множество пыток и изжоги.Я играл с созданием SSL_reads в отдельном потоке и уничтожением потока после истечения времени ожидания зависания, но это кажется опасным, поскольку неизвестно, в каком состоянии находится SSL (или как его сбросить), поскольку поток уничтожен.

Есть ли у кого-нибудь код для минимального цикла, похожего на описанный выше, но он не будет зависать от Chrome POST или SSL_read, это достаточно просто и ванильно, чтобы легко конвертировать в Delphi 6?

Ответы [ 2 ]

3 голосов
/ 14 августа 2011

Вы должны помнить, что TCP основан на потоке, и один вызов Read может вернуть любую часть данных, которую он может, и это может быть, например, половина заголовка или заголовок + немного данных поста. или что-нибудь между. Вы не можете ожидать, что одно чтение вернет полные данные.

Следовательно, единственным вариантом является следующий алгоритм:

  1. прочитайте что-нибудь.
  2. проверьте, есть ли у вас полный заголовок внутри.
  3. Если вы получили заголовок, проверьте, содержит ли он Content-Length (некоторые сообщения могут не содержать его)
  4. Если у вас длина контента, продолжайте чтение из сокета до длины контента, а затем обработайте полный запрос.
  5. Если у вас нет Content-length, тогда вам придется иметь дело с чанкованным кодированием. Это сложная вещь для решения, которая выходит за рамки вопроса SO.

На вашем месте я бы использовал существующую реализацию HTTP / HTTPS-сервера. Очевидными вариантами являются уровень Indy + SSL или пакет сервера HTTPBlackbox нашего SecureBlackbox.

0 голосов
/ 16 августа 2011

Я изменил OpenSSL s_server.c , который теперь делает свое дело, и опубликовал его как ответ на вопрос 7080958 .

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...