So, I'm working on a web services project.
Basically, it boils down to:
- PL/SQL side uploads a PDF file, then Base64-encodes this file, then sends it to my REST webservice.
- 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).
- 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.
- 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).
- 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;