ATLServer

Q. What is ATL Server?

A. It is a C++/COM based framework for building web apps

Q. Why would I want to use ATL Server?

A. ATL Server simplifies programming the http protocol, and also facilitates html generation similar to php, asp and ssi, except web-applications must be compiled with Visual C++

Q. What makes up an ATL Server web-application?

A. An ATL Server web-application is a dynamic link library (dll). It can also optionally have a stencil response file (.srf), which are html template files that enables server-side processing, similar to php, asp and ssi

Q. Where can I find more information about ATL Server?

A. MSDN Atl Server Reference | ATL Server High Performance c on NET

Sequence of Events

  • Client sends HTTP request to w3pi web-server
  • w3pi checks the url for .srf or .dll file extension
  • If .srf file extension is found, and if the http method is GET, then w3pi first checks if the URL + Query String is in the Page Response Cache
  • If the client submits a matching strong validator (eTag), than an HTTP 304 (Not Modified) response is returned
  • If the Page-Response-Cache content is still valid (freshness), then the cached, already parsed response is returned back to the client
  • Otherwise if the .srf file-name matches an entry in the Stencil Response File Cache , than the cache returns a pointer to the request handler to w3pi, which begins processing the request
  • Otherwise if the .srf file-name does not match an entry in the Stencil Response File Cache , the .srf file is parsed by w3pi which reads the handler tag to locate the request handler that should handle the request. The handler tag includes the location of the Web application DLL and the name of the request handler.
  • w3pi parses the .srf file Handler tag and checks whether the web application dll associated with the handler is in the DLL cache.
  • If the web application DLL is not in the DLL cache the DLL is loaded and cached.
  • w3pi returns the response back to the client from the web application DLL
_images/atlserver.png

Stencil Response Files (.srf)

A Stencil Response File (.srf) is a text file which contains static html content plus special tags that are substituted at run time with dynamically generated content. The special tags use double brace syntax as shown below:
Hello {{Hello}}

Suppose the corresponding web-application code (c++) would contain a handler for this tag that would write Hello! to the response stream After compiling the .dll, and deploying it underneath w3pi.exe, the output generated would be:

Hello Hello!

ATL Server also allows rendering instructions within replacement tags. These instructions include if, else, while and the logical operators (!, if_and, if_or). The if/else control tag must also always have an {{endif}} control tag, also while must always have an {{endwhile}}.

{{handler ..\showme.dll/Default}}
<html lang="en">
<head><title>basic srf</title></head>
<body>
    {{if LoggedIn}}
    Here is the private information {{MyInformation}}
    {{else}}
    Please login
    {{endif}}
    </body>
</html>

Here is another example:

{{if MyTrue}}
  {{if_and NestedTrue NestedTrue2}}
    {{while !NotTrue}}
      This is a test
    {{endwhile}}
  {{endif}}
{{endif}}

It is also possible to use parameters with replacement tags. For example, suppose you wanted to determine if a file is set for archiving

{{ if GetArchiveBit(c:\test\atlserver\myfile.bin) }}
  c:\test\atlserver\myfile.bin is ready for archive
{{endif}}

Corresponding c++ code in web-application dll:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
 HTTP_CODE OnGetArchiveBit(char *szFileName)
 {
     HTTP_CODE status = HTTP_S_FALSE;
     WIN32_FILE_ATTRIBUTE_DATA fadData;
     BOOL bRet = GetFileAttributesExA(szFileName, GetFileExInfoStandard, &fadData);
     if (bRet)
     {
         status = (fadData.dwFileAttributes & FILE_ATTRIBUTE_ARCHIVE)?HTTP_SUCCESS:HTTP_S_FALSE;
     }
     return status;
 }

The following tags have special meaning to ATL Server:

  • handler: used to designate the particular handler and dll combination used to process the .srf file. This must be the first ATL Server tag in the .srf file. The handlers created by the ATLServerWebApp extension will have a Default handler, which you can rename afterwards. You may also use relative paths inside the handler tag. The following example tells ATL Server to look in the parent directory for the showme.dll file and then to use the Default handler to process the .srf file. This item directly corresponds to the HANDLER_ENTRY macro as shown in Dll section
{{handler ..\showme.dll/Default}}
  • include: used to include another file (static or dynamic [.srf]) into the output. The syntax is the same as the handler tag, except only a filename needs to be specified. Again, relative paths are acceptable for this special ATL Server tag. If you do decide to include another .srf file, only the handler associated with the actual .srf file will apply to the included file.
  • subhandler: If you want to use more than one handler in an .srf file, you must use subhandler. Subhandlers have a name, which precedes the usual handler information in a handler tag. After you declare a subhandler, any replacement methods that you want to associate with this new subhandler must be prefixed with the subhandlers name. The following example shows how to use a subhandler:
{{subhandler dl ..\showme.dll/download}}

The associated replacement tag would look like this:

Hello {{dl.World}}

In summary, Stencil Response Files:

  • Integrate static and dynamic content without writing code in the srf file
  • Allow you to control the presentation layer with basic conditionals, loops and logic
  • They allow you to mix dynamic content from multiple sources without writing code
  • It seperates full-fledged server-side backend application code from basic presentation code
  • Enable use of incremental, delta-coded cache which is much easier to use than other web development techniques

Q. How do I use angular/vue js with srf files?

A. The recommended way is to put your angular code into a seperate, non-srf file and then include it. For example, you could include a text file with angular models inside the text file. This would then be passed onto the client without ATL Server trying to parse the angular models.

See srf reference for more information

Request Handlers??

Request handlers are c++ classes that implement the IRequestHandler interface, and reside in a dll that can be loaded by ATL Server. Here is an example:

 1
 2
 3
 4
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
 class CShowMeHandler : public CRequestHandlerT<CShowMeHandler>
 {
 public:

     BEGIN_REPLACEMENT_METHOD_MAP(CShowMeHandler)
         REPLACEMENT_METHOD_ENTRY("Hello", OnHello)
     END_REPLACEMENT_METHOD_MAP()

     HTTP_CODE ValidateAndExchange()
     {
         return HTTP_SUCCESS;
     }
 protected:
     HTTP_CODE OnHello(void)
     {
         m_HttpResponse << "Hello!";
         return HTTP_SUCCESS;
     }
 };

Inside the request handler c++ class is a series of REPLACEMENT_METHOD_ENTRY macros , which define the replacement tags in the .srf file that ATL Server should be expecting. Note that if you do not have an entry for a replacement tag, and ATL Server finds an un-handled replacement tag in your .srf file, your web-application will crash.

Every Request handler must have its definition in a HANDLER_ENTRY macro. This macro is also a leaf node inside BEGIN_HANDLER_MAP macro. These macros are usually located next to the dll construction, as shown below:

 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
 class CShowMeModule : public CAtlDllModuleT<CShowMeModule>
 {
 public:
     BOOL WINAPI DllMain(DWORD dwReason, LPVOID lpReserved) throw()
     {
         return __super::DllMain(dwReason, lpReserved);
     }
 };

 CShowMeModule _AtlModule;

 BEGIN_HANDLER_MAP()
     HANDLER_ENTRY("Default", CShowMeHandler)
 END_HANDLER_MAP()

 extern "C" BOOL WINAPI DllMain(HINSTANCE hInstance, DWORD dwReason, LPVOID lpReserved)
 {
     hInstance;
     return TRUE;
 }

Request handlers usually have a public ValidateAndExchange method. This method is called by ATL Server to initialize the request handler before stencil processing takes place. Here is an example of retrieving HTTP GET method URL parameters from a request:

 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
 HTTP_CODE CShowMeHandler::ValidateAndExchange()
 {
     const CHttpRequestParams *requestParams = &(this->m_HttpRequest.GetQueryParams());
     unsigned long count = requestParams->GetCount();
     if (count != 0)
     {
         char * pStr = requestParams->Lookup("Place");
         // do something with pStr
     }

     return HTTP_SUCCESS;
 }

Getting Started

Before getting started, ensure you have the latest version of Visual Studio 2017 installed, with these options:

_images/install-vs.png

Also make sure ATL for ARM is installed:

_images/atl-arm.png

The ATLServerWebApp extension for Visual Studio 2017 (included in setup.zip) creates visual c++ projects, including cpp files and a default .srf file

Setup.zip | Size: 496 KB which helps automate creating an atl server web app in Visual Studio 2017

A typical project layout for an ATL Server Web App is as follows:

  • <ProjectName>.vcxproj - the visual studio project
    • <ProjectName>Handler.h - the header file, which contains declarations for the request handler
    • <ProjectName>Module.h - the header file for the dll construction class with declarations only
    • stdafx.h - a precompiled header
    • targetver.h - a header for the Windows SDK
    • <ProjectName>Handler.cpp - the definition file for the request handler
    • <ProjectName>Module.cpp - the dll implementation
    • stdafx.cpp - corresponding precompiled header implementation
    • <ProjectName>.srf - a basic template file

To create a web-app, simply click the project template (ShowMe) and choose OK

_images/create-web-app.png

Debugging

Visual Studio 2017 allows you to remotely connect to the target device and deploy the ATL Server web app with Remote Debugging, however you must first deploy the remote debugger and w3pi web-server onto the device

  1. open the admin share on \ \minwinpc\c$ and create a new directory there called rdbg (c:\rdbg)
  2. next create a new directory called test (c:\test)
_images/minwinpc.png
  1. Copy all of the files from C:\Program Files (x86)\Microsoft Visual Studio\2017\Community\CoreCon\Binaries\Phone Tools\Debugger\target\armv4i\ on your development pc to the c:\rdbg folder on your Windows IoT device. if you have enterprise edition of Visual Studio, the files are located in C:\Program Files (x86)\Microsoft Visual Studio\2017\Enterprise\CoreCon\Binaries\Phone Tools\Debugger\target\armv4i
  2. Download w3pi.exe from download section
  3. Copy the w3pi.exe file to the c:\test folder on the Windows IoT device
  4. Open a SSH connection to the Windows IoT device. If using Putty, be sure to check Dont allocate a pseudo-terminal in the TTY settings, as this is not compatible with Windows IoT Core SSH server
_images/putty1.png
  1. run the following commands on the SSH terminal to the Windows IoT device
netsh advfirewall firewall add rule name="Remote Debugging TCP Inbound" dir=in action=allow protocol=TCP localport=4022
netsh advfirewall firewall add rule name="Remote Debugging UDP Inbound" dir=in action=allow protocol=UDP localport=3702
  1. Run the following program in the SSH terminal c:\rdbg\msvsmon.exe
_images/start-remote-debugger.png
  1. In Visual Studio, switch the build output to ARM
_images/create-v-project3.png
  1. Now you can try to initiate remote debugging by pressing F5
_images/create-v-project9.png
  1. When it gives an error, asking for the remote computer name, you must right click the project and choose properties, then click the debugging tab and choose Remote Windows Debugger from the Combobox. Fill in the desired parameters as shown below
_images/rdbg.png
  1. Right click the project and choose Deploy
  2. Set a breakpoint and start remote debugging
_images/start-remote-debugging.png
  1. Open a browser window to http://minwinpc/showme.srf and you should see an html form
  2. After a couple seconds, you will hit the breakpoint
_images/debug-break.png

http headers

Headers are typically encapsulated in the CHttpRequest class (exposed as m_HttpRequest in every handler). See the example below for retrieving the cookie header

 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
 HTTP_CODE CShowMeHandler::ValidateAndExchange()
 {
     HTTP_CODE status = HTTP_S_FALSE;
     CAtlStringA strSessionID;
     if (m_HttpRequest.Cookies(SESSION_COOKIE_NAME).GetValue(strSessionID))
     {
         if (!strSessionID.IsEmpty())
         {
             status = HTTP_SUCCESS;
         }
     }
     return status;
 }

Http headers not represented by a method in CHttpRequest can still be queried using the GetServerVariable method, but you must prefix the header name with HTTP_ , as shown below:

CAtlStringA str;
if (FALSE != m_HttpRequest.GetServerVariable("HTTP_te", str))
{
    //perform transfer coding processing on some http-form
}

Http response headers are typically represented by the CHttpResponse class (exposed as m_HttpResponse in every handler). Additional headers can be appended using the AppendHeader method as shown below:

m_HttpResponse.AppendHeader("Content-Security-Policy", "script-src 'self'");

Setting the following http response headers affects the way w3pi serves static content:

  • connection: other connections to the same client will be broken if you set it to close
  • keep-alive: its best to keep this the same as the Keepalive and Maxconnections config entries, otherwise other connections may be broken

Server Variables

Use the GetServerVariable method to retrieve one of these

  • CACHE_URL - returns the url as an utf-8 string
  • CERT_ISSUER - Issuer of the client certificate
  • CERT_STATUS - OK means certificate is valid, anything else will be indicated
  • CERT_SUBJECT- client certificate subject
  • CERT_NAME - the friendly certificate name
  • CERT_NOT_AFTER - certificate expiry time
  • CERT_NOT_BEFORE - certificate issue time
  • HTTPS - can be OFF or ON
  • LOCAL_ADDR - the server address on which the request came in
  • LOGON_USER - The user account name that the web-server is running as
  • REMOTE_ADDR - the remote ip address
  • REMOTE_PORT - the remote port number
  • SERVER_NAME - same as HTTP_HOST header value
  • SERVER_PORT - the actual port used for the connection
  • SERVER_PROTOCOL - the HTTP protocol version
  • SERVICE_NAME - the servicename configuration entry
  • SCRIPT_NAME - path to the script being executed
  • URI - the utf8 uri - everything after scheme but before extra info
  • x-actual-bytes - actual bytes received on the network interface
  • x-local-address - 169.254.227.228
  • x-remote-address - 169.254.227.228
  • x-connection-id - the unique connection id representing the connection
  • x_http_keep_alive - the value of the Keepalive and Maxconnections values set by the w3pi configuration file

Server Services

In addition to the built-in ATL Server services:

w3pi offers these additional services for web-apps:

  • IConfigurationCache - used to query or set w3pi config entries at runtime
  • IConnectionCache - tracks active connections to the w3pi web-server
  • IAuthCache - manages authenticated connections to w3pi web-server. See the authfile config entry
  • IHttpCCCache - used to apply http cache-control headers to static files being served by w3pi web-server. See the CacheControlFile config entry
  • IMimeCache - used to manage the content-type header for static files being served by w3pi web-server. See the mimefile config entry
  • IContentSecurityPolCache - used to manage content-security-policy headers for static files being served by w3pi web-server. See the ContentSecurityPolicyFile config entry
  • IContentSecurityRepCache - used to manage content-security-policy-reporting headers for static files being served by w3pi web-server
  • ICORSCache - used to manage access-control headers for static files being served by w3pi web-server. See the CorsFile config entry
  • IExtraHeadersCache - used to manage extra headers for static files being served by w3pi web-server. See the ExtraHeaders config entry
  • IPageCacheHistorySvc - used to add, retrieve filenames or purge files from the incremental, delta-coding cache

these extra services are also defined in atlcacheex.h, which is included in the setup.zip file which can be found in the this section

HTTP2 Push

w3pi allows your ATL Server web-app to push resources to the client using the HTTP2 Push Promise technique. Your must specify http2:ON in the config file or /h2 on the command line for this to work. Here is an example:

//PushFile takes a filepath and headers and pushes the resource to a client
    bool PushFile(CAtlStringA strPath, CAtlStringA strHeaders)
    {
            bool bRet = false;
            HANDLE hPushFile = CreateFile(CA2T(strPath), GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
            if (INVALID_HANDLE_VALUE != hPushFile)
            {
                    //use the HSE_IO_DECLARE_PUSH flag, headers must be http request headers, since we are emulating a clients GET request
                    if (m_spServerContext->TransmitFile(hPushFile, NULL, m_spServerContext, NULL, NULL, NULL, (void*)strHeaders.GetString(),
                        strHeaders.GetLength(), NULL, NULL, HSE_IO_DECLARE_PUSH | HSE_IO_SEND_HEADERS))
                    {
                            bRet = true;
                    }
                    //TransmitFile will automatically close the handle
            }
            return bRet;
    }

sample web-apps

In addition to the MSDN ATL Server Samples , please find below some additional samples that demonstrate the functionality of w3pi

dirlist.zip | Size: 50 KB
- A sample atl server project that shows a directory listing

redir.zip | Size: 59 KB
- A sample atl server project that shows how to perform an http redirect

myauth.zip | Size: 13 KB
- A sample atl server project that shows how to use the w3pi authentication cache, by building up an authenticated user from a username / password combination submitted by an HTTP POST request (aka. Forms authentication). Then the web app will add the authenticated user to the authentication cache and map their level of access, so requests for static resources (eg. .css or .png files) will be served by w3pi automatically without HTTP 401 errors. All usernames and passwords are handled by the developer of the webapp, the only information stored in the w3pi binary authentication cache is a listing of directories and the type of access required.

flipled.zip | Size: 140 KB
- A sample atl server project that shows you how to turn on/off the onboard LED of the raspberry pi. This sample uses the gpiokmdfdemo driver described in https://github.com/ms-iot/samples/tree/develop/DriverSamples/gpiokmdfdemo FlipLED shows you how you can use driver messages generated by a web application to control hardware on the raspberry pi. The author of this article assumes no responsibility for damaging your pi if you select the wrong pins in your own web application. The FlipLED sample toggles the drivers pin 13, which maps to the Pi GPIO pin 27 (onboard LED).
_static/img/atls/flipled-overview.png

mywebapp.zip | Size: 40 KB
- Shows how to use delta-coding with ATL Server response file cache. In this sample, a clock outputs the hour and minute on a web-page, but instead of re-downloading the entire page whenever a change is made, only the parts that have changed are sent to the browser from the server. The client then uses a javascript service-worker to patch the new changes into the old file. This greatly reduces the bandwidth requirements of an ATL Server web-app.
_static/img/atls/page-response-cache.png

Hosted by: w3pi