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@194
|
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@125
|
18 --{ proto = "tcp", host = "0.0.0.0", port = 8080 },
|
jbe@0
|
19
|
jbe@0
|
20 -- listen to a tcp version 6 socket
|
jbe@125
|
21 { proto = "tcp", host = "::", port = 8080},
|
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
|
bsw@121
|
33 min_fork = 4, -- 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@222
|
62 request_header_size_limit = 1024*1024, -- maximum size of request headers
|
jbe@222
|
63 request_body_size_limit = 16*1024*1024*1024, -- allow big file uploads
|
jbe@227
|
64 idle_timeout = 65, -- maximum time until receiving the first byte of the request headera
|
jbe@227
|
65 stall_timeout = 60, -- maximum time a client connection may be stalled
|
jbe@227
|
66 request_header_timeout = 120, -- maximum time until receiving the remaining bytes of the request header
|
jbe@227
|
67 response_timeout = 3600, -- time in which request body and response must be sent
|
jbe@227
|
68 maximum_input_chunk_size = 16384, -- tweaks behavior of request-body parser
|
jbe@227
|
69 minimum_output_chunk_size = 1024 -- chunk size for chunked-transfer-encoding
|
jbe@0
|
70 },
|
jbe@0
|
71 function(request)
|
jbe@0
|
72
|
jbe@33
|
73 local function error_response(status)
|
jbe@33
|
74 request:send_status(status)
|
jbe@33
|
75 request:send_header("Content-Type", "text/html")
|
jbe@33
|
76 request:send_data("<html>\n<head><title>", status, "</title></head>\n<body><h1>", status, "</h1></body>\n</html>\n")
|
jbe@33
|
77 request:finish()
|
jbe@23
|
78 end
|
jbe@23
|
79
|
jbe@0
|
80 if request.method == "GET" or request.method == "HEAD" then
|
jbe@0
|
81
|
jbe@10
|
82 if request.path == "" then
|
jbe@0
|
83 request:send_status("303 See Other")
|
jbe@0
|
84 request:send_header("Location", "http://" .. request.headers_value.host .. "/example_webpage.html")
|
jbe@0
|
85
|
jbe@0
|
86 else
|
jbe@10
|
87 local document_name = request.path
|
jbe@0
|
88 local document_extension = string.match(document_name, "%.([^.])$")
|
jbe@26
|
89 local document = documents[document_name] -- loads file contents from memory
|
jbe@0
|
90 if document then
|
jbe@0
|
91 request:send_status("200 OK")
|
jbe@0
|
92 if document_extension == "html" then
|
jbe@0
|
93 request:send_header("Content-Type", "text/html; charset=UTF-8")
|
jbe@0
|
94 elseif document_extension == "css" then
|
jbe@0
|
95 request:send_header("Content-Type", "text/css; charset=UTF-8")
|
jbe@0
|
96 end
|
jbe@0
|
97 request:send_data(document)
|
jbe@0
|
98 else
|
jbe@33
|
99 error_response("404 Not Found")
|
jbe@0
|
100 end
|
jbe@0
|
101
|
jbe@0
|
102 end
|
jbe@0
|
103
|
jbe@0
|
104 elseif request.method == "POST" then
|
jbe@0
|
105
|
jbe@10
|
106 if request.path == "post_example" then
|
jbe@0
|
107 local files = {}
|
jbe@0
|
108 do
|
jbe@0
|
109 local file
|
jbe@0
|
110 request:stream_post_param("files", function(chunk, field_name, meta)
|
jbe@0
|
111 if meta then
|
jbe@0
|
112 file = {
|
jbe@0
|
113 file_name = meta.file_name,
|
jbe@0
|
114 content_type = meta.content_type,
|
jbe@0
|
115 length = 0
|
jbe@0
|
116 }
|
jbe@0
|
117 end
|
jbe@0
|
118 if chunk then
|
jbe@0
|
119 file.length = file.length + #chunk
|
jbe@0
|
120 else
|
jbe@0
|
121 files[#files+1] = file
|
jbe@0
|
122 end
|
jbe@0
|
123 end)
|
jbe@0
|
124 end
|
jbe@0
|
125
|
jbe@0
|
126 request:send_status("200 OK")
|
jbe@194
|
127 request:send_header("Content-Type", "text/html; charset=UTF-8")
|
jbe@0
|
128 request:send_data("<html>\n<head>\n")
|
jbe@0
|
129 request:send_data('<link href="example_webpage.css" rel="stylesheet" type="text/css">\n')
|
jbe@0
|
130 request:send_data("<title>Moonbridge Network Server for Lua Applications – Example Application</title>\n")
|
jbe@0
|
131 request:send_data("</head>\n<body>\n")
|
jbe@0
|
132 request:send_data("<h1>Moonbridge Network Server for Lua – Example Application</h1>\n")
|
jbe@0
|
133 request:send_data("<h2>POST request successful</h2>\n")
|
jbe@0
|
134 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@192
|
135 request:consume_input()
|
jbe@0
|
136 for i, file in ipairs(files) do
|
jbe@0
|
137 request:send_data("<tr>")
|
jbe@0
|
138 request:send_data("<td>", http.encode_html(file.file_name or "(unknown)"), "</td>")
|
jbe@0
|
139 request:send_data("<td>", http.encode_html(file.content_type or "(unknown)"), "</td>")
|
jbe@0
|
140 request:send_data('<td class="numeric">', http.encode_html(tostring(file.length)), "</td>")
|
jbe@0
|
141 request:send_data("</tr>\n")
|
jbe@0
|
142 end
|
jbe@0
|
143 request:send_data("</tbody>\n</table>\n")
|
jbe@0
|
144 request:send_data("<p>Submitted comment: ", http.encode_html(request.post_params.comment), "</p>\n")
|
jbe@0
|
145 request:send_data("</body>\n</html>\n")
|
jbe@0
|
146
|
jbe@0
|
147 else
|
jbe@33
|
148 error_response("404 Not Found")
|
jbe@0
|
149
|
jbe@23
|
150 end
|
jbe@0
|
151
|
jbe@0
|
152 else
|
jbe@33
|
153 error_response("405 Method not allowed")
|
jbe@0
|
154
|
jbe@0
|
155 end
|
jbe@0
|
156
|
jbe@0
|
157 -- returning false causes termination of current process (and re-forking)
|
jbe@0
|
158 return true
|
jbe@0
|
159 end),
|
jbe@0
|
160
|
jbe@0
|
161 -- executed on process termination
|
jbe@0
|
162 finish = function()
|
jbe@26
|
163 -- e.g. close database connection
|
jbe@0
|
164 end
|
jbe@0
|
165 }
|
jbe@0
|
166
|