Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- #include <EditConstants.au3>
- #include <GUIConstantsEx.au3>
- #include <StaticConstants.au3>
- #include <WindowsConstants.au3>
- #Region ### START Koda GUI section ### Form=
- $Form1 = GUICreate("Example AutoIt Http", 300, 150, 192, 124)
- $GUIMethod = GUICtrlCreateLabel("Method", 0, 0, 300, 20, BitOR($SS_CENTER, $SS_CENTERIMAGE))
- $GUIBody = GUICtrlCreateEdit("", 0, 20, 300, 130, BitOR($ES_AUTOVSCROLL, $ES_WANTRETURN, $ES_READONLY), 0)
- GUICtrlSetColor(-1, 0x0000FF)
- GUISetState(@SW_SHOW)
- #EndRegion ### END Koda GUI section ###
- #cs
- // javascript post data example 1
- fetch('http://127.0.0.1:3000', {
- method: 'POST',
- body: 'data example',
- })
- // javascript post data example 2
- fetch('http://127.0.0.1:3000', {
- method: 'POST',
- body: JSON.stringify({ timestamp: Date.now(), href: window.location.href, title: document.title }),
- })
- #ce
- #Region Init
- ; step 1
- Global $Listener = HttpInit(3000) ; listen on port 3000
- OnAutoItExitRegister("OnAutoItExit")
- Func HttpInit($Port)
- TCPStartup()
- Opt("TCPTimeout", 20)
- Return TCPListen("0.0.0.0", $Port, 100)
- EndFunc ;==>HttpInit
- Func OnAutoItExit()
- If $Listener > 0 Then TCPCloseSocket($Listener)
- TCPShutdown()
- EndFunc ;==>OnAutoItExit
- ; step 2
- Local $aQueryData[1][5] = [[0]]
- Local $bReceived, $urlReq, $method, $ContentLength, $ContentBody, $ContentType, $Referer, $AcceptEncoding, $Header_Expect, $iSocket = -1
- #EndRegion
- While 1
- #Region Serve
- ; step 3
- HttpServe($Listener, $aQueryData, $bReceived, $urlReq, $method, $ContentLength, $ContentBody, $ContentType, $Referer, $AcceptEncoding, $Header_Expect, $iSocket)
- ; get method & path
- If $method <> "" Then
- GUICtrlSetData($GUIMethod, $method & " " & $urlReq)
- EndIf
- ; get body
- If $ContentBody <> "" Then
- GUICtrlSetData($GUIBody, $ContentBody)
- EndIf
- #EndRegion
- $nMsg = GUIGetMsg()
- Switch $nMsg
- Case $GUI_EVENT_CLOSE
- Exit
- EndSwitch
- WEnd
- #Region Original source code from https://www.autoitscript.com/forum/topic/201673-json-http-post-serverlistener/page/2/?tab=comments#comment-1447447
- Func HttpServe(ByRef $Listener, ByRef $aQueryData, ByRef $bReceived, ByRef $urlReq, ByRef $method, ByRef $ContentLength, ByRef $ContentBody, ByRef $ContentType, ByRef $Referer, ByRef $AcceptEncoding, ByRef $Header_Expect, ByRef $iSocket)
- If $iSocket = -1 Then
- $iSocket = TCPAccept($Listener)
- If @error Then
- MsgBox(0, "TCPAccept", "TCPAccept error " & @error)
- Return False
- EndIf
- Else
- $buffer = StringToBinary("")
- Do
- $bReceived = TCPRecv($iSocket, 4096, 1)
- $errTCPRecv = @error
- $extTCPRecv = @extended
- $buffer &= $bReceived
- If DiscernData(BinaryToString($buffer, 4), $urlReq, $method, $ContentLength, $ContentBody, $ContentType, $Referer, $aQueryData, $AcceptEncoding, $Header_Expect) Then ExitLoop
- Until $extTCPRecv Or $bReceived = ""
- If $errTCPRecv Or $urlReq = "" Then
- TCPCloseSocket($iSocket)
- $iSocket = -1
- Else
- If $Header_Expect = 100 Then
- HttpSender($iSocket, $AcceptEncoding, "", "text/html", "100 Continue")
- Sleep(200)
- Return
- EndIf
- ; process requests here
- ; response
- HttpSender($iSocket, $AcceptEncoding, 'AutoIt Http Server', 'text/plain')
- EndIf
- EndIf
- EndFunc ;==>HttpServe
- ; example of a "more proper" way to send back a response
- Func HttpSender(ByRef $iSocket, ByRef $AcceptEncoding, $sHtmlText, $ContentType = "text/html", $ResponseStatusCode = "200 OK")
- #forceref $AcceptEncoding
- Local $bHtmlText = Binary($sHtmlText)
- Local $_Head = "HTTP/1.1 " & $ResponseStatusCode & @CRLF ; https://en.wikipedia.org/wiki/List_of_HTTP_status_codes
- $_Head &= "Content-Type: " & $ContentType & @CRLF ; ..so the client knows what is getting.
- $_Head &= "Connection: close" & @CRLF ; SideNote: ..an interaction takes 10 ms., is there a need for "muti-concurrent" code ? ;)
- ; allow CORS header
- $_Head &= "Access-Control-Allow-Origin: *" & @CRLF
- $_Head &= "Access-Control-Allow-Headers: *" & @CRLF
- $_Head &= "Access-Control-Allow-Methods: *" & @CRLF
- $_Head &= "Access-Control-Allow-Credentials: true" & @CRLF
- ;~ If StringInStr($AcceptEncoding, "gzip") Then ; If you "#include <ZLIB.au3>" then you can compress the data.
- ;~ $bHtmlText = _ZLIB_GZCompress($bHtmlText, 5) ; It takes longer ( say 5 ms. ) to compress but on a slow connection, delivery is faster.
- ;~ $_Head &= "Content-Encoding: gzip" & @CRLF ; ..tho, if sending a compressed file, say a ZIP file, this is not to be used.
- ;~ EndIf
- $_Head &= "Content-Lenght: " & BinaryLen($bHtmlText) & @CRLF ; this is a must for binary file send. Might as well use it for everything.
- ;~ $_Head &= "Content-MD5: " & _Base64Encode(_Crypt_HashData($bHtmlText, $CALG_MD5)) & @CRLF ; https://tools.ietf.org/html/rfc1864 ; obsolete, https://stackoverflow.com/questions/8300471/is-content-md5-field-in-the-http-response-universal
- $_Head &= @CRLF ; end of header marker
- $_Head = Binary($_Head)
- TCPSendBinary($iSocket, $_Head) ; Send the head
- TCPSendBinary($iSocket, $bHtmlText) ; Send the body ( html or file, as delimited by the header )
- EndFunc ;==>HttpSender
- Func TCPSendBinary(ByRef $hSocket, ByRef $bData)
- Local $iBytesSent, $iBytesTotalSent = 0, $iBytesTotal = BinaryLen($bData)
- Do
- $iBytesSent = TCPSend($hSocket, $bData)
- If @error Then ExitLoop
- $iBytesTotalSent += $iBytesSent
- $bData = BinaryMid($bData, $iBytesSent + 1, BinaryLen($bData) - $iBytesSent)
- Until 0 = BinaryLen($bData)
- Return SetError(0, Int($iBytesTotalSent <> $iBytesTotal), $iBytesTotalSent)
- EndFunc ;==>TCPSendBinary
- Func DiscernData($buffer, ByRef $urlReq, ByRef $method, ByRef $ContentLength, ByRef $ContentBody, ByRef $ContentType, ByRef $Referer, ByRef $aQueryData, ByRef $AcceptEncoding, ByRef $Header_Expect)
- If $Header_Expect = 100 Then ; we were waiting for the body ( $ContentLength )
- $Header_Expect = 0 ; as we are not waiting anymore.
- $aQueryData = DiscernQuery2array($urlReq, $buffer, $ContentType) ; data is the $buffer. $urlReq and $ContentType should be the same as it hasn't changed.
- Return $ContentLength = StringLen($buffer) ; ..to flag that is all good.
- EndIf
- $urlReq = "" ; $aQueryData holds the query as an array but a JSON string will need extra coding.
- $method = "" ; If the $aQueryData[1][1] = "" then is likely a JSON string
- $Header_Expect = 0
- $ContentLength = 0 ; In this example, at first, all I wanted, is to know that the data sent is full
- $ContentBody = "" ; and complete, to speed up the loop ( and save about 100 ms. of timeout )
- Local $_Head = StringLeft($buffer, StringInStr($buffer, @CRLF & @CRLF) - 1)
- $ContentBody = StringTrimLeft($buffer, StringLen($_Head) + 4)
- Local $_BodyLen = StringLen($ContentBody)
- Local $aCRLF = StringSplit($_Head, @CRLF, 1)
- If UBound($aCRLF) < 2 Then Return
- Local $aSpaceSplit = StringSplit($aCRLF[1], " ")
- If UBound($aSpaceSplit) < 3 Then Return
- $method = $aSpaceSplit[1]
- $urlReq = $aSpaceSplit[2]
- For $n = 2 To $aCRLF[0]
- $aSpaceSplit = StringSplitHeader($aCRLF[$n])
- If UBound($aSpaceSplit) < 3 Then ContinueLoop
- If $aSpaceSplit[1] = "Content-Length" Then $ContentLength = Int($aSpaceSplit[2]) ; tis should be equal to StringLen($ContentBody)
- If $aSpaceSplit[1] = "Content-Type" Then $ContentType = $aSpaceSplit[2] ; Discern if is JSON, when needed
- If $aSpaceSplit[1] = "Referer" Then $Referer = $aSpaceSplit[2] ; Discern if is from "/home/"
- If $aSpaceSplit[1] = "Accept-Encoding" Then $AcceptEncoding = $aSpaceSplit[2] ; Discern if to use GZIP
- If $aSpaceSplit[1] = "Expect" Then $Header_Expect = Int($aSpaceSplit[2]) ; Discern if Expect: 100-continue
- ;~ ; https://www.ietf.org/rfc/rfc1864.txt ; https://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html
- ;~ If $aSpaceSplit[1] = "Content-MD5" Then $Header_Content_MD5 = _Base64Decode($aSpaceSplit[2]) ; Content-MD5: Q2hlY2sgSW50ZWdyaXR5IQ==
- Next
- If $Header_Expect = 100 Then Return 1 ; ..there is no data at this point, just header.
- Switch StringUpper($method)
- Case "GET"
- $aQueryData = DiscernQuery2array($urlReq, Default, $ContentType) ; data is part of the URL
- Case Else
- $aQueryData = DiscernQuery2array($urlReq, $ContentBody, $ContentType) ; data is part of the body
- EndSwitch
- Return $ContentLength = $_BodyLen And StringLen($method)
- EndFunc ;==>DiscernData
- Func StringSplitHeader($sStr)
- Local $i = StringInStr($sStr, ":")
- If Not $i Then Return SetError(0, 2, "") ; the https://tools.ietf.org/html/rfc2616 talks about the ":"
- Local $a[3] = [2, "", ""] ; but not the space next to it as a delimiter of the field.
- $a[1] = StringLeft($sStr, $i - 1) ; To avoid mishaps, this function takes care of it.
- $a[2] = StringStripWS(StringTrimLeft($sStr, $i), 3)
- Return SetError(0, ($a[2] = "" ? 1 : 0), $a)
- EndFunc ;==>StringSplitHeader
- Func DiscernGetFragment($urlReq)
- Local $a = StringSplit($urlReq, "#")
- If UBound($a) < 3 Then Return ""
- Return $a[$a[0]]
- EndFunc ;==>DiscernGetFragment
- Func DiscernQuery2array(ByRef $urlReq, $ContentBody = Default, $ContentType = Default)
- Local $sContentPath, $sContentQuery
- Local $sFragment = DiscernGetFragment($urlReq)
- If $ContentBody = Default Then
- Local $aQueryData[1][5] = [[0, "", $sFragment, $ContentType, ""]]
- Local $i = StringInStr($urlReq, "?")
- If Not $i Then Return $aQueryData
- $sContentPath = StringLeft($urlReq, $i - 1)
- $sContentQuery = StringTrimLeft($urlReq, $i)
- ElseIf StringInStr($ContentType, "application/json") Then
- Local $aQuery[2][5] = [[1, $urlReq, $sFragment, $ContentType, ""], [$ContentBody, "", "", "", ""]]
- Return $aQuery ; is a json string, so better not StringSplit() it.
- Else
- $sContentPath = $urlReq
- $sContentQuery = $ContentBody
- EndIf
- Local $b, $n, $a = StringSplit($sContentQuery, "&")
- $i = 0
- Local $aQuery[UBound($a) + 1][5]
- $aQuery[0][3] = $ContentType ; for debug
- For $n = 1 To UBound($a) - 1
- $b = StringSplit($a[$n], "=")
- $i += 1
- If $b[0] > 0 Then $aQuery[$i][0] = $b[1] ; name
- If $b[0] > 1 Then $aQuery[$i][1] = $b[2] ; value
- Next
- $aQuery[0][0] = $i ; this holds the name=value count
- $aQuery[0][1] = $sContentPath ; this holds the path ( minus the query if is a GET mathod )
- $aQuery[0][2] = $sFragment ; this would hold the fragment ( https://en.wikipedia.org/wiki/Fragment_identifier )
- ReDim $aQuery[$i + 1][5]
- Return $aQuery
- EndFunc ;==>DiscernQuery2array
- Func _Base64Encode($input) ; https://www.autoitscript.com/forum/topic/81332-_base64encode-_base64decode/
- $input = Binary($input)
- Local $struct = DllStructCreate("byte[" & BinaryLen($input) & "]")
- DllStructSetData($struct, 1, $input)
- Local $strc = DllStructCreate("int")
- Local $a_Call = DllCall("Crypt32.dll", "int", "CryptBinaryToString", _
- "ptr", DllStructGetPtr($struct), _
- "int", DllStructGetSize($struct), _
- "int", 1, _
- "ptr", 0, _
- "ptr", DllStructGetPtr($strc))
- If @error Or Not $a_Call[0] Then
- Return SetError(1, 0, "") ; error calculating the length of the buffer needed
- EndIf
- Local $a = DllStructCreate("char[" & DllStructGetData($strc, 1) & "]")
- $a_Call = DllCall("Crypt32.dll", "int", "CryptBinaryToString", _
- "ptr", DllStructGetPtr($struct), _
- "int", DllStructGetSize($struct), _
- "int", 1, _
- "ptr", DllStructGetPtr($a), _
- "ptr", DllStructGetPtr($strc))
- If @error Or Not $a_Call[0] Then
- Return SetError(2, 0, "") ; error encoding
- EndIf
- Return DllStructGetData($a, 1)
- EndFunc ;==>_Base64Encode
- Func _Base64Decode($input_string)
- Local $struct = DllStructCreate("int")
- Local $a_Call = DllCall("Crypt32.dll", "int", "CryptStringToBinary", _
- "str", $input_string, _
- "int", 0, _
- "int", 1, _
- "ptr", 0, _
- "ptr", DllStructGetPtr($struct, 1), _
- "ptr", 0, _
- "ptr", 0)
- If @error Or Not $a_Call[0] Then
- Return SetError(1, 0, "") ; error calculating the length of the buffer needed
- EndIf
- Local $a = DllStructCreate("byte[" & DllStructGetData($struct, 1) & "]")
- $a_Call = DllCall("Crypt32.dll", "int", "CryptStringToBinary", _
- "str", $input_string, _
- "int", 0, _
- "int", 1, _
- "ptr", DllStructGetPtr($a), _
- "ptr", DllStructGetPtr($struct, 1), _
- "ptr", 0, _
- "ptr", 0)
- If @error Or Not $a_Call[0] Then
- Return SetError(2, 0, "") ; error decoding
- EndIf
- Return DllStructGetData($a, 1)
- EndFunc ;==>_Base64Decode
- #EndRegion
Add Comment
Please, Sign In to add comment