Advertisement
jasondavis

HTTPQuery.ahk

Sep 4th, 2011
834
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. ; httpQuery-0-3-6.ahk
  2. httpQuery(byref p1 = "", p2 = "", p3="", p4="")
  3. {   ; v0.3.6 (w) Oct, 26 2010 by derRaphael / zLib-Style release
  4.    ; currently the verbs showHeader, storeHeader, and updateSize are supported in httpQueryOps
  5.    ; in case u need a different UserAgent, Proxy, ProxyByPass, Referrer, and AcceptType just
  6.    ; specify them as global variables - mind the varname for referrer is httpQueryReferer [sic].
  7.    ; Also if any special dwFlags are needed such as INTERNET_FLAG_NO_AUTO_REDIRECT or cache
  8.    ; handling this might be set using the httpQueryDwFlags variable as global
  9.    global httpQueryOps, httpAgent, httpProxy, httpProxyByPass, httpQueryReferer, httpQueryAcceptType
  10.        , httpQueryDwFlags
  11.    ; Get any missing default Values
  12.    
  13.    ;v0.3.6
  14.    ; check for syntax
  15.    if ( VarSetCapacity(p1) != 0 )
  16.       dReturn:=true,  result := "", lpszUrl := p1, POSTDATA := p2, HEADERS  := p3
  17.    else
  18.       result := p1, lpszUrl := p2, POSTDATA := p3, HEADERS  := p4
  19.    
  20.    defaultOps =
  21.    (LTrim Join|
  22.       httpAgent=AutoHotkeyScript|httpProxy=0|httpProxyByPass=0|INTERNET_FLAG_SECURE=0x00800000
  23.       SECURITY_FLAG_IGNORE_UNKNOWN_CA=0x00000100|SECURITY_FLAG_IGNORE_CERT_CN_INVALID=0x00001000
  24.       SECURITY_FLAG_IGNORE_CERT_DATE_INVALID=0x00002000|SECURITY_FLAG_IGNORE_CERT_WRONG_USAGE=0x00000200
  25.       INTERNET_OPEN_TYPE_PROXY=3|INTERNET_OPEN_TYPE_DIRECT=1|INTERNET_SERVICE_HTTP=3
  26.    )
  27.    Loop,Parse,defaultOps,|
  28.    {
  29.       RegExMatch(A_LoopField,"(?P<Option>[^=]+)=(?P<Default>.*)",http)
  30.       if StrLen(%httpOption%)=0
  31.          %httpOption% := httpDefault
  32.    }
  33.  
  34.    ; Load Library
  35.    hModule := DllCall("LoadLibrary", "Str", "WinINet.Dll")
  36.  
  37.    ; SetUpStructures for URL_COMPONENTS / needed for InternetCrackURL
  38.    ; http://msdn.microsoft.com/en-us/library/aa385420(VS.85).aspx
  39.    offset_name_length:= "4-lpszScheme-255|16-lpszHostName-1024|28-lpszUserName-1024|"
  40.                   . "36-lpszPassword-1024|44-lpszUrlPath-1024|52-lpszExtrainfo-1024"
  41.    VarSetCapacity(URL_COMPONENTS,60,0)
  42.    ; Struc Size               ; Scheme Size                  ; Max Port Number
  43.    NumPut(60,URL_COMPONENTS,0), NumPut(255,URL_COMPONENTS,12), NumPut(0xffff,URL_COMPONENTS,24)
  44.    
  45.    Loop,Parse,offset_name_length,|
  46.    {
  47.       RegExMatch(A_LoopField,"(?P<Offset>\d+)-(?P<Name>[a-zA-Z]+)-(?P<Size>\d+)",iCU_)
  48.       VarSetCapacity(%iCU_Name%,iCU_Size,0)
  49.       NumPut(&%iCU_Name%,URL_COMPONENTS,iCU_Offset)
  50.       NumPut(iCU_Size,URL_COMPONENTS,iCU_Offset+4)
  51.    }
  52.  
  53.    ; Split the given URL; extract scheme, user, pass, authotity (host), port, path, and query (extrainfo)
  54.    ; http://msdn.microsoft.com/en-us/library/aa384376(VS.85).aspx
  55.    DllCall("WinINet\InternetCrackUrlA","Str",lpszUrl,"uInt",StrLen(lpszUrl),"uInt",0,"uInt",&URL_COMPONENTS)
  56.  
  57.    ; Update variables to retrieve results
  58.    Loop,Parse,offset_name_length,|
  59.    {
  60.       RegExMatch(A_LoopField,"-(?P<Name>[a-zA-Z]+)-",iCU_)
  61.       VarSetCapacity(%iCU_Name%,-1)
  62.    }
  63.    nPort:=NumGet(URL_COMPONENTS,24,"uInt")
  64.    
  65.    ; Import any set dwFlags
  66.    dwFlags := httpQueryDwFlags
  67.    ; For some reasons using a selfsigned https certificates doesnt work
  68.    ; such as an own webmin service - even though every security is turned off
  69.    ; https with valid certificates works when
  70.    if (lpszScheme = "https")
  71.       dwFlags |= (INTERNET_FLAG_SECURE|SECURITY_FLAG_IGNORE_CERT_CN_INVALID
  72.                |SECURITY_FLAG_IGNORE_CERT_WRONG_USAGE)
  73.  
  74.    ; Check for Header and drop exception if unknown or invalid URL
  75.    if (lpszScheme="unknown") {
  76.       Result := "ERR: No Valid URL supplied."
  77.       Return StrLen(Result)
  78.    }
  79.  
  80.    ; Initialise httpQuery's use of the WinINet functions.
  81.    ; http://msdn.microsoft.com/en-us/library/aa385096(VS.85).aspx
  82.    hInternet := DllCall("WinINet\InternetOpenA"
  83.                   ,"Str",httpAgent,"UInt"
  84.                   ,(httpProxy != 0 ?  INTERNET_OPEN_TYPE_PROXY : INTERNET_OPEN_TYPE_DIRECT )
  85.                   ,"Str",httpProxy,"Str",httpProxyBypass,"Uint",0)
  86.  
  87.    ; Open HTTP session for the given URL
  88.    ; http://msdn.microsoft.com/en-us/library/aa384363(VS.85).aspx
  89.    hConnect := DllCall("WinINet\InternetConnectA"
  90.                   ,"uInt",hInternet,"Str",lpszHostname, "Int",nPort
  91.                   ,"Str",lpszUserName, "Str",lpszPassword,"uInt",INTERNET_SERVICE_HTTP
  92.                   ,"uInt",0,"uInt*",0)
  93.  
  94.    ; Do we POST? If so, check for header handling and set default
  95.    if (Strlen(POSTDATA)>0) {
  96.       HTTPVerb:="POST"
  97.       if StrLen(Headers)=0
  98.          Headers:="Content-Type: application/x-www-form-urlencoded"
  99.    } else ; otherwise mode must be GET - no header defaults needed
  100.       HTTPVerb:="GET"  
  101.  
  102.    ; Form the request with proper HTTP protocol version and create the request handle
  103.    ; http://msdn.microsoft.com/en-us/library/aa384233(VS.85).aspx
  104.    hRequest := DllCall("WinINet\HttpOpenRequestA"
  105.                   ,"uInt",hConnect,"Str",HTTPVerb,"Str",lpszUrlPath . lpszExtrainfo
  106.                   ,"Str",ProVer := "HTTP/1.1", "Str",httpQueryReferer,"Str",httpQueryAcceptTypes
  107.                   ,"uInt",dwFlags,"uInt",Context:=0 )
  108.  
  109.    ; Send the specified request to the server
  110.    ; http://msdn.microsoft.com/en-us/library/aa384247(VS.85).aspx
  111.    sRequest := DllCall("WinINet\HttpSendRequestA"
  112.                   , "uInt",hRequest,"Str",Headers, "uInt",Strlen(Headers)
  113.                   , "Str",POSTData,"uInt",Strlen(POSTData))
  114.  
  115.    VarSetCapacity(header, 2048, 0)  ; max 2K header data for httpResponseHeader
  116.    VarSetCapacity(header_len, 4, 0)
  117.    
  118.    ; Check for returned server response-header (works only _after_ request been sent)
  119.    ; http://msdn.microsoft.com/en-us/library/aa384238.aspx
  120.    Loop, 5
  121.      if ((headerRequest:=DllCall("WinINet\HttpQueryInfoA","uint",hRequest
  122.       ,"uint",21,"uint",&header,"uint",&header_len,"uint",0))=1)
  123.       break
  124.  
  125.    If (headerRequest=1) {
  126.       VarSetCapacity(res,headerLength:=NumGet(header_len),32)
  127.       DllCall("RtlMoveMemory","uInt",&res,"uInt",&header,"uInt",headerLength)
  128.       Loop,% headerLength
  129.          if (*(&res-1+a_index)=0) ; Change binary zero to linefeed
  130.             NumPut(Asc("`n"),res,a_index-1,"uChar")
  131.       VarSetCapacity(res,-1)
  132.    } else
  133.       res := "timeout"
  134.  
  135.    ; Get 1st Line of Full Response
  136.    Loop,Parse,res,`n,`r
  137.    {
  138.       RetValue := A_LoopField
  139.       break
  140.    }
  141.    
  142.    ; No Connection established - drop exception
  143.    If (RetValue="timeout") {
  144.       html := "Error: timeout"
  145.       return -1
  146.    }
  147.    ; Strip protocol version from return value
  148.    RetValue := RegExReplace(RetValue,"HTTP/1\.[01]\s+")
  149.    
  150.     ; List taken from http://en.wikipedia.org/wiki/List_of_HTTP_status_codes
  151.    HttpRetCodes := "100=Continue|101=Switching Protocols|102=Processing (WebDAV) (RFC 2518)|"
  152.               . "200=OK|201=Created|202=Accepted|203=Non-Authoritative Information|204=No"
  153.               . " Content|205=Reset Content|206=Partial Content|207=Multi-Status (WebDAV)"
  154.               . "|300=Multiple Choices|301=Moved Permanently|302=Found|303=See Other|304="
  155.               . "Not Modified|305=Use Proxy|306=Switch Proxy|307=Temporary Redirect|400=B"
  156.               . "ad Request|401=Unauthorized|402=Payment Required|403=Forbidden|404=Not F"
  157.               . "ound|405=Method Not Allowed|406=Not Acceptable|407=Proxy Authentication "
  158.               . "Required|408=Request Timeout|409=Conflict|410=Gone|411=Length Required|4"
  159.               . "12=Precondition Failed|413=Request Entity Too Large|414=Request-URI Too "
  160.               . "Long|415=Unsupported Media Type|416=Requested Range Not Satisfiable|417="
  161.               . "Expectation Failed|418=I'm a teapot (RFC 2324)|422=Unprocessable Entity "
  162.               . "(WebDAV) (RFC 4918)|423=Locked (WebDAV) (RFC 4918)|424=Failed Dependency"
  163.               . " (WebDAV) (RFC 4918)|425=Unordered Collection (RFC 3648)|426=Upgrade Req"
  164.               . "uired (RFC 2817)|449=Retry With|500=Internal Server Error|501=Not Implem"
  165.               . "ented|502=Bad Gateway|503=Service Unavailable|504=Gateway Timeout|505=HT"
  166.               . "TP Version Not Supported|506=Variant Also Negotiates (RFC 2295)|507=Insu"
  167.               . "fficient Storage (WebDAV) (RFC 4918)|509=Bandwidth Limit Exceeded|510=No"
  168.               . "t Extended (RFC 2774)"
  169.    
  170.    ; Gather numeric response value
  171.    RetValue := SubStr(RetValue,1,3)
  172.    
  173.    ; Parse through return codes and set according informations
  174.    Loop,Parse,HttpRetCodes,|
  175.    {
  176.       HttpReturnCode := SubStr(A_LoopField,1,3)    ; Numeric return value see above
  177.       HttpReturnMsg  := SubStr(A_LoopField,5)      ; link for additional information
  178.       if (RetValue=HttpReturnCode) {
  179.          RetMsg := HttpReturnMsg
  180.          break
  181.       }
  182.    }
  183.  
  184.    ; Global HttpQueryOps handling
  185.    if strlen(HTTPQueryOps)>0 {
  186.       ; Show full Header response (usefull for debugging)
  187.       if (instr(HTTPQueryOps,"showHeader"))
  188.          MsgBox % res
  189.       ; Save the full Header response in a global Variable
  190.       if (instr(HTTPQueryOps,"storeHeader"))
  191.          global HttpQueryHeader := res
  192.       ; Check for size updates to export to a global Var
  193.       if (instr(HTTPQueryOps,"updateSize")) {
  194.          Loop,Parse,res,`n
  195.             If RegExMatch(A_LoopField,"Content-Length:\s+?(?P<Size>\d+)",full) {
  196.                global HttpQueryFullSize := fullSize
  197.                break
  198.             }
  199.          if (fullSize+0=0)
  200.             HttpQueryFullSize := "size unavailable"
  201.       }
  202.    }
  203.  
  204.    ; Check for valid codes and drop exception if suspicious
  205.    if !(InStr("100 200 201 202 302",RetValue)) {
  206.       Result := RetValue " " RetMsg
  207.       return StrLen(Result)
  208.    }
  209.  
  210.    VarSetCapacity(BytesRead,4,0)
  211.    fsize := 0
  212.    Loop            ; the receiver loop - rewritten in the need to enable
  213.    {               ; support for larger file downloads
  214.       bc := A_Index
  215.       VarSetCapacity(buffer%bc%,1024,0) ; setup new chunk for this receive round
  216.       ReadFile := DllCall("wininet\InternetReadFile"
  217.                   ,"uInt",hRequest,"uInt",&buffer%bc%,"uInt",1024,"uInt",&BytesRead)
  218.       ReadBytes := NumGet(BytesRead)    ; how many bytes were received?
  219.       If ((ReadFile!=0)&&(!ReadBytes))  ; we have had no error yet and received no more bytes
  220.          break                         ; we must be done! so lets break the receiver loop
  221.       Else {
  222.          fsize += ReadBytes            ; sum up all chunk sizes for correct return size
  223.          sizeArray .= ReadBytes "|"
  224.       }
  225.       if (instr(HTTPQueryOps,"updateSize"))
  226.          Global HttpQueryCurrentSize := fsize
  227.    }
  228.    sizeArray := SubStr(sizeArray,1,-1)   ; trim last PipeChar
  229.    
  230.    VarSetCapacity( ( dReturn == true ) ? result : p1 ,fSize+1,0)      ; reconstruct the result from above generated chunkblocks
  231.    Dest := ( dReturn == true ) ? &result : &p1                 ; to a our ByRef result variable
  232.    Loop,Parse,SizeArray,|
  233.       DllCall("RtlMoveMemory","uInt",Dest,"uInt",&buffer%A_Index%,"uInt",A_LoopField)
  234.       , Dest += A_LoopField
  235.      
  236.    DllCall("WinINet\InternetCloseHandle", "uInt", hRequest)   ; close all opened
  237.    DllCall("WinINet\InternetCloseHandle", "uInt", hInternet)
  238.    DllCall("WinINet\InternetCloseHandle", "uInt", hConnect)
  239.    DllCall("FreeLibrary", "UInt", hModule)                    ; unload the library
  240.    
  241.    if ( dReturn == true ) {
  242.       VarSetCapacity( result, -1 )
  243.       ErrorLevel := fSize
  244.       return Result
  245.    } else
  246.       return fSize                      ; return the size - strings need update via VarSetCapacity(res,-1)
  247. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement