An implementation of Session that works on real cgi connections utilizing the BasicDataServer.
This is NOT ACTUALLY an input range! It is too different. Historical mistake kinda.
The main interface with the web request
A helper test class for request handler unittests.
Base class for REST collections.
thrown when a connection is closed remotely while we waiting on data from it
To use this thing:
A mock object that works like the real session, but doesn't actually interact with any actual database or http connection. Simply stores the data in its instance members.
You can throw this from an api handler to indicate a 404 response. This is done by the presentExceptionAsHtml function in the presenter.
The base of all REST objects, to be used with serveRestObject and serveRestCollectionOf.
The base class for the dispatcher function and object support.
A web presenter is responsible for rendering things to HTML to be usable in a web browser.
WEBSOCKET SUPPORT:
UDA used to indicate to the dispatcher that a trailing slash should always be added to or removed from the url. It will do it as a redirect header as-needed.
This is the function GenericMain calls. View its source for some simple boilerplate you can copy/paste and modify, or you can call it yourself from your main.
breaks down a url encoded string
breaks down a url encoded string, but only returns the last value of any array
Default host for listening. 127.0.0.1 for scgi, null (aka all interfaces) for all others. If you want the server directly accessible from other computers on the network, normally use null. If not, 127.0.0.1 is a bit better. Settable with default handlers with --listening-host command line argument.
Returns the default listening port for the current cgi configuration. 8085 for embedded httpd, 4000 for scgi, irrelevant for others.
Dispatches the URL (and anything under it) to another dispatcher function. The function should look something like this:
use this for testing or other isolated things when you want it to be no-ops
url encodes the whole string
url encodes a whole string
Dispatches the URL to a specific function.
Makes a data:// uri that can be used as links in most newer browsers (IE8+).
Encodes all but the explicitly unreserved characters per rfc 3986 Alphanumeric and -_.~ are the only ones left unencoded name is borrowed from php
Serves a class' methods, as a kind of low-state RPC over the web. To be used with dispatcher.
Redirects one url to another
Serves a REST object, similar to a Ruby on Rails resource.
Serves static data. To be used with dispatcher.
Serves a static file. To be used with dispatcher.
This serves a directory full of static files, figuring out the content-types from file extensions. It does not let you to descend into subdirectories (or ascend out of it, of course)
Tries to simulate a request from the command line. Returns true if it does, false if it didn't find the args.
Direct interface to the basic data add-on server. You can typically use Cgi.getSessionObject as a more convenient interface.
You can customize your server by subclassing the appropriate server. Then, register your subclass at compile time with the registerEventIoServer template, or implement your own main function and call it yourself.
A convenience object for talking to the BasicDataServer from a higher level. See: Cgi.getSessionObject.
Base for storing sessions in an array. Exists primarily for internal purposes and you should generally not use this.
If you want to use a subclass of Cgi with generic main, use this mixin.
Boilerplate mixin for a main function that uses the dispatcher function.
If you are doing a custom cgi class, mixing this in can take care of the required constructors for you
Use this instead of writing your own main
The stack size when a fiber is created. You can set this from your main or from a shared static constructor to optimize your memory use if you know you don't need this much space. Be careful though, some functions use more stack space than you realize and a recursive function (including ones like in dom.d) can easily grow fast!
This is meant to be returned by a function that takes a form POST submission. You want to set the url of the new resource it created, which is set as the http Location header for a "201 Created" result, and you can also set a separate destination for browser users, which it sets via a "Refresh" header.
UDA: default format to respond for this method
Used exclusively with dispatchTo
UDA: The name displayed to the user in auto-generated HTML.
Can return one of the given types, decided at runtime. The syntax is to declare all the possible types in the return value, then you can return typeof(return)(...value...) to construct it.
You can return this from WebObject subclasses for redirections.
A server control and configuration struct, as a potential alternative to calling GenericMain or cgiMainImpl. See the source of cgiMainImpl to an example of how you can use it.
See schedule to make one of these. You then call one of the methods here to set it up:
Represents a url that can be broken down or built up through properties
UDA: The name used in the URL or web parameter.
This can be attached to any constructor or function called from the cgi system.
Implies POST path for the thing itself, then GET will get the automatic form.
A URL dispatcher.
First step to schedule a job on the scheduled job server.
If you are using dub, use:
subConfiguration "arsd-official:cgi" "VALUE_HERE"
or to dub.json:
"subConfigurations": {"arsd-official:cgi": "VALUE_HERE"}
to change versions. The possible options for VALUE_HERE are:
With dmd, use:
Interfaces | (mutually exclusive) |
---|---|
-version=plain_cgi | The default building the module alone without dub - a traditional, plain CGI executable will be generated. |
-version=embedded_httpd | A HTTP server will be embedded in the generated executable. This is default when building with dub. |
-version=fastcgi | A FastCGI executable will be generated. |
-version=scgi | A SCGI (SimpleCGI) executable will be generated. |
-version=embedded_httpd_threads | The embedded HTTP server will use a single process with a thread pool. (use instead of plain embedded_httpd if you want this specific implementation) |
-version=embedded_httpd_processes | The embedded HTTP server will use a prefork style process pool. (use instead of plain embedded_httpd if you want this specific implementation) |
-version=embedded_httpd_processes_accept_after_fork | It will call accept() in each child process, after forking. This is currently the only option, though I am experimenting with other ideas. You probably should NOT specify this right now. |
-version=stdio_http | The embedded HTTP server will be spoken over stdin and stdout. |
Tweaks | (can be used together with others) |
-version=cgi_with_websocket | The CGI class has websocket server support. |
-version=with_openssl | not currently used |
-version=cgi_embedded_sessions | The session server will be embedded in the cgi.d server process |
-version=cgi_session_server_process | The session will be provided in a separate process, provided by cgi.d. |
For CGI, dmd yourfile.d cgi.d then put the executable in your cgi-bin directory.
For FastCGI: dmd yourfile.d cgi.d -version=fastcgi and run it. spawn-fcgi helps on nginx. You can put the file in the directory for Apache. On IIS, run it with a port on the command line (this causes it to call FCGX_OpenSocket, which can work on nginx too).
For SCGI: dmd yourfile.d cgi.d -version=scgi and run the executable, providing a port number on the command line.
For an embedded HTTP server, run dmd yourfile.d cgi.d -version=embedded_httpd and run the generated program. It listens on port 8085 by default. You can change this on the command line with the --port option when running your program.
You can also simulate a request by passing parameters on the command line, like:
./yourprogram GET / name=adr
And it will print the result to stdout.
On Apache, you may do SetHandler cgi-script in your .htaccess file.
cgi.d works well with dom.d for generating html. You may also use web.d for other utilities and automatic api wrapping.
dom.d usage:
import arsd.cgi; import arsd.dom; void hello_dom(Cgi cgi) { auto document = new Document(); static import std.file; // parse the file in strict mode, requiring it to be well-formed UTF-8 XHTML // (You'll appreciate this if you've ever had to deal with a missing </div> // or something in a php or erb template before that would randomly mess up // the output in your browser. Just check it and throw an exception early!) // // You could also hard-code a template or load one at compile time with an // import expression, but you might appreciate making it a regular file // because that means it can be more easily edited by the frontend team and // they can see their changes without needing to recompile the program. // // Note on CTFE: if you do choose to load a static file at compile time, // you *can* parse it in CTFE using enum, which will cause it to throw at // compile time, which is kinda cool too. Be careful in modifying that document, // though, as it will be a static instance. You might want to clone on on demand, // or perhaps modify it lazily as you print it out. (Try element.tree, it returns // a range of elements which you could send through std.algorithm functions. But // since my selector implementation doesn't work on that level yet, you'll find that // harder to use. Of course, you could make a static list of matching elements and // then use a simple e is e2 predicate... :) ) document.parseUtf8(std.file.read("your_template.html"), true, true); // fill in data using DOM functions, so placing it is in the hands of HTML // and it will be properly encoded as text too. // // Plain html templates can't run server side logic, but I think that's a // good thing - it keeps them simple. You may choose to extend the html, // but I think it is best to try to stick to standard elements and fill them // in with requested data with IDs or class names. A further benefit of // this is the designer can also highlight data based on sources in the CSS. // // However, all of dom.d is available, so you can format your data however // you like. You can do partial templates with innerHTML too, or perhaps better, // injecting cloned nodes from a partial document. // // There's a lot of possibilities. document["#name"].innerText = cgi.request("name", "default name"); // send the document to the browser. The second argument to `cgi.write` // indicates that this is all the data at once, enabling a few small // optimizations. cgi.write(document.toString(), true); }
Concepts: Input: Cgi.get, Cgi.post, Cgi.request, Cgi.files, Cgi.cookies, Cgi.pathInfo, Cgi.requestMethod, and HTTP headers (Cgi.headers, Cgi.userAgent, Cgi.referrer, Cgi.accept, Cgi.authorization, Cgi.lastEventId)
Output: Cgi.write, Cgi.header, Cgi.setResponseStatus, Cgi.setResponseContentType, Cgi.gzipResponse
Cookies: Cgi.setCookie, Cgi.clearCookie, Cgi.cookie, Cgi.cookies
Caching: Cgi.setResponseExpires, Cgi.updateResponseExpires, Cgi.setCache
Redirections: Cgi.setResponseLocation
Other Information: Cgi.remoteAddress, Cgi.https, Cgi.port, Cgi.scriptName, Cgi.requestUri, Cgi.getCurrentCompleteUri, Cgi.onRequestBodyDataReceived
Overriding behavior: Cgi.handleIncomingDataChunk, Cgi.prepareForIncomingDataChunks, Cgi.cleanUpPostDataState
Installing: Apache, IIS, CGI, FastCGI, SCGI, embedded HTTPD (not recommended for production use)
If you are coming from PHP, here's a quick guide to help you get started:
<?php $foo = $_POST["foo"]; $bar = $_GET["bar"]; $baz = $_COOKIE["baz"]; $user_ip = $_SERVER["REMOTE_ADDR"]; $host = $_SERVER["HTTP_HOST"]; $path = $_SERVER["PATH_INFO"]; setcookie("baz", "some value"); echo "hello!"; ?> | import arsd.cgi; void app(Cgi cgi) { string foo = cgi.post["foo"]; string bar = cgi.get["bar"]; string baz = cgi.cookies["baz"]; string user_ip = cgi.remoteAddress; string host = cgi.host; string path = cgi.pathInfo; cgi.setCookie("baz", "some value"); cgi.write("hello!"); } mixin GenericMain!app |
In PHP, you can give a form element a name like "something[]", and then $_POST["something"] gives an array. In D, you can use whatever name you want, and access an array of values with the cgi.getArray["name"] and cgi.postArray["name"] members.
PHP has a lot of stuff in its standard library. cgi.d doesn't include most of these, but the rest of my arsd repository has much of it. For example, to access a MySQL database, download database.d and mysql.d from my github repo, and try this code (assuming, of course, your database is set up):
import arsd.cgi; import arsd.mysql; void app(Cgi cgi) { auto database = new MySql("localhost", "username", "password", "database_name"); foreach(row; mysql.query("SELECT count(id) FROM people")) cgi.write(row[0] ~ " people in database"); } mixin GenericMain!app;
Similar modules are available for PostgreSQL, Microsoft SQL Server, and SQLite databases, implementing the same basic interface.
You may also want to see arsd.dom, arsd.web, and arsd.html for more code for making web applications.
For working with json, try arsd.jsvar.
arsd.database, arsd.mysql, arsd.postgres, arsd.mssql, and arsd.sqlite can help in accessing databases.
If you are looking to access a web application via HTTP, try std.net.curl, arsd.curl, or arsd.http2.
cgi.d copyright 2008-2022, Adam D. Ruppe. Provided under the Boost Software License.
Yes, this file is old, and yes, it is still actively maintained and used.
Provides a uniform server-side API for CGI, FastCGI, SCGI, and HTTP web applications.
Test on console (works in any interface mode):
If using http version (default on dub builds, or on custom builds when passing -version=embedded_httpd to dmd):
Please note: the default port for http is 8085 and for cgi is 4000. I recommend you set your own by the command line argument in a startup script instead of relying on any hard coded defaults. It is possible though to hard code your own with RequestServer.