Permalink
Browse files

XML parsing library (initial commit)

  • Loading branch information...
1 parent 5ccf528 commit 1c5af81d225a1450cf11f35322fe8d4f4a0e1c62 @ToxicFrog committed Mar 21, 2012
Showing with 1,603 additions and 0 deletions.
  1. +38 −0 xml/README
  2. +288 −0 xml/cgi.lua
  3. +63 −0 xml/cgitest.cgi
  4. +5 −0 xml/download.txt
  5. +305 −0 xml/handler.lua
  6. +86 −0 xml/pretty.lua
  7. +159 −0 xml/testxml.lua
  8. +472 −0 xml/xml.lua
  9. +36 −0 xml/xmlrpc-lua.cgi
  10. +151 −0 xml/xmlrpclib.lua
View
@@ -0,0 +1,38 @@
+
+LuaXML-0.0.0
+============
+
+This is an initial release of LuaXML - a native XML parser for Lua.
+
+The code (and documentation) is not complete as yet however it is usable
+and this release is indended to avoid potential duplication between efforts
+and get early feedback.
+
+The API is relatively stable however there may be some detailed changes.
+
+The distribution comprises -
+
+ README - This file
+ xml.lua - Main XML parser module
+ handler.lua - Standard XML handlers
+ testxml.lua - Command line test tool
+ xmlrpclib.lua - XMLRPC marshaller/unmarshaller
+ (incomplete and now probably superseeded)
+ xmlrpc-lua.cgi - Test XML-RPC server (CGI)
+ cgi.lua - CGI module to support XMLRPC server
+ (will probably be packaged separately idc)
+ cgitest.cgi -
+ pretty.lua - Lua pretty printer [23/02/2001 jcw@equi4.com]
+
+Most of the modules are relatively well documented in the source - the key
+ones are 'xml.lua' & 'handler.lua'. The 'testxml.lua' utility is also
+useful for testing the modules.
+
+This is all being released a bit earlier than I would have liked due
+to all the current XML related activity on lua-l and as a result isnt
+quite as well packaged/docuemnted as I would like. I will be working
+on fixing this asp.
+
+Paul Chakravarti
+paulc@passtheaardvark.com
+28 Nov 2001
View
@@ -0,0 +1,288 @@
+---
+-- Overview:
+-- =========
+-- This module provide a CGI request parser library for Lua
+--
+-- Features:
+-- =========
+-- * Handles both 'application/x-www-form-urlencoded' and 'multipart/form-data' content-types
+-- * Handles file uploads
+-- * Handles multi-valued fields
+-- * Optional hooks for XML handler to handle 'text/xml' content-types (eg xmlrpc etc)
+-- * Parses request data into following tables
+-- self.env - CGI Environment
+-- self.headers - Request Headers
+-- self.fields - Form Data
+-- self.files - File Uploads
+-- self.xml - Parsed XML Data
+-- self.cookies - NOT IMPLEMENTED (yet)
+--
+-- As Lua by default cant iterate through env (can only
+-- read specific values) it is not possible to pass through
+-- non-standard env variables (eg HTTP_xxxx) other than those
+-- predefined below (_HTTP_ENV)
+--
+-- NOTE:
+-- I wasnt able to find a complete CGI library for Lua & also
+-- wanted to be able to handle file uploads and xml payloads so
+-- wrote this (LuaCGI only seemed to be available in binary and
+-- wasnt available for MacOSX). This was my first attempt at Lua
+-- so the code is pretty ugly (particularly the multipart mime
+-- handling) and needs to be refactored.
+--
+-- Limitations/Todo:
+-- =================
+-- * Restucture to meet LTN7 & refactor code
+-- * Cookie processing
+-- * Implement response object for output
+-- * Complete Docs(!)
+--
+-- API/Options/Usage:
+-- ==================
+-- [To follow - see code]
+--
+-- c = CGI()
+-- c.options.xxxx = ....
+-- c.parse()
+-- for k,v in pairs(c.fields) do print(k,v) end
+--
+-- [See cgitest.cgi for example]
+--
+-- License:
+-- ========
+-- This code is freely distributable under the terms of the Lua license
+-- (<a href="http://www.lua.org/copyright.html">http://www.lua.org/copyright.html</a>)
+--
+-- History
+-- =======
+-- $Id: cgi.lua,v 1.1.1.1 2001/11/28 06:11:33 paulc Exp $
+--
+-- $Log: cgi.lua,v $
+-- Revision 1.1.1.1 2001/11/28 06:11:33 paulc
+-- Initial Import
+--@author Paul Chakravarti (paulc@passtheaardvark.com)<p/>
+
+_CGI_ENV = { "AUTH_TYPE",
+ "CONTENT_LENGTH",
+ "CONTENT_TYPE",
+ "GATEWAY_INTERFACE",
+ "PATH_INFO",
+ "PATH_TRANSLATED",
+ "QUERY_STRING",
+ "REMOTE_ADDR",
+ "REMOTE_HOST",
+ "REMOTE_IDENT",
+ "REMOTE_USER",
+ "REQUEST_METHOD",
+ "SCRIPT_NAME",
+ "SERVER_NAME",
+ "SERVER_PORT",
+ "SERVER_PROTOCOL",
+ "SERVER_SOFTWARE",
+ }
+
+_HTTP_ENV = {
+ "HTTP_ACCEPT",
+ "HTTP_ACCEPT_CHARSET",
+ "HTTP_ACCEPT_ENCODING",
+ "HTTP_ACCEPT_LANGUAGE",
+ "HTTP_CACHE_CONTROL",
+ "HTTP_COOKIE",
+ "HTTP_COOKIE2",
+ "HTTP_FROM",
+ "HTTP_HOST",
+ "HTTP_NEGOTIATE",
+ "HTTP_PRAGMA",
+ "HTTP_REFERER",
+ "HTTP_USER_AGENT",
+}
+
+
+function CGI()
+ return {
+ env = {},
+ headers = {},
+ fields = {},
+ files = {},
+ cookies = nil,
+ xml = nil,
+ multipart = { offset = 1, boundary = "" },
+ buf = "",
+ rfile = _INPUT,
+ wfile = _OUTPUT,
+
+ options = {
+ parse_qs = 1,
+ max_post = 2000,
+ error_handler = function (x) _ALERT("CGI Error:"..x.."\n") end,
+ xml_parser = nil,
+ xml_parser_options = nil,
+ xml_handler = nil,
+ xml_handler_options = nil,
+ },
+
+ parse = function(self)
+ self:parse_env()
+ self.env.content_length = tonumber(self.env.content_length) or 0
+ if self.env.request_method == 'GET' or self.options.parse_qs then
+ self:parse_get()
+ end
+ if self.env.request_method == 'POST' then
+ if self.env.content_type == 'application/x-www-form-urlencoded' then
+ self:parse_post()
+ elseif strfind(self.env.content_type, 'multipart/form-data',1,1) then
+ self:parse_multipart()
+ elseif self.env.content_type == 'text/xml' then
+ if self.options.xml_parser and self.options.xml_handler then
+ self:parse_xml()
+ else
+ self.options.error_handler("Invalid Content-Type:"..self.env.content_type)
+ end
+ else
+ self.options.error_handler("Invalid Content-Type:"..self.env.content_type)
+ end
+ else
+ end
+ end,
+
+ parse_env = function(self)
+ foreach (_CGI_ENV, function (k,v) self.env[strlower(v)] = getenv(v) end)
+ foreach (_HTTP_ENV, function (k,v) self.headers[strlower(gsub(v,'HTTP_',''))] = getenv(v) end)
+ end,
+
+ parse_qs = function(self,qs)
+ local str = qs or ""
+ while str ~= "" do
+ local i,j,k,v = strfind(str,"(.-)=([^&]*)")
+ if i == nil then break end
+ self:insert_formval(self:decode_url(k),self:decode_url(v))
+ str = strsub(str,j+2)
+ end
+ end,
+
+ parse_get = function(self)
+ self:parse_qs(self.env.query_string)
+ end,
+
+ parse_post = function(self)
+ local len = self.env.content_length or 0
+ if self.options.max_post and len > self.options.max_post then
+ self.options.error_handler("Max Post Length Exceeded")
+ else
+ local qs = read(self.rfile,len)
+ self:parse_qs(qs)
+ end
+ end,
+
+ parse_xml = function(self)
+ local handler = self.options.xml_handler()
+ if self.options.xml_handler_options then
+ handler.options = self.options.xml_handler_options
+ end
+ local parser = self.options.xml_parser(handler)
+ if self.options.xml_parser_options then
+ parser.options = self.options.xml_parser_options
+ end
+ local len = self.env.content_length or 0
+ if self.options.max_post and len > self.options.max_post then
+ self.options.error_handler("Max Post Length Exceeded")
+ else
+ local xml = read(self.rfile,len)
+ parser:parse(xml)
+ self.xml = handler.root
+ end
+ end,
+
+ parse_multipart = function(self)
+ local _,_,bdy = strfind(self.env.content_type,[[[Bb]oundary="?([^";,]+)"?]])
+ self.multipart.boundary = "--"..(bdy or "")
+ local len = self.env.content_length or 0
+ if self.options.max_post and len > self.options.max_post then
+ self.options.error_handler("Max Post Length Exceeded")
+ else
+ self.buf = read(self.rfile,len)
+ while self:read_part() do end
+ self.buf = nil
+ end
+ end,
+
+ read_part = function(self)
+ local start,ends,data,name,filename,key,val,_
+ -- Get multipart header
+ starts,ends = strfind(self.buf,self.multipart.boundary.."\r\n",self.multipart.offset,1)
+ if starts ~= self.multipart.offset then
+ self.options.error_handler("Invalid Multipart Data: Boundary Not Found")
+ return nil
+ else
+ self.multipart.offset = ends + 1
+ end
+ -- Get header fields
+ while 1 do
+ starts,ends,data = strfind(self.buf,"(.-)\r\n",self.multipart.offset)
+ if starts ~= self.multipart.offset then
+ self.options.error_handler("Invalid Multipart Data: Headers Not Found")
+ return nil
+ elseif data == "" then
+ self.multipart.offset = ends + 1
+ break
+ else
+ if strlower(strsub(data,1,19)) == 'content-disposition' then
+ _,_,name = strfind(data,[[[Nn]ame="?([^";,]+)"?]])
+ _,_,filename = strfind(data,[[[Ff]ilename="?([^";,]+)"?]])
+ if filename then
+ self.files[name] = {}
+ self.files[name].filename = filename
+ end
+ elseif filename then
+ _,_,key,val = strfind(data,"(.-):%s+(.+)")
+ self.files[name][key] = val
+ end
+ self.multipart.offset = ends + 1
+ end
+ end
+ -- Get data
+ starts,ends = strfind(self.buf,"\r\n"..self.multipart.boundary,self.multipart.offset,1)
+ if starts then
+ data = strsub(self.buf,self.multipart.offset,starts - 1)
+ if filename then
+ self.files[name].data = data
+ else
+ self:insert_formval(name,data)
+ end
+ if strsub(self.buf,ends+1,ends+2) == "--" then
+ return nil
+ else
+ self.multipart.offset = starts + 2
+ end
+ else
+ self.options.error_handler("Invalid Multipart Data: End Separator Not Found")
+ return nil
+ end
+ return 1
+ end,
+
+ insert_formval = function(self,key,val)
+ local cval = self.fields[key]
+ if type(cval) == 'nil' then
+ self.fields[key] = val
+ elseif type(cval) == 'string' then
+ self.fields[key] = {cval,val}
+ elseif type(cval) == 'table' then
+ cval[getn(cval)+1] = val
+ self.fields[key] = cval
+ else
+ self.options.error_handler("Field Type Error")
+ end
+ end,
+
+ hexchar = function(x)
+ return string.char(tonumber(x,16))
+ end,
+
+ decode_url = function(self,s)
+ s = string.gsub(s,"+"," ")
+ s = string.gsub(s,"%%(%x%x)",self.hexchar)
+ return s
+ end,
+ }
+end
View
@@ -0,0 +1,63 @@
+#!/usr/bin/lua
+
+dofile("cgi.lua")
+dofile("xml.lua")
+dofile("handler.lua")
+dofile("pretty.lua")
+
+c = CGI()
+c.options.xml_parser = xmlParser
+c.options.xml_handler = simpleTreeHandler
+c:parse()
+
+print [[Content-Type: text/plain
+
+LUA CGI
+=======
+
+Env:
+---
+]]
+
+for k,v in pairs(c.env) do
+ io.write(string.format("%-20s : %s\n",k,v))
+end
+
+print [[
+Headers:
+--------
+]]
+
+for k,v in pairs(c.headers) do
+ io.write(string.format("%-20s : %s\n",k,v))
+end
+
+print [[
+Fields:
+-------
+]]
+
+for k,v in pairs(c.fields) do
+ io.write(string.format("%-20s : %s\n",k,v))
+end
+
+print [[
+Files:
+-------
+]]
+
+for k,v in pairs(c.files) do
+ io.write(string.format("%-20s : %s\n","Name",k))
+ for k,v2 in pairs(v) do
+ if k ~= 'data' then
+ io.write(string.format("%-20s : %s\n",k,v2))
+ end
+ end
+end
+
+print [[
+XML:
+----
+]]
+
+pretty("XML", c.xml)
View
@@ -0,0 +1,5 @@
+Versão adaptada para Lua 5.x apartir de
+http://lua-users.org/wiki/LuaXml
+
+Download
+http://manoelcampos.com/files/LuaXML-0.0.0-lua5.1.tgz
Oops, something went wrong.

0 comments on commit 1c5af81

Please sign in to comment.