Convert byteArray to XSSFWorkbook using Apache POI - java

I am using Apache POI and I am trying to send a xlsx file as HTTP request and get it back as response. I am using jayway restassured for making HTTP requests.
Here is the part of the code where I send the request
File file = new File("path");
String response = given().multipart(file).when().post("URL").getBody().asString();
byte[] bytes = response.getBytes("ISO-8859-1");
InputStream stream = new ByteArrayOutputStream(bytes);
try
{
XSSFWorkbook workbook = new XSSFWorkbook(stream);
}
catch(Exception e){
e.printStackTrace();
}
Here is the code where the response is generated for the request
XSSFWorkbook workBook; //this workBook has the workbook sent as HTTP request
//code to make changes in workBook
ByteArrayOutputStream outStream = new ByteArrayOutputStream();
workBook.write(outStream);
byte[] byteArray = outStream.toByteArray();
String responseBody = new String(byteArray, "ISO-8859-1");
context.response().putHeader("Content-Type", "multipart/form-data").setStatusCode(200).end(responseBody);
So, what I am trying to do is send a xlsx file as request make some changes and get it back as a string response, convert it back to xssfworkbook. When converting back I get error in the following line-
XSSFWorkbook workbook = new XSSFWorkbook(stream);
The error I get is
java.util.zip.ZipException: invalid code lengths set

You cannot simply send the byte-array as ISO-8859-1 encoded text the way you attempt.
There will be special characters that might get replaced/truncated/modified.
Currently you mix binary data and a text-only channel (HTTP). You will need to do it differently, either use a binary data transfer and not convert it to String or use some binary-to-text representation, see e.g. https://en.wikipedia.org/wiki/Binary-to-text_encoding, the most common one being Base64

Use
InputStream stream = new ByteArrayInputStream(bytes);

Related

How to send Request file path in JSON request in Jmeter Test

All i am new to Jmeter and i am trying to create a rest api request that i can use to do some load test. I was able to authenticate and proceed to the next step of sending the post request.
Our Request is basically something like this
{"id" : 112, "someversion" : "2.0", "policyData" : "C:/TEMP/PGF/someinput.json" }
i was able to capture on the server what a sample request looks like. It seems that we are zipping and doing some base64 encoding before we send the request......
My main Question is how can i zip and encode this before posting so it can be similar to that format.
I have tried the following in jsr223 preprocessor:
import org.apache.commons.io.IOUtils;
import java.util.zip.GZIPOutputStream;
import org.apache.commons.codec.binary.Base64;
String bodyString = sampler.getArguments().getArgument(0).getValue();
byte [] requestBody = bodyString.getBytes();
ByteArrayOutputStream out = new ByteArrayOutputStream(requestBody.length);
GZIPOutputStream gzip = new GZIPOutputStream(out);
so in here i need to zip this. it seems it zipping and my request is as this:
I am thinking i just need to encode the policy data only and not the entire request ......
I need to do something like this in java and encrypt that file possibly before I send it in the request.
using (var cryptStream = new CryptoStream(streamWriter.BaseStream, new
ToBase64Transform(), CryptoStreamMode.Write, leaveOpen: true))
using (var gzipStream = new GZipStream(cryptStream,
CompressionMode.Compress))
using (var inputFile = new FileStream(requestData.policyData,
FileMode.Open, FileAccess.Read))
{
inputFile.CopyTo(gzipStream);
}
I think you need to:
Extract the path to file from the request body using JsonSlurper
GZip this file content
Encode the bytes array to Base64
Example code:
String bodyString = sampler.getArguments().getArgument(0).getValue();
File policyData = new File(new groovy.json.JsonSlurper().parseText(bodyString).policyData)
def fileStream = new ByteArrayOutputStream()
def gzipStream = new java.util.zip.GZIPOutputStream(fileStream)
gzipStream.write(policyData.bytes)
gzipStream.close()
def gzipped = fileStream.toByteArray()
fileStream.close()
log.info(gzipped.encodeBase64().toString())
More information on Groovy scripting in JMeter: Apache Groovy - Why and How You Should Use It
Thank you for your help... This is how i had initially solve my issue
String bodyString = sampler.getArguments().getArgument(0).getValue();
ByteArrayOutputStream rstBao = new ByteArrayOutputStream();
String JsonRequest = FileUtils.readFileToString(new
File("C:/TEMP/PGF/pgf_svc_input.json"));
GZIPOutputStream zos = new GZIPOutputStream(rstBao);
zos.write(JsonRequest.getBytes());
IOUtils.closeQuietly(zos);
byte[] bytes = rstBao.toByteArray();
//Here is where i am able to encode the bytes to base 64
Base64.encodeBase64String(bytes);
vars.put("postDataEncoded64",Base64.encodeBase64String(bytes));
log.info("khemlall this is the content"+ Base64.encodeBase64String(bytes));
log.info(vars.get("postDataEncoded64"));
rstBao.close()
In the body of my request i added the variable:
{
"id":"22351",
"pmmVersion":"2.0",
"policyData" : "${postDataEncoded64}"
}

Sending xls via API with Java apache poi and React

I'm trying to send a xls file from my java spring server to react client.
Using default Apache POI constructors creates xlsx file, that's not good. In order to override it I have to create the file using FileOutputStream.
FileOutputStream outputStream = new FileOutputStream("file.xls");
But I cannot sent the file over the web. I've tried using the following answer: https://stackoverflow.com/a/54765335/10319765 I quote: "While downloading a file , your code needs to stream a file chunk by chunk - thats what Java streams are for."
return ResponseEntity.ok().contentLength(inputStreamWrapper.getByteCount())
.contentType(MediaType.parseMediaType("application/vnd.ms-excel"))
.cacheControl(CacheControl.noCache())
.header("Content-Disposition", "attachment; filename=" + "file.xls")
.body(new InputStreamResource(inputStreamWrapper.getByteArrayInputStream()));
so my controller is sending InputStreamResource.
How can I construct InputStreamResource using my FileOutputStream?
P.S this is my React client:
axios.get('/issues/export', { responseType: 'arraybuffer' }).then(response => {
if (response && !response.error) {
const blob = new Blob([response.payload.data], {type: 'application/vnd.ms-excel'});
saveAs(blob);
}
});
Source: https://stackoverflow.com/a/46331201/10319765
Edit:
I've managed to do that with a trick, right after I've written to the FileOutputStream I've opened a FileInputStream and returned the value.
FileOutputStream outputStream = new FileOutputStream("file.xls");
workbook.write(outputStream);
workbook.close();
final InputStream fileInputStream = new FileInputStream("file.xls");
return fileInputStream;
but now, the xls file returned as response to the client is corrupted and has weird characters inside:
The excel file should look the following (taken from my java server after sending it):
Issue solved. Eventually what I did in order to solve the corrupted xls file is to work with byte arrays. the controller looks exactly the same but now the return type is ResponseEntity<byte[]>. To convert the InputStream to byte array I've used IOUtils.toByteArray() method.
Client side code has also changed a bit because now the type is no longer responseType: 'arraybuffer' but 'blob'.
axios.get('/issues/export', { responseType: 'blob' }).then(response => {
if (response && !response.error) {
const blob = new Blob([response.payload.data]);
saveAs(blob);
}
});
That's all.

Trouble to save PDF file from a java web service using C#

I'm retrieving a PDF file from a web server java, returning a byte array.
Need save the PDF on the local machine using C #, but the file is saved completely in blank, I think it is because of the byte array format is different.
Here is my code:
StreamReader responseReader = new StreamReader(webStream);
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(URL);
request.Method = "GET";
request.ContentType = "application/pdf";
WebResponse webResponse = request.GetResponse();
Stream webStream = webResponse.GetResponseStream();
StreamReader responseReader = new StreamReader(webStream);
string response = responseReader.ReadToEnd();
responseReader.Close();
byte[] docByte = Encoding.ASCII.GetBytes(response);
File.WriteAllBytes(#"C:\file.pdf", docByte);
Any suggestions on how to save the PDF file normally?
Thank you for listening
// ...
Stream webStream = webResponse.GetResponseStream();
using (var stream = File.Create(#"C:\file.pdf"))
{
webStream.CopyTo(stream);
}
Why don't you do it simply with WebClient like this?
using System.Net;
using (WebClient webClient = new WebClient())
{
webClient.DownloadFile(URL, #"C:\file.pdf");
}

Generate pdf file in Secured mode

I have written a code for pdf generation and it is working fine but now I to generate a pdf file in secured mode.
Here is my code for Secured mode
try {
HttpServletResponse response = ServletActionContext.getResponse();
PDFGenerator pdf = new PDFGenerator();
PDFGenerator generator=new PDFGenerator();
/* byte[] bytes = null;
bytes = (generator.generatepdf(sosValues.getCmaId(), null)).toByteArray();
//bytes = buffer.toByteArray();
response.setContentLength(bytes.length);
if (bytes != null) {
bis = new ByteArrayInputStream(bytes);
}*/
ByteArrayOutputStream baos=generator.generatepdf(sosValues.getCmaId(), null);
bis = new ByteArrayInputStream(baos.toByteArray());
PdfReader pdfReader=new PdfReader(bis);
PdfStamper pdfStamper=new PdfStamper(pdfReader, baos);
pdfStamper.setEncryption(null,null, PdfWriter.HideToolbar, PdfWriter.STRENGTH40BITS);
pdfStamper.setEncryption("Hello".getBytes(), "World".getBytes(), PdfWriter.AllowPrinting
| PdfWriter.AllowCopy, PdfWriter.STRENGTH40BITS);
pdfStamper.close();
baos.close();
} catch (Exception e) {
e.printStackTrace();
}
While debugging I was getting an exception at this line pdfStamper.setEncryption(null,null, PdfWriter.HideToolbar, PdfWriter.STRENGTH40BITS);
Exception in browser was:
The server encountered an internal error that prevented it from fulfilling this request.
PdfWriter.HideToolbar is a viewer preference, not a permission.
This is the list of permissions:
PdfWriter.ALLOW_PRINTING
PdfWriter.ALLOW_MODIFY_CONTENTS
PdfWriter.ALLOW_COPY
PdfWriter.ALLOW_MODIFY_ANNOTATIONS
PdfWriter.ALLOW_FILL_IN
PdfWriter.ALLOW_SCREEN_READERS
PdfWriter.ALLOW_ASSEMBLY
PdfWriter.ALLOW_DEGRADED_PRINTING
Moreover: hiding the toolbar in the hope to secure a PDF is wrong. Please read my answer to How to disable download option of pdf file in c# ?
Even using encryption to avoid printing may not be the best of ideas. See How to protect a PDF with a username and password?
However, this isn't what causes your problem. The internal error is caused by the strange way you're using the ByteArrayOutputStream. You generate a PDF in memory in the generatepdf() method. You didn't share that method, but:
if you're closing that stream, you get the exception because you're trying to add new bytes to it with your stamper object. You can't add extra bytes to a closed OutputStream.
if you're not closing that stream, your PDF isn't completer and you'll get an exception when PdfReader tries to read the (unfinished) PDF.
Furthermore, it's very strange that you would first create the PDF, and then read that PDF to encrypt it. Why not encrypt it right away? That saves you CPU-time.

How can I See the content of a MultipartForm request?

I am using Apache HTTPClient 4. I am doing very normal multipart stuff like this:
val entity = new MultipartEntity(HttpMultipartMode.BROWSER_COMPATIBLE);
entity.addPart("filename", new FileBody(new File(fileName), "application/zip").asInstanceOf[ContentBody])
entity.addPart("shared", new StringBody(sharedValue, "text/plain", Charset.forName("UTF-8")));
val post = new HttpPost(uploadUrl);
post.setEntity(entity);
I want to see the contents of the entity (or post, whatever) before I send it. However, that specific method is not implemented:
entity.getContent() // not defined for MultipartEntity
How can I see what I am posting?
Use the org.apache.http.entity.mime.MultipartEntity writeTo(java.io.OutputStream) method to write the content to an java.io.OutputStream, and then convert that stream to a String or byte[]:
// import java.io.ByteArrayOutputStream;
// import org.apache.http.entity.mime.MultipartEntity;
// ...
// MultipartEntity entity = ...;
// ...
ByteArrayOutputStream out = new ByteArrayOutputStream(entity.getContentLength());
// write content to stream
entity.writeTo(out);
// either convert stream to string
String string = out.toString();
// or convert stream to bytes
byte[] bytes = out.toByteArray();
Note: this only works for multipart entities small enough to be read into memory, and smaller than 2Gb which is the maximum size of a byte array in Java.
Following would help for sure:
ByteArrayOutputStream content = new ByteArrayOutputStream();
httpEntity.writeTo(content);
logger.info("Calling "+url+" with data: "+content.toString());
The above has a fix in comparison to the first answer, there is no need to pass any parameter to ByteArrayOutputStream constructor.
Do you not know the content? Although, you are building the StringBody by supplying sharedValue. So, how could it be different than sharedValue.
I have printed the Multipart request by following code, You can try like
ByteArrayOutputStream bytes = new ByteArrayOutputStream();
entity.writeTo(bytes);
String content = bytes.toString();
Log.e("MultiPartEntityRequest:",content);

Categories