Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Regression: Static JS files served as 'application/octet-stream' instead of 'application/javascript' [SPR-14368] #18940

Closed
spring-projects-issues opened this issue Jun 15, 2016 · 21 comments
Assignees
Milestone

Comments

@spring-projects-issues
Copy link
Collaborator

@spring-projects-issues spring-projects-issues commented Jun 15, 2016

Luis Lebolo opened SPR-14368 and commented

I upgraded from Spring 4.2.6 to 4.3.0 and now I'm receiving the following error in Chrome when my web page tries to load static javascript files.

Refused to execute script from http://.../someJsFile.js because its MIME type ('application/octet-stream') is not executable, and strict MIME type checking is enabled.

I double-checked the response header (using Spring 4.3.0) and I indeed see Content-Type:application/octet-stream. However, when I drop back down to Spring 4.2.6 I see Content-Type:application/javascript.

The files are included in my page like

<!DOCTYPE html>
<html lang="en">
<!-- ... -->
<body>
  <!-- ... -->
  <!-- Adding type="text/javascript" does not help -->
  <script src="/resources/js/someJsFile.js"></script>
</body>
</html>

and my config looks like

<!-- ... -->
<context:component-scan base-package="some.package.spec" />	
<mvc:resources mapping="/resources/**" location="/resources/" />
<mvc:annotation-driven />
<!-- ... -->

I tried looking at the Spring 4.3.0 release notes, but nothing immediately stood out (maybe #17493).

Any ideas what changes in 4.3.0 are affecting me? How do I tell Spring 4.3.0 to set the correct content type for static javascript files? Let me know if you need more details about configuration, etc. Unfortunately, I don't think I could package up the project - it's quite complex and lots of proprietary info.


Affects: 4.3 GA

Reference URL: http://stackoverflow.com/questions/37822460/upgraded-to-spring-4-3-0-and-static-js-files-are-now-served-as-application-octe

Issue Links:

  • #18233 ResourceHttpRequestHandler does not take into account mime types configured in WebMvcConfigurerAdapter

Referenced from: commits e38623d

0 votes, 5 watchers

@spring-projects-issues
Copy link
Collaborator Author

@spring-projects-issues spring-projects-issues commented Jun 16, 2016

Brian Clozel commented

Hello Luis Lebolo

This might be related to #18233, but I don't see why this is behaving like this.

Did you define a custom ContentNegotiationManager in your configuration or used a ContentNegotiationConfigurer to customize it?
What JVM / container are you using for this application?
Is the Java Activation Framework available in your JVM?

I've added a repro project for this and couldn't reproduce the problem with JDK8 on Tomcat 8.0 and Jetty 9.3. Could you try this repro project in your environment or adapt it to reproduce the issue?

Thanks

@spring-projects-issues
Copy link
Collaborator Author

@spring-projects-issues spring-projects-issues commented Jun 16, 2016

Rossen Stoyanchev commented

If it's not easy to provide a repro project, perhaps you can debug your application. See what happens in ResourceHttpRequestHandler#getMediaType. Comparing 4.2.6 and 4.3 will probably show the difference.

@spring-projects-issues
Copy link
Collaborator Author

@spring-projects-issues spring-projects-issues commented Jun 16, 2016

Luis Lebolo commented

Thanks for looking into this guys.

Brian, the only configuration I can think of around content negotiation is

<!-- ContentNegotiatingViewResolver delegates to other ViewResolvers based on application context/media type -->
<bean id="viewResolver" class="org.springframework.web.servlet.view.ContentNegotiatingViewResolver">
    <property name="viewResolvers">
        <list>
            <bean class="org.springframework.web.servlet.view.UrlBasedViewResolver">
                <property name="viewClass" value="org.springframework.web.servlet.view.JstlView" />
                <property name="prefix" value="/WEB-INF/jsp/" />
                <property name="suffix" value=".jsp" />
            </bean>
        </list>
    </property>
    <property name="defaultViews">
        <list>
            <bean class="org.springframework.web.servlet.view.json.MappingJackson2JsonView">
                <property name="prefixJson" value="true" />
            </bean>
        </list>
    </property>
</bean>

I'm using Tomcat 8.0.29 and Java 8 (jdk1.8.0_66). JAF is available. The only JVM settings I add when running Tomcat are -Xmx3g and -Xms1g.

I'll try to reproduce the issue in the repo you've created, but first I'll try to debug ResourceHttpRequestHandler#getMediaType as suggested by Rossen.

@spring-projects-issues
Copy link
Collaborator Author

@spring-projects-issues spring-projects-issues commented Jun 16, 2016

Rossen Stoyanchev commented

In 4.2.6 the media type for a resources was checked against the ServletContext#getMimeType and then as a fallback against JAF. In 4.3.0 we are delegating to the ServletPathExtensionContentNegotiationStrategy which seems to call super first (registered extensions and/or JAF) and then the ServletContext. That's probably something we need to address in any case but do tell us what you find out through debugging.

@spring-projects-issues
Copy link
Collaborator Author

@spring-projects-issues spring-projects-issues commented Jun 16, 2016

Luis Lebolo commented

I stepped through the debugger and the issue is definitely related to changes made in #18233. I tried configuring a custom content negotiating manager like this, but that didn't work.

<mvc:annotation-driven content-negotiation-manager="contentNegotiationManager" />

<bean id="contentNegotiationManager" class="org.springframework.web.accept.ContentNegotiationManagerFactoryBean">
    <property name="mediaTypes">
        <value>js=application/javascript</value>
    </property>
</bean>

!-- ContentNegotiatingViewResolver delegates to other ViewResolvers based on application context/media type-->
<bean id="viewResolver" class="org.springframework.web.servlet.view.ContentNegotiatingViewResolver">
    <property name="contentNegotiationManager" ref="contentNegotiationManager"/>
    <property name="viewResolvers">
        <list>
            <bean class="org.springframework.web.servlet.view.UrlBasedViewResolver">
                <property name="viewClass" value="org.springframework.web.servlet.view.JstlView" />
                <property name="prefix" value="/WEB-INF/jsp/" />
                <property name="suffix" value=".jsp" />
            </bean>
        </list>
    </property>
    <property name="defaultViews">
        <list>
            <bean class="org.springframework.web.servlet.view.json.MappingJackson2JsonView">
                <property name="prefixJson" value="true" />
            </bean>
        </list>
    </property>
</bean>

For completeness (excuse the verbosity :D), I looked at [ResourceHttpRequestHandler#getMediaType](https://github.com/spring-projects/spring-framework/blob/v4.3.0.RELEASE/spring-webmvc/src/main/java/org/springframework/web/servlet/resource/ResourceHttpRequestHandler.java#L517) for v4.3.0.RELEASE during a static resource request for a javascript file.

I get all the way to line 530 with mediaType == null (PathExtensionContentNegotiationStrategy.getMediaTypeForResource(resource) == null). Then the (default?) content negotiation manager returns an empty list of media types (getContentNegotiationManager().resolveMediaTypes(webRequest) == []). So the final return value is null.

If I step down further into [PathExtensionContentNegotiationStrategy](https://github.com/spring-projects/spring-framework/blob/v4.3.0.RELEASE/spring-web/src/main/java/org/springframework/web/accept/PathExtensionContentNegotiationStrategy.java#L147), getMediaTypeForResource() calls lookupMediaType(".js".) which returns null because this.mediaTypes is empty. Then JafMediaTypeFactory.getMediaType(filename) is called which returns an application/octet-stream media type, that ultimately gets set to null in the subsequent if branch and returned.

If I step down further into [ContentNegotiationManager](https://github.com/spring-projects/spring-framework/blob/v4.3.0.RELEASE/spring-web/src/main/java/org/springframework/web/accept/ContentNegotiationManager.java#L121), resovleMediaTypes() loops through the (default?) strategies. PathExtensionContentNegotiationStrategy ultimately returns an empty list of media types, presumably due to the same logic as above. Then the HeaderContentNegotiationStrategy returns * / * (MEDIA_TYPE_ALL) which is skipped in the subsequent if branch. So an empty list of media types is ultimately returned.

@spring-projects-issues
Copy link
Collaborator Author

@spring-projects-issues spring-projects-issues commented Jun 16, 2016

Luis Lebolo commented

In [ResourceHttpRequestHandler#getMediaType](https://github.com/spring-projects/spring-framework/blob/v4.2.6.RELEASE/spring-webmvc/src/main/java/org/springframework/web/servlet/resource/ResourceHttpRequestHandler.java#L391) for v4.2.6.RELEASE, getServletContext().getMimeType(resource.getFilename()) returns application/javascript, which causes MediaType.parseMediaType(mimeType) to also return a application/javascript meadia type (i.e. the subsequent JAF branch is never entered).

@spring-projects-issues
Copy link
Collaborator Author

@spring-projects-issues spring-projects-issues commented Jun 16, 2016

Rossen Stoyanchev commented

If I step down further into PathExtensionContentNegotiationStrategy

What's the actual instance? It should be ServletPathExtensionContentNegotiationStrategy which calls super first in getMetdiaTypeForResource and then servletContext.getMimeType(..), i.e. the same as in 4.2.6. Somehow that must not be the actual instance type or else it shouldn't fall through to the ContentNegotiationManager. This is set up in ContentNegotiationManagerFactoryBean, you can check what happens there.

I'm also surprised that setting up a mapping for "js" does not work. Any idea what happens in those same steps?

I'm starting to suspect something about the URL that's throwing off perhaps the determination of the extension?

@spring-projects-issues
Copy link
Collaborator Author

@spring-projects-issues spring-projects-issues commented Jun 19, 2016

Luis Lebolo commented

I'll be away for a few days, but will check on this at the end of the week.

@spring-projects-issues
Copy link
Collaborator Author

@spring-projects-issues spring-projects-issues commented Jun 20, 2016

Rossen Stoyanchev commented

I'm actually awaiting feedback from you (see my last comment).

@spring-projects-issues
Copy link
Collaborator Author

@spring-projects-issues spring-projects-issues commented Jun 27, 2016

Luis Lebolo commented

I'm back and able to devote some time. The actual instance is PathExtensionContentNegotiationStrategy. In ContentNegotiationManagerFactoryBean, this.servletContext == null so strategy gets instantiated as a PathExtensionContentNegotiationStrategy.

This is using the configuration I mentioned here.

@spring-projects-issues
Copy link
Collaborator Author

@spring-projects-issues spring-projects-issues commented Jun 27, 2016

Rossen Stoyanchev commented

Okay thanks I see the issue. I'll have a snapshot for you to try later today.

@spring-projects-issues
Copy link
Collaborator Author

@spring-projects-issues spring-projects-issues commented Jun 27, 2016

Rossen Stoyanchev commented

There is a fix in place that should address the issue. When the current build finishes please give it a try with a 4.3.1 snapshot and thanks!

@spring-projects-issues
Copy link
Collaborator Author

@spring-projects-issues spring-projects-issues commented Jun 27, 2016

Luis Lebolo commented

Sorry, I'm not too familiar with the Spring build system. Can you point me to the status of the current build? And if it's not too much trouble (I can Google around), how would I use the latest snapshot? I'm using Gradle to get Spring from mavenCentral, e.g.

apply plugin: 'java'
apply plugin: 'war'

repositories {
    mavenCentral()
}

dependencies {
    compile 'org.springframework:spring-web:4.2.+'
    // ...
}
@spring-projects-issues
Copy link
Collaborator Author

@spring-projects-issues spring-projects-issues commented Jun 27, 2016

Rossen Stoyanchev commented

The build is done. You need repo.spring.io/snapshot/ and version 4.3.1.BUILD-SNAPSHOT.

@spring-projects-issues
Copy link
Collaborator Author

@spring-projects-issues spring-projects-issues commented Jun 27, 2016

Luis Lebolo commented

Ok, things are back to normal with 4.3.1.BUILD-SNAPSHOT (i.e. javascript files have Content-Type:application/javascript). Thanks for the timely solution!

@spring-projects-issues
Copy link
Collaborator Author

@spring-projects-issues spring-projects-issues commented Sep 15, 2016

Steve commented

I am using Spring mvc 4.3.2 and Spring Security 4.1.3 and am still experiencing the same issue. All static js resource are being served as 'application/octet-stream'.

@spring-projects-issues
Copy link
Collaborator Author

@spring-projects-issues spring-projects-issues commented Sep 15, 2016

Steve commented

Previous comment, that is with an webapp with @EnableWebMvc. I have another spring app, same version but without EnableWebMvc and it is serving static js resources fine.

@spring-projects-issues
Copy link
Collaborator Author

@spring-projects-issues spring-projects-issues commented Sep 15, 2016

Brian Clozel commented

An issue related to that, #19146, has been fixed and will be released with 4.3.3. In the meantime, can you test your application with the 4.3.3.BUILD-SNAPSHOT version?

If you can still reproduce the problem with 4.3.3 snapshot, please open a new issue with a small repro project so we can investigate.

Thanks!

@spring-projects-issues
Copy link
Collaborator Author

@spring-projects-issues spring-projects-issues commented Oct 5, 2016

Steve commented

I can confirm that 4.3.3 fixes the issue and static js files are now served correctly.

@mffonseca
Copy link

@mffonseca mffonseca commented Feb 10, 2019

@spring-issuemaster I'm new with spring and I have the same problem. Could you give an example of how pom.xml should look?

@bclozel
Copy link
Member

@bclozel bclozel commented Feb 10, 2019

@mffonseca your pom.xml should look like a project generated from start.spring.io. If you need help with a problem in your application, you can ask a question on StackOverflow.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Linked pull requests

Successfully merging a pull request may close this issue.

None yet
4 participants