Rack::ResponseHeaders in rackup for Sinatra - sinatra

I think this is a very easy one, but I can't seem to get it right. Basically, I'm trying to use Rack middleware to set a default Cache-Control header into all responses served by my Sinatra app. It looks like Rack::ResponseHeaders should be able to do exactly what I need, but I get an error when attempting to use the syntax demonstrated here in my rackup file:
use Rack::ResponseHeaders do |headers|
headers['X-Foo'] = 'bar'
headers.delete('X-Baz')
end
I was able to get Rack::Cache to work successfully as follows:
use Rack::Cache,
:default_ttl => 3600
However, this doesn't achieve exactly the output I want, whereas Rack::ResponseHeaders gives fine-grained control of the headers.
FYI, my site is hosted on Heroku, and the required Rack gems are specified in my .gems manifest.
Thanks!
Update: After doing some research, it looks like the first issue is that Rack::ResponseHeaders is not found in the version of rack-contrib (0.9.2) which was installed. I'll start by looking into that.

In case anyone's interested, I was able to get this working. It didn't look like there would be an easy way to install rack-contrib-0.9.3 on Heroku, but the only file I needed was response_headers.rb, so I simply copied this into my project directory and edited my rackup as follows:
require 'rack/contrib/response_headers'
# set default cache-control header if not set by Sinatra
use Rack::ResponseHeaders do |headers|
if not headers['Cache-Control']
headers['Cache-Control'] = "public, max-age=3600"
end
end
This sets a default max-age of 1 hr on objects for which I'm not specifying an explicit Cache-Control header in Sinatra – namely, static assets.

Related

how call REST service with path variable in webmethod?

I'm using WM9.8. I want to know how to call a GET REST service with path variable like:
http://localhost:8080/client/1 in webmethod.
I can call POST rest service using pub.client.http. But it dosen't work to GET.
Use String varible called "method" to set type of Http request method.
Just put the path variable in the URL and made a substitution to the path variable
e.g: http://localhost:8080/client/%yourPathVariableHere%
Holy cow this is an old question but I just tumbled across it and I thought I might helps somebody else who does.
URLs in webmethods are fixed to a single value, like /client unless you enable watt.server.url.alias.partialMatching=true
After that, you can simply alias a service to /client and all subURLs like /client/1 are sent to that service. You still have to parse them to get the ID out.
Be careful, though, because ALL sub URLs are sent to the service. So after enabling this flag I get /client, /client/1, /client/1/name all going to the same service. You can see how this can quickly become REST-unfriendly.

Is it possible to use wildcards or catch-all paths in AWS API Gateway

I am trying to redirect all traffic for one domain to another. Rather than running a server specifically for this job I was trying to use AWS API Gateway with lambda to perform the redirect.
I have this working ok for the root path "/" but any requests for sub-paths e.g. /a are not handled. Is there a way to define a "catch all" resource or wildcard path handler?
As of last week, API Gateway now supports what they call “Catch-all Path Variables”.
Full details and a walk-through here: API Gateway Update – New Features Simplify API Development
You can create a resource with path like /{thepath+}. Plus sign is important.
Then in your lambda function you can access the value with both
event.path - always contains the full path
or event.pathParameters.thepath - contains the part defined by you. Other possible use case: define resource like /images/{imagepath+} to only match pathes with certain prefix. The variable will contain only the subpath.
You can debug all the values passed to your function with: JSON.stringify(event)
Full documentation
Update: As of last week, API Gateway now supports what they call “Catch-all Path Variables”. See API Gateway Update – New Features Simplify API Development.
You will need to create a resource for each level unfortunately. The reason for this is API Gateway allows you to access those params via an object.
For example: method.request.path.XXXX
So if you did just /{param} you could access that with: method.request.path.param but if you had a nested path (params with slashes), it wouldn't work. You'd also get a 404 for the entire request.
If method.request.path.param was an array instead...then it could get params by position when not named. For example method.request.path.param[] ...Named params could even be handled under there, but accessing them wouldn't really be easy. It would require using something some sort of JSON path mapping (think like what you can do with their mapping templates). Sadly this is not how it's handled in API Gateway.
I think it's ok though because this might make configuring API Gateway even more complex. However, it does also limit API Gateway and to handle this situation you will ultimately end up with a more confusing configuration anyway.
So, you can go the long way here. Create the same method for multiple resources and do something like: /{1}/{2}/{3}/{4}/{5}/{6}/{7} and so on. Then you can handle each path parameter level if need be.
IF the number of parameters is always the same, then you're a bit luckier and only need to set up a bunch of resources, but one method at the end.
source: https://forums.aws.amazon.com/thread.jspa?messageID=689700&#689700
Related to HTTPAPI that AWS introduced recently, $default is used a wildcard for catching all routes that don't match a defined pattern.
For more details, refer to: aws blogs
You can create a resource with path variable /{param}, and you can treat this as wildcard path handler.
Thanks,
- Ka Hou

How to use Postgres and static file manupulation in Nginx

I would like to use Nginx as my CDN for a file hosting system. I saw a great module for nginx that allows postgres connection (https://github.com/FRiCKLE/ngx_postgres) it works really well, however when I try to use it while having alias directive it seems to ignore the alias or file download and rather give me an empty file.
My idea is, to use the UUID from the URL and find the correct file doing a query and then using the found details to change the filename header so that the user's client will download automatically set the name to the original filename instead of a uuid.
Here is the code.
location /dl{
postgres_output none;
postgres_pass database;
postgres_query "SELECT * FROM \"Files\" WHERE uuid = '$args'";
postgres_set $filename 0 name;
alias /home/ubuntu/fileStorage;
add_header Content-Disposition "attachment; filename=$filename";
}
I think somehow the postgres directive is locking up this block. Is there a way I can run the postgres query without effecting the download block?
It seem that you expect that the line
add_header Content-Disposition "attachment; filename=$filename";
will cause the browser to download the file given by $filename. This is not how the Content-Disposition header works, it simply tells the browser to interpret the response body as a file. You're going to have to do something additional to get the proper content to the client. Perhaps what you really want is to issue a redirect?

How do I know what to name a file downloaded using HTTP?

I am creating an HTTP client downloader in Python. I am able to correctly download a file such as http://www.google.com/images/srpr/logo11w.png just fine. However, I'm not sure what to actually name the thing.
There is of course the filename at the end of the URL, but is this always reliable?
If I recall correctly, wget uses the following heuristic:
If a Content-Disposition header exists, get the filename from there.
If the filename component of the URL exists (e.g. http://myserver/filename), use that.
If there is no filename component (e.g. http://www.google.com), derive the filename from the Content-Type header (such as index.html for text/html)
In all cases, if this filename is already present in the directory use a numerical suffix, such as index (1).html, or overwrite, depending on configuration.
There are plenty of other flags that control other heuristics, such as creating .html for ASP/DHTML content-types.
In short, it really depends how far you want to go. For most people, doing the first two + basic Content-Type->name mapping should be enough.

How does one access (POST) arguments from nginx upload module in embedded lua/perl?

I've been trying to figure out how to access the results of the nginx upload module from embedded perl (using nginx-perl) or lua (using the embedded lua module). I've only been able to find examples of how to use the module with fastcgi (or similar), something I would, if possible, like to avoid having to use.
Simply letting the upload_pass have a lua/perl content handler does not seem to work; with the body being somehow truncated to just the first line (yes, I've told it to wait for the body and made sure it's not written to a file).
At least when using Perl (I haven't tried Lua, but I'm suspecting the same thing will happen), the complete body (as raw multipart/form-data) can be made available if one does a proxy_pass to another nginx instance.
My question is threefold. Firstly is this expected behaviour/how are arguments passed from the upload module? Secondly, is it possible to access the results of the upload module without (re)parsing the multipart/form-data using a perl/lua library in the content handler.
Finally, if the latter is not possible, can I use multipart/form-data parser used by nginx/upload without manually exporting the functions and using some form of FFI.
Thanks in advance.
With lua you can get at normal params via methods like this:
ngx.req.read_body()
local inputjson = ngx.req.get_body_data()
For post args documented: http://wiki.nginx.org/HttpLuaModule#ngx.req.get_post_args
Regular vars:
ngx.var.my_var
Lua nginx module has this well documented: http://wiki.nginx.org/HttpLuaModule
The vars that are documented for the upload module: http://www.grid.net.ru/nginx/upload.en.html
upload_set_form_field $upload_field_name.name "$upload_file_name";
upload_set_form_field $upload_field_name.content_type "$upload_content_type";
upload_set_form_field $upload_field_name.path "$upload_tmp_path";
should be accessible via:
ngx.var.upload_field_name.path
Just do a log or a print on the var to verify