I've been coding an NGINX filter module that can read/write cookies for incoming requests. If a particular cookie isn't set correctly (i.e. authentication cookie), it will set the outgoing header status to the appropriate error code. This works fine per the directions of Evan Miller's tutorial. The next part I'm trying to get working (and haven't thus far) is having the body filter be invoked so I can insert/replace body response text when error responses are encountered. I again followed Evan Miller's tutorial on body filters, and I cannot for the life of me get this working. Here's my setup:
static ngx_http_output_header_filter_pt ngx_http_next_header_filter;
static ngx_http_output_body_filter_pt ngx_http_next_body_filter;
...
...
static ngx_http_module_t ngx_http_source_cookie_module_ctx = {
NULL, /* preconfiguration */
ngx_http_source_cookie_init, /* postconfiguration */
NULL, /* create main configuration */
NULL, /* init main configuration */
NULL, /* create server configuration */
NULL, /* merge server configuration */
ngx_http_source_cookie_create_loc_conf, /* create location configuration */
ngx_http_source_cookie_merge_loc_conf /* merge location configuration */
};
ngx_module_t ngx_http_source_cookie_module = {
NGX_MODULE_V1,
&ngx_http_source_cookie_module_ctx, /* module context */
ngx_http_source_cookie_commands, /* module directives */
NGX_HTTP_MODULE, /* module type */
NULL, /* init master */
NULL, /* init module */
NULL, /* init process */
NULL, /* init thread */
NULL, /* exit thread */
NULL, /* exit process */
NULL, /* exit master */
NGX_MODULE_V1_PADDING
};
/*--------------------------------------------------------------------------*/
/*--------------------------------------------------------------------------*/
static ngx_int_t
ngx_http_source_cookie_header_filter(ngx_http_request_t *r)
{
// this gets invoked
...
}
/*--------------------------------------------------------------------------*/
/*--------------------------------------------------------------------------*/
static ngx_int_t
ngx_http_body_filter(ngx_http_request_t *r, ngx_chain_t *in)
{
// this never get invoked
...
}
/*--------------------------------------------------------------------------*/
/*--------------------------------------------------------------------------*/
static ngx_int_t
ngx_http_source_cookie_init(ngx_conf_t *cf)
{
// registering of my filters
ngx_http_next_header_filter = ngx_http_top_header_filter;
ngx_http_top_header_filter = ngx_http_source_cookie_header_filter;
ngx_http_next_body_filter = ngx_http_top_body_filter;
ngx_http_top_body_filter = ngx_http_body_filter;
return NGX_OK;
}
This is my basic setup, and as far as I can tell, it's spot on all the examples/tutorials I've come across. I'm wondering if there's something different altogether I need to enable... like a NGINX config option, NGINX ./configure compile option, etc.
Any help is greatly appreciated.
I note that Evan doesnt fix http content length in ngx_http_<module_name>_header_filter().
If I dont add http content length(r->headers_out.content_length_n), the inserted text to the end of request will not be output from nginx-1.2.7 stable.
Also you can see footer filter module.
Related
Currently I'm working on some basic OpenSSL. I'm confused about the basic behavior of SSL_write and SSL_read. In the documentation it is not clearly explained how the data is encrypted / decrypted. What I mean? Is the SSL_write, once the SSL_CTX is set and file descriptor assigned, by default encrypting the data or calling the encryption function, or does this have to be done by hand? Do I have to call some encryption function explicitly? Is the same true for the SSL_read? I need a deeper understanding of what SSL_write / read do automatically and what not, or sources where I can fall back to if I'm having issues.
Here is an example that I'm working with.
Example:
SSL *ssl;
int client = accept(server, (struct sockaddr*)&addr, &len); /* accept connection as usual */
printf("Connection: %s:%d\n",inet_ntoa(addr.sin_addr), ntohs(addr.sin_port));
ssl = SSL_new(ctx); /* get new SSL state with context */
SSL_set_fd(ssl, client); /* set connection socket to SSL state */
Servlet(ssl); /* service connection */
Servlet calls
void Servlet(SSL* ssl)
{
char buf[1024];
char reply[1024];
int sd, bytes;
const char* HTMLecho="<html><body><pre>%s</pre></body></html>\n\n";
if ( SSL_accept(ssl) == FAIL ) /* do SSL-protocol accept */
ERR_print_errors_fp(stderr);
else
{
ShowCerts(ssl); /* get any certificates */
bytes = SSL_read(ssl, buf, sizeof(buf)); /* get request */
if ( bytes > 0 )
{
buf[bytes] = 0;
printf("Client msg: \"%s\"\n", buf);
sprintf(reply, HTMLecho, buf); /* construct reply */
SSL_write(ssl, reply, strlen(reply)); /* send reply */
}
else
ERR_print_errors_fp(stderr);
}
sd = SSL_get_fd(ssl); /* get socket connection */
SSL_free(ssl); /* release SSL state */
close(sd); /* close connection */
}
Do I have to call some encryption function explicitly, is the same true for the SSL_read?
No. Encryption is handled within SSL_write automatically as is decryption in SSL_read. Both use the SSL structure which contains the necessary encryption keys once the TLS handshake is finished.
... sources where I can fall back to if I'm having issues
This depends on the issues you have. Both SSL_read and SSL_write have documentation. There are also easy to find examples. Being able to use a search engine helps also a lot to find more information. And StackOverflow is a good place to get help if things don't work as expected.
I need to build a javascript engine (duktape or jerryscript) for a embedded device which should be capable of executing shell commands. how can this be achieved?
With duktape in C, you can easily create a native ECMAScript function and create a reference to it via the global object:
#include "duktape.h"
int main() {
/* create heap */
duk_context* heap = duk_create_heap(NULL,NULL,NULL,NULL,
NULL); /* preferably, set an error callback here */
/* push the native function on the stack */
duk_push_c_function(ctx, /* heap context */
&native_js_shell, /* native function pointer */
1); /* accepted arguments */
/* make this javascript function a property of the global object */
duk_put_global_string(ctx, /* heap context*/
"shell"); /* function name in js */
return 0;
}
/* Your native C function */
duk_ret_t native_js_shell(duk_context* ctx) {
/* obtain the argument from javascript */
const char* cmd = duk_safe_to_string(ctx, /* heap context */
-1); /* position on stack */
/* run the shell command, etc. */
/* ... */
}
All the explanation for the duk_* functions can be found in the duktape API, but perhaps this gives you an idea of how it's structured.
p.s. Welcome to Stack Overflow! Your question may have been downrated since it pretty much requires someone to write all the code for you. In general, in the future, try to do the research on your own, and ask specific questions as you get stuck. :)
I want to write a module that serves a huge virtual .wav file (also plan to add a virtual .ogg file in the future).
I know the size of the file (2Gb) and its fake modification time (2000-01-01 0:00:00) and I have a function to read portion of the file:
void virtwav_read(void *buf, ssize_t bufsz, uint32_t virtofs);
I want to hook the low-level file operations like stat, read, seek, etc. The standard apache code should take care of parsing the headers (including range requests, cache-related stuff) and generate Content-Type, Content-Length, ETag, Last-Modified, etc.
Parsing the request_rec.range is not a big deal. What worries me more is sending the right cache-related headers and HTTP 206 and 304 when approprate. I'm sure apache would do that better than my code.
I thought that setting request_rec.mtime and request_rec.clength would do the trick, but they don't seem to be output fields.
Lastly, VFS is surprisingly unpopular topic. I found only one ancient project http://apvfs.sourceforge.net/ dated 2003.
Here's my minimal module and its config. The right Content-Type is added by apache, but no ETag
LoadModule virtwav_module modules/mod_virtwav.so
AddHandler virtwav-handler .wav
_
#include "apr_hash.h"
#include "ap_config.h"
#include "ap_provider.h"
#include "httpd.h"
#include "http_core.h"
#include "http_config.h"
#include "http_log.h"
#include "http_protocol.h"
#include "http_request.h"
#include <unistd.h> /* for sleep() */
static int example_handler(request_rec *r)
{
if (!r->handler || strcmp(r->handler, "virtwav-handler")) return (DECLINED);
//r->clength = 42;
//r->mtime = apr_time_now();
ap_rprintf(r, "clength: %" APR_INT64_T_FMT "\n", (apr_int64_t)r->clength);
ap_rprintf(r, "mtime: %" APR_INT64_T_FMT "\n", (apr_int64_t)r->mtime);
ap_rwrite("dummy", 5, r);
ap_rflush(r);
sleep(50);
return OK;
}
static void register_hooks(apr_pool_t *pool)
{
/* Create a hook in the request handler, so we get called when a request arrives */
ap_hook_handler(example_handler, NULL, NULL, APR_HOOK_LAST);
// ap_hook_dirwalk_stat ?
// This hook allows modules to handle/emulate the apr_stat()
// ap_hook_map_to_storage ?
// This hook allow modules to set the per_dir_config based on their own
}
module AP_MODULE_DECLARE_DATA virtwav_module =
{
STANDARD20_MODULE_STUFF,
NULL,
NULL,
NULL,
NULL,
NULL,
register_hooks /* Our hook registering function */
};
I wrote the module code like this:
static void *example_create_server_config(apr_pool_t *p, server_rec *s)
{
syslog(LOG_ERR, "create_server_config");
// create my handler
// my_handler_t *handler = (my_handler_t *)apr_palloc(pool, sizeof(my_handler_t));
return NULL;
}
/* Dispatch list for API hooks */
module AP_MODULE_DECLARE_DATA example_module = {
STANDARD20_MODULE_STUFF,
NULL, /* create per-dir config structures */
NULL, /* merge per-dir config structures */
example_create_server_config, /* create per-server config structures */
NULL, /* merge per-server config structures */
example_cmds, /* table of config file commands */
example_register_hooks /* register hooks */
};
When I restart Apache, the /var/log/syslog contains this:
Jan 31 14:46:49 su02 apache2: create_server_config
Jan 31 14:46:49 su02 apache2: create_server_config
Jan 31 14:46:49 su02 apache2: child_init
Why is the create_server_config function be called twice?
I malloc some global variables in this function. Is that safe or not?
It is perfectly safe to acquire memory using the apr_pool_t pointer that you receive inside of this function. Also, this function will be invoked once for every server/host configuration you have in your httpd.conf file, so that's why you see multiple calls to this function. For example a root server configuration and one configuration section would make this function be invoked twice.
typedef struct
{
int value;
} my_srv_cfg;
static void *example_create_server_config(apr_pool_t *pool, server_rec *s)
{
my_srv_cfg *new = apr_pcalloc(pool, sizeof (*new));
new->value = 100;
return new;
}
I used to write apache modules in apache 1.3, but these days I am willing to pass to apache2. The module that I am writing at the moment has is own binary data, not a database, for performance purposes. I need to load this data in shared memory, so every child can access it without making his own copy, and it would be practical to load/create the binary data at startup, as I was used to do with apache 1.3. Problem is that I don't find an init event in apache2, in 1.3 in the module struct, immediatly after STANDARD_MODULE_STUFF you find a place for a /** module initializer */, in which you can put a function that will be executed early.
Body of the function I used to write is something like:
if ( getppid == 1 )
{
// Load global data here
// this is the parent process
void* data = loadGlobalData( someFilePath );
setGlobalData( config, data );
}
else
{
// this is the init of a child process
// do nothing
}
I am looking for a place in apache2 in where I can put a similar function.
Can you help?
Thanks
Benvenuto
Since you want the server to create a single shared memory segment to be used by all children, I would recommend initialising this in the post config hook (ap_hook_post_config). This is called once the configuration has been read, but before the children are spawned, so it should work well.
Since Apache 2.x loads DSO modules twice, ap_hook_post_config() is called twice during Apache startup.
The following code added to the ap_hook_post_config() will prevent the initialization of your module during the first call and continue only during the second call.
This is a hack, but a neat hack :)
void *data = NULL;
const char *key = "dummy_post_config";
// This code is used to prevent double initialization of the module during Apache startup
apr_pool_userdata_get(&data, key, s->process->pool);
if ( data == NULL ) {
apr_pool_userdata_set((const void *)1, key, apr_pool_cleanup_null, s->process->pool);
return OK;
}
You can read more about double dso module loads on the Apache wiki.
You can use a child_init hook to initialize a resource that will last longer then request or connection.
typedef struct {
apr_pool_t *pool;
apr_hash_t *hash;
} my_server_config;
static void my_child_init(apr_pool_t *p, server_rec *s)
{
my_server_config cfg = ap_get_module_config(s->module_config, &my_module);
/* Create sub-pool: ap_pool_create(&cfg->pool, p); */
/* Create hash: cfg->hash = ap_hash_make(cfg->pool); */
}
static void my_register_hooks(apr_pool_t *p)
{
ap_hook_child_init(my_child_init, NULL, NULL, APR_HOOK_MIDDLE);
}
module AP_MODULE_DECLARE_DATA my_module =
{
STANDARD20_MODULE_STUFF,
NULL, /* per-directory config creator */
NULL, /* dir config merger */
NULL, /* server config creator */
NULL, /* server config merger */
NULL, /* command table */
my_register_hooks, /* set up other request processing hooks */
};
Child init hook will be called before apache enters operational mode or before threads are created in threaded MPM. The pool passed into the my_child_init function should be process pool.
For better example you should download apache source code and check the modules/experimental/mod_example.c file.