| @ -0,0 +1,47 @@ | |||
| from wsgiref.simple_server import make_server | |||
| def tracking_server(environ, respond): | |||
| """Function used to handle all requests made to | |||
| this tracking server | |||
| """ | |||
| if environ['PATH_INFO'] == '/track.js': | |||
| return track_user(environ, respond) | |||
| elif environ['PATH_INFO'] == '/favicon.ico': | |||
| respond('204 NO CONTENT', []) | |||
| return [''] | |||
| else: | |||
| return html_content(environ, respond) | |||
| def track_user(environ, respond): | |||
| """Function used to handle the route: /track.js | |||
| This will print environ information about the user | |||
| to stdout and return back an empty string | |||
| """ | |||
| headers = [('Content-Type', 'application/javascript')] | |||
| respond('200 OK', headers) | |||
| prefixes = ['PATH_', 'HTTP', 'REQUEST', 'QUERY'] | |||
| for key, value in environ.iteritems(): | |||
| if any(key.startswith(prefix) for prefix in prefixes): | |||
| print '%s: %s' % (key, value) | |||
| return [''] | |||
| def html_content(environ, respond): | |||
| """Function used to handle any route that is not /track.js | |||
| This will return to the user a very basic html page that has | |||
| a script that to call /track.js | |||
| """ | |||
| headers = [('Content-Type', 'text/html')] | |||
| respond('200 OK', headers) | |||
| return ['<html><head></head><body><h2>Welcome</h2><script src="/track.js"></script></body></html>\n'] | |||
| if __name__ == '__main__': | |||
| try: | |||
| httpd = make_server('', 8000, tracking_server) | |||
| print 'Tracking Server Listening on Port 8000...' | |||
| httpd.serve_forever() | |||
| except KeyboardInterrupt: | |||
| print 'Exiting...' | |||
| @ -0,0 +1,51 @@ | |||
| from urllib import quote | |||
| from urlparse import parse_qs | |||
| from wsgiref.simple_server import make_server | |||
| def tracking_server(environ, respond): | |||
| """Function used to handle all requests made to | |||
| this tracking server | |||
| """ | |||
| if environ['PATH_INFO'] == '/track.js': | |||
| return track_user(environ, respond) | |||
| elif environ['PATH_INFO'] == '/favicon.ico': | |||
| respond('204 NO CONTENT', []) | |||
| return [''] | |||
| else: | |||
| return html_content(environ, respond) | |||
| def track_user(environ, respond): | |||
| """Function used to handle the route: /track.js | |||
| This will also print what the user searched for | |||
| to stdout | |||
| """ | |||
| query = parse_qs(environ['QUERY_STRING']) | |||
| search = query.get('s', [''])[0] | |||
| print 'User Searched For: %s' % search | |||
| headers = [('Content-Type', 'application/javascript')] | |||
| respond('200 OK', headers) | |||
| return [''] | |||
| def html_content(environ, respond): | |||
| """Function used to handle any route that is not /track.js | |||
| This will return to the user a very basic html page that has | |||
| a script that to call /track.js?s=<SEARCH> with the content | |||
| of the ?search= parameter to this request. | |||
| """ | |||
| query = parse_qs(environ['QUERY_STRING']) | |||
| search = quote(query.get('search', [''])[0]) | |||
| headers = [('Content-Type', 'text/html')] | |||
| respond('200 OK', headers) | |||
| return ['<html><head></head><body><h2>Welcome</h2><script src="/track.js?s=%s"></script></body></html>\n' % search] | |||
| if __name__ == '__main__': | |||
| try: | |||
| httpd = make_server('', 8000, tracking_server) | |||
| print 'Tracking Server Listening on Port 8000...' | |||
| httpd.serve_forever() | |||
| except KeyboardInterrupt: | |||
| print 'Exiting...' | |||
| @ -0,0 +1,66 @@ | |||
| from Cookie import SimpleCookie | |||
| from urllib import quote | |||
| from urlparse import parse_qs | |||
| from uuid import uuid4 | |||
| from wsgiref.simple_server import make_server | |||
| def tracking_server(environ, respond): | |||
| """Function used to handle all requests made to | |||
| this tracking server | |||
| """ | |||
| if environ['PATH_INFO'] == '/track.js': | |||
| return track_user(environ, respond) | |||
| elif environ['PATH_INFO'] == '/favicon.ico': | |||
| respond('204 NO CONTENT', []) | |||
| return [''] | |||
| else: | |||
| return html_content(environ, respond) | |||
| def track_user(environ, respond): | |||
| """Function used to handle the route: /track.js | |||
| This will check to make sure that the user | |||
| has a cookie id=<USER_ID>, if not then we will | |||
| generate a new uuid4 id for them and set the | |||
| cookie. | |||
| This will also print to stdout when we generate | |||
| a new cookie as well as what the user searched for. | |||
| """ | |||
| cookies = SimpleCookie() | |||
| cookies.load(environ.get('HTTP_COOKIE', '')) | |||
| user_id = cookies.get('id') | |||
| if not user_id: | |||
| user_id = uuid4() | |||
| print 'User did not have id, giving: %s' % user_id | |||
| query = parse_qs(environ['QUERY_STRING']) | |||
| search = query.get('s', [''])[0] | |||
| print 'User %s Searched For: %s' % (user_id, search) | |||
| headers = [('Content-Type', 'application/javascript'), | |||
| ('Set-Cookie', 'id=%s' % user_id)] | |||
| respond('200 OK', headers) | |||
| return [''] | |||
| def html_content(environ, respond): | |||
| """Function used to handle any route that is not /track.js | |||
| This will return to the user a very basic html page that has | |||
| a script that to call /track.js?s=<SEARCH> with the content | |||
| of the ?search= parameter to this request. | |||
| """ | |||
| query = parse_qs(environ['QUERY_STRING']) | |||
| search = quote(query.get('search', [''])[0]) | |||
| headers = [('Content-Type', 'text/html')] | |||
| respond('200 OK', headers) | |||
| return ['<html><head></head><body><h2>Welcome</h2><script src="/track.js?s=%s"></script></body></html>\n' % search] | |||
| if __name__ == '__main__': | |||
| try: | |||
| httpd = make_server('', 8000, tracking_server) | |||
| print 'Tracking Server Listening on Port 8000...' | |||
| httpd.serve_forever() | |||
| except KeyboardInterrupt: | |||
| print 'Exiting...' | |||
| @ -0,0 +1,91 @@ | |||
| from Cookie import SimpleCookie | |||
| from urlparse import parse_qs | |||
| from uuid import uuid4 | |||
| from wsgiref.simple_server import make_server | |||
| def tracking_server(environ, respond): | |||
| """Function used to handle all requests made to | |||
| this tracking server | |||
| """ | |||
| if environ['PATH_INFO'] == '/track.js': | |||
| return track_user(environ, respond) | |||
| elif environ['PATH_INFO'] == '/buster.js': | |||
| return cache_buster(environ, respond) | |||
| elif environ['PATH_INFO'] == '/favicon.ico': | |||
| respond('204 NO CONTENT', []) | |||
| return [''] | |||
| else: | |||
| return html_content(environ, respond) | |||
| def track_user(environ, respond): | |||
| """Function used to handle the route: /track.js | |||
| This will check to make sure that the user | |||
| has a cookie id=<USER_ID>, if not then we will | |||
| generate a new uuid4 id for them and set the | |||
| cookie. | |||
| This will also print to stdout when we generate | |||
| a new cookie as well as what the user searched for. | |||
| """ | |||
| cookies = SimpleCookie() | |||
| cookies.load(environ.get('HTTP_COOKIE', '')) | |||
| if not cookies.get('id'): | |||
| user_id = uuid4() | |||
| print 'User did not have id, giving: %s' % user_id | |||
| else: | |||
| user_id = cookies['id'].value | |||
| query = parse_qs(environ['QUERY_STRING']) | |||
| search = query.get('s', [''])[0] | |||
| print 'User %s Searched For: %s' % (user_id, search) | |||
| headers = [('Content-Type', 'application/javascript'), | |||
| ('Set-Cookie', 'id=%s' % user_id)] | |||
| respond('200 OK', headers) | |||
| return [''] | |||
| def cache_buster(environ, respond): | |||
| """Function used to handle the /buster.js route | |||
| This will simply return our cache buster javascript | |||
| to the user, which adds a script tag to call /track.js | |||
| """ | |||
| headers = [('Content-Type', 'application/javascript')] | |||
| respond('200 OK', headers) | |||
| cb_js = """ | |||
| function getParameterByName(name){ | |||
| name = name.replace(/[\[]/, "\\\[").replace(/[\]]/, "\\\]"); | |||
| var regexS = "[\\?&]" + name + "=([^&#]*)"; | |||
| var regex = new RegExp(regexS); | |||
| var results = regex.exec(window.location.search); | |||
| if(results == null) | |||
| return ""; | |||
| else | |||
| return decodeURIComponent(results[1].replace(/\+/g, " ")); | |||
| } | |||
| var now = new Date().getTime(); | |||
| var random = Math.random() * 99999999999; | |||
| var search = getParameterByName('search'); | |||
| document.write('<script src="/track.js?t=' + now + '&r=' + random + '&s=' + search + '"></script>'); | |||
| """ | |||
| return [cb_js] | |||
| def html_content(environ, respond): | |||
| """Function used to handle any route that is not /track.js | |||
| This will return to the user a very basic html page that has | |||
| a script that to call our /buster.js script | |||
| """ | |||
| headers = [('Content-Type', 'text/html')] | |||
| respond('200 OK', headers) | |||
| return ['<html><head></head><body><h2>Welcome</h2><script src="/buster.js"></script></body></html>\n'] | |||
| if __name__ == '__main__': | |||
| try: | |||
| httpd = make_server('', 8000, tracking_server) | |||
| print 'Tracking Server Listening on Port 8000...' | |||
| httpd.serve_forever() | |||
| except KeyboardInterrupt: | |||
| print 'Exiting...' | |||
| @ -0,0 +1,31 @@ | |||
| Tracking Server Examples | |||
| ======================== | |||
| This repository contains the code examples to follow along with the blog post [Third Party Tracking Pixels](http://brett.is/writing/about/third-party-tracking-pixels) | |||
| by [Brett Langdon](http://brett.is). | |||
| Each example provided builds upon the previous examples code. | |||
| ## License | |||
| The MIT License (MIT) | |||
| Copyright (c) 2013 Brett Langdon <brett@blangdon.com> | |||
| Permission is hereby granted, free of charge, to any person obtaining a copy | |||
| of this software and associated documentation files (the "Software"), to deal | |||
| in the Software without restriction, including without limitation the rights | |||
| to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | |||
| copies of the Software, and to permit persons to whom the Software is | |||
| furnished to do so, subject to the following conditions: | |||
| The above copyright notice and this permission notice shall be included in | |||
| all copies or substantial portions of the Software. | |||
| THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |||
| IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |||
| FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | |||
| AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |||
| LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | |||
| OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | |||
| THE SOFTWARE. | |||