I'm trying to understand a strange behaviour in pdf file download using spring mvc servlet.
Here is the controller code used to download files:
#RequestMapping(value = "/handler/{id}", method = RequestMethod.GET)
public HttpEntity<byte[]> report(#PathVariable("id") Long id,
HttpServletResponse response,
HttpServletRequest request) {
byte[] bytes = service.reportById(id);
return DownloadUtil.downloadFile(response, "application/pdf",
"Filename.pdf", bytes);
}
public static HttpEntity<byte[]> downloadFile(
final HttpServletResponse response,
final String contentType,
final String fileName,
final byte[] item){
HttpHeaders header = new HttpHeaders();
header.setContentType(MediaType.valueOf(contentType));
header.set("Content-Disposition", "inline; filename=\"" + fileName +"\"");
header.set("Content-Transfer-Encoding", "application/octet-stream");
header.setContentLength(item.length);
return new HttpEntity<byte[]>(item, header);
}
When pdf is displayed in chrome pdf viewer it works. Here request/response headers:
Request:
GET /path/19649/download HTTP/1.1
Host: localhost:8080
Connection: keep-alive
Cache-Control: max-age=0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8
User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/41.0.2272.76 Safari/537.36
Referer: http://path/byDitta
Accept-Encoding: gzip, deflate, sdch
Accept-Language: it,en-US;q=0.8,en;q=0.6
Cookie: JSESSIONID=09CEA1438ACED879CDD96877BB536022; _ga=GA1.1.2013320496.1416898514
Response:
HTTP/1.1 200 OK
Server: Apache-Coyote/1.1
X-Content-Type-Options: nosniff
X-XSS-Protection: 1; mode=block
Cache-Control: no-cache, no-store, max-age=0, must-revalidate
Pragma: no-cache
Expires: 0
X-Frame-Options: DENY
Content-Disposition: inline; filename="file.pdf"
Content-Transfer-Encoding: application/octet-stream
Content-Type: application/pdf;charset=UTF-8
Content-Length: 296750
Date: Tue, 10 Mar 2015 09:39:05 GMT
When I save pdf displayed in pdf viewer I've this request/response header:
Request:
GET /path/19649/download HTTP/1.1
Host: localhost:8080
Connection: keep-alive
Referer: /path/19649/download
User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/41.0.2272.76 Safari/537.36
Accept-Encoding: gzip, deflate, sdch
Accept-Language: it,en-US;q=0.8,en;q=0.6
Cookie: JSESSIONID=09CEA1438ACED879CDD96877BB536022; _ga=GA1.1.2013320496.1416898514
Response:
HTTP/1.1 200 OK
Server: Apache-Coyote/1.1
X-Content-Type-Options: nosniff
X-XSS-Protection: 1; mode=block
Cache-Control: no-cache, no-store, max-age=0, must-revalidate
Pragma: no-cache
Expires: 0
X-Frame-Options: DENY
Content-Disposition: inline; filename="file.pdf"
Content-Transfer-Encoding: application/octet-stream
Content-Type: application/pdf;charset=UTF-8
Content-Length: 296750
Date: Tue, 10 Mar 2015 09:40:29 GMT
The difference is in accept request header, I think. It is missed in save pdf request.
The problem is that, when this file is saved it has a wrong encoding and so results to be damaged.
The strange thing is that I use the ~same code in another project to do the same thing and it works. So I think, may be something in servlet config?
How can I force right download encoding?
From the comment:
Comparing file size, working pdf is 227403 bytes, the other is 303206 bytes
This suggests the data is Base64 encoded. I don't see why this would happen; most of the time, you get this effect when the server thinks the client can't handle binary data (like when you do an AJAX request).
[EDIT] Install a proxy server like Fiddler which allows you to see the raw data which your server sends to the browser. Try to create only a small PDF, to make this easier.
With these tools, you can find out who encodes the data.
If your pdf file generated well, I think you should try in this way:
#RequestMapping(value = "clients/city")
#ResponseBody
private OutputStream getCity(HttpServletRequest request,HttpServletResponse response) throws IOException, JRException {
String path=request.getRealPath("resources/files");
createFileService.SpravkaCity(path);
// response.setContentType("text/plain");
// response.setHeader("Content-Disposition", "attachment; filename=reestr.xls");
File f=new File(path+"/city.pdf");
response.setContentType("application/pdf");
// response.setHeader("Content-Transfer-Encoding", "binary");
response.setHeader("Content-Length", String.valueOf(f.length()));
response.setHeader("Content-Disposition", "inline; filename=city.pdf");
Path p = Paths.get(path+"/city.pdf");
response.getOutputStream().write(Files.readAllBytes(p));
return response.getOutputStream();
}
Hope it will help you.
Related
I'm having a blocking exception while requesting the servlet parts in Weblogic 12.2.1.4-dev on docker.(please note that this is working on Wildfly server)
The Java code i'm using is:
import javax.servlet.http.*;
protected void doPut(HttpServletRequest request, HttpServletResponse response) throws IOException {
...
Collection<Part> parts = request.getParts();
...
}
the error i'm having in the server.log:
<Oct 2, 2020 9:17:59,302 AM GMT> <Warning> <HTTP> <BEA-101394> <The exception "The request content-type is not a multipart/form-data" occurred when processing getParameter or getParameterValues from a multipart value of a ServletRequest.>
javax.servlet.ServletException: The request content-type is not a multipart/form-data
at weblogic.servlet.utils.fileupload.Multipart.getParts(Multipart.java:158)
at weblogic.servlet.internal.ServletRequestImpl$RequestParameters.getParts(ServletRequestImpl.java:2497)
at weblogic.servlet.internal.ServletRequestImpl$RequestParameters.access$3000(ServletRequestImpl.java:2181)
at weblogic.servlet.internal.ServletRequestImpl.getParts(ServletRequestImpl.java:3652)
at javax.servlet.http.HttpServletRequestWrapper.getParts(HttpServletRequestWrapper.java:375)
And the Http request details on google chrome:
// GENERAL
Request URL: http://172.21.1.1:8310/backoffice/service
Request Method: PUT
Status Code: 400 Bad Request
Remote Address: 172.1.1.1:8310
Referrer Policy: strict-origin-when-cross-origin
// REQUEST HEADERS
Accept: */*
Accept-Encoding: gzip, deflate
Accept-Language: en-BE,en;q=0.9,fr-FR;q=0.8,fr;q=0.7,en-US;q=0.6,es;q=0.5,it;q=0.4
Cache-Control: no-cache
Connection: keep-alive
Content-Length: 647482
Content-Type: multipart/form-data; boundary=----WebKitFormBoundaryoCBB96YNI9S3vXob
Cookie: JSESSIONID=XIjomkiRAVxEtEn0qwlILe46arjsphNNibL00t2dHEhj75oc167A!-481127499
Host: 172.1.1.1:8310
Origin: http://172.1.1.1:8310
Pragma: no-cache
Referer: http://172.1.1.1:8310/backoffice/products/edit?id=MA01
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/85.0.4183.121 Safari/537.36
X-Requested-With: XMLHttpRequest
// FORM DATA
subside-velo-pedelec25.pdf: (binary)
actionId: 98c6e900-0289-4bb6-8e98-2b967b2ee363
windowId: YbVZr0XiCFHxU7K4hUlmBJmLoXwzY6
I faced the same issue.
FileUpload's servlet implementation from WebLogic core libs only allow multipart requests under "POST" method:
private boolean isMultipart() {
if (!this.request.getMethod().toLowerCase().equals("post"))
return false;
String contentType = this.request.getContentType();
if (contentType == null)
return false;
if (contentType.toLowerCase().startsWith("multipart/form-data"))
return true;
return false;
}
If this validation fails, it will throw an exception including a message that does not have any relation with the actual error:
if (!isMultipart())
throw new ServletException("The request content-type is not a multipart/form-data");
So I switched my method from PUT to POST.
I have to call a proprietary service that does not support multipart requests, I'm not sending any attachments but cxf seems to create a multipart request
POST /endpoint HTTP/1.1
Content-Type: multipart/related; type="text/xml"; boundary="uuid:86ebef4f-fc2a-431b-a21b-37e86b4901f9"; start="<root.message#cxf.apache.org>"; start-info="text/xml"
Accept: */*
Authorization: Basic U1dHMTAwNTA6MTIzNDU1
SOAPAction: "XYZ.0050"
User-Agent: Apache-CXF/3.3.6
Cache-Control: no-cache
Pragma: no-cache
Host: localhost:8082
Connection: keep-alive
Content-Length: 2134
--uuid:86ebef4f-fc2a-431b-a21b-37e86b4901f9
Content-Type: text/xml; charset=UTF-8
Content-Transfer-Encoding: binary
Content-ID: <root.message#cxf.apache.org>
[etc...]
I've noticed a non-multipart request works fine
POST /endpoint HTTP/1.1
Content-Type: text/xml;charset=UTF-8
Accept: */*
Authorization: Basic U1dHMTAwNTA6MTIzNDU1
Cache-Control: no-cache
Connection: keep-alive
Host: localhost:8082
Pragma: no-cache
SOAPAction: "XYZ.0050"
User-Agent: Apache-CXF/3.3.6
Content-Length: 2114
[etc...]
How do I force cxf to use a non-multipart request?
it looks like cxf creates a multipart any time there is a #XmlAttachmentRef / DataHandler attribute, in my case it is never used so I removed it from my classes.
a better solution would be to remove the SwAOutInterceptor from the interceptor chain by definining an interceptor remover
class InterceptorRemover : AbstractSoapInterceptor(Phase.PRE_LOGICAL) {
init {
addBefore(SwAOutInterceptor::class.java.name)
}
override fun handleMessage(message: SoapMessage?) {
if (message != null) {
val res = message.interceptorChain.firstOrNull() { it is SwAOutInterceptor }
if (res != null) {
message.interceptorChain.remove(res)
}
}
}
}
and add it to the chain:
val client = ClientProxy.getClient(port)
client.outInterceptors.add(InterceptorRemover())
I'm creating a basic local proxy server, the goal is to accept http and https traffic from my web browser, parse it for information, send and receive the requests to the proper host, and then return it to the web browser.
I currently have an open socket to my web browser. I am receiving both http and https requests from the browser like so:
HTTP:
GET http://example.com/ HTTP/1.1
Host: example.com User-Agent:
Mozilla/5.0 (X11; Linux x86_64; rv:66.0) Gecko/20100101 Firefox/66.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
Connection: keep-alive
Upgrade-Insecure-Requests: 1
HTTPS:
CONNECT example.com:443 HTTP/1.1
User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:66.0) Gecko/20100101 Firefox/66.0
Proxy-Connection: keep-alive
Connection: keep-alive
Host: example.com:443
I open a socket to the "Host:" from the above with the following code:
public void sendRequest() throws IOException{
Socket socket = new Socket(host, port);
//socket.getInputStream.read();
BufferedWriter out = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream(), "UTF8"));
BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
for(int i = 0; i < lines.size(); i++){
out.write(lines.get(i) + "\r\n");
}
out.flush();
outputReturn(in);
}
And I receive the reply like so:
public void outputReturn(BufferedReader in){
try{
System.out.println("\n * Response");
String line;
while ((line = in.readLine()) != null) {
System.out.println(line);
}
}
catch (IOException i){
System.out.println(i);
}
}
The replies come back as so:
HTTP:
* Response
HTTP/1.1 200 OK
Content-Encoding: gzip
Accept-Ranges: bytes
Cache-Control: max-age=604800
Content-Type: text/html; charset=UTF-8
Date: Wed, 10 Apr 2019 22:53:28 GMT
Etag: "1541025663+gzip"
Expires: Wed, 17 Apr 2019 22:53:28 GMT
Last-Modified: Fri, 09 Aug 2013 23:54:35 GMT
Server: ECS (ord/4C92)
Vary: Accept-Encoding
X-Cache: HIT
Content-Length: 606
;�R�TA��0
��W�ri]��S�V #���1k��Z��$�6���q۽���#+���l�I�I��s�PzUe���Bf
�'��+�>���+�OF �I4h��^#^
�ЧA�p#�M���u����������*
<�|ԅߎP���P�-�6�O��$}�Jl)ǰ_,�4yU�rQazw�r���t
.�s���3�
z�_������2�Mel
ϋ5����%�t
뫪R���t3
��:�|�Q��]���
V-z�|�Y3*���rKp�5th��"��C���NH����v��OOyޣ�xs�����V��$��X�6�BR�b�C��PqE���K�<� �G�כ7����E(17Vx2�US��
% x��)�d�����e��O&�4/䤘���~��Oi�s�X�dW�7��#�u�"��y\$]j<�L�r�˻'�ɪ�Vg?Kr {=��]E��^x;�ƱX
TU��]�[�{��s+�e����9�g���]����H�4���#�KA��'�Z�����*r�
�$�G� ��4�n�8���㊄+c���E�hA��X���������L��RIt�[4\����
HTTPS:
CONNECT getpocket.cdn.mozilla.net:443 HTTP/1.1
User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:66.0) Gecko/20100101 Firefox/66.0
Proxy-Connection: keep-alive
Connection: keep-alive
Host: getpocket.cdn.mozilla.net:443
* Response
java.net.SocketException: Connection reset
Questions:
Why do I receive what seems like binary from the HTTP request?
Why so I receive nothing from my HTTPS request?
What SHOULD I be doing instead?
Thanks in advance.
For your HTTP request, the Content-Encoding is gzip. The binary is the gzip-compressed data.
For your HTTPS request, you're not making an SSL/TLS handshake, so the server drops the connection.
For HTTP, I don't think you need to do anything, the browser should handle it for you. There's no feasible way to proxy an HTTPS/SSL/TLS using the method you described.
For testing I want to build HttpServletRequest object from some predefined data, something like:
GET / HTTP/1.1
User-Agent: Opera/9.80 (Windows NT 6.1; WOW64; U; en) Presto/2.10.289 Version/
12.01
Host: www.foo.com
Accept: text/html, application/xml;q=0.9, application/xhtml+xml, image/png,
image/webp, image/jpeg, image/gif, image/x-xbitmap;q=0.1
Accept-Language: ru-RU,ru;q=0.9,en;q=0.8
Accept-Encoding: gzip, deflate
Pragma: no-cache
Cache-Control: no-cache
Connection: Keep-Alive
And also setup url and client address. Is there some simple way to do it?
Kirill! I think the best way in your case is using Mockito framework.
For example, you can make mock of HttpServletRequest interface. And use:
HttpServletRequest httpRequest = Mockito.mock(HttpServletRequest.class);
Mockito.when(httpRequest.getHeader("Host")).thenReturn("http://www.foo.com");
Mockito.when(httpRequest.getHeader("Referer")).thenReturn("blalba");
Mockito.when(httpRequest.getHeader("User-Agent")).thenReturn("Opera");
Mockito.when(httpRequest.getRemoteAddr()).thenReturn("127.0.0.1");
You can write a parse to read the predefined data and use HttpClient to send requests as per your requirements.
HttpClient Tutorial
I have been tryig to handle a redirect(302) in java code and now that I am done doing it by my code. I ran into an other problem in which after login, on click on any link I get logged out. So I checked my TCP Stream through wireshark and found that there are few HeaderRequests missing. After implementation of my code, Http Header are as follows :
GET /index.php/ HTTP/1.1
Host: 10.28.161.31
User-Agent: Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.9.2.24) Gecko/20111109 CentOS/3.6-3.el5.centos Firefox/3.6.24
Cookie: PHPSESSID=d488eea5e85afc8ec526c1a749e7ab20; path=/
Referrer: http://10.28.161.31
Cookie: $Version=0; PHPSESSID=d488eea5e85afc8ec526c1a749e7ab20; $Path=/ ???
and original Http Headers are as follows :
GET / HTTP/1.1
Host: 10.28.161.31
User-Agent: Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.9.2.24) Gecko/20111109 CentOS/3.6-3.el5.centos Firefox/3.6.24
Referer: http://10.28.161.31/index.php
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
Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7
Keep-Alive: 115
Connection: keep-alive
Cookie: PHPSESSID=978ee1e3b3696743c5c8f507a2ec7212
According to my observation, I did not copied the Header's content properly and that's why it is logging out quickly. So my question is that, how can I copy the complete content of HttpMethod to another HttpMethod? If any one can provide a code snippet or an example/tutorial would be great or If any one can give me a heads up on where I am doing things wrong, that would be appreciable.
My implementation is right here :
private HttpMethod loadHttp302Request(HttpMethod method, HttpClient client,
int status, String urlString) throws HttpException, IOException {
if (status!=302)
return null;
String[] url = urlString.split("/");
HttpMethod theMethod = new GetMethod(urlString + method.getResponseHeader("Location").getValue());
theMethod.setRequestHeader("Cookie", method.getResponseHeader("Set-Cookie")
.getValue());
theMethod.setRequestHeader("Referrer",url[0]+"//"+url[2]);
int _status = client.executeMethod(theMethod);
return theMethod;
}
HttpClient can automatically handle the redirects if you set the strategy. Follow this post on usage example Httpclient 4, error 302. How to redirect?