moonbridge

changeset 165:00f01d945e13

Work on new HTTP module implementation
author jbe
date Sat Jun 13 18:02:57 2015 +0200 (2015-06-13)
parents 27dc025e76cc
children 41a44ae5c293
files moonbridge_http.lua
line diff
     1.1 --- a/moonbridge_http.lua	Sat Jun 13 00:55:01 2015 +0200
     1.2 +++ b/moonbridge_http.lua	Sat Jun 13 18:02:57 2015 +0200
     1.3 @@ -188,8 +188,97 @@
     1.4      repeat
     1.5        -- create a new request object:
     1.6        local request = {
     1.7 +        -- allow access to underlying socket:
     1.8          socket = socket,
     1.9 -        cookies = {}
    1.10 +        -- cookies are simply stored in a table:
    1.11 +        cookies = {},
    1.12 +        -- table mapping header field names to value-lists
    1.13 +        -- (raw access, but case-insensitive):
    1.14 +        headers = setmetatable({}, {
    1.15 +          __index = function(self, key)
    1.16 +            local lowerkey = string.lower(key)
    1.17 +            if lowerkey == key then
    1.18 +              return
    1.19 +            end
    1.20 +            local result = rawget(self, lowerkey)
    1.21 +            if result == nil then
    1.22 +              result = {}
    1.23 +            end
    1.24 +            self[lowerkey] = result
    1.25 +            self[key] = result
    1.26 +            return result
    1.27 +          end
    1.28 +        }),
    1.29 +        -- table mapping header field names to value-lists
    1.30 +        -- (for headers with comma separated values):
    1.31 +        headers_csv_table = setmetatable({}, {
    1.32 +          __index = function(self, key)
    1.33 +            local result = {}
    1.34 +            for i, line in ipairs(request.headers[key]) do
    1.35 +              for entry in string.gmatch(line, "[^,]+") do
    1.36 +                local value = string.match(entry, "^[ \t]*(..-)[ \t]*$")
    1.37 +                if value then
    1.38 +                  result[#result+1] = value
    1.39 +                end
    1.40 +              end
    1.41 +            end
    1.42 +            self[key] = result
    1.43 +            return result
    1.44 +          end
    1.45 +        }),
    1.46 +        -- table mapping header field names to a comma separated string
    1.47 +        -- (for headers with comma separated values):
    1.48 +        headers_csv_string = setmetatable({}, {
    1.49 +          __index = function(self, key)
    1.50 +            local result = {}
    1.51 +            for i, line in ipairs(request.headers[key]) do
    1.52 +              result[#result+1] = line
    1.53 +            end
    1.54 +            result = string.concat(result, ", ")
    1.55 +            self[key] = result
    1.56 +            return result
    1.57 +          end
    1.58 +        }),
    1.59 +        -- table mapping header field names to a single string value
    1.60 +        -- (or false if header has been sent multiple times):
    1.61 +        headers_value = setmetatable({}, {
    1.62 +          __index = function(self, key)
    1.63 +            if headers_value_nil[key] then
    1.64 +              return nil
    1.65 +            end
    1.66 +            local result = nil
    1.67 +            local values = request.headers_csv_table[key]
    1.68 +            if #values == 0 then
    1.69 +              headers_value_nil[key] = true
    1.70 +            elseif #values == 1 then
    1.71 +              result = values[1]
    1.72 +            else
    1.73 +              result = false
    1.74 +            end
    1.75 +            self[key] = result
    1.76 +            return result
    1.77 +          end
    1.78 +        }),
    1.79 +        -- table mapping header field names to a flag table,
    1.80 +        -- indicating if the comma separated value contains certain entries:
    1.81 +        headers_flags = setmetatable({}, {
    1.82 +          __index = function(self, key)
    1.83 +            local result = setmetatable({}, {
    1.84 +              __index = function(self, key)
    1.85 +                local lowerkey = string.lower(key)
    1.86 +                local result = rawget(self, lowerkey) or false
    1.87 +                self[lowerkey] = result
    1.88 +                self[key] = result
    1.89 +                return result
    1.90 +              end
    1.91 +            })
    1.92 +            for i, value in ipairs(request.headers_csv_table[key]) do
    1.93 +              result[string.lower(value)] = true
    1.94 +            end
    1.95 +            self[key] = result
    1.96 +            return result
    1.97 +          end
    1.98 +        })
    1.99        }
   1.100        -- local variables to track the state:
   1.101        local state = "init"        -- one of:
   1.102 @@ -434,6 +523,39 @@
   1.103            send_chunk()
   1.104          end
   1.105        end
   1.106 +      -- method to flush output buffer:
   1.107 +      function request:flush()
   1.108 +        assert_not_faulty()
   1.109 +        send_chunk()
   1.110 +        send_flush()
   1.111 +      end
   1.112 +      -- method to finish response:
   1.113 +      function request:finish()
   1.114 +        assert_not_faulty()
   1.115 +        if state == "finished" then
   1.116 +          return
   1.117 +        elseif state == "info_status_sent" then
   1.118 +          error("Informational HTTP response can be finished with :finish_headers() method")
   1.119 +        end
   1.120 +        finish_headers(false)
   1.121 +        if state == "headers_sent" then
   1.122 +          if request.method ~= "HEAD" then
   1.123 +            state = "faulty"
   1.124 +            if content_length then
   1.125 +              if bytes_sent ~= content_length then
   1.126 +                error("Content length not used")
   1.127 +              end
   1.128 +            else
   1.129 +              send_chunk()
   1.130 +              send("0\r\n\r\n")
   1.131 +            end
   1.132 +            finish()
   1.133 +          end
   1.134 +          state = "finished"
   1.135 +        elseif state ~= "finished" then
   1.136 +          error("Unexpected internal status in HTTP engine")
   1.137 +        end
   1.138 +      end
   1.139        -- function to report an error:
   1.140        local function request_error(throw_error, status, text)
   1.141          local errmsg = "Error while reading request from client. Error response: " .. status

Impressum / About Us