1

When calling a web service using utl_http, the calls fail when the SOAP envelope contains characters like ¿, ± or º.

IS
     http_req  utl_http.req;
     http_resp utl_http.resp;
     request_env varchar2(32767);
     response_env varchar2(32767); 
BEGIN

    request_env:='
<soap:Envelope 
     ...
</soap:Envelope>';

    http_req := utl_http.begin_request('http://ws.domain.com/Project.asmx', 'POST', utl_http.HTTP_VERSION_1_1);
    utl_http.set_header(http_req, 'Content-Type', 'text/xml; charset=utf-8');
    utl_http.set_header(http_req, 'Content-Length', length(request_env));
    utl_http.set_header(http_req, 'SOAPAction', '"http://domain.com/WS/ProjectAction"');
    utl_http.write_text(http_req, request_env);

I thought that charset=utf-8 in Content-Type should take care of that, but it still bombs and the characters above have to be replaced to their ASCII multi-characters equivalents beforehand.

This is an NLS report for this database:

NLS_CALENDAR    GREGORIAN
NLS_CHARACTERSET    WE8ISO8859P1
NLS_COMP    BINARY
NLS_CURRENCY    $
NLS_DATE_FORMAT DD-MON-RR
NLS_DATE_LANGUAGE   AMERICAN
NLS_DUAL_CURRENCY   $
NLS_ISO_CURRENCY    AMERICA
NLS_LANGUAGE    AMERICAN
NLS_LENGTH_SEMANTICS    BYTE
NLS_NCHAR_CHARACTERSET  AL16UTF16
NLS_NCHAR_CONV_EXCP FALSE
NLS_NUMERIC_CHARACTERS  .,
NLS_SORT    BINARY
NLS_TERRITORY   AMERICA
NLS_TIMESTAMP_FORMAT    DD-MON-RR HH.MI.SSXFF AM
NLS_TIMESTAMP_TZ_FORMAT DD-MON-RR HH.MI.SSXFF AM TZR
NLS_TIME_FORMAT HH.MI.SSXFF AM
NLS_TIME_TZ_FORMAT  HH.MI.SSXFF AM TZR

I am kind of consulting the in-house developers on this issue and before I will try to convince them to try redeclare request_env as NVARCHAR2, wanted to get the community opinion on whether that should be the fix they should attempt.

Jack Douglas
  • 40,517
  • 16
  • 106
  • 178
ajeh
  • 911
  • 5
  • 14
  • 31

2 Answers2

1

The problem is length or lengthb functions treat these special characters as 1 byte but write_text function (correctly) considers these as 2 bytes. Hence a mal-formed XML is sent to the server.

To resolve this error please use the following instead of the length / lengthb function.

lv_clob_length_bytes := utl_raw.length(utl_raw.convert(utl_raw.cast_to_raw(lv_request_body),'american_america.al32utf8','ENGLISH_UNITED KINGDOM.WE8ISO8859P15'));

The above casts the XML to raw and then converts it from our characterset to UTF8 before finding its length.

Sridhar
  • 11
  • 1
-1

Change write_text to write_raw like this:

UTL_HTTP.WRITE_RAW (r    => http_req,
                data => UTL_RAW.CAST_TO_RAW(request_env));