Files
apollinare-catering-software/docs/packages/XLIB_HTTP.md
2025-12-17 13:02:12 +01:00

15 KiB
Raw Blame History

XLIB_HTTP

Package Specification

PACKAGE      "XLIB_HTTP"
AS
/*=========================================================================

  Purpose  : Make http callouts

  License  : Copyright (c) 2010 Dietmar Aust (opal-consulting.de)
             Licensed under a BSD style license (license.txt)
             http://www.opal-consulting.de/pls/apex/f?p=20090928:14

 Version Date        Author           Comment
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
         19.02.2007  D. Aust          initial creation
         07.08.2008  D. Aust          - added check_get_request
                                      - display_url_raw: pass all request headers
                                          to the client
         05.08.2012  D. Aust		      suppress mime header TRANSFER-ENCODING,
                                        causes lots of problems with XMLDB listener
                                        and others choking.
 2.3.0.0 19.05.2014  D. Aust          - #294 - Fix chunked encoding problem in
                                          xlib_http.get_report
                                      - added version information to this package
 2.3.0.0 09.05.2015  D. Aust          pass JSESSIONID from backend J2EE server to client
                                        for image rendering in html reports
 2.6.1   28.09.2020  D. Aust          - #40 - APEX 20.1 security bundle (PSE 30990551) rejects response header "Cache-Control: private"
 2.6.2   13.10.2020  D. Aust          - added function check_acl()

=========================================================================*/

   c_success   CONSTANT CHAR (1) := '1';
   c_fail      CONSTANT CHAR (1) := '0';

  -- version of this package
  version_c constant varchar2(20 char) := '2.6.2';

  TYPE vc_arr_t IS TABLE OF VARCHAR2 (32767) INDEX BY BINARY_INTEGER;
  g_empty_vc_arr vc_arr_t;

/* Function: MyFunction
 *
 * Parameters:
 *
 *    x - Description of x.
 *    y - Description of y.
 *    z - Description of z.
 */
   PROCEDURE display_url_raw (
      p_url                       VARCHAR2,
      p_mime_type_override   IN   VARCHAR2 DEFAULT NULL,
      p_charset              IN   VARCHAR2 DEFAULT NULL,
      p_header_name_arr      IN   vc_arr_t default g_empty_vc_arr,
      p_header_value_arr     IN   vc_arr_t default g_empty_vc_arr
   );

/* Procedure: retrieve_blob_from_url

   Multiplies two integers.

   Parameters:

      p_url - url to be called

      o_blob - output: the resulting out blob
      o_mime_type - output: the resulting out mime type from the call

   Returns:

      The two integers multiplied together.
      o_blob - the resulting out blob

   See Also:

      <escape_form_data>
*/
   PROCEDURE retrieve_blob_from_url (
      p_url               VARCHAR2,
      o_blob        OUT   BLOB,
      o_mime_type   OUT   VARCHAR2
   );

/*
Function: escape_form_data
Here is some describing text ...

--- SQL
declare
  l_i number;
begin
  null;

  Select count(*)
    into l_count
    from dual;
end;
---


Parameters:
  s - string to be escaped

Returns:
the escaped data
*/
   FUNCTION escape_form_data (s VARCHAR2)
      RETURN VARCHAR2;

/*
Function: check_get_request

Parameters:
   p_url    the url to be called

Returns:
   Returns c_fail or c_success

*/
   FUNCTION check_get_request (p_url VARCHAR2)
      RETURN CHAR;

/*
Function: check_acl

Parameters:
   p_url    the url to be called

Returns:
   Returns c_fail or c_success
*/
   FUNCTION check_acl (p_url VARCHAR2)
      RETURN CHAR;
END;```

## Package Body

```sql
PACKAGE BODY      "XLIB_HTTP"
AS
/*=========================================================================

  Purpose  : Make http callouts

  License  : Copyright (c) 2010 Dietmar Aust (opal-consulting.de)
             Licensed under a BSD style license (license.txt)
             https://github.com/daust/JasperReportsIntegration

 Version Date        Author           Comment
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
         19.02.2007  D. Aust          initial creation
         07.08.2008  D. Aust          - added check_get_request
                                      - display_url_raw: pass all request headers
                                          to the client
         05.08.2012  D. Aust		      suppress mime header TRANSFER-ENCODING,
                                        causes lots of problems with XMLDB listener
                                        and others choking.
 2.3.0.0 19.05.2014  D. Aust          - #294 - Fix chunked encoding problem in
                                          xlib_http.get_report
                                      - added version information to this package
 2.3.0.0 09.05.2015  D. Aust          pass JSESSIONID from backend J2EE server to client
                                        for image rendering in html reports
 2.6.1   28.09.2020  D. Aust          - #40 - APEX 20.1 security bundle (PSE 30990551) rejects response header "Cache-Control: private"
 2.6.2   13.10.2020  D. Aust          - added function check_acl()

=========================================================================*/

   m_module   VARCHAR2 (50) := 'XLIB_HTTP';

   PROCEDURE display_url_raw (
      p_url                       VARCHAR2,
      p_mime_type_override   IN   VARCHAR2 DEFAULT NULL,
      p_charset              IN   VARCHAR2 DEFAULT NULL,
      p_header_name_arr      IN   vc_arr_t default g_empty_vc_arr,
      p_header_value_arr     IN   vc_arr_t default g_empty_vc_arr
   )
   IS
      l_http_request       UTL_HTTP.req;
      l_http_response      UTL_HTTP.resp;
      l_blob               BLOB;
      l_raw                RAW (32767);
      l_buffer_size        NUMBER          := 32767;
      --
      l_proc               VARCHAR2 (100)  := m_module || '.DISPLAY_URL_RAW';
      --
      l_mime_type          VARCHAR2 (100);
      l_header_name        VARCHAR2 (256);
      l_header_value       VARCHAR2 (1024);
      l_jsession           VARCHAR2 (256);
      l_path               VARCHAR2 (1024);
      --
      l_header_name_arr    vc_arr_t;
      l_header_value_arr   vc_arr_t;
      --
      l_msg                varchar2(32767);
   BEGIN
      xlog (l_proc, 'show url: ' || p_url);
      --htp.flush();
      --htp.init();

      -- Initialize the BLOB.
      DBMS_LOB.createtemporary (l_blob, FALSE);

      l_http_request := UTL_HTTP.begin_request (url          => p_url,
                                                method       => 'GET',
                                                http_version => utl_http.http_version_1_0);

      utl_http.set_header (l_http_request, 'Connection', 'Keep-Alive');

      -- pass additional headers to the target service
      for i in 1..p_header_name_arr.count loop
        xlog(l_proc, 'pass additional headers to target service: '|| p_header_name_arr(i) ||': '||p_header_value_arr(i));
        utl_http.set_header(l_http_request, p_header_name_arr(i), p_header_value_arr(i));
      end loop;

      -- get response from target service
      l_http_response := UTL_HTTP.get_response (l_http_request);

      FOR i IN 1 .. UTL_HTTP.get_header_count (l_http_response)
      LOOP
         UTL_HTTP.get_header (l_http_response,
                              i,
                              l_header_name,
                              l_header_value
                             );
         -- store header value in arr
         l_header_name_arr (i) := l_header_name;
         l_header_value_arr (i) := l_header_value;

         IF LOWER (l_header_name) = 'content-type'
         THEN
            l_mime_type := l_header_value;
            xlog(l_proc, 'content-type from server: ' || l_mime_type);
         END IF;
      END LOOP;

      -- override mime type
      IF p_mime_type_override IS NOT NULL
      THEN
         l_mime_type := p_mime_type_override;
      END IF;

      -- Copy the response into the BLOB.
      BEGIN
         LOOP
            UTL_HTTP.read_raw (l_http_response, l_raw, l_buffer_size);
            DBMS_LOB.writeappend (l_blob, UTL_RAW.LENGTH (l_raw), l_raw);
         END LOOP;
      EXCEPTION
         WHEN UTL_HTTP.end_of_body
         THEN
            UTL_HTTP.end_response (l_http_response);
      END;

      xlog(l_proc, 'set content-type: ' || l_mime_type);
      OWA_UTIL.mime_header (ccontent_type      => l_mime_type,
                            bclose_header      => FALSE,
                            ccharset           => p_charset
                           );

      FOR i IN 1 .. l_header_name_arr.COUNT
      LOOP
         IF UPPER (l_header_name_arr (i)) IN
                              ('CONTENT-LENGTH', 'CONTENT-TYPE', 'MIME-TYPE', 'TRANSFER-ENCODING',
                               'STRICT-TRANSPORT-SECURITY', 'CACHE-CONTROL', 'PRAGMA', 'EXPIRES')
         THEN
            --xlog (l_proc, 'skip header ' || l_header_name_arr (i));
            null;
         ELSE
            if upper(l_header_name_arr(i)) = 'SET-COOKIE' and l_header_value_arr (i) like 'JSESSIONID%' then
              xlog(l_proc , 'JSESSION_ID found !!!:'||l_header_value_arr (i));
              --extract path
              l_jsession := regexp_substr(l_header_value_arr (i), 'JSESSIONID=(.*);[ ]*Path',1, 1,'i',1);
              l_path := regexp_substr(l_header_value_arr (i), ';[ ]*Path=(.*)',1, 1,'i',1);

              xlog(l_proc, 'xx:full:'||l_header_value_arr (i)|| '; xx:session:'||l_jsession || '; xx:path:'||l_path);
            else
              l_header_value := l_header_value_arr (i);
            end if;
            xlog (l_proc,
                  'set header:'
               || l_header_name_arr (i)
               || ': '
               || l_header_value
              );
            HTP.p (l_header_name_arr (i) || ': ' || l_header_value);
         END IF;
      END LOOP;

      -- JSESSION Cookies ausgeben
      -- if using tunnel, then the cookie is JRI_JSESSIONID
      -- if not using tunnel, then cookie is JSESSIONID directly
      --
      if xlib_jasperreports.get_use_images_no_tunnel=false then
          l_msg := 'Set-Cookie: ' || xlib_jasperreports.m_jri_cookie_name_c || '=' || l_jsession;
          xlog (l_proc, 'set header:' || l_msg );
          HTP.p (l_msg);
          l_msg := 'Set-Cookie: ' || xlib_jasperreports.m_jri_path_cookie_name_c || '=' || l_path;
          xlog (l_proc, 'set header:' || l_msg );
          HTP.p (l_msg);
      else
          l_msg := 'Set-Cookie: JSESSIONID=' || l_jsession;
          if xlib_jasperreports.get_cookie_path_no_tunnel is not null then
            l_msg := l_msg || '; Path=' || xlib_jasperreports.get_cookie_path_no_tunnel;
          end if;
          xlog (l_proc, 'set header:' || l_msg );
          HTP.p (l_msg);
      end if;

      -- set content length
      HTP.p ('Content-length: ' || DBMS_LOB.getlength (l_blob));
      OWA_UTIL.http_header_close;
      WPG_DOCLOAD.download_file (l_blob);
      -- Relase the resources associated with the temporary LOB.
      DBMS_LOB.freetemporary (l_blob);
   EXCEPTION
      WHEN UTL_HTTP.end_of_body
      THEN
         UTL_HTTP.end_response (l_http_response);
         DBMS_LOB.freetemporary (l_blob);
         RAISE;
      WHEN OTHERS
      THEN
         xlog (l_proc, 'Error: ' || SQLERRM, 'ERROR');
         RAISE;
   END;

   PROCEDURE retrieve_blob_from_url (
      p_url               VARCHAR2,
      o_blob        OUT   BLOB,
      o_mime_type   OUT   VARCHAR2
   )
   IS
      l_http_request    UTL_HTTP.req;
      l_http_response   UTL_HTTP.resp;
      l_raw             RAW (32767);
      --
      l_proc            VARCHAR2 (100)
                                     := m_module || '.RETRIEVE_BLOB_FROM_URL';
      --
      l_header_name     VARCHAR2 (256);
      l_header_value    VARCHAR2 (1024);
   BEGIN
      -- Initialize the BLOB.
      dbms_lob.createtemporary (o_blob, false);
      l_http_request := utl_http.begin_request (url          => p_url,
                                                method       => 'GET',
                                                http_version => utl_http.http_version_1_0);

      l_http_response := UTL_HTTP.get_response (l_http_request);

      FOR i IN 1 .. UTL_HTTP.get_header_count (l_http_response)
      LOOP
         UTL_HTTP.get_header (l_http_response,
                              i,
                              l_header_name,
                              l_header_value
                             );

         IF LOWER (l_header_name) = 'content-type'
         THEN
            o_mime_type := l_header_value;
         END IF;
      END LOOP;

      -- Copy the response into the BLOB.
      BEGIN
         LOOP
            UTL_HTTP.read_raw (l_http_response, l_raw, 32767);
            DBMS_LOB.writeappend (o_blob, UTL_RAW.LENGTH (l_raw), l_raw);
         END LOOP;
      EXCEPTION
         WHEN UTL_HTTP.end_of_body
         THEN
            UTL_HTTP.end_response (l_http_response);
      END;
   -- Relase the resources associated with the temporary LOB.
   --DBMS_LOB.freetemporary (l_blob);
   EXCEPTION
      WHEN OTHERS
      THEN
         UTL_HTTP.end_response (l_http_response);
         DBMS_LOB.freetemporary (o_blob);
         xlog (l_proc, 'Error: ' || SQLERRM, 'ERROR');
         RAISE;
   END;

   FUNCTION escape_form_data (s VARCHAR2)
      RETURN VARCHAR2
   IS
      l_s   VARCHAR2 (500 CHAR);

      FUNCTION r (s VARCHAR2, c VARCHAR2)
         RETURN VARCHAR2
      IS
      BEGIN
         RETURN REPLACE (s, c, '%' || TRIM (TO_CHAR (ASCII (c), 'XX')));
      END;
   BEGIN
      l_s := s;
      l_s := REPLACE (l_s, ' ', '+');
      l_s := r (l_s, chr(37));  -- %
      l_s := r (l_s, chr(37));  -- /
      l_s := r (l_s, chr(63));  -- ?
      l_s := r (l_s, chr(38));  -- &
      l_s := r (l_s, chr(228));  -- <20><><EFBFBD>
      l_s := r (l_s, chr(196));  -- <20><>
      l_s := r (l_s, chr(246));  -- <20><>
      l_s := r (l_s, chr(214));  -- <20><>
      l_s := r (l_s, chr(252));  -- <20><>
      l_s := r (l_s, chr(220));  -- <20><><EFBFBD>
      l_s := r (l_s, chr(223));  -- <20><><EFBFBD>
      RETURN l_s;
   END;

   FUNCTION check_get_request (p_url VARCHAR2)
      RETURN CHAR
   IS
      l_clob   CLOB;
   BEGIN
      IF p_url IS NULL
      THEN
         RETURN c_fail;
      END IF;

      SELECT HTTPURITYPE (p_url).getclob ()
        INTO l_clob
        FROM DUAL;

      /*SELECT c_success
        INTO l_ret
        FROM DUAL
       WHERE EXISTS (SELECT HTTPURITYPE (p_url).getclob ()
                       FROM DUAL);
                       */
      RETURN c_success;
   EXCEPTION
      WHEN OTHERS
      THEN
         RETURN c_fail;
   END;

   FUNCTION check_acl (p_url VARCHAR2)
      RETURN CHAR
   IS
      l_clob   CLOB;
   BEGIN
      IF p_url IS NULL
      THEN
         RETURN c_fail;
      END IF;

      SELECT HTTPURITYPE (p_url).getclob ()
        INTO l_clob
        FROM DUAL;

      /*SELECT c_success
        INTO l_ret
        FROM DUAL
       WHERE EXISTS (SELECT HTTPURITYPE (p_url).getclob ()
                       FROM DUAL);
                       */
      RETURN c_success;
   EXCEPTION
      WHEN OTHERS
      THEN
         -- acl problem
         if sqlcode=24247 then
           RETURN c_fail;
         else
            -- no acl problem
            return c_success;
         end if;
   END;
END;```