#ifndef __SCGI_H_ #define __SCGI_H_ #include "../shared/MiscSupport.h" // This is some fairly generic sopport for an SCGI server. This doesn't know // anything about the threading model, sockets, etc. This is responsible // for marshalling and unmarshalling messages. // This protocol is spelled out in http://python.ca/scgi/protocol.txt // To attach an SCGI program to Apache see // http://httpd.apache.org/docs/2.3/mod/mod_proxy.html#proxypass // and // http://httpd.apache.org/docs/2.3/mod/mod_proxy_scgi.html // Similar documentation for lighttpd: // http://redmine.lighttpd.net/wiki/1/Docs:ModProxyCore class ScgiFromServer { private: PropertyList _headers; std::string _body; std::string _toParse; std::string _errorMsg; int _sectionLength; enum InternalState { InitialState, BadState, ReadHeadersState, ReadBodyState, DoneState }; InternalState _internalState; void parseHeaderLength(); void parseHeader(); void parseBody(); void parse(); std::string rootDirNoSlash() const; std::string relativeName() const; public: ScgiFromServer() : _internalState(InitialState) { } PropertyList const &getHeaders() const { return _headers; } std::string const &getBody() const { return _body; } bool success() const { return _internalState == DoneState; } bool error() const { return _internalState == BadState; } bool done() const { return success() || error(); } void addBytes(std::string const &bytes); TclList debugDump(); void getGetValues(PropertyList &addTo) const; void getPostValues(PropertyList &addTo) const; // This is the absolute addess of the root directory of server. For example // http://www.trade-ideas.com/ This is useful when you want to give a // relative link but you have to give an abolute link. For example, you // don't know if you're on the live or test server, and you want the link // to be on the same server, and you sending the url in a location header, // or displaying it on the screen for the user to see. std::string httpRootDir() const; // This is the absolute address of the directory containing the current // script. It is useful in similar cases to httpRootDir(). It always // ends with a slash. std::string locationBase() const; // This is the file name of the current script, without the directory. // locationBase() + shortScriptName() + '?' + getHeaders()["QUERY_STRING"] // will give you an absolute url matching the original request. This // is helpful because one C++ program might be doing the job traditionally // done by several php scripts. The program can look at the // shortScriptName() to see which (virtual) scirpt the user is trying to // access. std::string shortScriptName() const; // In the HTTP server config file, there are instructions to give a subtree // of the URL space to our program. For example, the config file might // name "/TI/HighPerformance.php". Then any user trying to access // "/TI/HighPerformance.php", "/TI/HighPerformance.php/", or even // "/TI/HighPerformance.php/images/recent/DELL.png?bars=10&time=daily" will // have his request forwarded to the SCGI program. I call // "/TI/HighPerformance.php" the mount point. It's up to the SCGI developer // whether to treat the mount point as a single script or a virtual directory // filled with scripts. Note: Even when I specify a "location" in Apache of // "/jsproxy/", the mountPoint still comes through as "/jsproxy". std::string mountPoint() const; // relativePath() tells you the path of the virtual script file relative to // the mountPoint(). You can easily look at the relative path to decide // which (virtual) script to execute. This allows you to have a whole // directory tree of scripts that all know how to access each other. The // web server administrator can change the mount point to move all of the // scripts at once, leaving the relative links in tact. // // In Apache relativePath() always starts with a slash. Sometimes it starts // with two slashes! If you say // // ProxyPass scgi://chuck-liddell:4433/ // // Then you can acess http://servername/jsproxy or http://servername/jsproxy/ // or http://servername/jsproxy/x/y?z=1. In the first case you will be // automatically redirected to http://servername/jsproxy/. In the second // case, you will see "/jsproxy" for the mountPoint() and "/" for the // relativePath(). In the third case you will see "/jsproxy" for the // mountPoint() and "/x/y" for the relativePath(); // // If instead you say // ProxyPass /jsproxy/ scgi://chuck-liddell:4433/ // (without the location tag) the first case will give a 404 rather than // a redirect, but the other two cases will work exacty the same as before. // // If you say // ProxyPass /jsproxy scgi://chuck-liddell:4433/ // (no trailing slash) then you see something different. // In this case you can acess http://servername/jsproxy or // http://servername/jsproxy/ or http://servername/jsproxy/x/y?z=1. In the // first case you will not get redirected and relativePath() will be "/". // In the second and third cases relativePath() will return "//" and "//x/y" // respectively. // // Note that mountPoint() returns the same thing (including a trailing slash) // for all three methods. But relativePath() returns an extra leading slash // for the third method. // // Apache recommends the location tag for performance. The third method // seems applicable if you wanted to look like a single file, i.e. if you // were replacing a single php script with an SCGI program and not changing // the clients. std::string relativePath() const; // Note: When I switched to lighttpd, I could not make relativePath() // or mountPoint() work as expected. PATH_INFO always comes to me as "" // and SCRIPT_NAME as the entire thing, i.e // "http://dice/jsproxy/Info.tcl?destination=live" => "/jsproxy/Info.tcl" // This is how I'm configuring lighttpd: // scgi.server = ("/jsproxy/" => // (( "host" => "192.168.1.219", // "port" => 4433, // "check-local" => "disable")) // ) }; class ScgiToServer { public: PropertyList _headers; std::string _body; void reset(); ScgiToServer() { reset(); } std::string toString() const; void setStatusOK(); void setStatusNotFound(); void setStatusMoved(std::string const &location); void setContentType(std::string const &type); void setContentTypeHtmlUtf8(); void setContentTypePlainUtf8(); void setContentTypeXml(); void allowCrossOriginRequests(); }; #endif