Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

Added documentation, tests and automated deployment.

  • Loading branch information...
commit 5282ee38399a9bdacab553d58e66f5406660f5b2 1 parent 8354fc9
Johannes Würbach authored
22 .travis.yml
View
@@ -0,0 +1,22 @@
+---
+language: node_js
+node_js:
+- 0.8
+env:
+ global:
+ - secure: ! 'brlwa/pTnyIx1jetVRbF+2Rg4Xokld5MAfVjqiGi9YaqmjWh67c6CIt8DIyb
+
+ +TzEDv8PP2LZo37491R7BVp362xJyi3izkGtMDUMgOZ31oNUmtREuSN05caC
+
+ ss2yxcmVTXvnPMgchLYityPyQ55LUds+S4HskN+6i9HhaAWtWG8='
+after_success:
+ - if [[ "$TRAVIS_BRANCH" != "master" || "$TRAVIS_PULL_REQUEST" == "true" ]]; then echo "Do not deploy."; exit 0; fi
+ - wget -qO- https://toolbelt.heroku.com/install-ubuntu.sh | sh
+ - git remote add heroku git@heroku.com:request-inspect.git
+ - echo "Host heroku.com" >> ~/.ssh/config
+ - echo " StrictHostKeyChecking no" >> ~/.ssh/config
+ - echo " CheckHostIP no" >> ~/.ssh/config
+ - echo " UserKnownHostsFile=/dev/null" >> ~/.ssh/config
+ - heroku keys:clear
+ - yes | heroku keys:add
+ - yes | git push heroku master
32 README.md
View
@@ -1,6 +1,30 @@
-request-inspect
-===============
+# request-inspect #
+[![Build Status](https://travis-ci.org/johanneswuerbach/request-inspect.png?branch=master)](https://travis-ci.org/johanneswuerbach/request-inspect)
-Inspect server-to-server requests.
+Simplifies inspecting of server-to-server requests.
-[Demo](http://request-inspect.johanneswuerbach.net)
+## Usage ##
+* Visit the documentation: http://request-inspect.johanneswuerbach.net
+
+## License ##
+
+Copyright (c) 2012 Johannes Würbach
+
+Permission is hereby granted, free of charge, to any person obtaining
+a copy of this software and associated documentation files (the
+"Software"), to deal in the Software without restriction, including
+without limitation the rights to use, copy, modify, merge, publish,
+distribute, sublicense, and/or sell copies of the Software, and to
+permit persons to whom the Software is furnished to do so, subject to
+the following conditions:
+
+The above copyright notice and this permission notice shall be
+included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
142 assets/css/application.css
View
@@ -0,0 +1,142 @@
+/*
+ Source: https://github.com/simonwhitaker/github-fork-ribbon-css
+*/
+body {
+ margin-top: 5px;
+}
+/* Left will inherit from right (so we don't need to duplicate code */
+.github-fork-ribbon {
+ /* The right and left lasses determine the side we attach our banner to */
+ position: absolute;
+
+ /* Add a bit of padding to give some substance outside the "stitching" */
+ padding: 2px 0;
+
+ /* Set the base colour */
+ background-color: #a00;
+
+ /* Set a gradient: transparent black at the top to almost-transparent black at the bottom */
+ background-image: -webkit-gradient(linear, left top, left bottom, from(rgba(0, 0, 0, 0.00)), to(rgba(0, 0, 0, 0.15)));
+ background-image: -webkit-linear-gradient(top, rgba(0, 0, 0, 0.00), rgba(0, 0, 0, 0.15));
+ background-image: -moz-linear-gradient(top, rgba(0, 0, 0, 0.00), rgba(0, 0, 0, 0.15));
+ background-image: -o-linear-gradient(top, rgba(0, 0, 0, 0.00), rgba(0, 0, 0, 0.15));
+ background-image: -ms-linear-gradient(top, rgba(0, 0, 0, 0.00), rgba(0, 0, 0, 0.15));
+ background-image: linear-gradient(top, rgba(0, 0, 0, 0.00), rgba(0, 0, 0, 0.15));
+ filter: progid:DXImageTransform.Microsoft.gradient(GradientType=0,StartColorStr='#000000', EndColorStr='#000000');
+
+ /* Add a drop shadow */
+ -webkit-box-shadow: 0px 2px 3px 0px rgba(0, 0, 0, 0.5);
+ box-shadow: 0px 2px 3px 0px rgba(0, 0, 0, 0.5);
+
+ z-index: 9999;
+}
+
+.github-fork-ribbon a {
+ /* Set the font */
+ font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
+ font-size: 13px;
+ font-weight: 700;
+ color: white;
+
+ /* Set the text properties */
+ text-decoration: none;
+ text-shadow: 0 -1px rgba(0,0,0,0.5);
+ text-align: center;
+
+ /* Set the geometry. If you fiddle with these you'll also need to tweak the top and right values in #github-fork-ribbon. */
+ width: 200px;
+ line-height: 20px;
+
+ /* Set the layout properties */
+ display: inline-block;
+ padding: 2px 0;
+
+ /* Add "stitching" effect */
+ border-width: 1px 0;
+ border-style: dotted;
+ border-color: rgba(255,255,255,0.7);
+}
+
+.github-fork-ribbon-wrapper {
+ width: 150px;
+ height: 150px;
+ position: absolute;
+ overflow: hidden;
+ top: 0;
+}
+
+.github-fork-ribbon-wrapper.left {
+ left: 0;
+}
+
+.github-fork-ribbon-wrapper.right {
+ right: 0;
+}
+
+.github-fork-ribbon-wrapper.left-bottom {
+ position: fixed;
+ top: inherit;
+ bottom: 0;
+ left: 0;
+}
+
+.github-fork-ribbon-wrapper.right-bottom {
+ position: fixed;
+ top: inherit;
+ bottom: 0;
+ right: 0;
+}
+
+.github-fork-ribbon-wrapper.right .github-fork-ribbon {
+ top: 42px;
+ right: -43px;
+
+ /* Rotate the banner 45 degrees */
+ -webkit-transform: rotate(45deg);
+ -moz-transform: rotate(45deg);
+ -o-transform: rotate(45deg);
+ transform: rotate(45deg);
+}
+
+.github-fork-ribbon-wrapper.left .github-fork-ribbon {
+ /* Attach to the left of the page */
+ top: 42px;
+ left: -43px;
+
+ /* Rotate the banner -45 degrees */
+ -webkit-transform: rotate(-45deg);
+ -moz-transform: rotate(-45deg);
+ -o-transform: rotate(-45deg);
+ transform: rotate(-45deg);
+}
+
+
+.github-fork-ribbon-wrapper.left-bottom .github-fork-ribbon {
+ /* Attach to the left of the page */
+ top: 75px;
+ left: -64px;
+
+ /* Rotate the banner -45 degrees */
+ -webkit-transform: rotate(45deg);
+ -moz-transform: rotate(45deg);
+ -o-transform: rotate(45deg);
+ transform: rotate(45deg);
+}
+.github-fork-ribbon-wrapper.left-bottom .github-fork-ribbon a {
+ padding-left: 18px;
+}
+
+.github-fork-ribbon-wrapper.right-bottom .github-fork-ribbon {
+ /* Attach to the left of the page */
+ top: 89px;
+ left: -10px;
+
+ /* Rotate the banner -45 degrees */
+ -webkit-transform: rotate(-45deg);
+ -moz-transform: rotate(-45deg);
+ -o-transform: rotate(-45deg);
+ transform: rotate(-45deg);
+}
+.github-fork-ribbon-wrapper.right-bottom .github-fork-ribbon a {
+ padding-left: 15px;
+}
84 lib/app.coffee
View
@@ -0,0 +1,84 @@
+express = require 'express'
+util = require 'util'
+
+module.exports = class App
+ constructor : (port, callback) ->
+ app = express()
+ server = (require 'http').createServer app
+ @io = (require 'socket.io').listen server
+
+ @io.configure =>
+ @io.set 'log level', 1
+ @io.set "transports", ["xhr-polling"] # Heroku does not support websockets
+ @io.set "polling duration", 10
+
+ app.use require('connect-assets')()
+ app.engine('.html', require('ejs').__express)
+ app.use @rawBody
+
+ # Express
+ app.get '/', @index
+ app.all '/:UUID/:type?/:response?', @catchRequest
+
+ # Socket.IO
+ @io.sockets.on 'connection', (socket) ->
+ socket.emit "ready"
+ socket.on "join", (data) ->
+ socket.join data.room
+
+ # Run the server
+ server.listen port, callback
+
+ # Renders the frontend
+ index : (req, res) ->
+ res.render 'index.ejs', {host: req.headers.host}
+
+ # Catches the request
+ catchRequest : (req, res) =>
+ UUID = req.params.UUID
+ request =
+ method: req.method
+ headers: req.headers
+ query: req.query
+ body: req.rawBody
+
+ # Remove headers injected by Heroku
+ herokuHeaders = [
+ "x-forwarded-proto", "x-forwarded-port",
+ "x-forwarded-for", "x-heroku-queue-wait-time",
+ "x-heroku-queue-depth", "x-heroku-dynos-in-use",
+ "x-request-start"
+ ]
+ if request.headers
+ for header in herokuHeaders
+ delete request.headers[header]
+
+ # Send the request into the room
+ @displayRequest UUID, request
+
+ # Send response, if requested
+ if !req.params.type || !req.params.response
+ res.send ""
+ return
+ type = req.params.type
+ response = req.params.response
+ if type == "json"
+ try
+ response = JSON.parse response
+ catch e
+ console.log e
+ res.send response
+
+ # Display a request in the frontend
+ displayRequest : (UUID, request) ->
+ @io.sockets.in(UUID).emit "request", request
+
+ # Adds the rawBody field
+ rawBody : (req, res, next) ->
+ data = ''
+ req.setEncoding 'utf8'
+ req.on 'data', (chunk) ->
+ data += chunk
+ req.on 'end', ->
+ req.rawBody = data
+ next()
13 package.json
View
@@ -1,10 +1,12 @@
{
"name": "request-inspect",
"version": "0.0.1",
- "description": "Inspect your server-to-server requests.",
+ "description": "Simplifies inspecting of server-to-server requests.",
+ "author": "Johannes Würbach <johannes.wuerbach@googlemail.com>",
"main": "server.coffee",
"scripts": {
- "start": "coffee server.coffee"
+ "start": "./node_modules/coffee-script/bin/coffee server.coffee",
+ "test": "./node_modules/mocha/bin/mocha --compilers coffee:coffee-script --ignore-leaks"
},
"repository": {
"type": "git",
@@ -17,6 +19,13 @@
"connect-assets": "2.3.x",
"ejs": "0.8.x"
},
+ "devDependencies" : {
+ "restler": "*",
+ "mocha": "*",
+ "sinon": "*",
+ "chai": "*",
+ "sinon-chai": "*"
+ },
"engines": {
"node": "0.8.x",
"npm": "1.1.x"
78 server.coffee
View
@@ -1,74 +1,6 @@
+App = require './lib/app'
+port = (process.env.PORT || 3000)
-express = require 'express'
-util = require 'util'
-app = express()
-server = (require 'http').createServer app
-io = (require 'socket.io').listen server
-
-io.configure ->
- io.set 'log level', 1
- # Heroku doesn't support real websockets
- io.set "transports", ["xhr-polling"]
- io.set "polling duration", 10
-
-server.listen (process.env.PORT || 3000)
-
-app.use require('connect-assets')()
-app.engine('.html', require('ejs').__express)
-app.use ((req, res, next) ->
- data = ''
- req.setEncoding 'utf8'
- req.on 'data', (chunk) ->
- data += chunk
-
- req.on 'end', () ->
- req.rawBody = data
- next()
-)
-
-# Express
-app.get '/', (req, res) ->
- res.render 'index.ejs', {host: req.headers.host}
-
-app.all '/:UUID/:type?/:response?', (req, res) ->
- UUID = req.param "UUID"
- request =
- method: req.method
- headers: req.headers
- query: req.query
- body: req.rawBody
-
- # Clean headers
- herokuHeaders = [
- "x-forwarded-proto",
- "x-forwarded-port",
- "x-forwarded-for",
- "x-heroku-queue-wait-time",
- "x-heroku-queue-depth",
- "x-heroku-dynos-in-use",
- "x-request-start"
- ]
-
- if request.headers
- for header in herokuHeaders
- delete request.headers[header]
-
- io.sockets.in(UUID).emit "request", request
-
- if (req.param "type") && (req.param "response")
- type = req.param "type"
- response = req.param "response"
- if type == "json"
- try
- response = JSON.parse response
- catch e
-
- res.send response
- else
- res.send ""
-
-# SocketIO
-io.sockets.on 'connection', (socket) ->
- socket.emit "ready"
- socket.on "join", (data) ->
- socket.join data.room
+console.log "Starting server on port #{port}."
+new App port, ->
+ console.log "Ready."
96 test/app.coffee
View
@@ -0,0 +1,96 @@
+rest = require 'restler'
+sinon = require 'sinon'
+chai = require "chai"
+chai.use (require "sinon-chai")
+should = chai.should()
+
+App = require '../lib/app'
+
+describe 'Server', ->
+ app = null
+ before (done) ->
+ # Load server
+ app = new App 5000, done
+
+ describe '#index', ->
+
+ it 'should return 200', (done) ->
+
+ rest.get('http://localhost:5000').on 'complete', (data, res) ->
+ res.statusCode.should.equal 200
+ done()
+
+ describe '#catchRequest', ->
+
+ describe 'displaying the request', ->
+
+ displayRequestSpy = null
+
+ before ->
+ displayRequestSpy = sinon.spy app, "displayRequest"
+
+ it 'should forward request', (done) ->
+ rest.get('http://localhost:5000/forward/?test=a').on 'complete', ->
+ displayRequestSpy.should.have.been.calledWith "forward",
+ body: ""
+ headers:
+ accept: "*/*"
+ "accept-encoding": "gzip, deflate"
+ connection: "keep-alive"
+ host: "localhost:5000"
+ "user-agent": "Restler for node.js"
+ method: "GET"
+ query:
+ test: "a"
+ done()
+
+ it 'should forward a post body', (done) ->
+ rest.post('http://localhost:5000/post/', {data: { a: 1, b: 2 }}).on 'complete', ->
+ displayRequestSpy.should.have.been.calledWith "post",
+ body: "a=1&b=2"
+ headers:
+ accept: "*/*",
+ "accept-encoding": "gzip, deflate"
+ connection: "keep-alive"
+ "content-length": "7",
+ "content-type": "application/x-www-form-urlencoded"
+ host: "localhost:5000"
+ "user-agent": "Restler for node.js"
+ method: "POST"
+ query: {}
+ done()
+
+ it 'should remove the headers injected by Heroku', (done) ->
+ headers =
+ "x-forwarded-proto": "x"
+ "x-forwarded-port": "y"
+ rest.get('http://localhost:5000/injected/', {headers: headers}).on 'complete', ->
+ displayRequestSpy.should.have.been.calledWith "injected",
+ body: ""
+ headers:
+ accept: "*/*",
+ "accept-encoding": "gzip, deflate"
+ connection: "keep-alive"
+ host: "localhost:5000"
+ "user-agent": "Restler for node.js"
+ method: "GET"
+ query: {}
+ done()
+
+ describe 'sending the response', ->
+
+ it 'should return a plain response', (done) ->
+ rest.get('http://localhost:5000/test/plain/*TEST*').on 'complete', (data) ->
+ data.should.equal "*TEST*"
+ done()
+
+ it 'should return a json response', (done) ->
+ test = JSON.stringify {test: true, service: "works"}
+ encodedJSON = encodeURIComponent test
+ rest.get('http://localhost:5000/test/json/' + encodedJSON).on 'complete', (data) ->
+ JSON.stringify(data).should.equal test
+ done()
+
+
+
+
45 views/index.ejs
View
@@ -11,6 +11,12 @@
<%- js('application') %>
</head>
<body>
+ <div class="github-fork-ribbon-wrapper right">
+ <div class="github-fork-ribbon">
+ <a href="https://github.com/johanneswuerbach/request-inspect">Fork me on GitHub</a>
+ </div>
+ </div>
+
<div class="container">
<div class="navbar">
<div class="navbar-inner">
@@ -18,6 +24,7 @@
<ul class="nav">
<li class="active"><a href="/">Inspector</a></li>
<li><a href="/">New session</a></li>
+ <li><a href="https://github.com/johanneswuerbach/request-inspect/issues">Issues</a></li>
<!-- <li><a href="http://johanneswuerbach.net">Homepage</a></li> -->
</ul>
</div>
@@ -27,12 +34,38 @@
</div>
<script id="ready" type="text/x-handlebars-template">
<div class="span12">
- <h4>Ready</h4>
- <p>Your target url is <code>{{url}}</code></p>
- <p>
- Example:
- <pre>curl -d "hello=world" {{url}}</pre>
- </p>
+ <h4>Usage</h4>
+ <h5>Empty response</h5>
+ <p>Your requests to <code>{{url}}</code>, will be displayed here.</p>
+ <h5>Plain response</h5>
+ <p>Send your request to <code>{{url}}/plain/YOUR_RESPONSE</code> and the response will be <code>YOUR_RESPONSE</code>.</p>
+ <h5>JSON response</h5>
+ <p>Send your request to <code>{{url}}/json/ENCODED_JSON</code> and the response will be <code>JSON</code>.</p>
+ <h5>Share the results</h5>
+ <p>To share the printed requests, just share the URL in your location bar.</p>
+ <h4>Examples</h4>
+ <h5>POSTing some data with curl</h5>
+ <pre>&gt; curl* -d "hello=world" {{url}}
+HTTP/1.1 200 OK
+Content-Type: text/html; charset=utf-8
+Content-Length: 0</pre>
+ <h5>GETing with a specified plain response</h5>
+ <pre>&gt; curl* {{url}}/plain/some%20text
+HTTP/1.1 200 OK
+Content-Type: text/html; charset=utf-8
+Content-Length: 9
+
+some text</pre>
+ <h5>GETing with a specified JSON response</h5>
+ <pre>&gt; curl* {{url}}/json/%7B%22json%22%3A%20%22test%22%7D
+HTTP/1.1 200 OK
+Content-Type: application/json; charset=utf-8
+Content-Length: 20
+
+{
+ "json": "test"
+}</pre>
+ * curl used with <code>-D /dev/stdout -o /dev/stdout -s</code>.
</div>
</script>
<script id="request" type="text/x-handlebars-template">
Please sign in to comment.
Something went wrong with that request. Please try again.