Additional Blogs by SAP
cancel
Showing results for 
Search instead for 
Did you mean: 
former_member181879
Active Contributor

Currently, we are processing a problem with the following text:

We have a <u>stateless</u> BSP application. After a predefined time, we would like all inactive sessions to be deleted from ICM, and then the user must be forced to supply a name and password again.

The rest of the problem description is not listed here. If only we can succeed in clearing the confusion in this one paragraph, the rest will be easy. What you need is a clear understanding of the expressions stateless sessions, stateful sessions, and +authentication</I>.</p>

Test Harness

As usual, as a first step, let's build a small test program to explain the different concepts. All that the program should do is increment a counter, plus allow us to switch the session between stateless, and stateful.

Create a new BSP application with one page. Define the following page attribute:

<!code>  counter TYPE I

This counter is defined as page attribute. While we are stateless, the page will be freshly created each time and the counter will always be initialised to zero. However, once the page is switched into stateful mode, the page (object) will be cached and reused. The counter will keep its previous value, allowing us to verify that we are always running in the same session and that this session is keeping its state.

For the layout page we have:

<!code>  <%@page language="abap" %>

<!code>   

<!code

<!code>   

<!code>    <%-- increment counter, and write out --%>

<!code>    <% counter = counter + 1. %>

<!code>   

<!code>   

<!code>    <%-- determine port from URL, for port get service timeout, sleep handling --%>

<!code>    <%

<!code>      DATA: port TYPE STRING.

<!code>      port = request->get_header_field( if_http_header_fields_sap=>server_port ).

<!code>   

<!code>      DATA: services TYPE TABLE OF ICM_SINFO.

<!code>      CALL FUNCTION 'ICM_GET_INFO' TABLES SERVLIST = services.

<!code>   

<!code>      FIELD-SYMBOLS:  TYPE ICM_SINFO.

<!code>      DATA: wait TYPE STRING.

<!code>      READ TABLE services ASSIGNING  WITH KEY service = port.

<!code>      wait = -KEEPALIVE + 5.

<!code>      CONDENSE wait.

<!code>   

<!code>      IF request->get_form_field( 'wait' ) IS NOT INITIAL.

<!code>        WAIT UP TO wait SECONDS.

<!code>      ENDIF.

<!code>    %>

<!code>   

<!code>   

<!code>   

<!code>    <%-- stateful or stateless? --%>

<!code>    <%

<!code>       DATA: stateful TYPE STRING.

<!code>       stateful = request->get_form_field( 'stateful' ).

<!code>       IF stateful IS NOT INITIAL. runtime->keep_context = 1.

<!code>       ELSE.                       runtime->keep_context = 0.

<!code>       ENDIF.

<!code>    %>

<!code>   

<input type="checkbox" name="stateful" value="checked" <%=stateful%>>

Stateful

<!code>   

<!code>   

<!code>    <%-- output similar to transaction SM04 --%>

<!code>    <%

<!code>      DATA: list TYPE TABLE OF UINFO,

<!code>            user LIKE LINE OF list.

<!code>      CALL FUNCTION 'TH_USER_LIST' TABLES LIST = list.

<!code>    %>

<!code>   

<!code>    <% LOOP AT list INTO user WHERE BNAME = sy-uname. %>

<!code>     

|

<!code>        

<td> <%= user-MANDT %>     </td>

<!code>        

<td> <%= user-BNAME %>     </td>

<!code>        

<td> <%= user-TERM %>      </td>

<!code>        

<td> <%= user-ZEIT %>      </td>

<!code>      </tr>

<!code>    <% ENDLOOP. %>

<!code>    </table>

<!code>   

<!code

</form></body></html>
</pre>

<p class=MsoNormal style='mso-layout-grid-align:none;text-autospace:none'> font-size:8.5pt;font-family:"Arial monospaced for SAP"; color:black;<![if !supportEmptyParas]> <![endif]></p>

<p>The program can be split into a few parts.</p>

<ul>
<li>The first part just increments a counter and writes the counter out (on a button) to the browser. Important! The value of the counter is not stored anywhere in the page. We only want to see if the counter (an attribute of the page object) is incremented for each request/response cycle or not.</li>
<li>The next coding sequence looks slightly complex, but does not actually do all that much. It first looks at the incoming request and determines the HTTP port number from the request. Then all ICM defined services are retrieved and we determine the processing time that is configured for this specific port. A button is rendered to “sleep” this number (plus five) seconds. If this button is actually pressed, the ABAP “WAIT UP TO” statement is used to simulate a long running HTTP request. This will be used later in the test to show the effect of the service timer.</li>
<li>The next section toggles 'stateful' or not, and renders a checkbox to manage this.</li>
<li>The last second outputs exactly the same information as transaction SM04. This lists all active sessions for the specific user.</li>
</ul>

<p>The output of the program after the first run is:</p>

<p>

!https://weblogs.sdn.sap.com/weblogs/images/13/BSP-InDepthConfusion-Between-Stateless-Stateful-And-Authentication_001.GIF|height=209|width=411|src=https://weblogs.sdn.sap.com/weblogs/images/13/BSP-InDepthConfusion-Between-Stateless-Stateful-And-Authentication_001.GIF|border=0!

The table displays client, user, terminal, and last update time (shortly before lunch :smile: .</p>

Stateless

For the first test, we leave the mode as 'stateless', and press the button three times. At the same time, we keep an eye on transaction SM04.

We see a number of very interesting aspects in the browser.

The first is that the counter is always one. Effectively, the session is stateless. Each time that the request hits the server, a completely new session (ABAP roll-area) is opened, and is used to execute this request. Thus, the BSP page is also re-created each time, resulting in the counter starting over. This is what would be expected from a stateless application.

The other interesting aspect is that the transaction SM04 shows only one session for us. However, the output of each request shows two sessions! During the time that the BSP page is being processed, there is actually an active session for this HTTP request. If we were very fast in refreshing the SM04 display (below 10 milliseconds!), we would actually see this second session for one moment. Directly after the HTTP request is processed, the session is cleared and does NOT exist anymore. However, during the brief time that the HTTP request is being processed, there does actually exist a normal Web AS session for this HTTP request.

After the HTTP request is processed, the session is closed, and the Web AS “forgets” completely about the user. No information is stored.

Stateful

For the next step, we switch to 'stateful' mode, and again press the button three times.

The first aspect we notice is that the counter is incremented, and now keeps state. This is the proof that we are running into the same session each time (so actually the session is kept even after the HTTP request has been processed).

Inside the request, again we see only two sessions listed at all times. One is the SAP GUI session that is open, and the other is the session for the HTTP request. If we look into transaction SM04, we also see both sessions there.

So even after the HTTP request is processed, the session is kept alive on the server.

Sidebar: HTTP, the One-Way Communication Protocol

In most communications, both partners are allowed to say something and keep the discussion alive. However, this is not true for HTTP. HTTP is a strictly request/response protocol. Only the browser is allowed to fire a request at the server. The server is only allowed to answer this specific request with a response.

It is not possible for the server to start a request to the browser, and it is not possible for the server to send a response, without having first received a request.

It's true that the HTTP/1.1 protocol allows the browser and server to keep the TCP/IP connection open between them for a short time after use, to reuse the same connection again. However, in terms of communication, the next HTTP request must still come from the browser. There is no way for the server to inform the browser of a specific event, such as a session termination.

Timer: Session Management

After about 35 minutes (after lunch!), we look into SM04 and see that only the SAP GUI session is listed. The server has completely “forgotten” about the HTTP session that was previously active. (In the browser, we see nothing of this event, due to the one-sided nature of the HTTP protocol.)

Session management is controlled by the profile parameter “rdisp/plugin_auto_logout”. This parameter, with a default value of 30 minutes, controls the time that a session can be idle before it is cleared.

Use transaction RZ11 to see/change this value. Important! Any change to this parameter affects all HTTP sessions for the application server!

After the idle timer expires, the session is silently cleared. All active locks are released.

Timer: HTTP Request Processing Time

The other interesting time is the length of time that one HTTP request will be processed before it is aborted. This time can be seen in transaction SMICM, under services. It is called “keep-alive” time (very unfortunate terminology), and is often confused with the session timeout value. This time is specified in the profile as part of the icm/server_port specification (which includes the port number to use, and the protocol for this port).

For our example program, we have a second button that will cause a very long-running HTTP request. We press this button and after waiting for ages, receive the answer in the browser:

After the timer expired, the ABAP processing of the HTTP request was aborted by ICM. The error message is returned by ICM (reflecting the “connection” between ICM and ABAP).

After the HTTP request processing is aborted, the session is still kept intact in Web AS 6.20. (To verify this, run the test program in stateful mode, increment the counter, and then press the wait button to cause the HTTP request processing error. Thereafter, delete the sequence “wait=Wait15seconds&” from the URL, and press ENTER again. The URL is submitted into the same session, and the counter will be incremented one more!) (Basic) Authentication

The last piece of the puzzle to explain is how basic authentication works. With this knowledge it will be possible to answer the initial question that led us down this road.

Below is a stripped down HTTP trace of the communications between the browser and the server.

<!code>  GET /sap/bc/bsp/sap/bcm06/session_test.htm HTTP/1.1

<!code>  Accept: /

<!code>   

<!code>  HTTP/1.1 401 Unauthorized

<!code>  www-authenticate: Basic realm="SAP Web Application Server  (B20)"

<!code>   

First, we enter the URL in the browser and it tries to access the page immediately. The server answers with 'unauthorized' (HTTP return code 401). Now the browser pops up a window asking for a user name and password. (We assume for this scenario simple basic authentication, and not the more interesting X.509 certificates, etc.)

<!code>  GET /sap/bc/bsp/sap/bcm06/session_test.htm HTTP/1.1

<!code>  Accept: /

<!code>  Authorization: Basic V2h5IG5vdCB3cml0ZSBhIFNETiBhcnRpY2xlPzpJdCBpcyBhIGxvdCBvZiBmdW4h

<!code>   

<!code>  HTTP/1.1 302 Moved temporarily

<!code>  location: /sap(bD1lbiZjPTAwMA==)/bc/bsp/sap/bcm06/session_test.htm

Now that the browser has the user name and password, the information is base64 encoded, and sent with the next request (in the “Authorization” header). The server receives an HTTP request from an authenticated user and passes the information to the BSP runtime. The BSP runtime does its URL mangling routine, and redirects the browser back to a new URL. (URL mangling is discussed in another BSP In-Depth article!).

<!code>  GET /sap(bD1lbiZjPTAwMA==)/bc/bsp/sap/bcm06/session_test.htm HTTP/1.1

<!code>  Accept: /

<!code>   

<!code>  HTTP/1.1 401 Unauthorized

<!code>  www-authenticate: Basic realm="SAP Web Application Server  (B20)"

<!code>   

<!code>  GET /sap(bD1lbiZjPTAwMA==)/bc/bsp/sap/bcm06/session_test.htm HTTP/1.1

<!code>  Accept: /

<!code>  Authorization: Basic V2h5IG5vdCB3cml0ZSBhIFNETiBhcnRpY2xlPzpJdCBpcyBhIGxvdCBvZiBmdW4h

<!code>   

<!code>  HTTP/1.1 200 OK

<!code>  content-length: 693

<!code>  content-type: text/html; charset=iso-8859-1

<!code>  ...

Now comes the most interesting sequence of all! The browser has a new URL to load (because of the redirect before). First, it tries to load this new URL without supplying any authentication information (notice no Authorization header!). The server does not like this request from an unknown user, and rejects it again. At this moment, the browser already has authorization information (keep the popup for user name and password in mind that was done previously). Therefore, the browser immediately again requests the new URL, but now supplies the authorization information that it had stored previously. The server is happy, the BSP runtime is even happier, and the BSP application is executed to do its song and dance. An OK answer (HTTP return code 200) is returned to the browser, and the page is displayed.

<!code>  GET /sap(bD1lbiZjPTAwMA==)/bc/bsp/sap/bcm06/session_test.htm HTTP/1.1

<!code>  Accept: /

<!code>  Authorization: Basic V2h5IG5vdCB3cml0ZSBhIFNETiBhcnRpY2xlPzpJdCBpcyBhIGxvdCBvZiBmdW4h

<!code>   

<!code>  HTTP/1.1 200 OK

<!code>  content-length: 693

<!code>  content-type: text/html; charset=iso-8859-1

<!code>  ...

From now on, the URL stays the same for the duration of the application, and the browser will always send the authorization information in all cases.

Summary: (basic) authentication is a feature of the browser. When requested from the server to supply some form of credentials, the browser will popup a window asking for this information. Thereafter, this information is used sparingly. For all new URLs, the browser will first attempt to access the URL without the authorization information it had stored. Only on failure is a second attempt made with the authorization header.

Sidebar: Defining a New ICM Service/Port

Each HTTP request is only allowed a limited time to be processed before ICM will abort processing, and return an HTTP return code 500. For usual production systems, this time is typically set between 15 and 90 seconds. This allows each request to be processed completely, and at the same time guards that the HTTP requests do not run out of control. (Effectively one aspect of a denial of service attack that must be controlled.)

Once a colleague debugged very fast for about 60 seconds, and then he spoke a few words of perfect German, before starting again. (No wonder my wife keeps asking me where I learn German :). The reason is that after 60 seconds, the processing time was up, and ICM aborted the HTTP request, and so the debugging session was stopped.

The solution is very simple: It's possible to define a new HTTP service (port) dynamically. For the new port, define a large processing time, say 900 seconds (= 15 minutes).

To do this, start transaction SMICM. Menu: Goto --> Services --> Menu: Go To --> Service --> Define. Specify a new port number and a large “keep alive” time. When testing, just change the port number in the URL to use the newly defined one.

This is the same technique used in this test program to get a very short processing time, so you do not wait for ages.

!https://weblogs.sdn.sap.com/weblogs/images/13/BSP-InDepthConfusion-Between-Stateless-Stateful-And-Authentication_007.GIF|height=362|width=552|src=https://weblogs.sdn.sap.com/weblogs/images/13/BSP-InDepthConfusion-Between-Stateless-Stateful-And-Authentication_007.GIF|border=0!</body>

10 Comments