You are viewing a plain text version of this content. The canonical link for it is here.
Posted to users@tomcat.apache.org by Ryan Yohnk <ry...@jamf.com> on 2017/02/20 15:38:50 UTC

"mime-mapping" and Content-Type

Hello everyone,

  I’ve come across a problem for which the “mime-mapping” element would be a good solution. Specifically I have a web application who’s source I can’t change, it’s not returning a specific Content-Type header and I’d like to start utilizing compression based on the mime-type.

  Durning my investigation I created a trivial web app for testing but was unable to get the mime-type specified in the mime-mapping applied to requests sent to the specific extension. This was with Tomcat 8.0.33. The details can be found below or at the stack overflow post here: http://stackoverflow.com/questions/42261607/tomcat-8-0-mime-mapping-content-type.

  As noted in the SO post, I can see that StandardContext:addMimeMapping() is being called with my specific mapping during initialization. But I’m never seeing the backing mimeMappings called from there.

  I’ve seen quite a few online posts on this topic but can’t seem find any official documentation for 8+. Is this feature something that’s still supported? If so, is there something I’m overlooking in my test or configuration?

  Any light you guys can shine on the subject would be greatly appreciated.

Thanks!
Ryan



Servlet:

public class SimpleServlet extends HttpServlet {
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        IOUtils.write("Hello There!", resp.getOutputStream());
        resp.setStatus(202);
    }
} 

web.xml:

<web-app
        version="3.0"
        xmlns="http://java.sun.com/xml/ns/javaee"
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd">

  <servlet>
    <servlet-name>SimpleServlet</servlet-name>
    <servlet-class>com.jamf.swa.SimpleServlet</servlet-class>
  </servlet>

  <servlet-mapping>
    <servlet-name>SimpleServlet</servlet-name>
    <url-pattern>*.swa</url-pattern>
  </servlet-mapping>

  <mime-mapping>
    <extension>swa</extension>
    <mime-type>text/rtf;charset=UTF-8</mime-type>
  </mime-mapping>

</web-app>

cURL request:

curl --trace-ascii - http://localhost:8080/testing.swa
== Info:   Trying ::1...
== Info: TCP_NODELAY set
== Info: Connected to localhost (::1) port 8080 (#0)
=> Send header, 89 bytes (0x59)
0000: GET /testing.swa HTTP/1.1
001b: Host: localhost:8080
0031: User-Agent: curl/7.51.0
004a: Accept: *
/*
0057: 
<= Recv header, 23 bytes (0x17)
0000: HTTP/1.1 202 Accepted
<= Recv header, 27 bytes (0x1b)
0000: Server: Apache-Coyote/1.1
<= Recv header, 20 bytes (0x14)
0000: Content-Length: 12
<= Recv header, 37 bytes (0x25)
0000: Date: Wed, 15 Feb 2017 22:37:17 GMT
<= Recv header, 2 bytes (0x2)
0000: 
<= Recv data, 12 bytes (0xc)
0000: Hello There!
Hello There!== Info: Curl_http_done: called premature == 0
== Info: Connection #0 to host localhost left intact
  
---------------------------------------------------------------------
To unsubscribe, e-mail: users-unsubscribe@tomcat.apache.org
For additional commands, e-mail: users-help@tomcat.apache.org


Re: "mime-mapping" and Content-Type

Posted by Christopher Schultz <ch...@christopherschultz.net>.
-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA256

Ryan,

On 2/27/17 9:50 AM, Ryan Yohnk wrote:
> I wasn\u2019t aware there was a servlet in-between simple requests like 
> you stated. But that makes perfect sense.

Something has to serve the bytes. In a Java web application server,
that's called the DefaultServlet.

> As noted in the SO post, I can see that 
> StandardContext:addMimeMapping() is being called with my specific 
> mapping during initialization. But I\u2019m never seeing the backing 
> mimeMappings called from there.

Right: because you are never consulting that mapping.

> I\u2019ve seen quite a few online posts on this topic but can\u2019t seem 
> find any official documentation for 8+. Is this feature something 
> that\u2019s still supported? If so, is there something I\u2019m overlooking 
> in my test or configuration?

I think you are misunderstanding what's going on entirely.

> Any light you guys can shine on the subject would be greatly 
> appreciated.

If you have a file on the disk called foo.swa, and you request it
using http://example.com/myapp/foo.swa and the DefaultServlet serves
the bytes off the disk, then the DefaultServlet will use the .swa
extension plus your mime-mapping to produce the "Content-Type:
text/rtf;charset=UTF-8" response header.

In your situation, your servlet is handling the request, and the
DefaultServlet isn't involved. Tomcat doesn't magically add response
headers based upon the URLs used to choose the servlet to serve the
bytes. Your own servlet is responsible for setting whatever response
headers it wants to use.

Tomcat will automatically add the following headers:

- - Date
- - Content-Encoding: chunked (if the response is committed and not yet
complete)
- - Content-Length (if not chunked)


... but nothing else. If you want a Content-Type header, you'll have
to add it yourself.

Here's your code:

> Servlet:
> 
> public class SimpleServlet extends HttpServlet { protected void
> doGet(HttpServletRequest req, HttpServletResponse resp) throws
> ServletException, IOException { IOUtils.write("Hello There!",
> resp.getOutputStream()); resp.setStatus(202); } }

You aren't writing any Content-Type header, so you aren't getting one.
If you want to add a Content-Type header, just do it:

public class SimpleServlet extends HttpServlet {
  protected void doGet(HttpServletRequest req,
                       HttpServletResponse resp)
    throws ServletException, IOException {
    IOUtils.write("Hello There!", resp.getOutputStream());
    resp.setContentType("text/plain");
    resp.setStatus(202);
  }
}

Or, if you want to detect the correct MIME type from the URL, you
could do this:

  ServletContext app = req.getServletContext();
  String mimeType = app.getMimeType(req.getRequestURI());
  resp.setContentType(mimeType);

>> You said you don't want to modify the source... what about
>> *adding* to it? Would it be okay to write a Filter and add it to
>> the configuration of the application? That is a very easy thing
>> to do, and you can add whatever headers you want for whatever
>> reason.
> 
> Yep, a filter will be the next step. Honestly that\u2019s the behavior 
> I\u2019m describing anyway. My initial hope was to keep the changes 
> limited to Tomcat configuration but if that\u2019s not possible that\u2019s 
> cool.
> 
> Since it seems like a pretty common filter, is anyone aware of an 
> existing implementation? I know it\u2019s pretty trivial but no sense
> in rewriting the wheel if it\u2019s already out there.

I'm not sure it's that common of a request. Usually the servlet knows
the type of data it returns, and sets the content-type accordingly. I
haven't seen many servlets that sometimes serve PDFs and sometimes
server plain-text responses, and can only tell the difference when the
request URL has a particular filename-looking-thing in it that has a
recognizable "file extension" (which is just a convention, of course).

If you wanted to write a filter that could do this kind of thing, it
would be only a few lines long:

public class MimeTypeFromURIFilter
    implements Filter {
  // ignoring init() and destroy() methods

  public void invoke(ServletRequest request,
                     ServletResponse response,
                     FilterChain chain)
    throws ServletException {

    // Don't clobber any existing content-type
    if(null == response.getContentType()) {
      ServletContext app = req.getServletContext();
      String mimeType = app.getMimeType(req.getRequestURI());
      response.setContentType(mimeType);
    }

    // You could also put this before the Content-Type check,
    // but it's possible that the response could be committed
    // by the filter chain (or servlet) and then the Content-Type
    // header wouldn't be included in the response.
    chain.doFilter(request, response);
  }
}

Hope that helps,
- -chris
-----BEGIN PGP SIGNATURE-----
Comment: GPGTools - http://gpgtools.org
Comment: Using GnuPG with Thunderbird - http://www.enigmail.net/

iQIcBAEBCAAGBQJYvZrBAAoJEBzwKT+lPKRYvroP/2kAnMDVRzWKKq94ovIYz5Nc
U5mnHQ2p4D3a2x4hxlfCiYDhOiwbSGK6GRLoD8fDVUnEJdux+XRvA8laAdMAcPV8
6BbvpqdqYSDzTkgzBM99LJDiaoGTef5nHUvz7XyS8Wvp0JVDz22fcDGqEdjvL/yd
/doLczuUGcqOkjrxqTpTVm5OYKF+wvrMJbPKt9zgtdDhEbIGe0rWY8Dl7ku+PHJq
SGTopaxwFE7JUGqVUcFNDtxf2ouF7R7T3FJ+dGJb93CzAcdL18o5z6qoLzxg3Ph6
EsL6mGnRIpJOBI0ZOuHFpGg4euXR8paXjinUktOaIWmv75vBCebyrAkN50CyVLmn
fN8zz64VT+zdK6UXN1k7h8/ZZopubZAcW/Gx9qDVbqqX4b6kaY1X1+zsJKOC4/db
IvXCNIB1UkPcx2warhkmpG+aaH95I7hv2JQJejqUqMjyWfBSnk6hwLyhJMqqtxUw
1FXQL+J90hzvbmIbt3OUAsrccgaXgNs9NEHLWII2y4Igjtd+ERjCN3IIDFQyMl/P
tNQaVc655dMu3B7b/8GaE8MnNBBjOau6bYDh4F7YC2BqBwTEl/RXpoluTOrMOEmA
9N/JF1a35aXSo+3YDQB09qeZbL6ptNNBH2KyiPy0Q4JJ4bo92NI1WXcez0FcJLN2
Y/KdjbOfiOOHv7fOGXAd
=k9bv
-----END PGP SIGNATURE-----

---------------------------------------------------------------------
To unsubscribe, e-mail: users-unsubscribe@tomcat.apache.org
For additional commands, e-mail: users-help@tomcat.apache.org


Re: "mime-mapping" and Content-Type

Posted by Ryan Yohnk <ry...@jamf.com>.
Chris,

On Feb 24, 2017, at 11:12 AM, Christopher Schultz <ch...@christopherschultz.net>> wrote:

-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA256

Ryan,

On 2/20/17 10:38 AM, Ryan Yohnk wrote:
I’ve come across a problem for which the “mime-mapping” element
would be a good solution. Specifically I have a web application
who’s source I can’t change, it’s not returning a specific
Content-Type header and I’d like to start utilizing compression
based on the mime-type.

Durning my investigation I created a trivial web app for testing
but was unable to get the mime-type specified in the mime-mapping
applied to requests sent to the specific extension. This was with
Tomcat 8.0.33. The details can be found below or at the stack
overflow post here:
http://stackoverflow.com/questions/42261607/tomcat-8-0-mime-mapping-co
ntent-type.

Just

so you know, the mime-mapping only applies to resources served by
the DefaultServlet. If the application is accepting a request to e.g.
/my-file.txt, then the content-type isn't automatically being set to
"text/plain" by Tomcat... it's up to the servlet to do that.

The Mime-Mappings are available to servlets, but it's pretty rare for
a custom servlet to bother actually using them.

I wasn’t aware there was a servlet in-between simple requests like you stated. But that makes perfect sense.


As noted in the SO post, I can see that
StandardContext:addMimeMapping() is being called with my specific
mapping during initialization. But I’m never seeing the backing
mimeMappings called from there.

I’ve seen quite a few online posts on this topic but can’t seem
find any official documentation for 8+. Is this feature something
that’s still supported? If so, is there something I’m overlooking
in my test or configuration?

Any light you guys can shine on the subject would be greatly
appreciated.

Thanks! Ryan



Servlet:

public class SimpleServlet extends HttpServlet { protected void
doGet(HttpServletRequest req, HttpServletResponse resp) throws
ServletException, IOException { IOUtils.write("Hello There!",
resp.getOutputStream()); resp.setStatus(202); } }

web.xml:

<web-app version="3.0" xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd">

<servlet> <servlet-name>SimpleServlet</servlet-name>
<servlet-class>com.jamf.swa.SimpleServlet</servlet-class>
</servlet>

<servlet-mapping> <servlet-name>SimpleServlet</servlet-name>
<url-pattern>*.swa</url-pattern> </servlet-mapping>

<mime-mapping> <extension>swa</extension>
<mime-type>text/rtf;charset=UTF-8</mime-type> </mime-mapping>

</web-app>

cURL request:

curl --trace-ascii - http://localhost:8080/testing.swa == Info:
Trying ::1... == Info: TCP_NODELAY set == Info: Connected to
localhost (::1) port 8080 (#0) => Send header, 89 bytes (0x59)
0000: GET /testing.swa HTTP/1.1 001b: Host: localhost:8080 0031:
User-Agent: curl/7.51.0 004a: Accept: * /* 0057: <= Recv header,
23 bytes (0x17) 0000: HTTP/1.1 202 Accepted <= Recv header, 27
bytes (0x1b) 0000: Server: Apache-Coyote/1.1 <= Recv header, 20
bytes (0x14) 0000: Content-Length: 12 <= Recv header, 37 bytes
(0x25) 0000: Date: Wed, 15 Feb 2017 22:37:17 GMT <= Recv header, 2
bytes (0x2) 0000: <= Recv data, 12 bytes (0xc) 0000: Hello There!
Hello There!== Info: Curl_http_done: called premature == 0 == Info:
Connection #0 to host localhost left intact

Yup: you are making a request to a custom servlet that doesn't do
anything with the MIME mappings.

You said you don't want to modify the source... what about *adding* to
it? Would it be okay to write a Filter and add it to the configuration
of the application? That is a very easy thing to do, and you can add
whatever headers you want for whatever reason.

Yep, a filter will be the next step. Honestly that’s the behavior I’m describing anyway. My initial hope was to keep the changes limited to Tomcat configuration but if that’s not possible that’s cool.

Since it seems like a pretty common filter, is anyone aware of an existing implementation? I know it’s pretty trivial but no sense in rewriting the wheel if it’s already out there.

Thanks!
Ryan


- -chris
-----BEGIN PGP SIGNATURE-----
Comment: GPGTools - http://gpgtools.org<http://gpgtools.org/>
Comment: Using GnuPG with Thunderbird - http://www.enigmail.net/

iQIcBAEBCAAGBQJYsGl1AAoJEBzwKT+lPKRYCkwP/i1lBjt3v6zsdYMWafdCNoTj
cIlYc3P6AAafDED7/Sf/8H3RQ1uOrp9n0DuM6hnjrh55ptv/VoAGDY3836ONSQ8S
ldWDJOipeTFW2byOeWc9fjT9+AJJ0B/3BidjUFgmljsyCw+f71ZYvHt2ECXNoXOO
T1nQG/OqqTnRZ54UZ1/d/PyZJSbEw1YHmS3f5DFfhtDHjgOS2bBsuQvSvX2XCUjK
lEcdCTbP1XaIU2jMIlRLF///i1Ytz2OsS12byt+tnotRC0MIVr1ST8Je6yvgaBLw
JHnStDdSJW4yFiy9aW8L54qChmdr1KCybavsnEHJKKgc7R5n+2qY2wDm4RwXl8b3
Aqyc9A5ELGhL/xn+kf3w4sC41yEAUXitYJyNkg33o69XoV+nxLfmuWTEqANwh5K+
RRsDQXTnnNZx9fewHpg2+/OnWUkLxaCtqfInU907c7AyXnuJ1jhWD9tBMXFy1SBA
jCQfj7U6hL/LsjQRPdpl0I0qpQ/KrxuCdBLCWwl28xwdXu21enlCV6ZvgHe3z6Vc
HVTc3dB/QbFNHJ9Qm1tbemOPTfR8rr2rycu3dcEXNlmwAwZ3yPASQGPnILZnxDyD
q1VmitMK3vfvoErXfMJ8yrPluQXRMus3f6Guu5k3gIYA/y9a+FUmUZ3pMPaTl69M
wLc5oAFEfPZcqfIdZlRd
=TfdZ
-----END PGP SIGNATURE-----

---------------------------------------------------------------------
To unsubscribe, e-mail: users-unsubscribe@tomcat.apache.org<ma...@tomcat.apache.org>
For additional commands, e-mail: users-help@tomcat.apache.org<ma...@tomcat.apache.org>


Re: "mime-mapping" and Content-Type

Posted by Christopher Schultz <ch...@christopherschultz.net>.
-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA256

Ryan,

On 2/20/17 10:38 AM, Ryan Yohnk wrote:
> I\u2019ve come across a problem for which the \u201cmime-mapping\u201d element
> would be a good solution. Specifically I have a web application
> who\u2019s source I can\u2019t change, it\u2019s not returning a specific
> Content-Type header and I\u2019d like to start utilizing compression
> based on the mime-type.
> 
> Durning my investigation I created a trivial web app for testing
> but was unable to get the mime-type specified in the mime-mapping
> applied to requests sent to the specific extension. This was with
> Tomcat 8.0.33. The details can be found below or at the stack
> overflow post here: 
> http://stackoverflow.com/questions/42261607/tomcat-8-0-mime-mapping-co
ntent-type.

Just
> 
so you know, the mime-mapping only applies to resources served by
the DefaultServlet. If the application is accepting a request to e.g.
/my-file.txt, then the content-type isn't automatically being set to
"text/plain" by Tomcat... it's up to the servlet to do that.

The Mime-Mappings are available to servlets, but it's pretty rare for
a custom servlet to bother actually using them.

> As noted in the SO post, I can see that 
> StandardContext:addMimeMapping() is being called with my specific 
> mapping during initialization. But I\u2019m never seeing the backing 
> mimeMappings called from there.
> 
> I\u2019ve seen quite a few online posts on this topic but can\u2019t seem
> find any official documentation for 8+. Is this feature something
> that\u2019s still supported? If so, is there something I\u2019m overlooking
> in my test or configuration?
> 
> Any light you guys can shine on the subject would be greatly 
> appreciated.
> 
> Thanks! Ryan
> 
> 
> 
> Servlet:
> 
> public class SimpleServlet extends HttpServlet { protected void 
> doGet(HttpServletRequest req, HttpServletResponse resp) throws 
> ServletException, IOException { IOUtils.write("Hello There!", 
> resp.getOutputStream()); resp.setStatus(202); } }
> 
> web.xml:
> 
> <web-app version="3.0" xmlns="http://java.sun.com/xml/ns/javaee" 
> xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
> xsi:schemaLocation="http://java.sun.com/xml/ns/javaee 
> http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd">
> 
> <servlet> <servlet-name>SimpleServlet</servlet-name> 
> <servlet-class>com.jamf.swa.SimpleServlet</servlet-class>
> </servlet>
> 
> <servlet-mapping> <servlet-name>SimpleServlet</servlet-name> 
> <url-pattern>*.swa</url-pattern> </servlet-mapping>
> 
> <mime-mapping> <extension>swa</extension> 
> <mime-type>text/rtf;charset=UTF-8</mime-type> </mime-mapping>
> 
> </web-app>
> 
> cURL request:
> 
> curl --trace-ascii - http://localhost:8080/testing.swa == Info: 
> Trying ::1... == Info: TCP_NODELAY set == Info: Connected to 
> localhost (::1) port 8080 (#0) => Send header, 89 bytes (0x59)
> 0000: GET /testing.swa HTTP/1.1 001b: Host: localhost:8080 0031: 
> User-Agent: curl/7.51.0 004a: Accept: * /* 0057: <= Recv header,
> 23 bytes (0x17) 0000: HTTP/1.1 202 Accepted <= Recv header, 27
> bytes (0x1b) 0000: Server: Apache-Coyote/1.1 <= Recv header, 20
> bytes (0x14) 0000: Content-Length: 12 <= Recv header, 37 bytes
> (0x25) 0000: Date: Wed, 15 Feb 2017 22:37:17 GMT <= Recv header, 2
> bytes (0x2) 0000: <= Recv data, 12 bytes (0xc) 0000: Hello There!
> Hello There!== Info: Curl_http_done: called premature == 0 == Info:
> Connection #0 to host localhost left intact

Yup: you are making a request to a custom servlet that doesn't do
anything with the MIME mappings.

You said you don't want to modify the source... what about *adding* to
it? Would it be okay to write a Filter and add it to the configuration
of the application? That is a very easy thing to do, and you can add
whatever headers you want for whatever reason.

- -chris
-----BEGIN PGP SIGNATURE-----
Comment: GPGTools - http://gpgtools.org
Comment: Using GnuPG with Thunderbird - http://www.enigmail.net/

iQIcBAEBCAAGBQJYsGl1AAoJEBzwKT+lPKRYCkwP/i1lBjt3v6zsdYMWafdCNoTj
cIlYc3P6AAafDED7/Sf/8H3RQ1uOrp9n0DuM6hnjrh55ptv/VoAGDY3836ONSQ8S
ldWDJOipeTFW2byOeWc9fjT9+AJJ0B/3BidjUFgmljsyCw+f71ZYvHt2ECXNoXOO
T1nQG/OqqTnRZ54UZ1/d/PyZJSbEw1YHmS3f5DFfhtDHjgOS2bBsuQvSvX2XCUjK
lEcdCTbP1XaIU2jMIlRLF///i1Ytz2OsS12byt+tnotRC0MIVr1ST8Je6yvgaBLw
JHnStDdSJW4yFiy9aW8L54qChmdr1KCybavsnEHJKKgc7R5n+2qY2wDm4RwXl8b3
Aqyc9A5ELGhL/xn+kf3w4sC41yEAUXitYJyNkg33o69XoV+nxLfmuWTEqANwh5K+
RRsDQXTnnNZx9fewHpg2+/OnWUkLxaCtqfInU907c7AyXnuJ1jhWD9tBMXFy1SBA
jCQfj7U6hL/LsjQRPdpl0I0qpQ/KrxuCdBLCWwl28xwdXu21enlCV6ZvgHe3z6Vc
HVTc3dB/QbFNHJ9Qm1tbemOPTfR8rr2rycu3dcEXNlmwAwZ3yPASQGPnILZnxDyD
q1VmitMK3vfvoErXfMJ8yrPluQXRMus3f6Guu5k3gIYA/y9a+FUmUZ3pMPaTl69M
wLc5oAFEfPZcqfIdZlRd
=TfdZ
-----END PGP SIGNATURE-----

---------------------------------------------------------------------
To unsubscribe, e-mail: users-unsubscribe@tomcat.apache.org
For additional commands, e-mail: users-help@tomcat.apache.org