I'm trying to gzip the output of my controller action to save some bandwidth:
new ByteArrayOutputStream().withStream{ baos ->
new GZIPOutputStream( baos ).withWriter{ it << m.text.bytes }
//def gzip = baos.toByteArray().encodeBase64()
def gzip = new String( baos.toByteArray() )
response.setHeader 'Content-Type', 'application/x-javascript'
response.setHeader 'Content-Encoding', 'x-gzip'
response.outputStream.withStream{ it << gzip }
}
}
when I open the url in a browser it gives me
Unknown Error: net::ERR_CONTENT_DECODING_FAILED
in IE
or
Content Encoding Error
in FF
What am I missing?
def index() {
response.setHeader 'Content-Type', 'application/x-javascript'
response.setHeader 'Content-Encoding', 'x-gzip'
new GZIPOutputStream(response.outputStream).withWriter{ it << "Content comes here" }
}
also consider using the capabilities of a webserver in front of your webapp (e.g. apache's gzip module can handle things like this way better). you would also have to check for the capabilities of the client first (Accept-Encoding header in the client request)
Related
I want to upload a txt file to a website using a POST request with HTTPBuilder and multipart/form-data
I've tried running my function and I get a HTTP 200 OK response, but the file doesn't appear on the website anywhere.
private Map fileUpload(String url, File file){
log.debug "doPost: $url body: ${file.getName()}"
FileBody fileBody = new FileBody(file,ContentType.APPLICATION_OCTET_STREAM)
def result = [:]
try {
def authSite = new HTTPBuilder(url)
authSite.auth.basic(user, password)
authSite.request(POST) { req ->
headers.Accept = "application/json, text/javascript, */*; q=0.01"
req.params.setParameter(CoreConnectionPNames.SO_TIMEOUT, 20000)
req.params.setParameter(CoreConnectionPNames.CONNECTION_TIMEOUT, 60000)
def mpe = new MultipartEntity(HttpMultipartMode.BROWSER_COMPATIBLE)
mpe.addPart("gxt",fileBody)
req.setEntity(mpe)
response.success = { resp, reader ->
result = reader
}
response.failure = { resp, reader ->
println "My response handler got response: ${resp.statusLine}"
}
}
}
catch (e) {
log.debug("Could not perform POST request on URL $url", e)
throw e
}
return result
}
From debugging this is the status recieved
3695 [main] DEBUG org.apache.http.wire - << "HTTP/1.1 200 OK[\r][\n]"
3695 [main] DEBUG org.apache.http.wire - << "Date: Thu, 10 Jan 2019 07:34:06 GMT[\r][\n]"
Anything I'm doing wrong? I don't get any errors but it just seems like nothing happens.
I don't have anything conclusive, but I suspect there is something invalid with the way you set up the multipart upload.
To help figure this out, below is a standalone, working, multipart upload groovy script using HttpBuilder:
#Grab('org.codehaus.groovy.modules.http-builder:http-builder:0.7.1')
#Grab('org.apache.httpcomponents:httpmime:4.2.1')
import org.apache.http.entity.mime.content.*
import org.apache.http.entity.mime.*
import groovyx.net.http.HTTPBuilder
import static groovyx.net.http.Method.POST
fileUpload('https://httpbin.org/post', new File('data.txt'))
Map fileUpload(String url, File file){
println "doPost: $url body: ${file.name}"
def result
try {
new HTTPBuilder(url).request(POST) { req ->
requestContentType = "multipart/form-data"
def content = new MultipartEntity(HttpMultipartMode.BROWSER_COMPATIBLE)
content.addPart(file.name, new InputStreamBody(file.newInputStream(), file.name))
req.entity = content
// json might be something else (like a reader)
// depending on the response content type
response.success = { resp, json ->
result = json
println "RESP: ${resp.statusLine}, RESULT: $json"
}
response.failure = { resp, json ->
println "My response handler got response: ${resp.statusLine}"
}
}
} catch (e) {
println "Could not perform POST request on URL $url"
throw e
}
result
}
The script assumes a file data.txt with the data to post in the current directory. The script posts to httpbin.org as a working test endpoint, adjust accordingly to post to your endpoint instead.
Saving the above in test.groovy and executing will yield something like:
~> groovy test.groovy
doPost: https://httpbin.org/post body: data.txt
RESP: HTTP/1.1 200 OK, RESULT: [args:[:], data:, files:[data.txt:{ "foo": "bar" }], form:[:], headers:[Accept:*/*, Connection:close, Content-Type:multipart/form-data; boundary=ZVZuV5HAdPOt2Sv7ZjxuUHjd8sDAzCz9VkTqpJYP, Host:httpbin.org, Transfer-Encoding:chunked], json:null, origin:80.252.172.140, url:https://httpbin.org/post]
(note that first run will take a while as groovy grapes need to download the http-builder dependency tree)
perhaps starting with this working example and working your way back to your code would help you pinpoint whatever is not working in your code.
I need to set a header in a post request: ["Authorization": request.token]
I have tried with wslite and with groovyx.net.http.HTTPBuilder but I always get a 401-Not authorized which means that I do cannot set the header right.
I have also thought of logging my request to debug it but I am not able to do that either.
With wslite this is what I do
Map<String, String> headers = new HashMap<String, String>(["Authorization": request.token])
TreeMap responseMap
def body = [amount: request.amount]
log.info(body)
try {
Response response = getRestClient().post(path: url, headers: headers) {
json body
}
responseMap = parseResponse(response)
} catch (RESTClientException e) {
log.error("Exception !: ${e.message}")
}
Regarding the groovyx.net.http.HTTPBuilder, I am reading this example https://github.com/jgritman/httpbuilder/wiki/POST-Examples but I do not see any header setting...
Can you please give me some advice on that?
I'm surprised that specifying the headers map in the post() method itself isn't working. However, here is how I've done this kind of thing in the past.
def username = ...
def password = ...
def questionId = ...
def responseText = ...
def client = new RestClient('https://myhost:1234/api/')
client.headers['Authorization'] = "Basic ${"$username:$password".bytes.encodeBase64()}"
def response = client.post(
path: "/question/$questionId/response/",
body: [text: responseText],
contentType: MediaType.APPLICATION_JSON_VALUE
)
...
Hope this helps.
Here is the method that uses Apache HTTPBuilder and that worked for me:
String encodedTokenString = "Basic " + base64EncodedCredentials
// build HTTP POST
def post = new HttpPost(bcTokenUrlString)
post.addHeader("Content-Type", "application/x-www-form-urlencoded")
post.addHeader("Authorization", encodedTokenString)
// execute
def client = HttpClientBuilder.create().build()
def response = client.execute(post)
def bufferedReader = new BufferedReader(new InputStreamReader(response.getEntity().getContent()))
def authResponse = new JsonSlurper().parseText(bufferedReader.getText())
I have a problem using HTTPBuilder in Grails.
The code is something like this.
def http = new HTTPBuilder("theURL")
http.request(method, ContentType.JSON) {
uri.path = "theURI"
headers.'Authorization' = "OAuth $accessToken"
headers.'Accept' = "application/json"
headers.'content-type' = "application/json;charset=utf-8"
response.success = { resp, json ->
result = json
}
}
return result
Now the response is a JSON with "Cobro N�� 1234" but i need "Cobro Nº 1234"
I tried this with curl and the response is fine "Cobro Nº 1234", this made me think that the problem is the HTTPBuilder and not my API who response the request.
I think that it is a problem with the response encoding.
http.encoders.charset = Charsets.UTF_8
Try this:
headers.'content-type' = "application/JSON;charset=UTF-8" //capitalized
Either, try this:
#Produces(MediaType.APPLICATION_JSON + ";charset=utf-8")
Try adding this after your 'http' declaration:
http.encoderRegistry = new EncoderRegistry( charset: 'utf-8' )
I couldn't follow if the content you are sending needs to be encoded with UTF-8, or if the content you are receiving needs to be read with UTF-8.
I was having a problem sending content with UTF-8, and this is what I did.
http.request(Method.PUT) { request ->
// set headers here
request.entity = new StringEntity(json.toString(), "UTF-8")
}
I'm converting a net.sf.json.JSONObject to a String in order to pass it along as the body of the PUT call. I'm using StringEntity, and previously I wasn't setting the encoding on the StringEntity, but there is a constructor that takes an encoding. Now that I'm setting "UTF-8" there, it is working.
I'm trying to specify a charset in the HTTP header of my Lighttpd-setup. I've tried numerous suggestions I've found throughout StackExchange's websites.
1. Tried looking in the mime.types file, so I could just add ; charset=utf-8 at the end of whatever file-types I wanted to specify a charset for in the HTTP header, but the mime.types-file is looking nothing like I expected: http://pastebin.com/QMKJ8Lqj
2. Tried changing create-mime.assign.pl from this:
#!/usr/bin/perl -w
use strict;
open MIMETYPES, "/etc/mime.types" or exit;
print "mimetype.assign = (\n";
my %extensions;
while(<MIMETYPES>) {
chomp;
s/\#.*//;
next if /^\w*$/;
if(/^([a-z0-9\/+-.]+)\s+((?:[a-z0-9.+-]+[ ]?)+)$/) {
foreach(split / /, $2) {
# mime.types can have same extension for different
# mime types
next if $extensions{$_};
$extensions{$_} = 1;
print "\".$_\" => \"$1\",\n";
}
}
}
print ")\n";
Into this:
#!/usr/bin/perl -w
use strict;
open MIMETYPES, "/etc/mime.types" or exit;
print "mimetype.assign = (\n";
my %extensions;
while(<MIMETYPES>) {
chomp;
s/\#.*//;
next if /^\w*$/;
if(/^([a-z0-9\/+-.]+)\s+((?:[a-z0-9.+-]+[ ]?)+)$/) {
my $pup = $1;
foreach(split / /, $2) {
# mime.types can have same extension for different
# mime types
next if $extensions{$_};
next if not defined $pup;
next if $pup eq '';
$extensions{$_} = 1;
if ($pup =~ /^text\//) {
print "\".$_\" => \"$pup; charset=utf-8\",\n";
} else {
print "\".$_\" => \"$pup\",\n";
}
}
}
}
print ")\n";
And restarted the Lighttpd server afterwards - nothing.
3. Afterwards I tried adding the following to the lighttpd.conf file:
mimetype.assign = (
".css" => "text/css; charset=utf-8",
".html" => "text/html; charset=utf-8",
".htm" => "text/html; charset=utf-8",
".js" => "text/javascript; charset=utf-8",
".text" => "text/plain; charset=utf-8",
".txt" => "text/plain; charset=utf-8",
".xml" => "text/xml; charset=utf-8"
)
And it gave me an error that it couldn't restart the Lighttpd server, because it found duplicate config variables of the "mimetype.assign" variable - one in create-mime.assign.pl and one in lighttpd.conf. I know I could try by removing include_shell "/usr/share/lighttpd/create-mime.assign.pl" from lighttpd.conf, so that there isn't any duplicate config variables, but what about all the other mime-types?
General info:
Lighttpd version: 1.4.28
PHP version: 5.3.29-1
Linux: Debian 6.0 Squeeze
Lighttpd.conf: http://pastebin.com/N6GrdUsi
Please try a newer version of lighttpd.
I am looking at 1.4.36 and doc/scripts/create-mime.conf.pl contains a list of extensions to which it appends "; charset=utf-8"
# text/* subtypes to serve as "text/...; charset=utf-8"
# text/html IS NOT INCLUDED: html has its own method for defining charset
# (<meta>), but the standards specify that content-type in HTTP wins over
# the setting in the html document.
my %text_utf8 = map { $_ => 1 } qw( # ......
You can find it in the git sources: https://github.com/lighttpd/lighttpd1.4/blob/master/doc/scripts/create-mime.conf.pl
I want to export a report as pdf and it should ask the user for a download location. How do I do this in grails?
This is my code:
def exportToPdf(JasperPrint jasperPrint,String path,request){
String cur_time =System.currentTimeMillis();
JRExporter pdfExporter = null;
pdfExporter = new JRPdfExporter();
log.debug("exporting to file..."+JasperExportManager.exportReportToPdfFile(jasperPrint, "C:\\pdfReport"+cur_time+".pdf"));
return ;
}
In jasper controller:
/**
* Generate a html response.
*/
def generateResponse = {reportDef ->
if (!reportDef.fileFormat.inline && !reportDef.parameters._inline) {
response.setHeader("Content-disposition", "attachment; filename=\"" + reportDef.name + "." + reportDef.fileFormat.extension + "\"");
response.contentType = reportDef.fileFormat.mimeTyp
response.characterEncoding = "UTF-8"
response.outputStream << reportDef.contentStream.toByteArray()
} else {
render(text: reportDef.contentStream, contentType: reportDef.fileFormat.mimeTyp, encoding: reportDef.parameters.encoding ? reportDef.parameters.encoding : 'UTF-8');
}
}
Have you looked at the Jasper Plugin? It seems to have the tools already built for you. As far as asking the user for a download location the browser has some controller over how files are received from a web page. Is your real issue that you want control over the download location?
[UPDATE]
Using the location 'c:\' is on your server not the client and this is why it is not downloading.
try something like this...
def controllerMethod = {
def temp_file = File.createTempFile("jasperReport",".pdf") //<-- you don't have to use a temp file but don't forget to delete them off the server at some point.
JasperExportManager.exportReportToPdfFile(jasperPrint, temp_file.absolutePath));
response.setContentType("application/pdf") //<-- you'll have to handle this dynamically at some point
response.setHeader("Content-disposition", "attachment;filename=${temp_file.getName()}")
response.outputStream << temp_file.newInputStream() //<-- binary stream copy to client
}
I have not tested this and there are better ways of handling the files and streams but i think you'll get the general idea.