Jetty response does not match any Compojure route

181 views
Skip to first unread message

larry google groups

unread,
Jul 13, 2014, 6:28:19 PM7/13/14
to comp...@googlegroups.com
At first I thought this was a jQuery/FireFox issue, so I posted this to StackOverflow, but now I think perhaps this might be a Compojure/Jetty issue. You can see what I wrote on StackOverflow here:


I'm using Charles to watch all of the network requests made on my machine, and the response that comes back from Jetty does not match any of my Compojure routes. And yet, if I test it with CURL, then everything works fine. Is there some default on OPTIONS requests that somehow ignores Compojure?

larry google groups

unread,
Jul 13, 2014, 6:49:22 PM7/13/14
to comp...@googlegroups.com
When I test this in Chrome, I get this error:

XMLHttpRequest cannot load http://localhost:40000/signup. Request header field Content-Type is not allowed by Access-Control-Allow-Headers. 

And, again, when I test this using CURL, I get the correct headers, and yet somehow Chrome and FireFox are going to a route that I have never defined. 

If I do this:

curl -X OPTIONS --verbose  http://localhost:40000/signup

I get these responses headers:

< HTTP/1.1 200 OK
< Date: Sun, 13 Jul 2014 22:45:00 GMT
< Access-Control-Allow-Origin: localhost:40000
< Access-Control-Allow-Methods: PUT, DELETE, POST, GET, OPTIONS, XMODIFY
< Access-Control-Max-Age: 2520
< Access-Control-Allow-Credentials: true
< Access-Control-Allow-Headers: x-requested-with, content-type, origin, accept
< Content-Type: application/json;charset=ISO-8859-1
< Content-Length: 12
< Server: Jetty(7.x.y-SNAPSHOT)


That includes Access-Control-Allow-Headers which has "content-type". But in both Chrome and FireFox, the browsers do a preflight OPTIONS call that gets a response that does not seem to come from any route that I have defined. 

If I use the Charles network debugger, I see FireFox send these headers:

OPTIONS /signup HTTP/1.1
Host: localhost:40000
Access-Control-Request-Method: POST
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_7_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/34.0.1847.131 Safari/537.36
Access-Control-Request-Headers: accept, content-type
Accept: */*
Accept-Encoding: gzip,deflate,sdch
Accept-Language: en-US,en;q=0.8

and get this response:

HTTP/1.1 200 OK
Date: Sun, 13 Jul 2014 22:42:58 GMT
Access-Control-Allow-Origin: http://localhost:34001
Access-Control-Allow-Methods: DELETE, GET, POST, PUT
Content-Type: application/octet-stream;charset=ISO-8859-1
Content-Length: 18
Server: Jetty(7.x.y-SNAPSHOT)

preflight complete

I have no idea where that response comes from. If I do this on my whole project:

grep -iR "preflight complete" *

The phrase "preflight complete" appears no where is my code. So where is this response coming from? And why don't FireFox and Chrome end up at the same route as when I make my call in CURL?

James Reeves

unread,
Jul 13, 2014, 8:13:27 PM7/13/14
to Compojure
Have you tried using another adapter, such as HttpKit? That would determine whether it's an issue with Jetty.

- James


--
You received this message because you are subscribed to the Google Groups "Compojure" group.
To unsubscribe from this group and stop receiving emails from it, send an email to compojure+...@googlegroups.com.
To post to this group, send email to comp...@googlegroups.com.
Visit this group at http://groups.google.com/group/compojure.
For more options, visit https://groups.google.com/d/optout.

larry google groups

unread,
Jul 13, 2014, 9:48:10 PM7/13/14
to comp...@googlegroups.com, ja...@booleanknot.com

Good idea. I'll try that.

larry google groups

unread,
Jul 13, 2014, 10:07:19 PM7/13/14
to comp...@googlegroups.com, ja...@booleanknot.com
>Have you tried using another adapter, such as HttpKit? That 
> would determine whether it's an issue with Jetty.

Okay, following your very good suggestion, I switched to HttpKit. So, once again, I try to do a cross-browser Ajax request with FireFox. Once again, FireFox does a behind the scenes "preflight" call to the server, using OPTIONS, to get permission to make the CORS request. The spec allows browers to hide the preflight from the client code, and FireFox does hide the activity, so this is one case where FireBug is useful. Instead I fire up the Charles network debugger, which shows me all activity. So in Charles I can see that FireFox makes this request:

OPTIONS /signup HTTP/1.1
Host: localhost:40000
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.7; rv:30.0) Gecko/20100101 Firefox/30.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
Access-Control-Request-Method: PUT
Access-Control-Request-Headers: content-type
Connection: keep-alive

and, very strange, it gets this reponse: 

HTTP/1.1 200 OK
Content-Type: application/octet-stream
Access-Control-Allow-Origin: http://localhost:34001
Access-Control-Allow-Methods: DELETE, GET, POST, PUT
Content-Length: 18
Server: http-kit
Date: Mon, 14 Jul 2014 01:58:22 GMT

preflight complete

Once again, the words "preflight complete" appear nowhere in my code. Nor do these headers exactly match what I write in any of my routes.

I defined my routes using Compojure, like so:


(defroutes app-routes
      (GET "/" request (login-form request))
      (POST "/" request (login request))
      (OPTIONS "/" request (preflight request))
      (GET "/signup" request (signup-form request))
      (PUT "/signup" request (signup request))
      (OPTIONS "/signup" request (preflight request))
      (route/resources "/")
      (route/not-found "Page not found. Check the http verb that you used (GET, POST, PUT, DELETE) and make sure you put a collection name in the URL, and possbly also a document ID."))


Any OPTIONS request should go to my preflight function, which looks like this:


(defn preflight [request]
  "2014-07-13 - this is meant to enable CORS so our frontenders can do cross-browser requests. The browser should do a 'preflight' OPTIONS request to get permission to do other requests."
  (print " IN PREFLIGHT ")
  (println " headers host is: " (str (get-in request [:headers "host"])))
  (assoc
      (ring.util.response/response "CORS enabled")
    :headers {"Content-Type" "application/json"
              "Access-Control-Allow-Origin" (str (get-in request [:headers "host"]))
              "Access-Control-Allow-Methods" "PUT, DELETE, POST, GET, OPTIONS, XMODIFY" 
              "Access-Control-Max-Age" "2520"
              "Access-Control-Allow-Credentials" "true"
              "Access-Control-Allow-Headers" "Authorization, X-Requested-With, Content-Type, Origin, Accept"}))

And, again, if I test this with CURL then request does go to the preflight function and I get back the headers that I expect: 

curl -X OPTIONS --verbose  http://localhost:34001/signup

* About to connect() to localhost port 34001 (#0)
*   Trying ::1... connected
* Connected to localhost (::1) port 34001 (#0)
> OPTIONS /signup HTTP/1.1
> User-Agent: curl/7.21.4 (universal-apple-darwin11.0) libcurl/7.21.4 OpenSSL/0.9.8x zlib/1.2.5
> Host: localhost:34001
> Accept: */*
< HTTP/1.1 200 OK
< Content-Type: application/json
< Access-Control-Allow-Origin: localhost:34001
< Access-Control-Allow-Methods: PUT, DELETE, POST, GET, OPTIONS, XMODIFY
< Access-Control-Max-Age: 2520
< Access-Control-Allow-Credentials: true
< Access-Control-Allow-Headers: Authorization, X-Requested-With, Content-Type, Origin, Accept
< Content-Length: 12
< Server: http-kit
< Date: Mon, 14 Jul 2014 02:04:46 GMT
* Connection #0 to host localhost left intact
* Closing connection #0

CORS enabled


But somehow FireFox and Chrome are going to a different route. And yet I can spy on their request via Charles, and what I see is: 

OPTIONS /signup HTTP/1.1
Host: localhost:40000

which I think should match this route: 

      (OPTIONS "/signup" request (preflight request))

Can anyone think of a reason this route would not match? 

And to what route might this be going, if it does not go to the above route? 




On Sunday, July 13, 2014 8:13:27 PM UTC-4, James Reeves wrote:

larry google groups

unread,
Jul 13, 2014, 10:10:05 PM7/13/14
to comp...@googlegroups.com, ja...@booleanknot.com
I used the wrong port number in my last curl example, but I get back the same thing when I use port 40000. I've spun up the same app on 2 ports. I am trying to make Ajax requests from one to the other, to test my CORS implementation. As I said before, this is not working, for reasons that confound me. 

larry google groups

unread,
Jul 13, 2014, 10:46:58 PM7/13/14
to comp...@googlegroups.com, ja...@booleanknot.com

Ah, I finally figured out what the problem was. I was thrashing about for several hours, trying to get CORS to work, and among many other experimentations, I applied this middleware: 


and that overrode the headers I was sending back. I am curious why this override only happened for Ajax requests and not curl requests. Maybe that is some magic r0man put into ring-cors. Either way, I deleted it and now I see the headers I am sending back.
Reply all
Reply to author
Forward
0 new messages