Сцэнарый
cFos Personal Net падтрымлівае сцэнарызм альбо праз агульны інтэрфейс шлюза (CGI), альбо праз убудаваны сцэнарый у JavaScript (альбо на іншай мове, якая падтрымлівае хост сцэнарыяў Windows, напрыклад, ActivePerl, ActivePython і г.д.).
CGI вызначае пэўныя зменныя асяроддзі, якія ўтрымліваюць інфармацыю пра бягучы запыт HTTP. cFos PNet ўсталёўвае гэтыя зменныя перад выкананнем сцэнарыя:
REMOTE_USER, AUTH_TYPE, SERVER_SOFTWARE, SERVER_PROTOCOL, GATEWAY_INTERFACE, DOCUMENT_ROOT, CONTENT_LENGTH, CONTENT_TYPE, REMOTE_ADDR, REMOTE_PORT, SERVER_NAME, SERVER_PORT, REQUEST_METHOD, QUERY_STRING, REMOTE_HOST, PATH_TRANSLATED, SCRIPT_NAME і ўсе HTTP загалоўкі з імем <xxx>, як HTTP_XXX.
Акрамя таго, ён усталёўвае наступныя зменныя асяроддзі: | |
_CFPNet_AUTHNAME | Value of the .htaccess AuthName directive. |
_CFPNet_REQUIRE | Value of the .htaccess Require directive. |
_CFPNet_AUTHUSERFILE | Value of the .htaccess AuthUserFile directive By using the above variables and/or REMOTE_USER and/or AUTH_TYPE a script can verify if HTTP authentication is according to a certain configuration before it does any action, see makedir.jss as example. |
_CFPNet_FILE | File part of the requested URL. Allows easy file operations. |
_CFPNet_PATH | Path part of the requested URL, including document root. Allows easy file operations. |
_CFPNet_RESPONSE_CODE | HTTP response code. |
_CFPNet_RESPONSE_TEXT | HTTP response text. Allows creation of general purpose error document as SSI (shtml). |
_CFPNet_SCRIPT_PARAM | Parameter string for script spawned or started at start-up, shutdown, etc. |
_CFPNet_REDIRECT_TO | Destination of the HTTP redirect. An shtml error document can use this to display a nice message with link to destination. |
_CFPNet_DOCUMENT_ROOT | Full path of the document root. Useful for all kinds of file operations. |
_CFPNet_PRIVATE_DIR | Full path to the cFos PNet private folder. |
Усе гэтыя пераменныя даступныя з сцэнарыя CGI або з JavaScript (у JavaScript аб'ект вэб-сервера cFos PNet мае метад Environment_var environment_var(name) для атрымання гэтых пераменных асяроддзя).
Падчас звароту да "JavaScript" мы маем на ўвазе хост сцэнарыя Windows з JavaScript або любую іншую мову, усталяваную ў ім.
Як і ў звычайных HTTP-запытах, усе сцэнарыі Host Scripting Host, як і JavaScript, выконваюцца ў адпаведнасці з указаннямі ў .htaccess з інструкцыяй карыстальніка. Мы настойліва рэкамендуем стварыць абмежаванага карыстальніка і дазволіць cFos PNet увесці сябе ў імя гэтага карыстальніка.
Такім чынам бяспека Windows (і ваша канфігурацыя, якой карыстальнік можа атрымаць доступ да тых тэчак у вашай файлавай сістэме) дае дадатковы ўзровень бяспекі ў выпадку памылкі ў PNet або ў сцэнарыях.
Бяспека сцэнарыяў CGI:
Для выканання сцэнарыя CGI cFos PNet павінен стварыць яшчэ адзін працэс. Для таго, каб стварыць працэс пад іншым карыстальнікам, вам трэба запусціць сервер альбо ў якасці павышанага адміністратара, альбо як абмежаванага карыстальніка.
У абодвух выпадках гэтым карыстальнікам, а не абавязкова карыстачу, пад якім запускаецца працэс, патрэбныя 2 прывілеі.
Перайдзіце да адміністрацыйных інструментаў, мясцовай палітыкі бяспекі, лакальнай палітыкі, прызначэння правоў карыстальніка і дайце карыстачу, які кіруе серверам, наступныя прывілеі:
Калі вы не выкарыстоўваеце дырэктыву карыстальніка ў файлах .htaccess, ствараецца даччыны працэс з тымі ж правамі, што і серверны працэс. Паколькі cFos PNet павінен быць запушчаны ў якасці адміністратара, вашы сцэнарыі будуць працаваць як адміністратар. Як і з любым наладжаным серверам, вы павінны праверыць, пад якім карыстальнікам выконваюцца вашы сцэнарыі, напрыклад, спрабуючы атрымаць доступ да файла толькі з адміністратарам.
Глабальны стан сцэнарыя
JavaScripts загружаюцца і разбіраюцца кожны раз, калі сцэнар выконваецца ўпершыню з моманту запуску сервера. На самай справе выконваць сцэнар cFos PNet называе функцыю сцэнарыя main(). У той час як сцэнарый разбіраецца cFos PNet правярае, ці выкарыстоўваецца сцэнар глабальных зменных або функцый (па-за main). Калі такія глабальныя аб'екты будуць выяўлены, скрыпт пазначаецца як "singleton", што сведчыць аб яго глабальным стане.
Калі сцэнар мае глабальны стан, адначасова можа выконваць яго толькі адзін паток. Калі падчас выканання сцэнарыя ў глабальным стане прыходзіць яшчэ адзін запыт HTTP для выканання гэтага сцэнарыя, новы запыт павінен пачакаць, пакуль не скончыцца папярэдні запыт. Усе астатнія сцэнарыі могуць быць некалькі асобнікаў і выкананы некалькімі тэмамі адначасова.
Такім чынам, сцэнары без глабальных станаў могуць выкарыстоўваць шмат'ядравыя працэсары і павінны быць выкарыстаны, калі не захаванне глабальнага стану. З іншага боку, глабальнае стан захоўваецца ў розных запытах HTTP.
Гэта азначае, што рэгулярныя зменныя JavaScript у глабальнай вобласці могуць забяспечваць доступ да інфармацыі пра розныя HTTP-запыты, такія як лічыльнікі, сесійныя кукі, рашэнні captcha і г. д. Іншы спосаб захавання глабальнага стану - выкарыстанне спісаў хэш (гл. Ніжэй). Такім чынам вашы сцэнарыі могуць паралельна выконваць глабальны стан у "базе дадзеных".
Пісаныя аб'екты
cFos PNet запускае JavaScript у якасці хостынгу Windows Script. Ён падтрымлівае наступныя глабальныя аб'екты: | |
alert(<x>) | Write <x> to the trace.txt file and to the script output for debugging. |
exit() | Exit the current script. |
require(<n>) | Load module named <n> for common.js module support (http://www.commonjs.org/specs/modules/1.0/). |
export | Exported object; for common.js module support (http://www.commonjs.org/specs/modules/1.0/). |
__declare_const(<name>) | Tell PNet that the global object <name> should not make this script "singleton". If you only set global variables, object to never changing, always the same values, you can declare them "const" to allow multi-threaded execution of the cript. |
The webserver object has the following members: | |
read_body(<max_cnt>) | Read the HTTP message body (for example of a POST request). Read at most <max_cnt> characters. If <max_cnt> == -1 or ommitted, the entire body is read. Returns a string. |
io_mode | Property. 0 = utf8, 1 = binary. In utf8 mode the input stream (e.g. of a POST) is interpreted as a sequence of UTF-8 characters and converted accordingly to a Javascript UTF-16 string. In binary mode, each character of the input string is zero-extended to a 16 bit wide character and returned in the result string of read_body. Normally you would use UTF-8 (which is the default), so process the body of a HTTP message. But for binary upload UTF-8 conversion would corrupt the data stream, so you can switch io_mode to 1. |
write_response(<str>) | Writes <str> to the output of the HTTP response, ie. send it to the client. If io_mode == 0 the <str> is converted into an UTF-8 string. If io_mode == 1 the low-bytes of <str> are used to form a byte string as output. cFos PNet will check, if the script created a content-length header before the first call to write_response. If not, it will create a 'transfer-encoding: chunked' header and output chunked data. So if you know in advance how many bytes the script will output, you can set a content-length header. However in most cases chunked data transfer will serve well, allowing you to output the script result whenever it or part of it is ready, thereby avoiding memory consuming accumulation of large data before sending. |
content_type(<str>) | Sets the content-type HTTP header field of the response to <str>. If you don't set the content-type, the first call to write_response will set it to "text/plain". |
content_type_from_ext(<filename>) | Returns the content-type according to the <filename> extension as stored as the mime-type in the Windows registry, e.g. content_type_from_ext("test.png") will may return "image/png". |
errors_to_response(<b>) | If <b> == true script errors are output with the HTTP response, so you can read it in your browser. <b> == falsedisables errors to HTTP response output. |
environment_var(<name>) | Returns the value of an environment variable. |
create_image(<filename>) | Create an image object with filename <filename>. See image object description below. |
server_object(<name>) | Create a Javascript object (set of key/value pairs). <name> may be the following: blocklist: List of blocked files, read_only audio_input_devices: List of available audio devices, read_only video_input_devices: List if available video devices, read_only connections: List of current connections to this server, IP address and name if authenticated, read_only http_response_header: all current HTTP response headers and values, read/write. You can add/change HTTP response headers before the first call to write_response. |
is_valid_mail_addr(<addr_list>) | Checks a comma separated list of email addresses for validity. Also a DNS query for the emails mx record is performed. This function can be used to check the validity of email addresses in form fields. |
create_mutex(<name>) | Create a mutex object in an aquired state, see description of the mutex object below. While individual hash list operations keep the integrity of the hash list during concurrent operations, you should use a mutex to keep a hash list (or other resources) in a consistent state, when performing different update operations concurrently. The mutex has the following methods: acquire() (re-)acquire the mutex release() release the mutex An exception is thrown, if you acquire an already acquired mutex or release an already released mutex. |
filename_ok(<filename>, <b>) | Checks if a gives <filename> is OK. If <b> == true the location indicated by the <filename> must be in the pub folder or it's subfolders. If <b> == false the location can also be in the private folder. You should check every <filename> the user gives you with this or the absolute_filename function. Otherwise script may access other files on your computer than you may have intented. |
absolute_filename(<filename>) | Converts the filename <filename> to an absolute filename in the public folder. It also performs a check for filename_ok(<filename>, true) and returns "" if the filename is illegal. |
encode_password(<p>) | Encodes <p> with the servers master key. So passwords don't need to be stored as clear text. But beware, if someone has control of your computer, he/she may also get the master key and can then decode the password. So it's only a measure against accidential or malicious file copying / reading. |
decode_password(<p>) | The reverse of encode_password. |
create_sendmail() | Creates a "send mail" (not to be confused with unix sendmail) interface, see description below. |
hexdump(<str>, <level>) | Dumps the string <str> into the cFos PNet trace. This is for debugging purposes. <level> must be >= the func_trace value specified in global.ini, section [param]. Otherwise the function will not dump. |
from_utf8(<str>) | Make a byte array of <str>'s low bytes, interpret it as UTF-8 and return the conversion to UTF-16. |
str2bytearray(<str>) | Make a byte array of <str>'s low bytes and return the result as a VARIANT containing a SafeArray of bytes. This can be used to convert Javascript strings into a form suitable foreign APIs, like ADO (for database access or binary writing of smaller files. |
bytearray2str(<a>) | Reverse of str2bytearray. |
authenticate(<url>, <verb>, <params>) | Perform HTTP authentication (Basic or Digest). Returns 0 if unsucessful, 1 if authenticated, 2 if authentication is not neccessary (thus returns true, if access is OK). After a call to this function these environment variables are set: AUTH_TYPE, _CFPNet_AUTHNAME, _CFPNet_REQUIRE, _CFPNet_AUTHUSERFILE. The environment variable REMOTE_USER is valid only if authenticated. You should only rely on it if this function returned 1. After performing the authentication, all relevant HTTP headers are set. So if the authentication is not successful and the script exits, a 401 response, including authentication challenge is returned to the users client. For Digest authentication, the neccessary nonce value for the next request are set in the request response. This function allows you seamless integration of HTTP authentication in simple script scenarios. cFos PNet sample scripts use it. The parameter url specifies for which URL the authentication is performed, ie. it loads the neccessary .htaccess parameters. <verb> allows the use of <Limit> directives in .htaccess files. You should specifiy in relation to which HTTP method (GET, POST, PUT, etc.) the authentication takes place. With <params> you can specify additional .htaccess directives, separated by \n. The are added to the existing parameters or replace them. This allows you to basically control access via .htaccess files and have your scripts also regard these settings. |
balloon(<title>, <text>, <url>) | Displays a balloon tip with <title> and <text>. Starts the default browser with <url> if the user clicks on the balloon. This allows scripts to notify the admin and start a webpage (with a local address) with additional information. |
add_on_disconnect_handler(<url>, <param>, <once>) | add a disconnection handler for this TCP connection. On disconnect, is starts a script at <url> with parameter <param> stored in _CFPNet_SCRIPT_PARAM. This can be used to clean up resources after disconnect. If <once> is true, the handler will only be called once for each TCP connection, otherwise it will be called as often, as add_on_disconnect_handler is invoked |
sleep(<msec>) | Suspend execution for <msec> milliseconds. |
spawn_script(<url>, <param>) | create a new thread and execute the script specified by <url> with the string <param> availabe as the environment variable _CFPNet_SCRIPT_PARAM. |
get_directive(<url>, <name>) | Return the value of the .htaccess directive <name> for a given <url>. .htaccess processing according to <url> is done before the value of the directive is returned. |
dns_lookup(<name>) | DNS loop up of IP address(es) for <name>. Return an IPv6 and IPv4 address, seperated by a comma. If no connectivity for IPv4 or IPv4 is available, the respective part is left empty. |
version() | Returns a cFos PNet version string. |
file() | Creates and returns a cFos PNet file object. In many cases file access via FileSystemObject or ADO binary files is sufficient. But sometimes you need low level file access (for example for handling arbitrary large files). Therefore cFos PNet offers a file object with C like access. See below for details. |
http_methods_allowed(<url>, <cmds>) | Check if the HTTP methods lists (comma-separated) in <cmds> are allowed according to the .htaccess settings as defined by <url>. This functions returns a comma-separated list of characters for each queried HTTP method. e = allowed, d = disabled, a = auth required. If for a given HTTP method a is returned the script should perform a HTTP authentication. Currently supported methods are PUT and DELETE. |
hrtime() | Returns to current timer ticks in micro-seconds. Can be users for profiling, benchmarking. |
request_params() | Return a Javascript object which contains all information about the current HTTP request. See below for details. |
logger(<filename>, <timeout>) | Return an object for logging purposes. The loggin object caches the output, so only every couple of seconds data is written to the disk. Also access to the logging object is cached. cFos PNet releases the logging object from the cache, after <timout> seconds of no access. The logger object provides the method write(<str>) to write <str> to the log file. |
set_compression(<deflate>, <gzip>, <level>, <mem_level>, <window_size>) | Gives the script control over gzip / deflate compression. <level>, <mem_level> and <window_size> are the usual compression parameters known from the respective .htaccess directives. <deflate> and <gzip> are booleans which control wether deflate and/or gzip compression is allowed. cFos PNet checks the browsers content-encoding HTTP header field to determine if the script output can be compressed. |
ini_file_value(<filename>, <section>, <key>) | On read the functions accesses the .INI file named <filename> and returns the key <key> in section <section>. if <filename> is "*" cFos PNet's GLOBAL.INI is accessed. On write, ie. ini_file_value(<filename>, <section>, <key>) = x the corresponding key is written. This function should only be used to access 3rd party .INI files or perfom read access to cFos PNet's GLOBAL.INI. If you run cFos PNet with impersonation of a limited user (as it is recommended for security reasons), the script cannot write to cFos PNet's GLOBAL.INI. For normal data storage we recommend the far more faster hash lists (see below). |
hash_list(<filename>, <timeout>) | Return a hash list object with filename <fn>. It is cached and unloaded after <timeout> seconds without access. See below for details on the hash_list object. |
private_hash_list(<filename>, <timeout>) | Return a private hash list object. Same as above, but the file is treated as relative to cFos PNet's private folder. |
stop_impersonation() | Stop the impersonation specified with the corresponding .htaccess USER directive and revert to elevated admin rights. This allows scripts to perform admin functions. stop_impersonation() checks cFos PNet's GLOBAL.INI file, section [scripts] if there is a key admin_script with the URL to the current executed script. If it doesn't find the current script, the function fails. If users have write access to your admin_scripts you need to restrict the write permissions of these script file to administrator only. Otherwise normal users could modify the script file, call stop_impersonation() and execute arbitrary code on your machine. |
restart_impersonation() | Restarts the impersonation, i.e. reverts the effects of stop_impersonation(). |
obj = CreateObject(<sobj>, <sink>) | Creates a new COM object with <sobj> as servername.typename (e.g WbemScripting.SWbemSink). <sink>can either be a string or an object. If <sink> is a string, it is treated as prefix for event handler function in the global namespace. If it is an object, cFos Personal Net calls the event handler function(s) in the <sink> object. The names of the functions are determined by the COM objects outgoing interface. |
evt = create_event() | Create a waitable event object. evt has the following methods: set(), reset() and is_set() to set, reset and query the event state. Event objects are created in reset state. |
res = wait_for_events(<obj>, <msec>, <wait_all>) | Wait until one (<wait_all> == false) or all (<wait_all> == true) events are set. <obj> can either be an JScript array or an object. cFos Personal Net will enumerate all members which are waitable event objects to determine for which events to wait. <msec> is the maximum wait time in milliseconds, -1 means wait indefinitely. The return value res will either be null (in case of timeout) or be a reference to the event just set so wait_for_events could return. The maximum number of events, this function can wait for is 64. |
The image object has the following properties/methods: | |
width | Returns the width of the image in pixels. |
height | Returns the height of the image in pixels. |
interpolation_mode = <v> | set the quality for image stretching. 0 = lowest, 7 = highest. The better the quality, the more computing power is needed. |
save(<n>, <w>, <h>) | Save the image under the full path <n>; stretch it to <w> x <h> pixels before. |
send(<w>, <h>, <cache>) | Send the image to the client, automatically using the correct content-type message header. Stretch it to <w> x <h> pixels before. If <cache> != "" store a cached version of the image with the same name as the original image plus size information to a folder specified by the string <cache>. For example if the image name is image0004.jpg and it is stretched to 42 x 64 pixels, the cache folder contains an image named image0004_42_64.jpg afterwards. See stretch.jss for an example of how the image object can be used. |
The sendmail object has the following properties/methods: | |
header(<n>, <v>) | Set message header field name <n> to value <v>. |
text_body(<s>) | Set message text body to string <s>. |
html_body(<s>) | Set message html body to string <s>. |
create_MHTML_body(<url>, <user>, <pwd>) | Create message html body using the given <url>. If access to the url requires authentication you can use the <user>, <pwd> to set the proper user credentials. Otherwise leave them out or set to 0. You can also specify a file location as <url>, like file:///c:/x.html. |
add_attachment(<a>, <filename>) | Add an attachment using the byte array <a> (SAFEARRAY of byte) as binary attachment data. <filename> is the name given in the mail for the attachent. |
add_attachment_file(<full_filename>, <filename>) | Add an attachment to the message, using the given <full_filename>. <filename> is the name given in the mail for the attachent. |
send() | send the message, using the SMTP account data in the [param] section of cfospnet.ini: smtp_server = address of the SMTP server smtp_username = your user name with the SMTP server smtp_password = your password with the SMTP server This allows using your SMTP account (probably the same account, you use for your normal mail program) without the need to store username / password information in the script. |
The file object has the following properties/methods: | |
open(<filename>, <flags>, <share>) | Open the file <filename> <flags> is a binary OR of the usual values: O_BINARY 0x8000 O_TEXT 0x4000 O_EXCL 0x400 O_TRUNC 0x200 O_CREAT 0x100 O_TEMPORARY 0x0040 O_SEQUENTIAL 0x0020 O_RANDOM 0x0010 O_APPEND 0x8 O_RDWR 0x2 O_WRONLY 0x1 O_RDONLY 0 <share> is a binary OR of the usual values: SH_DENYRW 0x10 SH_DENYWR 0x20 SH_DENYRD 0x30 SH_DENYNO 0x40 |
close() | Close the file. |
write(<v>) | Write <v> to the file. <v> can either be a string or an array of bytes. |
read(<cnt>) | Reverse of the write function. Returns a string. <cnt> is the maximum number of characters to read. |
seek(<ofs>, <origin>) | File seek of <ofs>, using <origin>. <origin> can be SEEK_SET 0 SEEK_CUR 1 SEEK_END 2. |
length() | Return file length in bytes. |
trunc() | Trunc the file at current position. |
last_error | Property which holds the last error number, 0 = no error. |
The hash_list object has the following properties/methods: | |
open(<filename>, <interval>) | Open a hash list, <interval> is the interval in seconds, after which changes are save periodically to disk, if neccessary. |
remove() | Clear the list, delete from disk and after timeout, unload from cache. You should set all references to the list to null afterwards. |
save(<filename>) | Save a snapshot of the hash list to disk. If the optional parameter <filename> is != null, the snapshot will be saved to file <filename>. |
value(<k>) | Retrieve value for key <k>. |
value(<k>) = v | Set key <k> to value v. |
toObject(k) | Returns an Javascript object (set of key, value pairs) which contains all hash list members whose key starts with <k>. |
size() | Returns the number of elements is the list. |
enable_logging(<size>) | Enable logging of all modifications to a file named filename.log (filename is the filename of the hash list). If the log file exceeds <sz> it will be renamed to filename_old.log and a new filename.log file is created. <sz> = 0 diables logging. |
log_prefix | Property, string which is prepended before each log entry. |
begin, end | Hash_list_iterators which point to the beginning / end of the hash list |
find(<k>) | Returns a hash_list_iterator which points to the element with key == <k> or end if <k> not found |
lower_bound(<k>) | Returns a hash_list_iterator which points to the element with key >= <k> or end if <k> not found |
upper_bound(<k>) | returns a hash_list_iterator which points to the element with key <k> or end if <k> not found |
A hash_list_iterator has the following properties/methods: | |
equal(<i>) | Returns true if the iterator is equal to another iterator <i> (ie. points to the same element), otherwise false. |
inc(<cnt>) | Increment the iterator <cnt> times. |
dec(<cnt>) | Decrement the iterator <cnt> times. |
key() | Get the key of the list element the iterator currently points to. |
value() | Get the value of the list element the iterator currently points to. |
value() = <v> | Set the value of the list element, the iterator currently points to, to <v>. |
Access to the hash list is synchronised between multiple threads. However when you use hash_list_iterators (see below), only access to an individual element is synchronised. For example one thread could set the iterator to a certain element using find(<k>). In the meantime the element <k> could be deleted by another thread. In the interest of performance in multi-threaded environment only access synchronisation for the individual list element is performed. So the first thread my get an empty string when querying the value of the already deleted element. You need to use mutexes if your script need a stronger synchronisation. However in many cases this kind of weak synchronisation is sufficient and may be much faster under heavy load. | |
The request_info has the following properties/methods: | |
url | Property, the URL of the current HTTP request. |
query_string | Property, the query string. |
request_method | Property, the request method. |
In addition all HTTP headers are available as read-write key/value pairs of the Javascript object Write access to the properties can be used from Rewrite scripts to modify the current request, before it is serviced. |
Тэставанне сцэнарыяў
Мы прадставім тэставы код для сцэнарыяў, якія пастаўляюцца разам з cFos PNet, у якасці асобнай загрузкі. Вы можаце распакаваць яго ў тэчку "selftest" ў адкрытай папцы і выканаць яе. Тэставы код таксама служыць прыкладам таго, як можна выкарыстоўваць аб'екты, метады і ўласцівасці сцэнарыяў cFos PNet.
cFos Personal Net дакументацыя
cFos Personal Net дакументацыя
Сцэнарый
Дакументацыя сцэнарыяў функцый cFos Personal Net