[go: up one dir, main page]

Menu

[r490]: / trunk / Delphi / docs / ref.html  Maximize  Restore  History

Download this file

606 lines (496 with data), 41.9 kB

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
<html>
<html>
<head>
<title>xxm - reference</title>
<link rel="stylesheet" type="text/css" href="xxm.css" />
</head>
<body>
<p><a href="http://sourceforge.net"><img src="http://sflogo.sourceforge.net/sflogo.php?group_id=230065&amp;type=5" width="210" height="62" border="0" alt="SourceForge.net Logo" align="right" /></a><img src="xxm.png" alt="xxm" /></p>
<p class="nav">
<a href="index.html">about</a> |
<a href="download.html">download</a> |
<a href="install.html">install</a> |
<b>reference</b> |
<a href="faq.html">faq</a> |
<a href="tips.html">tips&amp;tricks</a> |
<a href="sec.html">about security</a>
</p>
<ul>
<li><a href="#intro">Introduction</a></li>
<li><a href="#project">Project</a></li>
<li><a href="#syntax">Syntax</a></li>
<li><a href="#embedhtml">Embed HTML</a> <span class="newver">1.1.1</span></li>
<li><a href="#proto">Proto</a></li>
<li><a href="#interface">Interface</a></li>
<li><a href="#xxmproject">TXxmProject</a></li>
<li><a href="#xxmfragment">TXxmFragment, TXxmPage, TXxmInclude</a></li>
<li><a href="#xxmcontext">IXxmContext</a></li>
<li><a href="#xxmparameter">IXxmParameter</a></li>
<li><a href="#xxmversion">XxmVersion</a></li>
<li><a href="#htmlencode">HTMLEncode</a></li>
<li><a href="#binpublic">bin\public units</a></li>
<li><a href="#headers">Headers</a> <span class="newver">1.1.0</span></li>
<li><a href="#parservalues">Override parser values</a> <span class="newver">1.1.3</span></li>
<li><a href="#projectintf">Optional project interfaces</a></li>
<li><a href="#uploadprogress">Upload progress</a> <span class="newver">1.1.4</span></li>
<li><a href="#lpsupport">Long polling support</a> <span class="newver">1.2.2</span></li>
<li><a href="#wssupport">WebSocket support</a> <span class="newver">1.2.3</span></li>
</ul>
<p class="title"><a name="intro"></a>Introduction</p>
<p>xxm builds an xxm project into an xxm library. It does this by pre-parsing the xxm and xxmi files into pas files, generating other required Delphi project files, and calling the Delphi compiler. Depending on which installation you choose, you can either call the conversion utility to prepare a project for compiling, or use one of the development installations, to have the xxm library re-compiled when a source file changes.</p>
<p class="title"><a name="project"></a>Project</p>
<p>An xxm project is a directory with:</p>
<ul>
<li>a project definition file (typically named "Web.xxmp")</li>
<li>pages and fragment files: ".xxm" and ".xxmi" files, optionally in sub-directories</li>
<li>files that will be accessible over the website: css, graphics, client-side script, downloads...</li>
<li>optionally other files the Delphi project uses</li>
</ul>
<p>When the project is built into a library, following files are created:</p>
<ul>
<li>a directory "src", containing a .pas file for every .xxm and .xxmi file, and the Delphi project files (.dpr, .dof, .cfg)</li>
<li>a project class definition unit (typically named "xxmp.pas")</li>
<li>a compiled xxm library ".xxl"</li>
</ul>
<p>To transport a website into a live environment, copy only these files:</p>
<ul>
<li>the xxm library ".xxl" (AutoUpdate implementations check the existance of a ".xxu" file to update the live ".xxl" with between requests)</li>
<li>any files the library needs: configuration files, database or datalink files, DLLs, ...</li>
<li>any static files the website requires: css, graphics, client-side script, downloads...</li>
</ul>
<p class="title">Fragment</p>
<p>The URL of a request to an xxm website is first parsed to determine which xxm project to send the request to. (Each handler has its specific project registry.)
The project (IXxmProject) is loaded if not loaded already, and asked to provide a page object to handle the request (IXxmPage).
A page can include fragments to help construct the response (IXxmInclude).
Both pages and includes are fragments (IXxmFragment) provided by the project's fragment registry.
Because an xxm project has to provide a fragment registry, it has freedom of how to construct portion of the URL it processes.
A <i>stock-</i>implementation of a fragment registry is available by default for new xxm projects (xxmFReg.pas).</p>
<p class="title"><a name="syntax"></a>Syntax</p>
<p>xxm and xxmi files contain both HTML and Delphi source code. Delphi code is enclosed in double square brackets ("<code>[[ ]]</code>").<br />
A code section may have an alternate destination by starting with one of these characters:</p>
<dl>
<dt><code>[[=i]]</code></dt><dd><b>send:</b> the expression is evaluated and sent to the context.</dd>
<dt><code>[[#x]]</code></dt><dd><b>send HTML:</b> the expression is evaluated and sent to the context,
without converting the text into HTML (i.e.: without replacing angled brackets "<code>&lt; &gt;</code>" and ampersands into HTML code)
<br />
<b style="color:red;">!!!:</b> to prevent script injection, it is important
that any variable data is properly encoded. Use the <a href="#htmlencode"><code>HTMLEncode</code></a> function.
Read more <a href="http://xxm.sourceforge.net/sec.html">here</a>.
</dd>
<dt><code>[[?'x',1,'y',2]]</code></dt><dd><b>URL encode:</b> encodes key-value pairs into a query string, see also <a href="#urlencode"><code>URLEncode([])</code></a> <span class="newver">1.2.0</span></dd>
<dt><code>[[@Variants,]]</code></dt><dd><b>uses clause:</b> adds units to the uses clause. Separate unit names with comma.
(<span class="newver">1.0.3</span> A trailing comma is not required).</dd>
<dt><code>[[!var i:integer;]]</code></dt><dd><b>header:</b> adds code in front of 'begin' of the fragment's Build method implementation,
use this to declare local variables and constants,
<br /><b style="color:red;">*:</b> read below remarks for proper use</dd>
<dt><code>[[/ ]]</code></dt><dd><b>comment:</b> excludes a section of the xxm code</dd>
<dt><code>[[:resourcestring SHelloWorld='Hello world!';]]</code></dt><dd><b>definitions:</b> adds code in front of the fragment's Build method implementation,
<br /><b style="color:red;">*:</b> read below remarks for proper use</dd>
<dt><code>[[_ ]]</code></dt><dd><b>footer:</b> adds code right after the fragment's Build method implementation,
<br /><b style="color:red;">*:</b> read below remarks for proper use</dd>
<dt><code>[[* ]]</code></dt><dd><b><a href="#parservalues">override parser value</a></b> <span class="newver">1.1.3</span></dd>
<dt><code>[[[]]</code></dt><dd><b>opening square brackets:</b> is replaced by two opening square brackets "<code>[[</code>"</dd>
<dt><code>[[]]]</code></dt><dd><b>closing square brackets:</b> is replaced by two closing square brackets "<code>]]</code>"</dd>
<dt><code>[[& ]]</code> <code>[[% ]]</code> <code>[[. ]]</code> <code>[[, ]]</code> <code>[[; ]]</code><dt>
<dd>non-pre-defined section types for use with <a href="#extrasections">parser values</a> <span class="newver">1.2.0</span></dd>
</dl>
<p><b>Attention<span style="color:red;">*:</span></b> you can declare (nested) procedures and functions in header, footer and definition blocks,
but you can't use the <code>[[= ]]</code> and <code>[[# ]]</code> syntax and embedded HTML since this will break the <code>[[ ]]</code>-block the declaration is in.
It is advised to use include fragments with <code>Context.Include</code> instead.</p>
<p>Within a Delphi code block (including comment blocks), the number of opening and closing brackets and braces is counted (disregarding those in strings),
this enables code like this: <code style="background-color:#FFFFFF;"><span style="background-color:#CCFFCC">[[</span>Context.Send('<span style="background-color:#FFCCCC;">]]</span>');<span style="background-color:#CCFFCC">]]</span></code> and <code><span style="background-color:#CCFFCC">[[</span>=MyArray[x<span style="background-color:#FFCCCC">]</span><span style="background-color:#FFFFCC">]</span><span style="background-color:#CCFFCC">]</span></code>, but also enables a comment block to 'comment out' a full block of both HTML and code blocks.</p>
<p>Each xxm and xxmi source file is converted into a pas file, using a prototype file.
By default the prototype files are used from the <code>proto</code> directory provided with the xxm installation, but an xxm project can provide custom prototype files.</p>
<p>When the default prototype files are used, each resulting pas file declares a descendant TXxmFragment class (either TXxmPage or TXxmInclude).
The Delphi code blocks are duplicated in the predesignated spot, and all HTML is converted into calls to <code>Context.SendHTML();</code>
inside of the Build method implementation.</p>
<p><b>Attention:</b> longer portions of HTML may be split into several <code>Context.SendHTML();</code> calls, so be carefull whith code like this:</p>
<p><code>if MyBoolean then ]]&lt;b&gt;priority:[[=PriorityLevel]]&lt;/b&gt;[[</code></p>
<p>which gets parsed into:</p>
<p><code>if MyBoolean then <br />
Context.SendHTML('&lt;b&gt;priority:');<br />
Context.Send(PriorityLevel);<br />
Context.SendHTML('&lt;/b&gt;');</code></p>
<p>note that the two last lines are not part of the <code>if</code>-statement. So be sure to use <code>begin</code> and <code>end</code>:</p>
<p><code style="background-color:#FFFFFF;">if MyBoolean then <span style="background-color:#CCFFCC">begin</span>]]&lt;b&gt;priority:[[=PriorityLevel]]&lt;/b&gt;[[<span style="background-color:#CCFFCC">end</span>;</code></p>
<p class="title"><a name="embedhtml"></a>Embed HTML <span class="newver">1.1.1</span></p>
<p>To improve readability, sections with HTML elements can also be enclosed in an extra set of angled brackets ("<code>&lt;&gt;</code>") to escape them from a code block, for example:</p>
<p><code>if ShowExtraWarning then &lt;&lt;span class=&quot;warning&quot;&gt;be carefull!&lt;/span&gt;&gt;</code></p>
<p>As noted above, remember to use <code>begin</code> and <code>end</code> with larger HTML blocks or when the section has embedded code blocks.</p>
<p><code style="background-color:#FFFFFF;">if MyBoolean then <span style="background-color:#CCFFCC">begin</span> &lt;&lt;b&gt;priority:[[=PriorityLevel]]&lt;/b&gt;&gt; <span style="background-color:#CCFFCC">end</span>;</code></p>
<p><span class="newver">1.1.7</span> Blocks enclosed this way also support the alternate destination prefixes:</p>
<p><code>&lt;&lt;p&gt;Message: &lt;b&gt;&gt;=Message&lt;&lt;/p&gt;&gt;</code></p>
<p><span class="newver">1.2.2</span> If a line in a code section only contains a HTML tag, the extra opening and closing angled brackets ("<code>&lt;&gt;</code>") are not required.<br />
Please note that consecutive lines like this will have the end-of-line and surrounding whitespace converted to the module code and not the HTML output,
which in some cases might slightly alter the layout.</p>
<p><span class="newver">1.2.2</span> If a line in a code section only contains another section with a destination prefix (e.g. "<code>[[# ]]</code>"), it's not required to close the current code section ("<code>]]</code>") and open a new one right after ("<code>[[</code>").<br />
Please note that consecutive lines like this will have the end-of-line and surrounding whitespace converted to the module code and not the HTML output,
which in some cases might slightly alter the layout.</p>
<p class="title"><a name="proto"></a>Proto</p>
<p>To convert .xxm and .xxmi files into .pas files, the converter uses prototype files from the <code>proto</code> folder.
By default the files are used from the <code>proto</code> folder of the xxm installation, but an xxm project may provide its own <code>proto</code> folder with alternative prototype files.
This allows to add used units or declarations ready for use in all pages and includes of an xxm project.</p>
<p class="title"><a name="interface"></a>Interface</p>
<p>An xxm project uses the xxm.pas file that declares classes, interfaces and types required for the xxm interface.
Your xxm installation should provide a recent copy of the xxm.pas file in the "public" folder.</p>
<p><code>TXxmProjectLoadProc = function(AProjectName:WideString): IXxmProject; stdcall;</code></p>
<p>Each xxm project must export a function named "XxmProjectLoad", that creates an instance of the project. (by default provided in the xxmp.pas file)</p>
<dl>
<dt class="title"><a name="xxmproject"></a><code>TXxmProject = class(TInterfacedObject, IXxmProject)</code></dt>
<dd>An xxm project implements the IXxmProject. (by default provided in the xxmp.pas file)</dd>
<dt><code>function LoadPage(Context:IXxmContext;Address:WideString):IXxmFragment;</code></dt>
<dd>The project's LoadPage function is called to provide a page to process an incoming request,
e.g. to link it to a session (use <a href="#SessionID">Context.SessionID</a> for this).</dd>
<dt><code>function LoadFragment(Context:IXxmContext;Address,RelativeTo:WideString):IXxmFragment;</code></dt>
<dd>The project's LoadFragment function is called to provide a fragement, resolve RelativeTo to allow relative calls to Context.Include</dd>
<dt><code>procedure UnloadFragment(Fragment: IXxmFragment);</code></dt>
<dd>Pages and include fragments are passed to the UnloadFragment procedure to allow the xxm project to perform clean-up or re-use of object instances.</dd>
</dl>
<p>The TXxmProject object can also implement extra interfaces to add functionality, see <a href="#projectintf">optional project interfaces</a></p>
<dl>
<dt class="title"><a name="xxmfragment"></a><a name="xxmpage"></a><a name="xxminclude"></a><code>
TXxmFragment = class(TInterfacedObject, IXxmFragment)<br />
TXxmPage = class(TXxmFragment, IXxmPage)<br />
TXxmInclude = class(TXxmFragment, IXxmInclude)</code></dt>
<dd>The default xxm and xxmi prototype files convert xxm and xxmi source files into a definition of a descendant class of TXxmPage or TXxmInclude.</dd>
<dt><code>procedure Build(const Context: IXxmContext; const Caller: IXxmFragment;<br />
&nbsp; const Values: array of OleVariant;<br />
&nbsp; const Objects: array of TObject); virtual; abstract;</code></dt>
<dd>A fragment's Build method is called to build the response
<ul>
<li>Context: an instance of IXxmContext to build the response with</li>
<li>Caller: set to the fragment that calls Context.Include, nil otherwise</li>
<li>Values, Objects: values and objects as passed onto Context.Include by the calling fragment</li>
</ul>
</dd>
<dt class="title"><code><a name="xxmcontext"></a>IXxmContext = interface</code></dt>
<dd>an xxm context handles all interfacing to the incoming request and the outgoing response</dd>
<dt><code>property URL:WideString</code></dt>
<dd>read-only, the full URL of the request</dd>
<dt><code>property Page:IXxmFragment</code></dt>
<dd>read-only, the page the project provided to handle the request, also when an include fragment is called from the page or from another include fragment</dd>
<dt><a name="ContentType"></a><code>property ContentType:WideString</code></dt>
<dd>the MIME type of the outgoing response, by default set to 'text/html'</dd>
<dt><code>property AutoEncoding:TXxmAutoEncoding</code></dt>
<dd>the encoding used for the outgoing response
<ul>
<li>aeContentDefined: don't specify an encoding in the header so the content can define it's own encoding</li>
<li>aeUtf8: send the response using UTF8</li>
<li>aeUtf16: send the response using UTF16</li>
<li>aeIso8859: send the response using IS0-8859-1 encoding</li>
</ul>
</dd>
<dt><code>property Parameter[Key:OleVariant]:IXxmParameter<br />
property ParameterCount:integer</code></dt>
<dd>the parameters provided in the request, see below for more about IXxmParameter and its descendants</dd>
<dt><a name="SessionID"></a><code>property SessionID:WideString</code></dt>
<dd>read-only, a unique string constructed with random data, included in the response as a cookie,
to identify following requests as requests from the same browser session. A project may use this property to perform session management.</dd>
<dt><code>procedure Send(Data: OleVariant);</code></dt>
<dd>sends data to the response</dd>
<dt><code>procedure SendHTML(Data: OleVariant);</code></dt>
<dd>sends data to the response without HTMLEncode</dd>
<dt><code>procedure SendFile(FilePath: WideString);</code></dt>
<dd>sends the contents of the file to the response. If the response has not started sending data,
the <a href="#ContentType">ContentType</a> is set to the MIME-type string found in the Windows registry by the file extention (HKEY_CLASSES_ROOT)</dd>
<dt><code>procedure SendStream(s:IStream);</code></dt>
<dd>sends the contents of the stream to the response (use <code>TStreamAdapter</code> from the Classes unit
to provide an <code>IStream</code> interface on a <code>TStream</code> object)</dd>
<dt><a name="include"></a><code>
procedure Include(Address: WideString); overload;<br />
procedure Include(Address: WideString;<br />
&nbsp; const Values: array of OleVariant); overload;<br />
procedure Include(Address: WideString;<br />
&nbsp; const Values: array of OleVariant;<br />
&nbsp; const Objects: array of TObject); overload;<br />
</code></dt>
<dd><p>load an include fragment and call the Build method with provided Values and Objects.
Use <code>Context.Include</code> in favor of creating an instance of the fragment class directly,
to enable xxm's built-in exception handling and to enable performance enhancements provided by the fragment registry.</p>
<p><span class="newver">1.1.3</span> To load a fragment from another project,
prefix the fragment address with <code>xxm://project2/</code> where <code>project2</code> is the name of the other project.
<b>Attention:</b> this is disallowed by default, to enable this add <code>"allowInclude": true</code> to the xxm handler's project registry
(<a href="install.html#xxmjson"><code>xxm.json</code></a>).</p>
</dd>
<dt><a name="ContextString"></a><code>function ContextString(cs:TXxmContextString):WideString;</code></dt>
<dd>
provides information about the incoming request
<ul>
<li>csVersion: xxm version</li>
<li>csProjectName: name the xxm project was loaded with (is registered with)</li>
<li>csURL: the full URL of the request</li>
<li>csLocalURL: URL fraction that determines the loaded page</li>
<li>csVerb: HTTP verb, typically "GET" or "POST"</li>
<li>csReferer: the URL of the previous page opened in the browser</li>
<li>csQueryString: the URL portion after "?"</li>
<li>csUserAgent: browser's identification string</li>
<li>csExtraInfo: trailing URL information</li>
<li>csAcceptedMimeTypes: browser's accepted MIME types</li>
<li>csPostMimeType: the MIME type of the data posted in the request</li>
<li>csLanguage: browser's accepted languages</li>
<li>csRemoteAddress: client's network address</li>
<li>csRemoteHost: client's host name</li>
<li>csAuthUser: user name provided by the request authentification</li>
<li>csAuthPassword: password provided by the request authentification</li>
</ul>
</dd>
<dt><code>function PostData:IStream;</code></dt>
<dd>provides access to the data posted in the request (use <code>TOleStream</code> from the AxCtrls unit to use the <code>IStream</code> interface as a <code>TStream</code> descendant). See also <a href="#wssupport">WebSocket support</a> <span class="newver">1.2.3</span>.</dd>
<dt><code>function Connected:boolean;</code></dt>
<dd>checks whether the client disconnected, typically when a user presses abort, or the connection is lost</dd>
<dt><code>procedure SetStatus(Code:integer;Text:WideString);</code></dt>
<dd>sets the HTTP response code and text to respond with, by default set to 200,'OK'</dd>
<dt><code>procedure Redirect(RedirectURL:WideString; Relative:boolean);</code></dt>
<dd>redirects the browser to a different URL. Pass Relative as false when redirecting to a URL within the same project to optimally use resources.
<b>Attention:</b> a call to Redirect throws an <code>EXxmPageRedirected</code> exception to halt execution of the current page.
If you catch exceptions, re-raise these to make sure the redirect is correctly handled.</dd>
<dt><code>property Cookie[Name:WideString]:WideString</code></dt>
<dd>reads a cookie from the request</dd>
<dt><code>procedure SetCookie(Name,Value:WideString); overload;<br />
procedure SetCookie(Name,Value:WideString; KeepSeconds:cardinal;<br />
&nbsp; Comment,Domain,Path:WideString; Secure,HttpOnly:boolean); overload;</code></dt>
<dd>includes a cookie in the response, <b>Attention:</b> calling Cookie[] with the same Name as SetCookie has been called,
will not return the same Value in the same request as SetCookie has been called.</dd>
<dt><code>procedure DispositionAttach(FileName: WideString);</code></dt>
<dd>notifies the browser to show a 'save as' dialog to store the contents of the response</dd>
<dt><a name="buffersize"></a><code>property BufferSize: integer;</code> <span class="newver">1.1.4</span></dt>
<dd>set a buffer size to store sent data before actually transmitting. When the buffer is full, data is transmitted.
It's not guaranteed that the size of sent chunks will be of the exact number of bytes as defined.
Set buffer size to 0 to disable buffering and send everything rightaway. (This will perform less than optimal onder load).
It's highly recommended to set a buffer size, for example <code>Context.BufferSize=$100000;</code>,
for example from the LoadPage method in <code>xxmp.pas</code>.
This improves performance on projects that call the Send methods many times with small bits if data,
but could be confusing when debugging a project. (default value: 0)<br />
It is allowed to set BufferSize to a new value while data is already sent,
but whether any data still in the output buffer will get flushed or not depends on the implementation of the xxm handler.<br />
<span class="newver">1.2.2</span> Optionally override the default value by adding
<code>"bufferSize": <i>&lt;new default value&gt;</i></code> to the xxm handler's project registry (<a href="install.html#xxmjson"><code>xxm.json</code></a>).</dd>
<dt><code>procedure Flush;</code> <span class="newver">1.1.4</span></dt>
<dd>write any data waiting in the output buffer rightaway.
Call this right before any operation that could take some time server-side,
to be sure any progress display HTML is actually transmitted to the browser.</dd>
<dt class="title"><code><a name="xxmparameter"></a>IXxmParameter = interface</code></dt>
<dd>all parameters inherit from IXxmParameter</dd>
<dt><code>property Name:WideString</code></dt>
<dd>gets the parameter name</dd>
<dt><code>property Value:WideString</code></dt>
<dd>gets the value of the parameter, by default ''</dd>
<dt><code>function AsInteger:integer;</code></dt>
<dd>gets the value of the parameter as an integer value, by default 0</dd>
<dt><code>function NextBySameName:IXxmParameter;</code></dt>
<dd>gets the next parameter in sequence with the same name, if any</dd>
<dt class="title"><code>IXxmParameterGet = interface(IXxmParameter)</code></dt>
<dd>a parameter provided in the QueryString URL</dd>
<dt class="title"><code>IXxmParameterPost = interface(IXxmParameter)</code></dt>
<dd>a parameter provided in posted data</dd>
<dt class="title"><code>IXxmParameterPostFile = interface(IXxmParameterPost)</code></dt>
<dd>a file uploaded in posted data</dd>
<dt><code>property Size:integer</code></dt>
<dd>gets the file size</dd>
<dt><code>property MimeType:WideString</code></dt>
<dd>gets the MIME type of the file</dd>
<dt><code>procedure SaveToFile(FilePath:string);</code></dt>
<dd>saves the uploaded file</dd>
<dt><code>function SaveToStream(Stream:IStream):integer;</code></dt>
<dd>saves the uploaded content to a stream (use <code>TStreamAdapter</code> from the Classes unit
to provide an <code>IStream</code> interface on a <code>TStream</code> object)</dd>
<dt class="title"><a name="xxmversion"></a><code>function XxmVersion:TXxmVersion;<br />
TXxmVersion = record Major,Minor,Release,Build:integer; end;
</code></dt>
<dd>gets the xxm version, use the xxm version to check if newer features are available</dd>
<dt class="title"><a name="htmlencode"></a><code>function HTMLEncode(Data:WideString):WideString; overload;<br />
function HTMLEncode(Data:OleVariant):WideString; overload;
</code></dt>
<dd>encodes text for safe output into a HTML document</dd>
<dt class="title"><a name="urlencode"></a><code>function URLEncode(Data:OleVariant):string;<br />
function URLDecode(Data:string):WideString;<br />
function URLEncode(const KeyValuePairs:array of OleVariant):AnsiString; overload;</code> <span class="newver">1.2.0</span>
</dt>
<dd>encodes/decodes data to/from URL notation</dd>
</dl>
<p class="title"><a name="binpublic"></a>bin/public units</p>
<p>It's advised when installing xxm to store the <code>public</code> and <a href="#proto"><code>proto</code></a> folders together with the binaries. (e.g. <code>C:\InetPub\xxm</code>).<br />
A new xxm project has by default <code>&lt;CompileCommand&gt;</code> set to <code>dcc32 <span style="background-color:#CCCCFF">-U[[HandlerPath]]public</span> -Q [[ProjectName]].dpr</code> so these units are available by default.</p>
<dl>
<dt>xxm.pas</dt><dd>The main central xxm unit that defines the common <a href="#interface">interface</a> to interact with the xxm handler.</dd>
<dt>xxmFReg.pas</dt><dd>The default <a href="#fragment">fragment</a> class registry, used by the default <code>xxmp.pas</code>. You are free to change both in your project. In larger projects a specific solution may perform better then the default solution based on a plain <code>TStringList</code>.</dd>
<dt>xxmHeaders.pas <span class="newver">1.1.0</span></dt><dd>Extra interfaces to manipulate request and response <a href="#headers">headers</a>.</dd>
<dt>xxmSession.pas</dt><dd>A default session object. New xxm projects don't include this. Take a copy of this file in your project folder, add it to Web.xxmp (by adding <code>&lt;Unit UnitName="xxmSession"/&gt;</code>), add a SetSession call to your xxmp.pas' LoadPage method (where it says <code>//TODO: link session to request</code>), and modify the session object to hold the data required by your application.</dd>
<dt>xxmStream.pas</dt><dd>Defines the <code>TxxmOutputStream</code> class you can wrap around a <code>IXxmContext</code> to have a stream to write to and have the data sent to the response.</dd>
<dt>xxmString.pas</dt><dd>Defines the <code>TStringContext</code> that enables to catch output from fragments. Use it either by temporarily <a href="#parservalues">overriding parser values</a>, or by using its <a href="#include"><code>Include</code> method(s)</a>.
<dt>xxmWebSocket.pas <span class="newver">1.2.3</span></dt><dd>Defines the base class <code>TXxmWebSocket</code> you can inherit from to provide <a href="#wssupport">web sockets</a>.</dd>
</dl>
<p class="title"><a name="headers"></a>Headers <span class="newver">1.1.0</span></p>
<p>The xxm context objects provide separate interfaces to allow access to request and response HTTP headers and parameters.
Include the <code>xxmHeaders.pas</code> unit and query the Context object for an IXxmHttpHeaders or IXxmParameterCollection interface pointer.</p>
<dl>
<dt class="title"><code>IXxmHttpHeaders = interface</code></dt>
<dd>an interface provided by the context object to allow access to request and response HTTP headers.</dd>
<dt><code>property RequestHeaders:IXxmDictionaryEx</code></dt>
<dd>a read-only dictionary of name-value pairs of the request HTTP header</dd>
<dt><code>property ResponseHeaders:IXxmDictionaryEx</code></dt>
<dd>a dictionary of name-value pairs of the response HTTP header</dd>
<dt class="title"><code>IXxmDictionary = interface</code></dt>
<dd>a dictionary contains name-value pairs</dd>
<dt><code>property Item[Name:OleVariant]:WideString default;</code></dt>
<dd>gets or sets the value for the name-value pair</dd>
<dt><code>property Count:integer</code></dt>
<dd>read-only, the number of name-value pair in the dictionary</dd>
<dt><code>property Name[Idx:integer]:WideString</code></dt>
<dd>gets or sets the name for the name-value pair</dd>
<dt class="title"><code>IXxmDictionaryEx = interface(IXxmDictionary)</code></dt>
<dd>extends IXxmDictionary with support for complex entries with sub-values, e.g.:<br />
<code>Content-Type: text/plain; charset="iso-8859-15"<br />Content-Disposition: inline; name="file1"; filename="somefile.txt"</code></dd>
<dt><code>function Complex(Name:OleVariant;out Items:IXxmDictionary):WideString;</code></dt>
<dd>returns opening value and sets Items to a dictionary containing further name-value pairs</dd>
</dl>
<p>Example:</p><p><code>(Context as IXxmHttpHeaders).ResponseHeaders['X-Something']:='Hello world!';</code></p>
<dl>
<dt class="title"><code>IXxmParameterCollection</code></dt>
<dd>an interface provided by the context object that enables adding extra parameters, e.g. from the project's LoadPage method.</dd>
<dt><code>procedure AddParameter(Param: IXxmParameter);</code></dt>
<dd>adds an object to the parameter collection that implements the IXxmParameter interface.</dd>
</dl>
<p class="title"><a name="parservalues"></a>Override parser values <span class="newver">1.1.3</span></p>
<p>The script parser uses an internal set of values to use with converting certain sections into Delphi source code.</p>
<dl>
<dt>Send open (start of <code>[[=</code> sections)</dt><dd>default value: <code>Context.Send(</code><br />use <code>[[*=(<span style="background-color:#FFCCCC;">&nbsp;&nbsp;&nbsp;</span>]]</code> to override</dd>
<dt>Send close (end of <code>[[=</code> sections)</dt><dd>default value: <code>);</code><br />use <code>[[*=)<span style="background-color:#FFCCCC;">&nbsp;&nbsp;&nbsp;</span>]]</code> to override</dd>
<dt>Send HTML open (start of <code>[[#</code> sections)</dt><dd>default value: <code>Context.SendHTML(</code><br />use <code>[[*#(<span style="background-color:#FFCCCC;">&nbsp;&nbsp;&nbsp;</span>]]</code> to override</dd>
<dt>Send HTML close (end of <code>[[#</code> sections)</dt><dd>default value: <code>);</code><br />use <code>[[*#)<span style="background-color:#FFCCCC;">&nbsp;&nbsp;&nbsp;</span>]]</code> to override</dd>
<dt>URL encode open (start of <code>[[?</code> sections) <span class="newver">1.2.0</span></dt><dd>default value: <code>Context.Send(URLEncode([</code><br />use <code>[[*?(<span style="background-color:#FFCCCC;">&nbsp;&nbsp;&nbsp;</span>]]</code> to override</dd>
<dt>URL encode close (end of <code>[[?</code> sections) <span class="newver">1.2.0</span></dt><dd>default value: <code>]));</code><br />use <code>[[*?)<span style="background-color:#FFCCCC;">&nbsp;&nbsp;&nbsp;</span>]]</code> to override</dd>
</dl>
<p>It is possible to override several parser values in one <code>[[* ]]</code> section by defining each one on a line by itself, e.g.:</p>
<p><code>[[*<br />
&nbsp; =(Context.Send(qr['<br />
&nbsp; =)']);<br />
&nbsp; #(Context.SendHTML(qr['<br />
&nbsp; #)']);<br />
]]</code></p>
<p>Use an empty value, e.g. <code>[[*=(]]</code>, to reset a parser value to its default value.
Use <code>[[*]]</code> to reset all parser values to the default values.</p>
<p><span class="newver">1.1.8</span> Parser values for opening sections may optionally contain:</p>
<ul>
<li><code>$l</code> gets replaced by the line number in the xxm source file where the section starts</li>
<li><code>$v</code> gets replaced by the current parser value, this allows to add to the parser value</li>
<li><code>$d</code> gets replaced by the default value, this allows to revert to the default value and add to it in one operation</li>
</ul>
<p>To set parser values for the entire project, use xxmProject.exe. The values are stored in the <code>&lt;ParserValues&gt;</code> node in Web.xxmp.</p>
<p><a name="extrasections"></a><span class="newver">1.2.0</span> Additional section prefixes are available that use these parser values:</p>
<table cellspacing="4" cellpadding="1" border="0">
<tr><th rowspan="2">Section</th><th colspan="2">&lt;ParserValues&gt; element</th><th colspan="2">Default values</th></tr>
<tr><th>Open</th><th>Close</th><th>Open</th><th>Close</th></tr>
<tr><td><code>[[& ]]</code></td><td>&lt;Extra1Open&gt;</td><td>&lt;Extra1Close&gt;</td><td><code>Extra(</code></td><td><code>);</code></td></tr>
<tr><td><code>[[% ]]</code></td><td>&lt;Extra2Open&gt;</td><td>&lt;Extra2Close&gt;</td><td><code>Extra(</code></td><td><code>);</code></td></tr>
<tr><td><code>[[. ]]</code></td><td>&lt;Extra3Open&gt;</td><td>&lt;Extra3Close&gt;</td><td><code>Extra(</code></td><td><code>);</code></td></tr>
<tr><td><code>[[, ]]</code></td><td>&lt;Extra4Open&gt;</td><td>&lt;Extra4Close&gt;</td><td><code>Extra(</code></td><td><code>);</code></td></tr>
<tr><td><code>[[; ]]</code></td><td>&lt;Extra5Open&gt;</td><td>&lt;Extra5Close&gt;</td><td><code>Extra(</code></td><td><code>);</code></td></tr>
</table>
<p class="title"><a name="projectintf"></a>Optional project interfaces</p>
<dl>
<dt class="title"><code>IXxmProjectEvents = interface</code> <span class="newver">1.1.4</span></dt>
<dd>the project object can optionally expose this interface.
(The project object is typically defined in the <code>xxmp.pas</code> unit.)
If it does, the xxm handler will call its methods in certain events:</dd>
<dt><code>function HandleException(Context:IXxmContext;PageClass:WideString;Ex:Exception):boolean;</code> <span class="newver">1.1.4</span></dt>
<dd>when an exception occurred while building a page
<ul>
<li>Context: the IXxmContext the page was being built with</li>
<li>PageClass: an informational display of which fragment the exception occurred in, may contain a path of fragments that included eachother</li>
<li>Ex: the exception object that was raised</li>
</ul>
Return whether the exception was handled. Return false to have the xxm handler send the default exception message.
</dd>
<dt class="title"><code>IXxmProjectEvents1 = interface</code> <span class="newver">1.1.8</span></dt>
<dd>the project object can optionally export this interface.
(The project object is typically defined in the <code>xxmp.pas</code> unit.)
If it does, the xxm handler will call its methods in certain events:</dd>
<dt><code>function HandleException(Context:IXxmContext;PageClass,ExceptionClass,ExceptionMessage:WideString):boolean;</code></dt>
<dd>when an exception occured while building a page (and the project doesn't implement IXxmProjectEvents)<br />
Use this interface if a Delphi version conflict occurs using <code>IXxmProjectEvents.HandleException</code></dd>
<ul>
<li>Context: the IXxmContext the page was being built with</li>
<li>PageClass: an informational display of which fragment the exception occurred in, may contain a path of fragments that included eachother</li>
<li>ExceptionClass: the class name of the Exception object</li>
<li>ExceptionMessage: the message text of the Exception object</li>
</ul>
Return whether the exception was handled. Return false to have the xxm handler send the default exception message.
</dd>
<dt><code>procedure ReleasingContexts;</code></dt>
<dd>when the xxm handler is about to unload the project (due to a shutdown or an auto-update or auto-build event),
it calls <code>ReleasingContexts</code> before it waits for all current page requests to complete.</dd>
<dt><code>procedure ReleasingProject;</code></dt>
<dd>when the xxm handler is about to unload the project,
it calls <code>ReleasingProject</code> after it waited for all current page requests to complete.</dd>
</dl>
<p class="title"><a name="uploadprogress"></a>Upload progress <span class="newver">1.1.4</span></p>
<p>To display the progress of uploading a large file, you need to attach an upload progress agent to the context <b>before</b>
any context parameter is accessed. The request data is parsed when <code>Context.Parameter</code> is first accessed.</p>
<dl>
<dt class="title"><code>IXxmUploadProgressService = interface</code></dt>
<dd>an interface provided by the context object that enables attaching an upload progress agent.</dd>
<dt><code>procedure AttachAgent(Agent: IXxmUploadProgressAgent; Flags, Step: integer);</code></dt>
<dd>attaches an upload progress agent to the context. Attach any agents before calling <code>Context.Parameter</code>.
<ul>
<li>Flags=<code>xxmUploadProgressAttach_PostData</code>: report progress parsing the entire request data (<i>Step</i> value ignored)</li>
<li>Flags=<code>xxmUploadProgressAttach_FileFields</code>: report progress parsing each file, report progress every <i>Step</i> bytes</li>
</ul>
</dd>
<dt><code>IXxmUploadProgressAgent = interface</code></dt>
<dd>implement this interface on an object to use it as an upload progress agent</dd>
<dt><code>procedure ReportProgress(FieldName, FileName: AnsiString; Position: integer);</code></dt>
<dd>
<ul>
<li><code>xxmUploadProgressAttach_PostData</code>: Position into request body (FieldName, FileName not used)</li>
<li><code>xxmUploadProgressAttach_FileFields</code>: FieldName, FileName of post form field being parsed; Position into file data</li>
</ul>
</dd>
</dl>
<p class="title"><a name="lpsupport"></a>Long polling support <span class="newver">1.2.2</span></p>
<p>If you want to implement a <a href="https://en.wikipedia.org/wiki/Long_polling">Long polling</a> scenario,
it might be tempting to write something like this:</p>
<p><code><b>while</b> Context.Connected <b>do</b> <br />
<b>begin</b><br />
&nbsp;&nbsp;<b>while</b> <b>not</b> NewDataIsAvailable <b>do</b> Sleep(500);<br />
&nbsp;&nbsp;Context.SendHTML(GetDataAsHTML);<br />
&nbsp;&nbsp;Context.Flush; <i>//for in case <a href="#buffersize">Context.BufferSize</a> is set</i><br />
<b>end</b>;<br />
</code></p>
<p>This will keep the worker thread occupied for the duration of the connection,
and the number of worker threads is limited by the thread pool size configuration.
This method doesn't adapt to situations where the server has to handle more requests, or is asked to shut down cleanly.
If you want to use long polling requests, use these interfaces:</p>
<dl>
<dt class="title"><code>IXxmContextSuspend = interface</code></dt>
<dd>an interface provided by the context object that has long polling support.</dd>
<dt><code>procedure Suspend(const EventKey: WideString; CheckIntervalMS, MaxWaitTimeSec: cardinal;
const ResumeFragment: WideString; ResumeValue: OleVariant;
const DropFragment: WideString; DropValue: OleVariant);</code></dt>
<dd>register this context to keep the connection open after this <code>Build</code> call completes.
Then check for an event approximately every <code>CheckIntervalMS</code> milliseconds.
When <code>IXxmProjectEvents2.CheckEvent(EventKey)</code> returns true, resume the context and call <code>Context.Include</code>
with <code>ResumeFragment</code> and <code>ResumeValue</code>. If it doesn't by <code>MaxWaitTimeSec</code>,
resume the context and call <code>Context.Include</code> with <code>DropFragment</code> and <code>DropValue</code> if <code>DropFragment&lt;&gt;''</code>.<br />
If <code>ResumeValue</code> or <code>DropValue</code> is an array of variants,
it is passed to <code>Context.Include</code> as the <code>Values</code> parameter; else it's available as <code>Values[0]</code>; use <code>Null</code> to not pass any value.<br />
<b>Attention:</b> the timing values may not be strictly adhered to. Event checking is performed separate from the worker threads and the sequence
and priority of events may cause intervals to be longer or suspended contexts to be dropped sooner.
</dd>
<dt class="title"><code>IXxmProjectEvents2 = interface</code></dt>
<dd>implement this interface on the project object.
(The project object is typically defined in the <code>xxmp.pas</code> unit.)</dd>
<dt><code>function CheckEvent(const EventKey:WideString; var CheckIntervalMS: cardinal):boolean;</code></dt>
<dd>called periodically as configured by <code>IXxmContextSuspend.Suspend</code>. Return true to resume suspended context(s).
When <code>IXxmContextSuspend.Suspend</code> is called with several <code>CheckIntervalMS</code> values, the smaller value takes precedence.
Modify its value to control the timing of the next call.
<b>Attention:</b> the timing values may not be strictly adhered to. Event checking is performed separate from the worker threads and the sequence
and priority of events may cause intervals to be longer.
<br />
<b>Attention:</b> keep the work done by this call as light and performant as possible, optionally checking values set by a separate thread managed by the xxm project.</dd>
</dl>
<p class="title"><a name="wssupport"></a>WebSocket support <span class="newver">1.2.3</span></p>
<p>To implement a <a href="https://en.wikipedia.org/wiki/WebSocket">WebSocket</a>, create class that inherits from <code>TXxmWebSocket</code> declared in the <code>xxmWebSocket.pas</code> unit. It implements the <code>IXxmPage</code> interface, so can be registered with the fragment registry (e.g. xxmFReg.pas) which also may determine what URL the WebSocket will be accessible with (unless the project's <code>LoadPage</code> does other mapping of URLs).</p>
<p>Override the virtual methods <code>ReadMessage</code> or <code>ReadBinary</code> to handle incoming messages. Optionally override virtual methods <code>ConnectSuccess</code> and <code>ConnectionLost</code> to handle opening and closing socket connections.</p>
</body>
</html>