REBOL [
       Title: "Safe CGI data retriever"
       Date: 21-may-2006
       File: %safe-cgi-data-read.r
     Author: "Sunanda"
    Version: 0.0.2
    Purpose: {
        Safely retrieves CGI GET or POST data
        into a REBOL object.
   }

    library: [
      level: 'intermediate
      platform: 'all
      type: [function how-to tool]
      domain: [cgi other-net]
      tested-under: [Windows UNIX]
      support: none
      license: 'mit
      see-also: none
    ]
    
    History: [
            0.0.1 21-may-2006 "Sunanda" "first release"
            0.0.2 22-jun-2011 "Sunanda" "tweak by Peter Wood to allow running from console"
            ]
]

safe-cgi-data-read: func [ "Safe way to read CGI parameter data"
      /template template-obj [object!] "Default values"
      /keep-blocks "Do not collapse blocks to strings"
      /no-trim   "Do not trim whitespace"
      /refresh  "Do not use cached data"
      /local
           cgi-string
           cgi-block
           cgi-object
           read-cgi
           temp
][

;; -----------------------------
;; Inner function -- copied from
;; http://www.rebol.com/docs/words/wread-io.html
;; ---------------------------------------------

read-cgi: func [
	;Read CGI data. Return data as string or NONE.
	/local data buffer
][
	switch system/options/cgi/request-method [
		"POST" [
			data: make string! 1020
			buffer: make string! 16380
			while [positive? read-io system/ports/input buffer 16380][
				append data buffer
				clear buffer
			]
		]
		"GET" [data: system/options/cgi/query-string]
        #[none] [data: system/script/args]	     ;; 0.0.2 -- Peter Wood's tweak
	]
	data
]


;; -------------------------
;; mainline code starts here
;; -------------------------
     ;; -----------------------------------
     ;; Read CGI -- unless we had it cached
     ;; already from a previous invocation
     ;; -----------------------------------

 cgi-string: ""
 if refresh [clear cgi-string]
 if cgi-string = "" [temp: read-cgi if string? temp [append cgi-string temp]]

    ;; ------------------------------------------
    ;; preprocess to fix bad ampersands and SELF=
    ;; ------------------------------------------

 insert cgi-string "&"            ;; insert to make life easier
 while [find cgi-string "&&"] [replace/all cgi-string "&&" "&"]
 replace cgi-string "&self=" "&__self="
 cgi-string: copy next cgi-string ;; drop the inserted ampersand

    ;; ------------------------------
    ;; create a block with decode-cgi
    ;; ------------------------------
    ;; This may fail if the parameters
    ;; are badly formed -- like
    ;; "&=1"
    ;; decode-cgi may also return NONE
    ;; or a zero-length string if is no
    ;; cgi data to read

 cgi-block: copy []
 attempt [cgi-block: decode-cgi cgi-string]
 if not block? cgi-block [cgi-block: copy []]

   ;; ---------------------------------------
   ;; Post-process the resulting data fields:
   ;; ---------------------------------------
   ;; -- changing blocks to strings, if requested
   ;; -- trimming whitespace, if requested

 for n 2 length? cgi-block 2 [
    temp: cgi-block/:n
    if all [not keep-blocks
            block? temp][
         temp: form temp
        ]
    if all [string? temp not no-trim] [trim/lines temp]
    poke cgi-block n temp
    ]


   ;; ----------------------------
   ;; Heft into object, and return
   ;; ----------------------------

 if not template [return make object! cgi-block]
 return construct/with cgi-block template-obj
]