thongvsgame

AutoIt http server example

Jul 2nd, 2022 (edited)
132
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
AutoIt 12.23 KB | None | 0 0
  1. #include <EditConstants.au3>
  2. #include <GUIConstantsEx.au3>
  3. #include <StaticConstants.au3>
  4. #include <WindowsConstants.au3>
  5.  
  6. #Region ### START Koda GUI section ### Form=
  7. $Form1 = GUICreate("Example AutoIt Http", 300, 150, 192, 124)
  8. $GUIMethod = GUICtrlCreateLabel("Method", 0, 0, 300, 20, BitOR($SS_CENTER, $SS_CENTERIMAGE))
  9. $GUIBody = GUICtrlCreateEdit("", 0, 20, 300, 130, BitOR($ES_AUTOVSCROLL, $ES_WANTRETURN, $ES_READONLY), 0)
  10. GUICtrlSetColor(-1, 0x0000FF)
  11. GUISetState(@SW_SHOW)
  12. #EndRegion ### END Koda GUI section ###
  13.  
  14. #cs
  15. // javascript post data example 1
  16. fetch('http://127.0.0.1:3000', {
  17.     method: 'POST',
  18.     body: 'data example',
  19. })
  20.  
  21. // javascript post data example 2
  22. fetch('http://127.0.0.1:3000', {
  23.     method: 'POST',
  24.     body: JSON.stringify({ timestamp: Date.now(), href: window.location.href, title: document.title }),
  25. })
  26. #ce
  27.  
  28. #Region Init
  29. ; step 1
  30. Global $Listener = HttpInit(3000) ; listen on port 3000
  31. OnAutoItExitRegister("OnAutoItExit")
  32.  
  33. Func HttpInit($Port)
  34.     TCPStartup()
  35.     Opt("TCPTimeout", 20)
  36.     Return TCPListen("0.0.0.0", $Port, 100)
  37. EndFunc   ;==>HttpInit
  38.  
  39. Func OnAutoItExit()
  40.     If $Listener > 0 Then TCPCloseSocket($Listener)
  41.     TCPShutdown()
  42. EndFunc   ;==>OnAutoItExit
  43.  
  44. ; step 2
  45. Local $aQueryData[1][5] = [[0]]
  46. Local $bReceived, $urlReq, $method, $ContentLength, $ContentBody, $ContentType, $Referer, $AcceptEncoding, $Header_Expect, $iSocket = -1
  47. #EndRegion
  48.  
  49. While 1
  50.  
  51.     #Region Serve
  52.     ; step 3
  53.     HttpServe($Listener, $aQueryData, $bReceived, $urlReq, $method, $ContentLength, $ContentBody, $ContentType, $Referer, $AcceptEncoding, $Header_Expect, $iSocket)
  54.  
  55.     ; get method & path
  56.     If $method <> "" Then
  57.         GUICtrlSetData($GUIMethod, $method & " " & $urlReq)
  58.     EndIf
  59.     ; get body
  60.     If $ContentBody <> "" Then
  61.         GUICtrlSetData($GUIBody, $ContentBody)
  62.     EndIf
  63.     #EndRegion
  64.  
  65.     $nMsg = GUIGetMsg()
  66.     Switch $nMsg
  67.         Case $GUI_EVENT_CLOSE
  68.             Exit
  69.  
  70.     EndSwitch
  71. WEnd
  72.  
  73. #Region Original source code from https://www.autoitscript.com/forum/topic/201673-json-http-post-serverlistener/page/2/?tab=comments#comment-1447447
  74.  
  75. 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)
  76.     If $iSocket = -1 Then
  77.         $iSocket = TCPAccept($Listener)
  78.         If @error Then
  79.             MsgBox(0, "TCPAccept", "TCPAccept error " & @error)
  80.             Return False
  81.         EndIf
  82.     Else
  83.         $buffer = StringToBinary("")
  84.         Do
  85.             $bReceived = TCPRecv($iSocket, 4096, 1)
  86.             $errTCPRecv = @error
  87.             $extTCPRecv = @extended
  88.             $buffer &= $bReceived
  89.             If DiscernData(BinaryToString($buffer, 4), $urlReq, $method, $ContentLength, $ContentBody, $ContentType, $Referer, $aQueryData, $AcceptEncoding, $Header_Expect) Then ExitLoop
  90.         Until $extTCPRecv Or $bReceived = ""
  91.  
  92.         If $errTCPRecv Or $urlReq = "" Then
  93.             TCPCloseSocket($iSocket)
  94.             $iSocket = -1
  95.         Else
  96.             If $Header_Expect = 100 Then
  97.                 HttpSender($iSocket, $AcceptEncoding, "", "text/html", "100 Continue")
  98.                 Sleep(200)
  99.                 Return
  100.             EndIf
  101.             ; process requests here
  102.  
  103.             ; response
  104.             HttpSender($iSocket, $AcceptEncoding, 'AutoIt Http Server', 'text/plain')
  105.         EndIf
  106.     EndIf
  107. EndFunc   ;==>HttpServe
  108.  
  109. ; example of a "more proper" way to send back a response
  110. Func HttpSender(ByRef $iSocket, ByRef $AcceptEncoding, $sHtmlText, $ContentType = "text/html", $ResponseStatusCode = "200 OK")
  111.     #forceref $AcceptEncoding
  112.     Local $bHtmlText = Binary($sHtmlText)
  113.     Local $_Head = "HTTP/1.1 " & $ResponseStatusCode & @CRLF ; https://en.wikipedia.org/wiki/List_of_HTTP_status_codes
  114.     $_Head &= "Content-Type: " & $ContentType & @CRLF ; ..so the client knows what is getting.
  115.     $_Head &= "Connection: close" & @CRLF ; SideNote: ..an interaction takes 10 ms., is there a need for "muti-concurrent" code ?   ;)
  116.  
  117.     ; allow CORS header
  118.     $_Head &= "Access-Control-Allow-Origin: *" & @CRLF
  119.     $_Head &= "Access-Control-Allow-Headers: *" & @CRLF
  120.     $_Head &= "Access-Control-Allow-Methods: *" & @CRLF
  121.     $_Head &= "Access-Control-Allow-Credentials: true" & @CRLF
  122.  
  123. ;~  If StringInStr($AcceptEncoding, "gzip") Then     ; If you  "#include <ZLIB.au3>" then you can compress the data.
  124. ;~      $bHtmlText = _ZLIB_GZCompress($bHtmlText, 5) ; It takes longer ( say 5 ms. ) to compress but on a slow connection, delivery is faster.
  125. ;~      $_Head &= "Content-Encoding: gzip" & @CRLF   ; ..tho, if sending a compressed file, say a ZIP file, this is not to be used.
  126. ;~  EndIf
  127.  
  128.     $_Head &= "Content-Lenght: " & BinaryLen($bHtmlText) & @CRLF ; this is a must for binary file send. Might as well use it for everything.
  129. ;~  $_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
  130.     $_Head &= @CRLF ; end of header marker
  131.     $_Head = Binary($_Head)
  132.  
  133.     TCPSendBinary($iSocket, $_Head)     ; Send the head
  134.     TCPSendBinary($iSocket, $bHtmlText) ; Send the body ( html or file, as delimited by the header )
  135.  
  136. EndFunc   ;==>HttpSender
  137.  
  138. Func TCPSendBinary(ByRef $hSocket, ByRef $bData)
  139.     Local $iBytesSent, $iBytesTotalSent = 0, $iBytesTotal = BinaryLen($bData)
  140.     Do
  141.         $iBytesSent = TCPSend($hSocket, $bData)
  142.         If @error Then ExitLoop
  143.         $iBytesTotalSent += $iBytesSent
  144.         $bData = BinaryMid($bData, $iBytesSent + 1, BinaryLen($bData) - $iBytesSent)
  145.     Until 0 = BinaryLen($bData)
  146.     Return SetError(0, Int($iBytesTotalSent <> $iBytesTotal), $iBytesTotalSent)
  147. EndFunc   ;==>TCPSendBinary
  148.  
  149. Func DiscernData($buffer, ByRef $urlReq, ByRef $method, ByRef $ContentLength, ByRef $ContentBody, ByRef $ContentType, ByRef $Referer, ByRef $aQueryData, ByRef $AcceptEncoding, ByRef $Header_Expect)
  150.     If $Header_Expect = 100 Then ; we were waiting for the body ( $ContentLength )
  151.         $Header_Expect = 0       ; as we are not waiting anymore.
  152.         $aQueryData = DiscernQuery2array($urlReq, $buffer, $ContentType) ; data is the $buffer. $urlReq and $ContentType should be the same as it hasn't changed.
  153.         Return $ContentLength = StringLen($buffer) ; ..to flag that is all good.
  154.     EndIf
  155.     $urlReq = ""       ; $aQueryData holds the query as an array but a JSON string will need extra coding.
  156.     $method = ""       ; If the $aQueryData[1][1] = "" then is likely a JSON string
  157.     $Header_Expect = 0
  158.     $ContentLength = 0 ; In this example, at first, all I wanted, is to know that the data sent is full
  159.     $ContentBody = ""  ; and complete, to speed up the loop ( and save about 100 ms. of timeout )
  160.     Local $_Head = StringLeft($buffer, StringInStr($buffer, @CRLF & @CRLF) - 1)
  161.     $ContentBody = StringTrimLeft($buffer, StringLen($_Head) + 4)
  162.     Local $_BodyLen = StringLen($ContentBody)
  163.     Local $aCRLF = StringSplit($_Head, @CRLF, 1)
  164.     If UBound($aCRLF) < 2 Then Return
  165.     Local $aSpaceSplit = StringSplit($aCRLF[1], " ")
  166.     If UBound($aSpaceSplit) < 3 Then Return
  167.     $method = $aSpaceSplit[1]
  168.     $urlReq = $aSpaceSplit[2]
  169.     For $n = 2 To $aCRLF[0]
  170.         $aSpaceSplit = StringSplitHeader($aCRLF[$n])
  171.         If UBound($aSpaceSplit) < 3 Then ContinueLoop
  172.         If $aSpaceSplit[1] = "Content-Length" Then $ContentLength = Int($aSpaceSplit[2]) ; tis should be equal to StringLen($ContentBody)
  173.         If $aSpaceSplit[1] = "Content-Type" Then $ContentType = $aSpaceSplit[2]          ; Discern if is JSON, when needed
  174.         If $aSpaceSplit[1] = "Referer" Then $Referer = $aSpaceSplit[2]                   ; Discern if is from "/home/"
  175.         If $aSpaceSplit[1] = "Accept-Encoding" Then $AcceptEncoding = $aSpaceSplit[2]    ; Discern if to use GZIP
  176.         If $aSpaceSplit[1] = "Expect" Then $Header_Expect = Int($aSpaceSplit[2])         ; Discern if Expect: 100-continue
  177.  
  178. ;~      ; https://www.ietf.org/rfc/rfc1864.txt ; https://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html
  179. ;~      If $aSpaceSplit[1] = "Content-MD5" Then $Header_Content_MD5 = _Base64Decode($aSpaceSplit[2]) ; Content-MD5: Q2hlY2sgSW50ZWdyaXR5IQ==
  180.  
  181.     Next
  182.     If $Header_Expect = 100 Then Return 1 ; ..there is no data at this point, just header.
  183.     Switch StringUpper($method)
  184.         Case "GET"
  185.             $aQueryData = DiscernQuery2array($urlReq, Default, $ContentType) ; data is part of the URL
  186.         Case Else
  187.             $aQueryData = DiscernQuery2array($urlReq, $ContentBody, $ContentType) ; data is part of the body
  188.     EndSwitch
  189.     Return $ContentLength = $_BodyLen And StringLen($method)
  190. EndFunc   ;==>DiscernData
  191.  
  192. Func StringSplitHeader($sStr)
  193.     Local $i = StringInStr($sStr, ":")
  194.     If Not $i Then Return SetError(0, 2, "") ; the https://tools.ietf.org/html/rfc2616 talks about the ":"
  195.     Local $a[3] = [2, "", ""]                ; but not the space next to it as a delimiter of the field.
  196.     $a[1] = StringLeft($sStr, $i - 1)        ; To avoid mishaps, this function takes care of it.
  197.     $a[2] = StringStripWS(StringTrimLeft($sStr, $i), 3)
  198.     Return SetError(0, ($a[2] = "" ? 1 : 0), $a)
  199. EndFunc   ;==>StringSplitHeader
  200.  
  201. Func DiscernGetFragment($urlReq)
  202.     Local $a = StringSplit($urlReq, "#")
  203.     If UBound($a) < 3 Then Return ""
  204.     Return $a[$a[0]]
  205. EndFunc   ;==>DiscernGetFragment
  206.  
  207. Func DiscernQuery2array(ByRef $urlReq, $ContentBody = Default, $ContentType = Default)
  208.     Local $sContentPath, $sContentQuery
  209.     Local $sFragment = DiscernGetFragment($urlReq)
  210.     If $ContentBody = Default Then
  211.         Local $aQueryData[1][5] = [[0, "", $sFragment, $ContentType, ""]]
  212.         Local $i = StringInStr($urlReq, "?")
  213.         If Not $i Then Return $aQueryData
  214.         $sContentPath = StringLeft($urlReq, $i - 1)
  215.         $sContentQuery = StringTrimLeft($urlReq, $i)
  216.     ElseIf StringInStr($ContentType, "application/json") Then
  217.         Local $aQuery[2][5] = [[1, $urlReq, $sFragment, $ContentType, ""], [$ContentBody, "", "", "", ""]]
  218.         Return $aQuery ; is a json string, so better not StringSplit() it.
  219.     Else
  220.         $sContentPath = $urlReq
  221.         $sContentQuery = $ContentBody
  222.     EndIf
  223.     Local $b, $n, $a = StringSplit($sContentQuery, "&")
  224.     $i = 0
  225.     Local $aQuery[UBound($a) + 1][5]
  226.     $aQuery[0][3] = $ContentType ; for debug
  227.     For $n = 1 To UBound($a) - 1
  228.         $b = StringSplit($a[$n], "=")
  229.         $i += 1
  230.         If $b[0] > 0 Then $aQuery[$i][0] = $b[1] ; name
  231.         If $b[0] > 1 Then $aQuery[$i][1] = $b[2] ; value
  232.     Next
  233.     $aQuery[0][0] = $i            ; this holds the name=value count
  234.     $aQuery[0][1] = $sContentPath ; this holds the path ( minus the query if is a GET mathod )
  235.     $aQuery[0][2] = $sFragment    ; this would hold the fragment ( https://en.wikipedia.org/wiki/Fragment_identifier )
  236.     ReDim $aQuery[$i + 1][5]
  237.     Return $aQuery
  238. EndFunc   ;==>DiscernQuery2array
  239.  
  240. Func _Base64Encode($input) ; https://www.autoitscript.com/forum/topic/81332-_base64encode-_base64decode/
  241.     $input = Binary($input)
  242.     Local $struct = DllStructCreate("byte[" & BinaryLen($input) & "]")
  243.     DllStructSetData($struct, 1, $input)
  244.     Local $strc = DllStructCreate("int")
  245.     Local $a_Call = DllCall("Crypt32.dll", "int", "CryptBinaryToString", _
  246.             "ptr", DllStructGetPtr($struct), _
  247.             "int", DllStructGetSize($struct), _
  248.             "int", 1, _
  249.             "ptr", 0, _
  250.             "ptr", DllStructGetPtr($strc))
  251.     If @error Or Not $a_Call[0] Then
  252.         Return SetError(1, 0, "") ; error calculating the length of the buffer needed
  253.     EndIf
  254.     Local $a = DllStructCreate("char[" & DllStructGetData($strc, 1) & "]")
  255.     $a_Call = DllCall("Crypt32.dll", "int", "CryptBinaryToString", _
  256.             "ptr", DllStructGetPtr($struct), _
  257.             "int", DllStructGetSize($struct), _
  258.             "int", 1, _
  259.             "ptr", DllStructGetPtr($a), _
  260.             "ptr", DllStructGetPtr($strc))
  261.     If @error Or Not $a_Call[0] Then
  262.         Return SetError(2, 0, "") ; error encoding
  263.     EndIf
  264.     Return DllStructGetData($a, 1)
  265. EndFunc   ;==>_Base64Encode
  266.  
  267. Func _Base64Decode($input_string)
  268.     Local $struct = DllStructCreate("int")
  269.     Local $a_Call = DllCall("Crypt32.dll", "int", "CryptStringToBinary", _
  270.             "str", $input_string, _
  271.             "int", 0, _
  272.             "int", 1, _
  273.             "ptr", 0, _
  274.             "ptr", DllStructGetPtr($struct, 1), _
  275.             "ptr", 0, _
  276.             "ptr", 0)
  277.     If @error Or Not $a_Call[0] Then
  278.         Return SetError(1, 0, "") ; error calculating the length of the buffer needed
  279.     EndIf
  280.     Local $a = DllStructCreate("byte[" & DllStructGetData($struct, 1) & "]")
  281.     $a_Call = DllCall("Crypt32.dll", "int", "CryptStringToBinary", _
  282.             "str", $input_string, _
  283.             "int", 0, _
  284.             "int", 1, _
  285.             "ptr", DllStructGetPtr($a), _
  286.             "ptr", DllStructGetPtr($struct, 1), _
  287.             "ptr", 0, _
  288.             "ptr", 0)
  289.     If @error Or Not $a_Call[0] Then
  290.         Return SetError(2, 0, "") ; error decoding
  291.     EndIf
  292.     Return DllStructGetData($a, 1)
  293. EndFunc   ;==>_Base64Decode
  294.  
  295. #EndRegion
  296.  
Add Comment
Please, Sign In to add comment