ConnectionCache.cpp 2.7 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273
  1. /*
  2. * Copyright (c) 2021, Ali Mohammad Pur <mpfard@serenityos.org>
  3. *
  4. * SPDX-License-Identifier: BSD-2-Clause
  5. */
  6. #include "ConnectionCache.h"
  7. #include <LibCore/EventLoop.h>
  8. namespace RequestServer::ConnectionCache {
  9. HashMap<ConnectionKey, Vector<Connection<Core::TCPSocket>>> g_tcp_connection_cache {};
  10. HashMap<ConnectionKey, Vector<Connection<TLS::TLSv12>>> g_tls_connection_cache {};
  11. void request_did_finish(URL const& url, Core::Socket const* socket)
  12. {
  13. if (!socket) {
  14. dbgln("Request with a null socket finished for URL {}", url);
  15. return;
  16. }
  17. dbgln("Request for {} finished", url);
  18. ConnectionKey key { url.host(), url.port_or_default() };
  19. auto fire_off_next_job = [&](auto& cache) {
  20. auto it = cache.find(key);
  21. if (it == cache.end()) {
  22. dbgln("Request for URL {} finished, but we don't own that!", url);
  23. return;
  24. }
  25. auto connection_it = it->value.find_if([&](auto& connection) { return connection.socket == socket; });
  26. if (connection_it.is_end()) {
  27. dbgln("Request for URL {} finished, but we don't have a socket for that!", url);
  28. return;
  29. }
  30. auto& connection = *connection_it;
  31. if (connection.request_queue.is_empty()) {
  32. connection.has_started = false;
  33. connection.removal_timer->on_timeout = [&connection, &cache_entry = it->value] {
  34. Core::deferred_invoke([&] {
  35. dbgln("Removing no-longer-used connection {}", &connection);
  36. cache_entry.remove_first_matching([&](auto& entry) { return &entry == &connection; });
  37. });
  38. };
  39. connection.removal_timer->start();
  40. } else {
  41. using SocketType = RemoveCVReference<decltype(*connection.socket)>;
  42. bool is_connected;
  43. if constexpr (IsSame<SocketType, TLS::TLSv12>)
  44. is_connected = connection.socket->is_established();
  45. else
  46. is_connected = connection.socket->is_connected();
  47. if (!is_connected) {
  48. // Create another socket for the connection.
  49. dbgln("Creating a new socket for {}", url);
  50. connection.socket = SocketType::construct(nullptr);
  51. }
  52. dbgln("Running next job in queue for connection {}", &connection);
  53. auto request = connection.request_queue.take_first();
  54. request(connection.socket);
  55. }
  56. };
  57. if (is<TLS::TLSv12>(socket))
  58. fire_off_next_job(g_tls_connection_cache);
  59. else if (is<Core::TCPSocket>(socket))
  60. fire_off_next_job(g_tcp_connection_cache);
  61. else
  62. dbgln("Unknown socket {} finished for URL {}", *socket, url);
  63. }
  64. }