2012-08-07 18:28:07 +08:00
|
|
|
/****************************************************************************
|
|
|
|
Copyright (c) 2010-2012 cocos2d-x.org
|
2018-01-29 16:25:32 +08:00
|
|
|
Copyright (c) 2013-2016 Chukong Technologies Inc.
|
|
|
|
Copyright (c) 2017-2018 Xiamen Yaji Software Co., Ltd.
|
2021-06-24 12:33:07 +08:00
|
|
|
Copyright (c) 2021 Bytedance Inc.
|
2016-05-18 12:54:16 +08:00
|
|
|
|
2022-07-09 01:23:11 +08:00
|
|
|
https://axis-project.github.io/
|
2016-05-18 12:54:16 +08:00
|
|
|
|
2012-08-07 18:28:07 +08:00
|
|
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
|
|
of this software and associated documentation files (the "Software"), to deal
|
|
|
|
in the Software without restriction, including without limitation the rights
|
|
|
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
|
|
copies of the Software, and to permit persons to whom the Software is
|
|
|
|
furnished to do so, subject to the following conditions:
|
2016-05-18 12:54:16 +08:00
|
|
|
|
2012-08-07 18:28:07 +08:00
|
|
|
The above copyright notice and this permission notice shall be included in
|
|
|
|
all copies or substantial portions of the Software.
|
2016-05-18 12:54:16 +08:00
|
|
|
|
2012-08-07 18:28:07 +08:00
|
|
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
|
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
|
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
|
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
|
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
|
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
|
|
THE SOFTWARE.
|
|
|
|
****************************************************************************/
|
|
|
|
|
|
|
|
#ifndef __HTTP_RESPONSE__
|
|
|
|
#define __HTTP_RESPONSE__
|
2021-06-24 12:33:07 +08:00
|
|
|
#include <ctype.h>
|
2021-07-18 23:20:22 +08:00
|
|
|
#include <map>
|
2021-06-24 12:33:07 +08:00
|
|
|
#include <unordered_map>
|
2013-10-16 16:48:39 +08:00
|
|
|
#include "network/HttpRequest.h"
|
2021-06-24 12:33:07 +08:00
|
|
|
#include "network/Uri.h"
|
2021-07-18 23:20:22 +08:00
|
|
|
#include "llhttp.h"
|
2012-08-07 18:28:07 +08:00
|
|
|
|
2015-03-26 22:07:44 +08:00
|
|
|
/**
|
2015-05-28 15:46:36 +08:00
|
|
|
* @addtogroup network
|
2015-03-26 22:07:44 +08:00
|
|
|
* @{
|
|
|
|
*/
|
|
|
|
|
2014-01-02 16:25:35 +08:00
|
|
|
NS_CC_BEGIN
|
|
|
|
|
2021-12-25 10:04:45 +08:00
|
|
|
namespace network
|
|
|
|
{
|
2012-08-07 18:28:07 +08:00
|
|
|
|
2021-06-24 12:33:07 +08:00
|
|
|
class HttpClient;
|
2016-05-18 12:54:16 +08:00
|
|
|
/**
|
2015-03-19 16:45:53 +08:00
|
|
|
* @brief defines the object which users will receive at onHttpCompleted(sender, HttpResponse) callback.
|
|
|
|
* Please refer to samples/TestCpp/Classes/ExtensionTest/NetworkTest/HttpClientTest.cpp as a sample.
|
|
|
|
* @since v2.0.2.
|
|
|
|
* @lua NA
|
2012-08-08 12:05:02 +08:00
|
|
|
*/
|
2014-08-22 13:42:46 +08:00
|
|
|
class CC_DLL HttpResponse : public cocos2d::Ref
|
2012-08-07 18:28:07 +08:00
|
|
|
{
|
2021-06-24 12:33:07 +08:00
|
|
|
friend class HttpClient;
|
2021-12-25 10:04:45 +08:00
|
|
|
|
2012-08-07 18:28:07 +08:00
|
|
|
public:
|
2021-07-18 23:20:22 +08:00
|
|
|
using ResponseHeaderMap = std::multimap<std::string, std::string>;
|
2021-06-24 12:33:07 +08:00
|
|
|
|
2016-05-18 12:54:16 +08:00
|
|
|
/**
|
2015-03-19 16:45:53 +08:00
|
|
|
* Constructor, it's used by HttpClient internal, users don't need to create HttpResponse manually.
|
|
|
|
* @param request the corresponding HttpRequest which leads to this response.
|
2012-08-08 12:05:02 +08:00
|
|
|
*/
|
2021-12-25 10:04:45 +08:00
|
|
|
HttpResponse(HttpRequest* request) : _pHttpRequest(request)
|
2012-08-07 18:28:07 +08:00
|
|
|
{
|
|
|
|
if (_pHttpRequest)
|
|
|
|
{
|
|
|
|
_pHttpRequest->retain();
|
|
|
|
}
|
|
|
|
}
|
2016-05-18 12:54:16 +08:00
|
|
|
|
|
|
|
/**
|
2015-03-19 16:45:53 +08:00
|
|
|
* Destructor, it will be called in HttpClient internal.
|
2015-10-23 15:37:33 +08:00
|
|
|
* Users don't need to destruct HttpResponse object manually.
|
2012-08-08 12:05:02 +08:00
|
|
|
*/
|
2013-06-20 14:15:53 +08:00
|
|
|
virtual ~HttpResponse()
|
2012-08-07 18:28:07 +08:00
|
|
|
{
|
|
|
|
if (_pHttpRequest)
|
|
|
|
{
|
|
|
|
_pHttpRequest->release();
|
|
|
|
}
|
|
|
|
}
|
2016-05-18 12:54:16 +08:00
|
|
|
|
|
|
|
/**
|
2015-03-19 16:45:53 +08:00
|
|
|
* Override autorelease method to prevent developers from calling it.
|
|
|
|
* If this method is called , it would trigger CCASSERT.
|
|
|
|
* @return cocos2d::Ref* always return nullptr.
|
|
|
|
*/
|
2016-05-18 12:54:16 +08:00
|
|
|
cocos2d::Ref* autorelease()
|
2012-08-07 18:28:07 +08:00
|
|
|
{
|
2021-12-25 10:04:45 +08:00
|
|
|
CCASSERT(false,
|
|
|
|
"HttpResponse is used between network thread and ui thread \
|
2012-08-07 18:28:07 +08:00
|
|
|
therefore, autorelease is forbidden here");
|
2016-05-18 12:54:16 +08:00
|
|
|
return nullptr;
|
2012-08-07 18:28:07 +08:00
|
|
|
}
|
2016-05-18 12:54:16 +08:00
|
|
|
|
2012-08-08 12:05:02 +08:00
|
|
|
// getters, will be called by users
|
2016-05-18 12:54:16 +08:00
|
|
|
|
|
|
|
/**
|
2015-03-19 16:45:53 +08:00
|
|
|
* Get the corresponding HttpRequest object which leads to this response.
|
2016-09-06 10:14:14 +08:00
|
|
|
* There's no paired setter for it, because it's already set in class constructor
|
2015-03-19 16:45:53 +08:00
|
|
|
* @return HttpRequest* the corresponding HttpRequest object which leads to this response.
|
2012-08-08 12:05:02 +08:00
|
|
|
*/
|
2021-12-25 10:04:45 +08:00
|
|
|
HttpRequest* getHttpRequest() const { return _pHttpRequest; }
|
2016-05-18 12:54:16 +08:00
|
|
|
|
|
|
|
/**
|
2015-03-19 16:45:53 +08:00
|
|
|
* Get the http response data.
|
2021-12-10 19:15:48 +08:00
|
|
|
* @return yasio::sbyte_buffer* the pointer that point to the _responseData.
|
2015-03-19 16:45:53 +08:00
|
|
|
*/
|
2021-12-25 10:04:45 +08:00
|
|
|
yasio::sbyte_buffer* getResponseData() { return &_responseData; }
|
2016-05-18 12:54:16 +08:00
|
|
|
|
2021-12-25 10:04:45 +08:00
|
|
|
bool isSucceed() const { return _responseCode == 200; }
|
2012-08-08 12:05:02 +08:00
|
|
|
|
2016-05-18 12:54:16 +08:00
|
|
|
/**
|
2015-10-09 16:59:11 +08:00
|
|
|
* Get the http response code to judge whether response is successful or not.
|
2015-03-19 16:45:53 +08:00
|
|
|
* I know that you want to see the _responseCode is 200.
|
|
|
|
* If _responseCode is not 200, you should check the meaning for _responseCode by the net.
|
2021-09-02 13:39:28 +08:00
|
|
|
* @return int32_t the value of _responseCode
|
2012-08-08 12:05:02 +08:00
|
|
|
*/
|
2021-12-25 10:04:45 +08:00
|
|
|
int getResponseCode() const { return _responseCode; }
|
2012-08-08 12:05:02 +08:00
|
|
|
|
2021-06-25 18:29:16 +08:00
|
|
|
/*
|
2021-12-25 10:04:45 +08:00
|
|
|
* The yasio error code, see yasio::errc
|
|
|
|
*/
|
2020-10-05 02:40:38 +08:00
|
|
|
int getInternalCode() const { return _internalCode; }
|
|
|
|
|
2021-12-25 10:04:45 +08:00
|
|
|
int getRedirectCount() const { return _redirectCount; }
|
2016-05-18 12:54:16 +08:00
|
|
|
|
2021-12-25 10:04:45 +08:00
|
|
|
const ResponseHeaderMap& getResponseHeaders() const { return _responseHeaders; }
|
2016-05-18 12:54:16 +08:00
|
|
|
|
2021-06-24 12:33:07 +08:00
|
|
|
private:
|
2021-12-25 10:04:45 +08:00
|
|
|
void updateInternalCode(int value)
|
|
|
|
{
|
2021-06-25 18:29:16 +08:00
|
|
|
if (_internalCode == 0)
|
|
|
|
_internalCode = value;
|
|
|
|
}
|
|
|
|
|
2016-05-18 12:54:16 +08:00
|
|
|
/**
|
2021-06-24 12:33:07 +08:00
|
|
|
* To see if the http request is finished.
|
2012-08-08 12:05:02 +08:00
|
|
|
*/
|
2021-12-25 10:04:45 +08:00
|
|
|
bool isFinished() const { return _finished; }
|
2020-10-05 02:40:38 +08:00
|
|
|
|
2021-12-25 10:04:45 +08:00
|
|
|
void handleInput(const yasio::sbyte_buffer& data)
|
|
|
|
{
|
2021-06-24 12:33:07 +08:00
|
|
|
enum llhttp_errno err = llhttp_execute(&_context, data.data(), data.size());
|
2021-12-25 10:04:45 +08:00
|
|
|
if (err != HPE_OK)
|
|
|
|
{
|
2021-06-24 12:33:07 +08:00
|
|
|
_finished = true;
|
|
|
|
}
|
2016-05-18 12:54:16 +08:00
|
|
|
}
|
|
|
|
|
2015-03-19 16:45:53 +08:00
|
|
|
/**
|
|
|
|
* Set the response data by the string pointer and the defined size.
|
|
|
|
* @param value a string pointer that point to response data buffer.
|
|
|
|
* @param n the defined size that the response data buffer would be copied.
|
|
|
|
*/
|
2021-12-26 23:26:34 +08:00
|
|
|
bool prepareForProcess(std::string_view url)
|
2014-12-31 10:15:14 +08:00
|
|
|
{
|
2021-06-24 12:33:07 +08:00
|
|
|
/* Resets response status */
|
2021-12-25 10:04:45 +08:00
|
|
|
_finished = false;
|
2021-06-24 12:33:07 +08:00
|
|
|
_responseData.clear();
|
|
|
|
_currentHeader.clear();
|
|
|
|
_responseCode = -1;
|
|
|
|
_internalCode = 0;
|
|
|
|
|
|
|
|
Uri uri = Uri::parse(url);
|
|
|
|
if (!uri.isValid())
|
|
|
|
return false;
|
|
|
|
|
|
|
|
_requestUri = std::move(uri);
|
2021-12-25 10:04:45 +08:00
|
|
|
|
2021-06-24 12:33:07 +08:00
|
|
|
/* Initialize user callbacks and settings */
|
|
|
|
llhttp_settings_init(&_contextSettings);
|
|
|
|
|
|
|
|
/* Initialize the parser in HTTP_BOTH mode, meaning that it will select between
|
|
|
|
* HTTP_REQUEST and HTTP_RESPONSE parsing automatically while reading the first
|
|
|
|
* input.
|
|
|
|
*/
|
|
|
|
llhttp_init(&_context, HTTP_RESPONSE, &_contextSettings);
|
|
|
|
|
|
|
|
_context.data = this;
|
|
|
|
|
|
|
|
/* Set user callbacks */
|
2021-07-18 23:20:22 +08:00
|
|
|
_contextSettings.on_header_field = on_header_field;
|
|
|
|
_contextSettings.on_header_field_complete = on_header_field_complete;
|
|
|
|
_contextSettings.on_header_value = on_header_value;
|
|
|
|
_contextSettings.on_header_value_complete = on_header_value_complete;
|
|
|
|
_contextSettings.on_body = on_body;
|
|
|
|
_contextSettings.on_message_complete = on_complete;
|
2021-06-24 12:33:07 +08:00
|
|
|
|
|
|
|
return true;
|
2014-12-31 10:15:14 +08:00
|
|
|
}
|
2016-05-18 12:54:16 +08:00
|
|
|
|
2021-12-25 10:04:45 +08:00
|
|
|
const Uri& getRequestUri() const { return _requestUri; }
|
2021-06-24 12:33:07 +08:00
|
|
|
|
2021-12-25 10:04:45 +08:00
|
|
|
int increaseRedirectCount() { return ++_redirectCount; }
|
2021-06-24 12:33:07 +08:00
|
|
|
|
2021-12-25 10:04:45 +08:00
|
|
|
static int on_header_field(llhttp_t* context, const char* at, size_t length)
|
|
|
|
{
|
|
|
|
auto thiz = (HttpResponse*)context->data;
|
2021-07-18 23:20:22 +08:00
|
|
|
thiz->_currentHeader.insert(thiz->_currentHeader.end(), at, at + length);
|
|
|
|
return 0;
|
|
|
|
}
|
2021-12-25 10:04:45 +08:00
|
|
|
static int on_header_field_complete(llhttp_t* context)
|
|
|
|
{
|
2021-07-18 23:20:22 +08:00
|
|
|
auto thiz = (HttpResponse*)context->data;
|
2021-12-25 10:04:45 +08:00
|
|
|
std::transform(thiz->_currentHeader.begin(), thiz->_currentHeader.end(), thiz->_currentHeader.begin(),
|
|
|
|
::tolower);
|
2021-06-24 12:33:07 +08:00
|
|
|
return 0;
|
|
|
|
}
|
2021-12-25 10:04:45 +08:00
|
|
|
static int on_header_value(llhttp_t* context, const char* at, size_t length)
|
|
|
|
{
|
|
|
|
auto thiz = (HttpResponse*)context->data;
|
2021-07-18 23:20:22 +08:00
|
|
|
thiz->_currentHeaderValue.insert(thiz->_currentHeaderValue.end(), at, at + length);
|
|
|
|
return 0;
|
|
|
|
}
|
2021-12-25 10:04:45 +08:00
|
|
|
static int on_header_value_complete(llhttp_t* context)
|
|
|
|
{
|
2021-07-18 23:20:22 +08:00
|
|
|
auto thiz = (HttpResponse*)context->data;
|
|
|
|
thiz->_responseHeaders.emplace(std::move(thiz->_currentHeader), std::move(thiz->_currentHeaderValue));
|
2021-06-24 12:33:07 +08:00
|
|
|
return 0;
|
|
|
|
}
|
2021-12-25 10:04:45 +08:00
|
|
|
static int on_body(llhttp_t* context, const char* at, size_t length)
|
|
|
|
{
|
|
|
|
auto thiz = (HttpResponse*)context->data;
|
2021-06-24 12:33:07 +08:00
|
|
|
thiz->_responseData.insert(thiz->_responseData.end(), at, at + length);
|
|
|
|
return 0;
|
|
|
|
}
|
2021-12-25 10:04:45 +08:00
|
|
|
static int on_complete(llhttp_t* context)
|
|
|
|
{
|
|
|
|
auto thiz = (HttpResponse*)context->data;
|
2021-06-24 12:33:07 +08:00
|
|
|
thiz->_responseCode = context->status_code;
|
2021-12-25 10:04:45 +08:00
|
|
|
thiz->_finished = true;
|
2021-06-24 12:33:07 +08:00
|
|
|
return 0;
|
2014-12-31 10:15:14 +08:00
|
|
|
}
|
2016-05-18 12:54:16 +08:00
|
|
|
|
2012-08-07 18:28:07 +08:00
|
|
|
protected:
|
|
|
|
// properties
|
2021-12-25 10:04:45 +08:00
|
|
|
HttpRequest* _pHttpRequest; /// the corresponding HttpRequest pointer who leads to this response
|
|
|
|
int _redirectCount = 0;
|
2016-05-18 12:54:16 +08:00
|
|
|
|
2021-12-25 10:04:45 +08:00
|
|
|
Uri _requestUri;
|
|
|
|
bool _finished = false; /// to indicate if the http request is successful simply
|
2021-12-10 19:15:48 +08:00
|
|
|
yasio::sbyte_buffer _responseData; /// the returned raw data. You can also dump it as a string
|
2021-12-25 10:04:45 +08:00
|
|
|
std::string _currentHeader;
|
|
|
|
std::string _currentHeaderValue;
|
|
|
|
ResponseHeaderMap _responseHeaders; /// the returned raw header data. You can also dump it as a string
|
|
|
|
int _responseCode = -1; /// the status code returned from libcurl, e.g. 200, 404
|
|
|
|
int _internalCode = 0; /// the ret code of perform
|
|
|
|
llhttp_t _context;
|
|
|
|
llhttp_settings_t _contextSettings;
|
2012-08-07 18:28:07 +08:00
|
|
|
};
|
|
|
|
|
2021-12-25 10:04:45 +08:00
|
|
|
} // namespace network
|
2012-08-07 18:28:07 +08:00
|
|
|
|
2014-01-02 16:25:35 +08:00
|
|
|
NS_CC_END
|
|
|
|
|
2015-03-26 22:07:44 +08:00
|
|
|
// end group
|
|
|
|
/// @}
|
|
|
|
|
2021-12-25 10:04:45 +08:00
|
|
|
#endif //__HTTP_RESPONSE_H__
|