ConnectionCache.cpp 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596
  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 <AK/Debug.h>
  8. #include <LibCore/EventLoop.h>
  9. namespace RequestServer::ConnectionCache {
  10. HashMap<ConnectionKey, NonnullOwnPtr<NonnullOwnPtrVector<Connection<Core::TCPSocket>>>> g_tcp_connection_cache {};
  11. HashMap<ConnectionKey, NonnullOwnPtr<NonnullOwnPtrVector<Connection<TLS::TLSv12>>>> g_tls_connection_cache {};
  12. void request_did_finish(URL const& url, Core::Socket const* socket)
  13. {
  14. if (!socket) {
  15. dbgln("Request with a null socket finished for URL {}", url);
  16. return;
  17. }
  18. dbgln_if(REQUESTSERVER_DEBUG, "Request for {} finished", url);
  19. ConnectionKey key { url.host(), url.port_or_default() };
  20. auto fire_off_next_job = [&](auto& cache) {
  21. auto it = cache.find(key);
  22. if (it == cache.end()) {
  23. dbgln("Request for URL {} finished, but we don't own that!", url);
  24. return;
  25. }
  26. auto connection_it = it->value->find_if([&](auto& connection) { return connection->socket == socket; });
  27. if (connection_it.is_end()) {
  28. dbgln("Request for URL {} finished, but we don't have a socket for that!", url);
  29. return;
  30. }
  31. auto& connection = *connection_it;
  32. if (connection->request_queue.is_empty()) {
  33. connection->has_started = false;
  34. connection->current_url = {};
  35. connection->removal_timer->on_timeout = [ptr = connection.ptr(), &cache_entry = *it->value, key = it->key, &cache]() mutable {
  36. Core::deferred_invoke([&, key = move(key), ptr] {
  37. dbgln_if(REQUESTSERVER_DEBUG, "Removing no-longer-used connection {} (socket {})", ptr, ptr->socket);
  38. auto did_remove = cache_entry.remove_first_matching([&](auto& entry) { return entry == ptr; });
  39. VERIFY(did_remove);
  40. if (cache_entry.is_empty())
  41. cache.remove(key);
  42. });
  43. };
  44. connection->removal_timer->start();
  45. } else {
  46. recreate_socket_if_needed(*connection, url);
  47. dbgln_if(REQUESTSERVER_DEBUG, "Running next job in queue for connection {} @{}", &connection, connection->socket);
  48. auto request = connection->request_queue.take_first();
  49. connection->timer.start();
  50. connection->current_url = url;
  51. request(connection->socket);
  52. }
  53. };
  54. if (is<TLS::TLSv12>(socket))
  55. fire_off_next_job(g_tls_connection_cache);
  56. else if (is<Core::TCPSocket>(socket))
  57. fire_off_next_job(g_tcp_connection_cache);
  58. else
  59. dbgln("Unknown socket {} finished for URL {}", *socket, url);
  60. }
  61. void dump_jobs()
  62. {
  63. dbgln("=========== TLS Connection Cache ==========");
  64. for (auto& connection : g_tls_connection_cache) {
  65. dbgln(" - {}:{}", connection.key.hostname, connection.key.port);
  66. for (auto& entry : *connection.value) {
  67. dbgln(" - Connection {} (started={}) (socket={})", &entry, entry.has_started, entry.socket);
  68. dbgln(" Currently loading {} ({} elapsed)", entry.current_url, entry.timer.elapsed());
  69. dbgln(" Request Queue:");
  70. for (auto& job : entry.request_queue)
  71. dbgln(" - {}", &job);
  72. }
  73. }
  74. dbgln("=========== TCP Connection Cache ==========");
  75. for (auto& connection : g_tcp_connection_cache) {
  76. dbgln(" - {}:{}", connection.key.hostname, connection.key.port);
  77. for (auto& entry : *connection.value) {
  78. dbgln(" - Connection {} (started={}) (socket={})", &entry, entry.has_started, entry.socket);
  79. dbgln(" Currently loading {} ({} elapsed)", entry.current_url, entry.timer.elapsed());
  80. dbgln(" Request Queue:");
  81. for (auto& job : entry.request_queue)
  82. dbgln(" - {}", &job);
  83. }
  84. }
  85. }
  86. }