@@ -68,6 +68,32 @@ function _M.check_schema(conf)
6868 return core .schema .check (schema , conf )
6969end
7070
71+ local function exit (ctx , status )
72+ ctx .grpc_web_skip_body_filter = true
73+ return status
74+ end
75+
76+ local build_trailer = function (grpc_status , grpc_message )
77+ local status_str = " grpc-status:" .. grpc_status
78+ local status_msg = " grpc-message:" .. ( grpc_message or " " )
79+ local grpc_web_trailer = status_str .. " \r\n " .. status_msg .. " \r\n "
80+ local len = # grpc_web_trailer
81+
82+ -- 1 byte: 0x80
83+ local trailer_buf = string.char (0x80 )
84+ -- 4 bytes: length of the trailer
85+ trailer_buf = trailer_buf .. string.char (
86+ bit .band (bit .rshift (len , 24 ), 0xff ),
87+ bit .band (bit .rshift (len , 16 ), 0xff ),
88+ bit .band (bit .rshift (len , 8 ), 0xff ),
89+ bit .band (len , 0xff )
90+ )
91+ -- n bytes: trailer
92+ trailer_buf = trailer_buf .. grpc_web_trailer
93+
94+ return trailer_buf
95+ end
96+
7197function _M .access (conf , ctx )
7298 -- set context variable mime
7399 -- When processing non gRPC Web requests, `mime` can be obtained in the context
@@ -76,19 +102,19 @@ function _M.access(conf, ctx)
76102
77103 local method = core .request .get_method ()
78104 if method == ALLOW_METHOD_OPTIONS then
79- return 204
105+ return exit ( ctx , 204 )
80106 end
81107
82108 if method ~= ALLOW_METHOD_POST then
83109 -- https://github.com/grpc/grpc-web/blob/master/doc/browser-features.md#cors-support
84110 core .log .error (" request method: `" , method , " ` invalid" )
85- return 400
111+ return exit ( ctx , 405 )
86112 end
87113
88114 local encoding = grpc_web_content_encoding [ctx .grpc_web_mime ]
89115 if not encoding then
90116 core .log .error (" request Content-Type: `" , ctx .grpc_web_mime , " ` invalid" )
91- return 400
117+ return exit ( ctx , 400 )
92118 end
93119
94120 -- set context variable encoding method
@@ -98,7 +124,7 @@ function _M.access(conf, ctx)
98124 if not (ctx .curr_req_matched and ctx .curr_req_matched [" :ext" ]) then
99125 core .log .error (" routing configuration error, grpc-web plugin only supports " ,
100126 " `prefix matching` pattern routing" )
101- return 400
127+ return exit ( ctx , 400 )
102128 end
103129
104130 local path = ctx .curr_req_matched [" :ext" ]
@@ -110,16 +136,17 @@ function _M.access(conf, ctx)
110136
111137 -- set grpc body
112138 local body , err = core .request .get_body ()
113- if err then
139+ if err or not body then
114140 core .log .error (" failed to read request body, err: " , err )
115- return 400
141+ return exit ( ctx , 400 )
116142 end
117143
118144 if encoding == CONTENT_ENCODING_BASE64 then
119145 body = decode_base64 (body )
146+ ngx .log (ngx .WARN , " DECODE BODY: " , body )
120147 if not body then
121148 core .log .error (" failed to decode request body" )
122- return 400
149+ return exit ( ctx , 400 )
123150 end
124151 end
125152
@@ -139,11 +166,19 @@ function _M.header_filter(conf, ctx)
139166 if not ctx .cors_allow_origins then
140167 core .response .set_header (" Access-Control-Allow-Origin" , DEFAULT_CORS_ALLOW_ORIGIN )
141168 end
142- core .response .set_header (" Content-Type" , ctx .grpc_web_mime )
143169 core .response .set_header (" Access-Control-Expose-Headers" , DEFAULT_CORS_EXPOSE_HEADERS )
170+
171+ if not ctx .grpc_web_skip_body_filter then
172+ core .response .set_header (" Content-Type" , ctx .grpc_web_mime )
173+ core .response .set_header (" Content-Length" , nil )
174+ end
144175end
145176
146177function _M .body_filter (conf , ctx )
178+ if ctx .grpc_web_skip_body_filter then
179+ return
180+ end
181+
147182 -- If the MIME extension type description of the gRPC-Web standard is not obtained,
148183 -- indicating that the request is not based on the gRPC Web specification,
149184 -- the processing of the request body will be ignored
@@ -176,46 +211,17 @@ function _M.body_filter(conf, ctx)
176211 local status = ctx .var .upstream_trailer_grpc_status
177212 local message = ctx .var .upstream_trailer_grpc_message
178213
179- local build_trailer = function (grpc_status , grpc_message )
180- local status_str = " grpc-status:" .. grpc_status
181- local status_msg = " grpc-message:" .. ( grpc_message or " " )
182- local grpc_web_trailer = status_str .. " \r\n " .. status_msg .. " \r\n "
183- local len = # grpc_web_trailer
184-
185- -- 1 byte: 0x80
186- local trailer_buf = string.char (0x80 )
187- -- 4 bytes: length of the trailer
188- trailer_buf = trailer_buf .. string.char (
189- bit .band (bit .rshift (len , 24 ), 0xff ),
190- bit .band (bit .rshift (len , 16 ), 0xff ),
191- bit .band (bit .rshift (len , 8 ), 0xff ),
192- bit .band (len , 0xff )
193- )
194- -- n bytes: trailer
195- trailer_buf = trailer_buf .. grpc_web_trailer
196-
197- return trailer_buf
198- end
199-
200- local attach_trailer = function (trailer_buf )
201- if ctx .grpc_web_encoding == CONTENT_ENCODING_BINARY then
202- ngx_arg [1 ] = ngx_arg [1 ] .. trailer_buf
203- else
204- ngx_arg [1 ] = ngx_arg [1 ] .. encode_base64 (trailer_buf )
205- end
206-
207- -- clear trailer
208- ctx .var .upstream_trailer_grpc_status = nil
209- ctx .var .upstream_trailer_grpc_message = nil
210- end
211-
212214 -- When the response body completes and still does not receive the grpc status
213- if status == nil or status == " " then
214- core .log .error (" upstream grpc status not received" )
215- attach_trailer (build_trailer (2 , " upstream grpc status not received" ))
216- else
217- attach_trailer (build_trailer (status , message ))
215+ local resp_ok = status ~= nil and status ~= " "
216+ local trailer_buf = build_trailer (
217+ resp_ok and status or 2 ,
218+ resp_ok and message or " upstream grpc status not received"
219+ )
220+ if ctx .grpc_web_encoding == CONTENT_ENCODING_BASE64 then
221+ trailer_buf = encode_base64 (trailer_buf )
218222 end
223+
224+ ngx_arg [1 ] = ngx_arg [1 ] .. trailer_buf
219225 end
220226end
221227
0 commit comments