Skip to content

Instantly share code, notes, and snippets.

@vane
Last active November 7, 2023 22:47
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save vane/1249e8cf8a8e5532af26a6c33df35c9f to your computer and use it in GitHub Desktop.
Save vane/1249e8cf8a8e5532af26a6c33df35c9f to your computer and use it in GitHub Desktop.
openresty call script read stdout and return as response
-- test.py - set absolute path
-- functions
local function write_error(data)
ngx.status = 500
ngx.say('<h1>CGI response error</h1>')
ngx.say(data)
ngx.exit(ngx.OK)
end
local function write_body(headers, res)
local ss, ee = headers:find('([^&&]+)')
if ee == nil then
ngx.status = 404
ngx.say(res)
return ngx.exit(ngx.OK)
end
ngx.status = tonumber(headers:sub(ss, ee))
for header in headers:sub(ee+2):gmatch('([^&&]+)') do
local s, e = header:find('([^:]+)')
ngx.header[header:sub(s, e)] = header:sub(e+2)
end
local body = res:gsub('^\n?[^\n]*\n', '')
ngx.say(body)
ngx.exit(ngx.OK)
end
local function read_body()
ngx.req.read_body()
local raw_body = ngx.req.get_body_data()
if raw_body == nil then
local file = ngx.req.get_body_file()
if file == nil then
return ''
end
return file
end
-- if not content_type header starts with text then encode_base64
local content_type = ngx.req.get_headers().content_type
if content_type:find('text', 1, true) == 1 or content_type:find('application/json', 1, true) == 1 then
return raw_body:gsub('"', '\\\\"'):gsub("'", "\\\\'")
end
return ngx.encode_base64(raw_body)
end
-- logic
local raw_header = ngx.req.raw_header()
local raw_body = read_body()
-- todo read path and store executable in redis
local ps = io.popen("python3 test.py '" ..raw_header.. "' " ..raw_body)
local res = ps:read("*a")
ps:close()
if res == nil then
return write_error(res)
end
-- read headers - 200&&key1:value1&&key2:value2\n
local headers = res:match('([^\n]*)\n?')
if headers == nil then
return write_error(raw_header)
end
return write_body(headers, res)
server {
listen 443 ssl;
access_log /usr/local/openresty/nginx/logs/fn.example.com.log;
server_name fn.example.com;
ssl_certificate_by_lua_block {
auto_ssl:ssl_certificate();
}
ssl_certificate /etc/ssl/resty-auto-ssl-fallback.crt;
ssl_certificate_key /etc/ssl/resty-auto-ssl-fallback.key;
location / {
# set absolute path
content_by_lua_file cgi.lua;
}
}
#!/usr/bin/env python
# -*- coding: utf-8 -*-
import sys
import traceback
from http.server import BaseHTTPRequestHandler
from io import BytesIO
class Request(BaseHTTPRequestHandler):
def __init__(self, request_text):
self.rfile = BytesIO(request_text.encode('utf-8'))
self.raw_requestline = self.rfile.readline()
self.error_code = None
self.error_message = None
self.parse_request()
def send_error(self, code, message=None, explain=None):
self.error_code = code
self.error_message = message
def serve_image() -> None:
sys.stdout.buffer.write(b'200&&Content-Type:image/png\n')
with open('test.png', 'rb') as f:
sys.stdout.buffer.write(f.read())
def print_request(req: Request) -> None:
sys.stdout.buffer.write(b'404&&Content-Type:text/html&&custom:test\n')
print(f'''<html><body>
<div><h3>headers keys</h3><pre>{req.headers.keys()}</pre></div>
<div><h3>host</h3><pre>{req.headers.get('host')}</pre></div>
<div><h3>raw args</h3><pre>{sys.argv[1:]}</pre></div>
</html></body>''')
if __name__ == '__main__':
# write headers -- important !!! new line at end
req = Request(sys.argv[1])
try:
if req.path.startswith('/test.png'):
serve_image()
else:
print_request(req)
except:
sys.stdout.buffer.write(b'500&&Content-Type:text/html\n')
print('<div>problem<div>')
print(f'<div>{sys.argv[1:]}</div>')
print(f'<div><pre>{traceback.format_exc()}</pre></div>')
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment