I have a string of data, which I get from data in my database. I want to send it to the user, but without creating a local copy of the file, something like
Ok(MyString).as("file/csv")
But it is not working. How can I do it?
You can do this by using chunked with an Enumerator. I've also used withHeaders to specify the content type and disposition of the Result to "attachment", so that the client will interpret it as a file to download (rather than opening in the browser itself).
import play.api.libs.iteratee.Enumerator
val myString: String = ??? // the String you want to send as a file
Ok.chunked(Enumerator(myString.getBytes("UTF-8")).andThen(Enumerator.eof))
.withHeaders(
"Content-Type" -> "text/csv",
"Content-Disposition" -> "attachment; filename=mystring.csv"
)
This might not compile right away, depending on the types you're getting from the database.
Come to think of it, this should also work (without the Enumerator):
Ok(myString).withHeaders( /* headers from above */ )
Related
Recently I got a new project to work on a SOAP service and to Get and Post messages to a ASP.NET service based on xml.
The issue is that I managed to make the soap request and get the message.
The message looks like this:
UEsDBBQAAAAIAAdUe06+NXE0kR4AADLSAQALAAAAUHJvZHVzZS54bWzUXW1z48YN5k/h5EMnmbMsvomSpmkzFCXbjERJoSTb52/p9dq5mbxN2svczy/........
The message is Base64 Binary on RFC 4648 with multiple xml documents on it.
How I can construct this documents from the code in php?
The documents encrypted in this request are 3 xml files.
I managed to get them from an online decryptor called freeformatter with download function.
If I try to decode the result I get something like:
PKT{N�5q4�2�Produse.xml�]ms��
�O��C'��,����i3%یDI�$��o��ڹ��M����/�,��|vL�O�$�/�xv,,�u�s>9?;?....
Is there a solution for this?
I'm new to SOAP so I don't understand too much of it.
Thank you but i mannged to solve it.
I gonna post here the sollution so everyone who facing the same issue, get the response.
The first thing you need to do when you have an .zip file in a base64 binary string is to catch the response to a txt file.
Let's say the response from soap it's called ' $response ' and we need to catch this to an file. We do like this :
$response = $client -> _getLastResponse();
$fille = "response.xml";
fille_put_contents($fille,$response);
Now we got the response to an xml file.
The next thing to do is to get the response from xml values.
Lets say our value is <ResponseFromServer> .
`$b64 = "b64.txt";
$dom = new DomDocument();
$dom = load("response.xml");
$data = $dom->getElementByTagName("ResponseFromServer");
$catchb64 = $data;
fille_put_content($b64,$catchb64);`
Now we got the clean Base64 Binary string in one fille.
The next thing we need is to create the document ( in this case is a .zip fille)
`$input_fille = "response.txt"; // the fille with clean base64 binary data on it
$output_fille = "result.zip"; //the fille we need to create on system with the
documents decrypted
$content = fille_get_contents($input_fille); // Reading the content of input fille
$binary = base64_decode($content); // Decoding to binary
fille_put_contents($output_fille,$binary); // Writing to fille the vallues`
We dont need the ZipArchive() function, because is allready a zip archive, all we need to do is to create a empty document and after to send the binary data to it.
Cheer's and goodluck!
I enabled gzip compression for all the responses in my web service (Play 2.4) by following those instructions. Easy to set up, and I can see it works like a charm having checked with curl and wireshark that the responses are sent compressed.
Now I want to be a good developer and add an integration test to make sure no one breaks HTTP compression next week. Here's where the fun begins! My test looks like this:
"use HTTP compression" in {
forAll(endPoints) { endPoint =>
val response = await(
WS.url(Localhost + port + "/api" + endPoint).withHeaders("Accept-Encoding" -> "gzip").get()
)
response.header("Content-Encoding") mustBe Some("gzip")
}
}
However, the test fails as WS's response headers don't include content enconding information, and the body is returned as plain text, uncompressed.
[info] - should use HTTP compression *** FAILED ***
[info] forAll failed, because:
[info] at index 0, None was not equal to Some("gzip") (ApplicationSpec.scala:566)
Checking the traffic in wireshark when running this test I can clearly see the server is returning a gzip-encoded response, so it looks like WS is somehow transparently decompressing the response and stripping the content-encoding headers? Is there a way I can get the plain, compressed response with full headers so I can check whether the response is compressed or not?
I don't think you can do that. If I'm not mistaken , the problem here is that Netty return the content already uncompressed, so the header is removed also.
There is a configuration in AsyncHTTPClient to set that (setKeepEncoding), but unfortunately this only works in version 2.0 and newer, and Play 2.4 WS lib uses version 1.9.x.
Either way, the client Play gives you is already configured, and I don't know if you are able to tweak it. But you can create a new client to emulate that behavior:
// Converted from Java code: I have never worked with those APi's in Scala
val cfg = new AsyncHttpClientConfig.Builder().addResponseFilter(new ResponseFilter {
override def filter[T](ctx: FilterContext[T]): FilterContext[T] = {
val headers = ctx.getRequest.getHeaders
if (headers.containsKey("Accept-Encoding")) {
ctx.getResponseHeaders.getHeaders.put("Content-Encoding", List("gzip"))
}
ctx
}
}).build()
val client: NingWSClient = NingWSClient(cfg)
client.url("...") // (...)
Again, this is just emulating the result you need. Also, probably a more clever logic than just add gzip as Content-Encoding (ex: put the first algorithm requested in "Accepts Encoding") is advised.
Turns out we can't really use Play-WS for this specific test because it already returns the content uncompressed and stripped of the header (see #Salem's insightful answer), so there's no way to check whether the response is compressed.
However it's easy enough to write a test that checks for HTTP compression using standard Java classes. All we care about is whether the server answers in (valid) GZIP form when sending a request with Accept-Encoding: gzip. Here's what I ended up with:
forAll(endPoints) { endPoint =>
val url = new URL(Localhost + port + "/api/" + endPoint)
val connection = url.openConnection().asInstanceOf[HttpURLConnection]
connection.setRequestProperty("Accept-Encoding", "gzip")
Try {
new GZIPInputStream(connection.getInputStream)
} must be a 'success
}
I am getting a blob of binary data by executing a command-line program. This blob can be decoded by the same program.
I would like to send this binary data in a HTTP response. For that I use the "application/octet-stream" mime-type (I also tried "text/plain"). But when the client gets the data on the other end, it is not readable anymore. The format has changed somehow.
Here is my Scala code (but I think it is a generic question):
val command = s"samtools view -h $testbam $region"
val res: String = command.!! // Gets the stdout as string
Result(
header = ResponseHeader(200, Map.empty),
body = HttpEntity.Strict(ByteString(res), Some("application/octet-stream"))
)
The same command, run on the command-line, can be decoded properly. But the result of a "curl" here, although it does return a bunch of unreadable symbols, cannot be decoded.
Sending the same data in its readable (uncompressed) form goes through properly without losing content or formatting.
What kind of characters conversion am I missing ? Any encoding to specify ?
Edit: Play 2.5.0
I'm uploading a file using curl:
curl -X POST --data-binary #/home/me/my_file.jpb localhost:9001/upload
And here is how to store it:
def upload = Action(parse.temporaryFile) {
request =>
import java.io.File
val f = new File("tmp/someName") // how do I get the name of the file being uploaded?
request.body.moveTo(f, true)
Ok("File uploaded\n")
}
Note that files can be in any format. I want to get the name of the actually uploaded file. I tried request.body.file.getName but it returns gibberish.
How do I do that?
I am fairly certain you cannot get the file name from the binary stream you are uploading via curl. You need to explicitly provide the file name separately.
The options I can think of are these:
If your Content-Type header is instead multipart/form-data, then the process is quite simple as described here
Upload JSON with a String for the file name and a binary portion for the file.
I am implementing a file download feature via a servlet and tried using Files.probeContentType without success, it doesn't seem to pick up the right MIME type, so I use a default of application/octet-stream when that happens. In my testing, that setting seems to work ok with all the various file types like tar, gif, gz, mp4, xml, json, work as in the files are downloaded correctly and can be opened with their respective apps.
First question, if anyone can tell me what I am doing wrong with probeContentType or a better way to determine the mime type, that'll be most appreciated, here are the few lines of code in Scala
val is = new FileInputStream(file)
val mt = Files.probeContentType(file.toPath)
val mimetype = if (mt == null) "application/octet-stream" else mt
Regardless, is it ok to always set the HTTP response content-type to application/octet-stream? I have only tested with Chrome and Firefox.
UPDATE In case anyone is wondering, I ended up using MimeUtil courtesy of this post. It works great so far for all the file types I have thrown at it. Here's the snippet of Scala code
import eu.medsea.mimeutil.MimeUtil
val file = new File("path-to-your-file")
MimeUtil.registerMimeDetector("eu.medsea.mimeutil.detector.MagicMimeMimeDetector")
val mt = MimeUtil.getMimeTypes(file).toString
Here's a post with helpful code snippets for a few MIME type detection libraries.