Giter Site home page Giter Site logo

cuba's People

Contributors

0xflotus avatar agis avatar amclain avatar asterite avatar bemurphy avatar cordoval avatar cyx avatar doridoridoriand avatar eddiezane avatar fabianrbz avatar foca avatar frodsan avatar grempe avatar inkel avatar juanmcuello avatar kitop avatar martinpoljak avatar omab avatar rangeroob avatar rkh avatar samnang avatar slowernet avatar soveran avatar topalovic avatar vangberg avatar womblemuppet avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

cuba's Issues

Custom res.staus stops rendering on chrome.

On chrome inputting a custom res.staus stops page from rendering html/css/js properly and
just prints the html in plain text though it shows the right status.

here is some of my code that displays incorrectly on chrome (works in firefox and edge):

class Login < Cuba; end
  Login.define do
    on get do
      on root do
        res.status = 401
        res.write view('/login')
      end
    end

How to mount Cuba app as Rack app?

I am trying to mount a Cuba app with Rack builder as follows:

builder = Rack::Builder.new do
  use Rack::AuthMiddleware, :users => Tokens
  use API

  run lambda { |env| [200, {'Content-Type' => 'text/plain'}, ['All responses are OK']] }
end

But apparently, a Cuba constructor takes no arguments, and I get a:

/Users/pmu/.rbenv/versions/1.9.3-p194/lib/ruby/gems/1.9.1/gems/cuba-3.1.0/lib/cuba.rb:102:in `initialize'
/Users/pmu/.rbenv/versions/1.9.3-p194/lib/ruby/gems/1.9.1/gems/rack-1.4.4/lib/rack/builder.rb:82:in `new'
/Users/pmu/.rbenv/versions/1.9.3-p194/lib/ruby/gems/1.9.1/gems/rack-1.4.4/lib/rack/builder.rb:82:in `block in use'
/Users/pmu/.rbenv/versions/1.9.3-p194/lib/ruby/gems/1.9.1/gems/rack-1.4.4/lib/rack/builder.rb:130:in `[]'
/Users/pmu/.rbenv/versions/1.9.3-p194/lib/ruby/gems/1.9.1/gems/rack-1.4.4/lib/rack/builder.rb:130:in `block in to_app'
/Users/pmu/.rbenv/versions/1.9.3-p194/lib/ruby/gems/1.9.1/gems/rack-1.4.4/lib/rack/builder.rb:130:in `each'

Any ideas how to get this working?

[OT] - Thank you

Hi! I'm one of the many users that love Cuba. I also have the pleasure to know you and enjoy all of your work and products but now I want to show my gratitude in a public manner.

This OT and useless issue it's just my dumb way to say thank you for the work you do, the support to the community and the lesscode initiative that makes a bunch of us happy.

Next time I'll buy you a coffee and give you a hug.

Post Request with multiple parameters with the same name

Given I have a form on my website where I use a <select name="players" multiple>, my browser will send a POST request with the application/x-www-form-urlencoded request body "players=2&players=3". As you can see, it contains the key players twice.

If I now get the value of req.POST I get the value {"players"=>"3"}. The second occurrence of the key overwrote the first one. The only place where I can see all selections is in req.env["rack.request.form_vars"]. Here I will get the string "players=2&players=3".

So if I want to access the entire selection of the user, I will need to parse the form_vars by hand.

Is there any other solution? This also seems to be at the Rack level, right? So this is probably not even in the source code of Cuba. But maybe someone has a solution for it?

Allow Param defaults to be an empty string?

Hi,

Would make sense to allow empty strings as a default param value? While it makes sense to prevent empty strings from being captured from a request, the current implementation discards both empty params and empty defaults as they pass through the control flow. See: https://github.com/soveran/cuba/blob/master/lib/cuba.rb#L264

Would you be open to a pull request addressing this or would you guys be interested in tackling this small change?

Background Scenario/Usecase

I have a PORO JSON presenter/serializer wrapping an instance of data object, which together return validation errors. I'd like Cuba to pass the empty strings to my presenter/object, and could do so if I could set empty strings as my default. Currently, I'd have to have a second on true block that I'd rather not have cluttering up my code.

Serving static files using Rack::Static not working

I'm trying to serve static files from Cuba using Rack::Static @ ruby 2.3.1p112 (2016-04-26 revision 54768) [x86_64-linux]:

Cuba.use Rack::Static, :urls => %w("/css" "/js"), :root => "public"

But I keep on getting 404s. I tried all combinations - removing :root, moving /css from public/ to /, using :urls => { "/css/style.css" => ... using string keys instead of symbols in Rack::Static configuration ... - but nothing seams to work.

Thanks !

wrong number of arguments (given 0, expected 1..2) when upload file

  on get do
	on 'upload' do 
	    res.write '<form action="/multipart" enctype="multipart/form-data" method="post" ><input name="file" type="file" /><input type="submit" value="upload" /></form>'
		
	end
 end 
  on post do 

    on 'multipart' do 
	 
                 tmpfile =  param["file"][:tempfile]
		filename =  param["file"][:filename]
		target="public/upload/#{filename}"
		File.open(target,'wb') {
		|f| f.write(tmpfile.read) 
		}
		
	
    end
end

Create a generator

Create a simple generator with basics configurations, default ones commented.

cuba new <projectName>

Creates:

  • A config.ru
  • The main cuba file with
    • 1 method and its route to show the simple text renderer.
    • 1 method, its view and route to show the view renderer.

That's it.

It keeps it small and speed up the dev process when using cuba for most use cases.

Missing rack session in v4

Hi @soveran,

With the last version, I have

/usr/src/app # bundle exec puma
Puma starting in single mode...
* Puma version: 6.1.0 (ruby 3.2.1-p31) ("The Way Up")
*  Min threads: 0
*  Max threads: 5
*  Environment: development
*          PID: 7
! Unable to load application: LoadError: cannot load such file -- rack/session
bundler: failed to load command: puma (/usr/local/bundle/bin/puma)
<internal:/usr/local/lib/ruby/3.2.0/rubygems/core_ext/kernel_require.rb>:37:in `require': cannot load such file -- rack/session (LoadError)
	from <internal:/usr/local/lib/ruby/3.2.0/rubygems/core_ext/kernel_require.rb>:37:in `require'
	from /usr/local/bundle/gems/cuba-4.0.0/lib/cuba.rb:3:in `<top (required)>'
	from <internal:/usr/local/lib/ruby/3.2.0/rubygems/core_ext/kernel_require.rb>:37:in `require'
	from <internal:/usr/local/lib/ruby/3.2.0/rubygems/core_ext/kernel_require.rb>:37:in `require'
	from /usr/src/app/app.rb:3:in `<top (required)>'
	from config.ru:3:in `require_relative'
	from config.ru:3:in `block in <main>'
	from /usr/local/bundle/gems/rack-3.0.4.1/lib/rack/builder.rb:103:in `eval'
	from /usr/local/bundle/gems/rack-3.0.4.1/lib/rack/builder.rb:103:in `new_from_string'
	from /usr/local/bundle/gems/rack-3.0.4.1/lib/rack/builder.rb:94:in `load_file'
	from /usr/local/bundle/gems/rack-3.0.4.1/lib/rack/builder.rb:64:in `parse_file'
	from /usr/local/bundle/gems/puma-6.1.0/lib/puma/configuration.rb:365:in `load_rackup'
	from /usr/local/bundle/gems/puma-6.1.0/lib/puma/configuration.rb:287:in `app'
	from /usr/local/bundle/gems/puma-6.1.0/lib/puma/runner.rb:158:in `load_and_bind'
	from /usr/local/bundle/gems/puma-6.1.0/lib/puma/single.rb:44:in `run'
	from /usr/local/bundle/gems/puma-6.1.0/lib/puma/launcher.rb:189:in `run'
	from /usr/local/bundle/gems/puma-6.1.0/lib/puma/cli.rb:75:in `run'
	from /usr/local/bundle/gems/puma-6.1.0/bin/puma:10:in `<top (required)>'
	from /usr/local/bundle/bin/puma:25:in `load'
	from /usr/local/bundle/bin/puma:25:in `<top (required)>'
	from /usr/local/lib/ruby/3.2.0/bundler/cli/exec.rb:58:in `load'
	from /usr/local/lib/ruby/3.2.0/bundler/cli/exec.rb:58:in `kernel_load'
	from /usr/local/lib/ruby/3.2.0/bundler/cli/exec.rb:23:in `run'
	from /usr/local/lib/ruby/3.2.0/bundler/cli.rb:491:in `exec'
	from /usr/local/lib/ruby/3.2.0/bundler/vendor/thor/lib/thor/command.rb:27:in `run'
	from /usr/local/lib/ruby/3.2.0/bundler/vendor/thor/lib/thor/invocation.rb:127:in `invoke_command'
	from /usr/local/lib/ruby/3.2.0/bundler/vendor/thor/lib/thor.rb:392:in `dispatch'
	from /usr/local/lib/ruby/3.2.0/bundler/cli.rb:34:in `dispatch'
	from /usr/local/lib/ruby/3.2.0/bundler/vendor/thor/lib/thor/base.rb:485:in `start'
	from /usr/local/lib/ruby/3.2.0/bundler/cli.rb:28:in `start'
	from /usr/local/lib/ruby/gems/3.2.0/gems/bundler-2.4.6/libexec/bundle:45:in `block in <top (required)>'
	from /usr/local/lib/ruby/3.2.0/bundler/friendly_errors.rb:117:in `with_friendly_errors'
	from /usr/local/lib/ruby/gems/3.2.0/gems/bundler-2.4.6/libexec/bundle:33:in `<top (required)>'
	from /usr/local/bin/bundle:25:in `load'
	from /usr/local/bin/bundle:25:in `<main>'

seems that rack-session is missing.

Regards,

Related to the-benchmarker/web-frameworks#6148

[Suggestion] Adds support for beerpay.io

Hi @soveran , first congrats for all your projects, I have been used many of them for a lot of projects, cuba, ost, micromachine, etc...
I want to invite to you to add some projects to beerpay.io, so I can support them , and retribute at least some of everything you do for us
about Beerpay, it is a free plataform for support open source project and help them to grow up, I'm inviting to all people, who has projects that I'm using, for support them

thanks for all!

List of "routes" declared in the app

It would be awesome to have a sort of rake routes to have the list of the defined URL that the Cuba app can match on.

If you give me some pointers into the code I can try to code it myself and submit a PR.

Thanks!

Having issues with cuba safe

The app is:

on "idea" do
  on get do
    token = csrf.token
    res.write({csrf: token}.to_json)
  end

  on post do
    p csrf.safe?
  end
end

In the tests:

test "ideas works" do
  csrf_token = JSON.parse(get("idea").body)["csrf"]
  post "idea", "csrf_token" => csrf_token
end

And i get false in the console
I inspected the session and every time it has different contents
So It does not get stored between requests. What am I doing wrong here?

Optional query parameters

Hi, I have a question regarding optional query parameters. I have the following routes defined:

Cuba.define do
  on get do
    on 'movies' do
      on param("genre"), param("offset"), param("limit") do |genre, offset, limit|
        ...
      end
    end
  end
end

But this route only matches when exactly all query params are passed and I would like this route to match even if none are passed or just some. I mean, make these parameters are completely optional. Is there any way to achieve that in a simple way instead of using req.env["rack.request.query_hash"] directly?

Thanks

The dependencies in .gems.dev are not installed

I just followed the instruction from The Guide to Cuba, when I do "dep install", dep only install the dependency in .gems file and the gems defined in .gems.dev are not installed, do I need to install those gems manually or I can pass some argument like "dep install --develpment"?

Cuba::Render layouts not working

Hi, I'm having trouble using render from Cuba::Render - I get a LocalJumpError "no block given (yield)".
My setup is as follows:

# app.rb
require 'cuba'
require 'cuba/render'
require 'haml'
require 'tilt/haml'

Cuba.plugin Cuba::Render
Cuba.settings[:render][:template_engine] = 'haml'

Cuba.define do
  on root do
    render 'dashboard'
  end
end
-# views/layout.haml
!!!5
%html
  %head
    %title Title
  %body
    = yield
-# views/dashboard.haml
%h1 Dashboard

Accessing the root page gives the LocalJumpError as above.

settings can not use all objects when having a subclass and . . .

Cuba.settings[ :state ] = Proc.new { "ok" }
class A < Cuba; end

just does not work. some with singletons, lambdas, methods, etc

I solved the problem for myself with this plugin
https://github.com/mkristian/cuba-api/blob/master/lib/cuba_api/config.rb
which does implement a configuration with inheritance on class level:

Cuba.plugin CubaApi::Config
Cuba[ :state ] = Proc.new { "ok" }
class A < Cuba; end

and the value of can be changed later and A will see the change as well.

Cuba.plugin CubaApi::Config
Cuba[ :state ] = "ok"
Cuba.settings[ :state ] = "ok"
class A < Cuba; end
Cuba[ :state ] = "not-ok"
Cuba.settings[ :state ] = "not-ok"
p A[:state]
> "not-ok"
p A.settings[:state]
> "ok"

making a deep copy during class instantiation is also tricky since order of when the class gets defined does matter.

class A < Cuba; end
Cuba.settings[ :state ] = "ok"
class B < Cuba; end
p A.settings[:state]
> nil
p B.settings[:state]
> "ok"

although A and B are essentially the same class but were defined at different states of Cuba. having those A and B in their own files and require them makes it even harder to understand what is going on

require 'a'
Cuba.settings[ :state ] = "ok"
require 'b'
p A.settings[:state]
> nil
p B.settings[:state]
> "ok"

again using the cuby_api/config plugin makes the code more intuitive.

require 'a'
Cuba[ :state ] = "ok"
require 'b'
p A[:state]
> "ok"
p B[:state]
> "ok"

since intuition varies from person to person I would like to know other opinions.

BTW I would happy to prepare pull request to get something like cuby_api/config into Cuba and deprecate the current settings.

finally need to mention that I do like this little cuba framework a lot - I am about to switch my rails-api server to cuba/cuba_api and the new setup is so much easier to understand. I can understand the whole lot (including cuba) by reading half an hour code.

Manual Server start

I came to a situation where I needed to start a Cuba application by myself not using rackup or a config.ru file at all. Would be nice if we had an option to do so.

Proposal: remove `header` API

header API was introduced in bf5f628, but with no examples or instructions on how to use it and also no tests of it.

Actually from the name header, we assume it's used to ensure the request has some header with it, but http header in the env hash should be start with HTTP_ prefix. So the correct implementation might be

  ENV_HTTP_HEADER_PREFIX = "HTTP_".freeze
  def header(key)
    lambda { env["#{ENV_HTTP_HEADER_PREFIX}_#{key}".upcase.tr("-","_")] }
  end

Or the user has to call header('HTTP_KEYNAME') if he/she wants to make sure the KEYNAME exist in the header.

So, as I mentioned early, since there are no examples, instructions and tests on how to use it. Should cuba just remove it?

Or if you are concerned about breaking the backward compatibility, I will be happy to contribute some docs and tests on it.

Confusion over params capture

I was asking in #cuba.rb on this. The channel consensus seems to be that on param() matching should match blank (non-nil) param values. That is how the code behaves now.

However, the README, example, and comments seem to imply it's for checking the presence of a real, non-blank value. I'm confused which it is.

If the behavior is wrong, I can submit a pull request with tests. Thanks.

rack 3.0 support

will cuba support rack 3.0?

here some of the changes that effect cuba.

  • Extract rackup command, Rack::Server, Rack::Handler and related code into a separate gem.
  • Moved Rack::Session into separate gem.
  • Response header keys can no longer include uppercase characters.
  • Rack::Headers added to support lower-case header keys.

i've included links to rack 3.0's changelog and upgrade guide as a connivence.

change log
https://github.com/rack/rack/blob/3.0.0/CHANGELOG.md

upgrade guide
https://github.com/rack/rack/blob/3.0.0/UPGRADE-GUIDE.md

Rack 2.0 support?

Rails 5 and Rack 2 are out. Cuba is locked to Rack 1.6. Any plans for an upgrade?

Not all HTTP methods are supported

I noticed that matching for OPTIONS requests is not supported. I checked the source for Cuba and found out that matching for the existing methods is simple sugar on top of Rack (https://github.com/soveran/cuba/blob/master/lib/cuba.rb#L328-L331). I tried adding OPTIONS and the other missing HTTP methods in the same manner as the other methods have been implemented and it worked well.

I commited the new methods in my fork. There were no tests related to HTTP methods, so I didn't write any. The fork is ready for merge.

I think the added methods are a worthwhile patch. IMO, they are not a new feature but an extension to an existing one. The addition doesn't interfere with Cuba's minimalistic approach.

Reference in Readme to Cuba::TextHelpers

I quote:
That's the simplest kind of plugin you'll write. In fact, that's exactly how the markdown helper is written in Cuba::TextHelpers.

Where is Cuba::TextHelpers? Is it some cuba-contrib project I don't know about? Thanks

Possibility to disable csrf in test environment

Problem running tests is that none of my queries are all of sudden not authorized b/c of missing csrf token in headers. Is there a way to simply disable it ? Or actually set a csrf token on the header for every request made in test mode ?

Use of partials

I would like to extract a partial with some html from my layout.mote.
I was unable to find a easier solution than this:

layout.mote

...
{{ this.partial('mypartial') }}
...

then inside views/mypartial.mote i have some html content.

<p>This is the content of my partial.</p>

Is this the right way to do it?

BTW I like this little framework A LOT.
πŸ‘ Thx for the nice job πŸ‘

When running sample test, I get: cannot load such file -- cutest (LoadError)

/Library/Ruby/Site/2.0.0/rubygems/core_ext/kernel_require.rb:55:in `require': cannot load such file -- cutest (LoadError)
        from /Library/Ruby/Site/2.0.0/rubygems/core_ext/kernel_require.rb:55:in `require'
        from /Library/Ruby/Gems/2.0.0/gems/cuba-3.1.1/lib/cuba/test.rb:2:in `<top (required)>'
        from /Library/Ruby/Site/2.0.0/rubygems/core_ext/kernel_require.rb:135:in `require'
        from /Library/Ruby/Site/2.0.0/rubygems/core_ext/kernel_require.rb:135:in `rescue in require'
        from /Library/Ruby/Site/2.0.0/rubygems/core_ext/kernel_require.rb:144:in `require'

How about defining secure headers in lower case to match the HTTP/2 specification?

Hi!

Currently, the HTTP/2 protocol specification defines secure headers, which are security-related headers, in uppercase, which is not consistent with the specification since HTTP/2 normally treats headers in lowercase.
Also, since secure headers are currently defined in uppercase, some Ruby application servers, such as Rack, treat this as a lint error or validation error, which prevents the web application from starting properly.
I would like to propose that secure headers be redefined in lowercase to match the HTTP/2 specification. I believe this will improve consistency in the context of the HTTP/2 protocol and avoid compatibility and application server launch issues.

Currently, the following workaround is available, but I believe that redefining it in lowercase would be a more desirable form.

res.headers.keys.each do |key|
  res.headers[key.downcase] = res.headers.delete(key)
end

Specific changes:
I would like to make a correction to redefine the following in lower case.
https://github.com/doridoridoriand/cuba/blob/change-secure-headers-to-lowercase/lib/cuba/safe/secure_headers.rb#L29-L36

References:
https://github.com/rack/rack/blob/main/lib/rack/lint.rb#L655-L656
https://datatracker.ietf.org/doc/html/rfc9113#name-http-fields

Regards,

undefined method `DelegateClass' for Rack::Session::Cookie:Class (NoMethodError)

/Ruby27/lib/ruby/gems/2.7.0/gems/rack-2.2.3/lib/rack/session/cookie.rb:155:in <class:Cookie>': undefined method DelegateClass' for Rack::Session::Cookie:Class (NoMethodError)
hele_world.rb

require "cuba"
require "cuba/safe"

Cuba.use Rack::Session::Cookie, :secret => "__a_very_long_string__"

Cuba.plugin Cuba::Safe

Cuba.define do
  on get do
    on "hello" do
      res.write "Hello world!"
    end

    on root do
      res.redirect "/hello"
    end
  end
end

404 default Content-Type not set

The Content-Type isn't being set when a 404 occurs on our application, which means that plain text is rendered: http://cl.ly/image/1f401k340S29

Is this the intended default behavior?

I believe that the way it works is all 200's have a default Content-Type of text/html if not otherwise set, but other status codes have no Content-Type at all (see here)

Add travis.ci support

I haven't ever done this for a project, and don't know if there is some internal CI for cuba, but it would be useful to have, even if just for testing pull requests. Is anyone working on this? If not, I'll take a look tomorrow.

Support for generators via CLI

Rails has a great CLI interface for starting off new applications and it also has support for generating controllers, models, views and schemas.

Is something like this already in plan for Cuba? I understand that it is planned for a micro-framework and it does a good job with that but something like a cuba new my-new-app would be a great addition.

List of new commands -

  • cuba new path/to/my-new-app
    This will generate a new application skeleton for a cuba based application. Features for customizing it can be provided.
  • cuba init
    This is something on the lines of how compass works. If there is a json file with the config information, a cuba app will be initialized in that folder.
  • cuba generate my-controller This will create a new controller and create a new test file based on the config. No views and models will be generated.

If a feature of this sort is welcome, I would love to work on it.

Strict-Transport-Security header in Cuba::Safe::SecureHeaders is dangerously strict!

The setting of the 'Strict-Transport-Security' security header is by default set to:

"Strict-Transport-Security" => "max-age=631138519; includeSubdomains; preload"

The use of this header is good, but for a default setting (encouraged to use in the docs with no explanation of its repercussions) it is far to strict and could cause a developers other websites to inadvertently become inaccessible for long periods of time to any browser that visits the SecureHeader Cuba app over HTTPS.

In detail:

max-age=631138519;

This is good to set, but it is set for a very long period for a developer that may only be in testing mode. This value represents 20.013 years. That means that any browser that successfully visits that site will never allow it to be visited over a non-secure HTTP connection for at least 20 years. The only way to reset is for the server to set it to '0' explicitly and then the browser user has to visit the site again. I would suggest a more reasonable value of 1 month, or 2628000 seconds.

includeSubdomains

This is an optional value and it has potentially far-reaching effects and should not be included in a default setup. By setting this, you are telling every browser that visits this site over an HTTPS connection successfully (even once) that ALL SUBDOMAINS of this domain shall also be REQUIRED to visit over an https connection. So for example, if there is a pre-existing www.example.com website which does not have a TLS certificate, and then the developer of this Cuba mini-app decides to setup this secure little mini-site on HTTPS. From now on every browser that visited the mini-site will refuse to load the www site over simple HTTP since it is not protected by TLS!! This (spec optional) setting should be removed from Cuba's defaults.

preload

preload is another optional part of the spec, and is dangerous to include in a default setup. By having this set you are requesting (or allowing to be requested) that this domain be permanently hard-coded into the Chrome browser (and others who use their service) that they should only be allowed to see the site over HTTPS. This setting, when present, might allow an attacker to add the site on the HSTS preload site (https://hstspreload.appspot.com) and force all Chrome users to only allow access to this domain, and all sub-domains, over HTTPS. This option should also be removed from the defaults.

All of this is well documented here:

https://developer.mozilla.org/en-US/docs/Web/Security/HTTP_strict_transport_security

Twitter Secure Headers project, also does not use the optional attributes:

https://github.com/twitter/secureheaders

You should also include instructions for how to override specific security settings as appropriate for a Cuba app in the docs. I am doing so in my Cuba app with something like this which seems to be working as expected:

require 'cuba'
require 'cuba/safe'
...
Cuba.plugin Cuba::Safe::SecureHeaders
Cuba.settings[:default_headers].merge!({"Strict-Transport-Security" => "max-age=2628000"})
...
Cuba.define do
  ...
end

Allow multi mount routes on define

For example I have this

on default do
    run V1::Settings
    run V1::Setups
end

Currently that does not work, I have a bunch of endpoint on each Cuba class and I'd like to mount them using only run method.

I'm not pretty sure but Grape mount the endpoints like my approach using the mount method.

File sending

Would be nice if we had an API for sending files (using Rack::File?) which would set proper headers and stuff.

Improve performance by caching regexes?

Hi @soveran! πŸ˜„

I noticed that to consume segments a regex is created each and every time the segment tries to be matched:

matchdata = env[Rack::PATH_INFO].match(/\A\/(#{pattern})(\/|\z)/)

So I made this benchmark:

require_relative "./lib/cuba"

Cuba.define do
  on "users" do
    on ":id" do |id|
      on root do
        res.write "User #{id}"
      end

      on "projects" do
        on ":project_id" do |project_id|
          res.write "User #{id}, Project #{project_id}"
        end
      end
    end
  end
end

env1 = { "PATH_INFO" => "/users/1", "SCRIPT_NAME" => "/" }
env2 = { "PATH_INFO" => "/users/1/projects/2", "SCRIPT_NAME" => "/" }

time = Time.now
30_000.times do
  Cuba.call(env1)
  Cuba.call(env2)
end
puts Time.now - time

On my machine it takes about 4 seconds to complete.

Now I cache the regexes with this diff:

diff --git a/lib/cuba.rb b/lib/cuba.rb
index b12e9f3..b4090fe 100644
--- a/lib/cuba.rb
+++ b/lib/cuba.rb
@@ -5,6 +5,7 @@ class Cuba
   EMPTY   = "".freeze
   SEGMENT = "([^\\/]+)".freeze
   DEFAULT = "text/html; charset=utf-8".freeze
+  REGEXES = Hash.new { |h, pattern| h[pattern] = /\A\/(#{pattern})(\/|\z)/ }
 
   class Response
     LOCATION = "Location".freeze
@@ -211,7 +212,7 @@ class Cuba
   private :try
 
   def consume(pattern)
-    matchdata = env[Rack::PATH_INFO].match(/\A\/(#{pattern})(\/|\z)/)
+    matchdata = env[Rack::PATH_INFO].match(REGEXES[pattern])
 
     return false unless matchdata

I run the snippet above and it now takes 2 seconds.

Twice as fast!

Do you think this is a good change? I think it's harmless: the routes of an app are fixed (not dynamic) so that REGEXES hash will reach a reasonable maximum size. Plus it can help with routes like ":id" where they might be used in several places.

What do you think?

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    πŸ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. πŸ“ŠπŸ“ˆπŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❀️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.