diff --git a/NEWS.md b/NEWS.md index 3d1362d..60e33ed 100644 --- a/NEWS.md +++ b/NEWS.md @@ -5,6 +5,9 @@ in memory. - Added `use_html_template` to use `htmltools::htmlTemplate` as rendering. - Custom renderers (`as_renderer`) are now more robust. +- Add `limit` field to protect against large uploads. +- Fix issue with setting custom websocket handler [#62](https://github.com/devOpifex/ambiorix/issues/62). +- Add `engine` method on router to set custom renderers (`use` deprecated for custom renderers). # ambiorix 2.1.0 diff --git a/R/ambiorix.R b/R/ambiorix.R index 7b966f0..c5f3f64 100644 --- a/R/ambiorix.R +++ b/R/ambiorix.R @@ -7,6 +7,7 @@ #' @field on_stop Callback function to run when the app stops, takes no argument. #' @field port Port to run the application. #' @field host Host to run the application. +#' @field limit Max body size, defaults to `5 * 1024 * 1024`. #' #' @importFrom assertthat assert_that #' @importFrom utils browseURL @@ -177,7 +178,10 @@ Ambiorix <- R6::R6Class( #' if(interactive()) #' app$start(port = 3000L) start = function( - port = NULL, host = NULL, open = interactive()) { + port = NULL, + host = NULL, + open = interactive() + ) { if(private$.is_running){ cli::cli_alert_warning("Server is already running") return() @@ -208,6 +212,27 @@ Ambiorix <- R6::R6Class( ) ), onHeaders = function(req) { + size <- 0L + if (private$.limit <= 0) + return(NULL) + + if (length(req$CONTENT_LENGTH) > 0) + size <- as.numeric(req$CONTENT_LENGTH) + else if (length(req$HTTP_TRANSFER_ENCODING) > 0) + size <- Inf + + if (size > private$.limit){ + .globals$errorLog$log("Request size exceeded, see app$limit") + + return( + response( + "Maximum upload size exceeded", + status = 413L, + headers = list("Content-Type" = "text/plain") + ) + ) + } + return(NULL) } ) @@ -294,6 +319,12 @@ Ambiorix <- R6::R6Class( return(private$.host) private$.host <- value + }, + limit = function(value){ + if(missing(value)) + return(private$.limit) + + private$.limit <- as.integer(limit) } ), private = list( @@ -302,6 +333,7 @@ Ambiorix <- R6::R6Class( .server = NULL, .static = list(), .is_running = FALSE, + .limit = 5 * 1024 * 1024, n_routes = function(){ length(private$.routes) }, diff --git a/R/response.R b/R/response.R index 3a0b57e..aee3a6e 100644 --- a/R/response.R +++ b/R/response.R @@ -629,7 +629,7 @@ Response <- R6::R6Class( # hooks if(length(private$.preHooks) > 0) { - for(i in 1:length(private$.preHooks)) { + for(i in seq_along(private$.preHooks)) { pre_processed <- private$.preHooks[[i]](self, file_content, data, ext) if(!is_pre_hook(pre_processed)){ cat(error(), "Not a valid return value from pre-hook (ignoring)\n") @@ -817,4 +817,4 @@ deprecated_status <- function(status = NULL) { package = "ambiorix", msg = "Deprecated. Pass status to the `status` binding, e.g.: `res$status <- 404L`." ) -} \ No newline at end of file +} diff --git a/R/routing.R b/R/routing.R index c7fded2..33c7fca 100644 --- a/R/routing.R +++ b/R/routing.R @@ -227,6 +227,14 @@ Routing <- R6::R6Class( cli::cli_rule("Ambiorix", right = "web server") cli::cli_li("routes: {.val {private$n_routes()}}") }, + #' @details Engine to use for rendering templates. + engine = function(engine){ + if(!is_renderer_obj(engine)) + engine <- as_renderer(engine) + + self$use(engine) + invisible(self) + }, #' @details Use a router or middleware #' @param use Either a router as returned by [Router], a function to use as middleware, #' or a `list` of functions. @@ -259,6 +267,11 @@ Routing <- R6::R6Class( } if(is_renderer_obj(use)) { + .Deprecated( + "engine", + package = "ambiorix", + msg = "Use `engine` instead of `use` for custom renderers." + ) .globals$renderer <- use return(invisible(self)) } diff --git a/man/Ambiorix.Rd b/man/Ambiorix.Rd index 24c9486..2685e7f 100644 --- a/man/Ambiorix.Rd +++ b/man/Ambiorix.Rd @@ -141,6 +141,8 @@ if(interactive()) \item{\code{port}}{Port to run the application.} \item{\code{host}}{Host to run the application.} + +\item{\code{limit}}{Max body size, defaults to \code{5 * 1024 * 1024}.} } \if{html}{\out{}} } @@ -165,6 +167,7 @@ if(interactive())