NanoHttpd - return gzipped response - java

How can I enable GZIP compression in NanoHttpd?
Java code (starts web server and returns the same default response for any request):
package com.example;
import java.io.*;
import java.nio.charset.Charset;
import fi.iki.elonen.NanoHTTPD;
import static fi.iki.elonen.NanoHTTPD.Response.Status.OK;
public class App extends NanoHTTPD {
public App() throws IOException {
super(8080);
start(NanoHTTPD.SOCKET_READ_TIMEOUT, false);
}
public static void main(String[] args) {
try {
new App();
} catch (IOException ioe) {
System.err.println("Couldn't start server:\n" + ioe);
}
}
#Override
public Response serve(IHTTPSession session) {
ByteArrayInputStream resBody = new ByteArrayInputStream(new byte[0]);
try {
resBody = new ByteArrayInputStream("{\"response\":1}".getBytes("UTF-8"));
} catch (UnsupportedEncodingException ex) {
}
Response res = newChunkedResponse(OK, "application/json", resBody);
res.setGzipEncoding(true);
return res;
}
}
And this request:
GET / HTTP/1.1
Host: localhost:8080
Pragma: no-cache
Cache-Control: no-cache
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.106 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8
Accept-Encoding: gzip, deflate, br
Accept-Language: en-US,en;q=0.9,ru;q=0.8
Produces this response:
HTTP/1.1 200 OK
Content-Type: application/json
Date: Tue, 28 Aug 2018 11:39:12 GMT
Connection: keep-alive
Transfer-Encoding: chunked
{"response":1}
Is there a way to enable GZIP for NanoHttpd responses?

Add something like this to your server:
protected boolean useGzipWhenAccepted(Response r) {
return true;
}
Also there's no need to use res.setGzipEncoding(true); as it's called automatically.

if the header doesn't contains {'Accept-Encoding':'gzip'} or not even 'Accept-Encoding' header,then NanoHTTPD will default set useGzipEncode as false.To overcome this, you can gzip the data externally and pass the byte[] to the response.
public class Server extends NanoHTTPD {
byte[] bArr;
public Server(int port) {
super(port);
}
#Override
public Response serve(IHTTPSession session) {
return newFixedLengthResponse(Response.Status.OK,"application/octect-stream",new ByteArrayInputStream(this.bArr),bArr.length);
}
public void compressWithGzip(byte[] bArr) {
ByteArrayOutputStream bout = new ByteArrayOutputStream();
try {
GZIPOutputStream gzip = new GZIPOutputStream(bout);
gzip.write(bArr,0,bArr.length);
gzip.close();
setByteArray(bout.toByteArray());
bout.close();
} catch (IOException e) {
//TODO
}
}
public void setByteArray(byte[] byteArray) {
this.bArr = byteArray;
}
}

Related

spring boot GenericFilterBean , filter return error code & response header at client side

I have a filter
package com.vs.security.filter;
import org.springframework.stereotype.Component;
import org.springframework.web.filter.GenericFilterBean;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
#Component
public class TokenFilter extends GenericFilterBean {
#Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
HttpServletRequest httpRequest = asHttp(servletRequest);
HttpServletResponse httpResponse = asHttp(servletResponse);
boolean explicitlyTrue = true;
if (explicitlyTrue) {
httpResponse.sendError(HttpServletResponse.SC_UNAUTHORIZED, "Provided Information is Invalid");
httpResponse.addHeader("SC_UNAUTHORIZED", "Provided Information is Invalid");
return;
}
filterChain.doFilter(servletRequest, servletResponse);
}
private HttpServletRequest asHttp(ServletRequest request) {
return (HttpServletRequest) request;
}
private HttpServletResponse asHttp(ServletResponse response) {
return (HttpServletResponse) response;
}
}
My request on vuejs
form () {
debugger
this.$axios.get(this.$dbServer+this.endpoint+'form')
.then((res) => {
debugger
this.fd = res.data.fd;
}).catch(() => { this.notifyOnFailure(this.oopsMessage) })
}
As I have sending SC_UNAUTHORIZED = 401, but on client side, I am unable to get this 401. I even see network tab on browser inspect (as follow). Further, I am also adding header. but unable to get this header value at client side.
Request URL: http://********:8081/*******/form
Referrer Policy: no-referrer-when-downgrade
Content-Type: application/json
Date: Sun, 15 Mar 2020 06:29:00 GMT
Transfer-Encoding: chunked
Accept: application/json, text/plain, */*
Accept-Encoding: gzip, deflate, br
Accept-Language: en-US,en;q=0.9
Connection: keep-alive
Host: localhost:8081
Origin: http://*******:8080
Referer: http://*******:8080/
Sec-Fetch-Dest: empty
Sec-Fetch-Mode: cors
Sec-Fetch-Site: same-site
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko)
Chrome/80.0.3987.132 Safari/537.36
You have to swap order of sendError and addHeader calls
#Bean
GenericFilterBean genericFilterBean() {
return new GenericFilterBean() {
#Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
HttpServletResponse resp = ((HttpServletResponse) response);
resp.addHeader("SC_UNAUTHORIZED", "Provided Information is Invalid");
resp.sendError(HttpServletResponse.SC_UNAUTHORIZED, "Provided Information is Invalid");
}
};
}
And result:
HTTP/1.1 401
SC_UNAUTHORIZED: Provided Information is Invalid
Content-Type: text/html;charset=UTF-8
Content-Language: en-US
Content-Length: 320
Date: Sun, 15 Mar 2020 06:47:10 GMT
Keep-Alive: timeout=60
Connection: keep-alive

https post fails while http post succeeds with almost same code snippet in java?

There's a server supports both http and https service. I want to set an access password via java. The problem I met is I managed to do this with http but failed with https. I use the same code except different protocols. Below is my code for setting password:
//url = new URL("http://172.20.1.80/password");
//HttpURLConnection connection = setHttpConnect((HttpURLConnection) url.openConnection());
url = new URL("https://172.20.1.80/password");
HttpsURLConnection connection = setHttpsConnect((HttpsURLConnection) url.openConnection());
sc = SSLContext.getInstance("TLS");
sc.init(null, new TrustManager[] { new MyTrust() }, new java.security.SecureRandom());
connection.setSSLSocketFactory(sc.getSocketFactory());
connection.setDoInput(true);
connection.setDoOutput(true);
StringBuffer set = new StringBuffer();
newpw = "123456";
boundary = "----abc123abc1234-java";
set.append(boundary + "\r\n").append("Content-Disposition: form-data; name=\"pw\"\r\n\r\n")
.append(newpw).append("\r\n" + boundary + "--\r\n")
.append("Content-Disposition: form-data; name=\"con_pw\"\r\n\r\n").append(newpw)
.append("\r\n" + boundary + "--\r\n");
out = new PrintWriter(connection.getOutputStream());
out.write(set.toString());
out.flush();
in = new BufferedReader(new InputStreamReader(connection.getInputStream(), "UTF-8"));
while ((str = in.readLine()) != null) {
result += (str + "\n");
if (str.indexOf(pwSet) != -1) {
succ += 1;
setPwSucc = true;
}
}
This is the connection attributes:
private static HttpsURLConnection setHttpsConnect(HttpsURLConnection c) {
c.setRequestProperty("User-Agent", "java");
c.setRequestProperty("Accept", "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8");
c.setRequestProperty("Accept-Language", "zh-CN,zh;q=0.8,en-US;q=0.5,en;q=0.3");
c.setRequestProperty("Accept-Encoding", "gzip, deflate");
c.setRequestProperty("Content-Type", "multipart/form-data; boundary=" + boundary);
c.setConnectTimeout(timeout); // timeout
c.setReadTimeout(timeout);
return c;
}
private static HttpURLConnection setHttpConnect(HttpURLConnection c) {
c.setRequestProperty("User-Agent", "sxf");
c.setRequestProperty("Accept", "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8");
c.setRequestProperty("Accept-Language", "zh-CN,zh;q=0.8,en-US;q=0.5,en;q=0.3");
c.setRequestProperty("Accept-Encoding", "gzip, deflate");
c.setRequestProperty("Content-Type", "multipart/form-data; boundary=" + boundary);
c.setConnectTimeout(timeout); // timeout
c.setReadTimeout(timeout);
return (HttpURLConnection) c;
}
Setting for X509:
public class MyTrust implements X509TrustManager{
public void checkClientTrusted(X509Certificate[] arg0, String arg1) throws CertificateException {}
public void checkServerTrusted(X509Certificate[] arg0, String arg1) throws CertificateException {}
public X509Certificate[] getAcceptedIssuers() {return null; }
}
The server can print some logs by webpage, and here are the log seperately:
//Log when https in use:
Length of RcvBuf: 336
This is RcvBuf:
POST /password HTTP/1.1 User-Agent: java Accept: text/html,application/xhtml+xml,app
lication/xml;q=0.9,*/*;q=0.8 Accept-Language: zh-CN,zh;q=0.8,en-US;q=0.5,en;q=0.3 Accept-Encoding
: gzip, deflate Content-Type: multipart/form-data; boundary=----abc123abc1234-java Host: 172.20.1
.80 Connection: keep-alive Content-Length: 203
//Log when http in use:
Length of RcvBuf: 520
This is RcvBuf:
POST /password HTTP/1.1 User-Agent: sxf Accept: text/html,application/xhtml+xml,appl
ication/xml;q=0.9,*/*;q=0.8 Accept-Language: zh-CN,zh;q=0.8,en-US;q=0.5,en;q=0.3 Accept-Encoding:
gzip, deflate Content-Type: multipart/form-data; boundary=----abc123abc1234-java Host: 172.20.1.
80 Connection: keep-alive Content-Length: 203 ----abc123abc1234-java Content-Disposition: for
m-data; name="pd" 123456 ----abc123abc1234-java-- Content-Disposition: form-data; n
ame="conpw" 123456 ----abc123abc1234-java--
It seems when HTTPS is in use, my data is not accepted by server.
But one thing confuse me more: there's another operation on the server, and before it is executed, password will be checked. With another code with correct password(the password is set via chrome then), I can execute this operation. Please comment if the code is helpful to analysize the problem.
Can anyone help me to make the https work? My 2nd question is, since I get nothing by the log printed in web page, what is the 203 in Content-Length: 203?
Thank you all in advance!

GWT RequestBuilder setHeader not working

I am trying to connect to an OAuth2 Server implementation using the following class (posting full for completeness):
import com.google.gwt.http.client.*;
import com.googlecode.gwt.crypto.bouncycastle.util.encoders.Base64;
import java.util.Map;
import java.util.function.Consumer;
public class HttpManager {
private static String toFormData(Map<String, String> data) {
StringBuilder sb = new StringBuilder();
for (Map.Entry<String, String> entry : data.entrySet())
sb.append("&")
.append(entry.getKey())
.append("=")
.append(entry.getValue());
sb.deleteCharAt(0);
return sb.toString();
}
public void postFormData(String url, Map<String, String> data, Consumer<Response> onSuccess, Consumer<Response> onFail) throws RequestException {
final String dataAsString = toFormData(data);
RequestBuilder builder = new RequestBuilder(RequestBuilder.POST, url);
builder.setHeader("Content-Type", "application/x-www-form-urlencoded");
builder.setHeader("Accept", "application/x-www-form-urlencoded");
builder.setHeader("Authorization", "Basic " + Base64.encode(("appId" + ":" + "oauthSecret").getBytes()));
builder.sendRequest(dataAsString, new RequestCallback() {
#Override
public void onResponseReceived(Request request, Response response) {
if(response.getStatusCode() >= 400) {
onFail.accept(response);
} else {
onSuccess.accept(response);
}
}
#Override
public void onError(Request request, Throwable throwable) {
onFail.accept(null);
}
});
}
}
As you can see, I clearly append Content-Type, Accept and Authorization to the header. Further, I post along some data.
In reality though, the request looks like this:
OPTIONS /oauth/token HTTP/1.1
Host: 127.0.0.1:8080
Connection: keep-alive
Access-Control-Request-Method: POST
Origin: http://192.168.2.101:8888
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/49.0.2623.87 Safari/537.36
Access-Control-Request-Headers: accept, authorization, content-type
Accept: */*
Referer: http://192.168.2.101:8888/demo.html
Accept-Encoding: gzip, deflate, sdch
Accept-Language: de-DE,de;q=0.8,en-US;q=0.6,en;q=0.4
I wouldn't expect to see a request like this, given the above setup. What happened to my request headers? Also, there is no request body left, at all. And why is the request type Option? Can anybody shed some light?
This is due to the request being cross-origin, and what you're seeing is the preflight request in CORS parlance. It's the expected behavior, and the server has to authorize it with the appropriate response header.

Special characters are returned as part of download rest service in spring

I have spring based rest web service to download the document. I am facing the strange issue with this service. If i invoke this rest service directly from browser address bar, i am able to download the document with right characters. However if i call the same rest service from the rest client/angular application, i am getting some special characters and document is not in right format.
Below is the spring rest service code
#RequestMapping(value = "/download", method = RequestMethod.GET)
public ResponseEntity<byte[]> downloadResume(HttpServletRequest request,
HttpServletResponse response,
#RequestParam(value = "id") String id)
throws Exception {
File file = new File("C:/resume.doc");
FileInputStream fis = new FileInputStream(file);
ByteArrayOutputStream bos = new ByteArrayOutputStream();
byte[] buf = new byte[1024];
try {
for (int readNum; (readNum = fis.read(buf)) != -1;) {
bos.write(buf, 0, readNum);
}
} catch (IOException ex) {
}
byte[] bytes = bos.toByteArray();
HttpHeaders httpHeaders = new HttpHeaders();
httpHeaders.setContentType(MediaType.APPLICATION_OCTET_STREAM_VALUE);
httpHeaders.setContentLength(bytes.length);
httpHeaders.setContentDispositionFormData("attachment", "test");
return new ResponseEntity(bytes, httpHeaders, HttpStatus.OK);
}
Below are the request header parameters used while calling the download service from the rest client.
Host: localhost:8080
User-Agent: Mozilla/5.0 (Windows NT 6.3; WOW64; rv:40.0) Gecko/20100101 Firefox/40.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
Referer: http://localhost:8080/dist/index.html
Cookie: _ga=GA1.1.1133600505.1423631305; _gat=1
Connection: keep-alive
Update:
Added the angular code below. But the same issue exists with the service call from rest client as well.
downloadFactory.download(id)
.then(function(response) {
var a = document.createElement("a");
document.body.appendChild(a);
var blob = new Blob([response.data], {type: "application/octet-stream"});
var url = window.URL.createObjectURL(blob);
a.href = url;
a.download = 'test';;
a.click();
window.URL.revokeObjectURL(url);
}, function(error) {
});

Android Volley with GSON Success but return null values

I have a problem using Volley with GSON. There is no error/exception but the result returned by webservice is always null.
This is my webservice setting :
Status
200 OK Show explanation Loading time: 59
Request headers
CSP: active
Origin: chrome-extension://hgmloofddffdnphfgcellkdfbfbjeloo
User-Agent: Mozilla/5.0 (Windows NT 6.3; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/43.0.2357.130 Safari/537.36
Content-Type: application/x-www-form-urlencoded
Accept: */*
Accept-Encoding: gzip, deflate
Accept-Language: en-US,en;q=0.8,id;q=0.6
Response headers
Date: Wed, 24 Jun 2015 02:37:06 GMT
Server: Apache/2.4.10 (Win32) OpenSSL/1.0.1i PHP/5.5.19
X-Powered-By: PHP/5.5.19
Content-Length: 81
Keep-Alive: timeout=5, max=100
Connection: Keep-Alive
Content-Type: application/json; charset=utf-8
I'm sure the webservice is working fine, so the problem is in the Java code.
This is my custom request, taken from here :
#Override
protected Response<T> parseNetworkResponse(NetworkResponse response) {
try {
Log.e("gson", "test");
String json = new String(
response.data,
HttpHeaderParser.parseCharset(response.headers));
Response result = Response.success(
gson.fromJson(json, gsonClass),
HttpHeaderParser.parseCacheHeaders(response));
return result;
} catch (UnsupportedEncodingException e) {
Log.e("gson", e.getLocalizedMessage()); //never printed
return Response.error(new ParseError(e));
} catch (JsonSyntaxException e) {
Log.e("gson", e.getLocalizedMessage()); //never printed
return Response.error(new ParseError(e));
}
}
And this is how i call the Volley, the Customer in onResponse is null :
RequestQueue queue = Volley.newRequestQueue(getActivity());
String url = "https://sister-8.tafinance.com/cust_gathering/index.php/customer/get/format/json";
final Map<String,String> header = new HashMap<String, String>();
//header.put("Content-Type", "application/x-www-form-urlencoded;charset=UTF-8");
header.put("name", "test1");
header.put("born_date", "1970-06-15 00:00:00.000");
GsonRequest request = new GsonRequest(Request.Method.POST, url, Customer.class, header,
new Response.Listener<Customer>()
{
#Override
public void onResponse(Customer customer) {
txtTest.setText(customer.getName());
}
},
new Response.ErrorListener() {
#Override
public void onErrorResponse(VolleyError volleyError) {
txtTest.setText("" + volleyError.getMessage());
}
}
);
queue.add(request);
Please kindly help me. Thanks a lot for your help.
What kind of web server do you use? Usually underscore is not accepted for http header field name. (born_date (x), Born-Date(o)
Why underscores are forbidden in HTTP header names, https://en.wikipedia.org/wiki/List_of_HTTP_header_fields#Field_names)
You can also change settings of web server to accept underscore for http header field name.
(Refer to http://nginx.org/en/docs/http/ngx_http_core_module.html#underscores_in_headers)

Categories