You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@thrift.apache.org by ns...@apache.org on 2016/03/18 07:36:32 UTC

[3/4] thrift git commit: THRIFT-3728 http transport for thrift-lua

THRIFT-3728 http transport for thrift-lua

This closes #938


Project: http://git-wip-us.apache.org/repos/asf/thrift/repo
Commit: http://git-wip-us.apache.org/repos/asf/thrift/commit/e432c6b8
Tree: http://git-wip-us.apache.org/repos/asf/thrift/tree/e432c6b8
Diff: http://git-wip-us.apache.org/repos/asf/thrift/diff/e432c6b8

Branch: refs/heads/master
Commit: e432c6b828d70ee4901f1ec3e04b0145da2ce54e
Parents: b819260
Author: Wang Yaofu <vo...@sina.cn>
Authored: Wed Mar 9 16:39:03 2016 +0800
Committer: Nobuaki Sukegawa <ns...@apache.org>
Committed: Fri Mar 18 04:40:46 2016 +0900

----------------------------------------------------------------------
 lib/lua/THttpTransport.lua     | 182 ++++++++++++++++++++++++++++++++++++
 lib/lua/TServer.lua            |  11 ++-
 test/lua/test_basic_client.lua |   5 +-
 test/lua/test_basic_server.lua |   2 +
 test/tests.json                |   3 +-
 5 files changed, 196 insertions(+), 7 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/thrift/blob/e432c6b8/lib/lua/THttpTransport.lua
----------------------------------------------------------------------
diff --git a/lib/lua/THttpTransport.lua b/lib/lua/THttpTransport.lua
new file mode 100644
index 0000000..5bbfece
--- /dev/null
+++ b/lib/lua/THttpTransport.lua
@@ -0,0 +1,182 @@
+--
+-- 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.
+--
+
+require 'TTransport'
+
+THttpTransport = TTransportBase:new{
+  __type = 'THttpTransport',
+  path = '/',
+  wBuf = '',
+  rBuf = '',
+  CRLF = '\r\n',
+  VERSION = '1.0.0',
+  isServer = true
+}
+
+function THttpTransport:new(obj)
+  if ttype(obj) ~= 'table' then
+    error(ttype(self) .. 'must be initialized with a table')
+  end
+
+  -- Ensure a transport is provided
+  if not obj.trans then
+    error('You must provide ' .. ttype(self) .. ' with a trans')
+  end
+
+  return TTransportBase.new(self, obj)
+end
+
+function THttpTransport:isOpen()
+  return self.trans:isOpen()
+end
+
+function THttpTransport:open()
+  return self.trans:open()
+end
+
+function THttpTransport:close()
+  return self.trans:close()
+end
+
+function THttpTransport:readAll(len)
+  return self:read(len)
+end
+
+function THttpTransport:read(len)
+  if string.len(self.rBuf) == 0 then
+    self:_readMsg()
+  end
+  if len > string.len(self.rBuf) then
+    local val = self.rBuf
+    self.rBuf = ''
+    return val
+  end
+
+  local val = string.sub(self.rBuf, 0, len)
+  self.rBuf = string.sub(self.rBuf, len+1)
+  return val
+end
+
+function THttpTransport:_readMsg()
+  while true do
+    self.rBuf = self.rBuf .. self.trans:read(4)
+    if string.find(self.rBuf, self.CRLF .. self.CRLF) then
+      break
+    end
+  end
+  if not self.rBuf then
+    self.rBuf = ""
+    return
+  end
+  self:getLine()
+  local headers = self:_parseHeaders()
+  if not headers then
+    self.rBuf = ""
+    return
+  end
+
+  local length = tonumber(headers["Content-Length"])
+  if length then
+    length = length - string.len(self.rBuf)
+    self.rBuf = self.rBuf .. self.trans:readAll(length)
+  end
+  if self.rBuf == nil then
+    self.rBuf = ""
+  end
+end
+
+function THttpTransport:getLine()
+  local a,b = string.find(self.rBuf, self.CRLF)
+  local line = ""
+  if a and b then
+    line = string.sub(self.rBuf, 0, a-1)
+    self.rBuf = string.sub(self.rBuf, b+1)
+  end
+  return line
+end
+
+function THttpTransport:_parseHeaders()
+  local headers = {}
+
+  repeat
+    local line = self:getLine()
+    for key, val in string.gmatch(line, "([%w%-]+)%s*:%s*(.+)") do
+      if headers[key] then
+        local delimiter = ", "
+        if key == "Set-Cookie" then
+          delimiter = "; "
+        end
+        headers[key] = headers[key] .. delimiter .. tostring(val)
+      else
+        headers[key] = tostring(val)
+      end
+    end
+  until string.find(line, "^%s*$")
+
+  return headers
+end
+
+function THttpTransport:write(buf, len)
+  if len and len < string.len(buf) then
+    buf = string.sub(buf, 0, len)
+  end
+  self.wBuf = self.wBuf .. buf
+end
+
+function THttpTransport:writeHttpHeader(content_len)
+  if self.isServer then
+    local header =  "HTTP/1.1 200 OK" .. self.CRLF
+      .. "Server: Thrift/" .. self.VERSION .. self.CRLF
+      .. "Access-Control-Allow-Origin: *" .. self.CRLF
+      .. "Content-Type: application/x-thrift" .. self.CRLF
+      .. "Content-Length: " .. content_len .. self.CRLF
+      .. "Connection: Keep-Alive" .. self.CRLF .. self.CRLF
+    self.trans:write(header)
+  else
+    local header = "POST " .. self.path .. " HTTP/1.1" .. self.CRLF
+      .. "Host: " .. self.trans.host .. self.CRLF
+      .. "Content-Type: application/x-thrift" .. self.CRLF
+      .. "Content-Length: " .. content_len .. self.CRLF
+      .. "Accept: application/x-thrift " .. self.CRLF
+      .. "User-Agent: Thrift/" .. self.VERSION .. " (Lua/THttpClient)"
+      .. self.CRLF .. self.CRLF
+    self.trans:write(header)
+  end
+end
+
+function THttpTransport:flush()
+  -- If the write fails we still want wBuf to be clear
+  local tmp = self.wBuf
+  self.wBuf = ''
+  self:writeHttpHeader(string.len(tmp))
+  self.trans:write(tmp)
+  self.trans:flush()
+end
+
+THttpTransportFactory = TTransportFactoryBase:new{
+  __type = 'THttpTransportFactory'
+}
+function THttpTransportFactory:getTransport(trans)
+  if not trans then
+    terror(TProtocolException:new{
+      message = 'Must supply a transport to ' .. ttype(self)
+    })
+  end
+  return THttpTransport:new{trans = trans}
+end

http://git-wip-us.apache.org/repos/asf/thrift/blob/e432c6b8/lib/lua/TServer.lua
----------------------------------------------------------------------
diff --git a/lib/lua/TServer.lua b/lib/lua/TServer.lua
index d6b9cd0..4e37d58 100644
--- a/lib/lua/TServer.lua
+++ b/lib/lua/TServer.lua
@@ -93,15 +93,16 @@ end
 
 function TServer:serve() end
 function TServer:handle(client)
-  local itrans, otrans, iprot, oprot, ret, err =
+  local itrans, otrans =
     self.inputTransportFactory:getTransport(client),
-    self.outputTransportFactory:getTransport(client),
-    self.inputProtocolFactory:getProtocol(client),
-    self.outputProtocolFactory:getProtocol(client)
+    self.outputTransportFactory:getTransport(client)
+  local iprot, oprot =
+    self.inputProtocolFactory:getProtocol(itrans),
+    self.outputProtocolFactory:getProtocol(otrans)
 
   self:_clientBegin(iprot, oprot)
   while true do
-    ret, err = pcall(self.processor.process, self.processor, iprot, oprot)
+    local ret, err = pcall(self.processor.process, self.processor, iprot, oprot)
     if ret == false and err then
       if not string.find(err, "TTransportException") then
         self:_handleException(err)

http://git-wip-us.apache.org/repos/asf/thrift/blob/e432c6b8/test/lua/test_basic_client.lua
----------------------------------------------------------------------
diff --git a/test/lua/test_basic_client.lua b/test/lua/test_basic_client.lua
index fea426d..77d8d07 100644
--- a/test/lua/test_basic_client.lua
+++ b/test/lua/test_basic_client.lua
@@ -19,6 +19,7 @@
 require('TSocket')
 require('TBufferedTransport')
 require('TFramedTransport')
+require('THttpTransport')
 require('TCompactProtocol')
 require('TJsonProtocol')
 require('TBinaryProtocol')
@@ -65,10 +66,12 @@ function testBasicClient(rawArgs)
   local transports = {
     buffered = TBufferedTransport,
     framed = TFramedTransport,
+    http = THttpTransport,
   }
   assert(transports[opt.transport] ~= nil)
   local transport = transports[opt.transport]:new{
-    trans = socket
+    trans = socket,
+    isServer = false
   }
 
   local protocols = {

http://git-wip-us.apache.org/repos/asf/thrift/blob/e432c6b8/test/lua/test_basic_server.lua
----------------------------------------------------------------------
diff --git a/test/lua/test_basic_server.lua b/test/lua/test_basic_server.lua
index 864b63d..acd2d79 100644
--- a/test/lua/test_basic_server.lua
+++ b/test/lua/test_basic_server.lua
@@ -19,6 +19,7 @@ require('ThriftTest_ThriftTest')
 require('TSocket')
 require('TBufferedTransport')
 require('TFramedTransport')
+require('THttpTransport')
 require('TCompactProtocol')
 require('TJsonProtocol')
 require('TBinaryProtocol')
@@ -111,6 +112,7 @@ function testBasicServer(rawArgs)
   local transports = {
     buffered = TBufferedTransportFactory,
     framed = TFramedTransportFactory,
+    http = THttpTransportFactory,
   }
   assert(transports[opt.transport], 'Failed to create framed transport factory')
   local trans_factory = transports[opt.transport]:new{}

http://git-wip-us.apache.org/repos/asf/thrift/blob/e432c6b8/test/tests.json
----------------------------------------------------------------------
diff --git a/test/tests.json b/test/tests.json
index c9f357a..3938c57 100644
--- a/test/tests.json
+++ b/test/tests.json
@@ -523,7 +523,8 @@
       "timeout": 5,
       "transports": [
         "buffered",
-        "framed"
+        "framed",
+        "http"
       ],
       "sockets": [
         "ip"