Skip to content

Commit 6738b02

Browse files
authored
feat: create/free HTTP ctx (#12)
1 parent 098caac commit 6738b02

File tree

6 files changed

+396
-20
lines changed

6 files changed

+396
-20
lines changed

.github/workflows/test.yml

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -18,8 +18,10 @@ jobs:
1818

1919
- name: Get dependencies
2020
run: |
21-
sudo apt install -y cpanminus build-essential libncurses5-dev libreadline-dev libssl-dev perl
22-
wget https://github.com/tinygo-org/tinygo/releases/download/v0.19.0/tinygo_0.19.0_amd64.deb
21+
sudo apt install -y cpanminus build-essential libncurses5-dev libreadline-dev libssl-dev perl luarocks
22+
sudo luarocks install lua-resty-http > build.log 2>&1 || (cat build.log && exit 1)
23+
24+
wget https://github.com/tinygo-org/tinygo/releases/download/v0.19.0/tinygo_0.19.0_amd64.deb 2>/dev/null
2325
sudo dpkg -i tinygo_0.19.0_amd64.deb
2426
2527
- name: Before install
@@ -35,6 +37,6 @@ jobs:
3537
3638
- name: Script
3739
run: |
38-
make build.all.testdata
40+
sudo make build.all.testdata
3941
export PATH=$OPENRESTY_PREFIX/nginx/sbin:$PATH
4042
prove -I. -Itest-nginx/lib -r t/

lib/resty/proxy-wasm.lua

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,11 @@
11
local ffi = require("ffi")
2+
local base = require("resty.core.base")
23
local ffi_gc = ffi.gc
34
local C = ffi.C
5+
local get_request = base.get_request
6+
7+
8+
base.allows_subsystem("http")
49

510

611
ffi.cdef[[
@@ -9,10 +14,12 @@ void *ngx_http_wasm_load_plugin(const char *code, size_t size);
914
void ngx_http_wasm_unload_plugin(void *plugin);
1015
void *ngx_http_wasm_on_configure(void *plugin, const char *conf, size_t size);
1116
void ngx_http_wasm_delete_plugin_ctx(void *hwp_ctx);
17+
ngx_int_t ngx_http_wasm_on_http(void *hwp_ctx, void *r, int type);
1218
]]
1319

1420

1521
local _M = {}
22+
local HTTP_REQUEST_HEADERS = 1
1623

1724

1825
function _M.load(path)
@@ -55,4 +62,23 @@ function _M.on_configure(plugin, conf)
5562
end
5663

5764

65+
function _M.on_http_request_headers(plugin_ctx)
66+
if type(plugin_ctx) ~= "cdata" then
67+
return nil, "bad plugin ctx"
68+
end
69+
70+
local r = get_request()
71+
if not r then
72+
return nil, "bad request"
73+
end
74+
75+
local rc = C.ngx_http_wasm_on_http(plugin_ctx, r, HTTP_REQUEST_HEADERS)
76+
if rc < 0 then
77+
return nil, "failed to run proxy_on_http_request_headers"
78+
end
79+
80+
return true
81+
end
82+
83+
5884
return _M

src/http/ngx_http_wasm_ctx.h

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
#ifndef NGX_HTTP_WASM_CTX_H
2+
#define NGX_HTTP_WASM_CTX_H
3+
4+
5+
#include <ngx_core.h>
6+
#include "ngx_http_wasm_state.h"
7+
8+
9+
typedef struct {
10+
void *plugin;
11+
uint32_t cur_ctx_id;
12+
ngx_queue_t occupied;
13+
ngx_queue_t free;
14+
unsigned done:1;
15+
} ngx_http_wasm_plugin_t;
16+
17+
18+
typedef struct {
19+
ngx_queue_t queue;
20+
uint32_t id;
21+
ngx_http_wasm_state_t *state;
22+
ngx_http_wasm_plugin_t *hw_plugin;
23+
ngx_pool_t *pool;
24+
ngx_queue_t occupied;
25+
ngx_queue_t free;
26+
unsigned done:1;
27+
} ngx_http_wasm_plugin_ctx_t;
28+
29+
30+
typedef struct {
31+
ngx_queue_t queue;
32+
uint32_t id;
33+
ngx_http_wasm_plugin_ctx_t *hwp_ctx;
34+
} ngx_http_wasm_http_ctx_t;
35+
36+
37+
typedef struct {
38+
ngx_http_wasm_http_ctx_t *http_ctx;
39+
} ngx_http_wasm_ctx_t;
40+
41+
42+
#endif // NGX_HTTP_WASM_CTX_H

src/http/ngx_http_wasm_module.c

Lines changed: 193 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
#include <ngx_core.h>
33
#include <ngx_http.h>
44
#include "ngx_http_wasm_state.h"
5+
#include "ngx_http_wasm_ctx.h"
56
#include "vm/vm.h"
67

78

@@ -26,22 +27,9 @@ typedef struct {
2627
} ngx_http_wasm_main_conf_t;
2728

2829

29-
typedef struct {
30-
void *plugin;
31-
uint32_t cur_ctx_id;
32-
ngx_queue_t occupied;
33-
ngx_queue_t free;
34-
unsigned done:1;
35-
} ngx_http_wasm_plugin_t;
36-
37-
38-
typedef struct {
39-
uint32_t id;
40-
ngx_http_wasm_state_t *state;
41-
ngx_http_wasm_plugin_t *hw_plugin;
42-
ngx_pool_t *pool;
43-
ngx_queue_t queue;
44-
} ngx_http_wasm_plugin_ctx_t;
30+
typedef enum {
31+
HTTP_REQUEST_HEADERS = 1,
32+
} ngx_http_wasm_phase_t;
4533

4634

4735
static ngx_command_t ngx_http_wasm_cmds[] = {
@@ -249,7 +237,7 @@ ngx_http_wasm_unload_plugin(ngx_http_wasm_plugin_t *hw_plugin)
249237

250238

251239
void
252-
ngx_http_wasm_delete_plugin_ctx(ngx_http_wasm_plugin_ctx_t *hwp_ctx)
240+
ngx_http_wasm_free_plugin_ctx(ngx_http_wasm_plugin_ctx_t *hwp_ctx)
253241
{
254242
ngx_int_t rc;
255243
uint32_t ctx_id = hwp_ctx->id;
@@ -259,6 +247,11 @@ ngx_http_wasm_delete_plugin_ctx(ngx_http_wasm_plugin_ctx_t *hwp_ctx)
259247

260248
log = ngx_cycle->log;
261249

250+
if (!ngx_queue_empty(&hwp_ctx->occupied)) {
251+
/* some http ctxs are using it. Do not free */
252+
return;
253+
}
254+
262255
ngx_queue_remove(&hwp_ctx->queue);
263256
ngx_queue_insert_head(&hw_plugin->free, &hwp_ctx->queue);
264257

@@ -279,12 +272,22 @@ ngx_http_wasm_delete_plugin_ctx(ngx_http_wasm_plugin_ctx_t *hwp_ctx)
279272
hwp_ctx->pool = NULL;
280273
}
281274

275+
ngx_log_error(NGX_LOG_INFO, log, 0, "free plugin context %d", ctx_id);
276+
282277
if (hw_plugin->done) {
283278
ngx_http_wasm_free_plugin(hw_plugin);
284279
}
285280
}
286281

287282

283+
void
284+
ngx_http_wasm_delete_plugin_ctx(ngx_http_wasm_plugin_ctx_t *hwp_ctx)
285+
{
286+
hwp_ctx->done = 1;
287+
ngx_http_wasm_free_plugin_ctx(hwp_ctx);
288+
}
289+
290+
288291
void *
289292
ngx_http_wasm_on_configure(ngx_http_wasm_plugin_t *hw_plugin, const char *conf, size_t size)
290293
{
@@ -320,6 +323,8 @@ ngx_http_wasm_on_configure(ngx_http_wasm_plugin_t *hw_plugin, const char *conf,
320323
ctx_id = hw_plugin->cur_ctx_id;
321324
hwp_ctx->id = ctx_id;
322325
hwp_ctx->hw_plugin = hw_plugin;
326+
ngx_queue_init(&hwp_ctx->occupied);
327+
ngx_queue_init(&hwp_ctx->free);
323328
}
324329

325330
rc = ngx_wasm_vm.call(plugin, &proxy_on_context_create, false,
@@ -369,3 +374,174 @@ ngx_http_wasm_on_configure(ngx_http_wasm_plugin_t *hw_plugin, const char *conf,
369374
ngx_http_wasm_delete_plugin_ctx(hwp_ctx);
370375
return NULL;
371376
}
377+
378+
379+
ngx_http_wasm_http_ctx_t *
380+
ngx_http_wasm_create_http_ctx(ngx_http_wasm_plugin_ctx_t *hwp_ctx, ngx_http_request_t *r)
381+
{
382+
ngx_int_t rc;
383+
uint32_t ctx_id;
384+
ngx_http_wasm_http_ctx_t *http_ctx;
385+
ngx_http_wasm_plugin_t *hw_plugin = hwp_ctx->hw_plugin;
386+
void *plugin = hw_plugin->plugin;
387+
ngx_log_t *log;
388+
389+
log = r->connection->log;
390+
391+
if (!ngx_queue_empty(&hwp_ctx->free)) {
392+
ngx_queue_t *q;
393+
394+
q = ngx_queue_last(&hwp_ctx->free);
395+
ngx_queue_remove(q);
396+
http_ctx = ngx_queue_data(q, ngx_http_wasm_http_ctx_t, queue);
397+
ctx_id = http_ctx->id;
398+
399+
} else {
400+
http_ctx = ngx_pcalloc(hwp_ctx->pool, sizeof(ngx_http_wasm_http_ctx_t));
401+
if (http_ctx == NULL) {
402+
ngx_log_error(NGX_LOG_ERR, log, 0, "no memory");
403+
return NULL;
404+
}
405+
406+
hw_plugin->cur_ctx_id++;
407+
ctx_id = hw_plugin->cur_ctx_id;
408+
http_ctx->id = ctx_id;
409+
http_ctx->hwp_ctx = hwp_ctx;
410+
}
411+
412+
rc = ngx_wasm_vm.call(plugin, &proxy_on_context_create, false,
413+
NGX_WASM_PARAM_I32_I32, ctx_id, hwp_ctx->id);
414+
if (rc != NGX_OK) {
415+
ngx_log_error(NGX_LOG_ERR, log, 0, "failed to create context %d, rc: %d",
416+
ctx_id, rc);
417+
/* reuse the ctx_id */
418+
ngx_queue_insert_head(&hwp_ctx->free, &http_ctx->queue);
419+
return NULL;
420+
}
421+
422+
ngx_queue_insert_head(&hwp_ctx->occupied, &http_ctx->queue);
423+
424+
ngx_log_error(NGX_LOG_INFO, ngx_cycle->log, 0, "create http context %d", ctx_id);
425+
426+
return http_ctx;
427+
}
428+
429+
430+
static void
431+
ngx_http_wasm_cleanup(void *data)
432+
{
433+
ngx_int_t rc;
434+
ngx_http_wasm_ctx_t *ctx = data;
435+
ngx_http_wasm_http_ctx_t *http_ctx = ctx->http_ctx;
436+
uint32_t ctx_id;
437+
ngx_http_wasm_plugin_ctx_t *hwp_ctx;
438+
void *plugin;
439+
ngx_log_t *log;
440+
441+
log = ngx_cycle->log;
442+
443+
if (http_ctx == NULL) {
444+
return;
445+
}
446+
447+
ctx_id = http_ctx->id;
448+
hwp_ctx = http_ctx->hwp_ctx;
449+
plugin = hwp_ctx->hw_plugin->plugin;
450+
451+
ngx_queue_remove(&http_ctx->queue);
452+
ngx_queue_insert_head(&hwp_ctx->free, &http_ctx->queue);
453+
454+
rc = ngx_wasm_vm.call(plugin, &proxy_on_done, true, NGX_WASM_PARAM_I32, ctx_id);
455+
if (rc <= 0) {
456+
ngx_log_error(NGX_LOG_ERR, log, 0, "failed to mark context %d as done, rc: %d",
457+
ctx_id, rc);
458+
}
459+
460+
rc = ngx_wasm_vm.call(plugin, &proxy_on_delete, false, NGX_WASM_PARAM_I32, ctx_id);
461+
if (rc != NGX_OK) {
462+
ngx_log_error(NGX_LOG_ERR, log, 0, "failed to delete context %d, rc: %d",
463+
ctx_id, rc);
464+
}
465+
466+
ngx_log_error(NGX_LOG_INFO, log, 0, "free http context %d", ctx_id);
467+
468+
if (hwp_ctx->done) {
469+
ngx_http_wasm_free_plugin_ctx(hwp_ctx);
470+
}
471+
}
472+
473+
474+
static ngx_http_wasm_ctx_t *
475+
ngx_http_wasm_get_module_ctx(ngx_http_request_t *r)
476+
{
477+
ngx_http_wasm_ctx_t *ctx;
478+
ngx_pool_cleanup_t *cln;
479+
480+
ctx = ngx_http_get_module_ctx(r, ngx_http_wasm_module);
481+
482+
if (ctx == NULL) {
483+
ctx = ngx_pcalloc(r->pool, sizeof(ngx_http_wasm_ctx_t));
484+
if (ctx == NULL) {
485+
ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "no memory");
486+
return NULL;
487+
}
488+
489+
cln = ngx_pool_cleanup_add(r->pool, 0);
490+
if (cln == NULL) {
491+
ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "no memory");
492+
return NULL;
493+
}
494+
495+
cln->data = ctx;
496+
cln->handler = ngx_http_wasm_cleanup;
497+
498+
ngx_http_set_ctx(r, ctx, ngx_http_wasm_module);
499+
}
500+
501+
return ctx;
502+
}
503+
504+
505+
ngx_http_wasm_http_ctx_t *
506+
ngx_http_wasm_fetch_http_ctx(ngx_http_wasm_plugin_ctx_t *hwp_ctx, ngx_http_request_t *r)
507+
{
508+
ngx_http_wasm_ctx_t *ctx;
509+
510+
511+
ctx = ngx_http_wasm_get_module_ctx(r);
512+
if (ctx == NULL) {
513+
return NULL;
514+
}
515+
516+
if (ctx->http_ctx == NULL) {
517+
ctx->http_ctx = ngx_http_wasm_create_http_ctx(hwp_ctx, r);
518+
}
519+
520+
return ctx->http_ctx;
521+
}
522+
523+
524+
ngx_int_t
525+
ngx_http_wasm_on_http(ngx_http_wasm_plugin_ctx_t *hwp_ctx, ngx_http_request_t *r,
526+
ngx_http_wasm_phase_t type)
527+
{
528+
ngx_int_t rc;
529+
ngx_log_t *log;
530+
ngx_http_wasm_http_ctx_t *http_ctx;
531+
532+
log = r->connection->log;
533+
534+
if (!ngx_http_wasm_vm_inited) {
535+
ngx_log_error(NGX_LOG_ERR, log, 0, "miss wasm_vm configuration");
536+
return NGX_DECLINED;
537+
}
538+
539+
rc = NGX_OK;
540+
541+
http_ctx = ngx_http_wasm_fetch_http_ctx(hwp_ctx, r);
542+
if (http_ctx == NULL) {
543+
return NGX_DECLINED;
544+
}
545+
546+
return rc;
547+
}

0 commit comments

Comments
 (0)