AHKhttp - HTTP Server

Post your working scripts, libraries and tools for AHK v1.1 and older
brutus_skywalker
Posts: 175
Joined: 24 Dec 2016, 13:16
Location: Antarctica

Re: AHKhttp - HTTP Server

Post by brutus_skywalker » 20 May 2017, 23:50

badpost
Last edited by brutus_skywalker on 27 Sep 2018, 09:44, edited 1 time in total.
Outsourcing Clicks & Presses Since 2004.
brutus_skywalker
Posts: 175
Joined: 24 Dec 2016, 13:16
Location: Antarctica

Re: AHKhttp - HTTP Server

Post by brutus_skywalker » 27 May 2017, 01:04

badpost
Last edited by brutus_skywalker on 27 Sep 2018, 09:44, edited 1 time in total.
Outsourcing Clicks & Presses Since 2004.
DanielToward13
Posts: 74
Joined: 18 May 2017, 10:56

Re: AHKhttp - HTTP Server

Post by DanielToward13 » 28 Jul 2017, 22:00

Thanks for sharing.
is it possible to access this HTTP Server using its IP address and port on the internet? is it secure?
Last edited by DanielToward13 on 28 Jul 2017, 22:02, edited 1 time in total.
User avatar
metacognition
Posts: 117
Joined: 22 Oct 2014, 05:57
Location: Alaska
Contact:

Re: AHKhttp - HTTP Server

Post by metacognition » 28 Jul 2017, 22:02

yes.
DanielToward13
Posts: 74
Joined: 18 May 2017, 10:56

Re: AHKhttp - HTTP Server

Post by DanielToward13 » 28 Jul 2017, 22:07

metacognition wrote:yes.
:thumbup: What are the steps to make it live on the internet? Only set the port in AHKsock and run the script?
User avatar
metacognition
Posts: 117
Joined: 22 Oct 2014, 05:57
Location: Alaska
Contact:

Re: AHKhttp - HTTP Server

Post by metacognition » 28 Jul 2017, 22:11

If you are using a Nat based router you would have to forward a port, on your router, to that specific port on your pc, using the local ip address, you are headed into deep water here my friend, much deeper than the scope of this forum/topic, I suggest googling about setting up a home http server and port forwarding.
User avatar
kczx3
Posts: 1640
Joined: 06 Oct 2015, 21:39

Re: AHKhttp - HTTP Server

Post by kczx3 » 25 Aug 2017, 11:33

Started playing around with this a bit and utilizing JS frameworks as I code in JS quite a bit now.

Requires Jxon.ahk as well in a lib folder. Please note, it does write json to the file system in the script's directory. There is likely a better way of handling the js and css.


EDIT: Updated the code some to work with pagination of the Github API and some additional CSS for appeal.

Code: Select all

#Persistent
#SingleInstance, force
SetBatchLines, -1

paths := {}
paths["/"] := Func("HelloWorld")
paths["/ajax"] := Func("handleAjax")
paths["/javascript"] := Func("javascript")
paths["/css"] := Func("css")
paths["404"] := Func("NotFound")
paths["/logo"] := Func("Logo")

server := new HttpServer()
server.LoadMimes(A_ScriptDir . "/mime.types")
server.SetPaths(paths)
server.Serve(8000)
return

Logo(ByRef req, ByRef res, ByRef server) {
    server.ServeFile(res, A_ScriptDir . "/logo.png")
    res.status := 200
}

NotFound(ByRef req, ByRef res) {
    res.SetBodyText("Page not found")
}

javascript(ByRef req, ByRef res) {
    js := getJS()
    res.SetBodyText(js)
    res.status := 200
}

css(ByRef req, ByRef res, server) {
    css := getCSS()
    res.headers["Content-Type"] := "text/css"
    res.SetBodyText(css)
    res.status := 200
}

handleAjax(ByRef req, ByRef res, server) {
    if (func := req.queries.func) {
        if (req.queries.params)
            params := StrSplit(req.queries.params, "|")
        retval := %func%(params ? params : [])
    }
    res.status := 200
    res.SetBodyText(retval)
}

write(params) {
    FileRead, repos, autohotkey_repositories.json
    FileDelete, autohotkey_repositories.json
    if (!repos)
        repos := {repos: []}
    else
        repos := Jxon_Load(repos)
    for index, item in params
        repos.repos.push(item)
    FileAppend, % Jxon_Dump(repos), autohotkey_repositories.json
    return Jxon_Dump(repos)
    
}

HelloWorld(ByRef req, ByRef res) {
    html := getHTML()
    res.SetBodyText(html)
    res.status := 200
}

#include, %A_ScriptDir%\AHKhttp.ahk
#include <AHKsock>
#Include <Jxon>

getHTML() {
    html := 
    ( LTrim Join
    "<!doctype html>
    <html lang='en'>
        <head>
            <meta charset='utf-8'>
            <title>Mithril and AHK, Wow!</title>
            <script src='//unpkg.com/mithril/mithril.js'></script>
            <link href='/css' rel='stylesheet' />
        </head>
        <body></body>
        <script src='/javascript'></script>
    </html>"
    )
    return html
}

getJS() {
    JS =
    ( LTrim Join`n
    var root = document.body;
    
    var handleClick = function(text) {
        window.open(text);
    };
    
    var getRepos = function(page) {
        m.request({
            method: "GET",
            url: "https://api.github.com/search/repositories?q=language:AutoHotkey&page=" + page
        }).then(function(data) {
            reposList.list = data.items;
        });
    };
    
    var reposList = {
        list: [],
        oninit: function(vnode) {
            vnode.state.page = vnode.attrs.page;
            m.request({
                method: "GET",
                url: "https://api.github.com/search/repositories?q=language:AutoHotkey&page=" + vnode.state.page
            }).then(function(data) {
                reposList.list = data.items;
            });
        },
        view: function(vnode) {
            return m("ul.list", reposList.list.map(function(repo) {
                    return m("li.list-item", 
                        m("span", {
                            onclick: function() {handleClick(repo.html_url)},
                            title: repo.description
                        }, repo.full_name)
                    `)
                })
            `)
        }
    };
    
    var navButtons = {
        view: function (vnode) {
            return [
                m("button", {onclick: function() {if (nav.currPage === 1) return; nav.currPage--; getRepos(nav.currPage)}}, "Previous"),
                m("span.currPage", vnode.attrs.page),
                m("button", {onclick: function() {nav.currPage++, getRepos(nav.currPage)}}, "Next")
            ];
        }
    };
    
    var nav = {
        currPage: 1,
        view: function(vnode) {
            return m(".container", [
                m(".nav", m(navButtons, {page: vnode.state.currPage})),
                m(reposList, {page: vnode.state.currPage})
            ]);
        }
    };
    
    m.mount(root, nav);
    )
    return js
}

getCSS() {
    CSS =
    ( LTrim Join`n
    .list {list-style:none;margin:0 0 10px;padding:0;display:flex;align-items:center;align-content:flex-end;justify-content:center;flex-direction:row;flex-wrap:wrap;flex-flow:wrap;}
    .list-item {background:#fafafa;border:1px solid #ddd;color:#333;display:block;margin:0 0 1px;padding:8px 15px;text-decoration:none;width: 20`%}
    .list-item > span:hover {text-decoration:underline;cursor: pointer;}
    .nav {padding:5px;margin-bottom:20px;border: 1px solid #ddd;border-radius:5px;display: flex;align-items:center;justify-content:center;}
    .currPage {margin: 1`%;}
    )
    return CSS
}
wywywywy
Posts: 3
Joined: 12 Jan 2019, 21:15

Re: AHKhttp - HTTP Server

Post by wywywywy » 13 Jan 2019, 05:55

Hi,

There's a memory leak somewhere, even when using the example scripts.

After receiving some amount of requests (1000? 2000?) it will crash.

I am not sure if the problem is in AhkHttp.ahk or AhkSock.ahk.

I guess maybe an object or array is not cleared somewhere? I have had a look but couldn't find anything.

Has anyone any idea please?

Thanks.
magusneo
Posts: 45
Joined: 30 Sep 2013, 06:34

Re: AHKhttp - HTTP Server

Post by magusneo » 22 May 2019, 06:02

wywywywy wrote:
13 Jan 2019, 05:55
Hi,

There's a memory leak somewhere, even when using the example scripts.

After receiving some amount of requests (1000? 2000?) it will crash.

I am not sure if the problem is in AhkHttp.ahk or AhkSock.ahk.

I guess maybe an object or array is not cleared somewhere? I have had a look but couldn't find anything.

Has anyone any idea please?

Thanks.

There is memory leak.
Try this

Code: Select all

class Uri
{
    Decode(str) {
        Loop
            If RegExMatch(str, "i)(?<=%)[\da-f]{1,2}", hex)
                StringReplace, str, str, `%%hex%, % Chr("0x" . hex), All
            Else Break
        Return, str
    }

    Encode(str) {
        f = %A_FormatInteger%
        SetFormat, Integer, Hex
        If RegExMatch(str, "^\w+:/{0,2}", pr)
            StringTrimLeft, str, str, StrLen(pr)
        StringReplace, str, str, `%, `%25, All
        Loop
            If RegExMatch(str, "i)[^\w\.~%]", char)
                StringReplace, str, str, %char%, % "%" . Asc(char), All
            Else Break
        SetFormat, Integer, %f%
        Return, pr . str
    }
}

class HttpServer
{
    static servers := {}

    LoadMimes(file) {
        if (!FileExist(file))
            return false

        FileRead, data, % file
        types := StrSplit(data, "`n")
        this.mimes := {}
        for i, data in types {
            info := StrSplit(data, " ")
            type := info.Remove(1)
            ; Seperates type of content and file types
            info := StrSplit(LTrim(SubStr(data, StrLen(type) + 1)), " ")

            for i, ext in info {
                this.mimes[ext] := type
            }
        }
        return true
    }

    GetMimeType(file) {
        default := "text/plain"
        if (!this.mimes)
            return default

        SplitPath, file,,, ext
        type := this.mimes[ext]
        if (!type)
            return default
        return type
    }

    ServeFile(ByRef response, file) {
        f := FileOpen(file, "r")
        length := f.RawRead(data, f.Length)
        f.Close()

        response.SetBody(data, length)
        res.headers["Content-Type"] := this.GetMimeType(file)
    }

    SetPaths(paths) {
        this.paths := paths
    }

    Handle(ByRef request) {
        response := new HttpResponse()
        if (!this.paths[request.path]) {
            func := this.paths["404"]
            response.status := 404
            if (func)
                func.(request, response, this)
            return response
        } else {
            this.paths[request.path].(request, response, this)
        }
        return response
    }

    Serve(port) {
        this.port := port
        HttpServer.servers[port] := this

        AHKsock_Listen(port, "HttpHandler")
    }
}

HttpHandler(sEvent, iSocket = 0, sName = 0, sAddr = 0, sPort = 0, ByRef bData = 0, bDataLength = 0) {
    static sockets := {}

    if (!sockets[iSocket]) {
        sockets[iSocket] := new Socket(iSocket)
        AHKsock_SockOpt(iSocket, "SO_KEEPALIVE", true)
    }
    socket := sockets[iSocket]

    if (sEvent == "DISCONNECTED") {
        socket.request := false
        sockets[iSocket] := false
    } else if (sEvent == "SEND") {
        if (socket.TrySend()) {
            socket.Close()
        }

    } else if (sEvent == "RECEIVED") {
        server := HttpServer.servers[sPort]

        text := StrGet(&bData, "UTF-8")

        ; New request or old?
        if (socket.request) {
            ; Get data and append it to the existing request body
            socket.request.bytesLeft -= StrLen(text)
            socket.request.body := socket.request.body . text
            request := socket.request
        } else {
            ; Parse new request
            request := new HttpRequest(text)

            length := request.headers["Content-Length"]
            request.bytesLeft := length + 0

            if (request.body) {
                request.bytesLeft -= StrLen(request.body)
            }
        }

        if (request.bytesLeft <= 0) {
            request.done := true
        } else {
            socket.request := request
        }

        if (request.done || request.IsMultipart()) {
            response := server.Handle(request)
            if (response.status) {
                socket.SetData(response.Generate())
            }
        }
        if (socket.TrySend()) {
            if (!request.IsMultipart() || request.done) {
                socket.Close()
            }
        }    
        
    }
}

class HttpRequest
{
    __New(data = "") {
        if (data)
            this.Parse(data)
    }

    GetPathInfo(top) {
        results := []
        while (pos := InStr(top, " ")) {
            results.Insert(SubStr(top, 1, pos - 1))
            top := SubStr(top, pos + 1)
        }
        this.method := results[1]
        this.path := Uri.Decode(results[2])
        this.protocol := top
    }

    GetQuery() {
        pos := InStr(this.path, "?")
        query := StrSplit(SubStr(this.path, pos + 1), "&")
        if (pos)
            this.path := SubStr(this.path, 1, pos - 1)

        this.queries := {}
        for i, value in query {
            pos := InStr(value, "=")
            key := SubStr(value, 1, pos - 1)
            val := SubStr(value, pos + 1)
            this.queries[key] := val
        }
    }

    Parse(data) {
        this.raw := data
        data := StrSplit(data, "`n`r")
        headers := StrSplit(data[1], "`n")
        this.body := LTrim(data[2], "`n")

        this.GetPathInfo(headers.Remove(1))
        this.GetQuery()
        this.headers := {}

        for i, line in headers {
            pos := InStr(line, ":")
            key := SubStr(line, 1, pos - 1)
            val := Trim(SubStr(line, pos + 1), "`n`r ")

            this.headers[key] := val
        }
    }

    IsMultipart() {
        length := this.headers["Content-Length"]
        expect := this.headers["Expect"]

        if (expect = "100-continue" && length > 0)
            return true
        return false
    }
}

class HttpResponse
{
    __New() {
        this.headers := {}
        this.status := 0
        this.protocol := "HTTP/1.1"
        this.buffer:=""
        this.SetBodyText("")
    }
	__Delete(){
		this.buffer:=""
	}
    
    Generate() {
        FormatTime, date,, ddd, d MMM yyyy HH:mm:ss
        this.headers["Date"] := date

        headers := this.protocol . " " . this.status . "`r`n"
        for key, value in this.headers {
            headers := headers . key . ": " . value . "`r`n"
        }
        headers := headers . "`r`n"
        length := this.headers["Content-Length"]

        this.buffer := new Buffer((StrLen(headers) * 2) + length)
        this.buffer.WriteStr(headers)

        this.buffer.Append(this.body)
        this.buffer.Done()

        return this.buffer
    }

    SetBody(ByRef body, length) {
        this.body := new Buffer(length)
        this.body.Write(&body, length)
        this.headers["Content-Length"] := length
    }

    SetBodyText(text) {
        this.body := Buffer.FromString(text)
        this.headers["Content-Length"] := this.body.length
    }


}

class Socket
{
    __New(socket) {
        this.socket := socket
    }

    Close(timeout = 5000) {
        AHKsock_Close(this.socket, timeout)
    }

    SetData(data) {
        this.data := data
    }

    TrySend() {
        if (!this.data || this.data == "")
            return false

        p := this.data.GetPointer()
        length := this.data.length

        this.dataSent := 0
        loop {
            if ((i := AHKsock_Send(this.socket, p, length - this.dataSent)) < 0) {
                if (i == -2) {
                    return
                } else {
                    ; Failed to send
                    return
                }
            }

            if (i < length - this.dataSent) {
                this.dataSent += i
            } else {
                break
            }
        }
        this.dataSent := 0
        this.data := ""

        return true
    }
}

class Buffer
{
    __New(len) {
        this.SetCapacity("buffer", len)
        this.length := 0
    }
	__Delete(){
		this.buffer:=""
	}

    FromString(str, encoding = "UTF-8") {
        length := Buffer.GetStrSize(str, encoding)
        this.buffer := new Buffer(length)
        this.buffer.WriteStr(str)
        return this.buffer
    }

    GetStrSize(str, encoding = "UTF-8") {
        encodingSize := ((encoding="utf-16" || encoding="cp1200") ? 2 : 1)
        ; length of string, minus null char
        return StrPut(str, encoding) * encodingSize - encodingSize
    }

    WriteStr(str, encoding = "UTF-8") {
        length := this.GetStrSize(str, encoding)
        VarSetCapacity(text, length)
        StrPut(str, &text, encoding)

        this.Write(&text, length)
        return length
    }

    ; data is a pointer to the data
    Write(data, length) {
        p := this.GetPointer()
        DllCall("RtlMoveMemory", "uint", p + this.length, "uint", data, "uint", length)
        this.length += length
    }

    Append(ByRef buffer) {
        destP := this.GetPointer()
        sourceP := buffer.GetPointer()

        DllCall("RtlMoveMemory", "uint", destP + this.length, "uint", sourceP, "uint", buffer.length)
        this.length += buffer.length
    }

    GetPointer() {
        return this.GetAddress("buffer")
    }

    Done() {
        this.SetCapacity("buffer", this.length)
    }
}

User avatar
nnnik
Posts: 4500
Joined: 30 Sep 2013, 01:01
Location: Germany

Re: AHKhttp - HTTP Server

Post by nnnik » 12 Jun 2019, 09:05

Would you mind providing a new example code?
Recommends AHK Studio
magusneo
Posts: 45
Joined: 30 Sep 2013, 06:34

Re: AHKhttp - HTTP Server

Post by magusneo » 28 Jun 2019, 20:30

nnnik wrote:
12 Jun 2019, 09:05
Would you mind providing a new example code?
It's same to the first topic.Just fix memory leak.

Code: Select all

#Persistent
#SingleInstance, force
SetBatchLines, -1

paths := {}
paths["/"] := Func("HelloWorld")
paths["404"] := Func("NotFound")
paths["/logo"] := Func("Logo")

server := new HttpServer()
server.LoadMimes(A_ScriptDir . "/mime.types")
server.SetPaths(paths)
server.Serve(8000)
return

Logo(ByRef req, ByRef res, ByRef server) {
    server.ServeFile(res, A_ScriptDir . "/logo.png")
    res.status := 200
}

NotFound(ByRef req, ByRef res) {
    res.SetBodyText("Page not found")
}

HelloWorld(ByRef req, ByRef res) {
    res.SetBodyText("Hello World")
    res.status := 200
}


#include,AHKhttp.ahk
#include,ahksock-unicode.ahk
BuggyB
Posts: 44
Joined: 25 Mar 2019, 17:59

Re: AHKhttp - HTTP Server

Post by BuggyB » 11 Dec 2019, 14:32

#include,ahksock-unicode.ahk
what is it? Is there a special unicode version? I cannot find another reference to this on this forum
User avatar
CrashKoeck
Posts: 3
Joined: 08 Nov 2020, 17:17
Contact:

Re: AHKhttp - HTTP Server

Post by CrashKoeck » 08 Nov 2020, 18:28

Amazing work @Skittlez and great patch @magusneo! With the patch I'm able to get up to around 10K calls before running into an issue. But, there is definitely an issue still.

At about 3,000 calls during stress testing I do notice everything tends to slow down quite a bit and at around 10,000 calls I get the error Function recursion limit exceeded (attached pic)

I have tried to figure out exactly what is happening with this function but haven't had any luck. I have also tried to basically "reset" the HTTP server to clear everything at around 2,500 calls to give quite a bit of headroom but that hasn't worked either.

If anyone has any idea on how to extend this past 10K calls (looking like 50K is what I'd need to aim for) OR how to basically reset this without exiting the program, that would be awesome.
Attachments
Screenshot 2020-11-07 223403.png
Function recursion limit exceeded
Screenshot 2020-11-07 223403.png (13.1 KiB) Viewed 2666 times
magusneo
Posts: 45
Joined: 30 Sep 2013, 06:34

Re: AHKhttp - HTTP Server

Post by magusneo » 16 Nov 2020, 07:21

CrashKoeck wrote:
08 Nov 2020, 18:28


At about 3,000 calls during stress testing I do notice everything tends to slow down quite a bit and at around 10,000 calls I get the error Function recursion limit exceeded (attached pic)
What's your testing script?
User avatar
CrashKoeck
Posts: 3
Joined: 08 Nov 2020, 17:17
Contact:

Re: AHKhttp - HTTP Server

Post by CrashKoeck » 19 Nov 2020, 06:25

magusneo wrote:
16 Nov 2020, 07:21
CrashKoeck wrote:
08 Nov 2020, 18:28


At about 3,000 calls during stress testing I do notice everything tends to slow down quite a bit and at around 10,000 calls I get the error Function recursion limit exceeded (attached pic)
What's your testing script?
Something I threw together quick that allows me to adjust the parameters for each test. I hit the ~10K limit whether I let it just run wild with no delays built in or add a couple second delay between each call.

Code: Select all

#NoEnv
#SingleInstance, Off

global theURL
global targetcalls := 50000
global callCount := 0
global Prog := 0
global CallTimeAvgTally := 0 
global CallTimeAvg := 0 
global ServerSleep := 0
global SleepCount := 0
global SleepRestTrigger := 250
global ServerRestSeconds := 30
global ServerRestms := ServerRestSeconds * 1000

Progress, x100 y100 w750 m cbe6820a cw222222 cte6820a c01, Waiting for user input...`nWaiting for user input...`nWaiting for user input...`nWaiting for user input...`nWaiting for user input...`nWaiting for user input...`nWaiting for user input...`nWaiting for user input...`nWaiting for user input...`nWaiting for user input..., Calls: 0/0, Stress Tester (Press Esc to quit)
Progress, 100

InputBox, targetcalls , Server Stress Tester, Target successful calls,,300,125,,, Locale,, %targetcalls%
if ErrorLevel
    ExitApp

InputBox, theURL , Server Stress Tester, Select URL to stress test,,300,125,,, Locale,, 
if ErrorLevel
    ExitApp

InputBox, ServerSleep , Server Stress Tester, Delay between calls (ms),,300,125,,, Locale,, %ServerSleep%
if ErrorLevel
    ExitApp

SleepRestTrigger += ServerSleep
InputBox, SleepRestTrigger , Server Stress Tester, Sleep threshold (ms),,300,125,,, Locale,, %SleepRestTrigger%
if ErrorLevel
    ExitApp
	
InputBox, ServerRestSeconds , Server Stress Tester, Sleep duration (s),,300,125,,, Locale,, %ServerRestSeconds%
if ErrorLevel
    ExitApp

Progress, 0, Connecting to server...`nConnecting to server...`nConnecting to server...`nConnecting to server...`nConnecting to server...`nConnecting to server...`nConnecting to server...`nConnecting to server...`nConnecting to server...`nConnecting to server..., Calls: 0/%targetcalls%, Stress Tester (Press Esc to quit)

global targetcallsadjusted := 100/targetcalls

Stress()

Return

Stress(){
	TestStart := A_TickCount
	Try {
		tester := ComObjCreate("WinHttp.WinHttpRequest.5.1")
		CallTime := A_TickCount
		Loop
		{
			callCount := A_Index
			tester.Open("GET",theURL)
			tester.Send()
			output := tester.ResponseText
			outputstatus := tester.Status
			Prog += targetcallsadjusted
			
			x := A_TickCount - CallTime - ServerSleep
			
			if(x > SleepRestTrigger and callCount > 1){
				If(SleepCount > 10){
					MsgBox, 4096, Server Rest Exceeded, Server was allowed to rest for %ServerRestSeconds% seconds 10 times and still exceeded %SleepRestTrigger%ms.`nURL: %theURL%`nReturned Data: %output%`nStatus: %outputstatus%`nTarget Calls: %targetcalls%`nCurrent Call Time: %x%ms`nAvg Call Time: %CallTimeAvg%`nCall Delay: %ServerSleep%`nSleep Cycles: %SleepCount%`nSleep Threshold: %SleepRestTrigger%ms`nSleep Duration: %ServerRestSeconds%s, Calls: %callCount%
					ExitApp
				} else {
					Progress, %Prog%, URL: %theURL%`nReturned Data: %output%`nStatus: %outputstatus%`nCurrent Call Time: %x%ms`nAvg Call Time: %CallTimeAvg%`nCall Delay: %ServerSleep%`nSleep Cycles: Sleeping...`nSleep Threshold: %SleepRestTrigger%ms`nSleep Duration: %ServerRestSeconds%s, Calls: %callCount%/%targetcalls%, Stress Tester (Press Esc to quit)
					Sleep, % ServerRestms
					SleepCount++
				}
			}
			
			CallTime := A_TickCount
			CallTimeAvgTally += x
			if(A_Index < 100){
				CallTimeAvg := "Calculating..."
			} else {
				CallTimeAvg := Round(CallTimeAvgTally/callCount) . "ms"
			}

			Progress, %Prog%, URL: %theURL%`nReturned Data: %output%`nStatus: %outputstatus%`nCurrent Call Time: %x%ms`nAvg Call Time: %CallTimeAvg%`nCall Delay: %ServerSleep%`nSleep Cycles: %SleepCount%`nSleep Threshold: %SleepRestTrigger%ms`nSleep Duration: %ServerRestSeconds%s, Calls: %callCount%/%targetcalls%, Stress Tester (Press Esc to quit)
			
			if(Prog >= 100){
				TestDuration := (A_TickCount - TestStart) / 1000
				MsgBox,4096,, Sucessfully made %callCount% calls in %TestDuration% seconds.
				ExitApp
			}
			
			Sleep, % ServerSleep
		}
	} catch e {
		MsgBox,4096, ERROR, % callCount . " calls were made before there was an error`n`nWhat: " . e.what . "`n-----`nFile: " . e.file . "`n-----`nLine: " . e.line . "`n-----`nMessage: " . e.message . "`n-----`nExtra: " . e.extra . "`n-----`nRAW: " . e
		MsgBox,4096, ERROR, URL: %theURL%`nReturned Data: %output%`nStatus: %outputstatus%`nTarget Calls: %targetcalls%`nCalls: %callCount%`nCurrent Call Time: %x%ms`nAvg Call Time: %CallTimeAvg%`nCall Delay: %ServerSleep%`nSleep Cycles: %SleepCount%`nSleep Threshold: %SleepRestTrigger%ms`nSleep Duration: %ServerRestSeconds%s
		ExitApp
	}
}

Esc::
	ExitApp
return
CotswoldsMaker
Posts: 12
Joined: 16 Dec 2020, 04:42

Re: AHKhttp - HTTP Server

Post by CotswoldsMaker » 09 Feb 2021, 19:10

Hi all,

I see this is quiet an old thread, but I would love to everyone's thoughts on this. I have started using the above code (thanks everyone for sharing) and it works well. I am trying to build an IPC (interprocess communication) using HTTPS (note the 's'). Anyone had success using the above code with SSL in https?

Cheers
Mango123456
Posts: 3
Joined: 29 Jun 2019, 22:43

Re: AHKhttp - HTTP Server

Post by Mango123456 » 15 May 2021, 10:51

By restarting the server every 1000 hits, I was able to get up to 21486 hits before it crashed.
User avatar
joedf
Posts: 8940
Joined: 29 Sep 2013, 17:08
Location: Canada
Contact:

Re: AHKhttp - HTTP Server

Post by joedf » 15 May 2021, 15:43

Sounds like memory leaks... ? :think:
Image Image Image Image Image
Windows 10 x64 Professional, Intel i5-8500, NVIDIA GTX 1060 6GB, 2x16GB Kingston FURY Beast - DDR4 3200 MHz | [About Me] | [About the AHK Foundation] | [Courses on AutoHotkey]
[ASPDM - StdLib Distribution] | [Qonsole - Quake-like console emulator] | [LibCon - Autohotkey Console Library]
KiddoV
Posts: 13
Joined: 11 May 2020, 20:29

Re: AHKhttp - HTTP Server

Post by KiddoV » 15 Jul 2021, 15:29

Anyone still using this lib?
Any updated code to fix issues so far?
User avatar
CrashKoeck
Posts: 3
Joined: 08 Nov 2020, 17:17
Contact:

Re: AHKhttp - HTTP Server

Post by CrashKoeck » 15 Jul 2021, 23:19

@KiddoV still using it, still have memory leak issues. What I’ve done as a workaround is have the server basically refresh automatically after 7,500 calls. At about 10k it either slows down drastically or crashes.
Post Reply

Return to “Scripts and Functions (v1)”