create your dynamic linkable application on top of nginx module
nginx-link-function is a nginx module which provides dynamic linking to your application in server context and call the function of your application in location directive.You could direct link your C/C++ application (or any other which accept dynamic linking) to nginx server.
# nginx.conf
server {
listen 8888;
...
ngx_link_func_lib "/path/to/your/liblinkfuntest.so";
...
...
location = /testLinkFunGreeting {
# if not variable specified, direct write response out
ngx_link_func_call "my_app_simple_get_greeting";
}
}
server {
listen 8989;
aio threads;
...
ngx_link_func_lib "/path/to/your/liblinkfuntest.so"; # sharing data memory with server 1 if the path are same with server 1
...
...
location = /testLinkFunGreeting {
# if variable specified, not response write out, but it stored into myResponseVariable
ngx_link_func_call "my_app_simple_get_greeting" respTo=myResponseVariable;
return 200 $myResponseVariable;
}
}
server {
listen 8999;
aio threads;
...
ngx_link_func_lib "/path/to/your/liblinkfuntest2.so"; # another application
...
...
location = /testPost {
add_header Allow "GET, POST, HEAD" always;
if ( $request_method !~ ^(POST)$ ) {
return 405;
}
ngx_link_func_call "my_2nd_app_simple_get_token";
}
}
server {
listen 9888;
aio threads;
...
## Download application from cloud repo e.g. ngx_link_func_download_and_link_lib <download_link> <dest_link_file>
ngx_link_func_download_and_link_lib "http://abc.com/repos/liblinkfuntest.so" "/etc/nginx/liblinkfuntest3.so"
...
...
location = /testPost {
add_header Allow "GET, POST, HEAD" always;
if ( $request_method !~ ^(POST)$ ) {
return 405;
}
ngx_link_func_call "my_3rd_app_simple_get_token";
}
}
server {
listen 9898;
aio threads;
...
## Download application from cloud repo with extra header e.g. ngx_link_func_download_and_link_lib <download_link> <headers> <dest_link_file>
ngx_link_func_download_and_link_lib "https://abc.com/repos/liblinkfuntest.so" "Accept-Language:en_US\r\nAuthorization:Bearer KA.eyJ2ZXJzaadlasdlaldhjHJ2h3ldjklsjaklcjkljasdklcmasaskdaJxdkL3ftjM\r\n" "/etc/nginx/liblinkfuntest4.so"
...
...
location = /testPost {
add_header Allow "GET, POST, HEAD" always;
if ( $request_method !~ ^(POST)$ ) {
return 405;
}
ngx_link_func_call "my_other_app_simple_get_token";
}
}
wget 'http://nginx.org/download/nginx-1.10.3.tar.gz'
tar -xzvf nginx-1.10.3.tar.gz
cd nginx-1.10.3/
./configure --add-module=/path/to/nginx-link-function
make -j2
sudo make install
When first time configure this project, I purposely do not include this header, you may need to install it to your c header file as this header file need to share with your .so application as well.
install -m 644 /path/to/nginx-link-function/src/ngx_link_func_module.h /usr/local/include/
This is the interface that you can use to get more details from nginx server, it all inside the ngx_link_func_module.h.
#define ngx_link_func_content_type_plaintext "text/plain"
#define ngx_link_func_content_type_html "text/html; charset=utf-8"
#define ngx_link_func_content_type_json "application/json"
#define ngx_link_func_content_type_jsonp "application/javascript"
#define ngx_link_func_content_type_xformencoded "application/x-www-form-urlencoded"
typedef struct {
char *req_args; // Uri Args
u_char *req_body; // Request Body
size_t req_body_len; // length of body
void *shared_mem;
/* internal */
void* __r__;
void* __pl__;
void* __log__;
} ngx_link_func_ctx_t;
extern void ngx_link_func_log_debug(ngx_link_func_ctx_t *ctx, const char* msg);
extern void ngx_link_func_log_info(ngx_link_func_ctx_t *ctx, const char* msg);
extern void ngx_link_func_log_warn(ngx_link_func_ctx_t *ctx, const char* msg);
extern void ngx_link_func_log_err(ngx_link_func_ctx_t *ctx, const char* msg);
extern u_char* ngx_link_func_get_header(ngx_link_func_ctx_t *ctx, const char*key);
extern void* ngx_link_func_get_query_param(ngx_link_func_ctx_t *ctx, const char *key);
extern void* ngx_link_func_palloc(ngx_link_func_ctx_t *ctx, size_t size);
extern void* ngx_link_func_pcalloc(ngx_link_func_ctx_t *ctx, size_t size);
extern char *ngx_link_func_strdup(ngx_link_func_ctx_t *ctx, const char *src);
extern void ngx_link_func_write_resp(
ngx_link_func_ctx_t *ctx,
uintptr_t status_code,
const char* status_line,
const char* content_type,
const char* resp_content,
size_t resp_len
);
// Shared Memory and Cache Scope
extern uintptr_t ngx_link_func_shmtx_trylock(void *shared_mem);
extern void ngx_link_func_shmtx_lock(void *shared_mem);
extern void ngx_link_func_shmtx_unlock(void *shared_mem);
extern void* ngx_link_func_shm_alloc(void *shared_mem, size_t size);
extern void ngx_link_func_shm_free(void *shared_mem, void *ptr);
extern void* ngx_link_func_shm_alloc_locked(void *shared_mem, size_t size);
extern void ngx_link_func_shm_free_locked(void *shared_mem, void *ptr);
extern void* ngx_link_func_cache_get(void *shared_mem, const char* key);
extern void* ngx_link_func_cache_put(void *shared_mem, const char* key, void* value);
extern void* ngx_link_func_cache_new(void *shared_mem, const char* key, size_t size);
extern void* ngx_link_func_cache_remove(void *shared_mem, const char* key);
void* ngx_link_func_palloc(ngx_link_func_ctx_t *ctx, size_t size);
void* ngx_link_func_pcalloc(ngx_link_func_ctx_t *ctx, size_t size);
extern u_char* ngx_link_func_get_header(ngx_link_func_ctx_t *ctx, const char*key);
ctx->req_args;
extern void* ngx_link_func_get_query_param(ngx_link_func_ctx_t *ctx, const char *key);
ctx->req_body;
ctx->req_body_len;
extern void ngx_link_func_log_debug(ngx_link_func_ctx_t *ctx, const char* msg);
extern void ngx_link_func_log_info(ngx_link_func_ctx_t *ctx, const char* msg);
extern void ngx_link_func_log_warn(ngx_link_func_ctx_t *ctx, const char* msg);
extern void ngx_link_func_log_err(ngx_link_func_ctx_t *ctx, const char* msg);
extern void ngx_link_func_write_resp(
ngx_link_func_ctx_t *ctx,
uintptr_t status_code, // Status code
const char* status_line, // Status line
const char* content_type, // Response content type
const char* resp_content // Response content
size_t resp_len
);
Feel free to clone a sample project on Sample Project
#include <stdio.h>
#include <ngx_link_func_module.h>
/*** build the program as .so library and copy to the preferred place for nginx to link this library ***/
/*** gcc -shared -o liblinkfuntest.so -fPIC linkfuntest.c ***/
/*** cp liblinkfuntest.so /etc/nginx/ ***/
int is_service_on = 0;
void ngx_link_func_init_cycle(ngx_link_func_cycle_t* cyc) {
ngx_link_func_cyc_log(info, cyc, "%s", "Starting The Application");
is_service_on=1;
}
void my_app_simple_get_greeting(ngx_link_func_ctx_t *ctx) {
ngx_link_func_log_info(ctx, "Calling back and log from my_app_simple_get");
ngx_link_func_write_resp(
ctx,
200,
"200 OK",
"text/plain",
"greeting from ngx_http_c_func testing",
sizeof("greeting from ngx_http_c_func testing") - 1
);
}
void my_app_simple_get_args(ngx_link_func_ctx_t *ctx) {
ngx_link_func_log_info(ctx, "Calling back and log from my_app_simple_get_args");
ngx_link_func_write_resp(
ctx,
200,
"200 OK",
"text/plain",
ctx->req_args,
strlen(ctx->req_args)
);
}
void my_app_simple_get_token_args(ngx_link_func_ctx_t *ctx) {
ngx_link_func_log_info(ctx, "Calling back and log from my_app_simple_get_token_args");
char * tokenArgs = ngx_link_func_get_query_param(ctx, "token");
if (! tokenArgs) {
ngx_link_func_write_resp(
ctx,
401,
"401 unauthorized",
"text/plain",
"Token Not Found",
sizeof("Token Not Found") - 1
);
} else {
ngx_link_func_write_resp(
ctx,
401,
"401 unauthorized",
"text/plain",
tokenArgs,
strlen(tokenArgs)
);
}
}
void my_app_simple_post(ngx_link_func_ctx_t *ctx) {
ngx_link_func_log_info(ctx, "Calling back and log from my_app_simple_post");
// echo back
ngx_link_func_write_resp(
ctx,
202,
"202 Accepted and Processing",
"text/plain",
ctx->req_body,
ctx->req_body_len
);
}
void my_app_simple_get_no_resp(ngx_link_func_ctx_t *ctx) {
ngx_link_func_log_info(ctx, "Calling back and log from my_app_simple_get_no_resp");
}
void ngx_link_func_exit_cycle(ngx_link_func_cycle_t* cyc) {
ngx_link_func_cyc_log(info, cyc, "%s\n", "Shutting down The Application");
is_service_on = 0;
}
The link-func init and exit are reserved function when started the nginx, it will call init method, when stop nginx, it will call exit function.
void ngx_link_func_init_cycle(ngx_link_func_cycle_t* cyc){}
void ngx_link_func_exit_cycle(ngx_link_func_cycle_t* cyc){}
The log can be called, the logged message will be store where you config error log in nginx.conf
ngx_link_func_log_info(ctx, "This is info direct message");
ngx_link_func_log(info, ctx, "%s", "This is info with formatted message");
ngx_link_func_log_debug(ctx, "This is debug direct message");
ngx_link_func_log(debug, ctx, "%s", "This is debug with formatted message");
ngx_link_func_log_info(ctx, "%s", "This is info with formatted message"); // Wrong format
ngx_link_func_log_debug(ctx, "%s", "This is info with formatted message"); // Wrong format
ngx_link_func_ca_cert "/etc/ssl/certs/ca-cert.crt"
ngx_link_func_download_and_link_lib "https://abc.com/repos/liblinkfuntest.so" "/etc/nginx/liblinkfuntest4.so"
ngx_link_func_ca_cert "/etc/ssl/certs/ca-cert.crt"
ngx_link_func_download_and_link_lib "https://abc.com/repos/liblinkfuntest.so" "Accept-Language:en_US\r\nAuthorization:Bearer KA.eyJ2ZXJzaadlasdlaldhjHJ2h3ldjklsjaklcjkljasdklcmasaskdaJxdkL3ftjM\r\n" "/etc/nginx/liblinkfuntest4.so"
It depends on nginx test suite libs, please refer test-nginx for installation.
cd /path/to/nginx-link-function
export PATH=/path/to/nginx-dirname:$PATH
sudo prove -r t/
extern u_char* ngx_link_func_get_header(ngx_link_func_ctx_t *ctx, const char*key);
extern void* ngx_link_func_get_query_param(ngx_link_func_ctx_t *ctx, const char *key);
extern int ngx_link_func_add_header_in(ngx_link_func_ctx_t *ctx, const char *key, size_t keylen, const char *value, size_t val_len );
extern void ngx_link_func_write_resp(
ngx_link_func_ctx_t *ctx,
uintptr_t status_code,
const char* status_line,
const char* content_type,
const char* resp_content,
size_t resp_len
);
void interRouteCallForChecking(ngx_link_func_ctx_t *ctx) {
interRouteCallForChecking...........
if(OK) {
ngx_link_func_add_header_in(ctx, "okToProceed", sizeof("okToProceed") -1 , "true", sizeof("true") -1);
ngx_link_func_write_resp(
ctx,
200,
NULL,
ngx_link_func_content_type_plaintext,
"OK",
sizeof("OK") - 1
);
} else {
ngx_link_func_write_resp(
ctx,
404,
NULL,
ngx_link_func_content_type_plaintext,
"NOT FOUND",
sizeof("NOT FOUND") - 1
);
}
}
ngx_link_func_lib "/home/taymindis/github/nginx-link-function/t/Myapp.so";
location /internalRoute{
internal;
ngx_link_func_call "interRouteCallForChecking";
}
location /asyncRoute{
# configure async request ...
}
location = /externalRoute {
ngx_link_func_add_req_header userId $arg_userId; # add addition header in proxy if needed
ngx_link_func_add_req_header userSessionToken $arg_userSessionToken; # add addition header in proxy if needed
proxy_pass "http://otherapplication/...";
}
location = /callProcess {
ngx_link_func_subrequest /internalRoute check_status; # check_status will run and wait till finish then proceed to next subrequest, but it checks for the response status, if error status, it will break the request.
ngx_link_func_subrequest /externalRoute; # this will run with waiting other subrequest
ngx_link_func_subrequest /asyncRoute; # this will run without waiting for response and go for the next subrequest or function handler or proxy handler depends the next config level
ngx_link_func_call "afterDoneVerification"; # if proxy_pass is given, the response will be ignored, it will route to next phase which is proxy pass, if proxy pass not given, it should have response content
proxy_pass http://127.0.0.1:${server_port}/backendProcess?userSuccessStatus=$http_userSuccessStatus;
}
There are a lot of directive which able to support routing service, such as:
to be continue
Browse Wiki for more details
Please do not hesitate to raise an issue and I will fixed it as soon as I can
Alternatively, you may email to minikawoon2017@gmail.com
Copyright (c) 2018, Taymindis cloudleware2015@gmail.com
This module is licensed under the terms of the BSD license.
All rights reserved.
Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS “AS IS” AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.