Skip to main content

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [List Home]
Re: [jetty-users] Jetty 9 bug

Per RFC2616 (The HTTP/1.1 spec)
Section 14.43  User-Agent.

You are required to provide a value, otherwise the header is deemed invalid.

In your example request headers, jetty parses the User-Agent header, sees no valid, deems it to be bad, and excludes it from the header map.
Jetty has a philosophy of being tolerant on what it can accept, and strict on what it generates.
If we didn't have this philosophy, your bad header would result in an error 400 (Bad Request).

The fact that Jetty 8 gave you a blank is that Jetty 8 had the bug of keeping a reference to a bad header.
The Jetty 8 behavior is at best, undefined. 

With the common http handling introduced in Jetty 9 (for HTTP 1.0, HTTP 1.1, SPDY, and HTTP 2.0) many of these kinds of undefined behavior have been addressed.

Sorry :(


--
Joakim Erdfelt <joakim@xxxxxxxxxxx>
Developer advice, services and support
from the Jetty & CometD experts


On Fri, May 24, 2013 at 10:30 AM, Denis Bardadym <bardadymchik@xxxxxxxxx> wrote:
Hello.

I found that jetty 9.0.2.v20130417 HttpServletRequest.getHeader return null when header is empty. You can see this in simple application:

import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.servlet.ServletHandler;

public class MinimalServlets {

    public static void main(String[] args) throws Exception {
        Server server = new Server(8080);
        ServletHandler handler = new ServletHandler();
        server.setHandler(handler);
        handler.addServletWithMapping(HelloServlet.class, "/*");
        server.start();
        server.join();
    }

    public static class HelloServlet extends HttpServlet {

        @Override
        protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
            response.setContentType("text/html");
            response.setStatus(HttpServletResponse.SC_OK);
            java.io.Writer w = response.getWriter();
            w.println(request.getHeader("User-Agent"));
            w.println(request.getHeader("X-Not-Exists"));
        }
    }
}

When i send curl request like this:

mac:liftweb den$ curl -v -D - -H "User-Agent;" -H "User-Agent:" http://localhost:8080
* About to connect() to localhost port 8080 (#0)
*   Trying ::1...
* connected
* Connected to localhost (::1) port 8080 (#0)
> GET / HTTP/1.1
> Host: localhost:8080
> Accept: */*
> User-Agent:
>
< HTTP/1.1 200 OK
HTTP/1.1 200 OK
< Content-Type: text/html; charset=ISO-8859-1
Content-Type: text/html; charset=ISO-8859-1
< Transfer-Encoding: chunked
Transfer-Encoding: chunked
< Server: Jetty(9.0.2.v20130417)
Server: Jetty(9.0.2.v20130417)

<
null
null
* Connection #0 to host localhost left intact
* Closing connection #0

It returns both nulls. But by javadoc it should return null only if header not presented but you see that User-Agent: just empty.

This does not happen in jetty8:

@SuppressWarnings("serial")
public class HelloServlet extends HttpServlet
{
    String greeting = "Hello";

    public HelloServlet()
    {
    }

    public HelloServlet(String hi)
    {
        greeting = hi;
    }

    private String getVal(String s) {
        if(s == null) return "null";
        else return s;
    }

    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException
    {
        response.setContentType("text/html");
        response.setStatus(HttpServletResponse.SC_OK);
        PrintWriter writer = response.getWriter();
        writer.println("User-Agent: " + getVal(request.getHeader("User-Agent")));
        writer.println("X-Not-Exists: " + getVal(request.getHeader("X-Not-Exists")));
        writer.flush();
        writer.close();
    }
}

and
public class OneServletContext {
    public static void main(String[] args) throws Exception {
        Server server = new Server(8080);

        ServletContextHandler context = new ServletContextHandler(ServletContextHandler.SESSIONS);
        context.setContextPath("/");
        server.setHandler(context);

        // Server content from tmp
        ServletHolder holder = context.addServlet(org.eclipse.jetty.servlet.DefaultServlet.class, "/tmp/*");
        holder.setInitParameter("resourceBase", "/tmp");
        holder.setInitParameter("pathInfoOnly", "true");

        // Serve some hello world servlets
        context.addServlet(new ServletHolder(new HelloServlet()), "/*");
        context.addServlet(new ServletHolder(new HelloServlet("Buongiorno Mondo")), "/it/*");
        context.addServlet(new ServletHolder(new HelloServlet("Bonjour le Monde")), "/fr/*");

        server.start();
        server.join();
    }
}

so when i send it request:

mac:liftweb den$ curl -v -D - -H "User-Agent;" -H "User-Agent:" http://localhost:8080
* About to connect() to localhost port 8080 (#0)
*   Trying ::1...
* connected
* Connected to localhost (::1) port 8080 (#0)
> GET / HTTP/1.1
> Host: localhost:8080
> Accept: */*
> User-Agent:
>
< HTTP/1.1 200 OK
HTTP/1.1 200 OK
< Content-Type: text/html;charset=ISO-8859-1
Content-Type: text/html;charset=ISO-8859-1
< Transfer-Encoding: chunked
Transfer-Encoding: chunked
< Server: Jetty(8.1.10.v20130312)
Server: Jetty(8.1.10.v20130312)

<
User-Agent:
X-Not-Exists: null
* Connection #0 to host localhost left intact
* Closing connection #0


Does it really bug??

Thanks, Denis Bardadym.


_______________________________________________
jetty-users mailing list
jetty-users@xxxxxxxxxxx
https://dev.eclipse.org/mailman/listinfo/jetty-users


Back to the top