Thinkai's Blog

Autohoutkey|Python|php|aardio|VOIP|IT 爱好者

正在浏览分类 UserAgent

总共找到 1 篇

httpQuery——强大的网络下载函数 Autohotkey 2304

作者为 发表

Autohotkey网站建设


取自:http://www.autohotkey.com/board/topic/30624-function-httpquery-get-and-post-requests-update-036

httpQuery(byref p1 = "", p2 = "", p3="", p4="")
{   ; v0.3.6 (w) Oct, 26 2010 by derRaphael / zLib-Style release
	; currently the verbs showHeader, storeHeader, and updateSize are supported in httpQueryOps
	; in case u need a different UserAgent, Proxy, ProxyByPass, Referrer, and AcceptType just
	; specify them as global variables - mind the varname for referrer is httpQueryReferer [sic].
	; Also if any special dwFlags are needed such as INTERNET_FLAG_NO_AUTO_REDIRECT or cache
	; handling this might be set using the httpQueryDwFlags variable as global
	global httpQueryOps, httpAgent, httpProxy, httpProxyByPass, httpQueryReferer, httpQueryAcceptType
		, httpQueryDwFlags
	; Get any missing default Values

	;v0.3.6
	; check for syntax
	if ( VarSetCapacity(p1) != 0 )
		dreturn:=true,  result := "", lpszUrl := p1, POSTDATA := p2, HEADERS  := p3
	else
		result := p1, lpszUrl := p2, POSTDATA := p3, HEADERS  := p4

	DefaultOps =
	(LTrim Join|
		httpAgent=AutoHotkeyScript|httpProxy=0|httpProxyByPass=0|INTERNET_FLAG_SECURE=0x00800000
		SECURITY_FLAG_IGNORE_UNKNOWN_CA=0x00000100|SECURITY_FLAG_IGNORE_CERT_CN_INVALID=0x00001000
		SECURITY_FLAG_IGNORE_CERT_DATE_INVALID=0x00002000|SECURITY_FLAG_IGNORE_CERT_WRONG_USAGE=0x00000200
		INTERNET_OPEN_TYPE_PROXY=3|INTERNET_OPEN_TYPE_DIRECT=1|INTERNET_SERVICE_HTTP=3
	)
	Loop,Parse,DefaultOps,|
	{
		RegExMatch(A_LoopField,"(?P<Option>[^=]+)=(?P<Default>.*)",http)
		if StrLen(%httpOption%)=0
			%httpOption% := httpDefault
	}

	; Load Library
	hModule := DllCall("LoadLibrary", "Str", "WinINet.Dll")

	; SetUpStructures for URL_COMPONENTS / needed for InternetCrackURL
	; http://msdn.microsoft.com/en-us/library/aa385420(VS.85).aspx
	offset_name_length:= "4-lpszScheme-255|16-lpszHostName-1024|28-lpszUserName-1024|"
	. "36-lpszPassword-1024|44-lpszUrlPath-1024|52-lpszExtrainfo-1024"
	VarSetCapacity(URL_COMPONENTS,60,0)
	; Struc Size               ; Scheme Size                  ; Max Port Number
	NumPut(60,URL_COMPONENTS,0), NumPut(255,URL_COMPONENTS,12), NumPut(0xffff,URL_COMPONENTS,24)

	Loop,Parse,offset_name_length,|
	{
		RegExMatch(A_LoopField,"(?P<Offset>\d+)-(?P<Name>[a-zA-Z]+)-(?P<Size>\d+)",iCU_)
		VarSetCapacity(%iCU_Name%,iCU_Size,0)
		NumPut(&%iCU_Name%,URL_COMPONENTS,iCU_Offset)
		NumPut(iCU_Size,URL_COMPONENTS,iCU_Offset+4)
	}

	; Split the given URL; extract scheme, user, pass, authotity (host), port, path, and query (extrainfo)
	; http://msdn.microsoft.com/en-us/library/aa384376(VS.85).aspx
	DllCall("WinINet\InternetCrackUrlA","Str",lpszUrl,"uInt",StrLen(lpszUrl),"uInt",0,"uInt",&URL_COMPONENTS)

	; Update variables to retrieve results
	Loop,Parse,offset_name_length,|
	{
		RegExMatch(A_LoopField,"-(?P<Name>[a-zA-Z]+)-",iCU_)
		VarSetCapacity(%iCU_Name%,-1)
	}
	nPort:=NumGet(URL_COMPONENTS,24,"uInt")

	; Import any set dwFlags
	dwFlags := httpQueryDwFlags
	; For some reasons using a selfsigned https certificates doesnt work
	; such as an own webmin service - even though every security is turned off
	; https with valid certificates works when
	if (lpszScheme = "https")
		dwFlags |= (INTERNET_FLAG_SECURE|SECURITY_FLAG_IGNORE_CERT_CN_INVALID
	|SECURITY_FLAG_IGNORE_CERT_WRONG_USAGE)

	; Check for Header and drop exception if unknown or invalid URL
	if (lpszScheme="unknown") {
		Result := "ERR: No Valid URL supplied."
		return StrLen(Result)
	}

	; Initialise httpQuery's use of the WinINet functions.
	; http://msdn.microsoft.com/en-us/library/aa385096(VS.85).aspx
	hInternet := DllCall("WinINet\InternetOpenA"
		,"Str",httpAgent,"UInt"
		,(httpProxy != 0 ?  INTERNET_OPEN_TYPE_PROXY : INTERNET_OPEN_TYPE_DIRECT )
		,"Str",httpProxy,"Str",httpProxyBypass,"Uint",0)

	; Open HTTP session for the given URL
	; http://msdn.microsoft.com/en-us/library/aa384363(VS.85).aspx
	hConnect := DllCall("WinINet\InternetConnectA"
		,"uInt",hInternet,"Str",lpszHostname, "Int",nPort
		,"Str",lpszUserName, "Str",lpszPassword,"uInt",INTERNET_SERVICE_HTTP
		,"uInt",0,"uInt*",0)

	; Do we POST? If so, check for header handling and set default
	if (StrLen(POSTDATA)>0) {
		HTTPVerb:="POST"
		if StrLen(Headers)=0
Headers:="Content-Type: application/x-www-form-urlencoded"
} else ; otherwise mode must be GET - no header Defaults needed
	HTTPVerb:="GET"

; Form the request with proper HTTP protocol version and create the request handle
; http://msdn.microsoft.com/en-us/library/aa384233(VS.85).aspx
hRequest := DllCall("WinINet\HttpOpenRequestA"
	,"uInt",hConnect,"Str",HTTPVerb,"Str",lpszUrlPath . lpszExtrainfo
	,"Str",ProVer := "HTTP/1.1", "Str",httpQueryReferer,"Str",httpQueryAcceptTypes
	,"uInt",dwFlags,"uInt",Context:=0 )

; Send the specified request to the server
; http://msdn.microsoft.com/en-us/library/aa384247(VS.85).aspx
sRequest := DllCall("WinINet\HttpSendRequestA"
	, "uInt",hRequest,"Str",Headers, "uInt",StrLen(Headers)
	, "Str",POSTData,"uInt",StrLen(POSTData))

VarSetCapacity(header, 2048, 0)  ; max 2K header data for httpResponseHeader
VarSetCapacity(header_len, 4, 0)

; Check for returned server response-header (works only _after_ request been sent)
; http://msdn.microsoft.com/en-us/library/aa384238.aspx
Loop, 5
if ((headerRequest:=DllCall("WinINet\HttpQueryInfoA","uint",hRequest
	,"uint",21,"uint",&header,"uint",&header_len,"uint",0))=1)
	break

if (headerRequest=1) {
	VarSetCapacity(res,headerLength:=NumGet(header_len),32)
	DllCall("RtlMoveMemory","uInt",&res,"uInt",&header,"uInt",headerLength)
	Loop,% headerLength
		if (*(&res-1+a_index)=0) ; Change binary zero to linefeed
			NumPut(Asc("`n"),res,a_index-1,"uChar")
	VarSetCapacity(res,-1)
} else
	res := "timeout"

; Get 1st Line of Full Response
Loop,Parse,res,`n,`r
{
	RetValue := A_LoopField
	break
}

; No Connection established - drop exception
if (RetValue="timeout") {
	html := "Error: timeout"
	return -1
}
; Strip protocol version from return value
RetValue := RegExReplace(RetValue,"HTTP/1\.[01]\s+")

; List taken from http://en.wikipedia.org/wiki/List_of_HTTP_status_codes
HttpRetCodes := "100=continue|101=Switching Protocols|102=Processing (WebDAV) (RFC 2518)|"
. "200=OK|201=Created|202=Accepted|203=Non-Authoritative Information|204=No"
. " Content|205=Reset Content|206=Partial Content|207=Multi-Status (WebDAV)"
. "|300=Multiple Choices|301=Moved Permanently|302=Found|303=See Other|304="
. "Not Modified|305=Use Proxy|306=Switch Proxy|307=Temporary Redirect|400=B"
. "ad Request|401=Unauthorized|402=Payment Required|403=Forbidden|404=Not F"
. "ound|405=Method Not Allowed|406=Not Acceptable|407=Proxy Authentication "
. "Required|408=Request Timeout|409=Conflict|410=Gone|411=Length Required|4"
. "12=Precondition Failed|413=Request Entity Too Large|414=Request-URI Too "
. "Long|415=Unsupported Media Type|416=Requested Range Not Satisfiable|417="
. "Expectation Failed|418=I'm a teapot (RFC 2324)|422=UnProcessable Entity "
. "(WebDAV) (RFC 4918)|423=Locked (WebDAV) (RFC 4918)|424=Failed Dependency"
. " (WebDAV) (RFC 4918)|425=Unordered Collection (RFC 3648)|426=Upgrade Req"
. "uired (RFC 2817)|449=Retry With|500=Internal Server Error|501=Not Implem"
. "ented|502=Bad Gateway|503=Service Unavailable|504=Gateway Timeout|505=HT"
. "TP Version Not Supported|506=Variant Also Negotiates (RFC 2295)|507=Insu"
. "fficient Storage (WebDAV) (RFC 4918)|509=Bandwidth Limit Exceeded|510=No"
. "t Extended (RFC 2774)"

; Gather numeric response value
RetValue := SubStr(RetValue,1,3)

; Parse through return codes and set according informations
Loop,Parse,HttpRetCodes,|
{
	HttpreturnCode := SubStr(A_LoopField,1,3)    ; Numeric return value see above
	HttpreturnMsg  := SubStr(A_LoopField,5)      ; link for additional information
	if (RetValue=HttpreturnCode) {
		RetMsg := HttpreturnMsg
		break
	}
}

; Global HttpQueryOps handling
if StrLen(HTTPQueryOps)>0 {
	; Show full Header response (usefull for debugging)
	if (InStr(HTTPQueryOps,"showHeader"))
		MsgBox % res
	; Save the full Header response in a global Variable
	if (InStr(HTTPQueryOps,"storeHeader"))
		global HttpQueryHeader := res
	; Check for size updates to export to a global Var
	if (InStr(HTTPQueryOps,"updateSize")) {
		Loop,Parse,res,`n
			if RegExMatch(A_LoopField,"Content-Length:\s+?(?P<Size>\d+)",full) {
				global HttpQueryFullSize := fullSize
				break
			}
		if (fullSize+0=0)
			HttpQueryFullSize := "size unavailable"
	}
}

; Check for valid codes and drop exception if suspicious
if !(InStr("100 200 201 202 302",RetValue)) {
	Result := RetValue " " RetMsg
	return StrLen(Result)
}

VarSetCapacity(BytesRead,4,0)
fsize := 0
Loop            ; the receiver loop - rewritten in the need to enable
{               ; support for larger file downloads
	bc := A_Index
	VarSetCapacity(buffer%bc%,1024,0) ; setup new chunk for this receive round
	ReadFile := DllCall("wininet\InternetReadFile"
		,"uInt",hRequest,"uInt",&buffer%bc%,"uInt",1024,"uInt",&BytesRead)
	ReadBytes := NumGet(BytesRead)    ; how many bytes were received?
	if ((ReadFile!=0)&&(!ReadBytes))  ; we have had no error yet and received no more bytes
		break                         ; we must be done! so lets break the receiver loop
	else {
		fsize += ReadBytes            ; sum up all chunk sizes for correct return size
		sizeArray .= ReadBytes "|"
	}
	if (InStr(HTTPQueryOps,"updateSize"))
		Global HttpQueryCurrentSize := fsize
}
sizeArray := SubStr(sizeArray,1,-1)   ; trim last PipeChar

VarSetCapacity( ( dReturn == true ) ? result : p1 ,fSize+1,0)      ; reconstruct the result from above generated chunkblocks
Dest := ( dreturn == true ) ? &result : &p1                 ; to a our ByRef result variable
Loop,Parse,SizeArray,|
DllCall("RtlMoveMemory","uInt",Dest,"uInt",&buffer%A_Index%,"uInt",A_LoopField)
	, Dest += A_LoopField

DllCall("WinINet\InternetCloseHandle", "uInt", hRequest)   ; close all opened
DllCall("WinINet\InternetCloseHandle", "uInt", hInternet)
DllCall("WinINet\InternetCloseHandle", "uInt", hConnect)
DllCall("FreeLibrary", "UInt", hModule)                    ; unload the library

if ( dreturn == true ) {
	VarSetCapacity( result, -1 )
	ErrorLevel := fSize
	return Result
} else
return fSize                      ; return the size - strings need update via VarSetCapacity(res,-1)
}


说明:

这个函数有以下功能:


● 支持URL含有端口

● “用户名:密码@域名”格式的URL

● SSL(https)

● HTTP 报头信息 / Dumping(转储) / Storing(存储)

● 下载进度条界面

● 网络连接处理的标识 (自动跟踪特性等)

● 来源页支持

● 客户端接受到的MIME类型的支持

● 代理支持

● 超时支持

● 自定义浏览器UserAgent


使用方法很简单:

0.3.6版本引入另外一种语法与功能支持。从而简化了功能的使用。长话短说:

如果第一个参数不是空变量且包含有URL,httpquery会直接返回数据,消除了额外varsetcapacity的调用需要。然而旧的语法仍然是可用的和工作,所以使用此功能的脚本都需要进行改变。

记住,当处理二进制数据为压缩文件、下载可执行文件、或图片,我们将第一个参数为空值和第二包含URL。


使用新的语法:


html := httpQUERY(URL:="http://url") 将会返回获取到的html全文,长度为Errorlevel,使用的是GET方式,postparams(POST参数)长度为零。

html := httpQUERY(URL:="http://url",POSTDATA) 将会POST数据如果POSTDATA长度不为0


使用老的语法:


你需要定义一个变量将接收返回的数据缓存。所以VarSetCapacity(buffer,-1)释放内存是有必要的。


httpQUERY(buffer:="",URL) 将会返回长度,第一个参数将会缓存获取到的html全文,使用的是GET方式,postparams(POST参数)长度为零。

httpQUERY(buffer:="",URL,POSTDATA) 将会POST数据如果POSTDATA长度不为0


现在支持以下格式的URL:

<!– m –>http://username:pass… … s#fragment<!– m –>


Since httpQuery has been updated to use InternetCrackURL from winINet, all essential parts will be recognized. so there is no need to set up any additional parameters. Attention: When u need to authetificate in the Website the username / password attempt will not work. u have to submit those parameters via POST or GET method. 


Additional Parameters:

To see a dump of the received httpHeaders, there is buildIn support for a global Variable named httpQueryOps. It may consist of one or more Verbs. For now "showHeader", "storeHeader", and "updateSize" verbs are supported. If You use storeHeader the complete Header will be saved in a variable named HttpQueryHeader which will be made global at runtime. The verb updateSize will make two variables globally Available: httpQueryFullSize and httpQueryCurrentSize. An usage example to show a download status indicator is included


以下变量进行全局:

httpAgent:UserAgent,默认是AutoHotkeyScript

httpProxy: 代理,default = 0

httpProxyByPass: 不使用代理的网址列表. default = 0

httpQueryReferer: 来源页

httpQueryAcceptType: 客户端接受到的MIME类型

httpQueryDwFlags: if in need for any special flags for the current connection this is the variable to set (example V shows an useCase for this feat)


示例1 POST数据

url := "http://thinkai.net/test.php"
MsgBox, % httpQUERY(url,"a=1&b=我")

示例2 GET数据

url := "http://thinkai.net/test.php"
MsgBox, % httpQUERY(url "?a=1&b=我")

示例3 下载文件并存储

#noenv
data     := ""
URL      := "http://www.autohotkey.net/programs/AutoHotkey104706.zip"
httpQueryOps := "updateSize"
SetTimer,showSize,10
length   := httpQuery(data,URL)
Tooltip
if (write_bin(data,"ahk.exe",length)!=1)
	MsgBox "出错!"
else
	MsgBox "ahk.zip"已保存!
Return

showSize:
   Tooltip,% HttpQueryCurrentSize "/" HttpQueryFullSize
return

GuiClose:
GuiEscape:
   ExitApp

write_bin(byref bin,filename,size){
   h := DllCall("CreateFile","str",filename,"Uint",0x40000000
            ,"Uint",0,"UInt",0,"UInt",4,"Uint",0,"UInt",0)
   IfEqual h,-1, SetEnv, ErrorLevel, -1
   IfNotEqual ErrorLevel,0,ExitApp ; couldn't create the file
   r := DllCall("SetFilePointerEx","Uint",h,"Int64",0,"UInt *",p,"Int",0)
   IfEqual r,0, SetEnv, ErrorLevel, -3
   IfNotEqual ErrorLevel,0, {
      t = %ErrorLevel%              ; save ErrorLevel to be returned
      DllCall("CloseHandle", "Uint", h)
      ErrorLevel = %t%              ; return seek error
   }
   result := DllCall("WriteFile","UInt",h,"Str",bin,"UInt"
               ,size,"UInt *",Written,"UInt",0)
   h := DllCall("CloseHandle", "Uint", h)
   return, 1
}

#include httpQuery.ahk

示例4  上传图片到Imageshack使用官方(免费)API

; exmpl.imageshack.httpQuery.ahk
; This example uploads an image and constructs a multipart/form-data Type
; for fileuploading and returns the XML which is returned to show the stored Imagepath
	FileSelectFile,image
	FileGetSize,size,%image%
	SplitPath,image,OFN
	FileRead,img,%image%
	VarSetCapacity(placeholder,size,32)
	boundary := makeProperBoundary()
	post:="--" boundary "`ncontent-disposition: form-data; name=""MAX_FILE_SIZE""`n`n"
		. "1048576`n--" boundary "`ncontent-disposition: form-data; name=""xml""`n`nyes`n--"
		. boundary "`ncontent-disposition: form-data; name=""fileupload""; filename="""
		. ofn """`nContent-type: " MimeType(img) "`nContent-Transfer-Encoding: binary`n`n" 
		. placeholder "`n--" boundary "--"
	headers:="Content-type: multipart/form-data, boundary=" boundary "`nContent-Length: " strlen(post)
	DllCall("RtlMoveMemory","uInt",(offset:=&post+strlen(post)-strlen(Boundary)-size-5)
			,"uInt",&img,"uInt",size)
	size := httpQuery(result:="","http://www.imageshack.us/index.php",post,headers)
	VarSetCapacity(result,-1)
	Gui,Add,Edit,w800 h600, % result
	Gui,Show
return

GuiClose:
GuiEscape:
	ExitApp

makeProperBoundary(){
	Loop,26
		n .= chr(64+a_index)
	n .= "0123456789"
	Loop,% StrLen(A_Now) {
		Random,rnd,1,% StrLen(n)
		Random,UL,0,1
		b .= RegExReplace(SubStr(n,rnd,1),".$","$" (round(UL)? "U":"L") "0")
	}
	Return b
}

MimeType(ByRef Binary) {
	MimeTypes:="424d image/bmp|4749463 image/gif|ffd8ffe image/jpeg|89504e4 image/png|4657530"
			 . " application/x-shockwave-flash|49492a0 image/tiff"
	@:="0123456789abcdef"
	Loop,8
		hex .= substr(@,(*(a:=&Binary-1+a_index)>>4)+1,1) substr(@,((*a)&15)+1,1)
	Loop,Parse,MimeTypes,|
		if ((substr(hex,1,strlen(n:=RegExReplace(A_Loopfield,"\s.*"))))=n) 
			Mime := RegExReplace(A_LoopField,".*?\s")
	Return (Mime!="") ? Mime : "application/octet-stream"
}

#include httpQuery.ahk

更多示例详见顶部来源


友情链接:Autohotkey中文论坛Autohotkey中文帮助Autohotkey官网我的B站直播间如若生涯一场梦博客联系作者免GooglePlay APK下载

 主题设计 • skyfrit.com  Thinkai's Blog | 保留所有权利

49 queries in 1.045 seconds |