THRIFT-5370 Haxe 4 compatibility incl TConfiguration & MAX_MESSAGE_SIZE
Client: haxe
Patch: Jens Geyer

This closes #2349
diff --git a/.gitignore b/.gitignore
index 603838f..c34d9f6 100644
--- a/.gitignore
+++ b/.gitignore
@@ -355,6 +355,7 @@
 /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 725a534..9f8e946 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 @@
     (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 @@
   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 @@
   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 @@
   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 @@
   std::string constant_name(std::string name);
 
 private:
-  bool callbacks_;
   bool rtti_;
   string buildmacro_;
 
@@ -290,10 +288,17 @@
  * @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 @@
  * @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 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 @@
   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 @@
   } 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 @@
  *
  * @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,30 @@
  * @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;
+
+  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) << "_service;" << endl;
+    }
+  }
+
+  f_service_ << endl;
+
+  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;
@@ -1493,8 +1523,7 @@
 
   f_service_ << endl;
 
-  generate_service_interface(tservice);
-
+  generate_service_interface(tservice,true);
   f_service_.close();
 
   // Now make the implementation/client file
@@ -1515,7 +1544,6 @@
   f_service_ << endl;
 
   generate_service_client(tservice);
-
   f_service_.close();
 
   // Now make the helper class files
@@ -1525,18 +1553,20 @@
   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 @@
  *
  * @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 @@
  *
  * @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 @@
   }
 
   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 @@
  *
  * @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;
   }
 
-  generate_haxe_doc(f_service_, tservice);
-  // generate_rtti_decoration(f_service_); - not yet, because of
-  // https://github.com/HaxeFoundation/haxe/issues/3626
-  generate_macro_decoration(f_service_);
-  f_service_ << indent() << "interface " << get_cap_name(service_name_) << extends_iface << " {"
-             << endl << endl;
-  indent_up();
   vector<t_function*> functions = tservice->get_functions();
   vector<t_function*>::iterator f_iter;
+
+  generate_haxe_doc(f_service_, tservice);
+  generate_rtti_decoration(f_service_);
+  generate_macro_decoration(f_service_);
+  f_service_ << indent() << "interface " << get_cap_name(service_name_) << cbk_postfix << extends_iface << " {"
+             << endl << endl;
+  indent_up();
   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 @@
     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 @@
     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 @@
     } 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_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_) << "if (onError == null)" << endl;
       indent_up();
-      indent(f_service_) << "var x = 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_) << "throw error;" << 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(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_) << appex << " = TApplicationException.read(iprot_);" << endl;
+      indent(f_service_) << "iprot_.readMessageEnd();" << endl;
+      indent(f_service_) << "if (onError == null)" << endl;
+      indent_up();
+      indent(f_service_) << "throw " << appex << ";" << endl;
+      indent_down();
+      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_) << "}" << endl;
+        indent(f_service_) << "onError(" << result << "." << (*x_iter)->get_name() << ");" << endl;
+        indent(f_service_) << "return;" << endl;
+        indent_down();
+        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 @@
   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 @@
 
   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 @@
   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 @@
 
   // 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;
-    } 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_ << 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_ << 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 {
+      f_service_ << ", ";
+    }
+    f_service_ << "args." << (*f_iter)->get_name();
+  }
+  f_service_ << ");" << endl;
 
   indent_down();
   f_service_ << indent() << "}";
@@ -2128,16 +2113,16 @@
   }
 
   // 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 @@
  * @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 @@
     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 @@
 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 98327f4..2d6d62b 100755
--- a/configure.ac
+++ b/configure.ac
@@ -467,7 +467,7 @@
 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 c9f74b5..1f09c2c 100644
--- a/lib/haxe/README.md
+++ b/lib/haxe/README.md
@@ -26,16 +26,14 @@
 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 @@
 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,36 +83,25 @@
 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
+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.
 
 
-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.
-
-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 14d0dcb..61448da 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 44eec3a..3a7807d 100644
--- a/lib/haxe/src/org/apache/thrift/Limits.hx
+++ b/lib/haxe/src/org/apache/thrift/Limits.hx
@@ -23,9 +23,9 @@
 
     // 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 0000000..c5ec4e5
--- /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 54fa1ff..8bd9fcc 100644
--- a/lib/haxe/src/org/apache/thrift/TException.hx
+++ b/lib/haxe/src/org/apache/thrift/TException.hx
@@ -32,5 +32,10 @@
         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 8845fd0..a8e735f 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 @@
         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 @@
     }
 
     /**
+        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 @@
 
 // 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 @@
 
 // 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 7ef291c..2cc254b 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 @@
 /**
 * 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 @@
 
     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 @@
         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 @@
         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 @@
         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 @@
     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 @@
 
     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 @@
 
     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 @@
 
     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 @@
 
     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 @@
 
     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 @@
     }
 
     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 @@
 
     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 03b13e2..ae626b5 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.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 @@
 /**
 * 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 @@
     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 new( transport : TTransport) {
+		super(transport);
     }
 
-    public function getTransport() : TTransport {
-      return trans;
-    }
-
-
     public function Reset() : Void{
         while ( ! lastField_.isEmpty()) {
             lastField_.pop();
@@ -135,7 +122,7 @@
     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 @@
         }
 
         var tmp = i32buf.getBytes();
-        trans.write( tmp, 0, tmp.length);
+        Transport.write( tmp, 0, tmp.length);
     }
 
     /**
@@ -329,7 +316,7 @@
      */
     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 @@
      */
     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 @@
      */
     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 @@
             }
         }
         var tmp = varint64out.getBytes();
-        trans.write( tmp, 0, tmp.length);
+        Transport.write( tmp, 0, tmp.length);
     }
 
 
@@ -497,7 +481,9 @@
         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 @@
         }
 
         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 @@
         }
 
         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 @@
      */
     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 @@
      */
     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 @@
      */
     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 @@
      */
     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 @@
     {
         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 e20ff33..145eab9 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.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 @@
 *
 *  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 @@
     // 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 @@
         ReadJSONObjectStart();
 
         var map = new TMap( KeyType, ValueType, Count);
-        return map;
+		CheckReadBytesAvailableMap(map);
+		return map;
     }
 
     public function readMapEnd() : Void {
@@ -244,6 +235,7 @@
         var Count : Int = ReadJSONInteger();
 
         var list = new TList( ElementType, Count);
+		CheckReadBytesAvailableList(list);
         return list;
     }
 
@@ -257,6 +249,7 @@
         var Count : Int = ReadJSONInteger();
 
         var set = new TSet( ElementType, Count);
+		CheckReadBytesAvailableSet(set);
         return set;
     }
 
@@ -313,7 +306,7 @@
         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 @@
                 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 @@
                 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 @@
                     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 @@
                     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 @@
         }
 
         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 @@
         }
 
         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 @@
         }
 
         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 @@
         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 @@
 
             // 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 @@
 
     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 @@
         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 @@
     }
 
 
+	// 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 @@
             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 @@
             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 @@
     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 b7f3842..316067a 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 @@
     // 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 769e93c..011f42b 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 @@
     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 0000000..60e4a1f
--- /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 cf0211b..0000000
--- 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 4b33fcf..72ce921 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 @@
 
 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.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 @@
 
     // 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 @@
         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 @@
                 // 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 @@
         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 @@
                 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 @@
         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 @@
 
     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 539e720..11d1a72 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 @@
     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 0000000..8c0d3ef
--- /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 cef82ef..37e4959 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 @@
 
 import org.apache.thrift.transport.*;
 
+import haxe.Int64;
 import haxe.io.Eof;
 import haxe.io.Bytes;
 import haxe.io.BytesBuffer;
@@ -32,16 +33,9 @@
  * 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 @@
     /**
      * 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 @@
     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 @@
         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 @@
         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 8d45a64..ca04e7f 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 1972853..cc34ec4 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 @@
      * 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 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)  :  Void
-        {
-            CRLF.writeByte(13);
-            CRLF.writeByte(10);
-            this.host = host;
-            this.port = port;
-            this.resource = resource;
-        }
+	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()
-        }
+	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 remained:" + socket.bytesAvailable);
-                return socket.bytesAvailable>0;
-            }
-            return false;
-        }
+	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();
+	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;
-                    }
-                }
+		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();
+			// read chunk size
+			if (bytesInChunk == 0)
+			{
+				n1 = input.readByte();
+				n2 = input.readByte();
 
-                    chunkSize.writeByte(n1);
-                    chunkSize.writeByte(n2);
+				chunkSize.writeByte(n1);
+				chunkSize.writeByte(n2);
 
-                    while (!((n1 == 13) && (n2 == 10)))
-                    {
-                        n1 = n2;
-                        n2 = input.readByte();
-                        chunkSize.writeByte(n2);
-                    }
+				while (!((n1 == 13) && (n2 == 10)))
+				{
+					n1 = n2;
+					n2 = input.readByte();
+					chunkSize.writeByte(n2);
+				}
 
-                    bytesInChunk = parseInt(chunkSize.toString(), 16);
-                }
+				bytesInChunk = parseInt(chunkSize.toString(), 16);
+			}
 
-                input.readBytes(buf, off, len);
-                debugBuffer(buf);
-                bytesInChunk -= len;
+			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;
-        }
+			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 += " ";
-            }
+	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 + "<<");
-        }
+		trace(debug + "<<");
+	}
 
-        public override function write(buf : Bytes, off  :  Int, len  :  Int)  :  Void
-        {
-            obuffer.writeBytes(buf, off, len);
-        }
+	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 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 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 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 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 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 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 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 ? false  :  this.socket.connected);
-        }
+	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 79f8661..703dd81 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.Http;
 
+#if js
+import js.lib.Promise;
+#end
 
 
 /**
@@ -34,7 +38,7 @@
 * 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 @@
     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 @@
         var data =Bytes.alloc(len);
         len = responseBuffer_.readBytes(data, off, len);
         buf.addBytes(data,0,len);
+        CountConsumedMessageBytes(len);
         return len;
     }
 
@@ -78,24 +86,36 @@
         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_.onBytes = function(data : Bytes) {
+			responseBuffer_ = new BytesInput(data);
+			if( callback != null) {
+				callback(null);
+			}
+		};
 
-        request_.setPostData(buffer.getBytes().toString());
-        request_.request(true/*POST*/);
+		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 0000000..161d91e
--- /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 4badb2a..e1ef5a1 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.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 @@
     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 2189981..16fa564 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 @@
 
 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 7941ab9..a743543 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.Input;
 import haxe.io.Output;
 import haxe.io.Eof;
+import org.apache.thrift.TConfiguration;
 
 
 #if ! (flash || js)
@@ -46,7 +47,7 @@
    * Thrift Socket Server based implementations.
    */
 
-class TSocket extends TTransport  {
+class TSocket extends TEndpointTransport  {
 
     #if (flash || js)
     private var host  :  String;
@@ -79,7 +80,9 @@
     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 @@
                 buf.addByte( input.readByte());
                 --remaining;
             }
+            CountConsumedMessageBytes(len);
             return len;
 
             #elseif js
@@ -144,6 +148,7 @@
                 buf.addByte( input.get(off+nr));
                 ++nr;
             }
+			CountConsumedMessageBytes(len);
             return len;
 
             #else
@@ -158,6 +163,7 @@
             var got = input.readBytes(data, 0, len);
             buf.addBytes( data, 0, got);
             readCount += got;
+			CountConsumedMessageBytes(got);
             return got;
 
             #end
@@ -223,6 +229,7 @@
         #end
 
         obuffer = new BytesOutput();
+		ResetConsumedMessageSize();
 
 
         ioCallback = callback;
@@ -262,7 +269,7 @@
     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 @@
         #end
 
         assignSocket( socket);
+		ResetConsumedMessageSize();
     }
 
     #if js
@@ -308,11 +316,26 @@
         #end
     }
 
-    public function setTimeout( timeout : Float ) : Void {
+	#if (flash)
+	
+    public function setTimeout( timeout : UInt) : Void {
         if(isOpen()) {
-            socket.setTimeout(timeout);
+            socket.timeout = timeout;
         }
         this.timeout = timeout;
     }
 
+	#else
+	
+    public function setTimeout( timeout : Float ) : Void {
+        if(isOpen()) {
+			#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 31a7c14..59bef15 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.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 @@
     }
 
     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 e6b3179..8d2b5b8 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 b2272f3..6da6e01 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 @@
 */
 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 6c0483e..d37aaa7 100644
--- a/test/haxe/Makefile.am
+++ b/test/haxe/Makefile.am
@@ -34,6 +34,13 @@
 		../../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 @@
 
 
 
-#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 6696d80..44faa37 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 eaeba89..966bfa5 100644
--- a/test/haxe/make_all.bat
+++ b/test/haxe/make_all.bat
@@ -30,16 +30,19 @@
 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 395a852..f628c3a 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 9651898..c3aa97f 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 56e5253..023f250 100644
--- a/test/haxe/src/Arguments.hx
+++ b/test/haxe/src/Arguments.hx
@@ -92,7 +92,7 @@
     #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 853319e..579dc00 100644
--- a/test/haxe/src/TestClient.hx
+++ b/test/haxe/src/TestClient.hx
@@ -35,7 +35,7 @@
 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 450c8f2..d44c68c 100644
--- a/test/haxe/src/TestServer.hx
+++ b/test/haxe/src/TestServer.hx
@@ -39,20 +39,24 @@
             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 @@
 
 
             // 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 b8a2590..0e19105 100644
--- a/test/haxe/src/TestServerHandler.hx
+++ b/test/haxe/src/TestServerHandler.hx
@@ -36,7 +36,7 @@
 import thrift.test.*;  // generated code
 
 
-class TestServerHandler implements ThriftTest {
+class TestServerHandler implements ThriftTest_service {
 
     public var server:TServer;
 
@@ -465,8 +465,10 @@
     */
     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 796f648..44e0efd 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 395a852..88007c1 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 c2f6887..42bbf74 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 e9752db..fcb06d1 100644
--- a/tutorial/haxe/src/CalculatorHandler.hx
+++ b/tutorial/haxe/src/CalculatorHandler.hx
@@ -31,7 +31,7 @@
 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 6bebe71..a56549f 100644
--- a/tutorial/haxe/src/Main.hx
+++ b/tutorial/haxe/src/Main.hx
@@ -32,6 +32,7 @@
 enum Prot {
     binary;
     json;
+	compact;
 }
 
 enum Trns {
@@ -112,12 +113,12 @@
     #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 @@
                 } else if ( arg == "json") {
                     prot = json;
                     ++step;
+                } else if ( arg == "compact") {
+                    prot = compact;
+                    ++step;
                 } else {
                     throw "Unknown protocol "+arg;
                 }
@@ -217,6 +221,9 @@
         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 @@
         var client = ClientSetup();
 
         try {
-              client.ping();
+            client.ping();
             trace("ping() successful");
         } catch(error : TException) {
             trace('ping() failed: $error');
@@ -310,11 +317,12 @@
             #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 @@
         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