rev |
line source |
jbe@0
|
1 -- Moonbridge example application
|
jbe@0
|
2 -- invoke with ./moonbridge example_application.lua
|
jbe@33
|
3 --
|
jbe@33
|
4 -- see helloworld.lua for a simpler example
|
jbe@0
|
5
|
jbe@4
|
6 local http = require "moonbridge_http"
|
jbe@0
|
7
|
jbe@26
|
8 -- preparation before forking:
|
jbe@13
|
9 local documents = {}
|
jbe@13
|
10 for i, document_name in ipairs{"example_webpage.html", "example_webpage.css"} do
|
jbe@15
|
11 local file = assert(io.open(document_name))
|
jbe@26
|
12 documents[document_name] = file:read("*a") -- store file contents in memory
|
jbe@13
|
13 file:close()
|
jbe@13
|
14 end
|
jbe@0
|
15
|
jbe@0
|
16 listen{
|
jbe@0
|
17 -- listen to a tcp version 4 socket
|
jbe@0
|
18 { proto = "tcp4", port = 8080, localhost = true },
|
jbe@0
|
19
|
jbe@0
|
20 -- listen to a tcp version 6 socket
|
jbe@0
|
21 { proto = "tcp6", port = 8080, localhost = true },
|
jbe@0
|
22
|
jbe@0
|
23 -- listen to a unix domain socket
|
jbe@0
|
24 --{ proto = "local", path = 'socket' },
|
jbe@0
|
25
|
jbe@0
|
26 -- execute the listener regularly (without incoming connection)
|
jbe@0
|
27 --{ proto = "interval", name = "myint", delay = 10, strict = false },
|
jbe@0
|
28
|
jbe@0
|
29 -- desired number of spare (idle) processes
|
jbe@0
|
30 pre_fork = 1, -- number of forks
|
jbe@0
|
31
|
jbe@0
|
32 -- minimum number of processes
|
jbe@0
|
33 min_fork = 2, -- number of forks
|
jbe@0
|
34
|
jbe@0
|
35 -- maximum number of processes (hard limit)
|
jbe@0
|
36 max_fork = 16, -- number of forks
|
jbe@0
|
37
|
jbe@0
|
38 -- delay between creation of spare processes
|
jbe@61
|
39 fork_delay = 0.25, -- seconds
|
jbe@0
|
40
|
jbe@0
|
41 -- delay before retry of failed process creation
|
jbe@0
|
42 fork_error_delay = 2, -- seconds
|
jbe@0
|
43
|
jbe@0
|
44 -- delay between destruction of excessive spare processes
|
jbe@0
|
45 exit_delay = 60, -- seconds
|
jbe@0
|
46
|
jbe@0
|
47 -- idle time after a fork gets terminated
|
jbe@0
|
48 idle_timeout = 0, -- seconds (0 for no timeout)
|
jbe@0
|
49
|
jbe@0
|
50 -- maximum memory consumption before process gets terminated
|
jbe@23
|
51 --memory_limit = 1024*1024, -- bytes
|
jbe@0
|
52
|
jbe@11
|
53 -- preparation of process (executed after fork)
|
jbe@0
|
54 prepare = function()
|
jbe@26
|
55 -- e.g. open database connection
|
jbe@0
|
56 end,
|
jbe@0
|
57
|
jbe@0
|
58 -- connection handler
|
jbe@0
|
59 connect = http.generate_handler(
|
jbe@0
|
60 {
|
jbe@0
|
61 static_headers = {"Server: Moonbridge Example Server"},
|
jbe@54
|
62 request_body_size_limit = 16*1024*1024*1024, -- allow big file uploads
|
jbe@54
|
63 request_header_timeout = 360, -- request headers must be sent within 6 minutes (if nil, defaults to timeout below)
|
jbe@54
|
64 timeout = 1800 -- request body and response must be sent within 30 minutes
|
jbe@0
|
65 },
|
jbe@0
|
66 function(request)
|
jbe@0
|
67
|
jbe@33
|
68 local function error_response(status)
|
jbe@33
|
69 request:send_status(status)
|
jbe@33
|
70 request:send_header("Content-Type", "text/html")
|
jbe@33
|
71 request:send_data("<html>\n<head><title>", status, "</title></head>\n<body><h1>", status, "</h1></body>\n</html>\n")
|
jbe@33
|
72 request:finish()
|
jbe@23
|
73 end
|
jbe@23
|
74
|
jbe@0
|
75 if request.method == "GET" or request.method == "HEAD" then
|
jbe@0
|
76
|
jbe@10
|
77 if request.path == "" then
|
jbe@0
|
78 request:send_status("303 See Other")
|
jbe@0
|
79 request:send_header("Location", "http://" .. request.headers_value.host .. "/example_webpage.html")
|
jbe@0
|
80
|
jbe@0
|
81 else
|
jbe@10
|
82 local document_name = request.path
|
jbe@0
|
83 local document_extension = string.match(document_name, "%.([^.])$")
|
jbe@26
|
84 local document = documents[document_name] -- loads file contents from memory
|
jbe@0
|
85 if document then
|
jbe@0
|
86 request:send_status("200 OK")
|
jbe@0
|
87 if document_extension == "html" then
|
jbe@0
|
88 request:send_header("Content-Type", "text/html; charset=UTF-8")
|
jbe@0
|
89 elseif document_extension == "css" then
|
jbe@0
|
90 request:send_header("Content-Type", "text/css; charset=UTF-8")
|
jbe@0
|
91 end
|
jbe@0
|
92 request:send_data(document)
|
jbe@0
|
93 else
|
jbe@33
|
94 error_response("404 Not Found")
|
jbe@0
|
95 end
|
jbe@0
|
96
|
jbe@0
|
97 end
|
jbe@0
|
98
|
jbe@0
|
99 elseif request.method == "POST" then
|
jbe@0
|
100
|
jbe@10
|
101 if request.path == "post_example" then
|
jbe@0
|
102 local files = {}
|
jbe@0
|
103 do
|
jbe@0
|
104 local file
|
jbe@0
|
105 request:stream_post_param("files", function(chunk, field_name, meta)
|
jbe@0
|
106 if meta then
|
jbe@0
|
107 file = {
|
jbe@0
|
108 file_name = meta.file_name,
|
jbe@0
|
109 content_type = meta.content_type,
|
jbe@0
|
110 length = 0
|
jbe@0
|
111 }
|
jbe@0
|
112 end
|
jbe@0
|
113 if chunk then
|
jbe@0
|
114 file.length = file.length + #chunk
|
jbe@0
|
115 else
|
jbe@0
|
116 files[#files+1] = file
|
jbe@0
|
117 end
|
jbe@0
|
118 end)
|
jbe@0
|
119 end
|
jbe@0
|
120
|
jbe@0
|
121 request:send_status("200 OK")
|
jbe@0
|
122 request:send_header("Content-Type", "text/html; chatset=UTF-8")
|
jbe@0
|
123 request:send_data("<html>\n<head>\n")
|
jbe@0
|
124 request:send_data('<link href="example_webpage.css" rel="stylesheet" type="text/css">\n')
|
jbe@0
|
125 request:send_data("<title>Moonbridge Network Server for Lua Applications – Example Application</title>\n")
|
jbe@0
|
126 request:send_data("</head>\n<body>\n")
|
jbe@0
|
127 request:send_data("<h1>Moonbridge Network Server for Lua – Example Application</h1>\n")
|
jbe@0
|
128 request:send_data("<h2>POST request successful</h2>\n")
|
jbe@0
|
129 request:send_data('<table>\n<thead><th>File name</th><th>Content type</th><th class="numeric">Bytes received</th></thead>\n<tbody>\n')
|
jbe@0
|
130 for i, file in ipairs(files) do
|
jbe@0
|
131 request:send_data("<tr>")
|
jbe@0
|
132 request:send_data("<td>", http.encode_html(file.file_name or "(unknown)"), "</td>")
|
jbe@0
|
133 request:send_data("<td>", http.encode_html(file.content_type or "(unknown)"), "</td>")
|
jbe@0
|
134 request:send_data('<td class="numeric">', http.encode_html(tostring(file.length)), "</td>")
|
jbe@0
|
135 request:send_data("</tr>\n")
|
jbe@0
|
136 end
|
jbe@0
|
137 request:send_data("</tbody>\n</table>\n")
|
jbe@0
|
138 request:send_data("<p>Submitted comment: ", http.encode_html(request.post_params.comment), "</p>\n")
|
jbe@0
|
139 request:send_data("</body>\n</html>\n")
|
jbe@0
|
140
|
jbe@0
|
141 else
|
jbe@33
|
142 error_response("404 Not Found")
|
jbe@0
|
143
|
jbe@23
|
144 end
|
jbe@0
|
145
|
jbe@0
|
146 else
|
jbe@33
|
147 error_response("405 Method not allowed")
|
jbe@0
|
148
|
jbe@0
|
149 end
|
jbe@0
|
150
|
jbe@0
|
151 -- returning false causes termination of current process (and re-forking)
|
jbe@0
|
152 return true
|
jbe@0
|
153 end),
|
jbe@0
|
154
|
jbe@0
|
155 -- executed on process termination
|
jbe@0
|
156 finish = function()
|
jbe@26
|
157 -- e.g. close database connection
|
jbe@0
|
158 end
|
jbe@0
|
159 }
|
jbe@0
|
160
|