src/http/modules/ngx_http_flv_module.c - nginx source code

Global variables defined

Functions defined

Source code


  1. /*
  2. * Copyright (C) Igor Sysoev
  3. * Copyright (C) Nginx, Inc.
  4. */

  5. #include <ngx_config.h>
  6. #include <ngx_core.h>
  7. #include <ngx_http.h>


  8. static char *ngx_http_flv(ngx_conf_t *cf, ngx_command_t *cmd, void *conf);

  9. static ngx_command_t  ngx_http_flv_commands[] = {

  10.     { ngx_string("flv"),
  11.       NGX_HTTP_LOC_CONF|NGX_CONF_NOARGS,
  12.       ngx_http_flv,
  13.       0,
  14.       0,
  15.       NULL },

  16.       ngx_null_command
  17. };


  18. static u_char  ngx_flv_header[] = "FLV\x1\x5\0\0\0\x9\0\0\0\0";


  19. static ngx_http_module_t  ngx_http_flv_module_ctx = {
  20.     NULL,                          /* preconfiguration */
  21.     NULL,                          /* postconfiguration */

  22.     NULL,                          /* create main configuration */
  23.     NULL,                          /* init main configuration */

  24.     NULL,                          /* create server configuration */
  25.     NULL,                          /* merge server configuration */

  26.     NULL,                          /* create location configuration */
  27.     NULL                           /* merge location configuration */
  28. };


  29. ngx_module_t  ngx_http_flv_module = {
  30.     NGX_MODULE_V1,
  31.     &ngx_http_flv_module_ctx,      /* module context */
  32.     ngx_http_flv_commands,         /* module directives */
  33.     NGX_HTTP_MODULE,               /* module type */
  34.     NULL,                          /* init master */
  35.     NULL,                          /* init module */
  36.     NULL,                          /* init process */
  37.     NULL,                          /* init thread */
  38.     NULL,                          /* exit thread */
  39.     NULL,                          /* exit process */
  40.     NULL,                          /* exit master */
  41.     NGX_MODULE_V1_PADDING
  42. };


  43. static ngx_int_t
  44. ngx_http_flv_handler(ngx_http_request_t *r)
  45. {
  46.     u_char                    *last;
  47.     off_t                      start, len;
  48.     size_t                     root;
  49.     ngx_int_t                  rc;
  50.     ngx_uint_t                 level, i;
  51.     ngx_str_t                  path, value;
  52.     ngx_log_t                 *log;
  53.     ngx_buf_t                 *b;
  54.     ngx_chain_t                out[2];
  55.     ngx_open_file_info_t       of;
  56.     ngx_http_core_loc_conf_t  *clcf;

  57.     if (!(r->method & (NGX_HTTP_GET|NGX_HTTP_HEAD))) {
  58.         return NGX_HTTP_NOT_ALLOWED;
  59.     }

  60.     if (r->uri.data[r->uri.len - 1] == '/') {
  61.         return NGX_DECLINED;
  62.     }

  63.     rc = ngx_http_discard_request_body(r);

  64.     if (rc != NGX_OK) {
  65.         return rc;
  66.     }

  67.     last = ngx_http_map_uri_to_path(r, &path, &root, 0);
  68.     if (last == NULL) {
  69.         return NGX_HTTP_INTERNAL_SERVER_ERROR;
  70.     }

  71.     log = r->connection->log;

  72.     path.len = last - path.data;

  73.     ngx_log_debug1(NGX_LOG_DEBUG_HTTP, log, 0,
  74.                    "http flv filename: \"%V\"", &path);

  75.     clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);

  76.     ngx_memzero(&of, sizeof(ngx_open_file_info_t));

  77.     of.read_ahead = clcf->read_ahead;
  78.     of.directio = clcf->directio;
  79.     of.valid = clcf->open_file_cache_valid;
  80.     of.min_uses = clcf->open_file_cache_min_uses;
  81.     of.errors = clcf->open_file_cache_errors;
  82.     of.events = clcf->open_file_cache_events;

  83.     if (ngx_http_set_disable_symlinks(r, clcf, &path, &of) != NGX_OK) {
  84.         return NGX_HTTP_INTERNAL_SERVER_ERROR;
  85.     }

  86.     if (ngx_open_cached_file(clcf->open_file_cache, &path, &of, r->pool)
  87.         != NGX_OK)
  88.     {
  89.         switch (of.err) {

  90.         case 0:
  91.             return NGX_HTTP_INTERNAL_SERVER_ERROR;

  92.         case NGX_ENOENT:
  93.         case NGX_ENOTDIR:
  94.         case NGX_ENAMETOOLONG:

  95.             level = NGX_LOG_ERR;
  96.             rc = NGX_HTTP_NOT_FOUND;
  97.             break;

  98.         case NGX_EACCES:
  99. #if (NGX_HAVE_OPENAT)
  100.         case NGX_EMLINK:
  101.         case NGX_ELOOP:
  102. #endif

  103.             level = NGX_LOG_ERR;
  104.             rc = NGX_HTTP_FORBIDDEN;
  105.             break;

  106.         default:

  107.             level = NGX_LOG_CRIT;
  108.             rc = NGX_HTTP_INTERNAL_SERVER_ERROR;
  109.             break;
  110.         }

  111.         if (rc != NGX_HTTP_NOT_FOUND || clcf->log_not_found) {
  112.             ngx_log_error(level, log, of.err,
  113.                           "%s \"%s\" failed", of.failed, path.data);
  114.         }

  115.         return rc;
  116.     }

  117.     if (!of.is_file) {
  118.         return NGX_DECLINED;
  119.     }

  120.     r->root_tested = !r->error_page;

  121.     start = 0;
  122.     len = of.size;
  123.     i = 1;

  124.     if (r->args.len) {

  125.         if (ngx_http_arg(r, (u_char *) "start", 5, &value) == NGX_OK) {

  126.             start = ngx_atoof(value.data, value.len);

  127.             if (start == NGX_ERROR || start >= len) {
  128.                 start = 0;
  129.             }

  130.             if (start) {
  131.                 len = sizeof(ngx_flv_header) - 1 + len - start;
  132.                 i = 0;
  133.             }
  134.         }
  135.     }

  136.     log->action = "sending flv to client";

  137.     r->headers_out.status = NGX_HTTP_OK;
  138.     r->headers_out.content_length_n = len;
  139.     r->headers_out.last_modified_time = of.mtime;

  140.     if (ngx_http_set_etag(r) != NGX_OK) {
  141.         return NGX_HTTP_INTERNAL_SERVER_ERROR;
  142.     }

  143.     if (ngx_http_set_content_type(r) != NGX_OK) {
  144.         return NGX_HTTP_INTERNAL_SERVER_ERROR;
  145.     }

  146.     if (i == 0) {
  147.         b = ngx_calloc_buf(r->pool);
  148.         if (b == NULL) {
  149.             return NGX_HTTP_INTERNAL_SERVER_ERROR;
  150.         }

  151.         b->pos = ngx_flv_header;
  152.         b->last = ngx_flv_header + sizeof(ngx_flv_header) - 1;
  153.         b->memory = 1;

  154.         out[0].buf = b;
  155.         out[0].next = &out[1];
  156.     }


  157.     b = ngx_calloc_buf(r->pool);
  158.     if (b == NULL) {
  159.         return NGX_HTTP_INTERNAL_SERVER_ERROR;
  160.     }

  161.     b->file = ngx_pcalloc(r->pool, sizeof(ngx_file_t));
  162.     if (b->file == NULL) {
  163.         return NGX_HTTP_INTERNAL_SERVER_ERROR;
  164.     }

  165.     r->allow_ranges = 1;

  166.     rc = ngx_http_send_header(r);

  167.     if (rc == NGX_ERROR || rc > NGX_OK || r->header_only) {
  168.         return rc;
  169.     }

  170.     b->file_pos = start;
  171.     b->file_last = of.size;

  172.     b->in_file = b->file_last ? 1 : 0;
  173.     b->last_buf = (r == r->main) ? 1 : 0;
  174.     b->last_in_chain = 1;
  175.     b->sync = (b->last_buf || b->in_file) ? 0 : 1;

  176.     b->file->fd = of.fd;
  177.     b->file->name = path;
  178.     b->file->log = log;
  179.     b->file->directio = of.is_directio;

  180.     out[1].buf = b;
  181.     out[1].next = NULL;

  182.     return ngx_http_output_filter(r, &out[i]);
  183. }


  184. static char *
  185. ngx_http_flv(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
  186. {
  187.     ngx_http_core_loc_conf_t  *clcf;

  188.     clcf = ngx_http_conf_get_module_loc_conf(cf, ngx_http_core_module);
  189.     clcf->handler = ngx_http_flv_handler;

  190.     return NGX_CONF_OK;
  191. }