diff options
author | Jens Geyer <jensg@apache.org> | 2021-02-25 09:42:52 +0100 |
---|---|---|
committer | Jens Geyer <jensg@apache.org> | 2021-03-17 20:42:29 +0100 |
commit | 2dcefadba853c9ad0ab5e908894213826ec3b43a (patch) | |
tree | 2b5f791d79d67538dbb7001673b43203fecea339 | |
parent | 62beb6751d3c70f8db8fed4a3bb76e4ff3765c22 (diff) | |
download | thrift-2dcefadba853c9ad0ab5e908894213826ec3b43a.tar.gz |
THRIFT-5370 Haxe 4 compatibility incl TConfiguration & MAX_MESSAGE_SIZE
Client: haxe
Patch: Jens Geyer
This closes #2349
44 files changed, 1172 insertions, 757 deletions
diff --git a/.gitignore b/.gitignore index 603838fca..c34d9f643 100644 --- a/.gitignore +++ b/.gitignore @@ -355,6 +355,7 @@ project.lock.json /test/go/src/gen/ /test/go/src/thrift /test/haxe/bin +/test/haxe/.buildtemp /test/hs/TestClient /test/hs/TestServer /test/php/php_ext_dir/ diff --git a/compiler/cpp/src/thrift/generate/t_haxe_generator.cc b/compiler/cpp/src/thrift/generate/t_haxe_generator.cc index 725a5344e..9f8e9468d 100644 --- a/compiler/cpp/src/thrift/generate/t_haxe_generator.cc +++ b/compiler/cpp/src/thrift/generate/t_haxe_generator.cc @@ -52,12 +52,11 @@ public: (void)option_string; std::map<std::string, std::string>::const_iterator iter; - callbacks_ = false; rtti_ = false; buildmacro_ = ""; for( iter = parsed_options.begin(); iter != parsed_options.end(); ++iter) { if( iter->first.compare("callbacks") == 0) { - callbacks_ = true; + printf("Hint: The 'callbacks' option is no longer necessary.\n"); } else if( iter->first.compare("rtti") == 0) { rtti_ = true; } else if( iter->first.compare("buildmacro") == 0) { @@ -115,7 +114,7 @@ public: void generate_haxe_validator(std::ostream& out, t_struct* tstruct); void generate_haxe_struct_result_writer(std::ostream& out, t_struct* tstruct); void generate_haxe_struct_writer(std::ostream& out, t_struct* tstruct); - void generate_haxe_struct_tostring(std::ostream& out, t_struct* tstruct); + void generate_haxe_struct_tostring(std::ostream& out, t_struct* tstruct, bool is_override); void generate_haxe_meta_data_map(std::ostream& out, t_struct* tstruct); void generate_field_value_meta_data(std::ostream& out, t_type* type); std::string get_haxe_type_string(t_type* type); @@ -138,12 +137,12 @@ public: void generate_isset_set(ostream& out, t_field* field); // removed std::string isset_field_id(t_field* field); - void generate_service_interface(t_service* tservice); + void generate_service_interface(t_service* tservice, bool combined); void generate_service_helpers(t_service* tservice); void generate_service_client(t_service* tservice); void generate_service_server(t_service* tservice); void generate_process_function(t_service* tservice, t_function* tfunction); - void generate_service_method_signature(t_function* tfunction, bool is_interface); + void generate_service_method_signature(t_function* tfunction, bool is_interface, bool combined); /** * Serialization constructs @@ -186,13 +185,13 @@ public: std::string type_name(t_type* ttype, bool in_container = false, bool in_init = false); std::string base_type_name(t_base_type* tbase, bool in_container = false); std::string declare_field(t_field* tfield, bool init = false); - std::string function_signature_callback(t_function* tfunction); + std::string function_signature_combined(t_function* tfunction); std::string function_signature_normal(t_function* tfunction); std::string argument_list(t_struct* tstruct); std::string type_to_enum(t_type* ttype); std::string get_enum_class_name(t_type* type) override; string generate_service_method_onsuccess(t_function* tfunction, bool as_type, bool omit_name); - void generate_service_method_signature_callback(t_function* tfunction, bool is_interface); + void generate_service_method_signature_combined(t_function* tfunction, bool is_interface); void generate_service_method_signature_normal(t_function* tfunction, bool is_interface); bool type_can_be_null(t_type* ttype) { @@ -220,7 +219,6 @@ public: std::string constant_name(std::string name); private: - bool callbacks_; bool rtti_; string buildmacro_; @@ -290,10 +288,17 @@ string t_haxe_generator::haxe_package() { * @return List of imports for haxe types that are used in here */ string t_haxe_generator::haxe_type_imports() { - return string() + "import org.apache.thrift.helper.*;\n" + "import haxe.io.Bytes;\n" - + "import haxe.ds.IntMap;\n" + "import haxe.ds.StringMap;\n" - + "import haxe.ds.ObjectMap;\n" + "\n" + "#if flash\n" - + "import flash.errors.ArgumentError;\n" + "#end\n" + "\n"; + return string() + + "import org.apache.thrift.helper.*;\n" + + "import haxe.io.Bytes;\n" + + "import haxe.ds.IntMap;\n" + + "import haxe.ds.StringMap;\n" + + "import haxe.ds.ObjectMap;\n" + + "\n" + + "#if flash\n" + + "import flash.errors.ArgumentError;\n" + + "#end\n" + + "\n"; } /** @@ -302,8 +307,11 @@ string t_haxe_generator::haxe_type_imports() { * @return List of imports necessary for thrift */ string t_haxe_generator::haxe_thrift_imports() { - return string() + "import org.apache.thrift.*;\n" + "import org.apache.thrift.meta_data.*;\n" - + "import org.apache.thrift.protocol.*;\n" + "\n"; + return string() + + "import org.apache.thrift.*;\n" + + "import org.apache.thrift.meta_data.*;\n" + + "import org.apache.thrift.protocol.*;\n" + + "\n"; } /** @@ -348,8 +356,7 @@ string t_haxe_generator::haxe_thrift_gen_imports(t_service* tservice) { string package = program->get_namespace("haxe"); if (!package.empty()) { if (imports.find(package + "." + (*f_iter)->get_returntype()->get_name()) == string::npos) { - imports.append("import " + package + "." + (*f_iter)->get_returntype()->get_name() - + ";\n"); + imports.append("import " + package + "." + (*f_iter)->get_returntype()->get_name()+ ";\n"); } } } @@ -718,10 +725,8 @@ void t_haxe_generator::generate_haxe_struct_definition(ostream& out, if (is_exception) { out << "extends TException "; } - out << "implements TBase "; - - scope_up(out); - indent(out) << endl; + out << "implements TBase {" << endl << endl; + indent_up(); indent(out) << "static var STRUCT_DESC = { new TStruct(\"" << tstruct->get_name() << "\"); };" << endl; @@ -806,7 +811,7 @@ void t_haxe_generator::generate_haxe_struct_definition(ostream& out, } else { generate_haxe_struct_writer(out, tstruct); } - generate_haxe_struct_tostring(out, tstruct); + generate_haxe_struct_tostring(out, tstruct, is_exception); generate_haxe_validator(out, tstruct); scope_down(out); out << endl; @@ -1272,9 +1277,12 @@ void t_haxe_generator::generate_property_getters_setters(ostream& out, t_struct* * * @param tstruct The struct definition */ -void t_haxe_generator::generate_haxe_struct_tostring(ostream& out, t_struct* tstruct) { - out << indent() << "public " - << "function toString() : String {" << endl; +void t_haxe_generator::generate_haxe_struct_tostring(ostream& out, t_struct* tstruct, bool is_override) { + out << indent() << "public "; + if( is_override) { + out << "override "; + } + out << "function toString() : String {" << endl; indent_up(); out << indent() << "var ret : String = \"" << tstruct->get_name() << "(\";" << endl; @@ -1474,8 +1482,8 @@ void t_haxe_generator::generate_field_value_meta_data(std::ostream& out, t_type* * @param tservice The service definition */ void t_haxe_generator::generate_service(t_service* tservice) { - // Make interface file - string f_service_name = package_dir_ + "/" + get_cap_name(service_name_) + ".hx"; + // Make service interface file with only "normal" calls + string f_service_name = package_dir_ + "/" + get_cap_name(service_name_) + "_service.hx"; f_service_.open(f_service_name.c_str()); f_service_ << autogen_comment() << haxe_package() << ";" << endl; @@ -1487,14 +1495,35 @@ void t_haxe_generator::generate_service(t_service* tservice) { t_type* parent = tservice->get_extends(); string parent_namespace = parent->get_program()->get_namespace("haxe"); if (!parent_namespace.empty() && parent_namespace != package_name_) { - f_service_ << "import " << type_name(parent) << ";" << endl; + f_service_ << "import " << type_name(parent) << "_service;" << endl; } } f_service_ << endl; - generate_service_interface(tservice); + generate_service_interface(tservice,false); + f_service_.close(); + // Client interface file with dual suppport ("normal" and "callback" style) + f_service_name = package_dir_ + "/" + get_cap_name(service_name_) + ".hx"; + f_service_.open(f_service_name.c_str()); + + f_service_ << autogen_comment() << haxe_package() << ";" << endl; + + f_service_ << endl << haxe_type_imports() << haxe_thrift_imports() + << haxe_thrift_gen_imports(tservice); + + if (tservice->get_extends() != nullptr) { + t_type* parent = tservice->get_extends(); + string parent_namespace = parent->get_program()->get_namespace("haxe"); + if (!parent_namespace.empty() && parent_namespace != package_name_) { + f_service_ << "import " << type_name(parent) << ";" << endl; + } + } + + f_service_ << endl; + + generate_service_interface(tservice,true); f_service_.close(); // Now make the implementation/client file @@ -1515,7 +1544,6 @@ void t_haxe_generator::generate_service(t_service* tservice) { f_service_ << endl; generate_service_client(tservice); - f_service_.close(); // Now make the helper class files @@ -1525,18 +1553,20 @@ void t_haxe_generator::generate_service(t_service* tservice) { f_service_name = package_dir_ + "/" + get_cap_name(service_name_) + "Processor.hx"; f_service_.open(f_service_name.c_str()); - f_service_ << autogen_comment() << haxe_package() << ";" << endl << endl << haxe_type_imports() - << haxe_thrift_imports() << haxe_thrift_gen_imports(tservice) << endl; + f_service_ << autogen_comment() << haxe_package() << ";" << endl + << endl + << haxe_type_imports() + << haxe_thrift_imports() + << haxe_thrift_gen_imports(tservice) + << endl; if (!package_name_.empty()) { f_service_ << "import " << package_name_ << ".*;" << endl; - f_service_ << "import " << package_name_ << "." << get_cap_name(service_name_).c_str() - << "Impl;" << endl; + f_service_ << "import " << package_name_ << "." << get_cap_name(service_name_).c_str() << "Impl;" << endl; f_service_ << endl; } generate_service_server(tservice); - f_service_.close(); } @@ -1580,9 +1610,9 @@ string t_haxe_generator::generate_service_method_onsuccess(t_function* tfunction * * @param tfunction The service function to generate code for. */ -void t_haxe_generator::generate_service_method_signature(t_function* tfunction, bool is_interface) { - if (callbacks_) { - generate_service_method_signature_callback(tfunction, is_interface); +void t_haxe_generator::generate_service_method_signature(t_function* tfunction, bool is_interface, bool combined) { + if( combined) { + generate_service_method_signature_combined(tfunction, is_interface); } else { generate_service_method_signature_normal(tfunction, is_interface); } @@ -1607,7 +1637,7 @@ void t_haxe_generator::generate_service_method_signature_normal(t_function* tfun * * @param tfunction The service function to generate code for. */ -void t_haxe_generator::generate_service_method_signature_callback(t_function* tfunction, +void t_haxe_generator::generate_service_method_signature_combined(t_function* tfunction, bool is_interface) { if (!tfunction->is_oneway()) { std::string on_success_impl = generate_service_method_onsuccess(tfunction, false, false); @@ -1616,9 +1646,9 @@ void t_haxe_generator::generate_service_method_signature_callback(t_function* tf } if (is_interface) { - indent(f_service_) << function_signature_callback(tfunction) << ";" << endl << endl; + indent(f_service_) << function_signature_combined(tfunction) << ";" << endl << endl; } else { - indent(f_service_) << "public " << function_signature_callback(tfunction) << " {" << endl; + indent(f_service_) << "public " << function_signature_combined(tfunction) << " {" << endl; } } @@ -1627,24 +1657,26 @@ void t_haxe_generator::generate_service_method_signature_callback(t_function* tf * * @param tservice The service to generate a header definition for */ -void t_haxe_generator::generate_service_interface(t_service* tservice) { +void t_haxe_generator::generate_service_interface(t_service* tservice, bool combined) { + string cbk_postfix = combined ? "" : "_service"; + string extends_iface = ""; if (tservice->get_extends() != nullptr) { - extends_iface = " extends " + tservice->get_extends()->get_name(); + extends_iface = " extends " + tservice->get_extends()->get_name() + cbk_postfix; } + vector<t_function*> functions = tservice->get_functions(); + vector<t_function*>::iterator f_iter; + generate_haxe_doc(f_service_, tservice); - // generate_rtti_decoration(f_service_); - not yet, because of - // https://github.com/HaxeFoundation/haxe/issues/3626 + generate_rtti_decoration(f_service_); generate_macro_decoration(f_service_); - f_service_ << indent() << "interface " << get_cap_name(service_name_) << extends_iface << " {" + f_service_ << indent() << "interface " << get_cap_name(service_name_) << cbk_postfix << extends_iface << " {" << endl << endl; indent_up(); - vector<t_function*> functions = tservice->get_functions(); - vector<t_function*>::iterator f_iter; for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) { generate_haxe_doc(f_service_, *f_iter); - generate_service_method_signature(*f_iter, true); + generate_service_method_signature(*f_iter, true, combined); } indent_down(); f_service_ << indent() << "}" << endl << endl; @@ -1729,7 +1761,7 @@ void t_haxe_generator::generate_service_client(t_service* tservice) { string funname = (*f_iter)->get_name(); // Open function - generate_service_method_signature(*f_iter, false); + generate_service_method_signature(*f_iter, false, true); indent_up(); @@ -1741,21 +1773,23 @@ void t_haxe_generator::generate_service_client(t_service* tservice) { const vector<t_field*>& fields = arg_struct->get_members(); // Serialize the request + string args = tmp("args"); string calltype = (*f_iter)->is_oneway() ? "ONEWAY" : "CALL"; f_service_ << indent() << "oprot_.writeMessageBegin(new TMessage(\"" << funname << "\", TMessageType." << calltype << ", seqid_));" << endl << indent() - << "var args : " << argsname << " = new " << argsname << "();" << endl; + << "var " << args << " : " << argsname << " = new " << argsname << "();" << endl; for (fld_iter = fields.begin(); fld_iter != fields.end(); ++fld_iter) { - f_service_ << indent() << "args." << (*fld_iter)->get_name() << " = " + f_service_ << indent() << args << "." << (*fld_iter)->get_name() << " = " << (*fld_iter)->get_name() << ";" << endl; } - f_service_ << indent() << "args.write(oprot_);" << endl << indent() + f_service_ << indent() << args << ".write(oprot_);" << endl << indent() << "oprot_.writeMessageEnd();" << endl; + string retval = tmp("retval"); if (!((*f_iter)->is_oneway() || (*f_iter)->get_returntype()->is_void())) { - f_service_ << indent() << "var retval : " << type_name((*f_iter)->get_returntype()) << ";" + f_service_ << indent() << "var " << retval << " : " << type_name((*f_iter)->get_returntype()) << ";" << endl; } @@ -1764,109 +1798,108 @@ void t_haxe_generator::generate_service_client(t_service* tservice) { } else { indent(f_service_) << "oprot_.getTransport().flush(function(error:Dynamic) : Void {" << endl; indent_up(); - if (callbacks_) { - indent(f_service_) << "try {" << endl; - indent_up(); - } + indent(f_service_) << "try {" << endl; + indent_up(); + string appex = tmp("appex"); + indent(f_service_) << "var " << appex << " : TApplicationException;" << endl; string resultname = get_cap_name((*f_iter)->get_name() + "_result"); indent(f_service_) << "if (error != null) {" << endl; indent_up(); - if (callbacks_) { - indent(f_service_) << "if (onError != null) onError(error);" << endl; - indent(f_service_) << "return;" << endl; - } else { - indent(f_service_) << "throw error;" << endl; - } + indent(f_service_) << "if (onError == null)" << endl; + indent_up(); + indent(f_service_) << "throw error;" << endl; indent_down(); - indent(f_service_) << "}" << endl; - indent(f_service_) << "var msg : TMessage = iprot_.readMessageBegin();" << endl; - indent(f_service_) << "if (msg.type == TMessageType.EXCEPTION) {" << endl; + indent(f_service_) << "onError(error);" << endl; + indent(f_service_) << "return;" << endl; + indent_down(); + indent(f_service_) << "}" << endl << endl; + string msg = tmp("msg"); + indent(f_service_) << "var " << msg << " : TMessage = iprot_.readMessageBegin();" << endl; + indent(f_service_) << "if (" << msg << ".type == TMessageType.EXCEPTION) {" << endl; indent_up(); - indent(f_service_) << "var x = TApplicationException.read(iprot_);" << endl; + indent(f_service_) << appex << " = TApplicationException.read(iprot_);" << endl; indent(f_service_) << "iprot_.readMessageEnd();" << endl; - if (callbacks_) { - indent(f_service_) << "if (onError != null) onError(x);" << endl; - indent(f_service_) << "return;" << endl; - } else { - indent(f_service_) << "throw x;" << endl; - } + indent(f_service_) << "if (onError == null)" << endl; + indent_up(); + indent(f_service_) << "throw " << appex << ";" << endl; indent_down(); - indent(f_service_) << "}" << endl; - indent(f_service_) << "var result : " << resultname << " = new " << resultname << "();" - << endl; - indent(f_service_) << "result.read(iprot_);" << endl; + indent(f_service_) << "onError(" << appex << ");" << endl; + indent(f_service_) << "return;" << endl; + indent_down(); + indent(f_service_) << "}" << endl << endl; + string result = tmp("result"); + indent(f_service_) << "var " << result << " : " << resultname << " = new " << resultname << "();" << endl; + indent(f_service_) << "" << result << ".read(iprot_);" << endl; indent(f_service_) << "iprot_.readMessageEnd();" << endl; // Careful, only return _result if not a void function if (!(*f_iter)->get_returntype()->is_void()) { - indent(f_service_) << "if (result." << generate_isset_check("success") << ") {" << endl; + indent(f_service_) << "if (" << result << "." << generate_isset_check("success") << ") {" << endl; indent_up(); - if (callbacks_) { - indent(f_service_) << "if (onSuccess != null) onSuccess(result.success);" << endl; - indent(f_service_) << "return;" << endl; - } else { - indent(f_service_) << "retval = result.success;" << endl; - indent(f_service_) << "return;" << endl; - } + indent(f_service_) << "if (onSuccess != null)" << endl; + indent_up(); + indent(f_service_) << "onSuccess(" << result << ".success);" << endl; indent_down(); - indent(f_service_) << "}" << endl; + indent(f_service_) << retval << " = " << result << ".success;" << endl; + indent(f_service_) << "return;" << endl; + indent_down(); + indent(f_service_) << "}" << endl << endl; } t_struct* xs = (*f_iter)->get_xceptions(); const std::vector<t_field*>& xceptions = xs->get_members(); vector<t_field*>::const_iterator x_iter; for (x_iter = xceptions.begin(); x_iter != xceptions.end(); ++x_iter) { - indent(f_service_) << "if (result." << (*x_iter)->get_name() << " != null) {" << endl; + indent(f_service_) << "if (" << result << "." << (*x_iter)->get_name() << " != null) {" << endl; indent_up(); - if (callbacks_) { - indent(f_service_) << "if (onError != null) onError(result." << (*x_iter)->get_name() - << ");" << endl; - indent(f_service_) << "return;" << endl; - } else { - indent(f_service_) << "throw result." << (*x_iter)->get_name() << ";" << endl; - } + indent(f_service_) << "if (onError == null)" << endl; + indent_up(); + indent(f_service_) << "throw " << result << "." << (*x_iter)->get_name() << ";" << endl; + indent_down(); + indent(f_service_) << "onError(" << result << "." << (*x_iter)->get_name() << ");" << endl; + indent(f_service_) << "return;" << endl; indent_down(); - indent(f_service_) << "}" << endl; + indent(f_service_) << "}" << endl << endl; } // If you get here it's an exception, unless a void function if ((*f_iter)->get_returntype()->is_void()) { - if (callbacks_) { - indent(f_service_) << "if (onSuccess != null) onSuccess();" << endl; - } + indent(f_service_) << "if (onSuccess != null)" << endl; + indent_up(); + indent(f_service_) << "onSuccess();" << endl; + indent_down(); indent(f_service_) << "return;" << endl; } else { - if (callbacks_) { - indent(f_service_) << "if (onError != null)" << endl; - indent_up(); - indent(f_service_) - << "onError( new TApplicationException(TApplicationException.MISSING_RESULT," << endl; - indent(f_service_) << " \"" << (*f_iter)->get_name() - << " failed: unknown result\"));" << endl; - indent_down(); - } else { - indent(f_service_) - << "throw new TApplicationException(TApplicationException.MISSING_RESULT," << endl; - indent(f_service_) << " \"" << (*f_iter)->get_name() - << " failed: unknown result\");" << endl; - } - } - - if (callbacks_) { - indent_down(); - indent(f_service_) << "} catch( e : TException) {" << endl; + indent(f_service_) << appex << " = new TApplicationException(" + << "TApplicationException.MISSING_RESULT," + << "\"" << (*f_iter)->get_name() << " failed: unknown result\");" << endl; + indent(f_service_) << "if (onError == null)" << endl; indent_up(); - indent(f_service_) << "if (onError != null) onError(e);" << endl; + indent(f_service_) << "throw " << appex << ";" << endl; indent_down(); - indent(f_service_) << "}" << endl; + indent(f_service_) << "onError(" << appex << ");" << endl; + indent(f_service_) << "return;" << endl; } indent_down(); - indent(f_service_) << "});" << endl; + indent(f_service_) << endl; + indent(f_service_) << "} catch( e : TException) {" << endl; + indent_up(); + indent(f_service_) << "if (onError == null)" << endl; + indent_up(); + indent(f_service_) << "throw e;" << endl; + indent_down(); + indent(f_service_) << "onError(e);" << endl; + indent(f_service_) << "return;" << endl; + indent_down(); + indent(f_service_) << "}" << endl; + + indent_down(); + indent(f_service_) << "});" << endl << endl; } if (!((*f_iter)->is_oneway() || (*f_iter)->get_returntype()->is_void())) { - f_service_ << indent() << "return retval;" << endl; + f_service_ << indent() << "return " << retval << ";" << endl; } // Close function @@ -1904,7 +1937,7 @@ void t_haxe_generator::generate_service_server(t_service* tservice) { indent_up(); f_service_ << indent() << "private var " << get_cap_name(service_name_) - << "_iface_ : " << get_cap_name(service_name_) << ";" << endl; + << "_iface_ : " << get_cap_name(service_name_) << "_service;" << endl; if (extends.empty()) { f_service_ << indent() @@ -1914,7 +1947,7 @@ void t_haxe_generator::generate_service_server(t_service* tservice) { f_service_ << endl; - indent(f_service_) << "public function new( iface : " << get_cap_name(service_name_) << ")" + indent(f_service_) << "public function new( iface : " << get_cap_name(service_name_) << "_service)" << endl; scope_up(f_service_); if (!extends.empty()) { @@ -1943,20 +1976,20 @@ void t_haxe_generator::generate_service_server(t_service* tservice) { f_service_ << indent() << "var msg : TMessage = iprot.readMessageBegin();" << endl; // TODO(mcslee): validate message, was the seqid etc. legit? - // AS- If all method is oneway: - // do you have an oprot? - // do you you need nullcheck? + f_service_ - << indent() << "var fn = PROCESS_MAP.get(msg.name);" << endl << indent() - << "if (fn == null) {" << endl << indent() << " TProtocolUtil.skip(iprot, TType.STRUCT);" - << endl << indent() << " iprot.readMessageEnd();" << endl << indent() - << " var x = new TApplicationException(TApplicationException.UNKNOWN_METHOD, \"Invalid " - "method name: '\"+msg.name+\"'\");" << endl << indent() - << " oprot.writeMessageBegin(new TMessage(msg.name, TMessageType.EXCEPTION, msg.seqid));" - << endl << indent() << " x.write(oprot);" << endl << indent() << " oprot.writeMessageEnd();" - << endl << indent() << " oprot.getTransport().flush();" << endl << indent() - << " return true;" << endl << indent() << "}" << endl << indent() - << "fn( msg.seqid, iprot, oprot);" << endl; + << indent() << "var fn = PROCESS_MAP.get(msg.name);" << endl + << indent() << "if (fn == null) {" << endl + << indent() << " TProtocolUtil.skip(iprot, TType.STRUCT);" << endl + << indent() << " iprot.readMessageEnd();" << endl + << indent() << " var appex = new TApplicationException(TApplicationException.UNKNOWN_METHOD, " + << "\"Invalid method name: '\"+msg.name+\"'\");" << endl + << indent() << " oprot.writeMessageBegin(new TMessage(msg.name, TMessageType.EXCEPTION, msg.seqid));" << endl + << indent() << " appex.write(oprot);" << endl << indent() << " oprot.writeMessageEnd();" << endl + << indent() << " oprot.getTransport().flush();" << endl + << indent() << " return true;" << endl << indent() << "}" << endl + << indent() << "fn( msg.seqid, iprot, oprot);" << endl + ; f_service_ << indent() << "return true;" << endl; @@ -2029,84 +2062,36 @@ void t_haxe_generator::generate_process_function(t_service* tservice, t_function // Declare result for non oneway function if (!tfunction->is_oneway()) { - f_service_ << indent() << "var result : " << resultname << " = new " << resultname << "();" - << endl; + f_service_ << indent() << "var result : " << resultname << " = new " << resultname << "();" << endl; } // Try block for any function to catch (defined or undefined) exceptions f_service_ << indent() << "try {" << endl; indent_up(); - if (callbacks_) { - // callback function style onError/onSuccess - // Generate the function call - t_struct* arg_struct = tfunction->get_arglist(); - const std::vector<t_field*>& fields = arg_struct->get_members(); - vector<t_field*>::const_iterator f_iter; + // normal function():result style - f_service_ << indent(); - f_service_ << get_cap_name(service_name_) << "_iface_." << tfunction->get_name() << "("; - bool first = true; - for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) { - if (first) { - first = false; - } else { - f_service_ << ", "; - } - f_service_ << "args." << (*f_iter)->get_name(); - } + // Generate the function call + t_struct* arg_struct = tfunction->get_arglist(); + const std::vector<t_field*>& fields = arg_struct->get_members(); + vector<t_field*>::const_iterator f_iter; - if (tfunction->is_oneway()) { - f_service_ << ");" << endl; + f_service_ << indent(); + if (!(tfunction->is_oneway() || tfunction->get_returntype()->is_void())) { + f_service_ << "result.success = "; + } + f_service_ << get_cap_name(service_name_) << "_iface_." << tfunction->get_name() << "("; + bool first = true; + for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) { + if (first) { + first = false; } else { - if (first) { - first = false; - } else { - f_service_ << ", "; - } - string on_success = generate_service_method_onsuccess(tfunction, false, true); - indent_up(); - f_service_ << endl; - indent(f_service_) << "null, // errors are thrown by the handler" << endl; - if (tfunction->get_returntype()->is_void()) { - indent(f_service_) << "null); // no retval" << endl; - } else { - indent(f_service_) << "function" << on_success.c_str() << " {" << endl; - if (!tfunction->get_returntype()->is_void()) { - indent_up(); - indent(f_service_) << "result.success = retval;" << endl; - indent_down(); - } - indent(f_service_) << "});" << endl; - } - indent_down(); - } - - } else { - // normal function():result style - - // Generate the function call - t_struct* arg_struct = tfunction->get_arglist(); - const std::vector<t_field*>& fields = arg_struct->get_members(); - vector<t_field*>::const_iterator f_iter; - - f_service_ << indent(); - if (!(tfunction->is_oneway() || tfunction->get_returntype()->is_void())) { - f_service_ << "result.success = "; + f_service_ << ", "; } - f_service_ << get_cap_name(service_name_) << "_iface_." << tfunction->get_name() << "("; - bool first = true; - for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) { - if (first) { - first = false; - } else { - f_service_ << ", "; - } - f_service_ << "args." << (*f_iter)->get_name(); - } - f_service_ << ");" << endl; + f_service_ << "args." << (*f_iter)->get_name(); } + f_service_ << ");" << endl; indent_down(); f_service_ << indent() << "}"; @@ -2128,16 +2113,16 @@ void t_haxe_generator::generate_process_function(t_service* tservice, t_function } // always catch all exceptions to prevent from service denial + string appex = tmp("appex"); f_service_ << " catch (th : Dynamic) {" << endl; indent_up(); - indent(f_service_) << "trace(\"Internal error processing " << tfunction->get_name() << "\", th);" - << endl; + indent(f_service_) << "trace(\"Internal error processing " << tfunction->get_name() << "\", th);" << endl; if (!tfunction->is_oneway()) { - indent(f_service_) << "var x = new TApplicationException(TApplicationException.INTERNAL_ERROR, " + indent(f_service_) << "var appex = new TApplicationException(TApplicationException.INTERNAL_ERROR, " "\"Internal error processing " << tfunction->get_name() << "\");" << endl; indent(f_service_) << "oprot.writeMessageBegin(new TMessage(\"" << tfunction->get_name() << "\", TMessageType.EXCEPTION, seqid));" << endl; - indent(f_service_) << "x.write(oprot);" << endl; + indent(f_service_) << "appex.write(oprot);" << endl; indent(f_service_) << "oprot.writeMessageEnd();" << endl; indent(f_service_) << "oprot.getTransport().flush();" << endl; } @@ -2702,7 +2687,7 @@ string t_haxe_generator::declare_field(t_field* tfield, bool init) { * @param tfunction Function definition * @return String of rendered function definition */ -string t_haxe_generator::function_signature_callback(t_function* tfunction) { +string t_haxe_generator::function_signature_combined(t_function* tfunction) { std::string on_error_success = "onError : Dynamic->Void = null, " + generate_service_method_onsuccess(tfunction, true, false); @@ -2714,7 +2699,14 @@ string t_haxe_generator::function_signature_callback(t_function* tfunction) { arguments += on_error_success; //"onError : Function, onSuccess : Function"; } - std::string result = "function " + tfunction->get_name() + "(" + arguments + ") : Void"; + std::string resulttype; + if (tfunction->is_oneway() || tfunction->get_returntype()->is_void()) { + resulttype = "Void"; + } else { + resulttype = type_name(tfunction->get_returntype()); + } + + std::string result = "function " + tfunction->get_name() + "(" + arguments + ") : "+resulttype; return result; } @@ -2975,7 +2967,6 @@ std::string t_haxe_generator::get_enum_class_name(t_type* type) { THRIFT_REGISTER_GENERATOR( haxe, "Haxe", - " callbacks Use onError()/onSuccess() callbacks for service methods\n" " rtti Enable @:rtti for generated classes and interfaces\n" " buildmacro=my.macros.Class.method(args)\n" " Add @:build macro calls to generated classes and interfaces\n") diff --git a/configure.ac b/configure.ac index 98327f43b..2d6d62ba2 100755 --- a/configure.ac +++ b/configure.ac @@ -467,7 +467,7 @@ AX_THRIFT_LIB(haxe, [Haxe], yes) if test "$with_haxe" = "yes"; then AC_PATH_PROG([HAXE], [haxe]) if [[ -x "$HAXE" ]] ; then - AX_PROG_HAXE_VERSION( [3.1.3], have_haxe="yes", have_haxe="no") + AX_PROG_HAXE_VERSION( [4.2.1], have_haxe="yes", have_haxe="no") fi fi AM_CONDITIONAL(WITH_HAXE, [test "$have_haxe" = "yes"]) diff --git a/lib/haxe/README.md b/lib/haxe/README.md index c9f74b578..1f09c2c79 100644 --- a/lib/haxe/README.md +++ b/lib/haxe/README.md @@ -26,16 +26,14 @@ Using Thrift with Haxe Haxe setup --------------- -Thrift requires Haxe 3.1.3. Installers for Windows and OSX +Thrift requires Haxe 4.2.1. Installers for Windows and OSX platforms are available at `http://haxe.org/download`. Depending on the desired targets, you may have to install the appropriate HaxeLibs -after installing Haxe itself. For example, if you plan to target C#, Java and C++, -enter the following commands after installing Haxe: +after installing Haxe itself. For example, if you plan to target C++, enter the +following command after installing Haxe: haxelib install hxcpp - haxelib install hxjava - haxelib install hxcs For other targets, please consult the Haxe documentation whether or not any additional target libraries need to be installed and how to achieve this. @@ -66,12 +64,12 @@ or Thrift Haxe bindings ------------------- -Thrift Haxe bindings can be set up via the `haxelib` tool -either from the official ASF repo, or via the github mirror. +Thrift Haxe bindings can be set up via the `haxelib` tool as usual. +Alternatively, the "github" method can be used. -- To set up any **stable version**, choose the appropriate branch (e.g. `0.12.0`): +- To set up any **stable version**, choose the appropriate branch (e.g. `0.14.1`): - - `haxelib git thrift https://github.com/apache/thrift.git 0.12.0 lib/haxe` + - `haxelib git thrift https://github.com/apache/thrift.git 0.14.1 lib/haxe` - To set up the current **development version**, use the `master` branch: @@ -85,35 +83,24 @@ or build from source, depending on your operating system. Appropriate downloads and more information can be found at http://thrift.apache.org To get started, visit the /tutorial/haxe and /test/haxe dirs for examples. -If you are using HIDE or the FlashDevelop IDE, you'll find appropriate -project files in these folders. +If you are using the HaxeDevelop IDE, you'll find appropriate project files +in these folders. -Current status +Breaking changes ======================== -- tested with Haxe C++ target -- tested with Haxe PHP target (console/web server, binary protocols) -- transports: Socket, HTTP (servers run inside PHP server/PHP target only), Stream -- protocols: Binary, JSON, Multiplex, Compact -- tutorial client and server available -- cross-test client and server available +This version requires Haxe 4 and cannot be used with earlier versions. +It is recommended to clear out all gen-haxe contents once before switching +to the new version. Otherwise you may run into troubles with leftovers from +previous versions. -Further developments -======================== -- improve to work with C#, Java and JavaScript Haxe/OpenFL targets -- improve to work with more (ideally all) Haxe/OpenFL targets -- add HTTP server, update tutorial and tests accordingly - - -Known restrictions -======================== - -Although designed with maximum portability in mind, for technical reasons some platforms -may only support parts of the library, or not be compatible at all. +The compiler option ```callbacks``` is now obsolete. The compiler will always +generate a dual interface (i.e. with optional callback style) for use on the +client side, plus a new ```_service``` interface to be used for server +implementations. Consequentially, your client and server implementations will +need some manual intervention. -Javascript: -- tutorial fails to build because of unsupported Sys.args PHP HTTP Server notes ======================== diff --git a/lib/haxe/haxelib.json b/lib/haxe/haxelib.json index 14d0dcb79..61448dab5 100644 --- a/lib/haxe/haxelib.json +++ b/lib/haxe/haxelib.json @@ -2,11 +2,19 @@ "name": "thrift", "url" : "http://thrift.apache.org", "license": "Apache", - "tags": ["thrift", "rpc", "serialization", "cross", "framework"], + "tags": [ + "thrift", + "rpc", + "serialization", + "cross", + "framework" + ], "description": "Haxe bindings for the Apache Thrift RPC and serialization framework", "version": "0.15.0", "releasenote": "Licensed under Apache License, Version 2.0. The Apache Thrift compiler needs to be installed separately.", "contributors": ["ApacheThrift"], - "dependencies": { }, + "dependencies": { + "crypto": "" + }, "classPath": "src" } diff --git a/lib/haxe/src/org/apache/thrift/Limits.hx b/lib/haxe/src/org/apache/thrift/Limits.hx index 44eec3a61..3a7807dbd 100644 --- a/lib/haxe/src/org/apache/thrift/Limits.hx +++ b/lib/haxe/src/org/apache/thrift/Limits.hx @@ -23,9 +23,9 @@ class Limits { // Haxe limits are not fixed values, they depend on the target platform // For example, neko limits an int to 31 bits instead of 32. So we detect - // the values once during intialisation in order to + // the values once during initialization in order to // (a) get the right values for the current platform, and - // (b) prevent us from dependecies to a bunch of defines + // (b) prevent us from dependencies to a bunch of defines public static var I32_MAX = { var last : Int = 0; diff --git a/lib/haxe/src/org/apache/thrift/TConfiguration.hx b/lib/haxe/src/org/apache/thrift/TConfiguration.hx new file mode 100644 index 000000000..c5ec4e561 --- /dev/null +++ b/lib/haxe/src/org/apache/thrift/TConfiguration.hx @@ -0,0 +1,36 @@ +// Licensed to the Apache Software Foundation(ASF) under one +// or more contributor license agreements.See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership.The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +package org.apache.thrift; + +class TConfiguration +{ + public static inline var DEFAULT_MAX_MESSAGE_SIZE = 100 * 1024 * 1024; + public static inline var DEFAULT_MAX_FRAME_SIZE = 16384000; // this value is used consistently across all Thrift libraries + public static inline var DEFAULT_RECURSION_DEPTH = 64; + + public var MaxMessageSize(default,null) : Int = DEFAULT_MAX_MESSAGE_SIZE; + public var MaxFrameSize(default,null) : Int = DEFAULT_MAX_FRAME_SIZE; + public var RecursionLimit(default,null) : Int = DEFAULT_RECURSION_DEPTH; + + // TODO(JensG): add connection and i/o timeouts + + public function new() { + // CTOR + } +} + diff --git a/lib/haxe/src/org/apache/thrift/TException.hx b/lib/haxe/src/org/apache/thrift/TException.hx index 54fa1ffef..8bd9fcc3f 100644 --- a/lib/haxe/src/org/apache/thrift/TException.hx +++ b/lib/haxe/src/org/apache/thrift/TException.hx @@ -32,5 +32,10 @@ class TException { errorMsg = msg; } + public function toString() : String { + var clsname = Type.getClassName( Type.getClass(this)); + return '${clsname}: ${errorMsg} (code ${errorID})'; + } + }
\ No newline at end of file diff --git a/lib/haxe/src/org/apache/thrift/helper/Int64Map.hx b/lib/haxe/src/org/apache/thrift/helper/Int64Map.hx index 8845fd095..a8e735f81 100644 --- a/lib/haxe/src/org/apache/thrift/helper/Int64Map.hx +++ b/lib/haxe/src/org/apache/thrift/helper/Int64Map.hx @@ -137,6 +137,17 @@ class Int64Map<T> implements IMap< Int64, T> { return lomap.exists( GetLowIndex(key)); } + public function clear() : Void { + SubMaps.clear(); + } + + public function copy() : IMap< Int64, T> { + var retval = new Int64Map<T>(); + for( key in this.keys()) + retval.set( key, this.get(key)); + return retval; + } + /** Removes the mapping of `key` and returns true if such a mapping existed, false otherwise. If `key` is null, the result is unspecified. @@ -172,6 +183,14 @@ class Int64Map<T> implements IMap< Int64, T> { } /** + Returns an Iterator over the values of `this` Map. + The order of values is undefined. + **/ + public function keyValueIterator() : KeyValueIterator<Int64, T> { + return new Int64KeyValueIterator<T>(SubMaps); + } + + /** Returns a String representation of `this` Map. The exact representation depends on the platform and key-type. **/ @@ -246,7 +265,7 @@ private class Int64MapIteratorBase<T> { // internal helper class for Int64Map<T> // all class with matching methods can be used as iterator (duck typing) -private class Int64KeyIterator<T>extends Int64MapIteratorBase<T> { +private class Int64KeyIterator<T> extends Int64MapIteratorBase<T> { public function new( data : IntMap< IntMap< T>>) : Void { super(data); @@ -270,6 +289,32 @@ private class Int64KeyIterator<T>extends Int64MapIteratorBase<T> { // internal helper class for Int64Map<T> // all class with matching methods can be used as iterator (duck typing) +private class Int64KeyValueIterator<T> extends Int64MapIteratorBase<T> { + + public function new( data : IntMap< IntMap< T>>) : Void { + super(data); + }; + + /** + Returns the current key/item pair and advances to the next one. + + This method is not required to check hasNext() first. A call to this + method while hasNext() is false yields unspecified behavior. + **/ + public function next() : {value:T,key:Int64} { + if( ! hasNext()) + throw "no more elements"; + + return { + key: Int64.make( CurrentHi, LoIterator.next()), + value: SubMaps.get(CurrentHi).get(LoIterator.next()) + }; + } +} + + +// internal helper class for Int64Map<T> +// all class with matching methods can be used as iterator (duck typing) private class Int64ValueIterator<T> extends Int64MapIteratorBase<T> { public function new( data : IntMap< IntMap< T>>) : Void { diff --git a/lib/haxe/src/org/apache/thrift/protocol/TBinaryProtocol.hx b/lib/haxe/src/org/apache/thrift/protocol/TBinaryProtocol.hx index 7ef291c0e..2cc254b5e 100644 --- a/lib/haxe/src/org/apache/thrift/protocol/TBinaryProtocol.hx +++ b/lib/haxe/src/org/apache/thrift/protocol/TBinaryProtocol.hx @@ -31,7 +31,7 @@ import org.apache.thrift.transport.TTransport; /** * Binary protocol implementation for thrift. */ -class TBinaryProtocol extends TRecursionTracker implements TProtocol { +class TBinaryProtocol extends TProtocolImplBase implements TProtocol { private static var ANONYMOUS_STRUCT:TStruct = new TStruct(); @@ -40,19 +40,14 @@ class TBinaryProtocol extends TRecursionTracker implements TProtocol { private var strictRead_ : Bool = false; private var strictWrite_ : Bool = true; - private var trans_ : TTransport; /** * Constructor */ - public function new(trans:TTransport, strictRead : Bool=false, strictWrite : Bool=true) { - trans_ = trans; - strictRead_ = strictRead; - strictWrite_ = strictWrite; - } - - public function getTransport():TTransport { - return trans_; + public function new(transport:TTransport, strictRead : Bool = false, strictWrite : Bool = true) { + super(transport); + strictRead_ = strictRead; + strictWrite_ = strictWrite; } public function writeMessageBegin(message:TMessage) : Void { @@ -116,21 +111,21 @@ class TBinaryProtocol extends TRecursionTracker implements TProtocol { var out = new BytesOutput(); out.bigEndian = true; out.writeByte(b); - trans_.write(out.getBytes(), 0, 1); + Transport.write(out.getBytes(), 0, 1); } public function writeI16(i16 : Int) : Void { var out = new BytesOutput(); out.bigEndian = true; out.writeInt16(i16); - trans_.write(out.getBytes(), 0, 2); + Transport.write(out.getBytes(), 0, 2); } public function writeI32(i32 : Int) : Void { var out = new BytesOutput(); out.bigEndian = true; out.writeInt32(i32); - trans_.write(out.getBytes(), 0, 4); + Transport.write(out.getBytes(), 0, 4); } public function writeI64(i64 : haxe.Int64) : Void { @@ -145,14 +140,14 @@ class TBinaryProtocol extends TRecursionTracker implements TProtocol { out.writeInt32(i64.high); out.writeInt32(i64.low); #end - trans_.write(out.getBytes(), 0, 8); + Transport.write(out.getBytes(), 0, 8); } public function writeDouble(dub:Float) : Void { var out = new BytesOutput(); out.bigEndian = true; out.writeDouble(dub); - trans_.write(out.getBytes(), 0, 8); + Transport.write(out.getBytes(), 0, 8); } public function writeString(str : String) : Void { @@ -161,12 +156,12 @@ class TBinaryProtocol extends TRecursionTracker implements TProtocol { out.writeString(str); var bytes = out.getBytes(); writeI32( bytes.length); - trans_.write( bytes, 0, bytes.length); + Transport.write( bytes, 0, bytes.length); } public function writeBinary(bin:Bytes) : Void { writeI32(bin.length); - trans_.write(bin, 0, bin.length); + Transport.write(bin, 0, bin.length); } /** @@ -210,19 +205,25 @@ class TBinaryProtocol extends TRecursionTracker implements TProtocol { public function readFieldEnd() : Void {} public function readMapBegin() : TMap { - return new TMap(readByte(), readByte(), readI32()); + var map = new TMap(readByte(), readByte(), readI32()); + CheckReadBytesAvailableMap(map); + return map; } public function readMapEnd() : Void {} public function readListBegin():TList { - return new TList(readByte(), readI32()); + var list = new TList(readByte(), readI32()); + CheckReadBytesAvailableList(list); + return list; } public function readListEnd() : Void {} public function readSetBegin() : TSet { - return new TSet(readByte(), readI32()); + var set = new TSet(readByte(), readI32()); + CheckReadBytesAvailableSet(set); + return set; } public function readSetEnd() : Void {} @@ -234,7 +235,7 @@ class TBinaryProtocol extends TRecursionTracker implements TProtocol { public function readByte() : Int { var buffer = new BytesBuffer(); - var len = trans_.readAll( buffer, 0, 1); + var len = Transport.readAll( buffer, 0, 1); var inp = new BytesInput( buffer.getBytes(), 0, 1); inp.bigEndian = true; return inp.readByte(); @@ -242,7 +243,7 @@ class TBinaryProtocol extends TRecursionTracker implements TProtocol { public function readI16() : Int { var buffer = new BytesBuffer(); - var len = trans_.readAll( buffer, 0, 2); + var len = Transport.readAll( buffer, 0, 2); var inp = new BytesInput( buffer.getBytes(), 0, 2); inp.bigEndian = true; return inp.readInt16(); @@ -250,7 +251,7 @@ class TBinaryProtocol extends TRecursionTracker implements TProtocol { public function readI32() : Int { var buffer = new BytesBuffer(); - var len = trans_.readAll( buffer, 0, 4); + var len = Transport.readAll( buffer, 0, 4); var inp = new BytesInput( buffer.getBytes(), 0, 4); inp.bigEndian = true; return inp.readInt32(); @@ -258,7 +259,7 @@ class TBinaryProtocol extends TRecursionTracker implements TProtocol { public function readI64() : haxe.Int64 { var buffer = new BytesBuffer(); - var len = trans_.readAll( buffer, 0, 8); + var len = Transport.readAll( buffer, 0, 8); var inp = new BytesInput( buffer.getBytes(), 0, 8); inp.bigEndian = true; var hi = inp.readInt32(); @@ -268,7 +269,7 @@ class TBinaryProtocol extends TRecursionTracker implements TProtocol { public function readDouble():Float { var buffer = new BytesBuffer(); - var len = trans_.readAll( buffer, 0, 8); + var len = Transport.readAll( buffer, 0, 8); var inp = new BytesInput( buffer.getBytes(), 0, 8); inp.bigEndian = true; return inp.readDouble(); @@ -279,9 +280,10 @@ class TBinaryProtocol extends TRecursionTracker implements TProtocol { } public function readStringBody(len : Int) : String { + Transport.CheckReadBytesAvailable(len); if( len > 0) { var buffer = new BytesBuffer(); - trans_.readAll( buffer, 0, len); + Transport.readAll( buffer, 0, len); var inp = new BytesInput( buffer.getBytes(), 0, len); inp.bigEndian = true; return inp.readString(len); @@ -292,10 +294,33 @@ class TBinaryProtocol extends TRecursionTracker implements TProtocol { public function readBinary() : Bytes { var len : Int = readI32(); - var buffer = new BytesBuffer(); - trans_.readAll( buffer, 0, len); + Transport.CheckReadBytesAvailable(len); + var buffer = new BytesBuffer(); + Transport.readAll( buffer, 0, len); return buffer.getBytes(); } + // Return the minimum number of bytes a type will consume on the wire + public override function GetMinSerializedSize(type : TType) : Int + { + switch (type) + { + case TType.STOP: return 0; + case TType.VOID: return 0; + case TType.BOOL: return 1; + case TType.BYTE: return 1; + case TType.DOUBLE: return 8; + case TType.I16: return 2; + case TType.I32: return 4; + case TType.I64: return 8; + case TType.STRING: return 4; // string length + case TType.STRUCT: return 0; // empty struct + case TType.MAP: return 4; // element count + case TType.SET: return 4; // element count + case TType.LIST: return 4; // element count + default: throw new TProtocolException(TProtocolException.NOT_IMPLEMENTED, "unrecognized type code"); + } + } + } diff --git a/lib/haxe/src/org/apache/thrift/protocol/TCompactProtocol.hx b/lib/haxe/src/org/apache/thrift/protocol/TCompactProtocol.hx index 03b13e2f6..ae626b5f0 100644 --- a/lib/haxe/src/org/apache/thrift/protocol/TCompactProtocol.hx +++ b/lib/haxe/src/org/apache/thrift/protocol/TCompactProtocol.hx @@ -23,10 +23,10 @@ import haxe.io.Bytes; import haxe.io.BytesInput; import haxe.io.BytesOutput; import haxe.io.BytesBuffer; +import haxe.io.Encoding; import haxe.ds.GenericStack; import haxe.Int32; import haxe.Int64; -import haxe.Utf8; import org.apache.thrift.TException; import org.apache.thrift.transport.TTransport; @@ -37,7 +37,7 @@ import org.apache.thrift.helper.BitConverter; /** * Compact protocol implementation for thrift. */ -class TCompactProtocol extends TRecursionTracker implements TProtocol { +class TCompactProtocol extends TProtocolImplBase implements TProtocol { private static var ANONYMOUS_STRUCT : TStruct = new TStruct(""); private static var TSTOP : TField = new TField("", TType.STOP, 0); @@ -102,24 +102,11 @@ class TCompactProtocol extends TRecursionTracker implements TProtocol { private var boolValue_ : Null<Bool>; - // whether the underlying system holds Strings as UTF-8 - // http://old.haxe.org/manual/encoding - private static var utf8Strings = haxe.Utf8.validate("Ç-ß-Æ-Ю-Ш"); - - // the transport used - public var trans(default,null) : TTransport; - - // TCompactProtocol Constructor - public function new( trans : TTransport) { - this.trans = trans; - } - - public function getTransport() : TTransport { - return trans; + public function new( transport : TTransport) { + super(transport); } - public function Reset() : Void{ while ( ! lastField_.isEmpty()) { lastField_.pop(); @@ -135,7 +122,7 @@ class TCompactProtocol extends TRecursionTracker implements TProtocol { private function WriteByteDirect( b : Int) : Void { var buf = Bytes.alloc(1); buf.set( 0, b); - trans.write( buf, 0, 1); + Transport.write( buf, 0, 1); } /** @@ -158,7 +145,7 @@ class TCompactProtocol extends TRecursionTracker implements TProtocol { } var tmp = i32buf.getBytes(); - trans.write( tmp, 0, tmp.length); + Transport.write( tmp, 0, tmp.length); } /** @@ -329,7 +316,7 @@ class TCompactProtocol extends TRecursionTracker implements TProtocol { */ public function writeDouble( dub : Float) : Void { var data = BitConverter.fixedLongToBytes( BitConverter.DoubleToInt64Bits(dub)); - trans.write( data, 0, data.length); + Transport.write( data, 0, data.length); } /** @@ -337,10 +324,7 @@ class TCompactProtocol extends TRecursionTracker implements TProtocol { */ public function writeString(str : String) : Void { var buf = new BytesBuffer(); - if( utf8Strings) - buf.addString( str); // no need to encode on UTF8 targets, the string is just fine - else - buf.addString( Utf8.encode( str)); + buf.addString( str, Encoding.UTF8); var tmp = buf.getBytes(); writeBinary( tmp); } @@ -350,7 +334,7 @@ class TCompactProtocol extends TRecursionTracker implements TProtocol { */ public function writeBinary( bin : Bytes) : Void { WriteVarint32( cast(bin.length,UInt)); - trans.write( bin, 0, bin.length); + Transport.write( bin, 0, bin.length); } @@ -408,7 +392,7 @@ class TCompactProtocol extends TRecursionTracker implements TProtocol { } } var tmp = varint64out.getBytes(); - trans.write( tmp, 0, tmp.length); + Transport.write( tmp, 0, tmp.length); } @@ -497,7 +481,9 @@ class TCompactProtocol extends TRecursionTracker implements TProtocol { var keyAndValueType : Int = ((size == 0) ? 0 : readByte()); var key : Int = cast( getTType( (keyAndValueType & 0xF0) >> 4), Int); var val : Int = cast( getTType( keyAndValueType & 0x0F), Int); - return new TMap( key, val, size); + var map = new TMap( key, val, size); + CheckReadBytesAvailableMap(map); + return map; } /** @@ -515,7 +501,9 @@ class TCompactProtocol extends TRecursionTracker implements TProtocol { } var type = getTType(size_and_type); - return new TList( type, size); + var list = new TList( type, size); + CheckReadBytesAvailableList(list); + return list; } /** @@ -533,7 +521,9 @@ class TCompactProtocol extends TRecursionTracker implements TProtocol { } var type = getTType(size_and_type); - return new TSet( type, size); + var set = new TSet( type, size); + CheckReadBytesAvailableSet(set); + return set; } /** @@ -556,7 +546,7 @@ class TCompactProtocol extends TRecursionTracker implements TProtocol { */ public function readByte() : Int { var byteRawBuf = new BytesBuffer(); - trans.readAll( byteRawBuf, 0, 1); + Transport.readAll( byteRawBuf, 0, 1); return byteRawBuf.getBytes().get(0); } @@ -586,7 +576,7 @@ class TCompactProtocol extends TRecursionTracker implements TProtocol { */ public function readDouble():Float { var longBits = new BytesBuffer(); - trans.readAll( longBits, 0, 8); + Transport.readAll( longBits, 0, 8); return BitConverter.Int64BitsToDouble( BitConverter.bytesToLong( longBits.getBytes())); } @@ -595,21 +585,19 @@ class TCompactProtocol extends TRecursionTracker implements TProtocol { */ public function readString() : String { var length : Int = cast( ReadVarint32(), Int); + Transport.CheckReadBytesAvailable(length); if (length == 0) { return ""; } var buf = new BytesBuffer(); - trans.readAll( buf, 0, length); + Transport.readAll( buf, 0, length); length = buf.length; var inp = new BytesInput( buf.getBytes()); - var str = inp.readString( length); - if( utf8Strings) - return str; // no need to decode on UTF8 targets, the string is just fine - else - return Utf8.decode( str); + var str = inp.readString( length, Encoding.UTF8); + return str; } /** @@ -617,12 +605,13 @@ class TCompactProtocol extends TRecursionTracker implements TProtocol { */ public function readBinary() : Bytes { var length : Int = cast( ReadVarint32(), Int); + Transport.CheckReadBytesAvailable(length); if (length == 0) { return Bytes.alloc(0); } var buf = new BytesBuffer(); - trans.readAll( buf, 0, length); + Transport.readAll( buf, 0, length); return buf.getBytes(); } @@ -715,4 +704,27 @@ class TCompactProtocol extends TRecursionTracker implements TProtocol { { return cast( ttypeToCompactType[ttype], Int); } + + // Return the minimum number of bytes a type will consume on the wire + public override function GetMinSerializedSize(type : TType) : Int + { + switch (type) + { + case TType.STOP: return 0; + case TType.VOID: return 0; + case TType.BOOL: return 1; + case TType.DOUBLE: return 8; // uses fixedLongToBytes() which always writes 8 bytes + case TType.BYTE: return 1; + case TType.I16: return 1; // zigzag + case TType.I32: return 1; // zigzag + case TType.I64: return 1; // zigzag + case TType.STRING: return 1; // string length + case TType.STRUCT: return 0; // empty struct + case TType.MAP: return 1; // element count + case TType.SET: return 1; // element count + case TType.LIST: return 1; // element count + default: throw new TProtocolException(TProtocolException.NOT_IMPLEMENTED, "unrecognized type code"); + } + } + } diff --git a/lib/haxe/src/org/apache/thrift/protocol/TJSONProtocol.hx b/lib/haxe/src/org/apache/thrift/protocol/TJSONProtocol.hx index e20ff33c5..145eab911 100644 --- a/lib/haxe/src/org/apache/thrift/protocol/TJSONProtocol.hx +++ b/lib/haxe/src/org/apache/thrift/protocol/TJSONProtocol.hx @@ -23,8 +23,8 @@ import haxe.io.Bytes; import haxe.io.BytesInput; import haxe.io.BytesOutput; import haxe.io.BytesBuffer; +import haxe.io.Encoding; import haxe.ds.GenericStack; -import haxe.Utf8; import haxe.crypto.Base64; import haxe.Int64; @@ -45,9 +45,7 @@ import org.apache.thrift.transport.TTransport; * * Adapted from the Java version. */ -class TJSONProtocol extends TRecursionTracker implements TProtocol { - - public var trans(default,null) : TTransport; +class TJSONProtocol extends TProtocolImplBase implements TProtocol { // Stack of nested contexts that we may be in private var contextStack : GenericStack<JSONBaseContext> = new GenericStack<JSONBaseContext>(); @@ -58,22 +56,14 @@ class TJSONProtocol extends TRecursionTracker implements TProtocol { // Reader that manages a 1-byte buffer private var reader : LookaheadReader; - // whether the underlying system holds Strings as UTF-8 - // http://old.haxe.org/manual/encoding - private static var utf8Strings = haxe.Utf8.validate("Ç-ß-Æ-Ю-Ш"); - // TJSONProtocol Constructor - public function new( trans : TTransport) + public function new( transport : TTransport) { - this.trans = trans; + super(transport); this.context = new JSONBaseContext(this); this.reader = new LookaheadReader(this); } - public function getTransport() : TTransport { - return trans; - } - public function writeMessageBegin(message:TMessage) : Void { WriteJSONArrayStart(); WriteJSONInteger( JSONConstants.VERSION); @@ -230,7 +220,8 @@ class TJSONProtocol extends TRecursionTracker implements TProtocol { ReadJSONObjectStart(); var map = new TMap( KeyType, ValueType, Count); - return map; + CheckReadBytesAvailableMap(map); + return map; } public function readMapEnd() : Void { @@ -244,6 +235,7 @@ class TJSONProtocol extends TRecursionTracker implements TProtocol { var Count : Int = ReadJSONInteger(); var list = new TList( ElementType, Count); + CheckReadBytesAvailableList(list); return list; } @@ -257,6 +249,7 @@ class TJSONProtocol extends TRecursionTracker implements TProtocol { var Count : Int = ReadJSONInteger(); var set = new TSet( ElementType, Count); + CheckReadBytesAvailableSet(set); return set; } @@ -313,7 +306,7 @@ class TJSONProtocol extends TRecursionTracker implements TProtocol { context.Write(); var tmp = BytesFromString( JSONConstants.QUOTE); - trans.write( tmp, 0, tmp.length); + Transport.write( tmp, 0, tmp.length); for (i in 0 ... b.length) { var value = b.get(i); @@ -323,11 +316,11 @@ class TJSONProtocol extends TRecursionTracker implements TProtocol { if (String.fromCharCode(value) == JSONConstants.BACKSLASH.charAt(0)) { tmp = BytesFromString( JSONConstants.BACKSLASH + JSONConstants.BACKSLASH); - trans.write( tmp, 0, tmp.length); + Transport.write( tmp, 0, tmp.length); } else { - trans.write( b, i, 1); + Transport.write( b, i, 1); } } else @@ -335,7 +328,7 @@ class TJSONProtocol extends TRecursionTracker implements TProtocol { var num = JSONConstants.JSON_CHAR_TABLE[value]; if (num == 1) { - trans.write( b, i, 1); + Transport.write( b, i, 1); } else if (num > 1) { @@ -343,7 +336,7 @@ class TJSONProtocol extends TRecursionTracker implements TProtocol { buf.addString( JSONConstants.BACKSLASH); buf.addByte( num); tmp = buf.getBytes(); - trans.write( tmp, 0, tmp.length); + Transport.write( tmp, 0, tmp.length); } else { @@ -354,13 +347,13 @@ class TJSONProtocol extends TRecursionTracker implements TProtocol { buf.addString( HexChar( (value & 0x0000FF00) >> 4)); buf.addString( HexChar( value & 0x000000FF)); tmp = buf.getBytes(); - trans.write( tmp, 0, tmp.length); + Transport.write( tmp, 0, tmp.length); } } } tmp = BytesFromString( JSONConstants.QUOTE); - trans.write( tmp, 0, tmp.length); + Transport.write( tmp, 0, tmp.length); } // Write out number as a JSON value. If the context dictates so, @@ -382,7 +375,7 @@ class TJSONProtocol extends TRecursionTracker implements TProtocol { } var tmp = BytesFromString( str); - trans.write( tmp, 0, tmp.length); + Transport.write( tmp, 0, tmp.length); } // Write out number as a JSON value. If the context dictates so, @@ -404,7 +397,7 @@ class TJSONProtocol extends TRecursionTracker implements TProtocol { } var tmp = BytesFromString( str); - trans.write( tmp, 0, tmp.length); + Transport.write( tmp, 0, tmp.length); } // Write out a double as a JSON value. If it is NaN or infinity or if the @@ -441,7 +434,7 @@ class TJSONProtocol extends TRecursionTracker implements TProtocol { } var tmp = BytesFromString( str); - trans.write( tmp, 0, tmp.length); + Transport.write( tmp, 0, tmp.length); } // Write out contents of byte array b as a JSON string with base-64 encoded data @@ -454,33 +447,33 @@ class TJSONProtocol extends TRecursionTracker implements TProtocol { buf.addString( JSONConstants.QUOTE); var tmp = buf.getBytes(); - trans.write( tmp, 0, tmp.length); + Transport.write( tmp, 0, tmp.length); } private function WriteJSONObjectStart() : Void { context.Write(); var tmp = BytesFromString( JSONConstants.LBRACE); - trans.write( tmp, 0, tmp.length); + Transport.write( tmp, 0, tmp.length); PushContext( new JSONPairContext(this)); } private function WriteJSONObjectEnd() : Void { PopContext(); var tmp = BytesFromString( JSONConstants.RBRACE); - trans.write( tmp, 0, tmp.length); + Transport.write( tmp, 0, tmp.length); } private function WriteJSONArrayStart() : Void { context.Write(); var tmp = BytesFromString( JSONConstants.LBRACKET); - trans.write( tmp, 0, tmp.length); + Transport.write( tmp, 0, tmp.length); PushContext( new JSONListContext(this)); } private function WriteJSONArrayEnd() : Void { PopContext(); var tmp = BytesFromString( JSONConstants.RBRACKET); - trans.write( tmp, 0, tmp.length); + Transport.write( tmp, 0, tmp.length); } @@ -545,7 +538,7 @@ class TJSONProtocol extends TRecursionTracker implements TProtocol { // it's \uXXXX var hexbuf = new BytesBuffer(); - var hexlen = trans.readAll( hexbuf, 0, 4); + var hexlen = Transport.readAll( hexbuf, 0, 4); if( hexlen != 4) { throw new TProtocolException( TProtocolException.INVALID_DATA, "Not enough data for \\uNNNN sequence"); @@ -756,10 +749,7 @@ class TJSONProtocol extends TRecursionTracker implements TProtocol { public static function BytesFromString( str : String) : Bytes { var buf = new BytesBuffer(); - if( utf8Strings) - buf.addString( str); // no need to encode on UTF8 targets, the string is just fine - else - buf.addString( Utf8.encode( str)); + buf.addString( str, Encoding.UTF8); return buf.getBytes(); } @@ -767,11 +757,7 @@ class TJSONProtocol extends TRecursionTracker implements TProtocol { var inp = new BytesInput( buf); if( buf.length == 0) return ""; // readString() would return null in that case, which is wrong - var str = inp.readString( buf.length); - if( utf8Strings) - return str; // no need to decode on UTF8 targets, the string is just fine - else - return Utf8.decode( str); + return inp.readString( buf.length, Encoding.UTF8); } // Convert a byte containing a hex char ('0'-'9' or 'a'-'f') into its corresponding hex value @@ -790,6 +776,28 @@ class TJSONProtocol extends TRecursionTracker implements TProtocol { } + // Return the minimum number of bytes a type will consume on the wire + public override function GetMinSerializedSize(type : TType) : Int + { + switch (type) + { + case TType.STOP: return 0; + case TType.VOID: return 0; + case TType.BOOL: return 1; // written as int + case TType.BYTE: return 1; + case TType.DOUBLE: return 1; + case TType.I16: return 1; + case TType.I32: return 1; + case TType.I64: return 1; + case TType.STRING: return 2; // empty string + case TType.STRUCT: return 2; // empty struct + case TType.MAP: return 2; // empty map + case TType.SET: return 2; // empty set + case TType.LIST: return 2; // empty list + default: throw new TProtocolException(TProtocolException.NOT_IMPLEMENTED, "unrecognized type code"); + } + } + } @@ -971,7 +979,7 @@ class JSONListContext extends JSONBaseContext var buf = new BytesBuffer(); buf.addString( JSONConstants.COMMA); var tmp = buf.getBytes(); - proto.trans.write( tmp, 0, tmp.length); + proto.Transport.write( tmp, 0, tmp.length); } } @@ -1014,7 +1022,7 @@ class JSONPairContext extends JSONBaseContext var buf = new BytesBuffer(); buf.addString( colon ? JSONConstants.COLON : JSONConstants.COMMA); var tmp = buf.getBytes(); - proto.trans.write( tmp, 0, tmp.length); + proto.Transport.write( tmp, 0, tmp.length); colon = !colon; } } @@ -1064,7 +1072,7 @@ class LookaheadReader { public function Peek() : Bytes { if (data == null) { var buf = new BytesBuffer(); - proto.trans.readAll(buf, 0, 1); + proto.Transport.readAll(buf, 0, 1); data = buf.getBytes(); } return data; diff --git a/lib/haxe/src/org/apache/thrift/protocol/TProtocol.hx b/lib/haxe/src/org/apache/thrift/protocol/TProtocol.hx index b7f3842d0..316067a38 100644 --- a/lib/haxe/src/org/apache/thrift/protocol/TProtocol.hx +++ b/lib/haxe/src/org/apache/thrift/protocol/TProtocol.hx @@ -82,4 +82,7 @@ interface TProtocol { // recursion tracking function IncrementRecursionDepth() : Void; function DecrementRecursionDepth() : Void; + + // message size + function GetMinSerializedSize(type : TType) : Int; } diff --git a/lib/haxe/src/org/apache/thrift/protocol/TProtocolDecorator.hx b/lib/haxe/src/org/apache/thrift/protocol/TProtocolDecorator.hx index 769e93cc5..011f42b80 100644 --- a/lib/haxe/src/org/apache/thrift/protocol/TProtocolDecorator.hx +++ b/lib/haxe/src/org/apache/thrift/protocol/TProtocolDecorator.hx @@ -223,4 +223,10 @@ class TProtocolDecorator implements TProtocol public function DecrementRecursionDepth() : Void { return wrapped.DecrementRecursionDepth(); } + + // Returns the minimum amount of bytes needed to store the smallest possible instance of TType. + public function GetMinSerializedSize(type : TType) : Int + { + return wrapped.GetMinSerializedSize(type); + } } diff --git a/lib/haxe/src/org/apache/thrift/protocol/TProtocolImplBase.hx b/lib/haxe/src/org/apache/thrift/protocol/TProtocolImplBase.hx new file mode 100644 index 000000000..60e4a1f70 --- /dev/null +++ b/lib/haxe/src/org/apache/thrift/protocol/TProtocolImplBase.hx @@ -0,0 +1,86 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.apache.thrift.protocol; + +import org.apache.thrift.*; +import org.apache.thrift.transport.TTransport; + + +class TProtocolImplBase { + + private var Configuration : TConfiguration; + public var Transport(default,null) : TTransport; + + public function new( transport : TTransport) + { + Transport = transport; + Configuration = (transport.Configuration != null) ? transport.Configuration : new TConfiguration(); + } + + + public function getTransport() : TTransport { + return Transport; + } + + + // limit and actual value + public var recursionLimit(get,never) : Int; + private var recursionDepth : Int = 0; + + public function get_recursionLimit() : Int + { + return Configuration.RecursionLimit; + } + + + public function IncrementRecursionDepth() : Void + { + if (recursionDepth < recursionLimit) + ++recursionDepth; + else + throw new TProtocolException(TProtocolException.DEPTH_LIMIT, "Depth limit exceeded"); + } + + public function DecrementRecursionDepth() : Void + { + --recursionDepth; + } + + + private function CheckReadBytesAvailableSet(set : TSet) : Void + { + Transport.CheckReadBytesAvailable(set.size * GetMinSerializedSize(set.elemType)); + } + + private function CheckReadBytesAvailableList(list : TList) : Void + { + Transport.CheckReadBytesAvailable(list.size * GetMinSerializedSize(list.elemType)); + } + + private function CheckReadBytesAvailableMap (map : TMap) : Void + { + var elmSize = GetMinSerializedSize(map.keyType) + GetMinSerializedSize(map.valueType); + Transport.CheckReadBytesAvailable(map.size * elmSize); + } + + // Returns the minimum amount of bytes needed to store the smallest possible instance of TType. + public function GetMinSerializedSize(type : TType) : Int throw "abstract method called"; + +} diff --git a/lib/haxe/src/org/apache/thrift/protocol/TRecursionTracker.hx b/lib/haxe/src/org/apache/thrift/protocol/TRecursionTracker.hx deleted file mode 100644 index cf0211b39..000000000 --- a/lib/haxe/src/org/apache/thrift/protocol/TRecursionTracker.hx +++ /dev/null @@ -1,48 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -package org.apache.thrift.protocol; - -import org.apache.thrift.*; - - -class TRecursionTracker { - - // default - private static inline var DEFAULT_RECURSION_DEPTH : Int = 64; - - // limit and actual value - public var recursionLimit : Int = DEFAULT_RECURSION_DEPTH; - private var recursionDepth : Int = 0; - - public function IncrementRecursionDepth() : Void - { - if (recursionDepth < recursionLimit) - ++recursionDepth; - else - throw new TProtocolException(TProtocolException.DEPTH_LIMIT, "Depth limit exceeded"); - } - - public function DecrementRecursionDepth() : Void - { - --recursionDepth; - } - - -} diff --git a/lib/haxe/src/org/apache/thrift/transport/TBufferedTransport.hx b/lib/haxe/src/org/apache/thrift/transport/TBufferedTransport.hx index 4b33fcf86..72ce9218c 100644 --- a/lib/haxe/src/org/apache/thrift/transport/TBufferedTransport.hx +++ b/lib/haxe/src/org/apache/thrift/transport/TBufferedTransport.hx @@ -21,6 +21,7 @@ package org.apache.thrift.transport; import org.apache.thrift.transport.*; +import haxe.Int64; import haxe.io.Eof; import haxe.io.Bytes; import haxe.io.BytesBuffer; @@ -28,16 +29,13 @@ import haxe.io.BytesOutput; import haxe.io.BytesInput; -class TBufferedTransport extends TTransport +class TBufferedTransport extends TLayeredTransport { // constants public static inline var DEFAULT_BUFSIZE : Int = 0x1000; // 4096 Bytes public static inline var MIN_BUFSIZE : Int = 0x100; // 256 Bytes public static inline var MAX_BUFSIZE : Int = 0x100000; // 1 MB - // Underlying transport - public var transport(default,null) : TTransport = null; - // Buffer for input/output private var readBuffer_ : BytesInput = null; private var writeBuffer_ : BytesOutput = null; @@ -45,6 +43,7 @@ class TBufferedTransport extends TTransport // Constructor wraps around another transport public function new( transport : TTransport, bufSize : Int = DEFAULT_BUFSIZE) { + super(transport); // ensure buffer size is in the range if ( bufSize < MIN_BUFSIZE) @@ -52,22 +51,21 @@ class TBufferedTransport extends TTransport else if( bufSize > MAX_BUFSIZE) bufSize = MAX_BUFSIZE; - this.transport = transport; this.bufSize = bufSize; this.writeBuffer_ = new BytesOutput(); this.writeBuffer_.bigEndian = true; } public override function open() : Void { - transport.open(); + InnerTransport.open(); } public override function isOpen() : Bool { - return transport.isOpen(); + return InnerTransport.isOpen(); } public override function close() : Void { - transport.close(); + InnerTransport.close(); } public override function read(buf : BytesBuffer, off : Int, len : Int) : Int { @@ -86,7 +84,7 @@ class TBufferedTransport extends TTransport // there is no point in buffering whenever the // remaining length exceeds the buffer size if ( len >= bufSize) { - var got = transport.read( buf, off, len); + var got = InnerTransport.read( buf, off, len); if (got > 0) { buf.addBytes(data, 0, got); return got; @@ -109,7 +107,7 @@ class TBufferedTransport extends TTransport var size = bufSize; try { var buffer = new BytesBuffer(); - size = transport.read( buffer, 0, size); + size = InnerTransport.read( buffer, 0, size); readBuffer_ = new BytesInput( buffer.getBytes(), 0, size); readBuffer_.bigEndian = true; return size; @@ -125,7 +123,7 @@ class TBufferedTransport extends TTransport var buf = writeBuffer_.getBytes(); writeBuffer_ = new BytesOutput(); writeBuffer_.bigEndian = true; - transport.write(buf, 0, buf.length); + InnerTransport.write(buf, 0, buf.length); } } } @@ -141,7 +139,7 @@ class TBufferedTransport extends TTransport var write_thru : Bool = exceeds_buf && (writeBuffer_.length >= halfSize); if ( write_thru) { writeChunk(true); // force send whatever we have in there - transport.write(buf, off, len); // write thru + InnerTransport.write(buf, off, len); // write thru } else { writeBuffer_.writeBytes(buf, off, len); writeChunk(false); @@ -150,6 +148,18 @@ class TBufferedTransport extends TTransport public override function flush( callback : Dynamic->Void =null) : Void { writeChunk(true); - transport.flush(callback); + InnerTransport.flush(callback); } + + public override function CheckReadBytesAvailable(numBytes : Int64) : Void + { + var buffered = readBuffer_.length - readBuffer_.position; + if (buffered < numBytes) + { + numBytes -= buffered; + InnerTransport.CheckReadBytesAvailable(numBytes); + } + } + + } diff --git a/lib/haxe/src/org/apache/thrift/transport/TBufferedTransportFactory.hx b/lib/haxe/src/org/apache/thrift/transport/TBufferedTransportFactory.hx index 539e72033..11d1a72a9 100644 --- a/lib/haxe/src/org/apache/thrift/transport/TBufferedTransportFactory.hx +++ b/lib/haxe/src/org/apache/thrift/transport/TBufferedTransportFactory.hx @@ -27,7 +27,7 @@ class TBufferedTransportFactory extends TTransportFactory { private var bufSize : Int; public function new(bufSize : Int = TBufferedTransport.DEFAULT_BUFSIZE) { - super(); + super(); this.bufSize = bufSize; } diff --git a/lib/haxe/src/org/apache/thrift/transport/TEndpointTransport.hx b/lib/haxe/src/org/apache/thrift/transport/TEndpointTransport.hx new file mode 100644 index 000000000..8c0d3effa --- /dev/null +++ b/lib/haxe/src/org/apache/thrift/transport/TEndpointTransport.hx @@ -0,0 +1,95 @@ +// Licensed to the Apache Software Foundation(ASF) under one +// or more contributor license agreements.See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership.The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. +package org.apache.thrift.transport; + +import haxe.Int64; +import org.apache.thrift.TConfiguration; + +class TEndpointTransport extends TTransport +{ + private var MaxMessageSize(get, never) : Int64; + private var KnownMessageSize(default, null) : Int64 ; + private var RemainingMessageSize(default, null) : Int64 ; + + private var _configuration(default,null) : TConfiguration; + + public override function get_Configuration() : TConfiguration { + return _configuration; + } + + private function get_MaxMessageSize() : Int64 { + return Configuration.MaxMessageSize; + } + + + // private CTOR to prevent direct instantiation + // in other words, this class MUST be extended + private function new( config : TConfiguration) + { + _configuration = (config != null) ? config : new TConfiguration(); + ResetConsumedMessageSize(); + } + + // Resets RemainingMessageSize to the configured maximum + private function ResetConsumedMessageSize(?newSize : Int64) : Void + { + // full reset + if (newSize == null) + { + KnownMessageSize = MaxMessageSize; + RemainingMessageSize = MaxMessageSize; + return; + } + + // update only: message size can shrink, but not grow + if (newSize > KnownMessageSize) + throw new TTransportException(TTransportException.END_OF_FILE, "ResetConsumedMessageSize: MaxMessageSize reached"); + + KnownMessageSize = newSize; + RemainingMessageSize = newSize; + } + + // Updates RemainingMessageSize to reflect then known real message size (e.g. framed transport). + // Will throw if we already consumed too many bytes or if the new size is larger than allowed. + public override function UpdateKnownMessageSize(size : Int64) : Void + { + var consumed = KnownMessageSize - RemainingMessageSize; + ResetConsumedMessageSize(size); + CountConsumedMessageBytes(consumed); + } + + // Throws if there are not enough bytes in the input stream to satisfy a read of numBytes bytes of data + public override function CheckReadBytesAvailable(numBytes : Int64) : Void + { + if (RemainingMessageSize < numBytes) + throw new TTransportException(TTransportException.END_OF_FILE, 'CheckReadBytesAvailable(${numBytes}): MaxMessageSize reached, only ${RemainingMessageSize} bytes available'); + } + + // Consumes numBytes from the RemainingMessageSize. + private function CountConsumedMessageBytes(numBytes : Int64) : Void + { + if (RemainingMessageSize >= numBytes) + { + RemainingMessageSize -= numBytes; + } + else + { + RemainingMessageSize = 0; + throw new TTransportException(TTransportException.END_OF_FILE, 'CountConsumedMessageBytes(${numBytes}): MaxMessageSize reached'); + } + } +} diff --git a/lib/haxe/src/org/apache/thrift/transport/TFramedTransport.hx b/lib/haxe/src/org/apache/thrift/transport/TFramedTransport.hx index cef82ef61..37e495946 100644 --- a/lib/haxe/src/org/apache/thrift/transport/TFramedTransport.hx +++ b/lib/haxe/src/org/apache/thrift/transport/TFramedTransport.hx @@ -21,6 +21,7 @@ package org.apache.thrift.transport; import org.apache.thrift.transport.*; +import haxe.Int64; import haxe.io.Eof; import haxe.io.Bytes; import haxe.io.BytesBuffer; @@ -32,16 +33,9 @@ import haxe.io.BytesInput; * TFramedTransport is a buffered TTransport that ensures a fully read message * every time by preceding messages with a 4-byte frame size. */ -class TFramedTransport extends TTransport +class TFramedTransport extends TLayeredTransport { - public static inline var DEFAULT_MAX_LENGTH = 16384000; - - var maxLength_ : Int; - - /** - * Underlying transport - */ - var transport_ : TTransport = null; + private static inline var HEADER_SIZE = 4; /** * Buffer for output @@ -56,21 +50,20 @@ class TFramedTransport extends TTransport /** * Constructor wraps around another transport */ - public function new( transport : TTransport, maxLength : Int = DEFAULT_MAX_LENGTH) { - transport_ = transport; - maxLength_ = maxLength; + public function new( transport : TTransport) { + super(transport); } public override function open() : Void { - transport_.open(); + InnerTransport.open(); } public override function isOpen() : Bool { - return transport_.isOpen(); + return InnerTransport.isOpen(); } public override function close() : Void { - transport_.close(); + InnerTransport.close(); } public override function read(buf : BytesBuffer, off : Int, len : Int) : Int { @@ -101,13 +94,13 @@ class TFramedTransport extends TTransport function readFrameSize() : Int { try { var buffer = new BytesBuffer(); - var len = transport_.readAll( buffer, 0, 4); - var inp = new BytesInput( buffer.getBytes(), 0, 4); + var len = InnerTransport.readAll( buffer, 0, HEADER_SIZE); + var inp = new BytesInput( buffer.getBytes(), 0, HEADER_SIZE); inp.bigEndian = true; return inp.readInt32(); } catch(eof : Eof) { - throw new TTransportException(TTransportException.END_OF_FILE, 'Can\'t read 4 bytes!'); + throw new TTransportException(TTransportException.END_OF_FILE, 'Can\'t read ${HEADER_SIZE} bytes!'); } } @@ -118,13 +111,14 @@ class TFramedTransport extends TTransport if (size < 0) { throw new TTransportException(TTransportException.UNKNOWN, 'Read a negative frame size ($size)!'); }; - if (size > maxLength_) { - throw new TTransportException(TTransportException.UNKNOWN, 'Frame size ($size) larger than max length ($maxLength_)!'); + if (size > Configuration.MaxFrameSize) { + throw new TTransportException(TTransportException.UNKNOWN, 'Frame size ($size) larger than max length ($Configuration.MaxFrameSize)!'); }; + UpdateKnownMessageSize(size + HEADER_SIZE); try { var buffer = new BytesBuffer(); - size = transport_.readAll( buffer, 0, size); + size = InnerTransport.readAll( buffer, 0, size); readBuffer_ = new BytesInput( buffer.getBytes(), 0, size); readBuffer_.bigEndian = true; } @@ -141,18 +135,31 @@ class TFramedTransport extends TTransport var out = new BytesOutput(); out.bigEndian = true; out.writeInt32(len); - transport_.write(out.getBytes(), 0, 4); + InnerTransport.write(out.getBytes(), 0, HEADER_SIZE); } public override function flush( callback : Dynamic->Void =null) : Void { var buf : Bytes = writeBuffer_.getBytes(); var len : Int = buf.length; writeBuffer_ = new BytesOutput(); + readBuffer_ = null; writeFrameSize(len); - transport_.write(buf, 0, len); - transport_.flush(callback); + InnerTransport.write(buf, 0, len); + InnerTransport.flush(callback); } + + + public override function CheckReadBytesAvailable(numBytes : Int64) : Void + { + var buffered = readBuffer_.length - readBuffer_.position; + if (buffered < numBytes) + { + numBytes -= buffered; + InnerTransport.CheckReadBytesAvailable(numBytes); + } + } + } diff --git a/lib/haxe/src/org/apache/thrift/transport/TFramedTransportFactory.hx b/lib/haxe/src/org/apache/thrift/transport/TFramedTransportFactory.hx index 8d45a641a..ca04e7fe4 100644 --- a/lib/haxe/src/org/apache/thrift/transport/TFramedTransportFactory.hx +++ b/lib/haxe/src/org/apache/thrift/transport/TFramedTransportFactory.hx @@ -19,19 +19,17 @@ package org.apache.thrift.transport; +import org.apache.thrift.TConfiguration; import org.apache.thrift.transport.*; class TFramedTransportFactory extends TTransportFactory { - var maxLength_ : Int; - - public function new(maxLength : Int = TFramedTransport.DEFAULT_MAX_LENGTH) { - super(); - maxLength_ = maxLength; + public function new() { + super(); } public override function getTransport(base : TTransport) : TTransport { - return new TFramedTransport(base, maxLength_); + return new TFramedTransport(base); } } diff --git a/lib/haxe/src/org/apache/thrift/transport/TFullDuplexHttpClient.hx b/lib/haxe/src/org/apache/thrift/transport/TFullDuplexHttpClient.hx index 1972853ef..cc34ec4fa 100644 --- a/lib/haxe/src/org/apache/thrift/transport/TFullDuplexHttpClient.hx +++ b/lib/haxe/src/org/apache/thrift/transport/TFullDuplexHttpClient.hx @@ -41,213 +41,217 @@ import flash.events.EventDispatcher; * Unlike Http Client, it uses a single POST, and chunk-encoding to transfer all messages. */ - public class TFullDuplexHttpClient extends TTransport - { - private var socket : Socket = null; - private var host : String; - private var port : Int; - private var resource : String; - private var stripped : Bool = false; - private var obuffer : Bytes = new Bytes(); - private var input : IDataInput; - private var output : IDataOutput; - private var bytesInChunk : Int = 0; - private var CRLF : Bytes = new Bytes(); - private var ioCallback : TException->Void = null; - private var eventDispatcher : EventDispatcher = new EventDispatcher(); - - public function new(host : String, port : Int, resource : String) : Void - { - CRLF.writeByte(13); - CRLF.writeByte(10); - this.host = host; - this.port = port; - this.resource = resource; - } - - public override function close() : Void - { - this.input = null; - this.output = null; - this.stripped = false; - socket.close() - } - - public override function peek() : Bool - { - if(socket.connected) - { - trace("Bytes remained:" + socket.bytesAvailable); - return socket.bytesAvailable>0; - } - return false; - } - - public override function read(buf : Bytes, off : Int, len : Int) : Int - { - var n1 : Int = 0, n2 : Int = 0, n3 : Int = 0, n4 : Int = 0, cidx : Int = 2; - var chunkSize : Bytes = new Bytes(); - - try - { - while (!stripped) - { - n1 = n2; - n2 = n3; - n3 = n4; - n4 = input.readByte(); - if ((n1 == 13) && (n2 == 10) && (n3 == 13) && (n4 == 10)) - { - stripped = true; - } - } - - // read chunk size - if (bytesInChunk == 0) - { - n1 = input.readByte(); - n2 = input.readByte(); - - chunkSize.writeByte(n1); - chunkSize.writeByte(n2); - - while (!((n1 == 13) && (n2 == 10))) - { - n1 = n2; - n2 = input.readByte(); - chunkSize.writeByte(n2); - } - - bytesInChunk = parseInt(chunkSize.toString(), 16); - } - - input.readBytes(buf, off, len); - debugBuffer(buf); - bytesInChunk -= len; - - if (bytesInChunk == 0) - { - // advance the : "\r\n" - input.readUTFBytes(2); - } - return len; - } - catch (e : EOFError) - { - trace(e); - throw new TTransportException(TTransportException.UNKNOWN, "No more data available."); - } - catch (e : TException) - { - trace('TException $e'); - throw e; - } - catch (e : Error) - { - trace(e); - throw new TTransportException(TTransportException.UNKNOWN, 'Bad IO error: $e'); - } - catch (e : Dynamic) - { - trace(e); - throw new TTransportException(TTransportException.UNKNOWN, 'Bad IO error: $e'); - } - return 0; - } - - public function debugBuffer(buf : Bytes) : Void - { - var debug : String = "BUFFER >>"; - var i : Int; - for (i = 0; i < buf.length; i++) - { - debug += buf[i] as int; - debug += " "; - } - - trace(debug + "<<"); - } - - public override function write(buf : Bytes, off : Int, len : Int) : Void - { - obuffer.writeBytes(buf, off, len); - } - - public function addEventListener(type : String, listener : Function, useCapture : Bool = false, priority : Int = 0, useWeakReference : Bool = false) : Void - { - this.eventDispatcher.addEventListener(type, listener, useCapture, priority, useWeakReference); - } - - public override function open() : Void - { - this.socket = new Socket(); - this.socket.addEventListener(Event.CONNECT, socketConnected); - this.socket.addEventListener(IOErrorEvent.IO_ERROR, socketError); - this.socket.addEventListener(SecurityErrorEvent.SECURITY_ERROR, socketSecurityError); - this.socket.addEventListener(ProgressEvent.SOCKET_DATA, socketDataHandler); - this.socket.connect(host, port); - } - - public function socketConnected(event : Event) : Void - { - this.output = this.socket; - this.input = this.socket; - this.output.writeUTF( "CONNECT " + resource + " HTTP/1.1\n" - + "Host : " + host + ":" + port + "\r\n" - + "User-Agent : Thrift/Haxe\r\n" - + "Transfer-Encoding : chunked\r\n" - + "content-type : application/x-thrift\r\n" - + "Accept : */*\r\n" - + "\r\n"); - this.eventDispatcher.dispatchEvent(event); - } - - public function socketError(event : IOErrorEvent) : Void - { - trace("Error Connecting:" + event); - this.close(); - if (ioCallback == null) - { - return; - } - ioCallback(new TTransportException(TTransportException.UNKNOWN, "IOError : " + event.text)); - this.eventDispatcher.dispatchEvent(event); - } - - public function socketSecurityError(event : SecurityErrorEvent) : Void - { - trace("Security Error Connecting:" + event); - this.close(); - this.eventDispatcher.dispatchEvent(event); - } - - public function socketDataHandler(event : ProgressEvent) : Void - { - trace("Got Data call:" +ioCallback); - if (ioCallback != null) - { - ioCallback(null); - }; - this.eventDispatcher.dispatchEvent(event); - } - - public override function flush(callback : Error->Void = null) : Void - { - trace("set callback:" + callback); - this.ioCallback = callback; - this.output.writeUTF(this.obuffer.length.toString(16)); - this.output.writeBytes(CRLF); - this.output.writeBytes(this.obuffer); - this.output.writeBytes(CRLF); - this.socket.flush(); - // waiting for new Flex sdk 3.5 - //this.obuffer.clear(); - this.obuffer = new Bytes(); - } - - public override function isOpen() : Bool - { - return (this.socket == null ? false : this.socket.connected); - } +public class TFullDuplexHttpClient extends TEndpointTransport +{ + private var socket : Socket = null; + private var host : String; + private var port : Int; + private var resource : String; + private var stripped : Bool = false; + private var obuffer : Bytes = new Bytes(); + private var input : IDataInput; + private var output : IDataOutput; + private var bytesInChunk : Int = 0; + private var CRLF : Bytes = new Bytes(); + private var ioCallback : TException->Void = null; + private var eventDispatcher : EventDispatcher = new EventDispatcher(); + + public function new(host : String, port : Int, resource : String, config : TConfiguration = null) : Void + { + super(config); + CRLF.writeByte(13); + CRLF.writeByte(10); + this.host = host; + this.port = port; + this.resource = resource; + } + + public override function close() : Void + { + this.input = null; + this.output = null; + this.stripped = false; + socket.close(); + ResetConsumedMessageSize(); + } + + public override function peek() : Bool + { + if(socket.connected) + { + trace("Bytes remaining:" + socket.bytesAvailable); + return socket.bytesAvailable>0; + } + return false; + } + + public override function read(buf : Bytes, off : Int, len : Int) : Int + { + var n1 : Int = 0, n2 : Int = 0, n3 : Int = 0, n4 : Int = 0, cidx : Int = 2; + var chunkSize : Bytes = new Bytes(); + + try + { + while (!stripped) + { + n1 = n2; + n2 = n3; + n3 = n4; + n4 = input.readByte(); + if ((n1 == 13) && (n2 == 10) && (n3 == 13) && (n4 == 10)) + { + stripped = true; + } + } + + // read chunk size + if (bytesInChunk == 0) + { + n1 = input.readByte(); + n2 = input.readByte(); + + chunkSize.writeByte(n1); + chunkSize.writeByte(n2); + + while (!((n1 == 13) && (n2 == 10))) + { + n1 = n2; + n2 = input.readByte(); + chunkSize.writeByte(n2); + } + + bytesInChunk = parseInt(chunkSize.toString(), 16); + } + + input.readBytes(buf, off, len); + debugBuffer(buf); + bytesInChunk -= len; + + if (bytesInChunk == 0) + { + // advance the : "\r\n" + input.readUTFBytes(2); + } + + CountConsumedMessageBytes(len); + return len; + } + catch (e : EOFError) + { + trace(e); + throw new TTransportException(TTransportException.UNKNOWN, "No more data available."); + } + catch (e : TException) + { + trace('TException $e'); + throw e; + } + catch (e : Error) + { + trace(e); + throw new TTransportException(TTransportException.UNKNOWN, 'Bad IO error: $e'); + } + catch (e : Dynamic) + { + trace(e); + throw new TTransportException(TTransportException.UNKNOWN, 'Bad IO error: $e'); + } + return 0; + } + + public function debugBuffer(buf : Bytes) : Void + { + var debug : String = "BUFFER >>"; + var i : Int; + for (i = 0; i < buf.length; i++) + { + debug += buf[i] as int; + debug += " "; + } + + trace(debug + "<<"); + } + + public override function write(buf : Bytes, off : Int, len : Int) : Void + { + obuffer.writeBytes(buf, off, len); + } + + public function addEventListener(type : String, listener : Function, useCapture : Bool = false, priority : Int = 0, useWeakReference : Bool = false) : Void + { + this.eventDispatcher.addEventListener(type, listener, useCapture, priority, useWeakReference); + } + + public override function open() : Void + { + this.socket = new Socket(); + this.socket.addEventListener(Event.CONNECT, socketConnected); + this.socket.addEventListener(IOErrorEvent.IO_ERROR, socketError); + this.socket.addEventListener(SecurityErrorEvent.SECURITY_ERROR, socketSecurityError); + this.socket.addEventListener(ProgressEvent.SOCKET_DATA, socketDataHandler); + this.socket.connect(host, port); + ResetConsumedMessageSize(); + } + + public function socketConnected(event : Event) : Void + { + this.output = this.socket; + this.input = this.socket; + this.output.writeUTF( "CONNECT " + resource + " HTTP/1.1\n" + + "Host : " + host + ":" + port + "\r\n" + + "User-Agent : Thrift/Haxe\r\n" + + "Transfer-Encoding : chunked\r\n" + + "Content-Type : application/x-thrift\r\n" + + "Accept : */*\r\n" + + "\r\n"); + this.eventDispatcher.dispatchEvent(event); + } + + public function socketError(event : IOErrorEvent) : Void + { + trace("Error Connecting:" + event); + this.close(); + if (ioCallback == null) + { + return; + } + ioCallback(new TTransportException(TTransportException.UNKNOWN, "IOError : " + event.text)); + this.eventDispatcher.dispatchEvent(event); + } + + public function socketSecurityError(event : SecurityErrorEvent) : Void + { + trace("Security Error Connecting:" + event); + this.close(); + this.eventDispatcher.dispatchEvent(event); + } + + public function socketDataHandler(event : ProgressEvent) : Void + { + trace("Got Data call:" +ioCallback); + if (ioCallback != null) + { + ioCallback(null); + }; + this.eventDispatcher.dispatchEvent(event); + } + + public override function flush(callback : Error->Void = null) : Void + { + trace("set callback:" + callback); + this.ioCallback = callback; + this.output.writeUTF(this.obuffer.length.toString(16)); + this.output.writeBytes(CRLF); + this.output.writeBytes(this.obuffer); + this.output.writeBytes(CRLF); + this.socket.flush(); + this.obuffer = new Bytes(); + ResetConsumedMessageSize(); + } + + public override function isOpen() : Bool + { + return (this.socket != null) && this.socket.connected; + } }
\ No newline at end of file diff --git a/lib/haxe/src/org/apache/thrift/transport/THttpClient.hx b/lib/haxe/src/org/apache/thrift/transport/THttpClient.hx index 79f86610d..703dd81f6 100644 --- a/lib/haxe/src/org/apache/thrift/transport/THttpClient.hx +++ b/lib/haxe/src/org/apache/thrift/transport/THttpClient.hx @@ -20,6 +20,7 @@ package org.apache.thrift.transport; +import haxe.Timer; import haxe.io.Bytes; import haxe.io.BytesBuffer; import haxe.io.BytesOutput; @@ -27,6 +28,9 @@ import haxe.io.BytesInput; import haxe.Http; +#if js +import js.lib.Promise; +#end /** @@ -34,7 +38,7 @@ import haxe.Http; * Thrift web services implementation. */ -class THttpClient extends TTransport { +class THttpClient extends TEndpointTransport { private var requestBuffer_ : BytesOutput = new BytesOutput(); private var responseBuffer_ : BytesInput = null; @@ -42,20 +46,23 @@ class THttpClient extends TTransport { private var request_ : Http = null; - public function new( requestUrl : String) : Void { - request_ = new Http(requestUrl); - request_.addHeader( "contentType", "application/x-thrift"); + public function new( requestUrl : String, config : TConfiguration = null) : Void { + super(config); + + request_ = new Http(requestUrl); + request_.addHeader( "Content-Type", "application/x-thrift"); } public override function open() : Void { + ResetConsumedMessageSize(); } public override function close() : Void { } public override function isOpen() : Bool { - return true; + return true; } public override function read(buf:BytesBuffer, off : Int, len : Int) : Int { @@ -66,6 +73,7 @@ class THttpClient extends TTransport { var data =Bytes.alloc(len); len = responseBuffer_.readBytes(data, off, len); buf.addBytes(data,0,len); + CountConsumedMessageBytes(len); return len; } @@ -78,24 +86,36 @@ class THttpClient extends TTransport { var buffer = requestBuffer_; requestBuffer_ = new BytesOutput(); responseBuffer_ = null; + ResetConsumedMessageSize(); + /* request_.onData = function(data : String) { - var tmp = new BytesBuffer(); - tmp.addString(data); - responseBuffer_ = new BytesInput(tmp.getBytes()); - if( callback != null) { - callback(null); - } + var tmp = new BytesBuffer(); + tmp.addString(data); + responseBuffer_ = new BytesInput(tmp.getBytes()); + if( callback != null) { + callback(null); }; - - request_.onError = function(msg : String) { - if( callback != null) { - callback(new TTransportException(TTransportException.UNKNOWN, "IOError: " + msg)); - } - }; - - request_.setPostData(buffer.getBytes().toString()); - request_.request(true/*POST*/); + */ + + request_.onBytes = function(data : Bytes) { + responseBuffer_ = new BytesInput(data); + if( callback != null) { + callback(null); + } + }; + + request_.onError = function(msg : String) { + if( callback != null) { + callback(new TTransportException(TTransportException.UNKNOWN, "IOError: " + msg)); + } + }; + + + // the request + request_.setPostBytes(buffer.getBytes()); + request_.request(true/*POST*/); + } } diff --git a/lib/haxe/src/org/apache/thrift/transport/TLayeredTransport.hx b/lib/haxe/src/org/apache/thrift/transport/TLayeredTransport.hx new file mode 100644 index 000000000..161d91edd --- /dev/null +++ b/lib/haxe/src/org/apache/thrift/transport/TLayeredTransport.hx @@ -0,0 +1,50 @@ +// Licensed to the Apache Software Foundation(ASF) under one +// or more contributor license agreements.See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership.The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +package org.apache.thrift.transport; + +import haxe.Int64; +import org.apache.thrift.TConfiguration; + +class TLayeredTransport extends TTransport +{ + private var InnerTransport : TTransport; + + public override function get_Configuration() : TConfiguration { + return InnerTransport.Configuration; + } + + // private CTOR to prevent direct instantiation + // in other words, this class MUST be extended + private function new(transport : TTransport) + { + if( transport != null) + InnerTransport = transport; + else + throw new TTransportException( TTransportException.UNKNOWN, "Inner transport must not be null"); + } + + public override function UpdateKnownMessageSize(size : Int64) : Void + { + InnerTransport.UpdateKnownMessageSize(size); + } + + public override function CheckReadBytesAvailable(numBytes : Int64) : Void + { + InnerTransport.CheckReadBytesAvailable(numBytes); + } +} diff --git a/lib/haxe/src/org/apache/thrift/transport/TServerSocket.hx b/lib/haxe/src/org/apache/thrift/transport/TServerSocket.hx index 4badb2a1f..e1ef5a18f 100644 --- a/lib/haxe/src/org/apache/thrift/transport/TServerSocket.hx +++ b/lib/haxe/src/org/apache/thrift/transport/TServerSocket.hx @@ -19,7 +19,10 @@ package org.apache.thrift.transport; -import haxe.remoting.SocketProtocol; +#if (cs || neko || cpp || java || macro || lua || php || python || hl) +import sys.net.Socket; +#end + import haxe.io.Bytes; import haxe.io.BytesBuffer; import haxe.io.BytesInput; @@ -27,9 +30,9 @@ import haxe.io.BytesOutput; import haxe.io.Input; import haxe.io.Output; import haxe.io.Eof; +import org.apache.thrift.TConfiguration; -//import flash.net.ServerSocket; - not yet available on Haxe 3.1.3 -#if ! (flash || html5) +#if ! (flash || html5 || js) import sys.net.Host; @@ -46,8 +49,10 @@ class TServerSocket extends TServerTransport { private var _useBufferedSockets : Bool = false; - public function new(?address : String = 'localhost', port : Int, clientTimeout : Float = 5, useBufferedSockets : Bool = false) + public function new(?address : String = 'localhost', port : Int, clientTimeout : Float = 5, useBufferedSockets : Bool = false, config : TConfiguration = null) { + super(config); + _clientTimeout = clientTimeout; _useBufferedSockets = useBufferedSockets; diff --git a/lib/haxe/src/org/apache/thrift/transport/TServerTransport.hx b/lib/haxe/src/org/apache/thrift/transport/TServerTransport.hx index 21899819e..16fa564d5 100644 --- a/lib/haxe/src/org/apache/thrift/transport/TServerTransport.hx +++ b/lib/haxe/src/org/apache/thrift/transport/TServerTransport.hx @@ -21,6 +21,15 @@ package org.apache.thrift.transport; class TServerTransport { + private var Configuration(default,null) : TConfiguration; + + // private CTOR to prevent direct instantiation + // in other words, this class MUST be extended + private function new( config : TConfiguration) + { + Configuration = (config != null) ? config : new TConfiguration(); + } + public function Accept() : TTransport { var transport = AcceptImpl(); if (transport == null) { diff --git a/lib/haxe/src/org/apache/thrift/transport/TSocket.hx b/lib/haxe/src/org/apache/thrift/transport/TSocket.hx index 7941ab9fe..a7435437f 100644 --- a/lib/haxe/src/org/apache/thrift/transport/TSocket.hx +++ b/lib/haxe/src/org/apache/thrift/transport/TSocket.hx @@ -19,12 +19,12 @@ package org.apache.thrift.transport; -#if flash +#if (cs || neko || cpp || java || macro || lua || php || python || hl) +import sys.net.Socket; +#elseif flash import flash.net.Socket; #elseif js import js.html.WebSocket; -#else -import haxe.remoting.SocketProtocol; #end import haxe.io.Bytes; @@ -34,6 +34,7 @@ import haxe.io.BytesOutput; import haxe.io.Input; import haxe.io.Output; import haxe.io.Eof; +import org.apache.thrift.TConfiguration; #if ! (flash || js) @@ -46,7 +47,7 @@ import sys.net.Host; * Thrift Socket Server based implementations. */ -class TSocket extends TTransport { +class TSocket extends TEndpointTransport { #if (flash || js) private var host : String; @@ -79,7 +80,9 @@ class TSocket extends TTransport { private var ioCallback : TException->Void = null; private var readCount : Int = 0; - public function new(host : String, port : Int) : Void { + public function new(host : String, port : Int, config : TConfiguration = null) : Void { + super(config); + #if (flash || js) this.host = host; #else @@ -132,6 +135,7 @@ class TSocket extends TTransport { buf.addByte( input.readByte()); --remaining; } + CountConsumedMessageBytes(len); return len; #elseif js @@ -144,6 +148,7 @@ class TSocket extends TTransport { buf.addByte( input.get(off+nr)); ++nr; } + CountConsumedMessageBytes(len); return len; #else @@ -158,6 +163,7 @@ class TSocket extends TTransport { var got = input.readBytes(data, 0, len); buf.addBytes( data, 0, got); readCount += got; + CountConsumedMessageBytes(got); return got; #end @@ -223,6 +229,7 @@ class TSocket extends TTransport { #end obuffer = new BytesOutput(); + ResetConsumedMessageSize(); ioCallback = callback; @@ -262,7 +269,7 @@ class TSocket extends TTransport { public override function open() : Void { #if js - var socket = new WebSocket(); + var socket = new WebSocket(host); socket.onmessage = function( event : js.html.MessageEvent) { this.input = event.data; } @@ -287,6 +294,7 @@ class TSocket extends TTransport { #end assignSocket( socket); + ResetConsumedMessageSize(); } #if js @@ -308,11 +316,26 @@ class TSocket extends TTransport { #end } + #if (flash) + + public function setTimeout( timeout : UInt) : Void { + if(isOpen()) { + socket.timeout = timeout; + } + this.timeout = timeout; + } + + #else + public function setTimeout( timeout : Float ) : Void { if(isOpen()) { - socket.setTimeout(timeout); + #if ! (js) + socket.setTimeout(timeout); + #end } this.timeout = timeout; } + #end + } diff --git a/lib/haxe/src/org/apache/thrift/transport/TStreamTransport.hx b/lib/haxe/src/org/apache/thrift/transport/TStreamTransport.hx index 31a7c141e..59bef15d3 100644 --- a/lib/haxe/src/org/apache/thrift/transport/TStreamTransport.hx +++ b/lib/haxe/src/org/apache/thrift/transport/TStreamTransport.hx @@ -19,6 +19,7 @@ package org.apache.thrift.transport; +import org.apache.thrift.TConfiguration; import org.apache.thrift.transport.*; import org.apache.thrift.helper.*; @@ -28,13 +29,15 @@ import haxe.io.BytesOutput; import haxe.io.BytesInput; -class TStreamTransport extends TTransport { +class TStreamTransport extends TEndpointTransport { public var InputStream(default,null) : TStream; public var OutputStream(default,null) : TStream; - public function new( input : TStream, output : TStream) { + public function new( input : TStream, output : TStream, config : TConfiguration) { + super(config); + this.InputStream = input; this.OutputStream = output; } @@ -48,7 +51,7 @@ class TStreamTransport extends TTransport { } public override function open() : Void { - } + } public override function close() : Void { if (InputStream != null) diff --git a/lib/haxe/src/org/apache/thrift/transport/TTransport.hx b/lib/haxe/src/org/apache/thrift/transport/TTransport.hx index e6b31791f..8d2b5b8b9 100644 --- a/lib/haxe/src/org/apache/thrift/transport/TTransport.hx +++ b/lib/haxe/src/org/apache/thrift/transport/TTransport.hx @@ -19,12 +19,18 @@ package org.apache.thrift.transport; +import haxe.Int64; import haxe.io.Eof; import haxe.io.Bytes; import haxe.io.BytesBuffer; import org.apache.thrift.AbstractMethodError; class TTransport { + + public var Configuration(get, never) : TConfiguration; + public function get_Configuration() : TConfiguration throw "abstract method called"; + public function UpdateKnownMessageSize(size : Int64) : Void throw "abstract method called"; + public function CheckReadBytesAvailable(numBytes : Int64) : Void throw "abstract method called"; /** * Queries whether the transport is open. diff --git a/lib/haxe/src/org/apache/thrift/transport/TWrappingServerTransport.hx b/lib/haxe/src/org/apache/thrift/transport/TWrappingServerTransport.hx index b2272f387..6da6e018b 100644 --- a/lib/haxe/src/org/apache/thrift/transport/TWrappingServerTransport.hx +++ b/lib/haxe/src/org/apache/thrift/transport/TWrappingServerTransport.hx @@ -25,23 +25,25 @@ package org.apache.thrift.transport; */ class TWrappingServerTransport extends TServerTransport { - private var transport(default,null) : TTransport; + private var transport(default,null) : TTransport; - public function new(transport : TTransport) { - this.transport = transport; - } + public function new(transport : TTransport) { + super(transport.Configuration); - public override function Listen() : Void - { - } + this.transport = transport; + } - private override function AcceptImpl() : TTransport - { - return transport; - } + public override function Listen() : Void + { + } - public override function Close() : Void - { + private override function AcceptImpl() : TTransport + { + return transport; + } - } + public override function Close() : Void + { + + } } diff --git a/test/haxe/Makefile.am b/test/haxe/Makefile.am index 6c0483e9e..d37aaa77a 100644 --- a/test/haxe/Makefile.am +++ b/test/haxe/Makefile.am @@ -34,6 +34,13 @@ $(BIN_CPP): \ ../../lib/haxe/src/org/apache/thrift/**/*.hx \ gen-haxe/thrift/test/ThriftTest.hx $(HAXE) --cwd . cpp.hxml + +# $(HAXE) --cwd . csharp +# $(HAXE) --cwd . flash +# $(HAXE) --cwd . java +# $(HAXE) --cwd . javascript +# $(HAXE) --cwd . neko +# $(HAXE) --cwd . python $(BIN_PHP): \ src/*.hx \ @@ -49,15 +56,6 @@ $(BIN_PHP_WEB): \ -#TODO: other haxe targets -# $(HAXE) --cwd . csharp -# $(HAXE) --cwd . flash -# $(HAXE) --cwd . java -# $(HAXE) --cwd . javascript -# $(HAXE) --cwd . neko -# $(HAXE) --cwd . python # needs Haxe 3.2.0 - - clean-local: $(RM) -r gen-haxe bin diff --git a/test/haxe/TestClientServer.hxproj b/test/haxe/TestClientServer.hxproj index 6696d80c2..44faa37ee 100644 --- a/test/haxe/TestClientServer.hxproj +++ b/test/haxe/TestClientServer.hxproj @@ -4,7 +4,7 @@ <output> <movie outputType="Application" /> <movie input="" /> - <movie path="bin/TestClientServer" /> + <movie path="bin\TestClientServer" /> <movie fps="30" /> <movie width="800" /> <movie height="600" /> @@ -17,7 +17,7 @@ <classpaths> <class path="src" /> <class path="gen-haxe" /> - <class path="../../lib/haxe/src" /> + <class path="..\..\lib\haxe\src" /> </classpaths> <!-- Build options --> <build> diff --git a/test/haxe/make_all.bat b/test/haxe/make_all.bat index eaeba890d..966bfa530 100644 --- a/test/haxe/make_all.bat +++ b/test/haxe/make_all.bat @@ -30,16 +30,19 @@ thrift -r -gen haxe ..\ThriftTest.thrift if errorlevel 1 goto STOP rem # invoke Haxe compiler for all targets +rd .buildtemp /S /Q for %%a in (*.hxml) do ( - rem * filter Python, as it is not supported by Haxe 3.1.3 (but will be in 3.1.4) - if not "%%a"=="python.hxml" ( - echo -------------------------- - echo Building %%a ... - echo -------------------------- - haxe --cwd . %%a - ) + echo -------------------------- + echo Building %%a ... + echo -------------------------- + haxe --cwd . %%a + if not exist ".buildtemp" mkdir ".buildtemp" + move bin ".buildtemp\%%a" + if errorlevel 1 pause ) +rd bin /S /Q +rename .buildtemp bin echo. echo done. diff --git a/test/haxe/php-web-server.hxml b/test/haxe/php-web-server.hxml index 395a8521e..f628c3a51 100644 --- a/test/haxe/php-web-server.hxml +++ b/test/haxe/php-web-server.hxml @@ -26,8 +26,8 @@ -main Main #PHP target --php bin/php-web-server/ ---php-front Main-debug.php +-php bin/php-web-server +-D php-front=Main-debug.php #defines -D phpwebserver diff --git a/test/haxe/php.hxml b/test/haxe/php.hxml index 965189843..c3aa97fb3 100644 --- a/test/haxe/php.hxml +++ b/test/haxe/php.hxml @@ -26,8 +26,8 @@ -main Main #PHP target --php bin/php/ ---php-front Main-debug.php +-php bin/php +-D php-front=Main-debug.php #Add debug information diff --git a/test/haxe/src/Arguments.hx b/test/haxe/src/Arguments.hx index 56e525356..023f250fd 100644 --- a/test/haxe/src/Arguments.hx +++ b/test/haxe/src/Arguments.hx @@ -92,7 +92,7 @@ class Arguments #if sys private static function GetHelp() : String { - var sProg = Path.withoutDirectory( Sys.executablePath()); + var sProg = Path.withoutDirectory( Sys.programPath()); return "\n" +sProg+" [client|server] [options]\n" +"\n" diff --git a/test/haxe/src/TestClient.hx b/test/haxe/src/TestClient.hx index 853319e23..579dc00a1 100644 --- a/test/haxe/src/TestClient.hx +++ b/test/haxe/src/TestClient.hx @@ -35,7 +35,7 @@ import org.apache.thrift.server.*; import org.apache.thrift.meta_data.*; #if cpp -import cpp.vm.Thread; +import sys.thread.Thread; #else // no thread support (yet) #end diff --git a/test/haxe/src/TestServer.hx b/test/haxe/src/TestServer.hx index 450c8f28c..d44c68cfa 100644 --- a/test/haxe/src/TestServer.hx +++ b/test/haxe/src/TestServer.hx @@ -39,20 +39,24 @@ class TestServer switch( args.transport) { case socket: trace("- socket port "+args.port); + #if (flash || html5 || js) + throw "Transport not supported on this platform"; + #else transport = new TServerSocket( args.port); + #end case http: trace("- http"); - #if !phpwebserver - throw "HTTP server not implemented yet"; - //transport = new THttpServer( targetHost); + #if phpwebserver + transport = new TWrappingServerTransport( + new TStreamTransport( + new TFileStream("php://input", Read), + new TFileStream("php://output", Append), + null + ) + ); #else - transport = new TWrappingServerTransport( - new TStreamTransport( - new TFileStream("php://input", Read), - new TFileStream("php://output", Append) - ) - ); - + throw "Transport not supported on this platform"; + //transport = new THttpServer( targetHost); #end default: throw "Unhandled transport"; @@ -86,7 +90,7 @@ class TestServer // Processor - var handler = new TestServerHandler(); + var handler : ThriftTest_service = new TestServerHandler(); var processor = new ThriftTestProcessor(handler); // Simple Server diff --git a/test/haxe/src/TestServerHandler.hx b/test/haxe/src/TestServerHandler.hx index b8a2590d5..0e1910560 100644 --- a/test/haxe/src/TestServerHandler.hx +++ b/test/haxe/src/TestServerHandler.hx @@ -36,7 +36,7 @@ import haxe.ds.ObjectMap; import thrift.test.*; // generated code -class TestServerHandler implements ThriftTest { +class TestServerHandler implements ThriftTest_service { public var server:TServer; @@ -465,8 +465,10 @@ class TestServerHandler implements ThriftTest { */ public function testOneway(secondsToSleep:haxe.Int32):Void { + #if sys trace("testOneway(" + secondsToSleep + "), sleeping..."); Sys.sleep(secondsToSleep); + #end trace("testOneway finished"); } diff --git a/tutorial/haxe/Tutorial.hxproj b/tutorial/haxe/Tutorial.hxproj index 796f648a5..44e0efdbb 100644 --- a/tutorial/haxe/Tutorial.hxproj +++ b/tutorial/haxe/Tutorial.hxproj @@ -4,7 +4,7 @@ <output> <movie outputType="Application" /> <movie input="" /> - <movie path="bin/HaxeTutorial" /> + <movie path="bin\HaxeTutorial" /> <movie fps="30" /> <movie width="800" /> <movie height="600" /> @@ -17,7 +17,7 @@ <classpaths> <class path="src" /> <class path="gen-haxe" /> - <class path="../../lib/haxe/src" /> + <class path="..\..\lib\haxe\src" /> </classpaths> <!-- Build options --> <build> diff --git a/tutorial/haxe/php-web-server.hxml b/tutorial/haxe/php-web-server.hxml index 395a8521e..88007c18f 100644 --- a/tutorial/haxe/php-web-server.hxml +++ b/tutorial/haxe/php-web-server.hxml @@ -27,7 +27,7 @@ #PHP target -php bin/php-web-server/ ---php-front Main-debug.php +-D php-front=Main-debug.php #defines -D phpwebserver diff --git a/tutorial/haxe/php.hxml b/tutorial/haxe/php.hxml index c2f68878e..42bbf7424 100644 --- a/tutorial/haxe/php.hxml +++ b/tutorial/haxe/php.hxml @@ -27,7 +27,7 @@ #PHP target -php bin/php/ ---php-front Main-debug.php +-D php-front=Main-debug.php #Add debug information -debug diff --git a/tutorial/haxe/src/CalculatorHandler.hx b/tutorial/haxe/src/CalculatorHandler.hx index e9752db9f..fcb06d196 100644 --- a/tutorial/haxe/src/CalculatorHandler.hx +++ b/tutorial/haxe/src/CalculatorHandler.hx @@ -31,7 +31,7 @@ import tutorial.*; import shared.*; -class CalculatorHandler implements Calculator { +class CalculatorHandler implements Calculator_service { private var log = new IntMap<SharedStruct>(); diff --git a/tutorial/haxe/src/Main.hx b/tutorial/haxe/src/Main.hx index 6bebe7164..a56549f8c 100644 --- a/tutorial/haxe/src/Main.hx +++ b/tutorial/haxe/src/Main.hx @@ -32,6 +32,7 @@ import shared.*; enum Prot { binary; json; + compact; } enum Trns { @@ -112,12 +113,12 @@ class Main { #if ! (flash || js) private static function GetHelp() : String { - return Sys.executablePath()+" modus trnsOption transport protocol\n" + return Sys.programPath+" modus layered transport protocol\n" +"Options:\n" - +" modus: client, server (default: client)\n" - +" trnsOption: framed, buffered (default: none)\n" - +" transport: socket, http (default: socket)\n" - +" protocol: binary, json (default: binary)\n" + +" modus: client, server (default: client)\n" + +" layered: framed, buffered (default: none)\n" + +" transport: socket, http (default: socket)\n" + +" protocol: binary, json, compact (default: binary)\n" +"\n" +"All arguments are optional.\n"; } @@ -160,6 +161,9 @@ class Main { } else if ( arg == "json") { prot = json; ++step; + } else if ( arg == "compact") { + prot = compact; + ++step; } else { throw "Unknown protocol "+arg; } @@ -217,6 +221,9 @@ class Main { case json: trace("- JSON protocol"); protocol = new TJSONProtocol( transport); + case compact: + trace("- compact protocol"); + protocol = new TCompactProtocol( transport); default: throw "Unhandled protocol"; } @@ -232,7 +239,7 @@ class Main { var client = ClientSetup(); try { - client.ping(); + client.ping(); trace("ping() successful"); } catch(error : TException) { trace('ping() failed: $error'); @@ -310,11 +317,12 @@ class Main { #else trace("- http transport"); transport = new TWrappingServerTransport( - new TStreamTransport( - new TFileStream("php://input", Read), - new TFileStream("php://output", Append) - ) - ); + new TStreamTransport( + new TFileStream("php://input", Read), + new TFileStream("php://output", Append), + null + ) + ); #end default: @@ -341,11 +349,14 @@ class Main { case json: trace("- JSON protocol"); protfactory = new TJSONProtocolFactory(); + case compact: + trace("- compact protocol"); + protfactory = new TCompactProtocolFactory(); default: throw "Unhandled protocol"; } - var handler = new CalculatorHandler(); + var handler : Calculator_service = new CalculatorHandler(); var processor = new CalculatorProcessor(handler); var server = new TSimpleServer( processor, transport, transfactory, protfactory); #if phpwebserver |