CreateFormData - Create "multipart/form-data" for http post (Updated:2019-01-13)

Post your working scripts, libraries and tools for AHK v1.1 and older
tmplinshi
Posts: 1604
Joined: 01 Oct 2013, 14:57

Update on 1.30 (2019-01-13) - The file parameters are now placed at the end of the retData

12 Jan 2019, 12:26

Update on 1.30 (2019-01-13) - The file parameters are now placed at the end of the retData

There was an api that requires the file parameter to be the last part of the body, so I made that changes to the script. I found it also helps HTTP Debugger to display the multipart body as plain text instead of hex when the file parameter is in the middle of the body.
murataygun
Posts: 104
Joined: 07 Aug 2015, 15:53

Re: CreateFormData - Create "multipart/form-data" for http post (Updated:2019-01-13)

16 Jan 2019, 09:41

Cant get the value of upload[1] or 2??

Code: Select all

objParam := { "btSubmit": "Upload It!"
            , "adult": "no"
            , "mode": "local"
            , "forumurl": "http://postimage.org/"
            , "upload[]": ["2.png", "1.png"]
            , "um": "computer"
            , "MAX_FILE_SIZE": 16777216
            , "optsize": 0 }

     MsgBox % objParam["upload"][1]
malcev
Posts: 1769
Joined: 12 Aug 2014, 12:37

Re: CreateFormData - Create "multipart/form-data" for http post (Updated:2019-01-13)

05 Aug 2019, 06:53

How can we make SafeArray for big files - more than 1GB with ahk32 bit running on Win 64bit?
Just for test I wrote code which uploads file on https://files.fm.
It works fine on ahk64 bit, but dont work on ahk32 bit.
As I understand that is because of 32-bit processes have a 2 GB RAM limit.
But I can upload big files with any browser 32 bit.
How browser converts file to SafeArray?
Here is example of error:

Code: Select all

oADO := ComObjCreate("ADODB.Stream")
oADO.Type := 1 ; adTypeBinary
oADO.Open
oADO.LoadFromFile("D:\1gb.mp4")
oADO.Read
oADO.Close
msgbox ok
Script of upload to https://files.fm with ByteArray function:

Code: Select all

path := "D:\1GB.mp4"

HTTP := ComObjCreate("WinHTTP.WinHTTPRequest.5.1")
HTTP.Open("GET", "https://files.fm", true)
HTTP.SetRequestHeader("User-Agent", "Mozilla/5.0 (Windows NT 6.1; WOW64; Trident/7.0; rv:11.0) like Gecko")
HTTP.SetRequestHeader("Pragma", "no-cache")
HTTP.SetRequestHeader("Cache-Control", "no-cache, no-store")
HTTP.SetRequestHeader("If-Modified-Since", "Sat, 1 Jan 2000 00:00:00 GMT")
HTTP.Send()
HTTP.WaitForResponse()
RegexMatch(HTTP.ResponseText, "s)PHPSESSID=(.+?)"".+?strCurrentUploadCallServer = '(.+?)\.", match)
phpsessid := match1

HTTP.Open("GET", "https://files.fm/server_scripts/get_upload_id.php?show_add_key=1", true)
HTTP.SetRequestHeader("User-Agent", "Mozilla/5.0 (Windows NT 6.1; WOW64; Trident/7.0; rv:11.0) like Gecko")
HTTP.SetRequestHeader("Pragma", "no-cache")
HTTP.SetRequestHeader("Cache-Control", "no-cache, no-store")
HTTP.SetRequestHeader("If-Modified-Since", "Sat, 1 Jan 2000 00:00:00 GMT")
HTTP.Send()
HTTP.WaitForResponse()
RegexMatch(HTTP.ResponseText, "s)(.+?),.+?,(.+?)$", match)
up_id := match1, key := match2

now := A_NowUTC
EnvSub, now,1970, seconds
now .= A_MSec
objParam := {Filedata: [path]}
CreateFormData(PostData, hdr_ContentType, objParam)

HTTP.SetTimeouts(0, 0, 0, 0)
HTTP.Open("POST", "https://free.files.fm/save_file.php?PHPSESSID=" phpsessid "&up_id=" up_id "&ignore_user_abort=1&skip_update=1&key=" key "&v=" now, true)
HTTP.SetRequestHeader("User-Agent", "Mozilla/5.0 (Windows NT 6.1; WOW64; Trident/7.0; rv:11.0) like Gecko")
HTTP.SetRequestHeader("Content-Type", hdr_ContentType)
HTTP.SetRequestHeader("Pragma", "no-cache")
HTTP.SetRequestHeader("Cache-Control", "no-cache, no-store")
HTTP.SetRequestHeader("If-Modified-Since", "Sat, 1 Jan 2000 00:00:00 GMT")
HTTP.Send(PostData)
HTTP.WaitForResponse()
uploadedLink := "https://files.fm/u/" up_id

; test of uploading file
HTTP.SetTimeouts(0, 60000, 30000, 30000)
HTTP.Open("GET", uploadedLink, true)
HTTP.SetRequestHeader("User-Agent", "Mozilla/5.0 (Windows NT 6.1; WOW64; Trident/7.0; rv:11.0) like Gecko")
HTTP.SetRequestHeader("Pragma", "no-cache")
HTTP.SetRequestHeader("Cache-Control", "no-cache, no-store")
HTTP.SetRequestHeader("If-Modified-Since", "Sat, 1 Jan 2000 00:00:00 GMT")
HTTP.Send()
HTTP.WaitForResponse()
if InStr(HTTP.ResponseText, "tools_button_download")
   msgbox % clipboard := uploadedLink
else
   msgbox Error
return



; 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

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"
	}

}
User avatar
kczx3
Posts: 1640
Joined: 06 Oct 2015, 21:39

Re: CreateFormData - Create "multipart/form-data" for http post (Updated:2019-01-13)

05 Aug 2019, 18:43

I wonder if the undocumented ConvertAndEscapePostData function from mshtml.dll would help.

https://www.geoffchappell.com/studies/windows/ie/mshtml/api/index.htm
lx930129
Posts: 10
Joined: 13 Sep 2016, 03:41

Re: CreateFormData - Create "multipart/form-data" for http post (Updated:2019-01-13)

25 Sep 2019, 08:52

hi,i want to know how to check the website form parameters? I just can not find it.
malcev
Posts: 1769
Joined: 12 Aug 2014, 12:37

Re: CreateFormData - Create "multipart/form-data" for http post (Updated:2019-01-13)

30 Sep 2019, 20:24

You can check them, in chrome network log, for example.
thalesduarte
Posts: 95
Joined: 13 Sep 2021, 06:08

Re: CreateFormData - Create "multipart/form-data" for http post (Updated:2019-01-13)

10 Dec 2021, 13:31

Anyone know how i can make this requisition with ahk?
It's a form-data to send xml with two content-type inside a body
Image
thalesduarte
Posts: 95
Joined: 13 Sep 2021, 06:08

Re: CreateFormData - Create "multipart/form-data" for http post (Updated:2019-01-13)

10 Dec 2021, 14:27

malcev wrote:
10 Dec 2021, 14:08
Read 1 post example and do the same.
I Already did it, but.

{"error":{"code":500,"errors":[],"message":"HTTP 415 Unsupported Media Type"}}
malcev
Posts: 1769
Joined: 12 Aug 2014, 12:37

Re: CreateFormData - Create "multipart/form-data" for http post (Updated:2019-01-13)

10 Dec 2021, 14:28

Then You did it incorrect.
You need to send 2 parameters in body.
file[] and query.
thalesduarte
Posts: 95
Joined: 13 Sep 2021, 06:08

Re: CreateFormData - Create "multipart/form-data" for http post (Updated:2019-01-13)

10 Dec 2021, 14:50

malcev wrote:
10 Dec 2021, 14:28
Then You did it incorrect.
You need to send 2 parameters in body.
file[] and query.
I'm trying, like this.
But dont work.

Code: Select all

; ###############################################################################################
TokenValidador := "mytoken"
BearerValidador := "mybearer"
File := "C:\Users\Thales\Desktop\TESTES\1.XML"
FileRead, BOXE, C:\Users\Thales\Desktop\TESTES\boxe.txt
FileRead, ARQ, C:\Users\Thales\Desktop\TESTES\arq.txt

URL := "https://api.onvio.com.br/dominio/invoice/v3/batches"

SendXMLAPI := ComObjCreate("WinHttp.WinHttpRequest.5.1")
SendXMLAPI.Open("POST", URL , False)
SendXMLAPI.SetRequestHeader("x-integration-key", TokenValidador)
SendXMLAPI.SetRequestHeader("User-Agent", "Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; WOW64; Trident/5.0)")
SendXMLAPI.SetRequestHeader("Authorization","Bearer "  BearerValidador)

objParam := { "file[]": ARQ 
            , "query": BOXE }

CreateFormData(PostData, Header, objParam)

SendXMLAPI.Send(PostData)
Result := SendXMLAPI.ResponseText
Status := SendXMLAPI.Status

Gui, Add, Edit, w500 r10, 3 - Result: %Result%

Gui, Show
return

Guiclose:
ExitApp
and the result
{"error":{"code":500,"errors":[],"message":"HTTP 415 Unsupported Media Type"}}
malcev
Posts: 1769
Joined: 12 Aug 2014, 12:37

Re: CreateFormData - Create "multipart/form-data" for http post (Updated:2019-01-13)

10 Dec 2021, 14:56

You do it wrong, and I am too lazy to do it instead of You.
You need to understand how 1 example in this topic works and do the same.
thalesduarte
Posts: 95
Joined: 13 Sep 2021, 06:08

Re: CreateFormData - Create "multipart/form-data" for http post (Updated:2019-01-13)

11 Dec 2021, 13:42

malcev wrote:
10 Dec 2021, 14:56
You do it wrong, and I am too lazy to do it instead of You.
You need to understand how 1 example in this topic works and do the same.
I already try for 3 days and nothing :(
thalesduarte
Posts: 95
Joined: 13 Sep 2021, 06:08

Re: CreateFormData - Create "multipart/form-data" for http post (Updated:2019-01-13)

11 Dec 2021, 15:14

malcev wrote:
11 Dec 2021, 14:34
I do not see Your code.
There is

Code: Select all

; ###############################################################################################
TokenValidador := "mytoken"
BearerValidador := "mybearer"
File := "C:\Users\Thales\Desktop\TESTES\1.XML"
FileRead, BOXE, C:\Users\Thales\Desktop\TESTES\boxe.txt
FileRead, ARQ, C:\Users\Thales\Desktop\TESTES\arq.txt

URL := "https://api.onvio.com.br/dominio/invoice/v3/batches"

SendXMLAPI := ComObjCreate("WinHttp.WinHttpRequest.5.1")
SendXMLAPI.Open("POST", URL , False)
SendXMLAPI.SetRequestHeader("x-integration-key", TokenValidador)
SendXMLAPI.SetRequestHeader("User-Agent", "Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; WOW64; Trident/5.0)")
SendXMLAPI.SetRequestHeader("Authorization","Bearer "  BearerValidador)

objParam := { "file[]": ARQ 
            , "query": BOXE }

CreateFormData(PostData, Header, objParam)

SendXMLAPI.Send(PostData)
Result := SendXMLAPI.ResponseText
Status := SendXMLAPI.Status

Gui, Add, Edit, w500 r10, 3 - Result: %Result%

Gui, Show
return

Guiclose:
ExitApp
malcev
Posts: 1769
Joined: 12 Aug 2014, 12:37

Re: CreateFormData - Create "multipart/form-data" for http post (Updated:2019-01-13)

11 Dec 2021, 15:26

Are You kidding?
How I can know what You put at

Code: Select all

FileRead, BOXE, C:\Users\Thales\Desktop\TESTES\boxe.txt
FileRead, ARQ, C:\Users\Thales\Desktop\TESTES\arq.txt
thalesduarte
Posts: 95
Joined: 13 Sep 2021, 06:08

Re: CreateFormData - Create "multipart/form-data" for http post (Updated:2019-01-13)

13 Dec 2021, 05:34

malcev wrote:
11 Dec 2021, 15:26
Are You kidding?
How I can know what You put at

Code: Select all

FileRead, BOXE, C:\Users\Thales\Desktop\TESTES\boxe.txt
FileRead, ARQ, C:\Users\Thales\Desktop\TESTES\arq.txt
I'm sorry.
That's the contents in the files.

BOXE.TXT

Code: Select all

{"boxe/File": false}
ARQ.TXT

Code: Select all

C:\Users\Thales\Desktop\TESTES\1.XML
malcev
Posts: 1769
Joined: 12 Aug 2014, 12:37

Re: CreateFormData - Create "multipart/form-data" for http post (Updated:2019-01-13)

13 Dec 2021, 05:58

Files You need send as objects.

Code: Select all

"upload[]": ["2.png", "1.png"]
Because function CreateFormData checks if value of key is object or not and depending of it adds it to body with different ways.
https://gist.github.com/tmplinshi/8428a280bba58d25ef0b#file-createformdata-ahk-L52
thalesduarte
Posts: 95
Joined: 13 Sep 2021, 06:08

Re: CreateFormData - Create "multipart/form-data" for http post (Updated:2019-01-13)

13 Dec 2021, 08:00

Dont work :(, but thanks for the help, i will try in other moment

Return to “Scripts and Functions (v1)”

Who is online

Users browsing this forum: songdg and 53 guests