Results 1 to 40 of 118

Thread: VB6 Web Site/App Server

Threaded View

  1. #1

    Thread Starter
    PowerPoster
    Join Date
    Aug 2010
    Location
    Canada
    Posts
    2,900

    VB6 Web Site/App Server

    This project helps you serve web sites/apps with VB6. It is a work in progress. It will eventually become a DLL, but for now it is an EXE project while under development.

    It includes a number of nice features to make it easier to deliver websites such as:

    • Auto-serves static files (this can be disabled if you want to perform your own file serving).
    • Automatically handle If-None-Match headers to return 304 Not Modified when appropriate to save bandwidth.
    • Easily handle cookies with the CHttpCookies class.
    • Easily handle requests via the CHttpRequest class.
    • Easily respond to requests using the CHttpResponse class.
    • Include "helper" classes for things like handling dates, encoding HTML entities, "Safe" DB creation, regular expressions, and HTML templates (I call these VBML files, and they have a ".vbml" extension.
    • MIME type detection (file extension based).


    VBML files are just HTML files with special comments. The app server will detect the comments and raise an event to your app, which can then respond with HTML that will replace the VBML comment. VBML comments are formatted like this:

    Code:
    <!-- vbml: my_vbml_command -->
    Your app will receive "my_vbml_command" in the ConvertVbmlToHtml event, where it can set the p_Html property to whatever you'd like to replace the comment with. VBML commands can also include parameters:

    Code:
    <!-- vbml: my_vbmlcommand(2, "Param") -->
    The parameters will be passed in the po_VbmlParameters arraylist in the ConvertVbmlToHtml event, and you can use them however you like. Take a look at the Web/index.vbml file for examples of some VBML comments/commands, then look at the CApp class' mo_VbmlHelper_ConvertVbmlToHtml event sub to see how the VBML commands are processed.


    To Try It Out Yourself:

    IMPORTANT NOTE FOR LINUX/WINE USERS: Make sure to use an early Wine 5.x release or a Wine 7.x release. The late 5.x and 6.x series appears to have broken something related to networking, and the RC6 cWebServer class never receives data to respond to. This is discussed in more detail here.


    1. Make sure that all the RC6 DLLs are installed on your computer.
    2. Open VBWebAppServer.vbp and run it.
    3. In your browser, visit http://127.0.0.1:8080


    You should see the following page:

    Name:  rc6web.jpg
Views: 493925
Size:  40.8 KB

    Note that when running in the IDE, the server will be running as a single thread so performance won't be spectacular as each request will have to wait for the previous request to complete. You can however compile the EXE and use the /spawn switch to spawn as many app server listeners as you like. You can then put Nginx in front of the app server and configure it to be a reverse proxy to all your app server listeners.

    Here's the code that produces the dynamic portions of the demo page:

    Code:
    Option Explicit
    
    Private WithEvents mo_VbmlHelper As CAppHelperVbml
    
    Public Sub RespondToRequest(po_Req As CHttpRequest, po_Response As CHttpResponse, po_Helpers As CAppHelpers)
       Dim l_VisitCount As Long
       
       With po_Req.Cookies
          l_VisitCount = .CookieValueByKeyOrDefaultValue("visitcount", 0)
          l_VisitCount = l_VisitCount + 1
          .AddOrReplaceCookie "visitcount", l_VisitCount, , , Now + 10000
       End With
       
       With po_Response
          If po_Helpers.Regex.Test(po_Req.Url(urlsection_Path), "^showcase/[0-9]+$", False) Then
             ' Get requested showcase image from database by numeric id
             With New_C.Connection(pathApp & "web.sqlite", DBOpenFromFile)
             
                With .CreateSelectCommand("SELECT image, etag, extension FROM showcase WHERE id=?")
                   .SetInt32 1, Split(po_Req.Url(urlsection_Path), "/")(1)  ' Get image ID from request and use it for SELECT query
                   
                   With .Execute(True)
                      If .RecordCount = 0 Then
                         ' No image found!
                         po_Response.Send404NotFound
                         
                      Else
                         ' Found an image. Check to see if requester has a cached copy
                         If po_Req.Headers.HeaderValue("If-None-Match") = .Fields("etag").Value Then
                            ' Requester has a cached copy, send 304 Not Modified to save bandwidth
                            
                            po_Response.Send304NotModified
                            
                         Else
                            ' Requester does not have a cached copy of the image, so send it (along with the ETag so future cache hits can be tested).
                      
                            po_Response.AddHttpHeader "ETag", .Fields("etag").Value
                            po_Response.SendSimpleByteArrayResponse .Fields("image").Value, , , mimeTypeFromFilePath(.Fields("extension").Value)
                         End If
                      End If
                   End With
                End With
             End With
             
          Else
             If Not New_C.FSO.FileExists(po_Req.LocalPath) Then
                ' File Not found!
                .Send404NotFound
             
             Else
                If LCase$(Right$(po_Req.Url(urlsection_Path), 5)) = ".vbml" Then
                   ' Request for a dynamic .vbml page
                   Set mo_VbmlHelper = po_Helpers.Vbml ' Pass VBML helper to module level variable to receive events.
                   
                   .SendSimpleHtmlResponse mo_VbmlHelper.ParseVbmlString(New_C.FSO.ReadTextContent(po_Req.LocalPath)), po_Req.Cookies
                   
                Else
                   ' Since we have auto serve enabled, we should never get here
                   ' as the auto-serve feature should have found and served the requested file.
                   Debug.Assert False
                   
                   .Send400BadRequest
                End If
             End If
          End If
       End With
    End Sub
    
    Private Sub mo_VbmlHelper_ConvertVbmlToHtml(ByVal p_VbmlCommand As String, ByVal po_VbmlParameters As RC6.cArrayList, p_Html As String, p_ShouldEscapeHtml As e_HtmlEscapeType)
       Dim l_Date As Date
       Dim l_ShowcaseCount As Long
       
       Select Case p_VbmlCommand
       Case "get_rc6_version"
          ' Get the file version of RC6.dll for reporting the most recent version
          
          p_Html = New_C.Version
       
       Case "get_rc6_date"
          ' Get the file creation date of RC6 DLL for reporting the most date of the most recent release
          
          New_C.FSO.GetFileAttributesEx pathSystem & "RC6.dll", , , , l_Date
          
          p_Html = Format$(l_Date, "YYYY-MM-DD")
       
       Case "get_copyright"
          ' Get the copyright text for the page
          
          p_Html = "Copyright " & Year(Now) & " &mdash; Olaf Schmidt."
          p_ShouldEscapeHtml = htmlescape_No
          
       Case "get_random_showcase_items"
          ' Get random RC6 showcase items and build the product showcase card.
          ' You can pass a count parameter with this command to determine the number of random showcase items to retrieve
          
          l_ShowcaseCount = 2  ' Default to 2 showcase items
          If po_VbmlParameters.Count > 0 Then l_ShowcaseCount = po_VbmlParameters.Item(0)  ' Get the desired # of showcase items if defined.
          
          With New_C.Connection(pathApp & "web.sqlite", DBOpenFromFile)
             With .OpenRecordset("SELECT rowid, product_name, developer, description_html, website FROM showcase ORDER BY random() LIMIT " & l_ShowcaseCount)
                Do Until .EOF
                   p_Html = p_Html & "<div class='card p-4'>" & _
                                     "<h2 class='text-center'>" & htmlEscape(.Fields("product_name")) & "<br>by " & htmlEscape(.Fields("developer")) & "</h2>" & _
                                     "<img alt='" & htmlEscape(.Fields("product_name")) & " Screenshot' style='max-height: 150px;' class='img-fluid mt-4 mb-4 mx-auto' src='showcase/" & htmlEscape(.Fields("id")) & "' />" & _
                                     .Fields("description_html") & _
                                     "<p><a href='" & htmlEscape(.Fields("website")) & "'>Learn more about " & htmlEscape(.Fields("product_name")) & "...</a></p>" & _
                                     "</div>"
                
                   .MoveNext
                Loop
             End With
          End With
          
          p_ShouldEscapeHtml = htmlescape_No
          
       Case Else
          p_Html = "Unhandled VBML Command: " & p_VbmlCommand
          Debug.Print p_Html
          'Debug.Assert False
       
       End Select
    End Sub
    You can see it's pretty standard VB6 code, reasonably readable/understandable and concise (62 lines not including comments).

    Command Line Parameters

    If you compile the EXE you'll have access to some command line parameters:

    /spawn <number>
    Start the app server in "spawner" mode which will cause it to launch <number> processes in "listener" mode.

    /stop
    Stop all listener and spawner processes.

    /ip <IPv4 address>
    Tells the app server what IP to listen on

    /port <Port>
    Tells the app server what Port to listen on. When used with /spawn, this will be the first port of the first spawned listener. Additonal spawned listeners will listen on <port+spawnindex>. For example, spawning 3 listeners at base port 8080 with the command /spawn 3 /ip 127.0.0.1 /port 8080 will result in listeners on ports 8080, 8081, and 8082.

    /rootpath <folder path>
    Tells the server where the root folder is for serving static files. This defaults to the App.Path & "\web" folder. All of your static files should be placed in this folder (or subfolders thereof).

    It's recommended to start in spawner mode like this:

    Code:
    VbWebApp.exe /spawn 10 /ip 127.0.0.1 /port 8080
    The above command spawns 10 app listeners on ports 8080-8089.

    Note that the compiled EXE expects the RC6 DLLs to be in the App.Path & "\System" folder for reg-free use.

    Anyway, I hope some of you find this useful, and I'll be happy to answer any questions you might have.

    SOURCE CODE HERE: VBWebAppServer14.zip
    Last edited by jpbro; Jan 15th, 2022 at 02:35 PM.

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  



Click Here to Expand Forum to Full Width