22 *
33 * PROJECT: Multi Theft Auto v1.0
44 * LICENSE: See LICENSE in the top level directory
5- * FILE: core/AjaxResourceHandler .cpp
5+ * FILE: cefweb/CAjaxResourceHandler .cpp
66 * PURPOSE: CEF Handler for Ajax Requests with delayed results
77 *
8+ * Multi Theft Auto is available from https://www.multitheftauto.com/
9+ *
810 *****************************************************************************/
911
1012#include " StdInc.h"
11- #include " CWebCore.h"
12- #include " CWebView.h"
1313#include " CAjaxResourceHandler.h"
1414#undef min
1515
1616CAjaxResourceHandler::CAjaxResourceHandler (std::vector<SString>& vecGet, std::vector<SString>& vecPost, const CefString& strMime)
17- : m_vecGetData(vecGet), m_vecPostData(vecPost), m_strMime(strMime)
17+ : m_vecGetData(std::move( vecGet)) , m_vecPostData(std::move( vecPost) ), m_strMime(strMime)
1818{
1919}
2020
2121CAjaxResourceHandler::~CAjaxResourceHandler ()
2222{
2323 // Ensure callback is released if handler is destroyed before completion
24- if (m_callback)
25- {
26- m_callback = nullptr ;
27- }
28- }
29-
30- std::vector<SString>& CAjaxResourceHandler::GetGetData ()
31- {
32- return m_vecGetData;
33- }
24+ if (!m_callback)
25+ return ;
3426
35- std::vector<SString>& CAjaxResourceHandler::GetPostData ()
36- {
37- return m_vecPostData;
27+ m_callback = nullptr ;
3828}
3929
4030void CAjaxResourceHandler::SetResponse (const SString& data)
4131{
32+ // Prevent response corruption: ignore subsequent calls after data is set
33+ if (m_bHasData) [[unlikely]]
34+ return ;
35+
4236 m_strResponse = data;
4337 m_bHasData = true ;
4438
45- if (m_callback)
46- {
47- m_callback->Continue ();
48- // Release callback to prevent memory leak
49- m_callback = nullptr ;
50- }
39+ if (!m_callback)
40+ return ;
41+
42+ // Release callback to prevent memory leak
43+ auto callback = std::exchange (m_callback, nullptr );
44+ if (callback)
45+ callback->Continue ();
5146}
5247
5348// CefResourceHandler implementation
@@ -59,42 +54,64 @@ void CAjaxResourceHandler::Cancel()
5954
6055void CAjaxResourceHandler::GetResponseHeaders (CefRefPtr<CefResponse> response, int64& response_length, CefString& redirectUrl)
6156{
62- response->SetStatus (200 );
57+ if (!response) [[unlikely]]
58+ return ;
59+
60+ constexpr int HTTP_OK = 200 ;
61+ response->SetStatus (HTTP_OK);
6362 response->SetStatusText (" OK" );
64- response->SetMimeType (m_strMime);
63+
64+ // Use default MIME type if none provided
65+ if (!m_strMime.empty ())
66+ response->SetMimeType (m_strMime);
67+ else
68+ response->SetMimeType (" application/octet-stream" );
69+
6570 response_length = -1 ;
6671}
6772
68- bool CAjaxResourceHandler::ProcessRequest (CefRefPtr<CefRequest> request, CefRefPtr<CefCallback> callback)
73+ bool CAjaxResourceHandler::ProcessRequest ([[maybe_unused]] CefRefPtr<CefRequest> request, CefRefPtr<CefCallback> callback)
6974{
70- // Since we have nothing to process yet, continue
71- callback-> Continue ();
75+ // Don't call Continue() here - let ReadResponse handle async flow
76+ // Calling Continue() immediately would use the callback before data is ready
7277 return true ;
7378}
7479
7580bool CAjaxResourceHandler::ReadResponse (void * data_out, int bytes_to_read, int & bytes_read, CefRefPtr<CefCallback> callback)
7681{
82+ // Validate input parameters first
83+ if (!data_out || bytes_to_read <= 0 ) [[unlikely]]
84+ {
85+ bytes_read = 0 ;
86+ return false ;
87+ }
88+
7789 // If we have no data yet, wait
7890 if (!m_bHasData)
7991 {
8092 bytes_read = 0 ;
81- m_callback = callback;
82-
93+ // Store callback only if we don't already have one (prevent overwrite/leak)
94+ if (callback && !m_callback)
95+ m_callback = callback;
8396 return true ;
8497 }
8598
86- // Are we done?
87- if ( m_strResponse.length () - m_DataOffset <= 0 ) [[unlikely]]
88- return false ;
89-
90- if (bytes_to_read < = 0 ) [[unlikely]]
99+ // Are we done or response is empty ?
100+ const auto responseLength = m_strResponse.length ();
101+ if (m_DataOffset >= responseLength) [[unlikely]]
102+ {
103+ bytes_read = 0 ;
91104 return false ;
105+ }
92106
93- const size_t copyBytes = std::min (static_cast <size_t >(bytes_to_read), m_strResponse.length () - m_DataOffset);
107+ const auto remainingBytes = responseLength - m_DataOffset;
108+ const auto copyBytes = std::min (static_cast <size_t >(bytes_to_read), remainingBytes);
94109
95110 memcpy (data_out, m_strResponse.c_str () + m_DataOffset, copyBytes);
111+
112+ // copyBytes is bounded by bytes_to_read (an int), so cast is always safe
96113 bytes_read = static_cast <int >(copyBytes);
97-
114+
98115 m_DataOffset += copyBytes;
99116
100117 return true ;
0 commit comments