@@ -16,7 +16,7 @@ local errno = require 'errno'
16
16
local DETACHED = 101
17
17
18
18
local function errorf (fmt , ...)
19
- error (string.format (fmt , ... ))
19
+ error (string.format (fmt , ... ), 3 )
20
20
end
21
21
22
22
local function sprintf (fmt , ...)
@@ -35,6 +35,18 @@ local function is_callable(obj)
35
35
return false
36
36
end
37
37
38
+ local function is_callable (obj )
39
+ local t_obj = type (obj )
40
+ if t_obj == ' function' then
41
+ return true
42
+ end
43
+ if t_obj == ' table' then
44
+ local mt = getmetatable (obj )
45
+ return (type (mt ) == ' table' and type (mt .__call ) == ' function' )
46
+ end
47
+ return false
48
+ end
49
+
38
50
local function uri_escape (str )
39
51
local res = {}
40
52
if type (str ) == ' table' then
@@ -930,7 +942,7 @@ local function url_for_httpd(httpd, name, args, query)
930
942
end
931
943
end
932
944
933
- local function httpd_http11_parse_request ( session , request_raw )
945
+ local function httpd_parse_request ( request_raw )
934
946
local request_parsed = lib ._parse_request (request_raw )
935
947
if request_parsed .error then
936
948
return nil , request_parsed .error
@@ -940,6 +952,14 @@ local function httpd_http11_parse_request(session, request_raw)
940
952
request_parsed .path :find (" ./" , nil , true ) ~= nil then
941
953
return nil , " invalid uri"
942
954
end
955
+ return request_parsed
956
+ end
957
+
958
+ local function httpd_http11_parse_request (session , request_raw )
959
+ local request_parsed , err = httpd_parse_request (request_raw )
960
+ if not request_parsed then
961
+ return nil , err
962
+ end
943
963
request_parsed .httpd = session .server
944
964
request_parsed .s = session .socket
945
965
request_parsed .peer = session .peer
@@ -976,6 +996,30 @@ local function httpd_http11_handler(session)
976
996
return
977
997
end
978
998
999
+ if p .headers [' upgrade' ] then
1000
+ local proto_name = p .headers [' upgrade' ]:lower ()
1001
+ local proto = session .server .upgrades [proto_name ]
1002
+ if not proto then
1003
+ session :write (' HTTP/1.1 400 Bad Request\r\n\r\n ' )
1004
+ return false
1005
+ else
1006
+ local ok , upgrade_ok = pcall (proto .upgrade , session , p )
1007
+ if not ok then
1008
+ log .error (" Failed to upgrade to '%s': %s" , p .headers [' upgrade' ],
1009
+ upgrade_ok )
1010
+ session :write (' HTTP/1.1 500 Internal Error\r\n\r\n ' )
1011
+ return false
1012
+ elseif not upgrade_ok then
1013
+ -- TODO: should we close connection, or we should retry again
1014
+ return false
1015
+ end
1016
+
1017
+ session .ctx .proto = proto .name
1018
+ session .ctx .handler = proto .handler
1019
+ return true
1020
+ end
1021
+ end
1022
+
979
1023
if p .headers [' expect' ] == ' 100-continue' then
980
1024
session :write (' HTTP/1.1 100 Continue\r\n\r\n ' )
981
1025
elseif p .headers [' expect' ] then
@@ -1180,14 +1224,36 @@ local function httpd_start(self)
1180
1224
return self
1181
1225
end
1182
1226
1227
+ local function httpd_register_extension (self , ext_type , opts )
1228
+ if ext_type :lower () == ' upgrade' then
1229
+ if not (type (opts ) == ' table' ) then
1230
+ errorf (" Upgrade extension argument should be table" )
1231
+ end
1232
+ if not (type (opts .name ) == ' string' ) then
1233
+ errorf (" Upgrade extension name should be %s" , ' options.name' , ' string' )
1234
+ end
1235
+ if not is_callable (opts .upgrade ) then
1236
+ errorf (" Upgrade extension callback should be callable" )
1237
+ end
1238
+ if not is_callable (opts .handler ) then
1239
+ errorf (" Upgrade extension handler should be callable" )
1240
+ end
1241
+
1242
+ self .upgrades [opts .name :lower ()] = table .copy (opts )
1243
+ else
1244
+ errorf (' Unknown extension type: %s' , ext_type )
1245
+ end
1246
+ end
1247
+
1183
1248
local httpd_methods = {
1184
- stop = httpd_stop ,
1185
- start = httpd_start ,
1186
- route = add_route ,
1187
- match = match_route ,
1188
- helper = set_helper ,
1189
- hook = set_hook ,
1190
- url_for = url_for_httpd ,
1249
+ stop = httpd_stop ,
1250
+ start = httpd_start ,
1251
+ route = add_route ,
1252
+ match = match_route ,
1253
+ helper = set_helper ,
1254
+ hook = set_hook ,
1255
+ url_for = url_for_httpd ,
1256
+ register_extension = httpd_register_extension ,
1191
1257
}
1192
1258
1193
1259
local httpd_mt = {
@@ -1223,10 +1289,11 @@ local function httpd_new(host, port, options)
1223
1289
is_run = false ,
1224
1290
options = options ,
1225
1291
1226
- routes = { },
1227
- iroutes = { },
1228
- helpers = { url_for = url_for_helper , },
1229
- hooks = { },
1292
+ routes = { },
1293
+ iroutes = { },
1294
+ helpers = { url_for = url_for_helper , },
1295
+ hooks = { },
1296
+ upgrades = { },
1230
1297
1231
1298
-- caches
1232
1299
cache = { tpl = {}, ctx = {}, static = {}, },
@@ -1236,6 +1303,9 @@ local function httpd_new(host, port, options)
1236
1303
end
1237
1304
1238
1305
return {
1239
- DETACHED = DETACHED ,
1240
- new = httpd_new
1306
+ DETACHED = DETACHED ,
1307
+ new = httpd_new ,
1308
+ parse_headers = httpd_parse_request ,
1309
+ uri_escape = uri_escape ,
1310
+ uri_unescape = uri_unescape ,
1241
1311
}
0 commit comments