Persistent connection

Discussions related to HTTPAPI (An HTTP Client Package for RPG programming.) http://www.scottklement.com/httpapi/
Post Reply
Alan5432
Posts: 5
Joined: Mon Sep 26, 2022 10:03 pm

Persistent connection

Post by Alan5432 »

I'm trying to do multiple http_req('POST'... operations through TLS and it appears to be closing the connection after each post response is processed. Is there something that can be done to continue to re-use the established connection until the timeout is reached?

Code: Select all

recvresp(): entered
HTTP/1.1 200 OK
Cache-Control: private
Content-Type: application/json; charset=utf-8
Date: Wed, 19 Oct 2022 20:04:53 GMT
Content-Length: 2442
Strict-Transport-Security: max-age=15552000; includeSubDomains


SetError() #13: HTTP/1.1 200 OK
recvresp(): end with 200
recvdoc parms: identity 2442
header_load_cookies() entered
recvdoc(): entered
SetError() #0:
recvdoc(): Receiving 2442 bytes.
...
http_close(): entered
HTTPAPI Ver 1.45 released 2021-09-20
NTLM Ver 1.4.0 released 2014-12-22
OS/400 Ver V7R4M0

http_persist_open(): entered
Scott Klement
Site Admin
Posts: 635
Joined: Sun Jul 04, 2021 5:12 am

Re: Persistent connection

Post by Scott Klement »

You would need to change your code to call the following routines:
  1. http_persist_open(): This establishes the initial connection to the server that will persist. This returns a connection handle to the opened connection.
  2. http_persist_req(): This may be called many times (with a different URL each time, provided that it points to the same host/port) with the connection handle from step 1. Calling this with the connection handle ensures that it uses the already open connection. If for some reason you get a network error on that connection, you will have to close the connection and call http_persist_open again.
  3. http_persist_close(): This is called when you are ready to disconnect from the server.
Alan5432
Posts: 5
Joined: Mon Sep 26, 2022 10:03 pm

Re: Persistent connection

Post by Alan5432 »

I'm struggling with http_persist_req(). I'm using string variables for my send and receive and the send is working fine. In http_req the RcvProc is set to the %PADDR of RcvToBuf, but I don't think I have access to that internal procedure.

I saw several examples that used the IFS for the receive with - http_persist_get( pComm: URL: fd: %paddr('write')).

What do I use for the peSaveProc (procptr) parameter in http_persist_req if I'm using a string variable?
Scott Klement
Site Admin
Posts: 635
Joined: Sun Jul 04, 2021 5:12 am

Re: Persistent connection

Post by Scott Klement »

You would need to provide your own subprocedure that puts the data into a string variable.

Here's a simple example:

Code: Select all

**free
 Ctl-Opt DFTACTGRP(*NO) ACTGRP(*NEW) BNDDIR('HTTPAPI');

/define WEBFORMS
/copy qrpglesrc,httpapi_h

 Dcl-C CRLF       CONST(x'0D25');
 Dcl-S rc           Int(10);
 Dcl-S fromAddr     Varchar(100);
 Dcl-S Subject      Varchar(100);
 Dcl-S Message      Varchar(1000);
 Dcl-S formData     Varchar(32767);
 dcl-s result       varchar(500000) ccsid(*utf8);
 dcl-s url          varchar(500);
 dcl-s comm         pointer;

 http_debug(*on: '/tmp/persist_example_log.txt');

 //
 // CHANGE THIS TO YOUR E-MAIL ADDRESS:
 //
 FromAddr = 'example4@scottklement.com';

 //
 // CHANGE THIS TO THE SUBJECT YOU'D LIKE SENT TO ME:
 //
 Subject = 'EXAMPLE4 from HTTPAPI.';

 //
 // CHANGE THIS TO THE MESSAGE YOU'D LIKE SENT TO ME:
 //
 Message = 'Hi Scott!' + CRLF +
           '  Just a note to tell you that I''m testing out the +
           EXAMPLE4 program in HTTPAPI. If you receive this, it +
           must work!' + CRLF;

 //
 // Encode the data as it would appear on a web form
 //

 formData = 'from=' + http_urlEncode(FromAddr)
          + '&subject=' + http_urlEncode(Subject)
          + '&Comment=' + http_urlEncode(message);


 url = 'http://www.scottklement.com/cgi-bin/email_comment.cgi';

 comm = http_persist_open(url);

 if comm = *null;
   http_crash();
 endif;

 result = '';

 rc = http_persist_req( 'POST'
                      : comm
                      : url
                      : 0
                      : *null
                      : %addr(formData:*data)
                      : %len(formData)
                      : 0
                      : %paddr(Save2String)
                      : HTTP_TIMEOUT
                      : *omit
                      : 'application/x-www-form-urlencoded' );

 if rc=302;
    rc = http_persist_req( 'GET'
                         : comm
                         : http_redir_loc()
                         : 0
                         : *null
                         : *null
                         : 0
                         : 0
                         : %paddr(Save2String) );
 endif;

 // the "result" variable now contains the result of calling the server.

 // perform additional requests (must be to the same server) by calling http_persist_req
 // more times here.

 http_persist_close(comm);


 //
 // If there's an error, use the DSPLY opcode to show it on the
 // screen.   If not, use the DSPF command from OS/400 to display
 // the data that was returned onto the screen.
 //
 if rc <> 1;
    http_crash();
 endif;

 *inlr = *on;

 dcl-proc save2string;

   dcl-pi *n int(10);
     fd   int(10) value;
     data char(65535) options(*varsize) ccsid(*utf8);
     len  int(10) value;
   end-pi;

   if len > 0;
     result += %subst(data:1:len);
   endif;

   return len;
end-proc; 
fwiw, http_persist_req is considered a "lower level" routine, intended more for flexibility than for easy of use. If you're making many requests of the same server in a short amount of time, the fact that it leaves the connection open can make a huge performance difference. Most people don't need that, so this is really just out there for a few people (and for internal use of HTTPAPI) that need to do something special.
Post Reply