CORS requests with preflight on CouchDB - rest

We are trying to send HTTP cross domain requests to CouchDB.
To achieve this, we set up CouchDB with the following settings (inspired from the add-cors-to-couchdb tool):
[HTTPD]
enable_cors = true
[CORS]
origins = *
credentials = true
methods = GET, PUT, POST, HEAD, DELETE
headers = accept, authorization, content-type, origin, referer, x-csrf-token
And wrote code similar to this (but not hardcoded of course):
<html>
<body>
<script>
fetch("http://acme.org:5984/mydb/323958d9b42be0aaf811a3c96b4e5d9c", {
method: 'DELETE',
headers: {'If-Match': "1-0c2099c9793c2f4bf3c9fd6751e34f95"}
}).then(x => {
if (x.ok) return x.json().then(console.log);
console.error(x.statusText);
});
</script>
</body>
</html>
While it works fine with GET and POST, we get 405 Method not allowed on DELETE. The browser tells that the preflight response (to the OPTIONS request) was not successful, while the server indicates {"error":"method_not_allowed","reason":"Only DELETE,GET,HEAD,POST,PUT,COPY allowed"}.
We tried both with CouchDB 2.1.1 and 1.6.1. We also tried to replace origins: * with origins: http://localhost:8080 (where 8080 is the port serving the HTML above). We tried also to set credentials to false.

From a comment by #Ingo Radatz to a related question, I finally got that EVERY header used in the request must be included in CouchDB CORS settings.
In my personal case, I had to include if-match in the accepted headers:
[HTTPD]
enable_cors = true
[CORS]
origins = *
methods = GET, PUT, POST, HEAD, DELETE
headers = accept, authorization, content-type, origin, referer, if-match

Related

Rust warp redirect removing some headers

I'm trying to redirect requests to some URL. My server is using rust with warp.
The library https://docs.rs/warp-reverse-proxy/latest/warp_reverse_proxy/ seems to do exactly what I need, but when it redirects with all the headers the server receiving the request rejects it for 2 reasons:
the host header isn't what it expects
the content-length isn't what it expects
I tried removing those headers but I can't make the filters work. I tried so many combinations that pasting all of them here won't be very helpful.
Is there a preferred way of capturing a request, removing some headers and then redirect it?
Edit to add some code:
warp::serve(
warp::get()
.and(warp::path("graphiql"))
.and(juniper_warp::graphiql_filter("/graphql", None))
.or(warp::path("graphql").and(graphql_filter))
// .or(reverse_proxy_filter(
// "".to_string(),
// "https://example.com/".to_string(),
// ))
.with(log),
)
.run(([127, 0, 0, 1], 8080))
.await
user -> proxy.com -> example.com
The reverse_proxy_filter redirects, but the Host on the other side rejects the call. These are in different domains. So when example.com receives the request it rejects it because the Host header has the original domain.
Edit: Solved by adding another filter:
.or(warp::any().and(request_filter).and_then(
|path, query, method, mut headers: Headers, body: Body| {
headers.remove("Host");
headers.remove("Content-length");
proxy_to_and_forward_response(
"https://example.com".to_string(),
"".to_string(),
path,
query,
method,
headers,
body,
)
},
))

Scooping headers off of one Postman request and injecting them into others

My web service uses JWT-based authorization bearer token authentication:
HTTP clients send a valid POST to /v1/auth/signIn with a valid JSON request entity (includes username + password info)
If they authenticate successfully, that endpoint sends back an auth bearer token as an HTTP response header that (from curl) looks like:
Response from curl:
HTTP/1.1 200 OK
Date: Tue, 04 Sep 2018 01:18:28 GMT
X-Content-Type-Options: nosniff
X-XSS-Protection: 1; mode=block
Cache-Control: no-cache, no-store, max-age=0, must-revalidate
Pragma: no-cache
Expires: 0
X-Frame-Options: DENY
Access-Control-Expose-Headers: Authorization
Authorization: Bearer <big_huge_string>
Content-Length: 0
Subsequent service calls to authenticated endpoints just need to include the token as an HTTP request header whose key/name is Authorization and whose value is "Bearer <xyz>" (where <xyz>) is the <big_huge_string> that came back on the sign in call above. Pretty basic standard JWT stuff.
I'm trying to write a Postman collection that starts with a "Sign In Request" that successfully signs in and gets a JWT token from the service, and then adds the appropriate HTTP request header in each subsequent call. Any ideas as to how I can:
Extract the <big_huge_string> off the HTTP response header that I'll get back from my Sign In Request?; and then
How to save that <big_huge_string> as a variable and inject that as an HTTP request header for all subsequent calls?
Thanks in advance!
Update
Tried the suggestion:
Getting closer, but console.log(...) isn't printing anything to Postman (or at least I don't know where to look for it). I should mention I'm not using the Chrome Application version of Postman, but the standalone app/executable (Version 6.1.4):
Any ideas how/where I can get console.log(...) working? I'm concerned about just changing the test to:
pm.test("Can Extract JWT", function() {
var authHeader = pm.response.headers.toObject().Authorization;
pm.expect(authHeader).to.not.be.equal(null);
pm.globals.set('token', authHeader)
});
Without first seeing what that authHeader even is. Any ideas?!
Once you have that Token value you can reference it in each of the request headers using the {{token}} syntax. It's getting the sign in Auth header that's the harder part.
You could use pm.response.headers to get a list of the Headers and then extract out the value that you need.
This is returned as a list so maybe using something like Lodash or converting this to an object can help get the value you need. It would be something like pm.response.headers.toObject().Authorization - I haven't tried it so my syntax might be slightly wrong.
You can log the Headers out to the Postman console and narrow it down that way to - just wrap it in a Console.log() statement.
When you get that value, it's just a basic pm.globals.set('token, pm.response.headers.toObject().Authorization) to save this globally.

How to show an optional header in markdown for apiary?

How to indicate that one particular header of a request is optional with the markdown of apiary?
My code:
Request
The apiKey can be passed in the header (note the camelcase for "apiKey")
The Content-Encoding: gzip is optional, only if you gzip the entity
Headers
apiKey: `42452-eofefo-4534535` (optional)
Content-Type: application/json
Content-Encoding: gzip (optional)
Is the above ok?
As of January 2016, it's not possible.
On the other hand—if you go to the API Blueprint Roadmap, there's MSON Parameters and Headers feature which is currently in the RFC stage; this will enable you to describe HTTP Headers in the MSON syntax and mark each HTTP Header as required/optional (see below).
+ Response 200 (application/json)
+ Headers
+ Date (Date, optional) - Date at which the message was originated
Hoping MSON Headers will land soon.

How to redirect nginx to non http without html headers

I'm trying to redirect a url in nginx to a non http protocol such as test://123456 when i go to test.com/123456
I've tried the following rewrite:
rewrite ^/(.*)$ test://$1 permanent;
and it works however the weird part that it adds html/body headers which mess up my code, is there any way to do without the html headers or any other recommended way to to such rewrite?
HTTP/1.1 301 Moved Permanently
Server: nginx/1.1.19
Date: Tue, 30 Apr 2013 14:14:47 GMT
Content-Type: text/html
Content-Length: 185
Connection: keep-alive
Location: test://123456
<html>
<head><title>301 Moved Permanently</title></head>
<body bgcolor="white">
<center><h1>301 Moved Permanently</h1></center>
<hr><center>nginx/1.1.19</center>
</body>
</html>
This is not weird, this is how it’s supposed to be.
RFC 2616 specifies that the entity bodies you want to remove should be present.
10.3.2 301 Moved Permanently
The new permanent URI SHOULD be given by the Location field in the response. Unless the request method was HEAD, the entity of the response SHOULD contain a short hypertext note with a hyperlink to the new URI(s).
and...
10.3.3 302 Found
The temporary URI SHOULD be given by the Location field in the response. Unless the request method was HEAD, the entity of the response SHOULD contain a short hypertext note with a hyperlink to the new URI(s).
SHOULD, in this context, is defined in RFC 2119:
This word, or the adjective "RECOMMENDED", mean that there may exist valid reasons in particular circumstances to ignore a particular item, but the full implications must be understood and carefully weighed before choosing a different course.
Answer taken from NGINX 301 and 302 serving small nginx document body. Any way to remove this behaviour?
Of course you can still do it, one possibility would be to proxy the request and change the requests method from GET to HEAD. That should ensure that only HTTP headers are sent.
This is untested, but it should be a good starting point:
server {
listen 8080;
server_name localhost;
return 301 test://$request_uri;
}
server {
listen 80;
server_name example.com;
location / {
proxy_method HEAD;
proxy_pass http://localhost:8080;
}
}
Also from interest in this context NGINX convert HEAD to GET requests.

REST API GET/POST using jquery AJAX to get node using neo4j graph database

I'm new to REST API**(is that really my REST problem?)**
I want to get all node from neo4js by using
Cypher
START n = node(*)
return n;
how do i use if i use jquery ajax POST or GET method
in doc it recommend
POST http://localhost:7474/db/data/cypher
Accept: application/json
Content-Type: application/json
In my code i write
$.ajax({
type:"POST",
url: "http://localhost:7474/db/data/cypher",
accepts: "application/json",
dataType:"json",
contentType:"application/json",
data:{
"query" : "start n = node(*) return n",
"params" : {}
},
success: function(data, textStatus, jqXHR){
alert(textStatus);
},
error:function(jqXHR, textStatus, errorThrown){
alert(textStatus);
}
});//end of placelist ajax
What's my problem?
The error alert is below
You dont say what kind of error you get, but running exactly the same code as you, I get the following error:
XMLHttpRequest cannot load http://127.0.0.1:7474/db/data/cypher.
Origin http://127.0.0.1:3000 is not allowed by Access-Control-Allow-Origin.
So I am assuming that this is the error you are experiencing.
When performing a cross-domain Ajax call, there are two options:
JSONP, which Neo4J does not support.
Cross-Origin Resource Sharing (CORS). "The basic idea behind CORS is to use custom HTTP headers to allow both the browser and the server to know enough about each other to determine if the request or response should succeed or fail".
The OPTIONS request sent before the POST (preflight request), returns the following headers from the Neo4J REST server:
Access-Control-Allow-Origin:*
Allow:OPTIONS,POST
Server:Jetty(6.1.25)
A cruical header is missing here, namely the Content-Type header. This means that the POST request will fail when this header is sent with the POST request, which is exactly what is happening in your $.ajax() call.
The POST will succeed if you remove the following line
contentType:"application/json",
from your $.ajax() call.
This will prevent jQuery from sending the Content-Type header.