Skip to content

Commit 6cab1dd

Browse files
committed
Merge branch 'release/2.x' into dev
2 parents 1ee937b + 65782f9 commit 6cab1dd

5 files changed

Lines changed: 98 additions & 18 deletions

File tree

CHANGELOG.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
# axmol-2.9.0 ?? 2025
1+
# axmol-2.9.0 Oct.5 2025
22

33
## Significant changes relative to 2.8.x:
44

@@ -27,6 +27,7 @@
2727

2828
## Improvements
2929

30+
- Add Http setDataCallback for streaming data support by @halx99 in [#2805](https://github.com/axmolengine/axmol/pull/2805)
3031
- Improve ios EditBox orientation handling with keyboard by @halx99 in [#2791](https://github.com/axmolengine/axmol/pull/2791) and [#2795](https://github.com/axmolengine/axmol/pull/2795)
3132
- Add support for extracting the previous scene from the scene stack by @rh101 in [#2793](https://github.com/axmolengine/axmol/pull/2793)
3233
- Destroy `ScriptEngine` instance before `_scheduler` to respect dependency by @halx99

axmol/network/HttpClient.cpp

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -258,7 +258,13 @@ void HttpClient::handleNetworkEvent(yasio::io_event* event)
258258
if (!responseFinished)
259259
{
260260
auto&& pkt = event->packet_view();
261-
response->handleInput(pkt.data(), pkt.size());
261+
auto err = response->input(pkt.data(), pkt.size());
262+
if (err != HPE_OK)
263+
{
264+
response->updateInternalCode(err);
265+
_service->close(event->cindex());
266+
break;
267+
}
262268
}
263269
if (response->isFinished())
264270
{
@@ -389,6 +395,7 @@ void HttpClient::handleNetworkEvent(yasio::io_event* event)
389395
}
390396
break;
391397
case YEK_ON_CLOSE:
398+
response->handleConnectionClose();
392399
handleNetworkEOF(response, channel, event->status());
393400
break;
394401
}
@@ -460,8 +467,8 @@ void HttpClient::finishResponse(HttpResponse* response)
460467

461468
void HttpClient::invokeResposneCallbackAndRelease(HttpResponse* response)
462469
{
463-
HttpRequest* request = response->getHttpRequest();
464-
const ccHttpRequestCallback& callback = request->getCallback();
470+
auto request = response->getHttpRequest();
471+
auto& callback = request->getCompleteCallback();
465472

466473
if (callback != nullptr)
467474
callback(this, response);

axmol/network/HttpClient.h

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -120,7 +120,6 @@ class AX_DLL HttpClient
120120
* https://stackoverflow.com/questions/23714383/what-are-all-the-possible-values-for-http-content-type-header
121121
*/
122122
void send(HttpRequest* request);
123-
void sendImmediate(HttpRequest* request) { this->send(request); }
124123

125124
/**
126125
* Set the timeout value for connecting.

axmol/network/HttpRequest.h

Lines changed: 53 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,9 @@ namespace network
5353
class HttpClient;
5454
class HttpResponse;
5555

56-
typedef std::function<void(HttpClient* client, HttpResponse* response)> ccHttpRequestCallback;
56+
using HttpCompleteCallback = std::function<void(HttpClient* client, HttpResponse* response)>;
57+
using HttpDataCallback = std::function<void(HttpResponse* response, const char* data, size_t data_size)>;
58+
using ccHttpRequestCallback = HttpCompleteCallback;
5759

5860
/**
5961
* Defines the object which users must packed for HttpClient::send(HttpRequest*) method.
@@ -205,16 +207,60 @@ class AX_DLL HttpRequest : public ConcurrentRefCountedBase
205207
* Set response callback function of HttpRequest object.
206208
* When response come back, we would call _pCallback to process response data.
207209
*
208-
* @param callback the ccHttpRequestCallback function.
210+
* @param callback the HttpCompleteCallback function.
209211
*/
210-
void setResponseCallback(const ccHttpRequestCallback& callback) { _pCallback = callback; }
212+
void setCompleteCallback(const HttpCompleteCallback& callback) { _pCallback = callback; }
213+
AX_DEPRECATED(2.9) void setResponseCallback(const HttpCompleteCallback& callback) { setCompleteCallback(callback); }
211214

212215
/**
213-
* Get ccHttpRequestCallback callback function.
216+
* Get HttpCompleteCallback callback function.
214217
*
215-
* @return const ccHttpRequestCallback& ccHttpRequestCallback callback function.
218+
* @return const HttpCompleteCallback& completeCallback callback function.
216219
*/
217-
const ccHttpRequestCallback& getCallback() const { return _pCallback; }
220+
221+
const HttpCompleteCallback& getCompleteCallback() const { return _pCallback; }
222+
AX_DEPRECATED(2.9) const HttpCompleteCallback& getCallback() const { return getCompleteCallback(); }
223+
224+
/**
225+
* @brief Set the data callback for handling received data chunks.
226+
*
227+
* When a data callback is set, it will be invoked for each chunk of data received
228+
* during the HTTP response. This is particularly useful for:
229+
* - Large file downloads to process data incrementally
230+
* - Streaming data processing
231+
* - Memory-constrained environments
232+
*
233+
* @note If a data callback is set, the default behavior of appending received data
234+
* to HttpResponse::_responseData will be disabled. The response data buffer
235+
* will not accumulate data chunks automatically. You must handle all data
236+
* storage/processing within the callback function.
237+
*
238+
* @note The callback receives the following parameters:
239+
* - HttpResponse* response: The response object containing request context
240+
* - const char* data: Pointer to the received data chunk
241+
* - size_t data_size: Size of the data chunk in bytes
242+
*
243+
* @param callback The callback function to handle received data chunks
244+
*
245+
* @code
246+
* // Example: Stream data to file instead of memory
247+
* request->setDataCallback([](HttpResponse* response, const char* data, size_t size) {
248+
* // 0 for chunked transfer encoding, unknown size, or no Content-Length header
249+
* auto expectedTotal = response->getContentLength();
250+
* // Write directly to file, avoiding memory accumulation
251+
* fwrite(data, 1, size, outputFile);
252+
*
253+
* // Update progress
254+
* totalReceived += size;
255+
* updateProgress(totalReceived, expectedTotal);
256+
* });
257+
* @endcode
258+
*
259+
* @see HttpDataCallback
260+
* @see HttpResponse::_responseData
261+
*/
262+
void setDataCallback(const HttpDataCallback& callback) { _pDataCallback = callback; }
263+
const HttpDataCallback& getDataCallback() const { return _pDataCallback; }
218264

219265
/**
220266
* Set custom-defined headers.
@@ -258,6 +304,7 @@ class AX_DLL HttpRequest : public ConcurrentRefCountedBase
258304
yasio::sbyte_buffer _requestData; /// used for POST
259305
std::string _tag; /// user defined tag, to identify different requests in response callback
260306
ccHttpRequestCallback _pCallback; /// C++11 style callbacks
307+
HttpDataCallback _pDataCallback;
261308
void* _pUserData; /// You can add your customed data here
262309
std::vector<std::string> _headers; /// custom http headers
263310
std::vector<std::string> _hosts;

axmol/network/HttpResponse.h

Lines changed: 33 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -131,6 +131,8 @@ class AX_DLL HttpResponse : public ConcurrentRefCountedBase
131131

132132
const std::string& getStatusText() const { return _statusText; }
133133

134+
uint64_t getContentLength() const { return _context.content_length; }
135+
134136
private:
135137
void setResponseCode(int value) { _responseCode = value; }
136138

@@ -145,13 +147,9 @@ class AX_DLL HttpResponse : public ConcurrentRefCountedBase
145147
*/
146148
bool isFinished() const { return _finished; }
147149

148-
void handleInput(const char* d, size_t n)
150+
llhttp_errno_t input(const char* d, size_t n)
149151
{
150-
enum llhttp_errno err = llhttp_execute(&_context, d, n);
151-
if (err != HPE_OK)
152-
{
153-
_finished = true;
154-
}
152+
return llhttp_execute(&_context, d, n);
155153
}
156154

157155
bool tryRedirect()
@@ -194,6 +192,7 @@ class AX_DLL HttpResponse : public ConcurrentRefCountedBase
194192
/* Resets response status */
195193
_responseHeaders.clear();
196194
_finished = false;
195+
_contentLength = 0;
197196
_responseData.clear();
198197
_currentHeader.clear();
199198
_statusText.clear();
@@ -216,6 +215,7 @@ class AX_DLL HttpResponse : public ConcurrentRefCountedBase
216215
_contextSettings.on_header_field_complete = on_header_field_complete;
217216
_contextSettings.on_header_value = on_header_value;
218217
_contextSettings.on_header_value_complete = on_header_value_complete;
218+
_contextSettings.on_headers_complete = on_headers_complete;
219219
_contextSettings.on_body = on_body;
220220
_contextSettings.on_status = on_status;
221221
_contextSettings.on_message_complete = on_complete;
@@ -228,6 +228,16 @@ class AX_DLL HttpResponse : public ConcurrentRefCountedBase
228228

229229
const Uri& getRequestUri() const { return _requestUri; }
230230

231+
void handleConnectionClose()
232+
{
233+
if (_finished)
234+
return;
235+
if (llhttp_message_needs_eof(&_context))
236+
llhttp_finish(&_context);
237+
else
238+
_internalCode = -1;
239+
}
240+
231241
static int on_status(llhttp_t* context, const char* at, size_t length)
232242
{
233243
auto thiz = (HttpResponse*)context->data;
@@ -258,12 +268,27 @@ class AX_DLL HttpResponse : public ConcurrentRefCountedBase
258268
{
259269
auto thiz = (HttpResponse*)context->data;
260270
thiz->_responseHeaders.emplace(std::move(thiz->_currentHeader), std::move(thiz->_currentHeaderValue));
271+
272+
return 0;
273+
}
274+
static int on_headers_complete(llhttp_t* context)
275+
{
276+
auto thiz = (HttpResponse*)context->data;
277+
thiz->_contentLength = context->content_length;
278+
auto request = thiz->getHttpRequest();
279+
if (!request->getDataCallback() && thiz->_contentLength > 0)
280+
thiz->_responseData.reserve(thiz->_contentLength);
261281
return 0;
262282
}
263283
static int on_body(llhttp_t* context, const char* at, size_t length)
264284
{
265285
auto thiz = (HttpResponse*)context->data;
266-
thiz->_responseData.insert(thiz->_responseData.end(), at, at + length);
286+
auto request = thiz->getHttpRequest();
287+
auto dataCallback = request->getDataCallback();
288+
if (!dataCallback)
289+
thiz->_responseData.insert(thiz->_responseData.end(), at, at + length);
290+
else
291+
dataCallback(thiz, at, length);
267292
return 0;
268293
}
269294
static int on_complete(llhttp_t* context)
@@ -281,6 +306,7 @@ class AX_DLL HttpResponse : public ConcurrentRefCountedBase
281306

282307
Uri _requestUri;
283308
bool _finished = false; /// to indicate if the http request is successful simply
309+
uint64_t _contentLength{0};
284310
yasio::sbyte_buffer _responseData; /// the returned raw data. You can also dump it as a string
285311
std::string _currentHeader;
286312
std::string _currentHeaderValue;

0 commit comments

Comments
 (0)