Nginad广告生成代码分析
大家都知道实时竞价的广告一般会在一个iframe中,这个iframe会有一个复杂的src。那么这个iframe是如何生成的?
这里分析NginAd作为exchange时,如何让媒体网站通过引用一段ad tag达到竞价的目的。
当一个媒体网站对接到NginAd,注册完毕后,NginAd会给出一段Ad Tag,将这个Tag加到媒体网站内便会出现一个实时竞价的iframe。 给出一个Ad tag的示例:
script type='text/javascript' src='http://server.nginad.com/ad/nginad.js?pzoneid=7&height=400&width=240&tld=www.kliupubdomain.com&cb=1421739738'
这段Ad tag会执行nginad.js脚本,后面的参数附上了广告位的各种参数,那么这段脚本是怎么把广告拉进来的?我们分析下nginad.js的代码。 nginad.js的代码很长,我贴在最后,先讲解下它的执行过程。
1. 参数解析
标准html语法中,script标签是无法带参数的,所以这段tag只会简单的执行nginad.js。nginad.js脚本运行后,第一件事是从网页当前的dom树中找到自己所在的script节点,把参数
pzoneid=7&height=400&width=240&tld=www.kliupubdomain.com&cb=1421739738
解析出来,它的做法是在当前DOM中找到nginad.js所在的< script >元素,通过正则表达式的方式抽出参数字段并解析。
2. iframe创建
接下来,nginad.js解析自己script标签所在位置,如果它不在iframe的根部,就会自己创建一个iframe,并把它添加到dom树上自己的位置之前。
3. iframe src拼接
再接下来就是最关键的iframe src拼接,脚本会解析出当前网页所在url和可能的传递url,当前广告位是否在屏幕显示范围内,当前广告位的位置,大小等等一切信息,然后拼接成一个链接,链接的形式大致是
http://server.nginad.com/delivery?params
这个链接被作为iframe的src,查看nginad的源代码可知,当向这个地址发出http请求时,就相当于发出了一次竞价请求,nginad根据后面的params向所有注册的DPS发出广告竞价请求。最后获胜者给出的adm,也就是物料网址作为返回。因此当加载这个iframe时,用户便会看到最后竞价成功的广告内容。
附 nginad.js 代码
/**
* CDNPAL NGINAD Project
*
* @link http://www.nginad.com
* @copyright Copyright (c) 2013-2015 CDNPAL Ltd. All Rights Reserved
* @license GPLv3
*/
var adserver_domain = 'localhost';
var script_name = 'nginad.js';
var delivery_path = '/delivery/impress';
var quality_scoring_pixels = [
// QS SERVICE 1
// "http://myqualityscore1.com/server/pixel.htm?uid=user_id",
// QS SERVICE 2
// "http://myqualityscore2.com/server/pixel.htm?uid=user_id",
// QS SERVICE 3
// "http://myqualityscore3.com/server/pixel.htm?uid=user_id",
];
var cookie_matching_pixels = [
// ZENOVIA EXCHANGE
// "http://sync.nj.zenoviaexchange.com/usersync2/partner_id",
// TURN
// "http://ad.turn.com/server/pixel.htm?fpid=13&r=12345",
// MEDIA MATH
// "http://pixel.mathtag.com/sync/js?sync=auto",
// DSTILLERY
// "http://idpix.media6degrees.com/orbserv/hbpix?pixId=1",
// CHANGO
// "http://lj.d.chango.com/m/lj?r=12345",
// RFI HUB
// "http://p.rfihub.com/cm?in=1&pub=1",
// APPNEXUS
// "http://ib.adnxs.com/getuid?http://mydomain.com/merge?pid=12&3pid=$UID",
// RTB BIDDER
// "http://match.rtbidder.net/match?p=31&ord=12345",
// SITE SCOUT
// "http://pixel.sitescout.com/dmp/pixelSync?network=partner_id",
// CASALE MEDIA
// "http://ip.casalemedia.com/usermatch?s=178636&cb=http%3A%2F%2Fmydomain.com%2Fmerge%3Fpid%3D18%263pid%3D",
// IPONWEB:
// "http://x.bidswitch.net/sync?ssp=fmx",
// TRADE DESK
// "http://data.adsrvr.org/track/cmf/generic?ttd_pid=partner_id",
// RUBICON PROJECT
// "http://pixel.rubiconproject.com/tap.php?v=other&nid=partner_id&put={user_token}&expires={days}",
// AUDIENCE SCIENCE
// "http://pix04.revsci.net/D08734/a3/0/3/0.302?matchId=100&PV=0"
];
function createTrackingPixel(url) {
(new Image()).src = url;
}
function fireCookieMatchingPixels() {
for (i in cookie_matching_pixels) {
createTrackingPixel(cookie_matching_pixels[i]);
}
}
function fireQSPixels() {
for (i in quality_scoring_pixels) {
createTrackingPixel(quality_scoring_pixels[i]);
}
}
if (typeof NGIN_AdsiFrame_Opts === "undefined") {
var NGIN_AdsiFrame_Opts = null;
}
if (typeof NGIN_placement_id === "undefined") {
var NGIN_placement_id = null;
}
var NGIN_AdsiFrame=(function() {
function isInIframe() {
return self !== top;
}
function getScriptTag() {
if('currentScript' in document) {
return document.currentScript;
}
var scripts = document.getElementsByTagName('script');
var last_script = scripts[scripts.length-1];
var rg = new RegExp(script_name, 'i');
if(last_script.src.search(rg) >= 0) {
return last_script;
} else {
try{
for(var n = scripts.length-1; n >= 0; n--) {
if(scripts[n].src.search(rg) >= 0) {
return scripts[n];
}
}
}catch(e) {
}
}
return last_script;
}
function getQueryString() {
var myScript=getScriptTag();
var rg = new RegExp(script_name, 'i');
if(myScript.src.search(rg) >= 0) {
return myScript.src.replace(/^[^\?]+\??/,'');
} else {
return false;
}
}
function getQueryStringArg(qs, key, default_) {
default_ = default_||'';
var query_obj = {};
qs.replace( new RegExp("([^?=&]+)(=([^&]*))?","g"), function($0,$1,$2,$3) { query_obj[$1] = $3; } );
if(typeof(query_obj[key]) === 'undefined' || query_obj[key] === null) {
return default_;
} else {
return query_obj[key];
}
}
function getSiteURL() {
var site_loc='';
try{
if(isInIframe() && document.referrer) {
site_loc = document.referrer.replace(/^\s+|\s+$/g,'');
} else {
site_loc = document.location.href;
}
} catch(e) {
}
return site_loc.replace(/["']/g,'');
}
function getRefSiteURL() {
var ref='';
if(!isInIframe()) {
ref=document.referrer.replace(/^\s+|\s+$|["']/g,'');
}
return ref;
}
function getOD() {
return parseUri(document.location.href.replace(/["']/g,'')).host;
}
function getNGINZoneId(zoneid) {
var id = 'NGIN_' + zoneid;
var obj = document.getElementById(id);
if(!obj) {
return id;
}
var i = 1;
while(obj) {
id = 'NGIN_' + zoneid + '_' + i;
obj = document.getElementById(id);
i++;
}
return id;
}
function getNGINAtf(id, viewport){
var ret="";
if(!viewport || viewport.status != "ok") {
ret="error";
}
try {
var rect = getNGINPosition(id);
ret = ((rect.x+rect.width <= viewport.x + viewport.width) && (rect.y + rect.height <= viewport.y + viewport.height));
} catch(e) {
ret="error";
}
return ret == true ? 1 : 0;
}
function getNGINPosition(id, width, height) {
var w = (width) ? width : 0;
var h = (height) ? height : 0;
var y = 0;
var x = 0;
var rect = { x:x, y:y, width:w, height:h };
var de = document.documentElement;
try {
var obj = document.getElementById(id);
while (obj) {
rect.x += obj.offsetLeft;
rect.y += obj.offsetTop;
obj = obj.offsetParent;
}
if(self.pageYOffset) {
rect.x -= self.pageXOffset;
rect.y -= self.pageYOffset;
} else if (de && de.scrollTop) {
rect.x -= de.scrollLeft;
rect.y -= de.scrollTop;
} else if (document.body) {
rect.x -= document.body.scrollLeft;
rect.y -= document.body.scrollTop;
}
} catch(e){
}
return rect;
}
function getNGINViewport() {
var viewport = {x:0,y:0,width:0,height:0,status:''}
var bw = 0;
var bh = 0;
var de = de;
var w = window;
var db = document.body;
try {
if (typeof w.innerWidth==='number') {
bw=w.innerWidth;
bh=w.innerHeight;
} else if(de && (de.clientWidth || de.clientHeight)) {
bw = de.clientWidth;
bh = de.clientHeight;
} else if (db && (db.clientWidth || db.clientHeight)) {
bw = db.clientWidth;
bh = db.clientHeight;
} else if (de && (de.offsetWidth || de.offsetHeight)) {
bw = de.offsetWidth;
bh = de.offsetHeight;
}
viewport.status = "ok";
viewport.width = bw;
viewport.height = bh;
} catch(e){
viewport.status="error";
}
return viewport;
}
function parseUri(u) {
try{
var o = {
key:["source","protocol","authority","userInfo","user","password","host","port","relative","path","directory","file","query","anchor"],
q:{name:"queryKey", parser:/(?:^|&)([^&=]*)=?([^&]*)/g},
parser:{loose:/^(?:(?![^:@]+:[^:@\/]*@)([^:\/?#.]+):)?(?:\/\/)?((?:(([^:@]*)(?::([^:@]*))?)?@)?([^:\/?#]*)(?::(\d*))?)(((\/(?:[^?#](?![^?#\/]*\.[^?#\/.]+(?:[?#]|$)))*\/?)?([^?#\/]*))(?:\?([^#]*))?(?:#(.*))?)/}
};
var m = o.parser.loose.exec(u);
var uri={};
var i = 14;
while(i--) {
uri[o.key[i]] = m[i] || '';
}
uri[o.q.name] = {};
uri[o.key[12]].replace(o.q.parser, function($0,$1,$2){ if($1) uri[o.q.name][$1]=$2; } );
return uri;
} catch(e) {
this.reportError('Failed to get OD',e);
}
return u;
}
function getNGINQueryString(id, qs, atf, add_all_tokens) {
var qstring = '?atf=' + atf;
var viewport = getNGINViewport();
if(viewport && viewport.status == "ok") {
qstring += '&scres_height=' + viewport.height;
qstring += '&scres_width=' + viewport.width;
}
var adPosition = getNGINPosition(id);
if(adPosition) {
qstring += '&adpos_x=' + adPosition.x;
qstring += '&adpos_y=' + adPosition.y;
}
var e = encodeURIComponent;
if (add_all_tokens) {
qstring += '&loc=' + e(getSiteURL()) + '&od=' + e(getOD()) + '&ref=' + e(getRefSiteURL());
}
var args = qs.split('&');
for (var i = 0; i < args.length; i++) {
var arg = args[i].split('=')
var key = arg[0]
var value = arg[1];
if (key === 'debug'
|| key === 'u'
|| key === 'zoneid'
|| key === 'pzoneid'
|| key === 'n'
|| key === 'NGIN_domain'
|| key.match(/^NGIN_/)
) {
qstring += '&' + e(key) + "=" + e(value);
}
}
return qstring;
}
function createiFrame(id, width, height) {
var ifrm = document.createElement('iframe');
ifrm.setAttribute('id',id);
ifrm.setAttribute('margin','0');
ifrm.setAttribute('padding','0');
ifrm.setAttribute('frameBorder','0');
ifrm.setAttribute('width',width+'');
ifrm.setAttribute('height',height+'');
ifrm.setAttribute('scrolling','no');
try {
ifrm.style.margin = "0px";
ifrm.style.padding = "0px";
ifrm.style.border = '0px none';
ifrm.style.width = width + "px";
ifrm.style.height = height + "px";
ifrm.style.overflow = 'hidden';
} catch(e) {
}
return ifrm;
}
// fire off cookie matching pixels first
fireCookieMatchingPixels();
// next, fire off quality scoring pixels
fireQSPixels();
// now process the ad tag
var qs = null;
var scriptTag;
var fpTag;
if (NGIN_AdsiFrame_Opts!==null) {
qs = NGIN_AdsiFrame_Opts;
} else {
qs = getQueryString();
}
var cdpnLocTag = "<script type='text/javascript'>var NGIN_Loc={};" + "NGIN_Loc.loc='" + getSiteURL()
+ "';NGIN_Loc.ref='" + getRefSiteURL()
+ "';NGIN_Loc.ifr='" + (isInIframe() ? '1' : '0')
+ "';NGIN_Loc.od='" + getOD() + "';</script>";
var domain = getQueryStringArg(qs,'NGIN_domain', adserver_domain);
var abf = 0;
var id = getQueryStringArg(qs, 'pzoneid');
if (!id) {
id = getQueryStringArg(qs, 'zoneid');
}
abf = getNGINAtf(id, getNGINViewport());
var org_tld = getQueryStringArg(qs, 'tld', "");
var ct_url = getQueryStringArg(qs, 'ct0', "");
var buyer_id = getQueryStringArg(qs, 'buyerid', "");
var sndprc = getQueryStringArg(qs, 'sndprc', "");
var ui = getQueryStringArg(qs, 'ui', "");
var cb = Math.round(new Date().getTime() / 1000);
var adQueryString = getNGINQueryString(id, qs, abf, false);
adQueryString += "&dt=in";
adQueryString += "&buyerid=" + escape(buyer_id);
adQueryString += "&loc=" + escape(getSiteURL());
adQueryString += "&ref=" + escape(getRefSiteURL());
adQueryString += "&ifr=" + (isInIframe() ? '1' : '0');
adQueryString += "&tld=" + escape(getOD());
adQueryString += "&sndprc=" + escape(sndprc);
adQueryString += "&ui=" + ui;
adQueryString += "&ct=" + escape(ct_url);
adQueryString += "&org_tld=" + escape(org_tld);
adQueryString += "&cb=" + cb;
var fpTag = '<scr'+'ipt type="text/javascript" src="http://' + domain + delivery_path
+ adQueryString + '"></scr' + 'ipt>';
var htmlPrefix = "<html><head><title></title></head><body style='padding:0px;margin:0px;'>";
var htmlSuffix = "<![if !IE]><script type='text/javascript'>document.close();</script><![endif]></body></html>";
if (isInIframe()) {
document.write(fpTag);
} else {
if (NGIN_AdsiFrame_Opts !== null) {
var placement = NGIN_placement_id || "NGIN_FPI_" + getQueryStringArg(qs, 'z', 0);
scriptTag = document.getElementById(placement) || getScriptTag();
} else {
scriptTag = getScriptTag();
}
var width = getQueryStringArg(qs, 'width', 160);
var height = getQueryStringArg(qs, 'height', 600);
var ifrm = createiFrame(id, width, height);
scriptTag.parentNode.insertBefore(ifrm, scriptTag);
fpTag = '<scr'+'ipt type="text/javascript" src="http://' + domain + delivery_path + adQueryString + '"></scr'+'ipt>';
if(getQueryStringArg(qs, 'NGIN_src', '0') === '1') {
var ad_server_domain = getQueryStringArg(qs, 'NGIN_ad_domain', adserver_domain);
ifrm.src = 'http://' + ad_server_domain + delivery_path + adQueryString;
} else {
var ifr_content = ifrm.contentWindow.document || ifrm.contentDocument;
ifr_content.write(htmlPrefix + fpTag + htmlSuffix);
}
}
return {};
})();
NGIN_placement_id = null;
NGIN_AdsiFrame_Opts = null;
Nginad广告生成代码分析的更多相关文章
- IDL和生成代码分析
IDL:接口描述语言 这里使用thrift-0.8.0-xsb这个版本来介绍IDL的定义以及简单实例分析. 1. namespace 定义包名 2.struct 结构体,定义服务接口的参数和返回值用到 ...
- EF自动生成的模型edmx代码分析
edmx代码分析 本文分析Entity Framework从数据库自动生成的模型文件代码(扩展名为edmx). 1. 概述 本文使用的数据库结构尽量简单,只有2个表,一个用户表和一个分公司表(相当于部 ...
- 集成TFS Build生成与SonarQube获取代码分析结果
软件项目在开发过程中,往往由于任务重.时间紧等原因忽略软件代码的质量和规范检查,只注重软件功能的开发和交付.等软件交付上线以后,由于代码质量导致的问题会耗费开发和运维人员的大量时间.研发表明,项目上线 ...
- 2017-2018-2 20155314《网络对抗技术》Exp4 恶意代码分析
2017-2018-2 20155314<网络对抗技术>Exp4 恶意代码分析 目录 实验要求 实验内容 实验环境 基础问题回答 预备知识 实验步骤 1 静态分析 1.1 使用virsca ...
- 20155239 《网络对抗》Exp4 恶意代码分析
20155239 <网络对抗>Exp4 恶意代码分析 使用schtasks指令监控系统运行 先在C盘目录下建立一个netstatlog.bat文件,用来将记录的联网结果格式化输出到nets ...
- 20155323刘威良《网络对抗》Exp4 恶意代码分析
20155323刘威良<网络对抗>Exp4 恶意代码分析 实践目标 1是监控你自己系统的运行状态,看有没有可疑的程序在运行. 2是分析一个恶意软件,就分析Exp2或Exp3中生成后门软件: ...
- Android代码分析工具lint学习
1 lint简介 1.1 概述 lint是随Android SDK自带的一个静态代码分析工具.它用来对Android工程的源文件进行检查,找出在正确性.安全.性能.可使用性.可访问性及国际化等方面可能 ...
- pmd静态代码分析
在正式进入测试之前,进行一定的静态代码分析及code review对代码质量及系统提高是有帮助的,以上为数据证明 Pmd 它是一个基于静态规则集的Java源码分析器,它可以识别出潜在的如下问题:– 可 ...
- 完整全面的Java资源库(包括构建、操作、代码分析、编译器、数据库、社区等等)
构建 这里搜集了用来构建应用程序的工具. Apache Maven:Maven使用声明进行构建并进行依赖管理,偏向于使用约定而不是配置进行构建.Maven优于Apache Ant.后者采用了一种过程化 ...
随机推荐
- 解决erlang R17无法识别中文问题
erlang更新到R17已有一段时间了.公司项目打算从旧版的erlang迁移到R17,却不料有不少的困扰,当中一个问题是中文问题. 这个问题非常easy重现:新建一个文件t.erl.保存为utf-8无 ...
- 集合 Vector ArrayList 集合一
集合是存储对象的,与对象数组不同,集合可以自动的扩大自己的容量,像StringBuffer一样,存储的对象类型可以不一致,(object数组). 方法: add();remove();get();se ...
- 排序算法 c实现
c语言实现插入排序.冒泡排序.选择排序.快速排序.堆排序.归并排序.希尔排序示例,需要的朋友可以参考下 实现以下排序 插入排序O(n^2) 冒泡排序 O(n^2) 选择排序 O(n^2) 快速 ...
- SharePoint服务器端对象模型 之 对象模型概述(Part 1)
在一个传统的ASP.NET开发过程中,我们往往会把开发分为界面展现层.逻辑业务层和数据访问层这三个层面.作为一个应用开发平台,SharePoint是微软在直观的开发能力和自由的扩展能力之间,取到的一个 ...
- UESTC 491 Tricks in Bits
Tricks in Bits Time Limit: 1000MS Memory Limit: 65535KB 64bit IO Format: %lld & %llu Submit ...
- Sql注入基础一
凡是带入数据库查询的都有可能是注入. 整个数据包 Sql注入原理? 网站数据传输中,接受变量传递的值未进行过滤,导致直接带入数据库查询执行的操作问题. Sql注入对于渗透的作用? 获取数据(网 ...
- MySQL 第六天
回顾 外键: 关联关系(表与表之间: 表中字段指向另外一张表的主键) 外键条件: 字段类型必须一致, 存储引擎必须为innodb 外键约束: 子表约束: 不能插入父表不存在的记录 父表约束: 三种 ...
- 卷积神经网络(CNN)的训练及代码实现
本文部分内容来自zouxy09的博客.谢谢.http://blog.csdn.net/zouxy09/article/details/9993371 以及斯坦福大学深度学习教程:http://ufld ...
- Linux中对启动过程中选择启动级别那个界面设置密码
生成md5形式的密码: a.执行 grub-md5-crypt 命令 b.在接下来的交互界面中输入自己的密码 c.生成加密后的密码修改配置文件: a.vi /boot/grub/grub.conf ...
- 关于“Cannot find any provider supporting AES/ECB/PKCS7Padding”问题的解决方案
出现这个问题的原因是:java自带的是PKCS5Padding填充,不支持PKCS7Padding填充 参考:https://stackoverflow.com/questions/20770072/ ...