THRIFT-3833 haxe http server implementation (by embeding into php web server)
Client: Haxe
Patch: Oleksii Prudkyi <Oleksii.Prudkyi@gmail.com> + some modifications by Jens Geyer

This closes #1013
This closes #1020
diff --git a/lib/haxe/README.md b/lib/haxe/README.md
index 2692be9..c5ad680 100644
--- a/lib/haxe/README.md
+++ b/lib/haxe/README.md
@@ -94,8 +94,8 @@
 Current status
 ========================
 - tested with Haxe C++ target
-- tested with Haxe PHP target (console, binary protocols)
-- transports: Socket, HTTP (client only), Stream
+- 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 
@@ -117,3 +117,48 @@
 Javascript:
 - tutorial fails to build because of unsupported Sys.args
 
+PHP HTTP Server notes
+========================
+
+- you have to import PHP files generated by haxe into PHP
+```php
+require_once  dirname(__FILE__) . '/bin/php-web-server/Main-debug.php';
+```
+
+- trace() by default outputs into stdout (http response), so you have to redirect it to stderr or you own logs, something like
+```haxe
+//remap trace to error log
+haxe.Log.trace = function(v:Dynamic, ?infos:haxe.PosInfos) 
+{ 
+	//simulate normal trace https://github.com/HaxeFoundation/haxe/blob/development/std/haxe/Log.hx
+	var newValue : Dynamic;
+	if (infos != null && infos.customParams!=null) {
+		var extra:String = "";
+		for( v in infos.customParams )
+			extra += "," + v;
+		newValue = v + extra;
+	}
+	else {
+		newValue = v;
+	}
+	var msg = infos != null ? infos.fileName + ':' + infos.lineNumber + ': ' : '';
+	Sys.stderr().writeString('${msg}${newValue}\n');
+}
+```
+
+- to allow thrift server to read/write HTTP request/response, it should be pointed out to php streams
+```haxe
+transport =	new TWrappingServerTransport(
+				new TStreamTransport(
+					new TFileStream("php://input", Read),
+					new TFileStream("php://output", Append)
+					)
+				);
+```
+
+- TSimpleServer doesn't stop after first call, so processor.process() should be called instead, or use runOnce property 
+```haxe
+var server = new TSimpleServer( processor, transport, transfactory, protfactory);
+server.runOnce = true;
+```
+
diff --git a/lib/haxe/src/org/apache/thrift/server/TSimpleServer.hx b/lib/haxe/src/org/apache/thrift/server/TSimpleServer.hx
index 3b64b62..c9856b4 100644
--- a/lib/haxe/src/org/apache/thrift/server/TSimpleServer.hx
+++ b/lib/haxe/src/org/apache/thrift/server/TSimpleServer.hx
@@ -29,6 +29,10 @@
 
     private var stop : Bool = false;
 
+    //stops just after input transport returns EOF
+    //useful for limited scenarios, like embeding into php server
+    public var runOnce : Bool = false;
+
     public function new( processor : TProcessor,
                          serverTransport : TServerTransport,
                          transportFactory : TTransportFactory = null,
@@ -102,6 +106,11 @@
             catch( ttx : TTransportException)
             {
                 // Usually a client disconnect, expected
+                if(runOnce && ttx.errorID == TTransportException.END_OF_FILE) {
+                  //input returns eof, exit
+                  //follows lib/cpp/src/thrift/server/TServerFramework.cpp
+                  Stop();
+                }
             }
             catch( pex : TProtocolException)
             {
diff --git a/lib/haxe/src/org/apache/thrift/transport/TTransport.hx b/lib/haxe/src/org/apache/thrift/transport/TTransport.hx
index 4a3bd90..e6b3179 100644
--- a/lib/haxe/src/org/apache/thrift/transport/TTransport.hx
+++ b/lib/haxe/src/org/apache/thrift/transport/TTransport.hx
@@ -19,6 +19,7 @@
 
 package org.apache.thrift.transport;
 
+import haxe.io.Eof;
 import haxe.io.Bytes;
 import haxe.io.BytesBuffer;
 import org.apache.thrift.AbstractMethodError;
@@ -85,16 +86,21 @@
         var got : Int = 0;
         var ret : Int = 0;
         while (got < len) {
+          try {
             ret = read(buf, off+got, len-got);
             if (ret <= 0) {
               throw new TTransportException(TTransportException.UNKNOWN,
-                                        "Cannot read. Remote side has closed. Tried to read "
-                                        + len + " bytes, but only got " + got + " bytes.");
+                          "Cannot read. Remote side has closed. Tried to read "
+                          + len + " bytes, but only got " + got + " bytes.");
             }
-            got += ret;
+          }
+          catch (eof : Eof) {
+            throw new TTransportException(TTransportException.END_OF_FILE, 'Can\'t read $len bytes!');
+          }
+          got += ret;
         }
         return got;
-      }
+    }
 
     /**
      * Writes the buffer to the output
@@ -130,4 +136,4 @@
             throw new AbstractMethodError();
     }
 
-}
\ No newline at end of file
+}
diff --git a/lib/haxe/src/org/apache/thrift/transport/TWrappingServerTransport.hx b/lib/haxe/src/org/apache/thrift/transport/TWrappingServerTransport.hx
new file mode 100644
index 0000000..b2272f3
--- /dev/null
+++ b/lib/haxe/src/org/apache/thrift/transport/TWrappingServerTransport.hx
@@ -0,0 +1,47 @@
+/*
+ * 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;
+
+
+/*
+   wraps real transport, provided by constructor
+*/
+class TWrappingServerTransport extends TServerTransport {
+
+  private var transport(default,null) : TTransport;
+
+  public function new(transport : TTransport) {
+    this.transport = transport;
+  }
+
+  public override function Listen() : Void
+  {
+  }
+
+  private override function AcceptImpl() : TTransport
+  {
+    return transport;
+  }
+
+  public override function Close() : Void
+  {
+
+  }
+}