default path issue with static files with Suave, in F# - f#

I am not understanding the doc when it comes to serving static files.
I have a site where the backend is deployed to /app in a docker container and the front end part is deployed to /app/frontend
The main file for the front end is at: /app/frontend/index.html
In the config I have this:
homeFolder = Some "/app/frontend"
and then:
GET >=> choose
[
path "/healthcheck" >=> Successful.OK "ok"
pathScan "/checkqr/%s" checkQRCode
path "/" >=> Files.file "index.html"
Files.browseHome
]
when I go to domain.com I get a 404 but when I go to domain.com/index.html I get the index.
what did I miss with the syntax? I would like to serve the index.html file when going to domain.com
Tests done in the meantime:
path "/" >=> Files.browse "index.html"
path "/" >=> Files.file "index.html"
path "/" >=> Files.browseFile "/app/frontend" "index.html"
path "/" >=> Files.browseFile "frontend" "index.html"
path "/" >=> Files.sendFile "index.html" true
path "/" >=> Files.file (Files.resolvePath "/app/frontend" "index.html")
path "/" >=> Files.browseFileHome "index.html"
path "/" >=> Files.file "/app/frontend/index.html"
none of them work.
I confirmed, the file is at /app/frontend/index.html

Files.file doesn't look in the home folder, but Files.browseFileHome does:
path "/" >=> Files.browseFileHome "index.html"
I agree that the documentation is very fuzzy on this.

Related

How to get uwsgi to work with internal routing

Hi I'm trying to to get uwsgi to serve static files and untimately to try adding ".js" if the file was not found before defaulting to the python app.
I already compiled the pcre support into my uwsgi but still cannot get it to work.
As a first step I tried to set up a simple example. I created a file settings.ini:
[uwsgi]
route = ^/hi rewrite:/hello.html
route = ^/logo static:/icon.svg
route = ^/huhu static:/hello.html
and run
uwsgi --ini settings.ini --http=127.0.0.1:8000 --check-static static --wsgi-file app.py
The content of app.py is not relevant but I post it for completeness:
def application(env, start_response):
start_response('200 OK', [('Content-Type','text/html')])
return [b"went to python app"]
If I put files in a subfolder static (e.g. static/hello.html) then they are served correctly, also app.py is called when I navigate to anything that is neither found in the static folder nor matches anything in settings.ini.
However, if I navigate to http://127.0.0.1:8000/hi it goes to the app. I would expect to be served hello.html.
And if I navigate to http://127.0.0.1:8000/huhu I get The connection was reset error on the browser.
I also tried adding plugins = router_static or plugins = router_rewrite to settings.ini with no success.

how to set up Suave to access a post message on any route, and binding to "*"

I need to set up a service that need to accept POST messages to ANY route on that IP and have the web server listening to ALL IPs the machine has
I can make a list of local IPs easily, add 127.0.0.1 to it for testing.
How can I set up a callback on any post request, with the contents? I've just started to look at it 1h ago so the answer may be obvious.
This will handle all POST requests sent to whatever bindings you'd like:
open Suave
open Suave.Filters
open Suave.Operators
open Suave.Successful
[<EntryPoint>]
let main argv =
// list your bindings here
let bindings =
[
"127.0.0.1", 8080
"127.0.0.1", 8081
] |> List.map (fun (addr, port) ->
HttpBinding.createSimple HTTP addr port)
let cfg =
{ defaultConfig with bindings = bindings }
// handle all POST requests
let app =
POST >=> request (fun req ->
OK $"POST received: {req.path}")
startWebServer cfg app
0
Powershell test: Invoke-WebRequest -uri "http://127.0.0.1:8081/Hello" -Method POST
Output: POST received: /Hello

Operating on an uploaded file

I'm trying to parse an uploaded file as follows:
lib/thingy_web/controllers/things_controller.ex
def create(conn, %{"data" => %Plug.Upload{content_type: "application/octet-stream", filename: basename, path: dirname}}) do
things_params = dirname <> "/" <> basename
|> File.stream!
|> NimbleCSV.RFC4180.parse_stream
|> Enum.map(&AllThings.create_things_params/1)
|> Enum.map(&AllThings.create_things/1)
conn
|> put_status(:created)
end
However, when I try a POST with a test file:
curl -F 'data=#/root/test' http://localhost:4000/api/thing
I get the error:
[debug] Processing with ThingyWebWeb.ThingsController.create/2
Parameters: %{"data" => %Plug.Upload{content_type: "application/octet-stream", filename: "test", path: "/tmp/plug-1514/multipart-1514490176-65282591343221-1"}}
Pipelines: [:api]
[info] Sent 500 in 55ms
[error] #PID<0.544.0> running ThingyWeb.Endpoint terminated
Server: localhost:4000 (http)
Request: POST /api/thing
** (exit) an exception was raised:
** (File.Error) could not stream "/tmp/plug-1514/multipart-1514490176-65282591343221-1/test": not a directory
(elixir) lib/file/stream.ex:79: anonymous fn/2 in Enumerable.File.Stream.reduce/3
(elixir) lib/stream.ex:1270: anonymous fn/5 in Stream.resource/3
(elixir) lib/stream.ex:806: Stream.do_transform/8
Subsequent inspection of /tmp/plug-1514/ reveals that it is indeed an empty directory.
Is the uploaded file short-lived and can be configured to be long-lived, or am I missing something altogether here?
path contains the full path to the uploaded file. filename is just the name of the file that the user selected in the browser (or in this case, curl); the uploaded file is not stored with that name. You need to only pass the path to File.stream!/1:
things_params =
path
|> File.stream!
|> ...

How to solve ' No route matches [GET] image.png ' when I moved image to assets image path?

I moved image to assets/images path from public/images
I have image:
<%= image_tag("login_logo.png", :id => "login_logo") %>
I moved it from public folder to assets and changed path.
It is visible and working ok, but I get error in my console:
Started GET "/assets/logo_PG.png" for 127.0.0.1 at 2012-10-10 23:42:53 +0300
Served asset /logo_PG.png - 304 Not Modified (0ms)
ActionController::RoutingError (No route matches [GET] "/images/login_logo.png")
How can I solve this ?
Everything in subdirectories of assets (regardless whether it is an image, JS, etc.) is by default available under /assets/name.extension. So just make sure you refer to the image with the path /assets/login_logo.png, or use the asset_path helper:
<%= asset_path('login_logo.png') %>

Routing Error--image routing

Getting the following error:
ActionController::RoutingError (No route matches "/public/images/download.png" with {:method=>:get}):
This error means that a request is being made for the following URL:
http://YOURSERVER/public/images/download.png
Typically, this correlates to file in your application's home directory of:
public/public/images/download.png
Note the "public" dir nested within the "public" dir

Resources