Why JAX-RS Response.fromResponse(anotherResponse) not copying the entity? - jax-rs

This is part of a JAX-RS server which receives a response from another server and sends the same response back to its client.
This copies the entity from anotherResponse to responseForClient:
Response responseForClient = Response.fromResponse(anotherResponse).entity(anotherResponse.readEntity(InputStream.class)).build();
This doesn't copy the entity:
Response responseForClient = Response.fromResponse(anotherResponse).build();
The second one should also work as JAX-RS Response.fromResponse() should copy the entity also.
Why setting the entity is required?
I am using RestEasy-3.0.

You have to consume the InputStream before calling fromResponse because it only will copy the response. The JAX-RS won't do it automatically, and if you provide the new instance to the client then the entity will not be consumed
See the documentation of fromResponse
public static Response.ResponseBuilder fromResponse(Response response)
Create a new ResponseBuilder by performing a shallow copy of an existing Response.
The returned builder has its own response headers but the header values are shared with the original Response instance. The original response entity instance reference is set in the new response builder.
Note that if the entity is backed by an un-consumed input stream, the reference to the stream is copied. In such case make sure to buffer the entity stream of the original response instance before passing it to this method.
Buffer the response reading the InputStream to a byte array
InputStream is = anotherResponse.readEntity(InputStream.class);
byte[] bytes = IOUtils.toByteArray(is);
ByteArrayInputStream in= new ByteArrayInputStream (bytes);
This code is equivalent to yours
Response responseForClient =
Response.fromResponse(anotherResponse).entity(in).build()

Related

WCF Change message encoding from Utf-16 to Utf-8

I have a WCF connected service in a .net core application. I'm using the code that is autogenerated taken the wsdl definition.
Currently at the top of the request xml is including this line:
<?xml version="1.0" encoding="utf-16"?>
I can't find a simple way to change this encoding to UTF-8 when sending the request.
Since I could find a configuration option a the request/client objects, I've tried to change the message with following code at IClientMessageInspector.BeforeSendRequest
public object BeforeSendRequest(ref Message request, IClientChannel channel)
{
// Load a new xml document from current request
var xmlDocument = new XmlDocument();
xmlDocument.LoadXml(request.ToString());
((XmlDeclaration)xmlDocument.FirstChild).Encoding = Encoding.UTF8.HeaderName;
// Create streams to copy
var memoryStream = new MemoryStream();
var xmlWriter = XmlWriter.Create(memoryStream);
xmlDocument.Save(xmlWriter);
xmlWriter.Flush();
xmlWriter.Close();
memoryStream.Position = 0;
var xmlReader = XmlReader.Create(memoryStream);
// Create a new message
var newMessage = Message.CreateMessage(request.Version, null, xmlReader);
newMessage.Headers.CopyHeadersFrom(request);
newMessage.Properties.CopyProperties(request.Properties);
return null;
}
But the newMessage object still writes the xml declaration using utf-16. I can see it while debugging at the watch window since.
Any idea on how to accomplish this (should be) simple change will be very apreciated.
Which binding do you use to create the communication channel? The textmessageencoding element which has been contained in the CustomBinding generally contains TextEncoding property.
https://learn.microsoft.com/en-us/dotnet/framework/configure-apps/file-schema/wcf/textmessageencoding
WriteEncoding property specifies the character set encoding to be used for emitting messages on the binding. Valid values are
UnicodeFffeTextEncoding: Unicode BigEndian encoding
Utf16TextEncoding: Unicode encoding
Utf8TextEncoding: 8-bit encoding
The default is Utf8TextEncoding. This attribute is of type Encoding.
As for the specific binding, it contains the textEncoding property too.
https://learn.microsoft.com/en-us/dotnet/api/system.servicemodel.basichttpbinding.textencoding?view=netframework-4.0
Feel free to let me know if there is anything I can help with.

How to deserialise a proto that was received as a byte[]

I am using the Spring.Rest framework.
If we receive a 402, the body will contain a proto which in turn will contain various error information.
The Exception raised on a 402 is an instance of Spring.Rest.Client.HttpClientErrorException.
The response within the exception is an instance of Spring.HttpResponseMessage.
The Body within the response is of type byte[].
This means I have a byte[] while the Deserialiser is expecting a Stream.
In order to deserialise the proto contained in the body I have done the following:
MemoryStream mStream = new MemoryStream();
mStream.Write(exception.Response.Body,0,exception.Response.Body.Length);
var proto = Serializer.Deserialize<XXXRestProtoException>(mStream);
when I inspect the proto returned, its properties are all null.
Is my approach correct, or do I need to do more before presenting the Stream to the Deserialize method?
We have confirmed that the proto definitions used on Client and Server are in sync and the body is well formed on the server.
The Stream produced by this code has the same length and contents as the given byte[], which in turn matches the content-length header.
If you Write to a stream, then the Position is left at the end of the stream; 2 simple options:
rewind the stream; between the Write and the Deserialize, put:
ms.Position = 0;
initialize the stream from the blob:
MemoryStream mStream = new MemoryStream(exception.Response.Body);
I'd usually use the latter.

Restful WCF Service - returning byte[]?

I'm working with a RESTful WCF service. One of the service methods returns byte[] (which contains a file).
On the client side, I have some code that uses the WebRequest class to invoke that particular service method. Using the WebRequest, I'm getting the response stream like:
Stream stream = webReq.GetResponse().GetResponseStream();
From this stream, I am then reconstructing a byte[] and then outputting the File locally. The problem is that the reconstructed file on the client-side doesn't resemble the file that was returned from the service side (I get a corrupt PDF file that is much larger in size than the one sent from the service side). Just before the service method returns the byte[], I outputted that byte[] to disk on the service side and it created the file fine... This points to something going wrong between that method returning the byte[] and my client side reconstructing the byte[] from a Stream on the client side... to reconstruct the byte[] from the Stream, I'm using the following method which someone posted in the past on stackoverflow:
public static byte[] ReadFully(Stream input)
{
byte[] buffer = new byte[16*1024];
using (MemoryStream ms = new MemoryStream())
{
int read;
while ((read = input.Read(buffer, 0, buffer.Length)) > 0)
{
ms.Write(buffer, 0, read);
}
return ms.ToArray();
}
}
Any ideas what could be going wrong?
I guess that the response from the server contains some envelope in addition to the raw bytes. Like a XML envelope or something. Which would of course suppose that the bytes are base64 encoded string in the response because you cannot store binary data into XML. It would also explain why you are getting a bigger buffer on the client than the actual PDF that the server has sent.
This will of course depend on what binding your WCF service uses and how is it configured. When you dump the contents of the MemoryStream you are reading on the client what exactly do you see? This should give you further hints on how the actual PDF file is encoded in the HTTP response body.

How to edit WCF Message - WCF message interceptors

i'm having some problems implementing my WCF message interceptor. Basically i'm accessing the body contents and performing an xslt tranform over the nodeset to sort it alphabethicaly.
I've tested the XSLT stylesheet and it's working no problems. I write the result of the transform to a MemoryStream object and then attempt to recreate the message from the stream contents.
I examine the resulting stream using either a StreamReader or by loading it into an XmlDocument and i can see the the xml it contains it my expected result from the XSLT transform.
My problem occures when i try to recreate the message! I create an XmlReader based on the stream and use this as my body source for Message.CreateMessage(.....);
I cannot understand why i'm suddenly losing the "correct" contents in the stream when i could examine it and see a couple of statements earlier.
Help very much appreciated!
Full code of the method below:
public object AfterReceiveRequest(ref System.ServiceModel.Channels.Message request, IClientChannel channel, InstanceContext instanceContext)
{
MessageBuffer msgbuf = request.CreateBufferedCopy(int.MaxValue);
Message tmpMessage = msgbuf.CreateMessage();
XmlDictionaryReader xdr = tmpMessage.GetReaderAtBodyContents();
MemoryStream ms = new MemoryStream();
_compiledTransform.Transform(xdr,null,ms);
ms.Position = 0;
XmlDocument xmlDoc = new XmlDocument();
xmlDoc.Load(ms);
MemoryStream newStream = new MemoryStream();
xmlDoc.Save(newStream);
newStream.Position = 0;
//To debug contents of the stream
StreamReader sr = new StreamReader(newStream);
var temp = sr.ReadToEnd();
//At this point the XSLT tranforms has resulted in the fragment we want so all good!
XmlReaderSettings settings = new XmlReaderSettings();
settings.ConformanceLevel = ConformanceLevel.Fragment;
newStream.Position = 0;
XmlReader reader = XmlReader.Create(newStream,settings);
reader.MoveToContent();
//Reader seems to have lost the correct fragment!!! At least returned message does not contain correct fragment.
Message newMessage = Message.CreateMessage(request.Version, null, reader);
newMessage.Properties.CopyProperties(request.Properties);
request = newMessage;
return request;
}
I think your code works Griff. I've just plugged it into an existing an existing IDispatchMessageInspector implementation and it generated a good (transformed) message. I therefore suspect your problem lies elsewhere.
How are you establishing that the 'losing' the correct contents? Could whatever is inspecting the transformed message be reading the message prior to transformation by mistake?
Unless you are trying to correlate state with the BeforeSendReply method then you should be returning null instead of the request reference.

Add custom header into Security element with WCF

Can I add and read a custom header in the Envelope/Header/Security element? I tried using the MessageHeader attribute, but that does not allow me to put the header in the Security element.
I created a class that implements IClientMessageInspector thinking that I could access the Security header like so:
public object BeforeSendRequest(ref Message request, IClientChannel channel)
{
MessageBuffer buffer = request.CreateBufferedCopy(Int32.MaxValue);
request = buffer.CreateMessage();
Message originalMessage = buffer.CreateMessage();
foreach (MessageHeader h in originalMessage.Headers)
{
Console.WriteLine("\n{0}\n", h);
}
return null;
}
But the Security header is not present in the originalMessage.Headers object.
Create a custom message encoder: http://msdn.microsoft.com/en-us/library/ms751486.aspx.
You can access the message headers in your encoder's WriteMessage override. Note that the Message's Headers property will not contain the Security header (though this may depend on the type of security you're using). Write out the message to a stream or file using, say, Message.WriteMessage(XmlWriter). The stream/file will contain the contents of the message just before being sent over the wire, including the Security element. From there, you can modify your message as necessary and return an ArraySegment including your changes.