I am using RESTEasy to PUT some data by a key and value. I'd like to only accept data that's less than 4k in size, which I figured I'd check by getting the content length of the request. Here's the method I'm working with:
#PUT
#Path("/{key}")
#Consumes(MediaType.MULTIPART_FORM_DATA)
public Response addData(
final #PathParam("key") String dataKey,
MultipartFormDataInput data) throws IOException, ClassNotFoundException {
final HttpServletRequest request = ....getHttpRequest(); //returns the request
final Map<String, List<InputPart>> parts = data.getFormDataMap();
final List<InputPart> inputParts = parts.get("data");
final InputPart part= inputParts.get(0);
final InputStream dataStream = part.getBody(InputStream.class, null);
int length = request.getContentLength();
String length2 = request.getHeader("Content-Length");
System.out.println(length);
System.out.println(length2);
service.addData(key, dataStream);
return Response.status(204).build();
}
However, length and length2 return -1 and null respectively. If I monitor Fiddler and look at the request, I notice that the contentLength on the request is not -1 but it rather a correct value instead.
Any ideas on why I can't get the request content length? Thanks.
Edit: My PUT request look like this using the Advanced Rest Client Chrome Extension: http://i.imgur.com/aI6WNDy.png
Edit: Not sure I have much else to add, but any thoughts on this would be great.
see if #HeaderParam works for you
http://www.mkyong.com/webservices/jax-rs/get-http-header-in-jax-rs/
Related
I am trying to calculate the Content-Length of the request body of a http post request but I keep getting error that indicated wrong Content-Length. Request body looks like following:
Map<String, String> body = {
'grant_type': 'authorization_code',
'client_id': 'clientid',
'code': authCode,
'redirect_uri': 'http://localhost:8080/login/callback',
'code_verifier':
'codeverifier',
};
I tried couple solutions like concatenating content of the body into one string such as following and then convert it into byte array and send the length of it but it didn't work.
String bodyStr = "grant_type:authorization_code" +
"client_id:clientid" +
"code:{$authCode}" +
"redirect_uri:http://localhost:8080/login/callback" +
"code_verifier:codeverifier";
List<int> bytes = utf8.encode(bodyStr);
The post request body is x-www-form-urlencoded format and content length has to be calculated correctly. Any help is appreciated, thanks.
I encapsulated it myself. Generally, I don't need to calculate it. Unless it's a special occasion.
Okhttp3 is recommended
You don't need to make a list of integer...
String bodyStr = "...";
byte[] bytes = bodyStr.getBytes(Charset.forName("UTF-8"));
int len = bytes.length;
response.setContentLength(len);
response.getOutputStream().write(bytes);
This example is using the HttpServletResponse object from a HttpServlet. Not sure if that's what you need.
I have used this a fair amount, it works well.
I am using dropwizard for REST Services and would like to limit maximum body (json) size for POST request.
I tried setting org.eclipse.jetty.server.Request.maxFormContentSize to 1 but that doesn't limit body size.
If there any other way to set the limit ?
You can get the MutableServletContextHandler from the DropWizard environment:
environment.getApplicationContext().setMaxFormContentSize(1024);
However, the MaxFormContentSize only applies to form encoded requests.
To limit the size of the request body for a POST request, you can check the content length when you handle the request in your Resource class:
#POST
#Path("/test")
public Response test(#Context final HttpServletRequest request) {
int contentLength = request.getContentLength();
if (contentLength == -1 || contentLength > MAX_REQUEST_SIZE) {
// fail the request
}
// do work
}
I have a method that receives the inputstream via HTTP Put and converts it into byte[] and sends it to another method called verifysignature. I have been having a weird problem with it. The code is all right, but however the message digests don't match. After debugging, I found out it works fine if my inpustream has a single line of text but fails when there are multiple lines.
The request body of Http PUT looks like :
{
"Url":"http://live.dev:3000/access_tokens",
"AuthorizationUrl":"http://live.dev:3000/client_access_tokens",
"Cert":"test"
}
The method that responds to PUT request:
public #ResponseBody Map<String,String> createAuthorizationServer(HttpServletRequest request)throws IOException {
// This method converts inputstream to byte[]
byte[] inputStream = toBodyBytes(request.getInputStream());
X509Certificate signingCert = null;
//..... stuff
// Here I am using the byte array
signingCert = engine.verifySignature(signature,inputStream);
This works fine when the payload in request body is something in one line:
"test:;sample"
But fails when it has a multiple lines, like:
"test:;"
"sample"
Can someone please throw some light at this?
toBodyBytes method for your reference:
private static byte[] toBodyBytes(InputStream inputStream) throws IOException {
final int MAX_PAYLOAD_SIZE = 10240;
byte[] buf = new byte[MAX_PAYLOAD_SIZE];
// protect against OutOfMemoryError in case of misconfiguration (accidentally filtering uploads)
int bodySize = read(inputStream, buf, 0, buf.length);
checkState(bodySize < MAX_PAYLOAD_SIZE, "Looking for signature on upload payload?");
return copyOf(buf, bodySize);
}
Thank you!
I need to pass response from server to clinet (a'la proxy):
private void pushProxyToClient(HttpExchange httpExchange, HttpURLConnection connection) throws IOException {
// pass headers
Headers respHeaders = httpExchange.getResponseHeaders();
Map<String, List<String>> headers = connection.getHeaderFields();
for (String key: headers.keySet()) {
if (key == null){
continue;
}
List<String> values = headers.get(key);
respHeaders.put(key, values);
}
httpExchange.sendResponseHeaders(connection.getResponseCode(), connection.getContentLength());
// pass body
InputStreamReader isr = new InputStreamReader(connection.getInputStream());
OutputStreamWriter isw = new OutputStreamWriter(httpExchange.getResponseBody());
long count = 0;
while (count < connection.getContentLengthLong()) {
isw.write(isr.read());
count += 1;
}
isr.close();
isw.close();
}
Unfortunatley, the client (firefox) tries to download response as file instead of render it as html. What I'm doing wrong?
UPDATE
It's now working (sendResponseHeaders was invoked too early) but now I'm getting error (from browser) that it was unable to uncompress body.
The page you are trying to view cannot be shown because it uses an invalid or unsupported form of compression.
Content body is empty. Why?
UPDATE 2
It almost works. The problem was InputStreamWriter. Changing it to InputStream's read helped. Any way... some of pages render its content twice.. do not know why.
Do you set content type? You content type should be same (for example text/html) and not like application/octet-stream. Hardcoded example:
Headers headers = httpExchange.getResponseHeaders();
headers.add("Content-Type", "text/html");
In your example you set:
httpExchange.setAttribute(key, this.flatRequestValues(values));
instead of headers.add. Try:
Headers headers = httpExchange.getResponseHeaders();
for (String value: values) {
headers.add(key, value);
}
EDIT: or better:
Headers headers = httpExchange.getResponseHeaders();
headers.put(key, values);
I solved an issue I had with retrieving and displaying non-UTF-8 characters but I don't understand why my solution works.
The following code:
final HttpClient client = new HttpClient();
final HttpMethod method = new GetMethod(urlString);
client.executeMethod(method);
final String responseBodyAsString = method.getResponseBodyAsString();
System.out.println(responseBodyAsString);
was messing up some characters on the display, such as Yáñez
I changed:
final String responseBodyAsString = method.getResponseBodyAsString();
to
final ByteBuffer inputBuffer = ByteBuffer.wrap(method.getResponseBody());
final String responseBodyAsString = new String(inputBuffer.array());
and the same string as before is represented correctly as Yáñez
Why is that?
getResponseBodyAsString() uses the HTTP response's Content-Type header to know what the response body's charset is so the data can be converted to a String as needed. getResponseBody() simply returns the body's raw bytes as-is, which you are then converting to a String using the platform's default charset. Since you are able to get the desired String output by converting the raw bytes manually, that suggests to me that the HTTP server is not specifying a charset in the response's Content-Type header at all, or is specifying the wrong charset.
Yáñez is the UTF-8 encoded version of Yáñez, so it is odd that the String(bytes[]) constructor would be able to decode it correctly, unless the platform's default charset is actually UTF-8. It does make sense for getResponseBodyAsString() to return Yáñez if the response charset used is ISO-8859-1, which is the default charset for text/... media types sent over HTTP when no charset is explicitly specified, per RFC 2616 Section 3.7.1.
I would suggest looking for a bug in the server script that is sending the data (or reporting a bug report to the server admin), before suspecting a bug with getResponseBodyAsString(). You can use a packet sniffer like Wireshark, or a debugging proxy like Fiddler, to confirm the missing/invalid charset in the response Content-Type header.
Try the next:
private static final String UNICODE = "ÀàÈèÌìÒòÙùÁáÉéÍíÓóÚúÝýÂâÊêÎîÔôÛûŶŷÃãÕõÑñÄäËëÏïÖöÜüŸÿÅåÇçŐőŰű";
private static final String PLAIN_ASCII = "AaEeIiOoUuAaEeIiOoUuYyAaEeIiOoUuYyAaOoNnAaEeIiOoUuYyAaCcOoUu";
public static String convertNonAscii(String str) {
if (str == null) {
return null;
}
StringBuilder sb = new StringBuilder();
for (int i = 0; i < str.length(); i++) {
char c = str.charAt(i);
int pos = UNICODE.indexOf(c);
if (pos > -1)
sb.append(PLAIN_ASCII.charAt(pos));
else {
sb.append(c);
}
}
return sb.toString();
}
public static void main(String[] args) {
Pattern p = Pattern.compile("[^\\x00-\\x7E]", Pattern.CASE_INSENSITIVE);
System.out.println(p.matcher(UNICODE).find());
System.out.println(p.matcher(PLAIN_ASCII).find());
System.out.println(convertNonAscii("ú or ñ"));
}
Output:
true
false
u or n