Route HTTP images for a HTTPS site - java

I'm running a site where users can link images and thumbnails from other sites in their content. When viewing these images in the https secured user are, they are getting security warnings, because http content is contained in the https page..
To work around this, I'd like to route the images through my server to the client, there by "giving" them the required https protokoll.
e.g. when viewing content on the secure site an image tag would like this:
<img src="https://mysite/img.aspx?src=http://url.to/someimage.jpg" >
As my site using Umbraco (.NET 3.5, IIS7), I've already looked into using the urlrewritingnet library, but it only seems to be able to rewrite and redirect urls.
Has anybody done this?

The following works quite well:
I've got it to work by just passsing through the image bytes on the server. I'm not entierly convinced that it is a good solution so, I'll wait for better solutions:
public partial class Img : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
string url = Page.Request.QueryString["url"];
HttpWebRequest request = (HttpWebRequest)HttpWebRequest.Create(url);
request.Timeout = 5000;
request.ReadWriteTimeout = 20000;
HttpWebResponse imgresponse = (HttpWebResponse)request.GetResponse();
//StreamReader sr = new StreamReader(imgresponse.GetResponseStream());
Response.ContentType = "image/gif";
byte[] fileBytes = GetFileBytes(imgresponse.GetResponseStream());
Response.BinaryWrite(fileBytes);
Response.Flush();
}
protected byte[] GetFileBytes(Stream stream)
{
byte[] fileBytes = null;
byte[] buffer = new byte[4096];
try
{
MemoryStream memoryStream = new MemoryStream();
int chunkSize = 0;
do
{
chunkSize = stream.Read(buffer, 0, buffer.Length);
memoryStream.Write(buffer, 0, chunkSize);
} while (chunkSize != 0);
fileBytes = memoryStream.ToArray();
}
catch (Exception ex)
{
Response.Write(ex.Message);
}
return fileBytes;
}
}

Related

How to upload AppendBlob/a file larger than the 4mb limit into Azure Storage/Blob in Java?

How to upload a large(>4mb) file as an AppendBlob using Azure Storage Blob client library for Java?
I've successfully implemented the BlockBlob uploading with large files and it seems that the library internally handles the 4mb(?) limitation for single request and chunks the file into multiple requests.
Yet it seems that the library is not capable of doing the same for AppendBlob, so how can this chunking be done manually? Basically I think this requires to chunk an InputStream into smaller batches...
Using Azure Java SDK 12.14.1
Inspired by below answer in SO (related on doing this in C#):
c-sharp-azure-appendblob-appendblock-adding-a-file-larger-than-the-4mb-limit
... I ended up doing it like this in Java:
AppendBlobRequestConditions appendBlobRequestConditions = new AppendBlobRequestConditions()
.setLeaseId("myLeaseId");
try (InputStream input = new BufferedInputStream(
new FileInputStream(file));) {
byte[] buf = new byte[AppendBlobClient.MAX_APPEND_BLOCK_BYTES];
int bytesRead;
while ((bytesRead = input.read(buf)) > 0) {
if (bytesRead != buf.length) {
byte[] smallerData = new byte[bytesRead];
smallerData = Arrays.copyOf(buf, bytesRead);
buf = smallerData;
}
try (InputStream byteStream = new ByteArrayInputStream(buf);) {
appendBlobClient
.appendBlockWithResponse(byteStream, bytesRead,
null, appendBlobRequestConditions, null,
null);
}
}
}
Of course you need to do bunch of stuff before this, like make sure the AppendBlob exists, and if not then create it before trying to append any data.

WebResourceResponse can't read full inputstream from HttpConnection (Android)

I'm working with an ionic application(like hybrid) which can play some videos.I want to add some headers to the request so that I override the "shouldInterceptRequest".
URL myUrl = new URL(real);
HttpURLConnection connection = (HttpURLConnection) myUrl.openConnection();
for (Map.Entry < String, String > entry: headers.entrySet()) {
connection.setRequestProperty(entry.getKey(), entry.getValue());
}
InputStream in = connection.getInputStream();
WebResourceResponse response = new WebResourceResponse("video/mp4", "UTF-8", in );
for (Map.Entry < String, List < String >> entry: connection.getHeaderFields().entrySet()) {
resHeaders.put(entry.getKey(), entry.getValue().get(0));
}
This code can't work.The video tag in html can't play the video.
So I add some code.
byte[] bytes = new byte[30 * 1024 * 1024];
ByteArrayOutputStream byteBuffer = new ByteArrayOutputStream();
int len = 0;
while ((len = in.read(bytes)) != -1) {
byteBuffer.write(bytes, 0, len);
}
bytes = byteBuffer.toByteArray();
WebResourceResponse response = new WebResourceResponse("video/mp4", "UTF-8", new ByteArrayInputStream(bytes));
When I read inputstream into bytes and send bytes to WebResourceResponse, the video can be play.However it means my application will use lots of memory if the video is large.
So that, I want to know is there any way to play the video without saving inputstream into bytes.
OK.Fianlly,I found my way.
Actually, my goal is to add custom headers to resource request and now I found there is an easier way to do it.
For example, if I want to load a image,I will use img tag like this,<img src="the_url_of_image">,and I can't add any header to the request unless I interecept the request.
However,we can use blob now.We can request the resource by using something like ajax and use createObjectURL to create a url links to the resource.

Image byte stream is different when file is read in different ways

Under my Spring 4.3/Maven 3.3 project I have an image file, a PNG file, at:
src/main/resources/images/account.png
I have a util java application file that reads in an image, and it writes it to the database field. The code is as follows:
private static String _accountFilename = "src/main/resources/images/account.png";
private byte[] getByteArrayFromFile(String filename)
{
FileInputStream fileInputStream = null;
File file = new File(filename);
byte[] bFile = new byte[(int) file.length()];
try
{
// convert file into array of bytes
fileInputStream = new FileInputStream(file);
fileInputStream.read(bFile);
fileInputStream.close();
for (int i = 0; i < bFile.length; i++)
{
System.out.print((char) bFile[i]);
}
System.out.println("Done");
}
catch (Exception e)
{
e.printStackTrace();
}
return bFile;
}
public String getImageData(byte[] imageByteArray)
{
Base64.Encoder encoder = Base64.getEncoder();
String base64 = encoder.encodeToString(imageByteArray);
base64 = "data:image/png;base64," + base64;
return base64;
}
The String that comes back from "getImageData" works great. I can put that String in the MySQL database, in a table, and the field is defined as TEXT.
I can pull that base64 encoded data back, and display the image.
Now, If I am calling this code from a Spring Service instead of an application, then the image "src/main/resources/images/account.png" is not found.
After researching on the Net for some time, there are many, many examples of getting a file from "resources" and many of these did not work for me. Since I am in Spring, I tried a few things and finally this worked:
#Value(value = "classpath:images/account.png")
private Resource defaultAccountImage;
private byte[] getByteArrayFromFile(Resource image)
{
InputStream inputStream = null;
byte[] bFile = null;
try
{
bFile = new byte[(int) image.contentLength()];
// convert file into array of bytes
inputStream = image.getInputStream();
inputStream.read(bFile);
inputStream.close();
for (int i = 0; i < bFile.length; i++)
{
System.out.print((char) bFile[i]);
}
System.out.println("Done");
}
catch (Exception e)
{
e.printStackTrace();
}
return bFile;
}
private String getImageData(byte[] imageByteArray)
{
Base64.Encoder encoder = Base64.getEncoder();
String base64 = encoder.encodeToString(imageByteArray);
base64 = "data:image/png;base64," + base64;
return base64;
}
public String getDefaultAccountImage()
{
byte[] accountImage = getByteArrayFromFile(defaultAccountImage);
String fileString = getImageData(accountImage);
return fileString;
}
When I look at the String/Image data between the first way with the standalone java app, and the second way with the #Value and inputstream, there is a definite different in the string data.
part of the string data is similar, but then it drastically changes, and they don't match. As a result the text data for the image from the second method doesn't display as an image.
So, I was hoping I could get this image text data, and it would be the same, but it is not. If I can use my web-service, which calls the business service which calls this ImageUtil code where I use the #Value to get the image resource and it saves the text string correctly, that would be great.
If you have any advice, I would very much appreciate it. Thanks!
UPDATE 1:
This is a multi-maven project:
parent-project
entity
dao
service
ws
When I run my test code within the Service layer, the suggested solution works great! The images are found and the byte string gets loaded as it should be. And then I compiled the code into a jar.
The entity.jar gets created first.
The dao.jar gets created and pulls in the entity.jar.
The service.jar gets created and pulls in the dao.jar. This layer also has the /resources/images/account.png file. But this image is now in the jar.
The ws.WAR file pulls in the service.jar file ...
so the code in the answer does not find the image in the resources.
When I run the tests from the ws layer, I get a FileNotFoundException.
So ... now I am researching on how to get an image from jar ...
Does this change how I should be getting my image byte array?
You can get the file from the Resource, and proceed like the first example which works. Seems redundant, but if you can get the file, then you can test a number of things:
Write the file to disk and check the content
Write the file to disk and compare the sizes, etc.
import java.io.File;
import java.io.FileInputStream;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.core.io.Resource;
#Value(value = "classpath:images/account.png")
private Resource defaultAccountImage;
private byte[] getByteArrayFromFile(Resource image) {
FileInputStream fileInputStream = null;
byte[] bFile = null;
try {
File file = image.getFile();
bFile = new byte[(int) file.length()];
// convert file into array of bytes
fileInputStream = new FileInputStream(file);
fileInputStream.read(bFile);
fileInputStream.close();
for (int i = 0; i < bFile.length; i++) {
System.out.print((char) bFile[i]);
}
System.out.println("Done");
} catch (Exception e) {
e.printStackTrace();
}
return bFile;
}

Receive image file through rest Api

How to receive an image file through Rest APIs. There is an option of MULTIPART_FORM_DATA which looks like it will send files in parts as in more than one request.
I want to receive images very fast on server. around 2 images per second.
Simply read image in a File and use Response class to build the response.
Response.ok(new File("myimage.jpg"), "image/jpeg").build();
There are other variations of the same.
Read the image using following.
URL url = new URL("http://localhost:8080/myimage/1");
URLConnection connection = url.openConnection();
input = connection.getInputStream();
byte[] buffer = new byte[1024];
int n = - 1;
OutputStream fos = new FileOutputStream("Output.jpg" );
while ( (n = input.read(buffer)) != -1)
{
fos.write(buffer, 0, n);
}
fos.close();
You can use Apache HTTP client to make it prettier.

Uploading multiple files and metadata with CXF

I need to create a file upload handler as a REST web service with CXF. I've been able to upload a single file with metadata using code like the following:
#POST
#Path("/uploadImages")
#Consumes(MediaType.MULTIPART_FORM_DATA)
public Response uploadImage(#Multipart("firstName") String firstName,
#Multipart("lastName") String lastName,
List<Attachment> attachments) {
for (Attachment att : attachments) {
if (att.getContentType().getType().equals("image")) {
InputStream is = att.getDataHandler().getInputStream();
// read and store image file
}
}
return Response.ok().build();
}
Now I need to add support for uploading multiple files in the same request. In this case, instead of an attachment with image/jpeg content type, I get an attachment with multipart/mixed content type, which itself contains the individual image/jpeg attachments that I need.
I've seen examples for uploading multiple JSON or JAXB objects with metadata, but I have not been able to get anything to work with binary image data. I have tried using the MultipartBody directly, but it only returns the multipart/mixed attachment, not the image/jpeg attachments embedded within it.
Is there a way to recursively parse a multipart/mixed attachment to get the embedded attachments? I can of course get the input stream of the multipart/mixed attachment, and parse out the files myself, but I'm hoping there is a better way.
UPDATE
This seems kludgey, but the following bit of code is good enough for now. I would love to see a better way though.
for (Attachment att : attachments) {
LOG.debug("attachment content type: {}", att.getContentType().toString());
if (att.getContentType().getType().equals("multipart")) {
String ct = att.getContentType().toString();
Message msg = new MessageImpl();
msg.put(Message.CONTENT_TYPE, ct);
msg.setContent(InputStream.class, att.getDataHandler().getInputStream());
AttachmentDeserializer ad = new AttachmentDeserializer(msg, Arrays.asList(ct));
ad.initializeAttachments();
// store the first embedded attachment
storeFile(msg.getContent(InputStream.class));
// store remaining embedded attachments
for (org.apache.cxf.message.Attachment child : msg.getAttachments()) {
storeFile(child.getDataHandler().getInputStream());
}
}
else if (att.getContentType().getType().equals("image")) {
storeFile(att.getDataHandler().getInputStream());
}
}
I've build a similar service to upload multiple images. My implementation looks like the following (maybe it helps)
#Consumes({MediaType.MULTIPART_FORM_DATA,"multipart/mixed" })
public Response uploadImages(final List<Attachment> attachments) {
Map<String, InputStream> imageMap = new HashMap<String, InputStream>();
for (Attachment attachment : attachments) {
String imageName = attachment.getContentDisposition().getParameter("filename");
if (imageName == null) {
imageName = UUID.randomUUID().toString();
}
InputStream image = attachment.getDataHandler().getInputStream();
imageMap.put(imageName, image);
}
return imageMap;
}
if someone prefers bye arrays instead of input streams, it can be converted easily using this helper method
private static byte[] extractByteArray(final InputStream inputStream) throws IOException {
ByteArrayOutputStream buffer = new ByteArrayOutputStream();
byte[] dataChunk = new byte[1024 * 16];
int numRead = 0;
while (numRead != -1) {
numRead = inputStream.read(dataChunk, 0, dataChunk.length);
if (numRead != -1) {
buffer.write(dataChunk, 0, numRead);
}
}
buffer.flush();
return buffer.toByteArray();
}

Categories