2

I was following this answer by BalusC to try and upload a file to the server. I am using his code as-is.

When using JSF 2.2, the #{bean.save} was never reached, and the file was never saved.

The server's console showed nothing. But the js console showed this error:

Refused to display 'http://localhost:8080/my_app/hello.xhtml' in a frame because it set 'X-Frame-Options' to 'deny'.
jsf.js.xhtml?ln=javax.faces:1 Uncaught DOMException: Blocked a frame with origin "http://localhost:8080" from accessing a cross-origin frame.
    at FrameTransport.callback (http://localhost:8080/my_app/javax.faces.resource/jsf.js.xhtml?ln=javax.faces:1:5109)
    at HTMLIFrameElement.<anonymous> (http://localhost:8080/my_app/javax.faces.resource/jsf.js.xhtml?ln=javax.faces:1:5759)

I saw this answer which suggested it was a bug in JSF 2.2. So I uploaded to 2.3.

With JSF 2.3 the #{bean.save} is reached, and the file is successfully saved. But the js error remains, and I can't upload a second file.

Any ideas?


EDIT in case it helps: I don't know why, but after selecting the file to upload in the dialog, an <iframe> is added to my page somehow.


EDIT 2

BalusC and Selaron suggested I try to change the X-Frame-Options header to not 'DENY'. I tried adding a @WebFilter and setting the header there, like this:

public void doFilter(...) 
{ 
    HttpServletResponse response = (HttpServletResponse) res; 
    response.addHeader("X-Frame-Options", "sameorigin"); 
    response.setHeader("MyHeader", "whatever"); 
    chain.doFilter(req, res); 
}

I added a second header MyHeader with value "whatever" to check if the response contained that header when getting to the browser.

Turns out MyHeader gets to the browser correctly, but X-Frame-Options still remains as 'DENY'.


As I'm using Spring Security, I figured maybe there was some other filter messing with my response?

So, I have this:

@Configuration
@EnableWebSecurity
public class BasicConfiguration extends WebSecurityConfigurerAdapter {

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        ...
        http.addFilterAfter(
            new CustomFilter(), SwitchUserFilter.class);    
        ...
    }
}

My CustomFilter works as the previous one I showed: MyHeader remains, but X-Frame-Options does not.

I added it after SwitchUserFilter because the doc for HttpSecurity.addFilter says that is the last filter in the chain.

I am a bit lost now. My couple of questions:

  1. Am I right to assume the X-Frame-Options header is getting overwritten by some other filter?

  2. How could I ensure the X-Frame-Options I set remains? Or, how can I put my filter at the end of the chain?

Kukeltje
  • 12,223
  • 4
  • 24
  • 47
onzinsky
  • 541
  • 1
  • 6
  • 21
  • 1
    The error suggests that your app or server returns `X-Frame-Options:deny` response header. Is this true? Turn off it and retry. Ajax based file uploads can in older browsers only take place via an iframe. – BalusC Feb 06 '20 at 07:20
  • Hi @BalusC. I am having some trouble with setting the header. I am updating my question – onzinsky Feb 07 '20 at 00:09
  • 2
    Effectively, on the technical level, you have a new question. 1: Not per say, can also be a reverse proxy, loadbalancer or such. 2: by using the mechanisms available for this described in other existing Q/A in Stackoverflow – Kukeltje Feb 07 '20 at 06:51
  • 1
    2: first part: by checking if other systems override this (can even be a browser plugin) – Kukeltje Feb 07 '20 at 07:18
  • And if the filters do not work, see https://stackoverflow.com/questions/27358966/how-to-set-x-frame-options-on-iframe for 'proxy' things – Kukeltje Feb 07 '20 at 08:10
  • As you use Spring Security you might adjust the header this way: https://stackoverflow.com/questions/28647136/how-to-disable-x-frame-options-response-header-in-spring-security – Selaron Feb 20 '20 at 13:46

1 Answers1

3

I found this issue where the Mojarra team planned to Implement "ajax" file upload #2577 and the commit actually implementing it to the jsf javascript. Madly the documentation on issue 2577 are not accessible anymore and thus it does not explain the background on why an iframe is needed here.

The first passage of this blog gives a brief explanation on why AJAX file upload is/was(?) not possible directly:

Ajax Style File Uploading using Hidden iFrame by Viral Patel · November 18, 2008

File uploading using AJAX is not possible. AJAX doesn’t actually post forms to the server, it sends selected data to the server in the form of a POST or GET request. As javascript is not capable of grabbing the file from the users machine and sending it to the server, it’s just not possible with AJAX. You have to resort to regular old form submit. If you have read/seen it somewhere, then it is not through AJAX. File uploading occurs through an iframe in this case. You have to use a iframe to upload the files. So, you can use iframe to asynchronous upload (Like AJAX , but its not AJAX).

So finally your options are to either - as BalusC commented - relax your X-Frame-Options header setting or to change your upload to not use AJAX:

<h:form enctype="multipart/form-data">
    <h:inputFile value="#{bean.file}" />
    <h:commandButton value="upload" action="#{bean.save}"/>
</h:form>
Selaron
  • 6,105
  • 4
  • 31
  • 39
  • your solution without ajax works. I will keep trying the ajax way for a little, and if nothing works I will accept the answer – onzinsky Feb 07 '20 at 00:05