2013-05-08 18:59:07 +08:00
|
|
|
//
|
|
|
|
// XMLHTTPRequest.cpp
|
|
|
|
// XMLHttpRequest
|
|
|
|
//
|
2013-05-14 17:36:48 +08:00
|
|
|
// Created by Zynga 2013
|
2013-05-08 18:59:07 +08:00
|
|
|
//
|
2013-05-14 20:16:22 +08:00
|
|
|
// Heavy based on: https://github.com/funkaster/FakeWebGL/blob/master/FakeWebGL/WebGL/XMLHTTPRequest.cpp
|
2013-05-08 18:59:07 +08:00
|
|
|
// Copyright (c) 2012 Rolando Abarca. All rights reserved.
|
|
|
|
//
|
|
|
|
// 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:
|
|
|
|
//
|
|
|
|
// The above copyright notice and this permission notice shall be included in
|
|
|
|
// all copies or substantial portions of the Software.
|
|
|
|
//
|
|
|
|
// 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.
|
|
|
|
|
|
|
|
|
|
|
|
#include "XMLHTTPRequest.h"
|
|
|
|
#include <string>
|
|
|
|
|
|
|
|
using namespace std;
|
|
|
|
|
2013-05-20 17:47:47 +08:00
|
|
|
//#pragma mark - MinXmlHttpRequest
|
2013-05-08 18:59:07 +08:00
|
|
|
|
|
|
|
/**
|
2013-05-14 18:03:58 +08:00
|
|
|
* @brief Implementation for header retrieving.
|
|
|
|
* @param header
|
2013-05-08 18:59:07 +08:00
|
|
|
*/
|
|
|
|
void MinXmlHttpRequest::_gotHeader(string header) {
|
|
|
|
// Get Header and Set StatusText
|
|
|
|
// Split String into Tokens
|
|
|
|
char * cstr = new char [header.length()+1];
|
2013-05-13 22:57:55 +08:00
|
|
|
|
2013-05-08 18:59:07 +08:00
|
|
|
// check for colon.
|
|
|
|
unsigned found_header_field = header.find_first_of(":");
|
|
|
|
|
|
|
|
if (found_header_field != std::string::npos) {
|
|
|
|
|
|
|
|
// Found a header field.
|
|
|
|
string http_field;
|
|
|
|
string http_value;
|
|
|
|
|
|
|
|
http_field = header.substr(0,found_header_field);
|
|
|
|
http_value = header.substr(found_header_field+1, header.length());
|
|
|
|
|
|
|
|
// Get rid of all \n
|
2013-05-14 23:21:27 +08:00
|
|
|
if (!http_value.empty() && http_value[http_value.size() - 1] == '\n') {
|
|
|
|
http_value.erase(http_value.size() - 1);
|
|
|
|
}
|
2013-05-08 18:59:07 +08:00
|
|
|
|
|
|
|
http_header[http_field] = http_value;
|
|
|
|
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
|
|
|
|
// Seems like we have the response Code! Parse it and check for it.
|
|
|
|
char * pch;
|
|
|
|
std::strcpy(cstr, header.c_str());
|
|
|
|
|
|
|
|
pch = strtok(cstr," ");
|
|
|
|
while (pch != NULL)
|
|
|
|
{
|
|
|
|
|
|
|
|
stringstream ss;
|
|
|
|
string val;
|
|
|
|
|
|
|
|
ss << pch;
|
|
|
|
val = ss.str();
|
|
|
|
unsigned found_http = val.find("HTTP");
|
|
|
|
|
|
|
|
// Check for HTTP Header to set statusText
|
|
|
|
if (found_http != std::string::npos) {
|
|
|
|
|
|
|
|
stringstream mystream;
|
|
|
|
|
|
|
|
// Get Response Status
|
|
|
|
pch = strtok (NULL, " ");
|
|
|
|
mystream << pch;
|
|
|
|
|
|
|
|
pch = strtok (NULL, " ");
|
|
|
|
mystream << " " << pch;
|
|
|
|
|
|
|
|
statusText = mystream.str();
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
pch = strtok (NULL, " ");
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2013-05-14 18:03:58 +08:00
|
|
|
* @brief Set Request header for next call.
|
|
|
|
* @param field Name of the Header to be set.
|
|
|
|
* @param value Value of the Headerfield
|
2013-05-08 18:59:07 +08:00
|
|
|
*/
|
|
|
|
void MinXmlHttpRequest::_setRequestHeader(const char* field, const char* value) {
|
|
|
|
|
|
|
|
stringstream header_s;
|
|
|
|
stringstream value_s;
|
|
|
|
string header;
|
|
|
|
|
|
|
|
map<string, string>::iterator iter = request_header.find(field);
|
|
|
|
|
2013-05-14 17:36:48 +08:00
|
|
|
// Concatenate values when header exists.
|
2013-05-08 18:59:07 +08:00
|
|
|
if (iter != request_header.end() ) {
|
|
|
|
|
|
|
|
value_s << iter->second << "," << value;
|
|
|
|
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
value_s << value;
|
|
|
|
}
|
|
|
|
|
|
|
|
request_header[field] = value_s.str();
|
|
|
|
return;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2013-05-14 18:03:58 +08:00
|
|
|
* @brief If headers has been set, pass them to curl.
|
|
|
|
*
|
2013-05-08 18:59:07 +08:00
|
|
|
*/
|
2013-05-14 17:36:48 +08:00
|
|
|
void MinXmlHttpRequest::_setHttpRequestHeader() {
|
2013-05-08 18:59:07 +08:00
|
|
|
|
2013-05-14 17:36:48 +08:00
|
|
|
std::vector<string> header;
|
2013-05-08 18:59:07 +08:00
|
|
|
|
|
|
|
for (std::map<string,string>::iterator it = request_header.begin(); it != request_header.end(); ++it) {
|
2013-05-23 20:37:32 +08:00
|
|
|
|
|
|
|
const char* first = it->first.c_str();
|
|
|
|
const char* second = it->second.c_str();
|
|
|
|
size_t len = sizeof(char) * (strlen(first) + 3 + strlen(second));
|
|
|
|
char* test = (char*) malloc(len);
|
|
|
|
memset(test, 0,len);
|
2013-05-08 18:59:07 +08:00
|
|
|
|
2013-05-23 20:37:32 +08:00
|
|
|
strcpy(test, first);
|
|
|
|
strcpy(test + strlen(first) , ": ");
|
|
|
|
strcpy(test + strlen(first) + 2, second);
|
|
|
|
|
|
|
|
header.push_back(test);
|
2013-05-08 18:59:07 +08:00
|
|
|
|
2013-05-23 20:37:32 +08:00
|
|
|
free(test);
|
2013-05-08 18:59:07 +08:00
|
|
|
|
|
|
|
}
|
|
|
|
|
2013-05-14 17:36:48 +08:00
|
|
|
if (!header.empty()) {
|
|
|
|
cc_request->setHeaders(header);
|
2013-05-08 18:59:07 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
2013-05-13 22:57:55 +08:00
|
|
|
/**
|
2013-05-14 18:03:58 +08:00
|
|
|
* @brief Callback for HTTPRequest. Handles the response and invokes Callback.
|
|
|
|
* @param sender Object which initialized callback
|
|
|
|
* @param respone Response object
|
2013-05-13 22:57:55 +08:00
|
|
|
*/
|
2013-05-20 17:47:47 +08:00
|
|
|
void MinXmlHttpRequest::handle_requestResponse(cocos2d::extension::CCHttpClient *sender, cocos2d::extension::CCHttpResponse *response) {
|
2013-05-10 21:00:03 +08:00
|
|
|
|
|
|
|
if (0 != strlen(response->getHttpRequest()->getTag()))
|
|
|
|
{
|
2013-05-20 17:47:47 +08:00
|
|
|
CCLOG("%s completed", response->getHttpRequest()->getTag());
|
2013-05-10 21:00:03 +08:00
|
|
|
}
|
2013-05-08 18:59:07 +08:00
|
|
|
|
2013-05-10 21:00:03 +08:00
|
|
|
int statusCode = response->getResponseCode();
|
|
|
|
char statusString[64] = {};
|
|
|
|
sprintf(statusString, "HTTP Status Code: %d, tag = %s", statusCode, response->getHttpRequest()->getTag());
|
2013-05-08 18:59:07 +08:00
|
|
|
|
2013-05-10 21:00:03 +08:00
|
|
|
if (!response->isSucceed())
|
|
|
|
{
|
2013-05-20 17:47:47 +08:00
|
|
|
CCLOG("response failed");
|
|
|
|
CCLOG("error buffer: %s", response->getErrorBuffer());
|
2013-05-10 21:00:03 +08:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2013-05-13 22:57:55 +08:00
|
|
|
// set header
|
|
|
|
std::vector<char> *headers = response->getResponseHeader();
|
|
|
|
|
|
|
|
char* concatHeader = (char*) malloc(headers->size() + 1);
|
|
|
|
std::string header(headers->begin(), headers->end());
|
|
|
|
strcpy(concatHeader, header.c_str());
|
|
|
|
|
|
|
|
std::istringstream stream(concatHeader);
|
|
|
|
std::string line;
|
|
|
|
while(std::getline(stream, line)) {
|
|
|
|
_gotHeader(line);
|
|
|
|
}
|
|
|
|
|
|
|
|
/** get the response data **/
|
2013-05-10 21:00:03 +08:00
|
|
|
std::vector<char> *buffer = response->getResponseData();
|
|
|
|
char* concatenated = (char*) malloc(buffer->size() + 1);
|
|
|
|
std::string s2(buffer->begin(), buffer->end());
|
|
|
|
|
|
|
|
strcpy(concatenated, s2.c_str());
|
|
|
|
|
|
|
|
if (statusCode == 200)
|
2013-05-08 18:59:07 +08:00
|
|
|
{
|
|
|
|
//Succeeded
|
|
|
|
status = 200;
|
|
|
|
readyState = DONE;
|
2013-05-13 22:57:55 +08:00
|
|
|
data << concatenated;
|
|
|
|
|
2013-05-08 18:59:07 +08:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
status = 0;
|
|
|
|
}
|
2013-05-15 21:15:23 +08:00
|
|
|
// Free Memory.
|
|
|
|
free((void*) concatHeader);
|
|
|
|
free((void*) concatenated);
|
2013-05-10 21:00:03 +08:00
|
|
|
|
|
|
|
js_proxy_t * p;
|
|
|
|
void* ptr = (void*)this;
|
|
|
|
JS_GET_PROXY(p, ptr);
|
|
|
|
|
|
|
|
if(p){
|
|
|
|
JSContext* cx = ScriptingCore::getInstance()->getGlobalContext();
|
|
|
|
|
|
|
|
if (onreadystateCallback) {
|
|
|
|
//JS_IsExceptionPending(cx) && JS_ReportPendingException(cx);
|
|
|
|
jsval fval = OBJECT_TO_JSVAL(onreadystateCallback);
|
|
|
|
jsval out;
|
|
|
|
JS_CallFunctionValue(cx, NULL, fval, 0, NULL, &out);
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
2013-05-08 18:59:07 +08:00
|
|
|
|
2013-05-10 21:00:03 +08:00
|
|
|
}
|
|
|
|
/**
|
2013-05-14 18:03:58 +08:00
|
|
|
* @brief Send out request and fire callback when done.
|
|
|
|
* @param cx Javascript context
|
2013-05-10 21:00:03 +08:00
|
|
|
*/
|
|
|
|
void MinXmlHttpRequest::_sendRequest(JSContext *cx) {
|
|
|
|
|
2013-05-20 17:47:47 +08:00
|
|
|
cc_request->setResponseCallback(this, httpresponse_selector(MinXmlHttpRequest::handle_requestResponse));
|
2013-05-10 21:00:03 +08:00
|
|
|
cocos2d::extension::CCHttpClient::getInstance()->send(cc_request);
|
|
|
|
cc_request->release();
|
2013-05-13 22:57:55 +08:00
|
|
|
|
2013-05-08 18:59:07 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2013-05-14 18:03:58 +08:00
|
|
|
* @brief Constructor initializes cchttprequest and stuff
|
2013-05-08 18:59:07 +08:00
|
|
|
*
|
|
|
|
*/
|
2013-05-20 17:47:47 +08:00
|
|
|
MinXmlHttpRequest::MinXmlHttpRequest() : onreadystateCallback(NULL), isNetwork(true) {
|
2013-05-08 18:59:07 +08:00
|
|
|
|
|
|
|
http_header.clear();
|
|
|
|
request_header.clear();
|
2013-05-23 20:37:32 +08:00
|
|
|
withCredentialsValue = true;
|
2013-05-20 17:47:47 +08:00
|
|
|
cx = ScriptingCore::getInstance()->getGlobalContext();
|
2013-05-10 21:00:03 +08:00
|
|
|
cc_request = new cocos2d::extension::CCHttpRequest();
|
2013-05-08 18:59:07 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2013-05-14 18:03:58 +08:00
|
|
|
* @brief Destructor cleans up cc_request and stuff
|
2013-05-08 18:59:07 +08:00
|
|
|
*
|
|
|
|
*/
|
|
|
|
MinXmlHttpRequest::~MinXmlHttpRequest() {
|
|
|
|
|
|
|
|
http_header.clear();
|
|
|
|
request_header.clear();
|
2013-05-10 21:00:03 +08:00
|
|
|
|
2013-05-20 17:47:47 +08:00
|
|
|
if (onreadystateCallback != NULL)
|
|
|
|
{
|
|
|
|
JS_RemoveObjectRoot(cx, &onreadystateCallback);
|
|
|
|
}
|
|
|
|
|
2013-05-10 21:00:03 +08:00
|
|
|
if (cc_request) {
|
2013-05-20 17:47:47 +08:00
|
|
|
// We don't need to release cc_request here since it will be released in the http callback.
|
|
|
|
// cc_request->release();
|
2013-05-10 21:00:03 +08:00
|
|
|
}
|
2013-05-13 22:57:55 +08:00
|
|
|
|
2013-05-08 18:59:07 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2013-05-14 18:03:58 +08:00
|
|
|
* @brief Initialize Object and needed properties.
|
2013-05-08 18:59:07 +08:00
|
|
|
*
|
|
|
|
*/
|
|
|
|
JS_BINDED_CLASS_GLUE_IMPL(MinXmlHttpRequest);
|
|
|
|
|
|
|
|
/**
|
2013-05-14 18:03:58 +08:00
|
|
|
* @brief Implementation for the Javascript Constructor
|
2013-05-08 18:59:07 +08:00
|
|
|
*
|
|
|
|
*/
|
|
|
|
JS_BINDED_CONSTRUCTOR_IMPL(MinXmlHttpRequest)
|
|
|
|
{
|
|
|
|
MinXmlHttpRequest* req = new MinXmlHttpRequest();
|
2013-05-20 17:47:47 +08:00
|
|
|
req->autorelease();
|
|
|
|
|
2013-05-10 21:00:03 +08:00
|
|
|
js_proxy_t *p;
|
2013-05-08 18:59:07 +08:00
|
|
|
jsval out;
|
2013-05-10 21:00:03 +08:00
|
|
|
|
|
|
|
JSObject *obj = JS_NewObject(cx, &MinXmlHttpRequest::js_class, MinXmlHttpRequest::js_proto, MinXmlHttpRequest::js_parent);
|
|
|
|
|
|
|
|
if (obj) {
|
|
|
|
JS_SetPrivate(obj, req);
|
|
|
|
out = OBJECT_TO_JSVAL(obj);
|
|
|
|
}
|
|
|
|
|
2013-05-08 18:59:07 +08:00
|
|
|
JS_SET_RVAL(cx, vp, out);
|
2013-05-10 21:00:03 +08:00
|
|
|
JS_NEW_PROXY(p, req, obj);
|
|
|
|
|
|
|
|
JS_AddNamedObjectRoot(cx, &p->obj, "XMLHttpRequest");
|
2013-05-08 18:59:07 +08:00
|
|
|
return JS_TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2013-05-14 18:03:58 +08:00
|
|
|
* @brief get Callback function for Javascript
|
|
|
|
*
|
2013-05-08 18:59:07 +08:00
|
|
|
*/
|
|
|
|
JS_BINDED_PROP_GET_IMPL(MinXmlHttpRequest, onreadystatechange)
|
|
|
|
{
|
|
|
|
if (onreadystateCallback) {
|
|
|
|
|
|
|
|
JSString *tmpstr = JS_NewStringCopyZ(cx, "1");
|
|
|
|
jsval tmpval = STRING_TO_JSVAL(tmpstr);
|
|
|
|
JS_SetProperty(cx, onreadystateCallback, "readyState", &tmpval);
|
|
|
|
|
|
|
|
jsval out = OBJECT_TO_JSVAL(onreadystateCallback);
|
|
|
|
vp.set(out);
|
|
|
|
|
|
|
|
} else {
|
|
|
|
vp.set(JSVAL_NULL);
|
|
|
|
}
|
|
|
|
return JS_TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2013-05-14 18:03:58 +08:00
|
|
|
* @brief Set Callback function coming from Javascript
|
2013-05-08 18:59:07 +08:00
|
|
|
*
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
JS_BINDED_PROP_SET_IMPL(MinXmlHttpRequest, onreadystatechange)
|
|
|
|
{
|
|
|
|
jsval callback = vp.get();
|
|
|
|
if (callback != JSVAL_NULL) {
|
|
|
|
onreadystateCallback = JSVAL_TO_OBJECT(callback);
|
2013-05-20 17:47:47 +08:00
|
|
|
JS_AddNamedObjectRoot(cx, &onreadystateCallback, "onreadystateCallback");
|
2013-05-08 18:59:07 +08:00
|
|
|
}
|
|
|
|
return JS_TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2013-05-14 18:03:58 +08:00
|
|
|
* @brief upload getter - TODO
|
2013-05-08 18:59:07 +08:00
|
|
|
*
|
2013-05-14 18:03:58 +08:00
|
|
|
* Placeholder for further implementations!!
|
2013-05-08 18:59:07 +08:00
|
|
|
*/
|
|
|
|
JS_BINDED_PROP_GET_IMPL(MinXmlHttpRequest, upload)
|
|
|
|
{
|
|
|
|
vp.set(JSVAL_NULL);
|
|
|
|
return JS_TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2013-05-14 18:03:58 +08:00
|
|
|
* @brief upload setter - TODO
|
2013-05-08 18:59:07 +08:00
|
|
|
*
|
|
|
|
* Placeholder for further implementations
|
|
|
|
*/
|
|
|
|
JS_BINDED_PROP_SET_IMPL(MinXmlHttpRequest, upload)
|
|
|
|
{
|
|
|
|
vp.set(JSVAL_NULL);
|
|
|
|
return JS_TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2013-05-14 18:03:58 +08:00
|
|
|
* @brief timeout getter - TODO
|
2013-05-08 18:59:07 +08:00
|
|
|
*
|
|
|
|
* Placeholder for further implementations
|
|
|
|
*/
|
|
|
|
JS_BINDED_PROP_GET_IMPL(MinXmlHttpRequest, timeout)
|
|
|
|
{
|
|
|
|
vp.set(INT_TO_JSVAL(timeout));
|
|
|
|
return JS_TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2013-05-14 18:03:58 +08:00
|
|
|
* @brief timeout setter - TODO
|
2013-05-08 18:59:07 +08:00
|
|
|
*
|
|
|
|
* Placeholder for further implementations
|
|
|
|
*/
|
|
|
|
JS_BINDED_PROP_SET_IMPL(MinXmlHttpRequest, timeout)
|
|
|
|
{
|
|
|
|
jsval timeout_ms = vp.get();
|
|
|
|
|
|
|
|
timeout = JSVAL_TO_INT(timeout_ms);
|
2013-05-13 22:57:55 +08:00
|
|
|
//curl_easy_setopt(curlHandle, CURLOPT_CONNECTTIMEOUT_MS, timeout);
|
2013-05-08 18:59:07 +08:00
|
|
|
return JS_TRUE;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2013-05-14 18:03:58 +08:00
|
|
|
* @brief get response type for actual XHR
|
2013-05-08 18:59:07 +08:00
|
|
|
*
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
JS_BINDED_PROP_GET_IMPL(MinXmlHttpRequest, responseType)
|
|
|
|
{
|
|
|
|
JSString* str = JS_NewStringCopyN(cx, "", 0);
|
|
|
|
vp.set(STRING_TO_JSVAL(str));
|
|
|
|
return JS_TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2013-05-14 18:03:58 +08:00
|
|
|
* @brief responseXML getter - TODO
|
2013-05-08 18:59:07 +08:00
|
|
|
*
|
|
|
|
* Placeholder for further implementation.
|
|
|
|
*/
|
|
|
|
JS_BINDED_PROP_GET_IMPL(MinXmlHttpRequest, responseXML)
|
|
|
|
{
|
|
|
|
vp.set(JSVAL_NULL);
|
|
|
|
return JS_TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2013-05-14 18:03:58 +08:00
|
|
|
* @brief set response type for actual XHR
|
2013-05-08 18:59:07 +08:00
|
|
|
*
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
JS_BINDED_PROP_SET_IMPL(MinXmlHttpRequest, responseType)
|
|
|
|
{
|
|
|
|
jsval type = vp.get();
|
|
|
|
if (type.isString()) {
|
|
|
|
JSString* str = type.toString();
|
|
|
|
JSBool equal;
|
|
|
|
JS_StringEqualsAscii(cx, str, "text", &equal);
|
|
|
|
if (equal) {
|
|
|
|
responseType = kRequestResponseTypeString;
|
|
|
|
return JS_TRUE;
|
|
|
|
}
|
|
|
|
JS_StringEqualsAscii(cx, str, "arraybuffer", &equal);
|
|
|
|
if (equal) {
|
|
|
|
responseType = kRequestResponseTypeArrayBuffer;
|
|
|
|
return JS_TRUE;
|
|
|
|
}
|
|
|
|
JS_StringEqualsAscii(cx, str, "json", &equal);
|
|
|
|
if (equal) {
|
|
|
|
responseType = kRequestResponseTypeJSON;
|
|
|
|
return JS_TRUE;
|
|
|
|
}
|
|
|
|
// ignore the rest of the response types for now
|
|
|
|
return JS_TRUE;
|
|
|
|
}
|
|
|
|
JS_ReportError(cx, "Invalid response type");
|
|
|
|
return JS_FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2013-05-14 18:03:58 +08:00
|
|
|
* @brief get readyState for actual XHR
|
2013-05-08 18:59:07 +08:00
|
|
|
*
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
JS_BINDED_PROP_GET_IMPL(MinXmlHttpRequest, readyState)
|
|
|
|
{
|
|
|
|
vp.set(INT_TO_JSVAL(readyState));
|
|
|
|
return JS_TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2013-05-14 18:03:58 +08:00
|
|
|
* @brief get status for actual XHR
|
2013-05-08 18:59:07 +08:00
|
|
|
*
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
JS_BINDED_PROP_GET_IMPL(MinXmlHttpRequest, status)
|
|
|
|
{
|
|
|
|
vp.set(INT_TO_JSVAL(status));
|
|
|
|
return JS_TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2013-05-14 18:03:58 +08:00
|
|
|
* @brief get statusText for actual XHR
|
2013-05-08 18:59:07 +08:00
|
|
|
*
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
JS_BINDED_PROP_GET_IMPL(MinXmlHttpRequest, statusText)
|
|
|
|
{
|
|
|
|
JSString* str = JS_NewStringCopyZ(cx, statusText.c_str());//, dataSize);
|
|
|
|
|
|
|
|
if (str) {
|
|
|
|
vp.set(STRING_TO_JSVAL(str));
|
|
|
|
return JS_TRUE;
|
|
|
|
} else {
|
|
|
|
JS_ReportError(cx, "Error trying to create JSString from data");
|
|
|
|
return JS_FALSE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2013-05-14 18:03:58 +08:00
|
|
|
* @brief get value of withCredentials property.
|
2013-05-08 18:59:07 +08:00
|
|
|
*
|
|
|
|
*/
|
|
|
|
JS_BINDED_PROP_GET_IMPL(MinXmlHttpRequest, withCredentials)
|
|
|
|
{
|
|
|
|
vp.set(BOOLEAN_TO_JSVAL(withCredentialsValue));
|
|
|
|
return JS_TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* withCredentials - set value of withCredentials property.
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
JS_BINDED_PROP_SET_IMPL(MinXmlHttpRequest, withCredentials)
|
|
|
|
{
|
|
|
|
jsval credential = vp.get();
|
|
|
|
if (credential != JSVAL_NULL) {
|
|
|
|
withCredentialsValue = JSVAL_TO_BOOLEAN(credential);
|
|
|
|
}
|
|
|
|
|
|
|
|
return JS_TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2013-05-14 18:03:58 +08:00
|
|
|
* @brief get (raw) responseText
|
2013-05-08 18:59:07 +08:00
|
|
|
*
|
|
|
|
*/
|
|
|
|
JS_BINDED_PROP_GET_IMPL(MinXmlHttpRequest, responseText)
|
|
|
|
{
|
|
|
|
JSString* str = JS_NewStringCopyZ(cx, data.str().c_str());//, dataSize);
|
|
|
|
|
|
|
|
if (str) {
|
|
|
|
vp.set(STRING_TO_JSVAL(str));
|
|
|
|
//JS_ReportError(cx, "Result: %s", data.str().c_str());
|
|
|
|
return JS_TRUE;
|
|
|
|
} else {
|
|
|
|
JS_ReportError(cx, "Error trying to create JSString from data");
|
|
|
|
return JS_FALSE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2013-05-14 18:03:58 +08:00
|
|
|
* @brief get response of latest XHR
|
2013-05-08 18:59:07 +08:00
|
|
|
*
|
|
|
|
*/
|
|
|
|
JS_BINDED_PROP_GET_IMPL(MinXmlHttpRequest, response)
|
|
|
|
{
|
|
|
|
|
|
|
|
if (responseType == kRequestResponseTypeJSON) {
|
|
|
|
jsval outVal;
|
|
|
|
|
|
|
|
JSString* str = JS_NewStringCopyZ(cx, data.str().c_str());//, dataSize);
|
|
|
|
if (JS_ParseJSON(cx, JS_GetStringCharsZ(cx, str), dataSize, &outVal)) {
|
|
|
|
|
|
|
|
vp.set(outVal);
|
|
|
|
return JS_TRUE;
|
|
|
|
}
|
|
|
|
} else if (responseType == kRequestResponseTypeArrayBuffer) {
|
|
|
|
JSObject* tmp = JS_NewArrayBuffer(cx, dataSize);
|
|
|
|
uint8_t* tmpData = JS_GetArrayBufferData(tmp);
|
|
|
|
data.read((char*)tmpData, dataSize);
|
|
|
|
jsval outVal = OBJECT_TO_JSVAL(tmp);
|
|
|
|
|
|
|
|
vp.set(outVal);
|
|
|
|
return JS_TRUE;
|
|
|
|
}
|
|
|
|
// by default, return text
|
|
|
|
return _js_get_responseText(cx, id, vp);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2013-05-14 18:03:58 +08:00
|
|
|
* @brief initialize new xhr.
|
2013-05-08 18:59:07 +08:00
|
|
|
*
|
|
|
|
*/
|
|
|
|
JS_BINDED_FUNC_IMPL(MinXmlHttpRequest, open)
|
|
|
|
{
|
|
|
|
|
|
|
|
if (argc >= 2) {
|
|
|
|
jsval* argv = JS_ARGV(cx, vp);
|
|
|
|
const char* method;
|
|
|
|
const char* urlstr;
|
|
|
|
JSBool async = true;
|
|
|
|
JSString* jsMethod = JS_ValueToString(cx, argv[0]);
|
|
|
|
JSString* jsURL = JS_ValueToString(cx, argv[1]);
|
2013-05-13 22:57:55 +08:00
|
|
|
|
2013-05-08 18:59:07 +08:00
|
|
|
if (argc > 2) {
|
|
|
|
JS_ValueToBoolean(cx, argv[2], &async);
|
|
|
|
}
|
2013-05-13 22:57:55 +08:00
|
|
|
|
2013-05-08 18:59:07 +08:00
|
|
|
JSStringWrapper w1(jsMethod);
|
|
|
|
JSStringWrapper w2(jsURL);
|
|
|
|
method = w1;
|
|
|
|
urlstr = w2;
|
|
|
|
|
|
|
|
url = urlstr;
|
|
|
|
meth = method;
|
|
|
|
readyState = 1;
|
|
|
|
isAsync = async;
|
|
|
|
|
|
|
|
if (url.length() > 5 && url.compare(url.length() - 5, 5, ".json") == 0) {
|
|
|
|
responseType = kRequestResponseTypeJSON;
|
|
|
|
}
|
2013-05-13 22:57:55 +08:00
|
|
|
|
2013-05-08 18:59:07 +08:00
|
|
|
if (meth.compare("post") == 0 || meth.compare("POST") == 0) {
|
2013-05-10 21:00:03 +08:00
|
|
|
cc_request->setRequestType(cocos2d::extension::CCHttpRequest::kHttpPost);
|
2013-05-08 18:59:07 +08:00
|
|
|
}
|
|
|
|
else {
|
2013-05-10 21:00:03 +08:00
|
|
|
cc_request->setRequestType(cocos2d::extension::CCHttpRequest::kHttpGet);
|
2013-05-08 18:59:07 +08:00
|
|
|
}
|
2013-05-10 21:00:03 +08:00
|
|
|
|
|
|
|
cc_request->setUrl(url.c_str());
|
|
|
|
|
2013-05-08 18:59:07 +08:00
|
|
|
isNetwork = true;
|
|
|
|
readyState = OPENED;
|
2013-05-10 21:00:03 +08:00
|
|
|
|
2013-05-08 18:59:07 +08:00
|
|
|
return JS_TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
JS_ReportError(cx, "invalid call: %s", __FUNCTION__);
|
|
|
|
return JS_FALSE;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2013-05-14 18:03:58 +08:00
|
|
|
* @brief send xhr
|
2013-05-08 18:59:07 +08:00
|
|
|
*
|
|
|
|
*/
|
|
|
|
JS_BINDED_FUNC_IMPL(MinXmlHttpRequest, send)
|
|
|
|
{
|
|
|
|
|
2013-05-20 21:13:11 +08:00
|
|
|
JSString *str = NULL;
|
|
|
|
char *data = NULL;
|
2013-05-08 18:59:07 +08:00
|
|
|
|
|
|
|
// Clean up header map. New request, new headers!
|
|
|
|
http_header.clear();
|
2013-05-20 21:13:11 +08:00
|
|
|
if (argc == 1) {
|
2013-05-15 19:57:25 +08:00
|
|
|
if (!JS_ConvertArguments(cx, argc, JS_ARGV(cx, vp), "S", &str)) {
|
|
|
|
return JS_FALSE;
|
|
|
|
};
|
|
|
|
data = JS_EncodeString(cx, str);
|
|
|
|
}
|
|
|
|
|
2013-05-15 21:15:23 +08:00
|
|
|
|
2013-05-20 21:13:11 +08:00
|
|
|
if (data != NULL && meth.compare("post") == 0 || meth.compare("POST") == 0) {
|
2013-05-10 21:00:03 +08:00
|
|
|
cc_request->setRequestData(data, strlen(data));
|
2013-05-08 18:59:07 +08:00
|
|
|
}
|
2013-05-13 22:57:55 +08:00
|
|
|
|
2013-05-14 17:36:48 +08:00
|
|
|
_setHttpRequestHeader();
|
2013-05-10 21:00:03 +08:00
|
|
|
_sendRequest(cx);
|
2013-05-14 17:36:48 +08:00
|
|
|
|
|
|
|
return JS_TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2013-05-14 18:03:58 +08:00
|
|
|
* @brief abort function Placeholder!
|
2013-05-14 17:36:48 +08:00
|
|
|
*
|
|
|
|
*/
|
|
|
|
JS_BINDED_FUNC_IMPL(MinXmlHttpRequest, abort)
|
|
|
|
{
|
2013-05-08 18:59:07 +08:00
|
|
|
return JS_TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2013-05-14 18:03:58 +08:00
|
|
|
* @brief Get all response headers as a string
|
2013-05-08 18:59:07 +08:00
|
|
|
*
|
|
|
|
*/
|
|
|
|
JS_BINDED_FUNC_IMPL(MinXmlHttpRequest, getAllResponseHeaders)
|
|
|
|
{
|
|
|
|
stringstream responseheaders;
|
|
|
|
string responseheader;
|
|
|
|
|
|
|
|
for (std::map<string,string>::iterator it=http_header.begin(); it!=http_header.end(); ++it) {
|
|
|
|
responseheaders << it->first << ": " << it->second << "\n";
|
|
|
|
}
|
|
|
|
|
|
|
|
responseheader = responseheaders.str();
|
|
|
|
|
|
|
|
JSString* str = JS_NewStringCopyZ(cx, responseheader.c_str());
|
|
|
|
|
|
|
|
if (str) {
|
|
|
|
JS_SET_RVAL(cx, vp, STRING_TO_JSVAL(str));
|
|
|
|
return JS_TRUE;
|
|
|
|
} else {
|
|
|
|
JS_ReportError(cx, "Error trying to create JSString from data");
|
|
|
|
return JS_FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
return JS_TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2013-05-14 18:03:58 +08:00
|
|
|
* @brief Get all response headers as a string
|
2013-05-08 18:59:07 +08:00
|
|
|
*
|
|
|
|
*/
|
|
|
|
JS_BINDED_FUNC_IMPL(MinXmlHttpRequest, getResponseHeader)
|
|
|
|
{
|
|
|
|
|
|
|
|
JSString *header_value;
|
|
|
|
|
|
|
|
if (!JS_ConvertArguments(cx, argc, JS_ARGV(cx, vp), "S", &header_value)) {
|
|
|
|
return JS_FALSE;
|
|
|
|
};
|
|
|
|
|
|
|
|
char *data = JS_EncodeString(cx, header_value);
|
|
|
|
stringstream streamdata;
|
|
|
|
|
|
|
|
streamdata << data;
|
|
|
|
|
|
|
|
string value = streamdata.str();
|
|
|
|
|
|
|
|
map<string, string>::iterator iter = http_header.find(value);
|
|
|
|
if (iter != http_header.end() ) {
|
|
|
|
|
|
|
|
JSString *js_ret_val = JS_NewStringCopyZ(cx, iter->second.c_str());
|
|
|
|
|
|
|
|
// iter->second
|
|
|
|
JS_SET_RVAL(cx, vp, STRING_TO_JSVAL(js_ret_val));
|
|
|
|
return JS_TRUE;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
JS_SET_RVAL(cx, vp, JSVAL_NULL);
|
|
|
|
return JS_TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2013-05-14 18:03:58 +08:00
|
|
|
* @brief Set the given Fields to request Header.
|
2013-05-08 18:59:07 +08:00
|
|
|
*
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
JS_BINDED_FUNC_IMPL(MinXmlHttpRequest, setRequestHeader)
|
|
|
|
{
|
|
|
|
|
|
|
|
if (argc >= 2) {
|
|
|
|
jsval* argv = JS_ARGV(cx, vp);
|
|
|
|
const char* field;
|
|
|
|
const char* value;
|
|
|
|
|
|
|
|
JSString* jsField = JS_ValueToString(cx, argv[0]);
|
|
|
|
JSString* jsValue = JS_ValueToString(cx, argv[1]);
|
|
|
|
|
|
|
|
JSStringWrapper w1(jsField);
|
|
|
|
JSStringWrapper w2(jsValue);
|
|
|
|
field = w1;
|
|
|
|
value = w2;
|
2013-05-23 20:37:32 +08:00
|
|
|
|
2013-05-08 18:59:07 +08:00
|
|
|
// Populate the request_header map.
|
|
|
|
_setRequestHeader(field, value);
|
|
|
|
|
|
|
|
return JS_TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
return JS_FALSE;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2013-05-14 18:03:58 +08:00
|
|
|
* @brief overrideMimeType function - TODO!
|
2013-05-08 18:59:07 +08:00
|
|
|
*
|
|
|
|
* Just a placeholder for further implementations.
|
|
|
|
*/
|
|
|
|
JS_BINDED_FUNC_IMPL(MinXmlHttpRequest, overrideMimeType)
|
|
|
|
{
|
|
|
|
return JS_TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2013-05-14 18:03:58 +08:00
|
|
|
* @brief destructor for Javascript
|
2013-05-08 18:59:07 +08:00
|
|
|
*
|
|
|
|
*/
|
2013-05-20 17:47:47 +08:00
|
|
|
static void basic_object_finalize(JSFreeOp *freeOp, JSObject *obj) {
|
|
|
|
CCLOG("basic_object_finalize %p ...", obj);
|
2013-05-08 18:59:07 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2013-05-14 18:03:58 +08:00
|
|
|
* @brief Register XMLHttpRequest to be usable in JS and add properties and Mehtods.
|
|
|
|
* @param cx Global Spidermonkey JS Context.
|
|
|
|
* @param global Global Spidermonkey Javascript object.
|
2013-05-08 18:59:07 +08:00
|
|
|
*/
|
|
|
|
void MinXmlHttpRequest::_js_register(JSContext *cx, JSObject *global) {
|
|
|
|
|
|
|
|
JSClass js_class = {
|
|
|
|
"XMLHttpRequest", JSCLASS_HAS_PRIVATE, JS_PropertyStub,
|
|
|
|
JS_PropertyStub, JS_PropertyStub, JS_StrictPropertyStub,
|
|
|
|
JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub,
|
|
|
|
basic_object_finalize, JSCLASS_NO_OPTIONAL_MEMBERS
|
|
|
|
};
|
|
|
|
|
|
|
|
MinXmlHttpRequest::js_class = js_class;
|
|
|
|
static JSPropertySpec props[] = {
|
|
|
|
JS_BINDED_PROP_DEF_ACCESSOR(MinXmlHttpRequest, onreadystatechange),
|
|
|
|
JS_BINDED_PROP_DEF_ACCESSOR(MinXmlHttpRequest, responseType),
|
|
|
|
JS_BINDED_PROP_DEF_ACCESSOR(MinXmlHttpRequest, withCredentials),
|
|
|
|
JS_BINDED_PROP_DEF_GETTER(MinXmlHttpRequest, readyState),
|
|
|
|
JS_BINDED_PROP_DEF_GETTER(MinXmlHttpRequest, status),
|
|
|
|
JS_BINDED_PROP_DEF_GETTER(MinXmlHttpRequest, statusText),
|
|
|
|
JS_BINDED_PROP_DEF_GETTER(MinXmlHttpRequest, responseText),
|
2013-05-14 20:16:22 +08:00
|
|
|
JS_BINDED_PROP_DEF_GETTER(MinXmlHttpRequest, responseXML),
|
2013-05-08 18:59:07 +08:00
|
|
|
JS_BINDED_PROP_DEF_GETTER(MinXmlHttpRequest, response),
|
|
|
|
{0, 0, 0, 0, 0}
|
|
|
|
};
|
|
|
|
|
|
|
|
static JSFunctionSpec funcs[] = {
|
|
|
|
JS_BINDED_FUNC_FOR_DEF(MinXmlHttpRequest, open),
|
2013-05-14 17:36:48 +08:00
|
|
|
JS_BINDED_FUNC_FOR_DEF(MinXmlHttpRequest, abort),
|
2013-05-08 18:59:07 +08:00
|
|
|
JS_BINDED_FUNC_FOR_DEF(MinXmlHttpRequest, send),
|
|
|
|
JS_BINDED_FUNC_FOR_DEF(MinXmlHttpRequest, setRequestHeader),
|
|
|
|
JS_BINDED_FUNC_FOR_DEF(MinXmlHttpRequest, getAllResponseHeaders),
|
|
|
|
JS_BINDED_FUNC_FOR_DEF(MinXmlHttpRequest, getResponseHeader),
|
|
|
|
JS_BINDED_FUNC_FOR_DEF(MinXmlHttpRequest, overrideMimeType),
|
|
|
|
JS_FS_END
|
|
|
|
};
|
|
|
|
|
|
|
|
MinXmlHttpRequest::js_parent = NULL;
|
|
|
|
MinXmlHttpRequest::js_proto = JS_InitClass(cx, global, NULL, &MinXmlHttpRequest::js_class , MinXmlHttpRequest::_js_constructor, 0, props, funcs, NULL, NULL);
|
|
|
|
|
|
|
|
}
|
|
|
|
|