Uploaded image for project: 'JBoss Web'
  1. JBoss Web
  2. JBWEB-266

Cookie Processing of JSON Cookie destroys Cookie Header

    Details

    • Type: Bug
    • Status: Open (View Workflow)
    • Priority: Major
    • Resolution: Unresolved
    • Affects Version/s: JBossWeb-7.0.1.GA
    • Fix Version/s: None
    • Component/s: Tomcat
    • Labels:
      None
    • Steps to Reproduce:
      Hide

      Use the following servlet:

      protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws IOException {
      	resp.setContentType("text/plain");
      	resp.setCharacterEncoding("UTF-8");
      	Enumeration<String> headers = req.getHeaderNames();
      	while (headers.hasMoreElements()) {
      		String header = headers.nextElement();
      		if (header.equals("cookie")
      			resp.getWriter().write(header + ": " + req.getHeader(header) + '\n');
      	}
      	Cookie[] cookies = req.getCookies();
      	if (cookies != null)
      		for (Cookie cookie : cookies)
      			resp.getWriter().write(cookie.getName() + ": " + cookie.getValue() + '\n');
      	resp.setStatus(HttpServletResponse.SC_OK);
      }
      

      together with the following curl script

      URL="http://localhost:8080/"
      COOKIES="JSON_COOKIE=\"{\\\"name\\\":\\\"value\\\"}\""
      curl -i "${URL}" -H "Cookie: $COOKIES"
      

      As you can see this will send a cookie

      JSON_COOKIE="{\"name\":\"value\"}"
      

      to the server and the servlet simply echos the values of the cookie header as well as the processed cookies.

      The output is

      [curl HTTP header output]
      
      cookie: JSON_COOKIE="{"name":"value"}e\"}"
      JSON_COOKIE: {"name":"value"}
      

      but expected is

      [curl HTTP header output]
      
      cookie: JSON_COOKIE="{\"name\":\"value\"}"
      JSON_COOKIE: {"name":"value"}
      

      Here you see that in the current output the value for the header has also been unescaped but as the index for start and end have not been modified it is trailed by characters from the escaped header string between the unescaped end and the still-escaped end.

      Show
      Use the following servlet: protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws IOException { resp.setContentType( "text/plain" ); resp.setCharacterEncoding( "UTF-8" ); Enumeration< String > headers = req.getHeaderNames(); while (headers.hasMoreElements()) { String header = headers.nextElement(); if (header.equals( "cookie" ) resp.getWriter().write(header + ": " + req.getHeader(header) + '\n' ); } Cookie[] cookies = req.getCookies(); if (cookies != null ) for (Cookie cookie : cookies) resp.getWriter().write(cookie.getName() + ": " + cookie.getValue() + '\n' ); resp.setStatus(HttpServletResponse.SC_OK); } together with the following curl script URL="http://localhost:8080/" COOKIES="JSON_COOKIE=\"{\\\"name\\\":\\\"value\\\"}\"" curl -i "${URL}" -H "Cookie: $COOKIES" As you can see this will send a cookie JSON_COOKIE="{\"name\":\"value\"}" to the server and the servlet simply echos the values of the cookie header as well as the processed cookies. The output is [curl HTTP header output] cookie: JSON_COOKIE="{"name":"value"}e\"}" JSON_COOKIE: {"name":"value"} but expected is [curl HTTP header output] cookie: JSON_COOKIE="{\"name\":\"value\"}" JSON_COOKIE: {"name":"value"} Here you see that in the current output the value for the header has also been unescaped but as the index for start and end have not been modified it is trailed by characters from the escaped header string between the unescaped end and the still-escaped end .

      Description

      When sending a cookie with JSON content to JBoss the automatic cookie processing (triggered by looking for a session cookie) modifies the byte[] buffer which is also used for the HTTP headers.

      This is due to multiple objects depending on the same byte[] buffer instance. The following hierarchy should demonstrate this dependency:

      Http11Processor.request (Request)
      └> cookies (Cookies)
      |  └> scookies[] (ServerCookie)
      |     └> scookies[x] (where x is the index referencing the JSON cookie)
      |        └> value (MessageByte)
      |           └>byteC (ByteChunk)
      |             \
      |              |-> buff (byte[])
      |             /
      |          ┌> byteC (ByteChunk)
      |       ┌> valueB (MessageByte)
      |    ┌> headers[y] (where y is the index referencing the JSON cookie header)
      |  ┌> headers[] (MimeHeaderField)
      └> headers (MimeHeader)
      

      The method Cookies.unescapeDoubleQuotes(ByteChunk) modifies this buffer by overwriting its contents when removing the escaped double-quotes. This in return destroys the reference for the header as it will still maintain the start and end reference inside this buffer. If the value for this header is read later it will be the unescaped content trailed by the surplus escaped region (see reproduction instructions for a more detailed example).

      In my opinion the method Cookies.unescapeDoubleQuotes(ByteChunk) should copy the byte[] first to avoid side effects to other parts referencing this byte[] as it could be (and is in our case) that the headers (including cookie) need to be forwarded unmodified to another server.

        Gliffy Diagrams

          Attachments

            Activity

              People

              • Assignee:
                rmaucher Remy Maucherat
                Reporter:
                mschaeidt Manuel Coenen
              • Votes:
                0 Vote for this issue
                Watchers:
                2 Start watching this issue

                Dates

                • Created:
                  Updated: