Mixing JSON data and image content in a single HTTP response - spring

Is it possible to include multiple response types in a single HTTP response? For example, JSON data as well as an image.

Hey It is not possible to set multiple MIME TYPE to HTTPResponse. But what you can do is, you can set the content type as application/json. And using json you can send the image using BASEEncoder.
public static String encodeToString(BufferedImage image, String type) {
String imageString = null;
ByteArrayOutputStream bos = new ByteArrayOutputStream();
try {
ImageIO.write(image, type, bos);
byte[] imageBytes = bos.toByteArray();
BASE64Encoder encoder = new BASE64Encoder();
imageString = encoder.encode(imageBytes);
bos.close();
} catch (IOException e) {
e.printStackTrace();
}
return imageString;
}

No. I think one generally would send the URL of image in json, and use javascript to update the "src" attribute of "img" element

Related

Apache httpcomponents 5 chunked response

I am accessing an internal site that returns gzipped content. When the content reaches a certain size, the site returns a chunked response. I am using the Apache httpcomponents 5 CloseableHttpAsyncClient and the SimpleHttpRequest and SimpleHttpResponse. The internal site is a vendor product that can't be modified.
String encoding = getEncoding(response.getHeaders());
byte[] bytes;
byte[] bodyBytes = response.getBodyBytes();
if (encoding.equals("gzip")) {
ByteArrayInputStream inputStream = new ByteArrayInputStream(bodyBytes);
GZIPInputStream gzipInputStream = new GZIPInputStream(inputStream);
bytes = IOUtils.toByteArray(gzipInputStream);
} else {
bytes = bodyBytes;
}
String html = new String(bytes, StandardCharsets.UTF_8);
I check for the response type as follows
private String getEncoding(Header[] headers) {
for (Header header : headers) {
if (header.getName().toLowerCase().equals("transfer-encoding")) {
return header.getValue();
}
if (header.getName().toLowerCase().equals("content-encoding")) {
return header.getValue();
}
}
return "";
}
I know that there is a ChunkedInputStream class, but the inputs to the constructor are not obviously available from the response
ChunkedInputStream(SessionInputBuffer buffer, InputStream inputStream)
Wraps session input stream and reads chunk coded input.
ChunkedInputStream(SessionInputBuffer buffer, InputStream inputStream, Http1Config http1Config)
Default constructor.
Do I need to use a different response type? If so, which one? Or is there a different way that is better?
Thanks for your help.

How to set content type using Azure Java azure-storage-blob SDK

My code looks like:
try {
MultipartFile file = uploadFileInfo.getUploadFile();
InputStream inputStream = new BufferedInputStream(file.getInputStream());
BlobProperties props = blockBlobClient.getProperties();
blockBlobClient.upload(inputStream, file.getBytes().length);
} catch (IOException e) {
log.error("Unable to upload blob!", e);
return baseResp;
}
However the file contentType is application/octet-stream, and I need to set it to "image/jpg". How can I do this with the Java SDK?
To upload a blob and set it's content type, please use the following method: BlockBlobClient.uploadWithResponse. Here's the sample code (taken from the same link):
BlobHttpHeaders headers = new BlobHttpHeaders()
.setContentType("image/jpg");
Map<String, String> metadata = Collections.singletonMap("metadata", "value");
byte[] md5 = MessageDigest.getInstance("MD5").digest("data".getBytes(StandardCharsets.UTF_8));
BlobRequestConditions requestConditions = new BlobRequestConditions();
Context context = new Context("key", "value");
client.uploadWithResponse(data, length, headers, metadata, AccessTier.HOT, md5,
requestConditions, timeout, context);
The upload method does not provide this option, you need to use the uploadWithResponse method, which allows you to specify this and many other parameters. Here's an example:
ParallelTransferOptions parallelTransferOptions = new ParallelTransferOptions();
BlobHttpHeaders headers = new BlobHttpHeaders().setContentType(MediaType.IMAGE_JPEG_VALUE);
Map<String, String> metadata = Collections.singletonMap("metadata", "value");
BlobRequestConditions requestConditions = new BlobRequestConditions();
Context context = new Context("key", "value");
Duration timeout = Duration.ofSeconds(60);
blobClient.uploadWithResponse(inputStream, size, parallelTransferOptions, headers, metadata, AccessTier.HOT, requestConditions, timeout, context);

AWS Java Lambda compressed JSON responses fails: "Execution failed due to configuration error: Malformed Lambda proxy response"

I am invoking a AWS Lambda function from the AWS API Gateway. The returned JSON needs to be zipped since it sometimes became too big (body size too large etc). However, I have some issues getting the response through the API Gateway. This is my Java code:
#Override
public JSONObject handleRequest(Object input, Context context) {
String json_string = "";
try {
Gson gson = new Gson();
json_string = gson.toJson(input, LinkedHashMap.class);
} catch (ClassCastException ex) {
json_string = (String) input;
}
GenerateJson generateJson = new GenerateJson ();
String body = "";
try {
JSONParser parser = new JSONParser();
Object jsonObj = parser.parse(json_string);
JSONObject matchesobj = (JSONObject) jsonObj;
if (matchesobj.containsKey("body")) {
body = (String) matchesobj.get("body");
} else {
JSONObject error = new JSONObject();
error.put("error", "No body with Base64 data in Request.");
System.out.println(error.toJSONString());
return error;
}
} catch (ParseException ex) {
ex.printStackTrace();
}
byte[] decodedBytes = Base64.getDecoder().decode(body);
String decodedString = new String(decodedBytes);
// System.out.println(decodedString);
JSONObject json = generateJson .getJson(decodedString, "", 2);
JSONObject returnObject = new JSONObject();
JSONObject headers = new JSONObject();
returnObject.put("statusCode", 205);
returnObject.put("isBase64Encoded", true);
// returnObject.put("Content-Encoding", "gzip");
returnObject.put("headers", headers);
returnObject.put("body", compressStringAndReturnBase64(json.toString()));
return (returnObject);
}
public static String compressStringAndReturnBase64(String srcTxt) {
ByteArrayOutputStream rstBao = new ByteArrayOutputStream();
GZIPOutputStream zos;
try {
zos = new GZIPOutputStream(rstBao);
zos.write(srcTxt.getBytes());
IOUtils.closeQuietly(zos);
byte[] bytes = rstBao.toByteArray();
String base64comp = Base64.getEncoder().encodeToString(bytes);
System.out.println("Json String is " + srcTxt.toString().getBytes().length + " compressed " + bytes.length + " compressed Base64 " + base64comp.getBytes().length);
return base64comp;
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return "";
}
I've checked the Base64 output and that seems to work fine (pasted it in https://www.base64decode.org/). In addition, when I check with Postman, I get a binary blob which can be unpacked with 7-zip if I save the response to something that ends with .gz.
Under settings, the API Gateway Binary Media Types has been set to /
But I'd like to have the client "see" that it is GZIPped and decode it on the fly. However, when I add the line
returnObject.put("Content-Encoding", "gzip");
I get {"message": "Internal server error"} and in the AWS API logs: Execution failed due to configuration error: Malformed Lambda proxy response
The Lambda logs are fine, so it did execute successfully, just wasn't able to be returned.
I am thinking I need some more tweaking on the API Gateway side, any ideas?
This sounds like the binary support setting on API Gateway isn't configured correctly; API gateway is trying to parse the response from your lambda rather than passing it on directly to the client.
You can update this setting in the console:
In your HTTP request add "Accept" header with payload content type.
Accept: application/gzip
Also in the HTTP response, there should be "Content-Type" header indicating response content type.
Content-Type: application/gzip
Your lambda returns Base64 encoded binary data to API Gateway. So in order to decode data your HTTP request's Accept header and Response's Content-type headers should there.

Grab image data from URL via proxy and convert to base64

I've got a question related to grabbing an image from a URL via proxy and converting it to base64.
Is there a simple way of doing this like the below jsoup method?
Proxy proxy = new Proxy(Proxy.Type.HTTP, new InetSocketAddress("myproxyurl", 8080))
Document doc = Jsoup.connect("mytargeturl").proxy(proxy).get()
Elements headline = doc?.getElementsByClass("myHTMLclass")
I am looking to do this in Groovy/Java (preferably Groovy).
So far I got here:
Proxy proxy = new Proxy(Proxy.Type.HTTP, new InetSocketAddress("myproxy", 8080))
URL url = new URL("https://maps.googleapis.com/maps/api/staticmap?size=600x400&markers=size:large%7Ccolor:yellow%7Clabel:A%7CNew%20York")
def image = url.openConnection(proxy).getContent()
println(image)
But I'm getting sun.awt.image.URLImageSource#26d9b808 as an output in the console
Can anyone help? The image in question is this one:
Just to be clear, I want to grab the above image (actual image) from the above-mentioned URL and convert it to base64 string.
Just do:
// By default this won't use a proxy, but if you pass one in, it will!
String toBase64(URL url, Proxy proxy = Proxy.NO_PROXY) {
url.openConnection(proxy).inputStream.withCloseable {
it.bytes.encodeBase64()
}
}
URL url = new URL("https://maps.googleapis.com/maps/api/staticmap?size=600x400&markers=size:large%7Ccolor:yellow%7Clabel:A%7CNew%20York")
Proxy proxy = new Proxy(Proxy.Type.HTTP, new InetSocketAddress("myproxyurl", 8080));
String encoded = toBase64(url, proxy)
Not sure about proxy settings, but if you want to convert image into base64 with java, so that you can do with below code.
public class ChangeBase {
public static void main(String[] args) throws IOException {
// TODO Auto-generated method stub
String encodstring = encodeFileToBase64("http://imageurl");
System.out.println(encodstring);
}
private static byte[] getByteFromImage(String urlStr) throws Exception {
URL url = new URL(urlStr);
BufferedImage image = ImageIO.read(url);
// get DataBufferBytes from Raster
WritableRaster raster = image.getRaster();
DataBufferByte data = (DataBufferByte) raster.getDataBuffer();
return data.getData();
}
private static String encodeFileToBase64(String url) {
String encodedString = null;
try {
byte[] bytes = getByteFromImage(url);
encodedString = new String(Base64.getEncoder().encode(bytes), "UTF-8");
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return encodedString;
}
}
Note: I used above code for image stored in my drive, same thing you can try with image from url, suggested one is create byte to file from url and pass same to encodeFiletoBase64 method, don't save file locally on system.

Display the PDF file stored on the webserver on Browser new window using Spring MVC

I have a requirement to show PDF files in a browser. I use Spring MVC. Is there a way I can do this without using AbstractPdfView? I do not want to render the PDF at runtime. All the PDF files will be stored in my webserver.
This is the code I am using. But this directly downloads the file instead of showing it up in a browser.
#RequestMapping(value = "/download" , method = RequestMethod.GET)
public void doDownload(HttpServletRequest request,
HttpServletResponse response) throws IOException {
// get absolute path of the application
ServletContext context = request.getSession().getServletContext();
String appPath = context.getRealPath("");
String filename= request.getParameter("filename");
filePath = getDownloadFilePath(lessonName);
// construct the complete absolute path of the file
String fullPath = appPath + filePath;
File downloadFile = new File(fullPath);
FileInputStream inputStream = new FileInputStream(downloadFile);
// get MIME type of the file
String mimeType = context.getMimeType(fullPath);
if (mimeType == null) {
// set to binary type if MIME mapping not found
mimeType = "application/pdf";
}
System.out.println("MIME type: " + mimeType);
String headerKey = "Content-Disposition";
response.addHeader("Content-Disposition", "attachment;filename=report.pdf");
response.setContentType("application/pdf");
// get output stream of the response
OutputStream outStream = response.getOutputStream();
byte[] buffer = new byte[BUFFER_SIZE];
int bytesRead = -1;
// write bytes read from the input stream into the output stream
while ((bytesRead = inputStream.read(buffer)) != -1) {
outStream.write(buffer, 0, bytesRead);
}
inputStream.close();
outStream.close();
}
Remove the line
response.addHeader("Content-Disposition", "attachment;filename=report.pdf");
This line precisely tells the browser to display a download/save dialog rather than displaying the PDF directly.
Oh, and make sure to close the input sytream in a finally block.

Resources