//url 网址分析 namespace inet.url; ::Shlwapi := ..raw.loadDll("Shlwapi.dll"); is = function(url,urlis){ if(type(url)!="string") return false; return Shlwapi.UrlIsA(url,urlis : 0); } UrlCombine = Shlwapi.api("UrlCombineW", "int(ustring base,ustring relative,ustring& combined,INT& size, INT flags)" ) joinpath = function(base,relative,flag=0){ if(!#relative)return base; var hr,url,cch = UrlCombine(base,relative,0,0,flag); var hr,url = UrlCombine(base,relative,cch,cch,flag); if( !hr) return url; } append = function(base,relative,...){ if( base[#base] != '/'# ) base = base + "/" var url = joinpath( base,..string.trimleft(relative,"/\") ); if(!...) return url; return append(url,...); } appendExtraInfo = function(url,param){ if(type(param)==="table"){param=stringifyParameters(param)} if(!#param) return url; var turl = split(url); if(turl) { if( #turl.extraInfo ) turl.extraInfo = turl.extraInfo + "&" + param; else turl.extraInfo = param; return tostring(turl); } return url + "?" + param; } UrlCanonicalize = Shlwapi.api("UrlCanonicalizeW","int(ustring url,ustring& out,INT& size, INT flags)" ) canonicalize = function(url,flag=0){ var hr,url = UrlCanonicalize(url,0x1000,0x800,flag) if( !hr ) return url; } cmp = function(url,url2){ return ..string.cmp(canonicalize( decode(url) ),canonicalize( decode(url2) )); } hashNum = function(url){ var hr,hash = ::Shlwapi.HashData(url,#url,{INT value},4); if(!hr) return hash.value; } encode = function(s,cp){ if( cp === null ) cp = 65001; elseif( type(cp) != "number") cp = cp ? 65001 : 0; if( cp != 65001 ) s = ..string.fromto(s,65001,cp); return ..string.hex(s,"%","-._~"); } encodeUri = function(s,cp){ if( cp === null ) cp = 65001; elseif( type(cp) != "number") cp = cp ? 65001 : 0; if( cp != 65001 ) s = ..string.fromto(s,65001,cp); return ..string.hex(s,"%","-._~!*'();/?:@&=+$,#[]"); } encodeMbcs = function(s,cp){ if(!..string.find(s,":") ) return s; if( cp === null ) cp = 65001; elseif( type(cp) != "number") cp = cp ? 65001 : 0; if( cp != 65001 ) s = ..string.fromto(s,65001,cp); return ..string.hex(s,"%",'\x80'); } decodeUnicode = function(s){ s = ..string.replace(s,"\%u(\x\x\x\x)", "\\u\1" ); return decode(..string.unescape(s),true); } decode = function(s,cp){ if(!s) return; if( cp === null ) cp = "test"; elseif( type(cp) != "number") cp = cp ? 65001 : 0; s = ..string.replace(s,"\+"," "); s = ..string.unhex(s,"%"); if(!s) return; if(cp === "test"){ if( !..string.isUtf8(s) ){ return ..string.fromto(s,0,65001); } } elseif( cp != 65001 ) { return ..string.fromto(s,cp,65001); } return s; } stringifyParameters = function(param,cp,cmp){ if( type(param) != "table" ) return param; var lst,k,v,t = {}; for(k,v in ..table.eachName(param,cmp) ){ k = encode(k,cp); t = type(v) if(t===type.table){ for(i=1;#v;1){ ..table.push( lst,k,"[]=",( encode(tostring(v[i]),cp) ),"&" ) } for p,v in ..table.eachName(v,cmp){ ..table.push( lst,k,"[",encode(p,cp),"]=",( encode(tostring(v),cp) ),"&" ) } } else { if(t==="function") v = v(); ..table.push( lst,k,"=",( encode(tostring(v),cp) ),"&" ) } } if( lst[#lst] == '&' ) ..table.pop(lst) return ..string.join(lst ); } buildQuery = stringifyParameters;//@Deprecated sortParameters = function(p,cmp){ var t = p; if(type(t)!="table") t = splitParametersCs(p); return stringifyParameters(t,,cmp) } splitParametersCs = lambda(p,d,c,a)splitParameters(p,d,c,a,true) var searchParamsMeta = {_readonly=false;_type="object";_tostring=lambda() stringifyParameters(owner)} splitParameters = function(param,delimiter,cp,arrKey,caseSensitive){ var list,k,v = {@searchParamsMeta}; if( (param[1] == '?'#) && (delimiter===null) ) param = ..string.right(param,-2); for line in ..string.lines(param,delimiter : "\&\s*") { var kv = ..string.split(line,"=",2); k = #kv>0 ? decode(kv[1],cp) : kv[1]; if(!k) continue; if(!caseSensitive) k = ..string.lower(k); if(#kv==2) { v = decode( kv[2],cp ); if( k[#k] == ']'# ){ var n,p = ..string.match(k,"(.+)\[(.*)\]"); if(n){ if( type(list[n]) != type.table ){ list[n] = {list[n]} } if(#p){ list[n][tonumber(p):p] = v; } else { ..table.push(list[n],v); } continue; } } if(arrKey){ var k = ..string.match(k,"(.+)\.\d+$") || k; if(..table.find(arrKey,k)){ if( list[k] ) ..table.push(list[k],v); else list[k] = {v}; continue; } } list[k] = v; } elseif(#kv==1){list[k]=""} } return list; } ::Wininet := ..raw.loadDll("Wininet.dll") var _urlinfo = { _tostring = function(){ var push = ..table.push; var t = {owner.scheme:"http";'://'}; if(owner.user){ push(t,encode(owner.user));if(owner.password){ push(t,":",encode(owner.password));} push(t,"@"); } push(t,owner.host); if(owner.port){ if( ..string.cmp(owner.scheme,"https") == 0 ){ if( owner.port != 443 ) push(t,":",owner.port); } elseif( owner.port != 80 ) push(t,":",owner.port); } if(#owner.path){ if( owner.path[1] !='/'#){ push(t,"/"); } push(t,owner.path); } if(type(owner.extraInfo)=="table"){ push(t,"?",stringifyParameters(owner.extraInfo)); } elseif(owner.extraInfo) { if(owner.extraInfo[1]!='?'#) push(t,"?"); push(t,owner.extraInfo); } if(#owner.location)push(t,"#",owner.location); return ..string.join(t); } } stringify = function(info){ return tostring( ..table.assign( split(),info) ); } split = function(url,sortParam){ var info = { INT size = 60; ptr scheme; INT schemeLen = 1; INT schemeNum; ptr host; INT hostLen = 1; WORD port; ptr user; INT userLen = 1; ptr password; INT passwordLen = 1; ptr path; INT pathLen = 1; ptr extraInfo ; INT extraInfoLen = 1; }; if(!url) return {@_urlinfo}; url = ..string.toUtf16(url); var ok = ::Wininet.InternetCrackUrlW(url,#url/2,0,info); if(ok){ var v; var r = {@_urlinfo}; info.size = null; for(k,len in info){ var n = ..string.match(k,"(\w+)Len"); if(!n){ if( type(len)=="number") r[k]=len;continue;} v = info[n]; if(v) r[n] = ..string.fromUtf16(v,,len); } if(r.scheme) r.scheme = ..string.lower(r.scheme); if(#r.extraInfo){ var a,b = ..string.match(r.extraInfo,"(.*)#(.*)$") if(a && b) { r.extraInfo = #a ? a : null; r.location = #b ? b : null; } if(sortParam && #r.extraInfo){ r.extraInfo = sortParameters(r.extraInfo); } } return r; } } getFileName = function(url,d){ var turl = split(url); if(!turl) return ""; var tpath = ..io.splitpath(turl.path) return #tpath.file ? tpath.file : d : "index.html"; } getFilePath = function(url){ if(!url) return; var turl = split(url) if(turl.schemeNum==5/*_INTERNET_SCHEME_FILE*/){ return ..string.trimleft(decode(turl.path),"/"); } } getParams = function(url,k){ if(!url) return; var tUrl = ..inet.url.split(url); var p = ..inet.url.splitParameters(!tUrl ? url : tUrl.extraInfo); if(k) return p[..string.lower(k)]; return p; }; getQuery = getParams;//@Deprecated /**intellisense(inet.url) is(url,_URLIS__) = 检测URL joinpath( = 当对于当前URL的相对路径转换为完整 URL 。\n注意该函数忽略文件名,简单拼接请使用 append 函数替代 joinpath(.("当前URL",相对路径,_URL__) = 当对于当前 URL 的相对路径转换为完整 URL 。\n相对路径如果为空则直接返回参数 @1,\n可选使用参数三指定转换选项 appendExtraInfo(.(url,附加参数) = 在 URL 后追加参数。\n参数首字符不能是问号。\n参数@2也可以指定一个包含多个参数键值对的表。\n\n如果 @url 参数仅指定路径而非合法 URL,\n则简单添加 ? 号后拼接参数 append( = 拼接URL append(.(url目录,url子路径,->->->) = 支持不定个数参数。\n第一个参数无论是否以"/"字符结束都认为是一个目录。 canonicalize(__/*URL*/) = URL规范化转换\n扩展和适当置换路径中包含的所有 .. 和 . canonicalize("当前URL",_URL__) = URL规范化转换\n参数@3指定转换选项 hashNum(__/*url*/) = 返回哈希数值 split( = 拆分 URL 获取各部分的信息 split(.(url,sortExtraInfo) = 拆分 URL 返回包含协议、路径、端口、参数等的表对象。\n返回的表对象可以调用 tostring 重新生成 URL。\n参数 @url 可传入空值以获取用于拼接 URL 的表。\n如果可选的参数 @sortExtraInfo 为 true ,\n则将 extraInfo 包含的请求参按以字段名称的字典序重新排序。 split() = !inetUrlInfo. stringify(urlInfo) = @.stringify(\n scheme = "https";\n user = "";\n password ="";\n host ="__/*使用参数表构建并返回URL字符串*/";\n location = "";\n extraInfo = {\n name = value;\n };\n) sortParameters(.(URL参数,排序函数) = 重新排序 URL 参数,首字符为问号时自动移除。\n参数 @1 可以指定包含名值对的表或者字符串格式的 URL 请求参数。\n可选用参数 @2 指定排序函数,排序函数的要求与用法与 table.eachName 相同 splitParameters( = 解析 URL 查询参数格式字符串并返回名值对组成的表对象,作用类似 JS 里的 URLSearchParams 。\n\n所有参数名字都转换为小写,改用 inet.url.splitParametersCs 则保留大小写。\n如果名字尾部有 `[]` 或 `[键名]` 则将值转换为表或数组。\n如果只指定名字不指定值,则值为空字符串\n\n返回的表对象可增删修改,作为参数传入 tostring 可再次序列化为 URL 查询参数格式字符串。\n调用 [inet.url.stringifyParameters](#inet.url.stringifyParameters) 也可以序列化表对象为这种格式的字符串。 splitParameters(.(urlSearchParams,delimiter,utf8,arrayKeys) = 反序列化查询参数格式字符串( 也是 x-www-form-urlencoded 表单编码格式)。\n\n拆分 URL 查询参数格式的字符串 @urlSearchParams(可以为空字符串),并返回表对象。\n@delimiter 指定参数分隔符,支持模式语法,默认为`\&&`。\n如果不指定 @delimiter, 并且首字符是`?`号,则自动移除开始的 `?` 号。\n\n使用 UrlEncode 格式解码 @urlSearchParams 中的键值,\n参数 @utf8 指定 @urlSearchParams 在解码前是否 UTF-8 编码,不指定则自动检测。\n\n参数 @arrayKeys 可选指定一个总是返回为数组值的参数名称数组,\n如果 @urlSearchParams 里的参数名尾部有点号加数值则自动移除。 splitParametersCs( = 解析 URL 查询参数格式字符串并返回名值对组成的表对象。\n所有参数名字保留原大小写不变,改用 inet.url.splitParameters 则转为小写。\n如果名字尾部有 `[]` 或 `[键名]` 则将值转换为表或数组。\n如果只指定名字不指定值,则值为空字符串\n\n返回的表对象可增删修改,作为参数传入 tostring 可再次序列化为 URL 查询参数格式字符串。 splitParametersCs(.(urlSearchParams,delimiter,utf8,arrayKeys) = 反序列化查询参数格式字符串( 也是 x-www-form-urlencoded 表单编码格式),参数名保留大小写不变。\n\n拆分 URL 查询参数格式的字符串 @urlSearchParams(可以为空字符串),并返回表对象。\n@delimiter 指定参数分隔符,支持模式语法,默认为`\&&`。\n如果不指定 @delimiter, 并且首字符是`?`号,则自动移除开始的 `?` 号。\n\n使用 UrlEncode 格式解码 @urlSearchParams 中的键值,\n参数 @utf8 指定 @urlSearchParams 在解码前是否 UTF-8 编码,不指定则自动检测。\n\n参数 @arrayKeys 可选指定一个总是返回为数组值的参数名称数组,\n如果 @urlSearchParams 里的参数名尾部有点号加数值则自动移除。 stringifyParameters( = 将表对象转换为 URL 查询参数格式的字符串。\n使用 [inet.url.splitParameters](#inet.url.splitParameters) 可重新解析这种格式的字符串并返回表对象。 stringifyParameters(.(参数表,输出代码页,排序函数) = 序列化参数表为 URL 查询参数格式的字符串( 也是 x-www-form-urlencoded 表单编码格式)。\n使用`=`分隔单个参数里的键值对,使用`&&`分隔多个参数。\n如果值为表,则转换为多个键值对,每个键值对由`参数名[]=值`或`参数名[子键名]=值`组成。\n如果参数名对应的值为函数则调用该函数取返回值。\n所有参数值转换为字符串并使用 UrlEncode 编码。\n参数@2指定输出编码(codepage),默认为 65001(UTF8代码页)\n省略排序函数则使用默认字典序排序。 encode(.(字符串,输出代码页) = 除字母数字以及-._~等非保留字符以外的字符进行URL编码,\n参数二指定输出编码(codepage),默认为65001(UTF8代码页) decode(.(字符串,输入代码页) = URL解码并返回文本,失败返回空值,\n参数二指定输入编码(codepage),省略自动检测输入编码\n此函数返回数据转换为UTF8编码 encodeMbcs(.(字符串,输出代码页) = 如果字符串包含多字节字符,\n使用URL编码其中的汉字和%符号,\n参数二指定输出编码(codepage),默认为65001(UTF8代码页) decodeUnicode(.(字符串) = 解码%uXXXX或%uXX编码的字符串\n失败返回空值 encodeUri(.(字符串,输出代码页) = URL编码,\n字母数字以及 URL 非保留字符、URL 保留字符都不编码(RFC3986),\n参数二指定输出编码(codepage),默认为65001(UTF8代码页) getFileName(.(网址,默认文件名) = 获取URL中的文件名\n参数2可选,默认为"index.html" getFilePath(__) = 如果 URL 为 file: 协议开头,\n则返回 URL 解码后的文件路径,否则返回 null。\n传入 null 参数返回 null。 getParams(__) = 返回 URL 的参数表,参数名都转为小写。\n参数 @1 指定 URL,如果不指定则直接返回 null 。\n如果参数 @1 指定了参数名(忽略大小写),则返回对应的字符串值 cmp(__) = 比较参数@1与参数@2指定的网址是否相同。\n相同则返回 0 ,否则返回其他数值。\n比较前进行 URL 解码,并调用 inet.url.canonicalize 规范格式,\n比较时忽略大小写 end intellisense**/ /*intellisense(!inetUrlInfo) scheme = 协议,总是转换为小写 schemeNum = 协议(数值)。\n可用值为 _INTERNET_SCHEME_ 前缀的常量定义。\n重新拼接 URL 时忽略此参数 host = 域名 user = 用户名 password = 密码 path = 文件路径; extraInfo = 附加的 URL 参数,\不包含`#`号后面的网页位置。\n如果有 URL 参数,这里首字符默认会是`?`号。\n如果拆分 URL 时指定了 sortExtraInfo 参数为 true,\n则 URL 参数按字段名称的字典序排序,并且首字符的号被移除。。\n\n在调用 tostring 将 对象重新合并为 URL 时:\n不要求 extraInfo 第一个字符是`?`号,合并时会自动判断是否要插入`?`号。\n如果 extraInfo指定表对象,则自动转换为字符串格式的请求参数。\n不同的参数按参数名字的字典序排序,并在前面添加`?`号。\n实际上就是自动调用 inet.url.stringifyParameters 。 port = 端口 location = URL中#号后面的网页位置,不包含#号 end intellisense*/ /**intellisense() inet.url = 网址(URL)函数库。\ninet.http,inet.whttp 以及所有 web.rest 客户端都已经自动导入 inet.url 。 _URLIS_URL=@0x0/*_URLIS_URL*/ _URLIS_OPAQUE=@//是否Opaque URL,如邮件地址,Javascript脚本\n0x1/*_URLIS_OPAQUE*/ _URLIS_NOHISTORY=@//URL是否未曾访问过\n0x2/*_URLIS_NOHISTORY*/ _URLIS_FILEURL=@//是否指向本机文件\n0x3/*_URLIS_FILEURL*/ _URLIS_APPLIABLE=@//检测URL指定的协议是否可用\n0x4/*_URLIS_APPLIABLE*/ _URLIS_DIRECTORY=@//检测URL是否指向目录\n0x5/*_URLIS_DIRECTORY*/ _URLIS_HASQUERY=@//检测URL是否有参数(Query String)\n0x6/*_URLIS_HASQUERY*/ _URL_UNESCAPE=@0x10000000/*_URL_UNESCAPE*/ _URL_ESCAPE_UNSAFE=@0x20000000/*_URL_ESCAPE_UNSAFE*/ _URL_PLUGGABLE_PROTOCOL=@0x40000000/*_URL_PLUGGABLE_PROTOCOL*/ _URL_WININET_COMPATIBILITY=@0x80000000/*_URL_WININET_COMPATIBILITY*/ _URL_DONT_ESCAPE_EXTRA_INFO=@0x2000000/*_URL_DONT_ESCAPE_EXTRA_INFO*/ _URL_DONT_UNESCAPE_EXTRA_INFO=@0x2000000/*_URL_DONT_UNESCAPE_EXTRA_INFO*/ _URL_BROWSER_MODE=@0x2000000/*_URL_BROWSER_MODE*/ _URL_ESCAPE_SPACES_ONLY=@0x4000000/*_URL_ESCAPE_SPACES_ONLY*/ _URL_DONT_SIMPLIFY=@0x8000000/*_URL_DONT_SIMPLIFY*/ _URL_NO_META=@0x8000000/*_URL_NO_META*/ _URL_CONVERT_IF_DOSPATH=@0x200000/*_URL_CONVERT_IF_DOSPATH*/ _URL_UNESCAPE_HIGH_ANSI_ONLY=@0x400000/*_URL_UNESCAPE_HIGH_ANSI_ONLY*/ _URL_INTERNAL_PATH=@0x800000/*_URL_INTERNAL_PATH*/ _URL_FILE_USE_PATHURL=@0x10000/*_URL_FILE_USE_PATHURL*/ _URL_DONT_UNESCAPE=@0x20000/*_URL_DONT_UNESCAPE*/ _URL_ESCAPE_AS_UTF8=@0x40000/*_URL_ESCAPE_AS_UTF8*/ _URL_ESCAPE_PERCENT=@0x1000/*_URL_ESCAPE_PERCENT*/ _URL_ESCAPE_SEGMENT_ONLY=@0x2000/*_URL_ESCAPE_SEGMENT_ONLY*/ _URL_PARTFLAG_KEEPSCHEME=@1/*_URL_PARTFLAG_KEEPSCHEME*/ _URL_APPLY_DEFAULT=@1/*_URL_APPLY_DEFAULT*/ _URL_APPLY_GUESSSCHEME=@2/*_URL_APPLY_GUESSSCHEME*/ _URL_APPLY_GUESSFILE=@4/*_URL_APPLY_GUESSFILE*/ _URL_APPLY_FORCEAPPLY=@8/*_URL_APPLY_FORCEAPPLY*/ _INTERNET_SCHEME_PARTIAL=@0xFFFFFFFE/*_INTERNET_SCHEME_PARTIAL*/ _INTERNET_SCHEME_UNKNOWN=@0xFFFFFFFF/*_INTERNET_SCHEME_UNKNOWN*/ _INTERNET_SCHEME_DEFAULT=@0x0/*_INTERNET_SCHEME_DEFAULT*/ _INTERNET_SCHEME_FTP=@1/*_INTERNET_SCHEME_FTP*/ _INTERNET_SCHEME_GOPHER=@2/*_INTERNET_SCHEME_GOPHER*/ _INTERNET_SCHEME_HTTP=@3/*_INTERNET_SCHEME_HTTP*/ _INTERNET_SCHEME_HTTPS=@4/*_INTERNET_SCHEME_HTTPS*/ _INTERNET_SCHEME_FILE=@5/*_INTERNET_SCHEME_FILE*/ _INTERNET_SCHEME_NEWS=@6/*_INTERNET_SCHEME_NEWS*/ _INTERNET_SCHEME_MAILTO=@7/*_INTERNET_SCHEME_MAILTO*/ _INTERNET_SCHEME_SOCKS=@8/*_INTERNET_SCHEME_SOCKS*/ _INTERNET_SCHEME_JAVASCRIPT=@9/*_INTERNET_SCHEME_JAVASCRIPT*/ _INTERNET_SCHEME_VBSCRIPT=@0xA/*_INTERNET_SCHEME_VBSCRIPT*/ _INTERNET_SCHEME_RES=@0xB/*_INTERNET_SCHEME_RES*/ _INTERNET_SCHEME_FIRST=@1/*_INTERNET_SCHEME_FIRST*/ _INTERNET_SCHEME_LAST=@0xB/*_INTERNET_SCHEME_LAST*/ end intellisense**/