{"id":19155938,"url":"https://github.com/lyokha/nginx-easy-context","last_synced_at":"2026-02-03T16:35:13.195Z","repository":{"id":142525448,"uuid":"602236856","full_name":"lyokha/nginx-easy-context","owner":"lyokha","description":"Free persistent request contexts","archived":false,"fork":false,"pushed_at":"2024-08-18T09:44:59.000Z","size":30,"stargazers_count":2,"open_issues_count":0,"forks_count":0,"subscribers_count":2,"default_branch":"master","last_synced_at":"2025-06-28T17:47:39.306Z","etag":null,"topics":["context","nginx","persistent","request"],"latest_commit_sha":null,"homepage":"","language":"C","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"other","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/lyokha.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2023-02-15T19:32:47.000Z","updated_at":"2024-08-18T09:40:58.000Z","dependencies_parsed_at":"2024-11-09T08:44:36.564Z","dependency_job_id":null,"html_url":"https://github.com/lyokha/nginx-easy-context","commit_stats":null,"previous_names":[],"tags_count":1,"template":false,"template_full_name":null,"purl":"pkg:github/lyokha/nginx-easy-context","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/lyokha%2Fnginx-easy-context","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/lyokha%2Fnginx-easy-context/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/lyokha%2Fnginx-easy-context/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/lyokha%2Fnginx-easy-context/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/lyokha","download_url":"https://codeload.github.com/lyokha/nginx-easy-context/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/lyokha%2Fnginx-easy-context/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":29049194,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-02-03T15:43:47.601Z","status":"ssl_error","status_checked_at":"2026-02-03T15:43:46.709Z","response_time":96,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["context","nginx","persistent","request"],"created_at":"2024-11-09T08:32:44.911Z","updated_at":"2026-02-03T16:35:13.173Z","avatar_url":"https://github.com/lyokha.png","language":"C","funding_links":[],"categories":[],"sub_categories":[],"readme":"nginx-easy-context\n==================\n\n[![Build Status](https://github.com/lyokha/nginx-easy-context/workflows/CI/badge.svg)](https://github.com/lyokha/nginx-easy-context/actions?query=workflow%3ACI)\n\nFree persistent request contexts.\n\n*Free* means that they are not bound to the Nginx request object and their\nnumber is not anyhow restricted. *Persistent* means that they are not cleared\nupon internal redirections *unlike* the normal Nginx request context.\n\nNote that whether free contexts are shared between the main request and its\nsubrequests or not depends on how the subrequests are spawned. Internally, a\nfree context is bound to a distinct variable which tracks the context value.\nNormally, variables are shared between the main request and its subrequests\nwhich means that the contexts are shared too. However, some modules such as\n*echo-nginx-module* allocate a new set of variables in subrequests they spawn,\nand therefore the contexts in these subrequests branch off the main request.\n\nC API\n-----\n\nModule *ngx_easy_context* is tagged as *MISC* in the build config file. It does\nnot expose a module context or any handlers and directives. Instead, the module\nexports a number of C functions to help users build their own modules. In\ndirectory *test/*, there is a simple HTTP module *test_easy_context* aimed at\ndemonstration of how to use module *ngx_easy_context*.\n\n#### Register a request context handle\n\n```c\nngx_int_t ngx_http_register_easy_ctx(ngx_conf_t *cf,\n    ngx_module_t *module, ngx_http_easy_ctx_handle_t *handle);\n```\n\nRegistering a context handle means creation of a handle for using it when\nsetting and getting a request context during the lifetime of a request. The\nbest place for registering a context handle is the module's postconfiguration\nhandler. The best place for storing a context handle is the module's main\nconfiguration.\n\n###### Example (module *test_easy_context*)\n\n```c\ntypedef struct {\n    ngx_http_easy_ctx_handle_t  ctx1;\n    ngx_http_easy_ctx_handle_t  ctx2;\n} test_easy_ctx_main_conf_t;\n\ntypedef struct {\n    ngx_int_t  index;\n    ngx_str_t  value;\n} test_easy_ctx_ctx_t;\n\nstatic ngx_http_module_t  test_easy_context_ctx = {\n    // ---\n    test_easy_ctx_init,                    /* postconfiguration */\n    // ---\n};\n\nstatic ngx_int_t\ntest_easy_ctx_init(ngx_conf_t *cf)\n{\n    test_easy_ctx_main_conf_t  *mcf;\n\n    mcf = ngx_http_conf_get_module_main_conf(cf, test_easy_context);\n\n    if (ngx_http_register_easy_ctx(cf, \u0026test_easy_context, \u0026mcf-\u003ectx1)\n        == NGX_ERROR)\n    {\n        return NGX_ERROR;\n    }\n\n    if (ngx_http_register_easy_ctx(cf, \u0026test_easy_context, \u0026mcf-\u003ectx2)\n        == NGX_ERROR)\n    {\n        return NGX_ERROR;\n    }\n\n    return NGX_OK;\n}\n```\n\n#### Set a request context\n\n```c\nngx_int_t ngx_http_set_easy_ctx(ngx_http_request_t *r,\n    ngx_http_easy_ctx_handle_t *handle, void *ctx);\n```\n\nThis function is a direct equivalent to `ngx_http_set_ctx(r, ctx, module)`\nexcept it expects a registered context handle rather than a `module`.\n\n###### Example\n\n```c\n    test_easy_ctx_main_conf_t  *mcf;\n    test_easy_ctx_ctx_t        *ctx1;\n\n    ctx1 = ngx_pcalloc(r-\u003econnection-\u003epool, sizeof(test_easy_ctx_ctx_t));\n    if (ctx1 == NULL) {\n        return NGX_ERROR;\n    }\n\n    ctx1-\u003evalue.data = (u_char *) \"This is request context\";\n    ctx1-\u003evalue.len = ngx_strlen(ctx1-\u003edata);\n\n    mcf = ngx_http_get_module_main_conf(r, test_easy_context);\n\n    if (ngx_http_set_easy_ctx(r, \u0026mcf-\u003ectx1, ctx1) == NGX_ERROR) {\n        return NGX_ERROR;\n    }\n```\n\n#### Get a request context\n\n```c\nvoid *ngx_http_get_easy_ctx(ngx_http_request_t *r,\n    ngx_http_easy_ctx_handle_t *handle);\n```\n\nThis function is a direct equivalent to `ngx_http_get_module_ctx(r, module)`\nexcept it expects a registered context handle rather than a `module`.\n\n###### Example\n\n```c\n    test_easy_ctx_main_conf_t  *mcf;\n    test_easy_ctx_ctx_t        *ctx1;\n\n    mcf = ngx_http_get_module_main_conf(r, test_easy_context);\n\n    ctx1 = ngx_http_get_easy_ctx(r, \u0026mcf-\u003ectx1);\n```\n\nBuild\n-----\n\nFrom the Nginx source directory, run\n\n```ShellSession\n$ ./configure --add-module=/path/to/nginx-easy-context\n$ make\n```\n\nTest\n----\n\nIn module *test_easy_context* located in directory *test/*, two free request\ncontexts and one normal Nginx request context are created by running directive\n*test_easy_context*. All the contexts hold Nginx strings with simple text\nmessages that will be sent in the response.\n\nThe module is built from the Nginx source directory.\n\n```ShellSession\n$ ./configure --add-module=/path/to/nginx-easy-context --add-module=/path/to/nginx-easy-context/test\n$ make\n```\n\nThe order of the two *--add-module* options matters. Module *nginx-easy-context*\nmust go first.\n\n###### File *nginx.conf*\n\n```nginx\nuser                    nobody;\nworker_processes        4;\n\nevents {\n    worker_connections  1024;\n}\n\nerror_log               /tmp/nginx-test-easy-context-error.log warn;\n\nhttp {\n    default_type        application/octet-stream;\n    sendfile            on;\n\n    access_log          /tmp/nginx-test-easy-context-access.log;\n\n    server {\n        listen          8010;\n        server_name     main;\n\n        location / {\n            test_easy_context on;\n            error_page 502 = /error;\n            return 502;\n        }\n\n        location /error {\n            internal;\n            echo \"Request context: '$test_easy_ctx_req_ctx'\";\n            echo \"Ctx1: '$test_easy_ctx_ctx1'\";\n            echo \"Ctx2: '$test_easy_ctx_ctx2'\";\n        }\n    }\n}\n```\n\nAfter internal redirection via *error_page*, the normal request context must\nhave been cleared while the two free request contexts must still be alive.\n\nLet's test this.\n\n```ShellSession\n$ curl 'http://127.0.0.1:8010/'\nRequest context: ''\nCtx1: 'This is request context'\nCtx2: 'This is context 2'\n```\n\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Flyokha%2Fnginx-easy-context","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Flyokha%2Fnginx-easy-context","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Flyokha%2Fnginx-easy-context/lists"}