html - Strange Base64 encode/decode problem -
i'm using grails 1.3.7. have code uses built-in base64encode function , base64decode function. works fine in simple test cases encode binary data , decode resulting string , write new file. in case files identical.
but wrote web service took base64 encoded data parameter in post call. although length of base64 data identical string passed function, contents of base64 data being modified. spend days debugging , wrote test controller passed data in base64 post , took name of local file correct base64 encoded data, in:
data=aaa-base-64-data...&testfilename=/name/of/file/with/base64data within test function compared every byte in incoming data parameter appropriate byte in test file. found somehow every "+" character in input data parameter had been replaced " " (space, ordinal ascii 32). huh? have done that?
to sure correct, added line said:
data = data.replaceall(' ', '+') and sure enough data decoded right. tried arbitrarily long binary files , works every time. can't figure out life of me modifying data parameter in post convert ord(43) character ord(32)? know plus sign 1 of 2 platform dependent characters in base64 spec, given doing encoding , decoding on same machine super puzzled caused this. sure have "fix" since can make work, nervous "fixes" don't understand.
the code big post here, base64 encoding so:
def inputfile = new file(inputfilename) def rawdata = inputfile.getbytes() def encoded = rawdata.encodebase64().tostring() i write encoded string out new file can use testing later. if load file in same rawdata:
def encodedfile = new file(encodedfilename) string encoded = encodedfile.gettext() byte[] rawdata = encoded.decodebase64() so good. assume take "encoded" variable , add param post function so:
string querystring = "data=$encoded" string url = "http://localhost:8080/some_web_service" def results = urlpost(url, querystring) def urlpost(string urlstring, string querystring) { def url = new url(urlstring) def connection = url.openconnection() connection.setrequestmethod("post") connection.dooutput = true def writer = new outputstreamwriter(connection.outputstream) writer.write(querystring) writer.flush() writer.close() connection.connect() return (connection.responsecode == 200) ? connection.content.text : "error $connection.responsecode, $connection.responsemessage" } on web service side, in controller parameter so:
string data = params?.data println "incoming data parameter has length of ${data.size()}" //confirm right size //unless run following line, data not decode same source data = data.replaceall(' ', '+') //as long replace spaces plus, decodes correctly, why? byte[] bytedata = data.decodebase64() sorry long rant, i'd love understand why had "replace space plus sign" decode correctly. there problem plus sign being used in request parameter?
whatever populates params expects request url-encoded form (specifically, application/x-www-form-urlencoded, "+" means space), didn't url-encode it. don't know functions language provides, in pseudo code, querystring should constructed from
concat(uri_escape("data"), "=", uri_escape(base64_encode(rawbytes))) which simplifies to
concat("data=", uri_escape(base64_encode(rawbytes))) the "+" characters replaced "%2b".
Comments
Post a Comment