Home modules.gotpike.org
Username: Password: [Create Account]
[Forgot Password?]

Modules

ADT
Database
GTK2
GUI
IP
PiJAX
Public
Sql
Stdio
Subversion
System
Tools
Xosd
lua
v4l2
wx

Recent Changes

Public.Parser.XML2 1.50
Public.ZeroMQ 1.1
Public.Template.Mustache 1.0
Public.Protocols.XMPP 1.4
Sql.Provider.jdbc 1.0

Popular Downloads

Public.Parser.JSON2 1.0
Public.Parser.JSON 0.2
GTK2 2.23
Public.Web.FCGI 1.8
Public.Parser.XML2 1.48


Module Information
Public.Web.FCGI
Viewing contents of Public_Web_FCGI-1.3/module.pmod.in

/*
 * Copyright (c) 2006 Adam Montague 
 *
 * Permission to use, copy, modify, and distribute this software for any
 * purpose with or without fee is hereby granted, provided that the above
 * copyright notice and this permission notice appear in all copies.
 *
 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 */

constant __author = "Adam Montague ";
constant __version = "1.3";

inherit .___FCGI;

mapping(string:string|array(string)) decode_url_mapping(string s, string|void delim)
{
	mapping(string:string|array(string)) ret = ([]);
	string key, value;
	foreach (s / (delim || "&");; string s) {
		if (sscanf(s, "%s=%s", key, value) < 2) {
			key = decode_url(s);
			value = "";
		} else {
			key = decode_url(key);
			value = decode_url(value);
		}
		if (stringp(ret[key])) {
			ret[key] = ({ ret[key], value });
		} else if (arrayp(ret[key])) {
			ret[key] += ({ value });
		} else {
			ret[key] = value;
		}
	}
	return make_mappings(ret);
}

private mapping(string:string|array(string)|mapping(string:string|array(string))) make_mappings(mapping(string:string|array(string)) arg)
{
	mapping(string:string|array(string)|mapping(string:string|array(string))) ret = arg;
	string newkey, subkey;
	string|array(string) value;
	foreach (ret; string key; string|array(string) value) {
		if (sscanf(key, "%s[%s]", newkey, subkey) == 2) {
			value = m_delete(ret, key);
			if (!ret[newkey]) {
				ret[newkey] = ([ ]);
			}
			ret[newkey] += ([ subkey:value ]);
		}
	}
	return ret;
}

/*! @decl int max_post_size
/*!   The maximum size of post requests that will be accepted.
 */
int max_post_size = 5242880;		// 5MB
/*! @decl string tmp_dir
/*!   Directory where uploaded files will be written to.
 */
string tmp_dir = "/tmp";
/*! @decl mapping(string:string) default_headers
/*!   Default headers that will be sent to the client with each request.
 */
mapping(string:string) default_headers = ([
    "Content-type":"text/html"
]);

constant STATUS_200 = "200 OK";
constant STATUS_301 = "301 Moved Permanently";
constant STATUS_302 = "302 Found";
constant STATUS_304 = "304 Not Modified";
constant STATUS_307 = "307 Temporary Redirect";
constant STATUS_400 = "400 Bad Request";
constant STATUS_401 = "401 Unauthorized";
constant STATUS_403 = "403 Forbidden";
constant STATUS_404 = "404 Not Found";
constant STATUS_500 = "500 Internal Server Error";

constant POST_TOO_BIG = 2;
constant POST_ABORTED = 3;

class FCGI
{
	inherit .___FCGI.FCGI;

	private int max_post = max_post_size;
	private string tmp = tmp_dir;
	private mapping(string:string|array(string)) my_default_headers = default_headers;

/*! @decl mapping(string:string|array(string)) get
/*!   A mapping of all the GET paramaters sent with this request.
 */
	mapping(string:string|array(string)|mapping(string:string|array(string))) get = ([]);
/*! @decl mapping(string:string|array(string)) post
/*!   A mapping of all the POST paramaters sent with this request.
 */
	mapping(string:string|array(string)|mapping(string:string|array(string))) post = ([]);
	mapping(string:string|array(string)|mapping(string:string|array(string))) oldpost = ([]);
/*! @decl mapping(string:mapping(string:string|int)) files
/*!   A mapping of all the files uploaded with this request.
 */
	mapping(string:mapping(string:string|int)) files = ([]);
/*! @decl mapping(string:string|array(string)) cookies
/*!   A mapping of all the cookies sent with this request.
 */
	mapping(string:string|array(string)|mapping(string:string|array(string))) cookies = ([]);
/*! @decl mapping(string:string|array(string)) headers
/*!   A mapping of HTTP headers to be sent to the client for this request.
 */
	mapping(string:string|array(string)) headers = my_default_headers;
/*! @decl string status
/*!   HTTP status to be sent to the client for this request.
 */
	string status = STATUS_200;

	int accept()
	{
		int ret;

		if (!(ret = ::accept())) {
			return 0;
		}
		if (env["QUERY_STRING"] && sizeof(env["QUERY_STRING"])) {
			get = decode_url_mapping(env["QUERY_STRING"]);
		}
		if (env["HTTP_COOKIE"]) {
			cookies = decode_url_mapping(env["HTTP_COOKIE"], "; ");
			cookies = map(cookies, lambda(string|array(string) arg) {
                                if (stringp(arg)) {
                                        if (arg[0..8] == "__encoded") {
                                                return decode_value(MIME.decode_base64(arg[9..]));
                                        } else {
                                                return arg;
                                        }
                                } else {
					return (map(arg, lambda(string arg) {
                                                if (arg[0..8] == "__encoded") {
                                                        return decode_value(MIME.decode_base64(arg[9..]));
                                                } else {
                                                        return arg;
                                                }
                                        }));
                                }
                        });
		}
		if (env["REQUEST_METHOD"] && env["REQUEST_METHOD"] == "POST" && env["CONTENT_LENGTH"]) {
			if ((int)env["CONTENT_LENGTH"] > max_post) {
				return POST_TOO_BIG;
			}
			string input = read((int)env["CONTENT_LENGTH"]);
			if (sizeof(input) < (int)env["CONTENT_LENGTH"]) {
				return POST_ABORTED;
			}
			if (env["CONTENT_TYPE"] && lower_case(env["CONTENT_TYPE"][0..18]) == "multipart/form-data") {
				MIME.Message mesg = MIME.Message(input, ([ "content-type":env["CONTENT_TYPE"] ]));
				foreach (mesg->body_parts || ({ });; MIME.Message part) {
					string name = part->disp_params["name"];
					if (part->disp_params["filename"]) {
						string data = part->getdata();
						if (sizeof(data)) {
							string tmpname = combine_path(tmp, "pike_fcgi.");
							for (int i = 0; i < 10; i++) {
								tmpname += String.int2char(random(26) + 65);
							}
							Stdio.File file;
							file = Stdio.File(tmpname, "wxc", 0600);
							if (file->write(data) < sizeof(data)) {
								file->close();
								rm(tmpname);
								error("Writing uploaded file failed (disk full?)\n");
							}
							file->close();
							files[name] = ([
							    "tmpname":tmpname,
							    "filename":part->disp_params["filename"],
							    "type":part->type + "/" + part->subtype,
							    "size":sizeof(data)
							]);
						}
					} else {
						if (stringp(post[name])) {
							post[name] = ({ post[name], part->getdata() });
						} else if (arrayp(post[name])) {
							post[name] += ({ part->getdata() });
						} else {
							post[name] = part->getdata();
						}
					}
				}
			} else {
				post = decode_url_mapping(input);
			}
		}
		return ret;
	}

	function write = first_write;
	int first_write(string data, mixed ... extras)
	{
		string s = status + "\r\n";
		foreach (headers; string key; string|array(string) value) {
			foreach (Array.arrayify(value);; string v) {
				s += key + ": " + v + "\r\n";
			}
		}
		write = real_write;
		write(s + "\r\n");
		return write(data);
	}

	void finish()
	{
		if (write == first_write) {
			write("");
		}
		write = first_write;
		get = ([]);
		post = ([]);
		env = ([]);
		cookies = ([]);
		headers = my_default_headers;
		foreach (files; string name; mapping(string:string|int) file) {
			rm(file["tmpname"]);
		}
		files = ([]);
		::finish();
	}

	void set_cookie(string key, mixed value, mapping(string:string|int)|void options)
	{
		if (write != first_write) {
			error("Headers already sent.\n");
		}
		string val;
		string extra = "";
		key = String.trim_all_whites(key);

		if (!options) {
			options = ([ ]);
		}

		if (stringp(value)) {
			val = Protocols.HTTP.http_encode_cookie(value);
		} else {
			val = "__encoded" + Protocols.HTTP.http_encode_cookie(MIME.encode_base64(encode_value(value), 1));
		}

		if (options["expires"] && intp(options["expires"])) {
			extra += "; expires=" + Protocols.HTTP.Server.http_date(options["expires"]);
		}
		if (stringp(options["path"])) {
			extra += "; path=" + options["path"];
		}
		if (stringp(options["domain"])) {
			extra += "; domain=" + options["domain"];
		}
		if (options["secure"]) {
			extra += "; secure";
		}

		val = key + "=" + val + extra;

		if (stringp(headers["Set-Cookie"])) {
			headers["Set-Cookie"] = ({ headers["Set-Cookie"], val });
		} else if (arrayp(headers["Set-Cookie"])) {
			headers["Set-Cookie"] += ({ val });
		} else {
			headers["Set-Cookie"] = val;
		}
	}
}


gotpike.org | Copyright © 2004 - 2019 | Pike is a trademark of Department of Computer and Information Science, Linköping University