I want to send binary data from my stompClient to the spring controller.
this is my JS
var socket = new SockJS('/test/binary');
var stompClient = Stomp.over(socket);
socket.binaryType = "arraybuffer";
var appModel = new ApplicationModel(stompClient);
ko.applyBindings(appModel);
appModel.connect();
appModel.pushNotification("Notifications.");
var ctx = canvas.get()[0].getContext('2d');
ctx.drawImage(img, 0, 0, 320, 240);
var data = canvas.get()[0].toDataURL('image/jpeg', 1.0);
newblob = dataURItoBlob(data);
stompClient.send("/app/vid", {}, newblob);
function dataURItoBlob(dataURI) {
// convert base64/URLEncoded data component to raw binary data held in a string
var byteString;
if (dataURI.split(',')[0].indexOf('base64') >= 0)
byteString = atob(dataURI.split(',')[1]);
else
byteString = unescape(dataURI.split(',')[1]);
// separate out the mime component
var mimeString = dataURI.split(',')[0].split(':')[1].split(';')[0];
// write the bytes of the string to a typed array
var ia = new Uint8Array(byteString.length);
for (var i = 0; i < byteString.length; i++) {
ia[i] = byteString.charCodeAt(i);
}
return new Blob([ia], {type:mimeString});
I have tried sending Blob, Uint8Array the message is sent but on the server side I can not use it.
My method in the controller is:
#MessageMapping("/vid")
public void getVid(Message<byte[]> message, Principal principal) throws IOException {
ByteArrayOutputStream bOut = new ByteArrayOutputStream();
bOut.write(message.getPayload());
bOut.flush();
byte[] imageInByte = bOut.toByteArray();
bOut.close();
InputStream in = new ByteArrayInputStream(imageInByte);
BufferedImage bImageFromConvert = ImageIO.read(in);
ImageIO.write(bImageFromConvert, "jpeg", new File(
"E:/new-darksouls.jpg"));
template.convertAndSend("/topic/binarydemo2", message);
I have used ByteArrayMessageConverter,StringMessageConverter,MappingJackson2MessageConverter and a Base64JavaObjectMessageConverter that I wrote:
public class Base64JavaObjectMessageConverter extends AbstractMessageConverter {
public Base64JavaObjectMessageConverter() {
super(MimeTypeUtils.APPLICATION_OCTET_STREAM);
}
#Override
protected boolean supports(Class<?> clazz) {
return true;
}
#Override
public Object convertFromInternal(Message<?> message, Class<?> targetClass) {
byte[] messageBytes =Base64Utils.decode( (byte[])message.getPayload() );
return SerializationUtils.deserialize( messageBytes );
}
#Override
public Object convertToInternal(Object payload, MessageHeaders headers) {
byte[] messageBytes = SerializationUtils.serialize( payload );
return Base64Utils.encode( messageBytes);
}
}
I only am able to send the byte[] as string removing the 'base64' etc from it:
stompClient.send("/app/vid", {}, data.split(',')[1]);
in the controller :
#MessageMapping("/vid")
public void getVid(String message, Principal principal) throws IOException {
byte[] bytearray = Base64.decode(message);
BufferedImage imag=ImageIO.read(new ByteArrayInputStream(bytearray));
ImageIO.write(imag, "jpg", new File("E:/new-darksouls.jpg"));
But this is not what I wish to achieve. I suppose that this will take a tall on performance.
I am using Spring 4.2.0.RC1 WebSockets,StompJS
I read on different posts that it is possible to send from back end to client and client to back end but I was not able to reproduce it. I would be very thankful if I can get a concrete example how to structure and send the Uint8Array or blob on the client and how to deal with it on the server side.
Thank you for your time and help
SockJS does not support sending binary data. You can send binary messages with use STOMP over a plain WebSocket.
On the server side see StompSubProtocolHandler which checks if incoming messages are binary or text and hence can handle either. From there it doesn't matter much, i.e. from a STOMP perspective the body is a byte array and the content-type/content-length headers determine what the body contains and how it should be intepreted. On the sending side StompSubProtocolHandler can also send either binary or text and at the moment it uses binary if the content-type is application/octet-stream and as long as SockJS is not being used.
So in short over WebSocket it should work but not when using SockJS as the transport.
Related
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.
In my new project, I am going to include google recaptcha.
my question is fairly simple even if we do client side validation that user is not a robot even though it is suggested to do server side validation.
I want to know why it is necessary to do server side validation for google recaptcha? how does it add the extra layer of security? and how to do in spring boot with spring security?
Server side validation is MUST !! reCAPTCHA is designed in a way that client side just generates the 'g-captcha-response' which along with secret key (stored at server-side) is sent to https://www.google.com/recaptcha/api/siteverify for validation. The response is a JSON which states sucesss true or false and it is further pushed to client side. Validating only at the client side is technically possible, but it defeats the purpose. Moreover, you may get CORS (Cross-Origin Resource Sharing) policy error in console if you do only client side validation. I can share steps to do simple java based server side validation in servlet. Let me know if you need that.
Here is the code. Few points to be noted:
The parameter userResponse = request.getParameter("recaptchaResponse") is the way by which i am getting the 'g-recaptcha-response' generated by the user when he clicked reCAPTCHA widget on UI. On your javascript, capture the value of field 'g-recaptcha-response' and pass it appended to request. Then in servlet, we can get it from request.getParameter.
Sample code:
var recaptchaResponse = document.getElementById("g-recaptcha-response").value;
//alert("g-recaptcha-response= "+recaptchaResponse);
if (recaptchaResponse.length > 0)
{
var xmlhttp1;
if (window.XMLHttpRequest)
{
xmlhttp1=new XMLHttpRequest();
}
else
{
xmlhttp1=new ActiveXObject("Microsoft.XMLHTTP");
}
var query1 = "?recaptchaResponse=" + recaptchaResponse;
xmlhttp1.open("POST","captchaVerificationServlet" + query1, false);
xmlhttp1.send(null);
var resp1 = xmlhttp1.responseText;
alert("resp1= "+resp1);
if(resp1=='matched'){
return true;
}
else{
alert("resp1 did not match");
return false;
}
}
else{
alert("error: recaptcha response is blank");
return false;
}
For simplicity i am checking presence of "success:true" in returned JSON response. As you know, returned JSON contains two parameters : success and error-codes. You may use a JSONReader to read and parse JSON and obtain all parameters fully. Sample code will be like
JsonReader rdr = Json.createReader(your_inputstream);
JsonObject jsonObject = rdr.readObject();
Needless to say, remove all alerts and sop statements in production!
public class CaptchaVerificationServlet extends HttpServlet {
private static final String sec = YOUR_SECRET_KEY;
public void processRequest(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {}
protected void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
String userResponse = request.getParameter("recaptchaResponse");
response.setCharacterEncoding("UTF-8");
System.out.println("userResponse= "+userResponse);
//verify user response with Google ReCaptcha API
String ipAddress = request.getRemoteAddr(); //get client's ip address
System.out.println("ipAddress= "+ipAddress);
try{
String s = validateCaptcha(sec, userResponse, ipAddress);
Boolean success = (s.contains("\"success\": true"));
if(success)
response.getWriter().write("matched");
}
catch(Exception ioe){
ioe.printStackTrace();
ioe.printStackTrace(response.getWriter());
}
}
private String validateCaptcha(String secret, String response, String remoteip) throws IOException
{
URLConnection connection = null;
InputStream is = null;
String output = "";
String proxyHost = "YOUR_PROXY_NAME";
int proxyPort = 80; //proxy server port, generally 80 or 443 (confirm from sys-admin)
SocketAddress addr = new InetSocketAddress(proxyHost, proxyPort);
Proxy httpProxy = new Proxy(Proxy.Type.HTTP, addr);
String filename = System.getProperty("java.home") + "/lib/security/cacerts".replace('/', File.separatorChar);
String password = "changeit";
System.setProperty("javax.net.ssl.trustStore",filename);
System.setProperty("javax.net.ssl.trustAnchors",filename);
System.setProperty("javax.net.ssl.trustStorePassword",password);
String charset = Charset.forName("UTF-8").name();
String url = "https://www.google.com/recaptcha/api/siteverify";
try {
String query = String.format("secret=%s&response=%s&remoteip=%s",
URLEncoder.encode(secret, charset),
URLEncoder.encode(response, charset),
URLEncoder.encode(remoteip, charset));
URL fullURL = new URL(url + "?" + query);
connection = fullURL.openConnection(httpProxy);
connection.addRequestProperty("User-Agent", "Mozilla/5.0 (Windows NT 6.1; WOW64; rv:52.0) Gecko/20100101 Firefox/52.0");
is = connection.getInputStream();
System.out.println("connection InputStream");
BufferedReader reader = null;
String responseXXX = "";
reader = new BufferedReader(new InputStreamReader(is));
responseXXX = reader.readLine();
while (responseXXX!=null) {
output+= responseXXX;
responseXXX = reader.readLine();
}
System.out.println("Output: " + output);
}
finally {
if (is != null) {
try {
is.close();
} catch (IOException e) {
//cannot do anything here
}
}
}
return output;
}
}
I have a WP7 app where I'm trying to reconstruct an HTTPWebRequest that I have successfully written elsewhere using the synchronous methods (pasted at end) but which doesn't work in WP7, I assume because I'm doing something wrong with the Asynchronous versions of these methods.
I believe the issue stems from the fact that the non-working code on the Compact Framework can only send a bytearray[] - I don't have the option of sending the json string. If I send a bytearray in the code that works, I get an error there too. Is there a different option?
Here is my code - this does not work. The exception is thrown on the 2nd line of the last method - "Using(var respons ...)":
public void CreateUser()
{
var request = (HttpWebRequest)WebRequest.Create("http://staging.cloudapp.net:8080/api/users/");
request.Method = "POST";
request.ContentType = "text/json; charset=utf-8";
request.BeginGetRequestStream(new AsyncCallback(RequestCallback), request);
}
private static void RequestCallback(IAsyncResult result)
{
HttpWebRequest request = (HttpWebRequest)result.AsyncState;
using (Stream postStream = request.EndGetRequestStream(result))
{
User user = new User("Windows", "Phone", "USCA");
Formatting formatting = new Formatting();
JsonSerializerSettings settings = new JsonSerializerSettings();
settings.ReferenceLoopHandling = ReferenceLoopHandling.Ignore;
string json = JsonConvert.SerializeObject(user, formatting, settings);
byte[] byteArray = Encoding.UTF8.GetBytes(json);
postStream.Write(byteArray, 0, json.Length);
}
request.BeginGetResponse(new AsyncCallback(ResponseCallback), request);
}
private static void ResponseCallback(IAsyncResult result)
{
var request = (HttpWebRequest)result.AsyncState;
using (var response = (HttpWebResponse)request.EndGetResponse(result))
{
using (Stream streamResponse = response.GetResponseStream())
{
StreamReader reader = new StreamReader(streamResponse);
string responseString = reader.ReadToEnd();
reader.Close();
}
}
}
This code works (non-compact framework version of the same request):
HttpWebRequest request = HttpWebRequest.Create("http://staging.cloudapp.net/api/users/") as HttpWebRequest;
request.Method = "POST";
request.ContentType = "text/json";
using (var writer = new StreamWriter(request.GetRequestStream()))
{
User user = new user("Other", "Guy", "USWC");
Formatting formatting = new Formatting();
JsonSerializerSettings settings = new JsonSerializerSettings();
settings.ReferenceLoopHandling = ReferenceLoopHandling.Ignore;
string json = JsonConvert.SerializeObject(user, formatting, settings);
writer.Write(json);
}
var response = request.GetResponse() as HttpWebResponse;
using (var reader = new StreamReader(response.GetResponseStream()))
{
var responseText = reader.ReadToEnd();
return responseText;
}
thanks for any help!
looks like the server is responding with a "404 not found". Does the resource you are requesting exist at the server?
Does your JSON contain any non 7-bit ASCII characters, as you are currently doing:
byte[] byteArray = Encoding.UTF8.GetBytes(json);
postStream.Write(byteArray, 0, json.Length);
The number of bytes might not be identical to the number of characters in your string, which could lead to a malformed request.
It would be worthwhile using something like Fiddler to verify what is actually going over the wire from the emulator or phone (there are instructions on the Fiddler website for how to do this)
Well - I'm not sure why this problem went away. I liked #RowlandShaw's suggestion, but I didn't actually change anything in the json. Wish I could give a better solution.
I am working on GWT RPC. I am facing a problem in retrieving image from my SQL.
Here is my code:
Base64 bas = new Base64();
// sun.misc.BASE64Encoder enc = new sun.misc.BASE64Encoder();
UploadfileJpaController up = new UploadfileJpaController();
// this function returns the value in blob field in the form of byte array
byte[] b = up.findUploadfile(n);
String base64Contents = enc.encode(b).replaceAll("\\s+", "");
//String base64 = Base64Utils.toBase64(b);
base64Contents = "data:image/gif;base64,"+base64Contents;
return base64Contents;
But this is not working.. the image is not displayed. Please help :(
You should let a regular servlet take care of returning the image data, and not use GWT-RPC. The servlet should set the proper image/gif header and write the binary data to the response outputstream.
EDIT
This should look somewhat like this
public class FileDownloadServlet extends HttpServletv {
// This method is called by the servlet container to process a GET request.
public void doGet(HttpServletRequest req, HttpServletResponse resp) throws IOException {
// Set content type
resp.setContentType("image/gif");
//Up to you!
byte[] binaryData = getDataFromDbase();
ByteArrayInputStream bis = new ByteArrayInputStream(binaryData);
OutputStream out = resp.getOutputStream();
// Copy the contents of the file to the output stream
byte[] buf = new byte[1024];
int count = 0;
while ((count = bis.read(buf)) >= 0) {
out.write(buf, 0, count);
}
bis.close();
out.close();
}
}
You url is going to be something like
http://server/application/image_servlet?id=123545 where you use the id parameter in the servlet to look up the image. And of course add the servlet to you web.xml. Good luck.
I found an example about HTTP POST in msdn, but I am wondering how can I make use of reactive extensions here.
using System;
using System.Net;
using System.IO;
using System.Text; using System.Threading;
class HttpWebRequestBeginGetRequest
{
private static ManualResetEvent allDone = new ManualResetEvent(false);
public static void Main(string[] args)
{
// Create a new HttpWebRequest object.
HttpWebRequest request = (HttpWebRequest)WebRequest.Create("http://www.contoso.com/example.aspx");
request.ContentType = "application/x-www-form-urlencoded";
// Set the Method property to 'POST' to post data to the URI.
request.Method = "POST";
// start the asynchronous operation
request.BeginGetRequestStream(new AsyncCallback(GetRequestStreamCallback), request);
// Keep the main thread from continuing while the asynchronous
// operation completes. A real world application
// could do something useful such as updating its user interface.
allDone.WaitOne();
}
private static void GetRequestStreamCallback(IAsyncResult asynchronousResult)
{
HttpWebRequest request = (HttpWebRequest)asynchronousResult.AsyncState;
// End the operation
Stream postStream = request.EndGetRequestStream(asynchronousResult);
Console.WriteLine("Please enter the input data to be posted:");
string postData = Console.ReadLine();
// Convert the string into a byte array.
byte[] byteArray = Encoding.UTF8.GetBytes(postData);
// Write to the request stream.
postStream.Write(byteArray, 0, postData.Length);
postStream.Close();
// Start the asynchronous operation to get the response
request.BeginGetResponse(new AsyncCallback(GetResponseCallback), request);
}
private static void GetResponseCallback(IAsyncResult asynchronousResult)
{
HttpWebRequest request = (HttpWebRequest)asynchronousResult.AsyncState;
// End the operation
HttpWebResponse response = (HttpWebResponse)request.EndGetResponse(asynchronousResult);
Stream streamResponse = response.GetResponseStream();
StreamReader streamRead = new StreamReader(streamResponse);
string responseString = streamRead.ReadToEnd();
Console.WriteLine(responseString);
// Close the stream object
streamResponse.Close();
streamRead.Close();
// Release the HttpWebResponse
response.Close();
allDone.Set();
}
}
I am trying to use the following code, but it does not work. Can anyone help me out on this?
Thanks in advance -Peng
return (from request in
Observable.Return((HttpWebRequest)WebRequest.Create(new Uri(postUrl))).Catch(Observable.Empty<HttpWebRequest>())
.Do(req =>
{
// Set up the request properties
req.Method = "POST";
req.ContentType = contentType;
req.UserAgent = userAgent;
req.CookieContainer = new CookieContainer();
Observable.FromAsyncPattern<Stream>(req.BeginGetRequestStream, req.EndGetRequestStream)()
.ObserveOnDispatcher()
.Subscribe(stream =>
{
stream.Write(formData, 0,
formData.Length);
stream.Close();
})
;
})
from response in
Observable.FromAsyncPattern<WebResponse>(request.BeginGetResponse, request.EndGetResponse)().Catch(Observable.Empty<WebResponse>())
from item in GetPostResponse(response.GetResponseStream()).ToObservable().Catch(Observable.Empty<string>())
select item).ObserveOnDispatcher();
Edit: To make it clear, I want to use the rx to implement the same logic in MSDN example.
in the MSDN example, it seems it first makes async call to write RequestStream, and then in the GetRequestStreamCallback, fires another async call to get the response.
Using Rx, I am able to create 2 observables
1. Observable.FromAsyncPattern(request.BeginGetRequestStream, request.EndGetRequestStream)()
2. Observable.FromAsyncPattern(request.BeginGetResponse, request.EndGetResponse)()
The problem is the second observable depends on the first one's result, so how can I do this in Rx?
In the first observable's subcribe method to create the seond observable? is it the good way?
This is how I am doing it. I configure the two Async patters up front, then use SelectMany to chain them together.
I have cut out the error handling etc from this code to keep it simple and show only the bare minimum to get it working. You should append a .Catch() similar to your own code, and if you want to get more than just a string out (say the response code) then you'll need to create a class/struct to hold all the bits of data you need and return that instead.
public IObservable<string> BeginPost(Uri uri, string postData) {
var request = HttpWebRequest.CreateHttp(uri);
request.Method = "POST";
request.ContentType = "application/x-www-form-urlencoded";
var fetchRequestStream = Observable.FromAsyncPattern<Stream>(request.BeginGetRequestStream, request.EndGetRequestStream);
var fetchResponse = Observable.FromAsyncPattern<WebResponse>(request.BeginGetResponse, request.EndGetResponse);
return fetchRequestStream().SelectMany(stream => {
using (var writer = new StreamWriter(stream)) writer.Write(postData);
return fetchResponse();
}).Select(result => {
var response = (HttpWebResponse)result;
string s = "";
if (response.StatusCode == HttpStatusCode.OK) {
using (var reader = new StreamReader(response.GetResponseStream())) s = reader.ReadToEnd();
}
return s;
});
}
Your problem is your use of Do() here, you need to move the GetRequestStream into your SelectMany (into your "from bla in, from bla in"...), since it only makes sense to get the response stream after you've written the full request. Right now, you're trying to do both concurrently.