Standalone SSL WebApp with Apache as helper

For speed reasons, I run my Web App standalone.
For safety reasons, I force SSL connections.
For economy and convenience reasons, I host my web App on a Mac behind a router and do port mapping for HTTP and HTTPS (80 and 443)
For image speed reasons, I set up Apache to be my “helper App” to serve Images, so my Xojo Web App doesn’t have to deal with those.

This all works, with an extra port map of 8083 to the Mac port 8083,
and wherever I use images, the URL is https://www.myapp.com:8083/images/xxx.png

The problem is that when customers want to use my web App on a wifi network that has a firewall blocking anything other than 80 and 443,
my App loads without images.

Is there an easy way around this?
Would it not be sensible for Xojo Web to allow a specific path to be not served by the Web App, but leave that to Apache that can do that faster and multi threaded?
The alternative is to have the web App open the local file and return the contents, but that slows the web App down and still makes the whole thing pretty much single core, single threadn and dead slow with any amount of images.
Or would it be possible to launch a thread that deals with the image requests, so the main thread can concentrate on the web App logic?
And would that not be slower than Apache would be?

Could you use Apache as the SSL (port 443) endpoint, and to serve images from that same port, but ReverseProxy into the Web App on port 80?

This is easiest if your app is in its own path (www.myapp.com/app/).

There’s nothing we can do in this regard. Requests on a certain port can only be routed to a single app. If it goes to the web app, you’re stuck there. Taking the time to forward the request to Apache doesn’t get you anything because you’d have to wait for the response and send it back to the client.

You can do this today with App.HandleUrl. Browser requests all run in individual threads and requests to HandleUrl run on the main thread. As long as you yield once in a while (if you’re doing something very processor intensive) you should be just fine.

That said, if you’ll be serving the same images over and over, make sure you set the caching headers properly so the browsers don’t hit your app twice for the same image.

@Ian Jones Thanks for the reply, but I don’t think I want to use port 80, as all non secure sessions are re-routed by the App.

@Greg O’Lone Thanks Greg, I tried it with App.HandleURL and it works but I have two issues;
-1) Indeed all of my images load over and over; how do I setup caching so that the image are cached?
-2) Some images now end up shown as a ? so, they obviously did not load, although I can see my HandleURL returning a valid image;
could this be a yielding issue and how would I solve this?

When you say “returning a valid image” could you show your code?

This site has a pretty good explanation of caching headers: https://www.mobify.com/blog/beginners-guide-to-http-cache-headers/

@Greg O’Lone I might have been premature in my verdict that images were not served, I cleaned up the code a little bit and this now does serve the images correctly, but every time one of the images is requested it fires, so no caching.

dim startTime as double = Microseconds
  
  if left(Request.Path,7) = "Images/" then
    
    dim filePath as string = "/"+Request.Path
    
    dim FileType as string = Right(Request.Path,3)
    if FileType="png" then 
      Request.MIMEType="image/png"
    else
      ReQuest.MIMEType="image/jpeg" // Assume all non png's are jpegs 
    end
    
    dim f as Folderitem = GetFolderItem(Specialfolder.Desktop.NativePath+FilePath, folderitem.PathTypeNative)
    If f = nil then
      Request.Status=404
      system.DebugLog(Request.Path+" is Nill")
      return False
    else
      If f.Exists Then
        
        try
          dim i as MemoryBlock
          Dim bs as BinaryStream = BinaryStream.Open(f, False)
          
          Request.print bs.read(bs.Length)
          Request.status=200
          
        catch e as IOException
          system.DebugLog(Request.Path+" IO ErrorException")
          Request.status=409
          Return False
        end try
        
      else
        Return False // File not found
      End If
      Request.Status=200
      system.debuglog("URLHandle " + Request.path + " " + str((Microseconds-startTime) / 1000)+" ms, Status "+str(Request.Status) )
      return True
    end if
  end if

@Greg O’Lone My Header does have a caching instruction, but the HandleURL is called every time a browsers needs them;

MyApp

I’m not sure if this is the best cache setup or that I’m simply not doing it right?

You’ll need to set those caching headers on the images themselves, inside HandleUrl.

Hmm, not sure I follow. With Apache as the secure front end web server, you can ReverseProxy to your real stand-alone Xojo web app on whatever port you choose. While your Xojo made app will technically not be “secure”, it’ll only be accessible through the secure Apache web server.

But it sounds like you’re getting somewhere with using HandleUrl anyway.

@Greg O’Lone Thanks Greg, but I’m at a loss on what to return exactly; Now I just return the Image, how to I add a cache instruction with that?

@Ian Jones Thanks Ian, I hear what you are saying, but to be honest I have no experience with making my Mac Apache into a reverse proxy, so if it can be done reasonably well within Xojo that would be easier, allthough likely slower for both the image handling and the effect it has on my App’s responsiveness in general.

Apparently you have your own domain pointing to your machine, and port 80 is open. Apache should be able to directly serve the images without any extra fuss. And caching would then be automatic.

@Michel Bujardet

Well, no. The domain points to a router with ports 80 and 443 mapped to the Mac behind the router running the webApp. That’s stopping Apache from getting any requests, as my App gets all requests and returns a “file not found”.

Or should I consider making my Mac an exposed Host? Not sure if that works, but that could open up links like www.mayapp.com/images/pic1.png to Apache, right? But I’m slightly hesitant in exposing the Mac fully.

If it is your work machine, I would not recommend it, but if it is a dedicated box, it would be a lot simpler than to use an app to serve pictures. You will never be able to get even approaching performances as Apache.

@Michel Bujardet It is a dedicated box, so I’ll give it a try. Thanks for the speedy replies.

@Michel Bujardet I just looked into reverse proxy, and apparently Mac server’s version of Apache has everything stripped out non essential, including reverse proxy, so I don’t think I want to open that can of worms.
I think I’m stuck with HandleURL serving my images. If I knew how to add a cache to my response that would probably suffice, but I’m a newbie when it comes to caching.

Those items in the article are headers. You add them using the Header method. http://documentation.xojo.com/index.php/WebRequest.Header

@Greg O’Lone and @Paul Lefebvre Thanks, I did see that page, but it’s not exactly elaborate.
I tried the following in my HandleURL, which does not work, so I’m sure I’m not doing it right;
(f has the folder item to be returned)

          Dim bs as BinaryStream = BinaryStream.Open(f, False)
          Request.Header("cache-control") = "max-age=300"
          Request.print bs.read(bs.Length)
          Request.status=200

It’s probably my inexperience, but I would like some sample code projects that show how to optimise web app performance, using SSL in combination with HandleURL, caching, preloading images, using Xojo Web app as middleware, etc.
Although I think Xojo web is definitely making big steps in progress, documentation and samples are not excessive, and although this forum is great, it would be nice if there was more information on how to optimise web apps.
Possibly Paul could do a web cast on this topic?