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
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/config	Thu Jun 26 04:49:22 2008 +0400
@@ -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"
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/ngx_http_bytes_filter_module.c	Thu Jun 26 04:49:22 2008 +0400
@@ -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;
+}