Page 1 of 1

WinHttp post request

Posted: 05 Feb 2020, 07:10
by c7aesa7r
I have found this script bellow to send get Winhttp request, would like to ask for help in how i could use it to send a post request, like:

/api/item/write
So in the body:
{ "species": "value", "name": "item name", "quantity": 300 }

Code: Select all

getWebPage("https granblue.herokuapp.com /api/item/write/collection/550")  Broken Link for safety

;=========== get the content of a webpage into a variable
getWebPage(url, postdata :="")
{
    Static whr := ComObjCreate("WinHttp.WinHttpRequest.5.1")    ; Static will make it use the same object in memory
    whr.Open((postdata?"Post":"Get"), url, true)                ; Post or Get depending if postdata is submitted
    whr.SetTimeouts("30000", "30000", "30000", "30000")         ; timeout 30 seconds

    if (StrLen(postdata)>0)
    {
        whr.SetRequestHeader("Content-Type", "application/x-www-form-urlencoded")
        whr.Send(postdata)
    }
    else
    {
        whr.Send()
    }
    whr.WaitForResponse()
    Return whr.ResponseText
}

Re: WinHttp post request

Posted: 05 Feb 2020, 10:31
by Masonjar13
You need to create and send the form data (param 2). You can use this to build your data: https://gist.github.com/tmplinshi/8428a280bba58d25ef0b

Re: WinHttp post request

Posted: 05 Feb 2020, 17:16
by c7aesa7r
hi @Masonjar13

Code: Select all

; CreateFormData() by tmplinshi, AHK Topic: https://autohotkey.com/boards/viewtopic.php?t=7647
; Thanks to Coco: https://autohotkey.com/boards/viewtopic.php?p=41731#p41731
; Modified version by SKAN, 09/May/2016

whr := ComObjCreate("WinHttp.WinHttpRequest.5.1")
whr.Open("POST", "https  site  /api/item/write/",  Broken Link for safety true)

objParam := { "species": "bird"
            , "name": "cana"
            , "quantity": 5 }

CreateFormData(PostData, hdr_ContentType, objParam)

whr.SetRequestHeader("Content-Type", hdr_ContentType)
whr.SetRequestHeader("Referer", "https    site      /api/item/write/")  Broken Link for safety
whr.SetRequestHeader("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:72.0) Gecko/20100101 Firefox/72.0")
whr.Option(6) := False ; No auto redirect
whr.Send(PostData)
whr.WaitForResponse()
;Run, % "https black-desert-notifier.herokuapp.com /api/item/write/"  Broken Link for safety . whr.GetResponseHeader("Location")


CreateFormData(ByRef retData, ByRef retHeader, objParam) {
	New CreateFormData(retData, retHeader, objParam)
}

Class CreateFormData {

	__New(ByRef retData, ByRef retHeader, objParam) {

		Local CRLF := "`r`n", i, k, v, str, pvData
		; Create a random Boundary
		Local Boundary := this.RandomBoundary()
		Local BoundaryLine := "------------------------------" . Boundary

    this.Len := 0 ; GMEM_ZEROINIT|GMEM_FIXED = 0x40
    this.Ptr := DllCall( "GlobalAlloc", "UInt",0x40, "UInt",1, "Ptr"  )          ; allocate global memory

		; Loop input paramters
		For k, v in objParam
		{
			If IsObject(v) {
				For i, FileName in v
				{
					str := BoundaryLine . CRLF
					     . "Content-Disposition: form-data; name=""" . k . """; filename=""" . FileName . """" . CRLF
					     . "Content-Type: " . this.MimeType(FileName) . CRLF . CRLF
          this.StrPutUTF8( str )
          this.LoadFromFile( Filename )
          this.StrPutUTF8( CRLF )
				}
			} Else {
				str := BoundaryLine . CRLF
				     . "Content-Disposition: form-data; name=""" . k """" . CRLF . CRLF
				     . v . CRLF
        this.StrPutUTF8( str )
			}
		}

		this.StrPutUTF8( BoundaryLine . "--" . CRLF )

    ; Create a bytearray and copy data in to it.
    retData := ComObjArray( 0x11, this.Len ) ; Create SAFEARRAY = VT_ARRAY|VT_UI1
    pvData  := NumGet( ComObjValue( retData ) + 8 + A_PtrSize )
    DllCall( "RtlMoveMemory", "Ptr",pvData, "Ptr",this.Ptr, "Ptr",this.Len )

    this.Ptr := DllCall( "GlobalFree", "Ptr",this.Ptr, "Ptr" )                   ; free global memory 

    retHeader := "multipart/form-data; boundary=----------------------------" . Boundary
	}

  StrPutUTF8( str ) {
    Local ReqSz := StrPut( str, "utf-8" ) - 1
    this.Len += ReqSz                                  ; GMEM_ZEROINIT|GMEM_MOVEABLE = 0x42
    this.Ptr := DllCall( "GlobalReAlloc", "Ptr",this.Ptr, "UInt",this.len + 1, "UInt", 0x42 )   
    StrPut( str, this.Ptr + this.len - ReqSz, ReqSz, "utf-8" )
  }
  
  LoadFromFile( Filename ) {
    Local objFile := FileOpen( FileName, "r" )
    this.Len += objFile.Length                     ; GMEM_ZEROINIT|GMEM_MOVEABLE = 0x42 
    this.Ptr := DllCall( "GlobalReAlloc", "Ptr",this.Ptr, "UInt",this.len, "UInt", 0x42 )
    objFile.RawRead( this.Ptr + this.Len - objFile.length, objFile.length )
    objFile.Close()       
  }

	RandomBoundary() {
		str := "0|1|2|3|4|5|6|7|8|9|a|b|c|d|e|f|g|h|i|j|k|l|m|n|o|p|q|r|s|t|u|v|w|x|y|z"
		Sort, str, D| Random
		str := StrReplace(str, "|")
		Return SubStr(str, 1, 12)
	}

	MimeType(FileName) {
		n := FileOpen(FileName, "r").ReadUInt()
		Return (n        = 0x474E5089) ? "image/png"
		     : (n        = 0x38464947) ? "image/gif"
		     : (n&0xFFFF = 0x4D42    ) ? "image/bmp"
		     : (n&0xFFFF = 0xD8FF    ) ? "image/jpeg"
		     : (n&0xFFFF = 0x4949    ) ? "image/tiff"
		     : (n&0xFFFF = 0x4D4D    ) ? "image/tiff"
		     : "application/octet-stream"
	}

}

I followed the example on the link you post, but I'm not receiving anything on my site

Re: WinHttp post request

Posted: 05 Feb 2020, 17:25
by Masonjar13
Looks correct. Have you checked your server logs? Did you see a connection, possibly failed? You may need to authenticate first, or open your endpoint to the public. Potentially, you could also be timing out (though this should throw an error on AHK). You can use whr.setTimeouts() to alter those, if needed.

Re: WinHttp post request

Posted: 06 Feb 2020, 23:23
by tmplinshi
There are mainly 3 types of POST data.
  1. application/x-www-form-urlencoded
    example body: name=admin&shoesize=12
  2. application/json
    example body: {"name":"admin", "shoesize":12}
  3. multipart/form-data
    It's normally used for uploading binary file. CreateFormData is only used for this type.
The body is a json string, so it should be application/json.

Code: Select all

whr := ComObjCreate("WinHttp.WinHttpRequest.5.1")
whr.Open("POST", "https://granblue.herokuapp.com/api/item/write")
whr.SetRequestHeader("Content-Type", "application/json")
body = {"species": "value", "name": "item name", "quantity": 300}
whr.Send(body)
MsgBox % whr.ResponseText

Re: WinHttp post request

Posted: 26 Feb 2021, 15:16
by blue83
Hi @tmplinshi ,

I have tried this for upload file to Sharepoint, and my image creates, but can not be open, maybe some data are not transfering corectly?

Code: Select all

objParam := { "filename": ["Capture.jpg"] }

CreateFormData(postData, ContentType, objParam)

FileGetSize, filesize, %filename%
whr := ""
whr := ComObjCreate("WinHttp.WinHttpRequest.5.1")
whr.Open("POST", "https://xxx.sharepoint.com/sites/xxx/_api/web/GetFolderByServerRelativeUrl('" url "')/Files/add(url='" filename "')", true)
whr.SetRequestHeader("Content-Type", ContentType)
whr.SetRequestHeader("Authorization", "Bearer " access_token "")
whr.SetRequestHeader("Accept", "application/json;odata=nometadata")
whr.SetRequestHeader("X-RequestDigest", FormDigestValue)
whr.SetRequestHeader("Content-length", filesize)
whr.Option(6) := False ; No auto redirect
whr.Send(postData)
whr.WaitForResponse()
variable := ""
variable := whr.ResponseText
MsgBox,,, %variable%, 0

Re: WinHttp post request

Posted: 27 Feb 2021, 05:58
by blue83
Acctually I did it with .pdf file, but .jpg have some problems and cant be read when is uploaded.

blue

Re: WinHttp post request

Posted: 17 Dec 2021, 21:54
by Gate
Hi there,

I've modified the GetWebPage function to handle JSON well. Posting here for anyone to use.

Code: Select all


JsonData := {"contact": {"email": "johndoe@example.com","firstName": "John","lastName": "Doe","phone": "7223224241","fieldValues":[{"field":"1","value":"The Value for First Field"},{"field":"6","value":"2008-01-20"}]}}
msgbox % GetWebPage(URL,JsonData,{ "API-TOKEN" : APIkey })
; get BuildJson() https://www.autohotkey.com/board/topic/95262-obj-json-obj/

getWebPage(url, postData := 0, headers := 0, method := 0)
{   	
	if (postData && IsObject(postData))
		postData := BuildJson(postData)
	
	whr := ComObjCreate("WinHttp.WinHttpRequest.5.1")    ; Static will make it use the same object in memory	
    whr.Open((method?method:(postData?"POST":"GET")), url, true)                ; Post or Get depending if postdata is submitted
    whr.SetTimeouts("30000", "30000", "30000", "30000")         ; timeout 30 seconds
	
    postData ? whr.SetRequestHeader("Content-Type", "application/json")	
	
	if (IsObject(headers))
		for k, v in headers
			whr.SetRequestHeader(k, v)
	
	(postData?whr.Send(postData):whr.Send())
    whr.WaitForResponse()
    Return whr.ResponseText
}