Question

So, I'm working on a web services project.

Basically, it boils down to:

  1. PL/SQL side uploads a PDF file, then Base64-encodes this file, then sends it to my REST webservice.
  2. Java webservice receives the file. I save this file before doing anything else (just for a test): as expected, the file is corrupt (it's a Base64-string, this is normal).
  3. Java webservice Base64-decodes the file and then proceeds to do whatever it needs to do with the file. I save the file once again after this decoding, and once again it works as expected and I'm able to open and read the PDF.
  4. PL/SQL now requests to re-download the file. I re-encode the file and send it back to the requestor. I save the file after encoding, and as expected (it's Base64 encoded again): it doesn't work (corrupt).
  5. PL/SQL receives the file, Base64-decodes the file and tries to open it... Bam, corrupt, unable to read the file.

Probably something is wrong between the communication: it's Base64-encoded in Java, Base64-decoded in PL/SQL. You'd suspect there'd be no difference as it's using a standard (I guess Base64 is standard, right?).

We tried both options: after I re-encode the PDF in Java, I try to once again re-decode it and save it; this file is correct and I'm able to read the PDF. So we'd suppose the encoding in Java is correct. We also tried this in PL/SQL - upload a BLOB, encode to Base64, decode it back, download and open. This also works. So we'd suppose the encoding and decoding part in PL/SQL works, too.

What is weird is that I can Base64 encode the file in PL/SQL, then decode it in Java, then save and read it. It only goes wrong when I re-encode the file in Java and try to decode it in PL/SQL. So that sounds to me like there can't really be a problem between standards used in PL/SQL - Java, because then the first step would fail too.

We're using the commons library in Java (org.apache.commons.codec.binary.Base64). In PL/SQL, we've tried using the UTL-packages as well as a custom method as well as a Java stored procedure as well as the Apex_webservice (apex_web_service.blob2clobbase64(p_blob) and apex_web_service.clobbase642blob(p_clob)). They all give the same result.

We're slowly running out of ideas. Is there anyone who has another, better idea?

Thanks!

--- EDIT ---

This is how the file is decoded in PL/SQL:

FUNCTION encode_base64 (p_blob_in IN BLOB) 
    RETURN CLOB IS
        v_clob             CLOB;
        v_result           CLOB;
        v_offset           INTEGER;
        v_chunk_size       BINARY_INTEGER := (48 / 4) * 3;
        v_buffer_varchar   VARCHAR2 (48);
        v_buffer_raw       RAW (48);
    BEGIN
        IF p_blob_in IS NULL THEN
            RETURN NULL;
        END IF;
        DBMS_LOB.createtemporary (v_clob, TRUE);
        v_offset := 1;
        FOR i IN 1 .. CEIL (DBMS_LOB.getlength (p_blob_in) / v_chunk_size) LOOP
            DBMS_LOB.read (p_blob_in, v_chunk_size, v_offset, v_buffer_raw);
            v_buffer_raw := UTL_ENCODE.base64_encode (v_buffer_raw);
            v_buffer_varchar := UTL_RAW.cast_to_varchar2 (v_buffer_raw);
            DBMS_LOB.writeappend (v_clob, LENGTH (v_buffer_varchar), v_buffer_varchar);
            v_offset := v_offset + v_chunk_size;
        END LOOP;
        v_result := v_clob;
        DBMS_LOB.freetemporary (v_clob);
        RETURN v_result;
END encode_base64;

This is how the file is encoded in Java:

byte[] content = /*Here is my content in bytes. Before encoding, when I save, this is correct*/
Base64.encodeBase64String(content);

--- EDIT 2 ---

I accidently added the decode part in PL/SQL above. Here's the encode part in PL/SQL.

function decode_base64(p_clob_in in clob) return blob is
    v_blob blob;
    v_result blob;
    v_offset integer;
    v_buffer_size binary_integer := 48;
    v_buffer_varchar varchar2(48);
    v_buffer_raw raw(48);
    begin
        if p_clob_in is null then
            return null;
        end if;
        dbms_lob.createtemporary(v_blob, true);
        v_offset := 1;
        for i in 1 .. ceil(dbms_lob.getlength(p_clob_in) / v_buffer_size) loop
            dbms_lob.read(p_clob_in, v_buffer_size, v_offset, v_buffer_varchar);
            v_buffer_raw := utl_raw.cast_to_raw(v_buffer_varchar);
            v_buffer_raw := utl_encode.base64_decode(v_buffer_raw);
            dbms_lob.writeappend(v_blob, utl_raw.length(v_buffer_raw), v_buffer_raw);
            v_offset := v_offset + v_buffer_size;
        end loop;
        v_result := v_blob;
        dbms_lob.freetemporary(v_blob);
        return v_result;
end decode_base64;
Was it helpful?

Solution

Most of this kind of problems come from small things...

So what happened? I'm sending the Base64-String back inside an XML. In PL/SQL we extract that String into a clob before we decode it back to a blob.

We printed and checked that String... it was correct.

When we tried to check the difference between the clob we send from PL/SQL with the clob we get back in PL/SQL, we found some char(10) & char(13) - linebreaks, essentially. Not visible for the eye, but making the clob (and decoded blob) corrupt. A translate function got those out and now it works as a charm.

Thanks for all the help!

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top