├── .github └── FUNDING.yml ├── .gitignore ├── LICENSE ├── README.md ├── basebuild.xml ├── build.xml ├── default.properties ├── lib ├── ant-contrib-0.6.jar ├── splunkdevtools-1.0.1.jar ├── splunkdevtools-1.1.jar ├── yuicompressor-2.4.7.jar └── yuicompressor-2.4.8.jar ├── related ├── 2.2_tour.psd ├── 2.2_tour.pxm ├── 2.3_tour.afphoto ├── 2.7_tour.pxm ├── 2.8_tour.pxm ├── 2.9_tour.pxm ├── AlternativeappIcon.pxm ├── AlternativeappIcon2x.pxm ├── appIcon.pxm ├── appIcon2x.pxm ├── content_matches_tour.afphoto ├── fontello-stopwatch │ ├── README.txt │ ├── config.json │ ├── css │ │ ├── animation.css │ │ ├── stopwatch-codes.css │ │ ├── stopwatch-embedded.css │ │ ├── stopwatch-ie7-codes.css │ │ ├── stopwatch-ie7.css │ │ └── stopwatch.css │ ├── demo.html │ └── font │ │ ├── stopwatch.eot │ │ ├── stopwatch.svg │ │ ├── stopwatch.ttf │ │ ├── stopwatch.woff │ │ └── stopwatch.woff2 ├── macro_link.pxm ├── screenshot.pxm ├── screenshot_input.png ├── screenshot_main.png ├── screenshot_site_changes.png ├── screenshot_status_history.png ├── screenshots.pxm ├── shc.pxm ├── should_contain_content.afphoto ├── stopwatch icons │ ├── 0.svg │ ├── 100.svg │ ├── 25.svg │ ├── 50.svg │ └── 75.svg └── stopwatch_icon.pxm ├── src ├── README.txt ├── README │ ├── inputs.conf.spec │ ├── website_monitoring.conf.example │ └── website_monitoring.conf.spec ├── appserver │ ├── modules │ │ └── admin │ │ │ └── widgets │ │ │ ├── secure_password_storage.html │ │ │ ├── selection_dialog.html │ │ │ └── sourcetype_selection_fix.html │ └── static │ │ ├── WebsiteStatusCellRenderer.js │ │ ├── appIcon.png │ │ ├── application.css │ │ ├── application.js │ │ ├── css │ │ ├── AppSetupView.css │ │ └── BatchInputCreateView.css │ │ ├── dashboard.css │ │ ├── dashboard.js │ │ ├── font │ │ ├── stopwatch.eot │ │ ├── stopwatch.svg │ │ ├── stopwatch.ttf │ │ ├── stopwatch.woff │ │ └── stopwatch.woff2 │ │ ├── img │ │ ├── 0.png │ │ ├── 100.png │ │ ├── 25.png │ │ ├── 50.png │ │ ├── 75.png │ │ └── tour_new_features │ │ │ ├── alert_search.png │ │ │ ├── content_matches.png │ │ │ ├── edit_definition_dialog.png │ │ │ ├── edit_definition_link.png │ │ │ ├── exec_summary.png │ │ │ ├── filter_on_failures.png │ │ │ ├── include_headers.png │ │ │ ├── input_timeout.png │ │ │ ├── macro_link.png │ │ │ ├── setup_page.png │ │ │ ├── shc.png │ │ │ └── should_contain_string.png │ │ ├── js │ │ ├── lib │ │ │ ├── bootstrap-tagsinput.css │ │ │ ├── bootstrap-tagsinput.min.js │ │ │ └── text.js │ │ ├── templates │ │ │ ├── AppSetupView.html │ │ │ └── BatchInputCreateView.html │ │ ├── tests │ │ │ ├── TestBatchInputCreateView.js │ │ │ └── tests.json │ │ └── views │ │ │ ├── AppSetupView.js │ │ │ ├── BatchInputCreateView.js │ │ │ ├── InfoMessageView.js │ │ │ ├── SetupView.js │ │ │ ├── ValidationView.js │ │ │ └── WebsiteFailureEditorView.js │ │ ├── setup.js │ │ ├── site_changes.js │ │ ├── status_history.js │ │ ├── status_overview.css │ │ ├── status_overview.js │ │ ├── tests.js │ │ └── web_ping_batch_create.js ├── bin │ ├── modular_input.zip │ ├── ntlm3 │ │ ├── HTTPNtlmAuthHandler.py │ │ ├── U32.py │ │ ├── __init__.py │ │ ├── compat.py │ │ ├── des.py │ │ ├── des_c.py │ │ ├── des_data.py │ │ ├── md4.py │ │ └── ntlm.py │ ├── six.py │ ├── web_ping.py │ ├── web_ping_search_command.py │ ├── website_monitoring_app │ │ ├── __init__.py │ │ ├── expiring_dict │ │ │ ├── __init__.py │ │ │ └── expiringdict.py │ │ ├── requests │ │ │ ├── __init__.py │ │ │ ├── __version__.py │ │ │ ├── _internal_utils.py │ │ │ ├── adapters.py │ │ │ ├── api.py │ │ │ ├── auth.py │ │ │ ├── cacert.pem │ │ │ ├── certs.py │ │ │ ├── compat.py │ │ │ ├── cookies.py │ │ │ ├── exceptions.py │ │ │ ├── hooks.py │ │ │ ├── models.py │ │ │ ├── packages │ │ │ │ ├── README.rst │ │ │ │ ├── __init__.py │ │ │ │ ├── chardet │ │ │ │ │ ├── __init__.py │ │ │ │ │ ├── big5freq.py │ │ │ │ │ ├── big5prober.py │ │ │ │ │ ├── chardistribution.py │ │ │ │ │ ├── charsetgroupprober.py │ │ │ │ │ ├── charsetprober.py │ │ │ │ │ ├── cli │ │ │ │ │ │ ├── __init__.py │ │ │ │ │ │ └── chardetect.py │ │ │ │ │ ├── codingstatemachine.py │ │ │ │ │ ├── compat.py │ │ │ │ │ ├── cp949prober.py │ │ │ │ │ ├── enums.py │ │ │ │ │ ├── escprober.py │ │ │ │ │ ├── escsm.py │ │ │ │ │ ├── eucjpprober.py │ │ │ │ │ ├── euckrfreq.py │ │ │ │ │ ├── euckrprober.py │ │ │ │ │ ├── euctwfreq.py │ │ │ │ │ ├── euctwprober.py │ │ │ │ │ ├── gb2312freq.py │ │ │ │ │ ├── gb2312prober.py │ │ │ │ │ ├── hebrewprober.py │ │ │ │ │ ├── jisfreq.py │ │ │ │ │ ├── jpcntx.py │ │ │ │ │ ├── langbulgarianmodel.py │ │ │ │ │ ├── langcyrillicmodel.py │ │ │ │ │ ├── langgreekmodel.py │ │ │ │ │ ├── langhebrewmodel.py │ │ │ │ │ ├── langhungarianmodel.py │ │ │ │ │ ├── langthaimodel.py │ │ │ │ │ ├── langturkishmodel.py │ │ │ │ │ ├── latin1prober.py │ │ │ │ │ ├── mbcharsetprober.py │ │ │ │ │ ├── mbcsgroupprober.py │ │ │ │ │ ├── mbcssm.py │ │ │ │ │ ├── sbcharsetprober.py │ │ │ │ │ ├── sbcsgroupprober.py │ │ │ │ │ ├── sjisprober.py │ │ │ │ │ ├── universaldetector.py │ │ │ │ │ ├── utf8prober.py │ │ │ │ │ └── version.py │ │ │ │ ├── idna │ │ │ │ │ ├── __init__.py │ │ │ │ │ ├── codec.py │ │ │ │ │ ├── compat.py │ │ │ │ │ ├── core.py │ │ │ │ │ ├── idnadata.py │ │ │ │ │ ├── intranges.py │ │ │ │ │ └── uts46data.py │ │ │ │ └── urllib3 │ │ │ │ │ ├── __init__.py │ │ │ │ │ ├── _collections.py │ │ │ │ │ ├── connection.py │ │ │ │ │ ├── connectionpool.py │ │ │ │ │ ├── contrib │ │ │ │ │ ├── __init__.py │ │ │ │ │ ├── _securetransport │ │ │ │ │ │ ├── __init__.py │ │ │ │ │ │ ├── bindings.py │ │ │ │ │ │ └── low_level.py │ │ │ │ │ ├── appengine.py │ │ │ │ │ ├── ntlmpool.py │ │ │ │ │ ├── pyopenssl.py │ │ │ │ │ ├── securetransport.py │ │ │ │ │ └── socks.py │ │ │ │ │ ├── exceptions.py │ │ │ │ │ ├── fields.py │ │ │ │ │ ├── filepost.py │ │ │ │ │ ├── packages │ │ │ │ │ ├── __init__.py │ │ │ │ │ ├── backports │ │ │ │ │ │ ├── __init__.py │ │ │ │ │ │ └── makefile.py │ │ │ │ │ ├── ordered_dict.py │ │ │ │ │ ├── six.py │ │ │ │ │ └── ssl_match_hostname │ │ │ │ │ │ ├── __init__.py │ │ │ │ │ │ └── _implementation.py │ │ │ │ │ ├── poolmanager.py │ │ │ │ │ ├── request.py │ │ │ │ │ ├── response.py │ │ │ │ │ └── util │ │ │ │ │ ├── __init__.py │ │ │ │ │ ├── connection.py │ │ │ │ │ ├── request.py │ │ │ │ │ ├── response.py │ │ │ │ │ ├── retry.py │ │ │ │ │ ├── selectors.py │ │ │ │ │ ├── ssl_.py │ │ │ │ │ ├── timeout.py │ │ │ │ │ ├── url.py │ │ │ │ │ └── wait.py │ │ │ ├── sessions.py │ │ │ ├── status_codes.py │ │ │ ├── structures.py │ │ │ └── utils.py │ │ ├── requests_ntlm │ │ │ ├── __init__.py │ │ │ └── requests_ntlm.py │ │ ├── search_command.py │ │ ├── simple_rest_handler.py │ │ ├── socks.py │ │ └── sortedcontainers │ │ │ ├── __init__.py │ │ │ ├── sorteddict.py │ │ │ ├── sortedlist.py │ │ │ └── sortedset.py │ ├── website_monitoring_rest_handler.py │ └── win_inet_pton.py ├── default │ ├── app.conf │ ├── authorize.conf │ ├── commands.conf │ ├── data │ │ └── ui │ │ │ ├── manager │ │ │ └── data_inputs_web_ping.xml │ │ │ ├── nav │ │ │ └── default.xml │ │ │ └── views │ │ │ ├── adhoc_web_ping.xml │ │ │ ├── exec_summary.xml │ │ │ ├── setup_website_monitoring.xml │ │ │ ├── site_changes.xml │ │ │ ├── status_history.xml │ │ │ ├── status_overview.xml │ │ │ ├── test_website_monitoring.xml │ │ │ ├── web_ping_batch_create.xml │ │ │ ├── web_ping_logs.xml │ │ │ └── web_ping_status.xml │ ├── eventtypes.conf │ ├── inputs.conf │ ├── macros.conf │ ├── props.conf │ ├── restmap.conf │ ├── savedsearches.conf │ ├── searchbnf.conf │ ├── tags.conf │ ├── transforms.conf │ ├── ui-tour.conf │ ├── web.conf │ └── website_monitoring.conf ├── lookups │ └── http_response_codes.csv ├── metadata │ └── default.meta └── static │ ├── appIcon.png │ ├── appIconAlt.png │ └── appIcon_2x.png └── tests ├── HTMLTestRunner.py ├── configs ├── 00eb20db654dd807fd6734b18323f5af.json └── 35163af7282b92013f810b2b4822d7df.json ├── host.cert ├── host.key ├── test_proxy_server.py ├── test_web_server.py ├── unit.py ├── unit_test_web_server.py └── web_files └── test_page.html /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | # These are supported funding model platforms 2 | 3 | github: [LukeMurphey] 4 | custom: ['https://www.paypal.com/donate?business=MQSKTS3W7LUTY&item_name=Support+continued+development+of+Splunk+apps¤cy_code=USD'] 5 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.py[cod] 2 | 3 | # C extensions 4 | *.so 5 | 6 | # Packages 7 | *.egg 8 | *.egg-info 9 | dist 10 | build 11 | eggs 12 | parts 13 | var 14 | sdist 15 | develop-eggs 16 | .installed.cfg 17 | lib64 18 | tmp 19 | 20 | # Installer logs 21 | pip-log.txt 22 | 23 | # Unit test / coverage reports 24 | .coverage 25 | .tox 26 | nosetests.xml 27 | 28 | # Translations 29 | *.mo 30 | 31 | # Mr Developer 32 | .mr.developer.cfg 33 | .project 34 | .pydevproject 35 | 36 | local.properties 37 | .DS_Store 38 | .settings/* 39 | .vscode/* 40 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018 Luke Murphey 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | splunk-website-monitoring 2 | ************************ 3 | 4 | A Splunk application for monitoring web applications for downtime and slow response times. 5 | 6 | See https://splunkbase.splunk.com/app/1493 to download and install it. 7 | 8 | See http://lukemurphey.net/projects/splunk-website-monitoring/wiki for screenshots and technical information. 9 | -------------------------------------------------------------------------------- /build.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /default.properties: -------------------------------------------------------------------------------- 1 | value.build.packageoutput.directory=tmp/packages 2 | value.build.workingcopy.directory=. 3 | value.build.minimize=true 4 | value.deploy.minimize=false 5 | 6 | value.version.number=2.9.7 7 | # Define the location of your Splunk installation in local.properties so that you can deploy the application 8 | # to a Splunk installation automatically: 9 | #value.deploy.splunk_home=C:/Program Files/Splunk 10 | 11 | # Define parameters for unit tests that test using an HTTP proxy. You can run a local fake SOCKS4 proxy using 12 | # SSH ("ssh -N -D 0.0.0.0:1080 localhost"). See http://www.catonmat.net/blog/linux-socks5-proxy/. 13 | #value.test.proxy.address=127.0.0.1 14 | #value.test.proxy.port=8002 15 | #value.test.proxy.type=http -------------------------------------------------------------------------------- /lib/ant-contrib-0.6.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LukeMurphey/splunk-website-monitoring/442d08de5bbfed4a879de3b537eae0361de8e473/lib/ant-contrib-0.6.jar -------------------------------------------------------------------------------- /lib/splunkdevtools-1.0.1.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LukeMurphey/splunk-website-monitoring/442d08de5bbfed4a879de3b537eae0361de8e473/lib/splunkdevtools-1.0.1.jar -------------------------------------------------------------------------------- /lib/splunkdevtools-1.1.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LukeMurphey/splunk-website-monitoring/442d08de5bbfed4a879de3b537eae0361de8e473/lib/splunkdevtools-1.1.jar -------------------------------------------------------------------------------- /lib/yuicompressor-2.4.7.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LukeMurphey/splunk-website-monitoring/442d08de5bbfed4a879de3b537eae0361de8e473/lib/yuicompressor-2.4.7.jar -------------------------------------------------------------------------------- /lib/yuicompressor-2.4.8.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LukeMurphey/splunk-website-monitoring/442d08de5bbfed4a879de3b537eae0361de8e473/lib/yuicompressor-2.4.8.jar -------------------------------------------------------------------------------- /related/2.2_tour.psd: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LukeMurphey/splunk-website-monitoring/442d08de5bbfed4a879de3b537eae0361de8e473/related/2.2_tour.psd -------------------------------------------------------------------------------- /related/2.2_tour.pxm: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LukeMurphey/splunk-website-monitoring/442d08de5bbfed4a879de3b537eae0361de8e473/related/2.2_tour.pxm -------------------------------------------------------------------------------- /related/2.3_tour.afphoto: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LukeMurphey/splunk-website-monitoring/442d08de5bbfed4a879de3b537eae0361de8e473/related/2.3_tour.afphoto -------------------------------------------------------------------------------- /related/2.7_tour.pxm: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LukeMurphey/splunk-website-monitoring/442d08de5bbfed4a879de3b537eae0361de8e473/related/2.7_tour.pxm -------------------------------------------------------------------------------- /related/2.8_tour.pxm: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LukeMurphey/splunk-website-monitoring/442d08de5bbfed4a879de3b537eae0361de8e473/related/2.8_tour.pxm -------------------------------------------------------------------------------- /related/2.9_tour.pxm: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LukeMurphey/splunk-website-monitoring/442d08de5bbfed4a879de3b537eae0361de8e473/related/2.9_tour.pxm -------------------------------------------------------------------------------- /related/AlternativeappIcon.pxm: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LukeMurphey/splunk-website-monitoring/442d08de5bbfed4a879de3b537eae0361de8e473/related/AlternativeappIcon.pxm -------------------------------------------------------------------------------- /related/AlternativeappIcon2x.pxm: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LukeMurphey/splunk-website-monitoring/442d08de5bbfed4a879de3b537eae0361de8e473/related/AlternativeappIcon2x.pxm -------------------------------------------------------------------------------- /related/appIcon.pxm: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LukeMurphey/splunk-website-monitoring/442d08de5bbfed4a879de3b537eae0361de8e473/related/appIcon.pxm -------------------------------------------------------------------------------- /related/appIcon2x.pxm: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LukeMurphey/splunk-website-monitoring/442d08de5bbfed4a879de3b537eae0361de8e473/related/appIcon2x.pxm -------------------------------------------------------------------------------- /related/content_matches_tour.afphoto: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LukeMurphey/splunk-website-monitoring/442d08de5bbfed4a879de3b537eae0361de8e473/related/content_matches_tour.afphoto -------------------------------------------------------------------------------- /related/fontello-stopwatch/README.txt: -------------------------------------------------------------------------------- 1 | This webfont is generated by http://fontello.com open source project. 2 | 3 | 4 | ================================================================================ 5 | Please, note, that you should obey original font licenses, used to make this 6 | webfont pack. Details available in LICENSE.txt file. 7 | 8 | - Usually, it's enough to publish content of LICENSE.txt file somewhere on your 9 | site in "About" section. 10 | 11 | - If your project is open-source, usually, it will be ok to make LICENSE.txt 12 | file publicly available in your repository. 13 | 14 | - Fonts, used in Fontello, don't require a clickable link on your site. 15 | But any kind of additional authors crediting is welcome. 16 | ================================================================================ 17 | 18 | 19 | Comments on archive content 20 | --------------------------- 21 | 22 | - /font/* - fonts in different formats 23 | 24 | - /css/* - different kinds of css, for all situations. Should be ok with 25 | twitter bootstrap. Also, you can skip style and assign icon classes 26 | directly to text elements, if you don't mind about IE7. 27 | 28 | - demo.html - demo file, to show your webfont content 29 | 30 | - LICENSE.txt - license info about source fonts, used to build your one. 31 | 32 | - config.json - keeps your settings. You can import it back into fontello 33 | anytime, to continue your work 34 | 35 | 36 | Why so many CSS files ? 37 | ----------------------- 38 | 39 | Because we like to fit all your needs :) 40 | 41 | - basic file, .css - is usually enough, it contains @font-face 42 | and character code definitions 43 | 44 | - *-ie7.css - if you need IE7 support, but still don't wish to put char codes 45 | directly into html 46 | 47 | - *-codes.css and *-ie7-codes.css - if you like to use your own @font-face 48 | rules, but still wish to benefit from css generation. That can be very 49 | convenient for automated asset build systems. When you need to update font - 50 | no need to manually edit files, just override old version with archive 51 | content. See fontello source code for examples. 52 | 53 | - *-embedded.css - basic css file, but with embedded WOFF font, to avoid 54 | CORS issues in Firefox and IE9+, when fonts are hosted on the separate domain. 55 | We strongly recommend to resolve this issue by `Access-Control-Allow-Origin` 56 | server headers. But if you ok with dirty hack - this file is for you. Note, 57 | that data url moved to separate @font-face to avoid problems with 2 | 3 | 4 | Copyright (C) 2016 by original authors @ fontello.com 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /related/fontello-stopwatch/font/stopwatch.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LukeMurphey/splunk-website-monitoring/442d08de5bbfed4a879de3b537eae0361de8e473/related/fontello-stopwatch/font/stopwatch.ttf -------------------------------------------------------------------------------- /related/fontello-stopwatch/font/stopwatch.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LukeMurphey/splunk-website-monitoring/442d08de5bbfed4a879de3b537eae0361de8e473/related/fontello-stopwatch/font/stopwatch.woff -------------------------------------------------------------------------------- /related/fontello-stopwatch/font/stopwatch.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LukeMurphey/splunk-website-monitoring/442d08de5bbfed4a879de3b537eae0361de8e473/related/fontello-stopwatch/font/stopwatch.woff2 -------------------------------------------------------------------------------- /related/macro_link.pxm: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LukeMurphey/splunk-website-monitoring/442d08de5bbfed4a879de3b537eae0361de8e473/related/macro_link.pxm -------------------------------------------------------------------------------- /related/screenshot.pxm: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LukeMurphey/splunk-website-monitoring/442d08de5bbfed4a879de3b537eae0361de8e473/related/screenshot.pxm -------------------------------------------------------------------------------- /related/screenshot_input.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LukeMurphey/splunk-website-monitoring/442d08de5bbfed4a879de3b537eae0361de8e473/related/screenshot_input.png -------------------------------------------------------------------------------- /related/screenshot_main.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LukeMurphey/splunk-website-monitoring/442d08de5bbfed4a879de3b537eae0361de8e473/related/screenshot_main.png -------------------------------------------------------------------------------- /related/screenshot_site_changes.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LukeMurphey/splunk-website-monitoring/442d08de5bbfed4a879de3b537eae0361de8e473/related/screenshot_site_changes.png -------------------------------------------------------------------------------- /related/screenshot_status_history.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LukeMurphey/splunk-website-monitoring/442d08de5bbfed4a879de3b537eae0361de8e473/related/screenshot_status_history.png -------------------------------------------------------------------------------- /related/screenshots.pxm: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LukeMurphey/splunk-website-monitoring/442d08de5bbfed4a879de3b537eae0361de8e473/related/screenshots.pxm -------------------------------------------------------------------------------- /related/shc.pxm: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LukeMurphey/splunk-website-monitoring/442d08de5bbfed4a879de3b537eae0361de8e473/related/shc.pxm -------------------------------------------------------------------------------- /related/should_contain_content.afphoto: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LukeMurphey/splunk-website-monitoring/442d08de5bbfed4a879de3b537eae0361de8e473/related/should_contain_content.afphoto -------------------------------------------------------------------------------- /related/stopwatch icons/0.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /related/stopwatch icons/100.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /related/stopwatch icons/25.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /related/stopwatch icons/50.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /related/stopwatch icons/75.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /related/stopwatch_icon.pxm: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LukeMurphey/splunk-website-monitoring/442d08de5bbfed4a879de3b537eae0361de8e473/related/stopwatch_icon.pxm -------------------------------------------------------------------------------- /src/README/inputs.conf.spec: -------------------------------------------------------------------------------- 1 | [web_ping://default] 2 | * Configure an input for determining the status of a web site 3 | 4 | url = 5 | * The URL to be checked 6 | 7 | interval = 8 | * Indicates how often to perform the ping 9 | 10 | title = 11 | * A title of the URL 12 | 13 | configuration = 14 | * Indicates which stanza in website_monitoring.conf to get the configuration information from (optional) 15 | 16 | client_certificate = 17 | * Defines the path to a client SSL certificate (for client SSL authentication) 18 | 19 | client_certificate_key = 20 | * Defines the path to the client certificate key (necessary if the key is in a separate file from the certificate) 21 | 22 | username = 23 | * Defines the username to use for authenticating (only HTTP authentication supported) 24 | 25 | password = 26 | * DEPRECATED: the password should be stored in the secure password storage system 27 | * Defines the password to use for authenticating (only HTTP authentication supported) 28 | 29 | user_agent = 30 | * Defines the user-agent string used by the HTTP client 31 | 32 | should_contain_string = 33 | * Defines a string that ought to be included in the response content 34 | * If the content isn't included then the content will be considered wrong 35 | 36 | timeout = 37 | * The maximum number of seconds to wait for a web page to respond 38 | * Default: 30 39 | 40 | max_redirects = 41 | * The maximum number of redirects to follow. 42 | * '0' turns off redirection following. 43 | * '-1' or no value (default) will follow all redirects (no limit). 44 | 45 | return_body = 46 | * If 'true', will return the body of the response (up to the global limit defined in website_monitoring.conf) 47 | * Default: blank (false) 48 | 49 | return_headers = 50 | * If 'true', will include the headers in the output 51 | * Default: blank (false) 52 | 53 | warning_threshold = 54 | * If the response time of a page is higher than this number (in ms), consider it a 'Warning'. 55 | * Must be >= 0. 56 | * If not specified, the global value set in the UI will be used. 57 | * Default: blank (use global value) 58 | 59 | error_threshold = 60 | * If the response time of a page is higher than this number (in ms), consider it 'Failed'. 61 | * Must be >= 0. 62 | * If not specified, the global value set in the UI will be used. 63 | * Default: blank (use global value) 64 | -------------------------------------------------------------------------------- /src/README/website_monitoring.conf.example: -------------------------------------------------------------------------------- 1 | [default] 2 | proxy_server=some_proxy_server.acme.com 3 | proxy_port=1234 -------------------------------------------------------------------------------- /src/README/website_monitoring.conf.spec: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2013 Luke Murphey. All Rights Reserved. 2 | # 3 | # This file contains all possible options for an website_monitoring.conf file. Use this file to 4 | # configure how the website_monitoring app functions. 5 | # 6 | # To learn more about configuration files (including precedence) please see the documentation 7 | # located at http://docs.splunk.com/Documentation/latest/Admin/Aboutconfigurationfiles 8 | 9 | #****************************************************************************** 10 | # These options must be set under an [default] entry to apply to all inputs 11 | # Otherwise, the stanza name must be associated with the individual input. 12 | #****************************************************************************** 13 | [website_monitoring] 14 | proxy_server = 15 | * Defines the proxy server that will be used. 16 | * Examples: "1.2.3.4", "proxy.acme.com" 17 | 18 | proxy_port = 19 | * Defines the port that the proxy server is on 20 | * Example: 8080 21 | 22 | proxy_user = 23 | * Defines the user account to use for the proxy (leave blank to use no authentication) 24 | * Examples: johndoe 25 | 26 | proxy_password = 27 | * DEPRECATED: the password should be stored in the secure password storage system 28 | * Defines the proxy password to use (leave blank to use no authentication) 29 | * Examples: 0p3n_sesame 30 | 31 | proxy_type = 32 | * Defines the protocol used by the proxy server 33 | * Must be one of: socks4, socks5, http 34 | 35 | proxy_ignore = 36 | * A list of hosts that will not use a proxy server 37 | * You can disable all use of the proxy server by setting this to * (useful if a proxy server is being used from the environment) 38 | * Example: textcritical.net,textcritical.com 39 | 40 | thread_limit = 41 | * Defines the maximum number of threads that the input will create 42 | * Example: 200 43 | 44 | max_response_body_length = 45 | * The maximum length of the response body to return, if enabled. 46 | * Use 0 to disable returning response bodies (even if the setting is enabled in an input stanza). Use -1 for unlimited. 47 | * Example: 500 48 | * Default: 1000 -------------------------------------------------------------------------------- /src/appserver/modules/admin/widgets/selection_dialog.html: -------------------------------------------------------------------------------- 1 | <%page args="element" /> 2 | 19 | 86 | 87 | 90 | 155 | -------------------------------------------------------------------------------- /src/appserver/modules/admin/widgets/sourcetype_selection_fix.html: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/appserver/static/appIcon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LukeMurphey/splunk-website-monitoring/442d08de5bbfed4a879de3b537eae0361de8e473/src/appserver/static/appIcon.png -------------------------------------------------------------------------------- /src/appserver/static/application.js: -------------------------------------------------------------------------------- 1 | 2 | if( Splunk.Module.SimpleResultsTable ){ 3 | Splunk.Module.SimpleResultsTable = $.klass(Splunk.Module.SimpleResultsTable, { 4 | 5 | renderResults: function($super, htmlFragment) { 6 | $super(htmlFragment); 7 | 8 | if (this.getInferredEntityName()=="events") { 9 | this.renderedCount = $("tr", this.container).length - 1; 10 | } 11 | 12 | $.each( $('.simpleResultsTable td'), function(index, value) { 13 | $(this).attr('data-value', $(this).text() ); 14 | }); 15 | } 16 | }); 17 | } -------------------------------------------------------------------------------- /src/appserver/static/css/AppSetupView.css: -------------------------------------------------------------------------------- 1 | .horizontal-form-align-button{ 2 | margin-left: 180px; 3 | } 4 | 5 | .extra-link{ 6 | margin-left: 180px; 7 | margin-top: 20px; 8 | } -------------------------------------------------------------------------------- /src/appserver/static/css/BatchInputCreateView.css: -------------------------------------------------------------------------------- 1 | .bootstrap-tagsinput > .label-info{ 2 | background-color: #777; 3 | border: #777; 4 | text-transform: none; 5 | } 6 | 7 | .create-inputs{ 8 | margin-top: 16px; 9 | } 10 | 11 | #info-message, #warning-message{ 12 | vertical-align: top; 13 | padding-bottom: 0px; 14 | margin-bottom: 0px; 15 | } 16 | 17 | /* Reinstate the display none if the hide class is set (since the CSS about overrides this) */ 18 | #info-message.hide, #warning-message.hide{ 19 | display: none; 20 | } 21 | 22 | .message-dialogs{ 23 | margin-bottom: 16px; 24 | } 25 | 26 | .alert{ 27 | margin-top: 16px; 28 | } 29 | 30 | /* 31 | * Minor styling changes to the tags input 32 | */ 33 | .BatchInputCreateView .bootstrap-tagsinput .tag [data-role="remove"]:after{ 34 | content: "×"; 35 | padding: 0px 2px; 36 | } 37 | 38 | .BatchInputCreateView .bootstrap-tagsinput .tag{ 39 | padding-top: 2px; 40 | padding-bottom: 2px; 41 | padding-left: 8px; 42 | } 43 | 44 | .BatchInputCreateView .bootstrap-tagsinput > .label-info{ 45 | text-transform: none; 46 | } 47 | -------------------------------------------------------------------------------- /src/appserver/static/dashboard.css: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LukeMurphey/splunk-website-monitoring/442d08de5bbfed4a879de3b537eae0361de8e473/src/appserver/static/dashboard.css -------------------------------------------------------------------------------- /src/appserver/static/dashboard.js: -------------------------------------------------------------------------------- 1 | "expected blank" -------------------------------------------------------------------------------- /src/appserver/static/font/stopwatch.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LukeMurphey/splunk-website-monitoring/442d08de5bbfed4a879de3b537eae0361de8e473/src/appserver/static/font/stopwatch.eot -------------------------------------------------------------------------------- /src/appserver/static/font/stopwatch.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Copyright (C) 2016 by original authors @ fontello.com 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /src/appserver/static/font/stopwatch.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LukeMurphey/splunk-website-monitoring/442d08de5bbfed4a879de3b537eae0361de8e473/src/appserver/static/font/stopwatch.ttf -------------------------------------------------------------------------------- /src/appserver/static/font/stopwatch.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LukeMurphey/splunk-website-monitoring/442d08de5bbfed4a879de3b537eae0361de8e473/src/appserver/static/font/stopwatch.woff -------------------------------------------------------------------------------- /src/appserver/static/font/stopwatch.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LukeMurphey/splunk-website-monitoring/442d08de5bbfed4a879de3b537eae0361de8e473/src/appserver/static/font/stopwatch.woff2 -------------------------------------------------------------------------------- /src/appserver/static/img/0.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LukeMurphey/splunk-website-monitoring/442d08de5bbfed4a879de3b537eae0361de8e473/src/appserver/static/img/0.png -------------------------------------------------------------------------------- /src/appserver/static/img/100.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LukeMurphey/splunk-website-monitoring/442d08de5bbfed4a879de3b537eae0361de8e473/src/appserver/static/img/100.png -------------------------------------------------------------------------------- /src/appserver/static/img/25.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LukeMurphey/splunk-website-monitoring/442d08de5bbfed4a879de3b537eae0361de8e473/src/appserver/static/img/25.png -------------------------------------------------------------------------------- /src/appserver/static/img/50.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LukeMurphey/splunk-website-monitoring/442d08de5bbfed4a879de3b537eae0361de8e473/src/appserver/static/img/50.png -------------------------------------------------------------------------------- /src/appserver/static/img/75.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LukeMurphey/splunk-website-monitoring/442d08de5bbfed4a879de3b537eae0361de8e473/src/appserver/static/img/75.png -------------------------------------------------------------------------------- /src/appserver/static/img/tour_new_features/alert_search.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LukeMurphey/splunk-website-monitoring/442d08de5bbfed4a879de3b537eae0361de8e473/src/appserver/static/img/tour_new_features/alert_search.png -------------------------------------------------------------------------------- /src/appserver/static/img/tour_new_features/content_matches.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LukeMurphey/splunk-website-monitoring/442d08de5bbfed4a879de3b537eae0361de8e473/src/appserver/static/img/tour_new_features/content_matches.png -------------------------------------------------------------------------------- /src/appserver/static/img/tour_new_features/edit_definition_dialog.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LukeMurphey/splunk-website-monitoring/442d08de5bbfed4a879de3b537eae0361de8e473/src/appserver/static/img/tour_new_features/edit_definition_dialog.png -------------------------------------------------------------------------------- /src/appserver/static/img/tour_new_features/edit_definition_link.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LukeMurphey/splunk-website-monitoring/442d08de5bbfed4a879de3b537eae0361de8e473/src/appserver/static/img/tour_new_features/edit_definition_link.png -------------------------------------------------------------------------------- /src/appserver/static/img/tour_new_features/exec_summary.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LukeMurphey/splunk-website-monitoring/442d08de5bbfed4a879de3b537eae0361de8e473/src/appserver/static/img/tour_new_features/exec_summary.png -------------------------------------------------------------------------------- /src/appserver/static/img/tour_new_features/filter_on_failures.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LukeMurphey/splunk-website-monitoring/442d08de5bbfed4a879de3b537eae0361de8e473/src/appserver/static/img/tour_new_features/filter_on_failures.png -------------------------------------------------------------------------------- /src/appserver/static/img/tour_new_features/include_headers.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LukeMurphey/splunk-website-monitoring/442d08de5bbfed4a879de3b537eae0361de8e473/src/appserver/static/img/tour_new_features/include_headers.png -------------------------------------------------------------------------------- /src/appserver/static/img/tour_new_features/input_timeout.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LukeMurphey/splunk-website-monitoring/442d08de5bbfed4a879de3b537eae0361de8e473/src/appserver/static/img/tour_new_features/input_timeout.png -------------------------------------------------------------------------------- /src/appserver/static/img/tour_new_features/macro_link.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LukeMurphey/splunk-website-monitoring/442d08de5bbfed4a879de3b537eae0361de8e473/src/appserver/static/img/tour_new_features/macro_link.png -------------------------------------------------------------------------------- /src/appserver/static/img/tour_new_features/setup_page.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LukeMurphey/splunk-website-monitoring/442d08de5bbfed4a879de3b537eae0361de8e473/src/appserver/static/img/tour_new_features/setup_page.png -------------------------------------------------------------------------------- /src/appserver/static/img/tour_new_features/shc.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LukeMurphey/splunk-website-monitoring/442d08de5bbfed4a879de3b537eae0361de8e473/src/appserver/static/img/tour_new_features/shc.png -------------------------------------------------------------------------------- /src/appserver/static/img/tour_new_features/should_contain_string.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LukeMurphey/splunk-website-monitoring/442d08de5bbfed4a879de3b537eae0361de8e473/src/appserver/static/img/tour_new_features/should_contain_string.png -------------------------------------------------------------------------------- /src/appserver/static/js/lib/bootstrap-tagsinput.css: -------------------------------------------------------------------------------- 1 | /* 2 | * bootstrap-tagsinput v0.8.0 3 | * 4 | */ 5 | 6 | .bootstrap-tagsinput { 7 | background-color: #fff; 8 | border: 1px solid #ccc; 9 | box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075); 10 | display: inline-block; 11 | padding: 4px 6px; 12 | color: #555; 13 | vertical-align: middle; 14 | border-radius: 4px; 15 | max-width: 100%; 16 | line-height: 22px; 17 | cursor: text; 18 | } 19 | .bootstrap-tagsinput input { 20 | border: none; 21 | box-shadow: none; 22 | outline: none; 23 | background-color: transparent; 24 | padding: 0 6px; 25 | margin: 0; 26 | width: auto; 27 | max-width: inherit; 28 | } 29 | .bootstrap-tagsinput.form-control input::-moz-placeholder { 30 | color: #777; 31 | opacity: 1; 32 | } 33 | .bootstrap-tagsinput.form-control input:-ms-input-placeholder { 34 | color: #777; 35 | } 36 | .bootstrap-tagsinput.form-control input::-webkit-input-placeholder { 37 | color: #777; 38 | } 39 | .bootstrap-tagsinput input:focus { 40 | border: none; 41 | box-shadow: none; 42 | } 43 | .bootstrap-tagsinput .tag { 44 | margin-right: 2px; 45 | color: white; 46 | } 47 | .bootstrap-tagsinput .tag [data-role="remove"] { 48 | margin-left: 8px; 49 | cursor: pointer; 50 | } 51 | .bootstrap-tagsinput .tag [data-role="remove"]:after { 52 | content: "x"; 53 | padding: 0px 2px; 54 | } 55 | .bootstrap-tagsinput .tag [data-role="remove"]:hover { 56 | box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.2), 0 1px 2px rgba(0, 0, 0, 0.05); 57 | } 58 | .bootstrap-tagsinput .tag [data-role="remove"]:hover:active { 59 | box-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125); 60 | } 61 | -------------------------------------------------------------------------------- /src/appserver/static/js/templates/BatchInputCreateView.html: -------------------------------------------------------------------------------- 1 | <% if(is_shc) { %> 2 |
3 | 4 | You cannot make an input on a Search Head Cluster. Create the input on a forwarder or on the deployer instead. 5 |
6 | <% } else if(!has_permission) { %> 7 |
8 | 9 | You do not have permission to make Website Monitoring inputs. You are missing the following capabilities: <%- capabilities_missing.join(", ") %>. 10 |
11 | <% } else { %> 12 | 13 | 29 | 30 |
31 | 32 |

Create Multiple Website Monitoring Inputs

33 | Use this form to create a series of website monitoring inputs. If you want to make an individual input (and configure advanced options, use the Splunk Manager). 34 |
35 | You can also view existing inputs in the Manager. 36 |
37 |
38 |
39 | 40 |
Warning!
41 |
42 | 43 |
44 | 45 |
Ok!
46 |
47 |
48 | 49 |
50 | 51 |
52 | 53 | Enter a list of URLs and press enter or a comma to add another<%if(is_on_cloud) {%>; these must use HTTPS since Splunk Cloud requires encryption<%}%> 54 |
55 |
56 | 57 |
58 | 59 |
60 | 61 | 62 |
63 |
64 | 65 |
66 | 67 |
68 | 69 | 70 | Optional: enter the amount time to wait until considering the connection failed; will default to 30 seconds if not provided 71 |
72 |
73 | 74 |
75 |
76 | 79 | 80 |
81 |
82 |
83 | <% } %> -------------------------------------------------------------------------------- /src/appserver/static/js/tests/TestBatchInputCreateView.js: -------------------------------------------------------------------------------- 1 | 2 | require.config({ 3 | paths: { 4 | batch_input_create_view: "../app/website_monitoring/js/views/BatchInputCreateView", 5 | jasmine: '//cdnjs.cloudflare.com/ajax/libs/jasmine/1.3.1/jasmine' 6 | } 7 | }); 8 | 9 | require([ 10 | "jquery", 11 | "underscore", 12 | "backbone", 13 | "batch_input_create_view", 14 | "splunkjs/mvc/searchmanager", 15 | "splunkjs/mvc/utils", 16 | "jasmine", 17 | "splunkjs/mvc/simplexml/ready!" 18 | ], function( 19 | $, 20 | _, 21 | Backbone, 22 | BatchInputCreateView, 23 | SearchManager, 24 | utils 25 | ) 26 | { 27 | 28 | /** 29 | * The tests 30 | */ 31 | describe("BatchInputCreateView: ", function() { 32 | 33 | it("creation of a title from URL", function() { 34 | var view = new BatchInputCreateView(); 35 | expect(view.generateTitle("http://textcritical.net")).toBe("textcritical.net"); 36 | }); 37 | 38 | it("creation of a stanza from URL", function() { 39 | var view = new BatchInputCreateView(); 40 | expect(view.generateStanza("http://textcritical.net")).toBe("textcritical_net"); 41 | }); 42 | 43 | it("creation of a stanza from URL with list of existing stanzas", function() { 44 | var view = new BatchInputCreateView(); 45 | 46 | expect(view.generateStanza("http://textcritical.net", ["textcritical_net", "textcritical_net_1"])).toBe("textcritical_net_2"); 47 | }); 48 | 49 | it("parsing of URL", function() { 50 | var view = new BatchInputCreateView(); 51 | var parsed = view.parseURL("http://textcritical.net"); 52 | expect(parsed.hostname).toBe("textcritical.net"); 53 | }); 54 | 55 | it("validation of interval", function() { 56 | var view = new BatchInputCreateView(); 57 | 58 | expect(view.isValidInterval("2h")).toBe(true); 59 | }); 60 | 61 | it("validation of interval with only an integer", function() { 62 | var view = new BatchInputCreateView(); 63 | 64 | expect(view.isValidInterval("2")).toBe(true); 65 | }); 66 | 67 | it("validation of interval with a bad time unit", function() { 68 | var view = new BatchInputCreateView(); 69 | 70 | expect(view.isValidInterval("2z")).toBe(false); 71 | }); 72 | 73 | it("validation of interval with no count", function() { 74 | var view = new BatchInputCreateView(); 75 | 76 | expect(view.isValidInterval("m")).toBe(false); 77 | }); 78 | 79 | it("validation of interval that is blank", function() { 80 | var view = new BatchInputCreateView(); 81 | 82 | expect(view.isValidInterval("")).toBe(false); 83 | }); 84 | 85 | }); 86 | 87 | } 88 | ); -------------------------------------------------------------------------------- /src/appserver/static/js/tests/tests.json: -------------------------------------------------------------------------------- 1 | { 2 | "test_batch_create_input_view": "../app/website_monitoring/js/tests/TestBatchInputCreateView" 3 | } -------------------------------------------------------------------------------- /src/appserver/static/js/views/InfoMessageView.js: -------------------------------------------------------------------------------- 1 | define([ 2 | "underscore", 3 | "backbone", 4 | "splunkjs/mvc", 5 | "jquery", 6 | "splunkjs/mvc/simplesplunkview", 7 | "splunkjs/mvc/searchmanager", 8 | "splunkjs/mvc/utils" 9 | ], function( 10 | _, 11 | Backbone, 12 | mvc, 13 | $, 14 | SimpleSplunkView, 15 | SearchManager, 16 | utils 17 | ) { 18 | // Define the custom view class 19 | var InfoMessageView = SimpleSplunkView.extend({ 20 | className: "AnnotateEventView", 21 | apps: null, 22 | 23 | /** 24 | * Setup the defaults 25 | */ 26 | defaults: { 27 | message_el: ".dashboard-form-globalfieldset:first", 28 | search_manager: null, 29 | message: null, 30 | eval_function: null, 31 | show_if_results: false, 32 | show_if_no_results: true 33 | }, 34 | 35 | /** 36 | * Initialize the class 37 | */ 38 | initialize: function() { 39 | 40 | // Apply the defaults 41 | this.options = _.extend({}, this.defaults, this.options); 42 | 43 | options = this.options || {}; 44 | 45 | this.message_el = $(options.message_el); 46 | this.search_manager = options.search_manager; 47 | this.message = options.message; 48 | this.show_if_no_results = options.show_if_no_results; 49 | this.show_if_results = options.show_if_results; 50 | this.eval_function = options.eval_function; 51 | 52 | this.existing_message_el = null; // This keeps a reference to the element where a message has already been placed 53 | 54 | this.setupSearch(); 55 | }, 56 | 57 | /** 58 | * Show a message 59 | */ 60 | showMessage: function(message){ 61 | 62 | var content = '
' + 65 | '
' + 66 | ' ' + 67 | message + 68 | '
' + 69 | '
'; 70 | 71 | // If we already posted a message, then replace the existing message 72 | if(this.existing_message_el !== null){ 73 | this.existing_message_el.html(content_html); 74 | 75 | } 76 | 77 | // Otherwise, make a new one 78 | else{ 79 | var content_html = $(content); 80 | this.message_el.append(content_html); 81 | this.existing_message_el = content_html; 82 | } 83 | 84 | }, 85 | 86 | /** 87 | * Start the process of running the search for. 88 | */ 89 | setupSearch: function(){ 90 | 91 | if( !this.search_manager || !this.message ){ 92 | return; 93 | } 94 | 95 | this.search_manager.on("search:done", function() { 96 | console.log("Info message search completed"); 97 | }.bind(this)); 98 | 99 | // Process the results 100 | var searchResults = this.search_manager.data("results"); 101 | 102 | searchResults.on("data", function() { 103 | 104 | var rows_count = searchResults.data().rows.length; 105 | 106 | if(this.eval_function && this.eval_function(searchResults.data())){ 107 | this.showMessage(this.message); 108 | } 109 | else if( this.show_if_results && rows_count > 0){ 110 | this.showMessage(this.message); 111 | } 112 | 113 | }.bind(this)); 114 | 115 | this.search_manager.startSearch(); 116 | } 117 | 118 | 119 | }); 120 | 121 | return InfoMessageView; 122 | }); 123 | -------------------------------------------------------------------------------- /src/appserver/static/setup.js: -------------------------------------------------------------------------------- 1 | require.config({ 2 | paths: { 3 | custom_setup: "../app/website_monitoring/js/views/AppSetupView" 4 | } 5 | }); 6 | 7 | require([ 8 | "jquery", 9 | "custom_setup", 10 | "splunkjs/mvc/simplexml/ready!" 11 | ], function( 12 | $, 13 | AppSetupView 14 | ) 15 | { 16 | 17 | var appSetupView = new AppSetupView({ 18 | el: $('#setupView') 19 | }); 20 | 21 | appSetupView.render(); 22 | } 23 | ); -------------------------------------------------------------------------------- /src/appserver/static/site_changes.js: -------------------------------------------------------------------------------- 1 | require.config({ 2 | paths: { 3 | website_status_cell_renderer: '../app/website_monitoring/WebsiteStatusCellRenderer' 4 | } 5 | }); 6 | 7 | require(['jquery','underscore','splunkjs/mvc', 'website_status_cell_renderer', 'splunkjs/mvc/simplexml/ready!'], 8 | function($, _, mvc, WebsiteStatusCellRenderer){ 9 | 10 | var statusTable = mvc.Components.get('element1'); 11 | 12 | statusTable.getVisualization(function(tableView){ 13 | tableView.table.addCellRenderer(new WebsiteStatusCellRenderer()); 14 | tableView.table.render(); 15 | }); 16 | 17 | } 18 | ); -------------------------------------------------------------------------------- /src/appserver/static/status_history.js: -------------------------------------------------------------------------------- 1 | require.config({ 2 | paths: { 3 | website_status_cell_renderer: '../app/website_monitoring/WebsiteStatusCellRenderer' 4 | } 5 | }); 6 | 7 | 8 | require(['jquery','underscore','splunkjs/mvc', 'website_status_cell_renderer', 'splunkjs/mvc/simplexml/ready!'], 9 | function($, _, mvc, WebsiteStatusCellRenderer){ 10 | 11 | var statusTable = mvc.Components.get('element6'); 12 | 13 | statusTable.getVisualization(function(tableView){ 14 | tableView.table.addCellRenderer(new WebsiteStatusCellRenderer()); 15 | tableView.table.render(); 16 | }); 17 | 18 | } 19 | ); -------------------------------------------------------------------------------- /src/appserver/static/status_overview.js: -------------------------------------------------------------------------------- 1 | require.config({ 2 | paths: { 3 | website_status_cell_renderer: '../app/website_monitoring/WebsiteStatusCellRenderer', 4 | info_message_view: '../app/website_monitoring/js/views/InfoMessageView', 5 | website_failure_view: '../app/website_monitoring/js/views/WebsiteFailureEditorView' 6 | } 7 | }); 8 | 9 | require(['jquery','underscore','splunkjs/mvc', 'website_status_cell_renderer', 'info_message_view', 'splunkjs/mvc/searchmanager', 'website_failure_view', 'splunkjs/mvc/simplexml/ready!'], 10 | function($, _, mvc, WebsiteStatusCellRenderer, InfoMessageView, SearchManager, WebsiteFailureEditorView){ 11 | 12 | // Setup the cell renderer 13 | var statusTable = mvc.Components.get('element1'); 14 | 15 | statusTable.getVisualization(function(tableView){ 16 | tableView.table.addCellRenderer(new WebsiteStatusCellRenderer()); 17 | tableView.table.render(); 18 | }); 19 | 20 | // Make the search that will determine if website monitoring inputs exist 21 | var hasInputSearch = new SearchManager({ 22 | "id": "webping-inputs-search", 23 | "earliest_time": "-48h@h", 24 | "latest_time": "now", 25 | "search":'| rest /services/data/inputs/web_ping | append [search sourcetype="web_ping" | head 1] | stats count', 26 | "cancelOnUnload": true, 27 | "autostart": false, 28 | "app": '', 29 | "auto_cancel": 90, 30 | "preview": false 31 | }, {tokens: false}); 32 | 33 | var infoMessageView = new InfoMessageView({ 34 | search_manager: hasInputSearch, 35 | message: 'Create an input to monitor a website. Create a website monitoring input now.', 36 | eval_function: function(searchResults){ return searchResults.rows[0][0] === "0" } 37 | }); 38 | 39 | var websiteFailureEditorView = new WebsiteFailureEditorView({ 40 | "el": "#notification-options" 41 | }); 42 | 43 | websiteFailureEditorView.render(); 44 | 45 | } 46 | ); -------------------------------------------------------------------------------- /src/appserver/static/web_ping_batch_create.js: -------------------------------------------------------------------------------- 1 | 2 | //Translations for en_US 3 | i18n_register({"plural": function(n) { return n == 1 ? 0 : 1; }, "catalog": {}}); 4 | 5 | require.config({ 6 | paths: { 7 | batch_create_view: '../app/website_monitoring/js/views/BatchInputCreateView' 8 | } 9 | }); 10 | 11 | require(['jquery','underscore','splunkjs/mvc', 'batch_create_view', 'splunkjs/mvc/simplexml/ready!'], 12 | function($, _, mvc, BatchInputCreateView){ 13 | 14 | // Render the slideshow setup page 15 | var batchInputCreateView = new BatchInputCreateView({ 16 | el: $('#batch-create-inputs') 17 | }); 18 | 19 | // Render the page 20 | batchInputCreateView.render(); 21 | 22 | }); -------------------------------------------------------------------------------- /src/bin/modular_input.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LukeMurphey/splunk-website-monitoring/442d08de5bbfed4a879de3b537eae0361de8e473/src/bin/modular_input.zip -------------------------------------------------------------------------------- /src/bin/ntlm3/__init__.py: -------------------------------------------------------------------------------- 1 | 2 | from . import HTTPNtlmAuthHandler # noqa 3 | 4 | 5 | __all__ = ('HTTPNtlmAuthHandler') 6 | -------------------------------------------------------------------------------- /src/bin/ntlm3/compat.py: -------------------------------------------------------------------------------- 1 | 2 | 3 | def _long(value): 4 | try: 5 | return long(value) 6 | except NameError: # we're Python 3, we don't have longs 7 | return int(value) 8 | -------------------------------------------------------------------------------- /src/bin/ntlm3/des.py: -------------------------------------------------------------------------------- 1 | # This file is part of 'NTLM Authorization Proxy Server' http://sourceforge.net/projects/ntlmaps/ 2 | # Copyright 2001 Dmitry A. Rozmanov 3 | # 4 | # This library is free software: you can redistribute it and/or 5 | # modify it under the terms of the GNU Lesser General Public 6 | # License as published by the Free Software Foundation, either 7 | # version 3 of the License, or (at your option) any later version. 8 | 9 | # This library is distributed in the hope that it will be useful, 10 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 | # Lesser General Public License for more details. 13 | # 14 | # You should have received a copy of the GNU Lesser General Public 15 | # License along with this library. If not, see or . 16 | import six 17 | import logging 18 | 19 | from . import des_c 20 | 21 | 22 | log = logging.getLogger(__name__) 23 | 24 | 25 | class DES: 26 | des_c_obj = None 27 | 28 | def __init__(self, key_str): 29 | k = str_to_key56(key_str) 30 | k = key56_to_key64(k) 31 | 32 | key_str = b'' 33 | for i in k: 34 | key_str += six.int2byte(i & 0xFF) 35 | 36 | self.des_c_obj = des_c.DES(key_str) 37 | 38 | def encrypt(self, plain_text): 39 | return self.des_c_obj.encrypt(plain_text) 40 | 41 | def decrypt(self, crypted_text): 42 | return self.des_c_obj.decrypt(crypted_text) 43 | 44 | 45 | DESException = 'DESException' 46 | 47 | 48 | def str_to_key56(key_str): 49 | 50 | if not type(key_str) == six.binary_type: 51 | # TODO rsanders high - figure out how to make this not necessary 52 | key_str = key_str.encode('ascii') 53 | 54 | if len(key_str) < 7: 55 | key_str = key_str + b'\000\000\000\000\000\000\000'[:(7 - len(key_str))] 56 | key_56 = [] 57 | for i in six.iterbytes(key_str[:7]): 58 | key_56.append(i) 59 | 60 | return key_56 61 | 62 | 63 | def key56_to_key64(key_56): 64 | key = [] 65 | for i in range(8): 66 | key.append(0) 67 | 68 | key[0] = key_56[0] 69 | key[1] = ((key_56[0] << 7) & 0xFF) | (key_56[1] >> 1) 70 | key[2] = ((key_56[1] << 6) & 0xFF) | (key_56[2] >> 2) 71 | key[3] = ((key_56[2] << 5) & 0xFF) | (key_56[3] >> 3) 72 | key[4] = ((key_56[3] << 4) & 0xFF) | (key_56[4] >> 4) 73 | key[5] = ((key_56[4] << 3) & 0xFF) | (key_56[5] >> 5) 74 | key[6] = ((key_56[5] << 2) & 0xFF) | (key_56[6] >> 6) 75 | key[7] = (key_56[6] << 1) & 0xFF 76 | 77 | key = set_key_odd_parity(key) 78 | 79 | return key 80 | 81 | 82 | def set_key_odd_parity(key): 83 | for i in range(len(key)): 84 | for k in range(7): 85 | bit = 0 86 | t = key[i] >> k 87 | bit = (t ^ bit) & 0x1 88 | key[i] = (key[i] & 0xFE) | bit 89 | 90 | return key 91 | -------------------------------------------------------------------------------- /src/bin/ntlm3/md4.py: -------------------------------------------------------------------------------- 1 | # From https://gist.github.com/BenWiederhake/eb6dfc2c31d3dc8c34508f4fd091cea9 2 | # Based on https://gist.github.com/bonsaiviking/5644414 3 | # Converted to Python3 by hand. 4 | 5 | import codecs 6 | import struct 7 | 8 | def leftrotate(i, n): 9 | return ((i << n) & 0xffffffff) | (i >> (32 - n)) 10 | 11 | def F(x, y, z): 12 | return (x & y) | (~x & z) 13 | 14 | def G(x, y, z): 15 | return (x & y) | (x & z) | (y & z) 16 | 17 | def H(x, y, z): 18 | return x ^ y ^ z 19 | 20 | class MD4(object): 21 | def __init__(self, data=b''): 22 | self.remainder = data 23 | self.count = 0 24 | self.h = [ 25 | 0x67452301, 26 | 0xefcdab89, 27 | 0x98badcfe, 28 | 0x10325476 29 | ] 30 | 31 | def _add_chunk(self, chunk): 32 | self.count += 1 33 | X = list( struct.unpack("<16I", chunk) + (None,) * (80-16) ) 34 | h = [x for x in self.h] 35 | # Round 1 36 | s = (3, 7, 11, 19) 37 | for r in range(16): 38 | i = (16-r)%4 39 | k = r 40 | h[i] = leftrotate( (h[i] + F(h[(i+1)%4], h[(i+2)%4], h[(i+3)%4]) + X[k]) % 2**32, s[r%4] ) 41 | # Round 2 42 | s = (3, 5, 9, 13) 43 | for r in range(16): 44 | i = (16-r)%4 45 | k = 4*(r%4) + r//4 46 | h[i] = leftrotate( (h[i] + G(h[(i+1)%4], h[(i+2)%4], h[(i+3)%4]) + X[k] + 0x5a827999) % 2**32, s[r%4] ) 47 | # Round 3 48 | s = (3, 9, 11, 15) 49 | k = (0, 8, 4, 12, 2, 10, 6, 14, 1, 9, 5, 13, 3, 11, 7, 15) #wish I could function 50 | for r in range(16): 51 | i = (16-r)%4 52 | h[i] = leftrotate( (h[i] + H(h[(i+1)%4], h[(i+2)%4], h[(i+3)%4]) + X[k[r]] + 0x6ed9eba1) % 2**32, s[r%4] ) 53 | 54 | for i, v in enumerate(h): 55 | self.h[i] = (v + self.h[i]) % 2**32 56 | 57 | def add(self, data): 58 | message = self.remainder + data 59 | r = len(message) % 64 60 | if r != 0: 61 | self.remainder = message[-r:] 62 | else: 63 | self.remainder = b'' 64 | for chunk in range(0, len(message)-r, 64): 65 | self._add_chunk( message[chunk:chunk+64] ) 66 | return self 67 | 68 | def finish(self): 69 | l = len(self.remainder) + 64 * self.count 70 | self.add( b'\x80' + b'\x00' * ((55 - l) % 64) + struct.pack(" 0 else '', 47 | 'total_time': round(result.request_time, 2) if result.request_time > 0 else '', 48 | 'timed_out': result.timed_out, 49 | 'url': result.url 50 | } 51 | 52 | # Add the MD5 of the response if available 53 | if result.response_md5 is not None: 54 | data['content_md5'] = result.response_md5 55 | 56 | # Add the SHA-224 of the response if available 57 | if result.response_sha224 is not None: 58 | data['content_sha224'] = result.response_sha224 59 | 60 | # Add the size of the response if available 61 | if result.response_size is not None: 62 | data['content_size'] = result.response_size 63 | 64 | # Add the variable noting if the expected string was present 65 | if result.has_expected_string is not None: 66 | data['has_expected_string'] = str(result.has_expected_string).lower() 67 | 68 | # Add the the headers if present 69 | if result.headers is not None: 70 | for header in result.headers: 71 | data['header_' + header] = result.headers[header] 72 | 73 | # Output the results 74 | self.output_results([data]) 75 | 76 | if __name__ == '__main__': 77 | WebPingSearchCommand.execute() 78 | -------------------------------------------------------------------------------- /src/bin/website_monitoring_app/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LukeMurphey/splunk-website-monitoring/442d08de5bbfed4a879de3b537eae0361de8e473/src/bin/website_monitoring_app/__init__.py -------------------------------------------------------------------------------- /src/bin/website_monitoring_app/expiring_dict/__init__.py: -------------------------------------------------------------------------------- 1 | from .expiringdict import ExpiringDict 2 | -------------------------------------------------------------------------------- /src/bin/website_monitoring_app/expiring_dict/expiringdict.py: -------------------------------------------------------------------------------- 1 | try: 2 | from collections.abc import MutableMapping 3 | except ImportError: # Will allow usage with virtually any python 3 version 4 | from collections import MutableMapping 5 | 6 | from threading import Timer, Thread, Lock 7 | from ..sortedcontainers import SortedKeyList 8 | from time import time, sleep 9 | 10 | 11 | class ExpiringDict(MutableMapping): 12 | def __init__(self, ttl=None, interval=0.100, *args, **kwargs): 13 | """ 14 | Create an ExpiringDict class, optionally passing in a time-to-live 15 | number in seconds that will act globally as an expiration time for keys. 16 | 17 | If omitted, the dict will work like a normal dict by default, expiring 18 | only keys explicity set via the `.ttl` method. 19 | """ 20 | self.__store = dict(*args, **kwargs) 21 | self.__keys = SortedKeyList(key=lambda x: x[0]) 22 | self.__ttl = ttl 23 | self.__lock = Lock() 24 | self.__interval = interval 25 | 26 | thread = Thread(target=self.__worker) 27 | thread.daemon = True 28 | thread.start() 29 | 30 | def flush(self): 31 | now = time() 32 | max_index = 0 33 | with self.__lock: 34 | for index, (timestamp, key) in enumerate(self.__keys): 35 | if timestamp > now: # rest of the timestamps in future 36 | max_index = index 37 | break 38 | try: 39 | del self.__store[key] 40 | except KeyError: 41 | pass # don't care if it was deleted early 42 | del self.__keys[0:max_index] 43 | 44 | def __worker(self): 45 | while True: 46 | self.flush() 47 | sleep(self.__interval) 48 | 49 | def __setitem__(self, key, value): 50 | """ 51 | Set `value` of `key` in dict. `key` will be automatically 52 | deleted if the `ttl` option was provided for this object. 53 | """ 54 | if self.__ttl: 55 | self.__set_with_expire(key, value, self.__ttl) 56 | else: 57 | self.__store[key] = value 58 | 59 | def ttl(self, key, value, ttl): 60 | """ 61 | Set `value` of `key` in dict to expire after `ttl` seconds. 62 | Overrides object level `ttl` setting. 63 | """ 64 | self.__set_with_expire(key, value, ttl) 65 | 66 | def __set_with_expire(self, key, value, ttl): 67 | self.__lock.acquire() 68 | self.__keys.add((time() + ttl, key)) 69 | self.__store[key] = value 70 | self.__lock.release() 71 | 72 | def __delitem__(self, key): 73 | del self.__store[key] 74 | 75 | def __getitem__(self, key): 76 | return self.__store[key] 77 | 78 | def __iter__(self): 79 | return iter(self.__store) 80 | 81 | def __len__(self): 82 | return len(self.__store) 83 | -------------------------------------------------------------------------------- /src/bin/website_monitoring_app/requests/__init__.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | # __ 4 | # /__) _ _ _ _ _/ _ 5 | # / ( (- (/ (/ (- _) / _) 6 | # / 7 | 8 | """ 9 | Requests HTTP Library 10 | ~~~~~~~~~~~~~~~~~~~~~ 11 | 12 | Requests is an HTTP library, written in Python, for human beings. Basic GET 13 | usage: 14 | 15 | >>> import requests 16 | >>> r = requests.get('https://www.python.org') 17 | >>> r.status_code 18 | 200 19 | >>> 'Python is a programming language' in r.content 20 | True 21 | 22 | ... or POST: 23 | 24 | >>> payload = dict(key1='value1', key2='value2') 25 | >>> r = requests.post('http://httpbin.org/post', data=payload) 26 | >>> print(r.text) 27 | { 28 | ... 29 | "form": { 30 | "key2": "value2", 31 | "key1": "value1" 32 | }, 33 | ... 34 | } 35 | 36 | The other HTTP methods are supported - see `requests.api`. Full documentation 37 | is at . 38 | 39 | :copyright: (c) 2017 by Kenneth Reitz. 40 | :license: Apache 2.0, see LICENSE for more details. 41 | """ 42 | 43 | from .__version__ import __title__, __description__, __url__, __version__ 44 | from .__version__ import __build__, __author__, __author_email__, __license__ 45 | from .__version__ import __copyright__, __cake__ 46 | 47 | # Attempt to enable urllib3's SNI support, if possible 48 | try: 49 | from .packages.urllib3.contrib import pyopenssl 50 | pyopenssl.inject_into_urllib3() 51 | except ImportError: 52 | pass 53 | 54 | import warnings 55 | 56 | # urllib3's DependencyWarnings should be silenced. 57 | from .packages.urllib3.exceptions import DependencyWarning 58 | warnings.simplefilter('ignore', DependencyWarning) 59 | 60 | from . import utils 61 | from .models import Request, Response, PreparedRequest 62 | from .api import request, get, head, post, patch, put, delete, options 63 | from .sessions import session, Session 64 | from .status_codes import codes 65 | from .exceptions import ( 66 | RequestException, Timeout, URLRequired, 67 | TooManyRedirects, HTTPError, ConnectionError, 68 | FileModeWarning, ConnectTimeout, ReadTimeout 69 | ) 70 | 71 | # Set default logging handler to avoid "No handler found" warnings. 72 | import logging 73 | try: # Python 2.7+ 74 | from logging import NullHandler 75 | except ImportError: 76 | class NullHandler(logging.Handler): 77 | def emit(self, record): 78 | pass 79 | 80 | logging.getLogger(__name__).addHandler(NullHandler()) 81 | 82 | # FileModeWarnings go off per the default. 83 | warnings.simplefilter('default', FileModeWarning, append=True) 84 | -------------------------------------------------------------------------------- /src/bin/website_monitoring_app/requests/__version__.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | # .-. .-. .-. . . .-. .-. .-. .-. 4 | # |( |- |.| | | |- `-. | `-. 5 | # ' ' `-' `-`.`-' `-' `-' ' `-' 6 | 7 | __title__ = 'requests' 8 | __description__ = 'Python HTTP for Humans.' 9 | __url__ = 'http://python-requests.org' 10 | __version__ = '2.15.1' 11 | __build__ = 0x021501 12 | __author__ = 'Kenneth Reitz' 13 | __author_email__ = 'me@kennethreitz.org' 14 | __license__ = 'Apache 2.0' 15 | __copyright__ = 'Copyright 2017 Kenneth Reitz' 16 | __cake__ = u'✨ 🍰 ✨' 17 | -------------------------------------------------------------------------------- /src/bin/website_monitoring_app/requests/_internal_utils.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | """ 4 | requests._internal_utils 5 | ~~~~~~~~~~~~~~ 6 | 7 | Provides utility functions that are consumed internally by Requests 8 | which depend on extremely few external helpers (such as compat) 9 | """ 10 | 11 | from .compat import is_py2, builtin_str, str 12 | 13 | 14 | def to_native_string(string, encoding='ascii'): 15 | """Given a string object, regardless of type, returns a representation of 16 | that string in the native string type, encoding and decoding where 17 | necessary. This assumes ASCII unless told otherwise. 18 | """ 19 | if isinstance(string, builtin_str): 20 | out = string 21 | else: 22 | if is_py2: 23 | out = string.encode(encoding) 24 | else: 25 | out = string.decode(encoding) 26 | 27 | return out 28 | 29 | 30 | def unicode_is_ascii(u_string): 31 | """Determine if unicode string only contains ASCII characters. 32 | 33 | :param str u_string: unicode string to check. Must be unicode 34 | and not Python 2 `str`. 35 | :rtype: bool 36 | """ 37 | assert isinstance(u_string, str) 38 | try: 39 | u_string.encode('ascii') 40 | return True 41 | except UnicodeEncodeError: 42 | return False 43 | -------------------------------------------------------------------------------- /src/bin/website_monitoring_app/requests/certs.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | 4 | """ 5 | requests.certs 6 | ~~~~~~~~~~~~~~ 7 | 8 | This module returns the preferred default CA certificate bundle. 9 | 10 | If you are packaging Requests, e.g., for a Linux distribution or a managed 11 | environment, you can change the definition of where() to return a separately 12 | packaged CA bundle. 13 | """ 14 | import os.path 15 | 16 | try: 17 | from certifi import where 18 | except ImportError: 19 | def where(): 20 | """Return the preferred certificate bundle.""" 21 | # vendored bundle inside Requests 22 | return os.path.join(os.path.dirname(__file__), 'cacert.pem') 23 | 24 | if __name__ == '__main__': 25 | print(where()) 26 | -------------------------------------------------------------------------------- /src/bin/website_monitoring_app/requests/compat.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | """ 4 | requests.compat 5 | ~~~~~~~~~~~~~~~ 6 | 7 | This module handles import compatibility issues between Python 2 and 8 | Python 3. 9 | """ 10 | 11 | from .packages import chardet 12 | 13 | import sys 14 | 15 | # ------- 16 | # Pythons 17 | # ------- 18 | 19 | # Syntax sugar. 20 | _ver = sys.version_info 21 | 22 | #: Python 2.x? 23 | is_py2 = (_ver[0] == 2) 24 | 25 | #: Python 3.x? 26 | is_py3 = (_ver[0] == 3) 27 | 28 | try: 29 | import simplejson as json 30 | except (ImportError, SyntaxError): 31 | # simplejson does not support Python 3.2, it throws a SyntaxError 32 | # because of u'...' Unicode literals. 33 | import json 34 | 35 | # --------- 36 | # Specifics 37 | # --------- 38 | 39 | if is_py2: 40 | from urllib import ( 41 | quote, unquote, quote_plus, unquote_plus, urlencode, getproxies, 42 | proxy_bypass, proxy_bypass_environment, getproxies_environment) 43 | from urlparse import urlparse, urlunparse, urljoin, urlsplit, urldefrag 44 | from urllib2 import parse_http_list 45 | import cookielib 46 | from Cookie import Morsel 47 | from StringIO import StringIO 48 | from .packages.urllib3.packages.ordered_dict import OrderedDict 49 | 50 | builtin_str = str 51 | bytes = str 52 | str = unicode 53 | basestring = basestring 54 | numeric_types = (int, long, float) 55 | integer_types = (int, long) 56 | 57 | elif is_py3: 58 | from urllib.parse import urlparse, urlunparse, urljoin, urlsplit, urlencode, quote, unquote, quote_plus, unquote_plus, urldefrag 59 | from urllib.request import parse_http_list, getproxies, proxy_bypass, proxy_bypass_environment, getproxies_environment 60 | from http import cookiejar as cookielib 61 | from http.cookies import Morsel 62 | from io import StringIO 63 | from collections import OrderedDict 64 | 65 | builtin_str = str 66 | str = str 67 | bytes = bytes 68 | basestring = (str, bytes) 69 | numeric_types = (int, float) 70 | integer_types = (int,) 71 | -------------------------------------------------------------------------------- /src/bin/website_monitoring_app/requests/exceptions.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | """ 4 | requests.exceptions 5 | ~~~~~~~~~~~~~~~~~~~ 6 | 7 | This module contains the set of Requests' exceptions. 8 | """ 9 | from .packages.urllib3.exceptions import HTTPError as BaseHTTPError 10 | 11 | 12 | class RequestException(IOError): 13 | """There was an ambiguous exception that occurred while handling your 14 | request. 15 | """ 16 | 17 | def __init__(self, *args, **kwargs): 18 | """Initialize RequestException with `request` and `response` objects.""" 19 | response = kwargs.pop('response', None) 20 | self.response = response 21 | self.request = kwargs.pop('request', None) 22 | if (response is not None and not self.request and 23 | hasattr(response, 'request')): 24 | self.request = self.response.request 25 | super(RequestException, self).__init__(*args, **kwargs) 26 | 27 | 28 | class HTTPError(RequestException): 29 | """An HTTP error occurred.""" 30 | 31 | 32 | class ConnectionError(RequestException): 33 | """A Connection error occurred.""" 34 | 35 | 36 | class ProxyError(ConnectionError): 37 | """A proxy error occurred.""" 38 | 39 | 40 | class SSLError(ConnectionError): 41 | """An SSL error occurred.""" 42 | 43 | 44 | class Timeout(RequestException): 45 | """The request timed out. 46 | 47 | Catching this error will catch both 48 | :exc:`~requests.exceptions.ConnectTimeout` and 49 | :exc:`~requests.exceptions.ReadTimeout` errors. 50 | """ 51 | 52 | 53 | class ConnectTimeout(ConnectionError, Timeout): 54 | """The request timed out while trying to connect to the remote server. 55 | 56 | Requests that produced this error are safe to retry. 57 | """ 58 | 59 | 60 | class ReadTimeout(Timeout): 61 | """The server did not send any data in the allotted amount of time.""" 62 | 63 | 64 | class URLRequired(RequestException): 65 | """A valid URL is required to make a request.""" 66 | 67 | 68 | class TooManyRedirects(RequestException): 69 | """Too many redirects.""" 70 | 71 | 72 | class MissingSchema(RequestException, ValueError): 73 | """The URL schema (e.g. http or https) is missing.""" 74 | 75 | 76 | class InvalidSchema(RequestException, ValueError): 77 | """See defaults.py for valid schemas.""" 78 | 79 | 80 | class InvalidURL(RequestException, ValueError): 81 | """The URL provided was somehow invalid.""" 82 | 83 | 84 | class InvalidHeader(RequestException, ValueError): 85 | """The header value provided was somehow invalid.""" 86 | 87 | 88 | class ChunkedEncodingError(RequestException): 89 | """The server declared chunked encoding but sent an invalid chunk.""" 90 | 91 | 92 | class ContentDecodingError(RequestException, BaseHTTPError): 93 | """Failed to decode response content""" 94 | 95 | 96 | class StreamConsumedError(RequestException, TypeError): 97 | """The content for this response was already consumed""" 98 | 99 | 100 | class RetryError(RequestException): 101 | """Custom retries logic failed""" 102 | 103 | class UnrewindableBodyError(RequestException): 104 | """Requests encountered an error when trying to rewind a body""" 105 | 106 | # Warnings 107 | 108 | 109 | class RequestsWarning(Warning): 110 | """Base warning for Requests.""" 111 | pass 112 | 113 | 114 | class FileModeWarning(RequestsWarning, DeprecationWarning): 115 | """A file was opened in text mode, but Requests determined its binary length.""" 116 | pass 117 | -------------------------------------------------------------------------------- /src/bin/website_monitoring_app/requests/hooks.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | """ 4 | requests.hooks 5 | ~~~~~~~~~~~~~~ 6 | 7 | This module provides the capabilities for the Requests hooks system. 8 | 9 | Available hooks: 10 | 11 | ``response``: 12 | The response generated from a Request. 13 | """ 14 | HOOKS = ['response'] 15 | 16 | 17 | def default_hooks(): 18 | return dict((event, []) for event in HOOKS) 19 | 20 | # TODO: response is the only one 21 | 22 | 23 | def dispatch_hook(key, hooks, hook_data, **kwargs): 24 | """Dispatches a hook dictionary on a given piece of data.""" 25 | hooks = hooks or dict() 26 | hooks = hooks.get(key) 27 | if hooks: 28 | if hasattr(hooks, '__call__'): 29 | hooks = [hooks] 30 | for hook in hooks: 31 | _hook_data = hook(hook_data, **kwargs) 32 | if _hook_data is not None: 33 | hook_data = _hook_data 34 | return hook_data 35 | -------------------------------------------------------------------------------- /src/bin/website_monitoring_app/requests/packages/README.rst: -------------------------------------------------------------------------------- 1 | If you are planning to submit a pull request to requests with any changes in 2 | this library do not go any further. These are independent libraries which we 3 | vendor into requests. Any changes necessary to these libraries must be made in 4 | them and submitted as separate pull requests to those libraries. 5 | 6 | urllib3 pull requests go here: https://github.com/shazow/urllib3 7 | 8 | chardet pull requests go here: https://github.com/chardet/chardet 9 | 10 | idna pull requests go here: https://github.com/kjd/idna 11 | 12 | See https://github.com/kennethreitz/requests/pull/1812#issuecomment-30854316 13 | for the reasoning behind this. 14 | -------------------------------------------------------------------------------- /src/bin/website_monitoring_app/requests/packages/__init__.py: -------------------------------------------------------------------------------- 1 | ''' 2 | Debian and other distributions "unbundle" requests' vendored dependencies, and 3 | rewrite all imports to use the global versions of ``urllib3`` and ``chardet``. 4 | The problem with this is that not only requests itself imports those 5 | dependencies, but third-party code outside of the distros' control too. 6 | 7 | In reaction to these problems, the distro maintainers replaced 8 | ``requests.packages`` with a magical "stub module" that imports the correct 9 | modules. The implementations were varying in quality and all had severe 10 | problems. For example, a symlink (or hardlink) that links the correct modules 11 | into place introduces problems regarding object identity, since you now have 12 | two modules in `sys.modules` with the same API, but different identities:: 13 | 14 | requests.packages.urllib3 is not urllib3 15 | 16 | With version ``2.5.2``, requests started to maintain its own stub, so that 17 | distro-specific breakage would be reduced to a minimum, even though the whole 18 | issue is not requests' fault in the first place. See 19 | https://github.com/kennethreitz/requests/pull/2375 for the corresponding pull 20 | request. 21 | ''' 22 | 23 | from __future__ import absolute_import 24 | import sys 25 | 26 | try: 27 | from . import urllib3 28 | except ImportError: 29 | import urllib3 30 | sys.modules['%s.urllib3' % __name__] = urllib3 31 | 32 | try: 33 | from . import chardet 34 | except ImportError: 35 | import chardet 36 | sys.modules['%s.chardet' % __name__] = chardet 37 | -------------------------------------------------------------------------------- /src/bin/website_monitoring_app/requests/packages/chardet/__init__.py: -------------------------------------------------------------------------------- 1 | ######################## BEGIN LICENSE BLOCK ######################## 2 | # This library is free software; you can redistribute it and/or 3 | # modify it under the terms of the GNU Lesser General Public 4 | # License as published by the Free Software Foundation; either 5 | # version 2.1 of the License, or (at your option) any later version. 6 | # 7 | # This library is distributed in the hope that it will be useful, 8 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 9 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 10 | # Lesser General Public License for more details. 11 | # 12 | # You should have received a copy of the GNU Lesser General Public 13 | # License along with this library; if not, write to the Free Software 14 | # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 15 | # 02110-1301 USA 16 | ######################### END LICENSE BLOCK ######################### 17 | 18 | 19 | from .compat import PY2, PY3 20 | from .universaldetector import UniversalDetector 21 | from .version import __version__, VERSION 22 | 23 | 24 | def detect(byte_str): 25 | """ 26 | Detect the encoding of the given byte string. 27 | 28 | :param byte_str: The byte sequence to examine. 29 | :type byte_str: ``bytes`` or ``bytearray`` 30 | """ 31 | if not isinstance(byte_str, bytearray): 32 | if not isinstance(byte_str, bytes): 33 | raise TypeError('Expected object of type bytes or bytearray, got: ' 34 | '{0}'.format(type(byte_str))) 35 | else: 36 | byte_str = bytearray(byte_str) 37 | detector = UniversalDetector() 38 | detector.feed(byte_str) 39 | return detector.close() 40 | -------------------------------------------------------------------------------- /src/bin/website_monitoring_app/requests/packages/chardet/big5prober.py: -------------------------------------------------------------------------------- 1 | ######################## BEGIN LICENSE BLOCK ######################## 2 | # The Original Code is Mozilla Communicator client code. 3 | # 4 | # The Initial Developer of the Original Code is 5 | # Netscape Communications Corporation. 6 | # Portions created by the Initial Developer are Copyright (C) 1998 7 | # the Initial Developer. All Rights Reserved. 8 | # 9 | # Contributor(s): 10 | # Mark Pilgrim - port to Python 11 | # 12 | # This library is free software; you can redistribute it and/or 13 | # modify it under the terms of the GNU Lesser General Public 14 | # License as published by the Free Software Foundation; either 15 | # version 2.1 of the License, or (at your option) any later version. 16 | # 17 | # This library is distributed in the hope that it will be useful, 18 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 19 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 20 | # Lesser General Public License for more details. 21 | # 22 | # You should have received a copy of the GNU Lesser General Public 23 | # License along with this library; if not, write to the Free Software 24 | # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 25 | # 02110-1301 USA 26 | ######################### END LICENSE BLOCK ######################### 27 | 28 | from .mbcharsetprober import MultiByteCharSetProber 29 | from .codingstatemachine import CodingStateMachine 30 | from .chardistribution import Big5DistributionAnalysis 31 | from .mbcssm import BIG5_SM_MODEL 32 | 33 | 34 | class Big5Prober(MultiByteCharSetProber): 35 | def __init__(self): 36 | super(Big5Prober, self).__init__() 37 | self.coding_sm = CodingStateMachine(BIG5_SM_MODEL) 38 | self.distribution_analyzer = Big5DistributionAnalysis() 39 | self.reset() 40 | 41 | @property 42 | def charset_name(self): 43 | return "Big5" 44 | 45 | @property 46 | def language(self): 47 | return "Chinese" 48 | -------------------------------------------------------------------------------- /src/bin/website_monitoring_app/requests/packages/chardet/cli/__init__.py: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /src/bin/website_monitoring_app/requests/packages/chardet/cli/chardetect.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | """ 3 | Script which takes one or more file paths and reports on their detected 4 | encodings 5 | 6 | Example:: 7 | 8 | % chardetect somefile someotherfile 9 | somefile: windows-1252 with confidence 0.5 10 | someotherfile: ascii with confidence 1.0 11 | 12 | If no paths are provided, it takes its input from stdin. 13 | 14 | """ 15 | 16 | from __future__ import absolute_import, print_function, unicode_literals 17 | 18 | import argparse 19 | import sys 20 | 21 | from chardet import __version__ 22 | from chardet.compat import PY2 23 | from chardet.universaldetector import UniversalDetector 24 | 25 | 26 | def description_of(lines, name='stdin'): 27 | """ 28 | Return a string describing the probable encoding of a file or 29 | list of strings. 30 | 31 | :param lines: The lines to get the encoding of. 32 | :type lines: Iterable of bytes 33 | :param name: Name of file or collection of lines 34 | :type name: str 35 | """ 36 | u = UniversalDetector() 37 | for line in lines: 38 | line = bytearray(line) 39 | u.feed(line) 40 | # shortcut out of the loop to save reading further - particularly useful if we read a BOM. 41 | if u.done: 42 | break 43 | u.close() 44 | result = u.result 45 | if PY2: 46 | name = name.decode(sys.getfilesystemencoding(), 'ignore') 47 | if result['encoding']: 48 | return '{0}: {1} with confidence {2}'.format(name, result['encoding'], 49 | result['confidence']) 50 | else: 51 | return '{0}: no result'.format(name) 52 | 53 | 54 | def main(argv=None): 55 | """ 56 | Handles command line arguments and gets things started. 57 | 58 | :param argv: List of arguments, as if specified on the command-line. 59 | If None, ``sys.argv[1:]`` is used instead. 60 | :type argv: list of str 61 | """ 62 | # Get command line arguments 63 | parser = argparse.ArgumentParser( 64 | description="Takes one or more file paths and reports their detected \ 65 | encodings") 66 | parser.add_argument('input', 67 | help='File whose encoding we would like to determine. \ 68 | (default: stdin)', 69 | type=argparse.FileType('rb'), nargs='*', 70 | default=[sys.stdin if PY2 else sys.stdin.buffer]) 71 | parser.add_argument('--version', action='version', 72 | version='%(prog)s {0}'.format(__version__)) 73 | args = parser.parse_args(argv) 74 | 75 | for f in args.input: 76 | if f.isatty(): 77 | print("You are running chardetect interactively. Press " + 78 | "CTRL-D twice at the start of a blank line to signal the " + 79 | "end of your input. If you want help, run chardetect " + 80 | "--help\n", file=sys.stderr) 81 | print(description_of(f, f.name)) 82 | 83 | 84 | if __name__ == '__main__': 85 | main() 86 | -------------------------------------------------------------------------------- /src/bin/website_monitoring_app/requests/packages/chardet/codingstatemachine.py: -------------------------------------------------------------------------------- 1 | ######################## BEGIN LICENSE BLOCK ######################## 2 | # The Original Code is mozilla.org code. 3 | # 4 | # The Initial Developer of the Original Code is 5 | # Netscape Communications Corporation. 6 | # Portions created by the Initial Developer are Copyright (C) 1998 7 | # the Initial Developer. All Rights Reserved. 8 | # 9 | # Contributor(s): 10 | # Mark Pilgrim - port to Python 11 | # 12 | # This library is free software; you can redistribute it and/or 13 | # modify it under the terms of the GNU Lesser General Public 14 | # License as published by the Free Software Foundation; either 15 | # version 2.1 of the License, or (at your option) any later version. 16 | # 17 | # This library is distributed in the hope that it will be useful, 18 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 19 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 20 | # Lesser General Public License for more details. 21 | # 22 | # You should have received a copy of the GNU Lesser General Public 23 | # License along with this library; if not, write to the Free Software 24 | # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 25 | # 02110-1301 USA 26 | ######################### END LICENSE BLOCK ######################### 27 | 28 | import logging 29 | 30 | from .enums import MachineState 31 | 32 | 33 | class CodingStateMachine(object): 34 | """ 35 | A state machine to verify a byte sequence for a particular encoding. For 36 | each byte the detector receives, it will feed that byte to every active 37 | state machine available, one byte at a time. The state machine changes its 38 | state based on its previous state and the byte it receives. There are 3 39 | states in a state machine that are of interest to an auto-detector: 40 | 41 | START state: This is the state to start with, or a legal byte sequence 42 | (i.e. a valid code point) for character has been identified. 43 | 44 | ME state: This indicates that the state machine identified a byte sequence 45 | that is specific to the charset it is designed for and that 46 | there is no other possible encoding which can contain this byte 47 | sequence. This will to lead to an immediate positive answer for 48 | the detector. 49 | 50 | ERROR state: This indicates the state machine identified an illegal byte 51 | sequence for that encoding. This will lead to an immediate 52 | negative answer for this encoding. Detector will exclude this 53 | encoding from consideration from here on. 54 | """ 55 | def __init__(self, sm): 56 | self._model = sm 57 | self._curr_byte_pos = 0 58 | self._curr_char_len = 0 59 | self._curr_state = None 60 | self.logger = logging.getLogger(__name__) 61 | self.reset() 62 | 63 | def reset(self): 64 | self._curr_state = MachineState.START 65 | 66 | def next_state(self, c): 67 | # for each byte we get its class 68 | # if it is first byte, we also get byte length 69 | byte_class = self._model['class_table'][c] 70 | if self._curr_state == MachineState.START: 71 | self._curr_byte_pos = 0 72 | self._curr_char_len = self._model['char_len_table'][byte_class] 73 | # from byte's class and state_table, we get its next state 74 | curr_state = (self._curr_state * self._model['class_factor'] 75 | + byte_class) 76 | self._curr_state = self._model['state_table'][curr_state] 77 | self._curr_byte_pos += 1 78 | return self._curr_state 79 | 80 | def get_current_charlen(self): 81 | return self._curr_char_len 82 | 83 | def get_coding_state_machine(self): 84 | return self._model['name'] 85 | 86 | @property 87 | def language(self): 88 | return self._model['language'] 89 | -------------------------------------------------------------------------------- /src/bin/website_monitoring_app/requests/packages/chardet/compat.py: -------------------------------------------------------------------------------- 1 | ######################## BEGIN LICENSE BLOCK ######################## 2 | # Contributor(s): 3 | # Dan Blanchard 4 | # Ian Cordasco 5 | # 6 | # This library is free software; you can redistribute it and/or 7 | # modify it under the terms of the GNU Lesser General Public 8 | # License as published by the Free Software Foundation; either 9 | # version 2.1 of the License, or (at your option) any later version. 10 | # 11 | # This library is distributed in the hope that it will be useful, 12 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 | # Lesser General Public License for more details. 15 | # 16 | # You should have received a copy of the GNU Lesser General Public 17 | # License along with this library; if not, write to the Free Software 18 | # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 19 | # 02110-1301 USA 20 | ######################### END LICENSE BLOCK ######################### 21 | 22 | import sys 23 | 24 | 25 | if sys.version_info < (3, 0): 26 | PY2 = True 27 | PY3 = False 28 | base_str = (str, unicode) 29 | text_type = unicode 30 | else: 31 | PY2 = False 32 | PY3 = True 33 | base_str = (bytes, str) 34 | text_type = str 35 | -------------------------------------------------------------------------------- /src/bin/website_monitoring_app/requests/packages/chardet/cp949prober.py: -------------------------------------------------------------------------------- 1 | ######################## BEGIN LICENSE BLOCK ######################## 2 | # The Original Code is mozilla.org code. 3 | # 4 | # The Initial Developer of the Original Code is 5 | # Netscape Communications Corporation. 6 | # Portions created by the Initial Developer are Copyright (C) 1998 7 | # the Initial Developer. All Rights Reserved. 8 | # 9 | # Contributor(s): 10 | # Mark Pilgrim - port to Python 11 | # 12 | # This library is free software; you can redistribute it and/or 13 | # modify it under the terms of the GNU Lesser General Public 14 | # License as published by the Free Software Foundation; either 15 | # version 2.1 of the License, or (at your option) any later version. 16 | # 17 | # This library is distributed in the hope that it will be useful, 18 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 19 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 20 | # Lesser General Public License for more details. 21 | # 22 | # You should have received a copy of the GNU Lesser General Public 23 | # License along with this library; if not, write to the Free Software 24 | # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 25 | # 02110-1301 USA 26 | ######################### END LICENSE BLOCK ######################### 27 | 28 | from .chardistribution import EUCKRDistributionAnalysis 29 | from .codingstatemachine import CodingStateMachine 30 | from .mbcharsetprober import MultiByteCharSetProber 31 | from .mbcssm import CP949_SM_MODEL 32 | 33 | 34 | class CP949Prober(MultiByteCharSetProber): 35 | def __init__(self): 36 | super(CP949Prober, self).__init__() 37 | self.coding_sm = CodingStateMachine(CP949_SM_MODEL) 38 | # NOTE: CP949 is a superset of EUC-KR, so the distribution should be 39 | # not different. 40 | self.distribution_analyzer = EUCKRDistributionAnalysis() 41 | self.reset() 42 | 43 | @property 44 | def charset_name(self): 45 | return "CP949" 46 | 47 | @property 48 | def language(self): 49 | return "Korean" 50 | -------------------------------------------------------------------------------- /src/bin/website_monitoring_app/requests/packages/chardet/enums.py: -------------------------------------------------------------------------------- 1 | """ 2 | All of the Enums that are used throughout the chardet package. 3 | 4 | :author: Dan Blanchard (dan.blanchard@gmail.com) 5 | """ 6 | 7 | 8 | class InputState(object): 9 | """ 10 | This enum represents the different states a universal detector can be in. 11 | """ 12 | PURE_ASCII = 0 13 | ESC_ASCII = 1 14 | HIGH_BYTE = 2 15 | 16 | 17 | class LanguageFilter(object): 18 | """ 19 | This enum represents the different language filters we can apply to a 20 | ``UniversalDetector``. 21 | """ 22 | CHINESE_SIMPLIFIED = 0x01 23 | CHINESE_TRADITIONAL = 0x02 24 | JAPANESE = 0x04 25 | KOREAN = 0x08 26 | NON_CJK = 0x10 27 | ALL = 0x1F 28 | CHINESE = CHINESE_SIMPLIFIED | CHINESE_TRADITIONAL 29 | CJK = CHINESE | JAPANESE | KOREAN 30 | 31 | 32 | class ProbingState(object): 33 | """ 34 | This enum represents the different states a prober can be in. 35 | """ 36 | DETECTING = 0 37 | FOUND_IT = 1 38 | NOT_ME = 2 39 | 40 | 41 | class MachineState(object): 42 | """ 43 | This enum represents the different states a state machine can be in. 44 | """ 45 | START = 0 46 | ERROR = 1 47 | ITS_ME = 2 48 | 49 | 50 | class SequenceLikelihood(object): 51 | """ 52 | This enum represents the likelihood of a character following the previous one. 53 | """ 54 | NEGATIVE = 0 55 | UNLIKELY = 1 56 | LIKELY = 2 57 | POSITIVE = 3 58 | 59 | @classmethod 60 | def get_num_categories(cls): 61 | """:returns: The number of likelihood categories in the enum.""" 62 | return 4 63 | 64 | 65 | class CharacterCategory(object): 66 | """ 67 | This enum represents the different categories language models for 68 | ``SingleByteCharsetProber`` put characters into. 69 | 70 | Anything less than CONTROL is considered a letter. 71 | """ 72 | UNDEFINED = 255 73 | LINE_BREAK = 254 74 | SYMBOL = 253 75 | DIGIT = 252 76 | CONTROL = 251 77 | -------------------------------------------------------------------------------- /src/bin/website_monitoring_app/requests/packages/chardet/eucjpprober.py: -------------------------------------------------------------------------------- 1 | ######################## BEGIN LICENSE BLOCK ######################## 2 | # The Original Code is mozilla.org code. 3 | # 4 | # The Initial Developer of the Original Code is 5 | # Netscape Communications Corporation. 6 | # Portions created by the Initial Developer are Copyright (C) 1998 7 | # the Initial Developer. All Rights Reserved. 8 | # 9 | # Contributor(s): 10 | # Mark Pilgrim - port to Python 11 | # 12 | # This library is free software; you can redistribute it and/or 13 | # modify it under the terms of the GNU Lesser General Public 14 | # License as published by the Free Software Foundation; either 15 | # version 2.1 of the License, or (at your option) any later version. 16 | # 17 | # This library is distributed in the hope that it will be useful, 18 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 19 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 20 | # Lesser General Public License for more details. 21 | # 22 | # You should have received a copy of the GNU Lesser General Public 23 | # License along with this library; if not, write to the Free Software 24 | # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 25 | # 02110-1301 USA 26 | ######################### END LICENSE BLOCK ######################### 27 | 28 | from .enums import ProbingState, MachineState 29 | from .mbcharsetprober import MultiByteCharSetProber 30 | from .codingstatemachine import CodingStateMachine 31 | from .chardistribution import EUCJPDistributionAnalysis 32 | from .jpcntx import EUCJPContextAnalysis 33 | from .mbcssm import EUCJP_SM_MODEL 34 | 35 | 36 | class EUCJPProber(MultiByteCharSetProber): 37 | def __init__(self): 38 | super(EUCJPProber, self).__init__() 39 | self.coding_sm = CodingStateMachine(EUCJP_SM_MODEL) 40 | self.distribution_analyzer = EUCJPDistributionAnalysis() 41 | self.context_analyzer = EUCJPContextAnalysis() 42 | self.reset() 43 | 44 | def reset(self): 45 | super(EUCJPProber, self).reset() 46 | self.context_analyzer.reset() 47 | 48 | @property 49 | def charset_name(self): 50 | return "EUC-JP" 51 | 52 | @property 53 | def language(self): 54 | return "Japanese" 55 | 56 | def feed(self, byte_str): 57 | for i in range(len(byte_str)): 58 | # PY3K: byte_str is a byte array, so byte_str[i] is an int, not a byte 59 | coding_state = self.coding_sm.next_state(byte_str[i]) 60 | if coding_state == MachineState.ERROR: 61 | self.logger.debug('%s %s prober hit error at byte %s', 62 | self.charset_name, self.language, i) 63 | self._state = ProbingState.NOT_ME 64 | break 65 | elif coding_state == MachineState.ITS_ME: 66 | self._state = ProbingState.FOUND_IT 67 | break 68 | elif coding_state == MachineState.START: 69 | char_len = self.coding_sm.get_current_charlen() 70 | if i == 0: 71 | self._last_char[1] = byte_str[0] 72 | self.context_analyzer.feed(self._last_char, char_len) 73 | self.distribution_analyzer.feed(self._last_char, char_len) 74 | else: 75 | self.context_analyzer.feed(byte_str[i - 1:i + 1], 76 | char_len) 77 | self.distribution_analyzer.feed(byte_str[i - 1:i + 1], 78 | char_len) 79 | 80 | self._last_char[0] = byte_str[-1] 81 | 82 | if self.state == ProbingState.DETECTING: 83 | if (self.context_analyzer.got_enough_data() and 84 | (self.get_confidence() > self.SHORTCUT_THRESHOLD)): 85 | self._state = ProbingState.FOUND_IT 86 | 87 | return self.state 88 | 89 | def get_confidence(self): 90 | context_conf = self.context_analyzer.get_confidence() 91 | distrib_conf = self.distribution_analyzer.get_confidence() 92 | return max(context_conf, distrib_conf) 93 | -------------------------------------------------------------------------------- /src/bin/website_monitoring_app/requests/packages/chardet/euckrprober.py: -------------------------------------------------------------------------------- 1 | ######################## BEGIN LICENSE BLOCK ######################## 2 | # The Original Code is mozilla.org code. 3 | # 4 | # The Initial Developer of the Original Code is 5 | # Netscape Communications Corporation. 6 | # Portions created by the Initial Developer are Copyright (C) 1998 7 | # the Initial Developer. All Rights Reserved. 8 | # 9 | # Contributor(s): 10 | # Mark Pilgrim - port to Python 11 | # 12 | # This library is free software; you can redistribute it and/or 13 | # modify it under the terms of the GNU Lesser General Public 14 | # License as published by the Free Software Foundation; either 15 | # version 2.1 of the License, or (at your option) any later version. 16 | # 17 | # This library is distributed in the hope that it will be useful, 18 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 19 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 20 | # Lesser General Public License for more details. 21 | # 22 | # You should have received a copy of the GNU Lesser General Public 23 | # License along with this library; if not, write to the Free Software 24 | # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 25 | # 02110-1301 USA 26 | ######################### END LICENSE BLOCK ######################### 27 | 28 | from .mbcharsetprober import MultiByteCharSetProber 29 | from .codingstatemachine import CodingStateMachine 30 | from .chardistribution import EUCKRDistributionAnalysis 31 | from .mbcssm import EUCKR_SM_MODEL 32 | 33 | 34 | class EUCKRProber(MultiByteCharSetProber): 35 | def __init__(self): 36 | super(EUCKRProber, self).__init__() 37 | self.coding_sm = CodingStateMachine(EUCKR_SM_MODEL) 38 | self.distribution_analyzer = EUCKRDistributionAnalysis() 39 | self.reset() 40 | 41 | @property 42 | def charset_name(self): 43 | return "EUC-KR" 44 | 45 | @property 46 | def language(self): 47 | return "Korean" 48 | -------------------------------------------------------------------------------- /src/bin/website_monitoring_app/requests/packages/chardet/euctwprober.py: -------------------------------------------------------------------------------- 1 | ######################## BEGIN LICENSE BLOCK ######################## 2 | # The Original Code is mozilla.org code. 3 | # 4 | # The Initial Developer of the Original Code is 5 | # Netscape Communications Corporation. 6 | # Portions created by the Initial Developer are Copyright (C) 1998 7 | # the Initial Developer. All Rights Reserved. 8 | # 9 | # Contributor(s): 10 | # Mark Pilgrim - port to Python 11 | # 12 | # This library is free software; you can redistribute it and/or 13 | # modify it under the terms of the GNU Lesser General Public 14 | # License as published by the Free Software Foundation; either 15 | # version 2.1 of the License, or (at your option) any later version. 16 | # 17 | # This library is distributed in the hope that it will be useful, 18 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 19 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 20 | # Lesser General Public License for more details. 21 | # 22 | # You should have received a copy of the GNU Lesser General Public 23 | # License along with this library; if not, write to the Free Software 24 | # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 25 | # 02110-1301 USA 26 | ######################### END LICENSE BLOCK ######################### 27 | 28 | from .mbcharsetprober import MultiByteCharSetProber 29 | from .codingstatemachine import CodingStateMachine 30 | from .chardistribution import EUCTWDistributionAnalysis 31 | from .mbcssm import EUCTW_SM_MODEL 32 | 33 | class EUCTWProber(MultiByteCharSetProber): 34 | def __init__(self): 35 | super(EUCTWProber, self).__init__() 36 | self.coding_sm = CodingStateMachine(EUCTW_SM_MODEL) 37 | self.distribution_analyzer = EUCTWDistributionAnalysis() 38 | self.reset() 39 | 40 | @property 41 | def charset_name(self): 42 | return "EUC-TW" 43 | 44 | @property 45 | def language(self): 46 | return "Taiwan" 47 | -------------------------------------------------------------------------------- /src/bin/website_monitoring_app/requests/packages/chardet/gb2312prober.py: -------------------------------------------------------------------------------- 1 | ######################## BEGIN LICENSE BLOCK ######################## 2 | # The Original Code is mozilla.org code. 3 | # 4 | # The Initial Developer of the Original Code is 5 | # Netscape Communications Corporation. 6 | # Portions created by the Initial Developer are Copyright (C) 1998 7 | # the Initial Developer. All Rights Reserved. 8 | # 9 | # Contributor(s): 10 | # Mark Pilgrim - port to Python 11 | # 12 | # This library is free software; you can redistribute it and/or 13 | # modify it under the terms of the GNU Lesser General Public 14 | # License as published by the Free Software Foundation; either 15 | # version 2.1 of the License, or (at your option) any later version. 16 | # 17 | # This library is distributed in the hope that it will be useful, 18 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 19 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 20 | # Lesser General Public License for more details. 21 | # 22 | # You should have received a copy of the GNU Lesser General Public 23 | # License along with this library; if not, write to the Free Software 24 | # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 25 | # 02110-1301 USA 26 | ######################### END LICENSE BLOCK ######################### 27 | 28 | from .mbcharsetprober import MultiByteCharSetProber 29 | from .codingstatemachine import CodingStateMachine 30 | from .chardistribution import GB2312DistributionAnalysis 31 | from .mbcssm import GB2312_SM_MODEL 32 | 33 | class GB2312Prober(MultiByteCharSetProber): 34 | def __init__(self): 35 | super(GB2312Prober, self).__init__() 36 | self.coding_sm = CodingStateMachine(GB2312_SM_MODEL) 37 | self.distribution_analyzer = GB2312DistributionAnalysis() 38 | self.reset() 39 | 40 | @property 41 | def charset_name(self): 42 | return "GB2312" 43 | 44 | @property 45 | def language(self): 46 | return "Chinese" 47 | -------------------------------------------------------------------------------- /src/bin/website_monitoring_app/requests/packages/chardet/mbcharsetprober.py: -------------------------------------------------------------------------------- 1 | ######################## BEGIN LICENSE BLOCK ######################## 2 | # The Original Code is Mozilla Universal charset detector code. 3 | # 4 | # The Initial Developer of the Original Code is 5 | # Netscape Communications Corporation. 6 | # Portions created by the Initial Developer are Copyright (C) 2001 7 | # the Initial Developer. All Rights Reserved. 8 | # 9 | # Contributor(s): 10 | # Mark Pilgrim - port to Python 11 | # Shy Shalom - original C code 12 | # Proofpoint, Inc. 13 | # 14 | # This library is free software; you can redistribute it and/or 15 | # modify it under the terms of the GNU Lesser General Public 16 | # License as published by the Free Software Foundation; either 17 | # version 2.1 of the License, or (at your option) any later version. 18 | # 19 | # This library is distributed in the hope that it will be useful, 20 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 21 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 22 | # Lesser General Public License for more details. 23 | # 24 | # You should have received a copy of the GNU Lesser General Public 25 | # License along with this library; if not, write to the Free Software 26 | # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 27 | # 02110-1301 USA 28 | ######################### END LICENSE BLOCK ######################### 29 | 30 | from .charsetprober import CharSetProber 31 | from .enums import ProbingState, MachineState 32 | 33 | 34 | class MultiByteCharSetProber(CharSetProber): 35 | """ 36 | MultiByteCharSetProber 37 | """ 38 | 39 | def __init__(self, lang_filter=None): 40 | super(MultiByteCharSetProber, self).__init__(lang_filter=lang_filter) 41 | self.distribution_analyzer = None 42 | self.coding_sm = None 43 | self._last_char = [0, 0] 44 | 45 | def reset(self): 46 | super(MultiByteCharSetProber, self).reset() 47 | if self.coding_sm: 48 | self.coding_sm.reset() 49 | if self.distribution_analyzer: 50 | self.distribution_analyzer.reset() 51 | self._last_char = [0, 0] 52 | 53 | @property 54 | def charset_name(self): 55 | raise NotImplementedError 56 | 57 | @property 58 | def language(self): 59 | raise NotImplementedError 60 | 61 | def feed(self, byte_str): 62 | for i in range(len(byte_str)): 63 | coding_state = self.coding_sm.next_state(byte_str[i]) 64 | if coding_state == MachineState.ERROR: 65 | self.logger.debug('%s %s prober hit error at byte %s', 66 | self.charset_name, self.language, i) 67 | self._state = ProbingState.NOT_ME 68 | break 69 | elif coding_state == MachineState.ITS_ME: 70 | self._state = ProbingState.FOUND_IT 71 | break 72 | elif coding_state == MachineState.START: 73 | char_len = self.coding_sm.get_current_charlen() 74 | if i == 0: 75 | self._last_char[1] = byte_str[0] 76 | self.distribution_analyzer.feed(self._last_char, char_len) 77 | else: 78 | self.distribution_analyzer.feed(byte_str[i - 1:i + 1], 79 | char_len) 80 | 81 | self._last_char[0] = byte_str[-1] 82 | 83 | if self.state == ProbingState.DETECTING: 84 | if (self.distribution_analyzer.got_enough_data() and 85 | (self.get_confidence() > self.SHORTCUT_THRESHOLD)): 86 | self._state = ProbingState.FOUND_IT 87 | 88 | return self.state 89 | 90 | def get_confidence(self): 91 | return self.distribution_analyzer.get_confidence() 92 | -------------------------------------------------------------------------------- /src/bin/website_monitoring_app/requests/packages/chardet/mbcsgroupprober.py: -------------------------------------------------------------------------------- 1 | ######################## BEGIN LICENSE BLOCK ######################## 2 | # The Original Code is Mozilla Universal charset detector code. 3 | # 4 | # The Initial Developer of the Original Code is 5 | # Netscape Communications Corporation. 6 | # Portions created by the Initial Developer are Copyright (C) 2001 7 | # the Initial Developer. All Rights Reserved. 8 | # 9 | # Contributor(s): 10 | # Mark Pilgrim - port to Python 11 | # Shy Shalom - original C code 12 | # Proofpoint, Inc. 13 | # 14 | # This library is free software; you can redistribute it and/or 15 | # modify it under the terms of the GNU Lesser General Public 16 | # License as published by the Free Software Foundation; either 17 | # version 2.1 of the License, or (at your option) any later version. 18 | # 19 | # This library is distributed in the hope that it will be useful, 20 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 21 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 22 | # Lesser General Public License for more details. 23 | # 24 | # You should have received a copy of the GNU Lesser General Public 25 | # License along with this library; if not, write to the Free Software 26 | # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 27 | # 02110-1301 USA 28 | ######################### END LICENSE BLOCK ######################### 29 | 30 | from .charsetgroupprober import CharSetGroupProber 31 | from .utf8prober import UTF8Prober 32 | from .sjisprober import SJISProber 33 | from .eucjpprober import EUCJPProber 34 | from .gb2312prober import GB2312Prober 35 | from .euckrprober import EUCKRProber 36 | from .cp949prober import CP949Prober 37 | from .big5prober import Big5Prober 38 | from .euctwprober import EUCTWProber 39 | 40 | 41 | class MBCSGroupProber(CharSetGroupProber): 42 | def __init__(self, lang_filter=None): 43 | super(MBCSGroupProber, self).__init__(lang_filter=lang_filter) 44 | self.probers = [ 45 | UTF8Prober(), 46 | SJISProber(), 47 | EUCJPProber(), 48 | GB2312Prober(), 49 | EUCKRProber(), 50 | CP949Prober(), 51 | Big5Prober(), 52 | EUCTWProber() 53 | ] 54 | self.reset() 55 | -------------------------------------------------------------------------------- /src/bin/website_monitoring_app/requests/packages/chardet/sbcsgroupprober.py: -------------------------------------------------------------------------------- 1 | ######################## BEGIN LICENSE BLOCK ######################## 2 | # The Original Code is Mozilla Universal charset detector code. 3 | # 4 | # The Initial Developer of the Original Code is 5 | # Netscape Communications Corporation. 6 | # Portions created by the Initial Developer are Copyright (C) 2001 7 | # the Initial Developer. All Rights Reserved. 8 | # 9 | # Contributor(s): 10 | # Mark Pilgrim - port to Python 11 | # Shy Shalom - original C code 12 | # 13 | # This library is free software; you can redistribute it and/or 14 | # modify it under the terms of the GNU Lesser General Public 15 | # License as published by the Free Software Foundation; either 16 | # version 2.1 of the License, or (at your option) any later version. 17 | # 18 | # This library is distributed in the hope that it will be useful, 19 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 20 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 21 | # Lesser General Public License for more details. 22 | # 23 | # You should have received a copy of the GNU Lesser General Public 24 | # License along with this library; if not, write to the Free Software 25 | # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 26 | # 02110-1301 USA 27 | ######################### END LICENSE BLOCK ######################### 28 | 29 | from .charsetgroupprober import CharSetGroupProber 30 | from .sbcharsetprober import SingleByteCharSetProber 31 | from .langcyrillicmodel import (Win1251CyrillicModel, Koi8rModel, 32 | Latin5CyrillicModel, MacCyrillicModel, 33 | Ibm866Model, Ibm855Model) 34 | from .langgreekmodel import Latin7GreekModel, Win1253GreekModel 35 | from .langbulgarianmodel import Latin5BulgarianModel, Win1251BulgarianModel 36 | # from .langhungarianmodel import Latin2HungarianModel, Win1250HungarianModel 37 | from .langthaimodel import TIS620ThaiModel 38 | from .langhebrewmodel import Win1255HebrewModel 39 | from .hebrewprober import HebrewProber 40 | from .langturkishmodel import Latin5TurkishModel 41 | 42 | 43 | class SBCSGroupProber(CharSetGroupProber): 44 | def __init__(self): 45 | super(SBCSGroupProber, self).__init__() 46 | self.probers = [ 47 | SingleByteCharSetProber(Win1251CyrillicModel), 48 | SingleByteCharSetProber(Koi8rModel), 49 | SingleByteCharSetProber(Latin5CyrillicModel), 50 | SingleByteCharSetProber(MacCyrillicModel), 51 | SingleByteCharSetProber(Ibm866Model), 52 | SingleByteCharSetProber(Ibm855Model), 53 | SingleByteCharSetProber(Latin7GreekModel), 54 | SingleByteCharSetProber(Win1253GreekModel), 55 | SingleByteCharSetProber(Latin5BulgarianModel), 56 | SingleByteCharSetProber(Win1251BulgarianModel), 57 | # TODO: Restore Hungarian encodings (iso-8859-2 and windows-1250) 58 | # after we retrain model. 59 | # SingleByteCharSetProber(Latin2HungarianModel), 60 | # SingleByteCharSetProber(Win1250HungarianModel), 61 | SingleByteCharSetProber(TIS620ThaiModel), 62 | SingleByteCharSetProber(Latin5TurkishModel), 63 | ] 64 | hebrew_prober = HebrewProber() 65 | logical_hebrew_prober = SingleByteCharSetProber(Win1255HebrewModel, 66 | False, hebrew_prober) 67 | visual_hebrew_prober = SingleByteCharSetProber(Win1255HebrewModel, True, 68 | hebrew_prober) 69 | hebrew_prober.set_model_probers(logical_hebrew_prober, visual_hebrew_prober) 70 | self.probers.extend([hebrew_prober, logical_hebrew_prober, 71 | visual_hebrew_prober]) 72 | 73 | self.reset() 74 | -------------------------------------------------------------------------------- /src/bin/website_monitoring_app/requests/packages/chardet/sjisprober.py: -------------------------------------------------------------------------------- 1 | ######################## BEGIN LICENSE BLOCK ######################## 2 | # The Original Code is mozilla.org code. 3 | # 4 | # The Initial Developer of the Original Code is 5 | # Netscape Communications Corporation. 6 | # Portions created by the Initial Developer are Copyright (C) 1998 7 | # the Initial Developer. All Rights Reserved. 8 | # 9 | # Contributor(s): 10 | # Mark Pilgrim - port to Python 11 | # 12 | # This library is free software; you can redistribute it and/or 13 | # modify it under the terms of the GNU Lesser General Public 14 | # License as published by the Free Software Foundation; either 15 | # version 2.1 of the License, or (at your option) any later version. 16 | # 17 | # This library is distributed in the hope that it will be useful, 18 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 19 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 20 | # Lesser General Public License for more details. 21 | # 22 | # You should have received a copy of the GNU Lesser General Public 23 | # License along with this library; if not, write to the Free Software 24 | # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 25 | # 02110-1301 USA 26 | ######################### END LICENSE BLOCK ######################### 27 | 28 | from .mbcharsetprober import MultiByteCharSetProber 29 | from .codingstatemachine import CodingStateMachine 30 | from .chardistribution import SJISDistributionAnalysis 31 | from .jpcntx import SJISContextAnalysis 32 | from .mbcssm import SJIS_SM_MODEL 33 | from .enums import ProbingState, MachineState 34 | 35 | 36 | class SJISProber(MultiByteCharSetProber): 37 | def __init__(self): 38 | super(SJISProber, self).__init__() 39 | self.coding_sm = CodingStateMachine(SJIS_SM_MODEL) 40 | self.distribution_analyzer = SJISDistributionAnalysis() 41 | self.context_analyzer = SJISContextAnalysis() 42 | self.reset() 43 | 44 | def reset(self): 45 | super(SJISProber, self).reset() 46 | self.context_analyzer.reset() 47 | 48 | @property 49 | def charset_name(self): 50 | return self.context_analyzer.charset_name 51 | 52 | @property 53 | def language(self): 54 | return "Japanese" 55 | 56 | def feed(self, byte_str): 57 | for i in range(len(byte_str)): 58 | coding_state = self.coding_sm.next_state(byte_str[i]) 59 | if coding_state == MachineState.ERROR: 60 | self.logger.debug('%s %s prober hit error at byte %s', 61 | self.charset_name, self.language, i) 62 | self._state = ProbingState.NOT_ME 63 | break 64 | elif coding_state == MachineState.ITS_ME: 65 | self._state = ProbingState.FOUND_IT 66 | break 67 | elif coding_state == MachineState.START: 68 | char_len = self.coding_sm.get_current_charlen() 69 | if i == 0: 70 | self._last_char[1] = byte_str[0] 71 | self.context_analyzer.feed(self._last_char[2 - char_len:], 72 | char_len) 73 | self.distribution_analyzer.feed(self._last_char, char_len) 74 | else: 75 | self.context_analyzer.feed(byte_str[i + 1 - char_len:i + 3 76 | - char_len], char_len) 77 | self.distribution_analyzer.feed(byte_str[i - 1:i + 1], 78 | char_len) 79 | 80 | self._last_char[0] = byte_str[-1] 81 | 82 | if self.state == ProbingState.DETECTING: 83 | if (self.context_analyzer.got_enough_data() and 84 | (self.get_confidence() > self.SHORTCUT_THRESHOLD)): 85 | self._state = ProbingState.FOUND_IT 86 | 87 | return self.state 88 | 89 | def get_confidence(self): 90 | context_conf = self.context_analyzer.get_confidence() 91 | distrib_conf = self.distribution_analyzer.get_confidence() 92 | return max(context_conf, distrib_conf) 93 | -------------------------------------------------------------------------------- /src/bin/website_monitoring_app/requests/packages/chardet/utf8prober.py: -------------------------------------------------------------------------------- 1 | ######################## BEGIN LICENSE BLOCK ######################## 2 | # The Original Code is mozilla.org code. 3 | # 4 | # The Initial Developer of the Original Code is 5 | # Netscape Communications Corporation. 6 | # Portions created by the Initial Developer are Copyright (C) 1998 7 | # the Initial Developer. All Rights Reserved. 8 | # 9 | # Contributor(s): 10 | # Mark Pilgrim - port to Python 11 | # 12 | # This library is free software; you can redistribute it and/or 13 | # modify it under the terms of the GNU Lesser General Public 14 | # License as published by the Free Software Foundation; either 15 | # version 2.1 of the License, or (at your option) any later version. 16 | # 17 | # This library is distributed in the hope that it will be useful, 18 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 19 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 20 | # Lesser General Public License for more details. 21 | # 22 | # You should have received a copy of the GNU Lesser General Public 23 | # License along with this library; if not, write to the Free Software 24 | # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 25 | # 02110-1301 USA 26 | ######################### END LICENSE BLOCK ######################### 27 | 28 | from .charsetprober import CharSetProber 29 | from .enums import ProbingState, MachineState 30 | from .codingstatemachine import CodingStateMachine 31 | from .mbcssm import UTF8_SM_MODEL 32 | 33 | 34 | 35 | class UTF8Prober(CharSetProber): 36 | ONE_CHAR_PROB = 0.5 37 | 38 | def __init__(self): 39 | super(UTF8Prober, self).__init__() 40 | self.coding_sm = CodingStateMachine(UTF8_SM_MODEL) 41 | self._num_mb_chars = None 42 | self.reset() 43 | 44 | def reset(self): 45 | super(UTF8Prober, self).reset() 46 | self.coding_sm.reset() 47 | self._num_mb_chars = 0 48 | 49 | @property 50 | def charset_name(self): 51 | return "utf-8" 52 | 53 | @property 54 | def language(self): 55 | return "" 56 | 57 | def feed(self, byte_str): 58 | for c in byte_str: 59 | coding_state = self.coding_sm.next_state(c) 60 | if coding_state == MachineState.ERROR: 61 | self._state = ProbingState.NOT_ME 62 | break 63 | elif coding_state == MachineState.ITS_ME: 64 | self._state = ProbingState.FOUND_IT 65 | break 66 | elif coding_state == MachineState.START: 67 | if self.coding_sm.get_current_charlen() >= 2: 68 | self._num_mb_chars += 1 69 | 70 | if self.state == ProbingState.DETECTING: 71 | if self.get_confidence() > self.SHORTCUT_THRESHOLD: 72 | self._state = ProbingState.FOUND_IT 73 | 74 | return self.state 75 | 76 | def get_confidence(self): 77 | unlike = 0.99 78 | if self._num_mb_chars < 6: 79 | unlike *= self.ONE_CHAR_PROB ** self._num_mb_chars 80 | return 1.0 - unlike 81 | else: 82 | return unlike 83 | -------------------------------------------------------------------------------- /src/bin/website_monitoring_app/requests/packages/chardet/version.py: -------------------------------------------------------------------------------- 1 | """ 2 | This module exists only to simplify retrieving the version number of chardet 3 | from within setup.py and from chardet subpackages. 4 | 5 | :author: Dan Blanchard (dan.blanchard@gmail.com) 6 | """ 7 | 8 | __version__ = "3.0.2" 9 | VERSION = __version__.split('.') 10 | -------------------------------------------------------------------------------- /src/bin/website_monitoring_app/requests/packages/idna/__init__.py: -------------------------------------------------------------------------------- 1 | from .core import * 2 | -------------------------------------------------------------------------------- /src/bin/website_monitoring_app/requests/packages/idna/codec.py: -------------------------------------------------------------------------------- 1 | from .core import encode, decode, alabel, ulabel, IDNAError 2 | import codecs 3 | import re 4 | 5 | _unicode_dots_re = re.compile(u'[\u002e\u3002\uff0e\uff61]') 6 | 7 | class Codec(codecs.Codec): 8 | 9 | def encode(self, data, errors='strict'): 10 | 11 | if errors != 'strict': 12 | raise IDNAError("Unsupported error handling \"{0}\"".format(errors)) 13 | 14 | if not data: 15 | return "", 0 16 | 17 | return encode(data), len(data) 18 | 19 | def decode(self, data, errors='strict'): 20 | 21 | if errors != 'strict': 22 | raise IDNAError("Unsupported error handling \"{0}\"".format(errors)) 23 | 24 | if not data: 25 | return u"", 0 26 | 27 | return decode(data), len(data) 28 | 29 | class IncrementalEncoder(codecs.BufferedIncrementalEncoder): 30 | def _buffer_encode(self, data, errors, final): 31 | if errors != 'strict': 32 | raise IDNAError("Unsupported error handling \"{0}\"".format(errors)) 33 | 34 | if not data: 35 | return ("", 0) 36 | 37 | labels = _unicode_dots_re.split(data) 38 | trailing_dot = u'' 39 | if labels: 40 | if not labels[-1]: 41 | trailing_dot = '.' 42 | del labels[-1] 43 | elif not final: 44 | # Keep potentially unfinished label until the next call 45 | del labels[-1] 46 | if labels: 47 | trailing_dot = '.' 48 | 49 | result = [] 50 | size = 0 51 | for label in labels: 52 | result.append(alabel(label)) 53 | if size: 54 | size += 1 55 | size += len(label) 56 | 57 | # Join with U+002E 58 | result = ".".join(result) + trailing_dot 59 | size += len(trailing_dot) 60 | return (result, size) 61 | 62 | class IncrementalDecoder(codecs.BufferedIncrementalDecoder): 63 | def _buffer_decode(self, data, errors, final): 64 | if errors != 'strict': 65 | raise IDNAError("Unsupported error handling \"{0}\"".format(errors)) 66 | 67 | if not data: 68 | return (u"", 0) 69 | 70 | # IDNA allows decoding to operate on Unicode strings, too. 71 | if isinstance(data, unicode): 72 | labels = _unicode_dots_re.split(data) 73 | else: 74 | # Must be ASCII string 75 | data = str(data) 76 | unicode(data, "ascii") 77 | labels = data.split(".") 78 | 79 | trailing_dot = u'' 80 | if labels: 81 | if not labels[-1]: 82 | trailing_dot = u'.' 83 | del labels[-1] 84 | elif not final: 85 | # Keep potentially unfinished label until the next call 86 | del labels[-1] 87 | if labels: 88 | trailing_dot = u'.' 89 | 90 | result = [] 91 | size = 0 92 | for label in labels: 93 | result.append(ulabel(label)) 94 | if size: 95 | size += 1 96 | size += len(label) 97 | 98 | result = u".".join(result) + trailing_dot 99 | size += len(trailing_dot) 100 | return (result, size) 101 | 102 | 103 | class StreamWriter(Codec, codecs.StreamWriter): 104 | pass 105 | 106 | class StreamReader(Codec, codecs.StreamReader): 107 | pass 108 | 109 | def getregentry(): 110 | return codecs.CodecInfo( 111 | name='idna', 112 | encode=Codec().encode, 113 | decode=Codec().decode, 114 | incrementalencoder=IncrementalEncoder, 115 | incrementaldecoder=IncrementalDecoder, 116 | streamwriter=StreamWriter, 117 | streamreader=StreamReader, 118 | ) 119 | -------------------------------------------------------------------------------- /src/bin/website_monitoring_app/requests/packages/idna/compat.py: -------------------------------------------------------------------------------- 1 | from .core import * 2 | from .codec import * 3 | 4 | def ToASCII(label): 5 | return encode(label) 6 | 7 | def ToUnicode(label): 8 | return decode(label) 9 | 10 | def nameprep(s): 11 | raise NotImplementedError("IDNA 2008 does not utilise nameprep protocol") 12 | 13 | -------------------------------------------------------------------------------- /src/bin/website_monitoring_app/requests/packages/idna/intranges.py: -------------------------------------------------------------------------------- 1 | """ 2 | Given a list of integers, made up of (hopefully) a small number of long runs 3 | of consecutive integers, compute a representation of the form 4 | ((start1, end1), (start2, end2) ...). Then answer the question "was x present 5 | in the original list?" in time O(log(# runs)). 6 | """ 7 | 8 | import bisect 9 | 10 | def intranges_from_list(list_): 11 | """Represent a list of integers as a sequence of ranges: 12 | ((start_0, end_0), (start_1, end_1), ...), such that the original 13 | integers are exactly those x such that start_i <= x < end_i for some i. 14 | 15 | Ranges are encoded as single integers (start << 32 | end), not as tuples. 16 | """ 17 | 18 | sorted_list = sorted(list_) 19 | ranges = [] 20 | last_write = -1 21 | for i in range(len(sorted_list)): 22 | if i+1 < len(sorted_list): 23 | if sorted_list[i] == sorted_list[i+1]-1: 24 | continue 25 | current_range = sorted_list[last_write+1:i+1] 26 | ranges.append(_encode_range(current_range[0], current_range[-1] + 1)) 27 | last_write = i 28 | 29 | return tuple(ranges) 30 | 31 | def _encode_range(start, end): 32 | return (start << 32) | end 33 | 34 | def _decode_range(r): 35 | return (r >> 32), (r & ((1 << 32) - 1)) 36 | 37 | 38 | def intranges_contain(int_, ranges): 39 | """Determine if `int_` falls into one of the ranges in `ranges`.""" 40 | tuple_ = _encode_range(int_, 0) 41 | pos = bisect.bisect_left(ranges, tuple_) 42 | # we could be immediately ahead of a tuple (start, end) 43 | # with start < int_ <= end 44 | if pos > 0: 45 | left, right = _decode_range(ranges[pos-1]) 46 | if left <= int_ < right: 47 | return True 48 | # or we could be immediately behind a tuple (int_, end) 49 | if pos < len(ranges): 50 | left, _ = _decode_range(ranges[pos]) 51 | if left == int_: 52 | return True 53 | return False 54 | -------------------------------------------------------------------------------- /src/bin/website_monitoring_app/requests/packages/urllib3/__init__.py: -------------------------------------------------------------------------------- 1 | """ 2 | urllib3 - Thread-safe connection pooling and re-using. 3 | """ 4 | 5 | from __future__ import absolute_import 6 | import warnings 7 | 8 | from .connectionpool import ( 9 | HTTPConnectionPool, 10 | HTTPSConnectionPool, 11 | connection_from_url 12 | ) 13 | 14 | from . import exceptions 15 | from .filepost import encode_multipart_formdata 16 | from .poolmanager import PoolManager, ProxyManager, proxy_from_url 17 | from .response import HTTPResponse 18 | from .util.request import make_headers 19 | from .util.url import get_host 20 | from .util.timeout import Timeout 21 | from .util.retry import Retry 22 | 23 | 24 | # Set default logging handler to avoid "No handler found" warnings. 25 | import logging 26 | try: # Python 2.7+ 27 | from logging import NullHandler 28 | except ImportError: 29 | class NullHandler(logging.Handler): 30 | def emit(self, record): 31 | pass 32 | 33 | __author__ = 'Andrey Petrov (andrey.petrov@shazow.net)' 34 | __license__ = 'MIT' 35 | __version__ = '1.21.1' 36 | 37 | __all__ = ( 38 | 'HTTPConnectionPool', 39 | 'HTTPSConnectionPool', 40 | 'PoolManager', 41 | 'ProxyManager', 42 | 'HTTPResponse', 43 | 'Retry', 44 | 'Timeout', 45 | 'add_stderr_logger', 46 | 'connection_from_url', 47 | 'disable_warnings', 48 | 'encode_multipart_formdata', 49 | 'get_host', 50 | 'make_headers', 51 | 'proxy_from_url', 52 | ) 53 | 54 | logging.getLogger(__name__).addHandler(NullHandler()) 55 | 56 | 57 | def add_stderr_logger(level=logging.DEBUG): 58 | """ 59 | Helper for quickly adding a StreamHandler to the logger. Useful for 60 | debugging. 61 | 62 | Returns the handler after adding it. 63 | """ 64 | # This method needs to be in this __init__.py to get the __name__ correct 65 | # even if urllib3 is vendored within another package. 66 | logger = logging.getLogger(__name__) 67 | handler = logging.StreamHandler() 68 | handler.setFormatter(logging.Formatter('%(asctime)s %(levelname)s %(message)s')) 69 | logger.addHandler(handler) 70 | logger.setLevel(level) 71 | logger.debug('Added a stderr logging handler to logger: %s', __name__) 72 | return handler 73 | 74 | 75 | # ... Clean up. 76 | del NullHandler 77 | 78 | 79 | # All warning filters *must* be appended unless you're really certain that they 80 | # shouldn't be: otherwise, it's very hard for users to use most Python 81 | # mechanisms to silence them. 82 | # SecurityWarning's always go off by default. 83 | warnings.simplefilter('always', exceptions.SecurityWarning, append=True) 84 | # SubjectAltNameWarning's should go off once per host 85 | warnings.simplefilter('default', exceptions.SubjectAltNameWarning, append=True) 86 | # InsecurePlatformWarning's don't vary between requests, so we keep it default. 87 | warnings.simplefilter('default', exceptions.InsecurePlatformWarning, 88 | append=True) 89 | # SNIMissingWarnings should go off only once. 90 | warnings.simplefilter('default', exceptions.SNIMissingWarning, append=True) 91 | 92 | 93 | def disable_warnings(category=exceptions.HTTPWarning): 94 | """ 95 | Helper for quickly disabling all urllib3 warnings. 96 | """ 97 | warnings.simplefilter('ignore', category) 98 | -------------------------------------------------------------------------------- /src/bin/website_monitoring_app/requests/packages/urllib3/contrib/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LukeMurphey/splunk-website-monitoring/442d08de5bbfed4a879de3b537eae0361de8e473/src/bin/website_monitoring_app/requests/packages/urllib3/contrib/__init__.py -------------------------------------------------------------------------------- /src/bin/website_monitoring_app/requests/packages/urllib3/contrib/_securetransport/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LukeMurphey/splunk-website-monitoring/442d08de5bbfed4a879de3b537eae0361de8e473/src/bin/website_monitoring_app/requests/packages/urllib3/contrib/_securetransport/__init__.py -------------------------------------------------------------------------------- /src/bin/website_monitoring_app/requests/packages/urllib3/filepost.py: -------------------------------------------------------------------------------- 1 | from __future__ import absolute_import 2 | import codecs 3 | 4 | from uuid import uuid4 5 | from io import BytesIO 6 | 7 | from .packages import six 8 | from .packages.six import b 9 | from .fields import RequestField 10 | 11 | writer = codecs.lookup('utf-8')[3] 12 | 13 | 14 | def choose_boundary(): 15 | """ 16 | Our embarrassingly-simple replacement for mimetools.choose_boundary. 17 | """ 18 | return uuid4().hex 19 | 20 | 21 | def iter_field_objects(fields): 22 | """ 23 | Iterate over fields. 24 | 25 | Supports list of (k, v) tuples and dicts, and lists of 26 | :class:`~urllib3.fields.RequestField`. 27 | 28 | """ 29 | if isinstance(fields, dict): 30 | i = six.iteritems(fields) 31 | else: 32 | i = iter(fields) 33 | 34 | for field in i: 35 | if isinstance(field, RequestField): 36 | yield field 37 | else: 38 | yield RequestField.from_tuples(*field) 39 | 40 | 41 | def iter_fields(fields): 42 | """ 43 | .. deprecated:: 1.6 44 | 45 | Iterate over fields. 46 | 47 | The addition of :class:`~urllib3.fields.RequestField` makes this function 48 | obsolete. Instead, use :func:`iter_field_objects`, which returns 49 | :class:`~urllib3.fields.RequestField` objects. 50 | 51 | Supports list of (k, v) tuples and dicts. 52 | """ 53 | if isinstance(fields, dict): 54 | return ((k, v) for k, v in six.iteritems(fields)) 55 | 56 | return ((k, v) for k, v in fields) 57 | 58 | 59 | def encode_multipart_formdata(fields, boundary=None): 60 | """ 61 | Encode a dictionary of ``fields`` using the multipart/form-data MIME format. 62 | 63 | :param fields: 64 | Dictionary of fields or list of (key, :class:`~urllib3.fields.RequestField`). 65 | 66 | :param boundary: 67 | If not specified, then a random boundary will be generated using 68 | :func:`mimetools.choose_boundary`. 69 | """ 70 | body = BytesIO() 71 | if boundary is None: 72 | boundary = choose_boundary() 73 | 74 | for field in iter_field_objects(fields): 75 | body.write(b('--%s\r\n' % (boundary))) 76 | 77 | writer(body).write(field.render_headers()) 78 | data = field.data 79 | 80 | if isinstance(data, int): 81 | data = str(data) # Backwards compatibility 82 | 83 | if isinstance(data, six.text_type): 84 | writer(body).write(data) 85 | else: 86 | body.write(data) 87 | 88 | body.write(b'\r\n') 89 | 90 | body.write(b('--%s--\r\n' % (boundary))) 91 | 92 | content_type = str('multipart/form-data; boundary=%s' % boundary) 93 | 94 | return body.getvalue(), content_type 95 | -------------------------------------------------------------------------------- /src/bin/website_monitoring_app/requests/packages/urllib3/packages/__init__.py: -------------------------------------------------------------------------------- 1 | from __future__ import absolute_import 2 | 3 | from . import ssl_match_hostname 4 | 5 | __all__ = ('ssl_match_hostname', ) 6 | -------------------------------------------------------------------------------- /src/bin/website_monitoring_app/requests/packages/urllib3/packages/backports/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LukeMurphey/splunk-website-monitoring/442d08de5bbfed4a879de3b537eae0361de8e473/src/bin/website_monitoring_app/requests/packages/urllib3/packages/backports/__init__.py -------------------------------------------------------------------------------- /src/bin/website_monitoring_app/requests/packages/urllib3/packages/backports/makefile.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """ 3 | backports.makefile 4 | ~~~~~~~~~~~~~~~~~~ 5 | 6 | Backports the Python 3 ``socket.makefile`` method for use with anything that 7 | wants to create a "fake" socket object. 8 | """ 9 | import io 10 | 11 | from socket import SocketIO 12 | 13 | 14 | def backport_makefile(self, mode="r", buffering=None, encoding=None, 15 | errors=None, newline=None): 16 | """ 17 | Backport of ``socket.makefile`` from Python 3.5. 18 | """ 19 | if not set(mode) <= set(["r", "w", "b"]): 20 | raise ValueError( 21 | "invalid mode %r (only r, w, b allowed)" % (mode,) 22 | ) 23 | writing = "w" in mode 24 | reading = "r" in mode or not writing 25 | assert reading or writing 26 | binary = "b" in mode 27 | rawmode = "" 28 | if reading: 29 | rawmode += "r" 30 | if writing: 31 | rawmode += "w" 32 | raw = SocketIO(self, rawmode) 33 | self._makefile_refs += 1 34 | if buffering is None: 35 | buffering = -1 36 | if buffering < 0: 37 | buffering = io.DEFAULT_BUFFER_SIZE 38 | if buffering == 0: 39 | if not binary: 40 | raise ValueError("unbuffered streams must be binary") 41 | return raw 42 | if reading and writing: 43 | buffer = io.BufferedRWPair(raw, raw, buffering) 44 | elif reading: 45 | buffer = io.BufferedReader(raw, buffering) 46 | else: 47 | assert writing 48 | buffer = io.BufferedWriter(raw, buffering) 49 | if binary: 50 | return buffer 51 | text = io.TextIOWrapper(buffer, encoding, errors, newline) 52 | text.mode = mode 53 | return text 54 | -------------------------------------------------------------------------------- /src/bin/website_monitoring_app/requests/packages/urllib3/packages/ssl_match_hostname/__init__.py: -------------------------------------------------------------------------------- 1 | import sys 2 | 3 | try: 4 | # Our match_hostname function is the same as 3.5's, so we only want to 5 | # import the match_hostname function if it's at least that good. 6 | if sys.version_info < (3, 5): 7 | raise ImportError("Fallback to vendored code") 8 | 9 | from ssl import CertificateError, match_hostname 10 | except ImportError: 11 | try: 12 | # Backport of the function from a pypi module 13 | from backports.ssl_match_hostname import CertificateError, match_hostname 14 | except ImportError: 15 | # Our vendored copy 16 | from ._implementation import CertificateError, match_hostname 17 | 18 | # Not needed, but documenting what we provide. 19 | __all__ = ('CertificateError', 'match_hostname') 20 | -------------------------------------------------------------------------------- /src/bin/website_monitoring_app/requests/packages/urllib3/util/__init__.py: -------------------------------------------------------------------------------- 1 | from __future__ import absolute_import 2 | # For backwards compatibility, provide imports that used to be here. 3 | from .connection import is_connection_dropped 4 | from .request import make_headers 5 | from .response import is_fp_closed 6 | from .ssl_ import ( 7 | SSLContext, 8 | HAS_SNI, 9 | IS_PYOPENSSL, 10 | IS_SECURETRANSPORT, 11 | assert_fingerprint, 12 | resolve_cert_reqs, 13 | resolve_ssl_version, 14 | ssl_wrap_socket, 15 | ) 16 | from .timeout import ( 17 | current_time, 18 | Timeout, 19 | ) 20 | 21 | from .retry import Retry 22 | from .url import ( 23 | get_host, 24 | parse_url, 25 | split_first, 26 | Url, 27 | ) 28 | from .wait import ( 29 | wait_for_read, 30 | wait_for_write 31 | ) 32 | 33 | __all__ = ( 34 | 'HAS_SNI', 35 | 'IS_PYOPENSSL', 36 | 'IS_SECURETRANSPORT', 37 | 'SSLContext', 38 | 'Retry', 39 | 'Timeout', 40 | 'Url', 41 | 'assert_fingerprint', 42 | 'current_time', 43 | 'is_connection_dropped', 44 | 'is_fp_closed', 45 | 'get_host', 46 | 'parse_url', 47 | 'make_headers', 48 | 'resolve_cert_reqs', 49 | 'resolve_ssl_version', 50 | 'split_first', 51 | 'ssl_wrap_socket', 52 | 'wait_for_read', 53 | 'wait_for_write' 54 | ) 55 | -------------------------------------------------------------------------------- /src/bin/website_monitoring_app/requests/packages/urllib3/util/request.py: -------------------------------------------------------------------------------- 1 | from __future__ import absolute_import 2 | from base64 import b64encode 3 | 4 | from ..packages.six import b, integer_types 5 | from ..exceptions import UnrewindableBodyError 6 | 7 | ACCEPT_ENCODING = 'gzip,deflate' 8 | _FAILEDTELL = object() 9 | 10 | 11 | def make_headers(keep_alive=None, accept_encoding=None, user_agent=None, 12 | basic_auth=None, proxy_basic_auth=None, disable_cache=None): 13 | """ 14 | Shortcuts for generating request headers. 15 | 16 | :param keep_alive: 17 | If ``True``, adds 'connection: keep-alive' header. 18 | 19 | :param accept_encoding: 20 | Can be a boolean, list, or string. 21 | ``True`` translates to 'gzip,deflate'. 22 | List will get joined by comma. 23 | String will be used as provided. 24 | 25 | :param user_agent: 26 | String representing the user-agent you want, such as 27 | "python-urllib3/0.6" 28 | 29 | :param basic_auth: 30 | Colon-separated username:password string for 'authorization: basic ...' 31 | auth header. 32 | 33 | :param proxy_basic_auth: 34 | Colon-separated username:password string for 'proxy-authorization: basic ...' 35 | auth header. 36 | 37 | :param disable_cache: 38 | If ``True``, adds 'cache-control: no-cache' header. 39 | 40 | Example:: 41 | 42 | >>> make_headers(keep_alive=True, user_agent="Batman/1.0") 43 | {'connection': 'keep-alive', 'user-agent': 'Batman/1.0'} 44 | >>> make_headers(accept_encoding=True) 45 | {'accept-encoding': 'gzip,deflate'} 46 | """ 47 | headers = {} 48 | if accept_encoding: 49 | if isinstance(accept_encoding, str): 50 | pass 51 | elif isinstance(accept_encoding, list): 52 | accept_encoding = ','.join(accept_encoding) 53 | else: 54 | accept_encoding = ACCEPT_ENCODING 55 | headers['accept-encoding'] = accept_encoding 56 | 57 | if user_agent: 58 | headers['user-agent'] = user_agent 59 | 60 | if keep_alive: 61 | headers['connection'] = 'keep-alive' 62 | 63 | if basic_auth: 64 | headers['authorization'] = 'Basic ' + \ 65 | b64encode(b(basic_auth)).decode('utf-8') 66 | 67 | if proxy_basic_auth: 68 | headers['proxy-authorization'] = 'Basic ' + \ 69 | b64encode(b(proxy_basic_auth)).decode('utf-8') 70 | 71 | if disable_cache: 72 | headers['cache-control'] = 'no-cache' 73 | 74 | return headers 75 | 76 | 77 | def set_file_position(body, pos): 78 | """ 79 | If a position is provided, move file to that point. 80 | Otherwise, we'll attempt to record a position for future use. 81 | """ 82 | if pos is not None: 83 | rewind_body(body, pos) 84 | elif getattr(body, 'tell', None) is not None: 85 | try: 86 | pos = body.tell() 87 | except (IOError, OSError): 88 | # This differentiates from None, allowing us to catch 89 | # a failed `tell()` later when trying to rewind the body. 90 | pos = _FAILEDTELL 91 | 92 | return pos 93 | 94 | 95 | def rewind_body(body, body_pos): 96 | """ 97 | Attempt to rewind body to a certain position. 98 | Primarily used for request redirects and retries. 99 | 100 | :param body: 101 | File-like object that supports seek. 102 | 103 | :param int pos: 104 | Position to seek to in file. 105 | """ 106 | body_seek = getattr(body, 'seek', None) 107 | if body_seek is not None and isinstance(body_pos, integer_types): 108 | try: 109 | body_seek(body_pos) 110 | except (IOError, OSError): 111 | raise UnrewindableBodyError("An error occurred when rewinding request " 112 | "body for redirect/retry.") 113 | elif body_pos is _FAILEDTELL: 114 | raise UnrewindableBodyError("Unable to record file position for rewinding " 115 | "request body during a redirect/retry.") 116 | else: 117 | raise ValueError("body_pos must be of type integer, " 118 | "instead it was %s." % type(body_pos)) 119 | -------------------------------------------------------------------------------- /src/bin/website_monitoring_app/requests/packages/urllib3/util/response.py: -------------------------------------------------------------------------------- 1 | from __future__ import absolute_import 2 | from ..packages.six.moves import http_client as httplib 3 | 4 | from ..exceptions import HeaderParsingError 5 | 6 | 7 | def is_fp_closed(obj): 8 | """ 9 | Checks whether a given file-like object is closed. 10 | 11 | :param obj: 12 | The file-like object to check. 13 | """ 14 | 15 | try: 16 | # Check `isclosed()` first, in case Python3 doesn't set `closed`. 17 | # GH Issue #928 18 | return obj.isclosed() 19 | except AttributeError: 20 | pass 21 | 22 | try: 23 | # Check via the official file-like-object way. 24 | return obj.closed 25 | except AttributeError: 26 | pass 27 | 28 | try: 29 | # Check if the object is a container for another file-like object that 30 | # gets released on exhaustion (e.g. HTTPResponse). 31 | return obj.fp is None 32 | except AttributeError: 33 | pass 34 | 35 | raise ValueError("Unable to determine whether fp is closed.") 36 | 37 | 38 | def assert_header_parsing(headers): 39 | """ 40 | Asserts whether all headers have been successfully parsed. 41 | Extracts encountered errors from the result of parsing headers. 42 | 43 | Only works on Python 3. 44 | 45 | :param headers: Headers to verify. 46 | :type headers: `httplib.HTTPMessage`. 47 | 48 | :raises urllib3.exceptions.HeaderParsingError: 49 | If parsing errors are found. 50 | """ 51 | 52 | # This will fail silently if we pass in the wrong kind of parameter. 53 | # To make debugging easier add an explicit check. 54 | if not isinstance(headers, httplib.HTTPMessage): 55 | raise TypeError('expected httplib.Message, got {0}.'.format( 56 | type(headers))) 57 | 58 | defects = getattr(headers, 'defects', None) 59 | get_payload = getattr(headers, 'get_payload', None) 60 | 61 | unparsed_data = None 62 | if get_payload: # Platform-specific: Python 3. 63 | unparsed_data = get_payload() 64 | 65 | if defects or unparsed_data: 66 | raise HeaderParsingError(defects=defects, unparsed_data=unparsed_data) 67 | 68 | 69 | def is_response_to_head(response): 70 | """ 71 | Checks whether the request of a response has been a HEAD-request. 72 | Handles the quirks of AppEngine. 73 | 74 | :param conn: 75 | :type conn: :class:`httplib.HTTPResponse` 76 | """ 77 | # FIXME: Can we do this somehow without accessing private httplib _method? 78 | method = response._method 79 | if isinstance(method, int): # Platform-specific: Appengine 80 | return method == 3 81 | return method.upper() == 'HEAD' 82 | -------------------------------------------------------------------------------- /src/bin/website_monitoring_app/requests/packages/urllib3/util/wait.py: -------------------------------------------------------------------------------- 1 | from .selectors import ( 2 | HAS_SELECT, 3 | DefaultSelector, 4 | EVENT_READ, 5 | EVENT_WRITE 6 | ) 7 | 8 | 9 | def _wait_for_io_events(socks, events, timeout=None): 10 | """ Waits for IO events to be available from a list of sockets 11 | or optionally a single socket if passed in. Returns a list of 12 | sockets that can be interacted with immediately. """ 13 | if not HAS_SELECT: 14 | raise ValueError('Platform does not have a selector') 15 | if not isinstance(socks, list): 16 | # Probably just a single socket. 17 | if hasattr(socks, "fileno"): 18 | socks = [socks] 19 | # Otherwise it might be a non-list iterable. 20 | else: 21 | socks = list(socks) 22 | with DefaultSelector() as selector: 23 | for sock in socks: 24 | selector.register(sock, events) 25 | return [key[0].fileobj for key in 26 | selector.select(timeout) if key[1] & events] 27 | 28 | 29 | def wait_for_read(socks, timeout=None): 30 | """ Waits for reading to be available from a list of sockets 31 | or optionally a single socket if passed in. Returns a list of 32 | sockets that can be read from immediately. """ 33 | return _wait_for_io_events(socks, EVENT_READ, timeout) 34 | 35 | 36 | def wait_for_write(socks, timeout=None): 37 | """ Waits for writing to be available from a list of sockets 38 | or optionally a single socket if passed in. Returns a list of 39 | sockets that can be written to immediately. """ 40 | return _wait_for_io_events(socks, EVENT_WRITE, timeout) 41 | -------------------------------------------------------------------------------- /src/bin/website_monitoring_app/requests/status_codes.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | from .structures import LookupDict 4 | 5 | _codes = { 6 | 7 | # Informational. 8 | 100: ('continue',), 9 | 101: ('switching_protocols',), 10 | 102: ('processing',), 11 | 103: ('checkpoint',), 12 | 122: ('uri_too_long', 'request_uri_too_long'), 13 | 200: ('ok', 'okay', 'all_ok', 'all_okay', 'all_good', '\\o/', '✓'), 14 | 201: ('created',), 15 | 202: ('accepted',), 16 | 203: ('non_authoritative_info', 'non_authoritative_information'), 17 | 204: ('no_content',), 18 | 205: ('reset_content', 'reset'), 19 | 206: ('partial_content', 'partial'), 20 | 207: ('multi_status', 'multiple_status', 'multi_stati', 'multiple_stati'), 21 | 208: ('already_reported',), 22 | 226: ('im_used',), 23 | 24 | # Redirection. 25 | 300: ('multiple_choices',), 26 | 301: ('moved_permanently', 'moved', '\\o-'), 27 | 302: ('found',), 28 | 303: ('see_other', 'other'), 29 | 304: ('not_modified',), 30 | 305: ('use_proxy',), 31 | 306: ('switch_proxy',), 32 | 307: ('temporary_redirect', 'temporary_moved', 'temporary'), 33 | 308: ('permanent_redirect', 34 | 'resume_incomplete', 'resume',), # These 2 to be removed in 3.0 35 | 36 | # Client Error. 37 | 400: ('bad_request', 'bad'), 38 | 401: ('unauthorized',), 39 | 402: ('payment_required', 'payment'), 40 | 403: ('forbidden',), 41 | 404: ('not_found', '-o-'), 42 | 405: ('method_not_allowed', 'not_allowed'), 43 | 406: ('not_acceptable',), 44 | 407: ('proxy_authentication_required', 'proxy_auth', 'proxy_authentication'), 45 | 408: ('request_timeout', 'timeout'), 46 | 409: ('conflict',), 47 | 410: ('gone',), 48 | 411: ('length_required',), 49 | 412: ('precondition_failed', 'precondition'), 50 | 413: ('request_entity_too_large',), 51 | 414: ('request_uri_too_large',), 52 | 415: ('unsupported_media_type', 'unsupported_media', 'media_type'), 53 | 416: ('requested_range_not_satisfiable', 'requested_range', 'range_not_satisfiable'), 54 | 417: ('expectation_failed',), 55 | 418: ('im_a_teapot', 'teapot', 'i_am_a_teapot'), 56 | 421: ('misdirected_request',), 57 | 422: ('unprocessable_entity', 'unprocessable'), 58 | 423: ('locked',), 59 | 424: ('failed_dependency', 'dependency'), 60 | 425: ('unordered_collection', 'unordered'), 61 | 426: ('upgrade_required', 'upgrade'), 62 | 428: ('precondition_required', 'precondition'), 63 | 429: ('too_many_requests', 'too_many'), 64 | 431: ('header_fields_too_large', 'fields_too_large'), 65 | 444: ('no_response', 'none'), 66 | 449: ('retry_with', 'retry'), 67 | 450: ('blocked_by_windows_parental_controls', 'parental_controls'), 68 | 451: ('unavailable_for_legal_reasons', 'legal_reasons'), 69 | 499: ('client_closed_request',), 70 | 71 | # Server Error. 72 | 500: ('internal_server_error', 'server_error', '/o\\', '✗'), 73 | 501: ('not_implemented',), 74 | 502: ('bad_gateway',), 75 | 503: ('service_unavailable', 'unavailable'), 76 | 504: ('gateway_timeout',), 77 | 505: ('http_version_not_supported', 'http_version'), 78 | 506: ('variant_also_negotiates',), 79 | 507: ('insufficient_storage',), 80 | 509: ('bandwidth_limit_exceeded', 'bandwidth'), 81 | 510: ('not_extended',), 82 | 511: ('network_authentication_required', 'network_auth', 'network_authentication'), 83 | } 84 | 85 | codes = LookupDict(name='status_codes') 86 | 87 | for code, titles in _codes.items(): 88 | for title in titles: 89 | setattr(codes, title, code) 90 | if not title.startswith(('\\', '/')): 91 | setattr(codes, title.upper(), code) 92 | -------------------------------------------------------------------------------- /src/bin/website_monitoring_app/requests/structures.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | """ 4 | requests.structures 5 | ~~~~~~~~~~~~~~~~~~~ 6 | 7 | Data structures that power Requests. 8 | """ 9 | 10 | import collections 11 | 12 | from .compat import OrderedDict 13 | 14 | 15 | class CaseInsensitiveDict(collections.MutableMapping): 16 | """A case-insensitive ``dict``-like object. 17 | 18 | Implements all methods and operations of 19 | ``collections.MutableMapping`` as well as dict's ``copy``. Also 20 | provides ``lower_items``. 21 | 22 | All keys are expected to be strings. The structure remembers the 23 | case of the last key to be set, and ``iter(instance)``, 24 | ``keys()``, ``items()``, ``iterkeys()``, and ``iteritems()`` 25 | will contain case-sensitive keys. However, querying and contains 26 | testing is case insensitive:: 27 | 28 | cid = CaseInsensitiveDict() 29 | cid['Accept'] = 'application/json' 30 | cid['aCCEPT'] == 'application/json' # True 31 | list(cid) == ['Accept'] # True 32 | 33 | For example, ``headers['content-encoding']`` will return the 34 | value of a ``'Content-Encoding'`` response header, regardless 35 | of how the header name was originally stored. 36 | 37 | If the constructor, ``.update``, or equality comparison 38 | operations are given keys that have equal ``.lower()``s, the 39 | behavior is undefined. 40 | """ 41 | 42 | def __init__(self, data=None, **kwargs): 43 | self._store = OrderedDict() 44 | if data is None: 45 | data = {} 46 | self.update(data, **kwargs) 47 | 48 | def __setitem__(self, key, value): 49 | # Use the lowercased key for lookups, but store the actual 50 | # key alongside the value. 51 | self._store[key.lower()] = (key, value) 52 | 53 | def __getitem__(self, key): 54 | return self._store[key.lower()][1] 55 | 56 | def __delitem__(self, key): 57 | del self._store[key.lower()] 58 | 59 | def __iter__(self): 60 | return (casedkey for casedkey, mappedvalue in self._store.values()) 61 | 62 | def __len__(self): 63 | return len(self._store) 64 | 65 | def lower_items(self): 66 | """Like iteritems(), but with all lowercase keys.""" 67 | return ( 68 | (lowerkey, keyval[1]) 69 | for (lowerkey, keyval) 70 | in self._store.items() 71 | ) 72 | 73 | def __eq__(self, other): 74 | if isinstance(other, collections.Mapping): 75 | other = CaseInsensitiveDict(other) 76 | else: 77 | return NotImplemented 78 | # Compare insensitively 79 | return dict(self.lower_items()) == dict(other.lower_items()) 80 | 81 | # Copy is required 82 | def copy(self): 83 | return CaseInsensitiveDict(self._store.values()) 84 | 85 | def __repr__(self): 86 | return str(dict(self.items())) 87 | 88 | 89 | class LookupDict(dict): 90 | """Dictionary lookup object.""" 91 | 92 | def __init__(self, name=None): 93 | self.name = name 94 | super(LookupDict, self).__init__() 95 | 96 | def __repr__(self): 97 | return '' % (self.name) 98 | 99 | def __getitem__(self, key): 100 | # We allow fall-through here, so values default to None 101 | 102 | return self.__dict__.get(key, None) 103 | 104 | def get(self, key, default=None): 105 | return self.__dict__.get(key, default) 106 | -------------------------------------------------------------------------------- /src/bin/website_monitoring_app/requests_ntlm/__init__.py: -------------------------------------------------------------------------------- 1 | from .requests_ntlm import HttpNtlmAuth 2 | 3 | __all__ = ('HttpNtlmAuth',) 4 | -------------------------------------------------------------------------------- /src/bin/website_monitoring_app/sortedcontainers/__init__.py: -------------------------------------------------------------------------------- 1 | """Sorted Containers -- Sorted List, Sorted Dict, Sorted Set 2 | 3 | Sorted Containers is an Apache2 licensed containers library, written in 4 | pure-Python, and fast as C-extensions. 5 | 6 | Python's standard library is great until you need a sorted collections 7 | type. Many will attest that you can get really far without one, but the moment 8 | you **really need** a sorted list, dict, or set, you're faced with a dozen 9 | different implementations, most using C-extensions without great documentation 10 | and benchmarking. 11 | 12 | In Python, we can do better. And we can do it in pure-Python! 13 | 14 | :: 15 | 16 | >>> from sortedcontainers import SortedList 17 | >>> sl = SortedList(['e', 'a', 'c', 'd', 'b']) 18 | >>> sl 19 | SortedList(['a', 'b', 'c', 'd', 'e']) 20 | >>> sl *= 1000000 21 | >>> sl.count('c') 22 | 1000000 23 | >>> sl[-3:] 24 | ['e', 'e', 'e'] 25 | >>> from sortedcontainers import SortedDict 26 | >>> sd = SortedDict({'c': 3, 'a': 1, 'b': 2}) 27 | >>> sd 28 | SortedDict({'a': 1, 'b': 2, 'c': 3}) 29 | >>> sd.popitem(index=-1) 30 | ('c', 3) 31 | >>> from sortedcontainers import SortedSet 32 | >>> ss = SortedSet('abracadabra') 33 | >>> ss 34 | SortedSet(['a', 'b', 'c', 'd', 'r']) 35 | >>> ss.bisect_left('c') 36 | 2 37 | 38 | Sorted Containers takes all of the work out of Python sorted types - making 39 | your deployment and use of Python easy. There's no need to install a C compiler 40 | or pre-build and distribute custom extensions. Performance is a feature and 41 | testing has 100% coverage with unit tests and hours of stress. 42 | 43 | :copyright: (c) 2014-2018 by Grant Jenks. 44 | :license: Apache 2.0, see LICENSE for more details. 45 | 46 | """ 47 | 48 | 49 | from .sortedlist import SortedList, SortedKeyList, SortedListWithKey 50 | from .sortedset import SortedSet 51 | from .sorteddict import ( 52 | SortedDict, 53 | SortedKeysView, 54 | SortedItemsView, 55 | SortedValuesView, 56 | ) 57 | 58 | __all__ = [ 59 | 'SortedList', 60 | 'SortedKeyList', 61 | 'SortedListWithKey', 62 | 'SortedDict', 63 | 'SortedKeysView', 64 | 'SortedItemsView', 65 | 'SortedValuesView', 66 | 'SortedSet', 67 | ] 68 | 69 | __title__ = 'sortedcontainers' 70 | __version__ = '2.1.0' 71 | __build__ = 0x020100 72 | __author__ = 'Grant Jenks' 73 | __license__ = 'Apache 2.0' 74 | __copyright__ = '2014-2018, Grant Jenks' 75 | -------------------------------------------------------------------------------- /src/bin/win_inet_pton.py: -------------------------------------------------------------------------------- 1 | # This software released into the public domain. Anyone is free to copy, 2 | # modify, publish, use, compile, sell, or distribute this software, 3 | # either in source code form or as a compiled binary, for any purpose, 4 | # commercial or non-commercial, and by any means. 5 | 6 | import socket 7 | import ctypes 8 | import os 9 | 10 | 11 | class sockaddr(ctypes.Structure): 12 | _fields_ = [("sa_family", ctypes.c_short), 13 | ("__pad1", ctypes.c_ushort), 14 | ("ipv4_addr", ctypes.c_byte * 4), 15 | ("ipv6_addr", ctypes.c_byte * 16), 16 | ("__pad2", ctypes.c_ulong)] 17 | 18 | if hasattr(ctypes, 'windll'): 19 | WSAStringToAddressA = ctypes.windll.ws2_32.WSAStringToAddressA 20 | WSAAddressToStringA = ctypes.windll.ws2_32.WSAAddressToStringA 21 | else: 22 | def not_windows(): 23 | raise SystemError( 24 | "Invalid platform. ctypes.windll must be available." 25 | ) 26 | WSAStringToAddressA = not_windows 27 | WSAAddressToStringA = not_windows 28 | 29 | 30 | def inet_pton(address_family, ip_string): 31 | addr = sockaddr() 32 | addr.sa_family = address_family 33 | addr_size = ctypes.c_int(ctypes.sizeof(addr)) 34 | 35 | if WSAStringToAddressA( 36 | ip_string, 37 | address_family, 38 | None, 39 | ctypes.byref(addr), 40 | ctypes.byref(addr_size) 41 | ) != 0: 42 | raise socket.error(ctypes.FormatError()) 43 | 44 | if address_family == socket.AF_INET: 45 | return ctypes.string_at(addr.ipv4_addr, 4) 46 | if address_family == socket.AF_INET6: 47 | return ctypes.string_at(addr.ipv6_addr, 16) 48 | 49 | raise socket.error('unknown address family') 50 | 51 | 52 | def inet_ntop(address_family, packed_ip): 53 | addr = sockaddr() 54 | addr.sa_family = address_family 55 | addr_size = ctypes.c_int(ctypes.sizeof(addr)) 56 | ip_string = ctypes.create_string_buffer(128) 57 | ip_string_size = ctypes.c_int(ctypes.sizeof(ip_string)) 58 | 59 | if address_family == socket.AF_INET: 60 | if len(packed_ip) != ctypes.sizeof(addr.ipv4_addr): 61 | raise socket.error('packed IP wrong length for inet_ntoa') 62 | ctypes.memmove(addr.ipv4_addr, packed_ip, 4) 63 | elif address_family == socket.AF_INET6: 64 | if len(packed_ip) != ctypes.sizeof(addr.ipv6_addr): 65 | raise socket.error('packed IP wrong length for inet_ntoa') 66 | ctypes.memmove(addr.ipv6_addr, packed_ip, 16) 67 | else: 68 | raise socket.error('unknown address family') 69 | 70 | if WSAAddressToStringA( 71 | ctypes.byref(addr), 72 | addr_size, 73 | None, 74 | ip_string, 75 | ctypes.byref(ip_string_size) 76 | ) != 0: 77 | raise socket.error(ctypes.FormatError()) 78 | 79 | return ip_string[:ip_string_size.value - 1] 80 | 81 | # Adding our two functions to the socket library 82 | if os.name == 'nt': 83 | socket.inet_pton = inet_pton 84 | socket.inet_ntop = inet_ntop 85 | -------------------------------------------------------------------------------- /src/default/app.conf: -------------------------------------------------------------------------------- 1 | [launcher] 2 | version = ${value.version.number} 3 | description = Monitor website performance and uptime; detect errors and downtime 4 | author = LukeMurphey 5 | 6 | [package] 7 | id = website_monitoring 8 | 9 | [install] 10 | build = ${value.build.number} 11 | # Last commit: ${value.build.date} 12 | python.version = python3 13 | 14 | [ui] 15 | is_visible = true 16 | label = Website Monitoring 17 | 18 | [triggers] 19 | reload.website_monitoring = simple 20 | -------------------------------------------------------------------------------- /src/default/authorize.conf: -------------------------------------------------------------------------------- 1 | [capability::edit_modinput_web_ping] 2 | 3 | [role_admin] 4 | edit_modinput_web_ping = enabled 5 | 6 | [role_power] 7 | edit_modinput_web_ping = enabled -------------------------------------------------------------------------------- /src/default/commands.conf: -------------------------------------------------------------------------------- 1 | ## Usage: | webping url=https://textcritical.net 2 | ## Purpose: performs a web-ping on the given URL 3 | [webping] 4 | filename = web_ping_search_command.py 5 | generating = true 6 | passauth = false 7 | python.version = python3 8 | -------------------------------------------------------------------------------- /src/default/data/ui/nav/default.xml: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/default/data/ui/views/exec_summary.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 |
7 | 8 | Last 24 hours 9 | 10 | 11 | 12 | * 13 | 14 |
15 | 16 | 17 | 18 | sourcetype="web_ping" `website_monitoring_search_index` title="$title$" 19 | | `set_response_code` | `set_status` 20 | | stats latest(status) as status by source 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 |
-------------------------------------------------------------------------------- /src/default/data/ui/views/setup_website_monitoring.xml: -------------------------------------------------------------------------------- 1 |
2 | 3 | Global configuration for Website Monitoring 4 | 5 | 6 | 7 |
8 | 9 |
10 |
11 |
-------------------------------------------------------------------------------- /src/default/data/ui/views/site_changes.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 |
4 | 5 | 6 |
7 | 8 | Last 24 hours 9 | 10 | 11 | 12 | * 13 | 14 |
15 | 16 | 17 | 18 | 19 | sourcetype="web_ping" `website_monitoring_search_index` title="$title$" | eval content_hash=if(isnotnull(content_md5),content_md5,content_sha224) | stats count, min(_time) as changed, max(_time) as last_observed by url, content_hash, title | sort -changed | `timesince(changed,since_last_changed)` | convert ctime(changed) | convert ctime(last_observed) | fields title url changed since_last_changed last_observed count 20 | 21 | 22 | Change History 23 | 24 | 25 |
26 |
27 |
-------------------------------------------------------------------------------- /src/default/data/ui/views/status_overview.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 |
4 | 5 | 6 |
7 | 8 | Last 24 hours 9 | 10 | 11 | 12 | Include all inputs 13 | Include only enabled inputs 14 | Include only failures 15 | 16 | 17 | 18 | 19 |
20 | 21 | 22 | 23 | sourcetype="web_ping" `website_monitoring_search_index` 24 | | `set_response_code` | `set_status` 25 | | stats sparkline(avg(total_time)) as sparkline_response_time avg(total_time) as avg_response_time max(total_time) as max_response_time latest(response_code) as response_code latest(_time) as last_checked latest(title) as title latest(url) as url latest(total_time) as response_time range(total_time) as range min(total_time) as min latest(status) as status by source 26 | | search $only_enabled$ 27 | | eval response_time=round(response_time, 0)." ms" 28 | | eval average=round(avg_response_time, 0)." ms" 29 | | eval maximum=round(max_response_time, 0)." ms" 30 | | eval range=round(min, 0)." - ".round(min+range, 0)." ms" 31 | | eval response=response_code 32 | | table title url response last_checked response_time status average range sparkline_response_time 33 | | `timesince(last_checked,last_checked)` 34 | | sort -response_time 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 48 | 49 | 50 | 51 | 52 | 53 | 54 |
55 |
56 | 57 | 58 |

59 | 60 | 61 | 62 |

-------------------------------------------------------------------------------- /src/default/data/ui/views/test_website_monitoring.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 |
7 | 11 |
12 |
13 | 14 |
15 |
16 | -------------------------------------------------------------------------------- /src/default/data/ui/views/web_ping_batch_create.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 |
4 | 5 | 6 | 7 | 8 |
9 | 10 |
11 | 12 |
-------------------------------------------------------------------------------- /src/default/data/ui/views/web_ping_logs.xml: -------------------------------------------------------------------------------- 1 |
2 | 3 |
4 | 5 | 6 | 7 | -24h@h 8 | now 9 | 10 | 11 | 12 | 13 | All 14 | Debug 15 | Informational 16 | Informational (or above) 17 | Warning 18 | Warning (or above) 19 | Error 20 | Error (or above) 21 | Critical 22 | INFO OR WARNING OR ERROR OR CRITICAL 23 | 24 |
25 | 26 | 27 | 28 | 29 | index=_internal (sourcetype=web_availability_modular_input OR sourcetype=website_monitoring_rest_handler) | rex field=_raw "(?<severity>(DEBUG)|(ERROR)|(WARNING)|(INFO)|(CRITICAL)) (?<message>.*)" | fillnull severity value="UNDEFINED" | timechart count(severity) as count by severity 30 | $field1.earliest$ 31 | $field1.latest$ 32 | 33 | Logs by Severity (over time) 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | Logs by Severity 44 | 45 | index=_internal (sourcetype=web_availability_modular_input OR sourcetype=website_monitoring_rest_handler) | rex field=_raw "(?<severity>(DEBUG)|(ERROR)|(WARNING)|(INFO)|(CRITICAL)) (?<message>.*)" | fillnull value="undefined" vendor_severity | stats sparkline count by severity | sort -count 46 | $field1.earliest$ 47 | $field1.latest$ 48 | 49 | 50 | 51 | 52 | 53 | 54 |
55 |
56 |
57 | 58 | 59 | 60 | Latest Logs 61 | 62 | index=_internal (sourcetype=web_availability_modular_input OR sourcetype=website_monitoring_rest_handler) | rex field=_raw "(?<severity>(DEBUG)|(ERROR)|(WARNING)|(INFO)|(CRITICAL)) (?<message>.*)" | search severity=$severity$ | sort -_time | eval time=_time | convert ctime(time) | table time severity message 63 | $field1.earliest$ 64 | $field1.latest$ 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 |
75 |
76 |
77 |
-------------------------------------------------------------------------------- /src/default/eventtypes.conf: -------------------------------------------------------------------------------- 1 | # This eventtype can be used to filter out alerts from the search 2 | # For example, a value of "title=localhost" would stop alerts for the input with the title of localhost 3 | [filter_website_monitoring_alerts] 4 | search=FILL_THIS_SEARCH_IN -------------------------------------------------------------------------------- /src/default/inputs.conf: -------------------------------------------------------------------------------- 1 | [web_ping] 2 | user_agent=Splunk Website Monitoring (+https://splunkbase.splunk.com/app/1493/) 3 | python.version = python3 4 | -------------------------------------------------------------------------------- /src/default/macros.conf: -------------------------------------------------------------------------------- 1 | [response_time_threshold] 2 | definition = 1000 3 | 4 | [response_time_threshold_warning] 5 | definition = 800 6 | 7 | [timesince(2)] 8 | args = sourceField,destField 9 | definition = eval now=time() | eval $destField$ = case( $sourceField$ > now, "0 minutes ago", now-$sourceField$ > (2*86400), round((now-$sourceField$) / (86400)) . " days ago", now-$sourceField$ > (2*3600), round((now-$sourceField$) / (3600)) . " hours ago", now-$sourceField$ > (2*60), round((now-$sourceField$) / (60)) . " minutes ago", now-$sourceField$ > 60, "1 minute ago", now-$sourceField$ <= 60, "just now" ) | fields - now 10 | iseval = 0 11 | 12 | [duration(3)] 13 | args = startField,endField,destField 14 | definition = eval $destField$ = case( $startField$ > $endField$, "0 minutes", $endField$-$startField$ > (2*86400), round(($endField$-$startField$) / (86400)) . " days", $endField$-$startField$ > (2*3600), round(($endField$-$startField$) / (3600)) . " hours", $endField$-$startField$ > (2*60), round(($endField$-$startField$) / (60)) . " minutes", $endField$-$startField$ > 60, "1 minute", $endField$-$startField$ <= 60, "< a minute" ) 15 | iseval = 0 16 | 17 | [format_events] 18 | definition = eval time=_time | eval response_time=total_time | convert ctime(time) | fillnull response_code value="Connection failed" | eval response_code=if(timed_out == "True", "Connection timed out", response_code) | fields - _raw _time | fields time response_code response_time 19 | 20 | [format_events_raw] 21 | definition = eval time=_time | eval response_time=total_time | convert ctime(time) | fillnull response_code value="Connection failed" | eval response_code=if(timed_out == "True", "Connection timed out", response_code) 22 | 23 | [format_events_ex] 24 | definition = eval time=_time | eval response_time=total_time | convert ctime(time) | fillnull response_code value="Connection failed" | eval response_code=if(timed_out == "True", "Connection timed out", response_code) | fields - _raw _time | fields time title url response_code response_time 25 | 26 | [filter_inoperable] 27 | definition = (response_code>=400 OR timed_out="True" OR NOT response_code="*" OR response_code="") 28 | 29 | [filter_disabled] 30 | definition = | join source [| inputlookup append=t web_ping_inputs.csv | search disabled=0] 31 | 32 | [response_codes_to_alert_on] 33 | definition = response_code>=400 34 | 35 | [filter_response_codes_and_response_times] 36 | definition = `response_codes_to_alert_on` OR response_time>=`response_time_threshold` OR response_code="*false" OR response_code="Connection failed" OR response_code="Connection timed out" OR timed_out=True OR response_code="" OR has_expected_string="false" 37 | 38 | # This defines the search index (or indexes) that the app should search. Change this if you want 39 | # the views to search a particular index. 40 | # Example: 41 | # definition = index=main 42 | [website_monitoring_search_index] 43 | definition = () 44 | 45 | [set_response_code] 46 | definition = eval response_code=case(timed_out == "True", "Connection timed out", isnull(response_code) OR response_code="", "Connection failed", true(), response_code).coalesce(" ".has_expected_string,"") 47 | iseval = 0 48 | 49 | [set_status] 50 | definition = eval error_threshold=coalesce(error_threshold,`response_time_threshold`), warning_threshold=coalesce(warning_threshold,`response_time_threshold_warning`), status = case(`response_codes_to_alert_on` OR total_time>=error_threshold OR response_code="*false" OR response_code="Connection failed" OR response_code="Connection timed out" OR timed_out=True OR response_code="" OR has_expected_string="false", "Failed", total_time>=warning_threshold, "Warning", true(), "OK") 51 | iseval = 0 52 | 53 | -------------------------------------------------------------------------------- /src/default/props.conf: -------------------------------------------------------------------------------- 1 | [source::...web_availability_modular_input.log] 2 | sourcetype=web_availability_modular_input 3 | 4 | [source::...website_monitoring_rest_handler.log] 5 | sourcetype=website_monitoring_rest_handler -------------------------------------------------------------------------------- /src/default/restmap.conf: -------------------------------------------------------------------------------- 1 | [admin_external:website_monitoring] 2 | handlertype = python 3 | handlerfile = website_monitoring_rest_handler.py 4 | handleractions = list,edit,_reload,create 5 | python.version = python3 6 | 7 | [admin:website_monitoring] 8 | match = /app_config/* 9 | members = website_monitoring 10 | -------------------------------------------------------------------------------- /src/default/searchbnf.conf: -------------------------------------------------------------------------------- 1 | ################### 2 | # webping 3 | ################## 4 | [webping-command] 5 | syntax = webping () 6 | shortdesc = Perform a web-ping against given the given URL. 7 | description = This search command allows you to determine the state of the given web-site (whether it is performing adequately and is functioning). 8 | maintainer = LukeMurphey 9 | example1 = | webping url=https://textcritical.net 10 | comment1 = Performs a check of the URL https://textcritical.net 11 | generating = true 12 | usage = public 13 | 14 | [webping-options] 15 | syntax = | | 16 | description = Command options for the web-ping command. In most cases, only the URL parameter is necessary. 17 | 18 | [webping-url-option] 19 | syntax = url= 20 | description = The URL to test. 21 | 22 | [webping-expectedstring-option] 23 | syntax = expected_string= 24 | description = The string expected to be present in the response content. 25 | 26 | [webping-returnheaders-option] 27 | syntax = return_headers= 28 | description = Include the headers in the response -------------------------------------------------------------------------------- /src/default/tags.conf: -------------------------------------------------------------------------------- 1 | [eventtype=filter_website_monitoring_alerts] 2 | exclude_from_alerts = enabled -------------------------------------------------------------------------------- /src/default/transforms.conf: -------------------------------------------------------------------------------- 1 | [http_response_codes] 2 | filename = http_response_codes.csv -------------------------------------------------------------------------------- /src/default/ui-tour.conf: -------------------------------------------------------------------------------- 1 | [website_monitoring_2_2] 2 | type = image 3 | imgPath = /tour_new_features 4 | context = website_monitoring 5 | 6 | imageName1 = edit_definition_link.png 7 | imageCaption1 = In version 2.2, you can now edit the criteria that defines a failure. Click the link at the bottom of the "Status Overview" dashboard to edit the criteria. 8 | 9 | imageName2 = edit_definition_dialog.png 10 | imageCaption2 = Set the response time threshold that you consider a performance problem and the response codes you want to be alerted to. 11 | 12 | imageName3 = filter_on_failures.png 13 | imageCaption3 = You can then filter results on the "Status Overview" dashboard according to the definition you defined. 14 | 15 | imageName4 = alert_search.png 16 | imageCaption4 = You can use the new "Website Performance Problem" alert search to get notifications of outages. This search leverages the definition you configured on the "Status Overview" dashboard. 17 | 18 | [website_monitoring_2_3] 19 | type = image 20 | imgPath = /tour_new_features 21 | context = website_monitoring 22 | 23 | imageName1 = setup_page.png 24 | imageCaption1 = Version 2.3 includes an improved setup experience that is easier to use. 25 | 26 | imageName2 = setup_page.png 27 | imageCaption2 = Credentials in the app are also now stored using Splunk's secure storage in order to enhance security. Password's for existing inputs will automatically be updated to use secure storage whenever they are edited. 28 | 29 | [website_monitoring_2_5] 30 | type = image 31 | imgPath = /tour_new_features 32 | context = website_monitoring 33 | 34 | imageName1 = should_contain_string.png 35 | imageCaption1 = Version 2.5 includes the ability to define a string that you expect to be in the HTML page you monitor so that you can ensure that the content is valid. 36 | 37 | imageName2 = content_matches.png 38 | imageCaption2 = If the content doesn't match, the URL will be flagged on the Status Overview dashboard. 39 | 40 | [website_monitoring_2_6] 41 | type = image 42 | imgPath = /tour_new_features 43 | context = website_monitoring 44 | 45 | imageName1 = macro_link.png 46 | imageCaption1 = Version 2.6 includes the ability to define which indexes the app will search for results. 47 | 48 | imageName2 = macro_link.png 49 | imageCaption2 = Enter a list of indexes into the macro to limit the dashboards and saved searches to these indexes (e.g. "index=web_ping") 50 | 51 | [website_monitoring_2_7] 52 | type = image 53 | imgPath = /tour_new_features 54 | context = website_monitoring 55 | 56 | imageName1 = exec_summary.png 57 | imageCaption1 = Version 2.7 adds a new executive summary of current inputs. 58 | 59 | imageName2 = shc.png 60 | imageCaption2 = Support for SHC has been added. You can no longer make inputs on a SHC. Inputs deployed from the SHC deployer now work correctly. 61 | 62 | [website_monitoring_2_8] 63 | type = image 64 | imgPath = /tour_new_features 65 | context = website_monitoring 66 | 67 | imageName1 = input_timeout.png 68 | imageCaption1 = Version 2.8 adds the ability to customize the timeout on the inputs. 69 | 70 | imageName2 = input_timeout.png 71 | imageCaption2 = Inputs that take longer than the timeout will be considered a failure. You can leave the timeout blank to stay with the default (30 seconds). 72 | 73 | [website_monitoring_new_features] 74 | type = image 75 | imgPath = /tour_new_features 76 | context = website_monitoring 77 | 78 | imageName1 = include_headers.png 79 | imageCaption1 = Version 2.9 adds the ability to export HTTP headers. 80 | 81 | imageName2 = include_headers.png 82 | imageCaption2 = HTTP headers can be revied with results if the option to include headers is enabled. 83 | -------------------------------------------------------------------------------- /src/default/web.conf: -------------------------------------------------------------------------------- 1 | ## Web ping 2 | [expose:web_ping] 3 | methods = GET,POST 4 | pattern = data/inputs/web_ping 5 | 6 | [expose:website_monitoring] 7 | methods = GET,POST 8 | # The pattern below must match the entry in restmap.conf in order to avoid an appinspect failure 9 | pattern = /app_config/** 10 | -------------------------------------------------------------------------------- /src/default/website_monitoring.conf: -------------------------------------------------------------------------------- 1 | #[default] 2 | #proxy_server= 3 | #proxy_port= 4 | #proxy_type=http 5 | #proxy_ignore= 6 | #thread_limit=200 -------------------------------------------------------------------------------- /src/lookups/http_response_codes.csv: -------------------------------------------------------------------------------- 1 | response_code,title,description 2 | 100,HTTP_CONTINUE,Continue 3 | 101,HTTP_SWITCHING_PROTOCOLS,Switching Protocols 4 | 200,HTTP_OK,OK 5 | 201,HTTP_CREATED,Created 6 | 202,HTTP_ACCEPTED,Accepted 7 | 203,HTTP_NON_AUTHORITATIVE,Non-Authoritative Information 8 | 204,HTTP_NO_CONTENT,No Content 9 | 205,HTTP_RESET_CONTENT,Reset Content 10 | 206,HTTP_PARTIAL_CONTENT,Partial Content 11 | 300,HTTP_MULTIPLE_CHOICES,Multiple Choices 12 | 301,HTTP_MOVED_PERMANENTLY,Moved Permanently 13 | 302,HTTP_MOVED_TEMPORARILY,Found 14 | 303,HTTP_SEE_OTHER,See Other 15 | 304,HTTP_NOT_MODIFIED,Not Modified 16 | 305,HTTP_USE_PROXY,Use Proxy 17 | 307,HTTP_TEMPORARY_REDIRECT,Temporary Redirect 18 | 400,HTTP_BAD_REQUEST,Bad Request 19 | 401,HTTP_UNAUTHORIZED,Unauthorized 20 | 402,HTTP_PAYMENT_REQUIRED,Payment Required 21 | 403,HTTP_FORBIDDEN,Forbidden 22 | 404,HTTP_NOT_FOUND,Not Found 23 | 405,HTTP_METHOD_NOT_ALLOWED,Method Not Allowed 24 | 406,HTTP_NOT_ACCEPTABLE,Not Acceptable 25 | 407,HTTP_PROXY_AUTHENTICATION_REQUIRED,Proxy Authentication Required 26 | 408,HTTP_REQUEST_TIMEOUT,Request Timeout 27 | 409,HTTP_CONFLICT,Conflict 28 | 410,HTTP_GONE,Gone 29 | 411,HTTP_LENGTH REQUIRED,Length Required 30 | 412,HTTP_PRECONDITION_FAILED,Precondition Failed 31 | 413,HTTP_REQUEST_ENTITY_TOO_LARGE,Request Entity Too Large 32 | 414,HTTP_REQUEST_URI_TOO_LARGE,Request-URI Too Long 33 | 415,HTTP_UNSUPPORTED_MEDIA_TYPE,Unsupported Media Type 34 | 416,HTTP_RANGE_NOT_SATISFIABLE,Requested Range Not Satisfiable 35 | 417,HTTP_EXPECTATION_FAILED,Expectation Failed 36 | 500,HTTP_INTERNAL_SERVER_ERROR,Internal Server Error 37 | 501,HTTP_NOT IMPLEMENTED,Not Implemented 38 | 502,HTTP_BAD_GATEWAY,Bad Gateway 39 | 503,HTTP_SERVICE_UNAVAILABLE,Service Unavailable 40 | 504,HTTP_GATEWAY_TIME_OUT,Gateway Timeout 41 | 505,HTTP_VERSION_NOT_SUPPORTED,HTTP Version Not Supported -------------------------------------------------------------------------------- /src/metadata/default.meta: -------------------------------------------------------------------------------- 1 | [] 2 | access = read : [ * ], write : [ admin ] 3 | export = system 4 | 5 | [macros/response_codes_to_alert_on] 6 | access = read : [ * ], write : [ admin,power ] 7 | export = system 8 | 9 | [macros/response_time_threshold] 10 | access = read : [ * ], write : [ admin,power ] 11 | export = system 12 | 13 | [macros/response_time_threshold_warning] 14 | access = read : [ * ], write : [ admin,power ] 15 | export = system -------------------------------------------------------------------------------- /src/static/appIcon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LukeMurphey/splunk-website-monitoring/442d08de5bbfed4a879de3b537eae0361de8e473/src/static/appIcon.png -------------------------------------------------------------------------------- /src/static/appIconAlt.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LukeMurphey/splunk-website-monitoring/442d08de5bbfed4a879de3b537eae0361de8e473/src/static/appIconAlt.png -------------------------------------------------------------------------------- /src/static/appIcon_2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LukeMurphey/splunk-website-monitoring/442d08de5bbfed4a879de3b537eae0361de8e473/src/static/appIcon_2x.png -------------------------------------------------------------------------------- /tests/configs/00eb20db654dd807fd6734b18323f5af.json: -------------------------------------------------------------------------------- 1 | bad_json -------------------------------------------------------------------------------- /tests/configs/35163af7282b92013f810b2b4822d7df.json: -------------------------------------------------------------------------------- 1 | { 2 | "last_run": 1365486765 3 | } -------------------------------------------------------------------------------- /tests/host.cert: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE----- 2 | MIIDvjCCAqYCCQD915FGTsly8jANBgkqhkiG9w0BAQsFADCBoDELMAkGA1UEBhMC 3 | VVMxCzAJBgNVBAgMAklOMRUwEwYDVQQHDAxJbmRpYW5hcG9saXMxGDAWBgNVBAoM 4 | D0x1a2VNdXJwaGV5Lm5ldDENMAsGA1UECwwEVGVzdDEeMBwGA1UEAwwVbHVrZW11 5 | cnBoZXkubG9jYWxob3N0MSQwIgYJKoZIhvcNAQkBFhVMdWtlQFRleHRDcml0aWNh 6 | bC5uZXQwHhcNMjExMTE2MjE1OTEwWhcNMjIxMTE2MjE1OTEwWjCBoDELMAkGA1UE 7 | BhMCVVMxCzAJBgNVBAgMAklOMRUwEwYDVQQHDAxJbmRpYW5hcG9saXMxGDAWBgNV 8 | BAoMD0x1a2VNdXJwaGV5Lm5ldDENMAsGA1UECwwEVGVzdDEeMBwGA1UEAwwVbHVr 9 | ZW11cnBoZXkubG9jYWxob3N0MSQwIgYJKoZIhvcNAQkBFhVMdWtlQFRleHRDcml0 10 | aWNhbC5uZXQwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCmdmOwHlte 11 | OOFjToVoDFN1im7zvljbANdi+d/W48ZUjiqPspOBV1BaZhO973Cj5HO9IPEWXC3a 12 | y6P3BMIG4VjsY72yG5inIq1bDo6dlEVwmZmVNShQp/uqAKY1N4ob3IXNsnP9i/AN 13 | 52wDZ7fwdZL4iTDHg0Mk5svt647MvfPXU8afkOYXOz9gqSIumeCCSzZeUWXiROWU 14 | Y+JTJ0NuoDxtjDeb4hSCVA2d66TgKvSoUmaFJfMVwGo7r/pt4kjJsLpfITNaMOcy 15 | I82mjpnanO8FYYQgz8tE7aBBK6qll/SYW2eKk75RBroVrqxqCkSVl+ZwZLuyq8qT 16 | vdBe17haVqefAgMBAAEwDQYJKoZIhvcNAQELBQADggEBADteL0+cfDtZKTeuxg18 17 | gGH3FWOifizanCDsCxx7CplBsuiFia1ZN97MyhnUdawwxpk7+7gVSageFDql4AKU 18 | /zEZ7cAP1V7R14lz6dRIrXeVRebu5DVsPhPRxeIWKXlYFYFx2dXNsJfj6iTe9/ir 19 | Q9oNIESC7fO9FoOkBDCwJ4G+fVzmoD7SgdCcMcEedUBHFvtm0Lh+PkrvPVE84Fq5 20 | YJBFeo+80wTR5TM7k2Uozz2jyJaGlRxn0rHFbj6cAx9Oy7ndqweN1pNwFoXFwKz5 21 | VwDqk2tCODvj5HjqdIV+TVik28GA2mPuiAM6uNWQL1HCxSbWf7+B1+1+TtKUFmes 22 | M18= 23 | -----END CERTIFICATE----- 24 | -------------------------------------------------------------------------------- /tests/host.key: -------------------------------------------------------------------------------- 1 | -----BEGIN RSA PRIVATE KEY----- 2 | MIIEowIBAAKCAQEApnZjsB5bXjjhY06FaAxTdYpu875Y2wDXYvnf1uPGVI4qj7KT 3 | gVdQWmYTve9wo+RzvSDxFlwt2suj9wTCBuFY7GO9shuYpyKtWw6OnZRFcJmZlTUo 4 | UKf7qgCmNTeKG9yFzbJz/YvwDedsA2e38HWS+Ikwx4NDJObL7euOzL3z11PGn5Dm 5 | Fzs/YKkiLpnggks2XlFl4kTllGPiUydDbqA8bYw3m+IUglQNneuk4Cr0qFJmhSXz 6 | FcBqO6/6beJIybC6XyEzWjDnMiPNpo6Z2pzvBWGEIM/LRO2gQSuqpZf0mFtnipO+ 7 | UQa6Fa6sagpElZfmcGS7sqvKk73QXte4WlannwIDAQABAoIBAQCipmNZnw/fzOxN 8 | wFeSBxk1bIJlH8RqmTPbvhP9QKp1zEPCDNccNliJO9xmZiNFwN9mGV34XzFe7EPW 9 | BYwgdOgScpLUCSrrhHKm2l53kn0XPL5YkIxH4xuATQoaTZ5hAuSqzIeRYr64lztv 10 | SFTuW7OzrTlAeP2OfQUeAGCTpbcw2VLpJScvdGdcL02h9STcDd0wYt3t3tKY2BdP 11 | kJFgNyHYbb7hAA1YwpkjVRxMHBAp7CswoQnu12iIyILEIzaNVUGrxahSOVK7Lh9C 12 | HGrP3eieo+c2VZQHTZa3fkHw3iMlbTSWdNsMEY5NGMPArnj1qIXyFawPtvjCshVT 13 | RZIeZhgBAoGBANm+PuyA9n4uOaj/cbYxR5al7P2kkl6TEjOCUtPcbXCo4Hrw9Th2 14 | JOYYrMq/oH5q464ZPetH3DPUdLnPf51dQISMkuZHe6lDLGITXTrylikrw7XNdEtS 15 | bY5lctcqRfWV0hjD8gVh1VrA/yvd4QmmGR0pXLiw6qUlrAnmBynH8oUBAoGBAMO1 16 | ndW/q8HqDKx2Wo7EZPTIjxPzEHj/lM//mp/kjNEsyjf2nWxAUKn3pvR5tIySS6G2 17 | Ci1R0++ohL+2bZCSj8fM3aHPVM/2GFYAjn+noLdgQjO7S7kkwOe70OcfRpgwglPc 18 | xgQWn9ASoWUJhYoroaoJXxsuAWVrVu+w+sBqegyfAoGAd7e7Hwu0+yFtQHbaTYMA 19 | ylqGV9rhQzB3pGx2H9glL/kaG15aZWXH2d8dOghsNLWOY02rlq4W60RXvUXR83Kv 20 | I3Gq3wPUgPbW80GUU/HHD/HpFA9XboZuiAlNP/IVLvbl4gnyCnWE+fX9FmBS95wk 21 | WL1CJqXXDWAOHA8mRxmRRQECgYBK6PBiCXx3u9tgA+lDrj6qRz4kt6u9dK6EMuT/ 22 | gJ65zfgVFatJ7RAzDpz0BMWr7K9QVXptwF1r5UfyjaRAayjnpC3NKqve8eZ8vLfO 23 | et4Ucp7EaFNiqYPA723VmW4PALpR2TZeCD7hiNAH+W4I5gx6Jh4mLCTSqhRbqJVC 24 | Iz9WJwKBgCOaccC6mSsTm+FXQUzrtH3HfoTa+XxJK+74vj3MZ9075JnM+krNRAD2 25 | 8eR5FeQ03cmPDF1rEYMgw8XsjdOEdwYF/HpdMHh/KtHiIIEE/UL7xUHN+I1aaeZ0 26 | ZcmPLNbpMWolbSjKTpujimDN3t1dO+6tKYmH4DEOuuWFlsV3Abw1 27 | -----END RSA PRIVATE KEY----- 28 | -------------------------------------------------------------------------------- /tests/test_proxy_server.py: -------------------------------------------------------------------------------- 1 | """ 2 | This module serves a basic HTTP proxy which just passes on HTTP requests. 3 | """ 4 | from six.moves.socketserver import TCPServer 5 | from six.moves.urllib.request import urlopen 6 | from six.moves.SimpleHTTPServer import SimpleHTTPRequestHandler 7 | import time 8 | 9 | WAITING_FOR_PORT_SLEEP_TIME = 4 10 | WAITING_FOR_PORT_ATTEMPT_LIMIT = 75 11 | class Proxy(SimpleHTTPRequestHandler): 12 | def do_GET(self): 13 | self.send_response(200) 14 | self.end_headers() 15 | self.copyfile(urlopen(self.path), self.wfile) 16 | 17 | def get_server(port): 18 | """ 19 | Call proxyd.shutdown() to stop the server 20 | """ 21 | attempts = 0 22 | while attempts < WAITING_FOR_PORT_ATTEMPT_LIMIT: 23 | try: 24 | proxyd = TCPServer(("", port), Proxy) 25 | return proxyd 26 | 27 | except IOError: 28 | time.sleep(WAITING_FOR_PORT_SLEEP_TIME) 29 | attempts = attempts + 1 30 | 31 | raise IOError("Could not start proxy server") 32 | 33 | 34 | -------------------------------------------------------------------------------- /tests/web_files/test_page.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Page Title 5 | 6 | 7 | 8 |

My First Heading

9 |

My first paragraph.

10 | 11 | 12 | --------------------------------------------------------------------------------