0% found this document useful (0 votes)
85 views82 pages

Jarrednicholls Hacking Webkit and Js

This document discusses hacking the WebKit browser engine and its JavaScript engines. It provides an overview of WebKit, describes how to build the WebKit and Chromium projects from source code, and demonstrates how to add custom code to the Web Inspector tool to handle commands and persist data. The document encourages exploring ways to leverage WebKit with little investment for large returns, such as modifying the Web Inspector.

Uploaded by

Julio Barrera
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
85 views82 pages

Jarrednicholls Hacking Webkit and Js

This document discusses hacking the WebKit browser engine and its JavaScript engines. It provides an overview of WebKit, describes how to build the WebKit and Chromium projects from source code, and demonstrates how to add custom code to the Web Inspector tool to handle commands and persist data. The document encourages exploring ways to leverage WebKit with little investment for large returns, such as modifying the Web Inspector.

Uploaded by

Julio Barrera
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 82

Hacking WebKit &

Its JavaScript Engines


Jarred Nicholls
Work @ Sencha
WebKit Committer

Doing webkitty things...


Our Mission if we choose to accept it
Define: What is WebKit?

Some Simple Ways to Leverage WebKit


Little investment, Large ROI
Web Inspector Hacking
“Headless” WebKit
What is WebKit?

Browser at a High Level
User Interface

Data Persistence
Browser Engine

Render Engine

Networking JavaScript Graphics


I/O Engine Stack
Browser at a High Level
User Interface

We

Data Persistence
bK
it Browser Engine

Render Engine

Networking JavaScript Graphics


I/O Engine Stack


WebKit is
EVERYWHERE!
Even in your living room!
Portability

The WebKit project seeks to address a variety of needs. We want to


make it reasonable to port WebKit to a variety of desktop,
mobile, embedded and other platforms. We will provide the
infrastructure to do this with tight platform integration, reusing native
platform services where appropriate and providing friendly
embedding APIs.

http://www.webkit.org/projects/goals.html
How?
Client Interface
WebKit Components
Render Engine
CSS
DOM SVG

HTML Canvas

WebCore

Client Interface JavaScript Engine (JSC/V8)


WebKit Components
Render Engine
CSS
DOM SVG

HTML Canvas

WebCore

Client Interface JavaScript Engine (JSC/V8)


Port Abstraction
Networking
Thread Geolocation Timer
I/O

Client Interface

Clipboard Events Theme Graphics

API Calls
Events

Port
(Chrome, Safari, etc.)
Port Abstraction
Networking
Thread Geolocation Timer
I/O

Client Interface

Clipboard Events Theme Graphics

API Calls
Events

Port
(Chrome, Safari, etc.)
<input type=”number” />

Paint me
some spin
buttons, STAT!

I know how to
do that!

WebKit Port
<input type=”number” />

ri
pl ght
ea th
se er
,k e
th
x

WebKit
<input type=”number” />

Piece of cake!

y !
ex
’ s
in
ok
lo Port
<input type=”number” />
Theme Interface
bool paintInnerSpinButton(RenderObject*, const
PaintInfo&, const IntRect&);
<input type=”number” />
Theme Interface
bool paintInnerSpinButton(RenderObject*, const
PaintInfo&, const IntRect&);

Theme
Client Interface
RenderTheme->paint()

paintInnerSpinButton Port
WebKit Components
Render Engine
CSS
DOM SVG

HTML Canvas

WebCore

Client Interface JavaScript Engine (JSC/V8)


JavaScript Bindings
JavaScript Bindings

ArrayBuffer.idl
Web IDL
gen
erate
- bi n
ding
s.pl
ArrayBuffer
Wrapper
JavaScript Engine (JSC/V8)

ArrayBuffer

WebCore
ArrayBuffer.h

class  ArrayBuffer  :  public  RefCounted<ArrayBuffer>  {


public:
       //  ...
       inline  unsigned  byteLength()  const;

       inline  PassRefPtr<ArrayBuffer>  slice(int  begin,  int  end)  const;


       inline  PassRefPtr<ArrayBuffer>  slice(int  begin)  const;
       //  ...
};
Web[Kit]IDL

interface  [
       JSGenerateIsReachable=Impl,
       CustomConstructor,
       ConstructorParameters=1,
       JSNoStaticTables
]  ArrayBuffer  {
       readonly  attribute  int  byteLength;
       ArrayBuffer  slice(in  long  begin,  in  [Optional]  long  end);
};

>  perl  generate-­‐bindings.pl  -­‐-­‐generator  JS  ArrayBuffer.idl


>  perl  generate-­‐bindings.pl  -­‐-­‐generator  V8  ArrayBuffer.idl
JavaScriptCore

JSValue  jsArrayBufferByteLength(ExecState*  exec,  JSValue  slotBase,  PropertyName)


{
       JSArrayBuffer*  castedThis  =  jsCast<JSArrayBuffer*>(asObject(slotBase));
       UNUSED_PARAM(exec);
       ArrayBuffer*  impl  =  static_cast<ArrayBuffer*>(castedThis-­‐>impl());
       JSValue  result  =  jsNumber(impl-­‐>byteLength());
       return  result;
}
V8

static  v8::Handle<v8::Value>  byteLengthAttrGetter(v8::Local<v8::String>  name,


       const  v8::AccessorInfo&  info)
{
       INC_STATS("DOM.ArrayBuffer.byteLength._get");
       ArrayBuffer*  imp  =  V8ArrayBuffer::toNative(info.Holder());
       return  v8::Integer::New(imp-­‐>byteLength());
}
Hacking WebKit
For Fun & Profit
Building WebKit Nightly
Prerequisites
Prerequisites

Mac
Xcode 3.1.4+ & command-line tools
> which g++ => /usr/bin/g++

Windows
Don’t even bother (see “Building Chromium” :)
...but if you’re really brave: http://www.webkit.org/building/tools.html
Get the Source
Get the Source

SVN
svn checkout http://svn.webkit.org/repository/webkit/trunk WebKit

Git (RECOMMENDED!!!)
git clone git://git.webkit.org/WebKit.git
or
git clone git://github.com/WebKit/webkit.git WebKit
Build WebKit
Build WebKit

> cd WebKit
> Tools/Scripts/build-webkit

Go have lunch...

> Tools/Scripts/run-safari
Build WebKit

> cd WebKit
> Tools/Scripts/build-webkit

Go have lunch... runs local safari, but w/ new


WebKit framework
> Tools/Scripts/run-safari
Building Chromium
Prerequisites
Prerequisites

Depot Tools: http://www.chromium.org/developers/how-tos/install-depot-tools


Mac
Xcode 4.3+ & command-line tools
> which clang => /usr/bin/clang

Windows
Visual Studio (Express)
Windows SDK
DirectX SDK
Windows Driver Development Kit
Details: http://www.chromium.org/developers/how-tos/build-instructions-windows#TOC-Prerequisite-software
Get the Source
Get the Source

> mkdir chromium && cd chromium


> gclient config http://src.chromium.org/chrome/trunk/src
> gclient sync

Details: http://dev.chromium.org/developers/how-tos/get-the-code
Build Chromium
Build Chromium

> cd chromium/src
> GYP_GENERATORS=ninja gclient runhooks --force
> ninja -C out/Release chrome

Go on vacation...

> open out/Release/Chromium.app


Build Chromium

> cd chromium/src
> GYP_GENERATORS=ninja gclient runhooks --force
> ninja -C out/Release chrome
super fast “make” equivalent
Go on vacation... comes with depot tools

> open out/Release/Chromium.app


Let’s Hack
Web Inspector
Add in Hacks
inspector.js
var  re  =  /command=([^&]+)/,
       match  =  re.exec(location.href),
       command; command handler
if  (!match)  {
       return;
}

try  {
       command  =  eval('('  +  decodeURIComponent(match[1])  +  ')');
}  catch  (e)  {
       return;
}

switch  (command.type)  {
       default:
               break;
}
Add in Hacks
inspector.js persist data
var  saveData  =  function(filePath,  data)  {
       filePath  =  '/Users/jarred/qconny/'  +  filePath;

       var  xhr  =  new  XMLHttpRequest();


       xhr.onload  =  function()  {
               alert('Data  saved  successfully  to  '  +  filePath);
       };
       xhr.onerror  =  function()  {
               alert('Data  failed  to  save  to  '  +  filePath);
       };
       xhr.open('GET',  '/savedata');
       xhr.setRequestHeader('DevTools-­‐Data',  JSON.stringify(data));
       xhr.setRequestHeader('DevTools-­‐FilePath',  filePath);
       xhr.send(null);
};
Add in Hacks
devtools_http_handler_impl.cc
void  DevToolsHttpHandlerImpl::OnHttpRequest(
       int  connection_id,
       const  net::HttpServerRequestInfo&  info)  {
   //  ...

   if  (info.path.find("/savedata")  ==  0)  {


       BrowserThread::PostTask(
               BrowserThread::FILE,
               FROM_HERE,
               base::Bind(&DevToolsHttpHandlerImpl::OnSaveDataRequestFILE,
                                     this,
                                     connection_id,
                                     info));
       return;
   }
   //  ... persist data
}
Add in Hacks
devtools_http_handler_impl.cc

void  DevToolsHttpHandlerImpl::OnSaveDataRequestFILE(int  connection_id,  const  


net::HttpServerRequestInfo&  info)  {
   bool  success  =  false;
   FILE*  fp  =  fopen(info.GetHeaderValue("DevTools-­‐FilePath").c_str(),  "wb");
   if  (fp)  {
       std::string  data  =  info.GetHeaderValue("DevTools-­‐Data");
       fwrite(data.data(),  1,  data.size(),  fp);
       fclose(fp);
       success  =  true;
   }

   Send200(connection_id,  success  ?  "true"  :  "false",  "application/json;  charset=UTF-­‐8");


}

persist data
Web Inspector
Network
Export Network HAR Data

More info: http://www.softwareishard.com/blog/har-12-spec/


Add in Hacks
inspector.js exportHAR cmd
var  exportHAR  =  function(cmd)  {
       //  Force  a  reload  of  the  page  to  grab  network  stats.
       PageAgent.reload(true  /*  bypass  cache  */);

       setTimeout(function()  {
               var  networkData  =  
WebInspector.panels.network._networkLogView._getExportData();
               saveData((cmd.filename  ||  WebInspector.inspectedPageDomain)
                       +  '.har',  networkData);
       },  cmd.timeout);
};

case  'exportHAR':
       exportHAR(command);
       break;
Add in Hacks
NetworkPanel.js

export data fn
_getExportData:  function()  {
       return  {  log:  (new  WebInspector.HARLog(this._requests)).build()  };
}
Trigger Hack
Trigger Hack

http://localhost:9123/devtools/devtools.html?ws=localhost:9123/devtools/page/
3_1&command={type:'exportHAR',timeout:3000}
HAR Output

{"log":{"version":"1.2","creator":
{"name":"WebInspector","version":"536.5"},"pages":[],"entries":
[{"startedDateTime":"2012-­‐06-­‐19T18:02:16.852Z","time":8,"request":
{"method":"GET","url":"http://www.google.com/
blank.html","httpVersion":"HTTP/1.1","headers":[],"queryString":
[],"cookies":[],"headersSize":47,"bodySize":0},"response":
{"status":200,"statusText":"OK","httpVersion":"HTTP/1.1","headers":
[],"cookies":[],"content":{"size":0,"mimeType":"text/
html"},"redirectURL":"","headersSize":17,"bodySize":0},"cache":
{},"timings":{"blocked":
0,"dns":-­‐1,"connect":-­‐1,"send":-­‐1,"wait":-­‐1,"receive":0,"ssl":-­‐1}},
HAR Output

http://www.softwareishard.com/har/viewer/
Demo
Export Timeline Data
Add in Hacks
inspector.js exportTimeline cmd
var  exportTimeline  =  function(cmd)  {
       setTimeout(function()  {
               //  Start  the  timeline  profiler.
               WebInspector.panels.timeline._toggleTimelineButtonClicked();
               //  Force  a  reload  of  the  page  to  grab  latest  timeline  stats.
               PageAgent.reload(true  /*  bypass  cache  */);

               setTimeout(function()  {
                       //  Stop  the  timeline  profiler.
                       WebInspector.panels.timeline._toggleTimelineButtonClicked();

                       var  data  =  WebInspector.panels.timeline._model.getExportData();


                       saveData(cmd.filename  ||  (WebInspector.inspectedPageDomain  +  '-­‐
timeline.json'),  data);
               },  cmd.timeout);
       },  1000);
};

case  'exportTimeline':
       exportTimeline(command);
       break;
Add in Hacks
TimelineModel.js

export data fn
getExportData:  function()  {
       var  records  =  [];
       for  (var  i  =  0;  i  <  this._records.length;  i++)  {
               records.push(this._records[i]);
       }
       return  records;
}
Trigger Hack
Trigger Hack

http://localhost:9123/devtools/devtools.html?ws=localhost:9123/devtools/page/
3_1&command={type:'exportTimeline',timeout:3000}
Demo
Command Line
WebKit
Demo
How’d you do that!?
Headless WebKit
“Headless”
Normal Browser

Paint

Layout Display
Headless

Paint

X
Layout Display
What’s in it for me?
What’s in it for me?

Automated “smoke” tests

Continuous integration

Pixel-perfect regression tests

Web scraping

...
PhantomJS
Headless WebKit
Based on QtWebKit port

Full Web Stack


JS, DOM, CSS3, Canvas, SVG, etc.

Command Line Interface

JavaScript APIs

License: BSD / Open Source

http://www.phantomjs.org
Demo
Wrap Up
Hacking WebKit
Automation
Page scraping
Behavior/input emulation
Web Inspector hijacking

Quality Assurance / Continuous Integration


Smoke tests
Visual/pixel regression tests
Unit tests
Performance or Load regression tests
Jarred Nicholls
@jarrednicholls

Thanks!

You might also like

pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy