Mercurial > hg > ngx_http_bytes_filter_module
changeset 0:8aec31ab4d52
Bytes filter module skeleton, currently does nothing.
Bytes module designed to return only specific range of file as requested in
arguments. It's intended to replace flv module as more generic alternative.
author | Maxim Dounin <mdounin@mdounin.ru> |
---|---|
date | Thu, 26 Jun 2008 04:49:22 +0400 |
parents | |
children | 6b995d5251ec |
files | config ngx_http_bytes_filter_module.c |
diffstat | 2 files changed, 229 insertions(+), 0 deletions(-) [+] |
line wrap: on
line diff
new file mode 100644 --- /dev/null +++ b/config @@ -0,0 +1,10 @@ +# (C) Maxim Dounin +# Configuration for ngx_http_bytes_filter_module. + +ngx_addon_name="ngx_http_bytes_filter_module" + +HTTP_RANGE_BODY_FILTER_MODULE="$HTTP_RANGE_BODY_FILTER_MODULE \ + ngx_http_bytes_filter_module" + +NGX_ADDON_SRCS="$NGX_ADDON_SRCS \ + $ngx_addon_dir/ngx_http_bytes_filter_module.c"
new file mode 100644 --- /dev/null +++ b/ngx_http_bytes_filter_module.c @@ -0,0 +1,219 @@ + +/* + * Copyright (C) Maxim Dounin + */ + +#include <ngx_config.h> +#include <ngx_core.h> +#include <ngx_http.h> + + +typedef struct { + ngx_flag_t enable; +} ngx_http_bytes_conf_t; + + +typedef struct { + off_t start; + off_t end; +} ngx_http_bytes_t; + + +typedef struct { + off_t offset; + ngx_array_t ranges; +} ngx_http_bytes_ctx_t; + + +static void *ngx_http_bytes_create_conf(ngx_conf_t *cf); +static char *ngx_http_bytes_merge_conf(ngx_conf_t *cf, void *parent, + void *child); +static ngx_int_t ngx_http_bytes_init(ngx_conf_t *cf); + + +static ngx_command_t ngx_http_bytes_commands[] = { + + { ngx_string("bytes"), + NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG, + ngx_conf_set_flag_slot, + NGX_HTTP_LOC_CONF_OFFSET, + offsetof(ngx_http_bytes_conf_t, enable), + NULL }, + + ngx_null_command +}; + + +static ngx_http_module_t ngx_http_bytes_module_ctx = { + NULL, /* preconfiguration */ + ngx_http_bytes_init, /* postconfiguration */ + + NULL, /* create main configuration */ + NULL, /* init main configuration */ + + NULL, /* create server configuration */ + NULL, /* merge server configuration */ + + ngx_http_bytes_create_conf, /* create location configuration */ + ngx_http_bytes_merge_conf /* merge location configuration */ +}; + + +ngx_module_t ngx_http_bytes_filter_module = { + NGX_MODULE_V1, + &ngx_http_bytes_module_ctx, /* module context */ + ngx_http_bytes_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_http_output_header_filter_pt ngx_http_next_header_filter; +static ngx_http_output_body_filter_pt ngx_http_next_body_filter; + + +static ngx_int_t +ngx_http_bytes_header_filter(ngx_http_request_t *r) +{ + u_char *p; + ngx_http_bytes_conf_t *conf; + ngx_http_bytes_ctx_t *ctx; + + conf = ngx_http_get_module_loc_conf(r, ngx_http_bytes_filter_module); + + if (!conf->enable || r->args.len == 0) { + return ngx_http_next_header_filter(r); + } + + p = (u_char *) ngx_strnstr(r->args.data, "bytes=", r->args.len); + + if (p == NULL) { + return ngx_http_next_header_filter(r); + } + + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "bytes header filter: r %p", r); + + p += sizeof("bytes=") - 1; + + /* create context */ + + ctx = ngx_pcalloc(r->pool, sizeof(ngx_http_bytes_ctx_t)); + if (ctx == NULL) { + return NGX_ERROR; + } + + if (ngx_array_init(&ctx->ranges, r->pool, 1, sizeof(ngx_http_bytes_t)) + == NGX_ERROR) + { + return NGX_ERROR; + } + + /* + * bytes= contain ranges compatible with RFC 2616, "14.35.1 Byte Ranges", + * but no whitespaces permitted + */ + +#if 0 + for ( ;; ) { + start = 0; + end = 0; + suffix = 0; + + if (*p != '-') { + if (*p < '0' || *p > '9') { + break; + } + + while (*p >= '0' && *p <= '9') { + start = start * 10 + *p++ - '0'; + } + + if (*p != '-') { + break; + } + + if (*p == ',' || *p == '\0') { + /* no last-byte-pos, assume end of file */ + end = len - 1; + } + + } else { + suffix = 1; + p++; + } + } +#endif + + /* ... */ + + ngx_http_set_ctx(r, ctx, ngx_http_bytes_filter_module); + + return ngx_http_next_header_filter(r); +} + + +static ngx_int_t +ngx_http_bytes_body_filter(ngx_http_request_t *r, ngx_chain_t *in) +{ + ngx_http_bytes_ctx_t *ctx; + + ctx = ngx_http_get_module_ctx(r, ngx_http_bytes_filter_module); + + if (ctx == NULL) { + return ngx_http_next_body_filter(r, in); + } + + ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "bytes body filter: r %p, in %p", r, in); + + return ngx_http_next_body_filter(r, in); +} + + +static void * +ngx_http_bytes_create_conf(ngx_conf_t *cf) +{ + ngx_http_bytes_conf_t *conf; + + conf = ngx_pcalloc(cf->pool, sizeof(ngx_http_bytes_conf_t)); + if (conf == NULL) { + return NGX_CONF_ERROR; + } + + conf->enable = NGX_CONF_UNSET; + + return conf; +} + + +static char * +ngx_http_bytes_merge_conf(ngx_conf_t *cf, void *parent, void *child) +{ + ngx_http_bytes_conf_t *prev = parent; + ngx_http_bytes_conf_t *conf = child; + + ngx_conf_merge_value(conf->enable, prev->enable, 0); + + return NGX_CONF_OK; +} + + +static ngx_int_t +ngx_http_bytes_init(ngx_conf_t *cf) +{ + ngx_http_next_header_filter = ngx_http_top_header_filter; + ngx_http_top_header_filter = ngx_http_bytes_header_filter; + + ngx_http_next_body_filter = ngx_http_top_body_filter; + ngx_http_top_body_filter = ngx_http_bytes_body_filter; + + return NGX_OK; +}