B4J Library [B4X] xHttpServer (Http Server + jQuery)

It is a personal project of mine that I started as a hobby on B4i and it has become an interesting project, so that I have modified it to be multiplatform.

It is an http server, which allows a browser to navigate on html pages stored on the device. In addition, dynamic pages can also be created. Read the parameters of the GET and POST commands and read and write the COOKIES in the browser.
It also implements the WebSocket, starting from an example published in this forum by @Erel for the jServer library. I also made the jQueryElement class to interface with the JavaScript elements of the Browser page.
(You can get the source of the QueryElement class at this Post)

Obviously it is not at the level of existing and established servers, but it is a project that I want to share and that I think can be useful since it is cross-platform. The examples are in post 2

It is entirely written in B4X.
It may have some bugs
It does not support SSL / TLS. I didn't understand how it works.


aHttpServer

Author:
Star-Dust
Version: 0.77
  • QueryElement
    • Events:
      • change (Resp As ServletResponse, Params As Map) ' QueryElement Event Click
      • click (Resp As ServletResponse, Params As Map) ' QueryElement Event Click
      • dblclick (Resp As ServletResponse, Params As Map) ' QueryElement Event Click
      • focus (Resp As ServletResponse, Params As Map) ' QueryElement Event Click
      • focusin (Resp As ServletResponse, Params As Map) ' QueryElement Event Click
      • focusout (Resp As ServletResponse, Params As Map) ' QueryElement Event Click
      • keyup (Resp As ServletResponse, Params As Map) ' QueryElement Event Click
      • mousedown (Resp As ServletResponse, Params As Map) ' QueryElement Event Click
      • mouseenter (Resp As ServletResponse, Params As Map) ' QueryElement Event Click
      • mouseleave (Resp As ServletResponse, Params As Map) ' QueryElement Event Click
      • mousemove (Resp As ServletResponse, Params As Map) ' QueryElement Event Click
      • mouseup (Resp As ServletResponse, Params As Map) ' QueryElement Event Click
    • Fields:
      • Event_change As String
      • Event_click As String
      • Event_dblclick As String
      • Event_focus As String
      • Event_focusin As String
      • Event_focusout As String
      • Event_keyup As String
      • Event_mousedown As String
      • Event_mouseenter As String
      • Event_mouseleave As String
      • Event_mousemove As String
      • Event_mouseup As String
      • NoEvent As Map()
    • Functions:
      • Class_Globals As String
      • CreateEvent (ObjectName As String, Event As String, OtherEvent As Map()) As Map()
      • EscapeHtml (Raw As String) As String
      • Eval (Script As String, Params As List) As String
      • EvalWithResult (Script As String, Params As List) As String
      • GetPropriety (Property As String, Value As List) As String
      • GetVal (ID As String, ValueList As List) As String
      • Initialize (Response As ServletResponse) As String
        Initializes the object. You can add parameters to this method if needed.
      • IsInitialized As Boolean
        Verifica se l'oggetto sia stato inizializzato.
      • RunFunction (function As String, ID As String, Params As List) As String
        Param = list or array: array as Map or String (array as Object is wrong)
      • RunFunctionWithResult (function As String, ID As String, Params As List) As String
      • RunMethod (Method As String, ID As String, Params As List) As String
        Param = list or array: array as Object is wrong - array as Map is correct
      • RunMethodWithResult (Method As String, ID As String, Params As List) As String
        Param = list or array: array as Object is wrong - array as Map is correct
      • SelectElement (ID As String) As String
      • SetCommand (etype As String, Method As String, property As String, ID As String, Params As List, Arg As List) As String
      • SetCSS (id As String, Params As List) As String
      • SetDialog (id As String, Params As List) As String
        Public Sub GetWidth As Object
        End Sub
      • SetHtml (id As String, Params As List) As String

        Public Sub SetHeight (Value As String)
        End Sub
      • SetPropriety (Property As String, Value As List) As String
      • SetText (ID As String, TextList As List) As String
      • SetVal (ID As String, ValueList As List) As String
    • Properties:
      • AutomaticEvents
  • ServletRequest
    • Fields:
      • CharacterEncoding As String
      • ConnectionAlive As Boolean
      • ContentLength As Long
      • ContentType As String
      • ID As String
      • LogActive As Boolean
      • LogFirstRefuse As Boolean
      • MultipartFilename As Map
      • RequestCookies As Map
      • RequestHeader As Map
      • RequestParameter As Map
      • RequestPostDataRow As List
      • Timeout As Long
    • Functions:
      • ArrayInsert (DataSource As Byte(), Index As Int, DataInsert As Byte()) As Byte()
      • ArrayRemove (Data As Byte(), Start As Int, Last As Int) As Byte()
      • Class_Globals As String
      • Close As String
      • Connected As Boolean
      • GetHeader (Name As String) As String
      • GetHeadersName As List
        can be used to iterate over Header
        Example
        <code>
        For Each Name As String In ServletRequest.GetHeadersName
        Log("Value = " & ServletRequest.GetHeader(Name))
        Next</code>
      • GetInputStream As InputStream
      • GetMethod As String
      • GetRequestHOST As String
      • GetRequestURI As String
      • GetWebSocketCompressDeflateAccept As Boolean
      • GetWebSocketCompressGzipAccept As Boolean
      • GetWebSocketMapData As Map
      • GetWebSocketStringData As String
      • Initialize (CallBack As Object, EventName As String, Sck As Socket) As String
        Initializes the object. You can add parameters to this method if needed.
      • IsInitialized As Boolean
        Verifica se l'oggetto sia stato inizializzato.
      • ParameterMap As Map
      • RemoteAddress As String
      • RemotePort As Int
      • SubArray2 (Data As Byte(), Start As Int, Last As Int) As Byte()
  • ServletResponse
    • Fields:
      • CharacterEncoding As String
      • ContentLenght As Int
      • ContentType As String
      • Status As Int
    • Functions:
      • Class_Globals As String
      • Close As String
      • Connected As Boolean
      • Initialize (Req As ServletRequest, ast As AsyncStreams, Sck As Socket) As String
        Initializes the object. You can add parameters to this method if needed.
      • IsInitialized As Boolean
        Verifica se l'oggetto sia stato inizializzato.
      • ResetCookies As String
      • SendFile (Dir As String, fileName As String) As String
        don't use DirAssets
      • SendFile2 (Dir As String, fileName As String, Content_Type As String) As String
      • SendNotFound (filenameNotFound As String) As String
      • SendRaw (Data As Byte()) As String
      • SendRedirect (Address As String) As String
      • SendString (Text As String) As String
        sending text with Header
      • SendWebSocketBinary (Data As Byte(), Masked As Boolean) As String
      • SendWebSocketClose As String
      • SendWebSocketPing As String
      • SendWebSocketPong As String
      • SendWebSocketString (Text As String, Masked As Boolean, Compressed As String) As String
        Cmpressed as Deflate=zlib, gzip, none - (set always none)
      • SetCookies (Name As String, Value As String) As String
        Set Cokies values on Browser
      • SetHeader (Name As String, Value As String) As String
      • Write (Text As String) As String
        Sending text without header to dynamically send more text after the SendString
    • Properties:
      • OutputStream As OutputStream [read only]
      • Query As QueryElement [read only]
  • httpServer
    • Events:
      • Handle (req As ServletRequest, resp As ServletResponse)
      • HandleWebSocket (req As ServletRequest, resp As ServletResponse)
      • NewConection (req As ServletRequest)
      • SwitchToWebSocket (req As ServletRequest, resp As ServletResponse)
      • UploadedFile (req As ServletRequest, resp As ServletResponse)
      • WebSocketClose (CloseCode As Int, CloseMessage As String)
    • Fields:
      • DigestAuthentication As Boolean
      • DigestPath As String
      • htdigest As List
      • IgnoreNC As Boolean
      • realm As String
      • Timeout As Int
    • Functions:
      • Class_Globals As String
      • GetMyIP As String
      • GetMyWifiIp As String
      • Initialize (CallBack As Object, EventName As String) As String
        Initializes the object. You can add parameters to this method if needed.
      • IsInitialized As Boolean
        Verifica se l'oggetto sia stato inizializzato.
      • Start (Port As Int)
        eg. Start(51051)
      • Stop As String
    • Properties:
      • TempPath As String [read only]
 

Attachments

  • aHttpServer 0.77.zip
    35.2 KB · Views: 165
  • jHttpServer 0.77.zip
    35.1 KB · Views: 173
  • iHttpServer 0.77.zip
    446 KB · Views: 153
Last edited:

Star-Dust

Expert
Licensed User
Longtime User
Update 0.74
  • Completed jQuery class
  • Extended WebSocket example and completed in all its parts

1623313792361.png

1623313857295.png

1623313910330.png


If you want to understand more about jQuery go to this thread
 
Last edited:

Star-Dust

Expert
Licensed User
Longtime User
Here you can try the example of a queue eliminator made with xHttpServer and WebSocket. The server is B4X, the client uses the browser of the device
 

Star-Dust

Expert
Licensed User
Longtime User
Dear Star Dust!
Can you (urgently) enter an accessible boolean variable into the server that blocks the loading progress event?
When I have completed the work and tested, I will release the final version, for now consider it a beta version.

Question: When the server opens a new request (Svr_Handle), is it already independent and parallel to the main thread?
From this event, can we launch a copy of the object of our script interpreter (dynamic page interpreter and script), and each instance will work without blocking other instances and the main thread?
At the moment a connection is accepted, data streaming is handled by an instance of the ServletRequest class and an instance of the ServletResponse class. They are not managed by the httpServer main class.

Also Android 4+ doesn't allow apps to make network calls on the main thread (see here) so
 

VB6_man

Member
Hello!
Your example of downloading a file to a page works well. And opening pages through a GET request also works.
But any attempt to download the file, even by copying your entire code into my program, results in an error:

java.lang.ArrayIndexOutOfBoundsException: src.length=90498 srcPos=-1 dst.length=90499 dstPos=0 length=90499

Also, it is not clear how to upload the file on different pages. Let's say my boot page is different from the Upload File. And then what? It looks like your boot code doesn't distinguish between request addresses at all. Or I'm wrong.

I checked the downloads again in different versions, even just copied your code to a clean project. Same mistake. Where to dig?
 

VB6_man

Member
1) I seem to have defeated the first error. But I don’t know how.

2) But the second question is relevant: What if the page that receives and processes the image has a name other than FileUpload?
For example, in my script there is a case when the same page creates a form and receives a form response.
On your server, is the response going to a fixed address?
Here is my test case:
Page Index {
Router (GET: /index.html)
Router (POST: /index.html)
Template Index
GET {
s =' This GET-test and create Upload form'
up = Web.UploadFile ("/ Index.html", "Title", "Signature")
}

POST {
s = "This Post - test"
up = Web.a ('/ index.html', 'Home')
}
)
 

Star-Dust

Expert
Licensed User
Longtime User
1) I seem to have defeated the first error. But I don’t know how.

2) But the second question is relevant: What if the page that receives and processes the image has a name other than FileUpload?
For example, in my script there is a case when the same page creates a form and receives a form response.
On your server, is the response going to a fixed address?
Here is my test case:
Page Index {
Router (GET: /index.html)
Router (POST: /index.html)
Template Index
GET {
s =' This GET-test and create Upload form'
up = Web.UploadFile ("/ Index.html", "Title", "Signature")
}

POST {
s = "This Post - test"
up = Web.a ('/ index.html', 'Home')
}
)
I did not understand the question
 

Ibrahim Saleh

Member
Licensed User
Longtime User
@Star-Dust Can I create a video streaming app using this library. I want to play a video from the local folder and feed chunks of data into the video player. This can be done using a httpserver that reads part of the video file and send the correct data to the video player. I was not able to produce such a function using the original HttpServer from Erel. Altho I was able to do it using jHttpServer.
My question is will this new HttpServer be able to do such a thing. Thanks in advance.
 

Star-Dust

Expert
Licensed User
Longtime User
@Star-Dust Can I create a video streaming app using this library. I want to play a video from the local folder and feed chunks of data into the video player. This can be done using a httpserver that reads part of the video file and send the correct data to the video player. I was not able to produce such a function using the original HttpServer from Erel. Altho I was able to do it using jHttpServer.
My question is will this new HttpServer be able to do such a thing. Thanks in advance.
I am unable to answer this question. I have no experience about it.

To better understand what you mean I can't do with Erel's HttpServer but I can with jHttpServer? What instructions do you use? Perhaps with more details I can understand better
 

ilan

Expert
Licensed User
Longtime User
@Star-Dust Can I create a video streaming app using this library. I want to play a video from the local folder and feed chunks of data into the video player. This can be done using a httpserver that reads part of the video file and send the correct data to the video player. I was not able to produce such a function using the original HttpServer from Erel. Altho I was able to do it using jHttpServer.
My question is will this new HttpServer be able to do such a thing. Thanks in advance.

do you mean something like this:
 

wl

Well-Known Member
Licensed User
Longtime User
Just tried the IOS version, the HTTP sample application (as found in one of the first topics in this thread).
The application builds and runs fine, but when I click on 'click' nothing is being displayed in the web viewer ?

Any idea ?

Thanks
 

wl

Well-Known Member
Licensed User
Longtime User
Sorry, never mind. Was wrong: it runs, but I should have opened a browser :)
 

laguilar

Member
Licensed User
Longtime User
Seems this library no longer works. When publishing, it brings the same "ITMS-90338: Non-public API usage" error as the iReleaseLogger library and mentions the app has referenced non-public symbols: __NSSetLogCStringFunction
 

Star-Dust

Expert
Licensed User
Longtime User
Seems this library no longer works. When publishing, it brings the same "ITMS-90338: Non-public API usage" error as the iReleaseLogger library and mentions the app has referenced non-public symbols: __NSSetLogCStringFunction
Dear friend, I just tried and everything works fine.
I don't think I use iReleaseLogger in my examples. In any case it must be removed as indicated here. But is not a problem with my library.

Try one of my examples and see if that works
 

laguilar

Member
Licensed User
Longtime User
Dear friend, I just tried and everything works fine.
I don't think I use iReleaseLogger in my examples. In any case it must be removed as indicated here. But is not a problem with my library.

Try one of my examples and see if that works
I just tried again, as well. I don't really want to create useless app entries in my App Store Connect by uploading one of your examples. But see my steps below:

--B4I IDE--
1. Build Release App
2. Download Last Build
3. Upload To App Store
4. Check email, got email stating ITMS-90338: Non-public API usage - The app references non-public symbols in APP_NAME: __NSSetLogCStringFunction
5. Uncheck iHttpServer in Libraries Manager
6. Increment Version
7. Build Release App
8. Download Last Build
9. Upload To App Store
10. Check email, no warnings, and approves in App Store Connect for testflight.

Few things to note:
I am using the Hosted Builder as I have a windows machine I develop with.
I have tried the above steps with and without the "Clean Project" between builds, makes no difference.
In my libraries manager, everything appears to be up to date except 2 libraries (iHttpUtils2 and XUI Views).
I am using B4I v 7.80.
I've attached a screenshot that displays some of my project properties with identifiable information obscured.
 

Attachments

  • Capture.PNG
    Capture.PNG
    123.2 KB · Views: 220

Star-Dust

Expert
Licensed User
Longtime User
I just tried again, as well. I don't really want to create useless app entries in my App Store Connect by uploading one of your examples. But see my steps below:

--B4I IDE--
1. Build Release App
2. Download Last Build
3. Upload To App Store
4. Check email, got email stating ITMS-90338: Non-public API usage - The app references non-public symbols in APP_NAME: __NSSetLogCStringFunction
5. Uncheck iHttpServer in Libraries Manager
6. Increment Version
7. Build Release App
8. Download Last Build
9. Upload To App Store
10. Check email, no warnings, and approves in App Store Connect for testflight.

Few things to note:
I am using the Hosted Builder as I have a windows machine I develop with.
I have tried the above steps with and without the "Clean Project" between builds, makes no difference.
In my libraries manager, everything appears to be up to date except 2 libraries (iHttpUtils2 and XUI Views).
I am using B4I v 7.80.
I've attached a screenshot that displays some of my project properties with identifiable information obscured.
It is not necessary to publish an example. You should run my example in DEBUG instead. To do this you need to change the package name.
I also use HOESTED BUILDER with windows.
If the example works, the problem is to be found in your App.

When you do this test tell me what the outcome is.

PS. Did it work for you before? Have you made any changes?
 

laguilar

Member
Licensed User
Longtime User
It is not necessary to publish an example. You should run my example in DEBUG instead. To do this you need to change the package name.
I also use HOESTED BUILDER with windows.
If the example works, the problem is to be found in your App.

When you do this test tell me what the outcome is.

PS. Did it work for you before? Have you made any changes?
Your mis-understanding. Everything works fine in debug mode. I can include the ihttpserver or ireleaselogger, or any other library for that matter. But once I attempt to upload it to testflight, I get an email from apple saying the app has issues that need to be resolved, and they mention the "ITMS-90338: Non-public API usage - The app references non-public symbols in APP_NAME: __NSSetLogCStringFunction" issue.

The issue is not within my application. As I mentioned before, 2 attempts in a row to publish, the only difference being that iHttpServer library is checked in Library Manager. Without iHttpServer it approves just fine, and with, it fails and I get the above email from apple.
 
Top