Project

General

Profile

Actions

Mod magnet » History » Revision 7

« Previous | Revision 7/119 (diff) | Next »
jan, 2006-09-14 12:39
added a mod_cml migration


{{{
#!rst ==============
a power-magnet ==============

------------------
Module: mod_magnet
------------------

.. contents:: Table of Contents

Overview ========

mod_magnet is a module to control the request handling in lighty.

.. note:: Currently this page only describes the final syntax and some part might not work with the current svn-code.

Options =======

mod_magnet can attract a request in several stages in the request-handling.

  • either at the same level as mod_rewrite, before any parsing of the URL is done
  • or at a later stage, when the doc-root is known and the physical-path is already setup

It depends on the purpose of the script which stage you want to intercept. Usually you want to use
the 2nd stage where the physical-path which relates to your request is known. At this level you
can run checks against lighty.env["physical.path"].

::

magnet.attract-raw-url-to = ...
magnet.attract-physical-path-to = ...

Debugging =========

To easy debugging we overloaded the print()-function in lua and redirect the output of print() to the error-log. ::

print("Host: " .. lighty.request["Host"])
print("Request-URI: " .. lighty.env["request.uri"])

Examples ========

Sending text-files as HTML
--------------------------

This is a bit simplistic, but it illustrates the idea: Take a text-file and cover it in a

 tag.

Config-file ::

  magnet.attract-physical-path-to = server.docroot + "/readme.lua" 

readme.lua ::

  lighty.content = { "<pre>", { filename = "/README" }, "</pre>" }
  lighty.header["Content-Type"] = "text/html" 

  return 200

Maintainance pages
------------------

Your side might be on maintainance from time to time. Instead of shutting down the server confusing all
users, you can just send a maintainance page.

Config-file ::

  magnet.attract-physical-path-to = server.docroot + "/maintainance.lua" 

maintainance.lua ::

  require "lfs" 

  if (nil == lfs.attributes(lighty.env["physical.doc-root"] .. "/maintainance.html")) then
    lighty.content = ( lighty.env["physical.doc-root"] .. "/maintainance.html" )

    lighty.header["Content-Type"] = "text/html" 

    return 200
  end

mod_flv_streaming
-----------------

Config-file ::

  magnet.attract-physical-path-to = server.docroot + "/flv-streaming.lua" 

flv-streaming.lua::

  if (lighty.get["start"]) {
    lighty.content = { "FLV\x1\x1\0\0\0\x9\0\0\0\x9", 
       { filename = lighty.env["physical.path"], offset = lighty.get["start"] } }
    lighty.header["Content-Type"] = "video/x-flv" 
    return 200
  }

selecting a random file from a directory
----------------------------------------

Say, you want to send a random file (ad-content) from a directory. 

To simplify the code and to improve the performance we define:

* all images have the same format (e.g. image/png)
* all images use increasing numbers starting from 1
* a special index-file names the highest number

Config ::

  server.modules += ( "mod_magnet" )
  magnet.attract-physical-path-to = "random.lua" 

random.lua ::

  dir = lighty.env["physical.path"]

  f = assert(io.open(dir .. "/index", "r"))
  maxndx = f:read("*all")
  f:close()

  ndx = math.random(maxndx)

  lighty.content = { { filename = dir .. "/" .. ndx }}
  lighty.header["Content-Type"] = "image/png" 

  return 200

denying illegal character sequences in the URL
----------------------------------------------

Instead of implementing mod_security, you might just want to apply filters on the content
and deny special sequences that look like SQL injection. 

A common injection is using UNION to extend a query with another SELECT query.

::

  if (string.find(lighty.env["request.uri"], "UNION%s")) then
    return 400
  end

Complex rewrites
----------------

If you want to rewrite a URL depending on a complex condition, here you go:

:: 

  if (lfs.attributes(lighty.env["physical.path"])) then
    -- file exists, send it

    lighty.content = { { filename = lighty.env["physical.path"] } }
  fi
  -- path doesn't exist ... rewrite it

  lighty.env["request.uri"] = "/dispatch.fcgi" 

  return RESTART_REQUEST

Usertracking
------------

... or how to store data globally in the script-context:

Each script has its own script-context. When the script is started it only contains the lua-functions
and the special lighty.* name-space. If you want to save data between script runs, you can use the global-script
context:

::

  if (nil == _G["usertrack"]) then
    _G["usertrack"] = {}
  end
  if (nil == _G["usertrack"][lighty.request["Cookie"]]) then
    _G["usertrack"][lighty.request["Cookie"]]
  else 
    _G["usertrack"][lighty.request["Cookie"]] = _G["usertrack"][lighty.request["Cookie"]] + 1
  end

  print _G["usertrack"][lighty.request["Cookie"]]

The global-context is per script. If you update the script without restarting the server, the context will still be maintained.

Counters
--------

mod_status support a global statistics page and mod_magnet allows to add and update values in the status page:

Config ::

  status.statistics-url = "/server-counters" 
  magnet.attract-raw-url-to = server.docroot + "/counter.lua" 

counter.lua ::

  lighty.status["core.connections"] = lighty.status["core.connections"] + 1

Result::

  core.connections: 7
  fastcgi.backend.php-foo.0.connected: 0
  fastcgi.backend.php-foo.0.died: 0
  fastcgi.backend.php-foo.0.disabled: 0
  fastcgi.backend.php-foo.0.load: 0
  fastcgi.backend.php-foo.0.overloaded: 0
  fastcgi.backend.php-foo.1.connected: 0
  fastcgi.backend.php-foo.1.died: 0
  fastcgi.backend.php-foo.1.disabled: 0
  fastcgi.backend.php-foo.1.load: 0
  fastcgi.backend.php-foo.1.overloaded: 0
  fastcgi.backend.php-foo.load: 0

Porting mod_cml scripts
-----------------------

mod_cml got replaced by mod_magnet.

A CACHE_HIT in mod_cml::

  output_include = { "file1", "file2" } 

  return CACHE_HIT

becomes::

  content = { { filename = "/path/to/file1" }, { filename = "/path/to/file2"} }

  return 200

while a CACHE_MISS like::

  trigger_handler = "/index.php" 

  return CACHE_MISS

becomes::

  lighty.env["request.uri"] = "/index.php" 

  return RESTART_REQUEST

}}}

Updated by jan about 18 years ago · 7 revisions